github.com/aacfactory/rings@v1.1.2/immutable.go (about)

     1  package rings
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"math"
     7  	"unsafe"
     8  )
     9  
    10  func NewImmutable[E Entry](key string, values []E) (r *ImmutableRing[E]) {
    11  	if values == nil || len(values) == 0 {
    12  		panic(fmt.Errorf("new immutable ring failed, cause values is nil or empty"))
    13  		return
    14  	}
    15  	keys := make(map[string]int)
    16  	for _, value := range values {
    17  		n := keys[value.Key()]
    18  		n++
    19  		keys[value.Key()] = n
    20  	}
    21  	err := ""
    22  	for vk, n := range keys {
    23  		if n > 1 {
    24  			err = err + ", " + vk
    25  		}
    26  	}
    27  	if err != "" {
    28  		panic(fmt.Errorf("new immutable ring failed cause [%s] has duplicated", err[2:]))
    29  		return
    30  	}
    31  	valuesLen := uint32(len(values))
    32  	capacity := uint32(0)
    33  	doubleTimes := uint32(1)
    34  	for {
    35  		capacity = uint32(math.Pow(float64(2), float64(doubleTimes)))
    36  		if capacity >= valuesLen {
    37  			break
    38  		}
    39  		doubleTimes++
    40  	}
    41  	filledValues := make([]E, capacity)
    42  	for i := uint32(0); i < capacity; i++ {
    43  		idx := i % valuesLen
    44  		filledValues[i] = values[idx]
    45  	}
    46  
    47  	var elements []*element[E] = nil
    48  	align := uint32(unsafe.Alignof(elements))
    49  	mask := capacity - 1
    50  	shift := uint32(math.Log2(float64(capacity)))
    51  	elements = make([]*element[E], capacity*align)
    52  	for i := range elements {
    53  		elements[i] = &element[E]{}
    54  	}
    55  
    56  	elementBasePtr := uintptr(unsafe.Pointer(&elements[0]))
    57  	elementMSize := unsafe.Sizeof(elements[0])
    58  
    59  	r = &ImmutableRing[E]{
    60  		key:            key,
    61  		sequence:       NewSequence(),
    62  		size:           capacity,
    63  		shift:          shift,
    64  		align:          align,
    65  		mask:           mask,
    66  		elements:       elements,
    67  		elementBasePtr: elementBasePtr,
    68  		elementMSize:   elementMSize,
    69  	}
    70  
    71  	for i := uint32(0); i < capacity; i++ {
    72  		r.elementAt(i).value = filledValues[i]
    73  	}
    74  
    75  	return
    76  }
    77  
    78  type ImmutableRing[E Entry] struct {
    79  	sequence       *Sequence
    80  	elements       []*element[E]
    81  	size           uint32
    82  	shift          uint32
    83  	align          uint32
    84  	mask           uint32
    85  	elementBasePtr uintptr
    86  	elementMSize   uintptr
    87  	key            string
    88  }
    89  
    90  func (r *ImmutableRing[E]) Key() (key string) {
    91  	key = r.key
    92  	return
    93  }
    94  
    95  func (r *ImmutableRing[E]) Next() (value E) {
    96  	idx := r.sequence.Next() % r.size
    97  	e := r.elementAt(idx)
    98  	value = e.value
    99  	return
   100  }
   101  
   102  func (r *ImmutableRing[E]) Head() (value E, has bool) {
   103  	e := r.elementAt(r.sequence.Value())
   104  	value = e.value
   105  	has = true
   106  	return
   107  }
   108  
   109  func (r *ImmutableRing[E]) Get(key string) (value E, has bool) {
   110  	for i := uint32(0); i < r.size; i++ {
   111  		e := r.elementAt(i)
   112  		if e.value.Key() == key {
   113  			value = e.value
   114  			has = true
   115  			break
   116  		}
   117  	}
   118  	return
   119  }
   120  
   121  func (r *ImmutableRing[E]) String() (value string) {
   122  	p := bytes.NewBufferString("")
   123  	_ = p.WriteByte('[')
   124  	for i := uint32(0); i < r.size; i++ {
   125  		e := r.elementAt(i)
   126  		if i == 0 {
   127  			_, _ = p.WriteString(e.value.Key())
   128  		} else {
   129  			_, _ = p.WriteString(", ")
   130  			_, _ = p.WriteString(e.value.Key())
   131  		}
   132  	}
   133  	_ = p.WriteByte(']')
   134  	value = p.String()
   135  	return
   136  }
   137  
   138  func (r *ImmutableRing[E]) elementAt(idx uint32) (e *element[E]) {
   139  	elementPtr := r.elementBasePtr + uintptr(idx&r.mask*r.align)*r.elementMSize
   140  	e = *((*(*element[E]))(unsafe.Pointer(elementPtr)))
   141  	return
   142  }
   143  
   144  type element[E Entry] struct {
   145  	value E
   146  }