github.com/ergo-services/ergo@v1.999.224/etf/cache.go (about) 1 package etf 2 3 import ( 4 "sync" 5 ) 6 7 const ( 8 maxCacheItems = int16(2048) 9 ) 10 11 type AtomCache struct { 12 In *AtomCacheIn 13 Out *AtomCacheOut 14 } 15 16 type AtomCacheIn struct { 17 Atoms [maxCacheItems]*Atom 18 } 19 20 // AtomCache 21 type AtomCacheOut struct { 22 sync.RWMutex 23 cacheMap map[Atom]int16 24 id int16 25 cacheList [maxCacheItems]Atom 26 } 27 28 // CacheItem 29 type CacheItem struct { 30 ID int16 31 Encoded bool 32 Name Atom 33 } 34 35 var ( 36 encodingAtomCachePool = &sync.Pool{ 37 New: func() interface{} { 38 l := &EncodingAtomCache{ 39 L: make([]CacheItem, 0, 255), 40 added: make(map[Atom]uint8), 41 } 42 l.original = l.L 43 return l 44 }, 45 } 46 ) 47 48 // NewAtomCache 49 func NewAtomCache() AtomCache { 50 return AtomCache{ 51 In: &AtomCacheIn{}, 52 Out: &AtomCacheOut{ 53 cacheMap: make(map[Atom]int16), 54 id: -1, 55 }, 56 } 57 } 58 59 type AtomMapping struct { 60 MutexIn sync.RWMutex 61 In map[Atom]Atom 62 MutexOut sync.RWMutex 63 Out map[Atom]Atom 64 } 65 66 // NewAtomMapping 67 func NewAtomMapping() *AtomMapping { 68 return &AtomMapping{ 69 In: make(map[Atom]Atom), 70 Out: make(map[Atom]Atom), 71 } 72 } 73 74 // Append 75 func (a *AtomCacheOut) Append(atom Atom) (int16, bool) { 76 a.Lock() 77 defer a.Unlock() 78 79 if a.id > maxCacheItems-2 { 80 return 0, false 81 } 82 83 if id, exist := a.cacheMap[atom]; exist { 84 return id, false 85 } 86 87 a.id++ 88 a.cacheList[a.id] = atom 89 a.cacheMap[atom] = a.id 90 91 return a.id, true 92 } 93 94 // LastID 95 func (a *AtomCacheOut) LastAdded() (Atom, int16) { 96 a.RLock() 97 defer a.RUnlock() 98 l := len(a.cacheList) 99 if l == 0 { 100 return "", -1 101 } 102 return a.cacheList[l-1], int16(l - 1) 103 } 104 105 // ListSince 106 func (a *AtomCacheOut) ListSince(id int16) []Atom { 107 if id < 0 { 108 id = 0 109 } 110 if int(id) > len(a.cacheList)-1 { 111 return nil 112 } 113 return a.cacheList[id:] 114 } 115 116 // EncodingAtomCache 117 type EncodingAtomCache struct { 118 L []CacheItem 119 original []CacheItem 120 added map[Atom]uint8 121 HasLongAtom bool 122 } 123 124 // TakeEncodingAtomCache 125 func TakeEncodingAtomCache() *EncodingAtomCache { 126 return encodingAtomCachePool.Get().(*EncodingAtomCache) 127 } 128 129 // ReleaseEncodingAtomCache 130 func ReleaseEncodingAtomCache(l *EncodingAtomCache) { 131 l.L = l.original[:0] 132 if len(l.added) > 0 { 133 for k, _ := range l.added { 134 delete(l.added, k) 135 } 136 } 137 encodingAtomCachePool.Put(l) 138 } 139 140 // Reset 141 func (l *EncodingAtomCache) Reset() { 142 l.L = l.original[:0] 143 l.HasLongAtom = false 144 if len(l.added) > 0 { 145 for k, _ := range l.added { 146 delete(l.added, k) 147 } 148 } 149 } 150 151 // Append 152 func (l *EncodingAtomCache) Append(a CacheItem) uint8 { 153 id, added := l.added[a.Name] 154 if added { 155 return id 156 } 157 158 l.L = append(l.L, a) 159 if !a.Encoded && len(a.Name) > 255 { 160 l.HasLongAtom = true 161 } 162 id = uint8(len(l.L) - 1) 163 l.added[a.Name] = id 164 return id 165 } 166 167 // Delete 168 func (l *EncodingAtomCache) Delete(atom Atom) { 169 // clean up in order to get rid of map reallocation which is pretty expensive 170 delete(l.added, atom) 171 } 172 173 // Len 174 func (l *EncodingAtomCache) Len() int { 175 return len(l.L) 176 }