More doc improvements

This commit is contained in:
Hans Dembinski 2019-04-28 12:22:49 +02:00 committed by GitHub
parent 22ec005290
commit 073dffdf09
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 278 additions and 178 deletions

View File

@ -40,7 +40,6 @@ actions doxygen_postprocessing
boostbook histogram
:
histogram.qbk
reference_pp.xml
:
<xsl:param>boost.root=../../../..
<xsl:param>boost.libraries=../../../libraries.htm
@ -48,6 +47,7 @@ boostbook histogram
<xsl:param>chunk.first.sections=1
<xsl:param>generate.section.toc.level=1
<xsl:param>generate.toc="chapter nop section nop"
<dependency>reference_pp.xml
;
alias boostdoc ;

View File

@ -1,50 +1,95 @@
from __future__ import print_function
import sys
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])
root = tree.getroot()
parent_map = {c:p for p in tree.iter() for c in p}
unspecified = ET.Element("emphasis")
unspecified.text = "unspecified"
# hide all unnamed template parameters, these are used for SFINAE
for item in root.iter("template-type-parameter"):
if not item.get("name"):
for item in select(lambda x: x.get("name") == "", "template-type-parameter"):
parent = parent_map[item]
assert parent.tag == "template"
parent.remove(item)
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 "implementation_defined"
for item in root.iter("type"):
if not item.text:
continue
if "detail" in item.text:
item.text = "implementation_defined"
# 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
for item in root.iter("method-group"):
if item.get("name") == "private member functions":
parent_map[item].remove(item)
for item in select(lambda x: x.get("name") == "private member functions", "method-group"):
parent = parent_map[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
for tag in ("class", "struct", "function"):
for item in root.iter(tag):
# hide undocumented classes, structs, functions and replace those declared
# "implementation detail" with typedef to implementation_defined
for item in select(lambda x:True, "class", "struct", "function"):
purpose = item.find("purpose")
if purpose is None:
parent = parent_map[item]
log("removing undocumented", item.tag, item.get("name"), "from",
parent.tag, parent.get("name"))
parent_map[item].remove(item)
elif purpose.text.strip().lower() == "implementation detail":
log("replacing", item.tag, item.get("name"), "with unspecified typedef")
name = item.get("name")
item.clear()
item.tag = "typedef"
item.set("name", name)
type = ET.Element("type")
type.text = "implementation_defined"
type.append(unspecified)
item.append(type)
# hide methods and constructors explicitly declared as "implementation detail"
for tag in ("constructor", "method"):
for item in root.iter(tag):
purpose = item.find("purpose")
if purpose is not None and purpose.text.strip() == "implementation detail":
for item in select(is_detail, "constructor", "method"):
name = item.get("name")
log("removing", (item.tag + " " + name) if name is not None else item.tag,
"declared as implementation detail")
parent_map[item].remove(item)
tree.write(sys.argv[2])

View File

@ -26,51 +26,20 @@ using common_axes = mp11::mp_cond<
is_sequence_of_axis<U>, U,
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
template <class T>
using type_score = mp11::mp_size_t<((!std::is_pod<T>::value) * 1000 +
std::is_floating_point<T>::value * 50 + sizeof(T))>;
// Non-PODs rank highest, then floats, than integers; types with more capacity are higher
template <class Storage>
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>
struct common_storage_impl;
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;
using common_storage = mp11::mp_if_c<(type_rank<T>() >= type_rank<U>()), T, U>;
} // namespace detail
} // namespace histogram
} // namespace boost

View File

