Iros
 
Loading...
Searching...
No Matches
owning_node_hash_table.h
Go to the documentation of this file.
1#pragma once
2
13#include "di/meta/core.h"
14#include "di/meta/relation.h"
15#include "di/meta/vocab.h"
17
18namespace di::container {
19template<typename Self, typename T>
21
22template<typename T, typename Tag>
23struct OwningHashNode : HashNode<Tag> {
24public:
25 template<typename... Args>
26 requires(concepts::ConstructibleFrom<T, Args...>)
27 constexpr OwningHashNode(InPlace, Args&&... args) : m_value(util::forward<Args>(args)...) {}
28
29 constexpr auto value() -> T& { return m_value; }
30
31private:
32 T m_value;
33};
34
35template<typename Self, typename T>
36struct OwningHashNodeTag : IntrusiveTagBase<OwningHashNode<T, Self>> {
38
39 constexpr static auto is_sized(auto) -> bool { return false; }
40 constexpr static auto down_cast(auto, auto& node) -> OwningHashNode<T, Self>& {
41 return static_cast<OwningHashNode<T, Self>&>(node);
42 }
43 constexpr static auto down_cast(InPlaceType<T>, Node& node) -> T& { return node.value(); }
44
45 constexpr static void did_remove(auto& self, auto& node) {
46 if constexpr (requires { di::deallocate_one<Node>(self.allocator(), util::addressof(node)); }) {
47 util::destroy_at(util::addressof(node));
48 di::deallocate_one<Node>(self.allocator(), util::addressof(node));
49 }
50 }
51
52 constexpr static auto allow_rehashing_in_insert(auto) -> bool { return true; }
53};
54
55template<typename Value, typename Eq, concepts::Hasher Hasher, typename Buckets, typename Tag,
56 concepts::Allocator Alloc, typename Interface, bool is_multi, bool is_map>
58 : public NodeHashTable<Value, Eq, Hasher, Buckets, Tag, Interface, is_multi, is_map,
59 OwningNodeHashTable<Value, Eq, Hasher, Buckets, Tag, Alloc, Interface, is_multi, is_map>> {
60private:
61 using Base =
62 NodeHashTable<Value, Eq, Hasher, Buckets, Tag, Interface, is_multi, is_map,
64
65 using Node = HashNode<Tag>;
66 using Iterator = HashNodeIterator<Value, Tag>;
67 using ConstIterator = container::ConstIteratorImpl<Iterator>;
68
69 using AllocResult = meta::AllocatorResult<Alloc>;
70
71 template<typename T>
73
74 using InsertResult =
76
77public:
78 using Base::Base;
79
80 constexpr auto allocator() -> Alloc& { return m_allocator; }
81
82 template<typename U, concepts::Invocable F>
83 constexpr auto insert_with_factory(U&& needle, F&& factory) -> InsertResult {
84 if (this->bucket_count() == 0) {
85 if constexpr (concepts::Expected<AllocResult>) {
86 DI_TRY(this->reserve(20));
87 } else {
88 this->reserve(20);
89 }
90 }
91
92 auto const hash = this->hash(needle);
93 auto const bucket_index = hash % this->bucket_count();
94 auto* bucket = &vector::lookup(this->m_buckets, bucket_index);
95
96 auto before_it = bucket->before_begin();
97 while (container::next(before_it) != bucket->end()) {
98 auto&& current = *container::next(before_it);
99 if (this->equal(this->node_value(current), needle)) {
100 break;
101 }
102 ++before_it;
103 }
104 auto it = container::next(before_it);
105
106 auto do_insert = [&] {
107 if constexpr (is_multi) {
108 return true;
109 } else {
110 return it == bucket->end();
111 }
112 }();
113
114 if (do_insert) {
115 if (this->size() + 1 >= this->bucket_count()) {
116 auto new_capacity = 2 * this->bucket_count();
117 if constexpr (concepts::Expected<AllocResult>) {
118 DI_TRY(this->reserve(new_capacity));
119 } else {
120 this->reserve(new_capacity);
121 }
122 }
123 bucket = &vector::lookup(this->m_buckets, bucket_index);
124 before_it = bucket->before_begin();
125 it = container::next(before_it);
126 ++this->m_size;
127 } else if constexpr (!is_multi) {
128 return vocab::Tuple(Iterator { this->m_buckets.span(), bucket_index, before_it }, false);
129 }
130
131 return as_fallible(this->create_node(function::invoke(util::forward<F>(factory)))) % [&](auto* node) {
132 if constexpr (is_multi) {
133 if (it != bucket->end()) {
134 bucket->insert_after(it, *node);
135 Tag::did_insert(this->down_cast_self(), static_cast<Base::ConcreteNode&>(*node));
136 return Iterator { this->m_buckets.span(), bucket_index, it };
137 }
138 bucket->push_front(*node);
139 Tag::did_insert(this->down_cast_self(), static_cast<Base::ConcreteNode&>(*node));
140 return Iterator { this->m_buckets.span(), bucket_index, bucket->before_begin() };
141 } else {
142 if (it == bucket->end()) {
143 bucket->push_front(*node);
144 Tag::did_insert(this->down_cast_self(), static_cast<Base::ConcreteNode&>(*node));
145 return vocab::Tuple(Iterator { this->m_buckets.span(), bucket_index, bucket->before_begin() },
146 true);
147 }
148 return vocab::Tuple(Iterator { this->m_buckets.span(), bucket_index, before_it }, false);
149 }
150 } | try_infallible;
151 }
152
153 template<typename U, concepts::Invocable F>
154 constexpr auto insert_with_factory(ConstIterator, U&& needle, F&& factory) {
155 if constexpr (!is_multi) {
156 return as_fallible(this->insert_with_factory(util::forward<U>(needle), util::forward<F>(factory))) %
157 [](auto&& result) {
158 return util::get<0>(result);
159 } |
161 } else {
162 return this->insert_with_factory(util::forward<U>(needle), util::forward<F>(factory));
163 }
164 }
165
166private:
167 template<typename... Args>
168 requires(concepts::ConstructibleFrom<Value, Args...>)
169 constexpr auto create_node(Args&&... args) {
171 [&](OwningHashNode<Value, Tag>* pointer) {
172 util::construct_at(pointer, in_place, util::forward<Args>(args)...);
173 return static_cast<Node*>(pointer);
174 } |
176 }
177
178 [[no_unique_address]] Alloc m_allocator {};
179};
180}
Definition const_iterator_impl.h:19
Definition hash_node_iterator.h:15
constexpr auto reserve(usize new_capacity) -> decltype(util::declval< Buckets & >().reserve_from_nothing(new_capacity))
Definition node_hash_table.h:221
Definition owning_node_hash_table.h:59
constexpr auto insert_with_factory(U &&needle, F &&factory) -> InsertResult
Definition owning_node_hash_table.h:83
constexpr auto allocator() -> Alloc &
Definition owning_node_hash_table.h:80
constexpr auto insert_with_factory(ConstIterator, U &&needle, F &&factory)
Definition owning_node_hash_table.h:154
Definition allocator.h:9
Definition operations.h:11
Definition vocab.h:30
Definition hasher.h:8
#define DI_TRY(...)
Definition monad_try.h:13
constexpr auto lookup(concepts::detail::ConstantVector auto &vector, size_t index) -> decltype(auto)
Definition vector_lookup.h:10
Definition sequence.h:12
constexpr auto next
Definition next.h:35
constexpr auto equal
Definition equal.h:46
constexpr auto hash
Definition hash.h:21
constexpr auto invoke
Definition invoke.h:100
meta::LikeExpected< decltype(di::allocate(util::declval< Alloc & >(), 0, 0)), T > AllocatorResult
Definition allocator.h:25
Type< detail::LikeExpectedHelper< T, U > > LikeExpected
Definition vocab.h:60
di::meta::Decay< decltype(T)> Tag
Definition tag_invoke.h:28
constexpr auto get(T &&value) -> decltype(auto)
Definition get.h:8
constexpr auto destroy_at
Definition destroy_at.h:24
constexpr auto construct_at
Definition construct_at.h:27
Tuple(Types...) -> Tuple< Types... >
constexpr auto allocate_one
Definition allocate_one.h:29
constexpr auto as_fallible
Definition as_fallible.h:26
constexpr auto try_infallible
Definition try_infallible.h:31
constexpr auto in_place
Definition in_place.h:8
constexpr auto deallocate_one
Definition deallocate_one.h:27
Definition hash_node.h:7
Definition intrusive_tag_base.h:8
Definition owning_node_hash_table.h:36
OwningHashNode< T, Self > Node
Definition owning_node_hash_table.h:37
static constexpr auto down_cast(InPlaceType< T >, Node &node) -> T &
Definition owning_node_hash_table.h:43
static constexpr auto down_cast(auto, auto &node) -> OwningHashNode< T, Self > &
Definition owning_node_hash_table.h:40
static constexpr auto allow_rehashing_in_insert(auto) -> bool
Definition owning_node_hash_table.h:52
static constexpr auto is_sized(auto) -> bool
Definition owning_node_hash_table.h:39
static constexpr void did_remove(auto &self, auto &node)
Definition owning_node_hash_table.h:45
Definition owning_node_hash_table.h:23
constexpr OwningHashNode(InPlace, Args &&... args)
Definition owning_node_hash_table.h:27
constexpr auto value() -> T &
Definition owning_node_hash_table.h:29
Definition in_place_type.h:5
Definition in_place.h:4