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