github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/x/generics/list/list.go (about) 1 // Copyright (c) 2019 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 // This is a doubly linked list with its internal elements pooled. This allows 22 // the list to be reused as a shared resource to prevent unnecessary 23 // allocations/GC. 24 25 // This implementation is a modification from Go's container/list source code. 26 // Here is its license: 27 28 // Copyright (c) 2009 The Go Authors. All rights reserved. 29 30 // Redistribution and use in source and binary forms, with or without 31 // modification, are permitted provided that the following conditions are 32 // met: 33 34 // * Redistributions of source code must retain the above copyright 35 // notice, this list of conditions and the following disclaimer. 36 // * Redistributions in binary form must reproduce the above 37 // copyright notice, this list of conditions and the following disclaimer 38 // in the documentation and/or other materials provided with the 39 // distribution. 40 // * Neither the name of Google Inc. nor the names of its 41 // contributors may be used to endorse or promote products derived from 42 // this software without specific prior written permission. 43 44 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 45 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 46 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 47 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 48 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 49 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 50 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 51 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 52 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 53 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 54 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 55 56 package list 57 58 import ( 59 "sync" 60 61 "github.com/m3db/m3/src/x/pool" 62 63 "github.com/mauricelam/genny/generic" 64 ) 65 66 // ValueType is the generic element type for use with the list. 67 type ValueType generic.Type 68 69 // Element is an element of a linked list. 70 type Element struct { 71 // Next and previous pointers in the doubly-linked list of elements. 72 // To simplify the implementation, internally a list l is implemented 73 // as a ring, such that &l.root is both the next element of the last 74 // list element (l.Back()) and the previous element of the first list 75 // element (l.Front()). 76 next, prev *Element 77 78 // The list to which this element belongs. 79 list *List 80 81 // The value stored with this element. 82 Value ValueType 83 } 84 85 // Next returns the next list element or nil. 86 func (e *Element) Next() *Element { 87 if p := e.next; e.list != nil && p != &e.list.root { 88 return p 89 } 90 return nil 91 } 92 93 // Prev returns the previous list element or nil. 94 func (e *Element) Prev() *Element { 95 if p := e.prev; e.list != nil && p != &e.list.root { 96 return p 97 } 98 return nil 99 } 100 101 // List represents a doubly linked list. 102 // The zero value is an empty, ready to use list. 103 type List struct { 104 root Element // sentinel list element, only &root, root.prev, and root.next are used 105 len int // current list length excluding (this) sentinel element 106 Pool *ElementPool 107 } 108 109 // Init initializes or clears list l. 110 func (l *List) Init() *List { 111 l.root.next = &l.root 112 l.root.prev = &l.root 113 l.len = 0 114 if l.Pool == nil { 115 // Use a static pool at least, otherwise each time 116 // we create a list with no pool we create a wholly 117 // new pool of finalizeables (4096 of them). 118 defaultElementPoolOnce.Do(initElementPool) 119 l.Pool = defaultElementPool 120 } 121 return l 122 } 123 124 var ( 125 defaultElementPoolOnce sync.Once 126 defaultElementPool *ElementPool 127 ) 128 129 // define as a static method so lambda alloc not required 130 // when passing function pointer to sync.Once.Do. 131 func initElementPool() { 132 defaultElementPool = newElementPool(nil) 133 } 134 135 // newList returns an initialized list. 136 func newList(p *ElementPool) *List { 137 l := &List{Pool: p} 138 return l.Init() 139 } 140 141 // Len returns the number of elements of list l. 142 // The complexity is O(1). 143 func (l *List) Len() int { return l.len } 144 145 // Front returns the first element of list l or nil if the list is empty. 146 func (l *List) Front() *Element { 147 if l.len == 0 { 148 return nil 149 } 150 return l.root.next 151 } 152 153 // Back returns the last element of list l or nil if the list is empty. 154 func (l *List) Back() *Element { 155 if l.len == 0 { 156 return nil 157 } 158 return l.root.prev 159 } 160 161 // lazyInit lazily initializes a zero List value. 162 func (l *List) lazyInit() { 163 if l.root.next == nil { 164 l.Init() 165 } 166 } 167 168 // insert inserts e after at, increments l.len, and returns e. 169 func (l *List) insert(e, at *Element) *Element { 170 n := at.next 171 at.next = e 172 e.prev = at 173 e.next = n 174 n.prev = e 175 e.list = l 176 l.len++ 177 return e 178 } 179 180 // insertValue is a convenience wrapper for inserting using the list's pool. 181 func (l *List) insertValue(v ValueType, at *Element) *Element { 182 e := l.Pool.get() 183 e.Value = v 184 return l.insert(e, at) 185 } 186 187 // remove removes e from its list, decrements l.len, and returns e. 188 func (l *List) remove(e *Element) *Element { 189 e.prev.next = e.next 190 e.next.prev = e.prev 191 e.next = nil // avoid memory leaks 192 e.prev = nil // avoid memory leaks 193 e.list = nil 194 l.len-- 195 return e 196 } 197 198 // Remove removes e from l if e is an element of list l. 199 // It returns the element value e.Value. 200 // The element must not be nil. 201 func (l *List) Remove(e *Element) ValueType { 202 // read the value before returning to the pool to avoid a data race with another goroutine getting access to the 203 // list after it has been put back into the pool. 204 v := e.Value 205 if e.list == l { 206 // if e.list == l, l must have been initialized when e was inserted 207 // in l or l == nil (e is a zero Element) and l.remove will crash. 208 l.remove(e) 209 l.Pool.put(e) 210 } 211 return v 212 } 213 214 // PushFront inserts a new element e with value v at the front of list l and returns e. 215 func (l *List) PushFront(v ValueType) *Element { 216 l.lazyInit() 217 return l.insertValue(v, &l.root) 218 } 219 220 // PushBack inserts a new element e with value v at the back of list l and returns e. 221 func (l *List) PushBack(v ValueType) *Element { 222 l.lazyInit() 223 return l.insertValue(v, l.root.prev) 224 } 225 226 // InsertBefore inserts a new element e with value v immediately before mark and returns e. 227 // If mark is not an element of l, the list is not modified. 228 // The mark must not be nil. 229 func (l *List) InsertBefore(v ValueType, mark *Element) *Element { 230 if mark.list != l { 231 return nil 232 } 233 // see comment in List.Remove about initialization of l 234 return l.insertValue(v, mark.prev) 235 } 236 237 // InsertAfter inserts a new element e with value v immediately after mark and returns e. 238 // If mark is not an element of l, the list is not modified. 239 // The mark must not be nil. 240 func (l *List) InsertAfter(v ValueType, mark *Element) *Element { 241 if mark.list != l { 242 return nil 243 } 244 // see comment in List.Remove about initialization of l 245 return l.insertValue(v, mark) 246 } 247 248 // MoveToFront moves element e to the front of list l. 249 // If e is not an element of l, the list is not modified. 250 // The element must not be nil. 251 func (l *List) MoveToFront(e *Element) { 252 if e.list != l || l.root.next == e { 253 return 254 } 255 // see comment in List.Remove about initialization of l 256 l.insert(l.remove(e), &l.root) 257 } 258 259 // MoveToBack moves element e to the back of list l. 260 // If e is not an element of l, the list is not modified. 261 // The element must not be nil. 262 func (l *List) MoveToBack(e *Element) { 263 if e.list != l || l.root.prev == e { 264 return 265 } 266 // see comment in List.Remove about initialization of l 267 l.insert(l.remove(e), l.root.prev) 268 } 269 270 // MoveBefore moves element e to its new position before mark. 271 // If e or mark is not an element of l, or e == mark, the list is not modified. 272 // The element and mark must not be nil. 273 func (l *List) MoveBefore(e, mark *Element) { 274 if e.list != l || e == mark || mark.list != l { 275 return 276 } 277 l.insert(l.remove(e), mark.prev) 278 } 279 280 // MoveAfter moves element e to its new position after mark. 281 // If e or mark is not an element of l, or e == mark, the list is not modified. 282 // The element and mark must not be nil. 283 func (l *List) MoveAfter(e, mark *Element) { 284 if e.list != l || e == mark || mark.list != l { 285 return 286 } 287 l.insert(l.remove(e), mark) 288 } 289 290 // PushBackList inserts a copy of an other list at the back of list l. 291 // The lists l and other may be the same. They must not be nil. 292 func (l *List) PushBackList(other *List) { 293 l.lazyInit() 294 for i, e := other.Len(), other.Front(); i > 0; i, e = i-1, e.Next() { 295 l.insertValue(e.Value, l.root.prev) 296 } 297 } 298 299 // PushFrontList inserts a copy of an other list at the front of list l. 300 // The lists l and other may be the same. They must not be nil. 301 func (l *List) PushFrontList(other *List) { 302 l.lazyInit() 303 for i, e := other.Len(), other.Back(); i > 0; i, e = i-1, e.Prev() { 304 l.insertValue(e.Value, &l.root) 305 } 306 } 307 308 // Reset resets list l for reuse and puts all elements back into the pool. 309 func (l *List) Reset() { 310 for e := l.Back(); e != nil; e = l.Back() { 311 l.Remove(e) 312 } 313 } 314 315 // ElementPool provides a pool for Elements. 316 type ElementPool struct { 317 pool pool.ObjectPool 318 } 319 320 // Get gets an Element from the pool. 321 func (p *ElementPool) get() *Element { 322 return p.pool.Get().(*Element) 323 } 324 325 // Put puts an Element back into the pool. 326 func (p *ElementPool) put(e *Element) { 327 p.pool.Put(e) 328 } 329 330 // newElementPool creates a new generic ElementPool. 331 func newElementPool(opts pool.ObjectPoolOptions) *ElementPool { 332 p := &ElementPool{pool: pool.NewObjectPool(opts)} 333 p.pool.Init(func() interface{} { 334 return &Element{} 335 }) 336 return p 337 }