Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions include/boost/multi/detail/index_range.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -344,8 +344,17 @@ struct extension_t : public range<IndexType, IndexTypeLast> {
BOOST_MULTI_HD constexpr extension_t(IndexTypeLast last) noexcept // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) // NOSONAR(cpp:S1709) allow terse syntax
: range<IndexType, IndexTypeLast>(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,
std::enable_if_t<!std::is_base_of_v<extension_t, OtherExtension>, int> =0, // NOLINT(modernize-use-constraints,modernize-type-traits)
decltype(
detail::implicit_cast<IndexType>(std::declval<OtherExtension>().first()),
detail::implicit_cast<IndexTypeLast>(std::declval<OtherExtension>().last())
Expand All @@ -365,7 +374,9 @@ struct extension_t : public range<IndexType, IndexTypeLast> {
// BOOST_MULTI_HD constexpr explicit extension_t(OtherExtension const& other) noexcept
// : extension_t{other.first(), other.last()} {}

template<class OtherExtension>
template<class OtherExtension,
std::enable_if_t<!std::is_base_of_v<extension_t, OtherExtension>, int> =0 // NOLINT(modernize-use-constraints,modernize-type-traits)
>
BOOST_MULTI_HD constexpr auto operator=(OtherExtension const& other) -> extension_t& {
(*this) = extension_t{other};
return *this;
Expand Down
73 changes: 66 additions & 7 deletions include/boost/multi/detail/layout.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ class f_extensions_t {
}
}

class iterator {
class iterator : public weakly_incrementable_facade<iterator>, weakly_decrementable_facade<iterator> { // NOLINT(fuchsia-multiple-inheritance)
typename extensions_t<D>::iterator it_;
Proj proj_;

Expand All @@ -132,32 +132,43 @@ 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; }
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; }

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_; }
friend constexpr 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_; }
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<D - 1, decltype(ll)>(extensions_t<D - 1>(get<1>(*it_).base().tail()), ll);
} else {
return proj_(get<0>(*it_));
}
}

using value_type = int; // decltype(*std::declval<iterator&>());

auto operator[](difference_type dd) const { return *((*this) + dd); } // TODO(correaa) use ra_iterator_facade
};

Expand Down Expand Up @@ -239,7 +250,7 @@ struct extensions_t : boost::multi::detail::tuple_prepend_t<index_extension, typ

using element = boost::multi::detail::tuple_prepend_t<index_extension::value_type, typename extensions_t<D - 1>::element>;

extensions_t() = default;
constexpr extensions_t() = default;

template<class T = void, std::enable_if_t<sizeof(T*) && D == 1, int> = 0> // NOLINT(modernize-use-constraints) TODO(correaa)
// cppcheck-suppress noExplicitConstructor ; to allow passing tuple<int, int> // NOLINTNEXTLINE(runtime/explicit)
Expand Down Expand Up @@ -387,12 +398,12 @@ struct extensions_t : boost::multi::detail::tuple_prepend_t<index_extension, typ
template<class... Indices>
BOOST_MULTI_HD constexpr auto operator()(index idx, Indices... rest) const { return to_linear(idx, rest...); }

class iterator {
class iterator : weakly_incrementable_facade<iterator>, weakly_decrementable_facade<iterator> { // NOLINT(fuchsia-multiple-inheritance,cppcoreguidelines-pro-type-member-init,hicpp-member-init)
index idx_;
extensions_t<D - 1> rest_;
friend extensions_t;

iterator(index idx, extensions_t<D - 1> rest) : idx_{idx}, rest_{rest} {}
constexpr iterator(index idx, extensions_t<D - 1> rest) : idx_{idx}, rest_{rest} {}

public:
using difference_type = index;
Expand All @@ -401,6 +412,11 @@ struct extensions_t : boost::multi::detail::tuple_prepend_t<index_extension, typ
using reference = value_type;
using iterator_category = std::random_access_iterator_tag;

iterator() = default;

constexpr auto operator+=(difference_type d) -> 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_}; }

