/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 |