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