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);
79using HasHasher =
typename T::hasher;
98 typename Equal = std::equal_to<>,
99 typename Allocator = std::allocator<Value>>
100using ProjectedUnorderedSet =
utils::impl::TransparentSet<
102 impl::projected_set::Hash<Value, Projection, Hash>,
103 impl::projected_set::Compare<Value, Projection, Equal>,
108template <
typename Value,
auto Projection,
typename Compare = std::less<>,
typename Allocator = std::allocator<Value>>
109using ProjectedSet = std::set<Value, impl::projected_set::Compare<Value, Projection, Compare>, Allocator>;
113template <
typename Container,
typename Value>
115 impl::projected_set::DoInsert(set, std::forward<Value>(value));
124template <
typename Container,
typename Key>
126 if constexpr (meta::IsDetected<impl::projected_set::HasHasher, std::decay_t<Container>>) {
127 return utils::impl::FindTransparent(set, key);
129 return set.find(key);
141template <
typename Value>
142class MutableWrapper {
144 template <
typename... Args>
145 MutableWrapper(Args&&... args)
146 : value_(std::forward<Args>(args)...)
149 Value& operator*()
const {
return value_; }
150 Value* operator->()
const {
return std::addressof(value_); }
153 mutable Value value_;
156template <
typename Container,
typename Key>
157auto ProjectedFindOrNullptrUnsafe(Container& set,
const Key& key) {
158 auto iter =
utils::ProjectedFind(set, key);
159 if constexpr (std::is_const_v<Container>) {
160 return iter == set.end() ?
nullptr : std::addressof(std::as_const(**iter));
162 return iter == set.end() ?
nullptr : std::addressof(**iter);
169namespace impl::projected_set {
187 const ProjectedUnorderedSet<V1, P1, H1, E1, A1>& lhs,
188 const ProjectedUnorderedSet<V2, P2, H2, E2, A2>& rhs
203 const ProjectedUnorderedSet<V1, P1, H1, E1, A1>& lhs,
204 const ProjectedUnorderedSet<V2, P2, H2, E2, A2>& rhs
207template <
typename V1,
const auto& P1,
typename C1,
typename A1,
typename V2,
const auto& P2,
typename C2,
typename A2>
208void operator==(
const ProjectedSet<V1, P1, C1, A1>& lhs,
const ProjectedSet<V2, P2, C2, A2>& rhs) =
delete;
210template <
typename V1,
const auto& P1,
typename C1,
typename A1,
typename V2,
const auto& P2,
typename C2,
typename A2>
211void operator!=(
const ProjectedSet<V1, P1, C1, A1>& lhs,
const ProjectedSet<V2, P2, C2, A2>& rhs) =
delete;