├── .appveyor.yml ├── .clang-format ├── .clang_complete ├── .gitattributes ├── .github └── workflows │ ├── cov.yml │ ├── fast.yml │ ├── slow.yml │ └── superproject_cmake.yml ├── .gitignore ├── .pre-commit-config.yaml ├── CMakeLists.txt ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── benchmark ├── CMakeLists.txt ├── axis_index.cpp ├── axis_size.cpp ├── detail_normal.cpp ├── disable_cpu_scaling.sh ├── enable_cpu_scaling.sh ├── generator.hpp ├── histogram_filling.cpp ├── histogram_filling_gsl.cpp ├── histogram_filling_numpy.py ├── histogram_filling_root.cpp ├── histogram_iteration.cpp ├── histogram_parallel_filling.cpp ├── plot_benchmarks.py └── run_benchmarks.py ├── build.jam ├── doc ├── Jamfile ├── README.md ├── baseline_gcc83 ├── benchmarks.qbk ├── changelog.qbk ├── concepts.qbk ├── concepts │ ├── Accumulator.qbk │ ├── Axis.qbk │ ├── DiscreteAxis.qbk │ ├── IntervalAxis.qbk │ ├── Storage.qbk │ └── Transform.qbk ├── doxygen_postprocessing.py ├── fill_boost.json ├── fill_gsl.json ├── fill_performance.py ├── fill_performance.svg ├── fill_root.json ├── getting_started.qbk ├── guide.qbk ├── histogram.qbk ├── iteration_performance.dat ├── iteration_performance.py ├── iteration_performance.svg ├── logo │ ├── DENMARK.TTF │ ├── README │ ├── color.svg │ └── color_source.svg ├── overview.qbk ├── rationale.qbk ├── storage_3_cpp_int.svg ├── storage_3_uint16.svg ├── storage_3_uint32.svg ├── storage_3_uint64.svg ├── storage_3_uint8.svg └── storage_3_weight.svg ├── examples ├── Jamfile ├── getting_started_listing_01.cpp ├── getting_started_listing_02.cpp ├── getting_started_listing_03.cpp ├── getting_started_listing_04.cpp ├── getting_started_listing_05.cpp ├── guide_axis_basic_demo.cpp ├── guide_axis_circular.cpp ├── guide_axis_growing.cpp ├── guide_axis_with_labels.cpp ├── guide_axis_with_transform.cpp ├── guide_axis_with_uoflow_off.cpp ├── guide_custom_2d_axis.cpp ├── guide_custom_accumulators_advanced.cpp ├── guide_custom_accumulators_builtin.cpp ├── guide_custom_accumulators_ouroboros.cpp ├── guide_custom_accumulators_simple.cpp ├── guide_custom_accumulators_with_metadata.cpp ├── guide_custom_axis_multiple_value_types.cpp ├── guide_custom_minimal_axis.cpp ├── guide_custom_modified_axis.cpp ├── guide_custom_storage.cpp ├── guide_fill_histogram.cpp ├── guide_fill_profile.cpp ├── guide_fill_weighted_histogram.cpp ├── guide_fill_weighted_profile.cpp ├── guide_histogram_in_api.cpp ├── guide_histogram_operators.cpp ├── guide_histogram_projection.cpp ├── guide_histogram_reduction.cpp ├── guide_histogram_serialization.cpp ├── guide_histogram_streaming.cpp ├── guide_indexed_access.cpp ├── guide_make_dynamic_histogram.cpp ├── guide_make_static_histogram.cpp ├── guide_parallel_filling.cpp └── guide_stdlib_algorithms.cpp ├── include └── boost │ ├── histogram.hpp │ └── histogram │ ├── accumulators.hpp │ ├── accumulators │ ├── collector.hpp │ ├── count.hpp │ ├── fraction.hpp │ ├── is_thread_safe.hpp │ ├── mean.hpp │ ├── ostream.hpp │ ├── sum.hpp │ ├── weighted_mean.hpp │ └── weighted_sum.hpp │ ├── algorithm.hpp │ ├── algorithm │ ├── empty.hpp │ ├── project.hpp │ ├── reduce.hpp │ └── sum.hpp │ ├── axis.hpp │ ├── axis │ ├── boolean.hpp │ ├── category.hpp │ ├── integer.hpp │ ├── interval_view.hpp │ ├── iterator.hpp │ ├── metadata_base.hpp │ ├── option.hpp │ ├── ostream.hpp │ ├── polymorphic_bin.hpp │ ├── regular.hpp │ ├── traits.hpp │ ├── variable.hpp │ └── variant.hpp │ ├── detail │ ├── accumulator_traits.hpp │ ├── args_type.hpp │ ├── argument_traits.hpp │ ├── array_wrapper.hpp │ ├── atomic_number.hpp │ ├── axes.hpp │ ├── chunk_vector.hpp │ ├── common_type.hpp │ ├── convert_integer.hpp │ ├── counting_streambuf.hpp │ ├── debug.hpp │ ├── detect.hpp │ ├── erf_inv.hpp │ ├── fill.hpp │ ├── fill_n.hpp │ ├── ignore_deprecation_warning_begin.hpp │ ├── ignore_deprecation_warning_end.hpp │ ├── index_translator.hpp │ ├── iterator_adaptor.hpp │ ├── large_int.hpp │ ├── limits.hpp │ ├── linearize.hpp │ ├── make_default.hpp │ ├── mutex_base.hpp │ ├── nonmember_container_access.hpp │ ├── normal.hpp │ ├── operators.hpp │ ├── optional_index.hpp │ ├── priority.hpp │ ├── reduce_command.hpp │ ├── relaxed_equal.hpp │ ├── relaxed_tuple_size.hpp │ ├── replace_type.hpp │ ├── safe_comparison.hpp │ ├── square.hpp │ ├── static_if.hpp │ ├── static_vector.hpp │ ├── term_info.hpp │ ├── try_cast.hpp │ ├── tuple_slice.hpp │ ├── type_name.hpp │ └── variant_proxy.hpp │ ├── fwd.hpp │ ├── histogram.hpp │ ├── indexed.hpp │ ├── literals.hpp │ ├── make_histogram.hpp │ ├── make_profile.hpp │ ├── multi_index.hpp │ ├── ostream.hpp │ ├── sample.hpp │ ├── serialization.hpp │ ├── storage_adaptor.hpp │ ├── unlimited_storage.hpp │ ├── unsafe_access.hpp │ ├── utility │ ├── binomial_proportion_interval.hpp │ ├── clopper_pearson_interval.hpp │ ├── jeffreys_interval.hpp │ ├── wald_interval.hpp │ └── wilson_interval.hpp │ └── weight.hpp ├── index.html ├── meta └── libraries.json ├── test ├── CMakeLists.txt ├── Jamfile ├── accumulators_collector_test.cpp ├── accumulators_count_test.cpp ├── accumulators_count_thread_safe_test.cpp ├── accumulators_fraction_test.cpp ├── accumulators_mean_test.cpp ├── accumulators_serialization_test.cpp ├── accumulators_serialization_test_collector.xml ├── accumulators_serialization_test_fraction.xml ├── accumulators_serialization_test_mean.xml ├── accumulators_serialization_test_mean_v0.xml ├── accumulators_serialization_test_sum.xml ├── accumulators_serialization_test_weighted_mean.xml ├── accumulators_serialization_test_weighted_sum.xml ├── accumulators_sum_test.cpp ├── accumulators_weighted_mean_test.cpp ├── accumulators_weighted_sum_test.cpp ├── algorithm_empty_test.cpp ├── algorithm_project_test.cpp ├── algorithm_reduce_test.cpp ├── algorithm_sum_test.cpp ├── allocator.hpp ├── axis.hpp ├── axis_boolean_test.cpp ├── axis_category_fail0.cpp ├── axis_category_fail1.cpp ├── axis_category_fail2.cpp ├── axis_category_test.cpp ├── axis_integer_fail0.cpp ├── axis_integer_fail1.cpp ├── axis_integer_fail2.cpp ├── axis_integer_fail3.cpp ├── axis_integer_fail4.cpp ├── axis_integer_test.cpp ├── axis_option_test.cpp ├── axis_regular_fail0.cpp ├── axis_regular_fail1.cpp ├── axis_regular_test.cpp ├── axis_traits_test.cpp ├── axis_variable_fail0.cpp ├── axis_variable_fail1.cpp ├── axis_variable_test.cpp ├── axis_variant_serialization_test.cpp ├── axis_variant_serialization_test.xml ├── axis_variant_test.cpp ├── boost_accumulators_support_test.cpp ├── boost_range_support_test.cpp ├── boost_units_support_test.cpp ├── check_build_system.py ├── check_odr_test.py ├── deduction_guides_test.cpp ├── detail_accumulator_traits_test.cpp ├── detail_args_type_test.cpp ├── detail_argument_traits_test.cpp ├── detail_array_wrapper_serialization_test.cpp ├── detail_axes_test.cpp ├── detail_convert_integer_test.cpp ├── detail_detect_test.cpp ├── detail_erf_inv_test.cpp ├── detail_iterator_adaptor_test.cpp ├── detail_large_int_test.cpp ├── detail_limits_test.cpp ├── detail_make_default_test.cpp ├── detail_misc_test.cpp ├── detail_normal_test.cpp ├── detail_operators_test.cpp ├── detail_relaxed_equal_test.cpp ├── detail_replace_type_test.cpp ├── detail_safe_comparison_test.cpp ├── detail_static_if_test.cpp ├── detail_static_vector_and_span_test.cpp ├── detail_tuple_slice_test.cpp ├── dummy_storage.hpp ├── histogram.hpp ├── histogram_collector_test.cpp ├── histogram_custom_axis_test.cpp ├── histogram_dynamic_test.cpp ├── histogram_fail0.cpp ├── histogram_fail1.cpp ├── histogram_fail2.cpp ├── histogram_fail3.cpp ├── histogram_fail4.cpp ├── histogram_fill_test.cpp ├── histogram_fraction_test.cpp ├── histogram_growing_test.cpp ├── histogram_mixed_test.cpp ├── histogram_operators_test.cpp ├── histogram_ostream_ascii_test.cpp ├── histogram_ostream_test.cpp ├── histogram_serialization_test.cpp ├── histogram_serialization_test_dynamic.xml ├── histogram_serialization_test_static.xml ├── histogram_test.cpp ├── histogram_threaded_test.cpp ├── indexed_test.cpp ├── is_close.hpp ├── issue_290_test.cpp ├── issue_327_test.cpp ├── issue_353_test.cpp ├── iterator.hpp ├── make_histogram_fail0.cpp ├── make_histogram_fail1.cpp ├── odr_main_test.cpp ├── odr_test.cpp ├── ostream.hpp ├── quick.cpp ├── serialization.hpp ├── storage_adaptor_serialization_test.cpp ├── storage_adaptor_serialization_test_array_unsigned.xml ├── storage_adaptor_serialization_test_map_double.xml ├── storage_adaptor_serialization_test_vector_int.xml ├── storage_adaptor_serialization_test_vector_thread_safe_int.xml ├── storage_adaptor_test.cpp ├── storage_adaptor_threaded_test.cpp ├── str.hpp ├── throw_exception.hpp ├── tools_test.cpp ├── unlimited_storage_serialization_test.cpp ├── unlimited_storage_serialization_test_double.xml ├── unlimited_storage_serialization_test_large_int.xml ├── unlimited_storage_serialization_test_u16.xml ├── unlimited_storage_serialization_test_u32.xml ├── unlimited_storage_serialization_test_u64.xml ├── unlimited_storage_serialization_test_u8.xml ├── unlimited_storage_test.cpp ├── utility_binomial_proportion_interval_test.cpp ├── utility_clopper_pearson_interval_test.cpp ├── utility_jeffreys_interval_test.cpp ├── utility_wald_interval_test.cpp └── utility_wilson_interval_test.cpp └── tools ├── add_boilerplate.py ├── blacklist.supp ├── cov.py ├── crlf_to_lf.sh ├── llvm-gcov.sh └── tidy.py /.appveyor.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2017-2019 Hans Dembinski 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) 4 | 5 | shallow_clone: true 6 | max_jobs: 2 7 | 8 | image: 9 | - Visual Studio 2022 10 | 11 | branches: 12 | only: 13 | - master 14 | - develop 15 | 16 | build: off 17 | 18 | environment: 19 | B2_OPTS: -j2 -q warnings-as-errors=on 20 | 21 | install: 22 | # clone minimal set of Boost libraries 23 | - cd .. 24 | - git clone -b %APPVEYOR_REPO_BRANCH% --depth 5 https://github.com/boostorg/boost.git 25 | - cd boost 26 | - git submodule update --init --depth 5 tools/build tools/boostdep 27 | 28 | # replace Boost library with this project and install dependencies 29 | - xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\histogram\ 30 | - python tools\boostdep\depinst\depinst.py -N units -N range -N accumulators --git_args "--depth 5 --jobs 2" histogram 31 | 32 | # prepare Boost build 33 | - cmd /c bootstrap & cd libs\histogram 34 | 35 | test_script: 36 | # cxxstd=latest (aka 20) breaks VS 2022 in algorithm_project_test so we use cxxstd=17 37 | # msvc-14.3 breaks test//serialization, more precisely axis_variant_serialization_test 38 | - ..\..\b2 %B2_OPTS% cxxstd=17 test//minimal 39 | -------------------------------------------------------------------------------- /.clang_complete: -------------------------------------------------------------------------------- 1 | -Iinclude 2 | -I../../ 3 | -std=c++17 4 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behaviour, in case users don't have core.autocrlf set. 2 | * text=auto !eol 3 | 4 | # Scripts 5 | *.bat text eol=crlf 6 | *.sh text eol=lf 7 | -------------------------------------------------------------------------------- /.github/workflows/cov.yml: -------------------------------------------------------------------------------- 1 | name: Coverage 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | - develop 8 | paths-ignore: 9 | - 'doc/**' 10 | - 'examples/**' 11 | - '*.md' 12 | 13 | env: 14 | B2_OPTS: -q -j2 warnings-as-errors=on 15 | GCC_VERSION: 13 16 | 17 | concurrency: 18 | group: ${{ github.workflow }}-${{ github.head_ref }} 19 | cancel-in-progress: true 20 | 21 | jobs: 22 | cov: 23 | runs-on: ubuntu-24.04 24 | steps: 25 | - uses: actions/checkout@v4 26 | - name: Fetch Boost superproject 27 | run: | 28 | cd .. 29 | git clone -b $GITHUB_BASE_REF --depth 5 https://github.com/boostorg/boost.git 30 | cd boost 31 | mv -f $GITHUB_WORKSPACE/* libs/histogram 32 | git submodule update --init --depth 5 tools/build tools/boostdep 33 | python tools/boostdep/depinst/depinst.py --git_args "--depth 5 --jobs 3" histogram 34 | mv -f * $GITHUB_WORKSPACE 35 | 36 | - name: Prepare b2 37 | run: ./bootstrap.sh 38 | 39 | - name: Test cxxstd=latest coverage=on 40 | run: | 41 | cd libs/histogram 42 | 43 | # don't compile examples in coverage build, coverage must come from tests alone 44 | ../../b2 $B2_OPTS toolset=gcc-${GCC_VERSION} cxxstd=latest coverage=on test//all 45 | 46 | - name: Process coverage data 47 | run: | 48 | cd libs/histogram 49 | GCOV=gcov-${GCC_VERSION} tools/cov.py 50 | 51 | - uses: coverallsapp/github-action@v2 52 | with: 53 | github-token: ${{ secrets.GITHUB_TOKEN }} 54 | path-to-lcov: libs/histogram/coverage.info 55 | -------------------------------------------------------------------------------- /.github/workflows/fast.yml: -------------------------------------------------------------------------------- 1 | name: Fast 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - master 7 | - develop 8 | paths-ignore: 9 | - 'doc/**' 10 | - 'examples/**' 11 | - 'tools/**' 12 | - '*.md' 13 | push: 14 | branches: 15 | - master 16 | - develop 17 | paths-ignore: 18 | - 'doc/**' 19 | - 'examples/**' 20 | - 'tools/**' 21 | - '*.md' 22 | 23 | concurrency: 24 | group: ${{ github.workflow }}-${{ github.head_ref }} 25 | cancel-in-progress: true 26 | 27 | jobs: 28 | cmake: 29 | runs-on: ${{ matrix.os }} 30 | strategy: 31 | matrix: 32 | os: [ubuntu-latest, windows-latest, macos-latest] 33 | fail-fast: true 34 | steps: 35 | - uses: actions/checkout@v4 36 | - name: prepare build 37 | run: | 38 | mkdir build 39 | cd build 40 | cmake -DCMAKE_BUILD_TYPE=Debug .. 41 | - name: test 42 | run: | 43 | cd build 44 | cmake --build . --target check -j3 45 | -------------------------------------------------------------------------------- /.github/workflows/superproject_cmake.yml: -------------------------------------------------------------------------------- 1 | name: superproject cmake 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - develop 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.head_ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | build: 15 | runs-on: macos-latest 16 | steps: 17 | - uses: actions/checkout@v4 18 | - name: Fetch Boost superproject 19 | run: | 20 | cd .. 21 | git clone -b $GITHUB_BASE_REF --depth 5 https://github.com/boostorg/boost.git 22 | cd boost 23 | git submodule update --init --depth 5 24 | rm -rf libs/histogram/* 25 | mv -f $GITHUB_WORKSPACE/* libs/histogram 26 | mv -f * $GITHUB_WORKSPACE 27 | - name: CMake from superproject 28 | run: | 29 | cd .. 30 | cmake -DBoost_VERBOSE=1 $GITHUB_WORKSPACE 31 | cmake --build . --target all -j3 -- -k 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build* 2 | *.gcov 3 | doc/html 4 | doc/reference.xml 5 | doc/reference_pp.xml 6 | __pycache__ 7 | *.pyc 8 | .DS_Store 9 | .vs* 10 | *.info 11 | tools/lcov-* 12 | tools/codecov 13 | coverage-report 14 | .cache 15 | venv 16 | .pytest_cache 17 | !*.jam 18 | *.vcxproj 19 | *.vcxproj.filters 20 | *.sln 21 | BoostFetch.cmake 22 | cmake_install.cmake 23 | CMakeCache.txt 24 | CMakeFiles 25 | *.cmake 26 | DartConfiguration.tcl 27 | _deps 28 | *.obj 29 | *.recipe 30 | *.ilk 31 | *.pdb 32 | *.lastbuildstate 33 | *.tlog 34 | *.exe 35 | CTestCostData.txt 36 | LastTest.log -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # To use: 2 | # 3 | # pre-commit run -a 4 | # 5 | # Or: 6 | # 7 | # pre-commit install # (runs every time you commit in git) 8 | # 9 | # To update this file: 10 | # 11 | # pre-commit autoupdate 12 | # 13 | # See https://github.com/pre-commit/pre-commit 14 | 15 | repos: 16 | # Standard hooks 17 | - repo: https://github.com/pre-commit/pre-commit-hooks 18 | rev: v4.1.0 19 | hooks: 20 | - id: check-case-conflict 21 | - id: check-docstring-first 22 | - id: check-executables-have-shebangs 23 | - id: check-merge-conflict 24 | - id: check-symlinks 25 | - id: check-yaml 26 | args: ["--allow-multiple-documents"] 27 | - id: debug-statements 28 | - id: mixed-line-ending 29 | - id: sort-simple-yaml 30 | - id: file-contents-sorter 31 | - id: trailing-whitespace 32 | exclude: .*.(xml?)|(svg?) 33 | 34 | # C++ formatting 35 | - repo: https://github.com/pre-commit/mirrors-clang-format 36 | rev: v13.0.1 37 | hooks: 38 | - id: clang-format 39 | types_or: [c++, c] 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /benchmark/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Hans Dembinski 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt 4 | 5 | include(BoostFetch) 6 | 7 | # setup for google benchmark 8 | set(CMAKE_BUILD_TYPE Release) # ok, only set in local scope 9 | option(BENCHMARK_ENABLE_TESTING "" OFF) 10 | boost_fetch(google/benchmark TAG main) 11 | boost_fetch(boostorg/math TAG develop EXCLUDE_FROM_ALL) 12 | 13 | function(add_benchmark NAME) 14 | 15 | cmake_parse_arguments(PARSE_ARGV 1 _ "" "" ";INCLUDE_DIRECTORIES;LINK_LIBRARIES;COMPILE_OPTIONS") 16 | 17 | if(__UNPARSED_ARGUMENTS) 18 | message(AUTHOR_WARNING "add_benchmark: extra arguments ignored: ${__UNPARSED_ARGUMENTS}") 19 | endif() 20 | 21 | set(SOURCE ${NAME}.cpp) 22 | set(NAME benchmark_${NAME}) 23 | 24 | if(DEFINED BUILD_TESTING AND NOT BUILD_TESTING) 25 | return() 26 | endif() 27 | 28 | add_executable(${NAME} ${SOURCE}) 29 | target_include_directories(${NAME} PRIVATE ${__INCLUDE_DIRECTORIES}) 30 | target_link_libraries(${NAME} PRIVATE Boost::histogram Boost::math benchmark_main ${__LINK_LIBRARIES}) 31 | target_compile_options(${NAME} PRIVATE -DNDEBUG -O3 -funsafe-math-optimizations ${__COMPILE_OPTIONS}) 32 | if (NOT DARWIN) 33 | target_compile_options(${NAME} PRIVATE -march=native) 34 | endif() 35 | endfunction() 36 | 37 | add_benchmark(axis_size) 38 | add_benchmark(axis_index) 39 | add_benchmark(histogram_filling) 40 | add_benchmark(histogram_iteration) 41 | add_benchmark(detail_normal) 42 | 43 | find_package(Threads) 44 | if (Threads_FOUND) 45 | add_benchmark(histogram_parallel_filling) 46 | endif() 47 | 48 | find_package(GSL) 49 | if (GSL_FOUND) 50 | add_benchmark( 51 | histogram_filling_gsl 52 | INCLUDE_DIRECTORIES ${GSL_INCLUDE_DIRS} 53 | LINK_LIBRARIES ${GSL_LIBRARIES}) 54 | endif() 55 | 56 | find_package(ROOT QUIET) 57 | if (ROOT_FOUND) 58 | add_benchmark( 59 | histogram_filling_root 60 | INCLUDE_DIRECTORIES ${ROOT_INCLUDE_DIRS} 61 | LINK_LIBRARIES ${ROOT_LIBRARIES} 62 | COMPILE_OPTIONS -frtti -fexceptions 63 | ) 64 | # add ROOT linker flags? ${ROOT_EXE_LINKER_FLAGS} 65 | endif() 66 | -------------------------------------------------------------------------------- /benchmark/axis_size.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | 10 | #define SHOW_SIZE(x) std::cout << #x << " " << sizeof(x) << std::endl 11 | 12 | int main() { 13 | using namespace boost::histogram; 14 | 15 | using regular = axis::regular<>; 16 | using regular_float = axis::regular; 17 | using regular_pow = axis::regular; 18 | using regular_no_metadata = axis::regular; 19 | using circular = axis::circular<>; 20 | using variable = axis::variable<>; 21 | using integer = axis::integer<>; 22 | using category = axis::category<>; 23 | using boolean = axis::boolean<>; 24 | using boolean_no_metadata = axis::boolean; 25 | using variant = axis::variant; 26 | 27 | SHOW_SIZE(regular); 28 | SHOW_SIZE(regular_float); 29 | SHOW_SIZE(regular_pow); 30 | SHOW_SIZE(regular_no_metadata); 31 | SHOW_SIZE(circular); 32 | SHOW_SIZE(variable); 33 | SHOW_SIZE(integer); 34 | SHOW_SIZE(category); 35 | SHOW_SIZE(boolean); 36 | SHOW_SIZE(boolean_no_metadata); 37 | SHOW_SIZE(variant); 38 | } 39 | -------------------------------------------------------------------------------- /benchmark/detail_normal.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include "../test/throw_exception.hpp" 11 | #include "generator.hpp" 12 | 13 | namespace bm = boost::math; 14 | using namespace boost::histogram::detail; 15 | 16 | #include 17 | struct assert_check { 18 | assert_check() { 19 | assert(false); // don't run with asserts enabled 20 | } 21 | } _; 22 | 23 | static void math_cdf(benchmark::State& state) { 24 | generator gen; 25 | bm::normal norm; 26 | for (auto _ : state) benchmark::DoNotOptimize(cdf(norm, gen())); 27 | state.SetItemsProcessed(state.iterations()); 28 | } 29 | 30 | static void our_cdf(benchmark::State& state) { 31 | generator gen; 32 | for (auto _ : state) benchmark::DoNotOptimize(normal_cdf(gen())); 33 | state.SetItemsProcessed(state.iterations()); 34 | } 35 | 36 | static void math_ppf(benchmark::State& state) { 37 | generator gen; 38 | bm::normal norm; 39 | for (auto _ : state) benchmark::DoNotOptimize(quantile(norm, gen())); 40 | state.SetItemsProcessed(state.iterations()); 41 | } 42 | 43 | static void our_ppf(benchmark::State& state) { 44 | generator gen; 45 | for (auto _ : state) benchmark::DoNotOptimize(normal_ppf(gen())); 46 | state.SetItemsProcessed(state.iterations()); 47 | } 48 | 49 | BENCHMARK(math_cdf); 50 | BENCHMARK(our_cdf); 51 | BENCHMARK(math_ppf); 52 | BENCHMARK(our_ppf); 53 | -------------------------------------------------------------------------------- /benchmark/disable_cpu_scaling.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright Hans Dembinski 2019 4 | # Distributed under the Boost Software License, Version 1.0. 5 | # See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt 6 | 7 | for cpu in /sys/devices/system/cpu/cpu? ; do echo performance > $cpu/cpufreq/scaling_governor; done 8 | -------------------------------------------------------------------------------- /benchmark/enable_cpu_scaling.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright Hans Dembinski 2019 4 | # Distributed under the Boost Software License, Version 1.0. 5 | # See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt 6 | 7 | for cpu in /sys/devices/system/cpu/cpu? ; do echo powersave > $cpu/cpufreq/scaling_governor; done 8 | -------------------------------------------------------------------------------- /benchmark/generator.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | 10 | using uniform = std::uniform_real_distribution<>; 11 | using uniform_int = std::uniform_int_distribution<>; 12 | using normal = std::normal_distribution<>; 13 | 14 | template 15 | Distribution init(Ts...); 16 | 17 | template <> 18 | uniform init() { 19 | return uniform{0.0, 1.0}; 20 | } 21 | 22 | template <> 23 | normal init() { 24 | return normal{0.5, 0.3}; 25 | } 26 | 27 | template <> 28 | uniform_int init(int n) { 29 | return uniform_int{0, n}; 30 | } 31 | 32 | template 33 | struct generator : std::array { 34 | using base_t = std::array; 35 | 36 | template 37 | generator(Ts... ts) { 38 | std::default_random_engine rng(1); 39 | auto dis = init(ts...); 40 | std::generate(base_t::begin(), base_t::end(), [&] { return dis(rng); }); 41 | } 42 | 43 | const double& operator()() { 44 | ++ptr_; 45 | if (ptr_ == base_t::data() + N) ptr_ = base_t::data(); 46 | return *ptr_; 47 | } 48 | 49 | const double* ptr_ = base_t::data() - 1; 50 | }; 51 | -------------------------------------------------------------------------------- /benchmark/histogram_filling_gsl.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include "../test/throw_exception.hpp" 11 | #include "generator.hpp" 12 | 13 | #include 14 | struct assert_check { 15 | assert_check() { 16 | assert(false); // don't run with asserts enabled 17 | } 18 | } _; 19 | 20 | template 21 | static void fill_1d(benchmark::State& state) { 22 | gsl_histogram* h = gsl_histogram_alloc(100); 23 | gsl_histogram_set_ranges_uniform(h, 0, 1); 24 | generator gen; 25 | for (auto _ : state) benchmark::DoNotOptimize(gsl_histogram_increment(h, gen())); 26 | gsl_histogram_free(h); 27 | state.SetItemsProcessed(state.iterations()); 28 | } 29 | 30 | template 31 | static void fill_2d(benchmark::State& state) { 32 | gsl_histogram2d* h = gsl_histogram2d_alloc(100, 100); 33 | gsl_histogram2d_set_ranges_uniform(h, 0, 1, 0, 1); 34 | generator gen; 35 | for (auto _ : state) 36 | benchmark::DoNotOptimize(gsl_histogram2d_increment(h, gen(), gen())); 37 | gsl_histogram2d_free(h); 38 | state.SetItemsProcessed(state.iterations() * 2); 39 | } 40 | 41 | BENCHMARK_TEMPLATE(fill_1d, uniform); 42 | BENCHMARK_TEMPLATE(fill_2d, uniform); 43 | 44 | BENCHMARK_TEMPLATE(fill_1d, normal); 45 | BENCHMARK_TEMPLATE(fill_2d, normal); 46 | -------------------------------------------------------------------------------- /benchmark/histogram_filling_numpy.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import numpy as np 3 | # pip install fast-histogram 4 | from fast_histogram import histogram1d 5 | import timeit 6 | 7 | x = np.random.rand(1 << 20) 8 | nrepeat = 10 9 | 10 | print(timeit.timeit("np.histogram(x, bins=100, range=(0, 1))", 11 | "from __main__ import x, np", number=nrepeat) / (nrepeat * len(x)) / 1e-9) 12 | 13 | print(timeit.timeit("histogram1d(x, bins=100, range=(0, 1))", 14 | "from __main__ import x, histogram1d", number=nrepeat) / (nrepeat * len(x)) / 1e-9) -------------------------------------------------------------------------------- /build.jam: -------------------------------------------------------------------------------- 1 | # Copyright René Ferdinand Rivera Morell 2024 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # http://www.boost.org/LICENSE_1_0.txt) 5 | 6 | require-b2 5.2 ; 7 | 8 | # Special builds for Boost Histogram: 9 | # 10 | # Generate coverage data: b2 cxxstd=latest coverage=on test//all 11 | # Test without exceptions and rtti: b2 cxxstd=latest exception-handling=off rtti=off test//minimal 12 | # Test with sanitizers: b2 toolset=clang cxxstd=latest histogram_ubasan test 13 | 14 | # boost/serialization and boost/math must not be included here, they are optional dependencies 15 | constant boost_dependencies : 16 | /boost/config//boost_config 17 | /boost/core//boost_core 18 | /boost/mp11//boost_mp11 19 | /boost/throw_exception//boost_throw_exception 20 | /boost/variant2//boost_variant2 ; 21 | 22 | project /boost/histogram 23 | : requirements 24 | clang:"-Wsign-compare -Wstrict-aliasing -fstrict-aliasing -Wvexing-parse -Wfloat-conversion" 25 | gcc:"-Wsign-compare -Wstrict-aliasing -fstrict-aliasing -Wfloat-conversion" 26 | msvc:"/bigobj" 27 | intel-win:"/bigobj" 28 | hidden 29 | : default-build 30 | extra 31 | ; 32 | 33 | explicit 34 | [ alias boost_histogram : : : 35 | : include $(boost_dependencies) ] 36 | [ alias all : boost_histogram test examples ] 37 | ; 38 | 39 | call-if : boost-library histogram 40 | ; 41 | 42 | path-constant THIS_PATH : . ; 43 | 44 | # only works with clang because of -fsanitize-blacklist 45 | variant histogram_ubasan : debug : 46 | "-fno-omit-frame-pointer -O0 -fno-inline -fsanitize=address,leak,undefined -fno-sanitize-recover=all -fsanitize-blacklist=$(THIS_PATH)/tools/blacklist.supp" 47 | "-fsanitize=address,leak,undefined" 48 | ; 49 | 50 | -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | # Building the documentation 2 | 3 | For building the documentation, certain dependencies have to be installed and a user-config.jam has to be generated in the home directory. 4 | 5 | See [Quickbook documentation](https://www.boost.org/doc/libs/master/doc/html/quickbook/install.html) for details. 6 | 7 | In addition, b2 needs to be configured with Python support. 8 | 9 | See [b2 documentation](https://www.boost.org/doc/libs/1_76_0/tools/build/doc/html/index.html#bbv2.reference.tools.libraries.python) -------------------------------------------------------------------------------- /doc/concepts.qbk: -------------------------------------------------------------------------------- 1 | [/ 2 | Copyright Hans Dembinski 2018 - 2019. 3 | Distributed under the Boost Software License, Version 1.0. 4 | (See accompanying file LICENSE_1_0.txt or copy at 5 | https://www.boost.org/LICENSE_1_0.txt) 6 | ] 7 | 8 | [section:concepts Concepts] 9 | 10 | Users can extend the library with various new types whose concepts are defined here. 11 | 12 | [include concepts/Axis.qbk] 13 | [include concepts/DiscreteAxis.qbk] 14 | [include concepts/IntervalAxis.qbk] 15 | [include concepts/Transform.qbk] 16 | [include concepts/Storage.qbk] 17 | [include concepts/Accumulator.qbk] 18 | 19 | [endsect] 20 | -------------------------------------------------------------------------------- /doc/logo/DENMARK.TTF: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/boostorg/histogram/f859c9fe7ec0f55509e6ba51df2593e07c924863/doc/logo/DENMARK.TTF -------------------------------------------------------------------------------- /doc/logo/README: -------------------------------------------------------------------------------- 1 | The logo was edited using inkscape using the Denmark font that is used by the main Boost logo. The Denmark font is not embedded in the source SVG "color_source.svg" and cannot be displayed correctly on platforms which do not have it. Therefore the svg version "color.svg" used in the docs and the README.md has the letters rendered as shapes. 2 | 3 | It seems possible to manually embed the font, but this was not attempted. 4 | https://graphicdesign.stackexchange.com/questions/43300/embedding-fonts-in-inkscape 5 | -------------------------------------------------------------------------------- /examples/getting_started_listing_03.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | // clang-format off 8 | 9 | //[ getting_started_listing_03 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | int main() { 18 | using namespace boost::histogram; 19 | 20 | /* 21 | Create a profile. Profiles does not only count entries in each cell, but 22 | also compute the mean of a sample value in each cell. 23 | */ 24 | auto p = make_profile(axis::regular<>(5, 0.0, 1.0)); 25 | 26 | /* 27 | Fill profile with data, usually this happens in a loop. You pass the sample 28 | with the `sample` helper function. The sample can be the first or last 29 | argument. 30 | */ 31 | p(0.1, sample(1)); 32 | p(0.15, sample(3)); 33 | p(0.2, sample(4)); 34 | p(0.9, sample(5)); 35 | 36 | /* 37 | Iterate over bins and print profile. 38 | */ 39 | std::ostringstream os; 40 | for (auto&& x : indexed(p)) { 41 | os << boost::format("bin %i [%3.1f, %3.1f) count %i mean %g\n") 42 | % x.index() % x.bin().lower() % x.bin().upper() 43 | % x->count() % x->value(); 44 | } 45 | 46 | std::cout << os.str() << std::flush; 47 | assert(os.str() == "bin 0 [0.0, 0.2) count 2 mean 2\n" 48 | "bin 1 [0.2, 0.4) count 1 mean 4\n" 49 | "bin 2 [0.4, 0.6) count 0 mean 0\n" 50 | "bin 3 [0.6, 0.8) count 0 mean 0\n" 51 | "bin 4 [0.8, 1.0) count 1 mean 5\n"); 52 | } 53 | 54 | //] 55 | -------------------------------------------------------------------------------- /examples/getting_started_listing_04.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | // clang-format off 8 | 9 | //[ getting_started_listing_04 10 | 11 | #include // std::max_element 12 | #include // only needed for printing 13 | #include // make_histogram, integer, indexed 14 | #include // std::cout, std::endl 15 | #include // std::ostringstream 16 | 17 | int main() { 18 | using namespace boost::histogram; 19 | using namespace boost::histogram::literals; 20 | 21 | /* 22 | We make a 3d histogram for color values (r, g, b) in an image. We assume the values 23 | are of type char. The value range then is [0, 256). The integer axis is perfect for 24 | color values. 25 | */ 26 | auto h = make_histogram( 27 | axis::integer<>(0, 256, "r"), 28 | axis::integer<>(0, 256, "g"), 29 | axis::integer<>(0, 256, "b") 30 | ); 31 | 32 | /* 33 | We don't have real image data, so fill some fake data. 34 | */ 35 | h(1, 2, 3); 36 | h(1, 2, 3); 37 | h(0, 1, 0); 38 | 39 | /* 40 | Now let's say we want to know which color is most common. We can use std::max_element 41 | on an indexed range for that. 42 | */ 43 | auto ind = indexed(h); 44 | auto max_it = std::max_element(ind.begin(), ind.end()); 45 | 46 | /* 47 | max_it is a special iterator to the histogram cell with the highest count. 48 | This iterator allows one to access the cell value, bin indices, and bin values. 49 | You need to twice dereference it to get to the cell value. 50 | */ 51 | std::ostringstream os; 52 | os << boost::format("count=%i rgb=(%i, %i, %i)") 53 | % **max_it % max_it->bin(0_c) % max_it->bin(1) % max_it->bin(2); 54 | 55 | std::cout << os.str() << std::endl; 56 | 57 | assert(os.str() == "count=2 rgb=(1, 2, 3)"); 58 | } 59 | 60 | //] 61 | -------------------------------------------------------------------------------- /examples/guide_axis_circular.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_axis_circular 8 | 9 | #include 10 | #include 11 | 12 | int main() { 13 | using namespace boost::histogram; 14 | 15 | // make a circular regular axis ... [0, 180), [180, 360), [0, 180) .... 16 | using opts = decltype(axis::option::overflow | axis::option::circular); 17 | auto r = axis::regular{2, 0., 360.}; 18 | assert(r.index(-180) == 1); 19 | assert(r.index(0) == 0); 20 | assert(r.index(180) == 1); 21 | assert(r.index(360) == 0); 22 | assert(r.index(540) == 1); 23 | assert(r.index(720) == 0); 24 | // special values are mapped to the overflow bin index 25 | assert(r.index(std::numeric_limits::infinity()) == 2); 26 | assert(r.index(-std::numeric_limits::infinity()) == 2); 27 | assert(r.index(std::numeric_limits::quiet_NaN()) == 2); 28 | 29 | // since the regular axis is the most common circular axis, there exists an alias 30 | auto c = axis::circular<>{2, 0., 360.}; 31 | assert(r == c); 32 | 33 | // make a circular integer axis 34 | auto i = axis::integer{1, 4}; 35 | assert(i.index(0) == 2); 36 | assert(i.index(1) == 0); 37 | assert(i.index(2) == 1); 38 | assert(i.index(3) == 2); 39 | assert(i.index(4) == 0); 40 | assert(i.index(5) == 1); 41 | } 42 | 43 | //] 44 | -------------------------------------------------------------------------------- /examples/guide_axis_growing.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | // clang-format off 8 | 9 | //[ guide_axis_growing 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | int main() { 17 | using namespace boost::histogram; 18 | 19 | // make a growing regular axis 20 | // - it grows new bins with its constant bin width until the value is covered 21 | auto h1 = make_histogram(axis::regular{2, 0., 1.}); 25 | // nothing special happens here 26 | h1(0.1); 27 | h1(0.9); 28 | // state: [0, 0.5): 1, [0.5, 1.0): 1 29 | assert(h1.axis().size() == 2); 30 | assert(h1.axis().bin(0).lower() == 0.0); 31 | assert(h1.axis().bin(1).upper() == 1.0); 32 | 33 | // value below range: axis grows new bins until value is in range 34 | h1(-0.3); 35 | // state: [-0.5, 0.0): 1, [0, 0.5): 1, [0.5, 1.0): 1 36 | assert(h1.axis().size() == 3); 37 | assert(h1.axis().bin(0).lower() == -0.5); 38 | assert(h1.axis().bin(2).upper() == 1.0); 39 | 40 | h1(1.9); 41 | // state: [-0.5, 0.0): 1, [0, 0.5): 1, [0.5, 1.0): 1, [1.0, 1.5): 0 [1.5, 2.0): 1 42 | assert(h1.axis().size() == 5); 43 | assert(h1.axis().bin(0).lower() == -0.5); 44 | assert(h1.axis().bin(4).upper() == 2.0); 45 | 46 | // make a growing category axis (here strings) 47 | // - empty axis is allowed: very useful if categories are not known at the beginning 48 | auto h2 = make_histogram(axis::category()); 51 | assert(h2.size() == 0); // histogram is empty 52 | h2("foo"); // new bin foo, index 0 53 | assert(h2.size() == 1); 54 | h2("bar"); // new bin bar, index 1 55 | assert(h2.size() == 2); 56 | h2("foo"); 57 | assert(h2.size() == 2); 58 | assert(h2[0] == 2); 59 | assert(h2[1] == 1); 60 | } 61 | 62 | //] 63 | -------------------------------------------------------------------------------- /examples/guide_axis_with_labels.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_axis_with_labels 8 | 9 | #include 10 | 11 | int main() { 12 | using namespace boost::histogram; 13 | 14 | // create a 2d-histogram with an "age" and an "income" axis 15 | auto h = make_histogram(axis::regular<>(20, 0.0, 100.0, "age in years"), 16 | axis::regular<>(20, 0.0, 100.0, "yearly income in Thousands")); 17 | 18 | // do something with h 19 | } 20 | 21 | //] 22 | -------------------------------------------------------------------------------- /examples/guide_axis_with_uoflow_off.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_axis_with_uoflow_off 8 | 9 | #include 10 | #include 11 | 12 | int main() { 13 | using namespace boost::histogram; 14 | 15 | // create a 1d-histogram over integer values from 1 to 6 16 | auto h1 = make_histogram(axis::integer(1, 7)); 17 | // axis has size 6... 18 | assert(h1.axis().size() == 6); 19 | // ... but histogram has size 8, because of overflow and underflow bins 20 | assert(h1.size() == 8); 21 | 22 | // create a 1d-histogram for throws of a six-sided die without extra bins, 23 | // since the values cannot be smaller than 1 or larger than 6 24 | auto h2 = make_histogram(axis::integer(1, 7)); 25 | // now size of axis and histogram is equal 26 | assert(h2.axis().size() == 6); 27 | assert(h2.size() == 6); 28 | } 29 | 30 | //] 31 | -------------------------------------------------------------------------------- /examples/guide_custom_2d_axis.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_custom_2d_axis 8 | 9 | #include 10 | #include 11 | 12 | int main() { 13 | using namespace boost::histogram; 14 | 15 | // axis which returns 1 if the input falls inside the unit circle and zero otherwise 16 | struct circle_axis { 17 | // accepts a 2D point in form of a std::tuple 18 | axis::index_type index(const std::tuple& point) const { 19 | const auto x = std::get<0>(point); 20 | const auto y = std::get<1>(point); 21 | return x * x + y * y <= 1.0; 22 | } 23 | 24 | axis::index_type size() const { return 2; } 25 | }; 26 | 27 | auto h1 = make_histogram(circle_axis()); 28 | 29 | // fill looks normal for a histogram which has only one Nd-axis 30 | h1(0, 0); // in 31 | h1(0, -1); // in 32 | h1(0, 1); // in 33 | h1(-1, 0); // in 34 | h1(1, 0); // in 35 | h1(1, 1); // out 36 | h1(-1, -1); // out 37 | 38 | // 2D histogram, but only 1D index 39 | assert(h1.at(0) == 2); // out 40 | assert(h1.at(1) == 5); // in 41 | 42 | // other axes can be combined with a Nd-axis 43 | auto h2 = make_histogram(circle_axis(), axis::category({"red", "blue"})); 44 | 45 | // now we need to pass arguments for Nd-axis explicitly as std::tuple 46 | h2(std::make_tuple(0, 0), "red"); 47 | h2(std::make_tuple(1, 1), "blue"); 48 | 49 | // 3D histogram, but only 2D index 50 | assert(h2.at(0, 0) == 0); // out, red 51 | assert(h2.at(0, 1) == 1); // out, blue 52 | assert(h2.at(1, 0) == 1); // in, red 53 | assert(h2.at(1, 1) == 0); // in, blue 54 | } 55 | 56 | //] 57 | -------------------------------------------------------------------------------- /examples/guide_custom_accumulators_advanced.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_custom_accumulators_advanced 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int main() { 15 | using namespace boost::histogram; 16 | 17 | // Accumulator accepts two samples and an optional weight and computes the mean of each. 18 | struct multi_mean { 19 | accumulators::mean<> mx, my; 20 | 21 | // called when no weight is passed 22 | void operator()(double x, double y) { 23 | mx(x); 24 | my(y); 25 | } 26 | 27 | // called when a weight is passed 28 | void operator()(weight_type w, double x, double y) { 29 | mx(w, x); 30 | my(w, y); 31 | } 32 | }; 33 | // Note: The implementation can be made more efficient by sharing the sum of weights. 34 | 35 | // Create a 1D histogram that uses the custom accumulator. 36 | auto h = make_histogram_with(dense_storage(), axis::integer<>(0, 2)); 37 | h(0, sample(1, 2)); // samples go to first cell 38 | h(0, sample(3, 4)); // samples go to first cell 39 | h(1, sample(5, 6), weight(2)); // samples go to second cell 40 | h(1, sample(7, 8), weight(3)); // samples go to second cell 41 | 42 | std::ostringstream os; 43 | for (auto&& bin : indexed(h)) { 44 | os << boost::format("index %i mean-x %.1f mean-y %.1f\n") % bin.index() % 45 | bin->mx.value() % bin->my.value(); 46 | } 47 | std::cout << os.str() << std::flush; 48 | assert(os.str() == "index 0 mean-x 2.0 mean-y 3.0\n" 49 | "index 1 mean-x 6.2 mean-y 7.2\n"); 50 | } 51 | 52 | //] 53 | -------------------------------------------------------------------------------- /examples/guide_custom_accumulators_builtin.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_custom_accumulators_builtin 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int main() { 16 | using namespace boost::histogram; 17 | using mean = accumulators::mean<>; 18 | 19 | // Create a 1D-profile, which computes the mean of samples in each bin. 20 | auto h = make_histogram_with(dense_storage(), axis::integer<>(0, 2)); 21 | // The factory function `make_profile` is provided as a shorthand for this, so this is 22 | // equivalent to the previous line: auto h = make_profile(axis::integer<>(0, 2)); 23 | 24 | // An argument marked as `sample` is passed to the accumulator. 25 | h(0, sample(1)); // sample goes to first cell 26 | h(0, sample(2)); // sample goes to first cell 27 | h(1, sample(3)); // sample goes to second cell 28 | h(1, sample(4)); // sample goes to second cell 29 | 30 | std::ostringstream os; 31 | for (auto&& x : indexed(h)) { 32 | // Accumulators usually have methods to access their state. Use the arrow 33 | // operator to access them. Here, `count()` gives the number of samples, 34 | // `value()` the mean, and `variance()` the variance estimate of the mean. 35 | os << boost::format("index %i count %i mean %.1f variance %.1f\n") % x.index() % 36 | x->count() % x->value() % x->variance(); 37 | } 38 | std::cout << os.str() << std::flush; 39 | assert(os.str() == "index 0 count 2 mean 1.5 variance 0.5\n" 40 | "index 1 count 2 mean 3.5 variance 0.5\n"); 41 | } 42 | 43 | //] 44 | -------------------------------------------------------------------------------- /examples/guide_custom_accumulators_ouroboros.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_custom_accumulators_ouroboros 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int main() { 16 | using namespace boost::histogram; 17 | 18 | // First we define the nested histogram type. 19 | using axis_t = axis::category; 20 | using base_t = histogram>; 21 | 22 | // Now we make an accumulator out of it by using inheritance. 23 | // We only need to implement operator(). A matching version of operator() is actually 24 | // present in base_t, but it is templated and this is not allowed by the accumulator 25 | // concept. Initialization could also happen here. We don't need to initialize anything 26 | // here, because the default constructor of base_t is called automatically and 27 | // sufficient for this example. 28 | struct hist_t : base_t { 29 | void operator()(const double x) { base_t::operator()(x); } 30 | }; 31 | 32 | auto h = make_histogram_with(dense_storage(), axis::integer<>(1, 4)); 33 | 34 | auto x = {1, 1, 2, 2}; 35 | auto s = {1, 2, 3, 3}; // samples are filled into the nested histograms 36 | h.fill(x, sample(s)); 37 | 38 | std::ostringstream os; 39 | for (auto&& x : indexed(h)) { 40 | os << x.bin() << " "; 41 | for (auto&& y : indexed(*x)) { os << "(" << y.bin() << ": " << *y << ") "; } 42 | os << "\n"; 43 | } 44 | 45 | std::cout << os.str() << std::flush; 46 | assert(os.str() == "1 (1: 1) (2: 1) \n" 47 | "2 (3: 2) \n" 48 | "3 \n"); 49 | } 50 | 51 | //] 52 | -------------------------------------------------------------------------------- /examples/guide_custom_accumulators_simple.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_custom_accumulators_simple 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int main() { 16 | using namespace boost::histogram; 17 | 18 | // A custom accumulator which tracks the maximum of the samples. 19 | // It must have a call operator that accepts the argument of the `sample` function. 20 | struct maximum { 21 | // return value is ignored, so we use void 22 | void operator()(double x) { 23 | if (x > value) value = x; 24 | } 25 | double value = 0; // value is public and initialized to zero 26 | }; 27 | 28 | // Create 1D histogram that uses the custom accumulator. 29 | auto h = make_histogram_with(dense_storage(), axis::integer<>(0, 2)); 30 | h(0, sample(1.0)); // sample goes to first cell 31 | h(0, sample(2.0)); // sample goes to first cell 32 | h(1, sample(3.0)); // sample goes to second cell 33 | h(1, sample(4.0)); // sample goes to second cell 34 | 35 | std::ostringstream os; 36 | for (auto&& x : indexed(h)) { 37 | os << boost::format("index %i maximum %.1f\n") % x.index() % x->value; 38 | } 39 | std::cout << os.str() << std::flush; 40 | assert(os.str() == "index 0 maximum 2.0\n" 41 | "index 1 maximum 4.0\n"); 42 | } 43 | 44 | //] 45 | -------------------------------------------------------------------------------- /examples/guide_custom_accumulators_with_metadata.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_custom_accumulators_with_metadata 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int main() { 16 | using namespace boost::histogram; 17 | 18 | // derive custom accumulator from one of the builtins 19 | struct accumulator_with_metadata : accumulators::count<> { 20 | std::string meta; // custom meta data 21 | 22 | // arbitrary additional data and interface could be added here 23 | }; 24 | 25 | // make 1D histogram with custom accmulator 26 | auto h = make_histogram_with(dense_storage(), 27 | axis::integer<>(1, 4)); 28 | 29 | // fill some weighted entries 30 | auto x = {1, 0, 2, 1}; 31 | h.fill(x); 32 | 33 | // assigning meta data to two bins 34 | h[0].meta = "Foo"; 35 | h[2].meta = "Bar"; 36 | 37 | std::ostringstream os; 38 | for (auto&& x : indexed(h)) 39 | os << x.bin() << " value " << x->value() << " meta " << x->meta << "\n"; 40 | 41 | std::cout << os.str() << std::flush; 42 | assert(os.str() == "1 value 2 meta Foo\n" 43 | "2 value 1 meta \n" 44 | "3 value 0 meta Bar\n"); 45 | } 46 | 47 | //] 48 | -------------------------------------------------------------------------------- /examples/guide_custom_axis_multiple_value_types.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2025 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_custom_axis_multiple_value_types 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace boost::histogram; 14 | 15 | struct fraction { 16 | int numerator; 17 | int denominator; 18 | }; 19 | 20 | // We can use a converter type to accept multiple value types. 21 | struct my_axis : axis::regular { 22 | using base_type = axis::regular; 23 | 24 | using base_type::regular; // inherit constructors 25 | 26 | struct converter_type { 27 | double val_; 28 | // put overloads to handle multiple data types here or use a template 29 | converter_type(const fraction& x) 30 | : val_{static_cast(x.numerator) / x.denominator} {} 31 | converter_type(double x) : val_{x} {} 32 | }; 33 | 34 | axis::index_type index(converter_type x) const { 35 | return base_type::index(x.val_); 36 | } 37 | }; 38 | 39 | int main() { 40 | auto h = make_histogram(my_axis(4, 0.0, 1.0)); 41 | 42 | h(fraction{1, 3}); // 0.3333 43 | h(0.8); 44 | 45 | std::vector a = { 46 | {1, 5}, // 0.2 47 | {3, 5}, // 0.6 48 | }; 49 | h.fill(a); 50 | 51 | std::vector b = {0.2, 0.4}; 52 | h.fill(b); 53 | 54 | assert(h.at(0) == 2); // 0.0 ... 0.25 55 | assert(h.at(1) == 2); // 0.25 ... 0.5 56 | assert(h.at(2) == 1); // 0.5 ... 0.75 57 | assert(h.at(3) == 1); // 0.75 ... 1.0 58 | } 59 | 60 | //] 61 | -------------------------------------------------------------------------------- /examples/guide_custom_minimal_axis.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_custom_minimal_axis 8 | 9 | #include 10 | #include 11 | 12 | int main() { 13 | using namespace boost::histogram; 14 | 15 | // stateless axis which returns 1 if the input is even and 0 otherwise 16 | struct even_odd_axis { 17 | axis::index_type index(int x) const { return x % 2; } 18 | axis::index_type size() const { return 2; } 19 | }; 20 | 21 | // threshold axis which returns 1 if the input is above threshold 22 | struct threshold_axis { 23 | threshold_axis(double x) : thr(x) {} 24 | axis::index_type index(double x) const { return x >= thr; } 25 | axis::index_type size() const { return 2; } 26 | double thr; 27 | }; 28 | 29 | auto h = make_histogram(even_odd_axis(), threshold_axis(3.0)); 30 | 31 | h(0, 2.0); 32 | h(1, 4.0); 33 | h(2, 4.0); 34 | 35 | assert(h.at(0, 0) == 1); // even, below threshold 36 | assert(h.at(0, 1) == 1); // even, above threshold 37 | assert(h.at(1, 0) == 0); // odd, below threshold 38 | assert(h.at(1, 1) == 1); // odd, above threshold 39 | } 40 | 41 | //] 42 | -------------------------------------------------------------------------------- /examples/guide_custom_modified_axis.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_custom_modified_axis 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int main() { 15 | using namespace boost::histogram; 16 | 17 | // custom axis, which adapts builtin integer axis 18 | struct custom_axis : public axis::integer<> { 19 | using value_type = const char*; // type that is fed to the axis 20 | 21 | using integer::integer; // inherit ctors of base 22 | 23 | // the customization point 24 | // - accept const char* and convert to int 25 | // - then call index method of base class 26 | axis::index_type index(value_type s) const { return integer::index(std::atoi(s)); } 27 | }; 28 | 29 | auto h = make_histogram(custom_axis(3, 6)); 30 | h("-10"); 31 | h("3"); 32 | h("4"); 33 | h("9"); 34 | 35 | std::ostringstream os; 36 | for (auto&& b : indexed(h)) { 37 | os << "bin " << b.index() << " [" << b.bin() << "] " << *b << "\n"; 38 | } 39 | 40 | std::cout << os.str() << std::endl; 41 | 42 | assert(os.str() == "bin 0 [3] 1\n" 43 | "bin 1 [4] 1\n" 44 | "bin 2 [5] 0\n"); 45 | } 46 | 47 | //] 48 | -------------------------------------------------------------------------------- /examples/guide_custom_storage.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_custom_storage 8 | 9 | #include // std::for_each 10 | #include 11 | #include 12 | #include 13 | #include // std::ref 14 | #include 15 | #include 16 | 17 | int main() { 18 | using namespace boost::histogram; 19 | const auto axis = axis::regular<>(10, 0.0, 1.0); 20 | 21 | auto data = {0.1, 0.3, 0.2, 0.7}; 22 | 23 | // Create static histogram with vector as counter storage, you can use 24 | // other arithmetic types as counters, e.g. double. 25 | auto h1 = make_histogram_with(std::vector(), axis); 26 | std::for_each(data.begin(), data.end(), std::ref(h1)); 27 | assert(algorithm::sum(h1) == 4); 28 | 29 | // Create static histogram with array as counter storage which is 30 | // allocated completely on the stack (this is very fast). N may be larger than 31 | // the actual number of bins used; an exception is raised if N is too small to 32 | // hold all bins. 33 | auto h2 = make_histogram_with(std::array(), axis); 34 | std::for_each(data.begin(), data.end(), std::ref(h2)); 35 | assert(algorithm::sum(h2) == 4); 36 | 37 | // Create static histogram with unordered_map as counter storage; this 38 | // generates a sparse histogram where only memory is allocated for bins that 39 | // are non-zero. This sounds like a good idea for high-dimensional histograms, 40 | // but maps come with a memory and run-time overhead. The default_storage 41 | // usually performs better in high dimensions. 42 | auto h3 = make_histogram_with(std::unordered_map(), axis); 43 | std::for_each(data.begin(), data.end(), std::ref(h3)); 44 | assert(algorithm::sum(h3) == 4); 45 | } 46 | 47 | //] 48 | -------------------------------------------------------------------------------- /examples/guide_fill_profile.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_fill_profile 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | int main() { 17 | using namespace boost::histogram; 18 | 19 | // make a profile, it computes the mean of the samples in each histogram cell 20 | auto h = make_profile(axis::integer<>(0, 3)); 21 | 22 | // mean is computed from the values marked with the sample() helper function 23 | h(0, sample(1)); // sample goes to cell 0 24 | h(0, sample(2)); // sample goes to cell 0 25 | h(1, sample(3)); // sample goes to cell 1 26 | h(sample(4), 1); // sample goes to cell 1; sample can be first or last argument 27 | 28 | // fills from tuples are also supported, 5 and 6 go to cell 2 29 | auto a = std::make_tuple(2, sample(5)); 30 | auto b = std::make_tuple(sample(6), 2); 31 | h(a); 32 | h(b); 33 | 34 | // builtin accumulators have methods to access their state 35 | std::ostringstream os; 36 | for (auto&& x : indexed(h)) { 37 | // use `.` to access methods of accessor, like `index()` 38 | // use `->` to access methods of accumulator 39 | const auto i = x.index(); 40 | const auto n = x->count(); // how many samples are in this bin 41 | const auto vl = x->value(); // mean value 42 | const auto vr = x->variance(); // estimated variance of the mean value 43 | os << boost::format("index %i count %i value %.1f variance %.1f\n") % i % n % vl % vr; 44 | } 45 | 46 | std::cout << os.str() << std::flush; 47 | 48 | assert(os.str() == "index 0 count 2 value 1.5 variance 0.5\n" 49 | "index 1 count 2 value 3.5 variance 0.5\n" 50 | "index 2 count 2 value 5.5 variance 0.5\n"); 51 | } 52 | 53 | //] 54 | -------------------------------------------------------------------------------- /examples/guide_fill_weighted_histogram.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_fill_weighted_histogram 8 | 9 | #include 10 | #include 11 | 12 | int main() { 13 | using namespace boost::histogram; 14 | 15 | // Create a histogram with weight counters that keep track of a variance estimate. 16 | auto h = make_weighted_histogram(axis::regular<>(3, 0.0, 1.0)); 17 | 18 | h(0.0, weight(1)); // weight 1 goes to first bin 19 | h(0.1, weight(2)); // weight 2 goes to first bin 20 | h(0.4, weight(3)); // weight 3 goes to second bin 21 | h(0.5, weight(4)); // weight 4 goes to second bin 22 | 23 | // chunk-wise filling is also supported 24 | auto x = {0.2, 0.6}; 25 | auto w = {5, 6}; 26 | h.fill(x, weight(w)); 27 | 28 | // Weight counters have methods to access the value (sum of weights) and the variance 29 | // (sum of weights squared, why this gives the variance is explained in the rationale) 30 | assert(h[0].value() == 1 + 2 + 5); 31 | assert(h[0].variance() == 1 * 1 + 2 * 2 + 5 * 5); 32 | assert(h[1].value() == 3 + 4 + 6); 33 | assert(h[1].variance() == 3 * 3 + 4 * 4 + 6 * 6); 34 | } 35 | 36 | //] 37 | -------------------------------------------------------------------------------- /examples/guide_fill_weighted_profile.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_fill_weighted_profile 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int main() { 16 | using namespace boost::histogram; 17 | using namespace boost::histogram::literals; // _c suffix creates compile-time numbers 18 | 19 | // make 2D weighted profile 20 | auto h = make_weighted_profile(axis::integer<>(0, 2), axis::integer<>(0, 2)); 21 | 22 | // The mean is computed from the values marked with the sample() helper function. 23 | // Weights can be passed as well. The `sample` and `weight` arguments can appear in any 24 | // order, but they must be the first or last arguments. 25 | h(0, 0, sample(1)); // sample goes to cell (0, 0); weight is 1 26 | h(0, 0, sample(2), weight(3)); // sample goes to cell (0, 0); weight is 3 27 | h(1, 0, sample(3)); // sample goes to cell (1, 0); weight is 1 28 | h(1, 0, sample(4)); // sample goes to cell (1, 0); weight is 1 29 | h(0, 1, sample(5)); // sample goes to cell (1, 0); weight is 1 30 | h(0, 1, sample(6)); // sample goes to cell (1, 0); weight is 1 31 | h(1, 1, weight(4), sample(7)); // sample goes to cell (1, 1); weight is 4 32 | h(weight(5), sample(8), 1, 1); // sample goes to cell (1, 1); weight is 5 33 | 34 | std::ostringstream os; 35 | for (auto&& x : indexed(h)) { 36 | const auto i = x.index(0_c); 37 | const auto j = x.index(1_c); 38 | const auto m = x->value(); // weighted mean 39 | const auto v = x->variance(); // estimated variance of weighted mean 40 | os << boost::format("index %i,%i mean %.1f variance %.1f\n") % i % j % m % v; 41 | } 42 | 43 | std::cout << os.str() << std::flush; 44 | 45 | assert(os.str() == "index 0,0 mean 1.8 variance 0.5\n" 46 | "index 1,0 mean 3.5 variance 0.5\n" 47 | "index 0,1 mean 5.5 variance 0.5\n" 48 | "index 1,1 mean 7.6 variance 0.5\n"); 49 | } 50 | 51 | //] 52 | -------------------------------------------------------------------------------- /examples/guide_histogram_operators.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_histogram_operators 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | int main() { 14 | using namespace boost::histogram; 15 | 16 | // make two histograms 17 | auto h1 = make_histogram(axis::regular<>(2, -1.0, 1.0)); 18 | auto h2 = make_histogram(axis::regular<>(2, -1.0, 1.0)); 19 | 20 | h1(-0.5); // counts are: 1 0 21 | h2(0.5); // counts are: 0 1 22 | 23 | // add them 24 | auto h3 = h1; 25 | h3 += h2; // counts are: 1 1 26 | 27 | // adding multiple histograms at once is likely to be optimized by the compiler so that 28 | // superfluous temporaries avoided, but no guarantees are given; use this equivalent 29 | // code when you want to make sure: h4 = h1; h4 += h2; h4 += h3; 30 | auto h4 = h1 + h2 + h3; // counts are: 2 2 31 | 32 | assert(h4.at(0) == 2 && h4.at(1) == 2); 33 | 34 | // multiply by number, h4 *= 2 also works 35 | auto h5 = h4 * 2; // counts are: 4 4 36 | 37 | // divide by number; s4 /= 4 also works 38 | auto h6 = h5 / 4; // counts are: 1 1 39 | 40 | assert(h6.at(0) == 1 && h6.at(1) == 1); 41 | assert(h6 != h5 && h5 == 4 * h6); 42 | 43 | // note the special effect of multiplication on weight_storage 44 | auto h = make_histogram_with(weight_storage(), axis::regular<>(2, -1.0, 1.0)); 45 | h(-0.5); 46 | 47 | // counts are: 1 0 48 | assert(h.at(0).value() == 1 && h.at(1).value() == 0); 49 | 50 | auto h_sum = h + h; 51 | auto h_mul = 2 * h; 52 | 53 | // values are the same as expected... 54 | assert(h_sum.at(0).value() == h_mul.at(0).value()); 55 | // ... but variances differ 56 | assert(h_sum.at(0).variance() == 2 && h_mul.at(0).variance() == 4); 57 | 58 | // equality operator checks variances, so histograms are not equal 59 | assert(h_sum != h_mul); 60 | } 61 | 62 | //] 63 | -------------------------------------------------------------------------------- /examples/guide_histogram_projection.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_histogram_projection 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int main() { 15 | using namespace boost::histogram; 16 | using namespace literals; // enables _c suffix 17 | 18 | // make a 2d histogram 19 | auto h = make_histogram(axis::regular<>(3, -1.0, 1.0), axis::integer<>(0, 2)); 20 | 21 | h(-0.9, 0); 22 | h(0.9, 1); 23 | h(0.1, 0); 24 | 25 | auto hr0 = algorithm::project(h, 0_c); // keep only first axis 26 | auto hr1 = algorithm::project(h, 1_c); // keep only second axis 27 | 28 | // reduce does not remove counts; returned histograms are summed over 29 | // the removed axes, so h, hr0, and hr1 have same number of total counts; 30 | // we compute the sum of counts with the sum algorithm 31 | assert(algorithm::sum(h) == 3 && algorithm::sum(hr0) == 3 && algorithm::sum(hr1) == 3); 32 | 33 | std::ostringstream os1; 34 | for (auto&& x : indexed(h)) 35 | os1 << "(" << x.index(0) << ", " << x.index(1) << "): " << *x << "\n"; 36 | std::cout << os1.str() << std::flush; 37 | assert(os1.str() == "(0, 0): 1\n" 38 | "(1, 0): 1\n" 39 | "(2, 0): 0\n" 40 | "(0, 1): 0\n" 41 | "(1, 1): 0\n" 42 | "(2, 1): 1\n"); 43 | 44 | std::ostringstream os2; 45 | for (auto&& x : indexed(hr0)) os2 << "(" << x.index(0) << ", -): " << *x << "\n"; 46 | std::cout << os2.str() << std::flush; 47 | assert(os2.str() == "(0, -): 1\n" 48 | "(1, -): 1\n" 49 | "(2, -): 1\n"); 50 | 51 | std::ostringstream os3; 52 | for (auto&& x : indexed(hr1)) os3 << "(- ," << x.index(0) << "): " << *x << "\n"; 53 | std::cout << os3.str() << std::flush; 54 | assert(os3.str() == "(- ,0): 2\n" 55 | "(- ,1): 1\n"); 56 | } 57 | 58 | //] 59 | -------------------------------------------------------------------------------- /examples/guide_histogram_reduction.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_histogram_reduction 8 | 9 | #include 10 | #include 11 | 12 | int main() { 13 | using namespace boost::histogram; 14 | // import reduce commands into local namespace to save typing 15 | using algorithm::rebin; 16 | using algorithm::shrink; 17 | using algorithm::slice; 18 | 19 | // make a 2d histogram 20 | auto h = make_histogram(axis::regular<>(4, 0.0, 4.0), axis::regular<>(4, -2.0, 2.0)); 21 | 22 | h(0, -0.9); 23 | h(1, 0.9); 24 | h(2, 0.1); 25 | h(3, 0.1); 26 | 27 | // reduce takes positional commands which are applied to the axes in order 28 | // - shrink is applied to the first axis; the new axis range is 0.0 to 3.0 29 | // - rebin is applied to the second axis; pairs of adjacent bins are merged 30 | auto h2 = algorithm::reduce(h, shrink(0.0, 3.0), rebin(2)); 31 | 32 | assert(h2.axis(0) == axis::regular<>(3, 0.0, 3.0)); 33 | assert(h2.axis(1) == axis::regular<>(2, -2.0, 2.0)); 34 | 35 | // reduce does not change the total count if the histogram has underflow/overflow bins 36 | assert(algorithm::sum(h) == 4 && algorithm::sum(h2) == 4); 37 | 38 | // One can also explicitly specify the index of the axis in the histogram on which the 39 | // command should act, by using this index as the the first parameter. The position of 40 | // the command in the argument list of reduce is then ignored. We use this to slice only 41 | // the second axis (axis has index 1 in the histogram) from bin index 2 to 4. 42 | auto h3 = algorithm::reduce(h, slice(1, 2, 4)); 43 | 44 | assert(h3.axis(0) == h.axis(0)); // unchanged 45 | assert(h3.axis(1) == axis::regular<>(2, 0.0, 2.0)); 46 | } 47 | 48 | //] 49 | -------------------------------------------------------------------------------- /examples/guide_histogram_serialization.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_histogram_serialization 8 | 9 | #include 10 | #include 11 | #include 12 | #include // includes serialization code 13 | #include 14 | #include 15 | 16 | int main() { 17 | using namespace boost::histogram; 18 | 19 | auto a = make_histogram(axis::regular<>(3, -1.0, 1.0, "axis 0"), 20 | axis::integer<>(0, 2, "axis 1")); 21 | a(0.5, 1); 22 | 23 | std::string buf; // to hold persistent representation 24 | 25 | // store histogram 26 | { 27 | std::ostringstream os; 28 | boost::archive::text_oarchive oa(os); 29 | oa << a; 30 | buf = os.str(); 31 | } 32 | 33 | auto b = decltype(a)(); // create a default-constructed second histogram 34 | 35 | assert(b != a); // b is empty, a is not 36 | 37 | // load histogram 38 | { 39 | std::istringstream is(buf); 40 | boost::archive::text_iarchive ia(is); 41 | ia >> b; 42 | } 43 | 44 | assert(b == a); // now b is equal to a 45 | } 46 | 47 | //] 48 | -------------------------------------------------------------------------------- /examples/guide_make_dynamic_histogram.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_make_dynamic_histogram 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | const char* config = "4 1.0 2.0\n" 15 | "5 3.0 4.0\n"; 16 | 17 | int main() { 18 | using namespace boost::histogram; 19 | 20 | // read axis config from a config file (mocked here with std::istringstream) 21 | // and create vector of regular axes, the number of axis is not known at compile-time 22 | std::istringstream is(config); 23 | auto v1 = std::vector>(); 24 | while (is.good()) { 25 | unsigned bins; 26 | double start, stop; 27 | is >> bins >> start >> stop; 28 | v1.emplace_back(bins, start, stop); 29 | } 30 | 31 | // create histogram from iterator range 32 | // (copying or moving the vector also works, move is shown below) 33 | auto h1 = make_histogram(v1.begin(), v1.end()); 34 | assert(h1.rank() == v1.size()); 35 | 36 | // with a vector of axis::variant (polymorphic axis type that can hold any one of the 37 | // template arguments at a time) the types and number of axis can vary at run-time 38 | auto v2 = std::vector, axis::integer<>>>(); 39 | v2.emplace_back(axis::regular<>(100, -1.0, 1.0)); 40 | v2.emplace_back(axis::integer<>(1, 7)); 41 | 42 | // create dynamic histogram by moving the vector 43 | auto h2 = make_histogram(std::move(v2)); 44 | assert(h2.rank() == 2); 45 | } 46 | 47 | //] 48 | -------------------------------------------------------------------------------- /examples/guide_make_static_histogram.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_make_static_histogram 8 | 9 | #include 10 | #include 11 | 12 | int main() { 13 | using namespace boost::histogram; 14 | 15 | // create a 1d-histogram in default configuration which 16 | // covers the real line from -1 to 1 in 100 bins 17 | auto h = make_histogram(axis::regular<>(100, -1.0, 1.0)); 18 | 19 | // rank is the number of axes 20 | assert(h.rank() == 1); 21 | } 22 | 23 | //] 24 | -------------------------------------------------------------------------------- /examples/guide_parallel_filling.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | //[ guide_parallel_filling 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | // dummy fill function, to be executed in parallel by several threads 17 | template 18 | void fill(Histogram& h) { 19 | for (unsigned i = 0; i < 1000; ++i) { h(i % 10); } 20 | } 21 | 22 | int main() { 23 | using namespace boost::histogram; 24 | 25 | /* 26 | Create histogram with container of thread-safe counters for parallel filling in 27 | several threads. Only filling is thread-safe, other guarantees are not given. 28 | */ 29 | auto h = make_histogram_with(dense_storage>(), 30 | axis::integer<>(0, 10)); 31 | 32 | /* 33 | Run the fill function in parallel from different threads. This is safe when a 34 | thread-safe accumulator and a storage with thread-safe cell access are used. 35 | */ 36 | auto fill_h = [&h]() { fill(h); }; 37 | std::thread t1(fill_h); 38 | std::thread t2(fill_h); 39 | std::thread t3(fill_h); 40 | std::thread t4(fill_h); 41 | t1.join(); 42 | t2.join(); 43 | t3.join(); 44 | t4.join(); 45 | 46 | // Without a thread-safe accumulator, this number may be smaller. 47 | assert(algorithm::sum(h) == 4000); 48 | } 49 | 50 | //] 51 | -------------------------------------------------------------------------------- /include/boost/histogram.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_HPP 8 | #define BOOST_HISTOGRAM_HPP 9 | 10 | /** 11 | \file boost/histogram.hpp 12 | Includes all standard headers of the Boost.Histogram library. 13 | 14 | Extra headers not automatically included are: 15 | - [boost/histogram/ostream.hpp][1] 16 | - [boost/histogram/axis/ostream.hpp][2] 17 | - [boost/histogram/accumulators/ostream.hpp][3] 18 | - [boost/histogram/serialization.hpp][4] 19 | 20 | [1]: histogram/reference.html#header.boost.histogram.ostream_hpp 21 | [2]: histogram/reference.html#header.boost.histogram.axis.ostream_hpp 22 | [3]: histogram/reference.html#header.boost.histogram.accumulators.ostream_hpp 23 | [4]: histogram/reference.html#header.boost.histogram.serialization_hpp 24 | */ 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /include/boost/histogram/accumulators.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_ACCUMULATORS_HPP 8 | #define BOOST_HISTOGRAM_ACCUMULATORS_HPP 9 | 10 | /** 11 | \file boost/histogram/accumulators.hpp 12 | Includes all accumulator headers of the Boost.Histogram library. 13 | 14 | Extra header not automatically included: 15 | - [boost/histogram/accumulators/ostream.hpp][1] 16 | 17 | [1]: histogram/reference.html#header.boost.histogram.accumulators.ostream_hpp 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /include/boost/histogram/accumulators/is_thread_safe.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_ACCUMULATORS_IS_THREAD_SAFE_HPP 8 | #define BOOST_HISTOGRAM_ACCUMULATORS_IS_THREAD_SAFE_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace boost { 15 | namespace histogram { 16 | namespace detail { 17 | 18 | template 19 | constexpr bool is_thread_safe_impl(priority<0>) { 20 | return false; 21 | } 22 | 23 | template 24 | constexpr auto is_thread_safe_impl(priority<1>) -> decltype(T::thread_safe()) { 25 | return T::thread_safe(); 26 | } 27 | 28 | } // namespace detail 29 | 30 | namespace accumulators { 31 | 32 | template 33 | struct is_thread_safe 34 | : std::integral_constant(detail::priority<1>{})> {}; 36 | 37 | } // namespace accumulators 38 | } // namespace histogram 39 | } // namespace boost 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /include/boost/histogram/algorithm.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_ALGORITHM_HPP 8 | #define BOOST_HISTOGRAM_ALGORITHM_HPP 9 | 10 | /** 11 | \file boost/histogram/algorithm.hpp 12 | Includes all algorithm headers of the Boost.Histogram library. 13 | */ 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /include/boost/histogram/algorithm/empty.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Henry Schreiner 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_ALGORITHM_EMPTY_HPP 8 | #define BOOST_HISTOGRAM_ALGORITHM_EMPTY_HPP 9 | 10 | #include 11 | #include 12 | 13 | namespace boost { 14 | namespace histogram { 15 | namespace algorithm { 16 | /** Check to see if all histogram cells are empty. Use coverage to include or 17 | exclude the underflow/overflow bins. 18 | 19 | This algorithm has O(N) complexity, where N is the number of cells. 20 | 21 | Returns true if all cells are empty, and false otherwise. 22 | */ 23 | template 24 | auto empty(const histogram& h, coverage cov) { 25 | using value_type = typename histogram::value_type; 26 | const value_type default_value = value_type(); 27 | for (auto&& ind : indexed(h, cov)) { 28 | if (*ind != default_value) { return false; } 29 | } 30 | return true; 31 | } 32 | } // namespace algorithm 33 | } // namespace histogram 34 | } // namespace boost 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /include/boost/histogram/axis.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_AXIS_HPP 8 | #define BOOST_HISTOGRAM_AXIS_HPP 9 | 10 | /** 11 | \file boost/histogram/axis.hpp 12 | Includes all axis headers of the Boost.Histogram library. 13 | 14 | Extra header not automatically included: 15 | - [boost/histogram/axis/ostream.hpp][1] 16 | 17 | [1]: histogram/reference.html#header.boost.histogram.axis.ostream_hpp 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /include/boost/histogram/axis/interval_view.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_AXIS_INTERVAL_VIEW_HPP 8 | #define BOOST_HISTOGRAM_AXIS_INTERVAL_VIEW_HPP 9 | 10 | #include 11 | 12 | namespace boost { 13 | namespace histogram { 14 | namespace axis { 15 | 16 | /** 17 | Lightweight bin view. 18 | 19 | Represents the current bin interval. 20 | */ 21 | template 22 | class interval_view { 23 | public: 24 | interval_view(const Axis& axis, index_type idx) : axis_(axis), idx_(idx) {} 25 | // avoid viewing a temporary that goes out of scope 26 | interval_view(Axis&& axis, index_type idx) = delete; 27 | 28 | /// Return lower edge of bin. 29 | decltype(auto) lower() const noexcept { return axis_.value(idx_); } 30 | /// Return upper edge of bin. 31 | decltype(auto) upper() const noexcept { return axis_.value(idx_ + 1); } 32 | /// Return center of bin. 33 | decltype(auto) center() const noexcept { return axis_.value(idx_ + 0.5); } 34 | /// Return width of bin. 35 | decltype(auto) width() const noexcept { return upper() - lower(); } 36 | 37 | template 38 | bool operator==(const BinType& rhs) const noexcept { 39 | return lower() == rhs.lower() && upper() == rhs.upper(); 40 | } 41 | 42 | template 43 | bool operator!=(const BinType& rhs) const noexcept { 44 | return !operator==(rhs); 45 | } 46 | 47 | private: 48 | const Axis& axis_; 49 | const index_type idx_; 50 | }; 51 | 52 | } // namespace axis 53 | } // namespace histogram 54 | } // namespace boost 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/args_type.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_DETAIL_ARGS_TYPE_HPP 8 | #define BOOST_HISTOGRAM_DETAIL_ARGS_TYPE_HPP 9 | 10 | #include 11 | 12 | namespace boost { 13 | namespace histogram { 14 | namespace detail { 15 | 16 | template 17 | struct args_type_impl { 18 | using T::ERROR_this_should_never_be_instantiated_please_write_an_issue; 19 | }; 20 | 21 | template 22 | struct args_type_impl { 23 | using type = std::tuple; 24 | }; 25 | 26 | template 27 | struct args_type_impl { 28 | using type = std::tuple; 29 | }; 30 | 31 | template 32 | struct args_type_impl { 33 | using type = std::tuple; 34 | }; 35 | 36 | #if __cpp_noexcept_function_type >= 201510 37 | template 38 | struct args_type_impl { 39 | using type = std::tuple; 40 | }; 41 | 42 | template 43 | struct args_type_impl { 44 | using type = std::tuple; 45 | }; 46 | 47 | template 48 | struct args_type_impl { 49 | using type = std::tuple; 50 | }; 51 | #endif 52 | 53 | template 54 | using args_type = typename args_type_impl::type; 55 | 56 | template 57 | using arg_type = std::tuple_element_t>; 58 | 59 | } // namespace detail 60 | } // namespace histogram 61 | } // namespace boost 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/array_wrapper.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_DETAIL_ARRAY_WRAPPER_HPP 8 | #define BOOST_HISTOGRAM_DETAIL_ARRAY_WRAPPER_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace boost { 18 | namespace histogram { 19 | namespace detail { 20 | 21 | template )> 22 | struct has_save_array_impl; 23 | 24 | template )> 25 | struct has_load_array_impl; 26 | 27 | template 28 | using has_array_optimization = mp11::mp_or, 29 | mp11::mp_valid>; 30 | 31 | template 32 | struct array_wrapper { 33 | using pointer = T*; 34 | 35 | pointer ptr; 36 | std::size_t size; 37 | 38 | template 39 | void serialize(Archive& ar, unsigned /* version */) { 40 | static_if_c<(has_array_optimization::value && 41 | std::is_trivially_copyable::value)>( 42 | [this](auto& ar) { 43 | // cannot use and therefore bypass save_array / load_array interface, because 44 | // it requires exact type boost::serialization::array_wrapper 45 | static_if_c( 46 | [this](auto& ar) { ar.load_binary(this->ptr, sizeof(T) * this->size); }, 47 | [this](auto& ar) { ar.save_binary(this->ptr, sizeof(T) * this->size); }, 48 | ar); 49 | }, 50 | [this](auto& ar) { 51 | for (auto&& x : make_span(this->ptr, this->size)) ar& make_nvp("item", x); 52 | }, 53 | ar); 54 | } 55 | }; 56 | 57 | template 58 | auto make_array_wrapper(T* t, std::size_t s) { 59 | return array_wrapper{t, s}; 60 | } 61 | 62 | } // namespace detail 63 | } // namespace histogram 64 | } // namespace boost 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/common_type.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_DETAIL_COMMON_TYPE_HPP 8 | #define BOOST_HISTOGRAM_DETAIL_COMMON_TYPE_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | namespace boost { 18 | namespace histogram { 19 | namespace detail { 20 | // clang-format off 21 | template 22 | using common_axes = mp11::mp_cond< 23 | is_tuple, T, 24 | is_tuple, U, 25 | is_sequence_of_axis, T, 26 | is_sequence_of_axis, U, 27 | std::true_type, T 28 | >; 29 | // clang-format on 30 | 31 | // Non-PODs rank highest, then floats, than integers; types with more capacity are higher 32 | template 33 | constexpr std::size_t type_rank() { 34 | using T = typename Storage::value_type; 35 | return !std::is_arithmetic::value * 10000 + std::is_floating_point::value * 100 + 36 | 10 * sizeof(T) + 2 * is_array_like::value + 37 | is_vector_like::value; 38 | ; 39 | } 40 | 41 | template 42 | using common_storage = mp11::mp_if_c<(type_rank() >= type_rank()), T, U>; 43 | } // namespace detail 44 | } // namespace histogram 45 | } // namespace boost 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/convert_integer.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_DETAIL_CONVERT_INTEGER_HPP 8 | #define BOOST_HISTOGRAM_DETAIL_CONVERT_INTEGER_HPP 9 | 10 | #include 11 | 12 | namespace boost { 13 | namespace histogram { 14 | namespace detail { 15 | 16 | template 17 | using convert_integer = 18 | std::conditional_t>::value, U, T>; 19 | 20 | } 21 | } // namespace histogram 22 | } // namespace boost 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/counting_streambuf.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_DETAIL_COUNTING_STREAMBUF_HPP 8 | #define BOOST_HISTOGRAM_DETAIL_COUNTING_STREAMBUF_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace boost { 15 | namespace histogram { 16 | namespace detail { 17 | 18 | // detect how many characters will be printed by formatted output 19 | template > 20 | struct counting_streambuf : std::basic_streambuf { 21 | using base_t = std::basic_streambuf; 22 | using typename base_t::char_type; 23 | using typename base_t::int_type; 24 | 25 | std::streamsize* p_count; 26 | 27 | counting_streambuf(std::streamsize& c) : p_count(&c) {} 28 | 29 | std::streamsize xsputn(const char_type* /* s */, std::streamsize n) override { 30 | *p_count += n; 31 | return n; 32 | } 33 | 34 | int_type overflow(int_type ch) override { 35 | ++*p_count; 36 | return ch; 37 | } 38 | }; 39 | 40 | template 41 | struct count_guard { 42 | using bos = std::basic_ostream; 43 | using bsb = std::basic_streambuf; 44 | 45 | counting_streambuf csb; 46 | bos* p_os; 47 | bsb* p_rdbuf; 48 | 49 | count_guard(bos& os, std::streamsize& s) : csb(s), p_os(&os), p_rdbuf(os.rdbuf(&csb)) {} 50 | 51 | count_guard(count_guard&& o) 52 | : csb(o.csb), p_os(boost::exchange(o.p_os, nullptr)), p_rdbuf(o.p_rdbuf) {} 53 | 54 | count_guard& operator=(count_guard&& o) { 55 | if (this != &o) { 56 | csb = std::move(o.csb); 57 | p_os = boost::exchange(o.p_os, nullptr); 58 | p_rdbuf = o.p_rdbuf; 59 | } 60 | return *this; 61 | } 62 | 63 | ~count_guard() { 64 | if (p_os) p_os->rdbuf(p_rdbuf); 65 | } 66 | }; 67 | 68 | template 69 | count_guard make_count_guard(std::basic_ostream& os, std::streamsize& s) { 70 | return {os, s}; 71 | } 72 | 73 | } // namespace detail 74 | } // namespace histogram 75 | } // namespace boost 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/debug.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_DETAIL_DEBUG_HPP 8 | #define BOOST_HISTOGRAM_DETAIL_DEBUG_HPP 9 | 10 | #include 11 | 12 | BOOST_PRAGMA_MESSAGE("debug.hpp included") 13 | 14 | #include 15 | #include 16 | 17 | #define DEBUG(x) \ 18 | std::cout << __FILE__ << ":" << __LINE__ << " [" \ 19 | << boost::histogram::detail::type_name() << "] " #x "=" << x \ 20 | << std::endl; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/erf_inv.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Hans Dembinski, Jay Gohil 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_DETAIL_ERF_INF_HPP 8 | #define BOOST_HISTOGRAM_DETAIL_ERF_INF_HPP 9 | 10 | #include 11 | 12 | namespace boost { 13 | namespace histogram { 14 | namespace detail { 15 | 16 | // Simple implementation of erf_inv so that we do not depend on boost::math. 17 | // If you happen to discover this, prefer the boost::math implementation, 18 | // it is more accurate for x very close to -1 or 1 and faster. 19 | // The only virtue of this implementation is its simplicity. 20 | template 21 | double erf_inv(double x) noexcept { 22 | // Strategy: solve f(y) = x - erf(y) = 0 for given x with Newton's method. 23 | // f'(y) = -erf'(y) = -2/sqrt(pi) e^(-y^2) 24 | // Has quadratic convergence. Since erf_inv<0> is accurate to 1e-3, 25 | // we should have machine precision after three iterations. 26 | const double x0 = erf_inv(x); // recursion 27 | const double fx0 = x - std::erf(x0); 28 | const double pi = std::acos(-1); 29 | double fpx0 = -2.0 / std::sqrt(pi) * std::exp(-x0 * x0); 30 | return x0 - fx0 / fpx0; // = x1 31 | } 32 | 33 | template <> 34 | inline double erf_inv<0>(double x) noexcept { 35 | // Specialization to get initial estimate. 36 | // This formula is accurate to about 1e-3. 37 | // Based on https://stackoverflow.com/questions/27229371/inverse-error-function-in-c 38 | const double a = std::log((1 - x) * (1 + x)); 39 | const double b = std::fma(0.5, a, 4.120666747961526); 40 | const double c = 6.47272819164 * a; 41 | return std::copysign(std::sqrt(-b + std::sqrt(std::fma(b, b, -c))), x); 42 | } 43 | 44 | } // namespace detail 45 | } // namespace histogram 46 | } // namespace boost 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/ignore_deprecation_warning_begin.hpp: -------------------------------------------------------------------------------- 1 | #if (defined(__GNUC__) || defined(__clang__)) 2 | #pragma GCC diagnostic push 3 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 4 | 5 | #elif defined(_MSC_VER) 6 | #pragma warning(push) // preserve warning settings 7 | #pragma warning(disable : 4996) // disable depricated localtime/gmtime warning on vc8 8 | #endif 9 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/ignore_deprecation_warning_end.hpp: -------------------------------------------------------------------------------- 1 | #if (defined(__GNUC__) || defined(__clang__)) 2 | #pragma GCC diagnostic pop 3 | 4 | #elif defined(_MSC_VER) 5 | #pragma warning(pop) 6 | #endif 7 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/limits.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_DETAIL_LIMITS_HPP 8 | #define BOOST_HISTOGRAM_DETAIL_LIMITS_HPP 9 | 10 | #include 11 | 12 | namespace boost { 13 | namespace histogram { 14 | namespace detail { 15 | 16 | template 17 | constexpr T lowest() { 18 | return std::numeric_limits::lowest(); 19 | } 20 | 21 | template <> 22 | constexpr double lowest() { 23 | return -std::numeric_limits::infinity(); 24 | } 25 | 26 | template <> 27 | constexpr float lowest() { 28 | return -std::numeric_limits::infinity(); 29 | } 30 | 31 | template 32 | constexpr T highest() { 33 | return (std::numeric_limits::max)(); 34 | } 35 | 36 | template <> 37 | constexpr double highest() { 38 | return std::numeric_limits::infinity(); 39 | } 40 | 41 | template <> 42 | constexpr float highest() { 43 | return std::numeric_limits::infinity(); 44 | } 45 | 46 | } // namespace detail 47 | } // namespace histogram 48 | } // namespace boost 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/make_default.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_DETAIL_MAKE_DEFAULT_HPP 8 | #define BOOST_HISTOGRAM_DETAIL_MAKE_DEFAULT_HPP 9 | 10 | namespace boost { 11 | namespace histogram { 12 | namespace detail { 13 | 14 | template 15 | T make_default_impl(const T& t, decltype(t.get_allocator(), 0)) { 16 | return T(t.get_allocator()); 17 | } 18 | 19 | template 20 | T make_default_impl(const T&, float) { 21 | return T{}; 22 | } 23 | 24 | template 25 | T make_default(const T& t) { 26 | return make_default_impl(t, 0); 27 | } 28 | 29 | } // namespace detail 30 | } // namespace histogram 31 | } // namespace boost 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/mutex_base.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_DETAIL_NOOP_MUTEX_HPP 8 | #define BOOST_HISTOGRAM_DETAIL_NOOP_MUTEX_HPP 9 | 10 | #include 11 | #include 12 | #include // mp_if 13 | #include 14 | 15 | namespace boost { 16 | namespace histogram { 17 | namespace detail { 18 | 19 | struct null_mutex { 20 | bool try_lock() noexcept { return true; } 21 | void lock() noexcept {} 22 | void unlock() noexcept {} 23 | }; 24 | 25 | template ::value), 28 | std::mutex, detail::null_mutex>> 29 | struct mutex_base : empty_value { 30 | mutex_base() = default; 31 | // do not copy or move mutex 32 | mutex_base(const mutex_base&) : empty_value() {} 33 | // do not copy or move mutex 34 | mutex_base& operator=(const mutex_base&) { return *this; } 35 | }; 36 | 37 | } // namespace detail 38 | } // namespace histogram 39 | } // namespace boost 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/nonmember_container_access.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_DETAIL_NONMEMBER_CONTAINER_ACCESS_HPP 8 | #define BOOST_HISTOGRAM_DETAIL_NONMEMBER_CONTAINER_ACCESS_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace boost { 15 | namespace histogram { 16 | namespace detail { 17 | 18 | template 19 | constexpr auto data(C& c) -> decltype(c.data()) { 20 | return c.data(); 21 | } 22 | 23 | template 24 | constexpr auto data(const C& c) -> decltype(c.data()) { 25 | return c.data(); 26 | } 27 | 28 | template 29 | constexpr T* data(T (&array)[N]) noexcept { 30 | return array; 31 | } 32 | 33 | template 34 | constexpr const E* data(std::initializer_list il) noexcept { 35 | return il.begin(); 36 | } 37 | 38 | template 39 | constexpr const E* data(const std::valarray& v) noexcept { 40 | return std::begin(v); 41 | } 42 | 43 | template 44 | constexpr E* data(std::valarray& v) noexcept { 45 | return std::begin(v); 46 | } 47 | 48 | template 49 | constexpr auto size(const C& c) -> decltype(c.size()) { 50 | return c.size(); 51 | } 52 | 53 | template 54 | constexpr std::size_t size(const T (&)[N]) noexcept { 55 | return N; 56 | } 57 | 58 | } // namespace detail 59 | } // namespace histogram 60 | } // namespace boost 61 | 62 | #endif // BOOST_HISTOGRAM_DETAIL_NONMEMBER_CONTAINER_ACCESS_HPP 63 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/normal.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Hans Dembinski, Jay Gohil 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_DETAIL_NORMAL_HPP 8 | #define BOOST_HISTOGRAM_DETAIL_NORMAL_HPP 9 | 10 | #include 11 | #include 12 | 13 | namespace boost { 14 | namespace histogram { 15 | namespace detail { 16 | 17 | inline double normal_cdf(double x) noexcept { 18 | return std::fma(0.5, std::erf(x / std::sqrt(2)), 0.5); 19 | } 20 | 21 | inline double normal_ppf(double p) noexcept { 22 | return std::sqrt(2) * erf_inv(2 * (p - 0.5)); 23 | } 24 | 25 | } // namespace detail 26 | } // namespace histogram 27 | } // namespace boost 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/optional_index.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_DETAIL_OPTIONAL_INDEX_HPP 8 | #define BOOST_HISTOGRAM_DETAIL_OPTIONAL_INDEX_HPP 9 | 10 | #include 11 | #include 12 | 13 | namespace boost { 14 | namespace histogram { 15 | namespace detail { 16 | 17 | constexpr auto invalid_index = ~static_cast(0); 18 | 19 | // integer with a persistent invalid state, similar to NaN 20 | struct optional_index { 21 | std::size_t value; 22 | 23 | optional_index& operator=(std::size_t x) noexcept { 24 | value = x; 25 | return *this; 26 | } 27 | 28 | optional_index& operator+=(std::intptr_t x) noexcept { 29 | assert(x >= 0 || static_cast(-x) <= value); 30 | if (value != invalid_index) { value += x; } 31 | return *this; 32 | } 33 | 34 | optional_index& operator+=(const optional_index& x) noexcept { 35 | if (value != invalid_index) return operator+=(x.value); 36 | value = invalid_index; 37 | return *this; 38 | } 39 | 40 | operator std::size_t() const noexcept { return value; } 41 | 42 | friend bool operator<=(std::size_t x, optional_index idx) noexcept { 43 | return x <= idx.value; 44 | } 45 | }; 46 | 47 | constexpr inline bool is_valid(const std::size_t) noexcept { return true; } 48 | 49 | inline bool is_valid(const optional_index x) noexcept { return x.value != invalid_index; } 50 | 51 | } // namespace detail 52 | } // namespace histogram 53 | } // namespace boost 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/priority.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_DETAIL_PRIORITY_HPP 8 | #define BOOST_HISTOGRAM_DETAIL_PRIORITY_HPP 9 | 10 | #include 11 | 12 | namespace boost { 13 | namespace histogram { 14 | namespace detail { 15 | 16 | // priority is used to priorise ambiguous overloads 17 | 18 | template 19 | struct priority : priority<(N - 1)> {}; 20 | 21 | template <> 22 | struct priority<0> {}; 23 | 24 | } // namespace detail 25 | } // namespace histogram 26 | } // namespace boost 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/relaxed_equal.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_DETAIL_RELAXED_EQUAL_HPP 8 | #define BOOST_HISTOGRAM_DETAIL_RELAXED_EQUAL_HPP 9 | 10 | #include 11 | #include 12 | 13 | namespace boost { 14 | namespace histogram { 15 | namespace detail { 16 | 17 | struct relaxed_equal { 18 | template 19 | constexpr auto impl(const T& t, const U& u, priority<1>) const noexcept 20 | -> decltype(t == u) const { 21 | return t == u; 22 | } 23 | 24 | // consider T and U not equal, if there is no operator== defined for them 25 | template 26 | constexpr bool impl(const T&, const U&, priority<0>) const noexcept { 27 | return false; 28 | } 29 | 30 | // consider two T equal if they are stateless 31 | template 32 | constexpr bool impl(const T&, const T&, priority<0>) const noexcept { 33 | return std::is_empty::value; 34 | } 35 | 36 | template 37 | constexpr bool operator()(const T& t, const U& u) const noexcept { 38 | return impl(t, u, priority<1>{}); 39 | } 40 | }; 41 | 42 | } // namespace detail 43 | } // namespace histogram 44 | } // namespace boost 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/relaxed_tuple_size.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_DETAIL_RELAXED_TUPLE_SIZE_HPP 8 | #define BOOST_HISTOGRAM_DETAIL_RELAXED_TUPLE_SIZE_HPP 9 | 10 | #include 11 | 12 | namespace boost { 13 | namespace histogram { 14 | namespace detail { 15 | 16 | using dynamic_size = std::integral_constant(-1)>; 17 | 18 | // Returns static size of tuple or dynamic_size 19 | template 20 | constexpr dynamic_size relaxed_tuple_size(const T&) noexcept { 21 | return {}; 22 | } 23 | 24 | template 25 | constexpr std::integral_constant relaxed_tuple_size( 26 | const std::tuple&) noexcept { 27 | return {}; 28 | } 29 | 30 | template 31 | using relaxed_tuple_size_t = decltype(relaxed_tuple_size(std::declval())); 32 | 33 | } // namespace detail 34 | } // namespace histogram 35 | } // namespace boost 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/replace_type.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_DETAIL_REPLACE_TYPE_HPP 8 | #define BOOST_HISTOGRAM_DETAIL_REPLACE_TYPE_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace boost { 15 | namespace histogram { 16 | namespace detail { 17 | 18 | template 19 | using replace_type = std::conditional_t::value, To, T>; 20 | 21 | template 22 | using replace_default = replace_type; 23 | 24 | template 25 | using replace_cstring = replace_type; 26 | 27 | } // namespace detail 28 | } // namespace histogram 29 | } // namespace boost 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/square.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_DETAIL_SQUARE_HPP 8 | #define BOOST_HISTOGRAM_DETAIL_SQUARE_HPP 9 | 10 | namespace boost { 11 | namespace histogram { 12 | namespace detail { 13 | 14 | template 15 | T square(T t) { 16 | return t * t; 17 | } 18 | 19 | } // namespace detail 20 | } // namespace histogram 21 | } // namespace boost 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/static_if.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_DETAIL_STATIC_IF_HPP 8 | #define BOOST_HISTOGRAM_DETAIL_STATIC_IF_HPP 9 | 10 | #include 11 | #include 12 | 13 | namespace boost { 14 | namespace histogram { 15 | namespace detail { 16 | 17 | template 18 | constexpr decltype(auto) static_if_impl( 19 | std::true_type, T&& t, F&&, 20 | Args&&... args) noexcept(noexcept(std::declval()(std::declval()...))) { 21 | return std::forward(t)(std::forward(args)...); 22 | } 23 | 24 | template 25 | constexpr decltype(auto) static_if_impl( 26 | std::false_type, T&&, F&& f, 27 | Args&&... args) noexcept(noexcept(std::declval()(std::declval()...))) { 28 | return std::forward(f)(std::forward(args)...); 29 | } 30 | 31 | template 32 | constexpr decltype(auto) static_if_c(Ts&&... ts) noexcept( 33 | noexcept(static_if_impl(std::integral_constant{}, std::declval()...))) { 34 | return static_if_impl(std::integral_constant{}, std::forward(ts)...); 35 | } 36 | 37 | template 38 | constexpr decltype(auto) static_if(Ts&&... ts) noexcept( 39 | noexcept(static_if_impl(Bool{}, std::declval()...))) { 40 | return static_if_impl(Bool{}, std::forward(ts)...); 41 | } 42 | 43 | } // namespace detail 44 | } // namespace histogram 45 | } // namespace boost 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/try_cast.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_DETAIL_TRY_CAST_HPP 8 | #define BOOST_HISTOGRAM_DETAIL_TRY_CAST_HPP 9 | 10 | #include // BOOST_NORETURN 11 | #include 12 | #include 13 | 14 | namespace boost { 15 | namespace histogram { 16 | namespace detail { 17 | 18 | template 19 | constexpr T* ptr_cast(U*) noexcept { 20 | return nullptr; 21 | } 22 | 23 | template 24 | constexpr T* ptr_cast(T* p) noexcept { 25 | return p; 26 | } 27 | 28 | template 29 | constexpr const T* ptr_cast(const T* p) noexcept { 30 | return p; 31 | } 32 | 33 | template 34 | BOOST_NORETURN T try_cast_impl(std::false_type, std::false_type, U&&) { 35 | BOOST_THROW_EXCEPTION(E("type cast error")); 36 | } 37 | 38 | // converting cast 39 | template 40 | T try_cast_impl(std::false_type, std::true_type, U&& u) noexcept { 41 | return static_cast(u); // cast to avoid warnings 42 | } 43 | 44 | // pass-through cast 45 | template 46 | T&& try_cast_impl(std::true_type, std::true_type, T&& t) noexcept { 47 | return std::forward(t); 48 | } 49 | 50 | // cast fails at runtime with exception E instead of compile-time, T must be a value 51 | template 52 | T try_cast(U&& u) noexcept(std::is_convertible::value) { 53 | return try_cast_impl(std::is_same{}, std::is_convertible{}, 54 | std::forward(u)); 55 | } 56 | 57 | } // namespace detail 58 | } // namespace histogram 59 | } // namespace boost 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/tuple_slice.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_DETAIL_TUPLE_SLICE_HPP 8 | #define BOOST_HISTOGRAM_DETAIL_TUPLE_SLICE_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace boost { 15 | namespace histogram { 16 | namespace detail { 17 | 18 | template 19 | decltype(auto) tuple_slice_impl(T&& t, mp11::index_sequence) { 20 | return std::forward_as_tuple(std::get<(I + K)>(std::forward(t))...); 21 | } 22 | 23 | template 24 | decltype(auto) tuple_slice(Tuple&& t) { 25 | constexpr auto S = std::tuple_size>::value; 26 | static_assert(I + N <= S, "I, N must be a valid subset"); 27 | return tuple_slice_impl(std::forward(t), mp11::make_index_sequence{}); 28 | } 29 | 30 | } // namespace detail 31 | } // namespace histogram 32 | } // namespace boost 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /include/boost/histogram/detail/type_name.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_DETAIL_TYPE_NAME_HPP 8 | #define BOOST_HISTOGRAM_DETAIL_TYPE_NAME_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace boost { 15 | namespace histogram { 16 | namespace detail { 17 | 18 | template 19 | std::string type_name_impl(boost::type) { 20 | return boost::core::demangled_name(BOOST_CORE_TYPEID(T)); 21 | } 22 | 23 | template 24 | std::string type_name_impl(boost::type) { 25 | return type_name_impl(boost::type{}) + " const"; 26 | } 27 | 28 | template 29 | std::string type_name_impl(boost::type) { 30 | return type_name_impl(boost::type{}) + " &"; 31 | } 32 | 33 | template 34 | std::string type_name_impl(boost::type) { 35 | return type_name_impl(boost::type{}) + " &&"; 36 | } 37 | 38 | template 39 | std::string type_name() { 40 | return type_name_impl(boost::type{}); 41 | } 42 | 43 | } // namespace detail 44 | } // namespace histogram 45 | } // namespace boost 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /include/boost/histogram/literals.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2017 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_LITERALS_HPP 8 | #define BOOST_HISTOGRAM_LITERALS_HPP 9 | 10 | #include 11 | 12 | namespace boost { 13 | namespace histogram { 14 | namespace detail { 15 | constexpr unsigned parse_number(unsigned n) { return n; } 16 | 17 | template 18 | constexpr unsigned parse_number(unsigned n, char f, Rest... rest) { 19 | return parse_number(10u * n + static_cast(f - '0'), rest...); 20 | } 21 | } // namespace detail 22 | 23 | namespace literals { 24 | /// Suffix operator to generate literal compile-time numbers, 0_c, 12_c, etc. 25 | template 26 | auto operator ""_c() { 27 | return std::integral_constant(); 28 | } 29 | } // namespace literals 30 | } // namespace histogram 31 | } // namespace boost 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /include/boost/histogram/sample.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_SAMPLE_HPP 8 | #define BOOST_HISTOGRAM_SAMPLE_HPP 9 | 10 | #include 11 | #include 12 | 13 | namespace boost { 14 | namespace histogram { 15 | 16 | /** Sample holder and type envelope. 17 | 18 | You should not construct these directly, use the sample() helper function. 19 | 20 | @tparam Underlying type. 21 | */ 22 | template 23 | struct sample_type { 24 | T value; 25 | }; 26 | 27 | /** Helper function to mark arguments as sample. 28 | 29 | @param ts arguments to be forwarded to the accumulator. 30 | */ 31 | template 32 | auto sample(Ts&&... ts) noexcept { 33 | return sample_type>{std::forward_as_tuple(std::forward(ts)...)}; 34 | } 35 | 36 | } // namespace histogram 37 | } // namespace boost 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /include/boost/histogram/serialization.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_SERIALIZATION_HPP 8 | #define BOOST_HISTOGRAM_SERIALIZATION_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | /** 16 | \file boost/histogram/serialization.hpp 17 | 18 | Headers from 19 | [Boost.Serialization](https://www.boost.org/doc/libs/develop/libs/serialization/doc/index.html) 20 | needed to serialize STL types that are used internally by the Boost.Histogram classes. 21 | */ 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /include/boost/histogram/weight.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_WEIGHT_HPP 8 | #define BOOST_HISTOGRAM_WEIGHT_HPP 9 | 10 | #include 11 | 12 | namespace boost { 13 | namespace histogram { 14 | 15 | /** Weight holder and type envelope. 16 | 17 | You should not construct these directly, use the weight() helper function. 18 | 19 | @tparam Underlying arithmetic type. 20 | */ 21 | template 22 | struct weight_type { 23 | /// Access underlying value. 24 | T value; 25 | 26 | /// Allow implicit conversions of types when the underlying value type allows them. 27 | template 28 | operator weight_type() const { 29 | return weight_type{static_cast(value)}; 30 | } 31 | }; 32 | 33 | /** Helper function to mark argument as weight. 34 | 35 | @param t argument to be forward to the histogram. 36 | */ 37 | template 38 | auto weight(T&& t) noexcept { 39 | return weight_type{std::forward(t)}; 40 | } 41 | 42 | } // namespace histogram 43 | } // namespace boost 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Boost.Histogram 4 | 5 | 6 | 7 | Automatic redirection failed, please go to 8 | ./doc/html/index.html 9 |
10 | 11 | Boost.Histogram
12 |
13 | Copyright (C) 2015-2019 Hans Dembinski
14 |
15 | Distributed under the Boost Software License, Version 1.0. 16 | (See accompanying file LICENSE_1_0.txt or copy at 17 | http://www.boost.org/LICENSE_1_0.txt)
18 |
19 |
20 | 21 | 22 | -------------------------------------------------------------------------------- /meta/libraries.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "histogram", 3 | "name": "Histogram", 4 | "authors": [ 5 | "Hans Dembinski" 6 | ], 7 | "description": "Fast multi-dimensional histogram with convenient interface for C++14", 8 | "category": [ 9 | "Algorithms", 10 | "Data", 11 | "Math" 12 | ], 13 | "maintainers": [ 14 | "Hans Dembinski " 15 | ], 16 | "cxxstd": "14" 17 | } 18 | -------------------------------------------------------------------------------- /test/accumulators_count_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include "str.hpp" 11 | #include "throw_exception.hpp" 12 | 13 | using namespace boost::histogram; 14 | using namespace std::literals; 15 | 16 | template 17 | void run_tests() { 18 | using c_t = accumulators::count; 19 | 20 | { 21 | c_t c; 22 | ++c; 23 | BOOST_TEST_EQ(c.value(), static_cast(1)); 24 | BOOST_TEST_EQ(str(c), "1"s); 25 | BOOST_TEST_EQ(str(c, 2, false), " 1"s); 26 | BOOST_TEST_EQ(str(c, 2, true), "1 "s); 27 | 28 | c += 2; 29 | BOOST_TEST_EQ(str(c), "3"s); 30 | 31 | BOOST_TEST_EQ(c, static_cast(3)); 32 | BOOST_TEST_NE(c, static_cast(2)); 33 | } 34 | 35 | { 36 | c_t one(1), two(2), one_copy(1); 37 | BOOST_TEST_LT(one, two); 38 | BOOST_TEST_LE(one, two); 39 | BOOST_TEST_LE(one, one_copy); 40 | BOOST_TEST_GT(two, one); 41 | BOOST_TEST_GE(two, one); 42 | BOOST_TEST_GE(one, one_copy); 43 | } 44 | 45 | BOOST_TEST_EQ(c_t{} += c_t{}, c_t{}); 46 | 47 | { 48 | c_t two(2); 49 | auto six = two * 3; 50 | BOOST_TEST_EQ(six, static_cast(6)); 51 | six *= 2; 52 | BOOST_TEST_EQ(six, static_cast(12)); 53 | } 54 | 55 | { 56 | c_t six(6); 57 | auto two = six / 3; 58 | BOOST_TEST_EQ(two, static_cast(2)); 59 | two /= 2; 60 | BOOST_TEST_EQ(two, static_cast(1)); 61 | } 62 | } 63 | 64 | int main() { 65 | run_tests(); 66 | run_tests(); 67 | run_tests(); 68 | run_tests(); 69 | 70 | return boost::report_errors(); 71 | } 72 | -------------------------------------------------------------------------------- /test/accumulators_count_thread_safe_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "str.hpp" 13 | #include "throw_exception.hpp" 14 | 15 | using namespace boost::histogram; 16 | using namespace std::literals; 17 | 18 | constexpr int N = 10000; 19 | 20 | template 21 | void parallel(F f) { 22 | auto g = [&]() { 23 | for (int i = 0; i < N; ++i) f(); 24 | }; 25 | 26 | std::thread a(g), b(g), c(g), d(g); 27 | a.join(); 28 | b.join(); 29 | c.join(); 30 | d.join(); 31 | } 32 | 33 | template 34 | void test_on() { 35 | using ts_t = accumulators::count; 36 | 37 | // default ctor 38 | { 39 | ts_t i; 40 | BOOST_TEST_EQ(i, static_cast(0)); 41 | } 42 | 43 | // ctor from value 44 | { 45 | ts_t i{1001}; 46 | BOOST_TEST_EQ(i, static_cast(1001)); 47 | BOOST_TEST_EQ(str(i), "1001"s); 48 | } 49 | 50 | // add null 51 | BOOST_TEST_EQ(ts_t{} += ts_t{}, ts_t{}); 52 | 53 | // add non-null 54 | BOOST_TEST_EQ((ts_t{} += ts_t{2}), (ts_t{2})); 55 | 56 | // operator++ 57 | { 58 | ts_t t; 59 | parallel([&]() { ++t; }); 60 | BOOST_TEST_EQ(t, static_cast(4 * N)); 61 | } 62 | 63 | // operator+= with value 64 | { 65 | ts_t t; 66 | parallel([&]() { t += 2; }); 67 | BOOST_TEST_EQ(t, static_cast(8 * N)); 68 | } 69 | 70 | // operator+= with another thread-safe 71 | { 72 | ts_t t, u; 73 | u = 2; 74 | parallel([&]() { t += u; }); 75 | BOOST_TEST_EQ(t, static_cast(8 * N)); 76 | } 77 | } 78 | 79 | int main() { 80 | test_on(); 81 | test_on(); 82 | 83 | // copy and assignment from other thread-safe 84 | { 85 | accumulators::count r{1}; 86 | accumulators::count a{r}, b; 87 | b = r; 88 | BOOST_TEST_EQ(a, 1); 89 | BOOST_TEST_EQ(b, 1); 90 | } 91 | 92 | return boost::report_errors(); 93 | } 94 | -------------------------------------------------------------------------------- /test/accumulators_serialization_test_collector.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 2 15 | 0 16 | 1.50000000000000000e+00 17 | 4.00000000000000000e+00 18 | 19 | 20 | -------------------------------------------------------------------------------- /test/accumulators_serialization_test_fraction.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 1.00000000000000000e+00 14 | 1.00000000000000000e+00 15 | 16 | 17 | -------------------------------------------------------------------------------- /test/accumulators_serialization_test_mean.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 2.50000000000000000e+00 14 | 2.00000000000000000e+00 15 | 2.00000000000000000e+00 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/accumulators_serialization_test_mean_v0.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 3 14 | 2.00000000000000000e+00 15 | 1.00000000000000000e+00 16 | 17 | 18 | -------------------------------------------------------------------------------- /test/accumulators_serialization_test_sum.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 1.00000000000000002e+100 14 | 1.00000000000000000e+00 15 | 16 | 17 | -------------------------------------------------------------------------------- /test/accumulators_serialization_test_weighted_mean.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 2.50000000000000000e+00 14 | 2.25000000000000000e+00 15 | 2.00000000000000000e+00 16 | 2.00000000000000000e+00 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/accumulators_serialization_test_weighted_sum.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 1.10000000000000000e+01 14 | 1.01000000000000000e+02 15 | 16 | 17 | -------------------------------------------------------------------------------- /test/accumulators_sum_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include "str.hpp" 11 | #include "throw_exception.hpp" 12 | 13 | using namespace boost::histogram; 14 | using namespace std::literals; 15 | 16 | int main() { 17 | double bad_sum = 0; 18 | bad_sum += 1; 19 | bad_sum += 1e100; 20 | bad_sum += 1; 21 | bad_sum += -1e100; 22 | BOOST_TEST_EQ(bad_sum, 0); // instead of 2 23 | 24 | using s_t = accumulators::sum; 25 | s_t sum; 26 | ++sum; 27 | BOOST_TEST_EQ(sum, 1); 28 | BOOST_TEST_EQ(sum.value(), 1); 29 | BOOST_TEST_EQ(sum.large_part(), 1); 30 | BOOST_TEST_EQ(sum.small_part(), 0); 31 | BOOST_TEST_EQ(str(sum), "sum(1 + 0)"s); 32 | BOOST_TEST_EQ(str(sum, 15, false), " sum(1 + 0)"s); 33 | BOOST_TEST_EQ(str(sum, 15, true), "sum(1 + 0) "s); 34 | 35 | sum += 1e100; 36 | BOOST_TEST_EQ(sum, (s_t{1e100, 1})); 37 | ++sum; 38 | BOOST_TEST_EQ(sum, (s_t{1e100, 2})); 39 | sum += -1e100; 40 | BOOST_TEST_EQ(sum, (s_t{0, 2})); 41 | BOOST_TEST_EQ(sum, 2); // correct answer 42 | BOOST_TEST_EQ(sum.value(), 2); 43 | BOOST_TEST_EQ(sum.large_part(), 0); 44 | BOOST_TEST_EQ(sum.small_part(), 2); 45 | 46 | sum = s_t{1e100, 1}; 47 | sum += s_t{1e100, 1}; 48 | BOOST_TEST_EQ(sum, (s_t{2e100, 2})); 49 | sum = s_t{1e100, 1}; 50 | sum += s_t{1, 0}; 51 | BOOST_TEST_EQ(sum, (s_t{1e100, 2})); 52 | sum = s_t{1, 0}; 53 | sum += s_t{1e100, 1}; 54 | BOOST_TEST_EQ(sum, (s_t{1e100, 2})); 55 | sum = s_t{0, 1}; 56 | sum += s_t{1, 0}; 57 | BOOST_TEST_EQ(sum, (s_t{1, 1})); 58 | 59 | accumulators::sum a{3}, b{2}, c{3}; 60 | BOOST_TEST_LT(b, c); 61 | BOOST_TEST_LE(b, c); 62 | BOOST_TEST_LE(a, c); 63 | BOOST_TEST_GT(a, b); 64 | BOOST_TEST_GE(a, b); 65 | BOOST_TEST_GE(a, c); 66 | 67 | BOOST_TEST_EQ(s_t{} += s_t{}, s_t{}); 68 | 69 | return boost::report_errors(); 70 | } 71 | -------------------------------------------------------------------------------- /test/algorithm_empty_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "histogram.hpp" 15 | #include "throw_exception.hpp" 16 | 17 | using namespace boost::histogram; 18 | using boost::histogram::algorithm::empty; 19 | 20 | template 21 | void run_tests() { 22 | auto ax = axis::integer<>(0, 10); 23 | 24 | { 25 | auto h = make(Tag(), ax); 26 | BOOST_TEST(empty(h, coverage::all)); 27 | BOOST_TEST(empty(h, coverage::inner)); 28 | for (int i = -1; i < 11; ++i) { 29 | h.reset(); 30 | h(i); 31 | BOOST_TEST(!empty(h, coverage::all)); 32 | if (i == -1 || i == 10) { 33 | BOOST_TEST(empty(h, coverage::inner)); 34 | } else { 35 | BOOST_TEST(!empty(h, coverage::inner)); 36 | } 37 | } 38 | } 39 | 40 | { 41 | auto h = make_s(Tag(), std::vector>(), 42 | axis::integer<>(0, 10), axis::integer<>(0, 10)); 43 | BOOST_TEST(empty(h, coverage::all)); 44 | BOOST_TEST(empty(h, coverage::inner)); 45 | h.reset(); 46 | h(weight(2), -2, -4, sample(3)); 47 | BOOST_TEST(!empty(h, coverage::all)); 48 | BOOST_TEST(empty(h, coverage::inner)); 49 | h.reset(); 50 | h(weight(1), -4, 2, sample(2)); 51 | BOOST_TEST(!empty(h, coverage::all)); 52 | BOOST_TEST(empty(h, coverage::inner)); 53 | h.reset(); 54 | h(weight(3), 3, 5, sample(1)); 55 | BOOST_TEST(!empty(h, coverage::all)); 56 | BOOST_TEST(!empty(h, coverage::inner)); 57 | } 58 | } 59 | 60 | int main() { 61 | run_tests(); 62 | run_tests(); 63 | 64 | return boost::report_errors(); 65 | } 66 | -------------------------------------------------------------------------------- /test/axis.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_TEST_UTILITY_AXIS_HPP 8 | #define BOOST_HISTOGRAM_TEST_UTILITY_AXIS_HPP 9 | 10 | #include 11 | #include 12 | 13 | namespace boost { 14 | namespace histogram { 15 | 16 | template 17 | void test_axis_iterator(const Axis& a, axis::index_type begin, axis::index_type end) { 18 | for (auto bin : a) { 19 | BOOST_TEST_EQ(bin, a.bin(begin)); 20 | ++begin; 21 | } 22 | BOOST_TEST_EQ(begin, end); 23 | auto rit = a.rbegin(); 24 | for (; rit != a.rend(); ++rit) { 25 | --begin; 26 | BOOST_TEST_EQ(*rit, a.bin(begin)); 27 | } 28 | } 29 | 30 | namespace axis { 31 | bool operator==(const null_type&, const null_type&) { return true; } 32 | } // namespace axis 33 | 34 | } // namespace histogram 35 | } // namespace boost 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /test/axis_boolean_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "axis.hpp" 14 | #include "ostream.hpp" 15 | #include "str.hpp" 16 | #include "throw_exception.hpp" 17 | 18 | int main() { 19 | using namespace boost::histogram; 20 | 21 | BOOST_TEST(std::is_nothrow_move_assignable>::value); 22 | BOOST_TEST(std::is_nothrow_move_constructible>::value); 23 | 24 | // axis::integer with double type 25 | { 26 | axis::boolean<> a{"foo"}; 27 | BOOST_TEST_EQ(a.metadata(), "foo"); 28 | a.metadata() = "bar"; 29 | const auto& cref = a; 30 | BOOST_TEST_EQ(cref.metadata(), "bar"); 31 | cref.metadata() = "foo"; 32 | BOOST_TEST_EQ(cref.metadata(), "foo"); 33 | 34 | BOOST_TEST_EQ(a.index(true), 1); 35 | BOOST_TEST_EQ(a.index(false), 0); 36 | BOOST_TEST_EQ(a.index(1), 1); 37 | BOOST_TEST_EQ(a.index(0), 0); 38 | 39 | BOOST_TEST_EQ(a.options(), axis::option::none_t::value); 40 | 41 | BOOST_TEST_CSTR_EQ(str(a).c_str(), "boolean(metadata=\"foo\")"); 42 | 43 | axis::boolean<> b; 44 | BOOST_TEST_CSTR_EQ(str(b).c_str(), "boolean()"); 45 | 46 | BOOST_TEST_NE(a, b); 47 | b = a; 48 | BOOST_TEST_EQ(a, b); 49 | axis::boolean<> c = std::move(b); 50 | BOOST_TEST_EQ(c, a); 51 | axis::boolean<> d; 52 | BOOST_TEST_NE(c, d); 53 | d = std::move(c); 54 | BOOST_TEST_EQ(d, a); 55 | } 56 | 57 | // iterators 58 | test_axis_iterator(axis::boolean<>(), 0, 2); 59 | 60 | return boost::report_errors(); 61 | } 62 | -------------------------------------------------------------------------------- /test/axis_category_fail0.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | using namespace boost::histogram; 10 | 11 | int main() { 12 | // category axis cannot be circular 13 | (void)axis::category({1, 2}); 14 | } 15 | -------------------------------------------------------------------------------- /test/axis_category_fail1.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | using namespace boost::histogram; 10 | 11 | int main() { 12 | // category axis cannot have underflow 13 | (void)axis::category({1, 2}); 14 | } 15 | -------------------------------------------------------------------------------- /test/axis_category_fail2.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | using namespace boost::histogram; 10 | 11 | int main() { 12 | // growing category axis cannot have entries in overflow bin 13 | (void)axis::category({1, 2}); 15 | } 16 | -------------------------------------------------------------------------------- /test/axis_integer_fail0.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | using namespace boost::histogram; 10 | 11 | int main() { 12 | // circular integer axis cannot be growing 13 | (void)axis::integer(1, 2); 15 | } 16 | -------------------------------------------------------------------------------- /test/axis_integer_fail1.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | using namespace boost::histogram; 10 | 11 | int main() { 12 | // circular integer axis cannot have entries in underflow or overflow bins 13 | (void)axis::integer(1, 2); 15 | } 16 | -------------------------------------------------------------------------------- /test/axis_integer_fail2.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | using namespace boost::histogram; 10 | 11 | int main() { 12 | // circular integer axis cannot have entries in underflow or overflow bins 13 | (void)axis::integer(1, 2); 15 | } 16 | -------------------------------------------------------------------------------- /test/axis_integer_fail3.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | using namespace boost::histogram; 10 | 11 | int main() { 12 | // growing integer axis cannot have entries in underflow or overflow bins 13 | (void)axis::integer(1, 2); 15 | } 16 | -------------------------------------------------------------------------------- /test/axis_integer_fail4.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | using namespace boost::histogram; 10 | 11 | int main() { 12 | // growing integer axis cannot have entries in underflow or overflow bins 13 | (void)axis::integer(1, 2); 15 | } 16 | -------------------------------------------------------------------------------- /test/axis_option_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace boost::histogram::axis; 12 | 13 | template 14 | bool operator==(option::bitset, option::bitset) { 15 | return N == M; 16 | } 17 | 18 | template 19 | std::ostream& operator<<(std::ostream& os, option::bitset) { 20 | os << "underflow " << static_cast(N & option::underflow) << " " 21 | << "overflow " << static_cast(N & option::overflow) << " " 22 | << "circular " << static_cast(N & option::circular) << " " 23 | << "growth " << static_cast(N & option::growth); 24 | return os; 25 | } 26 | 27 | int main() { 28 | using namespace option; 29 | using uoflow = decltype(underflow | overflow); 30 | constexpr auto uoflow_growth = uoflow{} | growth; 31 | 32 | BOOST_TEST_EQ(uoflow::value, underflow | overflow); 33 | BOOST_TEST_EQ(underflow | overflow, overflow | underflow); 34 | 35 | BOOST_TEST(underflow.test(underflow)); 36 | BOOST_TEST_NOT(underflow.test(overflow)); 37 | BOOST_TEST_NOT(underflow.test(underflow | overflow)); 38 | BOOST_TEST(uoflow::test(underflow)); 39 | BOOST_TEST(uoflow::test(overflow)); 40 | BOOST_TEST_NOT(uoflow::test(circular)); 41 | BOOST_TEST_NOT(uoflow::test(growth)); 42 | BOOST_TEST(uoflow_growth.test(underflow)); 43 | BOOST_TEST(uoflow_growth.test(overflow)); 44 | BOOST_TEST(uoflow_growth.test(growth)); 45 | BOOST_TEST_NOT(uoflow_growth.test(circular)); 46 | 47 | BOOST_TEST_EQ(uoflow_growth & uoflow_growth, uoflow_growth); 48 | BOOST_TEST_EQ(uoflow_growth & growth, growth); 49 | BOOST_TEST_EQ(uoflow_growth & uoflow{}, uoflow::value); 50 | 51 | BOOST_TEST_EQ(uoflow_growth - growth, uoflow{}); 52 | BOOST_TEST_EQ(uoflow_growth - uoflow{}, growth); 53 | BOOST_TEST_EQ(uoflow_growth - underflow, growth | overflow); 54 | 55 | return boost::report_errors(); 56 | } 57 | -------------------------------------------------------------------------------- /test/axis_regular_fail0.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | using namespace boost::histogram; 10 | 11 | int main() { 12 | // regular axis requires a floating point value type 13 | (void)axis::regular(1, 2, 3); 14 | } 15 | -------------------------------------------------------------------------------- /test/axis_regular_fail1.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | using namespace boost::histogram; 10 | 11 | int main() { 12 | // circular regular axis cannot be growing 13 | (void)axis::regular(1, 2, 3); 15 | } 16 | -------------------------------------------------------------------------------- /test/axis_variable_fail0.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | using namespace boost::histogram; 10 | 11 | int main() { 12 | // variable axis requires a floating point value type 13 | (void)axis::variable({1, 2, 3}); 14 | } 15 | -------------------------------------------------------------------------------- /test/axis_variable_fail1.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | using namespace boost::histogram; 10 | 11 | int main() { 12 | // circular variable axis cannot be growing 13 | (void)axis::variable( 15 | {1, 2, 3}); 16 | } 17 | -------------------------------------------------------------------------------- /test/axis_variant_serialization_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | // This test is inspired by the corresponding boost/beast test of detail_variant. 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "axis.hpp" 17 | #include "serialization.hpp" 18 | #include "throw_exception.hpp" 19 | 20 | using namespace boost::histogram::axis; 21 | 22 | int main(int argc, char** argv) { 23 | assert(argc == 2); 24 | 25 | const auto filename = join(argv[1], "axis_variant_serialization_test.xml"); 26 | 27 | using R = regular<>; 28 | using I = integer<>; 29 | 30 | variant a(I(0, 3)); 31 | variant b(R(1, 0, 1)); 32 | print_xml(filename, b); 33 | BOOST_TEST_NE(a, b); 34 | load_xml(filename, a); 35 | BOOST_TEST_EQ(a, b); 36 | 37 | variant c; // load incompatible version 38 | BOOST_TEST_THROWS(load_xml(filename, c), std::runtime_error); 39 | 40 | return boost::report_errors(); 41 | } 42 | -------------------------------------------------------------------------------- /test/axis_variant_serialization_test.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 1 15 | 16 | 17 | 1 18 | 19 | 0.00000000000000000e+00 20 | 1.00000000000000000e+00 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /test/boost_accumulators_support_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include "throw_exception.hpp" 15 | 16 | namespace ba = boost::accumulators; 17 | 18 | int main() { 19 | using namespace boost::histogram; 20 | 21 | // mean 22 | { 23 | using mean = ba::accumulator_set >; 24 | 25 | auto h = make_histogram_with(dense_storage(), axis::integer<>(0, 2)); 26 | h(0, sample(1)); 27 | h(0, sample(2)); 28 | h(0, sample(3)); 29 | h(1, sample(2)); 30 | h(1, sample(3)); 31 | BOOST_TEST_EQ(ba::count(h[0]), 3); 32 | BOOST_TEST_EQ(ba::mean(h[0]), 2); 33 | BOOST_TEST_EQ(ba::count(h[1]), 2); 34 | BOOST_TEST_EQ(ba::mean(h[1]), 2.5); 35 | BOOST_TEST_EQ(ba::count(h[2]), 0); 36 | 37 | auto h2 = h; // copy ok 38 | BOOST_TEST_EQ(ba::count(h2[0]), 3); 39 | BOOST_TEST_EQ(ba::mean(h2[0]), 2); 40 | BOOST_TEST_EQ(ba::count(h2[1]), 2); 41 | BOOST_TEST_EQ(ba::mean(h2[1]), 2.5); 42 | BOOST_TEST_EQ(ba::count(h2[2]), 0); 43 | } 44 | return boost::report_errors(); 45 | } 46 | -------------------------------------------------------------------------------- /test/boost_range_support_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "throw_exception.hpp" 14 | 15 | using namespace boost::histogram; 16 | using namespace boost::adaptors; 17 | 18 | int main() { 19 | auto h = make_histogram(axis::integer<>(1, 4)); 20 | h(1, weight(1)); 21 | h(2, weight(2)); 22 | h(3, weight(3)); 23 | h(4, weight(4)); 24 | 25 | auto s1 = boost::accumulate(h | filtered([](double x) { return x > 2; }), 0.0); 26 | BOOST_TEST_EQ(s1, 7); 27 | 28 | return boost::report_errors(); 29 | } 30 | -------------------------------------------------------------------------------- /test/check_build_system.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright 2019 Hans Dembinski 4 | # 5 | # Distributed under the Boost Software License, Version 1.0. 6 | # See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt 7 | 8 | import sys 9 | import glob 10 | import os 11 | import re 12 | 13 | ps = os.path.split 14 | pj = os.path.join 15 | 16 | # assumes that check_build_system.py sits in /tests 17 | project_path = ps(ps(__file__)[0])[0] 18 | 19 | exit_code = 0 20 | 21 | for dir in (pj(project_path, "test"), pj(project_path, "examples")): 22 | cpp = set([os.path.basename(x) for x in glob.glob(dir + "/*.cpp")]) 23 | 24 | for build_file in ("Jamfile", "CMakeLists.txt"): 25 | filename = os.path.join(dir, build_file) 26 | if not os.path.exists(filename): 27 | continue 28 | run = set(re.findall(r"([a-zA-Z0-9_]+\.cpp)", open(filename).read())) 29 | 30 | diff = cpp - run 31 | diff.discard("check_cmake_version.cpp") # ignore 32 | diff.discard("check_build_system.py") # ignore 33 | 34 | if diff: 35 | print( 36 | "NOT TESTED in %s\n " % filename 37 | + "\n ".join(["%s/%s" % (dir, x) for x in diff]) 38 | ) 39 | exit_code = 1 40 | 41 | sys.exit(exit_code) 42 | -------------------------------------------------------------------------------- /test/detail_args_type_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include "ostream.hpp" 11 | 12 | namespace dtl = boost::histogram::detail; 13 | 14 | struct Foo { 15 | int f1(char); 16 | int f2(long) const; 17 | static int f3(char, int); 18 | auto f4(char, int) { return 0; }; 19 | }; 20 | 21 | int main() { 22 | BOOST_TEST_TRAIT_SAME(dtl::args_type, std::tuple); 23 | BOOST_TEST_TRAIT_SAME(dtl::args_type, std::tuple); 24 | BOOST_TEST_TRAIT_SAME(dtl::args_type, std::tuple); 25 | BOOST_TEST_TRAIT_SAME(dtl::args_type, std::tuple); 26 | 27 | BOOST_TEST_TRAIT_SAME(dtl::arg_type, char); 28 | BOOST_TEST_TRAIT_SAME(dtl::arg_type, int); 29 | 30 | return boost::report_errors(); 31 | } 32 | -------------------------------------------------------------------------------- /test/detail_argument_traits_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace dtl = boost::histogram::detail; 14 | 15 | int main() { 16 | using boost::histogram::sample; 17 | using boost::histogram::weight; 18 | 19 | // is_weight 20 | { 21 | struct A {}; 22 | using B = int; 23 | BOOST_TEST_NOT(dtl::is_weight::value); 24 | BOOST_TEST_NOT(dtl::is_weight::value); 25 | BOOST_TEST_NOT(dtl::is_weight::value); 26 | BOOST_TEST(dtl::is_weight::value); 27 | } 28 | 29 | // is_sample 30 | { 31 | struct A {}; 32 | using B = int; 33 | BOOST_TEST_NOT(dtl::is_sample::value); 34 | BOOST_TEST_NOT(dtl::is_sample::value); 35 | BOOST_TEST_NOT(dtl::is_sample::value); 36 | BOOST_TEST(dtl::is_sample::value); 37 | BOOST_TEST(dtl::is_sample::value); 38 | } 39 | 40 | using T1 = dtl::argument_traits; 41 | using E1 = dtl::argument_traits_holder<1, 0, -1, -1, std::tuple<>>; 42 | BOOST_TEST_TRAIT_SAME(T1, E1); 43 | 44 | using T2 = dtl::argument_traits; 45 | using E2 = dtl::argument_traits_holder<2, 0, -1, -1, std::tuple<>>; 46 | BOOST_TEST_TRAIT_SAME(T2, E2); 47 | 48 | using T3 = dtl::argument_traits; 49 | using E3 = dtl::argument_traits_holder<2, 1, 0, -1, std::tuple<>>; 50 | BOOST_TEST_TRAIT_SAME(T3, E3); 51 | 52 | using T4 = dtl::argument_traits; 53 | using E4 = dtl::argument_traits_holder<2, 1, 0, 3, std::tuple>; 54 | BOOST_TEST_TRAIT_SAME(T4, E4); 55 | 56 | using T5 = dtl::argument_traits; 57 | using E5 = dtl::argument_traits_holder<1, 0, -1, 1, std::tuple>; 58 | BOOST_TEST_TRAIT_SAME(T5, E5); 59 | 60 | return boost::report_errors(); 61 | } 62 | -------------------------------------------------------------------------------- /test/detail_array_wrapper_serialization_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "ostream.hpp" 17 | #include "throw_exception.hpp" 18 | 19 | namespace dtl = boost::histogram::detail; 20 | namespace ba = boost::archive; 21 | 22 | template 23 | struct dummy_array_wrapper { 24 | T* ptr; 25 | std::size_t size; 26 | template 27 | void serialize(Archive& ar, unsigned /* version */) { 28 | for (auto&& x : boost::make_span(ptr, size)) ar & x; 29 | } 30 | }; 31 | 32 | template 33 | void run_tests() { 34 | std::vector v = {{1, 2, 3}}; 35 | 36 | std::stringstream os1; 37 | { 38 | OArchive oa(os1); 39 | auto w = dtl::make_array_wrapper(v.data(), v.size()); 40 | oa << w; 41 | } 42 | 43 | std::ostringstream os2; 44 | { 45 | OArchive oa(os2); 46 | auto w = dummy_array_wrapper{v.data(), v.size()}; 47 | oa << w; 48 | } 49 | 50 | BOOST_TEST_EQ(os1.str(), os2.str()); 51 | 52 | std::vector v2(3, 0); 53 | { 54 | IArchive ia(os1); 55 | auto w = dtl::make_array_wrapper(v2.data(), v2.size()); 56 | ia >> w; 57 | } 58 | 59 | BOOST_TEST_EQ(v, v2); 60 | } 61 | 62 | int main() { 63 | BOOST_TEST(dtl::has_array_optimization::value); 64 | BOOST_TEST(dtl::has_array_optimization::value); 65 | BOOST_TEST_NOT(dtl::has_array_optimization::value); 66 | BOOST_TEST_NOT(dtl::has_array_optimization::value); 67 | 68 | run_tests(); 69 | run_tests(); 70 | 71 | return boost::report_errors(); 72 | } 73 | -------------------------------------------------------------------------------- /test/detail_convert_integer_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2017 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include "ostream.hpp" 11 | 12 | using namespace boost::histogram::detail; 13 | 14 | int main() { 15 | 16 | BOOST_TEST_TRAIT_SAME(convert_integer, float); 17 | BOOST_TEST_TRAIT_SAME(convert_integer, float); 18 | BOOST_TEST_TRAIT_SAME(convert_integer, double); 19 | BOOST_TEST_TRAIT_SAME(convert_integer, float); 20 | 21 | return boost::report_errors(); 22 | } 23 | -------------------------------------------------------------------------------- /test/detail_erf_inv_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "is_close.hpp" 12 | #include "throw_exception.hpp" 13 | 14 | using namespace boost::histogram::detail; 15 | 16 | int main() { 17 | auto x = {-0.9, -0.75, -0.5, 0.0, 0.1, 0.6, 18 | 0.99, 0.999, 0.9999, 0.99999, 0.999999, 0.9999999}; 19 | 20 | const double eps = std::numeric_limits::epsilon(); 21 | for (auto&& xi : x) 22 | BOOST_TEST_IS_CLOSE(std::erf(erf_inv(xi)), xi, 23 | // on linux and osx, this test passes with eps, 24 | // windows needs 2 * eps 25 | 2 * eps); 26 | 27 | return boost::report_errors(); 28 | } 29 | -------------------------------------------------------------------------------- /test/detail_limits_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2017 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace boost::histogram::detail; 12 | 13 | int main() { 14 | 15 | BOOST_TEST_EQ(lowest(), (std::numeric_limits::min)()); 16 | BOOST_TEST_EQ(lowest(), -std::numeric_limits::infinity()); 17 | BOOST_TEST_EQ(lowest(), -std::numeric_limits::infinity()); 18 | 19 | BOOST_TEST_EQ(highest(), (std::numeric_limits::max)()); 20 | BOOST_TEST_EQ(highest(), std::numeric_limits::infinity()); 21 | BOOST_TEST_EQ(highest(), std::numeric_limits::infinity()); 22 | 23 | return boost::report_errors(); 24 | } 25 | -------------------------------------------------------------------------------- /test/detail_make_default_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2017 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace boost::histogram::detail; 13 | 14 | template 15 | struct allocator_with_state { 16 | using value_type = T; 17 | 18 | allocator_with_state(int s = 0) : state(s) {} 19 | 20 | template 21 | allocator_with_state(const allocator_with_state& o) : state(o.state) {} 22 | 23 | value_type* allocate(std::size_t n) { 24 | return static_cast(::operator new(n * sizeof(T))); 25 | } 26 | void deallocate(value_type* ptr, std::size_t) { 27 | ::operator delete(static_cast(ptr)); 28 | } 29 | 30 | template 31 | bool operator==(const allocator_with_state&) const { 32 | return true; 33 | } 34 | 35 | template 36 | bool operator!=(const allocator_with_state&) const { 37 | return false; 38 | } 39 | 40 | int state; 41 | }; 42 | 43 | int main() { 44 | 45 | using V = std::vector>; 46 | V a(3, 0, allocator_with_state{42}); 47 | V b = make_default(a); 48 | V c; 49 | BOOST_TEST_EQ(a.size(), 3); 50 | BOOST_TEST_EQ(b.size(), 0); 51 | BOOST_TEST_EQ(c.size(), 0); 52 | BOOST_TEST_EQ(a.get_allocator().state, 42); 53 | BOOST_TEST_EQ(b.get_allocator().state, 42); 54 | BOOST_TEST_EQ(c.get_allocator().state, 0); 55 | 56 | return boost::report_errors(); 57 | } 58 | -------------------------------------------------------------------------------- /test/detail_normal_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Hans Dembinski, Jay Gohil 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "is_close.hpp" 12 | #include "throw_exception.hpp" 13 | 14 | using namespace boost::histogram::detail; 15 | namespace bm = boost::math; 16 | 17 | int main() { 18 | const auto x = {-6.0, -5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 6.0}; 19 | 20 | const double eps = std::numeric_limits::epsilon(); 21 | bm::normal norm; 22 | 23 | // cdf 24 | { 25 | for (auto&& xi : x) { 26 | const double expected = bm::cdf(norm, xi); 27 | BOOST_TEST_IS_CLOSE(normal_cdf(xi), expected, eps); 28 | } 29 | } 30 | 31 | // ppf 32 | { 33 | for (auto&& xi : x) { 34 | const double p = bm::cdf(norm, xi); 35 | BOOST_TEST_IS_CLOSE(normal_ppf(p), xi, 1e-8); 36 | } 37 | } 38 | 39 | return boost::report_errors(); 40 | } 41 | -------------------------------------------------------------------------------- /test/detail_relaxed_equal_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2017 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include "ostream.hpp" 11 | 12 | using namespace boost::histogram::detail; 13 | 14 | int main() { 15 | struct Stateless { 16 | } a, b; 17 | 18 | struct Stateful { 19 | int state; // has state 20 | } c, d; 21 | 22 | struct HasEqual { 23 | int state; 24 | bool operator==(const HasEqual& rhs) const { return state == rhs.state; } 25 | } e{1}, f{1}, g{2}; 26 | 27 | BOOST_TEST(relaxed_equal{}(a, b)); 28 | BOOST_TEST_NOT(relaxed_equal{}(a, c)); 29 | BOOST_TEST_NOT(relaxed_equal{}(c, d)); 30 | BOOST_TEST(relaxed_equal{}(e, f)); 31 | BOOST_TEST_NOT(relaxed_equal{}(e, g)); 32 | 33 | return boost::report_errors(); 34 | } 35 | -------------------------------------------------------------------------------- /test/detail_replace_type_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2017 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include "ostream.hpp" 11 | 12 | using namespace boost::histogram::detail; 13 | 14 | int main() { 15 | 16 | BOOST_TEST_TRAIT_SAME(replace_type, long); 17 | BOOST_TEST_TRAIT_SAME(replace_type, int); 18 | BOOST_TEST_TRAIT_SAME(replace_default, char); 19 | BOOST_TEST_TRAIT_SAME(replace_default, int); 20 | 21 | return boost::report_errors(); 22 | } 23 | -------------------------------------------------------------------------------- /test/detail_safe_comparison_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | 10 | using namespace boost::histogram::detail; 11 | 12 | int main() { 13 | auto eq = safe_equal{}; 14 | BOOST_TEST(eq(-1, -1)); 15 | BOOST_TEST(eq(1, 1u)); 16 | BOOST_TEST(eq(1u, 1)); 17 | BOOST_TEST(eq(1u, 1u)); 18 | BOOST_TEST(eq(1.0, 1)); 19 | BOOST_TEST(eq(1, 1.0)); 20 | BOOST_TEST(eq(1.0, 1u)); 21 | BOOST_TEST(eq(1u, 1.0)); 22 | BOOST_TEST_NOT(eq(-1, static_cast(-1))); 23 | BOOST_TEST_NOT(eq(static_cast(-1), -1)); 24 | 25 | auto lt = safe_less{}; 26 | BOOST_TEST(lt(1u, 2u)); 27 | BOOST_TEST(lt(-1, 1u)); 28 | BOOST_TEST(lt(1u, 2)); 29 | BOOST_TEST(lt(-2, -1)); 30 | BOOST_TEST(lt(-2.0, -1)); 31 | BOOST_TEST(lt(1, 2.0)); 32 | BOOST_TEST(lt(-1.0, 1u)); 33 | BOOST_TEST(lt(1u, 2.0)); 34 | BOOST_TEST(lt(1.0, 2.0)); 35 | BOOST_TEST_NOT(lt(1u, 1)); 36 | BOOST_TEST_NOT(lt(1, 1u)); 37 | BOOST_TEST_NOT(lt(1.0, 1)); 38 | BOOST_TEST_NOT(lt(1, 1.0)); 39 | BOOST_TEST_NOT(lt(1.0, 1u)); 40 | BOOST_TEST_NOT(lt(1u, 1.0)); 41 | BOOST_TEST_NOT(lt(1.0, 1.0)); 42 | 43 | auto gt = safe_greater{}; 44 | BOOST_TEST(gt(2u, 1u)); 45 | BOOST_TEST(gt(1u, -1)); 46 | BOOST_TEST(gt(2, 1u)); 47 | BOOST_TEST(gt(-1, -2)); 48 | BOOST_TEST(gt(-1, -2.0)); 49 | BOOST_TEST(gt(2.0, 1)); 50 | BOOST_TEST(gt(1u, -1.0)); 51 | BOOST_TEST(gt(2.0, 1u)); 52 | BOOST_TEST_NOT(gt(1u, 1)); 53 | BOOST_TEST_NOT(gt(1, 1u)); 54 | BOOST_TEST_NOT(gt(1.0, 1)); 55 | BOOST_TEST_NOT(gt(1, 1.0)); 56 | BOOST_TEST_NOT(gt(1.0, 1u)); 57 | BOOST_TEST_NOT(gt(1u, 1.0)); 58 | 59 | return boost::report_errors(); 60 | } 61 | -------------------------------------------------------------------------------- /test/detail_static_if_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2017 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include "throw_exception.hpp" 10 | 11 | using namespace boost::histogram::detail; 12 | 13 | int main() { 14 | using T = std::true_type; 15 | using F = std::false_type; 16 | 17 | // check that branch not taken does not have to compile 18 | BOOST_TEST_EQ(static_if([](auto) { return 1; }, [] {}, 0), 1); 19 | BOOST_TEST_EQ(static_if([] {}, [](auto) { return 1; }, 0), 1); 20 | 21 | BOOST_TEST_EQ(static_if_c([](auto) { return 1; }, [] {}, 0), 1); 22 | BOOST_TEST_EQ(static_if_c([] {}, [](auto) { return 1; }, 0), 1); 23 | 24 | // check that noexcept is correctly propagated 25 | auto may_throw = [](auto x) { return x; }; 26 | auto no_throw = [](auto x) noexcept { return x; }; 27 | 28 | // make this work with -fno-exceptions 29 | BOOST_TEST_EQ(noexcept(static_if(no_throw, may_throw, 0)), noexcept(may_throw(0))); 30 | BOOST_TEST(noexcept(static_if(no_throw, may_throw, 0))); 31 | 32 | return boost::report_errors(); 33 | } 34 | -------------------------------------------------------------------------------- /test/detail_tuple_slice_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2017 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include "ostream.hpp" 11 | 12 | using namespace boost::histogram::detail; 13 | 14 | int main() { 15 | 16 | auto a = std::make_tuple(1, 2, 3, 4); 17 | const auto b = tuple_slice<1, 2>(a); 18 | BOOST_TEST_EQ(b, std::make_tuple(2, 3)); 19 | 20 | return boost::report_errors(); 21 | } 22 | -------------------------------------------------------------------------------- /test/dummy_storage.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_TEST_DUMMY_STORAGE_HPP 8 | #define BOOST_HISTOGRAM_TEST_DUMMY_STORAGE_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | template 17 | struct dummy_storage : std::array { 18 | using base_t = std::array; 19 | 20 | static constexpr bool has_threading_support = false; 21 | static constexpr bool scaleable = 22 | Scaleable && boost::histogram::detail::has_operator_rmul::value; 23 | 24 | std::size_t size_ = 0; 25 | 26 | std::size_t size() const { return size_; } 27 | 28 | void reset(std::size_t n) { 29 | assert(n < this->max_size()); 30 | size_ = n; 31 | } 32 | 33 | auto end() { return this->begin() + size(); } 34 | auto end() const { return this->begin() + size(); } 35 | 36 | bool operator==(const dummy_storage& o) const { 37 | return std::equal(this->begin(), end(), o.begin(), o.end()); 38 | } 39 | 40 | template 41 | std::enable_if_t operator*=(double) { 42 | // do nothing, so it works with unscalable value types for testing purposes 43 | return *this; 44 | } 45 | }; 46 | 47 | struct unscaleable { 48 | int value = 0; 49 | void operator++() { ++value; } 50 | bool operator==(const int& o) const { return value == o; } 51 | }; 52 | 53 | inline std::ostream& operator<<(std::ostream& os, const unscaleable& x) { 54 | os << x.value; 55 | return os; 56 | } 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /test/histogram.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_TEST_UTILITY_HISTOGRAM_HPP 8 | #define BOOST_HISTOGRAM_TEST_UTILITY_HISTOGRAM_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | namespace boost { 21 | namespace histogram { 22 | 23 | template 24 | auto make_axis_vector(const Ts&... ts) { 25 | // make sure the variant is never trivial (contains only one type) 26 | using R = axis::regular; 27 | using I = axis::integer; 28 | using V = axis::variable; 29 | using C = axis::category; 30 | using Var = boost::mp11::mp_unique>; 31 | return std::vector({Var(ts)...}); 32 | } 33 | 34 | struct static_tag : std::false_type {}; 35 | struct dynamic_tag : std::true_type {}; 36 | 37 | template 38 | auto make(static_tag, const Axes&... axes) { 39 | return make_histogram(axes...); 40 | } 41 | 42 | template 43 | auto make_s(static_tag, S&& s, const Axes&... axes) { 44 | return make_histogram_with(s, axes...); 45 | } 46 | 47 | template 48 | auto make(dynamic_tag, const Axes&... axes) { 49 | return make_histogram(make_axis_vector(axes...)); 50 | } 51 | 52 | template 53 | auto make_s(dynamic_tag, S&& s, const Axes&... axes) { 54 | return make_histogram_with(s, make_axis_vector(axes...)); 55 | } 56 | 57 | } // namespace histogram 58 | } // namespace boost 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /test/histogram_collector_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2024 Ruggero Turra, Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "throw_exception.hpp" 14 | 15 | #include 16 | #include 17 | 18 | using namespace boost::histogram; 19 | 20 | int main() { 21 | using collector_t = accumulators::collector<>; 22 | 23 | auto h = make_histogram_with(dense_storage(), axis::integer<>(0, 5)); 24 | 25 | h(0, sample(1.1)); 26 | h(0, sample(2.2)); 27 | h(1, sample(10.10)); 28 | 29 | BOOST_TEST_EQ(h.at(0).count(), 2); 30 | BOOST_TEST_EQ(h.at(1).count(), 1); 31 | BOOST_TEST_EQ(h.at(2).count(), 0); 32 | 33 | BOOST_TEST_EQ(h.at(0), collector_t({1.1, 2.2})); 34 | BOOST_TEST_EQ(h.at(1)[0], 10.10); 35 | 36 | std::vector x = {0, 1, 0, 2, 0}; 37 | std::array data = {-1.1, -1.2, -1.3, -1.4, -1.5}; 38 | h.fill(x, sample(data)); 39 | 40 | BOOST_TEST_EQ(h.at(0).count(), 5); 41 | BOOST_TEST_EQ(h.at(1).count(), 2); 42 | BOOST_TEST_EQ(h.at(2).count(), 1); 43 | BOOST_TEST_NE(h.at(0), collector_t({1.1, 2.2})); 44 | BOOST_TEST_EQ(h.at(0), collector_t({1.1, 2.2, -1.1, -1.3, -1.5})); 45 | BOOST_TEST_EQ(h.at(1), collector_t({10.10, -1.2})); 46 | BOOST_TEST_EQ(h.at(2), collector_t({-1.4})); 47 | 48 | return boost::report_errors(); 49 | } 50 | -------------------------------------------------------------------------------- /test/histogram_fail0.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | 10 | int main() { 11 | using namespace boost::histogram; 12 | 13 | auto h = make_histogram(axis::integer<>(0, 5)); 14 | 15 | // invalid sample argument 16 | h(0, sample(1)); 17 | 18 | auto values = {0, 1}; 19 | h.fill(values, sample(values)); // invalid sample argument 20 | } 21 | -------------------------------------------------------------------------------- /test/histogram_fail1.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | 10 | int main() { 11 | using namespace boost::histogram; 12 | 13 | struct accumulator { 14 | void operator()() {} 15 | }; 16 | 17 | auto h = make_histogram_with(dense_storage(), axis::integer<>(0, 5)); 18 | 19 | // invalid weight argument 20 | h(0, weight(1)); 21 | 22 | auto values = {0, 1}; 23 | h.fill(values, weight(1)); 24 | } 25 | -------------------------------------------------------------------------------- /test/histogram_fail2.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | 10 | int main() { 11 | using namespace boost::histogram; 12 | 13 | struct accumulator { 14 | void operator()(double) {} 15 | void operator()(weight_type, double) {} 16 | }; 17 | 18 | auto h = make_histogram_with(dense_storage(), axis::integer<>(0, 5)); 19 | 20 | // accumulator requires sample 21 | h(0, weight(1)); 22 | 23 | auto values = {1, 2}; 24 | h.fill(values, weight(1)); 25 | } 26 | -------------------------------------------------------------------------------- /test/histogram_fail3.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | 10 | int main() { 11 | struct accumulator { 12 | void operator()(double) {} 13 | }; 14 | 15 | using namespace boost::histogram; 16 | auto h = make_histogram_with(dense_storage(), axis::integer<>(0, 5)); 17 | 18 | // wrong number of sample arguments 19 | h(0, sample(1, 2)); 20 | 21 | auto values = {0, 1}; 22 | h.fill(values, sample(values, values)); 23 | } 24 | -------------------------------------------------------------------------------- /test/histogram_fail4.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | 10 | int main() { 11 | using namespace boost::histogram; 12 | 13 | struct accumulator { 14 | void operator()(std::string) {} 15 | }; 16 | 17 | auto h = make_histogram_with(dense_storage(), axis::integer<>(0, 5)); 18 | 19 | // invalid weight argument 20 | h(0, sample(1)); 21 | 22 | auto values = {1, 2}; 23 | h.fill(values, sample(values)); 24 | } 25 | -------------------------------------------------------------------------------- /test/histogram_fraction_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include "throw_exception.hpp" 18 | 19 | using namespace boost::histogram; 20 | 21 | int main() { 22 | using fraction_t = accumulators::fraction<>; 23 | 24 | auto h = make_histogram_with(dense_storage(), axis::integer<>(0, 2)); 25 | 26 | h(0, sample(true)); 27 | h(0, sample(false)); 28 | h(1, sample(true)); 29 | 30 | BOOST_TEST_EQ(h.at(0), (fraction_t{1, 1})); 31 | BOOST_TEST_EQ(h.at(1), (fraction_t{1, 0})); 32 | 33 | // cannot use std::vector because of vector specialization 34 | std::vector s = {{true, false}}; 35 | std::vector x = {0, 1}; 36 | h.fill(x, sample(s)); 37 | BOOST_TEST_EQ(h.at(0), (fraction_t{2, 1})); 38 | BOOST_TEST_EQ(h.at(1), (fraction_t{1, 1})); 39 | 40 | // any contiguous container of bool works which is not specialized 41 | std::array s2 = {{false, true}}; 42 | h.fill(x, sample(s2)); 43 | BOOST_TEST_EQ(h.at(0), (fraction_t{2, 2})); 44 | BOOST_TEST_EQ(h.at(1), (fraction_t{2, 1})); 45 | 46 | std::valarray s3 = {{false, true}}; 47 | h.fill(x, sample(s3)); 48 | BOOST_TEST_EQ(h.at(0), (fraction_t{2, 3})); 49 | BOOST_TEST_EQ(h.at(1), (fraction_t{3, 1})); 50 | 51 | return boost::report_errors(); 52 | } 53 | -------------------------------------------------------------------------------- /test/histogram_serialization_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "histogram.hpp" 16 | #include "serialization.hpp" 17 | #include "throw_exception.hpp" 18 | 19 | using namespace boost::histogram; 20 | 21 | template 22 | void run_tests(const std::string& filename) { 23 | // histogram_serialization 24 | namespace tr = axis::transform; 25 | using def = use_default; 26 | using axis::option::none_t; 27 | auto a = 28 | make(Tag(), axis::regular(1, -1, 1, "reg"), 29 | axis::circular(1, 0.0, 1.0, "cir"), 30 | axis::regular(1, 1, std::exp(2), "reg-log"), 31 | axis::regular, axis::option::overflow_t>( 32 | tr::pow(0.5), 1, 1, 100, {1, 2, 3}), 33 | axis::variable({1.5, 2.5}, "var"), 34 | axis::category{3, 1}, 35 | axis::integer(1, 2)); 36 | a(0.5, 0.2, 2, 20, 2.2, 1, 1); 37 | print_xml(filename, a); 38 | 39 | auto b = decltype(a)(); 40 | BOOST_TEST_NE(a, b); 41 | load_xml(filename, b); 42 | BOOST_TEST_EQ(a, b); 43 | } 44 | 45 | int main(int argc, char** argv) { 46 | assert(argc == 2); 47 | run_tests(join(argv[1], "histogram_serialization_test_static.xml")); 48 | run_tests(join(argv[1], "histogram_serialization_test_dynamic.xml")); 49 | return boost::report_errors(); 50 | } 51 | -------------------------------------------------------------------------------- /test/is_close.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_TEST_IS_CLOSE_HPP 8 | #define BOOST_HISTOGRAM_TEST_IS_CLOSE_HPP 9 | 10 | #include 11 | #include 12 | 13 | struct is_close { 14 | bool operator()(double a, double b) { return std::abs(a - b) < atol; } 15 | double atol; 16 | }; 17 | 18 | #define BOOST_TEST_IS_CLOSE(a, b, atol) BOOST_TEST_WITH(a, b, is_close{atol}) 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /test/issue_290_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | // - bug only appears on cxxstd=17 or higher and only in gcc 8 | // - reported in issue: https://github.com/boostorg/histogram/issues/290 9 | // - originally caused by rank struct in boost/type_traits/rank.hpp, 10 | // which we emulate here to avoid the dependency on boost.type_traits 11 | 12 | // Original: #include 13 | template 14 | struct rank; 15 | 16 | #include 17 | 18 | int main() { return 0; } 19 | -------------------------------------------------------------------------------- /test/issue_327_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "throw_exception.hpp" 12 | 13 | namespace bh = boost::histogram; 14 | using uogrowth_t = decltype(bh::axis::option::growth | bh::axis::option::underflow | 15 | bh::axis::option::overflow); 16 | 17 | using arg_t = boost::variant2::variant, int>; 18 | 19 | int main() { 20 | using axis_type = 21 | bh::axis::regular; 22 | using axis_variant_type = bh::axis::variant; 23 | 24 | // 1D growing A 25 | { 26 | auto axes = std::vector({axis_type(10, 0, 1)}); 27 | auto h = bh::make_histogram_with(bh::dense_storage(), axes); 28 | auto h2 = h; 29 | 30 | h(-1); 31 | 32 | // used to crash, while growing B did not crash 33 | std::vector vargs = {-1}; 34 | h2.fill(vargs); 35 | 36 | BOOST_TEST_EQ(h, h2); 37 | } 38 | 39 | // 1D growing B 40 | { 41 | auto axes = std::vector({axis_type(10, 0, 1)}); 42 | auto h = bh::make_histogram_with(bh::dense_storage(), axes); 43 | auto h2 = h; 44 | 45 | h(2); 46 | h(-1); 47 | 48 | std::vector f1({2}); 49 | std::vector f2({-1}); 50 | 51 | h2.fill(f1); 52 | h2.fill(f2); 53 | 54 | BOOST_TEST_EQ(h, h2); 55 | } 56 | 57 | return boost::report_errors(); 58 | } 59 | -------------------------------------------------------------------------------- /test/issue_353_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "throw_exception.hpp" 5 | 6 | namespace bh = boost::histogram; 7 | 8 | struct empty { 9 | int index(double) { return 0; } 10 | int size() const { return 0; } 11 | }; 12 | 13 | int main() { 14 | { 15 | auto h = 16 | bh::make_histogram_with(std::vector(), bh::axis::integer<>(0, 2), empty()); 17 | 18 | auto ind1 = bh::indexed(h, bh::coverage::all); 19 | BOOST_TEST_EQ(std::distance(ind1.begin(), ind1.end()), 0); 20 | 21 | auto ind2 = bh::indexed(h, bh::coverage::inner); 22 | BOOST_TEST_EQ(std::distance(ind2.begin(), ind2.end()), 0); 23 | } 24 | 25 | { 26 | auto h = bh::make_histogram_with(std::vector(), bh::axis::integer<>(0, 2), 27 | bh::axis::integer<>(0, 1)); 28 | 29 | auto ind1 = bh::indexed(h, bh::coverage::all); 30 | BOOST_TEST_EQ(std::distance(ind1.begin(), ind1.end()), 12); 31 | 32 | auto ind2 = bh::indexed(h, bh::coverage::inner); 33 | BOOST_TEST_EQ(std::distance(ind2.begin(), ind2.end()), 2); 34 | } 35 | 36 | { 37 | auto h = bh::make_histogram_with(std::vector(), bh::axis::integer<>(0, 2), 38 | bh::axis::integer<>(0, 0)); 39 | 40 | auto ind1 = bh::indexed(h, bh::coverage::all); 41 | BOOST_TEST_EQ(std::distance(ind1.begin(), ind1.end()), 8); 42 | 43 | auto ind2 = bh::indexed(h, bh::coverage::inner); 44 | BOOST_TEST_EQ(std::distance(ind2.begin(), ind2.end()), 0); 45 | } 46 | 47 | return boost::report_errors(); 48 | } -------------------------------------------------------------------------------- /test/make_histogram_fail0.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | 9 | using namespace boost::histogram; 10 | 11 | int main() { 12 | // argument is not an axis 13 | (void)make_histogram(std::vector{}); 14 | } 15 | -------------------------------------------------------------------------------- /test/make_histogram_fail1.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace boost::histogram; 12 | 13 | int main() { 14 | // first and second arguments switched 15 | (void)make_histogram_with(axis::regular<>(3, 0, 1), std::vector{}); 16 | } 17 | -------------------------------------------------------------------------------- /test/odr_main_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Henry Schreiner, Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | /* 8 | For a header-only library, it is important to not accidentally violate the 9 | One-Definition-Rule (ODR), which causes linker errors. The ODR is violated 10 | when a non-templated function declared in a header is not inlined, and that 11 | header is then included in several translation units which are then linked 12 | together. 13 | 14 | We carry out this test by including all headers in two separate translation 15 | units which are then linked together. There is an additional test called 16 | check_odr_test.py which checks that "odr_test.cpp" includes all headers. 17 | */ 18 | 19 | #include "odr_test.cpp" 20 | 21 | int main() { return 0; } 22 | -------------------------------------------------------------------------------- /test/odr_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Henry Schreiner, Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | // The header windows.h and possibly others illegially use unprotected defines 8 | #define small macro_substitution_this_shouldn_t_be_happening 9 | #define min(A, B) macro_substitution_this_shouldn_t_be_happening 10 | #define max(A, B) macro_substitution_this_shouldn_t_be_happening 11 | // which violates the C++ standard. We make sure here that including our headers work 12 | // nevertheless by avoiding these preprocessing tokens or by preventing their macro 13 | // substitution. For more details, see https://github.com/boostorg/histogram/issues/342 14 | 15 | // include all Boost.Histogram header here; see odr_main_test.cpp for details 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | -------------------------------------------------------------------------------- /test/ostream.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_TEST_OSTREAM_HPP 8 | #define BOOST_HISTOGRAM_TEST_OSTREAM_HPP 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace std { 19 | // never add to std, we only do it here to get ADL working :( 20 | template 21 | ostream& operator<<(ostream& os, const vector& v) { 22 | os << "[ "; 23 | for (const auto& x : v) os << x << " "; 24 | os << "]"; 25 | return os; 26 | } 27 | 28 | template 29 | ostream& operator<<(ostream& os, const tuple& t) { 30 | os << "[ "; 31 | ::boost::mp11::tuple_for_each(t, [&os](const auto& x) { os << x << " "; }); 32 | os << "]"; 33 | return os; 34 | } 35 | 36 | template 37 | ostream& operator<<(ostream& os, const pair& t) { 38 | os << "[ " << t.first << " " << t.second << " ]"; 39 | return os; 40 | } 41 | 42 | template 43 | ostream& operator<<(ostream& os, const array& v) { 44 | os << "[ "; 45 | for (const auto& x : v) os << x << " "; 46 | os << "]"; 47 | return os; 48 | } 49 | } // namespace std 50 | 51 | namespace boost { 52 | template 53 | std::ostream& operator<<(std::ostream& os, const span& v) { 54 | os << "[ "; 55 | for (const auto& x : v) os << x << " "; 56 | os << "]"; 57 | return os; 58 | } 59 | } // namespace boost 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /test/quick.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include "throw_exception.hpp" 9 | 10 | int main() { 11 | using namespace boost::histogram; 12 | 13 | auto h = make_histogram(axis::integer<>(0, 5)); 14 | 15 | h(0); 16 | 17 | auto values = {1, 2}; 18 | h.fill(values); 19 | } 20 | -------------------------------------------------------------------------------- /test/serialization.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_TEST_UTILITY_SERIALIZATION_HPP 8 | #define BOOST_HISTOGRAM_TEST_UTILITY_SERIALIZATION_HPP 9 | 10 | #include 11 | #include 12 | #include // BOOST_WINDOWS 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | std::string join(const char* a, const char* b) { 20 | std::string filename = a; 21 | filename += 22 | #ifdef BOOST_WINDOWS 23 | "\\"; 24 | #else 25 | "/"; 26 | #endif 27 | filename += b; 28 | return filename; 29 | } 30 | 31 | template 32 | void load_xml(const std::string& filename, T& t) { 33 | std::ifstream ifs(filename); 34 | assert(ifs.is_open()); 35 | // manually skip XML comments at the beginning of the stream, because of 36 | // https://github.com/boostorg/serialization/issues/169 37 | char line[128]; 38 | do { 39 | ifs.getline(line, 128); 40 | assert(std::strlen(line) < 127); 41 | } while (!ifs.fail() && !ifs.eof() && std::strstr(line, "-->") == nullptr); 42 | boost::archive::xml_iarchive ia(ifs); 43 | ia >> boost::make_nvp("item", t); 44 | } 45 | 46 | template 47 | void print_xml(const std::string& filename, const T& t) { 48 | std::cout << filename << "\n"; 49 | boost::archive::xml_oarchive oa(std::cout); 50 | oa << boost::make_nvp("item", t); 51 | std::cout << std::flush; 52 | } 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /test/storage_adaptor_serialization_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "serialization.hpp" 16 | #include "throw_exception.hpp" 17 | 18 | using namespace boost::histogram; 19 | 20 | template 21 | void test_serialization(const std::string& filename) { 22 | auto a = storage_adaptor(); 23 | a.reset(3); 24 | a[1] += 1; 25 | a[2] += 2; 26 | print_xml(filename, a); 27 | 28 | auto b = storage_adaptor(); 29 | BOOST_TEST_NOT(a == b); 30 | load_xml(filename, b); 31 | BOOST_TEST(a == b); 32 | } 33 | 34 | int main(int argc, char** argv) { 35 | assert(argc == 2); 36 | 37 | test_serialization>( 38 | join(argv[1], "storage_adaptor_serialization_test_vector_int.xml")); 39 | test_serialization>( 40 | join(argv[1], "storage_adaptor_serialization_test_array_unsigned.xml")); 41 | test_serialization>( 42 | join(argv[1], "storage_adaptor_serialization_test_map_double.xml")); 43 | test_serialization>>( 44 | join(argv[1], "storage_adaptor_serialization_test_vector_thread_safe_int.xml")); 45 | 46 | return boost::report_errors(); 47 | } 48 | -------------------------------------------------------------------------------- /test/storage_adaptor_serialization_test_array_unsigned.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 3 15 | 16 | 0 17 | 1 18 | 2 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /test/storage_adaptor_serialization_test_map_double.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 3 15 | 16 | 2 17 | 0 18 | 19 | 1 20 | 1.00000000000000000e+00 21 | 22 | 23 | 2 24 | 2.00000000000000000e+00 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /test/storage_adaptor_serialization_test_vector_int.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 3 16 | 0 17 | 0 18 | 1 19 | 2 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /test/storage_adaptor_serialization_test_vector_thread_safe_int.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 3 16 | 0 17 | 18 | 0 19 | 20 | 21 | 1 22 | 23 | 24 | 2 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /test/storage_adaptor_threaded_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "throw_exception.hpp" 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | using namespace boost::histogram; 21 | 22 | constexpr auto n_fill = 1000000; 23 | 24 | template 25 | void tests() { 26 | { 27 | storage_adaptor s; 28 | s.reset(1); 29 | 30 | auto fill = [&s]() { 31 | for (unsigned i = 0; i < n_fill; ++i) { 32 | ++s[0]; 33 | s[0] += 1; 34 | } 35 | }; 36 | 37 | std::thread t1(fill); 38 | std::thread t2(fill); 39 | std::thread t3(fill); 40 | std::thread t4(fill); 41 | t1.join(); 42 | t2.join(); 43 | t3.join(); 44 | t4.join(); 45 | 46 | BOOST_TEST_EQ(s[0], 4 * 2 * n_fill); 47 | } 48 | } 49 | 50 | int main() { 51 | using ts_int = accumulators::count; 52 | tests>(); 53 | tests>(); 54 | tests>(); 55 | // stdlib maps are not thread-safe and not supported 56 | 57 | return boost::report_errors(); 58 | } 59 | -------------------------------------------------------------------------------- /test/str.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifndef BOOST_HISTOGRAM_TEST_UTILITY_STR_HPP 8 | #define BOOST_HISTOGRAM_TEST_UTILITY_STR_HPP 9 | 10 | #include 11 | 12 | template 13 | auto str(const T& t, int w = 0, bool left = true) { 14 | std::ostringstream os; 15 | auto saved = os.width(); 16 | os.width(w); 17 | if (left) 18 | os << std::left; 19 | else 20 | os << std::right; 21 | os << t; 22 | os.width(saved); 23 | return os.str(); 24 | } 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /test/throw_exception.hpp: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #ifdef BOOST_NO_EXCEPTIONS 8 | 9 | #include 10 | #include // std::abort 11 | #include 12 | #include 13 | 14 | namespace boost { 15 | 16 | // dummy implementation for user-defined function from boost/throw_exception.hpp 17 | inline void throw_exception(std::exception const& e, boost::source_location const& l) { 18 | std::cerr << l.file_name() << ":" << l.line() << ":" << l.column() << ": exception in '" 19 | << l.function_name() << " \"" << e.what() << "\"" << std::endl; 20 | std::abort(); 21 | } 22 | 23 | } // namespace boost 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /test/tools_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "allocator.hpp" 12 | #include "ostream.hpp" 13 | #include "throw_exception.hpp" 14 | 15 | using namespace boost::histogram; 16 | 17 | int main() { 18 | // vector streaming 19 | { 20 | std::ostringstream os; 21 | std::vector v = {1, 3, 2}; 22 | os << v; 23 | BOOST_TEST_EQ(os.str(), std::string("[ 1 3 2 ]")); 24 | } 25 | 26 | // tuple streaming 27 | { 28 | std::ostringstream os; 29 | auto v = std::make_tuple(1, 2.5, "hi"); 30 | os << v; 31 | BOOST_TEST_EQ(os.str(), std::string("[ 1 2.5 hi ]")); 32 | } 33 | 34 | // tracing_allocator 35 | { 36 | tracing_allocator_db db; 37 | tracing_allocator a(db); 38 | auto p1 = a.allocate(2); 39 | a.deallocate(p1, 2); 40 | tracing_allocator b(a); 41 | auto p2 = b.allocate(3); 42 | b.deallocate(p2, 3); 43 | BOOST_TEST_EQ(db.size(), 2); 44 | BOOST_TEST_EQ(db.at().first, 0); 45 | BOOST_TEST_EQ(db.at().second, 2); 46 | BOOST_TEST_EQ(db.at().first, 0); 47 | BOOST_TEST_EQ(db.at().second, 3); 48 | BOOST_TEST_EQ(db.first, 0); 49 | BOOST_TEST_EQ(db.second, 2 + 3 * sizeof(int)); 50 | } 51 | 52 | return boost::report_errors(); 53 | } 54 | -------------------------------------------------------------------------------- /test/unlimited_storage_serialization_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "serialization.hpp" 16 | #include "throw_exception.hpp" 17 | 18 | using unlimited_storage_type = boost::histogram::unlimited_storage<>; 19 | 20 | using namespace boost::histogram; 21 | 22 | template 23 | unlimited_storage_type prepare(std::size_t n, const T x) { 24 | std::unique_ptr v(new T[n]); 25 | std::fill(v.get(), v.get() + n, static_cast(0)); 26 | v.get()[0] = x; 27 | return unlimited_storage_type(n, v.get()); 28 | } 29 | 30 | template 31 | unlimited_storage_type prepare(std::size_t n) { 32 | return unlimited_storage_type(n, static_cast(nullptr)); 33 | } 34 | 35 | template 36 | void run_test(const std::string& filename) { 37 | const auto a = prepare(1, T(1)); 38 | print_xml(filename, a); 39 | unlimited_storage_type b; 40 | BOOST_TEST(!(a == b)); 41 | load_xml(filename, b); 42 | BOOST_TEST(a == b); 43 | } 44 | 45 | int main(int argc, char** argv) { 46 | assert(argc == 2); 47 | 48 | run_test(join(argv[1], "unlimited_storage_serialization_test_u8.xml")); 49 | run_test(join(argv[1], "unlimited_storage_serialization_test_u16.xml")); 50 | run_test(join(argv[1], "unlimited_storage_serialization_test_u32.xml")); 51 | run_test(join(argv[1], "unlimited_storage_serialization_test_u64.xml")); 52 | run_test( 53 | join(argv[1], "unlimited_storage_serialization_test_large_int.xml")); 54 | run_test(join(argv[1], "unlimited_storage_serialization_test_double.xml")); 55 | 56 | return boost::report_errors(); 57 | } 58 | -------------------------------------------------------------------------------- /test/unlimited_storage_serialization_test_double.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 5 14 | 1 15 | 16 | 1.00000000000000000e+00 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/unlimited_storage_serialization_test_large_int.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 4 14 | 1 15 | 16 | 17 | 18 | 1 19 | 0 20 | 1 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /test/unlimited_storage_serialization_test_u16.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 1 14 | 1 15 | 16 | 1 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/unlimited_storage_serialization_test_u32.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 2 14 | 1 15 | 16 | 1 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/unlimited_storage_serialization_test_u64.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 3 14 | 1 15 | 16 | 1 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/unlimited_storage_serialization_test_u8.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 | 12 | 13 | 0 14 | 1 15 | 16 | 1 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/utility_binomial_proportion_interval_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include "is_close.hpp" 10 | #include "throw_exception.hpp" 11 | 12 | using namespace boost::histogram::utility; 13 | 14 | int main() { 15 | 16 | // confidence_level <-> deviation 17 | { 18 | confidence_level cl1 = deviation{1}; 19 | BOOST_TEST_IS_CLOSE(static_cast(cl1), 0.683, 1e-3); 20 | BOOST_TEST_IS_CLOSE(static_cast(deviation(cl1)), 1, 1e-8); 21 | confidence_level cl2 = deviation{2}; 22 | BOOST_TEST_IS_CLOSE(static_cast(cl2), 0.954, 1e-3); 23 | BOOST_TEST_IS_CLOSE(static_cast(deviation(cl2)), 2, 1e-8); 24 | confidence_level cl3 = deviation{3}; 25 | BOOST_TEST_IS_CLOSE(static_cast(cl3), 0.997, 1e-3); 26 | BOOST_TEST_IS_CLOSE(static_cast(deviation(cl3)), 3, 1e-8); 27 | } 28 | 29 | // invalid values 30 | { 31 | BOOST_TEST_THROWS((void)deviation{-0.5}, std::invalid_argument); 32 | BOOST_TEST_THROWS((void)confidence_level{-0.1}, std::invalid_argument); 33 | BOOST_TEST_THROWS((void)confidence_level{0}, std::invalid_argument); 34 | BOOST_TEST_THROWS((void)confidence_level{1.1}, std::invalid_argument); 35 | } 36 | 37 | return boost::report_errors(); 38 | } 39 | -------------------------------------------------------------------------------- /test/utility_clopper_pearson_interval_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "is_close.hpp" 12 | #include "throw_exception.hpp" 13 | 14 | using namespace boost::histogram::utility; 15 | using namespace boost::histogram::accumulators; 16 | 17 | template 18 | void test() { 19 | const T atol = 0.001; 20 | 21 | clopper_pearson_interval iv(deviation{1}); 22 | 23 | { 24 | const auto x = iv(0.f, 1.f); 25 | BOOST_TEST_IS_CLOSE(x.first, 0.f, atol); 26 | BOOST_TEST_IS_CLOSE(x.second, 0.841f, atol); 27 | 28 | fraction f(0.f, 1.f); 29 | const auto y = iv(f); 30 | BOOST_TEST_IS_CLOSE(y.first, 0.f, atol); 31 | BOOST_TEST_IS_CLOSE(y.second, 0.841f, atol); 32 | } 33 | 34 | { 35 | const auto x = iv(1.f, 0.f); 36 | BOOST_TEST_IS_CLOSE(x.first, 0.158f, atol); 37 | BOOST_TEST_IS_CLOSE(x.second, 1.f, atol); 38 | 39 | fraction f(1.f, 0.f); 40 | const auto y = iv(f); 41 | BOOST_TEST_IS_CLOSE(y.first, 0.158f, atol); 42 | BOOST_TEST_IS_CLOSE(y.second, 1.f, atol); 43 | } 44 | 45 | { 46 | const auto x = iv(5.f, 5.f); 47 | BOOST_TEST_IS_CLOSE(x.first, 0.304f, atol); 48 | BOOST_TEST_IS_CLOSE(x.second, 0.695f, atol); 49 | } 50 | 51 | { 52 | const auto x = iv(1.f, 9.f); 53 | BOOST_TEST_IS_CLOSE(x.first, 0.017f, atol); 54 | BOOST_TEST_IS_CLOSE(x.second, 0.294f, atol); 55 | } 56 | 57 | { 58 | const auto x = iv(9.f, 1.f); 59 | BOOST_TEST_IS_CLOSE(x.first, 0.705f, atol); 60 | BOOST_TEST_IS_CLOSE(x.second, 0.982f, atol); 61 | } 62 | } 63 | 64 | int main() { 65 | test(); 66 | test(); 67 | return boost::report_errors(); 68 | } 69 | -------------------------------------------------------------------------------- /test/utility_wald_interval_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "is_close.hpp" 12 | #include "throw_exception.hpp" 13 | 14 | using namespace boost::histogram::utility; 15 | using namespace boost::histogram::accumulators; 16 | 17 | int main() { 18 | 19 | const double atol = std::numeric_limits::epsilon(); 20 | 21 | wald_interval<> iv(deviation{1}); 22 | 23 | { 24 | const auto x = iv(0, 1); 25 | BOOST_TEST_IS_CLOSE(x.first, 0.0, atol); 26 | BOOST_TEST_IS_CLOSE(x.second, 0.0, atol); 27 | 28 | fraction<> f(0, 1); 29 | const auto y = iv(f); 30 | BOOST_TEST_IS_CLOSE(y.first, 0.0, atol); 31 | BOOST_TEST_IS_CLOSE(y.second, 0.0, atol); 32 | } 33 | 34 | { 35 | const auto x = iv(1, 0); 36 | BOOST_TEST_IS_CLOSE(x.first, 1.0, atol); 37 | BOOST_TEST_IS_CLOSE(x.second, 1.0, atol); 38 | 39 | fraction<> f(1, 0); 40 | const auto y = iv(f); 41 | BOOST_TEST_IS_CLOSE(y.first, 1.0, atol); 42 | BOOST_TEST_IS_CLOSE(y.second, 1.0, atol); 43 | } 44 | 45 | { 46 | const auto x = iv(5, 5); 47 | BOOST_TEST_IS_CLOSE(x.first, 0.341886116991581, atol); 48 | BOOST_TEST_IS_CLOSE(x.second, 0.658113883008419, atol); 49 | } 50 | 51 | { 52 | const auto x = iv(1, 9); 53 | BOOST_TEST_IS_CLOSE(x.first, 0.005131670194948618, atol); 54 | BOOST_TEST_IS_CLOSE(x.second, 0.1948683298050514, atol); 55 | } 56 | 57 | { 58 | const auto x = iv(9, 1); 59 | BOOST_TEST_IS_CLOSE(x.first, 0.8051316701949487, atol); 60 | BOOST_TEST_IS_CLOSE(x.second, 0.9948683298050514, atol); 61 | } 62 | 63 | return boost::report_errors(); 64 | } 65 | -------------------------------------------------------------------------------- /test/utility_wilson_interval_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Hans Dembinski 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt 5 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "is_close.hpp" 13 | #include "throw_exception.hpp" 14 | 15 | using namespace boost::histogram::utility; 16 | using namespace boost::histogram::accumulators; 17 | 18 | template 19 | void test() { 20 | const double atol = std::numeric_limits::epsilon(); 21 | 22 | wilson_interval iv; 23 | 24 | { 25 | const auto x = iv(0, 0); 26 | BOOST_TEST(std::isnan(x.first)); 27 | BOOST_TEST(std::isnan(x.second)); 28 | } 29 | 30 | { 31 | const auto x = iv(0, 1); 32 | BOOST_TEST_IS_CLOSE(x.first, 0.0, atol); 33 | BOOST_TEST_IS_CLOSE(x.second, 0.5, atol); 34 | 35 | fraction f(0, 1); 36 | const auto y = iv(f); 37 | BOOST_TEST_IS_CLOSE(y.first, 0.0, atol); 38 | BOOST_TEST_IS_CLOSE(y.second, 0.5, atol); 39 | } 40 | 41 | { 42 | const auto x = iv(1, 0); 43 | BOOST_TEST_IS_CLOSE(x.first, 0.5, atol); 44 | BOOST_TEST_IS_CLOSE(x.second, 1.0, atol); 45 | 46 | fraction f(1, 0); 47 | const auto y = iv(f); 48 | BOOST_TEST_IS_CLOSE(y.first, 0.5, atol); 49 | BOOST_TEST_IS_CLOSE(y.second, 1.0, atol); 50 | } 51 | 52 | { 53 | const auto x = iv(5, 5); 54 | BOOST_TEST_IS_CLOSE(x.first, 0.3492443277111182, atol); 55 | BOOST_TEST_IS_CLOSE(x.second, 0.6507556722888819, atol); 56 | } 57 | 58 | { 59 | const auto x = iv(1, 9); 60 | BOOST_TEST_IS_CLOSE(x.first, 0.03887449732033081, atol); 61 | BOOST_TEST_IS_CLOSE(x.second, 0.23385277540694188, atol); 62 | } 63 | 64 | { 65 | const auto x = iv(9, 1); 66 | BOOST_TEST_IS_CLOSE(x.first, 0.7661472245930581, atol); 67 | BOOST_TEST_IS_CLOSE(x.second, 0.9611255026796692, atol); 68 | } 69 | } 70 | 71 | int main() { 72 | 73 | test(); 74 | test(); 75 | 76 | return boost::report_errors(); 77 | } 78 | -------------------------------------------------------------------------------- /tools/add_boilerplate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright Hans Dembinski 2019 4 | # Distributed under the Boost Software License, Version 1.0. 5 | # See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt 6 | 7 | import sys 8 | from os.path import abspath, join 9 | import re 10 | import datetime 11 | 12 | project_dir = "/".join(abspath(__file__).split("/")[:-2]) 13 | 14 | filename = abspath(sys.argv[1]) 15 | 16 | copyright = """// Copyright Hans Dembinski {} 17 | // 18 | // Distributed under the Boost Software License, Version 1.0. 19 | // (See accompanying file LICENSE_1_0.txt 20 | // or copy at http://www.boost.org/LICENSE_1_0.txt) 21 | 22 | """.format(datetime.datetime.today().year) 23 | 24 | if filename.endswith(".hpp"): 25 | with open(filename) as f: 26 | content = f.read() 27 | if not content.startswith("// Copyright"): 28 | content = copyright + content 29 | 30 | sub = filename[len(project_dir) + 1:] 31 | if sub.startswith("include/boost/"): 32 | sub = sub[len("include/boost/"):] 33 | if sub.startswith("test/"): 34 | sub = "histogram/" + sub 35 | guard_name = "BOOST_" + sub.replace(".", "_").replace("/", "_").upper() 36 | 37 | if guard_name not in content: 38 | lines = content.split("\n") 39 | for end, line in enumerate(lines): 40 | if line.startswith("//"): 41 | continue 42 | break 43 | for start in range(end, len(lines)): 44 | if lines[start] != "": 45 | break 46 | lines = lines[:end] + ["", "#ifndef " + guard_name, "#define " + guard_name, ""] + lines[start:] 47 | while lines[-1] == "": 48 | lines.pop() 49 | lines += ["", "#endif // " + guard_name, ""] 50 | content = "\n".join(lines) 51 | 52 | with open(filename, "w") as f: 53 | f.write(content) 54 | -------------------------------------------------------------------------------- /tools/blacklist.supp: -------------------------------------------------------------------------------- 1 | # boost/serialization/singleton.hpp:181:13: runtime error: reference binding to null pointer of type X 2 | src:../../boost/serialization/singleton.hpp 3 | 4 | # boost/archive/detail/interface_oarchive.hpp:47:16: runtime error: downcast of address X which does not point to an object of type Y 5 | src:../../boost/archive/detail/interface_oarchive.hpp 6 | 7 | # boost/archive/detail/interface_iarchive.hpp:46:16: runtime error: downcast of address X which does not point to an object of type Y 8 | src:../../boost/archive/detail/interface_iarchive.hpp 9 | 10 | # boost/archive/basic_binary_oprimitive.hpp:73:16: runtime error: downcast of address X which does not point to an object of type Y 11 | src:../../boost/archive/basic_binary_oprimitive.hpp 12 | 13 | # boost/archive/basic_binary_iprimitive.hpp:77:16: runtime error: downcast of address X which does not point to an object of type Y 14 | src:../../boost/archive/basic_binary_iprimitive.hpp 15 | 16 | # boost/archive/iterators/escape.hpp:85:12: runtime error: applying non-zero offset 1 to null pointer 17 | src:../../boost/archive/iterators/escape.hpp 18 | -------------------------------------------------------------------------------- /tools/crlf_to_lf.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Copyright Hans Dembinski 2019 4 | # Distributed under the Boost Software License, Version 1.0. 5 | # See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt 6 | 7 | # Find files with CRLF: `find -not -type d -exec file "{}" ";" | grep CRLF` 8 | 9 | perl -pi -e 's/\r\n/\n/g' $1 10 | -------------------------------------------------------------------------------- /tools/llvm-gcov.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Copyright Hans Dembinski 2018-2019 4 | # Distributed under the Boost Software License, Version 1.0. 5 | # See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt 6 | 7 | exec llvm-cov gcov "$@" 8 | -------------------------------------------------------------------------------- /tools/tidy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright 2019 Hans Dembinski 4 | # Distributed under the Boost Software License, Version 1.0. 5 | # See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt 6 | 7 | import subprocess as subp 8 | from pathlib import Path 9 | from multiprocessing.pool import ThreadPool 10 | 11 | clang_tidy_cmd = None 12 | for version in range(15, 5, -1): 13 | clang_tidy_cmd = f"clang-tidy-{version}" 14 | if subp.run(("which", clang_tidy_cmd), stdout=subp.DEVNULL).returncode == 0: 15 | break 16 | 17 | project_dir = Path(__file__).resolve().parents[1] 18 | assert project_dir.exists() 19 | boost_dir = project_dir.parents[1] 20 | 21 | filenames = (project_dir / "include").rglob("*.hpp") 22 | 23 | 24 | def run_tidy(filename): 25 | n = len(project_dir.parts) + 2 26 | cmd = f"{clang_tidy_cmd} {filename} -- -I{boost_dir}" 27 | return ( 28 | cmd, 29 | subp.run(cmd.split(), stdout=subp.PIPE, stderr=subp.STDOUT).stdout.decode( 30 | "utf-8" 31 | ), 32 | ) 33 | 34 | 35 | pool = ThreadPool() 36 | for cmd, report in pool.map(run_tidy, filenames): 37 | if report: 38 | print(cmd) 39 | print(report) 40 | --------------------------------------------------------------------------------