]>
Commit | Line | Data |
---|---|---|
20effc67 TL |
1 | // |
2 | // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) | |
3 | // | |
4 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
5 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
6 | // | |
7 | // Official repository: https://github.com/boostorg/json | |
8 | // | |
9 | ||
10 | #ifndef BOOST_JSON_PILFER_HPP | |
11 | #define BOOST_JSON_PILFER_HPP | |
12 | ||
13 | #include <boost/json/detail/config.hpp> | |
14 | #include <type_traits> | |
15 | #include <utility> | |
16 | ||
17 | /* | |
18 | Implements "pilfering" from P0308R0 | |
19 | ||
20 | @see | |
21 | http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0308r0.html | |
22 | */ | |
23 | ||
24 | namespace boost { | |
25 | namespace json { | |
26 | ||
27 | /** Tag wrapper to specify pilfer-construction. | |
28 | ||
29 | This wrapper is used to specify a pilfer constructor | |
30 | overload. | |
31 | ||
32 | @par Example | |
33 | ||
34 | A pilfer constructor accepts a single argument | |
35 | of type @ref pilfered and throws nothing: | |
36 | ||
37 | @code | |
38 | struct T | |
39 | { | |
40 | T( pilfered<T> ) noexcept; | |
41 | }; | |
42 | @endcode | |
43 | ||
44 | @note | |
45 | ||
46 | The constructor should not be marked explicit. | |
47 | ||
48 | @see @ref pilfer, @ref is_pilfer_constructible, | |
49 | <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0308r0.html"> | |
50 | Valueless Variants Considered Harmful</a> | |
51 | */ | |
52 | template<class T> | |
53 | class pilfered | |
54 | { | |
55 | T& t_; | |
56 | ||
57 | public: | |
58 | /** Constructor | |
59 | ||
60 | Construct the wrapper from `t`. | |
61 | ||
62 | @param t The pilferable object. Ownership | |
63 | is not transferred. | |
64 | */ | |
65 | explicit | |
66 | constexpr | |
67 | pilfered(T&& t) noexcept | |
68 | : t_(t) | |
69 | { | |
70 | } | |
71 | ||
72 | /** Return a reference to the pilferable object. | |
73 | ||
74 | This returns a reference to the wrapped object. | |
75 | */ | |
76 | constexpr T& | |
77 | get() const noexcept | |
78 | { | |
79 | return t_; | |
80 | } | |
81 | ||
82 | /** Return a pointer to the pilferable object. | |
83 | ||
84 | This returns a pointer to the wrapped object. | |
85 | */ | |
86 | constexpr T* | |
87 | operator->() const noexcept | |
88 | { | |
89 | //return std::addressof(t_); | |
90 | return reinterpret_cast<T*>( | |
91 | const_cast<char *>( | |
92 | &reinterpret_cast< | |
93 | const volatile char &>(t_))); | |
94 | } | |
95 | }; | |
96 | ||
97 | #ifndef BOOST_JSON_DOCS | |
1e59de90 | 98 | // VFALCO Renamed this to work around an msvc bug |
20effc67 TL |
99 | namespace detail_pilfer { |
100 | template<class> | |
101 | struct not_pilfered | |
102 | { | |
103 | }; | |
104 | } // detail_pilfer | |
105 | #endif | |
106 | ||
107 | /** Metafunction returning `true` if `T` is <em>PilferConstructible</em> | |
108 | ||
109 | If `T` can be pilfer constructed, this metafunction is | |
110 | equal to `std::true_type`. Otherwise it is equal to | |
111 | `std::false_type`. | |
112 | ||
113 | @see @ref pilfer, @ref pilfered, | |
114 | <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0308r0.html"> | |
115 | Valueless Variants Considered Harmful</a> | |
116 | */ | |
117 | template<class T> | |
118 | struct is_pilfer_constructible | |
119 | #ifndef BOOST_JSON_DOCS | |
120 | : std::integral_constant<bool, | |
121 | std::is_nothrow_move_constructible<T>::value || | |
122 | ( | |
123 | std::is_nothrow_constructible< | |
124 | T, pilfered<T> >::value && | |
125 | ! std::is_nothrow_constructible< | |
126 | T, detail_pilfer::not_pilfered<T> >::value | |
127 | )> | |
128 | #endif | |
129 | { | |
130 | }; | |
131 | ||
132 | /** Indicate that an object `t` may be pilfered from. | |
133 | ||
134 | A <em>pilfer</em> operation is the construction | |
135 | of a new object of type `T` from an existing | |
136 | object `t`. After the construction, the only | |
137 | valid operation on the pilfered-from object is | |
138 | destruction. This permits optimizations beyond | |
139 | those available for a move-construction, as the | |
140 | pilfered-from object is not required to be in | |
141 | a "usable" state. | |
142 | \n | |
143 | This is used similarly to `std::move`. | |
144 | ||
145 | @par Example | |
146 | ||
147 | A pilfer constructor accepts a single argument | |
148 | of type @ref pilfered and throws nothing: | |
149 | ||
150 | @code | |
151 | struct T | |
152 | { | |
153 | T( pilfered<T> ) noexcept; | |
154 | }; | |
155 | @endcode | |
156 | ||
157 | Pilfer construction is performed using @ref pilfer : | |
158 | ||
159 | @code | |
160 | { | |
161 | T t1; // default construction | |
162 | T t2( pilfer( t1 ) ); // pilfer-construct from t1 | |
163 | ||
164 | // At this point, t1 may only be destroyed | |
165 | } | |
166 | @endcode | |
167 | ||
168 | @see @ref pilfered, @ref is_pilfer_constructible, | |
169 | <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0308r0.html"> | |
170 | Valueless Variants Considered Harmful</a> | |
171 | */ | |
172 | template<class T> | |
173 | auto | |
174 | pilfer(T&& t) noexcept -> | |
175 | typename std::conditional< | |
176 | std::is_nothrow_constructible< | |
177 | typename std::remove_reference<T>::type, | |
178 | pilfered<typename | |
179 | std::remove_reference<T>::type> >::value && | |
180 | ! std::is_nothrow_constructible< | |
181 | typename std::remove_reference<T>::type, | |
182 | detail_pilfer::not_pilfered<typename | |
183 | std::remove_reference<T>::type> >::value, | |
184 | pilfered<typename std::remove_reference<T>::type>, | |
185 | typename std::remove_reference<T>::type&& | |
186 | >::type | |
187 | { | |
188 | using U = | |
189 | typename std::remove_reference<T>::type; | |
190 | static_assert( | |
191 | is_pilfer_constructible<U>::value, ""); | |
192 | return typename std::conditional< | |
193 | std::is_nothrow_constructible< | |
194 | U, pilfered<U> >::value && | |
195 | ! std::is_nothrow_constructible< | |
196 | U, detail_pilfer::not_pilfered<U> >::value, | |
197 | pilfered<U>, U&& | |
198 | >::type(std::move(t)); | |
199 | } | |
200 | ||
201 | /* | |
202 | template<class T> | |
203 | void | |
204 | relocate(T* dest, T& src) noexcept | |
205 | { | |
206 | static_assert( | |
207 | is_pilfer_constructible<T>::value, ""); | |
208 | ::new(dest) T(pilfer(src)); | |
209 | src.~T(); | |
210 | } | |
211 | */ | |
212 | ||
213 | } // json | |
214 | } // boost | |
215 | ||
216 | ||
217 | #endif |