-
Notifications
You must be signed in to change notification settings - Fork 0
Split range adaptors #10
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
base: main
Are you sure you want to change the base?
Changes from all 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 |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| #ifndef BEMAN_STR_SPLIT_DETAIL_NON_PROPAGATING_CACHE_HPP | ||
| #define BEMAN_STR_SPLIT_DETAIL_NON_PROPAGATING_CACHE_HPP | ||
|
|
||
| #include <optional> | ||
| #include <type_traits> | ||
|
|
||
| namespace beman::str_split::detail { | ||
|
|
||
| template <class T> | ||
| requires std::is_object_v<T> | ||
| struct non_propagating_cache : std::optional<T> { | ||
| non_propagating_cache() = default; | ||
|
|
||
| constexpr non_propagating_cache(const non_propagating_cache&) noexcept {} | ||
|
|
||
| constexpr non_propagating_cache(non_propagating_cache&& from) noexcept { this->reset(); } | ||
|
|
||
| ~non_propagating_cache() = default; | ||
|
|
||
| constexpr non_propagating_cache& operator=(const non_propagating_cache& from) noexcept { | ||
| if (this != std::addressof(from)) { | ||
| this->reset(); | ||
| } | ||
| return *this; | ||
| } | ||
|
|
||
| constexpr non_propagating_cache& operator=(non_propagating_cache&& from) noexcept { | ||
| this->reset(); | ||
| from.reset(); | ||
| return *this; | ||
| } | ||
|
|
||
| template <class It> | ||
| requires std::is_constructible_v<T, std::iter_reference_t<const It&>> | ||
| constexpr T& | ||
| emplace_deref(const It& it) noexcept(std::is_nothrow_constructible_v<T, std::iter_reference_t<const It&>>) { | ||
| return this->emplace(*it); | ||
| } | ||
| }; | ||
|
|
||
| } // namespace beman::str_split::detail | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,106 @@ | ||||||||||||||||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||||||||||||||
|
|
||||||||||||||||
| #ifndef BEMAN_STR_SPLIT_SPLIT_ITERATOR_HPP | ||||||||||||||||
| #define BEMAN_STR_SPLIT_SPLIT_ITERATOR_HPP | ||||||||||||||||
|
|
||||||||||||||||
| #include <iterator> | ||||||||||||||||
| #include <ranges> | ||||||||||||||||
|
|
||||||||||||||||
| namespace beman::str_split::detail { | ||||||||||||||||
|
|
||||||||||||||||
| template<class Parent> | ||||||||||||||||
| class split_sentinel; | ||||||||||||||||
|
|
||||||||||||||||
| template<class Parent> | ||||||||||||||||
| class split_iterator | ||||||||||||||||
| { | ||||||||||||||||
|
Comment on lines
+14
to
+16
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. [pre-commit] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||
| friend split_sentinel<Parent>; | ||||||||||||||||
|
|
||||||||||||||||
| using base_iterator = Parent::base_iterator; | ||||||||||||||||
|
|
||||||||||||||||
| public: | ||||||||||||||||
| using iterator_concept = std::forward_iterator_tag; | ||||||||||||||||
|
Comment on lines
+21
to
+22
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. [pre-commit] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||
| using iterator_category = std::input_iterator_tag; | ||||||||||||||||
| using value_type = Parent::base_subrange; | ||||||||||||||||
| using difference_type = std::iter_difference_t<base_iterator>; | ||||||||||||||||
|
Comment on lines
+24
to
+25
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. [pre-commit] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||
|
|
||||||||||||||||
| split_iterator() = default; | ||||||||||||||||
|
|
||||||||||||||||
| constexpr split_iterator(Parent& parent, base_iterator current, value_type next) | ||||||||||||||||
| : parent_(std::addressof(parent)) | ||||||||||||||||
| , current_(std::move(current)) | ||||||||||||||||
| , next_(std::move(next)) | ||||||||||||||||
| { | ||||||||||||||||
| } | ||||||||||||||||
|
Comment on lines
+30
to
+34
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. [pre-commit] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||
|
|
||||||||||||||||
| constexpr base_iterator base() const | ||||||||||||||||
| { | ||||||||||||||||
| return current_; | ||||||||||||||||
| } | ||||||||||||||||
|
Comment on lines
+36
to
+39
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. [pre-commit] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||
|
|
||||||||||||||||
| constexpr value_type operator*() const | ||||||||||||||||
| { | ||||||||||||||||
| return {current_, next_.begin()}; | ||||||||||||||||
| } | ||||||||||||||||
|
Comment on lines
+41
to
+44
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. [pre-commit] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||
|
|
||||||||||||||||
| constexpr split_iterator& operator++() | ||||||||||||||||
| { | ||||||||||||||||
|
Comment on lines
+46
to
+47
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. [pre-commit] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||
| current_ = next_.begin(); | ||||||||||||||||
|
|
||||||||||||||||
| if (current_ == std::ranges::end(parent_->base_)) { | ||||||||||||||||
| trailing_empty_ = false; | ||||||||||||||||
| } else { | ||||||||||||||||
| current_ = next_.end(); | ||||||||||||||||
| if (current_ == std::ranges::end(parent_->base_)) { | ||||||||||||||||
| trailing_empty_ = true; | ||||||||||||||||
| next_ = {current_, current_}; | ||||||||||||||||
|
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. [pre-commit] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||
| } else { | ||||||||||||||||
| next_ = parent_->find_next(current_); | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| return *this; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| constexpr split_iterator operator++(int) | ||||||||||||||||
| { | ||||||||||||||||
|
Comment on lines
+65
to
+66
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. [pre-commit] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||
| auto prev = *this; | ||||||||||||||||
| ++(*this); | ||||||||||||||||
| return prev; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| friend constexpr bool operator ==(const split_iterator& lhs, const split_iterator& rhs) | ||||||||||||||||
| { | ||||||||||||||||
|
Comment on lines
+72
to
+73
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. [pre-commit] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||
| return lhs.current_ == rhs.current_ && lhs.trailing_empty_ == rhs.trailing_empty_; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| private: | ||||||||||||||||
| Parent* parent_ = nullptr; | ||||||||||||||||
|
Comment on lines
+77
to
+78
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. [pre-commit] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||
| base_iterator current_{}; | ||||||||||||||||
| value_type next_{}; | ||||||||||||||||
| bool trailing_empty_ = false; | ||||||||||||||||
|
Comment on lines
+80
to
+81
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. [pre-commit] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||
| }; | ||||||||||||||||
|
|
||||||||||||||||
| template<class Parent> | ||||||||||||||||
| class split_sentinel | ||||||||||||||||
| { | ||||||||||||||||
| public: | ||||||||||||||||
|
Comment on lines
+84
to
+87
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. [pre-commit] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||
| split_sentinel() = default; | ||||||||||||||||
|
|
||||||||||||||||
| constexpr split_sentinel(Parent& parent) | ||||||||||||||||
| : end_(std::ranges::end(parent.base_)) | ||||||||||||||||
| { | ||||||||||||||||
| } | ||||||||||||||||
|
Comment on lines
+90
to
+93
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. [pre-commit] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||
|
|
||||||||||||||||
| friend constexpr bool operator ==(const split_iterator<Parent>& lhs, const split_sentinel& rhs) | ||||||||||||||||
| { | ||||||||||||||||
|
Comment on lines
+95
to
+96
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. [pre-commit] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||
| return lhs.current_ == rhs.end_ && !lhs.trailing_empty_; | ||||||||||||||||
| } | ||||||||||||||||
|
|
||||||||||||||||
| private: | ||||||||||||||||
|
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. [pre-commit] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||
| std::ranges::sentinel_t<decltype(std::declval<Parent>().base())> end_{}; | ||||||||||||||||
| }; | ||||||||||||||||
|
|
||||||||||||||||
| } | ||||||||||||||||
|
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. [pre-commit] reported by reviewdog 🐶
Suggested change
|
||||||||||||||||
|
|
||||||||||||||||
| #endif | ||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,160 @@ | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| #ifndef BEMAN_STR_SPLIT_SPLIT_HPP | ||
| #define BEMAN_STR_SPLIT_SPLIT_HPP | ||
|
|
||
| #include <beman/str_split/detail/non_propagating_cache.hpp> | ||
| #include <beman/str_split/detail/split_iterator.hpp> | ||
|
|
||
| #include <ranges> | ||
| #include <functional> | ||
|
|
||
| namespace beman::str_split { | ||
|
|
||
| namespace detail { | ||
|
|
||
| template <class V, class Pattern> | ||
| concept splittable_view = | ||
| std::ranges::view<V> && std::ranges::view<Pattern> && | ||
| std::indirectly_comparable<std::ranges::iterator_t<V>, std::ranges::iterator_t<Pattern>, std::ranges::equal_to>; | ||
|
|
||
| template <class Range> | ||
| using single_value_view_t = std::ranges::single_view<std::ranges::range_value_t<Range>>; | ||
|
|
||
| } // namespace detail | ||
|
|
||
| template <std::ranges::forward_range V, std::ranges::forward_range Pattern> | ||
| requires detail::splittable_view<V, Pattern> | ||
| class split_view : public std::ranges::view_interface<split_view<V, Pattern>> { | ||
| public: | ||
| using iterator = detail::split_iterator<split_view>; | ||
| friend iterator; | ||
|
|
||
| using sentinel = detail::split_sentinel<split_view>; | ||
| friend sentinel; | ||
|
|
||
| split_view() | ||
| requires std::default_initializable<V> && std::default_initializable<Pattern> | ||
| = default; | ||
|
|
||
| constexpr explicit split_view(V base, Pattern pattern) : base_(std::move(base)), pattern_(std::move(pattern)) {} | ||
|
|
||
| template <std::ranges::forward_range R> | ||
| requires std::constructible_from<V, std::ranges::views::all_t<R>> && | ||
| std::constructible_from<Pattern, detail::single_value_view_t<R>> | ||
| constexpr explicit split_view(R&& range, std::ranges::range_value_t<R> value) | ||
| : base_(std::ranges::views::all(std::forward<R>(range))), | ||
| pattern_(std::ranges::views::single(std::move(value))) {} | ||
|
|
||
| constexpr V base() const& | ||
| requires std::copy_constructible<V> | ||
| { | ||
| return base_; | ||
| } | ||
|
|
||
| constexpr V base() && { return std::move(base_); } | ||
|
|
||
| constexpr iterator begin() { | ||
| if (!cached_begin_) { | ||
| cached_begin_.emplace(find_next(std::ranges::begin(base_))); | ||
| } | ||
| return {*this, std::ranges::begin(base_), *cached_begin_}; | ||
| } | ||
|
|
||
| constexpr auto end() { | ||
| if constexpr (std::ranges::common_range<V>) { | ||
| return iterator(*this, std::ranges::end(base_), {}); | ||
| } else { | ||
| return sentinel(*this); | ||
| } | ||
| } | ||
|
|
||
| private: | ||
| using base_iterator = std::ranges::iterator_t<V>; | ||
| using base_subrange = std::ranges::subrange<base_iterator>; | ||
|
|
||
| constexpr base_subrange find_next(base_iterator it) { | ||
| auto [b, e] = std::ranges::search(std::ranges::subrange(it, std::ranges::end(base_)), pattern_); | ||
| if (b != std::ranges::end(base_) && std::ranges::empty(pattern_)) { | ||
| ++b; | ||
| ++e; | ||
| } | ||
| return {b, e}; | ||
| } | ||
|
|
||
| [[no_unique_address]] V base_{}; | ||
| [[no_unique_address]] Pattern pattern_{}; | ||
| detail::non_propagating_cache<base_subrange> cached_begin_{}; | ||
| }; | ||
|
|
||
| template <class R, class Pattern> | ||
| split_view(R&&, Pattern&&) -> split_view<std::ranges::views::all_t<R>, std::ranges::views::all_t<Pattern>>; | ||
|
|
||
| template <class R> | ||
| split_view(R&&, std::ranges::range_value_t<R>) | ||
| -> split_view<std::ranges::views::all_t<R>, detail::single_value_view_t<R>>; | ||
|
|
||
| namespace detail { | ||
|
|
||
| template <class R, class Pattern> | ||
| using split_view_t = decltype(split_view(std::declval<R>(), std::declval<Pattern>())); | ||
|
|
||
| template <std::move_constructible Pattern> | ||
| class split_adaptor_closure : public std::ranges::range_adaptor_closure<split_adaptor_closure<Pattern>> { | ||
| public: | ||
| constexpr explicit split_adaptor_closure(Pattern pattern) noexcept(std::is_nothrow_move_constructible_v<Pattern>) | ||
| : pattern_(std::move(pattern)) {} | ||
|
|
||
| template <class R> | ||
| constexpr split_view_t<R, Pattern> operator()(R&& range) const& noexcept( | ||
| std::is_nothrow_constructible_v<split_view_t<R, Pattern>, R, const Pattern&>) { | ||
| return split_view(std::forward<R>(range), pattern_); | ||
| } | ||
|
|
||
| template <class R> | ||
| constexpr split_view_t<R, Pattern> | ||
| operator()(R&& range) && noexcept(std::is_nothrow_constructible_v<split_view_t<R, Pattern>, R, Pattern>) { | ||
| return split_view(std::forward<R>(range), std::move(pattern_)); | ||
| } | ||
|
|
||
| private: | ||
| Pattern pattern_{}; | ||
| }; | ||
|
|
||
| template <class Pattern> | ||
| using split_adaptor_closure_t = split_adaptor_closure<std::decay_t<Pattern>>; | ||
|
|
||
| namespace split { | ||
|
|
||
| struct fn { | ||
| template <class R, class Pattern> | ||
| static constexpr split_view_t<R, Pattern> | ||
| operator()(R&& range, | ||
| Pattern&& pattern) noexcept(std::is_nothrow_constructible_v<split_view_t<R, Pattern>, R, Pattern>) { | ||
| return split_view(std::forward<R>(range), std::forward<Pattern>(pattern)); | ||
| } | ||
|
|
||
| template <class Pattern> | ||
| static constexpr split_adaptor_closure_t<Pattern> operator()(Pattern&& pattern) noexcept( | ||
| std::is_nothrow_constructible_v<split_adaptor_closure_t<Pattern>, Pattern>) { | ||
| return split_adaptor_closure(std::forward<Pattern>(pattern)); | ||
| } | ||
| }; | ||
|
|
||
| } // namespace split | ||
|
|
||
| } // namespace detail | ||
|
|
||
| namespace views { | ||
|
|
||
| inline namespace rao { | ||
|
|
||
| inline constexpr auto split = detail::split::fn{}; | ||
|
|
||
| } | ||
|
|
||
| } // namespace views | ||
|
|
||
| } // namespace beman::str_split | ||
|
|
||
| #endif |
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.
[pre-commit] reported by reviewdog 🐶