#pragma once

#include <concepts>
#include <ranges>

namespace util {
template <typename C>
concept reservable = requires(C &c, typename C::size_type i) {
  {c.reserve(i)};
};

template <typename C>
concept back_insertible = requires(C &c,
                                   const std::ranges::range_value_t<C> &t) {
  { std::back_inserter(c) } -> std::same_as<std::back_insert_iterator<C>>;
  {c.push_back(t)};
};

template <typename C>
concept front_insertible = requires(C &c,
                                    const std::ranges::range_value_t<C> &t) {
  { std::front_inserter(c) } -> std::same_as<std::front_insert_iterator<C>>;
  {c.push_front(t)};
};

template <typename C>
concept insertible = requires(C &c, std::ranges::iterator_t<C> i,
                              const std::ranges::range_value_t<C> &t) {
  { std::inserter(c, i) } -> std::same_as<std::insert_iterator<C>>;
  {c.insert(i, t)};
};
template <typename C, typename... Ts>
concept emplaceable = requires(C &c, Ts... t) {
  {c.emplace(std::move(t...))};
};

template <typename C, typename... Ts>
concept back_emplaceable = requires(C &c, Ts... t) {
  {c.emplace_back(std::move(t...))};
};
} // namespace util