Also got rid of the premature "v1" business that was attempting to create a binary compatibility story. Also added an in-progress CMakeLists.txt file.pull/13171/head
parent
0a95f73d0d
commit
e94ac4f757
14 changed files with 811 additions and 578 deletions
@ -0,0 +1,228 @@ |
|||||||
|
|
||||||
|
cmake_minimum_required (VERSION 3.0) |
||||||
|
cmake_policy(SET CMP0048 NEW) |
||||||
|
project (upb) |
||||||
|
|
||||||
|
# Options we define for users. |
||||||
|
option(UPB_ENABLE_ASAN "Enable address sanitizer." OFF) |
||||||
|
option(UPB_ENABLE_UBSAN "Enable undefined behavior sanitizer." OFF) |
||||||
|
|
||||||
|
# Set default build type. |
||||||
|
if(NOT CMAKE_BUILD_TYPE) |
||||||
|
message(STATUS "Setting build type to 'RelWithDebInfo' as none was specified.") |
||||||
|
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING |
||||||
|
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." |
||||||
|
FORCE) |
||||||
|
endif() |
||||||
|
|
||||||
|
# Check out Git submodules. |
||||||
|
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.gitmodules") |
||||||
|
execute_process (COMMAND git submodule update --init --recursive |
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) |
||||||
|
endif() |
||||||
|
|
||||||
|
set(protobuf_BUILD_TESTS OFF CACHE BOOL "enable tests for proto2" FORCE) |
||||||
|
set(protobuf_BUILD_SHARED_LIBS OFF CACHE BOOL "enable shared libs for proto2" FORCE) |
||||||
|
add_subdirectory(third_party/protobuf/cmake) |
||||||
|
|
||||||
|
# When using Ninja, compiler output won't be colorized without this. |
||||||
|
include(CheckCXXCompilerFlag) |
||||||
|
CHECK_CXX_COMPILER_FLAG(-fdiagnostics-color=always SUPPORTS_COLOR_ALWAYS) |
||||||
|
if(SUPPORTS_COLOR_ALWAYS) |
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always") |
||||||
|
endif() |
||||||
|
|
||||||
|
# Implement ASAN/UBSAN options |
||||||
|
if(UPB_ENABLE_ASAN) |
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") |
||||||
|
set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fsanitize=address") |
||||||
|
endif() |
||||||
|
|
||||||
|
if(UPB_ENABLE_UBSAN) |
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined") |
||||||
|
set(CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fsanitize=undefined") |
||||||
|
endif() |
||||||
|
|
||||||
|
include_directories(.) |
||||||
|
include_directories(${CMAKE_CURRENT_BINARY_DIR}) |
||||||
|
|
||||||
|
if(APPLE) |
||||||
|
elseif(UNIX) |
||||||
|
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--build-id") |
||||||
|
endif() |
||||||
|
|
||||||
|
FIND_PACKAGE(Lua) |
||||||
|
|
||||||
|
if(LUA_FOUND) |
||||||
|
include_directories(${LUA_INCLUDE_DIR}) |
||||||
|
|
||||||
|
add_library(upb_c SHARED |
||||||
|
upb/bindings/lua/upb.c |
||||||
|
upb/bindings/lua/def.c |
||||||
|
upb/bindings/lua/msg.c |
||||||
|
) |
||||||
|
target_link_libraries(upb_c LINK_PRIVATE |
||||||
|
upbpb_pic |
||||||
|
upbdef_pic |
||||||
|
upbhandlers_pic upb_pic ) |
||||||
|
|
||||||
|
add_library(table_c SHARED |
||||||
|
upb/bindings/lua/upb/table.c |
||||||
|
) |
||||||
|
target_link_libraries(table_c LINK_PRIVATE upb_c upb_pic) |
||||||
|
|
||||||
|
add_library(pb_c SHARED |
||||||
|
upb/bindings/lua/upb/pb.c |
||||||
|
) |
||||||
|
target_link_libraries(pb_c LINK_PRIVATE upb_c upbpb_pic) |
||||||
|
|
||||||
|
set_target_properties(upb_c |
||||||
|
PROPERTIES |
||||||
|
LIBRARY_OUTPUT_DIRECTORY "lua" |
||||||
|
PREFIX "") |
||||||
|
set_target_properties(table_c pb_c |
||||||
|
PROPERTIES |
||||||
|
LIBRARY_OUTPUT_DIRECTORY "lua/upb" |
||||||
|
PREFIX "") |
||||||
|
|
||||||
|
add_custom_command( |
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/tools/upbc |
||||||
|
DEPENDS ${CMAKE_SOURCE_DIR}/tools/upbc |
||||||
|
${CMAKE_SOURCE_DIR}/tools/upbc.lua |
||||||
|
${CMAKE_SOURCE_DIR}/tools/dump_cinit.lua |
||||||
|
${CMAKE_SOURCE_DIR}/tools/make_c_api.lua |
||||||
|
${CMAKE_SOURCE_DIR}/upb/bindings/lua/upb.lua |
||||||
|
${CMAKE_SOURCE_DIR}/upb/bindings/lua/upb/table.lua |
||||||
|
${CMAKE_SOURCE_DIR}/upb/bindings/lua/upb/pb.lua |
||||||
|
upb_c |
||||||
|
table_c |
||||||
|
pb_c |
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy |
||||||
|
${CMAKE_SOURCE_DIR}/tools/upbc |
||||||
|
${CMAKE_SOURCE_DIR}/tools/upbc.lua |
||||||
|
${CMAKE_SOURCE_DIR}/tools/dump_cinit.lua |
||||||
|
${CMAKE_SOURCE_DIR}/tools/make_c_api.lua |
||||||
|
${CMAKE_SOURCE_DIR}/upb/bindings/lua/upb.lua |
||||||
|
${CMAKE_SOURCE_DIR}/upb/bindings/lua/upb/table.lua |
||||||
|
${CMAKE_SOURCE_DIR}/upb/bindings/lua/upb/pb.lua |
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/tools) |
||||||
|
add_custom_command( |
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lua/upb.lua |
||||||
|
DEPENDS ${CMAKE_SOURCE_DIR}/upb/bindings/lua/upb.lua |
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy |
||||||
|
${CMAKE_SOURCE_DIR}/upb/bindings/lua/upb.lua |
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/lua) |
||||||
|
add_custom_command( |
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lua/upb/pb.lua |
||||||
|
DEPENDS ${CMAKE_SOURCE_DIR}/upb/bindings/lua/upb/table.lua |
||||||
|
${CMAKE_SOURCE_DIR}/upb/bindings/lua/upb/pb.lua |
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy |
||||||
|
${CMAKE_SOURCE_DIR}/upb/bindings/lua/upb/table.lua |
||||||
|
${CMAKE_SOURCE_DIR}/upb/bindings/lua/upb/pb.lua |
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/lua/upb) |
||||||
|
add_custom_target( |
||||||
|
upbc ALL |
||||||
|
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/tools/upbc |
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/lua/upb.lua |
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/lua/upb/pb.lua |
||||||
|
) |
||||||
|
|
||||||
|
add_custom_command( |
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/conformance.upb.h |
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/conformance.upb.c |
||||||
|
DEPENDS upbc ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/conformance/conformance.proto |
||||||
|
COMMAND protoc --include_imports |
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/conformance/conformance.proto |
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/src/google/protobuf/test_messages_proto3.proto |
||||||
|
-I${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/conformance |
||||||
|
-I${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/src |
||||||
|
-o${CMAKE_CURRENT_BINARY_DIR}/conformance.pb && |
||||||
|
tools/upbc ${CMAKE_CURRENT_BINARY_DIR}/conformance.pb |
||||||
|
) |
||||||
|
|
||||||
|
add_custom_command( |
||||||
|
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/google/protobuf/descriptor.upb.h |
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/google/protobuf/descriptor.upb.c |
||||||
|
DEPENDS upbc ${CMAKE_CURRENT_SOURCE_DIR}/google/protobuf/descriptor.proto |
||||||
|
COMMAND protoc |
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/google/protobuf/descriptor.proto |
||||||
|
-I${CMAKE_CURRENT_SOURCE_DIR} |
||||||
|
-o${CMAKE_CURRENT_BINARY_DIR}/descriptor.pb && |
||||||
|
tools/upbc ${CMAKE_CURRENT_BINARY_DIR}/descriptor.pb |
||||||
|
) |
||||||
|
|
||||||
|
add_custom_target( |
||||||
|
genfiles |
||||||
|
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/conformance.upb.h |
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/google/protobuf/descriptor.upb.h |
||||||
|
) |
||||||
|
endif() |
||||||
|
|
||||||
|
set(UPB_SRCS |
||||||
|
upb/decode.c |
||||||
|
upb/encode.c |
||||||
|
upb/msg.c |
||||||
|
upb/table.c |
||||||
|
upb/upb.c |
||||||
|
) |
||||||
|
|
||||||
|
set (UPBDEF_SRCS |
||||||
|
upb/descriptor/descriptor.upbdefs.c |
||||||
|
upb/descriptor/reader.c |
||||||
|
upb/def.c |
||||||
|
upb/msgfactory.c |
||||||
|
upb/refcounted.c |
||||||
|
) |
||||||
|
|
||||||
|
set(UPBHANDLERS_SRCS |
||||||
|
upb/sink.c |
||||||
|
upb/handlers.c |
||||||
|
) |
||||||
|
|
||||||
|
set(UPBPB_SRCS |
||||||
|
upb/pb/compile_decoder.c |
||||||
|
upb/pb/decoder.c |
||||||
|
upb/pb/encoder.c |
||||||
|
upb/pb/glue.c |
||||||
|
upb/pb/textprinter.c |
||||||
|
upb/pb/varint.c |
||||||
|
) |
||||||
|
|
||||||
|
set(UPBJSON_SRCS |
||||||
|
upb/json/parser.c |
||||||
|
upb/json/printer.c |
||||||
|
) |
||||||
|
|
||||||
|
add_library(upb ${UPB_SRCS}) |
||||||
|
add_library(upbdef ${UPBDEF_SRCS}) |
||||||
|
add_library(upbhandlers ${UPBHANDLERS_SRCS}) |
||||||
|
add_library(upbpb ${UPBPB_SRCS}) |
||||||
|
add_library(upbjson ${UPBJSON_SRCS}) |
||||||
|
|
||||||
|
add_library(upb_pic ${UPB_SRCS}) |
||||||
|
add_library(upbdef_pic ${UPBDEF_SRCS}) |
||||||
|
add_library(upbhandlers_pic ${UPBHANDLERS_SRCS}) |
||||||
|
add_library(upbpb_pic ${UPBPB_SRCS}) |
||||||
|
add_library(upbjson_pic ${UPBJSON_SRCS}) |
||||||
|
|
||||||
|
set_property(TARGET upb_pic PROPERTY POSITION_INDEPENDENT_CODE ON) |
||||||
|
set_property(TARGET upbdef_pic PROPERTY POSITION_INDEPENDENT_CODE ON) |
||||||
|
set_property(TARGET upbhandlers_pic PROPERTY POSITION_INDEPENDENT_CODE ON) |
||||||
|
set_property(TARGET upbpb_pic PROPERTY POSITION_INDEPENDENT_CODE ON) |
||||||
|
set_property(TARGET upbjson_pic PROPERTY POSITION_INDEPENDENT_CODE ON) |
||||||
|
|
||||||
|
add_executable(conformance_upb |
||||||
|
tests/conformance_upb.c |
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/google/protobuf/test_messages_proto3.upb.c |
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/google/protobuf/any.upb.c |
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/google/protobuf/duration.upb.c |
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/google/protobuf/field_mask.upb.c |
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/google/protobuf/struct.upb.c |
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/google/protobuf/test_messages_proto3.upb.c |
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/google/protobuf/timestamp.upb.c |
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/google/protobuf/wrappers.upb.c |
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/conformance.upb.c |
||||||
|
) |
||||||
|
target_link_libraries(conformance_upb LINK_PRIVATE |
||||||
|
upb |
||||||
|
) |
@ -0,0 +1,325 @@ |
|||||||
|
|
||||||
|
#include "upb/msgfactory.h" |
||||||
|
|
||||||
|
static bool is_power_of_two(size_t val) { |
||||||
|
return (val & (val - 1)) == 0; |
||||||
|
} |
||||||
|
|
||||||
|
/* Align up to the given power of 2. */ |
||||||
|
static size_t align_up(size_t val, size_t align) { |
||||||
|
UPB_ASSERT(is_power_of_two(align)); |
||||||
|
return (val + align - 1) & ~(align - 1); |
||||||
|
} |
||||||
|
|
||||||
|
static size_t div_round_up(size_t n, size_t d) { |
||||||
|
return (n + d - 1) / d; |
||||||
|
} |
||||||
|
|
||||||
|
static size_t upb_msgval_sizeof2(upb_fieldtype_t type) { |
||||||
|
switch (type) { |
||||||
|
case UPB_TYPE_DOUBLE: |
||||||
|
case UPB_TYPE_INT64: |
||||||
|
case UPB_TYPE_UINT64: |
||||||
|
return 8; |
||||||
|
case UPB_TYPE_ENUM: |
||||||
|
case UPB_TYPE_INT32: |
||||||
|
case UPB_TYPE_UINT32: |
||||||
|
case UPB_TYPE_FLOAT: |
||||||
|
return 4; |
||||||
|
case UPB_TYPE_BOOL: |
||||||
|
return 1; |
||||||
|
case UPB_TYPE_MESSAGE: |
||||||
|
return sizeof(void*); |
||||||
|
case UPB_TYPE_BYTES: |
||||||
|
case UPB_TYPE_STRING: |
||||||
|
return sizeof(upb_stringview); |
||||||
|
} |
||||||
|
UPB_UNREACHABLE(); |
||||||
|
} |
||||||
|
|
||||||
|
static uint8_t upb_msg_fielddefsize(const upb_fielddef *f) { |
||||||
|
if (upb_fielddef_isseq(f)) { |
||||||
|
return sizeof(void*); |
||||||
|
} else { |
||||||
|
return upb_msgval_sizeof2(upb_fielddef_type(f)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static upb_msgval upb_msgval_fromdefault(const upb_fielddef *f) { |
||||||
|
switch (upb_fielddef_type(f)) { |
||||||
|
case UPB_TYPE_FLOAT: |
||||||
|
return upb_msgval_float(upb_fielddef_defaultfloat(f)); |
||||||
|
case UPB_TYPE_DOUBLE: |
||||||
|
return upb_msgval_double(upb_fielddef_defaultdouble(f)); |
||||||
|
case UPB_TYPE_BOOL: |
||||||
|
return upb_msgval_bool(upb_fielddef_defaultbool(f)); |
||||||
|
case UPB_TYPE_STRING: |
||||||
|
case UPB_TYPE_BYTES: { |
||||||
|
size_t len; |
||||||
|
const char *ptr = upb_fielddef_defaultstr(f, &len); |
||||||
|
return upb_msgval_makestr(ptr, len); |
||||||
|
} |
||||||
|
case UPB_TYPE_MESSAGE: |
||||||
|
return upb_msgval_msg(NULL); |
||||||
|
case UPB_TYPE_ENUM: |
||||||
|
case UPB_TYPE_INT32: |
||||||
|
return upb_msgval_int32(upb_fielddef_defaultint32(f)); |
||||||
|
case UPB_TYPE_UINT32: |
||||||
|
return upb_msgval_uint32(upb_fielddef_defaultuint32(f)); |
||||||
|
case UPB_TYPE_INT64: |
||||||
|
return upb_msgval_int64(upb_fielddef_defaultint64(f)); |
||||||
|
case UPB_TYPE_UINT64: |
||||||
|
return upb_msgval_uint64(upb_fielddef_defaultuint64(f)); |
||||||
|
default: |
||||||
|
UPB_ASSERT(false); |
||||||
|
return upb_msgval_msg(NULL); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** upb_msglayout *************************************************************/ |
||||||
|
|
||||||
|
static void upb_msglayout_free(upb_msglayout *l) { |
||||||
|
upb_gfree(l->default_msg); |
||||||
|
upb_gfree(l); |
||||||
|
} |
||||||
|
|
||||||
|
static size_t upb_msglayout_place(upb_msglayout *l, size_t size) { |
||||||
|
size_t ret; |
||||||
|
|
||||||
|
l->size = align_up(l->size, size); |
||||||
|
ret = l->size; |
||||||
|
l->size += size; |
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
static bool upb_msglayout_initdefault(upb_msglayout *l, const upb_msgdef *m) { |
||||||
|
upb_msg_field_iter it; |
||||||
|
|
||||||
|
if (upb_msgdef_syntax(m) == UPB_SYNTAX_PROTO2 && l->size) { |
||||||
|
/* Allocate default message and set default values in it. */ |
||||||
|
l->default_msg = upb_gmalloc(l->size); |
||||||
|
if (!l->default_msg) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
memset(l->default_msg, 0, l->size); |
||||||
|
|
||||||
|
for (upb_msg_field_begin(&it, m); !upb_msg_field_done(&it); |
||||||
|
upb_msg_field_next(&it)) { |
||||||
|
const upb_fielddef *f = upb_msg_iter_field(&it); |
||||||
|
|
||||||
|
if (upb_fielddef_containingoneof(f)) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
/* TODO(haberman): handle strings. */ |
||||||
|
if (!upb_fielddef_isstring(f) && !upb_fielddef_issubmsg(f) && |
||||||
|
!upb_fielddef_isseq(f)) { |
||||||
|
upb_msg_set(l->default_msg, upb_fielddef_index(f), |
||||||
|
upb_msgval_fromdefault(f), l); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
static bool upb_msglayout_init(const upb_msgdef *m, |
||||||
|
upb_msglayout *l, |
||||||
|
upb_msgfactory *factory) { |
||||||
|
upb_msg_field_iter it; |
||||||
|
upb_msg_oneof_iter oit; |
||||||
|
size_t hasbit; |
||||||
|
size_t submsg_count = 0; |
||||||
|
const upb_msglayout **submsgs; |
||||||
|
upb_msglayout_field *fields; |
||||||
|
upb_msglayout_oneof *oneofs; |
||||||
|
|
||||||
|
for (upb_msg_field_begin(&it, m); |
||||||
|
!upb_msg_field_done(&it); |
||||||
|
upb_msg_field_next(&it)) { |
||||||
|
const upb_fielddef* f = upb_msg_iter_field(&it); |
||||||
|
if (upb_fielddef_issubmsg(f)) { |
||||||
|
submsg_count++; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
memset(l, 0, sizeof(*l)); |
||||||
|
|
||||||
|
fields = upb_gmalloc(upb_msgdef_numfields(m) * sizeof(*fields)); |
||||||
|
submsgs = upb_gmalloc(submsg_count * sizeof(*submsgs)); |
||||||
|
oneofs = upb_gmalloc(upb_msgdef_numoneofs(m) * sizeof(*oneofs)); |
||||||
|
|
||||||
|
if ((!fields && upb_msgdef_numfields(m)) || |
||||||
|
(!submsgs && submsg_count) || |
||||||
|
(!oneofs && upb_msgdef_numoneofs(m))) { |
||||||
|
/* OOM. */ |
||||||
|
upb_gfree(fields); |
||||||
|
upb_gfree(submsgs); |
||||||
|
upb_gfree(oneofs); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
l->field_count = upb_msgdef_numfields(m); |
||||||
|
l->oneof_count = upb_msgdef_numoneofs(m); |
||||||
|
l->fields = fields; |
||||||
|
l->submsgs = submsgs; |
||||||
|
l->oneofs = oneofs; |
||||||
|
l->is_proto2 = (upb_msgdef_syntax(m) == UPB_SYNTAX_PROTO2); |
||||||
|
|
||||||
|
/* Allocate data offsets in three stages:
|
||||||
|
* |
||||||
|
* 1. hasbits. |
||||||
|
* 2. regular fields. |
||||||
|
* 3. oneof fields. |
||||||
|
* |
||||||
|
* OPT: There is a lot of room for optimization here to minimize the size. |
||||||
|
*/ |
||||||
|
|
||||||
|
/* Allocate hasbits and set basic field attributes. */ |
||||||
|
submsg_count = 0; |
||||||
|
for (upb_msg_field_begin(&it, m), hasbit = 0; |
||||||
|
!upb_msg_field_done(&it); |
||||||
|
upb_msg_field_next(&it)) { |
||||||
|
const upb_fielddef* f = upb_msg_iter_field(&it); |
||||||
|
upb_msglayout_field *field = &fields[upb_fielddef_index(f)]; |
||||||
|
|
||||||
|
field->number = upb_fielddef_number(f); |
||||||
|
field->descriptortype = upb_fielddef_descriptortype(f); |
||||||
|
field->label = upb_fielddef_label(f); |
||||||
|
|
||||||
|
if (upb_fielddef_containingoneof(f)) { |
||||||
|
field->oneof_index = upb_oneofdef_index(upb_fielddef_containingoneof(f)); |
||||||
|
} else { |
||||||
|
field->oneof_index = UPB_NOT_IN_ONEOF; |
||||||
|
} |
||||||
|
|
||||||
|
if (upb_fielddef_issubmsg(f)) { |
||||||
|
const upb_msglayout *sub_layout = |
||||||
|
upb_msgfactory_getlayout(factory, upb_fielddef_msgsubdef(f)); |
||||||
|
field->submsg_index = submsg_count++; |
||||||
|
submsgs[field->submsg_index] = sub_layout; |
||||||
|
} else { |
||||||
|
field->submsg_index = UPB_NO_SUBMSG; |
||||||
|
} |
||||||
|
|
||||||
|
if (upb_fielddef_haspresence(f) && !upb_fielddef_containingoneof(f)) { |
||||||
|
field->hasbit = hasbit++; |
||||||
|
} else { |
||||||
|
field->hasbit = UPB_NO_HASBIT; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* Account for space used by hasbits. */ |
||||||
|
l->size = div_round_up(hasbit, 8); |
||||||
|
|
||||||
|
/* Allocate non-oneof fields. */ |
||||||
|
for (upb_msg_field_begin(&it, m); !upb_msg_field_done(&it); |
||||||
|
upb_msg_field_next(&it)) { |
||||||
|
const upb_fielddef* f = upb_msg_iter_field(&it); |
||||||
|
size_t field_size = upb_msg_fielddefsize(f); |
||||||
|
size_t index = upb_fielddef_index(f); |
||||||
|
|
||||||
|
if (upb_fielddef_containingoneof(f)) { |
||||||
|
/* Oneofs are handled separately below. */ |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
fields[index].offset = upb_msglayout_place(l, field_size); |
||||||
|
} |
||||||
|
|
||||||
|
/* Allocate oneof fields. Each oneof field consists of a uint32 for the case
|
||||||
|
* and space for the actual data. */ |
||||||
|
for (upb_msg_oneof_begin(&oit, m); !upb_msg_oneof_done(&oit); |
||||||
|
upb_msg_oneof_next(&oit)) { |
||||||
|
const upb_oneofdef* o = upb_msg_iter_oneof(&oit); |
||||||
|
upb_oneof_iter fit; |
||||||
|
|
||||||
|
size_t case_size = sizeof(uint32_t); /* Could potentially optimize this. */ |
||||||
|
upb_msglayout_oneof *oneof = &oneofs[upb_oneofdef_index(o)]; |
||||||
|
size_t field_size = 0; |
||||||
|
|
||||||
|
/* Calculate field size: the max of all field sizes. */ |
||||||
|
for (upb_oneof_begin(&fit, o); |
||||||
|
!upb_oneof_done(&fit); |
||||||
|
upb_oneof_next(&fit)) { |
||||||
|
const upb_fielddef* f = upb_oneof_iter_field(&fit); |
||||||
|
field_size = UPB_MAX(field_size, upb_msg_fielddefsize(f)); |
||||||
|
} |
||||||
|
|
||||||
|
/* Align and allocate case offset. */ |
||||||
|
oneof->case_offset = upb_msglayout_place(l, case_size); |
||||||
|
oneof->data_offset = upb_msglayout_place(l, field_size); |
||||||
|
} |
||||||
|
|
||||||
|
/* Size of the entire structure should be a multiple of its greatest
|
||||||
|
* alignment. TODO: track overall alignment for real? */ |
||||||
|
l->size = align_up(l->size, 8); |
||||||
|
|
||||||
|
return upb_msglayout_initdefault(l, m); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** upb_msgfactory ************************************************************/ |
||||||
|
|
||||||
|
struct upb_msgfactory { |
||||||
|
const upb_symtab *symtab; /* We own a ref. */ |
||||||
|
upb_inttable layouts; |
||||||
|
upb_inttable mergehandlers; |
||||||
|
}; |
||||||
|
|
||||||
|
upb_msgfactory *upb_msgfactory_new(const upb_symtab *symtab) { |
||||||
|
upb_msgfactory *ret = upb_gmalloc(sizeof(*ret)); |
||||||
|
|
||||||
|
ret->symtab = symtab; |
||||||
|
upb_inttable_init(&ret->layouts, UPB_CTYPE_PTR); |
||||||
|
upb_inttable_init(&ret->mergehandlers, UPB_CTYPE_CONSTPTR); |
||||||
|
|
||||||
|
return ret; |
||||||
|
} |
||||||
|
|
||||||
|
void upb_msgfactory_free(upb_msgfactory *f) { |
||||||
|
upb_inttable_iter i; |
||||||
|
upb_inttable_begin(&i, &f->layouts); |
||||||
|
for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { |
||||||
|
upb_msglayout *l = upb_value_getptr(upb_inttable_iter_value(&i)); |
||||||
|
upb_msglayout_free(l); |
||||||
|
} |
||||||
|
|
||||||
|
upb_inttable_begin(&i, &f->mergehandlers); |
||||||
|
for(; !upb_inttable_done(&i); upb_inttable_next(&i)) { |
||||||
|
const upb_handlers *h = upb_value_getconstptr(upb_inttable_iter_value(&i)); |
||||||
|
upb_handlers_unref(h, f); |
||||||
|
} |
||||||
|
|
||||||
|
upb_inttable_uninit(&f->layouts); |
||||||
|
upb_inttable_uninit(&f->mergehandlers); |
||||||
|
upb_gfree(f); |
||||||
|
} |
||||||
|
|
||||||
|
const upb_symtab *upb_msgfactory_symtab(const upb_msgfactory *f) { |
||||||
|
return f->symtab; |
||||||
|
} |
||||||
|
|
||||||
|
const upb_msglayout *upb_msgfactory_getlayout(upb_msgfactory *f, |
||||||
|
const upb_msgdef *m) { |
||||||
|
upb_value v; |
||||||
|
UPB_ASSERT(upb_symtab_lookupmsg(f->symtab, upb_msgdef_fullname(m)) == m); |
||||||
|
UPB_ASSERT(!upb_msgdef_mapentry(m)); |
||||||
|
|
||||||
|
if (upb_inttable_lookupptr(&f->layouts, m, &v)) { |
||||||
|
UPB_ASSERT(upb_value_getptr(v)); |
||||||
|
return upb_value_getptr(v); |
||||||
|
} else { |
||||||
|
/* In case of circular dependency, layout has to be inserted first. */ |
||||||
|
upb_msglayout *l = upb_gmalloc(sizeof(*l)); |
||||||
|
upb_msgfactory *mutable_f = (void*)f; |
||||||
|
upb_inttable_insertptr(&mutable_f->layouts, m, upb_value_ptr(l)); |
||||||
|
UPB_ASSERT(l); |
||||||
|
if (!upb_msglayout_init(m, l, f)) { |
||||||
|
upb_msglayout_free(l); |
||||||
|
} |
||||||
|
return l; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
|
||||||
|
#include "upb/def.h" |
||||||
|
#include "upb/msg.h" |
||||||
|
|
||||||
|
#ifndef UPB_MSGFACTORY_H_ |
||||||
|
#define UPB_MSGFACTORY_H_ |
||||||
|
|
||||||
|
UPB_DECLARE_TYPE(upb::MessageFactory, upb_msgfactory) |
||||||
|
|
||||||
|
/** upb_msgfactory ************************************************************/ |
||||||
|
|
||||||
|
/* A upb_msgfactory contains a cache of upb_msglayout, upb_handlers, and
|
||||||
|
* upb_visitorplan objects. These are the objects necessary to represent, |
||||||
|
* populate, and and visit upb_msg objects. |
||||||
|
* |
||||||
|
* These caches are all populated by upb_msgdef, and lazily created on demand. |
||||||
|
*/ |
||||||
|
|
||||||
|
/* Creates and destroys a msgfactory, respectively. The messages for this
|
||||||
|
* msgfactory must come from |symtab| (which should outlive the msgfactory). */ |
||||||
|
upb_msgfactory *upb_msgfactory_new(const upb_symtab *symtab); |
||||||
|
void upb_msgfactory_free(upb_msgfactory *f); |
||||||
|
|
||||||
|
const upb_symtab *upb_msgfactory_symtab(const upb_msgfactory *f); |
||||||
|
|
||||||
|
/* The functions to get cached objects, lazily creating them on demand. These
|
||||||
|
* all require: |
||||||
|
* |
||||||
|
* - m is in upb_msgfactory_symtab(f) |
||||||
|
* - upb_msgdef_mapentry(m) == false (since map messages can't have layouts). |
||||||
|
* |
||||||
|
* The returned objects will live for as long as the msgfactory does. |
||||||
|
* |
||||||
|
* TODO(haberman): consider making this thread-safe and take a const |
||||||
|
* upb_msgfactory. */ |
||||||
|
const upb_msglayout *upb_msgfactory_getlayout(upb_msgfactory *f, |
||||||
|
const upb_msgdef *m); |
||||||
|
|
||||||
|
|
||||||
|
#endif /* UPB_MSGFACTORY_H_ */ |
Loading…
Reference in new issue