• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 Hans Dembinski
2 //
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt
5 // or copy at http://www.boost.org/LICENSE_1_0.txt)
6 
7 #ifndef BOOST_HISTOGRAM_AXIS_POLYMORPHIC_BIN_HPP
8 #define BOOST_HISTOGRAM_AXIS_POLYMORPHIC_BIN_HPP
9 
10 namespace boost {
11 namespace histogram {
12 namespace axis {
13 
14 /**
15   Holds the bin data of an axis::variant.
16 
17   The interface is a superset of the axis::interval_view
18   class. In addition, the object is implicitly convertible to the value type,
19   returning the equivalent of a call to lower(). For discrete axes, lower() ==
20   upper(), and width() returns zero.
21 
22   This is not a view like axis::interval_view for two reasons.
23   - Sequential calls to lower() and upper() would have to each loop through
24     the variant types. This is likely to be slower than filling all the data in
25     one loop.
26   - polymorphic_bin may be created from a temporary instance of axis::variant,
27     like in the call histogram::axis(0). Storing a reference to the axis would
28     result in a dangling reference. Rather than specialing the code to handle
29     this, it seems easier to just use a value instead of a view.
30 */
31 template <class RealType>
32 class polymorphic_bin {
33   using value_type = RealType;
34 
35 public:
polymorphic_bin(value_type lower,value_type upper)36   polymorphic_bin(value_type lower, value_type upper)
37       : lower_or_value_(lower), upper_(upper) {}
38 
39   /// Implicitly convert to bin value (for axis with discrete values).
operator const value_type&() const40   operator const value_type&() const noexcept { return lower_or_value_; }
41 
42   /// Return lower edge of bin.
lower() const43   value_type lower() const noexcept { return lower_or_value_; }
44   /// Return upper edge of bin.
upper() const45   value_type upper() const noexcept { return upper_; }
46   /// Return center of bin.
center() const47   value_type center() const noexcept { return 0.5 * (lower() + upper()); }
48   /// Return width of bin.
width() const49   value_type width() const noexcept { return upper() - lower(); }
50 
51   template <class BinType>
operator ==(const BinType & rhs) const52   bool operator==(const BinType& rhs) const noexcept {
53     return equal_impl(rhs, 0);
54   }
55 
56   template <class BinType>
operator !=(const BinType & rhs) const57   bool operator!=(const BinType& rhs) const noexcept {
58     return !operator==(rhs);
59   }
60 
61   /// Return true if bin is discrete.
is_discrete() const62   bool is_discrete() const noexcept { return lower_or_value_ == upper_; }
63 
64 private:
equal_impl(const polymorphic_bin & rhs,int) const65   bool equal_impl(const polymorphic_bin& rhs, int) const noexcept {
66     return lower_or_value_ == rhs.lower_or_value_ && upper_ == rhs.upper_;
67   }
68 
69   template <class BinType>
70   auto equal_impl(const BinType& rhs, decltype(rhs.lower(), 0)) const noexcept {
71     return lower() == rhs.lower() && upper() == rhs.upper();
72   }
73 
74   template <class BinType>
equal_impl(const BinType & rhs,float) const75   bool equal_impl(const BinType& rhs, float) const noexcept {
76     return is_discrete() && static_cast<value_type>(*this) == rhs;
77   }
78 
79   const value_type lower_or_value_, upper_;
80 };
81 
82 } // namespace axis
83 } // namespace histogram
84 } // namespace boost
85 
86 #endif
87