1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
|
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
// SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
// SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
#ifndef DUNE_COMMON_PARALLEL_FUTURE_HH
#define DUNE_COMMON_PARALLEL_FUTURE_HH
#include <memory>
#include <type_traits>
#include <dune/common/exceptions.hh>
namespace Dune{
/*! \brief This exception is thrown when `ready()`, `wait()` or `get()` is
called on an invalid future. A future is valid until `get()` is called and
if it is not default-constructed and it was not moved from.
*/
class InvalidFutureException : public InvalidStateException
{};
// forward declaration
template<class T>
class PseudoFuture;
/*! \brief Type-erasure for future-like objects. A future-like object is a
object satisfying the interface of FutureBase.
*/
template<class T>
class Future{
// Future interface:
class FutureBase{
public:
virtual ~FutureBase() = default;
virtual void wait() = 0;
virtual bool ready() const = 0;
virtual bool valid() const = 0;
virtual T get() = 0;
};
// model class
template<class F>
class FutureModel
: public FutureBase
{
F _future;
public:
FutureModel(F&& f)
: _future(std::forward<F>(f))
{}
virtual void wait() override
{
_future.wait();
}
virtual bool ready() const override
{
return _future.ready();
}
virtual bool valid() const override
{
return _future.valid();
}
virtual T get() override{
return (T)_future.get();
}
};
std::unique_ptr<FutureBase> _future;
public:
template<class F>
Future(F&& f)
: _future(std::make_unique<FutureModel<F>>(std::forward<F>(f)))
{}
template<class U, std::enable_if_t<std::is_same<U,T>::value && !std::is_same<T,void>::value>>
Future(U&& data)
: _future(std::make_unique<FutureModel<PseudoFuture<T>>>(PseudoFuture<T>(std::forward<U>(data))))
{}
Future() = default;
/*! \brief wait until the future is ready
\throws InvalidFutureException
*/
void wait(){
_future->wait();
}
/*! \brief Waits until the future is ready and returns the resulting value
\returns The contained value
\throws InvalidFutureException
*/
T get() {
return _future->get();
}
/*! \brief
\returns true is the future is ready, otherwise false
\throws InvalidFutureException
*/
bool ready() const {
return _future->ready();
}
/*! \brief Checks whether the future is valid. I.e. `get()' was not called
on that future and when it was not default-constructed and not moved
from.
\returns true is the future is valid, otherwise false
*/
bool valid() const {
if(_future)
return _future->valid();
return false;
}
};
/*! \brief A wrapper-class for a object which is ready immediately.
*/
template<class T>
class PseudoFuture{
bool valid_;
T data_;
public:
PseudoFuture() :
valid_(false)
{}
template<class U>
PseudoFuture(U&& u) :
valid_(true),
data_(std::forward<U>(u))
{}
void wait() {
if(!valid_)
DUNE_THROW(InvalidFutureException, "The PseudoFuture is not valid");
}
bool ready() const {
if(!valid_)
DUNE_THROW(InvalidFutureException, "The PseudoFuture is not valid");
return true;
}
T get() {
if(!valid_)
DUNE_THROW(InvalidFutureException, "The PseudoFuture is not valid");
valid_ = false;
return std::forward<T>(data_);
}
bool valid() const {
return valid_;
}
};
template<>
class PseudoFuture<void>{
bool valid_;
public:
PseudoFuture(bool valid = false) :
valid_(valid)
{}
void wait(){
if(!valid_)
DUNE_THROW(InvalidFutureException, "The PseudoFuture is not valid");
}
bool ready() const{
if(!valid_)
DUNE_THROW(InvalidFutureException, "The PseudoFuture is not valid");
return true;
}
void get(){
if(!valid_)
DUNE_THROW(InvalidFutureException, "The PseudoFuture is not valid");
valid_ = false;
}
bool valid() const{
return valid_;
}
};
}
#endif // DUNE_COMMON_PARALLEL_FUTURE_HH
|