106class polymorphic :
private detail::empty_base_optimization<A> {
107 struct control_block {
108 using allocator_traits = std::allocator_traits<A>;
109 typename allocator_traits::pointer p_;
111 virtual ~control_block() =
default;
112 virtual void destroy(A& alloc) = 0;
113 virtual control_block* clone(
const A& alloc) = 0;
114 virtual control_block* move(
const A& alloc) = 0;
118 class direct_control_block final :
public control_block {
119 union uninitialized_storage {
122 uninitialized_storage() {}
124 ~uninitialized_storage() {}
127 using cb_allocator =
typename std::allocator_traits<
128 A>::template rebind_alloc<direct_control_block<U>>;
129 using cb_alloc_traits = std::allocator_traits<cb_allocator>;
132 template <
class... Ts>
133 direct_control_block(
const A& alloc, Ts&&... ts) {
134 cb_allocator cb_alloc(alloc);
135 cb_alloc_traits::construct(cb_alloc, std::addressof(storage_.u_),
136 std::forward<Ts>(ts)...);
137 control_block::p_ = std::addressof(storage_.u_);
140 control_block* clone(
const A& alloc)
override {
141 cb_allocator cb_alloc(alloc);
142 auto mem = cb_alloc_traits::allocate(cb_alloc, 1);
144 cb_alloc_traits::construct(cb_alloc, mem, alloc, storage_.u_);
147 cb_alloc_traits::deallocate(cb_alloc, mem, 1);
152 control_block* move(
const A& alloc)
override {
153 cb_allocator cb_alloc(alloc);
154 auto mem = cb_alloc_traits::allocate(cb_alloc, 1);
156 cb_alloc_traits::construct(cb_alloc, mem, alloc,
157 std::move(storage_.u_));
160 cb_alloc_traits::deallocate(cb_alloc, mem, 1);
165 void destroy(A& alloc)
override {
166 cb_allocator cb_alloc(alloc);
167 cb_alloc_traits::destroy(cb_alloc, std::addressof(storage_.u_));
168 cb_alloc_traits::deallocate(cb_alloc,
this, 1);
173 using allocator_traits = std::allocator_traits<A>;
174 using alloc_base = detail::empty_base_optimization<A>;
176 template <
class U,
class... Ts>
177 control_block* create_control_block(Ts&&... ts)
const {
178 using cb_allocator =
typename std::allocator_traits<
179 A>::template rebind_alloc<direct_control_block<U>>;
180 cb_allocator cb_alloc(alloc_base::get());
181 using cb_alloc_traits = std::allocator_traits<cb_allocator>;
182 auto mem = cb_alloc_traits::allocate(cb_alloc, 1);
184 cb_alloc_traits::construct(cb_alloc, mem, alloc_base::get(),
185 std::forward<Ts>(ts)...);
188 cb_alloc_traits::deallocate(cb_alloc, mem, 1);
194 using value_type = T;
195 using allocator_type = A;
196 using pointer =
typename allocator_traits::pointer;
197 using const_pointer =
typename allocator_traits::const_pointer;
199 template <
typename TT = T,
200 typename std::enable_if<std::is_default_constructible<TT>::value,
202 polymorphic(std::allocator_arg_t,
const A& alloc) : alloc_base(alloc) {
203 cb_ = create_control_block<T>();
206 template <
typename TT = T,
207 typename std::enable_if<std::is_default_constructible<TT>::value,
210 typename std::enable_if<std::is_default_constructible<AA>::value,
212 polymorphic() : alloc_base() {
213 cb_ = create_control_block<T>();
217 class U,
class... Ts,
218 typename std::enable_if<std::is_constructible<U, Ts&&...>::value,
220 typename std::enable_if<std::is_copy_constructible<U>::value,
int>::type =
222 typename std::enable_if<std::is_base_of<T, U>::value,
int>::type = 0>
223 polymorphic(std::allocator_arg_t,
const A& alloc, in_place_type_t<U>,
225 : alloc_base(alloc) {
226 cb_ = create_control_block<U>(std::forward<Ts>(ts)...);
230 class U,
class I,
class... Ts,
231 typename std::enable_if<
232 std::is_constructible<U, std::initializer_list<I>, Ts&&...>::value,
234 typename std::enable_if<std::is_copy_constructible<U>::value,
int>::type =
236 typename std::enable_if<std::is_base_of<T, U>::value,
int>::type = 0>
237 polymorphic(std::allocator_arg_t,
const A& alloc, in_place_type_t<U>,
238 std::initializer_list<I> ilist, Ts&&... ts)
239 : alloc_base(alloc) {
240 cb_ = create_control_block<T>(ilist, std::forward<Ts>(ts)...);
244 class U,
class I,
class... Ts,
245 typename std::enable_if<
246 std::is_constructible<U, std::initializer_list<I>, Ts&&...>::value,
248 typename std::enable_if<std::is_copy_constructible<U>::value,
int>::type =
250 typename std::enable_if<std::is_base_of<T, U>::value,
int>::type = 0,
252 typename std::enable_if<std::is_default_constructible<AA>::value,
254 explicit polymorphic(in_place_type_t<U>, std::initializer_list<I> ilist,
256 : polymorphic(std::allocator_arg, A(), in_place_type_t<U>{}, ilist,
257 std::forward<Ts>(ts)...) {}
260 class U,
class... Ts,
261 typename std::enable_if<std::is_constructible<U, Ts&&...>::value,
263 typename std::enable_if<std::is_copy_constructible<U>::value,
int>::type =
265 typename std::enable_if<std::is_base_of<T, U>::value,
int>::type = 0,
267 typename std::enable_if<std::is_default_constructible<AA>::value,
269 explicit polymorphic(in_place_type_t<U>, Ts&&... ts)
270 : polymorphic(std::allocator_arg, A(), in_place_type_t<U>{},
271 std::forward<Ts>(ts)...) {}
275 typename std::enable_if<
276 !std::is_same<polymorphic,
277 typename std::remove_cv<
typename std::remove_reference<
278 U>::type>::type>::value,
280 typename std::enable_if<
281 std::is_copy_constructible<
typename std::remove_cv<
282 typename std::remove_reference<U>::type>::type>::value,
284 typename std::enable_if<
286 T,
typename std::remove_cv<
287 typename std::remove_reference<U>::type>::type>::value,
289 explicit polymorphic(std::allocator_arg_t,
const A& alloc, U&& u)
290 : polymorphic(std::allocator_arg_t{}, alloc,
291 in_place_type_t<
typename std::remove_cv<
292 typename std::remove_reference<U>::type>::type>{},
293 std::forward<U>(u)) {}
297 typename std::enable_if<
298 !std::is_same<polymorphic,
299 typename std::remove_cv<
typename std::remove_reference<
300 U>::type>::type>::value,
302 typename std::enable_if<
303 std::is_copy_constructible<
typename std::remove_cv<
304 typename std::remove_reference<U>::type>::type>::value,
306 typename std::enable_if<
308 T,
typename std::remove_cv<
309 typename std::remove_reference<U>::type>::type>::value,
312 : polymorphic(std::allocator_arg_t{}, A{},
313 in_place_type_t<
typename std::remove_cv<
314 typename std::remove_reference<U>::type>::type>{},
315 std::forward<U>(u)) {}
317 polymorphic(std::allocator_arg_t,
const A& alloc,
const polymorphic& other)
318 : alloc_base(alloc) {
319 if (!other.valueless_after_move()) {
320 cb_ = other.cb_->clone(alloc_base::get());
326 polymorphic(
const polymorphic& other)
327 : polymorphic(std::allocator_arg,
328 allocator_traits::select_on_container_copy_construction(
329 other.get_allocator()),
333 std::allocator_arg_t,
const A& alloc,
334 polymorphic&& other)
noexcept(allocator_traits::is_always_equal::value)
335 : alloc_base(alloc) {
336 if (allocator_traits::propagate_on_container_copy_assignment::value) {
340 if (get_allocator() == other.get_allocator()) {
344 if (!other.valueless_after_move()) {
345 cb_ = other.cb_->move(alloc_base::get());
353 polymorphic(polymorphic&& other) noexcept
354 : polymorphic(std::allocator_arg, other.get_allocator(),
357 ~polymorphic() { reset(); }
359 constexpr polymorphic& operator=(
const polymorphic& other) {
360 if (
this == &other)
return *
this;
366 allocator_traits::propagate_on_container_copy_assignment::value;
368 if (other.valueless_after_move()) {
373 auto tmp = other.cb_->clone(update_alloc ? other.alloc_base::get()
374 : alloc_base::get());
379 alloc_base::get() = other.alloc_base::get();
384 constexpr polymorphic& operator=(polymorphic&& other)
noexcept(
385 allocator_traits::propagate_on_container_move_assignment::value ||
386 allocator_traits::is_always_equal::value) {
387 if (
this == &other)
return *
this;
393 allocator_traits::propagate_on_container_move_assignment::value;
395 if (other.valueless_after_move()) {
398 if (alloc_base::get() == other.alloc_base::get()) {
399 std::swap(cb_, other.cb_);
404 auto tmp = other.cb_->move(update_alloc ? other.alloc_base::get()
405 : alloc_base::get());
412 alloc_base::get() = other.alloc_base::get();
417 [[nodiscard]] pointer operator->()
noexcept {
418 assert(!valueless_after_move());
422 [[nodiscard]] const_pointer operator->()
const noexcept {
423 assert(!valueless_after_move());
428 assert(!valueless_after_move());
432 [[nodiscard]]
const T&
operator*()
const noexcept {
433 assert(!valueless_after_move());
437 [[nodiscard]]
bool valueless_after_move()
const noexcept {
438 return cb_ ==
nullptr;
441 allocator_type get_allocator()
const noexcept {
return alloc_base::get(); }
443 void swap(polymorphic& other)
noexcept(
444 std::allocator_traits<A>::propagate_on_container_swap::value ||
445 std::allocator_traits<A>::is_always_equal::value) {
446 if (allocator_traits::propagate_on_container_swap::value) {
448 std::swap(alloc_base::get(), other.alloc_base::get());
449 std::swap(cb_, other.cb_);
452 if (alloc_base::get() == other.alloc_base::get()) {
453 std::swap(cb_, other.cb_);
460 friend void swap(polymorphic& lhs,
461 polymorphic& rhs)
noexcept(
noexcept(lhs.swap(rhs))) {
466 void reset()
noexcept {
467 if (cb_ !=
nullptr) {
468 cb_->destroy(alloc_base::get());