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  }