├── .gitignore ├── hashmap └── fastinteger │ ├── hash.go │ ├── hash_test.go │ ├── hashmap.go │ └── hashmap_test.go ├── queue ├── error.go ├── mock_test.go ├── ring.go ├── priority_queue_test.go ├── ring_test.go └── priority_queue.go ├── btree ├── _link │ ├── mock_test.go │ ├── interface.go │ ├── key.go │ ├── tree.go │ └── node_test.go ├── palm │ ├── mock_test.go │ ├── key.go │ ├── action.go │ ├── interface.go │ └── node.go └── plus │ ├── mock_test.go │ ├── interface.go │ ├── iterator.go │ ├── btree.go │ └── node_test.go ├── tree └── avl │ ├── mock_test.go │ ├── interface.go │ └── node.go ├── trie ├── yfast │ ├── mock_test.go │ ├── interface.go │ ├── iterator.go │ ├── entries_test.go │ └── entries.go └── xfast │ ├── mock_test.go │ ├── iterator_test.go │ └── iterator.go ├── threadsafe └── err │ ├── error_test.go │ └── error.go ├── rangetree ├── entries_test.go ├── node.go ├── error.go ├── entries.go ├── skiplist │ └── mock_test.go ├── mock_test.go ├── interface.go ├── ordered_test.go ├── orderedtree.go └── ordered.go ├── augmentedtree ├── trees.go ├── intervals_test.go ├── intervals.go ├── mock_test.go └── interface.go ├── bitarray ├── error.go ├── block_test.go ├── util.go ├── iterator.go ├── block.go ├── interface.go ├── and.go ├── or.go ├── and_test.go └── or_test.go ├── sort ├── sort_test.go ├── interface.go ├── sort.go └── symmerge.go ├── slice ├── int64_test.go ├── skip │ ├── mock_test.go │ ├── iterator_test.go │ ├── node.go │ ├── interface.go │ ├── entries_test.go │ ├── iterator.go │ └── entries.go └── int64.go ├── datastructures.go ├── futures ├── futures_test.go └── futures.go ├── set ├── dict.go └── dict_test.go └── numerics └── optimization ├── global.go └── nelder_mead_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | *.out 2 | *.test -------------------------------------------------------------------------------- /hashmap/fastinteger/hash.go: -------------------------------------------------------------------------------- 1 | package fastinteger 2 | 3 | // hash will convert the uint64 key into a hash based on Murmur3's 64-bit 4 | // integer finalizer. 5 | // Details here: https://code.google.com/p/smhasher/wiki/MurmurHash3 6 | func hash(key uint64) uint64 { 7 | key ^= key >> 33 8 | key *= 0xff51afd7ed558ccd 9 | key ^= key >> 33 10 | key *= 0xc4ceb9fe1a85ec53 11 | key ^= key >> 33 12 | return key 13 | } 14 | -------------------------------------------------------------------------------- /queue/error.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package queue 18 | 19 | import "errors" 20 | 21 | var disposedError = errors.New(`Queue has been disposed.`) 22 | -------------------------------------------------------------------------------- /queue/mock_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package queue 18 | 19 | type mockItem int 20 | 21 | func (mi mockItem) Compare(other Item) int { 22 | omi := other.(mockItem) 23 | if mi > omi { 24 | return 1 25 | } else if mi == omi { 26 | return 0 27 | } 28 | return -1 29 | } 30 | -------------------------------------------------------------------------------- /btree/_link/mock_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package link 18 | 19 | type mockKey uint64 20 | 21 | func (mk mockKey) Compare(other Key) int { 22 | otherK := other.(mockKey) 23 | if mk < otherK { 24 | return -1 25 | } 26 | 27 | if mk > otherK { 28 | return 1 29 | } 30 | 31 | return 0 32 | } 33 | -------------------------------------------------------------------------------- /tree/avl/mock_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package avl 18 | 19 | type mockEntry int 20 | 21 | func (me mockEntry) Compare(other Entry) int { 22 | otherMe := other.(mockEntry) 23 | if me > otherMe { 24 | return 1 25 | } 26 | 27 | if me < otherMe { 28 | return -1 29 | } 30 | 31 | return 0 32 | } 33 | -------------------------------------------------------------------------------- /trie/yfast/mock_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package yfast 18 | 19 | type mockEntry struct { 20 | // not going to use mock here as it skews benchmarks 21 | key uint64 22 | } 23 | 24 | func (me *mockEntry) Key() uint64 { 25 | return me.key 26 | } 27 | 28 | func newMockEntry(key uint64) *mockEntry { 29 | return &mockEntry{key} 30 | } 31 | -------------------------------------------------------------------------------- /threadsafe/err/error_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package err 18 | 19 | import ( 20 | "fmt" 21 | "testing" 22 | 23 | "github.com/stretchr/testify/assert" 24 | ) 25 | 26 | func TestGetSetError(t *testing.T) { 27 | e := New() 28 | assert.Nil(t, e.Get()) 29 | 30 | err := fmt.Errorf(`test`) 31 | e.Set(err) 32 | 33 | assert.Equal(t, err, e.Get()) 34 | } 35 | -------------------------------------------------------------------------------- /rangetree/entries_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package rangetree 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | func TestDisposeEntries(t *testing.T) { 26 | entries := NewEntries() 27 | entries = append(entries, constructMockEntry(0, 0)) 28 | 29 | entries.Dispose() 30 | 31 | assert.Len(t, entries, 0) 32 | } 33 | -------------------------------------------------------------------------------- /augmentedtree/trees.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package augmentedtree 18 | 19 | import "runtime" 20 | 21 | type trees []*tree 22 | 23 | func (t trees) split() []trees { 24 | numParts := runtime.NumCPU() 25 | parts := make([]trees, numParts) 26 | for i := 0; i < numParts; i++ { 27 | parts[i] = t[i*len(t)/numParts : (i+1)*len(t)/numParts] 28 | } 29 | return parts 30 | } 31 | -------------------------------------------------------------------------------- /btree/palm/mock_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package palm 17 | 18 | import "github.com/Workiva/go-datastructures/slice/skip" 19 | 20 | type mockKey int 21 | 22 | func (mk mockKey) Compare(other skip.Entry) int { 23 | otherKey := other.(mockKey) 24 | 25 | if mk == otherKey { 26 | return 0 27 | } 28 | 29 | if mk > otherKey { 30 | return 1 31 | } 32 | 33 | return -1 34 | } 35 | -------------------------------------------------------------------------------- /trie/yfast/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package yfast 18 | 19 | // Entry defines items that can be inserted into the y-fast 20 | // trie. 21 | type Entry interface { 22 | // Key is the key for this entry. If the trie has been 23 | // given bit size n, only the last n bits of this key 24 | // will matter. Use a bit size of 64 to enable all 25 | // 2^64-1 keys. 26 | Key() uint64 27 | } 28 | -------------------------------------------------------------------------------- /trie/xfast/mock_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package xfast 18 | 19 | import "github.com/stretchr/testify/mock" 20 | 21 | type mockEntry struct { 22 | mock.Mock 23 | } 24 | 25 | func (me *mockEntry) Key() uint64 { 26 | args := me.Called() 27 | return args.Get(0).(uint64) 28 | } 29 | 30 | func newMockEntry(key uint64) *mockEntry { 31 | me := new(mockEntry) 32 | me.On(`Key`).Return(key) 33 | return me 34 | } 35 | -------------------------------------------------------------------------------- /btree/plus/mock_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package plus 18 | 19 | type mockKey struct { 20 | value int 21 | } 22 | 23 | func (mk *mockKey) Compare(other Key) int { 24 | key := other.(*mockKey) 25 | if key.value == mk.value { 26 | return 0 27 | } 28 | if key.value > mk.value { 29 | return 1 30 | } 31 | 32 | return -1 33 | } 34 | 35 | func newMockKey(value int) *mockKey { 36 | return &mockKey{value} 37 | } 38 | -------------------------------------------------------------------------------- /augmentedtree/intervals_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package augmentedtree 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | func TestIntervalsDispose(t *testing.T) { 26 | intervals := intervalsPool.Get().(Intervals) 27 | intervals = append(intervals, constructSingleDimensionInterval(0, 1, 0)) 28 | 29 | intervals.Dispose() 30 | 31 | assert.Len(t, intervals, 0) 32 | } 33 | -------------------------------------------------------------------------------- /bitarray/error.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package bitarray 18 | 19 | import "fmt" 20 | 21 | // OutOfRangeError is an error caused by trying to access a bitarray past the end of its 22 | // capacity. 23 | type OutOfRangeError uint64 24 | 25 | // Error returns a human readable description of the out-of-range error. 26 | func (err OutOfRangeError) Error() string { 27 | return fmt.Sprintf(`Index %d is out of range.`, err) 28 | } 29 | -------------------------------------------------------------------------------- /btree/_link/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package link 18 | 19 | // Keys is a typed list of Key interfaces. 20 | type Keys []Key 21 | 22 | type Key interface { 23 | // Compare should return an int indicating how this key relates 24 | // to the provided key. -1 will indicate less than, 0 will indicate 25 | // equality, and 1 will indicate greater than. Duplicate keys 26 | // are allowed, but duplicate IDs are not. 27 | Compare(Key) int 28 | } 29 | -------------------------------------------------------------------------------- /rangetree/node.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package rangetree 18 | 19 | type nodes []*node 20 | 21 | type node struct { 22 | value int64 23 | entry Entry 24 | orderedNodes orderedNodes 25 | } 26 | 27 | func newNode(value int64, entry Entry, needNextDimension bool) *node { 28 | n := &node{} 29 | n.value = value 30 | if needNextDimension { 31 | n.orderedNodes = make(orderedNodes, 0, 10) 32 | } else { 33 | n.entry = entry 34 | } 35 | 36 | return n 37 | } 38 | -------------------------------------------------------------------------------- /sort/sort_test.go: -------------------------------------------------------------------------------- 1 | package merge 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/stretchr/testify/assert" 7 | ) 8 | 9 | func TestMultiThreadedSortEvenNumber(t *testing.T) { 10 | comparators := constructOrderedMockComparators(10) 11 | comparators = reverseComparators(comparators) 12 | 13 | result := MultithreadedSortComparators(comparators) 14 | comparators = reverseComparators(comparators) 15 | 16 | assert.Equal(t, comparators, result) 17 | } 18 | 19 | func TestMultiThreadedSortOddNumber(t *testing.T) { 20 | comparators := constructOrderedMockComparators(9) 21 | comparators = reverseComparators(comparators) 22 | 23 | result := MultithreadedSortComparators(comparators) 24 | comparators = reverseComparators(comparators) 25 | 26 | assert.Equal(t, comparators, result) 27 | } 28 | 29 | func BenchmarkMultiThreadedSort(b *testing.B) { 30 | numCells := 100000 31 | 32 | comparators := constructOrderedMockComparators(numCells) 33 | comparators = reverseComparators(comparators) 34 | 35 | b.ResetTimer() 36 | for i := 0; i < b.N; i++ { 37 | MultithreadedSortComparators(comparators) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /btree/palm/key.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package palm 18 | 19 | func (keys Keys) reverse() Keys { 20 | reversed := make(Keys, len(keys)) 21 | for i := len(keys) - 1; i >= 0; i-- { 22 | reversed[len(keys)-1-i] = keys[i] 23 | } 24 | 25 | return reversed 26 | } 27 | 28 | func chunkKeys(keys Keys, numParts int64) []Keys { 29 | parts := make([]Keys, numParts) 30 | for i := int64(0); i < numParts; i++ { 31 | parts[i] = keys[i*int64(len(keys))/numParts : (i+1)*int64(len(keys))/numParts] 32 | } 33 | return parts 34 | } 35 | -------------------------------------------------------------------------------- /augmentedtree/intervals.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package augmentedtree 18 | 19 | import "sync" 20 | 21 | var intervalsPool = sync.Pool{ 22 | New: func() interface{} { 23 | return make(Intervals, 0, 10) 24 | }, 25 | } 26 | 27 | // Intervals represents a list of Intervals. 28 | type Intervals []Interval 29 | 30 | // Dispose will free any consumed resources and allow this list to be 31 | // re-allocated. 32 | func (ivs *Intervals) Dispose() { 33 | for i := 0; i < len(*ivs); i++ { 34 | (*ivs)[i] = nil 35 | } 36 | 37 | *ivs = (*ivs)[:0] 38 | intervalsPool.Put(*ivs) 39 | } 40 | -------------------------------------------------------------------------------- /sort/interface.go: -------------------------------------------------------------------------------- 1 | package merge 2 | 3 | // Comparators defines a typed list of type Comparator. 4 | type Comparators []Comparator 5 | 6 | // Less returns a bool indicating if the comparator at index i 7 | // is less than the comparator at index j. 8 | func (c Comparators) Less(i, j int) bool { 9 | return c[i].Compare(c[j]) < 0 10 | } 11 | 12 | // Len returns an int indicating the length of this list 13 | // of comparators. 14 | func (c Comparators) Len() int { 15 | return len(c) 16 | } 17 | 18 | // Swap swaps the values at positions i and j. 19 | func (c Comparators) Swap(i, j int) { 20 | c[j], c[i] = c[i], c[j] 21 | } 22 | 23 | // Comparator defines items that can be sorted. It contains 24 | // a single method allowing the compare logic to compare one 25 | // comparator to another. 26 | type Comparator interface { 27 | // Compare will return a value indicating how this comparator 28 | // compares with the provided comparator. A negative number 29 | // indicates this comparator is less than the provided comparator, 30 | // a 0 indicates equality, and a positive number indicates this 31 | // comparator is greater than the provided comparator. 32 | Compare(Comparator) int 33 | } 34 | -------------------------------------------------------------------------------- /tree/avl/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package avl 18 | 19 | // Entries is a list of type Entry. 20 | type Entries []Entry 21 | 22 | // Entry represents all items that can be placed into the AVL tree. 23 | // They must implement a Compare method that can be used to determine 24 | // the Entry's correct place in the tree. Any object can implement 25 | // Compare. 26 | type Entry interface { 27 | // Compare should return a value indicating the relationship 28 | // of this Entry to the provided Entry. A -1 means this entry 29 | // is less than, 0 means equality, and 1 means greater than. 30 | Compare(Entry) int 31 | } 32 | -------------------------------------------------------------------------------- /hashmap/fastinteger/hash_test.go: -------------------------------------------------------------------------------- 1 | package fastinteger 2 | 3 | import ( 4 | "encoding/binary" 5 | "hash/fnv" 6 | "math/rand" 7 | "testing" 8 | "time" 9 | 10 | "github.com/stretchr/testify/assert" 11 | ) 12 | 13 | func TestHash(t *testing.T) { 14 | key := uint64(5) 15 | h := hash(key) 16 | 17 | assert.NotEqual(t, key, h) 18 | } 19 | 20 | func BenchmarkHash(b *testing.B) { 21 | numItems := 1000 22 | r := rand.New(rand.NewSource(time.Now().UnixNano())) 23 | 24 | keys := make([]uint64, 0, numItems) 25 | for i := 0; i < numItems; i++ { 26 | key := uint64(r.Int63()) 27 | keys = append(keys, key) 28 | } 29 | 30 | b.ResetTimer() 31 | for i := 0; i < b.N; i++ { 32 | for _, key := range keys { 33 | hash(key) 34 | } 35 | } 36 | } 37 | 38 | func BenchmarkFnvHash(b *testing.B) { 39 | numItems := 1000 40 | r := rand.New(rand.NewSource(time.Now().UnixNano())) 41 | 42 | keys := make([]uint64, 0, numItems) 43 | for i := 0; i < numItems; i++ { 44 | key := uint64(r.Int63()) 45 | keys = append(keys, key) 46 | } 47 | 48 | b.ResetTimer() 49 | for i := 0; i < b.N; i++ { 50 | for _, key := range keys { 51 | hasher := fnv.New64() 52 | binary.Write(hasher, binary.LittleEndian, key) 53 | hasher.Sum64() 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /rangetree/error.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package rangetree 18 | 19 | import "fmt" 20 | 21 | // NoEntriesError is returned from an operation that requires 22 | // existing entries when none are found. 23 | type NoEntriesError struct{} 24 | 25 | func (nee NoEntriesError) Error() string { 26 | return `No entries in this tree.` 27 | } 28 | 29 | // OutOfDimensionError is returned when a requested operation 30 | // doesn't meet dimensional requirements. 31 | type OutOfDimensionError struct { 32 | provided, max uint64 33 | } 34 | 35 | func (oode OutOfDimensionError) Error() string { 36 | return fmt.Sprintf(`Provided dimension: %d is 37 | greater than max dimension: %d`, 38 | oode.provided, oode.max, 39 | ) 40 | } 41 | -------------------------------------------------------------------------------- /bitarray/block_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package bitarray 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | func TestBlockToNums(t *testing.T) { 26 | b := block(0) 27 | 28 | b = b.insert(s - 2) 29 | b = b.insert(s - 6) 30 | 31 | expected := []uint64{s - 6, s - 2} 32 | 33 | result := make([]uint64, 0, 0) 34 | b.toNums(0, &result) 35 | assert.Equal(t, expected, result) 36 | } 37 | 38 | func BenchmarkBlockToNums(b *testing.B) { 39 | block := block(0) 40 | for i := uint64(0); i < s; i++ { 41 | block = block.insert(i) 42 | } 43 | 44 | nums := make([]uint64, 0, 0) 45 | b.ResetTimer() 46 | 47 | for i := 0; i < b.N; i++ { 48 | block.toNums(0, &nums) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /rangetree/entries.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package rangetree 18 | 19 | import "sync" 20 | 21 | var entriesPool = sync.Pool{ 22 | New: func() interface{} { 23 | return make(Entries, 0, 10) 24 | }, 25 | } 26 | 27 | // Entries is a typed list of Entry that can be reused if Dispose 28 | // is called. 29 | type Entries []Entry 30 | 31 | // Dispose will free the resources consumed by this list and 32 | // allow the list to be reused. 33 | func (entries *Entries) Dispose() { 34 | for i := 0; i < len(*entries); i++ { 35 | (*entries)[i] = nil 36 | } 37 | 38 | *entries = (*entries)[:0] 39 | entriesPool.Put(*entries) 40 | } 41 | 42 | // NewEntries will return a reused list of entries. 43 | func NewEntries() Entries { 44 | return entriesPool.Get().(Entries) 45 | } 46 | -------------------------------------------------------------------------------- /rangetree/skiplist/mock_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package skiplist 18 | 19 | type mockEntry struct { 20 | values []int64 21 | } 22 | 23 | func (me *mockEntry) ValueAtDimension(dimension uint64) int64 { 24 | return me.values[dimension] 25 | } 26 | 27 | func newMockEntry(values ...int64) *mockEntry { 28 | return &mockEntry{values: values} 29 | } 30 | 31 | type mockInterval struct { 32 | lows, highs []int64 33 | } 34 | 35 | func (mi *mockInterval) LowAtDimension(dimension uint64) int64 { 36 | return mi.lows[dimension] 37 | } 38 | 39 | func (mi *mockInterval) HighAtDimension(dimension uint64) int64 { 40 | return mi.highs[dimension] 41 | } 42 | 43 | func newMockInterval(lows, highs []int64) *mockInterval { 44 | return &mockInterval{ 45 | lows: lows, 46 | highs: highs, 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tree/avl/node.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package avl 18 | 19 | type nodes []*node 20 | 21 | func (ns nodes) reset() { 22 | for i := range ns { 23 | ns[i] = nil 24 | } 25 | } 26 | 27 | type node struct { 28 | balance int8 // bounded, |balance| should be <= 1 29 | children [2]*node 30 | entry Entry 31 | } 32 | 33 | // copy returns a copy of this node with pointers to the original 34 | // children. 35 | func (n *node) copy() *node { 36 | return &node{ 37 | balance: n.balance, 38 | children: [2]*node{n.children[0], n.children[1]}, 39 | entry: n.entry, 40 | } 41 | } 42 | 43 | // newNode returns a new node for the provided entry. A nil 44 | // entry is used to represent the dummy node. 45 | func newNode(entry Entry) *node { 46 | return &node{ 47 | entry: entry, 48 | children: [2]*node{}, 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /slice/int64_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package slice 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | func TestSort(t *testing.T) { 26 | s := Int64Slice{3, 6, 1, 0, -1} 27 | s.Sort() 28 | 29 | assert.Equal(t, Int64Slice{-1, 0, 1, 3, 6}, s) 30 | } 31 | 32 | func TestSearch(t *testing.T) { 33 | s := Int64Slice{1, 3, 6} 34 | 35 | assert.Equal(t, 1, s.Search(3)) 36 | assert.Equal(t, 1, s.Search(2)) 37 | assert.Equal(t, 3, s.Search(7)) 38 | } 39 | 40 | func TestExists(t *testing.T) { 41 | s := Int64Slice{1, 3, 6} 42 | 43 | assert.True(t, s.Exists(3)) 44 | assert.False(t, s.Exists(4)) 45 | } 46 | 47 | func TestInsert(t *testing.T) { 48 | s := Int64Slice{1, 3, 6} 49 | s = s.Insert(2) 50 | assert.Equal(t, Int64Slice{1, 2, 3, 6}, s) 51 | 52 | s = s.Insert(7) 53 | assert.Equal(t, Int64Slice{1, 2, 3, 6, 7}, s) 54 | } 55 | -------------------------------------------------------------------------------- /slice/skip/mock_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package skip 18 | 19 | import "github.com/stretchr/testify/mock" 20 | 21 | type mockEntry uint64 22 | 23 | func (me mockEntry) Compare(other Entry) int { 24 | otherU := other.(mockEntry) 25 | if me == otherU { 26 | return 0 27 | } 28 | 29 | if me > otherU { 30 | return 1 31 | } 32 | 33 | return -1 34 | } 35 | 36 | func newMockEntry(key uint64) mockEntry { 37 | return mockEntry(key) 38 | } 39 | 40 | type mockIterator struct { 41 | mock.Mock 42 | } 43 | 44 | func (mi *mockIterator) Next() bool { 45 | args := mi.Called() 46 | return args.Bool(0) 47 | } 48 | 49 | func (mi *mockIterator) Value() Entry { 50 | args := mi.Called() 51 | result, ok := args.Get(0).(Entry) 52 | if !ok { 53 | return nil 54 | } 55 | 56 | return result 57 | } 58 | 59 | func (mi *mockIterator) exhaust() Entries { 60 | return nil 61 | } 62 | -------------------------------------------------------------------------------- /bitarray/util.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package bitarray 18 | 19 | // maxInt64 returns the highest integer in the provided list of int64s 20 | func maxInt64(ints ...int64) int64 { 21 | maxInt := ints[0] 22 | for i := 1; i < len(ints); i++ { 23 | if ints[i] > maxInt { 24 | maxInt = ints[i] 25 | } 26 | } 27 | 28 | return maxInt 29 | } 30 | 31 | // maxUint64 returns the highest integer in the provided list of uint64s 32 | func maxUint64(ints ...uint64) uint64 { 33 | maxInt := ints[0] 34 | for i := 1; i < len(ints); i++ { 35 | if ints[i] > maxInt { 36 | maxInt = ints[i] 37 | } 38 | } 39 | 40 | return maxInt 41 | } 42 | 43 | // minUint64 returns the lowest integer in the provided list of int32s 44 | func minUint64(ints ...uint64) uint64 { 45 | minInt := ints[0] 46 | for i := 1; i < len(ints); i++ { 47 | if ints[i] < minInt { 48 | minInt = ints[i] 49 | } 50 | } 51 | 52 | return minInt 53 | } 54 | -------------------------------------------------------------------------------- /datastructures.go: -------------------------------------------------------------------------------- 1 | /* 2 | Package datastructures exists solely to aid consumers of the go-datastructures 3 | library when using dependency managers. Depman, for instance, will work 4 | correctly with any datastructure by simply importing this package instead of 5 | each subpackage individually. 6 | 7 | For more information about the datastructures package, see the README at 8 | 9 | http://github.com/Workiva/go-datastructures 10 | 11 | */ 12 | package datastructures 13 | 14 | import ( 15 | _ "github.com/Workiva/go-datastructures/augmentedtree" 16 | _ "github.com/Workiva/go-datastructures/bitarray" 17 | _ "github.com/Workiva/go-datastructures/btree/palm" 18 | _ "github.com/Workiva/go-datastructures/btree/plus" 19 | _ "github.com/Workiva/go-datastructures/futures" 20 | _ "github.com/Workiva/go-datastructures/hashmap/fastinteger" 21 | _ "github.com/Workiva/go-datastructures/numerics/optimization" 22 | _ "github.com/Workiva/go-datastructures/queue" 23 | _ "github.com/Workiva/go-datastructures/rangetree" 24 | _ "github.com/Workiva/go-datastructures/rangetree/skiplist" 25 | _ "github.com/Workiva/go-datastructures/set" 26 | _ "github.com/Workiva/go-datastructures/slice" 27 | _ "github.com/Workiva/go-datastructures/slice/skip" 28 | _ "github.com/Workiva/go-datastructures/sort" 29 | _ "github.com/Workiva/go-datastructures/threadsafe/err" 30 | _ "github.com/Workiva/go-datastructures/tree/avl" 31 | _ "github.com/Workiva/go-datastructures/trie/xfast" 32 | _ "github.com/Workiva/go-datastructures/trie/yfast" 33 | ) 34 | -------------------------------------------------------------------------------- /slice/skip/iterator_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package skip 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | func TestIterate(t *testing.T) { 26 | e1 := newMockEntry(1) 27 | n1 := newNode(e1, 8) 28 | iter := &iterator{ 29 | n: n1, 30 | first: true, 31 | } 32 | 33 | assert.True(t, iter.Next()) 34 | assert.Equal(t, e1, iter.Value()) 35 | assert.False(t, iter.Next()) 36 | assert.Nil(t, iter.Value()) 37 | 38 | e2 := newMockEntry(2) 39 | n2 := newNode(e2, 8) 40 | n1.forward[0] = n2 41 | 42 | iter = &iterator{ 43 | n: n1, 44 | first: true, 45 | } 46 | 47 | assert.True(t, iter.Next()) 48 | assert.Equal(t, e1, iter.Value()) 49 | assert.True(t, iter.Next()) 50 | assert.Equal(t, e2, iter.Value()) 51 | assert.False(t, iter.Next()) 52 | assert.Nil(t, iter.Value()) 53 | 54 | iter = nilIterator() 55 | assert.False(t, iter.Next()) 56 | assert.Nil(t, iter.Value()) 57 | } 58 | -------------------------------------------------------------------------------- /trie/xfast/iterator_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package xfast 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | func TestIterator(t *testing.T) { 26 | iter := &Iterator{ 27 | first: true, 28 | } 29 | 30 | assert.False(t, iter.Next()) 31 | assert.Nil(t, iter.Value()) 32 | 33 | e1 := newMockEntry(5) 34 | n1 := newNode(nil, e1) 35 | iter = &Iterator{ 36 | first: true, 37 | n: n1, 38 | } 39 | 40 | assert.True(t, iter.Next()) 41 | assert.Equal(t, e1, iter.Value()) 42 | assert.False(t, iter.Next()) 43 | assert.Nil(t, iter.Value()) 44 | 45 | e2 := newMockEntry(10) 46 | n2 := newNode(nil, e2) 47 | n1.children[1] = n2 48 | 49 | iter = &Iterator{ 50 | first: true, 51 | n: n1, 52 | } 53 | 54 | assert.True(t, iter.Next()) 55 | assert.True(t, iter.Next()) 56 | assert.Equal(t, e2, iter.Value()) 57 | assert.False(t, iter.Next()) 58 | assert.Nil(t, iter.Value()) 59 | } 60 | -------------------------------------------------------------------------------- /slice/skip/node.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package skip 18 | 19 | type widths []uint64 20 | 21 | type nodes []*node 22 | 23 | type node struct { 24 | // forward denotes the forward pointing pointers in this 25 | // node. 26 | forward nodes 27 | // widths keeps track of the distance between this pointer 28 | // and the forward pointers so we can access skip list 29 | // values by position in logarithmic time. 30 | widths widths 31 | // entry is the associated value with this node. 32 | entry Entry 33 | } 34 | 35 | func (n *node) Compare(e Entry) int { 36 | return n.entry.Compare(e) 37 | } 38 | 39 | // newNode will allocate and return a new node with the entry 40 | // provided. maxLevels will determine the length of the forward 41 | // pointer list associated with this node. 42 | func newNode(entry Entry, maxLevels uint8) *node { 43 | return &node{ 44 | entry: entry, 45 | forward: make(nodes, maxLevels), 46 | widths: make(widths, maxLevels), 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /rangetree/mock_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package rangetree 18 | 19 | type mockEntry struct { 20 | id uint64 21 | dimensions []int64 22 | } 23 | 24 | func (me *mockEntry) ID() uint64 { 25 | return me.id 26 | } 27 | 28 | func (me *mockEntry) ValueAtDimension(dimension uint64) int64 { 29 | return me.dimensions[dimension-1] 30 | } 31 | 32 | func constructMockEntry(id uint64, values ...int64) *mockEntry { 33 | return &mockEntry{ 34 | id: id, 35 | dimensions: values, 36 | } 37 | } 38 | 39 | type dimension struct { 40 | low, high int64 41 | } 42 | 43 | type mockInterval struct { 44 | dimensions []dimension 45 | } 46 | 47 | func (mi *mockInterval) LowAtDimension(dimension uint64) int64 { 48 | return mi.dimensions[dimension-1].low 49 | } 50 | 51 | func (mi *mockInterval) HighAtDimension(dimension uint64) int64 { 52 | return mi.dimensions[dimension-1].high 53 | } 54 | 55 | func constructMockInterval(dimensions ...dimension) *mockInterval { 56 | return &mockInterval{ 57 | dimensions: dimensions, 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /btree/plus/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package plus 18 | 19 | // Keys is a typed list of Key interfaces. 20 | type Keys []Key 21 | 22 | type Key interface { 23 | // Compare should return an int indicating how this key relates 24 | // to the provided key. -1 will indicate less than, 0 will indicate 25 | // equality, and 1 will indicate greater than. Duplicate keys 26 | // are allowed, but duplicate IDs are not. 27 | Compare(Key) int 28 | } 29 | 30 | // Iterator will be called with matching keys until either false is 31 | // returned or we run out of keys to iterate. 32 | type Iterator interface { 33 | // Next will move the iterator to the next position and return 34 | // a bool indicating if there is a value. 35 | Next() bool 36 | // Value returns a Key at the associated iterator position. Returns 37 | // nil if the iterator is exhausted or has never been nexted. 38 | Value() Key 39 | // exhaust is an internal helper method to iterate this iterator 40 | // until exhausted and returns the resulting list of keys. 41 | exhaust() keys 42 | } 43 | -------------------------------------------------------------------------------- /threadsafe/err/error.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /* 18 | Package err implements a threadsafe error interface. In my places, 19 | I found myself needing a lock to protect writing to a common error interface 20 | from multiple go routines (channels are great but slow). This just makes 21 | that process more convenient. 22 | */ 23 | package err 24 | 25 | import "sync" 26 | 27 | // Error is a struct that holds an error and allows this error 28 | // to be set and retrieved in a threadsafe manner. 29 | type Error struct { 30 | lock sync.RWMutex 31 | err error 32 | } 33 | 34 | // Set will set the error of this structure to the provided 35 | // value. 36 | func (e *Error) Set(err error) { 37 | e.lock.Lock() 38 | defer e.lock.Unlock() 39 | 40 | e.err = err 41 | } 42 | 43 | // Get will return any error associated with this structure. 44 | func (e *Error) Get() error { 45 | e.lock.RLock() 46 | defer e.lock.RUnlock() 47 | 48 | return e.err 49 | } 50 | 51 | // New is a constructor to generate a new error object 52 | // that can be set and retrieved in a threadsafe manner. 53 | func New() *Error { 54 | return &Error{} 55 | } 56 | -------------------------------------------------------------------------------- /slice/skip/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package skip 18 | 19 | // Entry defines items that can be inserted into the skip list. 20 | // This will also be the type returned from a query. 21 | type Entry interface { 22 | // Compare this entry to the provided entry. Return a positive 23 | // number if this entry is greater than, 0 if equal, negative 24 | // number if less than. 25 | Compare(Entry) int 26 | } 27 | 28 | // Entries is a typed list of interface Entry. 29 | type Entries []Entry 30 | 31 | // Iterator defines an interface that allows a consumer to iterate 32 | // all results of a query. All values will be visited in-order. 33 | type Iterator interface { 34 | // Next returns a bool indicating if there is future value 35 | // in the iterator and moves the iterator to that value. 36 | Next() bool 37 | // Value returns an Entry representing the iterator's current 38 | // position. If there is no value, this returns nil. 39 | Value() Entry 40 | // exhaust is a helper method that will iterate this iterator 41 | // to completion and return a list of resulting Entries 42 | // in order. 43 | exhaust() Entries 44 | } 45 | -------------------------------------------------------------------------------- /btree/plus/iterator.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package plus 18 | 19 | const iteratorExhausted = -2 20 | 21 | type iterator struct { 22 | node *lnode 23 | index int 24 | } 25 | 26 | func (iter *iterator) Next() bool { 27 | if iter.index == iteratorExhausted { 28 | return false 29 | } 30 | 31 | iter.index++ 32 | if iter.index >= len(iter.node.keys) { 33 | iter.node = iter.node.pointer 34 | if iter.node == nil { 35 | iter.index = iteratorExhausted 36 | return false 37 | } 38 | iter.index = 0 39 | } 40 | 41 | return true 42 | } 43 | 44 | func (iter *iterator) Value() Key { 45 | if iter.index == iteratorExhausted || 46 | iter.index < 0 || iter.index >= len(iter.node.keys) { 47 | 48 | return nil 49 | } 50 | 51 | return iter.node.keys[iter.index] 52 | } 53 | 54 | // exhaust is a test function that's not exported 55 | func (iter *iterator) exhaust() keys { 56 | keys := make(keys, 0, 10) 57 | for iter := iter; iter.Next(); { 58 | keys = append(keys, iter.Value()) 59 | } 60 | 61 | return keys 62 | } 63 | 64 | func nilIterator() *iterator { 65 | return &iterator{ 66 | index: iteratorExhausted, 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /slice/skip/entries_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package skip 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | func TestEntriesInsert(t *testing.T) { 26 | e1 := newMockEntry(10) 27 | e2 := newMockEntry(5) 28 | 29 | entries := Entries{e1} 30 | result := entries.insert(e2) 31 | assert.Equal(t, Entries{e2, e1}, entries) 32 | assert.Nil(t, result) 33 | 34 | e3 := newMockEntry(15) 35 | result = entries.insert(e3) 36 | assert.Equal(t, Entries{e2, e1, e3}, entries) 37 | assert.Nil(t, result) 38 | } 39 | 40 | func TestInsertOverwrite(t *testing.T) { 41 | e1 := newMockEntry(10) 42 | e2 := newMockEntry(10) 43 | 44 | entries := Entries{e1} 45 | result := entries.insert(e2) 46 | assert.Equal(t, e1, result) 47 | } 48 | 49 | func TestEntriesDelete(t *testing.T) { 50 | e1 := newMockEntry(5) 51 | e2 := newMockEntry(10) 52 | 53 | entries := Entries{e1, e2} 54 | 55 | result := entries.delete(e2) 56 | assert.Equal(t, Entries{e1}, entries) 57 | assert.Equal(t, e2, result) 58 | 59 | result = entries.delete(e1) 60 | assert.Equal(t, Entries{}, entries) 61 | assert.Equal(t, e1, result) 62 | } 63 | -------------------------------------------------------------------------------- /trie/xfast/iterator.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package xfast 18 | 19 | // Entries is a typed list of Entry interfaces. 20 | type Entries []Entry 21 | 22 | // Iterator will iterate of the results of a query. 23 | type Iterator struct { 24 | n *node 25 | first bool 26 | } 27 | 28 | // Next will return a bool indicating if another value exists 29 | // in the iterator. 30 | func (iter *Iterator) Next() bool { 31 | if iter.first { 32 | iter.first = false 33 | return iter.n != nil 34 | } 35 | 36 | iter.n = iter.n.children[1] 37 | return iter.n != nil 38 | } 39 | 40 | // Value will return the Entry representing the iterator's current position. 41 | // If no Entry exists at the present condition, the iterator is 42 | // exhausted and this method will return nil. 43 | func (iter *Iterator) Value() Entry { 44 | if iter.n == nil { 45 | return nil 46 | } 47 | 48 | return iter.n.entry 49 | } 50 | 51 | // exhaust is a helper function that will exhaust this iterator 52 | // and return a list of entries. This is for internal use only. 53 | func (iter *Iterator) exhaust() Entries { 54 | entries := make(Entries, 0, 100) 55 | for it := iter; it.Next(); { 56 | entries = append(entries, it.Value()) 57 | } 58 | 59 | return entries 60 | } 61 | -------------------------------------------------------------------------------- /sort/sort.go: -------------------------------------------------------------------------------- 1 | package merge 2 | 3 | import ( 4 | "runtime" 5 | "sort" 6 | "sync" 7 | ) 8 | 9 | func sortBucket(comparators Comparators) { 10 | sort.Sort(comparators) 11 | } 12 | 13 | func copyChunk(chunk []Comparators) []Comparators { 14 | cp := make([]Comparators, len(chunk)) 15 | copy(cp, chunk) 16 | return cp 17 | } 18 | 19 | // MultithreadedSortComparators will take a list of comparators 20 | // and sort it using as many threads as are available. The list 21 | // is split into buckets for a bucket sort and then recursively 22 | // merged using SymMerge. 23 | func MultithreadedSortComparators(comparators Comparators) Comparators { 24 | toBeSorted := make(Comparators, len(comparators)) 25 | copy(toBeSorted, comparators) 26 | 27 | var wg sync.WaitGroup 28 | 29 | numCPU := int64(runtime.NumCPU()) 30 | if numCPU%2 == 1 { // single core machine 31 | numCPU++ 32 | } 33 | 34 | chunks := chunk(toBeSorted, numCPU) 35 | wg.Add(len(chunks)) 36 | for i := 0; i < len(chunks); i++ { 37 | go func(i int) { 38 | sortBucket(chunks[i]) 39 | wg.Done() 40 | }(i) 41 | } 42 | 43 | wg.Wait() 44 | todo := make([]Comparators, len(chunks)/2) 45 | for { 46 | todo = todo[:len(chunks)/2] 47 | wg.Add(len(chunks) / 2) 48 | for i := 0; i < len(chunks); i += 2 { 49 | go func(i int) { 50 | todo[i/2] = SymMerge(chunks[i], chunks[i+1]) 51 | wg.Done() 52 | }(i) 53 | } 54 | 55 | wg.Wait() 56 | 57 | chunks = copyChunk(todo) 58 | if len(chunks) == 1 { 59 | break 60 | } 61 | } 62 | 63 | return chunks[0] 64 | } 65 | 66 | func chunk(comparators Comparators, numParts int64) []Comparators { 67 | parts := make([]Comparators, numParts) 68 | for i := int64(0); i < numParts; i++ { 69 | parts[i] = comparators[i*int64(len(comparators))/numParts : (i+1)*int64(len(comparators))/numParts] 70 | } 71 | return parts 72 | } 73 | -------------------------------------------------------------------------------- /augmentedtree/mock_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package augmentedtree 18 | 19 | import "fmt" 20 | 21 | type dimension struct { 22 | low, high int64 23 | } 24 | 25 | type mockInterval struct { 26 | dimensions []*dimension 27 | id uint64 28 | } 29 | 30 | func (mi *mockInterval) checkDimension(dimension uint64) { 31 | if dimension > uint64(len(mi.dimensions)) { 32 | panic(fmt.Sprintf(`Dimension: %d out of range.`, dimension)) 33 | } 34 | } 35 | 36 | func (mi *mockInterval) LowAtDimension(dimension uint64) int64 { 37 | return mi.dimensions[dimension-1].low 38 | } 39 | 40 | func (mi *mockInterval) HighAtDimension(dimension uint64) int64 { 41 | return mi.dimensions[dimension-1].high 42 | } 43 | 44 | func (mi *mockInterval) OverlapsAtDimension(iv Interval, dimension uint64) bool { 45 | return mi.HighAtDimension(dimension) > iv.LowAtDimension(dimension) && 46 | mi.LowAtDimension(dimension) < iv.HighAtDimension(dimension) 47 | } 48 | 49 | func (mi mockInterval) ID() uint64 { 50 | return mi.id 51 | } 52 | 53 | func constructSingleDimensionInterval(low, high int64, id uint64) *mockInterval { 54 | return &mockInterval{[]*dimension{&dimension{low: low, high: high}}, id} 55 | } 56 | 57 | func constructMultiDimensionInterval(id uint64, dimensions ...*dimension) *mockInterval { 58 | return &mockInterval{dimensions: dimensions, id: id} 59 | } 60 | -------------------------------------------------------------------------------- /futures/futures_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package futures 18 | 19 | import ( 20 | "sync" 21 | "testing" 22 | "time" 23 | 24 | "github.com/stretchr/testify/assert" 25 | ) 26 | 27 | func TestWaitOnGetResult(t *testing.T) { 28 | completer := make(chan interface{}) 29 | f := New(completer, time.Duration(30*time.Minute)) 30 | var result interface{} 31 | var err error 32 | var wg sync.WaitGroup 33 | wg.Add(1) 34 | go func() { 35 | result, err = f.GetResult() 36 | wg.Done() 37 | }() 38 | 39 | completer <- `test` 40 | wg.Wait() 41 | 42 | assert.Nil(t, err) 43 | assert.Equal(t, `test`, result) 44 | 45 | // ensure we don't get paused on the next iteration. 46 | result, err = f.GetResult() 47 | 48 | assert.Equal(t, `test`, result) 49 | assert.Nil(t, err) 50 | } 51 | 52 | func TestTimeout(t *testing.T) { 53 | completer := make(chan interface{}) 54 | f := New(completer, time.Duration(0)) 55 | 56 | result, err := f.GetResult() 57 | 58 | assert.Nil(t, result) 59 | assert.NotNil(t, err) 60 | } 61 | 62 | func BenchmarkFuture(b *testing.B) { 63 | completer := make(chan interface{}) 64 | timeout := time.Duration(30 * time.Minute) 65 | var wg sync.WaitGroup 66 | 67 | b.ResetTimer() 68 | 69 | for i := 0; i < b.N; i++ { 70 | wg.Add(1) 71 | f := New(completer, timeout) 72 | go func() { 73 | f.GetResult() 74 | wg.Done() 75 | }() 76 | 77 | completer <- `test` 78 | wg.Wait() 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /btree/palm/action.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package palm 18 | 19 | import "sync/atomic" 20 | 21 | type actions []action 22 | 23 | type action interface { 24 | operation() operation 25 | getKey() (Key, uint64) // returns nil if operation complete 26 | addResult(index uint64, result Key) 27 | len() uint64 28 | complete() 29 | } 30 | 31 | type getAction struct { 32 | result, keys Keys 33 | count, done uint64 34 | completer chan Keys 35 | } 36 | 37 | func (ga *getAction) complete() { 38 | ga.completer <- ga.result 39 | close(ga.completer) 40 | } 41 | 42 | func (ga *getAction) operation() operation { 43 | return get 44 | } 45 | 46 | func (ga *getAction) addResult(index uint64, result Key) { 47 | i := atomic.AddUint64(&ga.done, 1) 48 | i-- 49 | if i >= uint64(len(ga.keys)) { 50 | return 51 | } 52 | ga.result[index] = result 53 | if i == uint64(len(ga.keys))-1 { 54 | ga.complete() 55 | } 56 | } 57 | 58 | func (ga *getAction) getKey() (Key, uint64) { 59 | index := atomic.AddUint64(&ga.count, 1) 60 | index-- // 0-index 61 | if index >= uint64(len(ga.keys)) { 62 | return nil, 0 63 | } 64 | 65 | return ga.keys[index], index 66 | } 67 | 68 | func (ga *getAction) len() uint64 { 69 | return uint64(len(ga.keys)) 70 | } 71 | 72 | func newGetAction(keys Keys) *getAction { 73 | return &getAction{ 74 | keys: keys, 75 | completer: make(chan Keys), 76 | result: make(Keys, len(keys)), 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /slice/skip/iterator.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package skip 18 | 19 | const iteratorExhausted = -2 20 | 21 | // iterator represents an object that can be iterated. It will 22 | // return false on Next and nil on Value if there are no further 23 | // values to be iterated. 24 | type iterator struct { 25 | first bool 26 | n *node 27 | } 28 | 29 | // Next returns a bool indicating if there are any further values 30 | // in this iterator. 31 | func (iter *iterator) Next() bool { 32 | if iter.first { 33 | iter.first = false 34 | return iter.n != nil 35 | } 36 | 37 | if iter.n == nil { 38 | return false 39 | } 40 | 41 | iter.n = iter.n.forward[0] 42 | return iter.n != nil 43 | } 44 | 45 | // Value returns an Entry representing the iterator's present 46 | // position in the query. Returns nil if no values remain to iterate. 47 | func (iter *iterator) Value() Entry { 48 | if iter.n == nil { 49 | return nil 50 | } 51 | 52 | return iter.n.entry 53 | } 54 | 55 | // exhaust is a helper method to exhaust this iterator and return 56 | // all remaining entries. 57 | func (iter *iterator) exhaust() Entries { 58 | entries := make(Entries, 0, 10) 59 | for i := iter; i.Next(); { 60 | entries = append(entries, i.Value()) 61 | } 62 | 63 | return entries 64 | } 65 | 66 | // nilIterator returns an iterator that will always return false 67 | // for Next and nil for Value. 68 | func nilIterator() *iterator { 69 | return &iterator{} 70 | } 71 | -------------------------------------------------------------------------------- /bitarray/iterator.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package bitarray 18 | 19 | type sparseBitArrayIterator struct { 20 | index int64 21 | sba *sparseBitArray 22 | } 23 | 24 | // Next increments the index and returns a bool indicating 25 | // if any further items exist. 26 | func (iter *sparseBitArrayIterator) Next() bool { 27 | iter.index++ 28 | return iter.index < int64(len(iter.sba.indices)) 29 | } 30 | 31 | // Value returns the index and block at the given index. 32 | func (iter *sparseBitArrayIterator) Value() (uint64, block) { 33 | return iter.sba.indices[iter.index], iter.sba.blocks[iter.index] 34 | } 35 | 36 | func newCompressedBitArrayIterator(sba *sparseBitArray) *sparseBitArrayIterator { 37 | return &sparseBitArrayIterator{ 38 | sba: sba, 39 | index: -1, 40 | } 41 | } 42 | 43 | type bitArrayIterator struct { 44 | index int64 45 | stopIndex uint64 46 | ba *bitArray 47 | } 48 | 49 | // Next increments the index and returns a bool indicating if any further 50 | // items exist. 51 | func (iter *bitArrayIterator) Next() bool { 52 | iter.index++ 53 | return uint64(iter.index) <= iter.stopIndex 54 | } 55 | 56 | // Value returns an index and the block at this index. 57 | func (iter *bitArrayIterator) Value() (uint64, block) { 58 | return uint64(iter.index), iter.ba.blocks[iter.index] 59 | } 60 | 61 | func newBitArrayIterator(ba *bitArray) *bitArrayIterator { 62 | stop, _ := getIndexAndRemainder(ba.highest) 63 | start, _ := getIndexAndRemainder(ba.lowest) 64 | return &bitArrayIterator{ 65 | ba: ba, 66 | index: int64(start) - 1, 67 | stopIndex: stop, 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /slice/skip/entries.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package skip 18 | 19 | import "sort" 20 | 21 | // search will look for the provided key and return the index 22 | // where that key would be inserted in this list. This could 23 | // be equal to the length of the list which means no suitable entry 24 | // point was found. 25 | func (entries Entries) search(e Entry) int { 26 | return sort.Search(len(entries), func(i int) bool { 27 | return entries[i].Compare(e) > -1 28 | }) 29 | } 30 | 31 | // insert will insert the provided entry into this list. 32 | func (entries *Entries) insert(entry Entry) Entry { 33 | i := entries.search(entry) 34 | if i >= len(*entries) { 35 | *entries = append(*entries, entry) 36 | return nil 37 | } 38 | 39 | if (*entries)[i].Compare(entry) == 0 { 40 | oldEntry := (*entries)[i] 41 | (*entries)[i] = entry 42 | return oldEntry 43 | } 44 | 45 | *entries = append(*entries, nil) 46 | copy((*entries)[i+1:], (*entries)[i:]) 47 | (*entries)[i] = entry 48 | return nil 49 | } 50 | 51 | // delete will delete the provided key from this list. 52 | func (entries *Entries) delete(e Entry) Entry { 53 | i := entries.search(e) 54 | if i >= len(*entries) { 55 | return nil 56 | } 57 | 58 | if (*entries)[i].Compare(e) != 0 { 59 | return nil 60 | } 61 | 62 | oldEntry := (*entries)[i] 63 | copy((*entries)[i:], (*entries)[i+1:]) 64 | (*entries)[len(*entries)-1] = nil 65 | *entries = (*entries)[:len(*entries)-1] 66 | return oldEntry 67 | } 68 | 69 | // get will return the entry associated with the provided key. 70 | // If no such Entry exists, this returns nil. 71 | func (entries Entries) get(e Entry) Entry { 72 | i := entries.search(e) 73 | if i >= len(entries) { 74 | return nil 75 | } 76 | 77 | if entries[i].Compare(e) == 0 { 78 | return entries[i] 79 | } 80 | 81 | return nil 82 | } 83 | -------------------------------------------------------------------------------- /btree/_link/key.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package link 18 | 19 | import "sort" 20 | 21 | func (keys Keys) search(key Key) int { 22 | return sort.Search(len(keys), func(i int) bool { 23 | return keys[i].Compare(key) >= 0 24 | }) 25 | } 26 | 27 | func (keys *Keys) insert(key Key) Key { 28 | i := keys.search(key) 29 | return keys.insertAt(key, i) 30 | } 31 | 32 | func (keys *Keys) insertAt(key Key, i int) Key { 33 | if i == len(*keys) { 34 | *keys = append(*keys, key) 35 | return nil 36 | } 37 | 38 | if (*keys)[i].Compare(key) == 0 { //overwrite case 39 | oldKey := (*keys)[i] 40 | (*keys)[i] = key 41 | return oldKey 42 | } 43 | 44 | *keys = append(*keys, nil) 45 | copy((*keys)[i+1:], (*keys)[i:]) 46 | (*keys)[i] = key 47 | return nil 48 | } 49 | 50 | func (keys *Keys) split() (Key, Keys, Keys) { 51 | i := (len(*keys) / 2) - 1 52 | middle := (*keys)[i] 53 | 54 | left, right := keys.splitAt(i) 55 | return middle, left, right 56 | } 57 | 58 | func (keys *Keys) splitAt(i int) (Keys, Keys) { 59 | right := make(Keys, len(*keys)-i-1, cap(*keys)) 60 | copy(right, (*keys)[i+1:]) 61 | for j := i + 1; j < len(*keys); j++ { 62 | (*keys)[j] = nil 63 | } 64 | *keys = (*keys)[:i+1] 65 | 66 | return *keys, right 67 | } 68 | 69 | func (keys Keys) last() Key { 70 | return keys[len(keys)-1] 71 | } 72 | 73 | func (keys Keys) first() Key { 74 | return keys[0] 75 | } 76 | 77 | func (keys Keys) needsSplit() bool { 78 | return cap(keys) == len(keys) 79 | } 80 | 81 | func (keys Keys) reverse() Keys { 82 | reversed := make(Keys, len(keys)) 83 | for i := len(keys) - 1; i >= 0; i-- { 84 | reversed[len(keys)-1-i] = keys[i] 85 | } 86 | 87 | return reversed 88 | } 89 | 90 | func chunkKeys(keys Keys, numParts int64) []Keys { 91 | parts := make([]Keys, numParts) 92 | for i := int64(0); i < numParts; i++ { 93 | parts[i] = keys[i*int64(len(keys))/numParts : (i+1)*int64(len(keys))/numParts] 94 | } 95 | return parts 96 | } 97 | -------------------------------------------------------------------------------- /btree/palm/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /* 18 | Package palm implements parallel architecture-friendly latch-free 19 | modifications (PALM). Details can be found here: 20 | 21 | http://cs.unc.edu/~sewall/palm.pdf 22 | 23 | The primary purpose of the tree is to efficiently batch operations 24 | in such a way that locks are not required. This is most beneficial 25 | for in-memory indices. Otherwise, the operations have typical B-tree 26 | time complexities. 27 | 28 | You primarily see the benefits of multithreading in availability and 29 | bulk operations. 30 | 31 | Benchmarks: 32 | 33 | BenchmarkReadAndWrites-8 1000 1543648 ns/op 34 | BenchmarkBulkAdd-8 1000 1705673 ns/op 35 | BenchmarkBulkAddToExisting-8 100 70056512 ns/op 36 | BenchmarkGet-8 100000 17128 ns/op 37 | BenchmarkBulkGet-8 3000 507249 ns/op 38 | */ 39 | package palm 40 | 41 | import "github.com/Workiva/go-datastructures/slice/skip" 42 | 43 | // Keys is a typed list of Key interfaces. 44 | type Keys []Key 45 | 46 | // Key defines items that can be inserted into or searched for 47 | // in the tree. 48 | type Key interface { 49 | // Compare should return an int indicating how this key relates 50 | // to the provided key. -1 will indicate less than, 0 will indicate 51 | // equality, and 1 will indicate greater than. Duplicate keys 52 | // are allowed, but duplicate IDs are not. 53 | Compare(skip.Entry) int 54 | } 55 | 56 | // BTree is the interface returned from this package's constructor. 57 | type BTree interface { 58 | // Insert will insert the provided keys into the tree. 59 | Insert(...Key) 60 | // Get will return a key matching the associated provided 61 | // key if it exists. 62 | Get(...Key) Keys 63 | // Len returns the number of items in the tree. 64 | Len() uint64 65 | // Dispose will clean up any resources used by this tree. This 66 | // must be called to prevent a memory leak. 67 | Dispose() 68 | } 69 | -------------------------------------------------------------------------------- /bitarray/block.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package bitarray 18 | 19 | import ( 20 | "fmt" 21 | "unsafe" 22 | ) 23 | 24 | // block defines how we split apart the bit array. This also determines the size 25 | // of s. This can be changed to any unsigned integer type: uint8, uint16, 26 | // uint32, and so on. 27 | type block uint64 28 | 29 | // s denotes the size of any element in the block array. 30 | // For a block of uint64, s will be equal to 64 31 | // For a block of uint32, s will be equal to 32 32 | // and so on... 33 | const s = uint64(unsafe.Sizeof(block(0)) * 8) 34 | 35 | // maximumBlock represents a block of all 1s and is used in the constructors. 36 | const maximumBlock = block(0) | ^block(0) 37 | 38 | func (b block) toNums(offset uint64, nums *[]uint64) { 39 | for i := uint64(0); i < s; i++ { 40 | if b&block(1< 0 { 41 | *nums = append(*nums, i+offset) 42 | } 43 | } 44 | } 45 | 46 | func (b block) findLeftPosition() uint64 { 47 | for i := s - 1; i < s; i-- { 48 | test := block(1 << i) 49 | if b&test == test { 50 | return i 51 | } 52 | } 53 | 54 | return s 55 | } 56 | 57 | func (b block) findRightPosition() uint64 { 58 | for i := uint64(0); i < s; i++ { 59 | test := block(1 << i) 60 | if b&test == test { 61 | return i 62 | } 63 | } 64 | 65 | return s 66 | } 67 | 68 | func (b block) insert(position uint64) block { 69 | return b | block(1<= x 48 | }) 49 | } 50 | 51 | // Sort will in-place sort this list of int64s. 52 | func (s Int64Slice) Sort() { 53 | sort.Sort(s) 54 | } 55 | 56 | // Swap will swap the elements at positions i and j. This is required 57 | // by sort.Interface. 58 | func (s Int64Slice) Swap(i, j int) { 59 | s[i], s[j] = s[j], s[i] 60 | } 61 | 62 | // Exists returns a bool indicating if the provided value exists 63 | // in this list. This has undefined behavior if the list is not 64 | // sorted. 65 | func (s Int64Slice) Exists(x int64) bool { 66 | i := s.Search(x) 67 | if i == len(s) { 68 | return false 69 | } 70 | 71 | return s[i] == x 72 | } 73 | 74 | // Insert will insert x into the sorted position in this list 75 | // and return a list with the value added. If this slice has not 76 | // been sorted Insert's behavior is undefined. 77 | func (s Int64Slice) Insert(x int64) Int64Slice { 78 | i := s.Search(x) 79 | if i == len(s) { 80 | return append(s, x) 81 | } 82 | 83 | if s[i] == x { 84 | return s 85 | } 86 | 87 | s = append(s, 0) 88 | copy(s[i+1:], s[i:]) 89 | s[i] = x 90 | return s 91 | } 92 | -------------------------------------------------------------------------------- /trie/yfast/iterator.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package yfast 18 | 19 | import "github.com/Workiva/go-datastructures/trie/xfast" 20 | 21 | // iteratorExhausted is a magic value for an index to tell us 22 | // that the iterator has been exhausted. 23 | const iteratorExhausted = -2 24 | 25 | // iterExhausted is a helper function to tell us if an iterator 26 | // has been exhausted. 27 | func iterExhausted(iter *Iterator) bool { 28 | return iter.index == iteratorExhausted 29 | } 30 | 31 | // Iterator will iterate of the results of a query. 32 | type Iterator struct { 33 | xfastIterator *xfast.Iterator 34 | index int 35 | entries *entriesWrapper 36 | } 37 | 38 | // Next will return a bool indicating if another value exists 39 | // in the iterator. 40 | func (iter *Iterator) Next() bool { 41 | if iterExhausted(iter) { 42 | return false 43 | } 44 | iter.index++ 45 | if iter.index >= len(iter.entries.entries) { 46 | next := iter.xfastIterator.Next() 47 | if !next { 48 | iter.index = iteratorExhausted 49 | return false 50 | } 51 | var ok bool 52 | iter.entries, ok = iter.xfastIterator.Value().(*entriesWrapper) 53 | if !ok { 54 | iter.index = iteratorExhausted 55 | return false 56 | } 57 | iter.index = 0 58 | } 59 | 60 | return true 61 | } 62 | 63 | // Value will return the Entry representing the iterator's current position. 64 | // If no Entry exists at the present condition, the iterator is 65 | // exhausted and this method will return nil. 66 | func (iter *Iterator) Value() Entry { 67 | if iterExhausted(iter) { 68 | return nil 69 | } 70 | 71 | if iter.entries == nil || iter.index < 0 || iter.index >= len(iter.entries.entries) { 72 | return nil 73 | } 74 | 75 | return iter.entries.entries[iter.index] 76 | } 77 | 78 | // exhaust is a helper function that will exhaust this iterator 79 | // and return a list of entries. This is for internal use only. 80 | func (iter *Iterator) exhaust() Entries { 81 | entries := make(Entries, 0, 100) 82 | for it := iter; it.Next(); { 83 | entries = append(entries, it.Value()) 84 | } 85 | 86 | return entries 87 | } 88 | 89 | // nilIterator is an iterator that will always return false 90 | // from Next() and nil for Value(). 91 | func nilIterator() *Iterator { 92 | return &Iterator{ 93 | index: iteratorExhausted, 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /futures/futures.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /* 18 | Package futures is useful for broadcasting an identical message to a multitude 19 | of listeners as opposed to channels which will choose a listener at random 20 | if multiple listeners are listening to the same channel. The future will 21 | also cache the result so any future interest will be immediately returned 22 | to the consumer. 23 | */ 24 | package futures 25 | 26 | import ( 27 | "fmt" 28 | "sync" 29 | "time" 30 | ) 31 | 32 | // Completer is a channel that the future expects to receive 33 | // a result on. The future only receives on this channel. 34 | type Completer <-chan interface{} 35 | 36 | // Future represents an object that can be used to perform asynchronous 37 | // tasks. The constructor of the future will complete it, and listeners 38 | // will block on getresult until a result is received. This is different 39 | // from a channel in that the future is only completed once, and anyone 40 | // listening on the future will get the result, regardless of the number 41 | // of listeners. 42 | type Future struct { 43 | triggered bool // because item can technically be nil and still be valid 44 | item interface{} 45 | err error 46 | lock sync.Mutex 47 | wg sync.WaitGroup 48 | } 49 | 50 | // GetResult will immediately fetch the result if it exists 51 | // or wait on the result until it is ready. 52 | func (f *Future) GetResult() (interface{}, error) { 53 | f.lock.Lock() 54 | if f.triggered { 55 | f.lock.Unlock() 56 | return f.item, f.err 57 | } 58 | f.lock.Unlock() 59 | 60 | f.wg.Wait() 61 | return f.item, f.err 62 | } 63 | 64 | func (f *Future) setItem(item interface{}, err error) { 65 | f.lock.Lock() 66 | f.triggered = true 67 | f.item = item 68 | f.err = err 69 | f.lock.Unlock() 70 | f.wg.Done() 71 | } 72 | 73 | func listenForResult(f *Future, ch Completer, timeout time.Duration, wg *sync.WaitGroup) { 74 | wg.Done() 75 | select { 76 | case item := <-ch: 77 | f.setItem(item, nil) 78 | case <-time.After(timeout): 79 | f.setItem(nil, fmt.Errorf(`Timeout after %f seconds.`, timeout.Seconds())) 80 | } 81 | } 82 | 83 | // New is the constructor to generate a new future. Pass the completed 84 | // item to the toComplete channel and any listeners will get 85 | // notified. If timeout is hit before toComplete is called, 86 | // any listeners will get passed an error. 87 | func New(completer Completer, timeout time.Duration) *Future { 88 | f := &Future{} 89 | f.wg.Add(1) 90 | var wg sync.WaitGroup 91 | wg.Add(1) 92 | go listenForResult(f, completer, timeout, &wg) 93 | wg.Wait() 94 | return f 95 | } 96 | -------------------------------------------------------------------------------- /bitarray/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /* 18 | Package bitarray or bitmap is useful when comparing large amounts of structured 19 | data if the data can be represented as integers. For instance, set 20 | intersection of {1, 3, 5} and {3, 5, 7} represented as bitarrays can 21 | be done in a single clock cycle (not counting the time it takes to convert) 22 | the resultant array back into integers). When Go implements a command 23 | to get trailing zeroes, the reconversion back into integers should be much faster. 24 | */ 25 | package bitarray 26 | 27 | // BitArray represents a structure that can be used to 28 | // quickly check for existence when using a large number 29 | // of items in a very memory efficient way. 30 | type BitArray interface { 31 | // SetBit sets the bit at the given position. This 32 | // function returns an error if the position is out 33 | // of range. A sparse bit array never returns an error. 34 | SetBit(k uint64) error 35 | // GetBit gets the bit at the given position. This 36 | // function returns an error if the position is out 37 | // of range. A sparse bit array never returns an error. 38 | GetBit(k uint64) (bool, error) 39 | // ClearBit clears the bit at the given position. This 40 | // function returns an error if the position is out 41 | // of range. A sparse bit array never returns an error. 42 | ClearBit(k uint64) error 43 | // Reset sets all values to zero. 44 | Reset() 45 | // Blocks returns an iterator to be used to iterate 46 | // over the bit array. 47 | Blocks() Iterator 48 | // Equals returns a bool indicating equality between the 49 | // two bit arrays. 50 | Equals(other BitArray) bool 51 | // Intersects returns a bool indicating if the other bit 52 | // array intersects with this bit array. 53 | Intersects(other BitArray) bool 54 | // Capacity returns either the given capacity of the bit array 55 | // in the case of a dense bit array or the highest possible 56 | // seen capacity of the sparse array. 57 | Capacity() uint64 58 | // Or will bitwise or the two bitarrays and return a new bitarray 59 | // representing the result. 60 | Or(other BitArray) BitArray 61 | // And will bitwise and the two bitarrays and return a new bitarray 62 | // representing the result. 63 | And(other BitArray) BitArray 64 | // ToNums converts this bit array to the list of numbers contained 65 | // within it. 66 | ToNums() []uint64 67 | } 68 | 69 | // Iterator defines methods used to iterate over a bit array. 70 | type Iterator interface { 71 | // Next moves the pointer to the next block. Returns 72 | // false when no blocks remain. 73 | Next() bool 74 | // Value returns the next block and its index 75 | Value() (uint64, block) 76 | } 77 | -------------------------------------------------------------------------------- /rangetree/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /* 18 | Package rangetree is designed to store n-dimensional data in an easy-to-query 19 | way. Given this package's primary use as representing cartesian data, this 20 | information is represented by int64s at n-dimensions. This implementation 21 | is not actually a tree but a sparse n-dimensional list. This package also 22 | includes two implementations of this sparse list, one mutable (and not threadsafe) 23 | and another that is immutable copy-on-write which is threadsafe. The mutable 24 | version is obviously faster but will likely have write contention for any 25 | consumer that needs a threadsafe rangetree. 26 | 27 | TODO: unify both implementations with the same interface. 28 | */ 29 | package rangetree 30 | 31 | // Entry defines items that can be added to the rangetree. 32 | type Entry interface { 33 | // ValueAtDimension returns the value of this entry 34 | // at the specified dimension. 35 | ValueAtDimension(dimension uint64) int64 36 | } 37 | 38 | // Interval describes the methods required to query the rangetree. 39 | type Interval interface { 40 | // LowAtDimension returns an integer representing the lower bound 41 | // at the requested dimension. 42 | LowAtDimension(dimension uint64) int64 43 | // HighAtDimension returns an integer representing the higher bound 44 | // at the request dimension. 45 | HighAtDimension(dimension uint64) int64 46 | } 47 | 48 | // RangeTree describes the methods available to the rangetree. 49 | type RangeTree interface { 50 | // Add will add the provided entries to the tree. Any entries that 51 | // were overwritten will be returned in the order in which they 52 | // were overwritten. If a cell's addition does not overwrite, a nil 53 | // is returned for that cell for its index in the provided cells. 54 | Add(entries ...Entry) Entries 55 | // Len returns the number of entries in the tree. 56 | Len() uint64 57 | // Delete will remove the provided entries from the tree. 58 | Delete(entries ...Entry) 59 | // Query will return a list of entries that fall within 60 | // the provided interval. 61 | Query(interval Interval) Entries 62 | // Apply will call the provided function with each entry that exists 63 | // within the provided range, in order. Return false at any time to 64 | // cancel iteration. Altering the entry in such a way that its location 65 | // changes will result in undefined behavior. 66 | Apply(interval Interval, fn func(Entry) bool) 67 | // InsertAtDimension will increment items at and above the given index 68 | // by the number provided. Provide a negative number to to decrement. 69 | // Returned are two lists. The first list is a list of entries that 70 | // were moved. The second is a list entries that were deleted. These 71 | // lists are exclusive. 72 | InsertAtDimension(dimension uint64, index, number int64) (Entries, Entries) 73 | } 74 | -------------------------------------------------------------------------------- /augmentedtree/interface.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /* 18 | Package augmentedtree is designed to be useful when checking 19 | for intersection of ranges in n-dimensions. For instance, if you imagine 20 | an xy plane then the augmented tree is for telling you if 21 | plane defined by the points (0, 0) and (10, 10). The augmented 22 | tree can tell you if that plane overlaps with a plane defined by 23 | (-5, -5) and (5, 5) (true in this case). You can also check 24 | intersections against a point by constructing a range of encompassed 25 | solely if a single point. 26 | 27 | The current tree is a simple top-down red-black binary search tree. 28 | 29 | TODO: Add a bottom-up implementation to assist with duplicate 30 | range handling. 31 | */ 32 | package augmentedtree 33 | 34 | // Interval is the interface that must be implemented by any 35 | // item added to the interval tree. 36 | type Interval interface { 37 | // LowAtDimension returns an integer representing the lower bound 38 | // at the requested dimension. 39 | LowAtDimension(uint64) int64 40 | // HighAtDimension returns an integer representing the higher bound 41 | // at the requested dimension. 42 | HighAtDimension(uint64) int64 43 | // OverlapsAtDimension should return a bool indicating if the provided 44 | // interval overlaps this interval at the dimension requested. 45 | OverlapsAtDimension(Interval, uint64) bool 46 | // ID should be a unique ID representing this interval. This 47 | // is used to identify which interval to delete from the tree if 48 | // there are duplicates. 49 | ID() uint64 50 | } 51 | 52 | // Tree defines the object that is returned from the 53 | // tree constructor. We use a Tree interface here because 54 | // the returned tree could be a single dimension or many 55 | // dimensions. 56 | type Tree interface { 57 | // Add will add the provided intervals to the tree. 58 | Add(intervals ...Interval) 59 | // Len returns the number of intervals in the tree. 60 | Len() uint64 61 | // Delete will remove the provided intervals from the tree. 62 | Delete(intervals ...Interval) 63 | // Query will return a list of intervals that intersect the provided 64 | // interval. The provided interval's ID method is ignored so the 65 | // provided ID is irrelevant. 66 | Query(interval Interval) Intervals 67 | // Insert will shift intervals in the tree based on the specified 68 | // index and the specified count. Dimension specifies where to 69 | // apply the shift. Returned is a list of intervals impacted and 70 | // list of intervals deleted. Intervals are deleted if the shift 71 | // makes the interval size zero or less, ie, min >= max. These 72 | // intervals are automatically removed from the tree. The tree 73 | // does not alter the ranges on the intervals themselves, the consumer 74 | // is expected to do that. 75 | Insert(dimension uint64, index, count int64) (Intervals, Intervals) 76 | } 77 | -------------------------------------------------------------------------------- /btree/plus/btree.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /* 18 | Package btree/plus implements the ubiquitous B+ tree. As of this writing, 19 | the tree is not quite finished. The delete-node merge functionaly needs 20 | to be added. There are also some performance improvements that can be 21 | made, with some possible concurrency mechanisms. 22 | 23 | This is a mutable b-tree so it is not threadsafe. 24 | 25 | Performance characteristics: 26 | Space: O(n) 27 | Insert: O(log n) 28 | Search: O(log n) 29 | 30 | BenchmarkIteration-8 10000 109347 ns/op 31 | BenchmarkInsert-8 3000000 608 ns/op 32 | BenchmarkGet-8 3000000 627 ns/op 33 | */ 34 | package plus 35 | 36 | func keySearch(keys keys, key Key) int { 37 | low, high := 0, len(keys)-1 38 | var mid int 39 | for low <= high { 40 | mid = (high + low) / 2 41 | switch keys[mid].Compare(key) { 42 | case 1: 43 | low = mid + 1 44 | case -1: 45 | high = mid - 1 46 | case 0: 47 | return mid 48 | } 49 | } 50 | return low 51 | } 52 | 53 | type btree struct { 54 | root node 55 | nodeSize, number uint64 56 | } 57 | 58 | func (tree *btree) insert(key Key) { 59 | if tree.root == nil { 60 | n := newLeafNode(tree.nodeSize) 61 | n.insert(tree, key) 62 | tree.number = 1 63 | return 64 | } 65 | 66 | result := tree.root.insert(tree, key) 67 | if result { 68 | tree.number++ 69 | } 70 | 71 | if tree.root.needsSplit(tree.nodeSize) { 72 | tree.root = split(tree, nil, tree.root) 73 | } 74 | } 75 | 76 | // Insert will insert the provided keys into the btree. This is an 77 | // O(m*log n) operation where m is the number of keys to be inserted 78 | // and n is the number of items in the tree. 79 | func (tree *btree) Insert(keys ...Key) { 80 | for _, key := range keys { 81 | tree.insert(key) 82 | } 83 | } 84 | 85 | // Iter returns an iterator that can be used to traverse the b-tree 86 | // starting from the specified key or its successor. 87 | func (tree *btree) Iter(key Key) Iterator { 88 | if tree.root == nil { 89 | return nilIterator() 90 | } 91 | 92 | return tree.root.find(key) 93 | } 94 | 95 | func (tree *btree) get(key Key) Key { 96 | iter := tree.root.find(key) 97 | if !iter.Next() { 98 | return nil 99 | } 100 | 101 | if iter.Value().Compare(key) == 0 { 102 | return iter.Value() 103 | } 104 | 105 | return nil 106 | } 107 | 108 | // Get will retrieve any keys matching the provided keys in the tree. 109 | // Returns nil in any place of a key that couldn't be found. Each lookup 110 | // is an O(log n) operation. 111 | func (tree *btree) Get(keys ...Key) Keys { 112 | results := make(Keys, 0, len(keys)) 113 | for _, k := range keys { 114 | results = append(results, tree.get(k)) 115 | } 116 | 117 | return results 118 | } 119 | 120 | // Len returns the number of items in this tree. 121 | func (tree *btree) Len() uint64 { 122 | return tree.number 123 | } 124 | 125 | func newBTree(nodeSize uint64) *btree { 126 | return &btree{ 127 | nodeSize: nodeSize, 128 | root: newLeafNode(nodeSize), 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /trie/yfast/entries_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package yfast 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | func TestEntriesInsert(t *testing.T) { 26 | es := Entries{} 27 | 28 | e1 := newMockEntry(5) 29 | e2 := newMockEntry(1) 30 | 31 | es.insert(e1) 32 | es.insert(e2) 33 | 34 | assert.Equal(t, Entries{e2, e1}, es) 35 | 36 | e3 := newMockEntry(3) 37 | es.insert(e3) 38 | 39 | assert.Equal(t, Entries{e2, e3, e1}, es) 40 | } 41 | 42 | func TestEntriesDelete(t *testing.T) { 43 | es := Entries{} 44 | 45 | e1 := newMockEntry(5) 46 | e2 := newMockEntry(1) 47 | es.insert(e1) 48 | es.insert(e2) 49 | 50 | es.delete(5) 51 | assert.Equal(t, Entries{e2}, es) 52 | 53 | es.delete(1) 54 | assert.Equal(t, Entries{}, es) 55 | } 56 | 57 | func TestEntriesMax(t *testing.T) { 58 | es := Entries{} 59 | max, ok := es.max() 60 | assert.Equal(t, uint64(0), max) 61 | assert.False(t, ok) 62 | 63 | e2 := newMockEntry(1) 64 | es.insert(e2) 65 | max, ok = es.max() 66 | assert.Equal(t, uint64(1), max) 67 | assert.True(t, ok) 68 | 69 | e1 := newMockEntry(5) 70 | es.insert(e1) 71 | max, ok = es.max() 72 | assert.Equal(t, uint64(5), max) 73 | assert.True(t, ok) 74 | } 75 | 76 | func TestEntriesGet(t *testing.T) { 77 | es := Entries{} 78 | 79 | e1 := newMockEntry(5) 80 | e2 := newMockEntry(1) 81 | es.insert(e1) 82 | es.insert(e2) 83 | 84 | result := es.get(5) 85 | assert.Equal(t, e1, result) 86 | 87 | result = es.get(1) 88 | assert.Equal(t, e2, result) 89 | 90 | result = es.get(10) 91 | assert.Nil(t, result) 92 | } 93 | 94 | func TestEntriesSuccessor(t *testing.T) { 95 | es := Entries{} 96 | 97 | successor, i := es.successor(5) 98 | assert.Equal(t, -1, i) 99 | assert.Nil(t, successor) 100 | 101 | e1 := newMockEntry(5) 102 | e2 := newMockEntry(1) 103 | es.insert(e1) 104 | es.insert(e2) 105 | 106 | successor, i = es.successor(0) 107 | assert.Equal(t, 0, i) 108 | assert.Equal(t, e2, successor) 109 | 110 | successor, i = es.successor(2) 111 | assert.Equal(t, 1, i) 112 | assert.Equal(t, e1, successor) 113 | 114 | successor, i = es.successor(5) 115 | assert.Equal(t, 1, i) 116 | assert.Equal(t, e1, successor) 117 | 118 | successor, i = es.successor(10) 119 | assert.Equal(t, -1, i) 120 | assert.Nil(t, successor) 121 | } 122 | 123 | func TestEntriesPredecessor(t *testing.T) { 124 | es := Entries{} 125 | 126 | predecessor, i := es.predecessor(5) 127 | assert.Equal(t, -1, i) 128 | assert.Nil(t, predecessor) 129 | 130 | e1 := newMockEntry(5) 131 | e2 := newMockEntry(1) 132 | es.insert(e1) 133 | es.insert(e2) 134 | 135 | predecessor, i = es.predecessor(0) 136 | assert.Equal(t, -1, i) 137 | assert.Nil(t, predecessor) 138 | 139 | predecessor, i = es.predecessor(2) 140 | assert.Equal(t, 0, i) 141 | assert.Equal(t, e2, predecessor) 142 | 143 | predecessor, i = es.predecessor(5) 144 | assert.Equal(t, 1, i) 145 | assert.Equal(t, e1, predecessor) 146 | 147 | predecessor, i = es.predecessor(10) 148 | assert.Equal(t, 1, i) 149 | assert.Equal(t, e1, predecessor) 150 | } 151 | -------------------------------------------------------------------------------- /bitarray/and.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package bitarray 18 | 19 | func andSparseWithSparseBitArray(sba, other *sparseBitArray) BitArray { 20 | max := maxInt64(int64(len(sba.indices)), int64(len(other.indices))) 21 | indices := make(uintSlice, 0, max) 22 | blocks := make(blocks, 0, max) 23 | 24 | selfIndex := 0 25 | otherIndex := 0 26 | 27 | // move through the array and compare the blocks if they happen to 28 | // intersect 29 | for { 30 | if selfIndex == len(sba.indices) || otherIndex == len(other.indices) { 31 | // One of the arrays has been exhausted. We don't need 32 | // to compare anything else for a bitwise and; the 33 | // operation is complete. 34 | break 35 | } 36 | 37 | selfValue := sba.indices[selfIndex] 38 | otherValue := other.indices[otherIndex] 39 | 40 | switch { 41 | case otherValue < selfValue: 42 | // The `sba` bitarray has a block with a index position 43 | // greater than us. We want to compare with that block 44 | // if possible, so move our `other` index closer to that 45 | // block's index. 46 | otherIndex++ 47 | 48 | case otherValue > selfValue: 49 | // This is the exact logical inverse of the above case. 50 | selfIndex++ 51 | 52 | default: 53 | // Here, our indices match for both `sba` and `other`. 54 | // Time to do the bitwise AND operation and add a block 55 | // to our result list. 56 | indices = append(indices, selfValue) 57 | blocks = append(blocks, sba.blocks[selfIndex].and(other.blocks[otherIndex])) 58 | selfIndex++ 59 | otherIndex++ 60 | } 61 | } 62 | 63 | return &sparseBitArray{ 64 | indices: indices, 65 | blocks: blocks, 66 | } 67 | } 68 | 69 | func andSparseWithDenseBitArray(sba *sparseBitArray, other *bitArray) BitArray { 70 | // Use a duplicate of the sparse array to store the results of the 71 | // bitwise and. More memory-efficient than allocating a new dense bit 72 | // array. 73 | // 74 | // NOTE: this could be faster if we didn't copy the values as well 75 | // (since they are overwritten), but I don't want this method to know 76 | // too much about the internals of sparseBitArray. The performance hit 77 | // should be minor anyway. 78 | ba := sba.copy() 79 | 80 | // Run through the sparse array and attempt comparisons wherever 81 | // possible against the dense bit array. 82 | for selfIndex, selfValue := range ba.indices { 83 | 84 | if selfValue >= uint64(len(other.blocks)) { 85 | // The dense bit array has been exhausted. This is the 86 | // annoying case because we have to trim the sparse 87 | // array to the size of the dense array. 88 | ba.blocks = ba.blocks[:selfIndex] 89 | ba.indices = ba.indices[:selfIndex] 90 | 91 | // once this is done, there are no more comparisons. 92 | // We're ready to return 93 | break 94 | } 95 | 96 | ba.blocks[selfIndex] = ba.blocks[selfIndex].and( 97 | other.blocks[selfValue]) 98 | } 99 | 100 | return ba 101 | } 102 | 103 | func andDenseWithDenseBitArray(dba, other *bitArray) BitArray { 104 | min := minUint64(uint64(len(dba.blocks)), uint64(len(other.blocks))) 105 | 106 | ba := newBitArray(min * s) 107 | 108 | for i := uint64(0); i < min; i++ { 109 | ba.blocks[i] = dba.blocks[i].and(other.blocks[i]) 110 | } 111 | 112 | ba.setLowest() 113 | ba.setHighest() 114 | 115 | return ba 116 | } 117 | -------------------------------------------------------------------------------- /rangetree/ordered_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package rangetree 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | func TestOrderedAdd(t *testing.T) { 26 | nodes := make(orderedNodes, 0) 27 | 28 | n1 := newNode(4, constructMockEntry(1, 4), false) 29 | n2 := newNode(1, constructMockEntry(2, 1), false) 30 | 31 | nodes.add(n1) 32 | nodes.add(n2) 33 | 34 | assert.Equal(t, orderedNodes{n2, n1}, nodes) 35 | } 36 | 37 | func TestOrderedDelete(t *testing.T) { 38 | nodes := make(orderedNodes, 0) 39 | 40 | n1 := newNode(4, constructMockEntry(1, 4), false) 41 | n2 := newNode(1, constructMockEntry(2, 1), false) 42 | 43 | nodes.add(n1) 44 | nodes.add(n2) 45 | 46 | nodes.delete(n2.value) 47 | 48 | assert.Equal(t, orderedNodes{n1}, nodes) 49 | 50 | nodes.delete(n1.value) 51 | 52 | assert.Len(t, nodes, 0) 53 | } 54 | 55 | func TestApply(t *testing.T) { 56 | ns := make(orderedNodes, 0) 57 | 58 | n1 := newNode(4, constructMockEntry(1, 4), false) 59 | n2 := newNode(1, constructMockEntry(2, 1), false) 60 | 61 | ns.add(n1) 62 | ns.add(n2) 63 | 64 | results := make(nodes, 0, 2) 65 | 66 | ns.apply(1, 2, func(n *node) bool { 67 | results = append(results, n) 68 | return true 69 | }) 70 | 71 | assert.Equal(t, nodes{n2}, results) 72 | 73 | results = results[:0] 74 | 75 | ns.apply(0, 1, func(n *node) bool { 76 | results = append(results, n) 77 | return true 78 | }) 79 | 80 | assert.Len(t, results, 0) 81 | results = results[:0] 82 | 83 | ns.apply(2, 4, func(n *node) bool { 84 | results = append(results, n) 85 | return true 86 | }) 87 | 88 | assert.Len(t, results, 0) 89 | results = results[:0] 90 | 91 | ns.apply(4, 5, func(n *node) bool { 92 | results = append(results, n) 93 | return true 94 | }) 95 | 96 | assert.Equal(t, nodes{n1}, results) 97 | results = results[:0] 98 | 99 | ns.apply(0, 5, func(n *node) bool { 100 | results = append(results, n) 101 | return true 102 | }) 103 | 104 | assert.Equal(t, nodes{n2, n1}, results) 105 | results = results[:0] 106 | 107 | ns.apply(5, 10, func(n *node) bool { 108 | results = append(results, n) 109 | return true 110 | }) 111 | 112 | assert.Len(t, results, 0) 113 | results = results[:0] 114 | 115 | ns.apply(0, 100, func(n *node) bool { 116 | results = append(results, n) 117 | return false 118 | }) 119 | 120 | assert.Equal(t, nodes{n2}, results) 121 | } 122 | 123 | func TestInsertDelete(t *testing.T) { 124 | ns := make(orderedNodes, 0) 125 | 126 | n1 := newNode(4, constructMockEntry(1, 4), false) 127 | n2 := newNode(1, constructMockEntry(2, 1), false) 128 | n3 := newNode(2, constructMockEntry(3, 2), false) 129 | 130 | ns.add(n1) 131 | ns.add(n2) 132 | ns.add(n3) 133 | 134 | modified := make(Entries, 0, 1) 135 | deleted := make(Entries, 0, 1) 136 | 137 | ns.insert(2, 2, 2, 0, -5, &modified, &deleted) 138 | 139 | assert.Len(t, ns, 0) 140 | assert.Equal(t, Entries{n2.entry, n3.entry, n1.entry}, deleted) 141 | } 142 | 143 | func BenchmarkPrepend(b *testing.B) { 144 | numItems := 100000 145 | ns := make(orderedNodes, 0, numItems) 146 | 147 | for i := b.N; i < b.N+numItems; i++ { 148 | ns.add(newNode(int64(i), constructMockEntry(uint64(i), int64(i)), false)) 149 | } 150 | 151 | b.ResetTimer() 152 | 153 | for i := 0; i < b.N; i++ { 154 | ns.add(newNode(int64(i), constructMockEntry(uint64(i), int64(i)), false)) 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /set/dict.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /* 18 | Package set is a simple unordered set implemented with a map. This set 19 | is threadsafe which decreases performance. 20 | 21 | TODO: Actually write custom hashmap using the hash/fnv hasher. 22 | */ 23 | 24 | package set 25 | 26 | import "sync" 27 | 28 | var pool = sync.Pool{} 29 | 30 | // Set is an implementation of ISet using the builtin map type. Set is threadsafe. 31 | type Set struct { 32 | items map[interface{}]struct{} 33 | lock sync.RWMutex 34 | flattened []interface{} 35 | } 36 | 37 | // Add will add the provided items to the set. 38 | func (set *Set) Add(items ...interface{}) { 39 | set.lock.Lock() 40 | defer set.lock.Unlock() 41 | 42 | set.flattened = nil 43 | for _, item := range items { 44 | set.items[item] = struct{}{} 45 | } 46 | } 47 | 48 | // Remove will remove the given items from the set. 49 | func (set *Set) Remove(items ...interface{}) { 50 | set.lock.Lock() 51 | defer set.lock.Unlock() 52 | 53 | set.flattened = nil 54 | for _, item := range items { 55 | delete(set.items, item) 56 | } 57 | } 58 | 59 | // Exists returns a bool indicating if the given item exists in the set. 60 | func (set *Set) Exists(item interface{}) bool { 61 | set.lock.RLock() 62 | 63 | _, ok := set.items[item] 64 | 65 | set.lock.RUnlock() 66 | 67 | return ok 68 | } 69 | 70 | // Flatten will return a list of the items in the set. 71 | func (set *Set) Flatten() []interface{} { 72 | set.lock.Lock() 73 | defer set.lock.Unlock() 74 | 75 | if set.flattened != nil { 76 | return set.flattened 77 | } 78 | 79 | set.flattened = make([]interface{}, 0, len(set.items)) 80 | for item := range set.items { 81 | set.flattened = append(set.flattened, item) 82 | } 83 | return set.flattened 84 | } 85 | 86 | // Len returns the number of items in the set. 87 | func (set *Set) Len() int64 { 88 | set.lock.RLock() 89 | 90 | size := int64(len(set.items)) 91 | 92 | set.lock.RUnlock() 93 | 94 | return size 95 | } 96 | 97 | // Clear will remove all items from the set. 98 | func (set *Set) Clear() { 99 | set.lock.Lock() 100 | 101 | set.items = map[interface{}]struct{}{} 102 | 103 | set.lock.Unlock() 104 | } 105 | 106 | // All returns a bool indicating if all of the supplied items exist in the set. 107 | func (set *Set) All(items ...interface{}) bool { 108 | set.lock.RLock() 109 | defer set.lock.RUnlock() 110 | 111 | for _, item := range items { 112 | if _, ok := set.items[item]; !ok { 113 | return false 114 | } 115 | } 116 | 117 | return true 118 | } 119 | 120 | // Dispose will add this set back into the pool. 121 | func (set *Set) Dispose() { 122 | set.lock.Lock() 123 | defer set.lock.Unlock() 124 | 125 | for k := range set.items { 126 | delete(set.items, k) 127 | } 128 | 129 | //this is so we don't hang onto any references 130 | for i := 0; i < len(set.flattened); i++ { 131 | set.flattened[i] = nil 132 | } 133 | 134 | set.flattened = set.flattened[:0] 135 | pool.Put(set) 136 | } 137 | 138 | // New is the constructor for sets. It will pull from a reuseable memory pool if it can. 139 | // Takes a list of items to initialize the set with. 140 | func New(items ...interface{}) *Set { 141 | set := pool.Get().(*Set) 142 | for _, item := range items { 143 | set.items[item] = struct{}{} 144 | } 145 | 146 | return set 147 | } 148 | 149 | func init() { 150 | pool.New = func() interface{} { 151 | return &Set{ 152 | items: make(map[interface{}]struct{}, 10), 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /bitarray/or.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package bitarray 18 | 19 | func orSparseWithSparseBitArray(sba *sparseBitArray, 20 | other *sparseBitArray) BitArray { 21 | 22 | if len(other.indices) == 0 { 23 | return sba.copy() 24 | } 25 | 26 | if len(sba.indices) == 0 { 27 | return other.copy() 28 | } 29 | 30 | max := maxInt64(int64(len(sba.indices)), int64(len(other.indices))) 31 | indices := make(uintSlice, 0, max) 32 | blocks := make(blocks, 0, max) 33 | 34 | selfIndex := 0 35 | otherIndex := 0 36 | for { 37 | // last comparison was a real or, we are both exhausted now 38 | if selfIndex == len(sba.indices) && otherIndex == len(other.indices) { 39 | break 40 | } else if selfIndex == len(sba.indices) { 41 | indices = append(indices, other.indices[otherIndex:]...) 42 | blocks = append(blocks, other.blocks[otherIndex:]...) 43 | break 44 | } else if otherIndex == len(other.indices) { 45 | indices = append(indices, sba.indices[selfIndex:]...) 46 | blocks = append(blocks, sba.blocks[selfIndex:]...) 47 | break 48 | } 49 | 50 | selfValue := sba.indices[selfIndex] 51 | otherValue := other.indices[otherIndex] 52 | 53 | switch diff := int(otherValue) - int(selfValue); { 54 | case diff > 0: 55 | indices = append(indices, selfValue) 56 | blocks = append(blocks, sba.blocks[selfIndex]) 57 | selfIndex++ 58 | case diff < 0: 59 | indices = append(indices, otherValue) 60 | blocks = append(blocks, other.blocks[otherIndex]) 61 | otherIndex++ 62 | default: 63 | indices = append(indices, otherValue) 64 | blocks = append(blocks, sba.blocks[selfIndex].or(other.blocks[otherIndex])) 65 | selfIndex++ 66 | otherIndex++ 67 | } 68 | } 69 | 70 | return &sparseBitArray{ 71 | indices: indices, 72 | blocks: blocks, 73 | } 74 | } 75 | 76 | func orSparseWithDenseBitArray(sba *sparseBitArray, other *bitArray) BitArray { 77 | if other.Capacity() == 0 || !other.anyset { 78 | return sba.copy() 79 | } 80 | 81 | if sba.Capacity() == 0 { 82 | return other.copy() 83 | } 84 | 85 | max := maxUint64(uint64(sba.Capacity()), uint64(other.Capacity())) 86 | 87 | ba := newBitArray(max * s) 88 | selfIndex := 0 89 | otherIndex := 0 90 | for { 91 | if selfIndex == len(sba.indices) && otherIndex == len(other.blocks) { 92 | break 93 | } else if selfIndex == len(sba.indices) { 94 | copy(ba.blocks[otherIndex:], other.blocks[otherIndex:]) 95 | break 96 | } else if otherIndex == len(other.blocks) { 97 | for i, value := range sba.indices[selfIndex:] { 98 | ba.blocks[value] = sba.blocks[i+selfIndex] 99 | } 100 | break 101 | } 102 | 103 | selfValue := sba.indices[selfIndex] 104 | if selfValue == uint64(otherIndex) { 105 | ba.blocks[otherIndex] = sba.blocks[selfIndex].or(other.blocks[otherIndex]) 106 | selfIndex++ 107 | otherIndex++ 108 | continue 109 | } 110 | 111 | ba.blocks[otherIndex] = other.blocks[otherIndex] 112 | otherIndex++ 113 | } 114 | 115 | ba.setHighest() 116 | ba.setLowest() 117 | 118 | return ba 119 | } 120 | 121 | func orDenseWithDenseBitArray(dba *bitArray, other *bitArray) BitArray { 122 | if dba.Capacity() == 0 || !dba.anyset { 123 | return other.copy() 124 | } 125 | 126 | if other.Capacity() == 0 || !other.anyset { 127 | return dba.copy() 128 | } 129 | 130 | max := maxUint64(uint64(len(dba.blocks)), uint64(len(other.blocks))) 131 | 132 | ba := newBitArray(max * s) 133 | 134 | for i := uint64(0); i < max; i++ { 135 | if i == uint64(len(dba.blocks)) { 136 | copy(ba.blocks[i:], other.blocks[i:]) 137 | break 138 | } 139 | 140 | if i == uint64(len(other.blocks)) { 141 | copy(ba.blocks[i:], dba.blocks[i:]) 142 | break 143 | } 144 | 145 | ba.blocks[i] = dba.blocks[i].or(other.blocks[i]) 146 | } 147 | 148 | ba.setLowest() 149 | ba.setHighest() 150 | 151 | return ba 152 | } 153 | -------------------------------------------------------------------------------- /set/dict_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package set 18 | 19 | import ( 20 | "reflect" 21 | "strconv" 22 | "testing" 23 | ) 24 | 25 | func TestAddDuplicateItem(t *testing.T) { 26 | set := New() 27 | set.Add(`test`) 28 | set.Add(`test`) 29 | 30 | if !reflect.DeepEqual([]interface{}{`test`}, set.Flatten()) { 31 | t.Errorf(`Incorrect result returned: %+v`, set.Flatten()) 32 | } 33 | } 34 | 35 | func TestAddItems(t *testing.T) { 36 | set := New() 37 | set.Add(`test`) 38 | set.Add(`test1`) 39 | 40 | firstSeen := false 41 | secondSeen := false 42 | // order is not guaranteed 43 | for _, item := range set.Flatten() { 44 | if item.(string) == `test` { 45 | firstSeen = true 46 | } else if item.(string) == `test1` { 47 | secondSeen = true 48 | } 49 | } 50 | 51 | if !firstSeen || !secondSeen { 52 | t.Errorf(`Not all items seen in set.`) 53 | } 54 | } 55 | 56 | func TestRemove(t *testing.T) { 57 | set := New() 58 | set.Add(`test`) 59 | set.Remove(`test`) 60 | 61 | if !reflect.DeepEqual([]interface{}{}, set.Flatten()) { 62 | t.Errorf(`Incorrect result returned: %+v`, set.Flatten()) 63 | } 64 | } 65 | 66 | func TestExists(t *testing.T) { 67 | set := New() 68 | set.Add(`test`) 69 | 70 | if !set.Exists(`test`) { 71 | t.Errorf(`Correct existence not determined`) 72 | } 73 | 74 | if set.Exists(`test1`) { 75 | t.Errorf(`Correct nonexistence not determined.`) 76 | } 77 | } 78 | 79 | func TestLen(t *testing.T) { 80 | set := New() 81 | set.Add(`test`) 82 | 83 | if set.Len() != 1 { 84 | t.Errorf(`Expected len: %d, received: %d`, 1, set.Len()) 85 | } 86 | 87 | set.Add(`test1`) 88 | if set.Len() != 2 { 89 | t.Errorf(`Expected len: %d, received: %d`, 2, set.Len()) 90 | } 91 | } 92 | 93 | func TestFlattenCaches(t *testing.T) { 94 | set := New() 95 | item := `test` 96 | set.Add(item) 97 | 98 | set.Flatten() 99 | 100 | if len(set.flattened) != 1 { 101 | t.Errorf(`Expected len: %d, received: %d`, 1, len(set.flattened)) 102 | } 103 | } 104 | 105 | func TestAddClearsCache(t *testing.T) { 106 | set := New() 107 | item := `test` 108 | set.Add(item) 109 | set.Flatten() 110 | 111 | set.Add(item) 112 | 113 | if len(set.flattened) != 0 { 114 | t.Errorf(`Expected len: %d, received: %d`, 0, len(set.flattened)) 115 | } 116 | 117 | item = `test2` 118 | set.Add(item) 119 | 120 | if set.flattened != nil { 121 | t.Errorf(`Cache not cleared.`) 122 | } 123 | } 124 | 125 | func TestDeleteClearsCache(t *testing.T) { 126 | set := New() 127 | item := `test` 128 | set.Add(item) 129 | set.Flatten() 130 | 131 | set.Remove(item) 132 | 133 | if set.flattened != nil { 134 | t.Errorf(`Cache not cleared.`) 135 | } 136 | } 137 | 138 | func TestAll(t *testing.T) { 139 | set := New() 140 | item := `test` 141 | set.Add(item) 142 | 143 | result := set.All(item) 144 | if !result { 145 | t.Errorf(`Expected true.`) 146 | } 147 | 148 | itemTwo := `test1` 149 | 150 | result = set.All(item, itemTwo) 151 | if result { 152 | t.Errorf(`Expected false.`) 153 | } 154 | } 155 | 156 | func TestClear(t *testing.T) { 157 | set := New() 158 | set.Add(`test`) 159 | 160 | set.Clear() 161 | 162 | if set.Len() != 0 { 163 | t.Errorf(`Expected len: %d, received: %d`, 0, set.Len()) 164 | } 165 | } 166 | 167 | func BenchmarkFlatten(b *testing.B) { 168 | set := New() 169 | for i := 0; i < 50; i++ { 170 | item := strconv.Itoa(i) 171 | set.Add(item) 172 | } 173 | 174 | b.ResetTimer() 175 | for i := 0; i < b.N; i++ { 176 | set.Flatten() 177 | } 178 | } 179 | 180 | func BenchmarkLen(b *testing.B) { 181 | set := New() 182 | for i := 0; i < 50; i++ { 183 | item := strconv.Itoa(i) 184 | set.Add(item) 185 | } 186 | 187 | b.ResetTimer() 188 | for i := 0; i < b.N; i++ { 189 | set.Len() 190 | } 191 | } 192 | 193 | func BenchmarkExists(b *testing.B) { 194 | set := New() 195 | set.Add(1) 196 | 197 | b.ResetTimer() 198 | for i := 0; i < b.N; i++ { 199 | set.Exists(1) 200 | } 201 | } 202 | 203 | func BenchmarkClear(b *testing.B) { 204 | set := New() 205 | for i := 0; i < b.N; i++ { 206 | set.Clear() 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /btree/_link/tree.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /* 18 | This is a b-link tree in progress from the following paper: 19 | http://www.csd.uoc.gr/~hy460/pdf/p650-lehman.pdf 20 | 21 | This is still a work in progress and the CRUD methods on the tree 22 | need to be parallelized. Until this is complete, there is no 23 | constructor method for this package. 24 | 25 | Time complexities: 26 | Space: O(n) 27 | Search: O(log n) 28 | Insert: O(log n) 29 | Delete: O(log n) 30 | 31 | Current benchmarks with 16 ary: 32 | BenchmarkSimpleAdd-8 1000000 1455 ns/op 33 | BenchmarkGet-8 2000000 704 ns/op 34 | 35 | B-link was chosen after examining this paper: 36 | http://www.vldb.org/journal/VLDBJ2/P361.pdf 37 | */ 38 | 39 | package link 40 | 41 | import ( 42 | "log" 43 | "sync" 44 | "sync/atomic" 45 | ) 46 | 47 | // numberOfItemsBeforeMultithread defines the number of items that have 48 | // to be called with a method before we multithread. 49 | const numberOfItemsBeforeMultithread = 10 50 | 51 | type blink struct { 52 | root *node 53 | lock sync.RWMutex 54 | number, ary, numRoutines uint64 55 | } 56 | 57 | func (blink *blink) insert(key Key, stack *nodes) Key { 58 | var parent *node 59 | blink.lock.Lock() 60 | if blink.root == nil { 61 | blink.root = newNode( 62 | true, make(Keys, 0, blink.ary), make(nodes, 0, blink.ary+1), 63 | ) 64 | blink.root.keys = make(Keys, 0, blink.ary) 65 | blink.root.isLeaf = true 66 | } 67 | parent = blink.root 68 | blink.lock.Unlock() 69 | 70 | result := insert(blink, parent, stack, key) 71 | if result == nil { 72 | atomic.AddUint64(&blink.number, 1) 73 | return nil 74 | } 75 | 76 | return result 77 | } 78 | 79 | func (blink *blink) multithreadedInsert(keys Keys) Keys { 80 | chunks := chunkKeys(keys, int64(blink.numRoutines)) 81 | overwritten := make(Keys, len(keys)) 82 | var offset uint64 83 | var wg sync.WaitGroup 84 | wg.Add(len(chunks)) 85 | 86 | for _, chunk := range chunks { 87 | go func(chunk Keys, offset uint64) { 88 | defer wg.Done() 89 | stack := make(nodes, 0, blink.ary) 90 | 91 | for i := 0; i < len(chunk); i++ { 92 | result := blink.insert(chunk[i], &stack) 93 | stack.reset() 94 | overwritten[offset+uint64(i)] = result 95 | } 96 | }(chunk, offset) 97 | offset += uint64(len(chunk)) 98 | } 99 | 100 | wg.Wait() 101 | 102 | return overwritten 103 | } 104 | 105 | // Insert will insert the provided keys into the b-tree and return 106 | // a list of keys overwritten, if any. Each insert is an O(log n) 107 | // operation. 108 | func (blink *blink) Insert(keys ...Key) Keys { 109 | if len(keys) > numberOfItemsBeforeMultithread { 110 | return blink.multithreadedInsert(keys) 111 | } 112 | overwritten := make(Keys, 0, len(keys)) 113 | stack := make(nodes, 0, blink.ary) 114 | for _, k := range keys { 115 | overwritten = append(overwritten, blink.insert(k, &stack)) 116 | stack.reset() 117 | } 118 | 119 | return overwritten 120 | } 121 | 122 | // Len returns the number of items in this b-link tree. 123 | func (blink *blink) Len() uint64 { 124 | return atomic.LoadUint64(&blink.number) 125 | } 126 | 127 | func (blink *blink) get(key Key) Key { 128 | var parent *node 129 | blink.lock.RLock() 130 | parent = blink.root 131 | blink.lock.RUnlock() 132 | k := search(parent, key) 133 | if k == nil { 134 | return nil 135 | } 136 | 137 | if k.Compare(key) == 0 { 138 | return k 139 | } 140 | 141 | return nil 142 | } 143 | 144 | // Get will retrieve the keys if they exist in this tree. If not, 145 | // a nil is returned in the proper place in the list of keys. Each 146 | // lookup is O(log n) time complexity. 147 | func (blink *blink) Get(keys ...Key) Keys { 148 | found := make(Keys, 0, len(keys)) 149 | for _, k := range keys { 150 | found = append(found, blink.get(k)) 151 | } 152 | 153 | return found 154 | } 155 | 156 | func (blink *blink) print(output *log.Logger) { 157 | output.Println(`PRINTING B-LINK`) 158 | if blink.root == nil { 159 | return 160 | } 161 | 162 | blink.root.print(output) 163 | } 164 | 165 | func newTree(ary, numRoutines uint64) *blink { 166 | return &blink{ary: ary, numRoutines: numRoutines} 167 | } 168 | -------------------------------------------------------------------------------- /trie/yfast/entries.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package yfast 18 | 19 | import "sort" 20 | 21 | type entriesWrapper struct { 22 | key uint64 23 | entries Entries 24 | } 25 | 26 | // Key will return the key of the highest entry in this list. 27 | // This is required by the x-fast trie Entry interface. This 28 | // returns 0 if this list is empty. 29 | func (ew *entriesWrapper) Key() uint64 { 30 | return ew.key 31 | } 32 | 33 | // Entries is a typed list of Entry. The size of entries 34 | // will be limited to 1/2log M to 2log M where M is the size 35 | // of the universe. 36 | type Entries []Entry 37 | 38 | // search will perform a sort package search on this list 39 | // of entries and return an index indicating position. 40 | // If the returned index is >= len(entries) then a suitable 41 | // position could not be found. The index does not guarantee 42 | // equality, just indicates where the key would be inserted. 43 | func (entries Entries) search(key uint64) int { 44 | return sort.Search(len(entries), func(i int) bool { 45 | return entries[i].Key() >= key 46 | }) 47 | } 48 | 49 | // insert will insert the provided entry into this list of 50 | // entries. Returned is an entry if an entry already exists 51 | // for the provided key. If nothing is overwritten, Entry 52 | // will be nil. 53 | func (entries *Entries) insert(entry Entry) Entry { 54 | i := entries.search(entry.Key()) 55 | 56 | if i == len(*entries) { 57 | *entries = append(*entries, entry) 58 | return nil 59 | } 60 | 61 | if (*entries)[i].Key() == entry.Key() { 62 | oldEntry := (*entries)[i] 63 | (*entries)[i] = entry 64 | return oldEntry 65 | } 66 | 67 | (*entries) = append(*entries, nil) 68 | copy((*entries)[i+1:], (*entries)[i:]) 69 | (*entries)[i] = entry 70 | return nil 71 | } 72 | 73 | // delete will remove the provided key from this list of entries. 74 | // Returned is a deleted Entry. This will be nil if the key 75 | // cannot be found. 76 | func (entries *Entries) delete(key uint64) Entry { 77 | i := entries.search(key) 78 | if i == len(*entries) { // key not found 79 | return nil 80 | } 81 | 82 | if (*entries)[i].Key() != key { 83 | return nil 84 | } 85 | 86 | oldEntry := (*entries)[i] 87 | copy((*entries)[i:], (*entries)[i+1:]) 88 | (*entries)[len(*entries)-1] = nil // GC 89 | *entries = (*entries)[:len(*entries)-1] 90 | return oldEntry 91 | } 92 | 93 | // max returns the value of the highest key in this list 94 | // of entries. The bool indicates if it's a valid key, that 95 | // is if there is more than zero entries in this list. 96 | func (entries Entries) max() (uint64, bool) { 97 | if len(entries) == 0 { 98 | return 0, false 99 | } 100 | 101 | return entries[len(entries)-1].Key(), true 102 | } 103 | 104 | // get will perform a lookup over this list of entries 105 | // and return an Entry if it exists. Returns nil if the 106 | // entry does not exist. 107 | func (entries Entries) get(key uint64) Entry { 108 | i := entries.search(key) 109 | if i == len(entries) { 110 | return nil 111 | } 112 | 113 | if entries[i].Key() == key { 114 | return entries[i] 115 | } 116 | 117 | return nil 118 | } 119 | 120 | // successor will return the first entry that has a key 121 | // greater than or equal to provided key. Also returned 122 | // is the index of the find. Returns nil, -1 if a successor does 123 | // not exist. 124 | func (entries Entries) successor(key uint64) (Entry, int) { 125 | i := entries.search(key) 126 | if i == len(entries) { 127 | return nil, -1 128 | } 129 | 130 | return entries[i], i 131 | } 132 | 133 | // predecessor will return the first entry that has a key 134 | // less than or equal to the provided key. Also returned 135 | // is the index of the find. Returns nil, -1 if a predecessor 136 | // does not exist. 137 | func (entries Entries) predecessor(key uint64) (Entry, int) { 138 | if len(entries) == 0 { 139 | return nil, -1 140 | } 141 | 142 | i := entries.search(key) 143 | if i == len(entries) { 144 | return entries[i-1], i - 1 145 | } 146 | 147 | if entries[i].Key() == key { 148 | return entries[i], i 149 | } 150 | 151 | i-- 152 | 153 | if i < 0 { 154 | return nil, -1 155 | } 156 | 157 | return entries[i], i 158 | } 159 | -------------------------------------------------------------------------------- /btree/_link/node_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package link 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | func newTestNode(isLeaf bool, ary int) *node { 26 | return &node{ 27 | isLeaf: isLeaf, 28 | keys: make(Keys, 0, ary), 29 | nodes: make(nodes, 0, ary+1), 30 | } 31 | } 32 | 33 | func checkTree(t testing.TB, tree *blink) bool { 34 | if tree.root == nil { 35 | return true 36 | } 37 | 38 | return checkNode(t, tree.root) 39 | } 40 | 41 | func checkNode(t testing.TB, n *node) bool { 42 | if len(n.keys) == 0 { 43 | assert.Len(t, n.nodes, 0) 44 | return false 45 | } 46 | 47 | if n.isLeaf { 48 | assert.Len(t, n.nodes, 0) 49 | return false 50 | } 51 | 52 | if !assert.Len(t, n.nodes, len(n.keys)+1) { 53 | return false 54 | } 55 | 56 | for i := 0; i < len(n.keys); i++ { 57 | if !assert.True(t, n.keys[i].Compare(n.nodes[i].key()) >= 0) { 58 | t.Logf(`N: %+v %p, n.keys[i]: %+v, n.nodes[i]: %+v`, n, n, n.keys[i], n.nodes[i]) 59 | return false 60 | } 61 | } 62 | 63 | if !assert.True(t, n.nodes[len(n.nodes)-1].key().Compare(n.keys.last()) > 0) { 64 | t.Logf(`m: %+v, %p, n.nodes[len(n.nodes)-1].key(): %+v, n.keys.last(): %+v`, n, n, n.nodes[len(n.nodes)-1].key(), n.keys.last()) 65 | return false 66 | } 67 | for _, child := range n.nodes { 68 | if !assert.NotNil(t, child) { 69 | return false 70 | } 71 | if !checkNode(t, child) { 72 | return false 73 | } 74 | } 75 | 76 | return true 77 | } 78 | 79 | func TestSplitInternalNodeOddAry(t *testing.T) { 80 | parent := newTestNode(false, 3) 81 | n1 := newTestNode(true, 3) 82 | n1.keys.insert(mockKey(1)) 83 | n2 := newTestNode(true, 3) 84 | n2.keys.insert(mockKey(5)) 85 | n3 := newTestNode(true, 3) 86 | n3.keys.insert(mockKey(10)) 87 | n4 := newTestNode(true, 3) 88 | n4.keys.insert(mockKey(15)) 89 | 90 | parent.nodes = nodes{n1, n2, n3, n4} 91 | parent.keys = Keys{mockKey(5), mockKey(10), mockKey(15)} 92 | 93 | key, l, r := parent.split() 94 | assert.Equal(t, mockKey(10), key) 95 | assert.Equal(t, Keys{mockKey(5)}, l.keys) 96 | assert.Equal(t, Keys{mockKey(15)}, r.keys) 97 | 98 | assert.Equal(t, nodes{n1, n2}, l.nodes) 99 | assert.Equal(t, nodes{n3, n4}, r.nodes) 100 | assert.Equal(t, l.right, r) 101 | assert.False(t, l.isLeaf) 102 | assert.False(t, r.isLeaf) 103 | } 104 | 105 | func TestSplitInternalNodeEvenAry(t *testing.T) { 106 | parent := newTestNode(false, 4) 107 | n1 := newTestNode(true, 4) 108 | n1.keys.insert(mockKey(1)) 109 | n2 := newTestNode(true, 4) 110 | n2.keys.insert(mockKey(5)) 111 | n3 := newTestNode(true, 4) 112 | n3.keys.insert(mockKey(10)) 113 | n4 := newTestNode(true, 4) 114 | n4.keys.insert(mockKey(15)) 115 | n5 := newTestNode(true, 4) 116 | n5.keys.insert(mockKey(20)) 117 | 118 | parent.nodes = nodes{n1, n2, n3, n4, n5} 119 | parent.keys = Keys{mockKey(5), mockKey(10), mockKey(15), mockKey(20)} 120 | 121 | key, l, r := parent.split() 122 | assert.Equal(t, mockKey(15), key) 123 | assert.Equal(t, Keys{mockKey(5), mockKey(10)}, l.keys) 124 | assert.Equal(t, Keys{mockKey(20)}, r.keys) 125 | 126 | assert.Equal(t, nodes{n1, n2, n3}, l.nodes) 127 | assert.Equal(t, nodes{n4, n5}, r.nodes) 128 | assert.Equal(t, l.right, r) 129 | assert.False(t, l.isLeaf) 130 | assert.False(t, r.isLeaf) 131 | } 132 | 133 | func TestSplitLeafNodeOddAry(t *testing.T) { 134 | parent := newTestNode(true, 3) 135 | k1 := mockKey(5) 136 | k2 := mockKey(15) 137 | k3 := mockKey(20) 138 | 139 | parent.keys = Keys{k1, k2, k3} 140 | key, l, r := parent.split() 141 | assert.Equal(t, k2, key) 142 | assert.Equal(t, Keys{k1, k2}, l.keys) 143 | assert.Equal(t, Keys{k3}, r.keys) 144 | assert.True(t, l.isLeaf) 145 | assert.True(t, r.isLeaf) 146 | assert.Equal(t, r, l.right) 147 | } 148 | 149 | func TestSplitLeafNodeEvenAry(t *testing.T) { 150 | parent := newTestNode(true, 4) 151 | k1 := mockKey(5) 152 | k2 := mockKey(15) 153 | k3 := mockKey(20) 154 | k4 := mockKey(25) 155 | 156 | parent.keys = Keys{k1, k2, k3, k4} 157 | key, l, r := parent.split() 158 | assert.Equal(t, k3, key) 159 | assert.Equal(t, Keys{k1, k2, k3}, l.keys) 160 | assert.Equal(t, Keys{k4}, r.keys) 161 | assert.True(t, l.isLeaf) 162 | assert.True(t, r.isLeaf) 163 | assert.Equal(t, r, l.right) 164 | } 165 | -------------------------------------------------------------------------------- /hashmap/fastinteger/hashmap.go: -------------------------------------------------------------------------------- 1 | // Package fastinteger is designed to provide a very primitive 2 | // implementation of a hash map for unsigned integer keys and 3 | // values. It is designed to have existence checks and insertions 4 | // that are faster than Go's native implementation. Like Go's 5 | // native implementation, FastIntegerHashMap will dynamically 6 | // grow in size. 7 | // 8 | // Current benchmarks on identical machine against native Go implementation: 9 | // BenchmarkInsert-8 10000 131258 ns/op 10 | // BenchmarkGoMapInsert-8 10000 208787 ns/op 11 | // BenchmarkExists-8 100000 15820 ns/op 12 | // BenchmarkGoMapExists-8 100000 16394 ns/op 13 | // BenchmarkDelete-8 100000 17909 ns/op 14 | // BenchmarkGoDelete-8 30000 49376 ns/op 15 | // BenchmarkInsertWithExpand-8 20000 90301 ns/op 16 | // BenchmarkGoInsertWithExpand-8 10000 142088 ns/op 17 | // 18 | // 19 | // This performance could be further enhanced by using a 20 | // better probing technique. 21 | package fastinteger 22 | 23 | const ratio = .75 // ratio sets the capacity the hashmap has to be at before it expands 24 | 25 | // roundUp takes a uint64 greater than 0 and rounds it up to the next 26 | // power of 2. 27 | func roundUp(v uint64) uint64 { 28 | v-- 29 | v |= v >> 1 30 | v |= v >> 2 31 | v |= v >> 4 32 | v |= v >> 8 33 | v |= v >> 16 34 | v |= v >> 32 35 | v++ 36 | return v 37 | } 38 | 39 | type packet struct { 40 | key, value uint64 41 | } 42 | 43 | type packets []*packet 44 | 45 | func (packets packets) find(key uint64) uint64 { 46 | h := hash(key) 47 | i := h & (uint64(len(packets)) - 1) 48 | for packets[i] != nil && packets[i].key != key { 49 | i = (i + 1) & (uint64(len(packets)) - 1) 50 | } 51 | 52 | return i 53 | } 54 | 55 | func (packets packets) set(packet *packet) { 56 | i := packets.find(packet.key) 57 | if packets[i] == nil { 58 | packets[i] = packet 59 | return 60 | } 61 | 62 | packets[i].value = packet.value 63 | } 64 | 65 | func (packets packets) get(key uint64) (uint64, bool) { 66 | i := packets.find(key) 67 | if packets[i] == nil { 68 | return 0, false 69 | } 70 | 71 | return packets[i].value, true 72 | } 73 | 74 | func (packets packets) delete(key uint64) bool { 75 | i := packets.find(key) 76 | if packets[i] == nil { 77 | return false 78 | } 79 | packets[i] = nil 80 | return true 81 | } 82 | 83 | func (packets packets) exists(key uint64) bool { 84 | i := packets.find(key) 85 | return packets[i] != nil // technically, they can store nil 86 | } 87 | 88 | // FastIntegerHashMap is a simple hashmap to be used with 89 | // integer only keys. It supports few operations, and is designed 90 | // primarily for cases where the consumer needs a very simple 91 | // datastructure to set and check for existence of integer 92 | // keys over a sparse range. 93 | type FastIntegerHashMap struct { 94 | count uint64 95 | packets packets 96 | } 97 | 98 | // rebuild is an expensive operation which requires us to iterate 99 | // over the current bucket and rehash the keys for insertion into 100 | // the new bucket. The new bucket is twice as large as the old 101 | // bucket by default. 102 | func (fi *FastIntegerHashMap) rebuild() { 103 | packets := make(packets, roundUp(uint64(len(fi.packets))+1)) 104 | for _, packet := range fi.packets { 105 | if packet == nil { 106 | continue 107 | } 108 | 109 | packets.set(packet) 110 | } 111 | fi.packets = packets 112 | } 113 | 114 | // Get returns an item from the map if it exists. Otherwise, 115 | // returns false for the second argument. 116 | func (fi *FastIntegerHashMap) Get(key uint64) (uint64, bool) { 117 | return fi.packets.get(key) 118 | } 119 | 120 | // Set will set the provided key with the provided value. 121 | func (fi *FastIntegerHashMap) Set(key, value uint64) { 122 | if float64(fi.count+1)/float64(len(fi.packets)) > ratio { 123 | fi.rebuild() 124 | } 125 | 126 | fi.packets.set(&packet{key: key, value: value}) 127 | fi.count++ 128 | } 129 | 130 | // Exists will return a bool indicating if the provided key 131 | // exists in the map. 132 | func (fi *FastIntegerHashMap) Exists(key uint64) bool { 133 | return fi.packets.exists(key) 134 | } 135 | 136 | // Delete will remove the provided key from the hashmap. If 137 | // the key cannot be found, this is a no-op. 138 | func (fi *FastIntegerHashMap) Delete(key uint64) { 139 | if fi.packets.delete(key) { 140 | fi.count-- 141 | } 142 | } 143 | 144 | // Len returns the number of items in the hashmap. 145 | func (fi *FastIntegerHashMap) Len() uint64 { 146 | return fi.count 147 | } 148 | 149 | // Cap returns the capacity of the hashmap. 150 | func (fi *FastIntegerHashMap) Cap() uint64 { 151 | return uint64(len(fi.packets)) 152 | } 153 | 154 | // New returns a new FastIntegerHashMap with a bucket size specified 155 | // by hint. 156 | func New(hint uint64) *FastIntegerHashMap { 157 | if hint == 0 { 158 | hint = 16 159 | } 160 | 161 | hint = roundUp(hint) 162 | return &FastIntegerHashMap{ 163 | count: 0, 164 | packets: make(packets, hint), 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /queue/ring.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package queue 17 | 18 | import ( 19 | "runtime" 20 | "sync/atomic" 21 | ) 22 | 23 | // roundUp takes a uint64 greater than 0 and rounds it up to the next 24 | // power of 2. 25 | func roundUp(v uint64) uint64 { 26 | v-- 27 | v |= v >> 1 28 | v |= v >> 2 29 | v |= v >> 4 30 | v |= v >> 8 31 | v |= v >> 16 32 | v |= v >> 32 33 | v++ 34 | return v 35 | } 36 | 37 | type node struct { 38 | position uint64 39 | data interface{} 40 | } 41 | 42 | type nodes []*node 43 | 44 | // RingBuffer is a MPMC buffer that achieves threadsafety with CAS operations 45 | // only. A put on full or get on empty call will block until an item 46 | // is put or retrieved. Calling Dispose on the RingBuffer will unblock 47 | // any blocked threads with an error. This buffer is similar to the buffer 48 | // described here: http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue 49 | // with some minor additions. 50 | type RingBuffer struct { 51 | nodes nodes 52 | queue, dequeue, mask, disposed uint64 53 | } 54 | 55 | func (rb *RingBuffer) init(size uint64) { 56 | size = roundUp(size) 57 | rb.nodes = make(nodes, size) 58 | for i := uint64(0); i < size; i++ { 59 | rb.nodes[i] = &node{position: i} 60 | } 61 | rb.mask = size - 1 // so we don't have to do this with every put/get operation 62 | } 63 | 64 | // Put adds the provided item to the queue. If the queue is full, this 65 | // call will block until an item is added to the queue or Dispose is called 66 | // on the queue. An error will be returned if the queue is disposed. 67 | func (rb *RingBuffer) Put(item interface{}) error { 68 | var n *node 69 | pos := atomic.LoadUint64(&rb.queue) 70 | L: 71 | for { 72 | if atomic.LoadUint64(&rb.disposed) == 1 { 73 | return disposedError 74 | } 75 | 76 | n = rb.nodes[pos&rb.mask] 77 | seq := atomic.LoadUint64(&n.position) 78 | switch dif := seq - pos; { 79 | case dif == 0: 80 | if atomic.CompareAndSwapUint64(&rb.queue, pos, pos+1) { 81 | break L 82 | } 83 | case dif < 0: 84 | panic(`Ring buffer in a compromised state during a put operation.`) 85 | default: 86 | pos = atomic.LoadUint64(&rb.queue) 87 | } 88 | runtime.Gosched() // free up the cpu before the next iteration 89 | } 90 | 91 | n.data = item 92 | atomic.StoreUint64(&n.position, pos+1) 93 | return nil 94 | } 95 | 96 | // Get will return the next item in the queue. This call will block 97 | // if the queue is empty. This call will unblock when an item is added 98 | // to the queue or Dispose is called on the queue. An error will be returned 99 | // if the queue is disposed. 100 | func (rb *RingBuffer) Get() (interface{}, error) { 101 | var n *node 102 | pos := atomic.LoadUint64(&rb.dequeue) 103 | L: 104 | for { 105 | if atomic.LoadUint64(&rb.disposed) == 1 { 106 | return nil, disposedError 107 | } 108 | 109 | n = rb.nodes[pos&rb.mask] 110 | seq := atomic.LoadUint64(&n.position) 111 | switch dif := seq - (pos + 1); { 112 | case dif == 0: 113 | if atomic.CompareAndSwapUint64(&rb.dequeue, pos, pos+1) { 114 | break L 115 | } 116 | case dif < 0: 117 | panic(`Ring buffer in compromised state during a get operation.`) 118 | default: 119 | pos = atomic.LoadUint64(&rb.dequeue) 120 | } 121 | runtime.Gosched() // free up cpu before next iteration 122 | } 123 | data := n.data 124 | n.data = nil 125 | atomic.StoreUint64(&n.position, pos+rb.mask+1) 126 | return data, nil 127 | } 128 | 129 | // Len returns the number of items in the queue. 130 | func (rb *RingBuffer) Len() uint64 { 131 | return atomic.LoadUint64(&rb.queue) - atomic.LoadUint64(&rb.dequeue) 132 | } 133 | 134 | // Cap returns the capacity of this ring buffer. 135 | func (rb *RingBuffer) Cap() uint64 { 136 | return uint64(len(rb.nodes)) 137 | } 138 | 139 | // Dispose will dispose of this queue and free any blocked threads 140 | // in the Put and/or Get methods. Calling those methods on a disposed 141 | // queue will return an error. 142 | func (rb *RingBuffer) Dispose() { 143 | atomic.CompareAndSwapUint64(&rb.disposed, 0, 1) 144 | } 145 | 146 | // IsDisposed will return a bool indicating if this queue has been 147 | // disposed. 148 | func (rb *RingBuffer) IsDisposed() bool { 149 | return atomic.LoadUint64(&rb.disposed) == 1 150 | } 151 | 152 | // NewRingBuffer will allocate, initialize, and return a ring buffer 153 | // with the specified size. 154 | func NewRingBuffer(size uint64) *RingBuffer { 155 | rb := &RingBuffer{} 156 | rb.init(size) 157 | return rb 158 | } 159 | -------------------------------------------------------------------------------- /bitarray/and_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package bitarray 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | // checkBit is a helper method for these unit tests 26 | func checkBit(t *testing.T, ba BitArray, position uint64, expected bool) { 27 | ok, err := ba.GetBit(position) 28 | if assert.NoError(t, err) { 29 | if expected { 30 | assert.True(t, ok, "Bitarray at position %d should be set", position) 31 | } else { 32 | assert.False(t, ok, "Bitarray at position %d should be unset", position) 33 | } 34 | } 35 | } 36 | 37 | func TestAndSparseWithSparseBitArray(t *testing.T) { 38 | sba := newSparseBitArray() 39 | other := newSparseBitArray() 40 | 41 | // bits for which only one of the arrays is set 42 | sba.SetBit(3) 43 | sba.SetBit(280) 44 | other.SetBit(9) 45 | other.SetBit(100) 46 | 47 | // bits for which both arrays are set 48 | sba.SetBit(1) 49 | other.SetBit(1) 50 | sba.SetBit(2680) 51 | other.SetBit(2680) 52 | sba.SetBit(30) 53 | other.SetBit(30) 54 | 55 | ba := andSparseWithSparseBitArray(sba, other) 56 | 57 | checkBit(t, ba, 1, true) 58 | checkBit(t, ba, 30, true) 59 | checkBit(t, ba, 2680, true) 60 | 61 | checkBit(t, ba, 3, false) 62 | checkBit(t, ba, 9, false) 63 | checkBit(t, ba, 100, false) 64 | checkBit(t, ba, 2, false) 65 | checkBit(t, ba, 280, false) 66 | } 67 | 68 | func TestAndSparseWithDenseBitArray(t *testing.T) { 69 | sba := newSparseBitArray() 70 | other := newBitArray(300) 71 | 72 | other.SetBit(1) 73 | sba.SetBit(1) 74 | other.SetBit(150) 75 | sba.SetBit(150) 76 | sba.SetBit(155) 77 | other.SetBit(156) 78 | sba.SetBit(300) 79 | other.SetBit(300) 80 | 81 | ba := andSparseWithDenseBitArray(sba, other) 82 | 83 | checkBit(t, ba, 1, true) 84 | checkBit(t, ba, 150, true) 85 | checkBit(t, ba, 155, false) 86 | checkBit(t, ba, 156, false) 87 | checkBit(t, ba, 300, true) 88 | } 89 | 90 | // Maks sure that the sparse array is trimmed correctly if compared against a 91 | // smaller dense bit array. 92 | func TestAndSparseWithSmallerDenseBitArray(t *testing.T) { 93 | sba := newSparseBitArray() 94 | other := newBitArray(512) 95 | 96 | other.SetBit(1) 97 | sba.SetBit(1) 98 | other.SetBit(150) 99 | sba.SetBit(150) 100 | sba.SetBit(155) 101 | sba.SetBit(500) 102 | 103 | other.SetBit(128) 104 | sba.SetBit(1500) 105 | sba.SetBit(1200) 106 | 107 | ba := andSparseWithDenseBitArray(sba, other) 108 | 109 | checkBit(t, ba, 1, true) 110 | checkBit(t, ba, 150, true) 111 | checkBit(t, ba, 155, false) 112 | checkBit(t, ba, 128, false) 113 | checkBit(t, ba, 500, false) 114 | checkBit(t, ba, 1200, false) 115 | checkBit(t, ba, 1500, false) 116 | } 117 | 118 | func TestAndDenseWithDenseBitArray(t *testing.T) { 119 | dba := newBitArray(1000) 120 | other := newBitArray(2000) 121 | 122 | dba.SetBit(1) 123 | other.SetBit(18) 124 | dba.SetBit(222) 125 | other.SetBit(222) 126 | other.SetBit(1501) 127 | 128 | ba := andDenseWithDenseBitArray(dba, other) 129 | 130 | checkBit(t, ba, 0, false) 131 | checkBit(t, ba, 1, false) 132 | checkBit(t, ba, 3, false) 133 | checkBit(t, ba, 18, false) 134 | checkBit(t, ba, 222, true) 135 | 136 | // check that the ba is the minimum of the size of `dba` and `other` 137 | // (dense bitarrays return an error on an out-of-bounds access) 138 | _, err := ba.GetBit(1500) 139 | assert.Equal(t, OutOfRangeError(1500), err) 140 | _, err = ba.GetBit(1501) 141 | assert.Equal(t, OutOfRangeError(1501), err) 142 | } 143 | 144 | func TestAndSparseWithEmptySparse(t *testing.T) { 145 | sba := newSparseBitArray() 146 | other := newSparseBitArray() 147 | 148 | sba.SetBit(5) 149 | 150 | ba := andSparseWithSparseBitArray(sba, other) 151 | checkBit(t, ba, 0, false) 152 | checkBit(t, ba, 5, false) 153 | checkBit(t, ba, 100, false) 154 | } 155 | 156 | func TestAndSparseWithEmptyDense(t *testing.T) { 157 | sba := newSparseBitArray() 158 | other := newBitArray(1000) 159 | 160 | sba.SetBit(5) 161 | ba := andSparseWithDenseBitArray(sba, other) 162 | checkBit(t, ba, 5, false) 163 | 164 | sba.Reset() 165 | other.SetBit(5) 166 | 167 | ba = andSparseWithDenseBitArray(sba, other) 168 | checkBit(t, ba, 5, false) 169 | } 170 | 171 | func TestAndDenseWithEmptyDense(t *testing.T) { 172 | dba := newBitArray(1000) 173 | other := newBitArray(1000) 174 | 175 | dba.SetBit(5) 176 | ba := andDenseWithDenseBitArray(dba, other) 177 | checkBit(t, ba, 5, false) 178 | 179 | dba.Reset() 180 | other.SetBit(5) 181 | ba = andDenseWithDenseBitArray(dba, other) 182 | checkBit(t, ba, 5, false) 183 | } 184 | -------------------------------------------------------------------------------- /queue/priority_queue_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package queue 18 | 19 | import ( 20 | "sync" 21 | "testing" 22 | 23 | "github.com/stretchr/testify/assert" 24 | ) 25 | 26 | func TestPriorityPut(t *testing.T) { 27 | q := NewPriorityQueue(1) 28 | 29 | q.Put(mockItem(2)) 30 | 31 | assert.Len(t, q.items, 1) 32 | assert.Equal(t, mockItem(2), q.items[0]) 33 | 34 | q.Put(mockItem(1)) 35 | 36 | if !assert.Len(t, q.items, 2) { 37 | return 38 | } 39 | assert.Equal(t, mockItem(1), q.items[0]) 40 | assert.Equal(t, mockItem(2), q.items[1]) 41 | } 42 | 43 | func TestPriorityGet(t *testing.T) { 44 | q := NewPriorityQueue(1) 45 | 46 | q.Put(mockItem(2)) 47 | result, err := q.Get(2) 48 | if !assert.Nil(t, err) { 49 | return 50 | } 51 | 52 | if !assert.Len(t, result, 1) { 53 | return 54 | } 55 | 56 | assert.Equal(t, mockItem(2), result[0]) 57 | assert.Len(t, q.items, 0) 58 | 59 | q.Put(mockItem(2)) 60 | q.Put(mockItem(1)) 61 | 62 | result, err = q.Get(1) 63 | if !assert.Nil(t, err) { 64 | return 65 | } 66 | 67 | if !assert.Len(t, result, 1) { 68 | return 69 | } 70 | 71 | assert.Equal(t, mockItem(1), result[0]) 72 | assert.Len(t, q.items, 1) 73 | 74 | result, err = q.Get(2) 75 | if !assert.Nil(t, err) { 76 | return 77 | } 78 | 79 | if !assert.Len(t, result, 1) { 80 | return 81 | } 82 | 83 | assert.Equal(t, mockItem(2), result[0]) 84 | } 85 | 86 | func TestAddEmptyPriorityPut(t *testing.T) { 87 | q := NewPriorityQueue(1) 88 | 89 | q.Put() 90 | 91 | assert.Len(t, q.items, 0) 92 | } 93 | 94 | func TestPriorityGetNonPositiveNumber(t *testing.T) { 95 | q := NewPriorityQueue(1) 96 | 97 | q.Put(mockItem(1)) 98 | 99 | result, err := q.Get(0) 100 | if !assert.Nil(t, err) { 101 | return 102 | } 103 | 104 | assert.Len(t, result, 0) 105 | 106 | result, err = q.Get(-1) 107 | if !assert.Nil(t, err) { 108 | return 109 | } 110 | 111 | assert.Len(t, result, 0) 112 | } 113 | 114 | func TestPriorityEmpty(t *testing.T) { 115 | q := NewPriorityQueue(1) 116 | assert.True(t, q.Empty()) 117 | 118 | q.Put(mockItem(1)) 119 | 120 | assert.False(t, q.Empty()) 121 | } 122 | 123 | func TestPriorityGetEmpty(t *testing.T) { 124 | q := NewPriorityQueue(1) 125 | 126 | go func() { 127 | q.Put(mockItem(1)) 128 | }() 129 | 130 | result, err := q.Get(1) 131 | if !assert.Nil(t, err) { 132 | return 133 | } 134 | 135 | if !assert.Len(t, result, 1) { 136 | return 137 | } 138 | assert.Equal(t, mockItem(1), result[0]) 139 | } 140 | 141 | func TestMultiplePriorityGetEmpty(t *testing.T) { 142 | q := NewPriorityQueue(1) 143 | var wg sync.WaitGroup 144 | wg.Add(2) 145 | results := make([][]Item, 2) 146 | 147 | go func() { 148 | wg.Done() 149 | local, _ := q.Get(1) 150 | results[0] = local 151 | wg.Done() 152 | }() 153 | 154 | go func() { 155 | wg.Done() 156 | local, _ := q.Get(1) 157 | results[1] = local 158 | wg.Done() 159 | }() 160 | 161 | wg.Wait() 162 | wg.Add(2) 163 | 164 | q.Put(mockItem(1), mockItem(3), mockItem(2)) 165 | wg.Wait() 166 | 167 | if !assert.Len(t, results[0], 1) || !assert.Len(t, results[1], 1) { 168 | return 169 | } 170 | 171 | assert.True( 172 | t, (results[0][0] == mockItem(1) && results[1][0] == mockItem(2)) || 173 | results[0][0] == mockItem(2) && results[1][0] == mockItem(1), 174 | ) 175 | } 176 | 177 | func TestEmptyPriorityGetWithDispose(t *testing.T) { 178 | q := NewPriorityQueue(1) 179 | var wg sync.WaitGroup 180 | wg.Add(1) 181 | 182 | var err error 183 | go func() { 184 | wg.Done() 185 | _, err = q.Get(1) 186 | wg.Done() 187 | }() 188 | 189 | wg.Wait() 190 | wg.Add(1) 191 | 192 | q.Dispose() 193 | 194 | wg.Wait() 195 | 196 | assert.IsType(t, disposedError, err) 197 | } 198 | 199 | func TestPriorityGetPutDisposed(t *testing.T) { 200 | q := NewPriorityQueue(1) 201 | q.Dispose() 202 | 203 | _, err := q.Get(1) 204 | assert.IsType(t, disposedError, err) 205 | 206 | err = q.Put(mockItem(1)) 207 | assert.IsType(t, disposedError, err) 208 | } 209 | 210 | func BenchmarkPriorityQueue(b *testing.B) { 211 | q := NewPriorityQueue(b.N) 212 | var wg sync.WaitGroup 213 | wg.Add(1) 214 | i := 0 215 | 216 | go func() { 217 | for { 218 | q.Get(1) 219 | i++ 220 | if i == b.N { 221 | wg.Done() 222 | break 223 | } 224 | } 225 | }() 226 | 227 | for i := 0; i < b.N; i++ { 228 | q.Put(mockItem(i)) 229 | } 230 | 231 | wg.Wait() 232 | } 233 | 234 | func TestPriorityPeek(t *testing.T) { 235 | q := NewPriorityQueue(1) 236 | q.Put(mockItem(1)) 237 | 238 | assert.Equal(t, mockItem(1), q.Peek()) 239 | } 240 | 241 | func TestInsertDuplicate(t *testing.T) { 242 | q := NewPriorityQueue(1) 243 | q.Put(mockItem(1)) 244 | q.Put(mockItem(1)) 245 | 246 | assert.Equal(t, 1, q.Len()) 247 | } 248 | -------------------------------------------------------------------------------- /numerics/optimization/global.go: -------------------------------------------------------------------------------- 1 | package optimization 2 | 3 | import ( 4 | "math" 5 | "sort" 6 | ) 7 | 8 | type pbs []*vertexProbabilityBundle 9 | 10 | type vertexProbabilityBundle struct { 11 | probability float64 12 | vertex *nmVertex 13 | } 14 | 15 | // calculateVVP will calculate the variable variance probability 16 | // of the provided vertex based on the previous best guess 17 | // and the provided sigma. The sigma changes with each run 18 | // of the optimization algorithm and accounts for a changing 19 | // number of guesses. 20 | // 21 | // VVP is defined as: 22 | // 1/((2*pi)^(1/2)*sigma)*(1-e^(-dmin^2/2*sigma^2)) 23 | // where dmin = euclidean distance between this vertex and the best guess 24 | // and sigma = (3*(m^(1/n)))^-1 25 | // 26 | func calculateVVP(guess, vertex *nmVertex, sigma float64) float64 { 27 | distance := -guess.euclideanDistance(vertex) 28 | lhs := 1 / (math.Sqrt(2*math.Pi) * sigma) 29 | rhs := 1 - math.Exp(math.Pow(distance, 2)/(2*math.Pow(sigma, 2))) 30 | return rhs * lhs 31 | } 32 | 33 | // calculateSigma will calculate sigma based on the provided information. 34 | // Typically, sigma will decrease as the number of sampled points 35 | // increases. 36 | // 37 | // sigma = (3*(m^(1/n)))^-1 38 | // 39 | func calculateSigma(dimensions, guesses int) float64 { 40 | return math.Pow(3*math.Pow(float64(guesses), 1/float64(dimensions)), -1) 41 | } 42 | 43 | func (pbs pbs) calculateProbabilities(bestGuess *nmVertex, sigma float64) { 44 | for _, v := range pbs { 45 | v.probability = calculateVVP(bestGuess, v.vertex, sigma) 46 | } 47 | } 48 | 49 | func (pbs pbs) sort() { 50 | sort.Sort(pbs) 51 | } 52 | 53 | func (pbs pbs) Less(i, j int) bool { 54 | return pbs[i].probability < pbs[j].probability 55 | } 56 | 57 | func (pbs pbs) Swap(i, j int) { 58 | pbs[i], pbs[j] = pbs[j], pbs[i] 59 | } 60 | 61 | func (pbs pbs) Len() int { 62 | return len(pbs) 63 | } 64 | 65 | // results stores the results of previous iterations of the 66 | // nelder-mead algorithm 67 | type results struct { 68 | // vertices are the results generated by the algorithm 69 | vertices vertices 70 | // config is useful for examining target 71 | config NelderMeadConfiguration 72 | // pbs contains the randomly generated guess vertices 73 | pbs pbs 74 | } 75 | 76 | // search will search this list of results based on order, order 77 | // being defined in the NelderMeadConfiguration, that is a defined 78 | // target will be treated 79 | func (results *results) search(result *nmVertex) int { 80 | return sort.Search(len(results.vertices), func(i int) bool { 81 | return !results.vertices[i].less(results.config, result) 82 | }) 83 | } 84 | 85 | func (results *results) exists(result *nmVertex, hint int) bool { 86 | if hint < 0 { 87 | hint = results.search(result) 88 | } 89 | 90 | // maximum hint here should be len(results.vertices) 91 | if hint > 0 && results.vertices[hint-1].approximatelyEqualToVertex(result) { 92 | return true 93 | } 94 | 95 | // -1 here because if hint == len(vertices) we would've already 96 | // checked the last value in the previous conditional 97 | if hint < len(results.vertices)-1 && results.vertices[hint].approximatelyEqualToVertex(result) { 98 | return true 99 | } 100 | 101 | return false 102 | } 103 | 104 | func (results *results) insert(vertex *nmVertex) { 105 | i := results.search(vertex) 106 | if results.exists(vertex, i) { 107 | return 108 | } 109 | 110 | if i == len(results.vertices) { 111 | results.vertices = append(results.vertices, vertex) 112 | return 113 | } 114 | 115 | results.vertices = append(results.vertices, nil) 116 | copy(results.vertices[i+1:], results.vertices[i:]) 117 | results.vertices[i] = vertex 118 | } 119 | 120 | func (results *results) grab(num int) vertices { 121 | vs := make(vertices, 0, num) 122 | // first, copy what you want to the list to return 123 | // not returning a sub-slice as we're about to mutate 124 | // the original slice 125 | for i := 0; i < num; i++ { 126 | vs = append(vs, results.pbs[i].vertex) 127 | } 128 | // now we overwrite the vertices that we are taking 129 | // from the beginning 130 | copy(results.pbs, results.pbs[num:]) 131 | length := len(results.pbs) - num 132 | // this next part is required for the GC 133 | for i := length; i < len(results.pbs); i++ { 134 | results.pbs[i] = nil 135 | } 136 | 137 | // and finally set the new slice as a subslice 138 | results.pbs = results.pbs[:length] 139 | return vs 140 | } 141 | 142 | // reSort will re-sort the list of possible guess vertices 143 | // based upon the latest calculated result. It was also 144 | // add this result to the list of results. 145 | func (results *results) reSort(vertex *nmVertex) { 146 | results.insert(vertex) 147 | 148 | bestGuess := results.vertices[0] 149 | sigma := calculateSigma(len(results.config.Vars), len(results.vertices)) 150 | results.pbs.calculateProbabilities(bestGuess, sigma) 151 | results.pbs.sort() 152 | } 153 | 154 | func newResults(guess *nmVertex, config NelderMeadConfiguration, num int) *results { 155 | vertices := make(vertices, 0, num+1) 156 | vertices = append(vertices, guess) 157 | vertices = append(vertices, generateRandomVerticesFromGuess(guess, num)...) 158 | 159 | bundles := make(pbs, 0, len(vertices)) 160 | for _, v := range vertices { 161 | bundles = append(bundles, &vertexProbabilityBundle{vertex: v}) 162 | } 163 | 164 | return &results{ 165 | pbs: bundles, 166 | config: config, 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /btree/palm/node.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package palm 18 | 19 | import ( 20 | "log" 21 | 22 | "github.com/Workiva/go-datastructures/slice/skip" 23 | ) 24 | 25 | func getParent(parent *node, key Key) *node { 26 | var n *node 27 | for parent != nil && !parent.isLeaf { 28 | n = parent.searchNode(key) 29 | parent = n 30 | } 31 | 32 | return parent 33 | } 34 | 35 | type nodes struct { 36 | list *skip.SkipList 37 | } 38 | 39 | func (ns *nodes) push(n *node) { 40 | ns.list.InsertAtPosition(ns.list.Len(), n) 41 | } 42 | 43 | func (ns *nodes) splitAt(i uint64) (*nodes, *nodes) { 44 | _, right := ns.list.SplitAt(i) 45 | return ns, &nodes{list: right} 46 | } 47 | 48 | func (ns *nodes) byPosition(pos uint64) *node { 49 | n, ok := ns.list.ByPosition(pos).(*node) 50 | if !ok { 51 | return nil 52 | } 53 | 54 | return n 55 | } 56 | 57 | func (ns *nodes) insertAt(i uint64, n *node) { 58 | ns.list.InsertAtPosition(i, n) 59 | } 60 | 61 | func (ns *nodes) replaceAt(i uint64, n *node) { 62 | ns.list.ReplaceAtPosition(i, n) 63 | } 64 | 65 | func (ns *nodes) len() uint64 { 66 | return ns.list.Len() 67 | } 68 | 69 | func newNodes() *nodes { 70 | return &nodes{ 71 | list: skip.New(uint64(0)), 72 | } 73 | } 74 | 75 | type keys struct { 76 | list *skip.SkipList 77 | } 78 | 79 | func (ks *keys) splitAt(i uint64) (*keys, *keys) { 80 | _, right := ks.list.SplitAt(i) 81 | return ks, &keys{list: right} 82 | } 83 | 84 | func (ks *keys) len() uint64 { 85 | return ks.list.Len() 86 | } 87 | 88 | func (ks *keys) byPosition(i uint64) Key { 89 | k, ok := ks.list.ByPosition(i).(Key) 90 | if !ok { 91 | return nil 92 | } 93 | 94 | return k 95 | } 96 | 97 | func (ks *keys) delete(k Key) { 98 | ks.list.Delete(k.(skip.Entry)) 99 | } 100 | 101 | func (ks *keys) search(key Key) uint64 { 102 | n, i := ks.list.GetWithPosition(key.(skip.Entry)) 103 | if n == nil { 104 | return ks.list.Len() 105 | } 106 | 107 | return i 108 | } 109 | 110 | func (ks *keys) insert(key Key) Key { 111 | old := ks.list.Insert(key)[0] 112 | if old == nil { 113 | return nil 114 | } 115 | 116 | return old.(Key) 117 | } 118 | 119 | func (ks *keys) last() Key { 120 | return ks.list.ByPosition(ks.list.Len() - 1).(Key) 121 | } 122 | 123 | func (ks *keys) insertAt(i uint64, k Key) { 124 | ks.list.InsertAtPosition(i, k.(skip.Entry)) 125 | } 126 | 127 | func newKeys() *keys { 128 | return &keys{ 129 | list: skip.New(uint64(0)), 130 | } 131 | } 132 | 133 | type node struct { 134 | keys *keys 135 | nodes *nodes 136 | isLeaf bool 137 | parent, right *node 138 | } 139 | 140 | func (n *node) needsSplit(ary uint64) bool { 141 | return n.keys.len() >= ary 142 | } 143 | 144 | func (n *node) splitLeaf() (Key, *node, *node) { 145 | i := n.keys.len() / 2 146 | key := n.keys.byPosition(i) 147 | _, rightKeys := n.keys.splitAt(i) 148 | nn := &node{ 149 | keys: rightKeys, 150 | nodes: newNodes(), 151 | isLeaf: true, 152 | } 153 | n.right = nn 154 | return key, n, nn 155 | } 156 | 157 | func (n *node) splitInternal() (Key, *node, *node) { 158 | i := n.keys.len() / 2 159 | key := n.keys.byPosition(i) 160 | n.keys.delete(key) 161 | 162 | _, rightKeys := n.keys.splitAt(i - 1) 163 | _, rightNodes := n.nodes.splitAt(i) 164 | 165 | nn := newNode(false, rightKeys, rightNodes) 166 | for iter := rightNodes.list.IterAtPosition(0); iter.Next(); { 167 | nd := iter.Value().(*node) 168 | nd.parent = nn 169 | } 170 | 171 | return key, n, nn 172 | } 173 | 174 | func (n *node) split() (Key, *node, *node) { 175 | if n.isLeaf { 176 | return n.splitLeaf() 177 | } 178 | 179 | return n.splitInternal() 180 | } 181 | 182 | func (n *node) search(key Key) uint64 { 183 | return n.keys.search(key) 184 | } 185 | 186 | func (n *node) searchNode(key Key) *node { 187 | i := n.search(key) 188 | 189 | return n.nodes.byPosition(uint64(i)) 190 | } 191 | 192 | func (n *node) key() Key { 193 | return n.keys.last() 194 | } 195 | 196 | func (n *node) print(output *log.Logger) { 197 | output.Printf(`NODE: %+v, %p`, n, n) 198 | for iter := n.keys.list.IterAtPosition(0); iter.Next(); { 199 | k := iter.Value().(Key) 200 | output.Printf(`KEY: %+v`, k) 201 | } 202 | if !n.isLeaf { 203 | for iter := n.nodes.list.IterAtPosition(0); iter.Next(); { 204 | n := iter.Value().(*node) 205 | if n == nil { 206 | output.Println(`NIL NODE`) 207 | continue 208 | } 209 | 210 | n.print(output) 211 | } 212 | } 213 | } 214 | 215 | // Compare is required by the skip.Entry interface but nodes are always 216 | // added by position so while this method is required it doesn't 217 | // need to return anything useful. 218 | func (n *node) Compare(e skip.Entry) int { 219 | return 0 220 | } 221 | 222 | func newNode(isLeaf bool, keys *keys, ns *nodes) *node { 223 | return &node{ 224 | isLeaf: isLeaf, 225 | keys: keys, 226 | nodes: ns, 227 | } 228 | } 229 | -------------------------------------------------------------------------------- /sort/symmerge.go: -------------------------------------------------------------------------------- 1 | package merge 2 | 3 | import ( 4 | "math" 5 | "sync" 6 | ) 7 | 8 | // symSearch is like symBinarySearch but operates 9 | // on two sorted lists instead of a sorted list and an index. 10 | // It's duplication of code but you buy performance. 11 | func symSearch(u, w Comparators) int { 12 | start, stop, p := 0, len(u), len(w)-1 13 | for start < stop { 14 | mid := (start + stop) / 2 15 | if u[mid].Compare(w[p-mid]) <= 0 { 16 | start = mid + 1 17 | } else { 18 | stop = mid 19 | } 20 | } 21 | 22 | return start 23 | } 24 | 25 | // swap will swap positions of the two lists from index 26 | // to the end of the list. It expects that these lists 27 | // are the same size or one different. 28 | func swap(u, w Comparators, index int) { 29 | for i := index; i < len(u); i++ { 30 | u[i], w[i-index] = w[i-index], u[i] 31 | } 32 | } 33 | 34 | // decomposeForSymMerge pulls an active site out of the list 35 | // of length in size. W becomes the active site for future sym 36 | // merges and v1, v2 are decomposed and split among the other 37 | // list to be merged and w. 38 | func decomposeForSymMerge(length int, 39 | comparators Comparators) (v1 Comparators, 40 | w Comparators, v2 Comparators) { 41 | 42 | if length >= len(comparators) { 43 | panic(`INCORRECT PARAMS FOR SYM MERGE.`) 44 | } 45 | 46 | overhang := (len(comparators) - length) / 2 47 | v1 = comparators[:overhang] 48 | w = comparators[overhang : overhang+length] 49 | v2 = comparators[overhang+length:] 50 | return 51 | } 52 | 53 | // symBinarySearch will perform a binary search between the provided 54 | // indices and find the index at which a rotation should occur. 55 | func symBinarySearch(u Comparators, start, stop, total int) int { 56 | for start < stop { 57 | mid := (start + stop) / 2 58 | if u[mid].Compare(u[total-mid]) <= 0 { 59 | start = mid + 1 60 | } else { 61 | stop = mid 62 | } 63 | } 64 | 65 | return start 66 | } 67 | 68 | // symSwap will perform a rotation or swap between the provided 69 | // indices. Again, there is duplication here with swap, but 70 | // we are buying performance. 71 | func symSwap(u Comparators, start1, start2, end int) { 72 | for i := 0; i < end; i++ { 73 | u[start1+i], u[start2+i] = u[start2+i], u[start1+i] 74 | } 75 | } 76 | 77 | // symRotate determines the indices to use in a symSwap and 78 | // performs the swap. 79 | func symRotate(u Comparators, start1, start2, end int) { 80 | i := start2 - start1 81 | if i == 0 { 82 | return 83 | } 84 | 85 | j := end - start2 86 | if j == 0 { 87 | return 88 | } 89 | 90 | if i == j { 91 | symSwap(u, start1, start2, i) 92 | return 93 | } 94 | 95 | p := start1 + i 96 | for i != j { 97 | if i > j { 98 | symSwap(u, p-i, p, j) 99 | i -= j 100 | } else { 101 | symSwap(u, p-i, p+j-i, i) 102 | j -= i 103 | } 104 | } 105 | symSwap(u, p-i, p, i) 106 | } 107 | 108 | // symMerge is the recursive and internal form of SymMerge. 109 | func symMerge(u Comparators, start1, start2, last int) { 110 | if start1 < start2 && start2 < last { 111 | mid := (start1 + last) / 2 112 | n := mid + start2 113 | var start int 114 | if start2 > mid { 115 | start = symBinarySearch(u, n-last, mid, n-1) 116 | } else { 117 | start = symBinarySearch(u, start1, start2, n-1) 118 | } 119 | end := n - start 120 | 121 | symRotate(u, start, start2, end) 122 | symMerge(u, start1, start, mid) 123 | symMerge(u, mid, end, last) 124 | } 125 | } 126 | 127 | // SymMerge will perform a symmetrical merge of the two provided 128 | // lists. It is expected that these lists are pre-sorted. Failure 129 | // to do so will result in undefined behavior. This function does 130 | // make use of goroutines, so multithreading can aid merge time. 131 | // This makes M*log(N/M+1) comparisons where M is the length 132 | // of the shorter list and N is the length of the longer list. 133 | func SymMerge(u, w Comparators) Comparators { 134 | lenU, lenW := len(u), len(w) 135 | if lenU == 0 { 136 | return w 137 | } 138 | 139 | if lenW == 0 { 140 | return u 141 | } 142 | 143 | diff := lenU - lenW 144 | if math.Abs(float64(diff)) > 1 { 145 | u1, w1, u2, w2 := prepareForSymMerge(u, w) 146 | 147 | lenU1 := len(u1) 148 | lenU2 := len(u2) 149 | u = append(u1, w1...) 150 | w = append(u2, w2...) 151 | var wg sync.WaitGroup 152 | wg.Add(2) 153 | go func() { 154 | symMerge(u, 0, lenU1, len(u)) 155 | wg.Done() 156 | }() 157 | go func() { 158 | symMerge(w, 0, lenU2, len(w)) 159 | wg.Done() 160 | }() 161 | 162 | wg.Wait() 163 | u = append(u, w...) 164 | return u 165 | } 166 | 167 | u = append(u, w...) 168 | symMerge(u, 0, lenU, len(u)) 169 | return u 170 | } 171 | 172 | // prepareForSymMerge performs a symmetrical decomposition on two 173 | // lists of different sizes. It breaks apart the longer list into 174 | // an active site (equal to the size of the shorter list) and performs 175 | // a symmetrical rotation with the active site and the shorter list. 176 | // The two stubs are then split between the active site and shorter list 177 | // ensuring two equally sized lists where every value in u' is less 178 | // than w'. 179 | func prepareForSymMerge(u, w Comparators) (u1, w1, u2, w2 Comparators) { 180 | if u.Len() > w.Len() { 181 | u, w = w, u 182 | } 183 | v1, w, v2 := decomposeForSymMerge(len(u), w) 184 | 185 | i := symSearch(u, w) 186 | 187 | u1 = make(Comparators, i) 188 | copy(u1, u[:i]) 189 | w1 = append(v1, w[:len(w)-i]...) 190 | 191 | u2 = make(Comparators, len(u)-i) 192 | copy(u2, u[i:]) 193 | 194 | w2 = append(w[len(w)-i:], v2...) 195 | return 196 | } 197 | -------------------------------------------------------------------------------- /numerics/optimization/nelder_mead_test.go: -------------------------------------------------------------------------------- 1 | package optimization 2 | 3 | import ( 4 | "math" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | ) 9 | 10 | func TestNelderMead(t *testing.T) { 11 | fn := func(vars []float64) (float64, bool) { 12 | return vars[0] * vars[1], true 13 | } 14 | config := NelderMeadConfiguration{ 15 | Target: float64(9), 16 | Fn: fn, 17 | Vars: []float64{2, 4}, 18 | } 19 | 20 | result, _ := fn(NelderMead(config)) 21 | assert.True(t, math.Abs(result-config.Target) <= .01) 22 | } 23 | 24 | func TestNelderMeadPolynomial(t *testing.T) { 25 | fn := func(vars []float64) (float64, bool) { 26 | // x^2-4x+y^2-y-xy, solution is (3, 2) 27 | return math.Pow(vars[0], 2) - 4*vars[0] + math.Pow(vars[1], 2) - vars[1] - vars[0]*vars[1], true 28 | } 29 | config := NelderMeadConfiguration{ 30 | Target: float64(-100), 31 | Fn: fn, 32 | Vars: []float64{-10, 10}, 33 | } 34 | 35 | result := NelderMead(config) 36 | calced, _ := fn(result) 37 | assert.True(t, math.Abs(7-math.Abs(calced)) <= .01) 38 | assert.True(t, math.Abs(3-result[0]) <= .1) 39 | assert.True(t, math.Abs(2-result[1]) <= .1) 40 | } 41 | 42 | func TestNelderMeadPolynomialMin(t *testing.T) { 43 | fn := func(vars []float64) (float64, bool) { 44 | // x^2-4x+y^2-y-xy, solution is (3, 2) 45 | return math.Pow(vars[0], 2) - 4*vars[0] + math.Pow(vars[1], 2) - vars[1] - vars[0]*vars[1], true 46 | } 47 | config := NelderMeadConfiguration{ 48 | Target: math.Inf(-1), 49 | Fn: fn, 50 | Vars: []float64{-10, 10}, 51 | } 52 | 53 | result := NelderMead(config) 54 | calced, _ := fn(result) 55 | assert.True(t, math.Abs(7-math.Abs(calced)) <= .01) 56 | assert.True(t, math.Abs(3-result[0]) <= .01) 57 | assert.True(t, math.Abs(2-result[1]) <= .01) 58 | } 59 | 60 | func TestNelderMeadPolynomialMax(t *testing.T) { 61 | fn := func(vars []float64) (float64, bool) { 62 | // 3+sin(x)+2cos(y)^2, the min on this equation is 2 and the max is 6 63 | return 3 + math.Sin(vars[0]) + 2*math.Pow(math.Cos(vars[1]), 2), true 64 | } 65 | 66 | config := NelderMeadConfiguration{ 67 | Target: math.Inf(1), 68 | Fn: fn, 69 | Vars: []float64{-5, 5}, 70 | } 71 | 72 | result := NelderMead(config) 73 | calced, _ := fn(result) 74 | assert.True(t, math.Abs(6-math.Abs(calced)) <= .01) 75 | } 76 | 77 | func TestNelderMeadConstrained(t *testing.T) { 78 | fn := func(vars []float64) (float64, bool) { 79 | if vars[0] < 1 || vars[1] < 1 { 80 | return 0, false 81 | } 82 | return math.Pow(vars[0], 2) - 4*vars[0] + math.Pow(vars[1], 2) - vars[1] - vars[0]*vars[1], true 83 | } 84 | // by default, converging on this point with the initial 85 | // guess of (6, 3) will converge to (~.46, ~4.75). The 86 | // fn has the added constraint that no guesses may be below 87 | // 1. This should now converge to a point (~8.28, ~4.93). 88 | config := NelderMeadConfiguration{ 89 | Target: float64(14), 90 | Fn: fn, 91 | Vars: []float64{6, 3}, 92 | } 93 | 94 | result := NelderMead(config) 95 | calced, _ := fn(result) 96 | assert.True(t, math.Abs(14-math.Abs(calced)) <= .01) 97 | assert.True(t, result[0] >= 1) 98 | assert.True(t, result[1] >= 1) 99 | 100 | fn = func(vars []float64) (float64, bool) { 101 | if vars[0] < 6 || vars[0] > 8 { 102 | return 0, false 103 | } 104 | 105 | if vars[1] < 0 || vars[1] > 2 { 106 | return 0, false 107 | } 108 | return math.Pow(vars[0], 2) - 4*vars[0] + math.Pow(vars[1], 2) - vars[1] - vars[0]*vars[1], true 109 | } 110 | 111 | config = NelderMeadConfiguration{ 112 | Target: float64(14), 113 | Fn: fn, 114 | Vars: []float64{6, .5}, 115 | } 116 | 117 | result = NelderMead(config) 118 | calced, _ = fn(result) 119 | // there are two local min here 120 | assert.True(t, math.Abs(14-math.Abs(calced)) <= .01 || math.Abs(8.75-math.Abs(calced)) <= .01) 121 | assert.True(t, result[0] >= 6 && result[0] <= 8) 122 | assert.True(t, result[1] >= 0 && result[1] <= 2) 123 | } 124 | 125 | func TestNelderMeadConstrainedBadGuess(t *testing.T) { 126 | fn := func(vars []float64) (float64, bool) { 127 | if vars[0] < 1 || vars[1] < 1 { 128 | return 0, false 129 | } 130 | return math.Pow(vars[0], 2) - 4*vars[0] + math.Pow(vars[1], 2) - vars[1] - vars[0]*vars[1], true 131 | } 132 | // this is a bad guess, as in the initial guess doesn't 133 | // match the constraints. In that case, we return the guessed 134 | // values. 135 | config := NelderMeadConfiguration{ 136 | Target: float64(14), 137 | Fn: fn, 138 | Vars: []float64{0, 3}, 139 | } 140 | 141 | result := NelderMead(config) 142 | assert.Equal(t, 0, result[0]) 143 | assert.Equal(t, 3, result[1]) 144 | } 145 | 146 | // Commenting this function out for now as it's entirely 147 | // probabilistic. Realistically, we can only say that we'll 148 | // find the local vs global min/max some percentage of the time 149 | // and that percentage depends entirely on the function. 150 | // This is here for debugging purposes. 151 | /* 152 | func TestNelderMeadFindGlobal(t *testing.T) { 153 | fn := func(vars []float64) (float64, bool) { 154 | if vars[0] < -4 || vars[0] > 2 { 155 | return 0, false 156 | } 157 | // x3 + 3x2 − 2x + 1 over [-4, 2] has a global maximum at x = 2 158 | return math.Pow(vars[0], 3) + 3*math.Pow(vars[0], 2) - 2*vars[0] + 1, true 159 | } 160 | 161 | config := NelderMeadConfiguration{ 162 | Target: math.Inf(1), 163 | Fn: fn, 164 | Vars: []float64{1.5}, 165 | } 166 | 167 | result := NelderMead(config) 168 | calced, _ := fn(result) 169 | wc, _ := fn([]float64{2}) 170 | t.Logf(`RESULT: %+v, CALCED: %+v, WC: %+v`, result, calced, wc) 171 | t.Fail() 172 | }*/ 173 | -------------------------------------------------------------------------------- /btree/plus/node_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package plus 18 | 19 | import ( 20 | "math/rand" 21 | "testing" 22 | 23 | "github.com/stretchr/testify/assert" 24 | ) 25 | 26 | func constructMockPayloads(num int) keys { 27 | keys := make(keys, 0, num) 28 | for i := 0; i < num; i++ { 29 | keys = append(keys, newMockKey(i)) 30 | } 31 | 32 | return keys 33 | } 34 | 35 | func constructMockKeys(num int) keys { 36 | keys := make(keys, 0, num) 37 | 38 | for i := 0; i < num; i++ { 39 | keys = append(keys, newMockKey(i)) 40 | } 41 | 42 | return keys 43 | } 44 | 45 | func constructRandomMockKeys(num int) keys { 46 | keys := make(keys, 0, num) 47 | for i := 0; i < num; i++ { 48 | keys = append(keys, newMockKey(rand.Int())) 49 | } 50 | 51 | return keys 52 | } 53 | 54 | func constructMockNodes(num int) nodes { 55 | nodes := make(nodes, 0, num) 56 | for i := 0; i < num; i++ { 57 | keys := make(keys, 0, num) 58 | for j := 0; j < num; j++ { 59 | keys = append(keys, newMockKey(j*i+j)) 60 | } 61 | 62 | node := &lnode{ 63 | keys: keys, 64 | } 65 | nodes = append(nodes, node) 66 | if i > 0 { 67 | nodes[i-1].(*lnode).pointer = node 68 | } 69 | } 70 | 71 | return nodes 72 | } 73 | 74 | func constructMockInternalNode(nodes nodes) *inode { 75 | if len(nodes) < 2 { 76 | return nil 77 | } 78 | 79 | keys := make(keys, 0, len(nodes)-1) 80 | for i := 1; i < len(nodes); i++ { 81 | keys = append(keys, nodes[i].(*lnode).keys[0]) 82 | } 83 | 84 | in := &inode{ 85 | keys: keys, 86 | nodes: nodes, 87 | } 88 | return in 89 | } 90 | 91 | func TestLeafNodeInsert(t *testing.T) { 92 | tree := newBTree(3) 93 | n := newLeafNode(3) 94 | key := newMockKey(3) 95 | 96 | n.insert(tree, key) 97 | 98 | assert.Len(t, n.keys, 1) 99 | assert.Nil(t, n.pointer) 100 | assert.Equal(t, n.keys[0], key) 101 | assert.Equal(t, 0, n.keys[0].Compare(key)) 102 | } 103 | 104 | func TestDuplicateLeafNodeInsert(t *testing.T) { 105 | tree := newBTree(3) 106 | n := newLeafNode(3) 107 | k1 := newMockKey(3) 108 | k2 := newMockKey(3) 109 | 110 | assert.True(t, n.insert(tree, k1)) 111 | assert.False(t, n.insert(tree, k2)) 112 | assert.False(t, n.insert(tree, k1)) 113 | } 114 | 115 | func TestMultipleLeafNodeInsert(t *testing.T) { 116 | tree := newBTree(3) 117 | n := newLeafNode(3) 118 | 119 | k1 := newMockKey(3) 120 | k2 := newMockKey(4) 121 | 122 | assert.True(t, n.insert(tree, k1)) 123 | n.insert(tree, k2) 124 | 125 | if !assert.Len(t, n.keys, 2) { 126 | return 127 | } 128 | assert.Nil(t, n.pointer) 129 | assert.Equal(t, k1, n.keys[0]) 130 | assert.Equal(t, k2, n.keys[1]) 131 | } 132 | 133 | func TestLeafNodeSplitEvenNumber(t *testing.T) { 134 | keys := constructMockPayloads(4) 135 | 136 | node := &lnode{ 137 | keys: keys, 138 | } 139 | 140 | key, left, right := node.split() 141 | assert.Equal(t, keys[2], key) 142 | assert.Equal(t, left.(*lnode).keys, keys[:2]) 143 | assert.Equal(t, right.(*lnode).keys, keys[2:]) 144 | assert.Equal(t, left.(*lnode).pointer, right) 145 | } 146 | 147 | func TestLeafNodeSplitOddNumber(t *testing.T) { 148 | keys := constructMockPayloads(3) 149 | 150 | node := &lnode{ 151 | keys: keys, 152 | } 153 | 154 | key, left, right := node.split() 155 | assert.Equal(t, keys[1], key) 156 | assert.Equal(t, left.(*lnode).keys, keys[:1]) 157 | assert.Equal(t, right.(*lnode).keys, keys[1:]) 158 | assert.Equal(t, left.(*lnode).pointer, right) 159 | } 160 | 161 | func TestTwoKeysLeafNodeSplit(t *testing.T) { 162 | keys := constructMockPayloads(2) 163 | 164 | node := &lnode{ 165 | keys: keys, 166 | } 167 | 168 | key, left, right := node.split() 169 | assert.Equal(t, keys[1], key) 170 | assert.Equal(t, left.(*lnode).keys, keys[:1]) 171 | assert.Equal(t, right.(*lnode).keys, keys[1:]) 172 | assert.Equal(t, left.(*lnode).pointer, right) 173 | } 174 | 175 | func TestLessThanTwoKeysSplit(t *testing.T) { 176 | keys := constructMockPayloads(1) 177 | 178 | node := &lnode{ 179 | keys: keys, 180 | } 181 | 182 | key, left, right := node.split() 183 | assert.Nil(t, key) 184 | assert.Nil(t, left) 185 | assert.Nil(t, right) 186 | } 187 | 188 | func TestInternalNodeSplit2_3_4(t *testing.T) { 189 | nodes := constructMockNodes(4) 190 | in := constructMockInternalNode(nodes) 191 | 192 | key, left, right := in.split() 193 | assert.Equal(t, nodes[3].(*lnode).keys[0], key) 194 | assert.Len(t, left.(*inode).keys, 1) 195 | assert.Len(t, right.(*inode).keys, 1) 196 | assert.Equal(t, nodes[:2], left.(*inode).nodes) 197 | assert.Equal(t, nodes[2:], right.(*inode).nodes) 198 | } 199 | 200 | func TestInternalNodeSplit3_4_5(t *testing.T) { 201 | nodes := constructMockNodes(5) 202 | in := constructMockInternalNode(nodes) 203 | 204 | key, left, right := in.split() 205 | assert.Equal(t, nodes[4].(*lnode).keys[0], key) 206 | assert.Len(t, left.(*inode).keys, 2) 207 | assert.Len(t, right.(*inode).keys, 1) 208 | assert.Equal(t, nodes[:3], left.(*inode).nodes) 209 | assert.Equal(t, nodes[3:], right.(*inode).nodes) 210 | } 211 | 212 | func TestInternalNodeLessThan3Keys(t *testing.T) { 213 | nodes := constructMockNodes(2) 214 | in := constructMockInternalNode(nodes) 215 | 216 | key, left, right := in.split() 217 | assert.Nil(t, key) 218 | assert.Nil(t, left) 219 | assert.Nil(t, right) 220 | } 221 | -------------------------------------------------------------------------------- /queue/ring_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package queue 18 | 19 | import ( 20 | "sync" 21 | "sync/atomic" 22 | "testing" 23 | 24 | "github.com/stretchr/testify/assert" 25 | ) 26 | 27 | func TestRingInsert(t *testing.T) { 28 | rb := NewRingBuffer(5) 29 | assert.Equal(t, uint64(8), rb.Cap()) 30 | 31 | err := rb.Put(5) 32 | if !assert.Nil(t, err) { 33 | return 34 | } 35 | 36 | result, err := rb.Get() 37 | if !assert.Nil(t, err) { 38 | return 39 | } 40 | 41 | assert.Equal(t, 5, result) 42 | } 43 | 44 | func TestRingMultipleInserts(t *testing.T) { 45 | rb := NewRingBuffer(5) 46 | 47 | err := rb.Put(1) 48 | if !assert.Nil(t, err) { 49 | return 50 | } 51 | 52 | err = rb.Put(2) 53 | if !assert.Nil(t, err) { 54 | return 55 | } 56 | 57 | result, err := rb.Get() 58 | if !assert.Nil(t, err) { 59 | return 60 | } 61 | 62 | assert.Equal(t, 1, result) 63 | 64 | result, err = rb.Get() 65 | if assert.Nil(t, err) { 66 | return 67 | } 68 | 69 | assert.Equal(t, 2, result) 70 | } 71 | 72 | func TestIntertwinedGetAndPut(t *testing.T) { 73 | rb := NewRingBuffer(5) 74 | err := rb.Put(1) 75 | if !assert.Nil(t, err) { 76 | return 77 | } 78 | 79 | result, err := rb.Get() 80 | if !assert.Nil(t, err) { 81 | return 82 | } 83 | 84 | assert.Equal(t, 1, result) 85 | 86 | err = rb.Put(2) 87 | if !assert.Nil(t, err) { 88 | return 89 | } 90 | 91 | result, err = rb.Get() 92 | if !assert.Nil(t, err) { 93 | return 94 | } 95 | 96 | assert.Equal(t, 2, result) 97 | } 98 | 99 | func TestPutToFull(t *testing.T) { 100 | rb := NewRingBuffer(3) 101 | 102 | for i := 0; i < 4; i++ { 103 | err := rb.Put(i) 104 | if !assert.Nil(t, err) { 105 | return 106 | } 107 | } 108 | 109 | var wg sync.WaitGroup 110 | wg.Add(2) 111 | 112 | go func() { 113 | err := rb.Put(4) 114 | assert.Nil(t, err) 115 | wg.Done() 116 | }() 117 | 118 | go func() { 119 | defer wg.Done() 120 | result, err := rb.Get() 121 | if !assert.Nil(t, err) { 122 | return 123 | } 124 | 125 | assert.Equal(t, 0, result) 126 | }() 127 | 128 | wg.Wait() 129 | } 130 | 131 | func TestRingGetEmpty(t *testing.T) { 132 | rb := NewRingBuffer(3) 133 | 134 | var wg sync.WaitGroup 135 | wg.Add(1) 136 | 137 | // want to kick off this consumer to ensure it blocks 138 | go func() { 139 | wg.Done() 140 | result, err := rb.Get() 141 | assert.Nil(t, err) 142 | assert.Equal(t, 0, result) 143 | wg.Done() 144 | }() 145 | 146 | wg.Wait() 147 | wg.Add(2) 148 | 149 | go func() { 150 | defer wg.Done() 151 | err := rb.Put(0) 152 | assert.Nil(t, err) 153 | }() 154 | 155 | wg.Wait() 156 | } 157 | 158 | func TestRingLen(t *testing.T) { 159 | rb := NewRingBuffer(4) 160 | assert.Equal(t, uint64(0), rb.Len()) 161 | 162 | rb.Put(1) 163 | assert.Equal(t, uint64(1), rb.Len()) 164 | 165 | rb.Get() 166 | assert.Equal(t, uint64(0), rb.Len()) 167 | 168 | for i := 0; i < 4; i++ { 169 | rb.Put(1) 170 | } 171 | assert.Equal(t, uint64(4), rb.Len()) 172 | 173 | rb.Get() 174 | assert.Equal(t, uint64(3), rb.Len()) 175 | } 176 | 177 | func TestDisposeOnGet(t *testing.T) { 178 | numThreads := 8 179 | var wg sync.WaitGroup 180 | wg.Add(numThreads) 181 | rb := NewRingBuffer(4) 182 | var spunUp sync.WaitGroup 183 | spunUp.Add(numThreads) 184 | 185 | for i := 0; i < numThreads; i++ { 186 | go func() { 187 | spunUp.Done() 188 | defer wg.Done() 189 | _, err := rb.Get() 190 | assert.NotNil(t, err) 191 | }() 192 | } 193 | 194 | spunUp.Wait() 195 | 196 | rb.Dispose() 197 | 198 | wg.Wait() 199 | 200 | assert.True(t, rb.IsDisposed()) 201 | } 202 | 203 | func TestDisposeOnPut(t *testing.T) { 204 | numThreads := 8 205 | var wg sync.WaitGroup 206 | wg.Add(numThreads) 207 | rb := NewRingBuffer(4) 208 | var spunUp sync.WaitGroup 209 | spunUp.Add(numThreads) 210 | 211 | // fill up the queue 212 | for i := 0; i < 4; i++ { 213 | rb.Put(i) 214 | } 215 | 216 | // it's now full 217 | for i := 0; i < numThreads; i++ { 218 | go func(i int) { 219 | spunUp.Done() 220 | defer wg.Done() 221 | err := rb.Put(i) 222 | assert.NotNil(t, err) 223 | }(i) 224 | } 225 | 226 | spunUp.Wait() 227 | 228 | rb.Dispose() 229 | 230 | wg.Wait() 231 | 232 | assert.True(t, rb.IsDisposed()) 233 | } 234 | 235 | func BenchmarkRBLifeCycle(b *testing.B) { 236 | rb := NewRingBuffer(64) 237 | 238 | counter := uint64(0) 239 | var wg sync.WaitGroup 240 | wg.Add(1) 241 | 242 | go func() { 243 | defer wg.Done() 244 | for { 245 | _, err := rb.Get() 246 | assert.Nil(b, err) 247 | 248 | if atomic.AddUint64(&counter, 1) == uint64(b.N) { 249 | return 250 | } 251 | } 252 | }() 253 | 254 | b.ResetTimer() 255 | 256 | for i := 0; i < b.N; i++ { 257 | rb.Put(i) 258 | } 259 | 260 | wg.Wait() 261 | } 262 | 263 | func BenchmarkRBPut(b *testing.B) { 264 | rbs := make([]*RingBuffer, 0, b.N) 265 | 266 | for i := 0; i < b.N; i++ { 267 | rbs = append(rbs, NewRingBuffer(2)) 268 | } 269 | 270 | b.ResetTimer() 271 | 272 | for i := 0; i < b.N; i++ { 273 | rbs[i].Put(i) 274 | } 275 | } 276 | 277 | func BenchmarkRBGet(b *testing.B) { 278 | rbs := make([]*RingBuffer, 0, b.N) 279 | 280 | for i := 0; i < b.N; i++ { 281 | rbs = append(rbs, NewRingBuffer(2)) 282 | rbs[i].Put(i) 283 | } 284 | 285 | b.ResetTimer() 286 | 287 | for i := 0; i < b.N; i++ { 288 | rbs[i].Get() 289 | } 290 | } 291 | -------------------------------------------------------------------------------- /hashmap/fastinteger/hashmap_test.go: -------------------------------------------------------------------------------- 1 | package fastinteger 2 | 3 | import ( 4 | "math/rand" 5 | "testing" 6 | "time" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | func generateKeys(num int) []uint64 { 12 | r := rand.New(rand.NewSource(time.Now().UnixNano())) 13 | 14 | keys := make([]uint64, 0, num) 15 | for i := 0; i < num; i++ { 16 | key := uint64(r.Int63()) 17 | keys = append(keys, key) 18 | } 19 | 20 | return keys 21 | } 22 | 23 | func TestRoundUp(t *testing.T) { 24 | result := roundUp(21) 25 | assert.Equal(t, uint64(32), result) 26 | 27 | result = roundUp(uint64(1<<31) - 234) 28 | assert.Equal(t, uint64(1<<31), result) 29 | 30 | result = roundUp(uint64(1<<63) - 324) 31 | assert.Equal(t, uint64(1<<63), result) 32 | } 33 | 34 | func TestInsert(t *testing.T) { 35 | hm := New(10) 36 | 37 | hm.Set(5, 5) 38 | 39 | assert.True(t, hm.Exists(5)) 40 | value, ok := hm.Get(5) 41 | assert.Equal(t, uint64(5), value) 42 | assert.True(t, ok) 43 | assert.Equal(t, uint64(16), hm.Cap()) 44 | } 45 | 46 | func TestInsertOverwrite(t *testing.T) { 47 | hm := New(10) 48 | 49 | hm.Set(5, 5) 50 | hm.Set(5, 10) 51 | 52 | assert.True(t, hm.Exists(5)) 53 | value, ok := hm.Get(5) 54 | assert.Equal(t, uint64(10), value) 55 | assert.True(t, ok) 56 | } 57 | 58 | func TestGet(t *testing.T) { 59 | hm := New(10) 60 | 61 | value, ok := hm.Get(5) 62 | assert.False(t, ok) 63 | assert.Equal(t, uint64(0), value) 64 | } 65 | 66 | func TestMultipleInserts(t *testing.T) { 67 | hm := New(10) 68 | 69 | hm.Set(5, 5) 70 | hm.Set(6, 6) 71 | 72 | assert.True(t, hm.Exists(6)) 73 | value, ok := hm.Get(6) 74 | assert.True(t, ok) 75 | assert.Equal(t, uint64(6), value) 76 | } 77 | 78 | func TestRebuild(t *testing.T) { 79 | numItems := uint64(100) 80 | 81 | hm := New(10) 82 | 83 | for i := uint64(0); i < numItems; i++ { 84 | hm.Set(i, i) 85 | } 86 | 87 | for i := uint64(0); i < numItems; i++ { 88 | value, _ := hm.Get(i) 89 | assert.Equal(t, i, value) 90 | } 91 | } 92 | 93 | func TestDelete(t *testing.T) { 94 | hm := New(10) 95 | 96 | hm.Set(5, 5) 97 | hm.Set(6, 6) 98 | 99 | hm.Delete(5) 100 | 101 | assert.Equal(t, uint64(1), hm.Len()) 102 | assert.False(t, hm.Exists(5)) 103 | 104 | hm.Delete(6) 105 | assert.Equal(t, uint64(0), hm.Len()) 106 | assert.False(t, hm.Exists(6)) 107 | } 108 | 109 | func TestDeleteAll(t *testing.T) { 110 | numItems := uint64(100) 111 | 112 | hm := New(10) 113 | 114 | for i := uint64(0); i < numItems; i++ { 115 | hm.Set(i, i) 116 | } 117 | 118 | for i := uint64(0); i < numItems; i++ { 119 | hm.Delete(i) 120 | assert.False(t, hm.Exists(i)) 121 | } 122 | } 123 | 124 | func BenchmarkInsert(b *testing.B) { 125 | numItems := uint64(1000) 126 | 127 | keys := generateKeys(int(numItems)) 128 | 129 | b.ResetTimer() 130 | 131 | for i := 0; i < b.N; i++ { 132 | hm := New(numItems * 2) // so we don't rebuild 133 | for _, k := range keys { 134 | hm.Set(k, k) 135 | } 136 | } 137 | } 138 | 139 | func BenchmarkGoMapInsert(b *testing.B) { 140 | numItems := uint64(1000) 141 | 142 | keys := generateKeys(int(numItems)) 143 | 144 | b.ResetTimer() 145 | 146 | for i := 0; i < b.N; i++ { 147 | hm := make(map[uint64]uint64, numItems*2) // so we don't rebuild 148 | for _, k := range keys { 149 | hm[k] = k 150 | } 151 | } 152 | } 153 | 154 | func BenchmarkExists(b *testing.B) { 155 | numItems := uint64(1000) 156 | 157 | keys := generateKeys(int(numItems)) 158 | hm := New(numItems * 2) // so we don't rebuild 159 | for _, key := range keys { 160 | hm.Set(key, key) 161 | } 162 | 163 | b.ResetTimer() 164 | 165 | for i := 0; i < b.N; i++ { 166 | for _, key := range keys { 167 | hm.Exists(key) 168 | } 169 | } 170 | } 171 | 172 | func BenchmarkGoMapExists(b *testing.B) { 173 | numItems := uint64(1000) 174 | 175 | keys := generateKeys(int(numItems)) 176 | hm := make(map[uint64]uint64, numItems*2) // so we don't rebuild 177 | for _, key := range keys { 178 | hm[key] = key 179 | } 180 | 181 | b.ResetTimer() 182 | 183 | var ok bool 184 | for i := 0; i < b.N; i++ { 185 | for _, key := range keys { 186 | _, ok = hm[key] // or the compiler complains 187 | } 188 | } 189 | 190 | b.StopTimer() 191 | if ok { // or the compiler complains 192 | } 193 | } 194 | 195 | func BenchmarkDelete(b *testing.B) { 196 | numItems := uint64(1000) 197 | 198 | hms := make([]*FastIntegerHashMap, 0, b.N) 199 | for i := 0; i < b.N; i++ { 200 | hm := New(numItems * 2) 201 | for j := uint64(0); j < numItems; j++ { 202 | hm.Set(j, j) 203 | } 204 | hms = append(hms, hm) 205 | } 206 | 207 | b.ResetTimer() 208 | 209 | for i := 0; i < b.N; i++ { 210 | hm := hms[i] 211 | for j := uint64(0); j < numItems; j++ { 212 | hm.Delete(j) 213 | } 214 | } 215 | } 216 | 217 | func BenchmarkGoDelete(b *testing.B) { 218 | numItems := uint64(1000) 219 | 220 | hms := make([]map[uint64]uint64, 0, b.N) 221 | for i := 0; i < b.N; i++ { 222 | hm := make(map[uint64]uint64, numItems*2) 223 | for j := uint64(0); j < numItems; j++ { 224 | hm[j] = j 225 | } 226 | hms = append(hms, hm) 227 | } 228 | 229 | b.ResetTimer() 230 | 231 | for i := 0; i < b.N; i++ { 232 | hm := hms[i] 233 | for j := uint64(0); j < numItems; j++ { 234 | delete(hm, j) 235 | } 236 | } 237 | } 238 | 239 | func BenchmarkInsertWithExpand(b *testing.B) { 240 | numItems := uint64(1000) 241 | 242 | hms := make([]*FastIntegerHashMap, 0, b.N) 243 | for i := 0; i < b.N; i++ { 244 | hm := New(10) 245 | hms = append(hms, hm) 246 | } 247 | 248 | b.ResetTimer() 249 | 250 | for i := 0; i < b.N; i++ { 251 | hm := hms[i] 252 | for j := uint64(0); j < numItems; j++ { 253 | hm.Set(j, j) 254 | } 255 | } 256 | } 257 | 258 | func BenchmarkGoInsertWithExpand(b *testing.B) { 259 | numItems := uint64(1000) 260 | 261 | hms := make([]map[uint64]uint64, 0, b.N) 262 | for i := 0; i < b.N; i++ { 263 | hm := make(map[uint64]uint64, 10) 264 | hms = append(hms, hm) 265 | } 266 | 267 | b.ResetTimer() 268 | 269 | for i := 0; i < b.N; i++ { 270 | hm := hms[i] 271 | for j := uint64(0); j < numItems; j++ { 272 | hm[j] = j 273 | } 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /queue/priority_queue.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | /* 18 | The priority queue is almost a spitting image of the logic 19 | used for a regular queue. In order to keep the logic fast, 20 | this code is repeated instead of using casts to cast to interface{} 21 | back and forth. If Go had inheritance and generics, this problem 22 | would be easier to solve. 23 | */ 24 | package queue 25 | 26 | import ( 27 | "sort" 28 | "sync" 29 | ) 30 | 31 | // Item is an item that can be added to the priority queue. 32 | type Item interface { 33 | // Compare returns a bool that can be used to determine 34 | // ordering in the priority queue. Assuming the queue 35 | // is in ascending order, this should return > logic. 36 | // Return 1 to indicate this object is greater than the 37 | // the other logic, 0 to indicate equality, and -1 to indicate 38 | // less than other. 39 | Compare(other Item) int 40 | } 41 | 42 | type priorityItems []Item 43 | 44 | func (items *priorityItems) get(number int) []Item { 45 | returnItems := make([]Item, 0, number) 46 | index := 0 47 | for i := 0; i < number; i++ { 48 | if i >= len(*items) { 49 | break 50 | } 51 | 52 | returnItems = append(returnItems, (*items)[i]) 53 | (*items)[i] = nil 54 | index++ 55 | } 56 | 57 | *items = (*items)[index:] 58 | return returnItems 59 | } 60 | 61 | func (items *priorityItems) insert(item Item) { 62 | if len(*items) == 0 { 63 | *items = append(*items, item) 64 | return 65 | } 66 | 67 | equalFound := false 68 | i := sort.Search(len(*items), func(i int) bool { 69 | result := (*items)[i].Compare(item) 70 | if result == 0 { 71 | equalFound = true 72 | } 73 | return result >= 0 74 | }) 75 | 76 | if equalFound { 77 | return 78 | } 79 | 80 | if i == len(*items) { 81 | *items = append(*items, item) 82 | return 83 | } 84 | 85 | *items = append(*items, nil) 86 | copy((*items)[i+1:], (*items)[i:]) 87 | (*items)[i] = item 88 | } 89 | 90 | // PriorityQueue is similar to queue except that it takes 91 | // items that implement the Item interface and adds them 92 | // to the queue in priority order. 93 | type PriorityQueue struct { 94 | waiters waiters 95 | items priorityItems 96 | lock sync.Mutex 97 | disposeLock sync.Mutex 98 | disposed bool 99 | } 100 | 101 | // Put adds items to the queue. 102 | func (pq *PriorityQueue) Put(items ...Item) error { 103 | if len(items) == 0 { 104 | return nil 105 | } 106 | 107 | pq.lock.Lock() 108 | if pq.disposed { 109 | pq.lock.Unlock() 110 | return disposedError 111 | } 112 | 113 | for _, item := range items { 114 | pq.items.insert(item) 115 | } 116 | 117 | for { 118 | sema := pq.waiters.get() 119 | if sema == nil { 120 | break 121 | } 122 | 123 | sema.response.Add(1) 124 | sema.wg.Done() 125 | sema.response.Wait() 126 | if len(pq.items) == 0 { 127 | break 128 | } 129 | } 130 | 131 | pq.lock.Unlock() 132 | return nil 133 | } 134 | 135 | // Get retrieves items from the queue. If the queue is empty, 136 | // this call blocks until the next item is added to the queue. This 137 | // will attempt to retrieve number of items. 138 | func (pq *PriorityQueue) Get(number int) ([]Item, error) { 139 | if number < 1 { 140 | return nil, nil 141 | } 142 | 143 | pq.lock.Lock() 144 | 145 | if pq.disposed { 146 | pq.lock.Unlock() 147 | return nil, disposedError 148 | } 149 | 150 | var items []Item 151 | 152 | if len(pq.items) == 0 { 153 | sema := newSema() 154 | pq.waiters.put(sema) 155 | sema.wg.Add(1) 156 | pq.lock.Unlock() 157 | 158 | sema.wg.Wait() 159 | pq.disposeLock.Lock() 160 | if pq.disposed { 161 | pq.disposeLock.Unlock() 162 | return nil, disposedError 163 | } 164 | pq.disposeLock.Unlock() 165 | 166 | items = pq.items.get(number) 167 | sema.response.Done() 168 | return items, nil 169 | } 170 | 171 | items = pq.items.get(number) 172 | pq.lock.Unlock() 173 | return items, nil 174 | } 175 | 176 | // Peek will look at the next item without removing it from the queue. 177 | func (pq *PriorityQueue) Peek() Item { 178 | pq.lock.Lock() 179 | defer pq.lock.Unlock() 180 | if len(pq.items) > 0 { 181 | return pq.items[0] 182 | } 183 | return nil 184 | } 185 | 186 | // Empty returns a bool indicating if there are any items left 187 | // in the queue. 188 | func (pq *PriorityQueue) Empty() bool { 189 | pq.lock.Lock() 190 | defer pq.lock.Unlock() 191 | 192 | return len(pq.items) == 0 193 | } 194 | 195 | // Len returns a number indicating how many items are in the queue. 196 | func (pq *PriorityQueue) Len() int { 197 | pq.lock.Lock() 198 | defer pq.lock.Unlock() 199 | 200 | return len(pq.items) 201 | } 202 | 203 | // Disposed returns a bool indicating if this queue has been disposed. 204 | func (pq *PriorityQueue) Disposed() bool { 205 | pq.lock.Lock() 206 | defer pq.lock.Unlock() 207 | 208 | return pq.disposed 209 | } 210 | 211 | // Dispose will prevent any further reads/writes to this queue 212 | // and frees available resources. 213 | func (pq *PriorityQueue) Dispose() { 214 | pq.lock.Lock() 215 | defer pq.lock.Unlock() 216 | 217 | pq.disposeLock.Lock() 218 | defer pq.disposeLock.Unlock() 219 | 220 | pq.disposed = true 221 | for _, waiter := range pq.waiters { 222 | waiter.response.Add(1) 223 | waiter.wg.Done() 224 | } 225 | 226 | pq.items = nil 227 | pq.waiters = nil 228 | } 229 | 230 | // NewPriorityQueue is the constructor for a priority queue. 231 | func NewPriorityQueue(hint int) *PriorityQueue { 232 | return &PriorityQueue{ 233 | items: make(priorityItems, 0, hint), 234 | } 235 | } 236 | -------------------------------------------------------------------------------- /rangetree/orderedtree.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package rangetree 18 | 19 | func isLastDimension(value, test uint64) bool { 20 | return test >= value 21 | } 22 | 23 | type nodeBundle struct { 24 | list *orderedNodes 25 | index int 26 | } 27 | 28 | type orderedTree struct { 29 | top orderedNodes 30 | number uint64 31 | dimensions uint64 32 | path []*nodeBundle 33 | } 34 | 35 | func (ot *orderedTree) resetPath() { 36 | ot.path = ot.path[:0] 37 | } 38 | 39 | func (ot *orderedTree) needNextDimension() bool { 40 | return ot.dimensions > 1 41 | } 42 | 43 | // add will add the provided entry to the rangetree and return an 44 | // entry if one was overwritten. 45 | func (ot *orderedTree) add(entry Entry) *node { 46 | var node *node 47 | list := &ot.top 48 | 49 | for i := uint64(1); i <= ot.dimensions; i++ { 50 | if isLastDimension(ot.dimensions, i) { 51 | overwritten := list.add( 52 | newNode(entry.ValueAtDimension(i), entry, false), 53 | ) 54 | if overwritten == nil { 55 | ot.number++ 56 | } 57 | return overwritten 58 | } 59 | node, _ = list.getOrAdd(entry, i, ot.dimensions) 60 | list = &node.orderedNodes 61 | } 62 | 63 | return nil 64 | } 65 | 66 | // Add will add the provided entries to the tree. This method 67 | // returns a list of cells that were overwritten in the order 68 | // in which cells were received. If a cell doesn't overwrite 69 | // anything, a nil will be returned for that entry in the returned 70 | // slice. 71 | func (ot *orderedTree) Add(entries ...Entry) Entries { 72 | if len(entries) == 0 { 73 | return nil 74 | } 75 | 76 | overwrittens := make(Entries, 0, len(entries)) 77 | for _, entry := range entries { 78 | if entry == nil { 79 | continue 80 | } 81 | 82 | overwritten := ot.add(entry) 83 | if overwritten != nil { 84 | overwrittens = append(overwrittens, overwritten.entry) 85 | } else { 86 | overwrittens = append(overwrittens, nil) 87 | } 88 | } 89 | 90 | return overwrittens 91 | } 92 | 93 | func (ot *orderedTree) delete(entry Entry) { 94 | ot.resetPath() 95 | var index int 96 | var node *node 97 | list := &ot.top 98 | 99 | for i := uint64(1); i <= ot.dimensions; i++ { 100 | value := entry.ValueAtDimension(i) 101 | node, index = list.get(value) 102 | if node == nil { // there's nothing to delete 103 | return 104 | } 105 | 106 | nb := &nodeBundle{list: list, index: index} 107 | ot.path = append(ot.path, nb) 108 | 109 | list = &node.orderedNodes 110 | } 111 | 112 | ot.number-- 113 | 114 | for i := len(ot.path) - 1; i >= 0; i-- { 115 | nb := ot.path[i] 116 | nb.list.deleteAt(nb.index) 117 | if len(*nb.list) > 0 { 118 | break 119 | } 120 | } 121 | } 122 | 123 | // Delete will remove the entries from the tree. 124 | func (ot *orderedTree) Delete(entries ...Entry) { 125 | for _, entry := range entries { 126 | ot.delete(entry) 127 | } 128 | } 129 | 130 | // Len returns the number of items in the tree. 131 | func (ot *orderedTree) Len() uint64 { 132 | return ot.number 133 | } 134 | 135 | func (ot *orderedTree) apply(list orderedNodes, interval Interval, 136 | dimension uint64, fn func(*node) bool) bool { 137 | 138 | low, high := interval.LowAtDimension(dimension), interval.HighAtDimension(dimension) 139 | 140 | if isLastDimension(ot.dimensions, dimension) { 141 | if !list.apply(low, high, fn) { 142 | return false 143 | } 144 | } else { 145 | if !list.apply(low, high, func(n *node) bool { 146 | if !ot.apply(n.orderedNodes, interval, dimension+1, fn) { 147 | return false 148 | } 149 | return true 150 | }) { 151 | return false 152 | } 153 | return true 154 | } 155 | 156 | return true 157 | } 158 | 159 | // Apply will call (in order) the provided function to every 160 | // entry that falls within the provided interval. Any alteration 161 | // the the entry that would result in different answers to the 162 | // interface methods results in undefined behavior. 163 | func (ot *orderedTree) Apply(interval Interval, fn func(Entry) bool) { 164 | ot.apply(ot.top, interval, 1, func(n *node) bool { 165 | return fn(n.entry) 166 | }) 167 | } 168 | 169 | // Query will return an ordered list of results in the given 170 | // interval. 171 | func (ot *orderedTree) Query(interval Interval) Entries { 172 | entries := NewEntries() 173 | 174 | ot.apply(ot.top, interval, 1, func(n *node) bool { 175 | entries = append(entries, n.entry) 176 | return true 177 | }) 178 | 179 | return entries 180 | } 181 | 182 | // InsertAtDimension will increment items at and above the given index 183 | // by the number provided. Provide a negative number to to decrement. 184 | // Returned are two lists. The first list is a list of entries that 185 | // were moved. The second is a list entries that were deleted. These 186 | // lists are exclusive. 187 | func (ot *orderedTree) InsertAtDimension(dimension uint64, 188 | index, number int64) (Entries, Entries) { 189 | 190 | // TODO: perhaps return an error here? 191 | if dimension > ot.dimensions || number == 0 { 192 | return nil, nil 193 | } 194 | 195 | modified := make(Entries, 0, 100) 196 | deleted := make(Entries, 0, 100) 197 | 198 | ot.top.insert(dimension, 1, ot.dimensions, 199 | index, number, &modified, &deleted, 200 | ) 201 | 202 | ot.number -= uint64(len(deleted)) 203 | 204 | return modified, deleted 205 | } 206 | 207 | func newOrderedTree(dimensions uint64) *orderedTree { 208 | return &orderedTree{ 209 | dimensions: dimensions, 210 | path: make([]*nodeBundle, 0, dimensions), 211 | } 212 | } 213 | 214 | // New is the constructor to create a new rangetree with 215 | // the provided number of dimensions. 216 | func New(dimensions uint64) RangeTree { 217 | return newOrderedTree(dimensions) 218 | } 219 | -------------------------------------------------------------------------------- /bitarray/or_test.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package bitarray 18 | 19 | import ( 20 | "testing" 21 | 22 | "github.com/stretchr/testify/assert" 23 | ) 24 | 25 | func TestOrSparseWithSparseBitArray(t *testing.T) { 26 | sba := newSparseBitArray() 27 | other := newSparseBitArray() 28 | 29 | ctx := false 30 | for i := uint64(0); i < 1000; i += s { 31 | if ctx { 32 | sba.SetBit(i) 33 | } else { 34 | other.SetBit(i) 35 | } 36 | 37 | ctx = !ctx 38 | } 39 | 40 | sba.SetBit(s - 1) 41 | other.SetBit(s - 1) 42 | 43 | result := orSparseWithSparseBitArray(sba, other) 44 | 45 | for i := uint64(0); i < 1000; i += s { 46 | ok, err := result.GetBit(i) 47 | assert.Nil(t, err) 48 | assert.True(t, ok) 49 | } 50 | 51 | ok, err := result.GetBit(s - 1) 52 | assert.Nil(t, err) 53 | assert.True(t, ok) 54 | 55 | ok, err = result.GetBit(s - 2) 56 | assert.Nil(t, err) 57 | assert.False(t, ok) 58 | 59 | other.SetBit(2000) 60 | result = orSparseWithSparseBitArray(sba, other) 61 | 62 | ok, err = result.GetBit(2000) 63 | assert.Nil(t, err) 64 | assert.True(t, ok) 65 | 66 | sba.SetBit(2000) 67 | result = orSparseWithSparseBitArray(sba, other) 68 | 69 | ok, err = result.GetBit(2000) 70 | assert.Nil(t, err) 71 | assert.True(t, ok) 72 | } 73 | 74 | func BenchmarkOrSparseWithSparse(b *testing.B) { 75 | numItems := uint64(160000) 76 | sba := newSparseBitArray() 77 | other := newSparseBitArray() 78 | 79 | ctx := false 80 | for i := uint64(0); i < numItems; i += s { 81 | if ctx { 82 | sba.SetBit(i) 83 | } else { 84 | other.SetBit(i) 85 | } 86 | 87 | ctx = !ctx 88 | } 89 | 90 | b.ResetTimer() 91 | 92 | for i := 0; i < b.N; i++ { 93 | orSparseWithSparseBitArray(sba, other) 94 | } 95 | } 96 | 97 | func TestOrSparseWithDenseBitArray(t *testing.T) { 98 | sba := newSparseBitArray() 99 | other := newBitArray(2000) 100 | 101 | ctx := false 102 | for i := uint64(0); i < 1000; i += s { 103 | if ctx { 104 | sba.SetBit(i) 105 | } else { 106 | other.SetBit(i) 107 | } 108 | 109 | ctx = !ctx 110 | } 111 | 112 | other.SetBit(1500) 113 | other.SetBit(s - 1) 114 | sba.SetBit(s - 1) 115 | 116 | result := orSparseWithDenseBitArray(sba, other) 117 | 118 | for i := uint64(0); i < 1000; i += s { 119 | ok, err := result.GetBit(i) 120 | assert.Nil(t, err) 121 | assert.True(t, ok) 122 | } 123 | 124 | ok, err := result.GetBit(1500) 125 | assert.Nil(t, err) 126 | assert.True(t, ok) 127 | 128 | ok, err = result.GetBit(s - 1) 129 | assert.Nil(t, err) 130 | assert.True(t, ok) 131 | 132 | ok, err = result.GetBit(s - 2) 133 | assert.Nil(t, err) 134 | assert.False(t, ok) 135 | 136 | sba.SetBit(2500) 137 | result = orSparseWithDenseBitArray(sba, other) 138 | 139 | ok, err = result.GetBit(2500) 140 | assert.Nil(t, err) 141 | assert.True(t, ok) 142 | } 143 | 144 | func BenchmarkOrSparseWithDense(b *testing.B) { 145 | numItems := uint64(160000) 146 | sba := newSparseBitArray() 147 | other := newBitArray(numItems) 148 | 149 | ctx := false 150 | for i := uint64(0); i < numItems; i += s { 151 | if ctx { 152 | sba.SetBit(i) 153 | } else { 154 | other.SetBit(i) 155 | } 156 | 157 | ctx = !ctx 158 | } 159 | 160 | b.ResetTimer() 161 | 162 | for i := 0; i < b.N; i++ { 163 | orSparseWithDenseBitArray(sba, other) 164 | } 165 | } 166 | 167 | func TestOrDenseWithDenseBitArray(t *testing.T) { 168 | dba := newBitArray(1000) 169 | other := newBitArray(2000) 170 | 171 | ctx := false 172 | for i := uint64(0); i < 1000; i += s { 173 | if ctx { 174 | dba.SetBit(i) 175 | } else { 176 | other.SetBit(i) 177 | } 178 | 179 | ctx = !ctx 180 | } 181 | 182 | other.SetBit(1500) 183 | other.SetBit(s - 1) 184 | dba.SetBit(s - 1) 185 | 186 | result := orDenseWithDenseBitArray(dba, other) 187 | 188 | for i := uint64(0); i < 1000; i += s { 189 | ok, err := result.GetBit(i) 190 | assert.Nil(t, err) 191 | assert.True(t, ok) 192 | } 193 | 194 | ok, err := result.GetBit(s - 1) 195 | assert.Nil(t, err) 196 | assert.True(t, ok) 197 | 198 | ok, err = result.GetBit(1500) 199 | assert.Nil(t, err) 200 | assert.True(t, ok) 201 | 202 | ok, err = result.GetBit(1700) 203 | assert.Nil(t, err) 204 | assert.False(t, ok) 205 | } 206 | 207 | func BenchmarkOrDenseWithDense(b *testing.B) { 208 | numItems := uint64(160000) 209 | dba := newBitArray(numItems) 210 | other := newBitArray(numItems) 211 | 212 | ctx := false 213 | for i := uint64(0); i < numItems; i += s { 214 | if ctx { 215 | dba.SetBit(i) 216 | } else { 217 | other.SetBit(i) 218 | } 219 | 220 | ctx = !ctx 221 | } 222 | 223 | b.ResetTimer() 224 | 225 | for i := 0; i < b.N; i++ { 226 | orDenseWithDenseBitArray(dba, other) 227 | } 228 | } 229 | 230 | func TestOrSparseWithEmptySparse(t *testing.T) { 231 | sba := newSparseBitArray() 232 | other := newSparseBitArray() 233 | 234 | sba.SetBit(5) 235 | 236 | result := orSparseWithSparseBitArray(sba, other) 237 | assert.Equal(t, sba, result) 238 | 239 | sba.Reset() 240 | other.SetBit(5) 241 | 242 | result = orSparseWithSparseBitArray(sba, other) 243 | assert.Equal(t, other, result) 244 | } 245 | 246 | func TestOrSparseWithEmptyDense(t *testing.T) { 247 | sba := newSparseBitArray() 248 | other := newBitArray(1000) 249 | 250 | sba.SetBit(5) 251 | result := orSparseWithDenseBitArray(sba, other) 252 | assert.Equal(t, sba, result) 253 | 254 | sba.Reset() 255 | other.SetBit(5) 256 | 257 | result = orSparseWithDenseBitArray(sba, other) 258 | assert.Equal(t, other, result) 259 | } 260 | 261 | func TestOrDenseWithEmptyDense(t *testing.T) { 262 | dba := newBitArray(1000) 263 | other := newBitArray(1000) 264 | 265 | dba.SetBit(5) 266 | result := orDenseWithDenseBitArray(dba, other) 267 | assert.Equal(t, dba, result) 268 | 269 | dba.Reset() 270 | other.SetBit(5) 271 | result = orDenseWithDenseBitArray(dba, other) 272 | assert.Equal(t, other, result) 273 | } 274 | -------------------------------------------------------------------------------- /rangetree/ordered.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright 2014 Workiva, LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package rangetree 18 | 19 | import "sort" 20 | 21 | // orderedNodes represents an ordered list of points living 22 | // at the last dimension. No duplicates can be inserted here. 23 | type orderedNodes nodes 24 | 25 | func (nodes orderedNodes) search(value int64) int { 26 | return sort.Search( 27 | len(nodes), 28 | func(i int) bool { return nodes[i].value >= value }, 29 | ) 30 | } 31 | 32 | // addAt will add the provided node at the provided index. Returns 33 | // a node if one was overwritten. 34 | func (nodes *orderedNodes) addAt(i int, node *node) *node { 35 | if i == len(*nodes) { 36 | *nodes = append(*nodes, node) 37 | return nil 38 | } 39 | 40 | if (*nodes)[i].value == node.value { 41 | overwritten := (*nodes)[i] 42 | // this is a duplicate, there can't be a duplicate 43 | // point in the last dimension 44 | (*nodes)[i] = node 45 | return overwritten 46 | } 47 | 48 | *nodes = append(*nodes, nil) 49 | copy((*nodes)[i+1:], (*nodes)[i:]) 50 | (*nodes)[i] = node 51 | return nil 52 | } 53 | 54 | func (nodes *orderedNodes) add(node *node) *node { 55 | i := nodes.search(node.value) 56 | return nodes.addAt(i, node) 57 | } 58 | 59 | func (nodes *orderedNodes) deleteAt(i int) { 60 | if i >= len(*nodes) { // no matching found 61 | return 62 | } 63 | 64 | copy((*nodes)[i:], (*nodes)[i+1:]) 65 | (*nodes)[len(*nodes)-1] = nil 66 | *nodes = (*nodes)[:len(*nodes)-1] 67 | } 68 | 69 | func (nodes *orderedNodes) delete(value int64) { 70 | i := nodes.search(value) 71 | 72 | if (*nodes)[i].value != value || i == len(*nodes) { 73 | return 74 | } 75 | 76 | nodes.deleteAt(i) 77 | } 78 | 79 | func (nodes orderedNodes) apply(low, high int64, fn func(*node) bool) bool { 80 | index := nodes.search(low) 81 | if index == len(nodes) { 82 | return true 83 | } 84 | 85 | for ; index < len(nodes); index++ { 86 | if nodes[index].value >= high { 87 | break 88 | } 89 | 90 | if !fn(nodes[index]) { 91 | return false 92 | } 93 | } 94 | 95 | return true 96 | } 97 | 98 | func (nodes orderedNodes) get(value int64) (*node, int) { 99 | i := nodes.search(value) 100 | if i == len(nodes) { 101 | return nil, i 102 | } 103 | 104 | if nodes[i].value == value { 105 | return nodes[i], i 106 | } 107 | 108 | return nil, i 109 | } 110 | 111 | func (nodes *orderedNodes) getOrAdd(entry Entry, 112 | dimension, lastDimension uint64) (*node, bool) { 113 | 114 | isLastDimension := isLastDimension(lastDimension, dimension) 115 | value := entry.ValueAtDimension(dimension) 116 | 117 | i := nodes.search(value) 118 | if i == len(*nodes) { 119 | node := newNode(value, entry, !isLastDimension) 120 | *nodes = append(*nodes, node) 121 | return node, true 122 | } 123 | 124 | if (*nodes)[i].value == value { 125 | return (*nodes)[i], false 126 | } 127 | 128 | node := newNode(value, entry, !isLastDimension) 129 | *nodes = append(*nodes, nil) 130 | copy((*nodes)[i+1:], (*nodes)[i:]) 131 | (*nodes)[i] = node 132 | return node, true 133 | } 134 | 135 | func (nodes orderedNodes) flatten(entries *Entries) { 136 | for _, node := range nodes { 137 | if node.orderedNodes != nil { 138 | node.orderedNodes.flatten(entries) 139 | } else { 140 | *entries = append(*entries, node.entry) 141 | } 142 | } 143 | } 144 | 145 | func (nodes *orderedNodes) insert(insertDimension, dimension, maxDimension uint64, 146 | index, number int64, modified, deleted *Entries) { 147 | 148 | lastDimension := isLastDimension(maxDimension, dimension) 149 | 150 | if insertDimension == dimension { 151 | i := nodes.search(index) 152 | var toDelete []int 153 | 154 | for j := i; j < len(*nodes); j++ { 155 | (*nodes)[j].value += number 156 | if (*nodes)[j].value < index { 157 | toDelete = append(toDelete, j) 158 | if lastDimension { 159 | *deleted = append(*deleted, (*nodes)[j].entry) 160 | } else { 161 | (*nodes)[j].orderedNodes.flatten(deleted) 162 | } 163 | continue 164 | } 165 | if lastDimension { 166 | *modified = append(*modified, (*nodes)[j].entry) 167 | } else { 168 | (*nodes)[j].orderedNodes.flatten(modified) 169 | } 170 | } 171 | 172 | for i, index := range toDelete { 173 | nodes.deleteAt(index - i) 174 | } 175 | 176 | return 177 | } 178 | 179 | for _, node := range *nodes { 180 | node.orderedNodes.insert( 181 | insertDimension, dimension+1, maxDimension, 182 | index, number, modified, deleted, 183 | ) 184 | } 185 | } 186 | 187 | func (nodes orderedNodes) immutableInsert(insertDimension, dimension, maxDimension uint64, 188 | index, number int64, modified, deleted *Entries) orderedNodes { 189 | 190 | lastDimension := isLastDimension(maxDimension, dimension) 191 | 192 | cp := make(orderedNodes, len(nodes)) 193 | copy(cp, nodes) 194 | 195 | if insertDimension == dimension { 196 | i := cp.search(index) 197 | var toDelete []int 198 | 199 | for j := i; j < len(cp); j++ { 200 | nn := newNode(cp[j].value+number, cp[j].entry, !lastDimension) 201 | nn.orderedNodes = cp[j].orderedNodes 202 | cp[j] = nn 203 | if cp[j].value < index { 204 | toDelete = append(toDelete, j) 205 | if lastDimension { 206 | *deleted = append(*deleted, cp[j].entry) 207 | } else { 208 | cp[j].orderedNodes.flatten(deleted) 209 | } 210 | continue 211 | } 212 | if lastDimension { 213 | *modified = append(*modified, cp[j].entry) 214 | } else { 215 | cp[j].orderedNodes.flatten(modified) 216 | } 217 | } 218 | 219 | for _, index := range toDelete { 220 | cp.deleteAt(index) 221 | } 222 | 223 | return cp 224 | } 225 | 226 | for i := 0; i < len(cp); i++ { 227 | oldNode := nodes[i] 228 | nn := newNode(oldNode.value, oldNode.entry, !lastDimension) 229 | nn.orderedNodes = oldNode.orderedNodes.immutableInsert( 230 | insertDimension, dimension+1, 231 | maxDimension, 232 | index, number, 233 | modified, deleted, 234 | ) 235 | cp[i] = nn 236 | } 237 | 238 | return cp 239 | } 240 | --------------------------------------------------------------------------------