Re-commit r208025, reverted in r208030, with a fix for a conformance issue

which GCC detects and Clang does not!


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@208033 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Richard Smith
2014-05-06 01:44:26 +00:00
parent f3a199b2ae
commit 36ecb2ee9d
9 changed files with 227 additions and 46 deletions

View File

@@ -55,6 +55,131 @@ struct greater_ptr : public std::binary_function<Ty, Ty, bool> {
}
};
/// An efficient, type-erasing, non-owning reference to a callable. This is
/// intended for use as the type of a function parameter that is not used
/// after the function in question returns.
///
/// This class does not own the callable, so it is not in general safe to store
/// a function_ref.
template<typename Fn> class function_ref;
#if LLVM_HAS_VARIADIC_TEMPLATES
template<typename Ret, typename ...Params>
class function_ref<Ret(Params...)> {
Ret (*callback)(void *callable, Params ...params);
void *callable;
template<typename Callable>
static Ret callback_fn(void *callable, Params ...params) {
return (*reinterpret_cast<Callable*>(callable))(
std::forward<Params>(params)...);
}
public:
template<typename Callable>
function_ref(Callable &&callable)
: callback(callback_fn<typename std::remove_reference<Callable>::type>),
callable(reinterpret_cast<void *>(&callable)) {}
Ret operator()(Params ...params) const {
return callback(callable, std::forward<Params>(params)...);
}
};
#else
template<typename Ret>
class function_ref<Ret()> {
Ret (*callback)(void *callable);
void *callable;
template<typename Callable>
static Ret callback_fn(void *callable) {
return (*reinterpret_cast<Callable*>(callable))();
}
public:
template<typename Callable>
function_ref(Callable &&callable)
: callback(callback_fn<typename std::remove_reference<Callable>::type>),
callable(reinterpret_cast<void *>(&callable)) {}
Ret operator()() const { return callback(callable); }
};
template<typename Ret, typename Param1>
class function_ref<Ret(Param1)> {
Ret (*callback)(void *callable, Param1 param1);
void *callable;
template<typename Callable>
static Ret callback_fn(void *callable, Param1 param1) {
return (*reinterpret_cast<Callable*>(callable))(
std::forward<Param1>(param1));
}
public:
template<typename Callable>
function_ref(Callable &&callable)
: callback(callback_fn<typename std::remove_reference<Callable>::type>),
callable(reinterpret_cast<void *>(&callable)) {}
Ret operator()(Param1 param1) {
return callback(callable, std::forward<Param1>(param1));
}
};
template<typename Ret, typename Param1, typename Param2>
class function_ref<Ret(Param1, Param2)> {
Ret (*callback)(void *callable, Param1 param1, Param2 param2);
void *callable;
template<typename Callable>
static Ret callback_fn(void *callable, Param1 param1, Param2 param2) {
return (*reinterpret_cast<Callable*>(callable))(
std::forward<Param1>(param1),
std::forward<Param2>(param2));
}
public:
template<typename Callable>
function_ref(Callable &&callable)
: callback(callback_fn<typename std::remove_reference<Callable>::type>),
callable(reinterpret_cast<void *>(&callable)) {}
Ret operator()(Param1 param1, Param2 param2) {
return callback(callable,
std::forward<Param1>(param1),
std::forward<Param2>(param2));
}
};
template<typename Ret, typename Param1, typename Param2, typename Param3>
class function_ref<Ret(Param1, Param2, Param3)> {
Ret (*callback)(void *callable, Param1 param1, Param2 param2, Param3 param3);
void *callable;
template<typename Callable>
static Ret callback_fn(void *callable, Param1 param1, Param2 param2,
Param3 param3) {
return (*reinterpret_cast<Callable*>(callable))(
std::forward<Param1>(param1),
std::forward<Param2>(param2),
std::forward<Param3>(param3));
}
public:
template<typename Callable>
function_ref(Callable &&callable)
: callback(callback_fn<typename std::remove_reference<Callable>::type>),
callable(reinterpret_cast<void *>(&callable)) {}
Ret operator()(Param1 param1, Param2 param2, Param3 param3) {
return callback(callable,
std::forward<Param1>(param1),
std::forward<Param2>(param2),
std::forward<Param3>(param3));
}
};
#endif
// deleter - Very very very simple method that is used to invoke operator
// delete on something. It is used like this:
//