mirror of
https://github.com/phishingclub/phishingclub.git
synced 2026-10-04 14:36:50 +02:00
275 lines
6.2 KiB
Go
275 lines
6.2 KiB
Go
package g
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"sync"
|
|
"sync/atomic"
|
|
)
|
|
|
|
// MapSafe is a concurrent-safe generic map built on sync.Map.
|
|
type MapSafe[K comparable, V any] struct {
|
|
data sync.Map
|
|
count atomic.Int64
|
|
structMu sync.RWMutex // coordinates key-presence changes with Clear
|
|
}
|
|
|
|
// NewMapSafe creates a new instance of MapSafe.
|
|
func NewMapSafe[K comparable, V any]() *MapSafe[K, V] { return &MapSafe[K, V]{} }
|
|
|
|
// MapSafeOf creates a new MapSafe from the provided key-value pairs.
|
|
// Duplicate keys keep the last-written value, mirroring MapOf / MapOrdOf.
|
|
func MapSafeOf[K comparable, V any](pairs ...Pair[K, V]) *MapSafe[K, V] {
|
|
ms := NewMapSafe[K, V]()
|
|
for _, p := range pairs {
|
|
ms.Insert(p.Unpack())
|
|
}
|
|
|
|
return ms
|
|
}
|
|
|
|
// Transform applies a transformation function to the MapSafe and returns the result.
|
|
func (ms *MapSafe[K, V]) Transform[U any](fn func(*MapSafe[K, V]) U) U {
|
|
return fn(ms)
|
|
}
|
|
|
|
// Iter provides a thread-safe iterator over the MapSafe's key-value pairs.
|
|
func (ms *MapSafe[K, V]) Iter() Seq2[K, V] {
|
|
return func(yield func(K, V) bool) {
|
|
ms.data.Range(func(key, value any) bool {
|
|
return yield(key.(K), *(value.(*V)))
|
|
})
|
|
}
|
|
}
|
|
|
|
// Entry returns a SafeEntry for the given key.
|
|
func (ms *MapSafe[K, V]) Entry(key K) SafeEntry[K, V] {
|
|
if _, ok := ms.data.Load(key); ok {
|
|
return OccupiedSafeEntry[K, V]{m: ms, key: key}
|
|
}
|
|
|
|
return VacantSafeEntry[K, V]{m: ms, key: key}
|
|
}
|
|
|
|
// Keys returns a slice of the MapSafe's keys.
|
|
func (ms *MapSafe[K, V]) Keys() Slice[K] {
|
|
keys := NewSlice[K](0, ms.Len())
|
|
|
|
ms.data.Range(func(key, _ any) bool {
|
|
keys = append(keys, key.(K))
|
|
return true
|
|
})
|
|
|
|
return keys
|
|
}
|
|
|
|
// Values returns a slice of the MapSafe's values.
|
|
func (ms *MapSafe[K, V]) Values() Slice[V] {
|
|
values := NewSlice[V](0, ms.Len())
|
|
|
|
ms.data.Range(func(_, value any) bool {
|
|
values = append(values, *(value.(*V)))
|
|
return true
|
|
})
|
|
|
|
return values
|
|
}
|
|
|
|
// Contains checks if the MapSafe contains the specified key.
|
|
func (ms *MapSafe[K, V]) Contains(key K) bool {
|
|
_, ok := ms.data.Load(key)
|
|
return ok
|
|
}
|
|
|
|
// Clone creates a deep copy of the MapSafe.
|
|
func (ms *MapSafe[K, V]) Clone() *MapSafe[K, V] {
|
|
res := NewMapSafe[K, V]()
|
|
|
|
ms.data.Range(func(key, value any) bool {
|
|
v := *(value.(*V))
|
|
res.data.Store(key, &v)
|
|
res.count.Add(1)
|
|
return true
|
|
})
|
|
|
|
return res
|
|
}
|
|
|
|
// Copy performs a deep copy of the source MapSafe's pairs into the current map.
|
|
func (ms *MapSafe[K, V]) Copy(src *MapSafe[K, V]) {
|
|
ms.structMu.RLock()
|
|
defer ms.structMu.RUnlock()
|
|
|
|
src.data.Range(func(key, value any) bool {
|
|
v := *(value.(*V))
|
|
_, loaded := ms.data.Swap(key, &v)
|
|
if !loaded {
|
|
ms.count.Add(1)
|
|
}
|
|
|
|
return true
|
|
})
|
|
}
|
|
|
|
// Remove removes the specified key from the MapSafe and returns the removed value.
|
|
func (ms *MapSafe[K, V]) Remove(key K) Option[V] {
|
|
ms.structMu.RLock()
|
|
defer ms.structMu.RUnlock()
|
|
|
|
if v, loaded := ms.data.LoadAndDelete(key); loaded {
|
|
ms.count.Add(-1)
|
|
return Some(*(v.(*V)))
|
|
}
|
|
|
|
return None[V]()
|
|
}
|
|
|
|
// Eq checks if two MapSafes are equal by deep-comparing their values.
|
|
func (ms *MapSafe[K, V]) Eq(other *MapSafe[K, V]) bool {
|
|
n := ms.Len()
|
|
if n != other.Len() {
|
|
return false
|
|
}
|
|
|
|
if n == 0 {
|
|
return true
|
|
}
|
|
|
|
comparable := isValueComparable[V]()
|
|
equal := true
|
|
|
|
ms.data.Range(func(key, value any) bool {
|
|
ovalue, ok := other.data.Load(key)
|
|
if !ok {
|
|
equal = false
|
|
return false
|
|
}
|
|
|
|
v1 := *(value.(*V))
|
|
v2 := *(ovalue.(*V))
|
|
|
|
if comparable {
|
|
if any(v1) != any(v2) {
|
|
equal = false
|
|
return false
|
|
}
|
|
} else {
|
|
if !reflect.DeepEqual(v1, v2) {
|
|
equal = false
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
})
|
|
|
|
return equal
|
|
}
|
|
|
|
// Get retrieves the value associated with the given key.
|
|
func (ms *MapSafe[K, V]) Get(key K) Option[V] {
|
|
if value, ok := ms.data.Load(key); ok {
|
|
return Some(*(value.(*V)))
|
|
}
|
|
|
|
return None[V]()
|
|
}
|
|
|
|
// Insert stores the value for the given key.
|
|
// Returns Some(previous_value) if the key existed, None if it was newly inserted.
|
|
//
|
|
// Example:
|
|
//
|
|
// ms := NewMapSafe[string, int]()
|
|
// ms.Insert("a", 1) // None (new key)
|
|
// ms.Insert("a", 2) // Some(1) (replaced)
|
|
// ms.Get("a").Some() // 2
|
|
func (ms *MapSafe[K, V]) Insert(key K, value V) Option[V] {
|
|
ms.structMu.RLock()
|
|
defer ms.structMu.RUnlock()
|
|
|
|
if previous, loaded := ms.data.Swap(key, &value); loaded {
|
|
return Some(*(previous.(*V)))
|
|
}
|
|
|
|
ms.count.Add(1)
|
|
return None[V]()
|
|
}
|
|
|
|
// TryInsert inserts value only if the key is absent.
|
|
// Returns Some(existing_value) if key already existed (no insert), None if inserted.
|
|
//
|
|
// Example:
|
|
//
|
|
// ms := NewMapSafe[string, int]()
|
|
// ms.TryInsert("a", 1) // None (inserted)
|
|
// ms.TryInsert("a", 2) // Some(1) (already existed, not replaced)
|
|
// ms.Get("a").Some() // 1
|
|
func (ms *MapSafe[K, V]) TryInsert(key K, value V) Option[V] {
|
|
ms.structMu.RLock()
|
|
defer ms.structMu.RUnlock()
|
|
|
|
if actual, loaded := ms.data.LoadOrStore(key, &value); loaded {
|
|
return Some(*(actual.(*V)))
|
|
}
|
|
|
|
ms.count.Add(1)
|
|
return None[V]()
|
|
}
|
|
|
|
// Len returns the number of key-value pairs in the MapSafe.
|
|
func (ms *MapSafe[K, V]) Len() Int { return Int(ms.count.Load()) }
|
|
|
|
// Ne checks if two MapSafes are not equal.
|
|
func (ms *MapSafe[K, V]) Ne(other *MapSafe[K, V]) bool { return !ms.Eq(other) }
|
|
|
|
// Clear removes all key-value pairs from the MapSafe.
|
|
func (ms *MapSafe[K, V]) Clear() {
|
|
ms.structMu.Lock()
|
|
defer ms.structMu.Unlock()
|
|
|
|
ms.data.Clear()
|
|
ms.count.Store(0)
|
|
}
|
|
|
|
// IsEmpty checks if the MapSafe is empty.
|
|
func (ms *MapSafe[K, V]) IsEmpty() bool { return ms.count.Load() == 0 }
|
|
|
|
// String returns a string representation of the MapSafe.
|
|
func (ms *MapSafe[K, V]) String() string {
|
|
var b Builder
|
|
b.Grow(ms.Len() * 16)
|
|
b.WriteString("MapSafe{")
|
|
|
|
first := true
|
|
|
|
ms.data.Range(func(key, value any) bool {
|
|
if !first {
|
|
b.WriteString(", ")
|
|
}
|
|
|
|
first = false
|
|
|
|
if vptr, ok := value.(*V); ok && vptr != nil {
|
|
fmt.Fprint(&b, key)
|
|
b.WriteByte(':')
|
|
fmt.Fprint(&b, *vptr)
|
|
} else {
|
|
fmt.Fprint(&b, key)
|
|
b.WriteString(":<invalid>")
|
|
}
|
|
|
|
return true
|
|
})
|
|
|
|
b.WriteString("}")
|
|
|
|
return b.String().Std()
|
|
}
|
|
|
|
// Print writes the MapSafe to standard output.
|
|
func (ms *MapSafe[K, V]) Print() *MapSafe[K, V] { fmt.Print(ms); return ms }
|
|
|
|
// Println writes the MapSafe to standard output with a newline.
|
|
func (ms *MapSafe[K, V]) Println() *MapSafe[K, V] { fmt.Println(ms); return ms }
|