262 lines
		
	
	
		
			8.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			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;
 | |
| 
 | |
| #if MIJIN_BOXED_OBJECT_DEBUG
 | |
|     constexpr ~BoxedObject() noexcept
 | |
|     {
 | |
|         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)
 |