github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/zarray/list.go (about)

     1  //go:build go1.18
     2  // +build go1.18
     3  
     4  package zarray
     5  
     6  import (
     7  	"sync/atomic"
     8  	"unsafe"
     9  
    10  	"github.com/sohaha/zlsgo/zutil"
    11  )
    12  
    13  const (
    14  	notDeleted uint32 = iota
    15  	deleted
    16  )
    17  
    18  type atomicPointer[T any] struct {
    19  	_   zutil.Nocmp
    20  	ptr unsafe.Pointer
    21  }
    22  
    23  func (p *atomicPointer[T]) Load() *T     { return (*T)(atomic.LoadPointer(&p.ptr)) }
    24  func (p *atomicPointer[T]) Store(v *T)   { atomic.StorePointer(&p.ptr, unsafe.Pointer(v)) }
    25  func (p *atomicPointer[T]) Swap(v *T) *T { return (*T)(atomic.SwapPointer(&p.ptr, unsafe.Pointer(v))) }
    26  func (p *atomicPointer[T]) CompareAndSwap(old, new *T) bool {
    27  	return atomic.CompareAndSwapPointer(&p.ptr, unsafe.Pointer(old), unsafe.Pointer(new))
    28  }
    29  
    30  func newListHead[K hashable, V any]() *element[K, V] {
    31  	e := &element[K, V]{keyHash: 0, key: *new(K)}
    32  	e.nextPtr.Store(nil)
    33  	e.value.Store(new(V))
    34  	return e
    35  }
    36  
    37  type element[K hashable, V any] struct {
    38  	key     K
    39  	nextPtr atomicPointer[element[K, V]]
    40  	value   atomicPointer[V]
    41  	keyHash uintptr
    42  	deleted uint32
    43  }
    44  
    45  func (self *element[K, V]) next() *element[K, V] {
    46  	for nextElement := self.nextPtr.Load(); nextElement != nil; {
    47  		if nextElement.isDeleted() {
    48  			self.nextPtr.CompareAndSwap(nextElement, nextElement.next())
    49  			nextElement = self.nextPtr.Load()
    50  		} else {
    51  			return nextElement
    52  		}
    53  	}
    54  	return nil
    55  }
    56  
    57  func (self *element[K, V]) addBefore(allocatedElement, before *element[K, V]) bool {
    58  	if self.next() != before {
    59  		return false
    60  	}
    61  	allocatedElement.nextPtr.Store(before)
    62  	return self.nextPtr.CompareAndSwap(before, allocatedElement)
    63  }
    64  
    65  func (self *element[K, V]) inject(c uintptr, key K, value *V) (*element[K, V], bool) {
    66  	var (
    67  		alloc             *element[K, V]
    68  		left, curr, right = self.search(c, key)
    69  	)
    70  	if curr != nil {
    71  		curr.value.Store(value)
    72  		return curr, false
    73  	}
    74  	if left != nil {
    75  		alloc = &element[K, V]{keyHash: c, key: key}
    76  		alloc.value.Store(value)
    77  		if left.addBefore(alloc, right) {
    78  			return alloc, true
    79  		}
    80  	}
    81  	return nil, false
    82  }
    83  
    84  func (self *element[K, V]) search(c uintptr, key K) (*element[K, V], *element[K, V], *element[K, V]) {
    85  	var (
    86  		left, right *element[K, V]
    87  		curr        = self
    88  	)
    89  	for {
    90  		if curr == nil {
    91  			return left, curr, right
    92  		}
    93  		right = curr.next()
    94  		if c < curr.keyHash {
    95  			right = curr
    96  			curr = nil
    97  			return left, curr, right
    98  		} else if c == curr.keyHash && key == curr.key {
    99  			return left, curr, right
   100  		}
   101  		left = curr
   102  		curr = left.next()
   103  		right = nil
   104  	}
   105  }
   106  
   107  func (self *element[K, V]) remove() bool {
   108  	return atomic.CompareAndSwapUint32(&self.deleted, notDeleted, deleted)
   109  }
   110  
   111  func (self *element[K, V]) isDeleted() bool {
   112  	return atomic.LoadUint32(&self.deleted) == deleted
   113  }