Documentation
¶
Overview ¶
Yet another sorted map in go.. but not really.
Technically the omap package implements very minital btree using a slice. The drivers of the design process, were the performance objectives. The btree implementation is ordered and does not allow for duplicates; The internals manage keys by splicing the internal slice. The side effect of this design results in what operates exactly like ordered map. Under spesific conditions or very large data sets, omap.SliceTree is faster on "Get" operations than the built in go map. An omap.SliceTree instance uses signifigantly less the memory than the map feature in go.
Performance objectives while maintinaing a sorted map:
- Lookups for both Put and Get operations are always a fixed complexity: o(log n).
- All iteration operations are fixed cost of o(1).
- Finding or removing elements between 2 points is always a fixed cost of o(log(n) + log(n)).
- Finding elements: at, before, or after a given point is always a fixed cost of o(log n)
- Mass Removal of unordered elements that may or may not exist has a maximum complexity of o(log(n) + log(k) + k)
- Pre-emptive but predictable growth, this is done by setting the Growth size.
The omap package provides a common interface OrderedMap implemented by the following:
- Thread safe ThreadSafeOrderedMap, this is a wrapper for SliceTree
- Not thread safe SliceTree, but can return a thread safe wrapper.
Basic Example:
kv:=New[string,string](cmp.Compare)
// Save a value
kv.Put("Hello"," ")
kv.Put("World","!\n")
// Itertor
for k,v :=range kv.All {
fmt.Printf("%s%s",k,v)
}
The resulting output will be:
"Hello World!\n"
We can now make things a bit smaller by removing things by a range.
kv.RemoveBetween("Sell","Universe")
// Itertor
for k,v :=range kv.All {
fmt.Printf("%s%s\n",k,v)
}
The resulting output will now be:
"Hello \n"
The index lookup creates 2 values for each potential key:
- Array postion, example: 0
- Offset can be any of the following: -1,0,1
Since lookups create both an index position and offsett, it becomes possible to look for the following:
- Elements before the array
- Positions between elements of the array
- Elements after the array
- Elements to overwrite
Index ¶
- Constants
- func GetIndex[K any, V any](k K, Cmp func(a, b K) int, Slices []KvSet[K, V]) (index, offset int)
- func KvIter[K any, V any](set []KvSet[K, V]) iter.Seq2[K, V]
- func Merge[K comparable, V any](dst OrderedMap[K, V], src map[K]V) int
- func ToMap[K comparable, V any](src OrderedMap[K, V]) map[K]V
- func TsKvIterWrapper[K any, V any](seq iter.Seq2[K, V]) iter.Seq2[K, V]
- type KvSet
- type OrderedMap
- type SliceTree
- func (s *SliceTree[K, V]) All() iter.Seq2[K, V]
- func (s *SliceTree[K, V]) Between(a, b K, opt ...int) (total int)
- func (s *SliceTree[K, V]) BetweenKV(a, b K, opt ...int) (seq iter.Seq2[K, V])
- func (s *SliceTree[K, V]) Contains(key K) bool
- func (s *SliceTree[K, V]) Exists(k K) bool
- func (s *SliceTree[K, V]) FirstKey() (key K, ok bool)
- func (s *SliceTree[K, V]) Get(k K) (value V, found bool)
- func (s *SliceTree[K, V]) Keys() iter.Seq[K]
- func (s *SliceTree[K, V]) LastKey() (key K, ok bool)
- func (s *SliceTree[K, V]) MassRemove(args ...K) (total int)
- func (s *SliceTree[K, V]) MassRemoveKV(args ...K) iter.Seq2[K, V]
- func (s *SliceTree[K, V]) Merge(set OrderedMap[K, V]) int
- func (s *SliceTree[K, V]) Put(k K, v V)
- func (s *SliceTree[K, V]) Remove(k K) (value V, ok bool)
- func (s *SliceTree[K, V]) RemoveAll() int
- func (s *SliceTree[K, V]) RemoveBetween(a, b K, opt ...int) (total int)
- func (s *SliceTree[K, V]) RemoveBetweenKV(a, b K, opt ...int) (removed iter.Seq2[K, V])
- func (s *SliceTree[K, V]) Set(index int, v V) (status bool)
- func (s *SliceTree[K, V]) SetGrowth(grow int)
- func (s *SliceTree[K, V]) SetIndex(idx, offset int, k K, v V) (index int)
- func (s *SliceTree[K, V]) SetOverwrite(cb func(key K, oldValue, newValue V))
- func (s *SliceTree[K, V]) Size() int
- func (s *SliceTree[K, V]) ThreadSafe() bool
- func (s *SliceTree[K, V]) ToTs() OrderedMap[K, V]
- func (s *SliceTree[K, V]) UnSafeMassRemove(keys ...K)
- func (s *SliceTree[K, V]) Values() iter.Seq[V]
- type ThreadSafeOrderedMap
- func (s *ThreadSafeOrderedMap[K, V]) All() iter.Seq2[K, V]
- func (s *ThreadSafeOrderedMap[K, V]) Between(a, b K, opt ...int) (total int)
- func (s *ThreadSafeOrderedMap[K, V]) BetweenKV(a, b K, opt ...int) (seq iter.Seq2[K, V])
- func (s *ThreadSafeOrderedMap[K, V]) Contains(key K) bool
- func (s *ThreadSafeOrderedMap[K, V]) Exists(key K) bool
- func (s *ThreadSafeOrderedMap[K, V]) FirstKey() (key K, ok bool)
- func (s *ThreadSafeOrderedMap[K, V]) Get(key K) (value V, found bool)
- func (s *ThreadSafeOrderedMap[K, V]) Keys() iter.Seq[K]
- func (s *ThreadSafeOrderedMap[K, V]) LastKey() (key K, ok bool)
- func (s *ThreadSafeOrderedMap[K, V]) MassRemove(keys ...K) (total int)
- func (s *ThreadSafeOrderedMap[K, V]) MassRemoveKV(keys ...K) iter.Seq2[K, V]
- func (s *ThreadSafeOrderedMap[K, V]) Merge(set OrderedMap[K, V]) int
- func (s *ThreadSafeOrderedMap[K, V]) Put(key K, value V)
- func (s *ThreadSafeOrderedMap[K, V]) Remove(key K) (V, bool)
- func (s *ThreadSafeOrderedMap[K, V]) RemoveAll() int
- func (s *ThreadSafeOrderedMap[K, V]) RemoveBetween(a, b K, opt ...int) (total int)
- func (s *ThreadSafeOrderedMap[K, V]) RemoveBetweenKV(a, b K, opt ...int) (seq iter.Seq2[K, V])
- func (s *ThreadSafeOrderedMap[K, V]) SetGrowth(grow int)
- func (s *ThreadSafeOrderedMap[K, V]) SetOverwrite(cb func(key K, oldValue, newValue V))
- func (s *ThreadSafeOrderedMap[K, V]) Size() int
- func (s *ThreadSafeOrderedMap[K, V]) ThreadSafe() bool
- func (s *ThreadSafeOrderedMap[K, V]) ToTs() OrderedMap[K, V]
- func (s *ThreadSafeOrderedMap[K, V]) Values() iter.Seq[V]
Constants ¶
const ( FIRST_KEY = 1 LAST_KEY = 2 )
Variables ¶
This section is empty.
Functions ¶
func GetIndex ¶
Returns the index and offset of a given key.
The index is the current relative postion in the slice.
The offset represents where the item would be placed:
- offset of 0, at index value.
- offset of 1, expand the slice after the inddex and put the value to the right of the index
- offset of -1, expand the slice before the index and put the value to left of the current postion
Complexity: o(log n)
func Merge ¶
func Merge[K comparable, V any](dst OrderedMap[K, V], src map[K]V) int
Merges a map into an OrderedMap instance.
func ToMap ¶
func ToMap[K comparable, V any](src OrderedMap[K, V]) map[K]V
Utility method, to convert from an OrderedMap instance to a regular map. Due to constraints placed on maps in go, this feature is implemented as a function, not a method.
Types ¶
type OrderedMap ¶
type OrderedMap[K any, V any] interface { // Should return an iterator for all key/value pairs All() iter.Seq2[K, V] // Returns all keys, the int just expected to be a sequential number Keys() iter.Seq[K] // Returns all the values, the int is expected to be a sequential number Values() iter.Seq[V] // Returns true if the key exists, false if it does not. Exists(key K) bool // Returns true if the key is between the first and last key Contains(key K) bool // Sets the key to the value, returns the index id. Put(key K, value V) // Tries to get the value using the given key. // If the key exists, found is set to true, if the key does not exists then found is set to false. Get(key K) (value V, found bool) // Tries to remove the given key, returns value is set if ok is true. Remove(key K) (value V, ok bool) // Removes all elements. // Returns how many element were removed. RemoveAll() int // Attempts to remove all keys, returns the number of keys removed. MassRemove(keys ...K) (total int) // Attempts to remove all keys, returns an iterator with the key/value pairs MassRemoveKV(keys ...K) iter.Seq2[K, V] // Returns the current number of key/value pairs. Size() int // If ok is true, returns the first key. FirstKey() (key K, ok bool) // If ok is true, returns the last key. LastKey() (key K, ok bool) // Returns total number of elements between a and b. // Neither a or b are required to exist. // // The the optional opt argument: // - When: opt[0]==omap.FIRST_KEY, a is ignored and the FirstKey is used. // - When: opt[0]==omap.LAST_KEY, b is ignored and the LastKey is used. // - To Ignore both a and b, set: opt[0]==omap.FIRST_KEY|omap.LAST_KEY. Between(a, b K, opt ...int) (total int) // Returns an iterator that contains the key value sets between a and b. // Neither a or b are required to exist. // // The the optional opt argument: // - When: opt[0]==omap.FIRST_KEY, a is ignored and the FirstKey is used. // - When: opt[0]==omap.LAST_KEY, b is ignored and the LastKey is used. // - To Ignore both a and b, set: opt[0]==omap.FIRST_KEY|omap.LAST_KEY. BetweenKV(a, b K, opt ...int) (seq iter.Seq2[K, V]) // Trys to delete the elements between a and b, returns the total number of elements deleted. // Neither a or b are required to exist. // // The the optional opt argument: // - When: opt[0]==omap.FIRST_KEY, a is ignored and the FirstKey is used. // - When: opt[0]==omap.LAST_KEY, b is ignored and the LastKey is used. // - To Ignore both a and b, set: opt[0]==omap.FIRST_KEY|omap.LAST_KEY. RemoveBetween(a, b K, opt ...int) (total int) // Trys to delete the elements between a and b, returns an iterator that contains removed K,V pairs. // Neither a or b are required to exist. // // The the optional opt argument: RemoveBetweenKV(a, b K, opt ...int) (seq iter.Seq2[K, V]) // Should return true if the instance is thread safe, fakse if not. ThreadSafe() bool // Merges a given [OrderedMap] into this one. // Returns the number of keys added Merge(set OrderedMap[K, V]) int // Sets the overwrite notice. Its good to know when things change! SetOverwrite(cb func(key K, oldValue, newValue V)) // Sets the growth value. SetGrowth(grow int) // Returns a thread safe instance. // If the instance is all ready thread safe, then the current instance is returned. ToTs() OrderedMap[K, V] }
func NewTs ¶
func NewTs[K any, V any](Cmp func(a, b K) int) (Map OrderedMap[K, V])
Creates a new thread safe OrderedMap instance.
type SliceTree ¶
type SliceTree[K any, V any] struct { // Internally managed keys slice Slices []KvSet[K, V] // Compare function. Cmp func(a, b K) int // Required non 0 value, determins by what capacity we grow the internal // Slice. Default is 1. Growth int // Required non nil value, called when ever a value is overwritten. // Seting this funtion saves on having to write a check when data is overwritten. OnOverWrite func(key K, oldValue V, newValue V) }
func New ¶
Creates a new SliceTee with the default Slices size of 100. If you require more control over the starting size of the slice use the NewSliceTree function in stead.
func NewFromMap ¶
func NewFromMap[K comparable, V any](m map[K]V, cb func(a, b K) int) *SliceTree[K, V]
func NewSliceTree ¶
Creatss a new SliceTree with the internal Slice set to "size".
func (*SliceTree[K, V]) All ¶
Returns an iterator for key/value pars. The internals of this iterator do not lock the tree or prevent updates. You can safely call an iterator from with an iterator. and not run into deadlocks.
func (*SliceTree[K, V]) Between ¶
Between implements OrderedMap
func (*SliceTree[K, V]) BetweenKV ¶
BetweenKV implements OrderedMap
func (*SliceTree[K, V]) FirstKey ¶
GetFirstKey implements OrderedMap
func (*SliceTree[K, V]) Get ¶
Tries to fetch value based on key of k, if k does not exist, found is false.
func (*SliceTree[K, V]) Keys ¶
Returns an iterator for the current keys. The internals of this iterator do not lock the tree or prevent updates. You can safely call an iterator from with an iterator. and not run into deadlocks.
func (*SliceTree[K, V]) LastKey ¶
GetLastKey implements OrderedMap
func (*SliceTree[K, V]) MassRemove ¶
Attempts to remove the keys from the tree in bulk. Returns the number of keys removed.
This is almost always faster than just looping over a list of keys and calling Remove one key at a time. The internals of The MassRemove method deletes elements in squential contiguys blocks: reducing on the number of internal splice operations.
Complexity:
Worst case shown (Per key removed or k): o(log(n) + o(log k) + 2*k).
In truth, the real world complexity is drastically reduced by the following:
- Deletetion of duplicate keys.
- Keys being deleted do not exist.
The complexity is defined by the steps required:
- Index lookups: o(log n) +k
- child index is created to de-duplicate and order keys for deletion: o(log k)
- key deletion is done in contiguous blocks: k
func (*SliceTree[K, V]) MassRemoveKV ¶
func (*SliceTree[K, V]) Merge ¶
func (s *SliceTree[K, V]) Merge(set OrderedMap[K, V]) int
Merge implements OrderedMap
func (*SliceTree[K, V]) Put ¶
func (s *SliceTree[K, V]) Put(k K, v V)
Sets the key/vale pair and returns the index id. Comlexity: o(log n)
func (*SliceTree[K, V]) Remove ¶
Tries to remove the element of k, returns false if it fails. Complexity: o(log n)
func (*SliceTree[K, V]) RemoveAll ¶
Removes all elements in the slice, but keeps the memory allocated.
func (*SliceTree[K, V]) RemoveBetween ¶
RemoveBetween implements OrderedMap
func (*SliceTree[K, V]) RemoveBetweenKV ¶
RemoveBetween implements OrderedMap
func (*SliceTree[K, V]) Set ¶
Sets the value in the index to v. The last index value returned from Put to update the last index point. This lets you bypass the o(log n) update complexity for writing to the same element over and over again. The internals still call s.OnOverWrite for you.
func (*SliceTree[K, V]) SetGrowth ¶
SetGrowth implements OrderedMap
func (*SliceTree[K, V]) SetIndex ¶
Sets the given k,v pair based on the index and offset provided by a call to GetIndex. Returns the resulting array index id.
Using a combinaiton of GetIndex and SetIndex lets you bypass the o(log n) comlexity when wiring to the same node over and over again. The value reutrned from Put can be used to update the internals using SetIndex with the offset being 0.
func (*SliceTree[K, V]) SetOverwrite ¶
func (s *SliceTree[K, V]) SetOverwrite(cb func(key K, oldValue, newValue V))
Sets the internal OnOverWrite function.
func (*SliceTree[K, V]) ToTs ¶
func (s *SliceTree[K, V]) ToTs() OrderedMap[K, V]
Returns a thread safe instnace from the current instance.
func (*SliceTree[K, V]) UnSafeMassRemove ¶
func (s *SliceTree[K, V]) UnSafeMassRemove(keys ...K)
This method is by defenition, unsafe, but fast.
Only use if the keys being removed meet all of the following requirements:
- no duplicate keys
- keys are in ascending ordered
- all keys currently exist in the internals of the tree
Complexity: key=keys; o(log n +k)
type ThreadSafeOrderedMap ¶
type ThreadSafeOrderedMap[K any, V any] struct { // Instance to wrap for locking Tree OrderedMap[K, V] // contains filtered or unexported fields }
func (*ThreadSafeOrderedMap[K, V]) All ¶
func (s *ThreadSafeOrderedMap[K, V]) All() iter.Seq2[K, V]
All implements OrderedMap.
func (*ThreadSafeOrderedMap[K, V]) Between ¶
func (s *ThreadSafeOrderedMap[K, V]) Between(a, b K, opt ...int) (total int)
Between implements OrderedMap
func (*ThreadSafeOrderedMap[K, V]) BetweenKV ¶
func (s *ThreadSafeOrderedMap[K, V]) BetweenKV(a, b K, opt ...int) (seq iter.Seq2[K, V])
BetweenKV implements OrderedMap
func (*ThreadSafeOrderedMap[K, V]) Contains ¶
func (s *ThreadSafeOrderedMap[K, V]) Contains(key K) bool
func (*ThreadSafeOrderedMap[K, V]) Exists ¶
func (s *ThreadSafeOrderedMap[K, V]) Exists(key K) bool
Exists implements OrderedMap.
func (*ThreadSafeOrderedMap[K, V]) FirstKey ¶
func (s *ThreadSafeOrderedMap[K, V]) FirstKey() (key K, ok bool)
GetFirstKey implements OrderedMap
func (*ThreadSafeOrderedMap[K, V]) Get ¶
func (s *ThreadSafeOrderedMap[K, V]) Get(key K) (value V, found bool)
Get implements OrderedMap.
func (*ThreadSafeOrderedMap[K, V]) Keys ¶
func (s *ThreadSafeOrderedMap[K, V]) Keys() iter.Seq[K]
Keys implements OrderedMap.
func (*ThreadSafeOrderedMap[K, V]) LastKey ¶
func (s *ThreadSafeOrderedMap[K, V]) LastKey() (key K, ok bool)
GetLastKey implements OrderedMap
func (*ThreadSafeOrderedMap[K, V]) MassRemove ¶
func (s *ThreadSafeOrderedMap[K, V]) MassRemove(keys ...K) (total int)
MassRemove implements OrderedMap.
func (*ThreadSafeOrderedMap[K, V]) MassRemoveKV ¶
func (s *ThreadSafeOrderedMap[K, V]) MassRemoveKV(keys ...K) iter.Seq2[K, V]
func (*ThreadSafeOrderedMap[K, V]) Merge ¶
func (s *ThreadSafeOrderedMap[K, V]) Merge(set OrderedMap[K, V]) int
Merge implements OrderedMap
func (*ThreadSafeOrderedMap[K, V]) Put ¶
func (s *ThreadSafeOrderedMap[K, V]) Put(key K, value V)
Put implements OrderedMap.
func (*ThreadSafeOrderedMap[K, V]) Remove ¶
func (s *ThreadSafeOrderedMap[K, V]) Remove(key K) (V, bool)
Remove implements OrderedMap.
func (*ThreadSafeOrderedMap[K, V]) RemoveAll ¶
func (s *ThreadSafeOrderedMap[K, V]) RemoveAll() int
RemoveAll implements OrderedMap.
func (*ThreadSafeOrderedMap[K, V]) RemoveBetween ¶
func (s *ThreadSafeOrderedMap[K, V]) RemoveBetween(a, b K, opt ...int) (total int)
RemoveBetween implements OrderedMap.
func (*ThreadSafeOrderedMap[K, V]) RemoveBetweenKV ¶
func (s *ThreadSafeOrderedMap[K, V]) RemoveBetweenKV(a, b K, opt ...int) (seq iter.Seq2[K, V])
RemoveBetweenKV implements OrderedMap.
func (*ThreadSafeOrderedMap[K, V]) SetGrowth ¶
func (s *ThreadSafeOrderedMap[K, V]) SetGrowth(grow int)
func (*ThreadSafeOrderedMap[K, V]) SetOverwrite ¶
func (s *ThreadSafeOrderedMap[K, V]) SetOverwrite(cb func(key K, oldValue, newValue V))
SetOverwrite implements OrderedMap
func (*ThreadSafeOrderedMap[K, V]) Size ¶
func (s *ThreadSafeOrderedMap[K, V]) Size() int
Size implements OrderedMap.
func (*ThreadSafeOrderedMap[K, V]) ThreadSafe ¶
func (s *ThreadSafeOrderedMap[K, V]) ThreadSafe() bool
Always returns true.
func (*ThreadSafeOrderedMap[K, V]) ToTs ¶
func (s *ThreadSafeOrderedMap[K, V]) ToTs() OrderedMap[K, V]
Always returns this instance.
func (*ThreadSafeOrderedMap[K, V]) Values ¶
func (s *ThreadSafeOrderedMap[K, V]) Values() iter.Seq[V]
Values implements OrderedMap.