Coverage Report

Created: 2026-08-14 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/zeek/src/probabilistic/CounterVector.cc
Line
Count
Source
1
// See the file "COPYING" in the main distribution directory for copyright.
2
3
#include "zeek/probabilistic/CounterVector.h"
4
5
#include <cassert>
6
#include <limits>
7
#include <memory>
8
9
#include "zeek/broker/Data.h"
10
#include "zeek/probabilistic/BitVector.h"
11
12
namespace zeek::probabilistic::detail {
13
14
0
CounterVector::CounterVector(size_t arg_width, size_t cells) {
15
0
    bits = new BitVector(arg_width * cells);
16
0
    width = arg_width;
17
0
}
18
19
0
CounterVector::CounterVector(const CounterVector& other) {
20
0
    bits = new BitVector(*other.bits);
21
0
    width = other.width;
22
0
}
23
24
0
CounterVector::~CounterVector() { delete bits; }
25
26
0
bool CounterVector::Increment(size_type cell, count_type value) {
27
0
    assert(cell < Size());
28
0
    assert(value != 0);
29
30
0
    size_t lsb = cell * width;
31
0
    bool carry = false;
32
33
0
    for ( size_t i = 0; i < width; ++i ) {
34
0
        bool b1 = (*bits)[lsb + i];
35
0
        bool b2 = value & (1 << i);
36
0
        (*bits)[lsb + i] = b1 ^ b2 ^ carry;
37
0
        carry = (b1 && b2) || (carry && (b1 != b2));
38
0
    }
39
40
0
    if ( carry ) {
41
0
        for ( size_t i = 0; i < width; ++i )
42
0
            bits->Set(lsb + i);
43
0
    }
44
45
0
    return ! carry;
46
0
}
47
48
0
bool CounterVector::Decrement(size_type cell, count_type value) {
49
0
    assert(cell < Size());
50
0
    assert(value != 0);
51
52
0
    value = ~value + 1; // A - B := A + ~B + 1
53
0
    bool carry = false;
54
0
    size_t lsb = cell * width;
55
56
0
    for ( size_t i = 0; i < width; ++i ) {
57
0
        bool b1 = (*bits)[lsb + i];
58
0
        bool b2 = value & (1 << i);
59
0
        (*bits)[lsb + i] = b1 ^ b2 ^ carry;
60
0
        carry = (b1 && b2) || (carry && (b1 != b2));
61
0
    }
62
63
0
    return carry;
64
0
}
65
66
0
bool CounterVector::AllZero() const { return bits->AllZero(); }
67
68
0
void CounterVector::Reset() { bits->Reset(); }
69
70
0
CounterVector::count_type CounterVector::Count(size_type cell) const {
71
0
    assert(cell < Size());
72
73
0
    size_t cnt = 0;
74
0
    size_t order = 1;
75
0
    size_t lsb = cell * width;
76
77
0
    for ( size_t i = lsb; i < lsb + width; ++i, order <<= 1 )
78
0
        if ( (*bits)[i] )
79
0
            cnt |= order;
80
81
0
    return cnt;
82
0
}
83
84
0
CounterVector::size_type CounterVector::Size() const { return bits->Size() / width; }
85
86
0
size_t CounterVector::Width() const { return width; }
87
88
0
size_t CounterVector::Max() const {
89
0
    return std::numeric_limits<size_t>::max() >> (std::numeric_limits<size_t>::digits - width);
90
0
}
91
92
0
CounterVector& CounterVector::Merge(const CounterVector& other) {
93
0
    assert(Size() == other.Size());
94
0
    assert(Width() == other.Width());
95
96
0
    for ( size_t cell = 0; cell < Size(); ++cell ) {
97
0
        size_t lsb = cell * width;
98
0
        bool carry = false;
99
100
0
        for ( size_t i = 0; i < width; ++i ) {
101
0
            bool b1 = (*bits)[lsb + i];
102
0
            bool b2 = (*other.bits)[lsb + i];
103
0
            (*bits)[lsb + i] = b1 ^ b2 ^ carry;
104
0
            carry = (b1 && b2) || (carry && (b1 != b2));
105
0
        }
106
107
0
        if ( carry ) {
108
0
            for ( size_t i = 0; i < width; ++i )
109
0
                bits->Set(lsb + i);
110
0
        }
111
0
    }
112
113
0
    return *this;
114
0
}
115
116
0
BitVector CounterVector::ToBitVector() const {
117
0
    auto newbits = BitVector(Size());
118
119
0
    for ( size_t cell = 0; cell < Size(); ++cell ) {
120
0
        size_t lsb = cell * width;
121
0
        bool set = false;
122
123
0
        for ( size_t i = 0; i < width; ++i )
124
0
            set |= (*bits)[lsb + 1];
125
126
0
        newbits[cell] = set;
127
0
    }
128
129
0
    return newbits;
130
0
}
131
132
0
CounterVector& CounterVector::operator|=(const CounterVector& other) { return Merge(other); }
133
134
0
CounterVector operator|(const CounterVector& x, const CounterVector& y) {
135
0
    CounterVector cv(x);
136
0
    return cv |= y;
137
0
}
138
139
0
uint64_t CounterVector::Hash() const { return bits->Hash(); }
140
141
0
std::optional<BrokerData> CounterVector::Serialize() const {
142
0
    auto b = bits->Serialize();
143
0
    if ( ! b )
144
0
        return std::nullopt; // Cannot serialize
145
146
0
    BrokerListBuilder builder;
147
0
    builder.Reserve(2);
148
0
    builder.AddCount(width);
149
0
    builder.Add(std::move(*b));
150
0
    return std::move(builder).Build();
151
0
}
152
153
0
std::unique_ptr<CounterVector> CounterVector::Unserialize(BrokerDataView data) {
154
0
    if ( ! data.IsList() )
155
0
        return nullptr;
156
157
0
    auto v = data.ToList();
158
0
    if ( v.Size() < 2 || ! v[0].IsCount() )
159
0
        return nullptr;
160
161
0
    auto width = v[0].ToCount();
162
0
    auto bits = BitVector::Unserialize(v[1]);
163
164
0
    if ( ! bits )
165
0
        return nullptr;
166
167
0
    auto cv = std::unique_ptr<CounterVector>{new CounterVector};
168
0
    cv->width = width;
169
0
    cv->bits = bits.release();
170
0
    return cv;
171
0
}
172
173
} // namespace zeek::probabilistic::detail