16#ifndef RANS_INTERNAL_CONTAINERS_DENSEHISTOGRAM_H_
17#define RANS_INTERNAL_CONTAINERS_DENSEHISTOGRAM_H_
24#include <fairlogger/Logger.h>
43namespace histogramImpl
46template <
typename source_T>
49 const auto [minIter, maxIter] = std::minmax_element(begin,
end);
50 return {*minIter, *maxIter};
55inline std::pair<uint32_t, uint32_t> minmaxImpl<uint32_t>(
const uint32_t* begin,
const uint32_t*
end)
57 return internal::simd::minmax(begin,
end);
61inline std::pair<int32_t, int32_t> minmaxImpl<int32_t>(
const int32_t* begin,
const int32_t*
end)
63 return internal::simd::minmax(begin,
end);
69template <
typename source_T>
70inline std::pair<source_T, source_T>
minmax(gsl::span<const source_T>
range)
72 const auto begin =
range.data();
73 const auto end = begin +
range.size();
74 return histogramImpl::minmaxImpl<source_T>(begin,
end);
81template <
typename source_T>
82inline std::pair<source_T, source_T>
minmax(gsl::span<const source_T>
range)
88template <
typename source_T,
typename =
void>
91template <
typename source_T>
94 typename internal::VectorContainer<source_T, uint32_t>::value_type,
95 typename internal::VectorContainer<source_T, uint32_t>::difference_type,
96 DenseHistogram<source_T>>
121 template <
typename freq_IT>
125 using HistogramConcept_type::addSamples;
127 using HistogramConcept_type::addFrequencies;
129 template <
typename source_IT>
132 if constexpr (std::is_pointer_v<source_IT>) {
135 return addSamplesImpl(begin,
end,
min,
max);
139 template <
typename source_IT>
142 return addSamplesImpl(span,
min,
max);
153 DenseHistogram& addSamplesImpl(gsl::span<const source_type> span);
155 template <
typename source_IT>
158 template <
typename source_IT>
163 template <
typename freq_IT>
167 inline static constexpr size_t MaxSize{
utils::pow2(30)};
169 bool isValidRange(difference_type
min, difference_type
max);
172template <
typename source_T>
173inline bool DenseHistogram<
source_T, std::enable_if_t<
sizeof(
source_T) == 4>>::isValidRange(difference_type
min, difference_type
max)
176 if constexpr (std::is_unsigned_v<source_T>) {
178 LOGP(warning,
"trying to add frequencies for a signed symbol to a DenseHistogram of an unsiged type.");
182 if (
max -
min >
static_cast<difference_type
>(this->MaxSize)) {
183 LOGP(warning,
"DenseHistogram exceeds {} elements threshold", this->MaxSize);
189template <
typename source_T>
196 LOG(warning) <<
"Passed empty message to " << __func__;
201template <
typename source_T>
202template <
typename source_IT>
206 const auto [minIter, maxIter] = std::minmax_element(begin,
end);
207 addSamplesImpl(begin,
end, *minIter, *maxIter);
209 LOG(warning) <<
"Passed empty message to " << __func__;
214template <
typename source_T>
217 using namespace internal;
218 using namespace utils;
225 const auto begin =
samples.data();
227 constexpr size_t ElemsPerQWord =
sizeof(uint64_t) /
sizeof(
source_type);
228 constexpr size_t nUnroll = 4 * ElemsPerQWord;
231 if (getRangeBits(
min,
max) <= 17) {
232 container_type histogram{this->mContainer.size(), this->mContainer.getOffset()};
234 auto addQWord = [&,
this](uint64_t in64) {
241 if (
end - nUnroll > begin) {
242 for (; iter <
end - nUnroll; iter += nUnroll) {
244 addQWord(load64(iter + ElemsPerQWord));
245 addQWord(load64(iter + 2 * ElemsPerQWord));
246 addQWord(load64(iter + 3 * ElemsPerQWord));
247 this->mNSamples += nUnroll;
248 __builtin_prefetch(iter + 512, 0);
252 while (iter !=
end) {
254 ++this->mContainer[*iter++];
256#if defined(RANS_OPENMP) && defined(RANS_SIMD)
259 for (
size_t i = 0;
i < this->
size(); ++
i) {
260 this->mContainer.data()[
i] += histogram.data()[
i];
263 auto addQWord = [&,
this](uint64_t in64) {
270 if (
end - nUnroll > begin) {
271 for (; iter <
end - nUnroll; iter += nUnroll) {
273 addQWord(load64(iter + ElemsPerQWord));
274 addQWord(load64(iter + 2 * ElemsPerQWord));
275 addQWord(load64(iter + 3 * ElemsPerQWord));
276 this->mNSamples += nUnroll;
277 __builtin_prefetch(iter + 512, 0);
281 while (iter !=
end) {
283 ++this->mContainer[*iter++];
290template <
typename source_T>
291template <
typename source_IT>
295 LOG(warning) <<
"Passed empty message to " << __func__;
298 if (!this->isValidRange(
min,
max)) {
299 throw HistogramError(fmt::format(
"Incompatible Frequency table dimensions: Cannot add samples in range [{},{}] to {} int32 histogram.",
300 min,
max, []() {
if constexpr (std::is_signed_v<source_T>) {
return "signed";}
else {
return "unsigned";} }()));
305 ++this->mContainer[symbol];
306 ++this->mNSamples; });
312template <
typename source_T>
313template <
typename freq_IT>
316 using namespace internal;
321 LOG(warning) <<
"Passed empty DenseHistogram to " << __func__;
327 if (!this->isValidRange(newMin, newMax) ||
328 newMin <
static_cast<difference_type>(std::numeric_limits<source_T>::min()) ||
329 newMax >
static_cast<difference_type>(std::numeric_limits<source_T>::max())) {
330 throw HistogramError(fmt::format(
"Incompatible Frequency table dimensions: Cannot add [{},{}] to {} int32 histogram.",
333 []() {if constexpr (std::is_signed_v<source_T>) {return
"signed";}
else {return
"unsigned";} }()));
339 return this->countSamples(frequency);
343 typename container_type::container_type newHistogram(newSize, 0);
346 assert(!histogramOverlap.empty());
351 assert(!histogramOverlap.empty());
354 histogramOverlap.begin(), histogramOverlap.begin(),
355 [
this](
const count_t&
a,
const count_t&
b) { return safeadd(this->countSamples(a), b); });
364template <
typename source_T>
367 using namespace utils;
369 auto getMaxSymbol = [
this]() {
374 max = std::max(
max, getMaxSymbol());
384 if (this->mContainer.empty()) {
391 return this->addFrequencies(oldHistogramView.begin(), oldHistogramView.end(), oldHistogramView.getMin());
395template <
typename source_T>
398 typename internal::VectorContainer<source_T, uint32_t>::value_type,
399 typename internal::VectorContainer<source_T, uint32_t>::difference_type,
400 DenseHistogram<source_T>>
408 friend containerBase_type;
409 friend HistogramConcept_type;
413 using value_type =
typename containerBase_type::value_type;
414 using container_type =
typename containerBase_type::container_type;
415 using size_type =
typename containerBase_type::size_type;
416 using difference_type =
typename containerBase_type::difference_type;
417 using reference =
typename containerBase_type::reference;
418 using const_reference =
typename containerBase_type::const_reference;
419 using pointer =
typename containerBase_type::pointer;
420 using const_pointer =
typename containerBase_type::const_pointer;
421 using const_iterator =
typename containerBase_type::const_iterator;
425 template <
typename freq_IT>
426 DenseHistogram(freq_IT begin, freq_IT
end, difference_type
offset) : containerBase_type{MaxSize,
std::numeric_limits<
source_type>::
min()},
427 HistogramConcept_type{begin,
end,
offset} {};
429 using HistogramConcept_type::addSamples;
431 template <
typename source_IT>
434 return addSamplesImpl(begin,
end);
437 template <
typename source_IT>
440 return addSamplesImpl(span);
443 using HistogramConcept_type::addFrequencies;
446 template <
typename source_IT>
447 DenseHistogram& addSamplesImpl(source_IT begin, source_IT
end);
449 DenseHistogram& addSamplesImpl(gsl::span<const source_type>
samples);
451 template <
typename freq_IT>
452 DenseHistogram& addFrequenciesImpl(freq_IT begin, freq_IT
end, difference_type
offset);
455 inline static constexpr size_t MaxSize = utils::pow2(utils::toBits<source_type>());
458template <
typename source_T>
459template <
typename source_IT>
460auto DenseHistogram<
source_T, std::enable_if_t<
sizeof(
source_T) <= 2>>::addSamplesImpl(source_IT begin, source_IT
end) -> DenseHistogram&
462 if constexpr (std::is_pointer_v<source_IT>) {
463 return addSamplesImpl({
begin,
end});
467 ++this->mContainer[symbol]; });
472template <
typename source_T>
473auto DenseHistogram<
source_T, std::enable_if_t<
sizeof(
source_T) <= 2>>::addSamplesImpl(gsl::span<const source_type>
samples) -> DenseHistogram&
475 using namespace internal;
476 using namespace utils;
484 constexpr size_t ElemsPerQWord =
sizeof(uint64_t) /
sizeof(
source_type);
485 constexpr size_t nUnroll = 2 * ElemsPerQWord;
490 std::array<ShiftableVector<source_type, value_type>, 3> histograms{
491 {{this->mContainer.size(), this->mContainer.getOffset()},
492 {this->mContainer.size(), this->mContainer.getOffset()},
493 {this->mContainer.size(), this->mContainer.getOffset()}}};
510 if (
end - nUnroll > begin) {
511 for (; iter <
end - nUnroll; iter += nUnroll) {
513 addQWord(load64(iter + ElemsPerQWord));
514 this->mNSamples += nUnroll;
515 __builtin_prefetch(iter + 512, 0);
521 ++this->mContainer[*iter++];
524#if defined(RANS_OPENMP)
525#pragma omp unroll full
527 for (
size_t j = 0;
j < 3; ++
j) {
528#if defined(RANS_OPENMP) && defined(RANS_SIMD)
531 for (
size_t i = 0;
i < 256; ++
i) {
532 this->mContainer(
i) += histograms[
j](
i);
536 container_type histogram{this->mContainer.size(), this->mContainer.getOffset()};
538 auto addQWord = [&,
this](uint64_t in64) {
547 if (
end - nUnroll > begin) {
548 for (; iter <
end - nUnroll; iter += nUnroll) {
551 this->mNSamples += nUnroll;
552 __builtin_prefetch(iter + 512, 0);
556 while (iter !=
end) {
558 ++this->mContainer[*iter++];
560#if defined(RANS_OPENMP) && defined(RANS_SIMD)
564 this->mContainer.data()[
i] += histogram.data()[
i];
571template <
typename source_T>
572template <
typename freq_IT>
573auto DenseHistogram<
source_T, std::enable_if_t<
sizeof(
source_T) <= 2>>::addFrequenciesImpl(freq_IT begin, freq_IT
end, difference_type
offset) -> DenseHistogram&
575 using namespace internal;
579 addedHistogramView = trim(addedHistogramView);
581 if constexpr (std::is_unsigned_v<source_T>) {
582 LOG_IF(warning,
addedHistogramView.getMin() < 0) << fmt::format(
"trying to add frequencies of a signed symbol type to a DenseHistogram of an unsiged type.");
584 if constexpr (std::is_signed_v<source_T>) {
585 const std::ptrdiff_t sourceTypeMax = std::numeric_limits<source_T>::max();
589 if (isMaxOutOfRange || isMinOutOfRange) {
590 LOGP(warning,
"trying to add frequencies of an unsigned symbol type to a DenseHistogram of a signed type");
597 if (isInvalidFrequencyRange) {
598 throw HistogramError(fmt::format(
"Incompatible Frequency table dimensions: Cannot add [{},{}] to [{}, {}] ",
608 auto frequency = *iter;
609 this->mContainer[
idx] = safeadd(this->mContainer[
idx], this->countSamples(frequency));
615template <
typename source_T>
unsigned short int uint16_t
Operations that will be performed on a histogram.
Non-owning, lightweight structure for histogram manipulation.
common helper classes and functions
Abstract container class that defines and implements basic properties shared by histograms and lookup...
typename containerBase_type::container_type container_type
DenseHistogram & addSamplesImpl(source_IT begin, source_IT end)
typename containerBase_type::const_iterator const_iterator
typename containerBase_type::const_pointer const_pointer
DenseHistogram & addSamplesImpl(source_IT begin, source_IT end, source_type min, source_type max)
typename containerBase_type::const_reference const_reference
typename containerBase_type::value_type value_type
DenseHistogram & resize(size_type newSize)
typename containerBase_type::reference reference
DenseHistogram(freq_IT begin, freq_IT end, difference_type offset)
typename containerBase_type::pointer pointer
DenseHistogram & addSamples(source_IT begin, source_IT end, source_type min, source_type max)
typename containerBase_type::difference_type difference_type
DenseHistogram & addFrequenciesImpl(freq_IT begin, freq_IT end, difference_type offset)
DenseHistogram & addSamples(gsl::span< const source_type > span, source_type min, source_type max)
typename containerBase_type::size_type size_type
typename base_type::reference reference
typename base_type::size_type size_type
typename base_type::const_pointer const_pointer
typename base_type::const_reference const_reference
typename base_type::value_type value_type
typename base_type::pointer pointer
typename base_type::const_iterator const_iterator
typename base_type::container_type container_type
typename base_type::difference_type difference_type
GLboolean GLboolean GLboolean b
GLboolean GLboolean GLboolean GLboolean a
auto make_span(const o2::rans::internal::simd::AlignedArray< T, width_V, size_V > &array)
std::pair< source_T, source_T > minmaxImpl(const source_T *begin, const source_T *end)
uint64_t load64(const void *__restrict src)
std::pair< source_T, source_T > minmax(gsl::span< const source_T > range)
constexpr size_t pow2(size_t n) noexcept
std::pair< source_T, source_T > minmax(gsl::span< const source_T > range)
auto DenseHistogram< source_T, std::enable_if_t< sizeof(source_T)<=2 > >::addFrequenciesImpl(freq_IT begin, freq_IT end, difference_type offset) -> DenseHistogram &HistogramView addedHistogramView
const auto thisHistogramView
class DenseHistogram< source_T, std::enable_if_t< sizeof(source_T)<=2 > > :public internal::VectorContainer< source_T, uint32_t >, internal::HistogramConcept< source_T, typename internal::VectorContainer< source_T, uint32_t >::value_type, typename internal::VectorContainer< source_T, uint32_t >::difference_type, DenseHistogram< source_T > >{ using containerBase_type=internal::VectorContainer< source_T, uint32_t >;using HistogramConcept_type=internal::HistogramConcept< source_T, typename internal::VectorContainer< source_T, uint32_t >::value_type, typename internal::VectorContainer< source_T, uint32_t >::difference_type, DenseHistogram< source_T > >;friend containerBase_type;friend HistogramConcept_type;public:using source_type=source_T;using value_type=typename containerBase_type::value_type;using container_type=typename containerBase_type::container_type;using size_type=typename containerBase_type::size_type;using difference_type=typename containerBase_type::difference_type;using reference=typename containerBase_type::reference;using const_reference=typename containerBase_type::const_reference;using pointer=typename containerBase_type::pointer;using const_pointer=typename containerBase_type::const_pointer;using const_iterator=typename containerBase_type::const_iterator;DenseHistogram() :containerBase_type{MaxSize, std::numeric_limits< source_type >::min()} {};template< typename freq_IT > DenseHistogram(freq_IT begin, freq_IT end, difference_type offset) :containerBase_type{MaxSize, std::numeric_limits< source_type >::min()}, HistogramConcept_type{begin, end, offset} {};using HistogramConcept_type::addSamples;template< typename source_IT > inline DenseHistogram &addSamples(source_IT begin, source_IT end, source_type min, source_type max) { return addSamplesImpl(begin, end);};template< typename source_IT > DenseHistogram &addSamples(gsl::span< const source_type > span, source_type min, source_type max) { return addSamplesImpl(span);};using HistogramConcept_type::addFrequencies;protected:template< typename source_IT > DenseHistogram &addSamplesImpl(source_IT begin, source_IT end);DenseHistogram &addSamplesImpl(gsl::span< const source_type > samples);template< typename freq_IT > DenseHistogram &addFrequenciesImpl(freq_IT begin, freq_IT end, difference_type offset);private:inline static constexpr size_t MaxSize=utils::pow2(utils::toBits< source_type >());};template< typename source_T >template< typename source_IT >auto DenseHistogram< source_T, std::enable_if_t< sizeof(source_T)<=2 > >::addSamplesImpl(source_IT begin, source_IT end) -> DenseHistogram &{ if constexpr(std::is_pointer_v< source_IT >) { return addSamplesImpl({begin, end});} else { std::for_each(begin, end, [this](const source_type &symbol) {++this->mNSamples;++this->mContainer[symbol];});} return *this;}template< typename source_T >auto DenseHistogram< source_T, std::enable_if_t< sizeof(source_T)<=2 > >::addSamplesImpl(gsl::span< const source_type > samples) -> DenseHistogram &{ using namespace internal;using namespace utils;if(samples.empty()) { return *this;} const auto begin=samples.data();const auto end=begin+samples.size();constexpr size_t ElemsPerQWord=sizeof(uint64_t)/sizeof(source_type);constexpr size_t nUnroll=2 *ElemsPerQWord;auto iter=begin;if constexpr(sizeof(source_type)==1) { std::array< ShiftableVector< source_type, value_type >, 3 > histograms{ {{this-> mContainer this mContainer auto addQWord
class DenseHistogram< source_T, std::enable_if_t< sizeof(source_T)<=2 > > :public internal::VectorContainer< source_T, uint32_t >, internal::HistogramConcept< source_T, typename internal::VectorContainer< source_T, uint32_t >::value_type, typename internal::VectorContainer< source_T, uint32_t >::difference_type, DenseHistogram< source_T > >{ using containerBase_type=internal::VectorContainer< source_T, uint32_t >;using HistogramConcept_type=internal::HistogramConcept< source_T, typename internal::VectorContainer< source_T, uint32_t >::value_type, typename internal::VectorContainer< source_T, uint32_t >::difference_type, DenseHistogram< source_T > >;friend containerBase_type;friend HistogramConcept_type;public:using source_type=source_T;using value_type=typename containerBase_type::value_type;using container_type=typename containerBase_type::container_type;using size_type=typename containerBase_type::size_type;using difference_type=typename containerBase_type::difference_type;using reference=typename containerBase_type::reference;using const_reference=typename containerBase_type::const_reference;using pointer=typename containerBase_type::pointer;using const_pointer=typename containerBase_type::const_pointer;using const_iterator=typename containerBase_type::const_iterator;DenseHistogram() :containerBase_type{MaxSize, std::numeric_limits< source_type >::min()} {};template< typename freq_IT > DenseHistogram(freq_IT begin, freq_IT end, difference_type offset) :containerBase_type{MaxSize, std::numeric_limits< source_type >::min()}, HistogramConcept_type{begin, end, offset} {};using HistogramConcept_type::addSamples;template< typename source_IT > inline DenseHistogram &addSamples(source_IT begin, source_IT end, source_type min, source_type max) { return addSamplesImpl(begin, end);};template< typename source_IT > DenseHistogram &addSamples(gsl::span< const source_type > span, source_type min, source_type max) { return addSamplesImpl(span);};using HistogramConcept_type::addFrequencies;protected:template< typename source_IT > DenseHistogram &addSamplesImpl(source_IT begin, source_IT end);DenseHistogram &addSamplesImpl(gsl::span< const source_type > samples);template< typename freq_IT > DenseHistogram &addFrequenciesImpl(freq_IT begin, freq_IT end, difference_type offset);private:inline static constexpr size_t MaxSize=utils::pow2(utils::toBits< source_type >());};template< typename source_T >template< typename source_IT >auto DenseHistogram< source_T, std::enable_if_t< sizeof(source_T)<=2 > >::addSamplesImpl(source_IT begin, source_IT end) -> DenseHistogram &{ if constexpr(std::is_pointer_v< source_IT >) { return addSamplesImpl({begin, end});} else { std::for_each(begin, end, [this](const source_type &symbol) {++this->mNSamples;++this->mContainer[symbol];});} return *this;}template< typename source_T >auto DenseHistogram< source_T, std::enable_if_t< sizeof(source_T)<=2 > >::addSamplesImpl(gsl::span< const source_type > samples) -> DenseHistogram &{ using namespace internal;using namespace utils;if(samples.empty()) { return *this;} const auto begin=samples.data();const auto end=begin+samples.size();constexpr size_t ElemsPerQWord=sizeof(uint64_t)/sizeof(source_type);constexpr size_t nUnroll=2 *ElemsPerQWord;auto iter=begin;if constexpr(sizeof(source_type)==1) { std::array< ShiftableVector< source_type, value_type >, 3 > histograms{ {{this-> mContainer this mContainer getOffset()}
HistogramView< HistA_IT > getIntersection(const HistogramView< HistA_IT > &histA, const HistogramView< HistB_IT > &histB)
class DenseHistogram< source_T, std::enable_if_t< sizeof(source_T)<=2 > > :public internal::VectorContainer< source_T, uint32_t >, internal::HistogramConcept< source_T, typename internal::VectorContainer< source_T, uint32_t >::value_type, typename internal::VectorContainer< source_T, uint32_t >::difference_type, DenseHistogram< source_T > >{ using containerBase_type=internal::VectorContainer< source_T, uint32_t >;using HistogramConcept_type=internal::HistogramConcept< source_T, typename internal::VectorContainer< source_T, uint32_t >::value_type, typename internal::VectorContainer< source_T, uint32_t >::difference_type, DenseHistogram< source_T > >;friend containerBase_type;friend HistogramConcept_type;public:using source_type=source_T;using value_type=typename containerBase_type::value_type;using container_type=typename containerBase_type::container_type;using size_type=typename containerBase_type::size_type;using difference_type=typename containerBase_type::difference_type;using reference=typename containerBase_type::reference;using const_reference=typename containerBase_type::const_reference;using pointer=typename containerBase_type::pointer;using const_pointer=typename containerBase_type::const_pointer;using const_iterator=typename containerBase_type::const_iterator;DenseHistogram() :containerBase_type{MaxSize, std::numeric_limits< source_type >::min()} {};template< typename freq_IT > DenseHistogram(freq_IT begin, freq_IT end, difference_type offset) :containerBase_type{MaxSize, std::numeric_limits< source_type >::min()}, HistogramConcept_type{begin, end, offset} {};using HistogramConcept_type::addSamples;template< typename source_IT > inline DenseHistogram &addSamples(source_IT begin, source_IT end, source_type min, source_type max) { return addSamplesImpl(begin, end);};template< typename source_IT > DenseHistogram &addSamples(gsl::span< const source_type > span, source_type min, source_type max) { return addSamplesImpl(span);};using HistogramConcept_type::addFrequencies;protected:template< typename source_IT > DenseHistogram &addSamplesImpl(source_IT begin, source_IT end);DenseHistogram &addSamplesImpl(gsl::span< const source_type > samples);template< typename freq_IT > DenseHistogram &addFrequenciesImpl(freq_IT begin, freq_IT end, difference_type offset);private:inline static constexpr size_t MaxSize=utils::pow2(utils::toBits< source_type >());};template< typename source_T >template< typename source_IT >auto DenseHistogram< source_T, std::enable_if_t< sizeof(source_T)<=2 > >::addSamplesImpl(source_IT begin, source_IT end) -> DenseHistogram &{ if constexpr(std::is_pointer_v< source_IT >) { return addSamplesImpl({begin, end});} else { std::for_each(begin, end,[this](const source_type &symbol) {++this->mNSamples;++this->mContainer[symbol];});} return *this;}template< typename source_T >auto DenseHistogram< source_T, std::enable_if_t< sizeof(source_T)<=2 > >::addSamplesImpl(gsl::span< const source_type > samples) -> DenseHistogram &{ using namespace internal;using namespace utils;if(samples.empty()) { return *this;} const auto begin=samples.data();const auto end=begin+samples.size();constexpr size_t ElemsPerQWord=sizeof(uint64_t)/sizeof(source_type);constexpr size_t nUnroll=2 *ElemsPerQWord;auto iter=begin;if constexpr(sizeof(source_type)==1) { std::array< ShiftableVector< source_type, value_type >, 3 > histograms{ {{this-> mContainer size()
auto makeHistogramView(container_T &container, std::ptrdiff_t offset) noexcept -> HistogramView< decltype(std::begin(container))>
HistogramView< Hist_IT > trim(const HistogramView< Hist_IT > &buffer)
size_t countNUsedAlphabetSymbols(const AdaptiveHistogram< source_T > &histogram)
const bool isInvalidFrequencyRange
Enum< T >::Iterator begin(Enum< T >)
Common utility functions.
wrapper around basic SIMD operations
basic SIMD datatypes and traits
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"
auto getOffset(const map_T &resultsMap) -> typename map_T::key_type