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 }