1 /** 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef PANDA_VERIF_PARSER_CALLABLE_H_ 17 #define PANDA_VERIF_PARSER_CALLABLE_H_ 18 19 #include <utility> 20 #include <tuple> 21 22 namespace panda::verifier { 23 /* 24 25 this is lightweight analogue of std::function. 26 Type-erased holder of function, closure or object with operator(). 27 28 NB! it does not keep object contents, only pointers, so 29 a closure must be accessible during lifetime of 30 the callable<...> object. 31 32 Motivation: in many cases using type-erased callable object 33 based on std::function is very heavy-weight: extra allocations, 34 data copying, vtbls and so on. 35 So here is lightweight counterpart, using static type-erasing 36 without extra storage other than two explicit private pointers. 37 */ 38 39 template <typename Signature> 40 class callable; 41 42 template <typename R, typename... Args> 43 class callable<R(Args...)> { 44 struct callable_type { 45 R operator()(Args...); 46 }; 47 typedef R (callable_type::*method_type)(Args...); 48 typedef R (*function_type)(Args...); 49 callable_type *object {nullptr}; 50 union method_union { 51 method_type m; 52 function_type f; method_union(method_type method)53 method_union(method_type method) : m(method) {} method_union(function_type function)54 method_union(function_type function) : f(function) {} method_union()55 method_union() : m {nullptr} {} 56 ~method_union() = default; 57 } method; 58 59 public: 60 using Result = R; 61 using Arguments = std::tuple<Args...>; 62 63 callable() = default; 64 callable(const callable &) = default; 65 callable(callable &&) = default; 66 callable &operator=(const callable &) = default; 67 callable &operator=(callable &&) = default; 68 ~callable() = default; 69 70 template <typename T, typename = decltype(static_cast<R (T::*)(Args...) const>(&T::operator()))> callable(const T & obj)71 constexpr callable(const T &obj) 72 : object {reinterpret_cast<callable_type *>(&const_cast<T &>(obj))}, 73 method {reinterpret_cast<method_type>(static_cast<R (T::*)(Args...) const>(&T::operator()))} 74 { 75 } 76 77 template <typename T, typename = decltype(static_cast<R (T::*)(Args...)>(&T::operator()))> callable(T & obj)78 constexpr callable(T &obj) 79 : object {reinterpret_cast<callable_type *>(&const_cast<T &>(obj))}, 80 method {reinterpret_cast<method_type>(static_cast<R (T::*)(Args...)>(&T::operator()))} 81 { 82 } 83 84 template <typename T> callable(const T & obj,R (T::* param_method)(Args...)const)85 constexpr callable(const T &obj, R (T::*param_method)(Args...) const) 86 : object {reinterpret_cast<callable_type *>(&const_cast<T &>(obj))}, 87 method {reinterpret_cast<method_type>(param_method)} 88 { 89 } 90 91 template <typename T> callable(T & obj,R (T::* param_method)(Args...))92 constexpr callable(T &obj, R (T::*param_method)(Args...)) 93 : object {reinterpret_cast<callable_type *>(&const_cast<T &>(obj))}, 94 method {reinterpret_cast<method_type>(param_method)} 95 { 96 } 97 callable(function_type func)98 constexpr callable(function_type func) : object {nullptr}, method {func} {} 99 operator()100 constexpr R operator()(Args... args) const 101 { 102 if (object == nullptr) { 103 return (method.f)(args...); 104 } 105 return (object->*(method.m))(args...); 106 } 107 108 operator bool() const 109 { 110 return (method.m != nullptr) || (method.f != nullptr); 111 } 112 }; 113 } // namespace panda::verifier 114 115 #endif // PANDA_VERIF_PARSER_CALLABLE_H_ 116