@@ -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"
0 commit comments