142 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			142 lines
		
	
	
		
			3.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
 | 
						|
#pragma once
 | 
						|
 | 
						|
#if !defined(MIJIN_ASYNC_FUTURE_HPP_INCLUDED)
 | 
						|
#define MIJIN_ASYNC_FUTURE_HPP_INCLUDED 1
 | 
						|
 | 
						|
#include <optional>
 | 
						|
#include <memory>
 | 
						|
#include <type_traits>
 | 
						|
#include "./signal.hpp"
 | 
						|
#include "../container/optional.hpp"
 | 
						|
#include "../debug/assert.hpp"
 | 
						|
#include "../internal/common.hpp"
 | 
						|
 | 
						|
namespace mijin
 | 
						|
{
 | 
						|
 | 
						|
//
 | 
						|
// public defines
 | 
						|
//
 | 
						|
 | 
						|
//
 | 
						|
// public constants
 | 
						|
//
 | 
						|
 | 
						|
//
 | 
						|
// public types
 | 
						|
//
 | 
						|
template<typename TValue>
 | 
						|
class Future;
 | 
						|
 | 
						|
// TODO: add support for mutexes and waiting for futures
 | 
						|
namespace impl
 | 
						|
{
 | 
						|
template<typename TValue>
 | 
						|
struct FutureStorage
 | 
						|
{
 | 
						|
    Optional<TValue> value;
 | 
						|
 | 
						|
    void setValue(TValue value_) MIJIN_NOEXCEPT { value = std::move(value_); }
 | 
						|
    [[nodiscard]] TValue& getValue() MIJIN_NOEXCEPT { return value.get(); }
 | 
						|
 | 
						|
};
 | 
						|
 | 
						|
// template<typename TValue>
 | 
						|
// struct FutureStorage<TValue&>
 | 
						|
// {
 | 
						|
//     Optional<TValue*> value;
 | 
						|
//
 | 
						|
//     void setValue(TValue& value_) MIJIN_NOEXCEPT { value = &value_; }
 | 
						|
//     [[nodiscard]] TValue& getValue() const MIJIN_NOEXCEPT { return *value.get(); }
 | 
						|
// };
 | 
						|
 | 
						|
template<>
 | 
						|
struct FutureStorage<void>
 | 
						|
{
 | 
						|
};
 | 
						|
} // namespace impl
 | 
						|
 | 
						|
template<typename TValue>
 | 
						|
class Future
 | 
						|
{
 | 
						|
private:
 | 
						|
    impl::FutureStorage<TValue> value_;
 | 
						|
    bool isSet_ = false;
 | 
						|
public:
 | 
						|
    Future() = default;
 | 
						|
    Future(const Future&) = delete;
 | 
						|
    Future(Future&&) MIJIN_NOEXCEPT = default;
 | 
						|
public:
 | 
						|
    Future& operator=(const Future&) = delete;
 | 
						|
    Future& operator=(Future&&) MIJIN_NOEXCEPT = default;
 | 
						|
 | 
						|
    [[nodiscard]]
 | 
						|
    constexpr explicit operator bool() const MIJIN_NOEXCEPT { return ready(); }
 | 
						|
 | 
						|
    [[nodiscard]]
 | 
						|
    constexpr bool operator!() const MIJIN_NOEXCEPT { return !ready(); }
 | 
						|
public: // access
 | 
						|
    [[nodiscard]]
 | 
						|
    constexpr decltype(auto) get() MIJIN_NOEXCEPT
 | 
						|
    {
 | 
						|
        MIJIN_ASSERT(isSet_, "Attempting to get from future that is not ready.");
 | 
						|
        if constexpr(std::is_same_v<TValue, void>) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            return value_.getValue();
 | 
						|
        }
 | 
						|
    }
 | 
						|
    [[nodiscard]]
 | 
						|
    constexpr decltype(auto) get() const MIJIN_NOEXCEPT
 | 
						|
    {
 | 
						|
        MIJIN_ASSERT(isSet_, "Attempting to get from future that is not ready.");
 | 
						|
        if constexpr(std::is_same_v<TValue, void>) {
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            return value_.getValue();
 | 
						|
        }
 | 
						|
    }
 | 
						|
    [[nodiscard]]
 | 
						|
    constexpr bool ready() const MIJIN_NOEXCEPT
 | 
						|
    {
 | 
						|
        return isSet_;
 | 
						|
    }
 | 
						|
public: // modification
 | 
						|
    template<typename TArg> requires (!std::is_same_v<TValue, void>)
 | 
						|
    constexpr void set(TArg&& value) MIJIN_NOEXCEPT
 | 
						|
    {
 | 
						|
        MIJIN_ASSERT(!isSet_, "Trying to set a future twice!");
 | 
						|
        value_.setValue(std::move(value));
 | 
						|
        isSet_ = true;
 | 
						|
        sigSet.emit();
 | 
						|
    }
 | 
						|
    constexpr void set() MIJIN_NOEXCEPT requires (std::is_same_v<TValue, void>)
 | 
						|
    {
 | 
						|
        MIJIN_ASSERT(!isSet_, "Trying to set a future twice!");
 | 
						|
        isSet_ = true;
 | 
						|
        if constexpr (std::is_same_v<TValue, void>) {
 | 
						|
            sigSet.emit();
 | 
						|
        }
 | 
						|
        else {
 | 
						|
            // would love to make this a compile-time error :/
 | 
						|
            MIJIN_ERROR("Attempting to call set(void) on future with value.");
 | 
						|
        }
 | 
						|
    }
 | 
						|
public: // signals
 | 
						|
    Signal<> sigSet;
 | 
						|
};
 | 
						|
 | 
						|
template<typename TValue>
 | 
						|
using FuturePtr = std::shared_ptr<Future<TValue>>;
 | 
						|
 | 
						|
//
 | 
						|
// public functions
 | 
						|
//
 | 
						|
 | 
						|
} // namespace mijin
 | 
						|
 | 
						|
#endif // !defined(MIJIN_ASYNC_FUTURE_HPP_INCLUDED)
 |