/proc/self/cwd/common/values/custom_map_value.h
Line | Count | Source |
1 | | // Copyright 2023 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 | | // IWYU pragma: private, include "common/value.h" |
16 | | // IWYU pragma: friend "common/value.h" |
17 | | |
18 | | // `CustomMapValue` represents values of the primitive `map` type. |
19 | | // `CustomMapValueView` is a non-owning view of `CustomMapValue`. |
20 | | // `CustomMapValueInterface` is the abstract base class of implementations. |
21 | | // `CustomMapValue` and `CustomMapValueView` act as smart pointers to |
22 | | // `CustomMapValueInterface`. |
23 | | |
24 | | #ifndef THIRD_PARTY_CEL_CPP_COMMON_VALUES_PARSED_MAP_VALUE_H_ |
25 | | #define THIRD_PARTY_CEL_CPP_COMMON_VALUES_PARSED_MAP_VALUE_H_ |
26 | | |
27 | | #include <cstddef> |
28 | | #include <ostream> |
29 | | #include <string> |
30 | | #include <utility> |
31 | | |
32 | | #include "absl/base/attributes.h" |
33 | | #include "absl/base/nullability.h" |
34 | | #include "absl/functional/function_ref.h" |
35 | | #include "absl/log/absl_check.h" |
36 | | #include "absl/status/status.h" |
37 | | #include "absl/status/statusor.h" |
38 | | #include "absl/strings/string_view.h" |
39 | | #include "common/native_type.h" |
40 | | #include "common/value_kind.h" |
41 | | #include "common/values/custom_value.h" |
42 | | #include "common/values/values.h" |
43 | | #include "google/protobuf/arena.h" |
44 | | #include "google/protobuf/descriptor.h" |
45 | | #include "google/protobuf/io/zero_copy_stream.h" |
46 | | #include "google/protobuf/message.h" |
47 | | |
48 | | namespace cel { |
49 | | |
50 | | class Value; |
51 | | class ListValue; |
52 | | class CustomMapValueInterface; |
53 | | class CustomMapValueInterfaceKeysIterator; |
54 | | class CustomMapValue; |
55 | | using CustomMapValueContent = CustomValueContent; |
56 | | |
57 | | struct CustomMapValueDispatcher { |
58 | | using GetTypeId = |
59 | | NativeTypeId (*)(const CustomMapValueDispatcher* absl_nonnull dispatcher, |
60 | | CustomMapValueContent content); |
61 | | |
62 | | using GetArena = google::protobuf::Arena* absl_nullable (*)( |
63 | | const CustomMapValueDispatcher* absl_nonnull dispatcher, |
64 | | CustomMapValueContent content); |
65 | | |
66 | | using DebugString = |
67 | | std::string (*)(const CustomMapValueDispatcher* absl_nonnull dispatcher, |
68 | | CustomMapValueContent content); |
69 | | |
70 | | using SerializeTo = absl::Status (*)( |
71 | | const CustomMapValueDispatcher* absl_nonnull dispatcher, |
72 | | CustomMapValueContent content, |
73 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
74 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
75 | | google::protobuf::io::ZeroCopyOutputStream* absl_nonnull output); |
76 | | |
77 | | using ConvertToJsonObject = absl::Status (*)( |
78 | | const CustomMapValueDispatcher* absl_nonnull dispatcher, |
79 | | CustomMapValueContent content, |
80 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
81 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
82 | | google::protobuf::Message* absl_nonnull json); |
83 | | |
84 | | using Equal = absl::Status (*)( |
85 | | const CustomMapValueDispatcher* absl_nonnull dispatcher, |
86 | | CustomMapValueContent content, const MapValue& other, |
87 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
88 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
89 | | google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result); |
90 | | |
91 | | using IsZeroValue = |
92 | | bool (*)(const CustomMapValueDispatcher* absl_nonnull dispatcher, |
93 | | CustomMapValueContent content); |
94 | | |
95 | | using IsEmpty = |
96 | | bool (*)(const CustomMapValueDispatcher* absl_nonnull dispatcher, |
97 | | CustomMapValueContent content); |
98 | | |
99 | | using Size = |
100 | | size_t (*)(const CustomMapValueDispatcher* absl_nonnull dispatcher, |
101 | | CustomMapValueContent content); |
102 | | |
103 | | using Find = absl::StatusOr<bool> (*)( |
104 | | const CustomMapValueDispatcher* absl_nonnull dispatcher, |
105 | | CustomMapValueContent content, const Value& key, |
106 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
107 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
108 | | google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result); |
109 | | |
110 | | using Has = absl::StatusOr<bool> (*)( |
111 | | const CustomMapValueDispatcher* absl_nonnull dispatcher, |
112 | | CustomMapValueContent content, const Value& key, |
113 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
114 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
115 | | google::protobuf::Arena* absl_nonnull arena); |
116 | | |
117 | | using ListKeys = absl::Status (*)( |
118 | | const CustomMapValueDispatcher* absl_nonnull dispatcher, |
119 | | CustomMapValueContent content, |
120 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
121 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
122 | | google::protobuf::Arena* absl_nonnull arena, ListValue* absl_nonnull result); |
123 | | |
124 | | using ForEach = absl::Status (*)( |
125 | | const CustomMapValueDispatcher* absl_nonnull dispatcher, |
126 | | CustomMapValueContent content, |
127 | | absl::FunctionRef<absl::StatusOr<bool>(const Value&, const Value&)> |
128 | | callback, |
129 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
130 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
131 | | google::protobuf::Arena* absl_nonnull arena); |
132 | | |
133 | | using NewIterator = absl::StatusOr<absl_nonnull ValueIteratorPtr> (*)( |
134 | | const CustomMapValueDispatcher* absl_nonnull dispatcher, |
135 | | CustomMapValueContent content); |
136 | | |
137 | | using Clone = CustomMapValue (*)( |
138 | | const CustomMapValueDispatcher* absl_nonnull dispatcher, |
139 | | CustomMapValueContent content, google::protobuf::Arena* absl_nonnull arena); |
140 | | |
141 | | absl_nonnull GetTypeId get_type_id; |
142 | | |
143 | | absl_nonnull GetArena get_arena; |
144 | | |
145 | | // If null, simply returns "map". |
146 | | absl_nullable DebugString debug_string = nullptr; |
147 | | |
148 | | // If null, attempts to serialize results in an UNIMPLEMENTED error. |
149 | | absl_nullable SerializeTo serialize_to = nullptr; |
150 | | |
151 | | // If null, attempts to convert to JSON results in an UNIMPLEMENTED error. |
152 | | absl_nullable ConvertToJsonObject convert_to_json_object = nullptr; |
153 | | |
154 | | // If null, an nonoptimal fallback implementation for equality is used. |
155 | | absl_nullable Equal equal = nullptr; |
156 | | |
157 | | absl_nonnull IsZeroValue is_zero_value; |
158 | | |
159 | | // If null, `size(...) == 0` is used. |
160 | | absl_nullable IsEmpty is_empty = nullptr; |
161 | | |
162 | | absl_nonnull Size size; |
163 | | |
164 | | absl_nonnull Find find; |
165 | | |
166 | | absl_nonnull Has has; |
167 | | |
168 | | absl_nonnull ListKeys list_keys; |
169 | | |
170 | | // If null, a fallback implementation based on `list_keys` is used. |
171 | | absl_nullable ForEach for_each = nullptr; |
172 | | |
173 | | // If null, a fallback implementation based on `list_keys` is used. |
174 | | absl_nullable NewIterator new_iterator = nullptr; |
175 | | |
176 | | absl_nonnull Clone clone; |
177 | | }; |
178 | | |
179 | | class CustomMapValueInterface { |
180 | | public: |
181 | 1.97k | CustomMapValueInterface() = default; |
182 | | CustomMapValueInterface(const CustomMapValueInterface&) = delete; |
183 | | CustomMapValueInterface(CustomMapValueInterface&&) = delete; |
184 | | |
185 | 283 | virtual ~CustomMapValueInterface() = default; |
186 | | |
187 | | CustomMapValueInterface& operator=(const CustomMapValueInterface&) = delete; |
188 | | CustomMapValueInterface& operator=(CustomMapValueInterface&&) = delete; |
189 | | |
190 | | using ForEachCallback = |
191 | | absl::FunctionRef<absl::StatusOr<bool>(const Value&, const Value&)>; |
192 | | |
193 | | private: |
194 | | friend class CustomMapValueInterfaceIterator; |
195 | | friend class CustomMapValue; |
196 | | friend absl::Status common_internal::MapValueEqual( |
197 | | const CustomMapValueInterface& lhs, const MapValue& rhs, |
198 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
199 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
200 | | google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result); |
201 | | |
202 | | virtual std::string DebugString() const = 0; |
203 | | |
204 | | virtual absl::Status SerializeTo( |
205 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
206 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
207 | | google::protobuf::io::ZeroCopyOutputStream* absl_nonnull output) const; |
208 | | |
209 | | virtual absl::Status ConvertToJsonObject( |
210 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
211 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
212 | | google::protobuf::Message* absl_nonnull json) const = 0; |
213 | | |
214 | | virtual absl::Status Equal( |
215 | | const MapValue& other, |
216 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
217 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
218 | | google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const; |
219 | | |
220 | 0 | virtual bool IsZeroValue() const { return IsEmpty(); } |
221 | | |
222 | | // Returns `true` if this map contains no entries, `false` otherwise. |
223 | 0 | virtual bool IsEmpty() const { return Size() == 0; } |
224 | | |
225 | | // Returns the number of entries in this map. |
226 | | virtual size_t Size() const = 0; |
227 | | |
228 | | // See the corresponding member function of `MapValue` for |
229 | | // documentation. |
230 | | virtual absl::Status ListKeys( |
231 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
232 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
233 | | google::protobuf::Arena* absl_nonnull arena, |
234 | | ListValue* absl_nonnull result) const = 0; |
235 | | |
236 | | // See the corresponding member function of `MapValue` for |
237 | | // documentation. |
238 | | virtual absl::Status ForEach( |
239 | | ForEachCallback callback, |
240 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
241 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
242 | | google::protobuf::Arena* absl_nonnull arena) const; |
243 | | |
244 | | // By default, implementations do not guarantee any iteration order. Unless |
245 | | // specified otherwise, assume the iteration order is random. |
246 | | virtual absl::StatusOr<absl_nonnull ValueIteratorPtr> NewIterator() const; |
247 | | |
248 | | virtual CustomMapValue Clone(google::protobuf::Arena* absl_nonnull arena) const = 0; |
249 | | |
250 | | virtual absl::StatusOr<bool> Find( |
251 | | const Value& key, |
252 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
253 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
254 | | google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const = 0; |
255 | | |
256 | | virtual absl::StatusOr<bool> Has( |
257 | | const Value& key, |
258 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
259 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
260 | | google::protobuf::Arena* absl_nonnull arena) const = 0; |
261 | | |
262 | | virtual NativeTypeId GetNativeTypeId() const = 0; |
263 | | |
264 | | struct Content { |
265 | | const CustomMapValueInterface* absl_nonnull interface; |
266 | | google::protobuf::Arena* absl_nullable arena; |
267 | | }; |
268 | | }; |
269 | | |
270 | | // Creates a custom map value from a manual dispatch table `dispatcher` and |
271 | | // opaque data `content` whose format is only know to functions in the manual |
272 | | // dispatch table. The dispatch table should probably be valid for the lifetime |
273 | | // of the process, but at a minimum must outlive all instances of the resulting |
274 | | // value. |
275 | | // |
276 | | // IMPORTANT: This approach to implementing CustomMapValue should only be |
277 | | // used when you know exactly what you are doing. When in doubt, just implement |
278 | | // CustomMapValueInterface. |
279 | | CustomMapValue UnsafeCustomMapValue(const CustomMapValueDispatcher* absl_nonnull |
280 | | dispatcher ABSL_ATTRIBUTE_LIFETIME_BOUND, |
281 | | CustomMapValueContent content); |
282 | | |
283 | | class CustomMapValue final |
284 | | : private common_internal::MapValueMixin<CustomMapValue> { |
285 | | public: |
286 | | static constexpr ValueKind kKind = ValueKind::kMap; |
287 | | |
288 | | // Constructs a custom map value from an implementation of |
289 | | // `CustomMapValueInterface` `interface` whose lifetime is tied to that of |
290 | | // the arena `arena`. |
291 | | CustomMapValue(const CustomMapValueInterface* absl_nonnull |
292 | | interface ABSL_ATTRIBUTE_LIFETIME_BOUND, |
293 | | google::protobuf::Arena* absl_nonnull arena |
294 | 1.97k | ABSL_ATTRIBUTE_LIFETIME_BOUND) { |
295 | 1.97k | ABSL_DCHECK(interface != nullptr); |
296 | 1.97k | ABSL_DCHECK(arena != nullptr); |
297 | 1.97k | content_ = CustomMapValueContent::From(CustomMapValueInterface::Content{ |
298 | 1.97k | .interface = interface, .arena = arena}); |
299 | 1.97k | } |
300 | | |
301 | | // By default, this creates an empty map whose type is `map(dyn, dyn)`. Unless |
302 | | // you can help it, you should use a more specific typed map value. |
303 | | CustomMapValue(); |
304 | | CustomMapValue(const CustomMapValue&) = default; |
305 | | CustomMapValue(CustomMapValue&&) = default; |
306 | | CustomMapValue& operator=(const CustomMapValue&) = default; |
307 | | CustomMapValue& operator=(CustomMapValue&&) = default; |
308 | | |
309 | 0 | static constexpr ValueKind kind() { return kKind; } |
310 | | |
311 | | NativeTypeId GetTypeId() const; |
312 | | |
313 | | absl::string_view GetTypeName() const; |
314 | | |
315 | | std::string DebugString() const; |
316 | | |
317 | | // See Value::SerializeTo(). |
318 | | absl::Status SerializeTo( |
319 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
320 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
321 | | google::protobuf::io::ZeroCopyOutputStream* absl_nonnull output) const; |
322 | | |
323 | | // See Value::ConvertToJson(). |
324 | | absl::Status ConvertToJson( |
325 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
326 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
327 | | google::protobuf::Message* absl_nonnull json) const; |
328 | | |
329 | | // See Value::ConvertToJsonObject(). |
330 | | absl::Status ConvertToJsonObject( |
331 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
332 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
333 | | google::protobuf::Message* absl_nonnull json) const; |
334 | | |
335 | | absl::Status Equal(const Value& other, |
336 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
337 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
338 | | google::protobuf::Arena* absl_nonnull arena, |
339 | | Value* absl_nonnull result) const; |
340 | | using MapValueMixin::Equal; |
341 | | |
342 | | bool IsZeroValue() const; |
343 | | |
344 | | CustomMapValue Clone(google::protobuf::Arena* absl_nonnull arena) const; |
345 | | |
346 | | bool IsEmpty() const; |
347 | | |
348 | | size_t Size() const; |
349 | | |
350 | | // See the corresponding member function of `MapValue` for |
351 | | // documentation. |
352 | | absl::Status Get(const Value& key, |
353 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
354 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
355 | | google::protobuf::Arena* absl_nonnull arena, |
356 | | Value* absl_nonnull result) const; |
357 | | using MapValueMixin::Get; |
358 | | |
359 | | // See the corresponding member function of `MapValue` for |
360 | | // documentation. |
361 | | absl::StatusOr<bool> Find( |
362 | | const Value& key, |
363 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
364 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
365 | | google::protobuf::Arena* absl_nonnull arena, Value* absl_nonnull result) const; |
366 | | using MapValueMixin::Find; |
367 | | |
368 | | // See the corresponding member function of `MapValue` for |
369 | | // documentation. |
370 | | absl::Status Has(const Value& key, |
371 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
372 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
373 | | google::protobuf::Arena* absl_nonnull arena, |
374 | | Value* absl_nonnull result) const; |
375 | | using MapValueMixin::Has; |
376 | | |
377 | | // See the corresponding member function of `MapValue` for |
378 | | // documentation. |
379 | | absl::Status ListKeys( |
380 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
381 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
382 | | google::protobuf::Arena* absl_nonnull arena, ListValue* absl_nonnull result) const; |
383 | | using MapValueMixin::ListKeys; |
384 | | |
385 | | // See the corresponding type declaration of `MapValueInterface` for |
386 | | // documentation. |
387 | | using ForEachCallback = typename CustomMapValueInterface::ForEachCallback; |
388 | | |
389 | | // See the corresponding member function of `MapValue` for |
390 | | // documentation. |
391 | | absl::Status ForEach( |
392 | | ForEachCallback callback, |
393 | | const google::protobuf::DescriptorPool* absl_nonnull descriptor_pool, |
394 | | google::protobuf::MessageFactory* absl_nonnull message_factory, |
395 | | google::protobuf::Arena* absl_nonnull arena) const; |
396 | | |
397 | | // See the corresponding member function of `MapValue` for |
398 | | // documentation. |
399 | | absl::StatusOr<absl_nonnull ValueIteratorPtr> NewIterator() const; |
400 | | |
401 | 0 | const CustomMapValueDispatcher* absl_nullable dispatcher() const { |
402 | 0 | return dispatcher_; |
403 | 0 | } |
404 | | |
405 | 0 | CustomMapValueContent content() const { |
406 | 0 | ABSL_DCHECK(dispatcher_ != nullptr); |
407 | 0 | return content_; |
408 | 0 | } |
409 | | |
410 | 43 | const CustomMapValueInterface* absl_nullable interface() const { |
411 | 43 | if (dispatcher_ == nullptr) { |
412 | 43 | return content_.To<CustomMapValueInterface::Content>().interface; |
413 | 43 | } |
414 | 0 | return nullptr; |
415 | 43 | } |
416 | | |
417 | 0 | friend void swap(CustomMapValue& lhs, CustomMapValue& rhs) noexcept { |
418 | 0 | using std::swap; |
419 | 0 | swap(lhs.dispatcher_, rhs.dispatcher_); |
420 | 0 | swap(lhs.content_, rhs.content_); |
421 | 0 | } |
422 | | |
423 | | private: |
424 | | friend class common_internal::ValueMixin<CustomMapValue>; |
425 | | friend class common_internal::MapValueMixin<CustomMapValue>; |
426 | | friend CustomMapValue UnsafeCustomMapValue( |
427 | | const CustomMapValueDispatcher* absl_nonnull dispatcher |
428 | | ABSL_ATTRIBUTE_LIFETIME_BOUND, |
429 | | CustomMapValueContent content); |
430 | | |
431 | | CustomMapValue(const CustomMapValueDispatcher* absl_nonnull dispatcher, |
432 | | CustomMapValueContent content) |
433 | 0 | : dispatcher_(dispatcher), content_(content) { |
434 | 0 | ABSL_DCHECK(dispatcher != nullptr); |
435 | 0 | ABSL_DCHECK(dispatcher->get_type_id != nullptr); |
436 | 0 | ABSL_DCHECK(dispatcher->get_arena != nullptr); |
437 | 0 | ABSL_DCHECK(dispatcher->is_zero_value != nullptr); |
438 | 0 | ABSL_DCHECK(dispatcher->size != nullptr); |
439 | 0 | ABSL_DCHECK(dispatcher->find != nullptr); |
440 | 0 | ABSL_DCHECK(dispatcher->has != nullptr); |
441 | 0 | ABSL_DCHECK(dispatcher->list_keys != nullptr); |
442 | 0 | ABSL_DCHECK(dispatcher->clone != nullptr); |
443 | 0 | } |
444 | | |
445 | | const CustomMapValueDispatcher* absl_nullable dispatcher_ = nullptr; |
446 | | CustomMapValueContent content_ = CustomMapValueContent::Zero(); |
447 | | }; |
448 | | |
449 | 0 | inline std::ostream& operator<<(std::ostream& out, const CustomMapValue& type) { |
450 | 0 | return out << type.DebugString(); |
451 | 0 | } |
452 | | |
453 | | template <> |
454 | | struct NativeTypeTraits<CustomMapValue> final { |
455 | 43 | static NativeTypeId Id(const CustomMapValue& type) { |
456 | 43 | return type.GetTypeId(); |
457 | 43 | } |
458 | | }; |
459 | | |
460 | | inline CustomMapValue UnsafeCustomMapValue( |
461 | | const CustomMapValueDispatcher* absl_nonnull dispatcher |
462 | | ABSL_ATTRIBUTE_LIFETIME_BOUND, |
463 | 0 | CustomMapValueContent content) { |
464 | 0 | return CustomMapValue(dispatcher, content); |
465 | 0 | } |
466 | | |
467 | | } // namespace cel |
468 | | |
469 | | #endif // THIRD_PARTY_CEL_CPP_COMMON_VALUES_PARSED_MAP_VALUE_H_ |