github.com/andy2046/gopie@v0.7.0/pkg/skiplist/skiplist.go (about)

     1  // Package skiplist provides a Skip List implementation.
     2  package skiplist
     3  
     4  import (
     5  	"math"
     6  	"math/rand"
     7  	"time"
     8  )
     9  
    10  const (
    11  	defaultMaxLevel int = 16
    12  
    13  	defaultProbability float64 = 1 / math.E
    14  )
    15  
    16  // New creates a new skip list with provided maxLevel or defaultMaxLevel.
    17  func New(maxLevel ...int) *SkipList {
    18  	level := defaultMaxLevel
    19  	if len(maxLevel) > 0 && maxLevel[0] >= 1 && maxLevel[0] <= 64 {
    20  		level = maxLevel[0]
    21  	}
    22  
    23  	return &SkipList{
    24  		elementNode:      elementNode{forward: make([]*Element, level)},
    25  		searchNodesCache: make([]*elementNode, level),
    26  		maxLevel:         level,
    27  		randSource:       rand.New(rand.NewSource(time.Now().UnixNano())),
    28  		probability:      defaultProbability,
    29  		probTable:        probabilityTable(defaultProbability, level),
    30  	}
    31  }
    32  
    33  // Front returns the first element in the list.
    34  func (list *SkipList) Front() *Element {
    35  	return list.forward[0]
    36  }
    37  
    38  // Len returns the list length.
    39  func (list *SkipList) Len() int {
    40  	list.mutex.RLock()
    41  	defer list.mutex.RUnlock()
    42  	return list.length
    43  }
    44  
    45  // MaxLevel sets current max level of skip list and returns the previous max level.
    46  // If `level` < 1, it does not set current max level.
    47  func (list *SkipList) MaxLevel(level int) int {
    48  	if level < 1 || list.maxLevel == level {
    49  		return list.maxLevel
    50  	}
    51  
    52  	list.mutex.Lock()
    53  	defer list.mutex.Unlock()
    54  	prev := list.maxLevel
    55  	list.maxLevel = level
    56  
    57  	switch {
    58  	case prev > level:
    59  		for k, n := level, len(list.forward); k < n; k++ {
    60  			list.forward[k] = nil // avoid mem leak
    61  		}
    62  		list.forward = list.forward[:level]
    63  		for k, n := level, len(list.searchNodesCache); k < n; k++ {
    64  			list.searchNodesCache[k] = nil // avoid mem leak
    65  		}
    66  		list.searchNodesCache = list.searchNodesCache[:level]
    67  		list.probTable = list.probTable[:level]
    68  	case prev < level:
    69  		f := make([]*Element, level)
    70  		copy(f, list.forward)
    71  		for i := range list.forward {
    72  			list.forward[i] = nil // avoid mem leak
    73  		}
    74  		list.forward = f
    75  		for i := range list.searchNodesCache {
    76  			list.searchNodesCache[i] = nil // avoid mem leak
    77  		}
    78  		list.searchNodesCache = make([]*elementNode, level)
    79  		list.probTable = probabilityTable(list.probability, level)
    80  	}
    81  
    82  	return prev
    83  }
    84  
    85  // Set upserts the value with provided key into the list and returns the element.
    86  func (list *SkipList) Set(key string, value int64) *Element {
    87  	list.mutex.Lock()
    88  	defer list.mutex.Unlock()
    89  
    90  	var element *Element
    91  	fingerSearches := list.fingerSearchNodes(key)
    92  
    93  	if element = fingerSearches[0].forward[0]; element != nil && element.key <= key {
    94  		element.value = value
    95  		return element
    96  	}
    97  
    98  	element = &Element{
    99  		elementNode: elementNode{
   100  			forward: make([]*Element, list.randLevel()),
   101  		},
   102  		key:   key,
   103  		value: value,
   104  	}
   105  
   106  	for i := range element.forward {
   107  		element.forward[i] = fingerSearches[i].forward[i]
   108  		fingerSearches[i].forward[i] = element
   109  	}
   110  
   111  	list.length++
   112  	return element
   113  }
   114  
   115  // Get searches element by provided key and returns the element if found or nil otherwise.
   116  func (list *SkipList) Get(key string) *Element {
   117  	list.mutex.Lock()
   118  	defer list.mutex.Unlock()
   119  
   120  	var next *Element
   121  	prev := &list.elementNode
   122  
   123  	for i := list.maxLevel - 1; i >= 0; i-- {
   124  		next = prev.forward[i]
   125  
   126  		for next != nil && key > next.key {
   127  			prev = &next.elementNode
   128  			next = next.forward[i]
   129  		}
   130  	}
   131  
   132  	if next != nil && next.key <= key {
   133  		return next
   134  	}
   135  
   136  	return nil
   137  }
   138  
   139  // Remove deletes the element with provided key from the list,
   140  // and returns the removed element if found or nil otherwise.
   141  func (list *SkipList) Remove(key string) *Element {
   142  	list.mutex.Lock()
   143  	defer list.mutex.Unlock()
   144  
   145  	fingerSearches := list.fingerSearchNodes(key)
   146  
   147  	if element := fingerSearches[0].forward[0]; element != nil && element.key <= key {
   148  		for k, v := range element.forward {
   149  			fingerSearches[k].forward[k] = v
   150  		}
   151  
   152  		list.length--
   153  		return element
   154  	}
   155  
   156  	return nil
   157  }
   158  
   159  // fingerSearchNodes returns a list of nodes, where nodes[i] contains a pointer to the rightmost node
   160  // of level i or higher that is to the left of the location of the `key`.
   161  func (list *SkipList) fingerSearchNodes(key string) []*elementNode {
   162  	var next *Element
   163  	prev := &list.elementNode
   164  	fingerSearches := list.searchNodesCache
   165  
   166  	for i := list.maxLevel - 1; i >= 0; i-- {
   167  		next = prev.forward[i]
   168  
   169  		for next != nil && key > next.key {
   170  			prev = &next.elementNode
   171  			next = next.forward[i]
   172  		}
   173  
   174  		fingerSearches[i] = prev
   175  	}
   176  
   177  	return fingerSearches
   178  }
   179  
   180  func (list *SkipList) randLevel() int {
   181  	r := float64(list.randSource.Int63()) / (1 << 63)
   182  	level := 1
   183  	for level < list.maxLevel && r < list.probTable[level] {
   184  		level++
   185  	}
   186  	return level
   187  }
   188  
   189  // Probability sets the P value of skip list and returns the previous P.
   190  // If `newProbability` < 0, it does not set current P.
   191  func (list *SkipList) Probability(newProbability float64) float64 {
   192  	p := list.probability
   193  	if newProbability >= 0 {
   194  		list.mutex.Lock()
   195  		defer list.mutex.Unlock()
   196  		list.probability = newProbability
   197  		list.probTable = probabilityTable(newProbability, list.maxLevel)
   198  	}
   199  	return p
   200  }
   201  
   202  // probabilityTable stores the probability for a new node appearing in a given level,
   203  // probability is in [0, 1], maxLevel is in (0, 64].
   204  func probabilityTable(probability float64, maxLevel int) []float64 {
   205  	t := make([]float64, 0, maxLevel)
   206  	for i := 1; i <= maxLevel; i++ {
   207  		t = append(t, math.Pow(probability, float64(i-1)))
   208  	}
   209  	return t
   210  }