-
Notifications
You must be signed in to change notification settings - Fork 32
add const_view #346
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
Open
dvirtz
wants to merge
6
commits into
CaseyCarter:master
Choose a base branch
from
dvirtz:const_view
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
add const_view #346
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,3 +9,5 @@ build*/ | |
| .vscode/ | ||
| .vs/ | ||
| *.*.swp | ||
| .history/ | ||
| .devcontainer/ | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,241 @@ | ||
| // 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/all.hpp> | ||
| #include <stl2/view/view_interface.hpp> | ||
|
|
||
| STL2_OPEN_NAMESPACE { | ||
| namespace ext { | ||
| template <input_range R> | ||
| requires view<R> | ||
| struct const_view : view_interface<const_view<R>> { | ||
| template <bool> | ||
| struct __iterator; | ||
|
|
||
| public: | ||
| const_view() = default; | ||
| constexpr explicit const_view(R base) : base_(std::move(base)) {} | ||
|
|
||
| constexpr R base() const noexcept { return base_; } | ||
|
|
||
| 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_)}; | ||
| } | ||
|
|
||
| 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<const R> { | ||
| return __stl2::size(base_); | ||
| } | ||
|
|
||
| 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_); | ||
|
Collaborator
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> | ||
| const_view(R&& r)->const_view<all_view<R>>; | ||
|
|
||
| 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 = range_value_t<base_t>; | ||
| using difference_type = range_difference_t<base_t>; | ||
|
|
||
| __iterator() = default; | ||
|
|
||
| constexpr __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>> | ||
| : parent_(other.parent_), current_(other.current_) {} | ||
|
|
||
| constexpr iterator_t<base_t> base() const { return current_; } | ||
|
|
||
| constexpr common_reference_t<value_type const &&, range_reference_t<base_t>> operator*() const { | ||
| return *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>> { | ||
| return x.current_ == y.current_; | ||
| } | ||
|
|
||
| friend constexpr bool operator!=(const __iterator& x, | ||
| const __iterator& y) requires equality_comparable<iterator_t<base_t>> { | ||
| return !(x == y); | ||
| } | ||
|
|
||
| friend constexpr bool operator==(const __iterator& x, | ||
| const sentinel_t<base_t>& y) { | ||
| 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> { | ||
| return x.current_ < y.current_; | ||
| } | ||
|
|
||
| friend constexpr bool operator>(const __iterator& x, const __iterator& y) | ||
| requires random_access_range<base_t> { | ||
| return y < x; | ||
| } | ||
|
|
||
| friend constexpr bool operator<=(const __iterator& x, const __iterator& y) | ||
| requires random_access_range<base_t> { | ||
| return !(y < x); | ||
| } | ||
|
|
||
| friend constexpr bool operator>=(const __iterator& x, const __iterator& y) | ||
| requires random_access_range<base_t> { | ||
| 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_; | ||
| } | ||
| }; | ||
|
|
||
| } // namespace ext | ||
|
|
||
| namespace views::ext { | ||
| struct __as_const_fn : detail::__pipeable<__as_const_fn> { | ||
| 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 | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| // 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 "../simple_test.hpp" | ||
| #include "../test_iterators.hpp" | ||
| #include <stl2/view/const.hpp> | ||
| #include <stl2/view/counted.hpp> | ||
| #include <stl2/view/filter.hpp> | ||
| #include <stl2/view/move.hpp> | ||
| #include <vector> | ||
|
|
||
| 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 rng6 = | ||
| rgi | views::filter([](auto) { return true; }) | views::ext::as_const; | ||
| static_assert(view<decltype(rng6)>); | ||
| } | ||
|
|
||
| { | ||
| auto rng7 = rgi | views::move | views::ext::as_const; | ||
| static_assert(same_as<int const &&, decltype(*begin(rng7))>); | ||
| static_assert( | ||
| same_as<int const &&, range_rvalue_reference_t<decltype(rng7)>>); | ||
| static_assert(view<decltype(rng7)>); | ||
| static_assert(common_range<decltype(rng7)>); | ||
| static_assert(sized_range<decltype(rng7)>); | ||
| static_assert(!forward_range<decltype(rng7)>); | ||
| CHECK_EQUAL(rng7, {1, 2, 3, 4}); | ||
| CHECK(rng7.size() == 4u); | ||
| // no move of const rvalue | ||
| CHECK_EQUAL(rgi, {1, 2, 3, 4}); | ||
| } | ||
|
|
||
| return ::test_result(); | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
A non-
constoverload is necessary forsize.