mijin2/source/mijin/container/boxed_object.hpp

262 lines
8.3 KiB
C++

#pragma once
#if !defined(MIJIN_CONTAINER_BOXED_OBJECT_HPP_INCLUDED)
#define MIJIN_CONTAINER_BOXED_OBJECT_HPP_INCLUDED 1
#include <iterator>
#include <memory>
#include "../debug/assert.hpp"
namespace mijin
{
//
// public defines
//
#if !defined(MIJIN_BOXED_OBJECT_DEBUG)
#if defined(MIJIN_DEBUG)
#define MIJIN_BOXED_OBJECT_DEBUG MIJIN_DEBUG
#else
#define MIJIN_BOXED_OBJECT_DEBUG 0
#endif
#endif // !defined(MIJIN_BOXED_OBJECT_DEBUG)
#define MIJIN_BOXED_PROXY_FUNC(funcname) \
template<typename... TFuncArgs> \
decltype(auto) funcname(TFuncArgs&&... args) \
{ \
return base_t::get().funcname(std::forward<TFuncArgs>(args)...); \
}
#define MIJIN_BOXED_PROXY_FUNC_CONST(funcname) \
template<typename... TFuncArgs> \
decltype(auto) funcname(TFuncArgs&&... args) const \
{ \
return base_t::get().funcname(std::forward<TFuncArgs>(args)...); \
}
//
// public constants
//
//
// public types
//
template<typename T>
class BoxedObject
{
private:
union {
std::byte placeholder_;
T object_;
};
#if MIJIN_BOXED_OBJECT_DEBUG
bool constructed = false;
#endif
public:
constexpr BoxedObject() MIJIN_NOEXCEPT : placeholder_() {};
explicit constexpr BoxedObject(T object) MIJIN_NOEXCEPT_IF(std::is_nothrow_move_constructible_v<T>)
#if MIJIN_BOXED_OBJECT_DEBUG
: constructed(true)
#endif
{
std::construct_at(&object_, std::move(object));
}
BoxedObject(const BoxedObject&) = delete;
BoxedObject(BoxedObject&&) = delete;
constexpr ~BoxedObject() noexcept
{
#if MIJIN_BOXED_OBJECT_DEBUG
MIJIN_ASSERT(!constructed, "BoxedObject::~BoxedObject(): Object has not been destroyed prior to destructor!");
#endif
}
BoxedObject& operator=(const BoxedObject&) = delete;
BoxedObject& operator=(BoxedObject&&) = delete;
constexpr T& operator*() noexcept { return get(); }
constexpr const T& operator*() const noexcept { return get(); }
constexpr T* operator->() noexcept { return &get(); }
constexpr const T* operator->() const noexcept { return &get(); }
template<typename... TArgs>
constexpr void construct(TArgs&&... args) MIJIN_NOEXCEPT_IF((std::is_nothrow_constructible_v<T, TArgs...>))
{
#if MIJIN_BOXED_OBJECT_DEBUG
MIJIN_ASSERT(!constructed, "BoxedObject::construct(): Attempt to construct an already constructed object!");
constructed = true;
#endif
std::construct_at(&object_, std::forward<TArgs>(args)...);
}
constexpr void destroy() MIJIN_NOEXCEPT
{
#if MIJIN_BOXED_OBJECT_DEBUG
MIJIN_ASSERT(constructed, "BoxedObject::destroy(): Attempt to destroy a not constructed object!");
constructed = false;
#endif
std::destroy_at(&object_);
}
constexpr void copyTo(BoxedObject& other) const MIJIN_NOEXCEPT_IF(std::is_nothrow_copy_constructible_v<T>)
{
#if MIJIN_BOXED_OBJECT_DEBUG
MIJIN_ASSERT(constructed, "BoxedObject::copy(): Attempt to copy a not constructed object!");
#endif
other.construct(object_);
}
constexpr void moveTo(BoxedObject& other) MIJIN_NOEXCEPT_IF(std::is_nothrow_move_constructible_v<T>)
{
#if MIJIN_BOXED_OBJECT_DEBUG
MIJIN_ASSERT(constructed, "BoxedObject::copy(): Attempt to copy a not constructed object!");
#endif
other.construct(std::move(object_));
destroy();
}
[[nodiscard]] constexpr T& get() MIJIN_NOEXCEPT
{
#if MIJIN_BOXED_OBJECT_DEBUG
MIJIN_ASSERT(constructed, "BoxedObject::get(): Attempt to access a not constructed object!");
#endif
return object_;
}
[[nodiscard]] constexpr const T& get() const MIJIN_NOEXCEPT
{
#if MIJIN_BOXED_OBJECT_DEBUG
MIJIN_ASSERT(constructed, "BoxedObject::get(): Attempt to access a not constructed object!");
#endif
return object_;
}
};
template<typename T>
class BoxedObjectIterator
{
public:
using difference_type = std::ptrdiff_t;
using value_type = T;
private:
BoxedObject<T>* box_ = nullptr;
#if MIJIN_CHECKED_ITERATORS
BoxedObject<T>* start_ = nullptr;
BoxedObject<T>* end_ = nullptr;
#endif
public:
BoxedObjectIterator() noexcept = default;
explicit constexpr BoxedObjectIterator(BoxedObject<T>* box, BoxedObject<T>* start, BoxedObject<T>* end) MIJIN_NOEXCEPT
: box_(box)
#if MIJIN_CHECKED_ITERATORS
, start_(start), end_(end)
#endif
{}
constexpr BoxedObjectIterator(const BoxedObjectIterator&) noexcept = default;
constexpr BoxedObjectIterator(BoxedObjectIterator&&) noexcept = default;
constexpr BoxedObjectIterator& operator=(const BoxedObjectIterator&) noexcept = default;
constexpr BoxedObjectIterator& operator=(BoxedObjectIterator&&) noexcept = default;
constexpr BoxedObjectIterator& operator+=(difference_type diff) MIJIN_NOEXCEPT;
constexpr BoxedObjectIterator& operator-=(difference_type diff) MIJIN_NOEXCEPT { return (*this += -diff); }
constexpr auto operator<=>(const BoxedObjectIterator& other) const noexcept = default;
[[nodiscard]] constexpr T& operator*() const MIJIN_NOEXCEPT;
[[nodiscard]] constexpr T* operator->() const MIJIN_NOEXCEPT;
constexpr BoxedObjectIterator& operator++() MIJIN_NOEXCEPT;
constexpr BoxedObjectIterator operator++(int) MIJIN_NOEXCEPT;
constexpr BoxedObjectIterator& operator--() MIJIN_NOEXCEPT;
constexpr BoxedObjectIterator operator--(int) MIJIN_NOEXCEPT;
[[nodiscard]] constexpr difference_type operator-(const BoxedObjectIterator& other) const MIJIN_NOEXCEPT { return box_ - other.box_; }
[[nodiscard]] constexpr BoxedObjectIterator operator+(difference_type diff) const MIJIN_NOEXCEPT;
[[nodiscard]] constexpr BoxedObjectIterator operator-(difference_type diff) const MIJIN_NOEXCEPT { return (*this + -diff); }
[[nodiscard]] T& operator[](difference_type diff) const MIJIN_NOEXCEPT { return *(*this + diff); }
};
template<typename T>
constexpr BoxedObjectIterator<T> operator+(std::iter_difference_t<T> diff, const BoxedObjectIterator<T>& iter) MIJIN_NOEXCEPT {
return iter + diff;
}
static_assert(std::random_access_iterator<BoxedObjectIterator<int>>);
//
// public functions
//
template<typename T>
constexpr BoxedObjectIterator<T>& BoxedObjectIterator<T>::operator+=(difference_type diff) MIJIN_NOEXCEPT
{
#if MIJIN_CHECKED_ITERATORS
MIJIN_ASSERT(diff <= (end_ - box_) && diff >= (box_ - start_), "BoxedObjectIterator::operator+=(): Attempt to iterate out of range.");
#endif
box_ += diff;
return *this;
}
template<typename T>
constexpr T& BoxedObjectIterator<T>::operator*() const MIJIN_NOEXCEPT
{
#if MIJIN_CHECKED_ITERATORS
MIJIN_ASSERT(box_ >= start_ && box_ < end_, "BoxedObjectIterator::operator->(): Attempt to dereference out-of-range iterator.");
#endif
return box_->get();
}
template<typename T>
constexpr BoxedObjectIterator<T>& BoxedObjectIterator<T>::operator++() MIJIN_NOEXCEPT
{
#if MIJIN_CHECKED_ITERATORS
MIJIN_ASSERT(box_ < end_, "BoxedObjectIterator::operator++(): Attempt to iterator past the end.");
#endif
++box_;
}
template<typename T>
constexpr BoxedObjectIterator<T> BoxedObjectIterator<T>::operator++(int) MIJIN_NOEXCEPT
{
#if MIJIN_CHECKED_ITERATORS
MIJIN_ASSERT(box_ < end_, "BoxedObjectIterator::operator++(int): Attempt to iterator past the end.");
#endif
BoxedObjectIterator copy(*this);
++box_;
return copy;
}
template<typename T>
constexpr BoxedObjectIterator<T>& BoxedObjectIterator<T>::operator--() MIJIN_NOEXCEPT
{
#if MIJIN_CHECKED_ITERATORS
MIJIN_ASSERT(box_ > start_, "BoxedObjectIterator::operator--(): Attempt to iterator past start.");
#endif
--box_;
}
template<typename T>
constexpr BoxedObjectIterator<T> BoxedObjectIterator<T>::operator--(int) MIJIN_NOEXCEPT
{
#if MIJIN_CHECKED_ITERATORS
MIJIN_ASSERT(box_ > start_, "BoxedObjectIterator::operator--(int): Attempt to iterator past start.");
#endif
BoxedObjectIterator copy(*this);
--box_;
return copy;
}
template<typename T>
constexpr BoxedObjectIterator<T> BoxedObjectIterator<T>::operator+(difference_type diff) const MIJIN_NOEXCEPT
{
BoxedObjectIterator copy(*this);
copy += diff;
return copy;
}
} // namespace mijin
#endif // !defined(MIJIN_CONTAINER_BOXED_OBJECT_HPP_INCLUDED)