blob: 83f47f42b06a2ca33330cb25468077baccac0cd1 (
plain)
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
|
// Copyright (C) 2018 Intel Corporation
//
// SPDX-License-Identifier: Apache-2.0
//
#ifndef UTIL_FUNC_REF_HPP
#define UTIL_FUNC_REF_HPP
#include <cstdint>
#include <utility>
#include "util/type_traits.hpp"
#include "util/assert.hpp"
namespace util
{
template<typename>
class func_ref; // undefined
/// Non-owning callable wrapper
template<typename R, typename... Args>
class func_ref<R(Args...)>
{
using func_t = R(*)(uintptr_t, Args...);
uintptr_t m_context = 0;
func_t m_func = nullptr;
template<typename T>
static R thunk(uintptr_t context, Args... args)
{
T* obj = reinterpret_cast<T*>(context);
return (*obj)(std::forward<Args>(args)...);
}
public:
template<typename Callable>
func_ref(Callable&& callable):
m_context(reinterpret_cast<uintptr_t>(&callable)),
m_func(&thunk<util::remove_reference_t<Callable>>)
{
using actual_result_type = util::result_of_t<Callable(Args...)>;
// If this condition doesn't hold, then thunk will return a reference
// to the temporary returned by callable.
static_assert(
!std::is_reference<R>::value || std::is_reference<actual_result_type>::value,
"If R is a reference, callable must also return a reference");
}
R operator()(Args... args) const
{
ASSERT(0 != m_context);
ASSERT(nullptr != m_func);
return m_func(m_context, std::forward<Args>(args)...);
}
};
}
#endif // UTIL_FUNC_REF_HPP
|