Expand Down Expand Up @@ -683,6 +699,10 @@ template<> struct extensions_t<0> : tuple<> {
: base_{tup} {}

extensions_t() = default;
// template<class T1>
// cppcheck-suppress noExplicitConstructor ; to allow passing tuple<int, int> // 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; }
Expand Down Expand Up @@ -811,6 +831,45 @@ template<> struct extensions_t<1> : tuple<multi::index_extension> {
return elements_t{get<0>(static_cast<tuple<multi::index_extension> const&>(*this))};
}

class iterator : weakly_incrementable_facade<iterator>, weakly_decrementable_facade<iterator> { // 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<index>(), std::declval<extensions_t<0>>().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<tuple<multi::index_extension> const&>(*this)).size();
Expand Down
16 changes: 16 additions & 0 deletions include/boost/multi/detail/operators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,22 @@ struct weakly_incrementable {
// friend T& operator++(weakly_incrementable& t){return ++static_cast<T&>(t);}
};

template<class Self> class default_initializable_facade {
default_initializable_facade() = default;
};

template<class Self> class weakly_incrementable_facade : selfable<Self> {
weakly_incrementable_facade() = default;
friend Self;
friend constexpr auto operator++(Self& self, int) -> Self { Self ret = self; ++self; return ret; }
};

template<class Self> class weakly_decrementable_facade : selfable<Self> {
weakly_decrementable_facade() = default;
friend Self;
friend constexpr auto operator--(Self& self, int) -> Self { Self ret = self; --self; return ret; }
};

template<class T>
struct weakly_decrementable {
protected:
Expand Down
108 changes: 105 additions & 3 deletions test/extensions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@

#include <boost/core/lightweight_test.hpp> // IWYU pragma: keep

#include <algorithm> // IWYU pragma: keep // for std::equal
#include <algorithm> // IWYU pragma: keep // for std::equal
#include <iostream>
#include <tuple> // IWYU pragma: keep
#include <type_traits> // for std::is_same_v
// IWYU pragma: no_include <variant> // for get, iwyu bug

#if defined(__cplusplus) && (__cplusplus >= 202002L)
#include <ranges> // IWYU pragma: keep // NOLINT(misc-include-cleaner)
#include <concepts> // for default_initializable
#include <iterator> // for reverse_iterator, input...
#include <ranges> // IWYU pragma: keep // NOLINT(misc-include-cleaner)
#endif

namespace multi = boost::multi;
Expand Down Expand Up @@ -448,18 +451,117 @@ 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 );

#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();
beg++;

static_assert(std::is_constructible_v<boost::multi::extensions_t<1>::iterator, boost::multi::extensions_t<1>::iterator>);

#if defined(__cpp_lib_ranges) && (__cpp_lib_ranges >= 201911L) && !defined(_MSC_VER)

static_assert(std::weakly_incrementable<boost::multi::extensions_t<2>::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<std::remove_cvref_t<boost::multi::extensions_t<2>&>>);

BOOST_TEST( get<0>((*(xs2D.end()-1))[5]) == 9 );

static_assert(std::ranges::bidirectional_range<multi::extensions_t<2>>);

auto rxs2D = xs2D | std::views::reverse;

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);
BOOST_TEST( xs1D.size() == 10 );
using std::get;
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 );

auto v1D = [](auto ii) { return ii * ii; } ^ multi::extensions_t(10);
auto end = xs1D.end();
auto endm1 = end - 1;
auto [ii] = *endm1;
std::cout << "line 501: lhs " <<ii << '\n';
BOOST_TEST( ii == 9 );

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 );

multi::extensions_t<1>::iterator const copy(xs1D.begin());
BOOST_TEST( copy == xs1D.begin() );

static_assert(std::is_constructible_v<boost::multi::extensions_t<1>::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<std::remove_cvref_t<boost::multi::extensions_t<1>&>>);

BOOST_TEST( get<0>(*(xs1D.end()-1)) == 9 );

static_assert(std::ranges::bidirectional_range<multi::extensions_t<1>>);

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 idx) { return idx * idx; } ^ 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)
#if !defined(__NVCC__) && !defined(__NVCOMPILER) // produces an error: ‘boost::multi::f_extensions_t<D, Proj>::proj_’ has incomplete type
static_assert(std::input_or_output_iterator<decltype(v1D.begin())>);
static_assert(std::default_initializable<decltype(v1D.begin())>);
static_assert(std::semiregular<decltype(v1D.begin())>);
#endif
BOOST_TEST( std::ranges::begin(v1D) == v1D.begin() );
BOOST_TEST( std::ranges::end(v1D) == v1D.end() );

static_assert(std::ranges::bidirectional_range<decltype(v1D)>);
static_assert(std::ranges::random_access_range<decltype(v1D)>);
auto rv1D = v1D | std::views::reverse;

BOOST_TEST( rv1D[0] == 81);
BOOST_TEST( rv1D[9] == 0 );
#endif
}
return boost::report_errors();
Expand Down
26 changes: 26 additions & 0 deletions test/index_range.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@
// IWYU pragma: no_include <tuple> // for tuple_element<>::type
#include <type_traits>

#if defined(__cplusplus) && (__cplusplus >= 202002L)
#include <ranges> // IWYU pragma: keep // NOLINT(misc-include-cleaner)
#endif

namespace multi = boost::multi;

auto main() -> int { // NOLINT(readability-function-cognitive-complexity,bugprone-exception-escape)
Expand Down Expand Up @@ -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<int> 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<std::remove_cvref_t<boost::multi::extensions_t<1>&>>);

// 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();
}
Loading