|
@@ -1,16 +1,16 @@
|
|
#ifndef __GBLIBCPP_MEMORY__
|
|
#ifndef __GBLIBCPP_MEMORY__
|
|
#define __GBLIBCPP_MEMORY__
|
|
#define __GBLIBCPP_MEMORY__
|
|
|
|
|
|
|
|
+#include <bits/compressed_pair>
|
|
#include <cstddef>
|
|
#include <cstddef>
|
|
|
|
+#include <new>
|
|
#include <type_traits>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
#include <utility>
|
|
-#include <new>
|
|
|
|
|
|
|
|
namespace std {
|
|
namespace std {
|
|
|
|
|
|
template <typename T>
|
|
template <typename T>
|
|
-constexpr T* addressof(T& arg) noexcept
|
|
|
|
-{
|
|
|
|
|
|
+constexpr T* addressof(T& arg) noexcept {
|
|
return __builtin_addressof(arg);
|
|
return __builtin_addressof(arg);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -37,79 +37,87 @@ const T* addressof(const T&&) = delete;
|
|
|
|
|
|
namespace __helpers {
|
|
namespace __helpers {
|
|
|
|
|
|
-template <typename Ptr, typename = void>
|
|
|
|
-struct pointer_difference_type
|
|
|
|
-{ using type = std::ptrdiff_t; };
|
|
|
|
|
|
+ template <typename Ptr, typename = void>
|
|
|
|
+ struct pointer_difference_type {
|
|
|
|
+ using type = std::ptrdiff_t;
|
|
|
|
+ };
|
|
|
|
|
|
-template <typename Ptr>
|
|
|
|
-struct pointer_difference_type<Ptr,
|
|
|
|
- std::void_t<typename Ptr::difference_type>>
|
|
|
|
-{ using type = typename Ptr::difference_type; };
|
|
|
|
|
|
+ template <typename Ptr>
|
|
|
|
+ struct pointer_difference_type<Ptr,
|
|
|
|
+ std::void_t<typename Ptr::difference_type>> {
|
|
|
|
+ using type = typename Ptr::difference_type;
|
|
|
|
+ };
|
|
|
|
|
|
-template <typename Ptr>
|
|
|
|
-using pointer_difference_type_t =
|
|
|
|
- typename pointer_difference_type<Ptr>::type;
|
|
|
|
|
|
+ template <typename Ptr>
|
|
|
|
+ using pointer_difference_type_t =
|
|
|
|
+ typename pointer_difference_type<Ptr>::type;
|
|
|
|
|
|
-template <typename Base, typename T>
|
|
|
|
-struct rebind;
|
|
|
|
|
|
+ template <typename Base, typename T>
|
|
|
|
+ struct rebind;
|
|
|
|
|
|
-template <template <typename, typename...> typename Template,
|
|
|
|
- typename NewType, typename OldType, typename... Args>
|
|
|
|
-struct rebind<Template<OldType, Args...>, NewType> {
|
|
|
|
- using type = Template<NewType, Args...>;
|
|
|
|
-};
|
|
|
|
|
|
+ template <template <typename, typename...> typename Template,
|
|
|
|
+ typename NewType, typename OldType, typename... Args>
|
|
|
|
+ struct rebind<Template<OldType, Args...>, NewType> {
|
|
|
|
+ using type = Template<NewType, Args...>;
|
|
|
|
+ };
|
|
|
|
|
|
-template <typename Ptr, typename T, typename = void>
|
|
|
|
-struct try_rebind { using type = typename rebind<Ptr, T>::type; };
|
|
|
|
|
|
+ template <typename Ptr, typename T, typename = void>
|
|
|
|
+ struct try_rebind {
|
|
|
|
+ using type = typename rebind<Ptr, T>::type;
|
|
|
|
+ };
|
|
|
|
|
|
-template <typename Ptr, typename T>
|
|
|
|
-struct try_rebind<Ptr, T,
|
|
|
|
- std::void_t<typename Ptr::template rebind<T>>> {
|
|
|
|
- using type = typename Ptr::template rebind<T>;
|
|
|
|
-};
|
|
|
|
|
|
+ template <typename Ptr, typename T>
|
|
|
|
+ struct try_rebind<Ptr, T, std::void_t<typename Ptr::template rebind<T>>> {
|
|
|
|
+ using type = typename Ptr::template rebind<T>;
|
|
|
|
+ };
|
|
|
|
|
|
-template <typename Ptr, typename = void>
|
|
|
|
-struct pointer_element {};
|
|
|
|
|
|
+ template <typename Ptr, typename = void>
|
|
|
|
+ struct pointer_element {};
|
|
|
|
|
|
-template <typename Ptr>
|
|
|
|
-struct pointer_element<Ptr, std::enable_if_t<
|
|
|
|
- std::is_same_v<void, std::void_t<typename Ptr::element_type>>
|
|
|
|
->> { using type = typename Ptr::element_type; };
|
|
|
|
|
|
+ template <typename Ptr>
|
|
|
|
+ struct pointer_element<
|
|
|
|
+ Ptr, std::enable_if_t<std::is_same_v<
|
|
|
|
+ void, std::void_t<typename Ptr::element_type>>>> {
|
|
|
|
+ using type = typename Ptr::element_type;
|
|
|
|
+ };
|
|
|
|
|
|
-template <template <typename, typename...> typename Template,
|
|
|
|
- typename T, typename... Args>
|
|
|
|
-struct pointer_element<Template<T, Args...>, void>
|
|
|
|
-{ using type = T; };
|
|
|
|
|
|
+ template <template <typename, typename...> typename Template, typename T,
|
|
|
|
+ typename... Args>
|
|
|
|
+ struct pointer_element<Template<T, Args...>, void> {
|
|
|
|
+ using type = T;
|
|
|
|
+ };
|
|
|
|
|
|
-template <typename Ptr, typename = void>
|
|
|
|
-struct pointer_traits_impl {};
|
|
|
|
|
|
+ template <typename Ptr, typename = void>
|
|
|
|
+ struct pointer_traits_impl {};
|
|
|
|
|
|
-template <typename Ptr>
|
|
|
|
-struct pointer_traits_impl<Ptr,
|
|
|
|
- std::void_t<typename pointer_element<Ptr>::type>> {
|
|
|
|
- using pointer = Ptr;
|
|
|
|
- using element_type = typename pointer_element<Ptr>::type;
|
|
|
|
- using difference_type = pointer_difference_type_t<Ptr>;
|
|
|
|
|
|
+ template <typename Ptr>
|
|
|
|
+ struct pointer_traits_impl<
|
|
|
|
+ Ptr, std::void_t<typename pointer_element<Ptr>::type>> {
|
|
|
|
+ using pointer = Ptr;
|
|
|
|
+ using element_type = typename pointer_element<Ptr>::type;
|
|
|
|
+ using difference_type = pointer_difference_type_t<Ptr>;
|
|
|
|
|
|
- template <typename U>
|
|
|
|
- using rebind = typename try_rebind<Ptr, U>::type;
|
|
|
|
|
|
+ template <typename U>
|
|
|
|
+ using rebind = typename try_rebind<Ptr, U>::type;
|
|
|
|
|
|
- static pointer pointer_to(element_type& ref)
|
|
|
|
- { return Ptr::pointer_to(ref); }
|
|
|
|
-};
|
|
|
|
|
|
+ static pointer pointer_to(element_type& ref) {
|
|
|
|
+ return Ptr::pointer_to(ref);
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
|
|
-template <typename T>
|
|
|
|
-struct pointer_traits_impl<T*, void> {
|
|
|
|
- using pointer = T*;
|
|
|
|
- using element_type = T;
|
|
|
|
- using difference_type = std::ptrdiff_t;
|
|
|
|
|
|
+ template <typename T>
|
|
|
|
+ struct pointer_traits_impl<T*, void> {
|
|
|
|
+ using pointer = T*;
|
|
|
|
+ using element_type = T;
|
|
|
|
+ using difference_type = std::ptrdiff_t;
|
|
|
|
|
|
- template <typename U>
|
|
|
|
- using rebind = U*;
|
|
|
|
|
|
+ template <typename U>
|
|
|
|
+ using rebind = U*;
|
|
|
|
|
|
- static pointer pointer_to(element_type& ref)
|
|
|
|
- { return std::addressof(ref); }
|
|
|
|
-};
|
|
|
|
|
|
+ static pointer pointer_to(element_type& ref) {
|
|
|
|
+ return std::addressof(ref);
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
|
|
} // namespace __helpers
|
|
} // namespace __helpers
|
|
|
|
|
|
@@ -118,160 +126,170 @@ struct pointer_traits : public __helpers::pointer_traits_impl<Ptr> {};
|
|
|
|
|
|
namespace __helpers {
|
|
namespace __helpers {
|
|
|
|
|
|
-template <typename Alloc, typename = void>
|
|
|
|
-struct allocator_pointer
|
|
|
|
-{ using type = typename Alloc::value_type*; };
|
|
|
|
|
|
+ template <typename Alloc, typename = void>
|
|
|
|
+ struct allocator_pointer {
|
|
|
|
+ using type = typename Alloc::value_type*;
|
|
|
|
+ };
|
|
|
|
|
|
-template <typename Alloc>
|
|
|
|
-struct allocator_pointer<Alloc,
|
|
|
|
- std::void_t<typename Alloc::pointer>>
|
|
|
|
-{ using type = typename Alloc::pointer; };
|
|
|
|
|
|
+ template <typename Alloc>
|
|
|
|
+ struct allocator_pointer<Alloc, std::void_t<typename Alloc::pointer>> {
|
|
|
|
+ using type = typename Alloc::pointer;
|
|
|
|
+ };
|
|
|
|
|
|
-template <typename Alloc>
|
|
|
|
-using allocator_pointer_t =
|
|
|
|
- typename allocator_pointer<Alloc>::type;
|
|
|
|
|
|
+ template <typename Alloc>
|
|
|
|
+ using allocator_pointer_t = typename allocator_pointer<Alloc>::type;
|
|
|
|
|
|
|
|
+ template <typename Alloc, typename Pointer, typename = void>
|
|
|
|
+ struct allocator_const_pointer {
|
|
|
|
+ using type = typename std::pointer_traits<Pointer>::template rebind<
|
|
|
|
+ const typename Alloc::value_type>;
|
|
|
|
+ };
|
|
|
|
|
|
-template <typename Alloc, typename Pointer, typename = void>
|
|
|
|
-struct allocator_const_pointer {
|
|
|
|
- using type = typename std::pointer_traits<Pointer>::template
|
|
|
|
- rebind<const typename Alloc::value_type>;
|
|
|
|
-};
|
|
|
|
|
|
+ template <typename Alloc, typename Pointer>
|
|
|
|
+ struct allocator_const_pointer<Alloc, Pointer,
|
|
|
|
+ std::void_t<typename Alloc::const_pointer>> {
|
|
|
|
+ using type = typename Alloc::const_pointer;
|
|
|
|
+ };
|
|
|
|
|
|
-template <typename Alloc, typename Pointer>
|
|
|
|
-struct allocator_const_pointer<Alloc, Pointer,
|
|
|
|
- std::void_t<typename Alloc::const_pointer>>
|
|
|
|
-{ using type = typename Alloc::const_pointer; };
|
|
|
|
|
|
+ template <typename Alloc, typename Pointer>
|
|
|
|
+ using allocator_const_pointer_t =
|
|
|
|
+ typename allocator_const_pointer<Alloc, Pointer>::type;
|
|
|
|
|
|
-template <typename Alloc, typename Pointer>
|
|
|
|
-using allocator_const_pointer_t =
|
|
|
|
- typename allocator_const_pointer<Alloc, Pointer>::type;
|
|
|
|
|
|
+ template <typename Alloc, typename Pointer, typename = void>
|
|
|
|
+ struct allocator_void_pointer {
|
|
|
|
+ using type =
|
|
|
|
+ typename std::pointer_traits<Pointer>::template rebind<void>;
|
|
|
|
+ };
|
|
|
|
|
|
|
|
+ template <typename Alloc, typename Pointer>
|
|
|
|
+ struct allocator_void_pointer<Alloc, Pointer,
|
|
|
|
+ std::void_t<typename Alloc::void_pointer>> {
|
|
|
|
+ using type = typename Alloc::void_pointer;
|
|
|
|
+ };
|
|
|
|
|
|
-template <typename Alloc, typename Pointer, typename = void>
|
|
|
|
-struct allocator_void_pointer {
|
|
|
|
- using type = typename std::pointer_traits<Pointer>::template
|
|
|
|
- rebind<void>;
|
|
|
|
-};
|
|
|
|
|
|
+ template <typename Alloc, typename Pointer>
|
|
|
|
+ using allocator_void_pointer_t =
|
|
|
|
+ typename allocator_void_pointer<Alloc, Pointer>::type;
|
|
|
|
|
|
-template <typename Alloc, typename Pointer>
|
|
|
|
-struct allocator_void_pointer<Alloc, Pointer,
|
|
|
|
- std::void_t<typename Alloc::void_pointer>>
|
|
|
|
-{ using type = typename Alloc::void_pointer; };
|
|
|
|
|
|
+ template <typename Alloc, typename Pointer, typename = void>
|
|
|
|
+ struct allocator_const_void_pointer {
|
|
|
|
+ using type =
|
|
|
|
+ typename std::pointer_traits<Pointer>::template rebind<const void>;
|
|
|
|
+ };
|
|
|
|
|
|
-template <typename Alloc, typename Pointer>
|
|
|
|
-using allocator_void_pointer_t =
|
|
|
|
- typename allocator_void_pointer<Alloc, Pointer>::type;
|
|
|
|
|
|
+ template <typename Alloc, typename Pointer>
|
|
|
|
+ struct allocator_const_void_pointer<
|
|
|
|
+ Alloc, Pointer, std::void_t<typename Alloc::const_void_pointer>> {
|
|
|
|
+ using type = typename Alloc::const_void_pointer;
|
|
|
|
+ };
|
|
|
|
|
|
|
|
+ template <typename Alloc, typename Pointer>
|
|
|
|
+ using allocator_const_void_pointer_t =
|
|
|
|
+ typename allocator_const_void_pointer<Alloc, Pointer>::type;
|
|
|
|
|
|
-template <typename Alloc, typename Pointer, typename = void>
|
|
|
|
-struct allocator_const_void_pointer {
|
|
|
|
- using type = typename std::pointer_traits<Pointer>::template
|
|
|
|
- rebind<const void>;
|
|
|
|
-};
|
|
|
|
|
|
+ template <typename Alloc, typename = void>
|
|
|
|
+ struct allocator_difference_type {
|
|
|
|
+ using type = std::ptrdiff_t;
|
|
|
|
+ };
|
|
|
|
+ template <typename Alloc>
|
|
|
|
+ struct allocator_difference_type<
|
|
|
|
+ Alloc, std::void_t<typename Alloc::difference_type>> {
|
|
|
|
+ using type = typename Alloc::difference_type;
|
|
|
|
+ };
|
|
|
|
+ template <typename Alloc>
|
|
|
|
+ using allocator_difference_type_t =
|
|
|
|
+ typename allocator_difference_type<Alloc>::type;
|
|
|
|
|
|
-template <typename Alloc, typename Pointer>
|
|
|
|
-struct allocator_const_void_pointer<Alloc, Pointer,
|
|
|
|
- std::void_t<typename Alloc::const_void_pointer>>
|
|
|
|
-{ using type = typename Alloc::const_void_pointer; };
|
|
|
|
-
|
|
|
|
-template <typename Alloc, typename Pointer>
|
|
|
|
-using allocator_const_void_pointer_t =
|
|
|
|
- typename allocator_const_void_pointer<Alloc, Pointer>::type;
|
|
|
|
-
|
|
|
|
-
|
|
|
|
-template <typename Alloc, typename = void>
|
|
|
|
-struct allocator_difference_type
|
|
|
|
-{ using type = std::ptrdiff_t; };
|
|
|
|
-template <typename Alloc>
|
|
|
|
-struct allocator_difference_type<Alloc,
|
|
|
|
- std::void_t<typename Alloc::difference_type>>
|
|
|
|
-{ using type = typename Alloc::difference_type; };
|
|
|
|
-template <typename Alloc>
|
|
|
|
-using allocator_difference_type_t =
|
|
|
|
- typename allocator_difference_type<Alloc>::type;
|
|
|
|
-
|
|
|
|
-template <typename Alloc, typename = void>
|
|
|
|
-struct allocator_size_type
|
|
|
|
-{ using type = std::size_t; };
|
|
|
|
-template <typename Alloc>
|
|
|
|
-struct allocator_size_type<Alloc,
|
|
|
|
- std::void_t<typename Alloc::size_type>>
|
|
|
|
-{ using type = typename Alloc::size_type; };
|
|
|
|
-template <typename Alloc>
|
|
|
|
-using allocator_size_type_t =
|
|
|
|
- typename allocator_size_type<Alloc>::type;
|
|
|
|
-
|
|
|
|
-template <typename Alloc, typename = void>
|
|
|
|
-struct allocator_prop_copy
|
|
|
|
-{ using type = std::false_type; };
|
|
|
|
-template <typename Alloc>
|
|
|
|
-struct allocator_prop_copy<Alloc,
|
|
|
|
- std::void_t<typename Alloc::propagate_on_container_copy_assignment>>
|
|
|
|
-{ using type = typename Alloc::propagate_on_container_copy_assignment; };
|
|
|
|
-template <typename Alloc>
|
|
|
|
-using allocator_prop_copy_t =
|
|
|
|
- typename allocator_prop_copy<Alloc>::type;
|
|
|
|
-
|
|
|
|
-template <typename Alloc, typename = void>
|
|
|
|
-struct allocator_prop_move
|
|
|
|
-{ using type = std::false_type; };
|
|
|
|
-template <typename Alloc>
|
|
|
|
-struct allocator_prop_move<Alloc,
|
|
|
|
- std::void_t<typename Alloc::propagate_on_container_move_assignment>>
|
|
|
|
-{ using type = typename Alloc::propagate_on_container_move_assignment; };
|
|
|
|
-template <typename Alloc>
|
|
|
|
-using allocator_prop_move_t =
|
|
|
|
- typename allocator_prop_move<Alloc>::type;
|
|
|
|
-
|
|
|
|
-template <typename Alloc, typename = void>
|
|
|
|
-struct allocator_prop_swap
|
|
|
|
-{ using type = std::false_type; };
|
|
|
|
-template <typename Alloc>
|
|
|
|
-struct allocator_prop_swap<Alloc,
|
|
|
|
- std::void_t<typename Alloc::propagate_on_container_swap>>
|
|
|
|
-{ using type = typename Alloc::propagate_on_container_swap; };
|
|
|
|
-template <typename Alloc>
|
|
|
|
-using allocator_prop_swap_t =
|
|
|
|
- typename allocator_prop_swap<Alloc>::type;
|
|
|
|
-
|
|
|
|
-template <typename Alloc, typename = void>
|
|
|
|
-struct is_always_equal
|
|
|
|
-{ using type = std::false_type; };
|
|
|
|
-template <typename Alloc>
|
|
|
|
-struct is_always_equal<Alloc,
|
|
|
|
- std::void_t<typename Alloc::is_always_equal>>
|
|
|
|
-{ using type = typename Alloc::is_always_equal; };
|
|
|
|
-template <typename Alloc>
|
|
|
|
-using is_always_equal_t =
|
|
|
|
- typename is_always_equal<Alloc>::type;
|
|
|
|
-
|
|
|
|
-template <typename Alloc, typename = void>
|
|
|
|
-struct allocator_select_on_copy {
|
|
|
|
- static constexpr Alloc get(const Alloc& alloc)
|
|
|
|
- { return alloc; }
|
|
|
|
-};
|
|
|
|
|
|
+ template <typename Alloc, typename = void>
|
|
|
|
+ struct allocator_size_type {
|
|
|
|
+ using type = std::size_t;
|
|
|
|
+ };
|
|
|
|
+ template <typename Alloc>
|
|
|
|
+ struct allocator_size_type<Alloc, std::void_t<typename Alloc::size_type>> {
|
|
|
|
+ using type = typename Alloc::size_type;
|
|
|
|
+ };
|
|
|
|
+ template <typename Alloc>
|
|
|
|
+ using allocator_size_type_t = typename allocator_size_type<Alloc>::type;
|
|
|
|
|
|
-template <typename Alloc>
|
|
|
|
-struct allocator_select_on_copy<Alloc, std::enable_if_t<
|
|
|
|
- std::is_same_v<void, std::void_t<decltype(
|
|
|
|
- std::declval<Alloc>().select_on_container_copy_construction()
|
|
|
|
- )>> >> {
|
|
|
|
- static constexpr Alloc get(const Alloc& alloc)
|
|
|
|
- { return alloc.select_on_container_copy_construction(); }
|
|
|
|
-};
|
|
|
|
|
|
+ template <typename Alloc, typename = void>
|
|
|
|
+ struct allocator_prop_copy {
|
|
|
|
+ using type = std::false_type;
|
|
|
|
+ };
|
|
|
|
+ template <typename Alloc>
|
|
|
|
+ struct allocator_prop_copy<
|
|
|
|
+ Alloc,
|
|
|
|
+ std::void_t<typename Alloc::propagate_on_container_copy_assignment>> {
|
|
|
|
+ using type = typename Alloc::propagate_on_container_copy_assignment;
|
|
|
|
+ };
|
|
|
|
+ template <typename Alloc>
|
|
|
|
+ using allocator_prop_copy_t = typename allocator_prop_copy<Alloc>::type;
|
|
|
|
|
|
-template <typename Allocator, typename T, typename = void>
|
|
|
|
-struct allocator_rebind_type {
|
|
|
|
- using type = typename rebind<Allocator, T>::type;
|
|
|
|
-};
|
|
|
|
|
|
+ template <typename Alloc, typename = void>
|
|
|
|
+ struct allocator_prop_move {
|
|
|
|
+ using type = std::false_type;
|
|
|
|
+ };
|
|
|
|
+ template <typename Alloc>
|
|
|
|
+ struct allocator_prop_move<
|
|
|
|
+ Alloc,
|
|
|
|
+ std::void_t<typename Alloc::propagate_on_container_move_assignment>> {
|
|
|
|
+ using type = typename Alloc::propagate_on_container_move_assignment;
|
|
|
|
+ };
|
|
|
|
+ template <typename Alloc>
|
|
|
|
+ using allocator_prop_move_t = typename allocator_prop_move<Alloc>::type;
|
|
|
|
|
|
-template <typename Allocator, typename T>
|
|
|
|
-struct allocator_rebind_type<Allocator, T, std::void_t<
|
|
|
|
- typename Allocator::template rebind<T>::other
|
|
|
|
->> {
|
|
|
|
- using type = typename Allocator::template rebind<T>::other;
|
|
|
|
-};
|
|
|
|
|
|
+ template <typename Alloc, typename = void>
|
|
|
|
+ struct allocator_prop_swap {
|
|
|
|
+ using type = std::false_type;
|
|
|
|
+ };
|
|
|
|
+ template <typename Alloc>
|
|
|
|
+ struct allocator_prop_swap<
|
|
|
|
+ Alloc, std::void_t<typename Alloc::propagate_on_container_swap>> {
|
|
|
|
+ using type = typename Alloc::propagate_on_container_swap;
|
|
|
|
+ };
|
|
|
|
+ template <typename Alloc>
|
|
|
|
+ using allocator_prop_swap_t = typename allocator_prop_swap<Alloc>::type;
|
|
|
|
+
|
|
|
|
+ template <typename Alloc, typename = void>
|
|
|
|
+ struct is_always_equal {
|
|
|
|
+ using type = std::false_type;
|
|
|
|
+ };
|
|
|
|
+ template <typename Alloc>
|
|
|
|
+ struct is_always_equal<Alloc,
|
|
|
|
+ std::void_t<typename Alloc::is_always_equal>> {
|
|
|
|
+ using type = typename Alloc::is_always_equal;
|
|
|
|
+ };
|
|
|
|
+ template <typename Alloc>
|
|
|
|
+ using is_always_equal_t = typename is_always_equal<Alloc>::type;
|
|
|
|
+
|
|
|
|
+ template <typename Alloc, typename = void>
|
|
|
|
+ struct allocator_select_on_copy {
|
|
|
|
+ static constexpr Alloc get(const Alloc& alloc) { return alloc; }
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ template <typename Alloc>
|
|
|
|
+ struct allocator_select_on_copy<
|
|
|
|
+ Alloc,
|
|
|
|
+ std::enable_if_t<std::is_same_v<
|
|
|
|
+ void,
|
|
|
|
+ std::void_t<
|
|
|
|
+ decltype(std::declval<Alloc>()
|
|
|
|
+ .select_on_container_copy_construction())>>>> {
|
|
|
|
+ static constexpr Alloc get(const Alloc& alloc) {
|
|
|
|
+ return alloc.select_on_container_copy_construction();
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ template <typename Allocator, typename T, typename = void>
|
|
|
|
+ struct allocator_rebind_type {
|
|
|
|
+ using type = typename rebind<Allocator, T>::type;
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ template <typename Allocator, typename T>
|
|
|
|
+ struct allocator_rebind_type<
|
|
|
|
+ Allocator, T,
|
|
|
|
+ std::void_t<typename Allocator::template rebind<T>::other>> {
|
|
|
|
+ using type = typename Allocator::template rebind<T>::other;
|
|
|
|
+ };
|
|
|
|
|
|
} // namespace __helpers
|
|
} // namespace __helpers
|
|
|
|
|
|
@@ -289,29 +307,30 @@ struct allocator {
|
|
constexpr ~allocator() = default;
|
|
constexpr ~allocator() = default;
|
|
|
|
|
|
// throws std::bad_alloc
|
|
// throws std::bad_alloc
|
|
- [[nodiscard]] constexpr T* allocate(std::size_t n)
|
|
|
|
- { return static_cast<T*>(::operator new(n * sizeof(T))); }
|
|
|
|
|
|
+ [[nodiscard]] constexpr T* allocate(std::size_t n) {
|
|
|
|
+ return static_cast<T*>(::operator new(n * sizeof(T)));
|
|
|
|
+ }
|
|
|
|
|
|
// TODO: check allocated size
|
|
// TODO: check allocated size
|
|
- constexpr void deallocate(T* ptr, std::size_t)
|
|
|
|
- { ::operator delete(ptr); }
|
|
|
|
|
|
+ constexpr void deallocate(T* ptr, std::size_t) { ::operator delete(ptr); }
|
|
};
|
|
};
|
|
|
|
|
|
template <typename T1, typename T2>
|
|
template <typename T1, typename T2>
|
|
-constexpr bool operator==(const allocator<T1>&, const allocator<T2>&) noexcept
|
|
|
|
-{ return true; }
|
|
|
|
|
|
+constexpr bool operator==(const allocator<T1>&, const allocator<T2>&) noexcept {
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
|
|
template <typename T, typename... Args>
|
|
template <typename T, typename... Args>
|
|
-constexpr std::enable_if_t<std::is_same_v<T*,
|
|
|
|
- decltype(::new(std::declval<void*>()) T(std::declval<Args>()...))> , T*>
|
|
|
|
-construct_at(T* p, Args&&... args)
|
|
|
|
-{
|
|
|
|
|
|
+constexpr std::enable_if_t<
|
|
|
|
+ std::is_same_v<T*, decltype(::new(std::declval<void*>())
|
|
|
|
+ T(std::declval<Args>()...))>,
|
|
|
|
+ T*>
|
|
|
|
+construct_at(T* p, Args&&... args) {
|
|
return ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
|
|
return ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
|
|
}
|
|
}
|
|
|
|
|
|
template <typename T>
|
|
template <typename T>
|
|
-constexpr void destroy_at(T* p)
|
|
|
|
-{
|
|
|
|
|
|
+constexpr void destroy_at(T* p) {
|
|
// TODO: destroy array
|
|
// TODO: destroy array
|
|
p->~T();
|
|
p->~T();
|
|
}
|
|
}
|
|
@@ -320,115 +339,123 @@ template <typename Allocator>
|
|
struct allocator_traits {
|
|
struct allocator_traits {
|
|
using allocator_type = Allocator;
|
|
using allocator_type = Allocator;
|
|
using value_type = typename Allocator::value_type;
|
|
using value_type = typename Allocator::value_type;
|
|
- using pointer =
|
|
|
|
- __helpers::allocator_pointer_t<Allocator>;
|
|
|
|
|
|
+ using pointer = __helpers::allocator_pointer_t<Allocator>;
|
|
using const_pointer =
|
|
using const_pointer =
|
|
__helpers::allocator_const_pointer_t<Allocator, pointer>;
|
|
__helpers::allocator_const_pointer_t<Allocator, pointer>;
|
|
using void_pointer =
|
|
using void_pointer =
|
|
__helpers::allocator_void_pointer_t<Allocator, pointer>;
|
|
__helpers::allocator_void_pointer_t<Allocator, pointer>;
|
|
using const_void_pointer =
|
|
using const_void_pointer =
|
|
__helpers::allocator_const_void_pointer_t<Allocator, pointer>;
|
|
__helpers::allocator_const_void_pointer_t<Allocator, pointer>;
|
|
- using difference_type =
|
|
|
|
- __helpers::allocator_difference_type_t<Allocator>;
|
|
|
|
- using size_type =
|
|
|
|
- __helpers::allocator_size_type_t<Allocator>;
|
|
|
|
|
|
+ using difference_type = __helpers::allocator_difference_type_t<Allocator>;
|
|
|
|
+ using size_type = __helpers::allocator_size_type_t<Allocator>;
|
|
using propagate_on_container_copy_assignment =
|
|
using propagate_on_container_copy_assignment =
|
|
__helpers::allocator_prop_copy_t<Allocator>;
|
|
__helpers::allocator_prop_copy_t<Allocator>;
|
|
using propagate_on_container_move_assignment =
|
|
using propagate_on_container_move_assignment =
|
|
__helpers::allocator_prop_move_t<Allocator>;
|
|
__helpers::allocator_prop_move_t<Allocator>;
|
|
using propagate_on_container_swap =
|
|
using propagate_on_container_swap =
|
|
__helpers::allocator_prop_swap_t<Allocator>;
|
|
__helpers::allocator_prop_swap_t<Allocator>;
|
|
- using is_always_equal =
|
|
|
|
- __helpers::is_always_equal_t<Allocator>;
|
|
|
|
|
|
+ using is_always_equal = __helpers::is_always_equal_t<Allocator>;
|
|
|
|
|
|
template <typename T>
|
|
template <typename T>
|
|
using rebind_alloc =
|
|
using rebind_alloc =
|
|
typename __helpers::allocator_rebind_type<Allocator, T>::type;
|
|
typename __helpers::allocator_rebind_type<Allocator, T>::type;
|
|
|
|
|
|
- [[nodiscard]] static constexpr pointer allocate(Allocator& alloc, size_type n)
|
|
|
|
- { return alloc.allocate(n); }
|
|
|
|
- static constexpr void deallocate(Allocator& alloc, pointer p, size_type n)
|
|
|
|
- { return alloc.deallocate(p, n); }
|
|
|
|
|
|
+ [[nodiscard]] static constexpr pointer allocate(Allocator& alloc,
|
|
|
|
+ size_type n) {
|
|
|
|
+ return alloc.allocate(n);
|
|
|
|
+ }
|
|
|
|
+ static constexpr void deallocate(Allocator& alloc, pointer p, size_type n) {
|
|
|
|
+ return alloc.deallocate(p, n);
|
|
|
|
+ }
|
|
template <typename T, typename... Args>
|
|
template <typename T, typename... Args>
|
|
- static constexpr void construct(Allocator&, T* p, Args&&... args)
|
|
|
|
- { std::construct_at(p, std::forward<Args>(args)...); }
|
|
|
|
|
|
+ static constexpr void construct(Allocator&, T* p, Args&&... args) {
|
|
|
|
+ std::construct_at(p, std::forward<Args>(args)...);
|
|
|
|
+ }
|
|
template <typename T>
|
|
template <typename T>
|
|
- static constexpr void destroy(Allocator&, T* p)
|
|
|
|
- { std::destroy_at(p); }
|
|
|
|
|
|
+ static constexpr void destroy(Allocator&, T* p) {
|
|
|
|
+ std::destroy_at(p);
|
|
|
|
+ }
|
|
|
|
|
|
- static constexpr Allocator
|
|
|
|
- select_on_container_copy_construction(const Allocator& alloc)
|
|
|
|
- { return __helpers::allocator_select_on_copy<Allocator>::get(alloc); }
|
|
|
|
|
|
+ static constexpr Allocator select_on_container_copy_construction(
|
|
|
|
+ const Allocator& alloc) {
|
|
|
|
+ return __helpers::allocator_select_on_copy<Allocator>::get(alloc);
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+template <typename T>
|
|
|
|
+struct default_delete {
|
|
|
|
+ __GBLIBCPP_CONSTEXPR default_delete() noexcept = default;
|
|
|
|
+
|
|
|
|
+ template <typename U,
|
|
|
|
+ std::enable_if_t<std::is_convertible_v<U*, T*>, bool> = true>
|
|
|
|
+ __GBLIBCPP_CONSTEXPR default_delete(const default_delete<U>&) noexcept {}
|
|
|
|
+
|
|
|
|
+ __GBLIBCPP_CONSTEXPR void operator()(T* p) const { delete p; }
|
|
};
|
|
};
|
|
|
|
|
|
// TODO: weak_ptr
|
|
// TODO: weak_ptr
|
|
template <typename T>
|
|
template <typename T>
|
|
class shared_ptr {
|
|
class shared_ptr {
|
|
-public:
|
|
|
|
|
|
+ public:
|
|
using element_type = std::remove_extent_t<T>;
|
|
using element_type = std::remove_extent_t<T>;
|
|
using pointer = element_type*; // TODO: pointer_traits
|
|
using pointer = element_type*; // TODO: pointer_traits
|
|
using const_pointer = const element_type*;
|
|
using const_pointer = const element_type*;
|
|
using reference = element_type&;
|
|
using reference = element_type&;
|
|
using const_reference = const element_type&;
|
|
using const_reference = const element_type&;
|
|
|
|
|
|
-private:
|
|
|
|
|
|
+ private:
|
|
struct control_block_base {
|
|
struct control_block_base {
|
|
std::size_t ref_count;
|
|
std::size_t ref_count;
|
|
std::size_t weak_count;
|
|
std::size_t weak_count;
|
|
pointer ptr;
|
|
pointer ptr;
|
|
|
|
|
|
constexpr control_block_base(std::size_t ref_count,
|
|
constexpr control_block_base(std::size_t ref_count,
|
|
- std::size_t weak_count, pointer ptr)
|
|
|
|
- : ref_count(ref_count), weak_count(weak_count), ptr(ptr) { }
|
|
|
|
|
|
+ std::size_t weak_count, pointer ptr)
|
|
|
|
+ : ref_count(ref_count), weak_count(weak_count), ptr(ptr) {}
|
|
|
|
|
|
virtual constexpr ~control_block_base() = default;
|
|
virtual constexpr ~control_block_base() = default;
|
|
virtual constexpr void do_delete() = 0;
|
|
virtual constexpr void do_delete() = 0;
|
|
|
|
+
|
|
|
|
+ // template <typename U, std::enable_if_t<std::is_convertible_v<T*, U*>,
|
|
|
|
+ // bool> = true> constexpr operator typename
|
|
|
|
+ // shared_ptr<U>::control_block_base*() const
|
|
|
|
+ // {
|
|
|
|
+ // return this;
|
|
|
|
+ // }
|
|
};
|
|
};
|
|
|
|
|
|
template <typename Deleter>
|
|
template <typename Deleter>
|
|
- struct control_block : public virtual control_block_base {
|
|
|
|
- Deleter deleter;
|
|
|
|
- virtual constexpr ~control_block() = default;
|
|
|
|
|
|
+ struct control_block : public virtual control_block_base, private Deleter {
|
|
|
|
+ using Base = control_block_base;
|
|
|
|
|
|
- template <typename UDeleter>
|
|
|
|
- constexpr control_block(std::size_t ref_count,
|
|
|
|
- std::size_t weak_count, pointer ptr, UDeleter&& deleter)
|
|
|
|
- : control_block_base { ref_count, weak_count, ptr }
|
|
|
|
- , deleter(std::forward<UDeleter>(deleter)) { }
|
|
|
|
-
|
|
|
|
- virtual constexpr void do_delete() override
|
|
|
|
- {
|
|
|
|
- if (this->ptr)
|
|
|
|
- deleter(this->ptr);
|
|
|
|
- this->ptr = nullptr;
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- struct default_control_block : public virtual control_block_base {
|
|
|
|
- virtual constexpr ~default_control_block() = default;
|
|
|
|
|
|
+ virtual constexpr ~control_block() = default;
|
|
|
|
|
|
- constexpr default_control_block(std::size_t ref_count,
|
|
|
|
- std::size_t weak_count, pointer ptr)
|
|
|
|
- : control_block_base { ref_count, weak_count, ptr } { }
|
|
|
|
|
|
+ constexpr control_block(std::size_t ref_count, std::size_t weak_count,
|
|
|
|
+ pointer ptr)
|
|
|
|
+ : control_block_base{ref_count, weak_count, ptr}, Deleter{} {}
|
|
|
|
|
|
- virtual constexpr void do_delete() override
|
|
|
|
- {
|
|
|
|
- if (this->ptr)
|
|
|
|
- delete this->ptr;
|
|
|
|
- this->ptr = nullptr;
|
|
|
|
|
|
+ template <typename UDeleter>
|
|
|
|
+ constexpr control_block(std::size_t ref_count, std::size_t weak_count,
|
|
|
|
+ pointer ptr, UDeleter&& deleter)
|
|
|
|
+ : control_block_base{ref_count, weak_count, ptr}
|
|
|
|
+ , Deleter(std::forward<UDeleter>(deleter)) {}
|
|
|
|
+
|
|
|
|
+ virtual constexpr void do_delete() override {
|
|
|
|
+ if (this->Base::ptr)
|
|
|
|
+ this->Deleter::operator()(this->Base::ptr);
|
|
|
|
+ this->Base::ptr = nullptr;
|
|
}
|
|
}
|
|
};
|
|
};
|
|
|
|
|
|
- control_block_base* cb { };
|
|
|
|
|
|
+ control_block_base* cb{};
|
|
|
|
+ pointer ptr{};
|
|
|
|
|
|
- void inc_ref()
|
|
|
|
- {
|
|
|
|
|
|
+ void inc_ref() {
|
|
if (cb)
|
|
if (cb)
|
|
++cb->ref_count; // TODO: lock and atomic
|
|
++cb->ref_count; // TODO: lock and atomic
|
|
}
|
|
}
|
|
|
|
|
|
- void dec_ref()
|
|
|
|
- {
|
|
|
|
|
|
+ void dec_ref() {
|
|
if (cb && --cb->ref_count == 0) {
|
|
if (cb && --cb->ref_count == 0) {
|
|
cb->do_delete();
|
|
cb->do_delete();
|
|
if (cb->weak_count == 0)
|
|
if (cb->weak_count == 0)
|
|
@@ -436,130 +463,112 @@ private:
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-private:
|
|
|
|
- template <typename Deleter>
|
|
|
|
- using rebind_allocator = typename std::allocator_traits<Deleter>::template
|
|
|
|
- rebind_alloc<control_block<Deleter>>;
|
|
|
|
|
|
+ private:
|
|
|
|
+ template <typename Allocator, typename Deleter>
|
|
|
|
+ using rebound_allocator = typename std::allocator_traits<
|
|
|
|
+ Allocator>::template rebind_alloc<control_block<Deleter>>;
|
|
|
|
+
|
|
|
|
+ template <typename Allocator, typename Deleter>
|
|
|
|
+ using rebound_traits =
|
|
|
|
+ typename std::allocator_traits<rebound_allocator<Allocator, Deleter>>;
|
|
|
|
|
|
template <typename U>
|
|
template <typename U>
|
|
friend class shared_ptr;
|
|
friend class shared_ptr;
|
|
|
|
|
|
-public:
|
|
|
|
- constexpr shared_ptr() noexcept = default;
|
|
|
|
- constexpr shared_ptr(std::nullptr_t) noexcept : cb { } { }
|
|
|
|
|
|
+ public:
|
|
|
|
+ __GBLIBCPP_CONSTEXPR shared_ptr() noexcept = default;
|
|
|
|
+ __GBLIBCPP_CONSTEXPR shared_ptr(std::nullptr_t) noexcept : shared_ptr{} {}
|
|
|
|
|
|
- template <typename U>
|
|
|
|
- __GBLIBCPP_CONSTEXPR
|
|
|
|
- explicit shared_ptr(U* ptr) // TODO: array type
|
|
|
|
- : cb(new default_control_block { 1, 0, ptr }) { }
|
|
|
|
|
|
+ template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
|
|
|
|
+ __GBLIBCPP_CONSTEXPR explicit shared_ptr(U* p) // TODO: array type
|
|
|
|
+ : cb(new control_block<default_delete<T>>{1, 0, p}), ptr(p) {}
|
|
|
|
|
|
- template <typename U, typename Deleter>
|
|
|
|
- __GBLIBCPP_CONSTEXPR
|
|
|
|
- explicit shared_ptr(U* ptr, Deleter d)
|
|
|
|
- : cb(new control_block<Deleter> { 1, 0, ptr, d }) { }
|
|
|
|
|
|
+ template <typename U, typename Deleter,
|
|
|
|
+ enable_if_t<is_convertible_v<U*, T*>, bool> = true>
|
|
|
|
+ __GBLIBCPP_CONSTEXPR explicit shared_ptr(U* p, Deleter d)
|
|
|
|
+ : cb(new control_block<Deleter>{1, 0, p, d}), ptr(p) {}
|
|
|
|
|
|
template <typename Deleter>
|
|
template <typename Deleter>
|
|
- __GBLIBCPP_CONSTEXPR
|
|
|
|
- explicit shared_ptr(std::nullptr_t, Deleter d)
|
|
|
|
- : cb(new control_block<Deleter> { 1, 0, nullptr, d }) { }
|
|
|
|
-
|
|
|
|
- // TODO: what the fuck
|
|
|
|
- // template <typename U, typename Deleter, typename Allocator>
|
|
|
|
- // __GBLIBCPP_CONSTEXPR
|
|
|
|
- // explicit shared_ptr(U* ptr, Deleter d, Allocator alloc)
|
|
|
|
- // {
|
|
|
|
- // cb = std::allocator_traits<
|
|
|
|
- // rebind_allocator<Deleter>>::allocate(alloc, 1);
|
|
|
|
-
|
|
|
|
- // std::allocator_traits<
|
|
|
|
- // rebind_allocator<Deleter>>::construct(alloc, cb, 1, 0, ptr, d);
|
|
|
|
- // }
|
|
|
|
-
|
|
|
|
- // template <typename Deleter, typename Allocator>
|
|
|
|
- // __GBLIBCPP_CONSTEXPR
|
|
|
|
- // explicit shared_ptr(std::nullptr_t, Deleter d, Allocator alloc)
|
|
|
|
- // {
|
|
|
|
- // cb = std::allocator_traits<
|
|
|
|
- // rebind_allocator<Deleter>>::allocate(alloc, 1);
|
|
|
|
-
|
|
|
|
- // std::allocator_traits<
|
|
|
|
- // rebind_allocator<Deleter>>::construct(alloc, cb, 1, 0, nullptr, d);
|
|
|
|
- // }
|
|
|
|
|
|
+ __GBLIBCPP_CONSTEXPR explicit shared_ptr(std::nullptr_t, Deleter d)
|
|
|
|
+ : cb(new control_block<Deleter>{1, 0, nullptr, d}) {}
|
|
|
|
|
|
- __GBLIBCPP_CONSTEXPR
|
|
|
|
- shared_ptr(const shared_ptr& other) noexcept
|
|
|
|
- : cb(other.cb) { inc_ref(); }
|
|
|
|
|
|
+ template <typename U, typename Deleter, typename Alloc,
|
|
|
|
+ enable_if_t<is_convertible_v<U*, T*>, bool> = true>
|
|
|
|
+ __GBLIBCPP_CONSTEXPR explicit shared_ptr(U* p, Deleter d, Alloc alloc) {
|
|
|
|
+ cb = rebound_traits<Alloc, Deleter>::allocate(alloc, 1);
|
|
|
|
+ rebound_traits<Alloc, Deleter>::construct(alloc, cb, 1, 0, p, d);
|
|
|
|
+
|
|
|
|
+ ptr = p;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ template <typename Deleter, typename Alloc>
|
|
|
|
+ __GBLIBCPP_CONSTEXPR explicit shared_ptr(std::nullptr_t, Deleter d,
|
|
|
|
+ Alloc alloc) {
|
|
|
|
+ cb = rebound_traits<Alloc, Deleter>::allocate(alloc, 1);
|
|
|
|
+ rebound_traits<Alloc, Deleter>::construct(alloc, cb, 1, 0, nullptr, d);
|
|
|
|
+ }
|
|
|
|
|
|
- template <typename U>
|
|
|
|
__GBLIBCPP_CONSTEXPR
|
|
__GBLIBCPP_CONSTEXPR
|
|
- shared_ptr(const shared_ptr<U>& other) noexcept
|
|
|
|
- : cb(other.cb) { inc_ref(); }
|
|
|
|
|
|
+ shared_ptr(const shared_ptr& other) noexcept
|
|
|
|
+ : cb(other.cb), ptr(other.ptr) {
|
|
|
|
+ inc_ref();
|
|
|
|
+ }
|
|
|
|
|
|
__GBLIBCPP_CONSTEXPR
|
|
__GBLIBCPP_CONSTEXPR
|
|
shared_ptr(shared_ptr&& other) noexcept
|
|
shared_ptr(shared_ptr&& other) noexcept
|
|
- : cb(std::exchange(other.cb, nullptr)) { }
|
|
|
|
|
|
+ : cb(std::exchange(other.cb, nullptr))
|
|
|
|
+ , ptr(std::exchange(other.ptr, nullptr)) {}
|
|
|
|
+
|
|
|
|
+ template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
|
|
|
|
+ __GBLIBCPP_CONSTEXPR shared_ptr(const shared_ptr<U>& other) noexcept
|
|
|
|
+ : cb((control_block_base*)other.cb), ptr((T*)other.ptr) {
|
|
|
|
+ inc_ref();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
|
|
|
|
+ __GBLIBCPP_CONSTEXPR shared_ptr(shared_ptr<U>&& other) noexcept
|
|
|
|
+ : cb((control_block_base*)std::exchange(other.cb, nullptr))
|
|
|
|
+ , ptr((T*)std::exchange(other.ptr, nullptr)) {}
|
|
|
|
|
|
- template <typename U>
|
|
|
|
- __GBLIBCPP_CONSTEXPR
|
|
|
|
- shared_ptr(shared_ptr<U>&& other) noexcept
|
|
|
|
- : cb(std::exchange(other.cb, nullptr)) { }
|
|
|
|
-
|
|
|
|
// TODO: weak_ptr and unique_ptr
|
|
// TODO: weak_ptr and unique_ptr
|
|
|
|
|
|
__GBLIBCPP_CONSTEXPR
|
|
__GBLIBCPP_CONSTEXPR
|
|
- ~shared_ptr() { dec_ref(); }
|
|
|
|
|
|
+ ~shared_ptr() {
|
|
|
|
+ dec_ref();
|
|
|
|
+ cb = nullptr;
|
|
|
|
+ ptr = nullptr;
|
|
|
|
+ }
|
|
|
|
|
|
__GBLIBCPP_CONSTEXPR
|
|
__GBLIBCPP_CONSTEXPR
|
|
- shared_ptr& operator=(const shared_ptr& other) noexcept
|
|
|
|
- {
|
|
|
|
- if (cb != other.cb) {
|
|
|
|
- dec_ref();
|
|
|
|
- cb = other.cb;
|
|
|
|
- inc_ref();
|
|
|
|
- }
|
|
|
|
|
|
+ shared_ptr& operator=(const shared_ptr& other) noexcept {
|
|
|
|
+ shared_ptr{other}.swap(*this);
|
|
return *this;
|
|
return *this;
|
|
}
|
|
}
|
|
|
|
|
|
- template <typename U>
|
|
|
|
- __GBLIBCPP_CONSTEXPR
|
|
|
|
- shared_ptr& operator=(const shared_ptr<U>& other) noexcept
|
|
|
|
- {
|
|
|
|
- if (cb != other.cb) {
|
|
|
|
- dec_ref();
|
|
|
|
- cb = other.cb;
|
|
|
|
- inc_ref();
|
|
|
|
- }
|
|
|
|
|
|
+ template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
|
|
|
|
+ __GBLIBCPP_CONSTEXPR shared_ptr& operator=(
|
|
|
|
+ const shared_ptr<U>& other) noexcept {
|
|
|
|
+ shared_ptr{other}.swap(*this);
|
|
return *this;
|
|
return *this;
|
|
}
|
|
}
|
|
|
|
|
|
__GBLIBCPP_CONSTEXPR
|
|
__GBLIBCPP_CONSTEXPR
|
|
- shared_ptr& operator=(shared_ptr&& other) noexcept
|
|
|
|
- {
|
|
|
|
- if (cb != other.cb) {
|
|
|
|
- dec_ref();
|
|
|
|
- cb = std::exchange(other.cb, nullptr);
|
|
|
|
- }
|
|
|
|
|
|
+ shared_ptr& operator=(shared_ptr&& other) noexcept {
|
|
|
|
+ shared_ptr{move(other)}.swap(*this);
|
|
return *this;
|
|
return *this;
|
|
}
|
|
}
|
|
|
|
|
|
- template <typename U>
|
|
|
|
- __GBLIBCPP_CONSTEXPR
|
|
|
|
- shared_ptr& operator=(shared_ptr<U>&& other) noexcept
|
|
|
|
- {
|
|
|
|
- if (cb != other.cb) {
|
|
|
|
- dec_ref();
|
|
|
|
- cb = std::exchange(other.cb, nullptr);
|
|
|
|
- }
|
|
|
|
|
|
+ template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
|
|
|
|
+ __GBLIBCPP_CONSTEXPR shared_ptr& operator=(shared_ptr<U>&& other) noexcept {
|
|
|
|
+ shared_ptr{move(other)}.swap(*this);
|
|
return *this;
|
|
return *this;
|
|
}
|
|
}
|
|
|
|
|
|
__GBLIBCPP_CONSTEXPR
|
|
__GBLIBCPP_CONSTEXPR
|
|
- element_type* get() const noexcept
|
|
|
|
- { return cb ? cb->ptr : nullptr; }
|
|
|
|
|
|
+ element_type* get() const noexcept { return cb ? ptr : nullptr; }
|
|
|
|
|
|
__GBLIBCPP_CONSTEXPR
|
|
__GBLIBCPP_CONSTEXPR
|
|
- explicit operator bool() const noexcept
|
|
|
|
- { return get(); }
|
|
|
|
|
|
+ explicit operator bool() const noexcept { return get(); }
|
|
|
|
|
|
__GBLIBCPP_CONSTEXPR
|
|
__GBLIBCPP_CONSTEXPR
|
|
T& operator*() const noexcept { return *get(); }
|
|
T& operator*() const noexcept { return *get(); }
|
|
@@ -572,45 +581,159 @@ public:
|
|
long use_count() const noexcept { return cb ? cb->ref_count : 0; }
|
|
long use_count() const noexcept { return cb ? cb->ref_count : 0; }
|
|
|
|
|
|
__GBLIBCPP_CONSTEXPR
|
|
__GBLIBCPP_CONSTEXPR
|
|
- bool owner_before(const shared_ptr& other) const noexcept
|
|
|
|
- { return cb < other.cb; }
|
|
|
|
|
|
+ bool owner_before(const shared_ptr& other) const noexcept {
|
|
|
|
+ return cb < other.cb;
|
|
|
|
+ }
|
|
|
|
|
|
__GBLIBCPP_CONSTEXPR
|
|
__GBLIBCPP_CONSTEXPR
|
|
- void swap(shared_ptr& other) noexcept { std::swap(cb->ptr, other.cb->ptr); }
|
|
|
|
|
|
+ void swap(shared_ptr& other) noexcept {
|
|
|
|
+ std::swap(cb, other.cb);
|
|
|
|
+ std::swap(ptr, other.ptr);
|
|
|
|
+ }
|
|
|
|
|
|
__GBLIBCPP_CONSTEXPR
|
|
__GBLIBCPP_CONSTEXPR
|
|
- void reset() noexcept { dec_ref(); cb = nullptr; }
|
|
|
|
|
|
+ void reset() noexcept { shared_ptr{}.swap(*this); }
|
|
|
|
|
|
- template <typename U>
|
|
|
|
- __GBLIBCPP_CONSTEXPR
|
|
|
|
- void reset(U* ptr) noexcept
|
|
|
|
- { dec_ref(); cb = new default_control_block { 1, 0, ptr }; }
|
|
|
|
|
|
+ template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
|
|
|
|
+ __GBLIBCPP_CONSTEXPR void reset(U* p) noexcept {
|
|
|
|
+ shared_ptr{p}.swap(*this);
|
|
|
|
+ }
|
|
|
|
|
|
- template <typename U, typename Deleter>
|
|
|
|
- __GBLIBCPP_CONSTEXPR
|
|
|
|
- void reset(U* ptr, Deleter d) noexcept
|
|
|
|
- { dec_ref(); cb = new control_block<Deleter> { 1, 0, ptr, d }; }
|
|
|
|
-
|
|
|
|
- // TODO: what the fuck
|
|
|
|
- // template <typename U, typename Deleter, typename Allocator>
|
|
|
|
- // __GBLIBCPP_CONSTEXPR
|
|
|
|
- // void reset(U* ptr, Deleter d, Allocator alloc)
|
|
|
|
- // {
|
|
|
|
- // dec_ref();
|
|
|
|
- // cb = std::allocator_traits<
|
|
|
|
- // rebind_allocator<Deleter>>::allocate(alloc, 1);
|
|
|
|
-
|
|
|
|
- // std::allocator_traits<
|
|
|
|
- // rebind_allocator<Deleter>>::construct(alloc, cb, 1, 0, ptr, d);
|
|
|
|
- // }
|
|
|
|
|
|
+ template <typename U, typename Deleter,
|
|
|
|
+ enable_if_t<is_convertible_v<U*, T*>, bool> = true>
|
|
|
|
+ __GBLIBCPP_CONSTEXPR void reset(U* p, Deleter d) noexcept {
|
|
|
|
+ shared_ptr{p, d}.swap(*this);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ template <typename U, typename Deleter, typename Allocator,
|
|
|
|
+ enable_if_t<is_convertible_v<U*, T*>, bool> = true>
|
|
|
|
+ __GBLIBCPP_CONSTEXPR void reset(U* p, Deleter d, Allocator alloc) {
|
|
|
|
+ shared_ptr{p, d, alloc}.swap(*this);
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+template <typename T, typename Deleter = std::default_delete<T>>
|
|
|
|
+class unique_ptr {
|
|
|
|
+ public:
|
|
|
|
+ using element_type = T;
|
|
|
|
+ using deleter_type = Deleter;
|
|
|
|
+ using pointer = element_type*;
|
|
|
|
+
|
|
|
|
+ template <typename U, typename UDeleter>
|
|
|
|
+ friend class unique_ptr;
|
|
|
|
+
|
|
|
|
+ private:
|
|
|
|
+ impl::compressed_pair<pointer, deleter_type> data;
|
|
|
|
+
|
|
|
|
+ public:
|
|
|
|
+ __GBLIBCPP_CONSTEXPR unique_ptr() noexcept
|
|
|
|
+ : data{impl::default_construct_t{}} {}
|
|
|
|
+ __GBLIBCPP_CONSTEXPR unique_ptr(std::nullptr_t) noexcept : unique_ptr{} {}
|
|
|
|
+ __GBLIBCPP_CONSTEXPR unique_ptr(pointer p) noexcept
|
|
|
|
+ : data{p, deleter_type{}} {}
|
|
|
|
+ __GBLIBCPP_CONSTEXPR unique_ptr(pointer p, const deleter_type& d) noexcept
|
|
|
|
+ : data{p, d} {}
|
|
|
|
+ __GBLIBCPP_CONSTEXPR unique_ptr(pointer p, deleter_type&& d) noexcept
|
|
|
|
+ : data{p, std::move(d)} {}
|
|
|
|
+ __GBLIBCPP_CONSTEXPR unique_ptr(const unique_ptr&) = delete;
|
|
|
|
+
|
|
|
|
+ __GBLIBCPP_CONSTEXPR unique_ptr(unique_ptr&& other) noexcept
|
|
|
|
+ : data{std::exchange(other.data.first(), nullptr),
|
|
|
|
+ std::move(other.data.second())} {}
|
|
|
|
+
|
|
|
|
+ template <
|
|
|
|
+ typename U, typename E,
|
|
|
|
+ std::enable_if_t<!std::is_array_v<U> && std::is_convertible_v<U*, T*> &&
|
|
|
|
+ std::is_convertible_v<E, Deleter>,
|
|
|
|
+ bool> = true>
|
|
|
|
+ __GBLIBCPP_CONSTEXPR unique_ptr(unique_ptr<U, E>&& other) noexcept
|
|
|
|
+ : data{std::exchange(other.data.first(), nullptr),
|
|
|
|
+ std::move(other.data.second())} {}
|
|
|
|
+
|
|
|
|
+ __GBLIBCPP_CONSTEXPR ~unique_ptr() { reset(); }
|
|
|
|
+
|
|
|
|
+ __GBLIBCPP_CONSTEXPR unique_ptr& operator=(const unique_ptr&) = delete;
|
|
|
|
+ __GBLIBCPP_CONSTEXPR unique_ptr& operator=(std::nullptr_t) noexcept {
|
|
|
|
+ reset();
|
|
|
|
+ return *this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ __GBLIBCPP_CONSTEXPR unique_ptr& operator=(unique_ptr&& other) noexcept {
|
|
|
|
+ reset(other.release());
|
|
|
|
+ get_deleter() = std::move(other.get_deleter());
|
|
|
|
+ return *this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ template <
|
|
|
|
+ typename U, typename E,
|
|
|
|
+ std::enable_if_t<!std::is_array_v<U> && std::is_convertible_v<U*, T*> &&
|
|
|
|
+ std::is_assignable_v<Deleter&, E&&>,
|
|
|
|
+ bool> = true>
|
|
|
|
+ __GBLIBCPP_CONSTEXPR unique_ptr& operator=(
|
|
|
|
+ unique_ptr<U, E>&& other) noexcept {
|
|
|
|
+ reset(other.release());
|
|
|
|
+ get_deleter() = std::move(other.get_deleter());
|
|
|
|
+ return *this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ __GBLIBCPP_CONSTEXPR void swap(unique_ptr& other) noexcept {
|
|
|
|
+ std::swap(data, other.data);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ __GBLIBCPP_CONSTEXPR pointer get() const noexcept { return data.first(); }
|
|
|
|
+ __GBLIBCPP_CONSTEXPR deleter_type& get_deleter() noexcept {
|
|
|
|
+ return data.second();
|
|
|
|
+ }
|
|
|
|
+ __GBLIBCPP_CONSTEXPR const deleter_type& get_deleter() const noexcept {
|
|
|
|
+ return data.second();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ __GBLIBCPP_CONSTEXPR pointer release() noexcept {
|
|
|
|
+ pointer ret = get();
|
|
|
|
+ data.first() = nullptr;
|
|
|
|
+ return ret;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ __GBLIBCPP_CONSTEXPR void reset(pointer p = pointer{}) noexcept {
|
|
|
|
+ pointer old = release();
|
|
|
|
+ data.first() = p;
|
|
|
|
+ if (old)
|
|
|
|
+ get_deleter()(old);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ __GBLIBCPP_CONSTEXPR explicit operator bool() const noexcept {
|
|
|
|
+ return get();
|
|
|
|
+ }
|
|
|
|
+ __GBLIBCPP_CONSTEXPR pointer operator->() const noexcept { return get(); }
|
|
|
|
+
|
|
|
|
+ __GBLIBCPP_CONSTEXPR std::add_lvalue_reference_t<T> operator*() const
|
|
|
|
+ noexcept(noexcept(*std::declval<pointer>())) {
|
|
|
|
+ return *get();
|
|
|
|
+ }
|
|
};
|
|
};
|
|
|
|
|
|
// TODO: use only one allocation
|
|
// TODO: use only one allocation
|
|
-// template <typename T, typename... Args>
|
|
|
|
-// std::shared_ptr<T> make_shared(Args&&... args)
|
|
|
|
-// {
|
|
|
|
-// return std::shared_ptr<T>(new T(std::forward<Args>(args)...));
|
|
|
|
-// }
|
|
|
|
|
|
+template <typename T, typename... Args>
|
|
|
|
+std::shared_ptr<T> make_shared(Args&&... args) {
|
|
|
|
+ return std::shared_ptr<T>(new T(std::forward<Args>(args)...));
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+template <typename T, typename... Args>
|
|
|
|
+__GBLIBCPP_CONSTEXPR std::unique_ptr<T> make_unique(Args&&... args) {
|
|
|
|
+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+template <typename T>
|
|
|
|
+__GBLIBCPP_CONSTEXPR void swap(std::shared_ptr<T>& lhs,
|
|
|
|
+ std::shared_ptr<T>& rhs) noexcept {
|
|
|
|
+ lhs.swap(rhs);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+template <typename T, typename D>
|
|
|
|
+__GBLIBCPP_CONSTEXPR void swap(std::unique_ptr<T, D>& lhs,
|
|
|
|
+ std::unique_ptr<T, D>& rhs) noexcept {
|
|
|
|
+ lhs.swap(rhs);
|
|
|
|
+}
|
|
|
|
|
|
} // namespace std
|
|
} // namespace std
|
|
|
|
|