20 #ifndef _HLL4ARRAY_INTERNAL_HPP_
21 #define _HLL4ARRAY_INTERNAL_HPP_
23 #include "Hll4Array.hpp"
33 Hll4Array<A>::Hll4Array(uint8_t lgConfigK,
bool startFullSize,
const A& allocator):
37 const uint32_t numBytes = this->hll4ArrBytes(lgConfigK);
38 this->hllByteArr_.resize(numBytes, 0);
42 Hll4Array<A>::Hll4Array(
const Hll4Array<A>& that) :
47 if (that.auxHashMap_ !=
nullptr) {
48 auxHashMap_ = that.auxHashMap_->copy();
50 auxHashMap_ =
nullptr;
55 Hll4Array<A>::Hll4Array(
const HllArray<A>& other) :
56 HllArray<A>(other.getLgConfigK(),
target_hll_type::
HLL_4, other.isStartFullSize(), other.getAllocator()),
59 const int numBytes = this->hll4ArrBytes(this->lgConfigK_);
60 this->hllByteArr_.resize(numBytes, 0);
61 this->oooFlag_ = other.isOutOfOrderFlag();
63 for (
const auto coupon : other) {
64 internalCouponUpdate(coupon);
66 this->hipAccum_ = other.getHipAccum();
67 this->rebuild_kxq_curmin_ =
false;
71 Hll4Array<A>::~Hll4Array() {
73 if (auxHashMap_ !=
nullptr) {
74 AuxHashMap<A>::make_deleter()(auxHashMap_);
79 std::function<void(HllSketchImpl<A>*)> Hll4Array<A>::get_deleter()
const {
80 return [](HllSketchImpl<A>* ptr) {
81 Hll4Array<A>* hll =
static_cast<Hll4Array<A>*
>(ptr);
82 using Hll4Alloc =
typename std::allocator_traits<A>::template rebind_alloc<Hll4Array<A>>;
83 Hll4Alloc hll4Alloc(hll->getAllocator());
85 hll4Alloc.deallocate(hll, 1);
90 Hll4Array<A>* Hll4Array<A>::copy()
const {
91 using Hll4Alloc =
typename std::allocator_traits<A>::template rebind_alloc<Hll4Array<A>>;
92 Hll4Alloc hll4Alloc(this->getAllocator());
93 return new (hll4Alloc.allocate(1)) Hll4Array<A>(*
this);
97 uint32_t Hll4Array<A>::getUpdatableSerializationBytes()
const {
98 AuxHashMap<A>* auxHashMap = getAuxHashMap();
100 if (auxHashMap ==
nullptr) {
101 auxBytes = 4 << hll_constants::LG_AUX_ARR_INTS[this->lgConfigK_];
103 auxBytes = 4 << auxHashMap->getLgAuxArrInts();
105 return hll_constants::HLL_BYTE_ARR_START + getHllByteArrBytes() + auxBytes;
109 uint32_t Hll4Array<A>::getHllByteArrBytes()
const {
110 return this->hll4ArrBytes(this->lgConfigK_);
114 AuxHashMap<A>* Hll4Array<A>::getAuxHashMap()
const {
119 void Hll4Array<A>::putAuxHashMap(AuxHashMap<A>* auxHashMap) {
120 this->auxHashMap_ = auxHashMap;
124 uint8_t Hll4Array<A>::getSlot(uint32_t slotNo)
const {
125 const uint8_t
byte = this->hllByteArr_[slotNo >> 1];
126 if ((slotNo & 1) > 0) {
129 return byte & hll_constants::loNibbleMask;
133 uint8_t Hll4Array<A>::adjustRawValue(uint32_t slot, uint8_t value)
const {
134 if (value != hll_constants::AUX_TOKEN)
return value + this->curMin_;
135 return auxHashMap_->mustFindValueFor(slot);
139 HllSketchImpl<A>* Hll4Array<A>::couponUpdate(uint32_t coupon) {
140 internalCouponUpdate(coupon);
145 void Hll4Array<A>::internalCouponUpdate(uint32_t coupon) {
146 const uint8_t newValue = HllUtil<A>::getValue(coupon);
147 if (newValue <= this->curMin_) {
150 const uint32_t configKmask = (1 << this->lgConfigK_) - 1;
151 const uint32_t slotNo = HllUtil<A>::getLow26(coupon) & configKmask;
152 internalHll4Update(slotNo, newValue);
156 void Hll4Array<A>::putSlot(uint32_t slotNo, uint8_t newValue) {
157 const uint32_t byteno = slotNo >> 1;
158 const uint8_t oldValue = this->hllByteArr_[byteno];
159 if ((slotNo & 1) == 0) {
160 this->hllByteArr_[byteno]
161 = ((oldValue & hll_constants::hiNibbleMask) | (newValue & hll_constants::loNibbleMask));
163 this->hllByteArr_[byteno]
164 = ((oldValue & hll_constants::loNibbleMask) | ((newValue << 4) & hll_constants::hiNibbleMask));
170 void Hll4Array<A>::internalHll4Update(uint32_t slotNo, uint8_t newVal) {
172 const uint8_t rawStoredOldValue = getSlot(slotNo);
174 const uint8_t lbOnOldValue = rawStoredOldValue + this->curMin_;
176 if (newVal > lbOnOldValue) {
179 const uint8_t actualOldValue = (rawStoredOldValue < hll_constants::AUX_TOKEN)
180 ? (lbOnOldValue) : (auxHashMap_->mustFindValueFor(slotNo));
182 if (newVal > actualOldValue) {
184 this->hipAndKxQIncrementalUpdate(actualOldValue, newVal);
188 const uint8_t shiftedNewValue = newVal - this->curMin_;
193 if (rawStoredOldValue == hll_constants::AUX_TOKEN) {
197 if (shiftedNewValue >= hll_constants::AUX_TOKEN) {
201 auxHashMap_->mustReplace(slotNo, newVal);
208 if (shiftedNewValue >= hll_constants::AUX_TOKEN) {
212 putSlot(slotNo, hll_constants::AUX_TOKEN);
213 if (auxHashMap_ ==
nullptr) {
214 auxHashMap_ = AuxHashMap<A>::newAuxHashMap(hll_constants::LG_AUX_ARR_INTS[this->lgConfigK_],
215 this->lgConfigK_, this->getAllocator());
217 auxHashMap_->mustAdd(slotNo, newVal);
222 putSlot(slotNo, shiftedNewValue);
227 if (actualOldValue == this->curMin_) {
228 --(this->numAtCurMin_);
229 while (this->numAtCurMin_ == 0) {
230 shiftToBiggerCurMin();
245 void Hll4Array<A>::shiftToBiggerCurMin() {
246 const uint8_t newCurMin = this->curMin_ + 1;
247 const uint32_t configK = 1 << this->lgConfigK_;
248 const uint32_t configKmask = configK - 1;
250 uint32_t numAtNewCurMin = 0;
251 uint32_t numAuxTokens = 0;
258 for (uint32_t i = 0; i < configK; i++) {
259 uint8_t oldStoredValue = getSlot(i);
260 if (oldStoredValue == 0) {
261 throw std::runtime_error(
"Array slots cannot be 0 at this point.");
263 if (oldStoredValue < hll_constants::AUX_TOKEN) {
264 putSlot(i, --oldStoredValue);
265 if (oldStoredValue == 0) { numAtNewCurMin++; }
268 if (auxHashMap_ ==
nullptr) {
269 throw std::logic_error(
"auxHashMap cannot be null at this point");
276 AuxHashMap<A>* newAuxMap =
nullptr;
277 if (auxHashMap_ !=
nullptr) {
279 uint8_t oldActualVal;
280 uint8_t newShiftedVal;
282 for (
const auto coupon: *auxHashMap_) {
283 slotNum = HllUtil<A>::getLow26(coupon) & configKmask;
284 oldActualVal = HllUtil<A>::getValue(coupon);
285 if (oldActualVal < newCurMin) {
286 throw std::logic_error(
"oldActualVal < newCurMin when incrementing curMin");
288 newShiftedVal = oldActualVal - newCurMin;
290 if (getSlot(slotNum) != hll_constants::AUX_TOKEN) {
291 throw std::logic_error(
"getSlot(slotNum) != AUX_TOKEN for item in auxiliary hash map");
294 if (newShiftedVal < hll_constants::AUX_TOKEN) {
295 if (newShiftedVal != 14) {
296 throw std::logic_error(
"newShiftedVal != 14 for item in old auxHashMap despite curMin increment");
300 putSlot(slotNum, newShiftedVal);
304 if (newAuxMap ==
nullptr) {
305 newAuxMap = AuxHashMap<A>::newAuxHashMap(hll_constants::LG_AUX_ARR_INTS[this->lgConfigK_],
306 this->lgConfigK_, this->getAllocator());
308 newAuxMap->mustAdd(slotNum, oldActualVal);
313 if (numAuxTokens != 0) {
314 throw std::logic_error(
"No auxiliary hash map, but numAuxTokens != 0");
318 if (newAuxMap !=
nullptr) {
319 if (newAuxMap->getAuxCount() != numAuxTokens) {
320 throw std::runtime_error(
"Inconsistent counts: auxCount: " + std::to_string(newAuxMap->getAuxCount())
321 +
", HLL tokesn: " + std::to_string(numAuxTokens));
325 if (auxHashMap_ !=
nullptr) {
326 AuxHashMap<A>::make_deleter()(auxHashMap_);
328 auxHashMap_ = newAuxMap;
330 this->curMin_ = newCurMin;
331 this->numAtCurMin_ = numAtNewCurMin;
335 typename HllArray<A>::const_iterator Hll4Array<A>::begin(
bool all)
const {
336 return typename HllArray<A>::const_iterator(this->hllByteArr_.data(), 1 << this->lgConfigK_, 0, this->tgtHllType_,
337 auxHashMap_, this->curMin_, all);
341 typename HllArray<A>::const_iterator Hll4Array<A>::end()
const {
342 return typename HllArray<A>::const_iterator(this->hllByteArr_.data(), 1 << this->lgConfigK_, 1 << this->lgConfigK_,
343 this->tgtHllType_, auxHashMap_, this->curMin_,
false);
DataSketches namespace.
Definition: binomial_bounds.hpp:38
target_hll_type
Specifies the target type of HLL sketch to be created.
Definition: hll.hpp:72
@ HLL_4
4 bits per entry (most compact, size may vary)
Definition: hll.hpp:73