Skip to content

Commit 78272bd

Browse files
jckingcopybara-github
authored andcommitted
Add dispatch table support for CustomListValue
PiperOrigin-RevId: 736513134
1 parent 0b2a2fc commit 78272bd

19 files changed

+2238
-323
lines changed

common/BUILD

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,16 +656,22 @@ cc_test(
656656
":value",
657657
":value_kind",
658658
":value_testing",
659+
"//base:attributes",
659660
"//internal:parse_text_proto",
661+
"//internal:status_macros",
660662
"//internal:testing",
661663
"//internal:testing_descriptor_pool",
662664
"//internal:testing_message_factory",
665+
"//runtime:runtime_options",
663666
"@com_google_absl//absl/base:core_headers",
667+
"@com_google_absl//absl/base:nullability",
668+
"@com_google_absl//absl/functional:function_ref",
664669
"@com_google_absl//absl/hash",
665670
"@com_google_absl//absl/log:die_if_null",
666671
"@com_google_absl//absl/status",
667672
"@com_google_absl//absl/status:status_matchers",
668673
"@com_google_absl//absl/status:statusor",
674+
"@com_google_absl//absl/strings",
669675
"@com_google_absl//absl/strings:cord",
670676
"@com_google_absl//absl/strings:cord_test_helpers",
671677
"@com_google_absl//absl/strings:string_view",

common/value.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2820,6 +2820,7 @@ absl::StatusOr<std::pair<Value, int>> StructValueMixin<Base>::Qualify(
28202820
absl::Nonnull<const google::protobuf::DescriptorPool*> descriptor_pool,
28212821
absl::Nonnull<google::protobuf::MessageFactory*> message_factory,
28222822
absl::Nonnull<google::protobuf::Arena*> arena) const {
2823+
ABSL_DCHECK_GT(qualifiers.size(), 0);
28232824
ABSL_DCHECK(descriptor_pool != nullptr);
28242825
ABSL_DCHECK(message_factory != nullptr);
28252826
ABSL_DCHECK(arena != nullptr);

common/value_testing.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,13 +263,13 @@ class ValueTest : public ::testing::TestWithParam<std::tuple<Ts...>> {
263263
}
264264

265265
template <typename T>
266-
auto GeneratedParseTextProto(absl::string_view text) {
266+
auto GeneratedParseTextProto(absl::string_view text = "") {
267267
return ::cel::internal::GeneratedParseTextProto<T>(
268268
arena(), text, descriptor_pool(), message_factory());
269269
}
270270

271271
template <typename T>
272-
auto DynamicParseTextProto(absl::string_view text) {
272+
auto DynamicParseTextProto(absl::string_view text = "") {
273273
return ::cel::internal::DynamicParseTextProto<T>(
274274
arena(), text, descriptor_pool(), message_factory());
275275
}

common/values/custom_list_value.cc

Lines changed: 293 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
#include "absl/strings/str_cat.h"
2727
#include "absl/strings/string_view.h"
2828
#include "common/casting.h"
29-
#include "common/memory.h"
29+
#include "common/native_type.h"
3030
#include "common/value.h"
3131
#include "common/values/list_value_builder.h"
3232
#include "common/values/values.h"
@@ -90,8 +90,8 @@ class EmptyListValue final : public common_internal::CompatListValue {
9090
return absl::OkStatus();
9191
}
9292

93-
CustomListValue Clone(absl::Nonnull<google::protobuf::Arena*>) const override {
94-
return CustomListValue();
93+
CustomListValue Clone(absl::Nonnull<google::protobuf::Arena*> arena) const override {
94+
return CustomListValue(&EmptyListValue::Get(), arena);
9595
}
9696

9797
int size() const override { return 0; }
@@ -159,6 +159,40 @@ class CustomListValueInterfaceIterator final : public ValueIterator {
159159
size_t index_ = 0;
160160
};
161161

162+
namespace {
163+
164+
class CustomListValueDispatcherIterator final : public ValueIterator {
165+
public:
166+
explicit CustomListValueDispatcherIterator(
167+
absl::Nonnull<const CustomListValueDispatcher*> dispatcher,
168+
CustomListValueContent content, size_t size)
169+
: dispatcher_(dispatcher), content_(content), size_(size) {}
170+
171+
bool HasNext() override { return index_ < size_; }
172+
173+
absl::Status Next(
174+
absl::Nonnull<const google::protobuf::DescriptorPool*> descriptor_pool,
175+
absl::Nonnull<google::protobuf::MessageFactory*> message_factory,
176+
absl::Nonnull<google::protobuf::Arena*> arena,
177+
absl::Nonnull<Value*> result) override {
178+
if (ABSL_PREDICT_FALSE(index_ >= size_)) {
179+
return absl::FailedPreconditionError(
180+
"ValueIterator::Next() called when "
181+
"ValueIterator::HasNext() returns false");
182+
}
183+
return dispatcher_->get(dispatcher_, content_, index_++, descriptor_pool,
184+
message_factory, arena, result);
185+
}
186+
187+
private:
188+
absl::Nonnull<const CustomListValueDispatcher*> const dispatcher_;
189+
const CustomListValueContent content_;
190+
const size_t size_;
191+
size_t index_ = 0;
192+
};
193+
194+
} // namespace
195+
162196
absl::Status CustomListValueInterface::SerializeTo(
163197
absl::Nonnull<const google::protobuf::DescriptorPool*> descriptor_pool,
164198
absl::Nonnull<google::protobuf::MessageFactory*> message_factory,
@@ -257,21 +291,269 @@ absl::Status CustomListValueInterface::Contains(
257291
return absl::OkStatus();
258292
}
259293

260-
CustomListValue::CustomListValue()
261-
: CustomListValue(Owned(Owner::None(), &EmptyListValue::Get())) {}
294+
CustomListValue::CustomListValue() {
295+
content_ = CustomListValueContent::From(CustomListValueInterface::Content{
296+
.interface = &EmptyListValue::Get(), .arena = nullptr});
297+
}
298+
299+
NativeTypeId CustomListValue::GetTypeId() const {
300+
if (dispatcher_ == nullptr) {
301+
CustomListValueInterface::Content content =
302+
content_.To<CustomListValueInterface::Content>();
303+
ABSL_DCHECK(content.interface != nullptr);
304+
return NativeTypeId::Of(*content.interface);
305+
}
306+
return dispatcher_->get_type_id(dispatcher_, content_);
307+
}
308+
309+
absl::string_view CustomListValue::GetTypeName() const { return "list"; }
310+
311+
std::string CustomListValue::DebugString() const {
312+
if (dispatcher_ == nullptr) {
313+
CustomListValueInterface::Content content =
314+
content_.To<CustomListValueInterface::Content>();
315+
ABSL_DCHECK(content.interface != nullptr);
316+
return content.interface->DebugString();
317+
}
318+
if (dispatcher_->debug_string != nullptr) {
319+
return dispatcher_->debug_string(dispatcher_, content_);
320+
}
321+
return "list";
322+
}
323+
324+
absl::Status CustomListValue::SerializeTo(
325+
absl::Nonnull<const google::protobuf::DescriptorPool*> descriptor_pool,
326+
absl::Nonnull<google::protobuf::MessageFactory*> message_factory,
327+
absl::Nonnull<absl::Cord*> value) const {
328+
if (dispatcher_ == nullptr) {
329+
CustomListValueInterface::Content content =
330+
content_.To<CustomListValueInterface::Content>();
331+
ABSL_DCHECK(content.interface != nullptr);
332+
return content.interface->SerializeTo(descriptor_pool, message_factory,
333+
value);
334+
}
335+
if (dispatcher_->serialize_to != nullptr) {
336+
return dispatcher_->serialize_to(dispatcher_, content_, descriptor_pool,
337+
message_factory, value);
338+
}
339+
return absl::UnimplementedError(
340+
absl::StrCat(GetTypeName(), " is unserializable"));
341+
}
342+
343+
absl::Status CustomListValue::ConvertToJson(
344+
absl::Nonnull<const google::protobuf::DescriptorPool*> descriptor_pool,
345+
absl::Nonnull<google::protobuf::MessageFactory*> message_factory,
346+
absl::Nonnull<google::protobuf::Message*> json) const {
347+
ABSL_DCHECK(descriptor_pool != nullptr);
348+
ABSL_DCHECK(message_factory != nullptr);
349+
ABSL_DCHECK(json != nullptr);
350+
ABSL_DCHECK_EQ(json->GetDescriptor()->well_known_type(),
351+
google::protobuf::Descriptor::WELLKNOWNTYPE_VALUE);
352+
353+
ValueReflection value_reflection;
354+
CEL_RETURN_IF_ERROR(value_reflection.Initialize(json->GetDescriptor()));
355+
google::protobuf::Message* json_array = value_reflection.MutableListValue(json);
356+
357+
return ConvertToJsonArray(descriptor_pool, message_factory, json_array);
358+
}
359+
360+
absl::Status CustomListValue::ConvertToJsonArray(
361+
absl::Nonnull<const google::protobuf::DescriptorPool*> descriptor_pool,
362+
absl::Nonnull<google::protobuf::MessageFactory*> message_factory,
363+
absl::Nonnull<google::protobuf::Message*> json) const {
364+
ABSL_DCHECK(descriptor_pool != nullptr);
365+
ABSL_DCHECK(message_factory != nullptr);
366+
ABSL_DCHECK(json != nullptr);
367+
ABSL_DCHECK_EQ(json->GetDescriptor()->well_known_type(),
368+
google::protobuf::Descriptor::WELLKNOWNTYPE_LISTVALUE);
369+
370+
if (dispatcher_ == nullptr) {
371+
CustomListValueInterface::Content content =
372+
content_.To<CustomListValueInterface::Content>();
373+
ABSL_DCHECK(content.interface != nullptr);
374+
return content.interface->ConvertToJsonArray(descriptor_pool,
375+
message_factory, json);
376+
}
377+
if (dispatcher_->convert_to_json_array != nullptr) {
378+
return dispatcher_->convert_to_json_array(
379+
dispatcher_, content_, descriptor_pool, message_factory, json);
380+
}
381+
return absl::UnimplementedError(
382+
absl::StrCat(GetTypeName(), " is not convertable to JSON"));
383+
}
384+
385+
absl::Status CustomListValue::Equal(
386+
const Value& other,
387+
absl::Nonnull<const google::protobuf::DescriptorPool*> descriptor_pool,
388+
absl::Nonnull<google::protobuf::MessageFactory*> message_factory,
389+
absl::Nonnull<google::protobuf::Arena*> arena, absl::Nonnull<Value*> result) const {
390+
ABSL_DCHECK(descriptor_pool != nullptr);
391+
ABSL_DCHECK(message_factory != nullptr);
392+
ABSL_DCHECK(arena != nullptr);
393+
ABSL_DCHECK(result != nullptr);
394+
395+
if (dispatcher_ == nullptr) {
396+
CustomListValueInterface::Content content =
397+
content_.To<CustomListValueInterface::Content>();
398+
ABSL_DCHECK(content.interface != nullptr);
399+
return content.interface->Equal(other, descriptor_pool, message_factory,
400+
arena, result);
401+
}
402+
if (auto other_list_value = other.AsList(); other_list_value) {
403+
if (dispatcher_->equal != nullptr) {
404+
return dispatcher_->equal(dispatcher_, content_, *other_list_value,
405+
descriptor_pool, message_factory, arena,
406+
result);
407+
}
408+
return common_internal::ListValueEqual(*this, *other_list_value,
409+
descriptor_pool, message_factory,
410+
arena, result);
411+
}
412+
*result = FalseValue();
413+
return absl::OkStatus();
414+
}
415+
416+
bool CustomListValue::IsZeroValue() const {
417+
if (dispatcher_ == nullptr) {
418+
CustomListValueInterface::Content content =
419+
content_.To<CustomListValueInterface::Content>();
420+
ABSL_DCHECK(content.interface != nullptr);
421+
return content.interface->IsZeroValue();
422+
}
423+
return dispatcher_->is_zero_value(dispatcher_, content_);
424+
}
262425

263426
CustomListValue CustomListValue::Clone(
264427
absl::Nonnull<google::protobuf::Arena*> arena) const {
265428
ABSL_DCHECK(arena != nullptr);
266-
ABSL_DCHECK(*this);
267429

268-
if (ABSL_PREDICT_FALSE(!interface_)) {
269-
return CustomListValue();
430+
if (dispatcher_ == nullptr) {
431+
CustomListValueInterface::Content content =
432+
content_.To<CustomListValueInterface::Content>();
433+
ABSL_DCHECK(content.interface != nullptr);
434+
if (content.arena != arena) {
435+
return content.interface->Clone(arena);
436+
}
437+
return *this;
270438
}
271-
if (interface_.arena() != arena) {
272-
return interface_->Clone(arena);
439+
return dispatcher_->clone(dispatcher_, content_, arena);
440+
}
441+
442+
bool CustomListValue::IsEmpty() const {
443+
if (dispatcher_ == nullptr) {
444+
CustomListValueInterface::Content content =
445+
content_.To<CustomListValueInterface::Content>();
446+
ABSL_DCHECK(content.interface != nullptr);
447+
return content.interface->IsEmpty();
448+
}
449+
if (dispatcher_->is_empty != nullptr) {
450+
return dispatcher_->is_empty(dispatcher_, content_);
451+
}
452+
return dispatcher_->size(dispatcher_, content_) == 0;
453+
}
454+
455+
size_t CustomListValue::Size() const {
456+
if (dispatcher_ == nullptr) {
457+
CustomListValueInterface::Content content =
458+
content_.To<CustomListValueInterface::Content>();
459+
ABSL_DCHECK(content.interface != nullptr);
460+
return content.interface->Size();
273461
}
274-
return *this;
462+
return dispatcher_->size(dispatcher_, content_);
463+
}
464+
465+
absl::Status CustomListValue::Get(
466+
size_t index, absl::Nonnull<const google::protobuf::DescriptorPool*> descriptor_pool,
467+
absl::Nonnull<google::protobuf::MessageFactory*> message_factory,
468+
absl::Nonnull<google::protobuf::Arena*> arena, absl::Nonnull<Value*> result) const {
469+
if (dispatcher_ == nullptr) {
470+
CustomListValueInterface::Content content =
471+
content_.To<CustomListValueInterface::Content>();
472+
ABSL_DCHECK(content.interface != nullptr);
473+
return content.interface->Get(index, descriptor_pool, message_factory,
474+
arena, result);
475+
}
476+
return dispatcher_->get(dispatcher_, content_, index, descriptor_pool,
477+
message_factory, arena, result);
478+
}
479+
480+
absl::Status CustomListValue::ForEach(
481+
ForEachWithIndexCallback callback,
482+
absl::Nonnull<const google::protobuf::DescriptorPool*> descriptor_pool,
483+
absl::Nonnull<google::protobuf::MessageFactory*> message_factory,
484+
absl::Nonnull<google::protobuf::Arena*> arena) const {
485+
if (dispatcher_ == nullptr) {
486+
CustomListValueInterface::Content content =
487+
content_.To<CustomListValueInterface::Content>();
488+
ABSL_DCHECK(content.interface != nullptr);
489+
return content.interface->ForEach(callback, descriptor_pool,
490+
message_factory, arena);
491+
}
492+
if (dispatcher_->for_each != nullptr) {
493+
return dispatcher_->for_each(dispatcher_, content_, callback,
494+
descriptor_pool, message_factory, arena);
495+
}
496+
const size_t size = dispatcher_->size(dispatcher_, content_);
497+
for (size_t index = 0; index < size; ++index) {
498+
Value element;
499+
CEL_RETURN_IF_ERROR(dispatcher_->get(dispatcher_, content_, index,
500+
descriptor_pool, message_factory,
501+
arena, &element));
502+
CEL_ASSIGN_OR_RETURN(auto ok, callback(index, element));
503+
if (!ok) {
504+
break;
505+
}
506+
}
507+
return absl::OkStatus();
508+
}
509+
510+
absl::StatusOr<absl::Nonnull<ValueIteratorPtr>> CustomListValue::NewIterator()
511+
const {
512+
if (dispatcher_ == nullptr) {
513+
CustomListValueInterface::Content content =
514+
content_.To<CustomListValueInterface::Content>();
515+
ABSL_DCHECK(content.interface != nullptr);
516+
return content.interface->NewIterator();
517+
}
518+
if (dispatcher_->new_iterator != nullptr) {
519+
return dispatcher_->new_iterator(dispatcher_, content_);
520+
}
521+
return std::make_unique<CustomListValueDispatcherIterator>(
522+
dispatcher_, content_, dispatcher_->size(dispatcher_, content_));
523+
}
524+
525+
absl::Status CustomListValue::Contains(
526+
const Value& other,
527+
absl::Nonnull<const google::protobuf::DescriptorPool*> descriptor_pool,
528+
absl::Nonnull<google::protobuf::MessageFactory*> message_factory,
529+
absl::Nonnull<google::protobuf::Arena*> arena, absl::Nonnull<Value*> result) const {
530+
if (dispatcher_ == nullptr) {
531+
CustomListValueInterface::Content content =
532+
content_.To<CustomListValueInterface::Content>();
533+
ABSL_DCHECK(content.interface != nullptr);
534+
return content.interface->Contains(other, descriptor_pool, message_factory,
535+
arena, result);
536+
}
537+
if (dispatcher_->contains != nullptr) {
538+
return dispatcher_->contains(dispatcher_, content_, other, descriptor_pool,
539+
message_factory, arena, result);
540+
}
541+
Value outcome = BoolValue(false);
542+
Value equal;
543+
CEL_RETURN_IF_ERROR(ForEach(
544+
[&](size_t index, const Value& element) -> absl::StatusOr<bool> {
545+
CEL_RETURN_IF_ERROR(element.Equal(other, descriptor_pool,
546+
message_factory, arena, &equal));
547+
if (auto bool_result = As<BoolValue>(equal);
548+
bool_result.has_value() && bool_result->NativeValue()) {
549+
outcome = BoolValue(true);
550+
return false;
551+
}
552+
return true;
553+
},
554+
descriptor_pool, message_factory, arena));
555+
*result = outcome;
556+
return absl::OkStatus();
275557
}
276558

277559
} // namespace cel

0 commit comments

Comments
 (0)