diff --git a/README.md b/README.md index 31fb705..f35bfb0 100644 --- a/README.md +++ b/README.md @@ -421,11 +421,11 @@ This single-header library has no other dependencies than the C++ Standard Libra | Platform | Compiler | Versions | Build | | :------- | :------- | -------: | :---- | -| Linux | GCC | 14-trunk | CI currently being ported to GitHub Actions | -| Linux | Clang | 17, 18-trunk | CI currently being ported to GitHub Actions | +| Linux | GCC | 14, 15-trunk | CI currently being ported to GitHub Actions | +| Linux | Clang | 18, 19-trunk | CI currently being ported to GitHub Actions | | Windows | Visual C++ | 17.7, 17.8, 17.9-trunk | CI currently being ported to GitHub Actions | -Note that this library makes liberal use of C++23 features, such as the `fold_left`, `shift_left` and `shift_right` algorithms, the `pairwise_transform`, `zip` and `zip_transform` views, the `to` range conversion, the `uz` literal for `size_t` and the `unreachable` utility. GCC 14-trunk, Clang 17 and 18-trunk (both only with the GCC 14-trunk standard library) and Visual C++ 17.7 and higher are supported at the moment. Also note that running the unit tests requires the presence of the [range-v3](https://github.com/ericniebler/range-v3) library (for the set algorithm views). +Note that this library makes liberal use of C++23 features, such as the `fold_left`, `shift_left` and `shift_right` algorithms, the `pairwise_transform`, `zip` and `zip_transform` views, the `to` range conversion, the `uz` literal for `size_t` and explicit object parameters (deducing `this`). GCC 14 and 15-trunk, Clang 18 and 19-trunk (both only with the GCC 14 or higher standard library) and Visual C++ 17.7 and higher are supported at the moment. Also note that running the unit tests requires the presence of the [range-v3](https://github.com/ericniebler/range-v3) library (for the set algorithm views). ## License diff --git a/include/ext/boost/dynamic_bitset.hpp b/include/ext/boost/dynamic_bitset.hpp index 1bd1235..fa78332 100644 --- a/include/ext/boost/dynamic_bitset.hpp +++ b/include/ext/boost/dynamic_bitset.hpp @@ -7,6 +7,7 @@ #include // dynamic_bitset #include // lexicographical_compare_three_way +#include // assert #include // strong_ordering #include // constructible_from, unsigned_integral #include // ptrdiff_t @@ -43,27 +44,27 @@ class dynamic_bitset_iterator m_ptr(ptr), m_val(val) { - [[assume(is_valid())]]; + assert(is_valid()); } [[nodiscard]] friend constexpr bool operator==(dynamic_bitset_iterator lhs, dynamic_bitset_iterator rhs) noexcept { - [[assume(is_comparable(lhs, rhs))]]; + assert(is_comparable(lhs, rhs)); return lhs.m_val == rhs.m_val; } [[nodiscard]] constexpr auto operator*() const noexcept -> dynamic_bitset_reference { - [[assume(is_dereferenceable())]]; + assert(is_dereferenceable()); return { *m_ptr, m_val }; } dynamic_bitset_iterator& operator++() noexcept { - [[assume(is_incrementable())]]; + assert(is_incrementable()); m_val = m_ptr->find_next(m_val); - [[assume(is_decrementable())]]; + assert(is_decrementable()); return *this; } @@ -74,9 +75,9 @@ class dynamic_bitset_iterator dynamic_bitset_iterator& operator--() noexcept { - [[assume(is_decrementable())]]; + assert(is_decrementable()); m_val = find_prev(m_val); - [[assume(is_incrementable())]]; + assert(is_incrementable()); return *this; } @@ -88,7 +89,7 @@ class dynamic_bitset_iterator private: [[nodiscard]] value_type find_prev(value_type n) noexcept { - [[assume(m_ptr->any())]]; + assert(m_ptr->any()); return *std::ranges::find_if(std::views::iota(0uz, std::ranges::min(n, m_ptr->size())) | std::views::reverse, [&](auto i) { return (*m_ptr)[i]; }); @@ -136,7 +137,7 @@ class dynamic_bitset_reference m_ref(ref), m_val(val) { - [[assume(is_valid())]]; + assert(is_valid()); } [[nodiscard]] constexpr dynamic_bitset_reference(const dynamic_bitset_reference&) noexcept = default; diff --git a/include/ext/std/bitset.hpp b/include/ext/std/bitset.hpp index 750f397..f30dd82 100644 --- a/include/ext/std/bitset.hpp +++ b/include/ext/std/bitset.hpp @@ -8,6 +8,7 @@ #include // lexicographical_compare_three_way #include // bitset +#include // assert #include // strong_ordering #include // constructible_from #include // ptrdiff_t, size_t @@ -86,12 +87,12 @@ class bitset_iterator m_ptr(ptr), m_val(val) { - [[assume(is_valid())]]; + assert(is_valid()); } [[nodiscard]] friend constexpr bool operator==(bitset_iterator lhs, bitset_iterator rhs) noexcept { - [[assume(is_comparable(lhs, rhs))]]; + assert(is_comparable(lhs, rhs)); if constexpr (N == 0) { return true; } else { @@ -102,15 +103,15 @@ class bitset_iterator [[nodiscard]] constexpr auto operator*() const noexcept -> bitset_reference { - [[assume(is_dereferenceable())]]; + assert(is_dereferenceable()); return { *m_ptr, m_val }; } constexpr bitset_iterator& operator++() noexcept { - [[assume(is_incrementable())]]; + assert(is_incrementable()); m_val = find_next(m_val); - [[assume(is_decrementable())]]; + assert(is_decrementable()); return *this; } @@ -121,9 +122,9 @@ class bitset_iterator constexpr bitset_iterator& operator--() noexcept { - [[assume(is_decrementable())]]; + assert(is_decrementable()); m_val = find_prev(m_val); - [[assume(is_incrementable())]]; + assert(is_incrementable()); return *this; } @@ -146,7 +147,7 @@ class bitset_iterator [[nodiscard]] constexpr value_type find_prev(value_type n) const noexcept { - [[assume(m_ptr->any())]]; + assert(m_ptr->any()); return *std::ranges::find_if(std::views::iota(0uz, n) | std::views::reverse, [&](auto i) { return (*m_ptr)[i]; }); @@ -194,7 +195,7 @@ class bitset_reference m_ref(ref), m_val(val) { - [[assume(is_valid())]]; + assert(is_valid()); } [[nodiscard]] constexpr bitset_reference(const bitset_reference&) noexcept = default; diff --git a/include/xstd/bit_set.hpp b/include/xstd/bit_set.hpp index ec1b786..6836a69 100644 --- a/include/xstd/bit_set.hpp +++ b/include/xstd/bit_set.hpp @@ -10,6 +10,7 @@ // all_of, any_of, fill_n, find_if, fold_left, for_each, max, none_of #include // array #include // countl_zero, countr_zero, popcount +#include // assert #include // strong_ordering #include // constructible_from, integral, same_as, unsigned_integral #include // ptrdiff_t, size_t @@ -297,7 +298,7 @@ class bit_set } else if constexpr (N > 0) { m_bits.fill(ones); } - [[assume(full())]]; + assert(full()); } constexpr void pop(key_type x) noexcept @@ -308,7 +309,7 @@ class bit_set constexpr iterator erase(const_iterator position) noexcept { - [[assume(position != end())]]; + assert(position != end()); pop(*position++); return position; } @@ -323,7 +324,7 @@ class bit_set constexpr iterator erase(const_iterator first, const_iterator last) noexcept { - [[assume(N > 0 || first == last)]]; + assert(N > 0 || first == last); std::ranges::for_each(first, last, [this](auto x) { pop(x); }); @@ -342,7 +343,7 @@ class bit_set if constexpr (N > 0) { m_bits.fill(zero); } - [[assume(empty())]]; + assert(empty()); } constexpr void complement(value_type x) noexcept @@ -428,7 +429,7 @@ class bit_set constexpr bit_set& operator<<=(size_type n [[maybe_unused]]) noexcept { - [[assume(is_valid(n))]]; + assert(is_valid(n)); if constexpr (num_blocks == 1) { m_bits[0] >>= n; } else if constexpr (num_blocks >= 2) { @@ -465,7 +466,7 @@ class bit_set constexpr bit_set& operator>>=(size_type n [[maybe_unused]]) noexcept { - [[assume(is_valid(n))]]; + assert(is_valid(n)); if constexpr (num_blocks == 1) { m_bits[0] <<= n; } else if constexpr (num_blocks >= 2) { @@ -688,7 +689,7 @@ class bit_set std::pair > { - [[assume(is_valid(n))]]; + assert(is_valid(n)); auto const [ index, offset ] = index_offset(n); return { self.m_bits[index], static_cast(left_mask >> offset) }; } @@ -702,13 +703,13 @@ class bit_set static constexpr void insert(block_type& block, block_type mask) noexcept { block |= mask; - [[assume(contains(block, mask))]]; + assert(contains(block, mask)); } static constexpr void erase(block_type& block, block_type mask) noexcept { block &= static_cast(~mask); - [[assume(!contains(block, mask))]]; + assert(!contains(block, mask)); } static constexpr void complement(block_type& block, block_type mask) noexcept @@ -741,7 +742,7 @@ class bit_set constexpr void do_insert(I first, S last) noexcept requires std::constructible_from { - [[assume(N > 0 || first == last)]]; + assert(N > 0 || first == last); std::ranges::for_each(first, last, [this](auto x) { add(x); }); @@ -756,28 +757,28 @@ class bit_set [[nodiscard]] constexpr size_type find_front() const noexcept { - [[assume(!empty())]]; + assert(!empty()); if constexpr (num_blocks == 1) { return static_cast(std::countl_zero(m_bits[0])); } else if constexpr (num_blocks == 2) { return m_bits[0] ? static_cast(std::countl_zero(m_bits[0])) : block_size + static_cast(std::countl_zero(m_bits[1])); } else if constexpr (num_blocks >= 3) { auto const front = std::ranges::find_if(m_bits, std::identity()); - [[assume(front != std::ranges::end(m_bits))]]; + assert(front != std::ranges::end(m_bits)); return static_cast(std::ranges::distance(std::ranges::begin(m_bits), front)) * block_size + static_cast(std::countl_zero(*front)); } } [[nodiscard]] constexpr size_type find_back() const noexcept { - [[assume(!empty())]]; + assert(!empty()); if constexpr (num_blocks == 1) { return last_bit - static_cast(std::countr_zero(m_bits[0])); } else if constexpr (num_blocks == 2) { return m_bits[1] ? last_bit - static_cast(std::countr_zero(m_bits[1])) : left_bit - static_cast(std::countr_zero(m_bits[0])); } else if constexpr (num_blocks >= 3) { auto const back = std::ranges::find_if(m_bits | std::views::reverse, std::identity()); - [[assume(back != std::ranges::rend(m_bits))]]; + assert(back != std::ranges::rend(m_bits)); return last_bit - static_cast(std::ranges::distance(std::ranges::rbegin(m_bits), back)) * block_size - static_cast(std::countr_zero(*back)); } } @@ -842,7 +843,7 @@ class bit_set [[nodiscard]] constexpr size_type find_prev(size_type n) const noexcept { - [[assume(!empty())]]; + assert(!empty()); if constexpr (num_blocks == 1) { return n - static_cast(std::countr_zero(static_cast(m_bits[0] >> (left_bit - n)))); } else if constexpr (num_blocks >= 2) { @@ -856,7 +857,7 @@ class bit_set } auto const rg = m_bits | std::views::reverse | std::views::drop(last_block - index); auto const prev = std::ranges::find_if(rg, std::identity()); - [[assume(prev != std::ranges::end(rg))]]; + assert(prev != std::ranges::end(rg)); return n - static_cast(std::ranges::distance(std::ranges::begin(rg), prev)) * block_size - static_cast(std::countr_zero(*prev)); } } @@ -884,7 +885,7 @@ class bit_set m_ptr(ptr), m_val(val) { - [[assume(is_valid())]]; + assert(is_valid()); } [[nodiscard]] constexpr proxy_const_iterator(pimpl_type ptr, value_type val) noexcept @@ -895,7 +896,7 @@ class bit_set [[nodiscard]] friend constexpr bool operator==(proxy_const_iterator lhs [[maybe_unused]], proxy_const_iterator rhs [[maybe_unused]]) noexcept { - [[assume(is_comparable(lhs, rhs))]]; + assert(is_comparable(lhs, rhs)); if constexpr (N == 0) { return true; } else { @@ -906,15 +907,15 @@ class bit_set [[nodiscard]] constexpr auto operator*() const noexcept -> proxy_const_reference { - [[assume(is_dereferenceable())]]; + assert(is_dereferenceable()); return { *m_ptr, m_val }; } constexpr proxy_const_iterator& operator++() noexcept { - [[assume(is_incrementable())]]; + assert(is_incrementable()); m_val = m_ptr->find_next(m_val + 1); - [[assume(is_decrementable())]]; + assert(is_decrementable()); return *this; } @@ -925,9 +926,9 @@ class bit_set constexpr proxy_const_iterator& operator--() noexcept { - [[assume(is_decrementable())]]; + assert(is_decrementable()); m_val = m_ptr->find_prev(m_val - 1); - [[assume(is_incrementable())]]; + assert(is_incrementable()); return *this; } @@ -979,7 +980,7 @@ class bit_set m_ref(ref), m_val(val) { - [[assume(is_valid())]]; + assert(is_valid()); } [[nodiscard]] constexpr proxy_const_reference(const proxy_const_reference&) noexcept = default; diff --git a/test/include/bitset/exhaustive.hpp b/test/include/bitset/exhaustive.hpp index 1d8b17c..1bd9882 100644 --- a/test/include/bitset/exhaustive.hpp +++ b/test/include/bitset/exhaustive.hpp @@ -8,6 +8,7 @@ #include // make_bitset #include // dynamic #include // max +#include // assert #include // cartesian_product, iota #if defined(_MSC_VER) @@ -31,22 +32,22 @@ inline constexpr auto L4 = 8uz; template> auto empty_set(auto fun) { - auto a = make_bitset(N); [[assume(a.none())]]; + auto a = make_bitset(N); assert(a.none()); fun(a); } template> auto full_set(auto fun) { - auto a = make_bitset(N, true); [[assume(a.all())]]; + auto a = make_bitset(N, true); assert(a.all()); fun(a); } template> auto empty_set_pair(auto fun) { - auto a = make_bitset(N); [[assume(a.none())]]; - auto b = make_bitset(N); [[assume(b.none())]]; + auto a = make_bitset(N); assert(a.none()); + auto b = make_bitset(N); assert(b.none()); fun(a, b); } @@ -76,7 +77,7 @@ auto all_cardinality_sets(auto fun) for (auto j : std::views::iota(0uz, i)) { a.set(j); } - [[assume(a.count() == i)]]; + assert(a.count() == i); fun(a); } } @@ -85,7 +86,7 @@ template> auto all_singleton_sets(auto fun) { for (auto i : std::views::iota(0uz, N)) { - auto a = make_bitset(N); a.set(i); [[assume(a.count() == 1)]]; + auto a = make_bitset(N); a.set(i); assert(a.count() == 1); fun(a); } } @@ -99,8 +100,8 @@ auto all_singleton_set_pairs(auto fun) std::views::iota(0uz, N), std::views::iota(0uz, N)) ) { - auto a = make_bitset(N); a.set(i); [[assume(a.count() == 1)]]; - auto b = make_bitset(N); b.set(j); [[assume(b.count() == 1)]]; + auto a = make_bitset(N); a.set(i); assert(a.count() == 1); + auto b = make_bitset(N); b.set(j); assert(b.count() == 1); fun(a, b); } } @@ -115,9 +116,9 @@ auto all_singleton_set_triples(auto fun) std::views::iota(0uz, N), std::views::iota(0uz, N) )) { - auto a = make_bitset(N); a.set(i); [[assume(a.count() == 1)]]; - auto b = make_bitset(N); b.set(j); [[assume(b.count() == 1)]]; - auto c = make_bitset(N); c.set(k); [[assume(c.count() == 1)]]; + auto a = make_bitset(N); a.set(i); assert(a.count() == 1); + auto b = make_bitset(N); b.set(j); assert(b.count() == 1); + auto c = make_bitset(N); c.set(k); assert(c.count() == 1); fun(a, b, c); } } @@ -135,8 +136,8 @@ auto all_doubleton_set_pairs(auto fun) std::views::iota(0uz, j), std::views::iota(0uz, n) )) { - auto a = make_bitset(N); a.set(i); a.set(j); [[assume(a.count() == 2)]]; - auto b = make_bitset(N); b.set(m); b.set(n); [[assume(b.count() == 2)]]; + auto a = make_bitset(N); a.set(i); a.set(j); assert(a.count() == 2); + auto b = make_bitset(N); b.set(m); b.set(n); assert(b.count() == 2); fun(a, b); } } diff --git a/test/include/set/exhaustive.hpp b/test/include/set/exhaustive.hpp index 1acd887..40e7c21 100644 --- a/test/include/set/exhaustive.hpp +++ b/test/include/set/exhaustive.hpp @@ -7,6 +7,7 @@ #include // max #include // array +#include // assert #include // integral #include // initializer_list #include // to @@ -38,22 +39,22 @@ inline constexpr auto limit_v = []() { template auto empty_set(auto fun) { - X a; [[assume(a.empty())]]; + X a; assert(a.empty()); fun(a); } template> auto full_set(auto fun) { - auto a = std::views::iota(Key(0), N) | std::ranges::to(); [[assume(a.size() == static_cast(N))]]; + auto a = std::views::iota(Key(0), N) | std::ranges::to(); assert(a.size() == static_cast(N)); fun(a); } template auto empty_set_pair(auto fun) { - X a; [[assume(a.empty())]]; - X b; [[assume(b.empty())]]; + X a; assert(a.empty()); + X b; assert(b.empty()); fun(a, b); } @@ -71,7 +72,7 @@ template(); [[assume(a.size() == static_cast(i))]]; + auto a = std::views::iota(Key(0), i) | std::ranges::to(); assert(a.size() == static_cast(i)); fun(a); } } @@ -80,7 +81,7 @@ template