-
Notifications
You must be signed in to change notification settings - Fork 68
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add const_view #346
base: master
Are you sure you want to change the base?
add const_view #346
Changes from 3 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,3 +9,5 @@ build*/ | |
.vscode/ | ||
.vs/ | ||
*.*.swp | ||
.history/ | ||
.devcontainer/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,276 @@ | ||
// cmcstl2 - A concept-enabled C++ standard library | ||
// | ||
// Copyright Dvir Yitzchaki 2019 | ||
// | ||
// Use, modification and distribution is subject to 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) | ||
// | ||
// Project home: https://github.com/caseycarter/cmcstl2 | ||
// | ||
#ifndef STL2_VIEW_CONST_HPP | ||
#define STL2_VIEW_CONST_HPP | ||
|
||
#include <stl2/detail/fwd.hpp> | ||
#include <stl2/detail/range/concepts.hpp> | ||
#include <stl2/view/view_interface.hpp> | ||
#include <stl2/view/all.hpp> | ||
|
||
STL2_OPEN_NAMESPACE | ||
{ | ||
|
||
namespace ext | ||
{ | ||
template <input_range R> | ||
requires view<R> | ||
class const_view : public view_interface<const_view<R>> | ||
{ | ||
template <bool> | ||
struct __iterator; | ||
|
||
public: | ||
const_view() = default; | ||
constexpr explicit const_view(R base) : base_(std::move(base)) {} | ||
|
||
constexpr auto base() const noexcept -> R { return base_; } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We usually don't use trailing return types. |
||
|
||
constexpr __iterator<false> begin() requires (!ext::simple_view<R>) | ||
{ | ||
return __iterator<false>{*this, __stl2::begin(base_)}; | ||
} | ||
constexpr __iterator<true> begin() const requires range<const R> | ||
{ | ||
return __iterator<true>{*this, __stl2::begin(base_)}; | ||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Stray semicolon. Also, I think @CaseyCarter's style is to have the opening brace on the same line as the function's head. |
||
|
||
constexpr auto end() requires (!ext::simple_view<R>) | ||
{ | ||
return end_impl(*this); | ||
} | ||
constexpr auto end() const requires range<const R> | ||
{ | ||
return end_impl(*this); | ||
} | ||
|
||
constexpr auto size() requires (!ext::simple_view<R> && sized_range<R>) | ||
{ | ||
return __stl2::size(base_); | ||
} | ||
|
||
constexpr auto size() const requires sized_range<R> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. s/ |
||
{ | ||
return __stl2::size(base_); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A non- |
||
|
||
private: | ||
R base_ = R{}; | ||
|
||
template <class Self> | ||
static constexpr auto end_impl(Self& self) | ||
{ | ||
if constexpr (common_range<R>) | ||
{ | ||
return __iterator<std::is_const_v<Self>>{ | ||
self, | ||
__stl2::end(self.base_)}; | ||
} | ||
else | ||
{ | ||
return __stl2::end(self.base_); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You'll need to make a custom sentinel type for this. @timsong-cpp pointed out that if a range adaptor has its own iterator, it needs its own sentinel so that we can compare both the adaptor's iterator and the adaptee's iterator against the sentinel. |
||
} | ||
} | ||
}; | ||
|
||
template <input_range R> | ||
template <bool is_const> | ||
class const_view<R>::__iterator | ||
{ | ||
using parent_t = __maybe_const<is_const, const_view>; | ||
using base_t = __maybe_const<is_const, R>; | ||
|
||
friend __iterator<!is_const>; | ||
|
||
parent_t *parent_ = nullptr; | ||
iterator_t<base_t> current_{}; | ||
|
||
public: | ||
using iterator_category = iterator_category_t<iterator_t<base_t>>; | ||
using value_type = std::add_const_t<range_value_t<base_t>>; | ||
using difference_type = range_difference_t<base_t>; | ||
|
||
__iterator() = default; | ||
|
||
constexpr explicit __iterator(parent_t& parent, iterator_t<base_t> current) | ||
: parent_{std::addressof(parent)}, | ||
current_{current} | ||
{ | ||
} | ||
|
||
constexpr __iterator(__iterator<!is_const> const& other) requires is_const && convertible_to<iterator_t<R>, iterator_t<base_t>> | ||
dvirtz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
: parent_(other.parent_), current_(other.current_) | ||
dvirtz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
} | ||
|
||
constexpr iterator_t<base_t> base() const | ||
{ | ||
return current_; | ||
} | ||
|
||
constexpr decltype(auto) operator*() const | ||
{ | ||
return std::as_const(*current_); | ||
} | ||
|
||
constexpr __iterator& operator++() | ||
{ | ||
++current_; | ||
return *this; | ||
} | ||
|
||
constexpr void operator++(int) | ||
{ | ||
(void)++*this; | ||
} | ||
|
||
constexpr __iterator operator++(int) requires forward_range<base_t> | ||
{ | ||
auto temp = *this; | ||
++*this; | ||
return temp; | ||
} | ||
|
||
constexpr __iterator& operator--() requires bidirectional_range<base_t> | ||
{ | ||
--current_; | ||
return *this; | ||
} | ||
|
||
constexpr __iterator operator--(int) requires bidirectional_range<base_t> | ||
{ | ||
auto temp = *this; | ||
--*this; | ||
return temp; | ||
} | ||
|
||
constexpr __iterator& operator+=(difference_type const n) requires random_access_range<base_t> | ||
{ | ||
current_ += n; | ||
return *this; | ||
} | ||
|
||
constexpr __iterator& operator-=(difference_type const n) requires random_access_range<base_t> | ||
{ | ||
current_ -= n; | ||
return *this; | ||
} | ||
|
||
constexpr decltype(auto) operator[](difference_type const n) const | ||
requires random_access_range<base_t> | ||
{ | ||
return *(*this + n); | ||
} | ||
|
||
friend constexpr bool operator==(const __iterator& x, const __iterator& y) requires equality_comparable<iterator_t<base_t>> | ||
dvirtz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
return x.current_ == y.current_; | ||
} | ||
|
||
friend constexpr bool operator!=(const __iterator& x, const __iterator& y) requires equality_comparable<iterator_t<base_t>> | ||
dvirtz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
return !(x == y); | ||
} | ||
|
||
friend constexpr bool operator==(const __iterator& x, const sentinel_t<base_t>& y) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remember to change these overloads when you make the custom sentinel. |
||
{ | ||
return x.current_ == y; | ||
} | ||
|
||
friend constexpr bool operator==(const sentinel_t<base_t>& y, const __iterator& x) | ||
{ | ||
return x == y; | ||
} | ||
|
||
friend constexpr bool operator!=(const __iterator& x, const sentinel_t<base_t>& y) | ||
{ | ||
return !(x == y); | ||
} | ||
|
||
friend constexpr bool operator!=(const sentinel_t<base_t>& y, const __iterator& x) | ||
{ | ||
return !(x == y); | ||
} | ||
|
||
friend constexpr bool operator<(const __iterator& x, const __iterator& y) requires random_access_range<base_t> | ||
dvirtz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
return x.current_ < y.current_; | ||
} | ||
|
||
friend constexpr bool operator>(const __iterator& x, const __iterator& y) requires random_access_range<base_t> | ||
dvirtz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
return y < x; | ||
} | ||
|
||
friend constexpr bool operator<=(const __iterator& x, const __iterator& y) requires random_access_range<base_t> | ||
dvirtz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
return !(y < x); | ||
} | ||
|
||
friend constexpr bool operator>=(const __iterator& x, const __iterator& y) requires random_access_range<base_t> | ||
dvirtz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
return !(x < y); | ||
} | ||
|
||
friend constexpr __iterator operator+(__iterator i, difference_type n) requires random_access_range<base_t> | ||
{ | ||
return i += n; | ||
} | ||
|
||
friend constexpr __iterator operator+(difference_type n, __iterator i) requires random_access_range<base_t> | ||
{ | ||
return i += n; | ||
} | ||
|
||
friend constexpr __iterator operator-(__iterator i, difference_type n) requires random_access_range<base_t> | ||
{ | ||
return i -= n; | ||
} | ||
|
||
friend constexpr difference_type operator-(const __iterator& x, const __iterator& y) requires random_access_range<base_t> | ||
{ | ||
return x.current_ - y.current_; | ||
} | ||
|
||
friend constexpr difference_type operator-(const __iterator& x, const sentinel_t<base_t>& y) requires sized_sentinel_for<iterator_t<base_t>, sentinel_t<base_t>> | ||
{ | ||
return x.current_ - y; | ||
} | ||
|
||
friend constexpr difference_type operator-(const sentinel_t<base_t>& x, const __iterator& y) requires sized_sentinel_for<iterator_t<base_t>, sentinel_t<base_t>> | ||
{ | ||
return x - y.current_; | ||
} | ||
}; | ||
|
||
template <input_range R> | ||
dvirtz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
const_view(R&& r)->const_view<all_view<R>>; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please also move this between the range adaptor and its iterator. |
||
|
||
} // namespace ext | ||
|
||
namespace views::ext | ||
{ | ||
struct __as_const_fn : detail::__pipeable<__as_const_fn> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Inheritance not needed for this one. Also, please look at some of the other adaptors to see what's usually done. I recommend There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's necessary for adaptors with no arguments. same as |
||
{ | ||
template <viewable_range Rng> | ||
constexpr auto operator()(Rng&& rng) const | ||
{ | ||
return __stl2::ext::const_view{std::forward<Rng>(rng)}; | ||
} | ||
}; | ||
|
||
inline constexpr __as_const_fn as_const{}; | ||
} // namespace views::ext | ||
} | ||
STL2_CLOSE_NAMESPACE | ||
|
||
#endif // STL2_VIEW_CONST_HPP |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
// cmcstl2 - A concept-enabled C++ standard library | ||
// | ||
// Copyright Dvir Yitzchaki 2019 | ||
// | ||
// Use, modification and distribution is subject to 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) | ||
// | ||
// Project home: https://github.com/caseycarter/cmcstl2 | ||
#include <stl2/view/const.hpp> | ||
#include <stl2/view/counted.hpp> | ||
#include <stl2/view/filter.hpp> | ||
#include <vector> | ||
#include "../simple_test.hpp" | ||
#include "../test_iterators.hpp" | ||
|
||
namespace ranges = __stl2; | ||
|
||
int main() { | ||
using namespace ranges; | ||
|
||
int rgi[] = {1, 2, 3, 4}; | ||
|
||
{ | ||
auto rng = rgi | views::ext::as_const; | ||
static_assert(same_as<int &, decltype(*begin(rgi))>); | ||
static_assert(same_as<int const &, decltype(*begin(rng))>); | ||
static_assert(same_as<int const &&, range_rvalue_reference_t<decltype(rng)>>); | ||
static_assert(view<decltype(rng)>); | ||
static_assert(common_range<decltype(rng)>); | ||
static_assert(sized_range<decltype(rng)>); | ||
static_assert(random_access_range<decltype(rng)>); | ||
CHECK_EQUAL(rng, {1, 2, 3, 4}); | ||
CHECK(&*begin(rng) == &rgi[0]); | ||
CHECK(rng.size() == 4u); | ||
} | ||
|
||
{ | ||
auto rng2 = views::counted(::forward_iterator(rgi), 4) | views::ext::as_const; | ||
static_assert(same_as<int const &, decltype(*begin(rng2))>); | ||
static_assert(same_as<range_rvalue_reference_t<decltype(rng2)>, int const &&>); | ||
static_assert(view<decltype(rng2)>); | ||
static_assert(forward_range<decltype(rng2)>); | ||
static_assert(!bidirectional_range<decltype(rng2)>); | ||
static_assert(!common_range<decltype(rng2)>); | ||
static_assert(sized_range<decltype(rng2)>); | ||
CHECK_EQUAL(rng2, {1, 2, 3, 4}); | ||
CHECK(&*begin(rng2) == &rgi[0]); | ||
CHECK(rng2.size() == 4u); | ||
} | ||
|
||
#if 0 // Test DISABLED pending view implementations. | ||
{ | ||
auto zip = views::zip(rgi, rgi); | ||
auto rng3 = zip | views::ext::as_const; | ||
has_type<common_pair<int &, int &>>(*begin(zip)); | ||
has_type<common_pair<int &&, int &&>>(iter_move(begin(zip))); | ||
has_type<common_pair<int const &, int const &>>(*begin(rng3)); | ||
has_type<common_pair<int const &&, int const &&>>(iter_move(begin(rng3))); | ||
static_assert(view<decltype(rng3)>); | ||
static_assert(random_access_range<decltype(rng3)>); | ||
static_assert(common_range<decltype(rng3)>); | ||
static_assert(sized_range<decltype(rng3)>); | ||
using P = std::pair<int,int>; | ||
CHECK_EQUAL(rng3, {P{1,1}, P{2,2}, P{3,3}, P{4,4}}); | ||
CHECK(&(*begin(rng3)).first == &rgi[0]); | ||
CHECK(rng3.size() == 4u); | ||
} | ||
|
||
{ | ||
auto zip2 = views::zip(rgi, rgi) | views::move; | ||
auto rng4 = zip2 | views::ext::as_const; | ||
has_type<common_pair<int &&, int &&>>(*begin(zip2)); | ||
has_type<common_pair<int &&, int &&>>(iter_move(begin(zip2))); | ||
has_type<common_pair<int const &&, int const &&>>(*begin(rng4)); | ||
has_type<common_pair<int const &&, int const &&>>(iter_move(begin(rng4))); | ||
static_assert(view<decltype(rng4)>); | ||
static_assert(random_access_range<decltype(rng4)>); | ||
static_assert(common_range<decltype(rng4)>); | ||
static_assert(sized_range<decltype(rng4)>); | ||
using P = std::pair<int,int>; | ||
CHECK_EQUAL(rng4, {P{1,1}, P{2,2}, P{3,3}, P{4,4}}); | ||
CHECK(&(*begin(rng4)).first == &rgi[0]); | ||
CHECK(rng4.size() == 4u); | ||
} | ||
|
||
{ | ||
auto rng = debug_input_view<int>{rgi} | views::ext::as_const; | ||
static_assert(same_as<int const&, range_reference_t<decltype(rng)>>); | ||
CHECK_EQUAL(rng, rgi); | ||
} | ||
#endif | ||
|
||
{ | ||
auto r = rgi | ||
| views::filter([](auto) { return true; }) | ||
| views::ext::as_const; | ||
static_assert(view<decltype(r)>); | ||
} | ||
|
||
return ::test_result(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please make this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like this project needs a .clang-format file