21 #include <initializer_list> 
   23 #include <unordered_map> 
   30 namespace Experimental {
 
   45    enum class EFindStatus {
 
   55    RAxisBase(
const RAxisBase &) = 
default;
 
   56    RAxisBase(RAxisBase &&) = 
default;
 
   57    RAxisBase &operator=(
const RAxisBase &) = 
default;
 
   58    RAxisBase &operator=(RAxisBase &&) = 
default;
 
   62    RAxisBase() = 
default;
 
   72    int AdjustOverflowBinNumber(
double rawbin)
 const 
   79       if (rawbin >= GetNBins())
 
   80          return GetNBins() - 1;
 
   91    class const_iterator: 
public std::iterator<std::random_access_iterator_tag, int , int ,
 
   92                                               const int * , const int & > {
 
   96       const_iterator() = 
default;
 
   99       explicit const_iterator(
int cursor) noexcept: fCursor(cursor) {}
 
  102       const_iterator &operator++() noexcept
 
  110       const_iterator &operator--() noexcept
 
  118       const_iterator operator++(
int)noexcept
 
  120          const_iterator old(*
this);
 
  126       const_iterator operator--(
int)noexcept
 
  128          const_iterator old(*
this);
 
  134       const_iterator &operator+=(
int d) noexcept
 
  141       const_iterator &operator-=(
int d) noexcept
 
  148       const_iterator operator+(
int d) noexcept
 
  150          const_iterator ret(*
this);
 
  156       const_iterator operator-(
int d) noexcept
 
  158          const_iterator ret(*
this);
 
  164       const int *operator*() const noexcept { 
return &fCursor; }
 
  167       int operator->() const noexcept { 
return fCursor; }
 
  169       friend bool operator<(const_iterator lhs, const_iterator rhs) noexcept;
 
  170       friend bool operator>(const_iterator lhs, const_iterator rhs) noexcept;
 
  171       friend bool operator<=(const_iterator lhs, const_iterator rhs) noexcept;
 
  172       friend bool operator>=(const_iterator lhs, const_iterator rhs) noexcept;
 
  173       friend bool operator==(const_iterator lhs, const_iterator rhs) noexcept;
 
  174       friend bool operator!=(const_iterator lhs, const_iterator rhs) noexcept;
 
  178    constexpr 
static const int kIgnoreBin = -1;
 
  181    constexpr 
static const int kNOverflowBins[4] = {0, 1, 1, 2};
 
  189    RAxisBase(std::string_view title, 
int nbinsNoOver, 
bool canGrow) noexcept
 
  190       : fNBins(nbinsNoOver + (canGrow ? 0 : 2)), fTitle(title), fCanGrow(canGrow)
 
  198    RAxisBase(
int nbinsNoOver, 
bool canGrow) noexcept: RAxisBase(
"", nbinsNoOver, canGrow) {}
 
  200    const std::string &GetTitle()
 const { 
return fTitle; }
 
  203    int GetNBinsNoOver() const noexcept { 
return fNBins - GetNOverflowBins(); }
 
  206    int GetNBins() const noexcept { 
return fNBins; }
 
  209    int GetNOverflowBins() const noexcept
 
  218    int GetUnderflowBin() const noexcept { 
return 0; }
 
  222    int GetOverflowBin() const noexcept { 
return GetNBinsNoOver() + 1; }
 
  225    bool IsUnderflowBin(
int bin) 
const noexcept { 
return bin <= GetUnderflowBin(); }
 
  228    bool IsOverflowBin(
int bin) 
const noexcept { 
return bin >= GetOverflowBin(); }
 
  234    const_iterator begin() const noexcept { 
return const_iterator{1}; }
 
  237    const_iterator begin_with_underflow() const noexcept { 
return const_iterator{0}; }
 
  241    const_iterator end() const noexcept { 
return const_iterator{GetOverflowBin()}; }
 
  244    const_iterator end_with_overflow() const noexcept { 
return const_iterator{GetOverflowBin() + 1}; }
 
  250    bool fCanGrow = 
false; 
 
  257 inline bool operator<(RAxisBase::const_iterator lhs, RAxisBase::const_iterator rhs) noexcept
 
  259    return lhs.fCursor < rhs.fCursor;
 
  263 inline bool operator>(RAxisBase::const_iterator lhs, RAxisBase::const_iterator rhs) noexcept
 
  265    return lhs.fCursor > rhs.fCursor;
 
  269 inline bool operator<=(RAxisBase::const_iterator lhs, RAxisBase::const_iterator rhs) noexcept
 
  271    return lhs.fCursor <= rhs.fCursor;
 
  275 inline bool operator>=(RAxisBase::const_iterator lhs, RAxisBase::const_iterator rhs) noexcept
 
  277    return lhs.fCursor >= rhs.fCursor;
 
  281 inline bool operator==(RAxisBase::const_iterator lhs, RAxisBase::const_iterator rhs) noexcept
 
  283    return lhs.fCursor == rhs.fCursor;
 
  287 inline bool operator!=(RAxisBase::const_iterator lhs, RAxisBase::const_iterator rhs) noexcept
 
  289    return lhs.fCursor != rhs.fCursor;
 
  300 class RAxisConfig: 
public RAxisBase {
 
  312    std::vector<double> fBinBorders;  
 
  313    std::vector<std::string> fLabels; 
 
  317    explicit RAxisConfig(std::string_view title, 
int nbins, 
double from, 
double to, EKind kind)
 
  318       : RAxisBase(title, nbins, kind == kGrow), fKind(kind), fBinBorders(2)
 
  323       fBinBorders[0] = from;
 
  335    constexpr 
static const Grow_t Grow{};
 
  339    RAxisConfig(std::string_view title, 
int nbins, 
double from, 
double to)
 
  340       : RAxisConfig(title, nbins, from, to, kEquidistant)
 
  344    RAxisConfig(
int nbins, 
double from, 
double to): RAxisConfig(
"", nbins, from, to, kEquidistant) {}
 
  347    RAxisConfig(std::string_view title, Grow_t, 
int nbins, 
double from, 
double to)
 
  348       : RAxisConfig(title, nbins, from, to, kGrow)
 
  352    RAxisConfig(Grow_t, 
int nbins, 
double from, 
double to): RAxisConfig(
"", nbins, from, to, kGrow) {}
 
  355    RAxisConfig(std::string_view title, 
const std::vector<double> &binborders)
 
  356       : RAxisBase(title, binborders.size() - 1, false ), fKind(kIrregular), fBinBorders(binborders)
 
  360    RAxisConfig(
const std::vector<double> &binborders): RAxisConfig(
"", binborders) {}
 
  363    RAxisConfig(std::string_view title, std::vector<double> &&binborders) noexcept
 
  364       : RAxisBase(title, binborders.size() - 1, false ), fKind(kIrregular),
 
  365         fBinBorders(std::move(binborders))
 
  369    RAxisConfig(std::vector<double> &&binborders) noexcept: RAxisConfig("", std::move(binborders)) {}
 
  372    RAxisConfig(std::string_view title, 
const std::vector<std::string_view> &labels)
 
  373       : RAxisBase(title, labels.size(), true ), fKind(kLabels), fLabels(labels.begin(), labels.end())
 
  377    RAxisConfig(
const std::vector<std::string_view> &labels): RAxisConfig(
"", labels) {}
 
  380    RAxisConfig(std::string_view title, std::vector<std::string> &&labels)
 
  381       : RAxisBase(title, labels.size(), true ), fKind(kLabels), fLabels(std::move(labels))
 
  385    RAxisConfig(std::vector<std::string> &&labels): RAxisConfig(
"", std::move(labels)) {}
 
  388    EKind GetKind() const noexcept { 
return fKind; }
 
  391    const std::vector<double> &GetBinBorders() const noexcept { 
return fBinBorders; }
 
  394    const std::vector<std::string> &GetBinLabels() const noexcept { 
return fLabels; }
 
  403 class RAxisEquidistant: 
public RAxisBase {
 
  406    double fInvBinWidth = 0.; 
 
  412    static double GetInvBinWidth(
int nbinsNoOver, 
double lowOrHigh, 
double highOrLow)
 
  414       return nbinsNoOver / std::abs(highOrLow - lowOrHigh);
 
  425    explicit RAxisEquidistant(std::string_view title, 
int nbinsNoOver, 
double low, 
double high, 
bool canGrow) noexcept
 
  426       : RAxisBase(title, nbinsNoOver, canGrow), fLow(low), fInvBinWidth(GetInvBinWidth(nbinsNoOver, low, high))
 
  436    explicit RAxisEquidistant(
int nbinsNoOver, 
double low, 
double high, 
bool canGrow) noexcept
 
  437       : RAxisEquidistant(
"", nbinsNoOver, low, high, canGrow)
 
  441    RAxisEquidistant() = 
default;
 
  451    explicit RAxisEquidistant(
int nbinsNoOver, 
double low, 
double high) noexcept
 
  452       : RAxisEquidistant(nbinsNoOver, low, high, 
false )
 
  463    explicit RAxisEquidistant(std::string_view title, 
int nbinsNoOver, 
double low, 
double high) noexcept
 
  464       : RAxisEquidistant(title, nbinsNoOver, low, high, 
false )
 
  468    operator RAxisConfig()
 const { 
return RAxisConfig(GetNBinsNoOver(), GetMinimum(), GetMaximum()); }
 
  473    int FindBin(
double x) 
const noexcept
 
  475       double rawbin = (x - fLow) * fInvBinWidth;
 
  476       return AdjustOverflowBinNumber(rawbin);
 
  480    static bool CanGrow() noexcept { 
return false; }
 
  483    double GetMinimum() const noexcept { 
return fLow; }
 
  486    double GetMaximum() const noexcept { 
return fLow + GetNBinsNoOver() / fInvBinWidth; }
 
  489    double GetBinWidth() const noexcept { 
return 1. / fInvBinWidth; }
 
  492    double GetInverseBinWidth() const noexcept { 
return fInvBinWidth; }
 
  497    double GetBinCenter(
int bin) 
const noexcept { 
return fLow + (bin - 0.5) / fInvBinWidth; }
 
  502    double GetBinFrom(
int bin) 
const noexcept { 
return fLow + (bin - 1) / fInvBinWidth; }
 
  507    double GetBinTo(
int bin) 
const noexcept { 
return GetBinFrom(bin + 1); }
 
  509    int GetBinIndexForLowEdge(
double x) 
const noexcept;
 
  513 inline bool operator==(
const RAxisEquidistant &lhs, 
const RAxisEquidistant &rhs) noexcept
 
  515    return lhs.GetNBins() == rhs.GetNBins() && lhs.GetMinimum() == rhs.GetMinimum() &&
 
  516           lhs.GetInverseBinWidth() == rhs.GetInverseBinWidth();
 
  523 class RAxisGrow: 
public RAxisEquidistant {
 
  534    explicit RAxisGrow(std::string_view title, 
int nbins, 
double low, 
double high) noexcept
 
  535       : RAxisEquidistant(title, nbins, low, high, CanGrow())
 
  548    explicit RAxisGrow(
int nbins, 
double low, 
double high) noexcept: RAxisEquidistant(nbins, low, high, CanGrow()) {}
 
  551    operator RAxisConfig()
 const { 
return RAxisConfig(RAxisConfig::Grow, GetNBinsNoOver(), GetMinimum(), GetMaximum()); }
 
  580    bool CanGrow()
 const { 
return true; }
 
  595 class RAxisIrregular: 
public RAxisBase {
 
  598    std::vector<double> fBinBorders;
 
  601    RAxisIrregular() = 
default;
 
  605    explicit RAxisIrregular(
const std::vector<double> &binborders)
 
  606       : RAxisBase(binborders.size() - 1, CanGrow()), fBinBorders(binborders)
 
  608 #ifdef R__DO_RANGE_CHECKS 
  609       if (!std::is_sorted(fBinBorders.begin(), fBinBorders.end()))
 
  610          R__ERROR_HERE(
"HIST") << 
"Bin borders must be sorted!";
 
  611 #endif // R__DO_RANGE_CHECKS 
  618    explicit RAxisIrregular(std::vector<double> &&binborders) noexcept
 
  619       : RAxisBase(binborders.size() - 1, CanGrow()), fBinBorders(std::move(binborders))
 
  621 #ifdef R__DO_RANGE_CHECKS 
  622       if (!std::is_sorted(fBinBorders.begin(), fBinBorders.end()))
 
  623          R__ERROR_HERE(
"HIST") << 
"Bin borders must be sorted!";
 
  624 #endif // R__DO_RANGE_CHECKS 
  629    explicit RAxisIrregular(std::string_view title, 
const std::vector<double> &binborders)
 
  630       : RAxisBase(title, binborders.size() - 1, CanGrow()), fBinBorders(binborders)
 
  632 #ifdef R__DO_RANGE_CHECKS 
  633       if (!std::is_sorted(fBinBorders.begin(), fBinBorders.end()))
 
  634          R__ERROR_HERE(
"HIST") << 
"Bin borders must be sorted!";
 
  635 #endif // R__DO_RANGE_CHECKS 
  642    explicit RAxisIrregular(std::string_view title, std::vector<double> &&binborders) noexcept
 
  643       : RAxisBase(title, binborders.size() - 1, CanGrow()), fBinBorders(std::move(binborders))
 
  645 #ifdef R__DO_RANGE_CHECKS 
  646       if (!std::is_sorted(fBinBorders.begin(), fBinBorders.end()))
 
  647          R__ERROR_HERE(
"HIST") << 
"Bin borders must be sorted!";
 
  648 #endif // R__DO_RANGE_CHECKS 
  652    operator RAxisConfig()
 const { 
return RAxisConfig(GetBinBorders()); }
 
  657    int FindBin(
double x) 
const noexcept
 
  659       const auto bBegin = fBinBorders.begin();
 
  660       const auto bEnd = fBinBorders.end();
 
  662       auto iNotLess = std::lower_bound(bBegin, bEnd, x);
 
  663       int rawbin = iNotLess - bBegin;
 
  677    double GetBinCenter(
int bin) 
const noexcept
 
  679       if (IsUnderflowBin(bin))
 
  680          return std::numeric_limits<double>::min();
 
  681       if (IsOverflowBin(bin))
 
  682          return std::numeric_limits<double>::max();
 
  683       return 0.5 * (fBinBorders[bin - 1] + fBinBorders[bin]);
 
  691    double GetBinFrom(
int bin) 
const noexcept
 
  693       if (IsUnderflowBin(bin))
 
  694          return std::numeric_limits<double>::min();
 
  697       return fBinBorders[bin - 1];
 
  705    double GetBinTo(
int bin) 
const noexcept
 
  707       if (IsOverflowBin(bin))
 
  708          return std::numeric_limits<double>::max();
 
  709       return GetBinFrom(bin + 1);
 
  713    static bool CanGrow() noexcept { 
return false; }
 
  716    const std::vector<double> &GetBinBorders() const noexcept { 
return fBinBorders; }
 
  736 class RAxisLabels: 
public RAxisGrow {
 
  739    std::unordered_map<std::string, 
int > fLabelsIndex;
 
  743    explicit RAxisLabels(std::string_view title, 
const std::vector<std::string_view> &labels)
 
  744       : RAxisGrow(title, labels.size(), 0., static_cast<double>(labels.size()))
 
  746       for (
size_t i = 0, n = labels.size(); i < n; ++i)
 
  747          fLabelsIndex[std::string(labels[i])] = i;
 
  751    explicit RAxisLabels(std::string_view title, 
const std::vector<std::string> &labels)
 
  752       : RAxisGrow(title, labels.size(), 0., static_cast<double>(labels.size()))
 
  754       for (
size_t i = 0, n = labels.size(); i < n; ++i)
 
  755          fLabelsIndex[labels[i]] = i;
 
  759    explicit RAxisLabels(
const std::vector<std::string_view> &labels): RAxisLabels(
"", labels) {}
 
  762    explicit RAxisLabels(
const std::vector<std::string> &labels): RAxisLabels(
"", labels) {}
 
  765    int GetBinIndex(
const std::string &label)
 
  767       auto insertResult = fLabelsIndex.insert({label, -1});
 
  768       if (insertResult.second) {
 
  770          int idx = fLabelsIndex.size() - 1;
 
  771          insertResult.first->second = idx;
 
  774       return insertResult.first->second;
 
  778    double GetBinCenter(
const std::string &label)
 
  780       return GetBinIndex(label) - 0.5; 
 
  784    std::vector<std::string_view> GetBinLabels()
 const 
  786       std::vector<std::string_view> vec(fLabelsIndex.size());
 
  787       for (
const auto &kv: fLabelsIndex)
 
  788          vec.at(kv.second) = kv.first;
 
  797 template <RAxisConfig::EKind>
 
  798 struct AxisConfigToType; 
 
  801 struct AxisConfigToType<RAxisConfig::kEquidistant> {
 
  802    using Axis_t = RAxisEquidistant;
 
  804    Axis_t operator()(
const RAxisConfig &cfg) noexcept
 
  806       return RAxisEquidistant(cfg.GetTitle(), cfg.GetNBinsNoOver(), cfg.GetBinBorders()[0], cfg.GetBinBorders()[1]);
 
  811 struct AxisConfigToType<RAxisConfig::kGrow> {
 
  812    using Axis_t = RAxisGrow;
 
  814    Axis_t operator()(
const RAxisConfig &cfg) noexcept
 
  816       return RAxisGrow(cfg.GetTitle(), cfg.GetNBinsNoOver(), cfg.GetBinBorders()[0], cfg.GetBinBorders()[1]);
 
  820 struct AxisConfigToType<RAxisConfig::kIrregular> {
 
  821    using Axis_t = RAxisIrregular;
 
  823    Axis_t operator()(
const RAxisConfig &cfg) { 
return RAxisIrregular(cfg.GetTitle(), cfg.GetBinBorders()); }
 
  827 struct AxisConfigToType<RAxisConfig::kLabels> {
 
  828    using Axis_t = RAxisLabels;
 
  830    Axis_t operator()(
const RAxisConfig &cfg) { 
return RAxisLabels(cfg.GetTitle(), cfg.GetBinLabels()); }
 
  838    const RAxisEquidistant *fEqui = 
nullptr;
 
  840    const RAxisIrregular *fIrr = 
nullptr;
 
  843    RAxisView() = 
default;
 
  846    RAxisView(
const RAxisEquidistant &equi): fEqui(&equi) {}
 
  849    RAxisView(
const RAxisIrregular &irr): fIrr(&irr) {}
 
  851    const std::string &GetTitle()
 const { 
return fEqui ? fEqui->GetTitle() : fIrr->GetTitle(); }
 
  854    int FindBin(
double x) 
const noexcept
 
  857          return fEqui->FindBin(x);
 
  858       return fIrr->FindBin(x);
 
  862    int GetNBins() const noexcept
 
  865          return fEqui->GetNBins();
 
  866       return fIrr->GetNBins();
 
  870    double GetFrom()
 const { 
return GetBinFrom(1); }
 
  872    double GetTo()
 const { 
return GetBinTo(GetNBins() - 2); }
 
  875    double GetBinCenter(
int i) 
const noexcept
 
  878          return fEqui->GetBinCenter(i);
 
  879       return fIrr->GetBinCenter(i);
 
  883    double GetBinFrom(
int i) 
const noexcept
 
  886          return fEqui->GetBinFrom(i);
 
  887       return fIrr->GetBinFrom(i);
 
  891    double GetBinTo(
int i) 
const noexcept
 
  894          return fEqui->GetBinTo(i);
 
  895       return fIrr->GetBinTo(i);
 
  899    const RAxisEquidistant *GetAsEquidistant()
 const { 
return fEqui; }
 
  901    const RAxisIrregular *GetAsIrregular()
 const { 
return fIrr; }
 
  906 enum class EAxisCompatibility {
 
  923 EAxisCompatibility CanMap(RAxisEquidistant &target, RAxisEquidistant &source) noexcept;