// Copyright (c) 2015-2016 The btcsuite developers // Use of this source code is governed by an ISC // license that can be found in the LICENSE file. package treap import ( "math/rand" "sync" "time" ) const ( // staticDepth is the size of the static array to use for keeping track // of the parent stack during treap iteration. Since a treap has a very // high probability that the tree height is logarithmic, it is // exceedingly unlikely that the parent stack will ever exceed this size // even for extremely large numbers of items. staticDepth = 128 // nodeFieldsSize is the size the fields of each node takes excluding // the contents of the key and value. It assumes 64-bit pointers so // technically it is smaller on 32-bit platforms, but overestimating the // size in that case is acceptable since it avoids the need to import // unsafe. It consists of 24-bytes for each key and value + 8 bytes for // each of the priority, left, and right fields (24*2 + 8*3). nodeFieldsSize = 80 ) var ( // emptySlice is used for keys that have no value associated with them // so callers can distinguish between a key that does not exist and one // that has no value associated with it. emptySlice = make([]byte, 0) ) const ( // Generation number for nodes in a Mutable treap. MutableGeneration int = -1 // Generation number for nodes in the free Pool. PoolGeneration int = -2 ) // treapNode represents a node in the treap. type treapNode struct { key []byte value []byte priority int left *treapNode right *treapNode generation int } // nodeSize returns the number of bytes the specified node occupies including // the struct fields and the contents of the key and value. func nodeSize(node *treapNode) uint64 { return nodeFieldsSize + uint64(len(node.key)+len(node.value)) } // Pool of treapNode available for reuse. var nodePool = &sync.Pool{ New: func() interface{} { return &treapNode{key: nil, value: nil, priority: 0, generation: PoolGeneration} }, } // getTreapNode returns a new node from the given key, value, and priority. The // node is not initially linked to any others. func getTreapNode(key, value []byte, priority int, generation int) *treapNode { n := nodePool.Get().(*treapNode) n.key = key n.value = value n.priority = priority n.left = nil n.right = nil n.generation = generation return n } // Put treapNode back in the nodePool for reuse. func putTreapNode(n *treapNode) { n.key = nil n.value = nil n.priority = 0 n.left = nil n.right = nil n.generation = PoolGeneration nodePool.Put(n) } // parentStack represents a stack of parent treap nodes that are used during // iteration. It consists of a static array for holding the parents and a // dynamic overflow slice. It is extremely unlikely the overflow will ever be // hit during normal operation, however, since a treap's height is // probabilistic, the overflow case needs to be handled properly. This approach // is used because it is much more efficient for the majority case than // dynamically allocating heap space every time the treap is iterated. type parentStack struct { index int items [staticDepth]*treapNode overflow []*treapNode } // Len returns the current number of items in the stack. func (s *parentStack) Len() int { return s.index } // At returns the item n number of items from the top of the stack, where 0 is // the topmost item, without removing it. It returns nil if n exceeds the // number of items on the stack. func (s *parentStack) At(n int) *treapNode { index := s.index - n - 1 if index < 0 { return nil } if index < staticDepth { return s.items[index] } return s.overflow[index-staticDepth] } // Pop removes the top item from the stack. It returns nil if the stack is // empty. func (s *parentStack) Pop() *treapNode { if s.index == 0 { return nil } s.index-- if s.index < staticDepth { node := s.items[s.index] s.items[s.index] = nil return node } node := s.overflow[s.index-staticDepth] s.overflow[s.index-staticDepth] = nil return node } // Push pushes the passed item onto the top of the stack. func (s *parentStack) Push(node *treapNode) { if s.index < staticDepth { s.items[s.index] = node s.index++ return } // This approach is used over append because reslicing the slice to pop // the item causes the compiler to make unneeded allocations. Also, // since the max number of items is related to the tree depth which // requires expontentially more items to increase, only increase the cap // one item at a time. This is more intelligent than the generic append // expansion algorithm which often doubles the cap. index := s.index - staticDepth if index+1 > cap(s.overflow) { overflow := make([]*treapNode, index+1) copy(overflow, s.overflow) s.overflow = overflow } s.overflow[index] = node s.index++ } func init() { rand.Seed(time.Now().UnixNano()) }