244 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			244 lines
		
	
	
		
			6.5 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)
 | 
						|
#define MIJIN_BOXED_OBJECT_DEBUG MIJIN_DEBUG
 | 
						|
#endif
 | 
						|
 | 
						|
//
 | 
						|
// 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:
 | 
						|
    BoxedObject() noexcept : placeholder_() {};
 | 
						|
    explicit BoxedObject(T object)
 | 
						|
#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
 | 
						|
    ~BoxedObject()
 | 
						|
    {
 | 
						|
        MIJIN_ASSERT(!constructed, "BoxedObject::~BoxedObject(): Object has not been destroyed prior to destructor!")
 | 
						|
    }
 | 
						|
#endif
 | 
						|
 | 
						|
    BoxedObject& operator=(const BoxedObject&) = delete;
 | 
						|
    BoxedObject& operator=(BoxedObject&&) = delete;
 | 
						|
 | 
						|
    T& operator*() noexcept { return get(); }
 | 
						|
    const T& operator*() const noexcept { return get(); }
 | 
						|
    T* operator->() noexcept { return &get(); }
 | 
						|
    const T* operator->() const noexcept { return &get(); }
 | 
						|
 | 
						|
    template<typename... TArgs>
 | 
						|
    void construct(TArgs&&... args)
 | 
						|
    {
 | 
						|
#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)...);
 | 
						|
    }
 | 
						|
 | 
						|
    void destroy()
 | 
						|
    {
 | 
						|
#if MIJIN_BOXED_OBJECT_DEBUG
 | 
						|
        MIJIN_ASSERT(constructed, "BoxedObject::destroy(): Attempt to destroy a not constructed object!")
 | 
						|
        constructed = false;
 | 
						|
#endif
 | 
						|
        std::destroy_at(&object_);
 | 
						|
    }
 | 
						|
    
 | 
						|
    void copyTo(BoxedObject& other) const
 | 
						|
    {
 | 
						|
#if MIJIN_BOXED_OBJECT_DEBUG
 | 
						|
        MIJIN_ASSERT(constructed, "BoxedObject::copy(): Attempt to copy a not constructed object!")
 | 
						|
#endif
 | 
						|
        other.construct(object_);
 | 
						|
    }
 | 
						|
 | 
						|
    void moveTo(BoxedObject& other)
 | 
						|
    {
 | 
						|
#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]] T& get()
 | 
						|
    {
 | 
						|
#if MIJIN_BOXED_OBJECT_DEBUG
 | 
						|
        MIJIN_ASSERT(constructed, "BoxedObject::get(): Attempt to access a not constructed object!")
 | 
						|
#endif
 | 
						|
        return object_;
 | 
						|
    }
 | 
						|
 | 
						|
    [[nodiscard]] const T& get() const
 | 
						|
    {
 | 
						|
#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() = default;
 | 
						|
    explicit constexpr BoxedObjectIterator(BoxedObject<T>* box, BoxedObject<T>* start, BoxedObject<T>* end)
 | 
						|
        : box_(box)
 | 
						|
#if MIJIN_CHECKED_ITERATORS
 | 
						|
    , start_(start), end_(end)
 | 
						|
#endif
 | 
						|
    {}
 | 
						|
    BoxedObjectIterator(const BoxedObjectIterator&) = default;
 | 
						|
    BoxedObjectIterator(BoxedObjectIterator&&) noexcept = default;
 | 
						|
 | 
						|
    BoxedObjectIterator& operator=(const BoxedObjectIterator&) = default;
 | 
						|
    BoxedObjectIterator& operator=(BoxedObjectIterator&&) noexcept = default;
 | 
						|
    BoxedObjectIterator& operator+=(difference_type diff);
 | 
						|
    BoxedObjectIterator& operator-=(difference_type diff) { return (*this += -diff); }
 | 
						|
 | 
						|
    constexpr auto operator<=>(const BoxedObjectIterator& other) const noexcept = default;
 | 
						|
 | 
						|
    [[nodiscard]] T& operator*() const;
 | 
						|
    [[nodiscard]] T* operator->() const;
 | 
						|
    BoxedObjectIterator& operator++();
 | 
						|
    BoxedObjectIterator operator++(int);
 | 
						|
    BoxedObjectIterator& operator--();
 | 
						|
    BoxedObjectIterator operator--(int);
 | 
						|
 | 
						|
    [[nodiscard]] difference_type operator-(const BoxedObjectIterator& other) const { return box_ - other.box_; }
 | 
						|
    [[nodiscard]] BoxedObjectIterator operator+(difference_type diff) const;
 | 
						|
    [[nodiscard]] BoxedObjectIterator operator-(difference_type diff) const { return (*this + -diff); }
 | 
						|
 | 
						|
    [[nodiscard]] T& operator[](difference_type diff) const { return *(*this + diff); }
 | 
						|
};
 | 
						|
template<typename T>
 | 
						|
inline BoxedObjectIterator<T> operator+(std::iter_difference_t<T> diff, const BoxedObjectIterator<T>& iter) {
 | 
						|
    return iter + diff;
 | 
						|
}
 | 
						|
static_assert(std::random_access_iterator<BoxedObjectIterator<int>>);
 | 
						|
 | 
						|
//
 | 
						|
// public functions
 | 
						|
//
 | 
						|
 | 
						|
template<typename T>
 | 
						|
BoxedObjectIterator<T>& BoxedObjectIterator<T>::operator+=(difference_type diff)
 | 
						|
{
 | 
						|
#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>
 | 
						|
T& BoxedObjectIterator<T>::operator*() const
 | 
						|
{
 | 
						|
#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>
 | 
						|
BoxedObjectIterator<T>& BoxedObjectIterator<T>::operator++()
 | 
						|
{
 | 
						|
#if MIJIN_CHECKED_ITERATORS
 | 
						|
    MIJIN_ASSERT(box_ < end_, "BoxedObjectIterator::operator++(): Attempt to iterator past the end.");
 | 
						|
#endif
 | 
						|
    ++box_;
 | 
						|
}
 | 
						|
 | 
						|
template<typename T>
 | 
						|
BoxedObjectIterator<T> BoxedObjectIterator<T>::operator++(int)
 | 
						|
{
 | 
						|
#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>
 | 
						|
BoxedObjectIterator<T>& BoxedObjectIterator<T>::operator--()
 | 
						|
{
 | 
						|
#if MIJIN_CHECKED_ITERATORS
 | 
						|
    MIJIN_ASSERT(box_ > start_, "BoxedObjectIterator::operator--(): Attempt to iterator past start.");
 | 
						|
#endif
 | 
						|
    --box_;
 | 
						|
}
 | 
						|
 | 
						|
template<typename T>
 | 
						|
BoxedObjectIterator<T> BoxedObjectIterator<T>::operator--(int)
 | 
						|
{
 | 
						|
#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>
 | 
						|
BoxedObjectIterator<T> BoxedObjectIterator<T>::operator+(difference_type diff) const
 | 
						|
{
 | 
						|
    BoxedObjectIterator copy(*this);
 | 
						|
    copy += diff;
 | 
						|
    return copy;
 | 
						|
}
 | 
						|
 | 
						|
} // namespace mijin
 | 
						|
 | 
						|
#endif // !defined(MIJIN_CONTAINER_BOXED_OBJECT_HPP_INCLUDED)
 |