9#include <unordered_set> 
   11USERVER_NAMESPACE_BEGIN
 
   15namespace impl::projected_set {
 
   17template <
typename Raw, 
auto Projection>
 
   18using ProjectionResult =
 
   19    std::decay_t<std::invoke_result_t<
decltype(Projection), 
const Raw&>>;
 
   21template <
typename Raw, 
auto Projection, 
typename ResultHash>
 
   22using DefaultedResultHash =
 
   23    std::conditional_t<std::is_void_v<ResultHash>,
 
   24                       std::hash<ProjectionResult<Raw, Projection>>,
 
   27template <
typename Raw, 
auto Projection, 
typename ResultHash>
 
   28struct Hash : 
public DefaultedResultHash<Raw, Projection, ResultHash> {
 
   29  using is_transparent [[maybe_unused]] = 
void;
 
   30  using Base = DefaultedResultHash<Raw, Projection, ResultHash>;
 
   32  auto operator()(
const Raw& value) 
const noexcept {
 
   33    return Base::operator()(std::invoke(Projection, value));
 
   36  using Base::operator();
 
   39template <
typename Raw, 
auto Projection, 
typename ResultCompare>
 
   40struct Compare : 
public ResultCompare {
 
   41  using is_transparent [[maybe_unused]] = 
void;
 
   43  auto operator()(
const Raw& lhs, 
const Raw& rhs) 
const noexcept {
 
   44    return ResultCompare::operator()(std::invoke(Projection, lhs),
 
   45                                     std::invoke(Projection, rhs));
 
   49  auto operator()(
const Raw& lhs, 
const T& rhs) 
const noexcept {
 
   50    return ResultCompare::operator()(std::invoke(Projection, lhs), rhs);
 
   54  auto operator()(
const T& lhs, 
const Raw& rhs) 
const noexcept {
 
   55    return ResultCompare::operator()(lhs, std::invoke(Projection, rhs));
 
   58  template <
typename T, 
typename U>
 
   59  auto operator()(
const T& lhs, 
const U& rhs) 
const noexcept {
 
   60    return ResultCompare::operator()(lhs, rhs);
 
   64template <
typename Set, 
typename Value>
 
   65void DoInsert(Set& set, Value&& value) {
 
   66  const auto [iter, success] = set.insert(std::forward<Value>(value));
 
   68    using SetValue = std::decay_t<
decltype(*iter)>;
 
   72    const_cast<SetValue&>(*iter) = std::forward<Value>(value);
 
   86template <
typename Value, 
auto Projection, 
typename Hash = 
void,
 
   87          typename Equal = std::equal_to<>,
 
   88          typename Allocator = std::allocator<Value>>
 
   89using ProjectedUnorderedSet = std::unordered_set<
 
   90    Value, impl::projected_set::Hash<Value, Projection, Hash>,
 
   91    impl::projected_set::Compare<Value, Projection, Equal>, Allocator>;
 
   95template <
typename Value, 
auto Projection, 
typename Compare = std::less<>,
 
   96          typename Allocator = std::allocator<Value>>
 
   98    std::set<Value, impl::projected_set::Compare<Value, Projection, Compare>,
 
  103template <
typename Container, 
typename Value>
 
  105  impl::projected_set::DoInsert(set, std::forward<Value>(value));
 
  108namespace impl::projected_set {
 
  114template <
typename V1, 
const auto& P1, 
typename H1, 
typename E1, 
typename A1,
 
  115          typename V2, 
const auto& P2, 
typename H2, 
typename E2, 
typename A2>
 
  116void operator==(
const ProjectedUnorderedSet<V1, P1, H1, E1, A1>& lhs,
 
  117                const ProjectedUnorderedSet<V2, P2, H2, E2, A2>& rhs) = 
delete;
 
  119template <
typename V1, 
const auto& P1, 
typename H1, 
typename E1, 
typename A1,
 
  120          typename V2, 
const auto& P2, 
typename H2, 
typename E2, 
typename A2>
 
  121void operator!=(
const ProjectedUnorderedSet<V1, P1, H1, E1, A1>& lhs,
 
  122                const ProjectedUnorderedSet<V2, P2, H2, E2, A2>& rhs) = 
delete;
 
  124template <
typename V1, 
const auto& P1, 
typename C1, 
typename A1, 
typename V2,
 
  125          const auto& P2, 
typename C2, 
typename A2>
 
  126void operator==(
const ProjectedSet<V1, P1, C1, A1>& lhs,
 
  127                const ProjectedSet<V2, P2, C2, A2>& rhs) = 
delete;
 
  129template <
typename V1, 
const auto& P1, 
typename C1, 
typename A1, 
typename V2,
 
  130          const auto& P2, 
typename C2, 
typename A2>
 
  131void operator!=(
const ProjectedSet<V1, P1, C1, A1>& lhs,
 
  132                const ProjectedSet<V2, P2, C2, A2>& rhs) = 
delete;