blob: fd3b30507311752487d14c2ee7862791d11bb31a [file] [log] [blame]
// Copyright 2016 The Goma Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef DEVTOOLS_GOMA_CLIENT_CALLBACK_H_
#define DEVTOOLS_GOMA_CLIENT_CALLBACK_H_
#include <memory>
#include <tuple>
#include <utility>
#include "basictypes.h"
namespace devtools_goma {
// Closure has two types: OneshotClosure and PermanentClosure.
// * Both has a fundamental type Closure.
// * OneshotClosure can take move-only arguments, especially std::unique_ptr.
// When Run() is called, such arguments are passed with std::move.
// * PermanentClosure cannot take a move-only argument, because arguments can be
// passed to the internal function several times. So, we cannot move them.
class Closure {
public:
Closure() {}
virtual ~Closure() {}
virtual void Run() = 0;
private:
DISALLOW_COPY_AND_ASSIGN(Closure);
};
class OneshotClosure : public Closure {
public:
OneshotClosure() {}
~OneshotClosure() override {}
private:
DISALLOW_COPY_AND_ASSIGN(OneshotClosure);
};
class PermanentClosure : public Closure {
public:
PermanentClosure() {}
~PermanentClosure() override {}
private:
DISALLOW_COPY_AND_ASSIGN(PermanentClosure);
};
namespace internal {
// ----------------------------------------------------------------------
// Making integer sequence (template).
//
// TODO: C++14 has std::index_sequence for the same purpose.
// We cannot implement the same thing since C++14 version uses
// template variable, which does not exist in C++11.
// Currently we need to call type().
// index_sequence will be made via index_sequence_for<Args>::type().
// The template arguments are <0, 1, 2, ..., N - 1> where N is the size of Args.
template<size_t...>
struct index_sequence {};
template<size_t I, typename T, typename... Types>
struct make_indexes_impl;
template<size_t I, size_t... Indexes, typename T, typename... Types>
struct make_indexes_impl<I, index_sequence<Indexes...>, T, Types...> {
typedef typename make_indexes_impl<I + 1,
index_sequence<Indexes..., I>,
Types...>::type type;
};
template<size_t I, size_t... Indexes>
struct make_indexes_impl<I, index_sequence<Indexes...>> {
typedef index_sequence<Indexes...> type;
};
template<typename... Types>
struct index_sequence_for : make_indexes_impl<0, index_sequence<>, Types...> {
};
// ----------------------------------------------------------------------
template<typename... Args>
class OneshotFunctionClosure : public OneshotClosure {
public:
typedef void (*FunctionType)(Args...);
OneshotFunctionClosure(FunctionType f, Args&&... args)
: function_(f), args_(std::forward<Args>(args)...) {
}
~OneshotFunctionClosure() override {}
void Run() override {
Apply(typename index_sequence_for<Args...>::type());
delete this;
}
private:
template<size_t... Indexes>
void Apply(index_sequence<Indexes...>) {
function_(std::forward<Args>(std::get<Indexes>(args_))...);
}
typename std::decay<FunctionType>::type function_;
std::tuple<typename std::decay<Args>::type...> args_;
};
template<typename Class, typename... Args>
class OneshotMethodClosure : public OneshotClosure {
public:
typedef void (Class::*MethodType)(Args... args);
OneshotMethodClosure(Class* object, MethodType method, Args&&... args)
: object_(object), method_(method), args_(std::forward<Args>(args)...) {}
~OneshotMethodClosure() override {}
void Run() override {
Apply(typename index_sequence_for<Args...>::type());
delete this;
}
private:
template<size_t... Indexes>
void Apply(index_sequence<Indexes...>) {
(object_->*method_)(std::forward<Args>(std::get<Indexes>(args_))...);
}
Class* object_;
typename std::decay<MethodType>::type method_;
std::tuple<typename std::decay<Args>::type...> args_;
};
template<typename... Args>
class PermanentFunctionClosure : public PermanentClosure {
public:
typedef void (*FunctionType)(Args...);
PermanentFunctionClosure(FunctionType f, Args... args)
: function_(f), args_(std::forward<Args>(args)...) {
}
~PermanentFunctionClosure() override {}
void Run() override {
Apply(typename index_sequence_for<Args...>::type());
}
private:
template<size_t... Indexes>
void Apply(index_sequence<Indexes...>) {
function_(std::get<Indexes>(args_)...);
}
typename std::decay<FunctionType>::type function_;
std::tuple<typename std::decay<Args>::type...> args_;
};
template<typename Class, typename... Args>
class PermanentMethodClosure : public PermanentClosure {
public:
typedef void (Class::*MethodType)(Args... args);
PermanentMethodClosure(Class* object, MethodType method, Args... args)
: object_(object), method_(method), args_(std::forward<Args>(args)...) {}
~PermanentMethodClosure() override {}
void Run() override {
Apply(typename index_sequence_for<Args...>::type());
}
private:
template<size_t... Indexes>
void Apply(index_sequence<Indexes...>) {
(object_->*method_)(std::get<Indexes>(args_)...);
}
Class* object_;
typename std::decay<MethodType>::type method_;
std::tuple<typename std::decay<Args>::type...> args_;
};
} // namespace internal
// TODO: NewCallback might have to return std::unique_ptr, too.
template<typename... Args>
inline OneshotClosure* NewCallback(void (*function)(Args...), Args... args) {
return new internal::OneshotFunctionClosure<Args...>(
function, std::forward<Args>(args)...);
}
template<typename Class, typename... Args>
inline OneshotClosure* NewCallback(
Class* object, void (Class::*method)(Args...), Args... args) {
return new internal::OneshotMethodClosure<Class, Args...>(
object, method, std::forward<Args>(args)...);
}
template<typename... Args>
inline std::unique_ptr<PermanentClosure> NewPermanentCallback(
void (*function)(Args...), Args... args) {
return std::unique_ptr<PermanentClosure>(
new internal::PermanentFunctionClosure<Args...>(
function, std::forward<Args>(args)...));
}
template<typename Class, typename... Args>
inline std::unique_ptr<PermanentClosure> NewPermanentCallback(
Class* object, void (Class::*method)(Args...), Args... args) {
return std::unique_ptr<PermanentClosure>(
new internal::PermanentMethodClosure<Class, Args...>(
object, method, std::forward<Args>(args)...));
}
} // namespace devtools_goma
#endif // DEVTOOLS_GOMA_CLIENT_CALLBACK_H_