Skip to content

Commit

Permalink
Update ranges::to (#27)
Browse files Browse the repository at this point in the history
* Add is_deductible
* Update iter_value_t.h
* Create container_appender.h
* Create reservable_container.h
* Fix namespace
* Refactor ranges::advance
* Update ranges::to
* Fix DEDUCE_EXPR on C++23
* Update CTAD for poor STL providers
* Fix ranges::to adaptors
  • Loading branch information
lackhole committed Jul 14, 2024
1 parent 164dce1 commit 6a1398d
Show file tree
Hide file tree
Showing 11 changed files with 710 additions and 554 deletions.
176 changes: 91 additions & 85 deletions README.md

Large diffs are not rendered by default.

217 changes: 98 additions & 119 deletions include/preview/__iterator/advance.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,126 +23,126 @@ namespace preview {
namespace ranges {
namespace detail {

struct advance_niebloid;
using preview::detail::conditional_tag;
using preview::detail::tag_1;
using preview::detail::tag_2;
using preview::detail::tag_3;
using preview::detail::tag_else;

template<typename I>
using advance_n_tag = conditional_tag<random_access_iterator<I>, bidirectional_iterator<I>>;

template<typename I>
constexpr void advance_n(I& i, iter_difference_t<I> n, tag_1 /* random_access_iterator */) {
i += n;
}

template<typename I>
constexpr void advance_n(I& i, iter_difference_t<I> n, tag_2 /* bidirectional_iterator */) {
while (n > 0) {
--n;
++i;
}
struct advance_niebloid {
private:
template<typename I, typename S, bool = has_typename_type<iter_difference<I>>::value /* false */>
struct convertible_to_iter_difference : std::false_type {};
template<typename I, typename S>
struct convertible_to_iter_difference<I, S, true> : convertible_to<S, iter_difference_t<I>> {};

while (n < 0) {
++n;
--i;
public:
template<typename I>
constexpr std::enable_if_t<input_or_output_iterator<I>::value>
operator()(I& i, iter_difference_t<I> n) const {
using tag_t = preview::detail::conditional_tag<random_access_iterator<I>, bidirectional_iterator<I>>;
advance_n(i, n, tag_t{});
}
}

template<typename I>
constexpr void advance_n(I& i, iter_difference_t<I> n, tag_else) {
while (n > 0) {
--n;
++i;
template<typename I, typename S, std::enable_if_t<conjunction<
input_or_output_iterator<I>,
negation<convertible_to_iter_difference<I, S>>,
sentinel_for<S, I>
>::value, int> = 0>
constexpr void operator()(I& i, S bound) const {
using tag_t = preview::detail::conditional_tag<assignable_from<I&, S>, sized_sentinel_for<S, I>>;
advance_bound(i, bound, tag_t{});
}
}

template<typename I, typename S>
struct advance_bound_check_impl : conjunction<input_or_output_iterator<I>, sentinel_for<S, I>> {};

template<typename I, typename S, bool = has_typename_type<iter_difference<I>>::value /* true */>
struct advance_bound_check : conjunction< negation<std::is_same<iter_difference_t<I>, S>>,
advance_bound_check_impl<I, S> > {};
template<typename I, typename S>
struct advance_bound_check<I, S, false> : advance_bound_check_impl<I, S> {};

template<typename I, typename S>
using advance_bound_tag = conditional_tag<assignable_from<I&, S>, sized_sentinel_for<S, I>>;

template<typename I, typename S>
constexpr void advance_bound(I& i, S bound, tag_1 /* assignable_from */) {
i = std::move(bound);
}

template<typename I, typename S>
constexpr void advance_bound(I& i, S bound, tag_2 /* sized_sentinel_for */);

template<typename I, typename S>
constexpr void advance_bound(I& i, S bound, tag_else) {
while (i != bound)
++i;
}


template<typename I, typename S>
using advance_mixed_tag = conditional_tag<sized_sentinel_for<S, I>, bidirectional_iterator<I>>;
template<typename I, typename S, std::enable_if_t<conjunction<
input_or_output_iterator<I>,
sentinel_for<S, I>
>::value, int> = 0>
constexpr iter_difference_t<I>
operator()(I& i, iter_difference_t<I> n, S bound) const {
using tag_t = preview::detail::conditional_tag<sized_sentinel_for<S, I>, bidirectional_iterator<I>>;
return advance_mixed(i, n, bound, tag_t{});
}

template<typename I, typename S>
constexpr iter_difference_t<I>
advance_mixed(I& i, iter_difference_t<I> n, S bound, tag_1 /* sized_sentinel_for */);
private:
using tag_1 = preview::detail::tag_1;
using tag_2 = preview::detail::tag_2;
using tag_else = preview::detail::tag_else;

template<typename I, typename S>
constexpr iter_difference_t<I>
advance_mixed(I& i, iter_difference_t<I> n, S bound, tag_2 /* bidirectional_iterator */) {
while (n > 0 && i != bound) {
--n;
++i;
template<typename I>
constexpr void advance_n(I& i, iter_difference_t<I> n, tag_1 /* random_access_iterator */) const {
i += n;
}

while (n < 0 && i != bound) {
++n;
--i;
template<typename I>
constexpr void advance_n(I& i, iter_difference_t<I> n, tag_2 /* bidirectional_iterator */) {
while (n > 0) {
--n;
++i;
}

while (n < 0) {
++n;
--i;
}
}

return n;
}

template<typename I, typename S>
constexpr iter_difference_t<I>
advance_mixed(I& i, iter_difference_t<I> n, S bound, tag_else) {
while (n > 0 && i != bound) {
--n;
++i;
template<typename I>
constexpr void advance_n(I& i, iter_difference_t<I> n, tag_else) const {
while (n > 0) {
--n;
++i;
}
}

return n;
}
template<typename I, typename S>
constexpr void advance_bound(I& i, S bound, tag_1 /* assignable_from */) const {
i = std::move(bound);
}

struct advance_niebloid {
template<typename I>
constexpr std::enable_if_t<input_or_output_iterator<I>::value>
operator()(I& i, iter_difference_t<I> n) const {
advance_n(i, n, advance_n_tag<I>{});
template<typename I, typename S>
constexpr void advance_bound(I& i, S bound, tag_2 /* sized_sentinel_for */) const {
(*this)(i, bound - i);
}

template<typename I, typename S>
constexpr void advance_bound(I& i, S bound, tag_else) const {
while (i != bound)
++i;
}

// Subsumes above
template<typename I, typename S>
constexpr std::enable_if_t<advance_bound_check<I, S>::value>
operator()(I& i, S bound) const {
advance_bound(i, bound, advance_bound_tag<I, S>{});
constexpr iter_difference_t<I>
advance_mixed(I& i, iter_difference_t<I> n, S bound, tag_1 /* sized_sentinel_for */) const {
const iter_difference_t<I> d = bound - i;
if ((n < 0 && n <= d) || (n > 0 && n >= d)) {
(*this)(i, d);
return n - d;
}

(*this)(i, n);
return 0;
}

template<typename I, typename S>
constexpr iter_difference_t<I>
advance_mixed(I& i, iter_difference_t<I> n, S bound, tag_2 /* bidirectional_iterator */) const {
while (n > 0 && i != bound) {
--n;
++i;
}

while (n < 0 && i != bound) {
++n;
--i;
}

return n;
}

template<typename I, typename S, std::enable_if_t<conjunction<
input_or_output_iterator<I>,
sentinel_for<S, I>
>::value, int> = 0>
template<typename I, typename S>
constexpr iter_difference_t<I>
operator()(I& i, iter_difference_t<I> n, S bound) const {
return advance_mixed(i, n, bound, advance_mixed_tag<I, S>{});
advance_mixed(I& i, iter_difference_t<I> n, S bound, tag_else) const {
while (n > 0 && i != bound) {
--n;
++i;
}

return n;
}
};
} // namespace detail
Expand All @@ -154,27 +154,6 @@ PREVIEW_INLINE_VARIABLE constexpr detail::advance_niebloid advance{};
} // namespace niebloid
using namespace niebloid;

namespace detail {

template<typename I, typename S>
constexpr void advance_bound(I& i, S bound, tag_2 /* sized_sentinel_for */) {
ranges::advance(i, bound - i);
}

template<typename I, typename S>
constexpr iter_difference_t<I>
advance_mixed(I& i, iter_difference_t<I> n, S bound, tag_1 /* sized_sentinel_for */) {
const iter_difference_t<I> d = bound - i;
if ((n < 0 && n <= d) || (n > 0 && n >= d)) {
ranges::advance(i, d);
return n - d;
}

ranges::advance(i, n);
return 0;
}

} // namespace detail
} // namespace ranges
} // namespace preview

Expand Down
8 changes: 4 additions & 4 deletions include/preview/__iterator/iter_value_t.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ template<
struct iter_value_impl {};

template<typename T, bool v>
struct iter_value_impl<T, false, v> {
using type = typename iterator_traits<remove_cvref_t<T>>::value_type;
struct iter_value_impl<T, true, v> {
using type = typename indirectly_readable_traits<remove_cvref_t<T>>::value_type;
};

template<typename T>
struct iter_value_impl<T, true, true> {
using type = typename indirectly_readable_traits<remove_cvref_t<T>>::value_type;
struct iter_value_impl<T, false, true> {
using type = typename iterator_traits<remove_cvref_t<T>>::value_type;
};

} // namespace detail
Expand Down
118 changes: 118 additions & 0 deletions include/preview/__ranges/detail/container_appender.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
//
// Created by lux on 2024. 7. 13..
//

#ifndef PREVIEW_RANGES_DETAIL_CONTAINER_APPENDER_H_
#define PREVIEW_RANGES_DETAIL_CONTAINER_APPENDER_H_

#include <type_traits>
#include <utility>

#include "preview/__ranges/range.h"
#include "preview/__type_traits/conjunction.h"
#include "preview/__type_traits/detail/tag.h"
#include "preview/__type_traits/is_invocable.h"
#include "preview/__type_traits/is_referenceable.h"
#include "preview/__type_traits/void_t.h"

namespace preview {
namespace ranges {
namespace detail {

template<typename C, typename Ref, typename = void>
struct mem_fn_emplace_back_callable : std::false_type {};
template<typename C, typename Ref>
struct mem_fn_emplace_back_callable<C, Ref, void_t<decltype(
std::declval<C&>().emplace_back(std::declval<Ref>())
)>> : std::true_type {};

template<typename C, typename Ref, typename = void>
struct mem_fn_push_back_callable : std::false_type {};
template<typename C, typename Ref>
struct mem_fn_push_back_callable<C, Ref, void_t<decltype(
std::declval<C&>().push_back(std::declval<Ref>())
)>> : std::true_type {};

template<typename C, typename = void>
struct has_mem_fn_end : std::false_type {};
template<typename C>
struct has_mem_fn_end<C, void_t<decltype(std::declval<C&>().end())>>
: is_referencable<decltype(std::declval<C&>().end())> {};

template<typename C, typename Ref, bool = has_mem_fn_end<C>::value /* false */, typename = void>
struct mem_fn_emplace_callable : std::false_type {};
template<typename C, typename Ref>
struct mem_fn_emplace_callable<C, Ref, true, void_t<decltype(
std::declval<C&>().emplace(std::declval<C&>().end(), std::declval<Ref>())
)>> : std::true_type {};

template<typename C, typename Ref, bool = has_mem_fn_end<C>::value /* false */, typename = void>
struct mem_fn_insert_callable : std::false_type {};
template<typename C, typename Ref>
struct mem_fn_insert_callable<C, Ref, true, void_t<decltype(
std::declval<C&>().insert(std::declval<C&>().end(), std::declval<Ref>())
)>> : std::true_type {};

template<typename Container>
class container_appender_object {
template<typename Reference>
using tag_t = preview::detail::conditional_tag<
mem_fn_emplace_back_callable<Container, Reference>,
mem_fn_push_back_callable<Container, Reference>,
mem_fn_emplace_callable<Container, Reference>,
mem_fn_insert_callable<Container, Reference>
>;

public:
constexpr explicit container_appender_object(Container& container) noexcept
: container_(container) {}

template<typename Reference, std::enable_if_t<(tag_t<Reference>::value > 0), int> = 0>
constexpr void operator()(Reference&& r) {
call(std::forward<Reference>(r), tag_t<Reference>{});
}

private:
using tag_1 = preview::detail::tag_1;
using tag_2 = preview::detail::tag_2;
using tag_3 = preview::detail::tag_3;
using tag_4 = preview::detail::tag_4;

template<typename Reference>
void call(Reference&& r, tag_1) {
container_.emplace_back(std::forward<Reference>(r));
}

template<typename Reference>
void call(Reference&& r, tag_2) {
container_.push_back(std::forward<Reference>(r));
}

template<typename Reference>
void call(Reference&& r, tag_3) {
container_.emplace(container_.end(), std::forward<Reference>(r));
}

template<typename Reference>
void call(Reference&& r, tag_4) {
container_.insert(container_.end(), std::forward<Reference>(r));
}

Container& container_;
};

} // namespace detail

template<typename Container, typename Reference>
struct container_appendable
: is_invocable<detail::container_appender_object<Container>, Reference> {};

template<typename Container>
constexpr auto container_appender(Container& c) noexcept {
return detail::container_appender_object<Container>{c};
}

} // namespace ranges
} // namespace preview

#endif // PREVIEW_RANGES_DETAIL_CONTAINER_APPENDER_H_
Loading

0 comments on commit 6a1398d

Please sign in to comment.