diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 18:24:20 +0000 |
commit | 483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch) | |
tree | e5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/boost/libs/histogram/test | |
parent | Initial commit. (diff) | |
download | ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.tar.xz ceph-483eb2f56657e8e7f419ab1a4fab8dce9ade8609.zip |
Adding upstream version 14.2.21.upstream/14.2.21upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/boost/libs/histogram/test')
107 files changed, 9264 insertions, 0 deletions
diff --git a/src/boost/libs/histogram/test/CMakeLists.txt b/src/boost/libs/histogram/test/CMakeLists.txt new file mode 100644 index 00000000..bc3f6648 --- /dev/null +++ b/src/boost/libs/histogram/test/CMakeLists.txt @@ -0,0 +1,186 @@ +# Copyright Hans Dembinski 2019 +# 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 + +boost_test(SOURCES check_cmake_version.cpp ARGUMENTS ${PROJECT_VERSION} + LIBRARIES Boost::core Boost::config) + +# checks that b2 and cmake are in sync +add_test(NAME check_build_system COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/check_build_system.py) + +# checks that all headers are included in odr test +add_test(NAME check_odr_test COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/check_odr_test.py) + +# keep in sync with Jamfile, this should be automatized... +boost_test(TYPE compile-fail SOURCES axis_category_fail0.cpp + LIBRARIES Boost::histogram +) +boost_test(TYPE compile-fail SOURCES axis_category_fail1.cpp + LIBRARIES Boost::histogram +) +boost_test(TYPE compile-fail SOURCES axis_category_fail2.cpp + LIBRARIES Boost::histogram +) +boost_test(TYPE compile-fail SOURCES axis_integer_fail0.cpp + LIBRARIES Boost::histogram +) +boost_test(TYPE compile-fail SOURCES axis_integer_fail1.cpp + LIBRARIES Boost::histogram +) +boost_test(TYPE compile-fail SOURCES axis_integer_fail2.cpp + LIBRARIES Boost::histogram +) +boost_test(TYPE compile-fail SOURCES axis_integer_fail3.cpp + LIBRARIES Boost::histogram +) +boost_test(TYPE compile-fail SOURCES axis_integer_fail4.cpp + LIBRARIES Boost::histogram +) +boost_test(TYPE compile-fail SOURCES axis_regular_fail0.cpp + LIBRARIES Boost::histogram +) +boost_test(TYPE compile-fail SOURCES axis_regular_fail1.cpp + LIBRARIES Boost::histogram +) +boost_test(TYPE compile-fail SOURCES axis_variable_fail0.cpp + LIBRARIES Boost::histogram +) +boost_test(TYPE compile-fail SOURCES axis_variable_fail1.cpp + LIBRARIES Boost::histogram +) +boost_test(TYPE compile-fail SOURCES make_histogram_fail0.cpp + LIBRARIES Boost::histogram +) +boost_test(TYPE compile-fail SOURCES make_histogram_fail1.cpp + LIBRARIES Boost::histogram +) +boost_test(TYPE compile-fail SOURCES histogram_fail0.cpp + LIBRARIES Boost::histogram +) +boost_test(TYPE compile-fail SOURCES histogram_fail1.cpp + LIBRARIES Boost::histogram +) +boost_test(TYPE compile-fail SOURCES histogram_fail2.cpp + LIBRARIES Boost::histogram +) +boost_test(TYPE compile-fail SOURCES histogram_fail3.cpp + LIBRARIES Boost::histogram +) +boost_test(TYPE compile-fail SOURCES histogram_fail4.cpp + LIBRARIES Boost::histogram +) +boost_test(TYPE run SOURCES accumulators_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES algorithm_project_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES algorithm_reduce_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES algorithm_sum_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES algorithm_empty_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES axis_category_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES axis_integer_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES axis_option_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES axis_regular_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES axis_size.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES axis_traits_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES axis_variable_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES axis_variant_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES detail_accumulator_traits_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES detail_argument_traits_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES detail_args_type_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES detail_axes_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES detail_convert_integer_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES detail_detect_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES detail_limits_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES detail_make_default_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES detail_misc_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES detail_large_int_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES detail_iterator_adaptor_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES detail_operators_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES detail_relaxed_equal_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES detail_replace_type_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES detail_safe_comparison_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES detail_static_if_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES detail_tuple_slice_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES histogram_custom_axis_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES histogram_dynamic_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES histogram_fill_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES histogram_growing_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES histogram_mixed_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES histogram_operators_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES histogram_ostream_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES histogram_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES indexed_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES storage_adaptor_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES unlimited_storage_test.cpp + LIBRARIES Boost::histogram Boost::core) +boost_test(TYPE run SOURCES utility_test.cpp + LIBRARIES Boost::histogram Boost::core) + +if (cxx_std_17 IN_LIST CMAKE_CXX_COMPILE_FEATURES) + boost_test(TYPE run SOURCES deduction_guides_test.cpp + LIBRARIES Boost::histogram Boost::core) + target_compile_features(BoostHistogram-deduction_guides_test_cpp PRIVATE cxx_std_17) +endif() + +if (Threads_FOUND) + boost_test(TYPE run SOURCES histogram_threaded_test.cpp + LIBRARIES Boost::histogram Boost::core Threads::Threads) + boost_test(TYPE run SOURCES storage_adaptor_threaded_test.cpp + LIBRARIES Boost::histogram Boost::core Threads::Threads) +endif() + +## No cmake support yet +# boost_test(TYPE link SOURCES odr_main_test.cpp odr_test.cpp +# LIBRARIES Boost::histogram Boost::core Boost::serialization) +# boost_test(TYPE run SOURCES boost_accumulators_support_test.cpp +# LIBRARIES Boost::histogram Boost::core Boost::accumulators) +# boost_test(TYPE run SOURCES boost_range_support_test.cpp +# LIBRARIES Boost::histogram Boost::core Boost::range) +# boost_test(TYPE run SOURCES boost_units_support_test.cpp +# LIBRARIES Boost::histogram Boost::core Boost::units) +# boost_test(TYPE run SOURCES detail_array_wrapper_serialization_test.cpp LIBRARIES Boost::histogram Boost::core Boost::serialization) +# boost_test(TYPE run SOURCES unlimited_storage_serialization_test.cpp LIBRARIES Boost::histogram Boost::core Boost::serialization) +# boost_test(TYPE run SOURCES storage_adaptor_serialization_test.cpp LIBRARIES Boost::histogram Boost::core Boost::serialization) +# boost_test(TYPE run SOURCES histogram_serialization_test.cpp LIBRARIES Boost::histogram Boost::core Boost::serialization) +# boost_test(TYPE run SOURCES axis_variant_serialization_test.cpp +# LIBRARIES Boost::histogram Boost::core Boost::serialization) +# boost_test(TYPE run SOURCES accumulators_serialization_test.cpp +# LIBRARIES Boost::histogram Boost::core Boost::serialization) diff --git a/src/boost/libs/histogram/test/Jamfile b/src/boost/libs/histogram/test/Jamfile new file mode 100644 index 00000000..cdb695a5 --- /dev/null +++ b/src/boost/libs/histogram/test/Jamfile @@ -0,0 +1,159 @@ +# Copyright 2016-2017 Klemens David Morgenstern +# Copyright 2018 Mateusz Loskot <mateusz@loskot.net> +# Copyright 2018-2019 Hans Dembinski +# +# Use, modification and distribution is subject to 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) + +import python ; +import os ; +import regex ; +import testing ; +import ../../config/checks/config : requires ; + +if ! [ python.configured ] +{ + using python ; +} + +path-constant THIS_PATH : . ; + +project + : requirements + [ requires + cxx14_constexpr cxx14_decltype_auto cxx14_generic_lambdas cxx14_return_type_deduction cxx11_user_defined_literals + # list could go on... + ] + ; + +# Check consistency of build systems +testing.make-test run-pyd : check_build_system.py : + <dependency>Jamfile <dependency>CMakeLists.txt ; + +# Verify One Definition Rule by linking two object files which include everything +testing.make-test run-pyd : check_odr_test.py : <dependency>odr_test.cpp ; +alias odr : + [ link odr_main_test.cpp odr_test.cpp ] + ; + +alias cxx14 : + [ run accumulators_test.cpp ] + [ run algorithm_project_test.cpp ] + [ run algorithm_reduce_test.cpp ] + [ run algorithm_sum_test.cpp ] + [ run algorithm_empty_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 detail_accumulator_traits_test.cpp ] + [ run detail_argument_traits_test.cpp ] + [ run detail_args_type_test.cpp ] + [ run detail_axes_test.cpp ] + [ run detail_convert_integer_test.cpp ] + [ run detail_detect_test.cpp ] + [ run detail_limits_test.cpp ] + [ run detail_make_default_test.cpp ] + [ run detail_misc_test.cpp ] + [ run detail_iterator_adaptor_test.cpp ] + [ run detail_large_int_test.cpp ] + [ run detail_operators_test.cpp ] + [ run detail_relaxed_equal_test.cpp ] + [ run detail_replace_type_test.cpp ] + [ run detail_safe_comparison_test.cpp ] + [ run detail_static_if_test.cpp ] + [ run detail_tuple_slice_test.cpp ] + [ run histogram_custom_axis_test.cpp ] + [ run histogram_dynamic_test.cpp ] + [ run histogram_fill_test.cpp ] + [ run histogram_growing_test.cpp ] + [ run histogram_mixed_test.cpp ] + [ run histogram_operators_test.cpp ] + [ run histogram_ostream_test.cpp ] + [ run histogram_test.cpp ] + [ run indexed_test.cpp ] + [ run storage_adaptor_test.cpp ] + [ run unlimited_storage_test.cpp ] + [ run utility_test.cpp ] + ; + +alias cxx17 : + [ run deduction_guides_test.cpp ] : + [ requires cpp_deduction_guides ] + ; + +# check that useful error messages are produced when library is used incorrectly +alias failure : + [ compile-fail axis_category_fail0.cpp ] + [ compile-fail axis_category_fail1.cpp ] + [ compile-fail axis_category_fail2.cpp ] + [ compile-fail axis_integer_fail0.cpp ] + [ compile-fail axis_integer_fail1.cpp ] + [ compile-fail axis_integer_fail2.cpp ] + [ compile-fail axis_integer_fail3.cpp ] + [ compile-fail axis_integer_fail4.cpp ] + [ compile-fail axis_regular_fail0.cpp ] + [ compile-fail axis_regular_fail1.cpp ] + [ compile-fail axis_variable_fail0.cpp ] + [ compile-fail axis_variable_fail1.cpp ] + [ compile-fail make_histogram_fail0.cpp ] + [ compile-fail make_histogram_fail1.cpp ] + [ compile-fail histogram_fail0.cpp ] + [ compile-fail histogram_fail1.cpp ] + [ compile-fail histogram_fail2.cpp ] + [ compile-fail histogram_fail3.cpp ] + [ compile-fail histogram_fail4.cpp ] + ; + +alias threading : + [ run histogram_threaded_test.cpp ] + [ run storage_adaptor_threaded_test.cpp ] + : + <threading>multi + ; + +# warnings are off for these other boost libraries, which tend to be not warning-free +alias accumulators : [ run boost_accumulators_support_test.cpp ] : <warnings>off ; +alias range : [ run boost_range_support_test.cpp ] : <warnings>off ; +alias units : [ run boost_units_support_test.cpp ] : <warnings>off ; +alias serialization : + [ run accumulators_serialization_test.cpp libserial : $(THIS_PATH) ] + [ run detail_array_wrapper_serialization_test.cpp libserial ] + [ run axis_variant_serialization_test.cpp libserial : $(THIS_PATH) ] + [ run histogram_serialization_test.cpp libserial : $(THIS_PATH) ] + [ run storage_adaptor_serialization_test.cpp libserial : $(THIS_PATH) ] + [ run unlimited_storage_serialization_test.cpp libserial : $(THIS_PATH) ] + ; + +alias libserial : + /boost/serialization//boost_serialization + : + <link>static <warnings>off <rtti>on + ; + +# for builds without optional boost dependencies +alias minimal : odr cxx14 cxx17 failure threading ; + +# all tests +alias all : minimal accumulators range units serialization ; + +# all except "failure", because it is distracting during development +alias develop : odr cxx14 cxx17 threading accumulators range units serialization ; + +explicit minimal ; +explicit all ; +explicit odr ; +explicit cxx14 ; +explicit cxx17 ; +explicit failure ; +explicit threading ; +explicit accumulators ; +explicit range ; +explicit units ; +explicit serialization ; +explicit libserial ; diff --git a/src/boost/libs/histogram/test/accumulators_serialization_test.cpp b/src/boost/libs/histogram/test/accumulators_serialization_test.cpp new file mode 100644 index 00000000..b97ff6bf --- /dev/null +++ b/src/boost/libs/histogram/test/accumulators_serialization_test.cpp @@ -0,0 +1,91 @@ +// 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/assert.hpp> +#include <boost/core/lightweight_test.hpp> +#include <boost/histogram/accumulators.hpp> +#include <boost/histogram/serialization.hpp> +#include <boost/histogram/weight.hpp> +#include "throw_exception.hpp" +#include "utility_serialization.hpp" + +using namespace boost::histogram; + +int main(int argc, char** argv) { + BOOST_ASSERT(argc == 2); + + // mean v0 + { + const auto filename = join(argv[1], "accumulators_serialization_test_mean_v0.xml"); + accumulators::mean<> a; + load_xml(filename, a); + BOOST_TEST_EQ(a.count(), 3); + BOOST_TEST_EQ(a.value(), 2); + BOOST_TEST_EQ(a.variance(), 0.5); + } + + // mean + { + const auto filename = join(argv[1], "accumulators_serialization_test_mean.xml"); + accumulators::mean<> a; + a(1); + a(weight(0.5), 2); + a(3); + print_xml(filename, a); + + accumulators::mean<> b; + BOOST_TEST_NOT(a == b); + load_xml(filename, b); + BOOST_TEST(a == b); + } + + // sum + { + const auto filename = join(argv[1], "accumulators_serialization_test_sum.xml"); + accumulators::sum<> a; + a += 1e100; + a += 1; + print_xml(filename, a); + + accumulators::sum<> b; + BOOST_TEST_NOT(a == b); + load_xml(filename, b); + BOOST_TEST(a == b); + } + + // weighted_mean + { + const auto filename = + join(argv[1], "accumulators_serialization_test_weighted_mean.xml"); + accumulators::weighted_mean<> a; + a(1); + a(weight(0.5), 2); + a(3); + print_xml(filename, a); + + accumulators::weighted_mean<> b; + BOOST_TEST_NOT(a == b); + load_xml(filename, b); + BOOST_TEST(a == b); + } + + // weighted_sum + { + const auto filename = + join(argv[1], "accumulators_serialization_test_weighted_sum.xml"); + accumulators::weighted_sum<> a; + a += 1; + a += 10; + print_xml(filename, a); + + accumulators::weighted_sum<> b; + BOOST_TEST_NOT(a == b); + load_xml(filename, b); + BOOST_TEST(a == b); + } + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/accumulators_serialization_test_mean.xml b/src/boost/libs/histogram/test/accumulators_serialization_test_mean.xml new file mode 100644 index 00000000..b63a1b0b --- /dev/null +++ b/src/boost/libs/histogram/test/accumulators_serialization_test_mean.xml @@ -0,0 +1,17 @@ +<!-- + 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) +--> + +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<!DOCTYPE boost_serialization> +<boost_serialization signature="serialization::archive" version="17"> +<item class_id="0" tracking_level="0" version="1"> + <sum>2.50000000000000000e+00</sum> + <mean>2.00000000000000000e+00</mean> + <sum_of_deltas_squared>2.00000000000000000e+00</sum_of_deltas_squared> +</item> +</boost_serialization> diff --git a/src/boost/libs/histogram/test/accumulators_serialization_test_mean_v0.xml b/src/boost/libs/histogram/test/accumulators_serialization_test_mean_v0.xml new file mode 100644 index 00000000..9e377202 --- /dev/null +++ b/src/boost/libs/histogram/test/accumulators_serialization_test_mean_v0.xml @@ -0,0 +1,17 @@ +<!-- + 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) +--> + +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<!DOCTYPE boost_serialization> +<boost_serialization signature="serialization::archive" version="17"> +<item class_id="0" tracking_level="0" version="0"> + <sum>3</sum> + <mean>2.00000000000000000e+00</mean> + <sum_of_deltas_squared>1.00000000000000000e+00</sum_of_deltas_squared> +</item> +</boost_serialization> diff --git a/src/boost/libs/histogram/test/accumulators_serialization_test_sum.xml b/src/boost/libs/histogram/test/accumulators_serialization_test_sum.xml new file mode 100644 index 00000000..1be3926c --- /dev/null +++ b/src/boost/libs/histogram/test/accumulators_serialization_test_sum.xml @@ -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) +--> + +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<!DOCTYPE boost_serialization> +<boost_serialization signature="serialization::archive" version="17"> +<item class_id="0" tracking_level="0" version="0"> + <large>1.00000000000000002e+100</large> + <small>1.00000000000000000e+00</small> +</item> +</boost_serialization> diff --git a/src/boost/libs/histogram/test/accumulators_serialization_test_weighted_mean.xml b/src/boost/libs/histogram/test/accumulators_serialization_test_weighted_mean.xml new file mode 100644 index 00000000..7feefc59 --- /dev/null +++ b/src/boost/libs/histogram/test/accumulators_serialization_test_weighted_mean.xml @@ -0,0 +1,18 @@ +<!-- + 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) +--> + +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<!DOCTYPE boost_serialization> +<boost_serialization signature="serialization::archive" version="17"> +<item class_id="0" tracking_level="0" version="0"> + <sum_of_weights>2.50000000000000000e+00</sum_of_weights> + <sum_of_weights_squared>2.25000000000000000e+00</sum_of_weights_squared> + <weighted_mean>2.00000000000000000e+00</weighted_mean> + <sum_of_weighted_deltas_squared>2.00000000000000000e+00</sum_of_weighted_deltas_squared> +</item> +</boost_serialization> diff --git a/src/boost/libs/histogram/test/accumulators_serialization_test_weighted_sum.xml b/src/boost/libs/histogram/test/accumulators_serialization_test_weighted_sum.xml new file mode 100644 index 00000000..9412c626 --- /dev/null +++ b/src/boost/libs/histogram/test/accumulators_serialization_test_weighted_sum.xml @@ -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) +--> + +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<!DOCTYPE boost_serialization> +<boost_serialization signature="serialization::archive" version="17"> +<item class_id="0" tracking_level="0" version="0"> + <sum_of_weights>1.10000000000000000e+01</sum_of_weights> + <sum_of_weights_squared>1.01000000000000000e+02</sum_of_weights_squared> +</item> +</boost_serialization> diff --git a/src/boost/libs/histogram/test/accumulators_test.cpp b/src/boost/libs/histogram/test/accumulators_test.cpp new file mode 100644 index 00000000..69177685 --- /dev/null +++ b/src/boost/libs/histogram/test/accumulators_test.cpp @@ -0,0 +1,227 @@ +// Copyright 2015-2018 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/core/lightweight_test.hpp> +#include <boost/histogram/accumulators/mean.hpp> +#include <boost/histogram/accumulators/ostream.hpp> +#include <boost/histogram/accumulators/sum.hpp> +#include <boost/histogram/accumulators/thread_safe.hpp> +#include <boost/histogram/accumulators/weighted_mean.hpp> +#include <boost/histogram/accumulators/weighted_sum.hpp> +#include <boost/histogram/weight.hpp> +#include <sstream> +#include "is_close.hpp" +#include "throw_exception.hpp" + +using namespace boost::histogram; +using namespace std::literals; + +template <class T> +auto str(const T& t, int w = 0, bool left = true) { + std::ostringstream os; + os.width(w); + if (left) + os << std::left; + else + os << std::right; + os << t; + return os.str(); +} + +int main() { + { + using w_t = accumulators::weighted_sum<double>; + w_t w; + BOOST_TEST_EQ(str(w), "weighted_sum(0, 0)"s); + BOOST_TEST_EQ(str(w, 20, false), " weighted_sum(0, 0)"s); + BOOST_TEST_EQ(str(w, 20, true), "weighted_sum(0, 0) "s); + BOOST_TEST_EQ(w, w_t{}); + + BOOST_TEST_EQ(w, w_t(0)); + BOOST_TEST_NE(w, w_t(1)); + w = w_t(1); + BOOST_TEST_EQ(w.value(), 1); + BOOST_TEST_EQ(w.variance(), 1); + BOOST_TEST_EQ(w, 1); + BOOST_TEST_NE(w, 2); + + w += 2; + BOOST_TEST_EQ(w.value(), 3); + BOOST_TEST_EQ(w.variance(), 5); + BOOST_TEST_EQ(w, w_t(3, 5)); + BOOST_TEST_NE(w, w_t(3)); + + w += w_t(1, 2); + BOOST_TEST_EQ(w.value(), 4); + BOOST_TEST_EQ(w.variance(), 7); + + // consistency: a weighted counter increased by weight 1 multiplied + // by 2 must be the same as a weighted counter increased by weight 2 + w_t u(0); + ++u; + u *= 2; + BOOST_TEST_EQ(u, w_t(2, 4)); + + w_t v(0); + v += 2; + BOOST_TEST_EQ(u, v); + + // conversion to RealType + w_t y(1, 2); + BOOST_TEST_NE(y, 1); + BOOST_TEST_EQ(static_cast<double>(y), 1); + + BOOST_TEST_EQ(w_t() += w_t(), w_t()); + } + + { + using m_t = accumulators::mean<double>; + m_t a; + BOOST_TEST_EQ(a.count(), 0); + BOOST_TEST_EQ(a, m_t{}); + + a(4); + a(7); + a(13); + a(16); + + BOOST_TEST_EQ(a.count(), 4); + BOOST_TEST_EQ(a.value(), 10); + BOOST_TEST_EQ(a.variance(), 30); + + BOOST_TEST_EQ(str(a), "mean(4, 10, 30)"s); + BOOST_TEST_EQ(str(a, 20, false), " mean(4, 10, 30)"s); + BOOST_TEST_EQ(str(a, 20, true), "mean(4, 10, 30) "s); + + m_t b; + b(1e8 + 4); + b(1e8 + 7); + b(1e8 + 13); + b(1e8 + 16); + + BOOST_TEST_EQ(b.count(), 4); + BOOST_TEST_EQ(b.value(), 1e8 + 10); + BOOST_TEST_EQ(b.variance(), 30); + + auto c = a; + c += a; // same as feeding all samples twice + + BOOST_TEST_EQ(c.count(), 8); + BOOST_TEST_EQ(c.value(), 10); + BOOST_TEST_IS_CLOSE(c.variance(), 25.714, 1e-3); + + // also same as feeding all samples twice + m_t d; + d(weight(2), 4); + d(weight(2), 7); + d(weight(2), 13); + d(weight(2), 16); + + BOOST_TEST_EQ(d, c); + + BOOST_TEST_EQ(m_t() += m_t(), m_t()); + BOOST_TEST_EQ(m_t(1, 2, 3) += m_t(), m_t(1, 2, 3)); + BOOST_TEST_EQ(m_t() += m_t(1, 2, 3), m_t(1, 2, 3)); + } + + { + using m_t = accumulators::weighted_mean<double>; + m_t a; + BOOST_TEST_EQ(a.sum_of_weights(), 0); + BOOST_TEST_EQ(a, m_t{}); + + a(weight(0.5), 1); + a(weight(1.0), 2); + a(weight(0.5), 3); + + BOOST_TEST_EQ(a.sum_of_weights(), 2); + BOOST_TEST_EQ(a.sum_of_weights_squared(), 1.5); + BOOST_TEST_EQ(a.value(), 2); + BOOST_TEST_IS_CLOSE(a.variance(), 0.8, 1e-3); + + BOOST_TEST_EQ(str(a), "weighted_mean(2, 2, 0.8)"s); + BOOST_TEST_EQ(str(a, 25, false), " weighted_mean(2, 2, 0.8)"s); + BOOST_TEST_EQ(str(a, 25, true), "weighted_mean(2, 2, 0.8) "s); + + auto b = a; + b += a; // same as feeding all samples twice + + BOOST_TEST_EQ(b.sum_of_weights(), 4); + BOOST_TEST_EQ(b.value(), 2); + BOOST_TEST_IS_CLOSE(b.variance(), 0.615, 1e-3); + + BOOST_TEST_EQ(m_t() += m_t(), m_t()); + BOOST_TEST_EQ(m_t(1, 2, 3, 4) += m_t(), m_t(1, 2, 3, 4)); + BOOST_TEST_EQ(m_t() += m_t(1, 2, 3, 4), m_t(1, 2, 3, 4)); + } + + { + double bad_sum = 0; + bad_sum += 1; + bad_sum += 1e100; + bad_sum += 1; + bad_sum += -1e100; + BOOST_TEST_EQ(bad_sum, 0); // instead of 2 + + using s_t = accumulators::sum<double>; + s_t sum; + ++sum; + BOOST_TEST_EQ(sum.large(), 1); + BOOST_TEST_EQ(sum.small(), 0); + BOOST_TEST_EQ(str(sum), "sum(1 + 0)"s); + BOOST_TEST_EQ(str(sum, 15, false), " sum(1 + 0)"s); + BOOST_TEST_EQ(str(sum, 15, true), "sum(1 + 0) "s); + + sum += 1e100; + BOOST_TEST_EQ(str(sum), "sum(1e+100 + 1)"s); + ++sum; + BOOST_TEST_EQ(str(sum), "sum(1e+100 + 2)"s); + sum += -1e100; + BOOST_TEST_EQ(str(sum), "sum(0 + 2)"s); + BOOST_TEST_EQ(sum, 2); // correct answer + BOOST_TEST_EQ(sum.large(), 0); + BOOST_TEST_EQ(sum.small(), 2); + + accumulators::sum<double> a(3), b(2), c(3); + BOOST_TEST_LT(b, c); + BOOST_TEST_LE(b, c); + BOOST_TEST_LE(a, c); + BOOST_TEST_GT(a, b); + BOOST_TEST_GE(a, b); + BOOST_TEST_GE(a, c); + + BOOST_TEST_EQ(s_t() += s_t(), s_t()); + } + + { + using s_t = accumulators::weighted_sum<accumulators::sum<double>>; + s_t w; + + ++w; + w += 1e100; + ++w; + w += -1e100; + + BOOST_TEST_EQ(w.value(), 2); + BOOST_TEST_EQ(w.variance(), 2e200); + + BOOST_TEST_EQ(s_t() += s_t(), s_t()); + } + + { + using ts_t = accumulators::thread_safe<int>; + ts_t i; + ++i; + i += 1000; + + BOOST_TEST_EQ(i, 1001); + BOOST_TEST_EQ(str(i), "1001"s); + + BOOST_TEST_EQ(ts_t() += ts_t(), ts_t()); + } + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/algorithm_empty_test.cpp b/src/boost/libs/histogram/test/algorithm_empty_test.cpp new file mode 100644 index 00000000..f3787f04 --- /dev/null +++ b/src/boost/libs/histogram/test/algorithm_empty_test.cpp @@ -0,0 +1,65 @@ +// Copyright 2018 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 <array> +#include <boost/core/lightweight_test.hpp> +#include <boost/histogram/accumulators/weighted_mean.hpp> +#include <boost/histogram/algorithm/empty.hpp> +#include <boost/histogram/axis/integer.hpp> +#include <unordered_map> +#include <vector> +#include "throw_exception.hpp" +#include "utility_histogram.hpp" + +using namespace boost::histogram; +using boost::histogram::algorithm::empty; + +template <typename Tag> +void run_tests() { + auto ax = axis::integer<>(0, 10); + + { + auto h = make(Tag(), ax); + BOOST_TEST(empty(h, coverage::all)); + BOOST_TEST(empty(h, coverage::inner)); + for (int i = -1; i < 11; ++i) { + h.reset(); + h(i); + BOOST_TEST(!empty(h, coverage::all)); + if (i == -1 || i == 10) { + BOOST_TEST(empty(h, coverage::inner)); + } else { + BOOST_TEST(!empty(h, coverage::inner)); + } + } + } + + { + auto h = make_s(Tag(), std::vector<accumulators::weighted_mean<>>(), + axis::integer<>(0, 10), axis::integer<>(0, 10)); + BOOST_TEST(empty(h, coverage::all)); + BOOST_TEST(empty(h, coverage::inner)); + h.reset(); + h(weight(2), -2, -4, sample(3)); + BOOST_TEST(!empty(h, coverage::all)); + BOOST_TEST(empty(h, coverage::inner)); + h.reset(); + h(weight(1), -4, 2, sample(2)); + BOOST_TEST(!empty(h, coverage::all)); + BOOST_TEST(empty(h, coverage::inner)); + h.reset(); + h(weight(3), 3, 5, sample(1)); + BOOST_TEST(!empty(h, coverage::all)); + BOOST_TEST(!empty(h, coverage::inner)); + } +} + +int main() { + run_tests<static_tag>(); + run_tests<dynamic_tag>(); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/algorithm_project_test.cpp b/src/boost/libs/histogram/test/algorithm_project_test.cpp new file mode 100644 index 00000000..79c5e793 --- /dev/null +++ b/src/boost/libs/histogram/test/algorithm_project_test.cpp @@ -0,0 +1,193 @@ +// Copyright 2015-2018 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/core/lightweight_test.hpp> +#include <boost/histogram/algorithm/project.hpp> +#include <boost/histogram/algorithm/sum.hpp> +#include <boost/histogram/axis/integer.hpp> +#include <boost/histogram/axis/ostream.hpp> +#include <boost/histogram/literals.hpp> +#include <boost/histogram/ostream.hpp> +#include <vector> +#include "throw_exception.hpp" +#include "utility_histogram.hpp" + +using namespace boost::histogram; +using namespace boost::histogram::literals; // to get _c suffix +using namespace boost::histogram::algorithm; + +template <typename Tag> +void run_tests() { + { + auto h = make(Tag(), axis::integer<>(0, 2), axis::integer<>(0, 3)); + h(0, 0); + h(0, 1); + h(1, 0); + h(1, 1); + h(1, 2); + h(1, 2); + + /* + matrix layout: + + x -> + y 1 1 + | 1 1 + v 0 2 + */ + + auto hx = project(h, 0_c); + BOOST_TEST_EQ(hx.rank(), 1); + BOOST_TEST_EQ(sum(hx), 6); + BOOST_TEST_EQ(hx.axis(), h.axis(0_c)); + BOOST_TEST_EQ(hx.at(0), 2); + BOOST_TEST_EQ(hx.at(1), 4); + + auto hy = project(h, 1_c); + BOOST_TEST_EQ(hy.rank(), 1); + BOOST_TEST_EQ(sum(hy), 6); + BOOST_TEST_EQ(hy.axis(), h.axis(1_c)); + BOOST_TEST_EQ(hy.at(0), 2); + BOOST_TEST_EQ(hy.at(1), 2); + BOOST_TEST_EQ(hy.at(2), 2); + + auto hyx = project(h, 1_c, 0_c); + BOOST_TEST_EQ(hyx.rank(), 2); + BOOST_TEST_EQ(sum(hyx), 6); + BOOST_TEST_EQ(hyx.axis(0_c), h.axis(1_c)); + BOOST_TEST_EQ(hyx.axis(1_c), h.axis(0_c)); + BOOST_TEST_EQ(hyx.at(0, 0), 1); + BOOST_TEST_EQ(hyx.at(1, 0), 1); + BOOST_TEST_EQ(hyx.at(2, 0), 0); + BOOST_TEST_EQ(hyx.at(0, 1), 1); + BOOST_TEST_EQ(hyx.at(1, 1), 1); + BOOST_TEST_EQ(hyx.at(2, 1), 2); + } + + { + auto h = + make(Tag(), axis::integer<>(0, 2), axis::integer<>(0, 3), axis::integer<>(0, 4)); + h(0, 0, 0); + h(0, 1, 0); + h(0, 1, 1); + h(0, 0, 2); + h(1, 0, 2); + + auto h_0 = project(h, 0_c); + BOOST_TEST_EQ(h_0.rank(), 1); + BOOST_TEST_EQ(sum(h_0), 5); + BOOST_TEST_EQ(h_0.at(0), 4); + BOOST_TEST_EQ(h_0.at(1), 1); + BOOST_TEST_EQ(h_0.axis(), axis::integer<>(0, 2)); + + auto h_1 = project(h, 1_c); + BOOST_TEST_EQ(h_1.rank(), 1); + BOOST_TEST_EQ(sum(h_1), 5); + BOOST_TEST_EQ(h_1.at(0), 3); + BOOST_TEST_EQ(h_1.at(1), 2); + BOOST_TEST_EQ(h_1.axis(), axis::integer<>(0, 3)); + + auto h_2 = project(h, 2_c); + BOOST_TEST_EQ(h_2.rank(), 1); + BOOST_TEST_EQ(sum(h_2), 5); + BOOST_TEST_EQ(h_2.at(0), 2); + BOOST_TEST_EQ(h_2.at(1), 1); + BOOST_TEST_EQ(h_2.at(2), 2); + BOOST_TEST_EQ(h_2.axis(), axis::integer<>(0, 4)); + + auto h_01 = project(h, 0_c, 1_c); + BOOST_TEST_EQ(h_01.rank(), 2); + BOOST_TEST_EQ(sum(h_01), 5); + BOOST_TEST_EQ(h_01.at(0, 0), 2); + BOOST_TEST_EQ(h_01.at(0, 1), 2); + BOOST_TEST_EQ(h_01.at(1, 0), 1); + BOOST_TEST_EQ(h_01.axis(0_c), axis::integer<>(0, 2)); + BOOST_TEST_EQ(h_01.axis(1_c), axis::integer<>(0, 3)); + + auto h_02 = project(h, 0_c, 2_c); + BOOST_TEST_EQ(h_02.rank(), 2); + BOOST_TEST_EQ(sum(h_02), 5); + BOOST_TEST_EQ(h_02.at(0, 0), 2); + BOOST_TEST_EQ(h_02.at(0, 1), 1); + BOOST_TEST_EQ(h_02.at(0, 2), 1); + BOOST_TEST_EQ(h_02.at(1, 2), 1); + BOOST_TEST_EQ(h_02.axis(0_c), axis::integer<>(0, 2)); + BOOST_TEST_EQ(h_02.axis(1_c), axis::integer<>(0, 4)); + + auto h_12 = project(h, 1_c, 2_c); + BOOST_TEST_EQ(h_12.rank(), 2); + BOOST_TEST_EQ(sum(h_12), 5); + BOOST_TEST_EQ(h_12.at(0, 0), 1); + BOOST_TEST_EQ(h_12.at(1, 0), 1); + BOOST_TEST_EQ(h_12.at(1, 1), 1); + BOOST_TEST_EQ(h_12.at(0, 2), 2); + BOOST_TEST_EQ(h_12.axis(0_c), axis::integer<>(0, 3)); + BOOST_TEST_EQ(h_12.axis(1_c), axis::integer<>(0, 4)); + + auto h_210 = project(h, 2_c, 1_c, 0_c); + BOOST_TEST_EQ(h_210.at(0, 0, 0), 1); + BOOST_TEST_EQ(h_210.at(0, 1, 0), 1); + BOOST_TEST_EQ(h_210.at(1, 1, 0), 1); + BOOST_TEST_EQ(h_210.at(2, 0, 0), 1); + BOOST_TEST_EQ(h_210.at(2, 0, 1), 1); + } + + { + auto h = make(dynamic_tag(), axis::integer<>(0, 2), axis::integer<>(0, 3)); + h(0, 0); + h(0, 1); + h(1, 0); + h(1, 1); + h(1, 2); + h(1, 2); + + std::vector<int> x; + + x = {0}; + auto hx = project(h, x); + BOOST_TEST_EQ(hx.rank(), 1); + BOOST_TEST_EQ(sum(hx), 6); + BOOST_TEST_EQ(hx.at(0), 2); + BOOST_TEST_EQ(hx.at(1), 4); + BOOST_TEST(hx.axis() == h.axis(0_c)); + + x = {1}; + auto hy = project(h, x); + BOOST_TEST_EQ(hy.rank(), 1); + BOOST_TEST_EQ(sum(hy), 6); + BOOST_TEST_EQ(hy.at(0), 2); + BOOST_TEST_EQ(hy.at(1), 2); + BOOST_TEST_EQ(hy.at(2), 2); + BOOST_TEST(hy.axis() == h.axis(1_c)); + + x = {1, 0}; + auto hyx = project(h, x); + BOOST_TEST_EQ(hyx.rank(), 2); + BOOST_TEST_EQ(hyx.axis(0_c), h.axis(1_c)); + BOOST_TEST_EQ(hyx.axis(1_c), h.axis(0_c)); + BOOST_TEST_EQ(sum(hyx), 6); + BOOST_TEST_EQ(hyx.at(0, 0), 1); + BOOST_TEST_EQ(hyx.at(1, 0), 1); + BOOST_TEST_EQ(hyx.at(0, 1), 1); + BOOST_TEST_EQ(hyx.at(1, 1), 1); + BOOST_TEST_EQ(hyx.at(2, 1), 2); + + // indices must be unique + x = {0, 0}; + BOOST_TEST_THROWS((void)project(h, x), std::invalid_argument); + + // indices must be valid + x = {2, 1}; + BOOST_TEST_THROWS((void)project(h, x), std::invalid_argument); + } +} + +int main() { + run_tests<static_tag>(); + run_tests<dynamic_tag>(); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/algorithm_reduce_test.cpp b/src/boost/libs/histogram/test/algorithm_reduce_test.cpp new file mode 100644 index 00000000..4b170e17 --- /dev/null +++ b/src/boost/libs/histogram/test/algorithm_reduce_test.cpp @@ -0,0 +1,234 @@ +// Copyright 2018 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/core/lightweight_test.hpp> +#include <boost/histogram/algorithm/reduce.hpp> +#include <boost/histogram/algorithm/sum.hpp> +#include <boost/histogram/axis/category.hpp> +#include <boost/histogram/axis/integer.hpp> +#include <boost/histogram/axis/ostream.hpp> +#include <boost/histogram/axis/regular.hpp> +#include <boost/histogram/axis/variable.hpp> +#include <boost/histogram/ostream.hpp> +#include <boost/histogram/unsafe_access.hpp> +#include <vector> +#include "throw_exception.hpp" +#include "utility_histogram.hpp" + +using namespace boost::histogram; +using namespace boost::histogram::algorithm; + +template <typename Tag> +void run_tests() { + // reduce: + // - does not work with arguments not convertible to double + // - does not work with category axis, which is not ordered + + using R = axis::regular<double, axis::transform::id, axis::null_type>; + using ID = axis::integer<double, axis::null_type>; + using V = axis::variable<double, axis::empty_type>; + using CI = axis::category<int, axis::empty_type>; + + // various failures + { + auto h = make(Tag(), R(4, 1, 5), R(3, -1, 2)); + + // not allowed: invalid axis index + BOOST_TEST_THROWS((void)reduce(h, slice(10, 2, 3)), std::invalid_argument); + // not allowed: repeated indices + BOOST_TEST_THROWS((void)reduce(h, slice(1, 0, 2), slice(1, 1, 3)), + std::invalid_argument); + BOOST_TEST_THROWS((void)reduce(h, rebin(0, 2), rebin(0, 2)), std::invalid_argument); + BOOST_TEST_THROWS((void)reduce(h, shrink(1, 0, 2), shrink(1, 0, 2)), + std::invalid_argument); + // not allowed: slice with begin >= end + BOOST_TEST_THROWS((void)reduce(h, slice(0, 1, 1)), std::invalid_argument); + BOOST_TEST_THROWS((void)reduce(h, slice(0, 2, 1)), std::invalid_argument); + // not allowed: shrink with lower == upper + BOOST_TEST_THROWS((void)reduce(h, shrink(0, 0, 0)), std::invalid_argument); + // not allowed: shrink axis to zero size + BOOST_TEST_THROWS((void)reduce(h, shrink(0, 10, 11)), std::invalid_argument); + // not allowed: rebin with zero merge + BOOST_TEST_THROWS((void)reduce(h, rebin(0, 0)), std::invalid_argument); + } + + // shrink behavior when value on edge and not on edge is inclusive: + // - lower edge of shrink: pick bin which contains edge, lower <= x < upper + // - upper edge of shrink: pick bin which contains edge + 1, lower < x <= upper + { + auto h = make(Tag(), ID(0, 3)); + const auto& ax = h.axis(); + BOOST_TEST_EQ(ax.value(0), 0); + BOOST_TEST_EQ(ax.value(1), 1); + BOOST_TEST_EQ(ax.value(2), 2); + BOOST_TEST_EQ(ax.value(3), 3); + BOOST_TEST_EQ(ax.index(-1), -1); + BOOST_TEST_EQ(ax.index(0), 0); + BOOST_TEST_EQ(ax.index(1), 1); + BOOST_TEST_EQ(ax.index(2), 2); + BOOST_TEST_EQ(ax.index(3), 3); + + BOOST_TEST_EQ(reduce(h, shrink(-1, 5)).axis(), ID(0, 3)); + BOOST_TEST_EQ(reduce(h, shrink(0, 3)).axis(), ID(0, 3)); + BOOST_TEST_EQ(reduce(h, shrink(1, 3)).axis(), ID(1, 3)); + BOOST_TEST_EQ(reduce(h, shrink(1.001, 3)).axis(), ID(1, 3)); + BOOST_TEST_EQ(reduce(h, shrink(1.999, 3)).axis(), ID(1, 3)); + BOOST_TEST_EQ(reduce(h, shrink(2, 3)).axis(), ID(2, 3)); + BOOST_TEST_EQ(reduce(h, shrink(0, 2.999)).axis(), ID(0, 3)); + BOOST_TEST_EQ(reduce(h, shrink(0, 2.001)).axis(), ID(0, 3)); + BOOST_TEST_EQ(reduce(h, shrink(0, 2)).axis(), ID(0, 2)); + BOOST_TEST_EQ(reduce(h, shrink(0, 1.999)).axis(), ID(0, 2)); + } + + { + auto h = make_s(Tag(), std::vector<int>(), R(4, 1, 5), R(3, -1, 2)); + + /* + matrix layout: + x -> + y 1 0 1 0 + | 1 1 0 0 + v 0 2 1 3 + */ + h.at(0, 0) = 1; + h.at(0, 1) = 1; + h.at(1, 1) = 1; + h.at(1, 2) = 2; + h.at(2, 0) = 1; + h.at(2, 2) = 1; + h.at(3, 2) = 3; + + // should do nothing, index order does not matter + auto hr = reduce(h, shrink(1, -1, 2), rebin(0, 1)); + BOOST_TEST_EQ(hr.rank(), 2); + BOOST_TEST_EQ(sum(hr), 10); + BOOST_TEST_EQ(hr.axis(0), R(4, 1, 5)); + BOOST_TEST_EQ(hr.axis(1), R(3, -1, 2)); + BOOST_TEST_EQ(hr, h); + + hr = reduce(h, slice(1, 0, 4), slice(0, 0, 4)); + BOOST_TEST_EQ(hr, h); + + hr = reduce(h, shrink(0, 2, 4)); + BOOST_TEST_EQ(hr.rank(), 2); + BOOST_TEST_EQ(sum(hr), 10); + BOOST_TEST_EQ(hr.axis(0), R(2, 2, 4)); + BOOST_TEST_EQ(hr.axis(1), R(3, -1, 2)); + BOOST_TEST_EQ(hr.at(-1, 0), 1); // underflow + BOOST_TEST_EQ(hr.at(0, 0), 0); + BOOST_TEST_EQ(hr.at(1, 0), 1); + BOOST_TEST_EQ(hr.at(2, 0), 0); // overflow + BOOST_TEST_EQ(hr.at(-1, 1), 1); + BOOST_TEST_EQ(hr.at(0, 1), 1); + BOOST_TEST_EQ(hr.at(1, 1), 0); + BOOST_TEST_EQ(hr.at(2, 1), 0); + BOOST_TEST_EQ(hr.at(-1, 2), 0); + BOOST_TEST_EQ(hr.at(0, 2), 2); + BOOST_TEST_EQ(hr.at(1, 2), 1); + BOOST_TEST_EQ(hr.at(2, 2), 3); + + /* + matrix layout: + x -> + y 1 0 1 0 + | 1 1 0 0 + v 0 2 1 3 + */ + + hr = reduce(h, shrink_and_rebin(0, 2, 5, 2), rebin(1, 3)); + BOOST_TEST_EQ(hr.rank(), 2); + BOOST_TEST_EQ(sum(hr), 10); + BOOST_TEST_EQ(hr.axis(0).size(), 1); + BOOST_TEST_EQ(hr.axis(1).size(), 1); + BOOST_TEST_EQ(hr.axis(0).bin(0).lower(), 2); + BOOST_TEST_EQ(hr.axis(0).bin(0).upper(), 4); + BOOST_TEST_EQ(hr.axis(1).bin(0).lower(), -1); + BOOST_TEST_EQ(hr.axis(1).bin(0).upper(), 2); + BOOST_TEST_EQ(hr.at(-1, 0), 2); // underflow + BOOST_TEST_EQ(hr.at(0, 0), 5); + BOOST_TEST_EQ(hr.at(1, 0), 3); // overflow + + // test overload that accepts iterable and test option fusion + std::vector<reduce_option> opts{{shrink(0, 2, 5), rebin(0, 2), rebin(1, 3)}}; + auto hr2 = reduce(h, opts); + BOOST_TEST_EQ(hr2, hr); + opts = {rebin(0, 2), slice(0, 1, 4), rebin(1, 3)}; + auto hr3 = reduce(h, opts); + BOOST_TEST_EQ(hr3, hr); + } + + // mixed axis types + { + R r(5, 0.0, 1.0); + V v{{1., 2., 3.}}; + CI c{{1, 2, 3}}; + auto h = make(Tag(), r, v, c); + auto hr = algorithm::reduce(h, shrink(0, 0.2, 0.7)); + BOOST_TEST_EQ(hr.axis(0).size(), 3); + BOOST_TEST_EQ(hr.axis(0).bin(0).lower(), 0.2); + BOOST_TEST_EQ(hr.axis(0).bin(2).upper(), 0.8); + BOOST_TEST_EQ(hr.axis(1).size(), 2); + BOOST_TEST_EQ(hr.axis(1).bin(0).lower(), 1); + BOOST_TEST_EQ(hr.axis(1).bin(1).upper(), 3); + BOOST_TEST_THROWS((void)algorithm::reduce(h, rebin(2, 2)), std::invalid_argument); + } + + // reduce on integer axis, rebin must fail + { + auto h = make(Tag(), axis::integer<>(1, 4)); + BOOST_TEST_THROWS((void)reduce(h, rebin(2)), std::invalid_argument); + auto hr = reduce(h, shrink(2, 3)); + BOOST_TEST_EQ(hr.axis().size(), 1); + BOOST_TEST_EQ(hr.axis().bin(0), 2); + BOOST_TEST_EQ(hr.axis().bin(1), 3); + } + + // reduce on circular axis, shrink must fail, also rebin with remainder + { + auto h = make(Tag(), axis::circular<>(4, 1, 4)); + BOOST_TEST_THROWS((void)reduce(h, shrink(0, 2)), std::invalid_argument); + BOOST_TEST_THROWS((void)reduce(h, rebin(3)), std::invalid_argument); + auto hr = reduce(h, rebin(2)); + BOOST_TEST_EQ(hr.axis().size(), 2); + BOOST_TEST_EQ(hr.axis().bin(0).lower(), 1); + BOOST_TEST_EQ(hr.axis().bin(1).upper(), 4); + } + + // reduce on variable axis + { + auto h = make(Tag(), V({0, 1, 2, 3, 4, 5, 6})); + auto hr = reduce(h, shrink_and_rebin(1, 5, 2)); + BOOST_TEST_EQ(hr.axis().size(), 2); + BOOST_TEST_EQ(hr.axis().value(0), 1); + BOOST_TEST_EQ(hr.axis().value(1), 3); + BOOST_TEST_EQ(hr.axis().value(2), 5); + } + + // reduce on axis with inverted range + { + auto h = make(Tag(), R(4, 2, -2)); + const auto& ax = h.axis(); + BOOST_TEST_EQ(ax.index(-0.999), 2); + BOOST_TEST_EQ(ax.index(-1.0), 3); + BOOST_TEST_EQ(ax.index(-1.5), 3); + + BOOST_TEST_EQ(reduce(h, shrink(3, -3)).axis(), R(4, 2, -2)); + BOOST_TEST_EQ(reduce(h, shrink(2, -2)).axis(), R(4, 2, -2)); + BOOST_TEST_EQ(reduce(h, shrink(1.999, -2)).axis(), R(4, 2, -2)); + BOOST_TEST_EQ(reduce(h, shrink(1.001, -2)).axis(), R(4, 2, -2)); + BOOST_TEST_EQ(reduce(h, shrink(1, -2)).axis(), R(3, 1, -2)); + BOOST_TEST_EQ(reduce(h, shrink(2, -1.999)).axis(), R(4, 2, -2)); + BOOST_TEST_EQ(reduce(h, shrink(2, -1.001)).axis(), R(4, 2, -2)); + BOOST_TEST_EQ(reduce(h, shrink(2, -1)).axis(), R(3, 2, -1)); + } +} + +int main() { + run_tests<static_tag>(); + run_tests<dynamic_tag>(); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/algorithm_sum_test.cpp b/src/boost/libs/histogram/test/algorithm_sum_test.cpp new file mode 100644 index 00000000..53f80ac9 --- /dev/null +++ b/src/boost/libs/histogram/test/algorithm_sum_test.cpp @@ -0,0 +1,58 @@ +// Copyright 2018 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 <array> +#include <boost/core/lightweight_test.hpp> +#include <boost/histogram/accumulators/weighted_sum.hpp> +#include <boost/histogram/algorithm/sum.hpp> +#include <boost/histogram/axis/integer.hpp> +#include "throw_exception.hpp" +#include <unordered_map> +#include <vector> +#include "utility_histogram.hpp" + +using namespace boost::histogram; +using boost::histogram::algorithm::sum; + +template <typename Tag> +void run_tests() { + auto ax = axis::integer<>(0, 100); + + auto h1 = make(Tag(), ax); + for (unsigned i = 0; i < 100; ++i) h1(i); + BOOST_TEST_EQ(sum(h1), 100); + + auto h2 = make_s(Tag(), std::vector<double>(), ax, ax); + for (unsigned i = 0; i < 100; ++i) + for (unsigned j = 0; j < 100; ++j) h2(i, j); + BOOST_TEST_EQ(sum(h2), 10000); + + auto h3 = make_s(Tag(), std::array<int, 102>(), ax); + for (unsigned i = 0; i < 100; ++i) h3(i); + BOOST_TEST_EQ(sum(h3), 100); + + auto h4 = make_s(Tag(), std::unordered_map<std::size_t, int>(), ax); + for (unsigned i = 0; i < 100; ++i) h4(i); + BOOST_TEST_EQ(sum(h4), 100); + + auto h5 = + make_s(Tag(), std::vector<accumulators::weighted_sum<>>(), axis::integer<>(0, 1), + axis::integer<int, axis::null_type, axis::option::none_t>(2, 4)); + h5(weight(2), 0, 2); + h5(-1, 2); + h5(1, 3); + + const auto v = algorithm::sum(h5); + BOOST_TEST_EQ(v.value(), 4); + BOOST_TEST_EQ(v.variance(), 6); +} + +int main() { + run_tests<static_tag>(); + run_tests<dynamic_tag>(); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/axis_category_fail0.cpp b/src/boost/libs/histogram/test/axis_category_fail0.cpp new file mode 100644 index 00000000..cc6d1cce --- /dev/null +++ b/src/boost/libs/histogram/test/axis_category_fail0.cpp @@ -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/axis/category.hpp> + +using namespace boost::histogram; + +int main() { + // category axis cannot be circular + (void)axis::category<int, boost::use_default, axis::option::circular_t>({1, 2}); +} diff --git a/src/boost/libs/histogram/test/axis_category_fail1.cpp b/src/boost/libs/histogram/test/axis_category_fail1.cpp new file mode 100644 index 00000000..cda21cd6 --- /dev/null +++ b/src/boost/libs/histogram/test/axis_category_fail1.cpp @@ -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/axis/category.hpp> + +using namespace boost::histogram; + +int main() { + // category axis cannot have underflow + (void)axis::category<int, boost::use_default, axis::option::underflow_t>({1, 2}); +} diff --git a/src/boost/libs/histogram/test/axis_category_fail2.cpp b/src/boost/libs/histogram/test/axis_category_fail2.cpp new file mode 100644 index 00000000..53d2de9d --- /dev/null +++ b/src/boost/libs/histogram/test/axis_category_fail2.cpp @@ -0,0 +1,15 @@ +// 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/category.hpp> + +using namespace boost::histogram; + +int main() { + // growing category axis cannot have entries in overflow bin + (void)axis::category<int, boost::use_default, + decltype(axis::option::growth | axis::option::overflow)>({1, 2}); +} diff --git a/src/boost/libs/histogram/test/axis_category_test.cpp b/src/boost/libs/histogram/test/axis_category_test.cpp new file mode 100644 index 00000000..92951a56 --- /dev/null +++ b/src/boost/libs/histogram/test/axis_category_test.cpp @@ -0,0 +1,157 @@ +// Copyright 2015-2018 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/core/ignore_unused.hpp> +#include <boost/core/lightweight_test.hpp> +#include <boost/core/lightweight_test_trait.hpp> +#include <boost/histogram/axis/category.hpp> +#include <boost/histogram/axis/ostream.hpp> +#include <boost/histogram/axis/traits.hpp> +#include <limits> +#include <sstream> +#include <string> +#include <type_traits> +#include "std_ostream.hpp" +#include "throw_exception.hpp" +#include "utility_axis.hpp" +#include "utility_str.hpp" + +int main() { + using namespace boost::histogram; + + BOOST_TEST(std::is_nothrow_move_constructible<axis::category<int>>::value); + BOOST_TEST(std::is_nothrow_move_constructible<axis::category<std::string>>::value); + BOOST_TEST(std::is_nothrow_move_assignable<axis::category<int>>::value); + BOOST_TEST(std::is_nothrow_move_assignable<axis::category<std::string>>::value); + + // bad ctor + { + int x[2]; + boost::ignore_unused(x); + BOOST_TEST_THROWS(axis::category<int>(x + 1, x), std::invalid_argument); + } + + // value should return copy for arithmetic types and const reference otherwise + { + enum class Foo { foo }; + + BOOST_TEST_TRAIT_SAME(axis::traits::value_type<axis::category<std::string>>, + std::string); + BOOST_TEST_TRAIT_SAME(decltype(std::declval<axis::category<std::string>>().value(0)), + const std::string&); + BOOST_TEST_TRAIT_SAME(axis::traits::value_type<axis::category<const char*>>, + const char*); + BOOST_TEST_TRAIT_SAME(decltype(std::declval<axis::category<const char*>>().value(0)), + const char*); + BOOST_TEST_TRAIT_SAME(axis::traits::value_type<axis::category<Foo>>, Foo); + BOOST_TEST_TRAIT_SAME(decltype(std::declval<axis::category<Foo>>().value(0)), Foo); + BOOST_TEST_TRAIT_SAME(axis::traits::value_type<axis::category<int>>, int); + BOOST_TEST_TRAIT_SAME(decltype(std::declval<axis::category<int>>().value(0)), int); + } + + // empty axis::category + { + axis::category<int> a; + axis::category<int> b(std::vector<int>(0)); + BOOST_TEST_EQ(a, b); + BOOST_TEST_EQ(a.size(), 0); + BOOST_TEST_EQ(a.index(-1), 0); + BOOST_TEST_EQ(a.index(0), 0); + BOOST_TEST_EQ(a.index(1), 0); + } + + // axis::category + { + std::string A("A"), B("B"), C("C"), other; + + axis::category<std::string> a({A, B, C}, "foo"); + BOOST_TEST_EQ(a.metadata(), "foo"); + BOOST_TEST_EQ(static_cast<const axis::category<std::string>&>(a).metadata(), "foo"); + a.metadata() = "bar"; + BOOST_TEST_EQ(static_cast<const axis::category<std::string>&>(a).metadata(), "bar"); + BOOST_TEST_EQ(a.size(), 3); + BOOST_TEST_EQ(a.index(A), 0); + BOOST_TEST_EQ(a.index(B), 1); + BOOST_TEST_EQ(a.index(C), 2); + BOOST_TEST_EQ(a.index(other), 3); + BOOST_TEST_EQ(a.value(0), A); + BOOST_TEST_EQ(a.value(1), B); + BOOST_TEST_EQ(a.value(2), C); + BOOST_TEST_THROWS(a.value(3), std::out_of_range); + + BOOST_TEST_EQ(str(a), + "category(\"A\", \"B\", \"C\", metadata=\"bar\", options=overflow)"); + } + + // category<int, axis::null_type>: copy, move + { + using C = axis::category<int, axis::null_type>; + C a({1, 2, 3}); + C a2(a); + BOOST_TEST_EQ(a2, a); + C b; + BOOST_TEST_NE(a, b); + b = a; + BOOST_TEST_EQ(a, b); + b = C{{2, 1, 3}}; + BOOST_TEST_NE(a, b); + b = a; + BOOST_TEST_EQ(a, b); + C c = std::move(b); + BOOST_TEST_EQ(c, a); + C d; + BOOST_TEST_NE(c, d); + d = std::move(c); + BOOST_TEST_EQ(d, a); + } + + // category<std::string>: copy, move + { + using C = axis::category<std::string>; + + C a({"A", "B", "C"}, "foo"); + C a2(a); + BOOST_TEST_EQ(a2, a); + C b; + BOOST_TEST_NE(a, b); + b = a; + BOOST_TEST_EQ(a, b); + b = C{{"B", "A", "C"}}; + BOOST_TEST_NE(a, b); + b = a; + BOOST_TEST_EQ(a, b); + C c = std::move(b); + BOOST_TEST_EQ(c, a); + C d; + BOOST_TEST_NE(c, d); + d = std::move(c); + BOOST_TEST_EQ(d, a); + } + + // axis::category with growth + { + axis::category<int, axis::null_type, axis::option::growth_t> a; + BOOST_TEST_EQ(a.size(), 0); + BOOST_TEST_EQ(a.update(5), std::make_pair(0, -1)); + BOOST_TEST_EQ(a.size(), 1); + BOOST_TEST_EQ(a.update(1), std::make_pair(1, -1)); + BOOST_TEST_EQ(a.size(), 2); + BOOST_TEST_EQ(a.update(10), std::make_pair(2, -1)); + BOOST_TEST_EQ(a.size(), 3); + BOOST_TEST_EQ(a.update(10), std::make_pair(2, 0)); + BOOST_TEST_EQ(a.size(), 3); + + BOOST_TEST_EQ(str(a), "category(5, 1, 10, options=growth)"); + } + + // iterators + { + test_axis_iterator(axis::category<>({3, 1, 2}, ""), 0, 3); + test_axis_iterator(axis::category<std::string>({"A", "B"}, ""), 0, 2); + } + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/axis_integer_fail0.cpp b/src/boost/libs/histogram/test/axis_integer_fail0.cpp new file mode 100644 index 00000000..e9eb8614 --- /dev/null +++ b/src/boost/libs/histogram/test/axis_integer_fail0.cpp @@ -0,0 +1,15 @@ +// 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/integer.hpp> + +using namespace boost::histogram; + +int main() { + // circular integer axis cannot be growing + (void)axis::integer<int, boost::use_default, + decltype(axis::option::circular | axis::option::growth)>(1, 2); +} diff --git a/src/boost/libs/histogram/test/axis_integer_fail1.cpp b/src/boost/libs/histogram/test/axis_integer_fail1.cpp new file mode 100644 index 00000000..2a1efad5 --- /dev/null +++ b/src/boost/libs/histogram/test/axis_integer_fail1.cpp @@ -0,0 +1,15 @@ +// 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/integer.hpp> + +using namespace boost::histogram; + +int main() { + // circular integer axis cannot have entries in underflow or overflow bins + (void)axis::integer<int, boost::use_default, + decltype(axis::option::circular | axis::option::underflow)>(1, 2); +} diff --git a/src/boost/libs/histogram/test/axis_integer_fail2.cpp b/src/boost/libs/histogram/test/axis_integer_fail2.cpp new file mode 100644 index 00000000..fcafc4d4 --- /dev/null +++ b/src/boost/libs/histogram/test/axis_integer_fail2.cpp @@ -0,0 +1,15 @@ +// 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/integer.hpp> + +using namespace boost::histogram; + +int main() { + // circular integer axis cannot have entries in underflow or overflow bins + (void)axis::integer<int, boost::use_default, + decltype(axis::option::circular | axis::option::overflow)>(1, 2); +} diff --git a/src/boost/libs/histogram/test/axis_integer_fail3.cpp b/src/boost/libs/histogram/test/axis_integer_fail3.cpp new file mode 100644 index 00000000..89717794 --- /dev/null +++ b/src/boost/libs/histogram/test/axis_integer_fail3.cpp @@ -0,0 +1,15 @@ +// 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/integer.hpp> + +using namespace boost::histogram; + +int main() { + // growing integer axis cannot have entries in underflow or overflow bins + (void)axis::integer<int, boost::use_default, + decltype(axis::option::growth | axis::option::underflow)>(1, 2); +} diff --git a/src/boost/libs/histogram/test/axis_integer_fail4.cpp b/src/boost/libs/histogram/test/axis_integer_fail4.cpp new file mode 100644 index 00000000..7b25eb30 --- /dev/null +++ b/src/boost/libs/histogram/test/axis_integer_fail4.cpp @@ -0,0 +1,15 @@ +// 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/integer.hpp> + +using namespace boost::histogram; + +int main() { + // growing integer axis cannot have entries in underflow or overflow bins + (void)axis::integer<int, boost::use_default, + decltype(axis::option::growth | axis::option::overflow)>(1, 2); +} diff --git a/src/boost/libs/histogram/test/axis_integer_test.cpp b/src/boost/libs/histogram/test/axis_integer_test.cpp new file mode 100644 index 00000000..9ea2b5b8 --- /dev/null +++ b/src/boost/libs/histogram/test/axis_integer_test.cpp @@ -0,0 +1,193 @@ +// Copyright 2015-2018 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/core/lightweight_test.hpp> +#include <boost/histogram/axis/integer.hpp> +#include <boost/histogram/axis/ostream.hpp> +#include <limits> +#include <sstream> +#include <type_traits> +#include "std_ostream.hpp" +#include "throw_exception.hpp" +#include "utility_axis.hpp" +#include "utility_str.hpp" + +int main() { + using namespace boost::histogram; + + BOOST_TEST(std::is_nothrow_move_assignable<axis::integer<>>::value); + BOOST_TEST(std::is_nothrow_move_constructible<axis::integer<>>::value); + + // bad_ctor + { BOOST_TEST_THROWS(axis::integer<>(1, -1), std::invalid_argument); } + + // axis::integer with double type + { + axis::integer<double> a{-1, 2, "foo"}; + BOOST_TEST_EQ(a.metadata(), "foo"); + BOOST_TEST_EQ(static_cast<const axis::integer<double>&>(a).metadata(), "foo"); + a.metadata() = "bar"; + BOOST_TEST_EQ(static_cast<const axis::integer<double>&>(a).metadata(), "bar"); + BOOST_TEST_EQ(a.bin(-1).lower(), -std::numeric_limits<double>::infinity()); + BOOST_TEST_EQ(a.bin(a.size()).upper(), std::numeric_limits<double>::infinity()); + BOOST_TEST_EQ(a.index(-10), -1); + BOOST_TEST_EQ(a.index(-2), -1); + BOOST_TEST_EQ(a.index(-1), 0); + BOOST_TEST_EQ(a.index(0), 1); + BOOST_TEST_EQ(a.index(1), 2); + BOOST_TEST_EQ(a.index(2), 3); + BOOST_TEST_EQ(a.index(10), 3); + BOOST_TEST_EQ(a.index(std::numeric_limits<double>::quiet_NaN()), 3); + + BOOST_TEST_EQ(str(a), + "integer(-1, 2, metadata=\"bar\", options=underflow | overflow)"); + + axis::integer<double> b; + BOOST_TEST_NE(a, b); + b = a; + BOOST_TEST_EQ(a, b); + axis::integer<double> c = std::move(b); + BOOST_TEST_EQ(c, a); + axis::integer<double> d; + BOOST_TEST_NE(c, d); + d = std::move(c); + BOOST_TEST_EQ(d, a); + } + + // empty axis::integer + { + axis::integer<> a; + BOOST_TEST_EQ(a.size(), 0); + BOOST_TEST_EQ(a.bin(1), 1); + BOOST_TEST_EQ(a.bin(0), 0); + BOOST_TEST_EQ(a.bin(-1), -1); + BOOST_TEST_EQ(a.index(-10), -1); + BOOST_TEST_EQ(a.index(-1), -1); + BOOST_TEST_EQ(a.index(0), 0); + BOOST_TEST_EQ(a.index(10), 0); + + BOOST_TEST_EQ(str(a), "integer(0, 0, options=underflow | overflow)"); + + axis::integer<> b{1, 1}; + BOOST_TEST_EQ(b.size(), 0); + BOOST_TEST_EQ(b.bin(1), 2); + BOOST_TEST_EQ(b.bin(0), 1); + BOOST_TEST_EQ(b.bin(-1), 0); + BOOST_TEST_EQ(b.index(-10), -1); + BOOST_TEST_EQ(b.index(-1), -1); + BOOST_TEST_EQ(b.index(0), -1); + BOOST_TEST_EQ(b.index(1), 0); + BOOST_TEST_EQ(b.index(10), 0); + + BOOST_TEST_EQ(str(b), "integer(1, 1, options=underflow | overflow)"); + } + + // axis::integer with int type + { + axis::integer<int> a{-1, 2}; + BOOST_TEST_EQ(a.bin(-2), -3); + BOOST_TEST_EQ(a.bin(4), 3); + BOOST_TEST_EQ(a.index(-10), -1); + BOOST_TEST_EQ(a.index(-2), -1); + BOOST_TEST_EQ(a.index(-1), 0); + BOOST_TEST_EQ(a.index(0), 1); + BOOST_TEST_EQ(a.index(1), 2); + BOOST_TEST_EQ(a.index(2), 3); + BOOST_TEST_EQ(a.index(10), 3); + + BOOST_TEST_EQ(str(a), "integer(-1, 2, options=underflow | overflow)"); + } + + // axis::integer int,circular + { + axis::integer<int, axis::null_type, axis::option::circular_t> a(-1, 1); + BOOST_TEST_EQ(a.value(-1), -2); + BOOST_TEST_EQ(a.value(0), -1); + BOOST_TEST_EQ(a.value(1), 0); + BOOST_TEST_EQ(a.value(2), 1); + BOOST_TEST_EQ(a.value(3), 2); + BOOST_TEST_EQ(a.index(-2), 1); + BOOST_TEST_EQ(a.index(-1), 0); + BOOST_TEST_EQ(a.index(0), 1); + BOOST_TEST_EQ(a.index(1), 0); + BOOST_TEST_EQ(a.index(2), 1); + + BOOST_TEST_EQ(str(a), "integer(-1, 1, options=circular)"); + } + + // axis::integer double,circular + { + axis::integer<double, axis::null_type, axis::option::circular_t> a(-1, 1); + BOOST_TEST_EQ(a.value(-1), -2); + BOOST_TEST_EQ(a.value(0), -1); + BOOST_TEST_EQ(a.value(1), 0); + BOOST_TEST_EQ(a.value(2), 1); + BOOST_TEST_EQ(a.value(3), 2); + BOOST_TEST_EQ(a.index(-2), 1); + BOOST_TEST_EQ(a.index(-1), 0); + BOOST_TEST_EQ(a.index(0), 1); + BOOST_TEST_EQ(a.index(1), 0); + BOOST_TEST_EQ(a.index(2), 1); + BOOST_TEST_EQ(a.index(std::numeric_limits<double>::quiet_NaN()), 2); + } + + // axis::integer with growth + { + axis::integer<double, axis::null_type, axis::option::growth_t> a; + BOOST_TEST_EQ(a.size(), 0); + BOOST_TEST_EQ(a.update(0), std::make_pair(0, -1)); + BOOST_TEST_EQ(a.size(), 1); + BOOST_TEST_EQ(a.update(1), std::make_pair(1, -1)); + BOOST_TEST_EQ(a.size(), 2); + BOOST_TEST_EQ(a.update(-1), std::make_pair(0, 1)); + BOOST_TEST_EQ(a.size(), 3); + BOOST_TEST_EQ(a.update(std::numeric_limits<double>::infinity()), + std::make_pair(a.size(), 0)); + BOOST_TEST_EQ(a.update(std::numeric_limits<double>::quiet_NaN()), + std::make_pair(a.size(), 0)); + BOOST_TEST_EQ(a.update(-std::numeric_limits<double>::infinity()), + std::make_pair(-1, 0)); + } + + // iterators + { + test_axis_iterator(axis::integer<int>(0, 4), 0, 4); + test_axis_iterator(axis::integer<double>(0, 4), 0, 4); + test_axis_iterator( + axis::integer<int, axis::null_type, axis::option::circular_t>(0, 4), 0, 4); + } + + // shrink and rebin + { + using A = axis::integer<>; + auto a = A(-1, 5); + auto b = A(a, 2, 5, 1); + BOOST_TEST_EQ(b.size(), 3); + BOOST_TEST_EQ(b.value(0), 1); + BOOST_TEST_EQ(b.value(3), 4); + auto c = A(a, 1, 5, 1); + BOOST_TEST_EQ(c.size(), 4); + BOOST_TEST_EQ(c.value(0), 0); + BOOST_TEST_EQ(c.value(4), 4); + auto e = A(a, 2, 5, 1); + BOOST_TEST_EQ(e.size(), 3); + BOOST_TEST_EQ(e.value(0), 1); + BOOST_TEST_EQ(e.value(3), 4); + } + + // shrink and rebin with circular option + { + using A = axis::integer<int, axis::null_type, axis::option::circular_t>; + auto a = A(1, 5); + auto b = A(a, 0, 4, 1); + BOOST_TEST_EQ(a, b); + BOOST_TEST_THROWS(A(a, 1, 4, 1), std::invalid_argument); + BOOST_TEST_THROWS(A(a, 0, 3, 1), std::invalid_argument); + BOOST_TEST_THROWS(A(a, 0, 4, 2), std::invalid_argument); + } + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/axis_option_test.cpp b/src/boost/libs/histogram/test/axis_option_test.cpp new file mode 100644 index 00000000..4b764748 --- /dev/null +++ b/src/boost/libs/histogram/test/axis_option_test.cpp @@ -0,0 +1,56 @@ +// Copyright 2018 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/core/lightweight_test.hpp> +#include <boost/histogram/axis/option.hpp> +#include <iostream> + +using namespace boost::histogram::axis; + +template <unsigned N, unsigned M> +bool operator==(option::bitset<N>, option::bitset<M>) { + return N == M; +} + +template <unsigned N> +std::ostream& operator<<(std::ostream& os, option::bitset<N>) { + os << "underflow " << static_cast<bool>(N & option::underflow) << " " + << "overflow " << static_cast<bool>(N & option::overflow) << " " + << "circular " << static_cast<bool>(N & option::circular) << " " + << "growth " << static_cast<bool>(N & option::growth); + return os; +} + +int main() { + using namespace option; + using uoflow = decltype(underflow | overflow); + constexpr auto uoflow_growth = uoflow{} | growth; + + BOOST_TEST_EQ(uoflow::value, underflow | overflow); + BOOST_TEST_EQ(underflow | overflow, overflow | underflow); + + BOOST_TEST(underflow.test(underflow)); + BOOST_TEST_NOT(underflow.test(overflow)); + BOOST_TEST_NOT(underflow.test(underflow | overflow)); + BOOST_TEST(uoflow::test(underflow)); + BOOST_TEST(uoflow::test(overflow)); + BOOST_TEST_NOT(uoflow::test(circular)); + BOOST_TEST_NOT(uoflow::test(growth)); + BOOST_TEST(uoflow_growth.test(underflow)); + BOOST_TEST(uoflow_growth.test(overflow)); + BOOST_TEST(uoflow_growth.test(growth)); + BOOST_TEST_NOT(uoflow_growth.test(circular)); + + BOOST_TEST_EQ(uoflow_growth & uoflow_growth, uoflow_growth); + BOOST_TEST_EQ(uoflow_growth & growth, growth); + BOOST_TEST_EQ(uoflow_growth & uoflow{}, uoflow::value); + + BOOST_TEST_EQ(uoflow_growth - growth, uoflow{}); + BOOST_TEST_EQ(uoflow_growth - uoflow{}, growth); + BOOST_TEST_EQ(uoflow_growth - underflow, growth | overflow); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/axis_regular_fail0.cpp b/src/boost/libs/histogram/test/axis_regular_fail0.cpp new file mode 100644 index 00000000..579e13ca --- /dev/null +++ b/src/boost/libs/histogram/test/axis_regular_fail0.cpp @@ -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/axis/regular.hpp> + +using namespace boost::histogram; + +int main() { + // regular axis requires a floating point value type + (void)axis::regular<int>(1, 2, 3); +} diff --git a/src/boost/libs/histogram/test/axis_regular_fail1.cpp b/src/boost/libs/histogram/test/axis_regular_fail1.cpp new file mode 100644 index 00000000..e5263a16 --- /dev/null +++ b/src/boost/libs/histogram/test/axis_regular_fail1.cpp @@ -0,0 +1,15 @@ +// 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> + +using namespace boost::histogram; + +int main() { + // circular regular axis cannot be growing + (void)axis::regular<double, boost::use_default, boost::use_default, + decltype(axis::option::circular | axis::option::growth)>(1, 2, 3); +} diff --git a/src/boost/libs/histogram/test/axis_regular_test.cpp b/src/boost/libs/histogram/test/axis_regular_test.cpp new file mode 100644 index 00000000..5d3e111c --- /dev/null +++ b/src/boost/libs/histogram/test/axis_regular_test.cpp @@ -0,0 +1,281 @@ +// Copyright 2015-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/core/lightweight_test.hpp> +#include <boost/histogram/axis/ostream.hpp> +#include <boost/histogram/axis/regular.hpp> +#include <limits> +#include <sstream> +#include <type_traits> +#include "is_close.hpp" +#include "std_ostream.hpp" +#include "throw_exception.hpp" +#include "utility_axis.hpp" +#include "utility_str.hpp" + +int main() { + using namespace boost::histogram; + using def = use_default; + namespace tr = axis::transform; + + BOOST_TEST(std::is_nothrow_move_assignable<axis::regular<>>::value); + BOOST_TEST(std::is_nothrow_move_constructible<axis::regular<>>::value); + + // bad_ctors + { + BOOST_TEST_THROWS(axis::regular<>(1, 0, 0), std::invalid_argument); + BOOST_TEST_THROWS(axis::regular<>(0, 0, 1), std::invalid_argument); + } + + // ctors and assignment + { + axis::regular<> a{4, -2, 2}; + axis::regular<> b; + BOOST_TEST_NE(a, b); + b = a; + BOOST_TEST_EQ(a, b); + axis::regular<> c = std::move(b); + BOOST_TEST_EQ(c, a); + axis::regular<> d; + BOOST_TEST_NE(c, d); + d = std::move(c); + BOOST_TEST_EQ(d, a); + } + + // input, output + { + axis::regular<> a{4, -2, 2, "foo"}; + BOOST_TEST_EQ(a.metadata(), "foo"); + BOOST_TEST_EQ(static_cast<const axis::regular<>&>(a).metadata(), "foo"); + a.metadata() = "bar"; + BOOST_TEST_EQ(static_cast<const axis::regular<>&>(a).metadata(), "bar"); + BOOST_TEST_EQ(a.value(0), -2); + BOOST_TEST_EQ(a.value(1), -1); + BOOST_TEST_EQ(a.value(2), 0); + BOOST_TEST_EQ(a.value(3), 1); + BOOST_TEST_EQ(a.value(4), 2); + BOOST_TEST_EQ(a.bin(-1).lower(), -std::numeric_limits<double>::infinity()); + BOOST_TEST_EQ(a.bin(-1).upper(), -2); + BOOST_TEST_EQ(a.bin(a.size()).lower(), 2); + BOOST_TEST_EQ(a.bin(a.size()).upper(), std::numeric_limits<double>::infinity()); + BOOST_TEST_EQ(a.index(-10.), -1); + BOOST_TEST_EQ(a.index(-2.1), -1); + BOOST_TEST_EQ(a.index(-2.0), 0); + BOOST_TEST_EQ(a.index(-1.1), 0); + BOOST_TEST_EQ(a.index(0.0), 2); + BOOST_TEST_EQ(a.index(0.9), 2); + BOOST_TEST_EQ(a.index(1.0), 3); + BOOST_TEST_EQ(a.index(10.), 4); + BOOST_TEST_EQ(a.index(-std::numeric_limits<double>::infinity()), -1); + BOOST_TEST_EQ(a.index(std::numeric_limits<double>::infinity()), 4); + BOOST_TEST_EQ(a.index(std::numeric_limits<double>::quiet_NaN()), 4); + + BOOST_TEST_EQ(str(a), + "regular(4, -2, 2, metadata=\"bar\", options=underflow | overflow)"); + } + + // with inverted range + { + axis::regular<> a{2, 1, -2}; + BOOST_TEST_EQ(a.bin(-1).lower(), std::numeric_limits<double>::infinity()); + BOOST_TEST_EQ(a.bin(0).lower(), 1); + BOOST_TEST_EQ(a.bin(1).lower(), -0.5); + BOOST_TEST_EQ(a.bin(2).lower(), -2); + BOOST_TEST_EQ(a.bin(2).upper(), -std::numeric_limits<double>::infinity()); + BOOST_TEST_EQ(a.index(2), -1); + BOOST_TEST_EQ(a.index(1.001), -1); + BOOST_TEST_EQ(a.index(1), 0); + BOOST_TEST_EQ(a.index(0), 0); + BOOST_TEST_EQ(a.index(-0.499), 0); + BOOST_TEST_EQ(a.index(-0.5), 1); + BOOST_TEST_EQ(a.index(-1), 1); + BOOST_TEST_EQ(a.index(-2), 2); + BOOST_TEST_EQ(a.index(-20), 2); + } + + // with log transform + { + auto a = axis::regular<double, tr::log>{2, 1e0, 1e2}; + BOOST_TEST_EQ(a.bin(-1).lower(), 0.0); + BOOST_TEST_IS_CLOSE(a.bin(0).lower(), 1.0, 1e-9); + BOOST_TEST_IS_CLOSE(a.bin(1).lower(), 10.0, 1e-9); + BOOST_TEST_IS_CLOSE(a.bin(2).lower(), 100.0, 1e-9); + BOOST_TEST_EQ(a.bin(2).upper(), std::numeric_limits<double>::infinity()); + + BOOST_TEST_EQ(a.index(-1), 2); // produces NaN in conversion + BOOST_TEST_EQ(a.index(0), -1); + BOOST_TEST_EQ(a.index(1), 0); + BOOST_TEST_EQ(a.index(9), 0); + BOOST_TEST_EQ(a.index(10), 1); + BOOST_TEST_EQ(a.index(90), 1); + BOOST_TEST_EQ(a.index(100), 2); + BOOST_TEST_EQ(a.index(std::numeric_limits<double>::infinity()), 2); + + BOOST_TEST_THROWS((axis::regular<double, tr::log>{2, -1, 0}), std::invalid_argument); + + BOOST_TEST_EQ(str(a), "regular_log(2, 1, 100, options=underflow | overflow)"); + } + + // with sqrt transform + { + axis::regular<double, tr::sqrt> a(2, 0, 4); + // this is weird, but -inf * -inf = inf, thus the lower bound + BOOST_TEST_EQ(a.bin(-1).lower(), std::numeric_limits<double>::infinity()); + BOOST_TEST_IS_CLOSE(a.bin(0).lower(), 0.0, 1e-9); + BOOST_TEST_IS_CLOSE(a.bin(1).lower(), 1.0, 1e-9); + BOOST_TEST_IS_CLOSE(a.bin(2).lower(), 4.0, 1e-9); + BOOST_TEST_EQ(a.bin(2).upper(), std::numeric_limits<double>::infinity()); + + BOOST_TEST_EQ(a.index(-1), 2); // produces NaN in conversion + BOOST_TEST_EQ(a.index(0), 0); + BOOST_TEST_EQ(a.index(0.99), 0); + BOOST_TEST_EQ(a.index(1), 1); + BOOST_TEST_EQ(a.index(3.99), 1); + BOOST_TEST_EQ(a.index(4), 2); + BOOST_TEST_EQ(a.index(100), 2); + BOOST_TEST_EQ(a.index(std::numeric_limits<double>::infinity()), 2); + + BOOST_TEST_EQ(str(a), "regular_sqrt(2, 0, 4, options=underflow | overflow)"); + } + + // with pow transform + { + axis::regular<double, tr::pow> a(tr::pow{0.5}, 2, 0, 4); + // this is weird, but -inf * -inf = inf, thus the lower bound + BOOST_TEST_EQ(a.bin(-1).lower(), std::numeric_limits<double>::infinity()); + BOOST_TEST_IS_CLOSE(a.bin(0).lower(), 0.0, 1e-9); + BOOST_TEST_IS_CLOSE(a.bin(1).lower(), 1.0, 1e-9); + BOOST_TEST_IS_CLOSE(a.bin(2).lower(), 4.0, 1e-9); + BOOST_TEST_EQ(a.bin(2).upper(), std::numeric_limits<double>::infinity()); + + BOOST_TEST_EQ(a.index(-1), 2); // produces NaN in conversion + BOOST_TEST_EQ(a.index(0), 0); + BOOST_TEST_EQ(a.index(0.99), 0); + BOOST_TEST_EQ(a.index(1), 1); + BOOST_TEST_EQ(a.index(3.99), 1); + BOOST_TEST_EQ(a.index(4), 2); + BOOST_TEST_EQ(a.index(100), 2); + BOOST_TEST_EQ(a.index(std::numeric_limits<double>::infinity()), 2); + + BOOST_TEST_EQ(str(a), + "regular_pow(2, 0, 4, options=underflow | overflow, power=0.5)"); + } + + // with step + { + axis::regular<> a(axis::step(0.5), 1, 3); + BOOST_TEST_EQ(a.size(), 4); + BOOST_TEST_EQ(a.bin(-1).lower(), -std::numeric_limits<double>::infinity()); + BOOST_TEST_EQ(a.value(0), 1); + BOOST_TEST_EQ(a.value(1), 1.5); + BOOST_TEST_EQ(a.value(2), 2); + BOOST_TEST_EQ(a.value(3), 2.5); + BOOST_TEST_EQ(a.value(4), 3); + BOOST_TEST_EQ(a.bin(4).upper(), std::numeric_limits<double>::infinity()); + + axis::regular<> b(axis::step(0.5), 1, 3.1); + BOOST_TEST_EQ(a, b); + } + + // with circular option + { + axis::circular<> a{4, 0, 1}; + BOOST_TEST_EQ(a.bin(-1).lower(), a.bin(a.size() - 1).lower() - 1); + BOOST_TEST_EQ(a.index(-1.0 * 3), 0); + BOOST_TEST_EQ(a.index(0.0), 0); + BOOST_TEST_EQ(a.index(0.25), 1); + BOOST_TEST_EQ(a.index(0.5), 2); + BOOST_TEST_EQ(a.index(0.75), 3); + BOOST_TEST_EQ(a.index(1.0), 0); + BOOST_TEST_EQ(a.index(std::numeric_limits<double>::infinity()), 4); + BOOST_TEST_EQ(a.index(-std::numeric_limits<double>::infinity()), 4); + BOOST_TEST_EQ(a.index(std::numeric_limits<double>::quiet_NaN()), 4); + } + + // with growth + { + axis::regular<double, def, def, axis::option::growth_t> a{1, 0, 1}; + BOOST_TEST_EQ(a.size(), 1); + BOOST_TEST_EQ(a.update(0), std::make_pair(0, 0)); + BOOST_TEST_EQ(a.size(), 1); + BOOST_TEST_EQ(a.update(1), std::make_pair(1, -1)); + BOOST_TEST_EQ(a.size(), 2); + BOOST_TEST_EQ(a.value(0), 0); + BOOST_TEST_EQ(a.value(2), 2); + BOOST_TEST_EQ(a.update(-1), std::make_pair(0, 1)); + BOOST_TEST_EQ(a.size(), 3); + BOOST_TEST_EQ(a.value(0), -1); + BOOST_TEST_EQ(a.value(3), 2); + BOOST_TEST_EQ(a.update(-10), std::make_pair(0, 9)); + BOOST_TEST_EQ(a.size(), 12); + BOOST_TEST_EQ(a.value(0), -10); + BOOST_TEST_EQ(a.value(12), 2); + BOOST_TEST_EQ(a.update(std::numeric_limits<double>::infinity()), + std::make_pair(a.size(), 0)); + BOOST_TEST_EQ(a.update(std::numeric_limits<double>::quiet_NaN()), + std::make_pair(a.size(), 0)); + BOOST_TEST_EQ(a.update(-std::numeric_limits<double>::infinity()), + std::make_pair(-1, 0)); + } + + // iterators + { + test_axis_iterator(axis::regular<>(5, 0, 1), 0, 5); + test_axis_iterator(axis::regular<double, def, def, axis::option::none_t>(5, 0, 1), 0, + 5); + test_axis_iterator(axis::circular<>(5, 0, 1), 0, 5); + } + + // bin_type streamable + { + auto test = [](const auto& x, const char* ref) { + std::ostringstream os; + os << x; + BOOST_TEST_EQ(os.str(), std::string(ref)); + }; + + auto a = axis::regular<>(2, 0, 1); + test(a.bin(0), "[0, 0.5)"); + } + + // null_type streamable + { + auto a = axis::regular<float, def, axis::null_type>(2, 0, 1); + BOOST_TEST_EQ(str(a), "regular(2, 0, 1, options=underflow | overflow)"); + } + + // shrink and rebin + { + using A = axis::regular<>; + auto a = A(5, 0, 5); + auto b = A(a, 1, 4, 1); + BOOST_TEST_EQ(b.size(), 3); + BOOST_TEST_EQ(b.value(0), 1); + BOOST_TEST_EQ(b.value(3), 4); + auto c = A(a, 0, 4, 2); + BOOST_TEST_EQ(c.size(), 2); + BOOST_TEST_EQ(c.value(0), 0); + BOOST_TEST_EQ(c.value(2), 4); + auto e = A(a, 1, 5, 2); + BOOST_TEST_EQ(e.size(), 2); + BOOST_TEST_EQ(e.value(0), 1); + BOOST_TEST_EQ(e.value(2), 5); + } + + // shrink and rebin with circular option + { + using A = axis::circular<>; + auto a = A(4, 1, 5); + BOOST_TEST_THROWS(A(a, 1, 4, 1), std::invalid_argument); + BOOST_TEST_THROWS(A(a, 0, 3, 1), std::invalid_argument); + auto b = A(a, 0, 4, 2); + BOOST_TEST_EQ(b.size(), 2); + BOOST_TEST_EQ(b.value(0), 1); + BOOST_TEST_EQ(b.value(2), 5); + } + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/axis_size.cpp b/src/boost/libs/histogram/test/axis_size.cpp new file mode 100644 index 00000000..54f55131 --- /dev/null +++ b/src/boost/libs/histogram/test/axis_size.cpp @@ -0,0 +1,34 @@ +// Copyright 2018 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.hpp> +#include <iostream> + +#define SHOW_SIZE(x) std::cout << #x << " " << sizeof(x) << std::endl + +int main() { + using namespace boost::histogram; + + using regular = axis::regular<>; + using regular_float = axis::regular<float>; + using regular_pow = axis::regular<double, axis::transform::pow>; + using regular_no_metadata = axis::regular<double, axis::transform::id, axis::null_type>; + using circular = axis::circular<>; + using variable = axis::variable<>; + using integer = axis::integer<>; + using category = axis::category<>; + using variant = axis::variant<regular, circular, variable, integer, category>; + + SHOW_SIZE(regular); + SHOW_SIZE(regular_float); + SHOW_SIZE(regular_pow); + SHOW_SIZE(regular_no_metadata); + SHOW_SIZE(circular); + SHOW_SIZE(variable); + SHOW_SIZE(integer); + SHOW_SIZE(category); + SHOW_SIZE(variant); +} diff --git a/src/boost/libs/histogram/test/axis_traits_test.cpp b/src/boost/libs/histogram/test/axis_traits_test.cpp new file mode 100644 index 00000000..ca0b14c1 --- /dev/null +++ b/src/boost/libs/histogram/test/axis_traits_test.cpp @@ -0,0 +1,214 @@ +// Copyright 2018 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/core/lightweight_test.hpp> +#include <boost/core/lightweight_test_trait.hpp> +#include <boost/histogram/axis.hpp> +#include <boost/histogram/axis/traits.hpp> +#include "std_ostream.hpp" +#include "throw_exception.hpp" +#include "utility_axis.hpp" + +using namespace boost::histogram::axis; + +int main() { + // value_type + { + BOOST_TEST_TRAIT_SAME(traits::value_type<integer<int>>, int); + BOOST_TEST_TRAIT_SAME(traits::value_type<category<int>>, int); + BOOST_TEST_TRAIT_SAME(traits::value_type<regular<double>>, double); + } + + // is_continuous + { + BOOST_TEST_TRAIT_TRUE((traits::is_continuous<regular<>>)); + BOOST_TEST_TRAIT_FALSE((traits::is_continuous<integer<int>>)); + BOOST_TEST_TRAIT_FALSE((traits::is_continuous<category<int>>)); + BOOST_TEST_TRAIT_TRUE((traits::is_continuous<integer<double>>)); + } + + // is_reducible + { + struct not_reducible {}; + struct reducible { + reducible(const reducible&, index_type, index_type, unsigned); + }; + + BOOST_TEST_TRAIT_TRUE((traits::is_reducible<reducible>)); + BOOST_TEST_TRAIT_FALSE((traits::is_reducible<not_reducible>)); + + BOOST_TEST_TRAIT_TRUE((traits::is_reducible<regular<>>)); + BOOST_TEST_TRAIT_TRUE((traits::is_reducible<variable<>>)); + BOOST_TEST_TRAIT_TRUE((traits::is_reducible<circular<>>)); + BOOST_TEST_TRAIT_TRUE((traits::is_reducible<integer<>>)); + BOOST_TEST_TRAIT_FALSE((traits::is_reducible<category<>>)); + } + + // static_is_inclusive + { + struct empty {}; + struct with_opts_not_inclusive { + static constexpr unsigned options() { return option::underflow | option::overflow; } + static constexpr bool inclusive() { return false; } + }; + + BOOST_TEST_TRAIT_FALSE((traits::static_is_inclusive<empty>)); + BOOST_TEST_TRAIT_FALSE((traits::static_is_inclusive<with_opts_not_inclusive>)); + + BOOST_TEST_TRAIT_TRUE((traits::static_is_inclusive<regular<>>)); + BOOST_TEST_TRAIT_FALSE( + (traits::static_is_inclusive< + regular<double, boost::use_default, boost::use_default, option::growth_t>>)); + BOOST_TEST_TRAIT_FALSE( + (traits::static_is_inclusive<regular<double, boost::use_default, + boost::use_default, option::circular_t>>)); + + BOOST_TEST_TRAIT_TRUE((traits::static_is_inclusive<variable<>>)); + BOOST_TEST_TRAIT_FALSE((traits::static_is_inclusive< + variable<double, boost::use_default, option::growth_t>>)); + BOOST_TEST_TRAIT_FALSE((traits::static_is_inclusive< + variable<double, boost::use_default, option::circular_t>>)); + + BOOST_TEST_TRAIT_TRUE((traits::static_is_inclusive<integer<int>>)); + BOOST_TEST_TRAIT_TRUE(( + traits::static_is_inclusive<integer<int, boost::use_default, option::growth_t>>)); + BOOST_TEST_TRAIT_TRUE((traits::static_is_inclusive< + integer<int, boost::use_default, option::circular_t>>)); + + BOOST_TEST_TRAIT_TRUE((traits::static_is_inclusive<integer<double>>)); + BOOST_TEST_TRAIT_FALSE((traits::static_is_inclusive< + integer<double, boost::use_default, option::growth_t>>)); + BOOST_TEST_TRAIT_FALSE((traits::static_is_inclusive< + integer<double, boost::use_default, option::circular_t>>)); + + BOOST_TEST_TRAIT_TRUE((traits::static_is_inclusive<category<int>>)); + BOOST_TEST_TRAIT_TRUE((traits::static_is_inclusive< + category<int, boost::use_default, option::growth_t>>)); + BOOST_TEST_TRAIT_FALSE( + (traits::static_is_inclusive<category<int, boost::use_default, option::none_t>>)); + } + + // index, rank, value, width + { + auto a = integer<>(1, 3); + BOOST_TEST_EQ(traits::index(a, 1), 0); + BOOST_TEST_EQ(traits::rank(a), 1); + BOOST_TEST_EQ(traits::value(a, 0), 1); + BOOST_TEST_EQ(traits::width(a, 0), 0); + BOOST_TEST_EQ(traits::width(a, 0), 0); + + auto b = integer<double>(1, 3); + BOOST_TEST_EQ(traits::index(b, 1), 0); + BOOST_TEST_EQ(traits::rank(b), 1); + BOOST_TEST_EQ(traits::value(b, 0), 1); + BOOST_TEST_EQ(traits::width(b, 0), 1); + BOOST_TEST(traits::static_options<decltype(b)>::test(option::underflow)); + + auto c = category<std::string>{"red", "blue"}; + BOOST_TEST_EQ(traits::index(c, "blue"), 1); + BOOST_TEST_EQ(traits::rank(c), 1); + BOOST_TEST_EQ(traits::value(c, 0), std::string("red")); + BOOST_TEST_EQ(traits::width(c, 0), 0); + + struct D { + index_type index(const std::tuple<int, double>& args) const { + return static_cast<index_type>(std::get<0>(args) + std::get<1>(args)); + } + index_type size() const { return 5u; } + } d; + BOOST_TEST_EQ(traits::index(d, std::make_tuple(1, 2.0)), 3.0); + BOOST_TEST_EQ(traits::rank(d), 2u); + + variant<D, integer<>> v; + v = a; + BOOST_TEST_EQ(traits::rank(v), 1u); + v = d; + BOOST_TEST_EQ(traits::rank(v), 2u); + } + + // static_options, options() + { + using A = integer<>; + BOOST_TEST_EQ(traits::static_options<A>::test(option::growth), false); + auto expected = option::underflow | option::overflow; + auto a = A{}; + BOOST_TEST_EQ(traits::options(a), expected); + BOOST_TEST_EQ(traits::options(static_cast<A&>(a)), expected); + BOOST_TEST_EQ(traits::options(static_cast<const A&>(a)), expected); + BOOST_TEST_EQ(traits::options(std::move(a)), expected); + + using B = integer<int, null_type, option::growth_t>; + BOOST_TEST_EQ(traits::static_options<B>::test(option::growth), true); + BOOST_TEST_EQ(traits::options(B{}), option::growth); + + struct growing { + auto update(double) { return std::make_pair(0, 0); } + }; + using C = growing; + BOOST_TEST_EQ(traits::static_options<C>::test(option::growth), true); + auto c = C{}; + BOOST_TEST_EQ(traits::options(c), option::growth); + BOOST_TEST_EQ(traits::options(static_cast<C&>(c)), option::growth); + BOOST_TEST_EQ(traits::options(static_cast<const C&>(c)), option::growth); + BOOST_TEST_EQ(traits::options(std::move(c)), option::growth); + + struct notgrowing { + auto index(double) { return 0; } + }; + using D = notgrowing; + BOOST_TEST_EQ(traits::static_options<D>::test(option::growth), false); + auto d = D{}; + BOOST_TEST_EQ(traits::options(d), option::none); + BOOST_TEST_EQ(traits::options(static_cast<D&>(d)), option::none); + BOOST_TEST_EQ(traits::options(static_cast<const D&>(d)), option::none); + BOOST_TEST_EQ(traits::options(std::move(d)), option::none); + } + + // update + { + auto a = integer<int, null_type, option::growth_t>(); + BOOST_TEST_EQ(traits::update(a, 0), (std::pair<index_type, index_type>(0, -1))); + BOOST_TEST_THROWS(traits::update(a, "foo"), std::invalid_argument); + + variant<integer<int, null_type, option::growth_t>, integer<>> v(a); + BOOST_TEST_EQ(traits::update(v, 0), (std::pair<index_type, index_type>(0, 0))); + } + + // metadata + { + struct None {}; + + struct Const { + const int& metadata() const { return m; }; + int m = 0; + }; + + struct Both { + const int& metadata() const { return m; }; + int& metadata() { return m; }; + int m = 0; + }; + + None none; + BOOST_TEST_TRAIT_SAME(decltype(traits::metadata(none)), null_type&); + BOOST_TEST_TRAIT_SAME(decltype(traits::metadata(static_cast<None&>(none))), + null_type&); + BOOST_TEST_TRAIT_SAME(decltype(traits::metadata(static_cast<const None&>(none))), + const null_type&); + + Const c; + BOOST_TEST_EQ(traits::metadata(c), 0); + BOOST_TEST_EQ(traits::metadata(static_cast<Const&>(c)), 0); + BOOST_TEST_EQ(traits::metadata(static_cast<const Const&>(c)), 0); + + Both b; + BOOST_TEST_EQ(traits::metadata(b), 0); + BOOST_TEST_EQ(traits::metadata(static_cast<Both&>(b)), 0); + BOOST_TEST_EQ(traits::metadata(static_cast<const Both&>(b)), 0); + } + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/axis_variable_fail0.cpp b/src/boost/libs/histogram/test/axis_variable_fail0.cpp new file mode 100644 index 00000000..b98930cb --- /dev/null +++ b/src/boost/libs/histogram/test/axis_variable_fail0.cpp @@ -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/axis/variable.hpp> + +using namespace boost::histogram; + +int main() { + // variable axis requires a floating point value type + (void)axis::variable<int>({1, 2, 3}); +} diff --git a/src/boost/libs/histogram/test/axis_variable_fail1.cpp b/src/boost/libs/histogram/test/axis_variable_fail1.cpp new file mode 100644 index 00000000..2a9ea02f --- /dev/null +++ b/src/boost/libs/histogram/test/axis_variable_fail1.cpp @@ -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/variable.hpp> + +using namespace boost::histogram; + +int main() { + // circular variable axis cannot be growing + (void)axis::variable<double, boost::use_default, + decltype(axis::option::circular | axis::option::growth)>( + {1, 2, 3}); +} diff --git a/src/boost/libs/histogram/test/axis_variable_test.cpp b/src/boost/libs/histogram/test/axis_variable_test.cpp new file mode 100644 index 00000000..cb27a093 --- /dev/null +++ b/src/boost/libs/histogram/test/axis_variable_test.cpp @@ -0,0 +1,162 @@ +// Copyright 2015-2017 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/core/lightweight_test.hpp> +#include <boost/histogram/axis/ostream.hpp> +#include <boost/histogram/axis/variable.hpp> +#include <limits> +#include <sstream> +#include <type_traits> +#include <vector> +#include "is_close.hpp" +#include "std_ostream.hpp" +#include "throw_exception.hpp" +#include "utility_axis.hpp" +#include "utility_str.hpp" + +using namespace boost::histogram; + +int main() { + BOOST_TEST(std::is_nothrow_move_assignable<axis::variable<>>::value); + BOOST_TEST(std::is_nothrow_move_constructible<axis::variable<>>::value); + + // bad_ctors + { + BOOST_TEST_THROWS(axis::variable<>(std::vector<double>{}), std::invalid_argument); + BOOST_TEST_THROWS(axis::variable<>({1.0}), std::invalid_argument); + BOOST_TEST_THROWS(axis::variable<>({1.0, 1.0}), std::invalid_argument); + BOOST_TEST_THROWS(axis::variable<>({1.0, -1.0}), std::invalid_argument); + } + + // axis::variable + { + axis::variable<> a{{-1, 0, 1}, "foo"}; + BOOST_TEST_EQ(a.size(), 2); + BOOST_TEST_EQ(a.metadata(), "foo"); + BOOST_TEST_EQ(static_cast<const axis::variable<>&>(a).metadata(), "foo"); + a.metadata() = "bar"; + BOOST_TEST_EQ(static_cast<const axis::variable<>&>(a).metadata(), "bar"); + BOOST_TEST_EQ(a.bin(-1).lower(), -std::numeric_limits<double>::infinity()); + BOOST_TEST_EQ(a.bin(a.size()).upper(), std::numeric_limits<double>::infinity()); + BOOST_TEST_EQ(a.value(0), -1); + BOOST_TEST_EQ(a.value(0.5), -0.5); + BOOST_TEST_EQ(a.value(1), 0); + BOOST_TEST_EQ(a.value(1.5), 0.5); + BOOST_TEST_EQ(a.value(2), 1); + BOOST_TEST_EQ(a.index(-10), -1); + BOOST_TEST_EQ(a.index(-1), 0); + BOOST_TEST_EQ(a.index(0), 1); + BOOST_TEST_EQ(a.index(1), 2); + BOOST_TEST_EQ(a.index(10), 2); + BOOST_TEST_EQ(a.index(-std::numeric_limits<double>::infinity()), -1); + BOOST_TEST_EQ(a.index(std::numeric_limits<double>::infinity()), 2); + BOOST_TEST_EQ(a.index(std::numeric_limits<double>::quiet_NaN()), 2); + + BOOST_TEST_EQ(str(a), + "variable(-1, 0, 1, metadata=\"bar\", options=underflow | overflow)"); + + axis::variable<> b; + BOOST_TEST_NE(a, b); + b = a; + BOOST_TEST_EQ(a, b); + axis::variable<> c = std::move(b); + BOOST_TEST_EQ(c, a); + axis::variable<> d; + BOOST_TEST_NE(c, d); + d = std::move(c); + BOOST_TEST_EQ(d, a); + axis::variable<> e{-2, 0, 2}; + BOOST_TEST_NE(a, e); + } + + // axis::variable circular + { + axis::variable<double, axis::null_type, axis::option::circular_t> a{-1, 1, 2}; + BOOST_TEST_EQ(a.value(-2), -4); + BOOST_TEST_EQ(a.value(-1), -2); + BOOST_TEST_EQ(a.value(0), -1); + BOOST_TEST_EQ(a.value(1), 1); + BOOST_TEST_EQ(a.value(2), 2); + BOOST_TEST_EQ(a.value(3), 4); + BOOST_TEST_EQ(a.value(4), 5); + BOOST_TEST_EQ(a.index(-3), 0); // -3 + 3 = 0 + BOOST_TEST_EQ(a.index(-2), 1); // -2 + 3 = 1 + BOOST_TEST_EQ(a.index(-1), 0); + BOOST_TEST_EQ(a.index(0), 0); + BOOST_TEST_EQ(a.index(1), 1); + BOOST_TEST_EQ(a.index(2), 0); + BOOST_TEST_EQ(a.index(3), 0); // 3 - 3 = 0 + BOOST_TEST_EQ(a.index(4), 1); // 4 - 3 = 1 + } + + // axis::regular with growth + { + axis::variable<double, axis::null_type, axis::option::growth_t> a{0, 1}; + BOOST_TEST_EQ(a.size(), 1); + BOOST_TEST_EQ(a.update(0), std::make_pair(0, 0)); + BOOST_TEST_EQ(a.size(), 1); + BOOST_TEST_EQ(a.update(1.1), std::make_pair(1, -1)); + BOOST_TEST_EQ(a.size(), 2); + BOOST_TEST_EQ(a.value(0), 0); + BOOST_TEST_EQ(a.value(1), 1); + BOOST_TEST_EQ(a.value(2), 1.5); + BOOST_TEST_EQ(a.update(-0.1), std::make_pair(0, 1)); + BOOST_TEST_EQ(a.value(0), -0.5); + BOOST_TEST_EQ(a.size(), 3); + BOOST_TEST_EQ(a.update(10), std::make_pair(3, -1)); + BOOST_TEST_EQ(a.size(), 4); + BOOST_TEST_IS_CLOSE(a.value(4), 10, 1e-9); + BOOST_TEST_EQ(a.update(-10), std::make_pair(0, 1)); + BOOST_TEST_EQ(a.size(), 5); + BOOST_TEST_IS_CLOSE(a.value(0), -10, 1e-9); + + BOOST_TEST_EQ(a.update(-std::numeric_limits<double>::infinity()), + std::make_pair(-1, 0)); + BOOST_TEST_EQ(a.update(std::numeric_limits<double>::infinity()), + std::make_pair(a.size(), 0)); + BOOST_TEST_EQ(a.update(std::numeric_limits<double>::quiet_NaN()), + std::make_pair(a.size(), 0)); + } + + // iterators + { + test_axis_iterator(axis::variable<>{1, 2, 3}, 0, 2); + test_axis_iterator( + axis::variable<double, axis::null_type, axis::option::circular_t>{1, 2, 3}, 0, 2); + } + + // shrink and rebin + { + using A = axis::variable<>; + auto a = A({0, 1, 2, 3, 4, 5}); + auto b = A(a, 1, 4, 1); + BOOST_TEST_EQ(b.size(), 3); + BOOST_TEST_EQ(b.value(0), 1); + BOOST_TEST_EQ(b.value(3), 4); + auto c = A(a, 0, 4, 2); + BOOST_TEST_EQ(c.size(), 2); + BOOST_TEST_EQ(c.value(0), 0); + BOOST_TEST_EQ(c.value(2), 4); + auto e = A(a, 1, 5, 2); + BOOST_TEST_EQ(e.size(), 2); + BOOST_TEST_EQ(e.value(0), 1); + BOOST_TEST_EQ(e.value(2), 5); + } + + // shrink and rebin with circular option + { + using A = axis::variable<double, axis::null_type, axis::option::circular_t>; + auto a = A({1, 2, 3, 4, 5}); + BOOST_TEST_THROWS(A(a, 1, 4, 1), std::invalid_argument); + BOOST_TEST_THROWS(A(a, 0, 3, 1), std::invalid_argument); + auto b = A(a, 0, 4, 2); + BOOST_TEST_EQ(b.size(), 2); + BOOST_TEST_EQ(b.value(0), 1); + BOOST_TEST_EQ(b.value(2), 5); + } + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/axis_variant_serialization_test.cpp b/src/boost/libs/histogram/test/axis_variant_serialization_test.cpp new file mode 100644 index 00000000..8514ddb3 --- /dev/null +++ b/src/boost/libs/histogram/test/axis_variant_serialization_test.cpp @@ -0,0 +1,41 @@ +// Copyright (c) 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) + +// This test is inspired by the corresponding boost/beast test of detail_variant. + +#include <boost/assert.hpp> +#include <boost/core/lightweight_test.hpp> +#include <boost/histogram/axis/integer.hpp> +#include <boost/histogram/axis/ostream.hpp> +#include <boost/histogram/axis/regular.hpp> +#include <boost/histogram/axis/variant.hpp> +#include <boost/histogram/serialization.hpp> +#include "throw_exception.hpp" +#include "utility_axis.hpp" +#include "utility_serialization.hpp" + +using namespace boost::histogram::axis; + +int main(int argc, char** argv) { + BOOST_ASSERT(argc == 2); + + const auto filename = join(argv[1], "axis_variant_serialization_test.xml"); + + using R = regular<>; + using I = integer<>; + + variant<I, R> a(I(0, 3)); + variant<I, R> b(R(1, 0, 1)); + print_xml(filename, b); + BOOST_TEST_NE(a, b); + load_xml(filename, a); + BOOST_TEST_EQ(a, b); + + variant<I> c; // load incompatible version + BOOST_TEST_THROWS(load_xml(filename, c), std::runtime_error); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/axis_variant_serialization_test.xml b/src/boost/libs/histogram/test/axis_variant_serialization_test.xml new file mode 100644 index 00000000..9504c511 --- /dev/null +++ b/src/boost/libs/histogram/test/axis_variant_serialization_test.xml @@ -0,0 +1,24 @@ +<!-- + Copyright 2018-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) +--> + +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<!DOCTYPE boost_serialization> +<boost_serialization signature="serialization::archive" version="17"> +<item class_id="0" tracking_level="0" version="0"> + <variant class_id="1" tracking_level="0" version="0"> + <which>1</which> + <value class_id="2" tracking_level="0" version="0"> + <transform class_id="3" tracking_level="0" version="0"></transform> + <size>1</size> + <meta></meta> + <min>0.00000000000000000e+00</min> + <delta>1.00000000000000000e+00</delta> + </value> + </variant> +</item> +</boost_serialization> diff --git a/src/boost/libs/histogram/test/axis_variant_test.cpp b/src/boost/libs/histogram/test/axis_variant_test.cpp new file mode 100644 index 00000000..016b592d --- /dev/null +++ b/src/boost/libs/histogram/test/axis_variant_test.cpp @@ -0,0 +1,250 @@ +// Copyright 2015-2018 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/core/lightweight_test.hpp> +#include <boost/core/lightweight_test_trait.hpp> +#include <boost/histogram/axis/category.hpp> +#include <boost/histogram/axis/integer.hpp> +#include <boost/histogram/axis/ostream.hpp> +#include <boost/histogram/axis/regular.hpp> +#include <boost/histogram/axis/variant.hpp> +#include <boost/histogram/detail/type_name.hpp> +#include <string> +#include <type_traits> +#include <vector> +#include "throw_exception.hpp" +#include "utility_allocator.hpp" +#include "utility_axis.hpp" +#include "utility_str.hpp" + +int main() { + using namespace boost::histogram; + namespace tr = axis::transform; + + { + (void)axis::variant<>{}; + } + + { + using meta_type = std::vector<int>; + using variant_type = + axis::variant<axis::integer<double>, axis::category<std::string, meta_type>>; + auto a = variant_type{axis::integer<double>(0, 2, "foo")}; + BOOST_TEST_EQ(a.index(-10), -1); + BOOST_TEST_EQ(a.index(-1), -1); + BOOST_TEST_EQ(a.index(0), 0); + BOOST_TEST_EQ(a.index(0.5), 0); + BOOST_TEST_EQ(a.index(1), 1); + BOOST_TEST_EQ(a.index(2), 2); + BOOST_TEST_EQ(a.index(10), 2); + BOOST_TEST_EQ(a.bin(-1).lower(), -std::numeric_limits<double>::infinity()); + BOOST_TEST_EQ(a.bin(a.size()).upper(), std::numeric_limits<double>::infinity()); + BOOST_TEST_EQ(a.bin(-10).lower(), -std::numeric_limits<double>::infinity()); + BOOST_TEST_EQ(a.bin(a.size() + 10).upper(), std::numeric_limits<double>::infinity()); + BOOST_TEST_EQ(a.metadata(), "foo"); + a.metadata() = "bar"; + BOOST_TEST_EQ(static_cast<const variant_type&>(a).metadata(), "bar"); + BOOST_TEST_EQ(a.options(), axis::option::underflow | axis::option::overflow); + + a = axis::category<std::string, meta_type>({"A", "B"}, {1, 2, 3}); + BOOST_TEST_EQ(a.index("A"), 0); + BOOST_TEST_EQ(a.index("B"), 1); + BOOST_TEST_THROWS(a.metadata(), std::runtime_error); + BOOST_TEST_THROWS(static_cast<const variant_type&>(a).metadata(), std::runtime_error); + BOOST_TEST_EQ(a.options(), axis::option::overflow_t::value); + } + + // axis::variant with pointers + { + using A = axis::integer<>; + using B = axis::regular<>; + auto a = A(1, 5, "foo"); + auto b = B(3, 1, 5, "bar"); + axis::variant<A*, B*> r1(&a); + BOOST_TEST_EQ(r1, a); + BOOST_TEST_NE(r1, A(2, 4)); + BOOST_TEST_NE(r1, b); + BOOST_TEST_EQ(r1.size(), 4); + BOOST_TEST_EQ(r1.value(0), 1); + BOOST_TEST_EQ(r1.metadata(), a.metadata()); + BOOST_TEST_EQ(r1.options(), a.options()); + // change original through r1 + axis::get<A>(r1).metadata() = "bar"; + BOOST_TEST_EQ(a.metadata(), "bar"); + r1 = &b; + BOOST_TEST_EQ(r1, b); + + axis::variant<const A*, const B*> r2(static_cast<const B*>(&b)); + BOOST_TEST_EQ(r2, b); + BOOST_TEST_NE(r2, B(4, 1, 5)); + BOOST_TEST_NE(r2, a); + BOOST_TEST_EQ(r2.size(), 3); + BOOST_TEST_EQ(r2.value(0), 1); + BOOST_TEST_EQ(r2.metadata(), "bar"); + b.metadata() = "baz"; + BOOST_TEST_EQ(r2.metadata(), "baz"); + } + + // axis::variant copyable + { + axis::variant<axis::regular<>> a1(axis::regular<>(2, -1, 1)); + axis::variant<axis::regular<>> a2(a1); + BOOST_TEST_EQ(a1, a2); + axis::variant<axis::regular<>> a3; + BOOST_TEST_NE(a3, a1); + a3 = a1; + BOOST_TEST_EQ(a3, a1); + axis::variant<axis::regular<>> a4(axis::regular<>(3, -2, 2)); + axis::variant<axis::regular<>, axis::integer<>> a5(a4); + BOOST_TEST_EQ(a4, a5); + axis::variant<axis::regular<>> a6; + a6 = a1; + BOOST_TEST_EQ(a6, a1); + axis::variant<axis::regular<>, axis::integer<>> a7(axis::integer<>(0, 2)); + BOOST_TEST_THROWS(axis::variant<axis::regular<>> a8(a7), std::runtime_error); + BOOST_TEST_THROWS(a4 = a7, std::runtime_error); + } + + // axis::variant movable + { + axis::variant<axis::regular<>> a(axis::regular<>(2, -1, 1)); + axis::variant<axis::regular<>> r(a); + axis::variant<axis::regular<>> b(std::move(a)); + BOOST_TEST_EQ(b, r); + axis::variant<axis::regular<>> c; + BOOST_TEST_NE(c, b); + c = std::move(b); + BOOST_TEST(c == r); + } + + // axis::variant streamable + { + auto test = [](auto&& a, const char* ref) { + using T = std::decay_t<decltype(a)>; + axis::variant<T> axis(std::move(a)); + BOOST_TEST_CSTR_EQ(str(axis).c_str(), ref); + }; + + test(axis::regular<>(2, -1, 1, "regular1"), + "regular(2, -1, 1, metadata=\"regular1\", options=underflow | overflow)"); + + struct user_defined {}; + const auto ref = "integer(-1, 1, metadata=" + detail::type_name<user_defined>() + + ", options=none)"; + test(axis::integer<int, user_defined, axis::option::none_t>(-1, 1), ref.c_str()); + } + + // bin_type operator<< + { + auto test = [](auto&& a, const char* ref) { + using T = std::decay_t<decltype(a)>; + axis::variant<T> axis(std::move(a)); + BOOST_TEST_CSTR_EQ(str(axis.bin(0)).c_str(), ref); + }; + + test(axis::regular<>(2, 1, 2), "[1, 1.5)"); + test(axis::category<>({1, 2}), "1"); + } + + // axis::variant operator== + { + enum { A, B, C }; + using variant = + axis::variant<axis::regular<>, axis::regular<double, axis::transform::pow>, + axis::category<>, axis::integer<>>; + std::vector<variant> axes; + axes.push_back(axis::regular<>{2, -1, 1}); + axes.push_back(axis::regular<double, tr::pow>(tr::pow(0.5), 2, 1, 4)); + axes.push_back(axis::category<>({A, B, C})); + axes.push_back(axis::integer<>{-1, 1}); + for (const auto& a : axes) { + BOOST_TEST(!(a == variant())); + BOOST_TEST_EQ(a, variant(a)); + } + BOOST_TEST_NOT(axes == std::vector<variant>()); + BOOST_TEST(axes == std::vector<variant>(axes)); + } + + // axis::variant with axis that has incompatible bin type + { + auto a = axis::variant<axis::category<std::string>>( + axis::category<std::string>({"A", "B", "C"})); + BOOST_TEST_THROWS(a.bin(0), std::runtime_error); + auto b = axis::variant<axis::category<int>>(axis::category<int>({2, 1, 3})); + BOOST_TEST_EQ(b.bin(0), 2); + BOOST_TEST_EQ(b.bin(0).lower(), + b.bin(0).upper()); // lower == upper for bin without interval + } + + // axis::variant support for user-defined axis types + { + struct minimal_axis { + int index(int x) const { return x % 2; } + int size() const { return 2; } + }; + + axis::variant<minimal_axis, axis::category<std::string>> axis; + BOOST_TEST_EQ(axis.index(0), 0); + BOOST_TEST_EQ(axis.index(9), 1); + BOOST_TEST_EQ(axis.size(), 2); + BOOST_TEST_EQ(axis.metadata(), axis::null_type{}); + BOOST_TEST_CSTR_EQ(str(axis).c_str(), "<unstreamable>"); + BOOST_TEST_THROWS(axis.value(0), std::runtime_error); + + axis = axis::category<std::string>({"A", "B"}, "category"); + BOOST_TEST_EQ(axis.index("B"), 1); + BOOST_TEST_THROWS(axis.value(0), std::runtime_error); + } + + // vector of axes with custom allocators + { + using M = std::vector<char, tracing_allocator<char>>; + using T1 = axis::regular<double, tr::id, M>; + using T2 = axis::integer<int, axis::null_type>; + using T3 = axis::category<long, axis::null_type, axis::option::overflow_t, + tracing_allocator<long>>; + using axis_type = axis::variant<T1, T2, T3>; // no heap allocation + using axes_type = std::vector<axis_type, tracing_allocator<axis_type>>; + + tracing_allocator_db db; + { + auto a = tracing_allocator<char>(db); + axes_type axes(a); + axes.reserve(3); + axes.emplace_back(T1(1, 0, 1, M(3, 'c', a))); + axes.emplace_back(T2(0, 4)); + axes.emplace_back(T3({1, 2, 3, 4, 5}, {}, a)); + } + // 3 axis::variant objects + BOOST_TEST_EQ(db.at<axis_type>().first, 0); + BOOST_TEST_EQ(db.at<axis_type>().second, 3); + + // label of T1 + BOOST_TEST_EQ(db.at<char>().first, 0); + BOOST_TEST_EQ(db.at<char>().second, 3); + + // T3 allocates storage for long array + BOOST_TEST_EQ(db.at<long>().first, 0); + BOOST_TEST_EQ(db.at<long>().second, 5); + } + + // testing pass-through versions of get + { + axis::regular<> a(10, 0, 1); + axis::integer<> b(0, 3); + const auto& ta = axis::get<axis::regular<>>(a); + BOOST_TEST_EQ(ta, a); + const auto* tb = axis::get_if<axis::integer<>>(&b); + BOOST_TEST_EQ(tb, &b); + const auto* tc = axis::get_if<axis::regular<>>(&b); + BOOST_TEST_EQ(tc, nullptr); + } + + // iterators + test_axis_iterator(axis::variant<axis::regular<>>(axis::regular<>(5, 0, 1)), 0, 5); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/boost_accumulators_support_test.cpp b/src/boost/libs/histogram/test/boost_accumulators_support_test.cpp new file mode 100644 index 00000000..b394342b --- /dev/null +++ b/src/boost/libs/histogram/test/boost_accumulators_support_test.cpp @@ -0,0 +1,45 @@ +// Copyright 2018-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/accumulators/accumulators.hpp> +#include <boost/accumulators/statistics/mean.hpp> +#include <boost/accumulators/statistics/stats.hpp> +#include <boost/core/lightweight_test.hpp> +#include <boost/histogram/axis/integer.hpp> +#include "throw_exception.hpp" +#include <boost/histogram/make_histogram.hpp> +#include <boost/histogram/storage_adaptor.hpp> + +namespace ba = boost::accumulators; + +int main() { + using namespace boost::histogram; + + // mean + { + using mean = ba::accumulator_set<double, ba::stats<ba::tag::mean>>; + + auto h = make_histogram_with(dense_storage<mean>(), axis::integer<>(0, 2)); + h(0, sample(1)); + h(0, sample(2)); + h(0, sample(3)); + h(1, sample(2)); + h(1, sample(3)); + BOOST_TEST_EQ(ba::count(h[0]), 3); + BOOST_TEST_EQ(ba::mean(h[0]), 2); + BOOST_TEST_EQ(ba::count(h[1]), 2); + BOOST_TEST_EQ(ba::mean(h[1]), 2.5); + BOOST_TEST_EQ(ba::count(h[2]), 0); + + auto h2 = h; // copy ok + BOOST_TEST_EQ(ba::count(h2[0]), 3); + BOOST_TEST_EQ(ba::mean(h2[0]), 2); + BOOST_TEST_EQ(ba::count(h2[1]), 2); + BOOST_TEST_EQ(ba::mean(h2[1]), 2.5); + BOOST_TEST_EQ(ba::count(h2[2]), 0); + } + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/boost_range_support_test.cpp b/src/boost/libs/histogram/test/boost_range_support_test.cpp new file mode 100644 index 00000000..cf1bedc3 --- /dev/null +++ b/src/boost/libs/histogram/test/boost_range_support_test.cpp @@ -0,0 +1,29 @@ +// Copyright 2018-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/core/lightweight_test.hpp> +#include <boost/histogram/axis/integer.hpp> +#include "throw_exception.hpp" +#include <boost/histogram/histogram.hpp> +#include <boost/histogram/make_histogram.hpp> +#include <boost/range/adaptor/filtered.hpp> +#include <boost/range/numeric.hpp> + +using namespace boost::histogram; +using namespace boost::adaptors; + +int main() { + auto h = make_histogram(axis::integer<>(1, 4)); + h(1, weight(1)); + h(2, weight(2)); + h(3, weight(3)); + h(4, weight(4)); + + auto s1 = boost::accumulate(h | filtered([](double x) { return x > 2; }), 0.0); + BOOST_TEST_EQ(s1, 7); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/boost_units_support_test.cpp b/src/boost/libs/histogram/test/boost_units_support_test.cpp new file mode 100644 index 00000000..1a3df653 --- /dev/null +++ b/src/boost/libs/histogram/test/boost_units_support_test.cpp @@ -0,0 +1,74 @@ +// Copyright 2018 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/core/lightweight_test.hpp> +#include <boost/histogram/axis/ostream.hpp> +#include <boost/histogram/axis/regular.hpp> +#include "throw_exception.hpp" +#include <boost/histogram/histogram.hpp> +#include <boost/histogram/indexed.hpp> +#include <boost/histogram/literals.hpp> +#include <boost/histogram/make_histogram.hpp> +#include <boost/histogram/ostream.hpp> +#include <boost/units/quantity.hpp> +#include <boost/units/systems/si/length.hpp> +#include <limits> +#include "is_close.hpp" + +using namespace boost::histogram; +using namespace boost::histogram::literals; +namespace tr = axis::transform; + +int main() { + using namespace boost::units; + using Q = quantity<si::length>; + + // axis::regular with quantity + { + axis::regular<Q> b(2, 0 * si::meter, 2 * si::meter); + BOOST_TEST_EQ(b.bin(-1).lower() / si::meter, + -std::numeric_limits<double>::infinity()); + BOOST_TEST_IS_CLOSE(b.bin(0).lower() / si::meter, 0.0, 1e-9); + BOOST_TEST_IS_CLOSE(b.bin(1).lower() / si::meter, 1.0, 1e-9); + BOOST_TEST_IS_CLOSE(b.bin(2).lower() / si::meter, 2.0, 1e-9); + BOOST_TEST_EQ(b.bin(2).upper() / si::meter, std::numeric_limits<double>::infinity()); + + BOOST_TEST_EQ(b.index(-std::numeric_limits<double>::infinity() * si::meter), -1); + BOOST_TEST_EQ(b.index(-1 * si::meter), -1); // produces NaN in conversion + BOOST_TEST_EQ(b.index(0 * si::meter), 0); + BOOST_TEST_EQ(b.index(0.99 * si::meter), 0); + BOOST_TEST_EQ(b.index(1 * si::meter), 1); + BOOST_TEST_EQ(b.index(1.99 * si::meter), 1); + BOOST_TEST_EQ(b.index(2 * si::meter), 2); + BOOST_TEST_EQ(b.index(100 * si::meter), 2); + BOOST_TEST_EQ(b.index(std::numeric_limits<double>::infinity() * si::meter), 2); + } + + // axis::regular with quantity and transform + { + axis::regular<Q, tr::log> b(2, 1 * si::meter, 10 * si::meter); + BOOST_TEST_EQ(b.value(-1) / si::meter, 0); + BOOST_TEST_IS_CLOSE(b.value(0) / si::meter, 1.0, 1e-9); + BOOST_TEST_IS_CLOSE(b.value(1) / si::meter, 3.1623, 1e-3); + BOOST_TEST_IS_CLOSE(b.value(2) / si::meter, 10.0, 1e-9); + BOOST_TEST_EQ(b.value(3) / si::meter, std::numeric_limits<double>::infinity()); + } + + // histogram with quantity axis + { + auto h = make_histogram(axis::regular<Q>(2, 0 * si::meter, 1 * si::meter), + axis::regular<>(2, 0, 1)); + h(0.1 * si::meter, 0.1); // fills bin (0, 0) + BOOST_TEST_EQ(h.at(0, 0), 1); + for (auto&& x : indexed(h)) { + BOOST_TEST_THROWS(x.density(), std::runtime_error); // cannot use density method + BOOST_TEST_EQ(x.index(0), 2.0 * x.bin(0_c).lower() / si::meter); + BOOST_TEST_EQ(x.index(1), 2.0 * x.bin(1_c).lower()); + } + } + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/check_build_system.py b/src/boost/libs/histogram/test/check_build_system.py new file mode 100755 index 00000000..39bc112c --- /dev/null +++ b/src/boost/libs/histogram/test/check_build_system.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +# Copyright Hans Dembinski 2019 +# 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 + +from __future__ import print_function +import sys +import glob +import os +import re + +ps = os.path.split +pj = os.path.join + +# assumes that check_build_system.py sits in <project_path>/tests +project_path = ps(ps(__file__)[0])[0] + +exit_code = 0 + +for dir in (pj(project_path, "test"), pj(project_path, "examples")): + cpp = set([os.path.basename(x) for x in glob.glob(dir + "/*.cpp")]) + + for build_file in ("Jamfile", "CMakeLists.txt"): + filename = os.path.join(dir, build_file) + if not os.path.exists(filename): + continue + run = set(re.findall("([a-zA-Z0-9_]+\.cpp)", open(filename).read())) + + diff = cpp - run + diff.discard("check_cmake_version.cpp") # ignore + diff.discard("check_build_system.py") # ignore + + if diff: + print( + "NOT TESTED in %s\n " % filename + + "\n ".join(["%s/%s" % (dir, x) for x in diff]) + ) + exit_code = 1 + +sys.exit(exit_code) diff --git a/src/boost/libs/histogram/test/check_cmake_version.cpp b/src/boost/libs/histogram/test/check_cmake_version.cpp new file mode 100644 index 00000000..160db585 --- /dev/null +++ b/src/boost/libs/histogram/test/check_cmake_version.cpp @@ -0,0 +1,25 @@ +// Check whether the version in CMakeLists.txt is up to date +// +// Copyright 2018 Peter Dimov +// +// 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/core/lightweight_test.hpp> +#include <boost/version.hpp> +#include <cstdio> + +int main(int ac, char const* av[]) { + BOOST_TEST_EQ(ac, 2); + + if (ac >= 2) { + char version[64]; + std::sprintf(version, "%d.%d.%d", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, + BOOST_VERSION % 100); + + BOOST_TEST_CSTR_EQ(av[1], version); + } + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/check_odr_test.py b/src/boost/libs/histogram/test/check_odr_test.py new file mode 100644 index 00000000..7537cc88 --- /dev/null +++ b/src/boost/libs/histogram/test/check_odr_test.py @@ -0,0 +1,54 @@ +# Copyright 2019 Hans Dembinski, Henry Schreiner +# +# 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) + +import os +import sys +import re + +this_path = os.path.dirname(__file__) + +all_headers = set() +include_path = os.path.join(this_path, "..", "include") +for root, dirs, files in os.walk(include_path): + for fn in files: + fn = os.path.join(root, fn) + assert fn.startswith(include_path) + fn = fn[len(include_path) + 1 :] + all_headers.add(fn) + + +def get_headers(filename): + with open(filename) as f: + for hdr in re.findall('^#include [<"]([^>"]+)[>"]', f.read(), re.MULTILINE): + if not hdr.startswith("boost/histogram"): + continue + yield hdr.replace("/", os.path.sep) # adapt the paths for Windows + + +included_headers = set() +unread_headers = set() +for hdr in get_headers(os.path.join(this_path, "odr_test.cpp")): + unread_headers.add(hdr) + +while unread_headers: + included_headers.update(unread_headers) + for hdr in tuple(unread_headers): # copy needed because unread_headers is modified + unread_headers.remove(hdr) + for hdr2 in get_headers(os.path.join(include_path, hdr)): + if hdr2 not in included_headers: + unread_headers.add(hdr2) + +diff = sorted(all_headers - set(included_headers)) + +if not diff: + sys.exit(0) + + +print("Header not included in odr_test.cpp:") +for fn in diff: + print(fn) + +sys.exit(1) diff --git a/src/boost/libs/histogram/test/deduction_guides_test.cpp b/src/boost/libs/histogram/test/deduction_guides_test.cpp new file mode 100644 index 00000000..2bd0f8bc --- /dev/null +++ b/src/boost/libs/histogram/test/deduction_guides_test.cpp @@ -0,0 +1,145 @@ +// Copyright 2018 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/core/lightweight_test.hpp> +#include <boost/core/lightweight_test_trait.hpp> +#include <boost/histogram/accumulators/weighted_sum.hpp> +#include <boost/histogram/axis.hpp> +#include <boost/histogram/axis/ostream.hpp> +#include <boost/histogram/histogram.hpp> +#include <boost/histogram/ostream.hpp> +#include <boost/histogram/storage_adaptor.hpp> +#include <boost/histogram/unlimited_storage.hpp> +#include <tuple> +#include <type_traits> +#include <vector> +#include "std_ostream.hpp" +#include "throw_exception.hpp" + +using namespace boost::histogram; +namespace tr = axis::transform; + +// tests requires a C++17 compatible compiler + +#define TEST BOOST_TEST_TRAIT_SAME + +int main() { + using axis::null_type; + + { + using axis::regular; + BOOST_TEST_TRAIT_SAME(decltype(regular(1, 0.0, 1.0)), + regular<double, tr::id, null_type>); + BOOST_TEST_TRAIT_SAME(decltype(regular(1, 0, 1)), regular<double, tr::id, null_type>); + BOOST_TEST_TRAIT_SAME(decltype(regular(1, 0.0f, 1.0f)), + regular<float, tr::id, null_type>); + BOOST_TEST_TRAIT_SAME(decltype(regular(1, 0, 1, 0)), regular<double, tr::id, int>); + BOOST_TEST_TRAIT_SAME(decltype(regular(1, 0.0f, 1.0f, "x")), + regular<float, tr::id, std::string>); + BOOST_TEST_TRAIT_SAME(decltype(regular(tr::sqrt(), 1, 0, 1)), + regular<double, tr::sqrt, null_type>); + BOOST_TEST_TRAIT_SAME(decltype(regular(tr::sqrt(), 1, 0.0f, 1.0f, "x")), + regular<float, tr::sqrt, std::string>); + BOOST_TEST_TRAIT_SAME(decltype(regular(tr::sqrt(), 1, 0, 1, 0)), + regular<double, tr::sqrt, int>); + } + + { + using axis::integer; + BOOST_TEST_TRAIT_SAME(decltype(integer(1, 2)), integer<int, null_type>); + BOOST_TEST_TRAIT_SAME(decltype(integer(1l, 2l)), integer<int, null_type>); + BOOST_TEST_TRAIT_SAME(decltype(integer(1.0, 2.0)), integer<double, null_type>); + BOOST_TEST_TRAIT_SAME(decltype(integer(1.0f, 2.0f)), integer<float, null_type>); + BOOST_TEST_TRAIT_SAME(decltype(integer(1, 2, "foo")), integer<int, std::string>); + BOOST_TEST_TRAIT_SAME(decltype(integer(1, 2, 0)), integer<int, int>); + } + + { + using axis::variable; + BOOST_TEST_TRAIT_SAME(decltype(variable{-1.0f, 1.0f}), variable<float, null_type>); + BOOST_TEST_TRAIT_SAME(decltype(variable{-1, 0, 1, 2}), variable<double, null_type>); + BOOST_TEST_TRAIT_SAME(decltype(variable{-1.0, 1.0}), variable<double, null_type>); + BOOST_TEST_TRAIT_SAME(decltype(variable({-1, 0, 1}, "foo")), + variable<double, std::string>); + BOOST_TEST_TRAIT_SAME(decltype(variable({-1, 1}, 0)), variable<double, int>); + + BOOST_TEST_TRAIT_SAME(decltype(variable(std::vector<int>{{-1, 1}})), + variable<double, null_type>); + BOOST_TEST_TRAIT_SAME(decltype(variable(std::vector<float>{{-1.0f, 1.0f}})), + variable<float, null_type>); + BOOST_TEST_TRAIT_SAME(decltype(variable(std::vector<int>{{-1, 1}}, "foo")), + variable<double, std::string>); + BOOST_TEST_TRAIT_SAME(decltype(variable(std::vector<int>{{-1, 1}}, 0)), + variable<double, int>); + } + + { + using axis::category; + BOOST_TEST_TRAIT_SAME(decltype(category{1, 2}), category<int, null_type>); + BOOST_TEST_TRAIT_SAME(decltype(category{"x", "y"}), category<std::string, null_type>); + BOOST_TEST_TRAIT_SAME(decltype(category({1, 2}, "foo")), category<int, std::string>); + BOOST_TEST_TRAIT_SAME(decltype(category({1, 2}, 0)), category<int, int>); + } + + { + auto h = histogram(axis::regular(3, -1, 1), axis::integer(0, 4)); + BOOST_TEST_TRAIT_SAME(decltype(h), + histogram<std::tuple<axis::regular<double, tr::id, null_type>, + axis::integer<int, null_type>>>); + BOOST_TEST_EQ(h.axis(0), axis::regular(3, -1, 1)); + BOOST_TEST_EQ(h.axis(1), axis::integer(0, 4)); + } + + { + auto h = histogram(std::tuple(axis::regular(3, -1, 1), axis::integer(0, 4)), + weight_storage()); + BOOST_TEST_TRAIT_SAME(decltype(h), + histogram<std::tuple<axis::regular<double, tr::id, null_type>, + axis::integer<int, null_type>>, + weight_storage>); + BOOST_TEST_EQ(h.axis(0), axis::regular(3, -1, 1)); + BOOST_TEST_EQ(h.axis(1), axis::integer(0, 4)); + } + + { + auto a0 = axis::regular(5, 0, 5); + auto a1 = axis::regular(3, -1, 1); + auto axes = {a0, a1}; + auto h = histogram(axes); + BOOST_TEST_TRAIT_SAME( + decltype(h), histogram<std::vector<axis::regular<double, tr::id, null_type>>>); + BOOST_TEST_EQ(h.rank(), 2); + BOOST_TEST_EQ(h.axis(0), a0); + BOOST_TEST_EQ(h.axis(1), a1); + } + + { + auto a0 = axis::regular(5, 0, 5); + auto a1 = axis::regular(3, -1, 1); + auto axes = {a0, a1}; + auto h = histogram(axes, weight_storage()); + BOOST_TEST_TRAIT_SAME( + decltype(h), + histogram<std::vector<axis::regular<double, tr::id, null_type>>, weight_storage>); + BOOST_TEST_EQ(h.rank(), 2); + BOOST_TEST_EQ(h.axis(0), a0); + BOOST_TEST_EQ(h.axis(1), a1); + } + + { + auto a0 = axis::regular(5, 0, 5); + auto a1 = axis::regular(3, -1, 1); + auto axes = std::vector<decltype(a0)>{{a0, a1}}; + auto h = histogram(axes); + BOOST_TEST_TRAIT_SAME( + decltype(h), histogram<std::vector<axis::regular<double, tr::id, null_type>>>); + BOOST_TEST_EQ(h.rank(), 2); + BOOST_TEST_EQ(h.axis(0), a0); + BOOST_TEST_EQ(h.axis(1), a1); + } + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/detail_accumulator_traits_test.cpp b/src/boost/libs/histogram/test/detail_accumulator_traits_test.cpp new file mode 100644 index 00000000..7846d28f --- /dev/null +++ b/src/boost/libs/histogram/test/detail_accumulator_traits_test.cpp @@ -0,0 +1,82 @@ +// 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/core/lightweight_test.hpp> +#include <boost/core/lightweight_test_trait.hpp> +#include <boost/histogram/detail/accumulator_traits.hpp> +#include <boost/histogram/weight.hpp> +#include <tuple> + +namespace dtl = boost::histogram::detail; + +int main() { + using boost::histogram::weight_type; + + struct A1 { + void operator()(){}; + }; + + BOOST_TEST_NOT(dtl::accumulator_traits<A1>::wsupport::value); + BOOST_TEST_TRAIT_SAME(typename dtl::accumulator_traits<A1>::args, std::tuple<>); + + struct A2 { + void operator()(int, double) {} + }; + + BOOST_TEST_NOT(dtl::accumulator_traits<A2>::wsupport::value); + BOOST_TEST_TRAIT_SAME(typename dtl::accumulator_traits<A2>::args, + std::tuple<int, double>); + + struct A3 { + void operator()() {} + void operator()(weight_type<int>) {} + }; + + BOOST_TEST(dtl::accumulator_traits<A3>::wsupport::value); + BOOST_TEST_TRAIT_SAME(typename dtl::accumulator_traits<A3>::args, std::tuple<>); + + struct A4 { + void operator()(int, double, char) {} + void operator()(weight_type<int>, int, double, char) {} + }; + + BOOST_TEST(dtl::accumulator_traits<A4>::wsupport::value); + BOOST_TEST_TRAIT_SAME(typename dtl::accumulator_traits<A4>::args, + std::tuple<int, double, char>); + + struct A5 { + void operator()(const weight_type<int>, int) {} + }; + + BOOST_TEST(dtl::accumulator_traits<A5>::wsupport::value); + BOOST_TEST_TRAIT_SAME(typename dtl::accumulator_traits<A5>::args, std::tuple<int>); + + struct A6 { + void operator()(const weight_type<int>&, const int) {} + }; + + BOOST_TEST(dtl::accumulator_traits<A6>::wsupport::value); + BOOST_TEST_TRAIT_SAME(typename dtl::accumulator_traits<A6>::args, std::tuple<int>); + + struct A7 { + void operator()(weight_type<int>&&, int&&) {} + }; + + BOOST_TEST(dtl::accumulator_traits<A7>::wsupport::value); + BOOST_TEST_TRAIT_SAME(typename dtl::accumulator_traits<A7>::args, std::tuple<int&&>); + + struct B { + int operator+=(int) { return 0; } + }; + + BOOST_TEST(dtl::accumulator_traits<B>::wsupport::value); + BOOST_TEST_TRAIT_SAME(typename dtl::accumulator_traits<B>::args, std::tuple<>); + + BOOST_TEST(dtl::accumulator_traits<int>::wsupport::value); + BOOST_TEST_TRAIT_SAME(dtl::accumulator_traits<int>::args, std::tuple<>); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/detail_args_type_test.cpp b/src/boost/libs/histogram/test/detail_args_type_test.cpp new file mode 100644 index 00000000..d9e4b242 --- /dev/null +++ b/src/boost/libs/histogram/test/detail_args_type_test.cpp @@ -0,0 +1,31 @@ +// Copyright 2015-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/core/lightweight_test_trait.hpp> +#include <boost/histogram/detail/args_type.hpp> +#include <tuple> +#include "std_ostream.hpp" + +namespace dtl = boost::histogram::detail; + +struct Foo { + int f1(char); + int f2(long) const; + static int f3(char, int); + auto f4(char, int) { return 0; }; +}; + +int main() { + BOOST_TEST_TRAIT_SAME(dtl::args_type<decltype(&Foo::f1)>, std::tuple<char>); + BOOST_TEST_TRAIT_SAME(dtl::args_type<decltype(&Foo::f2)>, std::tuple<long>); + BOOST_TEST_TRAIT_SAME(dtl::args_type<decltype(&Foo::f3)>, std::tuple<char, int>); + BOOST_TEST_TRAIT_SAME(dtl::args_type<decltype(&Foo::f4)>, std::tuple<char, int>); + + BOOST_TEST_TRAIT_SAME(dtl::arg_type<decltype(&Foo::f3)>, char); + BOOST_TEST_TRAIT_SAME(dtl::arg_type<decltype(&Foo::f3), 1>, int); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/detail_argument_traits_test.cpp b/src/boost/libs/histogram/test/detail_argument_traits_test.cpp new file mode 100644 index 00000000..23f740d0 --- /dev/null +++ b/src/boost/libs/histogram/test/detail_argument_traits_test.cpp @@ -0,0 +1,61 @@ +// 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/core/lightweight_test.hpp> +#include <boost/core/lightweight_test_trait.hpp> +#include <boost/histogram/detail/argument_traits.hpp> +#include <boost/histogram/sample.hpp> +#include <boost/histogram/weight.hpp> + +namespace dtl = boost::histogram::detail; + +int main() { + using boost::histogram::sample; + using boost::histogram::weight; + + // is_weight + { + struct A {}; + using B = int; + BOOST_TEST_NOT(dtl::is_weight<A>::value); + BOOST_TEST_NOT(dtl::is_weight<B>::value); + BOOST_TEST_NOT(dtl::is_weight<decltype(sample(0))>::value); + BOOST_TEST(dtl::is_weight<decltype(weight(0))>::value); + } + + // is_sample + { + struct A {}; + using B = int; + BOOST_TEST_NOT(dtl::is_sample<A>::value); + BOOST_TEST_NOT(dtl::is_sample<B>::value); + BOOST_TEST_NOT(dtl::is_sample<decltype(weight(0))>::value); + BOOST_TEST(dtl::is_sample<decltype(sample(0))>::value); + BOOST_TEST(dtl::is_sample<decltype(sample(0, A{}))>::value); + } + + using T1 = dtl::argument_traits<int>; + using E1 = dtl::argument_traits_holder<1, 0, -1, -1, std::tuple<>>; + BOOST_TEST_TRAIT_SAME(T1, E1); + + using T2 = dtl::argument_traits<int, int>; + using E2 = dtl::argument_traits_holder<2, 0, -1, -1, std::tuple<>>; + BOOST_TEST_TRAIT_SAME(T2, E2); + + using T3 = dtl::argument_traits<decltype(weight(0)), int, int>; + using E3 = dtl::argument_traits_holder<2, 1, 0, -1, std::tuple<>>; + BOOST_TEST_TRAIT_SAME(T3, E3); + + using T4 = dtl::argument_traits<decltype(weight(0)), int, int, decltype(sample(0))>; + using E4 = dtl::argument_traits_holder<2, 1, 0, 3, std::tuple<int>>; + BOOST_TEST_TRAIT_SAME(T4, E4); + + using T5 = dtl::argument_traits<int, decltype(sample(0, 0.0))>; + using E5 = dtl::argument_traits_holder<1, 0, -1, 1, std::tuple<int, double>>; + BOOST_TEST_TRAIT_SAME(T5, E5); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/detail_array_wrapper_serialization_test.cpp b/src/boost/libs/histogram/test/detail_array_wrapper_serialization_test.cpp new file mode 100644 index 00000000..edf3a97f --- /dev/null +++ b/src/boost/libs/histogram/test/detail_array_wrapper_serialization_test.cpp @@ -0,0 +1,71 @@ +// 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/archive/binary_iarchive.hpp> +#include <boost/archive/binary_oarchive.hpp> +#include <boost/archive/text_iarchive.hpp> +#include <boost/archive/text_oarchive.hpp> +#include <boost/core/lightweight_test.hpp> +#include <boost/histogram/detail/array_wrapper.hpp> +#include <sstream> +#include <vector> +#include "std_ostream.hpp" +#include "throw_exception.hpp" + +namespace dtl = boost::histogram::detail; +namespace ba = boost::archive; + +template <class T> +struct dummy_array_wrapper { + T* ptr; + std::size_t size; + template <class Archive> + void serialize(Archive& ar, unsigned /* version */) { + for (auto&& x : dtl::make_span(ptr, size)) ar& x; + } +}; + +template <class OArchive, class IArchive> +void run_tests() { + std::vector<int> v = {{1, 2, 3}}; + + std::stringstream os1; + { + OArchive oa(os1); + auto w = dtl::make_array_wrapper(v.data(), v.size()); + oa << w; + } + + std::ostringstream os2; + { + OArchive oa(os2); + auto w = dummy_array_wrapper<int>{v.data(), v.size()}; + oa << w; + } + + BOOST_TEST_EQ(os1.str(), os2.str()); + + std::vector<int> v2(3, 0); + { + IArchive ia(os1); + auto w = dtl::make_array_wrapper(v2.data(), v2.size()); + ia >> w; + } + + BOOST_TEST_EQ(v, v2); +} + +int main() { + BOOST_TEST(dtl::has_array_optimization<ba::binary_oarchive>::value); + BOOST_TEST(dtl::has_array_optimization<ba::binary_iarchive>::value); + BOOST_TEST_NOT(dtl::has_array_optimization<ba::text_oarchive>::value); + BOOST_TEST_NOT(dtl::has_array_optimization<ba::text_iarchive>::value); + + run_tests<ba::binary_oarchive, ba::binary_iarchive>(); + run_tests<ba::text_oarchive, ba::text_iarchive>(); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/detail_axes_test.cpp b/src/boost/libs/histogram/test/detail_axes_test.cpp new file mode 100644 index 00000000..c16c762c --- /dev/null +++ b/src/boost/libs/histogram/test/detail_axes_test.cpp @@ -0,0 +1,177 @@ +// Copyright 2015-2017 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 <array> +#include <boost/core/lightweight_test.hpp> +#include <boost/core/lightweight_test_trait.hpp> +#include <boost/histogram/axis.hpp> +#include <boost/histogram/axis/ostream.hpp> +#include <boost/histogram/detail/axes.hpp> +#include <limits> +#include <tuple> +#include <utility> +#include <vector> +#include "std_ostream.hpp" +#include "throw_exception.hpp" + +using namespace boost::histogram; + +int main() { + // dynamic axis_get with tuples + { + auto a1 = axis::integer<>(0, 1); + auto a2 = axis::integer<>(1, 2); + auto tup = std::make_tuple(a1, a2); + using E1 = axis::variant<axis::integer<>*>; + BOOST_TEST_TRAIT_SAME(decltype(detail::axis_get(tup, 0)), E1); + BOOST_TEST_EQ(detail::axis_get(tup, 0), a1); + BOOST_TEST_EQ(detail::axis_get(tup, 1), a2); + BOOST_TEST_NE(detail::axis_get(tup, 0), a2); + } + + // sequence equality + { + using R = axis::regular<>; + using I = axis::integer<>; + using V = axis::variable<>; + auto r = R(2, -1, 1); + auto i = I(-1, 1); + auto v = V{-1, 0, 1}; + + std::vector<axis::variant<R, I, V>> v1 = {r, i}; + std::vector<axis::variant<R, I>> v2 = {r, i}; + std::vector<axis::variant<R, I>> v3 = {i, r}; + std::vector<axis::variant<I, R>> v4 = {r, i}; + std::vector<axis::variant<R, I>> v5 = {r, r}; + std::vector<R> v6 = {r, r}; + + BOOST_TEST(detail::axes_equal(v1, v2)); + BOOST_TEST(detail::axes_equal(v1, v4)); + BOOST_TEST(detail::axes_equal(v5, v6)); + BOOST_TEST_NOT(detail::axes_equal(v1, v3)); + BOOST_TEST_NOT(detail::axes_equal(v2, v3)); + BOOST_TEST_NOT(detail::axes_equal(v3, v4)); + BOOST_TEST_NOT(detail::axes_equal(v1, v5)); + + auto t1 = std::make_tuple(r, i); + auto t2 = std::make_tuple(i, r); + auto t3 = std::make_tuple(v, i); + auto t4 = std::make_tuple(r, r); + + BOOST_TEST(detail::axes_equal(t1, v1)); + BOOST_TEST(detail::axes_equal(t1, v2)); + BOOST_TEST(detail::axes_equal(t1, v4)); + BOOST_TEST(detail::axes_equal(v1, t1)); + BOOST_TEST(detail::axes_equal(v2, t1)); + BOOST_TEST(detail::axes_equal(v4, t1)); + BOOST_TEST(detail::axes_equal(t2, v3)); + BOOST_TEST(detail::axes_equal(v3, t2)); + BOOST_TEST(detail::axes_equal(t4, v5)); + BOOST_TEST(detail::axes_equal(t4, v6)); + BOOST_TEST_NOT(detail::axes_equal(t1, t2)); + BOOST_TEST_NOT(detail::axes_equal(t2, t3)); + BOOST_TEST_NOT(detail::axes_equal(t1, v3)); + BOOST_TEST_NOT(detail::axes_equal(t1, v3)); + BOOST_TEST_NOT(detail::axes_equal(t3, v1)); + BOOST_TEST_NOT(detail::axes_equal(t3, v2)); + BOOST_TEST_NOT(detail::axes_equal(t3, v3)); + BOOST_TEST_NOT(detail::axes_equal(t3, v4)); + } + + // sequence assign + { + using R = axis::regular<>; + using I = axis::integer<>; + using V = axis::variable<>; + auto r = R(2, -1, 1); + auto i = I(-1, 1); + auto v = V{-1, 0, 1}; + + std::vector<axis::variant<R, V, I>> v1 = {r, i}; + std::vector<axis::variant<I, R>> v2; + std::vector<R> v3 = {r, r}; + + BOOST_TEST_NOT(detail::axes_equal(v2, v1)); + detail::axes_assign(v2, v1); + BOOST_TEST(detail::axes_equal(v2, v1)); + detail::axes_assign(v2, v3); + BOOST_TEST(detail::axes_equal(v2, v3)); + + auto t1 = std::make_tuple(r); + detail::axes_assign(v3, t1); + BOOST_TEST(detail::axes_equal(v3, t1)); + + auto t2 = std::make_tuple(r, i); + detail::axes_assign(v2, t2); + BOOST_TEST(detail::axes_equal(v2, t2)); + + auto t3 = std::make_tuple(R{3, -1, 1}, i); + BOOST_TEST_NOT(detail::axes_equal(t2, t3)); + detail::axes_assign(t2, t3); + BOOST_TEST(detail::axes_equal(t2, t3)); + } + + // axes_rank + { + std::tuple<int, int> a; + std::vector<int> b(3); + std::array<int, 4> c; + const std::tuple<int> d; + BOOST_TEST_EQ(detail::axes_rank(a), 2); + BOOST_TEST_EQ(detail::axes_rank(b), 3); + BOOST_TEST_EQ(detail::axes_rank(c), 4); + BOOST_TEST_EQ(detail::axes_rank(d), 1); + } + + // bincount overflow + { + auto v = std::vector<axis::integer<>>( + 100, axis::integer<>(0, (std::numeric_limits<int>::max)() - 2)); + BOOST_TEST_THROWS(detail::bincount(v), std::overflow_error); + } + + // has_growing_axis + { + struct growing { + auto update(int) { return std::make_pair(0, 0); } + }; + using T = growing; + using I = axis::integer<>; + + using A = std::tuple<I, T>; + using B = std::vector<T>; + using C = std::vector<axis::variant<I, T>>; + using D = std::tuple<I>; + using E = std::vector<I>; + using F = std::vector<axis::variant<I>>; + + BOOST_TEST_TRAIT_TRUE((detail::has_growing_axis<A>)); + BOOST_TEST_TRAIT_TRUE((detail::has_growing_axis<B>)); + BOOST_TEST_TRAIT_TRUE((detail::has_growing_axis<C>)); + BOOST_TEST_TRAIT_FALSE((detail::has_growing_axis<D>)); + BOOST_TEST_TRAIT_FALSE((detail::has_growing_axis<E>)); + BOOST_TEST_TRAIT_FALSE((detail::has_growing_axis<F>)); + } + + // value_types + { + using R = axis::regular<float>; + using I = axis::integer<int>; + using CI = axis::category<int>; + using CS = axis::category<std::string>; + using A = std::vector<axis::variant<R, I, CS>>; + using B = std::vector<axis::variant<CS, I, CI, R>>; + using C = std::tuple<I, R, CS>; + using D = std::tuple<CS, I, CI, R>; + using Expected = boost::mp11::mp_list<int, float, std::string>; + BOOST_TEST_TRAIT_SAME(detail::value_types<A>, Expected); + BOOST_TEST_TRAIT_SAME(detail::value_types<B>, Expected); + BOOST_TEST_TRAIT_SAME(detail::value_types<C>, Expected); + BOOST_TEST_TRAIT_SAME(detail::value_types<D>, Expected); + } + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/detail_convert_integer_test.cpp b/src/boost/libs/histogram/test/detail_convert_integer_test.cpp new file mode 100644 index 00000000..10e5f105 --- /dev/null +++ b/src/boost/libs/histogram/test/detail_convert_integer_test.cpp @@ -0,0 +1,22 @@ +// Copyright 2015-2017 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/core/lightweight_test.hpp> +#include <boost/core/lightweight_test_trait.hpp> +#include <boost/histogram/detail/convert_integer.hpp> +#include "std_ostream.hpp" + +using namespace boost::histogram::detail; + +int main() { + + BOOST_TEST_TRAIT_SAME(convert_integer<char, float>, float); + BOOST_TEST_TRAIT_SAME(convert_integer<int, float>, float); + BOOST_TEST_TRAIT_SAME(convert_integer<double, float>, double); + BOOST_TEST_TRAIT_SAME(convert_integer<float, double>, float); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/detail_detect_test.cpp b/src/boost/libs/histogram/test/detail_detect_test.cpp new file mode 100644 index 00000000..1304ef44 --- /dev/null +++ b/src/boost/libs/histogram/test/detail_detect_test.cpp @@ -0,0 +1,299 @@ +// Copyright 2015-2017 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 <array> +#include <boost/core/lightweight_test.hpp> +#include <boost/core/lightweight_test_trait.hpp> +#include <boost/histogram/axis/integer.hpp> +#include <boost/histogram/axis/regular.hpp> +#include <boost/histogram/axis/variable.hpp> +#include <boost/histogram/axis/variant.hpp> +#include <boost/histogram/detail/detect.hpp> +#include <boost/histogram/unlimited_storage.hpp> +#include <deque> +#include <initializer_list> +#include <map> +#include <string> +#include <type_traits> +#include <unordered_map> +#include <utility> +#include <vector> +#include "std_ostream.hpp" +#include "throw_exception.hpp" +#include "utility_allocator.hpp" + +using namespace boost::histogram; +using namespace boost::histogram::detail; + +int main() { + // has_method_value* + { + struct A {}; + struct B { + A value(int) const { return {}; } + }; + struct C { + char value(int) const { return 0; } + }; + + BOOST_TEST_TRAIT_FALSE((has_method_value<A>)); + BOOST_TEST_TRAIT_TRUE((has_method_value<B>)); + BOOST_TEST_TRAIT_TRUE((has_method_value<C>)); + } + + // has_method_options + { + struct A {}; + struct B { + void options() {} + }; + + BOOST_TEST_TRAIT_FALSE((has_method_options<A>)); + BOOST_TEST_TRAIT_TRUE((has_method_options<B>)); + } + + // has_method_metadata + { + struct A {}; + struct B { + void metadata(); + }; + + BOOST_TEST_TRAIT_FALSE((has_method_metadata<A>)); + BOOST_TEST_TRAIT_TRUE((has_method_metadata<B>)); + } + + // has_method_update + { + struct A {}; + struct B { + void update(int) {} + }; + using C = axis::integer<int, axis::null_type, use_default>; + + BOOST_TEST_TRAIT_FALSE((has_method_update<A>)); + BOOST_TEST_TRAIT_TRUE((has_method_update<B>)); + BOOST_TEST_TRAIT_TRUE((has_method_update<C>)); + } + + // has_method_resize + { + struct A {}; + using B = std::vector<int>; + using C = std::map<int, int>; + + BOOST_TEST_TRAIT_FALSE((has_method_resize<A>)); + BOOST_TEST_TRAIT_TRUE((has_method_resize<B>)); + BOOST_TEST_TRAIT_FALSE((has_method_resize<C>)); + } + + // has_method_size + { + struct A {}; + using B = std::vector<int>; + using C = std::map<int, int>; + + BOOST_TEST_TRAIT_FALSE((has_method_size<A>)); + BOOST_TEST_TRAIT_TRUE((has_method_size<B>)); + BOOST_TEST_TRAIT_TRUE((has_method_size<C>)); + } + + // has_method_clear + { + struct A {}; + using B = std::vector<int>; + using C = std::map<int, int>; + using D = std::array<int, 10>; + + BOOST_TEST_TRAIT_FALSE((has_method_clear<A>)); + BOOST_TEST_TRAIT_TRUE((has_method_clear<B>)); + BOOST_TEST_TRAIT_TRUE((has_method_clear<C>)); + BOOST_TEST_TRAIT_FALSE((has_method_clear<D>)); + } + + // has_allocator + { + struct A {}; + using B = std::vector<int>; + using C = std::map<int, int>; + using D = std::array<int, 10>; + + BOOST_TEST_TRAIT_FALSE((has_method_clear<A>)); + BOOST_TEST_TRAIT_TRUE((has_method_clear<B>)); + BOOST_TEST_TRAIT_TRUE((has_method_clear<C>)); + BOOST_TEST_TRAIT_FALSE((has_method_clear<D>)); + } + + // is_storage + { + struct A {}; + using B = std::vector<int>; + using C = unlimited_storage<>; + + BOOST_TEST_TRAIT_FALSE((is_storage<A>)); + BOOST_TEST_TRAIT_FALSE((is_storage<B>)); + BOOST_TEST_TRAIT_TRUE((is_storage<C>)); + } + + // is_indexable + { + struct A {}; + using B = std::vector<int>; + using C = std::map<int, int>; + using D = std::map<A, int>; + + BOOST_TEST_TRAIT_FALSE((is_indexable<A>)); + BOOST_TEST_TRAIT_TRUE((is_indexable<B>)); + BOOST_TEST_TRAIT_TRUE((is_indexable<C>)); + BOOST_TEST_TRAIT_FALSE((is_indexable<D>)); + } + + // is_transform + { + struct A {}; + struct B { + double forward(A); + A inverse(double); + }; + + BOOST_TEST_TRAIT_FALSE((is_transform<A, double>)); + BOOST_TEST_TRAIT_TRUE((is_transform<B, A>)); + BOOST_TEST_TRAIT_TRUE((is_transform<axis::transform::id, double>)); + } + + // is_vector_like + { + struct A {}; + using B = std::vector<int>; + using C = std::array<int, 10>; + using D = std::map<unsigned, int>; + using E = std::deque<int>; + BOOST_TEST_TRAIT_FALSE((is_vector_like<A>)); + BOOST_TEST_TRAIT_TRUE((is_vector_like<B>)); + BOOST_TEST_TRAIT_FALSE((is_vector_like<C>)); + BOOST_TEST_TRAIT_FALSE((is_vector_like<D>)); + BOOST_TEST_TRAIT_TRUE((is_vector_like<E>)); + } + + // is_array_like + { + struct A {}; + using B = std::vector<int>; + using C = std::array<int, 10>; + using D = std::map<unsigned, int>; + BOOST_TEST_TRAIT_FALSE((is_array_like<A>)); + BOOST_TEST_TRAIT_FALSE((is_array_like<B>)); + BOOST_TEST_TRAIT_TRUE((is_array_like<C>)); + BOOST_TEST_TRAIT_FALSE((is_array_like<D>)); + } + + // is_map_like + { + struct A {}; + using B = std::vector<int>; + using C = std::array<int, 10>; + using D = std::map<unsigned, int>; + using E = std::unordered_map<unsigned, int>; + BOOST_TEST_TRAIT_FALSE((is_map_like<A>)); + BOOST_TEST_TRAIT_FALSE((is_map_like<B>)); + BOOST_TEST_TRAIT_FALSE((is_map_like<C>)); + BOOST_TEST_TRAIT_TRUE((is_map_like<D>)); + BOOST_TEST_TRAIT_TRUE((is_map_like<E>)); + } + + // is_axis + { + struct A {}; + struct B { + int index(double); + int size() const; + }; + struct C { + int index(double); + }; + struct D { + int size(); + }; + using E = axis::variant<axis::regular<>>; + + BOOST_TEST_TRAIT_FALSE((is_axis<A>)); + BOOST_TEST_TRAIT_TRUE((is_axis<B>)); + BOOST_TEST_TRAIT_FALSE((is_axis<C>)); + BOOST_TEST_TRAIT_FALSE((is_axis<D>)); + BOOST_TEST_TRAIT_FALSE((is_axis<E>)); + } + + // is_iterable + { + using A = std::vector<int>; + using B = int[3]; + using C = std::initializer_list<int>; + BOOST_TEST_TRAIT_FALSE((is_iterable<int>)); + BOOST_TEST_TRAIT_TRUE((is_iterable<A>)); + BOOST_TEST_TRAIT_TRUE((is_iterable<B>)); + BOOST_TEST_TRAIT_TRUE((is_iterable<C>)); + } + + // is_streamable + { + struct Foo {}; + BOOST_TEST_TRAIT_TRUE((is_streamable<int>)); + BOOST_TEST_TRAIT_TRUE((is_streamable<std::string>)); + BOOST_TEST_TRAIT_FALSE((is_streamable<Foo>)); + } + + // is_axis_variant + { + struct A {}; + BOOST_TEST_TRAIT_FALSE((is_axis_variant<A>)); + BOOST_TEST_TRAIT_TRUE((is_axis_variant<axis::variant<>>)); + BOOST_TEST_TRAIT_TRUE((is_axis_variant<axis::variant<axis::regular<>>>)); + } + + // is_sequence_of_axis + { + using A = std::vector<axis::regular<>>; + using B = std::vector<axis::variant<axis::regular<>>>; + using C = std::vector<int>; + auto v = std::vector<axis::variant<axis::regular<>, axis::integer<>>>(); + BOOST_TEST_TRAIT_TRUE((is_sequence_of_any_axis<A>)); + BOOST_TEST_TRAIT_TRUE((is_sequence_of_axis<A>)); + BOOST_TEST_TRAIT_FALSE((is_sequence_of_axis_variant<A>)); + BOOST_TEST_TRAIT_TRUE((is_sequence_of_any_axis<B>)); + BOOST_TEST_TRAIT_TRUE((is_sequence_of_axis_variant<B>)); + BOOST_TEST_TRAIT_FALSE((is_sequence_of_axis<B>)); + BOOST_TEST_TRAIT_FALSE((is_sequence_of_any_axis<C>)); + BOOST_TEST_TRAIT_TRUE((is_sequence_of_any_axis<decltype(v)>)); + } + + // has_operator_equal + { + struct A {}; + struct B { + bool operator==(const B&) const { return true; } + }; + + BOOST_TEST_TRAIT_FALSE((has_operator_equal<A, A>)); + BOOST_TEST_TRAIT_FALSE((has_operator_equal<B, A>)); + BOOST_TEST_TRAIT_TRUE((has_operator_equal<B, B>)); + BOOST_TEST_TRAIT_TRUE((has_operator_equal<const B&, const B&>)); + } + + // has_operator_radd + { + struct A {}; + struct B { + B& operator+=(const B&) { return *this; } + }; + + BOOST_TEST_TRAIT_FALSE((has_operator_radd<A, A>)); + BOOST_TEST_TRAIT_FALSE((has_operator_radd<B, A>)); + BOOST_TEST_TRAIT_TRUE((has_operator_radd<B, B>)); + BOOST_TEST_TRAIT_TRUE((has_operator_radd<B&, const B&>)); + } + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/detail_iterator_adaptor_test.cpp b/src/boost/libs/histogram/test/detail_iterator_adaptor_test.cpp new file mode 100644 index 00000000..c7a3303d --- /dev/null +++ b/src/boost/libs/histogram/test/detail_iterator_adaptor_test.cpp @@ -0,0 +1,191 @@ +// (C) Copyright Thomas Witt 2003. +// (C) Copyright Hans Dembinski 2019. + +// 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) + +// See http://www.boost.org for most recent version including documentation. + +#include <boost/core/lightweight_test.hpp> +#include <boost/core/lightweight_test_trait.hpp> +#include <boost/histogram/detail/detect.hpp> +#include <boost/histogram/detail/iterator_adaptor.hpp> +#include "std_ostream.hpp" +#include "utility_iterator.hpp" + +#include <deque> +#include <set> +#include <vector> + +using namespace boost::histogram; +using boost::histogram::detail::iterator_adaptor; + +typedef std::deque<int> storage; +typedef std::deque<int*> pointer_deque; +typedef std::set<storage::iterator> iterator_set; + +template <class T> +struct foo; + +void blah(int) {} + +struct my_gen { + typedef int result_type; + my_gen() : n(0) {} + int operator()() { return ++n; } + int n; +}; + +template <class V> +struct ptr_iterator : iterator_adaptor<ptr_iterator<V>, V*> { +private: + typedef iterator_adaptor<ptr_iterator<V>, V*> super_t; + +public: + using base_type = typename super_t::base_type; + + ptr_iterator() {} + ptr_iterator(V* d) : super_t(d) {} + + template <class V2, class = detail::requires_convertible<V2*, V*>> + ptr_iterator(const ptr_iterator<V2>& x) : super_t(x.base()) {} + + V& operator*() const { return *(this->base()); } +}; + +template <class Iter> +struct constant_iterator + : iterator_adaptor<constant_iterator<Iter>, Iter, + typename std::iterator_traits<Iter>::value_type const&> { + typedef iterator_adaptor<constant_iterator<Iter>, Iter, + typename std::iterator_traits<Iter>::value_type const&> + base_t; + + constant_iterator() {} + constant_iterator(Iter it) : base_t(it) {} + + typename std::iterator_traits<Iter>::value_type const& operator*() const { + this->base().operator*(); + } +}; + +struct mutable_it : iterator_adaptor<mutable_it, int*> { + typedef iterator_adaptor<mutable_it, int*> super_t; + + mutable_it(); + explicit mutable_it(int* p) : super_t(p) {} + + bool equal(mutable_it const& rhs) const { return this->base() == rhs.base(); } +}; + +struct constant_it : iterator_adaptor<constant_it, int const*> { + typedef iterator_adaptor<constant_it, int const*> super_t; + + constant_it(); + explicit constant_it(int* p) : super_t(p) {} + constant_it(mutable_it const& x) : super_t(x.base()) {} + + bool equal(constant_it const& rhs) const { return this->base() == rhs.base(); } +}; + +template <class T> +class static_object { +public: + static T& get() { + static char d[sizeof(T)]; + return *reinterpret_cast<T*>(d); + } +}; + +int main() { + dummyT array[] = {dummyT(0), dummyT(1), dummyT(2), dummyT(3), dummyT(4), dummyT(5)}; + const int N = sizeof(array) / sizeof(dummyT); + + // Test the iterator_adaptor + { + ptr_iterator<dummyT> i(array); + using reference = typename std::iterator_traits<ptr_iterator<dummyT>>::reference; + using pointer = typename std::iterator_traits<ptr_iterator<dummyT>>::pointer; + BOOST_TEST_TRAIT_SAME(reference, dummyT&); + BOOST_TEST_TRAIT_SAME(pointer, dummyT*); + + random_access_iterator_test(i, N, array); + + ptr_iterator<const dummyT> j(array); + random_access_iterator_test(j, N, array); + const_nonconst_iterator_test(i, ++j); + } + + // Test the iterator_traits + { + // Test computation of defaults + typedef ptr_iterator<int> Iter1; + // don't use std::iterator_traits here to avoid VC++ problems + BOOST_TEST_TRAIT_SAME(Iter1::value_type, int); + BOOST_TEST_TRAIT_SAME(Iter1::reference, int&); + BOOST_TEST_TRAIT_SAME(Iter1::pointer, int*); + BOOST_TEST_TRAIT_SAME(Iter1::difference_type, std::ptrdiff_t); + } + + { + // Test computation of default when the Value is const + typedef ptr_iterator<int const> Iter1; + BOOST_TEST_TRAIT_SAME(Iter1::value_type, int); + BOOST_TEST_TRAIT_SAME(Iter1::reference, const int&); + BOOST_TEST_TRAIT_SAME(Iter1::pointer, int const*); + } + + { + // Test constant iterator idiom + typedef ptr_iterator<int> BaseIter; + typedef constant_iterator<BaseIter> Iter; + + BOOST_TEST_TRAIT_SAME(Iter::value_type, int); + BOOST_TEST_TRAIT_SAME(Iter::reference, int const&); + BOOST_TEST_TRAIT_SAME(Iter::pointer, int const*); + } + + // Test the iterator_adaptor + { + ptr_iterator<dummyT> i(array); + random_access_iterator_test(i, N, array); + + ptr_iterator<const dummyT> j(array); + random_access_iterator_test(j, N, array); + const_nonconst_iterator_test(i, ++j); + } + + // check that base_type is correct + { + // Test constant iterator idiom + typedef ptr_iterator<int> BaseIter; + + BOOST_TEST_TRAIT_SAME(BaseIter::base_type, int*); + BOOST_TEST_TRAIT_SAME(constant_iterator<BaseIter>::base_type, BaseIter); + } + + { + int data[] = {49, 77}; + + mutable_it i(data); + constant_it j(data + 1); + BOOST_TEST(i < j); + BOOST_TEST(j > i); + BOOST_TEST(i <= j); + BOOST_TEST(j >= i); + BOOST_TEST(j - i == 1); + BOOST_TEST(i - j == -1); + + constant_it k = i; + + BOOST_TEST(!(i < k)); + BOOST_TEST(!(k > i)); + BOOST_TEST(i <= k); + BOOST_TEST(k >= i); + BOOST_TEST(k - i == 0); + BOOST_TEST(i - k == 0); + } + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/detail_large_int_test.cpp b/src/boost/libs/histogram/test/detail_large_int_test.cpp new file mode 100644 index 00000000..7e50fcef --- /dev/null +++ b/src/boost/libs/histogram/test/detail_large_int_test.cpp @@ -0,0 +1,206 @@ +// Copyright 2018-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/core/lightweight_test.hpp> +#include <boost/histogram/detail/large_int.hpp> +#include <cstdint> +#include <iosfwd> +#include <limits> +#include "std_ostream.hpp" + +namespace boost { +namespace histogram { +namespace detail { +template <class Allocator> +std::ostream& operator<<(std::ostream& os, const large_int<Allocator>& x) { + os << "large_int" << x.data; + return os; +} +} // namespace detail +} // namespace histogram +} // namespace boost + +using namespace boost::histogram; + +using large_int = detail::large_int<std::allocator<std::uint64_t>>; + +template <class... Ts> +auto make_large_int(Ts... ts) { + large_int r; + r.data = {static_cast<uint64_t>(ts)...}; + return r; +} + +int main() { + // low-level tools + { + uint8_t c = 0; + BOOST_TEST_EQ(detail::safe_increment(c), true); + BOOST_TEST_EQ(c, 1); + c = 255; + BOOST_TEST_EQ(detail::safe_increment(c), false); + BOOST_TEST_EQ(c, 255); + c = 0; + BOOST_TEST_EQ(detail::safe_radd(c, 255u), true); + BOOST_TEST_EQ(c, 255); + c = 1; + BOOST_TEST_EQ(detail::safe_radd(c, 255u), false); + BOOST_TEST_EQ(c, 1); + c = 255; + BOOST_TEST_EQ(detail::safe_radd(c, 1u), false); + BOOST_TEST_EQ(c, 255); + } + + const auto vmax = (std::numeric_limits<std::uint64_t>::max)(); + + // ctors, assign + { + large_int a(42); + large_int b(a); + BOOST_TEST_EQ(b.data.front(), 42); + large_int c(std::move(b)); + BOOST_TEST_EQ(c.data.front(), 42); + large_int d, e; + d = a; + BOOST_TEST_EQ(d.data.front(), 42); + e = std::move(c); + BOOST_TEST_EQ(e.data.front(), 42); + } + + // comparison + { + BOOST_TEST_EQ(large_int(), 0u); + BOOST_TEST_EQ(large_int(1u), 1u); + BOOST_TEST_EQ(large_int(1u), 1.0); + BOOST_TEST_EQ(large_int(1u), large_int(1u)); + BOOST_TEST_NE(large_int(1u), 2u); + BOOST_TEST_NE(large_int(1u), 2.0); + BOOST_TEST_NE(large_int(1u), 2.0f); + BOOST_TEST_NE(large_int(1u), large_int(2u)); + BOOST_TEST_LT(large_int(1u), 2u); + BOOST_TEST_LT(large_int(1u), 2.0); + BOOST_TEST_LT(large_int(1u), 2.0f); + BOOST_TEST_LT(large_int(1u), large_int(2u)); + BOOST_TEST_LE(large_int(1u), 2u); + BOOST_TEST_LE(large_int(1u), 2.0); + BOOST_TEST_LE(large_int(1u), 2.0f); + BOOST_TEST_LE(large_int(1u), large_int(2u)); + BOOST_TEST_LE(large_int(1u), 1u); + BOOST_TEST_GT(large_int(1u), 0u); + BOOST_TEST_GT(large_int(1u), 0.0); + BOOST_TEST_GT(large_int(1u), 0.0f); + BOOST_TEST_GT(large_int(1u), large_int(0u)); + BOOST_TEST_GE(large_int(1u), 0u); + BOOST_TEST_GE(large_int(1u), 0.0); + BOOST_TEST_GE(large_int(1u), 0.0f); + BOOST_TEST_GE(large_int(1u), 1u); + BOOST_TEST_GE(large_int(1u), large_int(0u)); + BOOST_TEST_NOT(large_int(1u) < large_int(1u)); + BOOST_TEST_NOT(large_int(1u) > large_int(1u)); + + BOOST_TEST_GT(1, large_int()); + BOOST_TEST_LT(-1, large_int()); + BOOST_TEST_GE(1, large_int()); + BOOST_TEST_LE(-1, large_int()); + BOOST_TEST_NE(1, large_int()); + + constexpr auto nan = std::numeric_limits<double>::quiet_NaN(); + BOOST_TEST_NOT(large_int(1u) < nan); + BOOST_TEST_NOT(large_int(1u) > nan); + BOOST_TEST_NOT(large_int(1u) == nan); + BOOST_TEST(large_int(1u) != nan); // same behavior as int compared to nan + BOOST_TEST_NOT(large_int(1u) <= nan); + BOOST_TEST_NOT(large_int(1u) >= nan); + + BOOST_TEST_NOT(nan < large_int(1u)); + BOOST_TEST_NOT(nan > large_int(1u)); + BOOST_TEST_NOT(nan == large_int(1u)); + BOOST_TEST(nan != large_int(1u)); // same behavior as int compared to nan + BOOST_TEST_NOT(nan <= large_int(1u)); + BOOST_TEST_NOT(nan >= large_int(1u)); + } + + // increment + { + auto a = large_int(); + ++a; + BOOST_TEST_EQ(a.data.size(), 1); + BOOST_TEST_EQ(a.data[0], 1); + ++a; + BOOST_TEST_EQ(a.data[0], 2); + a = vmax; + BOOST_TEST_EQ(a, vmax); + BOOST_TEST_EQ(a, static_cast<double>(vmax)); + ++a; + BOOST_TEST_EQ(a, make_large_int(0, 1)); + ++a; + BOOST_TEST_EQ(a, make_large_int(1, 1)); + a += a; + BOOST_TEST_EQ(a, make_large_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_large_int(0, 2)); + // carry once B + a.data[0] = vmax; + a.data[1] = 1; + a += 1; + BOOST_TEST_EQ(a, make_large_int(0, 2)); + // carry once C + a.data[0] = vmax; + a.data[1] = 1; + a += make_large_int(1, 1); + BOOST_TEST_EQ(a, make_large_int(0, 3)); + + a.data[0] = vmax - 1; + a.data[1] = vmax; + ++a; + BOOST_TEST_EQ(a, make_large_int(vmax, vmax)); + + // carry two times A + ++a; + BOOST_TEST_EQ(a, make_large_int(0, 0, 1)); + // carry two times B + a = make_large_int(vmax, vmax); + a += 1; + BOOST_TEST_EQ(a, make_large_int(0, 0, 1)); + // carry two times C + a = make_large_int(vmax, vmax); + a += large_int(1); + BOOST_TEST_EQ(a, make_large_int(0, 0, 1)); + + // carry and enlarge + a = make_large_int(vmax, vmax); + a += a; + BOOST_TEST_EQ(a, make_large_int(vmax - 1, vmax, 1)); + + // add smaller to larger + a = make_large_int(1, 1, 1); + a += make_large_int(1, 1); + BOOST_TEST_EQ(a, make_large_int(2, 2, 1)); + + // add larger to smaller + a = make_large_int(1, 1); + a += make_large_int(1, 1, 1); + BOOST_TEST_EQ(a, make_large_int(2, 2, 1)); + + a = large_int(1); + auto b = 1.0; + BOOST_TEST_EQ(a, b); + for (unsigned i = 0; i < 80; ++i) { + b += b; + BOOST_TEST_NE(a, b); + a += a; + BOOST_TEST_EQ(a, b); + } + BOOST_TEST_GT(a.data.size(), 1u); + } + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/detail_limits_test.cpp b/src/boost/libs/histogram/test/detail_limits_test.cpp new file mode 100644 index 00000000..dc0d0417 --- /dev/null +++ b/src/boost/libs/histogram/test/detail_limits_test.cpp @@ -0,0 +1,24 @@ +// Copyright 2015-2017 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/core/lightweight_test.hpp> +#include <boost/histogram/detail/limits.hpp> +#include <limits> + +using namespace boost::histogram::detail; + +int main() { + + BOOST_TEST_EQ(lowest<int>(), (std::numeric_limits<int>::min)()); + BOOST_TEST_EQ(lowest<float>(), -std::numeric_limits<float>::infinity()); + BOOST_TEST_EQ(lowest<double>(), -std::numeric_limits<double>::infinity()); + + BOOST_TEST_EQ(highest<int>(), (std::numeric_limits<int>::max)()); + BOOST_TEST_EQ(highest<float>(), std::numeric_limits<float>::infinity()); + BOOST_TEST_EQ(highest<double>(), std::numeric_limits<double>::infinity()); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/detail_make_default_test.cpp b/src/boost/libs/histogram/test/detail_make_default_test.cpp new file mode 100644 index 00000000..3488cf28 --- /dev/null +++ b/src/boost/libs/histogram/test/detail_make_default_test.cpp @@ -0,0 +1,57 @@ +// Copyright 2015-2017 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/core/lightweight_test.hpp> +#include <boost/histogram/detail/make_default.hpp> +#include <new> +#include <vector> + +using namespace boost::histogram::detail; + +template <class T> +struct allocator_with_state { + using value_type = T; + + allocator_with_state(int s = 0) : state(s) {} + + template <class U> + allocator_with_state(const allocator_with_state<U>& o) : state(o.state) {} + + value_type* allocate(std::size_t n) { + return static_cast<value_type*>(::operator new(n * sizeof(T))); + } + void deallocate(value_type* ptr, std::size_t) { + ::operator delete(static_cast<void*>(ptr)); + } + + template <class U> + bool operator==(const allocator_with_state<U>&) const { + return true; + } + + template <class U> + bool operator!=(const allocator_with_state<U>&) const { + return false; + } + + int state; +}; + +int main() { + + using V = std::vector<int, allocator_with_state<int>>; + V a(3, 0, allocator_with_state<int>{42}); + V b = make_default(a); + V c; + BOOST_TEST_EQ(a.size(), 3); + BOOST_TEST_EQ(b.size(), 0); + BOOST_TEST_EQ(c.size(), 0); + BOOST_TEST_EQ(a.get_allocator().state, 42); + BOOST_TEST_EQ(b.get_allocator().state, 42); + BOOST_TEST_EQ(c.get_allocator().state, 0); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/detail_misc_test.cpp b/src/boost/libs/histogram/test/detail_misc_test.cpp new file mode 100644 index 00000000..abebe783 --- /dev/null +++ b/src/boost/libs/histogram/test/detail_misc_test.cpp @@ -0,0 +1,88 @@ +// Copyright 2015-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/core/lightweight_test.hpp> +#include <boost/core/lightweight_test_trait.hpp> +#include <boost/histogram/accumulators/weighted_sum.hpp> +#include <boost/histogram/detail/common_type.hpp> +#include <boost/histogram/detail/counting_streambuf.hpp> +#include <boost/histogram/detail/non_member_container_access.hpp> +#include <boost/histogram/fwd.hpp> +#include <boost/histogram/literals.hpp> +#include <boost/histogram/storage_adaptor.hpp> +#include <boost/histogram/unlimited_storage.hpp> +#include <ostream> +#include "std_ostream.hpp" + +using namespace boost::histogram; +using namespace boost::histogram::literals; +namespace dtl = boost::histogram::detail; + +int main() { + // literals + { + BOOST_TEST_TRAIT_SAME(std::integral_constant<unsigned, 0>, decltype(0_c)); + BOOST_TEST_TRAIT_SAME(std::integral_constant<unsigned, 3>, decltype(3_c)); + BOOST_TEST_EQ(decltype(10_c)::value, 10); + BOOST_TEST_EQ(decltype(213_c)::value, 213); + } + + // common_storage + { + BOOST_TEST_TRAIT_SAME(dtl::common_storage<unlimited_storage<>, unlimited_storage<>>, + unlimited_storage<>); + BOOST_TEST_TRAIT_SAME( + dtl::common_storage<dense_storage<double>, dense_storage<double>>, + dense_storage<double>); + BOOST_TEST_TRAIT_SAME(dtl::common_storage<dense_storage<int>, dense_storage<double>>, + dense_storage<double>); + BOOST_TEST_TRAIT_SAME(dtl::common_storage<dense_storage<double>, dense_storage<int>>, + dense_storage<double>); + BOOST_TEST_TRAIT_SAME(dtl::common_storage<dense_storage<double>, unlimited_storage<>>, + dense_storage<double>); + BOOST_TEST_TRAIT_SAME(dtl::common_storage<dense_storage<int>, unlimited_storage<>>, + unlimited_storage<>); + BOOST_TEST_TRAIT_SAME(dtl::common_storage<dense_storage<double>, weight_storage>, + weight_storage); + } + + // size & data + { + char a[4] = {1, 2, 3, 4}; + BOOST_TEST_EQ(dtl::size(a), 4u); + BOOST_TEST_EQ(dtl::data(a), a); + auto b = {1, 2}; + BOOST_TEST_EQ(dtl::size(b), 2u); + BOOST_TEST_EQ(dtl::data(b), b.begin()); + struct C { + unsigned size() const { return 3; } + int* data() { return buf; } + const int* data() const { return buf; } + int buf[1]; + } c; + BOOST_TEST_EQ(dtl::size(c), 3u); + BOOST_TEST_EQ(dtl::data(c), c.buf); + BOOST_TEST_EQ(dtl::data(static_cast<const C&>(c)), c.buf); + struct { + int size() const { return 5; } + } d; + BOOST_TEST_EQ(dtl::size(d), 5u); + } + + // counting_streambuf + { + dtl::counting_streambuf<char> cbuf; + std::ostream os(&cbuf); + os.put('x'); + BOOST_TEST_EQ(cbuf.count, 1); + os << 12; + BOOST_TEST_EQ(cbuf.count, 3); + os << "123"; + BOOST_TEST_EQ(cbuf.count, 6); + } + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/detail_operators_test.cpp b/src/boost/libs/histogram/test/detail_operators_test.cpp new file mode 100644 index 00000000..9fee2b33 --- /dev/null +++ b/src/boost/libs/histogram/test/detail_operators_test.cpp @@ -0,0 +1,143 @@ +// 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/core/lightweight_test.hpp> +#include <boost/core/lightweight_test_trait.hpp> +#include <boost/histogram/detail/operators.hpp> +#include <limits> +#include <ostream> + +using namespace boost::histogram::detail; + +struct TotallyOrdered : totally_ordered<TotallyOrdered, TotallyOrdered, void> { + TotallyOrdered(int i) : x(i) {} + + bool operator<(const TotallyOrdered& o) const noexcept { return x < o.x; } + bool operator==(const TotallyOrdered& o) const noexcept { return x == o.x; } + bool operator<(const int& o) const noexcept { return x < o; } + bool operator>(const int& o) const noexcept { return x > o; } + bool operator==(const int& o) const noexcept { return x == o; } + + int x; +}; + +std::ostream& operator<<(std::ostream& os, const TotallyOrdered& t) { + os << t.x; + return os; +} + +struct PartiallyOrdered : partially_ordered<PartiallyOrdered, PartiallyOrdered, void> { + PartiallyOrdered(double i) : x(i) {} + + bool operator<(const PartiallyOrdered& o) const noexcept { return x < o.x; } + bool operator==(const PartiallyOrdered& o) const noexcept { return x == o.x; } + bool operator<(const double& o) const noexcept { return x < o; } + bool operator>(const double& o) const noexcept { return x > o; } + bool operator==(const double& o) const noexcept { return x == o; } + + double x; +}; + +std::ostream& operator<<(std::ostream& os, const PartiallyOrdered& t) { + os << t.x; + return os; +} + +template <class T, class U> +void test_nan(std::false_type) {} + +template <class T, class U> +void test_nan(std::true_type) { + const U nan = std::numeric_limits<U>::quiet_NaN(); + + // IEEE 754: Any comparison with nan is false, except != which is true. + // But some of the following tests fail on MSVC: + // BOOST_TEST_NOT(nan < nan); // true, should be false + // BOOST_TEST_NOT(nan > nan); + // BOOST_TEST_NOT(nan == nan); + // BOOST_TEST_NOT(nan <= nan); // true, should be false + // BOOST_TEST_NOT(nan >= nan); + // BOOST_TEST(nan != nan); + // Probably related: + // https://developercommunity.visualstudio.com/content/problem/445462/nan-nan-is-constant-folded-to-true-but-should-prob.html + // The tests below don't fail probably because constant-folding doesn't happen. + + BOOST_TEST_NOT(T(1.0) < T(nan)); + BOOST_TEST_NOT(T(1.0) > T(nan)); + BOOST_TEST_NOT(T(1.0) == T(nan)); + BOOST_TEST_NOT(T(1.0) <= T(nan)); + BOOST_TEST_NOT(T(1.0) >= T(nan)); + BOOST_TEST(T(1.0) != T(nan)); + + BOOST_TEST_NOT(T(nan) < 1.0); + BOOST_TEST_NOT(T(nan) > 1.0); + BOOST_TEST_NOT(T(nan) == 1.0); + BOOST_TEST_NOT(T(nan) <= 1.0); + BOOST_TEST_NOT(T(nan) >= 1.0); + BOOST_TEST(T(nan) != 1.0); + + BOOST_TEST_NOT(1.0 < T(nan)); + BOOST_TEST_NOT(1.0 > T(nan)); + BOOST_TEST_NOT(1.0 == T(nan)); + BOOST_TEST_NOT(1.0 <= T(nan)); + BOOST_TEST_NOT(1.0 >= T(nan)); + BOOST_TEST(1.0 != T(nan)); + + BOOST_TEST_NOT(T(nan) < T(nan)); + BOOST_TEST_NOT(T(nan) > T(nan)); + BOOST_TEST_NOT(T(nan) == T(nan)); + BOOST_TEST_NOT(T(nan) <= T(nan)); + BOOST_TEST_NOT(T(nan) >= T(nan)); + BOOST_TEST(T(nan) != T(nan)); + + BOOST_TEST_NOT(T(nan) < nan); + BOOST_TEST_NOT(T(nan) > nan); + BOOST_TEST_NOT(T(nan) == nan); + BOOST_TEST_NOT(T(nan) <= nan); + BOOST_TEST_NOT(T(nan) >= nan); + BOOST_TEST(T(nan) != nan); + + BOOST_TEST_NOT(nan < T(nan)); + BOOST_TEST_NOT(nan > T(nan)); + BOOST_TEST_NOT(nan == T(nan)); + BOOST_TEST_NOT(nan <= T(nan)); + BOOST_TEST_NOT(nan >= T(nan)); + BOOST_TEST(nan != T(nan)); +} + +template <class T, class U> +void test() { + T x{1}; + U e{1}, l{0}, u{2}; + BOOST_TEST_EQ(x, e); + BOOST_TEST_NE(x, l); + BOOST_TEST_LT(x, u); + BOOST_TEST_GT(x, l); + BOOST_TEST_LE(x, e); + BOOST_TEST_LE(x, u); + BOOST_TEST_GE(x, e); + BOOST_TEST_GE(x, l); + + BOOST_TEST_EQ(e, x); + BOOST_TEST_NE(l, x); + BOOST_TEST_LT(l, x); + BOOST_TEST_GT(u, x); + BOOST_TEST_LE(e, x); + BOOST_TEST_LE(l, x); + BOOST_TEST_GE(e, x); + BOOST_TEST_GE(u, x); + + test_nan<T, U>(std::is_floating_point<U>{}); +} + +int main() { + test<TotallyOrdered, TotallyOrdered>(); + test<TotallyOrdered, int>(); + test<PartiallyOrdered, PartiallyOrdered>(); + test<PartiallyOrdered, double>(); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/detail_relaxed_equal_test.cpp b/src/boost/libs/histogram/test/detail_relaxed_equal_test.cpp new file mode 100644 index 00000000..bba643e8 --- /dev/null +++ b/src/boost/libs/histogram/test/detail_relaxed_equal_test.cpp @@ -0,0 +1,27 @@ +// Copyright 2015-2017 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/core/lightweight_test.hpp> +#include <boost/core/lightweight_test_trait.hpp> +#include <boost/histogram/detail/relaxed_equal.hpp> +#include "std_ostream.hpp" + +using namespace boost::histogram::detail; + +int main() { + struct A {}; + A a, b; + + struct B { + bool operator==(const B&) const { return false; } + }; + B c, d; + + BOOST_TEST(relaxed_equal(a, b)); + BOOST_TEST_NOT(relaxed_equal(c, d)); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/detail_replace_type_test.cpp b/src/boost/libs/histogram/test/detail_replace_type_test.cpp new file mode 100644 index 00000000..6318e11f --- /dev/null +++ b/src/boost/libs/histogram/test/detail_replace_type_test.cpp @@ -0,0 +1,22 @@ +// Copyright 2015-2017 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/core/lightweight_test.hpp> +#include <boost/core/lightweight_test_trait.hpp> +#include <boost/histogram/detail/replace_type.hpp> +#include "std_ostream.hpp" + +using namespace boost::histogram::detail; + +int main() { + + BOOST_TEST_TRAIT_SAME(replace_type<long, char, int>, long); + BOOST_TEST_TRAIT_SAME(replace_type<char, char, int>, int); + BOOST_TEST_TRAIT_SAME(replace_default<boost::use_default, char>, char); + BOOST_TEST_TRAIT_SAME(replace_default<int, char>, int); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/detail_safe_comparison_test.cpp b/src/boost/libs/histogram/test/detail_safe_comparison_test.cpp new file mode 100644 index 00000000..57f0f4d7 --- /dev/null +++ b/src/boost/libs/histogram/test/detail_safe_comparison_test.cpp @@ -0,0 +1,60 @@ +// Copyright 2018-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/core/lightweight_test.hpp> +#include <boost/histogram/detail/safe_comparison.hpp> + +using namespace boost::histogram::detail; + +int main() { + auto eq = safe_equal{}; + BOOST_TEST(eq(-1, -1)); + BOOST_TEST(eq(1, 1u)); + BOOST_TEST(eq(1u, 1)); + BOOST_TEST(eq(1u, 1u)); + BOOST_TEST(eq(1.0, 1)); + BOOST_TEST(eq(1, 1.0)); + BOOST_TEST(eq(1.0, 1u)); + BOOST_TEST(eq(1u, 1.0)); + BOOST_TEST_NOT(eq(-1, static_cast<unsigned>(-1))); + BOOST_TEST_NOT(eq(static_cast<unsigned>(-1), -1)); + + auto lt = safe_less{}; + BOOST_TEST(lt(1u, 2u)); + BOOST_TEST(lt(-1, 1u)); + BOOST_TEST(lt(1u, 2)); + BOOST_TEST(lt(-2, -1)); + BOOST_TEST(lt(-2.0, -1)); + BOOST_TEST(lt(1, 2.0)); + BOOST_TEST(lt(-1.0, 1u)); + BOOST_TEST(lt(1u, 2.0)); + BOOST_TEST(lt(1.0, 2.0)); + BOOST_TEST_NOT(lt(1u, 1)); + BOOST_TEST_NOT(lt(1, 1u)); + BOOST_TEST_NOT(lt(1.0, 1)); + BOOST_TEST_NOT(lt(1, 1.0)); + BOOST_TEST_NOT(lt(1.0, 1u)); + BOOST_TEST_NOT(lt(1u, 1.0)); + BOOST_TEST_NOT(lt(1.0, 1.0)); + + auto gt = safe_greater{}; + BOOST_TEST(gt(2u, 1u)); + BOOST_TEST(gt(1u, -1)); + BOOST_TEST(gt(2, 1u)); + BOOST_TEST(gt(-1, -2)); + BOOST_TEST(gt(-1, -2.0)); + BOOST_TEST(gt(2.0, 1)); + BOOST_TEST(gt(1u, -1.0)); + BOOST_TEST(gt(2.0, 1u)); + BOOST_TEST_NOT(gt(1u, 1)); + BOOST_TEST_NOT(gt(1, 1u)); + BOOST_TEST_NOT(gt(1.0, 1)); + BOOST_TEST_NOT(gt(1, 1.0)); + BOOST_TEST_NOT(gt(1.0, 1u)); + BOOST_TEST_NOT(gt(1u, 1.0)); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/detail_static_if_test.cpp b/src/boost/libs/histogram/test/detail_static_if_test.cpp new file mode 100644 index 00000000..d25d7ed7 --- /dev/null +++ b/src/boost/libs/histogram/test/detail_static_if_test.cpp @@ -0,0 +1,33 @@ +// Copyright 2015-2017 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/core/lightweight_test.hpp> +#include <boost/histogram/detail/static_if.hpp> +#include "throw_exception.hpp" + +using namespace boost::histogram::detail; + +int main() { + using T = std::true_type; + using F = std::false_type; + + // check that branch not taken does not have to compile + BOOST_TEST_EQ(static_if<T>([](auto) { return 1; }, [] {}, 0), 1); + BOOST_TEST_EQ(static_if<F>([] {}, [](auto) { return 1; }, 0), 1); + + BOOST_TEST_EQ(static_if_c<true>([](auto) { return 1; }, [] {}, 0), 1); + BOOST_TEST_EQ(static_if_c<false>([] {}, [](auto) { return 1; }, 0), 1); + + // check that noexcept is correctly propagated + auto may_throw = [](auto x) { return x; }; + auto no_throw = [](auto x) noexcept { return x; }; + + // make this work with -fno-exceptions + BOOST_TEST_EQ(noexcept(static_if<F>(no_throw, may_throw, 0)), noexcept(may_throw(0))); + BOOST_TEST(noexcept(static_if<T>(no_throw, may_throw, 0))); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/detail_tuple_slice_test.cpp b/src/boost/libs/histogram/test/detail_tuple_slice_test.cpp new file mode 100644 index 00000000..465e0f83 --- /dev/null +++ b/src/boost/libs/histogram/test/detail_tuple_slice_test.cpp @@ -0,0 +1,21 @@ +// Copyright 2015-2017 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/core/lightweight_test.hpp> +#include <boost/histogram/detail/tuple_slice.hpp> +#include <tuple> +#include "std_ostream.hpp" + +using namespace boost::histogram::detail; + +int main() { + + auto a = std::make_tuple(1, 2, 3, 4); + const auto b = tuple_slice<1, 2>(a); + BOOST_TEST_EQ(b, std::make_tuple(2, 3)); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/histogram_custom_axis_test.cpp b/src/boost/libs/histogram/test/histogram_custom_axis_test.cpp new file mode 100644 index 00000000..d31b3375 --- /dev/null +++ b/src/boost/libs/histogram/test/histogram_custom_axis_test.cpp @@ -0,0 +1,132 @@ +// Copyright 2018-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/core/lightweight_test.hpp> +#include <boost/histogram/accumulators/mean.hpp> +#include <boost/histogram/accumulators/weighted_mean.hpp> +#include <boost/histogram/axis.hpp> +#include <boost/histogram/axis/ostream.hpp> +#include <boost/histogram/histogram.hpp> +#include <boost/histogram/literals.hpp> +#include <boost/histogram/make_histogram.hpp> +#include <boost/histogram/ostream.hpp> +#include <boost/histogram/storage_adaptor.hpp> +#include <sstream> +#include <stdexcept> +#include <tuple> +#include <utility> +#include <vector> +#include "throw_exception.hpp" +#include "utility_histogram.hpp" + +using namespace boost::histogram; + +struct modified_axis : public axis::integer<> { + using integer::integer; // inherit ctors of base + // customization point: convert argument and call base class + auto index(const char* s) const { return integer::index(std::atoi(s)); } +}; + +struct minimal { + auto index(int x) const { return static_cast<axis::index_type>(x % 2); } + auto size() const { return axis::index_type{2}; } +}; + +struct axis2d { + auto index(const std::tuple<double, double>& x) const { + return axis::index_type{std::get<0>(x) == 1 && std::get<1>(x) == 2}; + } + auto size() const { return axis::index_type{2}; } +}; + +class axis2d_growing { +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 <class Tag> +void run_tests() { + // one 2d axis + { + auto h = make(Tag(), axis2d()); + h(1, 2); // ok, forwards 2d tuple to axis + h(std::make_tuple(1, 2)); // also ok, forwards 2d tuple to axis + BOOST_TEST_THROWS(h(1), std::invalid_argument); + BOOST_TEST_THROWS(h(1, 2, 3), std::invalid_argument); + BOOST_TEST_EQ(h.at(0), 0); // ok, bin access is still 1d + BOOST_TEST_EQ(h[std::make_tuple(1)], 2); + // also works with weights + h(1, 2, weight(2)); + h(std::make_tuple(weight(3), 1, 2)); + BOOST_TEST_EQ(h.at(0), 0); + BOOST_TEST_EQ(h.at(1), 7); + + auto h2 = make_s(Tag(), profile_storage(), axis2d()); + h2(1, 2, sample(2)); + BOOST_TEST_EQ(h2[1].count(), 1); + BOOST_TEST_EQ(h2[1].value(), 2); + + auto h3 = make_s(Tag(), weighted_profile_storage(), axis2d()); + h3(1, 2, weight(3), sample(2)); + BOOST_TEST_EQ(h3[1].sum_of_weights(), 3); + BOOST_TEST_EQ(h3[1].value(), 2); + } + + // several axes, one 2d + { + auto h = make(Tag(), modified_axis(0, 3), minimal(), axis2d()); + h("0", 1, std::make_tuple(1.0, 2.0)); + h("1", 2, std::make_tuple(2.0, 1.0)); + + BOOST_TEST_EQ(h.rank(), 3); + BOOST_TEST_EQ(h.at(0, 0, 0), 0); + BOOST_TEST_EQ(h.at(0, 1, 1), 1); + BOOST_TEST_EQ(h.at(1, 0, 0), 1); + } + + // growing axis + { + auto h = make_s(Tag{}, std::vector<int>{}, axis2d_growing{}); + 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() { + run_tests<static_tag>(); + run_tests<dynamic_tag>(); + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/histogram_dynamic_test.cpp b/src/boost/libs/histogram/test/histogram_dynamic_test.cpp new file mode 100644 index 00000000..8200f94a --- /dev/null +++ b/src/boost/libs/histogram/test/histogram_dynamic_test.cpp @@ -0,0 +1,123 @@ +// Copyright 2015-2017 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 <algorithm> +#include <boost/core/ignore_unused.hpp> +#include <boost/core/lightweight_test.hpp> +#include <boost/histogram/axis.hpp> +#include <boost/histogram/axis/ostream.hpp> +#include <boost/histogram/histogram.hpp> +#include <boost/histogram/make_histogram.hpp> +#include <boost/histogram/ostream.hpp> +#include <cstdlib> +#include <limits> +#include <numeric> +#include <sstream> +#include <tuple> +#include <utility> +#include <vector> +#include "throw_exception.hpp" +#include "utility_histogram.hpp" + +using namespace boost::histogram; + +int main() { + // special stuff that only works with dynamic_tag + + // init with vector of axis and vector of axis::variant + { + using R = axis::regular<>; + using I = axis::integer<>; + using V = axis::variable<>; + + auto v = std::vector<axis::variant<R, I, V>>(); + v.emplace_back(R{4, -1, 1}); + v.emplace_back(I{1, 7}); + v.emplace_back(V{1, 2, 3}); + auto h = make_histogram(v.begin(), v.end()); + BOOST_TEST_EQ(h.rank(), 3); + BOOST_TEST_EQ(h.axis(0), v[0]); + BOOST_TEST_EQ(h.axis(1), v[1]); + BOOST_TEST_EQ(h.axis(2), v[2]); + + auto h2 = make_histogram_with(std::vector<int>(), v); + BOOST_TEST_EQ(h2.rank(), 3); + BOOST_TEST_EQ(h2.axis(0), v[0]); + BOOST_TEST_EQ(h2.axis(1), v[1]); + BOOST_TEST_EQ(h2.axis(2), v[2]); + + auto v2 = std::vector<R>(); + v2.emplace_back(10, 0, 1); + v2.emplace_back(20, 0, 2); + auto h3 = make_histogram(v2); + BOOST_TEST_EQ(h3.axis(0), v2[0]); + BOOST_TEST_EQ(h3.axis(1), v2[1]); + } + + // too many axes + { + using I = axis::integer<int, axis::null_type, axis::option::none_t>; + + // test edge case + auto av = std::vector<I>(BOOST_HISTOGRAM_DETAIL_AXES_LIMIT, I(0, 1)); + auto h = make_histogram(av); + auto inputs = std::vector<std::vector<int>>(BOOST_HISTOGRAM_DETAIL_AXES_LIMIT, + std::vector<int>(1, 0)); + h.fill(inputs); // should not crash + + auto bad = std::vector<I>(BOOST_HISTOGRAM_DETAIL_AXES_LIMIT + 1, I(0, 1)); + boost::ignore_unused(bad); + BOOST_TEST_THROWS((void)make_histogram(bad), std::invalid_argument); + } + + // bad fill + { + auto a = axis::integer<>(0, 1); + auto b = make(dynamic_tag(), a); + BOOST_TEST_THROWS(b(0, 0), std::invalid_argument); + auto c = make(dynamic_tag(), a, a); + BOOST_TEST_THROWS(c(0), std::invalid_argument); + auto d = make(dynamic_tag(), a); + BOOST_TEST_THROWS(d(std::string()), std::invalid_argument); + + struct axis2d { + auto index(const std::tuple<double, double>& x) const { + return axis::index_type{std::get<0>(x) == 1 && std::get<1>(x) == 2}; + } + auto size() const { return axis::index_type{2}; } + } e; + + auto f = make(dynamic_tag(), a, e); + BOOST_TEST_THROWS(f(0, 0, 0), std::invalid_argument); + BOOST_TEST_THROWS(f(0, std::make_tuple(0, 0), 1), std::invalid_argument); + } + + // bad at + { + auto h1 = make(dynamic_tag(), axis::integer<>(0, 2)); + h1(1); + BOOST_TEST_THROWS(h1.at(0, 0), std::invalid_argument); + BOOST_TEST_THROWS(h1.at(std::make_tuple(0, 0)), std::invalid_argument); + } + + // incompatible axis variant methods + { + auto c = make(dynamic_tag(), axis::category<std::string>({"A", "B"})); + BOOST_TEST_THROWS(c.axis().value(0), std::runtime_error); + } + + { + auto h = make_histogram(std::vector<axis::integer<>>(1, axis::integer<>(0, 3))); + h(0); + h(1); + h(2); + BOOST_TEST_EQ(h.at(0), 1); + BOOST_TEST_EQ(h.at(1), 1); + BOOST_TEST_EQ(h.at(2), 1); + } + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/histogram_fail0.cpp b/src/boost/libs/histogram/test/histogram_fail0.cpp new file mode 100644 index 00000000..f4ca4a4b --- /dev/null +++ b/src/boost/libs/histogram/test/histogram_fail0.cpp @@ -0,0 +1,20 @@ +// 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/integer.hpp> +#include <boost/histogram/make_histogram.hpp> + +int main() { + using namespace boost::histogram; + + auto h = make_histogram(axis::integer<>(0, 5)); + + // invalid sample argument + h(0, sample(1)); + + auto values = {0, 1}; + h.fill(values, sample(values)); // invalid sample argument +} diff --git a/src/boost/libs/histogram/test/histogram_fail1.cpp b/src/boost/libs/histogram/test/histogram_fail1.cpp new file mode 100644 index 00000000..5f175259 --- /dev/null +++ b/src/boost/libs/histogram/test/histogram_fail1.cpp @@ -0,0 +1,24 @@ +// 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/integer.hpp> +#include <boost/histogram/make_histogram.hpp> + +int main() { + using namespace boost::histogram; + + struct accumulator { + void operator()() {} + }; + + auto h = make_histogram_with(dense_storage<accumulator>(), axis::integer<>(0, 5)); + + // invalid weight argument + h(0, weight(1)); + + auto values = {0, 1}; + h.fill(values, weight(1)); +} diff --git a/src/boost/libs/histogram/test/histogram_fail2.cpp b/src/boost/libs/histogram/test/histogram_fail2.cpp new file mode 100644 index 00000000..29ffac1e --- /dev/null +++ b/src/boost/libs/histogram/test/histogram_fail2.cpp @@ -0,0 +1,25 @@ +// 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/integer.hpp> +#include <boost/histogram/make_profile.hpp> + +int main() { + using namespace boost::histogram; + + struct accumulator { + void operator()(double) {} + void operator()(weight_type<double>, double) {} + }; + + auto h = make_histogram_with(dense_storage<accumulator>(), axis::integer<>(0, 5)); + + // accumulator requires sample + h(0, weight(1)); + + auto values = {1, 2}; + h.fill(values, weight(1)); +} diff --git a/src/boost/libs/histogram/test/histogram_fail3.cpp b/src/boost/libs/histogram/test/histogram_fail3.cpp new file mode 100644 index 00000000..9ff53415 --- /dev/null +++ b/src/boost/libs/histogram/test/histogram_fail3.cpp @@ -0,0 +1,23 @@ +// 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/integer.hpp> +#include <boost/histogram/make_histogram.hpp> + +int main() { + struct accumulator { + void operator()(double) {} + }; + + using namespace boost::histogram; + auto h = make_histogram_with(dense_storage<accumulator>(), axis::integer<>(0, 5)); + + // wrong number of sample arguments + h(0, sample(1, 2)); + + auto values = {0, 1}; + h.fill(values, sample(values, values)); +} diff --git a/src/boost/libs/histogram/test/histogram_fail4.cpp b/src/boost/libs/histogram/test/histogram_fail4.cpp new file mode 100644 index 00000000..22686daa --- /dev/null +++ b/src/boost/libs/histogram/test/histogram_fail4.cpp @@ -0,0 +1,24 @@ +// 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/integer.hpp> +#include <boost/histogram/make_histogram.hpp> + +int main() { + using namespace boost::histogram; + + struct accumulator { + void operator()(std::string) {} + }; + + auto h = make_histogram_with(dense_storage<accumulator>(), axis::integer<>(0, 5)); + + // invalid weight argument + h(0, sample(1)); + + auto values = {1, 2}; + h.fill(values, sample(values)); +} diff --git a/src/boost/libs/histogram/test/histogram_fill_test.cpp b/src/boost/libs/histogram/test/histogram_fill_test.cpp new file mode 100644 index 00000000..55c5e100 --- /dev/null +++ b/src/boost/libs/histogram/test/histogram_fill_test.cpp @@ -0,0 +1,361 @@ +// 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 <array> +#include <boost/config.hpp> +#include <boost/core/ignore_unused.hpp> +#include <boost/core/lightweight_test.hpp> +#include <boost/histogram/accumulators.hpp> +#include <boost/histogram/accumulators/ostream.hpp> +#include <boost/histogram/algorithm/sum.hpp> +#include <boost/histogram/axis/category.hpp> +#include <boost/histogram/axis/integer.hpp> +#include <boost/histogram/axis/ostream.hpp> +#include <boost/histogram/histogram.hpp> +#include <boost/histogram/literals.hpp> +#include <boost/histogram/make_histogram.hpp> +#include <boost/histogram/ostream.hpp> +#include <boost/histogram/storage_adaptor.hpp> +#include <boost/variant2/variant.hpp> +#include <random> +#include <sstream> +#include <stdexcept> +#include <tuple> +#include <utility> +#include <vector> +#include "throw_exception.hpp" +#include "utility_histogram.hpp" + +using namespace boost::histogram; +using namespace boost::histogram::algorithm; +using namespace boost::histogram::literals; // to get _c suffix +using boost::variant2::variant; + +constexpr auto ndata = 1 << 16; // should be larger than index buffer in fill_n + +using in = axis::integer<int, axis::null_type>; +using in0 = axis::integer<int, axis::null_type, axis::option::none_t>; +using ing = axis::integer<double, axis::null_type, + decltype(axis::option::growth | axis::option::underflow | + axis::option::overflow)>; +using cs = axis::category<std::string, axis::null_type>; +using csg = axis::category<std::string, axis::null_type, axis::option::growth_t>; + +struct axis2d { + auto size() const { return axis::index_type{2}; } + + auto index(const 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()); + } + + friend std::ostream& operator<<(std::ostream& os, const axis2d&) { + os << "axis2d()"; + return os; + } +}; + +template <class Tag> +void run_tests(const std::vector<int>& x, const std::vector<int>& y, + const std::vector<double>& w) { + + // 1D simple A + { + auto h = make(Tag(), in{1, 3}); + auto h2 = h; + for (auto&& xi : x) h(xi); + // uses 1D specialization + h2.fill(x); + BOOST_TEST_EQ(h, h2); + } + + // 1D simple B + { + auto h = make(Tag(), in{1, 3}); + auto h2 = h; + for (auto&& xi : x) h(xi); + // uses generic form + const auto vx = {x}; + h2.fill(vx); + BOOST_TEST_EQ(h, h2); + } + + // 1D simple C + { + auto h = make(Tag(), in{1, 3}); + auto h2 = h; + h(1); + for (auto&& xi : x) h(xi); + // uses variant + boost::variant2::variant<int, std::vector<int>, std::string> v[1]; + v[0] = 1; + h2.fill(v); + v[0] = x; + h2.fill(v); + BOOST_TEST_EQ(h, h2); + } + + // 1D bad arguments + { + auto h = make(Tag(), in{1, 3}); + + int bad1[2][4]; + boost::ignore_unused(bad1); + BOOST_TEST_THROWS(h.fill(bad1), std::invalid_argument); + + std::vector<std::array<int, 4>> bad2; + boost::ignore_unused(bad2); + BOOST_TEST_THROWS(h.fill(bad2), std::invalid_argument); + } + + // 1D with category axis + { + auto h = make(Tag(), cs{"A", "B"}); + auto h2 = h; + + const auto s = {"A", "B", "C"}; + for (auto&& si : s) h(si); + h2.fill(s); + + variant<int, std::string, std::vector<std::string>> v[1]; + h("B"); + v[0] = "B"; + h2.fill(v); + + v[0] = std::vector<std::string>(s.begin(), s.end()); + for (auto&& si : s) h(si); + h2.fill(v); + + BOOST_TEST_EQ(h, h2); + } + + // 1D weight + { + auto h = make(Tag(), in{1, 3}); + auto h2 = h; + + for (auto&& xi : x) h(weight(2), xi); + h2.fill(weight(2), x); + + for (unsigned i = 0; i < ndata; ++i) h(weight(w[i]), x[i]); + h2.fill(weight(w), x); + + BOOST_TEST_EQ(h, h2); + + auto w2 = {1}; + boost::ignore_unused(w2); + BOOST_TEST_THROWS(h2.fill(x, weight(w2)), std::invalid_argument); + } + + // 2D simple + { + auto h = make(Tag(), in{1, 3}, in0{1, 5}); + auto h2 = h; + + for (int i = 0; i < ndata; ++i) h(x[i], y[i]); + const auto xy = {x, y}; + h2.fill(xy); + + BOOST_TEST_EQ(h, h2); + + // wrong rank + BOOST_TEST_THROWS(h.fill(x), std::invalid_argument); + + // not rectangular + std::array<std::vector<int>, 2> bad = {{std::vector<int>(1), std::vector<int>(2)}}; + boost::ignore_unused(bad); + BOOST_TEST_THROWS(h2.fill(bad), std::invalid_argument); + } + + // 2D variant and weight + { + auto h = make(Tag(), in{1, 3}, in0{1, 5}); + + using V = variant<int, std::vector<int>, std::string>; + V xy[2]; + + { + xy[0] = 3; + xy[1] = y; + auto h1 = h; + auto h2 = h; + for (auto&& vi : y) h1(3, vi); + h2.fill(xy); + BOOST_TEST_EQ(h1, h2); + } + + { + xy[0] = x; + xy[1] = 3; + auto h1 = h; + auto h2 = h; + for (auto&& vi : x) h1(vi, 3); + h2.fill(xy); + BOOST_TEST_EQ(h1, h2); + } + + { + xy[0] = 3; + xy[1] = y; + auto h1 = h; + auto h2 = h; + for (auto&& vi : y) h1(3, vi, weight(2)); + h2.fill(xy, weight(2)); + BOOST_TEST_EQ(h1, h2); + } + + { + xy[0] = 3; + xy[1] = y; + auto h1 = h; + auto h2 = h; + for (unsigned i = 0; i < ndata; ++i) h1(3, y[i], weight(w[i])); + h2.fill(xy, weight(w)); + BOOST_TEST_EQ(sum(h1), sum(h2)); + BOOST_TEST_EQ(h1, h2); + } + } + + // 1D growing + { + auto h = make(Tag(), ing()); + auto h2 = h; + for (const auto& xi : x) h(xi); + h2.fill(x); + BOOST_TEST_EQ(h, h2); + } + + // 2D growing A + { + auto h = make(Tag(), in(1, 3), ing()); + auto h2 = h; + for (unsigned i = 0; i < ndata; ++i) h(x[i], y[i]); + const auto xy = {x, y}; + h2.fill(xy); + BOOST_TEST_EQ(h, h2); + } + + // 2D growing B + { + auto h = make(Tag(), ing(), ing()); + auto h2 = h; + for (unsigned i = 0; i < ndata; ++i) h(x[i], y[i]); + const auto xy = {x, y}; + h2.fill(xy); + BOOST_TEST_EQ(h, h2); + } + + // 2D growing with weights A + { + auto h = make(Tag(), in(1, 3), ing()); + auto h2 = h; + for (unsigned i = 0; i < ndata; ++i) h(x[i], y[i], weight(w[i])); + const auto xy = {x, y}; + h2.fill(xy, weight(w)); + BOOST_TEST_EQ(h, h2); + } + + // 2D growing with weights B + { + auto h = make(Tag(), ing(), ing()); + auto h2 = h; + for (unsigned i = 0; i < ndata; ++i) h(x[i], y[i], weight(2)); + const auto xy = {x, y}; + h2.fill(xy, weight(2)); + BOOST_TEST_EQ(h, h2); + } + + // 2D growing and variant + { + auto h = make(Tag(), csg{}, in{1, 2}); + auto h2 = h; + + h("foo", 1); + h("foo", 2); + + using V = variant<std::string, std::vector<std::string>, int, std::vector<int>>; + const auto xy = {V("foo"), V(std::vector<int>{1, 2})}; + h2.fill(xy); + + BOOST_TEST_EQ(h, h2); + + const auto bad = {V(std::vector<std::string>(1, "foo")), V(std::vector<int>{1, 2})}; + boost::ignore_unused(bad); + BOOST_TEST_THROWS(h.fill(bad), std::invalid_argument); + } + + // 1D profile with samples + { + auto h = make_s(Tag(), profile_storage(), in(1, 3)); + auto h2 = h; + + for (unsigned i = 0; i < ndata; ++i) h(x[i], sample(w[i])); + for (unsigned i = 0; i < ndata; ++i) h(x[i], sample(w[i]), weight(w[i])); + for (unsigned i = 0; i < ndata; ++i) h(x[i], sample(2), weight(w[i])); + for (unsigned i = 0; i < ndata; ++i) h(x[i], sample(w[i]), weight(2)); + + h2.fill(x, sample(w)); + h2.fill(x, sample(w), weight(w)); + h2.fill(x, sample(2), weight(w)); + h2.fill(x, sample(w), weight(2)); + + BOOST_TEST_EQ(h, h2); + } + + // 2D weighted profile with samples and weights + { + auto h = make_s(Tag(), weighted_profile_storage(), in(1, 3), in0(1, 3)); + auto h2 = h; + + for (unsigned i = 0; i < ndata; ++i) h(x[i], 3, sample(w[i]), weight(w[i])); + for (unsigned i = 0; i < ndata; ++i) h(x[i], 3, sample(2), weight(w[i])); + for (unsigned i = 0; i < ndata; ++i) h(x[i], 3, sample(w[i]), weight(2)); + + using V = variant<int, std::vector<int>>; + std::array<V, 2> xy; + xy[0] = x; + xy[1] = 3; + h2.fill(xy, sample(w), weight(w)); + h2.fill(xy, sample(2), weight(w)); + h2.fill(xy, sample(w), weight(2)); + + BOOST_TEST_EQ(h, h2); + } + + // axis2d + { + auto h = make(Tag(), axis2d{}); + auto h2 = h; + + std::vector<std::tuple<double, double>> xy; + xy.reserve(ndata); + for (unsigned i = 0; i < ndata; ++i) xy.emplace_back(x[i], y[i]); + + for (auto&& xyi : xy) h(xyi); + h2.fill(xy); + + BOOST_TEST_EQ(h, h2); + } +} + +int main() { + std::mt19937 gen(1); + std::normal_distribution<> id(0, 2); + std::vector<int> x(ndata), y(ndata); + auto generator = [&] { return static_cast<int>(id(gen)); }; + std::generate(x.begin(), x.end(), generator); + std::generate(y.begin(), y.end(), generator); + std::vector<double> w(ndata); + // must be all positive + std::generate(w.begin(), w.end(), [&] { return 0.5 + std::abs(id(gen)); }); + + run_tests<static_tag>(x, y, w); + run_tests<dynamic_tag>(x, y, w); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/histogram_growing_test.cpp b/src/boost/libs/histogram/test/histogram_growing_test.cpp new file mode 100644 index 00000000..2ab9a9c9 --- /dev/null +++ b/src/boost/libs/histogram/test/histogram_growing_test.cpp @@ -0,0 +1,206 @@ +// Copyright 2015-2018 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/core/lightweight_test.hpp> +#include <boost/histogram/algorithm/sum.hpp> +#include <boost/histogram/axis.hpp> +#include <boost/histogram/axis/ostream.hpp> +#include <boost/histogram/histogram.hpp> +#include <boost/histogram/ostream.hpp> +#include <string> +#include <utility> +#include "std_ostream.hpp" +#include "throw_exception.hpp" +#include "utility_histogram.hpp" + +using namespace boost::histogram; + +using def = use_default; + +using regular = axis::regular<double, def, def, axis::option::growth_t>; + +using integer = axis::integer<double, def, + decltype(axis::option::underflow | axis::option::overflow | + axis::option::growth)>; + +using category = axis::category<std::string, def, axis::option::growth_t>; + +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() { + { + auto h = make(Tag(), regular(2, 0, 1)); + const auto& a = h.axis(); + BOOST_TEST_EQ(a.size(), 2); + BOOST_TEST_EQ(h.size(), 2); + // [0.0, 0.5, 1.0] + h(0.1); + h(0.9); + BOOST_TEST_EQ(a.size(), 2); + BOOST_TEST_EQ(h.size(), 2); + h(-std::numeric_limits<double>::infinity()); + h(std::numeric_limits<double>::quiet_NaN()); + h(std::numeric_limits<double>::infinity()); + BOOST_TEST_EQ(a.size(), 2); + BOOST_TEST_EQ(h.size(), 2); + h(-0.3); + // [-0.5, 0.0, 0.5, 1.0] + BOOST_TEST_EQ(a.size(), 3); + BOOST_TEST_EQ(h.size(), 3); + BOOST_TEST_EQ(h[0], 1); + BOOST_TEST_EQ(h[1], 1); + BOOST_TEST_EQ(h[2], 1); + h(1.9); + // [-0.5, 0.0, 0.5, 1.0, 1.5, 2.0] + BOOST_TEST_EQ(a.size(), 5); + BOOST_TEST_EQ(h.size(), 5); + BOOST_TEST_EQ(h[0], 1); + BOOST_TEST_EQ(h[1], 1); + BOOST_TEST_EQ(h[2], 1); + BOOST_TEST_EQ(h[3], 0); + 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); + + 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); + } + + // mix of a growing and a non-growing axis + { + using reg_nogrow = axis::regular<>; + auto h = make(Tag(), reg_nogrow{2, 0.0, 1.0}, regular{2, 0.0, 1.0}); + BOOST_TEST_EQ(h.size(), 4 * 2); + h(0.0, 0.0); + BOOST_TEST_EQ(h.size(), 4 * 2); + BOOST_TEST_EQ(h.at(0, 0), 1); + h(-1.0, -0.1); + BOOST_TEST_EQ(h.size(), 4 * 3); + BOOST_TEST_EQ(h.at(-1, 0), 1); + h(2.0, 1.1); + BOOST_TEST_EQ(h.size(), 4 * 4); + // axis 0: [0.0, 0.5, 1.0] + under/overflow + // axis 1: [-0.5, 0.0, 0.5, 1.0, 1.5] + BOOST_TEST_EQ(h.at(-1, 0), 1); + BOOST_TEST_EQ(h.at(0, 1), 1); + BOOST_TEST_EQ(h.at(2, 3), 1); + BOOST_TEST_EQ(algorithm::sum(h), 3); + } +} + +int main() { + run_tests<static_tag>(); + run_tests<dynamic_tag>(); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/histogram_mixed_test.cpp b/src/boost/libs/histogram/test/histogram_mixed_test.cpp new file mode 100644 index 00000000..a24d7fb4 --- /dev/null +++ b/src/boost/libs/histogram/test/histogram_mixed_test.cpp @@ -0,0 +1,83 @@ +// Copyright 2015-2017 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/core/lightweight_test.hpp> +#include <boost/histogram/axis/integer.hpp> +#include <boost/histogram/axis/ostream.hpp> +#include <boost/histogram/axis/regular.hpp> +#include <boost/histogram/histogram.hpp> +#include <boost/histogram/literals.hpp> +#include <boost/histogram/ostream.hpp> +#include <boost/histogram/storage_adaptor.hpp> +#include <boost/histogram/unlimited_storage.hpp> +#include <vector> +#include "throw_exception.hpp" +#include "utility_histogram.hpp" + +using namespace boost::histogram; + +template <typename T1, typename T2> +void run_tests() { + // compare + { + 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}, + axis::integer<>(0, 2)); + BOOST_TEST_EQ(a, b); + auto b2 = make(T2{}, axis::integer<>{0, 3}, axis::integer<>(0, 2)); + BOOST_TEST_NE(a, b2); + auto b3 = make(T2{}, axis::regular<>(3, 0, 4), axis::integer<>(0, 2)); + BOOST_TEST_NE(a, b3); + } + + // operators + { + auto a = make(T1{}, axis::integer<int, use_default, axis::option::none_t>{0, 2}); + auto b = make(T2{}, axis::integer<int, use_default, axis::option::none_t>{0, 2}); + BOOST_TEST_EQ(a, b); + a(0); // 1 0 + b(1); // 0 1 + a += b; + BOOST_TEST_EQ(a[0], 1); + BOOST_TEST_EQ(a[1], 1); + a *= b; + BOOST_TEST_EQ(a[0], 0); + BOOST_TEST_EQ(a[1], 1); + a -= b; + BOOST_TEST_EQ(a[0], 0); + BOOST_TEST_EQ(a[1], 0); + a[0] = 2; + a[1] = 4; + b[0] = 2; + b[1] = 2; + a /= b; + BOOST_TEST_EQ(a[0], 1); + BOOST_TEST_EQ(a[1], 2); + + BOOST_TEST_THROWS(a += make(T2{}, axis::integer<>{0, 3}), std::invalid_argument); + BOOST_TEST_THROWS(a -= make(T2{}, axis::integer<>{0, 3}), std::invalid_argument); + BOOST_TEST_THROWS(a *= make(T2{}, axis::integer<>{0, 3}), std::invalid_argument); + BOOST_TEST_THROWS(a /= make(T2{}, axis::integer<>{0, 3}), std::invalid_argument); + } + + // copy_assign + { + auto a = make(T1{}, axis::regular<>{3, 0, 3}, axis::integer<>{0, 2}); + 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); + b = a; + BOOST_TEST_EQ(a, b); + } +} + +int main() { + run_tests<static_tag, dynamic_tag>(); + run_tests<dynamic_tag, static_tag>(); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/histogram_operators_test.cpp b/src/boost/libs/histogram/test/histogram_operators_test.cpp new file mode 100644 index 00000000..0639920b --- /dev/null +++ b/src/boost/libs/histogram/test/histogram_operators_test.cpp @@ -0,0 +1,174 @@ +// Copyright 2015-2018 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/core/is_same.hpp> +#include <boost/core/lightweight_test.hpp> +#include <boost/core/lightweight_test_trait.hpp> +#include <boost/histogram/axis.hpp> +#include <boost/histogram/axis/ostream.hpp> +#include <boost/histogram/histogram.hpp> +#include <boost/histogram/ostream.hpp> +#include <boost/throw_exception.hpp> +#include <string> +#include <vector> +#include "std_ostream.hpp" +#include "throw_exception.hpp" +#include "utility_histogram.hpp" + +using namespace boost::histogram; + +template <typename Tag> +void run_tests() { + // arithmetic operators + { + auto a = make(Tag(), axis::integer<int, use_default, axis::option::none_t>(0, 2)); + auto b = a; + a(0); + b(1); + auto c = a + b; + BOOST_TEST_EQ(c.at(0), 1); + BOOST_TEST_EQ(c.at(1), 1); + c += b; + BOOST_TEST_EQ(c.at(0), 1); + BOOST_TEST_EQ(c.at(1), 2); + auto d = a + b + c; + BOOST_TEST_TRAIT_SAME(decltype(d), decltype(a)); + BOOST_TEST_EQ(d.at(0), 2); + BOOST_TEST_EQ(d.at(1), 3); + + auto d2 = d - a - b - c; + BOOST_TEST_TRAIT_SAME(decltype(d2), decltype(a)); + BOOST_TEST_EQ(d2.at(0), 0); + BOOST_TEST_EQ(d2.at(1), 0); + d2 -= a; + BOOST_TEST_EQ(d2.at(0), -1); + BOOST_TEST_EQ(d2.at(1), 0); + + auto d3 = d; + d3 *= d; + BOOST_TEST_EQ(d3.at(0), 4); + BOOST_TEST_EQ(d3.at(1), 9); + auto d4 = d3 * (1 * d); // converted return type + BOOST_TEST_TRAIT_FALSE((boost::core::is_same<decltype(d4), decltype(d3)>)); + BOOST_TEST_EQ(d4.at(0), 8); + BOOST_TEST_EQ(d4.at(1), 27); + d4 /= d; + BOOST_TEST_EQ(d4.at(0), 4); + BOOST_TEST_EQ(d4.at(1), 9); + auto d5 = d4 / d; + BOOST_TEST_EQ(d5.at(0), 2); + BOOST_TEST_EQ(d5.at(1), 3); + + auto e = 3 * a; // converted return type + auto f = b * 2; // converted return type + BOOST_TEST_TRAIT_FALSE((boost::core::is_same<decltype(e), decltype(a)>)); + BOOST_TEST_TRAIT_FALSE((boost::core::is_same<decltype(f), decltype(a)>)); + BOOST_TEST_EQ(e.at(0), 3); + BOOST_TEST_EQ(e.at(1), 0); + BOOST_TEST_EQ(f.at(0), 0); + BOOST_TEST_EQ(f.at(1), 2); + auto r = 1.0 * a; + r += b; + r += e; + BOOST_TEST_EQ(r.at(0), 4); + BOOST_TEST_EQ(r.at(1), 1); + BOOST_TEST_EQ(r, a + b + 3 * a); + auto s = r / 4; + r /= 4; + BOOST_TEST_EQ(r.at(0), 1); + BOOST_TEST_EQ(r.at(1), 0.25); + BOOST_TEST_EQ(r, s); + } + + // arithmetic operators with mixed storage: unlimited vs. vector<unsigned> + { + auto ia = axis::integer<int, axis::null_type, axis::option::none_t>(0, 2); + auto a = make(Tag(), ia); + a(0, weight(2)); + a(1, weight(2)); + auto b = a; + auto c = make_s(Tag(), std::vector<int>(), ia); + c(0, weight(2)); + c(1, weight(2)); + auto a2 = a; + a2 += c; + BOOST_TEST_EQ(a2, (a + b)); + auto a3 = a; + a3 *= c; + BOOST_TEST_EQ(a3, (a * b)); + auto a4 = a; + a4 -= c; + BOOST_TEST_EQ(a4, (a - b)); + auto a5 = a; + a5 /= c; + BOOST_TEST_EQ(a5, (a / b)); + } + + // arithmetic operators with mixed storage: vector<unsigned char> vs. vector<unsigned> + { + auto ia = axis::integer<int, axis::null_type, axis::option::none_t>(0, 2); + auto a = make_s(Tag(), std::vector<unsigned long>{}, ia); + auto c = make_s(Tag(), std::vector<unsigned>(), ia); + a(0, weight(2u)); + a(1, weight(2u)); + auto b = a; + c(0, weight(2u)); + c(1, weight(2u)); + auto a2 = a; + a2 += c; + BOOST_TEST_EQ(a2, (a + b)); + auto a3 = a; + a3 *= c; + BOOST_TEST_EQ(a3, (a * b)); + auto a4 = a; + a4 -= c; + BOOST_TEST_EQ(a4, (a - b)); + auto a5 = a; + a5 /= c; + BOOST_TEST_EQ(a5, (a / b)); + } + + // add operators with weighted storage + { + auto ia = axis::integer<int, axis::null_type, axis::option::none_t>(0, 2); + auto a = make_s(Tag(), std::vector<accumulators::weighted_sum<>>(), ia); + auto b = make_s(Tag(), std::vector<accumulators::weighted_sum<>>(), ia); + + a(0); + BOOST_TEST_EQ(a.at(0).variance(), 1); + b(weight(3), 1); + BOOST_TEST_EQ(b.at(1).variance(), 9); + auto c = a; + c += b; + BOOST_TEST_EQ(c.at(0).value(), 1); + BOOST_TEST_EQ(c.at(0).variance(), 1); + BOOST_TEST_EQ(c.at(1).value(), 3); + BOOST_TEST_EQ(c.at(1).variance(), 9); + auto d = a; + d += b; + BOOST_TEST_EQ(d.at(0).value(), 1); + BOOST_TEST_EQ(d.at(0).variance(), 1); + BOOST_TEST_EQ(d.at(1).value(), 3); + BOOST_TEST_EQ(d.at(1).variance(), 9); + } + + // bad operations + { + auto a = make(Tag(), axis::integer<>(0, 2)); + auto b = make(Tag(), axis::integer<>(0, 3)); + BOOST_TEST_THROWS(a += b, std::invalid_argument); + BOOST_TEST_THROWS(a -= b, std::invalid_argument); + BOOST_TEST_THROWS(a *= b, std::invalid_argument); + BOOST_TEST_THROWS(a /= b, std::invalid_argument); + } +} + +int main() { + run_tests<static_tag>(); + run_tests<dynamic_tag>(); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/histogram_ostream_test.cpp b/src/boost/libs/histogram/test/histogram_ostream_test.cpp new file mode 100644 index 00000000..5047ba19 --- /dev/null +++ b/src/boost/libs/histogram/test/histogram_ostream_test.cpp @@ -0,0 +1,249 @@ +// Copyright 2019 Przemyslaw Bartosik +// 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/core/lightweight_test.hpp> +#include <boost/histogram/accumulators/mean.hpp> +#include <boost/histogram/accumulators/ostream.hpp> +#include <boost/histogram/axis/category.hpp> +#include <boost/histogram/axis/integer.hpp> +#include <boost/histogram/axis/option.hpp> +#include <boost/histogram/axis/regular.hpp> +#include <boost/histogram/make_histogram.hpp> +#include <boost/histogram/ostream.hpp> +#include <limits> +#include <sstream> +#include <string> +#include "throw_exception.hpp" +#include "utility_histogram.hpp" + +using namespace boost::histogram; + +template <class Histogram> +auto str(const Histogram& h, const unsigned width = 0) { + std::ostringstream os; + // BEGIN and END make nicer error messages + os << "BEGIN\n" << std::setw(width) << h << "END"; + return os.str(); +} + +template <class Tag> +void run_tests() { + using R = axis::regular<>; + using R2 = + axis::regular<double, boost::use_default, axis::null_type, axis::option::none_t>; + using R3 = axis::regular<double, axis::transform::log>; + using C = axis::category<std::string>; + using I = axis::integer<>; + + // regular + { + auto h = make(Tag(), R(3, -0.5, 1.0)); + h.at(0) = 1; + h.at(1) = 10; + h.at(2) = 5; + + const auto expected = + "BEGIN\n" + "histogram(regular(3, -0.5, 1, options=underflow | overflow))\n" + " +------------------------------------------------------------+\n" + "[-inf, -0.5) 0 | |\n" + "[-0.5, 0) 1 |====== |\n" + "[ 0, 0.5) 10 |=========================================================== |\n" + "[ 0.5, 1) 5 |============================== |\n" + "[ 1, inf) 0 | |\n" + " +------------------------------------------------------------+\n" + "END"; + + BOOST_TEST_CSTR_EQ(expected, str(h).c_str()); + } + + // regular, narrow + { + auto h = make(Tag(), R2(3, -0.5, 1.0)); + h.at(0) = 1; + h.at(1) = 10; + h.at(2) = 2; + + const auto expected = "BEGIN\n" + "histogram(regular(3, -0.5, 1, options=none))\n" + " +-----------------------+\n" + "[-0.5, 0) 1 |== |\n" + "[ 0, 0.5) 10 |====================== |\n" + "[ 0.5, 1) 2 |==== |\n" + " +-----------------------+\n" + "END"; + + BOOST_TEST_CSTR_EQ(expected, str(h, 40).c_str()); + + // too narrow + BOOST_TEST_CSTR_EQ("BEGIN\n" + "histogram(regular(3, -0.5, 1, options=none))END", + str(h, 10).c_str()); + } + + // regular2 + { + auto h = make(Tag(), R2(3, -0.5, 1.0)); + h.at(0) = 1; + h.at(1) = -5; + h.at(2) = 2; + + const auto expected = + "BEGIN\n" + "histogram(regular(3, -0.5, 1, options=none))\n" + " +-------------------------------------------------------------+\n" + "[-0.5, 0) 1 | ========= |\n" + "[ 0, 0.5) -5 |=========================================== |\n" + "[ 0.5, 1) 2 | ================= |\n" + " +-------------------------------------------------------------+\n" + "END"; + + BOOST_TEST_CSTR_EQ(expected, str(h).c_str()); + } + + // regular with log + { + auto h = make(Tag(), R3(6, 1e-3, 1e3, "foo")); + + const auto expected = + "BEGIN\n" + "histogram(regular_log(6, 0.001, 1000, metadata=\"foo\", options=underflow | " + "overflow))\n" + " +-----------------------------------------------------------+\n" + "[ 0, 0.001) 0 | |\n" + "[0.001, 0.01) 0 | |\n" + "[ 0.01, 0.1) 0 | |\n" + "[ 0.1, 1) 0 | |\n" + "[ 1, 10) 0 | |\n" + "[ 10, 100) 0 | |\n" + "[ 100, 1000) 0 | |\n" + "[ 1000, inf) 0 | |\n" + " +-----------------------------------------------------------+\n" + "END"; + + BOOST_TEST_CSTR_EQ(expected, str(h).c_str()); + } + + // integer + { + auto h = make(Tag(), I(0, 1)); + h.at(0) = -10; + h.at(1) = 5; + + const auto expected = + "BEGIN\n" + "histogram(integer(0, 1, options=underflow | overflow))\n" + " +---------------------------------------------------------------------+\n" + "-1 0 | |\n" + " 0 -10 |============================================= |\n" + " 1 5 | ======================= |\n" + " +---------------------------------------------------------------------+\n" + "END"; + + BOOST_TEST_CSTR_EQ(expected, str(h).c_str()); + } + + // catorgy<string> + { + auto h = make(Tag(), C({"a", "bb", "ccc", "dddd"})); + h.at(0) = 1.23; + h.at(1) = 1; + h.at(2) = 1.2345789e-3; + h.at(3) = 1.2345789e-12; + h.at(4) = std::numeric_limits<double>::quiet_NaN(); + + const auto expected = + "BEGIN\n" + "histogram(category(\"a\", \"bb\", \"ccc\", \"dddd\", options=overflow))\n" + " +------------------------------------------------------------+\n" + " a 1.23 |=========================================================== |\n" + " bb 1 |================================================ |\n" + " ccc 0.001235 | |\n" + " dddd 1.235e-12 | |\n" + "other nan | |\n" + " +------------------------------------------------------------+\n" + "END"; + + BOOST_TEST_CSTR_EQ(expected, str(h).c_str()); + } + + // histogram with axis that has no value method + { + struct minimal_axis { + int index(int x) const { return x % 2; } + int size() const { return 2; } + }; + + auto h = make(Tag(), minimal_axis{}); + h.at(0) = 3; + h.at(1) = 4; + + const auto expected = + "BEGIN\n" + "histogram(<unstreamable>)\n" + " +------------------------------------------------------------------------+\n" + "0 3 |===================================================== |\n" + "1 4 |======================================================================= |\n" + " +------------------------------------------------------------------------+\n" + "END"; + + BOOST_TEST_CSTR_EQ(expected, str(h).c_str()); + } + + // fallback for 2D + { + auto h = make(Tag(), R(1, -1, 1), R(2, -4, 7)); + h.at(-1, 0) = 1000; + h.at(-1, -1) = 123; + h.at(1, 0) = 1.23456789; + h.at(-1, 2) = std::numeric_limits<double>::quiet_NaN(); + + const auto expected = + "BEGIN\n" + "histogram(\n" + " regular(1, -1, 1, options=underflow | overflow)\n" + " regular(2, -4, 7, options=underflow | overflow)\n" + " (-1 -1): 123 ( 0 -1): 0 ( 1 -1): 0 (-1 0): 1000 \n" + " ( 0 0): 0 ( 1 0): 1.235 (-1 1): 0 ( 0 1): 0 \n" + " ( 1 1): 0 (-1 2): nan ( 0 2): 0 ( 1 2): 0 \n" + ")END"; + + BOOST_TEST_CSTR_EQ(expected, str(h).c_str()); + } + + // fallback for profile + { + auto h = make_s(Tag(), profile_storage(), R(1, -1, 1)); + h.at(0) = accumulators::mean<>(10, 100, 1000); + + const auto expected = "BEGIN\n" + "histogram(\n" + " regular(1, -1, 1, options=underflow | overflow)\n" + " (-1): mean(0, 0, -0) ( 0): mean(10, 100, 1000)\n" + " ( 1): mean(0, 0, -0) \n" + ")END"; + + BOOST_TEST_CSTR_EQ(expected, str(h).c_str()); + } +} + +int main() { + run_tests<static_tag>(); + run_tests<dynamic_tag>(); + + { + // cannot make empty static histogram + auto h = histogram<std::vector<axis::regular<>>>(); + + const auto expected = "BEGIN\n" + "histogram()END"; + + BOOST_TEST_CSTR_EQ(expected, str(h).c_str()); + } + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/histogram_serialization_test.cpp b/src/boost/libs/histogram/test/histogram_serialization_test.cpp new file mode 100644 index 00000000..29f6e5ae --- /dev/null +++ b/src/boost/libs/histogram/test/histogram_serialization_test.cpp @@ -0,0 +1,50 @@ +// Copyright 2018 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/assert.hpp> +#include <boost/core/lightweight_test.hpp> +#include <boost/histogram/axis.hpp> +#include <boost/histogram/axis/ostream.hpp> +#include <boost/histogram/ostream.hpp> +#include <boost/histogram/serialization.hpp> +#include <cmath> +#include <string> +#include "throw_exception.hpp" +#include "utility_histogram.hpp" +#include "utility_serialization.hpp" + +using namespace boost::histogram; + +template <typename Tag> +void run_tests(const std::string& filename) { + // histogram_serialization + namespace tr = axis::transform; + using def = use_default; + using axis::option::none_t; + auto a = + make(Tag(), axis::regular<double, def, def, none_t>(1, -1, 1, "reg"), + axis::circular<float, def, none_t>(1, 0.0, 1.0, "cir"), + axis::regular<double, tr::log, def, none_t>(1, 1, std::exp(2), "reg-log"), + axis::regular<double, tr::pow, std::vector<int>, axis::option::overflow_t>( + tr::pow(0.5), 1, 1, 100, {1, 2, 3}), + axis::variable<double, def, none_t>({1.5, 2.5}, "var"), + axis::category<int, def, none_t>{3, 1}, + axis::integer<int, axis::null_type, none_t>(1, 2)); + a(0.5, 0.2, 2, 20, 2.2, 1, 1); + print_xml(filename, a); + + auto b = decltype(a)(); + BOOST_TEST_NE(a, b); + load_xml(filename, b); + BOOST_TEST_EQ(a, b); +} + +int main(int argc, char** argv) { + BOOST_ASSERT(argc == 2); + run_tests<static_tag>(join(argv[1], "histogram_serialization_test_static.xml")); + run_tests<dynamic_tag>(join(argv[1], "histogram_serialization_test_dynamic.xml")); + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/histogram_serialization_test_dynamic.xml b/src/boost/libs/histogram/test/histogram_serialization_test_dynamic.xml new file mode 100644 index 00000000..3411c758 --- /dev/null +++ b/src/boost/libs/histogram/test/histogram_serialization_test_dynamic.xml @@ -0,0 +1,122 @@ +<!-- + Copyright 2018-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) +--> + +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<!DOCTYPE boost_serialization> +<boost_serialization signature="serialization::archive" version="17"> +<item class_id="0" tracking_level="0" version="0"> + <axes class_id="1" tracking_level="0" version="0"> + <count>7</count> + <item_version>0</item_version> + <item class_id="2" tracking_level="0" version="0"> + <variant class_id="3" tracking_level="1" version="0" object_id="_0"> + <which>0</which> + <value class_id="4" tracking_level="0" version="0"> + <transform class_id="5" tracking_level="0" version="0"></transform> + <size>1</size> + <meta>reg</meta> + <min>-1.00000000000000000e+00</min> + <delta>2.00000000000000000e+00</delta> + </value> + </variant> + </item> + <item> + <variant object_id="_1"> + <which>1</which> + <value class_id="6" tracking_level="0" version="0"> + <transform></transform> + <size>1</size> + <meta>cir</meta> + <min>0.000000000e+00</min> + <delta>1.000000000e+00</delta> + </value> + </variant> + </item> + <item> + <variant object_id="_2"> + <which>2</which> + <value class_id="7" tracking_level="0" version="0"> + <transform class_id="8" tracking_level="0" version="0"></transform> + <size>1</size> + <meta>reg-log</meta> + <min>0.00000000000000000e+00</min> + <delta>2.00000000000000000e+00</delta> + </value> + </variant> + </item> + <item> + <variant object_id="_3"> + <which>3</which> + <value class_id="9" tracking_level="0" version="0"> + <transform class_id="10" tracking_level="0" version="0"> + <power>5.00000000000000000e-01</power> + </transform> + <size>1</size> + <meta> + <count>3</count> + <item_version>0</item_version> + <item>1</item> + <item>2</item> + <item>3</item> + </meta> + <min>1.00000000000000000e+00</min> + <delta>9.00000000000000000e+00</delta> + </value> + </variant> + </item> + <item> + <variant object_id="_4"> + <which>4</which> + <value class_id="12" tracking_level="0" version="0"> + <seq> + <count>2</count> + <item_version>0</item_version> + <item>1.50000000000000000e+00</item> + <item>2.50000000000000000e+00</item> + </seq> + <meta>var</meta> + </value> + </variant> + </item> + <item> + <variant object_id="_5"> + <which>5</which> + <value class_id="14" tracking_level="0" version="0"> + <seq> + <count>2</count> + <item_version>0</item_version> + <item>3</item> + <item>1</item> + </seq> + <meta></meta> + </value> + </variant> + </item> + <item> + <variant object_id="_6"> + <which>6</which> + <value class_id="15" tracking_level="0" version="0"> + <size>1</size> + <meta class_id="16" tracking_level="0" version="0"></meta> + <min>1</min> + </value> + </variant> + </item> + </axes> + <storage class_id="17" tracking_level="0" version="0"> + <type>0</type> + <size>4</size> + <buffer> + <item>0</item> + <item>0</item> + <item>1</item> + <item>0</item> + </buffer> + </storage> +</item> +</boost_serialization> diff --git a/src/boost/libs/histogram/test/histogram_serialization_test_static.xml b/src/boost/libs/histogram/test/histogram_serialization_test_static.xml new file mode 100644 index 00000000..95699780 --- /dev/null +++ b/src/boost/libs/histogram/test/histogram_serialization_test_static.xml @@ -0,0 +1,85 @@ +<!-- + Copyright 2018-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) +--> + +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<!DOCTYPE boost_serialization> +<boost_serialization signature="serialization::archive" version="17"> +<item class_id="0" tracking_level="0" version="0"> + <axes class_id="1" tracking_level="0" version="0"> + <item class_id="2" tracking_level="0" version="0"> + <transform class_id="3" tracking_level="0" version="0"></transform> + <size>1</size> + <meta>reg</meta> + <min>-1.00000000000000000e+00</min> + <delta>2.00000000000000000e+00</delta> + </item> + <item class_id="4" tracking_level="0" version="0"> + <transform></transform> + <size>1</size> + <meta>cir</meta> + <min>0.000000000e+00</min> + <delta>1.000000000e+00</delta> + </item> + <item class_id="5" tracking_level="0" version="0"> + <transform class_id="6" tracking_level="0" version="0"></transform> + <size>1</size> + <meta>reg-log</meta> + <min>0.00000000000000000e+00</min> + <delta>2.00000000000000000e+00</delta> + </item> + <item class_id="7" tracking_level="0" version="0"> + <transform class_id="8" tracking_level="0" version="0"> + <power>5.00000000000000000e-01</power> + </transform> + <size>1</size> + <meta> + <count>3</count> + <item_version>0</item_version> + <item>1</item> + <item>2</item> + <item>3</item> + </meta> + <min>1.00000000000000000e+00</min> + <delta>9.00000000000000000e+00</delta> + </item> + <item class_id="10" tracking_level="0" version="0"> + <seq> + <count>2</count> + <item_version>0</item_version> + <item>1.50000000000000000e+00</item> + <item>2.50000000000000000e+00</item> + </seq> + <meta>var</meta> + </item> + <item class_id="12" tracking_level="0" version="0"> + <seq> + <count>2</count> + <item_version>0</item_version> + <item>3</item> + <item>1</item> + </seq> + <meta></meta> + </item> + <item class_id="13" tracking_level="0" version="0"> + <size>1</size> + <meta class_id="14" tracking_level="0" version="0"></meta> + <min>1</min> + </item> + </axes> + <storage class_id="15" tracking_level="0" version="0"> + <type>0</type> + <size>4</size> + <buffer> + <item>0</item> + <item>0</item> + <item>1</item> + <item>0</item> + </buffer> + </storage> +</item> +</boost_serialization> diff --git a/src/boost/libs/histogram/test/histogram_test.cpp b/src/boost/libs/histogram/test/histogram_test.cpp new file mode 100644 index 00000000..b5afb359 --- /dev/null +++ b/src/boost/libs/histogram/test/histogram_test.cpp @@ -0,0 +1,512 @@ +// Copyright 2015-2018 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/core/ignore_unused.hpp> +#include <boost/core/lightweight_test.hpp> +#include <boost/histogram/accumulators.hpp> +#include <boost/histogram/accumulators/ostream.hpp> +#include <boost/histogram/algorithm/sum.hpp> +#include <boost/histogram/axis.hpp> +#include <boost/histogram/axis/ostream.hpp> +#include <boost/histogram/histogram.hpp> +#include <boost/histogram/literals.hpp> +#include <boost/histogram/make_histogram.hpp> +#include <boost/histogram/ostream.hpp> +#include <sstream> +#include <stdexcept> +#include <tuple> +#include <utility> +#include <vector> +#include "is_close.hpp" +#include "std_ostream.hpp" +#include "throw_exception.hpp" +#include "utility_allocator.hpp" +#include "utility_axis.hpp" +#include "utility_histogram.hpp" + +using namespace boost::histogram; +using namespace boost::histogram::literals; // to get _c suffix + +template <class A, class S> +void pass_histogram(boost::histogram::histogram<A, S>& h) { + BOOST_TEST_EQ(h.at(0), 0); + BOOST_TEST_EQ(h.at(1), 1); + BOOST_TEST_EQ(h.at(2), 0); + BOOST_TEST_EQ(h.axis(0_c), axis::integer<>(0, 3)); +} + +template <class Tag> +void run_tests() { + // init_1 + { + auto h = make(Tag(), axis::regular<>{3, -1, 1}); + BOOST_TEST_EQ(h.rank(), 1); + BOOST_TEST_EQ(h.size(), 5); + BOOST_TEST_EQ(h.axis(0_c).size(), 3); + BOOST_TEST_EQ(h.axis().size(), 3); + auto h2 = make_s(Tag(), std::vector<unsigned>(), axis::regular<>{3, -1, 1}); + BOOST_TEST_EQ(h2, h); + } + + // init_2 + { + auto h = make(Tag(), axis::regular<>{3, -1, 1}, axis::integer<>{-1, 2}, + axis::circular<>{2, 0, 360}, axis::variable<>{-1, 0, 1}, + axis::category<>{{3, 1, 2}}); + BOOST_TEST_EQ(h.rank(), 5); + BOOST_TEST_EQ(h.size(), 5 * 5 * 3 * 4 * 4); + auto h2 = make_s(Tag(), std::vector<unsigned>(), axis::regular<>{3, -1, 1}, + axis::integer<>{-1, 2}, axis::circular<>{2, 0, 360}, + axis::variable<>{-1, 0, 1}, axis::category<>{{3, 1, 2}}); + BOOST_TEST_EQ(h2, h); + } + + // copy_ctor + { + auto h = make(Tag(), axis::integer<>{0, 2}, axis::integer<>{0, 3}); + h(0, 0); + auto h2 = decltype(h)(h); + BOOST_TEST_EQ(h2, h); + auto h3 = + histogram<std::tuple<axis::integer<>, axis::integer<>>, dense_storage<double>>(h); + BOOST_TEST_EQ(h3, h); + } + + // copy_assign + { + auto h = make(Tag(), axis::integer<>(0, 1), axis::integer<>(0, 2)); + h(0, 0); + auto h2 = decltype(h)(); + BOOST_TEST_NE(h, h2); + h2 = h; + BOOST_TEST_EQ(h, h2); + auto h3 = + histogram<std::tuple<axis::integer<>, axis::integer<>>, dense_storage<double>>(); + h3 = h; + BOOST_TEST_EQ(h, h3); + } + + // move + { + auto h = make(Tag(), axis::integer<>(0, 1), axis::integer<>(0, 2)); + h(0, 0); + const auto href = h; + decltype(h) h2(std::move(h)); + BOOST_TEST_EQ(algorithm::sum(h), 0); + BOOST_TEST_EQ(h.size(), 0); + BOOST_TEST_EQ(h2, href); + decltype(h) h3; + h3 = std::move(h2); + BOOST_TEST_EQ(algorithm::sum(h2), 0); + BOOST_TEST_EQ(h2.size(), 0); + BOOST_TEST_EQ(h3, href); + } + + // axis methods + { + auto a = make(Tag(), axis::integer<double>(1, 2, "foo")); + BOOST_TEST_EQ(a.axis().size(), 1); + BOOST_TEST_EQ(a.axis().bin(0).lower(), 1); + BOOST_TEST_EQ(a.axis().bin(0).upper(), 2); + BOOST_TEST_EQ(a.axis().metadata(), "foo"); + unsafe_access::axis(a, 0).metadata() = "bar"; + BOOST_TEST_EQ(a.axis().metadata(), "bar"); + + auto b = make(Tag(), axis::integer<double>(1, 2, "foo"), axis::integer<>(1, 3)); + + // check static access + BOOST_TEST_EQ(b.axis(0_c).size(), 1); + BOOST_TEST_EQ(b.axis(0_c).bin(0).lower(), 1); + BOOST_TEST_EQ(b.axis(0_c).bin(0).upper(), 2); + BOOST_TEST_EQ(b.axis(1_c).size(), 2); + BOOST_TEST_EQ(b.axis(1_c).bin(0), 1); + BOOST_TEST_EQ(b.axis(1_c).bin(1), 2); + unsafe_access::axis(b, 1_c).metadata() = "bar"; + BOOST_TEST_EQ(b.axis(0_c).metadata(), "foo"); + BOOST_TEST_EQ(b.axis(1_c).metadata(), "bar"); + + // check dynamic access + BOOST_TEST_EQ(b.axis(0).size(), 1); + BOOST_TEST_EQ(b.axis(0).bin(0).lower(), 1); + BOOST_TEST_EQ(b.axis(0).bin(0).upper(), 2); + BOOST_TEST_EQ(b.axis(1).size(), 2); + BOOST_TEST_EQ(b.axis(1).bin(0), 1); + BOOST_TEST_EQ(b.axis(1).bin(1), 2); + BOOST_TEST_EQ(b.axis(0).metadata(), "foo"); + BOOST_TEST_EQ(b.axis(1).metadata(), "bar"); + unsafe_access::axis(b, 0).metadata() = "baz"; + BOOST_TEST_EQ(b.axis(0).metadata(), "baz"); + + auto c = make(Tag(), axis::category<>({1, 2})); + BOOST_TEST_EQ(c.axis().size(), 2); + unsafe_access::axis(c, 0).metadata() = "foo"; + BOOST_TEST_EQ(c.axis().metadata(), "foo"); + // need to cast here for this to work with Tag == dynamic_tag, too + const auto& ca = axis::get<axis::category<>>(c.axis()); + BOOST_TEST_EQ(ca.bin(0), 1); + const auto& ca2 = axis::get<axis::category<>>(c.axis(0)); + BOOST_TEST_EQ(&ca2, &ca); + } + + // equal_compare + { + auto a = make(Tag(), axis::integer<>(0, 2)); + auto b = make(Tag(), axis::integer<>(0, 2), axis::integer<>(0, 3)); + BOOST_TEST(a != b); + BOOST_TEST(b != a); + auto c = make(Tag(), axis::integer<>(0, 2)); + BOOST_TEST(b != c); + BOOST_TEST(c != b); + BOOST_TEST(a == c); + BOOST_TEST(c == a); + auto d = make(Tag(), axis::regular<>(2, 0, 1)); + BOOST_TEST(c != d); + BOOST_TEST(d != c); + c(0); + BOOST_TEST(a != c); + BOOST_TEST(c != a); + a(0); + BOOST_TEST(a == c); + BOOST_TEST(c == a); + a(0); + BOOST_TEST(a != c); + BOOST_TEST(c != a); + } + + // 1D + { + auto h = make(Tag(), axis::integer<int, axis::null_type>{0, 2}); + h(0); + auto i = h(0); + BOOST_TEST(i == h.begin() + 1); // +1 because of underflow + i = h(-1); + BOOST_TEST(i == h.begin()); // underflow + i = h(10); + BOOST_TEST(i == h.end() - 1); // overflow + + BOOST_TEST_EQ(h.rank(), 1); + BOOST_TEST_EQ(h.axis().size(), 2); + BOOST_TEST_EQ(algorithm::sum(h), 4); + + BOOST_TEST_EQ(h.at(-1), 1); + BOOST_TEST_EQ(h.at(0), 2); + BOOST_TEST_EQ(h.at(1), 0); + BOOST_TEST_EQ(h.at(2), 1); + } + + // 1D no *flow + { + auto h = make(Tag(), axis::integer<int, axis::null_type, axis::option::none_t>(0, 2)); + h(0); + auto i = h(-0); + BOOST_TEST(i == h.begin()); + i = h(-1); + BOOST_TEST(i == h.end()); + i = h(10); + BOOST_TEST(i == h.end()); + + BOOST_TEST_EQ(h.rank(), 1); + BOOST_TEST_EQ(h.axis().size(), 2); + BOOST_TEST_EQ(algorithm::sum(h), 2); + + BOOST_TEST_EQ(h.at(0), 2); + BOOST_TEST_EQ(h.at(1), 0); + } + + // 1D category axis + { + auto h = make(Tag(), axis::category<>({1, 2})); + h(1); + h(2); + h(4); + h(5); + + BOOST_TEST_EQ(h.rank(), 1); + BOOST_TEST_EQ(h.axis().size(), 2); + BOOST_TEST_EQ(algorithm::sum(h), 4); + + BOOST_TEST_EQ(h.at(0), 1); + BOOST_TEST_EQ(h.at(1), 1); + BOOST_TEST_EQ(h.at(2), 2); // overflow bin + } + + // 1D weight + { + auto h = make_s(Tag(), weight_storage(), axis::integer<>(0, 2)); + h(-1); + h(0); + h(weight(0.5), 0); + h(1); + h(weight(2), 2); + + BOOST_TEST_EQ(algorithm::sum(h).value(), 5.5); + BOOST_TEST_EQ(algorithm::sum(h).variance(), 7.25); + + BOOST_TEST_EQ(h[-1].value(), 1); + BOOST_TEST_EQ(h[-1].variance(), 1); + BOOST_TEST_EQ(h[0].value(), 1.5); + BOOST_TEST_EQ(h[0].variance(), 1.25); + BOOST_TEST_EQ(h[1].value(), 1); + BOOST_TEST_EQ(h[1].variance(), 1); + BOOST_TEST_EQ(h[2].value(), 2); + BOOST_TEST_EQ(h[2].variance(), 4); + } + + // 1D profile + { + auto h = make_s(Tag(), profile_storage(), axis::integer<>(0, 2)); + + h(0, sample(1)); + h(0, sample(2)); + h(0, sample(3)); + h(sample(4), 1); + h(sample(5), 1); + h(sample(6), 1); + + BOOST_TEST_EQ(h[0].count(), 3); + BOOST_TEST_EQ(h[0].value(), 2); + BOOST_TEST_EQ(h[0].variance(), 1); + BOOST_TEST_EQ(h[1].count(), 3); + BOOST_TEST_EQ(h[1].value(), 5); + BOOST_TEST_EQ(h[1].variance(), 1); + } + + // 1D weighted profile + { + auto h = make_s(Tag(), weighted_profile_storage(), axis::integer<>(0, 2)); + + h(0, sample(1)); + h(sample(1), 0); + + h(0, weight(2), sample(3)); + h(0, sample(5), weight(2)); + + h(weight(2), 1, sample(1)); + h(sample(2), 1, weight(2)); + + h(weight(2), sample(3), 1); + h(sample(4), weight(2), 1); + + BOOST_TEST_EQ(h[0].sum_of_weights(), 6); + BOOST_TEST_EQ(h[0].value(), 3); + BOOST_TEST_EQ(h[1].sum_of_weights(), 8); + BOOST_TEST_EQ(h[1].value(), 2.5); + } + + // 2D + { + auto h = make(Tag(), axis::integer<>(-1, 1), + axis::integer<int, axis::null_type, axis::option::none_t>(-1, 2)); + h(-1, -1); + h(-1, 0); + h(-1, -10); + h(-10, 0); + + BOOST_TEST_EQ(h.rank(), 2); + BOOST_TEST_EQ(h.axis(0_c).size(), 2); + BOOST_TEST_EQ(h.axis(1_c).size(), 3); + BOOST_TEST_EQ(algorithm::sum(h), 3); + + BOOST_TEST_EQ(h.at(-1, 0), 0); + BOOST_TEST_EQ(h.at(-1, 1), 1); + BOOST_TEST_EQ(h.at(-1, 2), 0); + + BOOST_TEST_EQ(h.at(0, 0), 1); + BOOST_TEST_EQ(h.at(0, 1), 1); + BOOST_TEST_EQ(h.at(0, 2), 0); + + BOOST_TEST_EQ(h.at(1, 0), 0); + BOOST_TEST_EQ(h.at(1, 1), 0); + BOOST_TEST_EQ(h.at(1, 2), 0); + + BOOST_TEST_EQ(h.at(2, 0), 0); + BOOST_TEST_EQ(h.at(2, 1), 0); + BOOST_TEST_EQ(h.at(2, 2), 0); + } + + // 2D weight + { + auto h = make_s(Tag(), weight_storage(), axis::integer<>(-1, 1), + axis::integer<int, axis::null_type, axis::option::none_t>(-1, 2)); + h(-1, 0); // -> 0, 1 + h(weight(10), -1, -1); // -> 0, 0 + h(weight(5), -1, -10); // is ignored + h(weight(7), -10, 0); // -> -1, 1 + + BOOST_TEST_EQ(algorithm::sum(h).value(), 18); + BOOST_TEST_EQ(algorithm::sum(h).variance(), 150); + + BOOST_TEST_EQ(h.at(-1, 0).value(), 0); + BOOST_TEST_EQ(h.at(-1, 1).value(), 7); + BOOST_TEST_EQ(h.at(-1, 2).value(), 0); + + BOOST_TEST_EQ(h.at(0, 0).value(), 10); + BOOST_TEST_EQ(h.at(0, 1).value(), 1); + BOOST_TEST_EQ(h.at(0, 2).value(), 0); + + BOOST_TEST_EQ(h.at(1, 0).value(), 0); + BOOST_TEST_EQ(h.at(1, 1).value(), 0); + BOOST_TEST_EQ(h.at(1, 2).value(), 0); + + BOOST_TEST_EQ(h.at(2, 0).value(), 0); + BOOST_TEST_EQ(h.at(2, 1).value(), 0); + BOOST_TEST_EQ(h.at(2, 2).value(), 0); + + BOOST_TEST_EQ(h.at(-1, 0).variance(), 0); + BOOST_TEST_EQ(h.at(-1, 1).variance(), 49); + BOOST_TEST_EQ(h.at(-1, 2).variance(), 0); + + BOOST_TEST_EQ(h.at(0, 0).variance(), 100); + BOOST_TEST_EQ(h.at(0, 1).variance(), 1); + BOOST_TEST_EQ(h.at(0, 2).variance(), 0); + + BOOST_TEST_EQ(h.at(1, 0).variance(), 0); + BOOST_TEST_EQ(h.at(1, 1).variance(), 0); + BOOST_TEST_EQ(h.at(1, 2).variance(), 0); + + BOOST_TEST_EQ(h.at(2, 0).variance(), 0); + BOOST_TEST_EQ(h.at(2, 1).variance(), 0); + BOOST_TEST_EQ(h.at(2, 2).variance(), 0); + } + + // 3D weight + { + auto h = make_s(Tag(), weight_storage(), axis::integer<>(0, 3), axis::integer<>(0, 4), + axis::integer<>(0, 5)); + for (auto i = 0; i < h.axis(0_c).size(); ++i) + for (auto j = 0; j < h.axis(1_c).size(); ++j) + for (auto k = 0; k < h.axis(2_c).size(); ++k) h(i, j, k, weight(i + j + k)); + + for (auto i = 0; i < h.axis(0_c).size(); ++i) { + for (auto j = 0; j < h.axis(1_c).size(); ++j) { + for (auto k = 0; k < h.axis(2_c).size(); ++k) { + BOOST_TEST_EQ(h.at(i, j, k).value(), i + j + k); + BOOST_TEST_EQ(h.at(i, j, k).variance(), (i + j + k) * (i + j + k)); + } + } + } + } + + // STL support + { + auto v = std::vector<int>{0, 1, 2}; + auto h = std::for_each(v.begin(), v.end(), make(Tag(), axis::integer<>(0, 3))); + BOOST_TEST_EQ(h.at(0), 1); + BOOST_TEST_EQ(h.at(1), 1); + BOOST_TEST_EQ(h.at(2), 1); + BOOST_TEST_EQ(algorithm::sum(h), 3); + + auto a = std::vector<double>(); + // walks over all bins, including underflow and overflow + std::partial_sum(h.begin(), h.end(), std::back_inserter(a)); + BOOST_TEST_EQ(a.size(), 5); + BOOST_TEST_EQ(a[0], 0); + BOOST_TEST_EQ(a[1], 1); + BOOST_TEST_EQ(a[2], 2); + BOOST_TEST_EQ(a[3], 3); + BOOST_TEST_EQ(a[4], 3); + } + + // histogram_reset + { + auto h = make(Tag(), axis::integer<int, axis::null_type, axis::option::none_t>(0, 2)); + h(0); + h(1); + BOOST_TEST_EQ(h.at(0), 1); + BOOST_TEST_EQ(h.at(1), 1); + BOOST_TEST_EQ(algorithm::sum(h), 2); + h.reset(); + BOOST_TEST_EQ(h.at(0), 0); + BOOST_TEST_EQ(h.at(1), 0); + BOOST_TEST_EQ(algorithm::sum(h), 0); + } + + // using containers or input and output + { + auto h = make_s(Tag(), weight_storage(), axis::integer<>(0, 2), + axis::integer<double>(2, 4)); + // tuple in + h(std::make_tuple(0, 2.0)); + h(std::make_tuple(1, 3.0)); + + auto i00 = std::make_tuple(0, 0); + auto i11 = std::make_tuple(1, 1); + + // tuple out + BOOST_TEST_EQ(h.at(i00).value(), 1); + BOOST_TEST_EQ(h[i00].value(), 1); + BOOST_TEST_EQ(h[i11].value(), 1); + + // iterable out + int j11[] = {1, 1}; + BOOST_TEST_EQ(h.at(j11), 1); + BOOST_TEST_EQ(h[j11], 1); + int j111[] = {1, 1, 1}; + boost::ignore_unused(j111); + BOOST_TEST_THROWS((void)h.at(j111), std::invalid_argument); + int j13[] = {1, 3}; + boost::ignore_unused(j13); + BOOST_TEST_THROWS((void)h.at(j13), std::out_of_range); + + // tuple with weight + h(std::make_tuple(weight(2), 0, 2.0)); + h(std::make_tuple(1, 3.0, weight(2))); + + BOOST_TEST_EQ(h.at(i00).value(), 3); + BOOST_TEST_EQ(h[i00].value(), 3); + BOOST_TEST_EQ(h.at(i11).variance(), 5); + BOOST_TEST_EQ(h[i11].variance(), 5); + + // test special case of 1-dimensional histogram, which should unpack + // 1-dimensional tuple normally, but forward larger tuples to the axis + auto h1 = make(Tag(), axis::integer<>(0, 2)); + h1(std::make_tuple(0)); // as if one had passed 0 directly + BOOST_TEST_EQ(h1.at(std::make_tuple(0)), 1); // as if one had passed 0 directly + } + + // bad bin access + { + auto h = make(Tag(), axis::integer<>(0, 1), axis::integer<>(0, 1)); + BOOST_TEST_THROWS(h.at(0, 2), std::out_of_range); + BOOST_TEST_THROWS(h.at(std::make_tuple(2, 0)), std::out_of_range); + } + + // pass histogram to function + { + auto h = make(Tag(), axis::integer<>(0, 3)); + h(1); + pass_histogram(h); + } + + // allocator support + { + tracing_allocator_db db; + { + tracing_allocator<char> a(db); + auto h = make_s(Tag(), std::vector<int, tracing_allocator<int>>(a), + axis::integer<>(0, 1000)); + h(0); + } + + // int allocation for std::vector + BOOST_TEST_EQ(db.at<int>().first, 0); + BOOST_TEST_EQ(db.at<int>().second, 1002); + + if (Tag()) { // axis::variant allocation, only for dynamic histogram + using T = axis::variant<axis::integer<>>; + BOOST_TEST_EQ(db.at<T>().first, 0); + // may be zero if vector uses small-vector-optimisation + BOOST_TEST_LE(db.at<T>().second, 1); + } + } +} + +int main() { + run_tests<static_tag>(); + run_tests<dynamic_tag>(); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/histogram_threaded_test.cpp b/src/boost/libs/histogram/test/histogram_threaded_test.cpp new file mode 100644 index 00000000..1db41ea9 --- /dev/null +++ b/src/boost/libs/histogram/test/histogram_threaded_test.cpp @@ -0,0 +1,74 @@ +// 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/core/lightweight_test.hpp> +#include <boost/histogram/accumulators/thread_safe.hpp> +#include <boost/histogram/algorithm/sum.hpp> +#include <boost/histogram/axis/integer.hpp> +#include <boost/histogram/axis/ostream.hpp> +#include <boost/histogram/ostream.hpp> +#include <boost/histogram/storage_adaptor.hpp> +#include <iostream> +#include <random> +#include <thread> +#include "throw_exception.hpp" +#include "utility_histogram.hpp" + +using namespace boost::histogram; + +constexpr auto n_fill = 80000; +static_assert(n_fill % 4 == 0, "must be multiple of 4"); + +template <class Tag, class A1, class A2, class X, class Y> +void fill_test(const A1& a1, const A2& a2, const X& x, const Y& y) { + auto h1 = make_s(Tag{}, dense_storage<int>(), a1, a2); + auto xy = {x, y}; + h1.fill(xy); + + auto h2 = make_s(Tag{}, dense_storage<accumulators::thread_safe<int>>(), a1, a2); + auto run = [&h2, &x, &y](int k) { + constexpr auto shift = n_fill / 4; + auto xit = x.cbegin() + k * shift; + auto yit = y.cbegin() + k * shift; + for (unsigned i = 0; i < shift; ++i) h2(*xit++, *yit++); + }; + + std::thread t1([&] { run(0); }); + std::thread t2([&] { run(1); }); + std::thread t3([&] { run(2); }); + std::thread t4([&] { run(3); }); + t1.join(); + t2.join(); + t3.join(); + t4.join(); + + BOOST_TEST_EQ(algorithm::sum(h1), n_fill); + BOOST_TEST_EQ(algorithm::sum(h2), n_fill); + BOOST_TEST_EQ(h1, h2); +} + +template <class T> +void tests() { + std::mt19937 gen(1); + std::uniform_int_distribution<> id(-5, 5); + std::vector<int> vi(n_fill), vj(n_fill); + std::generate(vi.begin(), vi.end(), [&] { return id(gen); }); + std::generate(vj.begin(), vj.end(), [&] { return id(gen); }); + + using i = axis::integer<>; + using ig = axis::integer<int, use_default, axis::option::growth_t>; + fill_test<T>(i{0, 1}, i{0, 1}, vi, vj); + fill_test<T>(ig{0, 1}, i{0, 1}, vi, vj); + fill_test<T>(i{0, 1}, ig{0, 1}, vi, vj); + fill_test<T>(ig{0, 1}, ig{0, 1}, vi, vj); +} + +int main() { + tests<static_tag>(); + tests<dynamic_tag>(); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/indexed_test.cpp b/src/boost/libs/histogram/test/indexed_test.cpp new file mode 100644 index 00000000..0b09ad2f --- /dev/null +++ b/src/boost/libs/histogram/test/indexed_test.cpp @@ -0,0 +1,170 @@ +// Copyright 2018 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 <algorithm> +#include <boost/core/lightweight_test.hpp> +#include <boost/histogram/axis/integer.hpp> +#include <boost/histogram/axis/ostream.hpp> +#include <boost/histogram/axis/variable.hpp> +#include <boost/histogram/histogram.hpp> +#include <boost/histogram/indexed.hpp> +#include <boost/histogram/literals.hpp> +#include <boost/histogram/ostream.hpp> +#include <boost/mp11/algorithm.hpp> +#include <boost/mp11/list.hpp> +#include <iterator> +#include <ostream> +#include <type_traits> +#include <vector> +#include "throw_exception.hpp" +#include "utility_histogram.hpp" + +using namespace boost::histogram; +using namespace boost::histogram::literals; +using namespace boost::mp11; + +template <class IsDynamic, class Coverage> +void run_1d_tests(mp_list<IsDynamic, Coverage>) { + auto h = make(IsDynamic(), axis::integer<>(0, 3)); + h(-1, weight(1)); + h(0, weight(2)); + h(1, weight(3)); + h(2, weight(4)); + h(3, weight(5)); + + auto ind = indexed(h, Coverage()); + auto it = ind.begin(); + BOOST_TEST_EQ(it->indices().size(), 1); + BOOST_TEST_EQ(it->indices()[0], Coverage() == coverage::all ? -1 : 0); + + if (Coverage() == coverage::all) { + BOOST_TEST_EQ(it->index(0), -1); + BOOST_TEST_EQ(**it, 1); + BOOST_TEST_EQ(it->bin(0), h.axis().bin(-1)); + ++it; + } + BOOST_TEST_EQ(it->index(0), 0); + BOOST_TEST_EQ(**it, 2); + BOOST_TEST_EQ(it->bin(0), h.axis().bin(0)); + ++it; + BOOST_TEST_EQ(it->index(0), 1); + BOOST_TEST_EQ(**it, 3); + BOOST_TEST_EQ(it->bin(0), h.axis().bin(1)); + ++it; + // check post-increment + auto prev = it++; + BOOST_TEST_EQ(prev->index(0), 2); + BOOST_TEST_EQ(**prev, 4); + BOOST_TEST_EQ(prev->bin(0), h.axis().bin(2)); + if (Coverage() == coverage::all) { + BOOST_TEST_EQ(it->index(0), 3); + BOOST_TEST_EQ(**it, 5); + BOOST_TEST_EQ(it->bin(0), h.axis().bin(3)); + ++it; + } + BOOST_TEST(it == ind.end()); + + for (auto&& x : indexed(h, Coverage())) *x = 0; + + for (auto&& x : indexed(static_cast<const decltype(h)&>(h), Coverage())) + BOOST_TEST_EQ(*x, 0); +} + +template <class IsDynamic, class Coverage> +void run_3d_tests(mp_list<IsDynamic, Coverage>) { + auto h = make_s(IsDynamic(), std::vector<int>(), axis::integer<>(0, 2), + axis::integer<int, axis::null_type, axis::option::none_t>(0, 3), + axis::integer<int, axis::null_type, axis::option::overflow_t>(0, 4)); + + for (int i = -1; i < 3; ++i) + for (int j = -1; j < 4; ++j) + for (int k = -1; k < 5; ++k) h(i, j, k, weight(i * 100 + j * 10 + k)); + + auto ind = indexed(h, Coverage()); + auto it = ind.begin(); + BOOST_TEST_EQ(it->indices().size(), 3); + + const int d = Coverage() == coverage::all; + + // imitate iteration order of indexed loop + for (int k = 0; k < 4 + d; ++k) + for (int j = 0; j < 3; ++j) + for (int i = -d; i < 2 + d; ++i) { + BOOST_TEST_EQ(it->index(0), i); + BOOST_TEST_EQ(it->index(1), j); + BOOST_TEST_EQ(it->index(2), k); + BOOST_TEST_EQ(it->bin(0_c), h.axis(0_c).bin(i)); + BOOST_TEST_EQ(it->bin(1_c), h.axis(1_c).bin(j)); + BOOST_TEST_EQ(it->bin(2_c), h.axis(2_c).bin(k)); + BOOST_TEST_EQ(**it, i * 100 + j * 10 + k); + ++it; + } + BOOST_TEST(it == ind.end()); +} + +template <class IsDynamic, class Coverage> +void run_density_tests(mp_list<IsDynamic, Coverage>) { + auto ax = axis::variable<>({0.0, 0.1, 0.3, 0.6}); + auto ay = axis::integer<int>(0, 2); + auto az = ax; + auto h = make_s(IsDynamic(), std::vector<int>(), ax, ay, az); + + // fill uniformly + for (auto&& x : h) x = 1; + + for (auto&& x : indexed(h, Coverage())) { + BOOST_TEST_EQ(x.density(), *x / (x.bin(0).width() * x.bin(2).width())); + } +} + +template <class IsDynamic, class Coverage> +void run_stdlib_tests(mp_list<IsDynamic, Coverage>) { + auto ax = axis::regular<>(3, 0, 1); + auto ay = axis::integer<>(0, 2); + auto h = make_s(IsDynamic(), std::array<int, 20>(), ax, ay); + + struct generator { + int i = 0; + int operator()() { return ++i; } + }; + + auto ind = indexed(h, Coverage()); + std::generate(ind.begin(), ind.end(), generator{}); + + { + int i = 0; + for (auto&& x : ind) BOOST_TEST_EQ(*x, ++i); + } + + { + auto it = std::min_element(ind.begin(), ind.end()); + BOOST_TEST(it == ind.begin()); + BOOST_TEST(it != ind.end()); + } + + { + auto it = std::max_element(ind.begin(), ind.end()); + // get last before end() + auto it2 = ind.begin(); + auto it3 = it2; + while (it2 != ind.end()) it3 = it2++; + BOOST_TEST(it == it3); + BOOST_TEST(it != ind.begin()); + } +} + +int main() { + mp_for_each<mp_product<mp_list, mp_list<mp_false, mp_true>, + mp_list<std::integral_constant<coverage, coverage::inner>, + std::integral_constant<coverage, coverage::all>>>>( + [](auto&& x) { + run_1d_tests(x); + run_3d_tests(x); + run_density_tests(x); + run_stdlib_tests(x); + }); + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/is_close.hpp b/src/boost/libs/histogram/test/is_close.hpp new file mode 100644 index 00000000..7fe31057 --- /dev/null +++ b/src/boost/libs/histogram/test/is_close.hpp @@ -0,0 +1,15 @@ +// Copyright 2018 Hans Dembinski +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_HISTOGRAM_TEST_IS_CLOSE_HPP +#define BOOST_HISTOGRAM_TEST_IS_CLOSE_HPP + +#include <boost/core/lightweight_test.hpp> +#include <cmath> + +#define BOOST_TEST_IS_CLOSE(a, b, eps) BOOST_TEST(std::abs(a - b) < eps) + +#endif diff --git a/src/boost/libs/histogram/test/make_histogram_fail0.cpp b/src/boost/libs/histogram/test/make_histogram_fail0.cpp new file mode 100644 index 00000000..1c508a49 --- /dev/null +++ b/src/boost/libs/histogram/test/make_histogram_fail0.cpp @@ -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>{}); +} diff --git a/src/boost/libs/histogram/test/make_histogram_fail1.cpp b/src/boost/libs/histogram/test/make_histogram_fail1.cpp new file mode 100644 index 00000000..8768ca69 --- /dev/null +++ b/src/boost/libs/histogram/test/make_histogram_fail1.cpp @@ -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>{}); +} diff --git a/src/boost/libs/histogram/test/odr_main_test.cpp b/src/boost/libs/histogram/test/odr_main_test.cpp new file mode 100644 index 00000000..b074142a --- /dev/null +++ b/src/boost/libs/histogram/test/odr_main_test.cpp @@ -0,0 +1,10 @@ +// Copyright 2019 Henry Schreiner, 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 all headers again +#include "odr_test.cpp" + +int main() { return 0; } diff --git a/src/boost/libs/histogram/test/odr_test.cpp b/src/boost/libs/histogram/test/odr_test.cpp new file mode 100644 index 00000000..eb0e9a70 --- /dev/null +++ b/src/boost/libs/histogram/test/odr_test.cpp @@ -0,0 +1,12 @@ +// Copyright 2019 Henry Schreiner, 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 all Boost.Histogram header here +#include <boost/histogram.hpp> +#include <boost/histogram/accumulators.hpp> +#include <boost/histogram/axis/ostream.hpp> +#include <boost/histogram/ostream.hpp> +#include <boost/histogram/serialization.hpp> diff --git a/src/boost/libs/histogram/test/std_ostream.hpp b/src/boost/libs/histogram/test/std_ostream.hpp new file mode 100644 index 00000000..e5740a8d --- /dev/null +++ b/src/boost/libs/histogram/test/std_ostream.hpp @@ -0,0 +1,40 @@ +// Copyright 2018-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) + +#ifndef BOOST_HISTOGRAM_TEST_STD_OSTREAM_HPP +#define BOOST_HISTOGRAM_TEST_STD_OSTREAM_HPP + +#include <boost/mp11/tuple.hpp> +#include <ostream> +#include <utility> +#include <vector> + +namespace std { +// never add to std, we only do it here to get ADL working :( +template <typename T> +ostream& operator<<(ostream& os, const vector<T>& v) { + os << "[ "; + for (const auto& x : v) os << x << " "; + os << "]"; + return os; +} + +template <class... Ts> +ostream& operator<<(ostream& os, const std::tuple<Ts...>& t) { + os << "[ "; + ::boost::mp11::tuple_for_each(t, [&os](const auto& x) { os << x << " "; }); + os << "]"; + return os; +} + +template <class T, class U> +ostream& operator<<(ostream& os, const std::pair<T, U>& t) { + os << "[ " << t.first << " " << t.second << " ]"; + return os; +} +} // namespace std + +#endif diff --git a/src/boost/libs/histogram/test/storage_adaptor_serialization_test.cpp b/src/boost/libs/histogram/test/storage_adaptor_serialization_test.cpp new file mode 100644 index 00000000..892449bb --- /dev/null +++ b/src/boost/libs/histogram/test/storage_adaptor_serialization_test.cpp @@ -0,0 +1,47 @@ +// Copyright 2018 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 <array> +#include <boost/assert.hpp> +#include <boost/core/lightweight_test.hpp> +#include <boost/histogram/accumulators/thread_safe.hpp> +#include <boost/histogram/serialization.hpp> +#include <boost/histogram/storage_adaptor.hpp> +#include <map> +#include <vector> +#include "throw_exception.hpp" +#include "utility_serialization.hpp" + +using namespace boost::histogram; + +template <typename T> +void test_serialization(const std::string& filename) { + auto a = storage_adaptor<T>(); + a.reset(3); + a[1] += 1; + a[2] += 2; + print_xml(filename, a); + + auto b = storage_adaptor<T>(); + BOOST_TEST_NOT(a == b); + load_xml(filename, b); + BOOST_TEST(a == b); +} + +int main(int argc, char** argv) { + BOOST_ASSERT(argc == 2); + + test_serialization<std::vector<int>>( + join(argv[1], "storage_adaptor_serialization_test_vector_int.xml")); + test_serialization<std::array<unsigned, 10>>( + join(argv[1], "storage_adaptor_serialization_test_array_unsigned.xml")); + test_serialization<std::map<std::size_t, double>>( + join(argv[1], "storage_adaptor_serialization_test_map_double.xml")); + test_serialization<std::vector<accumulators::thread_safe<int>>>( + join(argv[1], "storage_adaptor_serialization_test_vector_thread_safe_int.xml")); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/storage_adaptor_serialization_test_array_unsigned.xml b/src/boost/libs/histogram/test/storage_adaptor_serialization_test_array_unsigned.xml new file mode 100644 index 00000000..180d322b --- /dev/null +++ b/src/boost/libs/histogram/test/storage_adaptor_serialization_test_array_unsigned.xml @@ -0,0 +1,23 @@ +<!-- + Copyright 2018-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) +--> + +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<!DOCTYPE boost_serialization> +<boost_serialization signature="serialization::archive" version="17"> +<item class_id="0" tracking_level="0" version="0"> + <impl class_id="1" tracking_level="0" version="0"> + <size>3</size> + <array> + <item>0</item> + <item>1</item> + <item>2</item> + </array> + </impl> +</item> +</boost_serialization> + diff --git a/src/boost/libs/histogram/test/storage_adaptor_serialization_test_map_double.xml b/src/boost/libs/histogram/test/storage_adaptor_serialization_test_map_double.xml new file mode 100644 index 00000000..ddf960f3 --- /dev/null +++ b/src/boost/libs/histogram/test/storage_adaptor_serialization_test_map_double.xml @@ -0,0 +1,30 @@ +<!-- + Copyright 2018-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) +--> + +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<!DOCTYPE boost_serialization> +<boost_serialization signature="serialization::archive" version="17"> +<item class_id="0" tracking_level="0" version="0"> + <impl class_id="1" tracking_level="0" version="0"> + <size>3</size> + <map class_id="2" tracking_level="0" version="0"> + <count>2</count> + <item_version>0</item_version> + <item class_id="3" tracking_level="0" version="0"> + <first>1</first> + <second>1.00000000000000000e+00</second> + </item> + <item> + <first>2</first> + <second>2.00000000000000000e+00</second> + </item> + </map> + </impl> +</item> +</boost_serialization> + diff --git a/src/boost/libs/histogram/test/storage_adaptor_serialization_test_vector_int.xml b/src/boost/libs/histogram/test/storage_adaptor_serialization_test_vector_int.xml new file mode 100644 index 00000000..c1e6de0c --- /dev/null +++ b/src/boost/libs/histogram/test/storage_adaptor_serialization_test_vector_int.xml @@ -0,0 +1,24 @@ +<!-- + Copyright 2018-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) +--> + +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<!DOCTYPE boost_serialization> +<boost_serialization signature="serialization::archive" version="17"> +<item class_id="0" tracking_level="0" version="0"> + <impl class_id="1" tracking_level="0" version="0"> + <vector> + <count>3</count> + <item_version>0</item_version> + <item>0</item> + <item>1</item> + <item>2</item> + </vector> + </impl> +</item> +</boost_serialization> + diff --git a/src/boost/libs/histogram/test/storage_adaptor_serialization_test_vector_thread_safe_int.xml b/src/boost/libs/histogram/test/storage_adaptor_serialization_test_vector_thread_safe_int.xml new file mode 100644 index 00000000..50a18365 --- /dev/null +++ b/src/boost/libs/histogram/test/storage_adaptor_serialization_test_vector_thread_safe_int.xml @@ -0,0 +1,29 @@ +<!-- + Copyright 2018-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) +--> + +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<!DOCTYPE boost_serialization> +<boost_serialization signature="serialization::archive" version="17"> +<item class_id="0" tracking_level="0" version="0"> + <impl class_id="1" tracking_level="0" version="0"> + <vector class_id="2" tracking_level="0" version="0"> + <count>3</count> + <item_version>0</item_version> + <item class_id="3" tracking_level="0" version="0"> + <value>0</value> + </item> + <item> + <value>1</value> + </item> + <item> + <value>2</value> + </item> + </vector> + </impl> +</item> +</boost_serialization> diff --git a/src/boost/libs/histogram/test/storage_adaptor_test.cpp b/src/boost/libs/histogram/test/storage_adaptor_test.cpp new file mode 100644 index 00000000..6f8e01f5 --- /dev/null +++ b/src/boost/libs/histogram/test/storage_adaptor_test.cpp @@ -0,0 +1,292 @@ +// Copyright 2015-2017 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 <array> +#include <boost/core/lightweight_test.hpp> +#include <boost/histogram/accumulators/weighted_mean.hpp> +#include <boost/histogram/accumulators/weighted_sum.hpp> +#include <boost/histogram/storage_adaptor.hpp> +#include <boost/histogram/unlimited_storage.hpp> +#include <boost/histogram/weight.hpp> +#include <cmath> +#include <deque> +#include <limits> +#include <map> +#include <sstream> +#include <vector> +#include "is_close.hpp" +#include "throw_exception.hpp" +#include "utility_allocator.hpp" + +using namespace boost::histogram; +using namespace std::literals; + +template <class T> +auto str(const T& t) { + std::ostringstream os; + os << t; + return os.str(); +} + +template <typename T> +void tests() { + using Storage = storage_adaptor<T>; + // ctor, copy, move + { + Storage a; + a.reset(2); + Storage b(a); + Storage c; + c = a; + BOOST_TEST_EQ(std::distance(a.begin(), a.end()), 2); + BOOST_TEST_EQ(a.size(), 2); + BOOST_TEST_EQ(b.size(), 2); + BOOST_TEST_EQ(c.size(), 2); + + Storage d(std::move(a)); + BOOST_TEST_EQ(d.size(), 2); + Storage e; + e = std::move(d); + BOOST_TEST_EQ(e.size(), 2); + + const auto t = T(); + storage_adaptor<T> g(t); // tests converting ctor + BOOST_TEST_EQ(g.size(), 0); + const auto u = std::vector<typename Storage::value_type>(3, 1); + Storage h(u); // tests converting ctor + BOOST_TEST_EQ(h.size(), 3); + BOOST_TEST_EQ(h[0], 1); + BOOST_TEST_EQ(h[1], 1); + BOOST_TEST_EQ(h[2], 1); + } + + // increment, add, sub, set, reset, compare + { + Storage a; + a.reset(1); + ++a[0]; + const auto save = a[0]++; + BOOST_TEST_EQ(save, 1); + BOOST_TEST_EQ(a[0], 2); + a.reset(2); + BOOST_TEST_EQ(a.size(), 2); + ++a[0]; + a[0] += 2; + a[1] += 5; + BOOST_TEST_EQ(a[0], 3); + BOOST_TEST_EQ(a[1], 5); + a[0] -= 2; + a[1] -= 5; + BOOST_TEST_EQ(a[0], 1); + BOOST_TEST_EQ(a[1], 0); + a[1] = 9; + BOOST_TEST_EQ(a[0], 1); + BOOST_TEST_EQ(a[1], 9); + BOOST_TEST_LT(a[0], 2); + BOOST_TEST_LT(0, a[1]); + BOOST_TEST_GT(a[1], 4); + BOOST_TEST_GT(3, a[0]); + a[1] = a[0]; + BOOST_TEST_EQ(a[0], 1); + BOOST_TEST_EQ(a[1], 1); + a.reset(0); + BOOST_TEST_EQ(a.size(), 0); + } + + // copy + { + Storage a; + a.reset(1); + ++a[0]; + Storage b; + b.reset(2); + BOOST_TEST(!(a == b)); + b = a; + BOOST_TEST(a == b); + BOOST_TEST_EQ(b.size(), 1); + BOOST_TEST_EQ(b[0], 1); + + Storage c(a); + BOOST_TEST(a == c); + BOOST_TEST_EQ(c.size(), 1); + BOOST_TEST_EQ(c[0], 1); + } + + // move + { + Storage a; + a.reset(1); + ++a[0]; + Storage b; + BOOST_TEST(!(a == b)); + b = std::move(a); + BOOST_TEST_EQ(b.size(), 1); + BOOST_TEST_EQ(b[0], 1); + Storage c(std::move(b)); + BOOST_TEST_EQ(c.size(), 1); + BOOST_TEST_EQ(c[0], 1); + } + + { + Storage a; + a.reset(1); + a[0] += 2; + BOOST_TEST_EQ(str(a[0]), "2"s); + } +} + +template <typename A, typename B> +void mixed_tests() { + // comparison + { + A a, b; + a.reset(1); + b.reset(1); + B c, d; + c.reset(1); + d.reset(2); + ++a[0]; + ++b[0]; + c[0] += 2; + d[0] = 3; + d[1] = 5; + BOOST_TEST_EQ(a[0], 1); + BOOST_TEST_EQ(b[0], 1); + BOOST_TEST_EQ(c[0], 2); + BOOST_TEST_EQ(d[0], 3); + BOOST_TEST_EQ(d[1], 5); + BOOST_TEST(a == a); + BOOST_TEST(a == b); + BOOST_TEST(!(a == c)); + BOOST_TEST(!(a == d)); + } + + // ctor, copy, move, assign + { + A a; + a.reset(2); + ++a[1]; + B b(a); + B c; + c = a; + BOOST_TEST_EQ(c[0], 0); + BOOST_TEST_EQ(c[1], 1); + c = A(); + BOOST_TEST_EQ(c.size(), 0); + B d(std::move(a)); + B e; + e = std::move(d); + BOOST_TEST_EQ(e[0], 0); + BOOST_TEST_EQ(e[1], 1); + } +} + +int main() { + tests<std::vector<int>>(); + tests<std::array<int, 100>>(); + tests<std::deque<int>>(); + tests<std::map<std::size_t, int>>(); + tests<std::unordered_map<std::size_t, int>>(); + + mixed_tests<storage_adaptor<std::vector<int>>, + storage_adaptor<std::array<double, 100>>>(); + 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>>>(); + + // special case for division of map-based storage_adaptor + { + auto a = storage_adaptor<std::map<std::size_t, double>>(); + a.reset(2); + a[0] /= 2; + BOOST_TEST_EQ(a[0], 0); + a[0] = 2; + a[0] /= 2; + BOOST_TEST_EQ(a[0], 1); + a[1] /= std::numeric_limits<double>::quiet_NaN(); + BOOST_TEST(std::isnan(static_cast<double>(a[1]))); + } + + // with accumulators::weighted_sum + { + auto a = storage_adaptor<std::vector<accumulators::weighted_sum<double>>>(); + a.reset(1); + ++a[0]; + a[0] += 1; + a[0] += 2; + a[0] += accumulators::weighted_sum<double>(1, 0); + BOOST_TEST_EQ(a[0].value(), 5); + BOOST_TEST_EQ(a[0].variance(), 6); + a[0] *= 2; + BOOST_TEST_EQ(a[0].value(), 10); + BOOST_TEST_EQ(a[0].variance(), 24); + } + + // with accumulators::weighted_mean + { + auto a = storage_adaptor<std::vector<accumulators::weighted_mean<double>>>(); + a.reset(1); + a[0](/* sample */ 1); + a[0](weight(2), /* sample */ 2); + a[0] += accumulators::weighted_mean<>(1, 0, 0, 0); + BOOST_TEST_EQ(a[0].sum_of_weights(), 4); + BOOST_TEST_IS_CLOSE(a[0].value(), 1.25, 1e-3); + BOOST_TEST_IS_CLOSE(a[0].variance(), 0.242, 1e-3); + } + + // exceeding array capacity + { + auto a = storage_adaptor<std::array<int, 10>>(); + a.reset(10); // should not throw + BOOST_TEST_THROWS(a.reset(11), std::length_error); + auto b = storage_adaptor<std::vector<int>>(); + b.reset(11); + BOOST_TEST_THROWS(a = b, std::length_error); + } + + // test sparsity of map backend + { + tracing_allocator_db db; + tracing_allocator<char> alloc(db); + using map_t = std::map<std::size_t, double, std::less<std::size_t>, + tracing_allocator<std::pair<const std::size_t, double>>>; + using A = storage_adaptor<map_t>; + auto a = A(alloc); + // MSVC implementation allocates some structures for debugging + const auto baseline = db.second; + a.reset(10); + BOOST_TEST_EQ(db.first, baseline); // nothing allocated yet + // queries do not allocate + BOOST_TEST_EQ(a[0], 0); + BOOST_TEST_EQ(a[9], 0); + BOOST_TEST_EQ(db.first, baseline); + ++a[5]; // causes one allocation + const auto node = db.first - baseline; + BOOST_TEST_EQ(a[5], 1); + a[4] += 2; // causes one allocation + BOOST_TEST_EQ(a[4], 2); + BOOST_TEST_EQ(db.first, baseline + 2 * node); + a[3] -= 2; // causes one allocation + BOOST_TEST_EQ(a[3], -2); + BOOST_TEST_EQ(db.first, baseline + 3 * node); + a[2] *= 2; // no allocation + BOOST_TEST_EQ(db.first, baseline + 3 * node); + a[2] /= 2; // no allocation + BOOST_TEST_EQ(db.first, baseline + 3 * node); + a[4] = 0; // causes one deallocation + BOOST_TEST_EQ(db.first, baseline + 2 * node); + + auto b = storage_adaptor<std::vector<int>>(); + b.reset(5); + ++b[2]; + a = b; + // only one new allocation for non-zero value + BOOST_TEST_EQ(db.first, baseline + node); + } + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/storage_adaptor_threaded_test.cpp b/src/boost/libs/histogram/test/storage_adaptor_threaded_test.cpp new file mode 100644 index 00000000..0ba47534 --- /dev/null +++ b/src/boost/libs/histogram/test/storage_adaptor_threaded_test.cpp @@ -0,0 +1,58 @@ +// 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/core/lightweight_test.hpp> +#include <boost/histogram/accumulators/ostream.hpp> +#include <boost/histogram/accumulators/thread_safe.hpp> +#include "throw_exception.hpp" +#include <boost/histogram/storage_adaptor.hpp> + +#include <array> +#include <deque> +#include <map> +#include <thread> +#include <unordered_map> +#include <vector> + +using namespace boost::histogram; + +constexpr auto n_fill = 1000000; + +template <class T> +void tests() { + { + storage_adaptor<T> s; + s.reset(1); + + auto fill = [&s]() { + for (unsigned i = 0; i < n_fill; ++i) { + ++s[0]; + s[0] += 1; + } + }; + + std::thread t1(fill); + std::thread t2(fill); + std::thread t3(fill); + std::thread t4(fill); + t1.join(); + t2.join(); + t3.join(); + t4.join(); + + BOOST_TEST_EQ(s[0], 4 * 2 * n_fill); + } +} + +int main() { + using ts_int = accumulators::thread_safe<int>; + tests<std::vector<ts_int>>(); + tests<std::array<ts_int, 100>>(); + tests<std::deque<ts_int>>(); + // stdlib maps are not thread-safe and not supported + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/throw_exception.hpp b/src/boost/libs/histogram/test/throw_exception.hpp new file mode 100644 index 00000000..e0160ed7 --- /dev/null +++ b/src/boost/libs/histogram/test/throw_exception.hpp @@ -0,0 +1,21 @@ +// 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) + +#ifdef BOOST_NO_EXCEPTIONS + +#include <cstdlib> // std::abort +#include <exception> +#include <iostream> + +namespace boost { +// dummy implementation for user-defined function from boost/throw_exception.hpp +inline void throw_exception(std::exception const& e) { + std::cerr << e.what() << std::endl; + std::abort(); +} +} // namespace boost + +#endif diff --git a/src/boost/libs/histogram/test/unlimited_storage_serialization_test.cpp b/src/boost/libs/histogram/test/unlimited_storage_serialization_test.cpp new file mode 100644 index 00000000..302bef3c --- /dev/null +++ b/src/boost/libs/histogram/test/unlimited_storage_serialization_test.cpp @@ -0,0 +1,57 @@ +// Copyright 2018 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/archive/text_iarchive.hpp> +#include <boost/archive/text_oarchive.hpp> +#include <boost/assert.hpp> +#include <boost/core/lightweight_test.hpp> +#include <boost/histogram/serialization.hpp> +#include <boost/histogram/unlimited_storage.hpp> +#include <memory> +#include <sstream> +#include "throw_exception.hpp" +#include "utility_serialization.hpp" + +using unlimited_storage_type = boost::histogram::unlimited_storage<>; + +using namespace boost::histogram; + +template <typename T> +unlimited_storage_type prepare(std::size_t n, const T x) { + std::unique_ptr<T[]> v(new T[n]); + std::fill(v.get(), v.get() + n, static_cast<T>(0)); + v.get()[0] = x; + return unlimited_storage_type(n, v.get()); +} + +template <typename T> +unlimited_storage_type prepare(std::size_t n) { + return unlimited_storage_type(n, static_cast<T*>(nullptr)); +} + +template <typename T> +void run_test(const std::string& filename) { + const auto a = prepare(1, T(1)); + print_xml(filename, a); + unlimited_storage_type b; + BOOST_TEST(!(a == b)); + load_xml(filename, b); + BOOST_TEST(a == b); +} + +int main(int argc, char** argv) { + BOOST_ASSERT(argc == 2); + + run_test<uint8_t>(join(argv[1], "unlimited_storage_serialization_test_u8.xml")); + run_test<uint16_t>(join(argv[1], "unlimited_storage_serialization_test_u16.xml")); + run_test<uint32_t>(join(argv[1], "unlimited_storage_serialization_test_u32.xml")); + run_test<uint64_t>(join(argv[1], "unlimited_storage_serialization_test_u64.xml")); + run_test<unlimited_storage_type::large_int>( + join(argv[1], "unlimited_storage_serialization_test_large_int.xml")); + run_test<double>(join(argv[1], "unlimited_storage_serialization_test_double.xml")); + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/unlimited_storage_serialization_test_double.xml b/src/boost/libs/histogram/test/unlimited_storage_serialization_test_double.xml new file mode 100644 index 00000000..8532503e --- /dev/null +++ b/src/boost/libs/histogram/test/unlimited_storage_serialization_test_double.xml @@ -0,0 +1,19 @@ +<!-- + Copyright 2018-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) +--> + +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<!DOCTYPE boost_serialization> +<boost_serialization signature="serialization::archive" version="17"> +<item class_id="0" tracking_level="0" version="0"> + <type>5</type> + <size>1</size> + <buffer> + <item>1.00000000000000000e+00</item> + </buffer> +</item> +</boost_serialization>
\ No newline at end of file diff --git a/src/boost/libs/histogram/test/unlimited_storage_serialization_test_large_int.xml b/src/boost/libs/histogram/test/unlimited_storage_serialization_test_large_int.xml new file mode 100644 index 00000000..e77ec437 --- /dev/null +++ b/src/boost/libs/histogram/test/unlimited_storage_serialization_test_large_int.xml @@ -0,0 +1,25 @@ +<!-- + Copyright 2018-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) +--> + +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<!DOCTYPE boost_serialization> +<boost_serialization signature="serialization::archive" version="17"> +<item class_id="0" tracking_level="0" version="0"> + <type>4</type> + <size>1</size> + <buffer> + <item class_id="1" tracking_level="0" version="0"> + <data> + <count>1</count> + <item_version>0</item_version> + <item>1</item> + </data> + </item> + </buffer> +</item> +</boost_serialization>
\ No newline at end of file diff --git a/src/boost/libs/histogram/test/unlimited_storage_serialization_test_u16.xml b/src/boost/libs/histogram/test/unlimited_storage_serialization_test_u16.xml new file mode 100644 index 00000000..c29f8600 --- /dev/null +++ b/src/boost/libs/histogram/test/unlimited_storage_serialization_test_u16.xml @@ -0,0 +1,19 @@ +<!-- + Copyright 2018-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) +--> + +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<!DOCTYPE boost_serialization> +<boost_serialization signature="serialization::archive" version="17"> +<item class_id="0" tracking_level="0" version="0"> + <type>1</type> + <size>1</size> + <buffer> + <item>1</item> + </buffer> +</item> +</boost_serialization>
\ No newline at end of file diff --git a/src/boost/libs/histogram/test/unlimited_storage_serialization_test_u32.xml b/src/boost/libs/histogram/test/unlimited_storage_serialization_test_u32.xml new file mode 100644 index 00000000..709ad01a --- /dev/null +++ b/src/boost/libs/histogram/test/unlimited_storage_serialization_test_u32.xml @@ -0,0 +1,19 @@ +<!-- + Copyright 2018-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) +--> + +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<!DOCTYPE boost_serialization> +<boost_serialization signature="serialization::archive" version="17"> +<item class_id="0" tracking_level="0" version="0"> + <type>2</type> + <size>1</size> + <buffer> + <item>1</item> + </buffer> +</item> +</boost_serialization>
\ No newline at end of file diff --git a/src/boost/libs/histogram/test/unlimited_storage_serialization_test_u64.xml b/src/boost/libs/histogram/test/unlimited_storage_serialization_test_u64.xml new file mode 100644 index 00000000..a6fed6ff --- /dev/null +++ b/src/boost/libs/histogram/test/unlimited_storage_serialization_test_u64.xml @@ -0,0 +1,19 @@ +<!-- + Copyright 2018-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) +--> + +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<!DOCTYPE boost_serialization> +<boost_serialization signature="serialization::archive" version="17"> +<item class_id="0" tracking_level="0" version="0"> + <type>3</type> + <size>1</size> + <buffer> + <item>1</item> + </buffer> +</item> +</boost_serialization>
\ No newline at end of file diff --git a/src/boost/libs/histogram/test/unlimited_storage_serialization_test_u8.xml b/src/boost/libs/histogram/test/unlimited_storage_serialization_test_u8.xml new file mode 100644 index 00000000..80dd69b7 --- /dev/null +++ b/src/boost/libs/histogram/test/unlimited_storage_serialization_test_u8.xml @@ -0,0 +1,19 @@ +<!-- + Copyright 2018-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) +--> + +<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> +<!DOCTYPE boost_serialization> +<boost_serialization signature="serialization::archive" version="17"> +<item class_id="0" tracking_level="0" version="0"> + <type>0</type> + <size>1</size> + <buffer> + <item>1</item> + </buffer> +</item> +</boost_serialization>
\ No newline at end of file diff --git a/src/boost/libs/histogram/test/unlimited_storage_test.cpp b/src/boost/libs/histogram/test/unlimited_storage_test.cpp new file mode 100644 index 00000000..1da2601e --- /dev/null +++ b/src/boost/libs/histogram/test/unlimited_storage_test.cpp @@ -0,0 +1,501 @@ +// Copyright 2015-2017 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 <algorithm> +#include <boost/core/lightweight_test.hpp> +#include <boost/core/lightweight_test_trait.hpp> +#include <boost/histogram/detail/detect.hpp> +#include <boost/histogram/storage_adaptor.hpp> +#include <boost/histogram/unlimited_storage.hpp> +#include <boost/histogram/unsafe_access.hpp> +#include <boost/mp11.hpp> +#include <iosfwd> +#include <limits> +#include <memory> +#include <numeric> +#include <vector> +#include "std_ostream.hpp" +#include "throw_exception.hpp" +#include "utility_allocator.hpp" + +namespace boost { +namespace histogram { +namespace detail { +template <class Allocator> +std::ostream& operator<<(std::ostream& os, const large_int<Allocator>& x) { + os << "large_int"; + os << x.data; + return os; +} +} // namespace detail +} // namespace histogram +} // namespace boost + +using namespace boost::histogram; + +using unlimited_storage_type = unlimited_storage<>; +template <typename T> +using vector_storage = storage_adaptor<std::vector<T>>; +using large_int = unlimited_storage_type::large_int; + +template <typename T = std::uint8_t> +unlimited_storage_type prepare(std::size_t n, T x = T{}) { + std::unique_ptr<T[]> v(new T[n]); + std::fill(v.get(), v.get() + n, static_cast<T>(0)); + v.get()[0] = x; + return unlimited_storage_type(n, v.get()); +} + +template <class T> +auto limits_max() { + return (std::numeric_limits<T>::max)(); +} + +template <> +inline auto limits_max<large_int>() { + return large_int(limits_max<uint64_t>()); +} + +template <typename T> +void copy() { + const auto b = prepare<T>(1); + auto a(b); + BOOST_TEST(a == b); + ++a[0]; + BOOST_TEST(!(a == b)); + a = b; + BOOST_TEST(a == b); + ++a[0]; + BOOST_TEST(!(a == b)); + a = prepare<T>(2); + BOOST_TEST(!(a == b)); + a = b; + BOOST_TEST(a == b); +} + +template <typename T> +void equal_1() { + auto a = prepare(1); + auto b = prepare(1, T(0)); + BOOST_TEST_EQ(a[0], 0.0); + BOOST_TEST(a == b); + ++b[0]; + BOOST_TEST(!(a == b)); +} + +template <typename T, typename U> +void equal_2() { + auto a = prepare<T>(1); + vector_storage<U> b; + b.reset(1); + BOOST_TEST(a == b); + ++b[0]; + BOOST_TEST(!(a == b)); +} + +template <typename T> +void increase_and_grow() { + auto tmax = limits_max<T>(); + auto s = prepare(2, tmax); + auto n = s; + auto n2 = s; + + ++n[0]; + + auto x = prepare(2); + ++x[0]; + n2[0] += x[0]; + + auto v = static_cast<double>(tmax); + ++v; + BOOST_TEST_EQ(n[0], v); + BOOST_TEST_EQ(n2[0], v); + BOOST_TEST_EQ(n[1], 0.0); + BOOST_TEST_EQ(n2[1], 0.0); +} + +template <typename T> +void convert_foreign_storage() { + + { + vector_storage<T> s; + s.reset(1); + ++s[0]; + BOOST_TEST_EQ(s[0], 1); + + // test converting copy ctor + unlimited_storage_type u(s); + using buffer_t = std::decay_t<decltype(unsafe_access::unlimited_storage_buffer(u))>; + BOOST_TEST_EQ(unsafe_access::unlimited_storage_buffer(u).type, + buffer_t::template type_index<T>()); + BOOST_TEST(u == s); + BOOST_TEST_EQ(u.size(), 1u); + BOOST_TEST_EQ(u[0], 1.0); + ++s[0]; + BOOST_TEST_NOT(u == s); + } + + vector_storage<uint8_t> s; + s.reset(1); + ++s[0]; + + // test assign and equal + auto a = prepare<T>(1); + a = s; + BOOST_TEST_EQ(a[0], 1.0); + BOOST_TEST(a == s); + ++a[0]; + BOOST_TEST_NOT(a == s); + + // test radd + auto c = prepare<T>(1); + c[0] += s[0]; + BOOST_TEST_EQ(c[0], 1); + BOOST_TEST(c == s); + c[0] += s[0]; + BOOST_TEST_EQ(c[0], 2); + BOOST_TEST_NOT(c == s); + + // test assign from float + vector_storage<float> t; + t.reset(1); + t[0] = 1.5; + auto d = prepare<T>(1); + d = t; + BOOST_TEST(d == t); + BOOST_TEST(d[0] == 1.5); + + // test "copy" ctor from float + unlimited_storage_type f(t); + BOOST_TEST_EQ(f[0], 1.5); + BOOST_TEST(f == t); + + // test radd from float + auto g = prepare<T>(1); + g[0] += t[0]; + BOOST_TEST_EQ(g[0], 1.5); + BOOST_TEST(g == t); + + vector_storage<int8_t> u; + u.reset(1); + u[0] = -10; + auto h = prepare<T>(1); + BOOST_TEST_NOT(h == u); + h = u; + BOOST_TEST(h == u); + BOOST_TEST_EQ(h[0], -10); + h[0] -= u[0]; + BOOST_TEST_EQ(h[0], 0); +} + +struct adder { + template <class LHS, class RHS> + void operator()(boost::mp11::mp_list<LHS, RHS>) { + using buffer_type = + std::remove_reference_t<decltype(unsafe_access::unlimited_storage_buffer( + std::declval<unlimited_storage_type&>()))>; + constexpr auto iLHS = buffer_type::template type_index<LHS>(); + constexpr auto iRHS = buffer_type::template type_index<RHS>(); + { + auto a = prepare<LHS>(1); + BOOST_TEST_EQ(unsafe_access::unlimited_storage_buffer(a).type, iLHS); + a[0] += static_cast<RHS>(2); + // LHS is never downgraded, only upgraded to RHS. + // If RHS is normal integer, LHS doesn't change. + BOOST_TEST_EQ(unsafe_access::unlimited_storage_buffer(a).type, + iRHS < 4 ? iLHS : (std::max)(iLHS, iRHS)); + BOOST_TEST_EQ(a[0], 2); + } + { + auto a = prepare<LHS>(1); + a[0] += 2; + BOOST_TEST_EQ(a[0], 2); + // subtracting converts to double + a[0] -= 2; + BOOST_TEST_EQ(unsafe_access::unlimited_storage_buffer(a).type, 5); + BOOST_TEST_EQ(a[0], 0); + } + { + auto a = prepare<LHS>(1); + auto b = prepare<RHS>(1, static_cast<RHS>(2u)); + // LHS is never downgraded, only upgraded to RHS. + // If RHS is normal integer, LHS doesn't change. + a[0] += b[0]; + BOOST_TEST_EQ(unsafe_access::unlimited_storage_buffer(a).type, + iRHS < 4 ? iLHS : (std::max)(iLHS, iRHS)); + BOOST_TEST_EQ(a[0], 2); + a[0] -= b[0]; + BOOST_TEST_EQ(a[0], 0); + a[0] -= b[0]; + BOOST_TEST_EQ(a[0], -2); + } + { + auto a = prepare<LHS>(1); + auto b = limits_max<RHS>(); + // LHS is never downgraded, only upgraded to RHS. + // If RHS is normal integer, LHS doesn't change. + a[0] += b; + // BOOST_TEST_EQ(unsafe_access::unlimited_storage_buffer(a).type, + // iRHS < 4 ? iLHS : std::max(iLHS, iRHS)); + BOOST_TEST_EQ(a[0], limits_max<RHS>()); + a[0] += prepare<RHS>(1, b)[0]; + // BOOST_TEST_EQ(unsafe_access::unlimited_storage_buffer(a).type, + // iRHS < 4 ? iLHS + 1 : std::max(iLHS, iRHS)); + BOOST_TEST_EQ(a[0], 2 * double(limits_max<RHS>())); + } + } +}; + +int main() { + // empty state + { + unlimited_storage_type a; + BOOST_TEST_EQ(a.size(), 0); + } + + // copy + { + copy<uint8_t>(); + copy<uint16_t>(); + copy<uint32_t>(); + copy<uint64_t>(); + copy<large_int>(); + copy<double>(); + } + + // equal_operator + { + equal_1<uint8_t>(); + equal_1<uint16_t>(); + equal_1<uint32_t>(); + equal_1<uint64_t>(); + equal_1<large_int>(); + equal_1<double>(); + + equal_2<uint8_t, unsigned>(); + equal_2<uint16_t, unsigned>(); + equal_2<uint32_t, unsigned>(); + equal_2<uint64_t, unsigned>(); + equal_2<large_int, unsigned>(); + equal_2<double, unsigned>(); + + equal_2<large_int, double>(); + + auto a = prepare<double>(1); + auto b = prepare<large_int>(1); + BOOST_TEST(a == b); + ++a[0]; + BOOST_TEST_NOT(a == b); + } + + // increase_and_grow + { + increase_and_grow<uint8_t>(); + increase_and_grow<uint16_t>(); + increase_and_grow<uint32_t>(); + increase_and_grow<uint64_t>(); + + // only increase for large_int + auto a = prepare<large_int>(2, static_cast<large_int>(1)); + BOOST_TEST_EQ(a[0], 1); + BOOST_TEST_EQ(a[1], 0); + ++a[0]; + BOOST_TEST_EQ(a[0], 2); + BOOST_TEST_EQ(a[1], 0); + } + + // add + { + using namespace boost::mp11; + using L = mp_list<uint8_t, uint16_t, uint64_t, large_int, double>; + mp_for_each<mp_product<mp_list, L, L>>(adder()); + } + + // add_and_grow + { + auto a = prepare(1); + a[0] += a[0]; + BOOST_TEST_EQ(a[0], 0); + ++a[0]; + double x = 1; + auto b = prepare(1); + ++b[0]; + BOOST_TEST_EQ(b[0], x); + for (unsigned i = 0; i < 80; ++i) { + x += x; + a[0] += a[0]; + b[0] += b[0]; + BOOST_TEST_EQ(a[0], x); + BOOST_TEST_EQ(b[0], x); + auto c = prepare(1); + c[0] += a[0]; + BOOST_TEST_EQ(c[0], x); + c[0] += 0; + BOOST_TEST_EQ(c[0], x); + auto d = prepare(1); + d[0] += x; + BOOST_TEST_EQ(d[0], x); + } + } + + // multiply + { + auto a = prepare(2); + ++a[0]; + a *= 3; + BOOST_TEST_EQ(a[0], 3); + BOOST_TEST_EQ(a[1], 0); + a[1] += 2; + a *= 3; + BOOST_TEST_EQ(a[0], 9); + BOOST_TEST_EQ(a[1], 6); + } + + // convert_foreign_storage + { + convert_foreign_storage<uint8_t>(); + convert_foreign_storage<uint16_t>(); + convert_foreign_storage<uint32_t>(); + convert_foreign_storage<uint64_t>(); + convert_foreign_storage<large_int>(); + convert_foreign_storage<double>(); + } + + // reference + { + auto a = prepare(1); + auto b = prepare<uint32_t>(1); + BOOST_TEST_EQ(a[0], b[0]); + BOOST_TEST_GE(a[0], b[0]); + BOOST_TEST_LE(a[0], b[0]); + a[0] = 1; + BOOST_TEST_NE(a[0], b[0]); + BOOST_TEST_LT(b[0], a[0]); + BOOST_TEST_GT(a[0], b[0]); + BOOST_TEST_EQ(a[0], 1); + BOOST_TEST_GE(a[0], 1); + BOOST_TEST_LE(a[0], 1); + BOOST_TEST_NE(a[0], 2); + BOOST_TEST_GT(2, a[0]); + BOOST_TEST_LT(0, a[0]); + BOOST_TEST_GE(1, a[0]); + BOOST_TEST_GE(2, a[0]); + BOOST_TEST_LE(0, a[0]); + BOOST_TEST_LE(1, a[0]); + BOOST_TEST_EQ(1, a[0]); + BOOST_TEST_NE(2, a[0]); + + ++b[0]; + BOOST_TEST_EQ(a[0], b[0]); + b[0] += 2; + a[0] = b[0]; + BOOST_TEST_EQ(a[0], 3); + a[0] -= 10; + BOOST_TEST_EQ(a[0], -7); + auto c = prepare(2); + c[0] = c[1] = 1; + BOOST_TEST_EQ(c[0], 1); + BOOST_TEST_EQ(c[1], 1); + + auto d = prepare(2); + d[1] = unlimited_storage_type::large_int{2}; + BOOST_TEST_EQ(unsafe_access::unlimited_storage_buffer(d).type, 4); + d[0] = -2; + BOOST_TEST_EQ(unsafe_access::unlimited_storage_buffer(d).type, 5); + BOOST_TEST_EQ(d[0], -2); + BOOST_TEST_EQ(d[1], 2); + + BOOST_TEST_TRAIT_TRUE((detail::has_operator_preincrement<decltype(d[0])>)); + } + + // iterators + { + using iterator = typename unlimited_storage_type::iterator; + using value_type = typename std::iterator_traits<iterator>::value_type; + using reference = typename std::iterator_traits<iterator>::reference; + + BOOST_TEST_TRAIT_SAME(value_type, double); + BOOST_TEST_TRAIT_FALSE((std::is_same<reference, double&>)); + + auto a = prepare(2); + for (auto&& x : a) BOOST_TEST_EQ(x, 0); + + std::vector<double> b(2, 1); + std::copy(b.begin(), b.end(), a.begin()); + + const auto& aconst = a; + BOOST_TEST(std::equal(aconst.begin(), aconst.end(), b.begin(), b.end())); + + unlimited_storage_type::iterator it1 = a.begin(); + BOOST_TEST_EQ(*it1, 1); + *it1 = 3; + BOOST_TEST_EQ(*it1, 3); + unlimited_storage_type::const_iterator it2 = a.begin(); + BOOST_TEST_EQ(*it2, 3); + unlimited_storage_type::const_iterator it3 = aconst.begin(); + BOOST_TEST_EQ(*it3, 3); + + std::copy(b.begin(), b.end(), a.begin()); + std::partial_sum(a.begin(), a.end(), a.begin()); + BOOST_TEST_EQ(a[0], 1); + BOOST_TEST_EQ(a[1], 2); + } + + // memory exhaustion + { + using S = unlimited_storage<tracing_allocator<char>>; + using alloc_t = typename S::allocator_type; + { + // check that large_int allocates in ctor + tracing_allocator_db db; + typename S::large_int li{1, alloc_t{db}}; + BOOST_TEST_GT(db.first, 0); + } + + tracing_allocator_db db; + // db.tracing = true; // uncomment this to monitor allocator activity + S s(alloc_t{db}); + s.reset(10); // should work + BOOST_TEST_EQ(db.at<uint8_t>().first, 10); + +#ifndef BOOST_NO_EXCEPTIONS + db.failure_countdown = 0; + BOOST_TEST_THROWS(s.reset(5), std::bad_alloc); + // storage must be still in valid state + BOOST_TEST_EQ(s.size(), 0); + auto& buffer = unsafe_access::unlimited_storage_buffer(s); + BOOST_TEST_EQ(buffer.ptr, nullptr); + BOOST_TEST_EQ(buffer.type, 0); + // all allocated memory should have returned + BOOST_TEST_EQ(db.first, 0); + + // test failure in buffer.make<large_int>(n, iter), AT::construct + s.reset(3); + s[1] = (std::numeric_limits<std::uint64_t>::max)(); + db.failure_countdown = 2; + const auto old_ptr = buffer.ptr; + BOOST_TEST_THROWS(++s[1], std::bad_alloc); + + // storage remains in previous state + BOOST_TEST_EQ(buffer.size, 3); + BOOST_TEST_EQ(buffer.ptr, old_ptr); + BOOST_TEST_EQ(buffer.type, 3); + + // test buffer.make<large_int>(n), AT::construct, called by serialization code + db.failure_countdown = 1; + BOOST_TEST_THROWS(buffer.make<typename S::large_int>(2), std::bad_alloc); + + // storage still in valid state + BOOST_TEST_EQ(s.size(), 0); + BOOST_TEST_EQ(buffer.ptr, nullptr); + BOOST_TEST_EQ(buffer.type, 0); + // all memory returned + BOOST_TEST_EQ(db.first, 0); +#endif + } + + return boost::report_errors(); +} diff --git a/src/boost/libs/histogram/test/utility_allocator.hpp b/src/boost/libs/histogram/test/utility_allocator.hpp new file mode 100644 index 00000000..60745d0e --- /dev/null +++ b/src/boost/libs/histogram/test/utility_allocator.hpp @@ -0,0 +1,131 @@ +// Copyright 2018 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 <algorithm> +#include <boost/config.hpp> +#include <boost/core/lightweight_test.hpp> +#include <boost/core/typeinfo.hpp> +#include <boost/histogram/detail/type_name.hpp> +#include <boost/throw_exception.hpp> +#include <iostream> +#include <unordered_map> +#include <utility> + +struct tracing_allocator_db : std::pair<int, int> { + template <class T> + auto& at() { + return map_[&BOOST_CORE_TYPEID(T)]; + } + + void clear() { + map_.clear(); + this->first = 0; + this->second = 0; + } + + int failure_countdown = -1; + bool tracing = false; + + template <class... Ts> + void log(Ts&&... ts) { + if (!tracing) return; + log_impl(std::forward<Ts>(ts)...); + std::cerr << std::endl; + } + + std::size_t size() const { return map_.size(); } + +private: + using map_t = std::unordered_map<const boost::core::typeinfo*, std::pair<int, int>>; + map_t map_; + + BOOST_ATTRIBUTE_UNUSED inline void log_impl() {} + + template <class T, class... Ts> + void log_impl(T&& t, Ts&&... ts) { + std::cerr << t; + log_impl(std::forward<Ts>(ts)...); + } +}; + +template <class T> +struct tracing_allocator { + using value_type = T; + + tracing_allocator_db* db = nullptr; + + tracing_allocator() noexcept = default; + tracing_allocator(const tracing_allocator&) noexcept = default; + tracing_allocator(tracing_allocator&&) noexcept = default; + + tracing_allocator(tracing_allocator_db& x) noexcept : db(&x) {} + template <class U> + tracing_allocator(const tracing_allocator<U>& a) noexcept : db(a.db) {} + template <class U> + tracing_allocator& operator=(const tracing_allocator<U>& a) noexcept { + db = a.db; + return *this; + } + ~tracing_allocator() noexcept {} + + T* allocate(std::size_t n) { + if (db) { + if (db->failure_countdown >= 0) { + const auto count = db->failure_countdown--; + db->log("allocator +", n, " ", boost::histogram::detail::type_name<T>(), + " [failure in ", count, "]"); + if (count == 0) BOOST_THROW_EXCEPTION(std::bad_alloc{}); + } else + db->log("allocator +", n, " ", boost::histogram::detail::type_name<T>()); + auto& p = db->at<T>(); + p.first += static_cast<int>(n); + p.second += static_cast<int>(n); + db->first += static_cast<int>(n * sizeof(T)); + db->second += static_cast<int>(n * sizeof(T)); + } + return static_cast<T*>(::operator new(n * sizeof(T))); + } + + void deallocate(T* p, std::size_t n) { + if (db) { + db->at<T>().first -= static_cast<int>(n); + db->first -= static_cast<int>(n * sizeof(T)); + db->log("allocator -", n, " ", boost::histogram::detail::type_name<T>()); + } + ::operator delete((void*)p); + } + + template <class... Ts> + void construct(T* p, Ts&&... ts) { + if (db) { + if (db->failure_countdown >= 0) { + const auto count = db->failure_countdown--; + db->log("allocator construct ", boost::histogram::detail::type_name<T>(), + "[ failure in ", count, "]"); + if (count == 0) BOOST_THROW_EXCEPTION(std::bad_alloc{}); + } else + db->log("allocator construct ", boost::histogram::detail::type_name<T>()); + } + ::new (static_cast<void*>(p)) T(std::forward<Ts>(ts)...); + } + + void destroy(T* p) { + if (db) db->log("allocator destroy ", boost::histogram::detail::type_name<T>()); + p->~T(); + } +}; + +template <class T, class U> +constexpr bool operator==(const tracing_allocator<T>&, + const tracing_allocator<U>&) noexcept { + return true; +} + +template <class T, class U> +constexpr bool operator!=(const tracing_allocator<T>& t, + const tracing_allocator<U>& u) noexcept { + return !operator==(t, u); +} diff --git a/src/boost/libs/histogram/test/utility_axis.hpp b/src/boost/libs/histogram/test/utility_axis.hpp new file mode 100644 index 00000000..89250270 --- /dev/null +++ b/src/boost/libs/histogram/test/utility_axis.hpp @@ -0,0 +1,37 @@ +// Copyright 2018-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) + +#ifndef BOOST_HISTOGRAM_TEST_UTILITY_AXIS_HPP +#define BOOST_HISTOGRAM_TEST_UTILITY_AXIS_HPP + +#include <boost/core/lightweight_test.hpp> +#include <boost/histogram/fwd.hpp> + +namespace boost { +namespace histogram { + +template <typename Axis> +void test_axis_iterator(const Axis& a, int begin, int end) { + for (auto bin : a) { + BOOST_TEST_EQ(bin, a.bin(begin)); + ++begin; + } + BOOST_TEST_EQ(begin, end); + auto rit = a.rbegin(); + for (; rit != a.rend(); ++rit) { + --begin; + BOOST_TEST_EQ(*rit, a.bin(begin)); + } +} + +namespace axis { +bool operator==(const null_type&, const null_type&) { return true; } +} // namespace axis + +} // namespace histogram +} // namespace boost + +#endif diff --git a/src/boost/libs/histogram/test/utility_histogram.hpp b/src/boost/libs/histogram/test/utility_histogram.hpp new file mode 100644 index 00000000..e8aa9a68 --- /dev/null +++ b/src/boost/libs/histogram/test/utility_histogram.hpp @@ -0,0 +1,60 @@ +// Copyright 2018 Hans Dembinski +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt +// or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_HISTOGRAM_TEST_UTILITY_HISTOGRAM_HPP +#define BOOST_HISTOGRAM_TEST_UTILITY_HISTOGRAM_HPP + +#include <boost/histogram/axis/category.hpp> +#include <boost/histogram/axis/integer.hpp> +#include <boost/histogram/axis/regular.hpp> +#include <boost/histogram/axis/variable.hpp> +#include <boost/histogram/axis/variant.hpp> +#include <boost/histogram/make_histogram.hpp> +#include <boost/mp11/algorithm.hpp> +#include <type_traits> +#include <vector> + +namespace boost { +namespace histogram { + +template <typename... Ts> +auto make_axis_vector(const Ts&... ts) { + // make sure the variant is never trivial (contains only one type) + using R = axis::regular<double, boost::use_default, axis::null_type>; + using I = axis::integer<int, axis::null_type, axis::option::none_t>; + using V = axis::variable<double, axis::null_type>; + using C = axis::category<int, axis::null_type>; + using Var = boost::mp11::mp_unique<axis::variant<Ts..., R, I, V, C>>; + return std::vector<Var>({Var(ts)...}); +} + +using static_tag = std::false_type; +using dynamic_tag = std::true_type; + +template <typename... Axes> +auto make(static_tag, const Axes&... axes) { + return make_histogram(axes...); +} + +template <typename S, typename... Axes> +auto make_s(static_tag, S&& s, const Axes&... axes) { + return make_histogram_with(s, axes...); +} + +template <typename... Axes> +auto make(dynamic_tag, const Axes&... axes) { + return make_histogram(make_axis_vector(axes...)); +} + +template <typename S, typename... Axes> +auto make_s(dynamic_tag, S&& s, const Axes&... axes) { + return make_histogram_with(s, make_axis_vector(axes...)); +} + +} // namespace histogram +} // namespace boost + +#endif diff --git a/src/boost/libs/histogram/test/utility_iterator.hpp b/src/boost/libs/histogram/test/utility_iterator.hpp new file mode 100644 index 00000000..c1168741 --- /dev/null +++ b/src/boost/libs/histogram/test/utility_iterator.hpp @@ -0,0 +1,229 @@ +// Copyright 2003 David Abrahams and Jeremy Siek +// 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) + +#ifndef BOOST_HISTOGRAM_TEST_ITERATOR_TESTS_HPP +#define BOOST_HISTOGRAM_TEST_ITERATOR_TESTS_HPP + +// This file contains adapted code from +// - boost::core::iterator; boost/pending/iterator_tests.hpp +// - boost::core::conversion; boost/implicit_cast.hpp + +#include <boost/core/ignore_unused.hpp> +#include <boost/core/lightweight_test.hpp> +#include <iterator> +#include <type_traits> + +namespace boost { +namespace histogram { + +namespace detail { +template <class T> +struct icast_identity { + typedef T type; +}; +} // namespace detail + +template <typename T> +inline T implicit_cast(typename detail::icast_identity<T>::type x) { + return x; +} + +// use this for the value type +struct dummyT { + dummyT() {} + dummyT(char) {} + dummyT(int x) : m_x(x) {} + int foo() const { return m_x; } + bool operator==(const dummyT& d) const { return m_x == d.m_x; } + int m_x; +}; + +// Tests whether type Iterator satisfies the requirements for a +// TrivialIterator. +// Preconditions: i != j, *i == val +template <class Iterator, class T> +void trivial_iterator_test(const Iterator i, const Iterator j, T val) { + Iterator k; + BOOST_TEST(i == i); + BOOST_TEST(j == j); + BOOST_TEST(i != j); + typename std::iterator_traits<Iterator>::value_type v = *i; + BOOST_TEST(v == val); + ignore_unused(v); + BOOST_TEST(v == i->foo()); + k = i; + BOOST_TEST(k == k); + BOOST_TEST(k == i); + BOOST_TEST(k != j); + BOOST_TEST(*k == val); + ignore_unused(k); +} + +// Preconditions: i != j +template <class Iterator, class T> +void mutable_trivial_iterator_test(const Iterator i, const Iterator j, T val) { + *i = val; + trivial_iterator_test(i, j, val); +} + +// Preconditions: *i == v1, *++i == v2 +template <class Iterator, class T> +void input_iterator_test(Iterator i, T v1, T v2) { + Iterator i1(i); + + BOOST_TEST(i == i1); + BOOST_TEST(!(i != i1)); + + // I can see no generic way to create an input iterator + // that is in the domain of== of i and != i. + // The following works for istream_iterator but is not + // guaranteed to work for arbitrary input iterators. + // + // Iterator i2; + // + // BOOST_TEST(i != i2); + // BOOST_TEST(!(i == i2)); + + BOOST_TEST(*i1 == v1); + BOOST_TEST(*i == v1); + + // we cannot test for equivalence of (void)++i & (void)i++ + // as i is only guaranteed to be single pass. + BOOST_TEST(*i++ == v1); + ignore_unused(i1); + + i1 = i; + + BOOST_TEST(i == i1); + BOOST_TEST(!(i != i1)); + + BOOST_TEST(*i1 == v2); + BOOST_TEST(*i == v2); + ignore_unused(i1); + + // i is dereferencable, so it must be incrementable. + ++i; + + // how to test for operator-> ? +} + +template <class Iterator, class T> +void forward_iterator_test(Iterator i, T v1, T v2) { + input_iterator_test(i, v1, v2); + + Iterator i1 = i, i2 = i; + + BOOST_TEST(i == i1++); + BOOST_TEST(i != ++i2); + + trivial_iterator_test(i, i1, v1); + trivial_iterator_test(i, i2, v1); + + ++i; + BOOST_TEST(i == i1); + BOOST_TEST(i == i2); + ++i1; + ++i2; + + trivial_iterator_test(i, i1, v2); + trivial_iterator_test(i, i2, v2); + + typedef typename std::iterator_traits<Iterator>::reference reference; + typedef typename std::iterator_traits<Iterator>::value_type value_type; + BOOST_TEST(std::is_reference<reference>::value); + BOOST_TEST((std::is_same<reference, value_type&>::value || + std::is_same<reference, const value_type&>::value)); +} + +// Preconditions: *i == v1, *++i == v2 +template <class Iterator, class T> +void bidirectional_iterator_test(Iterator i, T v1, T v2) { + forward_iterator_test(i, v1, v2); + ++i; + + Iterator i1 = i, i2 = i; + + BOOST_TEST(i == i1--); + BOOST_TEST(i != --i2); + + trivial_iterator_test(i, i1, v2); + trivial_iterator_test(i, i2, v2); + + --i; + BOOST_TEST(i == i1); + BOOST_TEST(i == i2); + ++i1; + ++i2; + + trivial_iterator_test(i, i1, v1); + trivial_iterator_test(i, i2, v1); +} + +// mutable_bidirectional_iterator_test + +template <class U> +struct undefined; + +// Preconditions: [i,i+N) is a valid range +template <class Iterator, class TrueVals> +void random_access_iterator_test(Iterator i, int N, TrueVals vals) { + bidirectional_iterator_test(i, vals[0], vals[1]); + const Iterator j = i; + int c; + + typedef typename std::iterator_traits<Iterator>::value_type value_type; + ignore_unused<value_type>(); + + for (c = 0; c < N - 1; ++c) { + BOOST_TEST(i == j + c); + BOOST_TEST(*i == vals[c]); + BOOST_TEST(*i == implicit_cast<value_type>(j[c])); + BOOST_TEST(*i == *(j + c)); + BOOST_TEST(*i == *(c + j)); + ++i; + BOOST_TEST(i > j); + BOOST_TEST(i >= j); + BOOST_TEST(j <= i); + BOOST_TEST(j < i); + } + + Iterator k = j + N - 1; + for (c = 0; c < N - 1; ++c) { + BOOST_TEST(i == k - c); + BOOST_TEST(*i == vals[N - 1 - c]); + BOOST_TEST(*i == implicit_cast<value_type>(j[N - 1 - c])); + Iterator q = k - c; + ignore_unused(q); + BOOST_TEST(*i == *q); + BOOST_TEST(i > j); + BOOST_TEST(i >= j); + BOOST_TEST(j <= i); + BOOST_TEST(j < i); + --i; + } +} + +// Precondition: i != j +template <class Iterator, class ConstIterator> +void const_nonconst_iterator_test(Iterator i, ConstIterator j) { + BOOST_TEST(i != j); + BOOST_TEST(j != i); + + ConstIterator k(i); + BOOST_TEST(k == i); + BOOST_TEST(i == k); + + k = i; + BOOST_TEST(k == i); + BOOST_TEST(i == k); + ignore_unused(k); +} + +} // namespace histogram +} // namespace boost + +#endif // BOOST_HISTOGRAM_TEST_ITERATOR_TESTS_HPP diff --git a/src/boost/libs/histogram/test/utility_serialization.hpp b/src/boost/libs/histogram/test/utility_serialization.hpp new file mode 100644 index 00000000..735add6a --- /dev/null +++ b/src/boost/libs/histogram/test/utility_serialization.hpp @@ -0,0 +1,54 @@ +// 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) + +#ifndef BOOST_HISTOGRAM_TEST_UTILITY_SERIALIZATION_HPP +#define BOOST_HISTOGRAM_TEST_UTILITY_SERIALIZATION_HPP + +#include <boost/archive/xml_iarchive.hpp> +#include <boost/archive/xml_oarchive.hpp> +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/core/nvp.hpp> +#include <fstream> +#include <iostream> +#include <string> + +std::string join(const char* a, const char* b) { + std::string filename = a; + filename += +#ifdef BOOST_WINDOWS + "\\"; +#else + "/"; +#endif + filename += b; + return filename; +} + +template <class T> +void load_xml(const std::string& filename, T& t) { + std::ifstream ifs(filename); + BOOST_ASSERT(ifs.is_open()); + // manually skip XML comments at the beginning of the stream, because of + // https://github.com/boostorg/serialization/issues/169 + char line[128]; + do { + ifs.getline(line, 128); + BOOST_ASSERT(std::strlen(line) < 127); + } while (!ifs.fail() && !ifs.eof() && std::strstr(line, "-->") == nullptr); + boost::archive::xml_iarchive ia(ifs); + ia >> boost::make_nvp("item", t); +} + +template <class T> +void print_xml(const std::string& filename, const T& t) { + std::cout << filename << "\n"; + boost::archive::xml_oarchive oa(std::cout); + oa << boost::make_nvp("item", t); + std::cout << std::flush; +} + +#endif diff --git a/src/boost/libs/histogram/test/utility_str.hpp b/src/boost/libs/histogram/test/utility_str.hpp new file mode 100644 index 00000000..a7f67275 --- /dev/null +++ b/src/boost/libs/histogram/test/utility_str.hpp @@ -0,0 +1,20 @@ +// 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) + +#ifndef BOOST_HISTOGRAM_TEST_UTILITY_STR_HPP +#define BOOST_HISTOGRAM_TEST_UTILITY_STR_HPP + +#include <sstream> +#include <string> + +template <class T> +std::string str(const T& t) { + std::ostringstream os; + os << t; + return os.str(); +} + +#endif diff --git a/src/boost/libs/histogram/test/utility_test.cpp b/src/boost/libs/histogram/test/utility_test.cpp new file mode 100644 index 00000000..f2e7fec3 --- /dev/null +++ b/src/boost/libs/histogram/test/utility_test.cpp @@ -0,0 +1,53 @@ +// Copyright 2018 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/core/lightweight_test.hpp> +#include "throw_exception.hpp" +#include <sstream> +#include <tuple> +#include <vector> +#include "utility_allocator.hpp" +#include "std_ostream.hpp" + +using namespace boost::histogram; + +int main() { + // vector streaming + { + std::ostringstream os; + std::vector<int> v = {1, 3, 2}; + os << v; + BOOST_TEST_EQ(os.str(), std::string("[ 1 3 2 ]")); + } + + // tuple streaming + { + std::ostringstream os; + auto v = std::make_tuple(1, 2.5, "hi"); + os << v; + BOOST_TEST_EQ(os.str(), std::string("[ 1 2.5 hi ]")); + } + + // tracing_allocator + { + tracing_allocator_db db; + tracing_allocator<char> a(db); + auto p1 = a.allocate(2); + a.deallocate(p1, 2); + tracing_allocator<int> b(a); + auto p2 = b.allocate(3); + b.deallocate(p2, 3); + BOOST_TEST_EQ(db.size(), 2); + BOOST_TEST_EQ(db.at<char>().first, 0); + BOOST_TEST_EQ(db.at<char>().second, 2); + BOOST_TEST_EQ(db.at<int>().first, 0); + BOOST_TEST_EQ(db.at<int>().second, 3); + BOOST_TEST_EQ(db.first, 0); + BOOST_TEST_EQ(db.second, 2 + 3 * sizeof(int)); + } + + return boost::report_errors(); +} |