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, success] = set.insert(std::forward<Value>(value));
67 using SetValue = std::decay_t<
decltype(*iter)>;
71 const_cast<SetValue&>(*iter) = std::forward<Value>(value);
76using HasHasher =
typename T::hasher;
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 if constexpr (meta::kIsDetected<impl::projected_set::HasHasher, std::decay_t<Container>>) {
124 return utils::impl::FindTransparent(set, key);
126 return set.find(key);
138template <
typename Value>
139class MutableWrapper {
141 template <
typename... Args>
142 MutableWrapper(Args&&... args) : value_(std::forward<Args>(args)...) {}
144 Value& operator*()
const {
return value_; }
145 Value* operator->()
const {
return std::addressof(value_); }
148 mutable Value value_;
151template <
typename Container,
typename Key>
152auto ProjectedFindOrNullptrUnsafe(Container& set,
const Key& key) {
153 auto iter =
utils::ProjectedFind(set, key);
154 if constexpr (std::is_const_v<Container>) {
155 return iter == set.end() ?
nullptr : std::addressof(std::as_const(**iter));
157 return iter == set.end() ?
nullptr : std::addressof(**iter);
164namespace impl::projected_set {
182 const ProjectedUnorderedSet<V1, P1, H1, E1, A1>& lhs,
183 const ProjectedUnorderedSet<V2, P2, H2, E2, A2>& rhs
198 const ProjectedUnorderedSet<V1, P1, H1, E1, A1>& lhs,
199 const ProjectedUnorderedSet<V2, P2, H2, E2, A2>& rhs
202template <
typename V1,
const auto& P1,
typename C1,
typename A1,
typename V2,
const auto& P2,
typename C2,
typename A2>
203void operator==(
const ProjectedSet<V1, P1, C1, A1>& lhs,
const ProjectedSet<V2, P2, C2, A2>& rhs) =
delete;
205template <
typename V1,
const auto& P1,
typename C1,
typename A1,
typename V2,
const auto& P2,
typename C2,
typename A2>
206void operator!=(
const ProjectedSet<V1, P1, C1, A1>& lhs,
const ProjectedSet<V2, P2, C2, A2>& rhs) =
delete;