/* This file is part of Fennix Kernel. Fennix Kernel is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Fennix Kernel is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>. */ #pragma once #include <type_traits> #include <functional> #include <cstddef> #include <utility> #include <limits> #include <new> #include <debug.h> namespace std { namespace __memory__detail { template <class> constexpr bool is_unbounded_array_v = false; template <class T> constexpr bool is_unbounded_array_v<T[]> = true; template <class> constexpr bool is_bounded_array_v = false; template <class T, std::size_t N> constexpr bool is_bounded_array_v<T[N]> = true; } template <class T, class... Args> constexpr T *construct_at(T *p, Args &&...args) { return ::new (static_cast<void *>(p)) T(std::forward<Args>(args)...); } template <class T> constexpr void destroy_at(T *p) { p->~T(); } template <class T> T *addressof(T &arg) { return reinterpret_cast<T *>(&const_cast<char &>(reinterpret_cast<const volatile char &>(arg))); } template <class T> const T *addressof(const T &&) = delete; template <class InputIt, class Size, class NoThrowForwardIt> NoThrowForwardIt uninitialized_copy_n(InputIt first, Size count, NoThrowForwardIt d_first) { using ValueType = typename std::iterator_traits<NoThrowForwardIt>::value_type; NoThrowForwardIt current = d_first; try { for (Size i = 0; i < count; ++i, (void)++current, ++first) { ::new (static_cast<void *>(std::addressof(*current))) ValueType(*first); } return current; } catch (...) { for (; d_first != current; ++d_first) { d_first->~ValueType(); } throw; } } template <class ExecutionPolicy, class ForwardIt, class Size, class NoThrowForwardIt> NoThrowForwardIt uninitialized_copy_n(ExecutionPolicy &&policy, ForwardIt first, Size count, NoThrowForwardIt d_first) { return uninitialized_copy_n(first, count, d_first); } template <class ForwardIt, class Size, class T> ForwardIt uninitialized_fill_n(ForwardIt first, Size count, const T &value) { using V = typename std::iterator_traits<ForwardIt>::value_type; ForwardIt current = first; try { for (; count > 0; ++current, (void)--count) ::new (static_cast<void *>(std::addressof(*current))) V(value); return current; } catch (...) { for (; first != current; ++first) first->~V(); throw; } } template <class ExecutionPolicy, class ForwardIt, class Size, class T> ForwardIt uninitialized_fill_n(ExecutionPolicy &&policy, ForwardIt first, Size count, const T &value) { return uninitialized_fill_n(first, count, value); } template <class Ptr> struct pointer_traits { using pointer = Ptr; using element_type = typename Ptr::element_type; using difference_type = typename Ptr::difference_type; template <class U> using rebind = typename Ptr::template rebind<U>; static pointer pointer_to(element_type &r) noexcept { return Ptr::pointer_to(r); } }; template <class T> struct pointer_traits<T *> { using pointer = T *; using element_type = T; using difference_type = std::ptrdiff_t; template <class U> using rebind = U *; static pointer pointer_to(element_type &r) noexcept { return std::addressof(r); } }; template <class Pointer, class SizeType = std::size_t> struct allocation_result { Pointer ptr; SizeType count; }; template <class Alloc> struct allocator_traits { typedef Alloc allocator_type; typedef typename Alloc::value_type value_type; typedef typename Alloc::pointer pointer; typedef typename Alloc::const_pointer const_pointer; // typedef typename Alloc::void_pointer void_pointer; // typedef typename Alloc::const_void_pointer const_void_pointer; // typedef typename std::pointer_traits<pointer>::rebind<void> void_pointer; // typedef typename std::pointer_traits<pointer>::rebind<const void> const_void_pointer; typedef typename Alloc::difference_type difference_type; typedef typename Alloc::size_type size_type; // typedef typename Alloc::propagate_on_container_copy_assignment propagate_on_container_copy_assignment; typedef typename std::false_type propagate_on_container_copy_assignment; typedef typename Alloc::propagate_on_container_move_assignment propagate_on_container_move_assignment; typedef typename std::false_type propagate_on_container_swap; typedef typename Alloc::is_always_equal is_always_equal; template <class T> using rebind_alloc = typename Alloc::template rebind<T>::other; template <class T> using rebind_traits = allocator_traits<rebind_alloc<T>>; [[nodiscard]] static constexpr pointer allocate(Alloc &a, size_type n) { return a.allocate(n); } // [[nodiscard]] static constexpr pointer allocate(Alloc &a, size_type n, const_void_pointer hint) // { // return a.allocate(n, hint); // } [[nodiscard]] static constexpr std::allocation_result<pointer, size_type> allocate_at_least(Alloc &a, size_type n) { return a.allocate_at_least(n); } static constexpr void deallocate(Alloc &a, pointer p, size_type n) { a.deallocate(p, n); } template <class T, class... Args> static constexpr void construct(Alloc &a, T *p, Args &&...args) { std::construct_at(p, std::forward<Args>(args)...); } template <class T> static constexpr void destroy(Alloc &a, T *p) { std::destroy_at(p); } static constexpr size_type max_size(const Alloc &a) { return a.max_size(); } static constexpr Alloc select_on_container_copy_construction(const Alloc &a) { return a; } }; template <class T> struct allocator { public: typedef T value_type; typedef T *pointer; typedef const T *const_pointer; typedef T &reference; typedef const T &const_reference; typedef std::size_t size_type; typedef std::ptrdiff_t difference_type; typedef std::true_type propagate_on_container_move_assignment; typedef std::true_type is_always_equal; template <class U> struct rebind { typedef allocator<U> other; }; allocator() {} allocator(const allocator &other) {} template <class U> allocator(const allocator<U> &other) {} ~allocator() {} pointer allocate(size_type n, const void *hint = 0) { return static_cast<pointer>(::operator new(n * sizeof(T))); } std::allocation_result<T *, std::size_t> allocate_at_least(std::size_t n) { return {static_cast<T *>(::operator new(n * sizeof(T))), n}; } void deallocate(T *p, std::size_t n) { ::operator delete(p); } pointer address(reference x) const { return &x; } const_pointer address(const_reference x) const { return &x; } }; template <class T> struct default_delete { constexpr default_delete() noexcept = default; template <class U> constexpr default_delete(const default_delete<U> &d) noexcept {} constexpr void operator()(T *ptr) const { delete ptr; } }; template <class T> struct default_delete<T[]> { constexpr default_delete() noexcept = default; template <class U> constexpr default_delete(const default_delete<U[]> &d) noexcept {} template <class U> constexpr void operator()(U *ptr) const { delete[] ptr; } }; template <class T, class Deleter = std::default_delete<T>> class unique_ptr { public: using pointer = T *; // std::remove_reference<Deleter>::type::pointer; using element_type = T; using deleter_type = Deleter; private: pointer _ptr; public: #pragma region Member Functions constexpr unique_ptr() noexcept : _ptr(nullptr) {} constexpr unique_ptr(std::nullptr_t) noexcept : _ptr(nullptr) {} constexpr explicit unique_ptr(pointer p) noexcept : _ptr(p) {} // constexpr unique_ptr(pointer p, /* TODO */ d1) noexcept : _ptr(p) {} // constexpr unique_ptr(pointer p, /* TODO */ d2) noexcept : _ptr(p) {} constexpr unique_ptr(unique_ptr &&u) noexcept : _ptr(u.release()) {} template <class U, class E> constexpr unique_ptr(unique_ptr<U, E> &&u) noexcept : _ptr(u.release()) {} unique_ptr(const unique_ptr &) = delete; ~unique_ptr() { if (_ptr == nullptr) return; Deleter d; d(_ptr); } constexpr unique_ptr &operator=(unique_ptr &&r) noexcept { reset(r.release()); return *this; } template <class U, class E> constexpr unique_ptr &operator=(unique_ptr<U, E> &&r) noexcept { reset(r.release()); return *this; } constexpr unique_ptr &operator=(std::nullptr_t) noexcept { reset(); return *this; } unique_ptr &operator=(const unique_ptr &) = delete; #pragma endregion Member Functions #pragma region Modifiers constexpr pointer release() noexcept { pointer p = _ptr; _ptr = nullptr; return p; } constexpr void reset(pointer ptr = pointer()) noexcept { Deleter d; d(_ptr); _ptr = ptr; } void swap(unique_ptr &other) noexcept { pointer tmp = _ptr; _ptr = other._ptr; other._ptr = tmp; } #pragma endregion Modifiers #pragma region Observers constexpr pointer get() const noexcept { return _ptr; } constexpr Deleter &get_deleter() noexcept { return _ptr; } constexpr const Deleter &get_deleter() const noexcept { return _ptr; } constexpr explicit operator bool() const noexcept { return get() != nullptr; } #pragma endregion Observers #pragma region Element Access constexpr typename std::add_lvalue_reference<T>::type operator*() const noexcept(noexcept(*std::declval<pointer>())) { return *_ptr; } constexpr pointer operator->() const noexcept { return _ptr; } #pragma endregion Element Access }; template <class T, class Deleter> class unique_ptr<T[], Deleter> { public: using pointer = T *; // std::remove_reference<Deleter>::type::pointer; using element_type = T; using deleter_type = Deleter; private: pointer _ptr; public: #pragma region Member Functions constexpr unique_ptr() noexcept : _ptr(nullptr) {} constexpr unique_ptr(std::nullptr_t) noexcept : _ptr(nullptr) {} template <class U> constexpr explicit unique_ptr(U p) noexcept : _ptr(p) {} // template <class U> // constexpr unique_ptr(U p, /* TODO */ d1) noexcept : _ptr(p) {} // template <class U> // constexpr unique_ptr(U p, /* TODO */ d2) noexcept : _ptr(p) {} constexpr unique_ptr(unique_ptr &&u) noexcept : _ptr(u.release()) {} template <class U, class E> constexpr unique_ptr(unique_ptr<U, E> &&u) noexcept : _ptr(u.release()) {} unique_ptr(const unique_ptr &) = delete; ~unique_ptr() { if (_ptr == nullptr) return; Deleter d; d(_ptr); } constexpr unique_ptr &operator=(unique_ptr &&r) noexcept { reset(r.release()); return *this; } template <class U, class E> constexpr unique_ptr &operator=(unique_ptr<U, E> &&r) noexcept { reset(r.release()); return *this; } constexpr unique_ptr &operator=(std::nullptr_t) noexcept { reset(); return *this; } unique_ptr &operator=(const unique_ptr &) = delete; #pragma endregion Member Functions #pragma region Modifiers constexpr pointer release() noexcept { pointer p = _ptr; _ptr = nullptr; return p; } template <class U> constexpr void reset(U ptr) noexcept { Deleter d; d(_ptr); _ptr = ptr; } constexpr void reset(std::nullptr_t = nullptr) noexcept { Deleter d; d(_ptr); _ptr = nullptr; } void swap(unique_ptr &other) noexcept { pointer tmp = _ptr; _ptr = other._ptr; other._ptr = tmp; } #pragma endregion Modifiers #pragma region Observers constexpr pointer get() const noexcept { return _ptr; } constexpr Deleter &get_deleter() noexcept { return _ptr; } constexpr const Deleter &get_deleter() const noexcept { return _ptr; } constexpr explicit operator bool() const noexcept { return get() != nullptr; } #pragma endregion Observers #pragma region Element Access constexpr T &operator[](std::size_t i) const { return _ptr[i]; } #pragma endregion Element Access }; template <class T, class... Args> std::enable_if_t<!std::is_array<T>::value, std::unique_ptr<T>> make_unique(Args &&...args) { return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); } template <class T> std::enable_if_t<__memory__detail::is_unbounded_array_v<T>, std::unique_ptr<T>> make_unique(std::size_t n) { return std::unique_ptr<T>(new std::remove_extent_t<T>[n]()); } template <class T, class... Args> std::enable_if_t<__memory__detail::is_bounded_array_v<T>> make_unique(Args &&...) = delete; template <class T> requires(!std::is_array_v<T>) std::unique_ptr<T> make_unique_for_overwrite() { return std::unique_ptr<T>(new T); } template <class T> requires std::is_unbounded_array_v<T> std::unique_ptr<T> make_unique_for_overwrite(std::size_t n) { return std::unique_ptr<T>(new std::remove_extent_t<T>[n]); } template <class T, class... Args> requires std::is_bounded_array_v<T> void make_unique_for_overwrite(Args &&...) = delete; template <class T1, class D1, class T2, class D2> constexpr bool operator==(const unique_ptr<T1, D1> &x, const unique_ptr<T2, D2> &y) { return x.get() == y.get(); } template <class T1, class D1, class T2, class D2> bool operator<(const unique_ptr<T1, D1> &x, const unique_ptr<T2, D2> &y) { return std::less<typename std::common_type<typename unique_ptr<T1, D1>::pointer, typename unique_ptr<T2, D2>::pointer>::type>()(x.get(), y.get()); } template <class T1, class D1, class T2, class D2> bool operator<=(const unique_ptr<T1, D1> &x, const unique_ptr<T2, D2> &y) { return !(y < x); } template <class T1, class D1, class T2, class D2> bool operator>(const unique_ptr<T1, D1> &x, const unique_ptr<T2, D2> &y) { return y < x; } template <class T1, class D1, class T2, class D2> bool operator>=(const unique_ptr<T1, D1> &x, const unique_ptr<T2, D2> &y) { return !(x < y); } // operator<=>(const unique_ptr<T1, D1> &x, const unique_ptr<T2, D2> &y); template <class T, class D> constexpr bool operator==(const unique_ptr<T, D> &x, std::nullptr_t) noexcept { return !x; } template <class T, class D> constexpr bool operator<(const unique_ptr<T, D> &x, std::nullptr_t) { return std::less<typename unique_ptr<T, D>::pointer>()(x.get(), nullptr); } template <class T, class D> constexpr bool operator<(std::nullptr_t, const unique_ptr<T, D> &y) { return std::less<typename unique_ptr<T, D>::pointer>()(nullptr, y.get()); } template <class T, class D> constexpr bool operator<=(const unique_ptr<T, D> &x, std::nullptr_t) { return !(nullptr < x); } template <class T, class D> constexpr bool operator<=(std::nullptr_t, const unique_ptr<T, D> &y) { return !(y < nullptr); } template <class T, class D> constexpr bool operator>(const unique_ptr<T, D> &x, std::nullptr_t) { return nullptr < x; } template <class T, class D> constexpr bool operator>(std::nullptr_t, const unique_ptr<T, D> &y) { return y < nullptr; } template <class T, class D> constexpr bool operator>=(const unique_ptr<T, D> &x, std::nullptr_t) { return !(x < nullptr); } template <class T, class D> constexpr bool operator>=(std::nullptr_t, const unique_ptr<T, D> &y) { return !(nullptr < y); } // operator<=>(const unique_ptr<T, D> &x, std::nullptr_t); // template <class CharT, class Traits, class Y, class D> // std::basic_ostream<CharT, Traits> &operator<<(std::basic_ostream<CharT, Traits> &os, const std::unique_ptr<Y, D> &p) // { // return os << p.get(); // } template <class T, class D> void swap(std::unique_ptr<T, D> &lhs, std::unique_ptr<T, D> &rhs) noexcept { lhs.swap(rhs); } }