@@ -95,45 +95,51 @@ void Hll8Array<A>::mergeList(const CouponList<A>& src) {
9595template <typename A>
9696void Hll8Array<A>::mergeHll(const HllArray<A>& src) {
9797 // at this point src_k >= dst_k
98- const uint32_t src_k = 1 << src.getLgConfigK ();
9998 const uint32_t dst_mask = (1 << this ->getLgConfigK ()) - 1 ;
100- // duplication below is to avoid a virtual method call in a loop
99+ // special treatment below to optimize performance
101100 if (src.getTgtHllType () == target_hll_type::HLL_8 ) {
102- for (uint32_t i = 0 ; i < src_k; i++) {
103- const uint8_t new_v = static_cast <const Hll8Array<A>&>(src).getSlot (i);
104- const uint32_t j = i & dst_mask;
105- const uint8_t old_v = this ->hllByteArr_ [j];
106- if (new_v > old_v) {
107- this ->hllByteArr_ [j] = new_v;
108- this ->hipAndKxQIncrementalUpdate (old_v, new_v);
109- this ->numAtCurMin_ -= old_v == 0 ;
110- }
101+ uint32_t i = 0 ;
102+ for (const auto value: src.getHllArray ()) {
103+ processValue (i++, dst_mask, value);
111104 }
112105 } else if (src.getTgtHllType () == target_hll_type::HLL_6 ) {
113- for (uint32_t i = 0 ; i < src_k; i++) {
114- const uint8_t new_v = static_cast <const Hll6Array<A>&>(src).getSlot (i);
115- const uint32_t j = i & dst_mask;
116- const uint8_t old_v = this ->hllByteArr_ [j];
117- if (new_v > old_v) {
118- this ->hllByteArr_ [j] = new_v;
119- this ->hipAndKxQIncrementalUpdate (old_v, new_v);
120- this ->numAtCurMin_ -= old_v == 0 ;
121- }
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);
122120 }
123121 } else { // HLL_4
124- for (uint32_t i = 0 ; i < src_k; i++) {
125- const uint8_t new_v = static_cast <const Hll4Array<A>&>(src).get_value (i);
126- const uint32_t j = i & dst_mask;
127- const uint8_t old_v = this ->hllByteArr_ [j];
128- if (new_v > old_v) {
129- this ->hllByteArr_ [j] = new_v;
130- this ->hipAndKxQIncrementalUpdate (old_v, new_v);
131- this ->numAtCurMin_ -= old_v == 0 ;
132- }
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;
133129 }
134130 }
135131}
136132
133+ template <typename A>
134+ void 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+ }
141+ }
142+
137143}
138144
139145#endif // _HLL8ARRAY_INTERNAL_HPP_
0 commit comments