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

68 lines
1.8 KiB
C++

#pragma once
#include <ranges>
namespace util {
namespace rg = std::ranges;
template <rg::sized_range R>
requires rg::view<R>
class drop_last_view : public rg::view_interface<drop_last_view<R>> {
private:
R base_{};
std::iter_difference_t<rg::iterator_t<R>> count_{};
rg::iterator_t<R> iter_{std::begin(base_)};
public:
drop_last_view() = default;
constexpr drop_last_view(R base,
std::iter_difference_t<rg::iterator_t<R>> count)
: base_(base), count_(count), iter_(std::begin(base_)) {}
constexpr R base() const & { return base_; }
constexpr R base() && { return std::move(base_); }
constexpr auto begin() const { return iter_; }
constexpr auto end() const { return std::end(base_) - count_; }
constexpr auto size() const requires rg::sized_range<const R> {
const auto s = rg::size(base_);
const auto c = static_cast<decltype(s)>(count_);
return s < c ? 0 : s - c;
}
};
namespace detail {
struct drop_last_range_adaptor_closure {
std::size_t count_;
constexpr drop_last_range_adaptor_closure(std::size_t count)
: count_(count) {}
template <rg::viewable_range R> constexpr auto operator()(R &&r) const {
return drop_last_view(std::forward<R>(r), count_);
}
};
struct drop_last_range_adaptor {
template <rg::viewable_range R>
constexpr auto operator()(R &&r,
std::iter_difference_t<rg::iterator_t<R>> count) {
return drop_last_view(std::forward<R>(r), count);
}
constexpr auto operator()(std::size_t count) {
return drop_last_range_adaptor_closure(count);
}
};
template <rg::viewable_range R>
constexpr auto operator|(R &&r, drop_last_range_adaptor_closure const &a) {
return a(std::forward<R>(r));
}
} // namespace detail
namespace views {
inline detail::drop_last_range_adaptor drop_last;
} // namespace views
} // namespace util