]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/boost/boost/histogram/histogram.hpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / boost / histogram / histogram.hpp
index 19b5c260d2bf99848316adb5d411ce87cb5a5b13..805849b43721173f15999bfa3a3a6cd75b5fcc68 100644 (file)
@@ -9,16 +9,18 @@
 
 #include <boost/histogram/detail/accumulator_traits.hpp>
 #include <boost/histogram/detail/argument_traits.hpp>
-#include <boost/histogram/detail/at.hpp>
 #include <boost/histogram/detail/axes.hpp>
 #include <boost/histogram/detail/common_type.hpp>
 #include <boost/histogram/detail/fill.hpp>
 #include <boost/histogram/detail/fill_n.hpp>
+#include <boost/histogram/detail/index_translator.hpp>
 #include <boost/histogram/detail/mutex_base.hpp>
-#include <boost/histogram/detail/non_member_container_access.hpp>
+#include <boost/histogram/detail/nonmember_container_access.hpp>
 #include <boost/histogram/detail/span.hpp>
 #include <boost/histogram/detail/static_if.hpp>
 #include <boost/histogram/fwd.hpp>
+#include <boost/histogram/indexed.hpp>
+#include <boost/histogram/multi_index.hpp>
 #include <boost/histogram/sample.hpp>
 #include <boost/histogram/storage_adaptor.hpp>
 #include <boost/histogram/unsafe_access.hpp>
@@ -68,6 +70,7 @@ public:
   // typedefs for boost::range_iterator
   using iterator = typename storage_type::iterator;
   using const_iterator = typename storage_type::const_iterator;
+  using multi_index_type = multi_index<detail::relaxed_tuple_size_t<axes_type>::value>;
 
 private:
   using mutex_base = typename detail::mutex_base<axes_type, storage_type>;
@@ -137,14 +140,14 @@ public:
   /// This version is more efficient than the one accepting a run-time number.
   template <unsigned N = 0>
   decltype(auto) axis(std::integral_constant<unsigned, N> = {}) const {
-    detail::axis_index_is_valid(axes_, N);
+    assert(N < rank());
     return detail::axis_get<N>(axes_);
   }
 
   /// Get N-th axis with run-time number.
   /// Prefer the version that accepts a compile-time number, if you can use it.
   decltype(auto) axis(unsigned i) const {
-    detail::axis_index_is_valid(axes_, i);
+    assert(i < rank());
     return detail::axis_get(axes_, i);
   }
 
@@ -349,79 +352,63 @@ public:
     @param is indices of second, third, ... axes.
     @returns reference to cell value.
   */
