31 m_bucket_val0s(bucket_val0s),
32 m_bucket_n_sz(bucket_n_sz),
33 m_linear_bucket_sz_or_0(0),
34 m_per_bucket_counts(bucket_val0s.size())
36 using std::adjacent_find;
37 using std::greater_equal;
45 assert((adjacent_find(start_it, end_it, greater_equal<value_t>()) == end_it)
46 &&
"Ctor contract violation: Needs to be sorted and sans repeats.");
48 const auto n_buckets =
size();
59 if (end_it != adjacent_find(start_it + 2, end_it,
75 m_bucket_val0s(n_buckets),
76 m_bucket_n_sz(bucket_sz),
77 m_linear_bucket_sz_or_0(bucket_sz),
78 m_per_bucket_counts(n_buckets)
82 assert((n_buckets > 1) &&
"Ctor contract violation.");
83 assert((bucket0_sz > 0) &&
"Ctor contract violation.");
84 assert((bucket_sz > 0) &&
"Ctor contract violation.");
93 auto next_val = bucket0_val0 + bucket0_sz;
94 for (
size_t idx = 1; idx != n_buckets; ++idx)
97 next_val += bucket_sz;
125 const auto n_buckets =
size();
126 for (
size_t idx = 0; idx != n_buckets; ++idx)
141 const auto n_buckets =
size();
142 for (
size_t idx = 0; idx != n_buckets; ++idx)
156 const auto n_buckets =
size();
157 for (
size_t idx = 0; idx != n_buckets; ++idx)
167 assert((divisor != 0) &&
"Divisor must not be zero.");
169 const auto n_buckets =
size();
170 for (
size_t idx = 0; idx != n_buckets; ++idx)
180 static_assert(
static_cast<int32_t
>(0xFFFF'FFFFu) ==
static_cast<int32_t
>(-1),
181 "We require two's complement in our reasoning; C++20 guarantees it; below that, no, but in "
184 using std::upper_bound;
193 return (val < (bucket0_val0 + bucket0_sz)) ? 0 : 1;
201 const auto idx = upper_bound(start_it,
m_bucket_val0s.end(), val) - start_it;
202 return (idx == 0) ? 0 : (idx - 1);
206 if (val <= bucket0_val0)
244 using offset_t = std::make_unsigned_t<value_t>;
245 auto offset =
static_cast<offset_t
>(val) -
static_cast<offset_t
>(bucket0_val0);
248 const auto bucket0_sz_pos =
static_cast<offset_t
>(bucket0_sz);
249 if (offset < bucket0_sz_pos)
255 offset -= bucket0_sz_pos;
263 const auto n_buckets =
size();
264 if (idx <
static_cast<offset_t
>(n_buckets))
266 return static_cast<size_t>(idx);
271 return n_buckets - 1;
281 assert(idx <
size());
289 store(&per_bucket_count, 0);
295 assert(idx <
size());
317 const auto n_buckets =
size();
324 size_t skipped0_ct = 0;
325 for (
size_t idx = 0; idx != n_buckets; ++idx)
327 const bool first = idx == 0;
328 const bool last = (idx + 1) == n_buckets;
329 const auto val = next_val;
331 const bool val0 = val == 0;
346 if ((!first) && (!last) && val0 && (next_val == 0))
358 const bool skipped0s = skipped0_ct != 0;
359 assert((val0 || (!skipped0s)) &&
"This-ct=0 => may or may not have skipped 1+ zeroes before us; "
360 "this-ct>0 => must not have skipped any zeroes before us.");
363 os <<
"..{" << skipped0_ct <<
"}";
380 os <<
'[' << val <<
']';
Stats counter: tracks a histogram that summarizes, cumulatively, the numeric outcome of an event that...
count_t count_for_bucket(size_t idx) const
Returns the event count accumulated so far in the bucket with the given index.
size_t idx_of_outcome(value_t val) const
Which index into m_per_bucket_counts points to the appropriate bucket for record_value(val)?
Histogram_counter & operator-=(const Histogram_counter &src)
Delta: bucket-by-bucket, makes *this bucket's count decremented by src's corresponding bucket's count...
std::vector< std::atomic< count_t > > m_per_bucket_counts
The data.
Histogram_counter & operator=(const Histogram_counter &src)
Straightforward copy assignment.
Histogram_counter & operator/=(count_t divisor)
Scaler: bucket-by-bucket, makes this->count_for_bucket(idx) equal to v / divisor, where v is its pre-...
value_t m_bucket_n_sz
Bucket structure: an addendum to m_bucket_val0s, this is the positive width of the last of size() buc...
value_t m_linear_bucket_sz_or_0
If size() == 2, or the non-bookend buckets are not all of the same width, this is zero; else the (pos...
uint64_t count_t
The count type.
size_t size() const
Returns the number of buckets in the histogram, as supplied to ctor as n_buckets.
int64_t value_t
Each event outcome recorded by record_value() must fit in the range of this type.
void clear()
Returns *this to the state as-if just-cted with the current bucket structure. Uses stat::store() x N.
Histogram_counter & operator+=(const Histogram_counter &src)
Aggregator: bucket-by-bucket, makes *this bucket's count incremented by src's corresponding bucket's ...
void to_ostream(std::ostream *os) const
Prints string representation to the given ostream.
Histogram_counter(size_t n_buckets, value_t bucket0_sz, value_t bucket_sz=1, value_t bucket0_val0=0)
Allocates the histogram data structure (linear-scale: bucket widths [ABBB...]) and initializes each b...
void overwrite_count_for_bucket(size_t idx, count_t new_count)
Set a bucket-value so that count_for_bucket(idx) == new_count.
std::vector< value_t > m_bucket_val0s
General bucket structure (except the last bucket's width): in strictly increasing order,...
Sub-module of flow::util providing lightweight facilities for working with simple structs of stat cou...
void fetch_sub(T *target_val, const boost::type_identity_t< T > &subtrahend_val)
Default fetch_sub(&target_stats.m_val, _val) that simply applies *target_val -= subtrahend_val.
const T & load(const T &val)
Default load(stats.m_val) that simply return stats.m_val.
void reset(Histogram_counter *target_val, const Histogram_counter &)
Executes target_val->clear(), where *target_val is a Histogram_counter.
void fetch_add(T *target_val, const boost::type_identity_t< T > &addend_val)
Default fetch_add(&target_stats.m_val, addend_val) that simply applies *target_val += addend_val.
std::ostream & operator<<(std::ostream &os, const Histogram_counter &val)
Prints string representation of the given Histogram_counter to the given ostream.
void store(T *target_val, const boost::type_identity_t< T > &val)
Default store(&target_stats.m_val, val) that simply assigns *target_val = val.