108 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			108 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
 | |
| #pragma once
 | |
| 
 | |
| #ifndef MIJIN_UTIL_PROPERTY_HPP_INCLUDED
 | |
| #define MIJIN_UTIL_PROPERTY_HPP_INCLUDED 1
 | |
| 
 | |
| #include <memory>
 | |
| #include <utility>
 | |
| #include "../debug/assert.hpp"
 | |
| 
 | |
| namespace mijin
 | |
| {
 | |
| 
 | |
| //
 | |
| // public defines
 | |
| //
 | |
| 
 | |
| //
 | |
| // public types
 | |
| //
 | |
| 
 | |
| template<typename T, typename TGet = const T&, typename TSet = T>
 | |
| 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<typename T>
 | |
| class SimplePropertyStorage : public PropertyStorage<T>
 | |
| {
 | |
| 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<typename T, typename TGet = const T&, typename TSet = T>
 | |
| class Property
 | |
| {
 | |
| private:
 | |
|     using storage_t = PropertyStorage<T, TGet, TSet>;
 | |
|     using storage_ptr_t = std::unique_ptr<storage_t>;
 | |
| 
 | |
|     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<T&>() = 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); }
 | |
| 
 | |
|     [[nodiscard]] TGet get() noexcept
 | |
|     {
 | |
|         MIJIN_ASSERT_FATAL(storage_ != nullptr, "Cannot get value from an unset property.");
 | |
|         return storage_->getValue();
 | |
|     }
 | |
|     void set(TSet value) noexcept(noexcept(std::declval<T&>() = std::move(value)))
 | |
|     {
 | |
|         MIJIN_ASSERT_FATAL(storage_ != nullptr, "Cannot set value of an unset property.");
 | |
|         storage_->setValue(std::move<TSet>(value));
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<typename TStorage>
 | |
| Property(std::unique_ptr<TStorage>) -> Property<typename TStorage::value_t, typename TStorage::get_t, typename TStorage::set_t>;
 | |
| 
 | |
| template<typename T>
 | |
| Property<T> makeSimpleProperty(T value) noexcept(noexcept(std::declval<T&>() = std::move(value)))
 | |
| {
 | |
|     return Property(std::make_unique<SimplePropertyStorage<T>>(std::move(value)));
 | |
| }
 | |
| }
 | |
| 
 | |
| #endif // MIJIN_UTIL_PROPERTY_HPP_INCLUDED
 |