summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/histogram/test
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 18:24:20 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 18:24:20 +0000
commit483eb2f56657e8e7f419ab1a4fab8dce9ade8609 (patch)
treee5d88d25d870d5dedacb6bbdbe2a966086a0a5cf /src/boost/libs/histogram/test
parentInitial commit. (diff)
downloadceph-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')
-rw-r--r--src/boost/libs/histogram/test/CMakeLists.txt186
-rw-r--r--src/boost/libs/histogram/test/Jamfile159
-rw-r--r--src/boost/libs/histogram/test/accumulators_serialization_test.cpp91
-rw-r--r--src/boost/libs/histogram/test/accumulators_serialization_test_mean.xml17
-rw-r--r--src/boost/libs/histogram/test/accumulators_serialization_test_mean_v0.xml17
-rw-r--r--src/boost/libs/histogram/test/accumulators_serialization_test_sum.xml16
-rw-r--r--src/boost/libs/histogram/test/accumulators_serialization_test_weighted_mean.xml18
-rw-r--r--src/boost/libs/histogram/test/accumulators_serialization_test_weighted_sum.xml16
-rw-r--r--src/boost/libs/histogram/test/accumulators_test.cpp227
-rw-r--r--src/boost/libs/histogram/test/algorithm_empty_test.cpp65
-rw-r--r--src/boost/libs/histogram/test/algorithm_project_test.cpp193
-rw-r--r--src/boost/libs/histogram/test/algorithm_reduce_test.cpp234
-rw-r--r--src/boost/libs/histogram/test/algorithm_sum_test.cpp58
-rw-r--r--src/boost/libs/histogram/test/axis_category_fail0.cpp14
-rw-r--r--src/boost/libs/histogram/test/axis_category_fail1.cpp14
-rw-r--r--src/boost/libs/histogram/test/axis_category_fail2.cpp15
-rw-r--r--src/boost/libs/histogram/test/axis_category_test.cpp157
-rw-r--r--src/boost/libs/histogram/test/axis_integer_fail0.cpp15
-rw-r--r--src/boost/libs/histogram/test/axis_integer_fail1.cpp15
-rw-r--r--src/boost/libs/histogram/test/axis_integer_fail2.cpp15
-rw-r--r--src/boost/libs/histogram/test/axis_integer_fail3.cpp15
-rw-r--r--src/boost/libs/histogram/test/axis_integer_fail4.cpp15
-rw-r--r--src/boost/libs/histogram/test/axis_integer_test.cpp193
-rw-r--r--src/boost/libs/histogram/test/axis_option_test.cpp56
-rw-r--r--src/boost/libs/histogram/test/axis_regular_fail0.cpp14
-rw-r--r--src/boost/libs/histogram/test/axis_regular_fail1.cpp15
-rw-r--r--src/boost/libs/histogram/test/axis_regular_test.cpp281
-rw-r--r--src/boost/libs/histogram/test/axis_size.cpp34
-rw-r--r--src/boost/libs/histogram/test/axis_traits_test.cpp214
-rw-r--r--src/boost/libs/histogram/test/axis_variable_fail0.cpp14
-rw-r--r--src/boost/libs/histogram/test/axis_variable_fail1.cpp16
-rw-r--r--src/boost/libs/histogram/test/axis_variable_test.cpp162
-rw-r--r--src/boost/libs/histogram/test/axis_variant_serialization_test.cpp41
-rw-r--r--src/boost/libs/histogram/test/axis_variant_serialization_test.xml24
-rw-r--r--src/boost/libs/histogram/test/axis_variant_test.cpp250
-rw-r--r--src/boost/libs/histogram/test/boost_accumulators_support_test.cpp45
-rw-r--r--src/boost/libs/histogram/test/boost_range_support_test.cpp29
-rw-r--r--src/boost/libs/histogram/test/boost_units_support_test.cpp74
-rwxr-xr-xsrc/boost/libs/histogram/test/check_build_system.py41
-rw-r--r--src/boost/libs/histogram/test/check_cmake_version.cpp25
-rw-r--r--src/boost/libs/histogram/test/check_odr_test.py54
-rw-r--r--src/boost/libs/histogram/test/deduction_guides_test.cpp145
-rw-r--r--src/boost/libs/histogram/test/detail_accumulator_traits_test.cpp82
-rw-r--r--src/boost/libs/histogram/test/detail_args_type_test.cpp31
-rw-r--r--src/boost/libs/histogram/test/detail_argument_traits_test.cpp61
-rw-r--r--src/boost/libs/histogram/test/detail_array_wrapper_serialization_test.cpp71
-rw-r--r--src/boost/libs/histogram/test/detail_axes_test.cpp177
-rw-r--r--src/boost/libs/histogram/test/detail_convert_integer_test.cpp22
-rw-r--r--src/boost/libs/histogram/test/detail_detect_test.cpp299
-rw-r--r--src/boost/libs/histogram/test/detail_iterator_adaptor_test.cpp191
-rw-r--r--src/boost/libs/histogram/test/detail_large_int_test.cpp206
-rw-r--r--src/boost/libs/histogram/test/detail_limits_test.cpp24
-rw-r--r--src/boost/libs/histogram/test/detail_make_default_test.cpp57
-rw-r--r--src/boost/libs/histogram/test/detail_misc_test.cpp88
-rw-r--r--src/boost/libs/histogram/test/detail_operators_test.cpp143
-rw-r--r--src/boost/libs/histogram/test/detail_relaxed_equal_test.cpp27
-rw-r--r--src/boost/libs/histogram/test/detail_replace_type_test.cpp22
-rw-r--r--src/boost/libs/histogram/test/detail_safe_comparison_test.cpp60
-rw-r--r--src/boost/libs/histogram/test/detail_static_if_test.cpp33
-rw-r--r--src/boost/libs/histogram/test/detail_tuple_slice_test.cpp21
-rw-r--r--src/boost/libs/histogram/test/histogram_custom_axis_test.cpp132
-rw-r--r--src/boost/libs/histogram/test/histogram_dynamic_test.cpp123
-rw-r--r--src/boost/libs/histogram/test/histogram_fail0.cpp20
-rw-r--r--src/boost/libs/histogram/test/histogram_fail1.cpp24
-rw-r--r--src/boost/libs/histogram/test/histogram_fail2.cpp25
-rw-r--r--src/boost/libs/histogram/test/histogram_fail3.cpp23
-rw-r--r--src/boost/libs/histogram/test/histogram_fail4.cpp24
-rw-r--r--src/boost/libs/histogram/test/histogram_fill_test.cpp361
-rw-r--r--src/boost/libs/histogram/test/histogram_growing_test.cpp206
-rw-r--r--src/boost/libs/histogram/test/histogram_mixed_test.cpp83
-rw-r--r--src/boost/libs/histogram/test/histogram_operators_test.cpp174
-rw-r--r--src/boost/libs/histogram/test/histogram_ostream_test.cpp249
-rw-r--r--src/boost/libs/histogram/test/histogram_serialization_test.cpp50
-rw-r--r--src/boost/libs/histogram/test/histogram_serialization_test_dynamic.xml122
-rw-r--r--src/boost/libs/histogram/test/histogram_serialization_test_static.xml85
-rw-r--r--src/boost/libs/histogram/test/histogram_test.cpp512
-rw-r--r--src/boost/libs/histogram/test/histogram_threaded_test.cpp74
-rw-r--r--src/boost/libs/histogram/test/indexed_test.cpp170
-rw-r--r--src/boost/libs/histogram/test/is_close.hpp15
-rw-r--r--src/boost/libs/histogram/test/make_histogram_fail0.cpp14
-rw-r--r--src/boost/libs/histogram/test/make_histogram_fail1.cpp16
-rw-r--r--src/boost/libs/histogram/test/odr_main_test.cpp10
-rw-r--r--src/boost/libs/histogram/test/odr_test.cpp12
-rw-r--r--src/boost/libs/histogram/test/std_ostream.hpp40
-rw-r--r--src/boost/libs/histogram/test/storage_adaptor_serialization_test.cpp47
-rw-r--r--src/boost/libs/histogram/test/storage_adaptor_serialization_test_array_unsigned.xml23
-rw-r--r--src/boost/libs/histogram/test/storage_adaptor_serialization_test_map_double.xml30
-rw-r--r--src/boost/libs/histogram/test/storage_adaptor_serialization_test_vector_int.xml24
-rw-r--r--src/boost/libs/histogram/test/storage_adaptor_serialization_test_vector_thread_safe_int.xml29
-rw-r--r--src/boost/libs/histogram/test/storage_adaptor_test.cpp292
-rw-r--r--src/boost/libs/histogram/test/storage_adaptor_threaded_test.cpp58
-rw-r--r--src/boost/libs/histogram/test/throw_exception.hpp21
-rw-r--r--src/boost/libs/histogram/test/unlimited_storage_serialization_test.cpp57
-rw-r--r--src/boost/libs/histogram/test/unlimited_storage_serialization_test_double.xml19
-rw-r--r--src/boost/libs/histogram/test/unlimited_storage_serialization_test_large_int.xml25
-rw-r--r--src/boost/libs/histogram/test/unlimited_storage_serialization_test_u16.xml19
-rw-r--r--src/boost/libs/histogram/test/unlimited_storage_serialization_test_u32.xml19
-rw-r--r--src/boost/libs/histogram/test/unlimited_storage_serialization_test_u64.xml19
-rw-r--r--src/boost/libs/histogram/test/unlimited_storage_serialization_test_u8.xml19
-rw-r--r--src/boost/libs/histogram/test/unlimited_storage_test.cpp501
-rw-r--r--src/boost/libs/histogram/test/utility_allocator.hpp131
-rw-r--r--src/boost/libs/histogram/test/utility_axis.hpp37
-rw-r--r--src/boost/libs/histogram/test/utility_histogram.hpp60
-rw-r--r--src/boost/libs/histogram/test/utility_iterator.hpp229
-rw-r--r--src/boost/libs/histogram/test/utility_serialization.hpp54
-rw-r--r--src/boost/libs/histogram/test/utility_str.hpp20
-rw-r--r--src/boost/libs/histogram/test/utility_test.cpp53
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();
+}