blob: 429d050b1a17da85cceacaafaa3cab140cdb01c0 [file]
// Protocol Buffers - Google's data interchange format
// Copyright 2025 Google LLC. All rights reserved.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file or at
// https://developers.google.com/open-source/licenses/bsd
#include "upb/wire/test_util/make_mini_table.h"
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <string>
#include <utility>
#include "absl/log/absl_check.h"
#include "absl/log/log.h"
#include "upb/base/descriptor_constants.h"
#include "upb/base/status.hpp"
#include "upb/mem/arena.h"
#include "upb/mini_descriptor/decode.h"
#include "upb/mini_descriptor/internal/encode.hpp"
#include "upb/mini_descriptor/internal/modifiers.h"
#include "upb/mini_descriptor/link.h"
#include "upb/mini_table/enum.h"
#include "upb/mini_table/field.h"
#include "upb/mini_table/message.h"
#include "upb/wire/decode_fast/combinations.h"
#include "upb/wire/decode_fast/data.h"
#include "upb/wire/reader.h"
// Must be last.
#include "upb/port/def.inc"
namespace upb {
namespace test {
int FieldModifiers(upb_DecodeFast_Type type,
upb_DecodeFast_Cardinality cardinality) {
int modifiers = 0;
switch (type) {
case kUpb_DecodeFast_String:
modifiers |= kUpb_FieldModifier_ValidateUtf8;
break;
case kUpb_DecodeFast_ClosedEnum:
modifiers |= kUpb_FieldModifier_IsClosedEnum;
break;
default:
break;
}
switch (cardinality) {
case kUpb_DecodeFast_Repeated:
modifiers |= kUpb_FieldModifier_IsRepeated;
break;
case kUpb_DecodeFast_Packed:
modifiers |= kUpb_FieldModifier_IsRepeated | kUpb_FieldModifier_IsPacked;
break;
default:
break;
}
return modifiers;
}
static const upb_MiniTableEnum* MakeTestEnum(upb_Arena* arena) {
// Accepts all values 0-(2M-1).
uint32_t max_val = 1 << 21;
size_t data_count = max_val / 32;
upb_MiniTableEnum* e = (upb_MiniTableEnum*)upb_Arena_Malloc(
arena, sizeof(upb_MiniTableEnum) + data_count * sizeof(uint32_t));
e->UPB_PRIVATE(mask_limit) = max_val;
e->UPB_PRIVATE(value_count) = 0;
memset(e->UPB_PRIVATE(data), 0xff, data_count * sizeof(uint32_t));
return e;
}
std::pair<const upb_MiniTable*, const upb_MiniTableField*>
MiniTable::MakeSingleFieldTable(int field_number, upb_FieldType type,
upb_DecodeFast_Type fast_type,
upb_DecodeFast_Cardinality cardinality,
upb_Arena* arena, bool extensible) {
MtDataEncoder encoder;
encoder.StartMessage(extensible ? kUpb_MessageModifier_IsExtendable : 0);
encoder.PutField(type, field_number, FieldModifiers(fast_type, cardinality));
if (cardinality == kUpb_DecodeFast_Oneof) {
encoder.StartOneof();
encoder.PutOneofField(field_number);
}
const std::string& data = encoder.data();
upb::Status status;
upb_MiniTable* table =
upb_MiniTable_Build(data.data(), data.size(), arena, status.ptr());
ABSL_CHECK(status.ok()) << status.error_message();
upb_MiniTableField* field =
const_cast<upb_MiniTableField*>(upb_MiniTable_GetFieldByIndex(table, 0));
ABSL_CHECK(field != nullptr);
if (type == kUpb_FieldType_Enum) {
const upb_MiniTableEnum* sub = MakeTestEnum(arena);
bool ok = upb_MiniTable_SetSubEnum(table, field, sub);
ABSL_CHECK(ok);
}
#if UPB_FASTTABLE
if (field_number < (1 << 11) && type != kUpb_FieldType_Group) {
ABSL_CHECK_EQ(HasFastTableEntry(table, field),
UPB_DECODEFAST_ISENABLED(fast_type, cardinality,
kUpb_DecodeFast_Tag1Byte))
<< "fast type: " << fast_type << ", cardinality: " << cardinality;
}
#endif
return std::make_pair(table, upb_MiniTable_GetFieldByIndex(table, 0));
}
bool MiniTable::HasFastTableEntry(const upb_MiniTable* mt,
const upb_MiniTableField* field) {
#if UPB_FASTTABLE
int n = (int8_t)mt->UPB_PRIVATE(table_mask) + 1;
for (int i = 0; i < n; ++i) {
const _upb_FastTable_Entry* entry = &mt->UPB_PRIVATE(fasttable)[i];
uint16_t encoded_tag = upb_DecodeFastData_GetExpectedTag(entry->field_data);
uint32_t tag;
char buf[16];
memset(buf, 0, sizeof(buf));
memcpy(buf, &encoded_tag, sizeof(encoded_tag));
const char* end = upb_WireReader_ReadTag(buf, &tag, nullptr);
ABSL_CHECK(end == buf + 1 || end == buf + 2);
if (tag >> 3 == field->UPB_PRIVATE(number)) {
return true;
}
}
return false;
#else
return false;
#endif
}
} // namespace test
} // namespace upb