#pragma once #ifndef MIJIN_UTIL_PROPERTY_HPP_INCLUDED #define MIJIN_UTIL_PROPERTY_HPP_INCLUDED 1 #include #include #include "../debug/assert.hpp" namespace mijin { // // public defines // // // public types // template class PropertyStorage { public: using value_t = T; using get_t = TGet; using set_t = TSet; virtual ~PropertyStorage() noexcept = default; [[nodiscard]] virtual TGet getValue() = 0; virtual void setValue(TSet value) = 0; }; template class SimplePropertyStorage : public PropertyStorage { private: T value_; public: SimplePropertyStorage() noexcept = default; SimplePropertyStorage(const SimplePropertyStorage& other) noexcept(noexcept(T(other.value_))) = default; SimplePropertyStorage(SimplePropertyStorage&& other) noexcept(noexcept(T(std::move(other.value_)))) = default; explicit SimplePropertyStorage(T value) noexcept(noexcept(T(std::move(value)))) : value_(std::move(value)) {} SimplePropertyStorage& operator=(const SimplePropertyStorage& other) noexcept(noexcept(value_ = other.value_)) = default; SimplePropertyStorage& operator=(SimplePropertyStorage&& other) noexcept(noexcept(value_ = std::move(other.value_))) = default; const T& getValue() noexcept override { return value_; } void setValue(T value) override { value_ = std::move(value); } }; template class Property { private: using storage_t = PropertyStorage; using storage_ptr_t = std::unique_ptr; storage_ptr_t storage_; public: class PropertyProxy { private: Property* base_; public: explicit PropertyProxy(Property* base) noexcept : base_(base) {} operator TGet() noexcept { return base_->get(); } PropertyProxy& operator=(TSet value) noexcept(noexcept(std::declval() = std::move(value))) { base_->set(std::move(value)); return *this; } }; Property() noexcept = default; explicit Property(storage_ptr_t storage) noexcept : storage_(std::move(storage)) {} Property(Property&&) noexcept = default; Property& operator=(Property&&) noexcept = default; PropertyProxy operator*() noexcept { return PropertyProxy(this); } std::remove_reference_t* operator->() const noexcept { return &get(); } [[nodiscard]] TGet get() const noexcept { MIJIN_ASSERT_FATAL(storage_ != nullptr, "Cannot get value from an unset property."); return storage_->getValue(); } void set(TSet value) noexcept(noexcept(std::declval() = std::move(value))) { MIJIN_ASSERT_FATAL(storage_ != nullptr, "Cannot set value of an unset property."); storage_->setValue(std::move(value)); } }; template Property(std::unique_ptr) -> Property; template Property makeSimpleProperty(T value) noexcept(noexcept(std::declval() = std::move(value))) { return Property(std::make_unique>(std::move(value))); } } #endif // MIJIN_UTIL_PROPERTY_HPP_INCLUDED