memory 18 KB

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