memory 18 KB

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