summaryrefslogtreecommitdiff
path: root/txnsync/bitmask.go
diff options
context:
space:
mode:
Diffstat (limited to 'txnsync/bitmask.go')
-rw-r--r--txnsync/bitmask.go250
1 files changed, 0 insertions, 250 deletions
diff --git a/txnsync/bitmask.go b/txnsync/bitmask.go
deleted file mode 100644
index 6990fc1d7..000000000
--- a/txnsync/bitmask.go
+++ /dev/null
@@ -1,250 +0,0 @@
-// Copyright (C) 2019-2021 Algorand, Inc.
-// This file is part of go-algorand
-//
-// go-algorand is free software: you can redistribute it and/or modify
-// it under the terms of the GNU Affero General Public License as
-// published by the Free Software Foundation, either version 3 of the
-// License, or (at your option) any later version.
-//
-// go-algorand is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU Affero General Public License for more details.
-//
-// You should have received a copy of the GNU Affero General Public License
-// along with go-algorand. If not, see <https://www.gnu.org/licenses/>.
-
-package txnsync
-
-import (
- "errors"
-)
-
-var errIndexNotFound = errors.New("invalid bitmask: index not found")
-var errInvalidBitmaskType = errors.New("invalid bitmask type")
-
-//msgp:allocbound bitmask maxBitmaskSize
-type bitmask []byte
-
-// assumed to be in mode 0, sets bit at index to 1
-func (b *bitmask) setBit(index int) {
- // bitmask type is stored at index 0, so the rest of the data is stored after.
- byteIndex := index/8 + 1
- (*b)[byteIndex] |= 1 << (index % 8)
-}
-
-// trimBitmask compresses the bitmask into one of the 4 types:
-// type 0: input bitmask bit pos x b -> output bitmask bit pos x b
-// type 1: input bitmask bit pos x b -> output bitmask bit pos x !b
-// type 2: stores the positions of bits where the bit value is 1
-// input bitmask first bit 1 at pos A, second bit 1 at pos B, ...
-// output bitmask stores A, B-A, ...
-// type 3: same as type 2, but stores the positons where the bit is 0
-func (b *bitmask) trimBitmask(entries int) {
- if *b == nil {
- return
- }
- numBitsCase0 := 0
- numBitsCase1 := 0
- numExists := 0
- for i := 0; i < entries; i++ {
- byteIndex := i/8 + 1
- if (*b)[byteIndex]&(1<<(i%8)) != 0 {
- numBitsCase0 = i + 1
- numExists++
- } else {
- numBitsCase1 = i + 1
- }
- }
- bitmaskType := 0
- bestSize := bytesNeededBitmask(numBitsCase0)
- if bestSize > bytesNeededBitmask(numBitsCase1) {
- bitmaskType = 1
- bestSize = bytesNeededBitmask(numBitsCase1)
- }
- if bestSize > numExists*2+1 {
- bitmaskType = 2
- bestSize = numExists*2 + 1
- }
- if bestSize > (entries-numExists)*2+1 {
- bitmaskType = 3
- bestSize = (entries-numExists)*2 + 1
- }
- switch bitmaskType {
- case 0:
- *b = (*b)[:bestSize]
- case 1:
- (*b)[0] = 1
- for i := range *b {
- if i != 0 {
- (*b)[i] = 255 - (*b)[i] // invert bits
- }
- }
- *b = (*b)[:bestSize]
- case 2:
- newBitmask := make(bitmask, 1, bestSize)
- newBitmask[0] = 2
- last := 0
- for i := 0; i < entries; i++ {
- byteIndex := i/8 + 1
- if (*b)[byteIndex]&(1<<(i%8)) != 0 {
- diff := i - last
- newBitmask = append(newBitmask, byte(diff/256), byte(diff%256))
- last = i
- }
- }
- *b = newBitmask
- case 3:
- newBitmask := make(bitmask, 1, bestSize)
- newBitmask[0] = 3
- last := 0
- for i := 0; i < entries; i++ {
- byteIndex := i/8 + 1
- if (*b)[byteIndex]&(1<<(i%8)) == 0 {
- diff := i - last
- newBitmask = append(newBitmask, byte(diff/256), byte(diff%256))
- last = i
- }
- }
- *b = newBitmask
- }
-}
-
-// iterate through the elements of bitmask without expanding it.
-// call the func(entriesCount, setBitIndex) for every set bit
-// numTransactions: is the size of the array that transactionIndex is accessing: transactionIndex < numTransactions
-// numItems: is the size of the array that itemIndex is accessing: itemIndex < numItems (itemIndex is also the set bit counter)
-func (b *bitmask) iterate(numTransactions int, numItems int, callback func(int, int) error) error {
- option := 0
- if len(*b) > 0 {
- option = int((*b)[0])
- } else { // nothing to iterate
- return nil
- }
- itemIndex := 0
- switch option {
- case 0:
- transactionIndex := 0
- maxV := bytesNeededBitmask(numTransactions)
- if len(*b) > maxV {
- return errIndexNotFound
- }
- for i, v := range (*b)[1:] {
- for ; transactionIndex < numTransactions && v > 0; transactionIndex++ {
- if v&1 != 0 {
- if itemIndex >= numItems {
- return errDataMissing
- }
- if err := callback(transactionIndex, itemIndex); err != nil {
- return err
- }
- itemIndex++
- }
- v >>= 1
- }
- if v > 0 {
- // remaining set bits, but transactionIndex exceeded numTransactions
- return errIndexNotFound
- }
- // in case the loop is cut short because there are no more set bits in the byte
- transactionIndex = (i + 1) * 8
- }
- case 1:
- transactionIndex := 0
- maxV := bytesNeededBitmask(numTransactions)
- if len(*b) > maxV {
- return errIndexNotFound
- }
- for _, v := range (*b)[1:] {
- // after the first iteration of the loop below, v will be less than 255
- if v >= 255 {
- transactionIndex += 8
- continue
- }
- maxJ := 8
- if maxJ > numTransactions-transactionIndex {
- maxJ = numTransactions - transactionIndex
- }
- for j := 0; j < maxJ; j++ {
- if v&1 == 0 {
- if itemIndex >= numItems {
- return errDataMissing
- }
- if err := callback(transactionIndex, itemIndex); err != nil {
- return err
- }
- itemIndex++
- }
- v >>= 1
- transactionIndex++
- }
- if 255>>maxJ != v {
- // The remaining of the bits must be 1
- return errIndexNotFound
- }
- }
- if numTransactions-transactionIndex > numItems-itemIndex {
- return errDataMissing
- }
- for ; transactionIndex < numTransactions; transactionIndex++ {
- if err := callback(transactionIndex, itemIndex); err != nil {
- return err
- }
- itemIndex++
- }
- case 2:
- sum := 0 // transactionIndex
- elementsCount := (len(*b) - 1) / 2
- if elementsCount > numItems {
- return errDataMissing
- }
- for itemIndex := 0; itemIndex < elementsCount; itemIndex++ {
- sum += int((*b)[itemIndex*2+1])*256 + int((*b)[itemIndex*2+2])
- if sum >= numTransactions {
- return errIndexNotFound
- }
- if err := callback(sum, itemIndex); err != nil {
- return err
- }
- }
- case 3:
- sum := 0
- // This is the least amount of elements can be set.
- // There could be more, if the numbers are corrupted
- // i.e. when sum >= numTransactions
- elementsCount := numTransactions - (len(*b)-1)/2
- if elementsCount > numItems || elementsCount < 0 {
- return errDataMissing
- }
- transactionIndex := 0
- for i := 0; i*2+2 < len(*b); i++ {
- sum += int((*b)[i*2+1])*256 + int((*b)[i*2+2])
- if sum >= numTransactions {
- return errIndexNotFound
- }
- for transactionIndex < sum {
- if err := callback(transactionIndex, itemIndex); err != nil {
- return err
- }
- transactionIndex++
- itemIndex++
- }
- transactionIndex++
- }
- for transactionIndex < numTransactions {
- if err := callback(transactionIndex, itemIndex); err != nil {
- return err
- }
- transactionIndex++
- itemIndex++
- }
- default:
- return errInvalidBitmaskType
- }
- return nil
-}
-
-// bytesNeededBitmask returns the number of bytes needed to store entries bits.
-func bytesNeededBitmask(entries int) int {
- return (entries+7)/8 + 1
-}