@@ -43,20 +43,42 @@ kxq1_(0.0),
4343hllByteArr_(allocator),
4444curMin_(0 ),
4545numAtCurMin_(1 << lgConfigK),
46- oooFlag_(false )
46+ oooFlag_(false ),
47+ rebuild_kxq_curmin_(false )
48+ {}
49+
50+ template <typename A>
51+ HllArray<A>::HllArray(const HllArray& other, target_hll_type tgtHllType) :
52+ HllSketchImpl<A>(other.getLgConfigK(), tgtHllType, hll_mode::HLL , other.isStartFullSize()),
53+ // remaining fields are initialized to empty sketch defaults
54+ // and left to subclass constructor to populate
55+ hipAccum_ (0.0 ),
56+ kxq0_(1 << other.getLgConfigK()),
57+ kxq1_(0.0 ),
58+ hllByteArr_(other.getAllocator()),
59+ curMin_(0 ),
60+ numAtCurMin_(1 << other.getLgConfigK()),
61+ oooFlag_(false ),
62+ rebuild_kxq_curmin_(false )
4763{}
4864
4965template <typename A>
5066HllArray<A>* HllArray<A>::copyAs(target_hll_type tgtHllType) const {
51- if (tgtHllType == this ->getTgtHllType ()) {
67+ // we may need to recompute KxQ and curMin data for a union gadget,
68+ // so only use a direct copy if we have a valid sketch
69+ if (tgtHllType == this ->getTgtHllType () && !this ->isRebuildKxqCurminFlag ()) {
5270 return static_cast <HllArray*>(copy ());
5371 }
54- if (tgtHllType == target_hll_type::HLL_4 ) {
55- return HllSketchImplFactory<A>::convertToHll4 (*this );
56- } else if (tgtHllType == target_hll_type::HLL_6 ) {
57- return HllSketchImplFactory<A>::convertToHll6 (*this );
58- } else { // tgtHllType == HLL_8
59- return HllSketchImplFactory<A>::convertToHll8 (*this );
72+
73+ // the factory methods replay the coupons and will always rebuild
74+ // the sketch in a consistent way
75+ switch (tgtHllType) {
76+ case target_hll_type::HLL_4 :
77+ return HllSketchImplFactory<A>::convertToHll4 (*this );
78+ case target_hll_type::HLL_6 :
79+ return HllSketchImplFactory<A>::convertToHll6 (*this );
80+ case target_hll_type::HLL_8 :
81+ return HllSketchImplFactory<A>::convertToHll8 (*this );
6082 }
6183}
6284
@@ -562,6 +584,16 @@ double HllArray<A>::getHllRawEstimate() const {
562584 return hyperEst;
563585}
564586
587+ template <typename A>
588+ void HllArray<A>::setRebuildKxqCurminFlag(bool rebuild) {
589+ rebuild_kxq_curmin_ = rebuild;
590+ }
591+
592+ template <typename A>
593+ bool HllArray<A>::isRebuildKxqCurminFlag() const {
594+ return rebuild_kxq_curmin_;
595+ }
596+
565597template <typename A>
566598typename HllArray<A>::const_iterator HllArray<A>::begin(bool all) const {
567599 return const_iterator (hllByteArr_.data (), 1 << this ->lgConfigK_ , 0 , this ->tgtHllType_ , nullptr , 0 , all);
@@ -604,6 +636,8 @@ auto HllArray<A>::const_iterator::operator*() const -> reference {
604636
605637template <typename A>
606638uint8_t HllArray<A>::const_iterator::get_value(const uint8_t * array, uint32_t index, target_hll_type hll_type, const AuxHashMap<A>* exceptions, uint8_t offset) {
639+ // TODO: we should be able to improve efficiency here by reading multiple bytes at a time
640+ // for HLL4 and HLL6
607641 if (hll_type == target_hll_type::HLL_4 ) {
608642 uint8_t value = array[index >> 1 ];
609643 if ((index & 1 ) > 0 ) { // odd
0 commit comments