#pragma once

#include <optional>
#include <ranges>
#include <xutility>


namespace util {
namespace rg = std::ranges;
namespace detail {

template <rg::input_range R>
constexpr auto get_first(R &&r) -> std::optional<rg::range_value_t<R>> {
  if (rg::begin(r) == rg::end(r)) {
    return std::nullopt;
  } else {
    return *rg::begin(r);
  }
}

struct first_range_adaptor {
  template <rg::input_range R> constexpr auto operator()(R &&r) const {
    return get_first(std::forward<R>(r));
  }
};

template <rg::viewable_range R>
constexpr auto operator|(R &&r, const first_range_adaptor &adaptor) {
  return adaptor(std::forward<R>(r));
}
} // namespace detail

namespace views {

inline detail::first_range_adaptor first;
}

template <rg::range R>
constexpr auto get_first(R &&r) -> std::optional<rg::range_value_t<R>>{
  return r | views::first;
}
} // namespace util