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.

216 lines
7.8 KiB

/*
* Copyright (c) 2009-2021, Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Google LLC nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "upb/msg.h"
#include <math.h>
#include "upb/msg_internal.h"
// Must be last.
#include "upb/port_def.inc"
3 years ago
/** upb_Message ***************************************************************/
5 years ago
static const size_t overhead = sizeof(upb_Message_InternalData);
static const upb_Message_Internal* upb_Message_Getinternal_const(
const upb_Message* msg) {
ptrdiff_t size = sizeof(upb_Message_Internal);
return (upb_Message_Internal*)((char*)msg - size);
}
upb_Message* upb_Message_New(const upb_MiniTable* mini_table,
upb_Arena* arena) {
return _upb_Message_New(mini_table, arena);
}
void _upb_Message_Clear(upb_Message* msg, const upb_MiniTable* l) {
void* mem = UPB_PTR_AT(msg, -sizeof(upb_Message_Internal), char);
memset(mem, 0, upb_msg_sizeof(l));
}
static bool realloc_internal(upb_Message* msg, size_t need, upb_Arena* arena) {
upb_Message_Internal* in = upb_Message_Getinternal(msg);
if (!in->internal) {
/* No internal data, allocate from scratch. */
size_t size = UPB_MAX(128, _upb_Log2CeilingSize(need + overhead));
upb_Message_InternalData* internal = upb_Arena_Malloc(arena, size);
if (!internal) return false;
internal->size = size;
internal->unknown_end = overhead;
internal->ext_begin = size;
in->internal = internal;
} else if (in->internal->ext_begin - in->internal->unknown_end < need) {
/* Internal data is too small, reallocate. */
size_t new_size = _upb_Log2CeilingSize(in->internal->size + need);
size_t ext_bytes = in->internal->size - in->internal->ext_begin;
size_t new_ext_begin = new_size - ext_bytes;
upb_Message_InternalData* internal =
upb_Arena_Realloc(arena, in->internal, in->internal->size, new_size);
if (!internal) return false;
if (ext_bytes) {
/* Need to move extension data to the end. */
char* ptr = (char*)internal;
memmove(ptr + new_ext_begin, ptr + internal->ext_begin, ext_bytes);
}
internal->ext_begin = new_ext_begin;
internal->size = new_size;
in->internal = internal;
}
UPB_ASSERT(in->internal->ext_begin - in->internal->unknown_end >= need);
return true;
}
bool _upb_Message_AddUnknown(upb_Message* msg, const char* data, size_t len,
upb_Arena* arena) {
if (!realloc_internal(msg, len, arena)) return false;
upb_Message_Internal* in = upb_Message_Getinternal(msg);
memcpy(UPB_PTR_AT(in->internal, in->internal->unknown_end, char), data, len);
in->internal->unknown_end += len;
return true;
5 years ago
}
void _upb_Message_DiscardUnknown_shallow(upb_Message* msg) {
upb_Message_Internal* in = upb_Message_Getinternal(msg);
if (in->internal) {
in->internal->unknown_end = overhead;
}
Fixes for PHP. (#286) - A new PHP-specific upb amalgamation. It contains everything related to upb_msg, but leaves out all of the old handlers-related interfaces and encoders/decoders. # Schema/Defs Changes - Changed `upb_fielddef_msgsubdef()` and `upb_fielddef_enumsubdef()` to return `NULL` instead of assert-failing if the field is not a message or enum. - Added `upb_msgdef_iswrapper()`, to test whether this is a wrapper well-known type. # Decoder - Decoder bugfix: when we parse a submessage inside a oneof, we need to clear out any previous data, so we don't misinterpret it as a pointer to an existing submessage. # JSON Decoder - Allowed well-known types at the top level to have their special processing. - Fixed a bug that could occur when parsing nested empty lists/objects, eg `[[]]`. - Made the "ignore unknown" option also be permissive about unknown enumerators by setting them to 0. # JSON Encoder - Allowed well-known types at the top level to have their special processing. - Removed all spaces after `:` and `,` characters, to match the old encoder and pass goldenfile tests. # Message / Reflection - Changed `upb_msg_hasoneof()` -> `upb_msg_whichoneof()`. The new function returns the `upb_fielddef*` of whichever oneof is set. - Implemented `upb_msg_clearfield()` and added/implemented `upb_msg_clear()`. - Added `upb_msg_discardunknown()`. Part of me thinks this should go in a util library instead of core reflection since it is a recursive algorithm. # Compiler - Always emit descriptors as an array instead of as a string, to avoid exceeding maximum string lengths. If this becomes a speed issue later we can go back to two separate paths.
5 years ago
}
const char* upb_Message_GetUnknown(const upb_Message* msg, size_t* len) {
const upb_Message_Internal* in = upb_Message_Getinternal_const(msg);
if (in->internal) {
*len = in->internal->unknown_end - overhead;
return (char*)(in->internal + 1);
} else {
*len = 0;
return NULL;
}
5 years ago
}
void upb_Message_DeleteUnknown(upb_Message* msg, const char* data, size_t len) {
upb_Message_Internal* in = upb_Message_Getinternal(msg);
const char* internal_unknown_end =
UPB_PTR_AT(in->internal, in->internal->unknown_end, char);
#ifndef NDEBUG
size_t full_unknown_size;
const char* full_unknown = upb_Message_GetUnknown(msg, &full_unknown_size);
UPB_ASSERT((uintptr_t)data >= (uintptr_t)full_unknown);
UPB_ASSERT((uintptr_t)data < (uintptr_t)(full_unknown + full_unknown_size));
UPB_ASSERT((uintptr_t)(data + len) > (uintptr_t)data);
UPB_ASSERT((uintptr_t)(data + len) <= (uintptr_t)internal_unknown_end);
#endif
if ((data + len) != internal_unknown_end) {
memmove((char*)data, data + len, internal_unknown_end - data - len);
}
in->internal->unknown_end -= len;
}
const upb_Message_Extension* _upb_Message_Getexts(const upb_Message* msg,
size_t* count) {
const upb_Message_Internal* in = upb_Message_Getinternal_const(msg);
if (in->internal) {
*count = (in->internal->size - in->internal->ext_begin) /
sizeof(upb_Message_Extension);
return UPB_PTR_AT(in->internal, in->internal->ext_begin, void);
} else {
*count = 0;
return NULL;
}
}
const upb_Message_Extension* _upb_Message_Getext(
const upb_Message* msg, const upb_MiniTable_Extension* e) {
size_t n;
const upb_Message_Extension* ext = _upb_Message_Getexts(msg, &n);
/* For now we use linear search exclusively to find extensions. If this
* becomes an issue due to messages with lots of extensions, we can introduce
* a table of some sort. */
for (size_t i = 0; i < n; i++) {
if (ext[i].ext == e) {
return &ext[i];
}
}
return NULL;
}
void _upb_Message_Clearext(upb_Message* msg,
const upb_MiniTable_Extension* ext_l) {
upb_Message_Internal* in = upb_Message_Getinternal(msg);
if (!in->internal) return;
const upb_Message_Extension* base =
UPB_PTR_AT(in->internal, in->internal->ext_begin, void);
upb_Message_Extension* ext =
(upb_Message_Extension*)_upb_Message_Getext(msg, ext_l);
if (ext) {
*ext = *base;
in->internal->ext_begin += sizeof(upb_Message_Extension);
}
}
upb_Message_Extension* _upb_Message_GetOrCreateExtension(
upb_Message* msg, const upb_MiniTable_Extension* e, upb_Arena* arena) {
upb_Message_Extension* ext =
(upb_Message_Extension*)_upb_Message_Getext(msg, e);
if (ext) return ext;
if (!realloc_internal(msg, sizeof(upb_Message_Extension), arena)) return NULL;
upb_Message_Internal* in = upb_Message_Getinternal(msg);
in->internal->ext_begin -= sizeof(upb_Message_Extension);
ext = UPB_PTR_AT(in->internal, in->internal->ext_begin, void);
memset(ext, 0, sizeof(upb_Message_Extension));
ext->ext = e;
return ext;
}
size_t upb_Message_ExtensionCount(const upb_Message* msg) {
size_t count;
_upb_Message_Getexts(msg, &count);
return count;
}
/** upb_Map *******************************************************************/
5 years ago
upb_Map* _upb_Map_New(upb_Arena* a, size_t key_size, size_t value_size) {
upb_Map* map = upb_Arena_Malloc(a, sizeof(upb_Map));
6 years ago
if (!map) {
return NULL;
}
upb_strtable_init(&map->table, 4, a);
map->key_size = key_size;
map->val_size = value_size;
6 years ago
return map;
}
Added map sorting to binary and text encoders. For the binary encoder, sorting is off by default. For the text encoder, sorting is on by default. Both defaults can be explicitly overridden. This grows code size a bit. I think we could potentially shave this (and other map-related code size) by having the generated code inject a function pointer to the map-related parsing/serialization code if maps are present. FILE SIZE VM SIZE -------------- -------------- +86% +1.07Ki +71% +768 upb/msg.c [NEW] +391 [NEW] +344 _upb_mapsorter_pushmap [NEW] +158 [NEW] +112 _upb_mapsorter_cmpstr [NEW] +111 [NEW] +64 _upb_mapsorter_cmpbool [NEW] +110 [NEW] +64 _upb_mapsorter_cmpi32 [NEW] +110 [NEW] +64 _upb_mapsorter_cmpi64 [NEW] +110 [NEW] +64 _upb_mapsorter_cmpu32 [NEW] +110 [NEW] +64 _upb_mapsorter_cmpu64 -3.6% -8 -4.3% -8 _upb_map_new +9.5% +464 +9.2% +424 upb/text_encode.c [NEW] +656 [NEW] +616 txtenc_mapentry +15% +32 +20% +32 upb_text_encode -20.1% -224 -20.7% -224 txtenc_msg +5.7% +342 +5.3% +296 upb/encode.c [NEW] +344 [NEW] +304 encode_mapentry [NEW] +246 [NEW] +208 upb_encode_ex [NEW] +41 [NEW] +16 upb_encode_ex.ch +0.7% +8 +0.7% +8 encode_scalar -1.0% -32 -1.0% -32 encode_message [DEL] -38 [DEL] -16 upb_encode.ch [DEL] -227 [DEL] -192 upb_encode +2.0% +152 +2.2% +152 upb/decode.c +44% +128 +44% +128 [section .rodata] +3.4% +24 +3.4% +24 _GLOBAL_OFFSET_TABLE_ +0.6% +107 +0.3% +48 upb/def.c [NEW] +100 [NEW] +48 upb_fielddef_descriptortype +7.1% +7 [ = ] 0 upb_fielddef_defaultint32 +2.9% +24 +2.9% +24 [section .dynsym] +1.2% +24 [ = ] 0 [section .symtab] +3.2% +16 +3.2% +16 [section .plt] [NEW] +16 [NEW] +16 memcmp@plt +0.5% +16 +0.6% +16 tests/conformance_upb.c +1.5% +16 +1.6% +16 DoTestIo +0.1% +16 +0.1% +16 upb/json_decode.c +0.4% +16 +0.4% +16 jsondec_wellknown +3.0% +8 +3.0% +8 [section .got.plt] +3.0% +8 +3.0% +8 _GLOBAL_OFFSET_TABLE_ +1.6% +7 +1.6% +7 [section .dynstr] +1.8% +4 +1.8% +4 [section .hash] +0.5% +3 +0.5% +3 [LOAD #2 [RX]] +2.8% +2 +2.8% +2 [section .gnu.version] -60.0% -1.74Ki [ = ] 0 [Unmapped] +0.3% +496 +1.4% +1.74Ki TOTAL
4 years ago
const float kUpb_FltInfinity = INFINITY;
const double kUpb_Infinity = INFINITY;