diff --git a/atomic/cast.go b/atomic/cast.go new file mode 100644 index 0000000..80ac0b6 --- /dev/null +++ b/atomic/cast.go @@ -0,0 +1,47 @@ +/* + * MIT License + * + * Copyright (c) 2024 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package atomic + +import "reflect" + +func Cast[M any](src any) (model M, casted bool) { + if reflect.DeepEqual(src, model) { + return model, false + } else if v, k := src.(M); !k { + return model, false + } else { + return v, true + } +} + +func IsEmpty[M any](src any) bool { + if _, k := Cast[M](src); !k { + return true + } + + return false +} diff --git a/atomic/default.go b/atomic/default.go new file mode 100644 index 0000000..c127b8b --- /dev/null +++ b/atomic/default.go @@ -0,0 +1,45 @@ +/* + * MIT License + * + * Copyright (c) 2024 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package atomic + +type defaultValue[T any] interface { + GetDefault() T +} + +type defVal[T any] struct { + v T +} + +func (d *defVal[T]) GetDefault() T { + return d.v +} + +func newDefault[T any](def T) *defVal[T] { + return &defVal[T]{ + v: def, + } +} diff --git a/atomic/interface.go b/atomic/interface.go new file mode 100644 index 0000000..a5898c1 --- /dev/null +++ b/atomic/interface.go @@ -0,0 +1,108 @@ +/* + * MIT License + * + * Copyright (c) 2024 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package atomic + +import ( + "sync" + "sync/atomic" +) + +type Value[T any] interface { + SetDefaultLoad(def T) + SetDefaultStore(def T) + + Load() (val T) + Store(val T) + Swap(new T) (old T) + CompareAndSwap(old, new T) (swapped bool) +} + +type Map[K comparable] interface { + Load(key K) (value any, ok bool) + Store(key K, value any) + + LoadOrStore(key K, value any) (actual any, loaded bool) + LoadAndDelete(key K) (value any, loaded bool) + + Delete(key K) + Swap(key K, value any) (previous any, loaded bool) + + CompareAndSwap(key K, old, new any) bool + CompareAndDelete(key K, old any) (deleted bool) + + Range(f func(key K, value any) bool) +} + +type MapTyped[K comparable, V any] interface { + Load(key K) (value V, ok bool) + Store(key K, value V) + + LoadOrStore(key K, value V) (actual V, loaded bool) + LoadAndDelete(key K) (value V, loaded bool) + + Delete(key K) + Swap(key K, value V) (previous V, loaded bool) + + CompareAndSwap(key K, old, new V) bool + CompareAndDelete(key K, old V) (deleted bool) + + Range(f func(key K, value V) bool) +} + +func NewValue[T any]() Value[T] { + var ( + tmp1 T + tmp2 T + ) + + return NewValueDefault[T](tmp1, tmp2) +} + +func NewValueDefault[T any](load, store T) Value[T] { + o := &val[T]{ + av: new(atomic.Value), + dl: new(atomic.Value), + ds: new(atomic.Value), + } + + o.SetDefaultLoad(load) + o.SetDefaultStore(store) + + return o +} + +func NewMapAny[K comparable]() Map[K] { + return &ma[K]{ + m: sync.Map{}, + } +} + +func NewMapTyped[K comparable, V any]() MapTyped[K, V] { + return &mt[K, V]{ + m: NewMapAny[K](), + } +} diff --git a/atomic/mapany.go b/atomic/mapany.go new file mode 100644 index 0000000..244dc07 --- /dev/null +++ b/atomic/mapany.go @@ -0,0 +1,83 @@ +/* + * MIT License + * + * Copyright (c) 2024 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package atomic + +import ( + "sync" +) + +type ma[K comparable] struct { + m sync.Map +} + +func (o *ma[K]) Load(key K) (value any, ok bool) { + return o.m.Load(key) +} + +func (o *ma[K]) Store(key K, value any) { + o.m.Store(key, value) +} + +func (o *ma[K]) LoadOrStore(key K, value any) (actual any, loaded bool) { + return o.m.LoadOrStore(key, value) +} + +func (o *ma[K]) LoadAndDelete(key K) (value any, loaded bool) { + return o.m.LoadAndDelete(key) +} + +func (o *ma[K]) Delete(key K) { + o.m.Delete(key) +} + +func (o *ma[K]) Swap(key K, value any) (previous any, loaded bool) { + return o.m.Swap(key, value) +} + +func (o *ma[K]) CompareAndSwap(key K, old, new any) bool { + return o.m.CompareAndSwap(key, old, new) +} + +func (o *ma[K]) CompareAndDelete(key K, old any) (deleted bool) { + return o.m.CompareAndDelete(key, old) +} + +func (o *ma[K]) Range(f func(key K, value any) bool) { + o.m.Range(func(key, value any) bool { + var ( + l bool + k K + ) + + if k, l = Cast[K](key); !l { + o.m.Delete(key) + return true + } + + return f(k, value) + }) +} diff --git a/atomic/synmap.go b/atomic/synmap.go new file mode 100644 index 0000000..3248d7b --- /dev/null +++ b/atomic/synmap.go @@ -0,0 +1,91 @@ +/* + * MIT License + * + * Copyright (c) 2024 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package atomic + +type mt[K comparable, V any] struct { + m Map[K] +} + +func (o *mt[K, V]) cast(in any) (value V, ok bool) { + return Cast[V](in) +} + +func (o *mt[K, V]) castBool(in any, chk bool) (value V, ok bool) { + if chk { + return Cast[V](in) + } else { + return value, false + } +} + +func (o *mt[K, V]) Load(key K) (value V, ok bool) { + return o.castBool(o.m.Load(key)) +} + +func (o *mt[K, V]) Store(key K, value V) { + o.m.Store(key, value) +} + +func (o *mt[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) { + return o.castBool(o.m.LoadOrStore(key, value)) +} + +func (o *mt[K, V]) LoadAndDelete(key K) (value V, loaded bool) { + return o.castBool(o.m.LoadAndDelete(key)) +} + +func (o *mt[K, V]) Delete(key K) { + o.m.Delete(key) +} + +func (o *mt[K, V]) Swap(key K, value V) (previous V, loaded bool) { + return o.castBool(o.m.Swap(key, value)) +} + +func (o *mt[K, V]) CompareAndSwap(key K, old, new V) bool { + return o.m.CompareAndSwap(key, old, new) +} + +func (o *mt[K, V]) CompareAndDelete(key K, old V) (deleted bool) { + return o.m.CompareAndDelete(key, old) +} + +func (o *mt[K, V]) Range(f func(key K, value V) bool) { + o.m.Range(func(key K, value any) bool { + var ( + l bool + v V + ) + + if v, l = Cast[V](value); !l { + o.m.Delete(key) + return true + } + + return f(key, v) + }) +} diff --git a/atomic/value.go b/atomic/value.go new file mode 100644 index 0000000..ae67434 --- /dev/null +++ b/atomic/value.go @@ -0,0 +1,102 @@ +/* + * MIT License + * + * Copyright (c) 2024 Nicolas JUHEL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * + * + */ + +package atomic + +import ( + "sync/atomic" +) + +type val[T any] struct { + av *atomic.Value // atomic value of T + dl *atomic.Value // default value for load + ds *atomic.Value // default value for store +} + +func (o *val[T]) SetDefaultLoad(def T) { + o.dl.Store(newDefault[T](def)) +} + +func (o *val[T]) SetDefaultStore(def T) { + o.ds.Store(newDefault[T](def)) +} + +func (o *val[T]) getDefault(i any) T { + if v, k := Cast[defaultValue[T]](i); !k { + var tmp T + return tmp + } else { + return v.GetDefault() + } +} + +func (o *val[T]) getDefaultLoad() T { + return o.getDefault(o.dl.Load()) +} + +func (o *val[T]) getDefaultStore() T { + return o.getDefault(o.ds.Load()) +} + +func (o *val[T]) Load() (val T) { + if v, k := Cast[T](o.av.Load()); !k { + return o.getDefaultLoad() + } else { + return v + } +} + +func (o *val[T]) Store(val T) { + if IsEmpty[T](val) { + o.av.Store(o.getDefaultStore()) + } else { + o.av.Store(val) + } +} + +func (o *val[T]) Swap(new T) (old T) { + if IsEmpty[T](new) { + new = o.getDefaultStore() + } + + if v, k := Cast[T](o.av.Swap(new)); !k { + return o.getDefaultLoad() + } else { + return v + } +} + +func (o *val[T]) CompareAndSwap(old, new T) (swapped bool) { + if IsEmpty[T](old) { + old = o.getDefaultStore() + } + + if IsEmpty[T](new) { + new = o.getDefaultStore() + } + + return o.av.CompareAndSwap(old, new) +}