docs: add plugin setup guide
This commit is contained in:
@@ -0,0 +1,395 @@
|
||||
#pragma once
|
||||
|
||||
namespace RE
|
||||
{
|
||||
template <class T>
|
||||
class BSTOptional
|
||||
{
|
||||
public:
|
||||
using value_type = T;
|
||||
|
||||
// 1a)
|
||||
constexpr BSTOptional() noexcept = default;
|
||||
|
||||
// 1b)
|
||||
constexpr BSTOptional(std::nullopt_t) noexcept {}
|
||||
|
||||
// 2) non-trivial
|
||||
constexpr BSTOptional(const BSTOptional& a_rhs) //
|
||||
noexcept(std::is_nothrow_copy_constructible_v<value_type>) //
|
||||
requires(std::is_copy_constructible_v<value_type> &&
|
||||
!std::is_trivially_copy_constructible_v<value_type>)
|
||||
{
|
||||
if (a_rhs.has_value()) {
|
||||
std::construct_at(std::addressof(_value), a_rhs.value());
|
||||
_active = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 2) trivial
|
||||
constexpr BSTOptional(const BSTOptional&)
|
||||
requires(std::is_trivially_copy_constructible_v<value_type>)
|
||||
= default;
|
||||
|
||||
// 3) non-trivial
|
||||
constexpr BSTOptional(BSTOptional&& a_rhs) //
|
||||
noexcept(std::is_nothrow_move_constructible_v<value_type>) //
|
||||
requires(std::is_move_constructible_v<value_type> &&
|
||||
!std::is_trivially_move_constructible_v<value_type>)
|
||||
{
|
||||
if (a_rhs.has_value()) {
|
||||
std::construct_at(std::addressof(_value), std::move(a_rhs).value());
|
||||
_active = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 2) trivial
|
||||
constexpr BSTOptional(BSTOptional&&)
|
||||
requires(std::is_trivially_move_constructible_v<value_type>)
|
||||
= default;
|
||||
|
||||
// 4)
|
||||
template <class U>
|
||||
explicit(!std::is_convertible_v<const U&, value_type>) //
|
||||
BSTOptional(const BSTOptional<U>& a_rhs) //
|
||||
noexcept(std::is_nothrow_constructible_v<value_type, const U&>) //
|
||||
requires(std::is_constructible_v<value_type, const U&> &&
|
||||
!std::is_constructible_v<value_type, BSTOptional<U>&> &&
|
||||
!std::is_constructible_v<value_type, const BSTOptional<U>&> &&
|
||||
!std::is_constructible_v<value_type, BSTOptional<U> &&> &&
|
||||
!std::is_constructible_v<value_type, const BSTOptional<U> &&> &&
|
||||
!std::is_convertible_v<BSTOptional<U>&, value_type> &&
|
||||
!std::is_convertible_v<const BSTOptional<U>&, value_type> &&
|
||||
!std::is_convertible_v<BSTOptional<U> &&, value_type> &&
|
||||
!std::is_convertible_v<const BSTOptional<U> &&, value_type>)
|
||||
{
|
||||
if (a_rhs.has_value()) {
|
||||
std::construct_at(std::addressof(_value), a_rhs.value());
|
||||
_active = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 5)
|
||||
template <class U>
|
||||
explicit(!std::is_convertible_v<U&&, T>) //
|
||||
BSTOptional(BSTOptional<U>&& a_rhs) //
|
||||
noexcept(std::is_nothrow_constructible_v<value_type, U&&>) //
|
||||
requires(std::is_constructible_v<value_type, U &&> &&
|
||||
!std::is_constructible_v<value_type, BSTOptional<U>&> &&
|
||||
!std::is_constructible_v<value_type, const BSTOptional<U>&> &&
|
||||
!std::is_constructible_v<value_type, BSTOptional<U> &&> &&
|
||||
!std::is_constructible_v<value_type, const BSTOptional<U> &&> &&
|
||||
!std::is_convertible_v<BSTOptional<U>&, value_type> &&
|
||||
!std::is_convertible_v<const BSTOptional<U>&, value_type> &&
|
||||
!std::is_convertible_v<BSTOptional<U> &&, value_type> &&
|
||||
!std::is_convertible_v<const BSTOptional<U> &&, value_type>)
|
||||
{
|
||||
if (a_rhs.has_value()) {
|
||||
std::construct_at(std::addressof(_value), std::move(a_rhs).value());
|
||||
_active = true;
|
||||
}
|
||||
}
|
||||
|
||||
// 6)
|
||||
template <class... Args>
|
||||
constexpr explicit BSTOptional(std::in_place_t, Args&&... a_args) //
|
||||
noexcept(std::is_nothrow_constructible_v<value_type, Args&&...>) //
|
||||
requires(std::is_constructible_v<value_type, Args && ...>)
|
||||
{
|
||||
std::construct_at(std::addressof(_value), std::forward<Args>(a_args)...);
|
||||
_active = true;
|
||||
}
|
||||
|
||||
// 7)
|
||||
template <class U, class... Args>
|
||||
constexpr explicit BSTOptional(std::in_place_t, std::initializer_list<U> a_ilist, Args&&... a_args) //
|
||||
noexcept(std::is_nothrow_constructible_v<value_type, std::initializer_list<U>&, Args&&...>) //
|
||||
requires(std::is_constructible_v<value_type, std::initializer_list<U>&, Args && ...>)
|
||||
{
|
||||
std::construct_at(std::addressof(_value), a_ilist, std::forward<Args>(a_args)...);
|
||||
_active = true;
|
||||
}
|
||||
|
||||
// 8)
|
||||
template <class U = value_type>
|
||||
constexpr explicit(!std::is_convertible_v<U&&, value_type>) //
|
||||
BSTOptional(U&& a_value) //
|
||||
noexcept(std::is_nothrow_constructible_v<value_type, U&&>) //
|
||||
requires(std::is_constructible_v<value_type, U &&> &&
|
||||
!std::same_as<std::remove_cvref_t<U>, std::in_place_t> &&
|
||||
!std::same_as<std::remove_cvref_t<U>, BSTOptional<value_type>>)
|
||||
{
|
||||
std::construct_at(std::addressof(_value), std::forward<U>(a_value));
|
||||
_active = true;
|
||||
}
|
||||
|
||||
// non-trivial
|
||||
~BSTOptional() //
|
||||
noexcept(std::is_nothrow_destructible_v<value_type>) //
|
||||
requires(!std::is_trivially_destructible_v<value_type>)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
// trivial
|
||||
~BSTOptional()
|
||||
requires(std::is_trivially_destructible_v<value_type>)
|
||||
= default;
|
||||
|
||||
// 1)
|
||||
BSTOptional& operator=(std::nullopt_t) //
|
||||
noexcept(noexcept(reset()))
|
||||
{
|
||||
reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
// 2) defined
|
||||
constexpr BSTOptional& operator=(const BSTOptional& a_rhs) //
|
||||
noexcept((std::is_nothrow_destructible_v<value_type> &&
|
||||
std::is_nothrow_copy_constructible_v<value_type> &&
|
||||
std::is_nothrow_copy_assignable_v<value_type>)) //
|
||||
requires((std::is_copy_constructible_v<value_type> &&
|
||||
std::is_copy_assignable_v<value_type>))
|
||||
{
|
||||
if (this != std::addressof(a_rhs)) {
|
||||
if (a_rhs.has_value()) {
|
||||
if (has_value()) {
|
||||
_value = a_rhs.value();
|
||||
} else {
|
||||
std::construct_at(std::addressof(_value), a_rhs.value());
|
||||
_active = true;
|
||||
}
|
||||
} else if (has_value()) {
|
||||
do_reset();
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// 2) deleted
|
||||
BSTOptional& operator=(const BSTOptional&) //
|
||||
requires(!std::is_copy_constructible_v<value_type> ||
|
||||
!std::is_copy_assignable_v<value_type>)
|
||||
= delete;
|
||||
|
||||
// 3) defined
|
||||
constexpr BSTOptional& operator=(BSTOptional&& a_rhs) //
|
||||
noexcept((std::is_nothrow_destructible_v<value_type> &&
|
||||
std::is_nothrow_move_constructible_v<value_type> &&
|
||||
std::is_nothrow_move_assignable_v<value_type>)) //
|
||||
requires((std::is_move_constructible_v<value_type> &&
|
||||
std::is_move_assignable_v<value_type>))
|
||||
{
|
||||
if (this != std::addressof(a_rhs)) {
|
||||
if (a_rhs.has_value()) {
|
||||
if (has_value()) {
|
||||
_value = std::move(a_rhs).value();
|
||||
} else {
|
||||
std::construct_at(std::addressof(_value), std::move(a_rhs).value());
|
||||
_active = true;
|
||||
}
|
||||
} else if (has_value()) {
|
||||
do_reset();
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// 3) deleted
|
||||
BSTOptional& operator=(BSTOptional&&) //
|
||||
requires(!std::is_move_constructible_v<value_type> ||
|
||||
!std::is_move_assignable_v<value_type>)
|
||||
= delete;
|
||||
|
||||
// 4)
|
||||
template <class U = value_type>
|
||||
BSTOptional& operator=(U&& a_value) //
|
||||
noexcept((std::is_nothrow_destructible_v<value_type> &&
|
||||
std::is_nothrow_constructible_v<value_type, U&&> &&
|
||||
std::is_nothrow_assignable_v<value_type&, U&&>)) //
|
||||
requires(!std::same_as<std::remove_cvref_t<U>, BSTOptional<value_type>> &&
|
||||
std::is_constructible_v<value_type, U &&> &&
|
||||
std::is_assignable_v<value_type&, U &&> &&
|
||||
(!std::is_scalar_v<value_type> || !std::same_as<std::decay_t<U>, T>))
|
||||
{
|
||||
if (has_value()) {
|
||||
_value = std::forward<U>(a_value);
|
||||
} else {
|
||||
std::construct_at(std::addressof(_value), std::forward<U>(a_value));
|
||||
_active = true;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// 5)
|
||||
template <class U>
|
||||
BSTOptional& operator=(const BSTOptional<U>& a_rhs) //
|
||||
noexcept((std::is_nothrow_destructible_v<value_type> &&
|
||||
std::is_nothrow_constructible_v<value_type, const U&> &&
|
||||
std::is_nothrow_assignable_v<value_type&, const U&>)) //
|
||||
requires(!std::is_constructible_v<value_type, BSTOptional<U>&> &&
|
||||
!std::is_constructible_v<value_type, const BSTOptional<U>&> &&
|
||||
!std::is_constructible_v<value_type, BSTOptional<U> &&> &&
|
||||
!std::is_constructible_v<value_type, const BSTOptional<U> &&> &&
|
||||
!std::is_convertible_v<BSTOptional<U>&, value_type> &&
|
||||
!std::is_convertible_v<const BSTOptional<U>&, value_type> &&
|
||||
!std::is_convertible_v<BSTOptional<U> &&, value_type> &&
|
||||
!std::is_convertible_v<const BSTOptional<U> &&, value_type> &&
|
||||
!std::is_assignable_v<value_type&, BSTOptional<U>&> &&
|
||||
!std::is_assignable_v<value_type&, const BSTOptional<U>&> &&
|
||||
!std::is_assignable_v<value_type&, BSTOptional<U> &&> &&
|
||||
!std::is_assignable_v<value_type&, const BSTOptional<U> &&> &&
|
||||
std::is_constructible_v<value_type, const U&> &&
|
||||
std::is_assignable_v<value_type&, const U&>)
|
||||
{
|
||||
if (a_rhs.has_value()) {
|
||||
if (has_value()) {
|
||||
_value = a_rhs.value();
|
||||
} else {
|
||||
std::construct_at(std::addressof(_value), a_rhs.value());
|
||||
_active = true;
|
||||
}
|
||||
} else if (has_value()) {
|
||||
reset();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// 6)
|
||||
template <class U>
|
||||
BSTOptional& operator=(BSTOptional<U>&& a_rhs) //
|
||||
noexcept((std::is_nothrow_destructible_v<value_type> &&
|
||||
std::is_nothrow_constructible_v<value_type, U> &&
|
||||
std::is_nothrow_assignable_v<value_type&, U>)) //
|
||||
requires(!std::is_constructible_v<value_type, BSTOptional<U>&> &&
|
||||
!std::is_constructible_v<value_type, const BSTOptional<U>&> &&
|
||||
!std::is_constructible_v<value_type, BSTOptional<U> &&> &&
|
||||
!std::is_constructible_v<value_type, const BSTOptional<U> &&> &&
|
||||
!std::is_convertible_v<BSTOptional<U>&, value_type> &&
|
||||
!std::is_convertible_v<const BSTOptional<U>&, value_type> &&
|
||||
!std::is_convertible_v<BSTOptional<U> &&, value_type> &&
|
||||
!std::is_convertible_v<const BSTOptional<U> &&, value_type> &&
|
||||
!std::is_assignable_v<value_type&, BSTOptional<U>&> &&
|
||||
!std::is_assignable_v<value_type&, const BSTOptional<U>&> &&
|
||||
!std::is_assignable_v<value_type&, BSTOptional<U> &&> &&
|
||||
!std::is_assignable_v<value_type&, const BSTOptional<U> &&> &&
|
||||
std::is_constructible_v<value_type, U> &&
|
||||
std::is_assignable_v<value_type&, U>)
|
||||
{
|
||||
if (a_rhs.has_value()) {
|
||||
if (has_value()) {
|
||||
_value = std::move(a_rhs).value();
|
||||
} else {
|
||||
std::construct_at(std::addressof(_value), std::move(a_rhs).value());
|
||||
_active = true;
|
||||
}
|
||||
} else if (has_value()) {
|
||||
reset();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const value_type* operator->() const noexcept { return std::addressof(value()); }
|
||||
[[nodiscard]] constexpr value_type* operator->() noexcept { return std::addressof(value()); }
|
||||
[[nodiscard]] constexpr const value_type& operator*() const& noexcept { return value(); }
|
||||
[[nodiscard]] constexpr value_type& operator*() & noexcept { return value(); }
|
||||
[[nodiscard]] constexpr const value_type&& operator*() const&& noexcept { return std::move(*this).value(); }
|
||||
[[nodiscard]] constexpr value_type&& operator*() && noexcept { return std::move(*this).value(); }
|
||||
|
||||
[[nodiscard]] constexpr explicit operator bool() const noexcept { return has_value(); }
|
||||
[[nodiscard]] constexpr bool has_value() const noexcept { return _active; }
|
||||
|
||||
[[nodiscard]] constexpr value_type& value() & noexcept
|
||||
{
|
||||
assert(has_value());
|
||||
return _value;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const value_type& value() const& noexcept
|
||||
{
|
||||
assert(has_value());
|
||||
return _value;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr value_type&& value() && noexcept
|
||||
{
|
||||
assert(has_value());
|
||||
return std::move(_value);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr const value_type&& value() const&& noexcept
|
||||
{
|
||||
assert(has_value());
|
||||
return std::move(_value);
|
||||
}
|
||||
|
||||
// 1)
|
||||
template <class U>
|
||||
[[nodiscard]] constexpr value_type value_or(U&& a_default) const& //
|
||||
requires((std::is_copy_constructible_v<value_type> &&
|
||||
std::convertible_to<U &&, value_type>))
|
||||
{
|
||||
return has_value() ? value() : static_cast<T>(std::forward<U>(a_default));
|
||||
}
|
||||
|
||||
// 2)
|
||||
template <class U>
|
||||
[[nodiscard]] constexpr value_type value_or(U&& a_default) && //
|
||||
requires((std::is_move_constructible_v<value_type> &&
|
||||
std::convertible_to<U&&, value_type>)) {
|
||||
return has_value() ? std::move(*this).value() : static_cast<T>(std::forward<U>(a_default));
|
||||
}
|
||||
|
||||
void reset() noexcept(noexcept(do_reset()))
|
||||
{
|
||||
do_reset();
|
||||
}
|
||||
|
||||
// 1)
|
||||
template <class... Args>
|
||||
value_type& emplace(Args&&... a_args) //
|
||||
noexcept(std::is_nothrow_constructible_v<value_type, Args&&...>) //
|
||||
requires(std::is_constructible_v<value_type, Args && ...>)
|
||||
{
|
||||
reset();
|
||||
std::construct_at(std::addressof(_value), std::forward<Args>(a_args)...);
|
||||
_active = true;
|
||||
return value();
|
||||
}
|
||||
|
||||
// 2)
|
||||
template <class U, class... Args>
|
||||
value_type& emplace(std::initializer_list<U> a_ilist, Args&&... a_args) //
|
||||
noexcept(std::is_nothrow_constructible_v<value_type, std::initializer_list<U>&, Args&&...>) //
|
||||
requires(std::is_constructible_v<value_type, std::initializer_list<U>&, Args && ...>)
|
||||
{
|
||||
reset();
|
||||
std::construct_at(std::addressof(_value), a_ilist, std::forward<Args>(a_args)...);
|
||||
_active = true;
|
||||
return value();
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr void
|
||||
do_reset() //
|
||||
noexcept(std::is_nothrow_destructible_v<value_type>)
|
||||
{
|
||||
if (has_value()) {
|
||||
std::destroy_at(std::addressof(_value));
|
||||
_active = false;
|
||||
}
|
||||
}
|
||||
|
||||
// members
|
||||
union
|
||||
{
|
||||
std::remove_const_t<value_type> _value;
|
||||
std::byte _buffer[sizeof(value_type)]{};
|
||||
}; // 00
|
||||
bool _active{ false }; // ??
|
||||
};
|
||||
|
||||
template <class T>
|
||||
BSTOptional(T) -> BSTOptional<T>;
|
||||
}
|
||||
Reference in New Issue
Block a user