9#include <unordered_set>
12#include <userver/utils/impl/projecting_view.hpp>
13#include <userver/utils/impl/transparent_hash.hpp>
14#include <userver/utils/meta_light.hpp>
16USERVER_NAMESPACE_BEGIN
20namespace impl::projected_set {
22template <
typename Raw,
auto Projection>
23using ProjectionResult = std::decay_t<std::invoke_result_t<
decltype(Projection),
const Raw&>>;
25template <
typename Raw,
auto Projection,
typename ResultHash>
26using DefaultedResultHash =
27 std::conditional_t<std::is_void_v<ResultHash>, std::hash<ProjectionResult<Raw, Projection>>, ResultHash>;
29template <
typename Raw,
auto Projection,
typename ResultHash>
30struct Hash :
public DefaultedResultHash<Raw, Projection, ResultHash> {
31 using is_transparent [[maybe_unused]] =
void;
32 using Base = DefaultedResultHash<Raw, Projection, ResultHash>;
34 auto operator()(
const Raw& value)
const noexcept {
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), std::invoke(Projection, rhs));
48 auto operator()(
const Raw& lhs,
const T& rhs)
const noexcept {
49 return ResultCompare::operator()(std::invoke(Projection, lhs), rhs);
53 auto operator()(
const T& lhs,
const Raw& rhs)
const noexcept {
54 return ResultCompare::operator()(lhs, std::invoke(Projection, rhs));
57 template <
typename T,
typename U>
58 auto operator()(
const T& lhs,
const U& rhs)
const noexcept {
59 return ResultCompare::operator()(lhs, rhs);
63template <
typename Set,
typename Value>
64void DoInsert(Set& set, Value&& value) {
65 const auto iter = set.find(value);
66 if (iter == set.end()) {
67 set.insert(set.end(), std::forward<Value>(value));
71 using SetValue = std::decay_t<
decltype(*iter)>;
75 const_cast<SetValue&>(*iter) = std::forward<Value>(value);
95 typename Equal = std::equal_to<>,
96 typename Allocator = std::allocator<Value>>
97using ProjectedUnorderedSet =
utils::impl::TransparentSet<
99 impl::projected_set::Hash<Value, Projection, Hash>,
100 impl::projected_set::Compare<Value, Projection, Equal>,
105template <
typename Value,
auto Projection,
typename Compare = std::less<>,
typename Allocator = std::allocator<Value>>
106using ProjectedSet = std::set<Value, impl::projected_set::Compare<Value, Projection, Compare>, Allocator>;
110template <
typename Container,
typename Value>
112 impl::projected_set::DoInsert(set, std::forward<Value>(value));
121template <
typename Container,
typename Key>
123 return set.find(key);
134template <
typename Value>
135class MutableWrapper {
137 template <
typename... Args>
138 MutableWrapper(Args&&... args)
139 : value_(std::forward<Args>(args)...)
142 Value& operator*()
const {
return value_; }
143 Value* operator->()
const {
return std::addressof(value_); }
146 mutable Value value_;
149template <
typename Container,
typename Key>
150auto ProjectedFindOrNullptrUnsafe(Container& set,
const Key& key) {
151 auto iter =
utils::ProjectedFind(set, key);
152 if constexpr (std::is_const_v<Container>) {
153 return iter == set.end() ?
nullptr : std::addressof(std::as_const(**iter));
155 return iter == set.end() ?
nullptr : std::addressof(**iter);
162namespace impl::projected_set {
180 const ProjectedUnorderedSet<V1, P1, H1, E1, A1>& lhs,
181 const ProjectedUnorderedSet<V2, P2, H2, E2, A2>& rhs
196 const ProjectedUnorderedSet<V1, P1, H1, E1, A1>& lhs,
197 const ProjectedUnorderedSet<V2, P2, H2, E2, A2>& rhs
200template <
typename V1,
const auto& P1,
typename C1,
typename A1,
typename V2,
const auto& P2,
typename C2,
typename A2>
201void operator==(
const ProjectedSet<V1, P1, C1, A1>& lhs,
const ProjectedSet<V2, P2, C2, A2>& rhs) =
delete;
203template <
typename V1,
const auto& P1,
typename C1,
typename A1,
typename V2,
const auto& P2,
typename C2,
typename A2>
204void operator!=(
const ProjectedSet<V1, P1, C1, A1>& lhs,
const ProjectedSet<V2, P2, C2, A2>& rhs) =
delete;