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  }