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