Initial
This commit is contained in:
125
internal/statuslist/list.go
Normal file
125
internal/statuslist/list.go
Normal file
@@ -0,0 +1,125 @@
|
||||
package statuslist
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrIndexOutOfRange = errors.New("index out of range")
|
||||
)
|
||||
|
||||
type StatusList struct {
|
||||
data []byte
|
||||
bitLength int
|
||||
}
|
||||
|
||||
// New vrne prazno bitno listo statusov.
|
||||
func New() *StatusList {
|
||||
return &StatusList{
|
||||
data: make([]byte, 0),
|
||||
bitLength: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// IzSurovihPodatkov zgradi listo iz bajtov in dolzine v bitih.
|
||||
func IzSurovihPodatkov(data []byte, bitLength int) (*StatusList, error) {
|
||||
if bitLength < 0 {
|
||||
return nil, errors.New("bitLength must be >= 0")
|
||||
}
|
||||
minBytes := steviloBajtovZaBite(bitLength)
|
||||
if len(data) < minBytes {
|
||||
return nil, errors.New("invalid data size for bitLength")
|
||||
}
|
||||
|
||||
cloned := make([]byte, minBytes)
|
||||
copy(cloned, data[:minBytes])
|
||||
return &StatusList{data: cloned, bitLength: bitLength}, nil
|
||||
}
|
||||
|
||||
// Dodaj doda novo stanje in vrne njegov index.
|
||||
func (s *StatusList) Dodaj(value bool) int {
|
||||
index := s.bitLength
|
||||
s.zagotoviIndex(index)
|
||||
s.nastaviBit(index, value)
|
||||
s.bitLength++
|
||||
return index
|
||||
}
|
||||
|
||||
// Nastavi spremeni obstojece stanje na podanem indexu.
|
||||
func (s *StatusList) Nastavi(index int, value bool) error {
|
||||
if index < 0 || index >= s.bitLength {
|
||||
return ErrIndexOutOfRange
|
||||
}
|
||||
s.nastaviBit(index, value)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Dobi vrne stanje na podanem indexu.
|
||||
func (s *StatusList) Dobi(index int) (bool, error) {
|
||||
if index < 0 || index >= s.bitLength {
|
||||
return false, ErrIndexOutOfRange
|
||||
}
|
||||
return s.dobiBit(index), nil
|
||||
}
|
||||
|
||||
// DolzinaBitov vrne stevilo aktivnih statusov.
|
||||
func (s *StatusList) DolzinaBitov() int {
|
||||
return s.bitLength
|
||||
}
|
||||
|
||||
// Bajti vrne kopijo notranjih bajtov liste.
|
||||
func (s *StatusList) Bajti() []byte {
|
||||
out := make([]byte, len(s.data))
|
||||
copy(out, s.data)
|
||||
return out
|
||||
}
|
||||
|
||||
// KodiranSeznam vrne base64(gzip(byteArray)) predstavitev liste.
|
||||
func (s *StatusList) KodiranSeznam() (string, error) {
|
||||
var buf bytes.Buffer
|
||||
zip := gzip.NewWriter(&buf)
|
||||
if _, err := zip.Write(s.data); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if err := zip.Close(); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.StdEncoding.EncodeToString(buf.Bytes()), nil
|
||||
}
|
||||
|
||||
// zagotoviIndex razsiri notranji buffer za podani index.
|
||||
func (s *StatusList) zagotoviIndex(index int) {
|
||||
required := steviloBajtovZaBite(index + 1)
|
||||
for len(s.data) < required {
|
||||
s.data = append(s.data, 0)
|
||||
}
|
||||
}
|
||||
|
||||
// nastaviBit vklopi ali izklopi bit na podanem indexu.
|
||||
func (s *StatusList) nastaviBit(index int, value bool) {
|
||||
byteIdx := index / 8
|
||||
mask := byte(1 << (index % 8))
|
||||
if value {
|
||||
s.data[byteIdx] |= mask
|
||||
return
|
||||
}
|
||||
s.data[byteIdx] &^= mask
|
||||
}
|
||||
|
||||
// dobiBit prebere bit na podanem indexu.
|
||||
func (s *StatusList) dobiBit(index int) bool {
|
||||
byteIdx := index / 8
|
||||
mask := byte(1 << (index % 8))
|
||||
return s.data[byteIdx]&mask != 0
|
||||
}
|
||||
|
||||
// steviloBajtovZaBite izracuna koliko bajtov potrebujemo za bite.
|
||||
func steviloBajtovZaBite(bitLength int) int {
|
||||
if bitLength == 0 {
|
||||
return 0
|
||||
}
|
||||
return (bitLength + 7) / 8
|
||||
}
|
||||
Reference in New Issue
Block a user