vari
Loading...
Searching...
No Matches
val_core.h
1
23
24#pragma once
25
26#include "../concept.h"
27#include "./dispatch.h"
28#include "./util.h"
29#include "./val_union.h"
30
31#include <compare>
32#include <memory>
33
34namespace vari
35{
36
37template < typename TL >
38struct _val_core
39{
40 using ST = _val_union< TL >;
41
42 index_type index = null_index;
43 ST storage;
44
45 constexpr _val_core() noexcept = default;
46
47 constexpr _val_core( _val_core const& other ) noexcept(
48 all_nothrow_copy_constructible_v< TL > )
49 {
50 _copy_or_move_construct< false, TL >( *this, other );
51 }
52
53 template < typename UL >
54 requires( vconvertible_to< UL, TL > )
55 constexpr _val_core( _val_core< UL > const& other ) noexcept(
56 all_nothrow_copy_constructible_v< UL > )
57 {
58 _copy_or_move_construct< false, UL >( *this, other );
59 }
60
61 constexpr _val_core( _val_core&& other ) noexcept( all_nothrow_move_constructible_v< TL > )
62 {
63 _copy_or_move_construct< true, TL >( *this, other );
64 }
65
66 template < typename UL >
67 requires( vconvertible_to< UL, TL > )
68 constexpr _val_core( _val_core< UL >&& other ) noexcept(
69 all_nothrow_move_constructible_v< UL > )
70 {
71 _copy_or_move_construct< true, UL >( *this, other );
72 }
73
74 template < bool IS_MOVE, typename UL >
75 static constexpr void _copy_or_move_construct( auto& self, auto& other ) noexcept(
76 IS_MOVE ? all_nothrow_move_constructible_v< UL > :
77 all_nothrow_copy_constructible_v< UL > )
78 {
79 if ( other.index == null_index )
80 return;
81 _dispatch_index< 0, UL::size >(
82 other.index, [&]< index_type j >() -> decltype( auto ) {
83 static constexpr index_type i = _vptr_cnv_map< TL, UL >::conv( j );
84 using OST = typename _val_core< UL >::ST;
85
86 self.index = i;
87 if constexpr ( IS_MOVE )
88 std::construct_at(
89 &ST::template get< i >( self.storage ),
90 std::move( OST::template get< j >( other.storage ) ) );
91 else
92 std::construct_at(
93 &ST::template get< i >( self.storage ),
94 OST::template get< j >( other.storage ) );
95 } );
96 }
97
98 template < typename O >
99 static constexpr bool is_nothrow_assignable =
100 noexcept( _val_core{ std::declval< O >() } ) &&
101 std::is_nothrow_swappable_v< _val_core >;
102
103 template < typename O >
104 constexpr void assign( O&& other ) noexcept( is_nothrow_assignable< O > )
105 {
106 _val_core tmp{ (O&&) other };
107 swap( *this, tmp );
108 }
109
110 friend constexpr void swap( _val_core& lh, _val_core& rh ) noexcept(
111 all_nothrow_swappable_v< TL > && all_nothrow_move_constructible_v< TL > &&
112 all_nothrow_destructible_v< TL > )
113 {
114 if ( lh.index == rh.index )
115 return _dispatch_index< 0, TL::size >(
116 lh.index, [&]< index_type j >() -> decltype( auto ) {
117 auto& l = ST::template get< j >( lh.storage );
118 auto& r = ST::template get< j >( rh.storage );
119 using namespace std;
120 swap( l, r );
121 } );
122
123 _val_core tmp{ std::move( lh ) };
124 if ( lh.index != null_index )
125 lh.destroy();
126
127 if ( rh.index != null_index )
128 move_from_to( rh, lh );
129
130 if ( tmp.index != null_index )
131 move_from_to( tmp, rh );
132 }
133
134 friend constexpr void move_from_to( _val_core& lh, _val_core& rh ) noexcept(
135 all_nothrow_move_constructible_v< TL > && all_nothrow_destructible_v< TL > )
136 {
137 _dispatch_index< 0, TL::size >(
138 lh.index, [&]< index_type j >() -> decltype( auto ) {
139 auto& l = ST::template get< j >( lh.storage );
140 auto& r = ST::template get< j >( rh.storage );
141 std::construct_at( &r, std::move( l ) );
142 rh.index = lh.index;
143 std::destroy_at( &l );
144 } );
145 }
146
147
148 template < typename... Fs >
149 static constexpr decltype( auto ) visit_impl( auto& self, Fs&&... fs )
150 {
151 return _dispatch_index< 0, TL::size >(
152 self.index, [&]< index_type j >() -> decltype( auto ) {
153 auto& p = ST::template get< j >( self.storage );
154 return _dispatch_fun( p, (Fs&&) fs... );
155 } );
156 }
157
158 template < typename F >
159 static constexpr decltype( auto ) visit_impl( auto& self, F&& f )
160 {
161 return _dispatch_index< 0, TL::size >(
162 self.index, [&]< index_type j >() -> decltype( auto ) {
163 auto& p = ST::template get< j >( self.storage );
164
165 return ( (F&&) f )( p );
166 } );
167 }
168
169 template < typename T, typename... Args >
170 constexpr auto&
171 emplace( Args&&... args ) noexcept( std::is_nothrow_constructible_v< T, Args... > )
172 {
173 constexpr index_type i = index_of_t_or_const_t_v< T, TL >;
174
175 index = i;
176 return *std::construct_at( &ST::template get< i >( storage ), (Args&&) args... );
177 }
178
179 constexpr void destroy() noexcept( all_nothrow_destructible_v< TL > )
180 {
181 _dispatch_index< 0, TL::size >( index, [&]< index_type j > {
182 std::destroy_at( &ST::template get< j >( storage ) );
183 } );
184 index = null_index;
185 }
186
187 // XXX: this needs serious tests
188 // XXX: derive the ordering!
189 static constexpr std::partial_ordering three_way_compare(
190 _val_core const& lh,
191 _val_core const& rh ) noexcept( all_nothrow_move_constructible_v< TL > )
192 {
193 // XXX: the partial ordering thing might be improved
194
195 index_type lh_i = lh.index;
196 index_type rh_i = rh.index;
197 if ( lh_i != rh_i )
198 return lh_i <=> rh_i;
199 return _dispatch_index< 0, TL::size >(
200 lh_i, [&]< index_type j >() -> std::partial_ordering {
201 return ST::template get< j >( lh.storage ) <=>
202 ST::template get< j >( rh.storage );
203 } );
204 }
205
206 static constexpr decltype( auto ) compare(
207 _val_core const& lh,
208 _val_core const& rh ) noexcept( all_nothrow_equality_comparable_v< TL > )
209 {
210 index_type lh_i = lh.index;
211 index_type rh_i = rh.index;
212 if ( lh_i != rh_i )
213 return lh_i == rh_i;
214 return _dispatch_index< 0, TL::size >( lh_i, [&]< index_type j > {
215 return ST::template get< j >( lh.storage ) ==
216 ST::template get< j >( rh.storage );
217 } );
218 }
219};
220
221// XXX:
222// - vref/vptr should be constructible from this
223
224} // namespace vari
MIT License.
Definition: dispatch.h:32