@ -215,9 +215,18 @@ BOOST_HISTOGRAM_DETECT_BINARY(has_operator_rmul,
BOOST_HISTOGRAM_DETECT_BINARY(has_operator_rdiv,
(std::declval<T&>() /= std::declval<U&>()));
BOOST_HISTOGRAM_DETECT(has_threading_support, (T::has_threading_support));
template <typename T>
using is_storage =
mp11::mp_bool<(is_indexable_container<T>::value && has_method_reset<T>::value)>;
using is_storage = mp11::mp_and<is_indexable_container<T>, has_method_reset<T>,
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>
struct is_tuple_impl : std::false_type {};

View File

@ -15,6 +15,7 @@
#include <boost/histogram/detail/noop_mutex.hpp>
#include <boost/histogram/detail/static_if.hpp>
#include <boost/histogram/fwd.hpp>
#include <boost/histogram/storage_adaptor.hpp>
#include <boost/mp11/list.hpp>
#include <boost/throw_exception.hpp>
#include <mutex>
@ -22,6 +23,7 @@
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
namespace boost {
namespace histogram {
@ -135,7 +137,7 @@ public:
}
/// 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 {
detail::axis_index_is_valid(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
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__
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
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.
__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>
auto operator()(const Ts&... ts) {
iterator operator()(const Ts&... ts) {
return operator()(std::make_tuple(ts...));
}
/// Fill histogram with values, an optional weight, and/or a sample from a `std::tuple`.
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);
}
/// 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
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::out_of_range.
@param i index of first axis.
@param is indices of second, third, ... axes.
@returns reference to cell value.
*/
template <class... Ts>
decltype(auto) at(axis::index_type t, Ts... ts) {
return at(std::forward_as_tuple(t, ts...));
template <class... Indices>
decltype(auto) at(axis::index_type i, Indices... is) {
return at(std::make_tuple(i, is...));
}
/// Access cell value at integral indices (read-only).
/// @copydoc at(axis::index_type t, Ts... ts)
template <class... Ts>
decltype(auto) at(axis::index_type t, Ts... ts) const {
return at(std::forward_as_tuple(t, ts...));
template <class... Indices>
decltype(auto) at(axis::index_type i, Indices... is) const {
return at(std::make_tuple(i, is...));
}
/// Access cell value at integral indices stored in `std::tuple`.
/// @copydoc at(axis::index_type t, Ts... ts)
template <typename... Ts>
decltype(auto) at(const std::tuple<Ts...>& t) {
const auto idx = detail::at(axes_, t);
if (!idx) BOOST_THROW_EXCEPTION(std::out_of_range("indices out of bounds"));
template <typename... Indices>
decltype(auto) at(const std::tuple<axis::index_type, Indices...>& is) {
const auto idx = detail::at(axes_, is);
if (!idx)
BOOST_THROW_EXCEPTION(std::out_of_range("at least one index out of bounds"));
return storage_and_mutex_.first()[*idx];
}
/// Access cell value at integral indices stored in `std::tuple` (read-only).
/// @copydoc at(axis::index_type t, Ts... ts)
template <typename... Ts>
decltype(auto) at(const std::tuple<Ts...>& t) const {
const auto idx = detail::at(axes_, t);
if (!idx) BOOST_THROW_EXCEPTION(std::out_of_range("indices out of bounds"));
template <typename... Indices>
decltype(auto) at(const std::tuple<axis::index_type, Indices...>& is) const {
const auto idx = detail::at(axes_, is);
if (!idx)
BOOST_THROW_EXCEPTION(std::out_of_range("at least one index out of bounds"));
return storage_and_mutex_.first()[*idx];
}
/// 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>>
decltype(auto) at(const Iterable& c) {
const auto idx = detail::at(axes_, c);
if (!idx) BOOST_THROW_EXCEPTION(std::out_of_range("indices out of bounds"));
decltype(auto) at(const Iterable& is) {
const auto idx = detail::at(axes_, is);
if (!idx)
BOOST_THROW_EXCEPTION(std::out_of_range("at least one index out of bounds"));
return storage_and_mutex_.first()[*idx];
}
/// 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>>
decltype(auto) at(const Iterable& c) const {
const auto idx = detail::at(axes_, c);
if (!idx) BOOST_THROW_EXCEPTION(std::out_of_range("indices out of bounds"));
decltype(auto) at(const Iterable& is) const {
const auto idx = detail::at(axes_, is);
if (!idx)
BOOST_THROW_EXCEPTION(std::out_of_range("at least one index out of bounds"));
return storage_and_mutex_.first()[*idx];
}
/// Access value at index (number for rank = 1, else `std::tuple` or iterable).
template <class T>
decltype(auto) operator[](const T& t) {
return at(t);
template <class Indices>
decltype(auto) operator[](const Indices& is) {
return at(is);
}
/// @copydoc operator[]
template <class T>
decltype(auto) operator[](const T& t) const {
return at(t);
/// Access value at index (read-only).
template <class Indices>
decltype(auto) operator[](const Indices& is) const {
return at(is);
}
/// Equality operator, tests equality for all axes and the storage.
@ -266,11 +271,10 @@ public:
}
/// 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) {
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)))
BOOST_THROW_EXCEPTION(std::invalid_argument("axes of histograms differ"));
auto rit = unsafe_access::storage(rhs).begin();
@ -280,11 +284,10 @@ public:
}
/// 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) {
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)))
BOOST_THROW_EXCEPTION(std::invalid_argument("axes of histograms differ"));
auto rit = unsafe_access::storage(rhs).begin();
@ -294,11 +297,10 @@ public:
}
/// 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) {
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)))
BOOST_THROW_EXCEPTION(std::invalid_argument("axes of histograms differ"));
auto rit = unsafe_access::storage(rhs).begin();
@ -308,11 +310,10 @@ public:
}
/// 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) {
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)))
BOOST_THROW_EXCEPTION(std::invalid_argument("axes of histograms differ"));
auto rit = unsafe_access::storage(rhs).begin();
@ -372,41 +373,72 @@ private:
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>
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);
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>
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);
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>
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);
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>
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);
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>
auto operator*(const histogram<A, S>& h, double x) {
auto r = histogram<A, detail::common_storage<S, dense_storage<double>>>(h);
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>
auto operator*(double x, const histogram<A, S>& h) {
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>
auto operator/(const histogram<A, S>& h, double x) {
return h * (1.0 / x);
@ -423,21 +455,24 @@ histogram(Axes&& axes, Storage&& storage)
#endif
/// Helper function to mark argument as weight.
/// @param t argument to be forward to the histogram.
/** Helper function to mark argument as weight.
@param t argument to be forward to the histogram.
*/
template <typename T>
auto weight(T&& t) noexcept {
return weight_type<T>{std::forward<T>(t)};
}
/// Helper function to mark arguments as sample.
/// @param ts arguments to be forwarded to the accumulator.
/** Helper function to mark arguments as sample.
@param ts arguments to be forwarded to the accumulator.
*/
template <typename... Ts>
auto sample(Ts&&... ts) noexcept {
return sample_type<std::tuple<Ts...>>{std::forward_as_tuple(std::forward<Ts>(ts)...)};
}
#ifndef BOOST_HISTOGRAM_DOXYGEN_INVOKED
template <class T>
struct weight_type {
T value;
@ -447,7 +482,6 @@ template <class T>
struct sample_type {
T value;
};
#endif
} // namespace histogram
} // namespace boost

View File

@ -30,7 +30,9 @@ namespace histogram {
@param axis First axis instance.
@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 a = std::make_tuple(std::forward<Axis>(axis), std::forward<Axes>(axes)...);
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.
*/
template <class Storage, class Iterable,
class = detail::requires_storage_or_adaptible<Storage>,
class = detail::requires_sequence_of_any_axis<Iterable>>
auto make_histogram_with(Storage&& storage, Iterable&& iterable) {
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 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) {
using T = detail::remove_cvref_t<decltype(*begin)>;
return make_histogram_with(std::forward<Storage>(storage), std::vector<T>(begin, end));

View File

@ -172,8 +172,8 @@ void serialize(Archive& ar, large_int<Allocator>& x, unsigned /* version */) {
template <class Archive, class T>
void serialize(Archive& ar, storage_adaptor<T>& x, unsigned /* version */) {
using impl_t = typename storage_adaptor<T>::base_type;
ar& serialization::make_nvp("impl", static_cast<impl_t&>(x));
auto& impl = unsafe_access::storage_adaptor_impl(x);
ar& serialization::make_nvp("impl", impl);
}
template <class Allocator, class Archive>

View File

@ -336,9 +336,9 @@ using storage_adaptor_impl =
/// Turns any vector-like, array-like, and map-like container into a storage type.
template <class T>
class storage_adaptor : public detail::storage_adaptor_impl<T> {
public:
using base_type = detail::storage_adaptor_impl<T>;
using impl_type = detail::storage_adaptor_impl<T>;
public:
// standard copy, move, assign
storage_adaptor(storage_adaptor&&) = default;
storage_adaptor(const storage_adaptor&) = default;
@ -347,12 +347,12 @@ public:
// forwarding constructor
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
template <class U>
storage_adaptor& operator=(U&& u) {
base_type::operator=(std::forward<U>(u));
impl_type::operator=(std::forward<U>(u));
return *this;
}
@ -362,6 +362,9 @@ public:
using std::end;
return std::equal(this->begin(), this->end(), begin(u), end(u), detail::equal{});
}
private:
friend struct unsafe_access;
};
} // namespace histogram

View File

@ -132,7 +132,6 @@ public:
using large_int = detail::large_int<
typename std::allocator_traits<allocator_type>::template rebind_alloc<uint64_t>>;
private:
struct buffer_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>;
@ -246,12 +245,14 @@ private:
mutable void* ptr = nullptr;
};
public:
class reference; // forward declare to make friend of const_reference
/// implementation detail
class const_reference {
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;
@ -355,6 +356,7 @@ public:
friend class reference;
};
/// implementation detail
class reference : public const_reference {
public:
reference(buffer_type& b, std::size_t i) : const_reference(b, i) {}
@ -425,28 +427,28 @@ public:
private:
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> {
public:
iterator_t() = default;
iterator_impl() = default;
template <class V, class R>
iterator_t(const iterator_t<V, R>& it)
: iterator_t::iterator_adaptor_(it.base()), buffer_(it.buffer_) {}
iterator_t(buffer_type* b, std::size_t i) noexcept
: iterator_t::iterator_adaptor_(i), buffer_(b) {}
iterator_impl(const iterator_impl<V, R>& it)
: iterator_impl::iterator_adaptor_(it.base()), buffer_(it.buffer_) {}
iterator_impl(buffer_type* b, std::size_t i) noexcept
: iterator_impl::iterator_adaptor_(i), buffer_(b) {}
Reference operator*() const noexcept { return {*buffer_, this->base()}; }
template <class V, class R>
friend class iterator_t;
friend class iterator_impl;
private:
mutable buffer_type* buffer_ = nullptr;
};
public:
using const_iterator = iterator_t<const value_type, const_reference>;
using iterator = iterator_t<value_type, reference>;
using const_iterator = iterator_impl<const value_type, const_reference>;
using iterator = iterator_impl<value_type, reference>;
explicit unlimited_storage(const allocator_type& a = {}) : buffer_(a) {}
unlimited_storage(const unlimited_storage&) = default;
@ -517,6 +519,7 @@ private:
struct incrementor {
template <class T>
void operator()(T* tp, buffer_type& b, std::size_t i) {
BOOST_ASSERT(tp && i < b.size);
if (!detail::safe_increment(tp[i])) {
using U = detail::next_type<typename buffer_type::types, T>;
b.template make<U>(b.size, tp);

View File

@ -82,6 +82,15 @@ struct unsafe_access {
static constexpr auto& unlimited_storage_buffer(unlimited_storage<Allocator>& storage) {
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

View File

@ -3,6 +3,8 @@
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
# 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
LIBRARIES Boost::histogram Boost::core)
boost_test(TYPE run SOURCES algorithm_reduce_test.cpp

View File

@ -34,6 +34,8 @@ project
;
alias cxx14 :
[ compile-fail make_histogram_fail0.cpp ]
[ compile-fail make_histogram_fail1.cpp ]
[ run algorithm_project_test.cpp ]
[ run algorithm_reduce_test.cpp ]
[ run algorithm_sum_test.cpp ]

View File

@ -134,19 +134,6 @@ int main() {
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
{
BOOST_TEST_TRAIT_SAME(

View File

@ -513,6 +513,8 @@ void run_tests() {
BOOST_TEST_EQ(h.at(j11), 1);
BOOST_TEST_EQ(h[j11], 1);
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
h(std::make_tuple(weight(2), 0, 2.0));

View 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>{});
}

View 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>{});
}