160class polymorphic :
private detail::empty_base_optimization<A> {
161 using cblock_t = detail::control_block<T, A>;
164 using allocator_traits = std::allocator_traits<A>;
165 using alloc_base = detail::empty_base_optimization<A>;
167 template <
class U,
class... Ts>
168 cblock_t* create_control_block(Ts&&... ts)
const {
169 using cb_allocator =
typename std::allocator_traits<
170 A>::template rebind_alloc<detail::direct_control_block<T, U, A>>;
171 cb_allocator cb_alloc(alloc_base::get());
172 using cb_alloc_traits = std::allocator_traits<cb_allocator>;
173 auto mem = cb_alloc_traits::allocate(cb_alloc, 1);
175 cb_alloc_traits::construct(cb_alloc, mem, alloc_base::get(),
176 std::forward<Ts>(ts)...);
179 cb_alloc_traits::deallocate(cb_alloc, mem, 1);
185 using value_type =
T;
186 using allocator_type = A;
187 using pointer =
typename allocator_traits::pointer;
188 using const_pointer =
typename allocator_traits::const_pointer;
190 template <
typename TT =
T,
191 typename std::enable_if<std::is_default_constructible<TT>::value,
193 polymorphic(std::allocator_arg_t,
const A& alloc) : alloc_base(alloc) {
194 cb_ = create_control_block<T>();
197 template <
typename TT =
T,
198 typename std::enable_if<std::is_default_constructible<TT>::value,
201 typename std::enable_if<std::is_default_constructible<AA>::value,
203 polymorphic() : alloc_base() {
204 cb_ = create_control_block<T>();
208 class U,
class... Ts,
209 typename std::enable_if<std::is_constructible<U, Ts&&...>::value,
211 typename std::enable_if<std::is_copy_constructible<U>::value,
int>::type =
213 typename std::enable_if<std::is_base_of<T, U>::value,
int>::type = 0>
214 polymorphic(std::allocator_arg_t,
const A& alloc, in_place_type_t<U>,
216 : alloc_base(alloc) {
217 cb_ = create_control_block<U>(std::forward<Ts>(ts)...);
221 class U,
class I,
class... Ts,
222 typename std::enable_if<
223 std::is_constructible<U, std::initializer_list<I>, Ts&&...>::value,
225 typename std::enable_if<std::is_copy_constructible<U>::value,
int>::type =
227 typename std::enable_if<std::is_base_of<T, U>::value,
int>::type = 0>
228 polymorphic(std::allocator_arg_t,
const A& alloc, in_place_type_t<U>,
229 std::initializer_list<I> ilist, Ts&&... ts)
230 : alloc_base(alloc) {
231 cb_ = create_control_block<T>(ilist, std::forward<Ts>(ts)...);
235 class U,
class I,
class... Ts,
236 typename std::enable_if<
237 std::is_constructible<U, std::initializer_list<I>, Ts&&...>::value,
239 typename std::enable_if<std::is_copy_constructible<U>::value,
int>::type =
241 typename std::enable_if<std::is_base_of<T, U>::value,
int>::type = 0,
243 typename std::enable_if<std::is_default_constructible<AA>::value,
245 explicit polymorphic(in_place_type_t<U>, std::initializer_list<I> ilist,
247 : polymorphic(std::allocator_arg, A(), in_place_type_t<U>{}, ilist,
248 std::forward<Ts>(ts)...) {}
251 class U,
class... Ts,
252 typename std::enable_if<std::is_constructible<U, Ts&&...>::value,
254 typename std::enable_if<std::is_copy_constructible<U>::value,
int>::type =
256 typename std::enable_if<std::is_base_of<T, U>::value,
int>::type = 0,
258 typename std::enable_if<std::is_default_constructible<AA>::value,
260 explicit polymorphic(in_place_type_t<U>, Ts&&... ts)
261 : polymorphic(std::allocator_arg, A(), in_place_type_t<U>{},
262 std::forward<Ts>(ts)...) {}
266 typename std::enable_if<
267 !std::is_same<polymorphic,
268 typename std::remove_cv<
typename std::remove_reference<
269 U>::type>::type>::value,
271 typename std::enable_if<
272 std::is_copy_constructible<
typename std::remove_cv<
273 typename std::remove_reference<U>::type>::type>::value,
275 typename std::enable_if<
277 T,
typename std::remove_cv<
278 typename std::remove_reference<U>::type>::type>::value,
280 explicit polymorphic(std::allocator_arg_t,
const A& alloc, U&& u)
281 : polymorphic(std::allocator_arg_t{}, alloc,
282 in_place_type_t<
typename std::remove_cv<
283 typename std::remove_reference<U>::type>::type>{},
284 std::forward<U>(u)) {}
288 typename std::enable_if<
289 !std::is_same<polymorphic,
290 typename std::remove_cv<
typename std::remove_reference<
291 U>::type>::type>::value,
293 typename std::enable_if<
294 std::is_copy_constructible<
typename std::remove_cv<
295 typename std::remove_reference<U>::type>::type>::value,
297 typename std::enable_if<
299 T,
typename std::remove_cv<
300 typename std::remove_reference<U>::type>::type>::value,
303 : polymorphic(std::allocator_arg_t{}, A{},
304 in_place_type_t<
typename std::remove_cv<
305 typename std::remove_reference<U>::type>::type>{},
306 std::forward<U>(u)) {}
308 polymorphic(std::allocator_arg_t,
const A& alloc,
const polymorphic& other)
309 : alloc_base(alloc) {
310 if (!other.valueless_after_move()) {
311 cb_ = other.cb_->clone(alloc_base::get());
317 polymorphic(
const polymorphic& other)
318 : polymorphic(std::allocator_arg,
319 allocator_traits::select_on_container_copy_construction(
320 other.get_allocator()),
324 std::allocator_arg_t,
const A& alloc,
325 polymorphic&& other)
noexcept(allocator_traits::is_always_equal::value)
326 : alloc_base(alloc) {
327 if (allocator_traits::propagate_on_container_copy_assignment::value) {
331 if (get_allocator() == other.get_allocator()) {
335 if (!other.valueless_after_move()) {
336 cb_ = other.cb_->move(alloc_base::get());
344 polymorphic(polymorphic&& other) noexcept
345 : polymorphic(std::allocator_arg, other.get_allocator(),
348 ~polymorphic() { reset(); }
350 constexpr polymorphic& operator=(
const polymorphic& other) {
351 if (
this == &other)
return *
this;
357 allocator_traits::propagate_on_container_copy_assignment::value;
359 if (other.valueless_after_move()) {
364 auto tmp = other.cb_->clone(update_alloc ? other.alloc_base::get()
365 : alloc_base::get());
370 alloc_base::get() = other.alloc_base::get();
375 constexpr polymorphic& operator=(polymorphic&& other)
noexcept(
376 allocator_traits::propagate_on_container_move_assignment::value ||
377 allocator_traits::is_always_equal::value) {
378 if (
this == &other)
return *
this;
384 allocator_traits::propagate_on_container_move_assignment::value;
386 if (other.valueless_after_move()) {
389 if (alloc_base::get() == other.alloc_base::get()) {
390 std::swap(cb_, other.cb_);
395 auto tmp = other.cb_->move(update_alloc ? other.alloc_base::get()
396 : alloc_base::get());
403 alloc_base::get() = other.alloc_base::get();
408 [[nodiscard]] pointer operator->()
noexcept {
409 assert(!valueless_after_move());
413 [[nodiscard]] const_pointer operator->()
const noexcept {
414 assert(!valueless_after_move());
418 [[nodiscard]]
T& operator*()
noexcept {
419 assert(!valueless_after_move());
423 [[nodiscard]]
const T& operator*()
const noexcept {
424 assert(!valueless_after_move());
428 [[nodiscard]]
bool valueless_after_move()
const noexcept {
429 return cb_ ==
nullptr;
432 allocator_type get_allocator()
const noexcept {
return alloc_base::get(); }
434 void swap(polymorphic& other)
noexcept(
435 std::allocator_traits<A>::propagate_on_container_swap::value ||
436 std::allocator_traits<A>::is_always_equal::value) {
437 if (allocator_traits::propagate_on_container_swap::value) {
439 std::swap(alloc_base::get(), other.alloc_base::get());
440 std::swap(cb_, other.cb_);
443 if (alloc_base::get() == other.alloc_base::get()) {
444 std::swap(cb_, other.cb_);
451 friend void swap(polymorphic& lhs,
452 polymorphic& rhs)
noexcept(
noexcept(lhs.swap(rhs))) {
457 void reset()
noexcept {
458 if (cb_ !=
nullptr) {
459 cb_->destroy(alloc_base::get());