diff --git a/include/kangaru/detail/cache.hpp b/include/kangaru/detail/cache.hpp index 3b61a75..9bb4695 100644 --- a/include/kangaru/detail/cache.hpp +++ b/include/kangaru/detail/cache.hpp @@ -5,14 +5,10 @@ #include "source.hpp" #include "ctti.hpp" #include "concepts.hpp" -#include "allocator.hpp" #include "cache_types.hpp" -#include "source_types.hpp" -#include "heap_storage.hpp" #include #include -#include #include #include "define.hpp" @@ -25,7 +21,11 @@ namespace kangaru { struct with_cache { using source_type = Source; using cache_type = Cache; - + + private: + using unwrapped_cache_type = maybe_wrapped_t; + + public: explicit constexpr with_cache(source_type source) noexcept requires ( std::default_initializable @@ -34,88 +34,88 @@ namespace kangaru { constexpr with_cache(source_type source, cache_type cache) noexcept : source{std::move(source)}, cache{std::move(cache)} {} - using key_type = typename cache_type::key_type; - using value_type = typename cache_type::value_type; - using mapped_type = typename cache_type::mapped_type; - using iterator = typename cache_type::iterator; - using const_iterator = typename cache_type::const_iterator; + using key_type = typename unwrapped_cache_type::key_type; + using value_type = typename unwrapped_cache_type::value_type; + using mapped_type = typename unwrapped_cache_type::mapped_type; + using iterator = typename unwrapped_cache_type::iterator; + using const_iterator = typename unwrapped_cache_type::const_iterator; source_type source; - constexpr auto insert(auto&& value) requires requires(cache_type c) { c.insert(KANGARU5_FWD(value)); } { - return cache.insert(KANGARU5_FWD(value)); + constexpr auto insert(auto&& value) requires requires(unwrapped_cache_type c) { c.insert(KANGARU5_FWD(value)); } { + return kangaru::maybe_unwrap(cache).insert(KANGARU5_FWD(value)); } template - constexpr auto insert(It begin, It end) requires requires(cache_type c) { c.insert(begin, end); } { - return cache.insert(begin, end); + constexpr auto insert(It begin, It end) requires requires(unwrapped_cache_type c) { c.insert(begin, end); } { + return kangaru::maybe_unwrap(cache).insert(begin, end); } [[nodiscard]] - constexpr auto find(auto const& key) requires requires(cache_type c) { c.find(key); } { - return cache.find(key); + constexpr auto find(auto const& key) requires requires(unwrapped_cache_type c) { c.find(key); } { + return kangaru::maybe_unwrap(cache).find(key); } [[nodiscard]] - constexpr auto find(auto const& key) const requires requires(cache_type const c) { c.find(key); } { - return cache.find(key); + constexpr auto find(auto const& key) const requires requires(unwrapped_cache_type const c) { c.find(key); } { + return kangaru::maybe_unwrap(cache).find(key); } [[nodiscard]] - constexpr auto contains(auto const& key) const requires requires(cache_type c) { c.contains(key); } { - return cache.contains(key); + constexpr auto contains(auto const& key) const requires requires(unwrapped_cache_type c) { c.contains(key); } { + return kangaru::maybe_unwrap(cache).contains(key); } [[nodiscard]] - constexpr auto begin() -> typename cache_type::iterator { - return cache.begin(); + constexpr auto begin() -> typename unwrapped_cache_type::iterator { + return kangaru::maybe_unwrap(cache).begin(); } [[nodiscard]] - constexpr auto end() -> typename cache_type::iterator { - return cache.end(); + constexpr auto end() -> typename unwrapped_cache_type::iterator { + return kangaru::maybe_unwrap(cache).end(); } [[nodiscard]] constexpr auto begin() const { - return cache.begin(); + return kangaru::maybe_unwrap(cache).begin(); } [[nodiscard]] constexpr auto end() const { - return cache.end(); + return kangaru::maybe_unwrap(cache).end(); } [[nodiscard]] - constexpr auto cbegin() const -> typename cache_type::const_iterator { - return cache.cbegin(); + constexpr auto cbegin() const -> typename unwrapped_cache_type::const_iterator { + return kangaru::maybe_unwrap(cache).cbegin(); } [[nodiscard]] - constexpr auto cend() const -> typename cache_type::const_iterator { - return cache.cend(); + constexpr auto cend() const -> typename unwrapped_cache_type::const_iterator { + return kangaru::maybe_unwrap(cache).cend(); } [[nodiscard]] constexpr auto empty() const -> bool { - return cache.empty(); + return kangaru::maybe_unwrap(cache).empty(); } constexpr auto clear() -> void { - return cache.clear(); + return kangaru::maybe_unwrap(cache).clear(); } [[nodiscard]] constexpr auto size() const { - return cache.size(); + return kangaru::maybe_unwrap(cache).size(); } [[nodiscard]] - constexpr auto erase(auto const& key) requires requires(cache_type c) { c.erase(key); } { - return cache.erase(key); + constexpr auto erase(auto const& key) requires requires(unwrapped_cache_type c) { c.erase(key); } { + return kangaru::maybe_unwrap(cache).erase(key); } - constexpr auto swap(with_cache other) noexcept -> void { + constexpr auto swap(with_cache& other) noexcept -> void { using std::swap; swap(source, other.source); swap(cache, other.cache); @@ -126,11 +126,11 @@ namespace kangaru { requires source_of, T> friend constexpr auto provide(provide_tag tag, Self&& source) -> T { constexpr auto id = detail::ctti::type_id_for(); - auto const it = source.cache.find(id); + auto const it = kangaru::maybe_unwrap(source.cache).find(id); - if (it == source.cache.end()) { + if (it == kangaru::maybe_unwrap(source.cache).end()) { auto object = provide(tag, KANGARU5_FWD(source).source); - auto const [it, _] = source.cache.insert(std::pair{id, std::move(object)}); + auto const [it, _] = kangaru::maybe_unwrap(source.cache).insert(std::pair{id, std::move(object)}); return static_cast(it->second); } else { return static_cast(it->second); @@ -147,109 +147,8 @@ namespace kangaru { } static_assert(cache_map>); - - template> - struct with_cache_reference_wrapper { - using source_type = source_reference_wrapper_for_t; - using cache_type = with_cache; - - explicit constexpr with_cache_reference_wrapper(with_cache& source) noexcept : - source{ref(source.source)}, cache{std::addressof(source)} {} - - using key_type = typename cache_type::key_type; - using value_type = typename cache_type::value_type; - using mapped_type = typename cache_type::mapped_type; - using iterator = typename cache_type::iterator; - using const_iterator = typename cache_type::const_iterator; - - source_type source; - - constexpr auto insert(auto&& value) const requires requires(cache_type c) { c.insert(KANGARU5_FWD(value)); } { - return cache->insert(KANGARU5_FWD(value)); - } - - template - constexpr auto insert(It begin, It end) const requires requires(cache_type c) { c.insert(begin, end); } { - return cache->insert(begin, end); - } - - [[nodiscard]] - constexpr auto find(auto const& key) const requires requires(cache_type const c) { c.find(key); } { - return cache->find(key); - } - - [[nodiscard]] - constexpr auto contains(auto const& key) const requires requires(cache_type c) { c.contains(key); } { - return cache->contains(key); - } - - [[nodiscard]] - constexpr auto begin() const -> typename cache_type::iterator { - return cache->begin(); - } - - [[nodiscard]] - constexpr auto end() const -> typename cache_type::iterator { - return cache->end(); - } - - [[nodiscard]] - constexpr auto cbegin() const -> typename cache_type::const_iterator { - return cache->cbegin(); - } - - [[nodiscard]] - constexpr auto cend() const -> typename cache_type::const_iterator { - return cache->cend(); - } - - [[nodiscard]] - constexpr auto empty() const -> bool { - return cache->empty(); - } - - constexpr auto clear() const -> void { - return cache->clear(); - } - - [[nodiscard]] - constexpr auto size() const { - return cache->size(); - } - - [[nodiscard]] - constexpr auto erase(auto const& key) const requires requires(cache_type c) { c.erase(key); } { - return cache->erase(key); - } - - constexpr auto swap(with_cache_reference_wrapper other) noexcept -> void { - using std::swap; - swap(source, other.source); - swap(cache, other.cache); - } - - [[nodiscard]] - constexpr auto unwrap() const -> with_cache& { - return *cache; - } - - private: - template Self> - requires source_of, T> - friend constexpr auto provide(provide_tag tag, Self&& source) -> T { - return provide(tag, *source.cache); - } - - cache_type* cache = {}; - }; - - template - struct source_reference_wrapper_for> { - using type = with_cache_reference_wrapper; - }; - - static_assert(cache_map>>); - static_assert(cache_map>>>); + static_assert(cache_map>>>); + static_assert(cache_map>>>); } #include "undef.hpp" diff --git a/include/kangaru/detail/cache_types.hpp b/include/kangaru/detail/cache_types.hpp index 9eef9f7..347a5f9 100644 --- a/include/kangaru/detail/cache_types.hpp +++ b/include/kangaru/detail/cache_types.hpp @@ -8,6 +8,7 @@ #include "ctti.hpp" #include "concepts.hpp" #include "allocator.hpp" +#include "source_types.hpp" #include #include @@ -21,7 +22,7 @@ namespace kangaru { template - concept cache_map = requires(T map, detail::ctti::type_id_for_result id) { + concept non_ref_cache_map = requires(T map, detail::ctti::type_id_for_result id) { { map.begin() } -> std::forward_iterator; { map.end() } -> std::forward_iterator; { std::as_const(map).begin() } -> std::forward_iterator; @@ -43,6 +44,11 @@ namespace kangaru { typename T::const_iterator; }; + template + concept cache_map = non_ref_cache_map or requires { + requires non_ref_cache_map>; + }; + static_assert(cache_map>); template diff --git a/include/kangaru/detail/heap_storage.hpp b/include/kangaru/detail/heap_storage.hpp index da52339..e0ceb58 100644 --- a/include/kangaru/detail/heap_storage.hpp +++ b/include/kangaru/detail/heap_storage.hpp @@ -36,7 +36,7 @@ namespace kangaru { } void* ptr; - dynamic_deleter* deleter; + dynamic_deleter KANGARU5_UNSAFE* deleter; }; template @@ -65,12 +65,28 @@ namespace kangaru { struct basic_heap_storage_base { template static constexpr auto destroyer() { - return [](void* ptr, void* allocator) KANGARU5_CONSTEXPR_VOIDSTAR noexcept { + return [](void* ptr, void* allocator) KANGARU5_UNSAFE KANGARU5_CONSTEXPR_VOIDSTAR noexcept { auto const object_ptr = static_cast(ptr); std::destroy_at(object_ptr); static_cast(allocator)->template deallocate_object(object_ptr); }; } + + template KANGARU5_UNSAFE + constexpr auto construct(Allocator& allocator, F function) -> std::invoke_result_t* { + using object_type = std::invoke_result_t; + + auto const ptr = allocator.template allocate_object(); + + auto provide_as_function_source = function_source{function}; + + std::construct_at( + ptr, + strict_deducer{provide_as_function_source} + ); + + return ptr; + } }; } // namespace detail::heap_storage @@ -100,30 +116,26 @@ namespace kangaru { } KANGARU5_CONSTEXPR_VOIDSTAR ~basic_heap_storage() { - for (auto it = container.rbegin(); it < container.rend(); ++it) { - it->deleter(it->ptr, &allocator); + KANGARU5_UNSAFE_BLOCK { + for (auto it = container.rbegin(); it < container.rend(); ++it) { + it->deleter(it->ptr, &allocator); + } } } template constexpr auto emplace_from(F function) -> std::invoke_result_t* { - using object_type = std::invoke_result_t; - - auto const ptr = allocator.template allocate_object(); - - auto provide_as_function_source = function_source{function}; - - std::construct_at( - ptr, - strict_deducer{provide_as_function_source} - ); - - container.push_back(runtime_dynamic_storage{ - ptr, - basic_heap_storage::template destroyer(), - }); - - return ptr; + KANGARU5_UNSAFE_BLOCK { + auto const ptr = basic_heap_storage::construct(allocator, std::move(function)); + + using object_type = std::invoke_result_t; + container.push_back(runtime_dynamic_storage{ + ptr, + basic_heap_storage::template destroyer(), + }); + + return ptr; + } } private: @@ -136,12 +148,17 @@ namespace kangaru { using default_heap_storage = basic_heap_storage, default_allocator>; template - concept heap_storage = + concept non_ref_heap_storage = std::move_constructible and requires(T storage, int(*function)()) { { storage.emplace_from(function) } -> std::same_as; }; + template + concept heap_storage = non_ref_heap_storage or requires { + requires non_ref_heap_storage>; + }; + static_assert(heap_storage_container>); template @@ -160,13 +177,13 @@ namespace kangaru { template constexpr auto emplace_from(F function) -> std::invoke_result_t* { - return storage.emplace_from(function); + return kangaru::maybe_unwrap(storage).emplace_from(function); } private: template requires source_of friend constexpr auto provide(provide_tag, forwarded auto&& source) -> T* { - return source.storage.emplace_from( + return kangaru::maybe_unwrap(source.storage).emplace_from( [&source] { return provide(provide_tag_v, KANGARU5_FWD(source).source); } @@ -185,42 +202,7 @@ namespace kangaru { static_assert(heap_storage>); static_assert(heap_storage>>); - - template - struct with_heap_storage_reference_wrapper { - using source_type = source_reference_wrapper_for_t; - - explicit constexpr with_heap_storage_reference_wrapper(with_heap_storage& source) noexcept : - source{ref(source.source)}, storage{std::addressof(source)} {} - - template - constexpr auto emplace_from(F function) -> std::invoke_result_t* { - return storage->emplace_from(function); - } - - [[nodiscard]] - constexpr auto unwrap() const noexcept -> with_heap_storage& { - return *storage; - } - - source_type source; - - private: - template requires source_of, T*> - friend constexpr auto provide(provide_tag tag, forwarded auto&& source) -> T* { - return provide(tag, *source.storage); - } - - with_heap_storage* storage; - }; - - template - struct source_reference_wrapper_for> { - using type = with_heap_storage_reference_wrapper; - }; - - static_assert(heap_storage>>); - static_assert(heap_storage>>>); + static_assert(heap_storage>>>); } // namespace kangaru #include "undef.hpp" diff --git a/include/kangaru/detail/recursive_source.hpp b/include/kangaru/detail/recursive_source.hpp index 0275756..8644d66 100644 --- a/include/kangaru/detail/recursive_source.hpp +++ b/include/kangaru/detail/recursive_source.hpp @@ -1,13 +1,13 @@ #ifndef KANGARU5_DETAIL_RECURSIVE_SOURCE_HPP #define KANGARU5_DETAIL_RECURSIVE_SOURCE_HPP -#include "kangaru/detail/source.hpp" #include "utility.hpp" -#include "source_types.hpp" #include "constructor.hpp" #include "injector.hpp" #include "tag.hpp" -#include "noreturn.hpp" +#include "source.hpp" +#include "source_reference_wrapper.hpp" +#include "source_types.hpp" #include #include @@ -119,7 +119,7 @@ namespace kangaru { }; template - requires (source> and callable, construct>) + requires (source> and callable, construct>) constexpr auto operator()(Source&& source) const { return make_injector(KANGARU5_FWD(source))(construct{}); } @@ -208,14 +208,34 @@ namespace kangaru { template typename Branch, kangaru::source Source> struct rebind_wrapper> { - template - using ttype = Branch; + template requires requires { typename Branch; } + struct ttype { + using type = Branch; + }; }; template typename Branch, kangaru::source Source, typename State> struct rebind_wrapper> { - template - using ttype = Branch; + template requires requires { typename Branch; } + struct ttype { + using type = Branch; + }; + }; + + template typename Branch, kangaru::source Source> + struct rebind_wrapper const> { + template requires requires { typename Branch; } + struct ttype { + using type = Branch; + }; + }; + + template typename Branch, kangaru::source Source, typename State> + struct rebind_wrapper const> { + template requires requires { typename Branch; } + struct ttype { + using type = Branch; + }; }; } @@ -225,13 +245,13 @@ namespace kangaru { and not reference_wrapper and wrapping_source and requires(Source source) { - typename std::type_identity< + typename std::type_identity_t< typename detail::recursive_source::rebind_wrapper::template ttype< std::decay_t - > - >::type; + >::type + >; requires std::constructible_from< - typename detail::recursive_source::rebind_wrapper::template ttype>, + typename detail::recursive_source::rebind_wrapper::template ttype>::type, std::decay_t >; }; @@ -242,19 +262,19 @@ namespace kangaru { and not reference_wrapper and rebindable_wrapping_source and requires(Source source) { - typename std::type_identity< + typename std::type_identity_t< typename detail::recursive_source::rebind_wrapper::template ttype< - std::decay_t, - decltype(ref(source)) - > - >::type; + std::decay_t, + decltype(kangaru::ref(source)) + >::type + >; requires std::constructible_from< typename detail::recursive_source::rebind_wrapper::template ttype< std::decay_t, - decltype(ref(source)) - >, + decltype(kangaru::ref(source)) + >::type, std::decay_t, - decltype(ref(source)) + decltype(kangaru::ref(source)) >; }; @@ -265,7 +285,7 @@ namespace kangaru { Source source; private: - template requires (not rebindable_wrapping_source> and not reference_wrapper>) + template constexpr static auto rebind_source_tree_for(forwarded auto&& self, Leaf&) noexcept -> auto { if constexpr (source_of and reference_wrapper) { return self.source; @@ -278,29 +298,29 @@ namespace kangaru { } } - template requires rebindable_wrapping_source> + template constexpr static auto rebind_source_tree_for(forwarded auto&& self, Wrapper& source) noexcept -> auto { - using rebound = typename detail::recursive_source::rebind_wrapper>::template ttype< + using rebound = typename detail::recursive_source::rebind_wrapper::template ttype< decltype(rebind_source_tree_for(KANGARU5_FWD(self), source.source)) - >; + >::type; return rebound{ rebind_source_tree_for(KANGARU5_FWD(self), source.source) }; } - template requires stateful_rebindable_wrapping_source> + template constexpr static auto rebind_source_tree_for(forwarded auto&& self, Wrapper& source) noexcept -> auto { - using rebound = typename detail::recursive_source::rebind_wrapper>::template ttype< + using rebound = typename detail::recursive_source::rebind_wrapper::template ttype< decltype(rebind_source_tree_for(KANGARU5_FWD(self), source.source)), decltype(kangaru::ref(source)) - >; + >::type; return rebound{ rebind_source_tree_for(KANGARU5_FWD(self), source.source), kangaru::ref(source), }; } - template requires reference_wrapper + template constexpr auto rebind_source_tree_for(forwarded auto&& self, Wrapper wrapper) -> auto { return rebind_source_tree_for(KANGARU5_FWD(self), wrapper.unwrap()); } @@ -320,15 +340,24 @@ namespace kangaru { } }; - template + template requires (source>) + inline constexpr auto make_source_with_recursion(Source&& source) { + return with_recursion>{KANGARU5_FWD(source)}; + } + + template struct with_construction { + private: + using construction_type = maybe_wrapped_t; + + public: explicit constexpr with_construction(Source source) noexcept - requires std::default_initializable : + requires std::default_initializable : source{std::move(source)} {} - constexpr with_construction(Source source, Construct construct) noexcept : + constexpr with_construction(Source source, Construction construction) noexcept : source{std::move(source)}, - construct{std::move(construct)} {} + construction{std::move(construction)} {} template Self> requires wrapping_source_of friend constexpr auto provide(provide_tag, Self&& source) -> T { @@ -336,32 +365,41 @@ namespace kangaru { } template Self> - requires (callable_template1> and not wrapping_source_of) + requires (callable_template1> and not wrapping_source_of) friend constexpr auto provide(provide_tag, Self&& source) -> T { - return source.construct.template operator()(KANGARU5_FWD(source).source); + return std::as_const(source.construction).template operator()(kangaru::fwd_ref(KANGARU5_FWD(source).source)); } Source source; private: - Construct construct; + Construction construction; }; - template requires (source> and movable_object>) + template requires (source> and construction>) inline constexpr auto make_source_with_construction(Source&& source, Construct&& construct) { return with_construction, std::remove_cvref_t>{KANGARU5_FWD(source), KANGARU5_FWD(construct)}; } + template + using with_non_empty_construction = with_construction; + template requires source> inline constexpr auto make_source_with_non_empty_construction(Source&& source) { return with_construction, non_empty_construction>{KANGARU5_FWD(source), non_empty_construction{}}; } + template + using with_exhaustive_construction = with_construction; + template requires source> inline constexpr auto make_source_with_exhaustive_construction(Source&& source) { return with_construction, exhaustive_construction>{KANGARU5_FWD(source), exhaustive_construction{}}; } + template + using with_unsafe_exhaustive_construction = with_construction; + template requires source> inline constexpr auto make_source_with_unsafe_exhaustive_construction(Source&& source) { return with_construction, unsafe_exhaustive_construction>{KANGARU5_FWD(source), unsafe_exhaustive_construction{}}; diff --git a/include/kangaru/detail/source_from_tag.hpp b/include/kangaru/detail/source_from_tag.hpp index 36d3417..59d0019 100644 --- a/include/kangaru/detail/source_from_tag.hpp +++ b/include/kangaru/detail/source_from_tag.hpp @@ -27,6 +27,11 @@ namespace kangaru { Source source; }; + + template requires source> + inline constexpr auto make_source_with_source_from_tag(Source&& source) { + return with_source_from_tag>{KANGARU5_FWD(source)}; + } } #include "undef.hpp" diff --git a/include/kangaru/detail/source_reference_wrapper.hpp b/include/kangaru/detail/source_reference_wrapper.hpp new file mode 100644 index 0000000..160e49a --- /dev/null +++ b/include/kangaru/detail/source_reference_wrapper.hpp @@ -0,0 +1,83 @@ +#ifndef KANGARU5_DETAIL_SOURCE_REFERENCE_WRAPPER_HPP +#define KANGARU5_DETAIL_SOURCE_REFERENCE_WRAPPER_HPP + +#include "source.hpp" +#include "concepts.hpp" + +#include + +#include "define.hpp" + +namespace kangaru { + template requires source> + struct source_reference_wrapper { + explicit constexpr source_reference_wrapper(Source& source) noexcept : source{std::addressof(source)} {} + + template + friend constexpr auto provide(provide_tag, source_reference_wrapper const& source) -> T + requires source_of { + return provide(provide_tag_v, *source.source); + } + + [[nodiscard]] + constexpr auto unwrap() const noexcept -> Source& { + return *source; + } + + private: + Source* source; + }; + + template requires source> + struct source_forwarding_reference_wrapper { + explicit constexpr source_forwarding_reference_wrapper(Source source) noexcept : source{std::addressof(source)} {} + + template + friend constexpr auto provide(provide_tag, source_forwarding_reference_wrapper const& source) -> T + requires source_of { + return provide(provide_tag_v, detail::utility::forward_like(*source.source)); + } + + [[nodiscard]] + constexpr auto unwrap() const& noexcept -> Source { + return detail::utility::forward_like(*source); + } + + private: + std::remove_reference_t* source; + }; + + template + concept reference_wrapper = source and requires(T ref) { + { ref.unwrap() } -> reference; + }; + + template requires reference_wrapper> + inline constexpr auto maybe_unwrap(T&& ref) noexcept -> decltype(auto) { + return KANGARU5_FWD(ref).unwrap(); + } + + inline constexpr auto maybe_unwrap(auto&& any) -> decltype(any) { + return KANGARU5_FWD(any); + } + + template + using source_reference_wrapped_type = std::remove_reference_t().unwrap())>; + + template + using maybe_wrapped_t = std::remove_reference_t()))>; + + template requires source> + inline constexpr auto ref(Source& source) -> source_reference_wrapper { + return source_reference_wrapper{source}; + } + + template requires source> + inline constexpr auto fwd_ref(Source&& source) -> source_forwarding_reference_wrapper { + return source_forwarding_reference_wrapper{KANGARU5_FWD(source)}; + } +} // namespace kangaru + +#include "undef.hpp" + +#endif // KANGARU5_DETAIL_SOURCE_REFERENCE_WRAPPER_HPP diff --git a/include/kangaru/detail/source_types.hpp b/include/kangaru/detail/source_types.hpp index c17100b..cef117e 100644 --- a/include/kangaru/detail/source_types.hpp +++ b/include/kangaru/detail/source_types.hpp @@ -6,6 +6,7 @@ #include "concepts.hpp" #include "utility.hpp" #include "constructor.hpp" +#include "source_reference_wrapper.hpp" #include #include @@ -253,44 +254,6 @@ namespace kangaru { return with_filter_passthrough, T>{KANGARU5_FWD(source)}; } - template - struct source_reference_wrapper { - constexpr source_reference_wrapper(Source& source) noexcept : source{std::addressof(source)} {} - - template - friend constexpr auto provide(provide_tag, source_reference_wrapper const& source) -> T - requires source_of { - return provide(provide_tag_v, *source.source); - } - - [[nodiscard]] - constexpr auto unwrap() const noexcept -> Source& { - return *source; - } - - private: - Source* source; - }; - - template - struct source_const_reference_wrapper { - constexpr source_const_reference_wrapper(Source const& source) noexcept : source{std::addressof(source)} {} - constexpr source_const_reference_wrapper(source_reference_wrapper const& source) noexcept : source{source.unwrap()} {} - - template requires source_of - friend constexpr auto provide(provide_tag, source_const_reference_wrapper const& source) -> T { - return provide(provide_tag_v, *source.source); - } - - [[nodiscard]] - constexpr auto unwrap() const noexcept -> Source const& { - return *source; - } - - private: - Source const* source; - }; - template struct filter_source { constexpr filter_source(Source source) noexcept : source{std::move(source)} {} @@ -327,42 +290,6 @@ namespace kangaru { return filter_if_source, Filter>{KANGARU5_FWD(source)}; } - template - struct source_reference_wrapper_for { - using type = source_reference_wrapper; - }; - - template - struct source_reference_wrapper_for { - using type = source_const_reference_wrapper; - }; - - template - using source_reference_wrapper_for_t = typename source_reference_wrapper_for::type; - - template - concept reference_wrapper = source and requires(T ref) { - { ref.unwrap() } -> reference; - }; - - template - concept reference_wrapper_for = requires(Wrapper const& ref) { - { ref.unwrap() } -> std::same_as; - }; - - template - using source_reference_wrapped_type = std::remove_reference_t().unwrap())>; - - template requires source> - inline constexpr auto ref(Source& source) -> source_reference_wrapper_for_t { - static_assert(reference_wrapper_for, Source>); - return source_reference_wrapper_for_t{source}; - } - - inline constexpr auto tie(source auto&... sources) { - return kangaru::concat(kangaru::ref(sources)...); - } - template struct with_reference_passthrough { explicit constexpr with_reference_passthrough(Source source) noexcept : source{std::move(source)} {} @@ -376,7 +303,7 @@ namespace kangaru { } template Self> - requires source_of().source)>, T> + requires wrapping_source_of friend constexpr auto provide(provide_tag tag, Self&& source) -> T { return provide(tag, KANGARU5_FWD(source).source.source); } @@ -413,7 +340,7 @@ namespace kangaru { struct basic_wrapping_source { template Self> requires source_of, T> friend constexpr auto provide(provide_tag, Self&& source) -> T { - return provide(provide_tag_v, std::forward(source).source); + return provide(provide_tag_v, KANGARU5_FWD(source).source); } Source source; @@ -423,6 +350,10 @@ namespace kangaru { constexpr auto wrap_source(Source&& source) { return basic_wrapping_source>{KANGARU5_FWD(source)}; } + + inline constexpr auto tie(source auto&... sources) { + return kangaru::concat(kangaru::ref(sources)...); + } } #include "undef.hpp" diff --git a/include/kangaru/detail/utility.hpp b/include/kangaru/detail/utility.hpp index abaa134..4da0532 100644 --- a/include/kangaru/detail/utility.hpp +++ b/include/kangaru/detail/utility.hpp @@ -68,7 +68,9 @@ namespace kangaru::detail::utility { template typename Template> struct template_type_identity { template - using ttype = Template; + struct ttype { + using type = Template; + }; }; } diff --git a/tests/src/5-reference-deducer.cpp b/tests/src/5-reference-deducer.cpp index 79eba3b..0d82028 100644 --- a/tests/src/5-reference-deducer.cpp +++ b/tests/src/5-reference-deducer.cpp @@ -11,7 +11,7 @@ TEST_CASE("Deducer can deduce reference types", "[deducer]") { by_lvalue_const_reference, by_rvalue_const_reference }; - + struct sneezy { how_t how; }; diff --git a/tests/src/5-runtime-source.cpp b/tests/src/5-runtime-source.cpp index eeeb71b..74efdd7 100644 --- a/tests/src/5-runtime-source.cpp +++ b/tests/src/5-runtime-source.cpp @@ -1,6 +1,7 @@ #include "kangaru/detail/deducer.hpp" #include "kangaru/detail/recursive_source.hpp" #include "kangaru/detail/source.hpp" +#include "kangaru/detail/source_from_tag.hpp" #include "kangaru/detail/source_types.hpp" #include #include @@ -61,6 +62,17 @@ struct service_b { friend auto tag(kangaru::tag_for) -> kangaru::cache_using_source_type; }; +struct service_aggregate { + service_a& sa; + service_b& sb; +}; + +struct service_c { + service_aggregate services; + + friend auto tag(kangaru::tag_for) -> kangaru::cache_using_source_type; +}; + TEST_CASE("Runtime source will cache sources results", "[deducer]") { SECTION("Will cache the result of sources") { auto runtime_source = kangaru::with_cache>{kangaru::with_heap_storage{kangaru::ref(source)}}; @@ -124,10 +136,10 @@ TEST_CASE("Runtime source will cache sources results", "[deducer]") { ) ) }; - + CHECK(kangaru::provide(kangaru::provide_tag_v, source).ref == 0); } - + SECTION("Support the service idiom and cache and construction") { auto source = kangaru::with_recursion{ kangaru::with_source_from_tag{ @@ -148,4 +160,36 @@ TEST_CASE("Runtime source will cache sources results", "[deducer]") { service_b& rb = kangaru::provide(kangaru::provide_tag_v, source); CHECK(std::addressof(ra) == std::addressof(rb.a)); } + + SECTION("Support the service idiom and cache and construction, with recursive construction on top") { + auto source = kangaru::with_recursion{ + kangaru::make_source_with_exhaustive_construction( + kangaru::with_recursion{ + kangaru::with_source_from_tag{ + kangaru::with_cache{ + kangaru::with_heap_storage{ + kangaru::make_source_with_exhaustive_construction( + increment_source{.n = 3} // just a source of int + ) + } + } + } + } + ) + }; + + CHECK(kangaru::provide(kangaru::provide_tag_v, source).a == 3); + + service_a& ra = kangaru::provide(kangaru::provide_tag_v, source); + service_b& rb = kangaru::provide(kangaru::provide_tag_v, source); + CHECK(std::addressof(ra) == std::addressof(rb.a)); + + auto c = kangaru::provide(kangaru::provide_tag_v, source); + CHECK(std::addressof(ra) == std::addressof(c.sa)); + CHECK(std::addressof(rb) == std::addressof(c.sb)); + + service_c& rc = kangaru::provide(kangaru::provide_tag_v, source); + CHECK(std::addressof(ra) == std::addressof(rc.services.sa)); + CHECK(std::addressof(rb) == std::addressof(rc.services.sb)); + } }