"ScL Feature"/
ScL Feature 0.0.1
C++20 composable proxy wrapper with pluggable executor strategy
Loading...
Searching...
No Matches
value_lock.h
1#pragma once
2
3#include <scl/feature/concepts/wrapper.h>
4#include <scl/feature/detail/wrapper_lock.h>
5#include <scl/utility/concepts/reference.h>
6#include <scl/utility/type_traits/forward_like.h>
7
8#include <cassert>
9#include <memory>
10#include <type_traits>
11#include <utility>
12
13namespace scl::feature::detail
14{
15 enum class value_lock_case : bool
16 {
17 value = false,
18 wrapper = true,
19 };
20
21 template <::scl::concepts::reference Refer,
22 value_lock_case Case = ::scl::feature::is_wrapper_v<Refer> ? value_lock_case::wrapper : value_lock_case::value>
23 class value_lock;
24
25 template <::scl::concepts::reference Refer>
26 class value_lock<Refer, value_lock_case::value>
27 {
28 public:
29 value_lock(value_lock &&) = delete;
30 value_lock(value_lock const &) = delete;
31 value_lock & operator=(value_lock &&) = delete;
32 value_lock & operator=(value_lock const &) = delete;
33 ~value_lock() = default;
34
35 constexpr explicit value_lock(Refer ref) noexcept
36 : m_ref{::std::forward<Refer>(ref)}
37 {}
38
39 template <::std::convertible_to<Refer> Target>
40 static constexpr void lock_for() noexcept
41 {}
42
43 template <::std::convertible_to<Refer> Target>
44 [[nodiscard]]
45 constexpr Target value_as() noexcept(::std::is_nothrow_convertible_v<Refer, Target>)
46 {
47 return ::std::forward<Refer>(m_ref);
48 }
49
50 private:
51 Refer m_ref;
52 };
53
54 // NOLINTBEGIN(cppcoreguidelines-pro-type-union-access)
55 template <concepts::wrapper_reference WrapperRefer>
56 class value_lock<WrapperRefer, value_lock_case::wrapper>
57 {
58 using wrapper_type = ::std::remove_cvref_t<WrapperRefer>;
59 using value_type = typename wrapper_type::value_type;
60 using value_refer = ::scl::forward_like_t<WrapperRefer, value_type>;
61
62 using outer_lock_type = ::scl::feature::detail::wrapper_lock<WrapperRefer, wrapper_lock_case::wrapper>;
63 using inner_lock_type = ::scl::feature::detail::value_lock<value_refer,
64 ::scl::feature::is_wrapper_v<value_refer> ? value_lock_case::wrapper : value_lock_case::value>;
65
66 public:
67 value_lock(value_lock &&) = delete;
68 value_lock(value_lock const &) = delete;
69 value_lock & operator=(value_lock &&) = delete;
70 value_lock & operator=(value_lock const &) = delete;
71
72 constexpr explicit value_lock(WrapperRefer ref) /**/
73 noexcept(noexcept(outer_lock_type{::std::declval<WrapperRefer>()}))
74 : m_outer_lock{::std::forward<WrapperRefer>(ref)}
75 {}
76
77 constexpr ~value_lock() /**/
78 noexcept(::std::is_nothrow_destructible_v<inner_lock_type> && ::std::is_nothrow_destructible_v<outer_lock_type>)
79 {
80 if (m_outer_lock.locked())
81 ::std::destroy_at(::std::addressof(m_inner_lock));
82 }
83
84 template <concepts::convertible_from<WrapperRefer> Target>
85 constexpr void lock_for() noexcept(lock_for_noexcept<Target>())
86 {
87 if constexpr (!::std::is_convertible_v<WrapperRefer, Target>)
88 {
89 m_outer_lock.lock();
90 ::std::construct_at(::std::addressof(m_inner_lock), m_outer_lock.value());
91 m_inner_lock.template lock_for<Target>();
92 }
93 }
94
95 template <concepts::convertible_from<WrapperRefer> Target>
96 [[nodiscard]]
97 constexpr Target value_as() noexcept(value_as_noexcept<Target>())
98 {
99 if constexpr (!::std::is_convertible_v<WrapperRefer, Target>)
100 {
101 assert(m_outer_lock.locked() && "value_as<Target>() requires a prior lock_for<Target>()");
102 return m_inner_lock.template value_as<Target>();
103 }
104 else
105 return m_outer_lock.wrapper_value();
106 }
107
108 private:
109 template <typename Target>
110 static constexpr bool lock_for_noexcept() noexcept
111 {
112 if constexpr (::std::is_convertible_v<WrapperRefer, Target>)
113 return true;
114 else
115 return noexcept(::std::declval<outer_lock_type &>().lock()) &&
116 noexcept(::std::declval<outer_lock_type &>().value()) &&
117 noexcept(inner_lock_type{::std::declval<outer_lock_type &>().value()}) &&
118 noexcept(::std::declval<inner_lock_type &>().template lock_for<Target>());
119 }
120
121 template <typename Target>
122 static constexpr bool value_as_noexcept() noexcept
123 {
124 if constexpr (::std::is_convertible_v<WrapperRefer, Target>)
125 return noexcept(::std::declval<outer_lock_type &>().wrapper_value());
126 else
127 return noexcept(::std::declval<inner_lock_type &>().template value_as<Target>());
128 }
129
130 private:
131 outer_lock_type m_outer_lock;
132
133 union
134 {
135 inner_lock_type m_inner_lock;
136 };
137 };
138 // NOLINTEND(cppcoreguidelines-pro-type-union-access)
139
140} // namespace scl::feature::detail
constexpr bool is_wrapper_v
Checks whether Type is a wrapper specialization.
Definition wrapper.h:32