Skip to content

Commit

Permalink
core: Add simple ranges::to adaptor.
Browse files Browse the repository at this point in the history
  • Loading branch information
xlauko committed Jul 10, 2024
1 parent ff277b6 commit 31eaa14
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 1 deletion.
49 changes: 49 additions & 0 deletions core/include/gap/core/ranges.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,53 @@ namespace gap::ranges
template< range R >
using range_value_t = std::iter_value_t< iterator_t< R > >;

template< typename T >
concept has_reserve = requires(T t, std::size_t s) { t.reserve(s); };

template< typename container_t, std::ranges::input_range R >
void move_or_copy_elements(R&& rng, container_t& container) {
if constexpr (std::is_rvalue_reference_v< decltype(rng) >) {
std::move(std::ranges::begin(rng), std::ranges::end(rng),
std::back_inserter(container)
);
} else {
std::copy(std::ranges::begin(rng), std::ranges::end(rng),
std::back_inserter(container)
);
}
}

template< template< typename... > class container_t >
struct to_fn {
template< std::ranges::input_range R >
auto operator()(R&& range) const {
using value_type = std::ranges::range_value_t< R >;
using result_container_t = container_t< value_type >;

result_container_t container;

if constexpr (has_reserve< result_container_t >) {
if constexpr (requires { std::ranges::size(range); }) {
container.reserve(std::ranges::size(range));
}
}

move_or_copy_elements(std::forward< R >(range), container);
return container;
}

template< std::ranges::input_range R >
friend auto operator|(R&& range, const to_fn& to) {
return to(std::forward< R >(range));
}
};

template< template< typename... > class container_t >
inline constexpr to_fn< container_t > to{};

template< template< typename... > class container_t, std::ranges::input_range R >
auto operator|(R&& range, to_fn< container_t > const& to) {
return to(std::forward< R >(range));
}

} // namespace gap::ranges
28 changes: 27 additions & 1 deletion test/core/ranges.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
// Copyright (c) 2022-present, Trail of Bits, Inc.

#include <array>
#include <doctest/doctest.h>

#include <gap/core/ranges.hpp>

#include <array>
#include <vector>
#include <list>
#include <ranges>

namespace gap::test
{
Expand Down Expand Up @@ -31,4 +35,26 @@ namespace gap::test
gr::range_value_t< std::vector< dummy > >, std::vector< dummy >::value_type
>);

TEST_SUITE("ranges") {
TEST_CASE("to vector") {
std::vector< int > v = {1, 2, 3, 4, 5};
auto v2 = v | gr::to< std::vector >;
CHECK(v == v2);
}

TEST_CASE("to list") {
std::vector< int > v = {1, 2, 3, 4, 5};
auto l = v | gr::to< std::list >;

CHECK(std::equal(v.begin(), v.end(), l.begin(), l.end()));
}

TEST_CASE("to with filter") {
std::vector< int > v = {1, 2, 3, 4, 5};
auto v2 = v | std::views::filter([] (int x) { return x % 2 == 0; })
| gr::to< std::vector >;
CHECK(v2 == std::vector{2, 4});
}
}

} // namespace gap::test

0 comments on commit 31eaa14

Please sign in to comment.