cpp-utils/include/ranges/collect.hpp
2022-06-23 17:26:19 +01:00

83 lines
2.1 KiB
C++

#pragma once
#include "../concepts/container.hpp"
#include <algorithm>
#include <ranges>
#include <unordered_set>
#include <vector>
namespace util {
namespace rg = std::ranges;
namespace detail {
template <typename Collection, rg::input_range R>
constexpr auto collect_range(R &&r) -> Collection {
Collection c;
if constexpr (rg::sized_range<R> && util::reservable<Collection>) {
c.reserve(r.size());
}
if constexpr (util::back_insertible<Collection>) {
rg::move(r, std::back_inserter(c));
} else if constexpr (util::back_emplaceable<Collection,
decltype(*r.begin())>) {
for (auto &&e : r) {
c.emplace_back(std::move(e));
}
} else if constexpr (util::emplaceable<Collection, decltype(*r.begin())>) {
for (auto &&e : r) {
c.emplace(std::move(e));
}
}
return c;
}
template <typename Collection> struct collect_range_adaptor {
template <rg::input_range R> constexpr auto operator()(R &&r) const {
return collect_range<Collection>(std::forward<R>(r));
}
};
template <typename Collection, rg::viewable_range R>
constexpr auto operator|(R &&r,
const collect_range_adaptor<Collection> &adaptor) {
return adaptor(std::forward<R>(r));
}
} // namespace detail
namespace views {
template <typename Collection>
inline detail::collect_range_adaptor<Collection> collect;
}
template <typename Collection, rg::range R>
constexpr auto collect(R &&r) -> Collection {
return r | views::collect<Collection>;
}
template <typename Range>
constexpr auto to_vector(Range r)
-> std::vector<rg::range_value_t<decltype(r)>> {
std::vector<rg::range_value_t<decltype(r)>> v;
if constexpr (rg::sized_range<decltype(r)>) {
v.reserve(rg::size(r));
}
std::ranges::copy(r, std::back_inserter(v));
return v;
}
template <typename Range>
constexpr auto to_unordered_set(Range r)
-> std::unordered_set<std::ranges::range_value_t<decltype(r)>> {
std::unordered_set<std::ranges::range_value_t<decltype(r)>> v(r.begin(),
r.end());
return v;
}
} // namespace util