Protocol Buffers - Google's data interchange format (grpc依赖)
https://developers.google.com/protocol-buffers/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
4.7 KiB
139 lines
4.7 KiB
// Protocol Buffers - Google's data interchange format |
|
// Copyright 2023 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/mini_descriptor/build_enum.h" |
|
|
|
#include <stddef.h> |
|
#include <stdint.h> |
|
|
|
#include "upb/base/status.h" |
|
#include "upb/mem/arena.h" |
|
#include "upb/mini_descriptor/internal/base92.h" |
|
#include "upb/mini_descriptor/internal/decoder.h" |
|
#include "upb/mini_descriptor/internal/wire_constants.h" |
|
#include "upb/mini_table/enum.h" |
|
#include "upb/mini_table/internal/enum.h" |
|
|
|
// Must be last. |
|
#include "upb/port/def.inc" |
|
|
|
typedef struct { |
|
upb_MdDecoder base; |
|
upb_Arena* arena; |
|
upb_MiniTableEnum* enum_table; |
|
uint32_t enum_value_count; |
|
uint32_t enum_data_count; |
|
uint32_t enum_data_capacity; |
|
} upb_MdEnumDecoder; |
|
|
|
static size_t upb_MiniTableEnum_Size(size_t count) { |
|
return sizeof(upb_MiniTableEnum) + count * sizeof(uint32_t); |
|
} |
|
|
|
static upb_MiniTableEnum* _upb_MiniTable_AddEnumDataMember(upb_MdEnumDecoder* d, |
|
uint32_t val) { |
|
if (d->enum_data_count == d->enum_data_capacity) { |
|
size_t old_sz = upb_MiniTableEnum_Size(d->enum_data_capacity); |
|
d->enum_data_capacity = UPB_MAX(2, d->enum_data_capacity * 2); |
|
size_t new_sz = upb_MiniTableEnum_Size(d->enum_data_capacity); |
|
d->enum_table = upb_Arena_Realloc(d->arena, d->enum_table, old_sz, new_sz); |
|
upb_MdDecoder_CheckOutOfMemory(&d->base, d->enum_table); |
|
} |
|
d->enum_table->UPB_PRIVATE(data)[d->enum_data_count++] = val; |
|
return d->enum_table; |
|
} |
|
|
|
static void upb_MiniTableEnum_BuildValue(upb_MdEnumDecoder* d, uint32_t val) { |
|
upb_MiniTableEnum* table = d->enum_table; |
|
d->enum_value_count++; |
|
if (table->UPB_PRIVATE(value_count) || |
|
(val > 512 && d->enum_value_count < val / 32)) { |
|
if (table->UPB_PRIVATE(value_count) == 0) { |
|
UPB_ASSERT(d->enum_data_count == table->UPB_PRIVATE(mask_limit) / 32); |
|
} |
|
table = _upb_MiniTable_AddEnumDataMember(d, val); |
|
table->UPB_PRIVATE(value_count)++; |
|
} else { |
|
uint32_t new_mask_limit = ((val / 32) + 1) * 32; |
|
while (table->UPB_PRIVATE(mask_limit) < new_mask_limit) { |
|
table = _upb_MiniTable_AddEnumDataMember(d, 0); |
|
table->UPB_PRIVATE(mask_limit) += 32; |
|
} |
|
table->UPB_PRIVATE(data)[val / 32] |= 1ULL << (val % 32); |
|
} |
|
} |
|
|
|
static upb_MiniTableEnum* upb_MtDecoder_DoBuildMiniTableEnum( |
|
upb_MdEnumDecoder* d, const char* data, size_t len) { |
|
// If the string is non-empty then it must begin with a version tag. |
|
if (len) { |
|
if (*data != kUpb_EncodedVersion_EnumV1) { |
|
upb_MdDecoder_ErrorJmp(&d->base, "Invalid enum version: %c", *data); |
|
} |
|
data++; |
|
len--; |
|
} |
|
|
|
upb_MdDecoder_CheckOutOfMemory(&d->base, d->enum_table); |
|
|
|
// Guarantee at least 64 bits of mask without checking mask size. |
|
d->enum_table->UPB_PRIVATE(mask_limit) = 64; |
|
d->enum_table = _upb_MiniTable_AddEnumDataMember(d, 0); |
|
d->enum_table = _upb_MiniTable_AddEnumDataMember(d, 0); |
|
|
|
d->enum_table->UPB_PRIVATE(value_count) = 0; |
|
|
|
const char* ptr = data; |
|
uint32_t base = 0; |
|
|
|
while (ptr < d->base.end) { |
|
char ch = *ptr++; |
|
if (ch <= kUpb_EncodedValue_MaxEnumMask) { |
|
uint32_t mask = _upb_FromBase92(ch); |
|
for (int i = 0; i < 5; i++, base++, mask >>= 1) { |
|
if (mask & 1) upb_MiniTableEnum_BuildValue(d, base); |
|
} |
|
} else if (kUpb_EncodedValue_MinSkip <= ch && |
|
ch <= kUpb_EncodedValue_MaxSkip) { |
|
uint32_t skip; |
|
ptr = upb_MdDecoder_DecodeBase92Varint(&d->base, ptr, ch, |
|
kUpb_EncodedValue_MinSkip, |
|
kUpb_EncodedValue_MaxSkip, &skip); |
|
base += skip; |
|
} else { |
|
upb_MdDecoder_ErrorJmp(&d->base, "Unexpected character: %c", ch); |
|
} |
|
} |
|
|
|
return d->enum_table; |
|
} |
|
|
|
static upb_MiniTableEnum* upb_MtDecoder_BuildMiniTableEnum( |
|
upb_MdEnumDecoder* const decoder, const char* const data, |
|
size_t const len) { |
|
if (UPB_SETJMP(decoder->base.err) != 0) return NULL; |
|
return upb_MtDecoder_DoBuildMiniTableEnum(decoder, data, len); |
|
} |
|
|
|
upb_MiniTableEnum* upb_MiniTableEnum_Build(const char* data, size_t len, |
|
upb_Arena* arena, |
|
upb_Status* status) { |
|
upb_MdEnumDecoder decoder = { |
|
.base = |
|
{ |
|
.end = UPB_PTRADD(data, len), |
|
.status = status, |
|
}, |
|
.arena = arena, |
|
.enum_table = upb_Arena_Malloc(arena, upb_MiniTableEnum_Size(2)), |
|
.enum_value_count = 0, |
|
.enum_data_count = 0, |
|
.enum_data_capacity = 1, |
|
}; |
|
|
|
return upb_MtDecoder_BuildMiniTableEnum(&decoder, data, len); |
|
}
|
|
|