From fe15ef07143b38d97599cee88c439b7fddabe9b7 Mon Sep 17 00:00:00 2001 From: Alfredo Correa Date: Wed, 22 Oct 2025 02:08:36 -0700 Subject: [PATCH 01/13] make restrictions reversible --- include/boost/multi/detail/index_range.hpp | 2 +- include/boost/multi/detail/layout.hpp | 61 +++++++++++++++++++++- include/boost/multi/detail/operators.hpp | 16 ++++++ test/extensions.cpp | 49 ++++++++++++++++- test/index_range.cpp | 26 +++++++++ 5 files changed, 150 insertions(+), 4 deletions(-) diff --git a/include/boost/multi/detail/index_range.hpp b/include/boost/multi/detail/index_range.hpp index efc52c0f0..d94be6e82 100644 --- a/include/boost/multi/detail/index_range.hpp +++ b/include/boost/multi/detail/index_range.hpp @@ -178,7 +178,7 @@ class range { ++curr_; return *this; } - constexpr auto operator--() -> const_iterator& { + constexpr auto operator--() noexcept(noexcept(--curr_)) -> const_iterator& { --curr_; return *this; } diff --git a/include/boost/multi/detail/layout.hpp b/include/boost/multi/detail/layout.hpp index 121a888f5..2cd7d3e86 100644 --- a/include/boost/multi/detail/layout.hpp +++ b/include/boost/multi/detail/layout.hpp @@ -123,7 +123,7 @@ class f_extensions_t { } } - class iterator { + class iterator : weakly_incrementable_facade, weakly_decrementable_facade { // NOLINT(fuchsia-multiple-inheritance) typename extensions_t::iterator it_; Proj proj_; @@ -132,6 +132,8 @@ class f_extensions_t { friend f_extensions_t; public: + iterator() = default; + using iterator_category = std::random_access_iterator_tag; auto operator++() -> auto& { ++it_; return *this; } @@ -140,6 +142,11 @@ class f_extensions_t { constexpr auto operator+=(difference_type dd) -> auto& { it_+=dd; return *this; } constexpr auto operator-=(difference_type dd) -> auto& { it_-=dd; return *this; } + constexpr auto operator+(difference_type dd) const { return iterator{*this} += dd; } + constexpr auto operator-(difference_type dd) const { return iterator{*this} -= dd; } + + friend constexpr auto operator+(difference_type dd, iterator const& self) { return self + dd; } + friend constexpr auto operator-(iterator const& self, iterator const& other) { return self.it_ - other.it_; } friend constexpr auto operator==(iterator const& self, iterator const& other) -> bool { return self.it_ == other.it_; } @@ -147,10 +154,12 @@ class f_extensions_t { friend auto operator<=(iterator const& self, iterator const& other) -> bool { return self.it_ <= other.it_; } friend auto operator< (iterator const& self, iterator const& other) -> bool { return self.it_ < other.it_; } + friend auto operator> (iterator const& self, iterator const& other) -> bool { return self.it_ > other.it_; } + friend auto operator>=(iterator const& self, iterator const& other) -> bool { return self.it_ >= other.it_; } constexpr auto operator*() const -> decltype(auto) { using std::get; - if constexpr(D != 1) { + if constexpr(D > 1) { auto ll = [idx = get<0>(*it_), proj = proj_](auto... rest) { return proj(idx, rest...); }; return f_extensions_t(extensions_t(get<1>(*it_).base().tail()), ll); } else { @@ -158,6 +167,8 @@ class f_extensions_t { } } + using value_type = int; // decltype(*std::declval()); + auto operator[](difference_type dd) const { return *((*this) + dd); } // TODO(correaa) use ra_iterator_facade }; @@ -401,6 +412,9 @@ struct extensions_t : boost::multi::detail::tuple_prepend_t iterator& { idx_ += d; return *this; } + constexpr auto operator-=(difference_type d) -> iterator& { idx_ -= d; return *this; } + constexpr auto operator+(difference_type d) const { return iterator{idx_ + d, rest_}; } constexpr auto operator-(difference_type d) const { return iterator{idx_ - d, rest_}; } @@ -683,6 +697,10 @@ template<> struct extensions_t<0> : tuple<> { : base_{tup} {} extensions_t() = default; + // template + // cppcheck-suppress noExplicitConstructor ; to allow passing tuple // NOLINTNEXTLINE(runtime/explicit) + // BOOST_MULTI_HD explicit constexpr extensions_t(tuple<> /*extensions*/) // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) + // : base_{} {} BOOST_MULTI_HD constexpr auto base() const& -> base_ const& { return *this; } BOOST_MULTI_HD constexpr auto base() & -> base_& { return *this; } @@ -811,6 +829,45 @@ template<> struct extensions_t<1> : tuple { return elements_t{get<0>(static_cast const&>(*this))}; } + class iterator : weakly_incrementable_facade, weakly_decrementable_facade { // NOLINT(fuchsia-multiple-inheritance) + index idx_; + extensions_t<0> rest_; + friend extensions_t; + + constexpr iterator(index idx, extensions_t<0> rest) : idx_{idx}, rest_{rest} {} + + public: + using difference_type = index; + using value_type = decltype(ht_tuple(std::declval(), std::declval>().base())); + using pointer = void; + using reference = value_type; + using iterator_category = std::random_access_iterator_tag; + + iterator() = default; + + constexpr auto operator+=(difference_type d) { idx_+=d; return *this; } + constexpr auto operator-=(difference_type d) { idx_-=d; return *this; } + + constexpr auto operator+(difference_type d) const { return iterator{idx_ + d, rest_}; } + constexpr auto operator-(difference_type d) const { return iterator{idx_ - d, rest_}; } + + friend constexpr auto operator-(iterator const& self, iterator const& other) -> difference_type { return self.idx_ - other.idx_; } + + constexpr auto operator++() -> auto& { ++idx_; return *this; } + constexpr auto operator--() -> auto& { --idx_; return *this; } + + constexpr auto operator*() const { + // multi::detail::what(rest_); + return ht_tuple(idx_, rest_.base()); + } + + friend constexpr auto operator==(iterator const& self, iterator const& other) { assert( self.rest_ == other.rest_ ); return self.idx_ == other.idx_; } + friend constexpr auto operator!=(iterator const& self, iterator const& other) { assert( self.rest_ == other.rest_ ); return self.idx_ != other.idx_; } + }; + + constexpr auto begin() const noexcept { return iterator{this->base().head().first(), extensions_t<0>(this->base().tail())}; } + constexpr auto end() const noexcept { return iterator{this->base().head().last() , extensions_t<0>(this->base().tail())}; } + constexpr auto size() const { using std::get; return get<0>(static_cast const&>(*this)).size(); diff --git a/include/boost/multi/detail/operators.hpp b/include/boost/multi/detail/operators.hpp index f66fe2ee3..9036665a5 100644 --- a/include/boost/multi/detail/operators.hpp +++ b/include/boost/multi/detail/operators.hpp @@ -121,6 +121,22 @@ struct weakly_incrementable { // friend T& operator++(weakly_incrementable& t){return ++static_cast(t);} }; +template class default_initializable_facade { + default_initializable_facade() = default; +}; + +template class weakly_incrementable_facade : selfable { + weakly_incrementable_facade() = default; + friend Self; + friend constexpr auto operator++(Self& self, int) -> Self { Self ret = self.self(); ++self.self(); return ret; } +}; + +template class weakly_decrementable_facade : selfable { + weakly_decrementable_facade() = default; + friend Self; + friend constexpr auto operator--(Self& self, int) -> Self { Self ret = self.self(); --self.self(); return ret; } +}; + template struct weakly_decrementable { protected: diff --git a/test/extensions.cpp b/test/extensions.cpp index 94c9c5973..8d5c5a11a 100644 --- a/test/extensions.cpp +++ b/test/extensions.cpp @@ -454,12 +454,59 @@ auto main() -> int { // NOLINT(bugprone-exception-escape,readability-function-c BOOST_TEST( xs1D.size() == 10 ); using std::get; BOOST_TEST( get<0>(xs1D[3]) == 3 ); + BOOST_TEST( get<0>(xs1D[4]) == 4 ); - auto v1D = [](auto ii) { return ii * ii; } ^ multi::extensions_t(10); + BOOST_TEST( get<0>(*xs1D.begin()) == 0 ); + BOOST_TEST( get<0>(*(xs1D.end()-1)) == 9 ); + + multi::extensions_t<1> const xs1D_copy(xs1D); + BOOST_TEST( xs1D_copy == xs1D ); + + multi::extensions_t<1>::iterator const copy(xs1D.begin()); + BOOST_TEST( copy == xs1D.begin() ); + + static_assert(std::is_constructible_v::iterator, boost::multi::extensions_t<1>::iterator>); + +#if defined(__cpp_lib_ranges) && (__cpp_lib_ranges >= 201911L) && !defined(_MSC_VER) + BOOST_TEST( get<0>(*std::ranges::begin(xs1D)) == 0 ); + + BOOST_TEST( get<0>(*(std::ranges::end(xs1D)-1)) == 9 ); + + static_assert(std::ranges::range&>>); + + BOOST_TEST( get<0>(*(xs1D.end()-1)) == 9 ); + + static_assert(std::ranges::bidirectional_range>); + + auto rxs1D = xs1D | std::views::reverse; + + BOOST_TEST( get<0>(*std::ranges::begin(rxs1D)) == 9 ); + BOOST_TEST( get<0>(*(std::ranges::end(rxs1D)-1)) == 0 ); +#endif + + auto const v1D = [](auto ii) { return ii * ii; } ^ multi::extensions_t(10); BOOST_TEST( v1D.size() == 10 ); BOOST_TEST( v1D.elements().size() == 10 ); + BOOST_TEST( v1D[0] == 0); BOOST_TEST( v1D[4] == 16 ); + BOOST_TEST( v1D[9] == 81 ); + BOOST_TEST( *v1D.begin() == 0 ); + BOOST_TEST( *(v1D.end() - 1) == 81 ); + #if defined(__cpp_lib_ranges) && (__cpp_lib_ranges >= 201911L) && !defined(_MSC_VER) + static_assert(std::input_or_output_iterator); + static_assert(std::default_initializable); + static_assert(std::semiregular); + + BOOST_TEST( std::ranges::begin(v1D) == v1D.begin() ); + BOOST_TEST( std::ranges::end(v1D) == v1D.end() ); + + static_assert(std::ranges::bidirectional_range); + static_assert(std::ranges::random_access_range); + auto rv1D = v1D | std::views::reverse; + + BOOST_TEST( rv1D[0] == 81); + BOOST_TEST( rv1D[9] == 0 ); #endif } return boost::report_errors(); diff --git a/test/index_range.cpp b/test/index_range.cpp index 7ba4a57bf..063de96eb 100644 --- a/test/index_range.cpp +++ b/test/index_range.cpp @@ -13,6 +13,10 @@ // IWYU pragma: no_include // for tuple_element<>::type #include +#if defined(__cplusplus) && (__cplusplus >= 202002L) +#include // IWYU pragma: keep // NOLINT(misc-include-cleaner) +#endif + namespace multi = boost::multi; auto main() -> int { // NOLINT(readability-function-cognitive-complexity,bugprone-exception-escape) @@ -259,5 +263,27 @@ auto main() -> int { // NOLINT(readability-function-cognitive-complexity,bugpro BOOST_TEST( sum == 5 + 6 + 7 + 8 + 9 + 10 + 11 ); } + { + multi::extension_t const ext(5); + + BOOST_TEST( *ext.begin() == 0 ); + BOOST_TEST( *(ext.end() - 1) == 4 ); +#if defined(__cpp_lib_ranges) && (__cpp_lib_ranges >= 201911L) && !defined(_MSC_VER) + + BOOST_TEST( *std::ranges::begin(ext) == 0 ); + BOOST_TEST( *(std::ranges::end(ext)-1) == 4 ); + + // static_assert(std::ranges::range&>>); + + // BOOST_TEST( get<0>(*(xs1D.end()-1)) == 9 ); + + BOOST_TEST( ext[1] == 1 ); + + auto rext = ext | std::views::reverse; + + BOOST_TEST( rext[1] == 3 ); +#endif + } + return boost::report_errors(); } From 9a17c6c5bec1197e643bc2139eaaebe0d8b7fb8b Mon Sep 17 00:00:00 2001 From: Alfredo Correa Date: Wed, 22 Oct 2025 10:37:16 -0700 Subject: [PATCH 02/13] more reverse --- include/boost/multi/detail/layout.hpp | 10 +++--- include/boost/multi/detail/operators.hpp | 4 +-- test/extensions.cpp | 42 ++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/include/boost/multi/detail/layout.hpp b/include/boost/multi/detail/layout.hpp index 2cd7d3e86..1c6c45e60 100644 --- a/include/boost/multi/detail/layout.hpp +++ b/include/boost/multi/detail/layout.hpp @@ -123,7 +123,7 @@ class f_extensions_t { } } - class iterator : weakly_incrementable_facade, weakly_decrementable_facade { // NOLINT(fuchsia-multiple-inheritance) + class iterator : public weakly_incrementable_facade, weakly_decrementable_facade { // NOLINT(fuchsia-multiple-inheritance) typename extensions_t::iterator it_; Proj proj_; @@ -136,8 +136,8 @@ class f_extensions_t { using iterator_category = std::random_access_iterator_tag; - auto operator++() -> auto& { ++it_; return *this; } - auto operator--() -> auto& { --it_; return *this; } + constexpr auto operator++() -> auto& { ++it_; return *this; } + constexpr auto operator--() -> auto& { --it_; return *this; } constexpr auto operator+=(difference_type dd) -> auto& { it_+=dd; return *this; } constexpr auto operator-=(difference_type dd) -> auto& { it_-=dd; return *this; } @@ -398,7 +398,7 @@ struct extensions_t : boost::multi::detail::tuple_prepend_t BOOST_MULTI_HD constexpr auto operator()(index idx, Indices... rest) const { return to_linear(idx, rest...); } - class iterator { + class iterator : weakly_incrementable_facade, weakly_decrementable_facade { // NOLINT(fuchsia-multiple-inheritance,cppcoreguidelines-pro-type-member-init) index idx_; extensions_t rest_; friend extensions_t; @@ -412,6 +412,8 @@ struct extensions_t : boost::multi::detail::tuple_prepend_t iterator& { idx_ += d; return *this; } constexpr auto operator-=(difference_type d) -> iterator& { idx_ -= d; return *this; } diff --git a/include/boost/multi/detail/operators.hpp b/include/boost/multi/detail/operators.hpp index 9036665a5..00e18ed88 100644 --- a/include/boost/multi/detail/operators.hpp +++ b/include/boost/multi/detail/operators.hpp @@ -128,13 +128,13 @@ template class default_initializable_facade { template class weakly_incrementable_facade : selfable { weakly_incrementable_facade() = default; friend Self; - friend constexpr auto operator++(Self& self, int) -> Self { Self ret = self.self(); ++self.self(); return ret; } + friend constexpr auto operator++(Self& self, int) -> Self { Self ret = self; ++self; return ret; } }; template class weakly_decrementable_facade : selfable { weakly_decrementable_facade() = default; friend Self; - friend constexpr auto operator--(Self& self, int) -> Self { Self ret = self.self(); --self.self(); return ret; } + friend constexpr auto operator--(Self& self, int) -> Self { Self ret = self; --self; return ret; } }; template diff --git a/test/extensions.cpp b/test/extensions.cpp index 8d5c5a11a..01fd74a83 100644 --- a/test/extensions.cpp +++ b/test/extensions.cpp @@ -448,7 +448,47 @@ auto main() -> int { // NOLINT(bugprone-exception-escape,readability-function-c } #endif } + { + auto xs2D = multi::extensions_t(10, 20); + BOOST_TEST( xs2D.size() == 10 ); + BOOST_TEST( xs2D.num_elements() == 200 ); + + using std::get; + BOOST_TEST( get<0>(xs2D[3][5]) == 3 ); + BOOST_TEST( get<0>(xs2D[4][5]) == 4 ); + + BOOST_TEST( get<0>((* xs2D.begin() )[5]) == 0 ); + BOOST_TEST( get<0>((*(xs2D.end()-1))[5]) == 9 ); + + auto const xs2D_copy = multi::extensions_t(xs2D); + BOOST_TEST( xs2D_copy == xs2D ); + + boost::multi::extensions_t<2>::iterator beg = xs2D.begin(); + beg++; + + static_assert(std::is_constructible_v::iterator, boost::multi::extensions_t<1>::iterator>); + + +#if defined(__cpp_lib_ranges) && (__cpp_lib_ranges >= 201911L) && !defined(_MSC_VER) + + static_assert( std::weakly_incrementable::iterator> ); + + BOOST_TEST( get<0>(*std::ranges::begin(xs2D)) == 0 ); + BOOST_TEST( get<0>(*(std::ranges::end(xs2D)-1)) == 9 ); + + // static_assert(std::ranges::range&>>); + + // BOOST_TEST( get<0>(*(xs1D.end()-1)) == 9 ); + // static_assert(std::ranges::bidirectional_range>); + + // auto rxs1D = xs1D | std::views::reverse; + + // BOOST_TEST( get<0>(*std::ranges::begin(rxs1D)) == 9 ); + // BOOST_TEST( get<0>(*(std::ranges::end(rxs1D)-1)) == 0 ); +#endif + + } { auto xs1D = multi::extensions_t(10); BOOST_TEST( xs1D.size() == 10 ); @@ -457,6 +497,8 @@ auto main() -> int { // NOLINT(bugprone-exception-escape,readability-function-c BOOST_TEST( get<0>(xs1D[4]) == 4 ); BOOST_TEST( get<0>(*xs1D.begin()) == 0 ); + + std::cout << "lhs " << get<0>(*(xs1D.end()-1)); BOOST_TEST( get<0>(*(xs1D.end()-1)) == 9 ); multi::extensions_t<1> const xs1D_copy(xs1D); From cf128c65d11e024a617b8b4b7b68cf2b711546c3 Mon Sep 17 00:00:00 2001 From: Alfredo Correa Date: Wed, 22 Oct 2025 10:41:22 -0700 Subject: [PATCH 03/13] more reverse --- include/boost/multi/detail/layout.hpp | 2 +- test/extensions.cpp | 13 +++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/boost/multi/detail/layout.hpp b/include/boost/multi/detail/layout.hpp index 1c6c45e60..6e4c3e258 100644 --- a/include/boost/multi/detail/layout.hpp +++ b/include/boost/multi/detail/layout.hpp @@ -398,7 +398,7 @@ struct extensions_t : boost::multi::detail::tuple_prepend_t BOOST_MULTI_HD constexpr auto operator()(index idx, Indices... rest) const { return to_linear(idx, rest...); } - class iterator : weakly_incrementable_facade, weakly_decrementable_facade { // NOLINT(fuchsia-multiple-inheritance,cppcoreguidelines-pro-type-member-init) + class iterator : weakly_incrementable_facade, weakly_decrementable_facade { // NOLINT(fuchsia-multiple-inheritance,cppcoreguidelines-pro-type-member-init,hicpp-member-init) index idx_; extensions_t rest_; friend extensions_t; diff --git a/test/extensions.cpp b/test/extensions.cpp index 01fd74a83..f6ef72efd 100644 --- a/test/extensions.cpp +++ b/test/extensions.cpp @@ -8,6 +8,7 @@ #include // IWYU pragma: keep #include // IWYU pragma: keep // for std::equal +#include #include // IWYU pragma: keep #include // for std::is_same_v // IWYU pragma: no_include // for get, iwyu bug @@ -476,16 +477,16 @@ auto main() -> int { // NOLINT(bugprone-exception-escape,readability-function-c BOOST_TEST( get<0>(*std::ranges::begin(xs2D)) == 0 ); BOOST_TEST( get<0>(*(std::ranges::end(xs2D)-1)) == 9 ); - // static_assert(std::ranges::range&>>); + static_assert(std::ranges::range&>>); - // BOOST_TEST( get<0>(*(xs1D.end()-1)) == 9 ); + BOOST_TEST( get<0>((*(xs2D.end()-1))[5]) == 9 ); - // static_assert(std::ranges::bidirectional_range>); + static_assert(std::ranges::bidirectional_range>); - // auto rxs1D = xs1D | std::views::reverse; + auto rxs2D = xs2D | std::views::reverse; - // BOOST_TEST( get<0>(*std::ranges::begin(rxs1D)) == 9 ); - // BOOST_TEST( get<0>(*(std::ranges::end(rxs1D)-1)) == 0 ); + BOOST_TEST( get<0>((*std::ranges::begin(rxs2D))[5]) == 9 ); + BOOST_TEST( get<0>((*(std::ranges::end(rxs2D)-1))[5]) == 0 ); #endif } From 013d0809358326d51aa56b42295087d5a3a5b6ce Mon Sep 17 00:00:00 2001 From: Alfredo Correa Date: Wed, 22 Oct 2025 11:13:41 -0700 Subject: [PATCH 04/13] more debug internal compiler error --- test/extensions.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/test/extensions.cpp b/test/extensions.cpp index f6ef72efd..e819afee0 100644 --- a/test/extensions.cpp +++ b/test/extensions.cpp @@ -7,14 +7,16 @@ #include // IWYU pragma: keep -#include // IWYU pragma: keep // for std::equal +#include // IWYU pragma: keep // for std::equal #include #include // IWYU pragma: keep #include // for std::is_same_v // IWYU pragma: no_include // for get, iwyu bug #if defined(__cplusplus) && (__cplusplus >= 202002L) -#include // IWYU pragma: keep // NOLINT(misc-include-cleaner) +#include // for default_initializable +#include // for reverse_iterator, input... +#include // IWYU pragma: keep // NOLINT(misc-include-cleaner) #endif namespace multi = boost::multi; @@ -469,10 +471,9 @@ auto main() -> int { // NOLINT(bugprone-exception-escape,readability-function-c static_assert(std::is_constructible_v::iterator, boost::multi::extensions_t<1>::iterator>); - #if defined(__cpp_lib_ranges) && (__cpp_lib_ranges >= 201911L) && !defined(_MSC_VER) - static_assert( std::weakly_incrementable::iterator> ); + static_assert(std::weakly_incrementable::iterator>); BOOST_TEST( get<0>(*std::ranges::begin(xs2D)) == 0 ); BOOST_TEST( get<0>(*(std::ranges::end(xs2D)-1)) == 9 ); @@ -488,7 +489,6 @@ auto main() -> int { // NOLINT(bugprone-exception-escape,readability-function-c BOOST_TEST( get<0>((*std::ranges::begin(rxs2D))[5]) == 9 ); BOOST_TEST( get<0>((*(std::ranges::end(rxs2D)-1))[5]) == 0 ); #endif - } { auto xs1D = multi::extensions_t(10); @@ -497,9 +497,10 @@ auto main() -> int { // NOLINT(bugprone-exception-escape,readability-function-c BOOST_TEST( get<0>(xs1D[3]) == 3 ); BOOST_TEST( get<0>(xs1D[4]) == 4 ); + std::cout << "line 500: lhs " << get<0>(*xs1D.begin()) << '\n'; BOOST_TEST( get<0>(*xs1D.begin()) == 0 ); - std::cout << "lhs " << get<0>(*(xs1D.end()-1)); + std::cout << "line 503: lhs " << get<0>(*(xs1D.end() - 1)) << '\n'; BOOST_TEST( get<0>(*(xs1D.end()-1)) == 9 ); multi::extensions_t<1> const xs1D_copy(xs1D); From 9b5c6c91db39aa720a132582f0522e17a957452f Mon Sep 17 00:00:00 2001 From: Alfredo Correa Date: Wed, 22 Oct 2025 11:44:02 -0700 Subject: [PATCH 05/13] add extensions constructor to workaround nvcc and nvhpc compiler bug --- include/boost/multi/detail/index_range.hpp | 8 ++++++++ test/extensions.cpp | 8 +++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/include/boost/multi/detail/index_range.hpp b/include/boost/multi/detail/index_range.hpp index d94be6e82..7f29c1fe5 100644 --- a/include/boost/multi/detail/index_range.hpp +++ b/include/boost/multi/detail/index_range.hpp @@ -344,6 +344,14 @@ struct extension_t : public range { BOOST_MULTI_HD constexpr extension_t(IndexTypeLast last) noexcept // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) // NOSONAR(cpp:S1709) allow terse syntax : range(IndexType{}, IndexType{} + last) {} + extension_t(extension_t const&) = default; + extension_t(extension_t&&) = default; + + auto operator=(extension_t const&) -> extension_t& = default; + auto operator=(extension_t&&) -> extension_t& = default; + + ~extension_t() = default; + template< class OtherExtension, decltype( diff --git a/test/extensions.cpp b/test/extensions.cpp index e819afee0..6aee7d65d 100644 --- a/test/extensions.cpp +++ b/test/extensions.cpp @@ -463,7 +463,7 @@ auto main() -> int { // NOLINT(bugprone-exception-escape,readability-function-c BOOST_TEST( get<0>((* xs2D.begin() )[5]) == 0 ); BOOST_TEST( get<0>((*(xs2D.end()-1))[5]) == 9 ); - auto const xs2D_copy = multi::extensions_t(xs2D); + multi::extensions_t const xs2D_copy(xs2D); BOOST_TEST( xs2D_copy == xs2D ); boost::multi::extensions_t<2>::iterator beg = xs2D.begin(); @@ -500,8 +500,10 @@ auto main() -> int { // NOLINT(bugprone-exception-escape,readability-function-c std::cout << "line 500: lhs " << get<0>(*xs1D.begin()) << '\n'; BOOST_TEST( get<0>(*xs1D.begin()) == 0 ); - std::cout << "line 503: lhs " << get<0>(*(xs1D.end() - 1)) << '\n'; - BOOST_TEST( get<0>(*(xs1D.end()-1)) == 9 ); + auto end = xs1D.end(); + auto endm1 = end - 1; + std::cout << "line 503: lhs " << get<0>(*endm1) << '\n'; + BOOST_TEST( get<0>(*endm1) == 9 ); multi::extensions_t<1> const xs1D_copy(xs1D); BOOST_TEST( xs1D_copy == xs1D ); From aa9e929decbb689fff185a1460e4d812280f144f Mon Sep 17 00:00:00 2001 From: Alfredo Correa Date: Wed, 22 Oct 2025 12:15:22 -0700 Subject: [PATCH 06/13] more compiler bug workaround --- include/boost/multi/detail/index_range.hpp | 5 ++++- test/extensions.cpp | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/include/boost/multi/detail/index_range.hpp b/include/boost/multi/detail/index_range.hpp index 7f29c1fe5..42591b0d5 100644 --- a/include/boost/multi/detail/index_range.hpp +++ b/include/boost/multi/detail/index_range.hpp @@ -354,6 +354,7 @@ struct extension_t : public range { template< class OtherExtension, + std::enable_if_t, int> =0, decltype( detail::implicit_cast(std::declval().first()), detail::implicit_cast(std::declval().last()) @@ -373,7 +374,9 @@ struct extension_t : public range { // BOOST_MULTI_HD constexpr explicit extension_t(OtherExtension const& other) noexcept // : extension_t{other.first(), other.last()} {} - template + template, int> =0 + > BOOST_MULTI_HD constexpr auto operator=(OtherExtension const& other) -> extension_t& { (*this) = extension_t{other}; return *this; diff --git a/test/extensions.cpp b/test/extensions.cpp index 6aee7d65d..72ef322cc 100644 --- a/test/extensions.cpp +++ b/test/extensions.cpp @@ -500,7 +500,7 @@ auto main() -> int { // NOLINT(bugprone-exception-escape,readability-function-c std::cout << "line 500: lhs " << get<0>(*xs1D.begin()) << '\n'; BOOST_TEST( get<0>(*xs1D.begin()) == 0 ); - auto end = xs1D.end(); + auto end = xs1D.end(); auto endm1 = end - 1; std::cout << "line 503: lhs " << get<0>(*endm1) << '\n'; BOOST_TEST( get<0>(*endm1) == 9 ); From b34fff9e3c1642671e8ea8eb6a0f484fda437063 Mon Sep 17 00:00:00 2001 From: Alfredo Correa Date: Wed, 22 Oct 2025 13:20:19 -0700 Subject: [PATCH 07/13] workaround for nvcc and nvhpc --- include/boost/multi/detail/index_range.hpp | 4 ++-- test/extensions.cpp | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/include/boost/multi/detail/index_range.hpp b/include/boost/multi/detail/index_range.hpp index 42591b0d5..9130911f0 100644 --- a/include/boost/multi/detail/index_range.hpp +++ b/include/boost/multi/detail/index_range.hpp @@ -354,7 +354,7 @@ struct extension_t : public range { template< class OtherExtension, - std::enable_if_t, int> =0, + std::enable_if_t, int> =0, // NOLINT(modernize-use-constraints) decltype( detail::implicit_cast(std::declval().first()), detail::implicit_cast(std::declval().last()) @@ -375,7 +375,7 @@ struct extension_t : public range { // : extension_t{other.first(), other.last()} {} template, int> =0 + std::enable_if_t, int> =0 // NOLINT(modernize-use-constraints) > BOOST_MULTI_HD constexpr auto operator=(OtherExtension const& other) -> extension_t& { (*this) = extension_t{other}; diff --git a/test/extensions.cpp b/test/extensions.cpp index 72ef322cc..5a343bbdb 100644 --- a/test/extensions.cpp +++ b/test/extensions.cpp @@ -463,7 +463,11 @@ auto main() -> int { // NOLINT(bugprone-exception-escape,readability-function-c BOOST_TEST( get<0>((* xs2D.begin() )[5]) == 0 ); BOOST_TEST( get<0>((*(xs2D.end()-1))[5]) == 9 ); +#if !defined(__NVCC__) && !defined(__NVCOMPILER) // this CTAD gives a compile error in nvhpc 22.7 and nvcc 12.0 multi::extensions_t const xs2D_copy(xs2D); +#else + multi::extensions_t<1> const xs2D_copy(xs2D); +#endif BOOST_TEST( xs2D_copy == xs2D ); boost::multi::extensions_t<2>::iterator beg = xs2D.begin(); @@ -540,10 +544,11 @@ auto main() -> int { // NOLINT(bugprone-exception-escape,readability-function-c BOOST_TEST( *(v1D.end() - 1) == 81 ); #if defined(__cpp_lib_ranges) && (__cpp_lib_ranges >= 201911L) && !defined(_MSC_VER) +#if !defined(__NVCC__) && !defined(__NVCOMPILER) // produces an error: ‘boost::multi::f_extensions_t::proj_’ has incomplete type static_assert(std::input_or_output_iterator); static_assert(std::default_initializable); static_assert(std::semiregular); - +#endif BOOST_TEST( std::ranges::begin(v1D) == v1D.begin() ); BOOST_TEST( std::ranges::end(v1D) == v1D.end() ); From f6350ccadda51c188801d294fc7d61f900d72754 Mon Sep 17 00:00:00 2001 From: Alfredo Correa Date: Wed, 22 Oct 2025 13:56:53 -0700 Subject: [PATCH 08/13] more workarounds --- include/boost/multi/detail/index_range.hpp | 4 ++-- include/boost/multi/detail/layout.hpp | 4 ++-- test/extensions.cpp | 4 ++++ 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/boost/multi/detail/index_range.hpp b/include/boost/multi/detail/index_range.hpp index 9130911f0..21c0682a5 100644 --- a/include/boost/multi/detail/index_range.hpp +++ b/include/boost/multi/detail/index_range.hpp @@ -354,7 +354,7 @@ struct extension_t : public range { template< class OtherExtension, - std::enable_if_t, int> =0, // NOLINT(modernize-use-constraints) + std::enable_if_t, int> =0, // NOLINT(modernize-use-constraints,modernize-type-traits) decltype( detail::implicit_cast(std::declval().first()), detail::implicit_cast(std::declval().last()) @@ -375,7 +375,7 @@ struct extension_t : public range { // : extension_t{other.first(), other.last()} {} template, int> =0 // NOLINT(modernize-use-constraints) + std::enable_if_t, int> =0 // NOLINT(modernize-use-constraints,modernize-type-traits) > BOOST_MULTI_HD constexpr auto operator=(OtherExtension const& other) -> extension_t& { (*this) = extension_t{other}; diff --git a/include/boost/multi/detail/layout.hpp b/include/boost/multi/detail/layout.hpp index 6e4c3e258..686571fe9 100644 --- a/include/boost/multi/detail/layout.hpp +++ b/include/boost/multi/detail/layout.hpp @@ -250,7 +250,7 @@ struct extensions_t : boost::multi::detail::tuple_prepend_t::element>; - extensions_t() = default; + constexpr extensions_t() = default; template = 0> // NOLINT(modernize-use-constraints) TODO(correaa) // cppcheck-suppress noExplicitConstructor ; to allow passing tuple // NOLINTNEXTLINE(runtime/explicit) @@ -403,7 +403,7 @@ struct extensions_t : boost::multi::detail::tuple_prepend_t rest_; friend extensions_t; - iterator(index idx, extensions_t rest) : idx_{idx}, rest_{rest} {} + constexpr iterator(index idx, extensions_t rest) : idx_{idx}, rest_{rest} {} public: using difference_type = index; diff --git a/test/extensions.cpp b/test/extensions.cpp index 5a343bbdb..283197d24 100644 --- a/test/extensions.cpp +++ b/test/extensions.cpp @@ -506,6 +506,10 @@ auto main() -> int { // NOLINT(bugprone-exception-escape,readability-function-c auto end = xs1D.end(); auto endm1 = end - 1; + aut [ii] = *endm1; + std::cout << "line 501: lhs " <(*endm1) << '\n'; BOOST_TEST( get<0>(*endm1) == 9 ); From a9eac9bd1c56d5a3ff0fb84bc3e36bd742f7ba04 Mon Sep 17 00:00:00 2001 From: Alfredo Correa Date: Wed, 22 Oct 2025 13:59:33 -0700 Subject: [PATCH 09/13] typo --- test/extensions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/extensions.cpp b/test/extensions.cpp index 283197d24..7de0c626b 100644 --- a/test/extensions.cpp +++ b/test/extensions.cpp @@ -506,7 +506,7 @@ auto main() -> int { // NOLINT(bugprone-exception-escape,readability-function-c auto end = xs1D.end(); auto endm1 = end - 1; - aut [ii] = *endm1; + auto [ii] = *endm1; std::cout << "line 501: lhs " < Date: Wed, 22 Oct 2025 14:04:07 -0700 Subject: [PATCH 10/13] more typo --- test/extensions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/extensions.cpp b/test/extensions.cpp index 7de0c626b..4b1628f85 100644 --- a/test/extensions.cpp +++ b/test/extensions.cpp @@ -508,7 +508,7 @@ auto main() -> int { // NOLINT(bugprone-exception-escape,readability-function-c auto endm1 = end - 1; auto [ii] = *endm1; std::cout << "line 501: lhs " <(*endm1) << '\n'; BOOST_TEST( get<0>(*endm1) == 9 ); From 88473af1744384754ee30d07877e55f49f49ec4f Mon Sep 17 00:00:00 2001 From: Alfredo Correa Date: Wed, 22 Oct 2025 14:05:28 -0700 Subject: [PATCH 11/13] more more typo --- test/extensions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/extensions.cpp b/test/extensions.cpp index 4b1628f85..ba2ddd49e 100644 --- a/test/extensions.cpp +++ b/test/extensions.cpp @@ -508,7 +508,7 @@ auto main() -> int { // NOLINT(bugprone-exception-escape,readability-function-c auto endm1 = end - 1; auto [ii] = *endm1; std::cout << "line 501: lhs " <(*endm1) << '\n'; BOOST_TEST( get<0>(*endm1) == 9 ); From 182304ab917ff83a87bc025f0939cc4b632ec43d Mon Sep 17 00:00:00 2001 From: Alfredo Correa Date: Wed, 22 Oct 2025 14:09:42 -0700 Subject: [PATCH 12/13] fix shadow --- test/extensions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/extensions.cpp b/test/extensions.cpp index ba2ddd49e..3643448cc 100644 --- a/test/extensions.cpp +++ b/test/extensions.cpp @@ -538,7 +538,7 @@ auto main() -> int { // NOLINT(bugprone-exception-escape,readability-function-c BOOST_TEST( get<0>(*(std::ranges::end(rxs1D)-1)) == 0 ); #endif - auto const v1D = [](auto ii) { return ii * ii; } ^ multi::extensions_t(10); + auto const v1D = [](auto idix) { return idx * idx; } ^ multi::extensions_t(10); BOOST_TEST( v1D.size() == 10 ); BOOST_TEST( v1D.elements().size() == 10 ); BOOST_TEST( v1D[0] == 0); From f9eb462c37647ff840d2823e084afc566e83197b Mon Sep 17 00:00:00 2001 From: Alfredo Correa Date: Wed, 22 Oct 2025 14:10:34 -0700 Subject: [PATCH 13/13] fix shadow --- test/extensions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/extensions.cpp b/test/extensions.cpp index 3643448cc..83adf07cd 100644 --- a/test/extensions.cpp +++ b/test/extensions.cpp @@ -538,7 +538,7 @@ auto main() -> int { // NOLINT(bugprone-exception-escape,readability-function-c BOOST_TEST( get<0>(*(std::ranges::end(rxs1D)-1)) == 0 ); #endif - auto const v1D = [](auto idix) { return idx * idx; } ^ multi::extensions_t(10); + auto const v1D = [](auto idx) { return idx * idx; } ^ multi::extensions_t(10); BOOST_TEST( v1D.size() == 10 ); BOOST_TEST( v1D.elements().size() == 10 ); BOOST_TEST( v1D[0] == 0);