diff --git a/src/tools/std20/algorithm.hpp b/src/tools/std20/algorithm.hpp index 2232e5b..a085398 100644 --- a/src/tools/std20/algorithm.hpp +++ b/src/tools/std20/algorithm.hpp @@ -43,7 +43,7 @@ //#include //#include //#include -//#include +#include "tools/std20/algorithm/mismatch.hpp" //#include //#include //#include diff --git a/src/tools/std20/algorithm/mismatch.hpp b/src/tools/std20/algorithm/mismatch.hpp new file mode 100644 index 0000000..7fc7dc7 --- /dev/null +++ b/src/tools/std20/algorithm/mismatch.hpp @@ -0,0 +1,132 @@ +// nanorange/algorithm/mismatch.hpp +// +// Copyright (c) 2018 Tristan Brindle (tcbrindle at gmail dot com) +// Distributed under 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) + +#ifndef NANORANGE_ALGORITHM_MISMATCH_HPP_INCLUDED +#define NANORANGE_ALGORITHM_MISMATCH_HPP_INCLUDED + +#include "tools/std20/detail/algorithm/result_types.hpp" +#include "tools/std20/ranges.hpp" + +NANO_BEGIN_NAMESPACE + +// [range.mismatch] + +template +using mismatch_result = in_in_result; + +namespace detail { + +struct mismatch_fn { +private: + friend struct is_permutation_fn; + + template + static constexpr mismatch_result + impl3(I1 first1, S1 last1, I2 first2, Pred& pred, Proj1& proj1, Proj2& proj2) + { + while (first1 != last1 && + nano::invoke(pred, nano::invoke(proj1, *first1), + nano::invoke(proj2, *first2))) { + ++first1; + ++first2; + } + + return {first1, first2}; + } + + template + static constexpr mismatch_result + impl4(I1 first1, S1 last1, I2 first2, S2 last2, Pred& pred, Proj1& proj1, + Proj2& proj2) + { + while (first1 != last1 && first2 != last2 && + nano::invoke(pred, nano::invoke(proj1, *first1), + nano::invoke(proj2, *first2))) { + ++first1; + ++first2; + } + + return {first1, first2}; + } + +public: + // three legged + template + NANO_DEPRECATED constexpr std::enable_if_t< + input_iterator && sentinel_for && + input_iterator> && + !input_range && + indirect_relation, projected, Proj2>>, + mismatch_result>> + operator()(I1 first1, S1 last1, I2&& first2, Pred pred = Pred{}, + Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{}) const + { + return mismatch_fn::impl3(std::move(first1), std::move(last1), + std::forward(first2), pred, + proj1, proj2); + } + + // range and a half + template + NANO_DEPRECATED constexpr std::enable_if_t< + input_range && input_iterator> && + !input_range && + indirect_relation, Proj1>, + projected, Proj2>>, + mismatch_result, std::decay_t>> + operator()(Rng1&& rng1, I2&& first2, Pred pred = Pred{}, + Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{}) const + { + return mismatch_fn::impl3(nano::begin(rng1), nano::end(rng1), + std::forward(first2), pred, + proj1, proj2); + } + + // four legged + template + constexpr std::enable_if_t< + input_iterator && sentinel_for && input_iterator && + sentinel_for && + indirect_relation, projected>, + mismatch_result> + operator()(I1 first1, S1 last1, I2 first2, S2 last2, Pred pred = Pred{}, + Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{}) const + { + return mismatch_fn::impl4(std::move(first1), std::move(last1), + std::move(first2), std::move(last2), + pred, proj1, proj2); + } + + // two ranges + template + constexpr std::enable_if_t< + input_range && input_range && + indirect_relation, Proj1>, + projected, Proj2>>, + mismatch_result, borrowed_iterator_t>> + operator()(Rng1&& rng1, Rng2&& rng2, Pred pred = Pred{}, + Proj1 proj1 = Proj1{}, Proj2 proj2 = Proj2{}) const + { + return mismatch_fn::impl4(nano::begin(rng1), nano::end(rng1), + nano::begin(rng2), nano::end(rng2), + pred, proj1, proj2); + } +}; + +} // namespace detail + +NANO_INLINE_VAR(detail::mismatch_fn, mismatch) + +NANO_END_NAMESPACE + +#endif diff --git a/src/tools/std20/detail/algorithm/result_types.hpp b/src/tools/std20/detail/algorithm/result_types.hpp new file mode 100644 index 0000000..447625e --- /dev/null +++ b/src/tools/std20/detail/algorithm/result_types.hpp @@ -0,0 +1,172 @@ +// nanorange/detail/algorithm/result_types.hpp +// +// Copyright (c) 2020 Boris Staletic (boris dot staletic at gmail dot com) +// Copyright (c) 2020 Tristan Brindle (tcbrindle at gmail dot com) +// Distributed under 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) + +#ifndef NANORANGE_DETAIL_ALGORITHM_RETURN_TYPES +#define NANORANGE_DETAIL_ALGORITHM_RETURN_TYPES + +#include "tools/std20/detail/macros.hpp" +#include "tools/std20/detail/concepts/core.hpp" + +#include + +NANO_BEGIN_NAMESPACE + +template +struct in_fun_result { + NANO_NO_UNIQUE_ADDRESS I in; + NANO_NO_UNIQUE_ADDRESS F fun; + + template && + convertible_to, int> = 0> + constexpr operator in_fun_result() const & + { + return {in, fun}; + } + + template && + convertible_to, int> = 0> + constexpr operator in_fun_result() && + { + return {std::move(in), std::move(fun)}; + } +}; + +template +struct in_in_result { + NANO_NO_UNIQUE_ADDRESS I1 in1; + NANO_NO_UNIQUE_ADDRESS I2 in2; + + template && + convertible_to, int> = 0> + constexpr operator in_in_result() const & + { + return {in1, in2}; + } + + template && + convertible_to, int> = 0> + constexpr operator in_in_result() && + { + return {std::move(in1), std::move(in2)}; + } +}; + +template +struct in_out_result { + NANO_NO_UNIQUE_ADDRESS I in; + NANO_NO_UNIQUE_ADDRESS O out; + + template && + convertible_to, int> = 0> + constexpr operator in_out_result() const & + { + return {in, out}; + } + + template && + convertible_to, int> = 0> + constexpr operator in_out_result() && + { + return {std::move(in), std::move(out)}; + } +}; + +template +struct in_in_out_result { + NANO_NO_UNIQUE_ADDRESS I1 in1; + NANO_NO_UNIQUE_ADDRESS I2 in2; + NANO_NO_UNIQUE_ADDRESS O out; + + template && + convertible_to && + convertible_to, int> = 0> + constexpr operator in_in_out_result() const & + { + return {in1, in2, out}; + } + + template && + convertible_to && + convertible_to, int> = 0> + constexpr operator in_in_out_result() && + { + return {std::move(in1), std::move(in2), std::move(out)}; + } +}; + +template +struct in_out_out_result { + NANO_NO_UNIQUE_ADDRESS I in; + NANO_NO_UNIQUE_ADDRESS O1 out1; + NANO_NO_UNIQUE_ADDRESS O2 out2; + + template && + convertible_to && + convertible_to, int> = 0> + constexpr operator in_out_out_result() const & + { + return {in, out1, out2}; + } + + template && + convertible_to && + convertible_to, int> = 0> + constexpr operator in_out_out_result() && + { + return {std::move(in), std::move(out1), std::move(out2)}; + } +}; + +template +struct min_max_result { + NANO_NO_UNIQUE_ADDRESS T min; + NANO_NO_UNIQUE_ADDRESS T max; + + template , int> = 0> + constexpr operator min_max_result() const & + { + return {min, max}; + } + + template , int> = 0> + constexpr operator min_max_result() && + { + return {std::move(min), std::move(max)}; + } +}; + +template +struct in_found_result { + NANO_NO_UNIQUE_ADDRESS I in; + bool found; + template, int> = 0> + constexpr operator in_found_result() const & { + return {in, found}; + } + template, int> = 0> + constexpr operator in_found_result() && { + return {std::move(in), found}; + } +}; + +NANO_END_NAMESPACE + +#endif diff --git a/src/tools/std20/views.hpp b/src/tools/std20/views.hpp index 5ac46db..81ad310 100644 --- a/src/tools/std20/views.hpp +++ b/src/tools/std20/views.hpp @@ -22,7 +22,7 @@ #include "tools/std20/views/ref.hpp" #include "tools/std20/views/reverse.hpp" #include "tools/std20/views/single.hpp" -//#include "tools/std20/views/split.hpp" +#include "tools/std20/views/split.hpp" #include "tools/std20/views/subrange.hpp" #include "tools/std20/views/take.hpp" #include "tools/std20/views/take_while.hpp" diff --git a/src/tools/std20/views/split.hpp b/src/tools/std20/views/split.hpp new file mode 100644 index 0000000..6a42f3f --- /dev/null +++ b/src/tools/std20/views/split.hpp @@ -0,0 +1,458 @@ +// nanorange/views/split.hpp +// +// Copyright (c) 2019 Tristan Brindle (tcbrindle at gmail dot com) +// Distributed under 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) + +#ifndef NANORANGE_VIEWS_SPLIT_HPP_INCLUDED +#define NANORANGE_VIEWS_SPLIT_HPP_INCLUDED + +#include "tools/std20/algorithm/mismatch.hpp" +#include "tools/std20/detail/views/range_adaptors.hpp" +#include "tools/std20/iterator/default_sentinel.hpp" +#include "tools/std20/views/all.hpp" +#include "tools/std20/views/interface.hpp" +#include "tools/std20/views/single.hpp" + +NANO_BEGIN_NAMESPACE + +namespace detail { + +template struct require_constant; + +struct tiny_range_concept { + + template + auto requires_() -> decltype( + std::declval::size()>>() + ); + + template + static auto test(long) -> std::false_type; + + template + static auto test(int) -> std::enable_if_t< + sized_range && + detail::requires_ && + (std::remove_reference_t::size() <= 1), + std::true_type>; +}; + +template +NANO_CONCEPT tiny_range = decltype(tiny_range_concept::test(0))::value; + +template +struct split_view_data { + V base_ = V(); + P pattern_ = P(); +}; + +template +struct split_view_data { + V base_ = V(); + P pattern_ = P(); + iterator_t current_ = iterator_t(); +}; + +} // namespace detail + +namespace split_view_ { + +template +struct split_view : view_interface> { +private: + + static_assert(input_range); + static_assert(forward_range); + static_assert(view); + static_assert(view); + static_assert(indirectly_comparable, iterator_t, + ranges::equal_to>); + static_assert(forward_range || detail::tiny_range); + + detail::split_view_data> data_{}; + + + + template + struct inner_iterator; + + template + struct outer_iterator { + private: + friend struct outer_iterator; + friend struct inner_iterator; + + using Parent = detail::conditional_t; + using Base = detail::conditional_t; + Parent* parent_ = nullptr; + iterator_t current_ = iterator_t(); + + constexpr decltype(auto) get_current() + { + if constexpr (forward_range) { + return (current_); + } else { + return (parent_->data_.current_); + } + } + + constexpr decltype(auto) get_current() const + { + if constexpr (forward_range) { + return (current_); + } else { + return (parent_->data_.current_); + } + } + + constexpr bool done() const + { + return get_current() == ranges::end(parent_->data_.base_); + } + + public: + // FIXME: iterator_concept + using iterator_category = detail::conditional_t< + forward_range, forward_iterator_tag, input_iterator_tag>; + + struct value_type { + private: + outer_iterator i_ = outer_iterator(); + + public: + value_type() = default; + + constexpr explicit value_type(outer_iterator i) + : i_(std::move(i)) + {} + + constexpr inner_iterator begin() const + { + return inner_iterator{i_}; + } + + constexpr default_sentinel_t end() const + { + return default_sentinel; + } + }; + + using difference_type = range_difference_t; + // Extension: legacy typedefs + using pointer = void; + using reference = value_type; + + outer_iterator() = default; + + template , int> = 0> + constexpr explicit outer_iterator(Parent& parent) + : parent_(std::addressof(parent)) + {} + + template , int> = 0> + constexpr outer_iterator(Parent& parent, iterator_t current) + : parent_(std::addressof(parent)), + current_(std::move(current)) + {} + + template >, int> = 0, + bool C = Const, typename VV = V, + std::enable_if_t, iterator_t>, int> = 0> + constexpr outer_iterator(I i) + : parent_(i.parent_), + current_(std::move(i.current_)) + {} + + constexpr value_type operator*() const { return value_type{*this}; } + + constexpr outer_iterator& operator++() + { + const auto end = ranges::end(parent_->data_.base_); + if (get_current() == end) { + return *this; + } + const auto [pbegin, pend] = subrange{parent_->data_.pattern_}; + if (pbegin == pend) { + ++get_current(); + } else { + do { + const auto [b, p] = ranges::mismatch(get_current(), end, + pbegin, pend); + if (p == pend) { + get_current() = b; + break; + } + } while (++get_current() != end); + } + return *this; + } + + constexpr decltype(auto) operator++(int) + { + if constexpr (forward_range) { + auto tmp = *this; + ++*this; + return tmp; + } else { + ++*this; + } + } + + template + friend constexpr auto operator==(const outer_iterator& x, const outer_iterator& y) + -> std::enable_if_t, bool> + { + return x.current_ == y.current_; + } + + template + friend constexpr auto operator!=(const outer_iterator& x, const outer_iterator& y) + -> std::enable_if_t, bool> + { + return !(x == y); + } + + friend constexpr bool operator==(const outer_iterator& x, default_sentinel_t) + { + return x.done(); + } + + friend constexpr bool operator==(default_sentinel_t d, const outer_iterator& x) + { + return x == d; + } + + friend constexpr bool operator!=(const outer_iterator& x, default_sentinel_t d) + { + return !(x == d); + } + + friend constexpr bool operator!=(default_sentinel_t d, const outer_iterator& x) + { + return !(x == d); + } + }; + + template + struct inner_iterator { + private: + using Base = detail::conditional_t; + static constexpr bool NoReallyGccConst = Const; + outer_iterator i_ = outer_iterator(); + bool incremented_ = false; + + constexpr bool done() const + { + auto cur = i_.get_current(); + auto end = ranges::end(i_.parent_->data_.base_); + if (cur == end) { + return true; + } + auto [pcur, pend] = subrange{i_.parent_->data_.pattern_}; + if (pcur == pend) { + return incremented_; + } + do { + if (*cur != *pcur) { + return false; + } + if (++pcur == pend) { + return true; + } + } while (++cur != end); + return false; + } + + constexpr decltype(auto) get_outer_current() const { return i_.get_current(); } + + public: + using iterator_category = detail::conditional_t< + derived_from>, forward_iterator_tag>, + forward_iterator_tag, + input_iterator_tag>; + using value_type = range_value_t; + using difference_type = range_difference_t; + + inner_iterator() = default; + + constexpr explicit inner_iterator(outer_iterator i) + : i_(std::move(i)) + {} + + constexpr decltype(auto) operator*() const { return *i_.get_current(); } + + constexpr inner_iterator& operator++() + { + incremented_ = true; + if constexpr (!forward_range) { + if constexpr (Pattern::size() == 0) { + return *this; + } + } + ++i_.get_current(); + return *this; + } + + + constexpr decltype(auto) operator++(int) + { + if constexpr (forward_range) { + auto tmp = *this; + ++*this; + return tmp; + } else { + ++*this; + } + } + + template + friend constexpr auto operator==(const inner_iterator& x, const inner_iterator& y) + -> std::enable_if_t, bool> + { + return x.get_outer_current() == y.get_outer_current(); + } + + template + friend constexpr auto operator!=(const inner_iterator& x, const inner_iterator& y) + -> std::enable_if_t, bool> + { + return !(x == y); + } + + friend constexpr bool operator==(const inner_iterator& x, default_sentinel_t) + { + return x.done(); + } + + friend constexpr bool operator==(default_sentinel_t d, const inner_iterator& x) + { + return x == d; + } + + friend constexpr bool operator!=(const inner_iterator& x, default_sentinel_t d) + { + return !(x == d); + } + + friend constexpr bool operator!=(default_sentinel_t d, const inner_iterator& x) + { + return !(x == d); + } + + friend constexpr decltype(auto) iter_move(const inner_iterator& i) + noexcept(noexcept(ranges::iter_move(i.get_outer_current()))) + { + return ranges::iter_move(i.get_outer_current()); + } + + template + friend constexpr auto iter_swap(const inner_iterator& x, const inner_iterator& y) + noexcept(noexcept(ranges::iter_swap(x.get_outer_current(), y.get_outer_current()))) + -> std::enable_if_t> + { + ranges::iter_swap(x.get_outer_current(), y.get_outer_current()); + } + }; + +public: + split_view() = default; + + constexpr split_view(V base, Pattern pattern) + : data_{std::move(base), std::move(pattern)} + {} + + template >, int> = 0, + std::enable_if_t< + constructible_from>>, int> = 0, + std::enable_if_t, int> = 0> + constexpr split_view(R&& r, range_value_t e) + : data_{views::all(std::forward(r)), single_view{std::move(e)}} + {} + + constexpr auto begin() + { + if constexpr (forward_range) { + return outer_iterator>{*this, ranges::begin(data_.base_)}; + } else { + data_.current_ = ranges::begin(data_.base_); + return outer_iterator{*this}; + } + } + + template && forward_range, int> = 0> + constexpr auto begin() const + { + return outer_iterator{*this, ranges::begin(data_.base_)}; + } + + template && common_range, int> = 0> + constexpr auto end() + { + return outer_iterator>{*this, ranges::end(data_.base_)}; + } + + constexpr auto end() const + { + if constexpr (forward_range && + forward_range && + common_range) { + return outer_iterator{*this, ranges::end(data_.base_)}; + } else { + return default_sentinel; + } + } +}; + +template +split_view(R&&, P&&) -> split_view, all_view

>; + +template , int> = 0> +split_view(R&&, range_value_t) + -> split_view, single_view>>; + +} // namespace split_view_ + +using split_view_::split_view; + +namespace detail { + +struct split_view_fn { + + template + constexpr auto operator()(E&& e, F&& f) const + -> decltype(split_view{std::forward(e), std::forward(f)}) + { + return split_view{std::forward(e), std::forward(f)}; + } + + template + constexpr auto operator()(P&& p) const + { + return detail::rao_proxy{ + [p = std::forward

(p)](auto&& r) mutable +#ifndef NANO_MSVC_LAMBDA_PIPE_WORKAROUND + -> decltype(split_view{std::forward(r), std::declval()}) +#endif + { + return split_view{std::forward(r), std::move(p)}; + }}; + } +}; + +} // namespace detail + +namespace views { + +NANO_INLINE_VAR(nano::detail::split_view_fn, split) + +} + +NANO_END_NAMESPACE + +#endif