mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-01 19:58:15 +00:00
Default Vector Support C++ (#8870)
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -157,3 +157,6 @@ MODULE.bazel.lock
|
|||||||
|
|
||||||
# Ignore the generated docs
|
# Ignore the generated docs
|
||||||
docs/site
|
docs/site
|
||||||
|
|
||||||
|
# Ignore generated files
|
||||||
|
*.fbs.h
|
||||||
|
|||||||
@@ -218,6 +218,8 @@ set(FlatHash_SRCS
|
|||||||
set(FlatBuffers_Tests_SRCS
|
set(FlatBuffers_Tests_SRCS
|
||||||
${FlatBuffers_Library_SRCS}
|
${FlatBuffers_Library_SRCS}
|
||||||
src/idl_gen_fbs.cpp
|
src/idl_gen_fbs.cpp
|
||||||
|
tests/default_vectors_strings_test.cpp
|
||||||
|
tests/default_vectors_strings_test.h
|
||||||
tests/evolution_test.cpp
|
tests/evolution_test.cpp
|
||||||
tests/flexbuffers_test.cpp
|
tests/flexbuffers_test.cpp
|
||||||
tests/fuzz_test.cpp
|
tests/fuzz_test.cpp
|
||||||
@@ -496,13 +498,14 @@ if(FLATBUFFERS_BUILD_SHAREDLIB)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
function(compile_schema SRC_FBS OPT OUT_GEN_FILE)
|
function(compile_schema SRC_FBS OPT SUFFIX OUT_GEN_FILE)
|
||||||
get_filename_component(SRC_FBS_DIR ${SRC_FBS} PATH)
|
get_filename_component(SRC_FBS_DIR ${SRC_FBS} PATH)
|
||||||
string(REGEX REPLACE "\\.fbs$" "_generated.h" GEN_HEADER ${SRC_FBS})
|
string(REGEX REPLACE "\\.fbs$" "${SUFFIX}.h" GEN_HEADER ${SRC_FBS})
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${GEN_HEADER}
|
OUTPUT ${GEN_HEADER}
|
||||||
COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}"
|
COMMAND "${FLATBUFFERS_FLATC_EXECUTABLE}"
|
||||||
${OPT}
|
${OPT}
|
||||||
|
--filename-suffix ${SUFFIX}
|
||||||
-o "${SRC_FBS_DIR}"
|
-o "${SRC_FBS_DIR}"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
|
"${CMAKE_CURRENT_SOURCE_DIR}/${SRC_FBS}"
|
||||||
DEPENDS flatc ${SRC_FBS}
|
DEPENDS flatc ${SRC_FBS}
|
||||||
@@ -512,12 +515,17 @@ function(compile_schema SRC_FBS OPT OUT_GEN_FILE)
|
|||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
function(compile_schema_for_test SRC_FBS OPT)
|
function(compile_schema_for_test SRC_FBS OPT)
|
||||||
compile_schema("${SRC_FBS}" "${OPT}" GEN_FILE)
|
compile_schema("${SRC_FBS}" "${OPT}" "_generated" GEN_FILE)
|
||||||
|
target_sources(flattests PRIVATE ${GEN_FILE})
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
function(compile_schema_for_test_fbsh SRC_FBS OPT)
|
||||||
|
compile_schema("${SRC_FBS}" "${OPT}" ".fbs" GEN_FILE)
|
||||||
target_sources(flattests PRIVATE ${GEN_FILE})
|
target_sources(flattests PRIVATE ${GEN_FILE})
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
function(compile_schema_for_samples SRC_FBS OPT)
|
function(compile_schema_for_samples SRC_FBS OPT)
|
||||||
compile_schema("${SRC_FBS}" "${OPT}" GEN_FILE)
|
compile_schema("${SRC_FBS}" "${OPT}" "_generated" GEN_FILE)
|
||||||
target_sources(flatsample PRIVATE ${GEN_FILE})
|
target_sources(flatsample PRIVATE ${GEN_FILE})
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
@@ -542,6 +550,7 @@ if(FLATBUFFERS_BUILD_TESTS)
|
|||||||
SET(FLATC_OPT_SCOPED_ENUMS ${FLATC_OPT_COMP};--scoped-enums)
|
SET(FLATC_OPT_SCOPED_ENUMS ${FLATC_OPT_COMP};--scoped-enums)
|
||||||
|
|
||||||
compile_schema_for_test(tests/alignment_test.fbs "${FLATC_OPT_COMP}")
|
compile_schema_for_test(tests/alignment_test.fbs "${FLATC_OPT_COMP}")
|
||||||
|
compile_schema_for_test_fbsh(tests/default_vectors_strings_test.fbs "${FLATC_OPT_COMP}")
|
||||||
compile_schema_for_test(tests/arrays_test.fbs "${FLATC_OPT_SCOPED_ENUMS}")
|
compile_schema_for_test(tests/arrays_test.fbs "${FLATC_OPT_SCOPED_ENUMS}")
|
||||||
compile_schema_for_test(tests/native_inline_table_test.fbs "${FLATC_OPT_COMP}")
|
compile_schema_for_test(tests/native_inline_table_test.fbs "${FLATC_OPT_COMP}")
|
||||||
compile_schema_for_test(tests/native_type_test.fbs "${FLATC_OPT_COMP}")
|
compile_schema_for_test(tests/native_type_test.fbs "${FLATC_OPT_COMP}")
|
||||||
|
|||||||
@@ -187,6 +187,7 @@ def flatbuffer_cc_library(
|
|||||||
visibility = None,
|
visibility = None,
|
||||||
compatible_with = None,
|
compatible_with = None,
|
||||||
restricted_to = None,
|
restricted_to = None,
|
||||||
|
filename_suffix = "_generated",
|
||||||
target_compatible_with = None,
|
target_compatible_with = None,
|
||||||
srcs_filegroup_visibility = None,
|
srcs_filegroup_visibility = None,
|
||||||
gen_reflections = False):
|
gen_reflections = False):
|
||||||
@@ -230,10 +231,13 @@ def flatbuffer_cc_library(
|
|||||||
Fileset([name]_reflection): (Optional) all generated reflection binaries.
|
Fileset([name]_reflection): (Optional) all generated reflection binaries.
|
||||||
cc_library([name]): library with sources and flatbuffers deps.
|
cc_library([name]): library with sources and flatbuffers deps.
|
||||||
"""
|
"""
|
||||||
output_headers = [
|
|
||||||
(out_prefix + "%s_generated.h") % (s.replace(".fbs", "").split("/")[-1].split(":")[-1])
|
output_headers = []
|
||||||
for s in srcs
|
for s in srcs:
|
||||||
]
|
base_name = s.split("/")[-1].split(":")[-1].replace(".fbs", "")
|
||||||
|
header = out_prefix + base_name + filename_suffix + ".h"
|
||||||
|
output_headers.append(header)
|
||||||
|
|
||||||
if deps and includes:
|
if deps and includes:
|
||||||
# There is no inherent reason we couldn't support both, but this discourages
|
# There is no inherent reason we couldn't support both, but this discourages
|
||||||
# use of includes without good reason.
|
# use of includes without good reason.
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
#define FLATBUFFERS_TABLE_H_
|
#define FLATBUFFERS_TABLE_H_
|
||||||
|
|
||||||
#include "flatbuffers/base.h"
|
#include "flatbuffers/base.h"
|
||||||
|
#include "flatbuffers/vector.h"
|
||||||
#include "flatbuffers/verifier.h"
|
#include "flatbuffers/verifier.h"
|
||||||
|
|
||||||
namespace flatbuffers {
|
namespace flatbuffers {
|
||||||
@@ -70,6 +71,32 @@ class Table {
|
|||||||
return GetPointer<P, uoffset64_t>(field);
|
return GetPointer<P, uoffset64_t>(field);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename P, typename SizeT = uoffset_t,
|
||||||
|
typename OffsetSize = uoffset_t>
|
||||||
|
const Vector<P, SizeT>* GetVectorPointerOrEmpty(voffset_t field) const {
|
||||||
|
auto* ptr = GetPointer<const Vector<P, SizeT>*, OffsetSize>(field);
|
||||||
|
return ptr ? ptr : EmptyVector<P, SizeT>();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P, typename SizeT = uoffset_t>
|
||||||
|
const Vector<P, SizeT>* GetVectorPointer64OrEmpty(voffset_t field) const {
|
||||||
|
return GetVectorPointerOrEmpty<P, SizeT, uoffset64_t>(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P, typename SizeT = uoffset_t,
|
||||||
|
typename OffsetSize = uoffset_t>
|
||||||
|
Vector<P, SizeT>* GetMutableVectorPointerOrEmpty(voffset_t field) {
|
||||||
|
auto* ptr = GetPointer<Vector<P, SizeT>*, OffsetSize>(field);
|
||||||
|
// This is a const_cast, but safe, since all mutable operations on an
|
||||||
|
// empty vector are NOPs.
|
||||||
|
return ptr ? ptr : const_cast<Vector<P, SizeT>*>(EmptyVector<P, SizeT>());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P, typename SizeT = uoffset_t>
|
||||||
|
Vector<P, SizeT>* GetMutableVectorPointer64OrEmpty(voffset_t field) {
|
||||||
|
return GetMutableVectorPointerOrEmpty<P, SizeT, uoffset64_t>(field);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename P>
|
template <typename P>
|
||||||
P GetStruct(voffset_t field) const {
|
P GetStruct(voffset_t field) const {
|
||||||
auto field_offset = GetOptionalFieldOffset(field);
|
auto field_offset = GetOptionalFieldOffset(field);
|
||||||
@@ -177,6 +204,39 @@ class Table {
|
|||||||
return VerifyOffsetRequired<uoffset64_t>(verifier, field);
|
return VerifyOffsetRequired<uoffset64_t>(verifier, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify a string that may have a default value.
|
||||||
|
template <typename OffsetT = uoffset_t>
|
||||||
|
bool VerifyStringWithDefault(const Verifier& verifier,
|
||||||
|
voffset_t field) const {
|
||||||
|
auto field_offset = GetOptionalFieldOffset(field);
|
||||||
|
return field_offset == 0 ||
|
||||||
|
verifier.VerifyString(GetPointer<const String*, OffsetT>(field));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify a vector that has a default empty value.
|
||||||
|
template <typename P, typename SizeT = uoffset_t,
|
||||||
|
typename OffsetSize = uoffset_t>
|
||||||
|
bool VerifyVectorWithDefault(const Verifier& verifier,
|
||||||
|
voffset_t field) const {
|
||||||
|
auto field_offset = GetOptionalFieldOffset(field);
|
||||||
|
return field_offset == 0 ||
|
||||||
|
verifier.VerifyVector(
|
||||||
|
GetPointer<const Vector<P, SizeT>*, OffsetSize>(field));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P, typename SizeT = uoffset_t>
|
||||||
|
bool VerifyVector64WithDefault(const Verifier& verifier,
|
||||||
|
voffset_t field) const {
|
||||||
|
return VerifyVectorWithDefault<P, SizeT, uoffset64_t>(verifier, field);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template <typename T, typename SizeT = uoffset_t>
|
||||||
|
static const Vector<T, SizeT>* EmptyVector() {
|
||||||
|
static const SizeT empty_vector_length = 0;
|
||||||
|
return reinterpret_cast<const Vector<T, SizeT>*>(&empty_vector_length);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// private constructor & copy constructor: you obtain instances of this
|
// private constructor & copy constructor: you obtain instances of this
|
||||||
// class by pointing to existing data only
|
// class by pointing to existing data only
|
||||||
|
|||||||
@@ -400,6 +400,10 @@ flatc(
|
|||||||
schema="nested_union_test.fbs",
|
schema="nested_union_test.fbs",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
flatc(
|
||||||
|
NO_INCL_OPTS + CPP_OPTS,
|
||||||
|
schema="default_vectors_strings_test.fbs",
|
||||||
|
)
|
||||||
|
|
||||||
# Optional Scalars
|
# Optional Scalars
|
||||||
optional_scalars_schema = "optional_scalars.fbs"
|
optional_scalars_schema = "optional_scalars.fbs"
|
||||||
|
|||||||
@@ -1924,6 +1924,10 @@ class CppGenerator : public BaseGenerator {
|
|||||||
} else {
|
} else {
|
||||||
return "0";
|
return "0";
|
||||||
}
|
}
|
||||||
|
} else if (IsVector(type) && field.value.constant == "[]") {
|
||||||
|
return "0";
|
||||||
|
} else if (IsString(type) && field.value.constant != "0") {
|
||||||
|
return "0";
|
||||||
} else if (IsStruct(type) && (field.value.constant == "0")) {
|
} else if (IsStruct(type) && (field.value.constant == "0")) {
|
||||||
return "nullptr";
|
return "nullptr";
|
||||||
} else {
|
} else {
|
||||||
@@ -2427,12 +2431,40 @@ class CppGenerator : public BaseGenerator {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BASE_TYPE_STRING: {
|
case BASE_TYPE_STRING: {
|
||||||
|
if (field.value.constant != "0") {
|
||||||
|
if (field.offset64) {
|
||||||
|
code_ +=
|
||||||
|
"{{PRE}}VerifyStringWithDefault<::flatbuffers::uoffset64_t>("
|
||||||
|
"verifier, "
|
||||||
|
"{{OFFSET}})\\";
|
||||||
|
} else {
|
||||||
|
code_ += "{{PRE}}VerifyStringWithDefault(verifier, {{OFFSET}})\\";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
code_ += "{{PRE}}verifier.VerifyString({{NAME}}())\\";
|
code_ += "{{PRE}}verifier.VerifyString({{NAME}}())\\";
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BASE_TYPE_VECTOR64:
|
case BASE_TYPE_VECTOR64:
|
||||||
case BASE_TYPE_VECTOR: {
|
case BASE_TYPE_VECTOR: {
|
||||||
|
if (field.value.constant == "[]") {
|
||||||
|
const auto& vec_type = field.value.type.VectorType();
|
||||||
|
const std::string vtype_wire = GenTypeWire(
|
||||||
|
vec_type, "", VectorElementUserFacing(vec_type), field.offset64);
|
||||||
|
std::string verify_call;
|
||||||
|
if (field.offset64) {
|
||||||
|
verify_call = "{{PRE}}VerifyVector64WithDefault<" + vtype_wire;
|
||||||
|
} else {
|
||||||
|
verify_call = "{{PRE}}VerifyVectorWithDefault<" + vtype_wire;
|
||||||
|
}
|
||||||
|
if (field.value.type.base_type == BASE_TYPE_VECTOR64) {
|
||||||
|
verify_call += ", ::flatbuffers::uoffset64_t";
|
||||||
|
}
|
||||||
|
verify_call += ">(verifier, {{OFFSET}})\\";
|
||||||
|
code_ += verify_call;
|
||||||
|
} else {
|
||||||
code_ += "{{PRE}}verifier.VerifyVector({{NAME}}())\\";
|
code_ += "{{PRE}}verifier.VerifyVector({{NAME}}())\\";
|
||||||
|
}
|
||||||
|
|
||||||
switch (field.value.type.element) {
|
switch (field.value.type.element) {
|
||||||
case BASE_TYPE_STRING: {
|
case BASE_TYPE_STRING: {
|
||||||
@@ -2723,7 +2755,37 @@ class CppGenerator : public BaseGenerator {
|
|||||||
code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
|
code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call));
|
||||||
code_.SetValue("NULLABLE_EXT", NullableExtension());
|
code_.SetValue("NULLABLE_EXT", NullableExtension());
|
||||||
code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
|
code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {";
|
||||||
|
if (IsVector(type) && field.value.constant == "[]") {
|
||||||
|
const auto& vec_type = type.VectorType();
|
||||||
|
const std::string vtype_wire = GenTypeWire(
|
||||||
|
vec_type, "", VectorElementUserFacing(vec_type), field.offset64);
|
||||||
|
std::string get_call;
|
||||||
|
if (field.offset64) {
|
||||||
|
get_call = " return GetVectorPointer64OrEmpty<" + vtype_wire;
|
||||||
|
} else {
|
||||||
|
get_call = " return GetVectorPointerOrEmpty<" + vtype_wire;
|
||||||
|
}
|
||||||
|
if (type.base_type == BASE_TYPE_VECTOR64) {
|
||||||
|
get_call += ", ::flatbuffers::uoffset64_t";
|
||||||
|
}
|
||||||
|
get_call += ">(" + offset_str + ");";
|
||||||
|
code_ += get_call;
|
||||||
|
} else if (IsString(type) && field.value.constant != "0") {
|
||||||
|
// TODO: Add logic to always convert the string to a valid C++ string
|
||||||
|
// literal by handling string escapes.
|
||||||
|
code_ += " auto* ptr = {{FIELD_VALUE}};";
|
||||||
|
code_ += " if (ptr) return ptr;";
|
||||||
|
code_ += " static const struct { uint32_t len; const char s[" +
|
||||||
|
NumToString(field.value.constant.length() + 1) +
|
||||||
|
"]; } bfbs_string = { " +
|
||||||
|
NumToString(field.value.constant.length()) + ", \"" +
|
||||||
|
field.value.constant + "\" };";
|
||||||
|
code_ +=
|
||||||
|
" return reinterpret_cast<const ::flatbuffers::String "
|
||||||
|
" *>(&bfbs_string);";
|
||||||
|
} else {
|
||||||
code_ += " return {{FIELD_VALUE}};";
|
code_ += " return {{FIELD_VALUE}};";
|
||||||
|
}
|
||||||
code_ += " }";
|
code_ += " }";
|
||||||
} else {
|
} else {
|
||||||
auto wire_type = GenTypeBasic(type, false);
|
auto wire_type = GenTypeBasic(type, false);
|
||||||
@@ -2910,6 +2972,27 @@ class CppGenerator : public BaseGenerator {
|
|||||||
} else {
|
} else {
|
||||||
auto postptr = " *" + NullableExtension();
|
auto postptr = " *" + NullableExtension();
|
||||||
auto wire_type = GenTypeGet(type, " ", "", postptr.c_str(), true);
|
auto wire_type = GenTypeGet(type, " ", "", postptr.c_str(), true);
|
||||||
|
code_.SetValue("FIELD_TYPE", wire_type);
|
||||||
|
|
||||||
|
if (IsVector(type) && field.value.constant == "[]") {
|
||||||
|
const auto& vec_type = type.VectorType();
|
||||||
|
const std::string vtype_wire = GenTypeWire(
|
||||||
|
vec_type, "", VectorElementUserFacing(vec_type), field.offset64);
|
||||||
|
code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
|
||||||
|
std::string get_call;
|
||||||
|
if (field.offset64) {
|
||||||
|
get_call =
|
||||||
|
" return GetMutableVectorPointer64OrEmpty<" + vtype_wire;
|
||||||
|
} else {
|
||||||
|
get_call = " return GetMutableVectorPointerOrEmpty<" + vtype_wire;
|
||||||
|
}
|
||||||
|
if (type.base_type == BASE_TYPE_VECTOR64) {
|
||||||
|
get_call += ", ::flatbuffers::uoffset64_t";
|
||||||
|
}
|
||||||
|
get_call += ">(" + offset_str + ");";
|
||||||
|
code_ += get_call;
|
||||||
|
code_ += " }";
|
||||||
|
} else {
|
||||||
const std::string accessor = [&]() {
|
const std::string accessor = [&]() {
|
||||||
if (IsStruct(type)) {
|
if (IsStruct(type)) {
|
||||||
return "GetStruct<";
|
return "GetStruct<";
|
||||||
@@ -2920,14 +3003,14 @@ class CppGenerator : public BaseGenerator {
|
|||||||
return "GetPointer<";
|
return "GetPointer<";
|
||||||
}();
|
}();
|
||||||
auto underlying = accessor + wire_type + ">(" + offset_str + ")";
|
auto underlying = accessor + wire_type + ">(" + offset_str + ")";
|
||||||
code_.SetValue("FIELD_TYPE", wire_type);
|
code_.SetValue("FIELD_VALUE",
|
||||||
code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, underlying));
|
GenUnderlyingCast(field, true, underlying));
|
||||||
|
|
||||||
code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
|
code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {";
|
||||||
code_ += " return {{FIELD_VALUE}};";
|
code_ += " return {{FIELD_VALUE}};";
|
||||||
code_ += " }";
|
code_ += " }";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string GetNestedFlatBufferName(const FieldDef& field) {
|
std::string GetNestedFlatBufferName(const FieldDef& field) {
|
||||||
auto nested = field.attributes.Lookup("nested_flatbuffer");
|
auto nested = field.attributes.Lookup("nested_flatbuffer");
|
||||||
@@ -3305,9 +3388,17 @@ class CppGenerator : public BaseGenerator {
|
|||||||
} else {
|
} else {
|
||||||
code_.SetValue("CREATE_STRING", "CreateSharedString");
|
code_.SetValue("CREATE_STRING", "CreateSharedString");
|
||||||
}
|
}
|
||||||
|
if (field->value.constant != "0") {
|
||||||
|
code_ +=
|
||||||
|
" auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? "
|
||||||
|
"_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : "
|
||||||
|
"_fbb.{{CREATE_STRING}}(\"" +
|
||||||
|
field->value.constant + "\");";
|
||||||
|
} else {
|
||||||
code_ +=
|
code_ +=
|
||||||
" auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? "
|
" auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? "
|
||||||
"_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : 0;";
|
"_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : 0;";
|
||||||
|
}
|
||||||
} else if (IsVector(field->value.type)) {
|
} else if (IsVector(field->value.type)) {
|
||||||
const std::string force_align_code =
|
const std::string force_align_code =
|
||||||
GenVectorForceAlign(*field, Name(*field) + "->size()");
|
GenVectorForceAlign(*field, Name(*field) + "->size()");
|
||||||
|
|||||||
@@ -2772,7 +2772,8 @@ bool Parser::SupportsOptionalScalars() const {
|
|||||||
|
|
||||||
bool Parser::SupportsDefaultVectorsAndStrings() const {
|
bool Parser::SupportsDefaultVectorsAndStrings() const {
|
||||||
static FLATBUFFERS_CONSTEXPR unsigned long supported_langs =
|
static FLATBUFFERS_CONSTEXPR unsigned long supported_langs =
|
||||||
IDLOptions::kRust | IDLOptions::kSwift | IDLOptions::kNim;
|
IDLOptions::kRust | IDLOptions::kSwift | IDLOptions::kNim |
|
||||||
|
IDLOptions::kCpp | IDLOptions::kBinary | IDLOptions::kJson;
|
||||||
return !(opts.lang_to_generate & ~supported_langs);
|
return !(opts.lang_to_generate & ~supported_langs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,8 @@ cc_test(
|
|||||||
"alignment_test.cpp",
|
"alignment_test.cpp",
|
||||||
"alignment_test.h",
|
"alignment_test.h",
|
||||||
"alignment_test_generated.h",
|
"alignment_test_generated.h",
|
||||||
|
"default_vectors_strings_test.cpp",
|
||||||
|
"default_vectors_strings_test.h",
|
||||||
"evolution_test.cpp",
|
"evolution_test.cpp",
|
||||||
"evolution_test.h",
|
"evolution_test.h",
|
||||||
"evolution_test/evolution_v1_generated.h",
|
"evolution_test/evolution_v1_generated.h",
|
||||||
@@ -134,6 +136,7 @@ cc_test(
|
|||||||
deps = [
|
deps = [
|
||||||
":alignment_test_cc_fbs",
|
":alignment_test_cc_fbs",
|
||||||
":arrays_test_cc_fbs",
|
":arrays_test_cc_fbs",
|
||||||
|
":default_vectors_strings_test_cc_fbs",
|
||||||
":monster_extra_cc_fbs",
|
":monster_extra_cc_fbs",
|
||||||
":monster_test_cc_fbs",
|
":monster_test_cc_fbs",
|
||||||
":native_type_test_cc_fbs",
|
":native_type_test_cc_fbs",
|
||||||
@@ -272,3 +275,16 @@ flatbuffer_cc_library(
|
|||||||
name = "alignment_test_cc_fbs",
|
name = "alignment_test_cc_fbs",
|
||||||
srcs = ["alignment_test.fbs"],
|
srcs = ["alignment_test.fbs"],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
flatbuffer_cc_library(
|
||||||
|
name = "default_vectors_strings_test_cc_fbs",
|
||||||
|
srcs = ["default_vectors_strings_test.fbs"],
|
||||||
|
flatc_args = [
|
||||||
|
"--gen-compare",
|
||||||
|
"--gen-mutable",
|
||||||
|
"--gen-object-api",
|
||||||
|
"--reflect-names",
|
||||||
|
"--filename-suffix .fbs",
|
||||||
|
],
|
||||||
|
filename_suffix = ".fbs"
|
||||||
|
)
|
||||||
|
|||||||
249
tests/default_vectors_strings_test.cpp
Normal file
249
tests/default_vectors_strings_test.cpp
Normal file
@@ -0,0 +1,249 @@
|
|||||||
|
#include "tests/default_vectors_strings_test.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "include/flatbuffers/buffer.h"
|
||||||
|
#include "include/flatbuffers/flatbuffer_builder.h"
|
||||||
|
#include "include/flatbuffers/string.h"
|
||||||
|
#include "include/flatbuffers/vector.h"
|
||||||
|
#include "include/flatbuffers/verifier.h"
|
||||||
|
#include "tests/default_vectors_strings_test.fbs.h"
|
||||||
|
#include "tests/test_assert.h"
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
namespace tests {
|
||||||
|
|
||||||
|
using flatbuffers::FlatBufferBuilder64;
|
||||||
|
using flatbuffers::Offset;
|
||||||
|
using flatbuffers::String;
|
||||||
|
using flatbuffers::Verifier;
|
||||||
|
|
||||||
|
void DefaultVectorsStringsTest_EmptyOnDefault_Const() {
|
||||||
|
FlatBufferBuilder64 builder;
|
||||||
|
|
||||||
|
// Create table without providing the fields with defaults.
|
||||||
|
DefaultVectorsStringsTest::TableWithDefaultVectorsBuilder tbl_builder(
|
||||||
|
builder);
|
||||||
|
tbl_builder.add_regular_int(100);
|
||||||
|
auto offset = tbl_builder.Finish();
|
||||||
|
builder.Finish(offset);
|
||||||
|
|
||||||
|
Verifier verifier(builder.GetBufferPointer(), builder.GetSize());
|
||||||
|
TEST_ASSERT(
|
||||||
|
DefaultVectorsStringsTest::VerifyTableWithDefaultVectorsBuffer(verifier));
|
||||||
|
|
||||||
|
const auto* table = DefaultVectorsStringsTest::GetTableWithDefaultVectors(
|
||||||
|
builder.GetBufferPointer());
|
||||||
|
TEST_NOTNULL(table);
|
||||||
|
|
||||||
|
// Verify default scalar vectors.
|
||||||
|
TEST_NOTNULL(table->int_vec());
|
||||||
|
TEST_EQ(table->int_vec()->size(), 0);
|
||||||
|
TEST_NOTNULL(table->bool_vec());
|
||||||
|
TEST_EQ(table->bool_vec()->size(), 0);
|
||||||
|
TEST_NOTNULL(table->char_vec());
|
||||||
|
TEST_EQ(table->char_vec()->size(), 0);
|
||||||
|
TEST_NOTNULL(table->uchar_vec());
|
||||||
|
TEST_EQ(table->uchar_vec()->size(), 0);
|
||||||
|
TEST_NOTNULL(table->short_vec());
|
||||||
|
TEST_EQ(table->short_vec()->size(), 0);
|
||||||
|
TEST_NOTNULL(table->ushort_vec());
|
||||||
|
TEST_EQ(table->ushort_vec()->size(), 0);
|
||||||
|
TEST_NOTNULL(table->uint_vec());
|
||||||
|
TEST_EQ(table->uint_vec()->size(), 0);
|
||||||
|
TEST_NOTNULL(table->long_vec());
|
||||||
|
TEST_EQ(table->long_vec()->size(), 0);
|
||||||
|
TEST_NOTNULL(table->ulong_vec());
|
||||||
|
TEST_EQ(table->ulong_vec()->size(), 0);
|
||||||
|
TEST_NOTNULL(table->float_vec());
|
||||||
|
TEST_EQ(table->float_vec()->size(), 0);
|
||||||
|
TEST_NOTNULL(table->double_vec());
|
||||||
|
TEST_EQ(table->double_vec()->size(), 0);
|
||||||
|
|
||||||
|
// Verify default string_vec.
|
||||||
|
TEST_NOTNULL(table->string_vec());
|
||||||
|
TEST_EQ(table->string_vec()->size(), 0);
|
||||||
|
|
||||||
|
// Verify default string fields.
|
||||||
|
TEST_NOTNULL(table->empty_string());
|
||||||
|
TEST_EQ_STR(table->empty_string()->c_str(), "");
|
||||||
|
TEST_NOTNULL(table->some_string());
|
||||||
|
TEST_EQ_STR(table->some_string()->c_str(), "some");
|
||||||
|
|
||||||
|
// Verify default struct_vec.
|
||||||
|
TEST_NOTNULL(table->struct_vec());
|
||||||
|
TEST_EQ(table->struct_vec()->size(), 0);
|
||||||
|
|
||||||
|
// Verify default table_vec.
|
||||||
|
TEST_NOTNULL(table->table_vec());
|
||||||
|
TEST_EQ(table->table_vec()->size(), 0);
|
||||||
|
|
||||||
|
// Verify default enum_vec.
|
||||||
|
TEST_NOTNULL(table->enum_vec());
|
||||||
|
TEST_EQ(table->enum_vec()->size(), 0);
|
||||||
|
|
||||||
|
// Verify non-default vector field.
|
||||||
|
TEST_NULL(table->regular_int_vec());
|
||||||
|
|
||||||
|
// Verify pointer and offset64 combinations.
|
||||||
|
TEST_NOTNULL(table->int_vec64());
|
||||||
|
TEST_EQ(table->int_vec64()->size(), 0);
|
||||||
|
TEST_NOTNULL(table->int_vec_offset64());
|
||||||
|
TEST_EQ(table->int_vec_offset64()->size(), 0);
|
||||||
|
|
||||||
|
// Verify non-default field.
|
||||||
|
TEST_EQ(table->regular_int(), 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefaultVectorsStringsTest_EmptyOnDefault_Mutable() {
|
||||||
|
FlatBufferBuilder64 builder;
|
||||||
|
|
||||||
|
// Create table without providing the fields with defaults.
|
||||||
|
DefaultVectorsStringsTest::TableWithDefaultVectorsBuilder tbl_builder(
|
||||||
|
builder);
|
||||||
|
tbl_builder.add_regular_int(100);
|
||||||
|
auto offset = tbl_builder.Finish();
|
||||||
|
builder.Finish(offset);
|
||||||
|
|
||||||
|
Verifier verifier(builder.GetBufferPointer(), builder.GetSize());
|
||||||
|
TEST_ASSERT(
|
||||||
|
DefaultVectorsStringsTest::VerifyTableWithDefaultVectorsBuffer(verifier));
|
||||||
|
|
||||||
|
auto* mutable_table =
|
||||||
|
DefaultVectorsStringsTest::GetMutableTableWithDefaultVectors(
|
||||||
|
builder.GetBufferPointer());
|
||||||
|
TEST_NOTNULL(mutable_table);
|
||||||
|
|
||||||
|
// Verify default scalar vectors.
|
||||||
|
TEST_NOTNULL(mutable_table->mutable_int_vec());
|
||||||
|
TEST_EQ(mutable_table->mutable_int_vec()->size(), 0);
|
||||||
|
TEST_NOTNULL(mutable_table->mutable_bool_vec());
|
||||||
|
TEST_EQ(mutable_table->mutable_bool_vec()->size(), 0);
|
||||||
|
TEST_NOTNULL(mutable_table->mutable_char_vec());
|
||||||
|
TEST_EQ(mutable_table->mutable_char_vec()->size(), 0);
|
||||||
|
TEST_NOTNULL(mutable_table->mutable_uchar_vec());
|
||||||
|
TEST_EQ(mutable_table->mutable_uchar_vec()->size(), 0);
|
||||||
|
TEST_NOTNULL(mutable_table->mutable_short_vec());
|
||||||
|
TEST_EQ(mutable_table->mutable_short_vec()->size(), 0);
|
||||||
|
TEST_NOTNULL(mutable_table->mutable_ushort_vec());
|
||||||
|
TEST_EQ(mutable_table->mutable_ushort_vec()->size(), 0);
|
||||||
|
TEST_NOTNULL(mutable_table->mutable_uint_vec());
|
||||||
|
TEST_EQ(mutable_table->mutable_uint_vec()->size(), 0);
|
||||||
|
TEST_NOTNULL(mutable_table->mutable_long_vec());
|
||||||
|
TEST_EQ(mutable_table->mutable_long_vec()->size(), 0);
|
||||||
|
TEST_NOTNULL(mutable_table->mutable_ulong_vec());
|
||||||
|
TEST_EQ(mutable_table->mutable_ulong_vec()->size(), 0);
|
||||||
|
TEST_NOTNULL(mutable_table->mutable_float_vec());
|
||||||
|
TEST_EQ(mutable_table->mutable_float_vec()->size(), 0);
|
||||||
|
TEST_NOTNULL(mutable_table->mutable_double_vec());
|
||||||
|
TEST_EQ(mutable_table->mutable_double_vec()->size(), 0);
|
||||||
|
|
||||||
|
// Verify default struct_vec.
|
||||||
|
TEST_NOTNULL(mutable_table->mutable_struct_vec());
|
||||||
|
TEST_EQ(mutable_table->mutable_struct_vec()->size(), 0);
|
||||||
|
|
||||||
|
// Verify default table_vec.
|
||||||
|
TEST_NOTNULL(mutable_table->mutable_table_vec());
|
||||||
|
TEST_EQ(mutable_table->mutable_table_vec()->size(), 0);
|
||||||
|
|
||||||
|
// Verify default enum_vec.
|
||||||
|
TEST_NOTNULL(mutable_table->mutable_enum_vec());
|
||||||
|
TEST_EQ(mutable_table->mutable_enum_vec()->size(), 0);
|
||||||
|
|
||||||
|
// Verify non-default vector field.
|
||||||
|
TEST_NULL(mutable_table->mutable_regular_int_vec());
|
||||||
|
|
||||||
|
// Verify pointer and offset64 combinations.
|
||||||
|
TEST_NOTNULL(mutable_table->mutable_int_vec64());
|
||||||
|
TEST_EQ(mutable_table->mutable_int_vec64()->size(), 0);
|
||||||
|
TEST_NOTNULL(mutable_table->mutable_int_vec_offset64());
|
||||||
|
TEST_EQ(mutable_table->mutable_int_vec_offset64()->size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefaultVectorsStringsTest_WithValues() {
|
||||||
|
// Create a table with values for the defaulted vector fields.
|
||||||
|
FlatBufferBuilder64 builder;
|
||||||
|
auto int_vec64 = builder.CreateVector64(std::vector<int>({30, 40}));
|
||||||
|
auto int_vec_offset64 =
|
||||||
|
builder.CreateVector64<flatbuffers::Vector>(std::vector<int>({50, 60}));
|
||||||
|
auto int_vec = builder.CreateVector(std::vector<int>({1, 2}));
|
||||||
|
auto bool_vec = builder.CreateVector(std::vector<uint8_t>({true, false}));
|
||||||
|
auto string_vec = builder.CreateVector(std::vector<Offset<String>>(
|
||||||
|
{builder.CreateString("a"), builder.CreateString("b")}));
|
||||||
|
auto empty_string = builder.CreateString("not empty");
|
||||||
|
auto some_string = builder.CreateString("not some");
|
||||||
|
DefaultVectorsStringsTest::MyStruct structs[] = {
|
||||||
|
DefaultVectorsStringsTest::MyStruct(1, 2),
|
||||||
|
DefaultVectorsStringsTest::MyStruct(3, 4)};
|
||||||
|
auto struct_vec = builder.CreateVectorOfStructs(structs, 2);
|
||||||
|
auto regular_int_vec = builder.CreateVector(std::vector<int>({10, 20}));
|
||||||
|
|
||||||
|
DefaultVectorsStringsTest::TableWithDefaultVectorsBuilder tbl_builder(
|
||||||
|
builder);
|
||||||
|
tbl_builder.add_int_vec(int_vec);
|
||||||
|
tbl_builder.add_int_vec64(int_vec64);
|
||||||
|
tbl_builder.add_int_vec_offset64(int_vec_offset64);
|
||||||
|
|
||||||
|
tbl_builder.add_bool_vec(bool_vec);
|
||||||
|
tbl_builder.add_string_vec(string_vec);
|
||||||
|
tbl_builder.add_empty_string(empty_string);
|
||||||
|
tbl_builder.add_some_string(some_string);
|
||||||
|
tbl_builder.add_struct_vec(struct_vec);
|
||||||
|
tbl_builder.add_regular_int_vec(regular_int_vec);
|
||||||
|
auto offset = tbl_builder.Finish();
|
||||||
|
builder.Finish(offset);
|
||||||
|
|
||||||
|
Verifier verifier(builder.GetBufferPointer(), builder.GetSize());
|
||||||
|
TEST_ASSERT(
|
||||||
|
DefaultVectorsStringsTest::VerifyTableWithDefaultVectorsBuffer(verifier));
|
||||||
|
|
||||||
|
const auto* table = DefaultVectorsStringsTest::GetTableWithDefaultVectors(
|
||||||
|
builder.GetBufferPointer());
|
||||||
|
|
||||||
|
TEST_EQ(table->int_vec()->size(), 2);
|
||||||
|
TEST_EQ(table->int_vec()->Get(1), 2);
|
||||||
|
TEST_EQ(table->bool_vec()->size(), 2);
|
||||||
|
TEST_EQ(table->bool_vec()->Get(0), true);
|
||||||
|
TEST_EQ(table->string_vec()->size(), 2);
|
||||||
|
TEST_EQ_STR(table->string_vec()->Get(1)->c_str(), "b");
|
||||||
|
TEST_EQ_STR(table->empty_string()->c_str(), "not empty");
|
||||||
|
TEST_EQ_STR(table->some_string()->c_str(), "not some");
|
||||||
|
TEST_EQ(table->struct_vec()->size(), 2);
|
||||||
|
TEST_EQ(table->struct_vec()->Get(1)->b(), 4);
|
||||||
|
TEST_EQ(table->regular_int_vec()->size(), 2);
|
||||||
|
TEST_EQ(table->regular_int_vec()->Get(1), 20);
|
||||||
|
|
||||||
|
TEST_EQ(table->int_vec64()->size(), 2);
|
||||||
|
TEST_EQ(table->int_vec64()->Get(1), 40);
|
||||||
|
TEST_EQ(table->int_vec_offset64()->size(), 2);
|
||||||
|
TEST_EQ(table->int_vec_offset64()->Get(1), 60);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefaultVectorsStringsTest_BufferSize() {
|
||||||
|
FlatBufferBuilder64 builder;
|
||||||
|
// Create a table where all fields with default values are omitted.
|
||||||
|
DefaultVectorsStringsTest::TableWithDefaultVectorsBuilder tbl_builder(
|
||||||
|
builder);
|
||||||
|
auto offset = tbl_builder.Finish();
|
||||||
|
builder.Finish(offset);
|
||||||
|
|
||||||
|
Verifier verifier(builder.GetBufferPointer(), builder.GetSize());
|
||||||
|
TEST_ASSERT(
|
||||||
|
DefaultVectorsStringsTest::VerifyTableWithDefaultVectorsBuffer(verifier));
|
||||||
|
|
||||||
|
// The buffer should be small when only defaults are used.
|
||||||
|
// This value can be adjusted if the schema changes.
|
||||||
|
constexpr unsigned int buffer_size_threshold_in_bytes = 12;
|
||||||
|
TEST_ASSERT(builder.GetSize() <= buffer_size_threshold_in_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DefaultVectorsStringsTest() {
|
||||||
|
DefaultVectorsStringsTest_EmptyOnDefault_Const();
|
||||||
|
DefaultVectorsStringsTest_EmptyOnDefault_Mutable();
|
||||||
|
DefaultVectorsStringsTest_WithValues();
|
||||||
|
DefaultVectorsStringsTest_BufferSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace tests
|
||||||
|
} // namespace flatbuffers
|
||||||
39
tests/default_vectors_strings_test.fbs
Normal file
39
tests/default_vectors_strings_test.fbs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// C++ Only Schema for Default Vectors Test
|
||||||
|
namespace DefaultVectorsStringsTest;
|
||||||
|
|
||||||
|
struct MyStruct {
|
||||||
|
a:int;
|
||||||
|
b:int;
|
||||||
|
}
|
||||||
|
|
||||||
|
table MyTable {
|
||||||
|
a:int;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum MyEnum:byte { A, B }
|
||||||
|
|
||||||
|
table TableWithDefaultVectors {
|
||||||
|
int_vec:[int] = [];
|
||||||
|
bool_vec:[bool] = [];
|
||||||
|
char_vec:[byte] = [];
|
||||||
|
uchar_vec:[ubyte] = [];
|
||||||
|
short_vec:[short] = [];
|
||||||
|
ushort_vec:[ushort] = [];
|
||||||
|
uint_vec:[uint] = [];
|
||||||
|
long_vec:[long] = [];
|
||||||
|
ulong_vec:[ulong] = [];
|
||||||
|
float_vec:[float] = [];
|
||||||
|
double_vec:[double] = [];
|
||||||
|
string_vec:[string] = [];
|
||||||
|
empty_string:string = "";
|
||||||
|
some_string:string = "some";
|
||||||
|
struct_vec:[MyStruct] = [];
|
||||||
|
table_vec:[MyTable] = [];
|
||||||
|
enum_vec:[MyEnum] = [];
|
||||||
|
regular_int_vec:[int];
|
||||||
|
regular_int:int;
|
||||||
|
int_vec_offset64:[int] = [] (offset64);
|
||||||
|
int_vec64:[int]= [] (vector64);
|
||||||
|
}
|
||||||
|
|
||||||
|
root_type TableWithDefaultVectors;
|
||||||
17
tests/default_vectors_strings_test.h
Normal file
17
tests/default_vectors_strings_test.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
#ifndef THIRDPARTY_FLATBUFFERS_TESTS_DEFAULT_VECTORS_STRINGS_TEST_H_
|
||||||
|
#define THIRDPARTY_FLATBUFFERS_TESTS_DEFAULT_VECTORS_STRINGS_TEST_H_
|
||||||
|
|
||||||
|
namespace flatbuffers {
|
||||||
|
namespace tests {
|
||||||
|
|
||||||
|
void DefaultVectorsStringsTest_EmptyOnDefault_Const();
|
||||||
|
void DefaultVectorsStringsTest_EmptyOnDefault_Mutable();
|
||||||
|
void DefaultVectorsStringsTest_EmptyOnDefault();
|
||||||
|
void DefaultVectorsStringsTest_WithValues();
|
||||||
|
void DefaultVectorsStringsTest_BufferSize();
|
||||||
|
void DefaultVectorsStringsTest();
|
||||||
|
|
||||||
|
} // namespace tests
|
||||||
|
} // namespace flatbuffers
|
||||||
|
|
||||||
|
#endif // THIRDPARTY_FLATBUFFERS_TESTS_DEFAULT_VECTORS_STRINGS_TEST_H_
|
||||||
@@ -34,6 +34,7 @@
|
|||||||
#include "third_party/absl/container/flat_hash_set.h"
|
#include "third_party/absl/container/flat_hash_set.h"
|
||||||
#endif
|
#endif
|
||||||
#include "alignment_test.h"
|
#include "alignment_test.h"
|
||||||
|
#include "default_vectors_strings_test.h"
|
||||||
#include "evolution_test.h"
|
#include "evolution_test.h"
|
||||||
#include "flatbuffers/flatbuffers.h"
|
#include "flatbuffers/flatbuffers.h"
|
||||||
#include "flatbuffers/idl.h"
|
#include "flatbuffers/idl.h"
|
||||||
@@ -1836,6 +1837,7 @@ int FlatBufferTests(const std::string& tests_data_path) {
|
|||||||
Offset64Tests();
|
Offset64Tests();
|
||||||
UnionUnderlyingTypeTest();
|
UnionUnderlyingTypeTest();
|
||||||
StructsInHashTableTest();
|
StructsInHashTableTest();
|
||||||
|
DefaultVectorsStringsTest();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
Reference in New Issue
Block a user