diff options
author | reshilkin <reshilkin@yandex-team.com> | 2023-08-02 13:42:42 +0300 |
---|---|---|
committer | reshilkin <reshilkin@yandex-team.com> | 2023-08-02 13:42:42 +0300 |
commit | 9355caf367a5fa8b2658dc09120a181e17e88646 (patch) | |
tree | edb8bd5125d918304808f1161f8f9a58acd623e8 /contrib/libs | |
parent | 65d926376d67e796c234da615753ab7c16021560 (diff) | |
download | ydb-9355caf367a5fa8b2658dc09120a181e17e88646.tar.gz |
Auto code-generation for .fbs.h in arrow
Diffstat (limited to 'contrib/libs')
91 files changed, 42646 insertions, 5304 deletions
diff --git a/contrib/libs/CMakeLists.darwin-x86_64.txt b/contrib/libs/CMakeLists.darwin-x86_64.txt index c0a9e6ecad..7c38598e03 100644 --- a/contrib/libs/CMakeLists.darwin-x86_64.txt +++ b/contrib/libs/CMakeLists.darwin-x86_64.txt @@ -21,6 +21,7 @@ add_subdirectory(double-conversion) add_subdirectory(expat) add_subdirectory(farmhash) add_subdirectory(fastlz) +add_subdirectory(flatbuffers) add_subdirectory(fmt) add_subdirectory(googleapis-common-protos) add_subdirectory(grpc) diff --git a/contrib/libs/CMakeLists.linux-aarch64.txt b/contrib/libs/CMakeLists.linux-aarch64.txt index 824ae3431f..af54fc4f93 100644 --- a/contrib/libs/CMakeLists.linux-aarch64.txt +++ b/contrib/libs/CMakeLists.linux-aarch64.txt @@ -20,6 +20,7 @@ add_subdirectory(double-conversion) add_subdirectory(expat) add_subdirectory(farmhash) add_subdirectory(fastlz) +add_subdirectory(flatbuffers) add_subdirectory(fmt) add_subdirectory(googleapis-common-protos) add_subdirectory(grpc) diff --git a/contrib/libs/CMakeLists.linux-x86_64.txt b/contrib/libs/CMakeLists.linux-x86_64.txt index e1a97af442..ddfc9ed05a 100644 --- a/contrib/libs/CMakeLists.linux-x86_64.txt +++ b/contrib/libs/CMakeLists.linux-x86_64.txt @@ -20,6 +20,7 @@ add_subdirectory(double-conversion) add_subdirectory(expat) add_subdirectory(farmhash) add_subdirectory(fastlz) +add_subdirectory(flatbuffers) add_subdirectory(fmt) add_subdirectory(googleapis-common-protos) add_subdirectory(grpc) diff --git a/contrib/libs/CMakeLists.windows-x86_64.txt b/contrib/libs/CMakeLists.windows-x86_64.txt index f4c4028e47..99a7d95650 100644 --- a/contrib/libs/CMakeLists.windows-x86_64.txt +++ b/contrib/libs/CMakeLists.windows-x86_64.txt @@ -20,6 +20,7 @@ add_subdirectory(double-conversion) add_subdirectory(expat) add_subdirectory(farmhash) add_subdirectory(fastlz) +add_subdirectory(flatbuffers) add_subdirectory(fmt) add_subdirectory(googleapis-common-protos) add_subdirectory(grpc) diff --git a/contrib/libs/apache/arrow/CMakeLists.darwin-x86_64.txt b/contrib/libs/apache/arrow/CMakeLists.darwin-x86_64.txt index 94c9dda6b7..25ad7cb3bf 100644 --- a/contrib/libs/apache/arrow/CMakeLists.darwin-x86_64.txt +++ b/contrib/libs/apache/arrow/CMakeLists.darwin-x86_64.txt @@ -7,6 +7,42 @@ find_package(ZLIB REQUIRED) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) add_library(libs-apache-arrow) target_compile_options(libs-apache-arrow PUBLIC @@ -31,6 +67,7 @@ target_compile_options(libs-apache-arrow PRIVATE $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> ) target_include_directories(libs-apache-arrow PUBLIC + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/src ) @@ -60,6 +97,7 @@ target_link_libraries(libs-apache-arrow PUBLIC contrib-restricted-fast_float contrib-restricted-thrift contrib-restricted-uriparser + contrib-libs-flatbuffers ) target_sources(libs-apache-arrow PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/arrow/adapters/orc/adapter.cc @@ -262,4 +300,58 @@ target_sources(libs-apache-arrow PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/parquet/stream_reader.cc ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/parquet/stream_writer.cc ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/parquet/types.cc + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/File.fbs.cpp + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Message.fbs.cpp + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Schema.fbs.cpp + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/SparseTensor.fbs.cpp + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Tensor.fbs.cpp + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/feather.fbs.cpp +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/File.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Message.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Schema.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/SparseTensor.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Tensor.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/feather.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} ) diff --git a/contrib/libs/apache/arrow/CMakeLists.linux-aarch64.txt b/contrib/libs/apache/arrow/CMakeLists.linux-aarch64.txt index c7853de814..82596c804a 100644 --- a/contrib/libs/apache/arrow/CMakeLists.linux-aarch64.txt +++ b/contrib/libs/apache/arrow/CMakeLists.linux-aarch64.txt @@ -7,6 +7,42 @@ find_package(ZLIB REQUIRED) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) add_library(libs-apache-arrow) target_compile_options(libs-apache-arrow PUBLIC @@ -31,6 +67,7 @@ target_compile_options(libs-apache-arrow PRIVATE $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> ) target_include_directories(libs-apache-arrow PUBLIC + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/src ) @@ -61,6 +98,7 @@ target_link_libraries(libs-apache-arrow PUBLIC contrib-restricted-fast_float contrib-restricted-thrift contrib-restricted-uriparser + contrib-libs-flatbuffers ) target_sources(libs-apache-arrow PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/arrow/adapters/orc/adapter.cc @@ -263,4 +301,58 @@ target_sources(libs-apache-arrow PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/parquet/stream_reader.cc ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/parquet/stream_writer.cc ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/parquet/types.cc + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/File.fbs.cpp + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Message.fbs.cpp + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Schema.fbs.cpp + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/SparseTensor.fbs.cpp + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Tensor.fbs.cpp + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/feather.fbs.cpp +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/File.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Message.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Schema.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/SparseTensor.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Tensor.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/feather.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} ) diff --git a/contrib/libs/apache/arrow/CMakeLists.linux-x86_64.txt b/contrib/libs/apache/arrow/CMakeLists.linux-x86_64.txt index c7853de814..82596c804a 100644 --- a/contrib/libs/apache/arrow/CMakeLists.linux-x86_64.txt +++ b/contrib/libs/apache/arrow/CMakeLists.linux-x86_64.txt @@ -7,6 +7,42 @@ find_package(ZLIB REQUIRED) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) add_library(libs-apache-arrow) target_compile_options(libs-apache-arrow PUBLIC @@ -31,6 +67,7 @@ target_compile_options(libs-apache-arrow PRIVATE $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> ) target_include_directories(libs-apache-arrow PUBLIC + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/src ) @@ -61,6 +98,7 @@ target_link_libraries(libs-apache-arrow PUBLIC contrib-restricted-fast_float contrib-restricted-thrift contrib-restricted-uriparser + contrib-libs-flatbuffers ) target_sources(libs-apache-arrow PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/arrow/adapters/orc/adapter.cc @@ -263,4 +301,58 @@ target_sources(libs-apache-arrow PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/parquet/stream_reader.cc ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/parquet/stream_writer.cc ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/parquet/types.cc + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/File.fbs.cpp + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Message.fbs.cpp + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Schema.fbs.cpp + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/SparseTensor.fbs.cpp + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Tensor.fbs.cpp + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/feather.fbs.cpp +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/File.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Message.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Schema.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/SparseTensor.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Tensor.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/feather.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} ) diff --git a/contrib/libs/apache/arrow/CMakeLists.windows-x86_64.txt b/contrib/libs/apache/arrow/CMakeLists.windows-x86_64.txt index 78fddcc593..e0d4023872 100644 --- a/contrib/libs/apache/arrow/CMakeLists.windows-x86_64.txt +++ b/contrib/libs/apache/arrow/CMakeLists.windows-x86_64.txt @@ -7,6 +7,42 @@ find_package(ZLIB REQUIRED) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) +get_built_tool_path( + TOOL_flatc_bin + TOOL_flatc_dependency + contrib/tools/flatc/bin + flatc +) add_library(libs-apache-arrow) target_compile_options(libs-apache-arrow PUBLIC @@ -30,6 +66,7 @@ target_compile_options(libs-apache-arrow PRIVATE $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> ) target_include_directories(libs-apache-arrow PUBLIC + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/src ) @@ -59,6 +96,7 @@ target_link_libraries(libs-apache-arrow PUBLIC contrib-restricted-fast_float contrib-restricted-thrift contrib-restricted-uriparser + contrib-libs-flatbuffers ) target_sources(libs-apache-arrow PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/arrow/adapters/orc/adapter.cc @@ -261,4 +299,58 @@ target_sources(libs-apache-arrow PRIVATE ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/parquet/stream_reader.cc ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/parquet/stream_writer.cc ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/parquet/types.cc + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/File.fbs.cpp + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Message.fbs.cpp + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Schema.fbs.cpp + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/SparseTensor.fbs.cpp + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Tensor.fbs.cpp + ${CMAKE_BINARY_DIR}/contrib/libs/apache/arrow/cpp/src/generated/feather.fbs.cpp +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/File.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Message.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Schema.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/SparseTensor.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/Tensor.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} +) +target_fbs_source(libs-apache-arrow + PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/apache/arrow/cpp/src/generated/feather.fbs + -I + ${CMAKE_BINARY_DIR} + -I + ${CMAKE_SOURCE_DIR} ) diff --git a/contrib/libs/apache/arrow/cpp/src/arrow/ipc/feather.cc b/contrib/libs/apache/arrow/cpp/src/arrow/ipc/feather.cc index b1c30eec0b..ff7726ae4b 100644 --- a/contrib/libs/apache/arrow/cpp/src/arrow/ipc/feather.cc +++ b/contrib/libs/apache/arrow/cpp/src/arrow/ipc/feather.cc @@ -49,7 +49,7 @@ #include "arrow/util/make_unique.h" #include "arrow/visitor_inline.h" -#include "generated/feather_generated.h" +#include "generated/feather.fbs.h" namespace arrow { @@ -207,8 +207,8 @@ class ReaderV1 : public Reader { TimeUnit::type unit = FromFlatbufferEnum(meta->unit()); std::string tz; // flatbuffer non-null - if (meta->timezone() != 0) { - tz = meta->timezone()->str(); + if (meta->time_zone() != 0) { + tz = meta->time_zone()->str(); } else { tz = ""; } diff --git a/contrib/libs/apache/arrow/cpp/src/arrow/ipc/message.cc b/contrib/libs/apache/arrow/cpp/src/arrow/ipc/message.cc index 197556efce..dd269a0dc0 100644 --- a/contrib/libs/apache/arrow/cpp/src/arrow/ipc/message.cc +++ b/contrib/libs/apache/arrow/cpp/src/arrow/ipc/message.cc @@ -37,7 +37,7 @@ #include "arrow/util/logging.h" #include "arrow/util/ubsan.h" -#include "generated/Message_generated.h" +#include "generated/Message.fbs.h" namespace arrow { diff --git a/contrib/libs/apache/arrow/cpp/src/arrow/ipc/metadata_internal.cc b/contrib/libs/apache/arrow/cpp/src/arrow/ipc/metadata_internal.cc index 4b332bd9e1..ad46cdc58f 100644 --- a/contrib/libs/apache/arrow/cpp/src/arrow/ipc/metadata_internal.cc +++ b/contrib/libs/apache/arrow/cpp/src/arrow/ipc/metadata_internal.cc @@ -41,11 +41,11 @@ #include "arrow/util/ubsan.h" #include "arrow/visitor_inline.h" -#include "generated/File_generated.h" -#include "generated/Message_generated.h" -#include "generated/Schema_generated.h" -#include "generated/SparseTensor_generated.h" -#include "generated/Tensor_generated.h" +#include "generated/File.fbs.h" +#include "generated/Message.fbs.h" +#include "generated/Schema.fbs.h" +#include "generated/SparseTensor.fbs.h" +#include "generated/Tensor.fbs.h" namespace arrow { @@ -312,7 +312,7 @@ Status ConcreteTypeFromFlatbuffer(flatbuf::Type type, const void* type_data, case flatbuf::Type::Timestamp: { auto ts_type = static_cast<const flatbuf::Timestamp*>(type_data); TimeUnit::type unit = FromFlatbufferUnit(ts_type->unit()); - *out = timestamp(unit, StringFromFlatbuffers(ts_type->timezone())); + *out = timestamp(unit, StringFromFlatbuffers(ts_type->time_zone())); return Status::OK(); } case flatbuf::Type::Duration: { diff --git a/contrib/libs/apache/arrow/cpp/src/arrow/ipc/metadata_internal.h b/contrib/libs/apache/arrow/cpp/src/arrow/ipc/metadata_internal.h index 9cf489dd66..9cc24a5d5b 100644 --- a/contrib/libs/apache/arrow/cpp/src/arrow/ipc/metadata_internal.h +++ b/contrib/libs/apache/arrow/cpp/src/arrow/ipc/metadata_internal.h @@ -38,9 +38,9 @@ #include "arrow/util/macros.h" #include "arrow/util/visibility.h" -#include "generated/Message_generated.h" -#include "generated/Schema_generated.h" -#include "generated/SparseTensor_generated.h" // IWYU pragma: keep +#include "generated/Message.fbs.h" +#include "generated/Schema.fbs.h" +#include "generated/SparseTensor.fbs.h" // IWYU pragma: keep namespace arrow { diff --git a/contrib/libs/apache/arrow/cpp/src/arrow/ipc/reader.cc b/contrib/libs/apache/arrow/cpp/src/arrow/ipc/reader.cc index a3c345cc44..eb62a83f04 100644 --- a/contrib/libs/apache/arrow/cpp/src/arrow/ipc/reader.cc +++ b/contrib/libs/apache/arrow/cpp/src/arrow/ipc/reader.cc @@ -57,10 +57,10 @@ #include "arrow/util/vector.h" #include "arrow/visitor_inline.h" -#include "generated/File_generated.h" // IWYU pragma: export -#include "generated/Message_generated.h" -#include "generated/Schema_generated.h" -#include "generated/SparseTensor_generated.h" +#include "generated/File.fbs.h" // IWYU pragma: export +#include "generated/Message.fbs.h" +#include "generated/Schema.fbs.h" +#include "generated/SparseTensor.fbs.h" namespace arrow { diff --git a/contrib/libs/apache/arrow/cpp/src/generated/File.fbs b/contrib/libs/apache/arrow/cpp/src/generated/File.fbs new file mode 100644 index 0000000000..906d494f27 --- /dev/null +++ b/contrib/libs/apache/arrow/cpp/src/generated/File.fbs @@ -0,0 +1,52 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +include "Schema.fbs"; + +namespace org.apache.arrow.flatbuf; + +/// ---------------------------------------------------------------------- +/// Arrow File metadata +/// + +table Footer { + version: org.apache.arrow.flatbuf.MetadataVersion; + + schema: org.apache.arrow.flatbuf.Schema; + + dictionaries: [ Block ]; + + recordBatches: [ Block ]; + + /// User-defined metadata + custom_metadata: [ KeyValue ]; +} + +struct Block { + + /// Index to the start of the RecordBlock (note this is past the Message header) + offset: long; + + /// Length of the metadata + metaDataLength: int; + + /// Length of the data (this is aligned so there can be a gap between this and + /// the metadata). + bodyLength: long; +} + +root_type Footer; diff --git a/contrib/libs/apache/arrow/cpp/src/generated/File_generated.h b/contrib/libs/apache/arrow/cpp/src/generated/File_generated.h deleted file mode 100644 index 06953c4a04..0000000000 --- a/contrib/libs/apache/arrow/cpp/src/generated/File_generated.h +++ /dev/null @@ -1,200 +0,0 @@ -// automatically generated by the FlatBuffers compiler, do not modify - - -#ifndef FLATBUFFERS_GENERATED_FILE_ORG_APACHE_ARROW_FLATBUF_H_ -#define FLATBUFFERS_GENERATED_FILE_ORG_APACHE_ARROW_FLATBUF_H_ - -#include "flatbuffers/flatbuffers.h" - -#include "Schema_generated.h" - -namespace org { -namespace apache { -namespace arrow { -namespace flatbuf { - -struct Footer; -struct FooterBuilder; - -struct Block; - -FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) Block FLATBUFFERS_FINAL_CLASS { - private: - int64_t offset_; - int32_t metaDataLength_; - int32_t padding0__; - int64_t bodyLength_; - - public: - Block() { - memset(static_cast<void *>(this), 0, sizeof(Block)); - } - Block(int64_t _offset, int32_t _metaDataLength, int64_t _bodyLength) - : offset_(flatbuffers::EndianScalar(_offset)), - metaDataLength_(flatbuffers::EndianScalar(_metaDataLength)), - padding0__(0), - bodyLength_(flatbuffers::EndianScalar(_bodyLength)) { - (void)padding0__; - } - /// Index to the start of the RecordBlock (note this is past the Message header) - int64_t offset() const { - return flatbuffers::EndianScalar(offset_); - } - /// Length of the metadata - int32_t metaDataLength() const { - return flatbuffers::EndianScalar(metaDataLength_); - } - /// Length of the data (this is aligned so there can be a gap between this and - /// the metadata). - int64_t bodyLength() const { - return flatbuffers::EndianScalar(bodyLength_); - } -}; -FLATBUFFERS_STRUCT_END(Block, 24); - -/// ---------------------------------------------------------------------- -/// Arrow File metadata -/// -struct Footer FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef FooterBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_VERSION = 4, - VT_SCHEMA = 6, - VT_DICTIONARIES = 8, - VT_RECORDBATCHES = 10, - VT_CUSTOM_METADATA = 12 - }; - org::apache::arrow::flatbuf::MetadataVersion version() const { - return static_cast<org::apache::arrow::flatbuf::MetadataVersion>(GetField<int16_t>(VT_VERSION, 0)); - } - const org::apache::arrow::flatbuf::Schema *schema() const { - return GetPointer<const org::apache::arrow::flatbuf::Schema *>(VT_SCHEMA); - } - const flatbuffers::Vector<const org::apache::arrow::flatbuf::Block *> *dictionaries() const { - return GetPointer<const flatbuffers::Vector<const org::apache::arrow::flatbuf::Block *> *>(VT_DICTIONARIES); - } - const flatbuffers::Vector<const org::apache::arrow::flatbuf::Block *> *recordBatches() const { - return GetPointer<const flatbuffers::Vector<const org::apache::arrow::flatbuf::Block *> *>(VT_RECORDBATCHES); - } - /// User-defined metadata - const flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>> *custom_metadata() const { - return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>> *>(VT_CUSTOM_METADATA); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int16_t>(verifier, VT_VERSION) && - VerifyOffset(verifier, VT_SCHEMA) && - verifier.VerifyTable(schema()) && - VerifyOffset(verifier, VT_DICTIONARIES) && - verifier.VerifyVector(dictionaries()) && - VerifyOffset(verifier, VT_RECORDBATCHES) && - verifier.VerifyVector(recordBatches()) && - VerifyOffset(verifier, VT_CUSTOM_METADATA) && - verifier.VerifyVector(custom_metadata()) && - verifier.VerifyVectorOfTables(custom_metadata()) && - verifier.EndTable(); - } -}; - -struct FooterBuilder { - typedef Footer Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_version(org::apache::arrow::flatbuf::MetadataVersion version) { - fbb_.AddElement<int16_t>(Footer::VT_VERSION, static_cast<int16_t>(version), 0); - } - void add_schema(flatbuffers::Offset<org::apache::arrow::flatbuf::Schema> schema) { - fbb_.AddOffset(Footer::VT_SCHEMA, schema); - } - void add_dictionaries(flatbuffers::Offset<flatbuffers::Vector<const org::apache::arrow::flatbuf::Block *>> dictionaries) { - fbb_.AddOffset(Footer::VT_DICTIONARIES, dictionaries); - } - void add_recordBatches(flatbuffers::Offset<flatbuffers::Vector<const org::apache::arrow::flatbuf::Block *>> recordBatches) { - fbb_.AddOffset(Footer::VT_RECORDBATCHES, recordBatches); - } - void add_custom_metadata(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>>> custom_metadata) { - fbb_.AddOffset(Footer::VT_CUSTOM_METADATA, custom_metadata); - } - explicit FooterBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - FooterBuilder &operator=(const FooterBuilder &); - flatbuffers::Offset<Footer> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<Footer>(end); - return o; - } -}; - -inline flatbuffers::Offset<Footer> CreateFooter( - flatbuffers::FlatBufferBuilder &_fbb, - org::apache::arrow::flatbuf::MetadataVersion version = org::apache::arrow::flatbuf::MetadataVersion::V1, - flatbuffers::Offset<org::apache::arrow::flatbuf::Schema> schema = 0, - flatbuffers::Offset<flatbuffers::Vector<const org::apache::arrow::flatbuf::Block *>> dictionaries = 0, - flatbuffers::Offset<flatbuffers::Vector<const org::apache::arrow::flatbuf::Block *>> recordBatches = 0, - flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>>> custom_metadata = 0) { - FooterBuilder builder_(_fbb); - builder_.add_custom_metadata(custom_metadata); - builder_.add_recordBatches(recordBatches); - builder_.add_dictionaries(dictionaries); - builder_.add_schema(schema); - builder_.add_version(version); - return builder_.Finish(); -} - -inline flatbuffers::Offset<Footer> CreateFooterDirect( - flatbuffers::FlatBufferBuilder &_fbb, - org::apache::arrow::flatbuf::MetadataVersion version = org::apache::arrow::flatbuf::MetadataVersion::V1, - flatbuffers::Offset<org::apache::arrow::flatbuf::Schema> schema = 0, - const std::vector<org::apache::arrow::flatbuf::Block> *dictionaries = nullptr, - const std::vector<org::apache::arrow::flatbuf::Block> *recordBatches = nullptr, - const std::vector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>> *custom_metadata = nullptr) { - auto dictionaries__ = dictionaries ? _fbb.CreateVectorOfStructs<org::apache::arrow::flatbuf::Block>(*dictionaries) : 0; - auto recordBatches__ = recordBatches ? _fbb.CreateVectorOfStructs<org::apache::arrow::flatbuf::Block>(*recordBatches) : 0; - auto custom_metadata__ = custom_metadata ? _fbb.CreateVector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>>(*custom_metadata) : 0; - return org::apache::arrow::flatbuf::CreateFooter( - _fbb, - version, - schema, - dictionaries__, - recordBatches__, - custom_metadata__); -} - -inline const org::apache::arrow::flatbuf::Footer *GetFooter(const void *buf) { - return flatbuffers::GetRoot<org::apache::arrow::flatbuf::Footer>(buf); -} - -inline const org::apache::arrow::flatbuf::Footer *GetSizePrefixedFooter(const void *buf) { - return flatbuffers::GetSizePrefixedRoot<org::apache::arrow::flatbuf::Footer>(buf); -} - -inline bool VerifyFooterBuffer( - flatbuffers::Verifier &verifier) { - return verifier.VerifyBuffer<org::apache::arrow::flatbuf::Footer>(nullptr); -} - -inline bool VerifySizePrefixedFooterBuffer( - flatbuffers::Verifier &verifier) { - return verifier.VerifySizePrefixedBuffer<org::apache::arrow::flatbuf::Footer>(nullptr); -} - -inline void FinishFooterBuffer( - flatbuffers::FlatBufferBuilder &fbb, - flatbuffers::Offset<org::apache::arrow::flatbuf::Footer> root) { - fbb.Finish(root); -} - -inline void FinishSizePrefixedFooterBuffer( - flatbuffers::FlatBufferBuilder &fbb, - flatbuffers::Offset<org::apache::arrow::flatbuf::Footer> root) { - fbb.FinishSizePrefixed(root); -} - -} // namespace flatbuf -} // namespace arrow -} // namespace apache -} // namespace org - -#endif // FLATBUFFERS_GENERATED_FILE_ORG_APACHE_ARROW_FLATBUF_H_ diff --git a/contrib/libs/apache/arrow/cpp/src/generated/Message.fbs b/contrib/libs/apache/arrow/cpp/src/generated/Message.fbs new file mode 100644 index 0000000000..f1c18d765d --- /dev/null +++ b/contrib/libs/apache/arrow/cpp/src/generated/Message.fbs @@ -0,0 +1,140 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +include "Schema.fbs"; +include "SparseTensor.fbs"; +include "Tensor.fbs"; + +namespace org.apache.arrow.flatbuf; + +/// ---------------------------------------------------------------------- +/// Data structures for describing a table row batch (a collection of +/// equal-length Arrow arrays) + +/// Metadata about a field at some level of a nested type tree (but not +/// its children). +/// +/// For example, a List<Int16> with values `[[1, 2, 3], null, [4], [5, 6], null]` +/// would have {length: 5, null_count: 2} for its List node, and {length: 6, +/// null_count: 0} for its Int16 node, as separate FieldNode structs +struct FieldNode { + /// The number of value slots in the Arrow array at this level of a nested + /// tree + length: long; + + /// The number of observed nulls. Fields with null_count == 0 may choose not + /// to write their physical validity bitmap out as a materialized buffer, + /// instead setting the length of the bitmap buffer to 0. + null_count: long; +} + +enum CompressionType:byte { + // LZ4 frame format, for portability, as provided by lz4frame.h or wrappers + // thereof. Not to be confused with "raw" (also called "block") format + // provided by lz4.h + LZ4_FRAME, + + // Zstandard + ZSTD +} + +/// Provided for forward compatibility in case we need to support different +/// strategies for compressing the IPC message body (like whole-body +/// compression rather than buffer-level) in the future +enum BodyCompressionMethod:byte { + /// Each constituent buffer is first compressed with the indicated + /// compressor, and then written with the uncompressed length in the first 8 + /// bytes as a 64-bit little-endian signed integer followed by the compressed + /// buffer bytes (and then padding as required by the protocol). The + /// uncompressed length may be set to -1 to indicate that the data that + /// follows is not compressed, which can be useful for cases where + /// compression does not yield appreciable savings. + BUFFER +} + +/// Optional compression for the memory buffers constituting IPC message +/// bodies. Intended for use with RecordBatch but could be used for other +/// message types +table BodyCompression { + /// Compressor library + codec: CompressionType = LZ4_FRAME; + + /// Indicates the way the record batch body was compressed + method: BodyCompressionMethod = BUFFER; +} + +/// A data header describing the shared memory layout of a "record" or "row" +/// batch. Some systems call this a "row batch" internally and others a "record +/// batch". +table RecordBatch { + /// number of records / rows. The arrays in the batch should all have this + /// length + length: long; + + /// Nodes correspond to the pre-ordered flattened logical schema + nodes: [FieldNode]; + + /// Buffers correspond to the pre-ordered flattened buffer tree + /// + /// The number of buffers appended to this list depends on the schema. For + /// example, most primitive arrays will have 2 buffers, 1 for the validity + /// bitmap and 1 for the values. For struct arrays, there will only be a + /// single buffer for the validity (nulls) bitmap + buffers: [Buffer]; + + /// Optional compression of the message body + compression: BodyCompression; +} + +/// For sending dictionary encoding information. Any Field can be +/// dictionary-encoded, but in this case none of its children may be +/// dictionary-encoded. +/// There is one vector / column per dictionary, but that vector / column +/// may be spread across multiple dictionary batches by using the isDelta +/// flag + +table DictionaryBatch { + id: long; + data: RecordBatch; + + /// If isDelta is true the values in the dictionary are to be appended to a + /// dictionary with the indicated id. If isDelta is false this dictionary + /// should replace the existing dictionary. + isDelta: bool = false; +} + +/// ---------------------------------------------------------------------- +/// The root Message type + +/// This union enables us to easily send different message types without +/// redundant storage, and in the future we can easily add new message types. +/// +/// Arrow implementations do not need to implement all of the message types, +/// which may include experimental metadata types. For maximum compatibility, +/// it is best to send data using RecordBatch +union MessageHeader { + Schema, DictionaryBatch, RecordBatch, Tensor, SparseTensor +} + +table Message { + version: org.apache.arrow.flatbuf.MetadataVersion; + header: MessageHeader; + bodyLength: long; + custom_metadata: [ KeyValue ]; +} + +root_type Message; diff --git a/contrib/libs/apache/arrow/cpp/src/generated/Message_generated.h b/contrib/libs/apache/arrow/cpp/src/generated/Message_generated.h deleted file mode 100644 index 822bec9952..0000000000 --- a/contrib/libs/apache/arrow/cpp/src/generated/Message_generated.h +++ /dev/null @@ -1,659 +0,0 @@ -// automatically generated by the FlatBuffers compiler, do not modify - - -#ifndef FLATBUFFERS_GENERATED_MESSAGE_ORG_APACHE_ARROW_FLATBUF_H_ -#define FLATBUFFERS_GENERATED_MESSAGE_ORG_APACHE_ARROW_FLATBUF_H_ - -#include "flatbuffers/flatbuffers.h" - -#include "Schema_generated.h" -#include "SparseTensor_generated.h" -#include "Tensor_generated.h" - -namespace org { -namespace apache { -namespace arrow { -namespace flatbuf { - -struct FieldNode; - -struct BodyCompression; -struct BodyCompressionBuilder; - -struct RecordBatch; -struct RecordBatchBuilder; - -struct DictionaryBatch; -struct DictionaryBatchBuilder; - -struct Message; -struct MessageBuilder; - -enum class CompressionType : int8_t { - LZ4_FRAME = 0, - ZSTD = 1, - MIN = LZ4_FRAME, - MAX = ZSTD -}; - -inline const CompressionType (&EnumValuesCompressionType())[2] { - static const CompressionType values[] = { - CompressionType::LZ4_FRAME, - CompressionType::ZSTD - }; - return values; -} - -inline const char * const *EnumNamesCompressionType() { - static const char * const names[3] = { - "LZ4_FRAME", - "ZSTD", - nullptr - }; - return names; -} - -inline const char *EnumNameCompressionType(CompressionType e) { - if (flatbuffers::IsOutRange(e, CompressionType::LZ4_FRAME, CompressionType::ZSTD)) return ""; - const size_t index = static_cast<size_t>(e); - return EnumNamesCompressionType()[index]; -} - -/// Provided for forward compatibility in case we need to support different -/// strategies for compressing the IPC message body (like whole-body -/// compression rather than buffer-level) in the future -enum class BodyCompressionMethod : int8_t { - /// Each constituent buffer is first compressed with the indicated - /// compressor, and then written with the uncompressed length in the first 8 - /// bytes as a 64-bit little-endian signed integer followed by the compressed - /// buffer bytes (and then padding as required by the protocol). The - /// uncompressed length may be set to -1 to indicate that the data that - /// follows is not compressed, which can be useful for cases where - /// compression does not yield appreciable savings. - BUFFER = 0, - MIN = BUFFER, - MAX = BUFFER -}; - -inline const BodyCompressionMethod (&EnumValuesBodyCompressionMethod())[1] { - static const BodyCompressionMethod values[] = { - BodyCompressionMethod::BUFFER - }; - return values; -} - -inline const char * const *EnumNamesBodyCompressionMethod() { - static const char * const names[2] = { - "BUFFER", - nullptr - }; - return names; -} - -inline const char *EnumNameBodyCompressionMethod(BodyCompressionMethod e) { - if (flatbuffers::IsOutRange(e, BodyCompressionMethod::BUFFER, BodyCompressionMethod::BUFFER)) return ""; - const size_t index = static_cast<size_t>(e); - return EnumNamesBodyCompressionMethod()[index]; -} - -/// ---------------------------------------------------------------------- -/// The root Message type -/// This union enables us to easily send different message types without -/// redundant storage, and in the future we can easily add new message types. -/// -/// Arrow implementations do not need to implement all of the message types, -/// which may include experimental metadata types. For maximum compatibility, -/// it is best to send data using RecordBatch -enum class MessageHeader : uint8_t { - NONE = 0, - Schema = 1, - DictionaryBatch = 2, - RecordBatch = 3, - Tensor = 4, - SparseTensor = 5, - MIN = NONE, - MAX = SparseTensor -}; - -inline const MessageHeader (&EnumValuesMessageHeader())[6] { - static const MessageHeader values[] = { - MessageHeader::NONE, - MessageHeader::Schema, - MessageHeader::DictionaryBatch, - MessageHeader::RecordBatch, - MessageHeader::Tensor, - MessageHeader::SparseTensor - }; - return values; -} - -inline const char * const *EnumNamesMessageHeader() { - static const char * const names[7] = { - "NONE", - "Schema", - "DictionaryBatch", - "RecordBatch", - "Tensor", - "SparseTensor", - nullptr - }; - return names; -} - -inline const char *EnumNameMessageHeader(MessageHeader e) { - if (flatbuffers::IsOutRange(e, MessageHeader::NONE, MessageHeader::SparseTensor)) return ""; - const size_t index = static_cast<size_t>(e); - return EnumNamesMessageHeader()[index]; -} - -template<typename T> struct MessageHeaderTraits { - static const MessageHeader enum_value = MessageHeader::NONE; -}; - -template<> struct MessageHeaderTraits<org::apache::arrow::flatbuf::Schema> { - static const MessageHeader enum_value = MessageHeader::Schema; -}; - -template<> struct MessageHeaderTraits<org::apache::arrow::flatbuf::DictionaryBatch> { - static const MessageHeader enum_value = MessageHeader::DictionaryBatch; -}; - -template<> struct MessageHeaderTraits<org::apache::arrow::flatbuf::RecordBatch> { - static const MessageHeader enum_value = MessageHeader::RecordBatch; -}; - -template<> struct MessageHeaderTraits<org::apache::arrow::flatbuf::Tensor> { - static const MessageHeader enum_value = MessageHeader::Tensor; -}; - -template<> struct MessageHeaderTraits<org::apache::arrow::flatbuf::SparseTensor> { - static const MessageHeader enum_value = MessageHeader::SparseTensor; -}; - -bool VerifyMessageHeader(flatbuffers::Verifier &verifier, const void *obj, MessageHeader type); -bool VerifyMessageHeaderVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types); - -/// ---------------------------------------------------------------------- -/// Data structures for describing a table row batch (a collection of -/// equal-length Arrow arrays) -/// Metadata about a field at some level of a nested type tree (but not -/// its children). -/// -/// For example, a List<Int16> with values [[1, 2, 3], null, [4], [5, 6], null] -/// would have {length: 5, null_count: 2} for its List node, and {length: 6, -/// null_count: 0} for its Int16 node, as separate FieldNode structs -FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) FieldNode FLATBUFFERS_FINAL_CLASS { - private: - int64_t length_; - int64_t null_count_; - - public: - FieldNode() { - memset(static_cast<void *>(this), 0, sizeof(FieldNode)); - } - FieldNode(int64_t _length, int64_t _null_count) - : length_(flatbuffers::EndianScalar(_length)), - null_count_(flatbuffers::EndianScalar(_null_count)) { - } - /// The number of value slots in the Arrow array at this level of a nested - /// tree - int64_t length() const { - return flatbuffers::EndianScalar(length_); - } - /// The number of observed nulls. Fields with null_count == 0 may choose not - /// to write their physical validity bitmap out as a materialized buffer, - /// instead setting the length of the bitmap buffer to 0. - int64_t null_count() const { - return flatbuffers::EndianScalar(null_count_); - } -}; -FLATBUFFERS_STRUCT_END(FieldNode, 16); - -/// Optional compression for the memory buffers constituting IPC message -/// bodies. Intended for use with RecordBatch but could be used for other -/// message types -struct BodyCompression FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef BodyCompressionBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_CODEC = 4, - VT_METHOD = 6 - }; - /// Compressor library - org::apache::arrow::flatbuf::CompressionType codec() const { - return static_cast<org::apache::arrow::flatbuf::CompressionType>(GetField<int8_t>(VT_CODEC, 0)); - } - /// Indicates the way the record batch body was compressed - org::apache::arrow::flatbuf::BodyCompressionMethod method() const { - return static_cast<org::apache::arrow::flatbuf::BodyCompressionMethod>(GetField<int8_t>(VT_METHOD, 0)); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int8_t>(verifier, VT_CODEC) && - VerifyField<int8_t>(verifier, VT_METHOD) && - verifier.EndTable(); - } -}; - -struct BodyCompressionBuilder { - typedef BodyCompression Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_codec(org::apache::arrow::flatbuf::CompressionType codec) { - fbb_.AddElement<int8_t>(BodyCompression::VT_CODEC, static_cast<int8_t>(codec), 0); - } - void add_method(org::apache::arrow::flatbuf::BodyCompressionMethod method) { - fbb_.AddElement<int8_t>(BodyCompression::VT_METHOD, static_cast<int8_t>(method), 0); - } - explicit BodyCompressionBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - BodyCompressionBuilder &operator=(const BodyCompressionBuilder &); - flatbuffers::Offset<BodyCompression> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<BodyCompression>(end); - return o; - } -}; - -inline flatbuffers::Offset<BodyCompression> CreateBodyCompression( - flatbuffers::FlatBufferBuilder &_fbb, - org::apache::arrow::flatbuf::CompressionType codec = org::apache::arrow::flatbuf::CompressionType::LZ4_FRAME, - org::apache::arrow::flatbuf::BodyCompressionMethod method = org::apache::arrow::flatbuf::BodyCompressionMethod::BUFFER) { - BodyCompressionBuilder builder_(_fbb); - builder_.add_method(method); - builder_.add_codec(codec); - return builder_.Finish(); -} - -/// A data header describing the shared memory layout of a "record" or "row" -/// batch. Some systems call this a "row batch" internally and others a "record -/// batch". -struct RecordBatch FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef RecordBatchBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_LENGTH = 4, - VT_NODES = 6, - VT_BUFFERS = 8, - VT_COMPRESSION = 10 - }; - /// number of records / rows. The arrays in the batch should all have this - /// length - int64_t length() const { - return GetField<int64_t>(VT_LENGTH, 0); - } - /// Nodes correspond to the pre-ordered flattened logical schema - const flatbuffers::Vector<const org::apache::arrow::flatbuf::FieldNode *> *nodes() const { - return GetPointer<const flatbuffers::Vector<const org::apache::arrow::flatbuf::FieldNode *> *>(VT_NODES); - } - /// Buffers correspond to the pre-ordered flattened buffer tree - /// - /// The number of buffers appended to this list depends on the schema. For - /// example, most primitive arrays will have 2 buffers, 1 for the validity - /// bitmap and 1 for the values. For struct arrays, there will only be a - /// single buffer for the validity (nulls) bitmap - const flatbuffers::Vector<const org::apache::arrow::flatbuf::Buffer *> *buffers() const { - return GetPointer<const flatbuffers::Vector<const org::apache::arrow::flatbuf::Buffer *> *>(VT_BUFFERS); - } - /// Optional compression of the message body - const org::apache::arrow::flatbuf::BodyCompression *compression() const { - return GetPointer<const org::apache::arrow::flatbuf::BodyCompression *>(VT_COMPRESSION); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int64_t>(verifier, VT_LENGTH) && - VerifyOffset(verifier, VT_NODES) && - verifier.VerifyVector(nodes()) && - VerifyOffset(verifier, VT_BUFFERS) && - verifier.VerifyVector(buffers()) && - VerifyOffset(verifier, VT_COMPRESSION) && - verifier.VerifyTable(compression()) && - verifier.EndTable(); - } -}; - -struct RecordBatchBuilder { - typedef RecordBatch Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_length(int64_t length) { - fbb_.AddElement<int64_t>(RecordBatch::VT_LENGTH, length, 0); - } - void add_nodes(flatbuffers::Offset<flatbuffers::Vector<const org::apache::arrow::flatbuf::FieldNode *>> nodes) { - fbb_.AddOffset(RecordBatch::VT_NODES, nodes); - } - void add_buffers(flatbuffers::Offset<flatbuffers::Vector<const org::apache::arrow::flatbuf::Buffer *>> buffers) { - fbb_.AddOffset(RecordBatch::VT_BUFFERS, buffers); - } - void add_compression(flatbuffers::Offset<org::apache::arrow::flatbuf::BodyCompression> compression) { - fbb_.AddOffset(RecordBatch::VT_COMPRESSION, compression); - } - explicit RecordBatchBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - RecordBatchBuilder &operator=(const RecordBatchBuilder &); - flatbuffers::Offset<RecordBatch> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<RecordBatch>(end); - return o; - } -}; - -inline flatbuffers::Offset<RecordBatch> CreateRecordBatch( - flatbuffers::FlatBufferBuilder &_fbb, - int64_t length = 0, - flatbuffers::Offset<flatbuffers::Vector<const org::apache::arrow::flatbuf::FieldNode *>> nodes = 0, - flatbuffers::Offset<flatbuffers::Vector<const org::apache::arrow::flatbuf::Buffer *>> buffers = 0, - flatbuffers::Offset<org::apache::arrow::flatbuf::BodyCompression> compression = 0) { - RecordBatchBuilder builder_(_fbb); - builder_.add_length(length); - builder_.add_compression(compression); - builder_.add_buffers(buffers); - builder_.add_nodes(nodes); - return builder_.Finish(); -} - -inline flatbuffers::Offset<RecordBatch> CreateRecordBatchDirect( - flatbuffers::FlatBufferBuilder &_fbb, - int64_t length = 0, - const std::vector<org::apache::arrow::flatbuf::FieldNode> *nodes = nullptr, - const std::vector<org::apache::arrow::flatbuf::Buffer> *buffers = nullptr, - flatbuffers::Offset<org::apache::arrow::flatbuf::BodyCompression> compression = 0) { - auto nodes__ = nodes ? _fbb.CreateVectorOfStructs<org::apache::arrow::flatbuf::FieldNode>(*nodes) : 0; - auto buffers__ = buffers ? _fbb.CreateVectorOfStructs<org::apache::arrow::flatbuf::Buffer>(*buffers) : 0; - return org::apache::arrow::flatbuf::CreateRecordBatch( - _fbb, - length, - nodes__, - buffers__, - compression); -} - -/// For sending dictionary encoding information. Any Field can be -/// dictionary-encoded, but in this case none of its children may be -/// dictionary-encoded. -/// There is one vector / column per dictionary, but that vector / column -/// may be spread across multiple dictionary batches by using the isDelta -/// flag -struct DictionaryBatch FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef DictionaryBatchBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_ID = 4, - VT_DATA = 6, - VT_ISDELTA = 8 - }; - int64_t id() const { - return GetField<int64_t>(VT_ID, 0); - } - const org::apache::arrow::flatbuf::RecordBatch *data() const { - return GetPointer<const org::apache::arrow::flatbuf::RecordBatch *>(VT_DATA); - } - /// If isDelta is true the values in the dictionary are to be appended to a - /// dictionary with the indicated id. If isDelta is false this dictionary - /// should replace the existing dictionary. - bool isDelta() const { - return GetField<uint8_t>(VT_ISDELTA, 0) != 0; - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int64_t>(verifier, VT_ID) && - VerifyOffset(verifier, VT_DATA) && - verifier.VerifyTable(data()) && - VerifyField<uint8_t>(verifier, VT_ISDELTA) && - verifier.EndTable(); - } -}; - -struct DictionaryBatchBuilder { - typedef DictionaryBatch Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_id(int64_t id) { - fbb_.AddElement<int64_t>(DictionaryBatch::VT_ID, id, 0); - } - void add_data(flatbuffers::Offset<org::apache::arrow::flatbuf::RecordBatch> data) { - fbb_.AddOffset(DictionaryBatch::VT_DATA, data); - } - void add_isDelta(bool isDelta) { - fbb_.AddElement<uint8_t>(DictionaryBatch::VT_ISDELTA, static_cast<uint8_t>(isDelta), 0); - } - explicit DictionaryBatchBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - DictionaryBatchBuilder &operator=(const DictionaryBatchBuilder &); - flatbuffers::Offset<DictionaryBatch> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<DictionaryBatch>(end); - return o; - } -}; - -inline flatbuffers::Offset<DictionaryBatch> CreateDictionaryBatch( - flatbuffers::FlatBufferBuilder &_fbb, - int64_t id = 0, - flatbuffers::Offset<org::apache::arrow::flatbuf::RecordBatch> data = 0, - bool isDelta = false) { - DictionaryBatchBuilder builder_(_fbb); - builder_.add_id(id); - builder_.add_data(data); - builder_.add_isDelta(isDelta); - return builder_.Finish(); -} - -struct Message FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef MessageBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_VERSION = 4, - VT_HEADER_TYPE = 6, - VT_HEADER = 8, - VT_BODYLENGTH = 10, - VT_CUSTOM_METADATA = 12 - }; - org::apache::arrow::flatbuf::MetadataVersion version() const { - return static_cast<org::apache::arrow::flatbuf::MetadataVersion>(GetField<int16_t>(VT_VERSION, 0)); - } - org::apache::arrow::flatbuf::MessageHeader header_type() const { - return static_cast<org::apache::arrow::flatbuf::MessageHeader>(GetField<uint8_t>(VT_HEADER_TYPE, 0)); - } - const void *header() const { - return GetPointer<const void *>(VT_HEADER); - } - template<typename T> const T *header_as() const; - const org::apache::arrow::flatbuf::Schema *header_as_Schema() const { - return header_type() == org::apache::arrow::flatbuf::MessageHeader::Schema ? static_cast<const org::apache::arrow::flatbuf::Schema *>(header()) : nullptr; - } - const org::apache::arrow::flatbuf::DictionaryBatch *header_as_DictionaryBatch() const { - return header_type() == org::apache::arrow::flatbuf::MessageHeader::DictionaryBatch ? static_cast<const org::apache::arrow::flatbuf::DictionaryBatch *>(header()) : nullptr; - } - const org::apache::arrow::flatbuf::RecordBatch *header_as_RecordBatch() const { - return header_type() == org::apache::arrow::flatbuf::MessageHeader::RecordBatch ? static_cast<const org::apache::arrow::flatbuf::RecordBatch *>(header()) : nullptr; - } - const org::apache::arrow::flatbuf::Tensor *header_as_Tensor() const { - return header_type() == org::apache::arrow::flatbuf::MessageHeader::Tensor ? static_cast<const org::apache::arrow::flatbuf::Tensor *>(header()) : nullptr; - } - const org::apache::arrow::flatbuf::SparseTensor *header_as_SparseTensor() const { - return header_type() == org::apache::arrow::flatbuf::MessageHeader::SparseTensor ? static_cast<const org::apache::arrow::flatbuf::SparseTensor *>(header()) : nullptr; - } - int64_t bodyLength() const { - return GetField<int64_t>(VT_BODYLENGTH, 0); - } - const flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>> *custom_metadata() const { - return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>> *>(VT_CUSTOM_METADATA); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int16_t>(verifier, VT_VERSION) && - VerifyField<uint8_t>(verifier, VT_HEADER_TYPE) && - VerifyOffset(verifier, VT_HEADER) && - VerifyMessageHeader(verifier, header(), header_type()) && - VerifyField<int64_t>(verifier, VT_BODYLENGTH) && - VerifyOffset(verifier, VT_CUSTOM_METADATA) && - verifier.VerifyVector(custom_metadata()) && - verifier.VerifyVectorOfTables(custom_metadata()) && - verifier.EndTable(); - } -}; - -template<> inline const org::apache::arrow::flatbuf::Schema *Message::header_as<org::apache::arrow::flatbuf::Schema>() const { - return header_as_Schema(); -} - -template<> inline const org::apache::arrow::flatbuf::DictionaryBatch *Message::header_as<org::apache::arrow::flatbuf::DictionaryBatch>() const { - return header_as_DictionaryBatch(); -} - -template<> inline const org::apache::arrow::flatbuf::RecordBatch *Message::header_as<org::apache::arrow::flatbuf::RecordBatch>() const { - return header_as_RecordBatch(); -} - -template<> inline const org::apache::arrow::flatbuf::Tensor *Message::header_as<org::apache::arrow::flatbuf::Tensor>() const { - return header_as_Tensor(); -} - -template<> inline const org::apache::arrow::flatbuf::SparseTensor *Message::header_as<org::apache::arrow::flatbuf::SparseTensor>() const { - return header_as_SparseTensor(); -} - -struct MessageBuilder { - typedef Message Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_version(org::apache::arrow::flatbuf::MetadataVersion version) { - fbb_.AddElement<int16_t>(Message::VT_VERSION, static_cast<int16_t>(version), 0); - } - void add_header_type(org::apache::arrow::flatbuf::MessageHeader header_type) { - fbb_.AddElement<uint8_t>(Message::VT_HEADER_TYPE, static_cast<uint8_t>(header_type), 0); - } - void add_header(flatbuffers::Offset<void> header) { - fbb_.AddOffset(Message::VT_HEADER, header); - } - void add_bodyLength(int64_t bodyLength) { - fbb_.AddElement<int64_t>(Message::VT_BODYLENGTH, bodyLength, 0); - } - void add_custom_metadata(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>>> custom_metadata) { - fbb_.AddOffset(Message::VT_CUSTOM_METADATA, custom_metadata); - } - explicit MessageBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - MessageBuilder &operator=(const MessageBuilder &); - flatbuffers::Offset<Message> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<Message>(end); - return o; - } -}; - -inline flatbuffers::Offset<Message> CreateMessage( - flatbuffers::FlatBufferBuilder &_fbb, - org::apache::arrow::flatbuf::MetadataVersion version = org::apache::arrow::flatbuf::MetadataVersion::V1, - org::apache::arrow::flatbuf::MessageHeader header_type = org::apache::arrow::flatbuf::MessageHeader::NONE, - flatbuffers::Offset<void> header = 0, - int64_t bodyLength = 0, - flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>>> custom_metadata = 0) { - MessageBuilder builder_(_fbb); - builder_.add_bodyLength(bodyLength); - builder_.add_custom_metadata(custom_metadata); - builder_.add_header(header); - builder_.add_version(version); - builder_.add_header_type(header_type); - return builder_.Finish(); -} - -inline flatbuffers::Offset<Message> CreateMessageDirect( - flatbuffers::FlatBufferBuilder &_fbb, - org::apache::arrow::flatbuf::MetadataVersion version = org::apache::arrow::flatbuf::MetadataVersion::V1, - org::apache::arrow::flatbuf::MessageHeader header_type = org::apache::arrow::flatbuf::MessageHeader::NONE, - flatbuffers::Offset<void> header = 0, - int64_t bodyLength = 0, - const std::vector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>> *custom_metadata = nullptr) { - auto custom_metadata__ = custom_metadata ? _fbb.CreateVector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>>(*custom_metadata) : 0; - return org::apache::arrow::flatbuf::CreateMessage( - _fbb, - version, - header_type, - header, - bodyLength, - custom_metadata__); -} - -inline bool VerifyMessageHeader(flatbuffers::Verifier &verifier, const void *obj, MessageHeader type) { - switch (type) { - case MessageHeader::NONE: { - return true; - } - case MessageHeader::Schema: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::Schema *>(obj); - return verifier.VerifyTable(ptr); - } - case MessageHeader::DictionaryBatch: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::DictionaryBatch *>(obj); - return verifier.VerifyTable(ptr); - } - case MessageHeader::RecordBatch: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::RecordBatch *>(obj); - return verifier.VerifyTable(ptr); - } - case MessageHeader::Tensor: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::Tensor *>(obj); - return verifier.VerifyTable(ptr); - } - case MessageHeader::SparseTensor: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::SparseTensor *>(obj); - return verifier.VerifyTable(ptr); - } - default: return true; - } -} - -inline bool VerifyMessageHeaderVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types) { - if (!values || !types) return !values && !types; - if (values->size() != types->size()) return false; - for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) { - if (!VerifyMessageHeader( - verifier, values->Get(i), types->GetEnum<MessageHeader>(i))) { - return false; - } - } - return true; -} - -inline const org::apache::arrow::flatbuf::Message *GetMessage(const void *buf) { - return flatbuffers::GetRoot<org::apache::arrow::flatbuf::Message>(buf); -} - -inline const org::apache::arrow::flatbuf::Message *GetSizePrefixedMessage(const void *buf) { - return flatbuffers::GetSizePrefixedRoot<org::apache::arrow::flatbuf::Message>(buf); -} - -inline bool VerifyMessageBuffer( - flatbuffers::Verifier &verifier) { - return verifier.VerifyBuffer<org::apache::arrow::flatbuf::Message>(nullptr); -} - -inline bool VerifySizePrefixedMessageBuffer( - flatbuffers::Verifier &verifier) { - return verifier.VerifySizePrefixedBuffer<org::apache::arrow::flatbuf::Message>(nullptr); -} - -inline void FinishMessageBuffer( - flatbuffers::FlatBufferBuilder &fbb, - flatbuffers::Offset<org::apache::arrow::flatbuf::Message> root) { - fbb.Finish(root); -} - -inline void FinishSizePrefixedMessageBuffer( - flatbuffers::FlatBufferBuilder &fbb, - flatbuffers::Offset<org::apache::arrow::flatbuf::Message> root) { - fbb.FinishSizePrefixed(root); -} - -} // namespace flatbuf -} // namespace arrow -} // namespace apache -} // namespace org - -#endif // FLATBUFFERS_GENERATED_MESSAGE_ORG_APACHE_ARROW_FLATBUF_H_ diff --git a/contrib/libs/apache/arrow/cpp/src/generated/Schema.fbs b/contrib/libs/apache/arrow/cpp/src/generated/Schema.fbs new file mode 100644 index 0000000000..e19e8bac28 --- /dev/null +++ b/contrib/libs/apache/arrow/cpp/src/generated/Schema.fbs @@ -0,0 +1,430 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +/// Logical types, vector layouts, and schemas + +namespace org.apache.arrow.flatbuf; + +enum MetadataVersion:short { + /// 0.1.0 (October 2016). + V1, + + /// 0.2.0 (February 2017). Non-backwards compatible with V1. + V2, + + /// 0.3.0 -> 0.7.1 (May - December 2017). Non-backwards compatible with V2. + V3, + + /// >= 0.8.0 (December 2017). Non-backwards compatible with V3. + V4, + + /// >= 1.0.0 (July 2020. Backwards compatible with V4 (V5 readers can read V4 + /// metadata and IPC messages). Implementations are recommended to provide a + /// V4 compatibility mode with V5 format changes disabled. + /// + /// Incompatible changes between V4 and V5: + /// - Union buffer layout has changed. In V5, Unions don't have a validity + /// bitmap buffer. + V5, +} + +/// Represents Arrow Features that might not have full support +/// within implementations. This is intended to be used in +/// two scenarios: +/// 1. A mechanism for readers of Arrow Streams +/// and files to understand that the stream or file makes +/// use of a feature that isn't supported or unknown to +/// the implementation (and therefore can meet the Arrow +/// forward compatibility guarantees). +/// 2. A means of negotiating between a client and server +/// what features a stream is allowed to use. The enums +/// values here are intented to represent higher level +/// features, additional details maybe negotiated +/// with key-value pairs specific to the protocol. +/// +/// Enums added to this list should be assigned power-of-two values +/// to facilitate exchanging and comparing bitmaps for supported +/// features. +enum Feature : long { + /// Needed to make flatbuffers happy. + UNUSED = 0, + /// The stream makes use of multiple full dictionaries with the + /// same ID and assumes clients implement dictionary replacement + /// correctly. + DICTIONARY_REPLACEMENT = 1, + /// The stream makes use of compressed bodies as described + /// in Message.fbs. + COMPRESSED_BODY = 2 +} + +/// These are stored in the flatbuffer in the Type union below + +table Null { +} + +/// A Struct_ in the flatbuffer metadata is the same as an Arrow Struct +/// (according to the physical memory layout). We used Struct_ here as +/// Struct is a reserved word in Flatbuffers +table Struct_ { +} + +table List { +} + +/// Same as List, but with 64-bit offsets, allowing to represent +/// extremely large data values. +table LargeList { +} + +table FixedSizeList { + /// Number of list items per value + listSize: int; +} + +/// A Map is a logical nested type that is represented as +/// +/// List<entries: Struct<key: K, value: V>> +/// +/// In this layout, the keys and values are each respectively contiguous. We do +/// not constrain the key and value types, so the application is responsible +/// for ensuring that the keys are hashable and unique. Whether the keys are sorted +/// may be set in the metadata for this field. +/// +/// In a field with Map type, the field has a child Struct field, which then +/// has two children: key type and the second the value type. The names of the +/// child fields may be respectively "entries", "key", and "value", but this is +/// not enforced. +/// +/// Map +/// ```text +/// - child[0] entries: Struct +/// - child[0] key: K +/// - child[1] value: V +/// ``` +/// Neither the "entries" field nor the "key" field may be nullable. +/// +/// The metadata is structured so that Arrow systems without special handling +/// for Map can make Map an alias for List. The "layout" attribute for the Map +/// field must have the same contents as a List. +table Map { + /// Set to true if the keys within each value are sorted + keysSorted: bool; +} + +enum UnionMode:short { Sparse, Dense } + +/// A union is a complex type with children in Field +/// By default ids in the type vector refer to the offsets in the children +/// optionally typeIds provides an indirection between the child offset and the type id +/// for each child `typeIds[offset]` is the id used in the type vector +table Union { + mode: UnionMode; + typeIds: [ int ]; // optional, describes typeid of each child. +} + +table Int { + bitWidth: int; // restricted to 8, 16, 32, and 64 in v1 + is_signed: bool; +} + +enum Precision:short {HALF, SINGLE, DOUBLE} + +table FloatingPoint { + precision: Precision; +} + +/// Unicode with UTF-8 encoding +table Utf8 { +} + +/// Opaque binary data +table Binary { +} + +/// Same as Utf8, but with 64-bit offsets, allowing to represent +/// extremely large data values. +table LargeUtf8 { +} + +/// Same as Binary, but with 64-bit offsets, allowing to represent +/// extremely large data values. +table LargeBinary { +} + +table FixedSizeBinary { + /// Number of bytes per value + byteWidth: int; +} + +table Bool { +} + +/// Exact decimal value represented as an integer value in two's +/// complement. Currently only 128-bit (16-byte) and 256-bit (32-byte) integers +/// are used. The representation uses the endianness indicated +/// in the Schema. +table Decimal { + /// Total number of decimal digits + precision: int; + + /// Number of digits after the decimal point "." + scale: int; + + /// Number of bits per value. The only accepted widths are 128 and 256. + /// We use bitWidth for consistency with Int::bitWidth. + bitWidth: int = 128; +} + +enum DateUnit: short { + DAY, + MILLISECOND +} + +/// Date is either a 32-bit or 64-bit type representing elapsed time since UNIX +/// epoch (1970-01-01), stored in either of two units: +/// +/// * Milliseconds (64 bits) indicating UNIX time elapsed since the epoch (no +/// leap seconds), where the values are evenly divisible by 86400000 +/// * Days (32 bits) since the UNIX epoch +table Date { + unit: DateUnit = MILLISECOND; +} + +enum TimeUnit: short { SECOND, MILLISECOND, MICROSECOND, NANOSECOND } + +/// Time type. The physical storage type depends on the unit +/// - SECOND and MILLISECOND: 32 bits +/// - MICROSECOND and NANOSECOND: 64 bits +table Time { + unit: TimeUnit = MILLISECOND; + bitWidth: int = 32; +} + +/// Time elapsed from the Unix epoch, 00:00:00.000 on 1 January 1970, excluding +/// leap seconds, as a 64-bit integer. Note that UNIX time does not include +/// leap seconds. +/// +/// Date & time libraries often have multiple different data types for temporal +/// data. In order to ease interoperability between different implementations the +/// Arrow project has some recommendations for encoding these types into a Timestamp +/// column. +/// +/// An "instant" represents a single moment in time that has no meaningful time zone +/// or the time zone is unknown. A column of instants can also contain values from +/// multiple time zones. To encode an instant set the timezone string to "UTC". +/// +/// A "zoned date-time" represents a single moment in time that has a meaningful +/// reference time zone. To encode a zoned date-time as a Timestamp set the timezone +/// string to the name of the timezone. There is some ambiguity between an instant +/// and a zoned date-time with the UTC time zone. Both of these are stored the same. +/// Typically, this distinction does not matter. If it does, then an application should +/// use custom metadata or an extension type to distinguish between the two cases. +/// +/// An "offset date-time" represents a single moment in time combined with a meaningful +/// offset from UTC. To encode an offset date-time as a Timestamp set the timezone string +/// to the numeric time zone offset string (e.g. "+03:00"). +/// +/// A "local date-time" does not represent a single moment in time. It represents a wall +/// clock time combined with a date. Because of daylight savings time there may multiple +/// instants that correspond to a single local date-time in any given time zone. A +/// local date-time is often stored as a struct or a Date32/Time64 pair. However, it can +/// also be encoded into a Timestamp column. To do so the value should be the the time +/// elapsed from the Unix epoch so that a wall clock in UTC would display the desired time. +/// The timezone string should be set to null or the empty string. +table Timestamp { + unit: TimeUnit; + + /// The time zone is a string indicating the name of a time zone, one of: + /// + /// * As used in the Olson time zone database (the "tz database" or + /// "tzdata"), such as "America/New_York" + /// * An absolute time zone offset of the form +XX:XX or -XX:XX, such as +07:30 + /// + /// Whether a timezone string is present indicates different semantics about + /// the data: + /// + /// * If the time zone is null or an empty string, the data is a local date-time + /// and does not represent a single moment in time. Instead it represents a wall clock + /// time and care should be taken to avoid interpreting it semantically as an instant. + /// + /// * If the time zone is set to a valid value, values can be displayed as + /// "localized" to that time zone, even though the underlying 64-bit + /// integers are identical to the same data stored in UTC. Converting + /// between time zones is a metadata-only operation and does not change the + /// underlying values + time_zone: string; +} + +enum IntervalUnit: short { YEAR_MONTH, DAY_TIME} +// A "calendar" interval which models types that don't necessarily +// have a precise duration without the context of a base timestamp (e.g. +// days can differ in length during day light savings time transitions). +// YEAR_MONTH - Indicates the number of elapsed whole months, stored as +// 4-byte integers. +// DAY_TIME - Indicates the number of elapsed days and milliseconds, +// stored as 2 contiguous 32-bit integers (8-bytes in total). Support +// of this IntervalUnit is not required for full arrow compatibility. +table Interval { + unit: IntervalUnit; +} + +// An absolute length of time unrelated to any calendar artifacts. +// +// For the purposes of Arrow Implementations, adding this value to a Timestamp +// ("t1") naively (i.e. simply summing the two number) is acceptable even +// though in some cases the resulting Timestamp (t2) would not account for +// leap-seconds during the elapsed time between "t1" and "t2". Similarly, +// representing the difference between two Unix timestamp is acceptable, but +// would yield a value that is possibly a few seconds off from the true elapsed +// time. +// +// The resolution defaults to millisecond, but can be any of the other +// supported TimeUnit values as with Timestamp and Time types. This type is +// always represented as an 8-byte integer. +table Duration { + unit: TimeUnit = MILLISECOND; +} + +/// ---------------------------------------------------------------------- +/// Top-level Type value, enabling extensible type-specific metadata. We can +/// add new logical types to Type without breaking backwards compatibility + +union Type { + Null, + Int, + FloatingPoint, + Binary, + Utf8, + Bool, + Decimal, + Date, + Time, + Timestamp, + Interval, + List, + Struct_, + Union, + FixedSizeBinary, + FixedSizeList, + Map, + Duration, + LargeBinary, + LargeUtf8, + LargeList, +} + +/// ---------------------------------------------------------------------- +/// user defined key value pairs to add custom metadata to arrow +/// key namespacing is the responsibility of the user + +table KeyValue { + key: string; + value: string; +} + +/// ---------------------------------------------------------------------- +/// Dictionary encoding metadata +/// Maintained for forwards compatibility, in the future +/// Dictionaries might be explicit maps between integers and values +/// allowing for non-contiguous index values +enum DictionaryKind : short { DenseArray } +table DictionaryEncoding { + /// The known dictionary id in the application where this data is used. In + /// the file or streaming formats, the dictionary ids are found in the + /// DictionaryBatch messages + id: long; + + /// The dictionary indices are constrained to be non-negative integers. If + /// this field is null, the indices must be signed int32. To maximize + /// cross-language compatibility and performance, implementations are + /// recommended to prefer signed integer types over unsigned integer types + /// and to avoid uint64 indices unless they are required by an application. + indexType: Int; + + /// By default, dictionaries are not ordered, or the order does not have + /// semantic meaning. In some statistical, applications, dictionary-encoding + /// is used to represent ordered categorical data, and we provide a way to + /// preserve that metadata here + isOrdered: bool; + + dictionaryKind: DictionaryKind; +} + +/// ---------------------------------------------------------------------- +/// A field represents a named column in a record / row batch or child of a +/// nested type. + +table Field { + /// Name is not required, in i.e. a List + name: string; + + /// Whether or not this field can contain nulls. Should be true in general. + nullable: bool; + + /// This is the type of the decoded value if the field is dictionary encoded. + type: Type; + + /// Present only if the field is dictionary encoded. + dictionary: DictionaryEncoding; + + /// children apply only to nested data types like Struct, List and Union. For + /// primitive types children will have length 0. + children: [ Field ]; + + /// User-defined metadata + custom_metadata: [ KeyValue ]; +} + +/// ---------------------------------------------------------------------- +/// Endianness of the platform producing the data + +enum Endianness:short { Little, Big } + +/// ---------------------------------------------------------------------- +/// A Buffer represents a single contiguous memory segment +struct Buffer { + /// The relative offset into the shared memory page where the bytes for this + /// buffer starts + offset: long; + + /// The absolute length (in bytes) of the memory buffer. The memory is found + /// from offset (inclusive) to offset + length (non-inclusive). When building + /// messages using the encapsulated IPC message, padding bytes may be written + /// after a buffer, but such padding bytes do not need to be accounted for in + /// the size here. + length: long; +} + +/// ---------------------------------------------------------------------- +/// A Schema describes the columns in a row batch + +table Schema { + + /// endianness of the buffer + /// it is Little Endian by default + /// if endianness doesn't match the underlying system then the vectors need to be converted + endianness: Endianness=Little; + + fields: [Field]; + // User-defined metadata + custom_metadata: [ KeyValue ]; + + /// Features used in the stream/file. + features : [ Feature ]; +} + +root_type Schema; diff --git a/contrib/libs/apache/arrow/cpp/src/generated/Schema_generated.h b/contrib/libs/apache/arrow/cpp/src/generated/Schema_generated.h deleted file mode 100644 index 91e01d3375..0000000000 --- a/contrib/libs/apache/arrow/cpp/src/generated/Schema_generated.h +++ /dev/null @@ -1,2265 +0,0 @@ -// automatically generated by the FlatBuffers compiler, do not modify - - -#ifndef FLATBUFFERS_GENERATED_SCHEMA_ORG_APACHE_ARROW_FLATBUF_H_ -#define FLATBUFFERS_GENERATED_SCHEMA_ORG_APACHE_ARROW_FLATBUF_H_ - -#include "flatbuffers/flatbuffers.h" - -namespace org { -namespace apache { -namespace arrow { -namespace flatbuf { - -struct Null; -struct NullBuilder; - -struct Struct_; -struct Struct_Builder; - -struct List; -struct ListBuilder; - -struct LargeList; -struct LargeListBuilder; - -struct FixedSizeList; -struct FixedSizeListBuilder; - -struct Map; -struct MapBuilder; - -struct Union; -struct UnionBuilder; - -struct Int; -struct IntBuilder; - -struct FloatingPoint; -struct FloatingPointBuilder; - -struct Utf8; -struct Utf8Builder; - -struct Binary; -struct BinaryBuilder; - -struct LargeUtf8; -struct LargeUtf8Builder; - -struct LargeBinary; -struct LargeBinaryBuilder; - -struct FixedSizeBinary; -struct FixedSizeBinaryBuilder; - -struct Bool; -struct BoolBuilder; - -struct Decimal; -struct DecimalBuilder; - -struct Date; -struct DateBuilder; - -struct Time; -struct TimeBuilder; - -struct Timestamp; -struct TimestampBuilder; - -struct Interval; -struct IntervalBuilder; - -struct Duration; -struct DurationBuilder; - -struct KeyValue; -struct KeyValueBuilder; - -struct DictionaryEncoding; -struct DictionaryEncodingBuilder; - -struct Field; -struct FieldBuilder; - -struct Buffer; - -struct Schema; -struct SchemaBuilder; - -enum class MetadataVersion : int16_t { - /// 0.1.0 (October 2016). - V1 = 0, - /// 0.2.0 (February 2017). Non-backwards compatible with V1. - V2 = 1, - /// 0.3.0 -> 0.7.1 (May - December 2017). Non-backwards compatible with V2. - V3 = 2, - /// >= 0.8.0 (December 2017). Non-backwards compatible with V3. - V4 = 3, - /// >= 1.0.0 (July 2020. Backwards compatible with V4 (V5 readers can read V4 - /// metadata and IPC messages). Implementations are recommended to provide a - /// V4 compatibility mode with V5 format changes disabled. - /// - /// Incompatible changes between V4 and V5: - /// - Union buffer layout has changed. In V5, Unions don't have a validity - /// bitmap buffer. - V5 = 4, - MIN = V1, - MAX = V5 -}; - -inline const MetadataVersion (&EnumValuesMetadataVersion())[5] { - static const MetadataVersion values[] = { - MetadataVersion::V1, - MetadataVersion::V2, - MetadataVersion::V3, - MetadataVersion::V4, - MetadataVersion::V5 - }; - return values; -} - -inline const char * const *EnumNamesMetadataVersion() { - static const char * const names[6] = { - "V1", - "V2", - "V3", - "V4", - "V5", - nullptr - }; - return names; -} - -inline const char *EnumNameMetadataVersion(MetadataVersion e) { - if (flatbuffers::IsOutRange(e, MetadataVersion::V1, MetadataVersion::V5)) return ""; - const size_t index = static_cast<size_t>(e); - return EnumNamesMetadataVersion()[index]; -} - -/// Represents Arrow Features that might not have full support -/// within implementations. This is intended to be used in -/// two scenarios: -/// 1. A mechanism for readers of Arrow Streams -/// and files to understand that the stream or file makes -/// use of a feature that isn't supported or unknown to -/// the implementation (and therefore can meet the Arrow -/// forward compatibility guarantees). -/// 2. A means of negotiating between a client and server -/// what features a stream is allowed to use. The enums -/// values here are intented to represent higher level -/// features, additional details maybe negotiated -/// with key-value pairs specific to the protocol. -/// -/// Enums added to this list should be assigned power-of-two values -/// to facilitate exchanging and comparing bitmaps for supported -/// features. -enum class Feature : int64_t { - /// Needed to make flatbuffers happy. - UNUSED = 0, - /// The stream makes use of multiple full dictionaries with the - /// same ID and assumes clients implement dictionary replacement - /// correctly. - DICTIONARY_REPLACEMENT = 1LL, - /// The stream makes use of compressed bodies as described - /// in Message.fbs. - COMPRESSED_BODY = 2LL, - MIN = UNUSED, - MAX = COMPRESSED_BODY -}; - -inline const Feature (&EnumValuesFeature())[3] { - static const Feature values[] = { - Feature::UNUSED, - Feature::DICTIONARY_REPLACEMENT, - Feature::COMPRESSED_BODY - }; - return values; -} - -inline const char * const *EnumNamesFeature() { - static const char * const names[4] = { - "UNUSED", - "DICTIONARY_REPLACEMENT", - "COMPRESSED_BODY", - nullptr - }; - return names; -} - -inline const char *EnumNameFeature(Feature e) { - if (flatbuffers::IsOutRange(e, Feature::UNUSED, Feature::COMPRESSED_BODY)) return ""; - const size_t index = static_cast<size_t>(e); - return EnumNamesFeature()[index]; -} - -enum class UnionMode : int16_t { - Sparse = 0, - Dense = 1, - MIN = Sparse, - MAX = Dense -}; - -inline const UnionMode (&EnumValuesUnionMode())[2] { - static const UnionMode values[] = { - UnionMode::Sparse, - UnionMode::Dense - }; - return values; -} - -inline const char * const *EnumNamesUnionMode() { - static const char * const names[3] = { - "Sparse", - "Dense", - nullptr - }; - return names; -} - -inline const char *EnumNameUnionMode(UnionMode e) { - if (flatbuffers::IsOutRange(e, UnionMode::Sparse, UnionMode::Dense)) return ""; - const size_t index = static_cast<size_t>(e); - return EnumNamesUnionMode()[index]; -} - -enum class Precision : int16_t { - HALF = 0, - SINGLE = 1, - DOUBLE = 2, - MIN = HALF, - MAX = DOUBLE -}; - -inline const Precision (&EnumValuesPrecision())[3] { - static const Precision values[] = { - Precision::HALF, - Precision::SINGLE, - Precision::DOUBLE - }; - return values; -} - -inline const char * const *EnumNamesPrecision() { - static const char * const names[4] = { - "HALF", - "SINGLE", - "DOUBLE", - nullptr - }; - return names; -} - -inline const char *EnumNamePrecision(Precision e) { - if (flatbuffers::IsOutRange(e, Precision::HALF, Precision::DOUBLE)) return ""; - const size_t index = static_cast<size_t>(e); - return EnumNamesPrecision()[index]; -} - -enum class DateUnit : int16_t { - DAY = 0, - MILLISECOND = 1, - MIN = DAY, - MAX = MILLISECOND -}; - -inline const DateUnit (&EnumValuesDateUnit())[2] { - static const DateUnit values[] = { - DateUnit::DAY, - DateUnit::MILLISECOND - }; - return values; -} - -inline const char * const *EnumNamesDateUnit() { - static const char * const names[3] = { - "DAY", - "MILLISECOND", - nullptr - }; - return names; -} - -inline const char *EnumNameDateUnit(DateUnit e) { - if (flatbuffers::IsOutRange(e, DateUnit::DAY, DateUnit::MILLISECOND)) return ""; - const size_t index = static_cast<size_t>(e); - return EnumNamesDateUnit()[index]; -} - -enum class TimeUnit : int16_t { - SECOND = 0, - MILLISECOND = 1, - MICROSECOND = 2, - NANOSECOND = 3, - MIN = SECOND, - MAX = NANOSECOND -}; - -inline const TimeUnit (&EnumValuesTimeUnit())[4] { - static const TimeUnit values[] = { - TimeUnit::SECOND, - TimeUnit::MILLISECOND, - TimeUnit::MICROSECOND, - TimeUnit::NANOSECOND - }; - return values; -} - -inline const char * const *EnumNamesTimeUnit() { - static const char * const names[5] = { - "SECOND", - "MILLISECOND", - "MICROSECOND", - "NANOSECOND", - nullptr - }; - return names; -} - -inline const char *EnumNameTimeUnit(TimeUnit e) { - if (flatbuffers::IsOutRange(e, TimeUnit::SECOND, TimeUnit::NANOSECOND)) return ""; - const size_t index = static_cast<size_t>(e); - return EnumNamesTimeUnit()[index]; -} - -enum class IntervalUnit : int16_t { - YEAR_MONTH = 0, - DAY_TIME = 1, - MIN = YEAR_MONTH, - MAX = DAY_TIME -}; - -inline const IntervalUnit (&EnumValuesIntervalUnit())[2] { - static const IntervalUnit values[] = { - IntervalUnit::YEAR_MONTH, - IntervalUnit::DAY_TIME - }; - return values; -} - -inline const char * const *EnumNamesIntervalUnit() { - static const char * const names[3] = { - "YEAR_MONTH", - "DAY_TIME", - nullptr - }; - return names; -} - -inline const char *EnumNameIntervalUnit(IntervalUnit e) { - if (flatbuffers::IsOutRange(e, IntervalUnit::YEAR_MONTH, IntervalUnit::DAY_TIME)) return ""; - const size_t index = static_cast<size_t>(e); - return EnumNamesIntervalUnit()[index]; -} - -/// ---------------------------------------------------------------------- -/// Top-level Type value, enabling extensible type-specific metadata. We can -/// add new logical types to Type without breaking backwards compatibility -enum class Type : uint8_t { - NONE = 0, - Null = 1, - Int = 2, - FloatingPoint = 3, - Binary = 4, - Utf8 = 5, - Bool = 6, - Decimal = 7, - Date = 8, - Time = 9, - Timestamp = 10, - Interval = 11, - List = 12, - Struct_ = 13, - Union = 14, - FixedSizeBinary = 15, - FixedSizeList = 16, - Map = 17, - Duration = 18, - LargeBinary = 19, - LargeUtf8 = 20, - LargeList = 21, - MIN = NONE, - MAX = LargeList -}; - -inline const Type (&EnumValuesType())[22] { - static const Type values[] = { - Type::NONE, - Type::Null, - Type::Int, - Type::FloatingPoint, - Type::Binary, - Type::Utf8, - Type::Bool, - Type::Decimal, - Type::Date, - Type::Time, - Type::Timestamp, - Type::Interval, - Type::List, - Type::Struct_, - Type::Union, - Type::FixedSizeBinary, - Type::FixedSizeList, - Type::Map, - Type::Duration, - Type::LargeBinary, - Type::LargeUtf8, - Type::LargeList - }; - return values; -} - -inline const char * const *EnumNamesType() { - static const char * const names[23] = { - "NONE", - "Null", - "Int", - "FloatingPoint", - "Binary", - "Utf8", - "Bool", - "Decimal", - "Date", - "Time", - "Timestamp", - "Interval", - "List", - "Struct_", - "Union", - "FixedSizeBinary", - "FixedSizeList", - "Map", - "Duration", - "LargeBinary", - "LargeUtf8", - "LargeList", - nullptr - }; - return names; -} - -inline const char *EnumNameType(Type e) { - if (flatbuffers::IsOutRange(e, Type::NONE, Type::LargeList)) return ""; - const size_t index = static_cast<size_t>(e); - return EnumNamesType()[index]; -} - -template<typename T> struct TypeTraits { - static const Type enum_value = Type::NONE; -}; - -template<> struct TypeTraits<org::apache::arrow::flatbuf::Null> { - static const Type enum_value = Type::Null; -}; - -template<> struct TypeTraits<org::apache::arrow::flatbuf::Int> { - static const Type enum_value = Type::Int; -}; - -template<> struct TypeTraits<org::apache::arrow::flatbuf::FloatingPoint> { - static const Type enum_value = Type::FloatingPoint; -}; - -template<> struct TypeTraits<org::apache::arrow::flatbuf::Binary> { - static const Type enum_value = Type::Binary; -}; - -template<> struct TypeTraits<org::apache::arrow::flatbuf::Utf8> { - static const Type enum_value = Type::Utf8; -}; - -template<> struct TypeTraits<org::apache::arrow::flatbuf::Bool> { - static const Type enum_value = Type::Bool; -}; - -template<> struct TypeTraits<org::apache::arrow::flatbuf::Decimal> { - static const Type enum_value = Type::Decimal; -}; - -template<> struct TypeTraits<org::apache::arrow::flatbuf::Date> { - static const Type enum_value = Type::Date; -}; - -template<> struct TypeTraits<org::apache::arrow::flatbuf::Time> { - static const Type enum_value = Type::Time; -}; - -template<> struct TypeTraits<org::apache::arrow::flatbuf::Timestamp> { - static const Type enum_value = Type::Timestamp; -}; - -template<> struct TypeTraits<org::apache::arrow::flatbuf::Interval> { - static const Type enum_value = Type::Interval; -}; - -template<> struct TypeTraits<org::apache::arrow::flatbuf::List> { - static const Type enum_value = Type::List; -}; - -template<> struct TypeTraits<org::apache::arrow::flatbuf::Struct_> { - static const Type enum_value = Type::Struct_; -}; - -template<> struct TypeTraits<org::apache::arrow::flatbuf::Union> { - static const Type enum_value = Type::Union; -}; - -template<> struct TypeTraits<org::apache::arrow::flatbuf::FixedSizeBinary> { - static const Type enum_value = Type::FixedSizeBinary; -}; - -template<> struct TypeTraits<org::apache::arrow::flatbuf::FixedSizeList> { - static const Type enum_value = Type::FixedSizeList; -}; - -template<> struct TypeTraits<org::apache::arrow::flatbuf::Map> { - static const Type enum_value = Type::Map; -}; - -template<> struct TypeTraits<org::apache::arrow::flatbuf::Duration> { - static const Type enum_value = Type::Duration; -}; - -template<> struct TypeTraits<org::apache::arrow::flatbuf::LargeBinary> { - static const Type enum_value = Type::LargeBinary; -}; - -template<> struct TypeTraits<org::apache::arrow::flatbuf::LargeUtf8> { - static const Type enum_value = Type::LargeUtf8; -}; - -template<> struct TypeTraits<org::apache::arrow::flatbuf::LargeList> { - static const Type enum_value = Type::LargeList; -}; - -bool VerifyType(flatbuffers::Verifier &verifier, const void *obj, Type type); -bool VerifyTypeVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types); - -/// ---------------------------------------------------------------------- -/// Dictionary encoding metadata -/// Maintained for forwards compatibility, in the future -/// Dictionaries might be explicit maps between integers and values -/// allowing for non-contiguous index values -enum class DictionaryKind : int16_t { - DenseArray = 0, - MIN = DenseArray, - MAX = DenseArray -}; - -inline const DictionaryKind (&EnumValuesDictionaryKind())[1] { - static const DictionaryKind values[] = { - DictionaryKind::DenseArray - }; - return values; -} - -inline const char * const *EnumNamesDictionaryKind() { - static const char * const names[2] = { - "DenseArray", - nullptr - }; - return names; -} - -inline const char *EnumNameDictionaryKind(DictionaryKind e) { - if (flatbuffers::IsOutRange(e, DictionaryKind::DenseArray, DictionaryKind::DenseArray)) return ""; - const size_t index = static_cast<size_t>(e); - return EnumNamesDictionaryKind()[index]; -} - -/// ---------------------------------------------------------------------- -/// Endianness of the platform producing the data -enum class Endianness : int16_t { - Little = 0, - Big = 1, - MIN = Little, - MAX = Big -}; - -inline const Endianness (&EnumValuesEndianness())[2] { - static const Endianness values[] = { - Endianness::Little, - Endianness::Big - }; - return values; -} - -inline const char * const *EnumNamesEndianness() { - static const char * const names[3] = { - "Little", - "Big", - nullptr - }; - return names; -} - -inline const char *EnumNameEndianness(Endianness e) { - if (flatbuffers::IsOutRange(e, Endianness::Little, Endianness::Big)) return ""; - const size_t index = static_cast<size_t>(e); - return EnumNamesEndianness()[index]; -} - -/// ---------------------------------------------------------------------- -/// A Buffer represents a single contiguous memory segment -FLATBUFFERS_MANUALLY_ALIGNED_STRUCT(8) Buffer FLATBUFFERS_FINAL_CLASS { - private: - int64_t offset_; - int64_t length_; - - public: - Buffer() { - memset(static_cast<void *>(this), 0, sizeof(Buffer)); - } - Buffer(int64_t _offset, int64_t _length) - : offset_(flatbuffers::EndianScalar(_offset)), - length_(flatbuffers::EndianScalar(_length)) { - } - /// The relative offset into the shared memory page where the bytes for this - /// buffer starts - int64_t offset() const { - return flatbuffers::EndianScalar(offset_); - } - /// The absolute length (in bytes) of the memory buffer. The memory is found - /// from offset (inclusive) to offset + length (non-inclusive). When building - /// messages using the encapsulated IPC message, padding bytes may be written - /// after a buffer, but such padding bytes do not need to be accounted for in - /// the size here. - int64_t length() const { - return flatbuffers::EndianScalar(length_); - } -}; -FLATBUFFERS_STRUCT_END(Buffer, 16); - -/// These are stored in the flatbuffer in the Type union below -struct Null FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef NullBuilder Builder; - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - verifier.EndTable(); - } -}; - -struct NullBuilder { - typedef Null Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - explicit NullBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - NullBuilder &operator=(const NullBuilder &); - flatbuffers::Offset<Null> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<Null>(end); - return o; - } -}; - -inline flatbuffers::Offset<Null> CreateNull( - flatbuffers::FlatBufferBuilder &_fbb) { - NullBuilder builder_(_fbb); - return builder_.Finish(); -} - -/// A Struct_ in the flatbuffer metadata is the same as an Arrow Struct -/// (according to the physical memory layout). We used Struct_ here as -/// Struct is a reserved word in Flatbuffers -struct Struct_ FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef Struct_Builder Builder; - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - verifier.EndTable(); - } -}; - -struct Struct_Builder { - typedef Struct_ Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - explicit Struct_Builder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - Struct_Builder &operator=(const Struct_Builder &); - flatbuffers::Offset<Struct_> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<Struct_>(end); - return o; - } -}; - -inline flatbuffers::Offset<Struct_> CreateStruct_( - flatbuffers::FlatBufferBuilder &_fbb) { - Struct_Builder builder_(_fbb); - return builder_.Finish(); -} - -struct List FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef ListBuilder Builder; - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - verifier.EndTable(); - } -}; - -struct ListBuilder { - typedef List Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - explicit ListBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - ListBuilder &operator=(const ListBuilder &); - flatbuffers::Offset<List> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<List>(end); - return o; - } -}; - -inline flatbuffers::Offset<List> CreateList( - flatbuffers::FlatBufferBuilder &_fbb) { - ListBuilder builder_(_fbb); - return builder_.Finish(); -} - -/// Same as List, but with 64-bit offsets, allowing to represent -/// extremely large data values. -struct LargeList FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef LargeListBuilder Builder; - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - verifier.EndTable(); - } -}; - -struct LargeListBuilder { - typedef LargeList Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - explicit LargeListBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - LargeListBuilder &operator=(const LargeListBuilder &); - flatbuffers::Offset<LargeList> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<LargeList>(end); - return o; - } -}; - -inline flatbuffers::Offset<LargeList> CreateLargeList( - flatbuffers::FlatBufferBuilder &_fbb) { - LargeListBuilder builder_(_fbb); - return builder_.Finish(); -} - -struct FixedSizeList FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef FixedSizeListBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_LISTSIZE = 4 - }; - /// Number of list items per value - int32_t listSize() const { - return GetField<int32_t>(VT_LISTSIZE, 0); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int32_t>(verifier, VT_LISTSIZE) && - verifier.EndTable(); - } -}; - -struct FixedSizeListBuilder { - typedef FixedSizeList Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_listSize(int32_t listSize) { - fbb_.AddElement<int32_t>(FixedSizeList::VT_LISTSIZE, listSize, 0); - } - explicit FixedSizeListBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - FixedSizeListBuilder &operator=(const FixedSizeListBuilder &); - flatbuffers::Offset<FixedSizeList> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<FixedSizeList>(end); - return o; - } -}; - -inline flatbuffers::Offset<FixedSizeList> CreateFixedSizeList( - flatbuffers::FlatBufferBuilder &_fbb, - int32_t listSize = 0) { - FixedSizeListBuilder builder_(_fbb); - builder_.add_listSize(listSize); - return builder_.Finish(); -} - -/// A Map is a logical nested type that is represented as -/// -/// List<entries: Struct<key: K, value: V>> -/// -/// In this layout, the keys and values are each respectively contiguous. We do -/// not constrain the key and value types, so the application is responsible -/// for ensuring that the keys are hashable and unique. Whether the keys are sorted -/// may be set in the metadata for this field. -/// -/// In a field with Map type, the field has a child Struct field, which then -/// has two children: key type and the second the value type. The names of the -/// child fields may be respectively "entries", "key", and "value", but this is -/// not enforced. -/// -/// Map -/// - child[0] entries: Struct -/// - child[0] key: K -/// - child[1] value: V -/// -/// Neither the "entries" field nor the "key" field may be nullable. -/// -/// The metadata is structured so that Arrow systems without special handling -/// for Map can make Map an alias for List. The "layout" attribute for the Map -/// field must have the same contents as a List. -struct Map FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef MapBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_KEYSSORTED = 4 - }; - /// Set to true if the keys within each value are sorted - bool keysSorted() const { - return GetField<uint8_t>(VT_KEYSSORTED, 0) != 0; - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<uint8_t>(verifier, VT_KEYSSORTED) && - verifier.EndTable(); - } -}; - -struct MapBuilder { - typedef Map Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_keysSorted(bool keysSorted) { - fbb_.AddElement<uint8_t>(Map::VT_KEYSSORTED, static_cast<uint8_t>(keysSorted), 0); - } - explicit MapBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - MapBuilder &operator=(const MapBuilder &); - flatbuffers::Offset<Map> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<Map>(end); - return o; - } -}; - -inline flatbuffers::Offset<Map> CreateMap( - flatbuffers::FlatBufferBuilder &_fbb, - bool keysSorted = false) { - MapBuilder builder_(_fbb); - builder_.add_keysSorted(keysSorted); - return builder_.Finish(); -} - -/// A union is a complex type with children in Field -/// By default ids in the type vector refer to the offsets in the children -/// optionally typeIds provides an indirection between the child offset and the type id -/// for each child typeIds[offset] is the id used in the type vector -struct Union FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef UnionBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_MODE = 4, - VT_TYPEIDS = 6 - }; - org::apache::arrow::flatbuf::UnionMode mode() const { - return static_cast<org::apache::arrow::flatbuf::UnionMode>(GetField<int16_t>(VT_MODE, 0)); - } - const flatbuffers::Vector<int32_t> *typeIds() const { - return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_TYPEIDS); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int16_t>(verifier, VT_MODE) && - VerifyOffset(verifier, VT_TYPEIDS) && - verifier.VerifyVector(typeIds()) && - verifier.EndTable(); - } -}; - -struct UnionBuilder { - typedef Union Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_mode(org::apache::arrow::flatbuf::UnionMode mode) { - fbb_.AddElement<int16_t>(Union::VT_MODE, static_cast<int16_t>(mode), 0); - } - void add_typeIds(flatbuffers::Offset<flatbuffers::Vector<int32_t>> typeIds) { - fbb_.AddOffset(Union::VT_TYPEIDS, typeIds); - } - explicit UnionBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - UnionBuilder &operator=(const UnionBuilder &); - flatbuffers::Offset<Union> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<Union>(end); - return o; - } -}; - -inline flatbuffers::Offset<Union> CreateUnion( - flatbuffers::FlatBufferBuilder &_fbb, - org::apache::arrow::flatbuf::UnionMode mode = org::apache::arrow::flatbuf::UnionMode::Sparse, - flatbuffers::Offset<flatbuffers::Vector<int32_t>> typeIds = 0) { - UnionBuilder builder_(_fbb); - builder_.add_typeIds(typeIds); - builder_.add_mode(mode); - return builder_.Finish(); -} - -inline flatbuffers::Offset<Union> CreateUnionDirect( - flatbuffers::FlatBufferBuilder &_fbb, - org::apache::arrow::flatbuf::UnionMode mode = org::apache::arrow::flatbuf::UnionMode::Sparse, - const std::vector<int32_t> *typeIds = nullptr) { - auto typeIds__ = typeIds ? _fbb.CreateVector<int32_t>(*typeIds) : 0; - return org::apache::arrow::flatbuf::CreateUnion( - _fbb, - mode, - typeIds__); -} - -struct Int FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef IntBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_BITWIDTH = 4, - VT_IS_SIGNED = 6 - }; - int32_t bitWidth() const { - return GetField<int32_t>(VT_BITWIDTH, 0); - } - bool is_signed() const { - return GetField<uint8_t>(VT_IS_SIGNED, 0) != 0; - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int32_t>(verifier, VT_BITWIDTH) && - VerifyField<uint8_t>(verifier, VT_IS_SIGNED) && - verifier.EndTable(); - } -}; - -struct IntBuilder { - typedef Int Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_bitWidth(int32_t bitWidth) { - fbb_.AddElement<int32_t>(Int::VT_BITWIDTH, bitWidth, 0); - } - void add_is_signed(bool is_signed) { - fbb_.AddElement<uint8_t>(Int::VT_IS_SIGNED, static_cast<uint8_t>(is_signed), 0); - } - explicit IntBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - IntBuilder &operator=(const IntBuilder &); - flatbuffers::Offset<Int> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<Int>(end); - return o; - } -}; - -inline flatbuffers::Offset<Int> CreateInt( - flatbuffers::FlatBufferBuilder &_fbb, - int32_t bitWidth = 0, - bool is_signed = false) { - IntBuilder builder_(_fbb); - builder_.add_bitWidth(bitWidth); - builder_.add_is_signed(is_signed); - return builder_.Finish(); -} - -struct FloatingPoint FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef FloatingPointBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_PRECISION = 4 - }; - org::apache::arrow::flatbuf::Precision precision() const { - return static_cast<org::apache::arrow::flatbuf::Precision>(GetField<int16_t>(VT_PRECISION, 0)); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int16_t>(verifier, VT_PRECISION) && - verifier.EndTable(); - } -}; - -struct FloatingPointBuilder { - typedef FloatingPoint Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_precision(org::apache::arrow::flatbuf::Precision precision) { - fbb_.AddElement<int16_t>(FloatingPoint::VT_PRECISION, static_cast<int16_t>(precision), 0); - } - explicit FloatingPointBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - FloatingPointBuilder &operator=(const FloatingPointBuilder &); - flatbuffers::Offset<FloatingPoint> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<FloatingPoint>(end); - return o; - } -}; - -inline flatbuffers::Offset<FloatingPoint> CreateFloatingPoint( - flatbuffers::FlatBufferBuilder &_fbb, - org::apache::arrow::flatbuf::Precision precision = org::apache::arrow::flatbuf::Precision::HALF) { - FloatingPointBuilder builder_(_fbb); - builder_.add_precision(precision); - return builder_.Finish(); -} - -/// Unicode with UTF-8 encoding -struct Utf8 FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef Utf8Builder Builder; - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - verifier.EndTable(); - } -}; - -struct Utf8Builder { - typedef Utf8 Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - explicit Utf8Builder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - Utf8Builder &operator=(const Utf8Builder &); - flatbuffers::Offset<Utf8> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<Utf8>(end); - return o; - } -}; - -inline flatbuffers::Offset<Utf8> CreateUtf8( - flatbuffers::FlatBufferBuilder &_fbb) { - Utf8Builder builder_(_fbb); - return builder_.Finish(); -} - -/// Opaque binary data -struct Binary FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef BinaryBuilder Builder; - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - verifier.EndTable(); - } -}; - -struct BinaryBuilder { - typedef Binary Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - explicit BinaryBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - BinaryBuilder &operator=(const BinaryBuilder &); - flatbuffers::Offset<Binary> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<Binary>(end); - return o; - } -}; - -inline flatbuffers::Offset<Binary> CreateBinary( - flatbuffers::FlatBufferBuilder &_fbb) { - BinaryBuilder builder_(_fbb); - return builder_.Finish(); -} - -/// Same as Utf8, but with 64-bit offsets, allowing to represent -/// extremely large data values. -struct LargeUtf8 FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef LargeUtf8Builder Builder; - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - verifier.EndTable(); - } -}; - -struct LargeUtf8Builder { - typedef LargeUtf8 Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - explicit LargeUtf8Builder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - LargeUtf8Builder &operator=(const LargeUtf8Builder &); - flatbuffers::Offset<LargeUtf8> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<LargeUtf8>(end); - return o; - } -}; - -inline flatbuffers::Offset<LargeUtf8> CreateLargeUtf8( - flatbuffers::FlatBufferBuilder &_fbb) { - LargeUtf8Builder builder_(_fbb); - return builder_.Finish(); -} - -/// Same as Binary, but with 64-bit offsets, allowing to represent -/// extremely large data values. -struct LargeBinary FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef LargeBinaryBuilder Builder; - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - verifier.EndTable(); - } -}; - -struct LargeBinaryBuilder { - typedef LargeBinary Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - explicit LargeBinaryBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - LargeBinaryBuilder &operator=(const LargeBinaryBuilder &); - flatbuffers::Offset<LargeBinary> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<LargeBinary>(end); - return o; - } -}; - -inline flatbuffers::Offset<LargeBinary> CreateLargeBinary( - flatbuffers::FlatBufferBuilder &_fbb) { - LargeBinaryBuilder builder_(_fbb); - return builder_.Finish(); -} - -struct FixedSizeBinary FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef FixedSizeBinaryBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_BYTEWIDTH = 4 - }; - /// Number of bytes per value - int32_t byteWidth() const { - return GetField<int32_t>(VT_BYTEWIDTH, 0); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int32_t>(verifier, VT_BYTEWIDTH) && - verifier.EndTable(); - } -}; - -struct FixedSizeBinaryBuilder { - typedef FixedSizeBinary Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_byteWidth(int32_t byteWidth) { - fbb_.AddElement<int32_t>(FixedSizeBinary::VT_BYTEWIDTH, byteWidth, 0); - } - explicit FixedSizeBinaryBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - FixedSizeBinaryBuilder &operator=(const FixedSizeBinaryBuilder &); - flatbuffers::Offset<FixedSizeBinary> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<FixedSizeBinary>(end); - return o; - } -}; - -inline flatbuffers::Offset<FixedSizeBinary> CreateFixedSizeBinary( - flatbuffers::FlatBufferBuilder &_fbb, - int32_t byteWidth = 0) { - FixedSizeBinaryBuilder builder_(_fbb); - builder_.add_byteWidth(byteWidth); - return builder_.Finish(); -} - -struct Bool FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef BoolBuilder Builder; - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - verifier.EndTable(); - } -}; - -struct BoolBuilder { - typedef Bool Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - explicit BoolBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - BoolBuilder &operator=(const BoolBuilder &); - flatbuffers::Offset<Bool> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<Bool>(end); - return o; - } -}; - -inline flatbuffers::Offset<Bool> CreateBool( - flatbuffers::FlatBufferBuilder &_fbb) { - BoolBuilder builder_(_fbb); - return builder_.Finish(); -} - -/// Exact decimal value represented as an integer value in two's -/// complement. Currently only 128-bit (16-byte) integers are used but this may -/// be expanded in the future. The representation uses the endianness indicated -/// in the Schema. -struct Decimal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef DecimalBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_PRECISION = 4, - VT_SCALE = 6, - VT_BITWIDTH = 8 - }; - /// Total number of decimal digits - int32_t precision() const { - return GetField<int32_t>(VT_PRECISION, 0); - } - /// Number of digits after the decimal point "." - int32_t scale() const { - return GetField<int32_t>(VT_SCALE, 0); - } - /// Number of bits per value. The only accepted width right now is 128 but - /// this field exists for forward compatibility so that other bit widths may - /// be supported in future format versions. We use bitWidth for consistency - /// with Int::bitWidth. - int32_t bitWidth() const { - return GetField<int32_t>(VT_BITWIDTH, 128); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int32_t>(verifier, VT_PRECISION) && - VerifyField<int32_t>(verifier, VT_SCALE) && - VerifyField<int32_t>(verifier, VT_BITWIDTH) && - verifier.EndTable(); - } -}; - -struct DecimalBuilder { - typedef Decimal Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_precision(int32_t precision) { - fbb_.AddElement<int32_t>(Decimal::VT_PRECISION, precision, 0); - } - void add_scale(int32_t scale) { - fbb_.AddElement<int32_t>(Decimal::VT_SCALE, scale, 0); - } - void add_bitWidth(int32_t bitWidth) { - fbb_.AddElement<int32_t>(Decimal::VT_BITWIDTH, bitWidth, 128); - } - explicit DecimalBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - DecimalBuilder &operator=(const DecimalBuilder &); - flatbuffers::Offset<Decimal> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<Decimal>(end); - return o; - } -}; - -inline flatbuffers::Offset<Decimal> CreateDecimal( - flatbuffers::FlatBufferBuilder &_fbb, - int32_t precision = 0, - int32_t scale = 0, - int32_t bitWidth = 128) { - DecimalBuilder builder_(_fbb); - builder_.add_bitWidth(bitWidth); - builder_.add_scale(scale); - builder_.add_precision(precision); - return builder_.Finish(); -} - -/// Date is either a 32-bit or 64-bit type representing elapsed time since UNIX -/// epoch (1970-01-01), stored in either of two units: -/// -/// * Milliseconds (64 bits) indicating UNIX time elapsed since the epoch (no -/// leap seconds), where the values are evenly divisible by 86400000 -/// * Days (32 bits) since the UNIX epoch -struct Date FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef DateBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_UNIT = 4 - }; - org::apache::arrow::flatbuf::DateUnit unit() const { - return static_cast<org::apache::arrow::flatbuf::DateUnit>(GetField<int16_t>(VT_UNIT, 1)); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int16_t>(verifier, VT_UNIT) && - verifier.EndTable(); - } -}; - -struct DateBuilder { - typedef Date Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_unit(org::apache::arrow::flatbuf::DateUnit unit) { - fbb_.AddElement<int16_t>(Date::VT_UNIT, static_cast<int16_t>(unit), 1); - } - explicit DateBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - DateBuilder &operator=(const DateBuilder &); - flatbuffers::Offset<Date> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<Date>(end); - return o; - } -}; - -inline flatbuffers::Offset<Date> CreateDate( - flatbuffers::FlatBufferBuilder &_fbb, - org::apache::arrow::flatbuf::DateUnit unit = org::apache::arrow::flatbuf::DateUnit::MILLISECOND) { - DateBuilder builder_(_fbb); - builder_.add_unit(unit); - return builder_.Finish(); -} - -/// Time type. The physical storage type depends on the unit -/// - SECOND and MILLISECOND: 32 bits -/// - MICROSECOND and NANOSECOND: 64 bits -struct Time FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef TimeBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_UNIT = 4, - VT_BITWIDTH = 6 - }; - org::apache::arrow::flatbuf::TimeUnit unit() const { - return static_cast<org::apache::arrow::flatbuf::TimeUnit>(GetField<int16_t>(VT_UNIT, 1)); - } - int32_t bitWidth() const { - return GetField<int32_t>(VT_BITWIDTH, 32); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int16_t>(verifier, VT_UNIT) && - VerifyField<int32_t>(verifier, VT_BITWIDTH) && - verifier.EndTable(); - } -}; - -struct TimeBuilder { - typedef Time Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_unit(org::apache::arrow::flatbuf::TimeUnit unit) { - fbb_.AddElement<int16_t>(Time::VT_UNIT, static_cast<int16_t>(unit), 1); - } - void add_bitWidth(int32_t bitWidth) { - fbb_.AddElement<int32_t>(Time::VT_BITWIDTH, bitWidth, 32); - } - explicit TimeBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - TimeBuilder &operator=(const TimeBuilder &); - flatbuffers::Offset<Time> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<Time>(end); - return o; - } -}; - -inline flatbuffers::Offset<Time> CreateTime( - flatbuffers::FlatBufferBuilder &_fbb, - org::apache::arrow::flatbuf::TimeUnit unit = org::apache::arrow::flatbuf::TimeUnit::MILLISECOND, - int32_t bitWidth = 32) { - TimeBuilder builder_(_fbb); - builder_.add_bitWidth(bitWidth); - builder_.add_unit(unit); - return builder_.Finish(); -} - -/// Time elapsed from the Unix epoch, 00:00:00.000 on 1 January 1970, excluding -/// leap seconds, as a 64-bit integer. Note that UNIX time does not include -/// leap seconds. -/// -/// The Timestamp metadata supports both "time zone naive" and "time zone -/// aware" timestamps. Read about the timezone attribute for more detail -struct Timestamp FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef TimestampBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_UNIT = 4, - VT_TIMEZONE = 6 - }; - org::apache::arrow::flatbuf::TimeUnit unit() const { - return static_cast<org::apache::arrow::flatbuf::TimeUnit>(GetField<int16_t>(VT_UNIT, 0)); - } - /// The time zone is a string indicating the name of a time zone, one of: - /// - /// * As used in the Olson time zone database (the "tz database" or - /// "tzdata"), such as "America/New_York" - /// * An absolute time zone offset of the form +XX:XX or -XX:XX, such as +07:30 - /// - /// Whether a timezone string is present indicates different semantics about - /// the data: - /// - /// * If the time zone is null or equal to an empty string, the data is "time - /// zone naive" and shall be displayed *as is* to the user, not localized - /// to the locale of the user. This data can be though of as UTC but - /// without having "UTC" as the time zone, it is not considered to be - /// localized to any time zone - /// - /// * If the time zone is set to a valid value, values can be displayed as - /// "localized" to that time zone, even though the underlying 64-bit - /// integers are identical to the same data stored in UTC. Converting - /// between time zones is a metadata-only operation and does not change the - /// underlying values - const flatbuffers::String *timezone() const { - return GetPointer<const flatbuffers::String *>(VT_TIMEZONE); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int16_t>(verifier, VT_UNIT) && - VerifyOffset(verifier, VT_TIMEZONE) && - verifier.VerifyString(timezone()) && - verifier.EndTable(); - } -}; - -struct TimestampBuilder { - typedef Timestamp Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_unit(org::apache::arrow::flatbuf::TimeUnit unit) { - fbb_.AddElement<int16_t>(Timestamp::VT_UNIT, static_cast<int16_t>(unit), 0); - } - void add_timezone(flatbuffers::Offset<flatbuffers::String> timezone) { - fbb_.AddOffset(Timestamp::VT_TIMEZONE, timezone); - } - explicit TimestampBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - TimestampBuilder &operator=(const TimestampBuilder &); - flatbuffers::Offset<Timestamp> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<Timestamp>(end); - return o; - } -}; - -inline flatbuffers::Offset<Timestamp> CreateTimestamp( - flatbuffers::FlatBufferBuilder &_fbb, - org::apache::arrow::flatbuf::TimeUnit unit = org::apache::arrow::flatbuf::TimeUnit::SECOND, - flatbuffers::Offset<flatbuffers::String> timezone = 0) { - TimestampBuilder builder_(_fbb); - builder_.add_timezone(timezone); - builder_.add_unit(unit); - return builder_.Finish(); -} - -inline flatbuffers::Offset<Timestamp> CreateTimestampDirect( - flatbuffers::FlatBufferBuilder &_fbb, - org::apache::arrow::flatbuf::TimeUnit unit = org::apache::arrow::flatbuf::TimeUnit::SECOND, - const char *timezone = nullptr) { - auto timezone__ = timezone ? _fbb.CreateString(timezone) : 0; - return org::apache::arrow::flatbuf::CreateTimestamp( - _fbb, - unit, - timezone__); -} - -struct Interval FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef IntervalBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_UNIT = 4 - }; - org::apache::arrow::flatbuf::IntervalUnit unit() const { - return static_cast<org::apache::arrow::flatbuf::IntervalUnit>(GetField<int16_t>(VT_UNIT, 0)); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int16_t>(verifier, VT_UNIT) && - verifier.EndTable(); - } -}; - -struct IntervalBuilder { - typedef Interval Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_unit(org::apache::arrow::flatbuf::IntervalUnit unit) { - fbb_.AddElement<int16_t>(Interval::VT_UNIT, static_cast<int16_t>(unit), 0); - } - explicit IntervalBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - IntervalBuilder &operator=(const IntervalBuilder &); - flatbuffers::Offset<Interval> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<Interval>(end); - return o; - } -}; - -inline flatbuffers::Offset<Interval> CreateInterval( - flatbuffers::FlatBufferBuilder &_fbb, - org::apache::arrow::flatbuf::IntervalUnit unit = org::apache::arrow::flatbuf::IntervalUnit::YEAR_MONTH) { - IntervalBuilder builder_(_fbb); - builder_.add_unit(unit); - return builder_.Finish(); -} - -struct Duration FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef DurationBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_UNIT = 4 - }; - org::apache::arrow::flatbuf::TimeUnit unit() const { - return static_cast<org::apache::arrow::flatbuf::TimeUnit>(GetField<int16_t>(VT_UNIT, 1)); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int16_t>(verifier, VT_UNIT) && - verifier.EndTable(); - } -}; - -struct DurationBuilder { - typedef Duration Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_unit(org::apache::arrow::flatbuf::TimeUnit unit) { - fbb_.AddElement<int16_t>(Duration::VT_UNIT, static_cast<int16_t>(unit), 1); - } - explicit DurationBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - DurationBuilder &operator=(const DurationBuilder &); - flatbuffers::Offset<Duration> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<Duration>(end); - return o; - } -}; - -inline flatbuffers::Offset<Duration> CreateDuration( - flatbuffers::FlatBufferBuilder &_fbb, - org::apache::arrow::flatbuf::TimeUnit unit = org::apache::arrow::flatbuf::TimeUnit::MILLISECOND) { - DurationBuilder builder_(_fbb); - builder_.add_unit(unit); - return builder_.Finish(); -} - -/// ---------------------------------------------------------------------- -/// user defined key value pairs to add custom metadata to arrow -/// key namespacing is the responsibility of the user -struct KeyValue FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef KeyValueBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_KEY = 4, - VT_VALUE = 6 - }; - const flatbuffers::String *key() const { - return GetPointer<const flatbuffers::String *>(VT_KEY); - } - const flatbuffers::String *value() const { - return GetPointer<const flatbuffers::String *>(VT_VALUE); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyOffset(verifier, VT_KEY) && - verifier.VerifyString(key()) && - VerifyOffset(verifier, VT_VALUE) && - verifier.VerifyString(value()) && - verifier.EndTable(); - } -}; - -struct KeyValueBuilder { - typedef KeyValue Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_key(flatbuffers::Offset<flatbuffers::String> key) { - fbb_.AddOffset(KeyValue::VT_KEY, key); - } - void add_value(flatbuffers::Offset<flatbuffers::String> value) { - fbb_.AddOffset(KeyValue::VT_VALUE, value); - } - explicit KeyValueBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - KeyValueBuilder &operator=(const KeyValueBuilder &); - flatbuffers::Offset<KeyValue> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<KeyValue>(end); - return o; - } -}; - -inline flatbuffers::Offset<KeyValue> CreateKeyValue( - flatbuffers::FlatBufferBuilder &_fbb, - flatbuffers::Offset<flatbuffers::String> key = 0, - flatbuffers::Offset<flatbuffers::String> value = 0) { - KeyValueBuilder builder_(_fbb); - builder_.add_value(value); - builder_.add_key(key); - return builder_.Finish(); -} - -inline flatbuffers::Offset<KeyValue> CreateKeyValueDirect( - flatbuffers::FlatBufferBuilder &_fbb, - const char *key = nullptr, - const char *value = nullptr) { - auto key__ = key ? _fbb.CreateString(key) : 0; - auto value__ = value ? _fbb.CreateString(value) : 0; - return org::apache::arrow::flatbuf::CreateKeyValue( - _fbb, - key__, - value__); -} - -struct DictionaryEncoding FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef DictionaryEncodingBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_ID = 4, - VT_INDEXTYPE = 6, - VT_ISORDERED = 8, - VT_DICTIONARYKIND = 10 - }; - /// The known dictionary id in the application where this data is used. In - /// the file or streaming formats, the dictionary ids are found in the - /// DictionaryBatch messages - int64_t id() const { - return GetField<int64_t>(VT_ID, 0); - } - /// The dictionary indices are constrained to be non-negative integers. If - /// this field is null, the indices must be signed int32. To maximize - /// cross-language compatibility and performance, implementations are - /// recommended to prefer signed integer types over unsigned integer types - /// and to avoid uint64 indices unless they are required by an application. - const org::apache::arrow::flatbuf::Int *indexType() const { - return GetPointer<const org::apache::arrow::flatbuf::Int *>(VT_INDEXTYPE); - } - /// By default, dictionaries are not ordered, or the order does not have - /// semantic meaning. In some statistical, applications, dictionary-encoding - /// is used to represent ordered categorical data, and we provide a way to - /// preserve that metadata here - bool isOrdered() const { - return GetField<uint8_t>(VT_ISORDERED, 0) != 0; - } - org::apache::arrow::flatbuf::DictionaryKind dictionaryKind() const { - return static_cast<org::apache::arrow::flatbuf::DictionaryKind>(GetField<int16_t>(VT_DICTIONARYKIND, 0)); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int64_t>(verifier, VT_ID) && - VerifyOffset(verifier, VT_INDEXTYPE) && - verifier.VerifyTable(indexType()) && - VerifyField<uint8_t>(verifier, VT_ISORDERED) && - VerifyField<int16_t>(verifier, VT_DICTIONARYKIND) && - verifier.EndTable(); - } -}; - -struct DictionaryEncodingBuilder { - typedef DictionaryEncoding Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_id(int64_t id) { - fbb_.AddElement<int64_t>(DictionaryEncoding::VT_ID, id, 0); - } - void add_indexType(flatbuffers::Offset<org::apache::arrow::flatbuf::Int> indexType) { - fbb_.AddOffset(DictionaryEncoding::VT_INDEXTYPE, indexType); - } - void add_isOrdered(bool isOrdered) { - fbb_.AddElement<uint8_t>(DictionaryEncoding::VT_ISORDERED, static_cast<uint8_t>(isOrdered), 0); - } - void add_dictionaryKind(org::apache::arrow::flatbuf::DictionaryKind dictionaryKind) { - fbb_.AddElement<int16_t>(DictionaryEncoding::VT_DICTIONARYKIND, static_cast<int16_t>(dictionaryKind), 0); - } - explicit DictionaryEncodingBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - DictionaryEncodingBuilder &operator=(const DictionaryEncodingBuilder &); - flatbuffers::Offset<DictionaryEncoding> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<DictionaryEncoding>(end); - return o; - } -}; - -inline flatbuffers::Offset<DictionaryEncoding> CreateDictionaryEncoding( - flatbuffers::FlatBufferBuilder &_fbb, - int64_t id = 0, - flatbuffers::Offset<org::apache::arrow::flatbuf::Int> indexType = 0, - bool isOrdered = false, - org::apache::arrow::flatbuf::DictionaryKind dictionaryKind = org::apache::arrow::flatbuf::DictionaryKind::DenseArray) { - DictionaryEncodingBuilder builder_(_fbb); - builder_.add_id(id); - builder_.add_indexType(indexType); - builder_.add_dictionaryKind(dictionaryKind); - builder_.add_isOrdered(isOrdered); - return builder_.Finish(); -} - -/// ---------------------------------------------------------------------- -/// A field represents a named column in a record / row batch or child of a -/// nested type. -struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef FieldBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_NAME = 4, - VT_NULLABLE = 6, - VT_TYPE_TYPE = 8, - VT_TYPE = 10, - VT_DICTIONARY = 12, - VT_CHILDREN = 14, - VT_CUSTOM_METADATA = 16 - }; - /// Name is not required, in i.e. a List - const flatbuffers::String *name() const { - return GetPointer<const flatbuffers::String *>(VT_NAME); - } - /// Whether or not this field can contain nulls. Should be true in general. - bool nullable() const { - return GetField<uint8_t>(VT_NULLABLE, 0) != 0; - } - org::apache::arrow::flatbuf::Type type_type() const { - return static_cast<org::apache::arrow::flatbuf::Type>(GetField<uint8_t>(VT_TYPE_TYPE, 0)); - } - /// This is the type of the decoded value if the field is dictionary encoded. - const void *type() const { - return GetPointer<const void *>(VT_TYPE); - } - template<typename T> const T *type_as() const; - const org::apache::arrow::flatbuf::Null *type_as_Null() const { - return type_type() == org::apache::arrow::flatbuf::Type::Null ? static_cast<const org::apache::arrow::flatbuf::Null *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Int *type_as_Int() const { - return type_type() == org::apache::arrow::flatbuf::Type::Int ? static_cast<const org::apache::arrow::flatbuf::Int *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::FloatingPoint *type_as_FloatingPoint() const { - return type_type() == org::apache::arrow::flatbuf::Type::FloatingPoint ? static_cast<const org::apache::arrow::flatbuf::FloatingPoint *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Binary *type_as_Binary() const { - return type_type() == org::apache::arrow::flatbuf::Type::Binary ? static_cast<const org::apache::arrow::flatbuf::Binary *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Utf8 *type_as_Utf8() const { - return type_type() == org::apache::arrow::flatbuf::Type::Utf8 ? static_cast<const org::apache::arrow::flatbuf::Utf8 *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Bool *type_as_Bool() const { - return type_type() == org::apache::arrow::flatbuf::Type::Bool ? static_cast<const org::apache::arrow::flatbuf::Bool *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Decimal *type_as_Decimal() const { - return type_type() == org::apache::arrow::flatbuf::Type::Decimal ? static_cast<const org::apache::arrow::flatbuf::Decimal *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Date *type_as_Date() const { - return type_type() == org::apache::arrow::flatbuf::Type::Date ? static_cast<const org::apache::arrow::flatbuf::Date *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Time *type_as_Time() const { - return type_type() == org::apache::arrow::flatbuf::Type::Time ? static_cast<const org::apache::arrow::flatbuf::Time *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Timestamp *type_as_Timestamp() const { - return type_type() == org::apache::arrow::flatbuf::Type::Timestamp ? static_cast<const org::apache::arrow::flatbuf::Timestamp *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Interval *type_as_Interval() const { - return type_type() == org::apache::arrow::flatbuf::Type::Interval ? static_cast<const org::apache::arrow::flatbuf::Interval *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::List *type_as_List() const { - return type_type() == org::apache::arrow::flatbuf::Type::List ? static_cast<const org::apache::arrow::flatbuf::List *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Struct_ *type_as_Struct_() const { - return type_type() == org::apache::arrow::flatbuf::Type::Struct_ ? static_cast<const org::apache::arrow::flatbuf::Struct_ *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Union *type_as_Union() const { - return type_type() == org::apache::arrow::flatbuf::Type::Union ? static_cast<const org::apache::arrow::flatbuf::Union *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::FixedSizeBinary *type_as_FixedSizeBinary() const { - return type_type() == org::apache::arrow::flatbuf::Type::FixedSizeBinary ? static_cast<const org::apache::arrow::flatbuf::FixedSizeBinary *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::FixedSizeList *type_as_FixedSizeList() const { - return type_type() == org::apache::arrow::flatbuf::Type::FixedSizeList ? static_cast<const org::apache::arrow::flatbuf::FixedSizeList *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Map *type_as_Map() const { - return type_type() == org::apache::arrow::flatbuf::Type::Map ? static_cast<const org::apache::arrow::flatbuf::Map *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Duration *type_as_Duration() const { - return type_type() == org::apache::arrow::flatbuf::Type::Duration ? static_cast<const org::apache::arrow::flatbuf::Duration *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::LargeBinary *type_as_LargeBinary() const { - return type_type() == org::apache::arrow::flatbuf::Type::LargeBinary ? static_cast<const org::apache::arrow::flatbuf::LargeBinary *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::LargeUtf8 *type_as_LargeUtf8() const { - return type_type() == org::apache::arrow::flatbuf::Type::LargeUtf8 ? static_cast<const org::apache::arrow::flatbuf::LargeUtf8 *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::LargeList *type_as_LargeList() const { - return type_type() == org::apache::arrow::flatbuf::Type::LargeList ? static_cast<const org::apache::arrow::flatbuf::LargeList *>(type()) : nullptr; - } - /// Present only if the field is dictionary encoded. - const org::apache::arrow::flatbuf::DictionaryEncoding *dictionary() const { - return GetPointer<const org::apache::arrow::flatbuf::DictionaryEncoding *>(VT_DICTIONARY); - } - /// children apply only to nested data types like Struct, List and Union. For - /// primitive types children will have length 0. - const flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::Field>> *children() const { - return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::Field>> *>(VT_CHILDREN); - } - /// User-defined metadata - const flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>> *custom_metadata() const { - return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>> *>(VT_CUSTOM_METADATA); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyOffset(verifier, VT_NAME) && - verifier.VerifyString(name()) && - VerifyField<uint8_t>(verifier, VT_NULLABLE) && - VerifyField<uint8_t>(verifier, VT_TYPE_TYPE) && - VerifyOffset(verifier, VT_TYPE) && - VerifyType(verifier, type(), type_type()) && - VerifyOffset(verifier, VT_DICTIONARY) && - verifier.VerifyTable(dictionary()) && - VerifyOffset(verifier, VT_CHILDREN) && - verifier.VerifyVector(children()) && - verifier.VerifyVectorOfTables(children()) && - VerifyOffset(verifier, VT_CUSTOM_METADATA) && - verifier.VerifyVector(custom_metadata()) && - verifier.VerifyVectorOfTables(custom_metadata()) && - verifier.EndTable(); - } -}; - -template<> inline const org::apache::arrow::flatbuf::Null *Field::type_as<org::apache::arrow::flatbuf::Null>() const { - return type_as_Null(); -} - -template<> inline const org::apache::arrow::flatbuf::Int *Field::type_as<org::apache::arrow::flatbuf::Int>() const { - return type_as_Int(); -} - -template<> inline const org::apache::arrow::flatbuf::FloatingPoint *Field::type_as<org::apache::arrow::flatbuf::FloatingPoint>() const { - return type_as_FloatingPoint(); -} - -template<> inline const org::apache::arrow::flatbuf::Binary *Field::type_as<org::apache::arrow::flatbuf::Binary>() const { - return type_as_Binary(); -} - -template<> inline const org::apache::arrow::flatbuf::Utf8 *Field::type_as<org::apache::arrow::flatbuf::Utf8>() const { - return type_as_Utf8(); -} - -template<> inline const org::apache::arrow::flatbuf::Bool *Field::type_as<org::apache::arrow::flatbuf::Bool>() const { - return type_as_Bool(); -} - -template<> inline const org::apache::arrow::flatbuf::Decimal *Field::type_as<org::apache::arrow::flatbuf::Decimal>() const { - return type_as_Decimal(); -} - -template<> inline const org::apache::arrow::flatbuf::Date *Field::type_as<org::apache::arrow::flatbuf::Date>() const { - return type_as_Date(); -} - -template<> inline const org::apache::arrow::flatbuf::Time *Field::type_as<org::apache::arrow::flatbuf::Time>() const { - return type_as_Time(); -} - -template<> inline const org::apache::arrow::flatbuf::Timestamp *Field::type_as<org::apache::arrow::flatbuf::Timestamp>() const { - return type_as_Timestamp(); -} - -template<> inline const org::apache::arrow::flatbuf::Interval *Field::type_as<org::apache::arrow::flatbuf::Interval>() const { - return type_as_Interval(); -} - -template<> inline const org::apache::arrow::flatbuf::List *Field::type_as<org::apache::arrow::flatbuf::List>() const { - return type_as_List(); -} - -template<> inline const org::apache::arrow::flatbuf::Struct_ *Field::type_as<org::apache::arrow::flatbuf::Struct_>() const { - return type_as_Struct_(); -} - -template<> inline const org::apache::arrow::flatbuf::Union *Field::type_as<org::apache::arrow::flatbuf::Union>() const { - return type_as_Union(); -} - -template<> inline const org::apache::arrow::flatbuf::FixedSizeBinary *Field::type_as<org::apache::arrow::flatbuf::FixedSizeBinary>() const { - return type_as_FixedSizeBinary(); -} - -template<> inline const org::apache::arrow::flatbuf::FixedSizeList *Field::type_as<org::apache::arrow::flatbuf::FixedSizeList>() const { - return type_as_FixedSizeList(); -} - -template<> inline const org::apache::arrow::flatbuf::Map *Field::type_as<org::apache::arrow::flatbuf::Map>() const { - return type_as_Map(); -} - -template<> inline const org::apache::arrow::flatbuf::Duration *Field::type_as<org::apache::arrow::flatbuf::Duration>() const { - return type_as_Duration(); -} - -template<> inline const org::apache::arrow::flatbuf::LargeBinary *Field::type_as<org::apache::arrow::flatbuf::LargeBinary>() const { - return type_as_LargeBinary(); -} - -template<> inline const org::apache::arrow::flatbuf::LargeUtf8 *Field::type_as<org::apache::arrow::flatbuf::LargeUtf8>() const { - return type_as_LargeUtf8(); -} - -template<> inline const org::apache::arrow::flatbuf::LargeList *Field::type_as<org::apache::arrow::flatbuf::LargeList>() const { - return type_as_LargeList(); -} - -struct FieldBuilder { - typedef Field Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_name(flatbuffers::Offset<flatbuffers::String> name) { - fbb_.AddOffset(Field::VT_NAME, name); - } - void add_nullable(bool nullable) { - fbb_.AddElement<uint8_t>(Field::VT_NULLABLE, static_cast<uint8_t>(nullable), 0); - } - void add_type_type(org::apache::arrow::flatbuf::Type type_type) { - fbb_.AddElement<uint8_t>(Field::VT_TYPE_TYPE, static_cast<uint8_t>(type_type), 0); - } - void add_type(flatbuffers::Offset<void> type) { - fbb_.AddOffset(Field::VT_TYPE, type); - } - void add_dictionary(flatbuffers::Offset<org::apache::arrow::flatbuf::DictionaryEncoding> dictionary) { - fbb_.AddOffset(Field::VT_DICTIONARY, dictionary); - } - void add_children(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::Field>>> children) { - fbb_.AddOffset(Field::VT_CHILDREN, children); - } - void add_custom_metadata(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>>> custom_metadata) { - fbb_.AddOffset(Field::VT_CUSTOM_METADATA, custom_metadata); - } - explicit FieldBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - FieldBuilder &operator=(const FieldBuilder &); - flatbuffers::Offset<Field> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<Field>(end); - return o; - } -}; - -inline flatbuffers::Offset<Field> CreateField( - flatbuffers::FlatBufferBuilder &_fbb, - flatbuffers::Offset<flatbuffers::String> name = 0, - bool nullable = false, - org::apache::arrow::flatbuf::Type type_type = org::apache::arrow::flatbuf::Type::NONE, - flatbuffers::Offset<void> type = 0, - flatbuffers::Offset<org::apache::arrow::flatbuf::DictionaryEncoding> dictionary = 0, - flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::Field>>> children = 0, - flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>>> custom_metadata = 0) { - FieldBuilder builder_(_fbb); - builder_.add_custom_metadata(custom_metadata); - builder_.add_children(children); - builder_.add_dictionary(dictionary); - builder_.add_type(type); - builder_.add_name(name); - builder_.add_type_type(type_type); - builder_.add_nullable(nullable); - return builder_.Finish(); -} - -inline flatbuffers::Offset<Field> CreateFieldDirect( - flatbuffers::FlatBufferBuilder &_fbb, - const char *name = nullptr, - bool nullable = false, - org::apache::arrow::flatbuf::Type type_type = org::apache::arrow::flatbuf::Type::NONE, - flatbuffers::Offset<void> type = 0, - flatbuffers::Offset<org::apache::arrow::flatbuf::DictionaryEncoding> dictionary = 0, - const std::vector<flatbuffers::Offset<org::apache::arrow::flatbuf::Field>> *children = nullptr, - const std::vector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>> *custom_metadata = nullptr) { - auto name__ = name ? _fbb.CreateString(name) : 0; - auto children__ = children ? _fbb.CreateVector<flatbuffers::Offset<org::apache::arrow::flatbuf::Field>>(*children) : 0; - auto custom_metadata__ = custom_metadata ? _fbb.CreateVector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>>(*custom_metadata) : 0; - return org::apache::arrow::flatbuf::CreateField( - _fbb, - name__, - nullable, - type_type, - type, - dictionary, - children__, - custom_metadata__); -} - -/// ---------------------------------------------------------------------- -/// A Schema describes the columns in a row batch -struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef SchemaBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_ENDIANNESS = 4, - VT_FIELDS = 6, - VT_CUSTOM_METADATA = 8, - VT_FEATURES = 10 - }; - /// endianness of the buffer - /// it is Little Endian by default - /// if endianness doesn't match the underlying system then the vectors need to be converted - org::apache::arrow::flatbuf::Endianness endianness() const { - return static_cast<org::apache::arrow::flatbuf::Endianness>(GetField<int16_t>(VT_ENDIANNESS, 0)); - } - const flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::Field>> *fields() const { - return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::Field>> *>(VT_FIELDS); - } - const flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>> *custom_metadata() const { - return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>> *>(VT_CUSTOM_METADATA); - } - /// Features used in the stream/file. - const flatbuffers::Vector<int64_t> *features() const { - return GetPointer<const flatbuffers::Vector<int64_t> *>(VT_FEATURES); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int16_t>(verifier, VT_ENDIANNESS) && - VerifyOffset(verifier, VT_FIELDS) && - verifier.VerifyVector(fields()) && - verifier.VerifyVectorOfTables(fields()) && - VerifyOffset(verifier, VT_CUSTOM_METADATA) && - verifier.VerifyVector(custom_metadata()) && - verifier.VerifyVectorOfTables(custom_metadata()) && - VerifyOffset(verifier, VT_FEATURES) && - verifier.VerifyVector(features()) && - verifier.EndTable(); - } -}; - -struct SchemaBuilder { - typedef Schema Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_endianness(org::apache::arrow::flatbuf::Endianness endianness) { - fbb_.AddElement<int16_t>(Schema::VT_ENDIANNESS, static_cast<int16_t>(endianness), 0); - } - void add_fields(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::Field>>> fields) { - fbb_.AddOffset(Schema::VT_FIELDS, fields); - } - void add_custom_metadata(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>>> custom_metadata) { - fbb_.AddOffset(Schema::VT_CUSTOM_METADATA, custom_metadata); - } - void add_features(flatbuffers::Offset<flatbuffers::Vector<int64_t>> features) { - fbb_.AddOffset(Schema::VT_FEATURES, features); - } - explicit SchemaBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - SchemaBuilder &operator=(const SchemaBuilder &); - flatbuffers::Offset<Schema> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<Schema>(end); - return o; - } -}; - -inline flatbuffers::Offset<Schema> CreateSchema( - flatbuffers::FlatBufferBuilder &_fbb, - org::apache::arrow::flatbuf::Endianness endianness = org::apache::arrow::flatbuf::Endianness::Little, - flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::Field>>> fields = 0, - flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>>> custom_metadata = 0, - flatbuffers::Offset<flatbuffers::Vector<int64_t>> features = 0) { - SchemaBuilder builder_(_fbb); - builder_.add_features(features); - builder_.add_custom_metadata(custom_metadata); - builder_.add_fields(fields); - builder_.add_endianness(endianness); - return builder_.Finish(); -} - -inline flatbuffers::Offset<Schema> CreateSchemaDirect( - flatbuffers::FlatBufferBuilder &_fbb, - org::apache::arrow::flatbuf::Endianness endianness = org::apache::arrow::flatbuf::Endianness::Little, - const std::vector<flatbuffers::Offset<org::apache::arrow::flatbuf::Field>> *fields = nullptr, - const std::vector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>> *custom_metadata = nullptr, - const std::vector<int64_t> *features = nullptr) { - auto fields__ = fields ? _fbb.CreateVector<flatbuffers::Offset<org::apache::arrow::flatbuf::Field>>(*fields) : 0; - auto custom_metadata__ = custom_metadata ? _fbb.CreateVector<flatbuffers::Offset<org::apache::arrow::flatbuf::KeyValue>>(*custom_metadata) : 0; - auto features__ = features ? _fbb.CreateVector<int64_t>(*features) : 0; - return org::apache::arrow::flatbuf::CreateSchema( - _fbb, - endianness, - fields__, - custom_metadata__, - features__); -} - -inline bool VerifyType(flatbuffers::Verifier &verifier, const void *obj, Type type) { - switch (type) { - case Type::NONE: { - return true; - } - case Type::Null: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::Null *>(obj); - return verifier.VerifyTable(ptr); - } - case Type::Int: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::Int *>(obj); - return verifier.VerifyTable(ptr); - } - case Type::FloatingPoint: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::FloatingPoint *>(obj); - return verifier.VerifyTable(ptr); - } - case Type::Binary: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::Binary *>(obj); - return verifier.VerifyTable(ptr); - } - case Type::Utf8: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::Utf8 *>(obj); - return verifier.VerifyTable(ptr); - } - case Type::Bool: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::Bool *>(obj); - return verifier.VerifyTable(ptr); - } - case Type::Decimal: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::Decimal *>(obj); - return verifier.VerifyTable(ptr); - } - case Type::Date: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::Date *>(obj); - return verifier.VerifyTable(ptr); - } - case Type::Time: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::Time *>(obj); - return verifier.VerifyTable(ptr); - } - case Type::Timestamp: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::Timestamp *>(obj); - return verifier.VerifyTable(ptr); - } - case Type::Interval: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::Interval *>(obj); - return verifier.VerifyTable(ptr); - } - case Type::List: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::List *>(obj); - return verifier.VerifyTable(ptr); - } - case Type::Struct_: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::Struct_ *>(obj); - return verifier.VerifyTable(ptr); - } - case Type::Union: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::Union *>(obj); - return verifier.VerifyTable(ptr); - } - case Type::FixedSizeBinary: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::FixedSizeBinary *>(obj); - return verifier.VerifyTable(ptr); - } - case Type::FixedSizeList: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::FixedSizeList *>(obj); - return verifier.VerifyTable(ptr); - } - case Type::Map: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::Map *>(obj); - return verifier.VerifyTable(ptr); - } - case Type::Duration: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::Duration *>(obj); - return verifier.VerifyTable(ptr); - } - case Type::LargeBinary: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::LargeBinary *>(obj); - return verifier.VerifyTable(ptr); - } - case Type::LargeUtf8: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::LargeUtf8 *>(obj); - return verifier.VerifyTable(ptr); - } - case Type::LargeList: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::LargeList *>(obj); - return verifier.VerifyTable(ptr); - } - default: return true; - } -} - -inline bool VerifyTypeVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types) { - if (!values || !types) return !values && !types; - if (values->size() != types->size()) return false; - for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) { - if (!VerifyType( - verifier, values->Get(i), types->GetEnum<Type>(i))) { - return false; - } - } - return true; -} - -inline const org::apache::arrow::flatbuf::Schema *GetSchema(const void *buf) { - return flatbuffers::GetRoot<org::apache::arrow::flatbuf::Schema>(buf); -} - -inline const org::apache::arrow::flatbuf::Schema *GetSizePrefixedSchema(const void *buf) { - return flatbuffers::GetSizePrefixedRoot<org::apache::arrow::flatbuf::Schema>(buf); -} - -inline bool VerifySchemaBuffer( - flatbuffers::Verifier &verifier) { - return verifier.VerifyBuffer<org::apache::arrow::flatbuf::Schema>(nullptr); -} - -inline bool VerifySizePrefixedSchemaBuffer( - flatbuffers::Verifier &verifier) { - return verifier.VerifySizePrefixedBuffer<org::apache::arrow::flatbuf::Schema>(nullptr); -} - -inline void FinishSchemaBuffer( - flatbuffers::FlatBufferBuilder &fbb, - flatbuffers::Offset<org::apache::arrow::flatbuf::Schema> root) { - fbb.Finish(root); -} - -inline void FinishSizePrefixedSchemaBuffer( - flatbuffers::FlatBufferBuilder &fbb, - flatbuffers::Offset<org::apache::arrow::flatbuf::Schema> root) { - fbb.FinishSizePrefixed(root); -} - -} // namespace flatbuf -} // namespace arrow -} // namespace apache -} // namespace org - -#endif // FLATBUFFERS_GENERATED_SCHEMA_ORG_APACHE_ARROW_FLATBUF_H_ diff --git a/contrib/libs/apache/arrow/cpp/src/generated/SparseTensor.fbs b/contrib/libs/apache/arrow/cpp/src/generated/SparseTensor.fbs new file mode 100644 index 0000000000..a6fd2f9e74 --- /dev/null +++ b/contrib/libs/apache/arrow/cpp/src/generated/SparseTensor.fbs @@ -0,0 +1,228 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +/// EXPERIMENTAL: Metadata for n-dimensional sparse arrays, aka "sparse tensors". +/// Arrow implementations in general are not required to implement this type + +include "Tensor.fbs"; + +namespace org.apache.arrow.flatbuf; + +/// ---------------------------------------------------------------------- +/// EXPERIMENTAL: Data structures for sparse tensors + +/// Coordinate (COO) format of sparse tensor index. +/// +/// COO's index list are represented as a NxM matrix, +/// where N is the number of non-zero values, +/// and M is the number of dimensions of a sparse tensor. +/// +/// indicesBuffer stores the location and size of the data of this indices +/// matrix. The value type and the stride of the indices matrix is +/// specified in indicesType and indicesStrides fields. +/// +/// For example, let X be a 2x3x4x5 tensor, and it has the following +/// 6 non-zero values: +/// ```text +/// X[0, 1, 2, 0] := 1 +/// X[1, 1, 2, 3] := 2 +/// X[0, 2, 1, 0] := 3 +/// X[0, 1, 3, 0] := 4 +/// X[0, 1, 2, 1] := 5 +/// X[1, 2, 0, 4] := 6 +/// ``` +/// In COO format, the index matrix of X is the following 4x6 matrix: +/// ```text +/// [[0, 0, 0, 0, 1, 1], +/// [1, 1, 1, 2, 1, 2], +/// [2, 2, 3, 1, 2, 0], +/// [0, 1, 0, 0, 3, 4]] +/// ``` +/// When isCanonical is true, the indices is sorted in lexicographical order +/// (row-major order), and it does not have duplicated entries. Otherwise, +/// the indices may not be sorted, or may have duplicated entries. +table SparseTensorIndexCOO { + /// The type of values in indicesBuffer + indicesType: Int (required); + + /// Non-negative byte offsets to advance one value cell along each dimension + /// If omitted, default to row-major order (C-like). + indicesStrides: [long]; + + /// The location and size of the indices matrix's data + indicesBuffer: Buffer (required); + + /// This flag is true if and only if the indices matrix is sorted in + /// row-major order, and does not have duplicated entries. + /// This sort order is the same as of Tensorflow's SparseTensor, + /// but it is inverse order of SciPy's canonical coo_matrix + /// (SciPy employs column-major order for its coo_matrix). + isCanonical: bool; +} + +enum SparseMatrixCompressedAxis: short { Row, Column } + +/// Compressed Sparse format, that is matrix-specific. +table SparseMatrixIndexCSX { + /// Which axis, row or column, is compressed + compressedAxis: SparseMatrixCompressedAxis; + + /// The type of values in indptrBuffer + indptrType: Int (required); + + /// indptrBuffer stores the location and size of indptr array that + /// represents the range of the rows. + /// The i-th row spans from `indptr[i]` to `indptr[i+1]` in the data. + /// The length of this array is 1 + (the number of rows), and the type + /// of index value is long. + /// + /// For example, let X be the following 6x4 matrix: + /// ```text + /// X := [[0, 1, 2, 0], + /// [0, 0, 3, 0], + /// [0, 4, 0, 5], + /// [0, 0, 0, 0], + /// [6, 0, 7, 8], + /// [0, 9, 0, 0]]. + /// ``` + /// The array of non-zero values in X is: + /// ```text + /// values(X) = [1, 2, 3, 4, 5, 6, 7, 8, 9]. + /// ``` + /// And the indptr of X is: + /// ```text + /// indptr(X) = [0, 2, 3, 5, 5, 8, 10]. + /// ``` + indptrBuffer: Buffer (required); + + /// The type of values in indicesBuffer + indicesType: Int (required); + + /// indicesBuffer stores the location and size of the array that + /// contains the column indices of the corresponding non-zero values. + /// The type of index value is long. + /// + /// For example, the indices of the above X is: + /// ```text + /// indices(X) = [1, 2, 2, 1, 3, 0, 2, 3, 1]. + /// ``` + /// Note that the indices are sorted in lexicographical order for each row. + indicesBuffer: Buffer (required); +} + +/// Compressed Sparse Fiber (CSF) sparse tensor index. +table SparseTensorIndexCSF { + /// CSF is a generalization of compressed sparse row (CSR) index. + /// See [smith2017knl](http://shaden.io/pub-files/smith2017knl.pdf) + /// + /// CSF index recursively compresses each dimension of a tensor into a set + /// of prefix trees. Each path from a root to leaf forms one tensor + /// non-zero index. CSF is implemented with two arrays of buffers and one + /// arrays of integers. + /// + /// For example, let X be a 2x3x4x5 tensor and let it have the following + /// 8 non-zero values: + /// ```text + /// X[0, 0, 0, 1] := 1 + /// X[0, 0, 0, 2] := 2 + /// X[0, 1, 0, 0] := 3 + /// X[0, 1, 0, 2] := 4 + /// X[0, 1, 1, 0] := 5 + /// X[1, 1, 1, 0] := 6 + /// X[1, 1, 1, 1] := 7 + /// X[1, 1, 1, 2] := 8 + /// ``` + /// As a prefix tree this would be represented as: + /// ```text + /// 0 1 + /// / \ | + /// 0 1 1 + /// / / \ | + /// 0 0 1 1 + /// /| /| | /| | + /// 1 2 0 2 0 0 1 2 + /// ``` + /// The type of values in indptrBuffers + indptrType: Int (required); + + /// indptrBuffers stores the sparsity structure. + /// Each two consecutive dimensions in a tensor correspond to a buffer in + /// indptrBuffers. A pair of consecutive values at `indptrBuffers[dim][i]` + /// and `indptrBuffers[dim][i + 1]` signify a range of nodes in + /// `indicesBuffers[dim + 1]` who are children of `indicesBuffers[dim][i]` node. + /// + /// For example, the indptrBuffers for the above X is: + /// ```text + /// indptrBuffer(X) = [ + /// [0, 2, 3], + /// [0, 1, 3, 4], + /// [0, 2, 4, 5, 8] + /// ]. + /// ``` + indptrBuffers: [Buffer] (required); + + /// The type of values in indicesBuffers + indicesType: Int (required); + + /// indicesBuffers stores values of nodes. + /// Each tensor dimension corresponds to a buffer in indicesBuffers. + /// For example, the indicesBuffers for the above X is: + /// ```text + /// indicesBuffer(X) = [ + /// [0, 1], + /// [0, 1, 1], + /// [0, 0, 1, 1], + /// [1, 2, 0, 2, 0, 0, 1, 2] + /// ]. + /// ``` + indicesBuffers: [Buffer] (required); + + /// axisOrder stores the sequence in which dimensions were traversed to + /// produce the prefix tree. + /// For example, the axisOrder for the above X is: + /// ```text + /// axisOrder(X) = [0, 1, 2, 3]. + /// ``` + axisOrder: [int] (required); +} + +union SparseTensorIndex { + SparseTensorIndexCOO, + SparseMatrixIndexCSX, + SparseTensorIndexCSF +} + +table SparseTensor { + /// The type of data contained in a value cell. + /// Currently only fixed-width value types are supported, + /// no strings or nested types. + type: Type (required); + + /// The dimensions of the tensor, optionally named. + shape: [TensorDim] (required); + + /// The number of non-zero values in a sparse tensor. + non_zero_length: long; + + /// Sparse tensor index + sparseIndex: SparseTensorIndex (required); + + /// The location and size of the tensor's data + data: Buffer (required); +} + +root_type SparseTensor; diff --git a/contrib/libs/apache/arrow/cpp/src/generated/SparseTensor_generated.h b/contrib/libs/apache/arrow/cpp/src/generated/SparseTensor_generated.h deleted file mode 100644 index ec4d414d4f..0000000000 --- a/contrib/libs/apache/arrow/cpp/src/generated/SparseTensor_generated.h +++ /dev/null @@ -1,913 +0,0 @@ -// automatically generated by the FlatBuffers compiler, do not modify - - -#ifndef FLATBUFFERS_GENERATED_SPARSETENSOR_ORG_APACHE_ARROW_FLATBUF_H_ -#define FLATBUFFERS_GENERATED_SPARSETENSOR_ORG_APACHE_ARROW_FLATBUF_H_ - -#include "flatbuffers/flatbuffers.h" - -#include "Schema_generated.h" -#include "Tensor_generated.h" - -namespace org { -namespace apache { -namespace arrow { -namespace flatbuf { - -struct SparseTensorIndexCOO; -struct SparseTensorIndexCOOBuilder; - -struct SparseMatrixIndexCSX; -struct SparseMatrixIndexCSXBuilder; - -struct SparseTensorIndexCSF; -struct SparseTensorIndexCSFBuilder; - -struct SparseTensor; -struct SparseTensorBuilder; - -enum class SparseMatrixCompressedAxis : int16_t { - Row = 0, - Column = 1, - MIN = Row, - MAX = Column -}; - -inline const SparseMatrixCompressedAxis (&EnumValuesSparseMatrixCompressedAxis())[2] { - static const SparseMatrixCompressedAxis values[] = { - SparseMatrixCompressedAxis::Row, - SparseMatrixCompressedAxis::Column - }; - return values; -} - -inline const char * const *EnumNamesSparseMatrixCompressedAxis() { - static const char * const names[3] = { - "Row", - "Column", - nullptr - }; - return names; -} - -inline const char *EnumNameSparseMatrixCompressedAxis(SparseMatrixCompressedAxis e) { - if (flatbuffers::IsOutRange(e, SparseMatrixCompressedAxis::Row, SparseMatrixCompressedAxis::Column)) return ""; - const size_t index = static_cast<size_t>(e); - return EnumNamesSparseMatrixCompressedAxis()[index]; -} - -enum class SparseTensorIndex : uint8_t { - NONE = 0, - SparseTensorIndexCOO = 1, - SparseMatrixIndexCSX = 2, - SparseTensorIndexCSF = 3, - MIN = NONE, - MAX = SparseTensorIndexCSF -}; - -inline const SparseTensorIndex (&EnumValuesSparseTensorIndex())[4] { - static const SparseTensorIndex values[] = { - SparseTensorIndex::NONE, - SparseTensorIndex::SparseTensorIndexCOO, - SparseTensorIndex::SparseMatrixIndexCSX, - SparseTensorIndex::SparseTensorIndexCSF - }; - return values; -} - -inline const char * const *EnumNamesSparseTensorIndex() { - static const char * const names[5] = { - "NONE", - "SparseTensorIndexCOO", - "SparseMatrixIndexCSX", - "SparseTensorIndexCSF", - nullptr - }; - return names; -} - -inline const char *EnumNameSparseTensorIndex(SparseTensorIndex e) { - if (flatbuffers::IsOutRange(e, SparseTensorIndex::NONE, SparseTensorIndex::SparseTensorIndexCSF)) return ""; - const size_t index = static_cast<size_t>(e); - return EnumNamesSparseTensorIndex()[index]; -} - -template<typename T> struct SparseTensorIndexTraits { - static const SparseTensorIndex enum_value = SparseTensorIndex::NONE; -}; - -template<> struct SparseTensorIndexTraits<org::apache::arrow::flatbuf::SparseTensorIndexCOO> { - static const SparseTensorIndex enum_value = SparseTensorIndex::SparseTensorIndexCOO; -}; - -template<> struct SparseTensorIndexTraits<org::apache::arrow::flatbuf::SparseMatrixIndexCSX> { - static const SparseTensorIndex enum_value = SparseTensorIndex::SparseMatrixIndexCSX; -}; - -template<> struct SparseTensorIndexTraits<org::apache::arrow::flatbuf::SparseTensorIndexCSF> { - static const SparseTensorIndex enum_value = SparseTensorIndex::SparseTensorIndexCSF; -}; - -bool VerifySparseTensorIndex(flatbuffers::Verifier &verifier, const void *obj, SparseTensorIndex type); -bool VerifySparseTensorIndexVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types); - -/// ---------------------------------------------------------------------- -/// EXPERIMENTAL: Data structures for sparse tensors -/// Coordinate (COO) format of sparse tensor index. -/// -/// COO's index list are represented as a NxM matrix, -/// where N is the number of non-zero values, -/// and M is the number of dimensions of a sparse tensor. -/// -/// indicesBuffer stores the location and size of the data of this indices -/// matrix. The value type and the stride of the indices matrix is -/// specified in indicesType and indicesStrides fields. -/// -/// For example, let X be a 2x3x4x5 tensor, and it has the following -/// 6 non-zero values: -/// -/// X[0, 1, 2, 0] := 1 -/// X[1, 1, 2, 3] := 2 -/// X[0, 2, 1, 0] := 3 -/// X[0, 1, 3, 0] := 4 -/// X[0, 1, 2, 1] := 5 -/// X[1, 2, 0, 4] := 6 -/// -/// In COO format, the index matrix of X is the following 4x6 matrix: -/// -/// [[0, 0, 0, 0, 1, 1], -/// [1, 1, 1, 2, 1, 2], -/// [2, 2, 3, 1, 2, 0], -/// [0, 1, 0, 0, 3, 4]] -/// -/// Note that the indices are sorted in lexicographical order. -struct SparseTensorIndexCOO FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef SparseTensorIndexCOOBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_INDICESTYPE = 4, - VT_INDICESSTRIDES = 6, - VT_INDICESBUFFER = 8, - VT_ISCANONICAL = 10 - }; - /// The type of values in indicesBuffer - const org::apache::arrow::flatbuf::Int *indicesType() const { - return GetPointer<const org::apache::arrow::flatbuf::Int *>(VT_INDICESTYPE); - } - /// Non-negative byte offsets to advance one value cell along each dimension - /// If omitted, default to row-major order (C-like). - const flatbuffers::Vector<int64_t> *indicesStrides() const { - return GetPointer<const flatbuffers::Vector<int64_t> *>(VT_INDICESSTRIDES); - } - /// The location and size of the indices matrix's data - const org::apache::arrow::flatbuf::Buffer *indicesBuffer() const { - return GetStruct<const org::apache::arrow::flatbuf::Buffer *>(VT_INDICESBUFFER); - } - /// The canonicality flag - bool isCanonical() const { - return GetField<uint8_t>(VT_ISCANONICAL, 0) != 0; - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyOffsetRequired(verifier, VT_INDICESTYPE) && - verifier.VerifyTable(indicesType()) && - VerifyOffset(verifier, VT_INDICESSTRIDES) && - verifier.VerifyVector(indicesStrides()) && - VerifyFieldRequired<org::apache::arrow::flatbuf::Buffer>(verifier, VT_INDICESBUFFER) && - VerifyField<uint8_t>(verifier, VT_ISCANONICAL) && - verifier.EndTable(); - } -}; - -struct SparseTensorIndexCOOBuilder { - typedef SparseTensorIndexCOO Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_indicesType(flatbuffers::Offset<org::apache::arrow::flatbuf::Int> indicesType) { - fbb_.AddOffset(SparseTensorIndexCOO::VT_INDICESTYPE, indicesType); - } - void add_indicesStrides(flatbuffers::Offset<flatbuffers::Vector<int64_t>> indicesStrides) { - fbb_.AddOffset(SparseTensorIndexCOO::VT_INDICESSTRIDES, indicesStrides); - } - void add_indicesBuffer(const org::apache::arrow::flatbuf::Buffer *indicesBuffer) { - fbb_.AddStruct(SparseTensorIndexCOO::VT_INDICESBUFFER, indicesBuffer); - } - void add_isCanonical(bool isCanonical) { - fbb_.AddElement<uint8_t>(SparseTensorIndexCOO::VT_ISCANONICAL, static_cast<uint8_t>(isCanonical), 0); - } - explicit SparseTensorIndexCOOBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - SparseTensorIndexCOOBuilder &operator=(const SparseTensorIndexCOOBuilder &); - flatbuffers::Offset<SparseTensorIndexCOO> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<SparseTensorIndexCOO>(end); - fbb_.Required(o, SparseTensorIndexCOO::VT_INDICESTYPE); - fbb_.Required(o, SparseTensorIndexCOO::VT_INDICESBUFFER); - return o; - } -}; - -inline flatbuffers::Offset<SparseTensorIndexCOO> CreateSparseTensorIndexCOO( - flatbuffers::FlatBufferBuilder &_fbb, - flatbuffers::Offset<org::apache::arrow::flatbuf::Int> indicesType = 0, - flatbuffers::Offset<flatbuffers::Vector<int64_t>> indicesStrides = 0, - const org::apache::arrow::flatbuf::Buffer *indicesBuffer = 0, - bool isCanonical = false) { - SparseTensorIndexCOOBuilder builder_(_fbb); - builder_.add_indicesBuffer(indicesBuffer); - builder_.add_indicesStrides(indicesStrides); - builder_.add_indicesType(indicesType); - builder_.add_isCanonical(isCanonical); - return builder_.Finish(); -} - -inline flatbuffers::Offset<SparseTensorIndexCOO> CreateSparseTensorIndexCOODirect( - flatbuffers::FlatBufferBuilder &_fbb, - flatbuffers::Offset<org::apache::arrow::flatbuf::Int> indicesType = 0, - const std::vector<int64_t> *indicesStrides = nullptr, - const org::apache::arrow::flatbuf::Buffer *indicesBuffer = 0, - bool isCanonical = false) { - auto indicesStrides__ = indicesStrides ? _fbb.CreateVector<int64_t>(*indicesStrides) : 0; - return org::apache::arrow::flatbuf::CreateSparseTensorIndexCOO( - _fbb, - indicesType, - indicesStrides__, - indicesBuffer, - isCanonical); -} - -/// Compressed Sparse format, that is matrix-specific. -struct SparseMatrixIndexCSX FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef SparseMatrixIndexCSXBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_COMPRESSEDAXIS = 4, - VT_INDPTRTYPE = 6, - VT_INDPTRBUFFER = 8, - VT_INDICESTYPE = 10, - VT_INDICESBUFFER = 12 - }; - /// Which axis, row or column, is compressed - org::apache::arrow::flatbuf::SparseMatrixCompressedAxis compressedAxis() const { - return static_cast<org::apache::arrow::flatbuf::SparseMatrixCompressedAxis>(GetField<int16_t>(VT_COMPRESSEDAXIS, 0)); - } - /// The type of values in indptrBuffer - const org::apache::arrow::flatbuf::Int *indptrType() const { - return GetPointer<const org::apache::arrow::flatbuf::Int *>(VT_INDPTRTYPE); - } - /// indptrBuffer stores the location and size of indptr array that - /// represents the range of the rows. - /// The i-th row spans from indptr[i] to indptr[i+1] in the data. - /// The length of this array is 1 + (the number of rows), and the type - /// of index value is long. - /// - /// For example, let X be the following 6x4 matrix: - /// - /// X := [[0, 1, 2, 0], - /// [0, 0, 3, 0], - /// [0, 4, 0, 5], - /// [0, 0, 0, 0], - /// [6, 0, 7, 8], - /// [0, 9, 0, 0]]. - /// - /// The array of non-zero values in X is: - /// - /// values(X) = [1, 2, 3, 4, 5, 6, 7, 8, 9]. - /// - /// And the indptr of X is: - /// - /// indptr(X) = [0, 2, 3, 5, 5, 8, 10]. - const org::apache::arrow::flatbuf::Buffer *indptrBuffer() const { - return GetStruct<const org::apache::arrow::flatbuf::Buffer *>(VT_INDPTRBUFFER); - } - /// The type of values in indicesBuffer - const org::apache::arrow::flatbuf::Int *indicesType() const { - return GetPointer<const org::apache::arrow::flatbuf::Int *>(VT_INDICESTYPE); - } - /// indicesBuffer stores the location and size of the array that - /// contains the column indices of the corresponding non-zero values. - /// The type of index value is long. - /// - /// For example, the indices of the above X is: - /// - /// indices(X) = [1, 2, 2, 1, 3, 0, 2, 3, 1]. - /// - /// Note that the indices are sorted in lexicographical order for each row. - const org::apache::arrow::flatbuf::Buffer *indicesBuffer() const { - return GetStruct<const org::apache::arrow::flatbuf::Buffer *>(VT_INDICESBUFFER); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int16_t>(verifier, VT_COMPRESSEDAXIS) && - VerifyOffsetRequired(verifier, VT_INDPTRTYPE) && - verifier.VerifyTable(indptrType()) && - VerifyFieldRequired<org::apache::arrow::flatbuf::Buffer>(verifier, VT_INDPTRBUFFER) && - VerifyOffsetRequired(verifier, VT_INDICESTYPE) && - verifier.VerifyTable(indicesType()) && - VerifyFieldRequired<org::apache::arrow::flatbuf::Buffer>(verifier, VT_INDICESBUFFER) && - verifier.EndTable(); - } -}; - -struct SparseMatrixIndexCSXBuilder { - typedef SparseMatrixIndexCSX Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_compressedAxis(org::apache::arrow::flatbuf::SparseMatrixCompressedAxis compressedAxis) { - fbb_.AddElement<int16_t>(SparseMatrixIndexCSX::VT_COMPRESSEDAXIS, static_cast<int16_t>(compressedAxis), 0); - } - void add_indptrType(flatbuffers::Offset<org::apache::arrow::flatbuf::Int> indptrType) { - fbb_.AddOffset(SparseMatrixIndexCSX::VT_INDPTRTYPE, indptrType); - } - void add_indptrBuffer(const org::apache::arrow::flatbuf::Buffer *indptrBuffer) { - fbb_.AddStruct(SparseMatrixIndexCSX::VT_INDPTRBUFFER, indptrBuffer); - } - void add_indicesType(flatbuffers::Offset<org::apache::arrow::flatbuf::Int> indicesType) { - fbb_.AddOffset(SparseMatrixIndexCSX::VT_INDICESTYPE, indicesType); - } - void add_indicesBuffer(const org::apache::arrow::flatbuf::Buffer *indicesBuffer) { - fbb_.AddStruct(SparseMatrixIndexCSX::VT_INDICESBUFFER, indicesBuffer); - } - explicit SparseMatrixIndexCSXBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - SparseMatrixIndexCSXBuilder &operator=(const SparseMatrixIndexCSXBuilder &); - flatbuffers::Offset<SparseMatrixIndexCSX> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<SparseMatrixIndexCSX>(end); - fbb_.Required(o, SparseMatrixIndexCSX::VT_INDPTRTYPE); - fbb_.Required(o, SparseMatrixIndexCSX::VT_INDPTRBUFFER); - fbb_.Required(o, SparseMatrixIndexCSX::VT_INDICESTYPE); - fbb_.Required(o, SparseMatrixIndexCSX::VT_INDICESBUFFER); - return o; - } -}; - -inline flatbuffers::Offset<SparseMatrixIndexCSX> CreateSparseMatrixIndexCSX( - flatbuffers::FlatBufferBuilder &_fbb, - org::apache::arrow::flatbuf::SparseMatrixCompressedAxis compressedAxis = org::apache::arrow::flatbuf::SparseMatrixCompressedAxis::Row, - flatbuffers::Offset<org::apache::arrow::flatbuf::Int> indptrType = 0, - const org::apache::arrow::flatbuf::Buffer *indptrBuffer = 0, - flatbuffers::Offset<org::apache::arrow::flatbuf::Int> indicesType = 0, - const org::apache::arrow::flatbuf::Buffer *indicesBuffer = 0) { - SparseMatrixIndexCSXBuilder builder_(_fbb); - builder_.add_indicesBuffer(indicesBuffer); - builder_.add_indicesType(indicesType); - builder_.add_indptrBuffer(indptrBuffer); - builder_.add_indptrType(indptrType); - builder_.add_compressedAxis(compressedAxis); - return builder_.Finish(); -} - -/// Compressed Sparse Fiber (CSF) sparse tensor index. -struct SparseTensorIndexCSF FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef SparseTensorIndexCSFBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_INDPTRTYPE = 4, - VT_INDPTRBUFFERS = 6, - VT_INDICESTYPE = 8, - VT_INDICESBUFFERS = 10, - VT_AXISORDER = 12 - }; - /// CSF is a generalization of compressed sparse row (CSR) index. - /// See [smith2017knl]: http://shaden.io/pub-files/smith2017knl.pdf - /// - /// CSF index recursively compresses each dimension of a tensor into a set - /// of prefix trees. Each path from a root to leaf forms one tensor - /// non-zero index. CSF is implemented with two arrays of buffers and one - /// arrays of integers. - /// - /// For example, let X be a 2x3x4x5 tensor and let it have the following - /// 8 non-zero values: - /// - /// X[0, 0, 0, 1] := 1 - /// X[0, 0, 0, 2] := 2 - /// X[0, 1, 0, 0] := 3 - /// X[0, 1, 0, 2] := 4 - /// X[0, 1, 1, 0] := 5 - /// X[1, 1, 1, 0] := 6 - /// X[1, 1, 1, 1] := 7 - /// X[1, 1, 1, 2] := 8 - /// - /// As a prefix tree this would be represented as: - /// - /// 0 1 - /// / \ | - /// 0 1 1 - /// / / \ | - /// 0 0 1 1 - /// /| /| | /| | - /// 1 2 0 2 0 0 1 2 - /// The type of values in indptrBuffers - const org::apache::arrow::flatbuf::Int *indptrType() const { - return GetPointer<const org::apache::arrow::flatbuf::Int *>(VT_INDPTRTYPE); - } - /// indptrBuffers stores the sparsity structure. - /// Each two consecutive dimensions in a tensor correspond to a buffer in - /// indptrBuffers. A pair of consecutive values at indptrBuffers[dim][i] - /// and indptrBuffers[dim][i + 1] signify a range of nodes in - /// indicesBuffers[dim + 1] who are children of indicesBuffers[dim][i] node. - /// - /// For example, the indptrBuffers for the above X is: - /// - /// indptrBuffer(X) = [ - /// [0, 2, 3], - /// [0, 1, 3, 4], - /// [0, 2, 4, 5, 8] - /// ]. - /// - const flatbuffers::Vector<const org::apache::arrow::flatbuf::Buffer *> *indptrBuffers() const { - return GetPointer<const flatbuffers::Vector<const org::apache::arrow::flatbuf::Buffer *> *>(VT_INDPTRBUFFERS); - } - /// The type of values in indicesBuffers - const org::apache::arrow::flatbuf::Int *indicesType() const { - return GetPointer<const org::apache::arrow::flatbuf::Int *>(VT_INDICESTYPE); - } - /// indicesBuffers stores values of nodes. - /// Each tensor dimension corresponds to a buffer in indicesBuffers. - /// For example, the indicesBuffers for the above X is: - /// - /// indicesBuffer(X) = [ - /// [0, 1], - /// [0, 1, 1], - /// [0, 0, 1, 1], - /// [1, 2, 0, 2, 0, 0, 1, 2] - /// ]. - /// - const flatbuffers::Vector<const org::apache::arrow::flatbuf::Buffer *> *indicesBuffers() const { - return GetPointer<const flatbuffers::Vector<const org::apache::arrow::flatbuf::Buffer *> *>(VT_INDICESBUFFERS); - } - /// axisOrder stores the sequence in which dimensions were traversed to - /// produce the prefix tree. - /// For example, the axisOrder for the above X is: - /// - /// axisOrder(X) = [0, 1, 2, 3]. - /// - const flatbuffers::Vector<int32_t> *axisOrder() const { - return GetPointer<const flatbuffers::Vector<int32_t> *>(VT_AXISORDER); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyOffsetRequired(verifier, VT_INDPTRTYPE) && - verifier.VerifyTable(indptrType()) && - VerifyOffsetRequired(verifier, VT_INDPTRBUFFERS) && - verifier.VerifyVector(indptrBuffers()) && - VerifyOffsetRequired(verifier, VT_INDICESTYPE) && - verifier.VerifyTable(indicesType()) && - VerifyOffsetRequired(verifier, VT_INDICESBUFFERS) && - verifier.VerifyVector(indicesBuffers()) && - VerifyOffsetRequired(verifier, VT_AXISORDER) && - verifier.VerifyVector(axisOrder()) && - verifier.EndTable(); - } -}; - -struct SparseTensorIndexCSFBuilder { - typedef SparseTensorIndexCSF Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_indptrType(flatbuffers::Offset<org::apache::arrow::flatbuf::Int> indptrType) { - fbb_.AddOffset(SparseTensorIndexCSF::VT_INDPTRTYPE, indptrType); - } - void add_indptrBuffers(flatbuffers::Offset<flatbuffers::Vector<const org::apache::arrow::flatbuf::Buffer *>> indptrBuffers) { - fbb_.AddOffset(SparseTensorIndexCSF::VT_INDPTRBUFFERS, indptrBuffers); - } - void add_indicesType(flatbuffers::Offset<org::apache::arrow::flatbuf::Int> indicesType) { - fbb_.AddOffset(SparseTensorIndexCSF::VT_INDICESTYPE, indicesType); - } - void add_indicesBuffers(flatbuffers::Offset<flatbuffers::Vector<const org::apache::arrow::flatbuf::Buffer *>> indicesBuffers) { - fbb_.AddOffset(SparseTensorIndexCSF::VT_INDICESBUFFERS, indicesBuffers); - } - void add_axisOrder(flatbuffers::Offset<flatbuffers::Vector<int32_t>> axisOrder) { - fbb_.AddOffset(SparseTensorIndexCSF::VT_AXISORDER, axisOrder); - } - explicit SparseTensorIndexCSFBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - SparseTensorIndexCSFBuilder &operator=(const SparseTensorIndexCSFBuilder &); - flatbuffers::Offset<SparseTensorIndexCSF> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<SparseTensorIndexCSF>(end); - fbb_.Required(o, SparseTensorIndexCSF::VT_INDPTRTYPE); - fbb_.Required(o, SparseTensorIndexCSF::VT_INDPTRBUFFERS); - fbb_.Required(o, SparseTensorIndexCSF::VT_INDICESTYPE); - fbb_.Required(o, SparseTensorIndexCSF::VT_INDICESBUFFERS); - fbb_.Required(o, SparseTensorIndexCSF::VT_AXISORDER); - return o; - } -}; - -inline flatbuffers::Offset<SparseTensorIndexCSF> CreateSparseTensorIndexCSF( - flatbuffers::FlatBufferBuilder &_fbb, - flatbuffers::Offset<org::apache::arrow::flatbuf::Int> indptrType = 0, - flatbuffers::Offset<flatbuffers::Vector<const org::apache::arrow::flatbuf::Buffer *>> indptrBuffers = 0, - flatbuffers::Offset<org::apache::arrow::flatbuf::Int> indicesType = 0, - flatbuffers::Offset<flatbuffers::Vector<const org::apache::arrow::flatbuf::Buffer *>> indicesBuffers = 0, - flatbuffers::Offset<flatbuffers::Vector<int32_t>> axisOrder = 0) { - SparseTensorIndexCSFBuilder builder_(_fbb); - builder_.add_axisOrder(axisOrder); - builder_.add_indicesBuffers(indicesBuffers); - builder_.add_indicesType(indicesType); - builder_.add_indptrBuffers(indptrBuffers); - builder_.add_indptrType(indptrType); - return builder_.Finish(); -} - -inline flatbuffers::Offset<SparseTensorIndexCSF> CreateSparseTensorIndexCSFDirect( - flatbuffers::FlatBufferBuilder &_fbb, - flatbuffers::Offset<org::apache::arrow::flatbuf::Int> indptrType = 0, - const std::vector<org::apache::arrow::flatbuf::Buffer> *indptrBuffers = nullptr, - flatbuffers::Offset<org::apache::arrow::flatbuf::Int> indicesType = 0, - const std::vector<org::apache::arrow::flatbuf::Buffer> *indicesBuffers = nullptr, - const std::vector<int32_t> *axisOrder = nullptr) { - auto indptrBuffers__ = indptrBuffers ? _fbb.CreateVectorOfStructs<org::apache::arrow::flatbuf::Buffer>(*indptrBuffers) : 0; - auto indicesBuffers__ = indicesBuffers ? _fbb.CreateVectorOfStructs<org::apache::arrow::flatbuf::Buffer>(*indicesBuffers) : 0; - auto axisOrder__ = axisOrder ? _fbb.CreateVector<int32_t>(*axisOrder) : 0; - return org::apache::arrow::flatbuf::CreateSparseTensorIndexCSF( - _fbb, - indptrType, - indptrBuffers__, - indicesType, - indicesBuffers__, - axisOrder__); -} - -struct SparseTensor FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef SparseTensorBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_TYPE_TYPE = 4, - VT_TYPE = 6, - VT_SHAPE = 8, - VT_NON_ZERO_LENGTH = 10, - VT_SPARSEINDEX_TYPE = 12, - VT_SPARSEINDEX = 14, - VT_DATA = 16 - }; - org::apache::arrow::flatbuf::Type type_type() const { - return static_cast<org::apache::arrow::flatbuf::Type>(GetField<uint8_t>(VT_TYPE_TYPE, 0)); - } - /// The type of data contained in a value cell. - /// Currently only fixed-width value types are supported, - /// no strings or nested types. - const void *type() const { - return GetPointer<const void *>(VT_TYPE); - } - template<typename T> const T *type_as() const; - const org::apache::arrow::flatbuf::Null *type_as_Null() const { - return type_type() == org::apache::arrow::flatbuf::Type::Null ? static_cast<const org::apache::arrow::flatbuf::Null *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Int *type_as_Int() const { - return type_type() == org::apache::arrow::flatbuf::Type::Int ? static_cast<const org::apache::arrow::flatbuf::Int *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::FloatingPoint *type_as_FloatingPoint() const { - return type_type() == org::apache::arrow::flatbuf::Type::FloatingPoint ? static_cast<const org::apache::arrow::flatbuf::FloatingPoint *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Binary *type_as_Binary() const { - return type_type() == org::apache::arrow::flatbuf::Type::Binary ? static_cast<const org::apache::arrow::flatbuf::Binary *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Utf8 *type_as_Utf8() const { - return type_type() == org::apache::arrow::flatbuf::Type::Utf8 ? static_cast<const org::apache::arrow::flatbuf::Utf8 *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Bool *type_as_Bool() const { - return type_type() == org::apache::arrow::flatbuf::Type::Bool ? static_cast<const org::apache::arrow::flatbuf::Bool *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Decimal *type_as_Decimal() const { - return type_type() == org::apache::arrow::flatbuf::Type::Decimal ? static_cast<const org::apache::arrow::flatbuf::Decimal *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Date *type_as_Date() const { - return type_type() == org::apache::arrow::flatbuf::Type::Date ? static_cast<const org::apache::arrow::flatbuf::Date *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Time *type_as_Time() const { - return type_type() == org::apache::arrow::flatbuf::Type::Time ? static_cast<const org::apache::arrow::flatbuf::Time *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Timestamp *type_as_Timestamp() const { - return type_type() == org::apache::arrow::flatbuf::Type::Timestamp ? static_cast<const org::apache::arrow::flatbuf::Timestamp *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Interval *type_as_Interval() const { - return type_type() == org::apache::arrow::flatbuf::Type::Interval ? static_cast<const org::apache::arrow::flatbuf::Interval *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::List *type_as_List() const { - return type_type() == org::apache::arrow::flatbuf::Type::List ? static_cast<const org::apache::arrow::flatbuf::List *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Struct_ *type_as_Struct_() const { - return type_type() == org::apache::arrow::flatbuf::Type::Struct_ ? static_cast<const org::apache::arrow::flatbuf::Struct_ *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Union *type_as_Union() const { - return type_type() == org::apache::arrow::flatbuf::Type::Union ? static_cast<const org::apache::arrow::flatbuf::Union *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::FixedSizeBinary *type_as_FixedSizeBinary() const { - return type_type() == org::apache::arrow::flatbuf::Type::FixedSizeBinary ? static_cast<const org::apache::arrow::flatbuf::FixedSizeBinary *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::FixedSizeList *type_as_FixedSizeList() const { - return type_type() == org::apache::arrow::flatbuf::Type::FixedSizeList ? static_cast<const org::apache::arrow::flatbuf::FixedSizeList *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Map *type_as_Map() const { - return type_type() == org::apache::arrow::flatbuf::Type::Map ? static_cast<const org::apache::arrow::flatbuf::Map *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Duration *type_as_Duration() const { - return type_type() == org::apache::arrow::flatbuf::Type::Duration ? static_cast<const org::apache::arrow::flatbuf::Duration *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::LargeBinary *type_as_LargeBinary() const { - return type_type() == org::apache::arrow::flatbuf::Type::LargeBinary ? static_cast<const org::apache::arrow::flatbuf::LargeBinary *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::LargeUtf8 *type_as_LargeUtf8() const { - return type_type() == org::apache::arrow::flatbuf::Type::LargeUtf8 ? static_cast<const org::apache::arrow::flatbuf::LargeUtf8 *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::LargeList *type_as_LargeList() const { - return type_type() == org::apache::arrow::flatbuf::Type::LargeList ? static_cast<const org::apache::arrow::flatbuf::LargeList *>(type()) : nullptr; - } - /// The dimensions of the tensor, optionally named. - const flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::TensorDim>> *shape() const { - return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::TensorDim>> *>(VT_SHAPE); - } - /// The number of non-zero values in a sparse tensor. - int64_t non_zero_length() const { - return GetField<int64_t>(VT_NON_ZERO_LENGTH, 0); - } - org::apache::arrow::flatbuf::SparseTensorIndex sparseIndex_type() const { - return static_cast<org::apache::arrow::flatbuf::SparseTensorIndex>(GetField<uint8_t>(VT_SPARSEINDEX_TYPE, 0)); - } - /// Sparse tensor index - const void *sparseIndex() const { - return GetPointer<const void *>(VT_SPARSEINDEX); - } - template<typename T> const T *sparseIndex_as() const; - const org::apache::arrow::flatbuf::SparseTensorIndexCOO *sparseIndex_as_SparseTensorIndexCOO() const { - return sparseIndex_type() == org::apache::arrow::flatbuf::SparseTensorIndex::SparseTensorIndexCOO ? static_cast<const org::apache::arrow::flatbuf::SparseTensorIndexCOO *>(sparseIndex()) : nullptr; - } - const org::apache::arrow::flatbuf::SparseMatrixIndexCSX *sparseIndex_as_SparseMatrixIndexCSX() const { - return sparseIndex_type() == org::apache::arrow::flatbuf::SparseTensorIndex::SparseMatrixIndexCSX ? static_cast<const org::apache::arrow::flatbuf::SparseMatrixIndexCSX *>(sparseIndex()) : nullptr; - } - const org::apache::arrow::flatbuf::SparseTensorIndexCSF *sparseIndex_as_SparseTensorIndexCSF() const { - return sparseIndex_type() == org::apache::arrow::flatbuf::SparseTensorIndex::SparseTensorIndexCSF ? static_cast<const org::apache::arrow::flatbuf::SparseTensorIndexCSF *>(sparseIndex()) : nullptr; - } - /// The location and size of the tensor's data - const org::apache::arrow::flatbuf::Buffer *data() const { - return GetStruct<const org::apache::arrow::flatbuf::Buffer *>(VT_DATA); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<uint8_t>(verifier, VT_TYPE_TYPE) && - VerifyOffsetRequired(verifier, VT_TYPE) && - VerifyType(verifier, type(), type_type()) && - VerifyOffsetRequired(verifier, VT_SHAPE) && - verifier.VerifyVector(shape()) && - verifier.VerifyVectorOfTables(shape()) && - VerifyField<int64_t>(verifier, VT_NON_ZERO_LENGTH) && - VerifyField<uint8_t>(verifier, VT_SPARSEINDEX_TYPE) && - VerifyOffsetRequired(verifier, VT_SPARSEINDEX) && - VerifySparseTensorIndex(verifier, sparseIndex(), sparseIndex_type()) && - VerifyFieldRequired<org::apache::arrow::flatbuf::Buffer>(verifier, VT_DATA) && - verifier.EndTable(); - } -}; - -template<> inline const org::apache::arrow::flatbuf::Null *SparseTensor::type_as<org::apache::arrow::flatbuf::Null>() const { - return type_as_Null(); -} - -template<> inline const org::apache::arrow::flatbuf::Int *SparseTensor::type_as<org::apache::arrow::flatbuf::Int>() const { - return type_as_Int(); -} - -template<> inline const org::apache::arrow::flatbuf::FloatingPoint *SparseTensor::type_as<org::apache::arrow::flatbuf::FloatingPoint>() const { - return type_as_FloatingPoint(); -} - -template<> inline const org::apache::arrow::flatbuf::Binary *SparseTensor::type_as<org::apache::arrow::flatbuf::Binary>() const { - return type_as_Binary(); -} - -template<> inline const org::apache::arrow::flatbuf::Utf8 *SparseTensor::type_as<org::apache::arrow::flatbuf::Utf8>() const { - return type_as_Utf8(); -} - -template<> inline const org::apache::arrow::flatbuf::Bool *SparseTensor::type_as<org::apache::arrow::flatbuf::Bool>() const { - return type_as_Bool(); -} - -template<> inline const org::apache::arrow::flatbuf::Decimal *SparseTensor::type_as<org::apache::arrow::flatbuf::Decimal>() const { - return type_as_Decimal(); -} - -template<> inline const org::apache::arrow::flatbuf::Date *SparseTensor::type_as<org::apache::arrow::flatbuf::Date>() const { - return type_as_Date(); -} - -template<> inline const org::apache::arrow::flatbuf::Time *SparseTensor::type_as<org::apache::arrow::flatbuf::Time>() const { - return type_as_Time(); -} - -template<> inline const org::apache::arrow::flatbuf::Timestamp *SparseTensor::type_as<org::apache::arrow::flatbuf::Timestamp>() const { - return type_as_Timestamp(); -} - -template<> inline const org::apache::arrow::flatbuf::Interval *SparseTensor::type_as<org::apache::arrow::flatbuf::Interval>() const { - return type_as_Interval(); -} - -template<> inline const org::apache::arrow::flatbuf::List *SparseTensor::type_as<org::apache::arrow::flatbuf::List>() const { - return type_as_List(); -} - -template<> inline const org::apache::arrow::flatbuf::Struct_ *SparseTensor::type_as<org::apache::arrow::flatbuf::Struct_>() const { - return type_as_Struct_(); -} - -template<> inline const org::apache::arrow::flatbuf::Union *SparseTensor::type_as<org::apache::arrow::flatbuf::Union>() const { - return type_as_Union(); -} - -template<> inline const org::apache::arrow::flatbuf::FixedSizeBinary *SparseTensor::type_as<org::apache::arrow::flatbuf::FixedSizeBinary>() const { - return type_as_FixedSizeBinary(); -} - -template<> inline const org::apache::arrow::flatbuf::FixedSizeList *SparseTensor::type_as<org::apache::arrow::flatbuf::FixedSizeList>() const { - return type_as_FixedSizeList(); -} - -template<> inline const org::apache::arrow::flatbuf::Map *SparseTensor::type_as<org::apache::arrow::flatbuf::Map>() const { - return type_as_Map(); -} - -template<> inline const org::apache::arrow::flatbuf::Duration *SparseTensor::type_as<org::apache::arrow::flatbuf::Duration>() const { - return type_as_Duration(); -} - -template<> inline const org::apache::arrow::flatbuf::LargeBinary *SparseTensor::type_as<org::apache::arrow::flatbuf::LargeBinary>() const { - return type_as_LargeBinary(); -} - -template<> inline const org::apache::arrow::flatbuf::LargeUtf8 *SparseTensor::type_as<org::apache::arrow::flatbuf::LargeUtf8>() const { - return type_as_LargeUtf8(); -} - -template<> inline const org::apache::arrow::flatbuf::LargeList *SparseTensor::type_as<org::apache::arrow::flatbuf::LargeList>() const { - return type_as_LargeList(); -} - -template<> inline const org::apache::arrow::flatbuf::SparseTensorIndexCOO *SparseTensor::sparseIndex_as<org::apache::arrow::flatbuf::SparseTensorIndexCOO>() const { - return sparseIndex_as_SparseTensorIndexCOO(); -} - -template<> inline const org::apache::arrow::flatbuf::SparseMatrixIndexCSX *SparseTensor::sparseIndex_as<org::apache::arrow::flatbuf::SparseMatrixIndexCSX>() const { - return sparseIndex_as_SparseMatrixIndexCSX(); -} - -template<> inline const org::apache::arrow::flatbuf::SparseTensorIndexCSF *SparseTensor::sparseIndex_as<org::apache::arrow::flatbuf::SparseTensorIndexCSF>() const { - return sparseIndex_as_SparseTensorIndexCSF(); -} - -struct SparseTensorBuilder { - typedef SparseTensor Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_type_type(org::apache::arrow::flatbuf::Type type_type) { - fbb_.AddElement<uint8_t>(SparseTensor::VT_TYPE_TYPE, static_cast<uint8_t>(type_type), 0); - } - void add_type(flatbuffers::Offset<void> type) { - fbb_.AddOffset(SparseTensor::VT_TYPE, type); - } - void add_shape(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::TensorDim>>> shape) { - fbb_.AddOffset(SparseTensor::VT_SHAPE, shape); - } - void add_non_zero_length(int64_t non_zero_length) { - fbb_.AddElement<int64_t>(SparseTensor::VT_NON_ZERO_LENGTH, non_zero_length, 0); - } - void add_sparseIndex_type(org::apache::arrow::flatbuf::SparseTensorIndex sparseIndex_type) { - fbb_.AddElement<uint8_t>(SparseTensor::VT_SPARSEINDEX_TYPE, static_cast<uint8_t>(sparseIndex_type), 0); - } - void add_sparseIndex(flatbuffers::Offset<void> sparseIndex) { - fbb_.AddOffset(SparseTensor::VT_SPARSEINDEX, sparseIndex); - } - void add_data(const org::apache::arrow::flatbuf::Buffer *data) { - fbb_.AddStruct(SparseTensor::VT_DATA, data); - } - explicit SparseTensorBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - SparseTensorBuilder &operator=(const SparseTensorBuilder &); - flatbuffers::Offset<SparseTensor> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<SparseTensor>(end); - fbb_.Required(o, SparseTensor::VT_TYPE); - fbb_.Required(o, SparseTensor::VT_SHAPE); - fbb_.Required(o, SparseTensor::VT_SPARSEINDEX); - fbb_.Required(o, SparseTensor::VT_DATA); - return o; - } -}; - -inline flatbuffers::Offset<SparseTensor> CreateSparseTensor( - flatbuffers::FlatBufferBuilder &_fbb, - org::apache::arrow::flatbuf::Type type_type = org::apache::arrow::flatbuf::Type::NONE, - flatbuffers::Offset<void> type = 0, - flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::TensorDim>>> shape = 0, - int64_t non_zero_length = 0, - org::apache::arrow::flatbuf::SparseTensorIndex sparseIndex_type = org::apache::arrow::flatbuf::SparseTensorIndex::NONE, - flatbuffers::Offset<void> sparseIndex = 0, - const org::apache::arrow::flatbuf::Buffer *data = 0) { - SparseTensorBuilder builder_(_fbb); - builder_.add_non_zero_length(non_zero_length); - builder_.add_data(data); - builder_.add_sparseIndex(sparseIndex); - builder_.add_shape(shape); - builder_.add_type(type); - builder_.add_sparseIndex_type(sparseIndex_type); - builder_.add_type_type(type_type); - return builder_.Finish(); -} - -inline flatbuffers::Offset<SparseTensor> CreateSparseTensorDirect( - flatbuffers::FlatBufferBuilder &_fbb, - org::apache::arrow::flatbuf::Type type_type = org::apache::arrow::flatbuf::Type::NONE, - flatbuffers::Offset<void> type = 0, - const std::vector<flatbuffers::Offset<org::apache::arrow::flatbuf::TensorDim>> *shape = nullptr, - int64_t non_zero_length = 0, - org::apache::arrow::flatbuf::SparseTensorIndex sparseIndex_type = org::apache::arrow::flatbuf::SparseTensorIndex::NONE, - flatbuffers::Offset<void> sparseIndex = 0, - const org::apache::arrow::flatbuf::Buffer *data = 0) { - auto shape__ = shape ? _fbb.CreateVector<flatbuffers::Offset<org::apache::arrow::flatbuf::TensorDim>>(*shape) : 0; - return org::apache::arrow::flatbuf::CreateSparseTensor( - _fbb, - type_type, - type, - shape__, - non_zero_length, - sparseIndex_type, - sparseIndex, - data); -} - -inline bool VerifySparseTensorIndex(flatbuffers::Verifier &verifier, const void *obj, SparseTensorIndex type) { - switch (type) { - case SparseTensorIndex::NONE: { - return true; - } - case SparseTensorIndex::SparseTensorIndexCOO: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::SparseTensorIndexCOO *>(obj); - return verifier.VerifyTable(ptr); - } - case SparseTensorIndex::SparseMatrixIndexCSX: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::SparseMatrixIndexCSX *>(obj); - return verifier.VerifyTable(ptr); - } - case SparseTensorIndex::SparseTensorIndexCSF: { - auto ptr = reinterpret_cast<const org::apache::arrow::flatbuf::SparseTensorIndexCSF *>(obj); - return verifier.VerifyTable(ptr); - } - default: return true; - } -} - -inline bool VerifySparseTensorIndexVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types) { - if (!values || !types) return !values && !types; - if (values->size() != types->size()) return false; - for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) { - if (!VerifySparseTensorIndex( - verifier, values->Get(i), types->GetEnum<SparseTensorIndex>(i))) { - return false; - } - } - return true; -} - -inline const org::apache::arrow::flatbuf::SparseTensor *GetSparseTensor(const void *buf) { - return flatbuffers::GetRoot<org::apache::arrow::flatbuf::SparseTensor>(buf); -} - -inline const org::apache::arrow::flatbuf::SparseTensor *GetSizePrefixedSparseTensor(const void *buf) { - return flatbuffers::GetSizePrefixedRoot<org::apache::arrow::flatbuf::SparseTensor>(buf); -} - -inline bool VerifySparseTensorBuffer( - flatbuffers::Verifier &verifier) { - return verifier.VerifyBuffer<org::apache::arrow::flatbuf::SparseTensor>(nullptr); -} - -inline bool VerifySizePrefixedSparseTensorBuffer( - flatbuffers::Verifier &verifier) { - return verifier.VerifySizePrefixedBuffer<org::apache::arrow::flatbuf::SparseTensor>(nullptr); -} - -inline void FinishSparseTensorBuffer( - flatbuffers::FlatBufferBuilder &fbb, - flatbuffers::Offset<org::apache::arrow::flatbuf::SparseTensor> root) { - fbb.Finish(root); -} - -inline void FinishSizePrefixedSparseTensorBuffer( - flatbuffers::FlatBufferBuilder &fbb, - flatbuffers::Offset<org::apache::arrow::flatbuf::SparseTensor> root) { - fbb.FinishSizePrefixed(root); -} - -} // namespace flatbuf -} // namespace arrow -} // namespace apache -} // namespace org - -#endif // FLATBUFFERS_GENERATED_SPARSETENSOR_ORG_APACHE_ARROW_FLATBUF_H_ diff --git a/contrib/libs/apache/arrow/cpp/src/generated/Tensor.fbs b/contrib/libs/apache/arrow/cpp/src/generated/Tensor.fbs new file mode 100644 index 0000000000..409297ccf8 --- /dev/null +++ b/contrib/libs/apache/arrow/cpp/src/generated/Tensor.fbs @@ -0,0 +1,54 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +/// EXPERIMENTAL: Metadata for n-dimensional arrays, aka "tensors" or +/// "ndarrays". Arrow implementations in general are not required to implement +/// this type + +include "Schema.fbs"; + +namespace org.apache.arrow.flatbuf; + +/// ---------------------------------------------------------------------- +/// Data structures for dense tensors + +/// Shape data for a single axis in a tensor +table TensorDim { + /// Length of dimension + size: long; + + /// Name of the dimension, optional + name: string; +} + +table Tensor { + /// The type of data contained in a value cell. Currently only fixed-width + /// value types are supported, no strings or nested types + type: Type (required); + + /// The dimensions of the tensor, optionally named + shape: [TensorDim] (required); + + /// Non-negative byte offsets to advance one value cell along each dimension + /// If omitted, default to row-major order (C-like). + strides: [long]; + + /// The location and size of the tensor's data + data: Buffer (required); +} + +root_type Tensor; diff --git a/contrib/libs/apache/arrow/cpp/src/generated/Tensor_generated.h b/contrib/libs/apache/arrow/cpp/src/generated/Tensor_generated.h deleted file mode 100644 index 062a3b91aa..0000000000 --- a/contrib/libs/apache/arrow/cpp/src/generated/Tensor_generated.h +++ /dev/null @@ -1,387 +0,0 @@ -// automatically generated by the FlatBuffers compiler, do not modify - - -#ifndef FLATBUFFERS_GENERATED_TENSOR_ORG_APACHE_ARROW_FLATBUF_H_ -#define FLATBUFFERS_GENERATED_TENSOR_ORG_APACHE_ARROW_FLATBUF_H_ - -#include "flatbuffers/flatbuffers.h" - -#include "Schema_generated.h" - -namespace org { -namespace apache { -namespace arrow { -namespace flatbuf { - -struct TensorDim; -struct TensorDimBuilder; - -struct Tensor; -struct TensorBuilder; - -/// ---------------------------------------------------------------------- -/// Data structures for dense tensors -/// Shape data for a single axis in a tensor -struct TensorDim FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef TensorDimBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_SIZE = 4, - VT_NAME = 6 - }; - /// Length of dimension - int64_t size() const { - return GetField<int64_t>(VT_SIZE, 0); - } - /// Name of the dimension, optional - const flatbuffers::String *name() const { - return GetPointer<const flatbuffers::String *>(VT_NAME); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int64_t>(verifier, VT_SIZE) && - VerifyOffset(verifier, VT_NAME) && - verifier.VerifyString(name()) && - verifier.EndTable(); - } -}; - -struct TensorDimBuilder { - typedef TensorDim Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_size(int64_t size) { - fbb_.AddElement<int64_t>(TensorDim::VT_SIZE, size, 0); - } - void add_name(flatbuffers::Offset<flatbuffers::String> name) { - fbb_.AddOffset(TensorDim::VT_NAME, name); - } - explicit TensorDimBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - TensorDimBuilder &operator=(const TensorDimBuilder &); - flatbuffers::Offset<TensorDim> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<TensorDim>(end); - return o; - } -}; - -inline flatbuffers::Offset<TensorDim> CreateTensorDim( - flatbuffers::FlatBufferBuilder &_fbb, - int64_t size = 0, - flatbuffers::Offset<flatbuffers::String> name = 0) { - TensorDimBuilder builder_(_fbb); - builder_.add_size(size); - builder_.add_name(name); - return builder_.Finish(); -} - -inline flatbuffers::Offset<TensorDim> CreateTensorDimDirect( - flatbuffers::FlatBufferBuilder &_fbb, - int64_t size = 0, - const char *name = nullptr) { - auto name__ = name ? _fbb.CreateString(name) : 0; - return org::apache::arrow::flatbuf::CreateTensorDim( - _fbb, - size, - name__); -} - -struct Tensor FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef TensorBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_TYPE_TYPE = 4, - VT_TYPE = 6, - VT_SHAPE = 8, - VT_STRIDES = 10, - VT_DATA = 12 - }; - org::apache::arrow::flatbuf::Type type_type() const { - return static_cast<org::apache::arrow::flatbuf::Type>(GetField<uint8_t>(VT_TYPE_TYPE, 0)); - } - /// The type of data contained in a value cell. Currently only fixed-width - /// value types are supported, no strings or nested types - const void *type() const { - return GetPointer<const void *>(VT_TYPE); - } - template<typename T> const T *type_as() const; - const org::apache::arrow::flatbuf::Null *type_as_Null() const { - return type_type() == org::apache::arrow::flatbuf::Type::Null ? static_cast<const org::apache::arrow::flatbuf::Null *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Int *type_as_Int() const { - return type_type() == org::apache::arrow::flatbuf::Type::Int ? static_cast<const org::apache::arrow::flatbuf::Int *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::FloatingPoint *type_as_FloatingPoint() const { - return type_type() == org::apache::arrow::flatbuf::Type::FloatingPoint ? static_cast<const org::apache::arrow::flatbuf::FloatingPoint *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Binary *type_as_Binary() const { - return type_type() == org::apache::arrow::flatbuf::Type::Binary ? static_cast<const org::apache::arrow::flatbuf::Binary *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Utf8 *type_as_Utf8() const { - return type_type() == org::apache::arrow::flatbuf::Type::Utf8 ? static_cast<const org::apache::arrow::flatbuf::Utf8 *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Bool *type_as_Bool() const { - return type_type() == org::apache::arrow::flatbuf::Type::Bool ? static_cast<const org::apache::arrow::flatbuf::Bool *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Decimal *type_as_Decimal() const { - return type_type() == org::apache::arrow::flatbuf::Type::Decimal ? static_cast<const org::apache::arrow::flatbuf::Decimal *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Date *type_as_Date() const { - return type_type() == org::apache::arrow::flatbuf::Type::Date ? static_cast<const org::apache::arrow::flatbuf::Date *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Time *type_as_Time() const { - return type_type() == org::apache::arrow::flatbuf::Type::Time ? static_cast<const org::apache::arrow::flatbuf::Time *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Timestamp *type_as_Timestamp() const { - return type_type() == org::apache::arrow::flatbuf::Type::Timestamp ? static_cast<const org::apache::arrow::flatbuf::Timestamp *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Interval *type_as_Interval() const { - return type_type() == org::apache::arrow::flatbuf::Type::Interval ? static_cast<const org::apache::arrow::flatbuf::Interval *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::List *type_as_List() const { - return type_type() == org::apache::arrow::flatbuf::Type::List ? static_cast<const org::apache::arrow::flatbuf::List *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Struct_ *type_as_Struct_() const { - return type_type() == org::apache::arrow::flatbuf::Type::Struct_ ? static_cast<const org::apache::arrow::flatbuf::Struct_ *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Union *type_as_Union() const { - return type_type() == org::apache::arrow::flatbuf::Type::Union ? static_cast<const org::apache::arrow::flatbuf::Union *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::FixedSizeBinary *type_as_FixedSizeBinary() const { - return type_type() == org::apache::arrow::flatbuf::Type::FixedSizeBinary ? static_cast<const org::apache::arrow::flatbuf::FixedSizeBinary *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::FixedSizeList *type_as_FixedSizeList() const { - return type_type() == org::apache::arrow::flatbuf::Type::FixedSizeList ? static_cast<const org::apache::arrow::flatbuf::FixedSizeList *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Map *type_as_Map() const { - return type_type() == org::apache::arrow::flatbuf::Type::Map ? static_cast<const org::apache::arrow::flatbuf::Map *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::Duration *type_as_Duration() const { - return type_type() == org::apache::arrow::flatbuf::Type::Duration ? static_cast<const org::apache::arrow::flatbuf::Duration *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::LargeBinary *type_as_LargeBinary() const { - return type_type() == org::apache::arrow::flatbuf::Type::LargeBinary ? static_cast<const org::apache::arrow::flatbuf::LargeBinary *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::LargeUtf8 *type_as_LargeUtf8() const { - return type_type() == org::apache::arrow::flatbuf::Type::LargeUtf8 ? static_cast<const org::apache::arrow::flatbuf::LargeUtf8 *>(type()) : nullptr; - } - const org::apache::arrow::flatbuf::LargeList *type_as_LargeList() const { - return type_type() == org::apache::arrow::flatbuf::Type::LargeList ? static_cast<const org::apache::arrow::flatbuf::LargeList *>(type()) : nullptr; - } - /// The dimensions of the tensor, optionally named - const flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::TensorDim>> *shape() const { - return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::TensorDim>> *>(VT_SHAPE); - } - /// Non-negative byte offsets to advance one value cell along each dimension - /// If omitted, default to row-major order (C-like). - const flatbuffers::Vector<int64_t> *strides() const { - return GetPointer<const flatbuffers::Vector<int64_t> *>(VT_STRIDES); - } - /// The location and size of the tensor's data - const org::apache::arrow::flatbuf::Buffer *data() const { - return GetStruct<const org::apache::arrow::flatbuf::Buffer *>(VT_DATA); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<uint8_t>(verifier, VT_TYPE_TYPE) && - VerifyOffsetRequired(verifier, VT_TYPE) && - VerifyType(verifier, type(), type_type()) && - VerifyOffsetRequired(verifier, VT_SHAPE) && - verifier.VerifyVector(shape()) && - verifier.VerifyVectorOfTables(shape()) && - VerifyOffset(verifier, VT_STRIDES) && - verifier.VerifyVector(strides()) && - VerifyFieldRequired<org::apache::arrow::flatbuf::Buffer>(verifier, VT_DATA) && - verifier.EndTable(); - } -}; - -template<> inline const org::apache::arrow::flatbuf::Null *Tensor::type_as<org::apache::arrow::flatbuf::Null>() const { - return type_as_Null(); -} - -template<> inline const org::apache::arrow::flatbuf::Int *Tensor::type_as<org::apache::arrow::flatbuf::Int>() const { - return type_as_Int(); -} - -template<> inline const org::apache::arrow::flatbuf::FloatingPoint *Tensor::type_as<org::apache::arrow::flatbuf::FloatingPoint>() const { - return type_as_FloatingPoint(); -} - -template<> inline const org::apache::arrow::flatbuf::Binary *Tensor::type_as<org::apache::arrow::flatbuf::Binary>() const { - return type_as_Binary(); -} - -template<> inline const org::apache::arrow::flatbuf::Utf8 *Tensor::type_as<org::apache::arrow::flatbuf::Utf8>() const { - return type_as_Utf8(); -} - -template<> inline const org::apache::arrow::flatbuf::Bool *Tensor::type_as<org::apache::arrow::flatbuf::Bool>() const { - return type_as_Bool(); -} - -template<> inline const org::apache::arrow::flatbuf::Decimal *Tensor::type_as<org::apache::arrow::flatbuf::Decimal>() const { - return type_as_Decimal(); -} - -template<> inline const org::apache::arrow::flatbuf::Date *Tensor::type_as<org::apache::arrow::flatbuf::Date>() const { - return type_as_Date(); -} - -template<> inline const org::apache::arrow::flatbuf::Time *Tensor::type_as<org::apache::arrow::flatbuf::Time>() const { - return type_as_Time(); -} - -template<> inline const org::apache::arrow::flatbuf::Timestamp *Tensor::type_as<org::apache::arrow::flatbuf::Timestamp>() const { - return type_as_Timestamp(); -} - -template<> inline const org::apache::arrow::flatbuf::Interval *Tensor::type_as<org::apache::arrow::flatbuf::Interval>() const { - return type_as_Interval(); -} - -template<> inline const org::apache::arrow::flatbuf::List *Tensor::type_as<org::apache::arrow::flatbuf::List>() const { - return type_as_List(); -} - -template<> inline const org::apache::arrow::flatbuf::Struct_ *Tensor::type_as<org::apache::arrow::flatbuf::Struct_>() const { - return type_as_Struct_(); -} - -template<> inline const org::apache::arrow::flatbuf::Union *Tensor::type_as<org::apache::arrow::flatbuf::Union>() const { - return type_as_Union(); -} - -template<> inline const org::apache::arrow::flatbuf::FixedSizeBinary *Tensor::type_as<org::apache::arrow::flatbuf::FixedSizeBinary>() const { - return type_as_FixedSizeBinary(); -} - -template<> inline const org::apache::arrow::flatbuf::FixedSizeList *Tensor::type_as<org::apache::arrow::flatbuf::FixedSizeList>() const { - return type_as_FixedSizeList(); -} - -template<> inline const org::apache::arrow::flatbuf::Map *Tensor::type_as<org::apache::arrow::flatbuf::Map>() const { - return type_as_Map(); -} - -template<> inline const org::apache::arrow::flatbuf::Duration *Tensor::type_as<org::apache::arrow::flatbuf::Duration>() const { - return type_as_Duration(); -} - -template<> inline const org::apache::arrow::flatbuf::LargeBinary *Tensor::type_as<org::apache::arrow::flatbuf::LargeBinary>() const { - return type_as_LargeBinary(); -} - -template<> inline const org::apache::arrow::flatbuf::LargeUtf8 *Tensor::type_as<org::apache::arrow::flatbuf::LargeUtf8>() const { - return type_as_LargeUtf8(); -} - -template<> inline const org::apache::arrow::flatbuf::LargeList *Tensor::type_as<org::apache::arrow::flatbuf::LargeList>() const { - return type_as_LargeList(); -} - -struct TensorBuilder { - typedef Tensor Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_type_type(org::apache::arrow::flatbuf::Type type_type) { - fbb_.AddElement<uint8_t>(Tensor::VT_TYPE_TYPE, static_cast<uint8_t>(type_type), 0); - } - void add_type(flatbuffers::Offset<void> type) { - fbb_.AddOffset(Tensor::VT_TYPE, type); - } - void add_shape(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::TensorDim>>> shape) { - fbb_.AddOffset(Tensor::VT_SHAPE, shape); - } - void add_strides(flatbuffers::Offset<flatbuffers::Vector<int64_t>> strides) { - fbb_.AddOffset(Tensor::VT_STRIDES, strides); - } - void add_data(const org::apache::arrow::flatbuf::Buffer *data) { - fbb_.AddStruct(Tensor::VT_DATA, data); - } - explicit TensorBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - TensorBuilder &operator=(const TensorBuilder &); - flatbuffers::Offset<Tensor> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<Tensor>(end); - fbb_.Required(o, Tensor::VT_TYPE); - fbb_.Required(o, Tensor::VT_SHAPE); - fbb_.Required(o, Tensor::VT_DATA); - return o; - } -}; - -inline flatbuffers::Offset<Tensor> CreateTensor( - flatbuffers::FlatBufferBuilder &_fbb, - org::apache::arrow::flatbuf::Type type_type = org::apache::arrow::flatbuf::Type::NONE, - flatbuffers::Offset<void> type = 0, - flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<org::apache::arrow::flatbuf::TensorDim>>> shape = 0, - flatbuffers::Offset<flatbuffers::Vector<int64_t>> strides = 0, - const org::apache::arrow::flatbuf::Buffer *data = 0) { - TensorBuilder builder_(_fbb); - builder_.add_data(data); - builder_.add_strides(strides); - builder_.add_shape(shape); - builder_.add_type(type); - builder_.add_type_type(type_type); - return builder_.Finish(); -} - -inline flatbuffers::Offset<Tensor> CreateTensorDirect( - flatbuffers::FlatBufferBuilder &_fbb, - org::apache::arrow::flatbuf::Type type_type = org::apache::arrow::flatbuf::Type::NONE, - flatbuffers::Offset<void> type = 0, - const std::vector<flatbuffers::Offset<org::apache::arrow::flatbuf::TensorDim>> *shape = nullptr, - const std::vector<int64_t> *strides = nullptr, - const org::apache::arrow::flatbuf::Buffer *data = 0) { - auto shape__ = shape ? _fbb.CreateVector<flatbuffers::Offset<org::apache::arrow::flatbuf::TensorDim>>(*shape) : 0; - auto strides__ = strides ? _fbb.CreateVector<int64_t>(*strides) : 0; - return org::apache::arrow::flatbuf::CreateTensor( - _fbb, - type_type, - type, - shape__, - strides__, - data); -} - -inline const org::apache::arrow::flatbuf::Tensor *GetTensor(const void *buf) { - return flatbuffers::GetRoot<org::apache::arrow::flatbuf::Tensor>(buf); -} - -inline const org::apache::arrow::flatbuf::Tensor *GetSizePrefixedTensor(const void *buf) { - return flatbuffers::GetSizePrefixedRoot<org::apache::arrow::flatbuf::Tensor>(buf); -} - -inline bool VerifyTensorBuffer( - flatbuffers::Verifier &verifier) { - return verifier.VerifyBuffer<org::apache::arrow::flatbuf::Tensor>(nullptr); -} - -inline bool VerifySizePrefixedTensorBuffer( - flatbuffers::Verifier &verifier) { - return verifier.VerifySizePrefixedBuffer<org::apache::arrow::flatbuf::Tensor>(nullptr); -} - -inline void FinishTensorBuffer( - flatbuffers::FlatBufferBuilder &fbb, - flatbuffers::Offset<org::apache::arrow::flatbuf::Tensor> root) { - fbb.Finish(root); -} - -inline void FinishSizePrefixedTensorBuffer( - flatbuffers::FlatBufferBuilder &fbb, - flatbuffers::Offset<org::apache::arrow::flatbuf::Tensor> root) { - fbb.FinishSizePrefixed(root); -} - -} // namespace flatbuf -} // namespace arrow -} // namespace apache -} // namespace org - -#endif // FLATBUFFERS_GENERATED_TENSOR_ORG_APACHE_ARROW_FLATBUF_H_ diff --git a/contrib/libs/apache/arrow/cpp/src/generated/feather.fbs b/contrib/libs/apache/arrow/cpp/src/generated/feather.fbs new file mode 100644 index 0000000000..50cc104199 --- /dev/null +++ b/contrib/libs/apache/arrow/cpp/src/generated/feather.fbs @@ -0,0 +1,156 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +/// DEPRECATED: Feather V2 is available starting in version 0.17.0 and does not +/// use this file at all. + +namespace arrow.ipc.feather.fbs; + +/// Feather is an experimental serialization format implemented using +/// techniques from Apache Arrow. It was created as a proof-of-concept of an +/// interoperable file format for storing data frames originating in Python or +/// R. It enabled the developers to sidestep some of the open design questions +/// in Arrow from early 2016 and instead create something simple and useful for +/// the intended use cases. + +enum Type : byte { + BOOL = 0, + + INT8 = 1, + INT16 = 2, + INT32 = 3, + INT64 = 4, + + UINT8 = 5, + UINT16 = 6, + UINT32 = 7, + UINT64 = 8, + + FLOAT = 9, + DOUBLE = 10, + + UTF8 = 11, + + BINARY = 12, + + CATEGORY = 13, + + TIMESTAMP = 14, + DATE = 15, + TIME = 16, + + LARGE_UTF8 = 17, + LARGE_BINARY = 18 +} + +enum Encoding : byte { + PLAIN = 0, + + /// Data is stored dictionary-encoded + /// dictionary size: <INT32 Dictionary size> + /// dictionary data: <TYPE primitive array> + /// dictionary index: <INT32 primitive array> + /// + /// TODO: do we care about storing the index values in a smaller typeclass + DICTIONARY = 1 +} + +enum TimeUnit : byte { + SECOND = 0, + MILLISECOND = 1, + MICROSECOND = 2, + NANOSECOND = 3 +} + +table PrimitiveArray { + type: Type; + + encoding: Encoding = PLAIN; + + /// Relative memory offset of the start of the array data excluding the size + /// of the metadata + offset: long; + + /// The number of logical values in the array + length: long; + + /// The number of observed nulls + null_count: long; + + /// The total size of the actual data in the file + total_bytes: long; + + /// TODO: Compression +} + +table CategoryMetadata { + /// The category codes are presumed to be integers that are valid indexes into + /// the levels array + + levels: PrimitiveArray; + ordered: bool = false; +} + +table TimestampMetadata { + unit: TimeUnit; + + /// Timestamp data is assumed to be UTC, but the time zone is stored here for + /// presentation as localized + time_zone: string; +} + +table DateMetadata { +} + +table TimeMetadata { + unit: TimeUnit; +} + +union TypeMetadata { + CategoryMetadata, + TimestampMetadata, + DateMetadata, + TimeMetadata, +} + +table Column { + name: string; + values: PrimitiveArray; + metadata: TypeMetadata; + + /// This should (probably) be JSON + user_metadata: string; +} + +table CTable { + /// Some text (or a name) metadata about what the file is, optional + description: string; + + num_rows: long; + columns: [Column]; + + /// Version number of the Feather format + /// + /// Internal versions 0, 1, and 2: Implemented in Apache Arrow <= 0.16.0 and + /// wesm/feather. Uses "custom" metadata defined in this file. + version: int; + + /// Table metadata (likely JSON), not yet used + metadata: string; +} + +root_type CTable; diff --git a/contrib/libs/apache/arrow/cpp/src/generated/feather_generated.h b/contrib/libs/apache/arrow/cpp/src/generated/feather_generated.h deleted file mode 100644 index b925eb2bc6..0000000000 --- a/contrib/libs/apache/arrow/cpp/src/generated/feather_generated.h +++ /dev/null @@ -1,863 +0,0 @@ -// automatically generated by the FlatBuffers compiler, do not modify - - -#ifndef FLATBUFFERS_GENERATED_FEATHER_ARROW_IPC_FEATHER_FBS_H_ -#define FLATBUFFERS_GENERATED_FEATHER_ARROW_IPC_FEATHER_FBS_H_ - -#include "flatbuffers/flatbuffers.h" - -namespace arrow { -namespace ipc { -namespace feather { -namespace fbs { - -struct PrimitiveArray; -struct PrimitiveArrayBuilder; - -struct CategoryMetadata; -struct CategoryMetadataBuilder; - -struct TimestampMetadata; -struct TimestampMetadataBuilder; - -struct DateMetadata; -struct DateMetadataBuilder; - -struct TimeMetadata; -struct TimeMetadataBuilder; - -struct Column; -struct ColumnBuilder; - -struct CTable; -struct CTableBuilder; - -/// Feather is an experimental serialization format implemented using -/// techniques from Apache Arrow. It was created as a proof-of-concept of an -/// interoperable file format for storing data frames originating in Python or -/// R. It enabled the developers to sidestep some of the open design questions -/// in Arrow from early 2016 and instead create something simple and useful for -/// the intended use cases. -enum class Type : int8_t { - BOOL = 0, - INT8 = 1, - INT16 = 2, - INT32 = 3, - INT64 = 4, - UINT8 = 5, - UINT16 = 6, - UINT32 = 7, - UINT64 = 8, - FLOAT = 9, - DOUBLE = 10, - UTF8 = 11, - BINARY = 12, - CATEGORY = 13, - TIMESTAMP = 14, - DATE = 15, - TIME = 16, - LARGE_UTF8 = 17, - LARGE_BINARY = 18, - MIN = BOOL, - MAX = LARGE_BINARY -}; - -inline const Type (&EnumValuesType())[19] { - static const Type values[] = { - Type::BOOL, - Type::INT8, - Type::INT16, - Type::INT32, - Type::INT64, - Type::UINT8, - Type::UINT16, - Type::UINT32, - Type::UINT64, - Type::FLOAT, - Type::DOUBLE, - Type::UTF8, - Type::BINARY, - Type::CATEGORY, - Type::TIMESTAMP, - Type::DATE, - Type::TIME, - Type::LARGE_UTF8, - Type::LARGE_BINARY - }; - return values; -} - -inline const char * const *EnumNamesType() { - static const char * const names[20] = { - "BOOL", - "INT8", - "INT16", - "INT32", - "INT64", - "UINT8", - "UINT16", - "UINT32", - "UINT64", - "FLOAT", - "DOUBLE", - "UTF8", - "BINARY", - "CATEGORY", - "TIMESTAMP", - "DATE", - "TIME", - "LARGE_UTF8", - "LARGE_BINARY", - nullptr - }; - return names; -} - -inline const char *EnumNameType(Type e) { - if (flatbuffers::IsOutRange(e, Type::BOOL, Type::LARGE_BINARY)) return ""; - const size_t index = static_cast<size_t>(e); - return EnumNamesType()[index]; -} - -enum class Encoding : int8_t { - PLAIN = 0, - /// Data is stored dictionary-encoded - /// dictionary size: <INT32 Dictionary size> - /// dictionary data: <TYPE primitive array> - /// dictionary index: <INT32 primitive array> - /// - /// TODO: do we care about storing the index values in a smaller typeclass - DICTIONARY = 1, - MIN = PLAIN, - MAX = DICTIONARY -}; - -inline const Encoding (&EnumValuesEncoding())[2] { - static const Encoding values[] = { - Encoding::PLAIN, - Encoding::DICTIONARY - }; - return values; -} - -inline const char * const *EnumNamesEncoding() { - static const char * const names[3] = { - "PLAIN", - "DICTIONARY", - nullptr - }; - return names; -} - -inline const char *EnumNameEncoding(Encoding e) { - if (flatbuffers::IsOutRange(e, Encoding::PLAIN, Encoding::DICTIONARY)) return ""; - const size_t index = static_cast<size_t>(e); - return EnumNamesEncoding()[index]; -} - -enum class TimeUnit : int8_t { - SECOND = 0, - MILLISECOND = 1, - MICROSECOND = 2, - NANOSECOND = 3, - MIN = SECOND, - MAX = NANOSECOND -}; - -inline const TimeUnit (&EnumValuesTimeUnit())[4] { - static const TimeUnit values[] = { - TimeUnit::SECOND, - TimeUnit::MILLISECOND, - TimeUnit::MICROSECOND, - TimeUnit::NANOSECOND - }; - return values; -} - -inline const char * const *EnumNamesTimeUnit() { - static const char * const names[5] = { - "SECOND", - "MILLISECOND", - "MICROSECOND", - "NANOSECOND", - nullptr - }; - return names; -} - -inline const char *EnumNameTimeUnit(TimeUnit e) { - if (flatbuffers::IsOutRange(e, TimeUnit::SECOND, TimeUnit::NANOSECOND)) return ""; - const size_t index = static_cast<size_t>(e); - return EnumNamesTimeUnit()[index]; -} - -enum class TypeMetadata : uint8_t { - NONE = 0, - CategoryMetadata = 1, - TimestampMetadata = 2, - DateMetadata = 3, - TimeMetadata = 4, - MIN = NONE, - MAX = TimeMetadata -}; - -inline const TypeMetadata (&EnumValuesTypeMetadata())[5] { - static const TypeMetadata values[] = { - TypeMetadata::NONE, - TypeMetadata::CategoryMetadata, - TypeMetadata::TimestampMetadata, - TypeMetadata::DateMetadata, - TypeMetadata::TimeMetadata - }; - return values; -} - -inline const char * const *EnumNamesTypeMetadata() { - static const char * const names[6] = { - "NONE", - "CategoryMetadata", - "TimestampMetadata", - "DateMetadata", - "TimeMetadata", - nullptr - }; - return names; -} - -inline const char *EnumNameTypeMetadata(TypeMetadata e) { - if (flatbuffers::IsOutRange(e, TypeMetadata::NONE, TypeMetadata::TimeMetadata)) return ""; - const size_t index = static_cast<size_t>(e); - return EnumNamesTypeMetadata()[index]; -} - -template<typename T> struct TypeMetadataTraits { - static const TypeMetadata enum_value = TypeMetadata::NONE; -}; - -template<> struct TypeMetadataTraits<arrow::ipc::feather::fbs::CategoryMetadata> { - static const TypeMetadata enum_value = TypeMetadata::CategoryMetadata; -}; - -template<> struct TypeMetadataTraits<arrow::ipc::feather::fbs::TimestampMetadata> { - static const TypeMetadata enum_value = TypeMetadata::TimestampMetadata; -}; - -template<> struct TypeMetadataTraits<arrow::ipc::feather::fbs::DateMetadata> { - static const TypeMetadata enum_value = TypeMetadata::DateMetadata; -}; - -template<> struct TypeMetadataTraits<arrow::ipc::feather::fbs::TimeMetadata> { - static const TypeMetadata enum_value = TypeMetadata::TimeMetadata; -}; - -bool VerifyTypeMetadata(flatbuffers::Verifier &verifier, const void *obj, TypeMetadata type); -bool VerifyTypeMetadataVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types); - -struct PrimitiveArray FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef PrimitiveArrayBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_TYPE = 4, - VT_ENCODING = 6, - VT_OFFSET = 8, - VT_LENGTH = 10, - VT_NULL_COUNT = 12, - VT_TOTAL_BYTES = 14 - }; - arrow::ipc::feather::fbs::Type type() const { - return static_cast<arrow::ipc::feather::fbs::Type>(GetField<int8_t>(VT_TYPE, 0)); - } - arrow::ipc::feather::fbs::Encoding encoding() const { - return static_cast<arrow::ipc::feather::fbs::Encoding>(GetField<int8_t>(VT_ENCODING, 0)); - } - /// Relative memory offset of the start of the array data excluding the size - /// of the metadata - int64_t offset() const { - return GetField<int64_t>(VT_OFFSET, 0); - } - /// The number of logical values in the array - int64_t length() const { - return GetField<int64_t>(VT_LENGTH, 0); - } - /// The number of observed nulls - int64_t null_count() const { - return GetField<int64_t>(VT_NULL_COUNT, 0); - } - /// The total size of the actual data in the file - int64_t total_bytes() const { - return GetField<int64_t>(VT_TOTAL_BYTES, 0); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int8_t>(verifier, VT_TYPE) && - VerifyField<int8_t>(verifier, VT_ENCODING) && - VerifyField<int64_t>(verifier, VT_OFFSET) && - VerifyField<int64_t>(verifier, VT_LENGTH) && - VerifyField<int64_t>(verifier, VT_NULL_COUNT) && - VerifyField<int64_t>(verifier, VT_TOTAL_BYTES) && - verifier.EndTable(); - } -}; - -struct PrimitiveArrayBuilder { - typedef PrimitiveArray Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_type(arrow::ipc::feather::fbs::Type type) { - fbb_.AddElement<int8_t>(PrimitiveArray::VT_TYPE, static_cast<int8_t>(type), 0); - } - void add_encoding(arrow::ipc::feather::fbs::Encoding encoding) { - fbb_.AddElement<int8_t>(PrimitiveArray::VT_ENCODING, static_cast<int8_t>(encoding), 0); - } - void add_offset(int64_t offset) { - fbb_.AddElement<int64_t>(PrimitiveArray::VT_OFFSET, offset, 0); - } - void add_length(int64_t length) { - fbb_.AddElement<int64_t>(PrimitiveArray::VT_LENGTH, length, 0); - } - void add_null_count(int64_t null_count) { - fbb_.AddElement<int64_t>(PrimitiveArray::VT_NULL_COUNT, null_count, 0); - } - void add_total_bytes(int64_t total_bytes) { - fbb_.AddElement<int64_t>(PrimitiveArray::VT_TOTAL_BYTES, total_bytes, 0); - } - explicit PrimitiveArrayBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - PrimitiveArrayBuilder &operator=(const PrimitiveArrayBuilder &); - flatbuffers::Offset<PrimitiveArray> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<PrimitiveArray>(end); - return o; - } -}; - -inline flatbuffers::Offset<PrimitiveArray> CreatePrimitiveArray( - flatbuffers::FlatBufferBuilder &_fbb, - arrow::ipc::feather::fbs::Type type = arrow::ipc::feather::fbs::Type::BOOL, - arrow::ipc::feather::fbs::Encoding encoding = arrow::ipc::feather::fbs::Encoding::PLAIN, - int64_t offset = 0, - int64_t length = 0, - int64_t null_count = 0, - int64_t total_bytes = 0) { - PrimitiveArrayBuilder builder_(_fbb); - builder_.add_total_bytes(total_bytes); - builder_.add_null_count(null_count); - builder_.add_length(length); - builder_.add_offset(offset); - builder_.add_encoding(encoding); - builder_.add_type(type); - return builder_.Finish(); -} - -struct CategoryMetadata FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef CategoryMetadataBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_LEVELS = 4, - VT_ORDERED = 6 - }; - /// The category codes are presumed to be integers that are valid indexes into - /// the levels array - const arrow::ipc::feather::fbs::PrimitiveArray *levels() const { - return GetPointer<const arrow::ipc::feather::fbs::PrimitiveArray *>(VT_LEVELS); - } - bool ordered() const { - return GetField<uint8_t>(VT_ORDERED, 0) != 0; - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyOffset(verifier, VT_LEVELS) && - verifier.VerifyTable(levels()) && - VerifyField<uint8_t>(verifier, VT_ORDERED) && - verifier.EndTable(); - } -}; - -struct CategoryMetadataBuilder { - typedef CategoryMetadata Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_levels(flatbuffers::Offset<arrow::ipc::feather::fbs::PrimitiveArray> levels) { - fbb_.AddOffset(CategoryMetadata::VT_LEVELS, levels); - } - void add_ordered(bool ordered) { - fbb_.AddElement<uint8_t>(CategoryMetadata::VT_ORDERED, static_cast<uint8_t>(ordered), 0); - } - explicit CategoryMetadataBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - CategoryMetadataBuilder &operator=(const CategoryMetadataBuilder &); - flatbuffers::Offset<CategoryMetadata> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<CategoryMetadata>(end); - return o; - } -}; - -inline flatbuffers::Offset<CategoryMetadata> CreateCategoryMetadata( - flatbuffers::FlatBufferBuilder &_fbb, - flatbuffers::Offset<arrow::ipc::feather::fbs::PrimitiveArray> levels = 0, - bool ordered = false) { - CategoryMetadataBuilder builder_(_fbb); - builder_.add_levels(levels); - builder_.add_ordered(ordered); - return builder_.Finish(); -} - -struct TimestampMetadata FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef TimestampMetadataBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_UNIT = 4, - VT_TIMEZONE = 6 - }; - arrow::ipc::feather::fbs::TimeUnit unit() const { - return static_cast<arrow::ipc::feather::fbs::TimeUnit>(GetField<int8_t>(VT_UNIT, 0)); - } - /// Timestamp data is assumed to be UTC, but the time zone is stored here for - /// presentation as localized - const flatbuffers::String *timezone() const { - return GetPointer<const flatbuffers::String *>(VT_TIMEZONE); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int8_t>(verifier, VT_UNIT) && - VerifyOffset(verifier, VT_TIMEZONE) && - verifier.VerifyString(timezone()) && - verifier.EndTable(); - } -}; - -struct TimestampMetadataBuilder { - typedef TimestampMetadata Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_unit(arrow::ipc::feather::fbs::TimeUnit unit) { - fbb_.AddElement<int8_t>(TimestampMetadata::VT_UNIT, static_cast<int8_t>(unit), 0); - } - void add_timezone(flatbuffers::Offset<flatbuffers::String> timezone) { - fbb_.AddOffset(TimestampMetadata::VT_TIMEZONE, timezone); - } - explicit TimestampMetadataBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - TimestampMetadataBuilder &operator=(const TimestampMetadataBuilder &); - flatbuffers::Offset<TimestampMetadata> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<TimestampMetadata>(end); - return o; - } -}; - -inline flatbuffers::Offset<TimestampMetadata> CreateTimestampMetadata( - flatbuffers::FlatBufferBuilder &_fbb, - arrow::ipc::feather::fbs::TimeUnit unit = arrow::ipc::feather::fbs::TimeUnit::SECOND, - flatbuffers::Offset<flatbuffers::String> timezone = 0) { - TimestampMetadataBuilder builder_(_fbb); - builder_.add_timezone(timezone); - builder_.add_unit(unit); - return builder_.Finish(); -} - -inline flatbuffers::Offset<TimestampMetadata> CreateTimestampMetadataDirect( - flatbuffers::FlatBufferBuilder &_fbb, - arrow::ipc::feather::fbs::TimeUnit unit = arrow::ipc::feather::fbs::TimeUnit::SECOND, - const char *timezone = nullptr) { - auto timezone__ = timezone ? _fbb.CreateString(timezone) : 0; - return arrow::ipc::feather::fbs::CreateTimestampMetadata( - _fbb, - unit, - timezone__); -} - -struct DateMetadata FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef DateMetadataBuilder Builder; - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - verifier.EndTable(); - } -}; - -struct DateMetadataBuilder { - typedef DateMetadata Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - explicit DateMetadataBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - DateMetadataBuilder &operator=(const DateMetadataBuilder &); - flatbuffers::Offset<DateMetadata> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<DateMetadata>(end); - return o; - } -}; - -inline flatbuffers::Offset<DateMetadata> CreateDateMetadata( - flatbuffers::FlatBufferBuilder &_fbb) { - DateMetadataBuilder builder_(_fbb); - return builder_.Finish(); -} - -struct TimeMetadata FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef TimeMetadataBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_UNIT = 4 - }; - arrow::ipc::feather::fbs::TimeUnit unit() const { - return static_cast<arrow::ipc::feather::fbs::TimeUnit>(GetField<int8_t>(VT_UNIT, 0)); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyField<int8_t>(verifier, VT_UNIT) && - verifier.EndTable(); - } -}; - -struct TimeMetadataBuilder { - typedef TimeMetadata Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_unit(arrow::ipc::feather::fbs::TimeUnit unit) { - fbb_.AddElement<int8_t>(TimeMetadata::VT_UNIT, static_cast<int8_t>(unit), 0); - } - explicit TimeMetadataBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - TimeMetadataBuilder &operator=(const TimeMetadataBuilder &); - flatbuffers::Offset<TimeMetadata> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<TimeMetadata>(end); - return o; - } -}; - -inline flatbuffers::Offset<TimeMetadata> CreateTimeMetadata( - flatbuffers::FlatBufferBuilder &_fbb, - arrow::ipc::feather::fbs::TimeUnit unit = arrow::ipc::feather::fbs::TimeUnit::SECOND) { - TimeMetadataBuilder builder_(_fbb); - builder_.add_unit(unit); - return builder_.Finish(); -} - -struct Column FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef ColumnBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_NAME = 4, - VT_VALUES = 6, - VT_METADATA_TYPE = 8, - VT_METADATA = 10, - VT_USER_METADATA = 12 - }; - const flatbuffers::String *name() const { - return GetPointer<const flatbuffers::String *>(VT_NAME); - } - const arrow::ipc::feather::fbs::PrimitiveArray *values() const { - return GetPointer<const arrow::ipc::feather::fbs::PrimitiveArray *>(VT_VALUES); - } - arrow::ipc::feather::fbs::TypeMetadata metadata_type() const { - return static_cast<arrow::ipc::feather::fbs::TypeMetadata>(GetField<uint8_t>(VT_METADATA_TYPE, 0)); - } - const void *metadata() const { - return GetPointer<const void *>(VT_METADATA); - } - template<typename T> const T *metadata_as() const; - const arrow::ipc::feather::fbs::CategoryMetadata *metadata_as_CategoryMetadata() const { - return metadata_type() == arrow::ipc::feather::fbs::TypeMetadata::CategoryMetadata ? static_cast<const arrow::ipc::feather::fbs::CategoryMetadata *>(metadata()) : nullptr; - } - const arrow::ipc::feather::fbs::TimestampMetadata *metadata_as_TimestampMetadata() const { - return metadata_type() == arrow::ipc::feather::fbs::TypeMetadata::TimestampMetadata ? static_cast<const arrow::ipc::feather::fbs::TimestampMetadata *>(metadata()) : nullptr; - } - const arrow::ipc::feather::fbs::DateMetadata *metadata_as_DateMetadata() const { - return metadata_type() == arrow::ipc::feather::fbs::TypeMetadata::DateMetadata ? static_cast<const arrow::ipc::feather::fbs::DateMetadata *>(metadata()) : nullptr; - } - const arrow::ipc::feather::fbs::TimeMetadata *metadata_as_TimeMetadata() const { - return metadata_type() == arrow::ipc::feather::fbs::TypeMetadata::TimeMetadata ? static_cast<const arrow::ipc::feather::fbs::TimeMetadata *>(metadata()) : nullptr; - } - /// This should (probably) be JSON - const flatbuffers::String *user_metadata() const { - return GetPointer<const flatbuffers::String *>(VT_USER_METADATA); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyOffset(verifier, VT_NAME) && - verifier.VerifyString(name()) && - VerifyOffset(verifier, VT_VALUES) && - verifier.VerifyTable(values()) && - VerifyField<uint8_t>(verifier, VT_METADATA_TYPE) && - VerifyOffset(verifier, VT_METADATA) && - VerifyTypeMetadata(verifier, metadata(), metadata_type()) && - VerifyOffset(verifier, VT_USER_METADATA) && - verifier.VerifyString(user_metadata()) && - verifier.EndTable(); - } -}; - -template<> inline const arrow::ipc::feather::fbs::CategoryMetadata *Column::metadata_as<arrow::ipc::feather::fbs::CategoryMetadata>() const { - return metadata_as_CategoryMetadata(); -} - -template<> inline const arrow::ipc::feather::fbs::TimestampMetadata *Column::metadata_as<arrow::ipc::feather::fbs::TimestampMetadata>() const { - return metadata_as_TimestampMetadata(); -} - -template<> inline const arrow::ipc::feather::fbs::DateMetadata *Column::metadata_as<arrow::ipc::feather::fbs::DateMetadata>() const { - return metadata_as_DateMetadata(); -} - -template<> inline const arrow::ipc::feather::fbs::TimeMetadata *Column::metadata_as<arrow::ipc::feather::fbs::TimeMetadata>() const { - return metadata_as_TimeMetadata(); -} - -struct ColumnBuilder { - typedef Column Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_name(flatbuffers::Offset<flatbuffers::String> name) { - fbb_.AddOffset(Column::VT_NAME, name); - } - void add_values(flatbuffers::Offset<arrow::ipc::feather::fbs::PrimitiveArray> values) { - fbb_.AddOffset(Column::VT_VALUES, values); - } - void add_metadata_type(arrow::ipc::feather::fbs::TypeMetadata metadata_type) { - fbb_.AddElement<uint8_t>(Column::VT_METADATA_TYPE, static_cast<uint8_t>(metadata_type), 0); - } - void add_metadata(flatbuffers::Offset<void> metadata) { - fbb_.AddOffset(Column::VT_METADATA, metadata); - } - void add_user_metadata(flatbuffers::Offset<flatbuffers::String> user_metadata) { - fbb_.AddOffset(Column::VT_USER_METADATA, user_metadata); - } - explicit ColumnBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - ColumnBuilder &operator=(const ColumnBuilder &); - flatbuffers::Offset<Column> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<Column>(end); - return o; - } -}; - -inline flatbuffers::Offset<Column> CreateColumn( - flatbuffers::FlatBufferBuilder &_fbb, - flatbuffers::Offset<flatbuffers::String> name = 0, - flatbuffers::Offset<arrow::ipc::feather::fbs::PrimitiveArray> values = 0, - arrow::ipc::feather::fbs::TypeMetadata metadata_type = arrow::ipc::feather::fbs::TypeMetadata::NONE, - flatbuffers::Offset<void> metadata = 0, - flatbuffers::Offset<flatbuffers::String> user_metadata = 0) { - ColumnBuilder builder_(_fbb); - builder_.add_user_metadata(user_metadata); - builder_.add_metadata(metadata); - builder_.add_values(values); - builder_.add_name(name); - builder_.add_metadata_type(metadata_type); - return builder_.Finish(); -} - -inline flatbuffers::Offset<Column> CreateColumnDirect( - flatbuffers::FlatBufferBuilder &_fbb, - const char *name = nullptr, - flatbuffers::Offset<arrow::ipc::feather::fbs::PrimitiveArray> values = 0, - arrow::ipc::feather::fbs::TypeMetadata metadata_type = arrow::ipc::feather::fbs::TypeMetadata::NONE, - flatbuffers::Offset<void> metadata = 0, - const char *user_metadata = nullptr) { - auto name__ = name ? _fbb.CreateString(name) : 0; - auto user_metadata__ = user_metadata ? _fbb.CreateString(user_metadata) : 0; - return arrow::ipc::feather::fbs::CreateColumn( - _fbb, - name__, - values, - metadata_type, - metadata, - user_metadata__); -} - -struct CTable FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { - typedef CTableBuilder Builder; - enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { - VT_DESCRIPTION = 4, - VT_NUM_ROWS = 6, - VT_COLUMNS = 8, - VT_VERSION = 10, - VT_METADATA = 12 - }; - /// Some text (or a name) metadata about what the file is, optional - const flatbuffers::String *description() const { - return GetPointer<const flatbuffers::String *>(VT_DESCRIPTION); - } - int64_t num_rows() const { - return GetField<int64_t>(VT_NUM_ROWS, 0); - } - const flatbuffers::Vector<flatbuffers::Offset<arrow::ipc::feather::fbs::Column>> *columns() const { - return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<arrow::ipc::feather::fbs::Column>> *>(VT_COLUMNS); - } - /// Version number of the Feather format - /// - /// Internal versions 0, 1, and 2: Implemented in Apache Arrow <= 0.16.0 and - /// wesm/feather. Uses "custom" metadata defined in this file. - int32_t version() const { - return GetField<int32_t>(VT_VERSION, 0); - } - /// Table metadata (likely JSON), not yet used - const flatbuffers::String *metadata() const { - return GetPointer<const flatbuffers::String *>(VT_METADATA); - } - bool Verify(flatbuffers::Verifier &verifier) const { - return VerifyTableStart(verifier) && - VerifyOffset(verifier, VT_DESCRIPTION) && - verifier.VerifyString(description()) && - VerifyField<int64_t>(verifier, VT_NUM_ROWS) && - VerifyOffset(verifier, VT_COLUMNS) && - verifier.VerifyVector(columns()) && - verifier.VerifyVectorOfTables(columns()) && - VerifyField<int32_t>(verifier, VT_VERSION) && - VerifyOffset(verifier, VT_METADATA) && - verifier.VerifyString(metadata()) && - verifier.EndTable(); - } -}; - -struct CTableBuilder { - typedef CTable Table; - flatbuffers::FlatBufferBuilder &fbb_; - flatbuffers::uoffset_t start_; - void add_description(flatbuffers::Offset<flatbuffers::String> description) { - fbb_.AddOffset(CTable::VT_DESCRIPTION, description); - } - void add_num_rows(int64_t num_rows) { - fbb_.AddElement<int64_t>(CTable::VT_NUM_ROWS, num_rows, 0); - } - void add_columns(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<arrow::ipc::feather::fbs::Column>>> columns) { - fbb_.AddOffset(CTable::VT_COLUMNS, columns); - } - void add_version(int32_t version) { - fbb_.AddElement<int32_t>(CTable::VT_VERSION, version, 0); - } - void add_metadata(flatbuffers::Offset<flatbuffers::String> metadata) { - fbb_.AddOffset(CTable::VT_METADATA, metadata); - } - explicit CTableBuilder(flatbuffers::FlatBufferBuilder &_fbb) - : fbb_(_fbb) { - start_ = fbb_.StartTable(); - } - CTableBuilder &operator=(const CTableBuilder &); - flatbuffers::Offset<CTable> Finish() { - const auto end = fbb_.EndTable(start_); - auto o = flatbuffers::Offset<CTable>(end); - return o; - } -}; - -inline flatbuffers::Offset<CTable> CreateCTable( - flatbuffers::FlatBufferBuilder &_fbb, - flatbuffers::Offset<flatbuffers::String> description = 0, - int64_t num_rows = 0, - flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<arrow::ipc::feather::fbs::Column>>> columns = 0, - int32_t version = 0, - flatbuffers::Offset<flatbuffers::String> metadata = 0) { - CTableBuilder builder_(_fbb); - builder_.add_num_rows(num_rows); - builder_.add_metadata(metadata); - builder_.add_version(version); - builder_.add_columns(columns); - builder_.add_description(description); - return builder_.Finish(); -} - -inline flatbuffers::Offset<CTable> CreateCTableDirect( - flatbuffers::FlatBufferBuilder &_fbb, - const char *description = nullptr, - int64_t num_rows = 0, - const std::vector<flatbuffers::Offset<arrow::ipc::feather::fbs::Column>> *columns = nullptr, - int32_t version = 0, - const char *metadata = nullptr) { - auto description__ = description ? _fbb.CreateString(description) : 0; - auto columns__ = columns ? _fbb.CreateVector<flatbuffers::Offset<arrow::ipc::feather::fbs::Column>>(*columns) : 0; - auto metadata__ = metadata ? _fbb.CreateString(metadata) : 0; - return arrow::ipc::feather::fbs::CreateCTable( - _fbb, - description__, - num_rows, - columns__, - version, - metadata__); -} - -inline bool VerifyTypeMetadata(flatbuffers::Verifier &verifier, const void *obj, TypeMetadata type) { - switch (type) { - case TypeMetadata::NONE: { - return true; - } - case TypeMetadata::CategoryMetadata: { - auto ptr = reinterpret_cast<const arrow::ipc::feather::fbs::CategoryMetadata *>(obj); - return verifier.VerifyTable(ptr); - } - case TypeMetadata::TimestampMetadata: { - auto ptr = reinterpret_cast<const arrow::ipc::feather::fbs::TimestampMetadata *>(obj); - return verifier.VerifyTable(ptr); - } - case TypeMetadata::DateMetadata: { - auto ptr = reinterpret_cast<const arrow::ipc::feather::fbs::DateMetadata *>(obj); - return verifier.VerifyTable(ptr); - } - case TypeMetadata::TimeMetadata: { - auto ptr = reinterpret_cast<const arrow::ipc::feather::fbs::TimeMetadata *>(obj); - return verifier.VerifyTable(ptr); - } - default: return true; - } -} - -inline bool VerifyTypeMetadataVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types) { - if (!values || !types) return !values && !types; - if (values->size() != types->size()) return false; - for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) { - if (!VerifyTypeMetadata( - verifier, values->Get(i), types->GetEnum<TypeMetadata>(i))) { - return false; - } - } - return true; -} - -inline const arrow::ipc::feather::fbs::CTable *GetCTable(const void *buf) { - return flatbuffers::GetRoot<arrow::ipc::feather::fbs::CTable>(buf); -} - -inline const arrow::ipc::feather::fbs::CTable *GetSizePrefixedCTable(const void *buf) { - return flatbuffers::GetSizePrefixedRoot<arrow::ipc::feather::fbs::CTable>(buf); -} - -inline bool VerifyCTableBuffer( - flatbuffers::Verifier &verifier) { - return verifier.VerifyBuffer<arrow::ipc::feather::fbs::CTable>(nullptr); -} - -inline bool VerifySizePrefixedCTableBuffer( - flatbuffers::Verifier &verifier) { - return verifier.VerifySizePrefixedBuffer<arrow::ipc::feather::fbs::CTable>(nullptr); -} - -inline void FinishCTableBuffer( - flatbuffers::FlatBufferBuilder &fbb, - flatbuffers::Offset<arrow::ipc::feather::fbs::CTable> root) { - fbb.Finish(root); -} - -inline void FinishSizePrefixedCTableBuffer( - flatbuffers::FlatBufferBuilder &fbb, - flatbuffers::Offset<arrow::ipc::feather::fbs::CTable> root) { - fbb.FinishSizePrefixed(root); -} - -} // namespace fbs -} // namespace feather -} // namespace ipc -} // namespace arrow - -#endif // FLATBUFFERS_GENERATED_FEATHER_ARROW_IPC_FEATHER_FBS_H_ diff --git a/contrib/libs/apache/arrow/ya.make b/contrib/libs/apache/arrow/ya.make index 9986f9107c..f4ed4463d1 100644 --- a/contrib/libs/apache/arrow/ya.make +++ b/contrib/libs/apache/arrow/ya.make @@ -41,6 +41,7 @@ PEERDIR( ) ADDINCL( + GLOBAL ${ARCADIA_BUILD_ROOT}/contrib/libs/apache/arrow/cpp/src GLOBAL contrib/libs/apache/arrow/cpp/src GLOBAL contrib/libs/apache/arrow/src contrib/libs/apache/arrow/cpp/src/generated @@ -80,6 +81,8 @@ IF (NOT OS_WINDOWS) ) ENDIF() +FLATC_FLAGS(--scoped-enums) + SRCS( cpp/src/arrow/adapters/orc/adapter.cc cpp/src/arrow/adapters/orc/adapter_util.cc @@ -249,6 +252,12 @@ SRCS( cpp/src/arrow/vendored/datetime/tz.cpp cpp/src/arrow/vendored/musl/strptime.c cpp/src/arrow/visitor.cc + cpp/src/generated/File.fbs + cpp/src/generated/Message.fbs + cpp/src/generated/Schema.fbs + cpp/src/generated/SparseTensor.fbs + cpp/src/generated/Tensor.fbs + cpp/src/generated/feather.fbs cpp/src/generated/parquet_constants.cpp cpp/src/generated/parquet_types.cpp cpp/src/parquet/arrow/path_internal.cc diff --git a/contrib/libs/flatbuffers/CMakeLists.darwin-x86_64.txt b/contrib/libs/flatbuffers/CMakeLists.darwin-x86_64.txt new file mode 100644 index 0000000000..69394c43b6 --- /dev/null +++ b/contrib/libs/flatbuffers/CMakeLists.darwin-x86_64.txt @@ -0,0 +1,27 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +add_subdirectory(flatc) + +add_library(contrib-libs-flatbuffers) +target_compile_options(contrib-libs-flatbuffers PRIVATE + -DFLATBUFFERS_LOCALE_INDEPENDENT=1 + $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> +) +target_include_directories(contrib-libs-flatbuffers PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/include +) +target_link_libraries(contrib-libs-flatbuffers PUBLIC + contrib-libs-cxxsupp +) +target_sources(contrib-libs-flatbuffers PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_text.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_parser.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/reflection.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/util.cpp +) diff --git a/contrib/libs/flatbuffers/CMakeLists.linux-aarch64.txt b/contrib/libs/flatbuffers/CMakeLists.linux-aarch64.txt new file mode 100644 index 0000000000..a176d50a06 --- /dev/null +++ b/contrib/libs/flatbuffers/CMakeLists.linux-aarch64.txt @@ -0,0 +1,28 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +add_subdirectory(flatc) + +add_library(contrib-libs-flatbuffers) +target_compile_options(contrib-libs-flatbuffers PRIVATE + -DFLATBUFFERS_LOCALE_INDEPENDENT=1 + $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> +) +target_include_directories(contrib-libs-flatbuffers PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/include +) +target_link_libraries(contrib-libs-flatbuffers PUBLIC + contrib-libs-linux-headers + contrib-libs-cxxsupp +) +target_sources(contrib-libs-flatbuffers PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_text.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_parser.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/reflection.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/util.cpp +) diff --git a/contrib/libs/flatbuffers/CMakeLists.linux-x86_64.txt b/contrib/libs/flatbuffers/CMakeLists.linux-x86_64.txt new file mode 100644 index 0000000000..a176d50a06 --- /dev/null +++ b/contrib/libs/flatbuffers/CMakeLists.linux-x86_64.txt @@ -0,0 +1,28 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +add_subdirectory(flatc) + +add_library(contrib-libs-flatbuffers) +target_compile_options(contrib-libs-flatbuffers PRIVATE + -DFLATBUFFERS_LOCALE_INDEPENDENT=1 + $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> +) +target_include_directories(contrib-libs-flatbuffers PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/include +) +target_link_libraries(contrib-libs-flatbuffers PUBLIC + contrib-libs-linux-headers + contrib-libs-cxxsupp +) +target_sources(contrib-libs-flatbuffers PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_text.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_parser.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/reflection.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/util.cpp +) diff --git a/contrib/libs/flatbuffers/CMakeLists.txt b/contrib/libs/flatbuffers/CMakeLists.txt new file mode 100644 index 0000000000..f8b31df0c1 --- /dev/null +++ b/contrib/libs/flatbuffers/CMakeLists.txt @@ -0,0 +1,17 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) + include(CMakeLists.linux-aarch64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + include(CMakeLists.darwin-x86_64.txt) +elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) + include(CMakeLists.windows-x86_64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) + include(CMakeLists.linux-x86_64.txt) +endif() diff --git a/contrib/libs/flatbuffers/CMakeLists.windows-x86_64.txt b/contrib/libs/flatbuffers/CMakeLists.windows-x86_64.txt new file mode 100644 index 0000000000..69394c43b6 --- /dev/null +++ b/contrib/libs/flatbuffers/CMakeLists.windows-x86_64.txt @@ -0,0 +1,27 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +add_subdirectory(flatc) + +add_library(contrib-libs-flatbuffers) +target_compile_options(contrib-libs-flatbuffers PRIVATE + -DFLATBUFFERS_LOCALE_INDEPENDENT=1 + $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> +) +target_include_directories(contrib-libs-flatbuffers PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/include +) +target_link_libraries(contrib-libs-flatbuffers PUBLIC + contrib-libs-cxxsupp +) +target_sources(contrib-libs-flatbuffers PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_text.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_parser.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/reflection.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/util.cpp +) diff --git a/contrib/libs/flatbuffers/CONTRIBUTING.md b/contrib/libs/flatbuffers/CONTRIBUTING.md new file mode 100644 index 0000000000..17428add54 --- /dev/null +++ b/contrib/libs/flatbuffers/CONTRIBUTING.md @@ -0,0 +1,42 @@ +Contributing {#contributing} +============ + +Want to contribute? Great! First, read this page (including the small print at +the end). + +# Before you contribute +Before we can use your code, you must sign the +[Google Individual Contributor License Agreement](https://developers.google.com/open-source/cla/individual?csw=1) +(CLA), which you can do online. The CLA is necessary mainly because you own the +copyright to your changes, even after your contribution becomes part of our +codebase, so we need your permission to use and distribute your code. We also +need to be sure of various other things—for instance that you'll tell us if you +know that your code infringes on other people's patents. You don't have to sign +the CLA until after you've submitted your code for review and a member has +approved it, but you must do it before we can put your code into our codebase. +Before you start working on a larger contribution, you should get in touch with +us first through the issue tracker with your idea so that we can help out and +possibly guide you. Coordinating up front makes it much easier to avoid +frustration later on. + +# Code reviews +All submissions, including submissions by project members, require review. We +use Github pull requests for this purpose. + +Some tips for good pull requests: +* Use our code + [style guide](https://google.github.io/styleguide/cppguide.html). + When in doubt, try to stay true to the existing code of the project. +* Write a descriptive commit message. What problem are you solving and what + are the consequences? Where and what did you test? Some good tips: + [here](http://robots.thoughtbot.com/5-useful-tips-for-a-better-commit-message) + and [here](https://www.kernel.org/doc/Documentation/SubmittingPatches). +* If your PR consists of multiple commits which are successive improvements / + fixes to your first commit, consider squashing them into a single commit + (`git rebase -i`) such that your PR is a single commit on top of the current + HEAD. This make reviewing the code so much easier, and our history more + readable. + +# The small print +Contributions made by corporations are covered by a different agreement than +the one above, the Software Grant and Corporate Contributor License Agreement. diff --git a/contrib/libs/flatbuffers/LICENSE.txt b/contrib/libs/flatbuffers/LICENSE.txt new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/contrib/libs/flatbuffers/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/contrib/libs/flatbuffers/flatc/CMakeLists.darwin-x86_64.txt b/contrib/libs/flatbuffers/flatc/CMakeLists.darwin-x86_64.txt new file mode 100644 index 0000000000..ee54cbf098 --- /dev/null +++ b/contrib/libs/flatbuffers/flatc/CMakeLists.darwin-x86_64.txt @@ -0,0 +1,52 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_library(libs-flatbuffers-flatc) +target_compile_options(libs-flatbuffers-flatc PRIVATE + -DFLATBUFFERS_LOCALE_INDEPENDENT=1 + $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> +) +target_include_directories(libs-flatbuffers-flatc PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/include +) +target_link_libraries(libs-flatbuffers-flatc PUBLIC + contrib-libs-cxxsupp +) +target_sources(libs-flatbuffers-flatc PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/cpp_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/go_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/java_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/python_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/swift_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/ts_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/code_generators.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/flatc.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_cpp.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_cpp_yandex_maps_iter.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_csharp.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_dart.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_fbs.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_go.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_grpc.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_java.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_json_schema.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_kotlin.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_lobster.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_lua.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_php.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_python.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_rust.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_swift.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_text.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_ts.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_parser.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/reflection.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/util.cpp +) diff --git a/contrib/libs/flatbuffers/flatc/CMakeLists.linux-aarch64.txt b/contrib/libs/flatbuffers/flatc/CMakeLists.linux-aarch64.txt new file mode 100644 index 0000000000..cae0280fd9 --- /dev/null +++ b/contrib/libs/flatbuffers/flatc/CMakeLists.linux-aarch64.txt @@ -0,0 +1,53 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_library(libs-flatbuffers-flatc) +target_compile_options(libs-flatbuffers-flatc PRIVATE + -DFLATBUFFERS_LOCALE_INDEPENDENT=1 + $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> +) +target_include_directories(libs-flatbuffers-flatc PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/include +) +target_link_libraries(libs-flatbuffers-flatc PUBLIC + contrib-libs-linux-headers + contrib-libs-cxxsupp +) +target_sources(libs-flatbuffers-flatc PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/cpp_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/go_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/java_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/python_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/swift_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/ts_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/code_generators.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/flatc.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_cpp.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_cpp_yandex_maps_iter.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_csharp.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_dart.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_fbs.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_go.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_grpc.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_java.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_json_schema.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_kotlin.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_lobster.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_lua.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_php.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_python.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_rust.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_swift.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_text.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_ts.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_parser.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/reflection.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/util.cpp +) diff --git a/contrib/libs/flatbuffers/flatc/CMakeLists.linux-x86_64.txt b/contrib/libs/flatbuffers/flatc/CMakeLists.linux-x86_64.txt new file mode 100644 index 0000000000..cae0280fd9 --- /dev/null +++ b/contrib/libs/flatbuffers/flatc/CMakeLists.linux-x86_64.txt @@ -0,0 +1,53 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_library(libs-flatbuffers-flatc) +target_compile_options(libs-flatbuffers-flatc PRIVATE + -DFLATBUFFERS_LOCALE_INDEPENDENT=1 + $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> +) +target_include_directories(libs-flatbuffers-flatc PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/include +) +target_link_libraries(libs-flatbuffers-flatc PUBLIC + contrib-libs-linux-headers + contrib-libs-cxxsupp +) +target_sources(libs-flatbuffers-flatc PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/cpp_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/go_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/java_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/python_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/swift_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/ts_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/code_generators.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/flatc.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_cpp.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_cpp_yandex_maps_iter.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_csharp.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_dart.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_fbs.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_go.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_grpc.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_java.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_json_schema.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_kotlin.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_lobster.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_lua.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_php.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_python.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_rust.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_swift.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_text.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_ts.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_parser.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/reflection.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/util.cpp +) diff --git a/contrib/libs/flatbuffers/flatc/CMakeLists.txt b/contrib/libs/flatbuffers/flatc/CMakeLists.txt new file mode 100644 index 0000000000..f8b31df0c1 --- /dev/null +++ b/contrib/libs/flatbuffers/flatc/CMakeLists.txt @@ -0,0 +1,17 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + +if (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64" AND NOT HAVE_CUDA) + include(CMakeLists.linux-aarch64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") + include(CMakeLists.darwin-x86_64.txt) +elseif (WIN32 AND CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64" AND NOT HAVE_CUDA) + include(CMakeLists.windows-x86_64.txt) +elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" AND NOT HAVE_CUDA) + include(CMakeLists.linux-x86_64.txt) +endif() diff --git a/contrib/libs/flatbuffers/flatc/CMakeLists.windows-x86_64.txt b/contrib/libs/flatbuffers/flatc/CMakeLists.windows-x86_64.txt new file mode 100644 index 0000000000..ee54cbf098 --- /dev/null +++ b/contrib/libs/flatbuffers/flatc/CMakeLists.windows-x86_64.txt @@ -0,0 +1,52 @@ + +# This file was generated by the build system used internally in the Yandex monorepo. +# Only simple modifications are allowed (adding source-files to targets, adding simple properties +# like target_include_directories). These modifications will be ported to original +# ya.make files by maintainers. Any complex modifications which can't be ported back to the +# original buildsystem will not be accepted. + + + +add_library(libs-flatbuffers-flatc) +target_compile_options(libs-flatbuffers-flatc PRIVATE + -DFLATBUFFERS_LOCALE_INDEPENDENT=1 + $<IF:$<CXX_COMPILER_ID:MSVC>,,-Wno-everything> +) +target_include_directories(libs-flatbuffers-flatc PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/include +) +target_link_libraries(libs-flatbuffers-flatc PUBLIC + contrib-libs-cxxsupp +) +target_sources(libs-flatbuffers-flatc PRIVATE + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/cpp_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/go_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/java_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/python_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/swift_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/grpc/src/compiler/ts_generator.cc + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/code_generators.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/flatc.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_cpp.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_cpp_yandex_maps_iter.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_csharp.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_dart.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_fbs.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_go.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_grpc.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_java.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_json_schema.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_kotlin.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_lobster.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_lua.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_php.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_python.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_rust.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_swift.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_text.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_gen_ts.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/idl_parser.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/reflection.cpp + ${CMAKE_SOURCE_DIR}/contrib/libs/flatbuffers/src/util.cpp +) diff --git a/contrib/libs/flatbuffers/flatc/ya.make b/contrib/libs/flatbuffers/flatc/ya.make new file mode 100644 index 0000000000..7186851a35 --- /dev/null +++ b/contrib/libs/flatbuffers/flatc/ya.make @@ -0,0 +1,56 @@ +# Generated by devtools/yamaker. + +LIBRARY() + +WITHOUT_LICENSE_TEXTS() + +LICENSE(Apache-2.0) + +ADDINCL( + contrib/libs/flatbuffers/grpc + contrib/libs/flatbuffers/include +) + +NO_COMPILER_WARNINGS() + +NO_UTIL() + +CFLAGS( + -DFLATBUFFERS_LOCALE_INDEPENDENT=1 +) + +SRCDIR(contrib/libs/flatbuffers) + +SRCS( + grpc/src/compiler/cpp_generator.cc + grpc/src/compiler/go_generator.cc + grpc/src/compiler/java_generator.cc + grpc/src/compiler/python_generator.cc + grpc/src/compiler/swift_generator.cc + grpc/src/compiler/ts_generator.cc + src/code_generators.cpp + src/flatc.cpp + src/idl_gen_cpp.cpp + src/idl_gen_cpp_yandex_maps_iter.cpp + src/idl_gen_csharp.cpp + src/idl_gen_dart.cpp + src/idl_gen_fbs.cpp + src/idl_gen_go.cpp + src/idl_gen_grpc.cpp + src/idl_gen_java.cpp + src/idl_gen_json_schema.cpp + src/idl_gen_kotlin.cpp + src/idl_gen_lobster.cpp + src/idl_gen_lua.cpp + src/idl_gen_php.cpp + src/idl_gen_python.cpp + src/idl_gen_rust.cpp + src/idl_gen_swift.cpp + src/idl_gen_text.cpp + src/idl_gen_ts.cpp + src/idl_parser.cpp + src/reflection.cpp + src/util.cpp +) + +END() diff --git a/contrib/libs/flatbuffers/grpc/README.md b/contrib/libs/flatbuffers/grpc/README.md new file mode 100644 index 0000000000..685003f92b --- /dev/null +++ b/contrib/libs/flatbuffers/grpc/README.md @@ -0,0 +1,43 @@ +GRPC implementation and test +============================ + +NOTE: files in `src/` are shared with the GRPC project, and maintained there +(any changes should be submitted to GRPC instead). These files are copied +from GRPC, and work with both the Protobuf and FlatBuffers code generator. + +`tests/` contains a GRPC specific test, you need to have built and installed +the GRPC libraries for this to compile. This test will build using the +`FLATBUFFERS_BUILD_GRPCTEST` option to the main FlatBuffers CMake project. + +## Building Flatbuffers with gRPC + +### Linux + +1. Download, build and install gRPC. See [instructions](https://github.com/grpc/grpc/tree/master/src/cpp). + * Lets say your gRPC clone is at `/your/path/to/grpc_repo`. + * Install gRPC in a custom directory by running `make install prefix=/your/path/to/grpc_repo/install`. +2. `export GRPC_INSTALL_PATH=/your/path/to/grpc_repo/install` +3. `export PROTOBUF_DOWNLOAD_PATH=/your/path/to/grpc_repo/third_party/protobuf` +4. `mkdir build ; cd build` +5. `cmake -DFLATBUFFERS_BUILD_GRPCTEST=ON -DGRPC_INSTALL_PATH=${GRPC_INSTALL_PATH} -DPROTOBUF_DOWNLOAD_PATH=${PROTOBUF_DOWNLOAD_PATH} ..` +6. `make` + +For Bazel users: + +```shell +$bazel test src/compiler/... +``` + +## Running FlatBuffer gRPC tests + +### Linux + +1. `ln -s ${GRPC_INSTALL_PATH}/lib/libgrpc++_unsecure.so.6 ${GRPC_INSTALL_PATH}/lib/libgrpc++_unsecure.so.1` +2. `export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${GRPC_INSTALL_PATH}/lib` +3. `make test ARGS=-V` + +For Bazel users: + +```shell +$bazel test tests/... +```
\ No newline at end of file diff --git a/contrib/libs/flatbuffers/grpc/src/compiler/config.h b/contrib/libs/flatbuffers/grpc/src/compiler/config.h new file mode 100644 index 0000000000..4adc594377 --- /dev/null +++ b/contrib/libs/flatbuffers/grpc/src/compiler/config.h @@ -0,0 +1,40 @@ +/* + * + * Copyright 2015, Google Inc. + * 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 Inc. 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 THE COPYRIGHT + * OWNER OR CONTRIBUTORS 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. + * + */ + +#ifndef SRC_COMPILER_CONFIG_H +#define SRC_COMPILER_CONFIG_H + +// This file is here only because schema_interface.h, which is copied from gRPC, +// includes it. There is nothing for Flatbuffers to configure. + +#endif // SRC_COMPILER_CONFIG_H diff --git a/contrib/libs/flatbuffers/grpc/src/compiler/cpp_generator.cc b/contrib/libs/flatbuffers/grpc/src/compiler/cpp_generator.cc new file mode 100644 index 0000000000..8dd408830c --- /dev/null +++ b/contrib/libs/flatbuffers/grpc/src/compiler/cpp_generator.cc @@ -0,0 +1,1780 @@ +/* + * + * Copyright 2015, Google Inc. + * 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 Inc. 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 THE COPYRIGHT + * OWNER OR CONTRIBUTORS 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 <map> + +#include "src/compiler/cpp_generator.h" +#include "flatbuffers/util.h" + +#include <sstream> + +namespace grpc_cpp_generator { +namespace { + +grpc::string message_header_ext() { return "_generated.h"; } +grpc::string service_header_ext() { return ".grpc.fb.h"; } + +template <class T> +grpc::string as_string(T x) { + std::ostringstream out; + out << x; + return out.str(); +} + +inline bool ClientOnlyStreaming(const grpc_generator::Method *method) { + return method->ClientStreaming() && !method->ServerStreaming(); +} + +inline bool ServerOnlyStreaming(const grpc_generator::Method *method) { + return !method->ClientStreaming() && method->ServerStreaming(); +} + +grpc::string FilenameIdentifier(const grpc::string &filename) { + grpc::string result; + for (unsigned i = 0; i < filename.size(); i++) { + char c = filename[i]; + if (isalnum(c)) { + result.push_back(c); + } else { + static char hex[] = "0123456789abcdef"; + result.push_back('_'); + result.push_back(hex[(c >> 4) & 0xf]); + result.push_back(hex[c & 0xf]); + } + } + return result; +} +} // namespace + +template <class T, size_t N> +T *array_end(T (&array)[N]) { + return array + N; +} + +void PrintIncludes(grpc_generator::Printer *printer, + const std::vector<grpc::string> &headers, + const Parameters ¶ms) { + std::map<grpc::string, grpc::string> vars; + + vars["l"] = params.use_system_headers ? '<' : '"'; + vars["r"] = params.use_system_headers ? '>' : '"'; + + auto &s = params.grpc_search_path; + if (!s.empty()) { + vars["l"] += s; + if (s[s.size() - 1] != '/') { + vars["l"] += '/'; + } + } + + for (auto i = headers.begin(); i != headers.end(); i++) { + vars["h"] = *i; + printer->Print(vars, "#include $l$$h$$r$\n"); + } +} + +grpc::string GetHeaderPrologue(grpc_generator::File *file, + const Parameters & /*params*/) { + grpc::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map<grpc::string, grpc::string> vars; + + vars["filename"] = file->filename(); + vars["filename_identifier"] = FilenameIdentifier(file->filename()); + vars["filename_base"] = file->filename_without_ext(); + vars["message_header_ext"] = message_header_ext(); + + printer->Print(vars, "// Generated by the gRPC C++ plugin.\n"); + printer->Print(vars, + "// If you make any local change, they will be lost.\n"); + printer->Print(vars, "// source: $filename$\n"); + grpc::string leading_comments = file->GetLeadingComments("//"); + if (!leading_comments.empty()) { + printer->Print(vars, "// Original file comments:\n"); + printer->Print(leading_comments.c_str()); + } + printer->Print(vars, "#ifndef GRPC_$filename_identifier$__INCLUDED\n"); + printer->Print(vars, "#define GRPC_$filename_identifier$__INCLUDED\n"); + printer->Print(vars, "\n"); + printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n"); + printer->Print(vars, file->additional_headers().c_str()); + printer->Print(vars, "\n"); + } + return output; +} + +grpc::string GetHeaderIncludes(grpc_generator::File *file, + const Parameters ¶ms) { + grpc::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map<grpc::string, grpc::string> vars; + + static const char *headers_strs[] = { + "grpcpp/impl/codegen/async_stream.h", + "grpcpp/impl/codegen/async_unary_call.h", + "grpcpp/impl/codegen/method_handler.h", + "grpcpp/impl/codegen/proto_utils.h", + "grpcpp/impl/codegen/rpc_method.h", + "grpcpp/impl/codegen/service_type.h", + "grpcpp/impl/codegen/status.h", + "grpcpp/impl/codegen/stub_options.h", + "grpcpp/impl/codegen/sync_stream.h"}; + std::vector<grpc::string> headers(headers_strs, array_end(headers_strs)); + PrintIncludes(printer.get(), headers, params); + printer->Print(vars, "\n"); + printer->Print(vars, "namespace grpc {\n"); + printer->Print(vars, "class CompletionQueue;\n"); + printer->Print(vars, "class Channel;\n"); + printer->Print(vars, "class ServerCompletionQueue;\n"); + printer->Print(vars, "class ServerContext;\n"); + printer->Print(vars, "} // namespace grpc\n\n"); + + if (!file->package().empty()) { + std::vector<grpc::string> parts = file->package_parts(); + + for (auto part = parts.begin(); part != parts.end(); part++) { + vars["part"] = *part; + printer->Print(vars, "namespace $part$ {\n"); + } + printer->Print(vars, "\n"); + } + } + return output; +} + +void PrintHeaderClientMethodInterfaces( + grpc_generator::Printer *printer, const grpc_generator::Method *method, + std::map<grpc::string, grpc::string> *vars, bool is_public) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + + struct { + grpc::string prefix; + grpc::string method_params; // extra arguments to method + grpc::string raw_args; // extra arguments to raw version of method + } async_prefixes[] = {{"Async", ", void* tag", ", tag"}, + {"PrepareAsync", "", ""}}; + + if (is_public) { + if (method->NoStreaming()) { + printer->Print( + *vars, + "virtual ::grpc::Status $Method$(::grpc::ClientContext* context, " + "const $Request$& request, $Response$* response) = 0;\n"); + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + printer->Print( + *vars, + "std::unique_ptr< " + "::grpc::ClientAsyncResponseReaderInterface< $Response$>> " + "$AsyncPrefix$$Method$(::grpc::ClientContext* context, " + "const $Request$& request, " + "::grpc::CompletionQueue* cq) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncResponseReaderInterface< $Response$>>(" + "$AsyncPrefix$$Method$Raw(context, request, cq));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientWriterInterface< $Request$>>" + " $Method$(" + "::grpc::ClientContext* context, $Response$* response) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientWriterInterface< $Request$>>" + "($Method$Raw(context, response));\n"); + printer->Outdent(); + printer->Print("}\n"); + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientAsyncWriterInterface< $Request$>>" + " $AsyncPrefix$$Method$(::grpc::ClientContext* context, " + "$Response$* " + "response, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Indent(); + printer->Print(*vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncWriterInterface< $Request$>>(" + "$AsyncPrefix$$Method$Raw(context, response, " + "cq$AsyncRawArgs$));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientReaderInterface< $Response$>>" + " $Method$(::grpc::ClientContext* context, const $Request$& request)" + " {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientReaderInterface< $Response$>>" + "($Method$Raw(context, request));\n"); + printer->Outdent(); + printer->Print("}\n"); + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientAsyncReaderInterface< $Response$>> " + "$AsyncPrefix$$Method$(" + "::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncReaderInterface< $Response$>>(" + "$AsyncPrefix$$Method$Raw(context, request, cq$AsyncRawArgs$));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } else if (method->BidiStreaming()) { + printer->Print(*vars, + "std::unique_ptr< ::grpc::ClientReaderWriterInterface< " + "$Request$, $Response$>> " + "$Method$(::grpc::ClientContext* context) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientReaderWriterInterface< $Request$, $Response$>>(" + "$Method$Raw(context));\n"); + printer->Outdent(); + printer->Print("}\n"); + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "std::unique_ptr< " + "::grpc::ClientAsyncReaderWriterInterface< $Request$, $Response$>> " + "$AsyncPrefix$$Method$(::grpc::ClientContext* context, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncReaderWriterInterface< $Request$, $Response$>>(" + "$AsyncPrefix$$Method$Raw(context, cq$AsyncRawArgs$));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } + } else { + if (method->NoStreaming()) { + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + printer->Print( + *vars, + "virtual ::grpc::ClientAsyncResponseReaderInterface< $Response$>* " + "$AsyncPrefix$$Method$Raw(::grpc::ClientContext* context, " + "const $Request$& request, " + "::grpc::CompletionQueue* cq) = 0;\n"); + } + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + "virtual ::grpc::ClientWriterInterface< $Request$>*" + " $Method$Raw(" + "::grpc::ClientContext* context, $Response$* response) = 0;\n"); + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + printer->Print( + *vars, + "virtual ::grpc::ClientAsyncWriterInterface< $Request$>*" + " $AsyncPrefix$$Method$Raw(::grpc::ClientContext* context, " + "$Response$* response, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) = 0;\n"); + } + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "virtual ::grpc::ClientReaderInterface< $Response$>* " + "$Method$Raw(" + "::grpc::ClientContext* context, const $Request$& request) = 0;\n"); + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + printer->Print( + *vars, + "virtual ::grpc::ClientAsyncReaderInterface< $Response$>* " + "$AsyncPrefix$$Method$Raw(" + "::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) = 0;\n"); + } + } else if (method->BidiStreaming()) { + printer->Print(*vars, + "virtual ::grpc::ClientReaderWriterInterface< $Request$, " + "$Response$>* " + "$Method$Raw(::grpc::ClientContext* context) = 0;\n"); + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + printer->Print( + *vars, + "virtual ::grpc::ClientAsyncReaderWriterInterface< " + "$Request$, $Response$>* " + "$AsyncPrefix$$Method$Raw(::grpc::ClientContext* context, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) = 0;\n"); + } + } + } +} + +void PrintHeaderClientMethod(grpc_generator::Printer *printer, + const grpc_generator::Method *method, + std::map<grpc::string, grpc::string> *vars, + bool is_public) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + struct { + grpc::string prefix; + grpc::string method_params; // extra arguments to method + grpc::string raw_args; // extra arguments to raw version of method + } async_prefixes[] = {{"Async", ", void* tag", ", tag"}, + {"PrepareAsync", "", ""}}; + + if (is_public) { + if (method->NoStreaming()) { + printer->Print( + *vars, + "::grpc::Status $Method$(::grpc::ClientContext* context, " + "const $Request$& request, $Response$* response) override;\n"); + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientAsyncResponseReader< $Response$>> " + "$AsyncPrefix$$Method$(::grpc::ClientContext* context, " + "const $Request$& request, " + "::grpc::CompletionQueue* cq) {\n"); + printer->Indent(); + printer->Print(*vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncResponseReader< $Response$>>(" + "$AsyncPrefix$$Method$Raw(context, request, cq));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientWriter< $Request$>>" + " $Method$(" + "::grpc::ClientContext* context, $Response$* response) {\n"); + printer->Indent(); + printer->Print(*vars, + "return std::unique_ptr< ::grpc::ClientWriter< $Request$>>" + "($Method$Raw(context, response));\n"); + printer->Outdent(); + printer->Print("}\n"); + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print(*vars, + "std::unique_ptr< ::grpc::ClientAsyncWriter< $Request$>>" + " $AsyncPrefix$$Method$(::grpc::ClientContext* context, " + "$Response$* response, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientAsyncWriter< $Request$>>(" + "$AsyncPrefix$$Method$Raw(context, response, " + "cq$AsyncRawArgs$));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientReader< $Response$>>" + " $Method$(::grpc::ClientContext* context, const $Request$& request)" + " {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientReader< $Response$>>" + "($Method$Raw(context, request));\n"); + printer->Outdent(); + printer->Print("}\n"); + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>> " + "$AsyncPrefix$$Method$(" + "::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< ::grpc::ClientAsyncReader< $Response$>>(" + "$AsyncPrefix$$Method$Raw(context, request, cq$AsyncRawArgs$));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } else if (method->BidiStreaming()) { + printer->Print( + *vars, + "std::unique_ptr< ::grpc::ClientReaderWriter< $Request$, $Response$>>" + " $Method$(::grpc::ClientContext* context) {\n"); + printer->Indent(); + printer->Print(*vars, + "return std::unique_ptr< " + "::grpc::ClientReaderWriter< $Request$, $Response$>>(" + "$Method$Raw(context));\n"); + printer->Outdent(); + printer->Print("}\n"); + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print(*vars, + "std::unique_ptr< ::grpc::ClientAsyncReaderWriter< " + "$Request$, $Response$>> " + "$AsyncPrefix$$Method$(::grpc::ClientContext* context, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Indent(); + printer->Print( + *vars, + "return std::unique_ptr< " + "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>>(" + "$AsyncPrefix$$Method$Raw(context, cq$AsyncRawArgs$));\n"); + printer->Outdent(); + printer->Print("}\n"); + } + } + } else { + if (method->NoStreaming()) { + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + printer->Print( + *vars, + "::grpc::ClientAsyncResponseReader< $Response$>* " + "$AsyncPrefix$$Method$Raw(::grpc::ClientContext* context, " + "const $Request$& request, " + "::grpc::CompletionQueue* cq) override;\n"); + } + } else if (ClientOnlyStreaming(method)) { + printer->Print(*vars, + "::grpc::ClientWriter< $Request$>* $Method$Raw(" + "::grpc::ClientContext* context, $Response$* response) " + "override;\n"); + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "::grpc::ClientAsyncWriter< $Request$>* $AsyncPrefix$$Method$Raw(" + "::grpc::ClientContext* context, $Response$* response, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) override;\n"); + } + } else if (ServerOnlyStreaming(method)) { + printer->Print(*vars, + "::grpc::ClientReader< $Response$>* $Method$Raw(" + "::grpc::ClientContext* context, const $Request$& request)" + " override;\n"); + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "::grpc::ClientAsyncReader< $Response$>* $AsyncPrefix$$Method$Raw(" + "::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) override;\n"); + } + } else if (method->BidiStreaming()) { + printer->Print(*vars, + "::grpc::ClientReaderWriter< $Request$, $Response$>* " + "$Method$Raw(::grpc::ClientContext* context) override;\n"); + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncRawArgs"] = async_prefix.raw_args; + printer->Print( + *vars, + "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>* " + "$AsyncPrefix$$Method$Raw(::grpc::ClientContext* context, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) override;\n"); + } + } + } +} + +void PrintHeaderClientMethodData(grpc_generator::Printer *printer, + const grpc_generator::Method *method, + std::map<grpc::string, grpc::string> *vars) { + (*vars)["Method"] = method->name(); + printer->Print(*vars, + "const ::grpc::internal::RpcMethod rpcmethod_$Method$_;\n"); +} + +void PrintHeaderServerMethodSync(grpc_generator::Printer *printer, + const grpc_generator::Method *method, + std::map<grpc::string, grpc::string> *vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + printer->Print(method->GetLeadingComments("//").c_str()); + if (method->NoStreaming()) { + printer->Print(*vars, + "virtual ::grpc::Status $Method$(" + "::grpc::ServerContext* context, const $Request$* request, " + "$Response$* response);\n"); + } else if (ClientOnlyStreaming(method)) { + printer->Print(*vars, + "virtual ::grpc::Status $Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerReader< $Request$>* reader, " + "$Response$* response);\n"); + } else if (ServerOnlyStreaming(method)) { + printer->Print(*vars, + "virtual ::grpc::Status $Method$(" + "::grpc::ServerContext* context, const $Request$* request, " + "::grpc::ServerWriter< $Response$>* writer);\n"); + } else if (method->BidiStreaming()) { + printer->Print( + *vars, + "virtual ::grpc::Status $Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerReaderWriter< $Response$, $Request$>* stream);" + "\n"); + } + printer->Print(method->GetTrailingComments("//").c_str()); +} + +void PrintHeaderServerMethodAsync(grpc_generator::Printer *printer, + const grpc_generator::Method *method, + std::map<grpc::string, grpc::string> *vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + printer->Print(*vars, "template <class BaseClass>\n"); + printer->Print(*vars, + "class WithAsyncMethod_$Method$ : public BaseClass {\n"); + printer->Print( + " private:\n" + " void BaseClassMustBeDerivedFromService(const Service *service) {}\n"); + printer->Print(" public:\n"); + printer->Indent(); + printer->Print(*vars, + "WithAsyncMethod_$Method$() {\n" + " ::grpc::Service::MarkMethodAsync($Idx$);\n" + "}\n"); + printer->Print(*vars, + "~WithAsyncMethod_$Method$() override {\n" + " BaseClassMustBeDerivedFromService(this);\n" + "}\n"); + if (method->NoStreaming()) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* context, const $Request$* request, " + "$Response$* response) final override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + printer->Print( + *vars, + "void Request$Method$(" + "::grpc::ServerContext* context, $Request$* request, " + "::grpc::ServerAsyncResponseWriter< $Response$>* response, " + "::grpc::CompletionQueue* new_call_cq, " + "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n"); + printer->Print(*vars, + " ::grpc::Service::RequestAsyncUnary($Idx$, context, " + "request, response, new_call_cq, notification_cq, tag);\n"); + printer->Print("}\n"); + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerReader< $Request$>* reader, " + "$Response$* response) final override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + printer->Print( + *vars, + "void Request$Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerAsyncReader< $Response$, $Request$>* reader, " + "::grpc::CompletionQueue* new_call_cq, " + "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n"); + printer->Print(*vars, + " ::grpc::Service::RequestAsyncClientStreaming($Idx$, " + "context, reader, new_call_cq, notification_cq, tag);\n"); + printer->Print("}\n"); + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* context, const $Request$* request, " + "::grpc::ServerWriter< $Response$>* writer) final override " + "{\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + printer->Print( + *vars, + "void Request$Method$(" + "::grpc::ServerContext* context, $Request$* request, " + "::grpc::ServerAsyncWriter< $Response$>* writer, " + "::grpc::CompletionQueue* new_call_cq, " + "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n"); + printer->Print( + *vars, + " ::grpc::Service::RequestAsyncServerStreaming($Idx$, " + "context, request, writer, new_call_cq, notification_cq, tag);\n"); + printer->Print("}\n"); + } else if (method->BidiStreaming()) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerReaderWriter< $Response$, $Request$>* stream) " + "final override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + printer->Print( + *vars, + "void Request$Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerAsyncReaderWriter< $Response$, $Request$>* stream, " + "::grpc::CompletionQueue* new_call_cq, " + "::grpc::ServerCompletionQueue* notification_cq, void *tag) {\n"); + printer->Print(*vars, + " ::grpc::Service::RequestAsyncBidiStreaming($Idx$, " + "context, stream, new_call_cq, notification_cq, tag);\n"); + printer->Print("}\n"); + } + printer->Outdent(); + printer->Print(*vars, "};\n"); +} + +void PrintHeaderServerMethodStreamedUnary( + grpc_generator::Printer *printer, const grpc_generator::Method *method, + std::map<grpc::string, grpc::string> *vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + if (method->NoStreaming()) { + printer->Print(*vars, "template <class BaseClass>\n"); + printer->Print(*vars, + "class WithStreamedUnaryMethod_$Method$ : " + "public BaseClass {\n"); + printer->Print( + " private:\n" + " void BaseClassMustBeDerivedFromService(const Service *service) " + "{}\n"); + printer->Print(" public:\n"); + printer->Indent(); + printer->Print(*vars, + "WithStreamedUnaryMethod_$Method$() {\n" + " ::grpc::Service::MarkMethodStreamed($Idx$,\n" + " new ::grpc::internal::StreamedUnaryHandler< $Request$, " + "$Response$>(std::bind" + "(&WithStreamedUnaryMethod_$Method$<BaseClass>::" + "Streamed$Method$, this, std::placeholders::_1, " + "std::placeholders::_2)));\n" + "}\n"); + printer->Print(*vars, + "~WithStreamedUnaryMethod_$Method$() override {\n" + " BaseClassMustBeDerivedFromService(this);\n" + "}\n"); + printer->Print( + *vars, + "// disable regular version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* context, const $Request$* request, " + "$Response$* response) final override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + printer->Print(*vars, + "// replace default version of method with streamed unary\n" + "virtual ::grpc::Status Streamed$Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerUnaryStreamer< " + "$Request$,$Response$>* server_unary_streamer)" + " = 0;\n"); + printer->Outdent(); + printer->Print(*vars, "};\n"); + } +} + +void PrintHeaderServerMethodSplitStreaming( + grpc_generator::Printer *printer, const grpc_generator::Method *method, + std::map<grpc::string, grpc::string> *vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + if (ServerOnlyStreaming(method)) { + printer->Print(*vars, "template <class BaseClass>\n"); + printer->Print(*vars, + "class WithSplitStreamingMethod_$Method$ : " + "public BaseClass {\n"); + printer->Print( + " private:\n" + " void BaseClassMustBeDerivedFromService(const Service *service) " + "{}\n"); + printer->Print(" public:\n"); + printer->Indent(); + printer->Print( + *vars, + "WithSplitStreamingMethod_$Method$() {\n" + " ::grpc::Service::MarkMethodStreamed($Idx$,\n" + " new ::grpc::internal::SplitServerStreamingHandler< $Request$, " + "$Response$>(std::bind" + "(&WithSplitStreamingMethod_$Method$<BaseClass>::" + "Streamed$Method$, this, std::placeholders::_1, " + "std::placeholders::_2)));\n" + "}\n"); + printer->Print(*vars, + "~WithSplitStreamingMethod_$Method$() override {\n" + " BaseClassMustBeDerivedFromService(this);\n" + "}\n"); + printer->Print( + *vars, + "// disable regular version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* context, const $Request$* request, " + "::grpc::ServerWriter< $Response$>* writer) final override " + "{\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + printer->Print(*vars, + "// replace default version of method with split streamed\n" + "virtual ::grpc::Status Streamed$Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerSplitStreamer< " + "$Request$,$Response$>* server_split_streamer)" + " = 0;\n"); + printer->Outdent(); + printer->Print(*vars, "};\n"); + } +} + +void PrintHeaderServerMethodGeneric( + grpc_generator::Printer *printer, const grpc_generator::Method *method, + std::map<grpc::string, grpc::string> *vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + printer->Print(*vars, "template <class BaseClass>\n"); + printer->Print(*vars, + "class WithGenericMethod_$Method$ : public BaseClass {\n"); + printer->Print( + " private:\n" + " void BaseClassMustBeDerivedFromService(const Service *service) {}\n"); + printer->Print(" public:\n"); + printer->Indent(); + printer->Print(*vars, + "WithGenericMethod_$Method$() {\n" + " ::grpc::Service::MarkMethodGeneric($Idx$);\n" + "}\n"); + printer->Print(*vars, + "~WithGenericMethod_$Method$() override {\n" + " BaseClassMustBeDerivedFromService(this);\n" + "}\n"); + if (method->NoStreaming()) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* context, const $Request$* request, " + "$Response$* response) final override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerReader< $Request$>* reader, " + "$Response$* response) final override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* context, const $Request$* request, " + "::grpc::ServerWriter< $Response$>* writer) final override " + "{\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } else if (method->BidiStreaming()) { + printer->Print( + *vars, + "// disable synchronous version of this method\n" + "::grpc::Status $Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerReaderWriter< $Response$, $Request$>* stream) " + "final override {\n" + " abort();\n" + " return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, \"\");\n" + "}\n"); + } + printer->Outdent(); + printer->Print(*vars, "};\n"); +} + +void PrintHeaderService(grpc_generator::Printer *printer, + const grpc_generator::Service *service, + std::map<grpc::string, grpc::string> *vars) { + (*vars)["Service"] = service->name(); + + printer->Print(service->GetLeadingComments("//").c_str()); + printer->Print(*vars, + "class $Service$ final {\n" + " public:\n"); + printer->Indent(); + + // Service metadata + printer->Print(*vars, + "static constexpr char const* service_full_name() {\n" + " return \"$Package$$Service$\";\n" + "}\n"); + + // Client side + printer->Print( + "class StubInterface {\n" + " public:\n"); + printer->Indent(); + printer->Print("virtual ~StubInterface() {}\n"); + for (int i = 0; i < service->method_count(); ++i) { + printer->Print(service->method(i)->GetLeadingComments("//").c_str()); + PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), vars, + true); + printer->Print(service->method(i)->GetTrailingComments("//").c_str()); + } + printer->Outdent(); + printer->Print("private:\n"); + printer->Indent(); + for (int i = 0; i < service->method_count(); ++i) { + PrintHeaderClientMethodInterfaces(printer, service->method(i).get(), vars, + false); + } + printer->Outdent(); + printer->Print("};\n"); + printer->Print( + "class Stub final : public StubInterface" + " {\n public:\n"); + printer->Indent(); + printer->Print( + "Stub(const std::shared_ptr< ::grpc::ChannelInterface>& " + "channel);\n"); + for (int i = 0; i < service->method_count(); ++i) { + PrintHeaderClientMethod(printer, service->method(i).get(), vars, true); + } + printer->Outdent(); + printer->Print("\n private:\n"); + printer->Indent(); + printer->Print("std::shared_ptr< ::grpc::ChannelInterface> channel_;\n"); + for (int i = 0; i < service->method_count(); ++i) { + PrintHeaderClientMethod(printer, service->method(i).get(), vars, false); + } + for (int i = 0; i < service->method_count(); ++i) { + PrintHeaderClientMethodData(printer, service->method(i).get(), vars); + } + printer->Outdent(); + printer->Print("};\n"); + printer->Print( + "static std::unique_ptr<Stub> NewStub(const std::shared_ptr< " + "::grpc::ChannelInterface>& channel, " + "const ::grpc::StubOptions& options = ::grpc::StubOptions());\n"); + + printer->Print("\n"); + + // Server side - base + printer->Print( + "class Service : public ::grpc::Service {\n" + " public:\n"); + printer->Indent(); + printer->Print("Service();\n"); + printer->Print("virtual ~Service();\n"); + for (int i = 0; i < service->method_count(); ++i) { + PrintHeaderServerMethodSync(printer, service->method(i).get(), vars); + } + printer->Outdent(); + printer->Print("};\n"); + + // Server side - Asynchronous + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintHeaderServerMethodAsync(printer, service->method(i).get(), vars); + } + + printer->Print("typedef "); + + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["method_name"] = service->method(i).get()->name(); + printer->Print(*vars, "WithAsyncMethod_$method_name$<"); + } + printer->Print("Service"); + for (int i = 0; i < service->method_count(); ++i) { + printer->Print(" >"); + } + printer->Print(" AsyncService;\n"); + + // Server side - Generic + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintHeaderServerMethodGeneric(printer, service->method(i).get(), vars); + } + + // Server side - Streamed Unary + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintHeaderServerMethodStreamedUnary(printer, service->method(i).get(), + vars); + } + + printer->Print("typedef "); + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["method_name"] = service->method(i).get()->name(); + if (service->method(i)->NoStreaming()) { + printer->Print(*vars, "WithStreamedUnaryMethod_$method_name$<"); + } + } + printer->Print("Service"); + for (int i = 0; i < service->method_count(); ++i) { + if (service->method(i)->NoStreaming()) { + printer->Print(" >"); + } + } + printer->Print(" StreamedUnaryService;\n"); + + // Server side - controlled server-side streaming + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintHeaderServerMethodSplitStreaming(printer, service->method(i).get(), + vars); + } + + printer->Print("typedef "); + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["method_name"] = service->method(i).get()->name(); + auto method = service->method(i); + if (ServerOnlyStreaming(method.get())) { + printer->Print(*vars, "WithSplitStreamingMethod_$method_name$<"); + } + } + printer->Print("Service"); + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + if (ServerOnlyStreaming(method.get())) { + printer->Print(" >"); + } + } + printer->Print(" SplitStreamedService;\n"); + + // Server side - typedef for controlled both unary and server-side streaming + printer->Print("typedef "); + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["method_name"] = service->method(i).get()->name(); + auto method = service->method(i); + if (ServerOnlyStreaming(method.get())) { + printer->Print(*vars, "WithSplitStreamingMethod_$method_name$<"); + } + if (service->method(i)->NoStreaming()) { + printer->Print(*vars, "WithStreamedUnaryMethod_$method_name$<"); + } + } + printer->Print("Service"); + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + if (service->method(i)->NoStreaming() || + ServerOnlyStreaming(method.get())) { + printer->Print(" >"); + } + } + printer->Print(" StreamedService;\n"); + + printer->Outdent(); + printer->Print("};\n"); + printer->Print(service->GetTrailingComments("//").c_str()); +} + +grpc::string GetHeaderServices(grpc_generator::File *file, + const Parameters ¶ms) { + grpc::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map<grpc::string, grpc::string> vars; + // Package string is empty or ends with a dot. It is used to fully qualify + // method names. + vars["Package"] = file->package(); + if (!file->package().empty()) { + vars["Package"].append("."); + } + + if (!params.services_namespace.empty()) { + vars["services_namespace"] = params.services_namespace; + printer->Print(vars, "\nnamespace $services_namespace$ {\n\n"); + } + + for (int i = 0; i < file->service_count(); ++i) { + PrintHeaderService(printer.get(), file->service(i).get(), &vars); + printer->Print("\n"); + } + + if (!params.services_namespace.empty()) { + printer->Print(vars, "} // namespace $services_namespace$\n\n"); + } + } + return output; +} + +grpc::string GetHeaderEpilogue(grpc_generator::File *file, + const Parameters & /*params*/) { + grpc::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map<grpc::string, grpc::string> vars; + + vars["filename"] = file->filename(); + vars["filename_identifier"] = FilenameIdentifier(file->filename()); + + if (!file->package().empty()) { + std::vector<grpc::string> parts = file->package_parts(); + + for (auto part = parts.rbegin(); part != parts.rend(); part++) { + vars["part"] = *part; + printer->Print(vars, "} // namespace $part$\n"); + } + printer->Print(vars, "\n"); + } + + printer->Print(vars, "\n"); + printer->Print(vars, "#endif // GRPC_$filename_identifier$__INCLUDED\n"); + + printer->Print(file->GetTrailingComments("//").c_str()); + } + return output; +} + +grpc::string GetSourcePrologue(grpc_generator::File *file, + const Parameters & /*params*/) { + grpc::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map<grpc::string, grpc::string> vars; + + vars["filename"] = file->filename(); + vars["filename_base"] = file->filename_without_ext(); + vars["message_header_ext"] = message_header_ext(); + vars["service_header_ext"] = service_header_ext(); + + printer->Print(vars, "// Generated by the gRPC C++ plugin.\n"); + printer->Print(vars, + "// If you make any local change, they will be lost.\n"); + printer->Print(vars, "// source: $filename$\n\n"); + + printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n"); + printer->Print(vars, "#include \"$filename_base$$service_header_ext$\"\n"); + printer->Print(vars, "\n"); + } + return output; +} + +grpc::string GetSourceIncludes(grpc_generator::File *file, + const Parameters ¶ms) { + grpc::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map<grpc::string, grpc::string> vars; + + static const char *headers_strs[] = { + "grpcpp/impl/codegen/async_stream.h", + "grpcpp/impl/codegen/async_unary_call.h", + "grpcpp/impl/codegen/channel_interface.h", + "grpcpp/impl/codegen/client_unary_call.h", + "grpcpp/impl/codegen/method_handler.h", + "grpcpp/impl/codegen/rpc_service_method.h", + "grpcpp/impl/codegen/service_type.h", + "grpcpp/impl/codegen/sync_stream.h"}; + std::vector<grpc::string> headers(headers_strs, array_end(headers_strs)); + PrintIncludes(printer.get(), headers, params); + + if (!file->package().empty()) { + std::vector<grpc::string> parts = file->package_parts(); + + for (auto part = parts.begin(); part != parts.end(); part++) { + vars["part"] = *part; + printer->Print(vars, "namespace $part$ {\n"); + } + } + + printer->Print(vars, "\n"); + } + return output; +} + +void PrintSourceClientMethod(grpc_generator::Printer *printer, + const grpc_generator::Method *method, + std::map<grpc::string, grpc::string> *vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + struct { + grpc::string prefix; + grpc::string start; // bool literal expressed as string + grpc::string method_params; // extra arguments to method + grpc::string create_args; // extra arguments to creator + } async_prefixes[] = {{"Async", "true", ", void* tag", ", tag"}, + {"PrepareAsync", "false", "", ", nullptr"}}; + if (method->NoStreaming()) { + printer->Print(*vars, + "::grpc::Status $ns$$Service$::Stub::$Method$(" + "::grpc::ClientContext* context, " + "const $Request$& request, $Response$* response) {\n"); + printer->Print(*vars, + " return ::grpc::internal::BlockingUnaryCall" + "(channel_.get(), rpcmethod_$Method$_, " + "context, request, response);\n}\n\n"); + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncStart"] = async_prefix.start; + printer->Print(*vars, + "::grpc::ClientAsyncResponseReader< $Response$>* " + "$ns$$Service$::Stub::$AsyncPrefix$$Method$Raw(::grpc::" + "ClientContext* context, " + "const $Request$& request, " + "::grpc::CompletionQueue* cq) {\n"); + printer->Print( + *vars, + " return " + "::grpc::internal::ClientAsyncResponseReaderFactory< $Response$>" + "::Create(channel_.get(), cq, " + "rpcmethod_$Method$_, " + "context, request, $AsyncStart$);\n" + "}\n\n"); + } + } else if (ClientOnlyStreaming(method)) { + printer->Print(*vars, + "::grpc::ClientWriter< $Request$>* " + "$ns$$Service$::Stub::$Method$Raw(" + "::grpc::ClientContext* context, $Response$* response) {\n"); + printer->Print( + *vars, + " return ::grpc::internal::ClientWriterFactory< $Request$>::Create(" + "channel_.get(), " + "rpcmethod_$Method$_, " + "context, response);\n" + "}\n\n"); + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncStart"] = async_prefix.start; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncCreateArgs"] = async_prefix.create_args; + printer->Print(*vars, + "::grpc::ClientAsyncWriter< $Request$>* " + "$ns$$Service$::Stub::$AsyncPrefix$$Method$Raw(" + "::grpc::ClientContext* context, $Response$* response, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Print( + *vars, + " return ::grpc::internal::ClientAsyncWriterFactory< $Request$>" + "::Create(channel_.get(), cq, " + "rpcmethod_$Method$_, " + "context, response, $AsyncStart$$AsyncCreateArgs$);\n" + "}\n\n"); + } + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "::grpc::ClientReader< $Response$>* " + "$ns$$Service$::Stub::$Method$Raw(" + "::grpc::ClientContext* context, const $Request$& request) {\n"); + printer->Print( + *vars, + " return ::grpc::internal::ClientReaderFactory< $Response$>::Create(" + "channel_.get(), " + "rpcmethod_$Method$_, " + "context, request);\n" + "}\n\n"); + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncStart"] = async_prefix.start; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncCreateArgs"] = async_prefix.create_args; + printer->Print( + *vars, + "::grpc::ClientAsyncReader< $Response$>* " + "$ns$$Service$::Stub::$AsyncPrefix$$Method$Raw(" + "::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Print( + *vars, + " return ::grpc::internal::ClientAsyncReaderFactory< $Response$>" + "::Create(channel_.get(), cq, " + "rpcmethod_$Method$_, " + "context, request, $AsyncStart$$AsyncCreateArgs$);\n" + "}\n\n"); + } + } else if (method->BidiStreaming()) { + printer->Print( + *vars, + "::grpc::ClientReaderWriter< $Request$, $Response$>* " + "$ns$$Service$::Stub::$Method$Raw(::grpc::ClientContext* context) {\n"); + printer->Print(*vars, + " return ::grpc::internal::ClientReaderWriterFactory< " + "$Request$, $Response$>::Create(" + "channel_.get(), " + "rpcmethod_$Method$_, " + "context);\n" + "}\n\n"); + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncStart"] = async_prefix.start; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["AsyncCreateArgs"] = async_prefix.create_args; + printer->Print(*vars, + "::grpc::ClientAsyncReaderWriter< $Request$, $Response$>* " + "$ns$$Service$::Stub::$AsyncPrefix$$Method$Raw(::grpc::" + "ClientContext* context, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$) {\n"); + printer->Print(*vars, + " return " + "::grpc::internal::ClientAsyncReaderWriterFactory< " + "$Request$, $Response$>::Create(" + "channel_.get(), cq, " + "rpcmethod_$Method$_, " + "context, $AsyncStart$$AsyncCreateArgs$);\n" + "}\n\n"); + } + } +} + +void PrintSourceServerMethod(grpc_generator::Printer *printer, + const grpc_generator::Method *method, + std::map<grpc::string, grpc::string> *vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + if (method->NoStreaming()) { + printer->Print(*vars, + "::grpc::Status $ns$$Service$::Service::$Method$(" + "::grpc::ServerContext* context, " + "const $Request$* request, $Response$* response) {\n"); + printer->Print(" (void) context;\n"); + printer->Print(" (void) request;\n"); + printer->Print(" (void) response;\n"); + printer->Print( + " return ::grpc::Status(" + "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"); + printer->Print("}\n\n"); + } else if (ClientOnlyStreaming(method)) { + printer->Print(*vars, + "::grpc::Status $ns$$Service$::Service::$Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerReader< $Request$>* reader, " + "$Response$* response) {\n"); + printer->Print(" (void) context;\n"); + printer->Print(" (void) reader;\n"); + printer->Print(" (void) response;\n"); + printer->Print( + " return ::grpc::Status(" + "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"); + printer->Print("}\n\n"); + } else if (ServerOnlyStreaming(method)) { + printer->Print(*vars, + "::grpc::Status $ns$$Service$::Service::$Method$(" + "::grpc::ServerContext* context, " + "const $Request$* request, " + "::grpc::ServerWriter< $Response$>* writer) {\n"); + printer->Print(" (void) context;\n"); + printer->Print(" (void) request;\n"); + printer->Print(" (void) writer;\n"); + printer->Print( + " return ::grpc::Status(" + "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"); + printer->Print("}\n\n"); + } else if (method->BidiStreaming()) { + printer->Print(*vars, + "::grpc::Status $ns$$Service$::Service::$Method$(" + "::grpc::ServerContext* context, " + "::grpc::ServerReaderWriter< $Response$, $Request$>* " + "stream) {\n"); + printer->Print(" (void) context;\n"); + printer->Print(" (void) stream;\n"); + printer->Print( + " return ::grpc::Status(" + "::grpc::StatusCode::UNIMPLEMENTED, \"\");\n"); + printer->Print("}\n\n"); + } +} + +void PrintSourceService(grpc_generator::Printer *printer, + const grpc_generator::Service *service, + std::map<grpc::string, grpc::string> *vars) { + (*vars)["Service"] = service->name(); + + if (service->method_count() > 0) { + printer->Print(*vars, + "static const char* $prefix$$Service$_method_names[] = {\n"); + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Method"] = service->method(i).get()->name(); + printer->Print(*vars, " \"/$Package$$Service$/$Method$\",\n"); + } + printer->Print(*vars, "};\n\n"); + } + + printer->Print(*vars, + "std::unique_ptr< $ns$$Service$::Stub> $ns$$Service$::NewStub(" + "const std::shared_ptr< ::grpc::ChannelInterface>& channel, " + "const ::grpc::StubOptions& options) {\n" + " std::unique_ptr< $ns$$Service$::Stub> stub(new " + "$ns$$Service$::Stub(channel));\n" + " return stub;\n" + "}\n\n"); + printer->Print(*vars, + "$ns$$Service$::Stub::Stub(const std::shared_ptr< " + "::grpc::ChannelInterface>& channel)\n"); + printer->Indent(); + printer->Print(": channel_(channel)"); + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + (*vars)["Method"] = method->name(); + (*vars)["Idx"] = as_string(i); + if (method->NoStreaming()) { + (*vars)["StreamingType"] = "NORMAL_RPC"; + // NOTE: There is no reason to consider streamed-unary as a separate + // category here since this part is setting up the client-side stub + // and this appears as a NORMAL_RPC from the client-side. + } else if (ClientOnlyStreaming(method.get())) { + (*vars)["StreamingType"] = "CLIENT_STREAMING"; + } else if (ServerOnlyStreaming(method.get())) { + (*vars)["StreamingType"] = "SERVER_STREAMING"; + } else { + (*vars)["StreamingType"] = "BIDI_STREAMING"; + } + printer->Print(*vars, + ", rpcmethod_$Method$_(" + "$prefix$$Service$_method_names[$Idx$], " + "::grpc::internal::RpcMethod::$StreamingType$, " + "channel" + ")\n"); + } + printer->Print("{}\n\n"); + printer->Outdent(); + + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintSourceClientMethod(printer, service->method(i).get(), vars); + } + + printer->Print(*vars, "$ns$$Service$::Service::Service() {\n"); + printer->Indent(); + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + (*vars)["Idx"] = as_string(i); + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + if (method->NoStreaming()) { + printer->Print( + *vars, + "AddMethod(new ::grpc::internal::RpcServiceMethod(\n" + " $prefix$$Service$_method_names[$Idx$],\n" + " ::grpc::internal::RpcMethod::NORMAL_RPC,\n" + " new ::grpc::internal::RpcMethodHandler< $ns$$Service$::Service, " + "$Request$, " + "$Response$>(\n" + " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n"); + } else if (ClientOnlyStreaming(method.get())) { + printer->Print( + *vars, + "AddMethod(new ::grpc::internal::RpcServiceMethod(\n" + " $prefix$$Service$_method_names[$Idx$],\n" + " ::grpc::internal::RpcMethod::CLIENT_STREAMING,\n" + " new ::grpc::internal::ClientStreamingHandler< " + "$ns$$Service$::Service, $Request$, $Response$>(\n" + " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n"); + } else if (ServerOnlyStreaming(method.get())) { + printer->Print( + *vars, + "AddMethod(new ::grpc::internal::RpcServiceMethod(\n" + " $prefix$$Service$_method_names[$Idx$],\n" + " ::grpc::internal::RpcMethod::SERVER_STREAMING,\n" + " new ::grpc::internal::ServerStreamingHandler< " + "$ns$$Service$::Service, $Request$, $Response$>(\n" + " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n"); + } else if (method->BidiStreaming()) { + printer->Print( + *vars, + "AddMethod(new ::grpc::internal::RpcServiceMethod(\n" + " $prefix$$Service$_method_names[$Idx$],\n" + " ::grpc::internal::RpcMethod::BIDI_STREAMING,\n" + " new ::grpc::internal::BidiStreamingHandler< " + "$ns$$Service$::Service, $Request$, $Response$>(\n" + " std::mem_fn(&$ns$$Service$::Service::$Method$), this)));\n"); + } + } + printer->Outdent(); + printer->Print(*vars, "}\n\n"); + printer->Print(*vars, + "$ns$$Service$::Service::~Service() {\n" + "}\n\n"); + for (int i = 0; i < service->method_count(); ++i) { + (*vars)["Idx"] = as_string(i); + PrintSourceServerMethod(printer, service->method(i).get(), vars); + } +} + +grpc::string GetSourceServices(grpc_generator::File *file, + const Parameters ¶ms) { + grpc::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map<grpc::string, grpc::string> vars; + // Package string is empty or ends with a dot. It is used to fully qualify + // method names. + vars["Package"] = file->package(); + if (!file->package().empty()) { + vars["Package"].append("."); + } + if (!params.services_namespace.empty()) { + vars["ns"] = params.services_namespace + "::"; + vars["prefix"] = params.services_namespace; + } else { + vars["ns"] = ""; + vars["prefix"] = ""; + } + + for (int i = 0; i < file->service_count(); ++i) { + PrintSourceService(printer.get(), file->service(i).get(), &vars); + printer->Print("\n"); + } + } + return output; +} + +grpc::string GetSourceEpilogue(grpc_generator::File *file, + const Parameters & /*params*/) { + grpc::string temp; + + if (!file->package().empty()) { + std::vector<grpc::string> parts = file->package_parts(); + + for (auto part = parts.begin(); part != parts.end(); part++) { + temp.append("} // namespace "); + temp.append(*part); + temp.append("\n"); + } + temp.append("\n"); + } + + return temp; +} + +// TODO(mmukhi): Make sure we need parameters or not. +grpc::string GetMockPrologue(grpc_generator::File *file, + const Parameters & /*params*/) { + grpc::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map<grpc::string, grpc::string> vars; + + vars["filename"] = file->filename(); + vars["filename_base"] = file->filename_without_ext(); + vars["message_header_ext"] = message_header_ext(); + vars["service_header_ext"] = service_header_ext(); + + printer->Print(vars, "// Generated by the gRPC C++ plugin.\n"); + printer->Print(vars, + "// If you make any local change, they will be lost.\n"); + printer->Print(vars, "// source: $filename$\n\n"); + + printer->Print(vars, "#include \"$filename_base$$message_header_ext$\"\n"); + printer->Print(vars, "#include \"$filename_base$$service_header_ext$\"\n"); + printer->Print(vars, file->additional_headers().c_str()); + printer->Print(vars, "\n"); + } + return output; +} + +// TODO(mmukhi): Add client-stream and completion-queue headers. +grpc::string GetMockIncludes(grpc_generator::File *file, + const Parameters ¶ms) { + grpc::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map<grpc::string, grpc::string> vars; + + static const char *headers_strs[] = { + "grpcpp/impl/codegen/async_stream.h", + "grpcpp/impl/codegen/sync_stream.h", + "gmock/gmock.h", + }; + std::vector<grpc::string> headers(headers_strs, array_end(headers_strs)); + PrintIncludes(printer.get(), headers, params); + + if (!file->package().empty()) { + std::vector<grpc::string> parts = file->package_parts(); + + for (auto part = parts.begin(); part != parts.end(); part++) { + vars["part"] = *part; + printer->Print(vars, "namespace $part$ {\n"); + } + } + + printer->Print(vars, "\n"); + } + return output; +} + +void PrintMockClientMethods(grpc_generator::Printer *printer, + const grpc_generator::Method *method, + std::map<grpc::string, grpc::string> *vars) { + (*vars)["Method"] = method->name(); + (*vars)["Request"] = method->input_type_name(); + (*vars)["Response"] = method->output_type_name(); + + struct { + grpc::string prefix; + grpc::string method_params; // extra arguments to method + int extra_method_param_count; + } async_prefixes[] = {{"Async", ", void* tag", 1}, {"PrepareAsync", "", 0}}; + + if (method->NoStreaming()) { + printer->Print( + *vars, + "MOCK_METHOD3($Method$, ::grpc::Status(::grpc::ClientContext* context, " + "const $Request$& request, $Response$* response));\n"); + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + printer->Print( + *vars, + "MOCK_METHOD3($AsyncPrefix$$Method$Raw, " + "::grpc::ClientAsyncResponseReaderInterface< $Response$>*" + "(::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq));\n"); + } + } else if (ClientOnlyStreaming(method)) { + printer->Print( + *vars, + "MOCK_METHOD2($Method$Raw, " + "::grpc::ClientWriterInterface< $Request$>*" + "(::grpc::ClientContext* context, $Response$* response));\n"); + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["MockArgs"] = + flatbuffers::NumToString(3 + async_prefix.extra_method_param_count); + printer->Print(*vars, + "MOCK_METHOD$MockArgs$($AsyncPrefix$$Method$Raw, " + "::grpc::ClientAsyncWriterInterface< $Request$>*" + "(::grpc::ClientContext* context, $Response$* response, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$));\n"); + } + } else if (ServerOnlyStreaming(method)) { + printer->Print( + *vars, + "MOCK_METHOD2($Method$Raw, " + "::grpc::ClientReaderInterface< $Response$>*" + "(::grpc::ClientContext* context, const $Request$& request));\n"); + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["MockArgs"] = + flatbuffers::NumToString(3 + async_prefix.extra_method_param_count); + printer->Print( + *vars, + "MOCK_METHOD$MockArgs$($AsyncPrefix$$Method$Raw, " + "::grpc::ClientAsyncReaderInterface< $Response$>*" + "(::grpc::ClientContext* context, const $Request$& request, " + "::grpc::CompletionQueue* cq$AsyncMethodParams$));\n"); + } + } else if (method->BidiStreaming()) { + printer->Print( + *vars, + "MOCK_METHOD1($Method$Raw, " + "::grpc::ClientReaderWriterInterface< $Request$, $Response$>*" + "(::grpc::ClientContext* context));\n"); + for (size_t i = 0; i < sizeof(async_prefixes)/sizeof(async_prefixes[0]); i ++) { + auto& async_prefix = async_prefixes[i]; + (*vars)["AsyncPrefix"] = async_prefix.prefix; + (*vars)["AsyncMethodParams"] = async_prefix.method_params; + (*vars)["MockArgs"] = + flatbuffers::NumToString(2 + async_prefix.extra_method_param_count); + printer->Print( + *vars, + "MOCK_METHOD$MockArgs$($AsyncPrefix$$Method$Raw, " + "::grpc::ClientAsyncReaderWriterInterface<$Request$, $Response$>*" + "(::grpc::ClientContext* context, ::grpc::CompletionQueue* cq" + "$AsyncMethodParams$));\n"); + } + } +} + +void PrintMockService(grpc_generator::Printer *printer, + const grpc_generator::Service *service, + std::map<grpc::string, grpc::string> *vars) { + (*vars)["Service"] = service->name(); + + printer->Print(*vars, + "class Mock$Service$Stub : public $Service$::StubInterface {\n" + " public:\n"); + printer->Indent(); + for (int i = 0; i < service->method_count(); ++i) { + PrintMockClientMethods(printer, service->method(i).get(), vars); + } + printer->Outdent(); + printer->Print("};\n"); +} + +grpc::string GetMockServices(grpc_generator::File *file, + const Parameters ¶ms) { + grpc::string output; + { + // Scope the output stream so it closes and finalizes output to the string. + auto printer = file->CreatePrinter(&output); + std::map<grpc::string, grpc::string> vars; + // Package string is empty or ends with a dot. It is used to fully qualify + // method names. + vars["Package"] = file->package(); + if (!file->package().empty()) { + vars["Package"].append("."); + } + + if (!params.services_namespace.empty()) { + vars["services_namespace"] = params.services_namespace; + printer->Print(vars, "\nnamespace $services_namespace$ {\n\n"); + } + + for (int i = 0; i < file->service_count(); i++) { + PrintMockService(printer.get(), file->service(i).get(), &vars); + printer->Print("\n"); + } + + if (!params.services_namespace.empty()) { + printer->Print(vars, "} // namespace $services_namespace$\n\n"); + } + } + return output; +} + +grpc::string GetMockEpilogue(grpc_generator::File *file, + const Parameters & /*params*/) { + grpc::string temp; + + if (!file->package().empty()) { + std::vector<grpc::string> parts = file->package_parts(); + + for (auto part = parts.begin(); part != parts.end(); part++) { + temp.append("} // namespace "); + temp.append(*part); + temp.append("\n"); + } + temp.append("\n"); + } + + return temp; +} + +} // namespace grpc_cpp_generator diff --git a/contrib/libs/flatbuffers/grpc/src/compiler/cpp_generator.h b/contrib/libs/flatbuffers/grpc/src/compiler/cpp_generator.h new file mode 100644 index 0000000000..6119ebe289 --- /dev/null +++ b/contrib/libs/flatbuffers/grpc/src/compiler/cpp_generator.h @@ -0,0 +1,138 @@ +/* + * + * Copyright 2015, Google Inc. + * 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 Inc. 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 THE COPYRIGHT + * OWNER OR CONTRIBUTORS 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. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H +#define GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H + +// cpp_generator.h/.cc do not directly depend on GRPC/ProtoBuf, such that they +// can be used to generate code for other serialization systems, such as +// FlatBuffers. + +#include <memory> +#include <vector> + +#include "src/compiler/config.h" +#include "src/compiler/schema_interface.h" + +#ifndef GRPC_CUSTOM_STRING +#include <string> +#define GRPC_CUSTOM_STRING std::string +#endif + +namespace grpc { + +typedef GRPC_CUSTOM_STRING string; + +} // namespace grpc + +namespace grpc_cpp_generator { + +// Contains all the parameters that are parsed from the command line. +struct Parameters { + // Puts the service into a namespace + grpc::string services_namespace; + // Use system includes (<>) or local includes ("") + bool use_system_headers; + // Prefix to any grpc include + grpc::string grpc_search_path; + // Generate GMOCK code to facilitate unit testing. + bool generate_mock_code; +}; + +// Return the prologue of the generated header file. +grpc::string GetHeaderPrologue(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the includes needed for generated header file. +grpc::string GetHeaderIncludes(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the includes needed for generated source file. +grpc::string GetSourceIncludes(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the epilogue of the generated header file. +grpc::string GetHeaderEpilogue(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the prologue of the generated source file. +grpc::string GetSourcePrologue(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the services for generated header file. +grpc::string GetHeaderServices(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the services for generated source file. +grpc::string GetSourceServices(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the epilogue of the generated source file. +grpc::string GetSourceEpilogue(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the prologue of the generated mock file. +grpc::string GetMockPrologue(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the includes needed for generated mock file. +grpc::string GetMockIncludes(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the services for generated mock file. +grpc::string GetMockServices(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the epilogue of generated mock file. +grpc::string GetMockEpilogue(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the prologue of the generated mock file. +grpc::string GetMockPrologue(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the includes needed for generated mock file. +grpc::string GetMockIncludes(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the services for generated mock file. +grpc::string GetMockServices(grpc_generator::File *file, + const Parameters ¶ms); + +// Return the epilogue of generated mock file. +grpc::string GetMockEpilogue(grpc_generator::File *file, + const Parameters ¶ms); + +} // namespace grpc_cpp_generator + +#endif // GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H diff --git a/contrib/libs/flatbuffers/grpc/src/compiler/go_generator.cc b/contrib/libs/flatbuffers/grpc/src/compiler/go_generator.cc new file mode 100644 index 0000000000..d646451aa6 --- /dev/null +++ b/contrib/libs/flatbuffers/grpc/src/compiler/go_generator.cc @@ -0,0 +1,501 @@ +/* + * + * Copyright 2015, Google Inc. + * 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 AN/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. 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 THE COPYRIGHT + * OWNER OR CONTRIBUTORS 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 <map> +#include <cctype> +#include <sstream> + +#include "src/compiler/go_generator.h" + +template <class T> +grpc::string as_string(T x) { + std::ostringstream out; + out << x; + return out.str(); +} + +inline bool ClientOnlyStreaming(const grpc_generator::Method *method) { + return method->ClientStreaming() && !method->ServerStreaming(); +} + +inline bool ServerOnlyStreaming(const grpc_generator::Method *method) { + return !method->ClientStreaming() && method->ServerStreaming(); +} + +namespace grpc_go_generator { + +// Returns string with first letter to lowerCase +grpc::string unexportName(grpc::string s) { + if (s.empty()) + return s; + s[0] = static_cast<char>(std::tolower(s[0])); + return s; +} + +// Returns string with first letter to uppercase +grpc::string exportName(grpc::string s) { + if (s.empty()) + return s; + s[0] = static_cast<char>(std::toupper(s[0])); + return s; +} + +void GenerateError(grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> vars, + const bool multiple_return = true) { + printer->Print(vars, "if $Error_Check$ {\n"); + printer->Indent(); + vars["Return"] = multiple_return ? "nil, err" : "err"; + printer->Print(vars, "return $Return$\n"); + printer->Outdent(); + printer->Print("}\n"); +} + +// Generates imports for the service +void GenerateImports(grpc_generator::File *file, grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> vars) { + vars["filename"] = file->filename(); + printer->Print("//Generated by gRPC Go plugin\n"); + printer->Print("//If you make any local changes, they will be lost\n"); + printer->Print(vars, "//source: $filename$\n\n"); + printer->Print(vars, "package $Package$\n\n"); + printer->Print("import (\n"); + printer->Indent(); + printer->Print(vars, "$context$ \"context\"\n"); + printer->Print("flatbuffers \"github.com/google/flatbuffers/go\"\n"); + printer->Print(vars, "$grpc$ \"google.golang.org/grpc\"\n"); + printer->Print("\"google.golang.org/grpc/codes\"\n"); + printer->Print("\"google.golang.org/grpc/status\"\n"); + printer->Outdent(); + printer->Print(")\n\n"); +} + +// Generates Server method signature source +void GenerateServerMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> vars) { + vars["Method"] = exportName(method->name()); + vars["Request"] = method->get_input_type_name(); + vars["Response"] = (vars["CustomMethodIO"] == "") ? method->get_output_type_name() : vars["CustomMethodIO"]; + if (method->NoStreaming()) { + printer->Print(vars, "$Method$($context$.Context, *$Request$) (*$Response$, error)$Ending$"); + } else if (ServerOnlyStreaming(method)) { + printer->Print(vars, "$Method$(*$Request$, $Service$_$Method$Server) error$Ending$"); + } else { + printer->Print(vars, "$Method$($Service$_$Method$Server) error$Ending$"); + } +} + +void GenerateServerMethod(const grpc_generator::Method *method, grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> vars) { + vars["Method"] = exportName(method->name()); + vars["Request"] = method->get_input_type_name(); + vars["Response"] = (vars["CustomMethodIO"] == "") ? method->get_output_type_name() : vars["CustomMethodIO"]; + vars["FullMethodName"] = "/" + vars["ServicePrefix"] + vars["Service"] + "/" + vars["Method"]; + vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler"; + if (method->NoStreaming()) { + printer->Print(vars, "func $Handler$(srv interface{}, ctx $context$.Context,\n\tdec func(interface{}) error, interceptor $grpc$.UnaryServerInterceptor) (interface{}, error) {\n"); + printer->Indent(); + printer->Print(vars, "in := new($Request$)\n"); + vars["Error_Check"] = "err := dec(in); err != nil"; + GenerateError(printer, vars); + printer->Print("if interceptor == nil {\n"); + printer->Indent(); + printer->Print(vars, "return srv.($Service$Server).$Method$(ctx, in)\n"); + printer->Outdent(); + printer->Print("}\n"); + printer->Print(vars, "info := &$grpc$.UnaryServerInfo{\n"); + printer->Indent(); + printer->Print("Server: srv,\n"); + printer->Print(vars, "FullMethod: \"$FullMethodName$\",\n"); + printer->Outdent(); + printer->Print("}\n"); + printer->Outdent(); + printer->Print("\n"); + printer->Indent(); + printer->Print(vars, "handler := func(ctx $context$.Context, req interface{}) (interface{}, error) {\n"); + printer->Indent(); + printer->Print(vars, "return srv.($Service$Server).$Method$(ctx, req.(*$Request$))\n"); + printer->Outdent(); + printer->Print("}\n"); + printer->Print("return interceptor(ctx, in, info, handler)\n"); + printer->Outdent(); + printer->Print("}\n"); + return; + } + vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Server"; + printer->Print(vars, "func $Handler$(srv interface{}, stream $grpc$.ServerStream) error {\n"); + printer->Indent(); + if (ServerOnlyStreaming(method)) { + printer->Print(vars, "m := new($Request$)\n"); + vars["Error_Check"] = "err := stream.RecvMsg(m); err != nil"; + GenerateError(printer, vars, false); + printer->Print(vars, "return srv.($Service$Server).$Method$(m, &$StreamType${stream})\n"); + } else { + printer->Print(vars, "return srv.($Service$Server).$Method$(&$StreamType${stream})\n"); + } + printer->Outdent(); + printer->Print("}\n\n"); + + bool genSend = method->BidiStreaming() || ServerOnlyStreaming(method); + bool genRecv = method->BidiStreaming() || ClientOnlyStreaming(method); + bool genSendAndClose = ClientOnlyStreaming(method); + + printer->Print(vars, "type $Service$_$Method$Server interface {\n"); + printer->Indent(); + if (genSend) { + printer->Print(vars, "Send(*$Response$) error\n"); + } + if (genRecv) { + printer->Print(vars, "Recv() (*$Request$, error)\n"); + } + if (genSendAndClose) { + printer->Print(vars, "SendAndClose(*$Response$) error\n"); + } + printer->Print(vars, "$grpc$.ServerStream\n"); + printer->Outdent(); + printer->Print("}\n\n"); + + printer->Print(vars, "type $StreamType$ struct {\n"); + printer->Indent(); + printer->Print(vars, "$grpc$.ServerStream\n"); + printer->Outdent(); + printer->Print("}\n\n"); + + if (genSend) { + printer->Print(vars, "func (x *$StreamType$) Send(m *$Response$) error {\n"); + printer->Indent(); + printer->Print("return x.ServerStream.SendMsg(m)\n"); + printer->Outdent(); + printer->Print("}\n\n"); + } + if (genRecv) { + printer->Print(vars, "func (x *$StreamType$) Recv() (*$Request$, error) {\n"); + printer->Indent(); + printer->Print(vars, "m := new($Request$)\n"); + vars["Error_Check"] = "err := x.ServerStream.RecvMsg(m); err != nil"; + GenerateError(printer, vars); + printer->Print("return m, nil\n"); + printer->Outdent(); + printer->Print("}\n\n"); + } + if (genSendAndClose) { + printer->Print(vars, "func (x *$StreamType$) SendAndClose(m *$Response$) error {\n"); + printer->Indent(); + printer->Print("return x.ServerStream.SendMsg(m)\n"); + printer->Outdent(); + printer->Print("}\n\n"); + } + +} + +// Generates Client method signature source +void GenerateClientMethodSignature(const grpc_generator::Method *method, grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> vars) { + vars["Method"] = exportName(method->name()); + vars["Request"] = ", in *" + ((vars["CustomMethodIO"] == "") ? method->get_input_type_name() : vars["CustomMethodIO"]); + if (ClientOnlyStreaming(method) || method->BidiStreaming()) { + vars["Request"] = ""; + } + vars["Response"] = "*" + method->get_output_type_name(); + if (ClientOnlyStreaming(method) || method->BidiStreaming() || ServerOnlyStreaming(method)) { + vars["Response"] = vars["Service"] + "_" + vars["Method"] + "Client" ; + } + printer->Print(vars, "$Method$(ctx $context$.Context$Request$,\n\topts ...$grpc$.CallOption) ($Response$, error)$Ending$"); +} + +// Generates Client method source +void GenerateClientMethod(const grpc_generator::Method *method, grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> vars) { + printer->Print(vars, "func (c *$ServiceUnexported$Client) "); + vars["Ending"] = " {\n"; + GenerateClientMethodSignature(method, printer, vars); + printer->Indent(); + vars["Method"] = exportName(method->name()); + vars["Request"] = (vars["CustomMethodIO"] == "") ? method->get_input_type_name() : vars["CustomMethodIO"]; + vars["Response"] = method->get_output_type_name(); + vars["FullMethodName"] = "/" + vars["ServicePrefix"] + vars["Service"] + "/" + vars["Method"]; + if (method->NoStreaming()) { + printer->Print(vars, "out := new($Response$)\n"); + printer->Print(vars, "err := c.cc.Invoke(ctx, \"$FullMethodName$\", in, out, opts...)\n"); + vars["Error_Check"] = "err != nil"; + GenerateError(printer, vars); + printer->Print("return out, nil\n"); + printer->Outdent(); + printer->Print("}\n\n"); + return; + } + vars["StreamType"] = vars["ServiceUnexported"] + vars["Method"] + "Client"; + printer->Print(vars, "stream, err := c.cc.NewStream(ctx, &$MethodDesc$, \"$FullMethodName$\", opts...)\n"); + vars["Error_Check"] = "err != nil"; + GenerateError(printer, vars); + + printer->Print(vars, "x := &$StreamType${stream}\n"); + if (ServerOnlyStreaming(method)) { + vars["Error_Check"] = "err := x.ClientStream.SendMsg(in); err != nil"; + GenerateError(printer, vars); + vars["Error_Check"] = "err := x.ClientStream.CloseSend(); err != nil"; + GenerateError(printer, vars); + } + printer->Print("return x, nil\n"); + printer->Outdent(); + printer->Print("}\n\n"); + + bool genSend = method->BidiStreaming() || ClientOnlyStreaming(method); + bool genRecv = method->BidiStreaming() || ServerOnlyStreaming(method); + bool genCloseAndRecv = ClientOnlyStreaming(method); + + //Stream interface + printer->Print(vars, "type $Service$_$Method$Client interface {\n"); + printer->Indent(); + if (genSend) { + printer->Print(vars, "Send(*$Request$) error\n"); + } + if (genRecv) { + printer->Print(vars, "Recv() (*$Response$, error)\n"); + } + if (genCloseAndRecv) { + printer->Print(vars, "CloseAndRecv() (*$Response$, error)\n"); + } + printer->Print(vars, "$grpc$.ClientStream\n"); + printer->Outdent(); + printer->Print("}\n\n"); + + //Stream Client + printer->Print(vars, "type $StreamType$ struct {\n"); + printer->Indent(); + printer->Print(vars, "$grpc$.ClientStream\n"); + printer->Outdent(); + printer->Print("}\n\n"); + + if (genSend) { + printer->Print(vars, "func (x *$StreamType$) Send(m *$Request$) error {\n"); + printer->Indent(); + printer->Print("return x.ClientStream.SendMsg(m)\n"); + printer->Outdent(); + printer->Print("}\n\n"); + } + + if (genRecv) { + printer->Print(vars, "func (x *$StreamType$) Recv() (*$Response$, error) {\n"); + printer->Indent(); + printer->Print(vars, "m := new($Response$)\n"); + vars["Error_Check"] = "err := x.ClientStream.RecvMsg(m); err != nil"; + GenerateError(printer, vars); + printer->Print("return m, nil\n"); + printer->Outdent(); + printer->Print("}\n\n"); + } + + if (genCloseAndRecv) { + printer->Print(vars, "func (x *$StreamType$) CloseAndRecv() (*$Response$, error) {\n"); + printer->Indent(); + vars["Error_Check"] = "err := x.ClientStream.CloseSend(); err != nil"; + GenerateError(printer, vars); + printer->Print(vars, "m := new($Response$)\n"); + vars["Error_Check"] = "err := x.ClientStream.RecvMsg(m); err != nil"; + GenerateError(printer, vars); + printer->Print("return m, nil\n"); + printer->Outdent(); + printer->Print("}\n\n"); + } +} + +// Generates client API for the service +void GenerateService(const grpc_generator::Service *service, grpc_generator::Printer* printer, + std::map<grpc::string, grpc::string> vars) { + vars["Service"] = exportName(service->name()); + // Client Interface + printer->Print(vars, "// Client API for $Service$ service\n"); + printer->Print(vars, "type $Service$Client interface {\n"); + printer->Indent(); + vars["Ending"] = "\n"; + for (int i = 0; i < service->method_count(); i++) { + GenerateClientMethodSignature(service->method(i).get(), printer, vars); + } + printer->Outdent(); + printer->Print("}\n\n"); + + // Client structure + vars["ServiceUnexported"] = unexportName(vars["Service"]); + printer->Print(vars, "type $ServiceUnexported$Client struct {\n"); + printer->Indent(); + printer->Print(vars, "cc $grpc$.ClientConnInterface\n"); + printer->Outdent(); + printer->Print("}\n\n"); + + // NewClient + printer->Print(vars, "func New$Service$Client(cc $grpc$.ClientConnInterface) $Service$Client {\n"); + printer->Indent(); + printer->Print(vars, "return &$ServiceUnexported$Client{cc}"); + printer->Outdent(); + printer->Print("\n}\n\n"); + + int unary_methods = 0, streaming_methods = 0; + vars["ServiceDesc"] = "_" + vars["Service"] + "_serviceDesc"; + for (int i = 0; i < service->method_count(); i++) { + auto method = service->method(i); + if (method->NoStreaming()) { + vars["MethodDesc"] = vars["ServiceDesc"] + ".Method[" + as_string(unary_methods) + "]"; + unary_methods++; + } else { + vars["MethodDesc"] = vars["ServiceDesc"] + ".Streams[" + as_string(streaming_methods) + "]"; + streaming_methods++; + } + GenerateClientMethod(method.get(), printer, vars); + } + + //Server Interface + printer->Print(vars, "// Server API for $Service$ service\n"); + printer->Print(vars, "type $Service$Server interface {\n"); + printer->Indent(); + vars["Ending"] = "\n"; + for (int i = 0; i < service->method_count(); i++) { + GenerateServerMethodSignature(service->method(i).get(), printer, vars); + } + printer->Print(vars, "mustEmbedUnimplemented$Service$Server()\n"); + printer->Outdent(); + printer->Print("}\n\n"); + + printer->Print(vars, "type Unimplemented$Service$Server struct {\n"); + printer->Print("}\n\n"); + + vars["Ending"] = " {\n"; + for (int i = 0; i < service->method_count(); i++) { + auto method = service->method(i); + vars["Method"] = exportName(method->name()); + vars["Nil"] = method->NoStreaming() ? "nil, " : ""; + printer->Print(vars, "func (Unimplemented$Service$Server) "); + GenerateServerMethodSignature(method.get(), printer, vars); + printer->Indent(); + printer->Print(vars, "return $Nil$status.Errorf(codes.Unimplemented, \"method $Method$ not implemented\")\n"); + printer->Outdent(); + printer->Print("}\n"); + printer->Print("\n"); + } + + printer->Print(vars, "func (Unimplemented$Service$Server) mustEmbedUnimplemented$Service$Server() {}"); + printer->Print("\n\n"); + + printer->Print(vars, "type Unsafe$Service$Server interface {\n"); + printer->Indent(); + printer->Print(vars, "mustEmbedUnimplemented$Service$Server()\n"); + printer->Outdent(); + printer->Print("}\n\n"); + // Server registration. + printer->Print(vars, "func Register$Service$Server(s $grpc$.ServiceRegistrar, srv $Service$Server) {\n"); + printer->Indent(); + printer->Print(vars, "s.RegisterService(&$ServiceDesc$, srv)\n"); + printer->Outdent(); + printer->Print("}\n\n"); + + for (int i = 0; i < service->method_count(); i++) { + GenerateServerMethod(service->method(i).get(), printer, vars); + } + + + //Service Descriptor + printer->Print(vars, "var $ServiceDesc$ = $grpc$.ServiceDesc{\n"); + printer->Indent(); + printer->Print(vars, "ServiceName: \"$ServicePrefix$$Service$\",\n"); + printer->Print(vars, "HandlerType: (*$Service$Server)(nil),\n"); + printer->Print(vars, "Methods: []$grpc$.MethodDesc{\n"); + printer->Indent(); + for (int i = 0; i < service->method_count(); i++) { + auto method = service->method(i); + vars["Method"] = exportName(method->name()); + vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler"; + if (method->NoStreaming()) { + printer->Print("{\n"); + printer->Indent(); + printer->Print(vars, "MethodName: \"$Method$\",\n"); + printer->Print(vars, "Handler: $Handler$,\n"); + printer->Outdent(); + printer->Print("},\n"); + } + } + printer->Outdent(); + printer->Print("},\n"); + printer->Print(vars, "Streams: []$grpc$.StreamDesc{\n"); + printer->Indent(); + for (int i = 0; i < service->method_count(); i++) { + auto method = service->method(i); + vars["Method"] = exportName(method->name()); + vars["Handler"] = "_" + vars["Service"] + "_" + vars["Method"] + "_Handler"; + if (!method->NoStreaming()) { + printer->Print("{\n"); + printer->Indent(); + printer->Print(vars, "StreamName: \"$Method$\",\n"); + printer->Print(vars, "Handler: $Handler$,\n"); + if (ClientOnlyStreaming(method.get())) { + printer->Print("ClientStreams: true,\n"); + } else if (ServerOnlyStreaming(method.get())) { + printer->Print("ServerStreams: true,\n"); + } else { + printer->Print("ServerStreams: true,\n"); + printer->Print("ClientStreams: true,\n"); + } + printer->Outdent(); + printer->Print("},\n"); + } + } + printer->Outdent(); + printer->Print("},\n"); + printer->Outdent(); + printer->Print("}\n"); + +} + + +// Returns source for the service +grpc::string GenerateServiceSource(grpc_generator::File *file, + const grpc_generator::Service *service, + grpc_go_generator::Parameters *parameters) { + grpc::string out; + auto p = file->CreatePrinter(&out, '\t'); + p->SetIndentationSize(1); + auto printer = p.get(); + std::map<grpc::string, grpc::string> vars; + vars["Package"] = parameters->package_name; + vars["ServicePrefix"] = parameters->service_prefix; + if (!parameters->service_prefix.empty()) + vars["ServicePrefix"].append("."); + vars["grpc"] = "grpc"; + vars["context"] = "context"; + GenerateImports(file, printer, vars); + if (parameters->custom_method_io_type != "") { + vars["CustomMethodIO"] = parameters->custom_method_io_type; + } + GenerateService(service, printer, vars); + return out; +} +}// Namespace grpc_go_generator diff --git a/contrib/libs/flatbuffers/grpc/src/compiler/go_generator.h b/contrib/libs/flatbuffers/grpc/src/compiler/go_generator.h new file mode 100644 index 0000000000..baa94e0599 --- /dev/null +++ b/contrib/libs/flatbuffers/grpc/src/compiler/go_generator.h @@ -0,0 +1,64 @@ +/* + * + * Copyright 2015, Google Inc. + * 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 Inc. 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 THE COPYRIGHT + * OWNER OR CONTRIBUTORS 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. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_GO_GENERATOR_H +#define GRPC_INTERNAL_COMPILER_GO_GENERATOR_H + +//go generator is used to generate GRPC code for serialization system, such as flatbuffers +#include <memory> +#include <vector> + +#include "src/compiler/schema_interface.h" + +namespace grpc_go_generator { + +struct Parameters { + //Defines the custom parameter types for methods + //eg: flatbuffers uses flatbuffers.Builder as input for the client and output for the server + grpc::string custom_method_io_type; + + //Package name for the service + grpc::string package_name; + + //Prefix for RPC Calls + grpc::string service_prefix; +}; + +// Return the source of the generated service file. +grpc::string GenerateServiceSource(grpc_generator::File *file, + const grpc_generator::Service *service, + grpc_go_generator::Parameters *parameters); + +} + +#endif // GRPC_INTERNAL_COMPILER_GO_GENERATOR_H diff --git a/contrib/libs/flatbuffers/grpc/src/compiler/java_generator.cc b/contrib/libs/flatbuffers/grpc/src/compiler/java_generator.cc new file mode 100644 index 0000000000..d2cf5ccc14 --- /dev/null +++ b/contrib/libs/flatbuffers/grpc/src/compiler/java_generator.cc @@ -0,0 +1,1135 @@ +/* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "src/compiler/java_generator.h" + +#include <algorithm> +#include <iostream> +#include <iterator> +#include <map> +#include <utility> +#include <vector> + +// just to get flatbuffer_version_string() +#include <flatbuffers/flatbuffers.h> +#include <flatbuffers/util.h> +#define to_string flatbuffers::NumToString + +// Stringify helpers used solely to cast GRPC_VERSION +#ifndef STR +#define STR(s) #s +#endif + +#ifndef XSTR +#define XSTR(s) STR(s) +#endif + + +typedef grpc_generator::Printer Printer; +typedef std::map<grpc::string, grpc::string> VARS; +typedef grpc_generator::Service ServiceDescriptor; +typedef grpc_generator::CommentHolder + DescriptorType; // base class of all 'descriptors' +typedef grpc_generator::Method MethodDescriptor; + +namespace grpc_java_generator { +typedef std::string string; +// Generates imports for the service +void GenerateImports(grpc_generator::File* file, + grpc_generator::Printer* printer, VARS& vars) { + vars["filename"] = file->filename(); + printer->Print( + vars, + "//Generated by flatc compiler (version $flatc_version$)\n"); + printer->Print("//If you make any local changes, they will be lost\n"); + printer->Print(vars, "//source: $filename$.fbs\n\n"); + printer->Print(vars, "package $Package$;\n\n"); + vars["Package"] = vars["Package"] + "."; + if (!file->additional_headers().empty()) { + printer->Print(file->additional_headers().c_str()); + printer->Print("\n\n"); + } +} + +// Adjust a method name prefix identifier to follow the JavaBean spec: +// - decapitalize the first letter +// - remove embedded underscores & capitalize the following letter +static string MixedLower(const string& word) { + string w; + w += static_cast<string::value_type>(tolower(word[0])); + bool after_underscore = false; + for (size_t i = 1; i < word.length(); ++i) { + if (word[i] == '_') { + after_underscore = true; + } else { + w += after_underscore ? static_cast<string::value_type>(toupper(word[i])) + : word[i]; + after_underscore = false; + } + } + return w; +} + +// Converts to the identifier to the ALL_UPPER_CASE format. +// - An underscore is inserted where a lower case letter is followed by an +// upper case letter. +// - All letters are converted to upper case +static string ToAllUpperCase(const string& word) { + string w; + for (size_t i = 0; i < word.length(); ++i) { + w += static_cast<string::value_type>(toupper(word[i])); + if ((i < word.length() - 1) && islower(word[i]) && isupper(word[i + 1])) { + w += '_'; + } + } + return w; +} + +static inline string LowerMethodName(const MethodDescriptor* method) { + return MixedLower(method->name()); +} + +static inline string MethodPropertiesFieldName(const MethodDescriptor* method) { + return "METHOD_" + ToAllUpperCase(method->name()); +} + +static inline string MethodPropertiesGetterName( + const MethodDescriptor* method) { + return MixedLower("get_" + method->name() + "_method"); +} + +static inline string MethodIdFieldName(const MethodDescriptor* method) { + return "METHODID_" + ToAllUpperCase(method->name()); +} + +static inline string JavaClassName(VARS& vars, const string& name) { + // string name = google::protobuf::compiler::java::ClassName(desc); + return vars["Package"] + name; +} + +static inline string ServiceClassName(const string& service_name) { + return service_name + "Grpc"; +} + +// TODO(nmittler): Remove once protobuf includes javadoc methods in +// distribution. +template <typename ITR> +static void GrpcSplitStringToIteratorUsing(const string& full, + const char* delim, ITR& result) { + // Optimize the common case where delim is a single character. + if (delim[0] != '\0' && delim[1] == '\0') { + char c = delim[0]; + const char* p = full.data(); + const char* end = p + full.size(); + while (p != end) { + if (*p == c) { + ++p; + } else { + const char* start = p; + while (++p != end && *p != c) + ; + *result++ = string(start, p - start); + } + } + return; + } + + string::size_type begin_index, end_index; + begin_index = full.find_first_not_of(delim); + while (begin_index != string::npos) { + end_index = full.find_first_of(delim, begin_index); + if (end_index == string::npos) { + *result++ = full.substr(begin_index); + return; + } + *result++ = full.substr(begin_index, (end_index - begin_index)); + begin_index = full.find_first_not_of(delim, end_index); + } +} + +static void GrpcSplitStringUsing(const string& full, const char* delim, + std::vector<string>* result) { + std::back_insert_iterator<std::vector<string>> it(*result); + GrpcSplitStringToIteratorUsing(full, delim, it); +} + +static std::vector<string> GrpcSplit(const string& full, const char* delim) { + std::vector<string> result; + GrpcSplitStringUsing(full, delim, &result); + return result; +} + +// TODO(nmittler): Remove once protobuf includes javadoc methods in +// distribution. +static string GrpcEscapeJavadoc(const string& input) { + string result; + result.reserve(input.size() * 2); + + char prev = '*'; + + for (string::size_type i = 0; i < input.size(); i++) { + char c = input[i]; + switch (c) { + case '*': + // Avoid "/*". + if (prev == '/') { + result.append("*"); + } else { + result.push_back(c); + } + break; + case '/': + // Avoid "*/". + if (prev == '*') { + result.append("/"); + } else { + result.push_back(c); + } + break; + case '@': + // '@' starts javadoc tags including the @deprecated tag, which will + // cause a compile-time error if inserted before a declaration that + // does not have a corresponding @Deprecated annotation. + result.append("@"); + break; + case '<': + // Avoid interpretation as HTML. + result.append("<"); + break; + case '>': + // Avoid interpretation as HTML. + result.append(">"); + break; + case '&': + // Avoid interpretation as HTML. + result.append("&"); + break; + case '\\': + // Java interprets Unicode escape sequences anywhere! + result.append("\"); + break; + default: + result.push_back(c); + break; + } + + prev = c; + } + + return result; +} + +static std::vector<string> GrpcGetDocLines(const string& comments) { + if (!comments.empty()) { + // TODO(kenton): Ideally we should parse the comment text as Markdown and + // write it back as HTML, but this requires a Markdown parser. For now + // we just use <pre> to get fixed-width text formatting. + + // If the comment itself contains block comment start or end markers, + // HTML-escape them so that they don't accidentally close the doc comment. + string escapedComments = GrpcEscapeJavadoc(comments); + + std::vector<string> lines = GrpcSplit(escapedComments, "\n"); + while (!lines.empty() && lines.back().empty()) { + lines.pop_back(); + } + return lines; + } + return std::vector<string>(); +} + +static std::vector<string> GrpcGetDocLinesForDescriptor( + const DescriptorType* descriptor) { + return descriptor->GetAllComments(); + // return GrpcGetDocLines(descriptor->GetLeadingComments("///")); +} + +static void GrpcWriteDocCommentBody(Printer* printer, VARS& vars, + const std::vector<string>& lines, + bool surroundWithPreTag) { + if (!lines.empty()) { + if (surroundWithPreTag) { + printer->Print(" * <pre>\n"); + } + + for (size_t i = 0; i < lines.size(); i++) { + // Most lines should start with a space. Watch out for lines that start + // with a /, since putting that right after the leading asterisk will + // close the comment. + vars["line"] = lines[i]; + if (!lines[i].empty() && lines[i][0] == '/') { + printer->Print(vars, " * $line$\n"); + } else { + printer->Print(vars, " *$line$\n"); + } + } + + if (surroundWithPreTag) { + printer->Print(" * </pre>\n"); + } + } +} + +static void GrpcWriteDocComment(Printer* printer, VARS& vars, + const string& comments) { + printer->Print("/**\n"); + std::vector<string> lines = GrpcGetDocLines(comments); + GrpcWriteDocCommentBody(printer, vars, lines, false); + printer->Print(" */\n"); +} + +static void GrpcWriteServiceDocComment(Printer* printer, VARS& vars, + const ServiceDescriptor* service) { + printer->Print("/**\n"); + std::vector<string> lines = GrpcGetDocLinesForDescriptor(service); + GrpcWriteDocCommentBody(printer, vars, lines, true); + printer->Print(" */\n"); +} + +void GrpcWriteMethodDocComment(Printer* printer, VARS& vars, + const MethodDescriptor* method) { + printer->Print("/**\n"); + std::vector<string> lines = GrpcGetDocLinesForDescriptor(method); + GrpcWriteDocCommentBody(printer, vars, lines, true); + printer->Print(" */\n"); +} + +//outputs static singleton extractor for type stored in "extr_type" and "extr_type_name" vars +static void PrintTypeExtractor(Printer* p, VARS& vars) { + p->Print( + vars, + "private static volatile FlatbuffersUtils.FBExtactor<$extr_type$> " + "extractorOf$extr_type_name$;\n" + "private static FlatbuffersUtils.FBExtactor<$extr_type$> " + "getExtractorOf$extr_type_name$() {\n" + " if (extractorOf$extr_type_name$ != null) return " + "extractorOf$extr_type_name$;\n" + " synchronized ($service_class_name$.class) {\n" + " if (extractorOf$extr_type_name$ != null) return " + "extractorOf$extr_type_name$;\n" + " extractorOf$extr_type_name$ = new " + "FlatbuffersUtils.FBExtactor<$extr_type$>() {\n" + " public $extr_type$ extract (ByteBuffer buffer) {\n" + " return " + "$extr_type$.getRootAs$extr_type_name$(buffer);\n" + " }\n" + " };\n" + " return extractorOf$extr_type_name$;\n" + " }\n" + "}\n\n"); +} +static void PrintMethodFields(Printer* p, VARS& vars, + const ServiceDescriptor* service) { + p->Print("// Static method descriptors that strictly reflect the proto.\n"); + vars["service_name"] = service->name(); + + //set of names of rpc input- and output- types that were already encountered. + //this is needed to avoid duplicating type extractor since it's possible that + //the same type is used as an input or output type of more than a single RPC method + std::set<std::string> encounteredTypes; + + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + vars["arg_in_id"] = to_string(2L * i); //trying to make msvc 10 happy + vars["arg_out_id"] = to_string(2L * i + 1); + vars["method_name"] = method->name(); + vars["input_type_name"] = method->get_input_type_name(); + vars["output_type_name"] = method->get_output_type_name(); + vars["input_type"] = JavaClassName(vars, method->get_input_type_name()); + vars["output_type"] = JavaClassName(vars, method->get_output_type_name()); + vars["method_field_name"] = MethodPropertiesFieldName(method.get()); + vars["method_new_field_name"] = MethodPropertiesGetterName(method.get()); + vars["method_method_name"] = MethodPropertiesGetterName(method.get()); + bool client_streaming = method->ClientStreaming() || method->BidiStreaming(); + bool server_streaming = method->ServerStreaming() || method->BidiStreaming(); + if (client_streaming) { + if (server_streaming) { + vars["method_type"] = "BIDI_STREAMING"; + } else { + vars["method_type"] = "CLIENT_STREAMING"; + } + } else { + if (server_streaming) { + vars["method_type"] = "SERVER_STREAMING"; + } else { + vars["method_type"] = "UNARY"; + } + } + + p->Print( + vars, + "@$ExperimentalApi$(\"https://github.com/grpc/grpc-java/issues/" + "1901\")\n" + "@$Deprecated$ // Use {@link #$method_method_name$()} instead. \n" + "public static final $MethodDescriptor$<$input_type$,\n" + " $output_type$> $method_field_name$ = $method_method_name$();\n" + "\n" + "private static volatile $MethodDescriptor$<$input_type$,\n" + " $output_type$> $method_new_field_name$;\n" + "\n"); + + if (encounteredTypes.insert(vars["input_type_name"]).second) { + vars["extr_type"] = vars["input_type"]; + vars["extr_type_name"] = vars["input_type_name"]; + PrintTypeExtractor(p, vars); + } + + if (encounteredTypes.insert(vars["output_type_name"]).second) { + vars["extr_type"] = vars["output_type"]; + vars["extr_type_name"] = vars["output_type_name"]; + PrintTypeExtractor(p, vars); + } + + p->Print( + vars, + "@$ExperimentalApi$(\"https://github.com/grpc/grpc-java/issues/" + "1901\")\n" + "public static $MethodDescriptor$<$input_type$,\n" + " $output_type$> $method_method_name$() {\n" + " $MethodDescriptor$<$input_type$, $output_type$> " + "$method_new_field_name$;\n" + " if (($method_new_field_name$ = " + "$service_class_name$.$method_new_field_name$) == null) {\n" + " synchronized ($service_class_name$.class) {\n" + " if (($method_new_field_name$ = " + "$service_class_name$.$method_new_field_name$) == null) {\n" + " $service_class_name$.$method_new_field_name$ = " + "$method_new_field_name$ = \n" + " $MethodDescriptor$.<$input_type$, " + "$output_type$>newBuilder()\n" + " .setType($MethodType$.$method_type$)\n" + " .setFullMethodName(generateFullMethodName(\n" + " \"$Package$$service_name$\", \"$method_name$\"))\n" + " .setSampledToLocalTracing(true)\n" + " .setRequestMarshaller(FlatbuffersUtils.marshaller(\n" + " $input_type$.class, " + "getExtractorOf$input_type_name$()))\n" + " .setResponseMarshaller(FlatbuffersUtils.marshaller(\n" + " $output_type$.class, " + "getExtractorOf$output_type_name$()))\n"); + + // vars["proto_method_descriptor_supplier"] = service->name() + + // "MethodDescriptorSupplier"; + p->Print(vars, " .setSchemaDescriptor(null)\n"); + //" .setSchemaDescriptor(new + //$proto_method_descriptor_supplier$(\"$method_name$\"))\n"); + + p->Print(vars, " .build();\n"); + p->Print(vars, + " }\n" + " }\n" + " }\n" + " return $method_new_field_name$;\n" + "}\n"); + + p->Print("\n"); + } +} +enum StubType { + ASYNC_INTERFACE = 0, + BLOCKING_CLIENT_INTERFACE = 1, + FUTURE_CLIENT_INTERFACE = 2, + BLOCKING_SERVER_INTERFACE = 3, + ASYNC_CLIENT_IMPL = 4, + BLOCKING_CLIENT_IMPL = 5, + FUTURE_CLIENT_IMPL = 6, + ABSTRACT_CLASS = 7, +}; + +enum CallType { ASYNC_CALL = 0, BLOCKING_CALL = 1, FUTURE_CALL = 2 }; + +static void PrintBindServiceMethodBody(Printer* p, VARS& vars, + const ServiceDescriptor* service); + +// Prints a client interface or implementation class, or a server interface. +static void PrintStub(Printer* p, VARS& vars, const ServiceDescriptor* service, + StubType type) { + const string service_name = service->name(); + vars["service_name"] = service_name; + vars["abstract_name"] = service_name + "ImplBase"; + string stub_name = service_name; + string client_name = service_name; + CallType call_type = ASYNC_CALL; + bool impl_base = false; + bool interface = false; + switch (type) { + case ABSTRACT_CLASS: + call_type = ASYNC_CALL; + impl_base = true; + break; + case ASYNC_CLIENT_IMPL: + call_type = ASYNC_CALL; + stub_name += "Stub"; + break; + case BLOCKING_CLIENT_INTERFACE: + interface = true; + FLATBUFFERS_FALLTHROUGH(); // fall thru + case BLOCKING_CLIENT_IMPL: + call_type = BLOCKING_CALL; + stub_name += "BlockingStub"; + client_name += "BlockingClient"; + break; + case FUTURE_CLIENT_INTERFACE: + interface = true; + FLATBUFFERS_FALLTHROUGH(); // fall thru + case FUTURE_CLIENT_IMPL: + call_type = FUTURE_CALL; + stub_name += "FutureStub"; + client_name += "FutureClient"; + break; + case ASYNC_INTERFACE: + call_type = ASYNC_CALL; + interface = true; + break; + default: + GRPC_CODEGEN_FAIL << "Cannot determine class name for StubType: " << type; + } + vars["stub_name"] = stub_name; + vars["client_name"] = client_name; + + // Class head + if (!interface) { + GrpcWriteServiceDocComment(p, vars, service); + } + if (impl_base) { + p->Print(vars, + "public static abstract class $abstract_name$ implements " + "$BindableService$ {\n"); + } else { + p->Print(vars, + "public static final class $stub_name$ extends " + "$AbstractStub$<$stub_name$> {\n"); + } + p->Indent(); + + // Constructor and build() method + if (!impl_base && !interface) { + p->Print(vars, "private $stub_name$($Channel$ channel) {\n"); + p->Indent(); + p->Print("super(channel);\n"); + p->Outdent(); + p->Print("}\n\n"); + p->Print(vars, + "private $stub_name$($Channel$ channel,\n" + " $CallOptions$ callOptions) {\n"); + p->Indent(); + p->Print("super(channel, callOptions);\n"); + p->Outdent(); + p->Print("}\n\n"); + p->Print(vars, + "@$Override$\n" + "protected $stub_name$ build($Channel$ channel,\n" + " $CallOptions$ callOptions) {\n"); + p->Indent(); + p->Print(vars, "return new $stub_name$(channel, callOptions);\n"); + p->Outdent(); + p->Print("}\n"); + } + + // RPC methods + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + vars["input_type"] = JavaClassName(vars, method->get_input_type_name()); + vars["output_type"] = JavaClassName(vars, method->get_output_type_name()); + vars["lower_method_name"] = LowerMethodName(&*method); + vars["method_method_name"] = MethodPropertiesGetterName(&*method); + bool client_streaming = method->ClientStreaming() || method->BidiStreaming(); + bool server_streaming = method->ServerStreaming() || method->BidiStreaming(); + + if (call_type == BLOCKING_CALL && client_streaming) { + // Blocking client interface with client streaming is not available + continue; + } + + if (call_type == FUTURE_CALL && (client_streaming || server_streaming)) { + // Future interface doesn't support streaming. + continue; + } + + // Method signature + p->Print("\n"); + // TODO(nmittler): Replace with WriteMethodDocComment once included by the + // protobuf distro. + if (!interface) { + GrpcWriteMethodDocComment(p, vars, &*method); + } + p->Print("public "); + switch (call_type) { + case BLOCKING_CALL: + GRPC_CODEGEN_CHECK(!client_streaming) + << "Blocking client interface with client streaming is unavailable"; + if (server_streaming) { + // Server streaming + p->Print(vars, + "$Iterator$<$output_type$> $lower_method_name$(\n" + " $input_type$ request)"); + } else { + // Simple RPC + p->Print(vars, + "$output_type$ $lower_method_name$($input_type$ request)"); + } + break; + case ASYNC_CALL: + if (client_streaming) { + // Bidirectional streaming or client streaming + p->Print(vars, + "$StreamObserver$<$input_type$> $lower_method_name$(\n" + " $StreamObserver$<$output_type$> responseObserver)"); + } else { + // Server streaming or simple RPC + p->Print(vars, + "void $lower_method_name$($input_type$ request,\n" + " $StreamObserver$<$output_type$> responseObserver)"); + } + break; + case FUTURE_CALL: + GRPC_CODEGEN_CHECK(!client_streaming && !server_streaming) + << "Future interface doesn't support streaming. " + << "client_streaming=" << client_streaming << ", " + << "server_streaming=" << server_streaming; + p->Print(vars, + "$ListenableFuture$<$output_type$> $lower_method_name$(\n" + " $input_type$ request)"); + break; + } + + if (interface) { + p->Print(";\n"); + continue; + } + // Method body. + p->Print(" {\n"); + p->Indent(); + if (impl_base) { + switch (call_type) { + // NB: Skipping validation of service methods. If something is wrong, + // we wouldn't get to this point as compiler would return errors when + // generating service interface. + case ASYNC_CALL: + if (client_streaming) { + p->Print(vars, + "return " + "asyncUnimplementedStreamingCall($method_method_name$(), " + "responseObserver);\n"); + } else { + p->Print(vars, + "asyncUnimplementedUnaryCall($method_method_name$(), " + "responseObserver);\n"); + } + break; + default: + break; + } + } else if (!interface) { + switch (call_type) { + case BLOCKING_CALL: + GRPC_CODEGEN_CHECK(!client_streaming) + << "Blocking client streaming interface is not available"; + if (server_streaming) { + vars["calls_method"] = "blockingServerStreamingCall"; + vars["params"] = "request"; + } else { + vars["calls_method"] = "blockingUnaryCall"; + vars["params"] = "request"; + } + p->Print(vars, + "return $calls_method$(\n" + " getChannel(), $method_method_name$(), " + "getCallOptions(), $params$);\n"); + break; + case ASYNC_CALL: + if (server_streaming) { + if (client_streaming) { + vars["calls_method"] = "asyncBidiStreamingCall"; + vars["params"] = "responseObserver"; + } else { + vars["calls_method"] = "asyncServerStreamingCall"; + vars["params"] = "request, responseObserver"; + } + } else { + if (client_streaming) { + vars["calls_method"] = "asyncClientStreamingCall"; + vars["params"] = "responseObserver"; + } else { + vars["calls_method"] = "asyncUnaryCall"; + vars["params"] = "request, responseObserver"; + } + } + vars["last_line_prefix"] = client_streaming ? "return " : ""; + p->Print(vars, + "$last_line_prefix$$calls_method$(\n" + " getChannel().newCall($method_method_name$(), " + "getCallOptions()), $params$);\n"); + break; + case FUTURE_CALL: + GRPC_CODEGEN_CHECK(!client_streaming && !server_streaming) + << "Future interface doesn't support streaming. " + << "client_streaming=" << client_streaming << ", " + << "server_streaming=" << server_streaming; + vars["calls_method"] = "futureUnaryCall"; + p->Print(vars, + "return $calls_method$(\n" + " getChannel().newCall($method_method_name$(), " + "getCallOptions()), request);\n"); + break; + } + } + p->Outdent(); + p->Print("}\n"); + } + + if (impl_base) { + p->Print("\n"); + p->Print( + vars, + "@$Override$ public final $ServerServiceDefinition$ bindService() {\n"); + vars["instance"] = "this"; + PrintBindServiceMethodBody(p, vars, service); + p->Print("}\n"); + } + + p->Outdent(); + p->Print("}\n\n"); +} + +static bool CompareMethodClientStreaming( + const std::unique_ptr<const grpc_generator::Method>& method1, + const std::unique_ptr<const grpc_generator::Method>& method2) { + return method1->ClientStreaming() < method2->ClientStreaming(); +} + +// Place all method invocations into a single class to reduce memory footprint +// on Android. +static void PrintMethodHandlerClass(Printer* p, VARS& vars, + const ServiceDescriptor* service) { + // Sort method ids based on ClientStreaming() so switch tables are compact. + std::vector<std::unique_ptr<const grpc_generator::Method>> sorted_methods( + service->method_count()); + for (int i = 0; i < service->method_count(); ++i) { + sorted_methods[i] = service->method(i); + } + stable_sort(sorted_methods.begin(), sorted_methods.end(), + CompareMethodClientStreaming); + for (size_t i = 0; i < sorted_methods.size(); i++) { + auto& method = sorted_methods[i]; + vars["method_id"] = to_string(i); + vars["method_id_name"] = MethodIdFieldName(&*method); + p->Print(vars, + "private static final int $method_id_name$ = $method_id$;\n"); + } + p->Print("\n"); + vars["service_name"] = service->name() + "ImplBase"; + p->Print(vars, + "private static final class MethodHandlers<Req, Resp> implements\n" + " io.grpc.stub.ServerCalls.UnaryMethod<Req, Resp>,\n" + " io.grpc.stub.ServerCalls.ServerStreamingMethod<Req, Resp>,\n" + " io.grpc.stub.ServerCalls.ClientStreamingMethod<Req, Resp>,\n" + " io.grpc.stub.ServerCalls.BidiStreamingMethod<Req, Resp> {\n" + " private final $service_name$ serviceImpl;\n" + " private final int methodId;\n" + "\n" + " MethodHandlers($service_name$ serviceImpl, int methodId) {\n" + " this.serviceImpl = serviceImpl;\n" + " this.methodId = methodId;\n" + " }\n\n"); + p->Indent(); + p->Print(vars, + "@$Override$\n" + "@java.lang.SuppressWarnings(\"unchecked\")\n" + "public void invoke(Req request, $StreamObserver$<Resp> " + "responseObserver) {\n" + " switch (methodId) {\n"); + p->Indent(); + p->Indent(); + + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + if (method->ClientStreaming() || method->BidiStreaming()) { + continue; + } + vars["method_id_name"] = MethodIdFieldName(&*method); + vars["lower_method_name"] = LowerMethodName(&*method); + vars["input_type"] = JavaClassName(vars, method->get_input_type_name()); + vars["output_type"] = JavaClassName(vars, method->get_output_type_name()); + p->Print(vars, + "case $method_id_name$:\n" + " serviceImpl.$lower_method_name$(($input_type$) request,\n" + " ($StreamObserver$<$output_type$>) responseObserver);\n" + " break;\n"); + } + p->Print( + "default:\n" + " throw new AssertionError();\n"); + + p->Outdent(); + p->Outdent(); + p->Print( + " }\n" + "}\n\n"); + + p->Print(vars, + "@$Override$\n" + "@java.lang.SuppressWarnings(\"unchecked\")\n" + "public $StreamObserver$<Req> invoke(\n" + " $StreamObserver$<Resp> responseObserver) {\n" + " switch (methodId) {\n"); + p->Indent(); + p->Indent(); + + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + if (!(method->ClientStreaming() || method->BidiStreaming())) { + continue; + } + vars["method_id_name"] = MethodIdFieldName(&*method); + vars["lower_method_name"] = LowerMethodName(&*method); + vars["input_type"] = JavaClassName(vars, method->get_input_type_name()); + vars["output_type"] = JavaClassName(vars, method->get_output_type_name()); + p->Print( + vars, + "case $method_id_name$:\n" + " return ($StreamObserver$<Req>) serviceImpl.$lower_method_name$(\n" + " ($StreamObserver$<$output_type$>) responseObserver);\n"); + } + p->Print( + "default:\n" + " throw new AssertionError();\n"); + + p->Outdent(); + p->Outdent(); + p->Print( + " }\n" + "}\n"); + + p->Outdent(); + p->Print("}\n\n"); +} + +static void PrintGetServiceDescriptorMethod(Printer* p, VARS& vars, + const ServiceDescriptor* service) { + vars["service_name"] = service->name(); + // vars["proto_base_descriptor_supplier"] = service->name() + + // "BaseDescriptorSupplier"; vars["proto_file_descriptor_supplier"] = + // service->name() + "FileDescriptorSupplier"; + // vars["proto_method_descriptor_supplier"] = service->name() + + // "MethodDescriptorSupplier"; vars["proto_class_name"] = + // google::protobuf::compiler::java::ClassName(service->file()); + // p->Print( + // vars, + // "private static abstract class + // $proto_base_descriptor_supplier$\n" " implements + // $ProtoFileDescriptorSupplier$, + // $ProtoServiceDescriptorSupplier$ {\n" " + // $proto_base_descriptor_supplier$() {}\n" + // "\n" + // " @$Override$\n" + // " public com.google.protobuf.Descriptors.FileDescriptor + // getFileDescriptor() {\n" " return + // $proto_class_name$.getDescriptor();\n" " }\n" + // "\n" + // " @$Override$\n" + // " public com.google.protobuf.Descriptors.ServiceDescriptor + // getServiceDescriptor() {\n" " return + // getFileDescriptor().findServiceByName(\"$service_name$\");\n" + // " }\n" + // "}\n" + // "\n" + // "private static final class + // $proto_file_descriptor_supplier$\n" " extends + // $proto_base_descriptor_supplier$ {\n" " + // $proto_file_descriptor_supplier$() {}\n" + // "}\n" + // "\n" + // "private static final class + // $proto_method_descriptor_supplier$\n" " extends + // $proto_base_descriptor_supplier$\n" " implements + // $ProtoMethodDescriptorSupplier$ {\n" " private final + // String methodName;\n" + // "\n" + // " $proto_method_descriptor_supplier$(String methodName) + // {\n" " this.methodName = methodName;\n" " }\n" + // "\n" + // " @$Override$\n" + // " public com.google.protobuf.Descriptors.MethodDescriptor + // getMethodDescriptor() {\n" " return + // getServiceDescriptor().findMethodByName(methodName);\n" " + // }\n" + // "}\n\n"); + + p->Print( + vars, + "private static volatile $ServiceDescriptor$ serviceDescriptor;\n\n"); + + p->Print(vars, + "public static $ServiceDescriptor$ getServiceDescriptor() {\n"); + p->Indent(); + p->Print(vars, "$ServiceDescriptor$ result = serviceDescriptor;\n"); + p->Print("if (result == null) {\n"); + p->Indent(); + p->Print(vars, "synchronized ($service_class_name$.class) {\n"); + p->Indent(); + p->Print("result = serviceDescriptor;\n"); + p->Print("if (result == null) {\n"); + p->Indent(); + + p->Print(vars, + "serviceDescriptor = result = " + "$ServiceDescriptor$.newBuilder(SERVICE_NAME)"); + p->Indent(); + p->Indent(); + p->Print(vars, "\n.setSchemaDescriptor(null)"); + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + vars["method_method_name"] = MethodPropertiesGetterName(&*method); + p->Print(vars, "\n.addMethod($method_method_name$())"); + } + p->Print("\n.build();\n"); + p->Outdent(); + p->Outdent(); + + p->Outdent(); + p->Print("}\n"); + p->Outdent(); + p->Print("}\n"); + p->Outdent(); + p->Print("}\n"); + p->Print("return result;\n"); + p->Outdent(); + p->Print("}\n"); +} + +static void PrintBindServiceMethodBody(Printer* p, VARS& vars, + const ServiceDescriptor* service) { + vars["service_name"] = service->name(); + p->Indent(); + p->Print(vars, + "return " + "$ServerServiceDefinition$.builder(getServiceDescriptor())\n"); + p->Indent(); + p->Indent(); + for (int i = 0; i < service->method_count(); ++i) { + auto method = service->method(i); + vars["lower_method_name"] = LowerMethodName(&*method); + vars["method_method_name"] = MethodPropertiesGetterName(&*method); + vars["input_type"] = JavaClassName(vars, method->get_input_type_name()); + vars["output_type"] = JavaClassName(vars, method->get_output_type_name()); + vars["method_id_name"] = MethodIdFieldName(&*method); + bool client_streaming = method->ClientStreaming() || method->BidiStreaming(); + bool server_streaming = method->ServerStreaming() || method->BidiStreaming(); + if (client_streaming) { + if (server_streaming) { + vars["calls_method"] = "asyncBidiStreamingCall"; + } else { + vars["calls_method"] = "asyncClientStreamingCall"; + } + } else { + if (server_streaming) { + vars["calls_method"] = "asyncServerStreamingCall"; + } else { + vars["calls_method"] = "asyncUnaryCall"; + } + } + p->Print(vars, ".addMethod(\n"); + p->Indent(); + p->Print(vars, + "$method_method_name$(),\n" + "$calls_method$(\n"); + p->Indent(); + p->Print(vars, + "new MethodHandlers<\n" + " $input_type$,\n" + " $output_type$>(\n" + " $instance$, $method_id_name$)))\n"); + p->Outdent(); + p->Outdent(); + } + p->Print(".build();\n"); + p->Outdent(); + p->Outdent(); + p->Outdent(); +} + +static void PrintService(Printer* p, VARS& vars, + const ServiceDescriptor* service, + bool disable_version) { + vars["service_name"] = service->name(); + vars["service_class_name"] = ServiceClassName(service->name()); + vars["grpc_version"] = ""; +#ifdef GRPC_VERSION + if (!disable_version) { + vars["grpc_version"] = " (version " XSTR(GRPC_VERSION) ")"; + } +#else + (void)disable_version; +#endif + // TODO(nmittler): Replace with WriteServiceDocComment once included by + // protobuf distro. + GrpcWriteServiceDocComment(p, vars, service); + p->Print(vars, + "@$Generated$(\n" + " value = \"by gRPC proto compiler$grpc_version$\",\n" + " comments = \"Source: $file_name$.fbs\")\n" + "public final class $service_class_name$ {\n\n"); + p->Indent(); + p->Print(vars, "private $service_class_name$() {}\n\n"); + + p->Print(vars, + "public static final String SERVICE_NAME = " + "\"$Package$$service_name$\";\n\n"); + + PrintMethodFields(p, vars, service); + + // TODO(nmittler): Replace with WriteDocComment once included by protobuf + // distro. + GrpcWriteDocComment( + p, vars, + " Creates a new async stub that supports all call types for the service"); + p->Print(vars, + "public static $service_name$Stub newStub($Channel$ channel) {\n"); + p->Indent(); + p->Print(vars, "return new $service_name$Stub(channel);\n"); + p->Outdent(); + p->Print("}\n\n"); + + // TODO(nmittler): Replace with WriteDocComment once included by protobuf + // distro. + GrpcWriteDocComment( + p, vars, + " Creates a new blocking-style stub that supports unary and streaming " + "output calls on the service"); + p->Print(vars, + "public static $service_name$BlockingStub newBlockingStub(\n" + " $Channel$ channel) {\n"); + p->Indent(); + p->Print(vars, "return new $service_name$BlockingStub(channel);\n"); + p->Outdent(); + p->Print("}\n\n"); + + // TODO(nmittler): Replace with WriteDocComment once included by protobuf + // distro. + GrpcWriteDocComment( + p, vars, + " Creates a new ListenableFuture-style stub that supports unary calls " + "on the service"); + p->Print(vars, + "public static $service_name$FutureStub newFutureStub(\n" + " $Channel$ channel) {\n"); + p->Indent(); + p->Print(vars, "return new $service_name$FutureStub(channel);\n"); + p->Outdent(); + p->Print("}\n\n"); + + PrintStub(p, vars, service, ABSTRACT_CLASS); + PrintStub(p, vars, service, ASYNC_CLIENT_IMPL); + PrintStub(p, vars, service, BLOCKING_CLIENT_IMPL); + PrintStub(p, vars, service, FUTURE_CLIENT_IMPL); + + PrintMethodHandlerClass(p, vars, service); + PrintGetServiceDescriptorMethod(p, vars, service); + p->Outdent(); + p->Print("}\n"); +} + +void PrintStaticImports(Printer* p) { + p->Print( + "import java.nio.ByteBuffer;\n" + "import static " + "io.grpc.MethodDescriptor.generateFullMethodName;\n" + "import static " + "io.grpc.stub.ClientCalls.asyncBidiStreamingCall;\n" + "import static " + "io.grpc.stub.ClientCalls.asyncClientStreamingCall;\n" + "import static " + "io.grpc.stub.ClientCalls.asyncServerStreamingCall;\n" + "import static " + "io.grpc.stub.ClientCalls.asyncUnaryCall;\n" + "import static " + "io.grpc.stub.ClientCalls.blockingServerStreamingCall;\n" + "import static " + "io.grpc.stub.ClientCalls.blockingUnaryCall;\n" + "import static " + "io.grpc.stub.ClientCalls.futureUnaryCall;\n" + "import static " + "io.grpc.stub.ServerCalls.asyncBidiStreamingCall;\n" + "import static " + "io.grpc.stub.ServerCalls.asyncClientStreamingCall;\n" + "import static " + "io.grpc.stub.ServerCalls.asyncServerStreamingCall;\n" + "import static " + "io.grpc.stub.ServerCalls.asyncUnaryCall;\n" + "import static " + "io.grpc.stub.ServerCalls.asyncUnimplementedStreamingCall;\n" + "import static " + "io.grpc.stub.ServerCalls.asyncUnimplementedUnaryCall;\n\n"); +} + +void GenerateService(const grpc_generator::Service* service, + grpc_generator::Printer* printer, VARS& vars, + bool disable_version) { + // All non-generated classes must be referred by fully qualified names to + // avoid collision with generated classes. + vars["String"] = "java.lang.String"; + vars["Deprecated"] = "java.lang.Deprecated"; + vars["Override"] = "java.lang.Override"; + vars["Channel"] = "io.grpc.Channel"; + vars["CallOptions"] = "io.grpc.CallOptions"; + vars["MethodType"] = "io.grpc.MethodDescriptor.MethodType"; + vars["ServerMethodDefinition"] = "io.grpc.ServerMethodDefinition"; + vars["BindableService"] = "io.grpc.BindableService"; + vars["ServerServiceDefinition"] = "io.grpc.ServerServiceDefinition"; + vars["ServiceDescriptor"] = "io.grpc.ServiceDescriptor"; + vars["ProtoFileDescriptorSupplier"] = + "io.grpc.protobuf.ProtoFileDescriptorSupplier"; + vars["ProtoServiceDescriptorSupplier"] = + "io.grpc.protobuf.ProtoServiceDescriptorSupplier"; + vars["ProtoMethodDescriptorSupplier"] = + "io.grpc.protobuf.ProtoMethodDescriptorSupplier"; + vars["AbstractStub"] = "io.grpc.stub.AbstractStub"; + vars["MethodDescriptor"] = "io.grpc.MethodDescriptor"; + vars["NanoUtils"] = "io.grpc.protobuf.nano.NanoUtils"; + vars["StreamObserver"] = "io.grpc.stub.StreamObserver"; + vars["Iterator"] = "java.util.Iterator"; + vars["Generated"] = "javax.annotation.Generated"; + vars["ListenableFuture"] = + "com.google.common.util.concurrent.ListenableFuture"; + vars["ExperimentalApi"] = "io.grpc.ExperimentalApi"; + + PrintStaticImports(printer); + + PrintService(printer, vars, service, disable_version); +} + +grpc::string GenerateServiceSource( + grpc_generator::File* file, const grpc_generator::Service* service, + grpc_java_generator::Parameters* parameters) { + grpc::string out; + auto printer = file->CreatePrinter(&out); + VARS vars; + vars["flatc_version"] = grpc::string( + FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MAJOR) "." FLATBUFFERS_STRING( + FLATBUFFERS_VERSION_MINOR) "." FLATBUFFERS_STRING(FLATBUFFERS_VERSION_REVISION)); + + vars["file_name"] = file->filename(); + + if (!parameters->package_name.empty()) { + vars["Package"] = parameters->package_name; // ServiceJavaPackage(service); + } + GenerateImports(file, &*printer, vars); + GenerateService(service, &*printer, vars, false); + return out; +} + +} // namespace grpc_java_generator diff --git a/contrib/libs/flatbuffers/grpc/src/compiler/java_generator.h b/contrib/libs/flatbuffers/grpc/src/compiler/java_generator.h new file mode 100644 index 0000000000..b101fbf565 --- /dev/null +++ b/contrib/libs/flatbuffers/grpc/src/compiler/java_generator.h @@ -0,0 +1,85 @@ +/* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef NET_GRPC_COMPILER_JAVA_GENERATOR_H_ +#define NET_GRPC_COMPILER_JAVA_GENERATOR_H_ + +#include <stdlib.h> // for abort() +#include <iostream> +#include <map> +#include <string> + +#include "src/compiler/schema_interface.h" + +class LogMessageVoidify { + public: + LogMessageVoidify() {} + // This has to be an operator with a precedence lower than << but + // higher than ?: + void operator&(std::ostream&) {} +}; + +class LogHelper { + std::ostream* os_; + + public: + LogHelper(std::ostream* os) : os_(os) {} +#if defined(_MSC_VER) +#pragma warning(push) +#pragma warning( \ + disable : 4722) // the flow of control terminates in a destructor + // (needed to compile ~LogHelper where destructor emits abort intentionally - + // inherited from grpc/java code generator). +#endif + ~LogHelper() { + *os_ << std::endl; + ::abort(); + } +#if defined(_MSC_VER) +#pragma warning(pop) +#endif + std::ostream& get_os() const { return *os_; } +}; + +// Abort the program after logging the mesage if the given condition is not +// true. Otherwise, do nothing. +#define GRPC_CODEGEN_CHECK(x) \ + (x) ? (void)0 \ + : LogMessageVoidify() & LogHelper(&std::cerr).get_os() \ + << "CHECK FAILED: " << __FILE__ << ":" \ + << __LINE__ << ": " + +// Abort the program after logging the mesage. +#define GRPC_CODEGEN_FAIL GRPC_CODEGEN_CHECK(false) + +namespace grpc_java_generator { +struct Parameters { + // //Defines the custom parameter types for methods + // //eg: flatbuffers uses flatbuffers.Builder as input for the client + // and output for the server grpc::string custom_method_io_type; + + // Package name for the service + grpc::string package_name; +}; + +// Return the source of the generated service file. +grpc::string GenerateServiceSource(grpc_generator::File* file, + const grpc_generator::Service* service, + grpc_java_generator::Parameters* parameters); + +} // namespace grpc_java_generator + +#endif // NET_GRPC_COMPILER_JAVA_GENERATOR_H_ diff --git a/contrib/libs/flatbuffers/grpc/src/compiler/python_generator.cc b/contrib/libs/flatbuffers/grpc/src/compiler/python_generator.cc new file mode 100644 index 0000000000..8108db45d5 --- /dev/null +++ b/contrib/libs/flatbuffers/grpc/src/compiler/python_generator.cc @@ -0,0 +1,149 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include <map> +#include <sstream> + +#include "flatbuffers/util.h" +#include "src/compiler/python_generator.h" + +namespace grpc_python_generator { + +grpc::string GenerateMethodType(const grpc_generator::Method *method) { + + if (method->NoStreaming()) + return "unary_unary"; + + if (method->ServerStreaming()) + return "unary_stream"; + + if (method->ClientStreaming()) + return "stream_unary"; + + return "stream_stream"; +} + +grpc::string GenerateMethodInput(const grpc_generator::Method *method) { + + if (method->NoStreaming() || method->ServerStreaming()) + return "self, request, context"; + + return "self, request_iterator, context"; +} + +void GenerateStub(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + printer->Print(vars, "class $ServiceName$Stub(object):\n"); + printer->Indent(); + printer->Print("\"\"\" Interface exported by the server. \"\"\""); + printer->Print("\n\n"); + printer->Print("def __init__(self, channel):\n"); + printer->Indent(); + printer->Print("\"\"\" Constructor. \n\n"); + printer->Print("Args: \n"); + printer->Print("channel: A grpc.Channel. \n"); + printer->Print("\"\"\"\n\n"); + + for (int j = 0; j < service->method_count(); j++) { + auto method = service->method(j); + vars["MethodName"] = method->name(); + vars["MethodType"] = GenerateMethodType(&*method); + printer->Print(vars, "self.$MethodName$ = channel.$MethodType$(\n"); + printer->Indent(); + printer->Print(vars, "\"/$PATH$$ServiceName$/$MethodName$\"\n"); + printer->Print(")\n"); + printer->Outdent(); + printer->Print("\n"); + } + printer->Outdent(); + printer->Outdent(); + printer->Print("\n"); +} + +void GenerateServicer(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + printer->Print(vars, "class $ServiceName$Servicer(object):\n"); + printer->Indent(); + printer->Print("\"\"\" Interface exported by the server. \"\"\""); + printer->Print("\n\n"); + + for (int j = 0; j < service->method_count(); j++) { + auto method = service->method(j); + vars["MethodName"] = method->name(); + vars["MethodInput"] = GenerateMethodInput(&*method); + printer->Print(vars, "def $MethodName$($MethodInput$):\n"); + printer->Indent(); + printer->Print("context.set_code(grpc.StatusCode.UNIMPLEMENTED)\n"); + printer->Print("context.set_details('Method not implemented!')\n"); + printer->Print("raise NotImplementedError('Method not implemented!')\n"); + printer->Outdent(); + printer->Print("\n\n"); + } + printer->Outdent(); + printer->Print("\n"); + +} + +void GenerateRegister(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + printer->Print(vars, "def add_$ServiceName$Servicer_to_server(servicer, server):\n"); + printer->Indent(); + printer->Print("rpc_method_handlers = {\n"); + printer->Indent(); + for (int j = 0; j < service->method_count(); j++) { + auto method = service->method(j); + vars["MethodName"] = method->name(); + vars["MethodType"] = GenerateMethodType(&*method); + printer->Print(vars, "'$MethodName$': grpc.$MethodType$_rpc_method_handler(\n"); + printer->Indent(); + printer->Print(vars, "servicer.$MethodName$\n"); + printer->Outdent(); + printer->Print("),\n"); + } + printer->Outdent(); + printer->Print("}\n"); + printer->Print(vars, "generic_handler = grpc.method_handlers_generic_handler(\n"); + printer->Indent(); + printer->Print(vars, "'$PATH$$ServiceName$', rpc_method_handlers)\n"); + printer->Outdent(); + printer->Print("server.add_generic_rpc_handlers((generic_handler,))"); + printer->Outdent(); + printer->Print("\n"); +} + +grpc::string Generate(grpc_generator::File *file, + const grpc_generator::Service *service) { + grpc::string output; + std::map<grpc::string, grpc::string> vars; + vars["PATH"] = file->package(); + if (!file->package().empty()) { vars["PATH"].append("."); } + vars["ServiceName"] = service->name(); + auto printer = file->CreatePrinter(&output); + GenerateStub(service, &*printer, &vars); + GenerateServicer(service, &*printer, &vars); + GenerateRegister(service, &*printer, &vars); + return output; +} + +} // namespace grpc_python_generator diff --git a/contrib/libs/flatbuffers/grpc/src/compiler/python_generator.h b/contrib/libs/flatbuffers/grpc/src/compiler/python_generator.h new file mode 100644 index 0000000000..4f8f5cc806 --- /dev/null +++ b/contrib/libs/flatbuffers/grpc/src/compiler/python_generator.h @@ -0,0 +1,33 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_H +#define GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_H + +#include <utility> + +#include "src/compiler/config.h" +#include "src/compiler/schema_interface.h" + +namespace grpc_python_generator { + +grpc::string Generate(grpc_generator::File *file, + const grpc_generator::Service *service); +} // namespace grpc_python_generator + +#endif // GRPC_INTERNAL_COMPILER_PYTHON_GENERATOR_H diff --git a/contrib/libs/flatbuffers/grpc/src/compiler/schema_interface.h b/contrib/libs/flatbuffers/grpc/src/compiler/schema_interface.h new file mode 100644 index 0000000000..0449498198 --- /dev/null +++ b/contrib/libs/flatbuffers/grpc/src/compiler/schema_interface.h @@ -0,0 +1,120 @@ +/* + * + * Copyright 2015 gRPC authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#ifndef GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H +#define GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H + +#include <memory> +#include <vector> + +#include "src/compiler/config.h" + +#ifndef GRPC_CUSTOM_STRING +# include <string> +# define GRPC_CUSTOM_STRING std::string +#endif + +namespace grpc { + +typedef GRPC_CUSTOM_STRING string; + +} // namespace grpc + +namespace grpc_generator { + +// A common interface for objects having comments in the source. +// Return formatted comments to be inserted in generated code. +struct CommentHolder { + virtual ~CommentHolder() {} + virtual grpc::string GetLeadingComments(const grpc::string prefix) const = 0; + virtual grpc::string GetTrailingComments(const grpc::string prefix) const = 0; + virtual std::vector<grpc::string> GetAllComments() const = 0; +}; + +// An abstract interface representing a method. +struct Method : public CommentHolder { + virtual ~Method() {} + + virtual grpc::string name() const = 0; + + virtual grpc::string input_type_name() const = 0; + virtual grpc::string output_type_name() const = 0; + + virtual bool get_module_and_message_path_input( + grpc::string *str, grpc::string generator_file_name, + bool generate_in_pb2_grpc, grpc::string import_prefix) const = 0; + virtual bool get_module_and_message_path_output( + grpc::string *str, grpc::string generator_file_name, + bool generate_in_pb2_grpc, grpc::string import_prefix) const = 0; + + virtual std::vector<grpc::string> get_input_namespace_parts() const = 0; + virtual grpc::string get_input_type_name() const = 0; + virtual std::vector<grpc::string> get_output_namespace_parts() const = 0; + virtual grpc::string get_output_type_name() const = 0; + + virtual grpc::string get_fb_builder() const = 0; + + virtual bool NoStreaming() const = 0; + virtual bool ClientStreaming() const = 0; + virtual bool ServerStreaming() const = 0; + virtual bool BidiStreaming() const = 0; +}; + +// An abstract interface representing a service. +struct Service : public CommentHolder { + virtual ~Service() {} + + virtual std::vector<grpc::string> namespace_parts() const = 0; + virtual grpc::string name() const = 0; + virtual bool is_internal() const = 0; + + virtual int method_count() const = 0; + virtual std::unique_ptr<const Method> method(int i) const = 0; +}; + +struct Printer { + virtual ~Printer() {} + + virtual void Print(const std::map<grpc::string, grpc::string> &vars, + const char *template_string) = 0; + virtual void Print(const char *string) = 0; + virtual void SetIndentationSize(const int size) = 0; + virtual void Indent() = 0; + virtual void Outdent() = 0; +}; + +// An interface that allows the source generated to be output using various +// libraries/idls/serializers. +struct File : public CommentHolder { + virtual ~File() {} + + virtual grpc::string filename() const = 0; + virtual grpc::string filename_without_ext() const = 0; + virtual grpc::string package() const = 0; + virtual std::vector<grpc::string> package_parts() const = 0; + virtual grpc::string additional_headers() const = 0; + + virtual int service_count() const = 0; + virtual std::unique_ptr<const Service> service(int i) const = 0; + + virtual std::unique_ptr<Printer> CreatePrinter( + grpc::string *str, const char indentation_type = ' ') const = 0; +}; +} // namespace grpc_generator + +#endif // GRPC_INTERNAL_COMPILER_SCHEMA_INTERFACE_H diff --git a/contrib/libs/flatbuffers/grpc/src/compiler/swift_generator.cc b/contrib/libs/flatbuffers/grpc/src/compiler/swift_generator.cc new file mode 100644 index 0000000000..403a803ef1 --- /dev/null +++ b/contrib/libs/flatbuffers/grpc/src/compiler/swift_generator.cc @@ -0,0 +1,438 @@ +/* + * Copyright 2020 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * NOTE: The following implementation is a translation for the Swift-grpc + * generator since flatbuffers doesnt allow plugins for now. if an issue arises + * please open an issue in the flatbuffers repository. This file should always + * be maintained according to the Swift-grpc repository + */ +#include <map> +#include <sstream> + +#include "flatbuffers/util.h" +#include "src/compiler/schema_interface.h" +#include "src/compiler/swift_generator.h" + +namespace grpc_swift_generator { + +std::string WrapInNameSpace(const std::vector<std::string> &components, + const grpc::string &name) { + std::string qualified_name; + for (auto it = components.begin(); it != components.end(); ++it) + qualified_name += *it + "_"; + return qualified_name + name; +} + +grpc::string GenerateMessage(const std::vector<std::string> &components, + const grpc::string &name) { + return "Message<" + WrapInNameSpace(components, name) + ">"; +} + +// MARK: - Client + +void GenerateClientFuncName(const grpc_generator::Method *method, + grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + if (method->NoStreaming()) { + printer->Print(vars, + " $GenAccess$func $MethodName$(\n" + " _ request: $Input$\n" + " , callOptions: CallOptions?$isNil$\n" + " ) -> UnaryCall<$Input$, $Output$>"); + return; + } + + if (method->ServerStreaming()) { + printer->Print(vars, + " $GenAccess$func $MethodName$(\n" + " _ request: $Input$\n" + " , callOptions: CallOptions?$isNil$,\n" + " handler: @escaping ($Output$) -> Void\n" + " ) -> ServerStreamingCall<$Input$, $Output$>"); + return; + } + + if (method->ClientStreaming()) { + printer->Print(vars, + " $GenAccess$func $MethodName$(\n" + " callOptions: CallOptions?$isNil$\n" + " ) -> ClientStreamingCall<$Input$, $Output$>"); + return; + } + + printer->Print(vars, + " $GenAccess$func $MethodName$(\n" + " callOptions: CallOptions?$isNil$,\n" + " handler: @escaping ($Output$ ) -> Void\n" + " ) -> BidirectionalStreamingCall<$Input$, $Output$>"); +} + +void GenerateClientFuncBody(const grpc_generator::Method *method, + grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + vars["Interceptor"] = + "interceptors: self.interceptors?.make$MethodName$Interceptors() ?? []"; + if (method->NoStreaming()) { + printer->Print( + vars, + " return self.makeUnaryCall(\n" + " path: \"/$PATH$$ServiceName$/$MethodName$\",\n" + " request: request,\n" + " callOptions: callOptions ?? self.defaultCallOptions,\n" + " $Interceptor$\n" + " )\n"); + return; + } + + if (method->ServerStreaming()) { + printer->Print( + vars, + " return self.makeServerStreamingCall(\n" + " path: \"/$PATH$$ServiceName$/$MethodName$\",\n" + " request: request,\n" + " callOptions: callOptions ?? self.defaultCallOptions,\n" + " $Interceptor$,\n" + " handler: handler\n" + " )\n"); + return; + } + + if (method->ClientStreaming()) { + printer->Print( + vars, + " return self.makeClientStreamingCall(\n" + " path: \"/$PATH$$ServiceName$/$MethodName$\",\n" + " callOptions: callOptions ?? self.defaultCallOptions,\n" + " $Interceptor$\n" + " )\n"); + return; + } + printer->Print(vars, + " return self.makeBidirectionalStreamingCall(\n" + " path: \"/$PATH$$ServiceName$/$MethodName$\",\n" + " callOptions: callOptions ?? self.defaultCallOptions,\n" + " $Interceptor$,\n" + " handler: handler\n" + " )\n"); +} + +void GenerateClientProtocol(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + printer->Print( + vars, + "$ACCESS$ protocol $ServiceQualifiedName$ClientProtocol: GRPCClient {"); + printer->Print("\n\n"); + printer->Print(" var serviceName: String { get }"); + printer->Print("\n\n"); + printer->Print( + vars, + " var interceptors: " + "$ServiceQualifiedName$ClientInterceptorFactoryProtocol? { get }"); + printer->Print("\n\n"); + + vars["GenAccess"] = ""; + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["Input"] = GenerateMessage(method->get_input_namespace_parts(), + method->get_input_type_name()); + vars["Output"] = GenerateMessage(method->get_output_namespace_parts(), + method->get_output_type_name()); + vars["MethodName"] = method->name(); + vars["isNil"] = ""; + GenerateClientFuncName(method.get(), &*printer, &vars); + printer->Print("\n\n"); + } + printer->Print("}\n\n"); + + printer->Print(vars, "extension $ServiceQualifiedName$ClientProtocol {"); + printer->Print("\n\n"); + printer->Print(vars, + " $ACCESS$ var serviceName: String { " + "\"$PATH$$ServiceName$\" }\n"); + + vars["GenAccess"] = service->is_internal() ? "internal " : "public "; + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["Input"] = GenerateMessage(method->get_input_namespace_parts(), + method->get_input_type_name()); + vars["Output"] = GenerateMessage(method->get_output_namespace_parts(), + method->get_output_type_name()); + vars["MethodName"] = method->name(); + vars["isNil"] = " = nil"; + printer->Print("\n"); + GenerateClientFuncName(method.get(), &*printer, &vars); + printer->Print(" {\n"); + GenerateClientFuncBody(method.get(), &*printer, &vars); + printer->Print(" }\n"); + } + printer->Print("}\n\n"); + + printer->Print(vars, + "$ACCESS$ protocol " + "$ServiceQualifiedName$ClientInterceptorFactoryProtocol {\n"); + + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["Input"] = GenerateMessage(method->get_input_namespace_parts(), + method->get_input_type_name()); + vars["Output"] = GenerateMessage(method->get_output_namespace_parts(), + method->get_output_type_name()); + vars["MethodName"] = method->name(); + printer->Print( + vars, + " /// - Returns: Interceptors to use when invoking '$MethodName$'.\n"); + printer->Print(vars, + " func make$MethodName$Interceptors() -> " + "[ClientInterceptor<$Input$, $Output$>]\n\n"); + } + printer->Print("}\n\n"); +} + +void GenerateClientClass(grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + printer->Print(vars, + "$ACCESS$ final class $ServiceQualifiedName$ServiceClient: " + "$ServiceQualifiedName$ClientProtocol {\n"); + printer->Print(vars, " $ACCESS$ let channel: GRPCChannel\n"); + printer->Print(vars, " $ACCESS$ var defaultCallOptions: CallOptions\n"); + printer->Print(vars, + " $ACCESS$ var interceptors: " + "$ServiceQualifiedName$ClientInterceptorFactoryProtocol?\n"); + printer->Print("\n"); + printer->Print( + vars, + " $ACCESS$ init(\n" + " channel: GRPCChannel,\n" + " defaultCallOptions: CallOptions = CallOptions(),\n" + " interceptors: " + "$ServiceQualifiedName$ClientInterceptorFactoryProtocol? = nil\n" + " ) {\n"); + printer->Print(" self.channel = channel\n"); + printer->Print(" self.defaultCallOptions = defaultCallOptions\n"); + printer->Print(" self.interceptors = interceptors\n"); + printer->Print(" }"); + printer->Print("\n"); + printer->Print("}\n"); +} + +// MARK: - Server + +grpc::string GenerateServerFuncName(const grpc_generator::Method *method) { + if (method->NoStreaming()) { + return "func $MethodName$(request: $Input$" + ", context: StatusOnlyCallContext) -> EventLoopFuture<$Output$>"; + } + + if (method->ClientStreaming()) { + return "func $MethodName$(context: UnaryResponseCallContext<$Output$>) -> " + "EventLoopFuture<(StreamEvent<$Input$" + ">) -> Void>"; + } + + if (method->ServerStreaming()) { + return "func $MethodName$(request: $Input$" + ", context: StreamingResponseCallContext<$Output$>) -> " + "EventLoopFuture<GRPCStatus>"; + } + return "func $MethodName$(context: StreamingResponseCallContext<$Output$>) " + "-> EventLoopFuture<(StreamEvent<$Input$>) -> Void>"; +} + +grpc::string GenerateServerExtensionBody(const grpc_generator::Method *method) { + grpc::string start = " case \"$MethodName$\":\n "; + grpc::string interceptors = + " interceptors: self.interceptors?.make$MethodName$Interceptors() " + "?? [],\n"; + if (method->NoStreaming()) { + return start + + "return UnaryServerHandler(\n" + " context: context,\n" + " requestDeserializer: GRPCPayloadDeserializer<$Input$>(),\n" + " responseSerializer: GRPCPayloadSerializer<$Output$>(),\n" + + interceptors + + " userFunction: self.$MethodName$(request:context:))\n"; + } + if (method->ServerStreaming()) { + return start + + "return ServerStreamingServerHandler(\n" + " context: context,\n" + " requestDeserializer: GRPCPayloadDeserializer<$Input$>(),\n" + " responseSerializer: GRPCPayloadSerializer<$Output$>(),\n" + + interceptors + + " userFunction: self.$MethodName$(request:context:))\n"; + } + if (method->ClientStreaming()) { + return start + + "return ClientStreamingServerHandler(\n" + " context: context,\n" + " requestDeserializer: GRPCPayloadDeserializer<$Input$>(),\n" + " responseSerializer: GRPCPayloadSerializer<$Output$>(),\n" + + interceptors + + " observerFactory: self.$MethodName$(context:))\n"; + } + if (method->BidiStreaming()) { + return start + + "return BidirectionalStreamingServerHandler(\n" + " context: context,\n" + " requestDeserializer: GRPCPayloadDeserializer<$Input$>(),\n" + " responseSerializer: GRPCPayloadSerializer<$Output$>(),\n" + + interceptors + + " observerFactory: self.$MethodName$(context:))\n"; + } + return ""; +} + +void GenerateServerProtocol(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + printer->Print(vars, + "$ACCESS$ protocol $ServiceQualifiedName$Provider: " + "CallHandlerProvider {\n"); + printer->Print( + vars, + " var interceptors: " + "$ServiceQualifiedName$ServerInterceptorFactoryProtocol? { get }\n"); + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["Input"] = GenerateMessage(method->get_input_namespace_parts(), + method->get_input_type_name()); + vars["Output"] = GenerateMessage(method->get_output_namespace_parts(), + method->get_output_type_name()); + vars["MethodName"] = method->name(); + printer->Print(" "); + auto func = GenerateServerFuncName(method.get()); + printer->Print(vars, func.c_str()); + printer->Print("\n"); + } + printer->Print("}\n\n"); + + printer->Print(vars, "$ACCESS$ extension $ServiceQualifiedName$Provider {\n"); + printer->Print("\n"); + printer->Print(vars, + " var serviceName: Substring { return " + "\"$PATH$$ServiceName$\" }\n"); + printer->Print("\n"); + printer->Print( + " func handle(method name: Substring, context: " + "CallHandlerContext) -> GRPCServerHandlerProtocol? {\n"); + printer->Print(" switch name {\n"); + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["Input"] = GenerateMessage(method->get_input_namespace_parts(), + method->get_input_type_name()); + vars["Output"] = GenerateMessage(method->get_output_namespace_parts(), + method->get_output_type_name()); + vars["MethodName"] = method->name(); + auto body = GenerateServerExtensionBody(method.get()); + printer->Print(vars, body.c_str()); + printer->Print("\n"); + } + printer->Print(" default: return nil;\n"); + printer->Print(" }\n"); + printer->Print(" }\n\n"); + printer->Print("}\n\n"); + + printer->Print(vars, + "$ACCESS$ protocol " + "$ServiceQualifiedName$ServerInterceptorFactoryProtocol {\n"); + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["Input"] = GenerateMessage(method->get_input_namespace_parts(), + method->get_input_type_name()); + vars["Output"] = GenerateMessage(method->get_output_namespace_parts(), + method->get_output_type_name()); + vars["MethodName"] = method->name(); + printer->Print( + vars, + " /// - Returns: Interceptors to use when handling '$MethodName$'.\n" + " /// Defaults to calling `self.makeInterceptors()`.\n"); + printer->Print(vars, + " func make$MethodName$Interceptors() -> " + "[ServerInterceptor<$Input$, $Output$>]\n\n"); + } + printer->Print("}"); +} + +grpc::string Generate(grpc_generator::File *file, + const grpc_generator::Service *service) { + grpc::string output; + std::map<grpc::string, grpc::string> vars; + vars["PATH"] = file->package(); + if (!file->package().empty()) { vars["PATH"].append("."); } + vars["ServiceQualifiedName"] = + WrapInNameSpace(service->namespace_parts(), service->name()); + vars["ServiceName"] = service->name(); + vars["ACCESS"] = service->is_internal() ? "internal" : "public"; + auto printer = file->CreatePrinter(&output); + printer->Print( + vars, + "/// Usage: instantiate $ServiceQualifiedName$ServiceClient, then call " + "methods of this protocol to make API calls.\n"); + GenerateClientProtocol(service, &*printer, &vars); + GenerateClientClass(&*printer, &vars); + printer->Print("\n"); + GenerateServerProtocol(service, &*printer, &vars); + return output; +} + +grpc::string GenerateHeader() { + grpc::string code; + code += + "/// The following code is generated by the Flatbuffers library which " + "might not be in sync with grpc-swift\n"; + code += + "/// in case of an issue please open github issue, though it would be " + "maintained\n"; + code += "\n"; + code += "// swiftlint:disable all\n"; + code += "// swiftformat:disable all\n"; + code += "\n"; + code += "import Foundation\n"; + code += "import GRPC\n"; + code += "import NIO\n"; + code += "import NIOHTTP1\n"; + code += "import FlatBuffers\n"; + code += "\n"; + code += + "public protocol GRPCFlatBufPayload: GRPCPayload, FlatBufferGRPCMessage " + "{}\n"; + + code += "public extension GRPCFlatBufPayload {\n"; + code += " init(serializedByteBuffer: inout NIO.ByteBuffer) throws {\n"; + code += + " self.init(byteBuffer: FlatBuffers.ByteBuffer(contiguousBytes: " + "serializedByteBuffer.readableBytesView, count: " + "serializedByteBuffer.readableBytes))\n"; + code += " }\n"; + + code += " func serialize(into buffer: inout NIO.ByteBuffer) throws {\n"; + code += + " let buf = UnsafeRawBufferPointer(start: self.rawPointer, count: " + "Int(self.size))\n"; + code += " buffer.writeBytes(buf)\n"; + code += " }\n"; + code += "}\n"; + code += "extension Message: GRPCFlatBufPayload {}\n"; + return code; +} +} // namespace grpc_swift_generator diff --git a/contrib/libs/flatbuffers/grpc/src/compiler/swift_generator.h b/contrib/libs/flatbuffers/grpc/src/compiler/swift_generator.h new file mode 100644 index 0000000000..1639cb07c8 --- /dev/null +++ b/contrib/libs/flatbuffers/grpc/src/compiler/swift_generator.h @@ -0,0 +1,55 @@ +/* + * + * Copyright 2020, Google Inc. + * 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 Inc. 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 THE COPYRIGHT + * OWNER OR CONTRIBUTORS 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 <memory> +#include <vector> + +#include "src/compiler/config.h" +#include "src/compiler/schema_interface.h" + +#ifndef GRPC_CUSTOM_STRING +# include <string> +# define GRPC_CUSTOM_STRING std::string +#endif + +namespace grpc { + +typedef GRPC_CUSTOM_STRING string; + +} // namespace grpc + +namespace grpc_swift_generator { +grpc::string Generate(grpc_generator::File *file, + const grpc_generator::Service *service); +grpc::string GenerateHeader(); +} // namespace grpc_swift_generator diff --git a/contrib/libs/flatbuffers/grpc/src/compiler/ts_generator.cc b/contrib/libs/flatbuffers/grpc/src/compiler/ts_generator.cc new file mode 100644 index 0000000000..e49fd8d925 --- /dev/null +++ b/contrib/libs/flatbuffers/grpc/src/compiler/ts_generator.cc @@ -0,0 +1,523 @@ +/* + * Copyright 2020 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * NOTE: The following implementation is a translation for the Swift-grpc + * generator since flatbuffers doesnt allow plugins for now. if an issue arises + * please open an issue in the flatbuffers repository. This file should always + * be maintained according to the Swift-grpc repository + */ + +#include <map> +#include <sstream> + +#include "flatbuffers/util.h" +#include "src/compiler/schema_interface.h" +#include "src/compiler/ts_generator.h" + +namespace grpc_ts_generator { + +grpc::string ToDasherizedCase(const grpc::string pascal_case) { + std::string dasherized_case; + char p = 0; + for (size_t i = 0; i < pascal_case.length(); i++) { + char const &c = pascal_case[i]; + if (flatbuffers::is_alpha_upper(c)) { + if (i > 0 && p != flatbuffers::kPathSeparator) dasherized_case += "-"; + dasherized_case += flatbuffers::CharToLower(c); + } else { + dasherized_case += c; + } + p = c; + } + return dasherized_case; +} + +grpc::string GenerateNamespace(const std::vector<std::string> namepsace, + const std::string filename, + const bool include_separator) { + grpc::string path = ""; + if (include_separator) path += "."; + + for (auto it = namepsace.begin(); it < namepsace.end(); it++) { + if (include_separator) path += "/"; + path += include_separator ? ToDasherizedCase(*it) : *it + "_"; + } + + if (include_separator) path += "/"; + path += include_separator ? ToDasherizedCase(filename) : filename; + return path; +} + +// MARK: - Shared code + +void GenerateImports(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary, + const bool grpc_var_import) { + auto vars = *dictonary; + printer->Print( + "// Generated GRPC code for FlatBuffers TS *** DO NOT EDIT ***\n"); + printer->Print("import * as flatbuffers from 'flatbuffers';\n"); + + std::set<grpc::string> generated_imports; + + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + auto output = method->get_output_type_name(); + auto input = method->get_input_type_name(); + auto input_namespace = method->get_input_namespace_parts(); + + vars["OUTPUT"] = output; + vars["INPUT"] = input; + + if (generated_imports.find(output) == generated_imports.end()) { + generated_imports.insert(output); + vars["OUTPUT_DIR"] = + GenerateNamespace(method->get_output_namespace_parts(), output, true); + vars["Output_alias"] = GenerateNamespace( + method->get_output_namespace_parts(), output, false); + printer->Print( + vars, "import { $OUTPUT$ as $Output_alias$ } from '$OUTPUT_DIR$';\n"); + } + if (generated_imports.find(input) == generated_imports.end()) { + generated_imports.insert(input); + vars["INPUT_DIR"] = + GenerateNamespace(method->get_output_namespace_parts(), input, true); + vars["Input_alias"] = + GenerateNamespace(method->get_output_namespace_parts(), input, false); + printer->Print( + vars, "import { $INPUT$ as $Input_alias$ } from '$INPUT_DIR$';\n"); + } + } + printer->Print("\n"); + if (grpc_var_import) + printer->Print("var grpc = require('grpc');\n"); + else + printer->Print("import * as grpc from 'grpc';\n"); + printer->Print("\n"); +} + +// MARK: - Generate Main GRPC Code + +void GetStreamType(grpc_generator::Printer *printer, + const grpc_generator::Method *method, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + auto client_streaming = method->ClientStreaming() || method->BidiStreaming(); + auto server_streaming = method->ServerStreaming() || method->BidiStreaming(); + vars["ClientStreaming"] = client_streaming ? "true" : "false"; + vars["ServerStreaming"] = server_streaming ? "true" : "false"; + printer->Print(vars, "requestStream: $ClientStreaming$,\n"); + printer->Print(vars, "responseStream: $ServerStreaming$,\n"); +} + +void GenerateSerializeMethod(grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + printer->Print(vars, "function serialize_$Type$(buffer_args) {\n"); + printer->Indent(); + printer->Print(vars, "if (!(buffer_args instanceof $Type$)) {\n"); + printer->Indent(); + printer->Print(vars, + "throw new Error('Expected argument of type $VALUE$');\n"); + printer->Outdent(); + printer->Print("}\n"); + printer->Print(vars, "return buffer_args.serialize();\n"); + printer->Outdent(); + printer->Print("}\n\n"); +} + +void GenerateDeserializeMethod( + grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + printer->Print(vars, "function deserialize_$Type$(buffer) {\n"); + printer->Indent(); + printer->Print(vars, + "return $Type$.getRootAs$VALUE$(new " + "flatbuffers.ByteBuffer(buffer))\n"); + printer->Outdent(); + printer->Print("}\n\n"); +} + +void GenerateMethods(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + + std::set<grpc::string> generated_functions; + + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + auto output = method->get_output_type_name(); + auto input = method->get_input_type_name(); + + if (generated_functions.find(output) == generated_functions.end()) { + generated_functions.insert(output); + vars["VALUE"] = output; + vars["Type"] = GenerateNamespace(method->get_output_namespace_parts(), + output, false); + GenerateSerializeMethod(printer, &vars); + GenerateDeserializeMethod(printer, &vars); + } + printer->Print("\n"); + if (generated_functions.find(input) == generated_functions.end()) { + generated_functions.insert(input); + vars["VALUE"] = input; + vars["Type"] = + GenerateNamespace(method->get_input_namespace_parts(), input, false); + GenerateSerializeMethod(printer, &vars); + GenerateDeserializeMethod(printer, &vars); + } + } +} + +void GenerateService(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + vars["NAME"] = service->name() + "Service"; + + printer->Print(vars, "var $NAME$ = exports.$NAME$ = {\n"); + printer->Indent(); + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["MethodName"] = method->name(); + vars["OUTPUT"] = GenerateNamespace(method->get_output_namespace_parts(), + method->get_output_type_name(), false); + vars["INPUT"] = GenerateNamespace(method->get_input_namespace_parts(), + method->get_input_type_name(), false); + printer->Print(vars, "$MethodName$: {\n"); + printer->Indent(); + printer->Print(vars, "path: '/$PATH$$ServiceName$/$MethodName$',\n"); + GetStreamType(printer, &*method, &vars); + printer->Print(vars, "requestType: flatbuffers.ByteBuffer,\n"); + printer->Print(vars, "responseType: $OUTPUT$,\n"); + printer->Print(vars, "requestSerialize: serialize_$INPUT$,\n"); + printer->Print(vars, "requestDeserialize: deserialize_$INPUT$,\n"); + printer->Print(vars, "responseSerialize: serialize_$OUTPUT$,\n"); + printer->Print(vars, "responseDeserialize: deserialize_$OUTPUT$,\n"); + printer->Outdent(); + printer->Print("},\n"); + } + printer->Outdent(); + printer->Print("};\n"); + printer->Print(vars, + "exports.$ServiceName$Client = " + "grpc.makeGenericClientConstructor($NAME$);"); +} + +grpc::string Generate(grpc_generator::File *file, + const grpc_generator::Service *service, + const grpc::string &filename) { + grpc::string output; + std::map<grpc::string, grpc::string> vars; + + vars["PATH"] = file->package(); + + if (!file->package().empty()) { vars["PATH"].append("."); } + + vars["ServiceName"] = service->name(); + vars["FBSFile"] = service->name() + "_fbs"; + vars["Filename"] = filename; + auto printer = file->CreatePrinter(&output); + + GenerateImports(service, &*printer, &vars, true); + GenerateMethods(service, &*printer, &vars); + GenerateService(service, &*printer, &vars); + return output; +} + +// MARK: - Generate Interface + +void FillInterface(grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + printer->Print(vars, + "interface I$ServiceName$Service_I$MethodName$ extends " + "grpc.MethodDefinition<$INPUT$, $OUTPUT$> {\n"); + printer->Indent(); + printer->Print(vars, "path: string; // /$PATH$$ServiceName$/$MethodName$\n"); + printer->Print(vars, "requestStream: boolean; // $ClientStreaming$\n"); + printer->Print(vars, "responseStream: boolean; // $ServerStreaming$\n"); + printer->Print(vars, "requestSerialize: grpc.serialize<$INPUT$>;\n"); + printer->Print(vars, "requestDeserialize: grpc.deserialize<$INPUT$>;\n"); + printer->Print(vars, "responseSerialize: grpc.serialize<$OUTPUT$>;\n"); + printer->Print(vars, "responseDeserialize: grpc.deserialize<$OUTPUT$>;\n"); + printer->Outdent(); + printer->Print("}\n"); +} + +void GenerateInterfaces(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + auto client_streaming = + method->ClientStreaming() || method->BidiStreaming(); + auto server_streaming = + method->ServerStreaming() || method->BidiStreaming(); + vars["ClientStreaming"] = client_streaming ? "true" : "false"; + vars["ServerStreaming"] = server_streaming ? "true" : "false"; + vars["MethodName"] = method->name(); + vars["OUTPUT"] = GenerateNamespace(method->get_output_namespace_parts(), + method->get_output_type_name(), false); + vars["INPUT"] = GenerateNamespace(method->get_input_namespace_parts(), + method->get_input_type_name(), false); + FillInterface(printer, &vars); + printer->Print("\n"); + } +} + +void GenerateExportedInterface( + const grpc_generator::Service *service, grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + printer->Print(vars, "export interface I$ServiceName$Server {\n"); + printer->Indent(); + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["Name"] = method->name(); + vars["OUTPUT"] = GenerateNamespace(method->get_output_namespace_parts(), + method->get_output_type_name(), false); + vars["INPUT"] = GenerateNamespace(method->get_input_namespace_parts(), + method->get_input_type_name(), false); + if (method->BidiStreaming()) { + printer->Print(vars, + "$Name$: grpc.handleBidiStreamingCall<$INPUT$, " + "$OUTPUT$>;\n"); + continue; + } + if (method->NoStreaming()) { + printer->Print(vars, + "$Name$: grpc.handleUnaryCall<$INPUT$, " + "$OUTPUT$>;\n"); + continue; + } + if (method->ClientStreaming()) { + printer->Print(vars, + "$Name$: grpc.handleClientStreamingCall<$INPUT$, " + "$OUTPUT$>;\n"); + continue; + } + if (method->ServerStreaming()) { + printer->Print(vars, + "$Name$: grpc.handleServerStreamingCall<$INPUT$, " + "$OUTPUT$>;\n"); + continue; + } + } + printer->Outdent(); + printer->Print("}\n"); +} + +void GenerateMainInterface(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + printer->Print( + vars, + "interface I$ServiceName$Service extends " + "grpc.ServiceDefinition<grpc.UntypedServiceImplementation> {\n"); + printer->Indent(); + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["MethodName"] = method->name(); + printer->Print(vars, + "$MethodName$: I$ServiceName$Service_I$MethodName$;\n"); + } + printer->Outdent(); + printer->Print("}\n"); + GenerateInterfaces(service, printer, &vars); + printer->Print("\n"); + printer->Print(vars, + "export const $ServiceName$Service: I$ServiceName$Service;\n"); + printer->Print("\n"); + GenerateExportedInterface(service, printer, &vars); +} + +grpc::string GenerateMetaData() { return "metadata: grpc.Metadata"; } + +grpc::string GenerateOptions() { return "options: Partial<grpc.CallOptions>"; } + +void GenerateUnaryClientInterface( + grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + grpc::string main = "$ISPUBLIC$$MethodName$(request: $INPUT$, "; + grpc::string callback = + "callback: (error: grpc.ServiceError | null, response: " + "$OUTPUT$) => void): grpc.ClientUnaryCall;\n"; + auto meta_data = GenerateMetaData() + ", "; + auto options = GenerateOptions() + ", "; + printer->Print(vars, (main + callback).c_str()); + printer->Print(vars, (main + meta_data + callback).c_str()); + printer->Print(vars, (main + meta_data + options + callback).c_str()); +} + +void GenerateClientWriteStreamInterface( + grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + grpc::string main = "$ISPUBLIC$$MethodName$("; + grpc::string callback = + "callback: (error: grpc.ServiceError | null, response: " + "$INPUT$) => void): " + "grpc.ClientWritableStream<$OUTPUT$>;\n"; + auto meta_data = GenerateMetaData() + ", "; + auto options = GenerateOptions() + ", "; + printer->Print(vars, (main + callback).c_str()); + printer->Print(vars, (main + meta_data + callback).c_str()); + printer->Print(vars, (main + options + callback).c_str()); + printer->Print(vars, (main + meta_data + options + callback).c_str()); +} + +void GenerateClientReadableStreamInterface( + grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + grpc::string main = "$ISPUBLIC$$MethodName$(request: $INPUT$, "; + grpc::string end_function = "): grpc.ClientReadableStream<$OUTPUT$>;\n"; + auto meta_data = GenerateMetaData(); + auto options = GenerateOptions(); + printer->Print(vars, (main + meta_data + end_function).c_str()); + printer->Print(vars, (main + options + end_function).c_str()); +} + +void GenerateDepluxStreamInterface( + grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + grpc::string main = "$ISPUBLIC$$MethodName$("; + grpc::string end_function = + "): grpc.ClientDuplexStream<$INPUT$, $OUTPUT$>;\n"; + auto meta_data = GenerateMetaData(); + auto options = GenerateOptions(); + printer->Print(vars, (main + end_function).c_str()); + printer->Print(vars, (main + options + end_function).c_str()); + printer->Print(vars, (main + meta_data + + ", options?: Partial<grpc.CallOptions>" + end_function) + .c_str()); +} + +void GenerateClientInterface(const grpc_generator::Service *service, + grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + printer->Print(vars, "export interface I$ServiceName$Client {\n"); + printer->Indent(); + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["MethodName"] = method->name(); + vars["OUTPUT"] = GenerateNamespace(method->get_output_namespace_parts(), + method->get_output_type_name(), false); + vars["INPUT"] = GenerateNamespace(method->get_input_namespace_parts(), + method->get_input_type_name(), false); + vars["ISPUBLIC"] = ""; + + if (method->NoStreaming()) { + GenerateUnaryClientInterface(printer, &vars); + continue; + } + if (method->BidiStreaming()) { + GenerateDepluxStreamInterface(printer, &vars); + continue; + } + + if (method->ClientStreaming()) { + GenerateClientWriteStreamInterface(printer, &vars); + continue; + } + + if (method->ServerStreaming()) { + GenerateClientReadableStreamInterface(printer, &vars); + continue; + } + } + printer->Outdent(); + printer->Print("}\n"); +} + +void GenerateClientClassInterface( + const grpc_generator::Service *service, grpc_generator::Printer *printer, + std::map<grpc::string, grpc::string> *dictonary) { + auto vars = *dictonary; + printer->Print(vars, + "export class $ServiceName$Client extends grpc.Client " + "implements I$ServiceName$Client {\n"); + printer->Indent(); + printer->Print( + "constructor(address: string, credentials: grpc.ChannelCredentials, " + "options?: object);"); + for (auto it = 0; it < service->method_count(); it++) { + auto method = service->method(it); + vars["MethodName"] = method->name(); + vars["OUTPUT"] = GenerateNamespace(method->get_output_namespace_parts(), + method->get_output_type_name(), false); + vars["INPUT"] = GenerateNamespace(method->get_input_namespace_parts(), + method->get_input_type_name(), false); + vars["ISPUBLIC"] = "public "; + if (method->NoStreaming()) { + GenerateUnaryClientInterface(printer, &vars); + continue; + } + if (method->BidiStreaming()) { + GenerateDepluxStreamInterface(printer, &vars); + continue; + } + + if (method->ClientStreaming()) { + GenerateClientWriteStreamInterface(printer, &vars); + continue; + } + + if (method->ServerStreaming()) { + GenerateClientReadableStreamInterface(printer, &vars); + continue; + } + } + printer->Outdent(); + printer->Print("}\n"); +} + +grpc::string GenerateInterface(grpc_generator::File *file, + const grpc_generator::Service *service, + const grpc::string &filename) { + grpc::string output; + + std::set<grpc::string> generated_functions; + std::map<grpc::string, grpc::string> vars; + + vars["PATH"] = file->package(); + + if (!file->package().empty()) { vars["PATH"].append("."); } + + vars["ServiceName"] = service->name(); + vars["FBSFile"] = service->name() + "_fbs"; + vars["Filename"] = filename; + auto printer = file->CreatePrinter(&output); + + GenerateImports(service, &*printer, &vars, false); + GenerateMainInterface(service, &*printer, &vars); + printer->Print("\n"); + GenerateClientInterface(service, &*printer, &vars); + printer->Print("\n"); + GenerateClientClassInterface(service, &*printer, &vars); + return output; +} +} // namespace grpc_ts_generator diff --git a/contrib/libs/flatbuffers/grpc/src/compiler/ts_generator.h b/contrib/libs/flatbuffers/grpc/src/compiler/ts_generator.h new file mode 100644 index 0000000000..a33bb3c5d2 --- /dev/null +++ b/contrib/libs/flatbuffers/grpc/src/compiler/ts_generator.h @@ -0,0 +1,61 @@ +/* + * + * Copyright 2020, Google Inc. + * 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 Inc. 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 THE COPYRIGHT + * OWNER OR CONTRIBUTORS 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 <memory> +#include <vector> +#include <set> + +#include "src/compiler/config.h" +#include "src/compiler/schema_interface.h" + +#ifndef GRPC_CUSTOM_STRING +# include <string> +# define GRPC_CUSTOM_STRING std::string +#endif + +namespace grpc { + +typedef GRPC_CUSTOM_STRING string; + +} // namespace grpc + +namespace grpc_ts_generator { +grpc::string Generate(grpc_generator::File *file, + const grpc_generator::Service *service, + const grpc::string &filename); + +grpc::string GenerateInterface(grpc_generator::File *file, + const grpc_generator::Service *service, + const grpc::string &filename); +} // namespace grpc_ts_generator + diff --git a/contrib/libs/flatbuffers/include/flatbuffers/code_generators.h b/contrib/libs/flatbuffers/include/flatbuffers/code_generators.h new file mode 100644 index 0000000000..09b773a468 --- /dev/null +++ b/contrib/libs/flatbuffers/include/flatbuffers/code_generators.h @@ -0,0 +1,235 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_CODE_GENERATORS_H_ +#define FLATBUFFERS_CODE_GENERATORS_H_ + +#include <map> +#include <sstream> + +#include "idl.h" + +namespace flatbuffers { + +// Utility class to assist in generating code through use of text templates. +// +// Example code: +// CodeWriter code("\t"); +// code.SetValue("NAME", "Foo"); +// code += "void {{NAME}}() { printf("%s", "{{NAME}}"); }"; +// code.SetValue("NAME", "Bar"); +// code += "void {{NAME}}() { printf("%s", "{{NAME}}"); }"; +// std::cout << code.ToString() << std::endl; +// +// Output: +// void Foo() { printf("%s", "Foo"); } +// void Bar() { printf("%s", "Bar"); } +class CodeWriter { + public: + CodeWriter(std::string pad = std::string()) + : pad_(pad), cur_ident_lvl_(0), ignore_ident_(false) {} + + // Clears the current "written" code. + void Clear() { + stream_.str(""); + stream_.clear(); + } + + // Associates a key with a value. All subsequent calls to operator+=, where + // the specified key is contained in {{ and }} delimiters will be replaced by + // the given value. + void SetValue(const std::string &key, const std::string &value) { + value_map_[key] = value; + } + + std::string GetValue(const std::string &key) const { + const auto it = value_map_.find(key); + return it == value_map_.end() ? "" : it->second; + } + + // Appends the given text to the generated code as well as a newline + // character. Any text within {{ and }} delimiters is replaced by values + // previously stored in the CodeWriter by calling SetValue above. The newline + // will be suppressed if the text ends with the \\ character. + void operator+=(std::string text); + + // Returns the current contents of the CodeWriter as a std::string. + std::string ToString() const { return stream_.str(); } + + // Increase ident level for writing code + void IncrementIdentLevel() { cur_ident_lvl_++; } + // Decrease ident level for writing code + void DecrementIdentLevel() { + if (cur_ident_lvl_) cur_ident_lvl_--; + } + + void SetPadding(const std::string &padding) { pad_ = padding; } + + private: + std::map<std::string, std::string> value_map_; + std::stringstream stream_; + std::string pad_; + int cur_ident_lvl_; + bool ignore_ident_; + + // Add ident padding (tab or space) based on ident level + void AppendIdent(std::stringstream &stream); +}; + +class BaseGenerator { + public: + virtual bool generate() = 0; + + static std::string NamespaceDir(const Parser &parser, const std::string &path, + const Namespace &ns, + const bool dasherize = false); + + static std::string ToDasherizedCase(const std::string pascal_case); + + std::string GeneratedFileName(const std::string &path, + const std::string &file_name, + const IDLOptions &options) const; + + protected: + BaseGenerator(const Parser &parser, const std::string &path, + const std::string &file_name, std::string qualifying_start, + std::string qualifying_separator, std::string default_extension) + : parser_(parser), + path_(path), + file_name_(file_name), + qualifying_start_(qualifying_start), + qualifying_separator_(qualifying_separator), + default_extension_(default_extension) {} + virtual ~BaseGenerator() {} + + // No copy/assign. + BaseGenerator &operator=(const BaseGenerator &); + BaseGenerator(const BaseGenerator &); + + std::string NamespaceDir(const Namespace &ns, + const bool dasherize = false) const; + + static const char *FlatBuffersGeneratedWarning(); + + static std::string FullNamespace(const char *separator, const Namespace &ns); + + static std::string LastNamespacePart(const Namespace &ns); + + // tracks the current namespace for early exit in WrapInNameSpace + // c++, java and csharp returns a different namespace from + // the following default (no early exit, always fully qualify), + // which works for js and php + virtual const Namespace *CurrentNameSpace() const { return nullptr; } + + // Ensure that a type is prefixed with its namespace even within + // its own namespace to avoid conflict between generated method + // names and similarly named classes or structs + std::string WrapInNameSpace(const Namespace *ns, + const std::string &name) const; + + std::string WrapInNameSpace(const Definition &def) const; + + std::string GetNameSpace(const Definition &def) const; + + const Parser &parser_; + const std::string &path_; + const std::string &file_name_; + const std::string qualifying_start_; + const std::string qualifying_separator_; + const std::string default_extension_; +}; + +struct CommentConfig { + const char *first_line; + const char *content_line_prefix; + const char *last_line; +}; + +extern void GenComment(const std::vector<std::string> &dc, + std::string *code_ptr, const CommentConfig *config, + const char *prefix = ""); + +class FloatConstantGenerator { + public: + virtual ~FloatConstantGenerator() {} + std::string GenFloatConstant(const FieldDef &field) const; + + private: + virtual std::string Value(double v, const std::string &src) const = 0; + virtual std::string Inf(double v) const = 0; + virtual std::string NaN(double v) const = 0; + + virtual std::string Value(float v, const std::string &src) const = 0; + virtual std::string Inf(float v) const = 0; + virtual std::string NaN(float v) const = 0; + + template<typename T> + std::string GenFloatConstantImpl(const FieldDef &field) const; +}; + +class SimpleFloatConstantGenerator : public FloatConstantGenerator { + public: + SimpleFloatConstantGenerator(const char *nan_number, + const char *pos_inf_number, + const char *neg_inf_number); + + private: + std::string Value(double v, + const std::string &src) const FLATBUFFERS_OVERRIDE; + std::string Inf(double v) const FLATBUFFERS_OVERRIDE; + std::string NaN(double v) const FLATBUFFERS_OVERRIDE; + + std::string Value(float v, const std::string &src) const FLATBUFFERS_OVERRIDE; + std::string Inf(float v) const FLATBUFFERS_OVERRIDE; + std::string NaN(float v) const FLATBUFFERS_OVERRIDE; + + const std::string nan_number_; + const std::string pos_inf_number_; + const std::string neg_inf_number_; +}; + +// C++, C#, Java like generator. +class TypedFloatConstantGenerator : public FloatConstantGenerator { + public: + TypedFloatConstantGenerator(const char *double_prefix, + const char *single_prefix, const char *nan_number, + const char *pos_inf_number, + const char *neg_inf_number = ""); + + private: + std::string Value(double v, + const std::string &src) const FLATBUFFERS_OVERRIDE; + std::string Inf(double v) const FLATBUFFERS_OVERRIDE; + + std::string NaN(double v) const FLATBUFFERS_OVERRIDE; + + std::string Value(float v, const std::string &src) const FLATBUFFERS_OVERRIDE; + std::string Inf(float v) const FLATBUFFERS_OVERRIDE; + std::string NaN(float v) const FLATBUFFERS_OVERRIDE; + + std::string MakeNaN(const std::string &prefix) const; + std::string MakeInf(bool neg, const std::string &prefix) const; + + const std::string double_prefix_; + const std::string single_prefix_; + const std::string nan_number_; + const std::string pos_inf_number_; + const std::string neg_inf_number_; +}; + +} // namespace flatbuffers + +#endif // FLATBUFFERS_CODE_GENERATORS_H_ diff --git a/contrib/libs/flatbuffers/include/flatbuffers/flatbuffers_iter.h b/contrib/libs/flatbuffers/include/flatbuffers/flatbuffers_iter.h new file mode 100644 index 0000000000..a770983dca --- /dev/null +++ b/contrib/libs/flatbuffers/include/flatbuffers/flatbuffers_iter.h @@ -0,0 +1,640 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_ITER_H_ +#define FLATBUFFERS_ITER_H_ + +#include "flatbuffers.h" +#include <optional> + +/// @file +namespace yandex { +namespace maps { +namespace flatbuffers_iter { + +#define FLATBUFFERS_FILE_IDENTIFIER_LENGTH 4 + +using flatbuffers::uoffset_t; +using flatbuffers::soffset_t; +using flatbuffers::voffset_t; +using flatbuffers::EndianScalar; + +// Wrapper for uoffset_t to allow safe template specialization. +template<typename T> struct Offset { + uoffset_t o; + Offset() : o(0) {} + Offset(uoffset_t _o) : o(_o) {} + Offset<void> Union() const { return Offset<void>(o); } +}; + +template<typename Iter> +inline bool hasContiguous(const Iter& spot, uoffset_t length) +{ + return spot.hasContiguous(length); +} + +inline bool hasContiguous(const uint8_t* /* spot */, uoffset_t /* length */) +{ + return true; +} + +template <typename Iter> +inline const uint8_t* getRawPointer(const Iter& spot) +{ + return spot.rawPointer(); +} + +inline const uint8_t* getRawPointer(const uint8_t* spot) +{ + return spot; +} + +template<typename T, typename Iter> +typename std::enable_if<sizeof(T) == 1, T>::type extractValue(const Iter& spot) +{ + typename std::remove_cv<T>::type ret; + std::memcpy(&ret, getRawPointer(spot), 1); + return ret; +} + +template<typename T, typename Iter> +typename std::enable_if<sizeof(T) != 1, T>::type extractValue(const Iter& spot) +{ + if (hasContiguous(spot, sizeof(T))) { + typename std::remove_cv<T>::type ret; + std::memcpy(&ret, getRawPointer(spot), sizeof(T)); + return ret; + } + Iter itr = spot; + alignas(T) uint8_t buf[sizeof(T)]; + for (std::size_t i = 0; i < sizeof(T); ++i) { + buf[i] = *itr; + ++itr; + } + return *reinterpret_cast<T*>(buf); +} + +template<typename T, typename Iter> T ReadScalar(Iter p) { + return EndianScalar(extractValue<T>(p)); +} + +// When we read serialized data from memory, in the case of most scalars, +// we want to just read T, but in the case of Offset, we want to actually +// perform the indirection and return a pointer. +// The template specialization below does just that. +// It is wrapped in a struct since function templates can't overload on the +// return type like this. +// The typedef is for the convenience of callers of this function +// (avoiding the need for a trailing return decltype) +template<typename T> struct IndirectHelper { + typedef T return_type; + typedef T mutable_return_type; + static const size_t element_stride = sizeof(T); + template<typename Iter> + static return_type Read(const Iter& p, uoffset_t i) { + return i ? EndianScalar(extractValue<return_type>(p+sizeof(return_type)*i)) : EndianScalar(extractValue<return_type>(p)); + } +}; +template<typename T> struct IndirectHelper<Offset<T>> { + typedef std::optional<T> return_type; + typedef std::optional<T> mutable_return_type; + static const size_t element_stride = sizeof(uoffset_t); + template<typename Iter> + static return_type Read(Iter p, uoffset_t i) { + p += i * sizeof(uoffset_t); + return return_type(T(p + ReadScalar<uoffset_t>(p))); + } +}; +template<typename T> struct IndirectHelper<const T *> { +}; + + +// An STL compatible iterator implementation for Vector below, effectively +// calling Get() for every element. +template<typename T, typename IT, typename Iter> +struct VectorIterator + : public std::iterator<std::random_access_iterator_tag, IT, uoffset_t> { + + typedef std::iterator<std::random_access_iterator_tag, IT, uoffset_t> super_type; + +public: + VectorIterator(const Iter& data, uoffset_t i) : + data_(data + IndirectHelper<T>::element_stride * i) {} + VectorIterator(const VectorIterator &other) : data_(other.data_) {} + #ifndef FLATBUFFERS_CPP98_STL + VectorIterator(VectorIterator &&other) : data_(std::move(other.data_)) {} + #endif + + VectorIterator &operator=(const VectorIterator &other) { + data_ = other.data_; + return *this; + } + + VectorIterator &operator=(VectorIterator &&other) { + data_ = other.data_; + return *this; + } + + bool operator==(const VectorIterator &other) const { + return data_ == other.data_; + } + + bool operator!=(const VectorIterator &other) const { + return data_ != other.data_; + } + + ptrdiff_t operator-(const VectorIterator &other) const { + return (data_ - other.data_) / IndirectHelper<T>::element_stride; + } + + typename super_type::value_type operator *() const { + return IndirectHelper<T>::Read(data_, 0); + } + + typename super_type::value_type operator->() const { + return IndirectHelper<T>::Read(data_, 0); + } + + VectorIterator &operator++() { + data_ += IndirectHelper<T>::element_stride; + return *this; + } + + VectorIterator operator++(int) { + VectorIterator temp(data_, 0); + data_ += IndirectHelper<T>::element_stride; + return temp; + } + + VectorIterator operator+(const uoffset_t &offset) { + return VectorIterator(data_ + offset * IndirectHelper<T>::element_stride, 0); + } + + VectorIterator& operator+=(const uoffset_t &offset) { + data_ += offset * IndirectHelper<T>::element_stride; + return *this; + } + + VectorIterator &operator--() { + data_ -= IndirectHelper<T>::element_stride; + return *this; + } + + VectorIterator operator--(int) { + VectorIterator temp(data_, 0); + data_ -= IndirectHelper<T>::element_stride; + return temp; + } + + VectorIterator operator-(const uoffset_t &offset) { + return VectorIterator(data_ - offset * IndirectHelper<T>::element_stride, 0); + } + + VectorIterator& operator-=(const uoffset_t &offset) { + data_ -= offset * IndirectHelper<T>::element_stride; + return *this; + } + +private: + Iter data_; +}; + +// This is used as a helper type for accessing vectors. +// Vector::data() assumes the vector elements start after the length field. +template<typename T, typename Iter> class Vector { +public: + typedef VectorIterator<T, typename IndirectHelper<T>::mutable_return_type, Iter> + iterator; + typedef VectorIterator<T, typename IndirectHelper<T>::return_type, Iter> + const_iterator; + + Vector(Iter data): + data_(data) + {} + + uoffset_t size() const { return EndianScalar(extractValue<uoffset_t>(data_)); } + + // Deprecated: use size(). Here for backwards compatibility. + uoffset_t Length() const { return size(); } + + typedef typename IndirectHelper<T>::return_type return_type; + typedef typename IndirectHelper<T>::mutable_return_type mutable_return_type; + + return_type Get(uoffset_t i) const { + assert(i < size()); + return IndirectHelper<T>::Read(Data(), i); + } + + return_type operator[](uoffset_t i) const { return Get(i); } + + // If this is a Vector of enums, T will be its storage type, not the enum + // type. This function makes it convenient to retrieve value with enum + // type E. + template<typename E> E GetEnum(uoffset_t i) const { + return static_cast<E>(Get(i)); + } + + const Iter GetStructFromOffset(size_t o) const { + return Data() + o; + } + + iterator begin() { return iterator(Data(), 0); } + const_iterator begin() const { return const_iterator(Data(), 0); } + + iterator end() { return iterator(Data(), size()); } + const_iterator end() const { return const_iterator(Data(), size()); } + + // The raw data in little endian format. Use with care. + const Iter Data() const { + return data_ + sizeof(uoffset_t); + } + + Iter Data() { + return data_ + sizeof(uoffset_t); + } + + template<typename K> return_type LookupByKey(K key) const { + auto search_result = std::lower_bound(begin(), end(), key, KeyCompare<K>); + + if (search_result == end() || (*search_result)->KeyCompareWithValue(key) != 0) { + return std::nullopt; // Key not found. + } + + return *search_result; + } + + operator Iter() const + { + return data_; + } + +protected: + Iter data_; + +private: + template<typename K> static int KeyCompare(const return_type& ap, const K& bp) { + return ap->KeyCompareWithValue(bp) < 0; + } +}; + +// Represent a vector much like the template above, but in this case we +// don't know what the element types are (used with reflection.h). +template <typename Iter> +class VectorOfAny { +public: + VectorOfAny(Iter data): + data_(data) + {} + + uoffset_t size() const { return EndianScalar(extractValue<uoffset_t>(data_)); } + + const Iter Data() const { + return data_; + } + Iter Data() { + return data_; + } +protected: + + Iter data_; +}; + +// Convenient helper function to get the length of any vector, regardless +// of wether it is null or not (the field is not set). +template<typename T, typename Iter> static inline size_t VectorLength(const std::optional<Vector<T, Iter>> &v) { + return v ? v->Length() : 0; +} + +template <typename Iter> struct String : public Vector<char, Iter> { + using Vector<char,Iter>::Vector; + using Vector<char,Iter>::data_; + + std::string str() const { + if (hasContiguous(data_, sizeof(uoffset_t) + this->Length())) + return std::string(reinterpret_cast<const char*>(getRawPointer(data_)) + sizeof(uoffset_t), this->Length()); + return std::string(this->begin(), this->begin() + this->Length()); } + + bool operator <(const String &o) const { + return str() < o.str(); + } +}; + +// Converts a Field ID to a virtual table offset. +inline voffset_t FieldIndexToOffset(voffset_t field_id) { + // Should correspond to what EndTable() below builds up. + const int fixed_fields = 2; // Vtable size and Object Size. + return static_cast<voffset_t>((field_id + fixed_fields) * sizeof(voffset_t)); +} + +/// @endcond + +/// @cond FLATBUFFERS_INTERNAL +template<typename T, typename Iter> std::optional<T> GetMutableRoot(Iter begin) { + flatbuffers::EndianCheck(); + return T(begin + EndianScalar(extractValue<uoffset_t>(begin))); +} + +template<typename T, typename Iter> std::optional<T> GetRoot(Iter begin) { + return GetMutableRoot<T, Iter>(begin); +} + +template<typename T, typename Iter> std::optional<T> GetSizePrefixedRoot(Iter buf) { + return GetRoot<T, Iter>(buf + sizeof(uoffset_t)); +} + +// Helper to see if the identifier in a buffer has the expected value. + +template <typename Iter> inline bool BufferHasIdentifier(const Iter& buf, const char *identifier) { + return std::equal( + identifier, + identifier + std::min(std::strlen(identifier) + 1, static_cast<std::size_t>(FLATBUFFERS_FILE_IDENTIFIER_LENGTH)), + buf + sizeof(uoffset_t)); +} + +// Helper class to verify the integrity of a FlatBuffer +template <typename Iter> +class Verifier FLATBUFFERS_FINAL_CLASS { + public: + Verifier(const Iter& buf, size_t buf_len, size_t _max_depth = 64, + size_t _max_tables = 1000000) + : buf_(buf), end_(buf + buf_len), depth_(0), max_depth_(_max_depth), + num_tables_(0), max_tables_(_max_tables) + #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE + , upper_bound_(buf) + #endif + {} + + // Central location where any verification failures register. + bool Check(bool ok) const { + #ifdef FLATBUFFERS_DEBUG_VERIFICATION_FAILURE + assert(ok); + #endif + #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE + if (!ok) + upper_bound_ = buf_; + #endif + return ok; + } + + // Verify any range within the buffer. + bool Verify(const Iter& elem, size_t elem_len) const { + #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE + auto upper_bound = elem + elem_len; + if (upper_bound_ < upper_bound) + upper_bound_ = upper_bound; + #endif + return Check(elem_len <= (size_t) (end_ - buf_) && + elem >= buf_ && + elem <= end_ - elem_len); + } + + // Verify a range indicated by sizeof(T). + template<typename T> bool Verify(const Iter& elem) const { + return Verify(elem, sizeof(T)); + } + + template<typename T> bool VerifyTable(const std::optional<T>& table) { + return !table || table->Verify(*this); + } + + template<typename T> bool Verify(const std::optional<Vector<T, Iter>>& vec) const { + Iter end; + return !vec || + VerifyVector(static_cast<Iter>(*vec), sizeof(T), + &end); + } + + template<typename T> bool Verify(const std::optional<Vector<const T, Iter>>& vec) const { + return Verify(*reinterpret_cast<const std::optional<Vector<T, Iter>> *>(&vec)); + } + + bool Verify(const std::optional<String<Iter>>& str) const { + Iter end; + return !str || + (VerifyVector(static_cast<Iter>(*str), 1, &end) && + Verify(end, 1) && // Must have terminator + Check(*end == '\0')); // Terminating byte must be 0. + } + + // Common code between vectors and strings. + bool VerifyVector(const Iter& vec, size_t elem_size, + Iter *end) const { + // Check we can read the size field. + if (!Verify<uoffset_t>(vec)) return false; + // Check the whole array. If this is a string, the byte past the array + // must be 0. + auto size = ReadScalar<uoffset_t>(vec); + auto max_elems = FLATBUFFERS_MAX_BUFFER_SIZE / elem_size; + if (!Check(size < max_elems)) + return false; // Protect against byte_size overflowing. + auto byte_size = sizeof(size) + elem_size * size; + *end = vec + byte_size; + return Verify(vec, byte_size); + } + + // Special case for string contents, after the above has been called. + bool VerifyVectorOfStrings(const std::optional<Vector<Offset<String<Iter>>, Iter>>& vec) const { + if (vec) { + for (uoffset_t i = 0; i < vec->size(); i++) { + if (!Verify(vec->Get(i))) return false; + } + } + return true; + } + + // Special case for table contents, after the above has been called. + template<typename T> bool VerifyVectorOfTables(const std::optional<Vector<Offset<T>, Iter>>& vec) { + if (vec) { + for (uoffset_t i = 0; i < vec->size(); i++) { + if (!vec->Get(i)->Verify(*this)) return false; + } + } + return true; + } + + template<typename T> bool VerifyBufferFromStart(const char *identifier, + const Iter& start) { + if (identifier && + (static_cast<std::size_t>(end_ - start) < 2 * sizeof(flatbuffers_iter::uoffset_t) || + !BufferHasIdentifier(start, identifier))) { + return false; + } + + // Call T::Verify, which must be in the generated code for this type. + return Verify<uoffset_t>(start) && + T(start + ReadScalar<uoffset_t>(start)). + Verify(*this) + #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE + && GetComputedSize() + #endif + ; + } + + // Verify this whole buffer, starting with root type T. + template<typename T> bool VerifyBuffer(const char *identifier) { + return VerifyBufferFromStart<T>(identifier, buf_); + } + + template<typename T> bool VerifySizePrefixedBuffer(const char *identifier) { + return Verify<uoffset_t>(buf_) && + ReadScalar<uoffset_t>(buf_) == end_ - buf_ - sizeof(uoffset_t) && + VerifyBufferFromStart<T>(identifier, buf_ + sizeof(uoffset_t)); + } + + // Called at the start of a table to increase counters measuring data + // structure depth and amount, and possibly bails out with false if + // limits set by the constructor have been hit. Needs to be balanced + // with EndTable(). + bool VerifyComplexity() { + depth_++; + num_tables_++; + return Check(depth_ <= max_depth_ && num_tables_ <= max_tables_); + } + + // Called at the end of a table to pop the depth count. + bool EndTable() { + depth_--; + return true; + } + + #ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE + // Returns the message size in bytes + size_t GetComputedSize() const { + uintptr_t size = upper_bound_ - buf_; + // Align the size to uoffset_t + size = (size - 1 + sizeof(uoffset_t)) & ~(sizeof(uoffset_t) - 1); + return (buf_ + size > end_) ? 0 : size; + } + #endif + + private: + const Iter buf_; + const Iter end_; + size_t depth_; + size_t max_depth_; + size_t num_tables_; + size_t max_tables_; +#ifdef FLATBUFFERS_TRACK_VERIFIER_BUFFER_SIZE + mutable const Iter upper_bound_; +#endif +}; + +// "structs" are flat structures that do not have an offset table, thus +// always have all members present and do not support forwards/backwards +// compatible extensions. +template <typename Iter> +class Struct FLATBUFFERS_FINAL_CLASS { + public: + template<typename T> T GetField(uoffset_t o) const { + return ReadScalar<T>(data_ + o); + } + + template<typename T> T GetStruct(uoffset_t o) const { + return T(data_ + o); + } + + private: + Iter data_; +}; + +// "tables" use an offset table (possibly shared) that allows fields to be +// omitted and added at will, but uses an extra indirection to read. +template<typename Iter> +class Table { + public: + Table(Iter data): data_(data) {} + + const Iter GetVTable() const { + return data_ - ReadScalar<soffset_t>(data_); + } + + // This gets the field offset for any of the functions below it, or 0 + // if the field was not present. + voffset_t GetOptionalFieldOffset(voffset_t field) const { + // The vtable offset is always at the start. + auto vtable = GetVTable(); + // The first element is the size of the vtable (fields + type id + itself). + auto vtsize = ReadScalar<voffset_t>(vtable); + // If the field we're accessing is outside the vtable, we're reading older + // data, so it's the same as if the offset was 0 (not present). + return field < vtsize ? ReadScalar<voffset_t>(vtable + field) : 0; + } + + template<typename T> T GetField(voffset_t field, T defaultval) const { + auto field_offset = GetOptionalFieldOffset(field); + return field_offset ? ReadScalar<T>(data_ + field_offset) : defaultval; + } + + template<typename P> std::optional<P> GetPointer(voffset_t field) { + auto field_offset = GetOptionalFieldOffset(field); + auto p = data_ + field_offset; + return field_offset ? std::optional<P>(P(p + ReadScalar<uoffset_t>(p))) : std::nullopt; + } + + template<typename P> std::optional<P> GetPointer(voffset_t field) const { + return const_cast<Table *>(this)->template GetPointer<P>(field); + } + + template<typename P> P GetStruct(voffset_t field) const { + auto field_offset = GetOptionalFieldOffset(field); + auto p = data_ + field_offset; + return extractValue<P>(p); + } + + bool CheckField(voffset_t field) const { + return GetOptionalFieldOffset(field) != 0; + } + + // Verify the vtable of this table. + // Call this once per table, followed by VerifyField once per field. + bool VerifyTableStart(Verifier<Iter> &verifier) const { + // Check the vtable offset. + if (!verifier.template Verify<soffset_t>(data_)) return false; + auto vtable = GetVTable(); + // Check the vtable size field, then check vtable fits in its entirety. + return verifier.VerifyComplexity() && + verifier.template Verify<voffset_t>(vtable) && + (ReadScalar<voffset_t>(vtable) & (sizeof(voffset_t) - 1)) == 0 && + verifier.Verify(vtable, ReadScalar<voffset_t>(vtable)); + } + + // Verify a particular field. + template<typename T> bool VerifyField(const Verifier<Iter> &verifier, + voffset_t field) const { + // Calling GetOptionalFieldOffset should be safe now thanks to + // VerifyTable(). + auto field_offset = GetOptionalFieldOffset(field); + // Check the actual field. + return !field_offset || verifier.template Verify<T>(data_ + field_offset); + } + + // VerifyField for required fields. + template<typename T> bool VerifyFieldRequired(const Verifier<Iter> &verifier, + voffset_t field) const { + auto field_offset = GetOptionalFieldOffset(field); + return verifier.Check(field_offset != 0) && + verifier.template Verify<T>(data_ + field_offset); + } + + private: + Iter data_; +}; +/// @endcond +} // namespace flatbuffers_iter +} // namespace maps +} // namespace yandex + +#endif // FLATBUFFERS_H_ diff --git a/contrib/libs/flatbuffers/include/flatbuffers/flatc.h b/contrib/libs/flatbuffers/include/flatbuffers/flatc.h new file mode 100644 index 0000000000..1466b3651d --- /dev/null +++ b/contrib/libs/flatbuffers/include/flatbuffers/flatc.h @@ -0,0 +1,100 @@ +/* + * Copyright 2017 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_FLATC_H_ +#define FLATBUFFERS_FLATC_H_ + +#include <functional> +#include <limits> +#include <string> + +#include "flatbuffers.h" +#include "idl.h" +#include "util.h" + +namespace flatbuffers { + +extern void LogCompilerWarn(const std::string &warn); +extern void LogCompilerError(const std::string &err); + +class FlatCompiler { + public: + // Output generator for the various programming languages and formats we + // support. + struct Generator { + typedef bool (*GenerateFn)(const flatbuffers::Parser &parser, + const std::string &path, + const std::string &file_name); + typedef std::string (*MakeRuleFn)(const flatbuffers::Parser &parser, + const std::string &path, + const std::string &file_name); + + GenerateFn generate; + const char *generator_opt_short; + const char *generator_opt_long; + const char *lang_name; + bool schema_only; + GenerateFn generateGRPC; + flatbuffers::IDLOptions::Language lang; + const char *generator_help; + MakeRuleFn make_rule; + }; + + typedef void (*WarnFn)(const FlatCompiler *flatc, const std::string &warn, + bool show_exe_name); + + typedef void (*ErrorFn)(const FlatCompiler *flatc, const std::string &err, + bool usage, bool show_exe_name); + + // Parameters required to initialize the FlatCompiler. + struct InitParams { + InitParams() + : generators(nullptr), + num_generators(0), + warn_fn(nullptr), + error_fn(nullptr) {} + + const Generator *generators; + size_t num_generators; + WarnFn warn_fn; + ErrorFn error_fn; + }; + + explicit FlatCompiler(const InitParams ¶ms) : params_(params) {} + + int Compile(int argc, const char **argv); + + std::string GetUsageString(const char *program_name) const; + + private: + void ParseFile(flatbuffers::Parser &parser, const std::string &filename, + const std::string &contents, + std::vector<const char *> &include_directories) const; + + void LoadBinarySchema(Parser &parser, const std::string &filename, + const std::string &contents); + + void Warn(const std::string &warn, bool show_exe_name = true) const; + + void Error(const std::string &err, bool usage = true, + bool show_exe_name = true) const; + + InitParams params_; +}; + +} // namespace flatbuffers + +#endif // FLATBUFFERS_FLATC_H_ diff --git a/contrib/libs/flatbuffers/include/flatbuffers/flexbuffers.h b/contrib/libs/flatbuffers/include/flatbuffers/flexbuffers.h new file mode 100644 index 0000000000..d855b67731 --- /dev/null +++ b/contrib/libs/flatbuffers/include/flatbuffers/flexbuffers.h @@ -0,0 +1,1636 @@ +/* + * Copyright 2017 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_FLEXBUFFERS_H_ +#define FLATBUFFERS_FLEXBUFFERS_H_ + +#include <map> +// Used to select STL variant. +#include "base.h" +// We use the basic binary writing functions from the regular FlatBuffers. +#include "util.h" + +#ifdef _MSC_VER +# include <intrin.h> +#endif + +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 4127) // C4127: conditional expression is constant +#endif + +namespace flexbuffers { + +class Reference; +class Map; + +// These are used in the lower 2 bits of a type field to determine the size of +// the elements (and or size field) of the item pointed to (e.g. vector). +enum BitWidth { + BIT_WIDTH_8 = 0, + BIT_WIDTH_16 = 1, + BIT_WIDTH_32 = 2, + BIT_WIDTH_64 = 3, +}; + +// These are used as the upper 6 bits of a type field to indicate the actual +// type. +enum Type { + FBT_NULL = 0, + FBT_INT = 1, + FBT_UINT = 2, + FBT_FLOAT = 3, + // Types above stored inline, types below store an offset. + FBT_KEY = 4, + FBT_STRING = 5, + FBT_INDIRECT_INT = 6, + FBT_INDIRECT_UINT = 7, + FBT_INDIRECT_FLOAT = 8, + FBT_MAP = 9, + FBT_VECTOR = 10, // Untyped. + FBT_VECTOR_INT = 11, // Typed any size (stores no type table). + FBT_VECTOR_UINT = 12, + FBT_VECTOR_FLOAT = 13, + FBT_VECTOR_KEY = 14, + // DEPRECATED, use FBT_VECTOR or FBT_VECTOR_KEY instead. + // Read test.cpp/FlexBuffersDeprecatedTest() for details on why. + FBT_VECTOR_STRING_DEPRECATED = 15, + FBT_VECTOR_INT2 = 16, // Typed tuple (no type table, no size field). + FBT_VECTOR_UINT2 = 17, + FBT_VECTOR_FLOAT2 = 18, + FBT_VECTOR_INT3 = 19, // Typed triple (no type table, no size field). + FBT_VECTOR_UINT3 = 20, + FBT_VECTOR_FLOAT3 = 21, + FBT_VECTOR_INT4 = 22, // Typed quad (no type table, no size field). + FBT_VECTOR_UINT4 = 23, + FBT_VECTOR_FLOAT4 = 24, + FBT_BLOB = 25, + FBT_BOOL = 26, + FBT_VECTOR_BOOL = + 36, // To Allow the same type of conversion of type to vector type +}; + +inline bool IsInline(Type t) { return t <= FBT_FLOAT || t == FBT_BOOL; } + +inline bool IsTypedVectorElementType(Type t) { + return (t >= FBT_INT && t <= FBT_STRING) || t == FBT_BOOL; +} + +inline bool IsTypedVector(Type t) { + return (t >= FBT_VECTOR_INT && t <= FBT_VECTOR_STRING_DEPRECATED) || + t == FBT_VECTOR_BOOL; +} + +inline bool IsFixedTypedVector(Type t) { + return t >= FBT_VECTOR_INT2 && t <= FBT_VECTOR_FLOAT4; +} + +inline Type ToTypedVector(Type t, size_t fixed_len = 0) { + FLATBUFFERS_ASSERT(IsTypedVectorElementType(t)); + switch (fixed_len) { + case 0: return static_cast<Type>(t - FBT_INT + FBT_VECTOR_INT); + case 2: return static_cast<Type>(t - FBT_INT + FBT_VECTOR_INT2); + case 3: return static_cast<Type>(t - FBT_INT + FBT_VECTOR_INT3); + case 4: return static_cast<Type>(t - FBT_INT + FBT_VECTOR_INT4); + default: FLATBUFFERS_ASSERT(0); return FBT_NULL; + } +} + +inline Type ToTypedVectorElementType(Type t) { + FLATBUFFERS_ASSERT(IsTypedVector(t)); + return static_cast<Type>(t - FBT_VECTOR_INT + FBT_INT); +} + +inline Type ToFixedTypedVectorElementType(Type t, uint8_t *len) { + FLATBUFFERS_ASSERT(IsFixedTypedVector(t)); + auto fixed_type = t - FBT_VECTOR_INT2; + *len = static_cast<uint8_t>(fixed_type / 3 + + 2); // 3 types each, starting from length 2. + return static_cast<Type>(fixed_type % 3 + FBT_INT); +} + +// TODO: implement proper support for 8/16bit floats, or decide not to +// support them. +typedef int16_t half; +typedef int8_t quarter; + +// TODO: can we do this without conditionals using intrinsics or inline asm +// on some platforms? Given branch prediction the method below should be +// decently quick, but it is the most frequently executed function. +// We could do an (unaligned) 64-bit read if we ifdef out the platforms for +// which that doesn't work (or where we'd read into un-owned memory). +template<typename R, typename T1, typename T2, typename T4, typename T8> +R ReadSizedScalar(const uint8_t *data, uint8_t byte_width) { + return byte_width < 4 + ? (byte_width < 2 + ? static_cast<R>(flatbuffers::ReadScalar<T1>(data)) + : static_cast<R>(flatbuffers::ReadScalar<T2>(data))) + : (byte_width < 8 + ? static_cast<R>(flatbuffers::ReadScalar<T4>(data)) + : static_cast<R>(flatbuffers::ReadScalar<T8>(data))); +} + +inline int64_t ReadInt64(const uint8_t *data, uint8_t byte_width) { + return ReadSizedScalar<int64_t, int8_t, int16_t, int32_t, int64_t>( + data, byte_width); +} + +inline uint64_t ReadUInt64(const uint8_t *data, uint8_t byte_width) { + // This is the "hottest" function (all offset lookups use this), so worth + // optimizing if possible. + // TODO: GCC apparently replaces memcpy by a rep movsb, but only if count is a + // constant, which here it isn't. Test if memcpy is still faster than + // the conditionals in ReadSizedScalar. Can also use inline asm. + // clang-format off + #if defined(_MSC_VER) && ((defined(_M_X64) && !defined(_M_ARM64EC)) || defined _M_IX86) + uint64_t u = 0; + __movsb(reinterpret_cast<uint8_t *>(&u), + reinterpret_cast<const uint8_t *>(data), byte_width); + return flatbuffers::EndianScalar(u); + #else + return ReadSizedScalar<uint64_t, uint8_t, uint16_t, uint32_t, uint64_t>( + data, byte_width); + #endif + // clang-format on +} + +inline double ReadDouble(const uint8_t *data, uint8_t byte_width) { + return ReadSizedScalar<double, quarter, half, float, double>(data, + byte_width); +} + +inline const uint8_t *Indirect(const uint8_t *offset, uint8_t byte_width) { + return offset - ReadUInt64(offset, byte_width); +} + +template<typename T> const uint8_t *Indirect(const uint8_t *offset) { + return offset - flatbuffers::ReadScalar<T>(offset); +} + +inline BitWidth WidthU(uint64_t u) { +#define FLATBUFFERS_GET_FIELD_BIT_WIDTH(value, width) \ + { \ + if (!((u) & ~((1ULL << (width)) - 1ULL))) return BIT_WIDTH_##width; \ + } + FLATBUFFERS_GET_FIELD_BIT_WIDTH(u, 8); + FLATBUFFERS_GET_FIELD_BIT_WIDTH(u, 16); + FLATBUFFERS_GET_FIELD_BIT_WIDTH(u, 32); +#undef FLATBUFFERS_GET_FIELD_BIT_WIDTH + return BIT_WIDTH_64; +} + +inline BitWidth WidthI(int64_t i) { + auto u = static_cast<uint64_t>(i) << 1; + return WidthU(i >= 0 ? u : ~u); +} + +inline BitWidth WidthF(double f) { + return static_cast<double>(static_cast<float>(f)) == f ? BIT_WIDTH_32 + : BIT_WIDTH_64; +} + +// Base class of all types below. +// Points into the data buffer and allows access to one type. +class Object { + public: + Object(const uint8_t *data, uint8_t byte_width) + : data_(data), byte_width_(byte_width) {} + + protected: + const uint8_t *data_; + uint8_t byte_width_; +}; + +// Object that has a size, obtained either from size prefix, or elsewhere. +class Sized : public Object { + public: + // Size prefix. + Sized(const uint8_t *data, uint8_t byte_width) + : Object(data, byte_width), size_(read_size()) {} + // Manual size. + Sized(const uint8_t *data, uint8_t byte_width, size_t sz) + : Object(data, byte_width), size_(sz) {} + size_t size() const { return size_; } + // Access size stored in `byte_width_` bytes before data_ pointer. + size_t read_size() const { + return static_cast<size_t>(ReadUInt64(data_ - byte_width_, byte_width_)); + } + + protected: + size_t size_; +}; + +class String : public Sized { + public: + // Size prefix. + String(const uint8_t *data, uint8_t byte_width) : Sized(data, byte_width) {} + // Manual size. + String(const uint8_t *data, uint8_t byte_width, size_t sz) + : Sized(data, byte_width, sz) {} + + size_t length() const { return size(); } + const char *c_str() const { return reinterpret_cast<const char *>(data_); } + std::string str() const { return std::string(c_str(), size()); } + + static String EmptyString() { + static const char *empty_string = ""; + return String(reinterpret_cast<const uint8_t *>(empty_string), 1, 0); + } + bool IsTheEmptyString() const { return data_ == EmptyString().data_; } +}; + +class Blob : public Sized { + public: + Blob(const uint8_t *data_buf, uint8_t byte_width) + : Sized(data_buf, byte_width) {} + + static Blob EmptyBlob() { + static const uint8_t empty_blob[] = { 0 /*len*/ }; + return Blob(empty_blob + 1, 1); + } + bool IsTheEmptyBlob() const { return data_ == EmptyBlob().data_; } + const uint8_t *data() const { return data_; } +}; + +class Vector : public Sized { + public: + Vector(const uint8_t *data, uint8_t byte_width) : Sized(data, byte_width) {} + + Reference operator[](size_t i) const; + + static Vector EmptyVector() { + static const uint8_t empty_vector[] = { 0 /*len*/ }; + return Vector(empty_vector + 1, 1); + } + bool IsTheEmptyVector() const { return data_ == EmptyVector().data_; } +}; + +class TypedVector : public Sized { + public: + TypedVector(const uint8_t *data, uint8_t byte_width, Type element_type) + : Sized(data, byte_width), type_(element_type) {} + + Reference operator[](size_t i) const; + + static TypedVector EmptyTypedVector() { + static const uint8_t empty_typed_vector[] = { 0 /*len*/ }; + return TypedVector(empty_typed_vector + 1, 1, FBT_INT); + } + bool IsTheEmptyVector() const { + return data_ == TypedVector::EmptyTypedVector().data_; + } + + Type ElementType() { return type_; } + + friend Reference; + + private: + Type type_; + + friend Map; +}; + +class FixedTypedVector : public Object { + public: + FixedTypedVector(const uint8_t *data, uint8_t byte_width, Type element_type, + uint8_t len) + : Object(data, byte_width), type_(element_type), len_(len) {} + + Reference operator[](size_t i) const; + + static FixedTypedVector EmptyFixedTypedVector() { + static const uint8_t fixed_empty_vector[] = { 0 /* unused */ }; + return FixedTypedVector(fixed_empty_vector, 1, FBT_INT, 0); + } + bool IsTheEmptyFixedTypedVector() const { + return data_ == FixedTypedVector::EmptyFixedTypedVector().data_; + } + + Type ElementType() { return type_; } + uint8_t size() { return len_; } + + private: + Type type_; + uint8_t len_; +}; + +class Map : public Vector { + public: + Map(const uint8_t *data, uint8_t byte_width) : Vector(data, byte_width) {} + + Reference operator[](const char *key) const; + Reference operator[](const std::string &key) const; + + Vector Values() const { return Vector(data_, byte_width_); } + + TypedVector Keys() const { + const size_t num_prefixed_fields = 3; + auto keys_offset = data_ - byte_width_ * num_prefixed_fields; + return TypedVector(Indirect(keys_offset, byte_width_), + static_cast<uint8_t>( + ReadUInt64(keys_offset + byte_width_, byte_width_)), + FBT_KEY); + } + + static Map EmptyMap() { + static const uint8_t empty_map[] = { + 0 /*keys_len*/, 0 /*keys_offset*/, 1 /*keys_width*/, 0 /*len*/ + }; + return Map(empty_map + 4, 1); + } + + bool IsTheEmptyMap() const { return data_ == EmptyMap().data_; } +}; + +template<typename T> +void AppendToString(std::string &s, T &&v, bool keys_quoted) { + s += "[ "; + for (size_t i = 0; i < v.size(); i++) { + if (i) s += ", "; + v[i].ToString(true, keys_quoted, s); + } + s += " ]"; +} + +class Reference { + public: + Reference() + : data_(nullptr), + parent_width_(0), + byte_width_(BIT_WIDTH_8), + type_(FBT_NULL) {} + + Reference(const uint8_t *data, uint8_t parent_width, uint8_t byte_width, + Type type) + : data_(data), + parent_width_(parent_width), + byte_width_(byte_width), + type_(type) {} + + Reference(const uint8_t *data, uint8_t parent_width, uint8_t packed_type) + : data_(data), parent_width_(parent_width) { + byte_width_ = 1U << static_cast<BitWidth>(packed_type & 3); + type_ = static_cast<Type>(packed_type >> 2); + } + + Type GetType() const { return type_; } + + bool IsNull() const { return type_ == FBT_NULL; } + bool IsBool() const { return type_ == FBT_BOOL; } + bool IsInt() const { return type_ == FBT_INT || type_ == FBT_INDIRECT_INT; } + bool IsUInt() const { + return type_ == FBT_UINT || type_ == FBT_INDIRECT_UINT; + } + bool IsIntOrUint() const { return IsInt() || IsUInt(); } + bool IsFloat() const { + return type_ == FBT_FLOAT || type_ == FBT_INDIRECT_FLOAT; + } + bool IsNumeric() const { return IsIntOrUint() || IsFloat(); } + bool IsString() const { return type_ == FBT_STRING; } + bool IsKey() const { return type_ == FBT_KEY; } + bool IsVector() const { return type_ == FBT_VECTOR || type_ == FBT_MAP; } + bool IsUntypedVector() const { return type_ == FBT_VECTOR; } + bool IsTypedVector() const { return flexbuffers::IsTypedVector(type_); } + bool IsFixedTypedVector() const { + return flexbuffers::IsFixedTypedVector(type_); + } + bool IsAnyVector() const { + return (IsTypedVector() || IsFixedTypedVector() || IsVector()); + } + bool IsMap() const { return type_ == FBT_MAP; } + bool IsBlob() const { return type_ == FBT_BLOB; } + bool AsBool() const { + return (type_ == FBT_BOOL ? ReadUInt64(data_, parent_width_) + : AsUInt64()) != 0; + } + + // Reads any type as a int64_t. Never fails, does most sensible conversion. + // Truncates floats, strings are attempted to be parsed for a number, + // vectors/maps return their size. Returns 0 if all else fails. + int64_t AsInt64() const { + if (type_ == FBT_INT) { + // A fast path for the common case. + return ReadInt64(data_, parent_width_); + } else + switch (type_) { + case FBT_INDIRECT_INT: return ReadInt64(Indirect(), byte_width_); + case FBT_UINT: return ReadUInt64(data_, parent_width_); + case FBT_INDIRECT_UINT: return ReadUInt64(Indirect(), byte_width_); + case FBT_FLOAT: + return static_cast<int64_t>(ReadDouble(data_, parent_width_)); + case FBT_INDIRECT_FLOAT: + return static_cast<int64_t>(ReadDouble(Indirect(), byte_width_)); + case FBT_NULL: return 0; + case FBT_STRING: return flatbuffers::StringToInt(AsString().c_str()); + case FBT_VECTOR: return static_cast<int64_t>(AsVector().size()); + case FBT_BOOL: return ReadInt64(data_, parent_width_); + default: + // Convert other things to int. + return 0; + } + } + + // TODO: could specialize these to not use AsInt64() if that saves + // extension ops in generated code, and use a faster op than ReadInt64. + int32_t AsInt32() const { return static_cast<int32_t>(AsInt64()); } + int16_t AsInt16() const { return static_cast<int16_t>(AsInt64()); } + int8_t AsInt8() const { return static_cast<int8_t>(AsInt64()); } + + uint64_t AsUInt64() const { + if (type_ == FBT_UINT) { + // A fast path for the common case. + return ReadUInt64(data_, parent_width_); + } else + switch (type_) { + case FBT_INDIRECT_UINT: return ReadUInt64(Indirect(), byte_width_); + case FBT_INT: return ReadInt64(data_, parent_width_); + case FBT_INDIRECT_INT: return ReadInt64(Indirect(), byte_width_); + case FBT_FLOAT: + return static_cast<uint64_t>(ReadDouble(data_, parent_width_)); + case FBT_INDIRECT_FLOAT: + return static_cast<uint64_t>(ReadDouble(Indirect(), byte_width_)); + case FBT_NULL: return 0; + case FBT_STRING: return flatbuffers::StringToUInt(AsString().c_str()); + case FBT_VECTOR: return static_cast<uint64_t>(AsVector().size()); + case FBT_BOOL: return ReadUInt64(data_, parent_width_); + default: + // Convert other things to uint. + return 0; + } + } + + uint32_t AsUInt32() const { return static_cast<uint32_t>(AsUInt64()); } + uint16_t AsUInt16() const { return static_cast<uint16_t>(AsUInt64()); } + uint8_t AsUInt8() const { return static_cast<uint8_t>(AsUInt64()); } + + double AsDouble() const { + if (type_ == FBT_FLOAT) { + // A fast path for the common case. + return ReadDouble(data_, parent_width_); + } else + switch (type_) { + case FBT_INDIRECT_FLOAT: return ReadDouble(Indirect(), byte_width_); + case FBT_INT: + return static_cast<double>(ReadInt64(data_, parent_width_)); + case FBT_UINT: + return static_cast<double>(ReadUInt64(data_, parent_width_)); + case FBT_INDIRECT_INT: + return static_cast<double>(ReadInt64(Indirect(), byte_width_)); + case FBT_INDIRECT_UINT: + return static_cast<double>(ReadUInt64(Indirect(), byte_width_)); + case FBT_NULL: return 0.0; + case FBT_STRING: { + double d; + flatbuffers::StringToNumber(AsString().c_str(), &d); + return d; + } + case FBT_VECTOR: return static_cast<double>(AsVector().size()); + case FBT_BOOL: + return static_cast<double>(ReadUInt64(data_, parent_width_)); + default: + // Convert strings and other things to float. + return 0; + } + } + + float AsFloat() const { return static_cast<float>(AsDouble()); } + + const char *AsKey() const { + if (type_ == FBT_KEY || type_ == FBT_STRING) { + return reinterpret_cast<const char *>(Indirect()); + } else { + return ""; + } + } + + // This function returns the empty string if you try to read something that + // is not a string or key. + String AsString() const { + if (type_ == FBT_STRING) { + return String(Indirect(), byte_width_); + } else if (type_ == FBT_KEY) { + auto key = Indirect(); + return String(key, byte_width_, + strlen(reinterpret_cast<const char *>(key))); + } else { + return String::EmptyString(); + } + } + + // Unlike AsString(), this will convert any type to a std::string. + std::string ToString() const { + std::string s; + ToString(false, false, s); + return s; + } + + // Convert any type to a JSON-like string. strings_quoted determines if + // string values at the top level receive "" quotes (inside other values + // they always do). keys_quoted determines if keys are quoted, at any level. + // TODO(wvo): add further options to have indentation/newlines. + void ToString(bool strings_quoted, bool keys_quoted, std::string &s) const { + if (type_ == FBT_STRING) { + String str(Indirect(), byte_width_); + if (strings_quoted) { + flatbuffers::EscapeString(str.c_str(), str.length(), &s, true, false); + } else { + s.append(str.c_str(), str.length()); + } + } else if (IsKey()) { + auto str = AsKey(); + if (keys_quoted) { + flatbuffers::EscapeString(str, strlen(str), &s, true, false); + } else { + s += str; + } + } else if (IsInt()) { + s += flatbuffers::NumToString(AsInt64()); + } else if (IsUInt()) { + s += flatbuffers::NumToString(AsUInt64()); + } else if (IsFloat()) { + s += flatbuffers::NumToString(AsDouble()); + } else if (IsNull()) { + s += "null"; + } else if (IsBool()) { + s += AsBool() ? "true" : "false"; + } else if (IsMap()) { + s += "{ "; + auto m = AsMap(); + auto keys = m.Keys(); + auto vals = m.Values(); + for (size_t i = 0; i < keys.size(); i++) { + keys[i].ToString(true, keys_quoted, s); + s += ": "; + vals[i].ToString(true, keys_quoted, s); + if (i < keys.size() - 1) s += ", "; + } + s += " }"; + } else if (IsVector()) { + AppendToString<Vector>(s, AsVector(), keys_quoted); + } else if (IsTypedVector()) { + AppendToString<TypedVector>(s, AsTypedVector(), keys_quoted); + } else if (IsFixedTypedVector()) { + AppendToString<FixedTypedVector>(s, AsFixedTypedVector(), keys_quoted); + } else if (IsBlob()) { + auto blob = AsBlob(); + flatbuffers::EscapeString(reinterpret_cast<const char *>(blob.data()), + blob.size(), &s, true, false); + } else { + s += "(?)"; + } + } + + // This function returns the empty blob if you try to read a not-blob. + // Strings can be viewed as blobs too. + Blob AsBlob() const { + if (type_ == FBT_BLOB || type_ == FBT_STRING) { + return Blob(Indirect(), byte_width_); + } else { + return Blob::EmptyBlob(); + } + } + + // This function returns the empty vector if you try to read a not-vector. + // Maps can be viewed as vectors too. + Vector AsVector() const { + if (type_ == FBT_VECTOR || type_ == FBT_MAP) { + return Vector(Indirect(), byte_width_); + } else { + return Vector::EmptyVector(); + } + } + + TypedVector AsTypedVector() const { + if (IsTypedVector()) { + auto tv = + TypedVector(Indirect(), byte_width_, ToTypedVectorElementType(type_)); + if (tv.type_ == FBT_STRING) { + // These can't be accessed as strings, since we don't know the bit-width + // of the size field, see the declaration of + // FBT_VECTOR_STRING_DEPRECATED above for details. + // We change the type here to be keys, which are a subtype of strings, + // and will ignore the size field. This will truncate strings with + // embedded nulls. + tv.type_ = FBT_KEY; + } + return tv; + } else { + return TypedVector::EmptyTypedVector(); + } + } + + FixedTypedVector AsFixedTypedVector() const { + if (IsFixedTypedVector()) { + uint8_t len = 0; + auto vtype = ToFixedTypedVectorElementType(type_, &len); + return FixedTypedVector(Indirect(), byte_width_, vtype, len); + } else { + return FixedTypedVector::EmptyFixedTypedVector(); + } + } + + Map AsMap() const { + if (type_ == FBT_MAP) { + return Map(Indirect(), byte_width_); + } else { + return Map::EmptyMap(); + } + } + + template<typename T> T As() const; + + // Experimental: Mutation functions. + // These allow scalars in an already created buffer to be updated in-place. + // Since by default scalars are stored in the smallest possible space, + // the new value may not fit, in which case these functions return false. + // To avoid this, you can construct the values you intend to mutate using + // Builder::ForceMinimumBitWidth. + bool MutateInt(int64_t i) { + if (type_ == FBT_INT) { + return Mutate(data_, i, parent_width_, WidthI(i)); + } else if (type_ == FBT_INDIRECT_INT) { + return Mutate(Indirect(), i, byte_width_, WidthI(i)); + } else if (type_ == FBT_UINT) { + auto u = static_cast<uint64_t>(i); + return Mutate(data_, u, parent_width_, WidthU(u)); + } else if (type_ == FBT_INDIRECT_UINT) { + auto u = static_cast<uint64_t>(i); + return Mutate(Indirect(), u, byte_width_, WidthU(u)); + } else { + return false; + } + } + + bool MutateBool(bool b) { + return type_ == FBT_BOOL && Mutate(data_, b, parent_width_, BIT_WIDTH_8); + } + + bool MutateUInt(uint64_t u) { + if (type_ == FBT_UINT) { + return Mutate(data_, u, parent_width_, WidthU(u)); + } else if (type_ == FBT_INDIRECT_UINT) { + return Mutate(Indirect(), u, byte_width_, WidthU(u)); + } else if (type_ == FBT_INT) { + auto i = static_cast<int64_t>(u); + return Mutate(data_, i, parent_width_, WidthI(i)); + } else if (type_ == FBT_INDIRECT_INT) { + auto i = static_cast<int64_t>(u); + return Mutate(Indirect(), i, byte_width_, WidthI(i)); + } else { + return false; + } + } + + bool MutateFloat(float f) { + if (type_ == FBT_FLOAT) { + return MutateF(data_, f, parent_width_, BIT_WIDTH_32); + } else if (type_ == FBT_INDIRECT_FLOAT) { + return MutateF(Indirect(), f, byte_width_, BIT_WIDTH_32); + } else { + return false; + } + } + + bool MutateFloat(double d) { + if (type_ == FBT_FLOAT) { + return MutateF(data_, d, parent_width_, WidthF(d)); + } else if (type_ == FBT_INDIRECT_FLOAT) { + return MutateF(Indirect(), d, byte_width_, WidthF(d)); + } else { + return false; + } + } + + bool MutateString(const char *str, size_t len) { + auto s = AsString(); + if (s.IsTheEmptyString()) return false; + // This is very strict, could allow shorter strings, but that creates + // garbage. + if (s.length() != len) return false; + memcpy(const_cast<char *>(s.c_str()), str, len); + return true; + } + bool MutateString(const char *str) { return MutateString(str, strlen(str)); } + bool MutateString(const std::string &str) { + return MutateString(str.data(), str.length()); + } + + private: + const uint8_t *Indirect() const { + return flexbuffers::Indirect(data_, parent_width_); + } + + template<typename T> + bool Mutate(const uint8_t *dest, T t, size_t byte_width, + BitWidth value_width) { + auto fits = static_cast<size_t>(static_cast<size_t>(1U) << value_width) <= + byte_width; + if (fits) { + t = flatbuffers::EndianScalar(t); + memcpy(const_cast<uint8_t *>(dest), &t, byte_width); + } + return fits; + } + + template<typename T> + bool MutateF(const uint8_t *dest, T t, size_t byte_width, + BitWidth value_width) { + if (byte_width == sizeof(double)) + return Mutate(dest, static_cast<double>(t), byte_width, value_width); + if (byte_width == sizeof(float)) + return Mutate(dest, static_cast<float>(t), byte_width, value_width); + FLATBUFFERS_ASSERT(false); + return false; + } + + const uint8_t *data_; + uint8_t parent_width_; + uint8_t byte_width_; + Type type_; +}; + +// Template specialization for As(). +template<> inline bool Reference::As<bool>() const { return AsBool(); } + +template<> inline int8_t Reference::As<int8_t>() const { return AsInt8(); } +template<> inline int16_t Reference::As<int16_t>() const { return AsInt16(); } +template<> inline int32_t Reference::As<int32_t>() const { return AsInt32(); } +template<> inline int64_t Reference::As<int64_t>() const { return AsInt64(); } + +template<> inline uint8_t Reference::As<uint8_t>() const { return AsUInt8(); } +template<> inline uint16_t Reference::As<uint16_t>() const { + return AsUInt16(); +} +template<> inline uint32_t Reference::As<uint32_t>() const { + return AsUInt32(); +} +template<> inline uint64_t Reference::As<uint64_t>() const { + return AsUInt64(); +} + +template<> inline double Reference::As<double>() const { return AsDouble(); } +template<> inline float Reference::As<float>() const { return AsFloat(); } + +template<> inline String Reference::As<String>() const { return AsString(); } +template<> inline std::string Reference::As<std::string>() const { + return AsString().str(); +} + +template<> inline Blob Reference::As<Blob>() const { return AsBlob(); } +template<> inline Vector Reference::As<Vector>() const { return AsVector(); } +template<> inline TypedVector Reference::As<TypedVector>() const { + return AsTypedVector(); +} +template<> inline FixedTypedVector Reference::As<FixedTypedVector>() const { + return AsFixedTypedVector(); +} +template<> inline Map Reference::As<Map>() const { return AsMap(); } + +inline uint8_t PackedType(BitWidth bit_width, Type type) { + return static_cast<uint8_t>(bit_width | (type << 2)); +} + +inline uint8_t NullPackedType() { return PackedType(BIT_WIDTH_8, FBT_NULL); } + +// Vector accessors. +// Note: if you try to access outside of bounds, you get a Null value back +// instead. Normally this would be an assert, but since this is "dynamically +// typed" data, you may not want that (someone sends you a 2d vector and you +// wanted 3d). +// The Null converts seamlessly into a default value for any other type. +// TODO(wvo): Could introduce an #ifdef that makes this into an assert? +inline Reference Vector::operator[](size_t i) const { + auto len = size(); + if (i >= len) return Reference(nullptr, 1, NullPackedType()); + auto packed_type = (data_ + len * byte_width_)[i]; + auto elem = data_ + i * byte_width_; + return Reference(elem, byte_width_, packed_type); +} + +inline Reference TypedVector::operator[](size_t i) const { + auto len = size(); + if (i >= len) return Reference(nullptr, 1, NullPackedType()); + auto elem = data_ + i * byte_width_; + return Reference(elem, byte_width_, 1, type_); +} + +inline Reference FixedTypedVector::operator[](size_t i) const { + if (i >= len_) return Reference(nullptr, 1, NullPackedType()); + auto elem = data_ + i * byte_width_; + return Reference(elem, byte_width_, 1, type_); +} + +template<typename T> int KeyCompare(const void *key, const void *elem) { + auto str_elem = reinterpret_cast<const char *>( + Indirect<T>(reinterpret_cast<const uint8_t *>(elem))); + auto skey = reinterpret_cast<const char *>(key); + return strcmp(skey, str_elem); +} + +inline Reference Map::operator[](const char *key) const { + auto keys = Keys(); + // We can't pass keys.byte_width_ to the comparison function, so we have + // to pick the right one ahead of time. + int (*comp)(const void *, const void *) = nullptr; + switch (keys.byte_width_) { + case 1: comp = KeyCompare<uint8_t>; break; + case 2: comp = KeyCompare<uint16_t>; break; + case 4: comp = KeyCompare<uint32_t>; break; + case 8: comp = KeyCompare<uint64_t>; break; + } + auto res = std::bsearch(key, keys.data_, keys.size(), keys.byte_width_, comp); + if (!res) return Reference(nullptr, 1, NullPackedType()); + auto i = (reinterpret_cast<uint8_t *>(res) - keys.data_) / keys.byte_width_; + return (*static_cast<const Vector *>(this))[i]; +} + +inline Reference Map::operator[](const std::string &key) const { + return (*this)[key.c_str()]; +} + +inline Reference GetRoot(const uint8_t *buffer, size_t size) { + // See Finish() below for the serialization counterpart of this. + // The root starts at the end of the buffer, so we parse backwards from there. + auto end = buffer + size; + auto byte_width = *--end; + auto packed_type = *--end; + end -= byte_width; // The root data item. + return Reference(end, byte_width, packed_type); +} + +inline Reference GetRoot(const std::vector<uint8_t> &buffer) { + return GetRoot(flatbuffers::vector_data(buffer), buffer.size()); +} + +// Flags that configure how the Builder behaves. +// The "Share" flags determine if the Builder automatically tries to pool +// this type. Pooling can reduce the size of serialized data if there are +// multiple maps of the same kind, at the expense of slightly slower +// serialization (the cost of lookups) and more memory use (std::set). +// By default this is on for keys, but off for strings. +// Turn keys off if you have e.g. only one map. +// Turn strings on if you expect many non-unique string values. +// Additionally, sharing key vectors can save space if you have maps with +// identical field populations. +enum BuilderFlag { + BUILDER_FLAG_NONE = 0, + BUILDER_FLAG_SHARE_KEYS = 1, + BUILDER_FLAG_SHARE_STRINGS = 2, + BUILDER_FLAG_SHARE_KEYS_AND_STRINGS = 3, + BUILDER_FLAG_SHARE_KEY_VECTORS = 4, + BUILDER_FLAG_SHARE_ALL = 7, +}; + +class Builder FLATBUFFERS_FINAL_CLASS { + public: + Builder(size_t initial_size = 256, + BuilderFlag flags = BUILDER_FLAG_SHARE_KEYS) + : buf_(initial_size), + finished_(false), + has_duplicate_keys_(false), + flags_(flags), + force_min_bit_width_(BIT_WIDTH_8), + key_pool(KeyOffsetCompare(buf_)), + string_pool(StringOffsetCompare(buf_)) { + buf_.clear(); + } + +#ifdef FLATBUFFERS_DEFAULT_DECLARATION + Builder(Builder &&) = default; + Builder &operator=(Builder &&) = default; +#endif + + /// @brief Get the serialized buffer (after you call `Finish()`). + /// @return Returns a vector owned by this class. + const std::vector<uint8_t> &GetBuffer() const { + Finished(); + return buf_; + } + + // Size of the buffer. Does not include unfinished values. + size_t GetSize() const { return buf_.size(); } + + // Reset all state so we can re-use the buffer. + void Clear() { + buf_.clear(); + stack_.clear(); + finished_ = false; + // flags_ remains as-is; + force_min_bit_width_ = BIT_WIDTH_8; + key_pool.clear(); + string_pool.clear(); + } + + // All value constructing functions below have two versions: one that + // takes a key (for placement inside a map) and one that doesn't (for inside + // vectors and elsewhere). + + void Null() { stack_.push_back(Value()); } + void Null(const char *key) { + Key(key); + Null(); + } + + void Int(int64_t i) { stack_.push_back(Value(i, FBT_INT, WidthI(i))); } + void Int(const char *key, int64_t i) { + Key(key); + Int(i); + } + + void UInt(uint64_t u) { stack_.push_back(Value(u, FBT_UINT, WidthU(u))); } + void UInt(const char *key, uint64_t u) { + Key(key); + UInt(u); + } + + void Float(float f) { stack_.push_back(Value(f)); } + void Float(const char *key, float f) { + Key(key); + Float(f); + } + + void Double(double f) { stack_.push_back(Value(f)); } + void Double(const char *key, double d) { + Key(key); + Double(d); + } + + void Bool(bool b) { stack_.push_back(Value(b)); } + void Bool(const char *key, bool b) { + Key(key); + Bool(b); + } + + void IndirectInt(int64_t i) { PushIndirect(i, FBT_INDIRECT_INT, WidthI(i)); } + void IndirectInt(const char *key, int64_t i) { + Key(key); + IndirectInt(i); + } + + void IndirectUInt(uint64_t u) { + PushIndirect(u, FBT_INDIRECT_UINT, WidthU(u)); + } + void IndirectUInt(const char *key, uint64_t u) { + Key(key); + IndirectUInt(u); + } + + void IndirectFloat(float f) { + PushIndirect(f, FBT_INDIRECT_FLOAT, BIT_WIDTH_32); + } + void IndirectFloat(const char *key, float f) { + Key(key); + IndirectFloat(f); + } + + void IndirectDouble(double f) { + PushIndirect(f, FBT_INDIRECT_FLOAT, WidthF(f)); + } + void IndirectDouble(const char *key, double d) { + Key(key); + IndirectDouble(d); + } + + size_t Key(const char *str, size_t len) { + auto sloc = buf_.size(); + WriteBytes(str, len + 1); + if (flags_ & BUILDER_FLAG_SHARE_KEYS) { + auto it = key_pool.find(sloc); + if (it != key_pool.end()) { + // Already in the buffer. Remove key we just serialized, and use + // existing offset instead. + buf_.resize(sloc); + sloc = *it; + } else { + key_pool.insert(sloc); + } + } + stack_.push_back(Value(static_cast<uint64_t>(sloc), FBT_KEY, BIT_WIDTH_8)); + return sloc; + } + + size_t Key(const char *str) { return Key(str, strlen(str)); } + size_t Key(const std::string &str) { return Key(str.c_str(), str.size()); } + + size_t String(const char *str, size_t len) { + auto reset_to = buf_.size(); + auto sloc = CreateBlob(str, len, 1, FBT_STRING); + if (flags_ & BUILDER_FLAG_SHARE_STRINGS) { + StringOffset so(sloc, len); + auto it = string_pool.find(so); + if (it != string_pool.end()) { + // Already in the buffer. Remove string we just serialized, and use + // existing offset instead. + buf_.resize(reset_to); + sloc = it->first; + stack_.back().u_ = sloc; + } else { + string_pool.insert(so); + } + } + return sloc; + } + size_t String(const char *str) { return String(str, strlen(str)); } + size_t String(const std::string &str) { + return String(str.c_str(), str.size()); + } + void String(const flexbuffers::String &str) { + String(str.c_str(), str.length()); + } + + void String(const char *key, const char *str) { + Key(key); + String(str); + } + void String(const char *key, const std::string &str) { + Key(key); + String(str); + } + void String(const char *key, const flexbuffers::String &str) { + Key(key); + String(str); + } + + size_t Blob(const void *data, size_t len) { + return CreateBlob(data, len, 0, FBT_BLOB); + } + size_t Blob(const std::vector<uint8_t> &v) { + return CreateBlob(flatbuffers::vector_data(v), v.size(), 0, FBT_BLOB); + } + + // TODO(wvo): support all the FlexBuffer types (like flexbuffers::String), + // e.g. Vector etc. Also in overloaded versions. + // Also some FlatBuffers types? + + size_t StartVector() { return stack_.size(); } + size_t StartVector(const char *key) { + Key(key); + return stack_.size(); + } + size_t StartMap() { return stack_.size(); } + size_t StartMap(const char *key) { + Key(key); + return stack_.size(); + } + + // TODO(wvo): allow this to specify an aligment greater than the natural + // alignment. + size_t EndVector(size_t start, bool typed, bool fixed) { + auto vec = CreateVector(start, stack_.size() - start, 1, typed, fixed); + // Remove temp elements and return vector. + stack_.resize(start); + stack_.push_back(vec); + return static_cast<size_t>(vec.u_); + } + + size_t EndMap(size_t start) { + // We should have interleaved keys and values on the stack. + // Make sure it is an even number: + auto len = stack_.size() - start; + FLATBUFFERS_ASSERT(!(len & 1)); + len /= 2; + // Make sure keys are all strings: + for (auto key = start; key < stack_.size(); key += 2) { + FLATBUFFERS_ASSERT(stack_[key].type_ == FBT_KEY); + } + // Now sort values, so later we can do a binary search lookup. + // We want to sort 2 array elements at a time. + struct TwoValue { + Value key; + Value val; + }; + // TODO(wvo): strict aliasing? + // TODO(wvo): allow the caller to indicate the data is already sorted + // for maximum efficiency? With an assert to check sortedness to make sure + // we're not breaking binary search. + // Or, we can track if the map is sorted as keys are added which would be + // be quite cheap (cheaper than checking it here), so we can skip this + // step automatically when appliccable, and encourage people to write in + // sorted fashion. + // std::sort is typically already a lot faster on sorted data though. + auto dict = + reinterpret_cast<TwoValue *>(flatbuffers::vector_data(stack_) + start); + std::sort(dict, dict + len, + [&](const TwoValue &a, const TwoValue &b) -> bool { + auto as = reinterpret_cast<const char *>( + flatbuffers::vector_data(buf_) + a.key.u_); + auto bs = reinterpret_cast<const char *>( + flatbuffers::vector_data(buf_) + b.key.u_); + auto comp = strcmp(as, bs); + // We want to disallow duplicate keys, since this results in a + // map where values cannot be found. + // But we can't assert here (since we don't want to fail on + // random JSON input) or have an error mechanism. + // Instead, we set has_duplicate_keys_ in the builder to + // signal this. + // TODO: Have to check for pointer equality, as some sort + // implementation apparently call this function with the same + // element?? Why? + if (!comp && &a != &b) has_duplicate_keys_ = true; + return comp < 0; + }); + // First create a vector out of all keys. + // TODO(wvo): if kBuilderFlagShareKeyVectors is true, see if we can share + // the first vector. + auto keys = CreateVector(start, len, 2, true, false); + auto vec = CreateVector(start + 1, len, 2, false, false, &keys); + // Remove temp elements and return map. + stack_.resize(start); + stack_.push_back(vec); + return static_cast<size_t>(vec.u_); + } + + // Call this after EndMap to see if the map had any duplicate keys. + // Any map with such keys won't be able to retrieve all values. + bool HasDuplicateKeys() const { return has_duplicate_keys_; } + + template<typename F> size_t Vector(F f) { + auto start = StartVector(); + f(); + return EndVector(start, false, false); + } + template<typename F, typename T> size_t Vector(F f, T &state) { + auto start = StartVector(); + f(state); + return EndVector(start, false, false); + } + template<typename F> size_t Vector(const char *key, F f) { + auto start = StartVector(key); + f(); + return EndVector(start, false, false); + } + template<typename F, typename T> + size_t Vector(const char *key, F f, T &state) { + auto start = StartVector(key); + f(state); + return EndVector(start, false, false); + } + + template<typename T> void Vector(const T *elems, size_t len) { + if (flatbuffers::is_scalar<T>::value) { + // This path should be a lot quicker and use less space. + ScalarVector(elems, len, false); + } else { + auto start = StartVector(); + for (size_t i = 0; i < len; i++) Add(elems[i]); + EndVector(start, false, false); + } + } + template<typename T> + void Vector(const char *key, const T *elems, size_t len) { + Key(key); + Vector(elems, len); + } + template<typename T> void Vector(const std::vector<T> &vec) { + Vector(flatbuffers::vector_data(vec), vec.size()); + } + + template<typename F> size_t TypedVector(F f) { + auto start = StartVector(); + f(); + return EndVector(start, true, false); + } + template<typename F, typename T> size_t TypedVector(F f, T &state) { + auto start = StartVector(); + f(state); + return EndVector(start, true, false); + } + template<typename F> size_t TypedVector(const char *key, F f) { + auto start = StartVector(key); + f(); + return EndVector(start, true, false); + } + template<typename F, typename T> + size_t TypedVector(const char *key, F f, T &state) { + auto start = StartVector(key); + f(state); + return EndVector(start, true, false); + } + + template<typename T> size_t FixedTypedVector(const T *elems, size_t len) { + // We only support a few fixed vector lengths. Anything bigger use a + // regular typed vector. + FLATBUFFERS_ASSERT(len >= 2 && len <= 4); + // And only scalar values. + static_assert(flatbuffers::is_scalar<T>::value, "Unrelated types"); + return ScalarVector(elems, len, true); + } + + template<typename T> + size_t FixedTypedVector(const char *key, const T *elems, size_t len) { + Key(key); + return FixedTypedVector(elems, len); + } + + template<typename F> size_t Map(F f) { + auto start = StartMap(); + f(); + return EndMap(start); + } + template<typename F, typename T> size_t Map(F f, T &state) { + auto start = StartMap(); + f(state); + return EndMap(start); + } + template<typename F> size_t Map(const char *key, F f) { + auto start = StartMap(key); + f(); + return EndMap(start); + } + template<typename F, typename T> size_t Map(const char *key, F f, T &state) { + auto start = StartMap(key); + f(state); + return EndMap(start); + } + template<typename T> void Map(const std::map<std::string, T> &map) { + auto start = StartMap(); + for (auto it = map.begin(); it != map.end(); ++it) + Add(it->first.c_str(), it->second); + EndMap(start); + } + + // If you wish to share a value explicitly (a value not shared automatically + // through one of the BUILDER_FLAG_SHARE_* flags) you can do so with these + // functions. Or if you wish to turn those flags off for performance reasons + // and still do some explicit sharing. For example: + // builder.IndirectDouble(M_PI); + // auto id = builder.LastValue(); // Remember where we stored it. + // .. more code goes here .. + // builder.ReuseValue(id); // Refers to same double by offset. + // LastValue works regardless of whether the value has a key or not. + // Works on any data type. + struct Value; + Value LastValue() { return stack_.back(); } + void ReuseValue(Value v) { stack_.push_back(v); } + void ReuseValue(const char *key, Value v) { + Key(key); + ReuseValue(v); + } + + // Overloaded Add that tries to call the correct function above. + void Add(int8_t i) { Int(i); } + void Add(int16_t i) { Int(i); } + void Add(int32_t i) { Int(i); } + void Add(int64_t i) { Int(i); } + void Add(uint8_t u) { UInt(u); } + void Add(uint16_t u) { UInt(u); } + void Add(uint32_t u) { UInt(u); } + void Add(uint64_t u) { UInt(u); } + void Add(float f) { Float(f); } + void Add(double d) { Double(d); } + void Add(bool b) { Bool(b); } + void Add(const char *str) { String(str); } + void Add(const std::string &str) { String(str); } + void Add(const flexbuffers::String &str) { String(str); } + + template<typename T> void Add(const std::vector<T> &vec) { Vector(vec); } + + template<typename T> void Add(const char *key, const T &t) { + Key(key); + Add(t); + } + + template<typename T> void Add(const std::map<std::string, T> &map) { + Map(map); + } + + template<typename T> void operator+=(const T &t) { Add(t); } + + // This function is useful in combination with the Mutate* functions above. + // It forces elements of vectors and maps to have a minimum size, such that + // they can later be updated without failing. + // Call with no arguments to reset. + void ForceMinimumBitWidth(BitWidth bw = BIT_WIDTH_8) { + force_min_bit_width_ = bw; + } + + void Finish() { + // If you hit this assert, you likely have objects that were never included + // in a parent. You need to have exactly one root to finish a buffer. + // Check your Start/End calls are matched, and all objects are inside + // some other object. + FLATBUFFERS_ASSERT(stack_.size() == 1); + + // Write root value. + auto byte_width = Align(stack_[0].ElemWidth(buf_.size(), 0)); + WriteAny(stack_[0], byte_width); + // Write root type. + Write(stack_[0].StoredPackedType(), 1); + // Write root size. Normally determined by parent, but root has no parent :) + Write(byte_width, 1); + + finished_ = true; + } + + private: + void Finished() const { + // If you get this assert, you're attempting to get access a buffer + // which hasn't been finished yet. Be sure to call + // Builder::Finish with your root object. + FLATBUFFERS_ASSERT(finished_); + } + + // Align to prepare for writing a scalar with a certain size. + uint8_t Align(BitWidth alignment) { + auto byte_width = 1U << alignment; + buf_.insert(buf_.end(), flatbuffers::PaddingBytes(buf_.size(), byte_width), + 0); + return static_cast<uint8_t>(byte_width); + } + + void WriteBytes(const void *val, size_t size) { + buf_.insert(buf_.end(), reinterpret_cast<const uint8_t *>(val), + reinterpret_cast<const uint8_t *>(val) + size); + } + + template<typename T> void Write(T val, size_t byte_width) { + FLATBUFFERS_ASSERT(sizeof(T) >= byte_width); + val = flatbuffers::EndianScalar(val); + WriteBytes(&val, byte_width); + } + + void WriteDouble(double f, uint8_t byte_width) { + switch (byte_width) { + case 8: Write(f, byte_width); break; + case 4: Write(static_cast<float>(f), byte_width); break; + // case 2: Write(static_cast<half>(f), byte_width); break; + // case 1: Write(static_cast<quarter>(f), byte_width); break; + default: FLATBUFFERS_ASSERT(0); + } + } + + void WriteOffset(uint64_t o, uint8_t byte_width) { + auto reloff = buf_.size() - o; + FLATBUFFERS_ASSERT(byte_width == 8 || reloff < 1ULL << (byte_width * 8)); + Write(reloff, byte_width); + } + + template<typename T> void PushIndirect(T val, Type type, BitWidth bit_width) { + auto byte_width = Align(bit_width); + auto iloc = buf_.size(); + Write(val, byte_width); + stack_.push_back(Value(static_cast<uint64_t>(iloc), type, bit_width)); + } + + static BitWidth WidthB(size_t byte_width) { + switch (byte_width) { + case 1: return BIT_WIDTH_8; + case 2: return BIT_WIDTH_16; + case 4: return BIT_WIDTH_32; + case 8: return BIT_WIDTH_64; + default: FLATBUFFERS_ASSERT(false); return BIT_WIDTH_64; + } + } + + template<typename T> static Type GetScalarType() { + static_assert(flatbuffers::is_scalar<T>::value, "Unrelated types"); + return flatbuffers::is_floating_point<T>::value + ? FBT_FLOAT + : flatbuffers::is_same<T, bool>::value + ? FBT_BOOL + : (flatbuffers::is_unsigned<T>::value ? FBT_UINT + : FBT_INT); + } + + public: + // This was really intended to be private, except for LastValue/ReuseValue. + struct Value { + union { + int64_t i_; + uint64_t u_; + double f_; + }; + + Type type_; + + // For scalars: of itself, for vector: of its elements, for string: length. + BitWidth min_bit_width_; + + Value() : i_(0), type_(FBT_NULL), min_bit_width_(BIT_WIDTH_8) {} + + Value(bool b) + : u_(static_cast<uint64_t>(b)), + type_(FBT_BOOL), + min_bit_width_(BIT_WIDTH_8) {} + + Value(int64_t i, Type t, BitWidth bw) + : i_(i), type_(t), min_bit_width_(bw) {} + Value(uint64_t u, Type t, BitWidth bw) + : u_(u), type_(t), min_bit_width_(bw) {} + + Value(float f) + : f_(static_cast<double>(f)), + type_(FBT_FLOAT), + min_bit_width_(BIT_WIDTH_32) {} + Value(double f) : f_(f), type_(FBT_FLOAT), min_bit_width_(WidthF(f)) {} + + uint8_t StoredPackedType(BitWidth parent_bit_width_ = BIT_WIDTH_8) const { + return PackedType(StoredWidth(parent_bit_width_), type_); + } + + BitWidth ElemWidth(size_t buf_size, size_t elem_index) const { + if (IsInline(type_)) { + return min_bit_width_; + } else { + // We have an absolute offset, but want to store a relative offset + // elem_index elements beyond the current buffer end. Since whether + // the relative offset fits in a certain byte_width depends on + // the size of the elements before it (and their alignment), we have + // to test for each size in turn. + for (size_t byte_width = 1; + byte_width <= sizeof(flatbuffers::largest_scalar_t); + byte_width *= 2) { + // Where are we going to write this offset? + auto offset_loc = buf_size + + flatbuffers::PaddingBytes(buf_size, byte_width) + + elem_index * byte_width; + // Compute relative offset. + auto offset = offset_loc - u_; + // Does it fit? + auto bit_width = WidthU(offset); + if (static_cast<size_t>(static_cast<size_t>(1U) << bit_width) == + byte_width) + return bit_width; + } + FLATBUFFERS_ASSERT(false); // Must match one of the sizes above. + return BIT_WIDTH_64; + } + } + + BitWidth StoredWidth(BitWidth parent_bit_width_ = BIT_WIDTH_8) const { + if (IsInline(type_)) { + return (std::max)(min_bit_width_, parent_bit_width_); + } else { + return min_bit_width_; + } + } + }; + + private: + void WriteAny(const Value &val, uint8_t byte_width) { + switch (val.type_) { + case FBT_NULL: + case FBT_INT: Write(val.i_, byte_width); break; + case FBT_BOOL: + case FBT_UINT: Write(val.u_, byte_width); break; + case FBT_FLOAT: WriteDouble(val.f_, byte_width); break; + default: WriteOffset(val.u_, byte_width); break; + } + } + + size_t CreateBlob(const void *data, size_t len, size_t trailing, Type type) { + auto bit_width = WidthU(len); + auto byte_width = Align(bit_width); + Write<uint64_t>(len, byte_width); + auto sloc = buf_.size(); + WriteBytes(data, len + trailing); + stack_.push_back(Value(static_cast<uint64_t>(sloc), type, bit_width)); + return sloc; + } + + template<typename T> + size_t ScalarVector(const T *elems, size_t len, bool fixed) { + auto vector_type = GetScalarType<T>(); + auto byte_width = sizeof(T); + auto bit_width = WidthB(byte_width); + // If you get this assert, you're trying to write a vector with a size + // field that is bigger than the scalars you're trying to write (e.g. a + // byte vector > 255 elements). For such types, write a "blob" instead. + // TODO: instead of asserting, could write vector with larger elements + // instead, though that would be wasteful. + FLATBUFFERS_ASSERT(WidthU(len) <= bit_width); + Align(bit_width); + if (!fixed) Write<uint64_t>(len, byte_width); + auto vloc = buf_.size(); + for (size_t i = 0; i < len; i++) Write(elems[i], byte_width); + stack_.push_back(Value(static_cast<uint64_t>(vloc), + ToTypedVector(vector_type, fixed ? len : 0), + bit_width)); + return vloc; + } + + Value CreateVector(size_t start, size_t vec_len, size_t step, bool typed, + bool fixed, const Value *keys = nullptr) { + FLATBUFFERS_ASSERT( + !fixed || + typed); // typed=false, fixed=true combination is not supported. + // Figure out smallest bit width we can store this vector with. + auto bit_width = (std::max)(force_min_bit_width_, WidthU(vec_len)); + auto prefix_elems = 1; + if (keys) { + // If this vector is part of a map, we will pre-fix an offset to the keys + // to this vector. + bit_width = (std::max)(bit_width, keys->ElemWidth(buf_.size(), 0)); + prefix_elems += 2; + } + Type vector_type = FBT_KEY; + // Check bit widths and types for all elements. + for (size_t i = start; i < stack_.size(); i += step) { + auto elem_width = + stack_[i].ElemWidth(buf_.size(), i - start + prefix_elems); + bit_width = (std::max)(bit_width, elem_width); + if (typed) { + if (i == start) { + vector_type = stack_[i].type_; + } else { + // If you get this assert, you are writing a typed vector with + // elements that are not all the same type. + FLATBUFFERS_ASSERT(vector_type == stack_[i].type_); + } + } + } + // If you get this assert, your fixed types are not one of: + // Int / UInt / Float / Key. + FLATBUFFERS_ASSERT(!fixed || IsTypedVectorElementType(vector_type)); + auto byte_width = Align(bit_width); + // Write vector. First the keys width/offset if available, and size. + if (keys) { + WriteOffset(keys->u_, byte_width); + Write<uint64_t>(1ULL << keys->min_bit_width_, byte_width); + } + if (!fixed) Write<uint64_t>(vec_len, byte_width); + // Then the actual data. + auto vloc = buf_.size(); + for (size_t i = start; i < stack_.size(); i += step) { + WriteAny(stack_[i], byte_width); + } + // Then the types. + if (!typed) { + for (size_t i = start; i < stack_.size(); i += step) { + buf_.push_back(stack_[i].StoredPackedType(bit_width)); + } + } + return Value(static_cast<uint64_t>(vloc), + keys ? FBT_MAP + : (typed ? ToTypedVector(vector_type, fixed ? vec_len : 0) + : FBT_VECTOR), + bit_width); + } + + // You shouldn't really be copying instances of this class. + Builder(const Builder &); + Builder &operator=(const Builder &); + + std::vector<uint8_t> buf_; + std::vector<Value> stack_; + + bool finished_; + bool has_duplicate_keys_; + + BuilderFlag flags_; + + BitWidth force_min_bit_width_; + + struct KeyOffsetCompare { + explicit KeyOffsetCompare(const std::vector<uint8_t> &buf) : buf_(&buf) {} + bool operator()(size_t a, size_t b) const { + auto stra = + reinterpret_cast<const char *>(flatbuffers::vector_data(*buf_) + a); + auto strb = + reinterpret_cast<const char *>(flatbuffers::vector_data(*buf_) + b); + return strcmp(stra, strb) < 0; + } + const std::vector<uint8_t> *buf_; + }; + + typedef std::pair<size_t, size_t> StringOffset; + struct StringOffsetCompare { + explicit StringOffsetCompare(const std::vector<uint8_t> &buf) + : buf_(&buf) {} + bool operator()(const StringOffset &a, const StringOffset &b) const { + auto stra = reinterpret_cast<const char *>( + flatbuffers::vector_data(*buf_) + a.first); + auto strb = reinterpret_cast<const char *>( + flatbuffers::vector_data(*buf_) + b.first); + return strncmp(stra, strb, (std::min)(a.second, b.second) + 1) < 0; + } + const std::vector<uint8_t> *buf_; + }; + + typedef std::set<size_t, KeyOffsetCompare> KeyOffsetMap; + typedef std::set<StringOffset, StringOffsetCompare> StringOffsetMap; + + KeyOffsetMap key_pool; + StringOffsetMap string_pool; +}; + +} // namespace flexbuffers + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif + +#endif // FLATBUFFERS_FLEXBUFFERS_H_ diff --git a/contrib/libs/flatbuffers/include/flatbuffers/hash.h b/contrib/libs/flatbuffers/include/flatbuffers/hash.h new file mode 100644 index 0000000000..52cc628cdf --- /dev/null +++ b/contrib/libs/flatbuffers/include/flatbuffers/hash.h @@ -0,0 +1,127 @@ +/* + * Copyright 2015 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_HASH_H_ +#define FLATBUFFERS_HASH_H_ + +#include <cstdint> +#include <cstring> + +#include "flatbuffers.h" + +namespace flatbuffers { + +template<typename T> struct FnvTraits { + static const T kFnvPrime; + static const T kOffsetBasis; +}; + +template<> struct FnvTraits<uint32_t> { + static const uint32_t kFnvPrime = 0x01000193; + static const uint32_t kOffsetBasis = 0x811C9DC5; +}; + +template<> struct FnvTraits<uint64_t> { + static const uint64_t kFnvPrime = 0x00000100000001b3ULL; + static const uint64_t kOffsetBasis = 0xcbf29ce484222645ULL; +}; + +template<typename T> T HashFnv1(const char *input) { + T hash = FnvTraits<T>::kOffsetBasis; + for (const char *c = input; *c; ++c) { + hash *= FnvTraits<T>::kFnvPrime; + hash ^= static_cast<unsigned char>(*c); + } + return hash; +} + +template<typename T> T HashFnv1a(const char *input) { + T hash = FnvTraits<T>::kOffsetBasis; + for (const char *c = input; *c; ++c) { + hash ^= static_cast<unsigned char>(*c); + hash *= FnvTraits<T>::kFnvPrime; + } + return hash; +} + +template<> inline uint16_t HashFnv1<uint16_t>(const char *input) { + uint32_t hash = HashFnv1<uint32_t>(input); + return (hash >> 16) ^ (hash & 0xffff); +} + +template<> inline uint16_t HashFnv1a<uint16_t>(const char *input) { + uint32_t hash = HashFnv1a<uint32_t>(input); + return (hash >> 16) ^ (hash & 0xffff); +} + +template<typename T> struct NamedHashFunction { + const char *name; + + typedef T (*HashFunction)(const char *); + HashFunction function; +}; + +const NamedHashFunction<uint16_t> kHashFunctions16[] = { + { "fnv1_16", HashFnv1<uint16_t> }, + { "fnv1a_16", HashFnv1a<uint16_t> }, +}; + +const NamedHashFunction<uint32_t> kHashFunctions32[] = { + { "fnv1_32", HashFnv1<uint32_t> }, + { "fnv1a_32", HashFnv1a<uint32_t> }, +}; + +const NamedHashFunction<uint64_t> kHashFunctions64[] = { + { "fnv1_64", HashFnv1<uint64_t> }, + { "fnv1a_64", HashFnv1a<uint64_t> }, +}; + +inline NamedHashFunction<uint16_t>::HashFunction FindHashFunction16( + const char *name) { + std::size_t size = sizeof(kHashFunctions16) / sizeof(kHashFunctions16[0]); + for (std::size_t i = 0; i < size; ++i) { + if (std::strcmp(name, kHashFunctions16[i].name) == 0) { + return kHashFunctions16[i].function; + } + } + return nullptr; +} + +inline NamedHashFunction<uint32_t>::HashFunction FindHashFunction32( + const char *name) { + std::size_t size = sizeof(kHashFunctions32) / sizeof(kHashFunctions32[0]); + for (std::size_t i = 0; i < size; ++i) { + if (std::strcmp(name, kHashFunctions32[i].name) == 0) { + return kHashFunctions32[i].function; + } + } + return nullptr; +} + +inline NamedHashFunction<uint64_t>::HashFunction FindHashFunction64( + const char *name) { + std::size_t size = sizeof(kHashFunctions64) / sizeof(kHashFunctions64[0]); + for (std::size_t i = 0; i < size; ++i) { + if (std::strcmp(name, kHashFunctions64[i].name) == 0) { + return kHashFunctions64[i].function; + } + } + return nullptr; +} + +} // namespace flatbuffers + +#endif // FLATBUFFERS_HASH_H_ diff --git a/contrib/libs/flatbuffers/include/flatbuffers/idl.h b/contrib/libs/flatbuffers/include/flatbuffers/idl.h new file mode 100644 index 0000000000..a82ff8a694 --- /dev/null +++ b/contrib/libs/flatbuffers/include/flatbuffers/idl.h @@ -0,0 +1,1208 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_IDL_H_ +#define FLATBUFFERS_IDL_H_ + +#include <map> +#include <memory> +#include <stack> + +#include "base.h" +#include "flatbuffers.h" +#include "flexbuffers.h" +#include "hash.h" +#include "reflection.h" + +#if !defined(FLATBUFFERS_CPP98_STL) +# include <functional> +#endif // !defined(FLATBUFFERS_CPP98_STL) + +// This file defines the data types representing a parsed IDL (Interface +// Definition Language) / schema file. + +// Limits maximum depth of nested objects. +// Prevents stack overflow while parse scheme, or json, or flexbuffer. +#if !defined(FLATBUFFERS_MAX_PARSING_DEPTH) +# define FLATBUFFERS_MAX_PARSING_DEPTH 64 +#endif + +namespace flatbuffers { + +// The order of these matters for Is*() functions below. +// Additionally, Parser::ParseType assumes bool..string is a contiguous range +// of type tokens. +// clang-format off +#define FLATBUFFERS_GEN_TYPES_SCALAR(TD) \ + TD(NONE, "", uint8_t, byte, byte, byte, uint8, u8, UByte, UInt8) \ + TD(UTYPE, "", uint8_t, byte, byte, byte, uint8, u8, UByte, UInt8) /* begin scalar/int */ \ + TD(BOOL, "bool", uint8_t, boolean,bool, bool, bool, bool, Boolean, Bool) \ + TD(CHAR, "byte", int8_t, byte, int8, sbyte, int8, i8, Byte, Int8) \ + TD(UCHAR, "ubyte", uint8_t, byte, byte, byte, uint8, u8, UByte, UInt8) \ + TD(SHORT, "short", int16_t, short, int16, short, int16, i16, Short, Int16) \ + TD(USHORT, "ushort", uint16_t, short, uint16, ushort, uint16, u16, UShort, UInt16) \ + TD(INT, "int", int32_t, int, int32, int, int32, i32, Int, Int32) \ + TD(UINT, "uint", uint32_t, int, uint32, uint, uint32, u32, UInt, UInt32) \ + TD(LONG, "long", int64_t, long, int64, long, int64, i64, Long, Int64) \ + TD(ULONG, "ulong", uint64_t, long, uint64, ulong, uint64, u64, ULong, UInt64) /* end int */ \ + TD(FLOAT, "float", float, float, float32, float, float32, f32, Float, Float32) /* begin float */ \ + TD(DOUBLE, "double", double, double, float64, double, float64, f64, Double, Double) /* end float/scalar */ +#define FLATBUFFERS_GEN_TYPES_POINTER(TD) \ + TD(STRING, "string", Offset<void>, int, int, StringOffset, int, unused, Int, Offset<String>) \ + TD(VECTOR, "", Offset<void>, int, int, VectorOffset, int, unused, Int, Offset<UOffset>) \ + TD(STRUCT, "", Offset<void>, int, int, int, int, unused, Int, Offset<UOffset>) \ + TD(UNION, "", Offset<void>, int, int, int, int, unused, Int, Offset<UOffset>) +#define FLATBUFFERS_GEN_TYPE_ARRAY(TD) \ + TD(ARRAY, "", int, int, int, int, int, unused, Int, Offset<UOffset>) +// The fields are: +// - enum +// - FlatBuffers schema type. +// - C++ type. +// - Java type. +// - Go type. +// - C# / .Net type. +// - Python type. +// - Rust type. +// - Kotlin type. + +// using these macros, we can now write code dealing with types just once, e.g. + +/* +switch (type) { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \ + RTYPE, KTYPE) \ + case BASE_TYPE_ ## ENUM: \ + // do something specific to CTYPE here + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD +} +*/ + +// If not all FLATBUFFERS_GEN_() arguments are necessary for implementation +// of FLATBUFFERS_TD, you can use a variadic macro (with __VA_ARGS__ if needed). +// In the above example, only CTYPE is used to generate the code, it can be rewritten: + +/* +switch (type) { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ + case BASE_TYPE_ ## ENUM: \ + // do something specific to CTYPE here + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD +} +*/ + +#define FLATBUFFERS_GEN_TYPES(TD) \ + FLATBUFFERS_GEN_TYPES_SCALAR(TD) \ + FLATBUFFERS_GEN_TYPES_POINTER(TD) \ + FLATBUFFERS_GEN_TYPE_ARRAY(TD) + +// Create an enum for all the types above. +#ifdef __GNUC__ +__extension__ // Stop GCC complaining about trailing comma with -Wpendantic. +#endif +enum BaseType { + #define FLATBUFFERS_TD(ENUM, ...) \ + BASE_TYPE_ ## ENUM, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD +}; + +#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ + static_assert(sizeof(CTYPE) <= sizeof(largest_scalar_t), \ + "define largest_scalar_t as " #CTYPE); + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) +#undef FLATBUFFERS_TD + +inline bool IsScalar (BaseType t) { return t >= BASE_TYPE_UTYPE && + t <= BASE_TYPE_DOUBLE; } +inline bool IsInteger(BaseType t) { return t >= BASE_TYPE_UTYPE && + t <= BASE_TYPE_ULONG; } +inline bool IsFloat (BaseType t) { return t == BASE_TYPE_FLOAT || + t == BASE_TYPE_DOUBLE; } +inline bool IsLong (BaseType t) { return t == BASE_TYPE_LONG || + t == BASE_TYPE_ULONG; } +inline bool IsBool (BaseType t) { return t == BASE_TYPE_BOOL; } +inline bool IsOneByte(BaseType t) { return t >= BASE_TYPE_UTYPE && + t <= BASE_TYPE_UCHAR; } + +inline bool IsUnsigned(BaseType t) { + return (t == BASE_TYPE_UTYPE) || (t == BASE_TYPE_UCHAR) || + (t == BASE_TYPE_USHORT) || (t == BASE_TYPE_UINT) || + (t == BASE_TYPE_ULONG); +} + +// clang-format on + +extern const char *const kTypeNames[]; +extern const char kTypeSizes[]; + +inline size_t SizeOf(BaseType t) { return kTypeSizes[t]; } + +struct StructDef; +struct EnumDef; +class Parser; + +// Represents any type in the IDL, which is a combination of the BaseType +// and additional information for vectors/structs_. +struct Type { + explicit Type(BaseType _base_type = BASE_TYPE_NONE, StructDef *_sd = nullptr, + EnumDef *_ed = nullptr, uint16_t _fixed_length = 0) + : base_type(_base_type), + element(BASE_TYPE_NONE), + struct_def(_sd), + enum_def(_ed), + fixed_length(_fixed_length) {} + + bool operator==(const Type &o) { + return base_type == o.base_type && element == o.element && + struct_def == o.struct_def && enum_def == o.enum_def; + } + + Type VectorType() const { + return Type(element, struct_def, enum_def, fixed_length); + } + + Offset<reflection::Type> Serialize(FlatBufferBuilder *builder) const; + + bool Deserialize(const Parser &parser, const reflection::Type *type); + + BaseType base_type; + BaseType element; // only set if t == BASE_TYPE_VECTOR + StructDef *struct_def; // only set if t or element == BASE_TYPE_STRUCT + EnumDef *enum_def; // set if t == BASE_TYPE_UNION / BASE_TYPE_UTYPE, + // or for an integral type derived from an enum. + uint16_t fixed_length; // only set if t == BASE_TYPE_ARRAY +}; + +// Represents a parsed scalar value, it's type, and field offset. +struct Value { + Value() + : constant("0"), + offset(static_cast<voffset_t>(~(static_cast<voffset_t>(0U)))) {} + Type type; + std::string constant; + voffset_t offset; +}; + +// Helper class that retains the original order of a set of identifiers and +// also provides quick lookup. +template<typename T> class SymbolTable { + public: + ~SymbolTable() { + for (auto it = vec.begin(); it != vec.end(); ++it) { delete *it; } + } + + bool Add(const std::string &name, T *e) { + vector_emplace_back(&vec, e); + auto it = dict.find(name); + if (it != dict.end()) return true; + dict[name] = e; + return false; + } + + void Move(const std::string &oldname, const std::string &newname) { + auto it = dict.find(oldname); + if (it != dict.end()) { + auto obj = it->second; + dict.erase(it); + dict[newname] = obj; + } else { + FLATBUFFERS_ASSERT(false); + } + } + + T *Lookup(const std::string &name) const { + auto it = dict.find(name); + return it == dict.end() ? nullptr : it->second; + } + + public: + std::map<std::string, T *> dict; // quick lookup + std::vector<T *> vec; // Used to iterate in order of insertion +}; + +// A name space, as set in the schema. +struct Namespace { + Namespace() : from_table(0) {} + + // Given a (potentially unqualified) name, return the "fully qualified" name + // which has a full namespaced descriptor. + // With max_components you can request less than the number of components + // the current namespace has. + std::string GetFullyQualifiedName(const std::string &name, + size_t max_components = 1000) const; + + std::vector<std::string> components; + size_t from_table; // Part of the namespace corresponds to a message/table. +}; + +inline bool operator<(const Namespace &a, const Namespace &b) { + size_t min_size = std::min(a.components.size(), b.components.size()); + for (size_t i = 0; i < min_size; ++i) { + if (a.components[i] != b.components[i]) + return a.components[i] < b.components[i]; + } + return a.components.size() < b.components.size(); +} + +// Base class for all definition types (fields, structs_, enums_). +struct Definition { + Definition() + : generated(false), + defined_namespace(nullptr), + serialized_location(0), + index(-1), + refcount(1) {} + + flatbuffers::Offset< + flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> + SerializeAttributes(FlatBufferBuilder *builder, const Parser &parser) const; + + bool DeserializeAttributes(Parser &parser, + const Vector<Offset<reflection::KeyValue>> *attrs); + + std::string name; + std::string file; + std::vector<std::string> doc_comment; + SymbolTable<Value> attributes; + bool generated; // did we already output code for this definition? + Namespace *defined_namespace; // Where it was defined. + + // For use with Serialize() + uoffset_t serialized_location; + int index; // Inside the vector it is stored. + int refcount; +}; + +struct FieldDef : public Definition { + FieldDef() + : deprecated(false), + key(false), + shared(false), + native_inline(false), + flexbuffer(false), + presence(kDefault), + nested_flatbuffer(NULL), + padding(0) {} + + Offset<reflection::Field> Serialize(FlatBufferBuilder *builder, uint16_t id, + const Parser &parser) const; + + bool Deserialize(Parser &parser, const reflection::Field *field); + + bool IsScalarOptional() const { + return IsScalar(value.type.base_type) && IsOptional(); + } + bool IsOptional() const { + return presence == kOptional; + } + bool IsRequired() const { + return presence == kRequired; + } + bool IsDefault() const { + return presence == kDefault; + } + + Value value; + bool deprecated; // Field is allowed to be present in old data, but can't be. + // written in new data nor accessed in new code. + bool key; // Field functions as a key for creating sorted vectors. + bool shared; // Field will be using string pooling (i.e. CreateSharedString) + // as default serialization behavior if field is a string. + bool native_inline; // Field will be defined inline (instead of as a pointer) + // for native tables if field is a struct. + bool flexbuffer; // This field contains FlexBuffer data. + + enum Presence { + // Field must always be present. + kRequired, + // Non-presence should be signalled to and controlled by users. + kOptional, + // Non-presence is hidden from users. + // Implementations may omit writing default values. + kDefault, + }; + Presence static MakeFieldPresence(bool optional, bool required) { + FLATBUFFERS_ASSERT(!(required && optional)); + // clang-format off + return required ? FieldDef::kRequired + : optional ? FieldDef::kOptional + : FieldDef::kDefault; + // clang-format on + } + Presence presence; + + StructDef *nested_flatbuffer; // This field contains nested FlatBuffer data. + size_t padding; // Bytes to always pad after this field. +}; + +struct StructDef : public Definition { + StructDef() + : fixed(false), + predecl(true), + sortbysize(true), + has_key(false), + minalign(1), + bytesize(0) {} + + void PadLastField(size_t min_align) { + auto padding = PaddingBytes(bytesize, min_align); + bytesize += padding; + if (fields.vec.size()) fields.vec.back()->padding = padding; + } + + Offset<reflection::Object> Serialize(FlatBufferBuilder *builder, + const Parser &parser) const; + + bool Deserialize(Parser &parser, const reflection::Object *object); + + SymbolTable<FieldDef> fields; + + bool fixed; // If it's struct, not a table. + bool predecl; // If it's used before it was defined. + bool sortbysize; // Whether fields come in the declaration or size order. + bool has_key; // It has a key field. + size_t minalign; // What the whole object needs to be aligned to. + size_t bytesize; // Size if fixed. + + flatbuffers::unique_ptr<std::string> original_location; +}; + +struct EnumDef; +struct EnumValBuilder; + +struct EnumVal { + Offset<reflection::EnumVal> Serialize(FlatBufferBuilder *builder, + const Parser &parser) const; + + bool Deserialize(const Parser &parser, const reflection::EnumVal *val); + + uint64_t GetAsUInt64() const { return static_cast<uint64_t>(value); } + int64_t GetAsInt64() const { return value; } + bool IsZero() const { return 0 == value; } + bool IsNonZero() const { return !IsZero(); } + + std::string name; + std::vector<std::string> doc_comment; + Type union_type; + + private: + friend EnumDef; + friend EnumValBuilder; + friend bool operator==(const EnumVal &lhs, const EnumVal &rhs); + + EnumVal(const std::string &_name, int64_t _val) : name(_name), value(_val) {} + EnumVal() : value(0) {} + + int64_t value; +}; + +struct EnumDef : public Definition { + EnumDef() : is_union(false), uses_multiple_type_instances(false) {} + + Offset<reflection::Enum> Serialize(FlatBufferBuilder *builder, + const Parser &parser) const; + + bool Deserialize(Parser &parser, const reflection::Enum *values); + + template<typename T> void ChangeEnumValue(EnumVal *ev, T new_val); + void SortByValue(); + void RemoveDuplicates(); + + std::string AllFlags() const; + const EnumVal *MinValue() const; + const EnumVal *MaxValue() const; + // Returns the number of integer steps from v1 to v2. + uint64_t Distance(const EnumVal *v1, const EnumVal *v2) const; + // Returns the number of integer steps from Min to Max. + uint64_t Distance() const { return Distance(MinValue(), MaxValue()); } + + EnumVal *ReverseLookup(int64_t enum_idx, + bool skip_union_default = false) const; + EnumVal *FindByValue(const std::string &constant) const; + + std::string ToString(const EnumVal &ev) const { + return IsUInt64() ? NumToString(ev.GetAsUInt64()) + : NumToString(ev.GetAsInt64()); + } + + size_t size() const { return vals.vec.size(); } + + const std::vector<EnumVal *> &Vals() const { return vals.vec; } + + const EnumVal *Lookup(const std::string &enum_name) const { + return vals.Lookup(enum_name); + } + + bool is_union; + // Type is a union which uses type aliases where at least one type is + // available under two different names. + bool uses_multiple_type_instances; + Type underlying_type; + + private: + bool IsUInt64() const { + return (BASE_TYPE_ULONG == underlying_type.base_type); + } + + friend EnumValBuilder; + SymbolTable<EnumVal> vals; +}; + +inline bool IsString(const Type &type) { + return type.base_type == BASE_TYPE_STRING; +} + +inline bool IsStruct(const Type &type) { + return type.base_type == BASE_TYPE_STRUCT && type.struct_def->fixed; +} + +inline bool IsUnion(const Type &type) { + return type.enum_def != nullptr && type.enum_def->is_union; +} + +inline bool IsVector(const Type &type) { + return type.base_type == BASE_TYPE_VECTOR; +} + +inline bool IsArray(const Type &type) { + return type.base_type == BASE_TYPE_ARRAY; +} + +inline bool IsSeries(const Type &type) { + return IsVector(type) || IsArray(type); +} + +inline bool IsEnum(const Type &type) { + return type.enum_def != nullptr && IsInteger(type.base_type); +} + +inline size_t InlineSize(const Type &type) { + return IsStruct(type) + ? type.struct_def->bytesize + : (IsArray(type) + ? InlineSize(type.VectorType()) * type.fixed_length + : SizeOf(type.base_type)); +} + +inline size_t InlineAlignment(const Type &type) { + if (IsStruct(type)) { + return type.struct_def->minalign; + } else if (IsArray(type)) { + return IsStruct(type.VectorType()) ? type.struct_def->minalign + : SizeOf(type.element); + } else { + return SizeOf(type.base_type); + } +} +inline bool operator==(const EnumVal &lhs, const EnumVal &rhs) { + return lhs.value == rhs.value; +} +inline bool operator!=(const EnumVal &lhs, const EnumVal &rhs) { + return !(lhs == rhs); +} + +inline bool EqualByName(const Type &a, const Type &b) { + return a.base_type == b.base_type && a.element == b.element && + (a.struct_def == b.struct_def || + a.struct_def->name == b.struct_def->name) && + (a.enum_def == b.enum_def || a.enum_def->name == b.enum_def->name); +} + +struct RPCCall : public Definition { + Offset<reflection::RPCCall> Serialize(FlatBufferBuilder *builder, + const Parser &parser) const; + + bool Deserialize(Parser &parser, const reflection::RPCCall *call); + + StructDef *request, *response; +}; + +struct ServiceDef : public Definition { + Offset<reflection::Service> Serialize(FlatBufferBuilder *builder, + const Parser &parser) const; + bool Deserialize(Parser &parser, const reflection::Service *service); + + SymbolTable<RPCCall> calls; +}; + +// Container of options that may apply to any of the source/text generators. +struct IDLOptions { + bool gen_jvmstatic; + // Use flexbuffers instead for binary and text generation + bool use_flexbuffers; + bool strict_json; + bool output_default_scalars_in_json; + int indent_step; + bool output_enum_identifiers; + bool prefixed_enums; + bool scoped_enums; + bool include_dependence_headers; + bool mutable_buffer; + bool one_file; + bool proto_mode; + bool proto_oneof_union; + bool generate_all; + bool skip_unexpected_fields_in_json; + bool generate_name_strings; + bool generate_object_based_api; + bool gen_compare; + std::string cpp_object_api_pointer_type; + std::string cpp_object_api_string_type; + bool cpp_object_api_string_flexible_constructor; + bool cpp_direct_copy; + bool gen_nullable; + bool java_checkerframework; + bool gen_generated; + std::string object_prefix; + std::string object_suffix; + bool union_value_namespacing; + bool allow_non_utf8; + bool natural_utf8; + std::string include_prefix; + bool keep_include_path; + bool binary_schema_comments; + bool binary_schema_builtins; + bool binary_schema_gen_embed; + std::string go_import; + std::string go_namespace; + bool protobuf_ascii_alike; + bool size_prefixed; + std::string root_type; + bool force_defaults; + bool java_primitive_has_method; + bool cs_gen_json_serializer; + std::vector<std::string> cpp_includes; + std::string cpp_std; + bool cpp_static_reflection; + std::string proto_namespace_suffix; + std::string filename_suffix; + std::string filename_extension; + bool no_warnings; + + // Possible options for the more general generator below. + enum Language { + kJava = 1 << 0, + kCSharp = 1 << 1, + kGo = 1 << 2, + kCpp = 1 << 3, + kPython = 1 << 5, + kPhp = 1 << 6, + kJson = 1 << 7, + kBinary = 1 << 8, + kTs = 1 << 9, + kJsonSchema = 1 << 10, + kDart = 1 << 11, + kLua = 1 << 12, + kLobster = 1 << 13, + kRust = 1 << 14, + kKotlin = 1 << 15, + kSwift = 1 << 16, + kCppYandexMapsIter = 1 << 17, + kMAX + }; + + Language lang; + + enum MiniReflect { kNone, kTypes, kTypesAndNames }; + + MiniReflect mini_reflect; + + // If set, require all fields in a table to be explicitly numbered. + bool require_explicit_ids; + + // The corresponding language bit will be set if a language is included + // for code generation. + unsigned long lang_to_generate; + + // If set (default behavior), empty string fields will be set to nullptr to + // make the flatbuffer more compact. + bool set_empty_strings_to_null; + + // If set (default behavior), empty vector fields will be set to nullptr to + // make the flatbuffer more compact. + bool set_empty_vectors_to_null; + + IDLOptions() + : gen_jvmstatic(false), + use_flexbuffers(false), + strict_json(false), + output_default_scalars_in_json(false), + indent_step(2), + output_enum_identifiers(true), + prefixed_enums(true), + scoped_enums(false), + include_dependence_headers(true), + mutable_buffer(false), + one_file(false), + proto_mode(false), + proto_oneof_union(false), + generate_all(false), + skip_unexpected_fields_in_json(false), + generate_name_strings(false), + generate_object_based_api(false), + gen_compare(false), + cpp_object_api_pointer_type("std::unique_ptr"), + cpp_object_api_string_flexible_constructor(false), + cpp_direct_copy(true), + gen_nullable(false), + java_checkerframework(false), + gen_generated(false), + object_suffix("T"), + union_value_namespacing(true), + allow_non_utf8(false), + natural_utf8(false), + keep_include_path(false), + binary_schema_comments(false), + binary_schema_builtins(false), + binary_schema_gen_embed(false), + protobuf_ascii_alike(false), + size_prefixed(false), + force_defaults(false), + java_primitive_has_method(false), + cs_gen_json_serializer(false), + cpp_static_reflection(false), + filename_suffix("_generated"), + filename_extension(), + no_warnings(false), + lang(IDLOptions::kJava), + mini_reflect(IDLOptions::kNone), + require_explicit_ids(false), + lang_to_generate(0), + set_empty_strings_to_null(true), + set_empty_vectors_to_null(true) {} +}; + +// This encapsulates where the parser is in the current source file. +struct ParserState { + ParserState() + : cursor_(nullptr), + line_start_(nullptr), + line_(0), + token_(-1), + attr_is_trivial_ascii_string_(true) {} + + protected: + void ResetState(const char *source) { + cursor_ = source; + line_ = 0; + MarkNewLine(); + } + + void MarkNewLine() { + line_start_ = cursor_; + line_ += 1; + } + + int64_t CursorPosition() const { + FLATBUFFERS_ASSERT(cursor_ && line_start_ && cursor_ >= line_start_); + return static_cast<int64_t>(cursor_ - line_start_); + } + + const char *cursor_; + const char *line_start_; + int line_; // the current line being parsed + int token_; + + // Flag: text in attribute_ is true ASCII string without escape + // sequences. Only printable ASCII (without [\t\r\n]). + // Used for number-in-string (and base64 string in future). + bool attr_is_trivial_ascii_string_; + std::string attribute_; + std::vector<std::string> doc_comment_; +}; + +// A way to make error propagation less error prone by requiring values to be +// checked. +// Once you create a value of this type you must either: +// - Call Check() on it. +// - Copy or assign it to another value. +// Failure to do so leads to an assert. +// This guarantees that this as return value cannot be ignored. +class CheckedError { + public: + explicit CheckedError(bool error) + : is_error_(error), has_been_checked_(false) {} + + CheckedError &operator=(const CheckedError &other) { + is_error_ = other.is_error_; + has_been_checked_ = false; + other.has_been_checked_ = true; + return *this; + } + + CheckedError(const CheckedError &other) { + *this = other; // Use assignment operator. + } + + ~CheckedError() { FLATBUFFERS_ASSERT(has_been_checked_); } + + bool Check() { + has_been_checked_ = true; + return is_error_; + } + + private: + bool is_error_; + mutable bool has_been_checked_; +}; + +// Additionally, in GCC we can get these errors statically, for additional +// assurance: +// clang-format off +#ifdef __GNUC__ +#define FLATBUFFERS_CHECKED_ERROR CheckedError \ + __attribute__((warn_unused_result)) +#else +#define FLATBUFFERS_CHECKED_ERROR CheckedError +#endif +// clang-format on + +class Parser : public ParserState { + public: + explicit Parser(const IDLOptions &options = IDLOptions()) + : current_namespace_(nullptr), + empty_namespace_(nullptr), + flex_builder_(256, flexbuffers::BUILDER_FLAG_SHARE_ALL), + root_struct_def_(nullptr), + opts(options), + uses_flexbuffers_(false), + advanced_features_(0), + source_(nullptr), + anonymous_counter_(0), + parse_depth_counter_(0) { + if (opts.force_defaults) { builder_.ForceDefaults(true); } + // Start out with the empty namespace being current. + empty_namespace_ = new Namespace(); + namespaces_.push_back(empty_namespace_); + current_namespace_ = empty_namespace_; + known_attributes_["deprecated"] = true; + known_attributes_["required"] = true; + known_attributes_["key"] = true; + known_attributes_["shared"] = true; + known_attributes_["hash"] = true; + known_attributes_["id"] = true; + known_attributes_["force_align"] = true; + known_attributes_["bit_flags"] = true; + known_attributes_["original_order"] = true; + known_attributes_["nested_flatbuffer"] = true; + known_attributes_["csharp_partial"] = true; + known_attributes_["streaming"] = true; + known_attributes_["idempotent"] = true; + known_attributes_["cpp_type"] = true; + known_attributes_["cpp_ptr_type"] = true; + known_attributes_["cpp_ptr_type_get"] = true; + known_attributes_["cpp_str_type"] = true; + known_attributes_["cpp_str_flex_ctor"] = true; + known_attributes_["native_inline"] = true; + known_attributes_["native_custom_alloc"] = true; + known_attributes_["native_type"] = true; + known_attributes_["native_type_pack_name"] = true; + known_attributes_["native_default"] = true; + known_attributes_["flexbuffer"] = true; + known_attributes_["private"] = true; + } + + ~Parser() { + for (auto it = namespaces_.begin(); it != namespaces_.end(); ++it) { + delete *it; + } + } + + // Parse the string containing either schema or JSON data, which will + // populate the SymbolTable's or the FlatBufferBuilder above. + // include_paths is used to resolve any include statements, and typically + // should at least include the project path (where you loaded source_ from). + // include_paths must be nullptr terminated if specified. + // If include_paths is nullptr, it will attempt to load from the current + // directory. + // If the source was loaded from a file and isn't an include file, + // supply its name in source_filename. + // All paths specified in this call must be in posix format, if you accept + // paths from user input, please call PosixPath on them first. + bool Parse(const char *_source, const char **include_paths = nullptr, + const char *source_filename = nullptr); + + bool ParseJson(const char *json, const char *json_filename = nullptr); + + // Set the root type. May override the one set in the schema. + bool SetRootType(const char *name); + + // Mark all definitions as already having code generated. + void MarkGenerated(); + + // Get the files recursively included by the given file. The returned + // container will have at least the given file. + std::set<std::string> GetIncludedFilesRecursive( + const std::string &file_name) const; + + // Fills builder_ with a binary version of the schema parsed. + // See reflection/reflection.fbs + void Serialize(); + + // Deserialize a schema buffer + bool Deserialize(const uint8_t *buf, const size_t size); + + // Fills internal structure as if the schema passed had been loaded by parsing + // with Parse except that included filenames will not be populated. + bool Deserialize(const reflection::Schema *schema); + + Type *DeserializeType(const reflection::Type *type); + + // Checks that the schema represented by this parser is a safe evolution + // of the schema provided. Returns non-empty error on any problems. + std::string ConformTo(const Parser &base); + + // Similar to Parse(), but now only accepts JSON to be parsed into a + // FlexBuffer. + bool ParseFlexBuffer(const char *source, const char *source_filename, + flexbuffers::Builder *builder); + + StructDef *LookupStruct(const std::string &id) const; + StructDef *LookupStructThruParentNamespaces(const std::string &id) const; + + std::string UnqualifiedName(const std::string &fullQualifiedName); + + FLATBUFFERS_CHECKED_ERROR Error(const std::string &msg); + + // @brief Verify that any of 'opts.lang_to_generate' supports Optional scalars + // in a schema. + // @param opts Options used to parce a schema and generate code. + static bool SupportsOptionalScalars(const flatbuffers::IDLOptions &opts); + + private: + class ParseDepthGuard; + + void Message(const std::string &msg); + void Warning(const std::string &msg); + FLATBUFFERS_CHECKED_ERROR ParseHexNum(int nibbles, uint64_t *val); + FLATBUFFERS_CHECKED_ERROR Next(); + FLATBUFFERS_CHECKED_ERROR SkipByteOrderMark(); + bool Is(int t) const; + bool IsIdent(const char *id) const; + FLATBUFFERS_CHECKED_ERROR Expect(int t); + std::string TokenToStringId(int t) const; + EnumDef *LookupEnum(const std::string &id); + FLATBUFFERS_CHECKED_ERROR ParseNamespacing(std::string *id, + std::string *last); + FLATBUFFERS_CHECKED_ERROR ParseTypeIdent(Type &type); + FLATBUFFERS_CHECKED_ERROR ParseType(Type &type); + FLATBUFFERS_CHECKED_ERROR AddField(StructDef &struct_def, + const std::string &name, const Type &type, + FieldDef **dest); + FLATBUFFERS_CHECKED_ERROR ParseField(StructDef &struct_def); + FLATBUFFERS_CHECKED_ERROR ParseString(Value &val, bool use_string_pooling); + FLATBUFFERS_CHECKED_ERROR ParseComma(); + FLATBUFFERS_CHECKED_ERROR ParseAnyValue(Value &val, FieldDef *field, + size_t parent_fieldn, + const StructDef *parent_struct_def, + uoffset_t count, + bool inside_vector = false); + template<typename F> + FLATBUFFERS_CHECKED_ERROR ParseTableDelimiters(size_t &fieldn, + const StructDef *struct_def, + F body); + FLATBUFFERS_CHECKED_ERROR ParseTable(const StructDef &struct_def, + std::string *value, uoffset_t *ovalue); + void SerializeStruct(const StructDef &struct_def, const Value &val); + void SerializeStruct(FlatBufferBuilder &builder, const StructDef &struct_def, + const Value &val); + template<typename F> + FLATBUFFERS_CHECKED_ERROR ParseVectorDelimiters(uoffset_t &count, F body); + FLATBUFFERS_CHECKED_ERROR ParseVector(const Type &type, uoffset_t *ovalue, + FieldDef *field, size_t fieldn); + FLATBUFFERS_CHECKED_ERROR ParseArray(Value &array); + FLATBUFFERS_CHECKED_ERROR ParseNestedFlatbuffer( + Value &val, FieldDef *field, size_t fieldn, + const StructDef *parent_struct_def); + FLATBUFFERS_CHECKED_ERROR ParseMetaData(SymbolTable<Value> *attributes); + FLATBUFFERS_CHECKED_ERROR TryTypedValue(const std::string *name, int dtoken, + bool check, Value &e, BaseType req, + bool *destmatch); + FLATBUFFERS_CHECKED_ERROR ParseHash(Value &e, FieldDef *field); + FLATBUFFERS_CHECKED_ERROR TokenError(); + FLATBUFFERS_CHECKED_ERROR ParseSingleValue(const std::string *name, Value &e, + bool check_now); + FLATBUFFERS_CHECKED_ERROR ParseFunction(const std::string *name, Value &e); + FLATBUFFERS_CHECKED_ERROR ParseEnumFromString(const Type &type, + std::string *result); + StructDef *LookupCreateStruct(const std::string &name, + bool create_if_new = true, + bool definition = false); + FLATBUFFERS_CHECKED_ERROR ParseEnum(bool is_union, EnumDef **dest); + FLATBUFFERS_CHECKED_ERROR ParseNamespace(); + FLATBUFFERS_CHECKED_ERROR StartStruct(const std::string &name, + StructDef **dest); + FLATBUFFERS_CHECKED_ERROR StartEnum(const std::string &name, bool is_union, + EnumDef **dest); + FLATBUFFERS_CHECKED_ERROR ParseDecl(); + FLATBUFFERS_CHECKED_ERROR ParseService(); + FLATBUFFERS_CHECKED_ERROR ParseProtoFields(StructDef *struct_def, + bool isextend, bool inside_oneof); + FLATBUFFERS_CHECKED_ERROR ParseProtoOption(); + FLATBUFFERS_CHECKED_ERROR ParseProtoKey(); + FLATBUFFERS_CHECKED_ERROR ParseProtoDecl(); + FLATBUFFERS_CHECKED_ERROR ParseProtoCurliesOrIdent(); + FLATBUFFERS_CHECKED_ERROR ParseTypeFromProtoType(Type *type); + FLATBUFFERS_CHECKED_ERROR SkipAnyJsonValue(); + FLATBUFFERS_CHECKED_ERROR ParseFlexBufferNumericConstant( + flexbuffers::Builder *builder); + FLATBUFFERS_CHECKED_ERROR ParseFlexBufferValue(flexbuffers::Builder *builder); + FLATBUFFERS_CHECKED_ERROR StartParseFile(const char *source, + const char *source_filename); + FLATBUFFERS_CHECKED_ERROR ParseRoot(const char *_source, + const char **include_paths, + const char *source_filename); + FLATBUFFERS_CHECKED_ERROR DoParse(const char *_source, + const char **include_paths, + const char *source_filename, + const char *include_filename); + FLATBUFFERS_CHECKED_ERROR DoParseJson(); + FLATBUFFERS_CHECKED_ERROR CheckClash(std::vector<FieldDef *> &fields, + StructDef *struct_def, + const char *suffix, BaseType baseType); + FLATBUFFERS_CHECKED_ERROR ParseAlignAttribute( + const std::string &align_constant, size_t min_align, size_t *align); + + bool SupportsAdvancedUnionFeatures() const; + bool SupportsAdvancedArrayFeatures() const; + bool SupportsOptionalScalars() const; + bool SupportsDefaultVectorsAndStrings() const; + Namespace *UniqueNamespace(Namespace *ns); + + FLATBUFFERS_CHECKED_ERROR RecurseError(); + template<typename F> CheckedError Recurse(F f); + + public: + SymbolTable<Type> types_; + SymbolTable<StructDef> structs_; + SymbolTable<EnumDef> enums_; + SymbolTable<ServiceDef> services_; + std::vector<Namespace *> namespaces_; + Namespace *current_namespace_; + Namespace *empty_namespace_; + std::string error_; // User readable error_ if Parse() == false + + FlatBufferBuilder builder_; // any data contained in the file + flexbuffers::Builder flex_builder_; + flexbuffers::Reference flex_root_; + StructDef *root_struct_def_; + std::string file_identifier_; + std::string file_extension_; + + std::map<uint64_t, std::string> included_files_; + std::map<std::string, std::set<std::string>> files_included_per_file_; + std::vector<std::string> native_included_files_; + + std::map<std::string, bool> known_attributes_; + + IDLOptions opts; + bool uses_flexbuffers_; + + uint64_t advanced_features_; + + private: + const char *source_; + + std::string file_being_parsed_; + + std::vector<std::pair<Value, FieldDef *>> field_stack_; + + int anonymous_counter_; + int parse_depth_counter_; // stack-overflow guard +}; + +// Utility functions for multiple generators: + +extern std::string MakeCamel(const std::string &in, bool first = true); + +extern std::string MakeScreamingCamel(const std::string &in); + +// Generate text (JSON) from a given FlatBuffer, and a given Parser +// object that has been populated with the corresponding schema. +// If ident_step is 0, no indentation will be generated. Additionally, +// if it is less than 0, no linefeeds will be generated either. +// See idl_gen_text.cpp. +// strict_json adds "quotes" around field names if true. +// If the flatbuffer cannot be encoded in JSON (e.g., it contains non-UTF-8 +// byte arrays in String values), returns false. +extern bool GenerateTextFromTable(const Parser &parser, const void *table, + const std::string &tablename, + std::string *text); +extern bool GenerateText(const Parser &parser, const void *flatbuffer, + std::string *text); +extern bool GenerateTextFile(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate Json schema to string +// See idl_gen_json_schema.cpp. +extern bool GenerateJsonSchema(const Parser &parser, std::string *json); + +// Generate binary files from a given FlatBuffer, and a given Parser +// object that has been populated with the corresponding schema. +// See code_generators.cpp. +extern bool GenerateBinary(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate a C++ header from the definitions in the Parser object. +// See idl_gen_cpp. +extern bool GenerateCPP(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate C# files from the definitions in the Parser object. +// See idl_gen_csharp.cpp. +extern bool GenerateCSharp(const Parser &parser, const std::string &path, + const std::string &file_name); + +extern bool GenerateDart(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate Java files from the definitions in the Parser object. +// See idl_gen_java.cpp. +extern bool GenerateJava(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate JavaScript or TypeScript code from the definitions in the Parser +// object. See idl_gen_js. +extern bool GenerateTS(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate Go files from the definitions in the Parser object. +// See idl_gen_go.cpp. +extern bool GenerateGo(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate Php code from the definitions in the Parser object. +// See idl_gen_php. +extern bool GeneratePhp(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate Python files from the definitions in the Parser object. +// See idl_gen_python.cpp. +extern bool GeneratePython(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate Lobster files from the definitions in the Parser object. +// See idl_gen_lobster.cpp. +extern bool GenerateLobster(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate Lua files from the definitions in the Parser object. +// See idl_gen_lua.cpp. +extern bool GenerateLua(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate Rust files from the definitions in the Parser object. +// See idl_gen_rust.cpp. +extern bool GenerateRust(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate Json schema file +// See idl_gen_json_schema.cpp. +extern bool GenerateJsonSchema(const Parser &parser, const std::string &path, + const std::string &file_name); + +extern bool GenerateKotlin(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate Swift classes. +// See idl_gen_swift.cpp +extern bool GenerateSwift(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate a schema file from the internal representation, useful after +// parsing a .proto schema. +extern std::string GenerateFBS(const Parser &parser, + const std::string &file_name); +extern bool GenerateFBS(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate a C++ header for reading with templated file iterator from +// the definitions in the Parser object. +// See idl_gen_cpp_yandex_maps_iter.cpp. +extern std::string GenerateCPPYandexMapsIter(const Parser &parser, + const std::string &include_guard_ident); +extern bool GenerateCPPYandexMapsIter(const Parser &parser, + const std::string &path, + const std::string &file_name); + +// Generate a make rule for the generated TypeScript code. +// See idl_gen_ts.cpp. +extern std::string TSMakeRule(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate a make rule for the generated C++ header. +// See idl_gen_cpp.cpp. +extern std::string CPPMakeRule(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate a make rule for the generated Dart code +// see idl_gen_dart.cpp +extern std::string DartMakeRule(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate a make rule for the generated Rust code. +// See idl_gen_rust.cpp. +extern std::string RustMakeRule(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate a make rule for generated Java or C# files. +// See code_generators.cpp. +extern std::string JavaCSharpMakeRule(const Parser &parser, + const std::string &path, + const std::string &file_name); + +// Generate a make rule for the generated text (JSON) files. +// See idl_gen_text.cpp. +extern std::string TextMakeRule(const Parser &parser, const std::string &path, + const std::string &file_names); + +// Generate a make rule for the generated binary files. +// See code_generators.cpp. +extern std::string BinaryMakeRule(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate GRPC Cpp interfaces. +// See idl_gen_grpc.cpp. +bool GenerateCppGRPC(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate GRPC Go interfaces. +// See idl_gen_grpc.cpp. +bool GenerateGoGRPC(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate GRPC Java classes. +// See idl_gen_grpc.cpp +bool GenerateJavaGRPC(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate GRPC Python interfaces. +// See idl_gen_grpc.cpp. +bool GeneratePythonGRPC(const Parser &parser, const std::string &path, + const std::string &file_name); + +// Generate GRPC Swift interfaces. +// See idl_gen_grpc.cpp. +extern bool GenerateSwiftGRPC(const Parser &parser, const std::string &path, + const std::string &file_name); + +extern bool GenerateTSGRPC(const Parser &parser, const std::string &path, + const std::string &file_name); +} // namespace flatbuffers + +#endif // FLATBUFFERS_IDL_H_ diff --git a/contrib/libs/flatbuffers/include/flatbuffers/reflection.h b/contrib/libs/flatbuffers/include/flatbuffers/reflection.h new file mode 100644 index 0000000000..d268a3ffea --- /dev/null +++ b/contrib/libs/flatbuffers/include/flatbuffers/reflection.h @@ -0,0 +1,502 @@ +/* + * Copyright 2015 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_REFLECTION_H_ +#define FLATBUFFERS_REFLECTION_H_ + +// This is somewhat of a circular dependency because flatc (and thus this +// file) is needed to generate this header in the first place. +// Should normally not be a problem since it can be generated by the +// previous version of flatc whenever this code needs to change. +// See reflection/generate_code.sh +#include "reflection_generated.h" + +// Helper functionality for reflection. + +namespace flatbuffers { + +// ------------------------- GETTERS ------------------------- + +inline bool IsScalar(reflection::BaseType t) { + return t >= reflection::UType && t <= reflection::Double; +} +inline bool IsInteger(reflection::BaseType t) { + return t >= reflection::UType && t <= reflection::ULong; +} +inline bool IsFloat(reflection::BaseType t) { + return t == reflection::Float || t == reflection::Double; +} +inline bool IsLong(reflection::BaseType t) { + return t == reflection::Long || t == reflection::ULong; +} + +// Size of a basic type, don't use with structs. +inline size_t GetTypeSize(reflection::BaseType base_type) { + // This needs to correspond to the BaseType enum. + static size_t sizes[] = { + 0, // None + 1, // UType + 1, // Bool + 1, // Byte + 1, // UByte + 2, // Short + 2, // UShort + 4, // Int + 4, // UInt + 8, // Long + 8, // ULong + 4, // Float + 8, // Double + 4, // String + 4, // Vector + 4, // Obj + 4, // Union + 0, // Array. Only used in structs. 0 was chosen to prevent out-of-bounds + // errors. + + 0 // MaxBaseType. This must be kept the last entry in this array. + }; + static_assert(sizeof(sizes) / sizeof(size_t) == reflection::MaxBaseType + 1, + "Size of sizes[] array does not match the count of BaseType " + "enum values."); + return sizes[base_type]; +} + +// Same as above, but now correctly returns the size of a struct if +// the field (or vector element) is a struct. +inline size_t GetTypeSizeInline(reflection::BaseType base_type, int type_index, + const reflection::Schema &schema) { + if (base_type == reflection::Obj && + schema.objects()->Get(type_index)->is_struct()) { + return schema.objects()->Get(type_index)->bytesize(); + } else { + return GetTypeSize(base_type); + } +} + +// Get the root, regardless of what type it is. +inline Table *GetAnyRoot(uint8_t *flatbuf) { + return GetMutableRoot<Table>(flatbuf); +} +inline const Table *GetAnyRoot(const uint8_t *flatbuf) { + return GetRoot<Table>(flatbuf); +} + +// Get a field's default, if you know it's an integer, and its exact type. +template<typename T> T GetFieldDefaultI(const reflection::Field &field) { + FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type())); + return static_cast<T>(field.default_integer()); +} + +// Get a field's default, if you know it's floating point and its exact type. +template<typename T> T GetFieldDefaultF(const reflection::Field &field) { + FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type())); + return static_cast<T>(field.default_real()); +} + +// Get a field, if you know it's an integer, and its exact type. +template<typename T> +T GetFieldI(const Table &table, const reflection::Field &field) { + FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type())); + return table.GetField<T>(field.offset(), + static_cast<T>(field.default_integer())); +} + +// Get a field, if you know it's floating point and its exact type. +template<typename T> +T GetFieldF(const Table &table, const reflection::Field &field) { + FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(field.type()->base_type())); + return table.GetField<T>(field.offset(), + static_cast<T>(field.default_real())); +} + +// Get a field, if you know it's a string. +inline const String *GetFieldS(const Table &table, + const reflection::Field &field) { + FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::String); + return table.GetPointer<const String *>(field.offset()); +} + +// Get a field, if you know it's a vector. +template<typename T> +Vector<T> *GetFieldV(const Table &table, const reflection::Field &field) { + FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Vector && + sizeof(T) == GetTypeSize(field.type()->element())); + return table.GetPointer<Vector<T> *>(field.offset()); +} + +// Get a field, if you know it's a vector, generically. +// To actually access elements, use the return value together with +// field.type()->element() in any of GetAnyVectorElemI below etc. +inline VectorOfAny *GetFieldAnyV(const Table &table, + const reflection::Field &field) { + return table.GetPointer<VectorOfAny *>(field.offset()); +} + +// Get a field, if you know it's a table. +inline Table *GetFieldT(const Table &table, const reflection::Field &field) { + FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj || + field.type()->base_type() == reflection::Union); + return table.GetPointer<Table *>(field.offset()); +} + +// Get a field, if you know it's a struct. +inline const Struct *GetFieldStruct(const Table &table, + const reflection::Field &field) { + // TODO: This does NOT check if the field is a table or struct, but we'd need + // access to the schema to check the is_struct flag. + FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj); + return table.GetStruct<const Struct *>(field.offset()); +} + +// Get a structure's field, if you know it's a struct. +inline const Struct *GetFieldStruct(const Struct &structure, + const reflection::Field &field) { + FLATBUFFERS_ASSERT(field.type()->base_type() == reflection::Obj); + return structure.GetStruct<const Struct *>(field.offset()); +} + +// Raw helper functions used below: get any value in memory as a 64bit int, a +// double or a string. +// All scalars get static_cast to an int64_t, strings use strtoull, every other +// data type returns 0. +int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data); +// All scalars static cast to double, strings use strtod, every other data +// type is 0.0. +double GetAnyValueF(reflection::BaseType type, const uint8_t *data); +// All scalars converted using stringstream, strings as-is, and all other +// data types provide some level of debug-pretty-printing. +std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data, + const reflection::Schema *schema, int type_index); + +// Get any table field as a 64bit int, regardless of what type it is. +inline int64_t GetAnyFieldI(const Table &table, + const reflection::Field &field) { + auto field_ptr = table.GetAddressOf(field.offset()); + return field_ptr ? GetAnyValueI(field.type()->base_type(), field_ptr) + : field.default_integer(); +} + +// Get any table field as a double, regardless of what type it is. +inline double GetAnyFieldF(const Table &table, const reflection::Field &field) { + auto field_ptr = table.GetAddressOf(field.offset()); + return field_ptr ? GetAnyValueF(field.type()->base_type(), field_ptr) + : field.default_real(); +} + +// Get any table field as a string, regardless of what type it is. +// You may pass nullptr for the schema if you don't care to have fields that +// are of table type pretty-printed. +inline std::string GetAnyFieldS(const Table &table, + const reflection::Field &field, + const reflection::Schema *schema) { + auto field_ptr = table.GetAddressOf(field.offset()); + return field_ptr ? GetAnyValueS(field.type()->base_type(), field_ptr, schema, + field.type()->index()) + : ""; +} + +// Get any struct field as a 64bit int, regardless of what type it is. +inline int64_t GetAnyFieldI(const Struct &st, const reflection::Field &field) { + return GetAnyValueI(field.type()->base_type(), + st.GetAddressOf(field.offset())); +} + +// Get any struct field as a double, regardless of what type it is. +inline double GetAnyFieldF(const Struct &st, const reflection::Field &field) { + return GetAnyValueF(field.type()->base_type(), + st.GetAddressOf(field.offset())); +} + +// Get any struct field as a string, regardless of what type it is. +inline std::string GetAnyFieldS(const Struct &st, + const reflection::Field &field) { + return GetAnyValueS(field.type()->base_type(), + st.GetAddressOf(field.offset()), nullptr, -1); +} + +// Get any vector element as a 64bit int, regardless of what type it is. +inline int64_t GetAnyVectorElemI(const VectorOfAny *vec, + reflection::BaseType elem_type, size_t i) { + return GetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i); +} + +// Get any vector element as a double, regardless of what type it is. +inline double GetAnyVectorElemF(const VectorOfAny *vec, + reflection::BaseType elem_type, size_t i) { + return GetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i); +} + +// Get any vector element as a string, regardless of what type it is. +inline std::string GetAnyVectorElemS(const VectorOfAny *vec, + reflection::BaseType elem_type, size_t i) { + return GetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i, + nullptr, -1); +} + +// Get a vector element that's a table/string/vector from a generic vector. +// Pass Table/String/VectorOfAny as template parameter. +// Warning: does no typechecking. +template<typename T> +T *GetAnyVectorElemPointer(const VectorOfAny *vec, size_t i) { + auto elem_ptr = vec->Data() + sizeof(uoffset_t) * i; + return reinterpret_cast<T *>(elem_ptr + ReadScalar<uoffset_t>(elem_ptr)); +} + +// Get the inline-address of a vector element. Useful for Structs (pass Struct +// as template arg), or being able to address a range of scalars in-line. +// Get elem_size from GetTypeSizeInline(). +// Note: little-endian data on all platforms, use EndianScalar() instead of +// raw pointer access with scalars). +template<typename T> +T *GetAnyVectorElemAddressOf(const VectorOfAny *vec, size_t i, + size_t elem_size) { + return reinterpret_cast<T *>(vec->Data() + elem_size * i); +} + +// Similarly, for elements of tables. +template<typename T> +T *GetAnyFieldAddressOf(const Table &table, const reflection::Field &field) { + return reinterpret_cast<T *>(table.GetAddressOf(field.offset())); +} + +// Similarly, for elements of structs. +template<typename T> +T *GetAnyFieldAddressOf(const Struct &st, const reflection::Field &field) { + return reinterpret_cast<T *>(st.GetAddressOf(field.offset())); +} + +// ------------------------- SETTERS ------------------------- + +// Set any scalar field, if you know its exact type. +template<typename T> +bool SetField(Table *table, const reflection::Field &field, T val) { + reflection::BaseType type = field.type()->base_type(); + if (!IsScalar(type)) { return false; } + FLATBUFFERS_ASSERT(sizeof(T) == GetTypeSize(type)); + T def; + if (IsInteger(type)) { + def = GetFieldDefaultI<T>(field); + } else { + FLATBUFFERS_ASSERT(IsFloat(type)); + def = GetFieldDefaultF<T>(field); + } + return table->SetField(field.offset(), val, def); +} + +// Raw helper functions used below: set any value in memory as a 64bit int, a +// double or a string. +// These work for all scalar values, but do nothing for other data types. +// To set a string, see SetString below. +void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val); +void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val); +void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val); + +// Set any table field as a 64bit int, regardless of type what it is. +inline bool SetAnyFieldI(Table *table, const reflection::Field &field, + int64_t val) { + auto field_ptr = table->GetAddressOf(field.offset()); + if (!field_ptr) return val == GetFieldDefaultI<int64_t>(field); + SetAnyValueI(field.type()->base_type(), field_ptr, val); + return true; +} + +// Set any table field as a double, regardless of what type it is. +inline bool SetAnyFieldF(Table *table, const reflection::Field &field, + double val) { + auto field_ptr = table->GetAddressOf(field.offset()); + if (!field_ptr) return val == GetFieldDefaultF<double>(field); + SetAnyValueF(field.type()->base_type(), field_ptr, val); + return true; +} + +// Set any table field as a string, regardless of what type it is. +inline bool SetAnyFieldS(Table *table, const reflection::Field &field, + const char *val) { + auto field_ptr = table->GetAddressOf(field.offset()); + if (!field_ptr) return false; + SetAnyValueS(field.type()->base_type(), field_ptr, val); + return true; +} + +// Set any struct field as a 64bit int, regardless of type what it is. +inline void SetAnyFieldI(Struct *st, const reflection::Field &field, + int64_t val) { + SetAnyValueI(field.type()->base_type(), st->GetAddressOf(field.offset()), + val); +} + +// Set any struct field as a double, regardless of type what it is. +inline void SetAnyFieldF(Struct *st, const reflection::Field &field, + double val) { + SetAnyValueF(field.type()->base_type(), st->GetAddressOf(field.offset()), + val); +} + +// Set any struct field as a string, regardless of type what it is. +inline void SetAnyFieldS(Struct *st, const reflection::Field &field, + const char *val) { + SetAnyValueS(field.type()->base_type(), st->GetAddressOf(field.offset()), + val); +} + +// Set any vector element as a 64bit int, regardless of type what it is. +inline void SetAnyVectorElemI(VectorOfAny *vec, reflection::BaseType elem_type, + size_t i, int64_t val) { + SetAnyValueI(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val); +} + +// Set any vector element as a double, regardless of type what it is. +inline void SetAnyVectorElemF(VectorOfAny *vec, reflection::BaseType elem_type, + size_t i, double val) { + SetAnyValueF(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val); +} + +// Set any vector element as a string, regardless of type what it is. +inline void SetAnyVectorElemS(VectorOfAny *vec, reflection::BaseType elem_type, + size_t i, const char *val) { + SetAnyValueS(elem_type, vec->Data() + GetTypeSize(elem_type) * i, val); +} + +// ------------------------- RESIZING SETTERS ------------------------- + +// "smart" pointer for use with resizing vectors: turns a pointer inside +// a vector into a relative offset, such that it is not affected by resizes. +template<typename T, typename U> class pointer_inside_vector { + public: + pointer_inside_vector(T *ptr, std::vector<U> &vec) + : offset_(reinterpret_cast<uint8_t *>(ptr) - + reinterpret_cast<uint8_t *>(flatbuffers::vector_data(vec))), + vec_(vec) {} + + T *operator*() const { + return reinterpret_cast<T *>( + reinterpret_cast<uint8_t *>(flatbuffers::vector_data(vec_)) + offset_); + } + T *operator->() const { return operator*(); } + + private: + size_t offset_; + std::vector<U> &vec_; +}; + +// Helper to create the above easily without specifying template args. +template<typename T, typename U> +pointer_inside_vector<T, U> piv(T *ptr, std::vector<U> &vec) { + return pointer_inside_vector<T, U>(ptr, vec); +} + +inline const char *UnionTypeFieldSuffix() { return "_type"; } + +// Helper to figure out the actual table type a union refers to. +inline const reflection::Object &GetUnionType( + const reflection::Schema &schema, const reflection::Object &parent, + const reflection::Field &unionfield, const Table &table) { + auto enumdef = schema.enums()->Get(unionfield.type()->index()); + // TODO: this is clumsy and slow, but no other way to find it? + auto type_field = parent.fields()->LookupByKey( + (unionfield.name()->str() + UnionTypeFieldSuffix()).c_str()); + FLATBUFFERS_ASSERT(type_field); + auto union_type = GetFieldI<uint8_t>(table, *type_field); + auto enumval = enumdef->values()->LookupByKey(union_type); + return *enumval->object(); +} + +// Changes the contents of a string inside a FlatBuffer. FlatBuffer must +// live inside a std::vector so we can resize the buffer if needed. +// "str" must live inside "flatbuf" and may be invalidated after this call. +// If your FlatBuffer's root table is not the schema's root table, you should +// pass in your root_table type as well. +void SetString(const reflection::Schema &schema, const std::string &val, + const String *str, std::vector<uint8_t> *flatbuf, + const reflection::Object *root_table = nullptr); + +// Resizes a flatbuffers::Vector inside a FlatBuffer. FlatBuffer must +// live inside a std::vector so we can resize the buffer if needed. +// "vec" must live inside "flatbuf" and may be invalidated after this call. +// If your FlatBuffer's root table is not the schema's root table, you should +// pass in your root_table type as well. +uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize, + const VectorOfAny *vec, uoffset_t num_elems, + uoffset_t elem_size, std::vector<uint8_t> *flatbuf, + const reflection::Object *root_table = nullptr); + +template<typename T> +void ResizeVector(const reflection::Schema &schema, uoffset_t newsize, T val, + const Vector<T> *vec, std::vector<uint8_t> *flatbuf, + const reflection::Object *root_table = nullptr) { + auto delta_elem = static_cast<int>(newsize) - static_cast<int>(vec->size()); + auto newelems = ResizeAnyVector( + schema, newsize, reinterpret_cast<const VectorOfAny *>(vec), vec->size(), + static_cast<uoffset_t>(sizeof(T)), flatbuf, root_table); + // Set new elements to "val". + for (int i = 0; i < delta_elem; i++) { + auto loc = newelems + i * sizeof(T); + auto is_scalar = flatbuffers::is_scalar<T>::value; + if (is_scalar) { + WriteScalar(loc, val); + } else { // struct + *reinterpret_cast<T *>(loc) = val; + } + } +} + +// Adds any new data (in the form of a new FlatBuffer) to an existing +// FlatBuffer. This can be used when any of the above methods are not +// sufficient, in particular for adding new tables and new fields. +// This is potentially slightly less efficient than a FlatBuffer constructed +// in one piece, since the new FlatBuffer doesn't share any vtables with the +// existing one. +// The return value can now be set using Vector::MutateOffset or SetFieldT +// below. +const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf, + const uint8_t *newbuf, size_t newlen); + +inline bool SetFieldT(Table *table, const reflection::Field &field, + const uint8_t *val) { + FLATBUFFERS_ASSERT(sizeof(uoffset_t) == + GetTypeSize(field.type()->base_type())); + return table->SetPointer(field.offset(), val); +} + +// ------------------------- COPYING ------------------------- + +// Generic copying of tables from a FlatBuffer into a FlatBuffer builder. +// Can be used to do any kind of merging/selecting you may want to do out +// of existing buffers. Also useful to reconstruct a whole buffer if the +// above resizing functionality has introduced garbage in a buffer you want +// to remove. +// Note: this does not deal with DAGs correctly. If the table passed forms a +// DAG, the copy will be a tree instead (with duplicates). Strings can be +// shared however, by passing true for use_string_pooling. + +Offset<const Table *> CopyTable(FlatBufferBuilder &fbb, + const reflection::Schema &schema, + const reflection::Object &objectdef, + const Table &table, + bool use_string_pooling = false); + +// Verifies the provided flatbuffer using reflection. +// root should point to the root type for this flatbuffer. +// buf should point to the start of flatbuffer data. +// length specifies the size of the flatbuffer data. +bool Verify(const reflection::Schema &schema, const reflection::Object &root, + const uint8_t *buf, size_t length, uoffset_t max_depth = 64, + uoffset_t max_tables = 1000000); + +} // namespace flatbuffers + +#endif // FLATBUFFERS_REFLECTION_H_ diff --git a/contrib/libs/flatbuffers/include/flatbuffers/reflection_generated.h b/contrib/libs/flatbuffers/include/flatbuffers/reflection_generated.h new file mode 100644 index 0000000000..93dc4b88b7 --- /dev/null +++ b/contrib/libs/flatbuffers/include/flatbuffers/reflection_generated.h @@ -0,0 +1,1278 @@ +// automatically generated by the FlatBuffers compiler, do not modify + + +#ifndef FLATBUFFERS_GENERATED_REFLECTION_REFLECTION_H_ +#define FLATBUFFERS_GENERATED_REFLECTION_REFLECTION_H_ + +#include "flatbuffers.h" + +namespace reflection { + +struct Type; +struct TypeBuilder; + +struct KeyValue; +struct KeyValueBuilder; + +struct EnumVal; +struct EnumValBuilder; + +struct Enum; +struct EnumBuilder; + +struct Field; +struct FieldBuilder; + +struct Object; +struct ObjectBuilder; + +struct RPCCall; +struct RPCCallBuilder; + +struct Service; +struct ServiceBuilder; + +struct Schema; +struct SchemaBuilder; + +enum BaseType { + None = 0, + UType = 1, + Bool = 2, + Byte = 3, + UByte = 4, + Short = 5, + UShort = 6, + Int = 7, + UInt = 8, + Long = 9, + ULong = 10, + Float = 11, + Double = 12, + String = 13, + Vector = 14, + Obj = 15, + Union = 16, + Array = 17, + MaxBaseType = 18 +}; + +inline const BaseType (&EnumValuesBaseType())[19] { + static const BaseType values[] = { + None, + UType, + Bool, + Byte, + UByte, + Short, + UShort, + Int, + UInt, + Long, + ULong, + Float, + Double, + String, + Vector, + Obj, + Union, + Array, + MaxBaseType + }; + return values; +} + +inline const char * const *EnumNamesBaseType() { + static const char * const names[20] = { + "None", + "UType", + "Bool", + "Byte", + "UByte", + "Short", + "UShort", + "Int", + "UInt", + "Long", + "ULong", + "Float", + "Double", + "String", + "Vector", + "Obj", + "Union", + "Array", + "MaxBaseType", + nullptr + }; + return names; +} + +inline const char *EnumNameBaseType(BaseType e) { + if (flatbuffers::IsOutRange(e, None, MaxBaseType)) return ""; + const size_t index = static_cast<size_t>(e); + return EnumNamesBaseType()[index]; +} + +enum AdvancedFeatures { + AdvancedArrayFeatures = 1ULL, + AdvancedUnionFeatures = 2ULL, + OptionalScalars = 4ULL, + DefaultVectorsAndStrings = 8ULL +}; + +inline const AdvancedFeatures (&EnumValuesAdvancedFeatures())[4] { + static const AdvancedFeatures values[] = { + AdvancedArrayFeatures, + AdvancedUnionFeatures, + OptionalScalars, + DefaultVectorsAndStrings + }; + return values; +} + +inline const char * const *EnumNamesAdvancedFeatures() { + static const char * const names[9] = { + "AdvancedArrayFeatures", + "AdvancedUnionFeatures", + "", + "OptionalScalars", + "", + "", + "", + "DefaultVectorsAndStrings", + nullptr + }; + return names; +} + +inline const char *EnumNameAdvancedFeatures(AdvancedFeatures e) { + if (flatbuffers::IsOutRange(e, AdvancedArrayFeatures, DefaultVectorsAndStrings)) return ""; + const size_t index = static_cast<size_t>(e) - static_cast<size_t>(AdvancedArrayFeatures); + return EnumNamesAdvancedFeatures()[index]; +} + +struct Type FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef TypeBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_BASE_TYPE = 4, + VT_ELEMENT = 6, + VT_INDEX = 8, + VT_FIXED_LENGTH = 10 + }; + reflection::BaseType base_type() const { + return static_cast<reflection::BaseType>(GetField<int8_t>(VT_BASE_TYPE, 0)); + } + reflection::BaseType element() const { + return static_cast<reflection::BaseType>(GetField<int8_t>(VT_ELEMENT, 0)); + } + int32_t index() const { + return GetField<int32_t>(VT_INDEX, -1); + } + uint16_t fixed_length() const { + return GetField<uint16_t>(VT_FIXED_LENGTH, 0); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyField<int8_t>(verifier, VT_BASE_TYPE) && + VerifyField<int8_t>(verifier, VT_ELEMENT) && + VerifyField<int32_t>(verifier, VT_INDEX) && + VerifyField<uint16_t>(verifier, VT_FIXED_LENGTH) && + verifier.EndTable(); + } +}; + +struct TypeBuilder { + typedef Type Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_base_type(reflection::BaseType base_type) { + fbb_.AddElement<int8_t>(Type::VT_BASE_TYPE, static_cast<int8_t>(base_type), 0); + } + void add_element(reflection::BaseType element) { + fbb_.AddElement<int8_t>(Type::VT_ELEMENT, static_cast<int8_t>(element), 0); + } + void add_index(int32_t index) { + fbb_.AddElement<int32_t>(Type::VT_INDEX, index, -1); + } + void add_fixed_length(uint16_t fixed_length) { + fbb_.AddElement<uint16_t>(Type::VT_FIXED_LENGTH, fixed_length, 0); + } + explicit TypeBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset<Type> Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset<Type>(end); + return o; + } +}; + +inline flatbuffers::Offset<Type> CreateType( + flatbuffers::FlatBufferBuilder &_fbb, + reflection::BaseType base_type = reflection::None, + reflection::BaseType element = reflection::None, + int32_t index = -1, + uint16_t fixed_length = 0) { + TypeBuilder builder_(_fbb); + builder_.add_index(index); + builder_.add_fixed_length(fixed_length); + builder_.add_element(element); + builder_.add_base_type(base_type); + return builder_.Finish(); +} + +struct KeyValue FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef KeyValueBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_KEY = 4, + VT_VALUE = 6 + }; + const flatbuffers::String *key() const { + return GetPointer<const flatbuffers::String *>(VT_KEY); + } + bool KeyCompareLessThan(const KeyValue *o) const { + return *key() < *o->key(); + } + int KeyCompareWithValue(const char *val) const { + return strcmp(key()->c_str(), val); + } + const flatbuffers::String *value() const { + return GetPointer<const flatbuffers::String *>(VT_VALUE); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffsetRequired(verifier, VT_KEY) && + verifier.VerifyString(key()) && + VerifyOffset(verifier, VT_VALUE) && + verifier.VerifyString(value()) && + verifier.EndTable(); + } +}; + +struct KeyValueBuilder { + typedef KeyValue Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_key(flatbuffers::Offset<flatbuffers::String> key) { + fbb_.AddOffset(KeyValue::VT_KEY, key); + } + void add_value(flatbuffers::Offset<flatbuffers::String> value) { + fbb_.AddOffset(KeyValue::VT_VALUE, value); + } + explicit KeyValueBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset<KeyValue> Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset<KeyValue>(end); + fbb_.Required(o, KeyValue::VT_KEY); + return o; + } +}; + +inline flatbuffers::Offset<KeyValue> CreateKeyValue( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset<flatbuffers::String> key = 0, + flatbuffers::Offset<flatbuffers::String> value = 0) { + KeyValueBuilder builder_(_fbb); + builder_.add_value(value); + builder_.add_key(key); + return builder_.Finish(); +} + +inline flatbuffers::Offset<KeyValue> CreateKeyValueDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *key = nullptr, + const char *value = nullptr) { + auto key__ = key ? _fbb.CreateString(key) : 0; + auto value__ = value ? _fbb.CreateString(value) : 0; + return reflection::CreateKeyValue( + _fbb, + key__, + value__); +} + +struct EnumVal FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef EnumValBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_VALUE = 6, + VT_OBJECT = 8, + VT_UNION_TYPE = 10, + VT_DOCUMENTATION = 12 + }; + const flatbuffers::String *name() const { + return GetPointer<const flatbuffers::String *>(VT_NAME); + } + int64_t value() const { + return GetField<int64_t>(VT_VALUE, 0); + } + bool KeyCompareLessThan(const EnumVal *o) const { + return value() < o->value(); + } + int KeyCompareWithValue(int64_t val) const { + return static_cast<int>(value() > val) - static_cast<int>(value() < val); + } + const reflection::Object *object() const { + return GetPointer<const reflection::Object *>(VT_OBJECT); + } + const reflection::Type *union_type() const { + return GetPointer<const reflection::Type *>(VT_UNION_TYPE); + } + const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const { + return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffsetRequired(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyField<int64_t>(verifier, VT_VALUE) && + VerifyOffset(verifier, VT_OBJECT) && + verifier.VerifyTable(object()) && + VerifyOffset(verifier, VT_UNION_TYPE) && + verifier.VerifyTable(union_type()) && + VerifyOffset(verifier, VT_DOCUMENTATION) && + verifier.VerifyVector(documentation()) && + verifier.VerifyVectorOfStrings(documentation()) && + verifier.EndTable(); + } +}; + +struct EnumValBuilder { + typedef EnumVal Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_name(flatbuffers::Offset<flatbuffers::String> name) { + fbb_.AddOffset(EnumVal::VT_NAME, name); + } + void add_value(int64_t value) { + fbb_.AddElement<int64_t>(EnumVal::VT_VALUE, value, 0); + } + void add_object(flatbuffers::Offset<reflection::Object> object) { + fbb_.AddOffset(EnumVal::VT_OBJECT, object); + } + void add_union_type(flatbuffers::Offset<reflection::Type> union_type) { + fbb_.AddOffset(EnumVal::VT_UNION_TYPE, union_type); + } + void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) { + fbb_.AddOffset(EnumVal::VT_DOCUMENTATION, documentation); + } + explicit EnumValBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset<EnumVal> Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset<EnumVal>(end); + fbb_.Required(o, EnumVal::VT_NAME); + return o; + } +}; + +inline flatbuffers::Offset<EnumVal> CreateEnumVal( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset<flatbuffers::String> name = 0, + int64_t value = 0, + flatbuffers::Offset<reflection::Object> object = 0, + flatbuffers::Offset<reflection::Type> union_type = 0, + flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) { + EnumValBuilder builder_(_fbb); + builder_.add_value(value); + builder_.add_documentation(documentation); + builder_.add_union_type(union_type); + builder_.add_object(object); + builder_.add_name(name); + return builder_.Finish(); +} + +inline flatbuffers::Offset<EnumVal> CreateEnumValDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *name = nullptr, + int64_t value = 0, + flatbuffers::Offset<reflection::Object> object = 0, + flatbuffers::Offset<reflection::Type> union_type = 0, + const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) { + auto name__ = name ? _fbb.CreateString(name) : 0; + auto documentation__ = documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0; + return reflection::CreateEnumVal( + _fbb, + name__, + value, + object, + union_type, + documentation__); +} + +struct Enum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef EnumBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_VALUES = 6, + VT_IS_UNION = 8, + VT_UNDERLYING_TYPE = 10, + VT_ATTRIBUTES = 12, + VT_DOCUMENTATION = 14 + }; + const flatbuffers::String *name() const { + return GetPointer<const flatbuffers::String *>(VT_NAME); + } + bool KeyCompareLessThan(const Enum *o) const { + return *name() < *o->name(); + } + int KeyCompareWithValue(const char *val) const { + return strcmp(name()->c_str(), val); + } + const flatbuffers::Vector<flatbuffers::Offset<reflection::EnumVal>> *values() const { + return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::EnumVal>> *>(VT_VALUES); + } + bool is_union() const { + return GetField<uint8_t>(VT_IS_UNION, 0) != 0; + } + const reflection::Type *underlying_type() const { + return GetPointer<const reflection::Type *>(VT_UNDERLYING_TYPE); + } + const flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>> *attributes() const { + return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>> *>(VT_ATTRIBUTES); + } + const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const { + return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffsetRequired(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyOffsetRequired(verifier, VT_VALUES) && + verifier.VerifyVector(values()) && + verifier.VerifyVectorOfTables(values()) && + VerifyField<uint8_t>(verifier, VT_IS_UNION) && + VerifyOffsetRequired(verifier, VT_UNDERLYING_TYPE) && + verifier.VerifyTable(underlying_type()) && + VerifyOffset(verifier, VT_ATTRIBUTES) && + verifier.VerifyVector(attributes()) && + verifier.VerifyVectorOfTables(attributes()) && + VerifyOffset(verifier, VT_DOCUMENTATION) && + verifier.VerifyVector(documentation()) && + verifier.VerifyVectorOfStrings(documentation()) && + verifier.EndTable(); + } +}; + +struct EnumBuilder { + typedef Enum Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_name(flatbuffers::Offset<flatbuffers::String> name) { + fbb_.AddOffset(Enum::VT_NAME, name); + } + void add_values(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::EnumVal>>> values) { + fbb_.AddOffset(Enum::VT_VALUES, values); + } + void add_is_union(bool is_union) { + fbb_.AddElement<uint8_t>(Enum::VT_IS_UNION, static_cast<uint8_t>(is_union), 0); + } + void add_underlying_type(flatbuffers::Offset<reflection::Type> underlying_type) { + fbb_.AddOffset(Enum::VT_UNDERLYING_TYPE, underlying_type); + } + void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes) { + fbb_.AddOffset(Enum::VT_ATTRIBUTES, attributes); + } + void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) { + fbb_.AddOffset(Enum::VT_DOCUMENTATION, documentation); + } + explicit EnumBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset<Enum> Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset<Enum>(end); + fbb_.Required(o, Enum::VT_NAME); + fbb_.Required(o, Enum::VT_VALUES); + fbb_.Required(o, Enum::VT_UNDERLYING_TYPE); + return o; + } +}; + +inline flatbuffers::Offset<Enum> CreateEnum( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset<flatbuffers::String> name = 0, + flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::EnumVal>>> values = 0, + bool is_union = false, + flatbuffers::Offset<reflection::Type> underlying_type = 0, + flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes = 0, + flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) { + EnumBuilder builder_(_fbb); + builder_.add_documentation(documentation); + builder_.add_attributes(attributes); + builder_.add_underlying_type(underlying_type); + builder_.add_values(values); + builder_.add_name(name); + builder_.add_is_union(is_union); + return builder_.Finish(); +} + +inline flatbuffers::Offset<Enum> CreateEnumDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *name = nullptr, + std::vector<flatbuffers::Offset<reflection::EnumVal>> *values = nullptr, + bool is_union = false, + flatbuffers::Offset<reflection::Type> underlying_type = 0, + std::vector<flatbuffers::Offset<reflection::KeyValue>> *attributes = nullptr, + const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) { + auto name__ = name ? _fbb.CreateString(name) : 0; + auto values__ = values ? _fbb.CreateVectorOfSortedTables<reflection::EnumVal>(values) : 0; + auto attributes__ = attributes ? _fbb.CreateVectorOfSortedTables<reflection::KeyValue>(attributes) : 0; + auto documentation__ = documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0; + return reflection::CreateEnum( + _fbb, + name__, + values__, + is_union, + underlying_type, + attributes__, + documentation__); +} + +struct Field FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef FieldBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_TYPE = 6, + VT_ID = 8, + VT_OFFSET = 10, + VT_DEFAULT_INTEGER = 12, + VT_DEFAULT_REAL = 14, + VT_DEPRECATED = 16, + VT_REQUIRED = 18, + VT_KEY = 20, + VT_ATTRIBUTES = 22, + VT_DOCUMENTATION = 24, + VT_OPTIONAL = 26 + }; + const flatbuffers::String *name() const { + return GetPointer<const flatbuffers::String *>(VT_NAME); + } + bool KeyCompareLessThan(const Field *o) const { + return *name() < *o->name(); + } + int KeyCompareWithValue(const char *val) const { + return strcmp(name()->c_str(), val); + } + const reflection::Type *type() const { + return GetPointer<const reflection::Type *>(VT_TYPE); + } + uint16_t id() const { + return GetField<uint16_t>(VT_ID, 0); + } + uint16_t offset() const { + return GetField<uint16_t>(VT_OFFSET, 0); + } + int64_t default_integer() const { + return GetField<int64_t>(VT_DEFAULT_INTEGER, 0); + } + double default_real() const { + return GetField<double>(VT_DEFAULT_REAL, 0.0); + } + bool deprecated() const { + return GetField<uint8_t>(VT_DEPRECATED, 0) != 0; + } + bool required() const { + return GetField<uint8_t>(VT_REQUIRED, 0) != 0; + } + bool key() const { + return GetField<uint8_t>(VT_KEY, 0) != 0; + } + const flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>> *attributes() const { + return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>> *>(VT_ATTRIBUTES); + } + const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const { + return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION); + } + bool optional() const { + return GetField<uint8_t>(VT_OPTIONAL, 0) != 0; + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffsetRequired(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyOffsetRequired(verifier, VT_TYPE) && + verifier.VerifyTable(type()) && + VerifyField<uint16_t>(verifier, VT_ID) && + VerifyField<uint16_t>(verifier, VT_OFFSET) && + VerifyField<int64_t>(verifier, VT_DEFAULT_INTEGER) && + VerifyField<double>(verifier, VT_DEFAULT_REAL) && + VerifyField<uint8_t>(verifier, VT_DEPRECATED) && + VerifyField<uint8_t>(verifier, VT_REQUIRED) && + VerifyField<uint8_t>(verifier, VT_KEY) && + VerifyOffset(verifier, VT_ATTRIBUTES) && + verifier.VerifyVector(attributes()) && + verifier.VerifyVectorOfTables(attributes()) && + VerifyOffset(verifier, VT_DOCUMENTATION) && + verifier.VerifyVector(documentation()) && + verifier.VerifyVectorOfStrings(documentation()) && + VerifyField<uint8_t>(verifier, VT_OPTIONAL) && + verifier.EndTable(); + } +}; + +struct FieldBuilder { + typedef Field Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_name(flatbuffers::Offset<flatbuffers::String> name) { + fbb_.AddOffset(Field::VT_NAME, name); + } + void add_type(flatbuffers::Offset<reflection::Type> type) { + fbb_.AddOffset(Field::VT_TYPE, type); + } + void add_id(uint16_t id) { + fbb_.AddElement<uint16_t>(Field::VT_ID, id, 0); + } + void add_offset(uint16_t offset) { + fbb_.AddElement<uint16_t>(Field::VT_OFFSET, offset, 0); + } + void add_default_integer(int64_t default_integer) { + fbb_.AddElement<int64_t>(Field::VT_DEFAULT_INTEGER, default_integer, 0); + } + void add_default_real(double default_real) { + fbb_.AddElement<double>(Field::VT_DEFAULT_REAL, default_real, 0.0); + } + void add_deprecated(bool deprecated) { + fbb_.AddElement<uint8_t>(Field::VT_DEPRECATED, static_cast<uint8_t>(deprecated), 0); + } + void add_required(bool required) { + fbb_.AddElement<uint8_t>(Field::VT_REQUIRED, static_cast<uint8_t>(required), 0); + } + void add_key(bool key) { + fbb_.AddElement<uint8_t>(Field::VT_KEY, static_cast<uint8_t>(key), 0); + } + void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes) { + fbb_.AddOffset(Field::VT_ATTRIBUTES, attributes); + } + void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) { + fbb_.AddOffset(Field::VT_DOCUMENTATION, documentation); + } + void add_optional(bool optional) { + fbb_.AddElement<uint8_t>(Field::VT_OPTIONAL, static_cast<uint8_t>(optional), 0); + } + explicit FieldBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset<Field> Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset<Field>(end); + fbb_.Required(o, Field::VT_NAME); + fbb_.Required(o, Field::VT_TYPE); + return o; + } +}; + +inline flatbuffers::Offset<Field> CreateField( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset<flatbuffers::String> name = 0, + flatbuffers::Offset<reflection::Type> type = 0, + uint16_t id = 0, + uint16_t offset = 0, + int64_t default_integer = 0, + double default_real = 0.0, + bool deprecated = false, + bool required = false, + bool key = false, + flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes = 0, + flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0, + bool optional = false) { + FieldBuilder builder_(_fbb); + builder_.add_default_real(default_real); + builder_.add_default_integer(default_integer); + builder_.add_documentation(documentation); + builder_.add_attributes(attributes); + builder_.add_type(type); + builder_.add_name(name); + builder_.add_offset(offset); + builder_.add_id(id); + builder_.add_optional(optional); + builder_.add_key(key); + builder_.add_required(required); + builder_.add_deprecated(deprecated); + return builder_.Finish(); +} + +inline flatbuffers::Offset<Field> CreateFieldDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *name = nullptr, + flatbuffers::Offset<reflection::Type> type = 0, + uint16_t id = 0, + uint16_t offset = 0, + int64_t default_integer = 0, + double default_real = 0.0, + bool deprecated = false, + bool required = false, + bool key = false, + std::vector<flatbuffers::Offset<reflection::KeyValue>> *attributes = nullptr, + const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr, + bool optional = false) { + auto name__ = name ? _fbb.CreateString(name) : 0; + auto attributes__ = attributes ? _fbb.CreateVectorOfSortedTables<reflection::KeyValue>(attributes) : 0; + auto documentation__ = documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0; + return reflection::CreateField( + _fbb, + name__, + type, + id, + offset, + default_integer, + default_real, + deprecated, + required, + key, + attributes__, + documentation__, + optional); +} + +struct Object FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ObjectBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_FIELDS = 6, + VT_IS_STRUCT = 8, + VT_MINALIGN = 10, + VT_BYTESIZE = 12, + VT_ATTRIBUTES = 14, + VT_DOCUMENTATION = 16 + }; + const flatbuffers::String *name() const { + return GetPointer<const flatbuffers::String *>(VT_NAME); + } + bool KeyCompareLessThan(const Object *o) const { + return *name() < *o->name(); + } + int KeyCompareWithValue(const char *val) const { + return strcmp(name()->c_str(), val); + } + const flatbuffers::Vector<flatbuffers::Offset<reflection::Field>> *fields() const { + return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::Field>> *>(VT_FIELDS); + } + bool is_struct() const { + return GetField<uint8_t>(VT_IS_STRUCT, 0) != 0; + } + int32_t minalign() const { + return GetField<int32_t>(VT_MINALIGN, 0); + } + int32_t bytesize() const { + return GetField<int32_t>(VT_BYTESIZE, 0); + } + const flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>> *attributes() const { + return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>> *>(VT_ATTRIBUTES); + } + const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const { + return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffsetRequired(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyOffsetRequired(verifier, VT_FIELDS) && + verifier.VerifyVector(fields()) && + verifier.VerifyVectorOfTables(fields()) && + VerifyField<uint8_t>(verifier, VT_IS_STRUCT) && + VerifyField<int32_t>(verifier, VT_MINALIGN) && + VerifyField<int32_t>(verifier, VT_BYTESIZE) && + VerifyOffset(verifier, VT_ATTRIBUTES) && + verifier.VerifyVector(attributes()) && + verifier.VerifyVectorOfTables(attributes()) && + VerifyOffset(verifier, VT_DOCUMENTATION) && + verifier.VerifyVector(documentation()) && + verifier.VerifyVectorOfStrings(documentation()) && + verifier.EndTable(); + } +}; + +struct ObjectBuilder { + typedef Object Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_name(flatbuffers::Offset<flatbuffers::String> name) { + fbb_.AddOffset(Object::VT_NAME, name); + } + void add_fields(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::Field>>> fields) { + fbb_.AddOffset(Object::VT_FIELDS, fields); + } + void add_is_struct(bool is_struct) { + fbb_.AddElement<uint8_t>(Object::VT_IS_STRUCT, static_cast<uint8_t>(is_struct), 0); + } + void add_minalign(int32_t minalign) { + fbb_.AddElement<int32_t>(Object::VT_MINALIGN, minalign, 0); + } + void add_bytesize(int32_t bytesize) { + fbb_.AddElement<int32_t>(Object::VT_BYTESIZE, bytesize, 0); + } + void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes) { + fbb_.AddOffset(Object::VT_ATTRIBUTES, attributes); + } + void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) { + fbb_.AddOffset(Object::VT_DOCUMENTATION, documentation); + } + explicit ObjectBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset<Object> Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset<Object>(end); + fbb_.Required(o, Object::VT_NAME); + fbb_.Required(o, Object::VT_FIELDS); + return o; + } +}; + +inline flatbuffers::Offset<Object> CreateObject( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset<flatbuffers::String> name = 0, + flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::Field>>> fields = 0, + bool is_struct = false, + int32_t minalign = 0, + int32_t bytesize = 0, + flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes = 0, + flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) { + ObjectBuilder builder_(_fbb); + builder_.add_documentation(documentation); + builder_.add_attributes(attributes); + builder_.add_bytesize(bytesize); + builder_.add_minalign(minalign); + builder_.add_fields(fields); + builder_.add_name(name); + builder_.add_is_struct(is_struct); + return builder_.Finish(); +} + +inline flatbuffers::Offset<Object> CreateObjectDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *name = nullptr, + std::vector<flatbuffers::Offset<reflection::Field>> *fields = nullptr, + bool is_struct = false, + int32_t minalign = 0, + int32_t bytesize = 0, + std::vector<flatbuffers::Offset<reflection::KeyValue>> *attributes = nullptr, + const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) { + auto name__ = name ? _fbb.CreateString(name) : 0; + auto fields__ = fields ? _fbb.CreateVectorOfSortedTables<reflection::Field>(fields) : 0; + auto attributes__ = attributes ? _fbb.CreateVectorOfSortedTables<reflection::KeyValue>(attributes) : 0; + auto documentation__ = documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0; + return reflection::CreateObject( + _fbb, + name__, + fields__, + is_struct, + minalign, + bytesize, + attributes__, + documentation__); +} + +struct RPCCall FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef RPCCallBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_REQUEST = 6, + VT_RESPONSE = 8, + VT_ATTRIBUTES = 10, + VT_DOCUMENTATION = 12 + }; + const flatbuffers::String *name() const { + return GetPointer<const flatbuffers::String *>(VT_NAME); + } + bool KeyCompareLessThan(const RPCCall *o) const { + return *name() < *o->name(); + } + int KeyCompareWithValue(const char *val) const { + return strcmp(name()->c_str(), val); + } + const reflection::Object *request() const { + return GetPointer<const reflection::Object *>(VT_REQUEST); + } + const reflection::Object *response() const { + return GetPointer<const reflection::Object *>(VT_RESPONSE); + } + const flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>> *attributes() const { + return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>> *>(VT_ATTRIBUTES); + } + const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const { + return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffsetRequired(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyOffsetRequired(verifier, VT_REQUEST) && + verifier.VerifyTable(request()) && + VerifyOffsetRequired(verifier, VT_RESPONSE) && + verifier.VerifyTable(response()) && + VerifyOffset(verifier, VT_ATTRIBUTES) && + verifier.VerifyVector(attributes()) && + verifier.VerifyVectorOfTables(attributes()) && + VerifyOffset(verifier, VT_DOCUMENTATION) && + verifier.VerifyVector(documentation()) && + verifier.VerifyVectorOfStrings(documentation()) && + verifier.EndTable(); + } +}; + +struct RPCCallBuilder { + typedef RPCCall Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_name(flatbuffers::Offset<flatbuffers::String> name) { + fbb_.AddOffset(RPCCall::VT_NAME, name); + } + void add_request(flatbuffers::Offset<reflection::Object> request) { + fbb_.AddOffset(RPCCall::VT_REQUEST, request); + } + void add_response(flatbuffers::Offset<reflection::Object> response) { + fbb_.AddOffset(RPCCall::VT_RESPONSE, response); + } + void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes) { + fbb_.AddOffset(RPCCall::VT_ATTRIBUTES, attributes); + } + void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) { + fbb_.AddOffset(RPCCall::VT_DOCUMENTATION, documentation); + } + explicit RPCCallBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset<RPCCall> Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset<RPCCall>(end); + fbb_.Required(o, RPCCall::VT_NAME); + fbb_.Required(o, RPCCall::VT_REQUEST); + fbb_.Required(o, RPCCall::VT_RESPONSE); + return o; + } +}; + +inline flatbuffers::Offset<RPCCall> CreateRPCCall( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset<flatbuffers::String> name = 0, + flatbuffers::Offset<reflection::Object> request = 0, + flatbuffers::Offset<reflection::Object> response = 0, + flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes = 0, + flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) { + RPCCallBuilder builder_(_fbb); + builder_.add_documentation(documentation); + builder_.add_attributes(attributes); + builder_.add_response(response); + builder_.add_request(request); + builder_.add_name(name); + return builder_.Finish(); +} + +inline flatbuffers::Offset<RPCCall> CreateRPCCallDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *name = nullptr, + flatbuffers::Offset<reflection::Object> request = 0, + flatbuffers::Offset<reflection::Object> response = 0, + std::vector<flatbuffers::Offset<reflection::KeyValue>> *attributes = nullptr, + const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) { + auto name__ = name ? _fbb.CreateString(name) : 0; + auto attributes__ = attributes ? _fbb.CreateVectorOfSortedTables<reflection::KeyValue>(attributes) : 0; + auto documentation__ = documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0; + return reflection::CreateRPCCall( + _fbb, + name__, + request, + response, + attributes__, + documentation__); +} + +struct Service FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef ServiceBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_NAME = 4, + VT_CALLS = 6, + VT_ATTRIBUTES = 8, + VT_DOCUMENTATION = 10 + }; + const flatbuffers::String *name() const { + return GetPointer<const flatbuffers::String *>(VT_NAME); + } + bool KeyCompareLessThan(const Service *o) const { + return *name() < *o->name(); + } + int KeyCompareWithValue(const char *val) const { + return strcmp(name()->c_str(), val); + } + const flatbuffers::Vector<flatbuffers::Offset<reflection::RPCCall>> *calls() const { + return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::RPCCall>> *>(VT_CALLS); + } + const flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>> *attributes() const { + return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>> *>(VT_ATTRIBUTES); + } + const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *documentation() const { + return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_DOCUMENTATION); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffsetRequired(verifier, VT_NAME) && + verifier.VerifyString(name()) && + VerifyOffset(verifier, VT_CALLS) && + verifier.VerifyVector(calls()) && + verifier.VerifyVectorOfTables(calls()) && + VerifyOffset(verifier, VT_ATTRIBUTES) && + verifier.VerifyVector(attributes()) && + verifier.VerifyVectorOfTables(attributes()) && + VerifyOffset(verifier, VT_DOCUMENTATION) && + verifier.VerifyVector(documentation()) && + verifier.VerifyVectorOfStrings(documentation()) && + verifier.EndTable(); + } +}; + +struct ServiceBuilder { + typedef Service Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_name(flatbuffers::Offset<flatbuffers::String> name) { + fbb_.AddOffset(Service::VT_NAME, name); + } + void add_calls(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::RPCCall>>> calls) { + fbb_.AddOffset(Service::VT_CALLS, calls); + } + void add_attributes(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes) { + fbb_.AddOffset(Service::VT_ATTRIBUTES, attributes); + } + void add_documentation(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation) { + fbb_.AddOffset(Service::VT_DOCUMENTATION, documentation); + } + explicit ServiceBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset<Service> Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset<Service>(end); + fbb_.Required(o, Service::VT_NAME); + return o; + } +}; + +inline flatbuffers::Offset<Service> CreateService( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset<flatbuffers::String> name = 0, + flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::RPCCall>>> calls = 0, + flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> attributes = 0, + flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> documentation = 0) { + ServiceBuilder builder_(_fbb); + builder_.add_documentation(documentation); + builder_.add_attributes(attributes); + builder_.add_calls(calls); + builder_.add_name(name); + return builder_.Finish(); +} + +inline flatbuffers::Offset<Service> CreateServiceDirect( + flatbuffers::FlatBufferBuilder &_fbb, + const char *name = nullptr, + std::vector<flatbuffers::Offset<reflection::RPCCall>> *calls = nullptr, + std::vector<flatbuffers::Offset<reflection::KeyValue>> *attributes = nullptr, + const std::vector<flatbuffers::Offset<flatbuffers::String>> *documentation = nullptr) { + auto name__ = name ? _fbb.CreateString(name) : 0; + auto calls__ = calls ? _fbb.CreateVectorOfSortedTables<reflection::RPCCall>(calls) : 0; + auto attributes__ = attributes ? _fbb.CreateVectorOfSortedTables<reflection::KeyValue>(attributes) : 0; + auto documentation__ = documentation ? _fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>(*documentation) : 0; + return reflection::CreateService( + _fbb, + name__, + calls__, + attributes__, + documentation__); +} + +struct Schema FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table { + typedef SchemaBuilder Builder; + enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE { + VT_OBJECTS = 4, + VT_ENUMS = 6, + VT_FILE_IDENT = 8, + VT_FILE_EXT = 10, + VT_ROOT_TABLE = 12, + VT_SERVICES = 14, + VT_ADVANCED_FEATURES = 16 + }; + const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>> *objects() const { + return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::Object>> *>(VT_OBJECTS); + } + const flatbuffers::Vector<flatbuffers::Offset<reflection::Enum>> *enums() const { + return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::Enum>> *>(VT_ENUMS); + } + const flatbuffers::String *file_ident() const { + return GetPointer<const flatbuffers::String *>(VT_FILE_IDENT); + } + const flatbuffers::String *file_ext() const { + return GetPointer<const flatbuffers::String *>(VT_FILE_EXT); + } + const reflection::Object *root_table() const { + return GetPointer<const reflection::Object *>(VT_ROOT_TABLE); + } + const flatbuffers::Vector<flatbuffers::Offset<reflection::Service>> *services() const { + return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<reflection::Service>> *>(VT_SERVICES); + } + reflection::AdvancedFeatures advanced_features() const { + return static_cast<reflection::AdvancedFeatures>(GetField<uint64_t>(VT_ADVANCED_FEATURES, 0)); + } + bool Verify(flatbuffers::Verifier &verifier) const { + return VerifyTableStart(verifier) && + VerifyOffsetRequired(verifier, VT_OBJECTS) && + verifier.VerifyVector(objects()) && + verifier.VerifyVectorOfTables(objects()) && + VerifyOffsetRequired(verifier, VT_ENUMS) && + verifier.VerifyVector(enums()) && + verifier.VerifyVectorOfTables(enums()) && + VerifyOffset(verifier, VT_FILE_IDENT) && + verifier.VerifyString(file_ident()) && + VerifyOffset(verifier, VT_FILE_EXT) && + verifier.VerifyString(file_ext()) && + VerifyOffset(verifier, VT_ROOT_TABLE) && + verifier.VerifyTable(root_table()) && + VerifyOffset(verifier, VT_SERVICES) && + verifier.VerifyVector(services()) && + verifier.VerifyVectorOfTables(services()) && + VerifyField<uint64_t>(verifier, VT_ADVANCED_FEATURES) && + verifier.EndTable(); + } +}; + +struct SchemaBuilder { + typedef Schema Table; + flatbuffers::FlatBufferBuilder &fbb_; + flatbuffers::uoffset_t start_; + void add_objects(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::Object>>> objects) { + fbb_.AddOffset(Schema::VT_OBJECTS, objects); + } + void add_enums(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::Enum>>> enums) { + fbb_.AddOffset(Schema::VT_ENUMS, enums); + } + void add_file_ident(flatbuffers::Offset<flatbuffers::String> file_ident) { + fbb_.AddOffset(Schema::VT_FILE_IDENT, file_ident); + } + void add_file_ext(flatbuffers::Offset<flatbuffers::String> file_ext) { + fbb_.AddOffset(Schema::VT_FILE_EXT, file_ext); + } + void add_root_table(flatbuffers::Offset<reflection::Object> root_table) { + fbb_.AddOffset(Schema::VT_ROOT_TABLE, root_table); + } + void add_services(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::Service>>> services) { + fbb_.AddOffset(Schema::VT_SERVICES, services); + } + void add_advanced_features(reflection::AdvancedFeatures advanced_features) { + fbb_.AddElement<uint64_t>(Schema::VT_ADVANCED_FEATURES, static_cast<uint64_t>(advanced_features), 0); + } + explicit SchemaBuilder(flatbuffers::FlatBufferBuilder &_fbb) + : fbb_(_fbb) { + start_ = fbb_.StartTable(); + } + flatbuffers::Offset<Schema> Finish() { + const auto end = fbb_.EndTable(start_); + auto o = flatbuffers::Offset<Schema>(end); + fbb_.Required(o, Schema::VT_OBJECTS); + fbb_.Required(o, Schema::VT_ENUMS); + return o; + } +}; + +inline flatbuffers::Offset<Schema> CreateSchema( + flatbuffers::FlatBufferBuilder &_fbb, + flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::Object>>> objects = 0, + flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::Enum>>> enums = 0, + flatbuffers::Offset<flatbuffers::String> file_ident = 0, + flatbuffers::Offset<flatbuffers::String> file_ext = 0, + flatbuffers::Offset<reflection::Object> root_table = 0, + flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<reflection::Service>>> services = 0, + reflection::AdvancedFeatures advanced_features = static_cast<reflection::AdvancedFeatures>(0)) { + SchemaBuilder builder_(_fbb); + builder_.add_advanced_features(advanced_features); + builder_.add_services(services); + builder_.add_root_table(root_table); + builder_.add_file_ext(file_ext); + builder_.add_file_ident(file_ident); + builder_.add_enums(enums); + builder_.add_objects(objects); + return builder_.Finish(); +} + +inline flatbuffers::Offset<Schema> CreateSchemaDirect( + flatbuffers::FlatBufferBuilder &_fbb, + std::vector<flatbuffers::Offset<reflection::Object>> *objects = nullptr, + std::vector<flatbuffers::Offset<reflection::Enum>> *enums = nullptr, + const char *file_ident = nullptr, + const char *file_ext = nullptr, + flatbuffers::Offset<reflection::Object> root_table = 0, + std::vector<flatbuffers::Offset<reflection::Service>> *services = nullptr, + reflection::AdvancedFeatures advanced_features = static_cast<reflection::AdvancedFeatures>(0)) { + auto objects__ = objects ? _fbb.CreateVectorOfSortedTables<reflection::Object>(objects) : 0; + auto enums__ = enums ? _fbb.CreateVectorOfSortedTables<reflection::Enum>(enums) : 0; + auto file_ident__ = file_ident ? _fbb.CreateString(file_ident) : 0; + auto file_ext__ = file_ext ? _fbb.CreateString(file_ext) : 0; + auto services__ = services ? _fbb.CreateVectorOfSortedTables<reflection::Service>(services) : 0; + return reflection::CreateSchema( + _fbb, + objects__, + enums__, + file_ident__, + file_ext__, + root_table, + services__, + advanced_features); +} + +inline const reflection::Schema *GetSchema(const void *buf) { + return flatbuffers::GetRoot<reflection::Schema>(buf); +} + +inline const reflection::Schema *GetSizePrefixedSchema(const void *buf) { + return flatbuffers::GetSizePrefixedRoot<reflection::Schema>(buf); +} + +inline const char *SchemaIdentifier() { + return "BFBS"; +} + +inline bool SchemaBufferHasIdentifier(const void *buf) { + return flatbuffers::BufferHasIdentifier( + buf, SchemaIdentifier()); +} + +inline bool VerifySchemaBuffer( + flatbuffers::Verifier &verifier) { + return verifier.VerifyBuffer<reflection::Schema>(SchemaIdentifier()); +} + +inline bool VerifySizePrefixedSchemaBuffer( + flatbuffers::Verifier &verifier) { + return verifier.VerifySizePrefixedBuffer<reflection::Schema>(SchemaIdentifier()); +} + +inline const char *SchemaExtension() { + return "bfbs"; +} + +inline void FinishSchemaBuffer( + flatbuffers::FlatBufferBuilder &fbb, + flatbuffers::Offset<reflection::Schema> root) { + fbb.Finish(root, SchemaIdentifier()); +} + +inline void FinishSizePrefixedSchemaBuffer( + flatbuffers::FlatBufferBuilder &fbb, + flatbuffers::Offset<reflection::Schema> root) { + fbb.FinishSizePrefixed(root, SchemaIdentifier()); +} + +} // namespace reflection + +#endif // FLATBUFFERS_GENERATED_REFLECTION_REFLECTION_H_ diff --git a/contrib/libs/flatbuffers/include/flatbuffers/util.h b/contrib/libs/flatbuffers/include/flatbuffers/util.h new file mode 100644 index 0000000000..4493c561c2 --- /dev/null +++ b/contrib/libs/flatbuffers/include/flatbuffers/util.h @@ -0,0 +1,698 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FLATBUFFERS_UTIL_H_ +#define FLATBUFFERS_UTIL_H_ + +#include <errno.h> + +#include "base.h" +#include "stl_emulation.h" + +#ifndef FLATBUFFERS_PREFER_PRINTF +# include <sstream> +#else // FLATBUFFERS_PREFER_PRINTF +# include <float.h> +# include <stdio.h> +#endif // FLATBUFFERS_PREFER_PRINTF + +#include <iomanip> +#include <string> + +namespace flatbuffers { + +// @locale-independent functions for ASCII characters set. + +// Fast checking that character lies in closed range: [a <= x <= b] +// using one compare (conditional branch) operator. +inline bool check_ascii_range(char x, char a, char b) { + FLATBUFFERS_ASSERT(a <= b); + // (Hacker's Delight): `a <= x <= b` <=> `(x-a) <={u} (b-a)`. + // The x, a, b will be promoted to int and subtracted without overflow. + return static_cast<unsigned int>(x - a) <= static_cast<unsigned int>(b - a); +} + +// Case-insensitive isalpha +inline bool is_alpha(char c) { + // ASCII only: alpha to upper case => reset bit 0x20 (~0x20 = 0xDF). + return check_ascii_range(c & 0xDF, 'a' & 0xDF, 'z' & 0xDF); +} + +// Check for uppercase alpha +inline bool is_alpha_upper(char c) { return check_ascii_range(c, 'A', 'Z'); } + +// Check (case-insensitive) that `c` is equal to alpha. +inline bool is_alpha_char(char c, char alpha) { + FLATBUFFERS_ASSERT(is_alpha(alpha)); + // ASCII only: alpha to upper case => reset bit 0x20 (~0x20 = 0xDF). + return ((c & 0xDF) == (alpha & 0xDF)); +} + +// https://en.cppreference.com/w/cpp/string/byte/isxdigit +// isdigit and isxdigit are the only standard narrow character classification +// functions that are not affected by the currently installed C locale. although +// some implementations (e.g. Microsoft in 1252 codepage) may classify +// additional single-byte characters as digits. +inline bool is_digit(char c) { return check_ascii_range(c, '0', '9'); } + +inline bool is_xdigit(char c) { + // Replace by look-up table. + return is_digit(c) || check_ascii_range(c & 0xDF, 'a' & 0xDF, 'f' & 0xDF); +} + +// Case-insensitive isalnum +inline bool is_alnum(char c) { return is_alpha(c) || is_digit(c); } + +inline char CharToUpper(char c) { + return static_cast<char>(::toupper(static_cast<unsigned char>(c))); +} + +inline char CharToLower(char c) { + return static_cast<char>(::tolower(static_cast<unsigned char>(c))); +} + +// @end-locale-independent functions for ASCII character set + +#ifdef FLATBUFFERS_PREFER_PRINTF +template<typename T> size_t IntToDigitCount(T t) { + size_t digit_count = 0; + // Count the sign for negative numbers + if (t < 0) digit_count++; + // Count a single 0 left of the dot for fractional numbers + if (-1 < t && t < 1) digit_count++; + // Count digits until fractional part + T eps = std::numeric_limits<float>::epsilon(); + while (t <= (-1 + eps) || (1 - eps) <= t) { + t /= 10; + digit_count++; + } + return digit_count; +} + +template<typename T> size_t NumToStringWidth(T t, int precision = 0) { + size_t string_width = IntToDigitCount(t); + // Count the dot for floating point numbers + if (precision) string_width += (precision + 1); + return string_width; +} + +template<typename T> +std::string NumToStringImplWrapper(T t, const char *fmt, int precision = 0) { + size_t string_width = NumToStringWidth(t, precision); + std::string s(string_width, 0x00); + // Allow snprintf to use std::string trailing null to detect buffer overflow + snprintf(const_cast<char *>(s.data()), (s.size() + 1), fmt, string_width, t); + return s; +} +#endif // FLATBUFFERS_PREFER_PRINTF + +// Convert an integer or floating point value to a string. +// In contrast to std::stringstream, "char" values are +// converted to a string of digits, and we don't use scientific notation. +template<typename T> std::string NumToString(T t) { + // clang-format off + + #ifndef FLATBUFFERS_PREFER_PRINTF + std::stringstream ss; + ss << t; + return ss.str(); + #else // FLATBUFFERS_PREFER_PRINTF + auto v = static_cast<long long>(t); + return NumToStringImplWrapper(v, "%.*lld"); + #endif // FLATBUFFERS_PREFER_PRINTF + // clang-format on +} +// Avoid char types used as character data. +template<> inline std::string NumToString<signed char>(signed char t) { + return NumToString(static_cast<int>(t)); +} +template<> inline std::string NumToString<unsigned char>(unsigned char t) { + return NumToString(static_cast<int>(t)); +} +template<> inline std::string NumToString<char>(char t) { + return NumToString(static_cast<int>(t)); +} +#if defined(FLATBUFFERS_CPP98_STL) +template<> inline std::string NumToString<long long>(long long t) { + char buf[21]; // (log((1 << 63) - 1) / log(10)) + 2 + snprintf(buf, sizeof(buf), "%lld", t); + return std::string(buf); +} + +template<> +inline std::string NumToString<unsigned long long>(unsigned long long t) { + char buf[22]; // (log((1 << 63) - 1) / log(10)) + 1 + snprintf(buf, sizeof(buf), "%llu", t); + return std::string(buf); +} +#endif // defined(FLATBUFFERS_CPP98_STL) + +// Special versions for floats/doubles. +template<typename T> std::string FloatToString(T t, int precision) { + // clang-format off + + #ifndef FLATBUFFERS_PREFER_PRINTF + // to_string() prints different numbers of digits for floats depending on + // platform and isn't available on Android, so we use stringstream + std::stringstream ss; + // Use std::fixed to suppress scientific notation. + ss << std::fixed; + // Default precision is 6, we want that to be higher for doubles. + ss << std::setprecision(precision); + ss << t; + auto s = ss.str(); + #else // FLATBUFFERS_PREFER_PRINTF + auto v = static_cast<double>(t); + auto s = NumToStringImplWrapper(v, "%0.*f", precision); + #endif // FLATBUFFERS_PREFER_PRINTF + // clang-format on + // Sadly, std::fixed turns "1" into "1.00000", so here we undo that. + auto p = s.find_last_not_of('0'); + if (p != std::string::npos) { + // Strip trailing zeroes. If it is a whole number, keep one zero. + s.resize(p + (s[p] == '.' ? 2 : 1)); + } + return s; +} + +template<> inline std::string NumToString<double>(double t) { + return FloatToString(t, 12); +} +template<> inline std::string NumToString<float>(float t) { + return FloatToString(t, 6); +} + +// Convert an integer value to a hexadecimal string. +// The returned string length is always xdigits long, prefixed by 0 digits. +// For example, IntToStringHex(0x23, 8) returns the string "00000023". +inline std::string IntToStringHex(int i, int xdigits) { + FLATBUFFERS_ASSERT(i >= 0); + // clang-format off + + #ifndef FLATBUFFERS_PREFER_PRINTF + std::stringstream ss; + ss << std::setw(xdigits) << std::setfill('0') << std::hex << std::uppercase + << i; + return ss.str(); + #else // FLATBUFFERS_PREFER_PRINTF + return NumToStringImplWrapper(i, "%.*X", xdigits); + #endif // FLATBUFFERS_PREFER_PRINTF + // clang-format on +} + +// clang-format off +// Use locale independent functions {strtod_l, strtof_l, strtoll_l, strtoull_l}. +#if defined(FLATBUFFERS_LOCALE_INDEPENDENT) && (FLATBUFFERS_LOCALE_INDEPENDENT > 0) + class ClassicLocale { + #ifdef _MSC_VER + typedef _locale_t locale_type; + #else + typedef locale_t locale_type; // POSIX.1-2008 locale_t type + #endif + ClassicLocale(); + ~ClassicLocale(); + locale_type locale_; + static ClassicLocale instance_; + public: + static locale_type Get() { return instance_.locale_; } + }; + + #ifdef _MSC_VER + #define __strtoull_impl(s, pe, b) _strtoui64_l(s, pe, b, ClassicLocale::Get()) + #define __strtoll_impl(s, pe, b) _strtoi64_l(s, pe, b, ClassicLocale::Get()) + #define __strtod_impl(s, pe) _strtod_l(s, pe, ClassicLocale::Get()) + #define __strtof_impl(s, pe) _strtof_l(s, pe, ClassicLocale::Get()) + #else + #define __strtoull_impl(s, pe, b) strtoull_l(s, pe, b, ClassicLocale::Get()) + #define __strtoll_impl(s, pe, b) strtoll_l(s, pe, b, ClassicLocale::Get()) + #define __strtod_impl(s, pe) strtod_l(s, pe, ClassicLocale::Get()) + #define __strtof_impl(s, pe) strtof_l(s, pe, ClassicLocale::Get()) + #endif +#else + #define __strtod_impl(s, pe) strtod(s, pe) + #define __strtof_impl(s, pe) static_cast<float>(strtod(s, pe)) + #ifdef _MSC_VER + #define __strtoull_impl(s, pe, b) _strtoui64(s, pe, b) + #define __strtoll_impl(s, pe, b) _strtoi64(s, pe, b) + #else + #define __strtoull_impl(s, pe, b) strtoull(s, pe, b) + #define __strtoll_impl(s, pe, b) strtoll(s, pe, b) + #endif +#endif + +inline void strtoval_impl(int64_t *val, const char *str, char **endptr, + int base) { + *val = __strtoll_impl(str, endptr, base); +} + +inline void strtoval_impl(uint64_t *val, const char *str, char **endptr, + int base) { + *val = __strtoull_impl(str, endptr, base); +} + +inline void strtoval_impl(double *val, const char *str, char **endptr) { + *val = __strtod_impl(str, endptr); +} + +// UBSAN: double to float is safe if numeric_limits<float>::is_iec559 is true. +__supress_ubsan__("float-cast-overflow") +inline void strtoval_impl(float *val, const char *str, char **endptr) { + *val = __strtof_impl(str, endptr); +} +#undef __strtoull_impl +#undef __strtoll_impl +#undef __strtod_impl +#undef __strtof_impl +// clang-format on + +// Adaptor for strtoull()/strtoll(). +// Flatbuffers accepts numbers with any count of leading zeros (-009 is -9), +// while strtoll with base=0 interprets first leading zero as octal prefix. +// In future, it is possible to add prefixed 0b0101. +// 1) Checks errno code for overflow condition (out of range). +// 2) If base <= 0, function try to detect base of number by prefix. +// +// Return value (like strtoull and strtoll, but reject partial result): +// - If successful, an integer value corresponding to the str is returned. +// - If full string conversion can't be performed, 0 is returned. +// - If the converted value falls out of range of corresponding return type, a +// range error occurs. In this case value MAX(T)/MIN(T) is returned. +template<typename T> +inline bool StringToIntegerImpl(T *val, const char *const str, + const int base = 0, + const bool check_errno = true) { + // T is int64_t or uint64_T + FLATBUFFERS_ASSERT(str); + if (base <= 0) { + auto s = str; + while (*s && !is_digit(*s)) s++; + if (s[0] == '0' && is_alpha_char(s[1], 'X')) + return StringToIntegerImpl(val, str, 16, check_errno); + // if a prefix not match, try base=10 + return StringToIntegerImpl(val, str, 10, check_errno); + } else { + if (check_errno) errno = 0; // clear thread-local errno + auto endptr = str; + strtoval_impl(val, str, const_cast<char **>(&endptr), base); + if ((*endptr != '\0') || (endptr == str)) { + *val = 0; // erase partial result + return false; // invalid string + } + // errno is out-of-range, return MAX/MIN + if (check_errno && errno) return false; + return true; + } +} + +template<typename T> +inline bool StringToFloatImpl(T *val, const char *const str) { + // Type T must be either float or double. + FLATBUFFERS_ASSERT(str && val); + auto end = str; + strtoval_impl(val, str, const_cast<char **>(&end)); + auto done = (end != str) && (*end == '\0'); + if (!done) *val = 0; // erase partial result + return done; +} + +// Convert a string to an instance of T. +// Return value (matched with StringToInteger64Impl and strtod): +// - If successful, a numeric value corresponding to the str is returned. +// - If full string conversion can't be performed, 0 is returned. +// - If the converted value falls out of range of corresponding return type, a +// range error occurs. In this case value MAX(T)/MIN(T) is returned. +template<typename T> inline bool StringToNumber(const char *s, T *val) { + // Assert on `unsigned long` and `signed long` on LP64. + // If it is necessary, it could be solved with flatbuffers::enable_if<B,T>. + static_assert(sizeof(T) < sizeof(int64_t), "unexpected type T"); + FLATBUFFERS_ASSERT(s && val); + int64_t i64; + // The errno check isn't needed, will return MAX/MIN on overflow. + if (StringToIntegerImpl(&i64, s, 0, false)) { + const int64_t max = (flatbuffers::numeric_limits<T>::max)(); + const int64_t min = flatbuffers::numeric_limits<T>::lowest(); + if (i64 > max) { + *val = static_cast<T>(max); + return false; + } + if (i64 < min) { + // For unsigned types return max to distinguish from + // "no conversion can be performed" when 0 is returned. + *val = static_cast<T>(flatbuffers::is_unsigned<T>::value ? max : min); + return false; + } + *val = static_cast<T>(i64); + return true; + } + *val = 0; + return false; +} + +template<> inline bool StringToNumber<int64_t>(const char *str, int64_t *val) { + return StringToIntegerImpl(val, str); +} + +template<> +inline bool StringToNumber<uint64_t>(const char *str, uint64_t *val) { + if (!StringToIntegerImpl(val, str)) return false; + // The strtoull accepts negative numbers: + // If the minus sign was part of the input sequence, the numeric value + // calculated from the sequence of digits is negated as if by unary minus + // in the result type, which applies unsigned integer wraparound rules. + // Fix this behaviour (except -0). + if (*val) { + auto s = str; + while (*s && !is_digit(*s)) s++; + s = (s > str) ? (s - 1) : s; // step back to one symbol + if (*s == '-') { + // For unsigned types return the max to distinguish from + // "no conversion can be performed". + *val = (flatbuffers::numeric_limits<uint64_t>::max)(); + return false; + } + } + return true; +} + +template<> inline bool StringToNumber(const char *s, float *val) { + return StringToFloatImpl(val, s); +} + +template<> inline bool StringToNumber(const char *s, double *val) { + return StringToFloatImpl(val, s); +} + +inline int64_t StringToInt(const char *s, int base = 10) { + int64_t val; + return StringToIntegerImpl(&val, s, base) ? val : 0; +} + +inline uint64_t StringToUInt(const char *s, int base = 10) { + uint64_t val; + return StringToIntegerImpl(&val, s, base) ? val : 0; +} + +typedef bool (*LoadFileFunction)(const char *filename, bool binary, + std::string *dest); +typedef bool (*FileExistsFunction)(const char *filename); + +LoadFileFunction SetLoadFileFunction(LoadFileFunction load_file_function); + +FileExistsFunction SetFileExistsFunction( + FileExistsFunction file_exists_function); + +// Check if file "name" exists. +bool FileExists(const char *name); + +// Check if "name" exists and it is also a directory. +bool DirExists(const char *name); + +// Load file "name" into "buf" returning true if successful +// false otherwise. If "binary" is false data is read +// using ifstream's text mode, otherwise data is read with +// no transcoding. +bool LoadFile(const char *name, bool binary, std::string *buf); + +// Save data "buf" of length "len" bytes into a file +// "name" returning true if successful, false otherwise. +// If "binary" is false data is written using ifstream's +// text mode, otherwise data is written with no +// transcoding. +bool SaveFile(const char *name, const char *buf, size_t len, bool binary); + +// Save data "buf" into file "name" returning true if +// successful, false otherwise. If "binary" is false +// data is written using ifstream's text mode, otherwise +// data is written with no transcoding. +inline bool SaveFile(const char *name, const std::string &buf, bool binary) { + return SaveFile(name, buf.c_str(), buf.size(), binary); +} + +// Functionality for minimalistic portable path handling. + +// The functions below behave correctly regardless of whether posix ('/') or +// Windows ('/' or '\\') separators are used. + +// Any new separators inserted are always posix. +FLATBUFFERS_CONSTEXPR char kPathSeparator = '/'; + +// Returns the path with the extension, if any, removed. +std::string StripExtension(const std::string &filepath); + +// Returns the extension, if any. +std::string GetExtension(const std::string &filepath); + +// Return the last component of the path, after the last separator. +std::string StripPath(const std::string &filepath); + +// Strip the last component of the path + separator. +std::string StripFileName(const std::string &filepath); + +// Concatenates a path with a filename, regardless of whether the path +// ends in a separator or not. +std::string ConCatPathFileName(const std::string &path, + const std::string &filename); + +// Replaces any '\\' separators with '/' +std::string PosixPath(const char *path); + +// This function ensure a directory exists, by recursively +// creating dirs for any parts of the path that don't exist yet. +void EnsureDirExists(const std::string &filepath); + +// Obtains the absolute path from any other path. +// Returns the input path if the absolute path couldn't be resolved. +std::string AbsolutePath(const std::string &filepath); + +// To and from UTF-8 unicode conversion functions + +// Convert a unicode code point into a UTF-8 representation by appending it +// to a string. Returns the number of bytes generated. +inline int ToUTF8(uint32_t ucc, std::string *out) { + FLATBUFFERS_ASSERT(!(ucc & 0x80000000)); // Top bit can't be set. + // 6 possible encodings: http://en.wikipedia.org/wiki/UTF-8 + for (int i = 0; i < 6; i++) { + // Max bits this encoding can represent. + uint32_t max_bits = 6 + i * 5 + static_cast<int>(!i); + if (ucc < (1u << max_bits)) { // does it fit? + // Remaining bits not encoded in the first byte, store 6 bits each + uint32_t remain_bits = i * 6; + // Store first byte: + (*out) += static_cast<char>((0xFE << (max_bits - remain_bits)) | + (ucc >> remain_bits)); + // Store remaining bytes: + for (int j = i - 1; j >= 0; j--) { + (*out) += static_cast<char>(((ucc >> (j * 6)) & 0x3F) | 0x80); + } + return i + 1; // Return the number of bytes added. + } + } + FLATBUFFERS_ASSERT(0); // Impossible to arrive here. + return -1; +} + +// Converts whatever prefix of the incoming string corresponds to a valid +// UTF-8 sequence into a unicode code. The incoming pointer will have been +// advanced past all bytes parsed. +// returns -1 upon corrupt UTF-8 encoding (ignore the incoming pointer in +// this case). +inline int FromUTF8(const char **in) { + int len = 0; + // Count leading 1 bits. + for (int mask = 0x80; mask >= 0x04; mask >>= 1) { + if (**in & mask) { + len++; + } else { + break; + } + } + if ((static_cast<unsigned char>(**in) << len) & 0x80) + return -1; // Bit after leading 1's must be 0. + if (!len) return *(*in)++; + // UTF-8 encoded values with a length are between 2 and 4 bytes. + if (len < 2 || len > 4) { return -1; } + // Grab initial bits of the code. + int ucc = *(*in)++ & ((1 << (7 - len)) - 1); + for (int i = 0; i < len - 1; i++) { + if ((**in & 0xC0) != 0x80) return -1; // Upper bits must 1 0. + ucc <<= 6; + ucc |= *(*in)++ & 0x3F; // Grab 6 more bits of the code. + } + // UTF-8 cannot encode values between 0xD800 and 0xDFFF (reserved for + // UTF-16 surrogate pairs). + if (ucc >= 0xD800 && ucc <= 0xDFFF) { return -1; } + // UTF-8 must represent code points in their shortest possible encoding. + switch (len) { + case 2: + // Two bytes of UTF-8 can represent code points from U+0080 to U+07FF. + if (ucc < 0x0080 || ucc > 0x07FF) { return -1; } + break; + case 3: + // Three bytes of UTF-8 can represent code points from U+0800 to U+FFFF. + if (ucc < 0x0800 || ucc > 0xFFFF) { return -1; } + break; + case 4: + // Four bytes of UTF-8 can represent code points from U+10000 to U+10FFFF. + if (ucc < 0x10000 || ucc > 0x10FFFF) { return -1; } + break; + } + return ucc; +} + +#ifndef FLATBUFFERS_PREFER_PRINTF +// Wraps a string to a maximum length, inserting new lines where necessary. Any +// existing whitespace will be collapsed down to a single space. A prefix or +// suffix can be provided, which will be inserted before or after a wrapped +// line, respectively. +inline std::string WordWrap(const std::string in, size_t max_length, + const std::string wrapped_line_prefix, + const std::string wrapped_line_suffix) { + std::istringstream in_stream(in); + std::string wrapped, line, word; + + in_stream >> word; + line = word; + + while (in_stream >> word) { + if ((line.length() + 1 + word.length() + wrapped_line_suffix.length()) < + max_length) { + line += " " + word; + } else { + wrapped += line + wrapped_line_suffix + "\n"; + line = wrapped_line_prefix + word; + } + } + wrapped += line; + + return wrapped; +} +#endif // !FLATBUFFERS_PREFER_PRINTF + +inline bool EscapeString(const char *s, size_t length, std::string *_text, + bool allow_non_utf8, bool natural_utf8) { + std::string &text = *_text; + text += "\""; + for (uoffset_t i = 0; i < length; i++) { + char c = s[i]; + switch (c) { + case '\n': text += "\\n"; break; + case '\t': text += "\\t"; break; + case '\r': text += "\\r"; break; + case '\b': text += "\\b"; break; + case '\f': text += "\\f"; break; + case '\"': text += "\\\""; break; + case '\\': text += "\\\\"; break; + default: + if (c >= ' ' && c <= '~') { + text += c; + } else { + // Not printable ASCII data. Let's see if it's valid UTF-8 first: + const char *utf8 = s + i; + int ucc = FromUTF8(&utf8); + if (ucc < 0) { + if (allow_non_utf8) { + text += "\\x"; + text += IntToStringHex(static_cast<uint8_t>(c), 2); + } else { + // There are two cases here: + // + // 1) We reached here by parsing an IDL file. In that case, + // we previously checked for non-UTF-8, so we shouldn't reach + // here. + // + // 2) We reached here by someone calling GenerateText() + // on a previously-serialized flatbuffer. The data might have + // non-UTF-8 Strings, or might be corrupt. + // + // In both cases, we have to give up and inform the caller + // they have no JSON. + return false; + } + } else { + if (natural_utf8) { + // utf8 points to past all utf-8 bytes parsed + text.append(s + i, static_cast<size_t>(utf8 - s - i)); + } else if (ucc <= 0xFFFF) { + // Parses as Unicode within JSON's \uXXXX range, so use that. + text += "\\u"; + text += IntToStringHex(ucc, 4); + } else if (ucc <= 0x10FFFF) { + // Encode Unicode SMP values to a surrogate pair using two \u + // escapes. + uint32_t base = ucc - 0x10000; + auto high_surrogate = (base >> 10) + 0xD800; + auto low_surrogate = (base & 0x03FF) + 0xDC00; + text += "\\u"; + text += IntToStringHex(high_surrogate, 4); + text += "\\u"; + text += IntToStringHex(low_surrogate, 4); + } + // Skip past characters recognized. + i = static_cast<uoffset_t>(utf8 - s - 1); + } + } + break; + } + } + text += "\""; + return true; +} + +inline std::string BufferToHexText(const void *buffer, size_t buffer_size, + size_t max_length, + const std::string &wrapped_line_prefix, + const std::string &wrapped_line_suffix) { + std::string text = wrapped_line_prefix; + size_t start_offset = 0; + const char *s = reinterpret_cast<const char *>(buffer); + for (size_t i = 0; s && i < buffer_size; i++) { + // Last iteration or do we have more? + bool have_more = i + 1 < buffer_size; + text += "0x"; + text += IntToStringHex(static_cast<uint8_t>(s[i]), 2); + if (have_more) { text += ','; } + // If we have more to process and we reached max_length + if (have_more && + text.size() + wrapped_line_suffix.size() >= start_offset + max_length) { + text += wrapped_line_suffix; + text += '\n'; + start_offset = text.size(); + text += wrapped_line_prefix; + } + } + text += wrapped_line_suffix; + return text; +} + +// Remove paired quotes in a string: "text"|'text' -> text. +std::string RemoveStringQuotes(const std::string &s); + +// Change th global C-locale to locale with name <locale_name>. +// Returns an actual locale name in <_value>, useful if locale_name is "" or +// null. +bool SetGlobalTestLocale(const char *locale_name, + std::string *_value = nullptr); + +// Read (or test) a value of environment variable. +bool ReadEnvironmentVariable(const char *var_name, + std::string *_value = nullptr); + +// MSVC specific: Send all assert reports to STDOUT to prevent CI hangs. +void SetupDefaultCRTReportMode(); + +} // namespace flatbuffers + +#endif // FLATBUFFERS_UTIL_H_ diff --git a/contrib/libs/flatbuffers/samples/monster.fbs b/contrib/libs/flatbuffers/samples/monster.fbs new file mode 100644 index 0000000000..af224512ee --- /dev/null +++ b/contrib/libs/flatbuffers/samples/monster.fbs @@ -0,0 +1,33 @@ +// Example IDL file for our monster's schema. + +namespace MyGame.Sample; + +enum Color:byte { Red = 0, Green, Blue = 2 } + +union Equipment { Weapon } // Optionally add more tables. + +struct Vec3 { + x:float; + y:float; + z:float; +} + +table Monster { + pos:Vec3; + mana:short = 150; + hp:short = 100; + name:string; + friendly:bool = false (deprecated); + inventory:[ubyte]; + color:Color = Blue; + weapons:[Weapon]; + equipped:Equipment; + path:[Vec3]; +} + +table Weapon { + name:string; + damage:short; +} + +root_type Monster; diff --git a/contrib/libs/flatbuffers/samples/sample_binary.cpp b/contrib/libs/flatbuffers/samples/sample_binary.cpp new file mode 100644 index 0000000000..6bd1cdcf43 --- /dev/null +++ b/contrib/libs/flatbuffers/samples/sample_binary.cpp @@ -0,0 +1,104 @@ +/* + * Copyright 2015 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <contrib/libs/flatbuffers/samples/monster.fbs.h> + +using namespace MyGame::Sample; + +// Example how to use FlatBuffers to create and read binary buffers. + +int main(int /*argc*/, const char * /*argv*/[]) { + // Build up a serialized buffer algorithmically: + flatbuffers::FlatBufferBuilder builder; + + // First, lets serialize some weapons for the Monster: A 'sword' and an 'axe'. + auto weapon_one_name = builder.CreateString("Sword"); + short weapon_one_damage = 3; + + auto weapon_two_name = builder.CreateString("Axe"); + short weapon_two_damage = 5; + + // Use the `CreateWeapon` shortcut to create Weapons with all fields set. + auto sword = CreateWeapon(builder, weapon_one_name, weapon_one_damage); + auto axe = CreateWeapon(builder, weapon_two_name, weapon_two_damage); + + // Create a FlatBuffer's `vector` from the `std::vector`. + std::vector<flatbuffers::Offset<Weapon>> weapons_vector; + weapons_vector.push_back(sword); + weapons_vector.push_back(axe); + auto weapons = builder.CreateVector(weapons_vector); + + // Second, serialize the rest of the objects needed by the Monster. + auto position = Vec3(1.0f, 2.0f, 3.0f); + + auto name = builder.CreateString("MyMonster"); + + unsigned char inv_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + auto inventory = builder.CreateVector(inv_data, 10); + + // Shortcut for creating monster with all fields set: + auto orc = CreateMonster(builder, &position, 150, 80, name, inventory, + Color_Red, weapons, Equipment_Weapon, axe.Union()); + + builder.Finish(orc); // Serialize the root of the object. + + // We now have a FlatBuffer we can store on disk or send over a network. + + // ** file/network code goes here :) ** + // access builder.GetBufferPointer() for builder.GetSize() bytes + + // Instead, we're going to access it right away (as if we just received it). + + // Get access to the root: + auto monster = GetMonster(builder.GetBufferPointer()); + + // Get and test some scalar types from the FlatBuffer. + assert(monster->hp() == 80); + assert(monster->mana() == 150); // default + assert(monster->name()->str() == "MyMonster"); + + // Get and test a field of the FlatBuffer's `struct`. + auto pos = monster->pos(); + assert(pos); + assert(pos->z() == 3.0f); + (void)pos; + + // Get a test an element from the `inventory` FlatBuffer's `vector`. + auto inv = monster->inventory(); + assert(inv); + assert(inv->Get(9) == 9); + (void)inv; + + // Get and test the `weapons` FlatBuffers's `vector`. + std::string expected_weapon_names[] = { "Sword", "Axe" }; + short expected_weapon_damages[] = { 3, 5 }; + auto weps = monster->weapons(); + for (unsigned int i = 0; i < weps->size(); i++) { + assert(weps->Get(i)->name()->str() == expected_weapon_names[i]); + assert(weps->Get(i)->damage() == expected_weapon_damages[i]); + } + (void)expected_weapon_names; + (void)expected_weapon_damages; + + // Get and test the `Equipment` union (`equipped` field). + assert(monster->equipped_type() == Equipment_Weapon); + auto equipped = static_cast<const Weapon *>(monster->equipped()); + assert(equipped->name()->str() == "Axe"); + assert(equipped->damage() == 5); + (void)equipped; + + printf("The FlatBuffer was successfully created and verified!\n"); +} diff --git a/contrib/libs/flatbuffers/samples/ya.make b/contrib/libs/flatbuffers/samples/ya.make new file mode 100644 index 0000000000..7855f8f461 --- /dev/null +++ b/contrib/libs/flatbuffers/samples/ya.make @@ -0,0 +1,18 @@ +PROGRAM() + +LICENSE(Apache-2.0) + +LICENSE_TEXTS(.yandex_meta/licenses.list.txt) + +NO_UTIL() + +SRCS( + monster.fbs + sample_binary.cpp +) + +PEERDIR( + contrib/libs/flatbuffers +) + +END() diff --git a/contrib/libs/flatbuffers/src/code_generators.cpp b/contrib/libs/flatbuffers/src/code_generators.cpp new file mode 100644 index 0000000000..745406ba95 --- /dev/null +++ b/contrib/libs/flatbuffers/src/code_generators.cpp @@ -0,0 +1,395 @@ +/* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "flatbuffers/code_generators.h" + +#include <assert.h> + +#include <cmath> + +#include "flatbuffers/base.h" +#include "flatbuffers/util.h" + +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 4127) // C4127: conditional expression is constant +#endif + +namespace flatbuffers { + +void CodeWriter::operator+=(std::string text) { + if (!ignore_ident_ && !text.empty()) AppendIdent(stream_); + + while (true) { + auto begin = text.find("{{"); + if (begin == std::string::npos) { break; } + + auto end = text.find("}}"); + if (end == std::string::npos || end < begin) { break; } + + // Write all the text before the first {{ into the stream. + stream_.write(text.c_str(), begin); + + // The key is between the {{ and }}. + const std::string key = text.substr(begin + 2, end - begin - 2); + + // Find the value associated with the key. If it exists, write the + // value into the stream, otherwise write the key itself into the stream. + auto iter = value_map_.find(key); + if (iter != value_map_.end()) { + const std::string &value = iter->second; + stream_ << value; + } else { + FLATBUFFERS_ASSERT(false && "could not find key"); + stream_ << key; + } + + // Update the text to everything after the }}. + text = text.substr(end + 2); + } + if (!text.empty() && string_back(text) == '\\') { + text.pop_back(); + ignore_ident_ = true; + stream_ << text; + } else { + ignore_ident_ = false; + stream_ << text << std::endl; + } +} + +void CodeWriter::AppendIdent(std::stringstream &stream) { + int lvl = cur_ident_lvl_; + while (lvl--) { + stream.write(pad_.c_str(), static_cast<std::streamsize>(pad_.size())); + } +} + +const char *BaseGenerator::FlatBuffersGeneratedWarning() { + return "automatically generated by the FlatBuffers compiler," + " do not modify"; +} + +std::string BaseGenerator::NamespaceDir(const Parser &parser, + const std::string &path, + const Namespace &ns, + const bool dasherize) { + EnsureDirExists(path); + if (parser.opts.one_file) return path; + std::string namespace_dir = path; // Either empty or ends in separator. + auto &namespaces = ns.components; + for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { + namespace_dir += !dasherize ? *it : ToDasherizedCase(*it); + namespace_dir += kPathSeparator; + EnsureDirExists(namespace_dir); + } + return namespace_dir; +} + +std::string BaseGenerator::NamespaceDir(const Namespace &ns, + const bool dasherize) const { + return BaseGenerator::NamespaceDir(parser_, path_, ns, dasherize); +} + +std::string BaseGenerator::ToDasherizedCase(const std::string pascal_case) { + std::string dasherized_case; + char p = 0; + for (size_t i = 0; i < pascal_case.length(); i++) { + char const &c = pascal_case[i]; + if (is_alpha_upper(c)) { + if (i > 0 && p != kPathSeparator) dasherized_case += "-"; + dasherized_case += CharToLower(c); + } else { + dasherized_case += c; + } + p = c; + } + return dasherized_case; +} + +std::string BaseGenerator::FullNamespace(const char *separator, + const Namespace &ns) { + std::string namespace_name; + auto &namespaces = ns.components; + for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { + if (namespace_name.length()) namespace_name += separator; + namespace_name += *it; + } + return namespace_name; +} + +std::string BaseGenerator::LastNamespacePart(const Namespace &ns) { + if (!ns.components.empty()) + return ns.components.back(); + else + return std::string(""); +} + +// Ensure that a type is prefixed with its namespace. +std::string BaseGenerator::WrapInNameSpace(const Namespace *ns, + const std::string &name) const { + std::string qualified_name = qualifying_start_; + for (auto it = ns->components.begin(); it != ns->components.end(); ++it) + qualified_name += *it + qualifying_separator_; + return qualified_name + name; +} + +std::string BaseGenerator::WrapInNameSpace(const Definition &def) const { + return WrapInNameSpace(def.defined_namespace, def.name); +} + +std::string BaseGenerator::GetNameSpace(const Definition &def) const { + const Namespace *ns = def.defined_namespace; + if (CurrentNameSpace() == ns) return ""; + std::string qualified_name = qualifying_start_; + for (auto it = ns->components.begin(); it != ns->components.end(); ++it) { + qualified_name += *it; + if ((it + 1) != ns->components.end()) { + qualified_name += qualifying_separator_; + } + } + + return qualified_name; +} + +std::string BaseGenerator::GeneratedFileName(const std::string &path, + const std::string &file_name, + const IDLOptions &options) const { + return path + file_name + options.filename_suffix + "." + + (options.filename_extension.empty() ? default_extension_ + : options.filename_extension); +} + +// Generate a documentation comment, if available. +void GenComment(const std::vector<std::string> &dc, std::string *code_ptr, + const CommentConfig *config, const char *prefix) { + if (dc.begin() == dc.end()) { + // Don't output empty comment blocks with 0 lines of comment content. + return; + } + + std::string &code = *code_ptr; + if (config != nullptr && config->first_line != nullptr) { + code += std::string(prefix) + std::string(config->first_line) + "\n"; + } + std::string line_prefix = + std::string(prefix) + + ((config != nullptr && config->content_line_prefix != nullptr) + ? config->content_line_prefix + : "///"); + for (auto it = dc.begin(); it != dc.end(); ++it) { + code += line_prefix + *it + "\n"; + } + if (config != nullptr && config->last_line != nullptr) { + code += std::string(prefix) + std::string(config->last_line) + "\n"; + } +} + +template<typename T> +std::string FloatConstantGenerator::GenFloatConstantImpl( + const FieldDef &field) const { + const auto &constant = field.value.constant; + T v; + auto done = StringToNumber(constant.c_str(), &v); + FLATBUFFERS_ASSERT(done); + if (done) { +#if (!defined(_MSC_VER) || (_MSC_VER >= 1800)) + if (std::isnan(v)) return NaN(v); + if (std::isinf(v)) return Inf(v); +#endif + return Value(v, constant); + } + return "#"; // compile time error +} + +std::string FloatConstantGenerator::GenFloatConstant( + const FieldDef &field) const { + switch (field.value.type.base_type) { + case BASE_TYPE_FLOAT: return GenFloatConstantImpl<float>(field); + case BASE_TYPE_DOUBLE: return GenFloatConstantImpl<double>(field); + default: { + FLATBUFFERS_ASSERT(false); + return "INVALID_BASE_TYPE"; + } + }; +} + +TypedFloatConstantGenerator::TypedFloatConstantGenerator( + const char *double_prefix, const char *single_prefix, + const char *nan_number, const char *pos_inf_number, + const char *neg_inf_number) + : double_prefix_(double_prefix), + single_prefix_(single_prefix), + nan_number_(nan_number), + pos_inf_number_(pos_inf_number), + neg_inf_number_(neg_inf_number) {} + +std::string TypedFloatConstantGenerator::MakeNaN( + const std::string &prefix) const { + return prefix + nan_number_; +} +std::string TypedFloatConstantGenerator::MakeInf( + bool neg, const std::string &prefix) const { + if (neg) + return !neg_inf_number_.empty() ? (prefix + neg_inf_number_) + : ("-" + prefix + pos_inf_number_); + else + return prefix + pos_inf_number_; +} + +std::string TypedFloatConstantGenerator::Value(double v, + const std::string &src) const { + (void)v; + return src; +} + +std::string TypedFloatConstantGenerator::Inf(double v) const { + return MakeInf(v < 0, double_prefix_); +} + +std::string TypedFloatConstantGenerator::NaN(double v) const { + (void)v; + return MakeNaN(double_prefix_); +} + +std::string TypedFloatConstantGenerator::Value(float v, + const std::string &src) const { + (void)v; + return src + "f"; +} + +std::string TypedFloatConstantGenerator::Inf(float v) const { + return MakeInf(v < 0, single_prefix_); +} + +std::string TypedFloatConstantGenerator::NaN(float v) const { + (void)v; + return MakeNaN(single_prefix_); +} + +SimpleFloatConstantGenerator::SimpleFloatConstantGenerator( + const char *nan_number, const char *pos_inf_number, + const char *neg_inf_number) + : nan_number_(nan_number), + pos_inf_number_(pos_inf_number), + neg_inf_number_(neg_inf_number) {} + +std::string SimpleFloatConstantGenerator::Value(double v, + const std::string &src) const { + (void)v; + return src; +} + +std::string SimpleFloatConstantGenerator::Inf(double v) const { + return (v < 0) ? neg_inf_number_ : pos_inf_number_; +} + +std::string SimpleFloatConstantGenerator::NaN(double v) const { + (void)v; + return nan_number_; +} + +std::string SimpleFloatConstantGenerator::Value(float v, + const std::string &src) const { + return this->Value(static_cast<double>(v), src); +} + +std::string SimpleFloatConstantGenerator::Inf(float v) const { + return this->Inf(static_cast<double>(v)); +} + +std::string SimpleFloatConstantGenerator::NaN(float v) const { + return this->NaN(static_cast<double>(v)); +} + +std::string JavaCSharpMakeRule(const Parser &parser, const std::string &path, + const std::string &file_name) { + FLATBUFFERS_ASSERT(parser.opts.lang == IDLOptions::kJava || + parser.opts.lang == IDLOptions::kCSharp); + + std::string file_extension = + (parser.opts.lang == IDLOptions::kJava) ? ".java" : ".cs"; + + std::string make_rule; + + for (auto it = parser.enums_.vec.begin(); it != parser.enums_.vec.end(); + ++it) { + auto &enum_def = **it; + if (!make_rule.empty()) make_rule += " "; + std::string directory = + BaseGenerator::NamespaceDir(parser, path, *enum_def.defined_namespace); + make_rule += directory + enum_def.name + file_extension; + } + + for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end(); + ++it) { + auto &struct_def = **it; + if (!make_rule.empty()) make_rule += " "; + std::string directory = BaseGenerator::NamespaceDir( + parser, path, *struct_def.defined_namespace); + make_rule += directory + struct_def.name + file_extension; + } + + make_rule += ": "; + auto included_files = parser.GetIncludedFilesRecursive(file_name); + for (auto it = included_files.begin(); it != included_files.end(); ++it) { + make_rule += " " + *it; + } + return make_rule; +} + +std::string BinaryFileName(const Parser &parser, const std::string &path, + const std::string &file_name) { + auto ext = parser.file_extension_.length() ? parser.file_extension_ : "bin"; + return path + file_name + "." + ext; +} + +bool GenerateBinary(const Parser &parser, const std::string &path, + const std::string &file_name) { + if (parser.opts.use_flexbuffers) { + auto data_vec = parser.flex_builder_.GetBuffer(); + auto data_ptr = reinterpret_cast<char *>(data(data_vec)); + return !parser.flex_builder_.GetSize() || + flatbuffers::SaveFile( + BinaryFileName(parser, path, file_name).c_str(), data_ptr, + parser.flex_builder_.GetSize(), true); + } + return !parser.builder_.GetSize() || + flatbuffers::SaveFile( + BinaryFileName(parser, path, file_name).c_str(), + reinterpret_cast<char *>(parser.builder_.GetBufferPointer()), + parser.builder_.GetSize(), true); +} + +std::string BinaryMakeRule(const Parser &parser, const std::string &path, + const std::string &file_name) { + if (!parser.builder_.GetSize()) return ""; + std::string filebase = + flatbuffers::StripPath(flatbuffers::StripExtension(file_name)); + std::string make_rule = + BinaryFileName(parser, path, filebase) + ": " + file_name; + auto included_files = + parser.GetIncludedFilesRecursive(parser.root_struct_def_->file); + for (auto it = included_files.begin(); it != included_files.end(); ++it) { + make_rule += " " + *it; + } + return make_rule; +} + +} // namespace flatbuffers + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif diff --git a/contrib/libs/flatbuffers/src/flatc.cpp b/contrib/libs/flatbuffers/src/flatc.cpp new file mode 100644 index 0000000000..221b88676d --- /dev/null +++ b/contrib/libs/flatbuffers/src/flatc.cpp @@ -0,0 +1,554 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "flatbuffers/flatc.h" + +#include <list> + +namespace flatbuffers { + +const char *FLATC_VERSION() { return FLATBUFFERS_VERSION(); } + +void FlatCompiler::ParseFile( + flatbuffers::Parser &parser, const std::string &filename, + const std::string &contents, + std::vector<const char *> &include_directories) const { + auto local_include_directory = flatbuffers::StripFileName(filename); + include_directories.push_back(local_include_directory.c_str()); + include_directories.push_back(nullptr); + if (!parser.Parse(contents.c_str(), &include_directories[0], + filename.c_str())) { + Error(parser.error_, false, false); + } + if (!parser.error_.empty()) { Warn(parser.error_, false); } + include_directories.pop_back(); + include_directories.pop_back(); +} + +void FlatCompiler::LoadBinarySchema(flatbuffers::Parser &parser, + const std::string &filename, + const std::string &contents) { + if (!parser.Deserialize(reinterpret_cast<const uint8_t *>(contents.c_str()), + contents.size())) { + Error("failed to load binary schema: " + filename, false, false); + } +} + +void FlatCompiler::Warn(const std::string &warn, bool show_exe_name) const { + params_.warn_fn(this, warn, show_exe_name); +} + +void FlatCompiler::Error(const std::string &err, bool usage, + bool show_exe_name) const { + params_.error_fn(this, err, usage, show_exe_name); +} + +std::string FlatCompiler::GetUsageString(const char *program_name) const { + std::stringstream ss; + ss << "Usage: " << program_name << " [OPTION]... FILE... [-- FILE...]\n"; + for (size_t i = 0; i < params_.num_generators; ++i) { + const Generator &g = params_.generators[i]; + + std::stringstream full_name; + full_name << std::setw(16) << std::left << g.generator_opt_long; + const char *name = g.generator_opt_short ? g.generator_opt_short : " "; + const char *help = g.generator_help; + + ss << " " << full_name.str() << " " << name << " " << help << ".\n"; + } + // clang-format off + + // Output width + // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 + ss << + " -o PATH Prefix PATH to all generated files.\n" + " -I PATH Search for includes in the specified path.\n" + " -M Print make rules for generated files.\n" + " --version Print the version number of flatc and exit.\n" + " --strict-json Strict JSON: field names must be / will be quoted,\n" + " no trailing commas in tables/vectors.\n" + " --allow-non-utf8 Pass non-UTF-8 input through parser and emit nonstandard\n" + " \\x escapes in JSON. (Default is to raise parse error on\n" + " non-UTF-8 input.)\n" + " --natural-utf8 Output strings with UTF-8 as human-readable strings.\n" + " By default, UTF-8 characters are printed as \\uXXXX escapes.\n" + " --defaults-json Output fields whose value is the default when\n" + " writing JSON\n" + " --unknown-json Allow fields in JSON that are not defined in the\n" + " schema. These fields will be discared when generating\n" + " binaries.\n" + " --no-prefix Don\'t prefix enum values with the enum type in C++.\n" + " --scoped-enums Use C++11 style scoped and strongly typed enums.\n" + " also implies --no-prefix.\n" + " --gen-includes (deprecated), this is the default behavior.\n" + " If the original behavior is required (no include\n" + " statements) use --no-includes.\n" + " --no-includes Don\'t generate include statements for included\n" + " schemas the generated file depends on (C++ / Python).\n" + " --gen-mutable Generate accessors that can mutate buffers in-place.\n" + " --gen-onefile Generate single output file for C# and Go.\n" + " --gen-name-strings Generate type name functions for C++ and Rust.\n" + " --gen-object-api Generate an additional object-based API.\n" + " --gen-compare Generate operator== for object-based API types.\n" + " --gen-nullable Add Clang _Nullable for C++ pointer. or @Nullable for Java\n" + " --java-checkerframe work Add @Pure for Java.\n" + " --gen-generated Add @Generated annotation for Java\n" + " --gen-jvmstatic Add @JvmStatic annotation for Kotlin methods\n" + " in companion object for interop from Java to Kotlin.\n" + " --gen-all Generate not just code for the current schema files,\n" + " but for all files it includes as well.\n" + " If the language uses a single file for output (by default\n" + " the case for C++ and JS), all code will end up in this one\n" + " file.\n" + " --cpp-include Adds an #include in generated file.\n" + " --cpp-ptr-type T Set object API pointer type (default std::unique_ptr).\n" + " --cpp-str-type T Set object API string type (default std::string).\n" + " T::c_str(), T::length() and T::empty() must be supported.\n" + " The custom type also needs to be constructible from std::string\n" + " (see the --cpp-str-flex-ctor option to change this behavior).\n" + " --cpp-str-flex-ctor Don't construct custom string types by passing std::string\n" + " from Flatbuffers, but (char* + length).\n" + " --cpp-std CPP_STD Generate a C++ code using features of selected C++ standard.\n" + " Supported CPP_STD values:\n" + " * 'c++0x' - generate code compatible with old compilers;\n" + " * 'c++11' - use C++11 code generator (default);\n" + " * 'c++17' - use C++17 features in generated code (experimental).\n" + " --cpp-static-reflection When using C++17, generate extra code to provide compile-time\n" + " (static) reflection of Flatbuffers types. Requires --cpp-std\n" + " to be \"c++17\" or higher.\n" + " --object-prefix Customise class prefix for C++ object-based API.\n" + " --object-suffix Customise class suffix for C++ object-based API.\n" + " Default value is \"T\".\n" + " --go-namespace Generate the overriding namespace in Golang.\n" + " --go-import Generate the overriding import for flatbuffers in Golang\n" + " (default is \"github.com/google/flatbuffers/go\").\n" + " --raw-binary Allow binaries without file_identifier to be read.\n" + " This may crash flatc given a mismatched schema.\n" + " --size-prefixed Input binaries are size prefixed buffers.\n" + " --proto Input is a .proto, translate to .fbs.\n" + " --proto-namespace-suffix Add this namespace to any flatbuffers generated\n" + " SUFFIX from protobufs.\n" + " --oneof-union Translate .proto oneofs to flatbuffer unions.\n" + " --grpc Generate GRPC interfaces for the specified languages.\n" + " --schema Serialize schemas instead of JSON (use with -b).\n" + " --bfbs-comments Add doc comments to the binary schema files.\n" + " --bfbs-builtins Add builtin attributes to the binary schema files.\n" + " --bfbs-gen-embed Generate code to embed the bfbs schema to the source.\n" + " --conform FILE Specify a schema the following schemas should be\n" + " an evolution of. Gives errors if not.\n" + " --conform-includes Include path for the schema given with --conform PATH\n" + " --filename-suffix The suffix appended to the generated file names.\n" + " Default is '_generated'.\n" + " --filename-ext The extension appended to the generated file names.\n" + " Default is language-specific (e.g., '.h' for C++)\n" + " --include-prefix Prefix this path to any generated include statements.\n" + " PATH\n" + " --keep-prefix Keep original prefix of schema include statement.\n" + " --reflect-types Add minimal type reflection to code generation.\n" + " --reflect-names Add minimal type/name reflection.\n" + " --root-type T Select or override the default root_type\n" + " --require-explicit-ids When parsing schemas, require explicit ids (id: x).\n" + " --force-defaults Emit default values in binary output from JSON\n" + " --force-empty When serializing from object API representation,\n" + " force strings and vectors to empty rather than null.\n" + " --force-empty-vectors When serializing from object API representation,\n" + " force vectors to empty rather than null.\n" + " --flexbuffers Used with \"binary\" and \"json\" options, it generates\n" + " data using schema-less FlexBuffers.\n" + " --no-warnings Inhibit all warning messages.\n" + "FILEs may be schemas (must end in .fbs), binary schemas (must end in .bfbs),\n" + "or JSON files (conforming to preceding schema). FILEs after the -- must be\n" + "binary flatbuffer format files.\n" + "Output files are named using the base file name of the input,\n" + "and written to the current directory or the path given by -o.\n" + "example: " << program_name << " -c -b schema1.fbs schema2.fbs data.json\n"; + // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 + // clang-format on + return ss.str(); +} + +int FlatCompiler::Compile(int argc, const char **argv) { + if (params_.generators == nullptr || params_.num_generators == 0) { + return 0; + } + + flatbuffers::IDLOptions opts; + std::string output_path; + + bool any_generator = false; + bool print_make_rules = false; + bool raw_binary = false; + bool schema_binary = false; + bool grpc_enabled = false; + std::vector<std::string> filenames; + std::list<std::string> include_directories_storage; + std::vector<const char *> include_directories; + std::vector<const char *> conform_include_directories; + std::vector<bool> generator_enabled(params_.num_generators, false); + size_t binary_files_from = std::numeric_limits<size_t>::max(); + std::string conform_to_schema; + + for (int argi = 0; argi < argc; argi++) { + std::string arg = argv[argi]; + if (arg[0] == '-') { + if (filenames.size() && arg[1] != '-') + Error("invalid option location: " + arg, true); + if (arg == "-o") { + if (++argi >= argc) Error("missing path following: " + arg, true); + output_path = flatbuffers::ConCatPathFileName( + flatbuffers::PosixPath(argv[argi]), ""); + } else if (arg == "-I") { + if (++argi >= argc) Error("missing path following: " + arg, true); + include_directories_storage.push_back( + flatbuffers::PosixPath(argv[argi])); + include_directories.push_back( + include_directories_storage.back().c_str()); + } else if (arg == "--conform") { + if (++argi >= argc) Error("missing path following: " + arg, true); + conform_to_schema = flatbuffers::PosixPath(argv[argi]); + } else if (arg == "--conform-includes") { + if (++argi >= argc) Error("missing path following: " + arg, true); + include_directories_storage.push_back( + flatbuffers::PosixPath(argv[argi])); + conform_include_directories.push_back( + include_directories_storage.back().c_str()); + } else if (arg == "--include-prefix") { + if (++argi >= argc) Error("missing path following: " + arg, true); + opts.include_prefix = flatbuffers::ConCatPathFileName( + flatbuffers::PosixPath(argv[argi]), ""); + } else if (arg == "--keep-prefix") { + opts.keep_include_path = true; + } else if (arg == "--strict-json") { + opts.strict_json = true; + } else if (arg == "--allow-non-utf8") { + opts.allow_non_utf8 = true; + } else if (arg == "--natural-utf8") { + opts.natural_utf8 = true; + } else if (arg == "--go-namespace") { + if (++argi >= argc) Error("missing golang namespace" + arg, true); + opts.go_namespace = argv[argi]; + } else if (arg == "--go-import") { + if (++argi >= argc) Error("missing golang import" + arg, true); + opts.go_import = argv[argi]; + } else if (arg == "--defaults-json") { + opts.output_default_scalars_in_json = true; + } else if (arg == "--unknown-json") { + opts.skip_unexpected_fields_in_json = true; + } else if (arg == "--no-prefix") { + opts.prefixed_enums = false; + } else if (arg == "--scoped-enums") { + opts.prefixed_enums = false; + opts.scoped_enums = true; + } else if (arg == "--no-union-value-namespacing") { + opts.union_value_namespacing = false; + } else if (arg == "--gen-mutable") { + opts.mutable_buffer = true; + } else if (arg == "--gen-name-strings") { + opts.generate_name_strings = true; + } else if (arg == "--gen-object-api") { + opts.generate_object_based_api = true; + } else if (arg == "--gen-compare") { + opts.gen_compare = true; + } else if (arg == "--cpp-include") { + if (++argi >= argc) Error("missing include following: " + arg, true); + opts.cpp_includes.push_back(argv[argi]); + } else if (arg == "--cpp-ptr-type") { + if (++argi >= argc) Error("missing type following: " + arg, true); + opts.cpp_object_api_pointer_type = argv[argi]; + } else if (arg == "--cpp-str-type") { + if (++argi >= argc) Error("missing type following: " + arg, true); + opts.cpp_object_api_string_type = argv[argi]; + } else if (arg == "--cpp-str-flex-ctor") { + opts.cpp_object_api_string_flexible_constructor = true; + } else if (arg == "--no-cpp-direct-copy") { + opts.cpp_direct_copy = false; + } else if (arg == "--gen-nullable") { + opts.gen_nullable = true; + } else if (arg == "--java-checkerframework") { + opts.java_checkerframework = true; + } else if (arg == "--gen-generated") { + opts.gen_generated = true; + } else if (arg == "--object-prefix") { + if (++argi >= argc) Error("missing prefix following: " + arg, true); + opts.object_prefix = argv[argi]; + } else if (arg == "--object-suffix") { + if (++argi >= argc) Error("missing suffix following: " + arg, true); + opts.object_suffix = argv[argi]; + } else if (arg == "--gen-all") { + opts.generate_all = true; + opts.include_dependence_headers = false; + } else if (arg == "--gen-includes") { + // Deprecated, remove this option some time in the future. + Warn("warning: --gen-includes is deprecated (it is now default)\n"); + } else if (arg == "--no-includes") { + opts.include_dependence_headers = false; + } else if (arg == "--gen-onefile") { + opts.one_file = true; + } else if (arg == "--raw-binary") { + raw_binary = true; + } else if (arg == "--size-prefixed") { + opts.size_prefixed = true; + } else if (arg == "--") { // Separator between text and binary inputs. + binary_files_from = filenames.size(); + } else if (arg == "--proto") { + opts.proto_mode = true; + } else if (arg == "--proto-namespace-suffix") { + if (++argi >= argc) Error("missing namespace suffix" + arg, true); + opts.proto_namespace_suffix = argv[argi]; + } else if (arg == "--oneof-union") { + opts.proto_oneof_union = true; + } else if (arg == "--schema") { + schema_binary = true; + } else if (arg == "-M") { + print_make_rules = true; + } else if (arg == "--version") { + printf("flatc version %s\n", FLATC_VERSION()); + exit(0); + } else if (arg == "--grpc") { + grpc_enabled = true; + } else if (arg == "--bfbs-comments") { + opts.binary_schema_comments = true; + } else if (arg == "--bfbs-builtins") { + opts.binary_schema_builtins = true; + } else if (arg == "--bfbs-gen-embed") { + opts.binary_schema_gen_embed = true; + } else if (arg == "--reflect-types") { + opts.mini_reflect = IDLOptions::kTypes; + } else if (arg == "--reflect-names") { + opts.mini_reflect = IDLOptions::kTypesAndNames; + } else if (arg == "--require-explicit-ids") { + opts.require_explicit_ids = true; + } else if (arg == "--root-type") { + if (++argi >= argc) Error("missing type following: " + arg, true); + opts.root_type = argv[argi]; + } else if (arg == "--filename-suffix") { + if (++argi >= argc) Error("missing filename suffix: " + arg, true); + opts.filename_suffix = argv[argi]; + } else if (arg == "--filename-ext") { + if (++argi >= argc) Error("missing filename extension: " + arg, true); + opts.filename_extension = argv[argi]; + } else if (arg == "--force-defaults") { + opts.force_defaults = true; + } else if (arg == "--force-empty") { + opts.set_empty_strings_to_null = false; + opts.set_empty_vectors_to_null = false; + } else if (arg == "--force-empty-vectors") { + opts.set_empty_vectors_to_null = false; + } else if (arg == "--java-primitive-has-method") { + opts.java_primitive_has_method = true; + } else if (arg == "--cs-gen-json-serializer") { + opts.cs_gen_json_serializer = true; + } else if (arg == "--flexbuffers") { + opts.use_flexbuffers = true; + } else if (arg == "--gen-jvmstatic") { + opts.gen_jvmstatic = true; + } else if (arg == "--no-warnings") { + opts.no_warnings = true; + } else if (arg == "--cpp-std") { + if (++argi >= argc) + Error("missing C++ standard specification" + arg, true); + opts.cpp_std = argv[argi]; + } else if (arg.rfind("--cpp-std=", 0) == 0) { + opts.cpp_std = arg.substr(std::string("--cpp-std=").size()); + } else if (arg == "--cpp-static-reflection") { + opts.cpp_static_reflection = true; + } else { + for (size_t i = 0; i < params_.num_generators; ++i) { + if (arg == params_.generators[i].generator_opt_long || + (params_.generators[i].generator_opt_short && + arg == params_.generators[i].generator_opt_short)) { + generator_enabled[i] = true; + any_generator = true; + opts.lang_to_generate |= params_.generators[i].lang; + goto found; + } + } + Error("unknown commandline argument: " + arg, true); + found:; + } + } else { + filenames.push_back(flatbuffers::PosixPath(argv[argi])); + } + } + + if (!filenames.size()) Error("missing input files", false, true); + + if (opts.proto_mode) { + if (any_generator) + Error("cannot generate code directly from .proto files", true); + } else if (!any_generator && conform_to_schema.empty()) { + Error("no options: specify at least one generator.", true); + } + + flatbuffers::Parser conform_parser; + if (!conform_to_schema.empty()) { + std::string contents; + if (!flatbuffers::LoadFile(conform_to_schema.c_str(), true, &contents)) + Error("unable to load schema: " + conform_to_schema); + + if (flatbuffers::GetExtension(conform_to_schema) == + reflection::SchemaExtension()) { + LoadBinarySchema(conform_parser, conform_to_schema, contents); + } else { + ParseFile(conform_parser, conform_to_schema, contents, + conform_include_directories); + } + } + + std::unique_ptr<flatbuffers::Parser> parser(new flatbuffers::Parser(opts)); + + for (auto file_it = filenames.begin(); file_it != filenames.end(); + ++file_it) { + auto &filename = *file_it; + std::string contents; + if (!flatbuffers::LoadFile(filename.c_str(), true, &contents)) + Error("unable to load file: " + filename); + + bool is_binary = + static_cast<size_t>(file_it - filenames.begin()) >= binary_files_from; + auto ext = flatbuffers::GetExtension(filename); + auto is_schema = ext == "fbs" || ext == "proto"; + auto is_binary_schema = ext == reflection::SchemaExtension(); + if (is_binary) { + parser->builder_.Clear(); + parser->builder_.PushFlatBuffer( + reinterpret_cast<const uint8_t *>(contents.c_str()), + contents.length()); + if (!raw_binary) { + // Generally reading binaries that do not correspond to the schema + // will crash, and sadly there's no way around that when the binary + // does not contain a file identifier. + // We'd expect that typically any binary used as a file would have + // such an identifier, so by default we require them to match. + if (!parser->file_identifier_.length()) { + Error("current schema has no file_identifier: cannot test if \"" + + filename + + "\" matches the schema, use --raw-binary to read this file" + " anyway."); + } else if (!flatbuffers::BufferHasIdentifier( + contents.c_str(), parser->file_identifier_.c_str(), + opts.size_prefixed)) { + Error("binary \"" + filename + + "\" does not have expected file_identifier \"" + + parser->file_identifier_ + + "\", use --raw-binary to read this file anyway."); + } + } + } else { + // Check if file contains 0 bytes. + if (!opts.use_flexbuffers && !is_binary_schema && + contents.length() != strlen(contents.c_str())) { + Error("input file appears to be binary: " + filename, true); + } + if (is_schema) { + // If we're processing multiple schemas, make sure to start each + // one from scratch. If it depends on previous schemas it must do + // so explicitly using an include. + parser.reset(new flatbuffers::Parser(opts)); + } + if (is_binary_schema) { + LoadBinarySchema(*parser.get(), filename, contents); + } + if (opts.use_flexbuffers) { + if (opts.lang_to_generate == IDLOptions::kJson) { + parser->flex_root_ = flexbuffers::GetRoot( + reinterpret_cast<const uint8_t *>(contents.c_str()), + contents.size()); + } else { + parser->flex_builder_.Clear(); + ParseFile(*parser.get(), filename, contents, include_directories); + } + } else { + ParseFile(*parser.get(), filename, contents, include_directories); + if (!is_schema && !parser->builder_.GetSize()) { + // If a file doesn't end in .fbs, it must be json/binary. Ensure we + // didn't just parse a schema with a different extension. + Error("input file is neither json nor a .fbs (schema) file: " + + filename, + true); + } + } + if ((is_schema || is_binary_schema) && !conform_to_schema.empty()) { + auto err = parser->ConformTo(conform_parser); + if (!err.empty()) Error("schemas don\'t conform: " + err); + } + if (schema_binary || opts.binary_schema_gen_embed) { + parser->Serialize(); + } + if (schema_binary) { + parser->file_extension_ = reflection::SchemaExtension(); + } + } + + std::string filebase = + flatbuffers::StripPath(flatbuffers::StripExtension(filename)); + + for (size_t i = 0; i < params_.num_generators; ++i) { + parser->opts.lang = params_.generators[i].lang; + if (generator_enabled[i]) { + if (!print_make_rules) { + flatbuffers::EnsureDirExists(output_path); + if ((!params_.generators[i].schema_only || + (is_schema || is_binary_schema)) && + !params_.generators[i].generate(*parser.get(), output_path, + filebase)) { + Error(std::string("Unable to generate ") + + params_.generators[i].lang_name + " for " + filebase); + } + } else { + if (params_.generators[i].make_rule == nullptr) { + Error(std::string("Cannot generate make rule for ") + + params_.generators[i].lang_name); + } else { + std::string make_rule = params_.generators[i].make_rule( + *parser.get(), output_path, filename); + if (!make_rule.empty()) + printf("%s\n", + flatbuffers::WordWrap(make_rule, 80, " ", " \\").c_str()); + } + } + if (grpc_enabled) { + if (params_.generators[i].generateGRPC != nullptr) { + if (!params_.generators[i].generateGRPC(*parser.get(), output_path, + filebase)) { + Error(std::string("Unable to generate GRPC interface for") + + params_.generators[i].lang_name); + } + } else { + Warn(std::string("GRPC interface generator not implemented for ") + + params_.generators[i].lang_name); + } + } + } + } + + if (!opts.root_type.empty()) { + if (!parser->SetRootType(opts.root_type.c_str())) + Error("unknown root type: " + opts.root_type); + else if (parser->root_struct_def_->fixed) + Error("root type must be a table"); + } + + if (opts.proto_mode) GenerateFBS(*parser.get(), output_path, filebase); + + // We do not want to generate code for the definitions in this file + // in any files coming up next. + parser->MarkGenerated(); + } + return 0; +} + +} // namespace flatbuffers diff --git a/contrib/libs/flatbuffers/src/flatc_main.cpp b/contrib/libs/flatbuffers/src/flatc_main.cpp new file mode 100644 index 0000000000..31ccbc7185 --- /dev/null +++ b/contrib/libs/flatbuffers/src/flatc_main.cpp @@ -0,0 +1,121 @@ +/* + * Copyright 2017 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "flatbuffers/flatc.h" +#include "flatbuffers/util.h" + +static const char *g_program_name = nullptr; + +static void Warn(const flatbuffers::FlatCompiler *flatc, + const std::string &warn, bool show_exe_name) { + (void)flatc; + if (show_exe_name) { printf("%s: ", g_program_name); } + printf("warning: %s\n", warn.c_str()); +} + +static void Error(const flatbuffers::FlatCompiler *flatc, + const std::string &err, bool usage, bool show_exe_name) { + if (show_exe_name) { printf("%s: ", g_program_name); } + printf("error: %s\n", err.c_str()); + if (usage && flatc) { + printf("%s", flatc->GetUsageString(g_program_name).c_str()); + } + exit(1); +} + +namespace flatbuffers { +void LogCompilerWarn(const std::string &warn) { + Warn(static_cast<const flatbuffers::FlatCompiler *>(nullptr), warn, true); +} +void LogCompilerError(const std::string &err) { + Error(static_cast<const flatbuffers::FlatCompiler *>(nullptr), err, false, + true); +} +} // namespace flatbuffers + +int main(int argc, const char *argv[]) { + // Prevent Appveyor-CI hangs. + flatbuffers::SetupDefaultCRTReportMode(); + + g_program_name = argv[0]; + + const flatbuffers::FlatCompiler::Generator generators[] = { + { flatbuffers::GenerateBinary, "-b", "--binary", "binary", false, nullptr, + flatbuffers::IDLOptions::kBinary, + "Generate wire format binaries for any data definitions", + flatbuffers::BinaryMakeRule }, + { flatbuffers::GenerateTextFile, "-t", "--json", "text", false, nullptr, + flatbuffers::IDLOptions::kJson, + "Generate text output for any data definitions", + flatbuffers::TextMakeRule }, + { flatbuffers::GenerateCPP, "-c", "--cpp", "C++", true, + flatbuffers::GenerateCppGRPC, flatbuffers::IDLOptions::kCpp, + "Generate C++ headers for tables/structs", flatbuffers::CPPMakeRule }, + { flatbuffers::GenerateGo, "-g", "--go", "Go", true, + flatbuffers::GenerateGoGRPC, flatbuffers::IDLOptions::kGo, + "Generate Go files for tables/structs", nullptr }, + { flatbuffers::GenerateJava, "-j", "--java", "Java", true, + flatbuffers::GenerateJavaGRPC, flatbuffers::IDLOptions::kJava, + "Generate Java classes for tables/structs", + flatbuffers::JavaCSharpMakeRule }, + { flatbuffers::GenerateDart, "-d", "--dart", "Dart", true, nullptr, + flatbuffers::IDLOptions::kDart, + "Generate Dart classes for tables/structs", flatbuffers::DartMakeRule }, + { flatbuffers::GenerateTS, "-T", "--ts", "TypeScript", true, + flatbuffers::GenerateTSGRPC, flatbuffers::IDLOptions::kTs, + "Generate TypeScript code for tables/structs", flatbuffers::TSMakeRule }, + { flatbuffers::GenerateCSharp, "-n", "--csharp", "C#", true, nullptr, + flatbuffers::IDLOptions::kCSharp, + "Generate C# classes for tables/structs", + flatbuffers::JavaCSharpMakeRule }, + { flatbuffers::GeneratePython, "-p", "--python", "Python", true, + flatbuffers::GeneratePythonGRPC, flatbuffers::IDLOptions::kPython, + "Generate Python files for tables/structs", nullptr }, + { flatbuffers::GenerateLobster, nullptr, "--lobster", "Lobster", true, + nullptr, flatbuffers::IDLOptions::kLobster, + "Generate Lobster files for tables/structs", nullptr }, + { flatbuffers::GenerateLua, "-l", "--lua", "Lua", true, nullptr, + flatbuffers::IDLOptions::kLua, "Generate Lua files for tables/structs", + nullptr }, + { flatbuffers::GenerateRust, "-r", "--rust", "Rust", true, nullptr, + flatbuffers::IDLOptions::kRust, "Generate Rust files for tables/structs", + flatbuffers::RustMakeRule }, + { flatbuffers::GeneratePhp, nullptr, "--php", "PHP", true, nullptr, + flatbuffers::IDLOptions::kPhp, "Generate PHP files for tables/structs", + nullptr }, + { flatbuffers::GenerateKotlin, nullptr, "--kotlin", "Kotlin", true, nullptr, + flatbuffers::IDLOptions::kKotlin, + "Generate Kotlin classes for tables/structs", nullptr }, + { flatbuffers::GenerateJsonSchema, nullptr, "--jsonschema", "JsonSchema", + true, nullptr, flatbuffers::IDLOptions::kJsonSchema, + "Generate Json schema", nullptr }, + { flatbuffers::GenerateSwift, nullptr, "--swift", "swift", true, + flatbuffers::GenerateSwiftGRPC, flatbuffers::IDLOptions::kSwift, + "Generate Swift files for tables/structs", nullptr }, + { flatbuffers::GenerateCPPYandexMapsIter, nullptr, "--yandex-maps-iter", "C++Iter", + true, nullptr, flatbuffers::IDLOptions::kCppYandexMapsIter, + "Generate C++ template headers for tables/structs", nullptr }, + }; + + flatbuffers::FlatCompiler::InitParams params; + params.generators = generators; + params.num_generators = sizeof(generators) / sizeof(generators[0]); + params.warn_fn = Warn; + params.error_fn = Error; + + flatbuffers::FlatCompiler flatc(params); + return flatc.Compile(argc - 1, argv + 1); +} diff --git a/contrib/libs/flatbuffers/src/idl_gen_cpp.cpp b/contrib/libs/flatbuffers/src/idl_gen_cpp.cpp new file mode 100644 index 0000000000..a33697eaed --- /dev/null +++ b/contrib/libs/flatbuffers/src/idl_gen_cpp.cpp @@ -0,0 +1,3514 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// independent from idl_parser, since this code is not needed for most clients + +#include <unordered_set> + +#include "flatbuffers/code_generators.h" +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/flatc.h" +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +namespace flatbuffers { + +// Make numerical literal with type-suffix. +// This function is only needed for C++! Other languages do not need it. +static inline std::string NumToStringCpp(std::string val, BaseType type) { + // Avoid issues with -2147483648, -9223372036854775808. + switch (type) { + case BASE_TYPE_INT: + return (val != "-2147483648") ? val : ("(-2147483647 - 1)"); + case BASE_TYPE_ULONG: return (val == "0") ? val : (val + "ULL"); + case BASE_TYPE_LONG: + if (val == "-9223372036854775808") + return "(-9223372036854775807LL - 1LL)"; + else + return (val == "0") ? val : (val + "LL"); + default: return val; + } +} + +static std::string GenIncludeGuard(const std::string &file_name, + const Namespace &name_space, + const std::string &postfix = "") { + // Generate include guard. + std::string guard = file_name; + // Remove any non-alpha-numeric characters that may appear in a filename. + struct IsAlnum { + bool operator()(char c) const { return !is_alnum(c); } + }; + guard.erase(std::remove_if(guard.begin(), guard.end(), IsAlnum()), + guard.end()); + guard = "FLATBUFFERS_GENERATED_" + guard; + guard += "_"; + // For further uniqueness, also add the namespace. + for (auto it = name_space.components.begin(); + it != name_space.components.end(); ++it) { + guard += *it + "_"; + } + // Anything extra to add to the guard? + if (!postfix.empty()) { guard += postfix + "_"; } + guard += "H_"; + std::transform(guard.begin(), guard.end(), guard.begin(), CharToUpper); + return guard; +} + +namespace cpp { + +enum CppStandard { CPP_STD_X0 = 0, CPP_STD_11, CPP_STD_17 }; + +// Define a style of 'struct' constructor if it has 'Array' fields. +enum GenArrayArgMode { + kArrayArgModeNone, // don't generate initialization args + kArrayArgModeSpanStatic, // generate flatbuffers::span<T,N> +}; + +// Extension of IDLOptions for cpp-generator. +struct IDLOptionsCpp : public IDLOptions { + // All fields start with 'g_' prefix to distinguish from the base IDLOptions. + CppStandard g_cpp_std; // Base version of C++ standard. + bool g_only_fixed_enums; // Generate underlaying type for all enums. + + IDLOptionsCpp(const IDLOptions &opts) + : IDLOptions(opts), g_cpp_std(CPP_STD_11), g_only_fixed_enums(true) {} +}; + +class CppGenerator : public BaseGenerator { + public: + CppGenerator(const Parser &parser, const std::string &path, + const std::string &file_name, IDLOptionsCpp opts) + : BaseGenerator(parser, path, file_name, "", "::", "h"), + cur_name_space_(nullptr), + opts_(opts), + float_const_gen_("std::numeric_limits<double>::", + "std::numeric_limits<float>::", "quiet_NaN()", + "infinity()") { + static const char *const keywords[] = { + "alignas", + "alignof", + "and", + "and_eq", + "asm", + "atomic_cancel", + "atomic_commit", + "atomic_noexcept", + "auto", + "bitand", + "bitor", + "bool", + "break", + "case", + "catch", + "char", + "char16_t", + "char32_t", + "class", + "compl", + "concept", + "const", + "constexpr", + "const_cast", + "continue", + "co_await", + "co_return", + "co_yield", + "decltype", + "default", + "delete", + "do", + "double", + "dynamic_cast", + "else", + "enum", + "explicit", + "export", + "extern", + "false", + "float", + "for", + "friend", + "goto", + "if", + "import", + "inline", + "int", + "long", + "module", + "mutable", + "namespace", + "new", + "noexcept", + "not", + "not_eq", + "nullptr", + "operator", + "or", + "or_eq", + "private", + "protected", + "public", + "register", + "reinterpret_cast", + "requires", + "return", + "short", + "signed", + "sizeof", + "static", + "static_assert", + "static_cast", + "struct", + "switch", + "synchronized", + "template", + "this", + "thread_local", + "throw", + "true", + "try", + "typedef", + "typeid", + "typename", + "union", + "unsigned", + "using", + "virtual", + "void", + "volatile", + "wchar_t", + "while", + "xor", + "xor_eq", + nullptr, + }; + for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw); + } + + void GenIncludeDependencies() { + int num_includes = 0; + if (opts_.generate_object_based_api) { + for (auto it = parser_.native_included_files_.begin(); + it != parser_.native_included_files_.end(); ++it) { + code_ += "#include \"" + *it + "\""; + num_includes++; + } + } + for (auto it = parser_.included_files_.begin(); + it != parser_.included_files_.end(); ++it) { + if (it->second.empty()) continue; + auto noext = flatbuffers::StripExtension(it->second); + auto basename = flatbuffers::StripPath(noext); + auto includeName = + GeneratedFileName(opts_.include_prefix, + opts_.keep_include_path ? noext : basename, opts_); + code_ += "#include \"" + includeName + "\""; + num_includes++; + } + if (num_includes) code_ += ""; + } + + void GenExtraIncludes() { + for (std::size_t i = 0; i < opts_.cpp_includes.size(); ++i) { + code_ += "#include \"" + opts_.cpp_includes[i] + "\""; + } + if (!opts_.cpp_includes.empty()) { code_ += ""; } + } + + std::string EscapeKeyword(const std::string &name) const { + return keywords_.find(name) == keywords_.end() ? name : name + "_"; + } + + std::string Name(const Definition &def) const { + return EscapeKeyword(def.name); + } + + std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); } + + bool generate_bfbs_embed() { + code_.Clear(); + code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n"; + + // If we don't have a root struct definition, + if (!parser_.root_struct_def_) { + // put a comment in the output why there is no code generated. + code_ += "// Binary schema not generated, no root struct found"; + } else { + auto &struct_def = *parser_.root_struct_def_; + const auto include_guard = + GenIncludeGuard(file_name_, *struct_def.defined_namespace, "bfbs"); + + code_ += "#ifndef " + include_guard; + code_ += "#define " + include_guard; + code_ += ""; + if (parser_.opts.gen_nullable) { + code_ += "#pragma clang system_header\n\n"; + } + + SetNameSpace(struct_def.defined_namespace); + auto name = Name(struct_def); + code_.SetValue("STRUCT_NAME", name); + + // Create code to return the binary schema data. + auto binary_schema_hex_text = + BufferToHexText(parser_.builder_.GetBufferPointer(), + parser_.builder_.GetSize(), 105, " ", ""); + + code_ += "struct {{STRUCT_NAME}}BinarySchema {"; + code_ += " static const uint8_t *data() {"; + code_ += " // Buffer containing the binary schema."; + code_ += " static const uint8_t bfbsData[" + + NumToString(parser_.builder_.GetSize()) + "] = {"; + code_ += binary_schema_hex_text; + code_ += " };"; + code_ += " return bfbsData;"; + code_ += " }"; + code_ += " static size_t size() {"; + code_ += " return " + NumToString(parser_.builder_.GetSize()) + ";"; + code_ += " }"; + code_ += " const uint8_t *begin() {"; + code_ += " return data();"; + code_ += " }"; + code_ += " const uint8_t *end() {"; + code_ += " return data() + size();"; + code_ += " }"; + code_ += "};"; + code_ += ""; + + if (cur_name_space_) SetNameSpace(nullptr); + + // Close the include guard. + code_ += "#endif // " + include_guard; + } + + // We are just adding "_bfbs" to the generated filename. + const auto file_path = + GeneratedFileName(path_, file_name_ + "_bfbs", opts_); + const auto final_code = code_.ToString(); + + return SaveFile(file_path.c_str(), final_code, false); + } + + // Iterate through all definitions we haven't generate code for (enums, + // structs, and tables) and output them to a single file. + bool generate() { + code_.Clear(); + code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n"; + + const auto include_guard = + GenIncludeGuard(file_name_, *parser_.current_namespace_); + code_ += "#ifndef " + include_guard; + code_ += "#define " + include_guard; + code_ += ""; + + if (opts_.gen_nullable) { code_ += "#pragma clang system_header\n\n"; } + + code_ += "#include <contrib/libs/flatbuffers/include/flatbuffers/flatbuffers.h>"; + if (parser_.uses_flexbuffers_) { + code_ += "#include <contrib/libs/flatbuffers/include/flatbuffers/flexbuffers.h>"; + } + code_ += ""; + + if (opts_.include_dependence_headers) { GenIncludeDependencies(); } + GenExtraIncludes(); + + FLATBUFFERS_ASSERT(!cur_name_space_); + + // Generate forward declarations for all structs/tables, since they may + // have circular references. + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + const auto &struct_def = **it; + if (!struct_def.generated) { + SetNameSpace(struct_def.defined_namespace); + code_ += "struct " + Name(struct_def) + ";"; + if (!struct_def.fixed) { + code_ += "struct " + Name(struct_def) + "Builder;"; + } + if (opts_.generate_object_based_api) { + auto nativeName = NativeName(Name(struct_def), &struct_def, opts_); + if (!struct_def.fixed) { code_ += "struct " + nativeName + ";"; } + } + code_ += ""; + } + } + + // Generate forward declarations for all equal operators + if (opts_.generate_object_based_api && opts_.gen_compare) { + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + const auto &struct_def = **it; + if (!struct_def.generated) { + SetNameSpace(struct_def.defined_namespace); + auto nativeName = NativeName(Name(struct_def), &struct_def, opts_); + code_ += "bool operator==(const " + nativeName + " &lhs, const " + + nativeName + " &rhs);"; + code_ += "bool operator!=(const " + nativeName + " &lhs, const " + + nativeName + " &rhs);"; + } + } + code_ += ""; + } + + // Generate preablmle code for mini reflection. + if (opts_.mini_reflect != IDLOptions::kNone) { + // To break cyclic dependencies, first pre-declare all tables/structs. + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + const auto &struct_def = **it; + if (!struct_def.generated) { + SetNameSpace(struct_def.defined_namespace); + GenMiniReflectPre(&struct_def); + } + } + } + + // Generate code for all the enum declarations. + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + const auto &enum_def = **it; + if (!enum_def.generated) { + SetNameSpace(enum_def.defined_namespace); + GenEnum(enum_def); + } + } + + // Generate code for all structs, then all tables. + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + const auto &struct_def = **it; + if (struct_def.fixed && !struct_def.generated) { + SetNameSpace(struct_def.defined_namespace); + GenStruct(struct_def); + } + } + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + const auto &struct_def = **it; + if (!struct_def.fixed && !struct_def.generated) { + SetNameSpace(struct_def.defined_namespace); + GenTable(struct_def); + } + } + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + const auto &struct_def = **it; + if (!struct_def.fixed && !struct_def.generated) { + SetNameSpace(struct_def.defined_namespace); + GenTablePost(struct_def); + } + } + + // Generate code for union verifiers. + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + const auto &enum_def = **it; + if (enum_def.is_union && !enum_def.generated) { + SetNameSpace(enum_def.defined_namespace); + GenUnionPost(enum_def); + } + } + + // Generate code for mini reflection. + if (opts_.mini_reflect != IDLOptions::kNone) { + // Then the unions/enums that may refer to them. + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + const auto &enum_def = **it; + if (!enum_def.generated) { + SetNameSpace(enum_def.defined_namespace); + GenMiniReflect(nullptr, &enum_def); + } + } + // Then the full tables/structs. + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + const auto &struct_def = **it; + if (!struct_def.generated) { + SetNameSpace(struct_def.defined_namespace); + GenMiniReflect(&struct_def, nullptr); + } + } + } + + // Generate convenient global helper functions: + if (parser_.root_struct_def_) { + auto &struct_def = *parser_.root_struct_def_; + SetNameSpace(struct_def.defined_namespace); + auto name = Name(struct_def); + auto qualified_name = cur_name_space_->GetFullyQualifiedName(name); + auto cpp_name = TranslateNameSpace(qualified_name); + + code_.SetValue("STRUCT_NAME", name); + code_.SetValue("CPP_NAME", cpp_name); + code_.SetValue("NULLABLE_EXT", NullableExtension()); + + // The root datatype accessor: + code_ += "inline \\"; + code_ += + "const {{CPP_NAME}} *{{NULLABLE_EXT}}Get{{STRUCT_NAME}}(const void " + "*buf) {"; + code_ += " return flatbuffers::GetRoot<{{CPP_NAME}}>(buf);"; + code_ += "}"; + code_ += ""; + + code_ += "inline \\"; + code_ += + "const {{CPP_NAME}} " + "*{{NULLABLE_EXT}}GetSizePrefixed{{STRUCT_NAME}}(const void " + "*buf) {"; + code_ += " return flatbuffers::GetSizePrefixedRoot<{{CPP_NAME}}>(buf);"; + code_ += "}"; + code_ += ""; + + if (opts_.mutable_buffer) { + code_ += "inline \\"; + code_ += "{{STRUCT_NAME}} *GetMutable{{STRUCT_NAME}}(void *buf) {"; + code_ += " return flatbuffers::GetMutableRoot<{{STRUCT_NAME}}>(buf);"; + code_ += "}"; + code_ += ""; + } + + if (parser_.file_identifier_.length()) { + // Return the identifier + code_ += "inline const char *{{STRUCT_NAME}}Identifier() {"; + code_ += " return \"" + parser_.file_identifier_ + "\";"; + code_ += "}"; + code_ += ""; + + // Check if a buffer has the identifier. + code_ += "inline \\"; + code_ += "bool {{STRUCT_NAME}}BufferHasIdentifier(const void *buf) {"; + code_ += " return flatbuffers::BufferHasIdentifier("; + code_ += " buf, {{STRUCT_NAME}}Identifier());"; + code_ += "}"; + code_ += ""; + } + + // The root verifier. + if (parser_.file_identifier_.length()) { + code_.SetValue("ID", name + "Identifier()"); + } else { + code_.SetValue("ID", "nullptr"); + } + + code_ += "inline bool Verify{{STRUCT_NAME}}Buffer("; + code_ += " flatbuffers::Verifier &verifier) {"; + code_ += " return verifier.VerifyBuffer<{{CPP_NAME}}>({{ID}});"; + code_ += "}"; + code_ += ""; + + code_ += "inline bool VerifySizePrefixed{{STRUCT_NAME}}Buffer("; + code_ += " flatbuffers::Verifier &verifier) {"; + code_ += + " return verifier.VerifySizePrefixedBuffer<{{CPP_NAME}}>({{ID}});"; + code_ += "}"; + code_ += ""; + + if (parser_.file_extension_.length()) { + // Return the extension + code_ += "inline const char *{{STRUCT_NAME}}Extension() {"; + code_ += " return \"" + parser_.file_extension_ + "\";"; + code_ += "}"; + code_ += ""; + } + + // Finish a buffer with a given root object: + code_ += "inline void Finish{{STRUCT_NAME}}Buffer("; + code_ += " flatbuffers::FlatBufferBuilder &fbb,"; + code_ += " flatbuffers::Offset<{{CPP_NAME}}> root) {"; + if (parser_.file_identifier_.length()) + code_ += " fbb.Finish(root, {{STRUCT_NAME}}Identifier());"; + else + code_ += " fbb.Finish(root);"; + code_ += "}"; + code_ += ""; + + code_ += "inline void FinishSizePrefixed{{STRUCT_NAME}}Buffer("; + code_ += " flatbuffers::FlatBufferBuilder &fbb,"; + code_ += " flatbuffers::Offset<{{CPP_NAME}}> root) {"; + if (parser_.file_identifier_.length()) + code_ += " fbb.FinishSizePrefixed(root, {{STRUCT_NAME}}Identifier());"; + else + code_ += " fbb.FinishSizePrefixed(root);"; + code_ += "}"; + code_ += ""; + + if (opts_.generate_object_based_api) { + // A convenient root unpack function. + auto native_name = WrapNativeNameInNameSpace(struct_def, opts_); + code_.SetValue("UNPACK_RETURN", + GenTypeNativePtr(native_name, nullptr, false)); + code_.SetValue("UNPACK_TYPE", + GenTypeNativePtr(native_name, nullptr, true)); + + code_ += "inline {{UNPACK_RETURN}} UnPack{{STRUCT_NAME}}("; + code_ += " const void *buf,"; + code_ += " const flatbuffers::resolver_function_t *res = nullptr) {"; + code_ += " return {{UNPACK_TYPE}}\\"; + code_ += "(Get{{STRUCT_NAME}}(buf)->UnPack(res));"; + code_ += "}"; + code_ += ""; + + code_ += "inline {{UNPACK_RETURN}} UnPackSizePrefixed{{STRUCT_NAME}}("; + code_ += " const void *buf,"; + code_ += " const flatbuffers::resolver_function_t *res = nullptr) {"; + code_ += " return {{UNPACK_TYPE}}\\"; + code_ += "(GetSizePrefixed{{STRUCT_NAME}}(buf)->UnPack(res));"; + code_ += "}"; + code_ += ""; + } + } + + if (cur_name_space_) SetNameSpace(nullptr); + + // Close the include guard. + code_ += "#endif // " + include_guard; + + const auto file_path = GeneratedFileName(path_, file_name_, opts_); + const auto final_code = code_.ToString(); + + // Save the file and optionally generate the binary schema code. + return SaveFile(file_path.c_str(), final_code, false) && + (!parser_.opts.binary_schema_gen_embed || generate_bfbs_embed()); + } + + private: + CodeWriter code_; + + std::unordered_set<std::string> keywords_; + + // This tracks the current namespace so we can insert namespace declarations. + const Namespace *cur_name_space_; + + const IDLOptionsCpp opts_; + const TypedFloatConstantGenerator float_const_gen_; + + const Namespace *CurrentNameSpace() const { return cur_name_space_; } + + // Translates a qualified name in flatbuffer text format to the same name in + // the equivalent C++ namespace. + static std::string TranslateNameSpace(const std::string &qualified_name) { + std::string cpp_qualified_name = qualified_name; + size_t start_pos = 0; + while ((start_pos = cpp_qualified_name.find('.', start_pos)) != + std::string::npos) { + cpp_qualified_name.replace(start_pos, 1, "::"); + } + return cpp_qualified_name; + } + + bool TypeHasKey(const Type &type) { + if (type.base_type != BASE_TYPE_STRUCT) { return false; } + for (auto it = type.struct_def->fields.vec.begin(); + it != type.struct_def->fields.vec.end(); ++it) { + const auto &field = **it; + if (field.key) { return true; } + } + return false; + } + + bool VectorElementUserFacing(const Type &type) const { + return opts_.g_cpp_std >= cpp::CPP_STD_17 && opts_.g_only_fixed_enums && + IsEnum(type); + } + + void GenComment(const std::vector<std::string> &dc, const char *prefix = "") { + std::string text; + ::flatbuffers::GenComment(dc, &text, nullptr, prefix); + code_ += text + "\\"; + } + + // Return a C++ type from the table in idl.h + std::string GenTypeBasic(const Type &type, bool user_facing_type) const { + // clang-format off + static const char *const ctypename[] = { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ + #CTYPE, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + }; + // clang-format on + if (user_facing_type) { + if (type.enum_def) return WrapInNameSpace(*type.enum_def); + if (type.base_type == BASE_TYPE_BOOL) return "bool"; + } + return ctypename[type.base_type]; + } + + // Return a C++ pointer type, specialized to the actual struct/table types, + // and vector element types. + std::string GenTypePointer(const Type &type) const { + switch (type.base_type) { + case BASE_TYPE_STRING: { + return "flatbuffers::String"; + } + case BASE_TYPE_VECTOR: { + const auto type_name = GenTypeWire( + type.VectorType(), "", VectorElementUserFacing(type.VectorType())); + return "flatbuffers::Vector<" + type_name + ">"; + } + case BASE_TYPE_STRUCT: { + return WrapInNameSpace(*type.struct_def); + } + case BASE_TYPE_UNION: + // fall through + default: { + return "void"; + } + } + } + + // Return a C++ type for any type (scalar/pointer) specifically for + // building a flatbuffer. + std::string GenTypeWire(const Type &type, const char *postfix, + bool user_facing_type) const { + if (IsScalar(type.base_type)) { + return GenTypeBasic(type, user_facing_type) + postfix; + } else if (IsStruct(type)) { + return "const " + GenTypePointer(type) + " *"; + } else { + return "flatbuffers::Offset<" + GenTypePointer(type) + ">" + postfix; + } + } + + // Return a C++ type for any type (scalar/pointer) that reflects its + // serialized size. + std::string GenTypeSize(const Type &type) const { + if (IsScalar(type.base_type)) { + return GenTypeBasic(type, false); + } else if (IsStruct(type)) { + return GenTypePointer(type); + } else { + return "flatbuffers::uoffset_t"; + } + } + + std::string NullableExtension() { + return opts_.gen_nullable ? " _Nullable " : ""; + } + + static std::string NativeName(const std::string &name, const StructDef *sd, + const IDLOptions &opts) { + return sd && !sd->fixed ? opts.object_prefix + name + opts.object_suffix + : name; + } + + std::string WrapNativeNameInNameSpace(const StructDef &struct_def, + const IDLOptions &opts) { + return WrapInNameSpace(struct_def.defined_namespace, + NativeName(Name(struct_def), &struct_def, opts)); + } + + const std::string &PtrType(const FieldDef *field) { + auto attr = field ? field->attributes.Lookup("cpp_ptr_type") : nullptr; + return attr ? attr->constant : opts_.cpp_object_api_pointer_type; + } + + const std::string NativeString(const FieldDef *field) { + auto attr = field ? field->attributes.Lookup("cpp_str_type") : nullptr; + auto &ret = attr ? attr->constant : opts_.cpp_object_api_string_type; + if (ret.empty()) { return "std::string"; } + return ret; + } + + bool FlexibleStringConstructor(const FieldDef *field) { + auto attr = field + ? (field->attributes.Lookup("cpp_str_flex_ctor") != nullptr) + : false; + auto ret = attr ? attr : opts_.cpp_object_api_string_flexible_constructor; + return ret && NativeString(field) != + "std::string"; // Only for custom string types. + } + + std::string GenTypeNativePtr(const std::string &type, const FieldDef *field, + bool is_constructor) { + auto &ptr_type = PtrType(field); + if (ptr_type != "naked") { + return (ptr_type != "default_ptr_type" + ? ptr_type + : opts_.cpp_object_api_pointer_type) + + "<" + type + ">"; + } else if (is_constructor) { + return ""; + } else { + return type + " *"; + } + } + + std::string GenPtrGet(const FieldDef &field) { + auto cpp_ptr_type_get = field.attributes.Lookup("cpp_ptr_type_get"); + if (cpp_ptr_type_get) return cpp_ptr_type_get->constant; + auto &ptr_type = PtrType(&field); + return ptr_type == "naked" ? "" : ".get()"; + } + + std::string GenOptionalNull() { return "flatbuffers::nullopt"; } + + std::string GenOptionalDecl(const Type &type) { + return "flatbuffers::Optional<" + GenTypeBasic(type, true) + ">"; + } + + std::string GenTypeNative(const Type &type, bool invector, + const FieldDef &field) { + switch (type.base_type) { + case BASE_TYPE_STRING: { + return NativeString(&field); + } + case BASE_TYPE_VECTOR: { + const auto type_name = GenTypeNative(type.VectorType(), true, field); + if (type.struct_def && + type.struct_def->attributes.Lookup("native_custom_alloc")) { + auto native_custom_alloc = + type.struct_def->attributes.Lookup("native_custom_alloc"); + return "std::vector<" + type_name + "," + + native_custom_alloc->constant + "<" + type_name + ">>"; + } else + return "std::vector<" + type_name + ">"; + } + case BASE_TYPE_STRUCT: { + auto type_name = WrapInNameSpace(*type.struct_def); + if (IsStruct(type)) { + auto native_type = type.struct_def->attributes.Lookup("native_type"); + if (native_type) { type_name = native_type->constant; } + if (invector || field.native_inline) { + return type_name; + } else { + return GenTypeNativePtr(type_name, &field, false); + } + } else { + return GenTypeNativePtr( + WrapNativeNameInNameSpace(*type.struct_def, opts_), &field, + false); + } + } + case BASE_TYPE_UNION: { + auto type_name = WrapInNameSpace(*type.enum_def); + return type_name + "Union"; + } + default: { + return field.IsScalarOptional() ? GenOptionalDecl(type) + : GenTypeBasic(type, true); + } + } + } + + // Return a C++ type for any type (scalar/pointer) specifically for + // using a flatbuffer. + std::string GenTypeGet(const Type &type, const char *afterbasic, + const char *beforeptr, const char *afterptr, + bool user_facing_type) { + if (IsScalar(type.base_type)) { + return GenTypeBasic(type, user_facing_type) + afterbasic; + } else if (IsArray(type)) { + auto element_type = type.VectorType(); + // Check if enum arrays are used in C++ without specifying --scoped-enums + if (IsEnum(element_type) && !opts_.g_only_fixed_enums) { + LogCompilerError( + "--scoped-enums must be enabled to use enum arrays in C++"); + FLATBUFFERS_ASSERT(true); + } + return beforeptr + + (IsScalar(element_type.base_type) + ? GenTypeBasic(element_type, user_facing_type) + : GenTypePointer(element_type)) + + afterptr; + } else { + return beforeptr + GenTypePointer(type) + afterptr; + } + } + + std::string GenTypeSpan(const Type &type, bool immutable, size_t extent) { + // Generate "flatbuffers::span<const U, extent>". + FLATBUFFERS_ASSERT(IsSeries(type) && "unexpected type"); + auto element_type = type.VectorType(); + std::string text = "flatbuffers::span<"; + text += immutable ? "const " : ""; + if (IsScalar(element_type.base_type)) { + text += GenTypeBasic(element_type, IsEnum(element_type)); + } else { + switch (element_type.base_type) { + case BASE_TYPE_STRING: { + text += "char"; + break; + } + case BASE_TYPE_STRUCT: { + FLATBUFFERS_ASSERT(type.struct_def); + text += WrapInNameSpace(*type.struct_def); + break; + } + default: + FLATBUFFERS_ASSERT(false && "unexpected element's type"); + break; + } + } + if (extent != flatbuffers::dynamic_extent) { + text += ", "; + text += NumToString(extent); + } + text += "> "; + return text; + } + + std::string GenEnumValDecl(const EnumDef &enum_def, + const std::string &enum_val) const { + return opts_.prefixed_enums ? Name(enum_def) + "_" + enum_val : enum_val; + } + + std::string GetEnumValUse(const EnumDef &enum_def, + const EnumVal &enum_val) const { + if (opts_.scoped_enums) { + return Name(enum_def) + "::" + Name(enum_val); + } else if (opts_.prefixed_enums) { + return Name(enum_def) + "_" + Name(enum_val); + } else { + return Name(enum_val); + } + } + + std::string StripUnionType(const std::string &name) { + return name.substr(0, name.size() - strlen(UnionTypeFieldSuffix())); + } + + std::string GetUnionElement(const EnumVal &ev, bool native_type, + const IDLOptions &opts) { + if (ev.union_type.base_type == BASE_TYPE_STRUCT) { + auto name = ev.union_type.struct_def->name; + if (native_type) { + name = NativeName(name, ev.union_type.struct_def, opts); + } + return WrapInNameSpace(ev.union_type.struct_def->defined_namespace, name); + } else if (IsString(ev.union_type)) { + return native_type ? "std::string" : "flatbuffers::String"; + } else { + FLATBUFFERS_ASSERT(false); + return Name(ev); + } + } + + std::string UnionVerifySignature(const EnumDef &enum_def) { + return "bool Verify" + Name(enum_def) + + "(flatbuffers::Verifier &verifier, const void *obj, " + + Name(enum_def) + " type)"; + } + + std::string UnionVectorVerifySignature(const EnumDef &enum_def) { + return "bool Verify" + Name(enum_def) + "Vector" + + "(flatbuffers::Verifier &verifier, " + + "const flatbuffers::Vector<flatbuffers::Offset<void>> *values, " + + "const flatbuffers::Vector<uint8_t> *types)"; + } + + std::string UnionUnPackSignature(const EnumDef &enum_def, bool inclass) { + return (inclass ? "static " : "") + std::string("void *") + + (inclass ? "" : Name(enum_def) + "Union::") + + "UnPack(const void *obj, " + Name(enum_def) + + " type, const flatbuffers::resolver_function_t *resolver)"; + } + + std::string UnionPackSignature(const EnumDef &enum_def, bool inclass) { + return "flatbuffers::Offset<void> " + + (inclass ? "" : Name(enum_def) + "Union::") + + "Pack(flatbuffers::FlatBufferBuilder &_fbb, " + + "const flatbuffers::rehasher_function_t *_rehasher" + + (inclass ? " = nullptr" : "") + ") const"; + } + + std::string TableCreateSignature(const StructDef &struct_def, bool predecl, + const IDLOptions &opts) { + return "flatbuffers::Offset<" + Name(struct_def) + "> Create" + + Name(struct_def) + "(flatbuffers::FlatBufferBuilder &_fbb, const " + + NativeName(Name(struct_def), &struct_def, opts) + + " *_o, const flatbuffers::rehasher_function_t *_rehasher" + + (predecl ? " = nullptr" : "") + ")"; + } + + std::string TablePackSignature(const StructDef &struct_def, bool inclass, + const IDLOptions &opts) { + return std::string(inclass ? "static " : "") + "flatbuffers::Offset<" + + Name(struct_def) + "> " + (inclass ? "" : Name(struct_def) + "::") + + "Pack(flatbuffers::FlatBufferBuilder &_fbb, " + "const " + + NativeName(Name(struct_def), &struct_def, opts) + "* _o, " + + "const flatbuffers::rehasher_function_t *_rehasher" + + (inclass ? " = nullptr" : "") + ")"; + } + + std::string TableUnPackSignature(const StructDef &struct_def, bool inclass, + const IDLOptions &opts) { + return NativeName(Name(struct_def), &struct_def, opts) + " *" + + (inclass ? "" : Name(struct_def) + "::") + + "UnPack(const flatbuffers::resolver_function_t *_resolver" + + (inclass ? " = nullptr" : "") + ") const"; + } + + std::string TableUnPackToSignature(const StructDef &struct_def, bool inclass, + const IDLOptions &opts) { + return "void " + (inclass ? "" : Name(struct_def) + "::") + "UnPackTo(" + + NativeName(Name(struct_def), &struct_def, opts) + " *" + + "_o, const flatbuffers::resolver_function_t *_resolver" + + (inclass ? " = nullptr" : "") + ") const"; + } + + void GenMiniReflectPre(const StructDef *struct_def) { + code_.SetValue("NAME", struct_def->name); + code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable();"; + code_ += ""; + } + + void GenMiniReflect(const StructDef *struct_def, const EnumDef *enum_def) { + code_.SetValue("NAME", struct_def ? struct_def->name : enum_def->name); + code_.SetValue("SEQ_TYPE", + struct_def ? (struct_def->fixed ? "ST_STRUCT" : "ST_TABLE") + : (enum_def->is_union ? "ST_UNION" : "ST_ENUM")); + auto num_fields = + struct_def ? struct_def->fields.vec.size() : enum_def->size(); + code_.SetValue("NUM_FIELDS", NumToString(num_fields)); + std::vector<std::string> names; + std::vector<Type> types; + + if (struct_def) { + for (auto it = struct_def->fields.vec.begin(); + it != struct_def->fields.vec.end(); ++it) { + const auto &field = **it; + names.push_back(Name(field)); + types.push_back(field.value.type); + } + } else { + for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end(); + ++it) { + const auto &ev = **it; + names.push_back(Name(ev)); + types.push_back(enum_def->is_union ? ev.union_type + : Type(enum_def->underlying_type)); + } + } + std::string ts; + std::vector<std::string> type_refs; + std::vector<uint16_t> array_sizes; + for (auto it = types.begin(); it != types.end(); ++it) { + auto &type = *it; + if (!ts.empty()) ts += ",\n "; + auto is_vector = IsVector(type); + auto is_array = IsArray(type); + auto bt = is_vector || is_array ? type.element : type.base_type; + auto et = IsScalar(bt) || bt == BASE_TYPE_STRING + ? bt - BASE_TYPE_UTYPE + ET_UTYPE + : ET_SEQUENCE; + int ref_idx = -1; + std::string ref_name = + type.struct_def + ? WrapInNameSpace(*type.struct_def) + : type.enum_def ? WrapInNameSpace(*type.enum_def) : ""; + if (!ref_name.empty()) { + auto rit = type_refs.begin(); + for (; rit != type_refs.end(); ++rit) { + if (*rit == ref_name) { + ref_idx = static_cast<int>(rit - type_refs.begin()); + break; + } + } + if (rit == type_refs.end()) { + ref_idx = static_cast<int>(type_refs.size()); + type_refs.push_back(ref_name); + } + } + if (is_array) { array_sizes.push_back(type.fixed_length); } + ts += "{ flatbuffers::" + std::string(ElementaryTypeNames()[et]) + ", " + + NumToString(is_vector || is_array) + ", " + NumToString(ref_idx) + + " }"; + } + std::string rs; + for (auto it = type_refs.begin(); it != type_refs.end(); ++it) { + if (!rs.empty()) rs += ",\n "; + rs += *it + "TypeTable"; + } + std::string as; + for (auto it = array_sizes.begin(); it != array_sizes.end(); ++it) { + as += NumToString(*it); + as += ", "; + } + std::string ns; + for (auto it = names.begin(); it != names.end(); ++it) { + if (!ns.empty()) ns += ",\n "; + ns += "\"" + *it + "\""; + } + std::string vs; + const auto consecutive_enum_from_zero = + enum_def && enum_def->MinValue()->IsZero() && + ((enum_def->size() - 1) == enum_def->Distance()); + if (enum_def && !consecutive_enum_from_zero) { + for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end(); + ++it) { + const auto &ev = **it; + if (!vs.empty()) vs += ", "; + vs += NumToStringCpp(enum_def->ToString(ev), + enum_def->underlying_type.base_type); + } + } else if (struct_def && struct_def->fixed) { + for (auto it = struct_def->fields.vec.begin(); + it != struct_def->fields.vec.end(); ++it) { + const auto &field = **it; + vs += NumToString(field.value.offset); + vs += ", "; + } + vs += NumToString(struct_def->bytesize); + } + code_.SetValue("TYPES", ts); + code_.SetValue("REFS", rs); + code_.SetValue("ARRAYSIZES", as); + code_.SetValue("NAMES", ns); + code_.SetValue("VALUES", vs); + code_ += "inline const flatbuffers::TypeTable *{{NAME}}TypeTable() {"; + if (num_fields) { + code_ += " static const flatbuffers::TypeCode type_codes[] = {"; + code_ += " {{TYPES}}"; + code_ += " };"; + } + if (!type_refs.empty()) { + code_ += " static const flatbuffers::TypeFunction type_refs[] = {"; + code_ += " {{REFS}}"; + code_ += " };"; + } + if (!as.empty()) { + code_ += " static const int16_t array_sizes[] = { {{ARRAYSIZES}} };"; + } + if (!vs.empty()) { + // Problem with uint64_t values greater than 9223372036854775807ULL. + code_ += " static const int64_t values[] = { {{VALUES}} };"; + } + auto has_names = + num_fields && opts_.mini_reflect == IDLOptions::kTypesAndNames; + if (has_names) { + code_ += " static const char * const names[] = {"; + code_ += " {{NAMES}}"; + code_ += " };"; + } + code_ += " static const flatbuffers::TypeTable tt = {"; + code_ += std::string(" flatbuffers::{{SEQ_TYPE}}, {{NUM_FIELDS}}, ") + + (num_fields ? "type_codes, " : "nullptr, ") + + (!type_refs.empty() ? "type_refs, " : "nullptr, ") + + (!as.empty() ? "array_sizes, " : "nullptr, ") + + (!vs.empty() ? "values, " : "nullptr, ") + + (has_names ? "names" : "nullptr"); + code_ += " };"; + code_ += " return &tt;"; + code_ += "}"; + code_ += ""; + } + + // Generate an enum declaration, + // an enum string lookup table, + // and an enum array of values + + void GenEnum(const EnumDef &enum_def) { + code_.SetValue("ENUM_NAME", Name(enum_def)); + code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false)); + + GenComment(enum_def.doc_comment); + code_ += + (opts_.scoped_enums ? "enum class " : "enum ") + Name(enum_def) + "\\"; + if (opts_.g_only_fixed_enums) { code_ += " : {{BASE_TYPE}}\\"; } + code_ += " {"; + + code_.SetValue("SEP", ","); + auto add_sep = false; + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + const auto &ev = **it; + if (add_sep) code_ += "{{SEP}}"; + GenComment(ev.doc_comment, " "); + code_.SetValue("KEY", GenEnumValDecl(enum_def, Name(ev))); + code_.SetValue("VALUE", + NumToStringCpp(enum_def.ToString(ev), + enum_def.underlying_type.base_type)); + code_ += " {{KEY}} = {{VALUE}}\\"; + add_sep = true; + } + const EnumVal *minv = enum_def.MinValue(); + const EnumVal *maxv = enum_def.MaxValue(); + + if (opts_.scoped_enums || opts_.prefixed_enums) { + FLATBUFFERS_ASSERT(minv && maxv); + + code_.SetValue("SEP", ",\n"); + if (enum_def.attributes.Lookup("bit_flags")) { + code_.SetValue("KEY", GenEnumValDecl(enum_def, "NONE")); + code_.SetValue("VALUE", "0"); + code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\"; + + code_.SetValue("KEY", GenEnumValDecl(enum_def, "ANY")); + code_.SetValue("VALUE", + NumToStringCpp(enum_def.AllFlags(), + enum_def.underlying_type.base_type)); + code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\"; + } else { // MIN & MAX are useless for bit_flags + code_.SetValue("KEY", GenEnumValDecl(enum_def, "MIN")); + code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*minv))); + code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\"; + + code_.SetValue("KEY", GenEnumValDecl(enum_def, "MAX")); + code_.SetValue("VALUE", GenEnumValDecl(enum_def, Name(*maxv))); + code_ += "{{SEP}} {{KEY}} = {{VALUE}}\\"; + } + } + code_ += ""; + code_ += "};"; + + if (opts_.scoped_enums && enum_def.attributes.Lookup("bit_flags")) { + code_ += + "FLATBUFFERS_DEFINE_BITMASK_OPERATORS({{ENUM_NAME}}, {{BASE_TYPE}})"; + } + code_ += ""; + + // Generate an array of all enumeration values + auto num_fields = NumToString(enum_def.size()); + code_ += "inline const {{ENUM_NAME}} (&EnumValues{{ENUM_NAME}}())[" + + num_fields + "] {"; + code_ += " static const {{ENUM_NAME}} values[] = {"; + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + const auto &ev = **it; + auto value = GetEnumValUse(enum_def, ev); + auto suffix = *it != enum_def.Vals().back() ? "," : ""; + code_ += " " + value + suffix; + } + code_ += " };"; + code_ += " return values;"; + code_ += "}"; + code_ += ""; + + // Generate a generate string table for enum values. + // Problem is, if values are very sparse that could generate really big + // tables. Ideally in that case we generate a map lookup instead, but for + // the moment we simply don't output a table at all. + auto range = enum_def.Distance(); + // Average distance between values above which we consider a table + // "too sparse". Change at will. + static const uint64_t kMaxSparseness = 5; + if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) { + code_ += "inline const char * const *EnumNames{{ENUM_NAME}}() {"; + code_ += " static const char * const names[" + + NumToString(range + 1 + 1) + "] = {"; + + auto val = enum_def.Vals().front(); + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); + ++it) { + auto ev = *it; + for (auto k = enum_def.Distance(val, ev); k > 1; --k) { + code_ += " \"\","; + } + val = ev; + code_ += " \"" + Name(*ev) + "\","; + } + code_ += " nullptr"; + code_ += " };"; + + code_ += " return names;"; + code_ += "}"; + code_ += ""; + + code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {"; + + code_ += " if (flatbuffers::IsOutRange(e, " + + GetEnumValUse(enum_def, *enum_def.MinValue()) + ", " + + GetEnumValUse(enum_def, *enum_def.MaxValue()) + + ")) return \"\";"; + + code_ += " const size_t index = static_cast<size_t>(e)\\"; + if (enum_def.MinValue()->IsNonZero()) { + auto vals = GetEnumValUse(enum_def, *enum_def.MinValue()); + code_ += " - static_cast<size_t>(" + vals + ")\\"; + } + code_ += ";"; + + code_ += " return EnumNames{{ENUM_NAME}}()[index];"; + code_ += "}"; + code_ += ""; + } else { + code_ += "inline const char *EnumName{{ENUM_NAME}}({{ENUM_NAME}} e) {"; + + code_ += " switch (e) {"; + + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); + ++it) { + const auto &ev = **it; + code_ += " case " + GetEnumValUse(enum_def, ev) + ": return \"" + + Name(ev) + "\";"; + } + + code_ += " default: return \"\";"; + code_ += " }"; + + code_ += "}"; + code_ += ""; + } + + // Generate type traits for unions to map from a type to union enum value. + if (enum_def.is_union && !enum_def.uses_multiple_type_instances) { + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); + ++it) { + const auto &ev = **it; + + if (it == enum_def.Vals().begin()) { + code_ += "template<typename T> struct {{ENUM_NAME}}Traits {"; + } else { + auto name = GetUnionElement(ev, false, opts_); + code_ += "template<> struct {{ENUM_NAME}}Traits<" + name + "> {"; + } + + auto value = GetEnumValUse(enum_def, ev); + code_ += " static const {{ENUM_NAME}} enum_value = " + value + ";"; + code_ += "};"; + code_ += ""; + } + } + + if (opts_.generate_object_based_api && enum_def.is_union) { + // Generate a union type + code_.SetValue("NAME", Name(enum_def)); + FLATBUFFERS_ASSERT(enum_def.Lookup("NONE")); + code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE"))); + + code_ += "struct {{NAME}}Union {"; + code_ += " {{NAME}} type;"; + code_ += " void *value;"; + code_ += ""; + code_ += " {{NAME}}Union() : type({{NONE}}), value(nullptr) {}"; + code_ += " {{NAME}}Union({{NAME}}Union&& u) FLATBUFFERS_NOEXCEPT :"; + code_ += " type({{NONE}}), value(nullptr)"; + code_ += " { std::swap(type, u.type); std::swap(value, u.value); }"; + code_ += " {{NAME}}Union(const {{NAME}}Union &);"; + code_ += " {{NAME}}Union &operator=(const {{NAME}}Union &u)"; + code_ += + " { {{NAME}}Union t(u); std::swap(type, t.type); std::swap(value, " + "t.value); return *this; }"; + code_ += + " {{NAME}}Union &operator=({{NAME}}Union &&u) FLATBUFFERS_NOEXCEPT"; + code_ += + " { std::swap(type, u.type); std::swap(value, u.value); return " + "*this; }"; + code_ += " ~{{NAME}}Union() { Reset(); }"; + code_ += ""; + code_ += " void Reset();"; + code_ += ""; + if (!enum_def.uses_multiple_type_instances) { + code_ += "#ifndef FLATBUFFERS_CPP98_STL"; + code_ += " template <typename T>"; + code_ += " void Set(T&& val) {"; + code_ += " using RT = typename std::remove_reference<T>::type;"; + code_ += " Reset();"; + code_ += + " type = {{NAME}}Traits<typename RT::TableType>::enum_value;"; + code_ += " if (type != {{NONE}}) {"; + code_ += " value = new RT(std::forward<T>(val));"; + code_ += " }"; + code_ += " }"; + code_ += "#endif // FLATBUFFERS_CPP98_STL"; + code_ += ""; + } + code_ += " " + UnionUnPackSignature(enum_def, true) + ";"; + code_ += " " + UnionPackSignature(enum_def, true) + ";"; + code_ += ""; + + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); + ++it) { + const auto &ev = **it; + if (ev.IsZero()) { continue; } + + const auto native_type = GetUnionElement(ev, true, opts_); + code_.SetValue("NATIVE_TYPE", native_type); + code_.SetValue("NATIVE_NAME", Name(ev)); + code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev)); + + code_ += " {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() {"; + code_ += " return type == {{NATIVE_ID}} ?"; + code_ += " reinterpret_cast<{{NATIVE_TYPE}} *>(value) : nullptr;"; + code_ += " }"; + + code_ += " const {{NATIVE_TYPE}} *As{{NATIVE_NAME}}() const {"; + code_ += " return type == {{NATIVE_ID}} ?"; + code_ += + " reinterpret_cast<const {{NATIVE_TYPE}} *>(value) : nullptr;"; + code_ += " }"; + } + code_ += "};"; + code_ += ""; + + if (opts_.gen_compare) { + code_ += ""; + code_ += + "inline bool operator==(const {{NAME}}Union &lhs, const " + "{{NAME}}Union &rhs) {"; + code_ += " if (lhs.type != rhs.type) return false;"; + code_ += " switch (lhs.type) {"; + + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); + ++it) { + const auto &ev = **it; + code_.SetValue("NATIVE_ID", GetEnumValUse(enum_def, ev)); + if (ev.IsNonZero()) { + const auto native_type = GetUnionElement(ev, true, opts_); + code_.SetValue("NATIVE_TYPE", native_type); + code_ += " case {{NATIVE_ID}}: {"; + code_ += + " return *(reinterpret_cast<const {{NATIVE_TYPE}} " + "*>(lhs.value)) =="; + code_ += + " *(reinterpret_cast<const {{NATIVE_TYPE}} " + "*>(rhs.value));"; + code_ += " }"; + } else { + code_ += " case {{NATIVE_ID}}: {"; + code_ += " return true;"; // "NONE" enum value. + code_ += " }"; + } + } + code_ += " default: {"; + code_ += " return false;"; + code_ += " }"; + code_ += " }"; + code_ += "}"; + + code_ += ""; + code_ += + "inline bool operator!=(const {{NAME}}Union &lhs, const " + "{{NAME}}Union &rhs) {"; + code_ += " return !(lhs == rhs);"; + code_ += "}"; + code_ += ""; + } + } + + if (enum_def.is_union) { + code_ += UnionVerifySignature(enum_def) + ";"; + code_ += UnionVectorVerifySignature(enum_def) + ";"; + code_ += ""; + } + } + + void GenUnionPost(const EnumDef &enum_def) { + // Generate a verifier function for this union that can be called by the + // table verifier functions. It uses a switch case to select a specific + // verifier function to call, this should be safe even if the union type + // has been corrupted, since the verifiers will simply fail when called + // on the wrong type. + code_.SetValue("ENUM_NAME", Name(enum_def)); + + code_ += "inline " + UnionVerifySignature(enum_def) + " {"; + code_ += " switch (type) {"; + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + const auto &ev = **it; + code_.SetValue("LABEL", GetEnumValUse(enum_def, ev)); + + if (ev.IsNonZero()) { + code_.SetValue("TYPE", GetUnionElement(ev, false, opts_)); + code_ += " case {{LABEL}}: {"; + auto getptr = + " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);"; + if (ev.union_type.base_type == BASE_TYPE_STRUCT) { + if (ev.union_type.struct_def->fixed) { + code_ += + " return verifier.Verify<{{TYPE}}>(static_cast<const " + "uint8_t *>(obj), 0);"; + } else { + code_ += getptr; + code_ += " return verifier.VerifyTable(ptr);"; + } + } else if (IsString(ev.union_type)) { + code_ += getptr; + code_ += " return verifier.VerifyString(ptr);"; + } else { + FLATBUFFERS_ASSERT(false); + } + code_ += " }"; + } else { + code_ += " case {{LABEL}}: {"; + code_ += " return true;"; // "NONE" enum value. + code_ += " }"; + } + } + code_ += " default: return true;"; // unknown values are OK. + code_ += " }"; + code_ += "}"; + code_ += ""; + + code_ += "inline " + UnionVectorVerifySignature(enum_def) + " {"; + code_ += " if (!values || !types) return !values && !types;"; + code_ += " if (values->size() != types->size()) return false;"; + code_ += " for (flatbuffers::uoffset_t i = 0; i < values->size(); ++i) {"; + code_ += " if (!Verify" + Name(enum_def) + "("; + code_ += " verifier, values->Get(i), types->GetEnum<" + + Name(enum_def) + ">(i))) {"; + code_ += " return false;"; + code_ += " }"; + code_ += " }"; + code_ += " return true;"; + code_ += "}"; + code_ += ""; + + if (opts_.generate_object_based_api) { + // Generate union Unpack() and Pack() functions. + code_ += "inline " + UnionUnPackSignature(enum_def, false) + " {"; + code_ += " switch (type) {"; + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); + ++it) { + const auto &ev = **it; + if (ev.IsZero()) { continue; } + + code_.SetValue("LABEL", GetEnumValUse(enum_def, ev)); + code_.SetValue("TYPE", GetUnionElement(ev, false, opts_)); + code_ += " case {{LABEL}}: {"; + code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(obj);"; + if (ev.union_type.base_type == BASE_TYPE_STRUCT) { + if (ev.union_type.struct_def->fixed) { + code_ += " return new " + + WrapInNameSpace(*ev.union_type.struct_def) + "(*ptr);"; + } else { + code_ += " return ptr->UnPack(resolver);"; + } + } else if (IsString(ev.union_type)) { + code_ += " return new std::string(ptr->c_str(), ptr->size());"; + } else { + FLATBUFFERS_ASSERT(false); + } + code_ += " }"; + } + code_ += " default: return nullptr;"; + code_ += " }"; + code_ += "}"; + code_ += ""; + + code_ += "inline " + UnionPackSignature(enum_def, false) + " {"; + code_ += " switch (type) {"; + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); + ++it) { + auto &ev = **it; + if (ev.IsZero()) { continue; } + + code_.SetValue("LABEL", GetEnumValUse(enum_def, ev)); + code_.SetValue("TYPE", GetUnionElement(ev, true, opts_)); + code_ += " case {{LABEL}}: {"; + code_ += " auto ptr = reinterpret_cast<const {{TYPE}} *>(value);"; + if (ev.union_type.base_type == BASE_TYPE_STRUCT) { + if (ev.union_type.struct_def->fixed) { + code_ += " return _fbb.CreateStruct(*ptr).Union();"; + } else { + code_.SetValue("NAME", ev.union_type.struct_def->name); + code_ += + " return Create{{NAME}}(_fbb, ptr, _rehasher).Union();"; + } + } else if (IsString(ev.union_type)) { + code_ += " return _fbb.CreateString(*ptr).Union();"; + } else { + FLATBUFFERS_ASSERT(false); + } + code_ += " }"; + } + code_ += " default: return 0;"; + code_ += " }"; + code_ += "}"; + code_ += ""; + + // Union copy constructor + code_ += + "inline {{ENUM_NAME}}Union::{{ENUM_NAME}}Union(const " + "{{ENUM_NAME}}Union &u) : type(u.type), value(nullptr) {"; + code_ += " switch (type) {"; + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); + ++it) { + const auto &ev = **it; + if (ev.IsZero()) { continue; } + code_.SetValue("LABEL", GetEnumValUse(enum_def, ev)); + code_.SetValue("TYPE", GetUnionElement(ev, true, opts_)); + code_ += " case {{LABEL}}: {"; + bool copyable = true; + if (ev.union_type.base_type == BASE_TYPE_STRUCT && + !ev.union_type.struct_def->fixed) { + // Don't generate code to copy if table is not copyable. + // TODO(wvo): make tables copyable instead. + for (auto fit = ev.union_type.struct_def->fields.vec.begin(); + fit != ev.union_type.struct_def->fields.vec.end(); ++fit) { + const auto &field = **fit; + if (!field.deprecated && field.value.type.struct_def && + !field.native_inline) { + copyable = false; + break; + } + } + } + if (copyable) { + code_ += + " value = new {{TYPE}}(*reinterpret_cast<{{TYPE}} *>" + "(u.value));"; + } else { + code_ += + " FLATBUFFERS_ASSERT(false); // {{TYPE}} not copyable."; + } + code_ += " break;"; + code_ += " }"; + } + code_ += " default:"; + code_ += " break;"; + code_ += " }"; + code_ += "}"; + code_ += ""; + + // Union Reset() function. + FLATBUFFERS_ASSERT(enum_def.Lookup("NONE")); + code_.SetValue("NONE", GetEnumValUse(enum_def, *enum_def.Lookup("NONE"))); + + code_ += "inline void {{ENUM_NAME}}Union::Reset() {"; + code_ += " switch (type) {"; + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); + ++it) { + const auto &ev = **it; + if (ev.IsZero()) { continue; } + code_.SetValue("LABEL", GetEnumValUse(enum_def, ev)); + code_.SetValue("TYPE", GetUnionElement(ev, true, opts_)); + code_ += " case {{LABEL}}: {"; + code_ += " auto ptr = reinterpret_cast<{{TYPE}} *>(value);"; + code_ += " delete ptr;"; + code_ += " break;"; + code_ += " }"; + } + code_ += " default: break;"; + code_ += " }"; + code_ += " value = nullptr;"; + code_ += " type = {{NONE}};"; + code_ += "}"; + code_ += ""; + } + } + + // Generates a value with optionally a cast applied if the field has a + // different underlying type from its interface type (currently only the + // case for enums. "from" specify the direction, true meaning from the + // underlying type to the interface type. + std::string GenUnderlyingCast(const FieldDef &field, bool from, + const std::string &val) { + if (from && field.value.type.base_type == BASE_TYPE_BOOL) { + return val + " != 0"; + } else if ((field.value.type.enum_def && + IsScalar(field.value.type.base_type)) || + field.value.type.base_type == BASE_TYPE_BOOL) { + return "static_cast<" + GenTypeBasic(field.value.type, from) + ">(" + + val + ")"; + } else { + return val; + } + } + + std::string GenFieldOffsetName(const FieldDef &field) { + std::string uname = Name(field); + std::transform(uname.begin(), uname.end(), uname.begin(), CharToUpper); + return "VT_" + uname; + } + + void GenFullyQualifiedNameGetter(const StructDef &struct_def, + const std::string &name) { + if (!opts_.generate_name_strings) { return; } + auto fullname = struct_def.defined_namespace->GetFullyQualifiedName(name); + code_.SetValue("NAME", fullname); + code_.SetValue("CONSTEXPR", "FLATBUFFERS_CONSTEXPR"); + code_ += " static {{CONSTEXPR}} const char *GetFullyQualifiedName() {"; + code_ += " return \"{{NAME}}\";"; + code_ += " }"; + } + + std::string GenDefaultConstant(const FieldDef &field) { + if (IsFloat(field.value.type.base_type)) + return float_const_gen_.GenFloatConstant(field); + else + return NumToStringCpp(field.value.constant, field.value.type.base_type); + } + + std::string GetDefaultScalarValue(const FieldDef &field, bool is_ctor) { + const auto &type = field.value.type; + if (field.IsScalarOptional()) { + return GenOptionalNull(); + } else if (type.enum_def && IsScalar(type.base_type)) { + auto ev = type.enum_def->FindByValue(field.value.constant); + if (ev) { + return WrapInNameSpace(type.enum_def->defined_namespace, + GetEnumValUse(*type.enum_def, *ev)); + } else { + return GenUnderlyingCast( + field, true, NumToStringCpp(field.value.constant, type.base_type)); + } + } else if (type.base_type == BASE_TYPE_BOOL) { + return field.value.constant == "0" ? "false" : "true"; + } else if (field.attributes.Lookup("cpp_type")) { + if (is_ctor) { + if (PtrType(&field) == "naked") { + return "nullptr"; + } else { + return ""; + } + } else { + return "0"; + } + } else { + return GenDefaultConstant(field); + } + } + + void GenParam(const FieldDef &field, bool direct, const char *prefix) { + code_.SetValue("PRE", prefix); + code_.SetValue("PARAM_NAME", Name(field)); + if (direct && IsString(field.value.type)) { + code_.SetValue("PARAM_TYPE", "const char *"); + code_.SetValue("PARAM_VALUE", "nullptr"); + } else if (direct && IsVector(field.value.type)) { + const auto vtype = field.value.type.VectorType(); + std::string type; + if (IsStruct(vtype)) { + type = WrapInNameSpace(*vtype.struct_def); + } else { + type = GenTypeWire(vtype, "", VectorElementUserFacing(vtype)); + } + if (TypeHasKey(vtype)) { + code_.SetValue("PARAM_TYPE", "std::vector<" + type + "> *"); + } else { + code_.SetValue("PARAM_TYPE", "const std::vector<" + type + "> *"); + } + code_.SetValue("PARAM_VALUE", "nullptr"); + } else { + const auto &type = field.value.type; + code_.SetValue("PARAM_VALUE", GetDefaultScalarValue(field, false)); + if (field.IsScalarOptional()) + code_.SetValue("PARAM_TYPE", GenOptionalDecl(type) + " "); + else + code_.SetValue("PARAM_TYPE", GenTypeWire(type, " ", true)); + } + code_ += "{{PRE}}{{PARAM_TYPE}}{{PARAM_NAME}} = {{PARAM_VALUE}}\\"; + } + + // Generate a member, including a default value for scalars and raw pointers. + void GenMember(const FieldDef &field) { + if (!field.deprecated && // Deprecated fields won't be accessible. + field.value.type.base_type != BASE_TYPE_UTYPE && + (field.value.type.base_type != BASE_TYPE_VECTOR || + field.value.type.element != BASE_TYPE_UTYPE)) { + auto type = GenTypeNative(field.value.type, false, field); + auto cpp_type = field.attributes.Lookup("cpp_type"); + auto full_type = + (cpp_type + ? (IsVector(field.value.type) + ? "std::vector<" + + GenTypeNativePtr(cpp_type->constant, &field, + false) + + "> " + : GenTypeNativePtr(cpp_type->constant, &field, false)) + : type + " "); + // Generate default member initializers for >= C++11. + std::string field_di = ""; + if (opts_.g_cpp_std >= cpp::CPP_STD_11) { + field_di = "{}"; + auto native_default = field.attributes.Lookup("native_default"); + // Scalar types get parsed defaults, raw pointers get nullptrs. + if (IsScalar(field.value.type.base_type)) { + field_di = + " = " + (native_default ? std::string(native_default->constant) + : GetDefaultScalarValue(field, true)); + } else if (field.value.type.base_type == BASE_TYPE_STRUCT) { + if (IsStruct(field.value.type) && native_default) { + field_di = " = " + native_default->constant; + } + } + } + code_.SetValue("FIELD_TYPE", full_type); + code_.SetValue("FIELD_NAME", Name(field)); + code_.SetValue("FIELD_DI", field_di); + code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}{{FIELD_DI}};"; + } + } + + // Generate the default constructor for this struct. Properly initialize all + // scalar members with default values. + void GenDefaultConstructor(const StructDef &struct_def) { + code_.SetValue("NATIVE_NAME", + NativeName(Name(struct_def), &struct_def, opts_)); + // In >= C++11, default member initializers are generated. + if (opts_.g_cpp_std >= cpp::CPP_STD_11) { return; } + std::string initializer_list; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (!field.deprecated && // Deprecated fields won't be accessible. + field.value.type.base_type != BASE_TYPE_UTYPE) { + auto cpp_type = field.attributes.Lookup("cpp_type"); + auto native_default = field.attributes.Lookup("native_default"); + // Scalar types get parsed defaults, raw pointers get nullptrs. + if (IsScalar(field.value.type.base_type)) { + if (!initializer_list.empty()) { initializer_list += ",\n "; } + initializer_list += Name(field); + initializer_list += + "(" + + (native_default ? std::string(native_default->constant) + : GetDefaultScalarValue(field, true)) + + ")"; + } else if (field.value.type.base_type == BASE_TYPE_STRUCT) { + if (IsStruct(field.value.type)) { + if (native_default) { + if (!initializer_list.empty()) { + initializer_list += ",\n "; + } + initializer_list += + Name(field) + "(" + native_default->constant + ")"; + } + } + } else if (cpp_type && field.value.type.base_type != BASE_TYPE_VECTOR) { + if (!initializer_list.empty()) { initializer_list += ",\n "; } + initializer_list += Name(field) + "(0)"; + } + } + } + if (!initializer_list.empty()) { + initializer_list = "\n : " + initializer_list; + } + + code_.SetValue("INIT_LIST", initializer_list); + + code_ += " {{NATIVE_NAME}}(){{INIT_LIST}} {"; + code_ += " }"; + } + + void GenCompareOperator(const StructDef &struct_def, + std::string accessSuffix = "") { + std::string compare_op; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (!field.deprecated && // Deprecated fields won't be accessible. + field.value.type.base_type != BASE_TYPE_UTYPE && + (field.value.type.base_type != BASE_TYPE_VECTOR || + field.value.type.element != BASE_TYPE_UTYPE)) { + if (!compare_op.empty()) { compare_op += " &&\n "; } + auto accessor = Name(field) + accessSuffix; + compare_op += "(lhs." + accessor + " == rhs." + accessor + ")"; + } + } + + std::string cmp_lhs; + std::string cmp_rhs; + if (compare_op.empty()) { + cmp_lhs = ""; + cmp_rhs = ""; + compare_op = " return true;"; + } else { + cmp_lhs = "lhs"; + cmp_rhs = "rhs"; + compare_op = " return\n " + compare_op + ";"; + } + + code_.SetValue("CMP_OP", compare_op); + code_.SetValue("CMP_LHS", cmp_lhs); + code_.SetValue("CMP_RHS", cmp_rhs); + code_ += ""; + code_ += + "inline bool operator==(const {{NATIVE_NAME}} &{{CMP_LHS}}, const " + "{{NATIVE_NAME}} &{{CMP_RHS}}) {"; + code_ += "{{CMP_OP}}"; + code_ += "}"; + + code_ += ""; + code_ += + "inline bool operator!=(const {{NATIVE_NAME}} &lhs, const " + "{{NATIVE_NAME}} &rhs) {"; + code_ += " return !(lhs == rhs);"; + code_ += "}"; + code_ += ""; + } + + void GenOperatorNewDelete(const StructDef &struct_def) { + if (auto native_custom_alloc = + struct_def.attributes.Lookup("native_custom_alloc")) { + code_ += " inline void *operator new (std::size_t count) {"; + code_ += " return " + native_custom_alloc->constant + + "<{{NATIVE_NAME}}>().allocate(count / sizeof({{NATIVE_NAME}}));"; + code_ += " }"; + code_ += " inline void operator delete (void *ptr) {"; + code_ += " return " + native_custom_alloc->constant + + "<{{NATIVE_NAME}}>().deallocate(static_cast<{{NATIVE_NAME}}*>(" + "ptr),1);"; + code_ += " }"; + } + } + + void GenNativeTable(const StructDef &struct_def) { + const auto native_name = NativeName(Name(struct_def), &struct_def, opts_); + code_.SetValue("STRUCT_NAME", Name(struct_def)); + code_.SetValue("NATIVE_NAME", native_name); + + // Generate a C++ object that can hold an unpacked version of this table. + code_ += "struct {{NATIVE_NAME}} : public flatbuffers::NativeTable {"; + code_ += " typedef {{STRUCT_NAME}} TableType;"; + GenFullyQualifiedNameGetter(struct_def, native_name); + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + GenMember(**it); + } + GenOperatorNewDelete(struct_def); + GenDefaultConstructor(struct_def); + code_ += "};"; + if (opts_.gen_compare) GenCompareOperator(struct_def); + code_ += ""; + } + + // Generate the code to call the appropriate Verify function(s) for a field. + void GenVerifyCall(const FieldDef &field, const char *prefix) { + code_.SetValue("PRE", prefix); + code_.SetValue("NAME", Name(field)); + code_.SetValue("REQUIRED", field.IsRequired() ? "Required" : ""); + code_.SetValue("SIZE", GenTypeSize(field.value.type)); + code_.SetValue("OFFSET", GenFieldOffsetName(field)); + if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type)) { + code_ += + "{{PRE}}VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, {{OFFSET}})\\"; + } else { + code_ += "{{PRE}}VerifyOffset{{REQUIRED}}(verifier, {{OFFSET}})\\"; + } + + switch (field.value.type.base_type) { + case BASE_TYPE_UNION: { + code_.SetValue("ENUM_NAME", field.value.type.enum_def->name); + code_.SetValue("SUFFIX", UnionTypeFieldSuffix()); + code_ += + "{{PRE}}Verify{{ENUM_NAME}}(verifier, {{NAME}}(), " + "{{NAME}}{{SUFFIX}}())\\"; + break; + } + case BASE_TYPE_STRUCT: { + if (!field.value.type.struct_def->fixed) { + code_ += "{{PRE}}verifier.VerifyTable({{NAME}}())\\"; + } + break; + } + case BASE_TYPE_STRING: { + code_ += "{{PRE}}verifier.VerifyString({{NAME}}())\\"; + break; + } + case BASE_TYPE_VECTOR: { + code_ += "{{PRE}}verifier.VerifyVector({{NAME}}())\\"; + + switch (field.value.type.element) { + case BASE_TYPE_STRING: { + code_ += "{{PRE}}verifier.VerifyVectorOfStrings({{NAME}}())\\"; + break; + } + case BASE_TYPE_STRUCT: { + if (!field.value.type.struct_def->fixed) { + code_ += "{{PRE}}verifier.VerifyVectorOfTables({{NAME}}())\\"; + } + break; + } + case BASE_TYPE_UNION: { + code_.SetValue("ENUM_NAME", field.value.type.enum_def->name); + code_ += + "{{PRE}}Verify{{ENUM_NAME}}Vector(verifier, {{NAME}}(), " + "{{NAME}}_type())\\"; + break; + } + default: break; + } + break; + } + default: { + break; + } + } + } + + // Generate CompareWithValue method for a key field. + void GenKeyFieldMethods(const FieldDef &field) { + FLATBUFFERS_ASSERT(field.key); + const bool is_string = (IsString(field.value.type)); + + code_ += " bool KeyCompareLessThan(const {{STRUCT_NAME}} *o) const {"; + if (is_string) { + // use operator< of flatbuffers::String + code_ += " return *{{FIELD_NAME}}() < *o->{{FIELD_NAME}}();"; + } else { + code_ += " return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();"; + } + code_ += " }"; + + if (is_string) { + code_ += " int KeyCompareWithValue(const char *val) const {"; + code_ += " return strcmp({{FIELD_NAME}}()->c_str(), val);"; + code_ += " }"; + } else { + FLATBUFFERS_ASSERT(IsScalar(field.value.type.base_type)); + auto type = GenTypeBasic(field.value.type, false); + if (opts_.scoped_enums && field.value.type.enum_def && + IsScalar(field.value.type.base_type)) { + type = GenTypeGet(field.value.type, " ", "const ", " *", true); + } + // Returns {field<val: -1, field==val: 0, field>val: +1}. + code_.SetValue("KEY_TYPE", type); + code_ += " int KeyCompareWithValue({{KEY_TYPE}} val) const {"; + code_ += + " return static_cast<int>({{FIELD_NAME}}() > val) - " + "static_cast<int>({{FIELD_NAME}}() < val);"; + code_ += " }"; + } + } + + void GenTableUnionAsGetters(const FieldDef &field) { + const auto &type = field.value.type; + auto u = type.enum_def; + + if (!type.enum_def->uses_multiple_type_instances) + code_ += + " template<typename T> " + "const T *{{NULLABLE_EXT}}{{FIELD_NAME}}_as() const;"; + + for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) { + auto &ev = **u_it; + if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; } + auto full_struct_name = GetUnionElement(ev, false, opts_); + + // @TODO: Mby make this decisions more universal? How? + code_.SetValue("U_GET_TYPE", + EscapeKeyword(field.name + UnionTypeFieldSuffix())); + code_.SetValue("U_ELEMENT_TYPE", WrapInNameSpace(u->defined_namespace, + GetEnumValUse(*u, ev))); + code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *"); + code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev)); + code_.SetValue("U_NULLABLE", NullableExtension()); + + // `const Type *union_name_asType() const` accessor. + code_ += " {{U_FIELD_TYPE}}{{U_NULLABLE}}{{U_FIELD_NAME}}() const {"; + code_ += + " return {{U_GET_TYPE}}() == {{U_ELEMENT_TYPE}} ? " + "static_cast<{{U_FIELD_TYPE}}>({{FIELD_NAME}}()) " + ": nullptr;"; + code_ += " }"; + } + } + + void GenTableFieldGetter(const FieldDef &field) { + const auto &type = field.value.type; + const auto offset_str = GenFieldOffsetName(field); + + GenComment(field.doc_comment, " "); + // Call a different accessor for pointers, that indirects. + if (false == field.IsScalarOptional()) { + const bool is_scalar = IsScalar(type.base_type); + std::string accessor; + if (is_scalar) + accessor = "GetField<"; + else if (IsStruct(type)) + accessor = "GetStruct<"; + else + accessor = "GetPointer<"; + auto offset_type = GenTypeGet(type, "", "const ", " *", false); + auto call = accessor + offset_type + ">(" + offset_str; + // Default value as second arg for non-pointer types. + if (is_scalar) { call += ", " + GenDefaultConstant(field); } + call += ")"; + + std::string afterptr = " *" + NullableExtension(); + code_.SetValue("FIELD_TYPE", + GenTypeGet(type, " ", "const ", afterptr.c_str(), true)); + code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call)); + code_.SetValue("NULLABLE_EXT", NullableExtension()); + code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {"; + code_ += " return {{FIELD_VALUE}};"; + code_ += " }"; + } else { + auto wire_type = GenTypeBasic(type, false); + auto face_type = GenTypeBasic(type, true); + auto opt_value = "GetOptional<" + wire_type + ", " + face_type + ">(" + + offset_str + ")"; + code_.SetValue("FIELD_TYPE", GenOptionalDecl(type)); + code_ += " {{FIELD_TYPE}} {{FIELD_NAME}}() const {"; + code_ += " return " + opt_value + ";"; + code_ += " }"; + } + + if (type.base_type == BASE_TYPE_UNION) { GenTableUnionAsGetters(field); } + } + + void GenTableFieldType(const FieldDef &field) { + const auto &type = field.value.type; + const auto offset_str = GenFieldOffsetName(field); + if (!field.IsScalarOptional()) { + std::string afterptr = " *" + NullableExtension(); + code_.SetValue("FIELD_TYPE", + GenTypeGet(type, "", "const ", afterptr.c_str(), true)); + code_ += " {{FIELD_TYPE}}\\"; + } else { + code_.SetValue("FIELD_TYPE", GenOptionalDecl(type)); + code_ += " {{FIELD_TYPE}}\\"; + } + } + + void GenStructFieldType(const FieldDef &field) { + const auto is_array = IsArray(field.value.type); + std::string field_type = + GenTypeGet(field.value.type, "", is_array ? "" : "const ", + is_array ? "" : " &", true); + code_.SetValue("FIELD_TYPE", field_type); + code_ += " {{FIELD_TYPE}}\\"; + } + + void GenFieldTypeHelper(const StructDef &struct_def) { + if (struct_def.fields.vec.empty()) { return; } + code_ += " template<size_t Index>"; + code_ += " using FieldType = \\"; + code_ += "decltype(std::declval<type>().get_field<Index>());"; + } + + void GenIndexBasedFieldGetter(const StructDef &struct_def) { + if (struct_def.fields.vec.empty()) { return; } + code_ += " template<size_t Index>"; + code_ += " auto get_field() const {"; + + size_t index = 0; + bool need_else = false; + // Generate one index-based getter for each field. + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.deprecated) { + // Deprecated fields won't be accessible. + continue; + } + code_.SetValue("FIELD_NAME", Name(field)); + code_.SetValue("FIELD_INDEX", + std::to_string(static_cast<long long>(index++))); + if (need_else) { + code_ += " else \\"; + } else { + code_ += " \\"; + } + need_else = true; + code_ += "if constexpr (Index == {{FIELD_INDEX}}) \\"; + code_ += "return {{FIELD_NAME}}();"; + } + code_ += " else static_assert(Index != Index, \"Invalid Field Index\");"; + code_ += " }"; + } + + // Sample for Vec3: + // + // static constexpr std::array<const char *, 3> field_names = { + // "x", + // "y", + // "z" + // }; + // + void GenFieldNames(const StructDef &struct_def) { + auto non_deprecated_field_count = std::count_if( + struct_def.fields.vec.begin(), struct_def.fields.vec.end(), + [](const FieldDef *field) { return !field->deprecated; }); + code_ += " static constexpr std::array<\\"; + code_.SetValue( + "FIELD_COUNT", + std::to_string(static_cast<long long>(non_deprecated_field_count))); + code_ += "const char *, {{FIELD_COUNT}}> field_names = {\\"; + if (struct_def.fields.vec.empty()) { + code_ += "};"; + return; + } + code_ += ""; + // Generate the field_names elements. + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.deprecated) { + // Deprecated fields won't be accessible. + continue; + } + code_.SetValue("FIELD_NAME", Name(field)); + code_ += " \"{{FIELD_NAME}}\"\\"; + if (it + 1 != struct_def.fields.vec.end()) { code_ += ","; } + } + code_ += "\n };"; + } + + void GenFieldsNumber(const StructDef &struct_def) { + auto non_deprecated_field_count = std::count_if( + struct_def.fields.vec.begin(), struct_def.fields.vec.end(), + [](const FieldDef *field) { return !field->deprecated; }); + code_.SetValue( + "FIELD_COUNT", + std::to_string(static_cast<long long>(non_deprecated_field_count))); + code_ += " static constexpr size_t fields_number = {{FIELD_COUNT}};"; + } + + void GenTraitsStruct(const StructDef &struct_def) { + code_.SetValue( + "FULLY_QUALIFIED_NAME", + struct_def.defined_namespace->GetFullyQualifiedName(Name(struct_def))); + code_ += "struct {{STRUCT_NAME}}::Traits {"; + code_ += " using type = {{STRUCT_NAME}};"; + if (!struct_def.fixed) { + // We have a table and not a struct. + code_ += " static auto constexpr Create = Create{{STRUCT_NAME}};"; + } + if (opts_.cpp_static_reflection) { + code_ += " static constexpr auto name = \"{{STRUCT_NAME}}\";"; + code_ += + " static constexpr auto fully_qualified_name = " + "\"{{FULLY_QUALIFIED_NAME}}\";"; + GenFieldNames(struct_def); + GenFieldTypeHelper(struct_def); + GenFieldsNumber(struct_def); + } + code_ += "};"; + code_ += ""; + } + + void GenTableFieldSetter(const FieldDef &field) { + const auto &type = field.value.type; + const bool is_scalar = IsScalar(type.base_type); + if (is_scalar && IsUnion(type)) + return; // changing of a union's type is forbidden + + auto offset_str = GenFieldOffsetName(field); + if (is_scalar) { + const auto wire_type = GenTypeWire(type, "", false); + code_.SetValue("SET_FN", "SetField<" + wire_type + ">"); + code_.SetValue("OFFSET_NAME", offset_str); + code_.SetValue("FIELD_TYPE", GenTypeBasic(type, true)); + code_.SetValue("FIELD_VALUE", + GenUnderlyingCast(field, false, "_" + Name(field))); + + code_ += + " bool mutate_{{FIELD_NAME}}({{FIELD_TYPE}} " + "_{{FIELD_NAME}}) {"; + if (false == field.IsScalarOptional()) { + code_.SetValue("DEFAULT_VALUE", GenDefaultConstant(field)); + code_ += + " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}}, " + "{{DEFAULT_VALUE}});"; + } else { + code_ += " return {{SET_FN}}({{OFFSET_NAME}}, {{FIELD_VALUE}});"; + } + code_ += " }"; + } else { + auto postptr = " *" + NullableExtension(); + auto wire_type = GenTypeGet(type, " ", "", postptr.c_str(), true); + std::string accessor = IsStruct(type) ? "GetStruct<" : "GetPointer<"; + auto underlying = accessor + wire_type + ">(" + offset_str + ")"; + code_.SetValue("FIELD_TYPE", wire_type); + code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, underlying)); + + code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {"; + code_ += " return {{FIELD_VALUE}};"; + code_ += " }"; + } + } + + // Generate an accessor struct, builder structs & function for a table. + void GenTable(const StructDef &struct_def) { + if (opts_.generate_object_based_api) { GenNativeTable(struct_def); } + + // Generate an accessor struct, with methods of the form: + // type name() const { return GetField<type>(offset, defaultval); } + GenComment(struct_def.doc_comment); + + code_.SetValue("STRUCT_NAME", Name(struct_def)); + code_ += + "struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS" + " : private flatbuffers::Table {"; + if (opts_.generate_object_based_api) { + code_ += " typedef {{NATIVE_NAME}} NativeTableType;"; + } + code_ += " typedef {{STRUCT_NAME}}Builder Builder;"; + if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += " struct Traits;"; } + if (opts_.mini_reflect != IDLOptions::kNone) { + code_ += + " static const flatbuffers::TypeTable *MiniReflectTypeTable() {"; + code_ += " return {{STRUCT_NAME}}TypeTable();"; + code_ += " }"; + } + + GenFullyQualifiedNameGetter(struct_def, Name(struct_def)); + + // Generate field id constants. + if (struct_def.fields.vec.size() > 0) { + // We need to add a trailing comma to all elements except the last one as + // older versions of gcc complain about this. + code_.SetValue("SEP", ""); + code_ += + " enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.deprecated) { + // Deprecated fields won't be accessible. + continue; + } + + code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field)); + code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset)); + code_ += "{{SEP}} {{OFFSET_NAME}} = {{OFFSET_VALUE}}\\"; + code_.SetValue("SEP", ",\n"); + } + code_ += ""; + code_ += " };"; + } + + // Generate the accessors. + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.deprecated) { + // Deprecated fields won't be accessible. + continue; + } + + code_.SetValue("FIELD_NAME", Name(field)); + GenTableFieldGetter(field); + if (opts_.mutable_buffer) { GenTableFieldSetter(field); } + + auto nested = field.attributes.Lookup("nested_flatbuffer"); + if (nested) { + std::string qualified_name = nested->constant; + auto nested_root = parser_.LookupStruct(nested->constant); + if (nested_root == nullptr) { + qualified_name = parser_.current_namespace_->GetFullyQualifiedName( + nested->constant); + nested_root = parser_.LookupStruct(qualified_name); + } + FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser. + (void)nested_root; + code_.SetValue("CPP_NAME", TranslateNameSpace(qualified_name)); + + code_ += " const {{CPP_NAME}} *{{FIELD_NAME}}_nested_root() const {"; + code_ += + " return " + "flatbuffers::GetRoot<{{CPP_NAME}}>({{FIELD_NAME}}()->Data());"; + code_ += " }"; + } + + if (field.flexbuffer) { + code_ += + " flexbuffers::Reference {{FIELD_NAME}}_flexbuffer_root()" + " const {"; + // Both Data() and size() are const-methods, therefore call order + // doesn't matter. + code_ += + " return flexbuffers::GetRoot({{FIELD_NAME}}()->Data(), " + "{{FIELD_NAME}}()->size());"; + code_ += " }"; + } + + // Generate a comparison function for this field if it is a key. + if (field.key) { GenKeyFieldMethods(field); } + } + + if (opts_.cpp_static_reflection) { GenIndexBasedFieldGetter(struct_def); } + + // Generate a verifier function that can check a buffer from an untrusted + // source will never cause reads outside the buffer. + code_ += " bool Verify(flatbuffers::Verifier &verifier) const {"; + code_ += " return VerifyTableStart(verifier)\\"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.deprecated) { continue; } + GenVerifyCall(field, " &&\n "); + } + + code_ += " &&\n verifier.EndTable();"; + code_ += " }"; + + if (opts_.generate_object_based_api) { + // Generate the UnPack() pre declaration. + code_ += " " + TableUnPackSignature(struct_def, true, opts_) + ";"; + code_ += " " + TableUnPackToSignature(struct_def, true, opts_) + ";"; + code_ += " " + TablePackSignature(struct_def, true, opts_) + ";"; + } + + code_ += "};"; // End of table. + code_ += ""; + + // Explicit specializations for union accessors + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.deprecated || field.value.type.base_type != BASE_TYPE_UNION) { + continue; + } + + auto u = field.value.type.enum_def; + if (u->uses_multiple_type_instances) continue; + + code_.SetValue("FIELD_NAME", Name(field)); + + for (auto u_it = u->Vals().begin(); u_it != u->Vals().end(); ++u_it) { + auto &ev = **u_it; + if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; } + + auto full_struct_name = GetUnionElement(ev, false, opts_); + + code_.SetValue( + "U_ELEMENT_TYPE", + WrapInNameSpace(u->defined_namespace, GetEnumValUse(*u, ev))); + code_.SetValue("U_FIELD_TYPE", "const " + full_struct_name + " *"); + code_.SetValue("U_ELEMENT_NAME", full_struct_name); + code_.SetValue("U_FIELD_NAME", Name(field) + "_as_" + Name(ev)); + + // `template<> const T *union_name_as<T>() const` accessor. + code_ += + "template<> " + "inline {{U_FIELD_TYPE}}{{STRUCT_NAME}}::{{FIELD_NAME}}_as" + "<{{U_ELEMENT_NAME}}>() const {"; + code_ += " return {{U_FIELD_NAME}}();"; + code_ += "}"; + code_ += ""; + } + } + + GenBuilders(struct_def); + + if (opts_.generate_object_based_api) { + // Generate a pre-declaration for a CreateX method that works with an + // unpacked C++ object. + code_ += TableCreateSignature(struct_def, true, opts_) + ";"; + code_ += ""; + } + } + + // Generate code to force vector alignment. Return empty string for vector + // that doesn't need alignment code. + std::string GenVectorForceAlign(const FieldDef &field, + const std::string &field_size) { + FLATBUFFERS_ASSERT(IsVector(field.value.type)); + // Get the value of the force_align attribute. + const auto *force_align = field.attributes.Lookup("force_align"); + const int align = force_align ? atoi(force_align->constant.c_str()) : 1; + // Generate code to do force_align for the vector. + if (align > 1) { + const auto vtype = field.value.type.VectorType(); + const auto type = IsStruct(vtype) ? WrapInNameSpace(*vtype.struct_def) + : GenTypeWire(vtype, "", false); + return "_fbb.ForceVectorAlignment(" + field_size + ", sizeof(" + type + + "), " + std::to_string(static_cast<long long>(align)) + ");"; + } + return ""; + } + + void GenBuilders(const StructDef &struct_def) { + code_.SetValue("STRUCT_NAME", Name(struct_def)); + + // Generate a builder struct: + code_ += "struct {{STRUCT_NAME}}Builder {"; + code_ += " typedef {{STRUCT_NAME}} Table;"; + code_ += " flatbuffers::FlatBufferBuilder &fbb_;"; + code_ += " flatbuffers::uoffset_t start_;"; + + bool has_string_or_vector_fields = false; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.deprecated) continue; + const bool is_scalar = IsScalar(field.value.type.base_type); + const bool is_default_scalar = is_scalar && !field.IsScalarOptional(); + const bool is_string = IsString(field.value.type); + const bool is_vector = IsVector(field.value.type); + if (is_string || is_vector) { has_string_or_vector_fields = true; } + + std::string offset = GenFieldOffsetName(field); + std::string name = GenUnderlyingCast(field, false, Name(field)); + std::string value = is_default_scalar ? GenDefaultConstant(field) : ""; + + // Generate accessor functions of the form: + // void add_name(type name) { + // fbb_.AddElement<type>(offset, name, default); + // } + code_.SetValue("FIELD_NAME", Name(field)); + code_.SetValue("FIELD_TYPE", GenTypeWire(field.value.type, " ", true)); + code_.SetValue("ADD_OFFSET", Name(struct_def) + "::" + offset); + code_.SetValue("ADD_NAME", name); + code_.SetValue("ADD_VALUE", value); + if (is_scalar) { + const auto type = GenTypeWire(field.value.type, "", false); + code_.SetValue("ADD_FN", "AddElement<" + type + ">"); + } else if (IsStruct(field.value.type)) { + code_.SetValue("ADD_FN", "AddStruct"); + } else { + code_.SetValue("ADD_FN", "AddOffset"); + } + + code_ += " void add_{{FIELD_NAME}}({{FIELD_TYPE}}{{FIELD_NAME}}) {"; + code_ += " fbb_.{{ADD_FN}}(\\"; + if (is_default_scalar) { + code_ += "{{ADD_OFFSET}}, {{ADD_NAME}}, {{ADD_VALUE}});"; + } else { + code_ += "{{ADD_OFFSET}}, {{ADD_NAME}});"; + } + code_ += " }"; + } + + // Builder constructor + code_ += + " explicit {{STRUCT_NAME}}Builder(flatbuffers::FlatBufferBuilder " + "&_fbb)"; + code_ += " : fbb_(_fbb) {"; + code_ += " start_ = fbb_.StartTable();"; + code_ += " }"; + + // Finish() function. + code_ += " flatbuffers::Offset<{{STRUCT_NAME}}> Finish() {"; + code_ += " const auto end = fbb_.EndTable(start_);"; + code_ += " auto o = flatbuffers::Offset<{{STRUCT_NAME}}>(end);"; + + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (!field.deprecated && field.IsRequired()) { + code_.SetValue("FIELD_NAME", Name(field)); + code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field)); + code_ += " fbb_.Required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}});"; + } + } + code_ += " return o;"; + code_ += " }"; + code_ += "};"; + code_ += ""; + + // Generate a convenient CreateX function that uses the above builder + // to create a table in one go. + code_ += + "inline flatbuffers::Offset<{{STRUCT_NAME}}> " + "Create{{STRUCT_NAME}}("; + code_ += " flatbuffers::FlatBufferBuilder &_fbb\\"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (!field.deprecated) { GenParam(field, false, ",\n "); } + } + code_ += ") {"; + + code_ += " {{STRUCT_NAME}}Builder builder_(_fbb);"; + for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1; + size; size /= 2) { + for (auto it = struct_def.fields.vec.rbegin(); + it != struct_def.fields.vec.rend(); ++it) { + const auto &field = **it; + if (!field.deprecated && (!struct_def.sortbysize || + size == SizeOf(field.value.type.base_type))) { + code_.SetValue("FIELD_NAME", Name(field)); + if (field.IsScalarOptional()) { + code_ += + " if({{FIELD_NAME}}) { " + "builder_.add_{{FIELD_NAME}}(*{{FIELD_NAME}}); }"; + } else { + code_ += " builder_.add_{{FIELD_NAME}}({{FIELD_NAME}});"; + } + } + } + } + code_ += " return builder_.Finish();"; + code_ += "}"; + code_ += ""; + + // Definition for type traits for this table type. This allows querying var- + // ious compile-time traits of the table. + if (opts_.g_cpp_std >= cpp::CPP_STD_17) { GenTraitsStruct(struct_def); } + + // Generate a CreateXDirect function with vector types as parameters + if (opts_.cpp_direct_copy && has_string_or_vector_fields) { + code_ += + "inline flatbuffers::Offset<{{STRUCT_NAME}}> " + "Create{{STRUCT_NAME}}Direct("; + code_ += " flatbuffers::FlatBufferBuilder &_fbb\\"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (!field.deprecated) { GenParam(field, true, ",\n "); } + } + // Need to call "Create" with the struct namespace. + const auto qualified_create_name = + struct_def.defined_namespace->GetFullyQualifiedName("Create"); + code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name)); + code_ += ") {"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (!field.deprecated) { + code_.SetValue("FIELD_NAME", Name(field)); + if (IsString(field.value.type)) { + if (!field.shared) { + code_.SetValue("CREATE_STRING", "CreateString"); + } else { + code_.SetValue("CREATE_STRING", "CreateSharedString"); + } + code_ += + " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? " + "_fbb.{{CREATE_STRING}}({{FIELD_NAME}}) : 0;"; + } else if (IsVector(field.value.type)) { + const std::string force_align_code = + GenVectorForceAlign(field, Name(field) + "->size()"); + if (!force_align_code.empty()) { + code_ += " if ({{FIELD_NAME}}) { " + force_align_code + " }"; + } + code_ += " auto {{FIELD_NAME}}__ = {{FIELD_NAME}} ? \\"; + const auto vtype = field.value.type.VectorType(); + const auto has_key = TypeHasKey(vtype); + if (IsStruct(vtype)) { + const auto type = WrapInNameSpace(*vtype.struct_def); + code_ += (has_key ? "_fbb.CreateVectorOfSortedStructs<" + : "_fbb.CreateVectorOfStructs<") + + type + ">\\"; + } else if (has_key) { + const auto type = WrapInNameSpace(*vtype.struct_def); + code_ += "_fbb.CreateVectorOfSortedTables<" + type + ">\\"; + } else { + const auto type = + GenTypeWire(vtype, "", VectorElementUserFacing(vtype)); + code_ += "_fbb.CreateVector<" + type + ">\\"; + } + code_ += + has_key ? "({{FIELD_NAME}}) : 0;" : "(*{{FIELD_NAME}}) : 0;"; + } + } + } + code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}("; + code_ += " _fbb\\"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (!field.deprecated) { + code_.SetValue("FIELD_NAME", Name(field)); + code_ += ",\n {{FIELD_NAME}}\\"; + if (IsString(field.value.type) || IsVector(field.value.type)) { + code_ += "__\\"; + } + } + } + code_ += ");"; + code_ += "}"; + code_ += ""; + } + } + + std::string GenUnionUnpackVal(const FieldDef &afield, + const char *vec_elem_access, + const char *vec_type_access) { + auto type_name = WrapInNameSpace(*afield.value.type.enum_def); + return type_name + "Union::UnPack(" + "_e" + vec_elem_access + ", " + + EscapeKeyword(afield.name + UnionTypeFieldSuffix()) + "()" + + vec_type_access + ", _resolver)"; + } + + std::string GenUnpackVal(const Type &type, const std::string &val, + bool invector, const FieldDef &afield) { + switch (type.base_type) { + case BASE_TYPE_STRING: { + if (FlexibleStringConstructor(&afield)) { + return NativeString(&afield) + "(" + val + "->c_str(), " + val + + "->size())"; + } else { + return val + "->str()"; + } + } + case BASE_TYPE_STRUCT: { + if (IsStruct(type)) { + const auto &struct_attrs = type.struct_def->attributes; + const auto native_type = struct_attrs.Lookup("native_type"); + if (native_type) { + std::string unpack_call = "flatbuffers::UnPack"; + const auto pack_name = struct_attrs.Lookup("native_type_pack_name"); + if (pack_name) { unpack_call += pack_name->constant; } + unpack_call += "(*" + val + ")"; + return unpack_call; + } else if (invector || afield.native_inline) { + return "*" + val; + } else { + const auto name = WrapInNameSpace(*type.struct_def); + const auto ptype = GenTypeNativePtr(name, &afield, true); + return ptype + "(new " + name + "(*" + val + "))"; + } + } else { + const auto ptype = GenTypeNativePtr( + WrapNativeNameInNameSpace(*type.struct_def, opts_), &afield, + true); + return ptype + "(" + val + "->UnPack(_resolver))"; + } + } + case BASE_TYPE_UNION: { + return GenUnionUnpackVal( + afield, invector ? "->Get(_i)" : "", + invector ? ("->GetEnum<" + type.enum_def->name + ">(_i)").c_str() + : ""); + } + default: { + return val; + break; + } + } + } + + std::string GenUnpackFieldStatement(const FieldDef &field, + const FieldDef *union_field) { + std::string code; + switch (field.value.type.base_type) { + case BASE_TYPE_VECTOR: { + auto name = Name(field); + if (field.value.type.element == BASE_TYPE_UTYPE) { + name = StripUnionType(Name(field)); + } + code += "{ _o->" + name + ".resize(_e->size()); "; + if (!field.value.type.enum_def && !IsBool(field.value.type.element) && + IsOneByte(field.value.type.element)) { + // For vectors of bytes, std::copy is used to improve performance. + // This doesn't work for: + // - enum types because they have to be explicitly static_cast. + // - vectors of bool, since they are a template specialization. + // - multiple-byte types due to endianness. + code += + "std::copy(_e->begin(), _e->end(), _o->" + name + ".begin()); }"; + } else { + std::string indexing; + if (field.value.type.enum_def) { + indexing += "static_cast<" + + WrapInNameSpace(*field.value.type.enum_def) + ">("; + } + indexing += "_e->Get(_i)"; + if (field.value.type.enum_def) { indexing += ")"; } + if (field.value.type.element == BASE_TYPE_BOOL) { + indexing += " != 0"; + } + // Generate code that pushes data from _e to _o in the form: + // for (uoffset_t i = 0; i < _e->size(); ++i) { + // _o->field.push_back(_e->Get(_i)); + // } + auto access = + field.value.type.element == BASE_TYPE_UTYPE + ? ".type" + : (field.value.type.element == BASE_TYPE_UNION ? ".value" + : ""); + + code += "for (flatbuffers::uoffset_t _i = 0;"; + code += " _i < _e->size(); _i++) { "; + auto cpp_type = field.attributes.Lookup("cpp_type"); + if (cpp_type) { + // Generate code that resolves the cpp pointer type, of the form: + // if (resolver) + // (*resolver)(&_o->field, (hash_value_t)(_e)); + // else + // _o->field = nullptr; + code += "//vector resolver, " + PtrType(&field) + "\n"; + code += "if (_resolver) "; + code += "(*_resolver)"; + code += "(reinterpret_cast<void **>(&_o->" + name + "[_i]" + + access + "), "; + code += + "static_cast<flatbuffers::hash_value_t>(" + indexing + "));"; + if (PtrType(&field) == "naked") { + code += " else "; + code += "_o->" + name + "[_i]" + access + " = nullptr"; + } else { + // code += " else "; + // code += "_o->" + name + "[_i]" + access + " = " + + // GenTypeNativePtr(cpp_type->constant, &field, true) + "();"; + code += "/* else do nothing */"; + } + } else { + code += "_o->" + name + "[_i]" + access + " = "; + code += GenUnpackVal(field.value.type.VectorType(), indexing, true, + field); + } + code += "; } }"; + } + break; + } + case BASE_TYPE_UTYPE: { + FLATBUFFERS_ASSERT(union_field->value.type.base_type == + BASE_TYPE_UNION); + // Generate code that sets the union type, of the form: + // _o->field.type = _e; + code += "_o->" + union_field->name + ".type = _e;"; + break; + } + case BASE_TYPE_UNION: { + // Generate code that sets the union value, of the form: + // _o->field.value = Union::Unpack(_e, field_type(), resolver); + code += "_o->" + Name(field) + ".value = "; + code += GenUnionUnpackVal(field, "", ""); + code += ";"; + break; + } + default: { + auto cpp_type = field.attributes.Lookup("cpp_type"); + if (cpp_type) { + // Generate code that resolves the cpp pointer type, of the form: + // if (resolver) + // (*resolver)(&_o->field, (hash_value_t)(_e)); + // else + // _o->field = nullptr; + code += "//scalar resolver, " + PtrType(&field) + " \n"; + code += "if (_resolver) "; + code += "(*_resolver)"; + code += "(reinterpret_cast<void **>(&_o->" + Name(field) + "), "; + code += "static_cast<flatbuffers::hash_value_t>(_e));"; + if (PtrType(&field) == "naked") { + code += " else "; + code += "_o->" + Name(field) + " = nullptr;"; + } else { + // code += " else "; + // code += "_o->" + Name(field) + " = " + + // GenTypeNativePtr(cpp_type->constant, &field, true) + "();"; + code += "/* else do nothing */;"; + } + } else { + // Generate code for assigning the value, of the form: + // _o->field = value; + code += "_o->" + Name(field) + " = "; + code += GenUnpackVal(field.value.type, "_e", false, field) + ";"; + } + break; + } + } + return code; + } + + std::string GenCreateParam(const FieldDef &field) { + std::string value = "_o->"; + if (field.value.type.base_type == BASE_TYPE_UTYPE) { + value += StripUnionType(Name(field)); + value += ".type"; + } else { + value += Name(field); + } + if (field.value.type.base_type != BASE_TYPE_VECTOR && + field.attributes.Lookup("cpp_type")) { + auto type = GenTypeBasic(field.value.type, false); + value = + "_rehasher ? " + "static_cast<" + + type + ">((*_rehasher)(" + value + GenPtrGet(field) + ")) : 0"; + } + + std::string code; + switch (field.value.type.base_type) { + // String fields are of the form: + // _fbb.CreateString(_o->field) + // or + // _fbb.CreateSharedString(_o->field) + case BASE_TYPE_STRING: { + if (!field.shared) { + code += "_fbb.CreateString("; + } else { + code += "_fbb.CreateSharedString("; + } + code += value; + code.push_back(')'); + + // For optional fields, check to see if there actually is any data + // in _o->field before attempting to access it. If there isn't, + // depending on set_empty_strings_to_null either set it to 0 or an empty + // string. + if (!field.IsRequired()) { + auto empty_value = opts_.set_empty_strings_to_null + ? "0" + : "_fbb.CreateSharedString(\"\")"; + code = value + ".empty() ? " + empty_value + " : " + code; + } + break; + } + // Vector fields come in several flavours, of the forms: + // _fbb.CreateVector(_o->field); + // _fbb.CreateVector((const utype*)_o->field.data(), + // _o->field.size()); _fbb.CreateVectorOfStrings(_o->field) + // _fbb.CreateVectorOfStructs(_o->field) + // _fbb.CreateVector<Offset<T>>(_o->field.size() [&](size_t i) { + // return CreateT(_fbb, _o->Get(i), rehasher); + // }); + case BASE_TYPE_VECTOR: { + auto vector_type = field.value.type.VectorType(); + switch (vector_type.base_type) { + case BASE_TYPE_STRING: { + if (NativeString(&field) == "std::string") { + code += "_fbb.CreateVectorOfStrings(" + value + ")"; + } else { + // Use by-function serialization to emulate + // CreateVectorOfStrings(); this works also with non-std strings. + code += + "_fbb.CreateVector<flatbuffers::Offset<flatbuffers::String>>" + " "; + code += "(" + value + ".size(), "; + code += "[](size_t i, _VectorArgs *__va) { "; + code += + "return __va->__fbb->CreateString(__va->_" + value + "[i]);"; + code += " }, &_va )"; + } + break; + } + case BASE_TYPE_STRUCT: { + if (IsStruct(vector_type)) { + const auto &struct_attrs = + field.value.type.struct_def->attributes; + const auto native_type = struct_attrs.Lookup("native_type"); + if (native_type) { + code += "_fbb.CreateVectorOfNativeStructs<"; + code += WrapInNameSpace(*vector_type.struct_def) + ", " + + native_type->constant + ">"; + code += "(" + value; + const auto pack_name = + struct_attrs.Lookup("native_type_pack_name"); + if (pack_name) { + code += ", flatbuffers::Pack" + pack_name->constant; + } + code += ")"; + } else { + code += "_fbb.CreateVectorOfStructs"; + code += "(" + value + ")"; + } + } else { + code += "_fbb.CreateVector<flatbuffers::Offset<"; + code += WrapInNameSpace(*vector_type.struct_def) + ">> "; + code += "(" + value + ".size(), "; + code += "[](size_t i, _VectorArgs *__va) { "; + code += "return Create" + vector_type.struct_def->name; + code += "(*__va->__fbb, __va->_" + value + "[i]" + + GenPtrGet(field) + ", "; + code += "__va->__rehasher); }, &_va )"; + } + break; + } + case BASE_TYPE_BOOL: { + code += "_fbb.CreateVector(" + value + ")"; + break; + } + case BASE_TYPE_UNION: { + code += + "_fbb.CreateVector<flatbuffers::" + "Offset<void>>(" + + value + + ".size(), [](size_t i, _VectorArgs *__va) { " + "return __va->_" + + value + "[i].Pack(*__va->__fbb, __va->__rehasher); }, &_va)"; + break; + } + case BASE_TYPE_UTYPE: { + value = StripUnionType(value); + code += "_fbb.CreateVector<uint8_t>(" + value + + ".size(), [](size_t i, _VectorArgs *__va) { " + "return static_cast<uint8_t>(__va->_" + + value + "[i].type); }, &_va)"; + break; + } + default: { + if (field.value.type.enum_def && + !VectorElementUserFacing(vector_type)) { + // For enumerations, we need to get access to the array data for + // the underlying storage type (eg. uint8_t). + const auto basetype = GenTypeBasic( + field.value.type.enum_def->underlying_type, false); + code += "_fbb.CreateVectorScalarCast<" + basetype + + ">(flatbuffers::data(" + value + "), " + value + + ".size())"; + } else if (field.attributes.Lookup("cpp_type")) { + auto type = GenTypeBasic(vector_type, false); + code += "_fbb.CreateVector<" + type + ">(" + value + ".size(), "; + code += "[](size_t i, _VectorArgs *__va) { "; + code += "return __va->__rehasher ? "; + code += "static_cast<" + type + ">((*__va->__rehasher)"; + code += "(__va->_" + value + "[i]" + GenPtrGet(field) + ")) : 0"; + code += "; }, &_va )"; + } else { + code += "_fbb.CreateVector(" + value + ")"; + } + break; + } + } + + // If set_empty_vectors_to_null option is enabled, for optional fields, + // check to see if there actually is any data in _o->field before + // attempting to access it. + if (opts_.set_empty_vectors_to_null && !field.IsRequired()) { + code = value + ".size() ? " + code + " : 0"; + } + break; + } + case BASE_TYPE_UNION: { + // _o->field.Pack(_fbb); + code += value + ".Pack(_fbb)"; + break; + } + case BASE_TYPE_STRUCT: { + if (IsStruct(field.value.type)) { + const auto &struct_attribs = field.value.type.struct_def->attributes; + const auto native_type = struct_attribs.Lookup("native_type"); + if (native_type) { + code += "flatbuffers::Pack"; + const auto pack_name = + struct_attribs.Lookup("native_type_pack_name"); + if (pack_name) { code += pack_name->constant; } + code += "(" + value + ")"; + } else if (field.native_inline) { + code += "&" + value; + } else { + code += value + " ? " + value + GenPtrGet(field) + " : 0"; + } + } else { + // _o->field ? CreateT(_fbb, _o->field.get(), _rehasher); + const auto type = field.value.type.struct_def->name; + code += value + " ? Create" + type; + code += "(_fbb, " + value + GenPtrGet(field) + ", _rehasher)"; + code += " : 0"; + } + break; + } + default: { + code += value; + break; + } + } + return code; + } + + // Generate code for tables that needs to come after the regular definition. + void GenTablePost(const StructDef &struct_def) { + code_.SetValue("STRUCT_NAME", Name(struct_def)); + code_.SetValue("NATIVE_NAME", + NativeName(Name(struct_def), &struct_def, opts_)); + + if (opts_.generate_object_based_api) { + // Generate the X::UnPack() method. + code_ += + "inline " + TableUnPackSignature(struct_def, false, opts_) + " {"; + + if (opts_.g_cpp_std == cpp::CPP_STD_X0) { + auto native_name = WrapNativeNameInNameSpace(struct_def, parser_.opts); + code_.SetValue("POINTER_TYPE", + GenTypeNativePtr(native_name, nullptr, false)); + code_ += + " {{POINTER_TYPE}} _o = {{POINTER_TYPE}}(new {{NATIVE_NAME}}());"; + } else if (opts_.g_cpp_std == cpp::CPP_STD_11) { + code_ += + " auto _o = std::unique_ptr<{{NATIVE_NAME}}>(new " + "{{NATIVE_NAME}}());"; + } else { + code_ += " auto _o = std::make_unique<{{NATIVE_NAME}}>();"; + } + code_ += " UnPackTo(_o.get(), _resolver);"; + code_ += " return _o.release();"; + code_ += "}"; + code_ += ""; + code_ += + "inline " + TableUnPackToSignature(struct_def, false, opts_) + " {"; + code_ += " (void)_o;"; + code_ += " (void)_resolver;"; + + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.deprecated) { continue; } + + // Assign a value from |this| to |_o|. Values from |this| are stored + // in a variable |_e| by calling this->field_type(). The value is then + // assigned to |_o| using the GenUnpackFieldStatement. + const bool is_union = field.value.type.base_type == BASE_TYPE_UTYPE; + const auto statement = + GenUnpackFieldStatement(field, is_union ? *(it + 1) : nullptr); + + code_.SetValue("FIELD_NAME", Name(field)); + auto prefix = " { auto _e = {{FIELD_NAME}}(); "; + auto check = IsScalar(field.value.type.base_type) ? "" : "if (_e) "; + auto postfix = " }"; + code_ += std::string(prefix) + check + statement + postfix; + } + code_ += "}"; + code_ += ""; + + // Generate the X::Pack member function that simply calls the global + // CreateX function. + code_ += "inline " + TablePackSignature(struct_def, false, opts_) + " {"; + code_ += " return Create{{STRUCT_NAME}}(_fbb, _o, _rehasher);"; + code_ += "}"; + code_ += ""; + + // Generate a CreateX method that works with an unpacked C++ object. + code_ += + "inline " + TableCreateSignature(struct_def, false, opts_) + " {"; + code_ += " (void)_rehasher;"; + code_ += " (void)_o;"; + + code_ += + " struct _VectorArgs " + "{ flatbuffers::FlatBufferBuilder *__fbb; " + "const " + + NativeName(Name(struct_def), &struct_def, opts_) + + "* __o; " + "const flatbuffers::rehasher_function_t *__rehasher; } _va = { " + "&_fbb, _o, _rehasher}; (void)_va;"; + + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) { continue; } + if (IsVector(field.value.type)) { + const std::string force_align_code = + GenVectorForceAlign(field, "_o->" + Name(field) + ".size()"); + if (!force_align_code.empty()) { code_ += " " + force_align_code; } + } + code_ += " auto _" + Name(field) + " = " + GenCreateParam(field) + ";"; + } + // Need to call "Create" with the struct namespace. + const auto qualified_create_name = + struct_def.defined_namespace->GetFullyQualifiedName("Create"); + code_.SetValue("CREATE_NAME", TranslateNameSpace(qualified_create_name)); + + code_ += " return {{CREATE_NAME}}{{STRUCT_NAME}}("; + code_ += " _fbb\\"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) { continue; } + + bool pass_by_address = false; + if (field.value.type.base_type == BASE_TYPE_STRUCT) { + if (IsStruct(field.value.type)) { + auto native_type = + field.value.type.struct_def->attributes.Lookup("native_type"); + if (native_type) { pass_by_address = true; } + } + } + + // Call the CreateX function using values from |_o|. + if (pass_by_address) { + code_ += ",\n &_" + Name(field) + "\\"; + } else { + code_ += ",\n _" + Name(field) + "\\"; + } + } + code_ += ");"; + code_ += "}"; + code_ += ""; + } + } + + static void GenPadding( + const FieldDef &field, std::string *code_ptr, int *id, + const std::function<void(int bits, std::string *code_ptr, int *id)> &f) { + if (field.padding) { + for (int i = 0; i < 4; i++) { + if (static_cast<int>(field.padding) & (1 << i)) { + f((1 << i) * 8, code_ptr, id); + } + } + FLATBUFFERS_ASSERT(!(field.padding & ~0xF)); + } + } + + static void PaddingDefinition(int bits, std::string *code_ptr, int *id) { + *code_ptr += " int" + NumToString(bits) + "_t padding" + + NumToString((*id)++) + "__;"; + } + + static void PaddingInitializer(int bits, std::string *code_ptr, int *id) { + (void)bits; + if (!code_ptr->empty()) *code_ptr += ",\n "; + *code_ptr += "padding" + NumToString((*id)++) + "__(0)"; + } + + static void PaddingNoop(int bits, std::string *code_ptr, int *id) { + (void)bits; + if (!code_ptr->empty()) *code_ptr += '\n'; + *code_ptr += " (void)padding" + NumToString((*id)++) + "__;"; + } + + void GenStructDefaultConstructor(const StructDef &struct_def) { + std::string init_list; + std::string body; + bool first_in_init_list = true; + int padding_initializer_id = 0; + int padding_body_id = 0; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto field = *it; + const auto field_name = field->name + "_"; + + if (first_in_init_list) { + first_in_init_list = false; + } else { + init_list += ","; + init_list += "\n "; + } + + init_list += field_name; + if (IsStruct(field->value.type) || IsArray(field->value.type)) { + // this is either default initialization of struct + // or + // implicit initialization of array + // for each object in array it: + // * sets it as zeros for POD types (integral, floating point, etc) + // * calls default constructor for classes/structs + init_list += "()"; + } else { + init_list += "(0)"; + } + if (field->padding) { + GenPadding(*field, &init_list, &padding_initializer_id, + PaddingInitializer); + GenPadding(*field, &body, &padding_body_id, PaddingNoop); + } + } + + if (init_list.empty()) { + code_ += " {{STRUCT_NAME}}()"; + code_ += " {}"; + } else { + code_.SetValue("INIT_LIST", init_list); + code_ += " {{STRUCT_NAME}}()"; + code_ += " : {{INIT_LIST}} {"; + if (!body.empty()) { code_ += body; } + code_ += " }"; + } + } + + void GenStructConstructor(const StructDef &struct_def, + GenArrayArgMode array_mode) { + std::string arg_list; + std::string init_list; + int padding_id = 0; + auto first = struct_def.fields.vec.begin(); + // skip arrays if generate ctor without array assignment + const auto init_arrays = (array_mode != kArrayArgModeNone); + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + const auto &type = field.value.type; + const auto is_array = IsArray(type); + const auto arg_name = "_" + Name(field); + if (!is_array || init_arrays) { + if (it != first && !arg_list.empty()) { arg_list += ", "; } + arg_list += !is_array ? GenTypeGet(type, " ", "const ", " &", true) + : GenTypeSpan(type, true, type.fixed_length); + arg_list += arg_name; + } + // skip an array with initialization from span + if (false == (is_array && init_arrays)) { + if (it != first && !init_list.empty()) { init_list += ",\n "; } + init_list += Name(field) + "_"; + if (IsScalar(type.base_type)) { + auto scalar_type = GenUnderlyingCast(field, false, arg_name); + init_list += "(flatbuffers::EndianScalar(" + scalar_type + "))"; + } else { + FLATBUFFERS_ASSERT((is_array && !init_arrays) || IsStruct(type)); + if (!is_array) + init_list += "(" + arg_name + ")"; + else + init_list += "()"; + } + } + if (field.padding) + GenPadding(field, &init_list, &padding_id, PaddingInitializer); + } + + if (!arg_list.empty()) { + code_.SetValue("ARG_LIST", arg_list); + code_.SetValue("INIT_LIST", init_list); + if (!init_list.empty()) { + code_ += " {{STRUCT_NAME}}({{ARG_LIST}})"; + code_ += " : {{INIT_LIST}} {"; + } else { + code_ += " {{STRUCT_NAME}}({{ARG_LIST}}) {"; + } + padding_id = 0; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + const auto &type = field.value.type; + if (IsArray(type) && init_arrays) { + const auto &element_type = type.VectorType(); + const auto is_enum = IsEnum(element_type); + FLATBUFFERS_ASSERT( + (IsScalar(element_type.base_type) || IsStruct(element_type)) && + "invalid declaration"); + const auto face_type = GenTypeGet(type, " ", "", "", is_enum); + std::string get_array = + is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray"; + const auto field_name = Name(field) + "_"; + const auto arg_name = "_" + Name(field); + code_ += " flatbuffers::" + get_array + "(" + field_name + + ").CopyFromSpan(" + arg_name + ");"; + } + if (field.padding) { + std::string padding; + GenPadding(field, &padding, &padding_id, PaddingNoop); + code_ += padding; + } + } + code_ += " }"; + } + } + + void GenArrayAccessor(const Type &type, bool mutable_accessor) { + FLATBUFFERS_ASSERT(IsArray(type)); + const auto is_enum = IsEnum(type.VectorType()); + // The Array<bool,N> is a tricky case, like std::vector<bool>. + // It requires a specialization of Array class. + // Generate Array<uint8_t> for Array<bool>. + const auto face_type = GenTypeGet(type, " ", "", "", is_enum); + std::string ret_type = "flatbuffers::Array<" + face_type + ", " + + NumToString(type.fixed_length) + ">"; + if (mutable_accessor) + code_ += " " + ret_type + " *mutable_{{FIELD_NAME}}() {"; + else + code_ += " const " + ret_type + " *{{FIELD_NAME}}() const {"; + + std::string get_array = + is_enum ? "CastToArrayOfEnum<" + face_type + ">" : "CastToArray"; + code_ += " return &flatbuffers::" + get_array + "({{FIELD_VALUE}});"; + code_ += " }"; + } + + // Generate an accessor struct with constructor for a flatbuffers struct. + void GenStruct(const StructDef &struct_def) { + // Generate an accessor struct, with private variables of the form: + // type name_; + // Generates manual padding and alignment. + // Variables are private because they contain little endian data on all + // platforms. + GenComment(struct_def.doc_comment); + code_.SetValue("ALIGN", NumToString(struct_def.minalign)); + code_.SetValue("STRUCT_NAME", Name(struct_def)); + + code_ += + "FLATBUFFERS_MANUALLY_ALIGNED_STRUCT({{ALIGN}}) " + "{{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS {"; + code_ += " private:"; + + int padding_id = 0; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + const auto &field_type = field.value.type; + code_.SetValue("FIELD_TYPE", GenTypeGet(field_type, " ", "", " ", false)); + code_.SetValue("FIELD_NAME", Name(field)); + code_.SetValue("ARRAY", + IsArray(field_type) + ? "[" + NumToString(field_type.fixed_length) + "]" + : ""); + code_ += (" {{FIELD_TYPE}}{{FIELD_NAME}}_{{ARRAY}};"); + + if (field.padding) { + std::string padding; + GenPadding(field, &padding, &padding_id, PaddingDefinition); + code_ += padding; + } + } + + // Generate GetFullyQualifiedName + code_ += ""; + code_ += " public:"; + + if (opts_.g_cpp_std >= cpp::CPP_STD_17) { code_ += " struct Traits;"; } + + // Make TypeTable accessible via the generated struct. + if (opts_.mini_reflect != IDLOptions::kNone) { + code_ += + " static const flatbuffers::TypeTable *MiniReflectTypeTable() {"; + code_ += " return {{STRUCT_NAME}}TypeTable();"; + code_ += " }"; + } + + GenFullyQualifiedNameGetter(struct_def, Name(struct_def)); + + // Generate a default constructor. + GenStructDefaultConstructor(struct_def); + + // Generate a constructor that takes all fields as arguments, + // excluding arrays. + GenStructConstructor(struct_def, kArrayArgModeNone); + + auto arrays_num = std::count_if(struct_def.fields.vec.begin(), + struct_def.fields.vec.end(), + [](const flatbuffers::FieldDef *fd) { + return IsArray(fd->value.type); + }); + if (arrays_num > 0) { + GenStructConstructor(struct_def, kArrayArgModeSpanStatic); + } + + // Generate accessor methods of the form: + // type name() const { return flatbuffers::EndianScalar(name_); } + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + const auto &type = field.value.type; + const auto is_scalar = IsScalar(type.base_type); + const auto is_array = IsArray(type); + + const auto field_type = GenTypeGet(type, " ", is_array ? "" : "const ", + is_array ? "" : " &", true); + auto member = Name(field) + "_"; + auto value = + is_scalar ? "flatbuffers::EndianScalar(" + member + ")" : member; + + code_.SetValue("FIELD_NAME", Name(field)); + code_.SetValue("FIELD_TYPE", field_type); + code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, value)); + + GenComment(field.doc_comment, " "); + + // Generate a const accessor function. + if (is_array) { + GenArrayAccessor(type, false); + } else { + code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {"; + code_ += " return {{FIELD_VALUE}};"; + code_ += " }"; + } + + // Generate a mutable accessor function. + if (opts_.mutable_buffer) { + auto mut_field_type = + GenTypeGet(type, " ", "", is_array ? "" : " &", true); + code_.SetValue("FIELD_TYPE", mut_field_type); + if (is_scalar) { + code_.SetValue("ARG", GenTypeBasic(type, true)); + code_.SetValue("FIELD_VALUE", + GenUnderlyingCast(field, false, "_" + Name(field))); + + code_ += " void mutate_{{FIELD_NAME}}({{ARG}} _{{FIELD_NAME}}) {"; + code_ += + " flatbuffers::WriteScalar(&{{FIELD_NAME}}_, " + "{{FIELD_VALUE}});"; + code_ += " }"; + } else if (is_array) { + GenArrayAccessor(type, true); + } else { + code_ += " {{FIELD_TYPE}}mutable_{{FIELD_NAME}}() {"; + code_ += " return {{FIELD_VALUE}};"; + code_ += " }"; + } + } + + // Generate a comparison function for this field if it is a key. + if (field.key) { GenKeyFieldMethods(field); } + } + code_.SetValue("NATIVE_NAME", Name(struct_def)); + GenOperatorNewDelete(struct_def); + + if (opts_.cpp_static_reflection) { GenIndexBasedFieldGetter(struct_def); } + + code_ += "};"; + + code_.SetValue("STRUCT_BYTE_SIZE", NumToString(struct_def.bytesize)); + code_ += "FLATBUFFERS_STRUCT_END({{STRUCT_NAME}}, {{STRUCT_BYTE_SIZE}});"; + if (opts_.gen_compare) GenCompareOperator(struct_def, "()"); + code_ += ""; + + // Definition for type traits for this table type. This allows querying var- + // ious compile-time traits of the table. + if (opts_.g_cpp_std >= cpp::CPP_STD_17) { GenTraitsStruct(struct_def); } + } + + // Set up the correct namespace. Only open a namespace if the existing one is + // different (closing/opening only what is necessary). + // + // The file must start and end with an empty (or null) namespace so that + // namespaces are properly opened and closed. + void SetNameSpace(const Namespace *ns) { + if (cur_name_space_ == ns) { return; } + + // Compute the size of the longest common namespace prefix. + // If cur_name_space is A::B::C::D and ns is A::B::E::F::G, + // the common prefix is A::B:: and we have old_size = 4, new_size = 5 + // and common_prefix_size = 2 + size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0; + size_t new_size = ns ? ns->components.size() : 0; + + size_t common_prefix_size = 0; + while (common_prefix_size < old_size && common_prefix_size < new_size && + ns->components[common_prefix_size] == + cur_name_space_->components[common_prefix_size]) { + common_prefix_size++; + } + + // Close cur_name_space in reverse order to reach the common prefix. + // In the previous example, D then C are closed. + for (size_t j = old_size; j > common_prefix_size; --j) { + code_ += "} // namespace " + cur_name_space_->components[j - 1]; + } + if (old_size != common_prefix_size) { code_ += ""; } + + // open namespace parts to reach the ns namespace + // in the previous example, E, then F, then G are opened + for (auto j = common_prefix_size; j != new_size; ++j) { + code_ += "namespace " + ns->components[j] + " {"; + } + if (new_size != common_prefix_size) { code_ += ""; } + + cur_name_space_ = ns; + } +}; + +} // namespace cpp + +bool GenerateCPP(const Parser &parser, const std::string &path, + const std::string &file_name) { + cpp::IDLOptionsCpp opts(parser.opts); + // The '--cpp_std' argument could be extended (like ASAN): + // Example: "flatc --cpp_std c++17:option1:option2". + auto cpp_std = !opts.cpp_std.empty() ? opts.cpp_std : "C++11"; + std::transform(cpp_std.begin(), cpp_std.end(), cpp_std.begin(), CharToUpper); + if (cpp_std == "C++0X") { + opts.g_cpp_std = cpp::CPP_STD_X0; + opts.g_only_fixed_enums = false; + } else if (cpp_std == "C++11") { + // Use the standard C++11 code generator. + opts.g_cpp_std = cpp::CPP_STD_11; + opts.g_only_fixed_enums = true; + } else if (cpp_std == "C++17") { + opts.g_cpp_std = cpp::CPP_STD_17; + // With c++17 generate strong enums only. + opts.scoped_enums = true; + // By default, prefixed_enums==true, reset it. + opts.prefixed_enums = false; + } else { + LogCompilerError("Unknown value of the '--cpp-std' switch: " + + opts.cpp_std); + return false; + } + // The opts.scoped_enums has priority. + opts.g_only_fixed_enums |= opts.scoped_enums; + + if (opts.cpp_static_reflection && opts.g_cpp_std < cpp::CPP_STD_17) { + LogCompilerError( + "--cpp-static-reflection requires using --cpp-std at \"C++17\" or " + "higher."); + return false; + } + + cpp::CppGenerator generator(parser, path, file_name, opts); + return generator.generate(); +} + +std::string CPPMakeRule(const Parser &parser, const std::string &path, + const std::string &file_name) { + const auto filebase = + flatbuffers::StripPath(flatbuffers::StripExtension(file_name)); + cpp::CppGenerator geneartor(parser, path, file_name, parser.opts); + const auto included_files = parser.GetIncludedFilesRecursive(file_name); + std::string make_rule = + geneartor.GeneratedFileName(path, filebase, parser.opts) + ": "; + for (auto it = included_files.begin(); it != included_files.end(); ++it) { + make_rule += " " + *it; + } + return make_rule; +} + +} // namespace flatbuffers diff --git a/contrib/libs/flatbuffers/src/idl_gen_cpp_yandex_maps_iter.cpp b/contrib/libs/flatbuffers/src/idl_gen_cpp_yandex_maps_iter.cpp new file mode 100644 index 0000000000..1ba2ef3e4a --- /dev/null +++ b/contrib/libs/flatbuffers/src/idl_gen_cpp_yandex_maps_iter.cpp @@ -0,0 +1,731 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// independent from idl_parser, since this code is not needed for most clients + +#include <unordered_set> + +#include "flatbuffers/code_generators.h" +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/flatc.h" +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +namespace flatbuffers { + +// Pedantic warning free version of toupper(). +inline char ToUpper(char c) { + return static_cast<char>(::toupper(static_cast<unsigned char>(c))); +} + +static std::string GeneratedIterFileName(const std::string &path, + const std::string &file_name) { + return path + file_name + ".iter.fbs.h"; +} + +namespace cpp_yandex_maps_iter { +class CppIterGenerator : public BaseGenerator { + public: + CppIterGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name, "", "::", "h"), + cur_name_space_(nullptr) { + static const char *const keywords[] = { + "alignas", + "alignof", + "and", + "and_eq", + "asm", + "atomic_cancel", + "atomic_commit", + "atomic_noexcept", + "auto", + "bitand", + "bitor", + "bool", + "break", + "case", + "catch", + "char", + "char16_t", + "char32_t", + "class", + "compl", + "concept", + "const", + "constexpr", + "const_cast", + "continue", + "co_await", + "co_return", + "co_yield", + "decltype", + "default", + "delete", + "do", + "double", + "dynamic_cast", + "else", + "enum", + "explicit", + "export", + "extern", + "false", + "float", + "for", + "friend", + "goto", + "if", + "import", + "inline", + "int", + "long", + "module", + "mutable", + "namespace", + "new", + "noexcept", + "not", + "not_eq", + "nullptr", + "operator", + "or", + "or_eq", + "private", + "protected", + "public", + "register", + "reinterpret_cast", + "requires", + "return", + "short", + "signed", + "sizeof", + "static", + "static_assert", + "static_cast", + "struct", + "switch", + "synchronized", + "template", + "this", + "thread_local", + "throw", + "true", + "try", + "typedef", + "typeid", + "typename", + "union", + "unsigned", + "using", + "virtual", + "void", + "volatile", + "wchar_t", + "while", + "xor", + "xor_eq", + nullptr, + }; + for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw); + } + + std::string GenIncludeGuard() const { + // Generate include guard. + std::string guard = file_name_; + // Remove any non-alpha-numeric characters that may appear in a filename. + struct IsAlnum { + bool operator()(char c) const { return !isalnum(c); } + }; + guard.erase(std::remove_if(guard.begin(), guard.end(), IsAlnum()), + guard.end()); + guard = "FLATBUFFERS_GENERATED_" + guard; + guard += "_"; + // For further uniqueness, also add the namespace. + auto name_space = parser_.current_namespace_; + for (auto it = name_space->components.begin(); + it != name_space->components.end(); ++it) { + guard += *it + "_"; + } + guard += "ITER_"; + guard += "H_"; + std::transform(guard.begin(), guard.end(), guard.begin(), ToUpper); + return guard; + } + + void GenIncludeDependencies() { + int num_includes = 0; + for (auto it = parser_.native_included_files_.begin(); + it != parser_.native_included_files_.end(); ++it) { + code_ += "#include \"" + *it + "\""; + num_includes++; + } + for (auto it = parser_.included_files_.begin(); + it != parser_.included_files_.end(); ++it) { + if (it->second.empty()) continue; + auto noext = flatbuffers::StripExtension(it->second); + auto basename = flatbuffers::StripPath(noext); + + code_ += "#include \"" + parser_.opts.include_prefix + + (parser_.opts.keep_include_path ? noext : basename) + + ".iter.fbs.h\""; + num_includes++; + } + if (num_includes) code_ += ""; + } + + std::string EscapeKeyword(const std::string &name) const { + return keywords_.find(name) == keywords_.end() ? name : name + "_"; + } + + std::string Name(const Definition &def) const { + return EscapeKeyword(def.name); + } + + std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); } + + // Iterate through all definitions we haven't generate code for (enums, + // structs, and tables) and output them to a single file. + bool generate() { + code_.Clear(); + code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n"; + + const auto include_guard = GenIncludeGuard(); + code_ += "#ifndef " + include_guard; + code_ += "#define " + include_guard; + code_ += ""; + + if (parser_.opts.gen_nullable) { + code_ += "#pragma clang system_header\n\n"; + } + + code_ += "#include \"" + file_name_ + ".fbs.h\""; + code_ += "#include \"contrib/libs/flatbuffers/include/flatbuffers/flatbuffers_iter.h\""; + code_ += ""; + + if (parser_.opts.include_dependence_headers) { GenIncludeDependencies(); } + + FLATBUFFERS_ASSERT(!cur_name_space_); + + // Generate forward declarations for all structs/tables, since they may + // have circular references. + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + const auto &struct_def = **it; + if (!struct_def.generated && !struct_def.fixed) { + SetNameSpace(struct_def.defined_namespace); + code_ += "template <typename Iter>"; + code_ += "struct " + Name(struct_def) + ";"; + code_ += ""; + } + } + + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + const auto &struct_def = **it; + if (!struct_def.fixed && !struct_def.generated) { + SetNameSpace(struct_def.defined_namespace); + GenTable(struct_def); + } + } + + // Generate convenient global helper functions: + if (parser_.root_struct_def_ && !parser_.root_struct_def_->fixed) { + auto &struct_def = *parser_.root_struct_def_; + SetNameSpace(struct_def.defined_namespace); + auto name = Name(struct_def); + auto qualified_name = cur_name_space_->GetFullyQualifiedName(name); + auto cpp_name = TranslateNameSpace(qualified_name, true); + const auto cpp_non_iter_name = TranslateNameSpace(qualified_name); + const auto cpp_non_iter_getter = TranslateNameSpace( + parser_.namespaces_.back()->GetFullyQualifiedName("Get"+name)); + + code_.SetValue("STRUCT_NAME", name); + code_.SetValue("CPP_NAME", cpp_name); + code_.SetValue("CPP_NON_ITER_NAME", cpp_non_iter_name); + code_.SetValue("CPP_NON_ITER_GETTER", cpp_non_iter_getter); + + // The root datatype accessor: + code_ += "template <typename Iter>"; + code_ += "inline \\"; + code_ += "std::optional<{{CPP_NAME}}<Iter>> Get{{STRUCT_NAME}}(const Iter& buf) {"; + code_ += " return yandex::maps::flatbuffers_iter::GetRoot<{{CPP_NAME}}<Iter>, Iter>(buf);"; + code_ += "}"; + code_ += ""; + + // The non_iter datatype accessor: + code_ += "inline \\"; + code_ += "const {{CPP_NON_ITER_NAME}} *Get{{STRUCT_NAME}}(const char *buf) {"; + code_ += " return {{CPP_NON_ITER_GETTER}}(buf);"; + code_ += "}"; + code_ += ""; + + if (parser_.file_identifier_.length()) { + // Return the identifier + code_ += "inline const char *{{STRUCT_NAME}}Identifier() {"; + code_ += " return \"" + parser_.file_identifier_ + "\";"; + code_ += "}"; + code_ += ""; + + // Check if a buffer has the identifier. + code_ += "template <typename Iter>"; + code_ += "inline \\"; + code_ += "bool {{STRUCT_NAME}}BufferHasIdentifier(const Iter& buf) {"; + code_ += " return yandex::maps::flatbuffers_iter::BufferHasIdentifier("; + code_ += " buf, {{STRUCT_NAME}}Identifier());"; + code_ += "}"; + code_ += ""; + } + + // The root verifier. + if (parser_.file_identifier_.length()) { + code_.SetValue("ID", name + "Identifier()"); + } else { + code_.SetValue("ID", "nullptr"); + } + + code_ += "template <typename Iter>"; + code_ += "inline bool Verify{{STRUCT_NAME}}Buffer("; + code_ += " yandex::maps::flatbuffers_iter::Verifier<Iter> &verifier) {"; + code_ += " return verifier.template VerifyBuffer<{{CPP_NAME}}<Iter>>({{ID}});"; + code_ += "}"; + code_ += ""; + + if (parser_.file_extension_.length()) { + // Return the extension + code_ += "inline const char *{{STRUCT_NAME}}Extension() {"; + code_ += " return \"" + parser_.file_extension_ + "\";"; + code_ += "}"; + code_ += ""; + } + } + + if (cur_name_space_) SetNameSpace(nullptr); + + // Close the include guard. + code_ += "#endif // " + include_guard; + + const auto file_path = GeneratedIterFileName(path_, file_name_); + const auto final_code = code_.ToString(); + return SaveFile(file_path.c_str(), final_code, false); + } + + private: + CodeWriter code_; + + std::unordered_set<std::string> keywords_; + + // This tracks the current namespace so we can insert namespace declarations. + const Namespace *cur_name_space_; + + const Namespace *CurrentNameSpace() const { return cur_name_space_; } + +// Ensure that a type is prefixed with its namespace whenever it is used +// outside of its namespace. + std::string WrapInNameSpace(const Namespace *ns, + const std::string &name, bool needIter = false) const { + if (CurrentNameSpace() == ns) return name; + std::string qualified_name = qualifying_start_; + for (auto it = ns->components.begin(); it != ns->components.end(); ++it) + qualified_name += *it + qualifying_separator_; + if (needIter) + qualified_name += "iter" + qualifying_separator_; + return qualified_name + name; + } + + std::string WrapInNameSpace(const Definition &def, bool needIter = false) const { + return WrapInNameSpace(def.defined_namespace, def.name, needIter); + } + + // Translates a qualified name in flatbuffer text format to the same name in + // the equivalent C++ namespace. + static std::string TranslateNameSpace(const std::string &qualified_name, bool needIter = false) { + std::string cpp_qualified_name = qualified_name; + size_t start_pos = 0; + while ((start_pos = cpp_qualified_name.find(".", start_pos)) != + std::string::npos) { + cpp_qualified_name.replace(start_pos, 1, "::"); + } + if (needIter) + { + start_pos = cpp_qualified_name.rfind("::"); + if (start_pos != std::string::npos) + cpp_qualified_name.replace(start_pos, 2, "::iter::"); + } + return cpp_qualified_name; + } + + void GenComment(const std::vector<std::string> &dc, const char *prefix = "") { + std::string text; + ::flatbuffers::GenComment(dc, &text, nullptr, prefix); + code_ += text + "\\"; + } + + // Return a C++ type from the table in idl.h + std::string GenTypeBasic(const Type &type, bool user_facing_type) const { + // clang-format off + static const char * const ctypename[] = { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ + #CTYPE, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + }; + // clang-format on + if (user_facing_type) { + if (type.enum_def) return WrapInNameSpace(*type.enum_def); + if (type.base_type == BASE_TYPE_BOOL) return "bool"; + } + return ctypename[type.base_type]; + } + + // Return a C++ pointer type, specialized to the actual struct/table types, + // and vector element types. + std::string GenTypePointer(const Type &type) const { + switch (type.base_type) { + case BASE_TYPE_STRING: { + return "yandex::maps::flatbuffers_iter::String<Iter>"; + } + case BASE_TYPE_VECTOR: { + const auto type_name = GenTypeWire(type.VectorType(), "", false); + return "yandex::maps::flatbuffers_iter::Vector<" + type_name + ", Iter>"; + } + case BASE_TYPE_STRUCT: { + if (IsStruct(type)) + return WrapInNameSpace(*type.struct_def, !type.struct_def->fixed); + return WrapInNameSpace(*type.struct_def, !type.struct_def->fixed) + "<Iter>"; + } + case BASE_TYPE_UNION: + // fall through + default: { return "void"; } + } + } + + // Return a C++ type for any type (scalar/pointer) specifically for + // building a flatbuffer. + std::string GenTypeWire(const Type &type, const char *postfix, + bool user_facing_type) const { + if (IsScalar(type.base_type)) { + return GenTypeBasic(type, user_facing_type) + postfix; + } else if (IsStruct(type)) { + return GenTypePointer(type); + } else { + return "yandex::maps::flatbuffers_iter::Offset<" + GenTypePointer(type) + ">" + postfix; + } + } + + // Return a C++ type for any type (scalar/pointer) that reflects its + // serialized size. + std::string GenTypeSize(const Type &type) const { + if (IsScalar(type.base_type)) { + return GenTypeBasic(type, false); + } else if (IsStruct(type)) { + return GenTypePointer(type); + } else { + return "yandex::maps::flatbuffers_iter::uoffset_t"; + } + } + + // Return a C++ type for any type (scalar/pointer) specifically for + // using a flatbuffer. + std::string GenTypeGet(const Type &type, const char *afterbasic, + const char *beforeptr, const char *afterptr, + bool user_facing_type) { + if (IsScalar(type.base_type)) { + return GenTypeBasic(type, user_facing_type) + afterbasic; + } else { + return beforeptr + GenTypePointer(type) + afterptr; + } + } + + // Generates a value with optionally a cast applied if the field has a + // different underlying type from its interface type (currently only the + // case for enums. "from" specify the direction, true meaning from the + // underlying type to the interface type. + std::string GenUnderlyingCast(const FieldDef &field, bool from, + const std::string &val) { + if (from && field.value.type.base_type == BASE_TYPE_BOOL) { + return val + " != 0"; + } else if ((field.value.type.enum_def && + IsScalar(field.value.type.base_type)) || + field.value.type.base_type == BASE_TYPE_BOOL) { + return "static_cast<" + GenTypeBasic(field.value.type, from) + ">(" + + val + ")"; + } else { + return val; + } + } + + std::string GenFieldOffsetName(const FieldDef &field) { + std::string uname = Name(field); + std::transform(uname.begin(), uname.end(), uname.begin(), ToUpper); + return "VT_" + uname; + } + + std::string GenDefaultConstant(const FieldDef &field) { + return field.value.type.base_type == BASE_TYPE_FLOAT + ? field.value.constant + "f" + : field.value.constant; + } + + // Generate the code to call the appropriate Verify function(s) for a field. + void GenVerifyCall(const FieldDef &field, const char *prefix) { + code_.SetValue("PRE", prefix); + code_.SetValue("NAME", Name(field)); + code_.SetValue("REQUIRED", field.IsRequired() ? "Required" : ""); + code_.SetValue("SIZE", GenTypeSize(field.value.type)); + code_.SetValue("OFFSET", GenFieldOffsetName(field)); + code_ += "{{PRE}}this->template VerifyField{{REQUIRED}}<{{SIZE}}>(verifier, {{OFFSET}})\\"; + + switch (field.value.type.base_type) { + case BASE_TYPE_UNION: { + code_.SetValue("ENUM_NAME", field.value.type.enum_def->name); + code_.SetValue("SUFFIX", UnionTypeFieldSuffix()); + code_ += + "{{PRE}}Verify{{ENUM_NAME}}(verifier, {{NAME}}(), " + "{{NAME}}{{SUFFIX}}())\\"; + break; + } + case BASE_TYPE_STRUCT: { + if (!field.value.type.struct_def->fixed) { + code_ += "{{PRE}}verifier.VerifyTable({{NAME}}())\\"; + } + break; + } + case BASE_TYPE_STRING: { + code_ += "{{PRE}}verifier.Verify({{NAME}}())\\"; + break; + } + case BASE_TYPE_VECTOR: { + code_ += "{{PRE}}verifier.Verify({{NAME}}())\\"; + + switch (field.value.type.element) { + case BASE_TYPE_STRING: { + code_ += "{{PRE}}verifier.VerifyVectorOfStrings({{NAME}}())\\"; + break; + } + case BASE_TYPE_STRUCT: { + if (!field.value.type.struct_def->fixed) { + code_ += "{{PRE}}verifier.VerifyVectorOfTables({{NAME}}())\\"; + } + break; + } + case BASE_TYPE_UNION: { + code_.SetValue("ENUM_NAME", field.value.type.enum_def->name); + code_ += + "{{PRE}}Verify{{ENUM_NAME}}Vector(verifier, {{NAME}}(), " + "{{NAME}}_type())\\"; + break; + } + default: break; + } + break; + } + default: { break; } + } + } + + // Generate CompareWithValue method for a key field. + void GenKeyFieldMethods(const FieldDef &field) { + FLATBUFFERS_ASSERT(field.key); + const bool is_string = (field.value.type.base_type == BASE_TYPE_STRING); + + code_ += " bool KeyCompareLessThan(const std::optional<{{STRUCT_NAME}}<Iter>>& o) const {"; + if (is_string) { + // use operator< of flatbuffers::String + code_ += " return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();"; + } else { + code_ += " return {{FIELD_NAME}}() < o->{{FIELD_NAME}}();"; + } + code_ += " }"; + + if (is_string) { + code_ += " int KeyCompareWithValue(const char *val) const {"; + code_ += " return strcmp({{FIELD_NAME}}()->str().c_str(), val);"; + code_ += " }"; + } else { + FLATBUFFERS_ASSERT(IsScalar(field.value.type.base_type)); + auto type = GenTypeBasic(field.value.type, false); + if (parser_.opts.scoped_enums && field.value.type.enum_def && + IsScalar(field.value.type.base_type)) { + type = GenTypeGet(field.value.type, " ", "const ", " *", true); + } + // Returns {field<val: -1, field==val: 0, field>val: +1}. + code_.SetValue("KEY_TYPE", type); + code_ += " int KeyCompareWithValue({{KEY_TYPE}} val) const {"; + code_ += + " return static_cast<int>({{FIELD_NAME}}() > val) - " + "static_cast<int>({{FIELD_NAME}}() < val);"; + code_ += " }"; + } + } + + + // Generate an accessor struct, builder structs & function for a table. + void GenTable(const StructDef &struct_def) { + // Generate an accessor struct, with methods of the form: + // type name() const { return GetField<type>(offset, defaultval); } + GenComment(struct_def.doc_comment); + + code_.SetValue("STRUCT_NAME", Name(struct_def)); + code_ += "template <typename Iter>"; + code_ += + "struct {{STRUCT_NAME}} FLATBUFFERS_FINAL_CLASS" + " : private yandex::maps::flatbuffers_iter::Table<Iter> {"; + + // Generate field id constants. + if (struct_def.fields.vec.size() > 0) { + // We need to add a trailing comma to all elements except the last one as + // older versions of gcc complain about this. + code_.SetValue("SEP", ""); + code_ += " enum {"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.deprecated) { + // Deprecated fields won't be accessible. + continue; + } + + code_.SetValue("OFFSET_NAME", GenFieldOffsetName(field)); + code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset)); + code_ += "{{SEP}} {{OFFSET_NAME}} = {{OFFSET_VALUE}}\\"; + code_.SetValue("SEP", ",\n"); + } + code_ += ""; + code_ += " };"; + } + + code_ += ""; + code_ += " using yandex::maps::flatbuffers_iter::Table<Iter>::Table;"; + + // Generate the accessors. + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.deprecated) { + // Deprecated fields won't be accessible. + continue; + } + + const bool is_struct = IsStruct(field.value.type); + const bool is_scalar = IsScalar(field.value.type.base_type); + code_.SetValue("FIELD_NAME", Name(field)); + + // Call a different accessor for pointers, that indirects. + std::string accessor = ""; + if (is_scalar) { + accessor = "this->template GetField<"; + } else if (is_struct) { + accessor = "this->template GetStruct<"; + } else { + accessor = "this->template GetPointer<"; + } + auto offset_str = GenFieldOffsetName(field); + auto offset_type = + GenTypeGet(field.value.type, "", "", "", false); + + auto call = accessor + offset_type + ">(" + offset_str; + // Default value as second arg for non-pointer types. + if (is_scalar) { call += ", " + GenDefaultConstant(field); } + call += ")"; + + GenComment(field.doc_comment, " "); + code_.SetValue("FIELD_TYPE", + GenTypeGet(field.value.type, " ", "std::optional<", "> ", true)); + code_.SetValue("FIELD_VALUE", GenUnderlyingCast(field, true, call)); + + code_ += " {{FIELD_TYPE}}{{FIELD_NAME}}() const {"; + code_ += " return {{FIELD_VALUE}};"; + code_ += " }"; + + // Generate a comparison function for this field if it is a key. + if (field.key) { + GenKeyFieldMethods(field); + } + } + + // Generate a verifier function that can check a buffer from an untrusted + // source will never cause reads outside the buffer. + code_ += " bool Verify(yandex::maps::flatbuffers_iter::Verifier<Iter> &verifier) const {"; + code_ += " return this->VerifyTableStart(verifier)\\"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.deprecated) { continue; } + GenVerifyCall(field, " &&\n "); + } + + code_ += " &&\n verifier.EndTable();"; + code_ += " }"; + + code_ += "};"; // End of table. + code_ += ""; + } + + // Set up the correct namespace. Only open a namespace if the existing one is + // different (closing/opening only what is necessary). + // + // The file must start and end with an empty (or null) namespace so that + // namespaces are properly opened and closed. + void SetNameSpace(const Namespace *ns) { + if (cur_name_space_ == ns) { return; } + + // Compute the size of the longest common namespace prefix. + // If cur_name_space is A::B::C::D and ns is A::B::E::F::G, + // the common prefix is A::B:: and we have old_size = 4, new_size = 5 + // and common_prefix_size = 2 + size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0; + size_t new_size = ns ? ns->components.size() : 0; + + size_t common_prefix_size = 0; + while (common_prefix_size < old_size && common_prefix_size < new_size && + ns->components[common_prefix_size] == + cur_name_space_->components[common_prefix_size]) { + common_prefix_size++; + } + + // Close cur_name_space in reverse order to reach the common prefix. + // In the previous example, D then C are closed. + if (old_size > 0) + code_ += "} // namespace iter"; + for (size_t j = old_size; j > common_prefix_size; --j) { + code_ += "} // namespace " + cur_name_space_->components[j - 1]; + } + if (old_size != common_prefix_size) { code_ += ""; } + + // open namespace parts to reach the ns namespace + // in the previous example, E, then F, then G are opened + for (auto j = common_prefix_size; j != new_size; ++j) { + code_ += "namespace " + ns->components[j] + " {"; + } + if (new_size > 0) + code_ += "namespace iter {"; + if (new_size != common_prefix_size) { code_ += ""; } + + cur_name_space_ = ns; + } +}; + +} // namespace cpp_yandex_maps_iter + +bool GenerateCPPYandexMapsIter(const Parser &parser, const std::string &path, + const std::string &file_name) { + cpp_yandex_maps_iter::CppIterGenerator generator(parser, path, file_name); + return generator.generate(); +} + +} // namespace flatbuffers diff --git a/contrib/libs/flatbuffers/src/idl_gen_csharp.cpp b/contrib/libs/flatbuffers/src/idl_gen_csharp.cpp new file mode 100644 index 0000000000..681ab6d642 --- /dev/null +++ b/contrib/libs/flatbuffers/src/idl_gen_csharp.cpp @@ -0,0 +1,2100 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// independent from idl_parser, since this code is not needed for most clients + +#include "flatbuffers/code_generators.h" +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +#if defined(FLATBUFFERS_CPP98_STL) +# include <cctype> +#endif // defined(FLATBUFFERS_CPP98_STL) + +namespace flatbuffers { + +static TypedFloatConstantGenerator CSharpFloatGen("Double.", "Single.", "NaN", + "PositiveInfinity", + "NegativeInfinity"); +static CommentConfig comment_config = { + nullptr, + "///", + nullptr, +}; + +namespace csharp { +class CSharpGenerator : public BaseGenerator { + struct FieldArrayLength { + std::string name; + int length; + }; + + public: + CSharpGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name, "", ".", "cs"), + cur_name_space_(nullptr) {} + + CSharpGenerator &operator=(const CSharpGenerator &); + + bool generate() { + std::string one_file_code; + cur_name_space_ = parser_.current_namespace_; + + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + std::string enumcode; + auto &enum_def = **it; + if (!parser_.opts.one_file) cur_name_space_ = enum_def.defined_namespace; + GenEnum(enum_def, &enumcode, parser_.opts); + if (parser_.opts.one_file) { + one_file_code += enumcode; + } else { + if (!SaveType(enum_def.name, *enum_def.defined_namespace, enumcode, + false)) + return false; + } + } + + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + std::string declcode; + auto &struct_def = **it; + if (!parser_.opts.one_file) + cur_name_space_ = struct_def.defined_namespace; + GenStruct(struct_def, &declcode, parser_.opts); + if (parser_.opts.one_file) { + one_file_code += declcode; + } else { + if (!SaveType(struct_def.name, *struct_def.defined_namespace, declcode, + true)) + return false; + } + } + + if (parser_.opts.one_file) { + return SaveType(file_name_, *parser_.current_namespace_, one_file_code, + true); + } + return true; + } + + // Save out the generated code for a single class while adding + // declaration boilerplate. + bool SaveType(const std::string &defname, const Namespace &ns, + const std::string &classcode, bool needs_includes) const { + if (!classcode.length()) return true; + + std::string code = + "// <auto-generated>\n" + "// " + + std::string(FlatBuffersGeneratedWarning()) + + "\n" + "// </auto-generated>\n\n"; + + std::string namespace_name = FullNamespace(".", ns); + if (!namespace_name.empty()) { + code += "namespace " + namespace_name + "\n{\n\n"; + } + if (needs_includes) { + code += "using global::System;\n"; + code += "using global::System.Collections.Generic;\n"; + code += "using global::FlatBuffers;\n\n"; + } + code += classcode; + if (!namespace_name.empty()) { code += "\n}\n"; } + auto filename = NamespaceDir(ns) + defname + ".cs"; + return SaveFile(filename.c_str(), code, false); + } + + const Namespace *CurrentNameSpace() const { return cur_name_space_; } + + std::string GenTypeBasic(const Type &type, bool enableLangOverrides) const { + // clang-format off + static const char * const csharp_typename[] = { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, ...) \ + #NTYPE, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + }; + // clang-format on + + if (enableLangOverrides) { + if (IsEnum(type)) return WrapInNameSpace(*type.enum_def); + if (type.base_type == BASE_TYPE_STRUCT) { + return "Offset<" + WrapInNameSpace(*type.struct_def) + ">"; + } + } + + return csharp_typename[type.base_type]; + } + + inline std::string GenTypeBasic(const Type &type) const { + return GenTypeBasic(type, true); + } + + std::string GenTypePointer(const Type &type) const { + switch (type.base_type) { + case BASE_TYPE_STRING: return "string"; + case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType()); + case BASE_TYPE_STRUCT: return WrapInNameSpace(*type.struct_def); + case BASE_TYPE_UNION: return "TTable"; + default: return "Table"; + } + } + + std::string GenTypeGet(const Type &type) const { + return IsScalar(type.base_type) + ? GenTypeBasic(type) + : (IsArray(type) ? GenTypeGet(type.VectorType()) + : GenTypePointer(type)); + } + + std::string GenOffsetType(const StructDef &struct_def) const { + return "Offset<" + WrapInNameSpace(struct_def) + ">"; + } + + std::string GenOffsetConstruct(const StructDef &struct_def, + const std::string &variable_name) const { + return "new Offset<" + WrapInNameSpace(struct_def) + ">(" + variable_name + + ")"; + } + + // Casts necessary to correctly read serialized data + std::string DestinationCast(const Type &type) const { + if (IsSeries(type)) { + return DestinationCast(type.VectorType()); + } else { + if (IsEnum(type)) return "(" + WrapInNameSpace(*type.enum_def) + ")"; + } + return ""; + } + + // Cast statements for mutator method parameters. + // In Java, parameters representing unsigned numbers need to be cast down to + // their respective type. For example, a long holding an unsigned int value + // would be cast down to int before being put onto the buffer. In C#, one cast + // directly cast an Enum to its underlying type, which is essential before + // putting it onto the buffer. + std::string SourceCast(const Type &type) const { + if (IsSeries(type)) { + return SourceCast(type.VectorType()); + } else { + if (IsEnum(type)) return "(" + GenTypeBasic(type, false) + ")"; + } + return ""; + } + + std::string SourceCastBasic(const Type &type) const { + return IsScalar(type.base_type) ? SourceCast(type) : ""; + } + + std::string GenEnumDefaultValue(const FieldDef &field) const { + auto &value = field.value; + FLATBUFFERS_ASSERT(value.type.enum_def); + auto &enum_def = *value.type.enum_def; + auto enum_val = enum_def.FindByValue(value.constant); + return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name) + : value.constant; + } + + std::string GenDefaultValue(const FieldDef &field, + bool enableLangOverrides) const { + // If it is an optional scalar field, the default is null + if (field.IsScalarOptional()) { return "null"; } + + auto &value = field.value; + if (enableLangOverrides) { + // handles both enum case and vector of enum case + if (value.type.enum_def != nullptr && + value.type.base_type != BASE_TYPE_UNION) { + return GenEnumDefaultValue(field); + } + } + + auto longSuffix = ""; + switch (value.type.base_type) { + case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true"; + case BASE_TYPE_ULONG: return value.constant; + case BASE_TYPE_UINT: + case BASE_TYPE_LONG: return value.constant + longSuffix; + default: + if (IsFloat(value.type.base_type)) + return CSharpFloatGen.GenFloatConstant(field); + else + return value.constant; + } + } + + std::string GenDefaultValue(const FieldDef &field) const { + return GenDefaultValue(field, true); + } + + std::string GenDefaultValueBasic(const FieldDef &field, + bool enableLangOverrides) const { + auto &value = field.value; + if (!IsScalar(value.type.base_type)) { + if (enableLangOverrides) { + switch (value.type.base_type) { + case BASE_TYPE_STRING: return "default(StringOffset)"; + case BASE_TYPE_STRUCT: + return "default(Offset<" + WrapInNameSpace(*value.type.struct_def) + + ">)"; + case BASE_TYPE_VECTOR: return "default(VectorOffset)"; + default: break; + } + } + return "0"; + } + return GenDefaultValue(field, enableLangOverrides); + } + + std::string GenDefaultValueBasic(const FieldDef &field) const { + return GenDefaultValueBasic(field, true); + } + + void GenEnum(EnumDef &enum_def, std::string *code_ptr, + const IDLOptions &opts) const { + std::string &code = *code_ptr; + if (enum_def.generated) return; + + // Generate enum definitions of the form: + // public static (final) int name = value; + // In Java, we use ints rather than the Enum feature, because we want them + // to map directly to how they're used in C/C++ and file formats. + // That, and Java Enums are expensive, and not universally liked. + GenComment(enum_def.doc_comment, code_ptr, &comment_config); + + if (opts.cs_gen_json_serializer && opts.generate_object_based_api) { + code += + "[Newtonsoft.Json.JsonConverter(typeof(Newtonsoft.Json.Converters." + "StringEnumConverter))]\n"; + } + // In C# this indicates enumeration values can be treated as bit flags. + if (enum_def.attributes.Lookup("bit_flags")) { + code += "[System.FlagsAttribute]\n"; + } + if (enum_def.attributes.Lookup("private")) { + code += "internal "; + } else { + code += "public "; + } + code += "enum " + enum_def.name; + code += " : " + GenTypeBasic(enum_def.underlying_type, false); + code += "\n{\n"; + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + auto &ev = **it; + GenComment(ev.doc_comment, code_ptr, &comment_config, " "); + code += " "; + code += ev.name + " = "; + code += enum_def.ToString(ev); + code += ",\n"; + } + // Close the class + code += "};\n\n"; + + if (opts.generate_object_based_api) { + GenEnum_ObjectAPI(enum_def, code_ptr, opts); + } + } + + bool HasUnionStringValue(const EnumDef &enum_def) const { + if (!enum_def.is_union) return false; + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + auto &val = **it; + if (IsString(val.union_type)) { return true; } + } + return false; + } + + // Returns the function name that is able to read a value of the given type. + std::string GenGetter(const Type &type) const { + switch (type.base_type) { + case BASE_TYPE_STRING: return "__p.__string"; + case BASE_TYPE_STRUCT: return "__p.__struct"; + case BASE_TYPE_UNION: return "__p.__union"; + case BASE_TYPE_VECTOR: return GenGetter(type.VectorType()); + case BASE_TYPE_ARRAY: return GenGetter(type.VectorType()); + default: { + std::string getter = "__p.bb.Get"; + if (type.base_type == BASE_TYPE_BOOL) { + getter = "0!=" + getter; + } else if (GenTypeBasic(type, false) != "byte") { + getter += MakeCamel(GenTypeBasic(type, false)); + } + return getter; + } + } + } + + // Returns the function name that is able to read a value of the given type. + std::string GenGetterForLookupByKey(flatbuffers::FieldDef *key_field, + const std::string &data_buffer, + const char *num = nullptr) const { + auto type = key_field->value.type; + auto dest_mask = ""; + auto dest_cast = DestinationCast(type); + auto getter = data_buffer + ".Get"; + if (GenTypeBasic(type, false) != "byte") { + getter += MakeCamel(GenTypeBasic(type, false)); + } + getter = dest_cast + getter + "(" + GenOffsetGetter(key_field, num) + ")" + + dest_mask; + return getter; + } + + // Direct mutation is only allowed for scalar fields. + // Hence a setter method will only be generated for such fields. + std::string GenSetter(const Type &type) const { + if (IsScalar(type.base_type)) { + std::string setter = "__p.bb.Put"; + if (GenTypeBasic(type, false) != "byte" && + type.base_type != BASE_TYPE_BOOL) { + setter += MakeCamel(GenTypeBasic(type, false)); + } + return setter; + } else { + return ""; + } + } + + // Returns the method name for use with add/put calls. + std::string GenMethod(const Type &type) const { + return IsScalar(type.base_type) ? MakeCamel(GenTypeBasic(type, false)) + : (IsStruct(type) ? "Struct" : "Offset"); + } + + // Recursively generate arguments for a constructor, to deal with nested + // structs. + void GenStructArgs(const StructDef &struct_def, std::string *code_ptr, + const char *nameprefix, size_t array_count = 0) const { + std::string &code = *code_ptr; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + const auto &field_type = field.value.type; + const auto array_field = IsArray(field_type); + const auto &type = array_field ? field_type.VectorType() : field_type; + const auto array_cnt = array_field ? (array_count + 1) : array_count; + if (IsStruct(type)) { + // Generate arguments for a struct inside a struct. To ensure names + // don't clash, and to make it obvious these arguments are constructing + // a nested struct, prefix the name with the field name. + GenStructArgs(*field_type.struct_def, code_ptr, + (nameprefix + (field.name + "_")).c_str(), array_cnt); + } else { + code += ", "; + code += GenTypeBasic(type); + if (field.IsScalarOptional()) { code += "?"; } + if (array_cnt > 0) { + code += "["; + for (size_t i = 1; i < array_cnt; i++) code += ","; + code += "]"; + } + code += " "; + code += nameprefix; + code += MakeCamel(field.name, true); + } + } + } + + // Recusively generate struct construction statements of the form: + // builder.putType(name); + // and insert manual padding. + void GenStructBody(const StructDef &struct_def, std::string *code_ptr, + const char *nameprefix, size_t index = 0, + bool in_array = false) const { + std::string &code = *code_ptr; + std::string indent((index + 1) * 2, ' '); + code += indent + " builder.Prep("; + code += NumToString(struct_def.minalign) + ", "; + code += NumToString(struct_def.bytesize) + ");\n"; + for (auto it = struct_def.fields.vec.rbegin(); + it != struct_def.fields.vec.rend(); ++it) { + auto &field = **it; + const auto &field_type = field.value.type; + if (field.padding) { + code += indent + " builder.Pad("; + code += NumToString(field.padding) + ");\n"; + } + if (IsStruct(field_type)) { + GenStructBody(*field_type.struct_def, code_ptr, + (nameprefix + (field.name + "_")).c_str(), index, + in_array); + } else { + const auto &type = + IsArray(field_type) ? field_type.VectorType() : field_type; + const auto index_var = "_idx" + NumToString(index); + if (IsArray(field_type)) { + code += indent + " for (int " + index_var + " = "; + code += NumToString(field_type.fixed_length); + code += "; " + index_var + " > 0; " + index_var + "--) {\n"; + in_array = true; + } + if (IsStruct(type)) { + GenStructBody(*field_type.struct_def, code_ptr, + (nameprefix + (field.name + "_")).c_str(), index + 1, + in_array); + } else { + code += IsArray(field_type) ? " " : ""; + code += indent + " builder.Put"; + code += GenMethod(type) + "("; + code += SourceCast(type); + auto argname = nameprefix + MakeCamel(field.name, true); + code += argname; + size_t array_cnt = index + (IsArray(field_type) ? 1 : 0); + if (array_cnt > 0) { + code += "["; + for (size_t i = 0; in_array && i < array_cnt; i++) { + code += "_idx" + NumToString(i) + "-1"; + if (i != (array_cnt - 1)) code += ","; + } + code += "]"; + } + code += ");\n"; + } + if (IsArray(field_type)) { code += indent + " }\n"; } + } + } + } + std::string GenOffsetGetter(flatbuffers::FieldDef *key_field, + const char *num = nullptr) const { + std::string key_offset = + "Table.__offset(" + NumToString(key_field->value.offset) + ", "; + if (num) { + key_offset += num; + key_offset += ".Value, builder.DataBuffer)"; + } else { + key_offset += "bb.Length"; + key_offset += " - tableOffset, bb)"; + } + return key_offset; + } + + std::string GenLookupKeyGetter(flatbuffers::FieldDef *key_field) const { + std::string key_getter = " "; + key_getter += "int tableOffset = Table."; + key_getter += "__indirect(vectorLocation + 4 * (start + middle)"; + key_getter += ", bb);\n "; + if (IsString(key_field->value.type)) { + key_getter += "int comp = Table."; + key_getter += "CompareStrings("; + key_getter += GenOffsetGetter(key_field); + key_getter += ", byteKey, bb);\n"; + } else { + auto get_val = GenGetterForLookupByKey(key_field, "bb"); + key_getter += "int comp = " + get_val + ".CompareTo(key);\n"; + } + return key_getter; + } + + std::string GenKeyGetter(flatbuffers::FieldDef *key_field) const { + std::string key_getter = ""; + auto data_buffer = "builder.DataBuffer"; + if (IsString(key_field->value.type)) { + key_getter += "Table.CompareStrings("; + key_getter += GenOffsetGetter(key_field, "o1") + ", "; + key_getter += GenOffsetGetter(key_field, "o2") + ", " + data_buffer + ")"; + } else { + auto field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o1"); + key_getter += field_getter; + field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2"); + key_getter += ".CompareTo(" + field_getter + ")"; + } + return key_getter; + } + + void GenStruct(StructDef &struct_def, std::string *code_ptr, + const IDLOptions &opts) const { + if (struct_def.generated) return; + std::string &code = *code_ptr; + + // Generate a struct accessor class, with methods of the form: + // public type name() { return bb.getType(i + offset); } + // or for tables of the form: + // public type name() { + // int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default; + // } + GenComment(struct_def.doc_comment, code_ptr, &comment_config); + if (struct_def.attributes.Lookup("private")) { + code += "internal "; + } else { + code += "public "; + } + if (struct_def.attributes.Lookup("csharp_partial")) { + // generate a partial class for this C# struct/table + code += "partial "; + } + code += "struct " + struct_def.name; + code += " : IFlatbufferObject"; + code += "\n{\n"; + code += " private "; + code += struct_def.fixed ? "Struct" : "Table"; + code += " __p;\n"; + + code += " public ByteBuffer ByteBuffer { get { return __p.bb; } }\n"; + + if (!struct_def.fixed) { + // Generate verson check method. + // Force compile time error if not using the same version runtime. + code += " public static void ValidateVersion() {"; + code += " FlatBufferConstants."; + code += "FLATBUFFERS_2_0_0(); "; + code += "}\n"; + + // Generate a special accessor for the table that when used as the root + // of a FlatBuffer + std::string method_name = "GetRootAs" + struct_def.name; + std::string method_signature = + " public static " + struct_def.name + " " + method_name; + + // create convenience method that doesn't require an existing object + code += method_signature + "(ByteBuffer _bb) "; + code += "{ return " + method_name + "(_bb, new " + struct_def.name + + "()); }\n"; + + // create method that allows object reuse + code += + method_signature + "(ByteBuffer _bb, " + struct_def.name + " obj) { "; + code += "return (obj.__assign(_bb.GetInt(_bb.Position"; + code += ") + _bb.Position"; + code += ", _bb)); }\n"; + if (parser_.root_struct_def_ == &struct_def) { + if (parser_.file_identifier_.length()) { + // Check if a buffer has the identifier. + code += " public static "; + code += "bool " + struct_def.name; + code += "BufferHasIdentifier(ByteBuffer _bb) { return "; + code += "Table.__has_identifier(_bb, \""; + code += parser_.file_identifier_; + code += "\"); }\n"; + } + } + } + // Generate the __init method that sets the field in a pre-existing + // accessor object. This is to allow object reuse. + code += " public void __init(int _i, ByteBuffer _bb) "; + code += "{ "; + code += "__p = new "; + code += struct_def.fixed ? "Struct" : "Table"; + code += "(_i, _bb); "; + code += "}\n"; + code += + " public " + struct_def.name + " __assign(int _i, ByteBuffer _bb) "; + code += "{ __init(_i, _bb); return this; }\n\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + GenComment(field.doc_comment, code_ptr, &comment_config, " "); + std::string type_name = GenTypeGet(field.value.type); + std::string type_name_dest = GenTypeGet(field.value.type); + std::string conditional_cast = ""; + std::string optional = ""; + if (!struct_def.fixed && + (field.value.type.base_type == BASE_TYPE_STRUCT || + field.value.type.base_type == BASE_TYPE_UNION || + (IsVector(field.value.type) && + (field.value.type.element == BASE_TYPE_STRUCT || + field.value.type.element == BASE_TYPE_UNION)))) { + optional = "?"; + conditional_cast = "(" + type_name_dest + optional + ")"; + } + if (field.IsScalarOptional()) { optional = "?"; } + std::string dest_mask = ""; + std::string dest_cast = DestinationCast(field.value.type); + std::string src_cast = SourceCast(field.value.type); + std::string field_name_camel = MakeCamel(field.name, true); + std::string method_start = + " public " + type_name_dest + optional + " " + field_name_camel; + std::string obj = "(new " + type_name + "())"; + + // Most field accessors need to retrieve and test the field offset first, + // this is the prefix code for that: + auto offset_prefix = + IsArray(field.value.type) + ? " { return " + : (" { int o = __p.__offset(" + NumToString(field.value.offset) + + "); return o != 0 ? "); + // Generate the accessors that don't do object reuse. + if (field.value.type.base_type == BASE_TYPE_STRUCT) { + } else if (IsVector(field.value.type) && + field.value.type.element == BASE_TYPE_STRUCT) { + } else if (field.value.type.base_type == BASE_TYPE_UNION || + (IsVector(field.value.type) && + field.value.type.VectorType().base_type == BASE_TYPE_UNION)) { + method_start += "<TTable>"; + type_name = type_name_dest; + } + std::string getter = dest_cast + GenGetter(field.value.type); + code += method_start; + std::string default_cast = ""; + // only create default casts for c# scalars or vectors of scalars + if ((IsScalar(field.value.type.base_type) || + (IsVector(field.value.type) && + IsScalar(field.value.type.element)))) { + // For scalars, default value will be returned by GetDefaultValue(). + // If the scalar is an enum, GetDefaultValue() returns an actual c# enum + // that doesn't need to be casted. However, default values for enum + // elements of vectors are integer literals ("0") and are still casted + // for clarity. + // If the scalar is optional and enum, we still need the cast. + if ((field.value.type.enum_def == nullptr || + IsVector(field.value.type)) || + (IsEnum(field.value.type) && field.IsScalarOptional())) { + default_cast = "(" + type_name_dest + optional + ")"; + } + } + std::string member_suffix = "; "; + if (IsScalar(field.value.type.base_type)) { + code += " { get"; + member_suffix += "} "; + if (struct_def.fixed) { + code += " { return " + getter; + code += "(__p.bb_pos + "; + code += NumToString(field.value.offset) + ")"; + code += dest_mask; + } else { + code += offset_prefix + getter; + code += "(o + __p.bb_pos)" + dest_mask; + code += " : " + default_cast; + code += GenDefaultValue(field); + } + } else { + switch (field.value.type.base_type) { + case BASE_TYPE_STRUCT: + code += " { get"; + member_suffix += "} "; + if (struct_def.fixed) { + code += " { return " + obj + ".__assign(" + "__p."; + code += "bb_pos + " + NumToString(field.value.offset) + ", "; + code += "__p.bb)"; + } else { + code += offset_prefix + conditional_cast; + code += obj + ".__assign("; + code += field.value.type.struct_def->fixed + ? "o + __p.bb_pos" + : "__p.__indirect(o + __p.bb_pos)"; + code += ", __p.bb) : null"; + } + break; + case BASE_TYPE_STRING: + code += " { get"; + member_suffix += "} "; + code += offset_prefix + getter + "(o + " + "__p."; + code += "bb_pos) : null"; + break; + case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru + case BASE_TYPE_VECTOR: { + auto vectortype = field.value.type.VectorType(); + if (vectortype.base_type == BASE_TYPE_UNION) { + conditional_cast = "(TTable?)"; + getter += "<TTable>"; + } + code += "("; + if (vectortype.base_type == BASE_TYPE_STRUCT) { + getter = obj + ".__assign"; + } else if (vectortype.base_type == BASE_TYPE_UNION) { + } + code += "int j)"; + const auto body = offset_prefix + conditional_cast + getter + "("; + if (vectortype.base_type == BASE_TYPE_UNION) { + code += " where TTable : struct, IFlatbufferObject" + body; + } else { + code += body; + } + std::string index = "__p."; + if (IsArray(field.value.type)) { + index += "bb_pos + " + NumToString(field.value.offset) + " + "; + } else { + index += "__vector(o) + "; + } + index += "j * " + NumToString(InlineSize(vectortype)); + if (vectortype.base_type == BASE_TYPE_STRUCT) { + code += vectortype.struct_def->fixed + ? index + : "__p.__indirect(" + index + ")"; + code += ", __p.bb"; + } else { + code += index; + } + code += ")" + dest_mask; + if (!IsArray(field.value.type)) { + code += " : "; + code += + field.value.type.element == BASE_TYPE_BOOL + ? "false" + : (IsScalar(field.value.type.element) ? default_cast + "0" + : "null"); + } + if (vectortype.base_type == BASE_TYPE_UNION && + HasUnionStringValue(*vectortype.enum_def)) { + code += member_suffix; + code += "}\n"; + code += " public string " + MakeCamel(field.name, true) + + "AsString(int j)"; + code += offset_prefix + GenGetter(Type(BASE_TYPE_STRING)); + code += "(" + index + ") : null"; + } + break; + } + case BASE_TYPE_UNION: + code += "() where TTable : struct, IFlatbufferObject"; + code += offset_prefix + "(TTable?)" + getter; + code += "<TTable>(o + __p.bb_pos) : null"; + if (HasUnionStringValue(*field.value.type.enum_def)) { + code += member_suffix; + code += "}\n"; + code += " public string " + MakeCamel(field.name, true) + + "AsString()"; + code += offset_prefix + GenGetter(Type(BASE_TYPE_STRING)); + code += "(o + __p.bb_pos) : null"; + } + // As<> accesors for Unions + // Loop through all the possible union types and generate an As + // accessor that casts to the correct type. + for (auto uit = field.value.type.enum_def->Vals().begin(); + uit != field.value.type.enum_def->Vals().end(); ++uit) { + auto val = *uit; + if (val->union_type.base_type == BASE_TYPE_NONE) { continue; } + auto union_field_type_name = GenTypeGet(val->union_type); + code += member_suffix + "}\n"; + if (val->union_type.base_type == BASE_TYPE_STRUCT && + val->union_type.struct_def->attributes.Lookup("private")) { + code += " internal "; + } else { + code += " public "; + } + code += union_field_type_name + " "; + code += field_name_camel + "As" + val->name + "() { return "; + code += field_name_camel; + if (IsString(val->union_type)) { + code += "AsString()"; + } else { + code += "<" + union_field_type_name + ">().Value"; + } + } + break; + default: FLATBUFFERS_ASSERT(0); + } + } + code += member_suffix; + code += "}\n"; + if (IsVector(field.value.type)) { + code += " public int " + MakeCamel(field.name, true); + code += "Length"; + code += " { get"; + code += offset_prefix; + code += "__p.__vector_len(o) : 0; "; + code += "} "; + code += "}\n"; + // See if we should generate a by-key accessor. + if (field.value.type.element == BASE_TYPE_STRUCT && + !field.value.type.struct_def->fixed) { + auto &sd = *field.value.type.struct_def; + auto &fields = sd.fields.vec; + for (auto kit = fields.begin(); kit != fields.end(); ++kit) { + auto &key_field = **kit; + if (key_field.key) { + auto qualified_name = WrapInNameSpace(sd); + code += " public " + qualified_name + "? "; + code += MakeCamel(field.name, true) + "ByKey("; + code += GenTypeGet(key_field.value.type) + " key)"; + code += offset_prefix; + code += qualified_name + ".__lookup_by_key("; + code += "__p.__vector(o), key, "; + code += "__p.bb) : null; "; + code += "}\n"; + break; + } + } + } + } + // Generate a ByteBuffer accessor for strings & vectors of scalars. + if ((IsVector(field.value.type) && + IsScalar(field.value.type.VectorType().base_type)) || + IsString(field.value.type)) { + code += "#if ENABLE_SPAN_T\n"; + code += " public Span<" + GenTypeBasic(field.value.type.VectorType()) + + "> Get"; + code += MakeCamel(field.name, true); + code += "Bytes() { return "; + code += "__p.__vector_as_span<" + + GenTypeBasic(field.value.type.VectorType()) + ">("; + code += NumToString(field.value.offset); + code += + ", " + NumToString(SizeOf(field.value.type.VectorType().base_type)); + code += "); }\n"; + code += "#else\n"; + code += " public ArraySegment<byte>? Get"; + code += MakeCamel(field.name, true); + code += "Bytes() { return "; + code += "__p.__vector_as_arraysegment("; + code += NumToString(field.value.offset); + code += "); }\n"; + code += "#endif\n"; + + // For direct blockcopying the data into a typed array + code += " public "; + code += GenTypeBasic(field.value.type.VectorType()); + code += "[] Get"; + code += MakeCamel(field.name, true); + code += "Array() { "; + if (IsEnum(field.value.type.VectorType())) { + // Since __vector_as_array does not work for enum types, + // fill array using an explicit loop. + code += "int o = __p.__offset("; + code += NumToString(field.value.offset); + code += "); if (o == 0) return null; int p = "; + code += "__p.__vector(o); int l = "; + code += "__p.__vector_len(o); "; + code += GenTypeBasic(field.value.type.VectorType()); + code += "[] a = new "; + code += GenTypeBasic(field.value.type.VectorType()); + code += "[l]; for (int i = 0; i < l; i++) { a[i] = " + getter; + code += "(p + i * "; + code += NumToString(InlineSize(field.value.type.VectorType())); + code += "); } return a;"; + } else { + code += "return "; + code += "__p.__vector_as_array<"; + code += GenTypeBasic(field.value.type.VectorType()); + code += ">("; + code += NumToString(field.value.offset); + code += ");"; + } + code += " }\n"; + } + // generate object accessors if is nested_flatbuffer + if (field.nested_flatbuffer) { + auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer); + auto nested_method_name = + MakeCamel(field.name, true) + "As" + field.nested_flatbuffer->name; + auto get_nested_method_name = nested_method_name; + get_nested_method_name = "Get" + nested_method_name; + conditional_cast = "(" + nested_type_name + "?)"; + obj = "(new " + nested_type_name + "())"; + code += " public " + nested_type_name + "? "; + code += get_nested_method_name + "("; + code += ") { int o = __p.__offset("; + code += NumToString(field.value.offset) + "); "; + code += "return o != 0 ? " + conditional_cast + obj + ".__assign("; + code += "__p."; + code += "__indirect(__p.__vector(o)), "; + code += "__p.bb) : null; }\n"; + } + // Generate mutators for scalar fields or vectors of scalars. + if (parser_.opts.mutable_buffer) { + auto is_series = (IsSeries(field.value.type)); + const auto &underlying_type = + is_series ? field.value.type.VectorType() : field.value.type; + // Boolean parameters have to be explicitly converted to byte + // representation. + auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL + ? "(byte)(" + field.name + " ? 1 : 0)" + : field.name; + auto mutator_prefix = MakeCamel("mutate", true); + // A vector mutator also needs the index of the vector element it should + // mutate. + auto mutator_params = (is_series ? "(int j, " : "(") + + GenTypeGet(underlying_type) + " " + field.name + + ") { "; + auto setter_index = + is_series + ? "__p." + + (IsArray(field.value.type) + ? "bb_pos + " + NumToString(field.value.offset) + : "__vector(o)") + + +" + j * " + NumToString(InlineSize(underlying_type)) + : (struct_def.fixed + ? "__p.bb_pos + " + NumToString(field.value.offset) + : "o + __p.bb_pos"); + if (IsScalar(underlying_type.base_type) && !IsUnion(field.value.type)) { + code += " public "; + code += struct_def.fixed ? "void " : "bool "; + code += mutator_prefix + MakeCamel(field.name, true); + code += mutator_params; + if (struct_def.fixed) { + code += GenSetter(underlying_type) + "(" + setter_index + ", "; + code += src_cast + setter_parameter + "); }\n"; + } else { + code += "int o = __p.__offset("; + code += NumToString(field.value.offset) + ");"; + code += " if (o != 0) { " + GenSetter(underlying_type); + code += "(" + setter_index + ", " + src_cast + setter_parameter + + "); return true; } else { return false; } }\n"; + } + } + } + if (parser_.opts.java_primitive_has_method && + IsScalar(field.value.type.base_type) && !struct_def.fixed) { + auto vt_offset_constant = " public static final int VT_" + + MakeScreamingCamel(field.name) + " = " + + NumToString(field.value.offset) + ";"; + + code += vt_offset_constant; + code += "\n"; + } + } + code += "\n"; + auto struct_has_create = false; + std::set<flatbuffers::FieldDef *> field_has_create_set; + flatbuffers::FieldDef *key_field = nullptr; + if (struct_def.fixed) { + struct_has_create = true; + // create a struct constructor function + code += " public static " + GenOffsetType(struct_def) + " "; + code += "Create"; + code += struct_def.name + "(FlatBufferBuilder builder"; + GenStructArgs(struct_def, code_ptr, ""); + code += ") {\n"; + GenStructBody(struct_def, code_ptr, ""); + code += " return "; + code += GenOffsetConstruct(struct_def, "builder.Offset"); + code += ";\n }\n"; + } else { + // Generate a method that creates a table in one go. This is only possible + // when the table has no struct fields, since those have to be created + // inline, and there's no way to do so in Java. + bool has_no_struct_fields = true; + int num_fields = 0; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + if (IsStruct(field.value.type)) { + has_no_struct_fields = false; + } else { + num_fields++; + } + } + // JVM specifications restrict default constructor params to be < 255. + // Longs and doubles take up 2 units, so we set the limit to be < 127. + if ((has_no_struct_fields || opts.generate_object_based_api) && + num_fields && num_fields < 127) { + struct_has_create = true; + // Generate a table constructor of the form: + // public static int createName(FlatBufferBuilder builder, args...) + code += " public static " + GenOffsetType(struct_def) + " "; + code += "Create" + struct_def.name; + code += "(FlatBufferBuilder builder"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + code += ",\n "; + if (IsStruct(field.value.type) && opts.generate_object_based_api) { + code += WrapInNameSpace( + field.value.type.struct_def->defined_namespace, + GenTypeName_ObjectAPI(field.value.type.struct_def->name, opts)); + code += " "; + code += field.name; + code += " = null"; + } else { + code += GenTypeBasic(field.value.type); + if (field.IsScalarOptional()) { code += "?"; } + code += " "; + code += field.name; + if (!IsScalar(field.value.type.base_type)) code += "Offset"; + + code += " = "; + code += GenDefaultValueBasic(field); + } + } + code += ") {\n builder."; + code += "StartTable("; + code += NumToString(struct_def.fields.vec.size()) + ");\n"; + for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1; + size; size /= 2) { + for (auto it = struct_def.fields.vec.rbegin(); + it != struct_def.fields.vec.rend(); ++it) { + auto &field = **it; + if (!field.deprecated && + (!struct_def.sortbysize || + size == SizeOf(field.value.type.base_type))) { + code += " " + struct_def.name + "."; + code += "Add"; + code += MakeCamel(field.name) + "(builder, "; + if (IsStruct(field.value.type) && + opts.generate_object_based_api) { + code += GenTypePointer(field.value.type) + ".Pack(builder, " + + field.name + ")"; + } else { + code += field.name; + if (!IsScalar(field.value.type.base_type)) code += "Offset"; + } + + code += ");\n"; + } + } + } + code += " return " + struct_def.name + "."; + code += "End" + struct_def.name; + code += "(builder);\n }\n\n"; + } + // Generate a set of static methods that allow table construction, + // of the form: + // public static void addName(FlatBufferBuilder builder, short name) + // { builder.addShort(id, name, default); } + // Unlike the Create function, these always work. + code += " public static void Start"; + code += struct_def.name; + code += "(FlatBufferBuilder builder) { builder."; + code += "StartTable("; + code += NumToString(struct_def.fields.vec.size()) + "); }\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + if (field.key) key_field = &field; + code += " public static void Add"; + code += MakeCamel(field.name); + code += "(FlatBufferBuilder builder, "; + code += GenTypeBasic(field.value.type); + auto argname = MakeCamel(field.name, false); + if (!IsScalar(field.value.type.base_type)) argname += "Offset"; + if (field.IsScalarOptional()) { code += "?"; } + code += " " + argname + ") { builder.Add"; + code += GenMethod(field.value.type) + "("; + code += NumToString(it - struct_def.fields.vec.begin()) + ", "; + code += SourceCastBasic(field.value.type); + code += argname; + if (!IsScalar(field.value.type.base_type) && + field.value.type.base_type != BASE_TYPE_UNION) { + code += ".Value"; + } + if (!field.IsScalarOptional()) { + // When the scalar is optional, use the builder method that doesn't + // supply a default value. Otherwise, we to continue to use the + // default value method. + code += ", "; + code += GenDefaultValue(field, false); + } + code += "); }\n"; + if (IsVector(field.value.type)) { + auto vector_type = field.value.type.VectorType(); + auto alignment = InlineAlignment(vector_type); + auto elem_size = InlineSize(vector_type); + if (!IsStruct(vector_type)) { + field_has_create_set.insert(&field); + code += " public static VectorOffset "; + code += "Create"; + code += MakeCamel(field.name); + code += "Vector(FlatBufferBuilder builder, "; + code += GenTypeBasic(vector_type) + "[] data) "; + code += "{ builder.StartVector("; + code += NumToString(elem_size); + code += ", data.Length, "; + code += NumToString(alignment); + code += "); for (int i = data."; + code += "Length - 1; i >= 0; i--) builder."; + code += "Add"; + code += GenMethod(vector_type); + code += "("; + code += SourceCastBasic(vector_type); + code += "data[i]"; + if (vector_type.base_type == BASE_TYPE_STRUCT || + IsString(vector_type)) + code += ".Value"; + code += "); return "; + code += "builder.EndVector(); }\n"; + + code += " public static VectorOffset "; + code += "Create"; + code += MakeCamel(field.name); + code += "VectorBlock(FlatBufferBuilder builder, "; + code += GenTypeBasic(vector_type) + "[] data) "; + code += "{ builder.StartVector("; + code += NumToString(elem_size); + code += ", data.Length, "; + code += NumToString(alignment); + code += "); builder.Add(data); return builder.EndVector(); }\n"; + } + // Generate a method to start a vector, data to be added manually + // after. + code += " public static void Start"; + code += MakeCamel(field.name); + code += "Vector(FlatBufferBuilder builder, int numElems) "; + code += "{ builder.StartVector("; + code += NumToString(elem_size); + code += ", numElems, " + NumToString(alignment); + code += "); }\n"; + } + } + code += " public static " + GenOffsetType(struct_def) + " "; + code += "End" + struct_def.name; + code += "(FlatBufferBuilder builder) {\n int o = builder."; + code += "EndTable();\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (!field.deprecated && field.IsRequired()) { + code += " builder.Required(o, "; + code += NumToString(field.value.offset); + code += "); // " + field.name + "\n"; + } + } + code += " return " + GenOffsetConstruct(struct_def, "o") + ";\n }\n"; + if (parser_.root_struct_def_ == &struct_def) { + std::string size_prefix[] = { "", "SizePrefixed" }; + for (int i = 0; i < 2; ++i) { + code += " public static void "; + code += "Finish" + size_prefix[i] + struct_def.name; + code += + "Buffer(FlatBufferBuilder builder, " + GenOffsetType(struct_def); + code += " offset) {"; + code += " builder.Finish" + size_prefix[i] + "(offset"; + code += ".Value"; + + if (parser_.file_identifier_.length()) + code += ", \"" + parser_.file_identifier_ + "\""; + code += "); }\n"; + } + } + } + // Only generate key compare function for table, + // because `key_field` is not set for struct + if (struct_def.has_key && !struct_def.fixed) { + FLATBUFFERS_ASSERT(key_field); + code += "\n public static VectorOffset "; + code += "CreateSortedVectorOf" + struct_def.name; + code += "(FlatBufferBuilder builder, "; + code += "Offset<" + struct_def.name + ">"; + code += "[] offsets) {\n"; + code += " Array.Sort(offsets, (Offset<" + struct_def.name + + "> o1, Offset<" + struct_def.name + "> o2) => " + + GenKeyGetter(key_field); + code += ");\n"; + code += " return builder.CreateVectorOfTables(offsets);\n }\n"; + + code += "\n public static " + struct_def.name + "?"; + code += " __lookup_by_key("; + code += "int vectorLocation, "; + code += GenTypeGet(key_field->value.type); + code += " key, ByteBuffer bb) {\n"; + if (IsString(key_field->value.type)) { + code += " byte[] byteKey = "; + code += "System.Text.Encoding.UTF8.GetBytes(key);\n"; + } + code += " int span = "; + code += "bb.GetInt(vectorLocation - 4);\n"; + code += " int start = 0;\n"; + code += " while (span != 0) {\n"; + code += " int middle = span / 2;\n"; + code += GenLookupKeyGetter(key_field); + code += " if (comp > 0) {\n"; + code += " span = middle;\n"; + code += " } else if (comp < 0) {\n"; + code += " middle++;\n"; + code += " start += middle;\n"; + code += " span -= middle;\n"; + code += " } else {\n"; + code += " return "; + code += "new " + struct_def.name + "()"; + code += ".__assign(tableOffset, bb);\n"; + code += " }\n }\n"; + code += " return null;\n"; + code += " }\n"; + } + + if (opts.generate_object_based_api) { + GenPackUnPack_ObjectAPI(struct_def, code_ptr, opts, struct_has_create, + field_has_create_set); + } + code += "};\n\n"; + + if (opts.generate_object_based_api) { + GenStruct_ObjectAPI(struct_def, code_ptr, opts); + } + } + + void GenVectorAccessObject(StructDef &struct_def, + std::string *code_ptr) const { + auto &code = *code_ptr; + // Generate a vector of structs accessor class. + code += "\n"; + code += " "; + if (!struct_def.attributes.Lookup("private")) code += "public "; + code += "static struct Vector : BaseVector\n{\n"; + + // Generate the __assign method that sets the field in a pre-existing + // accessor object. This is to allow object reuse. + std::string method_indent = " "; + code += method_indent + "public Vector "; + code += "__assign(int _vector, int _element_size, ByteBuffer _bb) { "; + code += "__reset(_vector, _element_size, _bb); return this; }\n\n"; + + auto type_name = struct_def.name; + auto method_start = method_indent + "public " + type_name + " Get"; + // Generate the accessors that don't do object reuse. + code += method_start + "(int j) { return Get"; + code += "(new " + type_name + "(), j); }\n"; + code += method_start + "(" + type_name + " obj, int j) { "; + code += " return obj.__assign("; + code += struct_def.fixed ? "__p.__element(j)" + : "__p.__indirect(__p.__element(j), bb)"; + code += ", __p.bb); }\n"; + // See if we should generate a by-key accessor. + if (!struct_def.fixed) { + auto &fields = struct_def.fields.vec; + for (auto kit = fields.begin(); kit != fields.end(); ++kit) { + auto &key_field = **kit; + if (key_field.key) { + auto nullable_annotation = + parser_.opts.gen_nullable ? "@Nullable " : ""; + code += method_indent + nullable_annotation; + code += "public " + type_name + "? "; + code += "GetByKey("; + code += GenTypeGet(key_field.value.type) + " key) { "; + code += " return __lookup_by_key(null, "; + code += "__p.__vector(), key, "; + code += "__p.bb); "; + code += "}\n"; + code += method_indent + nullable_annotation; + code += "public " + type_name + "?" + " "; + code += "GetByKey("; + code += type_name + "? obj, "; + code += GenTypeGet(key_field.value.type) + " key) { "; + code += " return __lookup_by_key(obj, "; + code += "__p.__vector(), key, "; + code += "__p.bb); "; + code += "}\n"; + break; + } + } + } + code += " }\n"; + } + + void GenEnum_ObjectAPI(EnumDef &enum_def, std::string *code_ptr, + const IDLOptions &opts) const { + auto &code = *code_ptr; + if (enum_def.generated) return; + if (!enum_def.is_union) return; + if (enum_def.attributes.Lookup("private")) { + code += "internal "; + } else { + code += "public "; + } + auto union_name = enum_def.name + "Union"; + code += "class " + union_name + " {\n"; + // Type + code += " public " + enum_def.name + " Type { get; set; }\n"; + // Value + code += " public object Value { get; set; }\n"; + code += "\n"; + // Constructor + code += " public " + union_name + "() {\n"; + code += " this.Type = " + enum_def.name + "." + + enum_def.Vals()[0]->name + ";\n"; + code += " this.Value = null;\n"; + code += " }\n\n"; + // As<T> + code += " public T As<T>() where T : class { return this.Value as T; }\n"; + // As + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + auto &ev = **it; + if (ev.union_type.base_type == BASE_TYPE_NONE) continue; + auto type_name = GenTypeGet_ObjectAPI(ev.union_type, opts); + if (ev.union_type.base_type == BASE_TYPE_STRUCT && + ev.union_type.struct_def->attributes.Lookup("private")) { + code += " internal "; + } else { + code += " public "; + } + code += type_name + " As" + ev.name + "() { return this.As<" + type_name + + ">(); }\n"; + } + code += "\n"; + // Pack() + code += " public static int Pack(FlatBuffers.FlatBufferBuilder builder, " + + union_name + " _o) {\n"; + code += " switch (_o.Type) {\n"; + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + auto &ev = **it; + if (ev.union_type.base_type == BASE_TYPE_NONE) { + code += " default: return 0;\n"; + } else { + code += " case " + enum_def.name + "." + ev.name + ": return "; + if (IsString(ev.union_type)) { + code += "builder.CreateString(_o.As" + ev.name + "()).Value;\n"; + } else { + code += GenTypeGet(ev.union_type) + ".Pack(builder, _o.As" + ev.name + + "()).Value;\n"; + } + } + } + code += " }\n"; + code += " }\n"; + code += "}\n\n"; + // JsonConverter + if (opts.cs_gen_json_serializer) { + if (enum_def.attributes.Lookup("private")) { + code += "internal "; + } else { + code += "public "; + } + code += "class " + union_name + + "_JsonConverter : Newtonsoft.Json.JsonConverter {\n"; + code += " public override bool CanConvert(System.Type objectType) {\n"; + code += " return objectType == typeof(" + union_name + + ") || objectType == typeof(System.Collections.Generic.List<" + + union_name + ">);\n"; + code += " }\n"; + code += + " public override void WriteJson(Newtonsoft.Json.JsonWriter writer, " + "object value, " + "Newtonsoft.Json.JsonSerializer serializer) {\n"; + code += " var _olist = value as System.Collections.Generic.List<" + + union_name + ">;\n"; + code += " if (_olist != null) {\n"; + code += " writer.WriteStartArray();\n"; + code += + " foreach (var _o in _olist) { this.WriteJson(writer, _o, " + "serializer); }\n"; + code += " writer.WriteEndArray();\n"; + code += " } else {\n"; + code += " this.WriteJson(writer, value as " + union_name + + ", serializer);\n"; + code += " }\n"; + code += " }\n"; + code += " public void WriteJson(Newtonsoft.Json.JsonWriter writer, " + + union_name + + " _o, " + "Newtonsoft.Json.JsonSerializer serializer) {\n"; + code += " if (_o == null) return;\n"; + code += " serializer.Serialize(writer, _o.Value);\n"; + code += " }\n"; + code += + " public override object ReadJson(Newtonsoft.Json.JsonReader " + "reader, " + "System.Type objectType, " + "object existingValue, Newtonsoft.Json.JsonSerializer serializer) " + "{\n"; + code += + " var _olist = existingValue as System.Collections.Generic.List<" + + union_name + ">;\n"; + code += " if (_olist != null) {\n"; + code += " for (var _j = 0; _j < _olist.Count; ++_j) {\n"; + code += " reader.Read();\n"; + code += + " _olist[_j] = this.ReadJson(reader, _olist[_j], " + "serializer);\n"; + code += " }\n"; + code += " reader.Read();\n"; + code += " return _olist;\n"; + code += " } else {\n"; + code += " return this.ReadJson(reader, existingValue as " + + union_name + ", serializer);\n"; + code += " }\n"; + code += " }\n"; + code += " public " + union_name + + " ReadJson(Newtonsoft.Json.JsonReader reader, " + union_name + + " _o, Newtonsoft.Json.JsonSerializer serializer) {\n"; + code += " if (_o == null) return null;\n"; + code += " switch (_o.Type) {\n"; + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); + ++it) { + auto &ev = **it; + if (ev.union_type.base_type == BASE_TYPE_NONE) { + code += " default: break;\n"; + } else { + auto type_name = GenTypeGet_ObjectAPI(ev.union_type, opts); + code += " case " + enum_def.name + "." + ev.name + + ": _o.Value = serializer.Deserialize<" + type_name + + ">(reader); break;\n"; + } + } + code += " }\n"; + code += " return _o;\n"; + code += " }\n"; + code += "}\n\n"; + } + } + + std::string GenTypeName_ObjectAPI(const std::string &name, + const IDLOptions &opts) const { + return opts.object_prefix + name + opts.object_suffix; + } + + void GenUnionUnPack_ObjectAPI(const EnumDef &enum_def, std::string *code_ptr, + const std::string &camel_name, + bool is_vector) const { + auto &code = *code_ptr; + std::string varialbe_name = "_o." + camel_name; + std::string type_suffix = ""; + std::string func_suffix = "()"; + std::string indent = " "; + if (is_vector) { + varialbe_name = "_o_" + camel_name; + type_suffix = "(_j)"; + func_suffix = "(_j)"; + indent = " "; + } + if (is_vector) { + code += indent + "var " + varialbe_name + " = new "; + } else { + code += indent + varialbe_name + " = new "; + } + code += WrapInNameSpace(enum_def) + "Union();\n"; + code += indent + varialbe_name + ".Type = this." + camel_name + "Type" + + type_suffix + ";\n"; + code += + indent + "switch (this." + camel_name + "Type" + type_suffix + ") {\n"; + for (auto eit = enum_def.Vals().begin(); eit != enum_def.Vals().end(); + ++eit) { + auto &ev = **eit; + if (ev.union_type.base_type == BASE_TYPE_NONE) { + code += indent + " default: break;\n"; + } else { + code += indent + " case " + WrapInNameSpace(enum_def) + "." + ev.name + + ":\n"; + code += indent + " " + varialbe_name + ".Value = this." + camel_name; + if (IsString(ev.union_type)) { + code += "AsString" + func_suffix + ";\n"; + } else { + code += "<" + GenTypeGet(ev.union_type) + ">" + func_suffix; + code += ".HasValue ? this." + camel_name; + code += "<" + GenTypeGet(ev.union_type) + ">" + func_suffix + + ".Value.UnPack() : null;\n"; + } + code += indent + " break;\n"; + } + } + code += indent + "}\n"; + if (is_vector) { + code += indent + "_o." + camel_name + ".Add(" + varialbe_name + ");\n"; + } + } + + void GenPackUnPack_ObjectAPI( + StructDef &struct_def, std::string *code_ptr, const IDLOptions &opts, + bool struct_has_create, + const std::set<FieldDef *> &field_has_create) const { + auto &code = *code_ptr; + auto struct_name = GenTypeName_ObjectAPI(struct_def.name, opts); + // UnPack() + code += " public " + struct_name + " UnPack() {\n"; + code += " var _o = new " + struct_name + "();\n"; + code += " this.UnPackTo(_o);\n"; + code += " return _o;\n"; + code += " }\n"; + // UnPackTo() + code += " public void UnPackTo(" + struct_name + " _o) {\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + auto camel_name = MakeCamel(field.name); + auto start = " _o." + camel_name + " = "; + switch (field.value.type.base_type) { + case BASE_TYPE_STRUCT: { + auto fixed = struct_def.fixed && field.value.type.struct_def->fixed; + if (fixed) { + code += start + "this." + camel_name + ".UnPack();\n"; + } else { + code += start + "this." + camel_name + ".HasValue ? this." + + camel_name + ".Value.UnPack() : null;\n"; + } + break; + } + case BASE_TYPE_ARRAY: { + auto type_name = GenTypeGet_ObjectAPI(field.value.type, opts); + auto length_str = NumToString(field.value.type.fixed_length); + auto unpack_method = field.value.type.struct_def == nullptr + ? "" + : field.value.type.struct_def->fixed + ? ".UnPack()" + : "?.UnPack()"; + code += start + "new " + type_name.substr(0, type_name.length() - 1) + + length_str + "];\n"; + code += " for (var _j = 0; _j < " + length_str + "; ++_j) { _o." + + camel_name + "[_j] = this." + camel_name + "(_j)" + + unpack_method + "; }\n"; + break; + } + case BASE_TYPE_VECTOR: + if (field.value.type.element == BASE_TYPE_UNION) { + code += start + "new " + + GenTypeGet_ObjectAPI(field.value.type, opts) + "();\n"; + code += " for (var _j = 0; _j < this." + camel_name + + "Length; ++_j) {\n"; + GenUnionUnPack_ObjectAPI(*field.value.type.enum_def, code_ptr, + camel_name, true); + code += " }\n"; + } else if (field.value.type.element != BASE_TYPE_UTYPE) { + auto fixed = field.value.type.struct_def == nullptr; + code += start + "new " + + GenTypeGet_ObjectAPI(field.value.type, opts) + "();\n"; + code += " for (var _j = 0; _j < this." + camel_name + + "Length; ++_j) {"; + code += "_o." + camel_name + ".Add("; + if (fixed) { + code += "this." + camel_name + "(_j)"; + } else { + code += "this." + camel_name + "(_j).HasValue ? this." + + camel_name + "(_j).Value.UnPack() : null"; + } + code += ");}\n"; + } + break; + case BASE_TYPE_UTYPE: break; + case BASE_TYPE_UNION: { + GenUnionUnPack_ObjectAPI(*field.value.type.enum_def, code_ptr, + camel_name, false); + break; + } + default: { + code += start + "this." + camel_name + ";\n"; + break; + } + } + } + code += " }\n"; + // Pack() + code += " public static " + GenOffsetType(struct_def) + + " Pack(FlatBufferBuilder builder, " + struct_name + " _o) {\n"; + code += " if (_o == null) return default(" + GenOffsetType(struct_def) + + ");\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + auto camel_name = MakeCamel(field.name); + // pre + switch (field.value.type.base_type) { + case BASE_TYPE_STRUCT: { + if (!field.value.type.struct_def->fixed) { + code += " var _" + field.name + " = _o." + camel_name + + " == null ? default(" + + GenOffsetType(*field.value.type.struct_def) + + ") : " + GenTypeGet(field.value.type) + + ".Pack(builder, _o." + camel_name + ");\n"; + } else if (struct_def.fixed && struct_has_create) { + std::vector<FieldArrayLength> array_lengths; + FieldArrayLength tmp_array_length = { + field.name, + field.value.type.fixed_length, + }; + array_lengths.push_back(tmp_array_length); + GenStructPackDecl_ObjectAPI(*field.value.type.struct_def, code_ptr, + array_lengths); + } + break; + } + case BASE_TYPE_STRING: { + std::string create_string = + field.shared ? "CreateSharedString" : "CreateString"; + code += " var _" + field.name + " = _o." + camel_name + + " == null ? default(StringOffset) : " + "builder." + + create_string + "(_o." + camel_name + ");\n"; + break; + } + case BASE_TYPE_VECTOR: { + if (field_has_create.find(&field) != field_has_create.end()) { + auto property_name = camel_name; + auto gen_for_loop = true; + std::string array_name = "__" + field.name; + std::string array_type = ""; + std::string to_array = ""; + switch (field.value.type.element) { + case BASE_TYPE_STRING: { + std::string create_string = + field.shared ? "CreateSharedString" : "CreateString"; + array_type = "StringOffset"; + to_array += "builder." + create_string + "(_o." + + property_name + "[_j])"; + break; + } + case BASE_TYPE_STRUCT: + array_type = "Offset<" + GenTypeGet(field.value.type) + ">"; + to_array = GenTypeGet(field.value.type) + ".Pack(builder, _o." + + property_name + "[_j])"; + break; + case BASE_TYPE_UTYPE: + property_name = camel_name.substr(0, camel_name.size() - 4); + array_type = WrapInNameSpace(*field.value.type.enum_def); + to_array = "_o." + property_name + "[_j].Type"; + break; + case BASE_TYPE_UNION: + array_type = "int"; + to_array = WrapInNameSpace(*field.value.type.enum_def) + + "Union.Pack(builder, _o." + property_name + "[_j])"; + break; + default: gen_for_loop = false; break; + } + code += " var _" + field.name + " = default(VectorOffset);\n"; + code += " if (_o." + property_name + " != null) {\n"; + if (gen_for_loop) { + code += " var " + array_name + " = new " + array_type + + "[_o." + property_name + ".Count];\n"; + code += " for (var _j = 0; _j < " + array_name + + ".Length; ++_j) { "; + code += array_name + "[_j] = " + to_array + "; }\n"; + } else { + code += " var " + array_name + " = _o." + property_name + + ".ToArray();\n"; + } + code += " _" + field.name + " = Create" + camel_name + + "Vector(builder, " + array_name + ");\n"; + code += " }\n"; + } else { + auto pack_method = + field.value.type.struct_def == nullptr + ? "builder.Add" + GenMethod(field.value.type.VectorType()) + + "(_o." + camel_name + "[_j]);" + : GenTypeGet(field.value.type) + ".Pack(builder, _o." + + camel_name + "[_j]);"; + code += " var _" + field.name + " = default(VectorOffset);\n"; + code += " if (_o." + camel_name + " != null) {\n"; + code += " Start" + camel_name + "Vector(builder, _o." + + camel_name + ".Count);\n"; + code += " for (var _j = _o." + camel_name + + ".Count - 1; _j >= 0; --_j) { " + pack_method + " }\n"; + code += " _" + field.name + " = builder.EndVector();\n"; + code += " }\n"; + } + break; + } + case BASE_TYPE_ARRAY: { + if (field.value.type.struct_def != nullptr) { + std::vector<FieldArrayLength> array_lengths; + FieldArrayLength tmp_array_length = { + field.name, + field.value.type.fixed_length, + }; + array_lengths.push_back(tmp_array_length); + GenStructPackDecl_ObjectAPI(*field.value.type.struct_def, code_ptr, + array_lengths); + } else { + code += " var _" + field.name + " = _o." + camel_name + ";\n"; + } + break; + } + case BASE_TYPE_UNION: { + code += " var _" + field.name + "_type = _o." + camel_name + + " == null ? " + WrapInNameSpace(*field.value.type.enum_def) + + ".NONE : " + "_o." + camel_name + ".Type;\n"; + code += + " var _" + field.name + " = _o." + camel_name + + " == null ? 0 : " + GenTypeGet_ObjectAPI(field.value.type, opts) + + ".Pack(builder, _o." + camel_name + ");\n"; + break; + } + default: break; + } + } + if (struct_has_create) { + // Create + code += " return Create" + struct_def.name + "(\n"; + code += " builder"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + auto camel_name = MakeCamel(field.name); + switch (field.value.type.base_type) { + case BASE_TYPE_STRUCT: { + if (struct_def.fixed) { + GenStructPackCall_ObjectAPI(*field.value.type.struct_def, + code_ptr, + " _" + field.name + "_"); + } else { + code += ",\n"; + if (field.value.type.struct_def->fixed) { + if (opts.generate_object_based_api) + code += " _o." + camel_name; + else + code += " " + GenTypeGet(field.value.type) + + ".Pack(builder, _o." + camel_name + ")"; + } else { + code += " _" + field.name; + } + } + break; + } + case BASE_TYPE_ARRAY: { + if (field.value.type.struct_def != nullptr) { + GenStructPackCall_ObjectAPI(*field.value.type.struct_def, + code_ptr, + " _" + field.name + "_"); + } else { + code += ",\n"; + code += " _" + field.name; + } + break; + } + case BASE_TYPE_UNION: FLATBUFFERS_FALLTHROUGH(); // fall thru + case BASE_TYPE_UTYPE: FLATBUFFERS_FALLTHROUGH(); // fall thru + case BASE_TYPE_STRING: FLATBUFFERS_FALLTHROUGH(); // fall thru + case BASE_TYPE_VECTOR: { + code += ",\n"; + code += " _" + field.name; + break; + } + default: // scalar + code += ",\n"; + code += " _o." + camel_name; + break; + } + } + code += ");\n"; + } else { + // Start, End + code += " Start" + struct_def.name + "(builder);\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + auto camel_name = MakeCamel(field.name); + switch (field.value.type.base_type) { + case BASE_TYPE_STRUCT: { + if (field.value.type.struct_def->fixed) { + code += " Add" + camel_name + "(builder, " + + GenTypeGet(field.value.type) + ".Pack(builder, _o." + + camel_name + "));\n"; + } else { + code += + " Add" + camel_name + "(builder, _" + field.name + ");\n"; + } + break; + } + case BASE_TYPE_STRING: FLATBUFFERS_FALLTHROUGH(); // fall thru + case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru + case BASE_TYPE_VECTOR: { + code += + " Add" + camel_name + "(builder, _" + field.name + ");\n"; + break; + } + case BASE_TYPE_UTYPE: break; + case BASE_TYPE_UNION: { + code += " Add" + camel_name + "Type(builder, _" + field.name + + "_type);\n"; + code += + " Add" + camel_name + "(builder, _" + field.name + ");\n"; + break; + } + // scalar + default: { + code += + " Add" + camel_name + "(builder, _o." + camel_name + ");\n"; + break; + } + } + } + code += " return End" + struct_def.name + "(builder);\n"; + } + code += " }\n"; + } + + void GenStructPackDecl_ObjectAPI( + const StructDef &struct_def, std::string *code_ptr, + std::vector<FieldArrayLength> &array_lengths) const { + auto &code = *code_ptr; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + auto is_array = IsArray(field.value.type); + const auto &field_type = + is_array ? field.value.type.VectorType() : field.value.type; + FieldArrayLength tmp_array_length = { + field.name, + field_type.fixed_length, + }; + array_lengths.push_back(tmp_array_length); + if (field_type.struct_def != nullptr) { + GenStructPackDecl_ObjectAPI(*field_type.struct_def, code_ptr, + array_lengths); + } else { + std::vector<FieldArrayLength> array_only_lengths; + for (size_t i = 0; i < array_lengths.size(); ++i) { + if (array_lengths[i].length > 0) { + array_only_lengths.push_back(array_lengths[i]); + } + } + std::string name; + for (size_t i = 0; i < array_lengths.size(); ++i) { + name += "_" + array_lengths[i].name; + } + code += " var " + name + " = "; + if (array_only_lengths.size() > 0) { + code += "new " + GenTypeBasic(field_type) + "["; + for (size_t i = 0; i < array_only_lengths.size(); ++i) { + if (i != 0) { code += ","; } + code += NumToString(array_only_lengths[i].length); + } + code += "];\n"; + code += " "; + // initialize array + for (size_t i = 0; i < array_only_lengths.size(); ++i) { + auto idx = "idx" + NumToString(i); + code += "for (var " + idx + " = 0; " + idx + " < " + + NumToString(array_only_lengths[i].length) + "; ++" + idx + + ") {"; + } + for (size_t i = 0; i < array_only_lengths.size(); ++i) { + auto idx = "idx" + NumToString(i); + if (i == 0) { + code += name + "[" + idx; + } else { + code += "," + idx; + } + } + code += "] = _o"; + for (size_t i = 0, j = 0; i < array_lengths.size(); ++i) { + code += "." + MakeCamel(array_lengths[i].name); + if (array_lengths[i].length <= 0) continue; + code += "[idx" + NumToString(j++) + "]"; + } + code += ";"; + for (size_t i = 0; i < array_only_lengths.size(); ++i) { + code += "}"; + } + } else { + code += "_o"; + for (size_t i = 0; i < array_lengths.size(); ++i) { + code += "." + MakeCamel(array_lengths[i].name); + } + code += ";"; + } + code += "\n"; + } + array_lengths.pop_back(); + } + } + + void GenStructPackCall_ObjectAPI(const StructDef &struct_def, + std::string *code_ptr, + std::string prefix) const { + auto &code = *code_ptr; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + const auto &field_type = field.value.type; + if (field_type.struct_def != nullptr) { + GenStructPackCall_ObjectAPI(*field_type.struct_def, code_ptr, + prefix + field.name + "_"); + } else { + code += ",\n"; + code += prefix + field.name; + } + } + } + + std::string GenTypeGet_ObjectAPI(flatbuffers::Type type, + const IDLOptions &opts) const { + auto type_name = GenTypeGet(type); + // Replace to ObjectBaseAPI Type Name + switch (type.base_type) { + case BASE_TYPE_STRUCT: FLATBUFFERS_FALLTHROUGH(); // fall thru + case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru + case BASE_TYPE_VECTOR: { + if (type.struct_def != nullptr) { + auto type_name_length = type.struct_def->name.length(); + auto new_type_name = + GenTypeName_ObjectAPI(type.struct_def->name, opts); + type_name.replace(type_name.length() - type_name_length, + type_name_length, new_type_name); + } else if (type.element == BASE_TYPE_UNION) { + type_name = WrapInNameSpace(*type.enum_def) + "Union"; + } + break; + } + + case BASE_TYPE_UNION: { + type_name = WrapInNameSpace(*type.enum_def) + "Union"; + break; + } + default: break; + } + + switch (type.base_type) { + case BASE_TYPE_ARRAY: { + type_name = type_name + "[]"; + break; + } + case BASE_TYPE_VECTOR: { + type_name = "List<" + type_name + ">"; + break; + } + default: break; + } + return type_name; + } + + void GenStruct_ObjectAPI(StructDef &struct_def, std::string *code_ptr, + const IDLOptions &opts) const { + auto &code = *code_ptr; + if (struct_def.attributes.Lookup("private")) { + code += "internal "; + } else { + code += "public "; + } + if (struct_def.attributes.Lookup("csharp_partial")) { + // generate a partial class for this C# struct/table + code += "partial "; + } + auto class_name = GenTypeName_ObjectAPI(struct_def.name, opts); + code += "class " + class_name; + code += "\n{\n"; + // Generate Properties + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + if (field.value.type.base_type == BASE_TYPE_UTYPE) continue; + if (field.value.type.element == BASE_TYPE_UTYPE) continue; + auto type_name = GenTypeGet_ObjectAPI(field.value.type, opts); + if (field.IsScalarOptional()) type_name += "?"; + auto camel_name = MakeCamel(field.name, true); + if (opts.cs_gen_json_serializer) { + if (IsUnion(field.value.type)) { + auto utype_name = WrapInNameSpace(*field.value.type.enum_def); + code += + " [Newtonsoft.Json.JsonProperty(\"" + field.name + "_type\")]\n"; + if (IsVector(field.value.type)) { + code += " private " + utype_name + "[] " + camel_name + "Type {\n"; + code += " get {\n"; + code += " if (this." + camel_name + " == null) return null;\n"; + code += " var _o = new " + utype_name + "[this." + camel_name + + ".Count];\n"; + code += + " for (var _j = 0; _j < _o.Length; ++_j) { _o[_j] = " + "this." + + camel_name + "[_j].Type; }\n"; + code += " return _o;\n"; + code += " }\n"; + code += " set {\n"; + code += " this." + camel_name + " = new List<" + utype_name + + "Union>();\n"; + code += " for (var _j = 0; _j < value.Length; ++_j) {\n"; + code += " var _o = new " + utype_name + "Union();\n"; + code += " _o.Type = value[_j];\n"; + code += " this." + camel_name + ".Add(_o);\n"; + code += " }\n"; + code += " }\n"; + code += " }\n"; + } else { + code += " private " + utype_name + " " + camel_name + "Type {\n"; + code += " get {\n"; + code += " return this." + camel_name + " != null ? this." + + camel_name + ".Type : " + utype_name + ".NONE;\n"; + code += " }\n"; + code += " set {\n"; + code += " this." + camel_name + " = new " + utype_name + + "Union();\n"; + code += " this." + camel_name + ".Type = value;\n"; + code += " }\n"; + code += " }\n"; + } + } + code += " [Newtonsoft.Json.JsonProperty(\"" + field.name + "\")]\n"; + if (IsUnion(field.value.type)) { + auto union_name = + (IsVector(field.value.type)) + ? GenTypeGet_ObjectAPI(field.value.type.VectorType(), opts) + : type_name; + code += " [Newtonsoft.Json.JsonConverter(typeof(" + union_name + + "_JsonConverter))]\n"; + } + if (field.attributes.Lookup("hash")) { + code += " [Newtonsoft.Json.JsonIgnore()]\n"; + } + } + code += " public " + type_name + " " + camel_name + " { get; set; }\n"; + } + // Generate Constructor + code += "\n"; + code += " public " + class_name + "() {\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + if (field.value.type.base_type == BASE_TYPE_UTYPE) continue; + if (field.value.type.element == BASE_TYPE_UTYPE) continue; + code += " this." + MakeCamel(field.name) + " = "; + auto type_name = GenTypeGet_ObjectAPI(field.value.type, opts); + if (IsScalar(field.value.type.base_type)) { + code += GenDefaultValue(field) + ";\n"; + } else { + switch (field.value.type.base_type) { + case BASE_TYPE_STRUCT: { + if (IsStruct(field.value.type)) { + code += "new " + type_name + "();\n"; + } else { + code += "null;\n"; + } + break; + } + case BASE_TYPE_ARRAY: { + code += "new " + type_name.substr(0, type_name.length() - 1) + + NumToString(field.value.type.fixed_length) + "];\n"; + break; + } + default: { + code += "null;\n"; + break; + } + } + } + } + code += " }\n"; + // Generate Serialization + if (opts.cs_gen_json_serializer && + parser_.root_struct_def_ == &struct_def) { + code += "\n"; + code += " public static " + class_name + + " DeserializeFromJson(string jsonText) {\n"; + code += " return Newtonsoft.Json.JsonConvert.DeserializeObject<" + + class_name + ">(jsonText);\n"; + code += " }\n"; + code += " public string SerializeToJson() {\n"; + code += + " return Newtonsoft.Json.JsonConvert.SerializeObject(this, " + "Newtonsoft.Json.Formatting.Indented);\n"; + code += " }\n"; + } + if (parser_.root_struct_def_ == &struct_def) { + code += " public static " + class_name + + " DeserializeFromBinary(byte[] fbBuffer) {\n"; + code += " return " + struct_def.name + ".GetRootAs" + struct_def.name + + "(new ByteBuffer(fbBuffer)).UnPack();\n"; + code += " }\n"; + code += " public byte[] SerializeToBinary() {\n"; + code += " var fbb = new FlatBufferBuilder(0x10000);\n"; + code += " " + struct_def.name + ".Finish" + struct_def.name + + "Buffer(fbb, " + struct_def.name + ".Pack(fbb, this));\n"; + code += " return fbb.DataBuffer.ToSizedArray();\n"; + code += " }\n"; + } + code += "}\n\n"; + } + + // This tracks the current namespace used to determine if a type need to be + // prefixed by its namespace + const Namespace *cur_name_space_; +}; +} // namespace csharp + +bool GenerateCSharp(const Parser &parser, const std::string &path, + const std::string &file_name) { + csharp::CSharpGenerator generator(parser, path, file_name); + return generator.generate(); +} + +} // namespace flatbuffers diff --git a/contrib/libs/flatbuffers/src/idl_gen_dart.cpp b/contrib/libs/flatbuffers/src/idl_gen_dart.cpp new file mode 100644 index 0000000000..56c4a82555 --- /dev/null +++ b/contrib/libs/flatbuffers/src/idl_gen_dart.cpp @@ -0,0 +1,955 @@ +/* + * Copyright 2018 Dan Field + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// independent from idl_parser, since this code is not needed for most clients +#include <cassert> + +#include "flatbuffers/code_generators.h" +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +namespace flatbuffers { + +namespace dart { + +const std::string _kFb = "fb"; +// see https://www.dartlang.org/guides/language/language-tour#keywords +// yeild*, async*, and sync* shouldn't be problems anyway but keeping them in +static const char *keywords[] = { + "abstract", "deferred", "if", "super", "as", "do", + "implements", "switch", "assert", "dynamic", "import", "sync*", + "async", "else", "in", "this", "async*", "enum", + "is", "throw", "await", "export", "library", "true", + "break", "external", "new", "try", "case", "extends", + "null", "typedef", "catch", "factory", "operator", "var", + "class", "false", "part", "void", "const", "final", + "rethrow", "while", "continue", "finally", "return", "with", + "covariant", "for", "set", "yield", "default", "get", + "static", "yield*" +}; + +// Iterate through all definitions we haven't generate code for (enums, structs, +// and tables) and output them to a single file. +class DartGenerator : public BaseGenerator { + public: + typedef std::map<std::string, std::string> namespace_code_map; + + DartGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name, "", ".", "dart") {} + // Iterate through all definitions we haven't generate code for (enums, + // structs, and tables) and output them to a single file. + bool generate() { + std::string code; + namespace_code_map namespace_code; + GenerateEnums(&namespace_code); + GenerateStructs(&namespace_code); + + for (auto kv = namespace_code.begin(); kv != namespace_code.end(); ++kv) { + code.clear(); + code = code + "// " + FlatBuffersGeneratedWarning() + "\n"; + code = code + + "// ignore_for_file: unused_import, unused_field, " + "unused_local_variable\n\n"; + + if (!kv->first.empty()) { code += "library " + kv->first + ";\n\n"; } + + code += "import 'dart:typed_data' show Uint8List;\n"; + code += "import 'package:flat_buffers/flat_buffers.dart' as " + _kFb + + ";\n\n"; + + for (auto kv2 = namespace_code.begin(); kv2 != namespace_code.end(); + ++kv2) { + if (kv2->first != kv->first) { + code += + "import '" + + GeneratedFileName( + "./", + file_name_ + (!kv2->first.empty() ? "_" + kv2->first : ""), + parser_.opts) + + "' as " + ImportAliasName(kv2->first) + ";\n"; + } + } + code += "\n"; + code += kv->second; + + if (!SaveFile( + GeneratedFileName( + path_, + file_name_ + (!kv->first.empty() ? "_" + kv->first : ""), + parser_.opts) + .c_str(), + code, false)) { + return false; + } + } + return true; + } + + private: + static std::string ImportAliasName(const std::string &ns) { + std::string ret; + ret.assign(ns); + size_t pos = ret.find('.'); + while (pos != std::string::npos) { + ret.replace(pos, 1, "_"); + pos = ret.find('.', pos + 1); + } + + return ret; + } + + static std::string BuildNamespaceName(const Namespace &ns) { + if (ns.components.empty()) { return ""; } + std::stringstream sstream; + std::copy(ns.components.begin(), ns.components.end() - 1, + std::ostream_iterator<std::string>(sstream, ".")); + + auto ret = sstream.str() + ns.components.back(); + for (size_t i = 0; i < ret.size(); i++) { + auto lower = CharToLower(ret[i]); + if (lower != ret[i]) { + ret[i] = lower; + if (i != 0 && ret[i - 1] != '.') { + ret.insert(i, "_"); + i++; + } + } + } + // std::transform(ret.begin(), ret.end(), ret.begin(), CharToLower); + return ret; + } + + void GenIncludeDependencies(std::string *code, + const std::string &the_namespace) { + for (auto it = parser_.included_files_.begin(); + it != parser_.included_files_.end(); ++it) { + if (it->second.empty()) continue; + + auto noext = flatbuffers::StripExtension(it->second); + auto basename = flatbuffers::StripPath(noext); + + *code += + "import '" + + GeneratedFileName( + "", basename + (the_namespace == "" ? "" : "_" + the_namespace), + parser_.opts) + + "';\n"; + } + } + + static std::string EscapeKeyword(const std::string &name) { + for (size_t i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) { + if (name == keywords[i]) { return MakeCamel(name + "_", false); } + } + + return MakeCamel(name, false); + } + + void GenerateEnums(namespace_code_map *namespace_code) { + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + auto &enum_def = **it; + GenEnum(enum_def, namespace_code); // enum_code_ptr); + } + } + + void GenerateStructs(namespace_code_map *namespace_code) { + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + auto &struct_def = **it; + GenStruct(struct_def, namespace_code); + } + } + + // Generate a documentation comment, if available. + static void GenDocComment(const std::vector<std::string> &dc, + std::string *code_ptr, + const std::string &extra_lines, + const char *indent = nullptr) { + if (dc.empty() && extra_lines.empty()) { + // Don't output empty comment blocks with 0 lines of comment content. + return; + } + + auto &code = *code_ptr; + + for (auto it = dc.begin(); it != dc.end(); ++it) { + if (indent) code += indent; + code += "/// " + *it + "\n"; + } + if (!extra_lines.empty()) { + if (!dc.empty()) { + if (indent) code += indent; + code += "///\n"; + } + if (indent) code += indent; + std::string::size_type start = 0; + for (;;) { + auto end = extra_lines.find('\n', start); + if (end != std::string::npos) { + code += "/// " + extra_lines.substr(start, end - start) + "\n"; + start = end + 1; + } else { + code += "/// " + extra_lines.substr(start) + "\n"; + break; + } + } + } + } + + static void GenDocComment(std::string *code_ptr, + const std::string &extra_lines) { + GenDocComment(std::vector<std::string>(), code_ptr, extra_lines); + } + + // Generate an enum declaration and an enum string lookup table. + void GenEnum(EnumDef &enum_def, namespace_code_map *namespace_code) { + if (enum_def.generated) return; + auto ns = BuildNamespaceName(*enum_def.defined_namespace); + std::string code; + GenDocComment(enum_def.doc_comment, &code, ""); + + auto name = enum_def.is_union ? enum_def.name + "TypeId" : enum_def.name; + auto is_bit_flags = enum_def.attributes.Lookup("bit_flags"); + + code += "class " + name + " {\n"; + code += " final int value;\n"; + code += " const " + name + "._(this.value);\n\n"; + code += " factory " + name + ".fromValue(int value) {\n"; + code += " if (value == null) value = 0;\n"; + + code += " if (!values.containsKey(value)) {\n"; + code += + " throw new StateError('Invalid value $value for bit flag enum "; + code += name + "');\n"; + code += " }\n"; + + code += " return values[value];\n"; + code += " }\n\n"; + + // this is meaningless for bit_flags + // however, note that unlike "regular" dart enums this enum can still have + // holes. + if (!is_bit_flags) { + code += " static const int minValue = " + + enum_def.ToString(*enum_def.MinValue()) + ";\n"; + code += " static const int maxValue = " + + enum_def.ToString(*enum_def.MaxValue()) + ";\n"; + } + + code += + " static bool containsValue(int value) =>" + " values.containsKey(value);\n\n"; + + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + auto &ev = **it; + + if (!ev.doc_comment.empty()) { + if (it != enum_def.Vals().begin()) { code += '\n'; } + GenDocComment(ev.doc_comment, &code, "", " "); + } + code += " static const " + name + " " + ev.name + " = "; + code += "const " + name + "._(" + enum_def.ToString(ev) + ");\n"; + } + + code += " static const Map<int," + name + "> values = {"; + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + auto &ev = **it; + code += enum_def.ToString(ev) + ": " + ev.name + ","; + } + code += "};\n\n"; + + code += " static const " + _kFb + ".Reader<" + name + + "> reader = const _" + name + "Reader();\n\n"; + code += " @override\n"; + code += " String toString() {\n"; + code += " return '" + name + "{value: $value}';\n"; + code += " }\n"; + code += "}\n\n"; + + GenEnumReader(enum_def, name, &code); + (*namespace_code)[ns] += code; + } + + void GenEnumReader(EnumDef &enum_def, const std::string &name, + std::string *code_ptr) { + auto &code = *code_ptr; + + code += "class _" + name + "Reader extends " + _kFb + ".Reader<" + name + + "> {\n"; + code += " const _" + name + "Reader();\n\n"; + code += " @override\n"; + code += " int get size => 1;\n\n"; + code += " @override\n"; + code += + " " + name + " read(" + _kFb + ".BufferContext bc, int offset) =>\n"; + code += " new " + name + ".fromValue(const " + _kFb + "." + + GenType(enum_def.underlying_type) + "Reader().read(bc, offset));\n"; + code += "}\n\n"; + } + + static std::string GenType(const Type &type) { + switch (type.base_type) { + case BASE_TYPE_BOOL: return "Bool"; + case BASE_TYPE_CHAR: return "Int8"; + case BASE_TYPE_UTYPE: + case BASE_TYPE_UCHAR: return "Uint8"; + case BASE_TYPE_SHORT: return "Int16"; + case BASE_TYPE_USHORT: return "Uint16"; + case BASE_TYPE_INT: return "Int32"; + case BASE_TYPE_UINT: return "Uint32"; + case BASE_TYPE_LONG: return "Int64"; + case BASE_TYPE_ULONG: return "Uint64"; + case BASE_TYPE_FLOAT: return "Float32"; + case BASE_TYPE_DOUBLE: return "Float64"; + case BASE_TYPE_STRING: return "String"; + case BASE_TYPE_VECTOR: return GenType(type.VectorType()); + case BASE_TYPE_STRUCT: return type.struct_def->name; + case BASE_TYPE_UNION: return type.enum_def->name + "TypeId"; + default: return "Table"; + } + } + + std::string GenReaderTypeName(const Type &type, Namespace *current_namespace, + const FieldDef &def, + bool parent_is_vector = false) { + if (type.base_type == BASE_TYPE_BOOL) { + return "const " + _kFb + ".BoolReader()"; + } else if (IsVector(type)) { + return "const " + _kFb + ".ListReader<" + + GenDartTypeName(type.VectorType(), current_namespace, def) + ">(" + + GenReaderTypeName(type.VectorType(), current_namespace, def, + true) + + ")"; + } else if (IsString(type)) { + return "const " + _kFb + ".StringReader()"; + } + if (IsScalar(type.base_type)) { + if (type.enum_def && parent_is_vector) { + return GenDartTypeName(type, current_namespace, def) + ".reader"; + } + return "const " + _kFb + "." + GenType(type) + "Reader()"; + } else { + return GenDartTypeName(type, current_namespace, def) + ".reader"; + } + } + + std::string GenDartTypeName(const Type &type, Namespace *current_namespace, + const FieldDef &def, bool addBuilder = false) { + if (type.enum_def) { + if (type.enum_def->is_union && type.base_type != BASE_TYPE_UNION) { + return type.enum_def->name + "TypeId"; + } else if (type.enum_def->is_union) { + return "dynamic"; + } else if (type.base_type != BASE_TYPE_VECTOR) { + return type.enum_def->name; + } + } + + switch (type.base_type) { + case BASE_TYPE_BOOL: return "bool"; + case BASE_TYPE_LONG: + case BASE_TYPE_ULONG: + case BASE_TYPE_INT: + case BASE_TYPE_UINT: + case BASE_TYPE_SHORT: + case BASE_TYPE_USHORT: + case BASE_TYPE_CHAR: + case BASE_TYPE_UCHAR: return "int"; + case BASE_TYPE_FLOAT: + case BASE_TYPE_DOUBLE: return "double"; + case BASE_TYPE_STRING: return "String"; + case BASE_TYPE_STRUCT: + return MaybeWrapNamespace( + type.struct_def->name + (addBuilder ? "ObjectBuilder" : ""), + current_namespace, def); + case BASE_TYPE_VECTOR: + return "List<" + + GenDartTypeName(type.VectorType(), current_namespace, def, + addBuilder) + + ">"; + default: assert(0); return "dynamic"; + } + } + + static const std::string MaybeWrapNamespace(const std::string &type_name, + Namespace *current_ns, + const FieldDef &field) { + auto curr_ns_str = BuildNamespaceName(*current_ns); + std::string field_ns_str = ""; + if (field.value.type.struct_def) { + field_ns_str += + BuildNamespaceName(*field.value.type.struct_def->defined_namespace); + } else if (field.value.type.enum_def) { + field_ns_str += + BuildNamespaceName(*field.value.type.enum_def->defined_namespace); + } + + if (field_ns_str != "" && field_ns_str != curr_ns_str) { + return ImportAliasName(field_ns_str) + "." + type_name; + } else { + return type_name; + } + } + + // Generate an accessor struct with constructor for a flatbuffers struct. + void GenStruct(const StructDef &struct_def, + namespace_code_map *namespace_code) { + if (struct_def.generated) return; + + auto object_namespace = BuildNamespaceName(*struct_def.defined_namespace); + std::string code; + + const auto &object_name = struct_def.name; + + // Emit constructor + + GenDocComment(struct_def.doc_comment, &code, ""); + + auto reader_name = "_" + object_name + "Reader"; + auto builder_name = object_name + "Builder"; + auto object_builder_name = object_name + "ObjectBuilder"; + + std::string reader_code, builder_code; + + code += "class " + object_name + " {\n"; + + code += " " + object_name + "._(this._bc, this._bcOffset);\n"; + if (!struct_def.fixed) { + code += " factory " + object_name + "(List<int> bytes) {\n"; + code += " " + _kFb + ".BufferContext rootRef = new " + _kFb + + ".BufferContext.fromBytes(bytes);\n"; + code += " return reader.read(rootRef, 0);\n"; + code += " }\n"; + } + + code += "\n"; + code += " static const " + _kFb + ".Reader<" + object_name + + "> reader = const " + reader_name + "();\n\n"; + + code += " final " + _kFb + ".BufferContext _bc;\n"; + code += " final int _bcOffset;\n\n"; + + std::vector<std::pair<int, FieldDef *>> non_deprecated_fields; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + auto offset = static_cast<int>(it - struct_def.fields.vec.begin()); + non_deprecated_fields.push_back(std::make_pair(offset, &field)); + } + + GenImplementationGetters(struct_def, non_deprecated_fields, &code); + + code += "}\n\n"; + + GenReader(struct_def, &reader_name, &reader_code); + GenBuilder(struct_def, non_deprecated_fields, &builder_name, &builder_code); + GenObjectBuilder(struct_def, non_deprecated_fields, &object_builder_name, + &builder_code); + + code += reader_code; + code += builder_code; + + (*namespace_code)[object_namespace] += code; + } + + std::string NamespaceAliasFromUnionType(Namespace *root_namespace, + const Type &type) { + const std::vector<std::string> qualified_name_parts = + type.struct_def->defined_namespace->components; + if (std::equal(root_namespace->components.begin(), + root_namespace->components.end(), + qualified_name_parts.begin())) { + return type.struct_def->name; + } + + std::string ns; + + for (auto it = qualified_name_parts.begin(); + it != qualified_name_parts.end(); ++it) { + auto &part = *it; + + for (size_t i = 0; i < part.length(); i++) { + if (i && !isdigit(part[i]) && part[i] == CharToUpper(part[i])) { + ns += "_"; + ns += CharToLower(part[i]); + } else { + ns += CharToLower(part[i]); + } + } + if (it != qualified_name_parts.end() - 1) { ns += "_"; } + } + + return ns + "." + type.struct_def->name; + } + + void GenImplementationGetters( + const StructDef &struct_def, + std::vector<std::pair<int, FieldDef *>> non_deprecated_fields, + std::string *code_ptr) { + auto &code = *code_ptr; + + for (auto it = non_deprecated_fields.begin(); + it != non_deprecated_fields.end(); ++it) { + auto pair = *it; + auto &field = *pair.second; + + std::string field_name = MakeCamel(field.name, false); + std::string type_name = GenDartTypeName( + field.value.type, struct_def.defined_namespace, field, false); + + GenDocComment(field.doc_comment, &code, "", " "); + + code += " " + type_name + " get " + field_name; + if (field.value.type.base_type == BASE_TYPE_UNION) { + code += " {\n"; + code += " switch (" + field_name + "Type?.value) {\n"; + auto &enum_def = *field.value.type.enum_def; + for (auto en_it = enum_def.Vals().begin() + 1; + en_it != enum_def.Vals().end(); ++en_it) { + auto &ev = **en_it; + + auto enum_name = NamespaceAliasFromUnionType( + enum_def.defined_namespace, ev.union_type); + code += " case " + enum_def.ToString(ev) + ": return " + + enum_name + ".reader.vTableGet(_bc, _bcOffset, " + + NumToString(field.value.offset) + ", null);\n"; + } + code += " default: return null;\n"; + code += " }\n"; + code += " }\n"; + } else { + code += " => "; + if (field.value.type.enum_def && + field.value.type.base_type != BASE_TYPE_VECTOR) { + code += "new " + + GenDartTypeName(field.value.type, + struct_def.defined_namespace, field) + + ".fromValue("; + } + + code += GenReaderTypeName(field.value.type, + struct_def.defined_namespace, field); + if (struct_def.fixed) { + code += + ".read(_bc, _bcOffset + " + NumToString(field.value.offset) + ")"; + } else { + code += ".vTableGet(_bc, _bcOffset, " + + NumToString(field.value.offset) + ", "; + if (!field.value.constant.empty() && field.value.constant != "0") { + if (IsBool(field.value.type.base_type)) { + code += "true"; + } else if (field.value.constant == "nan" || + field.value.constant == "+nan" || + field.value.constant == "-nan") { + code += "double.nan"; + } else if (field.value.constant == "inf" || + field.value.constant == "+inf") { + code += "double.infinity"; + } else if (field.value.constant == "-inf") { + code += "double.negativeInfinity"; + } else { + code += field.value.constant; + } + } else { + if (IsBool(field.value.type.base_type)) { + code += "false"; + } else if (IsScalar(field.value.type.base_type)) { + code += "0"; + } else { + code += "null"; + } + } + code += ")"; + } + if (field.value.type.enum_def && + field.value.type.base_type != BASE_TYPE_VECTOR) { + code += ")"; + } + code += ";\n"; + } + } + + code += "\n"; + + code += " @override\n"; + code += " String toString() {\n"; + code += " return '" + struct_def.name + "{"; + for (auto it = non_deprecated_fields.begin(); + it != non_deprecated_fields.end(); ++it) { + auto pair = *it; + auto &field = *pair.second; + code += + MakeCamel(field.name, false) + ": $" + MakeCamel(field.name, false); + if (it != non_deprecated_fields.end() - 1) { code += ", "; } + } + code += "}';\n"; + code += " }\n"; + } + + void GenReader(const StructDef &struct_def, std::string *reader_name_ptr, + std::string *code_ptr) { + auto &code = *code_ptr; + auto &reader_name = *reader_name_ptr; + auto &impl_name = struct_def.name; + + code += "class " + reader_name + " extends " + _kFb; + if (struct_def.fixed) { + code += ".StructReader<"; + } else { + code += ".TableReader<"; + } + code += impl_name + "> {\n"; + code += " const " + reader_name + "();\n\n"; + + if (struct_def.fixed) { + code += " @override\n"; + code += " int get size => " + NumToString(struct_def.bytesize) + ";\n\n"; + } + code += " @override\n"; + code += " " + impl_name + + " createObject(fb.BufferContext bc, int offset) => \n new " + + impl_name + "._(bc, offset);\n"; + code += "}\n\n"; + } + + void GenBuilder(const StructDef &struct_def, + std::vector<std::pair<int, FieldDef *>> non_deprecated_fields, + std::string *builder_name_ptr, std::string *code_ptr) { + if (non_deprecated_fields.size() == 0) { return; } + auto &code = *code_ptr; + auto &builder_name = *builder_name_ptr; + + code += "class " + builder_name + " {\n"; + code += " " + builder_name + "(this.fbBuilder) {\n"; + code += " assert(fbBuilder != null);\n"; + code += " }\n\n"; + code += " final " + _kFb + ".Builder fbBuilder;\n\n"; + + if (struct_def.fixed) { + StructBuilderBody(struct_def, non_deprecated_fields, code_ptr); + } else { + TableBuilderBody(struct_def, non_deprecated_fields, code_ptr); + } + + code += "}\n\n"; + } + + void StructBuilderBody( + const StructDef &struct_def, + std::vector<std::pair<int, FieldDef *>> non_deprecated_fields, + std::string *code_ptr) { + auto &code = *code_ptr; + + code += " int finish("; + for (auto it = non_deprecated_fields.begin(); + it != non_deprecated_fields.end(); ++it) { + auto pair = *it; + auto &field = *pair.second; + + if (IsStruct(field.value.type)) { + code += "fb.StructBuilder"; + } else { + code += GenDartTypeName(field.value.type, struct_def.defined_namespace, + field); + } + code += " " + field.name; + if (it != non_deprecated_fields.end() - 1) { code += ", "; } + } + code += ") {\n"; + + for (auto it = non_deprecated_fields.rbegin(); + it != non_deprecated_fields.rend(); ++it) { + auto pair = *it; + auto &field = *pair.second; + + if (field.padding) { + code += " fbBuilder.pad(" + NumToString(field.padding) + ");\n"; + } + + if (IsStruct(field.value.type)) { + code += " " + field.name + "();\n"; + } else { + code += " fbBuilder.put" + GenType(field.value.type) + "("; + code += field.name; + if (field.value.type.enum_def) { code += "?.value"; } + code += ");\n"; + } + } + code += " return fbBuilder.offset;\n"; + code += " }\n\n"; + } + + void TableBuilderBody( + const StructDef &struct_def, + std::vector<std::pair<int, FieldDef *>> non_deprecated_fields, + std::string *code_ptr) { + auto &code = *code_ptr; + + code += " void begin() {\n"; + code += " fbBuilder.startTable();\n"; + code += " }\n\n"; + + for (auto it = non_deprecated_fields.begin(); + it != non_deprecated_fields.end(); ++it) { + auto pair = *it; + auto &field = *pair.second; + auto offset = pair.first; + + if (IsScalar(field.value.type.base_type)) { + code += " int add" + MakeCamel(field.name) + "("; + code += GenDartTypeName(field.value.type, struct_def.defined_namespace, + field); + code += " " + MakeCamel(field.name, false) + ") {\n"; + code += " fbBuilder.add" + GenType(field.value.type) + "(" + + NumToString(offset) + ", "; + code += MakeCamel(field.name, false); + if (field.value.type.enum_def) { code += "?.value"; } + code += ");\n"; + } else if (IsStruct(field.value.type)) { + code += " int add" + MakeCamel(field.name) + "(int offset) {\n"; + code += + " fbBuilder.addStruct(" + NumToString(offset) + ", offset);\n"; + } else { + code += " int add" + MakeCamel(field.name) + "Offset(int offset) {\n"; + code += + " fbBuilder.addOffset(" + NumToString(offset) + ", offset);\n"; + } + code += " return fbBuilder.offset;\n"; + code += " }\n"; + } + + code += "\n"; + code += " int finish() {\n"; + code += " return fbBuilder.endTable();\n"; + code += " }\n"; + } + + void GenObjectBuilder( + const StructDef &struct_def, + std::vector<std::pair<int, FieldDef *>> non_deprecated_fields, + std::string *builder_name_ptr, std::string *code_ptr) { + auto &code = *code_ptr; + auto &builder_name = *builder_name_ptr; + + code += "class " + builder_name + " extends " + _kFb + ".ObjectBuilder {\n"; + for (auto it = non_deprecated_fields.begin(); + it != non_deprecated_fields.end(); ++it) { + auto pair = *it; + auto &field = *pair.second; + + code += " final " + + GenDartTypeName(field.value.type, struct_def.defined_namespace, + field, true) + + " _" + MakeCamel(field.name, false) + ";\n"; + } + code += "\n"; + code += " " + builder_name + "("; + + if (non_deprecated_fields.size() != 0) { + code += "{\n"; + for (auto it = non_deprecated_fields.begin(); + it != non_deprecated_fields.end(); ++it) { + auto pair = *it; + auto &field = *pair.second; + + code += " " + + GenDartTypeName(field.value.type, struct_def.defined_namespace, + field, true) + + " " + MakeCamel(field.name, false) + ",\n"; + } + code += " })\n"; + code += " : "; + for (auto it = non_deprecated_fields.begin(); + it != non_deprecated_fields.end(); ++it) { + auto pair = *it; + auto &field = *pair.second; + + code += "_" + MakeCamel(field.name, false) + " = " + + MakeCamel(field.name, false); + if (it == non_deprecated_fields.end() - 1) { + code += ";\n\n"; + } else { + code += ",\n "; + } + } + } else { + code += ");\n\n"; + } + + code += " /// Finish building, and store into the [fbBuilder].\n"; + code += " @override\n"; + code += " int finish(\n"; + code += " " + _kFb + ".Builder fbBuilder) {\n"; + code += " assert(fbBuilder != null);\n"; + + for (auto it = non_deprecated_fields.begin(); + it != non_deprecated_fields.end(); ++it) { + auto pair = *it; + auto &field = *pair.second; + + if (IsScalar(field.value.type.base_type) || IsStruct(field.value.type)) + continue; + + code += " final int " + MakeCamel(field.name, false) + "Offset"; + if (IsVector(field.value.type)) { + code += + " = _" + MakeCamel(field.name, false) + "?.isNotEmpty == true\n"; + code += " ? fbBuilder.writeList"; + switch (field.value.type.VectorType().base_type) { + case BASE_TYPE_STRING: + code += "(_" + MakeCamel(field.name, false) + + ".map((b) => fbBuilder.writeString(b)).toList())"; + break; + case BASE_TYPE_STRUCT: + if (field.value.type.struct_def->fixed) { + code += "OfStructs(_" + MakeCamel(field.name, false) + ")"; + } else { + code += "(_" + MakeCamel(field.name, false) + + ".map((b) => b.getOrCreateOffset(fbBuilder)).toList())"; + } + break; + default: + code += GenType(field.value.type.VectorType()) + "(_" + + MakeCamel(field.name, false); + if (field.value.type.enum_def) { code += ".map((f) => f.value)"; } + code += ")"; + } + code += "\n : null;\n"; + } else if (IsString(field.value.type)) { + code += " = fbBuilder.writeString(_" + MakeCamel(field.name, false) + + ");\n"; + } else { + code += " = _" + MakeCamel(field.name, false) + + "?.getOrCreateOffset(fbBuilder);\n"; + } + } + + code += "\n"; + if (struct_def.fixed) { + StructObjectBuilderBody(non_deprecated_fields, code_ptr); + } else { + TableObjectBuilderBody(non_deprecated_fields, code_ptr); + } + code += " }\n\n"; + + code += " /// Convenience method to serialize to byte list.\n"; + code += " @override\n"; + code += " Uint8List toBytes([String fileIdentifier]) {\n"; + code += " " + _kFb + ".Builder fbBuilder = new "; + code += _kFb + ".Builder();\n"; + code += " int offset = finish(fbBuilder);\n"; + code += " return fbBuilder.finish(offset, fileIdentifier);\n"; + code += " }\n"; + code += "}\n"; + } + + void StructObjectBuilderBody( + std::vector<std::pair<int, FieldDef *>> non_deprecated_fields, + std::string *code_ptr, bool prependUnderscore = true) { + auto &code = *code_ptr; + + for (auto it = non_deprecated_fields.rbegin(); + it != non_deprecated_fields.rend(); ++it) { + auto pair = *it; + auto &field = *pair.second; + + if (field.padding) { + code += " fbBuilder.pad(" + NumToString(field.padding) + ");\n"; + } + + if (IsStruct(field.value.type)) { + code += " "; + if (prependUnderscore) { code += "_"; } + code += field.name + ".finish(fbBuilder);\n"; + } else { + code += " fbBuilder.put" + GenType(field.value.type) + "("; + if (prependUnderscore) { code += "_"; } + code += field.name; + if (field.value.type.enum_def) { code += "?.value"; } + code += ");\n"; + } + } + + code += " return fbBuilder.offset;\n"; + } + + void TableObjectBuilderBody( + std::vector<std::pair<int, FieldDef *>> non_deprecated_fields, + std::string *code_ptr, bool prependUnderscore = true) { + std::string &code = *code_ptr; + code += " fbBuilder.startTable();\n"; + + for (auto it = non_deprecated_fields.begin(); + it != non_deprecated_fields.end(); ++it) { + auto pair = *it; + auto &field = *pair.second; + auto offset = pair.first; + + if (IsScalar(field.value.type.base_type)) { + code += " fbBuilder.add" + GenType(field.value.type) + "(" + + NumToString(offset) + ", "; + if (prependUnderscore) { code += "_"; } + code += MakeCamel(field.name, false); + if (field.value.type.enum_def) { code += "?.value"; } + code += ");\n"; + } else if (IsStruct(field.value.type)) { + code += " if ("; + if (prependUnderscore) { code += "_"; } + code += MakeCamel(field.name, false) + " != null) {\n"; + code += " fbBuilder.addStruct(" + NumToString(offset) + ", "; + code += "_" + MakeCamel(field.name, false) + ".finish(fbBuilder));\n"; + code += " }\n"; + } else { + code += + " if (" + MakeCamel(field.name, false) + "Offset != null) {\n"; + code += " fbBuilder.addOffset(" + NumToString(offset) + ", " + + MakeCamel(field.name, false) + "Offset);\n"; + code += " }\n"; + } + } + code += " return fbBuilder.endTable();\n"; + } +}; +} // namespace dart + +bool GenerateDart(const Parser &parser, const std::string &path, + const std::string &file_name) { + dart::DartGenerator generator(parser, path, file_name); + return generator.generate(); +} + +std::string DartMakeRule(const Parser &parser, const std::string &path, + const std::string &file_name) { + assert(parser.opts.lang <= IDLOptions::kMAX); + + auto filebase = + flatbuffers::StripPath(flatbuffers::StripExtension(file_name)); + dart::DartGenerator generator(parser, path, file_name); + auto make_rule = + generator.GeneratedFileName(path, file_name, parser.opts) + ": "; + + auto included_files = parser.GetIncludedFilesRecursive(file_name); + for (auto it = included_files.begin(); it != included_files.end(); ++it) { + make_rule += " " + *it; + } + return make_rule; +} + +} // namespace flatbuffers diff --git a/contrib/libs/flatbuffers/src/idl_gen_fbs.cpp b/contrib/libs/flatbuffers/src/idl_gen_fbs.cpp new file mode 100644 index 0000000000..35c1a7d4f5 --- /dev/null +++ b/contrib/libs/flatbuffers/src/idl_gen_fbs.cpp @@ -0,0 +1,154 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// independent from idl_parser, since this code is not needed for most clients + +#include "flatbuffers/code_generators.h" +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +namespace flatbuffers { + +static std::string GenType(const Type &type, bool underlying = false) { + switch (type.base_type) { + case BASE_TYPE_STRUCT: + return type.struct_def->defined_namespace->GetFullyQualifiedName( + type.struct_def->name); + case BASE_TYPE_VECTOR: return "[" + GenType(type.VectorType()) + "]"; + default: + if (type.enum_def && !underlying) { + return type.enum_def->defined_namespace->GetFullyQualifiedName( + type.enum_def->name); + } else { + return kTypeNames[type.base_type]; + } + } +} + +static void GenNameSpace(const Namespace &name_space, std::string *_schema, + const Namespace **last_namespace) { + if (*last_namespace == &name_space) return; + *last_namespace = &name_space; + auto &schema = *_schema; + schema += "namespace "; + for (auto it = name_space.components.begin(); + it != name_space.components.end(); ++it) { + if (it != name_space.components.begin()) schema += "."; + schema += *it; + } + schema += ";\n\n"; +} + +// Generate a flatbuffer schema from the Parser's internal representation. +std::string GenerateFBS(const Parser &parser, const std::string &file_name) { + // Proto namespaces may clash with table names, escape the ones that were + // generated from a table: + for (auto it = parser.namespaces_.begin(); it != parser.namespaces_.end(); + ++it) { + auto &ns = **it; + for (size_t i = 0; i < ns.from_table; i++) { + ns.components[ns.components.size() - 1 - i] += "_"; + } + + if (parser.opts.proto_mode && !parser.opts.proto_namespace_suffix.empty()) { + // Since we know that all these namespaces come from a .proto, and all are + // being converted, we can simply apply this suffix to all of them. + ns.components.insert(ns.components.end() - ns.from_table, + parser.opts.proto_namespace_suffix); + } + } + + std::string schema; + schema += "// Generated from " + file_name + ".proto\n\n"; + if (parser.opts.include_dependence_headers) { + // clang-format off + int num_includes = 0; + for (auto it = parser.included_files_.begin(); + it != parser.included_files_.end(); ++it) { + if (it->second.empty()) + continue; + std::string basename; + if(parser.opts.keep_include_path) { + basename = flatbuffers::StripExtension(it->second); + } else { + basename = flatbuffers::StripPath( + flatbuffers::StripExtension(it->second)); + } + schema += "include \"" + basename + ".fbs\";\n"; + num_includes++; + } + if (num_includes) schema += "\n"; + // clang-format on + } + // Generate code for all the enum declarations. + const Namespace *last_namespace = nullptr; + for (auto enum_def_it = parser.enums_.vec.begin(); + enum_def_it != parser.enums_.vec.end(); ++enum_def_it) { + EnumDef &enum_def = **enum_def_it; + if (parser.opts.include_dependence_headers && enum_def.generated) { + continue; + } + GenNameSpace(*enum_def.defined_namespace, &schema, &last_namespace); + GenComment(enum_def.doc_comment, &schema, nullptr); + if (enum_def.is_union) + schema += "union " + enum_def.name; + else + schema += "enum " + enum_def.name + " : "; + schema += GenType(enum_def.underlying_type, true) + " {\n"; + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + auto &ev = **it; + GenComment(ev.doc_comment, &schema, nullptr, " "); + if (enum_def.is_union) + schema += " " + GenType(ev.union_type) + ",\n"; + else + schema += " " + ev.name + " = " + enum_def.ToString(ev) + ",\n"; + } + schema += "}\n\n"; + } + // Generate code for all structs/tables. + for (auto it = parser.structs_.vec.begin(); it != parser.structs_.vec.end(); + ++it) { + StructDef &struct_def = **it; + if (parser.opts.include_dependence_headers && struct_def.generated) { + continue; + } + GenNameSpace(*struct_def.defined_namespace, &schema, &last_namespace); + GenComment(struct_def.doc_comment, &schema, nullptr); + schema += "table " + struct_def.name + " {\n"; + for (auto field_it = struct_def.fields.vec.begin(); + field_it != struct_def.fields.vec.end(); ++field_it) { + auto &field = **field_it; + if (field.value.type.base_type != BASE_TYPE_UTYPE) { + GenComment(field.doc_comment, &schema, nullptr, " "); + schema += " " + field.name + ":" + GenType(field.value.type); + if (field.value.constant != "0") schema += " = " + field.value.constant; + if (field.IsRequired()) schema += " (required)"; + schema += ";\n"; + } + } + schema += "}\n\n"; + } + return schema; +} + +bool GenerateFBS(const Parser &parser, const std::string &path, + const std::string &file_name) { + return SaveFile((path + file_name + ".fbs").c_str(), + GenerateFBS(parser, file_name), false); +} + +} // namespace flatbuffers diff --git a/contrib/libs/flatbuffers/src/idl_gen_go.cpp b/contrib/libs/flatbuffers/src/idl_gen_go.cpp new file mode 100644 index 0000000000..867f402322 --- /dev/null +++ b/contrib/libs/flatbuffers/src/idl_gen_go.cpp @@ -0,0 +1,1374 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// independent from idl_parser, since this code is not needed for most clients + +#include <sstream> +#include <string> + +#include "flatbuffers/code_generators.h" +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +#ifdef _WIN32 +# include <direct.h> +# define PATH_SEPARATOR "\\" +# define mkdir(n, m) _mkdir(n) +#else +# include <sys/stat.h> +# define PATH_SEPARATOR "/" +#endif + +namespace flatbuffers { + +namespace go { + +// see https://golang.org/ref/spec#Keywords +static const char *const g_golang_keywords[] = { + "break", "default", "func", "interface", "select", "case", "defer", + "go", "map", "struct", "chan", "else", "goto", "package", + "switch", "const", "fallthrough", "if", "range", "type", "continue", + "for", "import", "return", "var", +}; + +static std::string GoIdentity(const std::string &name) { + for (size_t i = 0; + i < sizeof(g_golang_keywords) / sizeof(g_golang_keywords[0]); i++) { + if (name == g_golang_keywords[i]) { return MakeCamel(name + "_", false); } + } + + return MakeCamel(name, false); +} + +class GoGenerator : public BaseGenerator { + public: + GoGenerator(const Parser &parser, const std::string &path, + const std::string &file_name, const std::string &go_namespace) + : BaseGenerator(parser, path, file_name, "" /* not used*/, + "" /* not used */, "go"), + cur_name_space_(nullptr) { + std::istringstream iss(go_namespace); + std::string component; + while (std::getline(iss, component, '.')) { + go_namespace_.components.push_back(component); + } + } + + bool generate() { + std::string one_file_code; + bool needs_imports = false; + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + tracked_imported_namespaces_.clear(); + needs_imports = false; + std::string enumcode; + GenEnum(**it, &enumcode); + if ((*it)->is_union && parser_.opts.generate_object_based_api) { + GenNativeUnion(**it, &enumcode); + GenNativeUnionPack(**it, &enumcode); + GenNativeUnionUnPack(**it, &enumcode); + needs_imports = true; + } + if (parser_.opts.one_file) { + one_file_code += enumcode; + } else { + if (!SaveType(**it, enumcode, needs_imports, true)) return false; + } + } + + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + tracked_imported_namespaces_.clear(); + std::string declcode; + GenStruct(**it, &declcode); + if (parser_.opts.one_file) { + one_file_code += declcode; + } else { + if (!SaveType(**it, declcode, true, false)) return false; + } + } + + if (parser_.opts.one_file) { + std::string code = ""; + const bool is_enum = !parser_.enums_.vec.empty(); + BeginFile(LastNamespacePart(go_namespace_), true, is_enum, &code); + code += one_file_code; + const std::string filename = + GeneratedFileName(path_, file_name_, parser_.opts); + return SaveFile(filename.c_str(), code, false); + } + + return true; + } + + private: + Namespace go_namespace_; + Namespace *cur_name_space_; + + struct NamespacePtrLess { + bool operator()(const Namespace *a, const Namespace *b) const { + return *a < *b; + } + }; + std::set<const Namespace *, NamespacePtrLess> tracked_imported_namespaces_; + + // Most field accessors need to retrieve and test the field offset first, + // this is the prefix code for that. + std::string OffsetPrefix(const FieldDef &field) { + return "{\n\to := flatbuffers.UOffsetT(rcv._tab.Offset(" + + NumToString(field.value.offset) + "))\n\tif o != 0 {\n"; + } + + // Begin a class declaration. + void BeginClass(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + + code += "type " + struct_def.name + " struct {\n\t"; + + // _ is reserved in flatbuffers field names, so no chance of name conflict: + code += "_tab "; + code += struct_def.fixed ? "flatbuffers.Struct" : "flatbuffers.Table"; + code += "\n}\n\n"; + } + + // Construct the name of the type for this enum. + std::string GetEnumTypeName(const EnumDef &enum_def) { + return WrapInNameSpaceAndTrack(enum_def.defined_namespace, + GoIdentity(enum_def.name)); + } + + // Create a type for the enum values. + void GenEnumType(const EnumDef &enum_def, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "type " + GetEnumTypeName(enum_def) + " "; + code += GenTypeBasic(enum_def.underlying_type) + "\n\n"; + } + + // Begin enum code with a class declaration. + void BeginEnum(std::string *code_ptr) { + std::string &code = *code_ptr; + code += "const (\n"; + } + + // A single enum member. + void EnumMember(const EnumDef &enum_def, const EnumVal &ev, + size_t max_name_length, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "\t"; + code += enum_def.name; + code += ev.name; + code += " "; + code += std::string(max_name_length - ev.name.length(), ' '); + code += GetEnumTypeName(enum_def); + code += " = "; + code += enum_def.ToString(ev) + "\n"; + } + + // End enum code. + void EndEnum(std::string *code_ptr) { + std::string &code = *code_ptr; + code += ")\n\n"; + } + + // Begin enum name map. + void BeginEnumNames(const EnumDef &enum_def, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "var EnumNames"; + code += enum_def.name; + code += " = map[" + GetEnumTypeName(enum_def) + "]string{\n"; + } + + // A single enum name member. + void EnumNameMember(const EnumDef &enum_def, const EnumVal &ev, + size_t max_name_length, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "\t"; + code += enum_def.name; + code += ev.name; + code += ": "; + code += std::string(max_name_length - ev.name.length(), ' '); + code += "\""; + code += ev.name; + code += "\",\n"; + } + + // End enum name map. + void EndEnumNames(std::string *code_ptr) { + std::string &code = *code_ptr; + code += "}\n\n"; + } + + // Generate String() method on enum type. + void EnumStringer(const EnumDef &enum_def, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "func (v " + enum_def.name + ") String() string {\n"; + code += "\tif s, ok := EnumNames" + enum_def.name + "[v]; ok {\n"; + code += "\t\treturn s\n"; + code += "\t}\n"; + code += "\treturn \"" + enum_def.name; + code += "(\" + strconv.FormatInt(int64(v), 10) + \")\"\n"; + code += "}\n\n"; + } + + // Begin enum value map. + void BeginEnumValues(const EnumDef &enum_def, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "var EnumValues"; + code += enum_def.name; + code += " = map[string]" + GetEnumTypeName(enum_def) + "{\n"; + } + + // A single enum value member. + void EnumValueMember(const EnumDef &enum_def, const EnumVal &ev, + size_t max_name_length, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "\t\""; + code += ev.name; + code += "\": "; + code += std::string(max_name_length - ev.name.length(), ' '); + code += enum_def.name; + code += ev.name; + code += ",\n"; + } + + // End enum value map. + void EndEnumValues(std::string *code_ptr) { + std::string &code = *code_ptr; + code += "}\n\n"; + } + + // Initialize a new struct or table from existing data. + void NewRootTypeFromBuffer(const StructDef &struct_def, + std::string *code_ptr) { + std::string &code = *code_ptr; + std::string size_prefix[] = { "", "SizePrefixed" }; + + for (int i = 0; i < 2; i++) { + code += "func Get" + size_prefix[i] + "RootAs"; + code += struct_def.name; + code += "(buf []byte, offset flatbuffers.UOffsetT) "; + code += "*" + struct_def.name + ""; + code += " {\n"; + if (i == 0) { + code += "\tn := flatbuffers.GetUOffsetT(buf[offset:])\n"; + } else { + code += + "\tn := " + "flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:])\n"; + } + code += "\tx := &" + struct_def.name + "{}\n"; + if (i == 0) { + code += "\tx.Init(buf, n+offset)\n"; + } else { + code += "\tx.Init(buf, n+offset+flatbuffers.SizeUint32)\n"; + } + code += "\treturn x\n"; + code += "}\n\n"; + } + } + + // Initialize an existing object with other data, to avoid an allocation. + void InitializeExisting(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + + GenReceiver(struct_def, code_ptr); + code += " Init(buf []byte, i flatbuffers.UOffsetT) "; + code += "{\n"; + code += "\trcv._tab.Bytes = buf\n"; + code += "\trcv._tab.Pos = i\n"; + code += "}\n\n"; + } + + // Implement the table accessor + void GenTableAccessor(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + + GenReceiver(struct_def, code_ptr); + code += " Table() flatbuffers.Table "; + code += "{\n"; + + if (struct_def.fixed) { + code += "\treturn rcv._tab.Table\n"; + } else { + code += "\treturn rcv._tab\n"; + } + code += "}\n\n"; + } + + // Get the length of a vector. + void GetVectorLen(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + + GenReceiver(struct_def, code_ptr); + code += " " + MakeCamel(field.name) + "Length("; + code += ") int " + OffsetPrefix(field); + code += "\t\treturn rcv._tab.VectorLen(o)\n\t}\n"; + code += "\treturn 0\n}\n\n"; + } + + // Get a [ubyte] vector as a byte slice. + void GetUByteSlice(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + + GenReceiver(struct_def, code_ptr); + code += " " + MakeCamel(field.name) + "Bytes("; + code += ") []byte " + OffsetPrefix(field); + code += "\t\treturn rcv._tab.ByteVector(o + rcv._tab.Pos)\n\t}\n"; + code += "\treturn nil\n}\n\n"; + } + + // Get the value of a struct's scalar. + void GetScalarFieldOfStruct(const StructDef &struct_def, + const FieldDef &field, std::string *code_ptr) { + std::string &code = *code_ptr; + std::string getter = GenGetter(field.value.type); + GenReceiver(struct_def, code_ptr); + code += " " + MakeCamel(field.name); + code += "() " + TypeName(field) + " {\n"; + code += "\treturn " + + CastToEnum(field.value.type, + getter + "(rcv._tab.Pos + flatbuffers.UOffsetT(" + + NumToString(field.value.offset) + "))"); + code += "\n}\n"; + } + + // Get the value of a table's scalar. + void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + std::string getter = GenGetter(field.value.type); + GenReceiver(struct_def, code_ptr); + code += " " + MakeCamel(field.name); + code += "() " + TypeName(field) + " "; + code += OffsetPrefix(field) + "\t\treturn "; + code += CastToEnum(field.value.type, getter + "(o + rcv._tab.Pos)"); + code += "\n\t}\n"; + code += "\treturn " + GenConstant(field) + "\n"; + code += "}\n\n"; + } + + // Get a struct by initializing an existing struct. + // Specific to Struct. + void GetStructFieldOfStruct(const StructDef &struct_def, + const FieldDef &field, std::string *code_ptr) { + std::string &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += " " + MakeCamel(field.name); + code += "(obj *" + TypeName(field); + code += ") *" + TypeName(field); + code += " {\n"; + code += "\tif obj == nil {\n"; + code += "\t\tobj = new(" + TypeName(field) + ")\n"; + code += "\t}\n"; + code += "\tobj.Init(rcv._tab.Bytes, rcv._tab.Pos+"; + code += NumToString(field.value.offset) + ")"; + code += "\n\treturn obj\n"; + code += "}\n"; + } + + // Get a struct by initializing an existing struct. + // Specific to Table. + void GetStructFieldOfTable(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += " " + MakeCamel(field.name); + code += "(obj *"; + code += TypeName(field); + code += ") *" + TypeName(field) + " " + OffsetPrefix(field); + if (field.value.type.struct_def->fixed) { + code += "\t\tx := o + rcv._tab.Pos\n"; + } else { + code += "\t\tx := rcv._tab.Indirect(o + rcv._tab.Pos)\n"; + } + code += "\t\tif obj == nil {\n"; + code += "\t\t\tobj = new(" + TypeName(field) + ")\n"; + code += "\t\t}\n"; + code += "\t\tobj.Init(rcv._tab.Bytes, x)\n"; + code += "\t\treturn obj\n\t}\n\treturn nil\n"; + code += "}\n\n"; + } + + // Get the value of a string. + void GetStringField(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += " " + MakeCamel(field.name); + code += "() " + TypeName(field) + " "; + code += OffsetPrefix(field) + "\t\treturn " + GenGetter(field.value.type); + code += "(o + rcv._tab.Pos)\n\t}\n\treturn nil\n"; + code += "}\n\n"; + } + + // Get the value of a union from an object. + void GetUnionField(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += " " + MakeCamel(field.name) + "("; + code += "obj " + GenTypePointer(field.value.type) + ") bool "; + code += OffsetPrefix(field); + code += "\t\t" + GenGetter(field.value.type); + code += "(obj, o)\n\t\treturn true\n\t}\n"; + code += "\treturn false\n"; + code += "}\n\n"; + } + + // Get the value of a vector's struct member. + void GetMemberOfVectorOfStruct(const StructDef &struct_def, + const FieldDef &field, std::string *code_ptr) { + std::string &code = *code_ptr; + auto vectortype = field.value.type.VectorType(); + + GenReceiver(struct_def, code_ptr); + code += " " + MakeCamel(field.name); + code += "(obj *" + TypeName(field); + code += ", j int) bool " + OffsetPrefix(field); + code += "\t\tx := rcv._tab.Vector(o)\n"; + code += "\t\tx += flatbuffers.UOffsetT(j) * "; + code += NumToString(InlineSize(vectortype)) + "\n"; + if (!(vectortype.struct_def->fixed)) { + code += "\t\tx = rcv._tab.Indirect(x)\n"; + } + code += "\t\tobj.Init(rcv._tab.Bytes, x)\n"; + code += "\t\treturn true\n\t}\n"; + code += "\treturn false\n"; + code += "}\n\n"; + } + + // Get the value of a vector's non-struct member. + void GetMemberOfVectorOfNonStruct(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + auto vectortype = field.value.type.VectorType(); + + GenReceiver(struct_def, code_ptr); + code += " " + MakeCamel(field.name); + code += "(j int) " + TypeName(field) + " "; + code += OffsetPrefix(field); + code += "\t\ta := rcv._tab.Vector(o)\n"; + code += "\t\treturn " + + CastToEnum(field.value.type, + GenGetter(field.value.type) + + "(a + flatbuffers.UOffsetT(j*" + + NumToString(InlineSize(vectortype)) + "))"); + code += "\n\t}\n"; + if (IsString(vectortype)) { + code += "\treturn nil\n"; + } else if (vectortype.base_type == BASE_TYPE_BOOL) { + code += "\treturn false\n"; + } else { + code += "\treturn 0\n"; + } + code += "}\n\n"; + } + + // Begin the creator function signature. + void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + + if (code.substr(code.length() - 2) != "\n\n") { + // a previous mutate has not put an extra new line + code += "\n"; + } + code += "func Create" + struct_def.name; + code += "(builder *flatbuffers.Builder"; + } + + // Recursively generate arguments for a constructor, to deal with nested + // structs. + void StructBuilderArgs(const StructDef &struct_def, const char *nameprefix, + std::string *code_ptr) { + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (IsStruct(field.value.type)) { + // Generate arguments for a struct inside a struct. To ensure names + // don't clash, and to make it obvious these arguments are constructing + // a nested struct, prefix the name with the field name. + StructBuilderArgs(*field.value.type.struct_def, + (nameprefix + (field.name + "_")).c_str(), code_ptr); + } else { + std::string &code = *code_ptr; + code += std::string(", ") + nameprefix; + code += GoIdentity(field.name); + code += " " + TypeName(field); + } + } + } + + // End the creator function signature. + void EndBuilderArgs(std::string *code_ptr) { + std::string &code = *code_ptr; + code += ") flatbuffers.UOffsetT {\n"; + } + + // Recursively generate struct construction statements and instert manual + // padding. + void StructBuilderBody(const StructDef &struct_def, const char *nameprefix, + std::string *code_ptr) { + std::string &code = *code_ptr; + code += "\tbuilder.Prep(" + NumToString(struct_def.minalign) + ", "; + code += NumToString(struct_def.bytesize) + ")\n"; + for (auto it = struct_def.fields.vec.rbegin(); + it != struct_def.fields.vec.rend(); ++it) { + auto &field = **it; + if (field.padding) + code += "\tbuilder.Pad(" + NumToString(field.padding) + ")\n"; + if (IsStruct(field.value.type)) { + StructBuilderBody(*field.value.type.struct_def, + (nameprefix + (field.name + "_")).c_str(), code_ptr); + } else { + code += "\tbuilder.Prepend" + GenMethod(field) + "("; + code += CastToBaseType(field.value.type, + nameprefix + GoIdentity(field.name)) + + ")\n"; + } + } + } + + void EndBuilderBody(std::string *code_ptr) { + std::string &code = *code_ptr; + code += "\treturn builder.Offset()\n"; + code += "}\n"; + } + + // Get the value of a table's starting offset. + void GetStartOfTable(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "func " + struct_def.name + "Start"; + code += "(builder *flatbuffers.Builder) {\n"; + code += "\tbuilder.StartObject("; + code += NumToString(struct_def.fields.vec.size()); + code += ")\n}\n"; + } + + // Set the value of a table's field. + void BuildFieldOfTable(const StructDef &struct_def, const FieldDef &field, + const size_t offset, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "func " + struct_def.name + "Add" + MakeCamel(field.name); + code += "(builder *flatbuffers.Builder, "; + code += GoIdentity(field.name) + " "; + if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) { + code += "flatbuffers.UOffsetT"; + } else { + code += TypeName(field); + } + code += ") {\n"; + code += "\tbuilder.Prepend"; + code += GenMethod(field) + "Slot("; + code += NumToString(offset) + ", "; + if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) { + code += "flatbuffers.UOffsetT"; + code += "("; + code += GoIdentity(field.name) + ")"; + } else { + code += CastToBaseType(field.value.type, GoIdentity(field.name)); + } + code += ", " + GenConstant(field); + code += ")\n}\n"; + } + + // Set the value of one of the members of a table's vector. + void BuildVectorOfTable(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + code += "func " + struct_def.name + "Start"; + code += MakeCamel(field.name); + code += "Vector(builder *flatbuffers.Builder, numElems int) "; + code += "flatbuffers.UOffsetT {\n\treturn builder.StartVector("; + auto vector_type = field.value.type.VectorType(); + auto alignment = InlineAlignment(vector_type); + auto elem_size = InlineSize(vector_type); + code += NumToString(elem_size); + code += ", numElems, " + NumToString(alignment); + code += ")\n}\n"; + } + + // Get the offset of the end of a table. + void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "func " + struct_def.name + "End"; + code += "(builder *flatbuffers.Builder) flatbuffers.UOffsetT "; + code += "{\n\treturn builder.EndObject()\n}\n"; + } + + // Generate the receiver for function signatures. + void GenReceiver(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "func (rcv *" + struct_def.name + ")"; + } + + // Generate a struct field getter, conditioned on its child type(s). + void GenStructAccessor(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + GenComment(field.doc_comment, code_ptr, nullptr, ""); + if (IsScalar(field.value.type.base_type)) { + if (struct_def.fixed) { + GetScalarFieldOfStruct(struct_def, field, code_ptr); + } else { + GetScalarFieldOfTable(struct_def, field, code_ptr); + } + } else { + switch (field.value.type.base_type) { + case BASE_TYPE_STRUCT: + if (struct_def.fixed) { + GetStructFieldOfStruct(struct_def, field, code_ptr); + } else { + GetStructFieldOfTable(struct_def, field, code_ptr); + } + break; + case BASE_TYPE_STRING: + GetStringField(struct_def, field, code_ptr); + break; + case BASE_TYPE_VECTOR: { + auto vectortype = field.value.type.VectorType(); + if (vectortype.base_type == BASE_TYPE_STRUCT) { + GetMemberOfVectorOfStruct(struct_def, field, code_ptr); + } else { + GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr); + } + break; + } + case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break; + default: FLATBUFFERS_ASSERT(0); + } + } + if (IsVector(field.value.type)) { + GetVectorLen(struct_def, field, code_ptr); + if (field.value.type.element == BASE_TYPE_UCHAR) { + GetUByteSlice(struct_def, field, code_ptr); + } + } + } + + // Mutate the value of a struct's scalar. + void MutateScalarFieldOfStruct(const StructDef &struct_def, + const FieldDef &field, std::string *code_ptr) { + std::string &code = *code_ptr; + std::string type = MakeCamel(GenTypeBasic(field.value.type)); + std::string setter = "rcv._tab.Mutate" + type; + GenReceiver(struct_def, code_ptr); + code += " Mutate" + MakeCamel(field.name); + code += "(n " + TypeName(field) + ") bool {\n\treturn " + setter; + code += "(rcv._tab.Pos+flatbuffers.UOffsetT("; + code += NumToString(field.value.offset) + "), "; + code += CastToBaseType(field.value.type, "n") + ")\n}\n\n"; + } + + // Mutate the value of a table's scalar. + void MutateScalarFieldOfTable(const StructDef &struct_def, + const FieldDef &field, std::string *code_ptr) { + std::string &code = *code_ptr; + std::string type = MakeCamel(GenTypeBasic(field.value.type)); + std::string setter = "rcv._tab.Mutate" + type + "Slot"; + GenReceiver(struct_def, code_ptr); + code += " Mutate" + MakeCamel(field.name); + code += "(n " + TypeName(field) + ") bool {\n\treturn "; + code += setter + "(" + NumToString(field.value.offset) + ", "; + code += CastToBaseType(field.value.type, "n") + ")\n"; + code += "}\n\n"; + } + + // Mutate an element of a vector of scalars. + void MutateElementOfVectorOfNonStruct(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + auto vectortype = field.value.type.VectorType(); + std::string type = MakeCamel(GenTypeBasic(vectortype)); + std::string setter = "rcv._tab.Mutate" + type; + GenReceiver(struct_def, code_ptr); + code += " Mutate" + MakeCamel(field.name); + code += "(j int, n " + TypeName(field) + ") bool "; + code += OffsetPrefix(field); + code += "\t\ta := rcv._tab.Vector(o)\n"; + code += "\t\treturn " + setter + "("; + code += "a+flatbuffers.UOffsetT(j*"; + code += NumToString(InlineSize(vectortype)) + "), "; + code += CastToBaseType(vectortype, "n") + ")\n"; + code += "\t}\n"; + code += "\treturn false\n"; + code += "}\n\n"; + } + + // Generate a struct field setter, conditioned on its child type(s). + void GenStructMutator(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + GenComment(field.doc_comment, code_ptr, nullptr, ""); + if (IsScalar(field.value.type.base_type)) { + if (struct_def.fixed) { + MutateScalarFieldOfStruct(struct_def, field, code_ptr); + } else { + MutateScalarFieldOfTable(struct_def, field, code_ptr); + } + } else if (IsVector(field.value.type)) { + if (IsScalar(field.value.type.element)) { + MutateElementOfVectorOfNonStruct(struct_def, field, code_ptr); + } + } + } + + // Generate table constructors, conditioned on its members' types. + void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) { + GetStartOfTable(struct_def, code_ptr); + + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + + auto offset = it - struct_def.fields.vec.begin(); + BuildFieldOfTable(struct_def, field, offset, code_ptr); + if (IsVector(field.value.type)) { + BuildVectorOfTable(struct_def, field, code_ptr); + } + } + + GetEndOffsetOnTable(struct_def, code_ptr); + } + + // Generate struct or table methods. + void GenStruct(const StructDef &struct_def, std::string *code_ptr) { + if (struct_def.generated) return; + + cur_name_space_ = struct_def.defined_namespace; + + GenComment(struct_def.doc_comment, code_ptr, nullptr); + if (parser_.opts.generate_object_based_api) { + GenNativeStruct(struct_def, code_ptr); + } + BeginClass(struct_def, code_ptr); + if (!struct_def.fixed) { + // Generate a special accessor for the table that has been declared as + // the root type. + NewRootTypeFromBuffer(struct_def, code_ptr); + } + // Generate the Init method that sets the field in a pre-existing + // accessor object. This is to allow object reuse. + InitializeExisting(struct_def, code_ptr); + // Generate _tab accessor + GenTableAccessor(struct_def, code_ptr); + + // Generate struct fields accessors + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + + GenStructAccessor(struct_def, field, code_ptr); + GenStructMutator(struct_def, field, code_ptr); + } + + // Generate builders + if (struct_def.fixed) { + // create a struct constructor function + GenStructBuilder(struct_def, code_ptr); + } else { + // Create a set of functions that allow table construction. + GenTableBuilders(struct_def, code_ptr); + } + } + + void GenNativeStruct(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + + code += "type " + NativeName(struct_def) + " struct {\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const FieldDef &field = **it; + if (field.deprecated) continue; + if (IsScalar(field.value.type.base_type) && + field.value.type.enum_def != nullptr && + field.value.type.enum_def->is_union) + continue; + code += "\t" + MakeCamel(field.name) + " " + + NativeType(field.value.type) + "\n"; + } + code += "}\n\n"; + + if (!struct_def.fixed) { + GenNativeTablePack(struct_def, code_ptr); + GenNativeTableUnPack(struct_def, code_ptr); + } else { + GenNativeStructPack(struct_def, code_ptr); + GenNativeStructUnPack(struct_def, code_ptr); + } + } + + void GenNativeUnion(const EnumDef &enum_def, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "type " + NativeName(enum_def) + " struct {\n"; + code += "\tType " + enum_def.name + "\n"; + code += "\tValue interface{}\n"; + code += "}\n\n"; + } + + void GenNativeUnionPack(const EnumDef &enum_def, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "func (t *" + NativeName(enum_def) + + ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n"; + code += "\tif t == nil {\n\t\treturn 0\n\t}\n"; + + code += "\tswitch t.Type {\n"; + for (auto it2 = enum_def.Vals().begin(); it2 != enum_def.Vals().end(); + ++it2) { + const EnumVal &ev = **it2; + if (ev.IsZero()) continue; + code += "\tcase " + enum_def.name + ev.name + ":\n"; + code += "\t\treturn t.Value.(" + NativeType(ev.union_type) + + ").Pack(builder)\n"; + } + code += "\t}\n"; + code += "\treturn 0\n"; + code += "}\n\n"; + } + + void GenNativeUnionUnPack(const EnumDef &enum_def, std::string *code_ptr) { + std::string &code = *code_ptr; + + code += "func (rcv " + enum_def.name + + ") UnPack(table flatbuffers.Table) *" + NativeName(enum_def) + + " {\n"; + code += "\tswitch rcv {\n"; + + for (auto it2 = enum_def.Vals().begin(); it2 != enum_def.Vals().end(); + ++it2) { + const EnumVal &ev = **it2; + if (ev.IsZero()) continue; + code += "\tcase " + enum_def.name + ev.name + ":\n"; + code += "\t\tx := " + ev.union_type.struct_def->name + "{_tab: table}\n"; + + code += "\t\treturn &" + + WrapInNameSpaceAndTrack(enum_def.defined_namespace, + NativeName(enum_def)) + + "{ Type: " + enum_def.name + ev.name + ", Value: x.UnPack() }\n"; + } + code += "\t}\n"; + code += "\treturn nil\n"; + code += "}\n\n"; + } + + void GenNativeTablePack(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + + code += "func (t *" + NativeName(struct_def) + + ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n"; + code += "\tif t == nil { return 0 }\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const FieldDef &field = **it; + if (field.deprecated) continue; + if (IsScalar(field.value.type.base_type)) continue; + + std::string offset = MakeCamel(field.name, false) + "Offset"; + + if (IsString(field.value.type)) { + code += "\t" + offset + " := builder.CreateString(t." + + MakeCamel(field.name) + ")\n"; + } else if (IsVector(field.value.type) && + field.value.type.element == BASE_TYPE_UCHAR && + field.value.type.enum_def == nullptr) { + code += "\t" + offset + " := flatbuffers.UOffsetT(0)\n"; + code += "\tif t." + MakeCamel(field.name) + " != nil {\n"; + code += "\t\t" + offset + " = builder.CreateByteString(t." + + MakeCamel(field.name) + ")\n"; + code += "\t}\n"; + } else if (IsVector(field.value.type)) { + code += "\t" + offset + " := flatbuffers.UOffsetT(0)\n"; + code += "\tif t." + MakeCamel(field.name) + " != nil {\n"; + std::string length = MakeCamel(field.name, false) + "Length"; + std::string offsets = MakeCamel(field.name, false) + "Offsets"; + code += "\t\t" + length + " := len(t." + MakeCamel(field.name) + ")\n"; + if (field.value.type.element == BASE_TYPE_STRING) { + code += "\t\t" + offsets + " := make([]flatbuffers.UOffsetT, " + + length + ")\n"; + code += "\t\tfor j := 0; j < " + length + "; j++ {\n"; + code += "\t\t\t" + offsets + "[j] = builder.CreateString(t." + + MakeCamel(field.name) + "[j])\n"; + code += "\t\t}\n"; + } else if (field.value.type.element == BASE_TYPE_STRUCT && + !field.value.type.struct_def->fixed) { + code += "\t\t" + offsets + " := make([]flatbuffers.UOffsetT, " + + length + ")\n"; + code += "\t\tfor j := 0; j < " + length + "; j++ {\n"; + code += "\t\t\t" + offsets + "[j] = t." + MakeCamel(field.name) + + "[j].Pack(builder)\n"; + code += "\t\t}\n"; + } + code += "\t\t" + struct_def.name + "Start" + MakeCamel(field.name) + + "Vector(builder, " + length + ")\n"; + code += "\t\tfor j := " + length + " - 1; j >= 0; j-- {\n"; + if (IsScalar(field.value.type.element)) { + code += "\t\t\tbuilder.Prepend" + + MakeCamel(GenTypeBasic(field.value.type.VectorType())) + "(" + + CastToBaseType(field.value.type.VectorType(), + "t." + MakeCamel(field.name) + "[j]") + + ")\n"; + } else if (field.value.type.element == BASE_TYPE_STRUCT && + field.value.type.struct_def->fixed) { + code += "\t\t\tt." + MakeCamel(field.name) + "[j].Pack(builder)\n"; + } else { + code += "\t\t\tbuilder.PrependUOffsetT(" + offsets + "[j])\n"; + } + code += "\t\t}\n"; + code += "\t\t" + offset + " = builder.EndVector(" + length + ")\n"; + code += "\t}\n"; + } else if (field.value.type.base_type == BASE_TYPE_STRUCT) { + if (field.value.type.struct_def->fixed) continue; + code += "\t" + offset + " := t." + MakeCamel(field.name) + + ".Pack(builder)\n"; + } else if (field.value.type.base_type == BASE_TYPE_UNION) { + code += "\t" + offset + " := t." + MakeCamel(field.name) + + ".Pack(builder)\n"; + code += "\t\n"; + } else { + FLATBUFFERS_ASSERT(0); + } + } + code += "\t" + struct_def.name + "Start(builder)\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const FieldDef &field = **it; + if (field.deprecated) continue; + + std::string offset = MakeCamel(field.name, false) + "Offset"; + if (IsScalar(field.value.type.base_type)) { + if (field.value.type.enum_def == nullptr || + !field.value.type.enum_def->is_union) { + code += "\t" + struct_def.name + "Add" + MakeCamel(field.name) + + "(builder, t." + MakeCamel(field.name) + ")\n"; + } + } else { + if (field.value.type.base_type == BASE_TYPE_STRUCT && + field.value.type.struct_def->fixed) { + code += "\t" + offset + " := t." + MakeCamel(field.name) + + ".Pack(builder)\n"; + } else if (field.value.type.enum_def != nullptr && + field.value.type.enum_def->is_union) { + code += "\tif t." + MakeCamel(field.name) + " != nil {\n"; + code += "\t\t" + struct_def.name + "Add" + + MakeCamel(field.name + UnionTypeFieldSuffix()) + + "(builder, t." + MakeCamel(field.name) + ".Type)\n"; + code += "\t}\n"; + } + code += "\t" + struct_def.name + "Add" + MakeCamel(field.name) + + "(builder, " + offset + ")\n"; + } + } + code += "\treturn " + struct_def.name + "End(builder)\n"; + code += "}\n\n"; + } + + void GenNativeTableUnPack(const StructDef &struct_def, + std::string *code_ptr) { + std::string &code = *code_ptr; + + code += "func (rcv *" + struct_def.name + ") UnPackTo(t *" + + NativeName(struct_def) + ") {\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const FieldDef &field = **it; + if (field.deprecated) continue; + std::string field_name_camel = MakeCamel(field.name); + std::string length = MakeCamel(field.name, false) + "Length"; + if (IsScalar(field.value.type.base_type)) { + if (field.value.type.enum_def != nullptr && + field.value.type.enum_def->is_union) + continue; + code += + "\tt." + field_name_camel + " = rcv." + field_name_camel + "()\n"; + } else if (IsString(field.value.type)) { + code += "\tt." + field_name_camel + " = string(rcv." + + field_name_camel + "())\n"; + } else if (IsVector(field.value.type) && + field.value.type.element == BASE_TYPE_UCHAR && + field.value.type.enum_def == nullptr) { + code += "\tt." + field_name_camel + " = rcv." + field_name_camel + + "Bytes()\n"; + } else if (IsVector(field.value.type)) { + code += "\t" + length + " := rcv." + field_name_camel + "Length()\n"; + code += "\tt." + field_name_camel + " = make(" + + NativeType(field.value.type) + ", " + length + ")\n"; + code += "\tfor j := 0; j < " + length + "; j++ {\n"; + if (field.value.type.element == BASE_TYPE_STRUCT) { + code += "\t\tx := " + + WrapInNameSpaceAndTrack(*field.value.type.struct_def) + + "{}\n"; + code += "\t\trcv." + field_name_camel + "(&x, j)\n"; + } + code += "\t\tt." + field_name_camel + "[j] = "; + if (IsScalar(field.value.type.element)) { + code += "rcv." + field_name_camel + "(j)"; + } else if (field.value.type.element == BASE_TYPE_STRING) { + code += "string(rcv." + field_name_camel + "(j))"; + } else if (field.value.type.element == BASE_TYPE_STRUCT) { + code += "x.UnPack()"; + } else { + // TODO(iceboy): Support vector of unions. + FLATBUFFERS_ASSERT(0); + } + code += "\n"; + code += "\t}\n"; + } else if (field.value.type.base_type == BASE_TYPE_STRUCT) { + code += "\tt." + field_name_camel + " = rcv." + field_name_camel + + "(nil).UnPack()\n"; + } else if (field.value.type.base_type == BASE_TYPE_UNION) { + std::string field_table = MakeCamel(field.name, false) + "Table"; + code += "\t" + field_table + " := flatbuffers.Table{}\n"; + code += + "\tif rcv." + MakeCamel(field.name) + "(&" + field_table + ") {\n"; + code += "\t\tt." + field_name_camel + " = rcv." + + MakeCamel(field.name + UnionTypeFieldSuffix()) + "().UnPack(" + + field_table + ")\n"; + code += "\t}\n"; + } else { + FLATBUFFERS_ASSERT(0); + } + } + code += "}\n\n"; + + code += "func (rcv *" + struct_def.name + ") UnPack() *" + + NativeName(struct_def) + " {\n"; + code += "\tif rcv == nil { return nil }\n"; + code += "\tt := &" + NativeName(struct_def) + "{}\n"; + code += "\trcv.UnPackTo(t)\n"; + code += "\treturn t\n"; + code += "}\n\n"; + } + + void GenNativeStructPack(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + + code += "func (t *" + NativeName(struct_def) + + ") Pack(builder *flatbuffers.Builder) flatbuffers.UOffsetT {\n"; + code += "\tif t == nil { return 0 }\n"; + code += "\treturn Create" + struct_def.name + "(builder"; + StructPackArgs(struct_def, "", code_ptr); + code += ")\n"; + code += "}\n"; + } + + void StructPackArgs(const StructDef &struct_def, const char *nameprefix, + std::string *code_ptr) { + std::string &code = *code_ptr; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const FieldDef &field = **it; + if (field.value.type.base_type == BASE_TYPE_STRUCT) { + StructPackArgs(*field.value.type.struct_def, + (nameprefix + MakeCamel(field.name) + ".").c_str(), + code_ptr); + } else { + code += std::string(", t.") + nameprefix + MakeCamel(field.name); + } + } + } + + void GenNativeStructUnPack(const StructDef &struct_def, + std::string *code_ptr) { + std::string &code = *code_ptr; + + code += "func (rcv *" + struct_def.name + ") UnPackTo(t *" + + NativeName(struct_def) + ") {\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const FieldDef &field = **it; + if (field.value.type.base_type == BASE_TYPE_STRUCT) { + code += "\tt." + MakeCamel(field.name) + " = rcv." + + MakeCamel(field.name) + "(nil).UnPack()\n"; + } else { + code += "\tt." + MakeCamel(field.name) + " = rcv." + + MakeCamel(field.name) + "()\n"; + } + } + code += "}\n\n"; + + code += "func (rcv *" + struct_def.name + ") UnPack() *" + + NativeName(struct_def) + " {\n"; + code += "\tif rcv == nil { return nil }\n"; + code += "\tt := &" + NativeName(struct_def) + "{}\n"; + code += "\trcv.UnPackTo(t)\n"; + code += "\treturn t\n"; + code += "}\n\n"; + } + + // Generate enum declarations. + void GenEnum(const EnumDef &enum_def, std::string *code_ptr) { + if (enum_def.generated) return; + + auto max_name_length = MaxNameLength(enum_def); + cur_name_space_ = enum_def.defined_namespace; + + GenComment(enum_def.doc_comment, code_ptr, nullptr); + GenEnumType(enum_def, code_ptr); + BeginEnum(code_ptr); + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + const EnumVal &ev = **it; + GenComment(ev.doc_comment, code_ptr, nullptr, "\t"); + EnumMember(enum_def, ev, max_name_length, code_ptr); + } + EndEnum(code_ptr); + + BeginEnumNames(enum_def, code_ptr); + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + const EnumVal &ev = **it; + EnumNameMember(enum_def, ev, max_name_length, code_ptr); + } + EndEnumNames(code_ptr); + + BeginEnumValues(enum_def, code_ptr); + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + auto &ev = **it; + EnumValueMember(enum_def, ev, max_name_length, code_ptr); + } + EndEnumValues(code_ptr); + + EnumStringer(enum_def, code_ptr); + } + + // Returns the function name that is able to read a value of the given type. + std::string GenGetter(const Type &type) { + switch (type.base_type) { + case BASE_TYPE_STRING: return "rcv._tab.ByteVector"; + case BASE_TYPE_UNION: return "rcv._tab.Union"; + case BASE_TYPE_VECTOR: return GenGetter(type.VectorType()); + default: return "rcv._tab.Get" + MakeCamel(GenTypeBasic(type)); + } + } + + // Returns the method name for use with add/put calls. + std::string GenMethod(const FieldDef &field) { + return IsScalar(field.value.type.base_type) + ? MakeCamel(GenTypeBasic(field.value.type)) + : (IsStruct(field.value.type) ? "Struct" : "UOffsetT"); + } + + std::string GenTypeBasic(const Type &type) { + // clang-format off + static const char *ctypename[] = { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, ...) \ + #GTYPE, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + }; + // clang-format on + return ctypename[type.base_type]; + } + + std::string GenTypePointer(const Type &type) { + switch (type.base_type) { + case BASE_TYPE_STRING: return "[]byte"; + case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType()); + case BASE_TYPE_STRUCT: return WrapInNameSpaceAndTrack(*type.struct_def); + case BASE_TYPE_UNION: + // fall through + default: return "*flatbuffers.Table"; + } + } + + std::string GenTypeGet(const Type &type) { + if (type.enum_def != nullptr) { return GetEnumTypeName(*type.enum_def); } + return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type); + } + + std::string TypeName(const FieldDef &field) { + return GenTypeGet(field.value.type); + } + + // If type is an enum, returns value with a cast to the enum type, otherwise + // returns value as-is. + std::string CastToEnum(const Type &type, std::string value) { + if (type.enum_def == nullptr) { + return value; + } else { + return GenTypeGet(type) + "(" + value + ")"; + } + } + + // If type is an enum, returns value with a cast to the enum base type, + // otherwise returns value as-is. + std::string CastToBaseType(const Type &type, std::string value) { + if (type.enum_def == nullptr) { + return value; + } else { + return GenTypeBasic(type) + "(" + value + ")"; + } + } + + std::string GenConstant(const FieldDef &field) { + switch (field.value.type.base_type) { + case BASE_TYPE_BOOL: + return field.value.constant == "0" ? "false" : "true"; + default: return field.value.constant; + } + } + + std::string NativeName(const StructDef &struct_def) { + return parser_.opts.object_prefix + struct_def.name + + parser_.opts.object_suffix; + } + + std::string NativeName(const EnumDef &enum_def) { + return parser_.opts.object_prefix + enum_def.name + + parser_.opts.object_suffix; + } + + std::string NativeType(const Type &type) { + if (IsScalar(type.base_type)) { + if (type.enum_def == nullptr) { + return GenTypeBasic(type); + } else { + return GetEnumTypeName(*type.enum_def); + } + } else if (IsString(type)) { + return "string"; + } else if (IsVector(type)) { + return "[]" + NativeType(type.VectorType()); + } else if (type.base_type == BASE_TYPE_STRUCT) { + return "*" + WrapInNameSpaceAndTrack(type.struct_def->defined_namespace, + NativeName(*type.struct_def)); + } else if (type.base_type == BASE_TYPE_UNION) { + return "*" + WrapInNameSpaceAndTrack(type.enum_def->defined_namespace, + NativeName(*type.enum_def)); + } + FLATBUFFERS_ASSERT(0); + return std::string(); + } + + // Create a struct with a builder and the struct's arguments. + void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) { + BeginBuilderArgs(struct_def, code_ptr); + StructBuilderArgs(struct_def, "", code_ptr); + EndBuilderArgs(code_ptr); + + StructBuilderBody(struct_def, "", code_ptr); + EndBuilderBody(code_ptr); + } + // Begin by declaring namespace and imports. + void BeginFile(const std::string &name_space_name, const bool needs_imports, + const bool is_enum, std::string *code_ptr) { + std::string &code = *code_ptr; + code = code + + "// Code generated by the FlatBuffers compiler. DO NOT EDIT.\n\n"; + code += "package " + name_space_name + "\n\n"; + if (needs_imports) { + code += "import (\n"; + if (is_enum) { code += "\t\"strconv\"\n\n"; } + if (!parser_.opts.go_import.empty()) { + code += "\tflatbuffers \"" + parser_.opts.go_import + "\"\n"; + } else { + code += "\tflatbuffers \"github.com/google/flatbuffers/go\"\n"; + } + if (tracked_imported_namespaces_.size() > 0) { + code += "\n"; + for (auto it = tracked_imported_namespaces_.begin(); + it != tracked_imported_namespaces_.end(); ++it) { + code += "\t" + NamespaceImportName(*it) + " \"" + + NamespaceImportPath(*it) + "\"\n"; + } + } + code += ")\n\n"; + } else { + if (is_enum) { code += "import \"strconv\"\n\n"; } + } + } + + // Save out the generated code for a Go Table type. + bool SaveType(const Definition &def, const std::string &classcode, + const bool needs_imports, const bool is_enum) { + if (!classcode.length()) return true; + + Namespace &ns = go_namespace_.components.empty() ? *def.defined_namespace + : go_namespace_; + std::string code = ""; + BeginFile(LastNamespacePart(ns), needs_imports, is_enum, &code); + code += classcode; + // Strip extra newlines at end of file to make it gofmt-clean. + while (code.length() > 2 && code.substr(code.length() - 2) == "\n\n") { + code.pop_back(); + } + std::string filename = NamespaceDir(ns) + def.name + ".go"; + return SaveFile(filename.c_str(), code, false); + } + + // Create the full name of the imported namespace (format: A__B__C). + std::string NamespaceImportName(const Namespace *ns) { + std::string s = ""; + for (auto it = ns->components.begin(); it != ns->components.end(); ++it) { + if (s.size() == 0) { + s += *it; + } else { + s += "__" + *it; + } + } + return s; + } + + // Create the full path for the imported namespace (format: A/B/C). + std::string NamespaceImportPath(const Namespace *ns) { + std::string s = ""; + for (auto it = ns->components.begin(); it != ns->components.end(); ++it) { + if (s.size() == 0) { + s += *it; + } else { + s += "/" + *it; + } + } + return s; + } + + // Ensure that a type is prefixed with its go package import name if it is + // used outside of its namespace. + std::string WrapInNameSpaceAndTrack(const Namespace *ns, + const std::string &name) { + if (CurrentNameSpace() == ns) return name; + + tracked_imported_namespaces_.insert(ns); + + std::string import_name = NamespaceImportName(ns); + return import_name + "." + name; + } + + std::string WrapInNameSpaceAndTrack(const Definition &def) { + return WrapInNameSpaceAndTrack(def.defined_namespace, def.name); + } + + const Namespace *CurrentNameSpace() const { return cur_name_space_; } + + static size_t MaxNameLength(const EnumDef &enum_def) { + size_t max = 0; + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + max = std::max((*it)->name.length(), max); + } + return max; + } +}; +} // namespace go + +bool GenerateGo(const Parser &parser, const std::string &path, + const std::string &file_name) { + go::GoGenerator generator(parser, path, file_name, parser.opts.go_namespace); + return generator.generate(); +} + +} // namespace flatbuffers diff --git a/contrib/libs/flatbuffers/src/idl_gen_grpc.cpp b/contrib/libs/flatbuffers/src/idl_gen_grpc.cpp new file mode 100644 index 0000000000..9aea745d4e --- /dev/null +++ b/contrib/libs/flatbuffers/src/idl_gen_grpc.cpp @@ -0,0 +1,557 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// independent from idl_parser, since this code is not needed for most clients + +#include "flatbuffers/code_generators.h" +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" +#include "src/compiler/cpp_generator.h" +#include "src/compiler/go_generator.h" +#include "src/compiler/java_generator.h" +#include "src/compiler/python_generator.h" +#include "src/compiler/swift_generator.h" +#include "src/compiler/ts_generator.h" + +#if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 4512) // C4512: 'class' : assignment operator could +// not be generated +#endif + +namespace flatbuffers { + +class FlatBufMethod : public grpc_generator::Method { + public: + enum Streaming { kNone, kClient, kServer, kBiDi }; + + FlatBufMethod(const RPCCall *method) : method_(method) { + streaming_ = kNone; + auto val = method_->attributes.Lookup("streaming"); + if (val) { + if (val->constant == "client") streaming_ = kClient; + if (val->constant == "server") streaming_ = kServer; + if (val->constant == "bidi") streaming_ = kBiDi; + } + } + + grpc::string GetLeadingComments(const grpc::string) const { return ""; } + + grpc::string GetTrailingComments(const grpc::string) const { return ""; } + + std::vector<grpc::string> GetAllComments() const { + return method_->doc_comment; + } + + std::string name() const { return method_->name; } + + // TODO: This method need to incorporate namespace for C++ side. Other + // language bindings simply don't use this method. + std::string GRPCType(const StructDef &sd) const { + return "flatbuffers::grpc::Message<" + sd.name + ">"; + } + + std::vector<std::string> get_input_namespace_parts() const { + return (*method_->request).defined_namespace->components; + } + + std::string get_input_type_name() const { return (*method_->request).name; } + + std::vector<std::string> get_output_namespace_parts() const { + return (*method_->response).defined_namespace->components; + } + + std::string get_output_type_name() const { return (*method_->response).name; } + + bool get_module_and_message_path_input(grpc::string * /*str*/, + grpc::string /*generator_file_name*/, + bool /*generate_in_pb2_grpc*/, + grpc::string /*import_prefix*/) const { + return true; + } + + bool get_module_and_message_path_output( + grpc::string * /*str*/, grpc::string /*generator_file_name*/, + bool /*generate_in_pb2_grpc*/, grpc::string /*import_prefix*/) const { + return true; + } + + std::string get_fb_builder() const { return "builder"; } + + std::string input_type_name() const { return GRPCType(*method_->request); } + + std::string output_type_name() const { return GRPCType(*method_->response); } + + bool NoStreaming() const { return streaming_ == kNone; } + + bool ClientStreaming() const { return streaming_ == kClient; } + + bool ServerStreaming() const { return streaming_ == kServer; } + + bool BidiStreaming() const { return streaming_ == kBiDi; } + + private: + const RPCCall *method_; + Streaming streaming_; +}; + +class FlatBufService : public grpc_generator::Service { + public: + FlatBufService(const ServiceDef *service) : service_(service) {} + + grpc::string GetLeadingComments(const grpc::string) const { return ""; } + + grpc::string GetTrailingComments(const grpc::string) const { return ""; } + + std::vector<grpc::string> GetAllComments() const { + return service_->doc_comment; + } + + std::vector<grpc::string> namespace_parts() const { + return service_->defined_namespace->components; + } + + std::string name() const { return service_->name; } + bool is_internal() const { + return service_->Definition::attributes.Lookup("private") ? true : false; + } + + int method_count() const { + return static_cast<int>(service_->calls.vec.size()); + } + + std::unique_ptr<const grpc_generator::Method> method(int i) const { + return std::unique_ptr<const grpc_generator::Method>( + new FlatBufMethod(service_->calls.vec[i])); + } + + private: + const ServiceDef *service_; +}; + +class FlatBufPrinter : public grpc_generator::Printer { + public: + FlatBufPrinter(std::string *str, const char indentation_type) + : str_(str), + escape_char_('$'), + indent_(0), + indentation_size_(2), + indentation_type_(indentation_type) {} + + void Print(const std::map<std::string, std::string> &vars, + const char *string_template) { + std::string s = string_template; + // Replace any occurrences of strings in "vars" that are surrounded + // by the escape character by what they're mapped to. + size_t pos; + while ((pos = s.find(escape_char_)) != std::string::npos) { + // Found an escape char, must also find the closing one. + size_t pos2 = s.find(escape_char_, pos + 1); + // If placeholder not closed, ignore. + if (pos2 == std::string::npos) break; + auto it = vars.find(s.substr(pos + 1, pos2 - pos - 1)); + // If unknown placeholder, ignore. + if (it == vars.end()) break; + // Subtitute placeholder. + s.replace(pos, pos2 - pos + 1, it->second); + } + Print(s.c_str()); + } + + void Print(const char *s) { + if (s == nullptr || *s == '\0') { return; } + // Add this string, but for each part separated by \n, add indentation. + for (;;) { + // Current indentation. + str_->insert(str_->end(), indent_ * indentation_size_, indentation_type_); + // See if this contains more than one line. + const char *lf = strchr(s, '\n'); + if (lf) { + (*str_) += std::string(s, lf + 1); + s = lf + 1; + if (!*s) break; // Only continue if there's more lines. + } else { + (*str_) += s; + break; + } + } + } + + void SetIndentationSize(const int size) { + FLATBUFFERS_ASSERT(str_->empty()); + indentation_size_ = size; + } + + void Indent() { indent_++; } + + void Outdent() { + indent_--; + FLATBUFFERS_ASSERT(indent_ >= 0); + } + + private: + std::string *str_; + char escape_char_; + int indent_; + int indentation_size_; + char indentation_type_; +}; + +class FlatBufFile : public grpc_generator::File { + public: + enum Language { + kLanguageGo, + kLanguageCpp, + kLanguageJava, + kLanguagePython, + kLanguageSwift, + kLanguageTS + }; + + FlatBufFile(const Parser &parser, const std::string &file_name, + Language language) + : parser_(parser), file_name_(file_name), language_(language) {} + + FlatBufFile &operator=(const FlatBufFile &); + + grpc::string GetLeadingComments(const grpc::string) const { return ""; } + + grpc::string GetTrailingComments(const grpc::string) const { return ""; } + + std::vector<grpc::string> GetAllComments() const { + return std::vector<grpc::string>(); + } + + std::string filename() const { return file_name_; } + + std::string filename_without_ext() const { + return StripExtension(file_name_); + } + + std::string message_header_ext() const { return "_generated.h"; } + + std::string service_header_ext() const { return ".grpc.fb.h"; } + + std::string package() const { + return parser_.current_namespace_->GetFullyQualifiedName(""); + } + + std::vector<std::string> package_parts() const { + return parser_.current_namespace_->components; + } + + std::string additional_headers() const { + switch (language_) { + case kLanguageCpp: { + return "#include \"flatbuffers/grpc.h\"\n"; + } + case kLanguageGo: { + return "import \"github.com/google/flatbuffers/go\""; + } + case kLanguageJava: { + return "import com.google.flatbuffers.grpc.FlatbuffersUtils;"; + } + case kLanguagePython: { + return ""; + } + case kLanguageSwift: { + return ""; + } + case kLanguageTS: { + return ""; + } + } + return ""; + } + + int service_count() const { + return static_cast<int>(parser_.services_.vec.size()); + } + + std::unique_ptr<const grpc_generator::Service> service(int i) const { + return std::unique_ptr<const grpc_generator::Service>( + new FlatBufService(parser_.services_.vec[i])); + } + + std::unique_ptr<grpc_generator::Printer> CreatePrinter( + std::string *str, const char indentation_type = ' ') const { + return std::unique_ptr<grpc_generator::Printer>( + new FlatBufPrinter(str, indentation_type)); + } + + private: + const Parser &parser_; + const std::string &file_name_; + const Language language_; +}; + +class GoGRPCGenerator : public flatbuffers::BaseGenerator { + public: + GoGRPCGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name, "", "" /*Unused*/, "go"), + parser_(parser), + path_(path), + file_name_(file_name) {} + + bool generate() { + FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageGo); + grpc_go_generator::Parameters p; + p.custom_method_io_type = "flatbuffers.Builder"; + for (int i = 0; i < file.service_count(); i++) { + auto service = file.service(i); + const Definition *def = parser_.services_.vec[i]; + p.package_name = LastNamespacePart(*(def->defined_namespace)); + p.service_prefix = + def->defined_namespace->GetFullyQualifiedName(""); // file.package(); + std::string output = + grpc_go_generator::GenerateServiceSource(&file, service.get(), &p); + std::string filename = + NamespaceDir(*def->defined_namespace) + def->name + "_grpc.go"; + if (!flatbuffers::SaveFile(filename.c_str(), output, false)) return false; + } + return true; + } + + protected: + const Parser &parser_; + const std::string &path_, &file_name_; +}; + +bool GenerateGoGRPC(const Parser &parser, const std::string &path, + const std::string &file_name) { + int nservices = 0; + for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end(); + ++it) { + if (!(*it)->generated) nservices++; + } + if (!nservices) return true; + return GoGRPCGenerator(parser, path, file_name).generate(); +} + +bool GenerateCppGRPC(const Parser &parser, const std::string &path, + const std::string &file_name) { + int nservices = 0; + for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end(); + ++it) { + if (!(*it)->generated) nservices++; + } + if (!nservices) return true; + + grpc_cpp_generator::Parameters generator_parameters; + // TODO(wvo): make the other parameters in this struct configurable. + generator_parameters.use_system_headers = true; + + FlatBufFile fbfile(parser, file_name, FlatBufFile::kLanguageCpp); + + std::string header_code = + grpc_cpp_generator::GetHeaderPrologue(&fbfile, generator_parameters) + + grpc_cpp_generator::GetHeaderIncludes(&fbfile, generator_parameters) + + grpc_cpp_generator::GetHeaderServices(&fbfile, generator_parameters) + + grpc_cpp_generator::GetHeaderEpilogue(&fbfile, generator_parameters); + + std::string source_code = + grpc_cpp_generator::GetSourcePrologue(&fbfile, generator_parameters) + + grpc_cpp_generator::GetSourceIncludes(&fbfile, generator_parameters) + + grpc_cpp_generator::GetSourceServices(&fbfile, generator_parameters) + + grpc_cpp_generator::GetSourceEpilogue(&fbfile, generator_parameters); + + return flatbuffers::SaveFile((path + file_name + ".grpc.fb.h").c_str(), + header_code, false) && + flatbuffers::SaveFile((path + file_name + ".grpc.fb.cc").c_str(), + source_code, false); +} + +class JavaGRPCGenerator : public flatbuffers::BaseGenerator { + public: + JavaGRPCGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name, "", "." /*separator*/, "java") {} + + bool generate() { + FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageJava); + grpc_java_generator::Parameters p; + for (int i = 0; i < file.service_count(); i++) { + auto service = file.service(i); + const Definition *def = parser_.services_.vec[i]; + p.package_name = + def->defined_namespace->GetFullyQualifiedName(""); // file.package(); + std::string output = + grpc_java_generator::GenerateServiceSource(&file, service.get(), &p); + std::string filename = + NamespaceDir(*def->defined_namespace) + def->name + "Grpc.java"; + if (!flatbuffers::SaveFile(filename.c_str(), output, false)) return false; + } + return true; + } +}; + +bool GenerateJavaGRPC(const Parser &parser, const std::string &path, + const std::string &file_name) { + int nservices = 0; + for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end(); + ++it) { + if (!(*it)->generated) nservices++; + } + if (!nservices) return true; + return JavaGRPCGenerator(parser, path, file_name).generate(); +} + +class PythonGRPCGenerator : public flatbuffers::BaseGenerator { + private: + CodeWriter code_; + + public: + PythonGRPCGenerator(const Parser &parser, const std::string &filename) + : BaseGenerator(parser, "", filename, "", "" /*Unused*/, "swift") {} + + bool generate() { + code_.Clear(); + code_ += + "# Generated by the gRPC Python protocol compiler plugin. " + "DO NOT EDIT!\n"; + code_ += "import grpc\n"; + + FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguagePython); + + for (int i = 0; i < file.service_count(); i++) { + auto service = file.service(i); + code_ += grpc_python_generator::Generate(&file, service.get()); + } + const auto final_code = code_.ToString(); + const auto filename = GenerateFileName(); + return SaveFile(filename.c_str(), final_code, false); + } + + std::string GenerateFileName() { + std::string namespace_dir; + auto &namespaces = parser_.namespaces_.back()->components; + for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { + if (it != namespaces.begin()) namespace_dir += kPathSeparator; + namespace_dir += *it; + } + std::string grpc_py_filename = namespace_dir; + if (!namespace_dir.empty()) grpc_py_filename += kPathSeparator; + return grpc_py_filename + file_name_ + "_grpc_fb.py"; + } +}; + +bool GeneratePythonGRPC(const Parser &parser, const std::string & /*path*/, + const std::string &file_name) { + int nservices = 0; + for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end(); + ++it) { + if (!(*it)->generated) nservices++; + } + if (!nservices) return true; + + return PythonGRPCGenerator(parser, file_name).generate(); +} + +class SwiftGRPCGenerator : public flatbuffers::BaseGenerator { + private: + CodeWriter code_; + + public: + SwiftGRPCGenerator(const Parser &parser, const std::string &path, + const std::string &filename) + : BaseGenerator(parser, path, filename, "", "" /*Unused*/, "swift") {} + + bool generate() { + code_.Clear(); + code_ += "// Generated GRPC code for FlatBuffers swift!"; + code_ += grpc_swift_generator::GenerateHeader(); + FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageSwift); + for (int i = 0; i < file.service_count(); i++) { + auto service = file.service(i); + code_ += grpc_swift_generator::Generate(&file, service.get()); + } + const auto final_code = code_.ToString(); + const auto filename = GeneratedFileName(path_, file_name_); + return SaveFile(filename.c_str(), final_code, false); + } + + static std::string GeneratedFileName(const std::string &path, + const std::string &file_name) { + return path + file_name + ".grpc.swift"; + } +}; + +bool GenerateSwiftGRPC(const Parser &parser, const std::string &path, + const std::string &file_name) { + int nservices = 0; + for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end(); + ++it) { + if (!(*it)->generated) nservices++; + } + if (!nservices) return true; + return SwiftGRPCGenerator(parser, path, file_name).generate(); +} + +class TSGRPCGenerator : public flatbuffers::BaseGenerator { + private: + CodeWriter code_; + + public: + TSGRPCGenerator(const Parser &parser, const std::string &path, + const std::string &filename) + : BaseGenerator(parser, path, filename, "", "" /*Unused*/, "ts") {} + + bool generate() { + code_.Clear(); + FlatBufFile file(parser_, file_name_, FlatBufFile::kLanguageTS); + + for (int i = 0; i < file.service_count(); i++) { + auto service = file.service(i); + code_ += grpc_ts_generator::Generate(&file, service.get(), file_name_); + const auto ts_name = GeneratedFileName(path_, file_name_); + if (!SaveFile(ts_name.c_str(), code_.ToString(), false)) return false; + + code_.Clear(); + code_ += grpc_ts_generator::GenerateInterface(&file, service.get(), + file_name_); + const auto ts_interface_name = GeneratedFileName(path_, file_name_, true); + if (!SaveFile(ts_interface_name.c_str(), code_.ToString(), false)) + return false; + } + return true; + } + + static std::string GeneratedFileName(const std::string &path, + const std::string &file_name, + const bool is_interface = false) { + if (is_interface) return path + file_name + "_grpc.d.ts"; + return path + file_name + "_grpc.js"; + } +}; + +bool GenerateTSGRPC(const Parser &parser, const std::string &path, + const std::string &file_name) { + int nservices = 0; + for (auto it = parser.services_.vec.begin(); it != parser.services_.vec.end(); + ++it) { + if (!(*it)->generated) nservices++; + } + if (!nservices) return true; + return TSGRPCGenerator(parser, path, file_name).generate(); +} + +} // namespace flatbuffers + +#if defined(_MSC_VER) +# pragma warning(pop) +#endif diff --git a/contrib/libs/flatbuffers/src/idl_gen_java.cpp b/contrib/libs/flatbuffers/src/idl_gen_java.cpp new file mode 100644 index 0000000000..cfd3a55cdb --- /dev/null +++ b/contrib/libs/flatbuffers/src/idl_gen_java.cpp @@ -0,0 +1,1244 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// independent from idl_parser, since this code is not needed for most clients + +#include "flatbuffers/code_generators.h" +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +#if defined(FLATBUFFERS_CPP98_STL) +# include <cctype> +#endif // defined(FLATBUFFERS_CPP98_STL) + +namespace flatbuffers { +namespace java { + +static TypedFloatConstantGenerator JavaFloatGen("Double.", "Float.", "NaN", + "POSITIVE_INFINITY", + "NEGATIVE_INFINITY"); + +static CommentConfig comment_config = { + "/**", + " *", + " */", +}; + +class JavaGenerator : public BaseGenerator { + public: + JavaGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name, "", ".", "java"), + cur_name_space_(nullptr) {} + + JavaGenerator &operator=(const JavaGenerator &); + bool generate() { + std::string one_file_code; + cur_name_space_ = parser_.current_namespace_; + + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + std::string enumcode; + auto &enum_def = **it; + if (!parser_.opts.one_file) cur_name_space_ = enum_def.defined_namespace; + GenEnum(enum_def, &enumcode); + if (parser_.opts.one_file) { + one_file_code += enumcode; + } else { + if (!SaveType(enum_def.name, *enum_def.defined_namespace, enumcode, + /* needs_includes= */ false)) + return false; + } + } + + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + std::string declcode; + auto &struct_def = **it; + if (!parser_.opts.one_file) + cur_name_space_ = struct_def.defined_namespace; + GenStruct(struct_def, &declcode); + if (parser_.opts.one_file) { + one_file_code += declcode; + } else { + if (!SaveType(struct_def.name, *struct_def.defined_namespace, declcode, + /* needs_includes= */ true)) + return false; + } + } + + if (parser_.opts.one_file) { + return SaveType(file_name_, *parser_.current_namespace_, one_file_code, + /* needs_includes= */ true); + } + return true; + } + + // Save out the generated code for a single class while adding + // declaration boilerplate. + bool SaveType(const std::string &defname, const Namespace &ns, + const std::string &classcode, bool needs_includes) const { + if (!classcode.length()) return true; + + std::string code; + code = "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n"; + + std::string namespace_name = FullNamespace(".", ns); + if (!namespace_name.empty()) { + code += "package " + namespace_name + ";"; + code += "\n\n"; + } + if (needs_includes) { + code += + "import java.nio.*;\nimport java.lang.*;\nimport " + "java.util.*;\nimport com.google.flatbuffers.*;\n"; + if (parser_.opts.gen_nullable) { + code += "\nimport javax.annotation.Nullable;\n"; + } + if (parser_.opts.java_checkerframework) { + code += "\nimport org.checkerframework.dataflow.qual.Pure;\n"; + } + code += "\n"; + } + + code += classcode; + if (!namespace_name.empty()) code += ""; + auto filename = NamespaceDir(ns) + defname + ".java"; + return SaveFile(filename.c_str(), code, false); + } + + const Namespace *CurrentNameSpace() const { return cur_name_space_; } + + std::string GenNullableAnnotation(const Type &t) const { + return parser_.opts.gen_nullable && + !IsScalar(DestinationType(t, true).base_type) && + t.base_type != BASE_TYPE_VECTOR + ? " @Nullable " + : ""; + } + + std::string GenPureAnnotation(const Type &t) const { + return parser_.opts.java_checkerframework && + !IsScalar(DestinationType(t, true).base_type) + ? " @Pure " + : ""; + } + + std::string GenTypeBasic(const Type &type) const { + // clang-format off + static const char * const java_typename[] = { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, ...) \ + #JTYPE, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + }; + // clang-format on + return java_typename[type.base_type]; + } + + std::string GenTypePointer(const Type &type) const { + switch (type.base_type) { + case BASE_TYPE_STRING: return "String"; + case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType()); + case BASE_TYPE_STRUCT: return WrapInNameSpace(*type.struct_def); + case BASE_TYPE_UNION: FLATBUFFERS_FALLTHROUGH(); // else fall thru + default: return "Table"; + } + } + + std::string GenTypeGet(const Type &type) const { + return IsScalar(type.base_type) + ? GenTypeBasic(type) + : (IsArray(type) ? GenTypeGet(type.VectorType()) + : GenTypePointer(type)); + } + + // Find the destination type the user wants to receive the value in (e.g. + // one size higher signed types for unsigned serialized values in Java). + Type DestinationType(const Type &type, bool vectorelem) const { + switch (type.base_type) { + // We use int for both uchar/ushort, since that generally means less + // casting than using short for uchar. + case BASE_TYPE_UCHAR: return Type(BASE_TYPE_INT); + case BASE_TYPE_USHORT: return Type(BASE_TYPE_INT); + case BASE_TYPE_UINT: return Type(BASE_TYPE_LONG); + case BASE_TYPE_ARRAY: + case BASE_TYPE_VECTOR: + if (vectorelem) return DestinationType(type.VectorType(), vectorelem); + FLATBUFFERS_FALLTHROUGH(); // else fall thru + default: return type; + } + } + + std::string GenOffsetType() const { return "int"; } + + std::string GenOffsetConstruct(const std::string &variable_name) const { + return variable_name; + } + + std::string GenVectorOffsetType() const { return "int"; } + + // Generate destination type name + std::string GenTypeNameDest(const Type &type) const { + return GenTypeGet(DestinationType(type, true)); + } + + // Mask to turn serialized value into destination type value. + std::string DestinationMask(const Type &type, bool vectorelem) const { + switch (type.base_type) { + case BASE_TYPE_UCHAR: return " & 0xFF"; + case BASE_TYPE_USHORT: return " & 0xFFFF"; + case BASE_TYPE_UINT: return " & 0xFFFFFFFFL"; + case BASE_TYPE_VECTOR: + if (vectorelem) return DestinationMask(type.VectorType(), vectorelem); + FLATBUFFERS_FALLTHROUGH(); // else fall thru + default: return ""; + } + } + + // Casts necessary to correctly read serialized data + std::string DestinationCast(const Type &type) const { + if (IsSeries(type)) { + return DestinationCast(type.VectorType()); + } else { + // Cast necessary to correctly read serialized unsigned values. + if (type.base_type == BASE_TYPE_UINT) return "(long)"; + } + return ""; + } + + // Cast statements for mutator method parameters. + // In Java, parameters representing unsigned numbers need to be cast down to + // their respective type. For example, a long holding an unsigned int value + // would be cast down to int before being put onto the buffer. + std::string SourceCast(const Type &type, bool castFromDest) const { + if (IsSeries(type)) { + return SourceCast(type.VectorType(), castFromDest); + } else { + if (castFromDest) { + if (type.base_type == BASE_TYPE_UINT) + return "(int)"; + else if (type.base_type == BASE_TYPE_USHORT) + return "(short)"; + else if (type.base_type == BASE_TYPE_UCHAR) + return "(byte)"; + } + } + return ""; + } + + std::string SourceCast(const Type &type) const { + return SourceCast(type, true); + } + + std::string SourceCastBasic(const Type &type, bool castFromDest) const { + return IsScalar(type.base_type) ? SourceCast(type, castFromDest) : ""; + } + + std::string SourceCastBasic(const Type &type) const { + return SourceCastBasic(type, true); + } + + std::string GenEnumDefaultValue(const FieldDef &field) const { + auto &value = field.value; + FLATBUFFERS_ASSERT(value.type.enum_def); + auto &enum_def = *value.type.enum_def; + auto enum_val = enum_def.FindByValue(value.constant); + return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name) + : value.constant; + } + + std::string GenDefaultValue(const FieldDef &field) const { + auto &value = field.value; + auto constant = field.IsScalarOptional() ? "0" : value.constant; + auto longSuffix = "L"; + switch (value.type.base_type) { + case BASE_TYPE_BOOL: return constant == "0" ? "false" : "true"; + case BASE_TYPE_ULONG: { + // Converts the ulong into its bits signed equivalent + uint64_t defaultValue = StringToUInt(constant.c_str()); + return NumToString(static_cast<int64_t>(defaultValue)) + longSuffix; + } + case BASE_TYPE_UINT: + case BASE_TYPE_LONG: return constant + longSuffix; + default: + if (IsFloat(value.type.base_type)) { + if (field.IsScalarOptional()) { + return value.type.base_type == BASE_TYPE_DOUBLE ? "0.0" : "0f"; + } + return JavaFloatGen.GenFloatConstant(field); + } else { + return constant; + } + } + } + + std::string GenDefaultValueBasic(const FieldDef &field) const { + auto &value = field.value; + if (!IsScalar(value.type.base_type)) { return "0"; } + return GenDefaultValue(field); + } + + void GenEnum(EnumDef &enum_def, std::string *code_ptr) const { + std::string &code = *code_ptr; + if (enum_def.generated) return; + + // Generate enum definitions of the form: + // public static (final) int name = value; + // In Java, we use ints rather than the Enum feature, because we want them + // to map directly to how they're used in C/C++ and file formats. + // That, and Java Enums are expensive, and not universally liked. + GenComment(enum_def.doc_comment, code_ptr, &comment_config); + + if (enum_def.attributes.Lookup("private")) { + // For Java, we leave the enum unmarked to indicate package-private + } else { + code += "public "; + } + code += "final class " + enum_def.name; + code += " {\n"; + code += " private " + enum_def.name + "() { }\n"; + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + auto &ev = **it; + GenComment(ev.doc_comment, code_ptr, &comment_config, " "); + code += " public static final "; + code += GenTypeBasic(DestinationType(enum_def.underlying_type, false)); + code += " "; + code += ev.name + " = "; + code += enum_def.ToString(ev); + code += ";\n"; + } + + // Generate a generate string table for enum values. + // Problem is, if values are very sparse that could generate really big + // tables. Ideally in that case we generate a map lookup instead, but for + // the moment we simply don't output a table at all. + auto range = enum_def.Distance(); + // Average distance between values above which we consider a table + // "too sparse". Change at will. + static const uint64_t kMaxSparseness = 5; + if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) { + code += "\n public static final String"; + code += "[] names = { "; + auto val = enum_def.Vals().front(); + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); + ++it) { + auto ev = *it; + for (auto k = enum_def.Distance(val, ev); k > 1; --k) code += "\"\", "; + val = ev; + code += "\"" + (*it)->name + "\", "; + } + code += "};\n\n"; + code += " public static "; + code += "String"; + code += " " + MakeCamel("name", false); + code += "(int e) { return names[e"; + if (enum_def.MinValue()->IsNonZero()) + code += " - " + enum_def.MinValue()->name; + code += "]; }\n"; + } + + // Close the class + code += "}\n\n"; + } + + // Returns the function name that is able to read a value of the given type. + std::string GenGetter(const Type &type) const { + switch (type.base_type) { + case BASE_TYPE_STRING: return "__string"; + case BASE_TYPE_STRUCT: return "__struct"; + case BASE_TYPE_UNION: return "__union"; + case BASE_TYPE_VECTOR: return GenGetter(type.VectorType()); + case BASE_TYPE_ARRAY: return GenGetter(type.VectorType()); + default: { + std::string getter = "bb.get"; + if (type.base_type == BASE_TYPE_BOOL) { + getter = "0!=" + getter; + } else if (GenTypeBasic(type) != "byte") { + getter += MakeCamel(GenTypeBasic(type)); + } + return getter; + } + } + } + + // Returns the function name that is able to read a value of the given type. + std::string GenGetterForLookupByKey(flatbuffers::FieldDef *key_field, + const std::string &data_buffer, + const char *num = nullptr) const { + auto type = key_field->value.type; + auto dest_mask = DestinationMask(type, true); + auto dest_cast = DestinationCast(type); + auto getter = data_buffer + ".get"; + if (GenTypeBasic(type) != "byte") { + getter += MakeCamel(GenTypeBasic(type)); + } + getter = dest_cast + getter + "(" + GenOffsetGetter(key_field, num) + ")" + + dest_mask; + return getter; + } + + // Direct mutation is only allowed for scalar fields. + // Hence a setter method will only be generated for such fields. + std::string GenSetter(const Type &type) const { + if (IsScalar(type.base_type)) { + std::string setter = "bb.put"; + if (GenTypeBasic(type) != "byte" && type.base_type != BASE_TYPE_BOOL) { + setter += MakeCamel(GenTypeBasic(type)); + } + return setter; + } else { + return ""; + } + } + + // Returns the method name for use with add/put calls. + std::string GenMethod(const Type &type) const { + return IsScalar(type.base_type) ? MakeCamel(GenTypeBasic(type)) + : (IsStruct(type) ? "Struct" : "Offset"); + } + + // Recursively generate arguments for a constructor, to deal with nested + // structs. + void GenStructArgs(const StructDef &struct_def, std::string *code_ptr, + const char *nameprefix, size_t array_count = 0) const { + std::string &code = *code_ptr; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + const auto &field_type = field.value.type; + const auto array_field = IsArray(field_type); + const auto &type = array_field ? field_type.VectorType() + : DestinationType(field_type, false); + const auto array_cnt = array_field ? (array_count + 1) : array_count; + if (IsStruct(type)) { + // Generate arguments for a struct inside a struct. To ensure names + // don't clash, and to make it obvious these arguments are constructing + // a nested struct, prefix the name with the field name. + GenStructArgs(*field_type.struct_def, code_ptr, + (nameprefix + (field.name + "_")).c_str(), array_cnt); + } else { + code += ", "; + code += GenTypeBasic(type); + for (size_t i = 0; i < array_cnt; i++) code += "[]"; + code += " "; + code += nameprefix; + code += MakeCamel(field.name, false); + } + } + } + + // Recusively generate struct construction statements of the form: + // builder.putType(name); + // and insert manual padding. + void GenStructBody(const StructDef &struct_def, std::string *code_ptr, + const char *nameprefix, size_t index = 0, + bool in_array = false) const { + std::string &code = *code_ptr; + std::string indent((index + 1) * 2, ' '); + code += indent + " builder.prep("; + code += NumToString(struct_def.minalign) + ", "; + code += NumToString(struct_def.bytesize) + ");\n"; + for (auto it = struct_def.fields.vec.rbegin(); + it != struct_def.fields.vec.rend(); ++it) { + auto &field = **it; + const auto &field_type = field.value.type; + if (field.padding) { + code += indent + " builder.pad("; + code += NumToString(field.padding) + ");\n"; + } + if (IsStruct(field_type)) { + GenStructBody(*field_type.struct_def, code_ptr, + (nameprefix + (field.name + "_")).c_str(), index, + in_array); + } else { + const auto &type = + IsArray(field_type) ? field_type.VectorType() : field_type; + const auto index_var = "_idx" + NumToString(index); + if (IsArray(field_type)) { + code += indent + " for (int " + index_var + " = "; + code += NumToString(field_type.fixed_length); + code += "; " + index_var + " > 0; " + index_var + "--) {\n"; + in_array = true; + } + if (IsStruct(type)) { + GenStructBody(*field_type.struct_def, code_ptr, + (nameprefix + (field.name + "_")).c_str(), index + 1, + in_array); + } else { + code += IsArray(field_type) ? " " : ""; + code += indent + " builder.put"; + code += GenMethod(type) + "("; + code += SourceCast(type); + auto argname = nameprefix + MakeCamel(field.name, false); + code += argname; + size_t array_cnt = index + (IsArray(field_type) ? 1 : 0); + for (size_t i = 0; in_array && i < array_cnt; i++) { + code += "[_idx" + NumToString(i) + "-1]"; + } + code += ");\n"; + } + if (IsArray(field_type)) { code += indent + " }\n"; } + } + } + } + + std::string GenByteBufferLength(const char *bb_name) const { + std::string bb_len = bb_name; + bb_len += ".capacity()"; + return bb_len; + } + + std::string GenOffsetGetter(flatbuffers::FieldDef *key_field, + const char *num = nullptr) const { + std::string key_offset = ""; + key_offset += "__offset(" + NumToString(key_field->value.offset) + ", "; + if (num) { + key_offset += num; + key_offset += ", _bb)"; + } else { + key_offset += GenByteBufferLength("bb"); + key_offset += " - tableOffset, bb)"; + } + return key_offset; + } + + std::string GenLookupKeyGetter(flatbuffers::FieldDef *key_field) const { + std::string key_getter = " "; + key_getter += "int tableOffset = "; + key_getter += "__indirect(vectorLocation + 4 * (start + middle)"; + key_getter += ", bb);\n "; + if (IsString(key_field->value.type)) { + key_getter += "int comp = "; + key_getter += "compareStrings("; + key_getter += GenOffsetGetter(key_field); + key_getter += ", byteKey, bb);\n"; + } else { + auto get_val = GenGetterForLookupByKey(key_field, "bb"); + key_getter += GenTypeNameDest(key_field->value.type) + " val = "; + key_getter += get_val + ";\n"; + key_getter += " int comp = val > key ? 1 : val < key ? -1 : 0;\n"; + } + return key_getter; + } + + std::string GenKeyGetter(flatbuffers::FieldDef *key_field) const { + std::string key_getter = ""; + auto data_buffer = "_bb"; + if (IsString(key_field->value.type)) { + key_getter += " return "; + key_getter += ""; + key_getter += "compareStrings("; + key_getter += GenOffsetGetter(key_field, "o1") + ", "; + key_getter += GenOffsetGetter(key_field, "o2") + ", " + data_buffer + ")"; + key_getter += ";"; + } else { + auto field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o1"); + key_getter += + "\n " + GenTypeNameDest(key_field->value.type) + " val_1 = "; + key_getter += + field_getter + ";\n " + GenTypeNameDest(key_field->value.type); + key_getter += " val_2 = "; + field_getter = GenGetterForLookupByKey(key_field, data_buffer, "o2"); + key_getter += field_getter + ";\n"; + key_getter += " return val_1 > val_2 ? 1 : val_1 < val_2 ? -1 : 0;\n "; + } + return key_getter; + } + + void GenStruct(StructDef &struct_def, std::string *code_ptr) const { + if (struct_def.generated) return; + std::string &code = *code_ptr; + + // Generate a struct accessor class, with methods of the form: + // public type name() { return bb.getType(i + offset); } + // or for tables of the form: + // public type name() { + // int o = __offset(offset); return o != 0 ? bb.getType(o + i) : default; + // } + GenComment(struct_def.doc_comment, code_ptr, &comment_config); + + if (parser_.opts.gen_generated) { + code += "@javax.annotation.Generated(value=\"flatc\")\n"; + } + code += "@SuppressWarnings(\"unused\")\n"; + if (struct_def.attributes.Lookup("private")) { + // For Java, we leave the struct unmarked to indicate package-private + } else { + code += "public "; + } + code += "final class " + struct_def.name; + code += " extends "; + code += struct_def.fixed ? "Struct" : "Table"; + code += " {\n"; + + if (!struct_def.fixed) { + // Generate verson check method. + // Force compile time error if not using the same version runtime. + code += " public static void ValidateVersion() {"; + code += " Constants."; + code += "FLATBUFFERS_2_0_0(); "; + code += "}\n"; + + // Generate a special accessor for the table that when used as the root + // of a FlatBuffer + std::string method_name = "getRootAs" + struct_def.name; + std::string method_signature = + " public static " + struct_def.name + " " + method_name; + + // create convenience method that doesn't require an existing object + code += method_signature + "(ByteBuffer _bb) "; + code += "{ return " + method_name + "(_bb, new " + struct_def.name + + "()); }\n"; + + // create method that allows object reuse + code += + method_signature + "(ByteBuffer _bb, " + struct_def.name + " obj) { "; + code += "_bb.order(ByteOrder.LITTLE_ENDIAN); "; + code += "return (obj.__assign(_bb.getInt(_bb."; + code += "position()"; + code += ") + _bb."; + code += "position()"; + code += ", _bb)); }\n"; + if (parser_.root_struct_def_ == &struct_def) { + if (parser_.file_identifier_.length()) { + // Check if a buffer has the identifier. + code += " public static "; + code += "boolean " + struct_def.name; + code += "BufferHasIdentifier(ByteBuffer _bb) { return "; + code += "__has_identifier(_bb, \""; + code += parser_.file_identifier_; + code += "\"); }\n"; + } + } + } + // Generate the __init method that sets the field in a pre-existing + // accessor object. This is to allow object reuse. + code += " public void __init(int _i, ByteBuffer _bb) "; + code += "{ "; + code += "__reset(_i, _bb); "; + code += "}\n"; + code += + " public " + struct_def.name + " __assign(int _i, ByteBuffer _bb) "; + code += "{ __init(_i, _bb); return this; }\n\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + GenComment(field.doc_comment, code_ptr, &comment_config, " "); + std::string type_name = GenTypeGet(field.value.type); + std::string type_name_dest = GenTypeNameDest(field.value.type); + std::string conditional_cast = ""; + std::string optional = ""; + std::string dest_mask = DestinationMask(field.value.type, true); + std::string dest_cast = DestinationCast(field.value.type); + std::string src_cast = SourceCast(field.value.type); + std::string method_start = + " public " + + (field.IsRequired() ? "" : GenNullableAnnotation(field.value.type)) + + GenPureAnnotation(field.value.type) + type_name_dest + optional + + " " + MakeCamel(field.name, false); + std::string obj = "obj"; + + // Most field accessors need to retrieve and test the field offset first, + // this is the prefix code for that: + auto offset_prefix = + IsArray(field.value.type) + ? " { return " + : (" { int o = __offset(" + NumToString(field.value.offset) + + "); return o != 0 ? "); + // Generate the accessors that don't do object reuse. + if (field.value.type.base_type == BASE_TYPE_STRUCT) { + // Calls the accessor that takes an accessor object with a new object. + code += method_start + "() { return "; + code += MakeCamel(field.name, false); + code += "(new "; + code += type_name + "()); }\n"; + } else if (IsVector(field.value.type) && + field.value.type.element == BASE_TYPE_STRUCT) { + // Accessors for vectors of structs also take accessor objects, this + // generates a variant without that argument. + code += method_start + "(int j) { return "; + code += MakeCamel(field.name, false); + code += "(new " + type_name + "(), j); }\n"; + } + + if (field.IsScalarOptional()) { code += GenOptionalScalarCheck(field); } + std::string getter = dest_cast + GenGetter(field.value.type); + code += method_start; + std::string default_cast = ""; + std::string member_suffix = "; "; + if (IsScalar(field.value.type.base_type)) { + code += "()"; + member_suffix += ""; + if (struct_def.fixed) { + code += " { return " + getter; + code += "(bb_pos + "; + code += NumToString(field.value.offset) + ")"; + code += dest_mask; + } else { + code += offset_prefix + getter; + code += "(o + bb_pos)" + dest_mask; + code += " : " + default_cast; + code += GenDefaultValue(field); + } + } else { + switch (field.value.type.base_type) { + case BASE_TYPE_STRUCT: + code += "(" + type_name + " obj)"; + if (struct_def.fixed) { + code += " { return " + obj + ".__assign("; + code += "bb_pos + " + NumToString(field.value.offset) + ", "; + code += "bb)"; + } else { + code += offset_prefix + conditional_cast; + code += obj + ".__assign("; + code += field.value.type.struct_def->fixed + ? "o + bb_pos" + : "__indirect(o + bb_pos)"; + code += ", bb) : null"; + } + break; + case BASE_TYPE_STRING: + code += "()"; + member_suffix += ""; + code += offset_prefix + getter + "(o + "; + code += "bb_pos) : null"; + break; + case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru + case BASE_TYPE_VECTOR: { + auto vectortype = field.value.type.VectorType(); + code += "("; + if (vectortype.base_type == BASE_TYPE_STRUCT) { + code += type_name + " obj, "; + getter = obj + ".__assign"; + } else if (vectortype.base_type == BASE_TYPE_UNION) { + code += type_name + " obj, "; + } + code += "int j)"; + const auto body = offset_prefix + conditional_cast + getter + "("; + if (vectortype.base_type == BASE_TYPE_UNION) { + code += body + "obj, "; + } else { + code += body; + } + std::string index; + if (IsArray(field.value.type)) { + index += "bb_pos + " + NumToString(field.value.offset) + " + "; + } else { + index += "__vector(o) + "; + } + index += "j * " + NumToString(InlineSize(vectortype)); + if (vectortype.base_type == BASE_TYPE_STRUCT) { + code += vectortype.struct_def->fixed + ? index + : "__indirect(" + index + ")"; + code += ", bb"; + } else { + code += index; + } + code += ")" + dest_mask; + if (!IsArray(field.value.type)) { + code += " : "; + code += + field.value.type.element == BASE_TYPE_BOOL + ? "false" + : (IsScalar(field.value.type.element) ? default_cast + "0" + : "null"); + } + + break; + } + case BASE_TYPE_UNION: + code += "(" + type_name + " obj)" + offset_prefix + getter; + code += "(obj, o + bb_pos) : null"; + break; + default: FLATBUFFERS_ASSERT(0); + } + } + code += member_suffix; + code += "}\n"; + if (IsVector(field.value.type)) { + code += " public int " + MakeCamel(field.name, false); + code += "Length"; + code += "()"; + code += offset_prefix; + code += "__vector_len(o) : 0; "; + code += ""; + code += "}\n"; + // See if we should generate a by-key accessor. + if (field.value.type.element == BASE_TYPE_STRUCT && + !field.value.type.struct_def->fixed) { + auto &sd = *field.value.type.struct_def; + auto &fields = sd.fields.vec; + for (auto kit = fields.begin(); kit != fields.end(); ++kit) { + auto &key_field = **kit; + if (key_field.key) { + auto qualified_name = WrapInNameSpace(sd); + code += " public " + qualified_name + " "; + code += MakeCamel(field.name, false) + "ByKey("; + code += GenTypeNameDest(key_field.value.type) + " key)"; + code += offset_prefix; + code += qualified_name + ".__lookup_by_key("; + code += "null, "; + code += "__vector(o), key, "; + code += "bb) : null; "; + code += "}\n"; + code += " public " + qualified_name + " "; + code += MakeCamel(field.name, false) + "ByKey("; + code += qualified_name + " obj, "; + code += GenTypeNameDest(key_field.value.type) + " key)"; + code += offset_prefix; + code += qualified_name + ".__lookup_by_key(obj, "; + code += "__vector(o), key, "; + code += "bb) : null; "; + code += "}\n"; + break; + } + } + } + } + // Generate the accessors for vector of structs with vector access object + if (IsVector(field.value.type)) { + std::string vector_type_name; + const auto &element_base_type = field.value.type.VectorType().base_type; + if (IsScalar(element_base_type)) { + vector_type_name = MakeCamel(type_name, true) + "Vector"; + } else if (element_base_type == BASE_TYPE_STRING) { + vector_type_name = "StringVector"; + } else if (element_base_type == BASE_TYPE_UNION) { + vector_type_name = "UnionVector"; + } else { + vector_type_name = type_name + ".Vector"; + } + auto vector_method_start = GenNullableAnnotation(field.value.type) + + " public " + vector_type_name + optional + + " " + MakeCamel(field.name, false) + + "Vector"; + code += vector_method_start + "() { return "; + code += MakeCamel(field.name, false) + "Vector"; + code += "(new " + vector_type_name + "()); }\n"; + code += vector_method_start + "(" + vector_type_name + " obj)"; + code += offset_prefix + conditional_cast + obj + ".__assign("; + code += "__vector(o), "; + if (!IsScalar(element_base_type)) { + auto vectortype = field.value.type.VectorType(); + code += NumToString(InlineSize(vectortype)) + ", "; + } + code += "bb) : null" + member_suffix + "}\n"; + } + // Generate a ByteBuffer accessor for strings & vectors of scalars. + if ((IsVector(field.value.type) && + IsScalar(field.value.type.VectorType().base_type)) || + IsString(field.value.type)) { + code += " public ByteBuffer "; + code += MakeCamel(field.name, false); + code += "AsByteBuffer() { return "; + code += "__vector_as_bytebuffer("; + code += NumToString(field.value.offset) + ", "; + code += NumToString(IsString(field.value.type) + ? 1 + : InlineSize(field.value.type.VectorType())); + code += "); }\n"; + code += " public ByteBuffer "; + code += MakeCamel(field.name, false); + code += "InByteBuffer(ByteBuffer _bb) { return "; + code += "__vector_in_bytebuffer(_bb, "; + code += NumToString(field.value.offset) + ", "; + code += NumToString(IsString(field.value.type) + ? 1 + : InlineSize(field.value.type.VectorType())); + code += "); }\n"; + } + // generate object accessors if is nested_flatbuffer + if (field.nested_flatbuffer) { + auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer); + auto nested_method_name = + MakeCamel(field.name, false) + "As" + field.nested_flatbuffer->name; + auto get_nested_method_name = nested_method_name; + code += " public " + nested_type_name + " "; + code += nested_method_name + "() { return "; + code += + get_nested_method_name + "(new " + nested_type_name + "()); }\n"; + code += " public " + nested_type_name + " "; + code += get_nested_method_name + "("; + code += nested_type_name + " obj"; + code += ") { int o = __offset("; + code += NumToString(field.value.offset) + "); "; + code += "return o != 0 ? " + conditional_cast + obj + ".__assign("; + code += ""; + code += "__indirect(__vector(o)), "; + code += "bb) : null; }\n"; + } + // Generate mutators for scalar fields or vectors of scalars. + if (parser_.opts.mutable_buffer) { + auto is_series = (IsSeries(field.value.type)); + const auto &underlying_type = + is_series ? field.value.type.VectorType() : field.value.type; + // Boolean parameters have to be explicitly converted to byte + // representation. + auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL + ? "(byte)(" + field.name + " ? 1 : 0)" + : field.name; + auto mutator_prefix = MakeCamel("mutate", false); + // A vector mutator also needs the index of the vector element it should + // mutate. + auto mutator_params = (is_series ? "(int j, " : "(") + + GenTypeNameDest(underlying_type) + " " + + field.name + ") { "; + auto setter_index = + is_series + ? (IsArray(field.value.type) + ? "bb_pos + " + NumToString(field.value.offset) + : "__vector(o)") + + +" + j * " + NumToString(InlineSize(underlying_type)) + : (struct_def.fixed + ? "bb_pos + " + NumToString(field.value.offset) + : "o + bb_pos"); + if (IsScalar(underlying_type.base_type) && !IsUnion(field.value.type)) { + code += " public "; + code += struct_def.fixed ? "void " : "boolean "; + code += mutator_prefix + MakeCamel(field.name, true); + code += mutator_params; + if (struct_def.fixed) { + code += GenSetter(underlying_type) + "(" + setter_index + ", "; + code += src_cast + setter_parameter + "); }\n"; + } else { + code += "int o = __offset("; + code += NumToString(field.value.offset) + ");"; + code += " if (o != 0) { " + GenSetter(underlying_type); + code += "(" + setter_index + ", " + src_cast + setter_parameter + + "); return true; } else { return false; } }\n"; + } + } + } + if (parser_.opts.java_primitive_has_method && + IsScalar(field.value.type.base_type) && !struct_def.fixed) { + auto vt_offset_constant = " public static final int VT_" + + MakeScreamingCamel(field.name) + " = " + + NumToString(field.value.offset) + ";"; + + code += vt_offset_constant; + code += "\n"; + } + } + code += "\n"; + flatbuffers::FieldDef *key_field = nullptr; + if (struct_def.fixed) { + // create a struct constructor function + code += " public static " + GenOffsetType() + " "; + code += "create"; + code += struct_def.name + "(FlatBufferBuilder builder"; + GenStructArgs(struct_def, code_ptr, ""); + code += ") {\n"; + GenStructBody(struct_def, code_ptr, ""); + code += " return "; + code += GenOffsetConstruct("builder." + std::string("offset()")); + code += ";\n }\n"; + } else { + // Generate a method that creates a table in one go. This is only possible + // when the table has no struct fields, since those have to be created + // inline, and there's no way to do so in Java. + bool has_no_struct_fields = true; + int num_fields = 0; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + if (IsStruct(field.value.type)) { + has_no_struct_fields = false; + } else { + num_fields++; + } + } + // JVM specifications restrict default constructor params to be < 255. + // Longs and doubles take up 2 units, so we set the limit to be < 127. + if (has_no_struct_fields && num_fields && num_fields < 127) { + // Generate a table constructor of the form: + // public static int createName(FlatBufferBuilder builder, args...) + code += " public static " + GenOffsetType() + " "; + code += "create" + struct_def.name; + code += "(FlatBufferBuilder builder"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + code += ",\n "; + code += GenTypeBasic(DestinationType(field.value.type, false)); + code += " "; + code += field.name; + if (!IsScalar(field.value.type.base_type)) code += "Offset"; + } + code += ") {\n builder."; + code += "startTable("; + code += NumToString(struct_def.fields.vec.size()) + ");\n"; + for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1; + size; size /= 2) { + for (auto it = struct_def.fields.vec.rbegin(); + it != struct_def.fields.vec.rend(); ++it) { + auto &field = **it; + if (!field.deprecated && + (!struct_def.sortbysize || + size == SizeOf(field.value.type.base_type))) { + code += " " + struct_def.name + "."; + code += "add"; + code += MakeCamel(field.name) + "(builder, " + field.name; + if (!IsScalar(field.value.type.base_type)) code += "Offset"; + code += ");\n"; + } + } + } + code += " return " + struct_def.name + "."; + code += "end" + struct_def.name; + code += "(builder);\n }\n\n"; + } + // Generate a set of static methods that allow table construction, + // of the form: + // public static void addName(FlatBufferBuilder builder, short name) + // { builder.addShort(id, name, default); } + // Unlike the Create function, these always work. + code += " public static void start"; + code += struct_def.name; + code += "(FlatBufferBuilder builder) { builder."; + code += "startTable("; + code += NumToString(struct_def.fields.vec.size()) + "); }\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + if (field.key) key_field = &field; + code += " public static void add"; + code += MakeCamel(field.name); + code += "(FlatBufferBuilder builder, "; + code += GenTypeBasic(DestinationType(field.value.type, false)); + auto argname = MakeCamel(field.name, false); + if (!IsScalar(field.value.type.base_type)) argname += "Offset"; + code += " " + argname + ") { builder.add"; + code += GenMethod(field.value.type) + "("; + code += NumToString(it - struct_def.fields.vec.begin()) + ", "; + code += SourceCastBasic(field.value.type); + code += argname; + code += ", "; + code += SourceCastBasic(field.value.type); + code += GenDefaultValue(field); + code += "); }\n"; + if (IsVector(field.value.type)) { + auto vector_type = field.value.type.VectorType(); + auto alignment = InlineAlignment(vector_type); + auto elem_size = InlineSize(vector_type); + if (!IsStruct(vector_type)) { + // generate a method to create a vector from a java array. + if ((vector_type.base_type == BASE_TYPE_CHAR || + vector_type.base_type == BASE_TYPE_UCHAR)) { + // Handle byte[] and ByteBuffers separately for Java + code += " public static " + GenVectorOffsetType() + " "; + code += "create"; + code += MakeCamel(field.name); + code += "Vector(FlatBufferBuilder builder, byte[] data) "; + code += "{ return builder.createByteVector(data); }\n"; + + code += " public static " + GenVectorOffsetType() + " "; + code += "create"; + code += MakeCamel(field.name); + code += "Vector(FlatBufferBuilder builder, ByteBuffer data) "; + code += "{ return builder.createByteVector(data); }\n"; + } else { + code += " public static " + GenVectorOffsetType() + " "; + code += "create"; + code += MakeCamel(field.name); + code += "Vector(FlatBufferBuilder builder, "; + code += GenTypeBasic(vector_type) + "[] data) "; + code += "{ builder.startVector("; + code += NumToString(elem_size); + code += ", data.length, "; + code += NumToString(alignment); + code += "); for (int i = data."; + code += "length - 1; i >= 0; i--) builder."; + code += "add"; + code += GenMethod(vector_type); + code += "("; + code += SourceCastBasic(vector_type, false); + code += "data[i]"; + code += "); return "; + code += "builder.endVector(); }\n"; + } + } + // Generate a method to start a vector, data to be added manually + // after. + code += " public static void start"; + code += MakeCamel(field.name); + code += "Vector(FlatBufferBuilder builder, int numElems) "; + code += "{ builder.startVector("; + code += NumToString(elem_size); + code += ", numElems, " + NumToString(alignment); + code += "); }\n"; + } + } + code += " public static " + GenOffsetType() + " "; + code += "end" + struct_def.name; + code += "(FlatBufferBuilder builder) {\n int o = builder."; + code += "endTable();\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (!field.deprecated && field.IsRequired()) { + code += " builder.required(o, "; + code += NumToString(field.value.offset); + code += "); // " + field.name + "\n"; + } + } + code += " return " + GenOffsetConstruct("o") + ";\n }\n"; + if (parser_.root_struct_def_ == &struct_def) { + std::string size_prefix[] = { "", "SizePrefixed" }; + for (int i = 0; i < 2; ++i) { + code += " public static void "; + code += "finish" + size_prefix[i] + struct_def.name; + code += "Buffer(FlatBufferBuilder builder, " + GenOffsetType(); + code += " offset) {"; + code += " builder.finish" + size_prefix[i] + "(offset"; + + if (parser_.file_identifier_.length()) + code += ", \"" + parser_.file_identifier_ + "\""; + code += "); }\n"; + } + } + } + // Only generate key compare function for table, + // because `key_field` is not set for struct + if (struct_def.has_key && !struct_def.fixed) { + FLATBUFFERS_ASSERT(key_field); + code += "\n @Override\n protected int keysCompare("; + code += "Integer o1, Integer o2, ByteBuffer _bb) {"; + code += GenKeyGetter(key_field); + code += " }\n"; + + code += "\n public static " + struct_def.name; + code += " __lookup_by_key("; + code += struct_def.name + " obj, "; + code += "int vectorLocation, "; + code += GenTypeNameDest(key_field->value.type); + code += " key, ByteBuffer bb) {\n"; + if (IsString(key_field->value.type)) { + code += " byte[] byteKey = "; + code += "key.getBytes(java.nio.charset.StandardCharsets.UTF_8);\n"; + } + code += " int span = "; + code += "bb.getInt(vectorLocation - 4);\n"; + code += " int start = 0;\n"; + code += " while (span != 0) {\n"; + code += " int middle = span / 2;\n"; + code += GenLookupKeyGetter(key_field); + code += " if (comp > 0) {\n"; + code += " span = middle;\n"; + code += " } else if (comp < 0) {\n"; + code += " middle++;\n"; + code += " start += middle;\n"; + code += " span -= middle;\n"; + code += " } else {\n"; + code += " return "; + code += "(obj == null ? new " + struct_def.name + "() : obj)"; + code += ".__assign(tableOffset, bb);\n"; + code += " }\n }\n"; + code += " return null;\n"; + code += " }\n"; + } + GenVectorAccessObject(struct_def, code_ptr); + code += "}"; + code += "\n\n"; + } + + std::string GenOptionalScalarCheck(FieldDef &field) const { + if (!field.IsScalarOptional()) return ""; + return " public boolean has" + MakeCamel(field.name, true) + + "() { return 0 != __offset(" + NumToString(field.value.offset) + + "); }\n"; + } + + void GenVectorAccessObject(StructDef &struct_def, + std::string *code_ptr) const { + auto &code = *code_ptr; + // Generate a vector of structs accessor class. + code += "\n"; + code += " "; + if (!struct_def.attributes.Lookup("private")) code += "public "; + code += "static "; + code += "final "; + code += "class Vector extends "; + code += "BaseVector {\n"; + + // Generate the __assign method that sets the field in a pre-existing + // accessor object. This is to allow object reuse. + std::string method_indent = " "; + code += method_indent + "public Vector "; + code += "__assign(int _vector, int _element_size, ByteBuffer _bb) { "; + code += "__reset(_vector, _element_size, _bb); return this; }\n\n"; + + auto type_name = struct_def.name; + auto method_start = method_indent + "public " + type_name + " get"; + // Generate the accessors that don't do object reuse. + code += method_start + "(int j) { return get"; + code += "(new " + type_name + "(), j); }\n"; + code += method_start + "(" + type_name + " obj, int j) { "; + code += " return obj.__assign("; + std::string index = "__element(j)"; + code += struct_def.fixed ? index : "__indirect(" + index + ", bb)"; + code += ", bb); }\n"; + // See if we should generate a by-key accessor. + if (!struct_def.fixed) { + auto &fields = struct_def.fields.vec; + for (auto kit = fields.begin(); kit != fields.end(); ++kit) { + auto &key_field = **kit; + if (key_field.key) { + auto nullable_annotation = + parser_.opts.gen_nullable ? "@Nullable " : ""; + code += method_indent + nullable_annotation; + code += "public " + type_name + " "; + code += "getByKey("; + code += GenTypeNameDest(key_field.value.type) + " key) { "; + code += " return __lookup_by_key(null, "; + code += "__vector(), key, "; + code += "bb); "; + code += "}\n"; + code += method_indent + nullable_annotation; + code += "public " + type_name + " "; + code += "getByKey("; + code += type_name + " obj, "; + code += GenTypeNameDest(key_field.value.type) + " key) { "; + code += " return __lookup_by_key(obj, "; + code += "__vector(), key, "; + code += "bb); "; + code += "}\n"; + break; + } + } + } + code += " }\n"; + } + + // This tracks the current namespace used to determine if a type need to be + // prefixed by its namespace + const Namespace *cur_name_space_; +}; +} // namespace java + +bool GenerateJava(const Parser &parser, const std::string &path, + const std::string &file_name) { + java::JavaGenerator generator(parser, path, file_name); + return generator.generate(); +} + +} // namespace flatbuffers diff --git a/contrib/libs/flatbuffers/src/idl_gen_json_schema.cpp b/contrib/libs/flatbuffers/src/idl_gen_json_schema.cpp new file mode 100644 index 0000000000..d58bb84976 --- /dev/null +++ b/contrib/libs/flatbuffers/src/idl_gen_json_schema.cpp @@ -0,0 +1,292 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <iostream> + +#include "flatbuffers/code_generators.h" +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +namespace flatbuffers { + +namespace jsons { + +template<class T> std::string GenFullName(const T *enum_def) { + std::string full_name; + const auto &name_spaces = enum_def->defined_namespace->components; + for (auto ns = name_spaces.cbegin(); ns != name_spaces.cend(); ++ns) { + full_name.append(*ns + "_"); + } + full_name.append(enum_def->name); + return full_name; +} + +template<class T> std::string GenTypeRef(const T *enum_def) { + return "\"$ref\" : \"#/definitions/" + GenFullName(enum_def) + "\""; +} + +std::string GenType(const std::string &name) { + return "\"type\" : \"" + name + "\""; +} + +std::string GenType(BaseType type) { + switch (type) { + case BASE_TYPE_BOOL: return "\"type\" : \"boolean\""; + case BASE_TYPE_CHAR: + return "\"type\" : \"integer\", \"minimum\" : " + + NumToString(std::numeric_limits<int8_t>::min()) + + ", \"maximum\" : " + + NumToString(std::numeric_limits<int8_t>::max()); + case BASE_TYPE_UCHAR: + return "\"type\" : \"integer\", \"minimum\" : 0, \"maximum\" :" + + NumToString(std::numeric_limits<uint8_t>::max()); + case BASE_TYPE_SHORT: + return "\"type\" : \"integer\", \"minimum\" : " + + NumToString(std::numeric_limits<int16_t>::min()) + + ", \"maximum\" : " + + NumToString(std::numeric_limits<int16_t>::max()); + case BASE_TYPE_USHORT: + return "\"type\" : \"integer\", \"minimum\" : 0, \"maximum\" : " + + NumToString(std::numeric_limits<uint16_t>::max()); + case BASE_TYPE_INT: + return "\"type\" : \"integer\", \"minimum\" : " + + NumToString(std::numeric_limits<int32_t>::min()) + + ", \"maximum\" : " + + NumToString(std::numeric_limits<int32_t>::max()); + case BASE_TYPE_UINT: + return "\"type\" : \"integer\", \"minimum\" : 0, \"maximum\" : " + + NumToString(std::numeric_limits<uint32_t>::max()); + case BASE_TYPE_LONG: + return "\"type\" : \"integer\", \"minimum\" : " + + NumToString(std::numeric_limits<int64_t>::min()) + + ", \"maximum\" : " + + NumToString(std::numeric_limits<int64_t>::max()); + case BASE_TYPE_ULONG: + return "\"type\" : \"integer\", \"minimum\" : 0, \"maximum\" : " + + NumToString(std::numeric_limits<uint64_t>::max()); + case BASE_TYPE_FLOAT: + case BASE_TYPE_DOUBLE: return "\"type\" : \"number\""; + case BASE_TYPE_STRING: return "\"type\" : \"string\""; + default: return ""; + } +} + +std::string GenBaseType(const Type &type) { + if (type.struct_def != nullptr) { return GenTypeRef(type.struct_def); } + if (type.enum_def != nullptr) { return GenTypeRef(type.enum_def); } + return GenType(type.base_type); +} + +std::string GenArrayType(const Type &type) { + std::string element_type; + if (type.struct_def != nullptr) { + element_type = GenTypeRef(type.struct_def); + } else if (type.enum_def != nullptr) { + element_type = GenTypeRef(type.enum_def); + } else { + element_type = GenType(type.element); + } + + return "\"type\" : \"array\", \"items\" : {" + element_type + "}"; +} + +std::string GenType(const Type &type) { + switch (type.base_type) { + case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru + case BASE_TYPE_VECTOR: { + return GenArrayType(type); + } + case BASE_TYPE_STRUCT: { + return GenTypeRef(type.struct_def); + } + case BASE_TYPE_UNION: { + std::string union_type_string("\"anyOf\": ["); + const auto &union_types = type.enum_def->Vals(); + for (auto ut = union_types.cbegin(); ut < union_types.cend(); ++ut) { + const auto &union_type = *ut; + if (union_type->union_type.base_type == BASE_TYPE_NONE) { continue; } + if (union_type->union_type.base_type == BASE_TYPE_STRUCT) { + union_type_string.append( + "{ " + GenTypeRef(union_type->union_type.struct_def) + " }"); + } + if (union_type != *type.enum_def->Vals().rbegin()) { + union_type_string.append(","); + } + } + union_type_string.append("]"); + return union_type_string; + } + case BASE_TYPE_UTYPE: return GenTypeRef(type.enum_def); + default: { + return GenBaseType(type); + } + } +} + +class JsonSchemaGenerator : public BaseGenerator { + private: + std::string code_; + + public: + JsonSchemaGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name, "", "", "json") {} + + explicit JsonSchemaGenerator(const BaseGenerator &base_generator) + : BaseGenerator(base_generator) {} + + std::string GeneratedFileName(const std::string &path, + const std::string &file_name, + const IDLOptions &options /* unused */) const { + (void)options; + return path + file_name + ".schema.json"; + } + + // If indentation is less than 0, that indicates we don't want any newlines + // either. + std::string NewLine() const { + return parser_.opts.indent_step >= 0 ? "\n" : ""; + } + + std::string Indent(int indent) const { + const auto num_spaces = indent * std::max(parser_.opts.indent_step, 0); + return std::string(num_spaces, ' '); + } + + bool generate() { + code_ = ""; + if (parser_.root_struct_def_ == nullptr) { return false; } + code_ += "{" + NewLine(); + code_ += Indent(1) + + "\"$schema\": \"https://json-schema.org/draft/2019-09/schema\"," + + NewLine(); + code_ += Indent(1) + "\"definitions\": {" + NewLine(); + for (auto e = parser_.enums_.vec.cbegin(); e != parser_.enums_.vec.cend(); + ++e) { + code_ += Indent(2) + "\"" + GenFullName(*e) + "\" : {" + NewLine(); + code_ += Indent(3) + GenType("string") + "," + NewLine(); + auto enumdef(Indent(3) + "\"enum\": ["); + for (auto enum_value = (*e)->Vals().begin(); + enum_value != (*e)->Vals().end(); ++enum_value) { + enumdef.append("\"" + (*enum_value)->name + "\""); + if (*enum_value != (*e)->Vals().back()) { enumdef.append(", "); } + } + enumdef.append("]"); + code_ += enumdef + NewLine(); + code_ += Indent(2) + "}," + NewLine(); // close type + } + for (auto s = parser_.structs_.vec.cbegin(); + s != parser_.structs_.vec.cend(); ++s) { + const auto &structure = *s; + code_ += Indent(2) + "\"" + GenFullName(structure) + "\" : {" + NewLine(); + code_ += Indent(3) + GenType("object") + "," + NewLine(); + std::string comment; + const auto &comment_lines = structure->doc_comment; + for (auto comment_line = comment_lines.cbegin(); + comment_line != comment_lines.cend(); ++comment_line) { + comment.append(*comment_line); + } + if (!comment.empty()) { + std::string description; + if (!EscapeString(comment.c_str(), comment.length(), &description, true, + true)) { + return false; + } + code_ += + Indent(3) + "\"description\" : " + description + "," + NewLine(); + } + code_ += Indent(3) + "\"properties\" : {" + NewLine(); + + const auto &properties = structure->fields.vec; + for (auto prop = properties.cbegin(); prop != properties.cend(); ++prop) { + const auto &property = *prop; + std::string arrayInfo = ""; + if (IsArray(property->value.type)) { + arrayInfo = "," + NewLine() + Indent(8) + "\"minItems\": " + + NumToString(property->value.type.fixed_length) + "," + + NewLine() + Indent(8) + "\"maxItems\": " + + NumToString(property->value.type.fixed_length); + } + std::string deprecated_info = ""; + if (property->deprecated) { + deprecated_info = + "," + NewLine() + Indent(8) + "\"deprecated\" : true,"; + } + std::string typeLine = Indent(4) + "\"" + property->name + "\""; + typeLine += " : {" + NewLine() + Indent(8); + typeLine += GenType(property->value.type); + typeLine += arrayInfo; + typeLine += deprecated_info; + typeLine += NewLine() + Indent(7) + "}"; + if (property != properties.back()) { typeLine.append(","); } + code_ += typeLine + NewLine(); + } + code_ += Indent(3) + "}," + NewLine(); // close properties + + std::vector<FieldDef *> requiredProperties; + std::copy_if(properties.begin(), properties.end(), + back_inserter(requiredProperties), + [](FieldDef const *prop) { return prop->IsRequired(); }); + if (!requiredProperties.empty()) { + auto required_string(Indent(3) + "\"required\" : ["); + for (auto req_prop = requiredProperties.cbegin(); + req_prop != requiredProperties.cend(); ++req_prop) { + required_string.append("\"" + (*req_prop)->name + "\""); + if (*req_prop != requiredProperties.back()) { + required_string.append(", "); + } + } + required_string.append("],"); + code_ += required_string + NewLine(); + } + code_ += Indent(3) + "\"additionalProperties\" : false" + NewLine(); + auto closeType(Indent(2) + "}"); + if (*s != parser_.structs_.vec.back()) { closeType.append(","); } + code_ += closeType + NewLine(); // close type + } + code_ += Indent(1) + "}," + NewLine(); // close definitions + + // mark root type + code_ += Indent(1) + "\"$ref\" : \"#/definitions/" + + GenFullName(parser_.root_struct_def_) + "\"" + NewLine(); + + code_ += "}" + NewLine(); // close schema root + return true; + } + + bool save() const { + const auto file_path = GeneratedFileName(path_, file_name_, parser_.opts); + return SaveFile(file_path.c_str(), code_, false); + } + + const std::string getJson() { return code_; } +}; +} // namespace jsons + +bool GenerateJsonSchema(const Parser &parser, const std::string &path, + const std::string &file_name) { + jsons::JsonSchemaGenerator generator(parser, path, file_name); + if (!generator.generate()) { return false; } + return generator.save(); +} + +bool GenerateJsonSchema(const Parser &parser, std::string *json) { + jsons::JsonSchemaGenerator generator(parser, "", ""); + if (!generator.generate()) { return false; } + *json = generator.getJson(); + return true; +} +} // namespace flatbuffers diff --git a/contrib/libs/flatbuffers/src/idl_gen_kotlin.cpp b/contrib/libs/flatbuffers/src/idl_gen_kotlin.cpp new file mode 100644 index 0000000000..fb4ce87a67 --- /dev/null +++ b/contrib/libs/flatbuffers/src/idl_gen_kotlin.cpp @@ -0,0 +1,1527 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// independent from idl_parser, since this code is not needed for most clients + +#include <functional> +#include <unordered_set> + +#include "flatbuffers/code_generators.h" +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" +#if defined(FLATBUFFERS_CPP98_STL) +# include <cctype> +#endif // defined(FLATBUFFERS_CPP98_STL) + +namespace flatbuffers { + +namespace kotlin { + +typedef std::map<std::string, std::pair<std::string, std::string> > FbbParamMap; +static TypedFloatConstantGenerator KotlinFloatGen("Double.", "Float.", "NaN", + "POSITIVE_INFINITY", + "NEGATIVE_INFINITY"); + +static const CommentConfig comment_config = { "/**", " *", " */" }; +static const std::string ident_pad = " "; +static const char *keywords[] = { + "package", "as", "typealias", "class", "this", "super", + "val", "var", "fun", "for", "null", "true", + "false", "is", "in", "throw", "return", "break", + "continue", "object", "if", "try", "else", "while", + "do", "when", "interface", "typeof", "Any", "Character" +}; + +// Escape Keywords +static std::string Esc(const std::string &name) { + for (size_t i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) { + if (name == keywords[i]) { return MakeCamel(name + "_", false); } + } + + return MakeCamel(name, false); +} + +class KotlinGenerator : public BaseGenerator { + public: + KotlinGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name, "", ".", "kt"), + cur_name_space_(nullptr) {} + + KotlinGenerator &operator=(const KotlinGenerator &); + bool generate() FLATBUFFERS_OVERRIDE { + std::string one_file_code; + + cur_name_space_ = parser_.current_namespace_; + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + CodeWriter enumWriter(ident_pad); + auto &enum_def = **it; + if (!parser_.opts.one_file) cur_name_space_ = enum_def.defined_namespace; + GenEnum(enum_def, enumWriter); + if (parser_.opts.one_file) { + one_file_code += enumWriter.ToString(); + } else { + if (!SaveType(enum_def.name, *enum_def.defined_namespace, + enumWriter.ToString(), false)) + return false; + } + } + + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + CodeWriter structWriter(ident_pad); + auto &struct_def = **it; + if (!parser_.opts.one_file) + cur_name_space_ = struct_def.defined_namespace; + GenStruct(struct_def, structWriter, parser_.opts); + if (parser_.opts.one_file) { + one_file_code += structWriter.ToString(); + } else { + if (!SaveType(struct_def.name, *struct_def.defined_namespace, + structWriter.ToString(), true)) + return false; + } + } + + if (parser_.opts.one_file) { + return SaveType(file_name_, *parser_.current_namespace_, one_file_code, + true); + } + return true; + } + + // Save out the generated code for a single class while adding + // declaration boilerplate. + bool SaveType(const std::string &defname, const Namespace &ns, + const std::string &classcode, bool needs_includes) const { + if (!classcode.length()) return true; + + std::string code = + "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n"; + + std::string namespace_name = FullNamespace(".", ns); + if (!namespace_name.empty()) { + code += "package " + namespace_name; + code += "\n\n"; + } + if (needs_includes) { + code += "import java.nio.*\n"; + code += "import kotlin.math.sign\n"; + code += "import com.google.flatbuffers.*\n\n"; + } + code += classcode; + auto filename = NamespaceDir(ns) + defname + ".kt"; + return SaveFile(filename.c_str(), code, false); + } + + const Namespace *CurrentNameSpace() const FLATBUFFERS_OVERRIDE { + return cur_name_space_; + } + + static bool IsEnum(const Type &type) { + return type.enum_def != nullptr && IsInteger(type.base_type); + } + + static std::string GenTypeBasic(const BaseType &type) { + // clang-format off + static const char * const kotlin_typename[] = { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE, ...) \ + #KTYPE, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + }; + // clang-format on + return kotlin_typename[type]; + } + + std::string GenTypePointer(const Type &type) const { + switch (type.base_type) { + case BASE_TYPE_STRING: return "String"; + case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType()); + case BASE_TYPE_STRUCT: return WrapInNameSpace(*type.struct_def); + default: return "Table"; + } + } + + // with the addition of optional scalar types, + // we are adding the nullable '?' operator to return type of a field. + std::string GetterReturnType(const FieldDef &field) const { + auto base_type = field.value.type.base_type; + + auto r_type = GenTypeGet(field.value.type); + if (field.IsScalarOptional() || + // string, structs and unions + (base_type == BASE_TYPE_STRING || base_type == BASE_TYPE_STRUCT || + base_type == BASE_TYPE_UNION) || + // vector of anything not scalar + (base_type == BASE_TYPE_VECTOR && + !IsScalar(field.value.type.VectorType().base_type))) { + r_type += "?"; + } + return r_type; + } + + std::string GenTypeGet(const Type &type) const { + return IsScalar(type.base_type) ? GenTypeBasic(type.base_type) + : GenTypePointer(type); + } + + std::string GenEnumDefaultValue(const FieldDef &field) const { + auto &value = field.value; + FLATBUFFERS_ASSERT(value.type.enum_def); + auto &enum_def = *value.type.enum_def; + auto enum_val = enum_def.FindByValue(value.constant); + return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name) + : value.constant; + } + + // Generate default values to compare against a default value when + // `force_defaults` is `false`. + // Main differences are: + // - Floats are upcasted to doubles + // - Unsigned are casted to signed + std::string GenFBBDefaultValue(const FieldDef &field) const { + if (field.IsScalarOptional()) { + // although default value is null, java API forces us to present a real + // default value for scalars, while adding a field to the buffer. This is + // not a problem because the default can be representing just by not + // calling builder.addMyField() + switch (field.value.type.base_type) { + case BASE_TYPE_DOUBLE: + case BASE_TYPE_FLOAT: return "0.0"; + case BASE_TYPE_BOOL: return "false"; + default: return "0"; + } + } + auto out = GenDefaultValue(field, true); + // All FlatBufferBuilder default floating point values are doubles + if (field.value.type.base_type == BASE_TYPE_FLOAT) { + if (out.find("Float") != std::string::npos) { + out.replace(0, 5, "Double"); + } + } + // Guarantee all values are doubles + if (out.back() == 'f') out.pop_back(); + return out; + } + + // FlatBufferBuilder only store signed types, so this function + // returns a cast for unsigned values + std::string GenFBBValueCast(const FieldDef &field) const { + if (IsUnsigned(field.value.type.base_type)) { + return CastToSigned(field.value.type); + } + return ""; + } + + std::string GenDefaultValue(const FieldDef &field, + bool force_signed = false) const { + auto &value = field.value; + auto base_type = field.value.type.base_type; + + if (field.IsScalarOptional()) { return "null"; } + if (IsFloat(base_type)) { + auto val = KotlinFloatGen.GenFloatConstant(field); + if (base_type == BASE_TYPE_DOUBLE && val.back() == 'f') { + val.pop_back(); + } + return val; + } + + if (base_type == BASE_TYPE_BOOL) { + return value.constant == "0" ? "false" : "true"; + } + + std::string suffix = ""; + + if (base_type == BASE_TYPE_LONG || !force_signed) { + suffix = LiteralSuffix(base_type); + } + return value.constant + suffix; + } + + void GenEnum(EnumDef &enum_def, CodeWriter &writer) const { + if (enum_def.generated) return; + + GenerateComment(enum_def.doc_comment, writer, &comment_config); + + writer += "@Suppress(\"unused\")"; + writer += "@ExperimentalUnsignedTypes"; + writer += "class " + Esc(enum_def.name) + " private constructor() {"; + writer.IncrementIdentLevel(); + + GenerateCompanionObject(writer, [&]() { + // Write all properties + auto vals = enum_def.Vals(); + for (auto it = vals.begin(); it != vals.end(); ++it) { + auto &ev = **it; + auto field_type = GenTypeBasic(enum_def.underlying_type.base_type); + auto val = enum_def.ToString(ev); + auto suffix = LiteralSuffix(enum_def.underlying_type.base_type); + writer.SetValue("name", Esc(ev.name)); + writer.SetValue("type", field_type); + writer.SetValue("val", val + suffix); + GenerateComment(ev.doc_comment, writer, &comment_config); + writer += "const val {{name}}: {{type}} = {{val}}"; + } + + // Generate a generate string table for enum values. + // Problem is, if values are very sparse that could generate really + // big tables. Ideally in that case we generate a map lookup + // instead, but for the moment we simply don't output a table at all. + auto range = enum_def.Distance(); + // Average distance between values above which we consider a table + // "too sparse". Change at will. + static const uint64_t kMaxSparseness = 5; + if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) { + GeneratePropertyOneLine(writer, "names", "Array<String>", [&]() { + writer += "arrayOf(\\"; + auto val = enum_def.Vals().front(); + for (auto it = vals.begin(); it != vals.end(); ++it) { + auto ev = *it; + for (auto k = enum_def.Distance(val, ev); k > 1; --k) + writer += "\"\", \\"; + val = ev; + writer += "\"" + (*it)->name + "\"\\"; + if (it + 1 != vals.end()) { writer += ", \\"; } + } + writer += ")"; + }); + GenerateFunOneLine( + writer, "name", "e: Int", "String", + [&]() { + writer += "names[e\\"; + if (enum_def.MinValue()->IsNonZero()) + writer += " - " + enum_def.MinValue()->name + ".toInt()\\"; + writer += "]"; + }, + parser_.opts.gen_jvmstatic); + } + }); + writer.DecrementIdentLevel(); + writer += "}"; + } + + // Returns the function name that is able to read a value of the given type. + std::string ByteBufferGetter(const Type &type, + std::string bb_var_name) const { + switch (type.base_type) { + case BASE_TYPE_STRING: return "__string"; + case BASE_TYPE_STRUCT: return "__struct"; + case BASE_TYPE_UNION: return "__union"; + case BASE_TYPE_VECTOR: + return ByteBufferGetter(type.VectorType(), bb_var_name); + case BASE_TYPE_INT: + case BASE_TYPE_UINT: return bb_var_name + ".getInt"; + case BASE_TYPE_SHORT: + case BASE_TYPE_USHORT: return bb_var_name + ".getShort"; + case BASE_TYPE_ULONG: + case BASE_TYPE_LONG: return bb_var_name + ".getLong"; + case BASE_TYPE_FLOAT: return bb_var_name + ".getFloat"; + case BASE_TYPE_DOUBLE: return bb_var_name + ".getDouble"; + case BASE_TYPE_CHAR: + case BASE_TYPE_UCHAR: + case BASE_TYPE_NONE: + case BASE_TYPE_UTYPE: return bb_var_name + ".get"; + case BASE_TYPE_BOOL: return "0.toByte() != " + bb_var_name + ".get"; + default: + return bb_var_name + ".get" + MakeCamel(GenTypeBasic(type.base_type)); + } + } + + std::string ByteBufferSetter(const Type &type) const { + if (IsScalar(type.base_type)) { + switch (type.base_type) { + case BASE_TYPE_INT: + case BASE_TYPE_UINT: return "bb.putInt"; + case BASE_TYPE_SHORT: + case BASE_TYPE_USHORT: return "bb.putShort"; + case BASE_TYPE_ULONG: + case BASE_TYPE_LONG: return "bb.putLong"; + case BASE_TYPE_FLOAT: return "bb.putFloat"; + case BASE_TYPE_DOUBLE: return "bb.putDouble"; + case BASE_TYPE_CHAR: + case BASE_TYPE_UCHAR: + case BASE_TYPE_BOOL: + case BASE_TYPE_NONE: + case BASE_TYPE_UTYPE: return "bb.put"; + default: return "bb.put" + MakeCamel(GenTypeBasic(type.base_type)); + } + } + return ""; + } + + // Returns the function name that is able to read a value of the given type. + std::string GenLookupByKey(flatbuffers::FieldDef *key_field, + const std::string &bb_var_name, + const char *num = nullptr) const { + auto type = key_field->value.type; + return ByteBufferGetter(type, bb_var_name) + "(" + + GenOffsetGetter(key_field, num) + ")"; + } + + // Returns the method name for use with add/put calls. + static std::string GenMethod(const Type &type) { + return IsScalar(type.base_type) ? ToSignedType(type) + : (IsStruct(type) ? "Struct" : "Offset"); + } + + // Recursively generate arguments for a constructor, to deal with nested + // structs. + static void GenStructArgs(const StructDef &struct_def, CodeWriter &writer, + const char *nameprefix) { + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (IsStruct(field.value.type)) { + // Generate arguments for a struct inside a struct. To ensure + // names don't clash, and to make it obvious these arguments are + // constructing a nested struct, prefix the name with the field + // name. + GenStructArgs(*field.value.type.struct_def, writer, + (nameprefix + (field.name + "_")).c_str()); + } else { + writer += std::string(", ") + nameprefix + "\\"; + writer += MakeCamel(field.name) + ": \\"; + writer += GenTypeBasic(field.value.type.base_type) + "\\"; + } + } + } + + // Recusively generate struct construction statements of the form: + // builder.putType(name); + // and insert manual padding. + static void GenStructBody(const StructDef &struct_def, CodeWriter &writer, + const char *nameprefix) { + writer.SetValue("align", NumToString(struct_def.minalign)); + writer.SetValue("size", NumToString(struct_def.bytesize)); + writer += "builder.prep({{align}}, {{size}})"; + auto fields_vec = struct_def.fields.vec; + for (auto it = fields_vec.rbegin(); it != fields_vec.rend(); ++it) { + auto &field = **it; + + if (field.padding) { + writer.SetValue("pad", NumToString(field.padding)); + writer += "builder.pad({{pad}})"; + } + if (IsStruct(field.value.type)) { + GenStructBody(*field.value.type.struct_def, writer, + (nameprefix + (field.name + "_")).c_str()); + } else { + writer.SetValue("type", GenMethod(field.value.type)); + writer.SetValue("argname", nameprefix + MakeCamel(field.name, false)); + writer.SetValue("cast", CastToSigned(field.value.type)); + writer += "builder.put{{type}}({{argname}}{{cast}})"; + } + } + } + + std::string GenByteBufferLength(const char *bb_name) const { + std::string bb_len = bb_name; + bb_len += ".capacity()"; + return bb_len; + } + + std::string GenOffsetGetter(flatbuffers::FieldDef *key_field, + const char *num = nullptr) const { + std::string key_offset = + "__offset(" + NumToString(key_field->value.offset) + ", "; + if (num) { + key_offset += num; + key_offset += ", _bb)"; + } else { + key_offset += GenByteBufferLength("bb"); + key_offset += " - tableOffset, bb)"; + } + return key_offset; + } + + void GenStruct(StructDef &struct_def, CodeWriter &writer, + IDLOptions options) const { + if (struct_def.generated) return; + + GenerateComment(struct_def.doc_comment, writer, &comment_config); + auto fixed = struct_def.fixed; + + writer.SetValue("struct_name", Esc(struct_def.name)); + writer.SetValue("superclass", fixed ? "Struct" : "Table"); + + writer += "@Suppress(\"unused\")"; + writer += "@ExperimentalUnsignedTypes"; + writer += "class {{struct_name}} : {{superclass}}() {\n"; + + writer.IncrementIdentLevel(); + + { + // Generate the __init() method that sets the field in a pre-existing + // accessor object. This is to allow object reuse. + GenerateFun(writer, "__init", "_i: Int, _bb: ByteBuffer", "", + [&]() { writer += "__reset(_i, _bb)"; }); + + // Generate assign method + GenerateFun(writer, "__assign", "_i: Int, _bb: ByteBuffer", + Esc(struct_def.name), [&]() { + writer += "__init(_i, _bb)"; + writer += "return this"; + }); + + // Generate all getters + GenerateStructGetters(struct_def, writer); + + // Generate Static Fields + GenerateCompanionObject(writer, [&]() { + if (!struct_def.fixed) { + FieldDef *key_field = nullptr; + + // Generate verson check method. + // Force compile time error if not using the same version + // runtime. + GenerateFunOneLine( + writer, "validateVersion", "", "", + [&]() { writer += "Constants.FLATBUFFERS_2_0_0()"; }, + options.gen_jvmstatic); + + GenerateGetRootAsAccessors(Esc(struct_def.name), writer, options); + GenerateBufferHasIdentifier(struct_def, writer, options); + GenerateTableCreator(struct_def, writer, options); + + GenerateStartStructMethod(struct_def, writer, options); + + // Static Add for fields + auto fields = struct_def.fields.vec; + int field_pos = -1; + for (auto it = fields.begin(); it != fields.end(); ++it) { + auto &field = **it; + field_pos++; + if (field.deprecated) continue; + if (field.key) key_field = &field; + GenerateAddField(NumToString(field_pos), field, writer, options); + + if (IsVector(field.value.type)) { + auto vector_type = field.value.type.VectorType(); + if (!IsStruct(vector_type)) { + GenerateCreateVectorField(field, writer, options); + } + GenerateStartVectorField(field, writer, options); + } + } + + GenerateEndStructMethod(struct_def, writer, options); + auto file_identifier = parser_.file_identifier_; + if (parser_.root_struct_def_ == &struct_def) { + GenerateFinishStructBuffer(struct_def, file_identifier, writer, + options); + GenerateFinishSizePrefixed(struct_def, file_identifier, writer, + options); + } + + if (struct_def.has_key) { + GenerateLookupByKey(key_field, struct_def, writer, options); + } + } else { + GenerateStaticConstructor(struct_def, writer, options); + } + }); + } + + // class closing + writer.DecrementIdentLevel(); + writer += "}"; + } + + // TODO: move key_field to reference instead of pointer + void GenerateLookupByKey(FieldDef *key_field, StructDef &struct_def, + CodeWriter &writer, const IDLOptions options) const { + std::stringstream params; + params << "obj: " << Esc(struct_def.name) << "?" + << ", "; + params << "vectorLocation: Int, "; + params << "key: " << GenTypeGet(key_field->value.type) << ", "; + params << "bb: ByteBuffer"; + + auto statements = [&]() { + auto base_type = key_field->value.type.base_type; + writer.SetValue("struct_name", Esc(struct_def.name)); + if (base_type == BASE_TYPE_STRING) { + writer += + "val byteKey = key." + "toByteArray(java.nio.charset.StandardCharsets.UTF_8)"; + } + writer += "var span = bb.getInt(vectorLocation - 4)"; + writer += "var start = 0"; + writer += "while (span != 0) {"; + writer.IncrementIdentLevel(); + writer += "var middle = span / 2"; + writer += + "val tableOffset = __indirect(vector" + "Location + 4 * (start + middle), bb)"; + if (IsString(key_field->value.type)) { + writer += "val comp = compareStrings(\\"; + writer += GenOffsetGetter(key_field) + "\\"; + writer += ", byteKey, bb)"; + } else { + auto cast = CastToUsigned(key_field->value.type); + auto get_val = GenLookupByKey(key_field, "bb"); + writer += "val value = " + get_val + cast; + writer += "val comp = value.compareTo(key)"; + } + writer += "when {"; + writer.IncrementIdentLevel(); + writer += "comp > 0 -> span = middle"; + writer += "comp < 0 -> {"; + writer.IncrementIdentLevel(); + writer += "middle++"; + writer += "start += middle"; + writer += "span -= middle"; + writer.DecrementIdentLevel(); + writer += "}"; // end comp < 0 + writer += "else -> {"; + writer.IncrementIdentLevel(); + writer += "return (obj ?: {{struct_name}}()).__assign(tableOffset, bb)"; + writer.DecrementIdentLevel(); + writer += "}"; // end else + writer.DecrementIdentLevel(); + writer += "}"; // end when + writer.DecrementIdentLevel(); + writer += "}"; // end while + writer += "return null"; + }; + GenerateFun(writer, "__lookup_by_key", params.str(), + Esc(struct_def.name) + "?", statements, options.gen_jvmstatic); + } + + void GenerateFinishSizePrefixed(StructDef &struct_def, + const std::string &identifier, + CodeWriter &writer, + const IDLOptions options) const { + auto id = identifier.length() > 0 ? ", \"" + identifier + "\"" : ""; + auto params = "builder: FlatBufferBuilder, offset: Int"; + auto method_name = "finishSizePrefixed" + Esc(struct_def.name) + "Buffer"; + GenerateFunOneLine( + writer, method_name, params, "", + [&]() { writer += "builder.finishSizePrefixed(offset" + id + ")"; }, + options.gen_jvmstatic); + } + void GenerateFinishStructBuffer(StructDef &struct_def, + const std::string &identifier, + CodeWriter &writer, + const IDLOptions options) const { + auto id = identifier.length() > 0 ? ", \"" + identifier + "\"" : ""; + auto params = "builder: FlatBufferBuilder, offset: Int"; + auto method_name = "finish" + Esc(struct_def.name) + "Buffer"; + GenerateFunOneLine( + writer, method_name, params, "", + [&]() { writer += "builder.finish(offset" + id + ")"; }, + options.gen_jvmstatic); + } + + void GenerateEndStructMethod(StructDef &struct_def, CodeWriter &writer, + const IDLOptions options) const { + // Generate end{{TableName}}(builder: FlatBufferBuilder) method + auto name = "end" + Esc(struct_def.name); + auto params = "builder: FlatBufferBuilder"; + auto returns = "Int"; + auto field_vec = struct_def.fields.vec; + + GenerateFun( + writer, name, params, returns, + [&]() { + writer += "val o = builder.endTable()"; + writer.IncrementIdentLevel(); + for (auto it = field_vec.begin(); it != field_vec.end(); ++it) { + auto &field = **it; + if (field.deprecated || !field.IsRequired()) { continue; } + writer.SetValue("offset", NumToString(field.value.offset)); + writer += "builder.required(o, {{offset}})"; + } + writer.DecrementIdentLevel(); + writer += "return o"; + }, + options.gen_jvmstatic); + } + + // Generate a method to create a vector from a Kotlin array. + void GenerateCreateVectorField(FieldDef &field, CodeWriter &writer, + const IDLOptions options) const { + auto vector_type = field.value.type.VectorType(); + auto method_name = "create" + MakeCamel(Esc(field.name)) + "Vector"; + auto params = "builder: FlatBufferBuilder, data: " + + GenTypeBasic(vector_type.base_type) + "Array"; + writer.SetValue("size", NumToString(InlineSize(vector_type))); + writer.SetValue("align", NumToString(InlineAlignment(vector_type))); + writer.SetValue("root", GenMethod(vector_type)); + writer.SetValue("cast", CastToSigned(vector_type)); + + GenerateFun( + writer, method_name, params, "Int", + [&]() { + writer += "builder.startVector({{size}}, data.size, {{align}})"; + writer += "for (i in data.size - 1 downTo 0) {"; + writer.IncrementIdentLevel(); + writer += "builder.add{{root}}(data[i]{{cast}})"; + writer.DecrementIdentLevel(); + writer += "}"; + writer += "return builder.endVector()"; + }, + options.gen_jvmstatic); + } + + void GenerateStartVectorField(FieldDef &field, CodeWriter &writer, + const IDLOptions options) const { + // Generate a method to start a vector, data to be added manually + // after. + auto vector_type = field.value.type.VectorType(); + auto params = "builder: FlatBufferBuilder, numElems: Int"; + writer.SetValue("size", NumToString(InlineSize(vector_type))); + writer.SetValue("align", NumToString(InlineAlignment(vector_type))); + + GenerateFunOneLine( + writer, "start" + MakeCamel(Esc(field.name) + "Vector", true), params, + "", + [&]() { + writer += "builder.startVector({{size}}, numElems, {{align}})"; + }, + options.gen_jvmstatic); + } + + void GenerateAddField(std::string field_pos, FieldDef &field, + CodeWriter &writer, const IDLOptions options) const { + auto field_type = GenTypeBasic(field.value.type.base_type); + auto secondArg = MakeCamel(Esc(field.name), false) + ": " + field_type; + + GenerateFunOneLine( + writer, "add" + MakeCamel(Esc(field.name), true), + "builder: FlatBufferBuilder, " + secondArg, "", + [&]() { + auto method = GenMethod(field.value.type); + writer.SetValue("field_name", MakeCamel(Esc(field.name), false)); + writer.SetValue("method_name", method); + writer.SetValue("pos", field_pos); + writer.SetValue("default", GenFBBDefaultValue(field)); + writer.SetValue("cast", GenFBBValueCast(field)); + + writer += "builder.add{{method_name}}({{pos}}, \\"; + writer += "{{field_name}}{{cast}}, {{default}})"; + }, + options.gen_jvmstatic); + } + + static std::string ToSignedType(const Type &type) { + switch (type.base_type) { + case BASE_TYPE_UINT: return GenTypeBasic(BASE_TYPE_INT); + case BASE_TYPE_ULONG: return GenTypeBasic(BASE_TYPE_LONG); + case BASE_TYPE_UCHAR: + case BASE_TYPE_NONE: + case BASE_TYPE_UTYPE: return GenTypeBasic(BASE_TYPE_CHAR); + case BASE_TYPE_USHORT: return GenTypeBasic(BASE_TYPE_SHORT); + case BASE_TYPE_VECTOR: return ToSignedType(type.VectorType()); + default: return GenTypeBasic(type.base_type); + } + } + + static std::string FlexBufferBuilderCast(const std::string &method, + FieldDef &field, bool isFirst) { + auto field_type = GenTypeBasic(field.value.type.base_type); + std::string to_type; + if (method == "Boolean") + to_type = "Boolean"; + else if (method == "Long") + to_type = "Long"; + else if (method == "Int" || method == "Offset" || method == "Struct") + to_type = "Int"; + else if (method == "Byte" || method.empty()) + to_type = isFirst ? "Byte" : "Int"; + else if (method == "Short") + to_type = isFirst ? "Short" : "Int"; + else if (method == "Double") + to_type = "Double"; + else if (method == "Float") + to_type = isFirst ? "Float" : "Double"; + else if (method == "UByte") + + if (field_type != to_type) return ".to" + to_type + "()"; + return ""; + } + + // fun startMonster(builder: FlatBufferBuilder) = builder.startTable(11) + void GenerateStartStructMethod(StructDef &struct_def, CodeWriter &code, + const IDLOptions options) const { + GenerateFunOneLine( + code, "start" + Esc(struct_def.name), "builder: FlatBufferBuilder", "", + [&]() { + code += "builder.startTable(" + + NumToString(struct_def.fields.vec.size()) + ")"; + }, + options.gen_jvmstatic); + } + + void GenerateTableCreator(StructDef &struct_def, CodeWriter &writer, + const IDLOptions options) const { + // Generate a method that creates a table in one go. This is only possible + // when the table has no struct fields, since those have to be created + // inline, and there's no way to do so in Java. + bool has_no_struct_fields = true; + int num_fields = 0; + auto fields_vec = struct_def.fields.vec; + + for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + if (IsStruct(field.value.type)) { + has_no_struct_fields = false; + } else { + num_fields++; + } + } + // JVM specifications restrict default constructor params to be < 255. + // Longs and doubles take up 2 units, so we set the limit to be < 127. + if (has_no_struct_fields && num_fields && num_fields < 127) { + // Generate a table constructor of the form: + // public static int createName(FlatBufferBuilder builder, args...) + + auto name = "create" + Esc(struct_def.name); + std::stringstream params; + params << "builder: FlatBufferBuilder"; + for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + params << ", " << MakeCamel(Esc(field.name), false); + if (!IsScalar(field.value.type.base_type)) { + params << "Offset: "; + } else { + params << ": "; + } + auto optional = field.IsScalarOptional() ? "?" : ""; + params << GenTypeBasic(field.value.type.base_type) << optional; + } + + GenerateFun( + writer, name, params.str(), "Int", + [&]() { + writer.SetValue("vec_size", NumToString(fields_vec.size())); + + writer += "builder.startTable({{vec_size}})"; + + auto sortbysize = struct_def.sortbysize; + auto largest = sortbysize ? sizeof(largest_scalar_t) : 1; + for (size_t size = largest; size; size /= 2) { + for (auto it = fields_vec.rbegin(); it != fields_vec.rend(); + ++it) { + auto &field = **it; + auto base_type_size = SizeOf(field.value.type.base_type); + if (!field.deprecated && + (!sortbysize || size == base_type_size)) { + writer.SetValue("camel_field_name", + MakeCamel(Esc(field.name), true)); + writer.SetValue("field_name", + MakeCamel(Esc(field.name), false)); + + // we wrap on null check for scalar optionals + writer += field.IsScalarOptional() + ? "{{field_name}}?.run { \\" + : "\\"; + + writer += "add{{camel_field_name}}(builder, {{field_name}}\\"; + if (!IsScalar(field.value.type.base_type)) { + writer += "Offset\\"; + } + // we wrap on null check for scalar optionals + writer += field.IsScalarOptional() ? ") }" : ")"; + } + } + } + writer += "return end{{struct_name}}(builder)"; + }, + options.gen_jvmstatic); + } + } + void GenerateBufferHasIdentifier(StructDef &struct_def, CodeWriter &writer, + IDLOptions options) const { + auto file_identifier = parser_.file_identifier_; + // Check if a buffer has the identifier. + if (parser_.root_struct_def_ != &struct_def || !file_identifier.length()) + return; + auto name = MakeCamel(Esc(struct_def.name), false); + GenerateFunOneLine( + writer, name + "BufferHasIdentifier", "_bb: ByteBuffer", "Boolean", + [&]() { + writer += "__has_identifier(_bb, \"" + file_identifier + "\")"; + }, + options.gen_jvmstatic); + } + + void GenerateStructGetters(StructDef &struct_def, CodeWriter &writer) const { + auto fields_vec = struct_def.fields.vec; + FieldDef *key_field = nullptr; + for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + if (field.key) key_field = &field; + + GenerateComment(field.doc_comment, writer, &comment_config); + + auto field_name = MakeCamel(Esc(field.name), false); + auto field_type = GenTypeGet(field.value.type); + auto field_default_value = GenDefaultValue(field); + auto return_type = GetterReturnType(field); + auto bbgetter = ByteBufferGetter(field.value.type, "bb"); + auto ucast = CastToUsigned(field); + auto offset_val = NumToString(field.value.offset); + auto offset_prefix = + "val o = __offset(" + offset_val + "); return o != 0 ? "; + auto value_base_type = field.value.type.base_type; + // Most field accessors need to retrieve and test the field offset + // first, this is the offset value for that: + writer.SetValue("offset", NumToString(field.value.offset)); + writer.SetValue("return_type", return_type); + writer.SetValue("field_type", field_type); + writer.SetValue("field_name", field_name); + writer.SetValue("field_default", field_default_value); + writer.SetValue("bbgetter", bbgetter); + writer.SetValue("ucast", ucast); + + // Generate the accessors that don't do object reuse. + if (value_base_type == BASE_TYPE_STRUCT) { + // Calls the accessor that takes an accessor object with a + // new object. + // val pos + // get() = pos(Vec3()) + GenerateGetterOneLine(writer, field_name, return_type, [&]() { + writer += "{{field_name}}({{field_type}}())"; + }); + } else if (value_base_type == BASE_TYPE_VECTOR && + field.value.type.element == BASE_TYPE_STRUCT) { + // Accessors for vectors of structs also take accessor objects, + // this generates a variant without that argument. + // ex: fun weapons(j: Int) = weapons(Weapon(), j) + GenerateFunOneLine(writer, field_name, "j: Int", return_type, [&]() { + writer += "{{field_name}}({{field_type}}(), j)"; + }); + } + + if (IsScalar(value_base_type)) { + if (struct_def.fixed) { + GenerateGetterOneLine(writer, field_name, return_type, [&]() { + writer += "{{bbgetter}}(bb_pos + {{offset}}){{ucast}}"; + }); + } else { + GenerateGetter(writer, field_name, return_type, [&]() { + writer += "val o = __offset({{offset}})"; + writer += + "return if(o != 0) {{bbgetter}}" + "(o + bb_pos){{ucast}} else " + "{{field_default}}"; + }); + } + } else { + switch (value_base_type) { + case BASE_TYPE_STRUCT: + if (struct_def.fixed) { + // create getter with object reuse + // ex: + // fun pos(obj: Vec3) : Vec3? = obj.__assign(bb_pos + 4, bb) + // ? adds nullability annotation + GenerateFunOneLine( + writer, field_name, "obj: " + field_type, return_type, + [&]() { writer += "obj.__assign(bb_pos + {{offset}}, bb)"; }); + } else { + // create getter with object reuse + // ex: + // fun pos(obj: Vec3) : Vec3? { + // val o = __offset(4) + // return if(o != 0) { + // obj.__assign(o + bb_pos, bb) + // else { + // null + // } + // } + // ? adds nullability annotation + GenerateFun( + writer, field_name, "obj: " + field_type, return_type, [&]() { + auto fixed = field.value.type.struct_def->fixed; + + writer.SetValue("seek", Indirect("o + bb_pos", fixed)); + OffsetWrapper( + writer, offset_val, + [&]() { writer += "obj.__assign({{seek}}, bb)"; }, + [&]() { writer += "null"; }); + }); + } + break; + case BASE_TYPE_STRING: + // create string getter + // e.g. + // val Name : String? + // get() = { + // val o = __offset(10) + // return if (o != 0) __string(o + bb_pos) else null + // } + // ? adds nullability annotation + GenerateGetter(writer, field_name, return_type, [&]() { + writer += "val o = __offset({{offset}})"; + writer += "return if (o != 0) __string(o + bb_pos) else null"; + }); + break; + case BASE_TYPE_VECTOR: { + // e.g. + // fun inventory(j: Int) : UByte { + // val o = __offset(14) + // return if (o != 0) { + // bb.get(__vector(o) + j * 1).toUByte() + // } else { + // 0 + // } + // } + + auto vectortype = field.value.type.VectorType(); + std::string params = "j: Int"; + + if (vectortype.base_type == BASE_TYPE_STRUCT || + vectortype.base_type == BASE_TYPE_UNION) { + params = "obj: " + field_type + ", j: Int"; + } + + GenerateFun(writer, field_name, params, return_type, [&]() { + auto inline_size = NumToString(InlineSize(vectortype)); + auto index = "__vector(o) + j * " + inline_size; + auto not_found = NotFoundReturn(field.value.type.element); + auto found = ""; + writer.SetValue("index", index); + switch (vectortype.base_type) { + case BASE_TYPE_STRUCT: { + bool fixed = vectortype.struct_def->fixed; + writer.SetValue("index", Indirect(index, fixed)); + found = "obj.__assign({{index}}, bb)"; + break; + } + case BASE_TYPE_UNION: + found = "{{bbgetter}}(obj, {{index}}){{ucast}}"; + break; + default: found = "{{bbgetter}}({{index}}){{ucast}}"; + } + OffsetWrapper( + writer, offset_val, [&]() { writer += found; }, + [&]() { writer += not_found; }); + }); + break; + } + case BASE_TYPE_UNION: + GenerateFun( + writer, field_name, "obj: " + field_type, return_type, [&]() { + writer += OffsetWrapperOneLine( + offset_val, bbgetter + "(obj, o + bb_pos)", "null"); + }); + break; + default: FLATBUFFERS_ASSERT(0); + } + } + + if (value_base_type == BASE_TYPE_VECTOR) { + // Generate Lenght functions for vectors + GenerateGetter(writer, field_name + "Length", "Int", [&]() { + writer += OffsetWrapperOneLine(offset_val, "__vector_len(o)", "0"); + }); + + // See if we should generate a by-key accessor. + if (field.value.type.element == BASE_TYPE_STRUCT && + !field.value.type.struct_def->fixed) { + auto &sd = *field.value.type.struct_def; + auto &fields = sd.fields.vec; + for (auto kit = fields.begin(); kit != fields.end(); ++kit) { + auto &kfield = **kit; + if (kfield.key) { + auto qualified_name = WrapInNameSpace(sd); + auto name = MakeCamel(Esc(field.name), false) + "ByKey"; + auto params = "key: " + GenTypeGet(kfield.value.type); + auto rtype = qualified_name + "?"; + GenerateFun(writer, name, params, rtype, [&]() { + OffsetWrapper( + writer, offset_val, + [&]() { + writer += qualified_name + + ".__lookup_by_key(null, __vector(o), key, bb)"; + }, + [&]() { writer += "null"; }); + }); + + auto param2 = "obj: " + qualified_name + + ", key: " + GenTypeGet(kfield.value.type); + GenerateFun(writer, name, param2, rtype, [&]() { + OffsetWrapper( + writer, offset_val, + [&]() { + writer += qualified_name + + ".__lookup_by_key(obj, __vector(o), key, bb)"; + }, + [&]() { writer += "null"; }); + }); + + break; + } + } + } + } + + if ((value_base_type == BASE_TYPE_VECTOR && + IsScalar(field.value.type.VectorType().base_type)) || + value_base_type == BASE_TYPE_STRING) { + auto end_idx = + NumToString(value_base_type == BASE_TYPE_STRING + ? 1 + : InlineSize(field.value.type.VectorType())); + // Generate a ByteBuffer accessor for strings & vectors of scalars. + // e.g. + // val inventoryByteBuffer: ByteBuffer + // get = __vector_as_bytebuffer(14, 1) + + GenerateGetterOneLine( + writer, field_name + "AsByteBuffer", "ByteBuffer", [&]() { + writer.SetValue("end", end_idx); + writer += "__vector_as_bytebuffer({{offset}}, {{end}})"; + }); + + // Generate a ByteBuffer accessor for strings & vectors of scalars. + // e.g. + // fun inventoryInByteBuffer(_bb: Bytebuffer): + // ByteBuffer = __vector_as_bytebuffer(_bb, 14, 1) + GenerateFunOneLine( + writer, field_name + "InByteBuffer", "_bb: ByteBuffer", + "ByteBuffer", [&]() { + writer.SetValue("end", end_idx); + writer += "__vector_in_bytebuffer(_bb, {{offset}}, {{end}})"; + }); + } + + // generate object accessors if is nested_flatbuffer + // fun testnestedflatbufferAsMonster() : Monster? + //{ return testnestedflatbufferAsMonster(new Monster()); } + + if (field.nested_flatbuffer) { + auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer); + auto nested_method_name = + field_name + "As" + field.nested_flatbuffer->name; + + GenerateGetterOneLine( + writer, nested_method_name, nested_type_name + "?", [&]() { + writer += nested_method_name + "(" + nested_type_name + "())"; + }); + + GenerateFun(writer, nested_method_name, "obj: " + nested_type_name, + nested_type_name + "?", [&]() { + OffsetWrapper( + writer, offset_val, + [&]() { + writer += + "obj.__assign(__indirect(__vector(o)), bb)"; + }, + [&]() { writer += "null"; }); + }); + } + + // Generate mutators for scalar fields or vectors of scalars. + if (parser_.opts.mutable_buffer) { + auto value_type = field.value.type; + auto underlying_type = value_base_type == BASE_TYPE_VECTOR + ? value_type.VectorType() + : value_type; + auto name = "mutate" + MakeCamel(Esc(field.name), true); + auto size = NumToString(InlineSize(underlying_type)); + auto params = Esc(field.name) + ": " + GenTypeGet(underlying_type); + // A vector mutator also needs the index of the vector element it should + // mutate. + if (value_base_type == BASE_TYPE_VECTOR) params.insert(0, "j: Int, "); + + // Boolean parameters have to be explicitly converted to byte + // representation. + auto setter_parameter = + underlying_type.base_type == BASE_TYPE_BOOL + ? "(if(" + Esc(field.name) + ") 1 else 0).toByte()" + : Esc(field.name); + + auto setter_index = + value_base_type == BASE_TYPE_VECTOR + ? "__vector(o) + j * " + size + : (struct_def.fixed ? "bb_pos + " + offset_val : "o + bb_pos"); + if (IsScalar(value_base_type) || + (value_base_type == BASE_TYPE_VECTOR && + IsScalar(value_type.VectorType().base_type))) { + auto statements = [&]() { + writer.SetValue("bbsetter", ByteBufferSetter(underlying_type)); + writer.SetValue("index", setter_index); + writer.SetValue("params", setter_parameter); + writer.SetValue("cast", CastToSigned(field)); + if (struct_def.fixed) { + writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})"; + } else { + OffsetWrapper( + writer, offset_val, + [&]() { + writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})"; + writer += "true"; + }, + [&]() { writer += "false"; }); + } + }; + + if (struct_def.fixed) { + GenerateFunOneLine(writer, name, params, "ByteBuffer", statements); + } else { + GenerateFun(writer, name, params, "Boolean", statements); + } + } + } + } + if (struct_def.has_key && !struct_def.fixed) { + // Key Comparison method + GenerateOverrideFun( + writer, "keysCompare", "o1: Int, o2: Int, _bb: ByteBuffer", "Int", + [&]() { + if (IsString(key_field->value.type)) { + writer.SetValue("offset", NumToString(key_field->value.offset)); + writer += + " return compareStrings(__offset({{offset}}, o1, " + "_bb), __offset({{offset}}, o2, _bb), _bb)"; + + } else { + auto getter1 = GenLookupByKey(key_field, "_bb", "o1"); + auto getter2 = GenLookupByKey(key_field, "_bb", "o2"); + writer += "val val_1 = " + getter1; + writer += "val val_2 = " + getter2; + writer += "return (val_1 - val_2).sign"; + } + }); + } + } + + static std::string CastToUsigned(const FieldDef &field) { + return CastToUsigned(field.value.type); + } + + static std::string CastToUsigned(const Type type) { + switch (type.base_type) { + case BASE_TYPE_UINT: return ".toUInt()"; + case BASE_TYPE_UCHAR: + case BASE_TYPE_UTYPE: return ".toUByte()"; + case BASE_TYPE_USHORT: return ".toUShort()"; + case BASE_TYPE_ULONG: return ".toULong()"; + case BASE_TYPE_VECTOR: return CastToUsigned(type.VectorType()); + default: return ""; + } + } + + static std::string CastToSigned(const FieldDef &field) { + return CastToSigned(field.value.type); + } + + static std::string CastToSigned(const Type type) { + switch (type.base_type) { + case BASE_TYPE_UINT: return ".toInt()"; + case BASE_TYPE_UCHAR: + case BASE_TYPE_UTYPE: return ".toByte()"; + case BASE_TYPE_USHORT: return ".toShort()"; + case BASE_TYPE_ULONG: return ".toLong()"; + case BASE_TYPE_VECTOR: return CastToSigned(type.VectorType()); + default: return ""; + } + } + + static std::string LiteralSuffix(const BaseType type) { + switch (type) { + case BASE_TYPE_UINT: + case BASE_TYPE_UCHAR: + case BASE_TYPE_UTYPE: + case BASE_TYPE_USHORT: return "u"; + case BASE_TYPE_ULONG: return "UL"; + case BASE_TYPE_LONG: return "L"; + default: return ""; + } + } + + void GenerateCompanionObject(CodeWriter &code, + const std::function<void()> &callback) const { + code += "companion object {"; + code.IncrementIdentLevel(); + callback(); + code.DecrementIdentLevel(); + code += "}"; + } + + // Generate a documentation comment, if available. + void GenerateComment(const std::vector<std::string> &dc, CodeWriter &writer, + const CommentConfig *config) const { + if (dc.begin() == dc.end()) { + // Don't output empty comment blocks with 0 lines of comment content. + return; + } + + if (config != nullptr && config->first_line != nullptr) { + writer += std::string(config->first_line); + } + std::string line_prefix = + ((config != nullptr && config->content_line_prefix != nullptr) + ? config->content_line_prefix + : "///"); + for (auto it = dc.begin(); it != dc.end(); ++it) { + writer += line_prefix + *it; + } + if (config != nullptr && config->last_line != nullptr) { + writer += std::string(config->last_line); + } + } + + static void GenerateGetRootAsAccessors(const std::string &struct_name, + CodeWriter &writer, + IDLOptions options) { + // Generate a special accessor for the table that when used as the root + // ex: fun getRootAsMonster(_bb: ByteBuffer): Monster {...} + writer.SetValue("gr_name", struct_name); + writer.SetValue("gr_method", "getRootAs" + struct_name); + + // create convenience method that doesn't require an existing object + GenerateJvmStaticAnnotation(writer, options.gen_jvmstatic); + writer += "fun {{gr_method}}(_bb: ByteBuffer): {{gr_name}} = \\"; + writer += "{{gr_method}}(_bb, {{gr_name}}())"; + + // create method that allows object reuse + // ex: fun Monster getRootAsMonster(_bb: ByteBuffer, obj: Monster) {...} + GenerateJvmStaticAnnotation(writer, options.gen_jvmstatic); + writer += + "fun {{gr_method}}" + "(_bb: ByteBuffer, obj: {{gr_name}}): {{gr_name}} {"; + writer.IncrementIdentLevel(); + writer += "_bb.order(ByteOrder.LITTLE_ENDIAN)"; + writer += + "return (obj.__assign(_bb.getInt(_bb.position())" + " + _bb.position(), _bb))"; + writer.DecrementIdentLevel(); + writer += "}"; + } + + static void GenerateStaticConstructor(const StructDef &struct_def, + CodeWriter &code, + const IDLOptions options) { + // create a struct constructor function + auto params = StructConstructorParams(struct_def); + GenerateFun( + code, "create" + Esc(struct_def.name), params, "Int", + [&]() { + GenStructBody(struct_def, code, ""); + code += "return builder.offset()"; + }, + options.gen_jvmstatic); + } + + static std::string StructConstructorParams(const StructDef &struct_def, + const std::string &prefix = "") { + // builder: FlatBufferBuilder + std::stringstream out; + auto field_vec = struct_def.fields.vec; + if (prefix.empty()) { out << "builder: FlatBufferBuilder"; } + for (auto it = field_vec.begin(); it != field_vec.end(); ++it) { + auto &field = **it; + if (IsStruct(field.value.type)) { + // Generate arguments for a struct inside a struct. To ensure + // names don't clash, and to make it obvious these arguments are + // constructing a nested struct, prefix the name with the field + // name. + out << StructConstructorParams(*field.value.type.struct_def, + prefix + (Esc(field.name) + "_")); + } else { + out << ", " << prefix << MakeCamel(Esc(field.name), false) << ": " + << GenTypeBasic(field.value.type.base_type); + } + } + return out.str(); + } + + static void GeneratePropertyOneLine(CodeWriter &writer, + const std::string &name, + const std::string &type, + const std::function<void()> &body) { + // Generates Kotlin getter for properties + // e.g.: + // val prop: Mytype = x + writer.SetValue("_name", name); + writer.SetValue("_type", type); + writer += "val {{_name}} : {{_type}} = \\"; + body(); + } + static void GenerateGetterOneLine(CodeWriter &writer, const std::string &name, + const std::string &type, + const std::function<void()> &body) { + // Generates Kotlin getter for properties + // e.g.: + // val prop: Mytype get() = x + writer.SetValue("_name", name); + writer.SetValue("_type", type); + writer += "val {{_name}} : {{_type}} get() = \\"; + body(); + } + + static void GenerateGetter(CodeWriter &writer, const std::string &name, + const std::string &type, + const std::function<void()> &body) { + // Generates Kotlin getter for properties + // e.g.: + // val prop: Mytype + // get() = { + // return x + // } + writer.SetValue("name", name); + writer.SetValue("type", type); + writer += "val {{name}} : {{type}}"; + writer.IncrementIdentLevel(); + writer += "get() {"; + writer.IncrementIdentLevel(); + body(); + writer.DecrementIdentLevel(); + writer += "}"; + writer.DecrementIdentLevel(); + } + + static void GenerateFun(CodeWriter &writer, const std::string &name, + const std::string ¶ms, + const std::string &returnType, + const std::function<void()> &body, + bool gen_jvmstatic = false) { + // Generates Kotlin function + // e.g.: + // fun path(j: Int): Vec3 { + // return path(Vec3(), j) + // } + auto noreturn = returnType.empty(); + writer.SetValue("name", name); + writer.SetValue("params", params); + writer.SetValue("return_type", noreturn ? "" : ": " + returnType); + GenerateJvmStaticAnnotation(writer, gen_jvmstatic); + writer += "fun {{name}}({{params}}) {{return_type}} {"; + writer.IncrementIdentLevel(); + body(); + writer.DecrementIdentLevel(); + writer += "}"; + } + + static void GenerateFunOneLine(CodeWriter &writer, const std::string &name, + const std::string ¶ms, + const std::string &returnType, + const std::function<void()> &body, + bool gen_jvmstatic = false) { + // Generates Kotlin function + // e.g.: + // fun path(j: Int): Vec3 = return path(Vec3(), j) + writer.SetValue("name", name); + writer.SetValue("params", params); + writer.SetValue("return_type_p", + returnType.empty() ? "" : " : " + returnType); + GenerateJvmStaticAnnotation(writer, gen_jvmstatic); + writer += "fun {{name}}({{params}}){{return_type_p}} = \\"; + body(); + } + + static void GenerateOverrideFun(CodeWriter &writer, const std::string &name, + const std::string ¶ms, + const std::string &returnType, + const std::function<void()> &body) { + // Generates Kotlin function + // e.g.: + // override fun path(j: Int): Vec3 = return path(Vec3(), j) + writer += "override \\"; + GenerateFun(writer, name, params, returnType, body); + } + + static void GenerateOverrideFunOneLine(CodeWriter &writer, + const std::string &name, + const std::string ¶ms, + const std::string &returnType, + const std::string &statement) { + // Generates Kotlin function + // e.g.: + // override fun path(j: Int): Vec3 = return path(Vec3(), j) + writer.SetValue("name", name); + writer.SetValue("params", params); + writer.SetValue("return_type", + returnType.empty() ? "" : " : " + returnType); + writer += "override fun {{name}}({{params}}){{return_type}} = \\"; + writer += statement; + } + + static std::string OffsetWrapperOneLine(const std::string &offset, + const std::string &found, + const std::string ¬_found) { + return "val o = __offset(" + offset + "); return if (o != 0) " + found + + " else " + not_found; + } + + static void OffsetWrapper(CodeWriter &code, const std::string &offset, + const std::function<void()> &found, + const std::function<void()> ¬_found) { + code += "val o = __offset(" + offset + ")"; + code += "return if (o != 0) {"; + code.IncrementIdentLevel(); + found(); + code.DecrementIdentLevel(); + code += "} else {"; + code.IncrementIdentLevel(); + not_found(); + code.DecrementIdentLevel(); + code += "}"; + } + + static std::string Indirect(const std::string &index, bool fixed) { + // We apply __indirect() and struct is not fixed. + if (!fixed) return "__indirect(" + index + ")"; + return index; + } + + static std::string NotFoundReturn(BaseType el) { + switch (el) { + case BASE_TYPE_FLOAT: return "0.0f"; + case BASE_TYPE_DOUBLE: return "0.0"; + case BASE_TYPE_BOOL: return "false"; + case BASE_TYPE_LONG: + case BASE_TYPE_INT: + case BASE_TYPE_CHAR: + case BASE_TYPE_SHORT: return "0"; + case BASE_TYPE_UINT: + case BASE_TYPE_UCHAR: + case BASE_TYPE_USHORT: + case BASE_TYPE_UTYPE: return "0u"; + case BASE_TYPE_ULONG: return "0uL"; + default: return "null"; + } + } + + // Prepend @JvmStatic to methods in companion object. + static void GenerateJvmStaticAnnotation(CodeWriter &code, + bool gen_jvmstatic) { + if (gen_jvmstatic) { code += "@JvmStatic"; } + } + + // This tracks the current namespace used to determine if a type need to be + // prefixed by its namespace + const Namespace *cur_name_space_; +}; +} // namespace kotlin + +bool GenerateKotlin(const Parser &parser, const std::string &path, + const std::string &file_name) { + kotlin::KotlinGenerator generator(parser, path, file_name); + return generator.generate(); +} +} // namespace flatbuffers diff --git a/contrib/libs/flatbuffers/src/idl_gen_lobster.cpp b/contrib/libs/flatbuffers/src/idl_gen_lobster.cpp new file mode 100644 index 0000000000..6fdd6dc26a --- /dev/null +++ b/contrib/libs/flatbuffers/src/idl_gen_lobster.cpp @@ -0,0 +1,391 @@ +/* + * Copyright 2018 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <string> +#include <unordered_set> + +#include "flatbuffers/code_generators.h" +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +namespace flatbuffers { +namespace lobster { + +class LobsterGenerator : public BaseGenerator { + public: + LobsterGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name, "" /* not used */, "_", + "lobster") { + static const char *const keywords[] = { + "nil", "true", "false", "return", "struct", "class", + "import", "int", "float", "string", "any", "def", + "is", "from", "program", "private", "coroutine", "resource", + "enum", "typeof", "var", "let", "pakfile", "switch", + "case", "default", "namespace", "not", "and", "or", + "bool", + }; + keywords_.insert(std::begin(keywords), std::end(keywords)); + } + + std::string EscapeKeyword(const std::string &name) const { + return keywords_.find(name) == keywords_.end() ? name : name + "_"; + } + + std::string NormalizedName(const Definition &definition) const { + return EscapeKeyword(definition.name); + } + + std::string NormalizedName(const EnumVal &ev) const { + return EscapeKeyword(ev.name); + } + + std::string NamespacedName(const Definition &def) { + return WrapInNameSpace(def.defined_namespace, NormalizedName(def)); + } + + std::string GenTypeName(const Type &type) { + auto bits = NumToString(SizeOf(type.base_type) * 8); + if (IsInteger(type.base_type)) return "int" + bits; + if (IsFloat(type.base_type)) return "float" + bits; + if (IsString(type)) return "string"; + if (type.base_type == BASE_TYPE_STRUCT) return "table"; + return "none"; + } + + std::string LobsterType(const Type &type) { + if (IsFloat(type.base_type)) return "float"; + if (IsScalar(type.base_type) && type.enum_def) + return NormalizedName(*type.enum_def); + if (!IsScalar(type.base_type)) return "flatbuffers_offset"; + return "int"; + } + + // Returns the method name for use with add/put calls. + std::string GenMethod(const Type &type) { + return IsScalar(type.base_type) + ? MakeCamel(GenTypeBasic(type)) + : (IsStruct(type) ? "Struct" : "UOffsetTRelative"); + } + + // This uses Python names for now.. + std::string GenTypeBasic(const Type &type) { + // clang-format off + static const char *ctypename[] = { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, ...) \ + #PTYPE, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + }; + // clang-format on + return ctypename[type.base_type]; + } + + // Generate a struct field, conditioned on its child type(s). + void GenStructAccessor(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + GenComment(field.doc_comment, code_ptr, nullptr, " "); + std::string &code = *code_ptr; + auto offsets = NumToString(field.value.offset); + auto def = " def " + NormalizedName(field); + if (IsScalar(field.value.type.base_type)) { + std::string acc; + if (struct_def.fixed) { + acc = "buf_.read_" + GenTypeName(field.value.type) + "_le(pos_ + " + + offsets + ")"; + + } else { + auto defval = field.IsOptional() ? "0" : field.value.constant; + acc = "buf_.flatbuffers_field_" + GenTypeName(field.value.type) + + "(pos_, " + offsets + ", " + defval + ")"; + } + if (field.value.type.enum_def) + acc = NormalizedName(*field.value.type.enum_def) + "(" + acc + ")"; + if (field.IsOptional()) + acc += ", buf_.flatbuffers_field_present(pos_, " + offsets + ")"; + code += def + "():\n return " + acc + "\n"; + return; + } + switch (field.value.type.base_type) { + case BASE_TYPE_STRUCT: { + auto name = NamespacedName(*field.value.type.struct_def); + code += def + "():\n "; + if (struct_def.fixed) { + code += "return " + name + "{ buf_, pos_ + " + offsets + " }\n"; + } else { + code += std::string("let o = buf_.flatbuffers_field_") + + (field.value.type.struct_def->fixed ? "struct" : "table") + + "(pos_, " + offsets + ")\n return if o: " + name + + " { buf_, o } else: nil\n"; + } + break; + } + case BASE_TYPE_STRING: + code += def + + "():\n return buf_.flatbuffers_field_string(pos_, " + + offsets + ")\n"; + break; + case BASE_TYPE_VECTOR: { + auto vectortype = field.value.type.VectorType(); + code += def + "(i:int):\n return "; + if (vectortype.base_type == BASE_TYPE_STRUCT) { + auto start = "buf_.flatbuffers_field_vector(pos_, " + offsets + + ") + i * " + NumToString(InlineSize(vectortype)); + if (!(vectortype.struct_def->fixed)) { + start = "buf_.flatbuffers_indirect(" + start + ")"; + } + code += NamespacedName(*field.value.type.struct_def) + " { buf_, " + + start + " }\n"; + } else { + if (IsString(vectortype)) + code += "buf_.flatbuffers_string"; + else + code += "buf_.read_" + GenTypeName(vectortype) + "_le"; + code += "(buf_.flatbuffers_field_vector(pos_, " + offsets + + ") + i * " + NumToString(InlineSize(vectortype)) + ")\n"; + } + break; + } + case BASE_TYPE_UNION: { + for (auto it = field.value.type.enum_def->Vals().begin(); + it != field.value.type.enum_def->Vals().end(); ++it) { + auto &ev = **it; + if (ev.IsNonZero()) { + code += def + "_as_" + ev.name + "():\n return " + + NamespacedName(*ev.union_type.struct_def) + + " { buf_, buf_.flatbuffers_field_table(pos_, " + offsets + + ") }\n"; + } + } + break; + } + default: FLATBUFFERS_ASSERT(0); + } + if (IsVector(field.value.type)) { + code += def + + "_length():\n return " + "buf_.flatbuffers_field_vector_len(pos_, " + + offsets + ")\n"; + } + } + + // Generate table constructors, conditioned on its members' types. + void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "struct " + NormalizedName(struct_def) + + "Builder:\n b_:flatbuffers_builder\n"; + code += " def start():\n b_.StartObject(" + + NumToString(struct_def.fields.vec.size()) + + ")\n return this\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + auto offset = it - struct_def.fields.vec.begin(); + code += " def add_" + NormalizedName(field) + "(" + + NormalizedName(field) + ":" + LobsterType(field.value.type) + + "):\n b_.Prepend" + GenMethod(field.value.type) + "Slot(" + + NumToString(offset) + ", " + NormalizedName(field); + if (IsScalar(field.value.type.base_type) && !field.IsOptional()) + code += ", " + field.value.constant; + code += ")\n return this\n"; + } + code += " def end():\n return b_.EndObject()\n\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + if (IsVector(field.value.type)) { + code += "def " + NormalizedName(struct_def) + "Start" + + MakeCamel(NormalizedName(field)) + + "Vector(b_:flatbuffers_builder, n_:int):\n b_.StartVector("; + auto vector_type = field.value.type.VectorType(); + auto alignment = InlineAlignment(vector_type); + auto elem_size = InlineSize(vector_type); + code += + NumToString(elem_size) + ", n_, " + NumToString(alignment) + ")\n"; + if (vector_type.base_type != BASE_TYPE_STRUCT || + !vector_type.struct_def->fixed) { + code += "def " + NormalizedName(struct_def) + "Create" + + MakeCamel(NormalizedName(field)) + + "Vector(b_:flatbuffers_builder, v_:[" + + LobsterType(vector_type) + "]):\n b_.StartVector(" + + NumToString(elem_size) + ", v_.length, " + + NumToString(alignment) + ")\n reverse(v_) e_: b_.Prepend" + + GenMethod(vector_type) + + "(e_)\n return b_.EndVector(v_.length)\n"; + } + code += "\n"; + } + } + } + + void GenStructPreDecl(const StructDef &struct_def, std::string *code_ptr) { + if (struct_def.generated) return; + std::string &code = *code_ptr; + CheckNameSpace(struct_def, &code); + code += "class " + NormalizedName(struct_def) + "\n\n"; + } + + // Generate struct or table methods. + void GenStruct(const StructDef &struct_def, std::string *code_ptr) { + if (struct_def.generated) return; + std::string &code = *code_ptr; + CheckNameSpace(struct_def, &code); + GenComment(struct_def.doc_comment, code_ptr, nullptr, ""); + code += "class " + NormalizedName(struct_def) + " : flatbuffers_handle\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + GenStructAccessor(struct_def, field, code_ptr); + } + code += "\n"; + if (!struct_def.fixed) { + // Generate a special accessor for the table that has been declared as + // the root type. + code += "def GetRootAs" + NormalizedName(struct_def) + + "(buf:string): return " + NormalizedName(struct_def) + + " { buf, buf.flatbuffers_indirect(0) }\n\n"; + } + if (struct_def.fixed) { + // create a struct constructor function + GenStructBuilder(struct_def, code_ptr); + } else { + // Create a set of functions that allow table construction. + GenTableBuilders(struct_def, code_ptr); + } + } + + // Generate enum declarations. + void GenEnum(const EnumDef &enum_def, std::string *code_ptr) { + if (enum_def.generated) return; + std::string &code = *code_ptr; + CheckNameSpace(enum_def, &code); + GenComment(enum_def.doc_comment, code_ptr, nullptr, ""); + code += "enum " + NormalizedName(enum_def) + ":\n"; + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + auto &ev = **it; + GenComment(ev.doc_comment, code_ptr, nullptr, " "); + code += " " + enum_def.name + "_" + NormalizedName(ev) + " = " + + enum_def.ToString(ev) + "\n"; + } + code += "\n"; + } + + // Recursively generate arguments for a constructor, to deal with nested + // structs. + void StructBuilderArgs(const StructDef &struct_def, const char *nameprefix, + std::string *code_ptr) { + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (IsStruct(field.value.type)) { + // Generate arguments for a struct inside a struct. To ensure names + // don't clash, and to make it obvious these arguments are constructing + // a nested struct, prefix the name with the field name. + StructBuilderArgs(*field.value.type.struct_def, + (nameprefix + (NormalizedName(field) + "_")).c_str(), + code_ptr); + } else { + std::string &code = *code_ptr; + code += ", " + (nameprefix + NormalizedName(field)) + ":" + + LobsterType(field.value.type); + } + } + } + + // Recursively generate struct construction statements and instert manual + // padding. + void StructBuilderBody(const StructDef &struct_def, const char *nameprefix, + std::string *code_ptr) { + std::string &code = *code_ptr; + code += " b_.Prep(" + NumToString(struct_def.minalign) + ", " + + NumToString(struct_def.bytesize) + ")\n"; + for (auto it = struct_def.fields.vec.rbegin(); + it != struct_def.fields.vec.rend(); ++it) { + auto &field = **it; + if (field.padding) + code += " b_.Pad(" + NumToString(field.padding) + ")\n"; + if (IsStruct(field.value.type)) { + StructBuilderBody(*field.value.type.struct_def, + (nameprefix + (NormalizedName(field) + "_")).c_str(), + code_ptr); + } else { + code += " b_.Prepend" + GenMethod(field.value.type) + "(" + + nameprefix + NormalizedName(field) + ")\n"; + } + } + } + + // Create a struct with a builder and the struct's arguments. + void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + code += + "def Create" + NormalizedName(struct_def) + "(b_:flatbuffers_builder"; + StructBuilderArgs(struct_def, "", code_ptr); + code += "):\n"; + StructBuilderBody(struct_def, "", code_ptr); + code += " return b_.Offset()\n\n"; + } + + void CheckNameSpace(const Definition &def, std::string *code_ptr) { + auto ns = GetNameSpace(def); + if (ns == current_namespace_) return; + current_namespace_ = ns; + std::string &code = *code_ptr; + code += "namespace " + ns + "\n\n"; + } + + bool generate() { + std::string code; + code += std::string("// ") + FlatBuffersGeneratedWarning() + + "\nimport flatbuffers\n\n"; + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + auto &enum_def = **it; + GenEnum(enum_def, &code); + } + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + auto &struct_def = **it; + GenStructPreDecl(struct_def, &code); + } + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + auto &struct_def = **it; + GenStruct(struct_def, &code); + } + return SaveFile(GeneratedFileName(path_, file_name_, parser_.opts).c_str(), + code, false); + } + + private: + std::unordered_set<std::string> keywords_; + std::string current_namespace_; +}; + +} // namespace lobster + +bool GenerateLobster(const Parser &parser, const std::string &path, + const std::string &file_name) { + lobster::LobsterGenerator generator(parser, path, file_name); + return generator.generate(); +} + +} // namespace flatbuffers diff --git a/contrib/libs/flatbuffers/src/idl_gen_lua.cpp b/contrib/libs/flatbuffers/src/idl_gen_lua.cpp new file mode 100644 index 0000000000..9efc435e24 --- /dev/null +++ b/contrib/libs/flatbuffers/src/idl_gen_lua.cpp @@ -0,0 +1,745 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// independent from idl_parser, since this code is not needed for most clients + +#include <string> +#include <unordered_set> + +#include "flatbuffers/code_generators.h" +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +namespace flatbuffers { +namespace lua { + +// Hardcode spaces per indentation. +const CommentConfig def_comment = { nullptr, "--", nullptr }; +const char *Indent = " "; +const char *Comment = "-- "; +const char *End = "end\n"; +const char *EndFunc = "end\n"; +const char *SelfData = "self.view"; +const char *SelfDataPos = "self.view.pos"; +const char *SelfDataBytes = "self.view.bytes"; + +class LuaGenerator : public BaseGenerator { + public: + LuaGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name, "" /* not used */, + "" /* not used */, "lua") { + static const char *const keywords[] = { + "and", "break", "do", "else", "elseif", "end", "false", "for", + "function", "goto", "if", "in", "local", "nil", "not", "or", + "repeat", "return", "then", "true", "until", "while" + }; + keywords_.insert(std::begin(keywords), std::end(keywords)); + } + + // Most field accessors need to retrieve and test the field offset first, + // this is the prefix code for that. + std::string OffsetPrefix(const FieldDef &field) { + return std::string(Indent) + "local o = " + SelfData + ":Offset(" + + NumToString(field.value.offset) + ")\n" + Indent + + "if o ~= 0 then\n"; + } + + // Begin a class declaration. + void BeginClass(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "local " + NormalizedName(struct_def) + " = {} -- the module\n"; + code += "local " + NormalizedMetaName(struct_def) + + " = {} -- the class metatable\n"; + code += "\n"; + } + + // Begin enum code with a class declaration. + void BeginEnum(const std::string &class_name, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "local " + class_name + " = {\n"; + } + + std::string EscapeKeyword(const std::string &name) const { + return keywords_.find(name) == keywords_.end() ? name : "_" + name; + } + + std::string NormalizedName(const Definition &definition) const { + return EscapeKeyword(definition.name); + } + + std::string NormalizedName(const EnumVal &ev) const { + return EscapeKeyword(ev.name); + } + + std::string NormalizedMetaName(const Definition &definition) const { + return EscapeKeyword(definition.name) + "_mt"; + } + + // A single enum member. + void EnumMember(const EnumDef &enum_def, const EnumVal &ev, + std::string *code_ptr) { + std::string &code = *code_ptr; + code += std::string(Indent) + NormalizedName(ev) + " = " + + enum_def.ToString(ev) + ",\n"; + } + + // End enum code. + void EndEnum(std::string *code_ptr) { + std::string &code = *code_ptr; + code += "}\n"; + } + + void GenerateNewObjectPrototype(const StructDef &struct_def, + std::string *code_ptr) { + std::string &code = *code_ptr; + + code += "function " + NormalizedName(struct_def) + ".New()\n"; + code += std::string(Indent) + "local o = {}\n"; + code += std::string(Indent) + + "setmetatable(o, {__index = " + NormalizedMetaName(struct_def) + + "})\n"; + code += std::string(Indent) + "return o\n"; + code += EndFunc; + } + + // Initialize a new struct or table from existing data. + void NewRootTypeFromBuffer(const StructDef &struct_def, + std::string *code_ptr) { + std::string &code = *code_ptr; + + code += "function " + NormalizedName(struct_def) + ".GetRootAs" + + NormalizedName(struct_def) + "(buf, offset)\n"; + code += std::string(Indent) + "if type(buf) == \"string\" then\n"; + code += std::string(Indent) + Indent + + "buf = flatbuffers.binaryArray.New(buf)\n"; + code += std::string(Indent) + "end\n"; + code += std::string(Indent) + + "local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)\n"; + code += std::string(Indent) + "local o = " + NormalizedName(struct_def) + + ".New()\n"; + code += std::string(Indent) + "o:Init(buf, n + offset)\n"; + code += std::string(Indent) + "return o\n"; + code += EndFunc; + } + + // Initialize an existing object with other data, to avoid an allocation. + void InitializeExisting(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + + GenReceiver(struct_def, code_ptr); + code += "Init(buf, pos)\n"; + code += + std::string(Indent) + SelfData + " = flatbuffers.view.New(buf, pos)\n"; + code += EndFunc; + } + + // Get the length of a vector. + void GetVectorLen(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)) + "Length()\n"; + code += OffsetPrefix(field); + code += + std::string(Indent) + Indent + "return " + SelfData + ":VectorLen(o)\n"; + code += std::string(Indent) + End; + code += std::string(Indent) + "return 0\n"; + code += EndFunc; + } + + // Get the value of a struct's scalar. + void GetScalarFieldOfStruct(const StructDef &struct_def, + const FieldDef &field, std::string *code_ptr) { + std::string &code = *code_ptr; + std::string getter = GenGetter(field.value.type); + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "()\n"; + code += std::string(Indent) + "return " + getter; + code += std::string(SelfDataPos) + " + " + NumToString(field.value.offset) + + ")\n"; + code += EndFunc; + } + + // Get the value of a table's scalar. + void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + std::string getter = GenGetter(field.value.type); + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "()\n"; + code += OffsetPrefix(field); + getter += std::string("o + ") + SelfDataPos + ")"; + auto is_bool = field.value.type.base_type == BASE_TYPE_BOOL; + if (is_bool) { getter = "(" + getter + " ~= 0)"; } + code += std::string(Indent) + Indent + "return " + getter + "\n"; + code += std::string(Indent) + End; + std::string default_value; + if (is_bool) { + default_value = field.value.constant == "0" ? "false" : "true"; + } else { + default_value = field.value.constant; + } + code += std::string(Indent) + "return " + default_value + "\n"; + code += EndFunc; + } + + // Get a struct by initializing an existing struct. + // Specific to Struct. + void GetStructFieldOfStruct(const StructDef &struct_def, + const FieldDef &field, std::string *code_ptr) { + std::string &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "(obj)\n"; + code += std::string(Indent) + "obj:Init(" + SelfDataBytes + ", " + + SelfDataPos + " + "; + code += NumToString(field.value.offset) + ")\n"; + code += std::string(Indent) + "return obj\n"; + code += EndFunc; + } + + // Get a struct by initializing an existing struct. + // Specific to Table. + void GetStructFieldOfTable(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "()\n"; + code += OffsetPrefix(field); + if (field.value.type.struct_def->fixed) { + code += + std::string(Indent) + Indent + "local x = o + " + SelfDataPos + "\n"; + } else { + code += std::string(Indent) + Indent + "local x = " + SelfData + + ":Indirect(o + " + SelfDataPos + ")\n"; + } + code += std::string(Indent) + Indent + "local obj = require('" + + TypeNameWithNamespace(field) + "').New()\n"; + code += + std::string(Indent) + Indent + "obj:Init(" + SelfDataBytes + ", x)\n"; + code += std::string(Indent) + Indent + "return obj\n"; + code += std::string(Indent) + End; + code += EndFunc; + } + + // Get the value of a string. + void GetStringField(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "()\n"; + code += OffsetPrefix(field); + code += + std::string(Indent) + Indent + "return " + GenGetter(field.value.type); + code += std::string("o + ") + SelfDataPos + ")\n"; + code += std::string(Indent) + End; + code += EndFunc; + } + + // Get the value of a union from an object. + void GetUnionField(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)) + "()\n"; + code += OffsetPrefix(field); + + // TODO(rw): this works and is not the good way to it: + // bool is_native_table = TypeName(field) == "*flatbuffers.Table"; + // if (is_native_table) { + // code += std::string(Indent) + Indent + "from flatbuffers.table import + // Table\n"; + //} else { + // code += std::string(Indent) + Indent + + // code += "from ." + TypeName(field) + " import " + TypeName(field) + + // "\n"; + //} + code += + std::string(Indent) + Indent + + "local obj = " + "flatbuffers.view.New(require('flatbuffers.binaryarray').New(0), 0)\n"; + code += std::string(Indent) + Indent + GenGetter(field.value.type) + + "obj, o)\n"; + code += std::string(Indent) + Indent + "return obj\n"; + code += std::string(Indent) + End; + code += EndFunc; + } + + // Get the value of a vector's struct member. + void GetMemberOfVectorOfStruct(const StructDef &struct_def, + const FieldDef &field, std::string *code_ptr) { + std::string &code = *code_ptr; + auto vectortype = field.value.type.VectorType(); + + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "(j)\n"; + code += OffsetPrefix(field); + code += + std::string(Indent) + Indent + "local x = " + SelfData + ":Vector(o)\n"; + code += std::string(Indent) + Indent + "x = x + ((j-1) * "; + code += NumToString(InlineSize(vectortype)) + ")\n"; + if (!(vectortype.struct_def->fixed)) { + code += + std::string(Indent) + Indent + "x = " + SelfData + ":Indirect(x)\n"; + } + code += std::string(Indent) + Indent + "local obj = require('" + + TypeNameWithNamespace(field) + "').New()\n"; + code += + std::string(Indent) + Indent + "obj:Init(" + SelfDataBytes + ", x)\n"; + code += std::string(Indent) + Indent + "return obj\n"; + code += std::string(Indent) + End; + code += EndFunc; + } + + // Get the value of a vector's non-struct member. Uses a named return + // argument to conveniently set the zero value for the result. + void GetMemberOfVectorOfNonStruct(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + auto vectortype = field.value.type.VectorType(); + + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "(j)\n"; + code += OffsetPrefix(field); + code += + std::string(Indent) + Indent + "local a = " + SelfData + ":Vector(o)\n"; + code += std::string(Indent) + Indent; + code += "return " + GenGetter(field.value.type); + code += "a + ((j-1) * "; + code += NumToString(InlineSize(vectortype)) + "))\n"; + code += std::string(Indent) + End; + if (IsString(vectortype)) { + code += std::string(Indent) + "return ''\n"; + } else { + code += std::string(Indent) + "return 0\n"; + } + code += EndFunc; + } + + // Access a byte/ubyte vector as a string + void AccessByteVectorAsString(const StructDef &struct_def, + const FieldDef &field, std::string *code_ptr) { + std::string &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "AsString(start, stop)\n"; + code += std::string(Indent) + "return " + SelfData + ":VectorAsString(" + + NumToString(field.value.offset) + ", start, stop)\n"; + code += EndFunc; + } + + // Begin the creator function signature. + void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + + code += "function " + NormalizedName(struct_def) + ".Create" + + NormalizedName(struct_def); + code += "(builder"; + } + + // Recursively generate arguments for a constructor, to deal with nested + // structs. + void StructBuilderArgs(const StructDef &struct_def, const char *nameprefix, + std::string *code_ptr) { + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (IsStruct(field.value.type)) { + // Generate arguments for a struct inside a struct. To ensure names + // don't clash, and to make it obvious these arguments are constructing + // a nested struct, prefix the name with the field name. + StructBuilderArgs(*field.value.type.struct_def, + (nameprefix + (NormalizedName(field) + "_")).c_str(), + code_ptr); + } else { + std::string &code = *code_ptr; + code += std::string(", ") + nameprefix; + code += MakeCamel(NormalizedName(field), false); + } + } + } + + // End the creator function signature. + void EndBuilderArgs(std::string *code_ptr) { + std::string &code = *code_ptr; + code += ")\n"; + } + + // Recursively generate struct construction statements and instert manual + // padding. + void StructBuilderBody(const StructDef &struct_def, const char *nameprefix, + std::string *code_ptr) { + std::string &code = *code_ptr; + code += std::string(Indent) + "builder:Prep(" + + NumToString(struct_def.minalign) + ", "; + code += NumToString(struct_def.bytesize) + ")\n"; + for (auto it = struct_def.fields.vec.rbegin(); + it != struct_def.fields.vec.rend(); ++it) { + auto &field = **it; + if (field.padding) + code += std::string(Indent) + "builder:Pad(" + + NumToString(field.padding) + ")\n"; + if (IsStruct(field.value.type)) { + StructBuilderBody(*field.value.type.struct_def, + (nameprefix + (NormalizedName(field) + "_")).c_str(), + code_ptr); + } else { + code += + std::string(Indent) + "builder:Prepend" + GenMethod(field) + "("; + code += nameprefix + MakeCamel(NormalizedName(field), false) + ")\n"; + } + } + } + + void EndBuilderBody(std::string *code_ptr) { + std::string &code = *code_ptr; + code += std::string(Indent) + "return builder:Offset()\n"; + code += EndFunc; + } + + // Get the value of a table's starting offset. + void GetStartOfTable(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "function " + NormalizedName(struct_def) + ".Start"; + code += "(builder) "; + code += "builder:StartObject("; + code += NumToString(struct_def.fields.vec.size()); + code += ") end\n"; + } + + // Set the value of a table's field. + void BuildFieldOfTable(const StructDef &struct_def, const FieldDef &field, + const size_t offset, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "function " + NormalizedName(struct_def) + ".Add" + + MakeCamel(NormalizedName(field)); + code += "(builder, "; + code += MakeCamel(NormalizedName(field), false); + code += ") "; + code += "builder:Prepend"; + code += GenMethod(field) + "Slot("; + code += NumToString(offset) + ", "; + // todo: i don't need to cast in Lua, but am I missing something? + // if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) { + // code += "flatbuffers.N.UOffsetTFlags.py_type"; + // code += "("; + // code += MakeCamel(NormalizedName(field), false) + ")"; + // } else { + code += MakeCamel(NormalizedName(field), false); + // } + code += ", " + field.value.constant; + code += ") end\n"; + } + + // Set the value of one of the members of a table's vector. + void BuildVectorOfTable(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + code += "function " + NormalizedName(struct_def) + ".Start"; + code += MakeCamel(NormalizedName(field)); + code += "Vector(builder, numElems) return builder:StartVector("; + auto vector_type = field.value.type.VectorType(); + auto alignment = InlineAlignment(vector_type); + auto elem_size = InlineSize(vector_type); + code += NumToString(elem_size); + code += ", numElems, " + NumToString(alignment); + code += ") end\n"; + } + + // Get the offset of the end of a table. + void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "function " + NormalizedName(struct_def) + ".End"; + code += "(builder) "; + code += "return builder:EndObject() end\n"; + } + + // Generate the receiver for function signatures. + void GenReceiver(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "function " + NormalizedMetaName(struct_def) + ":"; + } + + // Generate a struct field, conditioned on its child type(s). + void GenStructAccessor(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + GenComment(field.doc_comment, code_ptr, &def_comment); + if (IsScalar(field.value.type.base_type)) { + if (struct_def.fixed) { + GetScalarFieldOfStruct(struct_def, field, code_ptr); + } else { + GetScalarFieldOfTable(struct_def, field, code_ptr); + } + } else { + switch (field.value.type.base_type) { + case BASE_TYPE_STRUCT: + if (struct_def.fixed) { + GetStructFieldOfStruct(struct_def, field, code_ptr); + } else { + GetStructFieldOfTable(struct_def, field, code_ptr); + } + break; + case BASE_TYPE_STRING: + GetStringField(struct_def, field, code_ptr); + break; + case BASE_TYPE_VECTOR: { + auto vectortype = field.value.type.VectorType(); + if (vectortype.base_type == BASE_TYPE_STRUCT) { + GetMemberOfVectorOfStruct(struct_def, field, code_ptr); + } else { + GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr); + if (vectortype.base_type == BASE_TYPE_CHAR || + vectortype.base_type == BASE_TYPE_UCHAR) { + AccessByteVectorAsString(struct_def, field, code_ptr); + } + } + break; + } + case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break; + default: FLATBUFFERS_ASSERT(0); + } + } + if (IsVector(field.value.type)) { + GetVectorLen(struct_def, field, code_ptr); + } + } + + // Generate table constructors, conditioned on its members' types. + void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) { + GetStartOfTable(struct_def, code_ptr); + + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + + auto offset = it - struct_def.fields.vec.begin(); + BuildFieldOfTable(struct_def, field, offset, code_ptr); + if (IsVector(field.value.type)) { + BuildVectorOfTable(struct_def, field, code_ptr); + } + } + + GetEndOffsetOnTable(struct_def, code_ptr); + } + + // Generate struct or table methods. + void GenStruct(const StructDef &struct_def, std::string *code_ptr) { + if (struct_def.generated) return; + + GenComment(struct_def.doc_comment, code_ptr, &def_comment); + BeginClass(struct_def, code_ptr); + + GenerateNewObjectPrototype(struct_def, code_ptr); + + if (!struct_def.fixed) { + // Generate a special accessor for the table that has been declared as + // the root type. + NewRootTypeFromBuffer(struct_def, code_ptr); + } + + // Generate the Init method that sets the field in a pre-existing + // accessor object. This is to allow object reuse. + InitializeExisting(struct_def, code_ptr); + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + + GenStructAccessor(struct_def, field, code_ptr); + } + + if (struct_def.fixed) { + // create a struct constructor function + GenStructBuilder(struct_def, code_ptr); + } else { + // Create a set of functions that allow table construction. + GenTableBuilders(struct_def, code_ptr); + } + } + + // Generate enum declarations. + void GenEnum(const EnumDef &enum_def, std::string *code_ptr) { + if (enum_def.generated) return; + + GenComment(enum_def.doc_comment, code_ptr, &def_comment); + BeginEnum(NormalizedName(enum_def), code_ptr); + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + auto &ev = **it; + GenComment(ev.doc_comment, code_ptr, &def_comment, Indent); + EnumMember(enum_def, ev, code_ptr); + } + EndEnum(code_ptr); + } + + // Returns the function name that is able to read a value of the given type. + std::string GenGetter(const Type &type) { + switch (type.base_type) { + case BASE_TYPE_STRING: return std::string(SelfData) + ":String("; + case BASE_TYPE_UNION: return std::string(SelfData) + ":Union("; + case BASE_TYPE_VECTOR: return GenGetter(type.VectorType()); + default: + return std::string(SelfData) + ":Get(flatbuffers.N." + + MakeCamel(GenTypeGet(type)) + ", "; + } + } + + // Returns the method name for use with add/put calls. + std::string GenMethod(const FieldDef &field) { + return IsScalar(field.value.type.base_type) + ? MakeCamel(GenTypeBasic(field.value.type)) + : (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative"); + } + + std::string GenTypeBasic(const Type &type) { + // clang-format off + static const char *ctypename[] = { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, ...) \ + #PTYPE, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + }; + // clang-format on + return ctypename[type.base_type]; + } + + std::string GenTypePointer(const Type &type) { + switch (type.base_type) { + case BASE_TYPE_STRING: return "string"; + case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType()); + case BASE_TYPE_STRUCT: return type.struct_def->name; + case BASE_TYPE_UNION: + // fall through + default: return "*flatbuffers.Table"; + } + } + + std::string GenTypeGet(const Type &type) { + return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type); + } + + std::string GetNamespace(const Type &type) { + return type.struct_def->defined_namespace->GetFullyQualifiedName( + type.struct_def->name); + } + + std::string TypeName(const FieldDef &field) { + return GenTypeGet(field.value.type); + } + + std::string TypeNameWithNamespace(const FieldDef &field) { + return GetNamespace(field.value.type); + } + + // Create a struct with a builder and the struct's arguments. + void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) { + BeginBuilderArgs(struct_def, code_ptr); + StructBuilderArgs(struct_def, "", code_ptr); + EndBuilderArgs(code_ptr); + + StructBuilderBody(struct_def, "", code_ptr); + EndBuilderBody(code_ptr); + } + + bool generate() { + if (!generateEnums()) return false; + if (!generateStructs()) return false; + return true; + } + + private: + bool generateEnums() { + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + auto &enum_def = **it; + std::string enumcode; + GenEnum(enum_def, &enumcode); + if (!SaveType(enum_def, enumcode, false)) return false; + } + return true; + } + + bool generateStructs() { + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + auto &struct_def = **it; + std::string declcode; + GenStruct(struct_def, &declcode); + if (!SaveType(struct_def, declcode, true)) return false; + } + return true; + } + + // Begin by declaring namespace and imports. + void BeginFile(const std::string &name_space_name, const bool needs_imports, + std::string *code_ptr) { + std::string &code = *code_ptr; + code += std::string(Comment) + FlatBuffersGeneratedWarning() + "\n\n"; + code += std::string(Comment) + "namespace: " + name_space_name + "\n\n"; + if (needs_imports) { + code += "local flatbuffers = require('flatbuffers')\n\n"; + } + } + + // Save out the generated code for a Lua Table type. + bool SaveType(const Definition &def, const std::string &classcode, + bool needs_imports) { + if (!classcode.length()) return true; + + std::string namespace_dir = path_; + auto &namespaces = def.defined_namespace->components; + for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { + if (it != namespaces.begin()) namespace_dir += kPathSeparator; + namespace_dir += *it; + // std::string init_py_filename = namespace_dir + "/__init__.py"; + // SaveFile(init_py_filename.c_str(), "", false); + } + + std::string code = ""; + BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code); + code += classcode; + code += "\n"; + code += + "return " + NormalizedName(def) + " " + Comment + "return the module"; + std::string filename = + NamespaceDir(*def.defined_namespace) + NormalizedName(def) + ".lua"; + return SaveFile(filename.c_str(), code, false); + } + + private: + std::unordered_set<std::string> keywords_; +}; + +} // namespace lua + +bool GenerateLua(const Parser &parser, const std::string &path, + const std::string &file_name) { + lua::LuaGenerator generator(parser, path, file_name); + return generator.generate(); +} + +} // namespace flatbuffers diff --git a/contrib/libs/flatbuffers/src/idl_gen_php.cpp b/contrib/libs/flatbuffers/src/idl_gen_php.cpp new file mode 100644 index 0000000000..dd3ed68189 --- /dev/null +++ b/contrib/libs/flatbuffers/src/idl_gen_php.cpp @@ -0,0 +1,939 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// independent from idl_parser, since this code is not needed for most clients + +#include <string> + +#include "flatbuffers/code_generators.h" +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +namespace flatbuffers { +namespace php { +// Hardcode spaces per indentation. +const std::string Indent = " "; +class PhpGenerator : public BaseGenerator { + public: + PhpGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name, "\\", "\\", "php") {} + bool generate() { + if (!GenerateEnums()) return false; + if (!GenerateStructs()) return false; + return true; + } + + private: + bool GenerateEnums() { + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + auto &enum_def = **it; + std::string enumcode; + GenEnum(enum_def, &enumcode); + if (!SaveType(enum_def, enumcode, false)) return false; + } + return true; + } + + bool GenerateStructs() { + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + auto &struct_def = **it; + std::string declcode; + GenStruct(struct_def, &declcode); + if (!SaveType(struct_def, declcode, true)) return false; + } + return true; + } + + // Begin by declaring namespace and imports. + void BeginFile(const std::string &name_space_name, const bool needs_imports, + std::string *code_ptr) { + auto &code = *code_ptr; + code += "<?php\n"; + code = code + "// " + FlatBuffersGeneratedWarning() + "\n\n"; + + if (!name_space_name.empty()) { + code += "namespace " + name_space_name + ";\n\n"; + } + + if (needs_imports) { + code += "use \\Google\\FlatBuffers\\Struct;\n"; + code += "use \\Google\\FlatBuffers\\Table;\n"; + code += "use \\Google\\FlatBuffers\\ByteBuffer;\n"; + code += "use \\Google\\FlatBuffers\\FlatBufferBuilder;\n"; + code += "\n"; + } + } + + // Save out the generated code for a Php Table type. + bool SaveType(const Definition &def, const std::string &classcode, + bool needs_imports) { + if (!classcode.length()) return true; + + std::string code = ""; + BeginFile(FullNamespace("\\", *def.defined_namespace), needs_imports, + &code); + code += classcode; + + std::string filename = + NamespaceDir(*def.defined_namespace) + def.name + ".php"; + return SaveFile(filename.c_str(), code, false); + } + + // Begin a class declaration. + static void BeginClass(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + if (struct_def.fixed) { + code += "class " + struct_def.name + " extends Struct\n"; + } else { + code += "class " + struct_def.name + " extends Table\n"; + } + code += "{\n"; + } + + static void EndClass(std::string *code_ptr) { + std::string &code = *code_ptr; + code += "}\n"; + } + + // Begin enum code with a class declaration. + static void BeginEnum(const std::string &class_name, std::string *code_ptr) { + std::string &code = *code_ptr; + code += "class " + class_name + "\n{\n"; + } + + // A single enum member. + static void EnumMember(const EnumDef &enum_def, const EnumVal &ev, + std::string *code_ptr) { + std::string &code = *code_ptr; + code += Indent + "const "; + code += ev.name; + code += " = "; + code += enum_def.ToString(ev) + ";\n"; + } + + // End enum code. + static void EndEnum(std::string *code_ptr) { + std::string &code = *code_ptr; + code += "}\n"; + } + + // Initialize a new struct or table from existing data. + static void NewRootTypeFromBuffer(const StructDef &struct_def, + std::string *code_ptr) { + std::string &code = *code_ptr; + + code += Indent + "/**\n"; + code += Indent + " * @param ByteBuffer $bb\n"; + code += Indent + " * @return " + struct_def.name + "\n"; + code += Indent + " */\n"; + code += Indent + "public static function getRootAs"; + code += struct_def.name; + code += "(ByteBuffer $bb)\n"; + code += Indent + "{\n"; + + code += Indent + Indent + "$obj = new " + struct_def.name + "();\n"; + code += Indent + Indent; + code += "return ($obj->init($bb->getInt($bb->getPosition())"; + code += " + $bb->getPosition(), $bb));\n"; + code += Indent + "}\n\n"; + } + + // Initialize an existing object with other data, to avoid an allocation. + static void InitializeExisting(const StructDef &struct_def, + std::string *code_ptr) { + std::string &code = *code_ptr; + + code += Indent + "/**\n"; + code += Indent + " * @param int $_i offset\n"; + code += Indent + " * @param ByteBuffer $_bb\n"; + code += Indent + " * @return " + struct_def.name + "\n"; + code += Indent + " **/\n"; + code += Indent + "public function init($_i, ByteBuffer $_bb)\n"; + code += Indent + "{\n"; + code += Indent + Indent + "$this->bb_pos = $_i;\n"; + code += Indent + Indent + "$this->bb = $_bb;\n"; + code += Indent + Indent + "return $this;\n"; + code += Indent + "}\n\n"; + } + + // Get the length of a vector. + static void GetVectorLen(const FieldDef &field, std::string *code_ptr) { + std::string &code = *code_ptr; + + code += Indent + "/**\n"; + code += Indent + " * @return int\n"; + code += Indent + " */\n"; + code += Indent + "public function get"; + code += MakeCamel(field.name) + "Length()\n"; + code += Indent + "{\n"; + code += Indent + Indent + "$o = $this->__offset("; + code += NumToString(field.value.offset) + ");\n"; + code += Indent + Indent; + code += "return $o != 0 ? $this->__vector_len($o) : 0;\n"; + code += Indent + "}\n\n"; + } + + // Get a [ubyte] vector as a byte array. + static void GetUByte(const FieldDef &field, std::string *code_ptr) { + std::string &code = *code_ptr; + + code += Indent + "/**\n"; + code += Indent + " * @return string\n"; + code += Indent + " */\n"; + code += Indent + "public function get"; + code += MakeCamel(field.name) + "Bytes()\n"; + code += Indent + "{\n"; + code += Indent + Indent + "return $this->__vector_as_bytes("; + code += NumToString(field.value.offset) + ");\n"; + code += Indent + "}\n\n"; + } + + // Get the value of a struct's scalar. + static void GetScalarFieldOfStruct(const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + std::string getter = GenGetter(field.value.type); + + code += Indent + "/**\n"; + code += Indent + " * @return "; + code += GenTypeGet(field.value.type) + "\n"; + code += Indent + " */\n"; + code += Indent + "public function " + getter; + code += MakeCamel(field.name) + "()\n"; + code += Indent + "{\n"; + code += Indent + Indent + "return "; + + code += "$this->bb->get"; + code += MakeCamel(GenTypeGet(field.value.type)); + code += "($this->bb_pos + "; + code += NumToString(field.value.offset) + ")"; + code += ";\n"; + + code += Indent + "}\n\n"; + } + + // Get the value of a table's scalar. + void GetScalarFieldOfTable(const FieldDef &field, std::string *code_ptr) { + std::string &code = *code_ptr; + + code += Indent + "/**\n"; + code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n"; + code += Indent + " */\n"; + code += Indent + "public function get"; + code += MakeCamel(field.name); + code += "()\n"; + code += Indent + "{\n"; + code += Indent + Indent + "$o = $this->__offset(" + + NumToString(field.value.offset) + ");\n" + Indent + Indent + + "return $o != 0 ? "; + code += "$this->bb->get"; + code += MakeCamel(GenTypeGet(field.value.type)) + "($o + $this->bb_pos)"; + code += " : " + GenDefaultValue(field.value) + ";\n"; + code += Indent + "}\n\n"; + } + + // Get a struct by initializing an existing struct. + // Specific to Struct. + void GetStructFieldOfStruct(const FieldDef &field, std::string *code_ptr) { + std::string &code = *code_ptr; + + code += Indent + "/**\n"; + code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n"; + code += Indent + " */\n"; + code += Indent + "public function get"; + code += MakeCamel(field.name) + "()\n"; + code += Indent + "{\n"; + code += Indent + Indent + "$obj = new "; + code += GenTypeGet(field.value.type) + "();\n"; + code += Indent + Indent + "$obj->init($this->bb_pos + "; + code += NumToString(field.value.offset) + ", $this->bb);"; + code += "\n" + Indent + Indent + "return $obj;\n"; + code += Indent + "}\n\n"; + } + + // Get a struct by initializing an existing struct. + // Specific to Table. + void GetStructFieldOfTable(const FieldDef &field, std::string *code_ptr) { + std::string &code = *code_ptr; + + code += Indent + "public function get"; + code += MakeCamel(field.name); + code += "()\n"; + code += Indent + "{\n"; + code += Indent + Indent + "$obj = new "; + code += MakeCamel(GenTypeGet(field.value.type)) + "();\n"; + code += Indent + Indent + "$o = $this->__offset(" + + NumToString(field.value.offset) + ");\n"; + code += Indent + Indent; + code += "return $o != 0 ? $obj->init("; + if (field.value.type.struct_def->fixed) { + code += "$o + $this->bb_pos, $this->bb) : "; + } else { + code += "$this->__indirect($o + $this->bb_pos), $this->bb) : "; + } + code += GenDefaultValue(field.value) + ";\n"; + code += Indent + "}\n\n"; + } + + // Get the value of a string. + void GetStringField(const FieldDef &field, std::string *code_ptr) { + std::string &code = *code_ptr; + code += Indent + "public function get"; + code += MakeCamel(field.name); + code += "()\n"; + code += Indent + "{\n"; + code += Indent + Indent + "$o = $this->__offset(" + + NumToString(field.value.offset) + ");\n"; + code += Indent + Indent; + code += "return $o != 0 ? $this->__string($o + $this->bb_pos) : "; + code += GenDefaultValue(field.value) + ";\n"; + code += Indent + "}\n\n"; + } + + // Get the value of a union from an object. + void GetUnionField(const FieldDef &field, std::string *code_ptr) { + std::string &code = *code_ptr; + + code += Indent + "/**\n"; + code += Indent + " * @return" + GenTypeBasic(field.value.type) + "\n"; + code += Indent + " */\n"; + code += Indent + "public function get"; + code += MakeCamel(field.name) + "($obj)\n"; + code += Indent + "{\n"; + code += Indent + Indent + "$o = $this->__offset(" + + NumToString(field.value.offset) + ");\n"; + code += Indent + Indent; + code += "return $o != 0 ? $this->__union($obj, $o) : null;\n"; + code += Indent + "}\n\n"; + } + + // Get the value of a vector's struct member. + void GetMemberOfVectorOfStruct(const StructDef &struct_def, + const FieldDef &field, std::string *code_ptr) { + std::string &code = *code_ptr; + auto vectortype = field.value.type.VectorType(); + + code += Indent + "/**\n"; + code += Indent + " * @return" + GenTypeBasic(field.value.type) + "\n"; + code += Indent + " */\n"; + code += Indent + "public function get"; + code += MakeCamel(field.name); + code += "($j)\n"; + code += Indent + "{\n"; + code += Indent + Indent + "$o = $this->__offset(" + + NumToString(field.value.offset) + ");\n"; + code += Indent + Indent + "$obj = new "; + code += MakeCamel(GenTypeGet(field.value.type)) + "();\n"; + + switch (field.value.type.base_type) { + case BASE_TYPE_STRUCT: + if (struct_def.fixed) { + code += Indent + Indent; + code += "return $o != 0 ? $obj->init($this->bb_pos +" + + NumToString(field.value.offset) + ", $this->bb) : null;\n"; + } else { + code += Indent + Indent + "return $o != 0 ? $obj->init("; + code += field.value.type.struct_def->fixed + ? "$o + $this->bb_pos" + : "$this->__indirect($o + $this->bb_pos)"; + code += ", $this->bb) : null;\n"; + } + break; + case BASE_TYPE_STRING: + code += "// base_type_string\n"; + // TODO(chobie): do we need this? + break; + case BASE_TYPE_VECTOR: + if (vectortype.base_type == BASE_TYPE_STRUCT) { + code += Indent + Indent + "return $o != 0 ? $obj->init("; + if (vectortype.struct_def->fixed) { + code += "$this->__vector($o) + $j *"; + code += NumToString(InlineSize(vectortype)); + } else { + code += "$this->__indirect($this->__vector($o) + $j * "; + code += NumToString(InlineSize(vectortype)) + ")"; + } + code += ", $this->bb) : null;\n"; + } + break; + case BASE_TYPE_UNION: + code += Indent + Indent + "return $o != 0 ? $this->"; + code += GenGetter(field.value.type) + "($obj, $o); null;\n"; + break; + default: break; + } + + code += Indent + "}\n\n"; + } + + // Get the value of a vector's non-struct member. Uses a named return + // argument to conveniently set the zero value for the result. + void GetMemberOfVectorOfNonStruct(const FieldDef &field, + std::string *code_ptr) { + std::string &code = *code_ptr; + auto vectortype = field.value.type.VectorType(); + + code += Indent + "/**\n"; + code += Indent + " * @param int offset\n"; + code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n"; + code += Indent + " */\n"; + code += Indent + "public function get"; + code += MakeCamel(field.name); + code += "($j)\n"; + code += Indent + "{\n"; + code += Indent + Indent + "$o = $this->__offset(" + + NumToString(field.value.offset) + ");\n"; + + if (IsString(field.value.type.VectorType())) { + code += Indent + Indent; + code += "return $o != 0 ? $this->__string($this->__vector($o) + $j * "; + code += NumToString(InlineSize(vectortype)) + ") : "; + code += GenDefaultValue(field.value) + ";\n"; + } else { + code += Indent + Indent + "return $o != 0 ? $this->bb->get"; + code += MakeCamel(GenTypeGet(field.value.type)); + code += "($this->__vector($o) + $j * "; + code += NumToString(InlineSize(vectortype)) + ") : "; + code += GenDefaultValue(field.value) + ";\n"; + } + code += Indent + "}\n\n"; + } + + // Get the value of a vector's union member. Uses a named return + // argument to conveniently set the zero value for the result. + void GetMemberOfVectorOfUnion(const FieldDef &field, std::string *code_ptr) { + std::string &code = *code_ptr; + auto vectortype = field.value.type.VectorType(); + + code += Indent + "/**\n"; + code += Indent + " * @param int offset\n"; + code += Indent + " * @return " + GenTypeGet(field.value.type) + "\n"; + code += Indent + " */\n"; + code += Indent + "public function get"; + code += MakeCamel(field.name); + code += "($j, $obj)\n"; + code += Indent + "{\n"; + code += Indent + Indent + "$o = $this->__offset(" + + NumToString(field.value.offset) + ");\n"; + code += Indent + Indent + "return $o != 0 ? "; + code += "$this->__union($obj, $this->__vector($o) + $j * "; + code += NumToString(InlineSize(vectortype)) + " - $this->bb_pos) : null;\n"; + code += Indent + "}\n\n"; + } + + // Recursively generate arguments for a constructor, to deal with nested + // structs. + static void StructBuilderArgs(const StructDef &struct_def, + const char *nameprefix, std::string *code_ptr) { + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (IsStruct(field.value.type)) { + // Generate arguments for a struct inside a struct. To ensure names + // don't clash, and to make it obvious + // these arguments are constructing + // a nested struct, prefix the name with the field name. + StructBuilderArgs(*field.value.type.struct_def, + (nameprefix + (field.name + "_")).c_str(), code_ptr); + } else { + std::string &code = *code_ptr; + code += std::string(", $") + nameprefix; + code += MakeCamel(field.name, false); + } + } + } + + // Recursively generate struct construction statements and instert manual + // padding. + static void StructBuilderBody(const StructDef &struct_def, + const char *nameprefix, std::string *code_ptr) { + std::string &code = *code_ptr; + code += Indent + Indent + "$builder->prep("; + code += NumToString(struct_def.minalign) + ", "; + code += NumToString(struct_def.bytesize) + ");\n"; + for (auto it = struct_def.fields.vec.rbegin(); + it != struct_def.fields.vec.rend(); ++it) { + auto &field = **it; + if (field.padding) { + code += Indent + Indent + "$builder->pad("; + code += NumToString(field.padding) + ");\n"; + } + if (IsStruct(field.value.type)) { + StructBuilderBody(*field.value.type.struct_def, + (nameprefix + (field.name + "_")).c_str(), code_ptr); + } else { + code += Indent + Indent + "$builder->put" + GenMethod(field) + "($"; + code += nameprefix + MakeCamel(field.name, false) + ");\n"; + } + } + } + + // Get the value of a table's starting offset. + static void GetStartOfTable(const StructDef &struct_def, + std::string *code_ptr) { + std::string &code = *code_ptr; + + code += Indent + "/**\n"; + code += Indent + " * @param FlatBufferBuilder $builder\n"; + code += Indent + " * @return void\n"; + code += Indent + " */\n"; + code += Indent + "public static function start" + struct_def.name; + code += "(FlatBufferBuilder $builder)\n"; + code += Indent + "{\n"; + code += Indent + Indent + "$builder->StartObject("; + code += NumToString(struct_def.fields.vec.size()); + code += ");\n"; + code += Indent + "}\n\n"; + + code += Indent + "/**\n"; + code += Indent + " * @param FlatBufferBuilder $builder\n"; + code += Indent + " * @return " + struct_def.name + "\n"; + code += Indent + " */\n"; + code += Indent + "public static function create" + struct_def.name; + code += "(FlatBufferBuilder $builder, "; + + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + + if (field.deprecated) continue; + code += "$" + field.name; + if (it != struct_def.fields.vec.begin()) { code += ", "; } + } + code += ")\n"; + code += Indent + "{\n"; + code += Indent + Indent + "$builder->startObject("; + code += NumToString(struct_def.fields.vec.size()); + code += ");\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + + code += Indent + Indent + "self::add"; + code += MakeCamel(field.name) + "($builder, $" + field.name + ");\n"; + } + + code += Indent + Indent + "$o = $builder->endObject();\n"; + + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (!field.deprecated && field.IsRequired()) { + code += Indent + Indent + "$builder->required($o, "; + code += NumToString(field.value.offset); + code += "); // " + field.name + "\n"; + } + } + code += Indent + Indent + "return $o;\n"; + code += Indent + "}\n\n"; + } + + // Set the value of a table's field. + static void BuildFieldOfTable(const FieldDef &field, const size_t offset, + std::string *code_ptr) { + std::string &code = *code_ptr; + + code += Indent + "/**\n"; + code += Indent + " * @param FlatBufferBuilder $builder\n"; + code += Indent + " * @param " + GenTypeBasic(field.value.type) + "\n"; + code += Indent + " * @return void\n"; + code += Indent + " */\n"; + code += Indent + "public static function "; + code += "add" + MakeCamel(field.name); + code += "(FlatBufferBuilder $builder, "; + code += "$" + MakeCamel(field.name, false); + code += ")\n"; + code += Indent + "{\n"; + code += Indent + Indent + "$builder->add"; + code += GenMethod(field) + "X("; + code += NumToString(offset) + ", "; + + code += "$" + MakeCamel(field.name, false); + code += ", "; + + if (field.value.type.base_type == BASE_TYPE_BOOL) { + code += "false"; + } else { + code += field.value.constant; + } + code += ");\n"; + code += Indent + "}\n\n"; + } + + // Set the value of one of the members of a table's vector. + static void BuildVectorOfTable(const FieldDef &field, std::string *code_ptr) { + std::string &code = *code_ptr; + + auto vector_type = field.value.type.VectorType(); + auto alignment = InlineAlignment(vector_type); + auto elem_size = InlineSize(vector_type); + code += Indent + "/**\n"; + code += Indent + " * @param FlatBufferBuilder $builder\n"; + code += Indent + " * @param array offset array\n"; + code += Indent + " * @return int vector offset\n"; + code += Indent + " */\n"; + code += Indent + "public static function create"; + code += MakeCamel(field.name); + code += "Vector(FlatBufferBuilder $builder, array $data)\n"; + code += Indent + "{\n"; + code += Indent + Indent + "$builder->startVector("; + code += NumToString(elem_size); + code += ", count($data), " + NumToString(alignment); + code += ");\n"; + code += Indent + Indent; + code += "for ($i = count($data) - 1; $i >= 0; $i--) {\n"; + if (IsScalar(field.value.type.VectorType().base_type)) { + code += Indent + Indent + Indent; + code += "$builder->put"; + code += MakeCamel(GenTypeBasic(field.value.type.VectorType())); + code += "($data[$i]);\n"; + } else { + code += Indent + Indent + Indent; + code += "$builder->putOffset($data[$i]);\n"; + } + code += Indent + Indent + "}\n"; + code += Indent + Indent + "return $builder->endVector();\n"; + code += Indent + "}\n\n"; + + code += Indent + "/**\n"; + code += Indent + " * @param FlatBufferBuilder $builder\n"; + code += Indent + " * @param int $numElems\n"; + code += Indent + " * @return void\n"; + code += Indent + " */\n"; + code += Indent + "public static function start"; + code += MakeCamel(field.name); + code += "Vector(FlatBufferBuilder $builder, $numElems)\n"; + code += Indent + "{\n"; + code += Indent + Indent + "$builder->startVector("; + code += NumToString(elem_size); + code += ", $numElems, " + NumToString(alignment); + code += ");\n"; + code += Indent + "}\n\n"; + } + + // Get the offset of the end of a table. + void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) { + std::string &code = *code_ptr; + + code += Indent + "/**\n"; + code += Indent + " * @param FlatBufferBuilder $builder\n"; + code += Indent + " * @return int table offset\n"; + code += Indent + " */\n"; + code += Indent + "public static function end" + struct_def.name; + code += "(FlatBufferBuilder $builder)\n"; + code += Indent + "{\n"; + code += Indent + Indent + "$o = $builder->endObject();\n"; + + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (!field.deprecated && field.IsRequired()) { + code += Indent + Indent + "$builder->required($o, "; + code += NumToString(field.value.offset); + code += "); // " + field.name + "\n"; + } + } + code += Indent + Indent + "return $o;\n"; + code += Indent + "}\n"; + + if (parser_.root_struct_def_ == &struct_def) { + code += "\n"; + code += Indent + "public static function finish"; + code += struct_def.name; + code += "Buffer(FlatBufferBuilder $builder, $offset)\n"; + code += Indent + "{\n"; + code += Indent + Indent + "$builder->finish($offset"; + + if (parser_.file_identifier_.length()) + code += ", \"" + parser_.file_identifier_ + "\""; + code += ");\n"; + code += Indent + "}\n"; + } + } + + // Generate a struct field, conditioned on its child type(s). + void GenStructAccessor(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + GenComment(field.doc_comment, code_ptr, nullptr, Indent.c_str()); + + if (IsScalar(field.value.type.base_type)) { + if (struct_def.fixed) { + GetScalarFieldOfStruct(field, code_ptr); + } else { + GetScalarFieldOfTable(field, code_ptr); + } + } else { + switch (field.value.type.base_type) { + case BASE_TYPE_STRUCT: + if (struct_def.fixed) { + GetStructFieldOfStruct(field, code_ptr); + } else { + GetStructFieldOfTable(field, code_ptr); + } + break; + case BASE_TYPE_STRING: GetStringField(field, code_ptr); break; + case BASE_TYPE_VECTOR: { + auto vectortype = field.value.type.VectorType(); + if (vectortype.base_type == BASE_TYPE_UNION) { + GetMemberOfVectorOfUnion(field, code_ptr); + } else if (vectortype.base_type == BASE_TYPE_STRUCT) { + GetMemberOfVectorOfStruct(struct_def, field, code_ptr); + } else { + GetMemberOfVectorOfNonStruct(field, code_ptr); + } + break; + } + case BASE_TYPE_UNION: GetUnionField(field, code_ptr); break; + default: FLATBUFFERS_ASSERT(0); + } + } + if (IsVector(field.value.type)) { + GetVectorLen(field, code_ptr); + if (field.value.type.element == BASE_TYPE_UCHAR) { + GetUByte(field, code_ptr); + } + } + } + + // Generate table constructors, conditioned on its members' types. + void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) { + GetStartOfTable(struct_def, code_ptr); + + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + + auto offset = it - struct_def.fields.vec.begin(); + if (field.value.type.base_type == BASE_TYPE_UNION) { + std::string &code = *code_ptr; + code += Indent + "public static function add"; + code += MakeCamel(field.name); + code += "(FlatBufferBuilder $builder, $offset)\n"; + code += Indent + "{\n"; + code += Indent + Indent + "$builder->addOffsetX("; + code += NumToString(offset) + ", $offset, 0);\n"; + code += Indent + "}\n\n"; + } else { + BuildFieldOfTable(field, offset, code_ptr); + } + if (IsVector(field.value.type)) { BuildVectorOfTable(field, code_ptr); } + } + + GetEndOffsetOnTable(struct_def, code_ptr); + } + + // Generate struct or table methods. + void GenStruct(const StructDef &struct_def, std::string *code_ptr) { + if (struct_def.generated) return; + + GenComment(struct_def.doc_comment, code_ptr, nullptr); + BeginClass(struct_def, code_ptr); + + if (!struct_def.fixed) { + // Generate a special accessor for the table that has been declared as + // the root type. + NewRootTypeFromBuffer(struct_def, code_ptr); + } + + std::string &code = *code_ptr; + if (!struct_def.fixed) { + if (parser_.file_identifier_.length()) { + // Return the identifier + code += Indent + "public static function " + struct_def.name; + code += "Identifier()\n"; + code += Indent + "{\n"; + code += Indent + Indent + "return \""; + code += parser_.file_identifier_ + "\";\n"; + code += Indent + "}\n\n"; + + // Check if a buffer has the identifier. + code += Indent + "public static function " + struct_def.name; + code += "BufferHasIdentifier(ByteBuffer $buf)\n"; + code += Indent + "{\n"; + code += Indent + Indent + "return self::"; + code += "__has_identifier($buf, self::"; + code += struct_def.name + "Identifier());\n"; + code += Indent + "}\n\n"; + } + + if (parser_.file_extension_.length()) { + // Return the extension + code += Indent + "public static function " + struct_def.name; + code += "Extension()\n"; + code += Indent + "{\n"; + code += Indent + Indent + "return \"" + parser_.file_extension_; + code += "\";\n"; + code += Indent + "}\n\n"; + } + } + + // Generate the Init method that sets the field in a pre-existing + // accessor object. This is to allow object reuse. + InitializeExisting(struct_def, code_ptr); + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + + GenStructAccessor(struct_def, field, code_ptr); + } + + if (struct_def.fixed) { + // create a struct constructor function + GenStructBuilder(struct_def, code_ptr); + } else { + // Create a set of functions that allow table construction. + GenTableBuilders(struct_def, code_ptr); + } + EndClass(code_ptr); + } + + // Generate enum declarations. + static void GenEnum(const EnumDef &enum_def, std::string *code_ptr) { + if (enum_def.generated) return; + + GenComment(enum_def.doc_comment, code_ptr, nullptr); + BeginEnum(enum_def.name, code_ptr); + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + auto &ev = **it; + GenComment(ev.doc_comment, code_ptr, nullptr, Indent.c_str()); + EnumMember(enum_def, ev, code_ptr); + } + + std::string &code = *code_ptr; + code += "\n"; + code += Indent + "private static $names = array(\n"; + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + auto &ev = **it; + code += Indent + Indent + enum_def.name + "::" + ev.name + "=>" + "\"" + + ev.name + "\",\n"; + } + + code += Indent + ");\n\n"; + code += Indent + "public static function Name($e)\n"; + code += Indent + "{\n"; + code += Indent + Indent + "if (!isset(self::$names[$e])) {\n"; + code += Indent + Indent + Indent + "throw new \\Exception();\n"; + code += Indent + Indent + "}\n"; + code += Indent + Indent + "return self::$names[$e];\n"; + code += Indent + "}\n"; + EndEnum(code_ptr); + } + + // Returns the function name that is able to read a value of the given type. + static std::string GenGetter(const Type &type) { + switch (type.base_type) { + case BASE_TYPE_STRING: return "__string"; + case BASE_TYPE_STRUCT: return "__struct"; + case BASE_TYPE_UNION: return "__union"; + case BASE_TYPE_VECTOR: return GenGetter(type.VectorType()); + default: return "Get"; + } + } + + // Returns the method name for use with add/put calls. + static std::string GenMethod(const FieldDef &field) { + return IsScalar(field.value.type.base_type) + ? MakeCamel(GenTypeBasic(field.value.type)) + : (IsStruct(field.value.type) ? "Struct" : "Offset"); + } + + static std::string GenTypeBasic(const Type &type) { + // clang-format off + static const char *ctypename[] = { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ + CTYPE, JTYPE, GTYPE, NTYPE, ...) \ + #NTYPE, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + }; + // clang-format on + return ctypename[type.base_type]; + } + + std::string GenDefaultValue(const Value &value) { + if (value.type.enum_def) { + if (auto val = value.type.enum_def->FindByValue(value.constant)) { + return WrapInNameSpace(*value.type.enum_def) + "::" + val->name; + } + } + + switch (value.type.base_type) { + case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true"; + + case BASE_TYPE_STRING: return "null"; + + case BASE_TYPE_LONG: + case BASE_TYPE_ULONG: + if (value.constant != "0") { + int64_t constant = StringToInt(value.constant.c_str()); + return NumToString(constant); + } + return "0"; + + default: return value.constant; + } + } + + static std::string GenTypePointer(const Type &type) { + switch (type.base_type) { + case BASE_TYPE_STRING: return "string"; + case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType()); + case BASE_TYPE_STRUCT: return type.struct_def->name; + case BASE_TYPE_UNION: + // fall through + default: return "Table"; + } + } + + static std::string GenTypeGet(const Type &type) { + return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type); + } + + // Create a struct with a builder and the struct's arguments. + static void GenStructBuilder(const StructDef &struct_def, + std::string *code_ptr) { + std::string &code = *code_ptr; + code += "\n"; + code += Indent + "/**\n"; + code += Indent + " * @return int offset\n"; + code += Indent + " */\n"; + code += Indent + "public static function create" + struct_def.name; + code += "(FlatBufferBuilder $builder"; + StructBuilderArgs(struct_def, "", code_ptr); + code += ")\n"; + code += Indent + "{\n"; + + StructBuilderBody(struct_def, "", code_ptr); + + code += Indent + Indent + "return $builder->offset();\n"; + code += Indent + "}\n"; + } +}; +} // namespace php + +bool GeneratePhp(const Parser &parser, const std::string &path, + const std::string &file_name) { + php::PhpGenerator generator(parser, path, file_name); + return generator.generate(); +} +} // namespace flatbuffers diff --git a/contrib/libs/flatbuffers/src/idl_gen_python.cpp b/contrib/libs/flatbuffers/src/idl_gen_python.cpp new file mode 100644 index 0000000000..b3f394ebf9 --- /dev/null +++ b/contrib/libs/flatbuffers/src/idl_gen_python.cpp @@ -0,0 +1,1782 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// independent from idl_parser, since this code is not needed for most clients + +#include <cctype> +#include <set> +#include <string> +#include <unordered_set> +#include <vector> + +#include "flatbuffers/code_generators.h" +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +namespace flatbuffers { +namespace python { + +// Hardcode spaces per indentation. +const CommentConfig def_comment = { nullptr, "#", nullptr }; +const std::string Indent = " "; + +class PythonGenerator : public BaseGenerator { + public: + PythonGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name, "" /* not used */, + "" /* not used */, "py"), + float_const_gen_("float('nan')", "float('inf')", "float('-inf')") { + static const char *const keywords[] = { + "False", "None", "True", "and", "as", "assert", "break", + "class", "continue", "def", "del", "elif", "else", "except", + "finally", "for", "from", "global", "if", "import", "in", + "is", "lambda", "nonlocal", "not", "or", "pass", "raise", + "return", "try", "while", "with", "yield" + }; + keywords_.insert(std::begin(keywords), std::end(keywords)); + } + + // Most field accessors need to retrieve and test the field offset first, + // this is the prefix code for that. + std::string OffsetPrefix(const FieldDef &field) { + return "\n" + Indent + Indent + + "o = flatbuffers.number_types.UOffsetTFlags.py_type" + + "(self._tab.Offset(" + NumToString(field.value.offset) + "))\n" + + Indent + Indent + "if o != 0:\n"; + } + + // Begin a class declaration. + void BeginClass(const StructDef &struct_def, std::string *code_ptr) { + auto &code = *code_ptr; + code += "class " + NormalizedName(struct_def) + "(object):\n"; + code += Indent + "__slots__ = ['_tab']"; + code += "\n\n"; + } + + // Begin enum code with a class declaration. + void BeginEnum(const std::string &class_name, std::string *code_ptr) { + auto &code = *code_ptr; + code += "class " + class_name + "(object):\n"; + } + + std::string EscapeKeyword(const std::string &name) const { + return keywords_.find(name) == keywords_.end() ? name : name + "_"; + } + + std::string NormalizedName(const Definition &definition) const { + return EscapeKeyword(definition.name); + } + + std::string NormalizedName(const EnumVal &ev) const { + return EscapeKeyword(ev.name); + } + + // Converts the name of a definition into upper Camel format. + std::string MakeUpperCamel(const Definition &definition) const { + return MakeCamel(NormalizedName(definition), true); + } + + // Converts the name of a definition into lower Camel format. + std::string MakeLowerCamel(const Definition &definition) const { + auto name = MakeCamel(NormalizedName(definition), false); + name[0] = CharToLower(name[0]); + return name; + } + + // Starts a new line and then indents. + std::string GenIndents(int num) { + return "\n" + std::string(num * Indent.length(), ' '); + } + + // A single enum member. + void EnumMember(const EnumDef &enum_def, const EnumVal &ev, + std::string *code_ptr) { + auto &code = *code_ptr; + code += Indent; + code += NormalizedName(ev); + code += " = "; + code += enum_def.ToString(ev) + "\n"; + } + + // End enum code. + void EndEnum(std::string *code_ptr) { + auto &code = *code_ptr; + code += "\n"; + } + + // Initialize a new struct or table from existing data. + void NewRootTypeFromBuffer(const StructDef &struct_def, + std::string *code_ptr) { + auto &code = *code_ptr; + + code += Indent + "@classmethod\n"; + code += Indent + "def GetRootAs"; + code += "(cls, buf, offset=0):"; + code += "\n"; + code += Indent + Indent; + code += "n = flatbuffers.encode.Get"; + code += "(flatbuffers.packer.uoffset, buf, offset)\n"; + code += Indent + Indent + "x = " + NormalizedName(struct_def) + "()\n"; + code += Indent + Indent + "x.Init(buf, n + offset)\n"; + code += Indent + Indent + "return x\n"; + code += "\n"; + + // Add an alias with the old name + code += Indent + "@classmethod\n"; + code += Indent + "def GetRootAs"; + code += NormalizedName(struct_def); + code += "(cls, buf, offset=0):\n"; + code += Indent + Indent + "\"\"\"This method is deprecated. Please switch to GetRootAs.\"\"\"\n"; + code += Indent + Indent + "return cls.GetRootAs(buf, offset)\n"; + } + + // Initialize an existing object with other data, to avoid an allocation. + void InitializeExisting(const StructDef &struct_def, std::string *code_ptr) { + auto &code = *code_ptr; + + GenReceiver(struct_def, code_ptr); + code += "Init(self, buf, pos):\n"; + code += Indent + Indent + "self._tab = flatbuffers.table.Table(buf, pos)\n"; + code += "\n"; + } + + // Get the length of a vector. + void GetVectorLen(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + auto &code = *code_ptr; + + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)) + "Length(self"; + code += "):" + OffsetPrefix(field); + code += Indent + Indent + Indent + "return self._tab.VectorLen(o)\n"; + code += Indent + Indent + "return 0\n\n"; + } + + // Determines whether a vector is none or not. + void GetVectorIsNone(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + auto &code = *code_ptr; + + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)) + "IsNone(self"; + code += "):"; + code += GenIndents(2) + + "o = flatbuffers.number_types.UOffsetTFlags.py_type" + + "(self._tab.Offset(" + NumToString(field.value.offset) + "))"; + code += GenIndents(2) + "return o == 0"; + code += "\n\n"; + } + + // Get the value of a struct's scalar. + void GetScalarFieldOfStruct(const StructDef &struct_def, + const FieldDef &field, std::string *code_ptr) { + auto &code = *code_ptr; + std::string getter = GenGetter(field.value.type); + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "(self): return " + getter; + code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type("; + code += NumToString(field.value.offset) + "))\n"; + } + + // Get the value of a table's scalar. + void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + auto &code = *code_ptr; + std::string getter = GenGetter(field.value.type); + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "(self):"; + code += OffsetPrefix(field); + getter += "o + self._tab.Pos)"; + auto is_bool = IsBool(field.value.type.base_type); + if (is_bool) { getter = "bool(" + getter + ")"; } + code += Indent + Indent + Indent + "return " + getter + "\n"; + std::string default_value; + if (is_bool) { + default_value = field.value.constant == "0" ? "False" : "True"; + } else { + default_value = IsFloat(field.value.type.base_type) + ? float_const_gen_.GenFloatConstant(field) + : field.value.constant; + } + code += Indent + Indent + "return " + default_value + "\n\n"; + } + + // Get a struct by initializing an existing struct. + // Specific to Struct. + void GetStructFieldOfStruct(const StructDef &struct_def, + const FieldDef &field, std::string *code_ptr) { + auto &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "(self, obj):\n"; + code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + "; + code += NumToString(field.value.offset) + ")"; + code += "\n" + Indent + Indent + "return obj\n\n"; + } + + // Get the value of a fixed size array. + void GetArrayOfStruct(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + auto &code = *code_ptr; + const auto vec_type = field.value.type.VectorType(); + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + if (IsStruct(vec_type)) { + code += "(self, obj, i):\n"; + code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + "; + code += NumToString(field.value.offset) + " + i * "; + code += NumToString(InlineSize(vec_type)); + code += ")\n" + Indent + Indent + "return obj\n\n"; + } else { + auto getter = GenGetter(vec_type); + code += "(self): return [" + getter; + code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type("; + code += NumToString(field.value.offset) + " + i * "; + code += NumToString(InlineSize(vec_type)); + code += ")) for i in range("; + code += NumToString(field.value.type.fixed_length) + ")]\n"; + } + } + + // Get a struct by initializing an existing struct. + // Specific to Table. + void GetStructFieldOfTable(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + auto &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "(self):"; + code += OffsetPrefix(field); + if (field.value.type.struct_def->fixed) { + code += Indent + Indent + Indent + "x = o + self._tab.Pos\n"; + } else { + code += Indent + Indent + Indent; + code += "x = self._tab.Indirect(o + self._tab.Pos)\n"; + } + if (parser_.opts.include_dependence_headers) { + code += Indent + Indent + Indent; + code += "from " + GenPackageReference(field.value.type) + " import " + + TypeName(field) + "\n"; + } + code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n"; + code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n"; + code += Indent + Indent + Indent + "return obj\n"; + code += Indent + Indent + "return None\n\n"; + } + + // Get the value of a string. + void GetStringField(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + auto &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "(self):"; + code += OffsetPrefix(field); + code += Indent + Indent + Indent + "return " + GenGetter(field.value.type); + code += "o + self._tab.Pos)\n"; + code += Indent + Indent + "return None\n\n"; + } + + // Get the value of a union from an object. + void GetUnionField(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + auto &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)) + "(self):"; + code += OffsetPrefix(field); + + // TODO(rw): this works and is not the good way to it: + bool is_native_table = TypeName(field) == "*flatbuffers.Table"; + if (is_native_table) { + code += + Indent + Indent + Indent + "from flatbuffers.table import Table\n"; + } else if (parser_.opts.include_dependence_headers) { + code += Indent + Indent + Indent; + code += "from " + GenPackageReference(field.value.type) + " import " + + TypeName(field) + "\n"; + } + code += Indent + Indent + Indent + "obj = Table(bytearray(), 0)\n"; + code += Indent + Indent + Indent + GenGetter(field.value.type); + code += "obj, o)\n" + Indent + Indent + Indent + "return obj\n"; + code += Indent + Indent + "return None\n\n"; + } + + // Generate the package reference when importing a struct or enum from its + // module. + std::string GenPackageReference(const Type &type) { + Namespace *namespaces; + if (type.struct_def) { + namespaces = type.struct_def->defined_namespace; + } else if (type.enum_def) { + namespaces = type.enum_def->defined_namespace; + } else { + return "." + GenTypeGet(type); + } + + return namespaces->GetFullyQualifiedName(GenTypeGet(type)); + } + + // Get the value of a vector's struct member. + void GetMemberOfVectorOfStruct(const StructDef &struct_def, + const FieldDef &field, std::string *code_ptr) { + auto &code = *code_ptr; + auto vectortype = field.value.type.VectorType(); + + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "(self, j):" + OffsetPrefix(field); + code += Indent + Indent + Indent + "x = self._tab.Vector(o)\n"; + code += Indent + Indent + Indent; + code += "x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * "; + code += NumToString(InlineSize(vectortype)) + "\n"; + if (!(vectortype.struct_def->fixed)) { + code += Indent + Indent + Indent + "x = self._tab.Indirect(x)\n"; + } + if (parser_.opts.include_dependence_headers) { + code += Indent + Indent + Indent; + code += "from " + GenPackageReference(field.value.type) + " import " + + TypeName(field) + "\n"; + } + code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n"; + code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n"; + code += Indent + Indent + Indent + "return obj\n"; + code += Indent + Indent + "return None\n\n"; + } + + // Get the value of a vector's non-struct member. Uses a named return + // argument to conveniently set the zero value for the result. + void GetMemberOfVectorOfNonStruct(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + auto &code = *code_ptr; + auto vectortype = field.value.type.VectorType(); + + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "(self, j):"; + code += OffsetPrefix(field); + code += Indent + Indent + Indent + "a = self._tab.Vector(o)\n"; + code += Indent + Indent + Indent; + code += "return " + GenGetter(field.value.type); + code += "a + flatbuffers.number_types.UOffsetTFlags.py_type(j * "; + code += NumToString(InlineSize(vectortype)) + "))\n"; + if (IsString(vectortype)) { + code += Indent + Indent + "return \"\"\n"; + } else { + code += Indent + Indent + "return 0\n"; + } + code += "\n"; + } + + // Returns a non-struct vector as a numpy array. Much faster + // than iterating over the vector element by element. + void GetVectorOfNonStructAsNumpy(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + auto &code = *code_ptr; + auto vectortype = field.value.type.VectorType(); + + // Currently, we only support accessing as numpy array if + // the vector type is a scalar. + if (!(IsScalar(vectortype.base_type))) { return; } + + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)) + "AsNumpy(self):"; + code += OffsetPrefix(field); + + code += Indent + Indent + Indent; + code += "return "; + code += "self._tab.GetVectorAsNumpy(flatbuffers.number_types."; + code += MakeCamel(GenTypeGet(field.value.type)); + code += "Flags, o)\n"; + + if (IsString(vectortype)) { + code += Indent + Indent + "return \"\"\n"; + } else { + code += Indent + Indent + "return 0\n"; + } + code += "\n"; + } + + // Returns a nested flatbuffer as itself. + void GetVectorAsNestedFlatbuffer(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr) { + auto nested = field.attributes.Lookup("nested_flatbuffer"); + if (!nested) { return; } // There is no nested flatbuffer. + + std::string unqualified_name = nested->constant; + std::string qualified_name = nested->constant; + auto nested_root = parser_.LookupStruct(nested->constant); + if (nested_root == nullptr) { + qualified_name = + parser_.current_namespace_->GetFullyQualifiedName(nested->constant); + nested_root = parser_.LookupStruct(qualified_name); + } + FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser. + (void)nested_root; + + auto &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)) + "NestedRoot(self):"; + + code += OffsetPrefix(field); + + code += Indent + Indent + Indent; + code += "from " + qualified_name + " import " + unqualified_name + "\n"; + code += Indent + Indent + Indent + "return " + unqualified_name; + code += ".GetRootAs"; + code += "(self._tab.Bytes, self._tab.Vector(o))\n"; + code += Indent + Indent + "return 0\n"; + code += "\n"; + } + + // Begin the creator function signature. + void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) { + auto &code = *code_ptr; + + code += "\n"; + code += "def Create" + NormalizedName(struct_def); + code += "(builder"; + } + + // Recursively generate arguments for a constructor, to deal with nested + // structs. + void StructBuilderArgs(const StructDef &struct_def, + const std::string nameprefix, + const std::string namesuffix, bool has_field_name, + const std::string fieldname_suffix, + std::string *code_ptr) { + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + const auto &field_type = field.value.type; + const auto &type = + IsArray(field_type) ? field_type.VectorType() : field_type; + if (IsStruct(type)) { + // Generate arguments for a struct inside a struct. To ensure names + // don't clash, and to make it obvious these arguments are constructing + // a nested struct, prefix the name with the field name. + auto subprefix = nameprefix; + if (has_field_name) { + subprefix += NormalizedName(field) + fieldname_suffix; + } + StructBuilderArgs(*field.value.type.struct_def, subprefix, namesuffix, + has_field_name, fieldname_suffix, code_ptr); + } else { + auto &code = *code_ptr; + code += std::string(", ") + nameprefix; + if (has_field_name) { code += MakeCamel(NormalizedName(field), false); } + code += namesuffix; + } + } + } + + // End the creator function signature. + void EndBuilderArgs(std::string *code_ptr) { + auto &code = *code_ptr; + code += "):\n"; + } + + // Recursively generate struct construction statements and instert manual + // padding. + void StructBuilderBody(const StructDef &struct_def, const char *nameprefix, + std::string *code_ptr, size_t index = 0, + bool in_array = false) { + auto &code = *code_ptr; + std::string indent(index * 4, ' '); + code += + indent + " builder.Prep(" + NumToString(struct_def.minalign) + ", "; + code += NumToString(struct_def.bytesize) + ")\n"; + for (auto it = struct_def.fields.vec.rbegin(); + it != struct_def.fields.vec.rend(); ++it) { + auto &field = **it; + const auto &field_type = field.value.type; + const auto &type = + IsArray(field_type) ? field_type.VectorType() : field_type; + if (field.padding) + code += + indent + " builder.Pad(" + NumToString(field.padding) + ")\n"; + if (IsStruct(field_type)) { + StructBuilderBody(*field_type.struct_def, + (nameprefix + (NormalizedName(field) + "_")).c_str(), + code_ptr, index, in_array); + } else { + const auto index_var = "_idx" + NumToString(index); + if (IsArray(field_type)) { + code += indent + " for " + index_var + " in range("; + code += NumToString(field_type.fixed_length); + code += " , 0, -1):\n"; + in_array = true; + } + if (IsStruct(type)) { + StructBuilderBody( + *field_type.struct_def, + (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr, + index + 1, in_array); + } else { + code += IsArray(field_type) ? " " : ""; + code += indent + " builder.Prepend" + GenMethod(field) + "("; + code += nameprefix + MakeCamel(NormalizedName(field), false); + size_t array_cnt = index + (IsArray(field_type) ? 1 : 0); + for (size_t i = 0; in_array && i < array_cnt; i++) { + code += "[_idx" + NumToString(i) + "-1]"; + } + code += ")\n"; + } + } + } + } + + void EndBuilderBody(std::string *code_ptr) { + auto &code = *code_ptr; + code += " return builder.Offset()\n"; + } + + // Get the value of a table's starting offset. + void GetStartOfTable(const StructDef &struct_def, std::string *code_ptr) { + auto &code = *code_ptr; + code += "def Start(builder): "; + code += "builder.StartObject("; + code += NumToString(struct_def.fields.vec.size()); + code += ")\n"; + + // Add alias with the old name. + code += "def " + NormalizedName(struct_def) + "Start(builder):\n"; + code += Indent + "\"\"\"This method is deprecated. Please switch to Start.\"\"\"\n"; + code += Indent + "return Start(builder)\n"; + } + + // Set the value of a table's field. + void BuildFieldOfTable(const StructDef &struct_def, const FieldDef &field, + const size_t offset, std::string *code_ptr) { + auto &code = *code_ptr; + code += "def Add" + MakeCamel(NormalizedName(field)); + code += "(builder, "; + code += MakeCamel(NormalizedName(field), false); + code += "): "; + code += "builder.Prepend"; + code += GenMethod(field) + "Slot("; + code += NumToString(offset) + ", "; + if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) { + code += "flatbuffers.number_types.UOffsetTFlags.py_type"; + code += "("; + code += MakeCamel(NormalizedName(field), false) + ")"; + } else { + code += MakeCamel(NormalizedName(field), false); + } + code += ", "; + code += IsFloat(field.value.type.base_type) + ? float_const_gen_.GenFloatConstant(field) + : field.value.constant; + code += ")\n"; + + // Add alias with the old name. + code += "def " + NormalizedName(struct_def) + "Add" + MakeCamel(NormalizedName(field)); + code += "(builder, "; + code += MakeCamel(NormalizedName(field), false); + code += "):\n"; + code += Indent + "\"\"\"This method is deprecated. Please switch to Add"; + code += MakeCamel(NormalizedName(field)) + ".\"\"\"\n"; + code += Indent + "return Add" + MakeCamel(NormalizedName(field)); + code += "(builder, "; + code += MakeCamel(NormalizedName(field), false); + code += ")\n"; + + // Add alias with the old name. + } + + // Set the value of one of the members of a table's vector. + void BuildVectorOfTable(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + auto &code = *code_ptr; + code += "def Start"; + code += MakeCamel(NormalizedName(field)); + code += "Vector(builder, numElems): return builder.StartVector("; + auto vector_type = field.value.type.VectorType(); + auto alignment = InlineAlignment(vector_type); + auto elem_size = InlineSize(vector_type); + code += NumToString(elem_size); + code += ", numElems, " + NumToString(alignment); + code += ")\n"; + + // Add alias with the old name. + code += "def " + NormalizedName(struct_def) + "Start"; + code += MakeCamel(NormalizedName(field)); + code += "Vector(builder, numElems):\n"; + code += Indent + "\"\"\"This method is deprecated. Please switch to Start.\"\"\"\n"; + code += Indent + "return Start"; + code += MakeCamel(NormalizedName(field)); + code += "Vector(builder, numElems)\n"; + } + + // Set the value of one of the members of a table's vector and fills in the + // elements from a bytearray. This is for simplifying the use of nested + // flatbuffers. + void BuildVectorOfTableFromBytes(const FieldDef &field, std::string *code_ptr) { + auto nested = field.attributes.Lookup("nested_flatbuffer"); + if (!nested) { return; } // There is no nested flatbuffer. + + std::string unqualified_name = nested->constant; + std::string qualified_name = nested->constant; + auto nested_root = parser_.LookupStruct(nested->constant); + if (nested_root == nullptr) { + qualified_name = + parser_.current_namespace_->GetFullyQualifiedName(nested->constant); + nested_root = parser_.LookupStruct(qualified_name); + } + FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser. + (void)nested_root; + + auto &code = *code_ptr; + code += "def MakeVectorFromBytes(builder, bytes):\n"; + code += Indent + "builder.StartVector("; + auto vector_type = field.value.type.VectorType(); + auto alignment = InlineAlignment(vector_type); + auto elem_size = InlineSize(vector_type); + code += NumToString(elem_size); + code += ", len(bytes), " + NumToString(alignment); + code += ")\n"; + code += Indent + "builder.head = builder.head - len(bytes)\n"; + code += Indent + "builder.Bytes[builder.head : builder.head + len(bytes)]"; + code += " = bytes\n"; + code += Indent + "return builder.EndVector()\n"; + + // Add alias with the old name. + code += "def Make" + MakeCamel(NormalizedName(field)); + code += "VectorFromBytes(builder, bytes):\n"; + code += Indent + "builder.StartVector("; + code += NumToString(elem_size); + code += ", len(bytes), " + NumToString(alignment); + code += ")\n"; + code += Indent + "builder.head = builder.head - len(bytes)\n"; + code += Indent + "builder.Bytes[builder.head : builder.head + len(bytes)]"; + code += " = bytes\n"; + code += Indent + "return builder.EndVector()\n"; + } + + // Get the offset of the end of a table. + void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) { + auto &code = *code_ptr; + code += "def End(builder): return builder.EndObject()\n"; + + // Add alias with the old name. + code += "def " + NormalizedName(struct_def) + "End(builder):\n"; + code += Indent + "\"\"\"This method is deprecated. Please switch to End.\"\"\"\n"; + code += Indent + "return End(builder)"; + } + + // Generate the receiver for function signatures. + void GenReceiver(const StructDef &struct_def, std::string *code_ptr) { + auto &code = *code_ptr; + code += Indent + "# " + NormalizedName(struct_def) + "\n"; + code += Indent + "def "; + } + + // Generate a struct field, conditioned on its child type(s). + void GenStructAccessor(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + GenComment(field.doc_comment, code_ptr, &def_comment, Indent.c_str()); + if (IsScalar(field.value.type.base_type)) { + if (struct_def.fixed) { + GetScalarFieldOfStruct(struct_def, field, code_ptr); + } else { + GetScalarFieldOfTable(struct_def, field, code_ptr); + } + } else if (IsArray(field.value.type)) { + GetArrayOfStruct(struct_def, field, code_ptr); + } else { + switch (field.value.type.base_type) { + case BASE_TYPE_STRUCT: + if (struct_def.fixed) { + GetStructFieldOfStruct(struct_def, field, code_ptr); + } else { + GetStructFieldOfTable(struct_def, field, code_ptr); + } + break; + case BASE_TYPE_STRING: + GetStringField(struct_def, field, code_ptr); + break; + case BASE_TYPE_VECTOR: { + auto vectortype = field.value.type.VectorType(); + if (vectortype.base_type == BASE_TYPE_STRUCT) { + GetMemberOfVectorOfStruct(struct_def, field, code_ptr); + } else { + GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr); + GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr); + GetVectorAsNestedFlatbuffer(struct_def, field, code_ptr); + } + break; + } + case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break; + default: FLATBUFFERS_ASSERT(0); + } + } + if (IsVector(field.value.type) || IsArray(field.value.type)) { + GetVectorLen(struct_def, field, code_ptr); + GetVectorIsNone(struct_def, field, code_ptr); + } + } + + // Generate struct sizeof. + void GenStructSizeOf(const StructDef &struct_def, std::string *code_ptr) { + auto &code = *code_ptr; + code += Indent + "@classmethod\n"; + code += Indent + "def SizeOf(cls):\n"; + code += + Indent + Indent + "return " + NumToString(struct_def.bytesize) + "\n"; + code += "\n"; + } + + // Generate table constructors, conditioned on its members' types. + void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) { + GetStartOfTable(struct_def, code_ptr); + + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + + auto offset = it - struct_def.fields.vec.begin(); + BuildFieldOfTable(struct_def, field, offset, code_ptr); + if (IsVector(field.value.type)) { + BuildVectorOfTable(struct_def, field, code_ptr); + BuildVectorOfTableFromBytes(field, code_ptr); + } + } + + GetEndOffsetOnTable(struct_def, code_ptr); + } + + // Generate function to check for proper file identifier + void GenHasFileIdentifier(const StructDef &struct_def, + std::string *code_ptr) { + auto &code = *code_ptr; + std::string escapedID; + // In the event any of file_identifier characters are special(NULL, \, etc), + // problems occur. To prevent this, convert all chars to their hex-escaped + // equivalent. + for (auto it = parser_.file_identifier_.begin(); + it != parser_.file_identifier_.end(); ++it) { + escapedID += "\\x" + IntToStringHex(*it, 2); + } + + code += Indent + "@classmethod\n"; + code += Indent + "def " + NormalizedName(struct_def); + code += "BufferHasIdentifier(cls, buf, offset, size_prefixed=False):"; + code += "\n"; + code += Indent + Indent; + code += "return flatbuffers.util.BufferHasIdentifier(buf, offset, b\""; + code += escapedID; + code += "\", size_prefixed=size_prefixed)\n"; + code += "\n"; + } + + // Generates struct or table methods. + void GenStruct(const StructDef &struct_def, std::string *code_ptr) { + if (struct_def.generated) return; + + GenComment(struct_def.doc_comment, code_ptr, &def_comment); + BeginClass(struct_def, code_ptr); + if (!struct_def.fixed) { + // Generate a special accessor for the table that has been declared as + // the root type. + NewRootTypeFromBuffer(struct_def, code_ptr); + if (parser_.file_identifier_.length()) { + // Generate a special function to test file_identifier + GenHasFileIdentifier(struct_def, code_ptr); + } + } else { + // Generates the SizeOf method for all structs. + GenStructSizeOf(struct_def, code_ptr); + } + // Generates the Init method that sets the field in a pre-existing + // accessor object. This is to allow object reuse. + InitializeExisting(struct_def, code_ptr); + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + + GenStructAccessor(struct_def, field, code_ptr); + } + + if (struct_def.fixed) { + // creates a struct constructor function + GenStructBuilder(struct_def, code_ptr); + } else { + // Creates a set of functions that allow table construction. + GenTableBuilders(struct_def, code_ptr); + } + } + + void GenReceiverForObjectAPI(const StructDef &struct_def, + std::string *code_ptr) { + auto &code = *code_ptr; + code += GenIndents(1) + "# " + NormalizedName(struct_def) + "T"; + code += GenIndents(1) + "def "; + } + + void BeginClassForObjectAPI(const StructDef &struct_def, + std::string *code_ptr) { + auto &code = *code_ptr; + code += "\n"; + code += "class " + NormalizedName(struct_def) + "T(object):"; + code += "\n"; + } + + // Gets the accoresponding python builtin type of a BaseType for scalars and + // string. + std::string GetBasePythonTypeForScalarAndString(const BaseType &base_type) { + if (IsBool(base_type)) { + return "bool"; + } else if (IsFloat(base_type)) { + return "float"; + } else if (IsInteger(base_type)) { + return "int"; + } else if (base_type == BASE_TYPE_STRING) { + return "str"; + } else { + FLATBUFFERS_ASSERT(false && "base_type is not a scalar or string type."); + return ""; + } + } + + std::string GetDefaultValue(const FieldDef &field) { + BaseType base_type = field.value.type.base_type; + if (IsBool(base_type)) { + return field.value.constant == "0" ? "False" : "True"; + } else if (IsFloat(base_type)) { + return float_const_gen_.GenFloatConstant(field); + } else if (IsInteger(base_type)) { + return field.value.constant; + } else { + // For string, struct, and table. + return "None"; + } + } + + void GenUnionInit(const FieldDef &field, std::string *field_types_ptr, + std::set<std::string> *import_list, + std::set<std::string> *import_typing_list) { + // Gets all possible types in the union. + import_typing_list->insert("Union"); + auto &field_types = *field_types_ptr; + field_types = "Union["; + + std::string separator_string = ", "; + auto enum_def = field.value.type.enum_def; + for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end(); + ++it) { + auto &ev = **it; + // Union only supports string and table. + std::string field_type; + switch (ev.union_type.base_type) { + case BASE_TYPE_STRUCT: + field_type = GenTypeGet(ev.union_type) + "T"; + if (parser_.opts.include_dependence_headers) { + auto package_reference = GenPackageReference(ev.union_type); + field_type = package_reference + "." + field_type; + import_list->insert("import " + package_reference); + } + break; + case BASE_TYPE_STRING: field_type += "str"; break; + case BASE_TYPE_NONE: field_type += "None"; break; + default: break; + } + field_types += field_type + separator_string; + } + + // Removes the last separator_string. + field_types.erase(field_types.length() - separator_string.size()); + field_types += "]"; + + // Gets the import lists for the union. + if (parser_.opts.include_dependence_headers) { + // The package reference is generated based on enum_def, instead + // of struct_def in field.type. That's why GenPackageReference() is + // not used. + Namespace *namespaces = field.value.type.enum_def->defined_namespace; + auto package_reference = namespaces->GetFullyQualifiedName( + MakeUpperCamel(*(field.value.type.enum_def))); + auto union_name = MakeUpperCamel(*(field.value.type.enum_def)); + import_list->insert("import " + package_reference); + } + } + + void GenStructInit(const FieldDef &field, std::string *field_type_ptr, + std::set<std::string> *import_list, + std::set<std::string> *import_typing_list) { + import_typing_list->insert("Optional"); + auto &field_type = *field_type_ptr; + if (parser_.opts.include_dependence_headers) { + auto package_reference = GenPackageReference(field.value.type); + field_type = package_reference + "." + TypeName(field) + "T]"; + import_list->insert("import " + package_reference); + } else { + field_type = TypeName(field) + "T]"; + } + field_type = "Optional[" + field_type; + } + + void GenVectorInit(const FieldDef &field, std::string *field_type_ptr, + std::set<std::string> *import_list, + std::set<std::string> *import_typing_list) { + import_typing_list->insert("List"); + auto &field_type = *field_type_ptr; + auto base_type = field.value.type.VectorType().base_type; + if (base_type == BASE_TYPE_STRUCT) { + field_type = GenTypeGet(field.value.type.VectorType()) + "T]"; + if (parser_.opts.include_dependence_headers) { + auto package_reference = + GenPackageReference(field.value.type.VectorType()); + field_type = package_reference + "." + + GenTypeGet(field.value.type.VectorType()) + "T]"; + import_list->insert("import " + package_reference); + } + field_type = "List[" + field_type; + } else { + field_type = + "List[" + GetBasePythonTypeForScalarAndString(base_type) + "]"; + } + } + + void GenInitialize(const StructDef &struct_def, std::string *code_ptr, + std::set<std::string> *import_list) { + std::string code; + std::set<std::string> import_typing_list; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + + // Determines field type, default value, and typing imports. + auto base_type = field.value.type.base_type; + std::string field_type; + switch (base_type) { + case BASE_TYPE_UNION: { + GenUnionInit(field, &field_type, import_list, &import_typing_list); + break; + } + case BASE_TYPE_STRUCT: { + GenStructInit(field, &field_type, import_list, &import_typing_list); + break; + } + case BASE_TYPE_VECTOR: + case BASE_TYPE_ARRAY: { + GenVectorInit(field, &field_type, import_list, &import_typing_list); + break; + } + default: + // Scalar or sting fields. + field_type = GetBasePythonTypeForScalarAndString(base_type); + break; + } + + auto default_value = GetDefaultValue(field); + // Wrties the init statement. + auto field_instance_name = MakeLowerCamel(field); + code += GenIndents(2) + "self." + field_instance_name + " = " + + default_value + " # type: " + field_type; + } + + // Writes __init__ method. + auto &code_base = *code_ptr; + GenReceiverForObjectAPI(struct_def, code_ptr); + code_base += "__init__(self):"; + if (code.empty()) { + code_base += GenIndents(2) + "pass"; + } else { + code_base += code; + } + code_base += "\n"; + + // Merges the typing imports into import_list. + if (!import_typing_list.empty()) { + // Adds the try statement. + std::string typing_imports = "try:"; + typing_imports += GenIndents(1) + "from typing import "; + std::string separator_string = ", "; + for (auto it = import_typing_list.begin(); it != import_typing_list.end(); + ++it) { + const std::string &im = *it; + typing_imports += im + separator_string; + } + // Removes the last separator_string. + typing_imports.erase(typing_imports.length() - separator_string.size()); + + // Adds the except statement. + typing_imports += "\n"; + typing_imports += "except:"; + typing_imports += GenIndents(1) + "pass"; + import_list->insert(typing_imports); + } + + // Removes the import of the struct itself, if applied. + auto package_reference = + struct_def.defined_namespace->GetFullyQualifiedName( + MakeUpperCamel(struct_def)); + auto struct_import = "import " + package_reference; + import_list->erase(struct_import); + } + + void InitializeFromBuf(const StructDef &struct_def, std::string *code_ptr) { + auto &code = *code_ptr; + auto instance_name = MakeLowerCamel(struct_def); + auto struct_name = NormalizedName(struct_def); + + code += GenIndents(1) + "@classmethod"; + code += GenIndents(1) + "def InitFromBuf(cls, buf, pos):"; + code += GenIndents(2) + instance_name + " = " + struct_name + "()"; + code += GenIndents(2) + instance_name + ".Init(buf, pos)"; + code += GenIndents(2) + "return cls.InitFromObj(" + instance_name + ")"; + code += "\n"; + } + + void InitializeFromObjForObject(const StructDef &struct_def, + std::string *code_ptr) { + auto &code = *code_ptr; + auto instance_name = MakeLowerCamel(struct_def); + auto struct_name = NormalizedName(struct_def); + + code += GenIndents(1) + "@classmethod"; + code += GenIndents(1) + "def InitFromObj(cls, " + instance_name + "):"; + code += GenIndents(2) + "x = " + struct_name + "T()"; + code += GenIndents(2) + "x._UnPack(" + instance_name + ")"; + code += GenIndents(2) + "return x"; + code += "\n"; + } + + void GenUnPackForStruct(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + auto &code = *code_ptr; + auto struct_instance_name = MakeLowerCamel(struct_def); + auto field_instance_name = MakeLowerCamel(field); + auto field_accessor_name = MakeUpperCamel(field); + auto field_type = TypeName(field); + + if (parser_.opts.include_dependence_headers) { + auto package_reference = GenPackageReference(field.value.type); + field_type = package_reference + "." + TypeName(field); + } + + code += GenIndents(2) + "if " + struct_instance_name + "." + + field_accessor_name + "("; + // if field is a struct, we need to create an instance for it first. + if (struct_def.fixed && field.value.type.base_type == BASE_TYPE_STRUCT) { + code += field_type + "()"; + } + code += ") is not None:"; + code += GenIndents(3) + "self." + field_instance_name + " = " + field_type + + "T.InitFromObj(" + struct_instance_name + "." + + field_accessor_name + "("; + // A struct's accessor requires a struct buf instance. + if (struct_def.fixed && field.value.type.base_type == BASE_TYPE_STRUCT) { + code += field_type + "()"; + } + code += "))"; + } + + void GenUnPackForUnion(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + auto &code = *code_ptr; + auto field_instance_name = MakeLowerCamel(field); + auto field_accessor_name = MakeUpperCamel(field); + auto struct_instance_name = MakeLowerCamel(struct_def); + auto union_name = MakeUpperCamel(*(field.value.type.enum_def)); + + if (parser_.opts.include_dependence_headers) { + Namespace *namespaces = field.value.type.enum_def->defined_namespace; + auto package_reference = namespaces->GetFullyQualifiedName( + MakeUpperCamel(*(field.value.type.enum_def))); + union_name = package_reference + "." + union_name; + } + code += GenIndents(2) + "self." + field_instance_name + " = " + union_name + + "Creator(" + "self." + field_instance_name + "Type, " + + struct_instance_name + "." + field_accessor_name + "())"; + } + + void GenUnPackForStructVector(const StructDef &struct_def, + const FieldDef &field, std::string *code_ptr) { + auto &code = *code_ptr; + auto field_instance_name = MakeLowerCamel(field); + auto field_accessor_name = MakeUpperCamel(field); + auto struct_instance_name = MakeLowerCamel(struct_def); + + code += GenIndents(2) + "if not " + struct_instance_name + "." + + field_accessor_name + "IsNone():"; + code += GenIndents(3) + "self." + field_instance_name + " = []"; + code += GenIndents(3) + "for i in range(" + struct_instance_name + "." + + field_accessor_name + "Length()):"; + + auto field_type_name = TypeName(field); + auto one_instance = field_type_name + "_"; + one_instance[0] = CharToLower(one_instance[0]); + + if (parser_.opts.include_dependence_headers) { + auto package_reference = GenPackageReference(field.value.type); + field_type_name = package_reference + "." + TypeName(field); + } + + code += GenIndents(4) + "if " + struct_instance_name + "." + + field_accessor_name + "(i) is None:"; + code += GenIndents(5) + "self." + field_instance_name + ".append(None)"; + code += GenIndents(4) + "else:"; + code += GenIndents(5) + one_instance + " = " + field_type_name + + "T.InitFromObj(" + struct_instance_name + "." + + field_accessor_name + "(i))"; + code += GenIndents(5) + "self." + field_instance_name + ".append(" + + one_instance + ")"; + } + + void GenUnpackforScalarVectorHelper(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr, int indents) { + auto &code = *code_ptr; + auto field_instance_name = MakeLowerCamel(field); + auto field_accessor_name = MakeUpperCamel(field); + auto struct_instance_name = MakeLowerCamel(struct_def); + + code += GenIndents(indents) + "self." + field_instance_name + " = []"; + code += GenIndents(indents) + "for i in range(" + struct_instance_name + + "." + field_accessor_name + "Length()):"; + code += GenIndents(indents + 1) + "self." + field_instance_name + + ".append(" + struct_instance_name + "." + field_accessor_name + + "(i))"; + } + + void GenUnPackForScalarVector(const StructDef &struct_def, + const FieldDef &field, std::string *code_ptr) { + auto &code = *code_ptr; + auto field_instance_name = MakeLowerCamel(field); + auto field_accessor_name = MakeUpperCamel(field); + auto struct_instance_name = MakeLowerCamel(struct_def); + + code += GenIndents(2) + "if not " + struct_instance_name + "." + + field_accessor_name + "IsNone():"; + + // String does not have the AsNumpy method. + if (!(IsScalar(field.value.type.VectorType().base_type))) { + GenUnpackforScalarVectorHelper(struct_def, field, code_ptr, 3); + return; + } + + code += GenIndents(3) + "if np is None:"; + GenUnpackforScalarVectorHelper(struct_def, field, code_ptr, 4); + + // If numpy exists, use the AsNumpy method to optimize the unpack speed. + code += GenIndents(3) + "else:"; + code += GenIndents(4) + "self." + field_instance_name + " = " + + struct_instance_name + "." + field_accessor_name + "AsNumpy()"; + } + + void GenUnPackForScalar(const StructDef &struct_def, const FieldDef &field, + std::string *code_ptr) { + auto &code = *code_ptr; + auto field_instance_name = MakeLowerCamel(field); + auto field_accessor_name = MakeUpperCamel(field); + auto struct_instance_name = MakeLowerCamel(struct_def); + + code += GenIndents(2) + "self." + field_instance_name + " = " + + struct_instance_name + "." + field_accessor_name + "()"; + } + + // Generates the UnPack method for the object class. + void GenUnPack(const StructDef &struct_def, std::string *code_ptr) { + std::string code; + // Items that needs to be imported. No duplicate modules will be imported. + std::set<std::string> import_list; + + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + + auto field_type = TypeName(field); + switch (field.value.type.base_type) { + case BASE_TYPE_STRUCT: { + GenUnPackForStruct(struct_def, field, &code); + break; + } + case BASE_TYPE_UNION: { + GenUnPackForUnion(struct_def, field, &code); + break; + } + case BASE_TYPE_VECTOR: { + auto vectortype = field.value.type.VectorType(); + if (vectortype.base_type == BASE_TYPE_STRUCT) { + GenUnPackForStructVector(struct_def, field, &code); + } else { + GenUnPackForScalarVector(struct_def, field, &code); + } + break; + } + case BASE_TYPE_ARRAY: { + GenUnPackForScalarVector(struct_def, field, &code); + break; + } + default: GenUnPackForScalar(struct_def, field, &code); + } + } + + // Writes import statements and code into the generated file. + auto &code_base = *code_ptr; + auto struct_instance_name = MakeLowerCamel(struct_def); + auto struct_name = MakeUpperCamel(struct_def); + + GenReceiverForObjectAPI(struct_def, code_ptr); + code_base += "_UnPack(self, " + struct_instance_name + "):"; + code_base += GenIndents(2) + "if " + struct_instance_name + " is None:"; + code_base += GenIndents(3) + "return"; + + // Write the import statements. + for (std::set<std::string>::iterator it = import_list.begin(); + it != import_list.end(); ++it) { + code_base += GenIndents(2) + *it; + } + + // Write the code. + code_base += code; + code_base += "\n"; + } + + void GenPackForStruct(const StructDef &struct_def, std::string *code_ptr) { + auto &code = *code_ptr; + auto struct_name = MakeUpperCamel(struct_def); + + GenReceiverForObjectAPI(struct_def, code_ptr); + code += "Pack(self, builder):"; + code += GenIndents(2) + "return Create" + struct_name + "(builder"; + + StructBuilderArgs(struct_def, + /* nameprefix = */ "self.", + /* namesuffix = */ "", + /* has_field_name = */ true, + /* fieldname_suffix = */ ".", code_ptr); + code += ")\n"; + } + + void GenPackForStructVectorField(const StructDef &struct_def, + const FieldDef &field, + std::string *code_prefix_ptr, + std::string *code_ptr) { + auto &code_prefix = *code_prefix_ptr; + auto &code = *code_ptr; + auto field_instance_name = MakeLowerCamel(field); + auto struct_name = NormalizedName(struct_def); + auto field_accessor_name = MakeUpperCamel(field); + + // Creates the field. + code_prefix += + GenIndents(2) + "if self." + field_instance_name + " is not None:"; + if (field.value.type.struct_def->fixed) { + code_prefix += GenIndents(3) + "Start" + + field_accessor_name + "Vector(builder, len(self." + + field_instance_name + "))"; + code_prefix += GenIndents(3) + "for i in reversed(range(len(self." + + field_instance_name + "))):"; + code_prefix += + GenIndents(4) + "self." + field_instance_name + "[i].Pack(builder)"; + code_prefix += + GenIndents(3) + field_instance_name + " = builder.EndVector()"; + } else { + // If the vector is a struct vector, we need to first build accessor for + // each struct element. + code_prefix += GenIndents(3) + field_instance_name + "list = []"; + code_prefix += GenIndents(3); + code_prefix += "for i in range(len(self." + field_instance_name + ")):"; + code_prefix += GenIndents(4) + field_instance_name + "list.append(self." + + field_instance_name + "[i].Pack(builder))"; + + code_prefix += GenIndents(3) + "Start" + + field_accessor_name + "Vector(builder, len(self." + + field_instance_name + "))"; + code_prefix += GenIndents(3) + "for i in reversed(range(len(self." + + field_instance_name + "))):"; + code_prefix += GenIndents(4) + "builder.PrependUOffsetTRelative" + "(" + + field_instance_name + "list[i])"; + code_prefix += + GenIndents(3) + field_instance_name + " = builder.EndVector()"; + } + + // Adds the field into the struct. + code += GenIndents(2) + "if self." + field_instance_name + " is not None:"; + code += GenIndents(3) + "Add" + field_accessor_name + + "(builder, " + field_instance_name + ")"; + } + + void GenPackForScalarVectorFieldHelper(const StructDef &struct_def, + const FieldDef &field, + std::string *code_ptr, int indents) { + auto &code = *code_ptr; + auto field_instance_name = MakeLowerCamel(field); + auto field_accessor_name = MakeUpperCamel(field); + auto struct_name = NormalizedName(struct_def); + auto vectortype = field.value.type.VectorType(); + + code += GenIndents(indents) + "Start" + field_accessor_name + + "Vector(builder, len(self." + field_instance_name + "))"; + code += GenIndents(indents) + "for i in reversed(range(len(self." + + field_instance_name + "))):"; + code += GenIndents(indents + 1) + "builder.Prepend"; + + std::string type_name; + switch (vectortype.base_type) { + case BASE_TYPE_BOOL: type_name = "Bool"; break; + case BASE_TYPE_CHAR: type_name = "Byte"; break; + case BASE_TYPE_UCHAR: type_name = "Uint8"; break; + case BASE_TYPE_SHORT: type_name = "Int16"; break; + case BASE_TYPE_USHORT: type_name = "Uint16"; break; + case BASE_TYPE_INT: type_name = "Int32"; break; + case BASE_TYPE_UINT: type_name = "Uint32"; break; + case BASE_TYPE_LONG: type_name = "Int64"; break; + case BASE_TYPE_ULONG: type_name = "Uint64"; break; + case BASE_TYPE_FLOAT: type_name = "Float32"; break; + case BASE_TYPE_DOUBLE: type_name = "Float64"; break; + case BASE_TYPE_STRING: type_name = "UOffsetTRelative"; break; + default: type_name = "VOffsetT"; break; + } + code += type_name; + } + + void GenPackForScalarVectorField(const StructDef &struct_def, + const FieldDef &field, + std::string *code_prefix_ptr, + std::string *code_ptr) { + auto &code = *code_ptr; + auto &code_prefix = *code_prefix_ptr; + auto field_instance_name = MakeLowerCamel(field); + auto field_accessor_name = MakeUpperCamel(field); + auto struct_name = NormalizedName(struct_def); + + // Adds the field into the struct. + code += GenIndents(2) + "if self." + field_instance_name + " is not None:"; + code += GenIndents(3) + "Add" + field_accessor_name + + "(builder, " + field_instance_name + ")"; + + // Creates the field. + code_prefix += + GenIndents(2) + "if self." + field_instance_name + " is not None:"; + // If the vector is a string vector, we need to first build accessor for + // each string element. And this generated code, needs to be + // placed ahead of code_prefix. + auto vectortype = field.value.type.VectorType(); + if (IsString(vectortype)) { + code_prefix += GenIndents(3) + MakeLowerCamel(field) + "list = []"; + code_prefix += GenIndents(3) + "for i in range(len(self." + + field_instance_name + ")):"; + code_prefix += GenIndents(4) + MakeLowerCamel(field) + + "list.append(builder.CreateString(self." + + field_instance_name + "[i]))"; + GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 3); + code_prefix += "(" + MakeLowerCamel(field) + "list[i])"; + code_prefix += + GenIndents(3) + field_instance_name + " = builder.EndVector()"; + return; + } + + code_prefix += GenIndents(3) + "if np is not None and type(self." + + field_instance_name + ") is np.ndarray:"; + code_prefix += GenIndents(4) + field_instance_name + + " = builder.CreateNumpyVector(self." + field_instance_name + + ")"; + code_prefix += GenIndents(3) + "else:"; + GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 4); + code_prefix += "(self." + field_instance_name + "[i])"; + code_prefix += + GenIndents(4) + field_instance_name + " = builder.EndVector()"; + } + + void GenPackForStructField(const StructDef &struct_def, const FieldDef &field, + std::string *code_prefix_ptr, + std::string *code_ptr) { + auto &code_prefix = *code_prefix_ptr; + auto &code = *code_ptr; + auto field_instance_name = MakeLowerCamel(field); + + auto field_accessor_name = MakeUpperCamel(field); + auto struct_name = NormalizedName(struct_def); + + if (field.value.type.struct_def->fixed) { + // Pure struct fields need to be created along with their parent + // structs. + code += + GenIndents(2) + "if self." + field_instance_name + " is not None:"; + code += GenIndents(3) + field_instance_name + " = self." + + field_instance_name + ".Pack(builder)"; + } else { + // Tables need to be created before their parent structs are created. + code_prefix += + GenIndents(2) + "if self." + field_instance_name + " is not None:"; + code_prefix += GenIndents(3) + field_instance_name + " = self." + + field_instance_name + ".Pack(builder)"; + code += + GenIndents(2) + "if self." + field_instance_name + " is not None:"; + } + + code += GenIndents(3) + "Add" + field_accessor_name + + "(builder, " + field_instance_name + ")"; + } + + void GenPackForUnionField(const StructDef &struct_def, const FieldDef &field, + std::string *code_prefix_ptr, + std::string *code_ptr) { + auto &code_prefix = *code_prefix_ptr; + auto &code = *code_ptr; + auto field_instance_name = MakeLowerCamel(field); + + auto field_accessor_name = MakeUpperCamel(field); + auto struct_name = NormalizedName(struct_def); + + // TODO(luwa): TypeT should be moved under the None check as well. + code_prefix += + GenIndents(2) + "if self." + field_instance_name + " is not None:"; + code_prefix += GenIndents(3) + field_instance_name + " = self." + + field_instance_name + ".Pack(builder)"; + code += GenIndents(2) + "if self." + field_instance_name + " is not None:"; + code += GenIndents(3) + "Add" + field_accessor_name + + "(builder, " + field_instance_name + ")"; + } + + void GenPackForTable(const StructDef &struct_def, std::string *code_ptr) { + auto &code_base = *code_ptr; + std::string code, code_prefix; + auto struct_instance_name = MakeLowerCamel(struct_def); + auto struct_name = NormalizedName(struct_def); + + GenReceiverForObjectAPI(struct_def, code_ptr); + code_base += "Pack(self, builder):"; + code += GenIndents(2) + "Start(builder)"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + + auto field_accessor_name = MakeUpperCamel(field); + auto field_instance_name = MakeLowerCamel(field); + + switch (field.value.type.base_type) { + case BASE_TYPE_STRUCT: { + GenPackForStructField(struct_def, field, &code_prefix, &code); + break; + } + case BASE_TYPE_UNION: { + GenPackForUnionField(struct_def, field, &code_prefix, &code); + break; + } + case BASE_TYPE_VECTOR: { + auto vectortype = field.value.type.VectorType(); + if (vectortype.base_type == BASE_TYPE_STRUCT) { + GenPackForStructVectorField(struct_def, field, &code_prefix, &code); + } else { + GenPackForScalarVectorField(struct_def, field, &code_prefix, &code); + } + break; + } + case BASE_TYPE_ARRAY: { + GenPackForScalarVectorField(struct_def, field, &code_prefix, &code); + break; + } + case BASE_TYPE_STRING: { + code_prefix += GenIndents(2) + "if self." + field_instance_name + + " is not None:"; + code_prefix += GenIndents(3) + field_instance_name + + " = builder.CreateString(self." + field_instance_name + + ")"; + code += GenIndents(2) + "if self." + field_instance_name + + " is not None:"; + code += GenIndents(3) + "Add" + field_accessor_name + + "(builder, " + field_instance_name + ")"; + break; + } + default: + // Generates code for scalar values. If the value equals to the + // default value, builder will automatically ignore it. So we don't + // need to check the value ahead. + code += GenIndents(2) + "Add" + field_accessor_name + + "(builder, self." + field_instance_name + ")"; + break; + } + } + + code += GenIndents(2) + struct_instance_name + " = " + "End(builder)"; + code += GenIndents(2) + "return " + struct_instance_name; + + code_base += code_prefix + code; + code_base += "\n"; + } + + void GenStructForObjectAPI(const StructDef &struct_def, + std::string *code_ptr) { + if (struct_def.generated) return; + + std::set<std::string> import_list; + std::string code; + + // Creates an object class for a struct or a table + BeginClassForObjectAPI(struct_def, &code); + + GenInitialize(struct_def, &code, &import_list); + + InitializeFromBuf(struct_def, &code); + + InitializeFromObjForObject(struct_def, &code); + + GenUnPack(struct_def, &code); + + if (struct_def.fixed) { + GenPackForStruct(struct_def, &code); + } else { + GenPackForTable(struct_def, &code); + } + + // Adds the imports at top. + auto &code_base = *code_ptr; + code_base += "\n"; + for (auto it = import_list.begin(); it != import_list.end(); it++) { + auto im = *it; + code_base += im + "\n"; + } + code_base += code; + } + + void GenUnionCreatorForStruct(const EnumDef &enum_def, const EnumVal &ev, + std::string *code_ptr) { + auto &code = *code_ptr; + auto union_name = NormalizedName(enum_def); + auto field_name = NormalizedName(ev); + auto field_type = GenTypeGet(ev.union_type) + "T"; + + code += GenIndents(1) + "if unionType == " + union_name + "()." + + field_name + ":"; + if (parser_.opts.include_dependence_headers) { + auto package_reference = GenPackageReference(ev.union_type); + code += GenIndents(2) + "import " + package_reference; + field_type = package_reference + "." + field_type; + } + code += GenIndents(2) + "return " + field_type + + ".InitFromBuf(table.Bytes, table.Pos)"; + } + + void GenUnionCreatorForString(const EnumDef &enum_def, const EnumVal &ev, + std::string *code_ptr) { + auto &code = *code_ptr; + auto union_name = NormalizedName(enum_def); + auto field_name = NormalizedName(ev); + + code += GenIndents(1) + "if unionType == " + union_name + "()." + + field_name + ":"; + code += GenIndents(2) + "tab = Table(table.Bytes, table.Pos)"; + code += GenIndents(2) + "union = tab.String(table.Pos)"; + code += GenIndents(2) + "return union"; + } + + // Creates an union object based on union type. + void GenUnionCreator(const EnumDef &enum_def, std::string *code_ptr) { + auto &code = *code_ptr; + auto union_name = MakeUpperCamel(enum_def); + + code += "\n"; + code += "def " + union_name + "Creator(unionType, table):"; + code += GenIndents(1) + "from flatbuffers.table import Table"; + code += GenIndents(1) + "if not isinstance(table, Table):"; + code += GenIndents(2) + "return None"; + + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + auto &ev = **it; + // Union only supports string and table. + switch (ev.union_type.base_type) { + case BASE_TYPE_STRUCT: + GenUnionCreatorForStruct(enum_def, ev, &code); + break; + case BASE_TYPE_STRING: + GenUnionCreatorForString(enum_def, ev, &code); + break; + default: break; + } + } + code += GenIndents(1) + "return None"; + code += "\n"; + } + + // Generate enum declarations. + void GenEnum(const EnumDef &enum_def, std::string *code_ptr) { + if (enum_def.generated) return; + + GenComment(enum_def.doc_comment, code_ptr, &def_comment); + BeginEnum(NormalizedName(enum_def), code_ptr); + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + auto &ev = **it; + GenComment(ev.doc_comment, code_ptr, &def_comment, Indent.c_str()); + EnumMember(enum_def, ev, code_ptr); + } + EndEnum(code_ptr); + } + + // Returns the function name that is able to read a value of the given type. + std::string GenGetter(const Type &type) { + switch (type.base_type) { + case BASE_TYPE_STRING: return "self._tab.String("; + case BASE_TYPE_UNION: return "self._tab.Union("; + case BASE_TYPE_VECTOR: return GenGetter(type.VectorType()); + default: + return "self._tab.Get(flatbuffers.number_types." + + MakeCamel(GenTypeGet(type)) + "Flags, "; + } + } + + // Returns the method name for use with add/put calls. + std::string GenMethod(const FieldDef &field) { + return (IsScalar(field.value.type.base_type) || IsArray(field.value.type)) + ? MakeCamel(GenTypeBasic(field.value.type)) + : (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative"); + } + + std::string GenTypeBasic(const Type &type) { + // clang-format off + static const char *ctypename[] = { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, ...) \ + #PTYPE, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + }; + // clang-format on + return ctypename[IsArray(type) ? type.VectorType().base_type + : type.base_type]; + } + + std::string GenTypePointer(const Type &type) { + switch (type.base_type) { + case BASE_TYPE_STRING: return "string"; + case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType()); + case BASE_TYPE_STRUCT: return type.struct_def->name; + case BASE_TYPE_UNION: + // fall through + default: return "*flatbuffers.Table"; + } + } + + std::string GenTypeGet(const Type &type) { + return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type); + } + + std::string TypeName(const FieldDef &field) { + return GenTypeGet(field.value.type); + } + + // Create a struct with a builder and the struct's arguments. + void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) { + BeginBuilderArgs(struct_def, code_ptr); + StructBuilderArgs(struct_def, + /* nameprefix = */ "", + /* namesuffix = */ "", + /* has_field_name = */ true, + /* fieldname_suffix = */ "_", code_ptr); + EndBuilderArgs(code_ptr); + + StructBuilderBody(struct_def, "", code_ptr); + EndBuilderBody(code_ptr); + } + + bool generate() { + if (!generateEnums()) return false; + if (!generateStructs()) return false; + return true; + } + + private: + bool generateEnums() { + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + auto &enum_def = **it; + std::string enumcode; + GenEnum(enum_def, &enumcode); + if (parser_.opts.generate_object_based_api & enum_def.is_union) { + GenUnionCreator(enum_def, &enumcode); + } + if (!SaveType(enum_def, enumcode, false)) return false; + } + return true; + } + + bool generateStructs() { + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + auto &struct_def = **it; + std::string declcode; + GenStruct(struct_def, &declcode); + if (parser_.opts.generate_object_based_api) { + GenStructForObjectAPI(struct_def, &declcode); + } + if (!SaveType(struct_def, declcode, true)) return false; + } + return true; + } + + // Begin by declaring namespace and imports. + void BeginFile(const std::string &name_space_name, const bool needs_imports, + std::string *code_ptr) { + auto &code = *code_ptr; + code = code + "# " + FlatBuffersGeneratedWarning() + "\n\n"; + code += "# namespace: " + name_space_name + "\n\n"; + if (needs_imports) { + code += "import flatbuffers\n"; + code += "from flatbuffers.compat import import_numpy\n"; + code += "np = import_numpy()\n\n"; + } + } + + // Save out the generated code for a Python Table type. + bool SaveType(const Definition &def, const std::string &classcode, + bool needs_imports) { + if (!classcode.length()) return true; + + std::string namespace_dir = path_; + auto &namespaces = def.defined_namespace->components; + for (auto it = namespaces.begin(); it != namespaces.end(); ++it) { + if (it != namespaces.begin()) namespace_dir += kPathSeparator; + namespace_dir += *it; + std::string init_py_filename = namespace_dir + "/__init__.py"; + SaveFile(init_py_filename.c_str(), "", false); + } + + std::string code = ""; + BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code); + code += classcode; + std::string filename = + NamespaceDir(*def.defined_namespace) + NormalizedName(def) + ".py"; + return SaveFile(filename.c_str(), code, false); + } + + private: + std::unordered_set<std::string> keywords_; + const SimpleFloatConstantGenerator float_const_gen_; +}; + +} // namespace python + +bool GeneratePython(const Parser &parser, const std::string &path, + const std::string &file_name) { + python::PythonGenerator generator(parser, path, file_name); + return generator.generate(); +} + +} // namespace flatbuffers diff --git a/contrib/libs/flatbuffers/src/idl_gen_rust.cpp b/contrib/libs/flatbuffers/src/idl_gen_rust.cpp new file mode 100644 index 0000000000..455780cd94 --- /dev/null +++ b/contrib/libs/flatbuffers/src/idl_gen_rust.cpp @@ -0,0 +1,2817 @@ +/* + * Copyright 2018 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// independent from idl_parser, since this code is not needed for most clients + +#include "flatbuffers/code_generators.h" +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +namespace flatbuffers { + +// Convert a camelCaseIdentifier or CamelCaseIdentifier to a +// snake_case_identifier. +std::string MakeSnakeCase(const std::string &in) { + std::string s; + for (size_t i = 0; i < in.length(); i++) { + if (i == 0) { + s += CharToLower(in[0]); + } else if (in[i] == '_') { + s += '_'; + } else if (!islower(in[i])) { + // Prevent duplicate underscores for Upper_Snake_Case strings + // and UPPERCASE strings. + if (islower(in[i - 1])) { s += '_'; } + s += CharToLower(in[i]); + } else { + s += in[i]; + } + } + return s; +} + +// Convert a string to all uppercase. +std::string MakeUpper(const std::string &in) { + std::string s; + for (size_t i = 0; i < in.length(); i++) { s += CharToUpper(in[i]); } + return s; +} + +// Encapsulate all logical field types in this enum. This allows us to write +// field logic based on type switches, instead of branches on the properties +// set on the Type. +// TODO(rw): for backwards compatibility, we can't use a strict `enum class` +// declaration here. could we use the `-Wswitch-enum` warning to +// achieve the same effect? +enum FullType { + ftInteger = 0, + ftFloat = 1, + ftBool = 2, + + ftStruct = 3, + ftTable = 4, + + ftEnumKey = 5, + ftUnionKey = 6, + + ftUnionValue = 7, + + // TODO(rw): bytestring? + ftString = 8, + + ftVectorOfInteger = 9, + ftVectorOfFloat = 10, + ftVectorOfBool = 11, + ftVectorOfEnumKey = 12, + ftVectorOfStruct = 13, + ftVectorOfTable = 14, + ftVectorOfString = 15, + ftVectorOfUnionValue = 16, + + ftArrayOfBuiltin = 17, + ftArrayOfEnum = 18, + ftArrayOfStruct = 19, +}; + +// Convert a Type to a FullType (exhaustive). +FullType GetFullType(const Type &type) { + // N.B. The order of these conditionals matters for some types. + + if (IsString(type)) { + return ftString; + } else if (type.base_type == BASE_TYPE_STRUCT) { + if (type.struct_def->fixed) { + return ftStruct; + } else { + return ftTable; + } + } else if (IsVector(type)) { + switch (GetFullType(type.VectorType())) { + case ftInteger: { + return ftVectorOfInteger; + } + case ftFloat: { + return ftVectorOfFloat; + } + case ftBool: { + return ftVectorOfBool; + } + case ftStruct: { + return ftVectorOfStruct; + } + case ftTable: { + return ftVectorOfTable; + } + case ftString: { + return ftVectorOfString; + } + case ftEnumKey: { + return ftVectorOfEnumKey; + } + case ftUnionKey: + case ftUnionValue: { + FLATBUFFERS_ASSERT(false && "vectors of unions are unsupported"); + break; + } + default: { + FLATBUFFERS_ASSERT(false && "vector of vectors are unsupported"); + } + } + } else if (IsArray(type)) { + switch (GetFullType(type.VectorType())) { + case ftInteger: + case ftFloat: + case ftBool: { + return ftArrayOfBuiltin; + } + case ftStruct: { + return ftArrayOfStruct; + } + case ftEnumKey: { + return ftArrayOfEnum; + } + default: { + FLATBUFFERS_ASSERT(false && "Unsupported type for fixed array"); + } + } + } else if (type.enum_def != nullptr) { + if (type.enum_def->is_union) { + if (type.base_type == BASE_TYPE_UNION) { + return ftUnionValue; + } else if (IsInteger(type.base_type)) { + return ftUnionKey; + } else { + FLATBUFFERS_ASSERT(false && "unknown union field type"); + } + } else { + return ftEnumKey; + } + } else if (IsScalar(type.base_type)) { + if (IsBool(type.base_type)) { + return ftBool; + } else if (IsInteger(type.base_type)) { + return ftInteger; + } else if (IsFloat(type.base_type)) { + return ftFloat; + } else { + FLATBUFFERS_ASSERT(false && "unknown number type"); + } + } + + FLATBUFFERS_ASSERT(false && "completely unknown type"); + + // this is only to satisfy the compiler's return analysis. + return ftBool; +} + +// If the second parameter is false then wrap the first with Option<...> +std::string WrapInOptionIfNotRequired(std::string s, bool required) { + if (required) { + return s; + } else { + return "Option<" + s + ">"; + } +} + +// If the second parameter is false then add .unwrap() +std::string AddUnwrapIfRequired(std::string s, bool required) { + if (required) { + return s + ".unwrap()"; + } else { + return s; + } +} + +bool IsBitFlagsEnum(const EnumDef &enum_def) { + return enum_def.attributes.Lookup("bit_flags") != nullptr; +} +bool IsBitFlagsEnum(const FieldDef &field) { + EnumDef *ed = field.value.type.enum_def; + return ed && IsBitFlagsEnum(*ed); +} + +// TableArgs make required non-scalars "Option<_>". +// TODO(cneo): Rework how we do defaults and stuff. +bool IsOptionalToBuilder(const FieldDef &field) { + return field.IsOptional() || !IsScalar(field.value.type.base_type); +} + +namespace rust { + +class RustGenerator : public BaseGenerator { + public: + RustGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name, "", "::", "rs"), + cur_name_space_(nullptr) { + const char *keywords[] = { + // clang-format off + // list taken from: + // https://doc.rust-lang.org/book/second-edition/appendix-01-keywords.html + // + // we write keywords one per line so that we can easily compare them with + // changes to that webpage in the future. + + // currently-used keywords + "as", + "break", + "const", + "continue", + "crate", + "else", + "enum", + "extern", + "false", + "fn", + "for", + "if", + "impl", + "in", + "let", + "loop", + "match", + "mod", + "move", + "mut", + "pub", + "ref", + "return", + "Self", + "self", + "static", + "struct", + "super", + "trait", + "true", + "type", + "unsafe", + "use", + "where", + "while", + + // future possible keywords + "abstract", + "alignof", + "become", + "box", + "do", + "final", + "macro", + "offsetof", + "override", + "priv", + "proc", + "pure", + "sizeof", + "typeof", + "unsized", + "virtual", + "yield", + + // other rust terms we should not use + "std", + "usize", + "isize", + "u8", + "i8", + "u16", + "i16", + "u32", + "i32", + "u64", + "i64", + "u128", + "i128", + "f32", + "f64", + + // These are terms the code generator can implement on types. + // + // In Rust, the trait resolution rules (as described at + // https://github.com/rust-lang/rust/issues/26007) mean that, as long + // as we impl table accessors as inherent methods, we'll never create + // conflicts with these keywords. However, that's a fairly nuanced + // implementation detail, and how we implement methods could change in + // the future. as a result, we proactively block these out as reserved + // words. + "follow", + "push", + "size", + "alignment", + "to_little_endian", + "from_little_endian", + nullptr, + + // used by Enum constants + "ENUM_MAX", + "ENUM_MIN", + "ENUM_VALUES", + }; + for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw); + } + + // Iterate through all definitions we haven't generated code for (enums, + // structs, and tables) and output them to a single file. + bool generate() { + code_.Clear(); + code_ += "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n"; + + assert(!cur_name_space_); + + // Generate imports for the global scope in case no namespace is used + // in the schema file. + GenNamespaceImports(0); + code_ += ""; + + // Generate all code in their namespaces, once, because Rust does not + // permit re-opening modules. + // + // TODO(rw): Use a set data structure to reduce namespace evaluations from + // O(n**2) to O(n). + for (auto ns_it = parser_.namespaces_.begin(); + ns_it != parser_.namespaces_.end(); ++ns_it) { + const auto &ns = *ns_it; + + // Generate code for all the enum declarations. + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + const auto &enum_def = **it; + if (enum_def.defined_namespace == ns && !enum_def.generated) { + SetNameSpace(enum_def.defined_namespace); + GenEnum(enum_def); + } + } + + // Generate code for all structs. + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + const auto &struct_def = **it; + if (struct_def.defined_namespace == ns && struct_def.fixed && + !struct_def.generated) { + SetNameSpace(struct_def.defined_namespace); + GenStruct(struct_def); + } + } + + // Generate code for all tables. + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + const auto &struct_def = **it; + if (struct_def.defined_namespace == ns && !struct_def.fixed && + !struct_def.generated) { + SetNameSpace(struct_def.defined_namespace); + GenTable(struct_def); + if (parser_.opts.generate_object_based_api) { + GenTableObject(struct_def); + } + } + } + + // Generate global helper functions. + if (parser_.root_struct_def_) { + auto &struct_def = *parser_.root_struct_def_; + if (struct_def.defined_namespace != ns) { continue; } + SetNameSpace(struct_def.defined_namespace); + GenRootTableFuncs(struct_def); + } + } + if (cur_name_space_) SetNameSpace(nullptr); + + const auto file_path = GeneratedFileName(path_, file_name_, parser_.opts); + const auto final_code = code_.ToString(); + return SaveFile(file_path.c_str(), final_code, false); + } + + private: + CodeWriter code_; + + std::set<std::string> keywords_; + + // This tracks the current namespace so we can insert namespace declarations. + const Namespace *cur_name_space_; + + const Namespace *CurrentNameSpace() const { return cur_name_space_; } + + // Determine if a Type needs a lifetime template parameter when used in the + // Rust builder args. + bool TableBuilderTypeNeedsLifetime(const Type &type) const { + switch (GetFullType(type)) { + case ftInteger: + case ftFloat: + case ftBool: + case ftEnumKey: + case ftUnionKey: + case ftUnionValue: { + return false; + } + default: { + return true; + } + } + } + + // Determine if a table args rust type needs a lifetime template parameter. + bool TableBuilderArgsNeedsLifetime(const StructDef &struct_def) const { + FLATBUFFERS_ASSERT(!struct_def.fixed); + + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.deprecated) { continue; } + + if (TableBuilderTypeNeedsLifetime(field.value.type)) { return true; } + } + + return false; + } + + std::string EscapeKeyword(const std::string &name) const { + return keywords_.find(name) == keywords_.end() ? name : name + "_"; + } + std::string NamespacedNativeName(const Definition &def) { + return WrapInNameSpace(def.defined_namespace, NativeName(def)); + } + + std::string NativeName(const Definition &def) { + return parser_.opts.object_prefix + Name(def) + parser_.opts.object_suffix; + } + + std::string Name(const Definition &def) const { + return EscapeKeyword(def.name); + } + + std::string Name(const EnumVal &ev) const { return EscapeKeyword(ev.name); } + + std::string WrapInNameSpace(const Definition &def) const { + return WrapInNameSpace(def.defined_namespace, Name(def)); + } + std::string WrapInNameSpace(const Namespace *ns, + const std::string &name) const { + if (CurrentNameSpace() == ns) return name; + std::string prefix = GetRelativeNamespaceTraversal(CurrentNameSpace(), ns); + return prefix + name; + } + + // Determine the namespace traversal needed from the Rust crate root. + // This may be useful in the future for referring to included files, but is + // currently unused. + std::string GetAbsoluteNamespaceTraversal(const Namespace *dst) const { + std::stringstream stream; + + stream << "::"; + for (auto d = dst->components.begin(); d != dst->components.end(); ++d) { + stream << MakeSnakeCase(*d) + "::"; + } + return stream.str(); + } + + // Determine the relative namespace traversal needed to reference one + // namespace from another namespace. This is useful because it does not force + // the user to have a particular file layout. (If we output absolute + // namespace paths, that may require users to organize their Rust crates in a + // particular way.) + std::string GetRelativeNamespaceTraversal(const Namespace *src, + const Namespace *dst) const { + // calculate the path needed to reference dst from src. + // example: f(A::B::C, A::B::C) -> (none) + // example: f(A::B::C, A::B) -> super:: + // example: f(A::B::C, A::B::D) -> super::D + // example: f(A::B::C, A) -> super::super:: + // example: f(A::B::C, D) -> super::super::super::D + // example: f(A::B::C, D::E) -> super::super::super::D::E + // example: f(A, D::E) -> super::D::E + // does not include leaf object (typically a struct type). + + size_t i = 0; + std::stringstream stream; + + auto s = src->components.begin(); + auto d = dst->components.begin(); + for (;;) { + if (s == src->components.end()) { break; } + if (d == dst->components.end()) { break; } + if (*s != *d) { break; } + ++s; + ++d; + ++i; + } + + for (; s != src->components.end(); ++s) { stream << "super::"; } + for (; d != dst->components.end(); ++d) { + stream << MakeSnakeCase(*d) + "::"; + } + return stream.str(); + } + + // Generate a comment from the schema. + void GenComment(const std::vector<std::string> &dc, const char *prefix = "") { + std::string text; + ::flatbuffers::GenComment(dc, &text, nullptr, prefix); + code_ += text + "\\"; + } + + // Return a Rust type from the table in idl.h. + std::string GetTypeBasic(const Type &type) const { + switch (GetFullType(type)) { + case ftInteger: + case ftFloat: + case ftBool: + case ftEnumKey: + case ftUnionKey: { + break; + } + default: { + FLATBUFFERS_ASSERT(false && "incorrect type given"); + } + } + + // clang-format off + static const char * const ctypename[] = { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \ + RTYPE, ...) \ + #RTYPE, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + }; + // clang-format on + + if (type.enum_def) { return WrapInNameSpace(*type.enum_def); } + return ctypename[type.base_type]; + } + + // Look up the native type for an enum. This will always be an integer like + // u8, i32, etc. + std::string GetEnumTypeForDecl(const Type &type) { + const auto ft = GetFullType(type); + if (!(ft == ftEnumKey || ft == ftUnionKey)) { + FLATBUFFERS_ASSERT(false && "precondition failed in GetEnumTypeForDecl"); + } + + // clang-format off + static const char *ctypename[] = { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, \ + RTYPE, ...) \ + #RTYPE, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + }; + // clang-format on + + // Enums can be bools, but their Rust representation must be a u8, as used + // in the repr attribute (#[repr(bool)] is an invalid attribute). + if (type.base_type == BASE_TYPE_BOOL) return "u8"; + return ctypename[type.base_type]; + } + + // Return a Rust type for any type (scalar, table, struct) specifically for + // using a FlatBuffer. + std::string GetTypeGet(const Type &type) const { + switch (GetFullType(type)) { + case ftInteger: + case ftFloat: + case ftBool: + case ftEnumKey: + case ftUnionKey: { + return GetTypeBasic(type); + } + case ftArrayOfBuiltin: + case ftArrayOfEnum: + case ftArrayOfStruct: { + return "[" + GetTypeGet(type.VectorType()) + "; " + + NumToString(type.fixed_length) + "]"; + } + case ftTable: { + return WrapInNameSpace(type.struct_def->defined_namespace, + type.struct_def->name) + + "<'a>"; + } + default: { + return WrapInNameSpace(type.struct_def->defined_namespace, + type.struct_def->name); + } + } + } + + std::string GetEnumValue(const EnumDef &enum_def, + const EnumVal &enum_val) const { + return Name(enum_def) + "::" + Name(enum_val); + } + + // 1 suffix since old C++ can't figure out the overload. + void ForAllEnumValues1(const EnumDef &enum_def, + std::function<void(const EnumVal &)> cb) { + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + const auto &ev = **it; + code_.SetValue("VARIANT", Name(ev)); + code_.SetValue("VALUE", enum_def.ToString(ev)); + cb(ev); + } + } + void ForAllEnumValues(const EnumDef &enum_def, std::function<void()> cb) { + std::function<void(const EnumVal &)> wrapped = [&](const EnumVal &unused) { + (void)unused; + cb(); + }; + ForAllEnumValues1(enum_def, wrapped); + } + // Generate an enum declaration, + // an enum string lookup table, + // an enum match function, + // and an enum array of values + void GenEnum(const EnumDef &enum_def) { + code_.SetValue("ENUM_NAME", Name(enum_def)); + code_.SetValue("BASE_TYPE", GetEnumTypeForDecl(enum_def.underlying_type)); + code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def))); + code_.SetValue("ENUM_NAME_CAPS", MakeUpper(MakeSnakeCase(Name(enum_def)))); + const EnumVal *minv = enum_def.MinValue(); + const EnumVal *maxv = enum_def.MaxValue(); + FLATBUFFERS_ASSERT(minv && maxv); + code_.SetValue("ENUM_MIN_BASE_VALUE", enum_def.ToString(*minv)); + code_.SetValue("ENUM_MAX_BASE_VALUE", enum_def.ToString(*maxv)); + + if (IsBitFlagsEnum(enum_def)) { + // Defer to the convenient and canonical bitflags crate. We declare it in + // a module to #allow camel case constants in a smaller scope. This + // matches Flatbuffers c-modeled enums where variants are associated + // constants but in camel case. + code_ += "#[allow(non_upper_case_globals)]"; + code_ += "mod bitflags_{{ENUM_NAME_SNAKE}} {"; + code_ += " flatbuffers::bitflags::bitflags! {"; + GenComment(enum_def.doc_comment, " "); + code_ += " #[derive(Default)]"; + code_ += " pub struct {{ENUM_NAME}}: {{BASE_TYPE}} {"; + ForAllEnumValues1(enum_def, [&](const EnumVal &ev) { + this->GenComment(ev.doc_comment, " "); + code_ += " const {{VARIANT}} = {{VALUE}};"; + }); + code_ += " }"; + code_ += " }"; + code_ += "}"; + code_ += "pub use self::bitflags_{{ENUM_NAME_SNAKE}}::{{ENUM_NAME}};"; + code_ += ""; + + code_.SetValue("FROM_BASE", "unsafe { Self::from_bits_unchecked(b) }"); + code_.SetValue("INTO_BASE", "self.bits()"); + } else { + // Normal, c-modelled enums. + // Deprecated associated constants; + const std::string deprecation_warning = + "#[deprecated(since = \"2.0.0\", note = \"Use associated constants" + " instead. This will no longer be generated in 2021.\")]"; + code_ += deprecation_warning; + code_ += + "pub const ENUM_MIN_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}" + " = {{ENUM_MIN_BASE_VALUE}};"; + code_ += deprecation_warning; + code_ += + "pub const ENUM_MAX_{{ENUM_NAME_CAPS}}: {{BASE_TYPE}}" + " = {{ENUM_MAX_BASE_VALUE}};"; + auto num_fields = NumToString(enum_def.size()); + code_ += deprecation_warning; + code_ += "#[allow(non_camel_case_types)]"; + code_ += "pub const ENUM_VALUES_{{ENUM_NAME_CAPS}}: [{{ENUM_NAME}}; " + + num_fields + "] = ["; + ForAllEnumValues1(enum_def, [&](const EnumVal &ev) { + code_ += " " + GetEnumValue(enum_def, ev) + ","; + }); + code_ += "];"; + code_ += ""; + + GenComment(enum_def.doc_comment); + // Derive Default to be 0. flatc enforces this when the enum + // is put into a struct, though this isn't documented behavior, it is + // needed to derive defaults in struct objects. + code_ += + "#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, " + "Default)]"; + code_ += "#[repr(transparent)]"; + code_ += "pub struct {{ENUM_NAME}}(pub {{BASE_TYPE}});"; + code_ += "#[allow(non_upper_case_globals)]"; + code_ += "impl {{ENUM_NAME}} {"; + ForAllEnumValues1(enum_def, [&](const EnumVal &ev) { + this->GenComment(ev.doc_comment, " "); + code_ += " pub const {{VARIANT}}: Self = Self({{VALUE}});"; + }); + code_ += ""; + // Generate Associated constants + code_ += " pub const ENUM_MIN: {{BASE_TYPE}} = {{ENUM_MIN_BASE_VALUE}};"; + code_ += " pub const ENUM_MAX: {{BASE_TYPE}} = {{ENUM_MAX_BASE_VALUE}};"; + code_ += " pub const ENUM_VALUES: &'static [Self] = &["; + ForAllEnumValues(enum_def, [&]() { code_ += " Self::{{VARIANT}},"; }); + code_ += " ];"; + code_ += " /// Returns the variant's name or \"\" if unknown."; + code_ += " pub fn variant_name(self) -> Option<&'static str> {"; + code_ += " match self {"; + ForAllEnumValues(enum_def, [&]() { + code_ += " Self::{{VARIANT}} => Some(\"{{VARIANT}}\"),"; + }); + code_ += " _ => None,"; + code_ += " }"; + code_ += " }"; + code_ += "}"; + + // Generate Debug. Unknown variants are printed like "<UNKNOWN 42>". + code_ += "impl std::fmt::Debug for {{ENUM_NAME}} {"; + code_ += + " fn fmt(&self, f: &mut std::fmt::Formatter) ->" + " std::fmt::Result {"; + code_ += " if let Some(name) = self.variant_name() {"; + code_ += " f.write_str(name)"; + code_ += " } else {"; + code_ += " f.write_fmt(format_args!(\"<UNKNOWN {:?}>\", self.0))"; + code_ += " }"; + code_ += " }"; + code_ += "}"; + + code_.SetValue("FROM_BASE", "Self(b)"); + code_.SetValue("INTO_BASE", "self.0"); + } + + // Generate Follow and Push so we can serialize and stuff. + code_ += "impl<'a> flatbuffers::Follow<'a> for {{ENUM_NAME}} {"; + code_ += " type Inner = Self;"; + code_ += " #[inline]"; + code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {"; + code_ += " let b = unsafe {"; + code_ += " flatbuffers::read_scalar_at::<{{BASE_TYPE}}>(buf, loc)"; + code_ += " };"; + code_ += " {{FROM_BASE}}"; + code_ += " }"; + code_ += "}"; + code_ += ""; + code_ += "impl flatbuffers::Push for {{ENUM_NAME}} {"; + code_ += " type Output = {{ENUM_NAME}};"; + code_ += " #[inline]"; + code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {"; + code_ += + " unsafe { flatbuffers::emplace_scalar::<{{BASE_TYPE}}>" + "(dst, {{INTO_BASE}}); }"; + code_ += " }"; + code_ += "}"; + code_ += ""; + code_ += "impl flatbuffers::EndianScalar for {{ENUM_NAME}} {"; + code_ += " #[inline]"; + code_ += " fn to_little_endian(self) -> Self {"; + code_ += " let b = {{BASE_TYPE}}::to_le({{INTO_BASE}});"; + code_ += " {{FROM_BASE}}"; + code_ += " }"; + code_ += " #[inline]"; + code_ += " #[allow(clippy::wrong_self_convention)]"; + code_ += " fn from_little_endian(self) -> Self {"; + code_ += " let b = {{BASE_TYPE}}::from_le({{INTO_BASE}});"; + code_ += " {{FROM_BASE}}"; + code_ += " }"; + code_ += "}"; + code_ += ""; + + // Generate verifier - deferring to the base type. + code_ += "impl<'a> flatbuffers::Verifiable for {{ENUM_NAME}} {"; + code_ += " #[inline]"; + code_ += " fn run_verifier("; + code_ += " v: &mut flatbuffers::Verifier, pos: usize"; + code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {"; + code_ += " use self::flatbuffers::Verifiable;"; + code_ += " {{BASE_TYPE}}::run_verifier(v, pos)"; + code_ += " }"; + code_ += "}"; + code_ += ""; + // Enums are basically integers. + code_ += "impl flatbuffers::SimpleToVerifyInSlice for {{ENUM_NAME}} {}"; + + if (enum_def.is_union) { + // Generate typesafe offset(s) for unions + code_.SetValue("NAME", Name(enum_def)); + code_.SetValue("UNION_OFFSET_NAME", Name(enum_def) + "UnionTableOffset"); + code_ += "pub struct {{UNION_OFFSET_NAME}} {}"; + code_ += ""; + if (parser_.opts.generate_object_based_api) { GenUnionObject(enum_def); } + } + } + + // CASPER: dedup Object versions from non object versions. + void ForAllUnionObjectVariantsBesidesNone(const EnumDef &enum_def, + std::function<void()> cb) { + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + auto &enum_val = **it; + if (enum_val.union_type.base_type == BASE_TYPE_NONE) continue; + code_.SetValue("VARIANT_NAME", Name(enum_val)); + code_.SetValue("NATIVE_VARIANT", MakeCamel(Name(enum_val))); + code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(enum_val))); + code_.SetValue("U_ELEMENT_TABLE_TYPE", + NamespacedNativeName(*enum_val.union_type.struct_def)); + cb(); + } + } + void GenUnionObject(const EnumDef &enum_def) { + code_.SetValue("ENUM_NAME", Name(enum_def)); + code_.SetValue("ENUM_NAME_SNAKE", MakeSnakeCase(Name(enum_def))); + code_.SetValue("NATIVE_NAME", NativeName(enum_def)); + + // Generate native union. + code_ += "#[non_exhaustive]"; + code_ += "#[derive(Debug, Clone, PartialEq)]"; + code_ += "pub enum {{NATIVE_NAME}} {"; + code_ += " NONE,"; + ForAllUnionObjectVariantsBesidesNone(enum_def, [&] { + code_ += " {{NATIVE_VARIANT}}(Box<{{U_ELEMENT_TABLE_TYPE}}>),"; + }); + code_ += "}"; + // Generate Default (NONE). + code_ += "impl Default for {{NATIVE_NAME}} {"; + code_ += " fn default() -> Self {"; + code_ += " Self::NONE"; + code_ += " }"; + code_ += "}"; + + // Generate native union methods. + code_ += "impl {{NATIVE_NAME}} {"; + + // Get flatbuffers union key. + // CASPER: add docstrings? + code_ += " pub fn {{ENUM_NAME_SNAKE}}_type(&self) -> {{ENUM_NAME}} {"; + code_ += " match self {"; + code_ += " Self::NONE => {{ENUM_NAME}}::NONE,"; + ForAllUnionObjectVariantsBesidesNone(enum_def, [&] { + code_ += + " Self::{{NATIVE_VARIANT}}(_) => {{ENUM_NAME}}::" + "{{VARIANT_NAME}},"; + }); + code_ += " }"; + code_ += " }"; + // Pack flatbuffers union value + code_ += + " pub fn pack(&self, fbb: &mut flatbuffers::FlatBufferBuilder)" + " -> Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>" + " {"; + code_ += " match self {"; + code_ += " Self::NONE => None,"; + ForAllUnionObjectVariantsBesidesNone(enum_def, [&] { + code_ += + " Self::{{NATIVE_VARIANT}}(v) => " + "Some(v.pack(fbb).as_union_value()),"; + }); + code_ += " }"; + code_ += " }"; + + // Generate some accessors; + ForAllUnionObjectVariantsBesidesNone(enum_def, [&] { + // Move accessor. + code_ += + " /// If the union variant matches, return the owned " + "{{U_ELEMENT_TABLE_TYPE}}, setting the union to NONE."; + code_ += + " pub fn take_{{U_ELEMENT_NAME}}(&mut self) -> " + "Option<Box<{{U_ELEMENT_TABLE_TYPE}}>> {"; + code_ += " if let Self::{{NATIVE_VARIANT}}(_) = self {"; + code_ += " let v = std::mem::replace(self, Self::NONE);"; + code_ += " if let Self::{{NATIVE_VARIANT}}(w) = v {"; + code_ += " Some(w)"; + code_ += " } else {"; + code_ += " unreachable!()"; + code_ += " }"; + code_ += " } else {"; + code_ += " None"; + code_ += " }"; + code_ += " }"; + // Immutable reference accessor. + code_ += + " /// If the union variant matches, return a reference to the " + "{{U_ELEMENT_TABLE_TYPE}}."; + code_ += + " pub fn as_{{U_ELEMENT_NAME}}(&self) -> " + "Option<&{{U_ELEMENT_TABLE_TYPE}}> {"; + code_ += + " if let Self::{{NATIVE_VARIANT}}(v) = self " + "{ Some(v.as_ref()) } else { None }"; + code_ += " }"; + // Mutable reference accessor. + code_ += + " /// If the union variant matches, return a mutable reference" + " to the {{U_ELEMENT_TABLE_TYPE}}."; + code_ += + " pub fn as_{{U_ELEMENT_NAME}}_mut(&mut self) -> " + "Option<&mut {{U_ELEMENT_TABLE_TYPE}}> {"; + code_ += + " if let Self::{{NATIVE_VARIANT}}(v) = self " + "{ Some(v.as_mut()) } else { None }"; + code_ += " }"; + }); + code_ += "}"; // End union methods impl. + } + + std::string GetFieldOffsetName(const FieldDef &field) { + return "VT_" + MakeUpper(Name(field)); + } + + enum DefaultContext { kBuilder, kAccessor, kObject }; + std::string GetDefaultValue(const FieldDef &field, + const DefaultContext context) { + if (context == kBuilder) { + // Builders and Args structs model nonscalars "optional" even if they're + // required or have defaults according to the schema. I guess its because + // WIPOffset is not nullable. + if (!IsScalar(field.value.type.base_type) || field.IsOptional()) { + return "None"; + } + } else { + // This for defaults in objects. + // Unions have a NONE variant instead of using Rust's None. + if (field.IsOptional() && !IsUnion(field.value.type)) { return "None"; } + } + switch (GetFullType(field.value.type)) { + case ftInteger: + case ftFloat: { + return field.value.constant; + } + case ftBool: { + return field.value.constant == "0" ? "false" : "true"; + } + case ftUnionKey: + case ftEnumKey: { + auto ev = field.value.type.enum_def->FindByValue(field.value.constant); + if (!ev) return "Default::default()"; // Bitflags enum. + return WrapInNameSpace(field.value.type.enum_def->defined_namespace, + GetEnumValue(*field.value.type.enum_def, *ev)); + } + case ftUnionValue: { + return ObjectFieldType(field, true) + "::NONE"; + } + case ftString: { + // Required fields do not have defaults defined by the schema, but we + // need one for Rust's Default trait so we use empty string. The usual + // value of field.value.constant is `0`, which is non-sensical except + // maybe to c++ (nullptr == 0). + // TODO: Escape strings? + const std::string defval = + field.IsRequired() ? "\"\"" : "\"" + field.value.constant + "\""; + if (context == kObject) return defval + ".to_string()"; + if (context == kAccessor) return "&" + defval; + FLATBUFFERS_ASSERT("Unreachable."); + return "INVALID_CODE_GENERATION"; + } + + case ftArrayOfStruct: + case ftArrayOfEnum: + case ftArrayOfBuiltin: + case ftVectorOfBool: + case ftVectorOfFloat: + case ftVectorOfInteger: + case ftVectorOfString: + case ftVectorOfStruct: + case ftVectorOfTable: + case ftVectorOfEnumKey: + case ftVectorOfUnionValue: + case ftStruct: + case ftTable: { + // We only support empty vectors which matches the defaults for + // &[T] and Vec<T> anyway. + // + // For required structs and tables fields, we defer to their object API + // defaults. This works so long as there's nothing recursive happening, + // but `table Infinity { i: Infinity (required); }` does compile. + return "Default::default()"; + } + } + FLATBUFFERS_ASSERT("Unreachable."); + return "INVALID_CODE_GENERATION"; + } + + // Create the return type for fields in the *BuilderArgs structs that are + // used to create Tables. + // + // Note: we could make all inputs to the BuilderArgs be an Option, as well + // as all outputs. But, the UX of Flatbuffers is that the user doesn't get to + // know if the value is default or not, because there are three ways to + // return a default value: + // 1) return a stored value that happens to be the default, + // 2) return a hardcoded value because the relevant vtable field is not in + // the vtable, or + // 3) return a hardcoded value because the vtable field value is set to zero. + std::string TableBuilderArgsDefnType(const FieldDef &field, + const std::string &lifetime) { + const Type &type = field.value.type; + auto WrapOption = [&](std::string s) { + return IsOptionalToBuilder(field) ? "Option<" + s + ">" : s; + }; + auto WrapVector = [&](std::string ty) { + return WrapOption("flatbuffers::WIPOffset<flatbuffers::Vector<" + + lifetime + ", " + ty + ">>"); + }; + auto WrapUOffsetsVector = [&](std::string ty) { + return WrapVector("flatbuffers::ForwardsUOffset<" + ty + ">"); + }; + + switch (GetFullType(type)) { + case ftInteger: + case ftFloat: + case ftBool: { + return WrapOption(GetTypeBasic(type)); + } + case ftStruct: { + const auto typname = WrapInNameSpace(*type.struct_def); + return WrapOption("&" + lifetime + " " + typname); + } + case ftTable: { + const auto typname = WrapInNameSpace(*type.struct_def); + return WrapOption("flatbuffers::WIPOffset<" + typname + "<" + lifetime + + ">>"); + } + case ftString: { + return WrapOption("flatbuffers::WIPOffset<&" + lifetime + " str>"); + } + case ftEnumKey: + case ftUnionKey: { + return WrapOption(WrapInNameSpace(*type.enum_def)); + } + case ftUnionValue: { + return "Option<flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>>"; + } + + case ftVectorOfInteger: + case ftVectorOfBool: + case ftVectorOfFloat: { + const auto typname = GetTypeBasic(type.VectorType()); + return WrapVector(typname); + } + case ftVectorOfEnumKey: { + const auto typname = WrapInNameSpace(*type.enum_def); + return WrapVector(typname); + } + case ftVectorOfStruct: { + const auto typname = WrapInNameSpace(*type.struct_def); + return WrapVector(typname); + } + case ftVectorOfTable: { + const auto typname = WrapInNameSpace(*type.struct_def); + return WrapUOffsetsVector(typname + "<" + lifetime + ">"); + } + case ftVectorOfString: { + return WrapUOffsetsVector("&" + lifetime + " str"); + } + case ftVectorOfUnionValue: { + return WrapUOffsetsVector("flatbuffers::Table<" + lifetime + ">"); + } + case ftArrayOfEnum: + case ftArrayOfStruct: + case ftArrayOfBuiltin: { + FLATBUFFERS_ASSERT(false && "arrays are not supported within tables"); + return "ARRAYS_NOT_SUPPORTED_IN_TABLES"; + } + } + return "INVALID_CODE_GENERATION"; // for return analysis + } + + std::string ObjectFieldType(const FieldDef &field, bool in_a_table) { + const Type &type = field.value.type; + std::string ty; + switch (GetFullType(type)) { + case ftInteger: + case ftBool: + case ftFloat: { + ty = GetTypeBasic(type); + break; + } + case ftString: { + ty = "String"; + break; + } + case ftStruct: { + ty = NamespacedNativeName(*type.struct_def); + break; + } + case ftTable: { + // Since Tables can contain themselves, Box is required to avoid + // infinite types. + ty = "Box<" + NamespacedNativeName(*type.struct_def) + ">"; + break; + } + case ftUnionKey: { + // There is no native "UnionKey", natively, unions are rust enums with + // newtype-struct-variants. + return "INVALID_CODE_GENERATION"; + } + case ftUnionValue: { + ty = NamespacedNativeName(*type.enum_def); + break; + } + case ftEnumKey: { + ty = WrapInNameSpace(*type.enum_def); + break; + } + // Vectors are in tables and are optional + case ftVectorOfEnumKey: { + ty = "Vec<" + WrapInNameSpace(*type.VectorType().enum_def) + ">"; + break; + } + case ftVectorOfInteger: + case ftVectorOfBool: + case ftVectorOfFloat: { + ty = "Vec<" + GetTypeBasic(type.VectorType()) + ">"; + break; + } + case ftVectorOfString: { + ty = "Vec<String>"; + break; + } + case ftVectorOfTable: + case ftVectorOfStruct: { + ty = NamespacedNativeName(*type.VectorType().struct_def); + ty = "Vec<" + ty + ">"; + break; + } + case ftVectorOfUnionValue: { + FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported"); + return "INVALID_CODE_GENERATION"; // OH NO! + } + case ftArrayOfEnum: { + ty = "[" + WrapInNameSpace(*type.VectorType().enum_def) + "; " + + NumToString(type.fixed_length) + "]"; + break; + } + case ftArrayOfStruct: { + ty = "[" + NamespacedNativeName(*type.VectorType().struct_def) + "; " + + NumToString(type.fixed_length) + "]"; + break; + } + case ftArrayOfBuiltin: { + ty = "[" + GetTypeBasic(type.VectorType()) + "; " + + NumToString(type.fixed_length) + "]"; + break; + } + } + if (in_a_table && !IsUnion(type) && field.IsOptional()) { + return "Option<" + ty + ">"; + } else { + return ty; + } + } + + std::string TableBuilderArgsAddFuncType(const FieldDef &field, + const std::string &lifetime) { + const Type &type = field.value.type; + + switch (GetFullType(field.value.type)) { + case ftVectorOfStruct: { + const auto typname = WrapInNameSpace(*type.struct_def); + return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " + + typname + ">>"; + } + case ftVectorOfTable: { + const auto typname = WrapInNameSpace(*type.struct_def); + return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + + ", flatbuffers::ForwardsUOffset<" + typname + "<" + lifetime + + ">>>>"; + } + case ftVectorOfInteger: + case ftVectorOfBool: + case ftVectorOfFloat: { + const auto typname = GetTypeBasic(type.VectorType()); + return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " + + typname + ">>"; + } + case ftVectorOfString: { + return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + + ", flatbuffers::ForwardsUOffset<&" + lifetime + " str>>>"; + } + case ftVectorOfEnumKey: { + const auto typname = WrapInNameSpace(*type.enum_def); + return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + ", " + + typname + ">>"; + } + case ftVectorOfUnionValue: { + return "flatbuffers::WIPOffset<flatbuffers::Vector<" + lifetime + + ", flatbuffers::ForwardsUOffset<flatbuffers::Table<" + lifetime + + ">>>"; + } + case ftEnumKey: + case ftUnionKey: { + const auto typname = WrapInNameSpace(*type.enum_def); + return typname; + } + case ftStruct: { + const auto typname = WrapInNameSpace(*type.struct_def); + return "&" + typname + ""; + } + case ftTable: { + const auto typname = WrapInNameSpace(*type.struct_def); + return "flatbuffers::WIPOffset<" + typname + "<" + lifetime + ">>"; + } + case ftInteger: + case ftBool: + case ftFloat: { + return GetTypeBasic(type); + } + case ftString: { + return "flatbuffers::WIPOffset<&" + lifetime + " str>"; + } + case ftUnionValue: { + return "flatbuffers::WIPOffset<flatbuffers::UnionWIPOffset>"; + } + case ftArrayOfBuiltin: { + const auto typname = GetTypeBasic(type.VectorType()); + return "flatbuffers::Array<" + lifetime + ", " + typname + ", " + + NumToString(type.fixed_length) + ">"; + } + case ftArrayOfEnum: { + const auto typname = WrapInNameSpace(*type.enum_def); + return "flatbuffers::Array<" + lifetime + ", " + typname + ", " + + NumToString(type.fixed_length) + ">"; + } + case ftArrayOfStruct: { + const auto typname = WrapInNameSpace(*type.struct_def); + return "flatbuffers::Array<" + lifetime + ", " + typname + ", " + + NumToString(type.fixed_length) + ">"; + } + } + + return "INVALID_CODE_GENERATION"; // for return analysis + } + + std::string TableBuilderArgsAddFuncBody(const FieldDef &field) { + const Type &type = field.value.type; + + switch (GetFullType(field.value.type)) { + case ftInteger: + case ftBool: + case ftFloat: { + const auto typname = GetTypeBasic(field.value.type); + return (field.IsOptional() ? "self.fbb_.push_slot_always::<" + : "self.fbb_.push_slot::<") + + typname + ">"; + } + case ftEnumKey: + case ftUnionKey: { + const auto underlying_typname = GetTypeBasic(type); + return (field.IsOptional() ? "self.fbb_.push_slot_always::<" + : "self.fbb_.push_slot::<") + + underlying_typname + ">"; + } + + case ftStruct: { + const std::string typname = WrapInNameSpace(*type.struct_def); + return "self.fbb_.push_slot_always::<&" + typname + ">"; + } + case ftTable: { + const auto typname = WrapInNameSpace(*type.struct_def); + return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<" + + typname + ">>"; + } + + case ftUnionValue: + case ftString: + case ftVectorOfInteger: + case ftVectorOfFloat: + case ftVectorOfBool: + case ftVectorOfEnumKey: + case ftVectorOfStruct: + case ftVectorOfTable: + case ftVectorOfString: + case ftVectorOfUnionValue: { + return "self.fbb_.push_slot_always::<flatbuffers::WIPOffset<_>>"; + } + case ftArrayOfEnum: + case ftArrayOfStruct: + case ftArrayOfBuiltin: { + FLATBUFFERS_ASSERT(false && "arrays are not supported within tables"); + return "ARRAYS_NOT_SUPPORTED_IN_TABLES"; + } + } + return "INVALID_CODE_GENERATION"; // for return analysis + } + + std::string GenTableAccessorFuncReturnType(const FieldDef &field, + const std::string &lifetime) { + const Type &type = field.value.type; + const auto WrapOption = [&](std::string s) { + return field.IsOptional() ? "Option<" + s + ">" : s; + }; + + switch (GetFullType(field.value.type)) { + case ftInteger: + case ftFloat: + case ftBool: { + return WrapOption(GetTypeBasic(type)); + } + case ftStruct: { + const auto typname = WrapInNameSpace(*type.struct_def); + return WrapOption("&" + lifetime + " " + typname); + } + case ftTable: { + const auto typname = WrapInNameSpace(*type.struct_def); + return WrapOption(typname + "<" + lifetime + ">"); + } + case ftEnumKey: + case ftUnionKey: { + return WrapOption(WrapInNameSpace(*type.enum_def)); + } + + case ftUnionValue: { + return WrapOption("flatbuffers::Table<" + lifetime + ">"); + } + case ftString: { + return WrapOption("&" + lifetime + " str"); + } + case ftVectorOfInteger: + case ftVectorOfBool: + case ftVectorOfFloat: { + const auto typname = GetTypeBasic(type.VectorType()); + const auto vector_type = + IsOneByte(type.VectorType().base_type) + ? "&" + lifetime + " [" + typname + "]" + : "flatbuffers::Vector<" + lifetime + ", " + typname + ">"; + return WrapOption(vector_type); + } + case ftVectorOfEnumKey: { + const auto typname = WrapInNameSpace(*type.enum_def); + return WrapOption("flatbuffers::Vector<" + lifetime + ", " + typname + + ">"); + } + case ftVectorOfStruct: { + const auto typname = WrapInNameSpace(*type.struct_def); + return WrapOption("&" + lifetime + " [" + typname + "]"); + } + case ftVectorOfTable: { + const auto typname = WrapInNameSpace(*type.struct_def); + return WrapOption("flatbuffers::Vector<" + lifetime + + ", flatbuffers::ForwardsUOffset<" + typname + "<" + + lifetime + ">>>"); + } + case ftVectorOfString: { + return WrapOption("flatbuffers::Vector<" + lifetime + + ", flatbuffers::ForwardsUOffset<&" + lifetime + + " str>>"); + } + case ftVectorOfUnionValue: { + FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported"); + // TODO(rw): when we do support these, we should consider using the + // Into trait to convert tables to typesafe union values. + return "INVALID_CODE_GENERATION"; // for return analysis + } + case ftArrayOfEnum: + case ftArrayOfStruct: + case ftArrayOfBuiltin: { + FLATBUFFERS_ASSERT(false && "arrays are not supported within tables"); + return "ARRAYS_NOT_SUPPORTED_IN_TABLES"; + } + } + return "INVALID_CODE_GENERATION"; // for return analysis + } + + std::string FollowType(const Type &type, const std::string &lifetime) { + // IsVector... This can be made iterative? + + const auto WrapForwardsUOffset = [](std::string ty) -> std::string { + return "flatbuffers::ForwardsUOffset<" + ty + ">"; + }; + const auto WrapVector = [&](std::string ty) -> std::string { + return "flatbuffers::Vector<" + lifetime + ", " + ty + ">"; + }; + const auto WrapArray = [&](std::string ty, uint16_t length) -> std::string { + return "flatbuffers::Array<" + lifetime + ", " + ty + ", " + + NumToString(length) + ">"; + }; + switch (GetFullType(type)) { + case ftInteger: + case ftFloat: + case ftBool: { + return GetTypeBasic(type); + } + case ftStruct: { + return WrapInNameSpace(*type.struct_def); + } + case ftUnionKey: + case ftEnumKey: { + return WrapInNameSpace(*type.enum_def); + } + case ftTable: { + const auto typname = WrapInNameSpace(*type.struct_def); + return WrapForwardsUOffset(typname); + } + case ftUnionValue: { + return WrapForwardsUOffset("flatbuffers::Table<" + lifetime + ">"); + } + case ftString: { + return WrapForwardsUOffset("&str"); + } + case ftVectorOfInteger: + case ftVectorOfBool: + case ftVectorOfFloat: { + const auto typname = GetTypeBasic(type.VectorType()); + return WrapForwardsUOffset(WrapVector(typname)); + } + case ftVectorOfEnumKey: { + const auto typname = WrapInNameSpace(*type.VectorType().enum_def); + return WrapForwardsUOffset(WrapVector(typname)); + } + case ftVectorOfStruct: { + const auto typname = WrapInNameSpace(*type.struct_def); + return WrapForwardsUOffset(WrapVector(typname)); + } + case ftVectorOfTable: { + const auto typname = WrapInNameSpace(*type.struct_def); + return WrapForwardsUOffset(WrapVector(WrapForwardsUOffset(typname))); + } + case ftVectorOfString: { + return WrapForwardsUOffset( + WrapVector(WrapForwardsUOffset("&" + lifetime + " str"))); + } + case ftVectorOfUnionValue: { + FLATBUFFERS_ASSERT(false && "vectors of unions are not yet supported"); + return "INVALID_CODE_GENERATION"; // for return analysis + } + case ftArrayOfEnum: { + const auto typname = WrapInNameSpace(*type.VectorType().enum_def); + return WrapArray(typname, type.fixed_length); + } + case ftArrayOfStruct: { + const auto typname = WrapInNameSpace(*type.struct_def); + return WrapArray(typname, type.fixed_length); + } + case ftArrayOfBuiltin: { + const auto typname = GetTypeBasic(type.VectorType()); + return WrapArray(typname, type.fixed_length); + } + } + return "INVALID_CODE_GENERATION"; // for return analysis + } + + std::string GenTableAccessorFuncBody(const FieldDef &field, + const std::string &lifetime) { + const std::string vt_offset = GetFieldOffsetName(field); + const std::string typname = FollowType(field.value.type, lifetime); + // Default-y fields (scalars so far) are neither optional nor required. + const std::string default_value = + !(field.IsOptional() || field.IsRequired()) + ? "Some(" + GetDefaultValue(field, kAccessor) + ")" + : "None"; + const std::string unwrap = field.IsOptional() ? "" : ".unwrap()"; + + const auto t = GetFullType(field.value.type); + + // TODO(caspern): Shouldn't 1byte VectorOfEnumKey be slice too? + const std::string safe_slice = + (t == ftVectorOfStruct || + ((t == ftVectorOfBool || t == ftVectorOfFloat || + t == ftVectorOfInteger) && + IsOneByte(field.value.type.VectorType().base_type))) + ? ".map(|v| v.safe_slice())" + : ""; + + return "self._tab.get::<" + typname + ">({{STRUCT_NAME}}::" + vt_offset + + ", " + default_value + ")" + safe_slice + unwrap; + } + + // Generates a fully-qualified name getter for use with --gen-name-strings + void GenFullyQualifiedNameGetter(const StructDef &struct_def, + const std::string &name) { + code_ += " pub const fn get_fully_qualified_name() -> &'static str {"; + code_ += " \"" + + struct_def.defined_namespace->GetFullyQualifiedName(name) + "\""; + code_ += " }"; + code_ += ""; + } + + void ForAllUnionVariantsBesidesNone( + const EnumDef &def, std::function<void(const EnumVal &ev)> cb) { + FLATBUFFERS_ASSERT(def.is_union); + + for (auto it = def.Vals().begin(); it != def.Vals().end(); ++it) { + const EnumVal &ev = **it; + // TODO(cneo): Can variants be deprecated, should we skip them? + if (ev.union_type.base_type == BASE_TYPE_NONE) { continue; } + code_.SetValue( + "U_ELEMENT_ENUM_TYPE", + WrapInNameSpace(def.defined_namespace, GetEnumValue(def, ev))); + code_.SetValue( + "U_ELEMENT_TABLE_TYPE", + WrapInNameSpace(ev.union_type.struct_def->defined_namespace, + ev.union_type.struct_def->name)); + code_.SetValue("U_ELEMENT_NAME", MakeSnakeCase(Name(ev))); + cb(ev); + } + } + + void ForAllTableFields(const StructDef &struct_def, + std::function<void(const FieldDef &)> cb, + bool reversed = false) { + // TODO(cneo): Remove `reversed` overload. It's only here to minimize the + // diff when refactoring to the `ForAllX` helper functions. + auto go = [&](const FieldDef &field) { + if (field.deprecated) return; + code_.SetValue("OFFSET_NAME", GetFieldOffsetName(field)); + code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset)); + code_.SetValue("FIELD_NAME", Name(field)); + code_.SetValue("BLDR_DEF_VAL", GetDefaultValue(field, kBuilder)); + cb(field); + }; + const auto &fields = struct_def.fields.vec; + if (reversed) { + for (auto it = fields.rbegin(); it != fields.rend(); ++it) go(**it); + } else { + for (auto it = fields.begin(); it != fields.end(); ++it) go(**it); + } + } + // Generate an accessor struct, builder struct, and create function for a + // table. + void GenTable(const StructDef &struct_def) { + code_.SetValue("STRUCT_NAME", Name(struct_def)); + code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset"); + code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(Name(struct_def))); + + // Generate an offset type, the base type, the Follow impl, and the + // init_from_table impl. + code_ += "pub enum {{OFFSET_TYPELABEL}} {}"; + code_ += "#[derive(Copy, Clone, PartialEq)]"; + code_ += ""; + + GenComment(struct_def.doc_comment); + + code_ += "pub struct {{STRUCT_NAME}}<'a> {"; + code_ += " pub _tab: flatbuffers::Table<'a>,"; + code_ += "}"; + code_ += ""; + code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}}<'a> {"; + code_ += " type Inner = {{STRUCT_NAME}}<'a>;"; + code_ += " #[inline]"; + code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {"; + code_ += " Self { _tab: flatbuffers::Table { buf, loc } }"; + code_ += " }"; + code_ += "}"; + code_ += ""; + code_ += "impl<'a> {{STRUCT_NAME}}<'a> {"; + + if (parser_.opts.generate_name_strings) { + GenFullyQualifiedNameGetter(struct_def, struct_def.name); + } + + code_ += " #[inline]"; + code_ += + " pub fn init_from_table(table: flatbuffers::Table<'a>) -> " + "Self {"; + code_ += " {{STRUCT_NAME}} { _tab: table }"; + code_ += " }"; + + // Generate a convenient create* function that uses the above builder + // to create a table in one function call. + code_.SetValue("MAYBE_US", struct_def.fields.vec.size() == 0 ? "_" : ""); + code_.SetValue("MAYBE_LT", + TableBuilderArgsNeedsLifetime(struct_def) ? "<'args>" : ""); + code_ += " #[allow(unused_mut)]"; + code_ += " pub fn create<'bldr: 'args, 'args: 'mut_bldr, 'mut_bldr>("; + code_ += + " _fbb: " + "&'mut_bldr mut flatbuffers::FlatBufferBuilder<'bldr>,"; + code_ += + " {{MAYBE_US}}args: &'args {{STRUCT_NAME}}Args{{MAYBE_LT}})" + " -> flatbuffers::WIPOffset<{{STRUCT_NAME}}<'bldr>> {"; + + code_ += " let mut builder = {{STRUCT_NAME}}Builder::new(_fbb);"; + for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1; + size; size /= 2) { + ForAllTableFields( + struct_def, + [&](const FieldDef &field) { + if (struct_def.sortbysize && + size != SizeOf(field.value.type.base_type)) + return; + if (IsOptionalToBuilder(field)) { + code_ += + " if let Some(x) = args.{{FIELD_NAME}} " + "{ builder.add_{{FIELD_NAME}}(x); }"; + } else { + code_ += " builder.add_{{FIELD_NAME}}(args.{{FIELD_NAME}});"; + } + }, + /*reverse=*/true); + } + code_ += " builder.finish()"; + code_ += " }"; + code_ += ""; + // Generate Object API Packer function. + if (parser_.opts.generate_object_based_api) { + // TODO(cneo): Replace more for loops with ForAllX stuff. + // TODO(cneo): Manage indentation with IncrementIdentLevel? + code_.SetValue("OBJECT_NAME", NativeName(struct_def)); + code_ += " pub fn unpack(&self) -> {{OBJECT_NAME}} {"; + ForAllObjectTableFields(struct_def, [&](const FieldDef &field) { + const Type &type = field.value.type; + switch (GetFullType(type)) { + case ftInteger: + case ftBool: + case ftFloat: + case ftEnumKey: { + code_ += " let {{FIELD_NAME}} = self.{{FIELD_NAME}}();"; + return; + } + case ftUnionKey: return; + case ftUnionValue: { + const auto &enum_def = *type.enum_def; + code_.SetValue("ENUM_NAME", WrapInNameSpace(enum_def)); + code_.SetValue("NATIVE_ENUM_NAME", NamespacedNativeName(enum_def)); + code_ += + " let {{FIELD_NAME}} = match " + "self.{{FIELD_NAME}}_type() {"; + code_ += + " {{ENUM_NAME}}::NONE =>" + " {{NATIVE_ENUM_NAME}}::NONE,"; + ForAllUnionObjectVariantsBesidesNone(enum_def, [&] { + code_ += + " {{ENUM_NAME}}::{{VARIANT_NAME}} => " + "{{NATIVE_ENUM_NAME}}::{{NATIVE_VARIANT}}(Box::new("; + code_ += + " self.{{FIELD_NAME}}_as_" + "{{U_ELEMENT_NAME}}()"; + code_ += + " .expect(\"Invalid union table, " + "expected `{{ENUM_NAME}}::{{VARIANT_NAME}}`.\")"; + code_ += " .unpack()"; + code_ += " )),"; + }); + // Maybe we shouldn't throw away unknown discriminants? + code_ += " _ => {{NATIVE_ENUM_NAME}}::NONE,"; + code_ += " };"; + return; + } + // The rest of the types need special handling based on if the field + // is optional or not. + case ftString: { + code_.SetValue("EXPR", "x.to_string()"); + break; + } + case ftStruct: { + code_.SetValue("EXPR", "x.unpack()"); + break; + } + case ftTable: { + code_.SetValue("EXPR", "Box::new(x.unpack())"); + break; + } + case ftVectorOfInteger: + case ftVectorOfBool: { + if (IsOneByte(type.VectorType().base_type)) { + // 1 byte stuff is viewed w/ slice instead of flatbuffer::Vector + // and thus needs to be cloned out of the slice. + code_.SetValue("EXPR", "x.to_vec()"); + break; + } + code_.SetValue("EXPR", "x.into_iter().collect()"); + break; + } + case ftVectorOfFloat: + case ftVectorOfEnumKey: { + code_.SetValue("EXPR", "x.into_iter().collect()"); + break; + } + case ftVectorOfString: { + code_.SetValue("EXPR", "x.iter().map(|s| s.to_string()).collect()"); + break; + } + case ftVectorOfStruct: + case ftVectorOfTable: { + code_.SetValue("EXPR", "x.iter().map(|t| t.unpack()).collect()"); + break; + } + case ftVectorOfUnionValue: { + FLATBUFFERS_ASSERT(false && "vectors of unions not yet supported"); + return; + } + case ftArrayOfEnum: + case ftArrayOfStruct: + case ftArrayOfBuiltin: { + FLATBUFFERS_ASSERT(false && + "arrays are not supported within tables"); + return; + } + } + if (field.IsOptional()) { + code_ += " let {{FIELD_NAME}} = self.{{FIELD_NAME}}().map(|x| {"; + code_ += " {{EXPR}}"; + code_ += " });"; + } else { + code_ += " let {{FIELD_NAME}} = {"; + code_ += " let x = self.{{FIELD_NAME}}();"; + code_ += " {{EXPR}}"; + code_ += " };"; + } + }); + code_ += " {{OBJECT_NAME}} {"; + ForAllObjectTableFields(struct_def, [&](const FieldDef &field) { + if (field.value.type.base_type == BASE_TYPE_UTYPE) return; + code_ += " {{FIELD_NAME}},"; + }); + code_ += " }"; + code_ += " }"; + } + + // Generate field id constants. + ForAllTableFields(struct_def, [&](const FieldDef &unused) { + (void)unused; + code_ += + " pub const {{OFFSET_NAME}}: flatbuffers::VOffsetT = " + "{{OFFSET_VALUE}};"; + }); + if (struct_def.fields.vec.size() > 0) code_ += ""; + + // Generate the accessors. Each has one of two forms: + // + // If a value can be None: + // pub fn name(&'a self) -> Option<user_facing_type> { + // self._tab.get::<internal_type>(offset, defaultval) + // } + // + // If a value is always Some: + // pub fn name(&'a self) -> user_facing_type { + // self._tab.get::<internal_type>(offset, defaultval).unwrap() + // } + ForAllTableFields(struct_def, [&](const FieldDef &field) { + code_.SetValue("RETURN_TYPE", + GenTableAccessorFuncReturnType(field, "'a")); + + this->GenComment(field.doc_comment, " "); + code_ += " #[inline]"; + code_ += " pub fn {{FIELD_NAME}}(&self) -> {{RETURN_TYPE}} {"; + code_ += " " + GenTableAccessorFuncBody(field, "'a"); + code_ += " }"; + + // Generate a comparison function for this field if it is a key. + if (field.key) { GenKeyFieldMethods(field); } + + // Generate a nested flatbuffer field, if applicable. + auto nested = field.attributes.Lookup("nested_flatbuffer"); + if (nested) { + std::string qualified_name = nested->constant; + auto nested_root = parser_.LookupStruct(nested->constant); + if (nested_root == nullptr) { + qualified_name = parser_.current_namespace_->GetFullyQualifiedName( + nested->constant); + nested_root = parser_.LookupStruct(qualified_name); + } + FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser. + + code_.SetValue("NESTED", WrapInNameSpace(*nested_root)); + code_ += " pub fn {{FIELD_NAME}}_nested_flatbuffer(&'a self) -> \\"; + if (field.IsRequired()) { + code_ += "{{NESTED}}<'a> {"; + code_ += " let data = self.{{FIELD_NAME}}();"; + code_ += " use flatbuffers::Follow;"; + code_ += + " <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>" + "::follow(data, 0)"; + } else { + code_ += "Option<{{NESTED}}<'a>> {"; + code_ += " self.{{FIELD_NAME}}().map(|data| {"; + code_ += " use flatbuffers::Follow;"; + code_ += + " <flatbuffers::ForwardsUOffset<{{NESTED}}<'a>>>" + "::follow(data, 0)"; + code_ += " })"; + } + code_ += " }"; + } + }); + + // Explicit specializations for union accessors + ForAllTableFields(struct_def, [&](const FieldDef &field) { + if (field.value.type.base_type != BASE_TYPE_UNION) return; + code_.SetValue("FIELD_TYPE_FIELD_NAME", field.name); + ForAllUnionVariantsBesidesNone( + *field.value.type.enum_def, [&](const EnumVal &unused) { + (void)unused; + code_ += " #[inline]"; + code_ += " #[allow(non_snake_case)]"; + code_ += + " pub fn {{FIELD_NAME}}_as_{{U_ELEMENT_NAME}}(&self) -> " + "Option<{{U_ELEMENT_TABLE_TYPE}}<'a>> {"; + // If the user defined schemas name a field that clashes with a + // language reserved word, flatc will try to escape the field name + // by appending an underscore. This works well for most cases, + // except one. When generating union accessors (and referring to + // them internally within the code generated here), an extra + // underscore will be appended to the name, causing build failures. + // + // This only happens when unions have members that overlap with + // language reserved words. + // + // To avoid this problem the type field name is used unescaped here: + code_ += + " if self.{{FIELD_TYPE_FIELD_NAME}}_type() == " + "{{U_ELEMENT_ENUM_TYPE}} {"; + + // The following logic is not tested in the integration test, + // as of April 10, 2020 + if (field.IsRequired()) { + code_ += " let u = self.{{FIELD_NAME}}();"; + code_ += + " Some({{U_ELEMENT_TABLE_TYPE}}::init_from_table(u))"; + } else { + code_ += + " self.{{FIELD_NAME}}().map(" + "{{U_ELEMENT_TABLE_TYPE}}::init_from_table)"; + } + code_ += " } else {"; + code_ += " None"; + code_ += " }"; + code_ += " }"; + code_ += ""; + }); + }); + code_ += "}"; // End of table impl. + code_ += ""; + + // Generate Verifier; + code_ += "impl flatbuffers::Verifiable for {{STRUCT_NAME}}<'_> {"; + code_ += " #[inline]"; + code_ += " fn run_verifier("; + code_ += " v: &mut flatbuffers::Verifier, pos: usize"; + code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {"; + code_ += " use self::flatbuffers::Verifiable;"; + code_ += " v.visit_table(pos)?\\"; + // Escape newline and insert it onthe next line so we can end the builder + // with a nice semicolon. + ForAllTableFields(struct_def, [&](const FieldDef &field) { + if (GetFullType(field.value.type) == ftUnionKey) return; + + code_.SetValue("IS_REQ", field.IsRequired() ? "true" : "false"); + if (GetFullType(field.value.type) != ftUnionValue) { + // All types besides unions. + code_.SetValue("TY", FollowType(field.value.type, "'_")); + code_ += + "\n .visit_field::<{{TY}}>(&\"{{FIELD_NAME}}\", " + "Self::{{OFFSET_NAME}}, {{IS_REQ}})?\\"; + return; + } + // Unions. + EnumDef &union_def = *field.value.type.enum_def; + code_.SetValue("UNION_TYPE", WrapInNameSpace(union_def)); + code_ += + "\n .visit_union::<{{UNION_TYPE}}, _>(" + "&\"{{FIELD_NAME}}_type\", Self::{{OFFSET_NAME}}_TYPE, " + "&\"{{FIELD_NAME}}\", Self::{{OFFSET_NAME}}, {{IS_REQ}}, " + "|key, v, pos| {"; + code_ += " match key {"; + ForAllUnionVariantsBesidesNone(union_def, [&](const EnumVal &unused) { + (void)unused; + code_ += + " {{U_ELEMENT_ENUM_TYPE}} => v.verify_union_variant::" + "<flatbuffers::ForwardsUOffset<{{U_ELEMENT_TABLE_TYPE}}>>(" + "\"{{U_ELEMENT_ENUM_TYPE}}\", pos),"; + }); + code_ += " _ => Ok(()),"; + code_ += " }"; + code_ += " })?\\"; + }); + code_ += "\n .finish();"; + code_ += " Ok(())"; + code_ += " }"; + code_ += "}"; + + // Generate an args struct: + code_.SetValue("MAYBE_LT", + TableBuilderArgsNeedsLifetime(struct_def) ? "<'a>" : ""); + code_ += "pub struct {{STRUCT_NAME}}Args{{MAYBE_LT}} {"; + ForAllTableFields(struct_def, [&](const FieldDef &field) { + code_.SetValue("PARAM_TYPE", TableBuilderArgsDefnType(field, "'a")); + code_ += " pub {{FIELD_NAME}}: {{PARAM_TYPE}},"; + }); + code_ += "}"; + + // Generate an impl of Default for the *Args type: + code_ += "impl<'a> Default for {{STRUCT_NAME}}Args{{MAYBE_LT}} {"; + code_ += " #[inline]"; + code_ += " fn default() -> Self {"; + code_ += " {{STRUCT_NAME}}Args {"; + ForAllTableFields(struct_def, [&](const FieldDef &field) { + code_ += " {{FIELD_NAME}}: {{BLDR_DEF_VAL}},\\"; + code_ += field.IsRequired() ? " // required field" : ""; + }); + code_ += " }"; + code_ += " }"; + code_ += "}"; + + // Generate a builder struct: + code_ += "pub struct {{STRUCT_NAME}}Builder<'a: 'b, 'b> {"; + code_ += " fbb_: &'b mut flatbuffers::FlatBufferBuilder<'a>,"; + code_ += + " start_: flatbuffers::WIPOffset<" + "flatbuffers::TableUnfinishedWIPOffset>,"; + code_ += "}"; + + // Generate builder functions: + code_ += "impl<'a: 'b, 'b> {{STRUCT_NAME}}Builder<'a, 'b> {"; + ForAllTableFields(struct_def, [&](const FieldDef &field) { + const bool is_scalar = IsScalar(field.value.type.base_type); + std::string offset = GetFieldOffsetName(field); + // Generate functions to add data, which take one of two forms. + // + // If a value has a default: + // fn add_x(x_: type) { + // fbb_.push_slot::<type>(offset, x_, Some(default)); + // } + // + // If a value does not have a default: + // fn add_x(x_: type) { + // fbb_.push_slot_always::<type>(offset, x_); + // } + code_.SetValue("FIELD_OFFSET", Name(struct_def) + "::" + offset); + code_.SetValue("FIELD_TYPE", TableBuilderArgsAddFuncType(field, "'b ")); + code_.SetValue("FUNC_BODY", TableBuilderArgsAddFuncBody(field)); + code_ += " #[inline]"; + code_ += + " pub fn add_{{FIELD_NAME}}(&mut self, {{FIELD_NAME}}: " + "{{FIELD_TYPE}}) {"; + if (is_scalar && !field.IsOptional()) { + code_ += + " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}}, " + "{{BLDR_DEF_VAL}});"; + } else { + code_ += " {{FUNC_BODY}}({{FIELD_OFFSET}}, {{FIELD_NAME}});"; + } + code_ += " }"; + }); + + // Struct initializer (all fields required); + code_ += " #[inline]"; + code_ += + " pub fn new(_fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>) -> " + "{{STRUCT_NAME}}Builder<'a, 'b> {"; + code_.SetValue("NUM_FIELDS", NumToString(struct_def.fields.vec.size())); + code_ += " let start = _fbb.start_table();"; + code_ += " {{STRUCT_NAME}}Builder {"; + code_ += " fbb_: _fbb,"; + code_ += " start_: start,"; + code_ += " }"; + code_ += " }"; + + // finish() function. + code_ += " #[inline]"; + code_ += + " pub fn finish(self) -> " + "flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>> {"; + code_ += " let o = self.fbb_.end_table(self.start_);"; + + ForAllTableFields(struct_def, [&](const FieldDef &field) { + if (!field.IsRequired()) return; + code_ += + " self.fbb_.required(o, {{STRUCT_NAME}}::{{OFFSET_NAME}}," + "\"{{FIELD_NAME}}\");"; + }); + code_ += " flatbuffers::WIPOffset::new(o.value())"; + code_ += " }"; + code_ += "}"; + code_ += ""; + + code_ += "impl std::fmt::Debug for {{STRUCT_NAME}}<'_> {"; + code_ += + " fn fmt(&self, f: &mut std::fmt::Formatter<'_>" + ") -> std::fmt::Result {"; + code_ += " let mut ds = f.debug_struct(\"{{STRUCT_NAME}}\");"; + ForAllTableFields(struct_def, [&](const FieldDef &field) { + if (GetFullType(field.value.type) == ftUnionValue) { + // Generate a match statement to handle unions properly. + code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, "")); + code_.SetValue("FIELD_TYPE_FIELD_NAME", field.name); + code_.SetValue("UNION_ERR", + "&\"InvalidFlatbuffer: Union discriminant" + " does not match value.\""); + + code_ += " match self.{{FIELD_NAME}}_type() {"; + ForAllUnionVariantsBesidesNone( + *field.value.type.enum_def, [&](const EnumVal &unused) { + (void)unused; + code_ += " {{U_ELEMENT_ENUM_TYPE}} => {"; + code_ += + " if let Some(x) = " + "self.{{FIELD_TYPE_FIELD_NAME}}_as_" + "{{U_ELEMENT_NAME}}() {"; + code_ += " ds.field(\"{{FIELD_NAME}}\", &x)"; + code_ += " } else {"; + code_ += + " ds.field(\"{{FIELD_NAME}}\", {{UNION_ERR}})"; + code_ += " }"; + code_ += " },"; + }); + code_ += " _ => {"; + code_ += " let x: Option<()> = None;"; + code_ += " ds.field(\"{{FIELD_NAME}}\", &x)"; + code_ += " },"; + code_ += " };"; + } else { + // Most fields. + code_ += " ds.field(\"{{FIELD_NAME}}\", &self.{{FIELD_NAME}}());"; + } + }); + code_ += " ds.finish()"; + code_ += " }"; + code_ += "}"; + } + + void GenTableObject(const StructDef &table) { + code_.SetValue("OBJECT_NAME", NativeName(table)); + code_.SetValue("STRUCT_NAME", Name(table)); + + // Generate the native object. + code_ += "#[non_exhaustive]"; + code_ += "#[derive(Debug, Clone, PartialEq)]"; + code_ += "pub struct {{OBJECT_NAME}} {"; + ForAllObjectTableFields(table, [&](const FieldDef &field) { + // Union objects combine both the union discriminant and value, so we + // skip making a field for the discriminant. + if (field.value.type.base_type == BASE_TYPE_UTYPE) return; + code_ += " pub {{FIELD_NAME}}: {{FIELD_OBJECT_TYPE}},"; + }); + code_ += "}"; + + code_ += "impl Default for {{OBJECT_NAME}} {"; + code_ += " fn default() -> Self {"; + code_ += " Self {"; + ForAllObjectTableFields(table, [&](const FieldDef &field) { + if (field.value.type.base_type == BASE_TYPE_UTYPE) return; + std::string default_value = GetDefaultValue(field, kObject); + code_ += " {{FIELD_NAME}}: " + default_value + ","; + }); + code_ += " }"; + code_ += " }"; + code_ += "}"; + + // TODO(cneo): Generate defaults for Native tables. However, since structs + // may be required, they, and therefore enums need defaults. + + // Generate pack function. + code_ += "impl {{OBJECT_NAME}} {"; + code_ += " pub fn pack<'b>("; + code_ += " &self,"; + code_ += " _fbb: &mut flatbuffers::FlatBufferBuilder<'b>"; + code_ += " ) -> flatbuffers::WIPOffset<{{STRUCT_NAME}}<'b>> {"; + // First we generate variables for each field and then later assemble them + // using "StructArgs" to more easily manage ownership of the builder. + ForAllObjectTableFields(table, [&](const FieldDef &field) { + const Type &type = field.value.type; + switch (GetFullType(type)) { + case ftInteger: + case ftBool: + case ftFloat: + case ftEnumKey: { + code_ += " let {{FIELD_NAME}} = self.{{FIELD_NAME}};"; + return; + } + case ftUnionKey: return; // Generate union type with union value. + case ftUnionValue: { + code_.SetValue("SNAKE_CASE_ENUM_NAME", + MakeSnakeCase(Name(*field.value.type.enum_def))); + code_ += + " let {{FIELD_NAME}}_type = " + "self.{{FIELD_NAME}}.{{SNAKE_CASE_ENUM_NAME}}_type();"; + code_ += " let {{FIELD_NAME}} = self.{{FIELD_NAME}}.pack(_fbb);"; + return; + } + // The rest of the types require special casing around optionalness + // due to "required" annotation. + case ftString: { + MapNativeTableField(field, "_fbb.create_string(x)"); + return; + } + case ftStruct: { + // Hold the struct in a variable so we can reference it. + if (field.IsRequired()) { + code_ += + " let {{FIELD_NAME}}_tmp = " + "Some(self.{{FIELD_NAME}}.pack());"; + } else { + code_ += + " let {{FIELD_NAME}}_tmp = self.{{FIELD_NAME}}" + ".as_ref().map(|x| x.pack());"; + } + code_ += " let {{FIELD_NAME}} = {{FIELD_NAME}}_tmp.as_ref();"; + + return; + } + case ftTable: { + MapNativeTableField(field, "x.pack(_fbb)"); + return; + } + case ftVectorOfEnumKey: + case ftVectorOfInteger: + case ftVectorOfBool: + case ftVectorOfFloat: { + MapNativeTableField(field, "_fbb.create_vector(x)"); + return; + } + case ftVectorOfStruct: { + MapNativeTableField( + field, + "let w: Vec<_> = x.iter().map(|t| t.pack()).collect();" + "_fbb.create_vector(&w)"); + return; + } + case ftVectorOfString: { + // TODO(cneo): create_vector* should be more generic to avoid + // allocations. + + MapNativeTableField( + field, + "let w: Vec<_> = x.iter().map(|s| s.as_ref()).collect();" + "_fbb.create_vector_of_strings(&w)"); + return; + } + case ftVectorOfTable: { + MapNativeTableField( + field, + "let w: Vec<_> = x.iter().map(|t| t.pack(_fbb)).collect();" + "_fbb.create_vector(&w)"); + return; + } + case ftVectorOfUnionValue: { + FLATBUFFERS_ASSERT(false && "vectors of unions not yet supported"); + return; + } + case ftArrayOfEnum: + case ftArrayOfStruct: + case ftArrayOfBuiltin: { + FLATBUFFERS_ASSERT(false && "arrays are not supported within tables"); + return; + } + } + }); + code_ += " {{STRUCT_NAME}}::create(_fbb, &{{STRUCT_NAME}}Args{"; + ForAllObjectTableFields(table, [&](const FieldDef &field) { + (void)field; // Unused. + code_ += " {{FIELD_NAME}},"; + }); + code_ += " })"; + code_ += " }"; + code_ += "}"; + } + void ForAllObjectTableFields(const StructDef &table, + std::function<void(const FieldDef &)> cb) { + const std::vector<FieldDef *> &v = table.fields.vec; + for (auto it = v.begin(); it != v.end(); it++) { + const FieldDef &field = **it; + if (field.deprecated) continue; + code_.SetValue("FIELD_NAME", Name(field)); + code_.SetValue("FIELD_OBJECT_TYPE", ObjectFieldType(field, true)); + cb(field); + } + } + void MapNativeTableField(const FieldDef &field, const std::string &expr) { + if (field.IsOptional()) { + code_ += " let {{FIELD_NAME}} = self.{{FIELD_NAME}}.as_ref().map(|x|{"; + code_ += " " + expr; + code_ += " });"; + } else { + // For some reason Args has optional types for required fields. + // TODO(cneo): Fix this... but its a breaking change? + code_ += " let {{FIELD_NAME}} = Some({"; + code_ += " let x = &self.{{FIELD_NAME}};"; + code_ += " " + expr; + code_ += " });"; + } + } + + // Generate functions to compare tables and structs by key. This function + // must only be called if the field key is defined. + void GenKeyFieldMethods(const FieldDef &field) { + FLATBUFFERS_ASSERT(field.key); + + code_.SetValue("KEY_TYPE", GenTableAccessorFuncReturnType(field, "")); + + code_ += " #[inline]"; + code_ += + " pub fn key_compare_less_than(&self, o: &{{STRUCT_NAME}}) -> " + " bool {"; + code_ += " self.{{FIELD_NAME}}() < o.{{FIELD_NAME}}()"; + code_ += " }"; + code_ += ""; + code_ += " #[inline]"; + code_ += + " pub fn key_compare_with_value(&self, val: {{KEY_TYPE}}) -> " + " ::std::cmp::Ordering {"; + code_ += " let key = self.{{FIELD_NAME}}();"; + code_ += " key.cmp(&val)"; + code_ += " }"; + } + + // Generate functions for accessing the root table object. This function + // must only be called if the root table is defined. + void GenRootTableFuncs(const StructDef &struct_def) { + FLATBUFFERS_ASSERT(parser_.root_struct_def_ && "root table not defined"); + auto name = Name(struct_def); + + code_.SetValue("STRUCT_NAME", name); + code_.SetValue("STRUCT_NAME_SNAKECASE", MakeSnakeCase(name)); + code_.SetValue("STRUCT_NAME_CAPS", MakeUpper(MakeSnakeCase(name))); + + // The root datatype accessors: + code_ += "#[inline]"; + code_ += + "#[deprecated(since=\"2.0.0\", " + "note=\"Deprecated in favor of `root_as...` methods.\")]"; + code_ += + "pub fn get_root_as_{{STRUCT_NAME_SNAKECASE}}<'a>(buf: &'a [u8])" + " -> {{STRUCT_NAME}}<'a> {"; + code_ += + " unsafe { flatbuffers::root_unchecked::<{{STRUCT_NAME}}" + "<'a>>(buf) }"; + code_ += "}"; + code_ += ""; + + code_ += "#[inline]"; + code_ += + "#[deprecated(since=\"2.0.0\", " + "note=\"Deprecated in favor of `root_as...` methods.\")]"; + code_ += + "pub fn get_size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}" + "<'a>(buf: &'a [u8]) -> {{STRUCT_NAME}}<'a> {"; + code_ += + " unsafe { flatbuffers::size_prefixed_root_unchecked::<{{STRUCT_NAME}}" + "<'a>>(buf) }"; + code_ += "}"; + code_ += ""; + // Default verifier root fns. + code_ += "#[inline]"; + code_ += "/// Verifies that a buffer of bytes contains a `{{STRUCT_NAME}}`"; + code_ += "/// and returns it."; + code_ += "/// Note that verification is still experimental and may not"; + code_ += "/// catch every error, or be maximally performant. For the"; + code_ += "/// previous, unchecked, behavior use"; + code_ += "/// `root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`."; + code_ += + "pub fn root_as_{{STRUCT_NAME_SNAKECASE}}(buf: &[u8]) " + "-> Result<{{STRUCT_NAME}}, flatbuffers::InvalidFlatbuffer> {"; + code_ += " flatbuffers::root::<{{STRUCT_NAME}}>(buf)"; + code_ += "}"; + code_ += "#[inline]"; + code_ += "/// Verifies that a buffer of bytes contains a size prefixed"; + code_ += "/// `{{STRUCT_NAME}}` and returns it."; + code_ += "/// Note that verification is still experimental and may not"; + code_ += "/// catch every error, or be maximally performant. For the"; + code_ += "/// previous, unchecked, behavior use"; + code_ += "/// `size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`."; + code_ += + "pub fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}" + "(buf: &[u8]) -> Result<{{STRUCT_NAME}}, " + "flatbuffers::InvalidFlatbuffer> {"; + code_ += " flatbuffers::size_prefixed_root::<{{STRUCT_NAME}}>(buf)"; + code_ += "}"; + // Verifier with options root fns. + code_ += "#[inline]"; + code_ += "/// Verifies, with the given options, that a buffer of bytes"; + code_ += "/// contains a `{{STRUCT_NAME}}` and returns it."; + code_ += "/// Note that verification is still experimental and may not"; + code_ += "/// catch every error, or be maximally performant. For the"; + code_ += "/// previous, unchecked, behavior use"; + code_ += "/// `root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`."; + code_ += "pub fn root_as_{{STRUCT_NAME_SNAKECASE}}_with_opts<'b, 'o>("; + code_ += " opts: &'o flatbuffers::VerifierOptions,"; + code_ += " buf: &'b [u8],"; + code_ += + ") -> Result<{{STRUCT_NAME}}<'b>, flatbuffers::InvalidFlatbuffer>" + " {"; + code_ += " flatbuffers::root_with_opts::<{{STRUCT_NAME}}<'b>>(opts, buf)"; + code_ += "}"; + code_ += "#[inline]"; + code_ += "/// Verifies, with the given verifier options, that a buffer of"; + code_ += "/// bytes contains a size prefixed `{{STRUCT_NAME}}` and returns"; + code_ += "/// it. Note that verification is still experimental and may not"; + code_ += "/// catch every error, or be maximally performant. For the"; + code_ += "/// previous, unchecked, behavior use"; + code_ += "/// `root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked`."; + code_ += + "pub fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}_with_opts" + "<'b, 'o>("; + code_ += " opts: &'o flatbuffers::VerifierOptions,"; + code_ += " buf: &'b [u8],"; + code_ += + ") -> Result<{{STRUCT_NAME}}<'b>, flatbuffers::InvalidFlatbuffer>" + " {"; + code_ += + " flatbuffers::size_prefixed_root_with_opts::<{{STRUCT_NAME}}" + "<'b>>(opts, buf)"; + code_ += "}"; + // Unchecked root fns. + code_ += "#[inline]"; + code_ += + "/// Assumes, without verification, that a buffer of bytes " + "contains a {{STRUCT_NAME}} and returns it."; + code_ += "/// # Safety"; + code_ += + "/// Callers must trust the given bytes do indeed contain a valid" + " `{{STRUCT_NAME}}`."; + code_ += + "pub unsafe fn root_as_{{STRUCT_NAME_SNAKECASE}}_unchecked" + "(buf: &[u8]) -> {{STRUCT_NAME}} {"; + code_ += " flatbuffers::root_unchecked::<{{STRUCT_NAME}}>(buf)"; + code_ += "}"; + code_ += "#[inline]"; + code_ += + "/// Assumes, without verification, that a buffer of bytes " + "contains a size prefixed {{STRUCT_NAME}} and returns it."; + code_ += "/// # Safety"; + code_ += + "/// Callers must trust the given bytes do indeed contain a valid" + " size prefixed `{{STRUCT_NAME}}`."; + code_ += + "pub unsafe fn size_prefixed_root_as_{{STRUCT_NAME_SNAKECASE}}" + "_unchecked(buf: &[u8]) -> {{STRUCT_NAME}} {"; + code_ += + " flatbuffers::size_prefixed_root_unchecked::<{{STRUCT_NAME}}>" + "(buf)"; + code_ += "}"; + + if (parser_.file_identifier_.length()) { + // Declare the identifier + // (no lifetime needed as constants have static lifetimes by default) + code_ += "pub const {{STRUCT_NAME_CAPS}}_IDENTIFIER: &str\\"; + code_ += " = \"" + parser_.file_identifier_ + "\";"; + code_ += ""; + + // Check if a buffer has the identifier. + code_ += "#[inline]"; + code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_buffer_has_identifier\\"; + code_ += "(buf: &[u8]) -> bool {"; + code_ += " flatbuffers::buffer_has_identifier(buf, \\"; + code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, false)"; + code_ += "}"; + code_ += ""; + code_ += "#[inline]"; + code_ += "pub fn {{STRUCT_NAME_SNAKECASE}}_size_prefixed\\"; + code_ += "_buffer_has_identifier(buf: &[u8]) -> bool {"; + code_ += " flatbuffers::buffer_has_identifier(buf, \\"; + code_ += "{{STRUCT_NAME_CAPS}}_IDENTIFIER, true)"; + code_ += "}"; + code_ += ""; + } + + if (parser_.file_extension_.length()) { + // Return the extension + code_ += "pub const {{STRUCT_NAME_CAPS}}_EXTENSION: &str = \\"; + code_ += "\"" + parser_.file_extension_ + "\";"; + code_ += ""; + } + + // Finish a buffer with a given root object: + code_.SetValue("OFFSET_TYPELABEL", Name(struct_def) + "Offset"); + code_ += "#[inline]"; + code_ += "pub fn finish_{{STRUCT_NAME_SNAKECASE}}_buffer<'a, 'b>("; + code_ += " fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>,"; + code_ += " root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {"; + if (parser_.file_identifier_.length()) { + code_ += " fbb.finish(root, Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));"; + } else { + code_ += " fbb.finish(root, None);"; + } + code_ += "}"; + code_ += ""; + code_ += "#[inline]"; + code_ += + "pub fn finish_size_prefixed_{{STRUCT_NAME_SNAKECASE}}_buffer" + "<'a, 'b>(" + "fbb: &'b mut flatbuffers::FlatBufferBuilder<'a>, " + "root: flatbuffers::WIPOffset<{{STRUCT_NAME}}<'a>>) {"; + if (parser_.file_identifier_.length()) { + code_ += + " fbb.finish_size_prefixed(root, " + "Some({{STRUCT_NAME_CAPS}}_IDENTIFIER));"; + } else { + code_ += " fbb.finish_size_prefixed(root, None);"; + } + code_ += "}"; + } + + static void GenPadding( + const FieldDef &field, std::string *code_ptr, int *id, + const std::function<void(int bits, std::string *code_ptr, int *id)> &f) { + if (field.padding) { + for (int i = 0; i < 4; i++) { + if (static_cast<int>(field.padding) & (1 << i)) { + f((1 << i) * 8, code_ptr, id); + } + } + assert(!(field.padding & ~0xF)); + } + } + + static void PaddingDefinition(int bits, std::string *code_ptr, int *id) { + *code_ptr += + " padding" + NumToString((*id)++) + "__: u" + NumToString(bits) + ","; + } + + static void PaddingInitializer(int bits, std::string *code_ptr, int *id) { + (void)bits; + *code_ptr += "padding" + NumToString((*id)++) + "__: 0,"; + } + + void ForAllStructFields(const StructDef &struct_def, + std::function<void(const FieldDef &field)> cb) { + size_t offset_to_field = 0; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + code_.SetValue("FIELD_TYPE", GetTypeGet(field.value.type)); + code_.SetValue("FIELD_OBJECT_TYPE", ObjectFieldType(field, false)); + code_.SetValue("FIELD_NAME", Name(field)); + code_.SetValue("FIELD_OFFSET", NumToString(offset_to_field)); + code_.SetValue( + "REF", + IsStruct(field.value.type) || IsArray(field.value.type) ? "&" : ""); + cb(field); + const size_t size = InlineSize(field.value.type); + offset_to_field += size + field.padding; + } + } + // Generate an accessor struct with constructor for a flatbuffers struct. + void GenStruct(const StructDef &struct_def) { + // Generates manual padding and alignment. + // Variables are private because they contain little endian data on all + // platforms. + GenComment(struct_def.doc_comment); + code_.SetValue("ALIGN", NumToString(struct_def.minalign)); + code_.SetValue("STRUCT_NAME", Name(struct_def)); + code_.SetValue("STRUCT_SIZE", NumToString(struct_def.bytesize)); + + // We represent Flatbuffers-structs in Rust-u8-arrays since the data may be + // of the wrong endianness and alignment 1. + // + // PartialEq is useful to derive because we can correctly compare structs + // for equality by just comparing their underlying byte data. This doesn't + // hold for PartialOrd/Ord. + code_ += "// struct {{STRUCT_NAME}}, aligned to {{ALIGN}}"; + code_ += "#[repr(transparent)]"; + code_ += "#[derive(Clone, Copy, PartialEq)]"; + code_ += "pub struct {{STRUCT_NAME}}(pub [u8; {{STRUCT_SIZE}}]);"; + code_ += "impl Default for {{STRUCT_NAME}} { "; + code_ += " fn default() -> Self { "; + code_ += " Self([0; {{STRUCT_SIZE}}])"; + code_ += " }"; + code_ += "}"; + + // Debug for structs. + code_ += "impl std::fmt::Debug for {{STRUCT_NAME}} {"; + code_ += + " fn fmt(&self, f: &mut std::fmt::Formatter" + ") -> std::fmt::Result {"; + code_ += " f.debug_struct(\"{{STRUCT_NAME}}\")"; + ForAllStructFields(struct_def, [&](const FieldDef &unused) { + (void)unused; + code_ += " .field(\"{{FIELD_NAME}}\", &self.{{FIELD_NAME}}())"; + }); + code_ += " .finish()"; + code_ += " }"; + code_ += "}"; + code_ += ""; + + // Generate impls for SafeSliceAccess (because all structs are endian-safe), + // Follow for the value type, Follow for the reference type, Push for the + // value type, and Push for the reference type. + code_ += "impl flatbuffers::SimpleToVerifyInSlice for {{STRUCT_NAME}} {}"; + code_ += "impl flatbuffers::SafeSliceAccess for {{STRUCT_NAME}} {}"; + code_ += "impl<'a> flatbuffers::Follow<'a> for {{STRUCT_NAME}} {"; + code_ += " type Inner = &'a {{STRUCT_NAME}};"; + code_ += " #[inline]"; + code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {"; + code_ += " <&'a {{STRUCT_NAME}}>::follow(buf, loc)"; + code_ += " }"; + code_ += "}"; + code_ += "impl<'a> flatbuffers::Follow<'a> for &'a {{STRUCT_NAME}} {"; + code_ += " type Inner = &'a {{STRUCT_NAME}};"; + code_ += " #[inline]"; + code_ += " fn follow(buf: &'a [u8], loc: usize) -> Self::Inner {"; + code_ += " flatbuffers::follow_cast_ref::<{{STRUCT_NAME}}>(buf, loc)"; + code_ += " }"; + code_ += "}"; + code_ += "impl<'b> flatbuffers::Push for {{STRUCT_NAME}} {"; + code_ += " type Output = {{STRUCT_NAME}};"; + code_ += " #[inline]"; + code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {"; + code_ += " let src = unsafe {"; + code_ += + " ::std::slice::from_raw_parts(" + "self as *const {{STRUCT_NAME}} as *const u8, Self::size())"; + code_ += " };"; + code_ += " dst.copy_from_slice(src);"; + code_ += " }"; + code_ += "}"; + code_ += "impl<'b> flatbuffers::Push for &'b {{STRUCT_NAME}} {"; + code_ += " type Output = {{STRUCT_NAME}};"; + code_ += ""; + code_ += " #[inline]"; + code_ += " fn push(&self, dst: &mut [u8], _rest: &[u8]) {"; + code_ += " let src = unsafe {"; + code_ += + " ::std::slice::from_raw_parts(" + "*self as *const {{STRUCT_NAME}} as *const u8, Self::size())"; + code_ += " };"; + code_ += " dst.copy_from_slice(src);"; + code_ += " }"; + code_ += "}"; + code_ += ""; + + // Generate verifier: Structs are simple so presence and alignment are + // all that need to be checked. + code_ += "impl<'a> flatbuffers::Verifiable for {{STRUCT_NAME}} {"; + code_ += " #[inline]"; + code_ += " fn run_verifier("; + code_ += " v: &mut flatbuffers::Verifier, pos: usize"; + code_ += " ) -> Result<(), flatbuffers::InvalidFlatbuffer> {"; + code_ += " use self::flatbuffers::Verifiable;"; + code_ += " v.in_buffer::<Self>(pos)"; + code_ += " }"; + code_ += "}"; + + // Generate a constructor that takes all fields as arguments. + code_ += "impl<'a> {{STRUCT_NAME}} {"; + code_ += " #[allow(clippy::too_many_arguments)]"; + code_ += " pub fn new("; + ForAllStructFields(struct_def, [&](const FieldDef &unused) { + (void)unused; + code_ += " {{FIELD_NAME}}: {{REF}}{{FIELD_TYPE}},"; + }); + code_ += " ) -> Self {"; + code_ += " let mut s = Self([0; {{STRUCT_SIZE}}]);"; + ForAllStructFields(struct_def, [&](const FieldDef &unused) { + (void)unused; + code_ += " s.set_{{FIELD_NAME}}({{REF}}{{FIELD_NAME}});"; + }); + code_ += " s"; + code_ += " }"; + code_ += ""; + + if (parser_.opts.generate_name_strings) { + GenFullyQualifiedNameGetter(struct_def, struct_def.name); + } + + // Generate accessor methods for the struct. + ForAllStructFields(struct_def, [&](const FieldDef &field) { + this->GenComment(field.doc_comment, " "); + // Getter. + if (IsStruct(field.value.type)) { + code_ += " pub fn {{FIELD_NAME}}(&self) -> &{{FIELD_TYPE}} {"; + code_ += + " unsafe {" + " &*(self.0[{{FIELD_OFFSET}}..].as_ptr() as *const" + " {{FIELD_TYPE}}) }"; + } else if (IsArray(field.value.type)) { + code_.SetValue("ARRAY_SIZE", + NumToString(field.value.type.fixed_length)); + code_.SetValue("ARRAY_ITEM", GetTypeGet(field.value.type.VectorType())); + code_ += + " pub fn {{FIELD_NAME}}(&'a self) -> " + "flatbuffers::Array<'a, {{ARRAY_ITEM}}, {{ARRAY_SIZE}}> {"; + code_ += " flatbuffers::Array::follow(&self.0, {{FIELD_OFFSET}})"; + } else { + code_ += " pub fn {{FIELD_NAME}}(&self) -> {{FIELD_TYPE}} {"; + code_ += + " let mut mem = core::mem::MaybeUninit::" + "<{{FIELD_TYPE}}>::uninit();"; + code_ += " unsafe {"; + code_ += " core::ptr::copy_nonoverlapping("; + code_ += " self.0[{{FIELD_OFFSET}}..].as_ptr(),"; + code_ += " mem.as_mut_ptr() as *mut u8,"; + code_ += " core::mem::size_of::<{{FIELD_TYPE}}>(),"; + code_ += " );"; + code_ += " mem.assume_init()"; + code_ += " }.from_little_endian()"; + } + code_ += " }\n"; + // Setter. + if (IsStruct(field.value.type)) { + code_.SetValue("FIELD_SIZE", NumToString(InlineSize(field.value.type))); + code_ += " pub fn set_{{FIELD_NAME}}(&mut self, x: &{{FIELD_TYPE}}) {"; + code_ += + " self.0[{{FIELD_OFFSET}}..{{FIELD_OFFSET}}+{{FIELD_SIZE}}]" + ".copy_from_slice(&x.0)"; + } else if (IsArray(field.value.type)) { + if (GetFullType(field.value.type) == ftArrayOfBuiltin) { + code_.SetValue("ARRAY_ITEM", + GetTypeGet(field.value.type.VectorType())); + code_.SetValue( + "ARRAY_ITEM_SIZE", + NumToString(InlineSize(field.value.type.VectorType()))); + code_ += + " pub fn set_{{FIELD_NAME}}(&mut self, items: &{{FIELD_TYPE}}) " + "{"; + code_ += + " flatbuffers::emplace_scalar_array(&mut self.0, " + "{{FIELD_OFFSET}}, items);"; + } else { + code_.SetValue("FIELD_SIZE", + NumToString(InlineSize(field.value.type))); + code_ += + " pub fn set_{{FIELD_NAME}}(&mut self, x: &{{FIELD_TYPE}}) {"; + code_ += " unsafe {"; + code_ += " std::ptr::copy("; + code_ += " x.as_ptr() as *const u8,"; + code_ += " self.0.as_mut_ptr().add({{FIELD_OFFSET}}),"; + code_ += " {{FIELD_SIZE}},"; + code_ += " );"; + code_ += " }"; + } + } else { + code_ += " pub fn set_{{FIELD_NAME}}(&mut self, x: {{FIELD_TYPE}}) {"; + code_ += " let x_le = x.to_little_endian();"; + code_ += " unsafe {"; + code_ += " core::ptr::copy_nonoverlapping("; + code_ += " &x_le as *const {{FIELD_TYPE}} as *const u8,"; + code_ += " self.0[{{FIELD_OFFSET}}..].as_mut_ptr(),"; + code_ += " core::mem::size_of::<{{FIELD_TYPE}}>(),"; + code_ += " );"; + code_ += " }"; + } + code_ += " }\n"; + + // Generate a comparison function for this field if it is a key. + if (field.key) { GenKeyFieldMethods(field); } + }); + + // Generate Object API unpack method. + if (parser_.opts.generate_object_based_api) { + code_.SetValue("NATIVE_STRUCT_NAME", NativeName(struct_def)); + code_ += " pub fn unpack(&self) -> {{NATIVE_STRUCT_NAME}} {"; + code_ += " {{NATIVE_STRUCT_NAME}} {"; + ForAllStructFields(struct_def, [&](const FieldDef &field) { + if (IsArray(field.value.type)) { + if (GetFullType(field.value.type) == ftArrayOfStruct) { + code_ += + " {{FIELD_NAME}}: { let {{FIELD_NAME}} = " + "self.{{FIELD_NAME}}(); flatbuffers::array_init(|i| " + "{{FIELD_NAME}}.get(i).unpack()) },"; + } else { + code_ += " {{FIELD_NAME}}: self.{{FIELD_NAME}}().into(),"; + } + } else { + std::string unpack = IsStruct(field.value.type) ? ".unpack()" : ""; + code_ += " {{FIELD_NAME}}: self.{{FIELD_NAME}}()" + unpack + ","; + } + }); + code_ += " }"; + code_ += " }"; + } + + code_ += "}"; // End impl Struct methods. + code_ += ""; + + // Generate Struct Object. + if (parser_.opts.generate_object_based_api) { + // Struct declaration + code_ += "#[derive(Debug, Clone, PartialEq, Default)]"; + code_ += "pub struct {{NATIVE_STRUCT_NAME}} {"; + ForAllStructFields(struct_def, [&](const FieldDef &field) { + (void)field; // unused. + code_ += " pub {{FIELD_NAME}}: {{FIELD_OBJECT_TYPE}},"; + }); + code_ += "}"; + // The `pack` method that turns the native struct into its Flatbuffers + // counterpart. + code_ += "impl {{NATIVE_STRUCT_NAME}} {"; + code_ += " pub fn pack(&self) -> {{STRUCT_NAME}} {"; + code_ += " {{STRUCT_NAME}}::new("; + ForAllStructFields(struct_def, [&](const FieldDef &field) { + if (IsStruct(field.value.type)) { + code_ += " &self.{{FIELD_NAME}}.pack(),"; + } else if (IsArray(field.value.type)) { + if (GetFullType(field.value.type) == ftArrayOfStruct) { + code_ += + " &flatbuffers::array_init(|i| " + "self.{{FIELD_NAME}}[i].pack()),"; + } else { + code_ += " &self.{{FIELD_NAME}},"; + } + } else { + code_ += " self.{{FIELD_NAME}},"; + } + }); + code_ += " )"; + code_ += " }"; + code_ += "}"; + code_ += ""; + } + } + + void GenNamespaceImports(const int white_spaces) { + // DO not use global attributes (i.e. #![...]) since it interferes + // with users who include! generated files. + // See: https://github.com/google/flatbuffers/issues/6261 + std::string indent = std::string(white_spaces, ' '); + code_ += ""; + if (!parser_.opts.generate_all) { + for (auto it = parser_.included_files_.begin(); + it != parser_.included_files_.end(); ++it) { + if (it->second.empty()) continue; + auto noext = flatbuffers::StripExtension(it->second); + auto basename = flatbuffers::StripPath(noext); + + if (parser_.opts.include_prefix.empty()) { + code_ += indent + "use crate::" + basename + + parser_.opts.filename_suffix + "::*;"; + } else { + auto prefix = parser_.opts.include_prefix; + prefix.pop_back(); + + code_ += indent + "use crate::" + prefix + "::" + basename + + parser_.opts.filename_suffix + "::*;"; + } + } + } + code_ += indent + "use std::mem;"; + code_ += indent + "use std::cmp::Ordering;"; + code_ += ""; + code_ += indent + "extern crate flatbuffers;"; + code_ += indent + "use self::flatbuffers::{EndianScalar, Follow};"; + } + + // Set up the correct namespace. This opens a namespace if the current + // namespace is different from the target namespace. This function + // closes and opens the namespaces only as necessary. + // + // The file must start and end with an empty (or null) namespace so that + // namespaces are properly opened and closed. + void SetNameSpace(const Namespace *ns) { + if (cur_name_space_ == ns) { return; } + + // Compute the size of the longest common namespace prefix. + // If cur_name_space is A::B::C::D and ns is A::B::E::F::G, + // the common prefix is A::B:: and we have old_size = 4, new_size = 5 + // and common_prefix_size = 2 + size_t old_size = cur_name_space_ ? cur_name_space_->components.size() : 0; + size_t new_size = ns ? ns->components.size() : 0; + + size_t common_prefix_size = 0; + while (common_prefix_size < old_size && common_prefix_size < new_size && + ns->components[common_prefix_size] == + cur_name_space_->components[common_prefix_size]) { + common_prefix_size++; + } + + // Close cur_name_space in reverse order to reach the common prefix. + // In the previous example, D then C are closed. + for (size_t j = old_size; j > common_prefix_size; --j) { + code_ += "} // pub mod " + cur_name_space_->components[j - 1]; + } + if (old_size != common_prefix_size) { code_ += ""; } + + // open namespace parts to reach the ns namespace + // in the previous example, E, then F, then G are opened + for (auto j = common_prefix_size; j != new_size; ++j) { + code_ += "#[allow(unused_imports, dead_code)]"; + code_ += "pub mod " + MakeSnakeCase(ns->components[j]) + " {"; + // Generate local namespace imports. + GenNamespaceImports(2); + } + if (new_size != common_prefix_size) { code_ += ""; } + + cur_name_space_ = ns; + } +}; + +} // namespace rust + +bool GenerateRust(const Parser &parser, const std::string &path, + const std::string &file_name) { + rust::RustGenerator generator(parser, path, file_name); + return generator.generate(); +} + +std::string RustMakeRule(const Parser &parser, const std::string &path, + const std::string &file_name) { + std::string filebase = + flatbuffers::StripPath(flatbuffers::StripExtension(file_name)); + rust::RustGenerator generator(parser, path, file_name); + std::string make_rule = + generator.GeneratedFileName(path, filebase, parser.opts) + ": "; + + auto included_files = parser.GetIncludedFilesRecursive(file_name); + for (auto it = included_files.begin(); it != included_files.end(); ++it) { + make_rule += " " + *it; + } + return make_rule; +} + +} // namespace flatbuffers + +// TODO(rw): Generated code should import other generated files. +// TODO(rw): Generated code should refer to namespaces in included files in a +// way that makes them referrable. +// TODO(rw): Generated code should indent according to nesting level. +// TODO(rw): Generated code should generate endian-safe Debug impls. +// TODO(rw): Generated code could use a Rust-only enum type to access unions, +// instead of making the user use _type() to manually switch. +// TODO(maxburke): There should be test schemas added that use language +// keywords as fields of structs, tables, unions, enums, to make sure +// that internal code generated references escaped names correctly. +// TODO(maxburke): We should see if there is a more flexible way of resolving +// module paths for use declarations. Right now if schemas refer to +// other flatbuffer files, the include paths in emitted Rust bindings +// are crate-relative which may undesirable. diff --git a/contrib/libs/flatbuffers/src/idl_gen_swift.cpp b/contrib/libs/flatbuffers/src/idl_gen_swift.cpp new file mode 100644 index 0000000000..3fffd39455 --- /dev/null +++ b/contrib/libs/flatbuffers/src/idl_gen_swift.cpp @@ -0,0 +1,1575 @@ +/* + * Copyright 2020 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <cctype> +#include <unordered_set> + +#include "flatbuffers/code_generators.h" +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +namespace flatbuffers { + +namespace swift { + +inline std::string GenIndirect(const std::string &reading) { + return "{{ACCESS}}.indirect(" + reading + ")"; +} + +inline std::string GenArrayMainBody(const std::string &optional) { + return "{{ACCESS_TYPE}} func {{VALUENAME}}(at index: Int32) -> " + "{{VALUETYPE}}" + + optional + " { "; +} + +class SwiftGenerator : public BaseGenerator { + private: + CodeWriter code_; + std::unordered_set<std::string> keywords_; + int namespace_depth; + + public: + SwiftGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name, "", "_", "swift") { + namespace_depth = 0; + code_.SetPadding(" "); + static const char *const keywords[] = { + "associatedtype", + "class", + "deinit", + "enum", + "extension", + "fileprivate", + "func", + "import", + "init", + "inout", + "internal", + "let", + "open", + "operator", + "private", + "protocol", + "public", + "rethrows", + "static", + "struct", + "subscript", + "typealias", + "var", + "break", + "case", + "continue", + "default", + "defer", + "do", + "else", + "fallthrough", + "for", + "guard", + "if", + "in", + "repeat", + "return", + "switch", + "where", + "while", + "Any", + "catch", + "false", + "is", + "nil", + "super", + "self", + "Self", + "throw", + "throws", + "true", + "try", + "associativity", + "convenience", + "dynamic", + "didSet", + "final", + "get", + "infix", + "indirect", + "lazy", + "left", + "mutating", + "none", + "nonmutating", + "optional", + "override", + "postfix", + "precedence", + "prefix", + "Protocol", + "required", + "right", + "set", + "Type", + "unowned", + "weak", + "willSet", + "Void", + nullptr, + }; + for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw); + } + + bool generate() { + code_.Clear(); + code_.SetValue("ACCESS", "_accessor"); + code_.SetValue("TABLEOFFSET", "VTOFFSET"); + code_ += "// " + std::string(FlatBuffersGeneratedWarning()); + code_ += "// swiftlint:disable all"; + code_ += "// swiftformat:disable all\n"; + code_ += "import FlatBuffers\n"; + // Generate code for all the enum declarations. + + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + const auto &enum_def = **it; + if (!enum_def.generated) { GenEnum(enum_def); } + } + + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + const auto &struct_def = **it; + if (struct_def.fixed && !struct_def.generated) { + GenStructReader(struct_def); + GenMutableStructReader(struct_def); + } + } + + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + const auto &struct_def = **it; + if (!struct_def.fixed && !struct_def.generated) { + GenTable(struct_def); + if (parser_.opts.generate_object_based_api) { + GenObjectAPI(struct_def); + } + } + } + + const auto filename = GeneratedFileName(path_, file_name_, parser_.opts); + const auto final_code = code_.ToString(); + return SaveFile(filename.c_str(), final_code, false); + } + + void mark(const std::string &str) { + code_.SetValue("MARKVALUE", str); + code_ += "\n// MARK: - {{MARKVALUE}}\n"; + } + + // MARK: - Generating structs + + // Generates the reader for swift + void GenStructReader(const StructDef &struct_def) { + auto is_private_access = struct_def.attributes.Lookup("private"); + code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public"); + GenComment(struct_def.doc_comment); + code_.SetValue("STRUCTNAME", NameWrappedInNameSpace(struct_def)); + code_ += "{{ACCESS_TYPE}} struct {{STRUCTNAME}}: NativeStruct\\"; + if (parser_.opts.generate_object_based_api) code_ += ", NativeObject\\"; + code_ += " {"; + code_ += ""; + Indent(); + code_ += ValidateFunc(); + code_ += ""; + int padding_id = 0; + std::string constructor = ""; + std::vector<std::string> base_constructor; + std::vector<std::string> main_constructor; + + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + + if (!constructor.empty()) constructor += ", "; + + auto name = Name(field); + auto type = GenType(field.value.type); + code_.SetValue("VALUENAME", name); + if (IsEnum(field.value.type)) { + code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false)); + } + code_.SetValue("VALUETYPE", type); + GenComment(field.doc_comment); + std::string valueType = + IsEnum(field.value.type) ? "{{BASEVALUE}}" : "{{VALUETYPE}}"; + code_ += "private var _{{VALUENAME}}: " + valueType; + auto accessing_value = IsEnum(field.value.type) ? ".value" : ""; + auto base_value = + IsStruct(field.value.type) ? (type + "()") : field.value.constant; + + main_constructor.push_back("_" + name + " = " + name + accessing_value); + base_constructor.push_back("_" + name + " = " + base_value); + + if (field.padding) { GenPadding(field, &padding_id); } + constructor += name + ": " + type; + } + code_ += ""; + BuildObjectConstructor(main_constructor, constructor); + BuildObjectConstructor(base_constructor, ""); + + if (parser_.opts.generate_object_based_api) + GenerateObjectAPIStructConstructor(struct_def); + + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + auto name = Name(field); + auto type = GenType(field.value.type); + code_.SetValue("VALUENAME", name); + code_.SetValue("VALUETYPE", type); + GenComment(field.doc_comment); + if (!IsEnum(field.value.type)) { + code_ += GenReaderMainBody() + "_{{VALUENAME}} }"; + } else if (IsEnum(field.value.type)) { + code_ += + GenReaderMainBody() + "{{VALUETYPE}}(rawValue: _{{VALUENAME}})! }"; + } + } + Outdent(); + code_ += "}\n"; + } + + void GenMutableStructReader(const StructDef &struct_def) { + GenObjectHeader(struct_def); + + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + auto offset = NumToString(field.value.offset); + auto name = Name(field); + auto type = GenType(field.value.type); + code_.SetValue("VALUENAME", name); + if (IsEnum(field.value.type)) { + code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false)); + } + code_.SetValue("VALUETYPE", type); + code_.SetValue("OFFSET", offset); + if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type)) { + code_ += + GenReaderMainBody() + "return " + GenReader("VALUETYPE") + " }"; + } else if (IsEnum(field.value.type)) { + code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false)); + code_ += GenReaderMainBody() + "return " + + GenEnumConstructor("{{OFFSET}}") + "?? " + + GenEnumDefaultValue(field) + " }"; + } else if (IsStruct(field.value.type)) { + code_.SetValue("VALUETYPE", GenType(field.value.type) + Mutable()); + code_ += GenReaderMainBody() + "return " + + GenConstructor("{{ACCESS}}.postion + {{OFFSET}}"); + } + if (parser_.opts.mutable_buffer && !IsStruct(field.value.type)) + code_ += GenMutate("{{OFFSET}}", "", IsEnum(field.value.type)); + } + + if (parser_.opts.generate_object_based_api) { + GenerateObjectAPIExtensionHeader(NameWrappedInNameSpace(struct_def)); + code_ += "return builder.create(struct: obj)"; + Outdent(); + code_ += "}"; + } + Outdent(); + code_ += "}\n"; + } + + // Generates the create function for swift + void GenStructWriter(const StructDef &struct_def) { + auto is_private_access = struct_def.attributes.Lookup("private"); + code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public"); + code_.SetValue("STRUCTNAME", NameWrappedInNameSpace(struct_def)); + code_.SetValue("SHORT_STRUCTNAME", Name(struct_def)); + code_ += "extension {{STRUCTNAME}} {"; + Indent(); + code_ += "@discardableResult"; + code_ += + "{{ACCESS_TYPE}} static func create{{SHORT_STRUCTNAME}}(builder: inout " + "FlatBufferBuilder, \\"; + std::string func_header = ""; + GenerateStructArgs(struct_def, &func_header, "", ""); + code_ += func_header.substr(0, func_header.size() - 2) + "\\"; + code_ += ") -> Offset {"; + Indent(); + code_ += + "builder.createStructOf(size: {{STRUCTNAME}}.size, alignment: " + "{{STRUCTNAME}}.alignment)"; + code_ += "return builder.endStruct()"; + Outdent(); + code_ += "}\n"; + Outdent(); + code_ += "}\n"; + } + + void GenerateStructArgs(const StructDef &struct_def, std::string *code_ptr, + const std::string &nameprefix, + const std::string &object_name, + const std::string &obj_api_named = "", + bool is_obj_api = false) { + auto &code = *code_ptr; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + const auto &field_type = field.value.type; + if (IsStruct(field.value.type)) { + GenerateStructArgs( + *field_type.struct_def, code_ptr, (nameprefix + field.name), + (object_name + "." + field.name), obj_api_named, is_obj_api); + } else { + auto name = Name(field); + auto type = GenType(field.value.type); + if (!is_obj_api) { + code += nameprefix + name + ": " + type; + if (!IsEnum(field.value.type)) { + code += " = "; + auto is_bool = IsBool(field.value.type.base_type); + auto constant = + is_bool ? ("0" == field.value.constant ? "false" : "true") + : field.value.constant; + code += constant; + } + code += ", "; + continue; + } + code += + nameprefix + name + ": " + obj_api_named + object_name + "." + name; + code += ", "; + } + } + } + + // MARK: - Table Generator + + // Generates the reader for swift + void GenTable(const StructDef &struct_def) { + auto is_private_access = struct_def.attributes.Lookup("private"); + code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public"); + + GenObjectHeader(struct_def); + GenTableAccessors(struct_def); + GenTableReader(struct_def); + GenTableWriter(struct_def); + if (parser_.opts.generate_object_based_api) + GenerateObjectAPITableExtension(struct_def); + Outdent(); + code_ += "}\n"; + } + + // Generates the reader for swift + void GenTableAccessors(const StructDef &struct_def) { + // Generate field id constants. + if (struct_def.fields.vec.size() > 0) { + code_ += "private enum {{TABLEOFFSET}}: VOffset {"; + Indent(); + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.deprecated) { continue; } + code_.SetValue("OFFSET_NAME", Name(field)); + code_.SetValue("OFFSET_VALUE", NumToString(field.value.offset)); + code_ += "case {{OFFSET_NAME}} = {{OFFSET_VALUE}}"; + } + code_ += "var v: Int32 { Int32(self.rawValue) }"; + code_ += "var p: VOffset { self.rawValue }"; + Outdent(); + code_ += "}"; + code_ += ""; + } + } + + void GenObjectHeader(const StructDef &struct_def) { + GenComment(struct_def.doc_comment); + + code_.SetValue("SHORT_STRUCTNAME", Name(struct_def)); + code_.SetValue("STRUCTNAME", NameWrappedInNameSpace(struct_def)); + code_.SetValue("OBJECTTYPE", struct_def.fixed ? "Struct" : "Table"); + code_.SetValue("MUTABLE", struct_def.fixed ? Mutable() : ""); + code_ += + "{{ACCESS_TYPE}} struct {{STRUCTNAME}}{{MUTABLE}}: FlatBufferObject\\"; + if (!struct_def.fixed && parser_.opts.generate_object_based_api) + code_ += ", ObjectAPIPacker\\"; + code_ += " {\n"; + Indent(); + code_ += ValidateFunc(); + code_ += + "{{ACCESS_TYPE}} var __buffer: ByteBuffer! { return {{ACCESS}}.bb }"; + code_ += "private var {{ACCESS}}: {{OBJECTTYPE}}\n"; + if (!struct_def.fixed) { + if (parser_.file_identifier_.length()) { + code_.SetValue("FILENAME", parser_.file_identifier_); + code_ += + "{{ACCESS_TYPE}} static func finish(_ fbb: inout " + "FlatBufferBuilder, end: " + "Offset, prefix: Bool = false) { fbb.finish(offset: end, " + "fileId: " + "\"{{FILENAME}}\", addPrefix: prefix) }"; + } + code_ += + "{{ACCESS_TYPE}} static func getRootAs{{SHORT_STRUCTNAME}}(bb: " + "ByteBuffer) -> " + "{{STRUCTNAME}} { return {{STRUCTNAME}}(Table(bb: bb, position: " + "Int32(bb.read(def: UOffset.self, position: bb.reader)) + " + "Int32(bb.reader))) }\n"; + code_ += "private init(_ t: Table) { {{ACCESS}} = t }"; + } + code_ += + "{{ACCESS_TYPE}} init(_ bb: ByteBuffer, o: Int32) { {{ACCESS}} = " + "{{OBJECTTYPE}}(bb: " + "bb, position: o) }"; + code_ += ""; + } + + void GenTableWriter(const StructDef &struct_def) { + flatbuffers::FieldDef *key_field = nullptr; + std::vector<std::string> require_fields; + std::vector<std::string> create_func_body; + std::vector<std::string> create_func_header; + auto should_generate_create = struct_def.fields.vec.size() != 0; + + code_.SetValue("NUMBEROFFIELDS", NumToString(struct_def.fields.vec.size())); + code_ += + "{{ACCESS_TYPE}} static func start{{SHORT_STRUCTNAME}}(_ fbb: inout " + "FlatBufferBuilder) -> " + "UOffset { fbb.startTable(with: {{NUMBEROFFIELDS}}) }"; + + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + if (field.key) key_field = &field; + if (field.IsRequired()) + require_fields.push_back(NumToString(field.value.offset)); + + GenTableWriterFields(field, &create_func_body, &create_func_header); + } + code_ += + "{{ACCESS_TYPE}} static func end{{SHORT_STRUCTNAME}}(_ fbb: inout " + "FlatBufferBuilder, " + "start: " + "UOffset) -> Offset { let end = Offset(offset: " + "fbb.endTable(at: start))\\"; + if (require_fields.capacity() != 0) { + std::string fields = ""; + for (auto it = require_fields.begin(); it != require_fields.end(); ++it) + fields += *it + ", "; + code_.SetValue("FIELDS", fields.substr(0, fields.size() - 2)); + code_ += "; fbb.require(table: end, fields: [{{FIELDS}}])\\"; + } + code_ += "; return end }"; + + if (should_generate_create) { + code_ += "{{ACCESS_TYPE}} static func create{{SHORT_STRUCTNAME}}("; + Indent(); + code_ += "_ fbb: inout FlatBufferBuilder,"; + for (auto it = create_func_header.begin(); it < create_func_header.end(); + ++it) { + code_ += *it + "\\"; + if (it < create_func_header.end() - 1) code_ += ","; + } + code_ += ""; + Outdent(); + code_ += ") -> Offset {"; + Indent(); + code_ += "let __start = {{STRUCTNAME}}.start{{SHORT_STRUCTNAME}}(&fbb)"; + for (auto it = create_func_body.begin(); it < create_func_body.end(); + ++it) { + code_ += *it; + } + code_ += + "return {{STRUCTNAME}}.end{{SHORT_STRUCTNAME}}(&fbb, start: __start)"; + Outdent(); + code_ += "}"; + } + + std::string spacing = ""; + + if (key_field != nullptr && !struct_def.fixed && struct_def.has_key) { + code_.SetValue("VALUENAME", NameWrappedInNameSpace(struct_def)); + code_.SetValue("SHORT_VALUENAME", Name(struct_def)); + code_.SetValue("VOFFSET", NumToString(key_field->value.offset)); + + code_ += + "{{ACCESS_TYPE}} static func " + "sortVectorOf{{SHORT_VALUENAME}}(offsets:[Offset], " + "_ fbb: inout FlatBufferBuilder) -> Offset {"; + Indent(); + code_ += spacing + "var off = offsets"; + code_ += + spacing + + "off.sort { Table.compare(Table.offset(Int32($1.o), vOffset: " + "{{VOFFSET}}, fbb: fbb.buffer), Table.offset(Int32($0.o), vOffset: " + "{{VOFFSET}}, fbb: fbb.buffer), fbb: fbb.buffer) < 0 } "; + code_ += spacing + "return fbb.createVector(ofOffsets: off)"; + Outdent(); + code_ += "}"; + GenLookup(*key_field); + } + } + + void GenTableWriterFields(const FieldDef &field, + std::vector<std::string> *create_body, + std::vector<std::string> *create_header) { + std::string builder_string = ", _ fbb: inout FlatBufferBuilder) { "; + auto &create_func_body = *create_body; + auto &create_func_header = *create_header; + auto name = Name(field); + auto type = GenType(field.value.type); + auto opt_scalar = + field.IsOptional() && IsScalar(field.value.type.base_type); + auto nullable_type = opt_scalar ? type + "?" : type; + code_.SetValue("VALUENAME", name); + code_.SetValue("VALUETYPE", nullable_type); + code_.SetValue("OFFSET", name); + code_.SetValue("CONSTANT", field.value.constant); + std::string check_if_vector = + (IsVector(field.value.type) || IsArray(field.value.type)) ? "VectorOf(" + : "("; + auto body = "add" + check_if_vector + name + ": "; + code_ += "{{ACCESS_TYPE}} static func " + body + "\\"; + + create_func_body.push_back("{{STRUCTNAME}}." + body + name + ", &fbb)"); + + if (IsScalar(field.value.type.base_type) && + !IsBool(field.value.type.base_type)) { + std::string is_enum = IsEnum(field.value.type) ? ".rawValue" : ""; + std::string optional_enum = + IsEnum(field.value.type) ? ("?" + is_enum) : ""; + code_ += + "{{VALUETYPE}}" + builder_string + "fbb.add(element: {{VALUENAME}}\\"; + + code_ += field.IsOptional() ? (optional_enum + "\\") + : (is_enum + ", def: {{CONSTANT}}\\"); + + code_ += ", at: {{TABLEOFFSET}}.{{OFFSET}}.p) }"; + + auto default_value = + IsEnum(field.value.type) + ? (field.IsOptional() ? "nil" : GenEnumDefaultValue(field)) + : field.value.constant; + create_func_header.push_back( + "" + name + ": " + nullable_type + " = " + + (field.IsOptional() ? "nil" : default_value)); + return; + } + + if (IsBool(field.value.type.base_type)) { + std::string default_value = + "0" == field.value.constant ? "false" : "true"; + + code_.SetValue("CONSTANT", default_value); + code_.SetValue("VALUETYPE", field.IsOptional() ? "Bool?" : "Bool"); + code_ += "{{VALUETYPE}}" + builder_string + + "fbb.add(element: {{VALUENAME}},\\"; + code_ += field.IsOptional() ? "\\" : " def: {{CONSTANT}},"; + code_ += " at: {{TABLEOFFSET}}.{{OFFSET}}.p) }"; + create_func_header.push_back( + name + ": " + nullable_type + " = " + + (field.IsOptional() ? "nil" : default_value)); + return; + } + + if (IsStruct(field.value.type)) { + auto create_struct = + "guard let {{VALUENAME}} = {{VALUENAME}} else { return };" + " fbb.create(struct: {{VALUENAME}}, position: " + "{{TABLEOFFSET}}.{{OFFSET}}.p) }"; + code_ += type + "?" + builder_string + create_struct; + /// Optional hard coded since structs are always optional + create_func_header.push_back(name + ": " + type + "? = nil"); + return; + } + + auto camel_case_name = + MakeCamel(name, false) + + (IsVector(field.value.type) || IsArray(field.value.type) + ? "VectorOffset" + : "Offset"); + create_func_header.push_back(camel_case_name + " " + name + ": " + + "Offset = Offset()"); + auto reader_type = + IsStruct(field.value.type) && field.value.type.struct_def->fixed + ? "structOffset: {{TABLEOFFSET}}.{{OFFSET}}.p) }" + : "offset: {{VALUENAME}}, at: {{TABLEOFFSET}}.{{OFFSET}}.p) }"; + code_ += "Offset" + builder_string + "fbb.add(" + reader_type; + + auto vectortype = field.value.type.VectorType(); + + if ((vectortype.base_type == BASE_TYPE_STRUCT && + field.value.type.struct_def->fixed) && + (IsVector(field.value.type) || IsArray(field.value.type))) { + auto field_name = NameWrappedInNameSpace(*vectortype.struct_def); + code_ += "public static func startVectorOf" + MakeCamel(name, true) + + "(_ size: Int, in builder: inout " + "FlatBufferBuilder) {"; + Indent(); + code_ += "builder.startVector(size * MemoryLayout<" + field_name + + ">.size, elementSize: MemoryLayout<" + field_name + + ">.alignment)"; + Outdent(); + code_ += "}"; + } + } + + void GenTableReader(const StructDef &struct_def) { + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + GenTableReaderFields(field); + } + } + + void GenTableReaderFields(const FieldDef &field) { + auto offset = NumToString(field.value.offset); + auto name = Name(field); + auto type = GenType(field.value.type); + code_.SetValue("VALUENAME", name); + code_.SetValue("VALUETYPE", type); + code_.SetValue("OFFSET", name); + code_.SetValue("CONSTANT", field.value.constant); + std::string def_Val = field.IsDefault() ? "{{CONSTANT}}" : "nil"; + std::string optional = field.IsOptional() ? "?" : ""; + auto const_string = "return o == 0 ? " + def_Val + " : "; + GenComment(field.doc_comment); + if (IsScalar(field.value.type.base_type) && !IsEnum(field.value.type) && + !IsBool(field.value.type.base_type)) { + code_ += GenReaderMainBody(optional) + GenOffset() + const_string + + GenReader("VALUETYPE", "o") + " }"; + if (parser_.opts.mutable_buffer) code_ += GenMutate("o", GenOffset()); + return; + } + + if (IsBool(field.value.type.base_type)) { + std::string default_value = + "0" == field.value.constant ? "false" : "true"; + code_.SetValue("CONSTANT", default_value); + code_.SetValue("VALUETYPE", "Bool"); + code_ += GenReaderMainBody(optional) + "\\"; + code_.SetValue("VALUETYPE", "Byte"); + code_ += GenOffset() + "return o == 0 ? {{CONSTANT}} : 0 != " + + GenReader("VALUETYPE", "o") + " }"; + if (parser_.opts.mutable_buffer) code_ += GenMutate("o", GenOffset()); + return; + } + + if (IsEnum(field.value.type)) { + auto default_value = + field.IsOptional() ? "nil" : GenEnumDefaultValue(field); + code_.SetValue("BASEVALUE", GenTypeBasic(field.value.type, false)); + code_ += GenReaderMainBody(optional) + "\\"; + code_ += GenOffset() + "return o == 0 ? " + default_value + " : " + + GenEnumConstructor("o") + "?? " + default_value + " }"; + if (parser_.opts.mutable_buffer && !IsUnion(field.value.type)) + code_ += GenMutate("o", GenOffset(), true); + return; + } + + std::string is_required = field.IsRequired() ? "!" : "?"; + auto required_reader = field.IsRequired() ? "return " : const_string; + + if (IsStruct(field.value.type) && field.value.type.struct_def->fixed) { + code_.SetValue("VALUETYPE", GenType(field.value.type)); + code_.SetValue("CONSTANT", "nil"); + code_ += GenReaderMainBody(is_required) + GenOffset() + required_reader + + "{{ACCESS}}.readBuffer(of: {{VALUETYPE}}.self, at: o) }"; + code_.SetValue("VALUENAME", "mutable" + MakeCamel(name)); + code_.SetValue("VALUETYPE", GenType(field.value.type) + Mutable()); + code_.SetValue("CONSTANT", "nil"); + code_ += GenReaderMainBody(is_required) + GenOffset() + required_reader + + GenConstructor("o + {{ACCESS}}.postion"); + return; + } + switch (field.value.type.base_type) { + case BASE_TYPE_STRUCT: + code_.SetValue("VALUETYPE", GenType(field.value.type)); + code_.SetValue("CONSTANT", "nil"); + code_ += GenReaderMainBody(is_required) + GenOffset() + + required_reader + + GenConstructor(GenIndirect("o + {{ACCESS}}.postion")); + break; + + case BASE_TYPE_STRING: { + auto default_string = "\"" + field.value.constant + "\""; + code_.SetValue("VALUETYPE", GenType(field.value.type)); + code_.SetValue("CONSTANT", field.IsDefault() ? default_string : "nil"); + code_ += GenReaderMainBody(is_required) + GenOffset() + + required_reader + "{{ACCESS}}.string(at: o) }"; + code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}SegmentArray: [UInt8]" + + is_required + + " { return " + "{{ACCESS}}.getVector(at: {{TABLEOFFSET}}.{{OFFSET}}.v) }"; + break; + } + case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); // fall thru + case BASE_TYPE_VECTOR: GenTableReaderVectorFields(field); break; + case BASE_TYPE_UNION: + code_.SetValue("CONSTANT", "nil"); + code_ += + "{{ACCESS_TYPE}} func {{VALUENAME}}<T: " + "FlatbuffersInitializable>(type: " + "T.Type) -> T" + + is_required + " { " + GenOffset() + required_reader + + "{{ACCESS}}.union(o) }"; + break; + default: FLATBUFFERS_ASSERT(0); + } + } + + void GenTableReaderVectorFields(const FieldDef &field) { + std::string const_string = "return o == 0 ? {{CONSTANT}} : "; + auto vectortype = field.value.type.VectorType(); + code_.SetValue("SIZE", NumToString(InlineSize(vectortype))); + code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}Count: Int32 { " + GenOffset() + + "return o == 0 ? 0 : {{ACCESS}}.vector(count: o) }"; + code_.SetValue("CONSTANT", + IsScalar(vectortype.base_type) == true ? "0" : "nil"); + auto nullable = IsScalar(vectortype.base_type) == true ? "" : "?"; + nullable = IsEnum(vectortype) == true ? "?" : nullable; + + if (vectortype.base_type != BASE_TYPE_UNION) { + code_ += GenArrayMainBody(nullable) + GenOffset() + "\\"; + } else { + code_ += + "{{ACCESS_TYPE}} func {{VALUENAME}}<T: FlatbuffersInitializable>(at " + "index: " + "Int32, type: T.Type) -> T? { " + + GenOffset() + "\\"; + } + + if (IsBool(vectortype.base_type)) { + code_.SetValue("CONSTANT", field.value.offset == 0 ? "false" : "true"); + code_.SetValue("VALUETYPE", "Bool"); + } + + if (!IsEnum(vectortype)) code_ += const_string + "\\"; + + if (IsScalar(vectortype.base_type) && !IsEnum(vectortype) && + !IsBool(field.value.type.base_type)) { + code_ += + "{{ACCESS}}.directRead(of: {{VALUETYPE}}.self, offset: " + "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }"; + code_ += + "{{ACCESS_TYPE}} var {{VALUENAME}}: [{{VALUETYPE}}] { return " + "{{ACCESS}}.getVector(at: {{TABLEOFFSET}}.{{OFFSET}}.v) ?? [] }"; + if (parser_.opts.mutable_buffer) code_ += GenMutateArray(); + return; + } + + if (vectortype.base_type == BASE_TYPE_STRUCT && + field.value.type.struct_def->fixed) { + code_ += + "{{ACCESS}}.directRead(of: {{VALUETYPE}}.self, offset: " + "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }"; + code_.SetValue("VALUENAME", "mutable" + MakeCamel(Name(field))); + code_.SetValue("VALUETYPE", GenType(field.value.type) + Mutable()); + code_ += GenArrayMainBody(nullable) + GenOffset() + const_string + + GenConstructor("{{ACCESS}}.vector(at: o) + index * {{SIZE}}"); + + return; + } + + if (IsString(vectortype)) { + code_ += + "{{ACCESS}}.directString(at: {{ACCESS}}.vector(at: o) + " + "index * {{SIZE}}) }"; + return; + } + + if (IsEnum(vectortype)) { + code_.SetValue("BASEVALUE", GenTypeBasic(vectortype, false)); + code_ += "return o == 0 ? {{VALUETYPE}}" + GenEnumDefaultValue(field) + + " : {{VALUETYPE}}(rawValue: {{ACCESS}}.directRead(of: " + "{{BASEVALUE}}.self, offset: {{ACCESS}}.vector(at: o) + " + "index * {{SIZE}})) }"; + return; + } + if (vectortype.base_type == BASE_TYPE_UNION) { + code_ += + "{{ACCESS}}.directUnion({{ACCESS}}.vector(at: o) + " + "index * {{SIZE}}) }"; + return; + } + + if (vectortype.base_type == BASE_TYPE_STRUCT && + !field.value.type.struct_def->fixed) { + code_ += GenConstructor( + "{{ACCESS}}.indirect({{ACCESS}}.vector(at: o) + index * " + "{{SIZE}})"); + auto &sd = *field.value.type.struct_def; + auto &fields = sd.fields.vec; + for (auto kit = fields.begin(); kit != fields.end(); ++kit) { + auto &key_field = **kit; + if (key_field.key) { + GenByKeyFunctions(key_field); + break; + } + } + } + } + + void GenByKeyFunctions(const FieldDef &key_field) { + code_.SetValue("TYPE", GenType(key_field.value.type)); + code_ += + "{{ACCESS_TYPE}} func {{VALUENAME}}By(key: {{TYPE}}) -> {{VALUETYPE}}? " + "{ \\"; + code_ += GenOffset() + + "return o == 0 ? nil : {{VALUETYPE}}.lookupByKey(vector: " + "{{ACCESS}}.vector(at: o), key: key, fbb: {{ACCESS}}.bb) }"; + } + + void GenEnum(const EnumDef &enum_def) { + if (enum_def.generated) return; + auto is_private_access = enum_def.attributes.Lookup("private"); + code_.SetValue("ACCESS_TYPE", is_private_access ? "internal" : "public"); + code_.SetValue("ENUM_NAME", NameWrappedInNameSpace(enum_def)); + code_.SetValue("BASE_TYPE", GenTypeBasic(enum_def.underlying_type, false)); + GenComment(enum_def.doc_comment); + code_ += "{{ACCESS_TYPE}} enum {{ENUM_NAME}}: {{BASE_TYPE}}, Enum {"; + Indent(); + code_ += "{{ACCESS_TYPE}} typealias T = {{BASE_TYPE}}"; + code_ += + "{{ACCESS_TYPE}} static var byteSize: Int { return " + "MemoryLayout<{{BASE_TYPE}}>.size " + "}"; + code_ += + "{{ACCESS_TYPE}} var value: {{BASE_TYPE}} { return self.rawValue }"; + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + const auto &ev = **it; + auto name = Name(ev); + code_.SetValue("KEY", name); + code_.SetValue("VALUE", enum_def.ToString(ev)); + GenComment(ev.doc_comment); + code_ += "case {{KEY}} = {{VALUE}}"; + } + code_ += "\n"; + AddMinOrMaxEnumValue(Name(*enum_def.MaxValue()), "max"); + AddMinOrMaxEnumValue(Name(*enum_def.MinValue()), "min"); + Outdent(); + code_ += "}\n"; + if (parser_.opts.generate_object_based_api && enum_def.is_union) { + code_ += "{{ACCESS_TYPE}} struct {{ENUM_NAME}}Union {"; + Indent(); + code_ += "{{ACCESS_TYPE}} var type: {{ENUM_NAME}}"; + code_ += "{{ACCESS_TYPE}} var value: NativeObject?"; + code_ += + "{{ACCESS_TYPE}} init(_ v: NativeObject?, type: {{ENUM_NAME}}) {"; + Indent(); + code_ += "self.type = type"; + code_ += "self.value = v"; + Outdent(); + code_ += "}"; + code_ += + "{{ACCESS_TYPE}} func pack(builder: inout FlatBufferBuilder) -> " + "Offset {"; + Indent(); + BuildUnionEnumSwitchCaseWritter(enum_def); + Outdent(); + code_ += "}"; + Outdent(); + code_ += "}"; + } + } + + // MARK: - Object API + + void GenerateObjectAPIExtensionHeader(std::string name) { + code_ += "\n"; + code_ += "{{ACCESS_TYPE}} mutating func unpack() -> " + name + " {"; + Indent(); + code_ += "return " + name + "(&self)"; + Outdent(); + code_ += "}"; + code_ += + "{{ACCESS_TYPE}} static func pack(_ builder: inout FlatBufferBuilder, " + "obj: " + "inout " + + name + "?) -> Offset {"; + Indent(); + code_ += "guard var obj = obj else { return Offset() }"; + code_ += "return pack(&builder, obj: &obj)"; + Outdent(); + code_ += "}"; + code_ += ""; + code_ += + "{{ACCESS_TYPE}} static func pack(_ builder: inout FlatBufferBuilder, " + "obj: " + "inout " + + name + ") -> Offset {"; + Indent(); + } + + void GenerateObjectAPIStructConstructor(const StructDef &struct_def) { + code_ += + "{{ACCESS_TYPE}} init(_ _t: inout {{STRUCTNAME}}" + Mutable() + ") {"; + Indent(); + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + + auto name = Name(field); + auto type = GenType(field.value.type); + code_.SetValue("VALUENAME", name); + if (IsStruct(field.value.type)) { + code_ += "var _v{{VALUENAME}} = _t.{{VALUENAME}}"; + code_ += "_{{VALUENAME}} = _v{{VALUENAME}}.unpack()"; + continue; + } + std::string is_enum = IsEnum(field.value.type) ? ".value" : ""; + code_ += "_{{VALUENAME}} = _t.{{VALUENAME}}" + is_enum; + } + Outdent(); + code_ += "}\n"; + } + + void GenObjectAPI(const StructDef &struct_def) { + code_ += "{{ACCESS_TYPE}} class " + ObjectAPIName("{{STRUCTNAME}}") + + ": NativeObject {\n"; + std::vector<std::string> buffer_constructor; + std::vector<std::string> base_constructor; + Indent(); + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + BuildObjectAPIConstructorBody(field, struct_def.fixed, buffer_constructor, + base_constructor); + } + code_ += ""; + BuildObjectConstructor(buffer_constructor, + "_ _t: inout " + NameWrappedInNameSpace(struct_def)); + BuildObjectConstructor(base_constructor); + if (!struct_def.fixed) + code_ += + "{{ACCESS_TYPE}} func serialize() -> ByteBuffer { return " + "serialize(type: " + "{{STRUCTNAME}}.self) }\n"; + Outdent(); + code_ += "}"; + } + + void GenerateObjectAPITableExtension(const StructDef &struct_def) { + GenerateObjectAPIExtensionHeader(ObjectAPIName("{{STRUCTNAME}}")); + std::vector<std::string> unpack_body; + std::string builder = ", &builder)"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + auto name = Name(field); + auto type = GenType(field.value.type); + std::string check_if_vector = + (IsVector(field.value.type) || IsArray(field.value.type)) + ? "VectorOf(" + : "("; + std::string body = "add" + check_if_vector + name + ": "; + switch (field.value.type.base_type) { + case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); + case BASE_TYPE_VECTOR: { + GenerateVectorObjectAPITableExtension(field, name, type); + unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + name + + builder); + break; + } + case BASE_TYPE_UNION: { + code_ += "let __" + name + " = obj." + name + + "?.pack(builder: &builder) ?? Offset()"; + unpack_body.push_back("if let o = obj." + name + "?.type {"); + unpack_body.push_back(" {{STRUCTNAME}}.add(" + name + "Type: o" + + builder); + unpack_body.push_back(" {{STRUCTNAME}}." + body + "__" + name + + builder); + unpack_body.push_back("}\n"); + break; + } + case BASE_TYPE_STRUCT: { + if (field.value.type.struct_def && + field.value.type.struct_def->fixed) { + // This is a Struct (IsStruct), not a table. We create + // a native swift object in this case. + std::string code; + GenerateStructArgs(*field.value.type.struct_def, &code, "", "", + "$0", true); + code = code.substr(0, code.size() - 2); + unpack_body.push_back("{{STRUCTNAME}}." + body + "obj." + name + + builder); + } else { + code_ += "let __" + name + " = " + type + + ".pack(&builder, obj: &obj." + name + ")"; + unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + name + + builder); + } + break; + } + case BASE_TYPE_STRING: { + unpack_body.push_back("{{STRUCTNAME}}." + body + "__" + name + + builder); + if (field.IsRequired()) { + code_ += + "let __" + name + " = builder.create(string: obj." + name + ")"; + } else { + BuildingOptionalObjects(name, "builder.create(string: s)"); + } + break; + } + case BASE_TYPE_UTYPE: break; + default: + unpack_body.push_back("{{STRUCTNAME}}." + body + "obj." + name + + builder); + } + } + code_ += "let __root = {{STRUCTNAME}}.start{{SHORT_STRUCTNAME}}(&builder)"; + for (auto it = unpack_body.begin(); it < unpack_body.end(); it++) + code_ += *it; + code_ += + "return {{STRUCTNAME}}.end{{SHORT_STRUCTNAME}}(&builder, start: " + "__root)"; + Outdent(); + code_ += "}"; + } + + void GenerateVectorObjectAPITableExtension(const FieldDef &field, + const std::string &name, + const std::string &type) { + auto vectortype = field.value.type.VectorType(); + switch (vectortype.base_type) { + case BASE_TYPE_UNION: { + code_ += "var __" + name + "__: [Offset] = []"; + code_ += "for i in obj." + name + " {"; + Indent(); + code_ += "guard let off = i?.pack(builder: &builder) else { continue }"; + code_ += "__" + name + "__.append(off)"; + Outdent(); + code_ += "}"; + code_ += "let __" + name + " = builder.createVector(ofOffsets: __" + + name + "__)"; + code_ += "let __" + name + "Type = builder.createVector(obj." + name + + ".compactMap { $0?.type })"; + break; + } + case BASE_TYPE_UTYPE: break; + case BASE_TYPE_STRUCT: { + if (field.value.type.struct_def && + !field.value.type.struct_def->fixed) { + code_ += "var __" + name + "__: [Offset] = []"; + code_ += "for var i in obj." + name + " {"; + Indent(); + code_ += + "__" + name + "__.append(" + type + ".pack(&builder, obj: &i))"; + Outdent(); + code_ += "}"; + code_ += "let __" + name + " = builder.createVector(ofOffsets: __" + + name + "__)"; + } else { + code_ += "{{STRUCTNAME}}.startVectorOf" + MakeCamel(name, true) + + "(obj." + name + ".count, in: &builder)"; + std::string code; + GenerateStructArgs(*field.value.type.struct_def, &code, "", "", "_o", + true); + code = code.substr(0, code.size() - 2); + code_ += "for i in obj." + name + " {"; + Indent(); + code_ += "guard let _o = i else { continue }"; + code_ += "builder.create(struct: _o)"; + Outdent(); + code_ += "}"; + code_ += "let __" + name + " = builder.endVector(len: obj." + name + + ".count)"; + } + break; + } + case BASE_TYPE_STRING: { + code_ += "let __" + name + " = builder.createVector(ofStrings: obj." + + name + ".compactMap({ $0 }) )"; + break; + } + default: { + code_ += "let __" + name + " = builder.createVector(obj." + name + ")"; + break; + } + } + } + + void BuildingOptionalObjects(const std::string &name, + const std::string &body_front) { + code_ += "let __" + name + ": Offset"; + code_ += "if let s = obj." + name + " {"; + Indent(); + code_ += "__" + name + " = " + body_front; + Outdent(); + code_ += "} else {"; + Indent(); + code_ += "__" + name + " = Offset()"; + Outdent(); + code_ += "}"; + code_ += ""; + } + + void BuildObjectConstructor(const std::vector<std::string> &body, + const std::string &header = "") { + code_.SetValue("HEADER", header); + code_ += "{{ACCESS_TYPE}} init({{HEADER}}) {"; + Indent(); + for (auto it = body.begin(); it < body.end(); ++it) code_ += *it; + Outdent(); + code_ += "}\n"; + } + + void BuildObjectAPIConstructorBody( + const FieldDef &field, bool is_fixed, + std::vector<std::string> &buffer_constructor, + std::vector<std::string> &base_constructor) { + auto name = Name(field); + auto type = GenType(field.value.type); + code_.SetValue("VALUENAME", name); + code_.SetValue("VALUETYPE", type); + std::string is_required = field.IsRequired() ? "" : "?"; + + switch (field.value.type.base_type) { + case BASE_TYPE_STRUCT: { + type = GenType(field.value.type, true); + code_.SetValue("VALUETYPE", type); + auto optional = + (field.value.type.struct_def && field.value.type.struct_def->fixed); + std::string question_mark = + (field.IsRequired() || (optional && is_fixed) ? "" : "?"); + + code_ += + "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}" + question_mark; + base_constructor.push_back("" + name + " = " + type + "()"); + + if (field.value.type.struct_def->fixed) { + buffer_constructor.push_back("" + name + " = _t." + name); + } else { + buffer_constructor.push_back("var __" + name + " = _t." + name); + buffer_constructor.push_back( + "" + name + " = __" + name + + (field.IsRequired() ? "!" : question_mark) + ".unpack()"); + } + break; + } + case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); + case BASE_TYPE_VECTOR: { + BuildObjectAPIConstructorBodyVectors(field, name, buffer_constructor, + base_constructor, " "); + break; + } + case BASE_TYPE_STRING: { + code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: String" + is_required; + buffer_constructor.push_back(name + " = _t." + name); + + if (field.IsRequired()) { + std::string default_value = + field.IsDefault() ? field.value.constant : ""; + base_constructor.push_back(name + " = \"" + default_value + "\""); + break; + } + if (field.IsDefault() && !field.IsRequired()) { + std::string value = field.IsDefault() ? field.value.constant : "nil"; + base_constructor.push_back(name + " = \"" + value + "\""); + } + break; + } + case BASE_TYPE_UTYPE: break; + case BASE_TYPE_UNION: { + BuildUnionEnumSwitchCase(*field.value.type.enum_def, name, + buffer_constructor); + break; + } + default: { + buffer_constructor.push_back(name + " = _t." + name); + std::string nullable = field.IsOptional() ? "?" : ""; + if (IsScalar(field.value.type.base_type) && + !IsBool(field.value.type.base_type) && !IsEnum(field.value.type)) { + code_ += + "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}" + nullable; + if (!field.IsOptional()) + base_constructor.push_back(name + " = " + field.value.constant); + break; + } + + if (IsEnum(field.value.type)) { + auto default_value = IsEnum(field.value.type) + ? GenEnumDefaultValue(field) + : field.value.constant; + code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}"; + base_constructor.push_back(name + " = " + default_value); + break; + } + + if (IsBool(field.value.type.base_type)) { + code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: Bool" + nullable; + std::string default_value = + "0" == field.value.constant ? "false" : "true"; + if (!field.IsOptional()) + base_constructor.push_back(name + " = " + default_value); + } + } + } + } + + void BuildObjectAPIConstructorBodyVectors( + const FieldDef &field, const std::string &name, + std::vector<std::string> &buffer_constructor, + std::vector<std::string> &base_constructor, + const std::string &indentation) { + auto vectortype = field.value.type.VectorType(); + + if (vectortype.base_type != BASE_TYPE_UTYPE) { + buffer_constructor.push_back(name + " = []"); + buffer_constructor.push_back("for index in 0..<_t." + name + "Count {"); + base_constructor.push_back(name + " = []"); + } + + switch (vectortype.base_type) { + case BASE_TYPE_STRUCT: { + code_.SetValue("VALUETYPE", GenType(vectortype, true)); + code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: [{{VALUETYPE}}?]"; + if (!vectortype.struct_def->fixed) { + buffer_constructor.push_back(indentation + "var __v_ = _t." + name + + "(at: index)"); + buffer_constructor.push_back(indentation + name + + ".append(__v_?.unpack())"); + } else { + buffer_constructor.push_back(indentation + name + ".append(_t." + + name + "(at: index))"); + } + break; + } + case BASE_TYPE_ARRAY: FLATBUFFERS_FALLTHROUGH(); + case BASE_TYPE_VECTOR: { + break; + } + case BASE_TYPE_UNION: { + BuildUnionEnumSwitchCase(*field.value.type.enum_def, name, + buffer_constructor, indentation, true); + break; + } + case BASE_TYPE_UTYPE: break; + default: { + code_.SetValue( + "VALUETYPE", + (IsString(vectortype) ? "String?" : GenType(vectortype))); + code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: [{{VALUETYPE}}]"; + + if (IsEnum(vectortype) && vectortype.base_type != BASE_TYPE_UNION) { + auto default_value = IsEnum(field.value.type) + ? GenEnumDefaultValue(field) + : field.value.constant; + buffer_constructor.push_back(indentation + name + ".append(_t." + + name + "(at: index)!)"); + break; + } + buffer_constructor.push_back(indentation + name + ".append(_t." + name + + "(at: index))"); + break; + } + } + if (vectortype.base_type != BASE_TYPE_UTYPE) + buffer_constructor.push_back("}"); + } + + void BuildUnionEnumSwitchCaseWritter(const EnumDef &ev) { + auto field_name = Name(ev); + code_.SetValue("VALUETYPE", field_name); + code_ += "switch type {"; + for (auto it = ev.Vals().begin(); it < ev.Vals().end(); ++it) { + auto field = **it; + auto ev_name = Name(field); + auto type = GenType(field.union_type); + auto is_struct = IsStruct(field.union_type) ? type + Mutable() : type; + if (field.union_type.base_type == BASE_TYPE_NONE) { continue; } + code_ += "case ." + ev_name + ":"; + Indent(); + code_ += "var __obj = value as? " + GenType(field.union_type, true); + code_ += "return " + is_struct + ".pack(&builder, obj: &__obj)"; + Outdent(); + } + code_ += "default: return Offset()"; + code_ += "}"; + } + + void BuildUnionEnumSwitchCase(const EnumDef &ev, const std::string &name, + std::vector<std::string> &buffer_constructor, + const std::string &indentation = "", + const bool is_vector = false) { + auto field_name = NameWrappedInNameSpace(ev); + code_.SetValue("VALUETYPE", field_name); + code_ += "{{ACCESS_TYPE}} var {{VALUENAME}}: \\"; + code_ += is_vector ? "[{{VALUETYPE}}Union?]" : "{{VALUETYPE}}Union?"; + + auto vector_reader = is_vector ? "(at: index" : ""; + buffer_constructor.push_back(indentation + "switch _t." + name + "Type" + + vector_reader + (is_vector ? ")" : "") + " {"); + + for (auto it = ev.Vals().begin(); it < ev.Vals().end(); ++it) { + auto field = **it; + auto ev_name = Name(field); + if (field.union_type.base_type == BASE_TYPE_NONE) { continue; } + auto type = IsStruct(field.union_type) + ? GenType(field.union_type) + Mutable() + : GenType(field.union_type); + buffer_constructor.push_back(indentation + "case ." + ev_name + ":"); + buffer_constructor.push_back( + indentation + " var _v = _t." + name + (is_vector ? "" : "(") + + vector_reader + (is_vector ? ", " : "") + "type: " + type + ".self)"); + auto constructor = + field_name + "Union(_v?.unpack(), type: ." + ev_name + ")"; + buffer_constructor.push_back( + indentation + " " + name + + (is_vector ? ".append(" + constructor + ")" : " = " + constructor)); + } + buffer_constructor.push_back(indentation + "default: break"); + buffer_constructor.push_back(indentation + "}"); + } + + void AddMinOrMaxEnumValue(const std::string &str, const std::string &type) { + auto current_value = str; + code_.SetValue(type, current_value); + code_ += "{{ACCESS_TYPE}} static var " + type + + ": {{ENUM_NAME}} { return .{{" + type + "}} }"; + } + + void GenLookup(const FieldDef &key_field) { + code_.SetValue("OFFSET", NumToString(key_field.value.offset)); + std::string offset_reader = + "Table.offset(Int32(fbb.capacity) - tableOffset, vOffset: {{OFFSET}}, " + "fbb: fbb)"; + + code_.SetValue("TYPE", GenType(key_field.value.type)); + code_ += + "fileprivate static func lookupByKey(vector: Int32, key: {{TYPE}}, " + "fbb: " + "ByteBuffer) -> {{VALUENAME}}? {"; + Indent(); + if (IsString(key_field.value.type)) + code_ += "let key = key.utf8.map { $0 }"; + code_ += "var span = fbb.read(def: Int32.self, position: Int(vector - 4))"; + code_ += "var start: Int32 = 0"; + code_ += "while span != 0 {"; + Indent(); + code_ += "var middle = span / 2"; + code_ += + "let tableOffset = Table.indirect(vector + 4 * (start + middle), fbb)"; + if (IsString(key_field.value.type)) { + code_ += "let comp = Table.compare(" + offset_reader + ", key, fbb: fbb)"; + } else { + code_ += "let comp = fbb.read(def: {{TYPE}}.self, position: Int(" + + offset_reader + "))"; + } + + code_ += "if comp > 0 {"; + Indent(); + code_ += "span = middle"; + Outdent(); + code_ += "} else if comp < 0 {"; + Indent(); + code_ += "middle += 1"; + code_ += "start += middle"; + code_ += "span -= middle"; + Outdent(); + code_ += "} else {"; + Indent(); + code_ += "return {{VALUENAME}}(fbb, o: tableOffset)"; + Outdent(); + code_ += "}"; + Outdent(); + code_ += "}"; + code_ += "return nil"; + Outdent(); + code_ += "}"; + } + + inline void GenPadding(const FieldDef &field, int *id) { + if (field.padding) { + for (int i = 0; i < 4; i++) { + if (static_cast<int>(field.padding) & (1 << i)) { + auto bits = (1 << i) * 8; + code_ += "private let padding" + NumToString((*id)++) + "__: UInt" + + NumToString(bits) + " = 0"; + } + } + FLATBUFFERS_ASSERT(!(field.padding & ~0xF)); + } + } + + void GenComment(const std::vector<std::string> &dc) { + if (dc.begin() == dc.end()) { + // Don't output empty comment blocks with 0 lines of comment content. + return; + } + for (auto it = dc.begin(); it != dc.end(); ++it) { code_ += "/// " + *it; } + } + + std::string GenOffset() { + return "let o = {{ACCESS}}.offset({{TABLEOFFSET}}.{{OFFSET}}.v); "; + } + + std::string GenReaderMainBody(const std::string &optional = "") { + return "{{ACCESS_TYPE}} var {{VALUENAME}}: {{VALUETYPE}}" + optional + + " { "; + } + + std::string GenReader(const std::string &type, + const std::string &at = "{{OFFSET}}") { + return "{{ACCESS}}.readBuffer(of: {{" + type + "}}.self, at: " + at + ")"; + } + + std::string GenConstructor(const std::string &offset) { + return "{{VALUETYPE}}({{ACCESS}}.bb, o: " + offset + ") }"; + } + + std::string GenMutate(const std::string &offset, + const std::string &get_offset, bool isRaw = false) { + return "@discardableResult {{ACCESS_TYPE}} func mutate({{VALUENAME}}: " + "{{VALUETYPE}}) -> Bool {" + + get_offset + " return {{ACCESS}}.mutate({{VALUENAME}}" + + (isRaw ? ".rawValue" : "") + ", index: " + offset + ") }"; + } + + std::string GenMutateArray() { + return "{{ACCESS_TYPE}} func mutate({{VALUENAME}}: {{VALUETYPE}}, at " + "index: " + "Int32) -> Bool { " + + GenOffset() + + "return {{ACCESS}}.directMutate({{VALUENAME}}, index: " + "{{ACCESS}}.vector(at: o) + index * {{SIZE}}) }"; + } + + std::string GenEnumDefaultValue(const FieldDef &field) { + auto &value = field.value; + FLATBUFFERS_ASSERT(value.type.enum_def); + auto &enum_def = *value.type.enum_def; + // Vector of enum defaults are always "[]" which never works. + const std::string constant = IsVector(value.type) ? "0" : value.constant; + auto enum_val = enum_def.FindByValue(constant); + std::string name; + if (enum_val) { + name = Name(*enum_val); + } else { + const auto &ev = **enum_def.Vals().begin(); + name = Name(ev); + } + return "." + name; + } + + std::string GenEnumConstructor(const std::string &at) { + return "{{VALUETYPE}}(rawValue: " + GenReader("BASEVALUE", at) + ") "; + } + + std::string ValidateFunc() { + return "static func validateVersion() { FlatBuffersVersion_2_0_0() }"; + } + + std::string GenType(const Type &type, + const bool should_consider_suffix = false) const { + return IsScalar(type.base_type) + ? GenTypeBasic(type) + : (IsArray(type) ? GenType(type.VectorType()) + : GenTypePointer(type, should_consider_suffix)); + } + + std::string GenTypePointer(const Type &type, + const bool should_consider_suffix) const { + switch (type.base_type) { + case BASE_TYPE_STRING: return "String"; + case BASE_TYPE_VECTOR: return GenType(type.VectorType()); + case BASE_TYPE_STRUCT: { + auto &struct_ = *type.struct_def; + if (should_consider_suffix && !struct_.fixed) { + return WrapInNameSpace(struct_.defined_namespace, + ObjectAPIName(Name(struct_))); + } + return WrapInNameSpace(struct_.defined_namespace, Name(struct_)); + } + case BASE_TYPE_UNION: + default: return "FlatbuffersInitializable"; + } + } + + std::string GenTypeBasic(const Type &type) const { + return GenTypeBasic(type, true); + } + + std::string ObjectAPIName(const std::string &name) const { + return parser_.opts.object_prefix + name + parser_.opts.object_suffix; + } + + void Indent() { code_.IncrementIdentLevel(); } + + void Outdent() { code_.DecrementIdentLevel(); } + + std::string NameWrappedInNameSpace(const EnumDef &enum_def) const { + return WrapInNameSpace(enum_def.defined_namespace, Name(enum_def)); + } + + std::string NameWrappedInNameSpace(const StructDef &struct_def) const { + return WrapInNameSpace(struct_def.defined_namespace, Name(struct_def)); + } + + std::string GenTypeBasic(const Type &type, bool can_override) const { + // clang-format off + static const char * const swift_type[] = { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, \ + CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE, STYPE) \ + #STYPE, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + }; + // clang-format on + if (can_override) { + if (type.enum_def) return NameWrappedInNameSpace(*type.enum_def); + if (type.base_type == BASE_TYPE_BOOL) return "Bool"; + } + return swift_type[static_cast<int>(type.base_type)]; + } + + std::string EscapeKeyword(const std::string &name) const { + return keywords_.find(name) == keywords_.end() ? name : name + "_"; + } + + std::string Mutable() const { return "_Mutable"; } + + std::string Name(const EnumVal &ev) const { + auto name = ev.name; + if (isupper(name.front())) { + std::transform(name.begin(), name.end(), name.begin(), CharToLower); + } + return EscapeKeyword(MakeCamel(name, false)); + } + + std::string Name(const Definition &def) const { + return EscapeKeyword(MakeCamel(def.name, false)); + } +}; +} // namespace swift +bool GenerateSwift(const Parser &parser, const std::string &path, + const std::string &file_name) { + swift::SwiftGenerator generator(parser, path, file_name); + return generator.generate(); +} +} // namespace flatbuffers diff --git a/contrib/libs/flatbuffers/src/idl_gen_text.cpp b/contrib/libs/flatbuffers/src/idl_gen_text.cpp new file mode 100644 index 0000000000..903c41ecdb --- /dev/null +++ b/contrib/libs/flatbuffers/src/idl_gen_text.cpp @@ -0,0 +1,414 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// independent from idl_parser, since this code is not needed for most clients + +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/flexbuffers.h" +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +namespace flatbuffers { + +struct PrintScalarTag {}; +struct PrintPointerTag {}; +template<typename T> struct PrintTag { typedef PrintScalarTag type; }; +template<> struct PrintTag<const void *> { typedef PrintPointerTag type; }; + +struct JsonPrinter { + // If indentation is less than 0, that indicates we don't want any newlines + // either. + void AddNewLine() { + if (opts.indent_step >= 0) text += '\n'; + } + + void AddIndent(int ident) { text.append(ident, ' '); } + + int Indent() const { return std::max(opts.indent_step, 0); } + + // Output an identifier with or without quotes depending on strictness. + void OutputIdentifier(const std::string &name) { + if (opts.strict_json) text += '\"'; + text += name; + if (opts.strict_json) text += '\"'; + } + + // Print (and its template specialization below for pointers) generate text + // for a single FlatBuffer value into JSON format. + // The general case for scalars: + template<typename T> + bool PrintScalar(T val, const Type &type, int /*indent*/) { + if (IsBool(type.base_type)) { + text += val != 0 ? "true" : "false"; + return true; // done + } + + if (opts.output_enum_identifiers && type.enum_def) { + const auto &enum_def = *type.enum_def; + if (auto ev = enum_def.ReverseLookup(static_cast<int64_t>(val))) { + text += '\"'; + text += ev->name; + text += '\"'; + return true; // done + } else if (val && enum_def.attributes.Lookup("bit_flags")) { + const auto entry_len = text.length(); + const auto u64 = static_cast<uint64_t>(val); + uint64_t mask = 0; + text += '\"'; + for (auto it = enum_def.Vals().begin(), e = enum_def.Vals().end(); + it != e; ++it) { + auto f = (*it)->GetAsUInt64(); + if (f & u64) { + mask |= f; + text += (*it)->name; + text += ' '; + } + } + // Don't slice if (u64 != mask) + if (mask && (u64 == mask)) { + text[text.length() - 1] = '\"'; + return true; // done + } + text.resize(entry_len); // restore + } + // print as numeric value + } + + text += NumToString(val); + return true; + } + + void AddComma() { + if (!opts.protobuf_ascii_alike) text += ','; + } + + // Print a vector or an array of JSON values, comma seperated, wrapped in + // "[]". + template<typename Container> + bool PrintContainer(PrintScalarTag, const Container &c, size_t size, + const Type &type, int indent, const uint8_t *) { + const auto elem_indent = indent + Indent(); + text += '['; + AddNewLine(); + for (uoffset_t i = 0; i < size; i++) { + if (i) { + AddComma(); + AddNewLine(); + } + AddIndent(elem_indent); + if (!PrintScalar(c[i], type, elem_indent)) { return false; } + } + AddNewLine(); + AddIndent(indent); + text += ']'; + return true; + } + + // Print a vector or an array of JSON values, comma seperated, wrapped in + // "[]". + template<typename Container> + bool PrintContainer(PrintPointerTag, const Container &c, size_t size, + const Type &type, int indent, const uint8_t *prev_val) { + const auto is_struct = IsStruct(type); + const auto elem_indent = indent + Indent(); + text += '['; + AddNewLine(); + for (uoffset_t i = 0; i < size; i++) { + if (i) { + AddComma(); + AddNewLine(); + } + AddIndent(elem_indent); + auto ptr = is_struct ? reinterpret_cast<const void *>( + c.Data() + type.struct_def->bytesize * i) + : c[i]; + if (!PrintOffset(ptr, type, elem_indent, prev_val, + static_cast<soffset_t>(i))) { + return false; + } + } + AddNewLine(); + AddIndent(indent); + text += ']'; + return true; + } + + template<typename T> + bool PrintVector(const void *val, const Type &type, int indent, + const uint8_t *prev_val) { + typedef Vector<T> Container; + typedef typename PrintTag<typename Container::return_type>::type tag; + auto &vec = *reinterpret_cast<const Container *>(val); + return PrintContainer<Container>(tag(), vec, vec.size(), type, indent, + prev_val); + } + + // Print an array a sequence of JSON values, comma separated, wrapped in "[]". + template<typename T> + bool PrintArray(const void *val, size_t size, const Type &type, int indent) { + typedef Array<T, 0xFFFF> Container; + typedef typename PrintTag<typename Container::return_type>::type tag; + auto &arr = *reinterpret_cast<const Container *>(val); + return PrintContainer<Container>(tag(), arr, size, type, indent, nullptr); + } + + bool PrintOffset(const void *val, const Type &type, int indent, + const uint8_t *prev_val, soffset_t vector_index) { + switch (type.base_type) { + case BASE_TYPE_UNION: { + // If this assert hits, you have an corrupt buffer, a union type field + // was not present or was out of range. + FLATBUFFERS_ASSERT(prev_val); + auto union_type_byte = *prev_val; // Always a uint8_t. + if (vector_index >= 0) { + auto type_vec = reinterpret_cast<const Vector<uint8_t> *>( + prev_val + ReadScalar<uoffset_t>(prev_val)); + union_type_byte = type_vec->Get(static_cast<uoffset_t>(vector_index)); + } + auto enum_val = type.enum_def->ReverseLookup(union_type_byte, true); + if (enum_val) { + return PrintOffset(val, enum_val->union_type, indent, nullptr, -1); + } else { + return false; + } + } + case BASE_TYPE_STRUCT: + return GenStruct(*type.struct_def, reinterpret_cast<const Table *>(val), + indent); + case BASE_TYPE_STRING: { + auto s = reinterpret_cast<const String *>(val); + return EscapeString(s->c_str(), s->size(), &text, opts.allow_non_utf8, + opts.natural_utf8); + } + case BASE_TYPE_VECTOR: { + const auto vec_type = type.VectorType(); + // Call PrintVector above specifically for each element type: + // clang-format off + switch (vec_type.base_type) { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ + case BASE_TYPE_ ## ENUM: \ + if (!PrintVector<CTYPE>( \ + val, vec_type, indent, prev_val)) { \ + return false; \ + } \ + break; + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + } + // clang-format on + return true; + } + case BASE_TYPE_ARRAY: { + const auto vec_type = type.VectorType(); + // Call PrintArray above specifically for each element type: + // clang-format off + switch (vec_type.base_type) { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ + case BASE_TYPE_ ## ENUM: \ + if (!PrintArray<CTYPE>( \ + val, type.fixed_length, vec_type, indent)) { \ + return false; \ + } \ + break; + FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD) + // Arrays of scalars or structs are only possible. + FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + case BASE_TYPE_ARRAY: FLATBUFFERS_ASSERT(0); + } + // clang-format on + return true; + } + default: FLATBUFFERS_ASSERT(0); return false; + } + } + + template<typename T> static T GetFieldDefault(const FieldDef &fd) { + T val; + auto check = StringToNumber(fd.value.constant.c_str(), &val); + (void)check; + FLATBUFFERS_ASSERT(check); + return val; + } + + // Generate text for a scalar field. + template<typename T> + bool GenField(const FieldDef &fd, const Table *table, bool fixed, + int indent) { + return PrintScalar( + fixed ? reinterpret_cast<const Struct *>(table)->GetField<T>( + fd.value.offset) + : table->GetField<T>(fd.value.offset, GetFieldDefault<T>(fd)), + fd.value.type, indent); + } + + // Generate text for non-scalar field. + bool GenFieldOffset(const FieldDef &fd, const Table *table, bool fixed, + int indent, const uint8_t *prev_val) { + const void *val = nullptr; + if (fixed) { + // The only non-scalar fields in structs are structs or arrays. + FLATBUFFERS_ASSERT(IsStruct(fd.value.type) || IsArray(fd.value.type)); + val = reinterpret_cast<const Struct *>(table)->GetStruct<const void *>( + fd.value.offset); + } else if (fd.flexbuffer) { + auto vec = table->GetPointer<const Vector<uint8_t> *>(fd.value.offset); + auto root = flexbuffers::GetRoot(vec->data(), vec->size()); + root.ToString(true, opts.strict_json, text); + return true; + } else if (fd.nested_flatbuffer) { + auto vec = table->GetPointer<const Vector<uint8_t> *>(fd.value.offset); + auto root = GetRoot<Table>(vec->data()); + return GenStruct(*fd.nested_flatbuffer, root, indent); + } else { + val = IsStruct(fd.value.type) + ? table->GetStruct<const void *>(fd.value.offset) + : table->GetPointer<const void *>(fd.value.offset); + } + return PrintOffset(val, fd.value.type, indent, prev_val, -1); + } + + // Generate text for a struct or table, values separated by commas, indented, + // and bracketed by "{}" + bool GenStruct(const StructDef &struct_def, const Table *table, int indent) { + text += '{'; + int fieldout = 0; + const uint8_t *prev_val = nullptr; + const auto elem_indent = indent + Indent(); + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + FieldDef &fd = **it; + auto is_present = struct_def.fixed || table->CheckField(fd.value.offset); + auto output_anyway = (opts.output_default_scalars_in_json || fd.key) && + IsScalar(fd.value.type.base_type) && !fd.deprecated; + if (is_present || output_anyway) { + if (fieldout++) { AddComma(); } + AddNewLine(); + AddIndent(elem_indent); + OutputIdentifier(fd.name); + if (!opts.protobuf_ascii_alike || + (fd.value.type.base_type != BASE_TYPE_STRUCT && + fd.value.type.base_type != BASE_TYPE_VECTOR)) + text += ':'; + text += ' '; + // clang-format off + switch (fd.value.type.base_type) { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ + case BASE_TYPE_ ## ENUM: \ + if (!GenField<CTYPE>(fd, table, struct_def.fixed, elem_indent)) { \ + return false; \ + } \ + break; + FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + // Generate drop-thru case statements for all pointer types: + #define FLATBUFFERS_TD(ENUM, ...) \ + case BASE_TYPE_ ## ENUM: + FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD) + FLATBUFFERS_GEN_TYPE_ARRAY(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + if (!GenFieldOffset(fd, table, struct_def.fixed, elem_indent, prev_val)) { + return false; + } + break; + } + // clang-format on + // Track prev val for use with union types. + if (struct_def.fixed) { + prev_val = reinterpret_cast<const uint8_t *>(table) + fd.value.offset; + } else { + prev_val = table->GetAddressOf(fd.value.offset); + } + } + } + AddNewLine(); + AddIndent(indent); + text += '}'; + return true; + } + + JsonPrinter(const Parser &parser, std::string &dest) + : opts(parser.opts), text(dest) { + text.reserve(1024); // Reduce amount of inevitable reallocs. + } + + const IDLOptions &opts; + std::string &text; +}; + +static bool GenerateTextImpl(const Parser &parser, const Table *table, + const StructDef &struct_def, std::string *_text) { + JsonPrinter printer(parser, *_text); + if (!printer.GenStruct(struct_def, table, 0)) { return false; } + printer.AddNewLine(); + return true; +} + +// Generate a text representation of a flatbuffer in JSON format. +bool GenerateTextFromTable(const Parser &parser, const void *table, + const std::string &table_name, std::string *_text) { + auto struct_def = parser.LookupStruct(table_name); + if (struct_def == nullptr) { return false; } + auto root = static_cast<const Table *>(table); + return GenerateTextImpl(parser, root, *struct_def, _text); +} + +// Generate a text representation of a flatbuffer in JSON format. +bool GenerateText(const Parser &parser, const void *flatbuffer, + std::string *_text) { + FLATBUFFERS_ASSERT(parser.root_struct_def_); // call SetRootType() + auto root = parser.opts.size_prefixed ? GetSizePrefixedRoot<Table>(flatbuffer) + : GetRoot<Table>(flatbuffer); + return GenerateTextImpl(parser, root, *parser.root_struct_def_, _text); +} + +static std::string TextFileName(const std::string &path, + const std::string &file_name) { + return path + file_name + ".json"; +} + +bool GenerateTextFile(const Parser &parser, const std::string &path, + const std::string &file_name) { + if (parser.opts.use_flexbuffers) { + std::string json; + parser.flex_root_.ToString(true, parser.opts.strict_json, json); + return flatbuffers::SaveFile(TextFileName(path, file_name).c_str(), + json.c_str(), json.size(), true); + } + if (!parser.builder_.GetSize() || !parser.root_struct_def_) return true; + std::string text; + if (!GenerateText(parser, parser.builder_.GetBufferPointer(), &text)) { + return false; + } + return flatbuffers::SaveFile(TextFileName(path, file_name).c_str(), text, + false); +} + +std::string TextMakeRule(const Parser &parser, const std::string &path, + const std::string &file_name) { + if (!parser.builder_.GetSize() || !parser.root_struct_def_) return ""; + std::string filebase = + flatbuffers::StripPath(flatbuffers::StripExtension(file_name)); + std::string make_rule = TextFileName(path, filebase) + ": " + file_name; + auto included_files = + parser.GetIncludedFilesRecursive(parser.root_struct_def_->file); + for (auto it = included_files.begin(); it != included_files.end(); ++it) { + make_rule += " " + *it; + } + return make_rule; +} + +} // namespace flatbuffers diff --git a/contrib/libs/flatbuffers/src/idl_gen_ts.cpp b/contrib/libs/flatbuffers/src/idl_gen_ts.cpp new file mode 100644 index 0000000000..53e088fe13 --- /dev/null +++ b/contrib/libs/flatbuffers/src/idl_gen_ts.cpp @@ -0,0 +1,1583 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// independent from idl_parser, since this code is not needed for most clients +#include <algorithm> +#include <cassert> +#include <unordered_map> +#include <unordered_set> + +#include "flatbuffers/code_generators.h" +#include "flatbuffers/flatbuffers.h" +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +namespace flatbuffers { + +struct ImportDefinition { + std::string name; + std::string statement; + const Definition *dependent; + const Definition *dependency; +}; + +enum AnnotationType { kParam = 0, kType = 1, kReturns = 2 }; + +namespace ts { +// Iterate through all definitions we haven't generate code for (enums, structs, +// and tables) and output them to a single file. +class TsGenerator : public BaseGenerator { + public: + typedef std::map<std::string, ImportDefinition> import_set; + + TsGenerator(const Parser &parser, const std::string &path, + const std::string &file_name) + : BaseGenerator(parser, path, file_name, "", ".", "ts") {} + bool generate() { + generateEnums(); + generateStructs(); + return true; + } + + // Save out the generated code for a single class while adding + // declaration boilerplate. + bool SaveType(const Definition &definition, const std::string &classcode, + import_set &imports, import_set &bare_imports) const { + if (!classcode.length()) return true; + + std::string code = + "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n"; + + for (auto it = bare_imports.begin(); it != bare_imports.end(); it++) + code += it->second.statement + "\n"; + if (!bare_imports.empty()) code += "\n"; + + for (auto it = imports.begin(); it != imports.end(); it++) + if (it->second.dependency != &definition) // do not import itself + code += it->second.statement + "\n"; + if (!imports.empty()) code += "\n\n"; + + code += classcode; + auto filename = NamespaceDir(*definition.defined_namespace, true) + + ToDasherizedCase(definition.name) + ".ts"; + return SaveFile(filename.c_str(), code, false); + } + + private: + // Generate code for all enums. + void generateEnums() { + for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end(); + ++it) { + import_set bare_imports; + import_set imports; + std::string enumcode; + auto &enum_def = **it; + GenEnum(enum_def, &enumcode, imports, false); + GenEnum(enum_def, &enumcode, imports, true); + SaveType(enum_def, enumcode, imports, bare_imports); + } + } + + // Generate code for all structs. + void generateStructs() { + for (auto it = parser_.structs_.vec.begin(); + it != parser_.structs_.vec.end(); ++it) { + import_set bare_imports; + import_set imports; + AddImport(bare_imports, "* as flatbuffers", "flatbuffers"); + auto &struct_def = **it; + std::string declcode; + GenStruct(parser_, struct_def, &declcode, imports); + SaveType(struct_def, declcode, imports, bare_imports); + } + } + + // Generate a documentation comment, if available. + static void GenDocComment(const std::vector<std::string> &dc, + std::string *code_ptr, + const char *indent = nullptr) { + if (dc.empty()) { + // Don't output empty comment blocks with 0 lines of comment content. + return; + } + + std::string &code = *code_ptr; + if (indent) code += indent; + code += "/**\n"; + for (auto it = dc.begin(); it != dc.end(); ++it) { + if (indent) code += indent; + code += " *" + *it + "\n"; + } + if (indent) code += indent; + code += " */\n"; + } + + static void GenDocComment(std::string *code_ptr) { + GenDocComment(std::vector<std::string>(), code_ptr); + } + + // Generate an enum declaration and an enum string lookup table. + void GenEnum(EnumDef &enum_def, std::string *code_ptr, import_set &imports, + bool reverse) { + if (enum_def.generated) return; + if (reverse) return; // FIXME. + std::string &code = *code_ptr; + GenDocComment(enum_def.doc_comment, code_ptr); + std::string ns = GetNameSpace(enum_def); + std::string enum_def_name = enum_def.name + (reverse ? "Name" : ""); + code += "export enum " + enum_def.name + "{\n"; + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) { + auto &ev = **it; + if (!ev.doc_comment.empty()) { + if (it != enum_def.Vals().begin()) { code += '\n'; } + GenDocComment(ev.doc_comment, code_ptr, " "); + } + + // Generate mapping between EnumName: EnumValue(int) + if (reverse) { + code += " '" + enum_def.ToString(ev) + "'"; + code += " = "; + code += "'" + ev.name + "'"; + } else { + code += " " + ev.name; + code += " = "; + code += enum_def.ToString(ev); + } + + code += (it + 1) != enum_def.Vals().end() ? ",\n" : "\n"; + } + code += "}"; + + if (enum_def.is_union) { + code += GenUnionConvFunc(enum_def.underlying_type, imports); + } + + code += "\n\n"; + } + + static std::string GenType(const Type &type) { + switch (type.base_type) { + case BASE_TYPE_BOOL: + case BASE_TYPE_CHAR: return "Int8"; + case BASE_TYPE_UTYPE: + case BASE_TYPE_UCHAR: return "Uint8"; + case BASE_TYPE_SHORT: return "Int16"; + case BASE_TYPE_USHORT: return "Uint16"; + case BASE_TYPE_INT: return "Int32"; + case BASE_TYPE_UINT: return "Uint32"; + case BASE_TYPE_LONG: return "Int64"; + case BASE_TYPE_ULONG: return "Uint64"; + case BASE_TYPE_FLOAT: return "Float32"; + case BASE_TYPE_DOUBLE: return "Float64"; + case BASE_TYPE_STRING: return "String"; + case BASE_TYPE_VECTOR: return GenType(type.VectorType()); + case BASE_TYPE_STRUCT: return type.struct_def->name; + default: return "flatbuffers.Table"; + } + } + + std::string GenGetter(const Type &type, const std::string &arguments) { + switch (type.base_type) { + case BASE_TYPE_STRING: return GenBBAccess() + ".__string" + arguments; + case BASE_TYPE_STRUCT: return GenBBAccess() + ".__struct" + arguments; + case BASE_TYPE_UNION: + if (!UnionHasStringType(*type.enum_def)) { + return GenBBAccess() + ".__union" + arguments; + } + return GenBBAccess() + ".__union_with_string" + arguments; + case BASE_TYPE_VECTOR: return GenGetter(type.VectorType(), arguments); + default: { + auto getter = + GenBBAccess() + ".read" + MakeCamel(GenType(type)) + arguments; + if (type.base_type == BASE_TYPE_BOOL) { getter = "!!" + getter; } + return getter; + } + } + } + + std::string GenBBAccess() const { return "this.bb!"; } + + std::string GenDefaultValue(const FieldDef &field, const std::string &context, + import_set &imports) { + if (field.IsScalarOptional()) { return "null"; } + + const auto &value = field.value; + if (value.type.enum_def && value.type.base_type != BASE_TYPE_UNION && + value.type.base_type != BASE_TYPE_VECTOR) { + if (auto val = value.type.enum_def->FindByValue(value.constant)) { + return AddImport(imports, *value.type.enum_def, *value.type.enum_def) + + "." + val->name; + } else { + return value.constant; + } + } + + switch (value.type.base_type) { + case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true"; + + case BASE_TYPE_STRING: + case BASE_TYPE_UNION: + case BASE_TYPE_STRUCT: { + return "null"; + } + + case BASE_TYPE_VECTOR: return "[]"; + + case BASE_TYPE_LONG: + case BASE_TYPE_ULONG: { + int64_t constant = StringToInt(value.constant.c_str()); + std::string createLong = context + ".createLong"; + return createLong + "(" + NumToString(static_cast<int32_t>(constant)) + + ", " + NumToString(static_cast<int32_t>(constant >> 32)) + ")"; + } + + default: return value.constant; + } + } + + std::string GenTypeName(import_set &imports, const Definition &owner, + const Type &type, bool input, + bool allowNull = false) { + if (!input) { + if (IsString(type) || type.base_type == BASE_TYPE_STRUCT) { + std::string name; + if (IsString(type)) { + name = "string|Uint8Array"; + } else { + name = AddImport(imports, owner, *type.struct_def); + } + return allowNull ? (name + "|null") : name; + } + } + + switch (type.base_type) { + case BASE_TYPE_BOOL: return allowNull ? "boolean|null" : "boolean"; + case BASE_TYPE_LONG: + case BASE_TYPE_ULONG: + return allowNull ? "flatbuffers.Long|null" : "flatbuffers.Long"; + default: + if (IsScalar(type.base_type)) { + if (type.enum_def) { + const auto enum_name = AddImport(imports, owner, *type.enum_def); + return allowNull ? (enum_name + "|null") : enum_name; + } + return allowNull ? "number|null" : "number"; + } + return "flatbuffers.Offset"; + } + } + + // Returns the method name for use with add/put calls. + static std::string GenWriteMethod(const Type &type) { + // Forward to signed versions since unsigned versions don't exist + switch (type.base_type) { + case BASE_TYPE_UTYPE: + case BASE_TYPE_UCHAR: return GenWriteMethod(Type(BASE_TYPE_CHAR)); + case BASE_TYPE_USHORT: return GenWriteMethod(Type(BASE_TYPE_SHORT)); + case BASE_TYPE_UINT: return GenWriteMethod(Type(BASE_TYPE_INT)); + case BASE_TYPE_ULONG: return GenWriteMethod(Type(BASE_TYPE_LONG)); + default: break; + } + + return IsScalar(type.base_type) ? MakeCamel(GenType(type)) + : (IsStruct(type) ? "Struct" : "Offset"); + } + + template<typename T> static std::string MaybeAdd(T value) { + return value != 0 ? " + " + NumToString(value) : ""; + } + + template<typename T> static std::string MaybeScale(T value) { + return value != 1 ? " * " + NumToString(value) : ""; + } + + void GenStructArgs(import_set &imports, const StructDef &struct_def, + std::string *arguments, const std::string &nameprefix) { + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (IsStruct(field.value.type)) { + // Generate arguments for a struct inside a struct. To ensure names + // don't clash, and to make it obvious these arguments are constructing + // a nested struct, prefix the name with the field name. + GenStructArgs(imports, *field.value.type.struct_def, arguments, + nameprefix + field.name + "_"); + } else { + *arguments += + ", " + nameprefix + field.name + ": " + + GenTypeName(imports, field, field.value.type, true, field.IsOptional()); + } + } + } + + static void GenStructBody(const StructDef &struct_def, std::string *body, + const std::string &nameprefix) { + *body += " builder.prep("; + *body += NumToString(struct_def.minalign) + ", "; + *body += NumToString(struct_def.bytesize) + ");\n"; + + for (auto it = struct_def.fields.vec.rbegin(); + it != struct_def.fields.vec.rend(); ++it) { + auto &field = **it; + if (field.padding) { + *body += " builder.pad(" + NumToString(field.padding) + ");\n"; + } + if (IsStruct(field.value.type)) { + // Generate arguments for a struct inside a struct. To ensure names + // don't clash, and to make it obvious these arguments are constructing + // a nested struct, prefix the name with the field name. + GenStructBody(*field.value.type.struct_def, body, + nameprefix + field.name + "_"); + } else { + *body += " builder.write" + GenWriteMethod(field.value.type) + "("; + if (field.value.type.base_type == BASE_TYPE_BOOL) { *body += "+"; } + *body += nameprefix + field.name + ");\n"; + } + } + } + + std::string GenerateNewExpression(const std::string &object_name) { + return "new " + object_name + "()"; + } + + void GenerateRootAccessor(StructDef &struct_def, std::string *code_ptr, + std::string &code, const std::string &object_name, + bool size_prefixed) { + if (!struct_def.fixed) { + GenDocComment(code_ptr); + std::string sizePrefixed("SizePrefixed"); + code += "static get" + (size_prefixed ? sizePrefixed : "") + "Root" + + GetPrefixedName(struct_def, "As"); + code += "(bb:flatbuffers.ByteBuffer, obj?:" + object_name + + "):" + object_name + " {\n"; + if (size_prefixed) { + code += + " bb.setPosition(bb.position() + " + "flatbuffers.SIZE_PREFIX_LENGTH);\n"; + } + code += " return (obj || " + GenerateNewExpression(object_name); + code += ").__init(bb.readInt32(bb.position()) + bb.position(), bb);\n"; + code += "}\n\n"; + } + } + + void GenerateFinisher(StructDef &struct_def, std::string *code_ptr, + std::string &code, bool size_prefixed) { + if (parser_.root_struct_def_ == &struct_def) { + std::string sizePrefixed("SizePrefixed"); + GenDocComment(code_ptr); + + code += "static finish" + (size_prefixed ? sizePrefixed : "") + + GetPrefixedName(struct_def) + "Buffer"; + code += "(builder:flatbuffers.Builder, offset:flatbuffers.Offset) {\n"; + code += " builder.finish(offset"; + if (!parser_.file_identifier_.empty()) { + code += ", '" + parser_.file_identifier_ + "'"; + } + if (size_prefixed) { + if (parser_.file_identifier_.empty()) { code += ", undefined"; } + code += ", true"; + } + code += ");\n"; + code += "}\n\n"; + } + } + + static std::string GetObjApiClassName(const StructDef &sd, + const IDLOptions &opts) { + return GetObjApiClassName(sd.name, opts); + } + + static std::string GetObjApiClassName(const std::string &name, + const IDLOptions &opts) { + return opts.object_prefix + name + opts.object_suffix; + } + + bool UnionHasStringType(const EnumDef &union_enum) { + return std::any_of(union_enum.Vals().begin(), union_enum.Vals().end(), + [](const EnumVal *ev) { + return !ev->IsZero() && IsString(ev->union_type); + }); + } + + std::string GenUnionGenericTypeTS(const EnumDef &union_enum) { + // TODO: make it work without any + // return std::string("T") + (UnionHasStringType(union_enum) ? "|string" : + // ""); + return std::string("any") + + (UnionHasStringType(union_enum) ? "|string" : ""); + } + + std::string GenUnionTypeTS(const EnumDef &union_enum, import_set &imports) { + std::string ret; + std::set<std::string> type_list; + + for (auto it = union_enum.Vals().begin(); it != union_enum.Vals().end(); + ++it) { + const auto &ev = **it; + if (ev.IsZero()) { continue; } + + std::string type = ""; + if (IsString(ev.union_type)) { + type = "string"; // no need to wrap string type in namespace + } else if (ev.union_type.base_type == BASE_TYPE_STRUCT) { + type = AddImport(imports, union_enum, *ev.union_type.struct_def); + } else { + FLATBUFFERS_ASSERT(false); + } + type_list.insert(type); + } + + for (auto it = type_list.begin(); it != type_list.end(); ++it) { + ret += *it + ((std::next(it) == type_list.end()) ? "" : "|"); + } + + return ret; + } + + std::string AddImport(import_set &imports, const Definition &dependent, + const StructDef &dependency) { + std::string ns; + const auto &depc_comps = dependency.defined_namespace->components; + for (auto it = depc_comps.begin(); it != depc_comps.end(); it++) ns += *it; + std::string unique_name = ns + dependency.name; + std::string import_name = dependency.name; + std::string long_import_name; + if (imports.find(unique_name) != imports.end()) + return imports.find(unique_name)->second.name; + for (auto it = imports.begin(); it != imports.end(); it++) { + if (it->second.name == import_name) { + long_import_name = ns + import_name; + break; + } + } + std::string import_statement; + import_statement += "import { "; + if (long_import_name.empty()) { + import_statement += import_name; + if (parser_.opts.generate_object_based_api) + import_statement += ", " + import_name + "T"; + } else { + import_statement += dependency.name + " as " + long_import_name; + if (parser_.opts.generate_object_based_api) + import_statement += + ", " + dependency.name + "T as " + long_import_name + "T"; + } + import_statement += " } from '"; + std::string file_name; + const auto &dep_comps = dependent.defined_namespace->components; + for (size_t i = 0; i < dep_comps.size(); i++) + file_name += i == 0 ? ".." : (kPathSeparator + std::string("..")); + if (dep_comps.size() == 0) file_name += "."; + for (auto it = depc_comps.begin(); it != depc_comps.end(); it++) + file_name += kPathSeparator + ToDasherizedCase(*it); + file_name += kPathSeparator + ToDasherizedCase(dependency.name); + import_statement += file_name + "';"; + ImportDefinition import; + import.name = long_import_name.empty() ? import_name : long_import_name; + import.statement = import_statement; + import.dependency = &dependency; + import.dependent = &dependent; + imports.insert(std::make_pair(unique_name, import)); + return import.name; + } + + // TODO: largely (but not identical) duplicated code from above couln't find a + // good way to refactor + std::string AddImport(import_set &imports, const Definition &dependent, + const EnumDef &dependency) { + std::string ns; + const auto &depc_comps = dependency.defined_namespace->components; + for (auto it = depc_comps.begin(); it != depc_comps.end(); it++) ns += *it; + std::string unique_name = ns + dependency.name; + std::string import_name = dependency.name; + std::string long_import_name; + if (imports.find(unique_name) != imports.end()) + return imports.find(unique_name)->second.name; + for (auto it = imports.begin(); it != imports.end(); it++) { + if (it->second.name == import_name) { + long_import_name = ns + import_name; + break; + } + } + std::string import_statement; + import_statement += "import { "; + if (long_import_name.empty()) + import_statement += import_name; + else + import_statement += dependency.name + " as " + long_import_name; + if (dependency.is_union) { + import_statement += ", unionTo" + import_name; + import_statement += ", unionListTo" + import_name; + } + import_statement += " } from '"; + std::string file_name; + const auto &dep_comps = dependent.defined_namespace->components; + for (size_t i = 0; i < dep_comps.size(); i++) + file_name += i == 0 ? ".." : (kPathSeparator + std::string("..")); + if (dep_comps.size() == 0) file_name += "."; + for (auto it = depc_comps.begin(); it != depc_comps.end(); it++) + file_name += kPathSeparator + ToDasherizedCase(*it); + file_name += kPathSeparator + ToDasherizedCase(dependency.name); + import_statement += file_name + "';"; + ImportDefinition import; + import.name = long_import_name.empty() ? import_name : long_import_name; + import.statement = import_statement; + import.dependency = &dependency; + import.dependent = &dependent; + imports.insert(std::make_pair(unique_name, import)); + return import.name; + } + + void AddImport(import_set &imports, std::string import_name, + std::string fileName) { + ImportDefinition import; + import.name = import_name; + import.statement = "import " + import_name + " from '" + fileName + "';"; + imports.insert(std::make_pair(import_name, import)); + } + + // Generate a TS union type based on a union's enum + std::string GenObjApiUnionTypeTS(import_set &imports, const IDLOptions &opts, + const EnumDef &union_enum) { + std::string ret = ""; + std::set<std::string> type_list; + + for (auto it = union_enum.Vals().begin(); it != union_enum.Vals().end(); + ++it) { + const auto &ev = **it; + if (ev.IsZero()) { continue; } + + std::string type = ""; + if (IsString(ev.union_type)) { + type = "string"; // no need to wrap string type in namespace + } else if (ev.union_type.base_type == BASE_TYPE_STRUCT) { + type = GetObjApiClassName( + AddImport(imports, union_enum, *ev.union_type.struct_def), opts); + } else { + FLATBUFFERS_ASSERT(false); + } + type_list.insert(type); + } + + size_t totalPrinted = 0; + for (auto it = type_list.begin(); it != type_list.end(); ++it) { + ++totalPrinted; + ret += *it + ((totalPrinted == type_list.size()) ? "" : "|"); + } + + return ret; + } + + std::string GenUnionConvFuncName(const EnumDef &enum_def) { + return "unionTo" + enum_def.name; + } + + std::string GenUnionListConvFuncName(const EnumDef &enum_def) { + return "unionListTo" + enum_def.name; + } + + std::string GenUnionConvFunc(const Type &union_type, import_set &imports) { + if (union_type.enum_def) { + const auto &enum_def = *union_type.enum_def; + + const auto valid_union_type = GenUnionTypeTS(enum_def, imports); + const auto valid_union_type_with_null = valid_union_type + "|null"; + + auto ret = "\n\nexport function " + GenUnionConvFuncName(enum_def) + + "(\n type: " + enum_def.name + + ",\n accessor: (obj:" + valid_union_type + ") => " + + valid_union_type_with_null + + "\n): " + valid_union_type_with_null + " {\n"; + + const auto enum_type = AddImport(imports, enum_def, enum_def); + + const auto union_enum_loop = [&](const std::string &accessor_str) { + ret += " switch(" + enum_type + "[type]) {\n"; + ret += " case 'NONE': return null; \n"; + + for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); + ++it) { + const auto &ev = **it; + if (ev.IsZero()) { continue; } + + ret += " case '" + ev.name + "': "; + + if (IsString(ev.union_type)) { + ret += "return " + accessor_str + "'') as string;"; + } else if (ev.union_type.base_type == BASE_TYPE_STRUCT) { + const auto type = + AddImport(imports, enum_def, *ev.union_type.struct_def); + ret += "return " + accessor_str + "new " + type + "())! as " + + type + ";"; + } else { + FLATBUFFERS_ASSERT(false); + } + ret += "\n"; + } + + ret += " default: return null;\n"; + ret += " }\n"; + }; + + union_enum_loop("accessor("); + ret += "}"; + + ret += "\n\nexport function " + GenUnionListConvFuncName(enum_def) + + "(\n type: " + enum_def.name + + ", \n accessor: (index: number, obj:" + valid_union_type + + ") => " + valid_union_type_with_null + + ", \n index: number\n): " + valid_union_type_with_null + " {\n"; + union_enum_loop("accessor(index, "); + ret += "}"; + + return ret; + } + FLATBUFFERS_ASSERT(0); + return ""; + } + + // Used for generating a short function that returns the correct class + // based on union enum type. Assume the context is inside the non object api + // type + std::string GenUnionValTS(import_set &imports, const std::string &field_name, + const Type &union_type, + const bool is_array = false) { + if (union_type.enum_def) { + const auto &enum_def = *union_type.enum_def; + const auto enum_type = AddImport(imports, enum_def, enum_def); + const std::string union_accessor = "this." + field_name; + + const auto union_has_string = UnionHasStringType(enum_def); + const auto field_binded_method = "this." + field_name + ".bind(this)"; + + std::string ret; + + if (!is_array) { + const auto conversion_function = GenUnionConvFuncName(enum_def); + const auto target_enum = "this." + field_name + "Type()"; + + ret = "(() => {\n"; + ret += " let temp = " + conversion_function + "(" + target_enum + + ", " + field_binded_method + ");\n"; + ret += " if(temp === null) { return null; }\n"; + ret += union_has_string + ? " if(typeof temp === 'string') { return temp; }\n" + : ""; + ret += " return temp.unpack()\n"; + ret += " })()"; + } else { + const auto conversion_function = GenUnionListConvFuncName(enum_def); + const auto target_enum_accesor = "this." + field_name + "Type"; + const auto target_enum_length = target_enum_accesor + "Length()"; + + ret = "(() => {\n"; + ret += " let ret = [];\n"; + ret += " for(let targetEnumIndex = 0; targetEnumIndex < " + + target_enum_length + + "; " + "++targetEnumIndex) {\n"; + ret += " let targetEnum = " + target_enum_accesor + + "(targetEnumIndex);\n"; + ret += " if(targetEnum === null || " + enum_type + + "[targetEnum!] === 'NONE') { " + "continue; }\n\n"; + ret += " let temp = " + conversion_function + "(targetEnum, " + + field_binded_method + ", targetEnumIndex);\n"; + ret += " if(temp === null) { continue; }\n"; + ret += union_has_string ? " if(typeof temp === 'string') { " + "ret.push(temp); continue; }\n" + : ""; + ret += " ret.push(temp.unpack());\n"; + ret += " }\n"; + ret += " return ret;\n"; + ret += " })()"; + } + + return ret; + } + + FLATBUFFERS_ASSERT(0); + return ""; + } + + static std::string GenNullCheckConditional( + const std::string &nullCheckVar, const std::string &trueVal, + const std::string &falseVal = "null") { + return "(" + nullCheckVar + " !== null ? " + trueVal + " : " + falseVal + + ")"; + } + + std::string GenStructMemberValueTS(const StructDef &struct_def, + const std::string &prefix, + const std::string &delimiter, + const bool nullCheck = true) { + std::string ret; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + + const auto curr_member_accessor = + prefix + "." + MakeCamel(field.name, false); + if (IsStruct(field.value.type)) { + ret += GenStructMemberValueTS(*field.value.type.struct_def, + curr_member_accessor, delimiter); + } else { + if (nullCheck) { + ret += + "(" + prefix + " === null ? 0 : " + curr_member_accessor + "!)"; + } else { + ret += curr_member_accessor; + } + } + + if (std::next(it) != struct_def.fields.vec.end()) { ret += delimiter; } + } + + return ret; + } + + void GenObjApi(const Parser &parser, StructDef &struct_def, + std::string &obj_api_unpack_func, std::string &obj_api_class, + import_set &imports) { + const auto class_name = GetObjApiClassName(struct_def, parser.opts); + + std::string unpack_func = "\nunpack(): " + class_name + + " {\n return new " + class_name + "(" + + (struct_def.fields.vec.empty() ? "" : "\n"); + std::string unpack_to_func = "\nunpackTo(_o: " + class_name + "): void {" + + +(struct_def.fields.vec.empty() ? "" : "\n"); + + std::string constructor_func = "constructor("; + constructor_func += (struct_def.fields.vec.empty() ? "" : "\n"); + + const auto has_create = + struct_def.fixed || CanCreateFactoryMethod(struct_def); + + std::string pack_func_prototype = + "\npack(builder:flatbuffers.Builder): flatbuffers.Offset {\n"; + + std::string pack_func_offset_decl; + std::string pack_func_create_call; + + const auto struct_name = AddImport(imports, struct_def, struct_def); + + if (has_create) { + pack_func_create_call = " return " + struct_name + ".create" + + GetPrefixedName(struct_def) + "(builder" + + (struct_def.fields.vec.empty() ? "" : ",\n "); + } else { + pack_func_create_call = " " + struct_name + ".start" + + GetPrefixedName(struct_def) + "(builder);\n"; + } + + if (struct_def.fixed) { + // when packing struct, nested struct's members instead of the struct's + // offset are used + pack_func_create_call += + GenStructMemberValueTS(struct_def, "this", ",\n ", false) + "\n "; + } + + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + + const auto field_name = MakeCamel(field.name, false); + const std::string field_binded_method = + "this." + field_name + ".bind(this)"; + + std::string field_val; + std::string field_type; + // a string that declares a variable containing the + // offset for things that can't be generated inline + // empty otw + std::string field_offset_decl; + // a string that contains values for things that can be created inline or + // the variable name from field_offset_decl + std::string field_offset_val; + const auto field_default_val = + GenDefaultValue(field, "flatbuffers", imports); + + // Emit a scalar field + const auto is_string = IsString(field.value.type); + if (IsScalar(field.value.type.base_type) || is_string) { + const auto has_null_default = is_string || HasNullDefault(field); + + field_type += GenTypeName(imports, field, field.value.type, false, + has_null_default); + field_val = "this." + field_name + "()"; + + if (field.value.type.base_type != BASE_TYPE_STRING) { + field_offset_val = "this." + field_name; + } else { + field_offset_decl = GenNullCheckConditional( + "this." + field_name, + "builder.createString(this." + field_name + "!)", "0"); + } + } + + // Emit an object field + else { + auto is_vector = false; + switch (field.value.type.base_type) { + case BASE_TYPE_STRUCT: { + const auto &sd = *field.value.type.struct_def; + field_type += GetObjApiClassName(sd, parser.opts); + + const std::string field_accessor = "this." + field_name + "()"; + field_val = GenNullCheckConditional(field_accessor, + field_accessor + "!.unpack()"); + auto packing = GenNullCheckConditional( + "this." + field_name, "this." + field_name + "!.pack(builder)", + "0"); + + if (sd.fixed) { + field_offset_val = std::move(packing); + } else { + field_offset_decl = std::move(packing); + } + + break; + } + + case BASE_TYPE_VECTOR: { + auto vectortype = field.value.type.VectorType(); + auto vectortypename = + GenTypeName(imports, struct_def, vectortype, false); + is_vector = true; + + field_type = "("; + + switch (vectortype.base_type) { + case BASE_TYPE_STRUCT: { + const auto &sd = *field.value.type.struct_def; + field_type += GetObjApiClassName(sd, parser.opts); + field_type += ")[]"; + + field_val = GenBBAccess() + ".createObjList(" + + field_binded_method + ", this." + field_name + + "Length())"; + + if (sd.fixed) { + field_offset_decl = + "builder.createStructOffsetList(this." + field_name + + ", " + AddImport(imports, struct_def, struct_def) + + ".start" + MakeCamel(field_name) + "Vector)"; + } else { + field_offset_decl = + AddImport(imports, struct_def, struct_def) + ".create" + + MakeCamel(field_name) + + "Vector(builder, builder.createObjectOffsetList(" + + "this." + field_name + "))"; + } + + break; + } + + case BASE_TYPE_STRING: { + field_type += "string)[]"; + field_val = GenBBAccess() + ".createScalarList(" + + field_binded_method + ", this." + field_name + + "Length())"; + field_offset_decl = + AddImport(imports, struct_def, struct_def) + ".create" + + MakeCamel(field_name) + + "Vector(builder, builder.createObjectOffsetList(" + + "this." + field_name + "))"; + break; + } + + case BASE_TYPE_UNION: { + field_type += GenObjApiUnionTypeTS(imports, parser.opts, + *(vectortype.enum_def)); + field_type += ")[]"; + field_val = + GenUnionValTS(imports, field_name, vectortype, true); + + field_offset_decl = + AddImport(imports, struct_def, struct_def) + ".create" + + MakeCamel(field_name) + + "Vector(builder, builder.createObjectOffsetList(" + + "this." + field_name + "))"; + + break; + } + default: { + if (vectortype.enum_def) { + field_type += GenTypeName(imports, struct_def, vectortype, + false, HasNullDefault(field)); + } else { + field_type += vectortypename; + } + field_type += ")[]"; + field_val = GenBBAccess() + ".createScalarList(" + + field_binded_method + ", this." + field_name + + "Length())"; + + field_offset_decl = AddImport(imports, struct_def, struct_def) + + ".create" + MakeCamel(field_name) + + "Vector(builder, this." + field_name + ")"; + + break; + } + } + + break; + } + + case BASE_TYPE_UNION: { + field_type += GenObjApiUnionTypeTS(imports, parser.opts, + *(field.value.type.enum_def)); + + field_val = GenUnionValTS(imports, field_name, field.value.type); + field_offset_decl = + "builder.createObjectOffset(this." + field_name + ")"; + break; + } + + default: FLATBUFFERS_ASSERT(0); break; + } + + // length 0 vector is simply empty instead of null + field_type += is_vector ? "" : "|null"; + } + + if (!field_offset_decl.empty()) { + field_offset_decl = + " const " + field_name + " = " + field_offset_decl + ";"; + } + if (field_offset_val.empty()) { field_offset_val = field_name; } + + unpack_func += " " + field_val; + unpack_to_func += " _o." + field_name + " = " + field_val + ";"; + + constructor_func += " public " + field_name + ": " + field_type + " = " + + field_default_val; + + if (!struct_def.fixed) { + if (!field_offset_decl.empty()) { + pack_func_offset_decl += field_offset_decl + "\n"; + } + + if (has_create) { + pack_func_create_call += field_offset_val; + } else { + pack_func_create_call += " " + struct_name + ".add" + + MakeCamel(field.name) + "(builder, " + + field_offset_val + ");\n"; + } + } + + if (std::next(it) != struct_def.fields.vec.end()) { + constructor_func += ",\n"; + + if (!struct_def.fixed && has_create) { + pack_func_create_call += ",\n "; + } + + unpack_func += ",\n"; + unpack_to_func += "\n"; + } else { + constructor_func += "\n"; + if (!struct_def.fixed) { + pack_func_offset_decl += (pack_func_offset_decl.empty() ? "" : "\n"); + pack_func_create_call += "\n "; + } + + unpack_func += "\n "; + unpack_to_func += "\n"; + } + } + + constructor_func += "){}\n\n"; + + if (has_create) { + pack_func_create_call += ");"; + } else { + pack_func_create_call += "return " + struct_name + ".end" + + GetPrefixedName(struct_def) + "(builder);"; + } + + obj_api_class = "\nexport class " + + GetObjApiClassName(struct_def, parser.opts) + " {\n"; + + obj_api_class += constructor_func; + obj_api_class += pack_func_prototype + pack_func_offset_decl + + pack_func_create_call + "\n}"; + + obj_api_class += "\n}\n"; + + unpack_func += ");\n}"; + unpack_to_func += "}\n"; + + obj_api_unpack_func = unpack_func + "\n\n" + unpack_to_func; + } + + static bool CanCreateFactoryMethod(const StructDef &struct_def) { + // to preserve backwards compatibility, we allow the first field to be a + // struct + return struct_def.fields.vec.size() < 2 || + std::all_of(std::begin(struct_def.fields.vec) + 1, + std::end(struct_def.fields.vec), + [](const FieldDef *f) -> bool { + FLATBUFFERS_ASSERT(f != nullptr); + return f->value.type.base_type != BASE_TYPE_STRUCT; + }); + } + + // Generate an accessor struct with constructor for a flatbuffers struct. + void GenStruct(const Parser &parser, StructDef &struct_def, + std::string *code_ptr, import_set &imports) { + if (struct_def.generated) return; + std::string &code = *code_ptr; + + std::string object_name; + std::string object_namespace = GetNameSpace(struct_def); + + // Emit constructor + object_name = struct_def.name; + GenDocComment(struct_def.doc_comment, code_ptr); + code += "export class " + struct_def.name; + code += " {\n"; + code += " bb: flatbuffers.ByteBuffer|null = null;\n"; + code += " bb_pos = 0;\n"; + + // Generate the __init method that sets the field in a pre-existing + // accessor object. This is to allow object reuse. + code += + "__init(i:number, bb:flatbuffers.ByteBuffer):" + object_name + " {\n"; + code += " this.bb_pos = i;\n"; + code += " this.bb = bb;\n"; + code += " return this;\n"; + code += "}\n\n"; + + // Generate special accessors for the table that when used as the root of a + // FlatBuffer + GenerateRootAccessor(struct_def, code_ptr, code, object_name, false); + GenerateRootAccessor(struct_def, code_ptr, code, object_name, true); + + // Generate the identifier check method + if (!struct_def.fixed && parser_.root_struct_def_ == &struct_def && + !parser_.file_identifier_.empty()) { + GenDocComment(code_ptr); + code += + "static bufferHasIdentifier(bb:flatbuffers.ByteBuffer):boolean " + "{\n"; + code += " return bb.__has_identifier('" + parser_.file_identifier_; + code += "');\n}\n\n"; + } + + // Emit field accessors + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + auto offset_prefix = + " const offset = " + GenBBAccess() + ".__offset(this.bb_pos, " + + NumToString(field.value.offset) + ");\n return offset ? "; + + // Emit a scalar field + const auto is_string = IsString(field.value.type); + if (IsScalar(field.value.type.base_type) || is_string) { + const auto has_null_default = is_string || HasNullDefault(field); + + GenDocComment(field.doc_comment, code_ptr); + std::string prefix = MakeCamel(field.name, false) + "("; + if (is_string) { + code += prefix + "):string|null\n"; + code += + prefix + "optionalEncoding:flatbuffers.Encoding" + "):" + + GenTypeName(imports, struct_def, field.value.type, false, true) + + "\n"; + code += prefix + "optionalEncoding?:any"; + } else { + code += prefix; + } + if (field.value.type.enum_def) { + code += "):" + + GenTypeName(imports, struct_def, field.value.type, false, + field.IsOptional()) + + " {\n"; + } else { + code += "):" + + GenTypeName(imports, struct_def, field.value.type, false, + has_null_default) + + " {\n"; + } + + if (struct_def.fixed) { + code += + " return " + + GenGetter(field.value.type, + "(this.bb_pos" + MaybeAdd(field.value.offset) + ")") + + ";\n"; + } else { + std::string index = "this.bb_pos + offset"; + if (is_string) { index += ", optionalEncoding"; } + code += offset_prefix + + GenGetter(field.value.type, "(" + index + ")") + " : " + + GenDefaultValue(field, GenBBAccess(), imports); + code += ";\n"; + } + } + + // Emit an object field + else { + switch (field.value.type.base_type) { + case BASE_TYPE_STRUCT: { + const auto type = + AddImport(imports, struct_def, *field.value.type.struct_def); + GenDocComment(field.doc_comment, code_ptr); + code += MakeCamel(field.name, false); + code += "(obj?:" + type + "):" + type + "|null {\n"; + + if (struct_def.fixed) { + code += " return (obj || " + GenerateNewExpression(type); + code += ").__init(this.bb_pos"; + code += + MaybeAdd(field.value.offset) + ", " + GenBBAccess() + ");\n"; + } else { + code += offset_prefix + "(obj || " + GenerateNewExpression(type) + + ").__init("; + code += field.value.type.struct_def->fixed + ? "this.bb_pos + offset" + : GenBBAccess() + ".__indirect(this.bb_pos + offset)"; + code += ", " + GenBBAccess() + ") : null;\n"; + } + + break; + } + + case BASE_TYPE_VECTOR: { + auto vectortype = field.value.type.VectorType(); + auto vectortypename = + GenTypeName(imports, struct_def, vectortype, false); + auto inline_size = InlineSize(vectortype); + auto index = GenBBAccess() + + ".__vector(this.bb_pos + offset) + index" + + MaybeScale(inline_size); + std::string ret_type; + bool is_union = false; + switch (vectortype.base_type) { + case BASE_TYPE_STRUCT: ret_type = vectortypename; break; + case BASE_TYPE_STRING: ret_type = vectortypename; break; + case BASE_TYPE_UNION: + ret_type = "?flatbuffers.Table"; + is_union = true; + break; + default: ret_type = vectortypename; + } + GenDocComment(field.doc_comment, code_ptr); + std::string prefix = MakeCamel(field.name, false); + // TODO: make it work without any + // if (is_union) { prefix += "<T extends flatbuffers.Table>"; } + if (is_union) { prefix += ""; } + prefix += "(index: number"; + if (is_union) { + const auto union_type = + GenUnionGenericTypeTS(*(field.value.type.enum_def)); + + vectortypename = union_type; + code += prefix + ", obj:" + union_type; + } else if (vectortype.base_type == BASE_TYPE_STRUCT) { + code += prefix + ", obj?:" + vectortypename; + } else if (IsString(vectortype)) { + code += prefix + "):string\n"; + code += prefix + ",optionalEncoding:flatbuffers.Encoding" + + "):" + vectortypename + "\n"; + code += prefix + ",optionalEncoding?:any"; + } else { + code += prefix; + } + code += "):" + vectortypename + "|null {\n"; + + if (vectortype.base_type == BASE_TYPE_STRUCT) { + code += offset_prefix + "(obj || " + + GenerateNewExpression(vectortypename); + code += ").__init("; + code += vectortype.struct_def->fixed + ? index + : GenBBAccess() + ".__indirect(" + index + ")"; + code += ", " + GenBBAccess() + ")"; + } else { + if (is_union) { + index = "obj, " + index; + } else if (IsString(vectortype)) { + index += ", optionalEncoding"; + } + code += offset_prefix + GenGetter(vectortype, "(" + index + ")"); + } + code += " : "; + if (field.value.type.element == BASE_TYPE_BOOL) { + code += "false"; + } else if (field.value.type.element == BASE_TYPE_LONG || + field.value.type.element == BASE_TYPE_ULONG) { + code += GenBBAccess() + ".createLong(0, 0)"; + } else if (IsScalar(field.value.type.element)) { + if (field.value.type.enum_def) { + code += field.value.constant; + } else { + code += "0"; + } + } else { + code += "null"; + } + code += ";\n"; + break; + } + + case BASE_TYPE_UNION: { + GenDocComment(field.doc_comment, code_ptr); + code += MakeCamel(field.name, false); + + const auto &union_enum = *(field.value.type.enum_def); + const auto union_type = GenUnionGenericTypeTS(union_enum); + code += "<T extends flatbuffers.Table>(obj:" + union_type + + "):" + union_type + + "|null " + "{\n"; + + code += offset_prefix + + GenGetter(field.value.type, "(obj, this.bb_pos + offset)") + + " : null;\n"; + break; + } + default: FLATBUFFERS_ASSERT(0); + } + } + code += "}\n\n"; + + // Adds the mutable scalar value to the output + if (IsScalar(field.value.type.base_type) && parser.opts.mutable_buffer && + !IsUnion(field.value.type)) { + std::string type = + GenTypeName(imports, struct_def, field.value.type, true); + + code += "mutate_" + field.name + "(value:" + type + "):boolean {\n"; + + if (struct_def.fixed) { + code += " " + GenBBAccess() + ".write" + + MakeCamel(GenType(field.value.type)) + "(this.bb_pos + " + + NumToString(field.value.offset) + ", "; + } else { + code += " const offset = " + GenBBAccess() + + ".__offset(this.bb_pos, " + NumToString(field.value.offset) + + ");\n\n"; + code += " if (offset === 0) {\n"; + code += " return false;\n"; + code += " }\n\n"; + + // special case for bools, which are treated as uint8 + code += " " + GenBBAccess() + ".write" + + MakeCamel(GenType(field.value.type)) + + "(this.bb_pos + offset, "; + if (field.value.type.base_type == BASE_TYPE_BOOL) { code += "+"; } + } + + code += "value);\n"; + code += " return true;\n"; + code += "}\n\n"; + } + + // Emit vector helpers + if (IsVector(field.value.type)) { + // Emit a length helper + GenDocComment(code_ptr); + code += MakeCamel(field.name, false); + code += "Length():number {\n" + offset_prefix; + + code += + GenBBAccess() + ".__vector_len(this.bb_pos + offset) : 0;\n}\n\n"; + + // For scalar types, emit a typed array helper + auto vectorType = field.value.type.VectorType(); + if (IsScalar(vectorType.base_type) && !IsLong(vectorType.base_type)) { + GenDocComment(code_ptr); + + code += MakeCamel(field.name, false); + code += "Array():" + GenType(vectorType) + "Array|null {\n" + + offset_prefix; + + code += "new " + GenType(vectorType) + "Array(" + GenBBAccess() + + ".bytes().buffer, " + GenBBAccess() + + ".bytes().byteOffset + " + GenBBAccess() + + ".__vector(this.bb_pos + offset), " + GenBBAccess() + + ".__vector_len(this.bb_pos + offset)) : null;\n}\n\n"; + } + } + } + + // Emit the fully qualified name + if (parser_.opts.generate_name_strings) { + GenDocComment(code_ptr); + code += "static getFullyQualifiedName():string {\n"; + code += " return '" + WrapInNameSpace(struct_def) + "';\n"; + code += "}\n\n"; + } + + // Emit the size of the struct. + if (struct_def.fixed) { + GenDocComment(code_ptr); + code += "static sizeOf():number {\n"; + code += " return " + NumToString(struct_def.bytesize) + ";\n"; + code += "}\n\n"; + } + + // Emit a factory constructor + if (struct_def.fixed) { + std::string arguments; + GenStructArgs(imports, struct_def, &arguments, ""); + GenDocComment(code_ptr); + + code += "static create" + GetPrefixedName(struct_def) + + "(builder:flatbuffers.Builder"; + code += arguments + "):flatbuffers.Offset {\n"; + + GenStructBody(struct_def, &code, ""); + code += " return builder.offset();\n}\n\n"; + } else { + // Generate a method to start building a new object + GenDocComment(code_ptr); + + code += "static start" + GetPrefixedName(struct_def) + + "(builder:flatbuffers.Builder) {\n"; + + code += " builder.startObject(" + + NumToString(struct_def.fields.vec.size()) + ");\n"; + code += "}\n\n"; + + // Generate a set of static methods that allow table construction + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (field.deprecated) continue; + const auto argname = GetArgName(field); + + // Generate the field insertion method + GenDocComment(code_ptr); + code += "static add" + MakeCamel(field.name); + code += "(builder:flatbuffers.Builder, " + argname + ":" + + GetArgType(imports, struct_def, field, false) + ") {\n"; + code += " builder.addField" + GenWriteMethod(field.value.type) + "("; + code += NumToString(it - struct_def.fields.vec.begin()) + ", "; + if (field.value.type.base_type == BASE_TYPE_BOOL) { code += "+"; } + code += argname + ", "; + if (!IsScalar(field.value.type.base_type)) { + code += "0"; + } else if (HasNullDefault(field)) { + if (IsLong(field.value.type.base_type)) { + code += "builder.createLong(0, 0)"; + } else { + code += "0"; + } + } else { + if (field.value.type.base_type == BASE_TYPE_BOOL) { code += "+"; } + code += GenDefaultValue(field, "builder", imports); + } + code += ");\n}\n\n"; + + if (IsVector(field.value.type)) { + auto vector_type = field.value.type.VectorType(); + auto alignment = InlineAlignment(vector_type); + auto elem_size = InlineSize(vector_type); + + // Generate a method to create a vector from a JavaScript array + if (!IsStruct(vector_type)) { + GenDocComment(code_ptr); + + const std::string sig_begin = + "static create" + MakeCamel(field.name) + + "Vector(builder:flatbuffers.Builder, data:"; + const std::string sig_end = "):flatbuffers.Offset"; + std::string type = + GenTypeName(imports, struct_def, vector_type, true) + "[]"; + if (type == "number[]") { + const auto &array_type = GenType(vector_type); + // the old type should be deprecated in the future + std::string type_old = "number[]|Uint8Array"; + std::string type_new = "number[]|" + array_type + "Array"; + if (type_old == type_new) { + type = type_new; + } else { + // add function overloads + code += sig_begin + type_new + sig_end + ";\n"; + code += + "/**\n * @deprecated This Uint8Array overload will " + "be removed in the future.\n */\n"; + code += sig_begin + type_old + sig_end + ";\n"; + type = type_new + "|Uint8Array"; + } + } + code += sig_begin + type + sig_end + " {\n"; + code += " builder.startVector(" + NumToString(elem_size); + code += ", data.length, " + NumToString(alignment) + ");\n"; + code += " for (let i = data.length - 1; i >= 0; i--) {\n"; + code += " builder.add" + GenWriteMethod(vector_type) + "("; + if (vector_type.base_type == BASE_TYPE_BOOL) { code += "+"; } + code += "data[i]!);\n"; + code += " }\n"; + code += " return builder.endVector();\n"; + code += "}\n\n"; + } + + // Generate a method to start a vector, data to be added manually + // after + GenDocComment(code_ptr); + + code += "static start" + MakeCamel(field.name); + code += "Vector(builder:flatbuffers.Builder, numElems:number) {\n"; + code += " builder.startVector(" + NumToString(elem_size); + code += ", numElems, " + NumToString(alignment) + ");\n"; + code += "}\n\n"; + } + } + + // Generate a method to stop building a new object + GenDocComment(code_ptr); + + code += "static end" + GetPrefixedName(struct_def); + code += "(builder:flatbuffers.Builder):flatbuffers.Offset {\n"; + + code += " const offset = builder.endObject();\n"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + auto &field = **it; + if (!field.deprecated && field.IsRequired()) { + code += " builder.requiredField(offset, "; + code += NumToString(field.value.offset); + code += ") // " + field.name + "\n"; + } + } + code += " return offset;\n"; + code += "}\n\n"; + + // Generate the methods to complete buffer construction + GenerateFinisher(struct_def, code_ptr, code, false); + GenerateFinisher(struct_def, code_ptr, code, true); + + // Generate a convenient CreateX function + if (CanCreateFactoryMethod(struct_def)) { + code += "static create" + GetPrefixedName(struct_def); + code += "(builder:flatbuffers.Builder"; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.deprecated) continue; + code += ", " + GetArgName(field) + ":" + + GetArgType(imports, struct_def, field, true); + } + + code += "):flatbuffers.Offset {\n"; + code += " " + struct_def.name + ".start" + + GetPrefixedName(struct_def) + "(builder);\n"; + + std::string methodPrefix = struct_def.name; + for (auto it = struct_def.fields.vec.begin(); + it != struct_def.fields.vec.end(); ++it) { + const auto &field = **it; + if (field.deprecated) continue; + + const auto arg_name = GetArgName(field); + + if (field.IsScalarOptional()) { + code += " if (" + arg_name + " !== null)\n "; + } + + code += " " + methodPrefix + ".add" + MakeCamel(field.name) + "("; + code += "builder, " + arg_name + ");\n"; + } + + code += " return " + methodPrefix + ".end" + + GetPrefixedName(struct_def) + "(builder);\n"; + code += "}\n"; + } + } + + if (!struct_def.fixed && parser_.services_.vec.size() != 0) { + auto name = GetPrefixedName(struct_def, ""); + code += "\n"; + code += "serialize():Uint8Array {\n"; + code += " return this.bb!.bytes();\n"; + code += "}\n"; + + code += "\n"; + code += "static deserialize(buffer: Uint8Array):" + name + " {\n"; + code += " return " + AddImport(imports, struct_def, struct_def) + + ".getRootAs" + name + "(new flatbuffers.ByteBuffer(buffer))\n"; + code += "}\n"; + } + + if (parser_.opts.generate_object_based_api) { + std::string obj_api_class; + std::string obj_api_unpack_func; + GenObjApi(parser_, struct_def, obj_api_unpack_func, obj_api_class, + imports); + + code += obj_api_unpack_func + "}\n" + obj_api_class; + } else { + code += "}\n"; + } + } + + static bool HasNullDefault(const FieldDef &field) { + return field.IsOptional() && field.value.constant == "null"; + } + + std::string GetArgType(import_set &imports, const Definition &owner, + const FieldDef &field, bool allowNull) { + return GenTypeName(imports, owner, field.value.type, true, + allowNull && field.IsOptional()); + } + + static std::string GetArgName(const FieldDef &field) { + auto argname = MakeCamel(field.name, false); + if (!IsScalar(field.value.type.base_type)) { argname += "Offset"; } + + return argname; + } + + std::string GetPrefixedName(const StructDef &struct_def, + const char *prefix = "") { + return prefix + struct_def.name; + } +}; // namespace ts +} // namespace ts + +bool GenerateTS(const Parser &parser, const std::string &path, + const std::string &file_name) { + ts::TsGenerator generator(parser, path, file_name); + return generator.generate(); +} + +std::string TSMakeRule(const Parser &parser, const std::string &path, + const std::string &file_name) { + FLATBUFFERS_ASSERT(parser.opts.lang <= IDLOptions::kMAX); + + std::string filebase = + flatbuffers::StripPath(flatbuffers::StripExtension(file_name)); + ts::TsGenerator generator(parser, path, file_name); + std::string make_rule = + generator.GeneratedFileName(path, filebase, parser.opts) + ": "; + + auto included_files = parser.GetIncludedFilesRecursive(file_name); + for (auto it = included_files.begin(); it != included_files.end(); ++it) { + make_rule += " " + *it; + } + return make_rule; +} + +} // namespace flatbuffers diff --git a/contrib/libs/flatbuffers/src/idl_parser.cpp b/contrib/libs/flatbuffers/src/idl_parser.cpp new file mode 100644 index 0000000000..ad642d79a9 --- /dev/null +++ b/contrib/libs/flatbuffers/src/idl_parser.cpp @@ -0,0 +1,3986 @@ +/* + * Copyright 2014 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <algorithm> +#include <cmath> +#include <list> +#include <string> +#include <utility> + +#include "flatbuffers/idl.h" +#include "flatbuffers/util.h" + +namespace flatbuffers { + +// Reflects the version at the compiling time of binary(lib/dll/so). +const char *FLATBUFFERS_VERSION() { + // clang-format off + return + FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MAJOR) "." + FLATBUFFERS_STRING(FLATBUFFERS_VERSION_MINOR) "." + FLATBUFFERS_STRING(FLATBUFFERS_VERSION_REVISION); + // clang-format on +} + +const double kPi = 3.14159265358979323846; + +// clang-format off +const char *const kTypeNames[] = { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, ...) \ + IDLTYPE, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + nullptr +}; + +const char kTypeSizes[] = { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ + sizeof(CTYPE), + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD +}; +// clang-format on + +// The enums in the reflection schema should match the ones we use internally. +// Compare the last element to check if these go out of sync. +static_assert(BASE_TYPE_UNION == static_cast<BaseType>(reflection::Union), + "enums don't match"); + +// Any parsing calls have to be wrapped in this macro, which automates +// handling of recursive error checking a bit. It will check the received +// CheckedError object, and return straight away on error. +#define ECHECK(call) \ + { \ + auto ce = (call); \ + if (ce.Check()) return ce; \ + } + +// These two functions are called hundreds of times below, so define a short +// form: +#define NEXT() ECHECK(Next()) +#define EXPECT(tok) ECHECK(Expect(tok)) + +static bool ValidateUTF8(const std::string &str) { + const char *s = &str[0]; + const char *const sEnd = s + str.length(); + while (s < sEnd) { + if (FromUTF8(&s) < 0) { return false; } + } + return true; +} + +static bool IsLowerSnakeCase(const std::string &str) { + for (size_t i = 0; i < str.length(); i++) { + char c = str[i]; + if (!check_ascii_range(c, 'a', 'z') && !is_digit(c) && c != '_') { + return false; + } + } + return true; +} + +// Convert an underscore_based_identifier in to camelCase. +// Also uppercases the first character if first is true. +std::string MakeCamel(const std::string &in, bool first) { + std::string s; + for (size_t i = 0; i < in.length(); i++) { + if (!i && first) + s += CharToUpper(in[0]); + else if (in[i] == '_' && i + 1 < in.length()) + s += CharToUpper(in[++i]); + else + s += in[i]; + } + return s; +} + +// Convert an underscore_based_identifier in to screaming snake case. +std::string MakeScreamingCamel(const std::string &in) { + std::string s; + for (size_t i = 0; i < in.length(); i++) { + if (in[i] != '_') + s += CharToUpper(in[i]); + else + s += in[i]; + } + return s; +} + +void DeserializeDoc(std::vector<std::string> &doc, + const Vector<Offset<String>> *documentation) { + if (documentation == nullptr) return; + for (uoffset_t index = 0; index < documentation->size(); index++) + doc.push_back(documentation->Get(index)->str()); +} + +void Parser::Message(const std::string &msg) { + if (!error_.empty()) error_ += "\n"; // log all warnings and errors + error_ += file_being_parsed_.length() ? AbsolutePath(file_being_parsed_) : ""; + // clang-format off + + #ifdef _WIN32 // MSVC alike + error_ += + "(" + NumToString(line_) + ", " + NumToString(CursorPosition()) + ")"; + #else // gcc alike + if (file_being_parsed_.length()) error_ += ":"; + error_ += NumToString(line_) + ": " + NumToString(CursorPosition()); + #endif + // clang-format on + error_ += ": " + msg; +} + +void Parser::Warning(const std::string &msg) { + if (!opts.no_warnings) Message("warning: " + msg); +} + +CheckedError Parser::Error(const std::string &msg) { + Message("error: " + msg); + return CheckedError(true); +} + +inline CheckedError NoError() { return CheckedError(false); } + +CheckedError Parser::RecurseError() { + return Error("maximum parsing depth " + NumToString(parse_depth_counter_) + + " reached"); +} + +class Parser::ParseDepthGuard { + public: + explicit ParseDepthGuard(Parser *parser_not_null) + : parser_(*parser_not_null), caller_depth_(parser_.parse_depth_counter_) { + FLATBUFFERS_ASSERT(caller_depth_ <= (FLATBUFFERS_MAX_PARSING_DEPTH) && + "Check() must be called to prevent stack overflow"); + parser_.parse_depth_counter_ += 1; + } + + ~ParseDepthGuard() { parser_.parse_depth_counter_ -= 1; } + + CheckedError Check() { + return caller_depth_ >= (FLATBUFFERS_MAX_PARSING_DEPTH) + ? parser_.RecurseError() + : CheckedError(false); + } + + FLATBUFFERS_DELETE_FUNC(ParseDepthGuard(const ParseDepthGuard &)); + FLATBUFFERS_DELETE_FUNC(ParseDepthGuard &operator=(const ParseDepthGuard &)); + + private: + Parser &parser_; + const int caller_depth_; +}; + +template<typename T> std::string TypeToIntervalString() { + return "[" + NumToString((flatbuffers::numeric_limits<T>::lowest)()) + "; " + + NumToString((flatbuffers::numeric_limits<T>::max)()) + "]"; +} + +// atot: template version of atoi/atof: convert a string to an instance of T. +template<typename T> +bool atot_scalar(const char *s, T *val, bool_constant<false>) { + return StringToNumber(s, val); +} + +template<typename T> +bool atot_scalar(const char *s, T *val, bool_constant<true>) { + // Normalize NaN parsed from fbs or json to unsigned NaN. + if (false == StringToNumber(s, val)) return false; + *val = (*val != *val) ? std::fabs(*val) : *val; + return true; +} + +template<typename T> CheckedError atot(const char *s, Parser &parser, T *val) { + auto done = atot_scalar(s, val, bool_constant<is_floating_point<T>::value>()); + if (done) return NoError(); + if (0 == *val) + return parser.Error("invalid number: \"" + std::string(s) + "\""); + else + return parser.Error("invalid number: \"" + std::string(s) + "\"" + + ", constant does not fit " + TypeToIntervalString<T>()); +} +template<> +inline CheckedError atot<Offset<void>>(const char *s, Parser &parser, + Offset<void> *val) { + (void)parser; + *val = Offset<void>(atoi(s)); + return NoError(); +} + +std::string Namespace::GetFullyQualifiedName(const std::string &name, + size_t max_components) const { + // Early exit if we don't have a defined namespace. + if (components.empty() || !max_components) { return name; } + std::string stream_str; + for (size_t i = 0; i < std::min(components.size(), max_components); i++) { + stream_str += components[i]; + stream_str += '.'; + } + if (!stream_str.empty()) stream_str.pop_back(); + if (name.length()) { + stream_str += '.'; + stream_str += name; + } + return stream_str; +} + +template<typename T> +T *LookupTableByName(const SymbolTable<T> &table, const std::string &name, + const Namespace ¤t_namespace, size_t skip_top) { + const auto &components = current_namespace.components; + if (table.dict.empty()) return nullptr; + if (components.size() < skip_top) return nullptr; + const auto N = components.size() - skip_top; + std::string full_name; + for (size_t i = 0; i < N; i++) { + full_name += components[i]; + full_name += '.'; + } + for (size_t i = N; i > 0; i--) { + full_name += name; + auto obj = table.Lookup(full_name); + if (obj) return obj; + auto len = full_name.size() - components[i - 1].size() - 1 - name.size(); + full_name.resize(len); + } + FLATBUFFERS_ASSERT(full_name.empty()); + return table.Lookup(name); // lookup in global namespace +} + +// Declare tokens we'll use. Single character tokens are represented by their +// ascii character code (e.g. '{'), others above 256. +// clang-format off +#define FLATBUFFERS_GEN_TOKENS(TD) \ + TD(Eof, 256, "end of file") \ + TD(StringConstant, 257, "string constant") \ + TD(IntegerConstant, 258, "integer constant") \ + TD(FloatConstant, 259, "float constant") \ + TD(Identifier, 260, "identifier") +#ifdef __GNUC__ +__extension__ // Stop GCC complaining about trailing comma with -Wpendantic. +#endif +enum { + #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) kToken ## NAME = VALUE, + FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN) + #undef FLATBUFFERS_TOKEN +}; + +static std::string TokenToString(int t) { + static const char * const tokens[] = { + #define FLATBUFFERS_TOKEN(NAME, VALUE, STRING) STRING, + FLATBUFFERS_GEN_TOKENS(FLATBUFFERS_TOKEN) + #undef FLATBUFFERS_TOKEN + #define FLATBUFFERS_TD(ENUM, IDLTYPE, ...) \ + IDLTYPE, + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + }; + if (t < 256) { // A single ascii char token. + std::string s; + s.append(1, static_cast<char>(t)); + return s; + } else { // Other tokens. + return tokens[t - 256]; + } +} +// clang-format on + +std::string Parser::TokenToStringId(int t) const { + return t == kTokenIdentifier ? attribute_ : TokenToString(t); +} + +// Parses exactly nibbles worth of hex digits into a number, or error. +CheckedError Parser::ParseHexNum(int nibbles, uint64_t *val) { + FLATBUFFERS_ASSERT(nibbles > 0); + for (int i = 0; i < nibbles; i++) + if (!is_xdigit(cursor_[i])) + return Error("escape code must be followed by " + NumToString(nibbles) + + " hex digits"); + std::string target(cursor_, cursor_ + nibbles); + *val = StringToUInt(target.c_str(), 16); + cursor_ += nibbles; + return NoError(); +} + +CheckedError Parser::SkipByteOrderMark() { + if (static_cast<unsigned char>(*cursor_) != 0xef) return NoError(); + cursor_++; + if (static_cast<unsigned char>(*cursor_) != 0xbb) + return Error("invalid utf-8 byte order mark"); + cursor_++; + if (static_cast<unsigned char>(*cursor_) != 0xbf) + return Error("invalid utf-8 byte order mark"); + cursor_++; + return NoError(); +} + +static inline bool IsIdentifierStart(char c) { + return is_alpha(c) || (c == '_'); +} + +CheckedError Parser::Next() { + doc_comment_.clear(); + bool seen_newline = cursor_ == source_; + attribute_.clear(); + attr_is_trivial_ascii_string_ = true; + for (;;) { + char c = *cursor_++; + token_ = c; + switch (c) { + case '\0': + cursor_--; + token_ = kTokenEof; + return NoError(); + case ' ': + case '\r': + case '\t': break; + case '\n': + MarkNewLine(); + seen_newline = true; + break; + case '{': + case '}': + case '(': + case ')': + case '[': + case ']': + case ',': + case ':': + case ';': + case '=': return NoError(); + case '\"': + case '\'': { + int unicode_high_surrogate = -1; + + while (*cursor_ != c) { + if (*cursor_ < ' ' && static_cast<signed char>(*cursor_) >= 0) + return Error("illegal character in string constant"); + if (*cursor_ == '\\') { + attr_is_trivial_ascii_string_ = false; // has escape sequence + cursor_++; + if (unicode_high_surrogate != -1 && *cursor_ != 'u') { + return Error( + "illegal Unicode sequence (unpaired high surrogate)"); + } + switch (*cursor_) { + case 'n': + attribute_ += '\n'; + cursor_++; + break; + case 't': + attribute_ += '\t'; + cursor_++; + break; + case 'r': + attribute_ += '\r'; + cursor_++; + break; + case 'b': + attribute_ += '\b'; + cursor_++; + break; + case 'f': + attribute_ += '\f'; + cursor_++; + break; + case '\"': + attribute_ += '\"'; + cursor_++; + break; + case '\'': + attribute_ += '\''; + cursor_++; + break; + case '\\': + attribute_ += '\\'; + cursor_++; + break; + case '/': + attribute_ += '/'; + cursor_++; + break; + case 'x': { // Not in the JSON standard + cursor_++; + uint64_t val; + ECHECK(ParseHexNum(2, &val)); + attribute_ += static_cast<char>(val); + break; + } + case 'u': { + cursor_++; + uint64_t val; + ECHECK(ParseHexNum(4, &val)); + if (val >= 0xD800 && val <= 0xDBFF) { + if (unicode_high_surrogate != -1) { + return Error( + "illegal Unicode sequence (multiple high surrogates)"); + } else { + unicode_high_surrogate = static_cast<int>(val); + } + } else if (val >= 0xDC00 && val <= 0xDFFF) { + if (unicode_high_surrogate == -1) { + return Error( + "illegal Unicode sequence (unpaired low surrogate)"); + } else { + int code_point = 0x10000 + + ((unicode_high_surrogate & 0x03FF) << 10) + + (val & 0x03FF); + ToUTF8(code_point, &attribute_); + unicode_high_surrogate = -1; + } + } else { + if (unicode_high_surrogate != -1) { + return Error( + "illegal Unicode sequence (unpaired high surrogate)"); + } + ToUTF8(static_cast<int>(val), &attribute_); + } + break; + } + default: return Error("unknown escape code in string constant"); + } + } else { // printable chars + UTF-8 bytes + if (unicode_high_surrogate != -1) { + return Error( + "illegal Unicode sequence (unpaired high surrogate)"); + } + // reset if non-printable + attr_is_trivial_ascii_string_ &= + check_ascii_range(*cursor_, ' ', '~'); + + attribute_ += *cursor_++; + } + } + if (unicode_high_surrogate != -1) { + return Error("illegal Unicode sequence (unpaired high surrogate)"); + } + cursor_++; + if (!attr_is_trivial_ascii_string_ && !opts.allow_non_utf8 && + !ValidateUTF8(attribute_)) { + return Error("illegal UTF-8 sequence"); + } + token_ = kTokenStringConstant; + return NoError(); + } + case '/': + if (*cursor_ == '/') { + const char *start = ++cursor_; + while (*cursor_ && *cursor_ != '\n' && *cursor_ != '\r') cursor_++; + if (*start == '/') { // documentation comment + if (!seen_newline) + return Error( + "a documentation comment should be on a line on its own"); + doc_comment_.push_back(std::string(start + 1, cursor_)); + } + break; + } else if (*cursor_ == '*') { + cursor_++; + // TODO: make nested. + while (*cursor_ != '*' || cursor_[1] != '/') { + if (*cursor_ == '\n') MarkNewLine(); + if (!*cursor_) return Error("end of file in comment"); + cursor_++; + } + cursor_ += 2; + break; + } + FLATBUFFERS_FALLTHROUGH(); // else fall thru + default: + if (IsIdentifierStart(c)) { + // Collect all chars of an identifier: + const char *start = cursor_ - 1; + while (IsIdentifierStart(*cursor_) || is_digit(*cursor_)) cursor_++; + attribute_.append(start, cursor_); + token_ = kTokenIdentifier; + return NoError(); + } + + const auto has_sign = (c == '+') || (c == '-'); + if (has_sign && IsIdentifierStart(*cursor_)) { + // '-'/'+' and following identifier - it could be a predefined + // constant. Return the sign in token_, see ParseSingleValue. + return NoError(); + } + + auto dot_lvl = + (c == '.') ? 0 : 1; // dot_lvl==0 <=> exactly one '.' seen + if (!dot_lvl && !is_digit(*cursor_)) return NoError(); // enum? + // Parser accepts hexadecimal-floating-literal (see C++ 5.13.4). + if (is_digit(c) || has_sign || !dot_lvl) { + const auto start = cursor_ - 1; + auto start_digits = !is_digit(c) ? cursor_ : cursor_ - 1; + if (!is_digit(c) && is_digit(*cursor_)) { + start_digits = cursor_; // see digit in cursor_ position + c = *cursor_++; + } + // hex-float can't begind with '.' + auto use_hex = dot_lvl && (c == '0') && is_alpha_char(*cursor_, 'X'); + if (use_hex) start_digits = ++cursor_; // '0x' is the prefix, skip it + // Read an integer number or mantisa of float-point number. + do { + if (use_hex) { + while (is_xdigit(*cursor_)) cursor_++; + } else { + while (is_digit(*cursor_)) cursor_++; + } + } while ((*cursor_ == '.') && (++cursor_) && (--dot_lvl >= 0)); + // Exponent of float-point number. + if ((dot_lvl >= 0) && (cursor_ > start_digits)) { + // The exponent suffix of hexadecimal float number is mandatory. + if (use_hex && !dot_lvl) start_digits = cursor_; + if ((use_hex && is_alpha_char(*cursor_, 'P')) || + is_alpha_char(*cursor_, 'E')) { + dot_lvl = 0; // Emulate dot to signal about float-point number. + cursor_++; + if (*cursor_ == '+' || *cursor_ == '-') cursor_++; + start_digits = cursor_; // the exponent-part has to have digits + // Exponent is decimal integer number + while (is_digit(*cursor_)) cursor_++; + if (*cursor_ == '.') { + cursor_++; // If see a dot treat it as part of invalid number. + dot_lvl = -1; // Fall thru to Error(). + } + } + } + // Finalize. + if ((dot_lvl >= 0) && (cursor_ > start_digits)) { + attribute_.append(start, cursor_); + token_ = dot_lvl ? kTokenIntegerConstant : kTokenFloatConstant; + return NoError(); + } else { + return Error("invalid number: " + std::string(start, cursor_)); + } + } + std::string ch; + ch = c; + if (false == check_ascii_range(c, ' ', '~')) + ch = "code: " + NumToString(c); + return Error("illegal character: " + ch); + } + } +} + +// Check if a given token is next. +bool Parser::Is(int t) const { return t == token_; } + +bool Parser::IsIdent(const char *id) const { + return token_ == kTokenIdentifier && attribute_ == id; +} + +// Expect a given token to be next, consume it, or error if not present. +CheckedError Parser::Expect(int t) { + if (t != token_) { + return Error("expecting: " + TokenToString(t) + + " instead got: " + TokenToStringId(token_)); + } + NEXT(); + return NoError(); +} + +CheckedError Parser::ParseNamespacing(std::string *id, std::string *last) { + while (Is('.')) { + NEXT(); + *id += "."; + *id += attribute_; + if (last) *last = attribute_; + EXPECT(kTokenIdentifier); + } + return NoError(); +} + +EnumDef *Parser::LookupEnum(const std::string &id) { + // Search thru parent namespaces. + return LookupTableByName(enums_, id, *current_namespace_, 0); +} + +StructDef *Parser::LookupStruct(const std::string &id) const { + auto sd = structs_.Lookup(id); + if (sd) sd->refcount++; + return sd; +} + +StructDef *Parser::LookupStructThruParentNamespaces( + const std::string &id) const { + auto sd = LookupTableByName(structs_, id, *current_namespace_, 1); + if (sd) sd->refcount++; + return sd; +} + +CheckedError Parser::ParseTypeIdent(Type &type) { + std::string id = attribute_; + EXPECT(kTokenIdentifier); + ECHECK(ParseNamespacing(&id, nullptr)); + auto enum_def = LookupEnum(id); + if (enum_def) { + type = enum_def->underlying_type; + if (enum_def->is_union) type.base_type = BASE_TYPE_UNION; + } else { + type.base_type = BASE_TYPE_STRUCT; + type.struct_def = LookupCreateStruct(id); + } + return NoError(); +} + +// Parse any IDL type. +CheckedError Parser::ParseType(Type &type) { + if (token_ == kTokenIdentifier) { + if (IsIdent("bool")) { + type.base_type = BASE_TYPE_BOOL; + NEXT(); + } else if (IsIdent("byte") || IsIdent("int8")) { + type.base_type = BASE_TYPE_CHAR; + NEXT(); + } else if (IsIdent("ubyte") || IsIdent("uint8")) { + type.base_type = BASE_TYPE_UCHAR; + NEXT(); + } else if (IsIdent("short") || IsIdent("int16")) { + type.base_type = BASE_TYPE_SHORT; + NEXT(); + } else if (IsIdent("ushort") || IsIdent("uint16")) { + type.base_type = BASE_TYPE_USHORT; + NEXT(); + } else if (IsIdent("int") || IsIdent("int32")) { + type.base_type = BASE_TYPE_INT; + NEXT(); + } else if (IsIdent("uint") || IsIdent("uint32")) { + type.base_type = BASE_TYPE_UINT; + NEXT(); + } else if (IsIdent("long") || IsIdent("int64")) { + type.base_type = BASE_TYPE_LONG; + NEXT(); + } else if (IsIdent("ulong") || IsIdent("uint64")) { + type.base_type = BASE_TYPE_ULONG; + NEXT(); + } else if (IsIdent("float") || IsIdent("float32")) { + type.base_type = BASE_TYPE_FLOAT; + NEXT(); + } else if (IsIdent("double") || IsIdent("float64")) { + type.base_type = BASE_TYPE_DOUBLE; + NEXT(); + } else if (IsIdent("string")) { + type.base_type = BASE_TYPE_STRING; + NEXT(); + } else { + ECHECK(ParseTypeIdent(type)); + } + } else if (token_ == '[') { + ParseDepthGuard depth_guard(this); + ECHECK(depth_guard.Check()); + NEXT(); + Type subtype; + ECHECK(ParseType(subtype)); + if (IsSeries(subtype)) { + // We could support this, but it will complicate things, and it's + // easier to work around with a struct around the inner vector. + return Error("nested vector types not supported (wrap in table first)"); + } + if (token_ == ':') { + NEXT(); + if (token_ != kTokenIntegerConstant) { + return Error("length of fixed-length array must be an integer value"); + } + uint16_t fixed_length = 0; + bool check = StringToNumber(attribute_.c_str(), &fixed_length); + if (!check || fixed_length < 1) { + return Error( + "length of fixed-length array must be positive and fit to " + "uint16_t type"); + } + type = Type(BASE_TYPE_ARRAY, subtype.struct_def, subtype.enum_def, + fixed_length); + NEXT(); + } else { + type = Type(BASE_TYPE_VECTOR, subtype.struct_def, subtype.enum_def); + } + type.element = subtype.base_type; + EXPECT(']'); + } else { + return Error("illegal type syntax"); + } + return NoError(); +} + +CheckedError Parser::AddField(StructDef &struct_def, const std::string &name, + const Type &type, FieldDef **dest) { + auto &field = *new FieldDef(); + field.value.offset = + FieldIndexToOffset(static_cast<voffset_t>(struct_def.fields.vec.size())); + field.name = name; + field.file = struct_def.file; + field.value.type = type; + if (struct_def.fixed) { // statically compute the field offset + auto size = InlineSize(type); + auto alignment = InlineAlignment(type); + // structs_ need to have a predictable format, so we need to align to + // the largest scalar + struct_def.minalign = std::max(struct_def.minalign, alignment); + struct_def.PadLastField(alignment); + field.value.offset = static_cast<voffset_t>(struct_def.bytesize); + struct_def.bytesize += size; + } + if (struct_def.fields.Add(name, &field)) + return Error("field already exists: " + name); + *dest = &field; + return NoError(); +} + +CheckedError Parser::ParseField(StructDef &struct_def) { + std::string name = attribute_; + + if (LookupCreateStruct(name, false, false)) + return Error("field name can not be the same as table/struct name"); + + if (!IsLowerSnakeCase(name)) { + Warning("field names should be lowercase snake_case, got: " + name); + } + + std::vector<std::string> dc = doc_comment_; + EXPECT(kTokenIdentifier); + EXPECT(':'); + Type type; + ECHECK(ParseType(type)); + + if (struct_def.fixed) { + auto valid = IsScalar(type.base_type) || IsStruct(type); + if (!valid && IsArray(type)) { + const auto &elem_type = type.VectorType(); + valid |= IsScalar(elem_type.base_type) || IsStruct(elem_type); + } + if (!valid) + return Error("structs may contain only scalar or struct fields"); + } + + if (!struct_def.fixed && IsArray(type)) + return Error("fixed-length array in table must be wrapped in struct"); + + if (IsArray(type)) { + advanced_features_ |= reflection::AdvancedArrayFeatures; + if (!SupportsAdvancedArrayFeatures()) { + return Error( + "Arrays are not yet supported in all " + "the specified programming languages."); + } + } + + FieldDef *typefield = nullptr; + if (type.base_type == BASE_TYPE_UNION) { + // For union fields, add a second auto-generated field to hold the type, + // with a special suffix. + ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(), + type.enum_def->underlying_type, &typefield)); + } else if (IsVector(type) && type.element == BASE_TYPE_UNION) { + advanced_features_ |= reflection::AdvancedUnionFeatures; + // Only cpp, js and ts supports the union vector feature so far. + if (!SupportsAdvancedUnionFeatures()) { + return Error( + "Vectors of unions are not yet supported in at least one of " + "the specified programming languages."); + } + // For vector of union fields, add a second auto-generated vector field to + // hold the types, with a special suffix. + Type union_vector(BASE_TYPE_VECTOR, nullptr, type.enum_def); + union_vector.element = BASE_TYPE_UTYPE; + ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(), union_vector, + &typefield)); + } + + FieldDef *field; + ECHECK(AddField(struct_def, name, type, &field)); + + if (token_ == '=') { + NEXT(); + ECHECK(ParseSingleValue(&field->name, field->value, true)); + if (IsStruct(type) || (struct_def.fixed && field->value.constant != "0")) + return Error( + "default values are not supported for struct fields, table fields, " + "or in structs."); + if (IsString(type) || IsVector(type)) { + advanced_features_ |= reflection::DefaultVectorsAndStrings; + if (field->value.constant != "0" && field->value.constant != "null" && + !SupportsDefaultVectorsAndStrings()) { + return Error( + "Default values for strings and vectors are not supported in one " + "of the specified programming languages"); + } + } + + if (IsVector(type) && field->value.constant != "0" && + field->value.constant != "[]") { + return Error("The only supported default for vectors is `[]`."); + } + } + + // Append .0 if the value has not it (skip hex and scientific floats). + // This suffix needed for generated C++ code. + if (IsFloat(type.base_type)) { + auto &text = field->value.constant; + FLATBUFFERS_ASSERT(false == text.empty()); + auto s = text.c_str(); + while (*s == ' ') s++; + if (*s == '-' || *s == '+') s++; + // 1) A float constants (nan, inf, pi, etc) is a kind of identifier. + // 2) A float number needn't ".0" at the end if it has exponent. + if ((false == IsIdentifierStart(*s)) && + (std::string::npos == field->value.constant.find_first_of(".eEpP"))) { + field->value.constant += ".0"; + } + } + + field->doc_comment = dc; + ECHECK(ParseMetaData(&field->attributes)); + field->deprecated = field->attributes.Lookup("deprecated") != nullptr; + auto hash_name = field->attributes.Lookup("hash"); + if (hash_name) { + switch ((IsVector(type)) ? type.element : type.base_type) { + case BASE_TYPE_SHORT: + case BASE_TYPE_USHORT: { + if (FindHashFunction16(hash_name->constant.c_str()) == nullptr) + return Error("Unknown hashing algorithm for 16 bit types: " + + hash_name->constant); + break; + } + case BASE_TYPE_INT: + case BASE_TYPE_UINT: { + if (FindHashFunction32(hash_name->constant.c_str()) == nullptr) + return Error("Unknown hashing algorithm for 32 bit types: " + + hash_name->constant); + break; + } + case BASE_TYPE_LONG: + case BASE_TYPE_ULONG: { + if (FindHashFunction64(hash_name->constant.c_str()) == nullptr) + return Error("Unknown hashing algorithm for 64 bit types: " + + hash_name->constant); + break; + } + default: + return Error( + "only short, ushort, int, uint, long and ulong data types support " + "hashing."); + } + } + + // For historical convenience reasons, string keys are assumed required. + // Scalars are kDefault unless otherwise specified. + // Nonscalars are kOptional unless required; + field->key = field->attributes.Lookup("key") != nullptr; + const bool required = field->attributes.Lookup("required") != nullptr || + (IsString(type) && field->key); + const bool default_str_or_vec = + ((IsString(type) || IsVector(type)) && field->value.constant != "0"); + const bool optional = IsScalar(type.base_type) + ? (field->value.constant == "null") + : !(required || default_str_or_vec); + if (required && optional) { + return Error("Fields cannot be both optional and required."); + } + field->presence = FieldDef::MakeFieldPresence(optional, required); + + if (required && (struct_def.fixed || IsScalar(type.base_type))) { + return Error("only non-scalar fields in tables may be 'required'"); + } + if (field->key) { + if (struct_def.has_key) return Error("only one field may be set as 'key'"); + struct_def.has_key = true; + if (!IsScalar(type.base_type) && !IsString(type)) { + return Error("'key' field must be string or scalar type"); + } + } + + if (field->IsScalarOptional()) { + advanced_features_ |= reflection::OptionalScalars; + if (type.enum_def && type.enum_def->Lookup("null")) { + FLATBUFFERS_ASSERT(IsInteger(type.base_type)); + return Error( + "the default 'null' is reserved for declaring optional scalar " + "fields, it conflicts with declaration of enum '" + + type.enum_def->name + "'."); + } + if (field->attributes.Lookup("key")) { + return Error( + "only a non-optional scalar field can be used as a 'key' field"); + } + if (!SupportsOptionalScalars()) { + return Error( + "Optional scalars are not yet supported in at least one the of " + "the specified programming languages."); + } + } + + if (type.enum_def) { + // Verify the enum's type and default value. + const std::string &constant = field->value.constant; + if (type.base_type == BASE_TYPE_UNION) { + if (constant != "0") { return Error("Union defaults must be NONE"); } + } else if (IsVector(type)) { + if (constant != "0" && constant != "[]") { + return Error("Vector defaults may only be `[]`."); + } + } else if (IsArray(type)) { + if (constant != "0") { + return Error("Array defaults are not supported yet."); + } + } else { + if (!IsInteger(type.base_type)) { + return Error("Enums must have integer base types"); + } + // Optional and bitflags enums may have default constants that are not + // their specified variants. + if (!field->IsOptional() && + type.enum_def->attributes.Lookup("bit_flags") == nullptr) { + if (type.enum_def->FindByValue(constant) == nullptr) { + return Error("default value of `" + constant + "` for " + "field `" + + name + "` is not part of enum `" + type.enum_def->name + + "`."); + } + } + } + } + + if (field->deprecated && struct_def.fixed) + return Error("can't deprecate fields in a struct"); + + auto cpp_type = field->attributes.Lookup("cpp_type"); + if (cpp_type) { + if (!hash_name) + return Error("cpp_type can only be used with a hashed field"); + /// forcing cpp_ptr_type to 'naked' if unset + auto cpp_ptr_type = field->attributes.Lookup("cpp_ptr_type"); + if (!cpp_ptr_type) { + auto val = new Value(); + val->type = cpp_type->type; + val->constant = "naked"; + field->attributes.Add("cpp_ptr_type", val); + } + } + + field->shared = field->attributes.Lookup("shared") != nullptr; + if (field->shared && field->value.type.base_type != BASE_TYPE_STRING) + return Error("shared can only be defined on strings"); + + auto field_native_custom_alloc = + field->attributes.Lookup("native_custom_alloc"); + if (field_native_custom_alloc) + return Error( + "native_custom_alloc can only be used with a table or struct " + "definition"); + + field->native_inline = field->attributes.Lookup("native_inline") != nullptr; + if (field->native_inline && !IsStruct(field->value.type)) + return Error("native_inline can only be defined on structs"); + + auto nested = field->attributes.Lookup("nested_flatbuffer"); + if (nested) { + if (nested->type.base_type != BASE_TYPE_STRING) + return Error( + "nested_flatbuffer attribute must be a string (the root type)"); + if (type.base_type != BASE_TYPE_VECTOR || type.element != BASE_TYPE_UCHAR) + return Error( + "nested_flatbuffer attribute may only apply to a vector of ubyte"); + // This will cause an error if the root type of the nested flatbuffer + // wasn't defined elsewhere. + field->nested_flatbuffer = LookupCreateStruct(nested->constant); + } + + if (field->attributes.Lookup("flexbuffer")) { + field->flexbuffer = true; + uses_flexbuffers_ = true; + if (type.base_type != BASE_TYPE_VECTOR || type.element != BASE_TYPE_UCHAR) + return Error("flexbuffer attribute may only apply to a vector of ubyte"); + } + + if (typefield) { + if (!IsScalar(typefield->value.type.base_type)) { + // this is a union vector field + typefield->presence = field->presence; + } + // If this field is a union, and it has a manually assigned id, + // the automatically added type field should have an id as well (of N - 1). + auto attr = field->attributes.Lookup("id"); + if (attr) { + const auto &id_str = attr->constant; + voffset_t id = 0; + const auto done = !atot(id_str.c_str(), *this, &id).Check(); + if (done && id > 0) { + auto val = new Value(); + val->type = attr->type; + val->constant = NumToString(id - 1); + typefield->attributes.Add("id", val); + } else { + return Error( + "a union type effectively adds two fields with non-negative ids, " + "its id must be that of the second field (the first field is " + "the type field and not explicitly declared in the schema);\n" + "field: " + + field->name + ", id: " + id_str); + } + } + // if this field is a union that is deprecated, + // the automatically added type field should be deprecated as well + if (field->deprecated) { typefield->deprecated = true; } + } + + EXPECT(';'); + return NoError(); +} + +CheckedError Parser::ParseString(Value &val, bool use_string_pooling) { + auto s = attribute_; + EXPECT(kTokenStringConstant); + if (use_string_pooling) { + val.constant = NumToString(builder_.CreateSharedString(s).o); + } else { + val.constant = NumToString(builder_.CreateString(s).o); + } + return NoError(); +} + +CheckedError Parser::ParseComma() { + if (!opts.protobuf_ascii_alike) EXPECT(','); + return NoError(); +} + +CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field, + size_t parent_fieldn, + const StructDef *parent_struct_def, + uoffset_t count, bool inside_vector) { + switch (val.type.base_type) { + case BASE_TYPE_UNION: { + FLATBUFFERS_ASSERT(field); + std::string constant; + Vector<uint8_t> *vector_of_union_types = nullptr; + // Find corresponding type field we may have already parsed. + for (auto elem = field_stack_.rbegin() + count; + elem != field_stack_.rbegin() + parent_fieldn + count; ++elem) { + auto &type = elem->second->value.type; + if (type.enum_def == val.type.enum_def) { + if (inside_vector) { + if (IsVector(type) && type.element == BASE_TYPE_UTYPE) { + // Vector of union type field. + uoffset_t offset; + ECHECK(atot(elem->first.constant.c_str(), *this, &offset)); + vector_of_union_types = reinterpret_cast<Vector<uint8_t> *>( + builder_.GetCurrentBufferPointer() + builder_.GetSize() - + offset); + break; + } + } else { + if (type.base_type == BASE_TYPE_UTYPE) { + // Union type field. + constant = elem->first.constant; + break; + } + } + } + } + if (constant.empty() && !inside_vector) { + // We haven't seen the type field yet. Sadly a lot of JSON writers + // output these in alphabetical order, meaning it comes after this + // value. So we scan past the value to find it, then come back here. + // We currently don't do this for vectors of unions because the + // scanning/serialization logic would get very complicated. + auto type_name = field->name + UnionTypeFieldSuffix(); + FLATBUFFERS_ASSERT(parent_struct_def); + auto type_field = parent_struct_def->fields.Lookup(type_name); + FLATBUFFERS_ASSERT(type_field); // Guaranteed by ParseField(). + // Remember where we are in the source file, so we can come back here. + auto backup = *static_cast<ParserState *>(this); + ECHECK(SkipAnyJsonValue()); // The table. + ECHECK(ParseComma()); + auto next_name = attribute_; + if (Is(kTokenStringConstant)) { + NEXT(); + } else { + EXPECT(kTokenIdentifier); + } + if (next_name == type_name) { + EXPECT(':'); + ParseDepthGuard depth_guard(this); + ECHECK(depth_guard.Check()); + Value type_val = type_field->value; + ECHECK(ParseAnyValue(type_val, type_field, 0, nullptr, 0)); + constant = type_val.constant; + // Got the information we needed, now rewind: + *static_cast<ParserState *>(this) = backup; + } + } + if (constant.empty() && !vector_of_union_types) { + return Error("missing type field for this union value: " + field->name); + } + uint8_t enum_idx; + if (vector_of_union_types) { + enum_idx = vector_of_union_types->Get(count); + } else { + ECHECK(atot(constant.c_str(), *this, &enum_idx)); + } + auto enum_val = val.type.enum_def->ReverseLookup(enum_idx, true); + if (!enum_val) return Error("illegal type id for: " + field->name); + if (enum_val->union_type.base_type == BASE_TYPE_STRUCT) { + ECHECK(ParseTable(*enum_val->union_type.struct_def, &val.constant, + nullptr)); + if (enum_val->union_type.struct_def->fixed) { + // All BASE_TYPE_UNION values are offsets, so turn this into one. + SerializeStruct(*enum_val->union_type.struct_def, val); + builder_.ClearOffsets(); + val.constant = NumToString(builder_.GetSize()); + } + } else if (IsString(enum_val->union_type)) { + ECHECK(ParseString(val, field->shared)); + } else { + FLATBUFFERS_ASSERT(false); + } + break; + } + case BASE_TYPE_STRUCT: + ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr)); + break; + case BASE_TYPE_STRING: { + ECHECK(ParseString(val, field->shared)); + break; + } + case BASE_TYPE_VECTOR: { + uoffset_t off; + ECHECK(ParseVector(val.type.VectorType(), &off, field, parent_fieldn)); + val.constant = NumToString(off); + break; + } + case BASE_TYPE_ARRAY: { + ECHECK(ParseArray(val)); + break; + } + case BASE_TYPE_INT: + case BASE_TYPE_UINT: + case BASE_TYPE_LONG: + case BASE_TYPE_ULONG: { + if (field && field->attributes.Lookup("hash") && + (token_ == kTokenIdentifier || token_ == kTokenStringConstant)) { + ECHECK(ParseHash(val, field)); + } else { + ECHECK(ParseSingleValue(field ? &field->name : nullptr, val, false)); + } + break; + } + default: + ECHECK(ParseSingleValue(field ? &field->name : nullptr, val, false)); + break; + } + return NoError(); +} + +void Parser::SerializeStruct(const StructDef &struct_def, const Value &val) { + SerializeStruct(builder_, struct_def, val); +} + +void Parser::SerializeStruct(FlatBufferBuilder &builder, + const StructDef &struct_def, const Value &val) { + FLATBUFFERS_ASSERT(val.constant.length() == struct_def.bytesize); + builder.Align(struct_def.minalign); + builder.PushBytes(reinterpret_cast<const uint8_t *>(val.constant.c_str()), + struct_def.bytesize); + builder.AddStructOffset(val.offset, builder.GetSize()); +} + +template<typename F> +CheckedError Parser::ParseTableDelimiters(size_t &fieldn, + const StructDef *struct_def, F body) { + // We allow tables both as JSON object{ .. } with field names + // or vector[..] with all fields in order + char terminator = '}'; + bool is_nested_vector = struct_def && Is('['); + if (is_nested_vector) { + NEXT(); + terminator = ']'; + } else { + EXPECT('{'); + } + for (;;) { + if ((!opts.strict_json || !fieldn) && Is(terminator)) break; + std::string name; + if (is_nested_vector) { + if (fieldn >= struct_def->fields.vec.size()) { + return Error("too many unnamed fields in nested array"); + } + name = struct_def->fields.vec[fieldn]->name; + } else { + name = attribute_; + if (Is(kTokenStringConstant)) { + NEXT(); + } else { + EXPECT(opts.strict_json ? kTokenStringConstant : kTokenIdentifier); + } + if (!opts.protobuf_ascii_alike || !(Is('{') || Is('['))) EXPECT(':'); + } + ECHECK(body(name, fieldn, struct_def)); + if (Is(terminator)) break; + ECHECK(ParseComma()); + } + NEXT(); + if (is_nested_vector && fieldn != struct_def->fields.vec.size()) { + return Error("wrong number of unnamed fields in table vector"); + } + return NoError(); +} + +CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value, + uoffset_t *ovalue) { + ParseDepthGuard depth_guard(this); + ECHECK(depth_guard.Check()); + + size_t fieldn_outer = 0; + auto err = ParseTableDelimiters( + fieldn_outer, &struct_def, + [&](const std::string &name, size_t &fieldn, + const StructDef *struct_def_inner) -> CheckedError { + if (name == "$schema") { + ECHECK(Expect(kTokenStringConstant)); + return NoError(); + } + auto field = struct_def_inner->fields.Lookup(name); + if (!field) { + if (!opts.skip_unexpected_fields_in_json) { + return Error("unknown field: " + name); + } else { + ECHECK(SkipAnyJsonValue()); + } + } else { + if (IsIdent("null") && !IsScalar(field->value.type.base_type)) { + ECHECK(Next()); // Ignore this field. + } else { + Value val = field->value; + if (field->flexbuffer) { + flexbuffers::Builder builder(1024, + flexbuffers::BUILDER_FLAG_SHARE_ALL); + ECHECK(ParseFlexBufferValue(&builder)); + builder.Finish(); + // Force alignment for nested flexbuffer + builder_.ForceVectorAlignment(builder.GetSize(), sizeof(uint8_t), + sizeof(largest_scalar_t)); + auto off = builder_.CreateVector(builder.GetBuffer()); + val.constant = NumToString(off.o); + } else if (field->nested_flatbuffer) { + ECHECK( + ParseNestedFlatbuffer(val, field, fieldn, struct_def_inner)); + } else { + ECHECK(ParseAnyValue(val, field, fieldn, struct_def_inner, 0)); + } + // Hardcoded insertion-sort with error-check. + // If fields are specified in order, then this loop exits + // immediately. + auto elem = field_stack_.rbegin(); + for (; elem != field_stack_.rbegin() + fieldn; ++elem) { + auto existing_field = elem->second; + if (existing_field == field) + return Error("field set more than once: " + field->name); + if (existing_field->value.offset < field->value.offset) break; + } + // Note: elem points to before the insertion point, thus .base() + // points to the correct spot. + field_stack_.insert(elem.base(), std::make_pair(val, field)); + fieldn++; + } + } + return NoError(); + }); + ECHECK(err); + + // Check if all required fields are parsed. + for (auto field_it = struct_def.fields.vec.begin(); + field_it != struct_def.fields.vec.end(); ++field_it) { + auto required_field = *field_it; + if (!required_field->IsRequired()) { continue; } + bool found = false; + for (auto pf_it = field_stack_.end() - fieldn_outer; + pf_it != field_stack_.end(); ++pf_it) { + auto parsed_field = pf_it->second; + if (parsed_field == required_field) { + found = true; + break; + } + } + if (!found) { + return Error("required field is missing: " + required_field->name + + " in " + struct_def.name); + } + } + + if (struct_def.fixed && fieldn_outer != struct_def.fields.vec.size()) + return Error("struct: wrong number of initializers: " + struct_def.name); + + auto start = struct_def.fixed ? builder_.StartStruct(struct_def.minalign) + : builder_.StartTable(); + + for (size_t size = struct_def.sortbysize ? sizeof(largest_scalar_t) : 1; size; + size /= 2) { + // Go through elements in reverse, since we're building the data backwards. + for (auto it = field_stack_.rbegin(); + it != field_stack_.rbegin() + fieldn_outer; ++it) { + auto &field_value = it->first; + auto field = it->second; + if (!struct_def.sortbysize || + size == SizeOf(field_value.type.base_type)) { + switch (field_value.type.base_type) { + // clang-format off + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ + case BASE_TYPE_ ## ENUM: \ + builder_.Pad(field->padding); \ + if (struct_def.fixed) { \ + CTYPE val; \ + ECHECK(atot(field_value.constant.c_str(), *this, &val)); \ + builder_.PushElement(val); \ + } else { \ + CTYPE val, valdef; \ + ECHECK(atot(field_value.constant.c_str(), *this, &val)); \ + ECHECK(atot(field->value.constant.c_str(), *this, &valdef)); \ + builder_.AddElement(field_value.offset, val, valdef); \ + } \ + break; + FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ + case BASE_TYPE_ ## ENUM: \ + builder_.Pad(field->padding); \ + if (IsStruct(field->value.type)) { \ + SerializeStruct(*field->value.type.struct_def, field_value); \ + } else { \ + CTYPE val; \ + ECHECK(atot(field_value.constant.c_str(), *this, &val)); \ + builder_.AddOffset(field_value.offset, val); \ + } \ + break; + FLATBUFFERS_GEN_TYPES_POINTER(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + case BASE_TYPE_ARRAY: + builder_.Pad(field->padding); + builder_.PushBytes( + reinterpret_cast<const uint8_t*>(field_value.constant.c_str()), + InlineSize(field_value.type)); + break; + // clang-format on + } + } + } + } + for (size_t i = 0; i < fieldn_outer; i++) field_stack_.pop_back(); + + if (struct_def.fixed) { + builder_.ClearOffsets(); + builder_.EndStruct(); + FLATBUFFERS_ASSERT(value); + // Temporarily store this struct in the value string, since it is to + // be serialized in-place elsewhere. + value->assign( + reinterpret_cast<const char *>(builder_.GetCurrentBufferPointer()), + struct_def.bytesize); + builder_.PopBytes(struct_def.bytesize); + FLATBUFFERS_ASSERT(!ovalue); + } else { + auto val = builder_.EndTable(start); + if (ovalue) *ovalue = val; + if (value) *value = NumToString(val); + } + return NoError(); +} + +template<typename F> +CheckedError Parser::ParseVectorDelimiters(uoffset_t &count, F body) { + EXPECT('['); + for (;;) { + if ((!opts.strict_json || !count) && Is(']')) break; + ECHECK(body(count)); + count++; + if (Is(']')) break; + ECHECK(ParseComma()); + } + NEXT(); + return NoError(); +} + +static bool CompareSerializedScalars(const uint8_t *a, const uint8_t *b, + const FieldDef &key) { + switch (key.value.type.base_type) { +#define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ + case BASE_TYPE_##ENUM: { \ + CTYPE def = static_cast<CTYPE>(0); \ + if (!a || !b) { StringToNumber(key.value.constant.c_str(), &def); } \ + const auto av = a ? ReadScalar<CTYPE>(a) : def; \ + const auto bv = b ? ReadScalar<CTYPE>(b) : def; \ + return av < bv; \ + } + FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD) +#undef FLATBUFFERS_TD + default: { + FLATBUFFERS_ASSERT(false && "scalar type expected"); + return false; + } + } +} + +static bool CompareTablesByScalarKey(const Offset<Table> *_a, + const Offset<Table> *_b, + const FieldDef &key) { + const voffset_t offset = key.value.offset; + // Indirect offset pointer to table pointer. + auto a = reinterpret_cast<const uint8_t *>(_a) + ReadScalar<uoffset_t>(_a); + auto b = reinterpret_cast<const uint8_t *>(_b) + ReadScalar<uoffset_t>(_b); + // Fetch field address from table. + a = reinterpret_cast<const Table *>(a)->GetAddressOf(offset); + b = reinterpret_cast<const Table *>(b)->GetAddressOf(offset); + return CompareSerializedScalars(a, b, key); +} + +static bool CompareTablesByStringKey(const Offset<Table> *_a, + const Offset<Table> *_b, + const FieldDef &key) { + const voffset_t offset = key.value.offset; + // Indirect offset pointer to table pointer. + auto a = reinterpret_cast<const uint8_t *>(_a) + ReadScalar<uoffset_t>(_a); + auto b = reinterpret_cast<const uint8_t *>(_b) + ReadScalar<uoffset_t>(_b); + // Fetch field address from table. + a = reinterpret_cast<const Table *>(a)->GetAddressOf(offset); + b = reinterpret_cast<const Table *>(b)->GetAddressOf(offset); + if (a && b) { + // Indirect offset pointer to string pointer. + a += ReadScalar<uoffset_t>(a); + b += ReadScalar<uoffset_t>(b); + return *reinterpret_cast<const String *>(a) < + *reinterpret_cast<const String *>(b); + } else { + return a ? true : false; + } +} + +static void SwapSerializedTables(Offset<Table> *a, Offset<Table> *b) { + // These are serialized offsets, so are relative where they are + // stored in memory, so compute the distance between these pointers: + ptrdiff_t diff = (b - a) * sizeof(Offset<Table>); + FLATBUFFERS_ASSERT(diff >= 0); // Guaranteed by SimpleQsort. + auto udiff = static_cast<uoffset_t>(diff); + a->o = EndianScalar(ReadScalar<uoffset_t>(a) - udiff); + b->o = EndianScalar(ReadScalar<uoffset_t>(b) + udiff); + std::swap(*a, *b); +} + +// See below for why we need our own sort :( +template<typename T, typename F, typename S> +void SimpleQsort(T *begin, T *end, size_t width, F comparator, S swapper) { + if (end - begin <= static_cast<ptrdiff_t>(width)) return; + auto l = begin + width; + auto r = end; + while (l < r) { + if (comparator(begin, l)) { + r -= width; + swapper(l, r); + } else { + l += width; + } + } + l -= width; + swapper(begin, l); + SimpleQsort(begin, l, width, comparator, swapper); + SimpleQsort(r, end, width, comparator, swapper); +} + +CheckedError Parser::ParseAlignAttribute(const std::string &align_constant, + size_t min_align, size_t *align) { + // Use uint8_t to avoid problems with size_t==`unsigned long` on LP64. + uint8_t align_value; + if (StringToNumber(align_constant.c_str(), &align_value) && + VerifyAlignmentRequirements(static_cast<size_t>(align_value), + min_align)) { + *align = align_value; + return NoError(); + } + return Error("unexpected force_align value '" + align_constant + + "', alignment must be a power of two integer ranging from the " + "type\'s natural alignment " + + NumToString(min_align) + " to " + + NumToString(FLATBUFFERS_MAX_ALIGNMENT)); +} + +CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue, + FieldDef *field, size_t fieldn) { + uoffset_t count = 0; + auto err = ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError { + Value val; + val.type = type; + ECHECK(ParseAnyValue(val, field, fieldn, nullptr, count, true)); + field_stack_.push_back(std::make_pair(val, nullptr)); + return NoError(); + }); + ECHECK(err); + + const size_t len = count * InlineSize(type) / InlineAlignment(type); + const size_t elemsize = InlineAlignment(type); + const auto force_align = field->attributes.Lookup("force_align"); + if (force_align) { + size_t align; + ECHECK(ParseAlignAttribute(force_align->constant, 1, &align)); + if (align > 1) { builder_.ForceVectorAlignment(len, elemsize, align); } + } + + builder_.StartVector(len, elemsize); + for (uoffset_t i = 0; i < count; i++) { + // start at the back, since we're building the data backwards. + auto &val = field_stack_.back().first; + switch (val.type.base_type) { + // clang-format off + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE,...) \ + case BASE_TYPE_ ## ENUM: \ + if (IsStruct(val.type)) SerializeStruct(*val.type.struct_def, val); \ + else { \ + CTYPE elem; \ + ECHECK(atot(val.constant.c_str(), *this, &elem)); \ + builder_.PushElement(elem); \ + } \ + break; + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + // clang-format on + } + field_stack_.pop_back(); + } + + builder_.ClearOffsets(); + *ovalue = builder_.EndVector(count); + + if (type.base_type == BASE_TYPE_STRUCT && type.struct_def->has_key) { + // We should sort this vector. Find the key first. + const FieldDef *key = nullptr; + for (auto it = type.struct_def->fields.vec.begin(); + it != type.struct_def->fields.vec.end(); ++it) { + if ((*it)->key) { + key = (*it); + break; + } + } + FLATBUFFERS_ASSERT(key); + // Now sort it. + // We can't use std::sort because for structs the size is not known at + // compile time, and for tables our iterators dereference offsets, so can't + // be used to swap elements. + // And we can't use C qsort either, since that would force use to use + // globals, making parsing thread-unsafe. + // So for now, we use SimpleQsort above. + // TODO: replace with something better, preferably not recursive. + + if (type.struct_def->fixed) { + const voffset_t offset = key->value.offset; + const size_t struct_size = type.struct_def->bytesize; + auto v = + reinterpret_cast<VectorOfAny *>(builder_.GetCurrentBufferPointer()); + SimpleQsort<uint8_t>( + v->Data(), v->Data() + v->size() * type.struct_def->bytesize, + type.struct_def->bytesize, + [offset, key](const uint8_t *a, const uint8_t *b) -> bool { + return CompareSerializedScalars(a + offset, b + offset, *key); + }, + [struct_size](uint8_t *a, uint8_t *b) { + // FIXME: faster? + for (size_t i = 0; i < struct_size; i++) { std::swap(a[i], b[i]); } + }); + } else { + auto v = reinterpret_cast<Vector<Offset<Table>> *>( + builder_.GetCurrentBufferPointer()); + // Here also can't use std::sort. We do have an iterator type for it, + // but it is non-standard as it will dereference the offsets, and thus + // can't be used to swap elements. + if (key->value.type.base_type == BASE_TYPE_STRING) { + SimpleQsort<Offset<Table>>( + v->data(), v->data() + v->size(), 1, + [key](const Offset<Table> *_a, const Offset<Table> *_b) -> bool { + return CompareTablesByStringKey(_a, _b, *key); + }, + SwapSerializedTables); + } else { + SimpleQsort<Offset<Table>>( + v->data(), v->data() + v->size(), 1, + [key](const Offset<Table> *_a, const Offset<Table> *_b) -> bool { + return CompareTablesByScalarKey(_a, _b, *key); + }, + SwapSerializedTables); + } + } + } + return NoError(); +} + +CheckedError Parser::ParseArray(Value &array) { + std::vector<Value> stack; + FlatBufferBuilder builder; + const auto &type = array.type.VectorType(); + auto length = array.type.fixed_length; + uoffset_t count = 0; + auto err = ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError { + vector_emplace_back(&stack, Value()); + auto &val = stack.back(); + val.type = type; + if (IsStruct(type)) { + ECHECK(ParseTable(*val.type.struct_def, &val.constant, nullptr)); + } else { + ECHECK(ParseSingleValue(nullptr, val, false)); + } + return NoError(); + }); + ECHECK(err); + if (length != count) return Error("Fixed-length array size is incorrect."); + + for (auto it = stack.rbegin(); it != stack.rend(); ++it) { + auto &val = *it; + // clang-format off + switch (val.type.base_type) { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ + case BASE_TYPE_ ## ENUM: \ + if (IsStruct(val.type)) { \ + SerializeStruct(builder, *val.type.struct_def, val); \ + } else { \ + CTYPE elem; \ + ECHECK(atot(val.constant.c_str(), *this, &elem)); \ + builder.PushElement(elem); \ + } \ + break; + FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + default: FLATBUFFERS_ASSERT(0); + } + // clang-format on + } + + array.constant.assign( + reinterpret_cast<const char *>(builder.GetCurrentBufferPointer()), + InlineSize(array.type)); + return NoError(); +} + +CheckedError Parser::ParseNestedFlatbuffer(Value &val, FieldDef *field, + size_t fieldn, + const StructDef *parent_struct_def) { + if (token_ == '[') { // backwards compat for 'legacy' ubyte buffers + ECHECK(ParseAnyValue(val, field, fieldn, parent_struct_def, 0)); + } else { + auto cursor_at_value_begin = cursor_; + ECHECK(SkipAnyJsonValue()); + std::string substring(cursor_at_value_begin - 1, cursor_ - 1); + + // Create and initialize new parser + Parser nested_parser; + FLATBUFFERS_ASSERT(field->nested_flatbuffer); + nested_parser.root_struct_def_ = field->nested_flatbuffer; + nested_parser.enums_ = enums_; + nested_parser.opts = opts; + nested_parser.uses_flexbuffers_ = uses_flexbuffers_; + nested_parser.parse_depth_counter_ = parse_depth_counter_; + // Parse JSON substring into new flatbuffer builder using nested_parser + bool ok = nested_parser.Parse(substring.c_str(), nullptr, nullptr); + + // Clean nested_parser to avoid deleting the elements in + // the SymbolTables on destruction + nested_parser.enums_.dict.clear(); + nested_parser.enums_.vec.clear(); + + if (!ok) { ECHECK(Error(nested_parser.error_)); } + // Force alignment for nested flatbuffer + builder_.ForceVectorAlignment( + nested_parser.builder_.GetSize(), sizeof(uint8_t), + nested_parser.builder_.GetBufferMinAlignment()); + + auto off = builder_.CreateVector(nested_parser.builder_.GetBufferPointer(), + nested_parser.builder_.GetSize()); + val.constant = NumToString(off.o); + } + return NoError(); +} + +CheckedError Parser::ParseMetaData(SymbolTable<Value> *attributes) { + if (Is('(')) { + NEXT(); + for (;;) { + auto name = attribute_; + if (false == (Is(kTokenIdentifier) || Is(kTokenStringConstant))) + return Error("attribute name must be either identifier or string: " + + name); + if (known_attributes_.find(name) == known_attributes_.end()) + return Error("user define attributes must be declared before use: " + + name); + NEXT(); + auto e = new Value(); + if (attributes->Add(name, e)) Warning("attribute already found: " + name); + if (Is(':')) { + NEXT(); + ECHECK(ParseSingleValue(&name, *e, true)); + } + if (Is(')')) { + NEXT(); + break; + } + EXPECT(','); + } + } + return NoError(); +} + +CheckedError Parser::ParseEnumFromString(const Type &type, + std::string *result) { + const auto base_type = + type.enum_def ? type.enum_def->underlying_type.base_type : type.base_type; + if (!IsInteger(base_type)) return Error("not a valid value for this field"); + uint64_t u64 = 0; + for (size_t pos = 0; pos != std::string::npos;) { + const auto delim = attribute_.find_first_of(' ', pos); + const auto last = (std::string::npos == delim); + auto word = attribute_.substr(pos, !last ? delim - pos : std::string::npos); + pos = !last ? delim + 1 : std::string::npos; + const EnumVal *ev = nullptr; + if (type.enum_def) { + ev = type.enum_def->Lookup(word); + } else { + auto dot = word.find_first_of('.'); + if (std::string::npos == dot) + return Error("enum values need to be qualified by an enum type"); + auto enum_def_str = word.substr(0, dot); + const auto enum_def = LookupEnum(enum_def_str); + if (!enum_def) return Error("unknown enum: " + enum_def_str); + auto enum_val_str = word.substr(dot + 1); + ev = enum_def->Lookup(enum_val_str); + } + if (!ev) return Error("unknown enum value: " + word); + u64 |= ev->GetAsUInt64(); + } + *result = IsUnsigned(base_type) ? NumToString(u64) + : NumToString(static_cast<int64_t>(u64)); + return NoError(); +} + +CheckedError Parser::ParseHash(Value &e, FieldDef *field) { + FLATBUFFERS_ASSERT(field); + Value *hash_name = field->attributes.Lookup("hash"); + switch (e.type.base_type) { + case BASE_TYPE_SHORT: { + auto hash = FindHashFunction16(hash_name->constant.c_str()); + int16_t hashed_value = static_cast<int16_t>(hash(attribute_.c_str())); + e.constant = NumToString(hashed_value); + break; + } + case BASE_TYPE_USHORT: { + auto hash = FindHashFunction16(hash_name->constant.c_str()); + uint16_t hashed_value = hash(attribute_.c_str()); + e.constant = NumToString(hashed_value); + break; + } + case BASE_TYPE_INT: { + auto hash = FindHashFunction32(hash_name->constant.c_str()); + int32_t hashed_value = static_cast<int32_t>(hash(attribute_.c_str())); + e.constant = NumToString(hashed_value); + break; + } + case BASE_TYPE_UINT: { + auto hash = FindHashFunction32(hash_name->constant.c_str()); + uint32_t hashed_value = hash(attribute_.c_str()); + e.constant = NumToString(hashed_value); + break; + } + case BASE_TYPE_LONG: { + auto hash = FindHashFunction64(hash_name->constant.c_str()); + int64_t hashed_value = static_cast<int64_t>(hash(attribute_.c_str())); + e.constant = NumToString(hashed_value); + break; + } + case BASE_TYPE_ULONG: { + auto hash = FindHashFunction64(hash_name->constant.c_str()); + uint64_t hashed_value = hash(attribute_.c_str()); + e.constant = NumToString(hashed_value); + break; + } + default: FLATBUFFERS_ASSERT(0); + } + NEXT(); + return NoError(); +} + +CheckedError Parser::TokenError() { + return Error("cannot parse value starting with: " + TokenToStringId(token_)); +} + +// Re-pack helper (ParseSingleValue) to normalize defaults of scalars. +template<typename T> inline void SingleValueRepack(Value &e, T val) { + // Remove leading zeros. + if (IsInteger(e.type.base_type)) { e.constant = NumToString(val); } +} +#if defined(FLATBUFFERS_HAS_NEW_STRTOD) && (FLATBUFFERS_HAS_NEW_STRTOD > 0) +// Normalize defaults NaN to unsigned quiet-NaN(0) if value was parsed from +// hex-float literal. +static inline void SingleValueRepack(Value &e, float val) { + if (val != val) e.constant = "nan"; +} +static inline void SingleValueRepack(Value &e, double val) { + if (val != val) e.constant = "nan"; +} +#endif + +CheckedError Parser::ParseFunction(const std::string *name, Value &e) { + ParseDepthGuard depth_guard(this); + ECHECK(depth_guard.Check()); + + // Copy name, attribute will be changed on NEXT(). + const auto functionname = attribute_; + if (!IsFloat(e.type.base_type)) { + return Error(functionname + ": type of argument mismatch, expecting: " + + kTypeNames[BASE_TYPE_DOUBLE] + + ", found: " + kTypeNames[e.type.base_type] + + ", name: " + (name ? *name : "") + ", value: " + e.constant); + } + NEXT(); + EXPECT('('); + ECHECK(ParseSingleValue(name, e, false)); + EXPECT(')'); + // calculate with double precision + double x, y = 0.0; + ECHECK(atot(e.constant.c_str(), *this, &x)); + // clang-format off + auto func_match = false; + #define FLATBUFFERS_FN_DOUBLE(name, op) \ + if (!func_match && functionname == name) { y = op; func_match = true; } + FLATBUFFERS_FN_DOUBLE("deg", x / kPi * 180); + FLATBUFFERS_FN_DOUBLE("rad", x * kPi / 180); + FLATBUFFERS_FN_DOUBLE("sin", sin(x)); + FLATBUFFERS_FN_DOUBLE("cos", cos(x)); + FLATBUFFERS_FN_DOUBLE("tan", tan(x)); + FLATBUFFERS_FN_DOUBLE("asin", asin(x)); + FLATBUFFERS_FN_DOUBLE("acos", acos(x)); + FLATBUFFERS_FN_DOUBLE("atan", atan(x)); + // TODO(wvo): add more useful conversion functions here. + #undef FLATBUFFERS_FN_DOUBLE + // clang-format on + if (true != func_match) { + return Error(std::string("Unknown conversion function: ") + functionname + + ", field name: " + (name ? *name : "") + + ", value: " + e.constant); + } + e.constant = NumToString(y); + return NoError(); +} + +CheckedError Parser::TryTypedValue(const std::string *name, int dtoken, + bool check, Value &e, BaseType req, + bool *destmatch) { + FLATBUFFERS_ASSERT(*destmatch == false && dtoken == token_); + *destmatch = true; + e.constant = attribute_; + // Check token match + if (!check) { + if (e.type.base_type == BASE_TYPE_NONE) { + e.type.base_type = req; + } else { + return Error(std::string("type mismatch: expecting: ") + + kTypeNames[e.type.base_type] + + ", found: " + kTypeNames[req] + + ", name: " + (name ? *name : "") + ", value: " + e.constant); + } + } + // The exponent suffix of hexadecimal float-point number is mandatory. + // A hex-integer constant is forbidden as an initializer of float number. + if ((kTokenFloatConstant != dtoken) && IsFloat(e.type.base_type)) { + const auto &s = e.constant; + const auto k = s.find_first_of("0123456789."); + if ((std::string::npos != k) && (s.length() > (k + 1)) && + (s[k] == '0' && is_alpha_char(s[k + 1], 'X')) && + (std::string::npos == s.find_first_of("pP", k + 2))) { + return Error( + "invalid number, the exponent suffix of hexadecimal " + "floating-point literals is mandatory: \"" + + s + "\""); + } + } + NEXT(); + return NoError(); +} + +CheckedError Parser::ParseSingleValue(const std::string *name, Value &e, + bool check_now) { + if (token_ == '+' || token_ == '-') { + const char sign = static_cast<char>(token_); + // Get an indentifier: NAN, INF, or function name like cos/sin/deg. + NEXT(); + if (token_ != kTokenIdentifier) return Error("constant name expected"); + attribute_.insert(size_t(0), size_t(1), sign); + } + + const auto in_type = e.type.base_type; + const auto is_tok_ident = (token_ == kTokenIdentifier); + const auto is_tok_string = (token_ == kTokenStringConstant); + + // First see if this could be a conversion function. + if (is_tok_ident && *cursor_ == '(') { return ParseFunction(name, e); } + + // clang-format off + auto match = false; + + #define IF_ECHECK_(force, dtoken, check, req) \ + if (!match && ((dtoken) == token_) && ((check) || IsConstTrue(force))) \ + ECHECK(TryTypedValue(name, dtoken, check, e, req, &match)) + #define TRY_ECHECK(dtoken, check, req) IF_ECHECK_(false, dtoken, check, req) + #define FORCE_ECHECK(dtoken, check, req) IF_ECHECK_(true, dtoken, check, req) + // clang-format on + + if (is_tok_ident || is_tok_string) { + const auto kTokenStringOrIdent = token_; + // The string type is a most probable type, check it first. + TRY_ECHECK(kTokenStringConstant, in_type == BASE_TYPE_STRING, + BASE_TYPE_STRING); + + // avoid escaped and non-ascii in the string + if (!match && is_tok_string && IsScalar(in_type) && + !attr_is_trivial_ascii_string_) { + return Error( + std::string("type mismatch or invalid value, an initializer of " + "non-string field must be trivial ASCII string: type: ") + + kTypeNames[in_type] + ", name: " + (name ? *name : "") + + ", value: " + attribute_); + } + + // A boolean as true/false. Boolean as Integer check below. + if (!match && IsBool(in_type)) { + auto is_true = attribute_ == "true"; + if (is_true || attribute_ == "false") { + attribute_ = is_true ? "1" : "0"; + // accepts both kTokenStringConstant and kTokenIdentifier + TRY_ECHECK(kTokenStringOrIdent, IsBool(in_type), BASE_TYPE_BOOL); + } + } + // Check for optional scalars. + if (!match && IsScalar(in_type) && attribute_ == "null") { + e.constant = "null"; + NEXT(); + match = true; + } + // Check if this could be a string/identifier enum value. + // Enum can have only true integer base type. + if (!match && IsInteger(in_type) && !IsBool(in_type) && + IsIdentifierStart(*attribute_.c_str())) { + ECHECK(ParseEnumFromString(e.type, &e.constant)); + NEXT(); + match = true; + } + // Parse a float/integer number from the string. + // A "scalar-in-string" value needs extra checks. + if (!match && is_tok_string && IsScalar(in_type)) { + // Strip trailing whitespaces from attribute_. + auto last_non_ws = attribute_.find_last_not_of(' '); + if (std::string::npos != last_non_ws) attribute_.resize(last_non_ws + 1); + if (IsFloat(e.type.base_type)) { + // The functions strtod() and strtof() accept both 'nan' and + // 'nan(number)' literals. While 'nan(number)' is rejected by the parser + // as an unsupported function if is_tok_ident is true. + if (attribute_.find_last_of(')') != std::string::npos) { + return Error("invalid number: " + attribute_); + } + } + } + // Float numbers or nan, inf, pi, etc. + TRY_ECHECK(kTokenStringOrIdent, IsFloat(in_type), BASE_TYPE_FLOAT); + // An integer constant in string. + TRY_ECHECK(kTokenStringOrIdent, IsInteger(in_type), BASE_TYPE_INT); + // Unknown tokens will be interpreted as string type. + // An attribute value may be a scalar or string constant. + FORCE_ECHECK(kTokenStringConstant, in_type == BASE_TYPE_STRING, + BASE_TYPE_STRING); + } else { + // Try a float number. + TRY_ECHECK(kTokenFloatConstant, IsFloat(in_type), BASE_TYPE_FLOAT); + // Integer token can init any scalar (integer of float). + FORCE_ECHECK(kTokenIntegerConstant, IsScalar(in_type), BASE_TYPE_INT); + } + // Match empty vectors for default-empty-vectors. + if (!match && IsVector(e.type) && token_ == '[') { + NEXT(); + if (token_ != ']') { return Error("Expected `]` in vector default"); } + NEXT(); + match = true; + e.constant = "[]"; + } + +#undef FORCE_ECHECK +#undef TRY_ECHECK +#undef IF_ECHECK_ + + if (!match) { + std::string msg; + msg += "Cannot assign token starting with '" + TokenToStringId(token_) + + "' to value of <" + std::string(kTypeNames[in_type]) + "> type."; + return Error(msg); + } + const auto match_type = e.type.base_type; // may differ from in_type + // The check_now flag must be true when parse a fbs-schema. + // This flag forces to check default scalar values or metadata of field. + // For JSON parser the flag should be false. + // If it is set for JSON each value will be checked twice (see ParseTable). + // Special case 'null' since atot can't handle that. + if (check_now && IsScalar(match_type) && e.constant != "null") { + // clang-format off + switch (match_type) { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ + case BASE_TYPE_ ## ENUM: {\ + CTYPE val; \ + ECHECK(atot(e.constant.c_str(), *this, &val)); \ + SingleValueRepack(e, val); \ + break; } + FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + default: break; + } + // clang-format on + } + return NoError(); +} + +StructDef *Parser::LookupCreateStruct(const std::string &name, + bool create_if_new, bool definition) { + std::string qualified_name = current_namespace_->GetFullyQualifiedName(name); + // See if it exists pre-declared by an unqualified use. + auto struct_def = LookupStruct(name); + if (struct_def && struct_def->predecl) { + if (definition) { + // Make sure it has the current namespace, and is registered under its + // qualified name. + struct_def->defined_namespace = current_namespace_; + structs_.Move(name, qualified_name); + } + return struct_def; + } + // See if it exists pre-declared by an qualified use. + struct_def = LookupStruct(qualified_name); + if (struct_def && struct_def->predecl) { + if (definition) { + // Make sure it has the current namespace. + struct_def->defined_namespace = current_namespace_; + } + return struct_def; + } + if (!definition && !struct_def) { + struct_def = LookupStructThruParentNamespaces(name); + } + if (!struct_def && create_if_new) { + struct_def = new StructDef(); + if (definition) { + structs_.Add(qualified_name, struct_def); + struct_def->name = name; + struct_def->defined_namespace = current_namespace_; + } else { + // Not a definition. + // Rather than failing, we create a "pre declared" StructDef, due to + // circular references, and check for errors at the end of parsing. + // It is defined in the current namespace, as the best guess what the + // final namespace will be. + structs_.Add(name, struct_def); + struct_def->name = name; + struct_def->defined_namespace = current_namespace_; + struct_def->original_location.reset( + new std::string(file_being_parsed_ + ":" + NumToString(line_))); + } + } + return struct_def; +} + +const EnumVal *EnumDef::MinValue() const { + return vals.vec.empty() ? nullptr : vals.vec.front(); +} +const EnumVal *EnumDef::MaxValue() const { + return vals.vec.empty() ? nullptr : vals.vec.back(); +} + +template<typename T> static uint64_t EnumDistanceImpl(T e1, T e2) { + if (e1 < e2) { std::swap(e1, e2); } // use std for scalars + // Signed overflow may occur, use unsigned calculation. + // The unsigned overflow is well-defined by C++ standard (modulo 2^n). + return static_cast<uint64_t>(e1) - static_cast<uint64_t>(e2); +} + +uint64_t EnumDef::Distance(const EnumVal *v1, const EnumVal *v2) const { + return IsUInt64() ? EnumDistanceImpl(v1->GetAsUInt64(), v2->GetAsUInt64()) + : EnumDistanceImpl(v1->GetAsInt64(), v2->GetAsInt64()); +} + +std::string EnumDef::AllFlags() const { + FLATBUFFERS_ASSERT(attributes.Lookup("bit_flags")); + uint64_t u64 = 0; + for (auto it = Vals().begin(); it != Vals().end(); ++it) { + u64 |= (*it)->GetAsUInt64(); + } + return IsUInt64() ? NumToString(u64) : NumToString(static_cast<int64_t>(u64)); +} + +EnumVal *EnumDef::ReverseLookup(int64_t enum_idx, + bool skip_union_default) const { + auto skip_first = static_cast<int>(is_union && skip_union_default); + for (auto it = Vals().begin() + skip_first; it != Vals().end(); ++it) { + if ((*it)->GetAsInt64() == enum_idx) { return *it; } + } + return nullptr; +} + +EnumVal *EnumDef::FindByValue(const std::string &constant) const { + int64_t i64; + auto done = false; + if (IsUInt64()) { + uint64_t u64; // avoid reinterpret_cast of pointers + done = StringToNumber(constant.c_str(), &u64); + i64 = static_cast<int64_t>(u64); + } else { + done = StringToNumber(constant.c_str(), &i64); + } + FLATBUFFERS_ASSERT(done); + if (!done) return nullptr; + return ReverseLookup(i64, false); +} + +void EnumDef::SortByValue() { + auto &v = vals.vec; + if (IsUInt64()) + std::sort(v.begin(), v.end(), [](const EnumVal *e1, const EnumVal *e2) { + return e1->GetAsUInt64() < e2->GetAsUInt64(); + }); + else + std::sort(v.begin(), v.end(), [](const EnumVal *e1, const EnumVal *e2) { + return e1->GetAsInt64() < e2->GetAsInt64(); + }); +} + +void EnumDef::RemoveDuplicates() { + // This method depends form SymbolTable implementation! + // 1) vals.vec - owner (raw pointer) + // 2) vals.dict - access map + auto first = vals.vec.begin(); + auto last = vals.vec.end(); + if (first == last) return; + auto result = first; + while (++first != last) { + if ((*result)->value != (*first)->value) { + *(++result) = *first; + } else { + auto ev = *first; + for (auto it = vals.dict.begin(); it != vals.dict.end(); ++it) { + if (it->second == ev) it->second = *result; // reassign + } + delete ev; // delete enum value + *first = nullptr; + } + } + vals.vec.erase(++result, last); +} + +template<typename T> void EnumDef::ChangeEnumValue(EnumVal *ev, T new_value) { + ev->value = static_cast<int64_t>(new_value); +} + +namespace EnumHelper { +template<BaseType E> struct EnumValType { typedef int64_t type; }; +template<> struct EnumValType<BASE_TYPE_ULONG> { typedef uint64_t type; }; +} // namespace EnumHelper + +struct EnumValBuilder { + EnumVal *CreateEnumerator(const std::string &ev_name) { + FLATBUFFERS_ASSERT(!temp); + auto first = enum_def.vals.vec.empty(); + user_value = first; + temp = new EnumVal(ev_name, first ? 0 : enum_def.vals.vec.back()->value); + return temp; + } + + EnumVal *CreateEnumerator(const std::string &ev_name, int64_t val) { + FLATBUFFERS_ASSERT(!temp); + user_value = true; + temp = new EnumVal(ev_name, val); + return temp; + } + + FLATBUFFERS_CHECKED_ERROR AcceptEnumerator(const std::string &name) { + FLATBUFFERS_ASSERT(temp); + ECHECK(ValidateValue(&temp->value, false == user_value)); + FLATBUFFERS_ASSERT((temp->union_type.enum_def == nullptr) || + (temp->union_type.enum_def == &enum_def)); + auto not_unique = enum_def.vals.Add(name, temp); + temp = nullptr; + if (not_unique) return parser.Error("enum value already exists: " + name); + return NoError(); + } + + FLATBUFFERS_CHECKED_ERROR AcceptEnumerator() { + return AcceptEnumerator(temp->name); + } + + FLATBUFFERS_CHECKED_ERROR AssignEnumeratorValue(const std::string &value) { + user_value = true; + auto fit = false; + if (enum_def.IsUInt64()) { + uint64_t u64; + fit = StringToNumber(value.c_str(), &u64); + temp->value = static_cast<int64_t>(u64); // well-defined since C++20. + } else { + int64_t i64; + fit = StringToNumber(value.c_str(), &i64); + temp->value = i64; + } + if (!fit) return parser.Error("enum value does not fit, \"" + value + "\""); + return NoError(); + } + + template<BaseType E, typename CTYPE> + inline FLATBUFFERS_CHECKED_ERROR ValidateImpl(int64_t *ev, int m) { + typedef typename EnumHelper::EnumValType<E>::type T; // int64_t or uint64_t + static_assert(sizeof(T) == sizeof(int64_t), "invalid EnumValType"); + const auto v = static_cast<T>(*ev); + auto up = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::max)()); + auto dn = static_cast<T>((flatbuffers::numeric_limits<CTYPE>::lowest)()); + if (v < dn || v > (up - m)) { + return parser.Error("enum value does not fit, \"" + NumToString(v) + + (m ? " + 1\"" : "\"") + " out of " + + TypeToIntervalString<CTYPE>()); + } + *ev = static_cast<int64_t>(v + m); // well-defined since C++20. + return NoError(); + } + + FLATBUFFERS_CHECKED_ERROR ValidateValue(int64_t *ev, bool next) { + // clang-format off + switch (enum_def.underlying_type.base_type) { + #define FLATBUFFERS_TD(ENUM, IDLTYPE, CTYPE, ...) \ + case BASE_TYPE_##ENUM: { \ + if (!IsInteger(BASE_TYPE_##ENUM)) break; \ + return ValidateImpl<BASE_TYPE_##ENUM, CTYPE>(ev, next ? 1 : 0); \ + } + FLATBUFFERS_GEN_TYPES_SCALAR(FLATBUFFERS_TD) + #undef FLATBUFFERS_TD + default: break; + } + // clang-format on + return parser.Error("fatal: invalid enum underlying type"); + } + + EnumValBuilder(Parser &_parser, EnumDef &_enum_def) + : parser(_parser), + enum_def(_enum_def), + temp(nullptr), + user_value(false) {} + + ~EnumValBuilder() { delete temp; } + + Parser &parser; + EnumDef &enum_def; + EnumVal *temp; + bool user_value; +}; + +CheckedError Parser::ParseEnum(const bool is_union, EnumDef **dest) { + std::vector<std::string> enum_comment = doc_comment_; + NEXT(); + std::string enum_name = attribute_; + EXPECT(kTokenIdentifier); + EnumDef *enum_def; + ECHECK(StartEnum(enum_name, is_union, &enum_def)); + enum_def->doc_comment = enum_comment; + if (!is_union && !opts.proto_mode) { + // Give specialized error message, since this type spec used to + // be optional in the first FlatBuffers release. + if (!Is(':')) { + return Error( + "must specify the underlying integer type for this" + " enum (e.g. \': short\', which was the default)."); + } else { + NEXT(); + } + // Specify the integer type underlying this enum. + ECHECK(ParseType(enum_def->underlying_type)); + if (!IsInteger(enum_def->underlying_type.base_type) || + IsBool(enum_def->underlying_type.base_type)) + return Error("underlying enum type must be integral"); + // Make this type refer back to the enum it was derived from. + enum_def->underlying_type.enum_def = enum_def; + } + ECHECK(ParseMetaData(&enum_def->attributes)); + const auto underlying_type = enum_def->underlying_type.base_type; + if (enum_def->attributes.Lookup("bit_flags") && + !IsUnsigned(underlying_type)) { + // todo: Convert to the Error in the future? + Warning("underlying type of bit_flags enum must be unsigned"); + } + EnumValBuilder evb(*this, *enum_def); + EXPECT('{'); + // A lot of code generatos expect that an enum is not-empty. + if ((is_union || Is('}')) && !opts.proto_mode) { + evb.CreateEnumerator("NONE"); + ECHECK(evb.AcceptEnumerator()); + } + std::set<std::pair<BaseType, StructDef *>> union_types; + while (!Is('}')) { + if (opts.proto_mode && attribute_ == "option") { + ECHECK(ParseProtoOption()); + } else { + auto &ev = *evb.CreateEnumerator(attribute_); + auto full_name = ev.name; + ev.doc_comment = doc_comment_; + EXPECT(kTokenIdentifier); + if (is_union) { + ECHECK(ParseNamespacing(&full_name, &ev.name)); + if (opts.union_value_namespacing) { + // Since we can't namespace the actual enum identifiers, turn + // namespace parts into part of the identifier. + ev.name = full_name; + std::replace(ev.name.begin(), ev.name.end(), '.', '_'); + } + if (Is(':')) { + NEXT(); + ECHECK(ParseType(ev.union_type)); + if (ev.union_type.base_type != BASE_TYPE_STRUCT && + ev.union_type.base_type != BASE_TYPE_STRING) + return Error("union value type may only be table/struct/string"); + } else { + ev.union_type = Type(BASE_TYPE_STRUCT, LookupCreateStruct(full_name)); + } + if (!enum_def->uses_multiple_type_instances) { + auto ins = union_types.insert(std::make_pair( + ev.union_type.base_type, ev.union_type.struct_def)); + enum_def->uses_multiple_type_instances = (false == ins.second); + } + } + + if (Is('=')) { + NEXT(); + ECHECK(evb.AssignEnumeratorValue(attribute_)); + EXPECT(kTokenIntegerConstant); + } + + ECHECK(evb.AcceptEnumerator()); + + if (opts.proto_mode && Is('[')) { + NEXT(); + // ignore attributes on enums. + while (token_ != ']') NEXT(); + NEXT(); + } + } + if (!Is(opts.proto_mode ? ';' : ',')) break; + NEXT(); + } + EXPECT('}'); + + // At this point, the enum can be empty if input is invalid proto-file. + if (!enum_def->size()) + return Error("incomplete enum declaration, values not found"); + + if (enum_def->attributes.Lookup("bit_flags")) { + const auto base_width = static_cast<uint64_t>(8 * SizeOf(underlying_type)); + for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end(); + ++it) { + auto ev = *it; + const auto u = ev->GetAsUInt64(); + // Stop manipulations with the sign. + if (!IsUnsigned(underlying_type) && u == (base_width - 1)) + return Error("underlying type of bit_flags enum must be unsigned"); + if (u >= base_width) + return Error("bit flag out of range of underlying integral type"); + enum_def->ChangeEnumValue(ev, 1ULL << u); + } + } + + enum_def->SortByValue(); // Must be sorted to use MinValue/MaxValue. + + // Ensure enum value uniqueness. + auto prev_it = enum_def->Vals().begin(); + for (auto it = prev_it + 1; it != enum_def->Vals().end(); ++it) { + auto prev_ev = *prev_it; + auto ev = *it; + if (prev_ev->GetAsUInt64() == ev->GetAsUInt64()) + return Error("all enum values must be unique: " + prev_ev->name + + " and " + ev->name + " are both " + + NumToString(ev->GetAsInt64())); + } + + if (dest) *dest = enum_def; + types_.Add(current_namespace_->GetFullyQualifiedName(enum_def->name), + new Type(BASE_TYPE_UNION, nullptr, enum_def)); + return NoError(); +} + +CheckedError Parser::StartStruct(const std::string &name, StructDef **dest) { + auto &struct_def = *LookupCreateStruct(name, true, true); + if (!struct_def.predecl) return Error("datatype already exists: " + name); + struct_def.predecl = false; + struct_def.name = name; + struct_def.file = file_being_parsed_; + // Move this struct to the back of the vector just in case it was predeclared, + // to preserve declaration order. + *std::remove(structs_.vec.begin(), structs_.vec.end(), &struct_def) = + &struct_def; + *dest = &struct_def; + return NoError(); +} + +CheckedError Parser::CheckClash(std::vector<FieldDef *> &fields, + StructDef *struct_def, const char *suffix, + BaseType basetype) { + auto len = strlen(suffix); + for (auto it = fields.begin(); it != fields.end(); ++it) { + auto &fname = (*it)->name; + if (fname.length() > len && + fname.compare(fname.length() - len, len, suffix) == 0 && + (*it)->value.type.base_type != BASE_TYPE_UTYPE) { + auto field = + struct_def->fields.Lookup(fname.substr(0, fname.length() - len)); + if (field && field->value.type.base_type == basetype) + return Error("Field " + fname + + " would clash with generated functions for field " + + field->name); + } + } + return NoError(); +} + +bool Parser::SupportsOptionalScalars(const flatbuffers::IDLOptions &opts) { + static FLATBUFFERS_CONSTEXPR unsigned long supported_langs = + IDLOptions::kRust | IDLOptions::kSwift | IDLOptions::kLobster | + IDLOptions::kKotlin | IDLOptions::kCpp | IDLOptions::kJava | + IDLOptions::kCSharp | IDLOptions::kTs | IDLOptions::kBinary; + unsigned long langs = opts.lang_to_generate; + return (langs > 0 && langs < IDLOptions::kMAX) && !(langs & ~supported_langs); +} +bool Parser::SupportsOptionalScalars() const { + // Check in general if a language isn't specified. + return opts.lang_to_generate == 0 || SupportsOptionalScalars(opts); +} + +bool Parser::SupportsDefaultVectorsAndStrings() const { + static FLATBUFFERS_CONSTEXPR unsigned long supported_langs = + IDLOptions::kRust | IDLOptions::kSwift; + return !(opts.lang_to_generate & ~supported_langs); +} + +bool Parser::SupportsAdvancedUnionFeatures() const { + return opts.lang_to_generate != 0 && + (opts.lang_to_generate & + ~(IDLOptions::kCpp | IDLOptions::kTs | IDLOptions::kPhp | + IDLOptions::kJava | IDLOptions::kCSharp | IDLOptions::kKotlin | + IDLOptions::kBinary | IDLOptions::kSwift)) == 0; +} + +bool Parser::SupportsAdvancedArrayFeatures() const { + return (opts.lang_to_generate & + ~(IDLOptions::kCpp | IDLOptions::kPython | IDLOptions::kJava | + IDLOptions::kCSharp | IDLOptions::kJsonSchema | IDLOptions::kJson | + IDLOptions::kBinary | IDLOptions::kRust)) == 0; +} + +Namespace *Parser::UniqueNamespace(Namespace *ns) { + for (auto it = namespaces_.begin(); it != namespaces_.end(); ++it) { + if (ns->components == (*it)->components) { + delete ns; + return *it; + } + } + namespaces_.push_back(ns); + return ns; +} + +std::string Parser::UnqualifiedName(const std::string &full_qualified_name) { + Namespace *ns = new Namespace(); + + std::size_t current, previous = 0; + current = full_qualified_name.find('.'); + while (current != std::string::npos) { + ns->components.push_back( + full_qualified_name.substr(previous, current - previous)); + previous = current + 1; + current = full_qualified_name.find('.', previous); + } + current_namespace_ = UniqueNamespace(ns); + return full_qualified_name.substr(previous, current - previous); +} + +static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) { + auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str()); + auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str()); + return a_id < b_id; +} + +CheckedError Parser::ParseDecl() { + std::vector<std::string> dc = doc_comment_; + bool fixed = IsIdent("struct"); + if (!fixed && !IsIdent("table")) return Error("declaration expected"); + NEXT(); + std::string name = attribute_; + EXPECT(kTokenIdentifier); + StructDef *struct_def; + ECHECK(StartStruct(name, &struct_def)); + struct_def->doc_comment = dc; + struct_def->fixed = fixed; + ECHECK(ParseMetaData(&struct_def->attributes)); + struct_def->sortbysize = + struct_def->attributes.Lookup("original_order") == nullptr && !fixed; + EXPECT('{'); + while (token_ != '}') ECHECK(ParseField(*struct_def)); + if (fixed) { + const auto force_align = struct_def->attributes.Lookup("force_align"); + if (force_align) { + size_t align; + ECHECK(ParseAlignAttribute(force_align->constant, struct_def->minalign, + &align)); + struct_def->minalign = align; + } + if (!struct_def->bytesize) return Error("size 0 structs not allowed"); + } + struct_def->PadLastField(struct_def->minalign); + // Check if this is a table that has manual id assignments + auto &fields = struct_def->fields.vec; + if (!fixed && fields.size()) { + size_t num_id_fields = 0; + for (auto it = fields.begin(); it != fields.end(); ++it) { + if ((*it)->attributes.Lookup("id")) num_id_fields++; + } + // If any fields have ids.. + if (num_id_fields || opts.require_explicit_ids) { + // Then all fields must have them. + if (num_id_fields != fields.size()) { + if (opts.require_explicit_ids) { + return Error( + "all fields must have an 'id' attribute when " + "--require-explicit-ids is used"); + } else { + return Error( + "either all fields or no fields must have an 'id' attribute"); + } + } + // Simply sort by id, then the fields are the same as if no ids had + // been specified. + std::sort(fields.begin(), fields.end(), compareFieldDefs); + // Verify we have a contiguous set, and reassign vtable offsets. + FLATBUFFERS_ASSERT(fields.size() <= + flatbuffers::numeric_limits<voffset_t>::max()); + for (voffset_t i = 0; i < static_cast<voffset_t>(fields.size()); i++) { + auto &field = *fields[i]; + const auto &id_str = field.attributes.Lookup("id")->constant; + // Metadata values have a dynamic type, they can be `float`, 'int', or + // 'string`. + // The FieldIndexToOffset(i) expects the voffset_t so `id` is limited by + // this type. + voffset_t id = 0; + const auto done = !atot(id_str.c_str(), *this, &id).Check(); + if (!done) + return Error("field id\'s must be non-negative number, field: " + + field.name + ", id: " + id_str); + if (i != id) + return Error("field id\'s must be consecutive from 0, id " + + NumToString(i) + " missing or set twice, field: " + + field.name + ", id: " + id_str); + field.value.offset = FieldIndexToOffset(i); + } + } + } + + ECHECK( + CheckClash(fields, struct_def, UnionTypeFieldSuffix(), BASE_TYPE_UNION)); + ECHECK(CheckClash(fields, struct_def, "Type", BASE_TYPE_UNION)); + ECHECK(CheckClash(fields, struct_def, "_length", BASE_TYPE_VECTOR)); + ECHECK(CheckClash(fields, struct_def, "Length", BASE_TYPE_VECTOR)); + ECHECK(CheckClash(fields, struct_def, "_byte_vector", BASE_TYPE_STRING)); + ECHECK(CheckClash(fields, struct_def, "ByteVector", BASE_TYPE_STRING)); + EXPECT('}'); + types_.Add(current_namespace_->GetFullyQualifiedName(struct_def->name), + new Type(BASE_TYPE_STRUCT, struct_def, nullptr)); + return NoError(); +} + +CheckedError Parser::ParseService() { + std::vector<std::string> service_comment = doc_comment_; + NEXT(); + auto service_name = attribute_; + EXPECT(kTokenIdentifier); + auto &service_def = *new ServiceDef(); + service_def.name = service_name; + service_def.file = file_being_parsed_; + service_def.doc_comment = service_comment; + service_def.defined_namespace = current_namespace_; + if (services_.Add(current_namespace_->GetFullyQualifiedName(service_name), + &service_def)) + return Error("service already exists: " + service_name); + ECHECK(ParseMetaData(&service_def.attributes)); + EXPECT('{'); + do { + std::vector<std::string> doc_comment = doc_comment_; + auto rpc_name = attribute_; + EXPECT(kTokenIdentifier); + EXPECT('('); + Type reqtype, resptype; + ECHECK(ParseTypeIdent(reqtype)); + EXPECT(')'); + EXPECT(':'); + ECHECK(ParseTypeIdent(resptype)); + if (reqtype.base_type != BASE_TYPE_STRUCT || reqtype.struct_def->fixed || + resptype.base_type != BASE_TYPE_STRUCT || resptype.struct_def->fixed) + return Error("rpc request and response types must be tables"); + auto &rpc = *new RPCCall(); + rpc.name = rpc_name; + rpc.request = reqtype.struct_def; + rpc.response = resptype.struct_def; + rpc.doc_comment = doc_comment; + if (service_def.calls.Add(rpc_name, &rpc)) + return Error("rpc already exists: " + rpc_name); + ECHECK(ParseMetaData(&rpc.attributes)); + EXPECT(';'); + } while (token_ != '}'); + NEXT(); + return NoError(); +} + +bool Parser::SetRootType(const char *name) { + root_struct_def_ = LookupStruct(name); + if (!root_struct_def_) + root_struct_def_ = + LookupStruct(current_namespace_->GetFullyQualifiedName(name)); + return root_struct_def_ != nullptr; +} + +void Parser::MarkGenerated() { + // This function marks all existing definitions as having already + // been generated, which signals no code for included files should be + // generated. + for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) { + (*it)->generated = true; + } + for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) { + if (!(*it)->predecl) { (*it)->generated = true; } + } + for (auto it = services_.vec.begin(); it != services_.vec.end(); ++it) { + (*it)->generated = true; + } +} + +CheckedError Parser::ParseNamespace() { + NEXT(); + auto ns = new Namespace(); + namespaces_.push_back(ns); // Store it here to not leak upon error. + if (token_ != ';') { + for (;;) { + ns->components.push_back(attribute_); + EXPECT(kTokenIdentifier); + if (Is('.')) NEXT() else break; + } + } + namespaces_.pop_back(); + current_namespace_ = UniqueNamespace(ns); + EXPECT(';'); + return NoError(); +} + +// Best effort parsing of .proto declarations, with the aim to turn them +// in the closest corresponding FlatBuffer equivalent. +// We parse everything as identifiers instead of keywords, since we don't +// want protobuf keywords to become invalid identifiers in FlatBuffers. +CheckedError Parser::ParseProtoDecl() { + bool isextend = IsIdent("extend"); + if (IsIdent("package")) { + // These are identical in syntax to FlatBuffer's namespace decl. + ECHECK(ParseNamespace()); + } else if (IsIdent("message") || isextend) { + std::vector<std::string> struct_comment = doc_comment_; + NEXT(); + StructDef *struct_def = nullptr; + Namespace *parent_namespace = nullptr; + if (isextend) { + if (Is('.')) NEXT(); // qualified names may start with a . ? + auto id = attribute_; + EXPECT(kTokenIdentifier); + ECHECK(ParseNamespacing(&id, nullptr)); + struct_def = LookupCreateStruct(id, false); + if (!struct_def) + return Error("cannot extend unknown message type: " + id); + } else { + std::string name = attribute_; + EXPECT(kTokenIdentifier); + ECHECK(StartStruct(name, &struct_def)); + // Since message definitions can be nested, we create a new namespace. + auto ns = new Namespace(); + // Copy of current namespace. + *ns = *current_namespace_; + // But with current message name. + ns->components.push_back(name); + ns->from_table++; + parent_namespace = current_namespace_; + current_namespace_ = UniqueNamespace(ns); + } + struct_def->doc_comment = struct_comment; + ECHECK(ParseProtoFields(struct_def, isextend, false)); + if (!isextend) { current_namespace_ = parent_namespace; } + if (Is(';')) NEXT(); + } else if (IsIdent("enum")) { + // These are almost the same, just with different terminator: + EnumDef *enum_def; + ECHECK(ParseEnum(false, &enum_def)); + if (Is(';')) NEXT(); + // Temp: remove any duplicates, as .fbs files can't handle them. + enum_def->RemoveDuplicates(); + } else if (IsIdent("syntax")) { // Skip these. + NEXT(); + EXPECT('='); + EXPECT(kTokenStringConstant); + EXPECT(';'); + } else if (IsIdent("option")) { // Skip these. + ECHECK(ParseProtoOption()); + EXPECT(';'); + } else if (IsIdent("service")) { // Skip these. + NEXT(); + EXPECT(kTokenIdentifier); + ECHECK(ParseProtoCurliesOrIdent()); + } else { + return Error("don\'t know how to parse .proto declaration starting with " + + TokenToStringId(token_)); + } + return NoError(); +} + +CheckedError Parser::StartEnum(const std::string &enum_name, bool is_union, + EnumDef **dest) { + auto &enum_def = *new EnumDef(); + enum_def.name = enum_name; + enum_def.file = file_being_parsed_; + enum_def.doc_comment = doc_comment_; + enum_def.is_union = is_union; + enum_def.defined_namespace = current_namespace_; + if (enums_.Add(current_namespace_->GetFullyQualifiedName(enum_name), + &enum_def)) + return Error("enum already exists: " + enum_name); + enum_def.underlying_type.base_type = + is_union ? BASE_TYPE_UTYPE : BASE_TYPE_INT; + enum_def.underlying_type.enum_def = &enum_def; + if (dest) *dest = &enum_def; + return NoError(); +} + +CheckedError Parser::ParseProtoFields(StructDef *struct_def, bool isextend, + bool inside_oneof) { + EXPECT('{'); + while (token_ != '}') { + if (IsIdent("message") || IsIdent("extend") || IsIdent("enum")) { + // Nested declarations. + ECHECK(ParseProtoDecl()); + } else if (IsIdent("extensions")) { // Skip these. + NEXT(); + EXPECT(kTokenIntegerConstant); + if (Is(kTokenIdentifier)) { + NEXT(); // to + NEXT(); // num + } + EXPECT(';'); + } else if (IsIdent("option")) { // Skip these. + ECHECK(ParseProtoOption()); + EXPECT(';'); + } else if (IsIdent("reserved")) { // Skip these. + NEXT(); + while (!Is(';')) { NEXT(); } // A variety of formats, just skip. + NEXT(); + } else { + std::vector<std::string> field_comment = doc_comment_; + // Parse the qualifier. + bool required = false; + bool repeated = false; + bool oneof = false; + if (!inside_oneof) { + if (IsIdent("optional")) { + // This is the default. + NEXT(); + } else if (IsIdent("required")) { + required = true; + NEXT(); + } else if (IsIdent("repeated")) { + repeated = true; + NEXT(); + } else if (IsIdent("oneof")) { + oneof = true; + NEXT(); + } else { + // can't error, proto3 allows decls without any of the above. + } + } + StructDef *anonymous_struct = nullptr; + EnumDef *oneof_union = nullptr; + Type type; + if (IsIdent("group") || oneof) { + if (!oneof) NEXT(); + if (oneof && opts.proto_oneof_union) { + auto name = MakeCamel(attribute_, true) + "Union"; + ECHECK(StartEnum(name, true, &oneof_union)); + type = Type(BASE_TYPE_UNION, nullptr, oneof_union); + } else { + auto name = "Anonymous" + NumToString(anonymous_counter_++); + ECHECK(StartStruct(name, &anonymous_struct)); + type = Type(BASE_TYPE_STRUCT, anonymous_struct); + } + } else { + ECHECK(ParseTypeFromProtoType(&type)); + } + // Repeated elements get mapped to a vector. + if (repeated) { + type.element = type.base_type; + type.base_type = BASE_TYPE_VECTOR; + if (type.element == BASE_TYPE_VECTOR) { + // We have a vector or vectors, which FlatBuffers doesn't support. + // For now make it a vector of string (since the source is likely + // "repeated bytes"). + // TODO(wvo): A better solution would be to wrap this in a table. + type.element = BASE_TYPE_STRING; + } + } + std::string name = attribute_; + EXPECT(kTokenIdentifier); + if (!oneof) { + // Parse the field id. Since we're just translating schemas, not + // any kind of binary compatibility, we can safely ignore these, and + // assign our own. + EXPECT('='); + EXPECT(kTokenIntegerConstant); + } + FieldDef *field = nullptr; + if (isextend) { + // We allow a field to be re-defined when extending. + // TODO: are there situations where that is problematic? + field = struct_def->fields.Lookup(name); + } + if (!field) ECHECK(AddField(*struct_def, name, type, &field)); + field->doc_comment = field_comment; + if (!IsScalar(type.base_type) && required) { + field->presence = FieldDef::kRequired; + } + // See if there's a default specified. + if (Is('[')) { + NEXT(); + for (;;) { + auto key = attribute_; + ECHECK(ParseProtoKey()); + EXPECT('='); + auto val = attribute_; + ECHECK(ParseProtoCurliesOrIdent()); + if (key == "default") { + // Temp: skip non-numeric and non-boolean defaults (enums). + auto numeric = strpbrk(val.c_str(), "0123456789-+."); + if (IsScalar(type.base_type) && numeric == val.c_str()) { + field->value.constant = val; + } else if (val == "true") { + field->value.constant = val; + } // "false" is default, no need to handle explicitly. + } else if (key == "deprecated") { + field->deprecated = val == "true"; + } + if (!Is(',')) break; + NEXT(); + } + EXPECT(']'); + } + if (anonymous_struct) { + ECHECK(ParseProtoFields(anonymous_struct, false, oneof)); + if (Is(';')) NEXT(); + } else if (oneof_union) { + // Parse into a temporary StructDef, then transfer fields into an + // EnumDef describing the oneof as a union. + StructDef oneof_struct; + ECHECK(ParseProtoFields(&oneof_struct, false, oneof)); + if (Is(';')) NEXT(); + for (auto field_it = oneof_struct.fields.vec.begin(); + field_it != oneof_struct.fields.vec.end(); ++field_it) { + const auto &oneof_field = **field_it; + const auto &oneof_type = oneof_field.value.type; + if (oneof_type.base_type != BASE_TYPE_STRUCT || + !oneof_type.struct_def || oneof_type.struct_def->fixed) + return Error("oneof '" + name + + "' cannot be mapped to a union because member '" + + oneof_field.name + "' is not a table type."); + EnumValBuilder evb(*this, *oneof_union); + auto ev = evb.CreateEnumerator(oneof_type.struct_def->name); + ev->union_type = oneof_type; + ev->doc_comment = oneof_field.doc_comment; + ECHECK(evb.AcceptEnumerator(oneof_field.name)); + } + } else { + EXPECT(';'); + } + } + } + NEXT(); + return NoError(); +} + +CheckedError Parser::ParseProtoKey() { + if (token_ == '(') { + NEXT(); + // Skip "(a.b)" style custom attributes. + while (token_ == '.' || token_ == kTokenIdentifier) NEXT(); + EXPECT(')'); + while (Is('.')) { + NEXT(); + EXPECT(kTokenIdentifier); + } + } else { + EXPECT(kTokenIdentifier); + } + return NoError(); +} + +CheckedError Parser::ParseProtoCurliesOrIdent() { + if (Is('{')) { + NEXT(); + for (int nesting = 1; nesting;) { + if (token_ == '{') + nesting++; + else if (token_ == '}') + nesting--; + NEXT(); + } + } else { + NEXT(); // Any single token. + } + return NoError(); +} + +CheckedError Parser::ParseProtoOption() { + NEXT(); + ECHECK(ParseProtoKey()); + EXPECT('='); + ECHECK(ParseProtoCurliesOrIdent()); + return NoError(); +} + +// Parse a protobuf type, and map it to the corresponding FlatBuffer one. +CheckedError Parser::ParseTypeFromProtoType(Type *type) { + struct type_lookup { + const char *proto_type; + BaseType fb_type, element; + }; + static type_lookup lookup[] = { + { "float", BASE_TYPE_FLOAT, BASE_TYPE_NONE }, + { "double", BASE_TYPE_DOUBLE, BASE_TYPE_NONE }, + { "int32", BASE_TYPE_INT, BASE_TYPE_NONE }, + { "int64", BASE_TYPE_LONG, BASE_TYPE_NONE }, + { "uint32", BASE_TYPE_UINT, BASE_TYPE_NONE }, + { "uint64", BASE_TYPE_ULONG, BASE_TYPE_NONE }, + { "sint32", BASE_TYPE_INT, BASE_TYPE_NONE }, + { "sint64", BASE_TYPE_LONG, BASE_TYPE_NONE }, + { "fixed32", BASE_TYPE_UINT, BASE_TYPE_NONE }, + { "fixed64", BASE_TYPE_ULONG, BASE_TYPE_NONE }, + { "sfixed32", BASE_TYPE_INT, BASE_TYPE_NONE }, + { "sfixed64", BASE_TYPE_LONG, BASE_TYPE_NONE }, + { "bool", BASE_TYPE_BOOL, BASE_TYPE_NONE }, + { "string", BASE_TYPE_STRING, BASE_TYPE_NONE }, + { "bytes", BASE_TYPE_VECTOR, BASE_TYPE_UCHAR }, + { nullptr, BASE_TYPE_NONE, BASE_TYPE_NONE } + }; + for (auto tl = lookup; tl->proto_type; tl++) { + if (attribute_ == tl->proto_type) { + type->base_type = tl->fb_type; + type->element = tl->element; + NEXT(); + return NoError(); + } + } + if (Is('.')) NEXT(); // qualified names may start with a . ? + ECHECK(ParseTypeIdent(*type)); + return NoError(); +} + +CheckedError Parser::SkipAnyJsonValue() { + ParseDepthGuard depth_guard(this); + ECHECK(depth_guard.Check()); + + switch (token_) { + case '{': { + size_t fieldn_outer = 0; + return ParseTableDelimiters(fieldn_outer, nullptr, + [&](const std::string &, size_t &fieldn, + const StructDef *) -> CheckedError { + ECHECK(SkipAnyJsonValue()); + fieldn++; + return NoError(); + }); + } + case '[': { + uoffset_t count = 0; + return ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError { + return SkipAnyJsonValue(); + }); + } + case kTokenStringConstant: + case kTokenIntegerConstant: + case kTokenFloatConstant: NEXT(); break; + default: + if (IsIdent("true") || IsIdent("false") || IsIdent("null")) { + NEXT(); + } else + return TokenError(); + } + return NoError(); +} + +CheckedError Parser::ParseFlexBufferNumericConstant( + flexbuffers::Builder *builder) { + double d; + if (!StringToNumber(attribute_.c_str(), &d)) + return Error("unexpected floating-point constant: " + attribute_); + builder->Double(d); + return NoError(); +} + +CheckedError Parser::ParseFlexBufferValue(flexbuffers::Builder *builder) { + ParseDepthGuard depth_guard(this); + ECHECK(depth_guard.Check()); + + switch (token_) { + case '{': { + auto start = builder->StartMap(); + size_t fieldn_outer = 0; + auto err = + ParseTableDelimiters(fieldn_outer, nullptr, + [&](const std::string &name, size_t &fieldn, + const StructDef *) -> CheckedError { + builder->Key(name); + ECHECK(ParseFlexBufferValue(builder)); + fieldn++; + return NoError(); + }); + ECHECK(err); + builder->EndMap(start); + if (builder->HasDuplicateKeys()) + return Error("FlexBuffers map has duplicate keys"); + break; + } + case '[': { + auto start = builder->StartVector(); + uoffset_t count = 0; + ECHECK(ParseVectorDelimiters(count, [&](uoffset_t &) -> CheckedError { + return ParseFlexBufferValue(builder); + })); + builder->EndVector(start, false, false); + break; + } + case kTokenStringConstant: + builder->String(attribute_); + EXPECT(kTokenStringConstant); + break; + case kTokenIntegerConstant: + builder->Int(StringToInt(attribute_.c_str())); + EXPECT(kTokenIntegerConstant); + break; + case kTokenFloatConstant: { + double d; + StringToNumber(attribute_.c_str(), &d); + builder->Double(d); + EXPECT(kTokenFloatConstant); + break; + } + case '-': + case '+': { + // `[-+]?(nan|inf|infinity)`, see ParseSingleValue(). + const auto sign = static_cast<char>(token_); + NEXT(); + if (token_ != kTokenIdentifier) + return Error("floating-point constant expected"); + attribute_.insert(size_t(0), size_t(1), sign); + ECHECK(ParseFlexBufferNumericConstant(builder)); + NEXT(); + break; + } + default: + if (IsIdent("true")) { + builder->Bool(true); + NEXT(); + } else if (IsIdent("false")) { + builder->Bool(false); + NEXT(); + } else if (IsIdent("null")) { + builder->Null(); + NEXT(); + } else if (IsIdent("inf") || IsIdent("infinity") || IsIdent("nan")) { + ECHECK(ParseFlexBufferNumericConstant(builder)); + NEXT(); + } else + return TokenError(); + } + return NoError(); +} + +bool Parser::ParseFlexBuffer(const char *source, const char *source_filename, + flexbuffers::Builder *builder) { + const auto initial_depth = parse_depth_counter_; + (void)initial_depth; + auto ok = !StartParseFile(source, source_filename).Check() && + !ParseFlexBufferValue(builder).Check(); + if (ok) builder->Finish(); + FLATBUFFERS_ASSERT(initial_depth == parse_depth_counter_); + return ok; +} + +bool Parser::Parse(const char *source, const char **include_paths, + const char *source_filename) { + const auto initial_depth = parse_depth_counter_; + (void)initial_depth; + bool r; + + if (opts.use_flexbuffers) { + r = ParseFlexBuffer(source, source_filename, &flex_builder_); + } else { + r = !ParseRoot(source, include_paths, source_filename).Check(); + } + FLATBUFFERS_ASSERT(initial_depth == parse_depth_counter_); + return r; +} + +bool Parser::ParseJson(const char *json, const char *json_filename) { + const auto initial_depth = parse_depth_counter_; + (void)initial_depth; + builder_.Clear(); + const auto done = + !StartParseFile(json, json_filename).Check() && !DoParseJson().Check(); + FLATBUFFERS_ASSERT(initial_depth == parse_depth_counter_); + return done; +} + +CheckedError Parser::StartParseFile(const char *source, + const char *source_filename) { + file_being_parsed_ = source_filename ? source_filename : ""; + source_ = source; + ResetState(source_); + error_.clear(); + ECHECK(SkipByteOrderMark()); + NEXT(); + if (Is(kTokenEof)) return Error("input file is empty"); + return NoError(); +} + +CheckedError Parser::ParseRoot(const char *source, const char **include_paths, + const char *source_filename) { + ECHECK(DoParse(source, include_paths, source_filename, nullptr)); + + // Check that all types were defined. + for (auto it = structs_.vec.begin(); it != structs_.vec.end();) { + auto &struct_def = **it; + if (struct_def.predecl) { + if (opts.proto_mode) { + // Protos allow enums to be used before declaration, so check if that + // is the case here. + EnumDef *enum_def = nullptr; + for (size_t components = + struct_def.defined_namespace->components.size() + 1; + components && !enum_def; components--) { + auto qualified_name = + struct_def.defined_namespace->GetFullyQualifiedName( + struct_def.name, components - 1); + enum_def = LookupEnum(qualified_name); + } + if (enum_def) { + // This is pretty slow, but a simple solution for now. + auto initial_count = struct_def.refcount; + for (auto struct_it = structs_.vec.begin(); + struct_it != structs_.vec.end(); ++struct_it) { + auto &sd = **struct_it; + for (auto field_it = sd.fields.vec.begin(); + field_it != sd.fields.vec.end(); ++field_it) { + auto &field = **field_it; + if (field.value.type.struct_def == &struct_def) { + field.value.type.struct_def = nullptr; + field.value.type.enum_def = enum_def; + auto &bt = IsVector(field.value.type) + ? field.value.type.element + : field.value.type.base_type; + FLATBUFFERS_ASSERT(bt == BASE_TYPE_STRUCT); + bt = enum_def->underlying_type.base_type; + struct_def.refcount--; + enum_def->refcount++; + } + } + } + if (struct_def.refcount) + return Error("internal: " + NumToString(struct_def.refcount) + "/" + + NumToString(initial_count) + + " use(s) of pre-declaration enum not accounted for: " + + enum_def->name); + structs_.dict.erase(structs_.dict.find(struct_def.name)); + it = structs_.vec.erase(it); + delete &struct_def; + continue; // Skip error. + } + } + auto err = "type referenced but not defined (check namespace): " + + struct_def.name; + if (struct_def.original_location) + err += ", originally at: " + *struct_def.original_location; + return Error(err); + } + ++it; + } + + // This check has to happen here and not earlier, because only now do we + // know for sure what the type of these are. + for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) { + auto &enum_def = **it; + if (enum_def.is_union) { + for (auto val_it = enum_def.Vals().begin(); + val_it != enum_def.Vals().end(); ++val_it) { + auto &val = **val_it; + if (!SupportsAdvancedUnionFeatures() && + (IsStruct(val.union_type) || IsString(val.union_type))) + return Error( + "only tables can be union elements in the generated language: " + + val.name); + } + } + } + // Parse JSON object only if the scheme has been parsed. + if (token_ == '{') { ECHECK(DoParseJson()); } + EXPECT(kTokenEof); + return NoError(); +} + +// Generate a unique hash for a file based on its name and contents (if any). +static uint64_t HashFile(const char *source_filename, const char *source) { + uint64_t hash = 0; + + if (source_filename) + hash = HashFnv1a<uint64_t>(StripPath(source_filename).c_str()); + + if (source && *source) hash ^= HashFnv1a<uint64_t>(source); + + return hash; +} + +CheckedError Parser::DoParse(const char *source, const char **include_paths, + const char *source_filename, + const char *include_filename) { + uint64_t source_hash = 0; + if (source_filename) { + // If the file is in-memory, don't include its contents in the hash as we + // won't be able to load them later. + if (FileExists(source_filename)) + source_hash = HashFile(source_filename, source); + else + source_hash = HashFile(source_filename, nullptr); + + if (included_files_.find(source_hash) == included_files_.end()) { + included_files_[source_hash] = include_filename ? include_filename : ""; + files_included_per_file_[source_filename] = std::set<std::string>(); + } else { + return NoError(); + } + } + if (!include_paths) { + static const char *current_directory[] = { "", nullptr }; + include_paths = current_directory; + } + field_stack_.clear(); + builder_.Clear(); + // Start with a blank namespace just in case this file doesn't have one. + current_namespace_ = empty_namespace_; + + ECHECK(StartParseFile(source, source_filename)); + + // Includes must come before type declarations: + for (;;) { + // Parse pre-include proto statements if any: + if (opts.proto_mode && (attribute_ == "option" || attribute_ == "syntax" || + attribute_ == "package")) { + ECHECK(ParseProtoDecl()); + } else if (IsIdent("native_include")) { + NEXT(); + vector_emplace_back(&native_included_files_, attribute_); + EXPECT(kTokenStringConstant); + EXPECT(';'); + } else if (IsIdent("include") || (opts.proto_mode && IsIdent("import"))) { + NEXT(); + if (opts.proto_mode && attribute_ == "public") NEXT(); + auto name = flatbuffers::PosixPath(attribute_.c_str()); + EXPECT(kTokenStringConstant); + // Look for the file relative to the directory of the current file. + std::string filepath; + if (source_filename) { + auto source_file_directory = + flatbuffers::StripFileName(source_filename); + filepath = flatbuffers::ConCatPathFileName(source_file_directory, name); + } + if (filepath.empty() || !FileExists(filepath.c_str())) { + // Look for the file in include_paths. + for (auto paths = include_paths; paths && *paths; paths++) { + filepath = flatbuffers::ConCatPathFileName(*paths, name); + if (FileExists(filepath.c_str())) break; + } + } + if (filepath.empty()) + return Error("unable to locate include file: " + name); + if (source_filename) + files_included_per_file_[source_filename].insert(filepath); + + std::string contents; + bool file_loaded = LoadFile(filepath.c_str(), true, &contents); + if (included_files_.find(HashFile(filepath.c_str(), contents.c_str())) == + included_files_.end()) { + // We found an include file that we have not parsed yet. + // Parse it. + if (!file_loaded) return Error("unable to load include file: " + name); + ECHECK(DoParse(contents.c_str(), include_paths, filepath.c_str(), + name.c_str())); + // We generally do not want to output code for any included files: + if (!opts.generate_all) MarkGenerated(); + // Reset these just in case the included file had them, and the + // parent doesn't. + root_struct_def_ = nullptr; + file_identifier_.clear(); + file_extension_.clear(); + // This is the easiest way to continue this file after an include: + // instead of saving and restoring all the state, we simply start the + // file anew. This will cause it to encounter the same include + // statement again, but this time it will skip it, because it was + // entered into included_files_. + // This is recursive, but only go as deep as the number of include + // statements. + included_files_.erase(source_hash); + return DoParse(source, include_paths, source_filename, + include_filename); + } + EXPECT(';'); + } else { + break; + } + } + // Now parse all other kinds of declarations: + while (token_ != kTokenEof) { + if (opts.proto_mode) { + ECHECK(ParseProtoDecl()); + } else if (IsIdent("namespace")) { + ECHECK(ParseNamespace()); + } else if (token_ == '{') { + return NoError(); + } else if (IsIdent("enum")) { + ECHECK(ParseEnum(false, nullptr)); + } else if (IsIdent("union")) { + ECHECK(ParseEnum(true, nullptr)); + } else if (IsIdent("root_type")) { + NEXT(); + auto root_type = attribute_; + EXPECT(kTokenIdentifier); + ECHECK(ParseNamespacing(&root_type, nullptr)); + if (opts.root_type.empty()) { + if (!SetRootType(root_type.c_str())) + return Error("unknown root type: " + root_type); + if (root_struct_def_->fixed) return Error("root type must be a table"); + } + EXPECT(';'); + } else if (IsIdent("file_identifier")) { + NEXT(); + file_identifier_ = attribute_; + EXPECT(kTokenStringConstant); + if (file_identifier_.length() != FlatBufferBuilder::kFileIdentifierLength) + return Error("file_identifier must be exactly " + + NumToString(FlatBufferBuilder::kFileIdentifierLength) + + " characters"); + EXPECT(';'); + } else if (IsIdent("file_extension")) { + NEXT(); + file_extension_ = attribute_; + EXPECT(kTokenStringConstant); + EXPECT(';'); + } else if (IsIdent("include")) { + return Error("includes must come before declarations"); + } else if (IsIdent("attribute")) { + NEXT(); + auto name = attribute_; + if (Is(kTokenIdentifier)) { + NEXT(); + } else { + EXPECT(kTokenStringConstant); + } + EXPECT(';'); + known_attributes_[name] = false; + } else if (IsIdent("rpc_service")) { + ECHECK(ParseService()); + } else { + ECHECK(ParseDecl()); + } + } + return NoError(); +} + +CheckedError Parser::DoParseJson() { + if (token_ != '{') { + EXPECT('{'); + } else { + if (!root_struct_def_) return Error("no root type set to parse json with"); + if (builder_.GetSize()) { + return Error("cannot have more than one json object in a file"); + } + uoffset_t toff; + ECHECK(ParseTable(*root_struct_def_, nullptr, &toff)); + if (opts.size_prefixed) { + builder_.FinishSizePrefixed( + Offset<Table>(toff), + file_identifier_.length() ? file_identifier_.c_str() : nullptr); + } else { + builder_.Finish(Offset<Table>(toff), file_identifier_.length() + ? file_identifier_.c_str() + : nullptr); + } + } + // Check that JSON file doesn't contain more objects or IDL directives. + // Comments after JSON are allowed. + EXPECT(kTokenEof); + return NoError(); +} + +std::set<std::string> Parser::GetIncludedFilesRecursive( + const std::string &file_name) const { + std::set<std::string> included_files; + std::list<std::string> to_process; + + if (file_name.empty()) return included_files; + to_process.push_back(file_name); + + while (!to_process.empty()) { + std::string current = to_process.front(); + to_process.pop_front(); + included_files.insert(current); + + // Workaround the lack of const accessor in C++98 maps. + auto &new_files = + (*const_cast<std::map<std::string, std::set<std::string>> *>( + &files_included_per_file_))[current]; + for (auto it = new_files.begin(); it != new_files.end(); ++it) { + if (included_files.find(*it) == included_files.end()) + to_process.push_back(*it); + } + } + + return included_files; +} + +// Schema serialization functionality: + +template<typename T> bool compareName(const T *a, const T *b) { + return a->defined_namespace->GetFullyQualifiedName(a->name) < + b->defined_namespace->GetFullyQualifiedName(b->name); +} + +template<typename T> void AssignIndices(const std::vector<T *> &defvec) { + // Pre-sort these vectors, such that we can set the correct indices for them. + auto vec = defvec; + std::sort(vec.begin(), vec.end(), compareName<T>); + for (int i = 0; i < static_cast<int>(vec.size()); i++) vec[i]->index = i; +} + +void Parser::Serialize() { + builder_.Clear(); + AssignIndices(structs_.vec); + AssignIndices(enums_.vec); + std::vector<Offset<reflection::Object>> object_offsets; + for (auto it = structs_.vec.begin(); it != structs_.vec.end(); ++it) { + auto offset = (*it)->Serialize(&builder_, *this); + object_offsets.push_back(offset); + (*it)->serialized_location = offset.o; + } + std::vector<Offset<reflection::Enum>> enum_offsets; + for (auto it = enums_.vec.begin(); it != enums_.vec.end(); ++it) { + auto offset = (*it)->Serialize(&builder_, *this); + enum_offsets.push_back(offset); + (*it)->serialized_location = offset.o; + } + std::vector<Offset<reflection::Service>> service_offsets; + for (auto it = services_.vec.begin(); it != services_.vec.end(); ++it) { + auto offset = (*it)->Serialize(&builder_, *this); + service_offsets.push_back(offset); + (*it)->serialized_location = offset.o; + } + auto objs__ = builder_.CreateVectorOfSortedTables(&object_offsets); + auto enum__ = builder_.CreateVectorOfSortedTables(&enum_offsets); + auto fiid__ = builder_.CreateString(file_identifier_); + auto fext__ = builder_.CreateString(file_extension_); + auto serv__ = builder_.CreateVectorOfSortedTables(&service_offsets); + auto schema_offset = reflection::CreateSchema( + builder_, objs__, enum__, fiid__, fext__, + (root_struct_def_ ? root_struct_def_->serialized_location : 0), serv__, + static_cast<reflection::AdvancedFeatures>(advanced_features_)); + if (opts.size_prefixed) { + builder_.FinishSizePrefixed(schema_offset, reflection::SchemaIdentifier()); + } else { + builder_.Finish(schema_offset, reflection::SchemaIdentifier()); + } +} + +static Namespace *GetNamespace( + const std::string &qualified_name, std::vector<Namespace *> &namespaces, + std::map<std::string, Namespace *> &namespaces_index) { + size_t dot = qualified_name.find_last_of('.'); + std::string namespace_name = (dot != std::string::npos) + ? std::string(qualified_name.c_str(), dot) + : ""; + Namespace *&ns = namespaces_index[namespace_name]; + + if (!ns) { + ns = new Namespace(); + namespaces.push_back(ns); + + size_t pos = 0; + + for (;;) { + dot = qualified_name.find('.', pos); + if (dot == std::string::npos) { break; } + ns->components.push_back(qualified_name.substr(pos, dot - pos)); + pos = dot + 1; + } + } + + return ns; +} + +Offset<reflection::Object> StructDef::Serialize(FlatBufferBuilder *builder, + const Parser &parser) const { + std::vector<Offset<reflection::Field>> field_offsets; + for (auto it = fields.vec.begin(); it != fields.vec.end(); ++it) { + field_offsets.push_back((*it)->Serialize( + builder, static_cast<uint16_t>(it - fields.vec.begin()), parser)); + } + auto qualified_name = defined_namespace->GetFullyQualifiedName(name); + auto name__ = builder->CreateString(qualified_name); + auto flds__ = builder->CreateVectorOfSortedTables(&field_offsets); + auto attr__ = SerializeAttributes(builder, parser); + auto docs__ = parser.opts.binary_schema_comments + ? builder->CreateVectorOfStrings(doc_comment) + : 0; + return reflection::CreateObject(*builder, name__, flds__, fixed, + static_cast<int>(minalign), + static_cast<int>(bytesize), attr__, docs__); +} + +bool StructDef::Deserialize(Parser &parser, const reflection::Object *object) { + if (!DeserializeAttributes(parser, object->attributes())) return false; + DeserializeDoc(doc_comment, object->documentation()); + name = parser.UnqualifiedName(object->name()->str()); + predecl = false; + sortbysize = attributes.Lookup("original_order") == nullptr && !fixed; + const auto &of = *(object->fields()); + auto indexes = std::vector<uoffset_t>(of.size()); + for (uoffset_t i = 0; i < of.size(); i++) indexes[of.Get(i)->id()] = i; + size_t tmp_struct_size = 0; + for (size_t i = 0; i < indexes.size(); i++) { + auto field = of.Get(indexes[i]); + auto field_def = new FieldDef(); + if (!field_def->Deserialize(parser, field) || + fields.Add(field_def->name, field_def)) { + delete field_def; + return false; + } + if (fixed) { + // Recompute padding since that's currently not serialized. + auto size = InlineSize(field_def->value.type); + auto next_field = + i + 1 < indexes.size() ? of.Get(indexes[i + 1]) : nullptr; + tmp_struct_size += size; + field_def->padding = + next_field ? (next_field->offset() - field_def->value.offset) - size + : PaddingBytes(tmp_struct_size, minalign); + tmp_struct_size += field_def->padding; + } + } + FLATBUFFERS_ASSERT(static_cast<int>(tmp_struct_size) == object->bytesize()); + return true; +} + +Offset<reflection::Field> FieldDef::Serialize(FlatBufferBuilder *builder, + uint16_t id, + const Parser &parser) const { + auto name__ = builder->CreateString(name); + auto type__ = value.type.Serialize(builder); + auto attr__ = SerializeAttributes(builder, parser); + auto docs__ = parser.opts.binary_schema_comments + ? builder->CreateVectorOfStrings(doc_comment) + : 0; + double d; + StringToNumber(value.constant.c_str(), &d); + return reflection::CreateField( + *builder, name__, type__, id, value.offset, + // Is uint64>max(int64) tested? + IsInteger(value.type.base_type) ? StringToInt(value.constant.c_str()) : 0, + // result may be platform-dependent if underlying is float (not double) + IsFloat(value.type.base_type) ? d : 0.0, deprecated, IsRequired(), key, + attr__, docs__, IsOptional()); + // TODO: value.constant is almost always "0", we could save quite a bit of + // space by sharing it. Same for common values of value.type. +} + +bool FieldDef::Deserialize(Parser &parser, const reflection::Field *field) { + name = field->name()->str(); + defined_namespace = parser.current_namespace_; + if (!value.type.Deserialize(parser, field->type())) return false; + value.offset = field->offset(); + if (IsInteger(value.type.base_type)) { + value.constant = NumToString(field->default_integer()); + } else if (IsFloat(value.type.base_type)) { + value.constant = FloatToString(field->default_real(), 16); + } + presence = FieldDef::MakeFieldPresence(field->optional(), field->required()); + key = field->key(); + if (!DeserializeAttributes(parser, field->attributes())) return false; + // TODO: this should probably be handled by a separate attribute + if (attributes.Lookup("flexbuffer")) { + flexbuffer = true; + parser.uses_flexbuffers_ = true; + if (value.type.base_type != BASE_TYPE_VECTOR || + value.type.element != BASE_TYPE_UCHAR) + return false; + } + if (auto nested = attributes.Lookup("nested_flatbuffer")) { + auto nested_qualified_name = + parser.current_namespace_->GetFullyQualifiedName(nested->constant); + nested_flatbuffer = parser.LookupStruct(nested_qualified_name); + if (!nested_flatbuffer) return false; + } + shared = attributes.Lookup("shared") != nullptr; + DeserializeDoc(doc_comment, field->documentation()); + return true; +} + +Offset<reflection::RPCCall> RPCCall::Serialize(FlatBufferBuilder *builder, + const Parser &parser) const { + auto name__ = builder->CreateString(name); + auto attr__ = SerializeAttributes(builder, parser); + auto docs__ = parser.opts.binary_schema_comments + ? builder->CreateVectorOfStrings(doc_comment) + : 0; + return reflection::CreateRPCCall( + *builder, name__, request->serialized_location, + response->serialized_location, attr__, docs__); +} + +bool RPCCall::Deserialize(Parser &parser, const reflection::RPCCall *call) { + name = call->name()->str(); + if (!DeserializeAttributes(parser, call->attributes())) return false; + DeserializeDoc(doc_comment, call->documentation()); + request = parser.structs_.Lookup(call->request()->name()->str()); + response = parser.structs_.Lookup(call->response()->name()->str()); + if (!request || !response) { return false; } + return true; +} + +Offset<reflection::Service> ServiceDef::Serialize(FlatBufferBuilder *builder, + const Parser &parser) const { + std::vector<Offset<reflection::RPCCall>> servicecall_offsets; + for (auto it = calls.vec.begin(); it != calls.vec.end(); ++it) { + servicecall_offsets.push_back((*it)->Serialize(builder, parser)); + } + auto qualified_name = defined_namespace->GetFullyQualifiedName(name); + auto name__ = builder->CreateString(qualified_name); + auto call__ = builder->CreateVector(servicecall_offsets); + auto attr__ = SerializeAttributes(builder, parser); + auto docs__ = parser.opts.binary_schema_comments + ? builder->CreateVectorOfStrings(doc_comment) + : 0; + return reflection::CreateService(*builder, name__, call__, attr__, docs__); +} + +bool ServiceDef::Deserialize(Parser &parser, + const reflection::Service *service) { + name = parser.UnqualifiedName(service->name()->str()); + if (service->calls()) { + for (uoffset_t i = 0; i < service->calls()->size(); ++i) { + auto call = new RPCCall(); + if (!call->Deserialize(parser, service->calls()->Get(i)) || + calls.Add(call->name, call)) { + delete call; + return false; + } + } + } + if (!DeserializeAttributes(parser, service->attributes())) return false; + DeserializeDoc(doc_comment, service->documentation()); + return true; +} + +Offset<reflection::Enum> EnumDef::Serialize(FlatBufferBuilder *builder, + const Parser &parser) const { + std::vector<Offset<reflection::EnumVal>> enumval_offsets; + for (auto it = vals.vec.begin(); it != vals.vec.end(); ++it) { + enumval_offsets.push_back((*it)->Serialize(builder, parser)); + } + auto qualified_name = defined_namespace->GetFullyQualifiedName(name); + auto name__ = builder->CreateString(qualified_name); + auto vals__ = builder->CreateVector(enumval_offsets); + auto type__ = underlying_type.Serialize(builder); + auto attr__ = SerializeAttributes(builder, parser); + auto docs__ = parser.opts.binary_schema_comments + ? builder->CreateVectorOfStrings(doc_comment) + : 0; + return reflection::CreateEnum(*builder, name__, vals__, is_union, type__, + attr__, docs__); +} + +bool EnumDef::Deserialize(Parser &parser, const reflection::Enum *_enum) { + name = parser.UnqualifiedName(_enum->name()->str()); + for (uoffset_t i = 0; i < _enum->values()->size(); ++i) { + auto val = new EnumVal(); + if (!val->Deserialize(parser, _enum->values()->Get(i)) || + vals.Add(val->name, val)) { + delete val; + return false; + } + } + is_union = _enum->is_union(); + if (!underlying_type.Deserialize(parser, _enum->underlying_type())) { + return false; + } + if (!DeserializeAttributes(parser, _enum->attributes())) return false; + DeserializeDoc(doc_comment, _enum->documentation()); + return true; +} + +Offset<reflection::EnumVal> EnumVal::Serialize(FlatBufferBuilder *builder, + const Parser &parser) const { + auto name__ = builder->CreateString(name); + auto type__ = union_type.Serialize(builder); + auto docs__ = parser.opts.binary_schema_comments + ? builder->CreateVectorOfStrings(doc_comment) + : 0; + return reflection::CreateEnumVal( + *builder, name__, value, + union_type.struct_def ? union_type.struct_def->serialized_location : 0, + type__, docs__); +} + +bool EnumVal::Deserialize(const Parser &parser, + const reflection::EnumVal *val) { + name = val->name()->str(); + value = val->value(); + if (!union_type.Deserialize(parser, val->union_type())) return false; + DeserializeDoc(doc_comment, val->documentation()); + return true; +} + +Offset<reflection::Type> Type::Serialize(FlatBufferBuilder *builder) const { + return reflection::CreateType( + *builder, static_cast<reflection::BaseType>(base_type), + static_cast<reflection::BaseType>(element), + struct_def ? struct_def->index : (enum_def ? enum_def->index : -1), + fixed_length); +} + +bool Type::Deserialize(const Parser &parser, const reflection::Type *type) { + if (type == nullptr) return true; + base_type = static_cast<BaseType>(type->base_type()); + element = static_cast<BaseType>(type->element()); + fixed_length = type->fixed_length(); + if (type->index() >= 0) { + bool is_series = type->base_type() == reflection::Vector || + type->base_type() == reflection::Array; + if (type->base_type() == reflection::Obj || + (is_series && type->element() == reflection::Obj)) { + if (static_cast<size_t>(type->index()) < parser.structs_.vec.size()) { + struct_def = parser.structs_.vec[type->index()]; + struct_def->refcount++; + } else { + return false; + } + } else { + if (static_cast<size_t>(type->index()) < parser.enums_.vec.size()) { + enum_def = parser.enums_.vec[type->index()]; + } else { + return false; + } + } + } + return true; +} + +flatbuffers::Offset< + flatbuffers::Vector<flatbuffers::Offset<reflection::KeyValue>>> +Definition::SerializeAttributes(FlatBufferBuilder *builder, + const Parser &parser) const { + std::vector<flatbuffers::Offset<reflection::KeyValue>> attrs; + for (auto kv = attributes.dict.begin(); kv != attributes.dict.end(); ++kv) { + auto it = parser.known_attributes_.find(kv->first); + FLATBUFFERS_ASSERT(it != parser.known_attributes_.end()); + if (parser.opts.binary_schema_builtins || !it->second) { + auto key = builder->CreateString(kv->first); + auto val = builder->CreateString(kv->second->constant); + attrs.push_back(reflection::CreateKeyValue(*builder, key, val)); + } + } + if (attrs.size()) { + return builder->CreateVectorOfSortedTables(&attrs); + } else { + return 0; + } +} + +bool Definition::DeserializeAttributes( + Parser &parser, const Vector<Offset<reflection::KeyValue>> *attrs) { + if (attrs == nullptr) return true; + for (uoffset_t i = 0; i < attrs->size(); ++i) { + auto kv = attrs->Get(i); + auto value = new Value(); + if (kv->value()) { value->constant = kv->value()->str(); } + if (attributes.Add(kv->key()->str(), value)) { + delete value; + return false; + } + parser.known_attributes_[kv->key()->str()]; + } + return true; +} + +/************************************************************************/ +/* DESERIALIZATION */ +/************************************************************************/ +bool Parser::Deserialize(const uint8_t *buf, const size_t size) { + flatbuffers::Verifier verifier(reinterpret_cast<const uint8_t *>(buf), size); + bool size_prefixed = false; + if (!reflection::SchemaBufferHasIdentifier(buf)) { + if (!flatbuffers::BufferHasIdentifier(buf, reflection::SchemaIdentifier(), + true)) + return false; + else + size_prefixed = true; + } + auto verify_fn = size_prefixed ? &reflection::VerifySizePrefixedSchemaBuffer + : &reflection::VerifySchemaBuffer; + if (!verify_fn(verifier)) { return false; } + auto schema = size_prefixed ? reflection::GetSizePrefixedSchema(buf) + : reflection::GetSchema(buf); + return Deserialize(schema); +} + +bool Parser::Deserialize(const reflection::Schema *schema) { + file_identifier_ = schema->file_ident() ? schema->file_ident()->str() : ""; + file_extension_ = schema->file_ext() ? schema->file_ext()->str() : ""; + std::map<std::string, Namespace *> namespaces_index; + + // Create defs without deserializing so references from fields to structs and + // enums can be resolved. + for (auto it = schema->objects()->begin(); it != schema->objects()->end(); + ++it) { + auto struct_def = new StructDef(); + struct_def->bytesize = it->bytesize(); + struct_def->fixed = it->is_struct(); + struct_def->minalign = it->minalign(); + if (structs_.Add(it->name()->str(), struct_def)) { + delete struct_def; + return false; + } + auto type = new Type(BASE_TYPE_STRUCT, struct_def, nullptr); + if (types_.Add(it->name()->str(), type)) { + delete type; + return false; + } + } + for (auto it = schema->enums()->begin(); it != schema->enums()->end(); ++it) { + auto enum_def = new EnumDef(); + if (enums_.Add(it->name()->str(), enum_def)) { + delete enum_def; + return false; + } + auto type = new Type(BASE_TYPE_UNION, nullptr, enum_def); + if (types_.Add(it->name()->str(), type)) { + delete type; + return false; + } + } + + // Now fields can refer to structs and enums by index. + for (auto it = schema->objects()->begin(); it != schema->objects()->end(); + ++it) { + std::string qualified_name = it->name()->str(); + auto struct_def = structs_.Lookup(qualified_name); + struct_def->defined_namespace = + GetNamespace(qualified_name, namespaces_, namespaces_index); + if (!struct_def->Deserialize(*this, *it)) { return false; } + if (schema->root_table() == *it) { root_struct_def_ = struct_def; } + } + for (auto it = schema->enums()->begin(); it != schema->enums()->end(); ++it) { + std::string qualified_name = it->name()->str(); + auto enum_def = enums_.Lookup(qualified_name); + enum_def->defined_namespace = + GetNamespace(qualified_name, namespaces_, namespaces_index); + if (!enum_def->Deserialize(*this, *it)) { return false; } + } + + if (schema->services()) { + for (auto it = schema->services()->begin(); it != schema->services()->end(); + ++it) { + std::string qualified_name = it->name()->str(); + auto service_def = new ServiceDef(); + service_def->defined_namespace = + GetNamespace(qualified_name, namespaces_, namespaces_index); + if (!service_def->Deserialize(*this, *it) || + services_.Add(qualified_name, service_def)) { + delete service_def; + return false; + } + } + } + advanced_features_ = schema->advanced_features(); + return true; +} + +std::string Parser::ConformTo(const Parser &base) { + for (auto sit = structs_.vec.begin(); sit != structs_.vec.end(); ++sit) { + auto &struct_def = **sit; + auto qualified_name = + struct_def.defined_namespace->GetFullyQualifiedName(struct_def.name); + auto struct_def_base = base.LookupStruct(qualified_name); + if (!struct_def_base) continue; + for (auto fit = struct_def.fields.vec.begin(); + fit != struct_def.fields.vec.end(); ++fit) { + auto &field = **fit; + auto field_base = struct_def_base->fields.Lookup(field.name); + if (field_base) { + if (field.value.offset != field_base->value.offset) + return "offsets differ for field: " + field.name; + if (field.value.constant != field_base->value.constant) + return "defaults differ for field: " + field.name; + if (!EqualByName(field.value.type, field_base->value.type)) + return "types differ for field: " + field.name; + } else { + // Doesn't have to exist, deleting fields is fine. + // But we should check if there is a field that has the same offset + // but is incompatible (in the case of field renaming). + for (auto fbit = struct_def_base->fields.vec.begin(); + fbit != struct_def_base->fields.vec.end(); ++fbit) { + field_base = *fbit; + if (field.value.offset == field_base->value.offset) { + if (!EqualByName(field.value.type, field_base->value.type)) + return "field renamed to different type: " + field.name; + break; + } + } + } + } + } + for (auto eit = enums_.vec.begin(); eit != enums_.vec.end(); ++eit) { + auto &enum_def = **eit; + auto qualified_name = + enum_def.defined_namespace->GetFullyQualifiedName(enum_def.name); + auto enum_def_base = base.enums_.Lookup(qualified_name); + if (!enum_def_base) continue; + for (auto evit = enum_def.Vals().begin(); evit != enum_def.Vals().end(); + ++evit) { + auto &enum_val = **evit; + auto enum_val_base = enum_def_base->Lookup(enum_val.name); + if (enum_val_base) { + if (enum_val != *enum_val_base) + return "values differ for enum: " + enum_val.name; + } + } + } + return ""; +} + +} // namespace flatbuffers diff --git a/contrib/libs/flatbuffers/src/reflection.cpp b/contrib/libs/flatbuffers/src/reflection.cpp new file mode 100644 index 0000000000..2dedcb4f18 --- /dev/null +++ b/contrib/libs/flatbuffers/src/reflection.cpp @@ -0,0 +1,713 @@ +/* + * Copyright 2015 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "flatbuffers/reflection.h" + +#include "flatbuffers/util.h" + +// Helper functionality for reflection. + +namespace flatbuffers { + +int64_t GetAnyValueI(reflection::BaseType type, const uint8_t *data) { +// clang-format off + #define FLATBUFFERS_GET(T) static_cast<int64_t>(ReadScalar<T>(data)) + switch (type) { + case reflection::UType: + case reflection::Bool: + case reflection::UByte: return FLATBUFFERS_GET(uint8_t); + case reflection::Byte: return FLATBUFFERS_GET(int8_t); + case reflection::Short: return FLATBUFFERS_GET(int16_t); + case reflection::UShort: return FLATBUFFERS_GET(uint16_t); + case reflection::Int: return FLATBUFFERS_GET(int32_t); + case reflection::UInt: return FLATBUFFERS_GET(uint32_t); + case reflection::Long: return FLATBUFFERS_GET(int64_t); + case reflection::ULong: return FLATBUFFERS_GET(uint64_t); + case reflection::Float: return FLATBUFFERS_GET(float); + case reflection::Double: return FLATBUFFERS_GET(double); + case reflection::String: { + auto s = reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) + + data); + return s ? StringToInt(s->c_str()) : 0; + } + default: return 0; // Tables & vectors do not make sense. + } + #undef FLATBUFFERS_GET + // clang-format on +} + +double GetAnyValueF(reflection::BaseType type, const uint8_t *data) { + switch (type) { + case reflection::Float: return static_cast<double>(ReadScalar<float>(data)); + case reflection::Double: return ReadScalar<double>(data); + case reflection::String: { + auto s = + reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) + data); + if (s) { + double d; + StringToNumber(s->c_str(), &d); + return d; + } else { + return 0.0; + } + } + default: return static_cast<double>(GetAnyValueI(type, data)); + } +} + +std::string GetAnyValueS(reflection::BaseType type, const uint8_t *data, + const reflection::Schema *schema, int type_index) { + switch (type) { + case reflection::Float: + case reflection::Double: return NumToString(GetAnyValueF(type, data)); + case reflection::String: { + auto s = + reinterpret_cast<const String *>(ReadScalar<uoffset_t>(data) + data); + return s ? s->c_str() : ""; + } + case reflection::Obj: + if (schema) { + // Convert the table to a string. This is mostly for debugging purposes, + // and does NOT promise to be JSON compliant. + // Also prefixes the type. + auto &objectdef = *schema->objects()->Get(type_index); + auto s = objectdef.name()->str(); + if (objectdef.is_struct()) { + s += "(struct)"; // TODO: implement this as well. + } else { + auto table_field = reinterpret_cast<const Table *>( + ReadScalar<uoffset_t>(data) + data); + s += " { "; + auto fielddefs = objectdef.fields(); + for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) { + auto &fielddef = **it; + if (!table_field->CheckField(fielddef.offset())) continue; + auto val = GetAnyFieldS(*table_field, fielddef, schema); + if (fielddef.type()->base_type() == reflection::String) { + std::string esc; + flatbuffers::EscapeString(val.c_str(), val.length(), &esc, true, + false); + val = esc; + } + s += fielddef.name()->str(); + s += ": "; + s += val; + s += ", "; + } + s += "}"; + } + return s; + } else { + return "(table)"; + } + case reflection::Vector: + return "[(elements)]"; // TODO: implement this as well. + case reflection::Union: return "(union)"; // TODO: implement this as well. + default: return NumToString(GetAnyValueI(type, data)); + } +} + +void SetAnyValueI(reflection::BaseType type, uint8_t *data, int64_t val) { +// clang-format off + #define FLATBUFFERS_SET(T) WriteScalar(data, static_cast<T>(val)) + switch (type) { + case reflection::UType: + case reflection::Bool: + case reflection::UByte: FLATBUFFERS_SET(uint8_t ); break; + case reflection::Byte: FLATBUFFERS_SET(int8_t ); break; + case reflection::Short: FLATBUFFERS_SET(int16_t ); break; + case reflection::UShort: FLATBUFFERS_SET(uint16_t); break; + case reflection::Int: FLATBUFFERS_SET(int32_t ); break; + case reflection::UInt: FLATBUFFERS_SET(uint32_t); break; + case reflection::Long: FLATBUFFERS_SET(int64_t ); break; + case reflection::ULong: FLATBUFFERS_SET(uint64_t); break; + case reflection::Float: FLATBUFFERS_SET(float ); break; + case reflection::Double: FLATBUFFERS_SET(double ); break; + // TODO: support strings + default: break; + } + #undef FLATBUFFERS_SET + // clang-format on +} + +void SetAnyValueF(reflection::BaseType type, uint8_t *data, double val) { + switch (type) { + case reflection::Float: WriteScalar(data, static_cast<float>(val)); break; + case reflection::Double: WriteScalar(data, val); break; + // TODO: support strings. + default: SetAnyValueI(type, data, static_cast<int64_t>(val)); break; + } +} + +void SetAnyValueS(reflection::BaseType type, uint8_t *data, const char *val) { + switch (type) { + case reflection::Float: + case reflection::Double: { + double d; + StringToNumber(val, &d); + SetAnyValueF(type, data, d); + break; + } + // TODO: support strings. + default: SetAnyValueI(type, data, StringToInt(val)); break; + } +} + +// Resize a FlatBuffer in-place by iterating through all offsets in the buffer +// and adjusting them by "delta" if they straddle the start offset. +// Once that is done, bytes can now be inserted/deleted safely. +// "delta" may be negative (shrinking). +// Unless "delta" is a multiple of the largest alignment, you'll create a small +// amount of garbage space in the buffer (usually 0..7 bytes). +// If your FlatBuffer's root table is not the schema's root table, you should +// pass in your root_table type as well. +class ResizeContext { + public: + ResizeContext(const reflection::Schema &schema, uoffset_t start, int delta, + std::vector<uint8_t> *flatbuf, + const reflection::Object *root_table = nullptr) + : schema_(schema), + startptr_(vector_data(*flatbuf) + start), + delta_(delta), + buf_(*flatbuf), + dag_check_(flatbuf->size() / sizeof(uoffset_t), false) { + auto mask = static_cast<int>(sizeof(largest_scalar_t) - 1); + delta_ = (delta_ + mask) & ~mask; + if (!delta_) return; // We can't shrink by less than largest_scalar_t. + // Now change all the offsets by delta_. + auto root = GetAnyRoot(vector_data(buf_)); + Straddle<uoffset_t, 1>(vector_data(buf_), root, vector_data(buf_)); + ResizeTable(root_table ? *root_table : *schema.root_table(), root); + // We can now add or remove bytes at start. + if (delta_ > 0) + buf_.insert(buf_.begin() + start, delta_, 0); + else + buf_.erase(buf_.begin() + start + delta_, buf_.begin() + start); + } + + // Check if the range between first (lower address) and second straddles + // the insertion point. If it does, change the offset at offsetloc (of + // type T, with direction D). + template<typename T, int D> + void Straddle(const void *first, const void *second, void *offsetloc) { + if (first <= startptr_ && second >= startptr_) { + WriteScalar<T>(offsetloc, ReadScalar<T>(offsetloc) + delta_ * D); + DagCheck(offsetloc) = true; + } + } + + // This returns a boolean that records if the corresponding offset location + // has been modified already. If so, we can't even read the corresponding + // offset, since it is pointing to a location that is illegal until the + // resize actually happens. + // This must be checked for every offset, since we can't know which offsets + // will straddle and which won't. + uint8_t &DagCheck(const void *offsetloc) { + auto dag_idx = reinterpret_cast<const uoffset_t *>(offsetloc) - + reinterpret_cast<const uoffset_t *>(vector_data(buf_)); + return dag_check_[dag_idx]; + } + + void ResizeTable(const reflection::Object &objectdef, Table *table) { + if (DagCheck(table)) return; // Table already visited. + auto vtable = table->GetVTable(); + // Early out: since all fields inside the table must point forwards in + // memory, if the insertion point is before the table we can stop here. + auto tableloc = reinterpret_cast<uint8_t *>(table); + if (startptr_ <= tableloc) { + // Check if insertion point is between the table and a vtable that + // precedes it. This can't happen in current construction code, but check + // just in case we ever change the way flatbuffers are built. + Straddle<soffset_t, -1>(vtable, table, table); + } else { + // Check each field. + auto fielddefs = objectdef.fields(); + for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) { + auto &fielddef = **it; + auto base_type = fielddef.type()->base_type(); + // Ignore scalars. + if (base_type <= reflection::Double) continue; + // Ignore fields that are not stored. + auto offset = table->GetOptionalFieldOffset(fielddef.offset()); + if (!offset) continue; + // Ignore structs. + auto subobjectdef = + base_type == reflection::Obj + ? schema_.objects()->Get(fielddef.type()->index()) + : nullptr; + if (subobjectdef && subobjectdef->is_struct()) continue; + // Get this fields' offset, and read it if safe. + auto offsetloc = tableloc + offset; + if (DagCheck(offsetloc)) continue; // This offset already visited. + auto ref = offsetloc + ReadScalar<uoffset_t>(offsetloc); + Straddle<uoffset_t, 1>(offsetloc, ref, offsetloc); + // Recurse. + switch (base_type) { + case reflection::Obj: { + ResizeTable(*subobjectdef, reinterpret_cast<Table *>(ref)); + break; + } + case reflection::Vector: { + auto elem_type = fielddef.type()->element(); + if (elem_type != reflection::Obj && elem_type != reflection::String) + break; + auto vec = reinterpret_cast<Vector<uoffset_t> *>(ref); + auto elemobjectdef = + elem_type == reflection::Obj + ? schema_.objects()->Get(fielddef.type()->index()) + : nullptr; + if (elemobjectdef && elemobjectdef->is_struct()) break; + for (uoffset_t i = 0; i < vec->size(); i++) { + auto loc = vec->Data() + i * sizeof(uoffset_t); + if (DagCheck(loc)) continue; // This offset already visited. + auto dest = loc + vec->Get(i); + Straddle<uoffset_t, 1>(loc, dest, loc); + if (elemobjectdef) + ResizeTable(*elemobjectdef, reinterpret_cast<Table *>(dest)); + } + break; + } + case reflection::Union: { + ResizeTable(GetUnionType(schema_, objectdef, fielddef, *table), + reinterpret_cast<Table *>(ref)); + break; + } + case reflection::String: break; + default: FLATBUFFERS_ASSERT(false); + } + } + // Check if the vtable offset points beyond the insertion point. + // Must do this last, since GetOptionalFieldOffset above still reads + // this value. + Straddle<soffset_t, -1>(table, vtable, table); + } + } + + private: + const reflection::Schema &schema_; + uint8_t *startptr_; + int delta_; + std::vector<uint8_t> &buf_; + std::vector<uint8_t> dag_check_; +}; + +void SetString(const reflection::Schema &schema, const std::string &val, + const String *str, std::vector<uint8_t> *flatbuf, + const reflection::Object *root_table) { + auto delta = static_cast<int>(val.size()) - static_cast<int>(str->size()); + auto str_start = static_cast<uoffset_t>( + reinterpret_cast<const uint8_t *>(str) - vector_data(*flatbuf)); + auto start = str_start + static_cast<uoffset_t>(sizeof(uoffset_t)); + if (delta) { + // Clear the old string, since we don't want parts of it remaining. + memset(vector_data(*flatbuf) + start, 0, str->size()); + // Different size, we must expand (or contract). + ResizeContext(schema, start, delta, flatbuf, root_table); + // Set the new length. + WriteScalar(vector_data(*flatbuf) + str_start, + static_cast<uoffset_t>(val.size())); + } + // Copy new data. Safe because we created the right amount of space. + memcpy(vector_data(*flatbuf) + start, val.c_str(), val.size() + 1); +} + +uint8_t *ResizeAnyVector(const reflection::Schema &schema, uoffset_t newsize, + const VectorOfAny *vec, uoffset_t num_elems, + uoffset_t elem_size, std::vector<uint8_t> *flatbuf, + const reflection::Object *root_table) { + auto delta_elem = static_cast<int>(newsize) - static_cast<int>(num_elems); + auto delta_bytes = delta_elem * static_cast<int>(elem_size); + auto vec_start = + reinterpret_cast<const uint8_t *>(vec) - vector_data(*flatbuf); + auto start = static_cast<uoffset_t>(vec_start + sizeof(uoffset_t) + + elem_size * num_elems); + if (delta_bytes) { + if (delta_elem < 0) { + // Clear elements we're throwing away, since some might remain in the + // buffer. + auto size_clear = -delta_elem * elem_size; + memset(vector_data(*flatbuf) + start - size_clear, 0, size_clear); + } + ResizeContext(schema, start, delta_bytes, flatbuf, root_table); + WriteScalar(vector_data(*flatbuf) + vec_start, newsize); // Length field. + // Set new elements to 0.. this can be overwritten by the caller. + if (delta_elem > 0) { + memset(vector_data(*flatbuf) + start, 0, delta_elem * elem_size); + } + } + return vector_data(*flatbuf) + start; +} + +const uint8_t *AddFlatBuffer(std::vector<uint8_t> &flatbuf, + const uint8_t *newbuf, size_t newlen) { + // Align to sizeof(uoffset_t) past sizeof(largest_scalar_t) since we're + // going to chop off the root offset. + while ((flatbuf.size() & (sizeof(uoffset_t) - 1)) || + !(flatbuf.size() & (sizeof(largest_scalar_t) - 1))) { + flatbuf.push_back(0); + } + auto insertion_point = static_cast<uoffset_t>(flatbuf.size()); + // Insert the entire FlatBuffer minus the root pointer. + flatbuf.insert(flatbuf.end(), newbuf + sizeof(uoffset_t), newbuf + newlen); + auto root_offset = ReadScalar<uoffset_t>(newbuf) - sizeof(uoffset_t); + return vector_data(flatbuf) + insertion_point + root_offset; +} + +void CopyInline(FlatBufferBuilder &fbb, const reflection::Field &fielddef, + const Table &table, size_t align, size_t size) { + fbb.Align(align); + fbb.PushBytes(table.GetStruct<const uint8_t *>(fielddef.offset()), size); + fbb.TrackField(fielddef.offset(), fbb.GetSize()); +} + +Offset<const Table *> CopyTable(FlatBufferBuilder &fbb, + const reflection::Schema &schema, + const reflection::Object &objectdef, + const Table &table, bool use_string_pooling) { + // Before we can construct the table, we have to first generate any + // subobjects, and collect their offsets. + std::vector<uoffset_t> offsets; + auto fielddefs = objectdef.fields(); + for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) { + auto &fielddef = **it; + // Skip if field is not present in the source. + if (!table.CheckField(fielddef.offset())) continue; + uoffset_t offset = 0; + switch (fielddef.type()->base_type()) { + case reflection::String: { + offset = use_string_pooling + ? fbb.CreateSharedString(GetFieldS(table, fielddef)).o + : fbb.CreateString(GetFieldS(table, fielddef)).o; + break; + } + case reflection::Obj: { + auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index()); + if (!subobjectdef.is_struct()) { + offset = CopyTable(fbb, schema, subobjectdef, + *GetFieldT(table, fielddef), use_string_pooling) + .o; + } + break; + } + case reflection::Union: { + auto &subobjectdef = GetUnionType(schema, objectdef, fielddef, table); + offset = CopyTable(fbb, schema, subobjectdef, + *GetFieldT(table, fielddef), use_string_pooling) + .o; + break; + } + case reflection::Vector: { + auto vec = + table.GetPointer<const Vector<Offset<Table>> *>(fielddef.offset()); + auto element_base_type = fielddef.type()->element(); + auto elemobjectdef = + element_base_type == reflection::Obj + ? schema.objects()->Get(fielddef.type()->index()) + : nullptr; + switch (element_base_type) { + case reflection::String: { + std::vector<Offset<const String *>> elements(vec->size()); + auto vec_s = reinterpret_cast<const Vector<Offset<String>> *>(vec); + for (uoffset_t i = 0; i < vec_s->size(); i++) { + elements[i] = use_string_pooling + ? fbb.CreateSharedString(vec_s->Get(i)).o + : fbb.CreateString(vec_s->Get(i)).o; + } + offset = fbb.CreateVector(elements).o; + break; + } + case reflection::Obj: { + if (!elemobjectdef->is_struct()) { + std::vector<Offset<const Table *>> elements(vec->size()); + for (uoffset_t i = 0; i < vec->size(); i++) { + elements[i] = CopyTable(fbb, schema, *elemobjectdef, + *vec->Get(i), use_string_pooling); + } + offset = fbb.CreateVector(elements).o; + break; + } + } + FLATBUFFERS_FALLTHROUGH(); // fall thru + default: { // Scalars and structs. + auto element_size = GetTypeSize(element_base_type); + if (elemobjectdef && elemobjectdef->is_struct()) + element_size = elemobjectdef->bytesize(); + fbb.StartVector(vec->size(), element_size); + fbb.PushBytes(vec->Data(), element_size * vec->size()); + offset = fbb.EndVector(vec->size()); + break; + } + } + break; + } + default: // Scalars. + break; + } + if (offset) { offsets.push_back(offset); } + } + // Now we can build the actual table from either offsets or scalar data. + auto start = objectdef.is_struct() ? fbb.StartStruct(objectdef.minalign()) + : fbb.StartTable(); + size_t offset_idx = 0; + for (auto it = fielddefs->begin(); it != fielddefs->end(); ++it) { + auto &fielddef = **it; + if (!table.CheckField(fielddef.offset())) continue; + auto base_type = fielddef.type()->base_type(); + switch (base_type) { + case reflection::Obj: { + auto &subobjectdef = *schema.objects()->Get(fielddef.type()->index()); + if (subobjectdef.is_struct()) { + CopyInline(fbb, fielddef, table, subobjectdef.minalign(), + subobjectdef.bytesize()); + break; + } + } + FLATBUFFERS_FALLTHROUGH(); // fall thru + case reflection::Union: + case reflection::String: + case reflection::Vector: + fbb.AddOffset(fielddef.offset(), Offset<void>(offsets[offset_idx++])); + break; + default: { // Scalars. + auto size = GetTypeSize(base_type); + CopyInline(fbb, fielddef, table, size, size); + break; + } + } + } + FLATBUFFERS_ASSERT(offset_idx == offsets.size()); + if (objectdef.is_struct()) { + fbb.ClearOffsets(); + return fbb.EndStruct(); + } else { + return fbb.EndTable(start); + } +} + +bool VerifyStruct(flatbuffers::Verifier &v, + const flatbuffers::Table &parent_table, + voffset_t field_offset, const reflection::Object &obj, + bool required) { + auto offset = parent_table.GetOptionalFieldOffset(field_offset); + if (required && !offset) { return false; } + + return !offset || v.Verify(reinterpret_cast<const uint8_t *>(&parent_table), + offset, obj.bytesize()); +} + +bool VerifyVectorOfStructs(flatbuffers::Verifier &v, + const flatbuffers::Table &parent_table, + voffset_t field_offset, + const reflection::Object &obj, bool required) { + auto p = parent_table.GetPointer<const uint8_t *>(field_offset); + if (required && !p) { return false; } + + return !p || v.VerifyVectorOrString(p, obj.bytesize()); +} + +// forward declare to resolve cyclic deps between VerifyObject and VerifyVector +bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema, + const reflection::Object &obj, + const flatbuffers::Table *table, bool required); + +bool VerifyUnion(flatbuffers::Verifier &v, const reflection::Schema &schema, + uint8_t utype, const uint8_t *elem, + const reflection::Field &union_field) { + if (!utype) return true; // Not present. + auto fb_enum = schema.enums()->Get(union_field.type()->index()); + if (utype >= fb_enum->values()->size()) return false; + auto elem_type = fb_enum->values()->Get(utype)->union_type(); + switch (elem_type->base_type()) { + case reflection::Obj: { + auto elem_obj = schema.objects()->Get(elem_type->index()); + if (elem_obj->is_struct()) { + return v.VerifyFromPointer(elem, elem_obj->bytesize()); + } else { + return VerifyObject(v, schema, *elem_obj, + reinterpret_cast<const flatbuffers::Table *>(elem), + true); + } + } + case reflection::String: + return v.VerifyString( + reinterpret_cast<const flatbuffers::String *>(elem)); + default: return false; + } +} + +bool VerifyVector(flatbuffers::Verifier &v, const reflection::Schema &schema, + const flatbuffers::Table &table, + const reflection::Field &vec_field) { + FLATBUFFERS_ASSERT(vec_field.type()->base_type() == reflection::Vector); + if (!table.VerifyField<uoffset_t>(v, vec_field.offset())) return false; + + switch (vec_field.type()->element()) { + case reflection::UType: + return v.VerifyVector(flatbuffers::GetFieldV<uint8_t>(table, vec_field)); + case reflection::Bool: + case reflection::Byte: + case reflection::UByte: + return v.VerifyVector(flatbuffers::GetFieldV<int8_t>(table, vec_field)); + case reflection::Short: + case reflection::UShort: + return v.VerifyVector(flatbuffers::GetFieldV<int16_t>(table, vec_field)); + case reflection::Int: + case reflection::UInt: + return v.VerifyVector(flatbuffers::GetFieldV<int32_t>(table, vec_field)); + case reflection::Long: + case reflection::ULong: + return v.VerifyVector(flatbuffers::GetFieldV<int64_t>(table, vec_field)); + case reflection::Float: + return v.VerifyVector(flatbuffers::GetFieldV<float>(table, vec_field)); + case reflection::Double: + return v.VerifyVector(flatbuffers::GetFieldV<double>(table, vec_field)); + case reflection::String: { + auto vec_string = + flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::String>>( + table, vec_field); + if (v.VerifyVector(vec_string) && v.VerifyVectorOfStrings(vec_string)) { + return true; + } else { + return false; + } + } + case reflection::Obj: { + auto obj = schema.objects()->Get(vec_field.type()->index()); + if (obj->is_struct()) { + return VerifyVectorOfStructs(v, table, vec_field.offset(), *obj, + vec_field.required()); + } else { + auto vec = + flatbuffers::GetFieldV<flatbuffers::Offset<flatbuffers::Table>>( + table, vec_field); + if (!v.VerifyVector(vec)) return false; + if (!vec) return true; + for (uoffset_t j = 0; j < vec->size(); j++) { + if (!VerifyObject(v, schema, *obj, vec->Get(j), true)) { + return false; + } + } + return true; + } + } + case reflection::Union: { + auto vec = flatbuffers::GetFieldV<flatbuffers::Offset<uint8_t>>( + table, vec_field); + if (!v.VerifyVector(vec)) return false; + if (!vec) return true; + auto type_vec = table.GetPointer<Vector<uint8_t> *>(vec_field.offset() - + sizeof(voffset_t)); + if (!v.VerifyVector(type_vec)) return false; + for (uoffset_t j = 0; j < vec->size(); j++) { + // get union type from the prev field + auto utype = type_vec->Get(j); + auto elem = vec->Get(j); + if (!VerifyUnion(v, schema, utype, elem, vec_field)) return false; + } + return true; + } + case reflection::Vector: + case reflection::None: + default: FLATBUFFERS_ASSERT(false); return false; + } +} + +bool VerifyObject(flatbuffers::Verifier &v, const reflection::Schema &schema, + const reflection::Object &obj, + const flatbuffers::Table *table, bool required) { + if (!table) return !required; + if (!table->VerifyTableStart(v)) return false; + for (uoffset_t i = 0; i < obj.fields()->size(); i++) { + auto field_def = obj.fields()->Get(i); + switch (field_def->type()->base_type()) { + case reflection::None: FLATBUFFERS_ASSERT(false); break; + case reflection::UType: + if (!table->VerifyField<uint8_t>(v, field_def->offset())) return false; + break; + case reflection::Bool: + case reflection::Byte: + case reflection::UByte: + if (!table->VerifyField<int8_t>(v, field_def->offset())) return false; + break; + case reflection::Short: + case reflection::UShort: + if (!table->VerifyField<int16_t>(v, field_def->offset())) return false; + break; + case reflection::Int: + case reflection::UInt: + if (!table->VerifyField<int32_t>(v, field_def->offset())) return false; + break; + case reflection::Long: + case reflection::ULong: + if (!table->VerifyField<int64_t>(v, field_def->offset())) return false; + break; + case reflection::Float: + if (!table->VerifyField<float>(v, field_def->offset())) return false; + break; + case reflection::Double: + if (!table->VerifyField<double>(v, field_def->offset())) return false; + break; + case reflection::String: + if (!table->VerifyField<uoffset_t>(v, field_def->offset()) || + !v.VerifyString(flatbuffers::GetFieldS(*table, *field_def))) { + return false; + } + break; + case reflection::Vector: + if (!VerifyVector(v, schema, *table, *field_def)) return false; + break; + case reflection::Obj: { + auto child_obj = schema.objects()->Get(field_def->type()->index()); + if (child_obj->is_struct()) { + if (!VerifyStruct(v, *table, field_def->offset(), *child_obj, + field_def->required())) { + return false; + } + } else { + if (!VerifyObject(v, schema, *child_obj, + flatbuffers::GetFieldT(*table, *field_def), + field_def->required())) { + return false; + } + } + break; + } + case reflection::Union: { + // get union type from the prev field + voffset_t utype_offset = field_def->offset() - sizeof(voffset_t); + auto utype = table->GetField<uint8_t>(utype_offset, 0); + auto uval = reinterpret_cast<const uint8_t *>( + flatbuffers::GetFieldT(*table, *field_def)); + if (!VerifyUnion(v, schema, utype, uval, *field_def)) { return false; } + break; + } + default: FLATBUFFERS_ASSERT(false); break; + } + } + + if (!v.EndTable()) return false; + + return true; +} + +bool Verify(const reflection::Schema &schema, const reflection::Object &root, + const uint8_t *buf, size_t length, uoffset_t max_depth /*= 64*/, + uoffset_t max_tables /*= 1000000*/) { + Verifier v(buf, length, max_depth, max_tables); + return VerifyObject(v, schema, root, flatbuffers::GetAnyRoot(buf), true); +} + +} // namespace flatbuffers diff --git a/contrib/libs/flatbuffers/src/util.cpp b/contrib/libs/flatbuffers/src/util.cpp new file mode 100644 index 0000000000..3670a01939 --- /dev/null +++ b/contrib/libs/flatbuffers/src/util.cpp @@ -0,0 +1,287 @@ +/* + * Copyright 2016 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// clang-format off +// Dont't remove `format off`, it prevent reordering of win-includes. + +#if defined(__MINGW32__) || defined(__MINGW64__) || defined(__CYGWIN__) || \ + defined(__QNXNTO__) +# define _POSIX_C_SOURCE 200809L +# define _XOPEN_SOURCE 700L +#endif + +#ifdef _WIN32 +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# ifndef NOMINMAX +# define NOMINMAX +# endif +# ifdef _MSC_VER +# include <crtdbg.h> +# endif +# include <windows.h> // Must be included before <direct.h> +# include <direct.h> +# include <winbase.h> +# undef interface // This is also important because of reasons +#endif +// clang-format on + +#include "flatbuffers/base.h" +#include "flatbuffers/util.h" + +#include <sys/stat.h> +#include <clocale> +#include <cstdlib> +#include <fstream> + +namespace flatbuffers { + +bool FileExistsRaw(const char *name) { + std::ifstream ifs(name); + return ifs.good(); +} + +bool LoadFileRaw(const char *name, bool binary, std::string *buf) { + if (DirExists(name)) return false; + std::ifstream ifs(name, binary ? std::ifstream::binary : std::ifstream::in); + if (!ifs.is_open()) return false; + if (binary) { + // The fastest way to read a file into a string. + ifs.seekg(0, std::ios::end); + auto size = ifs.tellg(); + (*buf).resize(static_cast<size_t>(size)); + ifs.seekg(0, std::ios::beg); + ifs.read(&(*buf)[0], (*buf).size()); + } else { + // This is slower, but works correctly on all platforms for text files. + std::ostringstream oss; + oss << ifs.rdbuf(); + *buf = oss.str(); + } + return !ifs.bad(); +} + +static LoadFileFunction g_load_file_function = LoadFileRaw; +static FileExistsFunction g_file_exists_function = FileExistsRaw; + +bool LoadFile(const char *name, bool binary, std::string *buf) { + FLATBUFFERS_ASSERT(g_load_file_function); + return g_load_file_function(name, binary, buf); +} + +bool FileExists(const char *name) { + FLATBUFFERS_ASSERT(g_file_exists_function); + return g_file_exists_function(name); +} + +bool DirExists(const char *name) { + // clang-format off + + #ifdef _WIN32 + #define flatbuffers_stat _stat + #define FLATBUFFERS_S_IFDIR _S_IFDIR + #else + #define flatbuffers_stat stat + #define FLATBUFFERS_S_IFDIR S_IFDIR + #endif + // clang-format on + struct flatbuffers_stat file_info; + if (flatbuffers_stat(name, &file_info) != 0) return false; + return (file_info.st_mode & FLATBUFFERS_S_IFDIR) != 0; +} + +LoadFileFunction SetLoadFileFunction(LoadFileFunction load_file_function) { + LoadFileFunction previous_function = g_load_file_function; + g_load_file_function = load_file_function ? load_file_function : LoadFileRaw; + return previous_function; +} + +FileExistsFunction SetFileExistsFunction( + FileExistsFunction file_exists_function) { + FileExistsFunction previous_function = g_file_exists_function; + g_file_exists_function = + file_exists_function ? file_exists_function : FileExistsRaw; + return previous_function; +} + +bool SaveFile(const char *name, const char *buf, size_t len, bool binary) { + std::ofstream ofs(name, binary ? std::ofstream::binary : std::ofstream::out); + if (!ofs.is_open()) return false; + ofs.write(buf, len); + return !ofs.bad(); +} + +// We internally store paths in posix format ('/'). Paths supplied +// by the user should go through PosixPath to ensure correct behavior +// on Windows when paths are string-compared. + +static const char kPathSeparatorWindows = '\\'; +static const char *PathSeparatorSet = "\\/"; // Intentionally no ':' + +std::string StripExtension(const std::string &filepath) { + size_t i = filepath.find_last_of('.'); + return i != std::string::npos ? filepath.substr(0, i) : filepath; +} + +std::string GetExtension(const std::string &filepath) { + size_t i = filepath.find_last_of('.'); + return i != std::string::npos ? filepath.substr(i + 1) : ""; +} + +std::string StripPath(const std::string &filepath) { + size_t i = filepath.find_last_of(PathSeparatorSet); + return i != std::string::npos ? filepath.substr(i + 1) : filepath; +} + +std::string StripFileName(const std::string &filepath) { + size_t i = filepath.find_last_of(PathSeparatorSet); + return i != std::string::npos ? filepath.substr(0, i) : ""; +} + +std::string ConCatPathFileName(const std::string &path, + const std::string &filename) { + std::string filepath = path; + if (filepath.length()) { + char &filepath_last_character = string_back(filepath); + if (filepath_last_character == kPathSeparatorWindows) { + filepath_last_character = kPathSeparator; + } else if (filepath_last_character != kPathSeparator) { + filepath += kPathSeparator; + } + } + filepath += filename; + // Ignore './' at the start of filepath. + if (filepath[0] == '.' && filepath[1] == kPathSeparator) { + filepath.erase(0, 2); + } + return filepath; +} + +std::string PosixPath(const char *path) { + std::string p = path; + std::replace(p.begin(), p.end(), '\\', '/'); + return p; +} + +void EnsureDirExists(const std::string &filepath) { + auto parent = StripFileName(filepath); + if (parent.length()) EnsureDirExists(parent); + // clang-format off + + #ifdef _WIN32 + (void)_mkdir(filepath.c_str()); + #else + mkdir(filepath.c_str(), S_IRWXU|S_IRGRP|S_IXGRP); + #endif + // clang-format on +} + +std::string AbsolutePath(const std::string &filepath) { + // clang-format off + + #ifdef FLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION + return filepath; + #else + #ifdef _WIN32 + char abs_path[MAX_PATH]; + return GetFullPathNameA(filepath.c_str(), MAX_PATH, abs_path, nullptr) + #else + char *abs_path_temp = realpath(filepath.c_str(), nullptr); + bool success = abs_path_temp != nullptr; + std::string abs_path; + if(success) { + abs_path = abs_path_temp; + free(abs_path_temp); + } + return success + #endif + ? abs_path + : filepath; + #endif // FLATBUFFERS_NO_ABSOLUTE_PATH_RESOLUTION + // clang-format on +} + +// Locale-independent code. +#if defined(FLATBUFFERS_LOCALE_INDEPENDENT) && \ + (FLATBUFFERS_LOCALE_INDEPENDENT > 0) + +// clang-format off +// Allocate locale instance at startup of application. +ClassicLocale ClassicLocale::instance_; + +#ifdef _MSC_VER + ClassicLocale::ClassicLocale() + : locale_(_create_locale(LC_ALL, "C")) {} + ClassicLocale::~ClassicLocale() { _free_locale(locale_); } +#else + ClassicLocale::ClassicLocale() + : locale_(newlocale(LC_ALL, "C", nullptr)) {} + ClassicLocale::~ClassicLocale() { freelocale(locale_); } +#endif +// clang-format on + +#endif // !FLATBUFFERS_LOCALE_INDEPENDENT + +std::string RemoveStringQuotes(const std::string &s) { + auto ch = *s.c_str(); + return ((s.size() >= 2) && (ch == '\"' || ch == '\'') && + (ch == string_back(s))) + ? s.substr(1, s.length() - 2) + : s; +} + +bool SetGlobalTestLocale(const char *locale_name, std::string *_value) { + const auto the_locale = setlocale(LC_ALL, locale_name); + if (!the_locale) return false; + if (_value) *_value = std::string(the_locale); + return true; +} + +bool ReadEnvironmentVariable(const char *var_name, std::string *_value) { +#ifdef _MSC_VER + __pragma(warning(disable : 4996)); // _CRT_SECURE_NO_WARNINGS +#endif + auto env_str = std::getenv(var_name); + if (!env_str) return false; + if (_value) *_value = std::string(env_str); + return true; +} + +void SetupDefaultCRTReportMode() { + // clang-format off + + #ifdef _MSC_VER + // By default, send all reports to STDOUT to prevent CI hangs. + // Enable assert report box [Abort|Retry|Ignore] if a debugger is present. + const int dbg_mode = (_CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG) | + (IsDebuggerPresent() ? _CRTDBG_MODE_WNDW : 0); + (void)dbg_mode; // release mode fix + // CrtDebug reports to _CRT_WARN channel. + _CrtSetReportMode(_CRT_WARN, dbg_mode); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT); + // The assert from <assert.h> reports to _CRT_ERROR channel + _CrtSetReportMode(_CRT_ERROR, dbg_mode); + _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT); + // Internal CRT assert channel? + _CrtSetReportMode(_CRT_ASSERT, dbg_mode); + _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT); + #endif + + // clang-format on +} + +} // namespace flatbuffers diff --git a/contrib/libs/flatbuffers/ya.make b/contrib/libs/flatbuffers/ya.make new file mode 100644 index 0000000000..0fa3e01129 --- /dev/null +++ b/contrib/libs/flatbuffers/ya.make @@ -0,0 +1,40 @@ +# Generated by devtools/yamaker from nixpkgs 22.05. + +LIBRARY() + +VERSION(2.0.0) + +ORIGINAL_SOURCE(https://github.com/google/flatbuffers/archive/v2.0.0.tar.gz) + +LICENSE( + Apache-2.0 AND + BSD-3-Clause +) + +LICENSE_TEXTS(.yandex_meta/licenses.list.txt) + +ADDINCL( + contrib/libs/flatbuffers/include +) + +NO_COMPILER_WARNINGS() + +NO_UTIL() + +CFLAGS( + -DFLATBUFFERS_LOCALE_INDEPENDENT=1 +) + +SRCS( + src/idl_gen_text.cpp + src/idl_parser.cpp + src/reflection.cpp + src/util.cpp +) + +END() + +RECURSE( + flatc + samples +) |