12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 |
- // Copyright 2020 Hans Dembinski
- //
- // Distributed under the Boost Software License, Version 1.0.
- // (See accompanying file LICENSE_1_0.txt
- // or copy at http://www.boost.org/LICENSE_1_0.txt)
- #ifndef BOOST_HISTOGRAM_DETAIL_REDUCE_COMMAND_HPP
- #define BOOST_HISTOGRAM_DETAIL_REDUCE_COMMAND_HPP
- #include <boost/histogram/detail/span.hpp>
- #include <boost/histogram/fwd.hpp>
- #include <boost/throw_exception.hpp>
- #include <cassert>
- #include <stdexcept>
- #include <string>
- namespace boost {
- namespace histogram {
- namespace detail {
- struct reduce_command {
- static constexpr unsigned unset = static_cast<unsigned>(-1);
- unsigned iaxis = unset;
- enum class range_t : char {
- none,
- indices,
- values,
- } range = range_t::none;
- union {
- axis::index_type index;
- double value;
- } begin{0}, end{0};
- unsigned merge = 0; // default value indicates unset option
- bool crop = false;
- // for internal use by the reduce algorithm
- bool is_ordered = true;
- bool use_underflow_bin = true;
- bool use_overflow_bin = true;
- };
- // - puts commands in correct axis order
- // - sets iaxis for positional commands
- // - detects and fails on invalid settings
- // - fuses merge commands with non-merge commands
- inline void normalize_reduce_commands(span<reduce_command> out,
- span<const reduce_command> in) {
- unsigned iaxis = 0;
- for (const auto& o_in : in) {
- assert(o_in.merge > 0);
- if (o_in.iaxis != reduce_command::unset && o_in.iaxis >= out.size())
- BOOST_THROW_EXCEPTION(std::invalid_argument("invalid axis index"));
- auto& o_out = out.begin()[o_in.iaxis == reduce_command::unset ? iaxis : o_in.iaxis];
- if (o_out.merge == 0) {
- o_out = o_in;
- } else {
- // Some command was already set for this axis, try to fuse commands.
- if (!((o_in.range == reduce_command::range_t::none) ^
- (o_out.range == reduce_command::range_t::none)) ||
- (o_out.merge > 1 && o_in.merge > 1))
- BOOST_THROW_EXCEPTION(std::invalid_argument(
- "multiple conflicting reduce commands for axis " +
- std::to_string(o_in.iaxis == reduce_command::unset ? iaxis : o_in.iaxis)));
- if (o_in.range != reduce_command::range_t::none) {
- o_out.range = o_in.range;
- o_out.begin = o_in.begin;
- o_out.end = o_in.end;
- } else {
- o_out.merge = o_in.merge;
- }
- }
- ++iaxis;
- }
- iaxis = 0;
- for (auto& o : out) o.iaxis = iaxis++;
- }
- } // namespace detail
- } // namespace histogram
- } // namespace boost
- #endif
|