#pragma once #if !defined(MIJIN_CONTAINER_BOXED_OBJECT_HPP_INCLUDED) #define MIJIN_CONTAINER_BOXED_OBJECT_HPP_INCLUDED 1 #include #include #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 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 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(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 class BoxedObjectIterator { public: using difference_type = std::ptrdiff_t; using value_type = T; private: BoxedObject* box_ = nullptr; #if MIJIN_CHECKED_ITERATORS BoxedObject* start_ = nullptr; BoxedObject* end_ = nullptr; #endif public: BoxedObjectIterator() = default; explicit constexpr BoxedObjectIterator(BoxedObject* box, BoxedObject* start, BoxedObject* 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 inline BoxedObjectIterator operator+(std::iter_difference_t diff, const BoxedObjectIterator& iter) { return iter + diff; } static_assert(std::random_access_iterator>); // // public functions // template BoxedObjectIterator& BoxedObjectIterator::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 T& BoxedObjectIterator::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 BoxedObjectIterator& BoxedObjectIterator::operator++() { #if MIJIN_CHECKED_ITERATORS MIJIN_ASSERT(box_ < end_, "BoxedObjectIterator::operator++(): Attempt to iterator past the end."); #endif ++box_; } template BoxedObjectIterator BoxedObjectIterator::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 BoxedObjectIterator& BoxedObjectIterator::operator--() { #if MIJIN_CHECKED_ITERATORS MIJIN_ASSERT(box_ > start_, "BoxedObjectIterator::operator--(): Attempt to iterator past start."); #endif --box_; } template BoxedObjectIterator BoxedObjectIterator::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 BoxedObjectIterator BoxedObjectIterator::operator+(difference_type diff) const { BoxedObjectIterator copy(*this); copy += diff; return copy; } } // namespace mijin #endif // !defined(MIJIN_CONTAINER_BOXED_OBJECT_HPP_INCLUDED)