1 | // Copyright 2019 Google LLC |
2 | // |
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 | // https://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 | #ifndef dap_typeof_h |
16 | #define dap_typeof_h |
17 | |
18 | #include "typeinfo.h" |
19 | #include "types.h" |
20 | |
21 | #include "serialization.h" |
22 | |
23 | namespace dap { |
24 | |
25 | // BasicTypeInfo is an implementation of the TypeInfo interface for the simple |
26 | // template type T. |
27 | template <typename T> |
28 | struct BasicTypeInfo : public TypeInfo { |
29 | constexpr BasicTypeInfo(std::string&& name) : name_(std::move(name)) {} |
30 | |
31 | // TypeInfo compliance |
32 | inline std::string name() const override { return name_; } |
33 | inline size_t size() const override { return sizeof(T); } |
34 | inline size_t alignment() const override { return alignof(T); } |
35 | inline void construct(void* ptr) const override { new (ptr) T(); } |
36 | inline void copyConstruct(void* dst, const void* src) const override { |
37 | new (dst) T(*reinterpret_cast<const T*>(src)); |
38 | } |
39 | inline void destruct(void* ptr) const override { |
40 | reinterpret_cast<T*>(ptr)->~T(); |
41 | } |
42 | inline bool deserialize(const Deserializer* d, void* ptr) const override { |
43 | return d->deserialize(reinterpret_cast<T*>(ptr)); |
44 | } |
45 | inline bool serialize(Serializer* s, const void* ptr) const override { |
46 | return s->serialize(*reinterpret_cast<const T*>(ptr)); |
47 | } |
48 | |
49 | private: |
50 | std::string name_; |
51 | }; |
52 | |
53 | // TypeOf has a template specialization for each DAP type, each declaring a |
54 | // const TypeInfo* type() static member function that describes type T. |
55 | template <typename T> |
56 | struct TypeOf {}; |
57 | |
58 | template <> |
59 | struct TypeOf<boolean> { |
60 | static const TypeInfo* type(); |
61 | }; |
62 | |
63 | template <> |
64 | struct TypeOf<string> { |
65 | static const TypeInfo* type(); |
66 | }; |
67 | |
68 | template <> |
69 | struct TypeOf<integer> { |
70 | static const TypeInfo* type(); |
71 | }; |
72 | |
73 | template <> |
74 | struct TypeOf<number> { |
75 | static const TypeInfo* type(); |
76 | }; |
77 | |
78 | template <> |
79 | struct TypeOf<object> { |
80 | static const TypeInfo* type(); |
81 | }; |
82 | |
83 | template <> |
84 | struct TypeOf<any> { |
85 | static const TypeInfo* type(); |
86 | }; |
87 | |
88 | template <> |
89 | struct TypeOf<null> { |
90 | static const TypeInfo* type(); |
91 | }; |
92 | |
93 | template <typename T> |
94 | struct TypeOf<array<T>> { |
95 | static inline const TypeInfo* type() { |
96 | static auto typeinfo = TypeInfo::create<BasicTypeInfo<array<T>>>( |
97 | "array<" + TypeOf<T>::type()->name() + ">" ); |
98 | return typeinfo; |
99 | } |
100 | }; |
101 | |
102 | template <typename T0, typename... Types> |
103 | struct TypeOf<variant<T0, Types...>> { |
104 | static inline const TypeInfo* type() { |
105 | static auto typeinfo = |
106 | TypeInfo::create<BasicTypeInfo<variant<T0, Types...>>>("variant" ); |
107 | return typeinfo; |
108 | } |
109 | }; |
110 | |
111 | template <typename T> |
112 | struct TypeOf<optional<T>> { |
113 | static inline const TypeInfo* type() { |
114 | static auto typeinfo = TypeInfo::create<BasicTypeInfo<optional<T>>>( |
115 | "optional<" + TypeOf<T>::type()->name() + ">" ); |
116 | return typeinfo; |
117 | } |
118 | }; |
119 | |
120 | // DAP_OFFSETOF() macro is a generalization of the offsetof() macro defined in |
121 | // <cstddef>. It evaluates to the offset of the given field, with fewer |
122 | // restrictions than offsetof(). We cast the address '32' and subtract it again, |
123 | // because null-dereference is undefined behavior. |
124 | #define DAP_OFFSETOF(s, m) \ |
125 | ((int)(size_t) & reinterpret_cast<const volatile char&>((((s*)32)->m)) - 32) |
126 | |
127 | // internal functionality |
128 | namespace detail { |
129 | template <class T, class M> |
130 | M member_type(M T::*); |
131 | } // namespace detail |
132 | |
133 | // DAP_TYPEOF() returns the type of the struct (s) member (m). |
134 | #define DAP_TYPEOF(s, m) decltype(detail::member_type(&s::m)) |
135 | |
136 | // DAP_FIELD() declares a structure field for the DAP_IMPLEMENT_STRUCT_TYPEINFO |
137 | // macro. |
138 | // FIELD is the name of the struct field. |
139 | // NAME is the serialized name of the field, as described by the DAP |
140 | // specification. |
141 | #define DAP_FIELD(FIELD, NAME) \ |
142 | ::dap::Field { \ |
143 | NAME, DAP_OFFSETOF(StructTy, FIELD), \ |
144 | TypeOf<DAP_TYPEOF(StructTy, FIELD)>::type(), \ |
145 | } |
146 | |
147 | // DAP_DECLARE_STRUCT_TYPEINFO() declares a TypeOf<> specialization for STRUCT. |
148 | // Must be used within the 'dap' namespace. |
149 | #define DAP_DECLARE_STRUCT_TYPEINFO(STRUCT) \ |
150 | template <> \ |
151 | struct TypeOf<STRUCT> { \ |
152 | static constexpr bool has_custom_serialization = true; \ |
153 | static const TypeInfo* type(); \ |
154 | static bool deserializeFields(const Deserializer*, void* obj); \ |
155 | static bool serializeFields(FieldSerializer*, const void* obj); \ |
156 | } |
157 | |
158 | // DAP_IMPLEMENT_STRUCT_FIELD_SERIALIZATION() implements the deserializeFields() |
159 | // and serializeFields() static methods of a TypeOf<> specialization. Used |
160 | // internally by DAP_IMPLEMENT_STRUCT_TYPEINFO() and |
161 | // DAP_IMPLEMENT_STRUCT_TYPEINFO_EXT(). |
162 | // You probably do not want to use this directly. |
163 | #define DAP_IMPLEMENT_STRUCT_FIELD_SERIALIZATION(STRUCT, NAME, ...) \ |
164 | bool TypeOf<STRUCT>::deserializeFields(const Deserializer* d, void* obj) { \ |
165 | using StructTy = STRUCT; \ |
166 | (void)sizeof(StructTy); /* avoid unused 'using' warning */ \ |
167 | for (auto field : std::initializer_list<Field>{__VA_ARGS__}) { \ |
168 | if (!d->field(field.name, [&](Deserializer* d) { \ |
169 | auto ptr = reinterpret_cast<uint8_t*>(obj) + field.offset; \ |
170 | return field.type->deserialize(d, ptr); \ |
171 | })) { \ |
172 | return false; \ |
173 | } \ |
174 | } \ |
175 | return true; \ |
176 | } \ |
177 | bool TypeOf<STRUCT>::serializeFields(FieldSerializer* s, const void* obj) { \ |
178 | using StructTy = STRUCT; \ |
179 | (void)sizeof(StructTy); /* avoid unused 'using' warning */ \ |
180 | for (auto field : std::initializer_list<Field>{__VA_ARGS__}) { \ |
181 | if (!s->field(field.name, [&](Serializer* s) { \ |
182 | auto ptr = reinterpret_cast<const uint8_t*>(obj) + field.offset; \ |
183 | return field.type->serialize(s, ptr); \ |
184 | })) { \ |
185 | return false; \ |
186 | } \ |
187 | } \ |
188 | return true; \ |
189 | } |
190 | |
191 | // DAP_IMPLEMENT_STRUCT_TYPEINFO() implements the type() member function for the |
192 | // TypeOf<> specialization for STRUCT. |
193 | // STRUCT is the structure typename. |
194 | // NAME is the serialized name of the structure, as described by the DAP |
195 | // specification. The variadic (...) parameters should be a repeated list of |
196 | // DAP_FIELD()s, one for each field of the struct. |
197 | // Must be used within the 'dap' namespace. |
198 | #define DAP_IMPLEMENT_STRUCT_TYPEINFO(STRUCT, NAME, ...) \ |
199 | DAP_IMPLEMENT_STRUCT_FIELD_SERIALIZATION(STRUCT, NAME, __VA_ARGS__) \ |
200 | const ::dap::TypeInfo* TypeOf<STRUCT>::type() { \ |
201 | struct TI : BasicTypeInfo<STRUCT> { \ |
202 | TI() : BasicTypeInfo<STRUCT>(NAME) {} \ |
203 | bool deserialize(const Deserializer* d, void* obj) const override { \ |
204 | return deserializeFields(d, obj); \ |
205 | } \ |
206 | bool serialize(Serializer* s, const void* obj) const override { \ |
207 | return s->object( \ |
208 | [&](FieldSerializer* fs) { return serializeFields(fs, obj); }); \ |
209 | } \ |
210 | }; \ |
211 | static TI typeinfo; \ |
212 | return &typeinfo; \ |
213 | } |
214 | |
215 | // DAP_STRUCT_TYPEINFO() is a helper for declaring and implementing a TypeOf<> |
216 | // specialization for STRUCT in a single statement. |
217 | // Must be used within the 'dap' namespace. |
218 | #define DAP_STRUCT_TYPEINFO(STRUCT, NAME, ...) \ |
219 | DAP_DECLARE_STRUCT_TYPEINFO(STRUCT); \ |
220 | DAP_IMPLEMENT_STRUCT_TYPEINFO(STRUCT, NAME, __VA_ARGS__) |
221 | |
222 | // DAP_IMPLEMENT_STRUCT_TYPEINFO_EXT() implements the type() member function for |
223 | // the TypeOf<> specialization for STRUCT that derives from BASE. |
224 | // STRUCT is the structure typename. |
225 | // BASE is the base structure typename. |
226 | // NAME is the serialized name of the structure, as described by the DAP |
227 | // specification. The variadic (...) parameters should be a repeated list of |
228 | // DAP_FIELD()s, one for each field of the struct. |
229 | // Must be used within the 'dap' namespace. |
230 | #define DAP_IMPLEMENT_STRUCT_TYPEINFO_EXT(STRUCT, BASE, NAME, ...) \ |
231 | static_assert(std::is_base_of<BASE, STRUCT>::value, \ |
232 | #STRUCT " does not derive from " #BASE); \ |
233 | DAP_IMPLEMENT_STRUCT_FIELD_SERIALIZATION(STRUCT, NAME, __VA_ARGS__) \ |
234 | const ::dap::TypeInfo* TypeOf<STRUCT>::type() { \ |
235 | struct TI : BasicTypeInfo<STRUCT> { \ |
236 | TI() : BasicTypeInfo<STRUCT>(NAME) {} \ |
237 | bool deserialize(const Deserializer* d, void* obj) const override { \ |
238 | auto derived = static_cast<STRUCT*>(obj); \ |
239 | auto base = static_cast<BASE*>(obj); \ |
240 | return TypeOf<BASE>::deserializeFields(d, base) && \ |
241 | deserializeFields(d, derived); \ |
242 | } \ |
243 | bool serialize(Serializer* s, const void* obj) const override { \ |
244 | return s->object([&](FieldSerializer* fs) { \ |
245 | auto derived = static_cast<const STRUCT*>(obj); \ |
246 | auto base = static_cast<const BASE*>(obj); \ |
247 | return TypeOf<BASE>::serializeFields(fs, base) && \ |
248 | serializeFields(fs, derived); \ |
249 | }); \ |
250 | } \ |
251 | }; \ |
252 | static TI typeinfo; \ |
253 | return &typeinfo; \ |
254 | } |
255 | |
256 | // DAP_STRUCT_TYPEINFO_EXT() is a helper for declaring and implementing a |
257 | // TypeOf<> specialization for STRUCT that derives from BASE in a single |
258 | // statement. |
259 | // Must be used within the 'dap' namespace. |
260 | #define DAP_STRUCT_TYPEINFO_EXT(STRUCT, BASE, NAME, ...) \ |
261 | DAP_DECLARE_STRUCT_TYPEINFO(STRUCT); \ |
262 | DAP_IMPLEMENT_STRUCT_TYPEINFO_EXT(STRUCT, BASE, NAME, __VA_ARGS__) |
263 | |
264 | } // namespace dap |
265 | |
266 | #endif // dap_typeof_h |
267 | |