msvc fixes, simplification and bug-fixes of mp_int, more test coverage (#159)

* fixes broken msvc build
* smaller xml files for testing serialization
* fixing many warnings on msvc
* bug-fixes to mp_int regarding operators and new tests to check their behavior 
* don't expect iterable histogram::at to have size method
* build benchmarks in release mode
* test everything by default when b2 is run on project directory
* more test coverage
This commit is contained in:
Hans Dembinski 2019-02-18 10:04:27 +01:00 committed by GitHub
parent 9abbe46e3d
commit 2568a68f76
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 489 additions and 38822 deletions

View File

@ -36,14 +36,6 @@ matrix:
script:
- ../../b2 -j2 -q cxxstd=14 test examples test//serial examples//serial
# - name: "clang: minimal"
# addons:
# apt:
# sources: ubuntu-toolchain-r-test
# packages: libc++-dev
# script:
# - ./b2 -j2 -q toolset=clang cxxflags="-stdlib=libc++" linkflags="-lc++" libs/histogram
- name: "gcc-5: ubasan"
addons:
apt:
@ -51,8 +43,10 @@ matrix:
packages: g++-5
script:
# ubsan+asan disabled in serial tests, because of bug in boost/serialization
- ../../b2 -j2 -q toolset=gcc-5 cxxstd=14 ubasan test examples &&
../../b2 -j2 -q toolset=gcc-5 cxxstd=14 test//serial examples//serial
- ../../b2 -j2 -q toolset=gcc-5 cxxstd=14 ubasan
test//minimal examples//minimal &&
../../b2 -j2 -q toolset=gcc-5 cxxstd=14
test//serial examples//serial
- name: "gcc-7: coverage"
addons:
@ -61,7 +55,6 @@ matrix:
packages: g++-7
script:
- ../../b2 -j2 -q toolset=gcc-7 coverage
test examples test//serial examples//serial
after_success:
- GCOV=gcov-7 tools/cov.sh
@ -72,8 +65,10 @@ matrix:
packages: g++-8
script:
# ubsan+asan disabled in serial tests, because of bug in boost/serialization
- ../../b2 -j2 -q toolset=gcc-8 cxxstd=17 ubasan test examples &&
../../b2 -j2 -q toolset=gcc-8 cxxstd=17 test//serial examples//serial
- ../../b2 -j2 -q toolset=gcc-8 cxxstd=17 ubasan
test//minimal examples//minimal &&
../../b2 -j2 -q toolset=gcc-8 cxxstd=17
test//serial examples//serial
before_script:
# Cloning minimal set of Boost libraries

View File

@ -11,6 +11,7 @@ project
: requirements
<include>$(BOOST_ROOT)
<include>.
<variant>release
;
alias run-speed-test :

View File

@ -51,8 +51,6 @@ double compare_1d(unsigned n, int distrib) {
template <typename Tag, typename Storage>
double compare_2d(unsigned n, int distrib) {
auto r = random_array(n, distrib);
auto best = std::numeric_limits<double>::max();
auto h = make_s(Tag(), Storage(), reg(100, 0, 1), reg(100, 0, 1));
auto t = clock();
for (auto it = r.get(), end = r.get() + n; it != end;) {

View File

@ -4,37 +4,42 @@
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
run getting_started_listing_01.cpp ;
run getting_started_listing_02.cpp ;
run getting_started_listing_03.cpp ;
run guide_axis_basic_demo.cpp ;
run guide_axis_circular.cpp ;
run guide_axis_growing.cpp ;
run guide_axis_with_labels.cpp ;
run guide_axis_with_transform.cpp ;
run guide_axis_with_uoflow_off.cpp ;
run guide_custom_2d_axis.cpp ;
run guide_custom_accumulators.cpp ;
run guide_custom_minimal_axis.cpp ;
run guide_custom_modified_axis.cpp ;
run guide_custom_storage.cpp ;
run guide_fill_accumulator.cpp ;
run guide_fill_histogram.cpp ;
run guide_fill_profile.cpp ;
run guide_histogram_operators.cpp ;
run guide_histogram_reduction.cpp ;
run guide_histogram_streaming.cpp ;
run guide_indexed_access.cpp ;
run guide_make_dynamic_histogram.cpp ;
run guide_make_static_histogram.cpp ;
run guide_parallel_filling.cpp ;
run guide_stdlib_algorithms.cpp ;
test-suite minimal :
[ run getting_started_listing_01.cpp ]
[ run getting_started_listing_02.cpp ]
[ run getting_started_listing_03.cpp ]
[ run guide_axis_basic_demo.cpp ]
[ run guide_axis_circular.cpp ]
[ run guide_axis_growing.cpp ]
[ run guide_axis_with_labels.cpp ]
[ run guide_axis_with_transform.cpp ]
[ run guide_axis_with_uoflow_off.cpp ]
[ run guide_custom_2d_axis.cpp ]
[ run guide_custom_accumulators.cpp ]
[ run guide_custom_minimal_axis.cpp ]
[ run guide_custom_modified_axis.cpp ]
[ run guide_custom_storage.cpp ]
[ run guide_fill_accumulator.cpp ]
[ run guide_fill_histogram.cpp ]
[ run guide_fill_profile.cpp ]
[ run guide_histogram_operators.cpp ]
[ run guide_histogram_reduction.cpp ]
[ run guide_histogram_streaming.cpp ]
[ run guide_indexed_access.cpp ]
[ run guide_make_dynamic_histogram.cpp ]
[ run guide_make_static_histogram.cpp ]
[ run guide_parallel_filling.cpp ]
[ run guide_stdlib_algorithms.cpp ]
;
alias libserial : /boost/serialization//boost_serialization : <link>static ;
alias serial :
test-suite serial :
[ run guide_histogram_serialization.cpp libserial ]
;
test-suite all : minimal serial ;
explicit minimal ;
explicit libserial ;
explicit serial ;

View File

@ -7,6 +7,7 @@
#ifndef BOOST_HISTOGRAM_AXIS_OPTION_HPP
#define BOOST_HISTOGRAM_AXIS_OPTION_HPP
#include <boost/mp11.hpp>
#include <type_traits>
/**
@ -44,26 +45,28 @@ using growth = bit<3>;
namespace detail {
constexpr inline unsigned join_impl(unsigned a) { return a; }
template <unsigned N, class... Ts>
constexpr unsigned join_impl(unsigned a, axis::option::bit<N>, Ts... ts) {
using namespace axis::option;
const auto o = bit<N>::value;
const auto c = a | o;
if (o == underflow::value) return join_impl(c & ~circular::value, ts...);
if (o == circular::value)
return join_impl(c & ~(underflow::value | growth::value), ts...);
if (o == growth::value) return join_impl(c & ~circular::value, ts...);
return join_impl(c, ts...);
}
template <class T, class U>
struct join_impl : axis::option_set<(T::value | U::value)> {};
template <class T>
struct join_impl<T, axis::option::underflow>
: axis::option_set<((T::value & ~axis::option::circular::value) |
axis::option::underflow::value)> {};
template <class T>
struct join_impl<T, axis::option::circular>
: axis::option_set<(
(T::value & ~(axis::option::growth::value | axis::option::underflow::value)) |
axis::option::circular::value)> {};
template <class T>
struct join_impl<T, axis::option::growth>
: axis::option_set<((T::value & ~axis::option::circular::value) |
axis::option::growth::value)> {};
} // namespace detail
namespace axis {
/// Combines options and corrects for mutually exclusive options.
template <class T, class... Ts>
using join = axis::option_set<detail::join_impl(T::value, Ts{}...)>;
template <class... Ts>
using join = mp11::mp_fold<mp11::mp_list<Ts...>, option_set<0>, detail::join_impl>;
/// Test whether the bits in b are also set in a.
template <class T, class U>

View File

@ -286,7 +286,7 @@ public:
else {
z = std::numeric_limits<internal_value_type>::infinity() * delta_;
}
return this->inverse(z) * unit_type();
return static_cast<value_type>(this->inverse(z) * unit_type());
}
/// Return bin for index argument.

View File

@ -73,9 +73,9 @@ decltype(auto) metadata(T&& t) noexcept {
template <class T>
using static_options =
detail::mp_eval_or<detail::static_options_impl, detail::remove_cvref_t<T>,
mp11::mp_if<detail::has_method_update<detail::remove_cvref_t<T>>,
axis::option::growth, axis::option::none>>;
detail::mp_eval_or<mp11::mp_if<detail::has_method_update<detail::remove_cvref_t<T>>,
axis::option::growth, axis::option::none>,
detail::static_options_impl, detail::remove_cvref_t<T>>;
template <class T>
constexpr unsigned options(const T& t) noexcept {
@ -112,7 +112,11 @@ template <class T, class U>
auto index(const T& axis, const U& value) {
using V = detail::arg_type<decltype(&T::index)>;
return detail::static_if<std::is_convertible<U, V>>(
[&value](const auto& axis) { return axis.index(value); },
[&value](const auto& axis) {
using A = detail::remove_cvref_t<decltype(axis)>;
using V2 = detail::arg_type<decltype(&A::index)>;
return axis.index(static_cast<V2>(value));
},
[](const T&) {
BOOST_THROW_EXCEPTION(std::invalid_argument(
detail::cat(boost::core::demangled_name(BOOST_CORE_TYPEID(T)),

View File

@ -112,14 +112,14 @@ void linearize_index(optional_index& out, const A& axis, const axis::index_type
template <class S, class A, class T>
void maybe_replace_storage(S& storage, const A& axes, const T& shifts) {
bool update_needed = false;
auto sh = shifts;
for_each_axis(axes, [&](const auto&) { update_needed |= (*sh++ != 0); });
auto sit = shifts;
for_each_axis(axes, [&](const auto&) { update_needed |= (*sit++ != 0); });
if (!update_needed) return;
struct item {
axis::index_type idx, old_extend;
std::size_t new_stride;
} data[buffer_size<A>::value];
auto sit = shifts;
sit = shifts;
auto dit = data;
std::size_t s = 1;
for_each_axis(axes, [&](const auto& a) {
@ -129,15 +129,17 @@ void maybe_replace_storage(S& storage, const A& axes, const T& shifts) {
});
auto new_storage = make_default(storage);
new_storage.reset(detail::bincount(axes));
const auto dlast = data + get_size(axes) - 1;
for (const auto& x : storage) {
auto ns = new_storage.begin();
sit = shifts;
dit = data;
for_each_axis(axes, [&](const auto& a) {
using opt = axis::traits::static_options<remove_cvref_t<decltype(a)>>;
using opt = axis::traits::static_options<decltype(a)>;
if (axis::test<opt, axis::option::underflow>::value) {
if (dit->idx == 0) {
// noop
// axis has underflow and we are in the underflow bin:
// keep storage pointer unchanged
++dit;
++sit;
return;
@ -145,20 +147,26 @@ void maybe_replace_storage(S& storage, const A& axes, const T& shifts) {
}
if (axis::test<opt, axis::option::overflow>::value) {
if (dit->idx == dit->old_extend - 1) {
// axis has overflow and we are in the overflow bin:
// move storage pointer to corresponding overflow bin position
ns += (axis::traits::extend(a) - 1) * dit->new_stride;
++dit;
++sit;
return;
}
}
// we are in a normal bin:
// move storage pointer to index position, apply positive shifts
ns += (dit->idx + std::max(*sit, 0)) * dit->new_stride;
++dit;
++sit;
});
// assign old value to new location
*ns = x;
// advance multi-dimensional index
dit = data;
++dit->idx;
while (dit != (data + get_size(axes) - 1) && dit->idx == dit->old_extend) {
while (dit != dlast && dit->idx == dit->old_extend) {
dit->idx = 0;
++(++dit)->idx;
}
@ -166,12 +174,6 @@ void maybe_replace_storage(S& storage, const A& axes, const T& shifts) {
storage = std::move(new_storage);
}
template <class T>
struct size_or_zero : mp11::mp_size_t<0> {};
template <class... Ts>
struct size_or_zero<std::tuple<Ts...>> : mp11::mp_size_t<sizeof...(Ts)> {};
// special case: if histogram::operator()(tuple(1, 2)) is called on 1d histogram
// with axis that accepts 2d tuple, this should not fail
// - solution is to forward tuples of size > 1 directly to axis for 1d
@ -192,8 +194,8 @@ optional_index args_to_index(std::false_type, S&, const T& axes, const U& args)
if (rank != N)
BOOST_THROW_EXCEPTION(
std::invalid_argument("number of arguments != histogram rank"));
constexpr unsigned M = size_or_zero<remove_cvref_t<decltype(axes)>>::value;
mp11::mp_for_each<mp11::mp_iota_c<(M == 0 ? N : M)>>([&](auto J) {
constexpr unsigned M = buffer_size<remove_cvref_t<decltype(axes)>>::value;
mp11::mp_for_each<mp11::mp_iota_c<(N < M ? N : M)>>([&](auto J) {
linearize_value(idx, axis_get<J>(axes), std::get<(J + I)>(args));
});
}
@ -212,8 +214,8 @@ optional_index args_to_index(std::true_type, S& storage, T& axes, const U& args)
if (rank != N)
BOOST_THROW_EXCEPTION(
std::invalid_argument("number of arguments != histogram rank"));
constexpr unsigned M = size_or_zero<remove_cvref_t<decltype(axes)>>::value;
mp11::mp_for_each<mp11::mp_iota_c<(M == 0 ? N : M)>>([&](auto J) {
constexpr unsigned M = buffer_size<remove_cvref_t<decltype(axes)>>::value;
mp11::mp_for_each<mp11::mp_iota_c<(N < M ? N : M)>>([&](auto J) {
linearize_value(idx, shifts[J], axis_get<J>(axes), std::get<(J + I)>(args));
});
}
@ -334,7 +336,7 @@ optional_index at(const A& axes, const std::tuple<Us...>& args) {
template <typename A, typename U>
optional_index at(const A& axes, const U& args) {
if (get_size(axes) != args.size())
if (get_size(axes) != get_size(args))
BOOST_THROW_EXCEPTION(std::invalid_argument("number of arguments != histogram rank"));
optional_index idx;
using std::begin;

View File

@ -52,8 +52,9 @@ using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;
template <class T, class U>
using convert_integer = mp11::mp_if<std::is_integral<remove_cvref_t<T>>, U, T>;
template <template <class> class F, class T, class E>
using mp_eval_or = mp11::mp_eval_if_c<!(mp11::mp_valid<F, T>::value), E, F, T>;
// to be replaced by official version from mp11
template <class E, template <class...> class F, class... Ts>
using mp_eval_or = mp11::mp_eval_if_c<!(mp11::mp_valid<F, Ts...>::value), E, F, Ts...>;
template <class T1, class T2>
using copy_qualifiers = mp11::mp_if<
@ -171,7 +172,7 @@ using get_value_method_return_type_impl = decltype(std::declval<T&>().value(0));
template <typename T, typename R>
using has_method_value_with_convertible_return_type =
typename std::is_convertible<mp_eval_or<get_value_method_return_type_impl, T, void>,
typename std::is_convertible<mp_eval_or<void, get_value_method_return_type_impl, T>,
R>::type;
BOOST_HISTOGRAM_DETECT(has_method_options, (&T::options));
@ -328,7 +329,9 @@ std::size_t get_size_impl(std::true_type, const T&) noexcept {
template <class T>
std::size_t get_size_impl(std::false_type, const T& t) noexcept {
return t.size();
using std::begin;
using std::end;
return static_cast<std::size_t>(std::distance(begin(t), end(t)));
}
template <class T>
@ -338,8 +341,8 @@ std::size_t get_size(const T& t) noexcept {
template <class T>
using buffer_size =
mp_eval_or<tuple_size_t, T,
std::integral_constant<std::size_t, BOOST_HISTOGRAM_DETAIL_AXES_LIMIT>>;
mp_eval_or<std::integral_constant<std::size_t, BOOST_HISTOGRAM_DETAIL_AXES_LIMIT>,
tuple_size_t, T>;
template <class T, std::size_t N>
class sub_array : public std::array<T, N> {
@ -376,7 +379,7 @@ template <class T>
using get_scale_type_helper = typename T::value_type;
template <class T>
using get_scale_type = detail::mp_eval_or<detail::get_scale_type_helper, T, T>;
using get_scale_type = mp_eval_or<T, detail::get_scale_type_helper, T>;
struct one_unit {};
@ -394,7 +397,7 @@ template <class T>
using get_unit_type_helper = typename T::unit_type;
template <class T>
using get_unit_type = detail::mp_eval_or<detail::get_unit_type_helper, T, one_unit>;
using get_unit_type = mp_eval_or<one_unit, detail::get_unit_type_helper, T>;
template <class T, class R = get_scale_type<T>>
R get_scale(const T& t) {
@ -404,6 +407,13 @@ R get_scale(const T& t) {
template <class T, class Default>
using replace_default = mp11::mp_if<std::is_same<T, use_default>, Default, T>;
template <class T, class U>
using is_convertible_helper =
mp11::mp_apply<mp11::mp_all, mp11::mp_transform<std::is_convertible, T, U>>;
template <class T, class U>
using is_convertible = mp_eval_or<std::false_type, is_convertible_helper, T, U>;
} // namespace detail
} // namespace histogram
} // namespace boost

View File

@ -154,7 +154,7 @@ public:
*/
template <class... Ts>
auto operator()(const Ts&... ts) {
return operator()(std::forward_as_tuple(ts...));
return operator()(std::make_tuple(ts...));
}
/// Fill histogram with values, an optional weight, and/or a sample from a `std::tuple`.

View File

@ -160,20 +160,23 @@ public:
const auto clast = ca + hist_.rank() - 1;
std::size_t stride = 1;
h.for_each_axis([&, this](const auto& a) {
using opt = axis::traits::static_options<detail::remove_cvref_t<decltype(a)>>;
const auto shift = axis::test<opt, axis::option::underflow>::value;
using opt = axis::traits::static_options<decltype(a)>;
constexpr auto under = axis::test<opt, axis::option::underflow>::value ? 1 : 0;
constexpr auto over = axis::test<opt, axis::option::overflow>::value ? 1 : 0;
const auto size = a.size();
ca->extend = axis::traits::extend(a);
ca->begin = cover_all_ ? -shift : 0;
ca->end = ca->extend - shift -
(cover_all_ ? 0 : axis::test<opt, axis::option::overflow>::value);
ca->extend = size + under + over;
// -1 if underflow and cover all, else 0
ca->begin = cover_all_ ? -under : 0;
// size + 1 if overflow and cover all, else size
ca->end = cover_all_ ? size + over : size;
ca->idx = ca->begin;
begin_ += (ca->begin + shift) * stride;
begin_ += (ca->begin + under) * stride;
if (ca < clast)
end_ += (ca->begin + shift) * stride;
end_ += (ca->begin + under) * stride;
else
end_ += (ca->end + shift) * stride;
end_ += (ca->end + under) * stride;
stride *= ca->extend;
++ca;

View File

@ -179,7 +179,7 @@ template <class A>
template <class Archive>
void unlimited_storage<A>::serialize(Archive& ar, unsigned /* version */) {
if (Archive::is_loading::value) {
buffer_type dummy(0, buffer.alloc);
buffer_type dummy(buffer.alloc);
std::size_t size;
ar& serialization::make_nvp("type", dummy.type);
ar& serialization::make_nvp("size", size);

View File

@ -43,7 +43,9 @@ bool safe_increment(T& t) {
}
template <class T, class U>
bool safe_radd(std::true_type, T& t, const U& u) {
bool safe_radd(T& t, const U& u) {
static_assert(is_unsigned_integral<T>::value, "T must be unsigned integral type");
static_assert(is_unsigned_integral<U>::value, "T must be unsigned integral type");
if (static_cast<T>(std::numeric_limits<T>::max() - t) >= u) {
t += static_cast<T>(u); // static_cast to suppress conversion warning
return true;
@ -51,45 +53,6 @@ bool safe_radd(std::true_type, T& t, const U& u) {
return false;
}
template <class T, class U>
bool safe_radd(std::false_type, T& t, const U& u) {
static_assert(std::is_integral<U>::value, "U must be integral type");
if (u >= 0) {
if (static_cast<T>(std::numeric_limits<T>::max() - t) >=
static_cast<std::make_unsigned_t<U>>(u)) {
t += static_cast<T>(u);
return true;
}
return false;
}
if (t >= static_cast<std::make_unsigned_t<U>>(-u)) {
t -= static_cast<T>(-u);
return true;
}
return false;
}
template <class T, class A>
bool safe_radd(std::false_type, T& t, const mp_int<A>& u) {
if (u >= 0) {
if (std::numeric_limits<T>::max() - t > u) {
t += static_cast<T>(u);
return true;
}
}
if (u + t >= 0) {
t -= static_cast<T>(-u);
return true;
}
return false;
}
template <class T, class U>
bool safe_radd(T& t, const U& u) {
static_assert(is_unsigned_integral<T>::value, "T must be unsigned integral type");
return safe_radd(is_unsigned_integral<U>{}, t, u);
}
// use boost.multiprecision.cpp_int in your own code, it is much more sophisticated
// than this implementation; we use it here to reduce coupling between boost libs
template <class Allocator>
@ -107,7 +70,7 @@ struct mp_int {
}
mp_int& operator++() {
BOOST_ASSERT(data.size() >= 1);
BOOST_ASSERT(data.size() > 0u);
std::size_t i = 0;
while (!safe_increment(data[i])) {
data[i] = 0;
@ -153,7 +116,7 @@ struct mp_int {
}
mp_int& operator+=(uint64_t o) {
BOOST_ASSERT(data.size() >= 1);
BOOST_ASSERT(data.size() > 0u);
if (safe_radd(data[0], o)) return *this;
add_remainder(data[0], o);
// carry the one, data may grow several times
@ -168,40 +131,45 @@ struct mp_int {
}
operator double() const noexcept {
BOOST_ASSERT(data.size() >= 1);
double result = data[0];
BOOST_ASSERT(data.size() > 0u);
double result = static_cast<double>(data[0]);
std::size_t i = 0;
while (++i < data.size())
result += static_cast<double>(data[i]) * std::pow(2.0, i * 64);
return result;
}
bool operator<(uint64_t o) const noexcept {
BOOST_ASSERT(data.size() >= 1);
bool less(uint64_t o) const noexcept {
BOOST_ASSERT(data.size() > 0u);
return data.size() == 1 && data[0] < o;
}
bool operator>(uint64_t o) const noexcept {
BOOST_ASSERT(data.size() >= 1);
bool greater(uint64_t o) const noexcept {
BOOST_ASSERT(data.size() > 0u);
return data.size() > 1 || data[0] > o;
}
bool operator==(uint64_t o) const noexcept {
BOOST_ASSERT(data.size() >= 1);
bool equal(uint64_t o) const noexcept {
BOOST_ASSERT(data.size() > 0u);
return data.size() == 1 && data[0] == o;
}
bool operator<(double o) const noexcept { return operator double() < o; }
bool less(double o) const noexcept { return operator double() < o; }
bool operator>(double o) const noexcept { return operator double() > o; }
bool greater(double o) const noexcept { return operator double() > o; }
bool operator==(double o) const noexcept { return operator double() == o; }
bool equal(double o) const noexcept { return operator double() == o; }
bool operator<(const mp_int& o) const noexcept {
bool less(const mp_int& o) const noexcept {
BOOST_ASSERT(data.size() > 0u);
BOOST_ASSERT(o.data.size() > 0u);
// no leading zeros allowed
BOOST_ASSERT(data.size() == 1 || data.back() > 0u);
BOOST_ASSERT(o.data.size() == 1 || o.data.back() > 0u);
if (data.size() < o.data.size()) return true;
if (data.size() > o.data.size()) return false;
auto s = data.size();
while (s > 0) {
while (s > 0u) {
--s;
if (data[s] < o.data[s]) return true;
if (data[s] > o.data[s]) return false;
@ -209,11 +177,16 @@ struct mp_int {
return false; // args are equal
}
bool operator>(const mp_int& o) const noexcept {
bool greater(const mp_int& o) const noexcept {
BOOST_ASSERT(data.size() > 0u);
BOOST_ASSERT(o.data.size() > 0u);
// no leading zeros allowed
BOOST_ASSERT(data.size() == 1 || data.back() > 0u);
BOOST_ASSERT(o.data.size() == 1 || o.data.back() > 0u);
if (data.size() > o.data.size()) return true;
if (data.size() < o.data.size()) return false;
auto s = data.size();
while (s > 0) {
while (s > 0u) {
--s;
if (data[s] > o.data[s]) return true;
if (data[s] < o.data[s]) return false;
@ -221,7 +194,12 @@ struct mp_int {
return false; // args are equal
}
bool operator==(const mp_int& o) const noexcept {
bool equal(const mp_int& o) const noexcept {
BOOST_ASSERT(data.size() > 0u);
BOOST_ASSERT(o.data.size() > 0u);
// no leading zeros allowed
BOOST_ASSERT(data.size() == 1 || data.back() > 0u);
BOOST_ASSERT(o.data.size() == 1 || o.data.back() > 0u);
if (data.size() != o.data.size()) return false;
for (std::size_t s = 0; s < data.size(); ++s)
if (data[s] != o.data[s]) return false;
@ -229,66 +207,86 @@ struct mp_int {
}
template <class T>
bool operator<(const T& o) const noexcept {
return std::is_integral<T>::value ? operator<(static_cast<uint64_t>(o)) :
operator<(static_cast<double>(o));
bool less(const T& o) const noexcept {
return std::is_integral<T>::value ? less(static_cast<uint64_t>(o))
: less(static_cast<double>(o));
}
template <class T>
bool operator>(const T& o) const noexcept {
return std::is_integral<T>::value ? operator>(static_cast<uint64_t>(o)) :
operator>(static_cast<double>(o));
bool greater(const T& o) const noexcept {
return std::is_integral<T>::value ? greater(static_cast<uint64_t>(o))
: greater(static_cast<double>(o));
}
template <class T>
bool operator==(const T& o) const noexcept {
return std::is_integral<T>::value ? operator==(static_cast<uint64_t>(o)) :
operator==(static_cast<double>(o));
bool equal(const T& o) const noexcept {
return std::is_integral<T>::value ? equal(static_cast<uint64_t>(o))
: equal(static_cast<double>(o));
}
template <class T>
bool operator<=(const T& o) const noexcept {
return !operator>(o);
friend bool operator<(const mp_int& a, const T& o) noexcept {
return a.less(o);
}
template <class T>
bool operator>=(const T& o) const noexcept {
return !operator<(o);
friend bool operator>(const mp_int& a, const T& o) noexcept {
return a.greater(o);
}
template <class T>
bool operator!=(const T& o) const noexcept {
return !operator==(o);
friend bool operator==(const mp_int& a, const T& o) noexcept {
return a.equal(o);
}
template <class T>
friend bool operator<=(const mp_int& a, const T& o) noexcept {
return !a.greater(o);
}
template <class T>
friend bool operator>=(const mp_int& a, const T& o) noexcept {
return !a.less(o);
}
template <class T>
friend bool operator!=(const mp_int& a, const T& o) noexcept {
return !a.equal(o);
}
template <class T>
friend bool operator<(const T& a, const mp_int& b) noexcept {
return !(b >= a);
// a < b == b >= a == !(b < a)
return !b.less(a);
}
template <class T>
friend bool operator>(const T& a, const mp_int& b) noexcept {
return !(b <= a);
// a > b == b <= a == !(b > a)
return !b.greater(a);
}
template <class T>
friend bool operator<=(const T& a, const mp_int& b) noexcept {
return !(b > a);
return b.greater(a);
}
template <class T>
friend bool operator>=(const T& a, const mp_int& b) noexcept {
return !(b < a);
return b.less(a);
}
template <class T>
friend bool operator==(const T& a, const mp_int& b) noexcept {
return b == a;
return b.equal(a);
}
template <class T>
friend bool operator!=(const T& a, const mp_int& b) noexcept {
return b != a;
return !b.equal(a);
}
friend bool operator<(const mp_int& a, const mp_int& b) noexcept { return a.less(b); }
friend bool operator>(const mp_int& a, const mp_int& b) noexcept {
return a.greater(b);
}
friend bool operator<=(const mp_int& a, const mp_int& b) noexcept {
return b.greater(a);
}
friend bool operator>=(const mp_int& a, const mp_int& b) noexcept { return b.less(a); }
friend bool operator==(const mp_int& a, const mp_int& b) noexcept { return a.equal(b); }
friend bool operator!=(const mp_int& a, const mp_int& b) noexcept {
return !a.equal(b);
}
uint64_t& maybe_extend(std::size_t i) {
@ -297,7 +295,7 @@ struct mp_int {
}
static void add_remainder(uint64_t& d, const uint64_t o) noexcept {
BOOST_ASSERT(d > 0);
BOOST_ASSERT(d > 0u);
// in decimal system it would look like this:
// 8 + 8 = 6 = 8 - (9 - 8) - 1
// 9 + 1 = 0 = 9 - (9 - 1) - 1
@ -331,7 +329,7 @@ auto create_buffer(Allocator& a, std::size_t n) {
template <class Allocator, class Iterator>
auto create_buffer(Allocator& a, std::size_t n, Iterator iter) {
BOOST_ASSERT(n > 0);
BOOST_ASSERT(n > 0u);
using AT = std::allocator_traits<Allocator>;
auto ptr = AT::allocate(a, n); // may throw
static_assert(std::is_trivially_copyable<decltype(ptr)>::value,
@ -354,7 +352,7 @@ template <class Allocator>
void destroy_buffer(Allocator& a, typename std::allocator_traits<Allocator>::pointer p,
std::size_t n) {
BOOST_ASSERT(p);
BOOST_ASSERT(n > 0);
BOOST_ASSERT(n > 0u);
using AT = std::allocator_traits<Allocator>;
auto it = p + n;
while (it != p) AT::destroy(a, --it);
@ -421,21 +419,7 @@ private:
return f(static_cast<double*>(ptr), std::forward<Ts>(ts)...);
}
buffer_type(std::size_t s = 0, allocator_type a = {})
: alloc(std::move(a)), size(s), type(type_index<uint8_t>()) {
if (size > 0) {
// rebind allocator
using alloc_type = typename std::allocator_traits<
allocator_type>::template rebind_alloc<uint8_t>;
alloc_type a(alloc);
try {
ptr = detail::create_buffer(a, size); // may throw
} catch (...) {
size = 0;
throw;
}
}
}
buffer_type(allocator_type a = {}) : alloc(std::move(a)) {}
buffer_type(buffer_type&& o) noexcept
: alloc(std::move(o.alloc)), size(o.size), type(o.type), ptr(o.ptr) {
@ -626,9 +610,7 @@ public:
template <class T>
reference& operator-=(const T& t) {
base_type::buffer_->apply(adder(), *base_type::buffer_, base_type::idx_,
-static_cast<double>(t));
return *this;
return operator+=(-t);
}
template <class T>
@ -684,7 +666,7 @@ public:
using const_iterator = iterator_t<const value_type, const_reference, const buffer_type>;
using iterator = iterator_t<value_type, reference, buffer_type>;
explicit unlimited_storage(allocator_type a = {}) : buffer(0, std::move(a)) {}
explicit unlimited_storage(allocator_type a = {}) : buffer(std::move(a)) {}
unlimited_storage(const unlimited_storage&) = default;
unlimited_storage& operator=(const unlimited_storage&) = default;
unlimited_storage(unlimited_storage&&) = default;
@ -746,7 +728,7 @@ public:
/// @private used by unit tests, not part of generic storage interface
template <class T>
unlimited_storage(std::size_t s, const T* p, allocator_type a = {})
: buffer(0, std::move(a)) {
: buffer(std::move(a)) {
buffer.template make<T>(s, p);
}
@ -777,37 +759,49 @@ private:
struct adder {
template <class Buffer, class U>
void if_U_is_integral(std::true_type, mp_int* tp, Buffer&, std::size_t i,
const U& x) {
tp[i] += x;
void operator()(double* tp, Buffer&, std::size_t i, const U& x) {
tp[i] += static_cast<double>(x);
}
template <class T, class Buffer, class U>
void if_U_is_integral(std::true_type, T* tp, Buffer& b, std::size_t i, const U& x) {
if (detail::safe_radd(tp[i], x)) return;
if (x >= 0) {
using V = mp11::mp_at_c<types, (type_index<T>() + 1)>;
b.template make<V>(b.size, tp);
if_U_is_integral(std::true_type{}, static_cast<V*>(b.ptr), b, i, x);
} else {
if_U_is_integral(std::false_type{}, tp, b, i, x);
}
void operator()(T* tp, Buffer& b, std::size_t i, const U& x) {
U_is_integral(std::is_integral<U>{}, tp, b, i, x);
}
template <class T, class Buffer, class U>
void if_U_is_integral(std::false_type, T* tp, Buffer& b, std::size_t i, const U& x) {
void U_is_integral(std::false_type, T* tp, Buffer& b, std::size_t i, const U& x) {
b.template make<double>(b.size, tp);
operator()(static_cast<double*>(b.ptr), b, i, x);
}
template <class T, class Buffer, class U>
void operator()(T* tp, Buffer& b, std::size_t i, const U& x) {
if_U_is_integral(std::is_integral<U>{}, tp, b, i, x);
void U_is_integral(std::true_type, T* tp, Buffer& b, std::size_t i, const U& x) {
U_is_unsigned_integral(std::is_unsigned<U>{}, tp, b, i, x);
}
template <class T, class Buffer, class U>
void U_is_unsigned_integral(std::false_type, T* tp, Buffer& b, std::size_t i,
const U& x) {
if (x >= 0)
U_is_unsigned_integral(std::true_type{}, tp, b, i,
static_cast<typename std::make_unsigned<U>::type>(x));
else
U_is_integral(std::false_type{}, tp, b, i, static_cast<double>(x));
}
template <class Buffer, class U>
void operator()(double* tp, Buffer&, std::size_t i, const U& x) {
tp[i] += static_cast<double>(x);
void U_is_unsigned_integral(std::true_type, mp_int* tp, Buffer&, std::size_t i,
const U& x) {
tp[i] += x;
}
template <class T, class Buffer, class U>
void U_is_unsigned_integral(std::true_type, T* tp, Buffer& b, std::size_t i,
const U& x) {
if (detail::safe_radd(tp[i], x)) return;
using V = mp11::mp_at_c<types, (type_index<T>() + 1)>;
b.template make<V>(b.size, tp);
U_is_unsigned_integral(std::true_type{}, static_cast<V*>(b.ptr), b, i, x);
}
};

View File

@ -14,47 +14,52 @@ project
<define>XML_PATH=\\\"$(THIS_PATH)/\\\"
;
run algorithm_project_test.cpp ;
run algorithm_reduce_test.cpp ;
run algorithm_sum_test.cpp ;
run axis_category_test.cpp ;
run axis_integer_test.cpp ;
run axis_option_test.cpp ;
run axis_regular_test.cpp ;
run axis_size.cpp ;
run axis_traits_test.cpp ;
run axis_variable_test.cpp ;
run axis_variant_test.cpp ;
run boost_range_support_test.cpp ;
run boost_units_support_test.cpp ;
run detail_test.cpp ;
run histogram_dynamic_test.cpp ;
run histogram_growing_test.cpp ;
run histogram_mixed_test.cpp ;
run histogram_operators_test.cpp ;
run histogram_test.cpp ;
run indexed_test.cpp ;
run internal_accumulators_test.cpp ;
run linearize_test.cpp ;
run meta_test.cpp ;
run storage_adaptor_test.cpp ;
run unlimited_storage_test.cpp ;
run utility_test.cpp ;
test-suite minimal :
[ run algorithm_project_test.cpp ]
[ run algorithm_reduce_test.cpp ]
[ run algorithm_sum_test.cpp ]
[ run axis_category_test.cpp ]
[ run axis_integer_test.cpp ]
[ run axis_option_test.cpp ]
[ run axis_regular_test.cpp ]
[ run axis_size.cpp ]
[ run axis_traits_test.cpp ]
[ run axis_variable_test.cpp ]
[ run axis_variant_test.cpp ]
[ run boost_range_support_test.cpp ]
[ run boost_units_support_test.cpp ]
[ run detail_test.cpp ]
[ run histogram_dynamic_test.cpp ]
[ run histogram_growing_test.cpp ]
[ run histogram_mixed_test.cpp ]
[ run histogram_operators_test.cpp ]
[ run histogram_test.cpp ]
[ run indexed_test.cpp ]
[ run internal_accumulators_test.cpp ]
[ run linearize_test.cpp ]
[ run meta_test.cpp ]
[ run storage_adaptor_test.cpp ]
[ run unlimited_storage_test.cpp ]
[ run utility_test.cpp ]
;
# has additional requirements only available on develop branch
alias deduction_guides : [ run deduction_guides_test.cpp ] ;
test-suite deduction_guides : [ run deduction_guides_test.cpp ] ;
# disabled until boost.parameter usage is fixed
alias accumulator : [ run boost_accumulators_support_test.cpp ] ;
test-suite accumulator : [ run boost_accumulators_support_test.cpp ] ;
alias libserial : /boost/serialization//boost_serialization : <link>static ;
alias serial :
test-suite serial :
[ run storage_adaptor_serialization_test.cpp libserial ]
[ run histogram_serialization_test.cpp libserial ]
[ run unlimited_storage_serialization_test.cpp libserial ]
;
test-suite all : minimal serial ;
explicit minimal ;
explicit libserial ;
explicit serial ;
explicit accumulator ;

View File

@ -13,31 +13,40 @@
using namespace boost::histogram;
using regular =
axis::regular<double, axis::transform::id, axis::null_type, axis::option::growth>;
using def = use_default;
// using integer = axis::integer<double, axis::null_type,
// axis::option::underflow |
// axis::option::overflow
// | axis::option::growth>;
// using category =
// axis::category<std::string, axis::null_type, axis::option::growth>;
using regular = axis::regular<double, def, def, axis::option::growth>;
// class custom_2d_axis {
// public:
// auto index(double x, double y) const {
// const auto r = std::sqrt(x * x + y * y);
// return std::min(static_cast<axis::index_type>(r), size());
// }
//
// auto update(double x, double y) { const auto r = std::sqrt(x * x + y * y);
// }
//
// axis::index_type size() const { return size_; }
//
// private:
// axis::index_type size_ = 0;
// };
using integer = axis::integer<
double, def,
axis::join<axis::option::underflow, axis::option::overflow, axis::option::growth>>;
using category = axis::category<std::string, def, axis::option::growth>;
class custom_2d_axis {
public:
auto index(std::tuple<double, double> xy) const {
const auto x = std::get<0>(xy);
const auto y = std::get<1>(xy);
const auto r = std::sqrt(x * x + y * y);
return std::min(static_cast<axis::index_type>(r), size());
}
auto update(std::tuple<double, double> xy) {
const auto x = std::get<0>(xy);
const auto y = std::get<1>(xy);
const auto r = std::sqrt(x * x + y * y);
const auto n = static_cast<int>(r);
const auto old = size_;
if (n >= size_) size_ = n + 1;
return std::make_pair(n, old - size_);
}
axis::index_type size() const { return size_; }
private:
axis::index_type size_ = 0;
};
template <typename Tag>
void run_tests() {
@ -74,75 +83,93 @@ void run_tests() {
BOOST_TEST_EQ(h[4], 1);
}
// {
// auto h = make_s(Tag(), std::vector<int>(), integer());
// const auto& a = h.axis();
// h(-std::numeric_limits<double>::infinity());
// h(std::numeric_limits<double>::quiet_NaN());
// h(std::numeric_limits<double>::infinity());
// BOOST_TEST_EQ(a.size(), 0);
// BOOST_TEST_EQ(h.size(), 2);
// BOOST_TEST_EQ(h[-1], 1);
// BOOST_TEST_EQ(h[0], 2);
// h(0);
// BOOST_TEST_EQ(a.size(), 1);
// BOOST_TEST_EQ(h.size(), 3);
// BOOST_TEST_EQ(h[-1], 1);
// BOOST_TEST_EQ(h[0], 1);
// BOOST_TEST_EQ(h[1], 2);
// h(2);
// BOOST_TEST_EQ(a.size(), 3);
// BOOST_TEST_EQ(h.size(), 5);
// BOOST_TEST_EQ(h[-1], 1);
// BOOST_TEST_EQ(h[0], 1);
// BOOST_TEST_EQ(h[1], 0);
// BOOST_TEST_EQ(h[2], 1);
// BOOST_TEST_EQ(h[3], 2);
// h(-2);
// BOOST_TEST_EQ(a.size(), 5);
// BOOST_TEST_EQ(h.size(), 7);
// // BOOST_TEST_EQ(h[-1], 1)
// BOOST_TEST_EQ(h[0], 1);
// BOOST_TEST_EQ(h[1], 0);
// BOOST_TEST_EQ(h[2], 1);
// BOOST_TEST_EQ(h[3], 0);
// BOOST_TEST_EQ(h[4], 1);
// BOOST_TEST_EQ(h[5], 2);
// }
//
// {
// auto h = make_s(Tag(), std::vector<int>(), integer(), category());
// const auto& a = h.axis(0);
// const auto& b = h.axis(1);
// BOOST_TEST_EQ(a.size(), 0);
// BOOST_TEST_EQ(b.size(), 0);
// BOOST_TEST_EQ(h.size(), 0);
// h(0, "x");
// h(-std::numeric_limits<double>::infinity(), "x");
// h(std::numeric_limits<double>::infinity(), "x");
// h(std::numeric_limits<double>::quiet_NaN(), "x");
// BOOST_TEST_EQ(a.size(), 1);
// BOOST_TEST_EQ(b.size(), 1);
// BOOST_TEST_EQ(h.size(), 3);
// h(2, "x");
// BOOST_TEST_EQ(a.size(), 3);
// BOOST_TEST_EQ(b.size(), 1);
// BOOST_TEST_EQ(h.size(), 5);
// h(1, "y");
// BOOST_TEST_EQ(a.size(), 3);
// BOOST_TEST_EQ(b.size(), 2);
// BOOST_TEST_EQ(h.size(), 10);
// BOOST_TEST_EQ(h.at(-1, 0), 1);
// BOOST_TEST_EQ(h.at(-1, 1), 0);
// BOOST_TEST_EQ(h.at(3, 0), 2);
// BOOST_TEST_EQ(h.at(3, 1), 0);
// BOOST_TEST_EQ(h.at(a.index(0), b.index("x")), 1);
// BOOST_TEST_EQ(h.at(a.index(1), b.index("x")), 0);
// BOOST_TEST_EQ(h.at(a.index(2), b.index("x")), 1);
// BOOST_TEST_EQ(h.at(a.index(0), b.index("y")), 0);
// BOOST_TEST_EQ(h.at(a.index(1), b.index("y")), 1);
// BOOST_TEST_EQ(h.at(a.index(2), b.index("y")), 0);
// }
{
auto h = make_s(Tag(), std::vector<int>(), integer());
const auto& a = h.axis();
h(-std::numeric_limits<double>::infinity());
h(std::numeric_limits<double>::quiet_NaN());
h(std::numeric_limits<double>::infinity());
BOOST_TEST_EQ(a.size(), 0);
BOOST_TEST_EQ(h.size(), 2);
BOOST_TEST_EQ(h[-1], 1);
BOOST_TEST_EQ(h[0], 2);
h(0);
BOOST_TEST_EQ(a.size(), 1);
BOOST_TEST_EQ(h.size(), 3);
BOOST_TEST_EQ(h[-1], 1);
BOOST_TEST_EQ(h[0], 1);
BOOST_TEST_EQ(h[1], 2);
h(2);
BOOST_TEST_EQ(a.size(), 3);
BOOST_TEST_EQ(h.size(), 5);
BOOST_TEST_EQ(h[-1], 1);
BOOST_TEST_EQ(h[0], 1);
BOOST_TEST_EQ(h[1], 0);
BOOST_TEST_EQ(h[2], 1);
BOOST_TEST_EQ(h[3], 2);
h(-2);
BOOST_TEST_EQ(a.size(), 5);
BOOST_TEST_EQ(h.size(), 7);
// BOOST_TEST_EQ(h[-1], 1)
BOOST_TEST_EQ(h[0], 1);
BOOST_TEST_EQ(h[1], 0);
BOOST_TEST_EQ(h[2], 1);
BOOST_TEST_EQ(h[3], 0);
BOOST_TEST_EQ(h[4], 1);
BOOST_TEST_EQ(h[5], 2);
}
{
auto h = make_s(Tag(), std::vector<int>(), integer(), category());
const auto& a = h.axis(0);
const auto& b = h.axis(1);
BOOST_TEST_EQ(a.size(), 0);
BOOST_TEST_EQ(b.size(), 0);
BOOST_TEST_EQ(h.size(), 0);
h(0, "x");
h(-std::numeric_limits<double>::infinity(), "x");
h(std::numeric_limits<double>::infinity(), "x");
h(std::numeric_limits<double>::quiet_NaN(), "x");
BOOST_TEST_EQ(a.size(), 1);
BOOST_TEST_EQ(b.size(), 1);
BOOST_TEST_EQ(h.size(), 3);
h(2, "x");
BOOST_TEST_EQ(a.size(), 3);
BOOST_TEST_EQ(b.size(), 1);
BOOST_TEST_EQ(h.size(), 5);
h(1, "y");
BOOST_TEST_EQ(a.size(), 3);
BOOST_TEST_EQ(b.size(), 2);
BOOST_TEST_EQ(h.size(), 10);
BOOST_TEST_EQ(h.at(-1, 0), 1);
BOOST_TEST_EQ(h.at(-1, 1), 0);
BOOST_TEST_EQ(h.at(3, 0), 2);
BOOST_TEST_EQ(h.at(3, 1), 0);
BOOST_TEST_EQ(h.at(a.index(0), b.index("x")), 1);
BOOST_TEST_EQ(h.at(a.index(1), b.index("x")), 0);
BOOST_TEST_EQ(h.at(a.index(2), b.index("x")), 1);
BOOST_TEST_EQ(h.at(a.index(0), b.index("y")), 0);
BOOST_TEST_EQ(h.at(a.index(1), b.index("y")), 1);
BOOST_TEST_EQ(h.at(a.index(2), b.index("y")), 0);
BOOST_TEST_THROWS(h(0, "x", 42), std::invalid_argument);
}
{
auto h = make_s(Tag{}, std::vector<int>{}, custom_2d_axis{});
BOOST_TEST_EQ(h.size(), 0);
h(0, 0);
BOOST_TEST_EQ(h.size(), 1);
h(1, 0);
h(0, 1);
BOOST_TEST_EQ(h.size(), 2);
h(10, 0);
BOOST_TEST_EQ(h.size(), 11);
BOOST_TEST_EQ(h[0], 1);
BOOST_TEST_EQ(h[1], 2);
BOOST_TEST_EQ(h[10], 1);
BOOST_TEST_THROWS(h(0), std::invalid_argument);
}
}
int main() {

View File

@ -62,7 +62,7 @@ void run_tests() {
// copy_assign
{
auto a = make(T1{}, axis::regular<>{3, 0, 3}, axis::integer<>{0, 2});
auto b = make_s(T2{}, std::vector<unsigned>(), axis::regular<>{3, 0, 3},
auto b = make_s(T2{}, std::vector<double>(), axis::regular<>{3, 0, 3},
axis::integer<>{0, 2});
a(1, 1);
BOOST_TEST_NE(a, b);

View File

@ -83,7 +83,7 @@ void run_tests() {
a(0, weight(2));
a(1, weight(2));
auto b = a;
auto c = make_s(Tag(), std::vector<unsigned>(), ia);
auto c = make_s(Tag(), std::vector<int>(), ia);
c(0, weight(2));
c(1, weight(2));
auto a2 = a;

View File

@ -17,14 +17,17 @@ template <typename Tag>
void run_tests(const char* filename) {
// histogram_serialization
namespace tr = axis::transform;
auto a =
make(Tag(), axis::regular<>(3, -1, 1, "reg"), axis::circular<>(2, 0.0, 1.0, "cir"),
axis::regular<double, tr::log>(3, 1, std::exp(2), "reg-log"),
axis::regular<double, tr::pow, std::vector<int>, axis::option::overflow>(
tr::pow(0.5), 3, 1, 100, {1, 2, 3}),
axis::variable<>({1.0, 2.0, 3.0}, "var"), axis::category<>{3, 1, 2},
axis::integer<int, axis::null_type>(0, 2));
a(0.5, 0.2, 20, 20, 2.5, 1, 1);
using def = use_default;
using axis::option::none;
auto a = make(Tag(), axis::regular<double, def, def, none>(1, -1, 1, "reg"),
axis::circular<float, def, none>(1, 0.0, 1.0, "cir"),
axis::regular<double, tr::log, def, none>(1, 1, std::exp(2), "reg-log"),
axis::regular<double, tr::pow, std::vector<int>, axis::option::overflow>(
tr::pow(0.5), 1, 1, 100, {1, 2, 3}),
axis::variable<double, def, none>({1.5, 2.5}, "var"),
axis::category<int, def, none>{3, 1},
axis::integer<int, axis::null_type, none>(1, 2));
a(0.5, 0.2, 2, 20, 2.2, 1, 1);
print_xml(filename, a);
auto b = decltype(a)();

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,7 @@
#include <boost/core/lightweight_test.hpp>
#include <boost/histogram.hpp>
#include <boost/histogram/accumulators/ostream.hpp>
#include <sstream>
#include <stdexcept>
#include <tuple>
@ -109,7 +110,7 @@ void run_tests() {
h2 = h;
BOOST_TEST_EQ(h, h2);
auto h3 = histogram<std::tuple<axis::integer<>, axis::integer<>>,
storage_adaptor<std::vector<unsigned>>>();
storage_adaptor<std::vector<double>>>();
h3 = h;
BOOST_TEST_EQ(h, h3);
}
@ -485,7 +486,7 @@ void run_tests() {
BOOST_TEST_EQ(h.at(1, 0, 0), 1);
}
// using static containers
// using containers or input and output
{
auto h = make_s(Tag(), std::vector<accumulators::weighted_sum<>>(),
axis::integer<>(0, 2), axis::regular<>(2, 2, 4));
@ -501,6 +502,13 @@ void run_tests() {
BOOST_TEST_EQ(h[i00].value(), 1);
BOOST_TEST_EQ(h[i11].value(), 1);
// iterable out
int j11[] = {1, 1};
int j111[] = {1, 1, 1};
BOOST_TEST_EQ(h.at(j11), 1);
BOOST_TEST_EQ(h[j11], 1);
BOOST_TEST_THROWS((void)h.at(j111), std::invalid_argument);
// tuple with weight
h(std::make_tuple(weight(2), 0, 2.0));
h(std::make_tuple(1, 3.0, weight(2)));

View File

@ -159,7 +159,7 @@ int main() {
mixed_tests<storage_adaptor<std::vector<int>>,
storage_adaptor<std::array<double, 100>>>();
mixed_tests<unlimited_storage<>, storage_adaptor<std::vector<int>>>();
mixed_tests<unlimited_storage<>, storage_adaptor<std::vector<double>>>();
mixed_tests<storage_adaptor<std::vector<int>>, unlimited_storage<>>();
mixed_tests<storage_adaptor<std::vector<int>>,
storage_adaptor<std::map<std::size_t, int>>>();

View File

@ -101,7 +101,7 @@ void increase_and_grow() {
++x[0];
n2[0] += x[0];
double v = tmax;
auto v = static_cast<double>(tmax);
++v;
BOOST_TEST_EQ(n[0], v);
BOOST_TEST_EQ(n2[0], v);
@ -216,47 +216,41 @@ int main() {
c = 0;
BOOST_TEST_EQ(bh::detail::safe_radd(c, 255u), true);
BOOST_TEST_EQ(c, 255);
c = 0;
BOOST_TEST_EQ(bh::detail::safe_radd(c, 255), true);
BOOST_TEST_EQ(c, 255);
c = 1;
BOOST_TEST_EQ(bh::detail::safe_radd(c, 255), false);
BOOST_TEST_EQ(c, 1);
BOOST_TEST_EQ(bh::detail::safe_radd(c, 255u), false);
BOOST_TEST_EQ(c, 1);
c = 255;
BOOST_TEST_EQ(bh::detail::safe_radd(c, 1u), false);
BOOST_TEST_EQ(c, 255);
BOOST_TEST_EQ(bh::detail::safe_radd(c, 1), false);
BOOST_TEST_EQ(c, 255);
BOOST_TEST_EQ(bh::detail::safe_radd(c, -255), true);
BOOST_TEST_EQ(c, 0);
BOOST_TEST_EQ(bh::detail::safe_radd(c, -1), false);
BOOST_TEST_EQ(c, 0);
uint32_t i = 0;
BOOST_TEST_EQ(bh::detail::safe_radd(i, 2), true);
BOOST_TEST_EQ(i, 2u);
BOOST_TEST_EQ(bh::detail::safe_radd(i, -2), true);
BOOST_TEST_EQ(i, 0u);
BOOST_TEST_EQ(bh::detail::safe_radd(i, -2), false);
BOOST_TEST_EQ(i, 0u);
}
// mp_int
{
const auto vmax = max<uint64_t>();
BOOST_TEST_EQ(mp_int(), 0);
BOOST_TEST_EQ(mp_int(), 0.0);
BOOST_TEST_EQ(mp_int(1), 1);
BOOST_TEST_NE(mp_int(1), 2);
BOOST_TEST_LT(mp_int(1), 2);
BOOST_TEST_LE(mp_int(1), 2);
BOOST_TEST_LE(mp_int(1), 1);
BOOST_TEST_GT(mp_int(1), 0);
BOOST_TEST_GE(mp_int(1), 0);
BOOST_TEST_GE(mp_int(1), 1);
BOOST_TEST_EQ(mp_int(), 0u);
BOOST_TEST_EQ(mp_int(1u), 1u);
BOOST_TEST_EQ(mp_int(1u), 1.0);
BOOST_TEST_EQ(mp_int(1u), mp_int(1u));
BOOST_TEST_NE(mp_int(1u), 2u);
BOOST_TEST_NE(mp_int(1u), 2.0);
BOOST_TEST_NE(mp_int(1u), mp_int(2u));
BOOST_TEST_LT(mp_int(1u), 2u);
BOOST_TEST_LT(mp_int(1u), 2.0);
BOOST_TEST_LT(mp_int(1u), mp_int(2u));
BOOST_TEST_LE(mp_int(1u), 2u);
BOOST_TEST_LE(mp_int(1u), 2.0);
BOOST_TEST_LE(mp_int(1u), mp_int(2u));
BOOST_TEST_LE(mp_int(1u), 1u);
BOOST_TEST_GT(mp_int(1u), 0u);
BOOST_TEST_GT(mp_int(1u), 0.0);
BOOST_TEST_GT(mp_int(1u), mp_int(0u));
BOOST_TEST_GE(mp_int(1u), 0u);
BOOST_TEST_GE(mp_int(1u), 0.0);
BOOST_TEST_GE(mp_int(1u), 1u);
BOOST_TEST_GE(mp_int(1u), mp_int(0u));
BOOST_TEST_NOT(mp_int(1u) < mp_int(1u));
BOOST_TEST_NOT(mp_int(1u) > mp_int(1u));
auto a = mp_int();
++a;
@ -268,24 +262,34 @@ int main() {
BOOST_TEST_EQ(a, vmax);
BOOST_TEST_EQ(a, static_cast<double>(vmax));
++a;
BOOST_TEST_EQ(a.data.size(), 2);
BOOST_TEST_EQ(a.data[0], 0);
BOOST_TEST_EQ(a.data[1], 1);
BOOST_TEST_EQ(a, make_mp_int(0, 1));
++a;
BOOST_TEST_EQ(a.data.size(), 2);
BOOST_TEST_EQ(a.data[0], 1);
BOOST_TEST_EQ(a.data[1], 1);
BOOST_TEST_EQ(a, make_mp_int(1, 1));
a += a;
BOOST_TEST_EQ(a.data.size(), 2);
BOOST_TEST_EQ(a.data[0], 2);
BOOST_TEST_EQ(a.data[1], 2);
BOOST_TEST_EQ(a, make_mp_int(2, 2));
BOOST_TEST_EQ(a, 2 * static_cast<double>(vmax) + 2);
// carry once A
a.data[0] = vmax;
a.data[1] = 1;
++a;
BOOST_TEST_EQ(a, make_mp_int(0, 2));
// carry once B
a.data[0] = vmax;
a.data[1] = 1;
a += 1;
BOOST_TEST_EQ(a, make_mp_int(0, 2));
// carry once C
a.data[0] = vmax;
a.data[1] = 1;
a += make_mp_int(1, 1);
BOOST_TEST_EQ(a, make_mp_int(0, 3));
a.data[0] = vmax - 1;
a.data[1] = vmax;
++a;
BOOST_TEST_EQ(a.data.size(), 2);
BOOST_TEST_EQ(a.data[0], vmax);
BOOST_TEST_EQ(a.data[1], vmax);
BOOST_TEST_EQ(a, make_mp_int(vmax, vmax));
// carry two times A
++a;
BOOST_TEST_EQ(a, make_mp_int(0, 0, 1));
@ -298,6 +302,7 @@ int main() {
a += mp_int(1);
BOOST_TEST_EQ(a, make_mp_int(0, 0, 1));
// carry and enlarge
a = make_mp_int(vmax, vmax);
a += a;
BOOST_TEST_EQ(a, make_mp_int(vmax - 1, vmax, 1));
@ -321,7 +326,7 @@ int main() {
a += a;
BOOST_TEST_EQ(a, b);
}
BOOST_TEST_GT(a.data.size(), 1);
BOOST_TEST_GT(a.data.size(), 1u);
}
// empty state