memory 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740
  1. #ifndef __GBLIBCPP_MEMORY__
  2. #define __GBLIBCPP_MEMORY__
  3. #include <bits/compressed_pair>
  4. #include <cstddef>
  5. #include <new>
  6. #include <type_traits>
  7. #include <utility>
  8. namespace std {
  9. template <typename T>
  10. constexpr T* addressof(T& arg) noexcept {
  11. return __builtin_addressof(arg);
  12. }
  13. // template <typename T>
  14. // constexpr enable_if_t<is_function_v<remove_reference_t<T>>, T*>
  15. // addressof(T& arg) noexcept
  16. // {
  17. // return &arg;
  18. // }
  19. // template <typename T>
  20. // constexpr enable_if_t<!is_function_v<remove_reference_t<T>>, T*>
  21. // addressof(T& arg) noexcept
  22. // {
  23. // return reinterpret_cast<T*>(
  24. // &const_cast<char&>(
  25. // reinterpret_cast<const volatile char&>(arg)
  26. // )
  27. // );
  28. // }
  29. template <typename T>
  30. const T* addressof(const T&&) = delete;
  31. namespace __helpers {
  32. template <typename Ptr, typename = void>
  33. struct pointer_difference_type {
  34. using type = std::ptrdiff_t;
  35. };
  36. template <typename Ptr>
  37. struct pointer_difference_type<Ptr,
  38. std::void_t<typename Ptr::difference_type>> {
  39. using type = typename Ptr::difference_type;
  40. };
  41. template <typename Ptr>
  42. using pointer_difference_type_t =
  43. typename pointer_difference_type<Ptr>::type;
  44. template <typename Base, typename T>
  45. struct rebind;
  46. template <template <typename, typename...> typename Template,
  47. typename NewType, typename OldType, typename... Args>
  48. struct rebind<Template<OldType, Args...>, NewType> {
  49. using type = Template<NewType, Args...>;
  50. };
  51. template <typename Ptr, typename T, typename = void>
  52. struct try_rebind {
  53. using type = typename rebind<Ptr, T>::type;
  54. };
  55. template <typename Ptr, typename T>
  56. struct try_rebind<Ptr, T, std::void_t<typename Ptr::template rebind<T>>> {
  57. using type = typename Ptr::template rebind<T>;
  58. };
  59. template <typename Ptr, typename = void>
  60. struct pointer_element {};
  61. template <typename Ptr>
  62. struct pointer_element<
  63. Ptr, std::enable_if_t<std::is_same_v<
  64. void, std::void_t<typename Ptr::element_type>>>> {
  65. using type = typename Ptr::element_type;
  66. };
  67. template <template <typename, typename...> typename Template, typename T,
  68. typename... Args>
  69. struct pointer_element<Template<T, Args...>, void> {
  70. using type = T;
  71. };
  72. template <typename Ptr, typename = void>
  73. struct pointer_traits_impl {};
  74. template <typename Ptr>
  75. struct pointer_traits_impl<
  76. Ptr, std::void_t<typename pointer_element<Ptr>::type>> {
  77. using pointer = Ptr;
  78. using element_type = typename pointer_element<Ptr>::type;
  79. using difference_type = pointer_difference_type_t<Ptr>;
  80. template <typename U>
  81. using rebind = typename try_rebind<Ptr, U>::type;
  82. static pointer pointer_to(element_type& ref) {
  83. return Ptr::pointer_to(ref);
  84. }
  85. };
  86. template <typename T>
  87. struct pointer_traits_impl<T*, void> {
  88. using pointer = T*;
  89. using element_type = T;
  90. using difference_type = std::ptrdiff_t;
  91. template <typename U>
  92. using rebind = U*;
  93. static pointer pointer_to(element_type& ref) {
  94. return std::addressof(ref);
  95. }
  96. };
  97. } // namespace __helpers
  98. template <typename Ptr>
  99. struct pointer_traits : public __helpers::pointer_traits_impl<Ptr> {};
  100. namespace __helpers {
  101. template <typename Alloc, typename = void>
  102. struct allocator_pointer {
  103. using type = typename Alloc::value_type*;
  104. };
  105. template <typename Alloc>
  106. struct allocator_pointer<Alloc, std::void_t<typename Alloc::pointer>> {
  107. using type = typename Alloc::pointer;
  108. };
  109. template <typename Alloc>
  110. using allocator_pointer_t = typename allocator_pointer<Alloc>::type;
  111. template <typename Alloc, typename Pointer, typename = void>
  112. struct allocator_const_pointer {
  113. using type = typename std::pointer_traits<Pointer>::template rebind<
  114. const typename Alloc::value_type>;
  115. };
  116. template <typename Alloc, typename Pointer>
  117. struct allocator_const_pointer<Alloc, Pointer,
  118. std::void_t<typename Alloc::const_pointer>> {
  119. using type = typename Alloc::const_pointer;
  120. };
  121. template <typename Alloc, typename Pointer>
  122. using allocator_const_pointer_t =
  123. typename allocator_const_pointer<Alloc, Pointer>::type;
  124. template <typename Alloc, typename Pointer, typename = void>
  125. struct allocator_void_pointer {
  126. using type =
  127. typename std::pointer_traits<Pointer>::template rebind<void>;
  128. };
  129. template <typename Alloc, typename Pointer>
  130. struct allocator_void_pointer<Alloc, Pointer,
  131. std::void_t<typename Alloc::void_pointer>> {
  132. using type = typename Alloc::void_pointer;
  133. };
  134. template <typename Alloc, typename Pointer>
  135. using allocator_void_pointer_t =
  136. typename allocator_void_pointer<Alloc, Pointer>::type;
  137. template <typename Alloc, typename Pointer, typename = void>
  138. struct allocator_const_void_pointer {
  139. using type =
  140. typename std::pointer_traits<Pointer>::template rebind<const void>;
  141. };
  142. template <typename Alloc, typename Pointer>
  143. struct allocator_const_void_pointer<
  144. Alloc, Pointer, std::void_t<typename Alloc::const_void_pointer>> {
  145. using type = typename Alloc::const_void_pointer;
  146. };
  147. template <typename Alloc, typename Pointer>
  148. using allocator_const_void_pointer_t =
  149. typename allocator_const_void_pointer<Alloc, Pointer>::type;
  150. template <typename Alloc, typename = void>
  151. struct allocator_difference_type {
  152. using type = std::ptrdiff_t;
  153. };
  154. template <typename Alloc>
  155. struct allocator_difference_type<
  156. Alloc, std::void_t<typename Alloc::difference_type>> {
  157. using type = typename Alloc::difference_type;
  158. };
  159. template <typename Alloc>
  160. using allocator_difference_type_t =
  161. typename allocator_difference_type<Alloc>::type;
  162. template <typename Alloc, typename = void>
  163. struct allocator_size_type {
  164. using type = std::size_t;
  165. };
  166. template <typename Alloc>
  167. struct allocator_size_type<Alloc, std::void_t<typename Alloc::size_type>> {
  168. using type = typename Alloc::size_type;
  169. };
  170. template <typename Alloc>
  171. using allocator_size_type_t = typename allocator_size_type<Alloc>::type;
  172. template <typename Alloc, typename = void>
  173. struct allocator_prop_copy {
  174. using type = std::false_type;
  175. };
  176. template <typename Alloc>
  177. struct allocator_prop_copy<
  178. Alloc,
  179. std::void_t<typename Alloc::propagate_on_container_copy_assignment>> {
  180. using type = typename Alloc::propagate_on_container_copy_assignment;
  181. };
  182. template <typename Alloc>
  183. using allocator_prop_copy_t = typename allocator_prop_copy<Alloc>::type;
  184. template <typename Alloc, typename = void>
  185. struct allocator_prop_move {
  186. using type = std::false_type;
  187. };
  188. template <typename Alloc>
  189. struct allocator_prop_move<
  190. Alloc,
  191. std::void_t<typename Alloc::propagate_on_container_move_assignment>> {
  192. using type = typename Alloc::propagate_on_container_move_assignment;
  193. };
  194. template <typename Alloc>
  195. using allocator_prop_move_t = typename allocator_prop_move<Alloc>::type;
  196. template <typename Alloc, typename = void>
  197. struct allocator_prop_swap {
  198. using type = std::false_type;
  199. };
  200. template <typename Alloc>
  201. struct allocator_prop_swap<
  202. Alloc, std::void_t<typename Alloc::propagate_on_container_swap>> {
  203. using type = typename Alloc::propagate_on_container_swap;
  204. };
  205. template <typename Alloc>
  206. using allocator_prop_swap_t = typename allocator_prop_swap<Alloc>::type;
  207. template <typename Alloc, typename = void>
  208. struct is_always_equal {
  209. using type = std::false_type;
  210. };
  211. template <typename Alloc>
  212. struct is_always_equal<Alloc,
  213. std::void_t<typename Alloc::is_always_equal>> {
  214. using type = typename Alloc::is_always_equal;
  215. };
  216. template <typename Alloc>
  217. using is_always_equal_t = typename is_always_equal<Alloc>::type;
  218. template <typename Alloc, typename = void>
  219. struct allocator_select_on_copy {
  220. static constexpr Alloc get(const Alloc& alloc) { return alloc; }
  221. };
  222. template <typename Alloc>
  223. struct allocator_select_on_copy<
  224. Alloc,
  225. std::enable_if_t<std::is_same_v<
  226. void,
  227. std::void_t<
  228. decltype(std::declval<Alloc>()
  229. .select_on_container_copy_construction())>>>> {
  230. static constexpr Alloc get(const Alloc& alloc) {
  231. return alloc.select_on_container_copy_construction();
  232. }
  233. };
  234. template <typename Allocator, typename T, typename = void>
  235. struct allocator_rebind_type {
  236. using type = typename rebind<Allocator, T>::type;
  237. };
  238. template <typename Allocator, typename T>
  239. struct allocator_rebind_type<
  240. Allocator, T,
  241. std::void_t<typename Allocator::template rebind<T>::other>> {
  242. using type = typename Allocator::template rebind<T>::other;
  243. };
  244. } // namespace __helpers
  245. template <typename T>
  246. struct allocator {
  247. using value_type = T;
  248. using propagate_on_container_move_assignment = std::true_type;
  249. constexpr allocator() noexcept = default;
  250. constexpr allocator(const allocator& other) noexcept = default;
  251. template <typename U>
  252. constexpr allocator(const allocator<U>&) noexcept {}
  253. constexpr ~allocator() = default;
  254. // throws std::bad_alloc
  255. [[nodiscard]] constexpr T* allocate(std::size_t n) {
  256. return static_cast<T*>(::operator new(n * sizeof(T)));
  257. }
  258. // TODO: check allocated size
  259. constexpr void deallocate(T* ptr, std::size_t) { ::operator delete(ptr); }
  260. };
  261. template <typename T1, typename T2>
  262. constexpr bool operator==(const allocator<T1>&, const allocator<T2>&) noexcept {
  263. return true;
  264. }
  265. template <typename T, typename... Args>
  266. constexpr std::enable_if_t<
  267. std::is_same_v<T*, decltype(::new(std::declval<void*>())
  268. T(std::declval<Args>()...))>,
  269. T*>
  270. construct_at(T* p, Args&&... args) {
  271. return ::new (static_cast<void*>(p)) T(std::forward<Args>(args)...);
  272. }
  273. template <typename T>
  274. constexpr void destroy_at(T* p) {
  275. // TODO: destroy array
  276. p->~T();
  277. }
  278. template <typename Allocator>
  279. struct allocator_traits {
  280. using allocator_type = Allocator;
  281. using value_type = typename Allocator::value_type;
  282. using pointer = __helpers::allocator_pointer_t<Allocator>;
  283. using const_pointer =
  284. __helpers::allocator_const_pointer_t<Allocator, pointer>;
  285. using void_pointer =
  286. __helpers::allocator_void_pointer_t<Allocator, pointer>;
  287. using const_void_pointer =
  288. __helpers::allocator_const_void_pointer_t<Allocator, pointer>;
  289. using difference_type = __helpers::allocator_difference_type_t<Allocator>;
  290. using size_type = __helpers::allocator_size_type_t<Allocator>;
  291. using propagate_on_container_copy_assignment =
  292. __helpers::allocator_prop_copy_t<Allocator>;
  293. using propagate_on_container_move_assignment =
  294. __helpers::allocator_prop_move_t<Allocator>;
  295. using propagate_on_container_swap =
  296. __helpers::allocator_prop_swap_t<Allocator>;
  297. using is_always_equal = __helpers::is_always_equal_t<Allocator>;
  298. template <typename T>
  299. using rebind_alloc =
  300. typename __helpers::allocator_rebind_type<Allocator, T>::type;
  301. [[nodiscard]] static constexpr pointer allocate(Allocator& alloc,
  302. size_type n) {
  303. return alloc.allocate(n);
  304. }
  305. static constexpr void deallocate(Allocator& alloc, pointer p, size_type n) {
  306. return alloc.deallocate(p, n);
  307. }
  308. template <typename T, typename... Args>
  309. static constexpr void construct(Allocator&, T* p, Args&&... args) {
  310. std::construct_at(p, std::forward<Args>(args)...);
  311. }
  312. template <typename T>
  313. static constexpr void destroy(Allocator&, T* p) {
  314. std::destroy_at(p);
  315. }
  316. static constexpr Allocator select_on_container_copy_construction(
  317. const Allocator& alloc) {
  318. return __helpers::allocator_select_on_copy<Allocator>::get(alloc);
  319. }
  320. };
  321. template <typename T>
  322. struct default_delete {
  323. __GBLIBCPP_CONSTEXPR default_delete() noexcept = default;
  324. template <typename U,
  325. std::enable_if_t<std::is_convertible_v<U*, T*>, bool> = true>
  326. __GBLIBCPP_CONSTEXPR default_delete(const default_delete<U>&) noexcept {}
  327. __GBLIBCPP_CONSTEXPR void operator()(T* p) const { delete p; }
  328. };
  329. // TODO: weak_ptr
  330. template <typename T>
  331. class shared_ptr {
  332. public:
  333. using element_type = std::remove_extent_t<T>;
  334. using pointer = element_type*; // TODO: pointer_traits
  335. using const_pointer = const element_type*;
  336. using reference = element_type&;
  337. using const_reference = const element_type&;
  338. private:
  339. struct control_block_base {
  340. std::size_t ref_count;
  341. std::size_t weak_count;
  342. pointer ptr;
  343. constexpr control_block_base(std::size_t ref_count,
  344. std::size_t weak_count, pointer ptr)
  345. : ref_count(ref_count), weak_count(weak_count), ptr(ptr) {}
  346. virtual constexpr ~control_block_base() = default;
  347. virtual constexpr void do_delete() = 0;
  348. // template <typename U, std::enable_if_t<std::is_convertible_v<T*, U*>,
  349. // bool> = true> constexpr operator typename
  350. // shared_ptr<U>::control_block_base*() const
  351. // {
  352. // return this;
  353. // }
  354. };
  355. template <typename Deleter>
  356. struct control_block : public virtual control_block_base, private Deleter {
  357. using Base = control_block_base;
  358. virtual constexpr ~control_block() = default;
  359. constexpr control_block(std::size_t ref_count, std::size_t weak_count,
  360. pointer ptr)
  361. : control_block_base{ref_count, weak_count, ptr}, Deleter{} {}
  362. template <typename UDeleter>
  363. constexpr control_block(std::size_t ref_count, std::size_t weak_count,
  364. pointer ptr, UDeleter&& deleter)
  365. : control_block_base{ref_count, weak_count, ptr}
  366. , Deleter(std::forward<UDeleter>(deleter)) {}
  367. virtual constexpr void do_delete() override {
  368. if (this->Base::ptr)
  369. this->Deleter::operator()(this->Base::ptr);
  370. this->Base::ptr = nullptr;
  371. }
  372. };
  373. control_block_base* cb{};
  374. pointer ptr{};
  375. void inc_ref() {
  376. if (cb)
  377. ++cb->ref_count; // TODO: lock and atomic
  378. }
  379. void dec_ref() {
  380. if (cb && --cb->ref_count == 0) {
  381. cb->do_delete();
  382. if (cb->weak_count == 0)
  383. delete cb;
  384. }
  385. }
  386. private:
  387. template <typename Allocator, typename Deleter>
  388. using rebound_allocator = typename std::allocator_traits<
  389. Allocator>::template rebind_alloc<control_block<Deleter>>;
  390. template <typename Allocator, typename Deleter>
  391. using rebound_traits =
  392. typename std::allocator_traits<rebound_allocator<Allocator, Deleter>>;
  393. template <typename U>
  394. friend class shared_ptr;
  395. public:
  396. __GBLIBCPP_CONSTEXPR shared_ptr() noexcept = default;
  397. __GBLIBCPP_CONSTEXPR shared_ptr(std::nullptr_t) noexcept : shared_ptr{} {}
  398. template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
  399. __GBLIBCPP_CONSTEXPR explicit shared_ptr(U* p) // TODO: array type
  400. : cb(new control_block<default_delete<T>>{1, 0, p}), ptr(p) {}
  401. template <typename U, typename Deleter,
  402. enable_if_t<is_convertible_v<U*, T*>, bool> = true>
  403. __GBLIBCPP_CONSTEXPR explicit shared_ptr(U* p, Deleter d)
  404. : cb(new control_block<Deleter>{1, 0, p, d}), ptr(p) {}
  405. template <typename Deleter>
  406. __GBLIBCPP_CONSTEXPR explicit shared_ptr(std::nullptr_t, Deleter d)
  407. : cb(new control_block<Deleter>{1, 0, nullptr, d}) {}
  408. template <typename U, typename Deleter, typename Alloc,
  409. enable_if_t<is_convertible_v<U*, T*>, bool> = true>
  410. __GBLIBCPP_CONSTEXPR explicit shared_ptr(U* p, Deleter d, Alloc alloc) {
  411. cb = rebound_traits<Alloc, Deleter>::allocate(alloc, 1);
  412. rebound_traits<Alloc, Deleter>::construct(alloc, cb, 1, 0, p, d);
  413. ptr = p;
  414. }
  415. template <typename Deleter, typename Alloc>
  416. __GBLIBCPP_CONSTEXPR explicit shared_ptr(std::nullptr_t, Deleter d,
  417. Alloc alloc) {
  418. cb = rebound_traits<Alloc, Deleter>::allocate(alloc, 1);
  419. rebound_traits<Alloc, Deleter>::construct(alloc, cb, 1, 0, nullptr, d);
  420. }
  421. __GBLIBCPP_CONSTEXPR
  422. shared_ptr(const shared_ptr& other) noexcept
  423. : cb(other.cb), ptr(other.ptr) {
  424. inc_ref();
  425. }
  426. __GBLIBCPP_CONSTEXPR
  427. shared_ptr(shared_ptr&& other) noexcept
  428. : cb(std::exchange(other.cb, nullptr))
  429. , ptr(std::exchange(other.ptr, nullptr)) {}
  430. template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
  431. __GBLIBCPP_CONSTEXPR shared_ptr(const shared_ptr<U>& other) noexcept
  432. : cb((control_block_base*)other.cb), ptr((T*)other.ptr) {
  433. inc_ref();
  434. }
  435. template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
  436. __GBLIBCPP_CONSTEXPR shared_ptr(shared_ptr<U>&& other) noexcept
  437. : cb((control_block_base*)std::exchange(other.cb, nullptr))
  438. , ptr((T*)std::exchange(other.ptr, nullptr)) {}
  439. // TODO: weak_ptr and unique_ptr
  440. __GBLIBCPP_CONSTEXPR
  441. ~shared_ptr() {
  442. dec_ref();
  443. cb = nullptr;
  444. ptr = nullptr;
  445. }
  446. __GBLIBCPP_CONSTEXPR
  447. shared_ptr& operator=(const shared_ptr& other) noexcept {
  448. shared_ptr{other}.swap(*this);
  449. return *this;
  450. }
  451. template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
  452. __GBLIBCPP_CONSTEXPR shared_ptr& operator=(
  453. const shared_ptr<U>& other) noexcept {
  454. shared_ptr{other}.swap(*this);
  455. return *this;
  456. }
  457. __GBLIBCPP_CONSTEXPR
  458. shared_ptr& operator=(shared_ptr&& other) noexcept {
  459. shared_ptr{move(other)}.swap(*this);
  460. return *this;
  461. }
  462. template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
  463. __GBLIBCPP_CONSTEXPR shared_ptr& operator=(shared_ptr<U>&& other) noexcept {
  464. shared_ptr{move(other)}.swap(*this);
  465. return *this;
  466. }
  467. __GBLIBCPP_CONSTEXPR
  468. element_type* get() const noexcept { return cb ? ptr : nullptr; }
  469. __GBLIBCPP_CONSTEXPR
  470. explicit operator bool() const noexcept { return get(); }
  471. __GBLIBCPP_CONSTEXPR
  472. T& operator*() const noexcept { return *get(); }
  473. __GBLIBCPP_CONSTEXPR
  474. T* operator->() const noexcept { return get(); }
  475. __GBLIBCPP_CONSTEXPR
  476. element_type& operator[](std::size_t i) const noexcept { return get()[i]; }
  477. __GBLIBCPP_CONSTEXPR
  478. long use_count() const noexcept { return cb ? cb->ref_count : 0; }
  479. __GBLIBCPP_CONSTEXPR
  480. bool owner_before(const shared_ptr& other) const noexcept {
  481. return cb < other.cb;
  482. }
  483. __GBLIBCPP_CONSTEXPR
  484. void swap(shared_ptr& other) noexcept {
  485. std::swap(cb, other.cb);
  486. std::swap(ptr, other.ptr);
  487. }
  488. __GBLIBCPP_CONSTEXPR
  489. void reset() noexcept { shared_ptr{}.swap(*this); }
  490. template <typename U, enable_if_t<is_convertible_v<U*, T*>, bool> = true>
  491. __GBLIBCPP_CONSTEXPR void reset(U* p) noexcept {
  492. shared_ptr{p}.swap(*this);
  493. }
  494. template <typename U, typename Deleter,
  495. enable_if_t<is_convertible_v<U*, T*>, bool> = true>
  496. __GBLIBCPP_CONSTEXPR void reset(U* p, Deleter d) noexcept {
  497. shared_ptr{p, d}.swap(*this);
  498. }
  499. template <typename U, typename Deleter, typename Allocator,
  500. enable_if_t<is_convertible_v<U*, T*>, bool> = true>
  501. __GBLIBCPP_CONSTEXPR void reset(U* p, Deleter d, Allocator alloc) {
  502. shared_ptr{p, d, alloc}.swap(*this);
  503. }
  504. };
  505. template <typename T, typename Deleter = std::default_delete<T>>
  506. class unique_ptr {
  507. public:
  508. using element_type = T;
  509. using deleter_type = Deleter;
  510. using pointer = element_type*;
  511. template <typename U, typename UDeleter>
  512. friend class unique_ptr;
  513. private:
  514. impl::compressed_pair<pointer, deleter_type> data;
  515. public:
  516. __GBLIBCPP_CONSTEXPR unique_ptr() noexcept
  517. : data{impl::default_construct_t{}} {}
  518. __GBLIBCPP_CONSTEXPR unique_ptr(std::nullptr_t) noexcept : unique_ptr{} {}
  519. __GBLIBCPP_CONSTEXPR unique_ptr(pointer p) noexcept
  520. : data{p, deleter_type{}} {}
  521. __GBLIBCPP_CONSTEXPR unique_ptr(pointer p, const deleter_type& d) noexcept
  522. : data{p, d} {}
  523. __GBLIBCPP_CONSTEXPR unique_ptr(pointer p, deleter_type&& d) noexcept
  524. : data{p, std::move(d)} {}
  525. __GBLIBCPP_CONSTEXPR unique_ptr(const unique_ptr&) = delete;
  526. __GBLIBCPP_CONSTEXPR unique_ptr(unique_ptr&& other) noexcept
  527. : data{std::exchange(other.data.first(), nullptr),
  528. std::move(other.data.second())} {}
  529. template <
  530. typename U, typename E,
  531. std::enable_if_t<!std::is_array_v<U> && std::is_convertible_v<U*, T*> &&
  532. std::is_convertible_v<E, Deleter>,
  533. bool> = true>
  534. __GBLIBCPP_CONSTEXPR unique_ptr(unique_ptr<U, E>&& other) noexcept
  535. : data{std::exchange(other.data.first(), nullptr),
  536. std::move(other.data.second())} {}
  537. __GBLIBCPP_CONSTEXPR ~unique_ptr() { reset(); }
  538. __GBLIBCPP_CONSTEXPR unique_ptr& operator=(const unique_ptr&) = delete;
  539. __GBLIBCPP_CONSTEXPR unique_ptr& operator=(std::nullptr_t) noexcept {
  540. reset();
  541. return *this;
  542. }
  543. __GBLIBCPP_CONSTEXPR unique_ptr& operator=(unique_ptr&& other) noexcept {
  544. reset(other.release());
  545. get_deleter() = std::move(other.get_deleter());
  546. return *this;
  547. }
  548. template <
  549. typename U, typename E,
  550. std::enable_if_t<!std::is_array_v<U> && std::is_convertible_v<U*, T*> &&
  551. std::is_assignable_v<Deleter&, E&&>,
  552. bool> = true>
  553. __GBLIBCPP_CONSTEXPR unique_ptr& operator=(
  554. unique_ptr<U, E>&& other) noexcept {
  555. reset(other.release());
  556. get_deleter() = std::move(other.get_deleter());
  557. return *this;
  558. }
  559. __GBLIBCPP_CONSTEXPR void swap(unique_ptr& other) noexcept {
  560. std::swap(data, other.data);
  561. }
  562. __GBLIBCPP_CONSTEXPR pointer get() const noexcept { return data.first(); }
  563. __GBLIBCPP_CONSTEXPR deleter_type& get_deleter() noexcept {
  564. return data.second();
  565. }
  566. __GBLIBCPP_CONSTEXPR const deleter_type& get_deleter() const noexcept {
  567. return data.second();
  568. }
  569. __GBLIBCPP_CONSTEXPR pointer release() noexcept {
  570. pointer ret = get();
  571. data.first() = nullptr;
  572. return ret;
  573. }
  574. __GBLIBCPP_CONSTEXPR void reset(pointer p = pointer{}) noexcept {
  575. pointer old = release();
  576. data.first() = p;
  577. if (old)
  578. get_deleter()(old);
  579. }
  580. __GBLIBCPP_CONSTEXPR explicit operator bool() const noexcept {
  581. return get();
  582. }
  583. __GBLIBCPP_CONSTEXPR pointer operator->() const noexcept { return get(); }
  584. __GBLIBCPP_CONSTEXPR std::add_lvalue_reference_t<T> operator*() const
  585. noexcept(noexcept(*std::declval<pointer>())) {
  586. return *get();
  587. }
  588. };
  589. // TODO: use only one allocation
  590. template <typename T, typename... Args>
  591. std::shared_ptr<T> make_shared(Args&&... args) {
  592. return std::shared_ptr<T>(new T(std::forward<Args>(args)...));
  593. }
  594. template <typename T, typename... Args>
  595. __GBLIBCPP_CONSTEXPR std::unique_ptr<T> make_unique(Args&&... args) {
  596. return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
  597. }
  598. template <typename T>
  599. __GBLIBCPP_CONSTEXPR void swap(std::shared_ptr<T>& lhs,
  600. std::shared_ptr<T>& rhs) noexcept {
  601. lhs.swap(rhs);
  602. }
  603. template <typename T, typename D>
  604. __GBLIBCPP_CONSTEXPR void swap(std::unique_ptr<T, D>& lhs,
  605. std::unique_ptr<T, D>& rhs) noexcept {
  606. lhs.swap(rhs);
  607. }
  608. } // namespace std
  609. #endif