Как реализовать BitSet с Go?

Я не нашел пакет BitSet в Go, поэтому я попытался его реализовать. Я бы хотел использовать массив uint64 для хранения бит.

Мне нужно количество бит для выделения массива uint64. С помощью Java я могу определить конструктор, который принимает целое число. Хотя Go не предоставляет конструктор, как я могу правильно инициализировать объект BitSet ', когда пользователь вызывает new()?

Ответ 1

Объявить bitSet как частную структуру:

type bitSet struct {
  len int
  array []uint64
}

Открыть интерфейс BitSet:

type BitSet interface {
  Has(pos int) bool
  Add(pos int) bool
  Len() int
}

Также выставляем функцию NewBitSet:

func NewBitSet(len int) BitSet {
  return &bitSet{len, make(uint64, (len+7) / 8) }
}

Это путь для инкапсуляции: обменивайтесь интерфейсом, а не реализацией.

Ответ 2

Если вы используете кусочек [] uint64 для хранения ваших данных, нулевой срез может работать как пустой битсет. Фактически, добавление к nil-фрагменту выделяет вам новый массив, хотя языковая спецификация не гарантирует этого. При такой настройке новый (BitSet) будет немедленно использоваться. Пример:

bitset.go:

package bitset

const size = 64

type bits uint64

// BitSet is a set of bits that can be set, cleared and queried.
type BitSet []bits

// Set ensures that the given bit is set in the BitSet.
func (s *BitSet) Set(i uint) {
    if len(*s) < int(i/size+1) {
        r := make([]bits, i/size+1)
        copy(r, *s)
        *s = r
    }
    (*s)[i/size] |= 1 << (i % size)
}

// Clear ensures that the given bit is cleared (not set) in the BitSet.
func (s *BitSet) Clear(i uint) {
    if len(*s) >= int(i/size+1) {
        (*s)[i/size] &^= 1 << (i % size)
    }
}

// IsSet returns true if the given bit is set, false if it is cleared.
func (s *BitSet) IsSet(i uint) bool {
    return (*s)[i/size]&(1<<(i%size)) != 0
}

bitset_test.go:

package bitset

import "fmt"

func ExampleBitSet() {
    s := new(BitSet)
    s.Set(13)
    s.Set(45)
    s.Clear(13)
    fmt.Printf("s.IsSet(13) = %t; s.IsSet(45) = %t; s.IsSet(30) = %t\n",
               s.IsSet(13), s.IsSet(45), s.IsSet(30))
    // Output: s.IsSet(13) = false; s.IsSet(45) = true; s.IsSet(30) = false
}

Ответ 3

Короткий ответ: вы не можете правильно инициализировать объект BitSet, когда клиент вызывает new().

Лучшее, что вы можете сделать, это сделать так, чтобы ваше нулевое значение BitSet было допустимым. Это типы типа list.List, sync.Mutex и big.Int do. Таким образом, вы знаете, что для клиента невозможно получить недопустимое значение.

Следующее лучшее, что вы можете сделать, это создать функцию, похожую на constuctor (названную NewBitSet в этом случае) и ожидать, что клиенты ее назовут.

Ответ 4

Go стандартный big.Int может быть использован в качестве набора битов:

package main

import (
    "fmt"
    "math/big"
)

func main() {
    var bits big.Int
    for i := 1000; i < 2000; i++ {
        bits.SetBit(&bits, i, 1)
    }
    for i := 0; i < 10000; i++ {
        if bits.Bit(i) != 0 {
            fmt.Println(i)
        }
    }
}

https://play.golang.org/p/xbIK-boouqC