diff --git a/include/boost/histogram/axis/category.hpp b/include/boost/histogram/axis/category.hpp index 857000d4..ee112f16 100644 --- a/include/boost/histogram/axis/category.hpp +++ b/include/boost/histogram/axis/category.hpp @@ -70,8 +70,12 @@ public: */ template > category(It begin, It end, metadata_type meta = {}, allocator_type alloc = {}) - : metadata_base(std::move(meta)), vec_(begin, end, alloc) { - if (size() == 0) BOOST_THROW_EXCEPTION(std::invalid_argument("bins > 0 required")); + : metadata_base(std::move(meta)), vec_(alloc) { + if (std::distance(begin, end) < 0) + BOOST_THROW_EXCEPTION( + std::invalid_argument("end must be reachable by incrementing begin")); + vec_.reserve(std::distance(begin, end)); + while (begin != end) vec_.emplace_back(*begin++); } /** Construct axis from iterable sequence of unique values. diff --git a/include/boost/histogram/axis/integer.hpp b/include/boost/histogram/axis/integer.hpp index 28d7dca3..ba94ac36 100644 --- a/include/boost/histogram/axis/integer.hpp +++ b/include/boost/histogram/axis/integer.hpp @@ -77,7 +77,8 @@ public: : metadata_base(std::move(meta)) , size_(static_cast(stop - start)) , min_(start) { - if (stop <= start) BOOST_THROW_EXCEPTION(std::invalid_argument("bins > 0 required")); + if (!(stop >= start)) + BOOST_THROW_EXCEPTION(std::invalid_argument("stop >= start required")); } /// Constructor used by algorithm::reduce to shrink and rebin. diff --git a/include/boost/histogram/axis/variable.hpp b/include/boost/histogram/axis/variable.hpp index 53af4416..ef24ca57 100644 --- a/include/boost/histogram/axis/variable.hpp +++ b/include/boost/histogram/axis/variable.hpp @@ -78,7 +78,7 @@ public: template > variable(It begin, It end, metadata_type meta = {}, allocator_type alloc = {}) : metadata_base(std::move(meta)), vec_(std::move(alloc)) { - if (std::distance(begin, end) <= 1) + if (std::distance(begin, end) < 2) BOOST_THROW_EXCEPTION(std::invalid_argument("bins > 0 required")); vec_.reserve(std::distance(begin, end)); diff --git a/test/axis_category_test.cpp b/test/axis_category_test.cpp index 5afe477c..92951a56 100644 --- a/test/axis_category_test.cpp +++ b/test/axis_category_test.cpp @@ -4,6 +4,7 @@ // (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) +#include #include #include #include @@ -26,10 +27,11 @@ int main() { BOOST_TEST(std::is_nothrow_move_assignable>::value); BOOST_TEST(std::is_nothrow_move_assignable>::value); - // bad_ctors + // bad ctor { - auto empty = std::vector(0); - BOOST_TEST_THROWS((axis::category<>(empty)), std::invalid_argument); + int x[2]; + boost::ignore_unused(x); + BOOST_TEST_THROWS(axis::category(x + 1, x), std::invalid_argument); } // value should return copy for arithmetic types and const reference otherwise @@ -50,6 +52,17 @@ int main() { BOOST_TEST_TRAIT_SAME(decltype(std::declval>().value(0)), int); } + // empty axis::category + { + axis::category a; + axis::category b(std::vector(0)); + BOOST_TEST_EQ(a, b); + BOOST_TEST_EQ(a.size(), 0); + BOOST_TEST_EQ(a.index(-1), 0); + BOOST_TEST_EQ(a.index(0), 0); + BOOST_TEST_EQ(a.index(1), 0); + } + // axis::category { std::string A("A"), B("B"), C("C"), other; diff --git a/test/axis_integer_test.cpp b/test/axis_integer_test.cpp index d3556f41..9ea2b5b8 100644 --- a/test/axis_integer_test.cpp +++ b/test/axis_integer_test.cpp @@ -22,10 +22,7 @@ int main() { BOOST_TEST(std::is_nothrow_move_constructible>::value); // bad_ctor - { - BOOST_TEST_THROWS(axis::integer<>(1, 1), std::invalid_argument); - BOOST_TEST_THROWS(axis::integer<>(1, -1), std::invalid_argument); - } + { BOOST_TEST_THROWS(axis::integer<>(1, -1), std::invalid_argument); } // axis::integer with double type { @@ -60,6 +57,34 @@ int main() { BOOST_TEST_EQ(d, a); } + // empty axis::integer + { + axis::integer<> a; + BOOST_TEST_EQ(a.size(), 0); + BOOST_TEST_EQ(a.bin(1), 1); + BOOST_TEST_EQ(a.bin(0), 0); + BOOST_TEST_EQ(a.bin(-1), -1); + BOOST_TEST_EQ(a.index(-10), -1); + BOOST_TEST_EQ(a.index(-1), -1); + BOOST_TEST_EQ(a.index(0), 0); + BOOST_TEST_EQ(a.index(10), 0); + + BOOST_TEST_EQ(str(a), "integer(0, 0, options=underflow | overflow)"); + + axis::integer<> b{1, 1}; + BOOST_TEST_EQ(b.size(), 0); + BOOST_TEST_EQ(b.bin(1), 2); + BOOST_TEST_EQ(b.bin(0), 1); + BOOST_TEST_EQ(b.bin(-1), 0); + BOOST_TEST_EQ(b.index(-10), -1); + BOOST_TEST_EQ(b.index(-1), -1); + BOOST_TEST_EQ(b.index(0), -1); + BOOST_TEST_EQ(b.index(1), 0); + BOOST_TEST_EQ(b.index(10), 0); + + BOOST_TEST_EQ(str(b), "integer(1, 1, options=underflow | overflow)"); + } + // axis::integer with int type { axis::integer a{-1, 2}; diff --git a/test/histogram_dynamic_test.cpp b/test/histogram_dynamic_test.cpp index 655d571b..8200f94a 100644 --- a/test/histogram_dynamic_test.cpp +++ b/test/histogram_dynamic_test.cpp @@ -5,6 +5,7 @@ // or copy at http://www.boost.org/LICENSE_1_0.txt) #include +#include #include #include #include @@ -67,10 +68,9 @@ int main() { std::vector(1, 0)); h.fill(inputs); // should not crash -#ifndef BOOST_NO_EXCEPTIONS auto bad = std::vector(BOOST_HISTOGRAM_DETAIL_AXES_LIMIT + 1, I(0, 1)); + boost::ignore_unused(bad); BOOST_TEST_THROWS((void)make_histogram(bad), std::invalid_argument); -#endif } // bad fill diff --git a/test/histogram_fill_test.cpp b/test/histogram_fill_test.cpp index 6a0edf5d..76eae4ea 100644 --- a/test/histogram_fill_test.cpp +++ b/test/histogram_fill_test.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -74,12 +75,12 @@ void run_tests(const std::vector& x, const std::vector& y, BOOST_TEST_EQ(h, h2); BOOST_TEST_EQ(h, h3); -#ifndef BOOST_NO_EXCEPTIONS int bad1[2][4]; + boost::ignore_unused(bad1); std::vector> bad2; + boost::ignore_unused(bad2); BOOST_TEST_THROWS(h.fill(bad1), std::invalid_argument); BOOST_TEST_THROWS(h.fill(bad2), std::invalid_argument); -#endif } // 2D simple @@ -93,14 +94,13 @@ void run_tests(const std::vector& x, const std::vector& y, BOOST_TEST_EQ(h, h2); -#ifndef BOOST_NO_EXCEPTIONS // wrong rank BOOST_TEST_THROWS(h.fill(x), std::invalid_argument); // not rectangular std::array, 2> bad = {{std::vector(2), std::vector(3)}}; + boost::ignore_unused(bad); BOOST_TEST_THROWS(h2.fill(bad), std::invalid_argument); -#endif } // 1D variant and weight @@ -130,11 +130,10 @@ void run_tests(const std::vector& x, const std::vector& y, BOOST_TEST_EQ(h1, h2); -#ifndef BOOST_NO_EXCEPTIONS auto w2 = w; w2.resize(ndata - 1); + boost::ignore_unused(w2); BOOST_TEST_THROWS(h2.fill(v, weight(w2)), std::invalid_argument); -#endif } // 2D variant and weight diff --git a/test/histogram_test.cpp b/test/histogram_test.cpp index 54585002..a18919ff 100644 --- a/test/histogram_test.cpp +++ b/test/histogram_test.cpp @@ -4,6 +4,7 @@ // (See accompanying file LICENSE_1_0.txt // or copy at http://www.boost.org/LICENSE_1_0.txt) +#include #include #include #include @@ -441,12 +442,12 @@ void run_tests() { int j11[] = {1, 1}; BOOST_TEST_EQ(h.at(j11), 1); BOOST_TEST_EQ(h[j11], 1); -#ifndef BOOST_NO_EXCEPTIONS int j111[] = {1, 1, 1}; + boost::ignore_unused(j111); BOOST_TEST_THROWS((void)h.at(j111), std::invalid_argument); int j13[] = {1, 3}; + boost::ignore_unused(j13); BOOST_TEST_THROWS((void)h.at(j13), std::out_of_range); -#endif // tuple with weight h(std::make_tuple(weight(2), 0, 2.0));