109 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			109 lines
		
	
	
		
			3.2 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); }
 | 
						|
    std::remove_reference_t<TGet>* 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<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
 |