-
Notifications
You must be signed in to change notification settings - Fork 73
Expand file tree
/
Copy pathstruct_type.h
More file actions
397 lines (302 loc) · 11.9 KB
/
Copy pathstruct_type.h
File metadata and controls
397 lines (302 loc) · 11.9 KB
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef THIRD_PARTY_CEL_CPP_BASE_TYPES_STRUCT_TYPE_H_
#define THIRD_PARTY_CEL_CPP_BASE_TYPES_STRUCT_TYPE_H_
#include <cstddef>
#include <cstdint>
#include <string>
#include <type_traits>
#include <utility>
#include "absl/base/attributes.h"
#include "absl/log/absl_check.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "absl/types/variant.h"
#include "base/internal/data.h"
#include "base/kind.h"
#include "base/memory.h"
#include "base/type.h"
#include "internal/rtti.h"
namespace cel {
namespace interop_internal {
struct LegacyStructTypeAccess;
}
class MemoryManager;
class StructValue;
class TypedStructValueFactory;
class TypeManager;
// StructType represents an struct type. An struct is a set of fields
// that can be looked up by name and/or number.
class StructType : public Type {
public:
struct Field;
class FieldId final {
public:
FieldId() = delete;
FieldId(const FieldId&) = default;
FieldId(FieldId&&) = default;
FieldId& operator=(const FieldId&) = default;
FieldId& operator=(FieldId&&) = default;
std::string DebugString() const;
friend bool operator==(const FieldId& lhs, const FieldId& rhs) {
return lhs.data_ == rhs.data_;
}
friend bool operator<(const FieldId& lhs, const FieldId& rhs);
template <typename H>
friend H AbslHashValue(H state, const FieldId& id) {
return H::combine(std::move(state), id.data_);
}
template <typename S>
friend void AbslStringify(S& sink, const FieldId& id) {
sink.Append(id.DebugString());
}
private:
friend class StructType;
friend class StructValue;
friend struct base_internal::FieldIdFactory;
explicit FieldId(absl::string_view name)
: data_(absl::in_place_type<absl::string_view>, name) {}
explicit FieldId(int64_t number)
: data_(absl::in_place_type<int64_t>, number) {}
absl::variant<absl::string_view, int64_t> data_;
};
static constexpr Kind kKind = Kind::kStruct;
static bool Is(const Type& type) { return type.kind() == kKind; }
using Type::Is;
static const StructType& Cast(const Type& type) {
ABSL_DCHECK(Is(type)) << "cannot cast " << type.name() << " to struct";
return static_cast<const StructType&>(type);
}
Kind kind() const { return kKind; }
absl::string_view name() const ABSL_ATTRIBUTE_LIFETIME_BOUND;
std::string DebugString() const;
size_t field_count() const;
// Find the field definition for the given identifier. If the field does
// not exist, an OK status and empty optional is returned. If the field
// exists, an OK status and the field is returned. Otherwise an error is
// returned.
absl::StatusOr<absl::optional<Field>> FindField(TypeManager& type_manager,
FieldId id) const
ABSL_ATTRIBUTE_LIFETIME_BOUND;
// Called by FindField.
absl::StatusOr<absl::optional<Field>> FindFieldByName(
TypeManager& type_manager,
absl::string_view name) const ABSL_ATTRIBUTE_LIFETIME_BOUND;
// Called by FindField.
absl::StatusOr<absl::optional<Field>> FindFieldByNumber(
TypeManager& type_manager,
int64_t number) const ABSL_ATTRIBUTE_LIFETIME_BOUND;
class FieldIterator;
absl::StatusOr<UniqueRef<FieldIterator>> NewFieldIterator(
MemoryManager& memory_manager) const ABSL_ATTRIBUTE_LIFETIME_BOUND;
protected:
static FieldId MakeFieldId(absl::string_view name) { return FieldId(name); }
static FieldId MakeFieldId(int64_t number) { return FieldId(number); }
template <typename E>
static std::enable_if_t<
std::conjunction_v<
std::is_enum<E>,
std::is_convertible<std::underlying_type_t<E>, int64_t>>,
FieldId>
MakeFieldId(E e) {
return MakeFieldId(
static_cast<int64_t>(static_cast<std::underlying_type_t<E>>(e)));
}
private:
friend internal::TypeInfo base_internal::GetStructTypeTypeId(
const StructType& struct_type);
struct FindFieldVisitor;
friend struct FindFieldVisitor;
friend class MemoryManager;
friend class TypeFactory;
friend class base_internal::TypeHandle;
friend class StructValue;
friend class base_internal::LegacyStructType;
friend class base_internal::AbstractStructType;
StructType() = default;
// Called by CEL_IMPLEMENT_STRUCT_TYPE() and Is() to perform type checking.
internal::TypeInfo TypeId() const;
};
// Field describes a single field in a struct. All fields are valid so long as
// StructType is valid, except Field::type which is managed.
struct StructType::Field final {
explicit Field(FieldId id, absl::string_view name, int64_t number,
Handle<Type> type, const void* hint = nullptr)
: id(id), name(name), number(number), type(std::move(type)), hint(hint) {}
// Identifier which allows the most efficient form of lookup, compared to
// looking up by name or number.
FieldId id;
// The field name.
absl::string_view name;
// The field number.
int64_t number;
// The field type;
Handle<Type> type;
// Some implementation-specific data that can be laundered to the value
// implementation for this type to enable potential optimizations.
const void* hint = nullptr;
};
class StructType::FieldIterator {
public:
using FieldId = StructType::FieldId;
using Field = StructType::Field;
virtual ~FieldIterator() = default;
ABSL_MUST_USE_RESULT virtual bool HasNext() = 0;
virtual absl::StatusOr<Field> Next(TypeManager& type_manager) = 0;
virtual absl::StatusOr<FieldId> NextId(TypeManager& type_manager);
virtual absl::StatusOr<absl::string_view> NextName(TypeManager& type_manager);
virtual absl::StatusOr<int64_t> NextNumber(TypeManager& type_manager);
virtual absl::StatusOr<Handle<Type>> NextType(TypeManager& type_manager);
};
namespace base_internal {
// In an ideal world we would just make StructType a heap type. Unfortunately we
// have to deal with our legacy API and we do not want to unncessarily perform
// heap allocations during interop. So we have an inline variant and heap
// variant.
ABSL_ATTRIBUTE_WEAK absl::string_view MessageTypeName(uintptr_t msg);
ABSL_ATTRIBUTE_WEAK size_t MessageTypeFieldCount(uintptr_t msg);
class LegacyStructValueFieldIterator;
class LegacyStructType final : public StructType, public InlineData {
public:
static bool Is(const Type& type) {
return StructType::Is(type) &&
static_cast<const StructType&>(type).TypeId() ==
internal::TypeId<LegacyStructType>();
}
using StructType::Is;
static const LegacyStructType& Cast(const Type& type) {
ABSL_DCHECK(Is(type)) << "cannot cast " << type.name() << " to struct";
return static_cast<const LegacyStructType&>(type);
}
absl::string_view name() const ABSL_ATTRIBUTE_LIFETIME_BOUND;
// Always returns the same string.
std::string DebugString() const { return std::string(name()); }
size_t field_count() const;
// Always returns an error.
absl::StatusOr<absl::optional<Field>> FindFieldByName(
TypeManager& type_manager,
absl::string_view name) const ABSL_ATTRIBUTE_LIFETIME_BOUND;
// Always returns an error.
absl::StatusOr<absl::optional<Field>> FindFieldByNumber(
TypeManager& type_manager,
int64_t number) const ABSL_ATTRIBUTE_LIFETIME_BOUND;
absl::StatusOr<UniqueRef<FieldIterator>> NewFieldIterator(
MemoryManager& memory_manager) const ABSL_ATTRIBUTE_LIFETIME_BOUND;
private:
static constexpr uintptr_t kMetadata =
kStoredInline | kTrivial | (static_cast<uintptr_t>(kKind) << kKindShift);
friend class LegacyStructValueFieldIterator;
friend struct interop_internal::LegacyStructTypeAccess;
friend class cel::StructType;
friend class LegacyStructValue;
template <size_t Size, size_t Align>
friend struct AnyData;
explicit LegacyStructType(uintptr_t msg)
: StructType(), InlineData(kMetadata), msg_(msg) {}
internal::TypeInfo TypeId() const {
return internal::TypeId<LegacyStructType>();
}
// This is a type erased pointer to google::protobuf::Message or LegacyTypeInfoApis. It
// is tagged when it is google::protobuf::Message.
uintptr_t msg_;
};
class AbstractStructType : public StructType, public HeapData {
public:
static bool Is(const Type& type) {
return StructType::Is(type) &&
static_cast<const StructType&>(type).TypeId() !=
internal::TypeId<LegacyStructType>();
}
using StructType::Is;
static const AbstractStructType& Cast(const Type& type) {
ABSL_DCHECK(Is(type)) << "cannot cast " << type.name() << " to struct";
return static_cast<const AbstractStructType&>(type);
}
virtual absl::string_view name() const ABSL_ATTRIBUTE_LIFETIME_BOUND = 0;
virtual std::string DebugString() const { return std::string(name()); }
virtual size_t field_count() const = 0;
// Called by FindField.
virtual absl::StatusOr<absl::optional<Field>> FindFieldByName(
TypeManager& type_manager,
absl::string_view name) const ABSL_ATTRIBUTE_LIFETIME_BOUND = 0;
// Called by FindField.
virtual absl::StatusOr<absl::optional<Field>> FindFieldByNumber(
TypeManager& type_manager,
int64_t number) const ABSL_ATTRIBUTE_LIFETIME_BOUND = 0;
virtual absl::StatusOr<UniqueRef<FieldIterator>> NewFieldIterator(
MemoryManager& memory_manager) const ABSL_ATTRIBUTE_LIFETIME_BOUND = 0;
protected:
AbstractStructType();
private:
friend internal::TypeInfo GetStructTypeTypeId(const StructType& struct_type);
struct FindFieldVisitor;
friend struct FindFieldVisitor;
friend class MemoryManager;
friend class TypeFactory;
friend class TypeHandle;
friend class StructValue;
friend class cel::StructType;
AbstractStructType(const AbstractStructType&) = delete;
AbstractStructType(AbstractStructType&&) = delete;
// Called by CEL_IMPLEMENT_STRUCT_TYPE() and Is() to perform type checking.
virtual internal::TypeInfo TypeId() const = 0;
};
} // namespace base_internal
#define CEL_STRUCT_TYPE_CLASS ::cel::base_internal::AbstractStructType
// CEL_DECLARE_STRUCT_TYPE declares `struct_type` as an struct type. It must be
// part of the class definition of `struct_type`.
//
// class MyStructType : public CEL_STRUCT_TYPE_CLASS {
// ...
// private:
// CEL_DECLARE_STRUCT_TYPE(MyStructType);
// };
#define CEL_DECLARE_STRUCT_TYPE(struct_type) \
CEL_INTERNAL_DECLARE_TYPE(Struct, struct_type)
// CEL_IMPLEMENT_ENUM_TYPE implements `struct_type` as an struct type. It
// must be called after the class definition of `struct_type`.
//
// class MyStructType : public CEL_STRUCT_TYPE_CLASS {
// ...
// private:
// CEL_DECLARE_STRUCT_TYPE(MyStructType);
// };
//
// CEL_IMPLEMENT_STRUCT_TYPE(MyStructType);
#define CEL_IMPLEMENT_STRUCT_TYPE(struct_type) \
CEL_INTERNAL_IMPLEMENT_TYPE(Struct, struct_type)
CEL_INTERNAL_TYPE_DECL(StructType);
namespace base_internal {
// This should be used for testing only, and is private.
struct FieldIdFactory {
static StructType::FieldId Make(absl::string_view name) {
return StructType::FieldId(name);
}
static StructType::FieldId Make(int64_t number) {
return StructType::FieldId(number);
}
};
inline internal::TypeInfo GetStructTypeTypeId(const StructType& struct_type) {
return struct_type.TypeId();
}
} // namespace base_internal
namespace base_internal {
template <>
struct TypeTraits<StructType> {
using value_type = StructValue;
};
} // namespace base_internal
} // namespace cel
#endif // THIRD_PARTY_CEL_CPP_BASE_TYPES_STRUCT_TYPE_H_