@@ -32,6 +32,25 @@ HllArray<A>(lgConfigK, target_hll_type::HLL_8, startFullSize, allocator)
3232 this ->hllByteArr_ .resize (numBytes, 0 );
3333}
3434
35+ template <typename A>
36+ Hll8Array<A>::Hll8Array(const HllArray<A>& other):
37+ HllArray<A>(other.getLgConfigK(), target_hll_type::HLL_8 , other.isStartFullSize(), other.getAllocator())
38+ {
39+ const int numBytes = this ->hll8ArrBytes (this ->lgConfigK_ );
40+ this ->hllByteArr_ .resize (numBytes, 0 );
41+ this ->oooFlag_ = other.isOutOfOrderFlag ();
42+ uint32_t num_zeros = 1 << this ->lgConfigK_ ;
43+
44+ for (const auto coupon : other) { // all = false, so skip empty values
45+ num_zeros--;
46+ internalCouponUpdate (coupon); // updates KxQ registers
47+ }
48+
49+ this ->numAtCurMin_ = num_zeros;
50+ this ->hipAccum_ = other.getHipAccum ();
51+ this ->rebuild_kxq_curmin_ = false ;
52+ }
53+
3554template <typename A>
3655std::function<void (HllSketchImpl<A>*)> Hll8Array<A>::get_deleter() const {
3756 return [](HllSketchImpl<A>* ptr) {
@@ -95,49 +114,88 @@ void Hll8Array<A>::mergeList(const CouponList<A>& src) {
95114template <typename A>
96115void Hll8Array<A>::mergeHll(const HllArray<A>& src) {
97116 // at this point src_k >= dst_k
98- const uint32_t dst_mask = (1 << this ->getLgConfigK ()) - 1 ;
99- // special treatment below to optimize performance
100- if (src.getTgtHllType () == target_hll_type::HLL_8 ) {
101- uint32_t i = 0 ;
102- for (const auto value: src.getHllArray ()) {
103- processValue (i++, dst_mask, value);
104- }
105- } else if (src.getTgtHllType () == target_hll_type::HLL_6 ) {
106- const uint32_t src_k = 1 << src.getLgConfigK ();
107- uint32_t i = 0 ;
108- const uint8_t * ptr = src.getHllArray ().data ();
109- while (i < src_k) {
110- uint8_t value = *ptr & 0x3f ;
111- processValue (i++, dst_mask, value);
112- value = *ptr++ >> 6 ;
113- value |= (*ptr & 0x0f ) << 2 ;
114- processValue (i++, dst_mask, value);
115- value = *ptr++ >> 4 ;
116- value |= (*ptr & 3 ) << 4 ;
117- processValue (i++, dst_mask, value);
118- value = *ptr++ >> 2 ;
119- processValue (i++, dst_mask, value);
117+ // we can optimize further when the k values are equal
118+ if (this ->getLgConfigK () == src.getLgConfigK ()) {
119+ if (src.getTgtHllType () == target_hll_type::HLL_8 ) {
120+ uint32_t i = 0 ;
121+ for (const auto value: src.getHllArray ()) {
122+ this ->hllByteArr_ [i] = std::max (this ->hllByteArr_ [i], value);
123+ ++i;
124+ }
125+ } else if (src.getTgtHllType () == target_hll_type::HLL_6 ) {
126+ const uint32_t src_k = 1 << src.getLgConfigK ();
127+ uint32_t i = 0 ;
128+ const uint8_t * ptr = src.getHllArray ().data ();
129+ while (i < src_k) {
130+ uint8_t value = *ptr & 0x3f ;
131+ this ->hllByteArr_ [i] = std::max (this ->hllByteArr_ [i], value);
132+ ++i;
133+ value = *ptr++ >> 6 ;
134+ value |= (*ptr & 0x0f ) << 2 ;
135+ this ->hllByteArr_ [i] = std::max (this ->hllByteArr_ [i], value);
136+ ++i;
137+ value = *ptr++ >> 4 ;
138+ value |= (*ptr & 3 ) << 4 ;
139+ this ->hllByteArr_ [i] = std::max (this ->hllByteArr_ [i], value);
140+ ++i;
141+ value = *ptr++ >> 2 ;
142+ this ->hllByteArr_ [i] = std::max (this ->hllByteArr_ [i], value);
143+ ++i;
144+ }
145+ } else { // HLL_4
146+ const auto & src4 = static_cast <const Hll4Array<A>&>(src);
147+ uint32_t i = 0 ;
148+ for (const auto byte: src.getHllArray ()) {
149+ this ->hllByteArr_ [i] = std::max (this ->hllByteArr_ [i], src4.adjustRawValue (i, byte & hll_constants::loNibbleMask));
150+ ++i;
151+ this ->hllByteArr_ [i] = std::max (this ->hllByteArr_ [i], src4.adjustRawValue (i, byte >> 4 ));
152+ ++i;
153+ }
120154 }
121- } else { // HLL_4
122- const auto & src4 = static_cast <const Hll4Array<A>&>(src);
123- uint32_t i = 0 ;
124- for (const auto byte: src.getHllArray ()) {
125- processValue (i, dst_mask, src4.adjustRawValue (i, byte & hll_constants::loNibbleMask));
126- ++i;
127- processValue (i, dst_mask, src4.adjustRawValue (i, byte >> 4 ));
128- ++i;
155+ } else {
156+ // src_k > dst_k
157+ const uint32_t dst_mask = (1 << this ->getLgConfigK ()) - 1 ;
158+ // special treatment below to optimize performance
159+ if (src.getTgtHllType () == target_hll_type::HLL_8 ) {
160+ uint32_t i = 0 ;
161+ for (const auto value: src.getHllArray ()) {
162+ processValue (i++, dst_mask, value);
163+ }
164+ } else if (src.getTgtHllType () == target_hll_type::HLL_6 ) {
165+ const uint32_t src_k = 1 << src.getLgConfigK ();
166+ uint32_t i = 0 ;
167+ const uint8_t * ptr = src.getHllArray ().data ();
168+ while (i < src_k) {
169+ uint8_t value = *ptr & 0x3f ;
170+ processValue (i++, dst_mask, value);
171+ value = *ptr++ >> 6 ;
172+ value |= (*ptr & 0x0f ) << 2 ;
173+ processValue (i++, dst_mask, value);
174+ value = *ptr++ >> 4 ;
175+ value |= (*ptr & 3 ) << 4 ;
176+ processValue (i++, dst_mask, value);
177+ value = *ptr++ >> 2 ;
178+ processValue (i++, dst_mask, value);
179+ }
180+ } else { // HLL_4
181+ const auto & src4 = static_cast <const Hll4Array<A>&>(src);
182+ uint32_t i = 0 ;
183+ for (const auto byte: src.getHllArray ()) {
184+ processValue (i, dst_mask, src4.adjustRawValue (i, byte & hll_constants::loNibbleMask));
185+ ++i;
186+ processValue (i, dst_mask, src4.adjustRawValue (i, byte >> 4 ));
187+ ++i;
188+ }
129189 }
130190 }
191+ this ->setRebuildKxqCurminFlag (true );
131192}
132193
194+
133195template <typename A>
134196void Hll8Array<A>::processValue(uint32_t slot, uint32_t mask, uint8_t new_val) {
135- const uint8_t old_val = this ->hllByteArr_ [slot & mask];
136- if (new_val > old_val) {
137- this ->hllByteArr_ [slot & mask] = new_val;
138- this ->hipAndKxQIncrementalUpdate (old_val, new_val);
139- this ->numAtCurMin_ -= old_val == 0 ;
140- }
197+ const size_t index = slot & mask;
198+ this ->hllByteArr_ [index] = std::max (this ->hllByteArr_ [index], new_val);
141199}
142200
143201}
0 commit comments