Skip to content

Commit 1e9db5a

Browse files
committed
Make polymorphic container work
1 parent 648af03 commit 1e9db5a

14 files changed

+423
-198
lines changed

include/kangaru/detail/cache.hpp

Lines changed: 99 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,23 @@ namespace kangaru {
2727

2828
template<
2929
source Source,
30-
cache_map Cache = std::unordered_map<std::size_t, std::any>
30+
cache_map Cache = std::unordered_map<std::size_t, std::any>,
31+
template<source> typename CacheFrom = detail::utility::type_identity
3132
>
32-
struct with_cache {
33+
struct with_cache_asymmetric {
3334
using source_type = Source;
3435
using cache_type = Cache;
3536

3637
private:
3738
using unwrapped_cache_type = maybe_wrapped_t<cache_type>;
3839

3940
public:
40-
explicit constexpr with_cache(source_type source) noexcept
41+
explicit constexpr with_cache_asymmetric(source_type source) noexcept
4142
requires (
4243
std::default_initializable<cache_type>
4344
) : source{std::move(source)}, cache{} {}
4445

45-
constexpr with_cache(source_type source, cache_type cache) noexcept :
46+
constexpr with_cache_asymmetric(source_type source, cache_type cache) noexcept :
4647
source{std::move(source)}, cache{std::move(cache)} {}
4748

4849
using key_type = typename unwrapped_cache_type::key_type;
@@ -126,14 +127,14 @@ namespace kangaru {
126127
return KANGARU5_NO_ADL(maybe_unwrap)(cache).erase(key);
127128
}
128129

129-
constexpr auto swap(with_cache& other) noexcept -> void {
130+
constexpr auto swap(with_cache_asymmetric& other) noexcept -> void {
130131
std::ranges::swap(source, other.source);
131132
std::ranges::swap(cache, other.cache);
132133
}
133134

134-
template<forwarded<with_cache> Original, forwarded_source NewSource>
135-
static constexpr auto rebind(Original&& original, NewSource&& new_source) -> with_cache<std::decay_t<NewSource>, source_reference_wrapper<unwrapped_cache_type>> {
136-
return with_cache<std::decay_t<NewSource>, source_reference_wrapper<unwrapped_cache_type>>{
135+
template<forwarded<with_cache_asymmetric> Original, forwarded_source NewSource>
136+
static constexpr auto rebind(Original&& original, NewSource&& new_source) -> with_cache_asymmetric<std::decay_t<NewSource>, source_reference_wrapper<unwrapped_cache_type>, CacheFrom> {
137+
return with_cache_asymmetric<std::decay_t<NewSource>, source_reference_wrapper<unwrapped_cache_type>, CacheFrom>{
137138
KANGARU5_FWD(new_source),
138139
KANGARU5_NO_ADL(ref)(original.cache)
139140
};
@@ -150,15 +151,17 @@ namespace kangaru {
150151
return static_cast<To>(KANGARU5_FWD(any));
151152
}
152153

153-
template<object T, forwarded<with_cache> Self>
154-
requires source_of<detail::utility::forward_like_t<Self, source_type>, T>
154+
template<object T, forwarded<with_cache_asymmetric> Self>
155+
requires source_of<detail::utility::forward_like_t<Self, source_type>, CacheFrom<T>>
155156
friend constexpr auto provide(Self&& source) -> T {
156157
constexpr auto id = detail::ctti::type_id_for<T>();
157158
auto const it = KANGARU5_NO_ADL(maybe_unwrap)(source.cache).find(id);
158159

159160
if (it == KANGARU5_NO_ADL(maybe_unwrap)(source.cache).end()) {
160-
auto object = kangaru::provide<T>(KANGARU5_FWD(source).source);
161-
auto const [it, _] = KANGARU5_NO_ADL(maybe_unwrap)(source.cache).insert(std::pair{id, std::move(object)});
161+
decltype(auto) object = kangaru::provide<CacheFrom<T>>(KANGARU5_FWD(source).source);
162+
auto const [it, _] = KANGARU5_NO_ADL(maybe_unwrap)(source.cache).insert(
163+
std::pair<std::remove_const_t<decltype(id)>, decltype(object)>{id, KANGARU5_FWD(object)}
164+
);
162165
return cast<T>(it->second);
163166
} else {
164167
return cast<T>(it->second);
@@ -168,6 +171,51 @@ namespace kangaru {
168171
cache_type cache;
169172
};
170173

174+
template<template<source> typename CacheFrom, forwarded_source Source, forwarded_cache_map Cache>
175+
constexpr auto make_source_with_cache_asymmetric(Source&& source, Cache&& cache) {
176+
return with_cache_asymmetric<std::decay_t<Source>, std::decay_t<Cache>, CacheFrom>{KANGARU5_FWD(source), KANGARU5_FWD(cache)};
177+
}
178+
179+
template<template<source> typename CacheFrom, forwarded_source Source>
180+
constexpr auto make_source_with_cache_asymmetric(Source&& source) {
181+
return with_cache_asymmetric<std::decay_t<Source>, std::unordered_map<std::size_t, std::any>, CacheFrom>{KANGARU5_FWD(source)};
182+
}
183+
184+
template<
185+
source Source,
186+
cache_map Cache = std::unordered_map<std::size_t, std::any>
187+
>
188+
struct with_cache : with_cache_asymmetric<Source, Cache> {
189+
private:
190+
using parent_t = with_cache_asymmetric<Source, Cache>;
191+
192+
template<source S, cache_map C>
193+
friend struct with_cache;
194+
195+
explicit constexpr with_cache(parent_t&& parent) noexcept : with_cache_asymmetric<Source, Cache>{std::move(parent)} {}
196+
explicit constexpr with_cache(parent_t const& parent) : with_cache_asymmetric<Source, Cache>{parent} {}
197+
198+
public:
199+
explicit constexpr with_cache(Source source) noexcept
200+
requires (
201+
std::default_initializable<Cache>
202+
) : parent_t{std::move(source)} {}
203+
204+
constexpr with_cache(Source source, Cache cache) noexcept :
205+
parent_t{std::move(source), std::move(cache)} {}
206+
207+
template<forwarded<with_cache> Original, forwarded_source NewSource>
208+
static constexpr auto rebind(Original&& original, NewSource&& new_source) -> with_cache<std::decay_t<NewSource>, source_reference_wrapper<maybe_wrapped_t<Cache>>> {
209+
return with_cache<std::decay_t<NewSource>, source_reference_wrapper<maybe_wrapped_t<Cache>>>{parent_t::rebind(static_cast<detail::utility::forward_like_t<Original, parent_t>&&>(original), KANGARU5_FWD(new_source))};
210+
}
211+
212+
template<object T, forwarded<with_cache> Self>
213+
requires source_of<detail::utility::forward_like_t<Self, Source>, T>
214+
friend constexpr auto provide(Self&& source) -> T {
215+
return kangaru::provide<T>(static_cast<detail::utility::forward_like_t<Self, parent_t>&&>(source));
216+
}
217+
};
218+
171219
template<forwarded_source Source, forwarded_cache_map Cache>
172220
constexpr auto make_source_with_cache(Source&& source, Cache&& cache) {
173221
return with_cache<std::decay_t<Source>, std::decay_t<Cache>>{KANGARU5_FWD(source), KANGARU5_FWD(cache)};
@@ -181,6 +229,45 @@ namespace kangaru {
181229
static_assert(cache_map<with_cache<none_source>>);
182230
static_assert(cache_map<source_reference_wrapper<with_cache<with_cache<none_source>>>>);
183231
static_assert(cache_map<with_cache<none_source, source_reference_wrapper<with_cache<none_source>>>>);
232+
233+
template<template<unqualified_object> typename SourceType>
234+
struct cached_pointer_to_source {
235+
template<injectable T>
236+
using source = SourceType<std::remove_cvref_t<T>>*;
237+
};
238+
239+
template<source Source, template<typename> typename SourceFor>
240+
struct with_cache_using_source {
241+
template<injectable T, forwarded<with_cache_using_source> Self>
242+
requires (
243+
is_cachable_v<T>
244+
and not detail::utility::is_specialisation_of_v<SourceFor, T>
245+
and wrapping_source_of<Self, SourceFor<T>>
246+
)
247+
friend constexpr auto provide(Self&& source) -> T {
248+
decltype(auto) source_for_t = kangaru::provide<SourceFor<T>>(KANGARU5_FWD(source).source);
249+
// TODO: Can we avoid this pointer thing?
250+
if constexpr (std::is_pointer_v<decltype(source_for_t)>) {
251+
return kangaru::provide<T>(*KANGARU5_FWD(source_for_t));
252+
} else {
253+
return kangaru::provide<T>(KANGARU5_FWD(source_for_t));
254+
}
255+
}
256+
257+
template<forwarded<with_cache_using_source> Original, forwarded_source NewSource>
258+
static constexpr auto rebind(Original&& original, NewSource&& new_source) -> with_cache_using_source<std::decay_t<NewSource>, SourceFor> {
259+
return with_cache_using_source<std::decay_t<NewSource>, SourceFor>{
260+
KANGARU5_FWD(new_source),
261+
};
262+
}
263+
264+
Source source;
265+
};
266+
267+
template<template<typename> typename SourceFor>
268+
inline constexpr auto make_source_with_cache_using_source(forwarded_source auto&& source) {
269+
return with_cache_using_source<std::decay_t<decltype(source)>, SourceFor>{KANGARU5_FWD(source)};
270+
}
184271
}
185272

186273
#include "undef.hpp"

include/kangaru/detail/cache_types.hpp

Lines changed: 26 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -108,21 +108,14 @@ namespace kangaru {
108108
return map.insert(std::move(value));
109109
}
110110

111-
constexpr auto insert(allows_construction_of<value_type> auto&& value) -> std::pair<iterator, bool> {
112-
if constexpr (requires{ { detail::utility::decay_copy(std::get<1>(value)) } -> kangaru::pointer; }) {
113-
insert_overrides(std::get<1>(value));
114-
}
115-
return map.insert(KANGARU5_FWD(value));
116-
}
117-
118-
template<different_from<void> T>
119-
constexpr auto insert(std::pair<detail::ctti::type_id_for_result<T>, T*> const& value) -> std::pair<iterator, bool> {
111+
template<different_from<void> T, allows_construction_of<T> U>
112+
constexpr auto insert(std::pair<detail::ctti::type_id_for_result<T>, U> const& value) -> std::pair<iterator, bool> {
120113
insert_overrides(value.second);
121114
return map.insert(value);
122115
}
123116

124-
template<different_from<void> T>
125-
constexpr auto insert(std::pair<detail::ctti::type_id_for_result<T>, T*>&& value) -> std::pair<iterator, bool> {
117+
template<different_from<void> T, allows_construction_of<T> U>
118+
constexpr auto insert(std::pair<detail::ctti::type_id_for_result<T>, U>&& value) -> std::pair<iterator, bool> {
126119
insert_overrides(value.second);
127120
return map.insert(value);
128121
}
@@ -135,41 +128,21 @@ namespace kangaru {
135128
return map.insert(hint, std::move(value));
136129
}
137130

138-
constexpr auto insert(const_iterator hint, allows_construction_of<value_type> auto&& value) -> std::pair<iterator, bool> {
139-
if constexpr (requires{ { detail::utility::decay_copy(std::get<1>(value)) } -> kangaru::pointer; }) {
140-
insert_overrides(std::get<1>(value));
141-
}
142-
143-
return map.insert(hint, KANGARU5_FWD(value));
144-
}
145-
146131
template<std::input_iterator Iterator> requires requires(Iterator it) { { *it } -> std::convertible_to<const_reference>; }
147132
constexpr auto insert(Iterator begin, Iterator end) -> void {
148133
map.insert(begin, end);
149134
}
150135

151-
template<different_from<void> T>
152-
constexpr auto insert_or_assign(detail::ctti::type_id_for_result<T> const& k, assign_into<value_type> auto&& obj) {
153-
insert_or_assign_overrides(static_cast<T*>(std::get<1>(KANGARU5_FWD(obj))));
154-
map.insert_or_assign(k, KANGARU5_FWD(obj));
136+
template<different_from<void> T, std::convertible_to<T> U> requires assign_into<U, mapped_type>
137+
constexpr auto insert_or_assign(detail::ctti::type_id_for_result<T> const& k, U&& obj) {
138+
insert_or_assign_overrides(std::get<1>(obj));
139+
map.insert_or_assign(k, static_cast<T>(KANGARU5_FWD(obj)));
155140
}
156141

157-
template<different_from<void> T>
158-
constexpr auto insert_or_assign(detail::ctti::type_id_for_result<T>&& k, assign_into<value_type> auto&& obj) {
159-
insert_or_assign_overrides(static_cast<T*>(std::get<1>(KANGARU5_FWD(obj))));
160-
map.insert_or_assign(std::move(k), KANGARU5_FWD(obj));
161-
}
162-
163-
template<different_from<void> T>
164-
constexpr auto insert_or_assign(const_iterator hint, detail::ctti::type_id_for_result<T> const& k, assign_into<value_type> auto&& obj) {
165-
insert_or_assign_overrides(static_cast<T*>(std::get<1>(KANGARU5_FWD(obj))));
166-
map.insert_or_assign(hint, k, KANGARU5_FWD(obj));
167-
}
168-
169-
template<different_from<void> T>
170-
constexpr auto insert_or_assign(const_iterator hint, detail::ctti::type_id_for_result<T>&& k, assign_into<value_type> auto&& obj) {
171-
insert_or_assign_overrides(static_cast<T*>(std::get<1>(KANGARU5_FWD(obj))));
172-
map.insert_or_assign(hint, std::move(k), KANGARU5_FWD(obj));
142+
template<different_from<void> T, std::convertible_to<T> U> requires assign_into<U, mapped_type>
143+
constexpr auto insert_or_assign(const_iterator hint, detail::ctti::type_id_for_result<T> const& k, U&& obj) {
144+
insert_or_assign_overrides(std::get<1>(obj));
145+
map.insert_or_assign(hint, k, static_cast<T>(KANGARU5_FWD(obj)));
173146
}
174147

175148
constexpr auto erase(iterator pos) -> iterator {
@@ -180,7 +153,7 @@ namespace kangaru {
180153
return map.erase(pos);
181154
}
182155

183-
template<typename T>
156+
template<different_from<void> T>
184157
constexpr auto erase(detail::ctti::type_id_for_result<T> id) -> size_type {
185158
auto const overrides = remove_overrides<T>();
186159
return overrides + map.erase(id);
@@ -241,29 +214,29 @@ namespace kangaru {
241214

242215
private:
243216
template<different_from<void> T>
244-
constexpr auto insert_overrides(T* ptr) -> void {
217+
constexpr auto insert_overrides(T& value) -> void {
245218
using overrides = overrides_types_in_cache_t<T>;
246-
std::apply([this, ptr](auto... s) {
219+
std::apply([this, &value](auto... s) {
247220
[[maybe_unused]]
248-
auto const for_each = [this](auto i, T* ptr) {
221+
auto const for_each = [this](auto i, T& value) {
249222
using override = std::tuple_element_t<i, overrides>;
250-
constexpr auto id = detail::ctti::type_id_for<override*>();
251-
map.insert(std::pair{id, static_cast<override*>(ptr)});
223+
constexpr auto id = detail::ctti::type_id_for<override>();
224+
map.insert(std::pair{id, static_cast<override>(value)});
252225
};
253-
(for_each(s, ptr), ...);
226+
(for_each(s, value), ...);
254227
}, detail::utility::sequence_tuple_for_tuple<overrides>{});
255228
}
256229

257230
template<different_from<void> T>
258-
constexpr auto insert_or_assign_overrides(T* ptr) -> void {
231+
constexpr auto insert_or_assign_overrides(T& value) -> void {
259232
using overrides = overrides_types_in_cache_t<T>;
260-
std::apply([this, ptr](auto... s) {
261-
auto const for_each = [this](auto i, T* ptr) {
233+
std::apply([this, &value](auto... s) {
234+
auto const for_each = [this](auto i, T& value) {
262235
using override = std::tuple_element_t<i, overrides>;
263-
constexpr auto id = detail::ctti::type_id_for<override*>();
264-
map.insert_or_assign(std::pair{id, static_cast<override*>(ptr)});
236+
constexpr auto id = detail::ctti::type_id_for<override>();
237+
map.insert_or_assign(std::pair{id, static_cast<override>(value)});
265238
};
266-
(for_each(s, ptr), ...);
239+
(for_each(s, value), ...);
267240
}, detail::utility::sequence_tuple_for_tuple<overrides>{});
268241
}
269242

@@ -274,7 +247,7 @@ namespace kangaru {
274247
std::apply([this, &n](auto... s) {
275248
auto const for_each = [this, &n](auto i) {
276249
using override = std::tuple_element_t<i, overrides>;
277-
constexpr auto id = detail::ctti::type_id_for<override*>();
250+
constexpr auto id = detail::ctti::type_id_for<override>();
278251
n += map.erase(id);
279252
};
280253
(for_each(s), ...);

include/kangaru/detail/concepts.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ namespace kangaru {
6060
concept explicitly_castable_to = requires(From&& from) {
6161
static_cast<To>(KANGARU5_FWD(from));
6262
};
63+
64+
template<typename From, typename To>
65+
concept safe_convertible_to =
66+
std::convertible_to<From, To>
67+
and (reference<From> or unqualified_object<To>);
6368
}
6469

6570
#include "undef.hpp"

include/kangaru/detail/container.hpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
#include "recursive_source.hpp"
66
#include "cache.hpp"
77
#include "heap_storage.hpp"
8-
#include "source_from_tag.hpp"
98

109
#include <unordered_map>
1110
#include <concepts>
@@ -14,6 +13,9 @@
1413

1514

1615
namespace kangaru {
16+
template<injectable T>
17+
using cached_pointer_to_injectable_reference_source = typename cached_pointer_to_source<injectable_reference_source>::template source<T>;
18+
1719
template<source Source, cache_map Cache = std::unordered_map<std::size_t, void*>, heap_storage Storage = default_heap_storage>
1820
struct dynamic_container {
1921
explicit constexpr dynamic_container(Source source) noexcept :
@@ -24,7 +26,7 @@ namespace kangaru {
2426
std::move(source)
2527
)
2628
),
27-
std::unordered_map<std::size_t, void*>{}
29+
Cache{}
2830
)
2931
} {}
3032

@@ -46,7 +48,7 @@ namespace kangaru {
4648
make_source_with_exhaustive_construction(
4749
with_alternative{
4850
with_recursion{
49-
make_source_with_cache_using<injectable_reference_source>(
51+
make_source_with_cache_using_source<cached_pointer_to_injectable_reference_source>(
5052
KANGARU5_NO_ADL(fwd_ref)(KANGARU5_FWD(source))
5153
)
5254
},

0 commit comments

Comments
 (0)