1 /** 2 * Copyright (c) 2021-2024 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 ark::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 CallableType { 45 R operator()(Args...); 46 }; 47 using MethodType = R (CallableType::*)(Args...); 48 using FunctionType = R (*)(Args...); 49 CallableType *object_ {nullptr}; 50 union MethodUnion { 51 MethodType m {nullptr}; 52 FunctionType f; MethodUnion(MethodType method)53 explicit MethodUnion(MethodType method) : m(method) {} MethodUnion(FunctionType function)54 explicit MethodUnion(FunctionType function) : f(function) {} 55 MethodUnion() = default; 56 } method_; 57 58 public: 59 using Result = R; 60 using Arguments = std::tuple<Args...>; 61 62 callable() = default; 63 callable(const callable &) = default; 64 callable(callable &&) = default; 65 callable &operator=(const callable &) = default; // NOLINT(cppcoreguidelines-pro-type-union-access) 66 callable &operator=(callable &&) = default; // NOLINT(cppcoreguidelines-pro-type-union-access) 67 ~callable() = default; 68 69 template <typename T, typename = decltype(static_cast<R (T::*)(Args...) const>(&T::operator()))> callable(const T &obj)70 constexpr callable(const T &obj) // NOLINT(google-explicit-constructor) 71 : object_ {reinterpret_cast<CallableType *>(&const_cast<T &>(obj))}, 72 method_ {reinterpret_cast<MethodType>(static_cast<R (T::*)(Args...) const>(&T::operator()))} 73 { 74 } 75 76 template <typename T, typename = decltype(static_cast<R (T::*)(Args...)>(&T::operator()))> callable(T &obj)77 constexpr callable(T &obj) // NOLINT(google-explicit-constructor) 78 : object_ {reinterpret_cast<CallableType *>(&const_cast<T &>(obj))}, 79 method_ {reinterpret_cast<MethodType>(static_cast<R (T::*)(Args...)>(&T::operator()))} 80 { 81 } 82 83 template <typename T> callable(const T &obj, R (T::*paramMethod)(Args...) const)84 constexpr callable(const T &obj, R (T::*paramMethod)(Args...) const) 85 : object_ {reinterpret_cast<CallableType *>(&const_cast<T &>(obj))}, 86 method_ {reinterpret_cast<MethodType>(paramMethod)} 87 { 88 } 89 90 template <typename T> callable(T &obj, R (T::*paramMethod)(Args...))91 constexpr callable(T &obj, R (T::*paramMethod)(Args...)) 92 : object_ {reinterpret_cast<CallableType *>(&const_cast<T &>(obj))}, 93 method_ {reinterpret_cast<MethodType>(paramMethod)} 94 { 95 } 96 callable(FunctionType func)97 constexpr callable(FunctionType func) : method_ {func} {} // NOLINT(google-explicit-constructor) 98 operator ()(Args.... args) const99 constexpr R operator()(Args... args) const 100 { 101 if (object_ == nullptr) { 102 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access) 103 return (method_.f)(args...); 104 } 105 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access) 106 return (object_->*(method_.m))(args...); 107 } 108 operator bool() const109 operator bool() const // NOLINT(google-explicit-constructor) 110 { 111 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access) 112 return (method_.m != nullptr) || (method_.f != nullptr); 113 } 114 }; 115 } // namespace ark::verifier 116 117 #endif // PANDA_VERIF_PARSER_CALLABLE_H_ 118