// ----------------------------------------------------------------------
// File: OpaqueFuture.hh
// Author: Abhishek Lekshmanan - CERN
// ----------------------------------------------------------------------
/************************************************************************
* EOS - the CERN Disk Storage System *
* Copyright (C) 2022 CERN/Switzerland *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see .*
************************************************************************/
#pragma once
#include
#include
#include
namespace eos::common
{
namespace detail
{
template
struct has_isReady : std::false_type {};
template
struct has_isReady().isReady())>> :
std::true_type {};
template
struct has_cancel : std::false_type {};
template
struct has_cancel().cancel())>> :
std::true_type {};
// some tests to assert this works as expected; these will fail compilation in
// case our assertions are wrong but are thrown out from the actual object code
static_assert(has_isReady>::value,
"folly::Future implements isReady");
static_assert(has_isReady>::value,
"folly::SemiFuture implements isReady");
static_assert(!has_isReady>::value,
"std::future doesn't implement isReady");
}
/* A type erased future holder to help interop std::future
* and folly::Future types. This mainly allows for holding a vector
* of futures or in situations like classes with virtual Functions
* which cannot be templated
*/
template
class OpaqueFuture
{
public:
T
getValue()
{
return fut_holder->getValue();
}
bool ready()
{
return fut_holder->ready();
}
bool valid()
{
return fut_holder->valid();
}
void wait()
{
return fut_holder->wait();
}
void cancel()
{
return fut_holder->cancel();
}
template
OpaqueFuture(F&& fut) : fut_holder(std::make_unique>(std::move(
fut))) {}
private:
struct base_future_holder {
virtual ~base_future_holder() = default;
virtual T getValue() = 0;
virtual bool valid() = 0;
virtual bool ready() = 0;
virtual void wait() = 0;
virtual void cancel() = 0;
};
template
struct future_holder : public base_future_holder {
future_holder(F&& f) : fut_(std::move(f)) {}
T getValue() override
{
// This is a hack for the fact that folly::Future is
// not a void type but we're behaving as though it is!
// So we need to realize the future but throw away the unit future return
if constexpr(std::is_same_v) {
std::move(fut_).get();
} else {
return std::move(fut_).get();
}
}
bool valid() override
{
return fut_.valid();
}
void wait() override
{
fut_.wait();
}
bool ready() override
{
if constexpr(detail::has_isReady::value) {
return fut_.isReady();
} else if constexpr(std::is_same_v>) {
return fut_.wait_for(std::chrono::seconds(0)) == std::future_status::ready;
}
}
void cancel() override
{
if constexpr(detail::has_cancel::value) {
fut_.cancel();
}
}
F fut_;
};
std::unique_ptr fut_holder;
};
} // eos::common