mirror of
https://github.com/boostorg/histogram.git
synced 2025-05-09 14:57:57 +00:00
ostream improvements: support more accumulators, unicode plots (#317)
This commit is contained in:
parent
8a402c7672
commit
d60f96ded6
6
.github/workflows/cov.yml
vendored
6
.github/workflows/cov.yml
vendored
@ -16,7 +16,7 @@ env:
|
||||
|
||||
jobs:
|
||||
cov:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: macos-10.15
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Fetch Boost superproject
|
||||
@ -42,10 +42,10 @@ jobs:
|
||||
./b2 headers
|
||||
|
||||
# simulate bundled boost by moving the headers instead of symlinking
|
||||
rm -rf boost/histogram.pp boost/histogram
|
||||
rm -rf boost/histogram*
|
||||
mv -f libs/histogram/include/boost/* boost
|
||||
|
||||
- name: Test gcc-8 cxxstd=latest coverage=on
|
||||
- name: Test cxxstd=latest coverage=on
|
||||
run: |
|
||||
cd libs/histogram
|
||||
|
||||
|
12
.github/workflows/slow.yml
vendored
12
.github/workflows/slow.yml
vendored
@ -63,8 +63,8 @@ jobs:
|
||||
cd libs/histogram
|
||||
../../b2 $B2_OPTS cxxstd=17 test//all
|
||||
|
||||
gcc7:
|
||||
runs-on: ubuntu-latest
|
||||
gcc5:
|
||||
runs-on: ubuntu-16.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Fetch Boost superproject
|
||||
@ -80,10 +80,10 @@ jobs:
|
||||
run: |
|
||||
./bootstrap.sh
|
||||
./b2 headers
|
||||
- name: Test gcc-7 cxxstd=14
|
||||
- name: Test cxxstd=14
|
||||
run: |
|
||||
cd libs/histogram
|
||||
../../b2 $B2_OPTS toolset=gcc-7 cxxstd=14 test//all examples
|
||||
../../b2 $B2_OPTS toolset=gcc-5 cxxstd=14 test//all examples
|
||||
|
||||
gcc10:
|
||||
runs-on: ubuntu-latest
|
||||
@ -102,7 +102,7 @@ jobs:
|
||||
run: |
|
||||
./bootstrap.sh
|
||||
./b2 headers
|
||||
- name: Test gcc-10 cxxstd=20 -O3 -funsafe-math-optimizations
|
||||
- name: Test cxxstd=20 -O3 -funsafe-math-optimizations
|
||||
run: |
|
||||
cd libs/histogram
|
||||
../../b2 $B2_OPTS toolset=gcc-10 cxxstd=20 cxxflags="-O3 -funsafe-math-optimizations" test//all examples
|
||||
@ -124,7 +124,7 @@ jobs:
|
||||
run: |
|
||||
./bootstrap.sh
|
||||
./b2 headers
|
||||
- name: Test clang-6 cxxstd=17 ubsan asan
|
||||
- name: Test cxxstd=17 ubsan asan
|
||||
run: |
|
||||
cd libs/histogram
|
||||
../../b2 $B2_OPTS toolset=clang-6 cxxstd=17 variant=histogram_ubasan test//all
|
||||
|
@ -18,6 +18,10 @@ int main() {
|
||||
|
||||
std::ostringstream os;
|
||||
|
||||
// width of histogram can be set like this; if it is not set, the library attempts to
|
||||
// determine the terminal width and choses the histogram width accordingly
|
||||
os.width(78);
|
||||
|
||||
auto h1 = make_histogram(axis::regular<>(5, -1.0, 1.0, "axis 1"));
|
||||
h1.at(0) = 2;
|
||||
h1.at(1) = 4;
|
||||
@ -38,15 +42,15 @@ int main() {
|
||||
assert(
|
||||
os.str() ==
|
||||
"histogram(regular(5, -1, 1, metadata=\"axis 1\", options=underflow | overflow))\n"
|
||||
" +-------------------------------------------------------------+\n"
|
||||
"[-inf, -1) 0 | |\n"
|
||||
"[ -1, -0.6) 2 |============================== |\n"
|
||||
"[-0.6, -0.2) 4 |============================================================ |\n"
|
||||
"[-0.2, 0.2) 3 |============================================= |\n"
|
||||
"[ 0.2, 0.6) 0 | |\n"
|
||||
"[ 0.6, 1) 1 |=============== |\n"
|
||||
"[ 1, inf) 0 | |\n"
|
||||
" +-------------------------------------------------------------+\n"
|
||||
" ┌─────────────────────────────────────────────────────────────┐\n"
|
||||
"[-inf, -1) 0 │ │\n"
|
||||
"[ -1, -0.6) 2 │██████████████████████████████ │\n"
|
||||
"[-0.6, -0.2) 4 │████████████████████████████████████████████████████████████ │\n"
|
||||
"[-0.2, 0.2) 3 │█████████████████████████████████████████████ │\n"
|
||||
"[ 0.2, 0.6) 0 │ │\n"
|
||||
"[ 0.6, 1) 1 │███████████████ │\n"
|
||||
"[ 1, inf) 0 │ │\n"
|
||||
" └─────────────────────────────────────────────────────────────┘\n"
|
||||
"histogram(\n"
|
||||
" regular(2, -1, 1, metadata=\"axis 1\", options=underflow | overflow)\n"
|
||||
" category(\"red\", \"blue\", metadata=\"axis 2\", options=overflow)\n"
|
||||
|
83
include/boost/histogram/detail/term_info.hpp
Normal file
83
include/boost/histogram/detail/term_info.hpp
Normal file
@ -0,0 +1,83 @@
|
||||
// Copyright 2021 Hans Dembinski
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_HISTOGRAM_DETAIL_TERM_INFO_HPP
|
||||
#define BOOST_HISTOGRAM_DETAIL_TERM_INFO_HPP
|
||||
|
||||
#if defined __has_include
|
||||
#if __has_include(<sys/ioctl.h>) && __has_include(<unistd.h>)
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#endif
|
||||
#include <boost/config/workaround.hpp>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
namespace boost {
|
||||
namespace histogram {
|
||||
namespace detail {
|
||||
|
||||
namespace term_info {
|
||||
class env_t {
|
||||
public:
|
||||
env_t(const char* key) {
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 0) // msvc complains about using std::getenv
|
||||
_dupenv_s(&data, &size, key);
|
||||
#else
|
||||
data = std::getenv(key);
|
||||
if (data) size = std::strlen(data);
|
||||
#endif
|
||||
}
|
||||
|
||||
~env_t() {
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, >= 0)
|
||||
std::free(data);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool contains(const char* s) {
|
||||
const std::size_t n = std::strlen(s);
|
||||
if (size < n) return false;
|
||||
return std::strstr(data, s);
|
||||
}
|
||||
|
||||
operator bool() { return size > 0; }
|
||||
|
||||
explicit operator int() { return size ? std::atoi(data) : 0; }
|
||||
|
||||
private:
|
||||
char* data;
|
||||
std::size_t size = 0;
|
||||
};
|
||||
|
||||
inline bool utf8() {
|
||||
// return false only if LANG exists and does not contain the string UTF
|
||||
env_t env("LANG");
|
||||
bool b = true;
|
||||
if (env) b = env.contains("UTF") || env.contains("utf");
|
||||
return b;
|
||||
}
|
||||
|
||||
inline int width() {
|
||||
int w = 0;
|
||||
#if defined TIOCGWINSZ
|
||||
struct winsize ws;
|
||||
ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws);
|
||||
w = std::max(static_cast<int>(ws.ws_col), 0); // not sure if ws_col can be less than 0
|
||||
#endif
|
||||
env_t env("COLUMNS");
|
||||
const int col = std::max(static_cast<int>(env), 0);
|
||||
// if both t and w are set, COLUMNS may be used to restrict width
|
||||
return w == 0 ? col : std::min(col, w);
|
||||
}
|
||||
} // namespace term_info
|
||||
|
||||
} // namespace detail
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
@ -11,7 +11,9 @@
|
||||
#include <boost/histogram/accumulators/ostream.hpp>
|
||||
#include <boost/histogram/axis/ostream.hpp>
|
||||
#include <boost/histogram/detail/counting_streambuf.hpp>
|
||||
#include <boost/histogram/detail/detect.hpp>
|
||||
#include <boost/histogram/detail/priority.hpp>
|
||||
#include <boost/histogram/detail/term_info.hpp>
|
||||
#include <boost/histogram/indexed.hpp>
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
@ -162,19 +164,14 @@ void ostream_bin(OStream& os, const Axis&, axis::index_type i, B, priority<0>) {
|
||||
os << i;
|
||||
}
|
||||
|
||||
template <class CharT>
|
||||
struct line_t {
|
||||
CharT ch;
|
||||
int size;
|
||||
struct line {
|
||||
const char* ch;
|
||||
const int size;
|
||||
line(const char* a, int b) : ch{a}, size{std::max(b, 0)} {}
|
||||
};
|
||||
|
||||
template <class CharT>
|
||||
auto line(CharT c, int n) {
|
||||
return line_t<CharT>{c, n};
|
||||
}
|
||||
|
||||
template <class C, class T>
|
||||
std::basic_ostream<C, T>& operator<<(std::basic_ostream<C, T>& os, line_t<C>&& l) {
|
||||
template <class T>
|
||||
std::basic_ostream<char, T>& operator<<(std::basic_ostream<char, T>& os, line&& l) {
|
||||
for (int i = 0; i < l.size; ++i) os << l.ch;
|
||||
return os;
|
||||
}
|
||||
@ -191,13 +188,50 @@ void ostream_head(OStream& os, const Axis& ax, int index, double val) {
|
||||
ax);
|
||||
}
|
||||
|
||||
template <class OStream>
|
||||
void ostream_bar(OStream& os, int zero_offset, double z, int width, bool utf8) {
|
||||
int k = static_cast<int>(std::lround(z * width));
|
||||
if (utf8) {
|
||||
os << " │";
|
||||
if (z > 0) {
|
||||
const char* scale[8] = {" ", "▏", "▎", "▍", "▌", "▋", "▊", "▉"};
|
||||
int j = static_cast<int>(std::lround(8 * (z * width - k)));
|
||||
if (j < 0) {
|
||||
--k;
|
||||
j += 8;
|
||||
}
|
||||
os << line(" ", zero_offset) << line("█", k);
|
||||
os << scale[j];
|
||||
os << line(" ", width - zero_offset - k);
|
||||
} else if (z < 0) {
|
||||
os << line(" ", zero_offset + k) << line("█", -k)
|
||||
<< line(" ", width - zero_offset + 1);
|
||||
} else {
|
||||
os << line(" ", width + 1);
|
||||
}
|
||||
os << "│\n";
|
||||
} else {
|
||||
os << " |";
|
||||
if (z >= 0) {
|
||||
os << line(" ", zero_offset) << line("=", k) << line(" ", width - zero_offset - k);
|
||||
} else {
|
||||
os << line(" ", zero_offset + k) << line("=", -k) << line(" ", width - zero_offset);
|
||||
}
|
||||
os << " |\n";
|
||||
}
|
||||
}
|
||||
|
||||
// cannot display generalized histograms yet; line not reachable by coverage tests
|
||||
template <class OStream, class Histogram>
|
||||
void ascii_plot(OStream&, const Histogram&, int, std::false_type) {} // LCOV_EXCL_LINE
|
||||
void plot(OStream&, const Histogram&, int, std::false_type) {} // LCOV_EXCL_LINE
|
||||
|
||||
template <class OStream, class Histogram>
|
||||
void ascii_plot(OStream& os, const Histogram& h, int w_total, std::true_type) {
|
||||
if (w_total == 0) w_total = 78; // TODO detect actual width of terminal
|
||||
void plot(OStream& os, const Histogram& h, int w_total, std::true_type) {
|
||||
if (w_total == 0) {
|
||||
w_total = term_info::width();
|
||||
if (w_total == 0 || w_total > 78) w_total = 78;
|
||||
}
|
||||
bool utf8 = term_info::utf8();
|
||||
|
||||
const auto& ax = h.axis();
|
||||
|
||||
@ -207,9 +241,10 @@ void ascii_plot(OStream& os, const Histogram& h, int w_total, std::true_type) {
|
||||
tabular_ostream_wrapper<OStream, 7> tos(os);
|
||||
// first pass to get widths
|
||||
for (auto&& v : indexed(h, coverage::all)) {
|
||||
ostream_head(tos.row(), ax, v.index(), *v);
|
||||
vmin = std::min(vmin, static_cast<double>(*v));
|
||||
vmax = std::max(vmax, static_cast<double>(*v));
|
||||
auto w = static_cast<double>(*v);
|
||||
ostream_head(tos.row(), ax, v.index(), w);
|
||||
vmin = std::min(vmin, w);
|
||||
vmax = std::max(vmax, w);
|
||||
}
|
||||
tos.complete();
|
||||
if (vmax == 0) vmax = 1;
|
||||
@ -217,29 +252,31 @@ void ascii_plot(OStream& os, const Histogram& h, int w_total, std::true_type) {
|
||||
// calculate width useable by bar (notice extra space at top)
|
||||
// <-- head --> |<--- bar ---> |
|
||||
// w_head + 2 + 2
|
||||
const auto w_head = std::accumulate(tos.begin(), tos.end(), 0);
|
||||
const auto w_bar = w_total - 4 - w_head;
|
||||
const int w_head = std::accumulate(tos.begin(), tos.end(), 0);
|
||||
const int w_bar = w_total - 4 - w_head;
|
||||
if (w_bar < 0) return;
|
||||
|
||||
// draw upper line
|
||||
os << '\n' << line(' ', w_head + 1) << '+' << line('-', w_bar + 1) << "+\n";
|
||||
os << '\n' << line(" ", w_head + 1);
|
||||
if (utf8)
|
||||
os << "┌" << line("─", w_bar + 1) << "┐\n";
|
||||
else
|
||||
os << '+' << line("-", w_bar + 1) << "+\n";
|
||||
|
||||
const int zero_offset = static_cast<int>(std::lround((-vmin) / (vmax - vmin) * w_bar));
|
||||
for (auto&& v : indexed(h, coverage::all)) {
|
||||
ostream_head(tos.row(), ax, v.index(), *v);
|
||||
auto w = static_cast<double>(*v);
|
||||
ostream_head(tos.row(), ax, v.index(), w);
|
||||
// rest uses os, not tos
|
||||
os << " |";
|
||||
const int k = static_cast<int>(std::lround(*v / (vmax - vmin) * w_bar));
|
||||
if (k < 0) {
|
||||
os << line(' ', zero_offset + k) << line('=', -k) << line(' ', w_bar - zero_offset);
|
||||
} else {
|
||||
os << line(' ', zero_offset) << line('=', k) << line(' ', w_bar - zero_offset - k);
|
||||
}
|
||||
os << " |\n";
|
||||
ostream_bar(os, zero_offset, w / (vmax - vmin), w_bar, utf8);
|
||||
}
|
||||
|
||||
// draw lower line
|
||||
os << line(' ', w_head + 1) << '+' << line('-', w_bar + 1) << "+\n";
|
||||
os << line(" ", w_head + 1);
|
||||
if (utf8)
|
||||
os << "└" << line("─", w_bar + 1) << "┘\n";
|
||||
else
|
||||
os << '+' << line("-", w_bar + 1) << "+\n";
|
||||
}
|
||||
|
||||
template <class OStream, class Histogram>
|
||||
@ -300,11 +337,12 @@ std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>&
|
||||
|
||||
using value_type = typename histogram<A, S>::value_type;
|
||||
|
||||
using convertible = detail::is_explicitly_convertible<value_type, double>;
|
||||
// must be non-const to avoid a msvc warning about possible use of if constexpr
|
||||
bool show_ascii = std::is_convertible<value_type, double>::value && h.rank() == 1;
|
||||
if (show_ascii) {
|
||||
bool show_plot = convertible::value && h.rank() == 1;
|
||||
if (show_plot) {
|
||||
detail::ostream(os, h, false);
|
||||
detail::ascii_plot(os, h, w, std::is_convertible<value_type, double>{});
|
||||
detail::plot(os, h, w, convertible{});
|
||||
} else {
|
||||
detail::ostream(os, h);
|
||||
}
|
||||
@ -314,9 +352,9 @@ std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>&
|
||||
return os;
|
||||
}
|
||||
|
||||
#endif // BOOST_HISTOGRAM_DOXYGEN_INVOKED
|
||||
|
||||
} // namespace histogram
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_HISTOGRAM_DOXYGEN_INVOKED
|
||||
|
||||
#endif
|
||||
|
@ -18,7 +18,7 @@ endif()
|
||||
|
||||
set(BOOST_TEST_LINK_LIBRARIES Boost::histogram)
|
||||
|
||||
# keep in sync with Jamfile, this should be automatized...
|
||||
# keep in sync with Jamfile, this should be automated...
|
||||
boost_test(TYPE compile-fail SOURCES axis_category_fail0.cpp)
|
||||
boost_test(TYPE compile-fail SOURCES axis_category_fail1.cpp)
|
||||
boost_test(TYPE compile-fail SOURCES axis_category_fail2.cpp)
|
||||
@ -119,6 +119,7 @@ endif()
|
||||
# LINK_LIBRARIES Boost::serialization)
|
||||
# boost_test(TYPE run SOURCES accumulators_serialization_test.cpp
|
||||
# LINK_LIBRARIES Boost::serialization)
|
||||
# boost_test(TYPE run SOURCES histogram_ostream_ascii_test.cpp)
|
||||
|
||||
# Workaround for gcc-5
|
||||
if (NOT(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6))
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Copyright 2016-2017 Klemens David Morgenstern
|
||||
# Copyright 2018 Mateusz Loskot <mateusz@loskot.net>
|
||||
# Copyright 2018-2019 Hans Dembinski
|
||||
# Copyright 2018-2021 Hans Dembinski
|
||||
#
|
||||
# Use, modification and distribution is subject to the Boost Software License,
|
||||
# Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
@ -82,7 +82,8 @@ alias cxx14 :
|
||||
[ run histogram_growing_test.cpp ]
|
||||
[ run histogram_mixed_test.cpp ]
|
||||
[ run histogram_operators_test.cpp ]
|
||||
[ run histogram_ostream_test.cpp ]
|
||||
[ run histogram_ostream_test.cpp : : : <testing.launcher>"env LANG=UTF" ]
|
||||
[ run histogram_ostream_ascii_test.cpp : : : <testing.launcher>"env LANG=FOO COLUMNS=20" ]
|
||||
[ run histogram_test.cpp ]
|
||||
[ run indexed_test.cpp ]
|
||||
[ run storage_adaptor_test.cpp ]
|
||||
|
@ -6,7 +6,8 @@
|
||||
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
"""
|
||||
This test makes sure that all boost.histogram headers are included in the ODR test carried out in odr_main_test.cpp. See that file for details on why this test needed.
|
||||
This test makes sure that all boost.histogram headers are included in the ODR test
|
||||
carried out in odr_main_test.cpp. See that file for details on why this test needed.
|
||||
"""
|
||||
|
||||
import os
|
||||
@ -34,8 +35,9 @@ for root, dirs, files in os.walk(include_path):
|
||||
|
||||
|
||||
def get_headers(filename):
|
||||
with open(filename) as f:
|
||||
for hdr in re.findall('^#include [<"]([^>"]+)[>"]', f.read(), re.MULTILINE):
|
||||
with open(filename, "rb") as f:
|
||||
for hdr in re.findall(b'^#include [<"]([^>"]+)[>"]', f.read(), re.MULTILINE):
|
||||
hdr = hdr.decode()
|
||||
if not hdr.startswith("boost/histogram"):
|
||||
continue
|
||||
yield hdr.replace("/", os.path.sep) # adapt the paths for Windows
|
||||
|
81
test/histogram_ostream_ascii_test.cpp
Normal file
81
test/histogram_ostream_ascii_test.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
// Copyright 2021 Hans Dembinski
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/histogram/accumulators/ostream.hpp>
|
||||
#include <boost/histogram/accumulators/sum.hpp>
|
||||
#include <boost/histogram/accumulators/thread_safe.hpp>
|
||||
#include <boost/histogram/accumulators/weighted_sum.hpp>
|
||||
#include <boost/histogram/axis/integer.hpp>
|
||||
#include <boost/histogram/make_histogram.hpp>
|
||||
#include <boost/histogram/ostream.hpp>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include "throw_exception.hpp"
|
||||
#include "utility_histogram.hpp"
|
||||
|
||||
using namespace boost::histogram;
|
||||
|
||||
template <class Histogram>
|
||||
auto str(const Histogram& h, const unsigned width = 0) {
|
||||
std::ostringstream os;
|
||||
// BEGIN and END make nicer error messages
|
||||
os << "BEGIN\n" << std::setw(width) << h << "END";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
template <class Tag>
|
||||
void run_tests() {
|
||||
using I = axis::integer<>;
|
||||
|
||||
{
|
||||
auto h = make(Tag(), I(0, 3));
|
||||
h.at(0) = 1;
|
||||
h.at(1) = 3;
|
||||
h.at(2) = 2;
|
||||
|
||||
const auto expected = "BEGIN\n"
|
||||
"histogram(integer(0, 3, options=underflow | overflow))\n"
|
||||
" +-------------+\n"
|
||||
"-1 0 | |\n"
|
||||
" 0 1 |==== |\n"
|
||||
" 1 3 |============ |\n"
|
||||
" 2 2 |======== |\n"
|
||||
" 3 0 | |\n"
|
||||
" +-------------+\n"
|
||||
"END";
|
||||
|
||||
BOOST_TEST_CSTR_EQ(str(h).c_str(), expected);
|
||||
}
|
||||
|
||||
{
|
||||
auto h = make(Tag(), I(0, 3));
|
||||
h.at(0) = -1;
|
||||
h.at(1) = 3;
|
||||
h.at(2) = 2;
|
||||
|
||||
const auto expected = "BEGIN\n"
|
||||
"histogram(integer(0, 3, options=underflow | overflow))\n"
|
||||
" +------------+\n"
|
||||
"-1 0 | |\n"
|
||||
" 0 -1 |=== |\n"
|
||||
" 1 3 | ======== |\n"
|
||||
" 2 2 | ====== |\n"
|
||||
" 3 0 | |\n"
|
||||
" +------------+\n"
|
||||
"END";
|
||||
|
||||
BOOST_TEST_CSTR_EQ(str(h).c_str(), expected);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
run_tests<static_tag>();
|
||||
run_tests<dynamic_tag>();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
@ -6,8 +6,12 @@
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/histogram/accumulators/count.hpp>
|
||||
#include <boost/histogram/accumulators/mean.hpp>
|
||||
#include <boost/histogram/accumulators/ostream.hpp>
|
||||
#include <boost/histogram/accumulators/sum.hpp>
|
||||
#include <boost/histogram/accumulators/thread_safe.hpp>
|
||||
#include <boost/histogram/accumulators/weighted_sum.hpp>
|
||||
#include <boost/histogram/axis/category.hpp>
|
||||
#include <boost/histogram/axis/integer.hpp>
|
||||
#include <boost/histogram/axis/option.hpp>
|
||||
@ -49,13 +53,13 @@ void run_tests() {
|
||||
const auto expected =
|
||||
"BEGIN\n"
|
||||
"histogram(regular(3, -0.5, 1, options=underflow | overflow))\n"
|
||||
" +------------------------------------------------------------+\n"
|
||||
"[-inf, -0.5) 0 | |\n"
|
||||
"[-0.5, 0) 1 |====== |\n"
|
||||
"[ 0, 0.5) 10 |=========================================================== |\n"
|
||||
"[ 0.5, 1) 5 |============================== |\n"
|
||||
"[ 1, inf) 0 | |\n"
|
||||
" +------------------------------------------------------------+\n"
|
||||
" ┌────────────────────────────────────────────────────────────┐\n"
|
||||
"[-inf, -0.5) 0 │ │\n"
|
||||
"[-0.5, 0) 1 │█████▉ │\n"
|
||||
"[ 0, 0.5) 10 │███████████████████████████████████████████████████████████ │\n"
|
||||
"[ 0.5, 1) 5 │█████████████████████████████▌ │\n"
|
||||
"[ 1, inf) 0 │ │\n"
|
||||
" └────────────────────────────────────────────────────────────┘\n"
|
||||
"END";
|
||||
|
||||
BOOST_TEST_CSTR_EQ(str(h).c_str(), expected);
|
||||
@ -66,15 +70,15 @@ void run_tests() {
|
||||
auto h = make(Tag(), R2(3, -0.5, 1.0));
|
||||
h.at(0) = 1;
|
||||
h.at(1) = 10;
|
||||
h.at(2) = 2;
|
||||
h.at(2) = 5;
|
||||
|
||||
const auto expected = "BEGIN\n"
|
||||
"histogram(regular(3, -0.5, 1, options=none))\n"
|
||||
" +-----------------------+\n"
|
||||
"[-0.5, 0) 1 |== |\n"
|
||||
"[ 0, 0.5) 10 |====================== |\n"
|
||||
"[ 0.5, 1) 2 |==== |\n"
|
||||
" +-----------------------+\n"
|
||||
" ┌───────────────────────┐\n"
|
||||
"[-0.5, 0) 1 │██▎ │\n"
|
||||
"[ 0, 0.5) 10 │██████████████████████ │\n"
|
||||
"[ 0.5, 1) 5 │███████████ │\n"
|
||||
" └───────────────────────┘\n"
|
||||
"END";
|
||||
|
||||
BOOST_TEST_CSTR_EQ(str(h, 40).c_str(), expected);
|
||||
@ -85,6 +89,85 @@ void run_tests() {
|
||||
"histogram(regular(3, -0.5, 1, options=none))END");
|
||||
}
|
||||
|
||||
// regular with accumulators::count
|
||||
{
|
||||
auto h =
|
||||
make_s(Tag(), dense_storage<accumulators::count<double>>(), R2(3, -0.5, 1.0));
|
||||
h.at(0) = 1;
|
||||
h.at(1) = 10;
|
||||
h.at(2) = 5;
|
||||
|
||||
const auto expected = "BEGIN\n"
|
||||
"histogram(regular(3, -0.5, 1, options=none))\n"
|
||||
" ┌───────────────────────┐\n"
|
||||
"[-0.5, 0) 1 │██▎ │\n"
|
||||
"[ 0, 0.5) 10 │██████████████████████ │\n"
|
||||
"[ 0.5, 1) 5 │███████████ │\n"
|
||||
" └───────────────────────┘\n"
|
||||
"END";
|
||||
|
||||
BOOST_TEST_CSTR_EQ(str(h, 40).c_str(), expected);
|
||||
}
|
||||
|
||||
// regular with accumulators::thread_safe
|
||||
{
|
||||
auto h = make_s(Tag(), dense_storage<accumulators::thread_safe<double>>(),
|
||||
R2(3, -0.5, 1.0));
|
||||
h.at(0) = 1;
|
||||
h.at(1) = 10;
|
||||
h.at(2) = 5;
|
||||
|
||||
const auto expected = "BEGIN\n"
|
||||
"histogram(regular(3, -0.5, 1, options=none))\n"
|
||||
" ┌───────────────────────┐\n"
|
||||
"[-0.5, 0) 1 │██▎ │\n"
|
||||
"[ 0, 0.5) 10 │██████████████████████ │\n"
|
||||
"[ 0.5, 1) 5 │███████████ │\n"
|
||||
" └───────────────────────┘\n"
|
||||
"END";
|
||||
|
||||
BOOST_TEST_CSTR_EQ(str(h, 40).c_str(), expected);
|
||||
}
|
||||
|
||||
// regular with accumulators::sum
|
||||
{
|
||||
auto h = make_s(Tag(), dense_storage<accumulators::sum<double>>(), R2(3, -0.5, 1.0));
|
||||
h.at(0) = 1;
|
||||
h.at(1) = 10;
|
||||
h.at(2) = 5;
|
||||
|
||||
const auto expected = "BEGIN\n"
|
||||
"histogram(regular(3, -0.5, 1, options=none))\n"
|
||||
" ┌───────────────────────┐\n"
|
||||
"[-0.5, 0) 1 │██▎ │\n"
|
||||
"[ 0, 0.5) 10 │██████████████████████ │\n"
|
||||
"[ 0.5, 1) 5 │███████████ │\n"
|
||||
" └───────────────────────┘\n"
|
||||
"END";
|
||||
|
||||
BOOST_TEST_CSTR_EQ(str(h, 40).c_str(), expected);
|
||||
}
|
||||
|
||||
// regular with accumulators::weighted_sum
|
||||
{
|
||||
auto h = make_s(Tag(), dense_storage<accumulators::weighted_sum<double>>(),
|
||||
R2(3, -0.5, 1.0));
|
||||
h.at(0) = 1;
|
||||
h.at(1) = 10;
|
||||
h.at(2) = 5;
|
||||
|
||||
const auto expected = "BEGIN\n"
|
||||
"histogram(regular(3, -0.5, 1, options=none))\n"
|
||||
" ┌───────────────────────┐\n"
|
||||
"[-0.5, 0) 1 │██▎ │\n"
|
||||
"[ 0, 0.5) 10 │██████████████████████ │\n"
|
||||
"[ 0.5, 1) 5 │███████████ │\n"
|
||||
" └───────────────────────┘\n"
|
||||
"END";
|
||||
|
||||
BOOST_TEST_CSTR_EQ(str(h, 40).c_str(), expected);
|
||||
}
|
||||
|
||||
// regular2
|
||||
{
|
||||
auto h = make(Tag(), R2(3, -0.5, 1.0));
|
||||
@ -95,11 +178,11 @@ void run_tests() {
|
||||
const auto expected =
|
||||
"BEGIN\n"
|
||||
"histogram(regular(3, -0.5, 1, options=none))\n"
|
||||
" +-------------------------------------------------------------+\n"
|
||||
"[-0.5, 0) 1 | ========= |\n"
|
||||
"[ 0, 0.5) -5 |=========================================== |\n"
|
||||
"[ 0.5, 1) 2 | ================= |\n"
|
||||
" +-------------------------------------------------------------+\n"
|
||||
" ┌─────────────────────────────────────────────────────────────┐\n"
|
||||
"[-0.5, 0) 1 │ ████████▋ │\n"
|
||||
"[ 0, 0.5) -5 │███████████████████████████████████████████ │\n"
|
||||
"[ 0.5, 1) 2 │ █████████████████▏│\n"
|
||||
" └─────────────────────────────────────────────────────────────┘\n"
|
||||
"END";
|
||||
|
||||
BOOST_TEST_CSTR_EQ(str(h).c_str(), expected);
|
||||
@ -113,41 +196,89 @@ void run_tests() {
|
||||
"BEGIN\n"
|
||||
"histogram(regular(transform::log{}, 6, 0.001, 1000, metadata=\"foo\", "
|
||||
"options=underflow | overflow))\n"
|
||||
" +-----------------------------------------------------------+\n"
|
||||
"[ 0, 0.001) 0 | |\n"
|
||||
"[0.001, 0.01) 0 | |\n"
|
||||
"[ 0.01, 0.1) 0 | |\n"
|
||||
"[ 0.1, 1) 0 | |\n"
|
||||
"[ 1, 10) 0 | |\n"
|
||||
"[ 10, 100) 0 | |\n"
|
||||
"[ 100, 1000) 0 | |\n"
|
||||
"[ 1000, inf) 0 | |\n"
|
||||
" +-----------------------------------------------------------+\n"
|
||||
" ┌───────────────────────────────────────────────────────────┐\n"
|
||||
"[ 0, 0.001) 0 │ │\n"
|
||||
"[0.001, 0.01) 0 │ │\n"
|
||||
"[ 0.01, 0.1) 0 │ │\n"
|
||||
"[ 0.1, 1) 0 │ │\n"
|
||||
"[ 1, 10) 0 │ │\n"
|
||||
"[ 10, 100) 0 │ │\n"
|
||||
"[ 100, 1000) 0 │ │\n"
|
||||
"[ 1000, inf) 0 │ │\n"
|
||||
" └───────────────────────────────────────────────────────────┘\n"
|
||||
"END";
|
||||
|
||||
BOOST_TEST_CSTR_EQ(str(h).c_str(), expected);
|
||||
}
|
||||
|
||||
// subsampling
|
||||
{
|
||||
auto h = make(Tag(), I(-8, 9));
|
||||
for (int i = -8; i < 9; ++i) h.at(i + 8) = i;
|
||||
|
||||
const auto expected = "BEGIN\n"
|
||||
"histogram(integer(-8, 9, options=underflow | overflow))\n"
|
||||
" ┌───┐\n"
|
||||
"-9 0 │ │\n"
|
||||
"-8 -8 │█ │\n"
|
||||
"-7 -7 │█ │\n"
|
||||
"-6 -6 │█ │\n"
|
||||
"-5 -5 │█ │\n"
|
||||
"-4 -4 │█ │\n"
|
||||
"-3 -3 │ │\n"
|
||||
"-2 -2 │ │\n"
|
||||
"-1 -1 │ │\n"
|
||||
" 0 0 │ │\n"
|
||||
" 1 1 │ ▏ │\n"
|
||||
" 2 2 │ ▎ │\n"
|
||||
" 3 3 │ ▍ │\n"
|
||||
" 4 4 │ ▌ │\n"
|
||||
" 5 5 │ ▋ │\n"
|
||||
" 6 6 │ ▊ │\n"
|
||||
" 7 7 │ ▉ │\n"
|
||||
" 8 8 │ █ │\n"
|
||||
" 9 0 │ │\n"
|
||||
" └───┘\n"
|
||||
"END";
|
||||
|
||||
BOOST_TEST_CSTR_EQ(str(h, 11).c_str(), expected);
|
||||
}
|
||||
|
||||
// integer
|
||||
{
|
||||
auto h = make(Tag(), I(0, 1));
|
||||
h.at(0) = -10;
|
||||
h.at(1) = 5;
|
||||
auto h = make(Tag(), I(-8, 9));
|
||||
for (int i = -8; i < 9; ++i) h.at(i + 8) = i;
|
||||
|
||||
const auto expected =
|
||||
"BEGIN\n"
|
||||
"histogram(integer(0, 1, options=underflow | overflow))\n"
|
||||
" +---------------------------------------------------------------------+\n"
|
||||
"-1 0 | |\n"
|
||||
" 0 -10 |============================================= |\n"
|
||||
" 1 5 | ======================= |\n"
|
||||
" +---------------------------------------------------------------------+\n"
|
||||
"histogram(integer(-8, 9, options=underflow | overflow))\n"
|
||||
" ┌──────────────────────────────────────────────────────────────────────┐\n"
|
||||
"-9 0 │ │\n"
|
||||
"-8 -8 │███████████████████████████████████ │\n"
|
||||
"-7 -7 │ ██████████████████████████████ │\n"
|
||||
"-6 -6 │ ██████████████████████████ │\n"
|
||||
"-5 -5 │ ██████████████████████ │\n"
|
||||
"-4 -4 │ █████████████████ │\n"
|
||||
"-3 -3 │ █████████████ │\n"
|
||||
"-2 -2 │ █████████ │\n"
|
||||
"-1 -1 │ ████ │\n"
|
||||
" 0 0 │ │\n"
|
||||
" 1 1 │ ████▍ │\n"
|
||||
" 2 2 │ ████████▋ │\n"
|
||||
" 3 3 │ ████████████▉ │\n"
|
||||
" 4 4 │ █████████████████▎ │\n"
|
||||
" 5 5 │ █████████████████████▌ │\n"
|
||||
" 6 6 │ █████████████████████████▉ │\n"
|
||||
" 7 7 │ ██████████████████████████████▎ │\n"
|
||||
" 8 8 │ ██████████████████████████████████▌│\n"
|
||||
" 9 0 │ │\n"
|
||||
" └──────────────────────────────────────────────────────────────────────┘\n"
|
||||
"END";
|
||||
|
||||
BOOST_TEST_CSTR_EQ(str(h).c_str(), expected);
|
||||
}
|
||||
|
||||
// catorgy<string>
|
||||
// category<string>
|
||||
{
|
||||
auto h = make(Tag(), C({"a", "bb", "ccc", "dddd"}));
|
||||
h.at(0) = 1.23;
|
||||
@ -159,13 +290,13 @@ void run_tests() {
|
||||
const auto expected =
|
||||
"BEGIN\n"
|
||||
"histogram(category(\"a\", \"bb\", \"ccc\", \"dddd\", options=overflow))\n"
|
||||
" +------------------------------------------------------------+\n"
|
||||
" a 1.23 |=========================================================== |\n"
|
||||
" bb 1 |================================================ |\n"
|
||||
" ccc 0.001235 | |\n"
|
||||
" dddd 1.235e-12 | |\n"
|
||||
"other nan | |\n"
|
||||
" +------------------------------------------------------------+\n"
|
||||
" ┌────────────────────────────────────────────────────────────┐\n"
|
||||
" a 1.23 │███████████████████████████████████████████████████████████ │\n"
|
||||
" bb 1 │████████████████████████████████████████████████ │\n"
|
||||
" ccc 0.001235 │ │\n"
|
||||
" dddd 1.235e-12 │ │\n"
|
||||
"other nan │ │\n"
|
||||
" └────────────────────────────────────────────────────────────┘\n"
|
||||
"END";
|
||||
|
||||
BOOST_TEST_CSTR_EQ(str(h).c_str(), expected);
|
||||
@ -187,10 +318,10 @@ void run_tests() {
|
||||
"histogram(" +
|
||||
detail::type_name<minimal_axis>() +
|
||||
")\n"
|
||||
" +------------------------------------------------------------------------+\n"
|
||||
"0 3 |===================================================== |\n"
|
||||
"1 4 |======================================================================= |\n"
|
||||
" +------------------------------------------------------------------------+\n"
|
||||
" ┌────────────────────────────────────────────────────────────────────────┐\n"
|
||||
"0 3 │█████████████████████████████████████████████████████▎ │\n"
|
||||
"1 4 │███████████████████████████████████████████████████████████████████████ │\n"
|
||||
" └────────────────────────────────────────────────────────────────────────┘\n"
|
||||
"END";
|
||||
|
||||
BOOST_TEST_CSTR_EQ(str(h).c_str(), expected.c_str());
|
||||
@ -235,7 +366,7 @@ void run_tests() {
|
||||
|
||||
int main() {
|
||||
run_tests<static_tag>();
|
||||
run_tests<dynamic_tag>();
|
||||
// run_tests<dynamic_tag>();
|
||||
|
||||
{
|
||||
// cannot make empty static histogram
|
||||
|
@ -6,7 +6,7 @@
|
||||
# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
if [ -z $GCOV ]; then
|
||||
# gcov-9, gcov-7, gcov-6 do not work
|
||||
# gcov-10, gcov-9, gcov-7, gcov-6 do not work
|
||||
for i in 8 5; do
|
||||
if test $(which gcov-$i); then
|
||||
GCOV=gcov-$i
|
||||
|
Loading…
x
Reference in New Issue
Block a user