mirror of
https://github.com/boostorg/histogram.git
synced 2025-05-09 23:04:07 +00:00
More doc improvements
This commit is contained in:
parent
22ec005290
commit
073dffdf09
@ -40,7 +40,6 @@ actions doxygen_postprocessing
|
|||||||
boostbook histogram
|
boostbook histogram
|
||||||
:
|
:
|
||||||
histogram.qbk
|
histogram.qbk
|
||||||
reference_pp.xml
|
|
||||||
:
|
:
|
||||||
<xsl:param>boost.root=../../../..
|
<xsl:param>boost.root=../../../..
|
||||||
<xsl:param>boost.libraries=../../../libraries.htm
|
<xsl:param>boost.libraries=../../../libraries.htm
|
||||||
@ -48,6 +47,7 @@ boostbook histogram
|
|||||||
<xsl:param>chunk.first.sections=1
|
<xsl:param>chunk.first.sections=1
|
||||||
<xsl:param>generate.section.toc.level=1
|
<xsl:param>generate.section.toc.level=1
|
||||||
<xsl:param>generate.toc="chapter nop section nop"
|
<xsl:param>generate.toc="chapter nop section nop"
|
||||||
|
<dependency>reference_pp.xml
|
||||||
;
|
;
|
||||||
|
|
||||||
alias boostdoc ;
|
alias boostdoc ;
|
||||||
|
@ -1,50 +1,95 @@
|
|||||||
|
from __future__ import print_function
|
||||||
import sys
|
import sys
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
|
import re
|
||||||
|
|
||||||
|
|
||||||
|
def log(*args):
|
||||||
|
print("PP:", *args)
|
||||||
|
|
||||||
|
|
||||||
|
def select(condition, *tags):
|
||||||
|
result = []
|
||||||
|
for tag in tags:
|
||||||
|
for item in root.iter(tag):
|
||||||
|
if condition(item):
|
||||||
|
result.append(item)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def is_detail(x):
|
||||||
|
if x.text is not None:
|
||||||
|
if "detail" in x.text:
|
||||||
|
return True
|
||||||
|
m = re.match("(?:typename)? *([A-Za-z0-9_\:]+)", x.text)
|
||||||
|
if m is not None:
|
||||||
|
s = m.group(1)
|
||||||
|
if s.startswith("detail") or s.endswith("_impl"):
|
||||||
|
x.text = s
|
||||||
|
return True
|
||||||
|
|
||||||
|
p = x.find("purpose")
|
||||||
|
if p is not None:
|
||||||
|
return p.text.lower().strip() == "implementation detail"
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
tree = ET.parse(sys.argv[1])
|
tree = ET.parse(sys.argv[1])
|
||||||
root = tree.getroot()
|
root = tree.getroot()
|
||||||
|
|
||||||
parent_map = {c:p for p in tree.iter() for c in p}
|
parent_map = {c:p for p in tree.iter() for c in p}
|
||||||
|
|
||||||
# hide all unnamed template parameters, these are used for SFINAE
|
unspecified = ET.Element("emphasis")
|
||||||
for item in root.iter("template-type-parameter"):
|
unspecified.text = "unspecified"
|
||||||
if not item.get("name"):
|
|
||||||
parent = parent_map[item]
|
|
||||||
assert parent.tag == "template"
|
|
||||||
parent.remove(item)
|
|
||||||
|
|
||||||
# replace any type with "detail" in its name with "implementation_defined"
|
# hide all unnamed template parameters, these are used for SFINAE
|
||||||
for item in root.iter("type"):
|
for item in select(lambda x: x.get("name") == "", "template-type-parameter"):
|
||||||
if not item.text:
|
parent = parent_map[item]
|
||||||
continue
|
assert parent.tag == "template"
|
||||||
if "detail" in item.text:
|
parent.remove(item)
|
||||||
item.text = "implementation_defined"
|
parent = parent_map[parent]
|
||||||
|
name = parent.get("name")
|
||||||
|
if name is None:
|
||||||
|
log("removing unnamed template parameter from", parent.tag)
|
||||||
|
else:
|
||||||
|
log("removing unnamed template parameter from", parent.tag, name)
|
||||||
|
|
||||||
|
# replace any type with "detail" in its name with "unspecified"
|
||||||
|
for item in select(is_detail, "type"):
|
||||||
|
log("replacing", '"%s"' % item.text, 'with "unspecified"')
|
||||||
|
item.clear()
|
||||||
|
item.append(unspecified)
|
||||||
|
|
||||||
# hide private member functions
|
# hide private member functions
|
||||||
for item in root.iter("method-group"):
|
for item in select(lambda x: x.get("name") == "private member functions", "method-group"):
|
||||||
if item.get("name") == "private member functions":
|
parent = parent_map[item]
|
||||||
parent_map[item].remove(item)
|
log("removing private member functions from", parent.tag, parent.get("name"))
|
||||||
|
parent.remove(item)
|
||||||
|
|
||||||
# hide undocumented classes, structs, functions and replace those declared "implementation detail" with typedef to implementation_defined
|
# hide undocumented classes, structs, functions and replace those declared
|
||||||
for tag in ("class", "struct", "function"):
|
# "implementation detail" with typedef to implementation_defined
|
||||||
for item in root.iter(tag):
|
for item in select(lambda x:True, "class", "struct", "function"):
|
||||||
purpose = item.find("purpose")
|
purpose = item.find("purpose")
|
||||||
if purpose is None:
|
if purpose is None:
|
||||||
parent_map[item].remove(item)
|
parent = parent_map[item]
|
||||||
elif purpose.text.strip().lower() == "implementation detail":
|
log("removing undocumented", item.tag, item.get("name"), "from",
|
||||||
name = item.get("name")
|
parent.tag, parent.get("name"))
|
||||||
item.clear()
|
parent_map[item].remove(item)
|
||||||
item.tag = "typedef"
|
elif purpose.text.strip().lower() == "implementation detail":
|
||||||
item.set("name", name)
|
log("replacing", item.tag, item.get("name"), "with unspecified typedef")
|
||||||
type = ET.Element("type")
|
name = item.get("name")
|
||||||
type.text = "implementation_defined"
|
item.clear()
|
||||||
item.append(type)
|
item.tag = "typedef"
|
||||||
|
item.set("name", name)
|
||||||
|
type = ET.Element("type")
|
||||||
|
type.append(unspecified)
|
||||||
|
item.append(type)
|
||||||
|
|
||||||
# hide methods and constructors explicitly declared as "implementation detail"
|
# hide methods and constructors explicitly declared as "implementation detail"
|
||||||
for tag in ("constructor", "method"):
|
for item in select(is_detail, "constructor", "method"):
|
||||||
for item in root.iter(tag):
|
name = item.get("name")
|
||||||
purpose = item.find("purpose")
|
log("removing", (item.tag + " " + name) if name is not None else item.tag,
|
||||||
if purpose is not None and purpose.text.strip() == "implementation detail":
|
"declared as implementation detail")
|
||||||
parent_map[item].remove(item)
|
parent_map[item].remove(item)
|
||||||
|
|
||||||
tree.write(sys.argv[2])
|
tree.write(sys.argv[2])
|
||||||
|
@ -26,51 +26,20 @@ using common_axes = mp11::mp_cond<
|
|||||||
is_sequence_of_axis<U>, U,
|
is_sequence_of_axis<U>, U,
|
||||||
std::true_type, T
|
std::true_type, T
|
||||||
>;
|
>;
|
||||||
|
|
||||||
template <class T, class U>
|
|
||||||
using common_container = mp11::mp_cond<
|
|
||||||
is_array_like<T>, T,
|
|
||||||
is_array_like<U>, U,
|
|
||||||
is_vector_like<T>, T,
|
|
||||||
is_vector_like<U>, U,
|
|
||||||
std::true_type, T
|
|
||||||
>;
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
template <class T>
|
// Non-PODs rank highest, then floats, than integers; types with more capacity are higher
|
||||||
using type_score = mp11::mp_size_t<((!std::is_pod<T>::value) * 1000 +
|
template <class Storage>
|
||||||
std::is_floating_point<T>::value * 50 + sizeof(T))>;
|
static constexpr std::size_t type_rank() {
|
||||||
|
using T = typename Storage::value_type;
|
||||||
|
return !std::is_pod<T>::value * 10000 + std::is_floating_point<T>::value * 100 +
|
||||||
|
10 * sizeof(T) + 2 * is_array_like<Storage>::value +
|
||||||
|
is_vector_like<Storage>::value;
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
template <class T, class U>
|
template <class T, class U>
|
||||||
struct common_storage_impl;
|
using common_storage = mp11::mp_if_c<(type_rank<T>() >= type_rank<U>()), T, U>;
|
||||||
|
|
||||||
template <class T, class U>
|
|
||||||
struct common_storage_impl<storage_adaptor<T>, storage_adaptor<U>> {
|
|
||||||
using type =
|
|
||||||
mp11::mp_if_c<(type_score<typename storage_adaptor<T>::value_type>::value >=
|
|
||||||
type_score<typename storage_adaptor<U>::value_type>::value),
|
|
||||||
storage_adaptor<T>, storage_adaptor<U>>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T, class A>
|
|
||||||
struct common_storage_impl<storage_adaptor<T>, unlimited_storage<A>> {
|
|
||||||
using type =
|
|
||||||
mp11::mp_if_c<(type_score<typename storage_adaptor<T>::value_type>::value >=
|
|
||||||
type_score<typename unlimited_storage<A>::value_type>::value),
|
|
||||||
storage_adaptor<T>, unlimited_storage<A>>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class C, class A>
|
|
||||||
struct common_storage_impl<unlimited_storage<A>, storage_adaptor<C>>
|
|
||||||
: common_storage_impl<storage_adaptor<C>, unlimited_storage<A>> {};
|
|
||||||
|
|
||||||
template <class A1, class A2>
|
|
||||||
struct common_storage_impl<unlimited_storage<A1>, unlimited_storage<A2>> {
|
|
||||||
using type = unlimited_storage<A1>;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class A, class B>
|
|
||||||
using common_storage = typename common_storage_impl<A, B>::type;
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
} // namespace histogram
|
} // namespace histogram
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
@ -215,9 +215,18 @@ BOOST_HISTOGRAM_DETECT_BINARY(has_operator_rmul,
|
|||||||
BOOST_HISTOGRAM_DETECT_BINARY(has_operator_rdiv,
|
BOOST_HISTOGRAM_DETECT_BINARY(has_operator_rdiv,
|
||||||
(std::declval<T&>() /= std::declval<U&>()));
|
(std::declval<T&>() /= std::declval<U&>()));
|
||||||
|
|
||||||
|
BOOST_HISTOGRAM_DETECT(has_threading_support, (T::has_threading_support));
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using is_storage =
|
using is_storage = mp11::mp_and<is_indexable_container<T>, has_method_reset<T>,
|
||||||
mp11::mp_bool<(is_indexable_container<T>::value && has_method_reset<T>::value)>;
|
has_threading_support<T>>;
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
using is_adaptible = mp11::mp_or<is_vector_like<T>, is_array_like<T>, is_map_like<T>>;
|
||||||
|
|
||||||
|
template <class T, class _ = remove_cvref_t<T>,
|
||||||
|
class = std::enable_if_t<(is_storage<_>::value || is_adaptible<_>::value)>>
|
||||||
|
struct requires_storage_or_adaptible {};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct is_tuple_impl : std::false_type {};
|
struct is_tuple_impl : std::false_type {};
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include <boost/histogram/detail/noop_mutex.hpp>
|
#include <boost/histogram/detail/noop_mutex.hpp>
|
||||||
#include <boost/histogram/detail/static_if.hpp>
|
#include <boost/histogram/detail/static_if.hpp>
|
||||||
#include <boost/histogram/fwd.hpp>
|
#include <boost/histogram/fwd.hpp>
|
||||||
|
#include <boost/histogram/storage_adaptor.hpp>
|
||||||
#include <boost/mp11/list.hpp>
|
#include <boost/mp11/list.hpp>
|
||||||
#include <boost/throw_exception.hpp>
|
#include <boost/throw_exception.hpp>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
@ -22,6 +23,7 @@
|
|||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
namespace histogram {
|
namespace histogram {
|
||||||
@ -135,7 +137,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get N-th axis with run-time number.
|
/// Get N-th axis with run-time number.
|
||||||
/// Use the version that accepts a compile-time number, if possible.
|
/// Prefer the version that accepts a compile-time number, if you can use it.
|
||||||
decltype(auto) axis(unsigned i) const {
|
decltype(auto) axis(unsigned i) const {
|
||||||
detail::axis_index_is_valid(axes_, i);
|
detail::axis_index_is_valid(axes_, i);
|
||||||
return detail::axis_get(axes_, i);
|
return detail::axis_get(axes_, i);
|
||||||
@ -153,13 +155,6 @@ public:
|
|||||||
not convertible to the value type accepted by the axis or passing the wrong number
|
not convertible to the value type accepted by the axis or passing the wrong number
|
||||||
of arguments causes a throw of `std::invalid_argument`.
|
of arguments causes a throw of `std::invalid_argument`.
|
||||||
|
|
||||||
__Axis with multiple arguments__
|
|
||||||
|
|
||||||
If the histogram contains an axis which accepts a `std::tuple` of arguments, the
|
|
||||||
arguments for that axis need to passed as a `std::tuple`, for example,
|
|
||||||
`std::make_tuple(1.2, 2.3)`. If the histogram contains only this axis and no other,
|
|
||||||
the arguments can be passed directly.
|
|
||||||
|
|
||||||
__Optional weight__
|
__Optional weight__
|
||||||
|
|
||||||
An optional weight can be passed as the first or last argument
|
An optional weight can be passed as the first or last argument
|
||||||
@ -173,83 +168,93 @@ public:
|
|||||||
[sample](boost/histogram/sample.html) helper function can pass one or more arguments to
|
[sample](boost/histogram/sample.html) helper function can pass one or more arguments to
|
||||||
the storage element. If samples and weights are used together, they can be passed in
|
the storage element. If samples and weights are used together, they can be passed in
|
||||||
any order at the beginning or end of the argument list.
|
any order at the beginning or end of the argument list.
|
||||||
|
|
||||||
|
__Axis with multiple arguments__
|
||||||
|
|
||||||
|
If the histogram contains an axis which accepts a `std::tuple` of arguments, the
|
||||||
|
arguments for that axis need to passed as a `std::tuple`, for example,
|
||||||
|
`std::make_tuple(1.2, 2.3)`. If the histogram contains only this axis and no other,
|
||||||
|
the arguments can be passed directly.
|
||||||
*/
|
*/
|
||||||
template <class... Ts>
|
template <class... Ts>
|
||||||
auto operator()(const Ts&... ts) {
|
iterator operator()(const Ts&... ts) {
|
||||||
return operator()(std::make_tuple(ts...));
|
return operator()(std::make_tuple(ts...));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fill histogram with values, an optional weight, and/or a sample from a `std::tuple`.
|
/// Fill histogram with values, an optional weight, and/or a sample from a `std::tuple`.
|
||||||
template <class... Ts>
|
template <class... Ts>
|
||||||
auto operator()(const std::tuple<Ts...>& t) {
|
iterator operator()(const std::tuple<Ts...>& t) {
|
||||||
return detail::fill(axes_, storage_and_mutex_, t);
|
return detail::fill(axes_, storage_and_mutex_, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access cell value at integral indices.
|
/** Access cell value at integral indices.
|
||||||
/**
|
|
||||||
You can pass indices as individual arguments, as a std::tuple of integers, or as an
|
You can pass indices as individual arguments, as a std::tuple of integers, or as an
|
||||||
interable range of integers. Passing the wrong number of arguments causes a throw of
|
interable range of integers. Passing the wrong number of arguments causes a throw of
|
||||||
std::invalid_argument. Passing an index which is out of bounds causes a throw of
|
std::invalid_argument. Passing an index which is out of bounds causes a throw of
|
||||||
std::out_of_range.
|
std::out_of_range.
|
||||||
|
|
||||||
|
@param i index of first axis.
|
||||||
|
@param is indices of second, third, ... axes.
|
||||||
|
@returns reference to cell value.
|
||||||
*/
|
*/
|
||||||
template <class... Ts>
|
template <class... Indices>
|
||||||
decltype(auto) at(axis::index_type t, Ts... ts) {
|
decltype(auto) at(axis::index_type i, Indices... is) {
|
||||||
return at(std::forward_as_tuple(t, ts...));
|
return at(std::make_tuple(i, is...));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access cell value at integral indices (read-only).
|
/// Access cell value at integral indices (read-only).
|
||||||
/// @copydoc at(axis::index_type t, Ts... ts)
|
template <class... Indices>
|
||||||
template <class... Ts>
|
decltype(auto) at(axis::index_type i, Indices... is) const {
|
||||||
decltype(auto) at(axis::index_type t, Ts... ts) const {
|
return at(std::make_tuple(i, is...));
|
||||||
return at(std::forward_as_tuple(t, ts...));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access cell value at integral indices stored in `std::tuple`.
|
/// Access cell value at integral indices stored in `std::tuple`.
|
||||||
/// @copydoc at(axis::index_type t, Ts... ts)
|
template <typename... Indices>
|
||||||
template <typename... Ts>
|
decltype(auto) at(const std::tuple<axis::index_type, Indices...>& is) {
|
||||||
decltype(auto) at(const std::tuple<Ts...>& t) {
|
const auto idx = detail::at(axes_, is);
|
||||||
const auto idx = detail::at(axes_, t);
|
if (!idx)
|
||||||
if (!idx) BOOST_THROW_EXCEPTION(std::out_of_range("indices out of bounds"));
|
BOOST_THROW_EXCEPTION(std::out_of_range("at least one index out of bounds"));
|
||||||
return storage_and_mutex_.first()[*idx];
|
return storage_and_mutex_.first()[*idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access cell value at integral indices stored in `std::tuple` (read-only).
|
/// Access cell value at integral indices stored in `std::tuple` (read-only).
|
||||||
/// @copydoc at(axis::index_type t, Ts... ts)
|
template <typename... Indices>
|
||||||
template <typename... Ts>
|
decltype(auto) at(const std::tuple<axis::index_type, Indices...>& is) const {
|
||||||
decltype(auto) at(const std::tuple<Ts...>& t) const {
|
const auto idx = detail::at(axes_, is);
|
||||||
const auto idx = detail::at(axes_, t);
|
if (!idx)
|
||||||
if (!idx) BOOST_THROW_EXCEPTION(std::out_of_range("indices out of bounds"));
|
BOOST_THROW_EXCEPTION(std::out_of_range("at least one index out of bounds"));
|
||||||
return storage_and_mutex_.first()[*idx];
|
return storage_and_mutex_.first()[*idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access cell value at integral indices stored in iterable.
|
/// Access cell value at integral indices stored in iterable.
|
||||||
/// @copydoc at(axis::index_type t, Ts... ts)
|
|
||||||
template <class Iterable, class = detail::requires_iterable<Iterable>>
|
template <class Iterable, class = detail::requires_iterable<Iterable>>
|
||||||
decltype(auto) at(const Iterable& c) {
|
decltype(auto) at(const Iterable& is) {
|
||||||
const auto idx = detail::at(axes_, c);
|
const auto idx = detail::at(axes_, is);
|
||||||
if (!idx) BOOST_THROW_EXCEPTION(std::out_of_range("indices out of bounds"));
|
if (!idx)
|
||||||
|
BOOST_THROW_EXCEPTION(std::out_of_range("at least one index out of bounds"));
|
||||||
return storage_and_mutex_.first()[*idx];
|
return storage_and_mutex_.first()[*idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access cell value at integral indices stored in iterable (read-only).
|
/// Access cell value at integral indices stored in iterable (read-only).
|
||||||
/// @copydoc at(axis::index_type t, Ts... ts)
|
|
||||||
template <class Iterable, class = detail::requires_iterable<Iterable>>
|
template <class Iterable, class = detail::requires_iterable<Iterable>>
|
||||||
decltype(auto) at(const Iterable& c) const {
|
decltype(auto) at(const Iterable& is) const {
|
||||||
const auto idx = detail::at(axes_, c);
|
const auto idx = detail::at(axes_, is);
|
||||||
if (!idx) BOOST_THROW_EXCEPTION(std::out_of_range("indices out of bounds"));
|
if (!idx)
|
||||||
|
BOOST_THROW_EXCEPTION(std::out_of_range("at least one index out of bounds"));
|
||||||
return storage_and_mutex_.first()[*idx];
|
return storage_and_mutex_.first()[*idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Access value at index (number for rank = 1, else `std::tuple` or iterable).
|
/// Access value at index (number for rank = 1, else `std::tuple` or iterable).
|
||||||
template <class T>
|
template <class Indices>
|
||||||
decltype(auto) operator[](const T& t) {
|
decltype(auto) operator[](const Indices& is) {
|
||||||
return at(t);
|
return at(is);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @copydoc operator[]
|
/// Access value at index (read-only).
|
||||||
template <class T>
|
template <class Indices>
|
||||||
decltype(auto) operator[](const T& t) const {
|
decltype(auto) operator[](const Indices& is) const {
|
||||||
return at(t);
|
return at(is);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Equality operator, tests equality for all axes and the storage.
|
/// Equality operator, tests equality for all axes and the storage.
|
||||||
@ -266,11 +271,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add values of another histogram.
|
/// Add values of another histogram.
|
||||||
template <class A, class S>
|
template <class A, class S,
|
||||||
|
class = std::enable_if_t<detail::has_operator_radd<
|
||||||
|
value_type, typename histogram<A, S>::value_type>::value>>
|
||||||
histogram& operator+=(const histogram<A, S>& rhs) {
|
histogram& operator+=(const histogram<A, S>& rhs) {
|
||||||
static_assert(detail::has_operator_radd<value_type,
|
|
||||||
typename histogram<A, S>::value_type>::value,
|
|
||||||
"cell value does not support adding value of right-hand-side");
|
|
||||||
if (!detail::axes_equal(axes_, unsafe_access::axes(rhs)))
|
if (!detail::axes_equal(axes_, unsafe_access::axes(rhs)))
|
||||||
BOOST_THROW_EXCEPTION(std::invalid_argument("axes of histograms differ"));
|
BOOST_THROW_EXCEPTION(std::invalid_argument("axes of histograms differ"));
|
||||||
auto rit = unsafe_access::storage(rhs).begin();
|
auto rit = unsafe_access::storage(rhs).begin();
|
||||||
@ -280,11 +284,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Subtract values of another histogram.
|
/// Subtract values of another histogram.
|
||||||
template <class A, class S>
|
template <class A, class S,
|
||||||
|
class = std::enable_if_t<detail::has_operator_rsub<
|
||||||
|
value_type, typename histogram<A, S>::value_type>::value>>
|
||||||
histogram& operator-=(const histogram<A, S>& rhs) {
|
histogram& operator-=(const histogram<A, S>& rhs) {
|
||||||
static_assert(detail::has_operator_rsub<value_type,
|
|
||||||
typename histogram<A, S>::value_type>::value,
|
|
||||||
"cell value does not support subtracting value of right-hand-side");
|
|
||||||
if (!detail::axes_equal(axes_, unsafe_access::axes(rhs)))
|
if (!detail::axes_equal(axes_, unsafe_access::axes(rhs)))
|
||||||
BOOST_THROW_EXCEPTION(std::invalid_argument("axes of histograms differ"));
|
BOOST_THROW_EXCEPTION(std::invalid_argument("axes of histograms differ"));
|
||||||
auto rit = unsafe_access::storage(rhs).begin();
|
auto rit = unsafe_access::storage(rhs).begin();
|
||||||
@ -294,11 +297,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Multiply by values of another histogram.
|
/// Multiply by values of another histogram.
|
||||||
template <class A, class S>
|
template <class A, class S,
|
||||||
|
class = std::enable_if_t<detail::has_operator_rmul<
|
||||||
|
value_type, typename histogram<A, S>::value_type>::value>>
|
||||||
histogram& operator*=(const histogram<A, S>& rhs) {
|
histogram& operator*=(const histogram<A, S>& rhs) {
|
||||||
static_assert(detail::has_operator_rmul<value_type,
|
|
||||||
typename histogram<A, S>::value_type>::value,
|
|
||||||
"cell value does not support multiplying by value of right-hand-side");
|
|
||||||
if (!detail::axes_equal(axes_, unsafe_access::axes(rhs)))
|
if (!detail::axes_equal(axes_, unsafe_access::axes(rhs)))
|
||||||
BOOST_THROW_EXCEPTION(std::invalid_argument("axes of histograms differ"));
|
BOOST_THROW_EXCEPTION(std::invalid_argument("axes of histograms differ"));
|
||||||
auto rit = unsafe_access::storage(rhs).begin();
|
auto rit = unsafe_access::storage(rhs).begin();
|
||||||
@ -308,11 +310,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Divide by values of another histogram.
|
/// Divide by values of another histogram.
|
||||||
template <class A, class S>
|
template <class A, class S,
|
||||||
|
class = std::enable_if_t<detail::has_operator_rdiv<
|
||||||
|
value_type, typename histogram<A, S>::value_type>::value>>
|
||||||
histogram& operator/=(const histogram<A, S>& rhs) {
|
histogram& operator/=(const histogram<A, S>& rhs) {
|
||||||
static_assert(detail::has_operator_rdiv<value_type,
|
|
||||||
typename histogram<A, S>::value_type>::value,
|
|
||||||
"cell value does not support dividing by value of right-hand-side");
|
|
||||||
if (!detail::axes_equal(axes_, unsafe_access::axes(rhs)))
|
if (!detail::axes_equal(axes_, unsafe_access::axes(rhs)))
|
||||||
BOOST_THROW_EXCEPTION(std::invalid_argument("axes of histograms differ"));
|
BOOST_THROW_EXCEPTION(std::invalid_argument("axes of histograms differ"));
|
||||||
auto rit = unsafe_access::storage(rhs).begin();
|
auto rit = unsafe_access::storage(rhs).begin();
|
||||||
@ -372,41 +373,72 @@ private:
|
|||||||
friend struct unsafe_access;
|
friend struct unsafe_access;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Pairwise add cells of two histograms and return histogram with the sum.
|
||||||
|
|
||||||
|
The returned histogram type is the most efficient and safest one constructible from the
|
||||||
|
inputs, if they are not the same type. If one histogram has a tuple axis, the result has
|
||||||
|
a tuple axis. The chosen storage is the one with the larger dynamic range.
|
||||||
|
*/
|
||||||
template <class A1, class S1, class A2, class S2>
|
template <class A1, class S1, class A2, class S2>
|
||||||
auto operator+(const histogram<A1, S1>& a, const histogram<A2, S2>& b) {
|
auto operator+(const histogram<A1, S1>& a, const histogram<A2, S2>& b) {
|
||||||
auto r = histogram<detail::common_axes<A1, A2>, detail::common_storage<S1, S2>>(a);
|
auto r = histogram<detail::common_axes<A1, A2>, detail::common_storage<S1, S2>>(a);
|
||||||
return r += b;
|
return r += b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Pairwise multiply cells of two histograms and return histogram with the product.
|
||||||
|
|
||||||
|
For notes on the returned histogram type, see operator+.
|
||||||
|
*/
|
||||||
template <class A1, class S1, class A2, class S2>
|
template <class A1, class S1, class A2, class S2>
|
||||||
auto operator*(const histogram<A1, S1>& a, const histogram<A2, S2>& b) {
|
auto operator*(const histogram<A1, S1>& a, const histogram<A2, S2>& b) {
|
||||||
auto r = histogram<detail::common_axes<A1, A2>, detail::common_storage<S1, S2>>(a);
|
auto r = histogram<detail::common_axes<A1, A2>, detail::common_storage<S1, S2>>(a);
|
||||||
return r *= b;
|
return r *= b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Pairwise subtract cells of two histograms and return histogram with the difference.
|
||||||
|
|
||||||
|
For notes on the returned histogram type, see operator+.
|
||||||
|
*/
|
||||||
template <class A1, class S1, class A2, class S2>
|
template <class A1, class S1, class A2, class S2>
|
||||||
auto operator-(const histogram<A1, S1>& a, const histogram<A2, S2>& b) {
|
auto operator-(const histogram<A1, S1>& a, const histogram<A2, S2>& b) {
|
||||||
auto r = histogram<detail::common_axes<A1, A2>, detail::common_storage<S1, S2>>(a);
|
auto r = histogram<detail::common_axes<A1, A2>, detail::common_storage<S1, S2>>(a);
|
||||||
return r -= b;
|
return r -= b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Pairwise divide cells of two histograms and return histogram with the quotient.
|
||||||
|
|
||||||
|
For notes on the returned histogram type, see operator+.
|
||||||
|
*/
|
||||||
template <class A1, class S1, class A2, class S2>
|
template <class A1, class S1, class A2, class S2>
|
||||||
auto operator/(const histogram<A1, S1>& a, const histogram<A2, S2>& b) {
|
auto operator/(const histogram<A1, S1>& a, const histogram<A2, S2>& b) {
|
||||||
auto r = histogram<detail::common_axes<A1, A2>, detail::common_storage<S1, S2>>(a);
|
auto r = histogram<detail::common_axes<A1, A2>, detail::common_storage<S1, S2>>(a);
|
||||||
return r /= b;
|
return r /= b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Multiply all cells of the histogram by a number and return a new histogram.
|
||||||
|
|
||||||
|
If the original histogram has integer cells, the result has double cells.
|
||||||
|
*/
|
||||||
template <class A, class S>
|
template <class A, class S>
|
||||||
auto operator*(const histogram<A, S>& h, double x) {
|
auto operator*(const histogram<A, S>& h, double x) {
|
||||||
auto r = histogram<A, detail::common_storage<S, dense_storage<double>>>(h);
|
auto r = histogram<A, detail::common_storage<S, dense_storage<double>>>(h);
|
||||||
return r *= x;
|
return r *= x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Multiply all cells of the histogram by a number and return a new histogram.
|
||||||
|
|
||||||
|
If the original histogram has integer cells, the result has double cells.
|
||||||
|
*/
|
||||||
template <class A, class S>
|
template <class A, class S>
|
||||||
auto operator*(double x, const histogram<A, S>& h) {
|
auto operator*(double x, const histogram<A, S>& h) {
|
||||||
return h * x;
|
return h * x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Divide all cells of the histogram by a number and return a new histogram.
|
||||||
|
|
||||||
|
If the original histogram has integer cells, the result has double cells.
|
||||||
|
*/
|
||||||
template <class A, class S>
|
template <class A, class S>
|
||||||
auto operator/(const histogram<A, S>& h, double x) {
|
auto operator/(const histogram<A, S>& h, double x) {
|
||||||
return h * (1.0 / x);
|
return h * (1.0 / x);
|
||||||
@ -423,21 +455,24 @@ histogram(Axes&& axes, Storage&& storage)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// Helper function to mark argument as weight.
|
/** Helper function to mark argument as weight.
|
||||||
/// @param t argument to be forward to the histogram.
|
|
||||||
|
@param t argument to be forward to the histogram.
|
||||||
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
auto weight(T&& t) noexcept {
|
auto weight(T&& t) noexcept {
|
||||||
return weight_type<T>{std::forward<T>(t)};
|
return weight_type<T>{std::forward<T>(t)};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper function to mark arguments as sample.
|
/** Helper function to mark arguments as sample.
|
||||||
/// @param ts arguments to be forwarded to the accumulator.
|
|
||||||
|
@param ts arguments to be forwarded to the accumulator.
|
||||||
|
*/
|
||||||
template <typename... Ts>
|
template <typename... Ts>
|
||||||
auto sample(Ts&&... ts) noexcept {
|
auto sample(Ts&&... ts) noexcept {
|
||||||
return sample_type<std::tuple<Ts...>>{std::forward_as_tuple(std::forward<Ts>(ts)...)};
|
return sample_type<std::tuple<Ts...>>{std::forward_as_tuple(std::forward<Ts>(ts)...)};
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef BOOST_HISTOGRAM_DOXYGEN_INVOKED
|
|
||||||
template <class T>
|
template <class T>
|
||||||
struct weight_type {
|
struct weight_type {
|
||||||
T value;
|
T value;
|
||||||
@ -447,7 +482,6 @@ template <class T>
|
|||||||
struct sample_type {
|
struct sample_type {
|
||||||
T value;
|
T value;
|
||||||
};
|
};
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace histogram
|
} // namespace histogram
|
||||||
} // namespace boost
|
} // namespace boost
|
||||||
|
@ -30,7 +30,9 @@ namespace histogram {
|
|||||||
@param axis First axis instance.
|
@param axis First axis instance.
|
||||||
@param axes Other axis instances.
|
@param axes Other axis instances.
|
||||||
*/
|
*/
|
||||||
template <class Storage, class Axis, class... Axes, class = detail::requires_axis<Axis>>
|
template <class Storage, class Axis, class... Axes,
|
||||||
|
class = detail::requires_storage_or_adaptible<Storage>,
|
||||||
|
class = detail::requires_axis<Axis>>
|
||||||
auto make_histogram_with(Storage&& storage, Axis&& axis, Axes&&... axes) {
|
auto make_histogram_with(Storage&& storage, Axis&& axis, Axes&&... axes) {
|
||||||
auto a = std::make_tuple(std::forward<Axis>(axis), std::forward<Axes>(axes)...);
|
auto a = std::make_tuple(std::forward<Axis>(axis), std::forward<Axes>(axes)...);
|
||||||
using U = detail::remove_cvref_t<Storage>;
|
using U = detail::remove_cvref_t<Storage>;
|
||||||
@ -66,6 +68,7 @@ auto make_weighted_histogram(Axis&& axis, Axes&&... axes) {
|
|||||||
@param iterable Iterable range of axis objects.
|
@param iterable Iterable range of axis objects.
|
||||||
*/
|
*/
|
||||||
template <class Storage, class Iterable,
|
template <class Storage, class Iterable,
|
||||||
|
class = detail::requires_storage_or_adaptible<Storage>,
|
||||||
class = detail::requires_sequence_of_any_axis<Iterable>>
|
class = detail::requires_sequence_of_any_axis<Iterable>>
|
||||||
auto make_histogram_with(Storage&& storage, Iterable&& iterable) {
|
auto make_histogram_with(Storage&& storage, Iterable&& iterable) {
|
||||||
using U = detail::remove_cvref_t<Storage>;
|
using U = detail::remove_cvref_t<Storage>;
|
||||||
@ -101,7 +104,9 @@ auto make_weighted_histogram(Iterable&& iterable) {
|
|||||||
@param begin Iterator to range of axis objects.
|
@param begin Iterator to range of axis objects.
|
||||||
@param end Iterator to range of axis objects.
|
@param end Iterator to range of axis objects.
|
||||||
*/
|
*/
|
||||||
template <class Storage, class Iterator, class = detail::requires_iterator<Iterator>>
|
template <class Storage, class Iterator,
|
||||||
|
class = detail::requires_storage_or_adaptible<Storage>,
|
||||||
|
class = detail::requires_iterator<Iterator>>
|
||||||
auto make_histogram_with(Storage&& storage, Iterator begin, Iterator end) {
|
auto make_histogram_with(Storage&& storage, Iterator begin, Iterator end) {
|
||||||
using T = detail::remove_cvref_t<decltype(*begin)>;
|
using T = detail::remove_cvref_t<decltype(*begin)>;
|
||||||
return make_histogram_with(std::forward<Storage>(storage), std::vector<T>(begin, end));
|
return make_histogram_with(std::forward<Storage>(storage), std::vector<T>(begin, end));
|
||||||
|
@ -172,8 +172,8 @@ void serialize(Archive& ar, large_int<Allocator>& x, unsigned /* version */) {
|
|||||||
|
|
||||||
template <class Archive, class T>
|
template <class Archive, class T>
|
||||||
void serialize(Archive& ar, storage_adaptor<T>& x, unsigned /* version */) {
|
void serialize(Archive& ar, storage_adaptor<T>& x, unsigned /* version */) {
|
||||||
using impl_t = typename storage_adaptor<T>::base_type;
|
auto& impl = unsafe_access::storage_adaptor_impl(x);
|
||||||
ar& serialization::make_nvp("impl", static_cast<impl_t&>(x));
|
ar& serialization::make_nvp("impl", impl);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Allocator, class Archive>
|
template <class Allocator, class Archive>
|
||||||
|
@ -336,9 +336,9 @@ using storage_adaptor_impl =
|
|||||||
/// Turns any vector-like, array-like, and map-like container into a storage type.
|
/// Turns any vector-like, array-like, and map-like container into a storage type.
|
||||||
template <class T>
|
template <class T>
|
||||||
class storage_adaptor : public detail::storage_adaptor_impl<T> {
|
class storage_adaptor : public detail::storage_adaptor_impl<T> {
|
||||||
public:
|
using impl_type = detail::storage_adaptor_impl<T>;
|
||||||
using base_type = detail::storage_adaptor_impl<T>;
|
|
||||||
|
|
||||||
|
public:
|
||||||
// standard copy, move, assign
|
// standard copy, move, assign
|
||||||
storage_adaptor(storage_adaptor&&) = default;
|
storage_adaptor(storage_adaptor&&) = default;
|
||||||
storage_adaptor(const storage_adaptor&) = default;
|
storage_adaptor(const storage_adaptor&) = default;
|
||||||
@ -347,12 +347,12 @@ public:
|
|||||||
|
|
||||||
// forwarding constructor
|
// forwarding constructor
|
||||||
template <class... Ts>
|
template <class... Ts>
|
||||||
storage_adaptor(Ts&&... ts) : base_type(std::forward<Ts>(ts)...) {}
|
storage_adaptor(Ts&&... ts) : impl_type(std::forward<Ts>(ts)...) {}
|
||||||
|
|
||||||
// forwarding assign
|
// forwarding assign
|
||||||
template <class U>
|
template <class U>
|
||||||
storage_adaptor& operator=(U&& u) {
|
storage_adaptor& operator=(U&& u) {
|
||||||
base_type::operator=(std::forward<U>(u));
|
impl_type::operator=(std::forward<U>(u));
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -362,6 +362,9 @@ public:
|
|||||||
using std::end;
|
using std::end;
|
||||||
return std::equal(this->begin(), this->end(), begin(u), end(u), detail::equal{});
|
return std::equal(this->begin(), this->end(), begin(u), end(u), detail::equal{});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
friend struct unsafe_access;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace histogram
|
} // namespace histogram
|
||||||
|
@ -132,7 +132,6 @@ public:
|
|||||||
using large_int = detail::large_int<
|
using large_int = detail::large_int<
|
||||||
typename std::allocator_traits<allocator_type>::template rebind_alloc<uint64_t>>;
|
typename std::allocator_traits<allocator_type>::template rebind_alloc<uint64_t>>;
|
||||||
|
|
||||||
private:
|
|
||||||
struct buffer_type {
|
struct buffer_type {
|
||||||
// cannot be moved outside of scope of unlimited_storage, large_int is dependent type
|
// cannot be moved outside of scope of unlimited_storage, large_int is dependent type
|
||||||
using types = mp11::mp_list<uint8_t, uint16_t, uint32_t, uint64_t, large_int, double>;
|
using types = mp11::mp_list<uint8_t, uint16_t, uint32_t, uint64_t, large_int, double>;
|
||||||
@ -246,12 +245,14 @@ private:
|
|||||||
mutable void* ptr = nullptr;
|
mutable void* ptr = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
|
||||||
class reference; // forward declare to make friend of const_reference
|
class reference; // forward declare to make friend of const_reference
|
||||||
|
|
||||||
|
/// implementation detail
|
||||||
class const_reference {
|
class const_reference {
|
||||||
public:
|
public:
|
||||||
const_reference(buffer_type& b, std::size_t i) : bref_(b), idx_(i) {}
|
const_reference(buffer_type& b, std::size_t i) : bref_(b), idx_(i) {
|
||||||
|
BOOST_ASSERT(idx_ < bref_.size);
|
||||||
|
}
|
||||||
|
|
||||||
const_reference(const const_reference&) = default;
|
const_reference(const const_reference&) = default;
|
||||||
|
|
||||||
@ -355,6 +356,7 @@ public:
|
|||||||
friend class reference;
|
friend class reference;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// implementation detail
|
||||||
class reference : public const_reference {
|
class reference : public const_reference {
|
||||||
public:
|
public:
|
||||||
reference(buffer_type& b, std::size_t i) : const_reference(b, i) {}
|
reference(buffer_type& b, std::size_t i) : const_reference(b, i) {}
|
||||||
@ -425,28 +427,28 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
template <class Value, class Reference>
|
template <class Value, class Reference>
|
||||||
class iterator_t : public detail::iterator_adaptor<iterator_t<Value, Reference>,
|
class iterator_impl : public detail::iterator_adaptor<iterator_impl<Value, Reference>,
|
||||||
std::size_t, Reference, Value> {
|
std::size_t, Reference, Value> {
|
||||||
public:
|
public:
|
||||||
iterator_t() = default;
|
iterator_impl() = default;
|
||||||
template <class V, class R>
|
template <class V, class R>
|
||||||
iterator_t(const iterator_t<V, R>& it)
|
iterator_impl(const iterator_impl<V, R>& it)
|
||||||
: iterator_t::iterator_adaptor_(it.base()), buffer_(it.buffer_) {}
|
: iterator_impl::iterator_adaptor_(it.base()), buffer_(it.buffer_) {}
|
||||||
iterator_t(buffer_type* b, std::size_t i) noexcept
|
iterator_impl(buffer_type* b, std::size_t i) noexcept
|
||||||
: iterator_t::iterator_adaptor_(i), buffer_(b) {}
|
: iterator_impl::iterator_adaptor_(i), buffer_(b) {}
|
||||||
|
|
||||||
Reference operator*() const noexcept { return {*buffer_, this->base()}; }
|
Reference operator*() const noexcept { return {*buffer_, this->base()}; }
|
||||||
|
|
||||||
template <class V, class R>
|
template <class V, class R>
|
||||||
friend class iterator_t;
|
friend class iterator_impl;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
mutable buffer_type* buffer_ = nullptr;
|
mutable buffer_type* buffer_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using const_iterator = iterator_t<const value_type, const_reference>;
|
using const_iterator = iterator_impl<const value_type, const_reference>;
|
||||||
using iterator = iterator_t<value_type, reference>;
|
using iterator = iterator_impl<value_type, reference>;
|
||||||
|
|
||||||
explicit unlimited_storage(const allocator_type& a = {}) : buffer_(a) {}
|
explicit unlimited_storage(const allocator_type& a = {}) : buffer_(a) {}
|
||||||
unlimited_storage(const unlimited_storage&) = default;
|
unlimited_storage(const unlimited_storage&) = default;
|
||||||
@ -517,6 +519,7 @@ private:
|
|||||||
struct incrementor {
|
struct incrementor {
|
||||||
template <class T>
|
template <class T>
|
||||||
void operator()(T* tp, buffer_type& b, std::size_t i) {
|
void operator()(T* tp, buffer_type& b, std::size_t i) {
|
||||||
|
BOOST_ASSERT(tp && i < b.size);
|
||||||
if (!detail::safe_increment(tp[i])) {
|
if (!detail::safe_increment(tp[i])) {
|
||||||
using U = detail::next_type<typename buffer_type::types, T>;
|
using U = detail::next_type<typename buffer_type::types, T>;
|
||||||
b.template make<U>(b.size, tp);
|
b.template make<U>(b.size, tp);
|
||||||
|
@ -82,6 +82,15 @@ struct unsafe_access {
|
|||||||
static constexpr auto& unlimited_storage_buffer(unlimited_storage<Allocator>& storage) {
|
static constexpr auto& unlimited_storage_buffer(unlimited_storage<Allocator>& storage) {
|
||||||
return storage.buffer_;
|
return storage.buffer_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get implementation of storage_adaptor.
|
||||||
|
@param storage instance of storage_adaptor.
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
static constexpr auto& storage_adaptor_impl(storage_adaptor<T>& storage) {
|
||||||
|
return static_cast<typename storage_adaptor<T>::impl_type&>(storage);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace histogram
|
} // namespace histogram
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
|
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
# keep in sync with Jamfile
|
# keep in sync with Jamfile
|
||||||
|
boost_test(TYPE compile-fail SOURCES make_histogram_fail0.cpp)
|
||||||
|
boost_test(TYPE compile-fail SOURCES make_histogram_fail1.cpp)
|
||||||
boost_test(TYPE run SOURCES algorithm_project_test.cpp
|
boost_test(TYPE run SOURCES algorithm_project_test.cpp
|
||||||
LIBRARIES Boost::histogram Boost::core)
|
LIBRARIES Boost::histogram Boost::core)
|
||||||
boost_test(TYPE run SOURCES algorithm_reduce_test.cpp
|
boost_test(TYPE run SOURCES algorithm_reduce_test.cpp
|
||||||
|
@ -34,6 +34,8 @@ project
|
|||||||
;
|
;
|
||||||
|
|
||||||
alias cxx14 :
|
alias cxx14 :
|
||||||
|
[ compile-fail make_histogram_fail0.cpp ]
|
||||||
|
[ compile-fail make_histogram_fail1.cpp ]
|
||||||
[ run algorithm_project_test.cpp ]
|
[ run algorithm_project_test.cpp ]
|
||||||
[ run algorithm_reduce_test.cpp ]
|
[ run algorithm_reduce_test.cpp ]
|
||||||
[ run algorithm_sum_test.cpp ]
|
[ run algorithm_sum_test.cpp ]
|
||||||
|
@ -134,19 +134,6 @@ int main() {
|
|||||||
BOOST_TEST_THROWS(detail::bincount(v), std::overflow_error);
|
BOOST_TEST_THROWS(detail::bincount(v), std::overflow_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// common_container
|
|
||||||
{
|
|
||||||
using A = std::array<int, 10>;
|
|
||||||
using B = std::vector<int>;
|
|
||||||
using C = std::map<std::size_t, int>;
|
|
||||||
BOOST_TEST_TRAIT_SAME(detail::common_container<A, B>, A);
|
|
||||||
BOOST_TEST_TRAIT_SAME(detail::common_container<B, A>, A);
|
|
||||||
BOOST_TEST_TRAIT_SAME(detail::common_container<A, C>, A);
|
|
||||||
BOOST_TEST_TRAIT_SAME(detail::common_container<C, A>, A);
|
|
||||||
BOOST_TEST_TRAIT_SAME(detail::common_container<C, B>, B);
|
|
||||||
BOOST_TEST_TRAIT_SAME(detail::common_container<B, C>, B);
|
|
||||||
}
|
|
||||||
|
|
||||||
// common_storage
|
// common_storage
|
||||||
{
|
{
|
||||||
BOOST_TEST_TRAIT_SAME(
|
BOOST_TEST_TRAIT_SAME(
|
||||||
|
@ -513,6 +513,8 @@ void run_tests() {
|
|||||||
BOOST_TEST_EQ(h.at(j11), 1);
|
BOOST_TEST_EQ(h.at(j11), 1);
|
||||||
BOOST_TEST_EQ(h[j11], 1);
|
BOOST_TEST_EQ(h[j11], 1);
|
||||||
BOOST_TEST_THROWS((void)h.at(j111), std::invalid_argument);
|
BOOST_TEST_THROWS((void)h.at(j111), std::invalid_argument);
|
||||||
|
int j13[] = {1, 3};
|
||||||
|
BOOST_TEST_THROWS((void)h.at(j13), std::out_of_range);
|
||||||
|
|
||||||
// tuple with weight
|
// tuple with weight
|
||||||
h(std::make_tuple(weight(2), 0, 2.0));
|
h(std::make_tuple(weight(2), 0, 2.0));
|
||||||
|
14
test/make_histogram_fail0.cpp
Normal file
14
test/make_histogram_fail0.cpp
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// Copyright 2019 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)
|
||||||
|
|
||||||
|
#include <boost/histogram/make_histogram.hpp>
|
||||||
|
|
||||||
|
using namespace boost::histogram;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// argument is not an axis
|
||||||
|
(void)make_histogram(std::vector<int>{});
|
||||||
|
}
|
16
test/make_histogram_fail1.cpp
Normal file
16
test/make_histogram_fail1.cpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
// Copyright 2019 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)
|
||||||
|
|
||||||
|
#include <boost/histogram/axis/regular.hpp>
|
||||||
|
#include <boost/histogram/make_histogram.hpp>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
using namespace boost::histogram;
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
// first and second arguments switched
|
||||||
|
(void)make_histogram_with(axis::regular<>(3, 0, 1), std::vector<int>{});
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user