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

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