/*
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 .
*/
#pragma once
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace std
{
namespace detail
{
template
constexpr bool is_unbounded_array_v = false;
template
constexpr bool is_unbounded_array_v = true;
template
constexpr bool is_bounded_array_v = false;
template
constexpr bool is_bounded_array_v = true;
}
template
constexpr T *construct_at(T *p, Args &&...args)
{
return ::new (static_cast(p)) T(std::forward(args)...);
}
template
constexpr void destroy_at(T *p)
{
p->~T();
}
template
T *addressof(T &arg)
{
return reinterpret_cast(&const_cast(reinterpret_cast(arg)));
}
template
const T *addressof(const T &&) = delete;
template
NoThrowForwardIt uninitialized_copy_n(InputIt first, Size count, NoThrowForwardIt d_first)
{
using ValueType = typename std::iterator_traits::value_type;
NoThrowForwardIt current = d_first;
try
{
for (Size i = 0; i < count; ++i, (void)++current, ++first)
{
::new (static_cast(std::addressof(*current))) ValueType(*first);
}
return current;
}
catch (...)
{
for (; d_first != current; ++d_first)
{
d_first->~ValueType();
}
throw;
}
}
template
NoThrowForwardIt uninitialized_copy_n(ExecutionPolicy &&policy, ForwardIt first, Size count, NoThrowForwardIt d_first)
{
return uninitialized_copy_n(first, count, d_first);
}
template
ForwardIt uninitialized_fill_n(ForwardIt first, Size count, const T &value)
{
using V = typename std::iterator_traits::value_type;
ForwardIt current = first;
try
{
for (; count > 0; ++current, (void)--count)
::new (static_cast(std::addressof(*current))) V(value);
return current;
}
catch (...)
{
for (; first != current; ++first)
first->~V();
throw;
}
}
template
ForwardIt uninitialized_fill_n(ExecutionPolicy &&policy, ForwardIt first, Size count, const T &value)
{
return uninitialized_fill_n(first, count, value);
}
template
struct pointer_traits
{
using pointer = Ptr;
using element_type = typename Ptr::element_type;
using difference_type = typename Ptr::difference_type;
template
using rebind = typename Ptr::template rebind;
static pointer pointer_to(element_type &r) noexcept
{
return Ptr::pointer_to(r);
}
};
template
struct pointer_traits
{
using pointer = T *;
using element_type = T;
using difference_type = std::ptrdiff_t;
template
using rebind = U *;
static pointer pointer_to(element_type &r) noexcept
{
return std::addressof(r);
}
};
template
struct allocation_result
{
Pointer ptr;
SizeType count;
};
template
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::rebind void_pointer;
// typedef typename std::pointer_traits::rebind 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
using rebind_alloc = typename Alloc::template rebind::other;
template
using rebind_traits = allocator_traits>;
[[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 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
static constexpr void construct(Alloc &a, T *p, Args &&...args)
{
std::construct_at(p, std::forward(args)...);
}
template
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
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
struct rebind
{
typedef allocator other;
};
allocator() {}
allocator(const allocator &other) {}
template
allocator(const allocator &other) {}
~allocator() {}
pointer allocate(size_type n, const void *hint = 0)
{
return static_cast(::operator new(n * sizeof(T)));
}
std::allocation_result allocate_at_least(std::size_t n)
{
return {static_cast(::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
struct default_delete
{
constexpr default_delete() noexcept = default;
template
constexpr default_delete(const default_delete &d) noexcept {}
constexpr void operator()(T *ptr) const { delete ptr; }
};
template
struct default_delete
{
constexpr default_delete() noexcept = default;
template
constexpr default_delete(const default_delete &d) noexcept {}
template
constexpr void operator()(U *ptr) const { delete[] ptr; }
};
template >
class unique_ptr
{
public:
using pointer = T *; // std::remove_reference::type::pointer;
using element_type = T;
using deleter_type = Deleter;
private:
pointer _ptr;
public:
#pragma region Constructors
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
constexpr unique_ptr(unique_ptr &&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
constexpr unique_ptr &operator=(unique_ptr &&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 Constructors
#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::type operator*() const noexcept(noexcept(*std::declval())) { return *_ptr; }
constexpr pointer operator->() const noexcept { return _ptr; }
#pragma endregion Element Access
};
template
class unique_ptr
{
public:
using pointer = T *; // std::remove_reference::type::pointer;
using element_type = T;
using deleter_type = Deleter;
private:
pointer _ptr;
public:
#pragma region Constructors
constexpr unique_ptr() noexcept : _ptr(nullptr) {}
constexpr unique_ptr(std::nullptr_t) noexcept : _ptr(nullptr) {}
template
constexpr explicit unique_ptr(U p) noexcept : _ptr(p) {}
// template
// constexpr unique_ptr(U p, /* TODO */ d1) noexcept : _ptr(p) {}
// template
// constexpr unique_ptr(U p, /* TODO */ d2) noexcept : _ptr(p) {}
constexpr unique_ptr(unique_ptr &&u) noexcept : _ptr(u.release()) {}
template
constexpr unique_ptr(unique_ptr &&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
constexpr unique_ptr &operator=(unique_ptr &&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 Constructors
#pragma region Modifiers
constexpr pointer release() noexcept
{
pointer p = _ptr;
_ptr = nullptr;
return p;
}
template
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
std::enable_if_t::value, std::unique_ptr>
make_unique(Args &&...args)
{
return std::unique_ptr(new T(std::forward(args)...));
}
template
std::enable_if_t, std::unique_ptr>
make_unique(std::size_t n)
{
return std::unique_ptr(new std::remove_extent_t[n]());
}
template
std::enable_if_t> make_unique(Args &&...) = delete;
template
requires(!std::is_array_v)
std::unique_ptr make_unique_for_overwrite()
{
return std::unique_ptr(new T);
}
template
requires std::is_unbounded_array_v
std::unique_ptr make_unique_for_overwrite(std::size_t n)
{
return std::unique_ptr(new std::remove_extent_t[n]);
}
template
requires std::is_bounded_array_v
void make_unique_for_overwrite(Args &&...) = delete;
template
constexpr bool operator==(const unique_ptr &x, const unique_ptr &y) { return x.get() == y.get(); }
template
bool operator<(const unique_ptr &x, const unique_ptr &y)
{
return std::less::pointer, typename unique_ptr::pointer>::type>()(x.get(), y.get());
}
template
bool operator<=(const unique_ptr &x, const unique_ptr &y) { return !(y < x); }
template
bool operator>(const unique_ptr &x, const unique_ptr &y) { return y < x; }
template
bool operator>=(const unique_ptr &x, const unique_ptr &y) { return !(x < y); }
// operator<=>(const unique_ptr &x, const unique_ptr &y);
template
constexpr bool operator==(const unique_ptr &x, std::nullptr_t) noexcept { return !x; }
template
constexpr bool operator<(const unique_ptr &x, std::nullptr_t) { return std::less::pointer>()(x.get(), nullptr); }
template
constexpr bool operator<(std::nullptr_t, const unique_ptr &y) { return std::less::pointer>()(nullptr, y.get()); }
template
constexpr bool operator<=(const unique_ptr &x, std::nullptr_t) { return !(nullptr < x); }
template
constexpr bool operator<=(std::nullptr_t, const unique_ptr &y) { return !(y < nullptr); }
template
constexpr bool operator>(const unique_ptr &x, std::nullptr_t) { return nullptr < x; }
template
constexpr bool operator>(std::nullptr_t, const unique_ptr &y) { return y < nullptr; }
template
constexpr bool operator>=(const unique_ptr &x, std::nullptr_t) { return !(x < nullptr); }
template
constexpr bool operator>=(std::nullptr_t, const unique_ptr &y) { return !(nullptr < y); }
// operator<=>(const unique_ptr &x, std::nullptr_t);
// template
// std::basic_ostream &operator<<(std::basic_ostream &os, const std::unique_ptr &p)
// {
// return os << p.get();
// }
template
void swap(std::unique_ptr &lhs, std::unique_ptr &rhs) noexcept
{
lhs.swap(rhs);
}
template
struct uses_allocator : std::integral_constant
{
};
template
constexpr bool uses_allocator_v = uses_allocator::value;
struct allocator_arg_t
{
explicit allocator_arg_t() = default;
};
constexpr std::allocator_arg_t allocator_arg{};
template
class weak_ptr;
template
class shared_ptr
{
private:
struct control_block_base
{
long ref_count;
virtual void destroy() = 0;
virtual void *get_ptr() const = 0;
control_block_base() : ref_count(1) {}
virtual ~control_block_base() = default;
};
template
struct control_block_impl : control_block_base
{
Y *ptr;
Deleter deleter;
void destroy() override { deleter(ptr); }
void *get_ptr() const override { return ptr; }
control_block_impl(Y *p, Deleter d) : ptr(p), deleter(d) {}
~control_block_impl() override {}
};
struct control_block_default : control_block_base
{
T *ptr;
void destroy() override { delete ptr; }
void *get_ptr() const override { return ptr; }
control_block_default(T *p) : ptr(p) {}
~control_block_default() override {}
};
template
struct control_block_alloc : control_block_base
{
Y *ptr;
Deleter deleter;
Alloc alloc;
void destroy() override { deleter(ptr); }
void *get_ptr() const override { return ptr; }
control_block_alloc(Y *p, Deleter d, Alloc a) : ptr(p), deleter(d), alloc(a) {}
~control_block_alloc() override {}
void *operator new(std::size_t sz, Alloc &a)
{
using AllocTraits = std::allocator_traits;
return AllocTraits::allocate(a, sz);
}
void operator delete(void *p, std::size_t sz)
{
::operator delete(p);
}
};
control_block_base *cb;
public:
using weak_type = std::weak_ptr;
using element_type = std::remove_extent_t;
constexpr shared_ptr() noexcept : cb(nullptr) {}
constexpr shared_ptr(std::nullptr_t) noexcept : cb(nullptr) {}
template
explicit shared_ptr(Y *ptr) : cb(ptr ? new control_block_default(ptr) : nullptr) {}
template
shared_ptr(Y *ptr, Deleter d) : cb(ptr ? new control_block_impl(ptr, d) : nullptr) {}
template
shared_ptr(std::nullptr_t ptr, Deleter d) : cb(nullptr) {}
template
shared_ptr(Y *ptr, Deleter d, Alloc alloc)
: cb(ptr ? new(alloc) control_block_alloc(ptr, d, alloc) : nullptr) {}
template
shared_ptr(std::nullptr_t ptr, Deleter d, Alloc alloc) : cb(nullptr) {}
template
shared_ptr(const shared_ptr &r, element_type *ptr) noexcept : cb(r.cb)
{
if (cb)
++cb->ref_count;
}
template
shared_ptr(shared_ptr &&r, element_type *ptr) noexcept : cb(r.cb) { r.cb = nullptr; }
shared_ptr(const shared_ptr &r) noexcept : cb(r.cb)
{
if (cb)
++cb->ref_count;
}
template
shared_ptr(const shared_ptr &r) noexcept : cb(r.cb)
{
if (cb)
++cb->ref_count;
}
shared_ptr(shared_ptr &&r) noexcept : cb(r.cb) { r.cb = nullptr; }
template
shared_ptr(shared_ptr &&r) noexcept : cb(r.cb) { r.cb = nullptr; }
template
explicit shared_ptr(const std::weak_ptr &r) : cb(nullptr) { /* Not implemented */ }
template
shared_ptr(std::unique_ptr &&r) : cb(r.get() ? new control_block_impl(r.release(), Deleter()) : nullptr) {}
~shared_ptr()
{
if (cb)
{
if (--cb->ref_count == 0)
{
cb->destroy();
delete cb;
}
}
}
shared_ptr &operator=(const shared_ptr &r) noexcept
{
if (this != &r)
{
if (cb && --cb->ref_count == 0)
{
cb->destroy();
delete cb;
}
cb = r.cb;
if (cb)
++cb->ref_count;
}
return *this;
}
template
shared_ptr &operator=(const shared_ptr &r) noexcept
{
if (cb && --cb->ref_count == 0)
{
cb->destroy();
delete cb;
}
cb = r.cb;
if (cb)
++cb->ref_count;
return *this;
}
shared_ptr &operator=(shared_ptr &&r) noexcept
{
if (this != &r)
{
if (cb && --cb->ref_count == 0)
{
cb->destroy();
delete cb;
}
cb = r.cb;
r.cb = nullptr;
}
return *this;
}
template
shared_ptr &operator=(shared_ptr &&r) noexcept
{
if (cb && --cb->ref_count == 0)
{
cb->destroy();
delete cb;
}
cb = r.cb;
r.cb = nullptr;
return *this;
}
template
shared_ptr &operator=(std::unique_ptr &&r)
{
reset(r.get(), Deleter());
r.release();
return *this;
}
void reset() noexcept
{
if (cb && --cb->ref_count == 0)
{
cb->destroy();
delete cb;
}
cb = nullptr;
}
template
void reset(Y *ptr)
{
reset();
if (ptr)
cb = new control_block_default(ptr);
}
template
void reset(Y *ptr, Deleter d)
{
reset();
if (ptr)
cb = new control_block_impl(ptr, d);
}
template
void reset(Y *ptr, Deleter d, Alloc alloc)
{
reset();
if (ptr)
cb = new (alloc) control_block_alloc(ptr, d, alloc);
}
void swap(shared_ptr &r) noexcept
{
control_block_base *tmp = cb;
cb = r.cb;
r.cb = tmp;
}
element_type *get() const noexcept { return cb ? static_cast(cb->get_ptr()) : nullptr; }
T &operator*() const noexcept { return *get(); }
T *operator->() const noexcept { return get(); }
element_type &operator[](std::ptrdiff_t idx) const { return get()[idx]; }
long use_count() const noexcept { return cb ? cb->ref_count : 0; }
explicit operator bool() const noexcept { return cb != nullptr; }
template
bool owner_before(const shared_ptr &other) const noexcept { return cb < other.cb; }
template
bool owner_before(const std::weak_ptr &other) const noexcept { return cb < other.cb; }
};
template
shared_ptr make_shared(Args &&...args) { return shared_ptr(new T(std::forward(args)...)); }
template
shared_ptr make_shared(std::size_t N) { return shared_ptr(new T[N]); }
template
shared_ptr make_shared() { return shared_ptr(new T); }
template
shared_ptr make_shared(std::size_t N, const std::remove_extent_t &u) { return shared_ptr(new T[N](u)); }
template
shared_ptr make_shared(const std::remove_extent_t &u) { return shared_ptr(new T(u)); }
template
shared_ptr make_shared_for_overwrite() { return shared_ptr(new T); }
template
shared_ptr make_shared_for_overwrite(std::size_t N) { return shared_ptr(new T[N]); }
template
shared_ptr allocate_shared(const Alloc &alloc, Args &&...args)
{
using AllocTraits = std::allocator_traits;
using U = typename std::remove_extent::type;
Alloc a = alloc;
U *ptr = AllocTraits::allocate(a, 1);
try
{
AllocTraits::construct(a, ptr, std::forward(args)...);
return shared_ptr(ptr, [a](U *p) mutable
{
AllocTraits::destroy(a, p);
AllocTraits::deallocate(a, p, 1); }, a);
}
catch (...)
{
AllocTraits::deallocate(a, ptr, 1);
throw;
}
}
template
shared_ptr allocate_shared(const Alloc &alloc, std::size_t N)
{
using AllocTraits = std::allocator_traits;
using U = typename std::remove_extent::type;
Alloc a = alloc;
U *ptr = AllocTraits::allocate(a, N);
try
{
for (std::size_t i = 0; i < N; ++i)
AllocTraits::construct(a, ptr + i);
return shared_ptr(ptr, [a, N](U *p) mutable
{
for (std::size_t i = 0; i < N; ++i)
AllocTraits::destroy(a, p + i);
AllocTraits::deallocate(a, p, N); }, a);
}
catch (...)
{
AllocTraits::deallocate(a, ptr, N);
throw;
}
}
template
shared_ptr allocate_shared(const Alloc &alloc)
{
return allocate_shared(alloc);
}
template
shared_ptr allocate_shared(const Alloc &alloc, std::size_t N, const std::remove_extent_t &u)
{
using AllocTraits = std::allocator_traits;
using U = typename std::remove_extent::type;
Alloc a = alloc;
U *ptr = AllocTraits::allocate(a, N);
try
{
for (std::size_t i = 0; i < N; ++i)
AllocTraits::construct(a, ptr + i, u);
return shared_ptr(ptr, [a, N](U *p) mutable
{
for (std::size_t i = 0; i < N; ++i)
AllocTraits::destroy(a, p + i);
AllocTraits::deallocate(a, p, N); }, a);
}
catch (...)
{
AllocTraits::deallocate(a, ptr, N);
throw;
}
}
template
shared_ptr allocate_shared(const Alloc &alloc, const std::remove_extent_t &u)
{
return allocate_shared(alloc, 1, u);
}
template
shared_ptr allocate_shared_for_overwrite(const Alloc &alloc)
{
using AllocTraits = std::allocator_traits;
using U = typename std::remove_extent