-  template <class... Indices>
-  decltype(auto) at(axis::index_type i, Indices... is) {
-    return at(std::forward_as_tuple(i, is...));
+  template <class... Is>
+  decltype(auto) at(axis::index_type i, Is... is) {
+    return at(multi_index_type{i, static_cast<axis::index_type>(is)...});
   }
 
   /// Access cell value at integral indices (read-only).
-  template <class... Indices>
-  decltype(auto) at(axis::index_type i, Indices... is) const {
-    return at(std::forward_as_tuple(i, is...));
+  template <class... Is>
+  decltype(auto) at(axis::index_type i, Is... is) const {
+    return at(multi_index_type{i, static_cast<axis::index_type>(is)...});
   }
 
-  /// Access cell value at integral indices stored in `std::tuple`.
-  template <class... Indices>
-  decltype(auto) at(const std::tuple<Indices...>& is) {
-    if (rank() != sizeof...(Indices))
+  /// Access cell value at integral indices stored in iterable.
+  decltype(auto) at(const multi_index_type& is) {
+    if (rank() != is.size())
       BOOST_THROW_EXCEPTION(
           std::invalid_argument("number of arguments != histogram rank"));
-    const auto idx = detail::at(axes_, is);
+    const auto idx = detail::linearize_indices(axes_, is);
     if (!is_valid(idx))
       BOOST_THROW_EXCEPTION(std::out_of_range("at least one index out of bounds"));
-    BOOST_ASSERT(idx < storage_.size());
+    assert(idx < storage_.size());
     return storage_[idx];
   }
 
-  /// Access cell value at integral indices stored in `std::tuple` (read-only).
-  template <class... Indices>
-  decltype(auto) at(const std::tuple<Indices...>& is) const {
-    if (rank() != sizeof...(Indices))
+  /// Access cell value at integral indices stored in iterable (read-only).
+  decltype(auto) at(const multi_index_type& is) const {
+    if (rank() != is.size())
       BOOST_THROW_EXCEPTION(
           std::invalid_argument("number of arguments != histogram rank"));
-    const auto idx = detail::at(axes_, is);
+    const auto idx = detail::linearize_indices(axes_, is);
     if (!is_valid(idx))
       BOOST_THROW_EXCEPTION(std::out_of_range("at least one index out of bounds"));
-    BOOST_ASSERT(idx < storage_.size());
+    assert(idx < storage_.size());
     return storage_[idx];
   }
 
-  /// Access cell value at integral indices stored in iterable.
-  template <class Iterable, class = detail::requires_iterable<Iterable>>
-  decltype(auto) at(const Iterable& is) {
-    if (rank() != detail::axes_rank(is))
-      BOOST_THROW_EXCEPTION(
-          std::invalid_argument("number of arguments != histogram rank"));
-    const auto idx = detail::at(axes_, is);
-    if (!is_valid(idx))
-      BOOST_THROW_EXCEPTION(std::out_of_range("at least one index out of bounds"));
-    BOOST_ASSERT(idx < storage_.size());
-    return storage_[idx];
+  /// Access value at index (for rank = 1).
+  decltype(auto) operator[](axis::index_type i) {
+    const axis::index_type shift =
+        axis::traits::options(axis()) & axis::option::underflow ? 1 : 0;
+    return storage_[static_cast<std::size_t>(i + shift)];
   }
 
-  /// Access cell value at integral indices stored in iterable (read-only).
-  template <class Iterable, class = detail::requires_iterable<Iterable>>
-  decltype(auto) at(const Iterable& is) const {
-    if (rank() != detail::axes_rank(is))
-      BOOST_THROW_EXCEPTION(
-          std::invalid_argument("number of arguments != histogram rank"));
-    const auto idx = detail::at(axes_, is);
-    if (!is_valid(idx))
-      BOOST_THROW_EXCEPTION(std::out_of_range("at least one index out of bounds"));
-    BOOST_ASSERT(idx < storage_.size());
-    return storage_[idx];
+  /// Access value at index (for rank = 1, read-only).
+  decltype(auto) operator[](axis::index_type i) const {
+    const axis::index_type shift =
+        axis::traits::options(axis()) & axis::option::underflow ? 1 : 0;
+    return storage_[static_cast<std::size_t>(i + shift)];
   }
 
-  /// Access value at index (number for rank = 1, else `std::tuple` or iterable).
-  template <class Indices>
-  decltype(auto) operator[](const Indices& is) {
-    return at(is);
+  /// Access value at index tuple.
+  decltype(auto) operator[](const multi_index_type& is) {
+    return storage_[detail::linearize_indices(axes_, is)];
   }
 
-  /// Access value at index (read-only).
-  template <class Indices>
-  decltype(auto) operator[](const Indices& is) const {
-    return at(is);
+  /// Access value at index tuple (read-only).
+  decltype(auto) operator[](const multi_index_type& is) const {
+    return storage_[detail::linearize_indices(axes_, is)];
   }
 
   /// Equality operator, tests equality for all axes and the storage.
@@ -442,6 +429,11 @@ public:
   /** Add values of another histogram.
 
     This operator is only available if the value_type supports operator+=.
+
+    Both histograms must be compatible to be addable. The histograms are compatible, if
+    the axes are either all identical. If the axes only differ in the states of their
+    discrete growing axis types, then they are also compatible. The discrete growing
+    axes are merged in this case.
   */
   template <class A, class S>
 #ifdef BOOST_HISTOGRAM_DOXYGEN_INVOKED
@@ -459,6 +451,37 @@ public:
     return *this;
   }
 
+  // specialization that allows axes merging
+  template <class S>
+#ifdef BOOST_HISTOGRAM_DOXYGEN_INVOKED
+  histogram&
+#else
+  std::enable_if_t<detail::has_operator_radd<
+                       value_type, typename histogram<axes_type, S>::value_type>::value,
+                   histogram&>
+#endif
+  operator+=(const histogram<axes_type, S>& rhs) {
+    const auto& raxes = unsafe_access::axes(rhs);
+    if (detail::axes_equal(axes_, unsafe_access::axes(rhs))) {
+      auto rit = unsafe_access::storage(rhs).begin();
+      for (auto&& x : storage_) x += *rit++;
+      return *this;
+    }
+
+    if (rank() != detail::axes_rank(raxes))
+      BOOST_THROW_EXCEPTION(std::invalid_argument("axes have different length"));
+    auto h = histogram<axes_type, storage_type>(
+        detail::axes_transform(axes_, raxes, detail::axis_merger{}),
+        detail::make_default(storage_));
+    const auto& axes = unsafe_access::axes(h);
+    const auto tr1 = detail::make_index_translator(axes, axes_);
+    for (auto&& x : indexed(*this, coverage::all)) h[tr1(x.indices())] += *x;
+    const auto tr2 = detail::make_index_translator(axes, raxes);
+    for (auto&& x : indexed(rhs, coverage::all)) h[tr2(x.indices())] += *x;
+    *this = std::move(h);
+    return *this;
+  }
+
   /** Subtract values of another histogram.
 
     This operator is only available if the value_type supports operator-=.
@@ -665,24 +688,23 @@ auto operator/(const histogram<A, S>& h, double x) {
 #if __cpp_deduction_guides >= 201606
 
 template <class... Axes, class = detail::requires_axes<std::tuple<std::decay_t<Axes>...>>>
-histogram(Axes...)->histogram<std::tuple<std::decay_t<Axes>...>>;
+histogram(Axes...) -> histogram<std::tuple<std::decay_t<Axes>...>>;
 
 template <class... Axes, class S, class = detail::requires_storage_or_adaptible<S>>
 histogram(std::tuple<Axes...>, S)
-    ->histogram<std::tuple<Axes...>, std::conditional_t<detail::is_adaptible<S>::value,
-                                                        storage_adaptor<S>, S>>;
+    -> histogram<std::tuple<Axes...>, std::conditional_t<detail::is_adaptible<S>::value,
+                                                         storage_adaptor<S>, S>>;
 
 template <class Iterable, class = detail::requires_iterable<Iterable>,
           class = detail::requires_any_axis<typename Iterable::value_type>>
-histogram(Iterable)->histogram<std::vector<typename Iterable::value_type>>;
+histogram(Iterable) -> histogram<std::vector<typename Iterable::value_type>>;
 
 template <class Iterable, class S, class = detail::requires_iterable<Iterable>,
           class = detail::requires_any_axis<typename Iterable::value_type>,
           class = detail::requires_storage_or_adaptible<S>>
-histogram(Iterable, S)
-    ->histogram<
-        std::vector<typename Iterable::value_type>,
-        std::conditional_t<detail::is_adaptible<S>::value, storage_adaptor<S>, S>>;
+histogram(Iterable, S) -> histogram<
+    std::vector<typename Iterable::value_type>,
+    std::conditional_t<detail::is_adaptible<S>::value, storage_adaptor<S>, S>>;
 
 #endif