1 // Copyright 2020 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_DETAIL_REDUCE_COMMAND_HPP 8 #define BOOST_HISTOGRAM_DETAIL_REDUCE_COMMAND_HPP 9 10 #include <boost/histogram/detail/span.hpp> 11 #include <boost/histogram/fwd.hpp> 12 #include <boost/throw_exception.hpp> 13 #include <cassert> 14 #include <stdexcept> 15 #include <string> 16 17 namespace boost { 18 namespace histogram { 19 namespace detail { 20 21 struct reduce_command { 22 static constexpr unsigned unset = static_cast<unsigned>(-1); 23 unsigned iaxis = unset; 24 enum class range_t : char { 25 none, 26 indices, 27 values, 28 } range = range_t::none; 29 union { 30 axis::index_type index; 31 double value; 32 } begin{0}, end{0}; 33 unsigned merge = 0; // default value indicates unset option 34 bool crop = false; 35 // for internal use by the reduce algorithm 36 bool is_ordered = true; 37 bool use_underflow_bin = true; 38 bool use_overflow_bin = true; 39 }; 40 41 // - puts commands in correct axis order 42 // - sets iaxis for positional commands 43 // - detects and fails on invalid settings 44 // - fuses merge commands with non-merge commands normalize_reduce_commands(span<reduce_command> out,span<const reduce_command> in)45inline void normalize_reduce_commands(span<reduce_command> out, 46 span<const reduce_command> in) { 47 unsigned iaxis = 0; 48 for (const auto& o_in : in) { 49 assert(o_in.merge > 0); 50 if (o_in.iaxis != reduce_command::unset && o_in.iaxis >= out.size()) 51 BOOST_THROW_EXCEPTION(std::invalid_argument("invalid axis index")); 52 auto& o_out = out.begin()[o_in.iaxis == reduce_command::unset ? iaxis : o_in.iaxis]; 53 if (o_out.merge == 0) { 54 o_out = o_in; 55 } else { 56 // Some command was already set for this axis, try to fuse commands. 57 if (!((o_in.range == reduce_command::range_t::none) ^ 58 (o_out.range == reduce_command::range_t::none)) || 59 (o_out.merge > 1 && o_in.merge > 1)) 60 BOOST_THROW_EXCEPTION(std::invalid_argument( 61 "multiple conflicting reduce commands for axis " + 62 std::to_string(o_in.iaxis == reduce_command::unset ? iaxis : o_in.iaxis))); 63 if (o_in.range != reduce_command::range_t::none) { 64 o_out.range = o_in.range; 65 o_out.begin = o_in.begin; 66 o_out.end = o_in.end; 67 } else { 68 o_out.merge = o_in.merge; 69 } 70 } 71 ++iaxis; 72 } 73 74 iaxis = 0; 75 for (auto& o : out) o.iaxis = iaxis++; 76 } 77 78 } // namespace detail 79 } // namespace histogram 80 } // namespace boost 81 82 #endif 83