github.com/min1324/cmap@v1.0.3-0.20220418125848-74e72bbe3be4/fmap.go (about) 1 package cmap 2 3 import ( 4 "sync" 5 "sync/atomic" 6 ) 7 8 const ( 9 bBit = 5 10 bMask uintptr = 1<<bBit - 1 11 ) 12 13 // FMap has fixation len bucket map 14 type FMap struct { 15 count int64 // number of element 16 bucket [bMask + 1]sync.Map 17 } 18 19 func (m *FMap) getBucket(i uintptr) *sync.Map { 20 return &m.bucket[i&bMask] 21 } 22 23 // Load returns the value stored in the map for a key, or nil if no 24 // value is present. 25 // The ok result indicates whether value was found in the map. 26 func (m *FMap) Load(key interface{}) (value interface{}, ok bool) { 27 hash := chash(key) 28 b := m.getBucket(hash) 29 return b.Load(key) 30 } 31 32 // Store sets the value for a key. 33 func (m *FMap) Store(key, value interface{}) { 34 hash := chash(key) 35 b := m.getBucket(hash) 36 _, loaded := b.LoadOrStore(key, value) 37 if loaded { 38 b.Store(key, value) 39 } else { 40 atomic.AddInt64(&m.count, 1) 41 } 42 } 43 44 // LoadOrStore returns the existing value for the key if present. 45 // Otherwise, it stores and returns the given value. 46 // The loaded result is true if the value was loaded, false if stored. 47 func (m *FMap) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) { 48 hash := chash(key) 49 b := m.getBucket(hash) 50 actual, loaded = b.LoadOrStore(key, value) 51 if !loaded { 52 atomic.AddInt64(&m.count, 1) 53 } 54 return 55 } 56 57 // Delete deletes the value for a key. 58 func (m *FMap) Delete(key interface{}) { 59 m.LoadAndDelete(key) 60 } 61 62 // LoadAndDelete deletes the value for a key, returning the previous value if any. 63 // The loaded result reports whether the key was present. 64 func (m *FMap) LoadAndDelete(key interface{}) (value interface{}, loaded bool) { 65 hash := chash(key) 66 b := m.getBucket(hash) 67 value, loaded = b.LoadAndDelete(key) 68 if loaded { 69 atomic.AddInt64(&m.count, ^int64(0)) 70 } 71 return 72 } 73 74 // Range calls f sequentially for each key and value present in the map. 75 // If f returns false, range stops the iteration. 76 // 77 // Range does not necessarily correspond to any consistent snapshot of the Map's 78 // contents: no key will be visited more than once, but if the value for any key 79 // is stored or deleted concurrently, Range may reflect any mapping for that key 80 // from any point during the Range call. 81 // 82 // Range may be O(N) with the number of elements in the map even if f returns 83 // false after a constant number of calls. 84 func (m *FMap) Range(f func(key, value interface{}) bool) { 85 var flag = true 86 for i := 0; i <= len(m.bucket); i++ { 87 b := m.getBucket(uintptr(i)) 88 b.Range(func(key, value interface{}) bool { 89 flag = f(key, value) 90 return flag 91 }) 92 if !flag { 93 return 94 } 95 } 96 } 97 98 // Count returns the number of elements within the map. 99 func (m *FMap) Count() int64 { 100 return atomic.LoadInt64(&m.count) 101 }