#pragma once #ifndef MIJIN_UTIL_PROPERTY_HPP_INCLUDED #define MIJIN_UTIL_PROPERTY_HPP_INCLUDED 1 #include #include #include "../debug/assert.hpp" #include "../internal/common.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() MIJIN_NOEXCEPT = default; [[nodiscard]] virtual TGet getValue() = 0; virtual void setValue(TSet value) = 0; }; template class SimplePropertyStorage : public PropertyStorage { private: T value_; public: SimplePropertyStorage() MIJIN_NOEXCEPT = default; SimplePropertyStorage(const SimplePropertyStorage& other) MIJIN_CONDITIONAL_NOEXCEPT(noexcept(T(other.value_))) = default; SimplePropertyStorage(SimplePropertyStorage&& other) MIJIN_CONDITIONAL_NOEXCEPT(noexcept(T(std::move(other.value_)))) = default; explicit SimplePropertyStorage(T value) MIJIN_CONDITIONAL_NOEXCEPT(noexcept(T(std::move(value)))) : value_(std::move(value)) {} SimplePropertyStorage& operator=(const SimplePropertyStorage& other) MIJIN_CONDITIONAL_NOEXCEPT(noexcept(value_ = other.value_)) = default; SimplePropertyStorage& operator=(SimplePropertyStorage&& other) MIJIN_CONDITIONAL_NOEXCEPT(noexcept(value_ = std::move(other.value_))) = default; const T& getValue() MIJIN_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) MIJIN_NOEXCEPT : base_(base) {} operator TGet() MIJIN_NOEXCEPT { return base_->get(); } PropertyProxy& operator=(TSet value) MIJIN_CONDITIONAL_NOEXCEPT(noexcept(std::declval() = std::move(value))) { base_->set(std::move(value)); return *this; } }; Property() MIJIN_NOEXCEPT = default; explicit Property(storage_ptr_t storage) MIJIN_NOEXCEPT : storage_(std::move(storage)) {} Property(Property&&) MIJIN_NOEXCEPT = default; Property& operator=(Property&&) MIJIN_NOEXCEPT = default; PropertyProxy operator*() MIJIN_NOEXCEPT { return PropertyProxy(this); } std::remove_reference_t* operator->() const MIJIN_NOEXCEPT { return &get(); } [[nodiscard]] TGet get() const MIJIN_NOEXCEPT { MIJIN_ASSERT_FATAL(storage_ != nullptr, "Cannot get value from an unset property."); return storage_->getValue(); } void set(TSet value) MIJIN_CONDITIONAL_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) MIJIN_CONDITIONAL_NOEXCEPT(noexcept(std::declval() = std::move(value))) { return Property(std::make_unique>(std::move(value))); } } #endif // MIJIN_UTIL_PROPERTY_HPP_INCLUDED