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;