Merge branch 'master' of github.com:google/flatbuffers

This commit is contained in:
Romain Gilles
2016-07-05 11:40:33 +02:00
66 changed files with 4342 additions and 1385 deletions

View File

@@ -63,6 +63,13 @@ function(build_flatbuffers flatbuffers_schemas
set(FLATC_TARGET flatc)
set(FLATC flatc)
endif()
set(FLATC_SCHEMA_ARGS --gen-mutable)
if(FLATBUFFERS_FLATC_SCHEMA_EXTRA_ARGS)
set(FLATC_SCHEMA_ARGS
${FLATBUFFERS_FLATC_SCHEMA_EXTRA_ARGS}
${FLATC_SCHEMA_ARGS}
)
endif()
set(schema_glob "*.fbs")
# Generate the include files parameters.
@@ -86,7 +93,7 @@ function(build_flatbuffers flatbuffers_schemas
set(generated_include ${generated_includes_dir}/${filename}_generated.h)
add_custom_command(
OUTPUT ${generated_include}
COMMAND ${FLATC} --gen-mutable
COMMAND ${FLATC} ${FLATC_SCHEMA_ARGS}
-o ${generated_includes_dir}
${include_params}
-c ${schema}

View File

@@ -9,6 +9,7 @@ option(FLATBUFFERS_INSTALL "Enable the installation of targets." ON)
option(FLATBUFFERS_BUILD_FLATLIB "Enable the build of the flatbuffers library" ON)
option(FLATBUFFERS_BUILD_FLATC "Enable the build of the flatbuffers compiler" ON)
option(FLATBUFFERS_BUILD_FLATHASH "Enable the build of flathash" ON)
option(FLATBUFFERS_BUILD_GRPCTEST "Enable the build of grpctest" OFF)
if(NOT FLATBUFFERS_BUILD_FLATC AND FLATBUFFERS_BUILD_TESTS)
message(WARNING
@@ -39,7 +40,10 @@ set(FlatBuffers_Compiler_SRCS
src/idl_gen_php.cpp
src/idl_gen_python.cpp
src/idl_gen_fbs.cpp
src/idl_gen_grpc.cpp
src/flatc.cpp
grpc/src/compiler/cpp_generator.h
grpc/src/compiler/cpp_generator.cc
)
set(FlatHash_SRCS
@@ -76,6 +80,16 @@ set(FlatBuffers_Sample_Text_SRCS
${CMAKE_CURRENT_BINARY_DIR}/samples/monster_generated.h
)
set(FlatBuffers_GRPCTest_SRCS
include/flatbuffers/flatbuffers.h
include/flatbuffers/grpc.h
tests/monster_test.grpc.fb.h
tests/monster_test.grpc.fb.cc
grpc/tests/grpctest.cpp
# file generated by running compiler on samples/monster.fbs
${CMAKE_CURRENT_BINARY_DIR}/samples/monster_generated.h
)
# source_group(Compiler FILES ${FlatBuffers_Compiler_SRCS})
# source_group(Tests FILES ${FlatBuffers_Tests_SRCS})
@@ -129,6 +143,7 @@ if(BIICODE)
endif()
include_directories(include)
include_directories(grpc)
if(FLATBUFFERS_BUILD_FLATLIB)
add_library(flatbuffers STATIC ${FlatBuffers_Library_SRCS})
@@ -174,6 +189,14 @@ if(FLATBUFFERS_BUILD_TESTS)
add_executable(flatsampletext ${FlatBuffers_Sample_Text_SRCS})
endif()
if(FLATBUFFERS_BUILD_GRPCTEST)
if(CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unused-parameter")
endif()
add_executable(grpctest ${FlatBuffers_GRPCTest_SRCS})
target_link_libraries(grpctest grpc++_unsecure grpc pthread dl)
endif()
if(FLATBUFFERS_INSTALL)
install(DIRECTORY include/flatbuffers DESTINATION include)
if(FLATBUFFERS_BUILD_FLATLIB)

View File

@@ -18,5 +18,5 @@ APP_PROJECT_PATH := $(call my-dir)/..
APP_STL := gnustl_static
APP_ABI := armeabi-v7a
NDK_TOOLCHAIN_VERSION := 4.8
APP_CPPFLAGS += -std=c++11

View File

@@ -33,6 +33,8 @@ For any schema input files, one or more generators can be specified:
- `--php`: Generate PHP code.
- `--grpc`: Generate RPC stub code for GRPC.
For any data input files:
- `--binary`, `-b` : If data is contained in this file, generate a

View File

@@ -237,7 +237,8 @@ as the response (both of which must be table types):
}
What code this produces and how it is used depends on language and RPC system
used, FlatBuffers itself does not offer this functionality.
used, there is preliminary support for GRPC through the `--grpc` code generator,
see `grpc/tests` for an example.
### Comments & documentation
@@ -271,7 +272,7 @@ Current understood attributes:
the union field should have id 8, and the unions type field will
implicitly be 7.
IDs allow the fields to be placed in any order in the schema.
When a new field is added to the schema is must use the next available ID.
When a new field is added to the schema it must use the next available ID.
- `deprecated` (on a field): do not generate accessors for this field
anymore, code should stop using this data.
- `required` (on a non-scalar table field): this field must always be set.
@@ -333,6 +334,10 @@ JSON:
- A field that has the value `null` (e.g. `field: null`) is intended to
have the default value for that field (thus has the same effect as if
that field wasn't specified at all).
- It has some built in conversion functions, so you can write for example
`rad(180)` where ever you'd normally write `3.14159`.
Currently supports the following functions: `rad`, `deg`, `cos`, `sin`,
`tan`, `acos`, `asin`, `atan`.
When parsing JSON, it recognizes the following escape codes in strings:

View File

@@ -790,6 +790,14 @@ offsets.
~~~
</div>
<div class="language-cpp">
<br>
Note there's additional convenience overloads of `CreateVector`, allowing you
to work with data that's not in a `std::vector`, or allowing you to generate
elements by calling a lambda. For the common case of `std::vector<std::string>`
there's also `CreateVectorOfStrings`.
</div>
To create a `struct`, use the `Vec3` class/struct that was generated by
the schema compiler:
@@ -1075,7 +1083,7 @@ Here is a repetition these lines, to help highlight them more clearly:
<div class="language-c">
~~~{.c}
// Add union type and data simultanously.
ns(Monster_equipped_Weapon_add(B, axe));
ns(Monster_equipped_Weapon_add(B, axe));
~~~
</div>

11
grpc/README.md Normal file
View File

@@ -0,0 +1,11 @@
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.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,147 @@
/*
*
* 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>
#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;
};
// An abstract interface representing a method.
struct Method {
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 NoStreaming() const = 0;
virtual bool ClientOnlyStreaming() const = 0;
virtual bool ServerOnlyStreaming() const = 0;
virtual bool BidiStreaming() const = 0;
};
// An abstract interface representing a service.
struct Service {
virtual ~Service() {}
virtual grpc::string name() 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 Indent() = 0;
virtual void Outdent() = 0;
};
// An interface that allows the source generated to be output using various
// libraries/idls/serializers.
struct File {
virtual ~File() {}
virtual grpc::string filename() const = 0;
virtual grpc::string filename_without_ext() const = 0;
virtual grpc::string message_header_ext() const = 0;
virtual grpc::string service_header_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 = 0;
};
// Return the prologue of the generated header file.
grpc::string GetHeaderPrologue(File *file, const Parameters &params);
// Return the includes needed for generated header file.
grpc::string GetHeaderIncludes(File *file, const Parameters &params);
// Return the includes needed for generated source file.
grpc::string GetSourceIncludes(File *file, const Parameters &params);
// Return the epilogue of the generated header file.
grpc::string GetHeaderEpilogue(File *file, const Parameters &params);
// Return the prologue of the generated source file.
grpc::string GetSourcePrologue(File *file, const Parameters &params);
// Return the services for generated header file.
grpc::string GetHeaderServices(File *file, const Parameters &params);
// Return the services for generated source file.
grpc::string GetSourceServices(File *file, const Parameters &params);
// Return the epilogue of the generated source file.
grpc::string GetSourceEpilogue(File *file, const Parameters &params);
} // namespace grpc_cpp_generator
#endif // GRPC_INTERNAL_COMPILER_CPP_GENERATOR_H

124
grpc/tests/grpctest.cpp Normal file
View File

@@ -0,0 +1,124 @@
/*
* 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 <thread>
#include <grpc++/grpc++.h>
#include "monster_test_generated.h"
#include "monster_test.grpc.fb.h"
using namespace MyGame::Example;
// The callback implementation of our server, that derives from the generated
// code. It implements all rpcs specified in the FlatBuffers schema.
class ServiceImpl final : public MyGame::Example::MonsterStorage::Service {
virtual ::grpc::Status Store(::grpc::ServerContext* context,
const flatbuffers::BufferRef<Monster> *request,
flatbuffers::BufferRef<Stat> *response)
override {
// Create a response from the incoming request name.
fbb_.Clear();
auto stat_offset = CreateStat(fbb_, fbb_.CreateString("Hello, " +
request->GetRoot()->name()->str()));
fbb_.Finish(stat_offset);
// Since we keep reusing the same FlatBufferBuilder, the memory it owns
// remains valid until the next call (this BufferRef doesn't own the
// memory it points to).
*response = flatbuffers::BufferRef<Stat>(fbb_.GetBufferPointer(),
fbb_.GetSize());
return grpc::Status::OK;
}
virtual ::grpc::Status Retrieve(::grpc::ServerContext *context,
const flatbuffers::BufferRef<Stat> *request,
flatbuffers::BufferRef<Monster> *response)
override {
assert(false); // We're not actually using this RPC.
return grpc::Status::CANCELLED;
}
private:
flatbuffers::FlatBufferBuilder fbb_;
};
// Track the server instance, so we can terminate it later.
grpc::Server *server_instance = nullptr;
// Mutex to protec this variable.
std::mutex wait_for_server;
std::condition_variable server_instance_cv;
// This function implements the server thread.
void RunServer() {
auto server_address = "0.0.0.0:50051";
// Callback interface we implemented above.
ServiceImpl service;
grpc::ServerBuilder builder;
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
builder.RegisterService(&service);
// Start the server. Lock to change the variable we're changing.
wait_for_server.lock();
server_instance = builder.BuildAndStart().release();
wait_for_server.unlock();
server_instance_cv.notify_one();
std::cout << "Server listening on " << server_address << std::endl;
// This will block the thread and serve requests.
server_instance->Wait();
}
int main(int /*argc*/, const char * /*argv*/[]) {
// Launch server.
std::thread server_thread(RunServer);
// wait for server to spin up.
std::unique_lock<std::mutex> lock(wait_for_server);
while (!server_instance) server_instance_cv.wait(lock);
// Now connect the client.
auto channel = grpc::CreateChannel("localhost:50051",
grpc::InsecureChannelCredentials());
auto stub = MyGame::Example::MonsterStorage::NewStub(channel);
grpc::ClientContext context;
// Build a request with the name set.
flatbuffers::FlatBufferBuilder fbb;
auto monster_offset = CreateMonster(fbb, 0, 0, 0, fbb.CreateString("Fred"));
fbb.Finish(monster_offset);
auto request = flatbuffers::BufferRef<Monster>(fbb.GetBufferPointer(),
fbb.GetSize());
flatbuffers::BufferRef<Stat> response;
// The actual RPC.
auto status = stub->Store(&context, request, &response);
if (status.ok()) {
auto resp = response.GetRoot()->id();
std::cout << "RPC response: " << resp->str() << std::endl;
} else {
std::cout << "RPC failed" << std::endl;
}
server_instance->Shutdown();
server_thread.join();
delete server_instance;
return 0;
}

View File

@@ -24,11 +24,12 @@ class BaseGenerator {
virtual bool generate() = 0;
static const std::string NamespaceDir(const Parser &parser,
const std::string &path) {
const std::string &path,
const Namespace &ns) {
EnsureDirExists(path.c_str());
if (parser.opts.one_file) return path;
std::string namespace_dir = path; // Either empty or ends in separator.
auto &namespaces = parser.namespaces_.back()->components;
auto &namespaces = ns.components;
for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
namespace_dir += *it + kPathSeparator;
EnsureDirExists(namespace_dir.c_str());
@@ -38,17 +39,24 @@ class BaseGenerator {
protected:
BaseGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
const std::string &file_name,
const std::string qualifying_start,
const std::string qualifying_separator)
: parser_(parser),
path_(path),
file_name_(file_name),
namespace_dir_(BaseGenerator::NamespaceDir(parser, path)){};
qualifying_start_(qualifying_start),
qualifying_separator_(qualifying_separator){};
virtual ~BaseGenerator(){};
// No copy/assign.
BaseGenerator &operator=(const BaseGenerator &);
BaseGenerator(const BaseGenerator &);
const std::string NamespaceDir(const Namespace &ns) {
return BaseGenerator::NamespaceDir(parser_, path_, ns);
}
const char *FlatBuffersGeneratedWarning() {
return "automatically generated by the FlatBuffers compiler,"
" do not modify\n\n";
@@ -66,9 +74,9 @@ class BaseGenerator {
return true;
}
std::string FullNamespace(const char *separator) {
std::string FullNamespace(const char *separator, const Namespace &ns) {
std::string namespace_name;
auto &namespaces = parser_.namespaces_.back()->components;
auto &namespaces = ns.components;
for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
if (namespace_name.length()) namespace_name += separator;
namespace_name += *it;
@@ -76,15 +84,36 @@ class BaseGenerator {
return namespace_name;
}
const std::string LastNamespacePart() {
auto &namespaces = parser_.namespaces_.back()->components;
const std::string LastNamespacePart(const Namespace &ns) {
auto &namespaces = ns.components;
if (namespaces.size()) return *(namespaces.end() - 1); else return std::string("");
}
// 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() { return nullptr; }
// 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) {
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_;
return qualified_name + name;
}
std::string WrapInNameSpace(const Definition &def) {
return WrapInNameSpace(def.defined_namespace, def.name);
}
const Parser &parser_;
const std::string &path_;
const std::string &file_name_;
const std::string namespace_dir_;
const std::string qualifying_start_;
const std::string qualifying_separator_;
};
} // namespace flatbuffers

View File

@@ -36,16 +36,17 @@
(!defined(_MSC_VER) || _MSC_VER < 1600) && \
(!defined(__GNUC__) || \
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40400))
#error A C++11 compatible compiler with support for the auto typing is required for FlatBuffers.
#error A C++11 compatible compiler with support for the auto typing is \
required for FlatBuffers.
#error __cplusplus _MSC_VER __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__
#endif
#if !defined(__clang__) && \
defined(__GNUC__) && \
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40600)
// Backwards compatability for g++ 4.4, and 4.5 which don't have the nullptr and constexpr
// keywords. Note the __clang__ check is needed, because clang presents itself as an older GNUC
// compiler.
// Backwards compatability for g++ 4.4, and 4.5 which don't have the nullptr
// and constexpr keywords. Note the __clang__ check is needed, because clang
// presents itself as an older GNUC compiler.
#ifndef nullptr_t
const class nullptr_t {
public:
@@ -207,6 +208,7 @@ template<typename T> size_t AlignOf() {
// (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);
static return_type Read(const uint8_t *p, uoffset_t i) {
return EndianScalar((reinterpret_cast<const T *>(p))[i]);
@@ -214,6 +216,7 @@ template<typename T> struct IndirectHelper {
};
template<typename T> struct IndirectHelper<Offset<T>> {
typedef const T *return_type;
typedef T *mutable_return_type;
static const size_t element_stride = sizeof(uoffset_t);
static return_type Read(const uint8_t *p, uoffset_t i) {
p += i * sizeof(uoffset_t);
@@ -222,6 +225,7 @@ template<typename T> struct IndirectHelper<Offset<T>> {
};
template<typename T> struct IndirectHelper<const T *> {
typedef const T *return_type;
typedef T *mutable_return_type;
static const size_t element_stride = sizeof(T);
static return_type Read(const uint8_t *p, uoffset_t i) {
return reinterpret_cast<const T *>(p + i * sizeof(T));
@@ -306,6 +310,7 @@ public:
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());
@@ -347,6 +352,12 @@ public:
WriteScalar(data() + i, val - (Data() + i * sizeof(uoffset_t)));
}
// Get a mutable pointer to tables/strings inside this vector.
mutable_return_type GetMutableObject(uoffset_t i) const {
assert(i < size());
return const_cast<mutable_return_type>(IndirectHelper<T>::Read(Data(), i));
}
// The raw data in little endian format. Use with care.
const uint8_t *Data() const {
return reinterpret_cast<const uint8_t *>(&length_ + 1);
@@ -973,6 +984,33 @@ FLATBUFFERS_FINAL_CLASS
return CreateVector(v.data(), v.size());
}
/// @brief Serialize values returned by a function into a FlatBuffer `vector`.
/// This is a convenience function that takes care of iteration for you.
/// @tparam T The data type of the `std::vector` elements.
/// @param f A function that takes the current iteration 0..vector_size-1 and
/// returns any type that you can construct a FlatBuffers vector out of.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template<typename T> Offset<Vector<T>> CreateVector(size_t vector_size,
const std::function<T (size_t i)> &f) {
std::vector<T> elems(vector_size);
for (size_t i = 0; i < vector_size; i++) elems[i] = f(i);
return CreateVector(elems.data(), elems.size());
}
/// @brief Serialize a `std::vector<std::string>` into a FlatBuffer `vector`.
/// This is a convenience function for a common case.
/// @param v A const reference to the `std::vector` to serialize into the
/// buffer as a `vector`.
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
Offset<Vector<Offset<String>>> CreateVectorOfStrings(
const std::vector<std::string> &v) {
std::vector<Offset<String>> offsets(v.size());
for (size_t i = 0; i < v.size(); i++) offsets[i] = CreateString(v[i]);
return CreateVector(offsets.data(), offsets.size());
}
/// @brief Serialize an array of structs into a FlatBuffer `vector`.
/// @tparam T The data type of the struct array elements.
/// @param[in] v A pointer to the array of type `T` to serialize into the
@@ -981,7 +1019,7 @@ FLATBUFFERS_FINAL_CLASS
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template<typename T> Offset<Vector<const T *>> CreateVectorOfStructs(
const T *v, size_t len) {
const T *v, size_t len) {
StartVector(len * sizeof(T) / AlignOf<T>(), AlignOf<T>());
PushBytes(reinterpret_cast<const uint8_t *>(v), sizeof(T) * len);
return Offset<Vector<const T *>>(EndVector(len));
@@ -994,7 +1032,7 @@ FLATBUFFERS_FINAL_CLASS
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template<typename T> Offset<Vector<const T *>> CreateVectorOfStructs(
const std::vector<T> &v) {
const std::vector<T> &v) {
return CreateVectorOfStructs(v.data(), v.size());
}
@@ -1023,7 +1061,7 @@ FLATBUFFERS_FINAL_CLASS
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template<typename T> Offset<Vector<Offset<T>>> CreateVectorOfSortedTables(
Offset<T> *v, size_t len) {
Offset<T> *v, size_t len) {
std::sort(v, v + len, TableKeyComparator<T>(buf_));
return CreateVector(v, len);
}
@@ -1036,7 +1074,7 @@ FLATBUFFERS_FINAL_CLASS
/// @return Returns a typed `Offset` into the serialized data indicating
/// where the vector is stored.
template<typename T> Offset<Vector<Offset<T>>> CreateVectorOfSortedTables(
std::vector<Offset<T>> *v) {
std::vector<Offset<T>> *v) {
return CreateVectorOfSortedTables(v->data(), v->size());
}
@@ -1067,7 +1105,7 @@ FLATBUFFERS_FINAL_CLASS
/// written to at a later time to serialize the data into a `vector`
/// in the buffer.
template<typename T> Offset<Vector<T>> CreateUninitializedVector(
size_t len, T **buf) {
size_t len, T **buf) {
return CreateUninitializedVector(len, sizeof(T),
reinterpret_cast<uint8_t **>(buf));
}
@@ -1152,13 +1190,16 @@ template<typename T> const T *GetRoot(const void *buf) {
}
/// Helpers to get a typed pointer to objects that are currently beeing built.
/// @warning Creating new objects will lead to reallocations and invalidates the pointer!
template<typename T> T *GetMutableTemporaryPointer(FlatBufferBuilder &fbb, Offset<T> offset) {
/// @warning Creating new objects will lead to reallocations and invalidates
/// the pointer!
template<typename T> T *GetMutableTemporaryPointer(FlatBufferBuilder &fbb,
Offset<T> offset) {
return reinterpret_cast<T *>(fbb.GetCurrentBufferPointer() +
fbb.GetSize() - offset.o);
}
template<typename T> const T *GetTemporaryPointer(FlatBufferBuilder &fbb, Offset<T> offset) {
template<typename T> const T *GetTemporaryPointer(FlatBufferBuilder &fbb,
Offset<T> offset) {
return GetMutableTemporaryPointer<T>(fbb, offset);
}
@@ -1293,6 +1334,29 @@ class Verifier FLATBUFFERS_FINAL_CLASS {
size_t max_tables_;
};
// Convenient way to bundle a buffer and its length, to pass it around
// typed by its root.
// A BufferRef does not own its buffer.
struct BufferRefBase {}; // for std::is_base_of
template<typename T> struct BufferRef : BufferRefBase {
BufferRef() : buf(nullptr), len(0), must_free(false) {}
BufferRef(uint8_t *_buf, uoffset_t _len)
: buf(_buf), len(_len), must_free(false) {}
~BufferRef() { if (must_free) free(buf); }
const T *GetRoot() const { return flatbuffers::GetRoot<T>(buf); }
bool Verify() {
Verifier verifier(buf, len);
return verifier.VerifyBuffer<T>();
}
uint8_t *buf;
uoffset_t len;
bool must_free;
};
// "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.

View File

@@ -0,0 +1,72 @@
/*
* 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_GRPC_H_
#define FLATBUFFERS_GRPC_H_
// Helper functionality to glue FlatBuffers and GRPC.
#include "grpc++/support/byte_buffer.h"
#include "grpc/byte_buffer_reader.h"
namespace grpc {
template <class T>
class SerializationTraits<T, typename std::enable_if<std::is_base_of<
flatbuffers::BufferRefBase, T>::value>::type> {
public:
// The type we're passing here is a BufferRef, which is already serialized
// FlatBuffer data, which then gets passed to GRPC.
static grpc::Status Serialize(const T& msg,
grpc_byte_buffer **buffer,
bool *own_buffer) {
// TODO(wvo): make this work without copying.
auto slice = gpr_slice_from_copied_buffer(
reinterpret_cast<const char *>(msg.buf), msg.len);
*buffer = grpc_raw_byte_buffer_create(&slice, 1);
*own_buffer = true;
return grpc::Status();
}
// There is no de-serialization step in FlatBuffers, so we just receive
// the data from GRPC.
static grpc::Status Deserialize(grpc_byte_buffer *buffer,
T *msg,
int max_message_size) {
// TODO(wvo): make this more efficient / zero copy when possible.
auto len = grpc_byte_buffer_length(buffer);
msg->buf = reinterpret_cast<uint8_t *>(malloc(len));
msg->len = static_cast<flatbuffers::uoffset_t>(len);
msg->must_free = true;
uint8_t *current = msg->buf;
grpc_byte_buffer_reader reader;
grpc_byte_buffer_reader_init(&reader, buffer);
gpr_slice slice;
while (grpc_byte_buffer_reader_next(&reader, &slice)) {
memcpy(current, GPR_SLICE_START_PTR(slice), GPR_SLICE_LENGTH(slice));
current += GPR_SLICE_LENGTH(slice);
gpr_slice_unref(slice);
}
GPR_ASSERT(current == msg->buf + msg->len);
grpc_byte_buffer_reader_destroy(&reader);
grpc_byte_buffer_destroy(buffer);
return grpc::Status();
}
};
} // namespace grpc;
#endif // FLATBUFFERS_GRPC_H_

View File

@@ -359,6 +359,19 @@ struct IDLOptions {
lang(IDLOptions::kJava) {}
};
// This encapsulates where the parser is in the current source file.
struct ParserState {
ParserState() : cursor_(nullptr), line_(1), token_(-1) {}
protected:
const char *cursor_;
int line_; // the current line being parsed
int token_;
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:
@@ -400,14 +413,12 @@ class CheckedError {
#define FLATBUFFERS_CHECKED_ERROR CheckedError
#endif
class Parser {
class Parser : public ParserState {
public:
explicit Parser(const IDLOptions &options = IDLOptions())
: root_struct_def_(nullptr),
opts(options),
source_(nullptr),
cursor_(nullptr),
line_(1),
anonymous_counter(0) {
// Just in case none are declared:
namespaces_.push_back(new Namespace());
@@ -421,7 +432,7 @@ class Parser {
known_attributes_["original_order"] = true;
known_attributes_["nested_flatbuffer"] = true;
known_attributes_["csharp_partial"] = true;
known_attributes_["stream"] = true;
known_attributes_["streaming"] = true;
known_attributes_["idempotent"] = true;
}
@@ -478,7 +489,8 @@ private:
FieldDef **dest);
FLATBUFFERS_CHECKED_ERROR ParseField(StructDef &struct_def);
FLATBUFFERS_CHECKED_ERROR ParseAnyValue(Value &val, FieldDef *field,
size_t parent_fieldn);
size_t parent_fieldn,
const StructDef *parent_struct_def);
FLATBUFFERS_CHECKED_ERROR ParseTable(const StructDef &struct_def,
std::string *value, uoffset_t *ovalue);
void SerializeStruct(const StructDef &struct_def, const Value &val);
@@ -538,13 +550,9 @@ private:
IDLOptions opts;
private:
const char *source_, *cursor_;
int line_; // the current line being parsed
int token_;
std::string file_being_parsed_;
const char *source_;
std::string attribute_;
std::vector<std::string> doc_comment_;
std::string file_being_parsed_;
std::vector<std::pair<Value, FieldDef *>> field_stack_;
@@ -671,6 +679,12 @@ extern std::string BinaryMakeRule(const Parser &parser,
const std::string &path,
const std::string &file_name);
// Generate GRPC interfaces.
// See idl_gen_grpc.cpp.
bool GenerateGRPC(const Parser &parser,
const std::string &path,
const std::string &file_name);
} // namespace flatbuffers
#endif // FLATBUFFERS_IDL_H_

View File

@@ -335,6 +335,8 @@ template<typename T, typename U> pointer_inside_vector<T, U> piv(T *ptr,
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,
@@ -342,7 +344,7 @@ inline const reflection::Object &GetUnionType(
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() + "_type").c_str());
(unionfield.name()->str() + UnionTypeFieldSuffix()).c_str());
assert(type_field);
auto union_type = GetFieldI<uint8_t>(table, *type_field);
auto enumval = enumdef->values()->LookupByKey(union_type);

View File

@@ -35,9 +35,10 @@
#include <winbase.h>
#include <direct.h>
#else
#include <sys/stat.h>
#include <limits.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include "flatbuffers/flatbuffers.h"
@@ -124,6 +125,9 @@ FileExistsFunction SetFileExistsFunction(FileExistsFunction
// 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

View File

@@ -23,10 +23,18 @@ package com.google.flatbuffers;
*/
public class Constants {
// Java doesn't seem to have these.
/** The number of bytes in an `byte`. */
static final int SIZEOF_BYTE = 1;
/** The number of bytes in a `short`. */
static final int SIZEOF_SHORT = 2;
/** The number of bytes in an `int`. */
static final int SIZEOF_INT = 4;
/** The number of bytes in an `float`. */
static final int SIZEOF_FLOAT = 4;
/** The number of bytes in an `long`. */
static final int SIZEOF_LONG = 8;
/** The number of bytes in an `double`. */
static final int SIZEOF_DOUBLE = 8;
/** The number of bytes in a file identifier. */
static final int FILE_IDENTIFIER_LENGTH = 4;
}

View File

@@ -188,7 +188,7 @@ public class FlatBufferBuilder {
*
* @param x A `boolean` to put into the buffer.
*/
public void putBoolean(boolean x) { bb.put (space -= 1, (byte)(x ? 1 : 0)); }
public void putBoolean(boolean x) { bb.put (space -= Constants.SIZEOF_BYTE, (byte)(x ? 1 : 0)); }
/**
* Add a `byte` to the buffer, backwards from the current location. Doesn't align nor
@@ -196,7 +196,7 @@ public class FlatBufferBuilder {
*
* @param x A `byte` to put into the buffer.
*/
public void putByte (byte x) { bb.put (space -= 1, x); }
public void putByte (byte x) { bb.put (space -= Constants.SIZEOF_BYTE, x); }
/**
* Add a `short` to the buffer, backwards from the current location. Doesn't align nor
@@ -204,7 +204,7 @@ public class FlatBufferBuilder {
*
* @param x A `short` to put into the buffer.
*/
public void putShort (short x) { bb.putShort (space -= 2, x); }
public void putShort (short x) { bb.putShort (space -= Constants.SIZEOF_SHORT, x); }
/**
* Add an `int` to the buffer, backwards from the current location. Doesn't align nor
@@ -212,7 +212,7 @@ public class FlatBufferBuilder {
*
* @param x An `int` to put into the buffer.
*/
public void putInt (int x) { bb.putInt (space -= 4, x); }
public void putInt (int x) { bb.putInt (space -= Constants.SIZEOF_INT, x); }
/**
* Add a `long` to the buffer, backwards from the current location. Doesn't align nor
@@ -220,7 +220,7 @@ public class FlatBufferBuilder {
*
* @param x A `long` to put into the buffer.
*/
public void putLong (long x) { bb.putLong (space -= 8, x); }
public void putLong (long x) { bb.putLong (space -= Constants.SIZEOF_LONG, x); }
/**
* Add a `float` to the buffer, backwards from the current location. Doesn't align nor
@@ -228,7 +228,7 @@ public class FlatBufferBuilder {
*
* @param x A `float` to put into the buffer.
*/
public void putFloat (float x) { bb.putFloat (space -= 4, x); }
public void putFloat (float x) { bb.putFloat (space -= Constants.SIZEOF_FLOAT, x); }
/**
* Add a `double` to the buffer, backwards from the current location. Doesn't align nor
@@ -236,7 +236,7 @@ public class FlatBufferBuilder {
*
* @param x A `double` to put into the buffer.
*/
public void putDouble (double x) { bb.putDouble(space -= 8, x); }
public void putDouble (double x) { bb.putDouble(space -= Constants.SIZEOF_DOUBLE, x); }
/// @endcond
/**
@@ -244,49 +244,49 @@ public class FlatBufferBuilder {
*
* @param x A `boolean` to put into the buffer.
*/
public void addBoolean(boolean x) { prep(1, 0); putBoolean(x); }
public void addBoolean(boolean x) { prep(Constants.SIZEOF_BYTE, 0); putBoolean(x); }
/**
* Add a `byte` to the buffer, properly aligned, and grows the buffer (if necessary).
*
* @param x A `byte` to put into the buffer.
*/
public void addByte (byte x) { prep(1, 0); putByte (x); }
public void addByte (byte x) { prep(Constants.SIZEOF_BYTE, 0); putByte (x); }
/**
* Add a `short` to the buffer, properly aligned, and grows the buffer (if necessary).
*
* @param x A `short` to put into the buffer.
*/
public void addShort (short x) { prep(2, 0); putShort (x); }
public void addShort (short x) { prep(Constants.SIZEOF_SHORT, 0); putShort (x); }
/**
* Add an `int` to the buffer, properly aligned, and grows the buffer (if necessary).
*
* @param x An `int` to put into the buffer.
*/
public void addInt (int x) { prep(4, 0); putInt (x); }
public void addInt (int x) { prep(Constants.SIZEOF_INT, 0); putInt (x); }
/**
* Add a `long` to the buffer, properly aligned, and grows the buffer (if necessary).
*
* @param x A `long` to put into the buffer.
*/
public void addLong (long x) { prep(8, 0); putLong (x); }
public void addLong (long x) { prep(Constants.SIZEOF_LONG, 0); putLong (x); }
/**
* Add a `float` to the buffer, properly aligned, and grows the buffer (if necessary).
*
* @param x A `float` to put into the buffer.
*/
public void addFloat (float x) { prep(4, 0); putFloat (x); }
public void addFloat (float x) { prep(Constants.SIZEOF_FLOAT, 0); putFloat (x); }
/**
* Add a `double` to the buffer, properly aligned, and grows the buffer (if necessary).
*
* @param x A `double` to put into the buffer.
*/
public void addDouble (double x) { prep(8, 0); putDouble (x); }
public void addDouble (double x) { prep(Constants.SIZEOF_DOUBLE, 0); putDouble (x); }
/**
* Adds on offset, relative to where it will be written.

View File

@@ -18,5 +18,5 @@ APP_PROJECT_PATH := $(call my-dir)/..
APP_STL := gnustl_static
APP_ABI := armeabi-v7a
NDK_TOOLCHAIN_VERSION := 4.8
APP_CPPFLAGS += -std=c++11

View File

@@ -74,10 +74,14 @@ const Generator generators[] = {
flatbuffers::IDLOptions::kMAX,
"Generate Python files for tables/structs",
flatbuffers::GeneralMakeRule },
{ flatbuffers::GeneratePhp, nullptr, "--php", "PHP",
{ flatbuffers::GeneratePhp, nullptr, "--php", "PHP",
flatbuffers::IDLOptions::kMAX,
"Generate PHP files for tables/structs",
flatbuffers::GeneralMakeRule },
{ flatbuffers::GenerateGRPC, nullptr, "--grpc", "GRPC",
flatbuffers::IDLOptions::kMAX,
"Generate GRPC interfaces",
flatbuffers::CPPMakeRule },
};
const char *program_name = nullptr;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -625,7 +625,8 @@ class GoGenerator : public BaseGenerator {
public:
GoGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
: BaseGenerator(parser, path, file_name){};
: BaseGenerator(parser, path, file_name, "" /* not used*/,
"" /* not used */){};
bool generate() {
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
++it) {
@@ -664,9 +665,10 @@ class GoGenerator : public BaseGenerator {
if (!classcode.length()) return true;
std::string code = "";
BeginFile(LastNamespacePart(), needs_imports, &code);
BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
code += classcode;
std::string filename = namespace_dir_ + def.name + ".go";
std::string filename =
NamespaceDir(*def.defined_namespace) + def.name + ".go";
return SaveFile(filename.c_str(), code, false);
}
};

216
src/idl_gen_grpc.cpp Normal file
View File

@@ -0,0 +1,216 @@
/*
* 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/idl.h"
#include "flatbuffers/util.h"
#include "src/compiler/cpp_generator.h"
namespace flatbuffers {
class FlatBufMethod : public grpc_cpp_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;
}
}
std::string name() const { return method_->name; }
std::string GRPCType(const StructDef &sd) const {
return "flatbuffers::BufferRef<" + sd.name + ">";
}
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 ClientOnlyStreaming() const { return streaming_ == kClient; }
bool ServerOnlyStreaming() const { return streaming_ == kServer; }
bool BidiStreaming() const { return streaming_ == kBiDi; }
private:
const RPCCall *method_;
Streaming streaming_;
};
class FlatBufService : public grpc_cpp_generator::Service {
public:
FlatBufService(const ServiceDef *service) : service_(service) {}
std::string name() const { return service_->name; }
int method_count() const {
return static_cast<int>(service_->calls.vec.size());
};
std::unique_ptr<const grpc_cpp_generator::Method> method(int i) const {
return std::unique_ptr<const grpc_cpp_generator::Method>(
new FlatBufMethod(service_->calls.vec[i]));
};
private:
const ServiceDef *service_;
};
class FlatBufPrinter : public grpc_cpp_generator::Printer {
public:
FlatBufPrinter(std::string *str)
: str_(str), escape_char_('$'), indent_(0) {}
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) {
// Add this string, but for each part separated by \n, add indentation.
for (;;) {
// Current indentation.
str_->insert(str_->end(), indent_ * 2, ' ');
// 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 Indent() { indent_++; }
void Outdent() { indent_--; assert(indent_ >= 0); }
private:
std::string *str_;
char escape_char_;
int indent_;
};
class FlatBufFile : public grpc_cpp_generator::File {
public:
FlatBufFile(const Parser &parser, const std::string &file_name)
: parser_(parser), file_name_(file_name) {}
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_.namespaces_.back()->GetFullyQualifiedName("");
}
std::vector<std::string> package_parts() const {
return parser_.namespaces_.back()->components;
}
std::string additional_headers() const {
return "#include \"flatbuffers/grpc.h\"\n";
}
int service_count() const {
return static_cast<int>(parser_.services_.vec.size());
};
std::unique_ptr<const grpc_cpp_generator::Service> service(int i) const {
return std::unique_ptr<const grpc_cpp_generator::Service> (
new FlatBufService(parser_.services_.vec[i]));
}
std::unique_ptr<grpc_cpp_generator::Printer> CreatePrinter(std::string *str) const {
return std::unique_ptr<grpc_cpp_generator::Printer>(
new FlatBufPrinter(str));
}
private:
const Parser &parser_;
const std::string &file_name_;
};
bool GenerateGRPC(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);
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((file_name + ".grpc.fb.h").c_str(),
header_code, false) &&
flatbuffers::SaveFile((file_name + ".grpc.fb.cc").c_str(),
source_code, false);
}
} // namespace flatbuffers

View File

@@ -22,14 +22,71 @@
#include "flatbuffers/code_generators.h"
namespace flatbuffers {
namespace js {
static void GenNamespaces(const Parser &parser, std::string *code_ptr,
std::string *exports_ptr) {
static std::string GeneratedFileName(const std::string &path,
const std::string &file_name) {
return path + file_name + "_generated.js";
}
namespace js {
// Iterate through all definitions we haven't generate code for (enums, structs,
// and tables) and output them to a single file.
class JsGenerator : public BaseGenerator {
public:
JsGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
: BaseGenerator(parser, path, file_name, "", "."){};
// Iterate through all definitions we haven't generate code for (enums,
// structs, and tables) and output them to a single file.
bool generate() {
if (IsEverythingGenerated()) return true;
std::string enum_code, struct_code, exports_code, code;
generateEnums(&enum_code, &exports_code);
generateStructs(&struct_code, &exports_code);
code = code + "// " + FlatBuffersGeneratedWarning();
// Generate code for all the namespace declarations.
GenNamespaces(&code, &exports_code);
// Output the main declaration code from above.
code += enum_code;
code += struct_code;
if (!exports_code.empty() && !parser_.opts.skip_js_exports) {
code += "// Exports for Node.js and RequireJS\n";
code += exports_code;
}
return SaveFile(GeneratedFileName(path_, file_name_).c_str(), code, false);
}
private:
// Generate code for all enums.
void generateEnums(std::string *enum_code_ptr,
std::string *exports_code_ptr) {
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
++it) {
auto &enum_def = **it;
GenEnum(enum_def, enum_code_ptr, exports_code_ptr);
}
}
// Generate code for all structs.
void generateStructs(std::string *decl_code_ptr,
std::string *exports_code_ptr) {
for (auto it = parser_.structs_.vec.begin();
it != parser_.structs_.vec.end(); ++it) {
auto &struct_def = **it;
GenStruct(struct_def, decl_code_ptr, exports_code_ptr);
}
}
void GenNamespaces(std::string *code_ptr, std::string *exports_ptr) {
std::set<std::string> namespaces;
for (auto it = parser.namespaces_.begin();
it != parser.namespaces_.end(); ++it) {
for (auto it = parser_.namespaces_.begin();
it != parser_.namespaces_.end(); ++it) {
std::string namespace_so_far;
// Gather all parent namespaces for this namespace
@@ -62,22 +119,6 @@ static void GenNamespaces(const Parser &parser, std::string *code_ptr,
}
}
// Ensure that a type is prefixed with its namespace whenever it is used
// outside of its namespace.
static std::string WrapInNameSpace(const Namespace *ns,
const std::string &name) {
std::string qualified_name;
for (auto it = ns->components.begin();
it != ns->components.end(); ++it) {
qualified_name += *it + ".";
}
return qualified_name + name;
}
static std::string WrapInNameSpace(const Definition &def) {
return WrapInNameSpace(def.defined_namespace, def.name);
}
// Generate a documentation comment, if available.
static void GenDocComment(const std::vector<std::string> &dc,
std::string *code_ptr,
@@ -123,7 +164,7 @@ static void GenDocComment(std::string *code_ptr,
}
// Generate an enum declaration and an enum string lookup table.
static void GenEnum(EnumDef &enum_def, std::string *code_ptr,
void GenEnum(EnumDef &enum_def, std::string *code_ptr,
std::string *exports_ptr) {
if (enum_def.generated) return;
std::string &code = *code_ptr;
@@ -170,7 +211,7 @@ static std::string GenType(const Type &type) {
}
}
static std::string GenGetter(const Type &type, const std::string &arguments) {
std::string GenGetter(const Type &type, const std::string &arguments) {
switch (type.base_type) {
case BASE_TYPE_STRING: return "this.bb.__string" + arguments;
case BASE_TYPE_STRUCT: return "this.bb.__struct" + arguments;
@@ -190,7 +231,7 @@ static std::string GenGetter(const Type &type, const std::string &arguments) {
}
}
static std::string GenDefaultValue(const Value &value, const std::string &context) {
std::string GenDefaultValue(const Value &value, const std::string &context) {
if (value.type.enum_def) {
if (auto val = value.type.enum_def->ReverseLookup(
atoi(value.constant.c_str()), false)) {
@@ -217,7 +258,7 @@ static std::string GenDefaultValue(const Value &value, const std::string &contex
}
}
static std::string GenTypeName(const Type &type, bool input) {
std::string GenTypeName(const Type &type, bool input) {
if (!input) {
if (type.base_type == BASE_TYPE_STRING) {
return "string|Uint8Array";
@@ -269,7 +310,7 @@ static std::string MaybeScale(T value) {
return value != 1 ? " * " + NumToString(value) : "";
}
static void GenStructArgs(const StructDef &struct_def,
void GenStructArgs(const StructDef &struct_def,
std::string *annotations,
std::string *arguments,
const std::string &nameprefix) {
@@ -320,8 +361,7 @@ static void GenStructBody(const StructDef &struct_def,
}
// Generate an accessor struct with constructor for a flatbuffers struct.
static void GenStruct(const Parser &parser, StructDef &struct_def,
std::string *code_ptr, std::string *exports_ptr) {
void GenStruct(StructDef &struct_def, std::string *code_ptr, std::string *exports_ptr) {
if (struct_def.generated) return;
std::string &code = *code_ptr;
std::string &exports = *exports_ptr;
@@ -375,13 +415,13 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
code += "};\n\n";
// Generate the identifier check method
if (parser.root_struct_def_ == &struct_def &&
!parser.file_identifier_.empty()) {
if (parser_.root_struct_def_ == &struct_def &&
!parser_.file_identifier_.empty()) {
GenDocComment(code_ptr,
"@param {flatbuffers.ByteBuffer} bb\n"
"@returns {boolean}");
code += object_name + ".bufferHasIdentifier = function(bb) {\n";
code += " return bb.__has_identifier('" + parser.file_identifier_;
code += " return bb.__has_identifier('" + parser_.file_identifier_;
code += "');\n};\n\n";
}
}
@@ -644,83 +684,21 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
code += "};\n\n";
// Generate the method to complete buffer construction
if (parser.root_struct_def_ == &struct_def) {
if (parser_.root_struct_def_ == &struct_def) {
GenDocComment(code_ptr,
"@param {flatbuffers.Builder} builder\n"
"@param {flatbuffers.Offset} offset");
code += object_name + ".finish" + struct_def.name + "Buffer";
code += " = function(builder, offset) {\n";
code += " builder.finish(offset";
if (!parser.file_identifier_.empty()) {
code += ", '" + parser.file_identifier_ + "'";
if (!parser_.file_identifier_.empty()) {
code += ", '" + parser_.file_identifier_ + "'";
}
code += ");\n";
code += "};\n\n";
}
}
}
} // namespace js
static std::string GeneratedFileName(const std::string &path,
const std::string &file_name) {
return path + file_name + "_generated.js";
}
namespace js {
// Iterate through all definitions we haven't generate code for (enums, structs,
// and tables) and output them to a single file.
class JsGenerator : public BaseGenerator {
public:
JsGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
: BaseGenerator(parser, path, file_name){};
// Iterate through all definitions we haven't generate code for (enums,
// structs, and tables) and output them to a single file.
bool generate() {
if (IsEverythingGenerated()) return true;
std::string enum_code, struct_code, exports_code, code;
generateEnums(&enum_code, &exports_code);
generateStructs(&struct_code, &exports_code);
code = code + "// " + FlatBuffersGeneratedWarning();
// Generate code for all the namespace declarations.
GenNamespaces(parser_, &code, &exports_code);
// Output the main declaration code from above.
code += enum_code;
code += struct_code;
if (!exports_code.empty() && !parser_.opts.skip_js_exports) {
code += "// Exports for Node.js and RequireJS\n";
code += exports_code;
}
return SaveFile(GeneratedFileName(path_, file_name_).c_str(), code, false);
}
private:
// Generate code for all enums.
void generateEnums(std::string *enum_code_ptr,
std::string *exports_code_ptr) {
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
++it) {
auto &enum_def = **it;
GenEnum(enum_def, enum_code_ptr, exports_code_ptr);
}
}
// Generate code for all structs.
void generateStructs(std::string *decl_code_ptr,
std::string *exports_code_ptr) {
for (auto it = parser_.structs_.vec.begin();
it != parser_.structs_.vec.end(); ++it) {
auto &struct_def = **it;
GenStruct(parser_, struct_def, decl_code_ptr, exports_code_ptr);
}
}
};
} // namespace js

View File

@@ -25,35 +25,74 @@
namespace flatbuffers {
namespace php {
static std::string GenGetter(const Type &type);
static std::string GenDefaultValue(const Value &value);
static std::string GenMethod(const FieldDef &field);
static void GenStructBuilder(const StructDef &struct_def,
std::string *code_ptr);
static std::string GenTypeBasic(const Type &type);
static std::string GenTypeGet(const Type &type);
// Ensure that a type is prefixed with its namespace whenever it is used
// outside of its namespace.
static std::string WrapInNameSpace(const Namespace *ns,
const std::string &name) {
std::string qualified_name = "\\";
for (auto it = ns->components.begin();
it != ns->components.end(); ++it) {
qualified_name += *it + "\\";
}
return qualified_name + name;
}
static std::string WrapInNameSpace(const Definition &def) {
return WrapInNameSpace(def.defined_namespace, def.name);
}
// 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, "\\", "\\"){};
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 += "<?php\n";
code = code + "// " + FlatBuffersGeneratedWarning();
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) +
kPathSeparator + 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;
@@ -189,8 +228,7 @@ namespace php {
}
// Get the value of a table's scalar.
static void GetScalarFieldOfTable(const FieldDef &field,
std::string *code_ptr) {
void GetScalarFieldOfTable(const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
std::string getter = GenGetter(field.value.type);
@@ -213,8 +251,7 @@ namespace php {
// Get a struct by initializing an existing struct.
// Specific to Struct.
static void GetStructFieldOfStruct(const FieldDef &field,
std::string *code_ptr) {
void GetStructFieldOfStruct(const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
code += Indent + "/**\n";
@@ -233,8 +270,7 @@ namespace php {
// Get a struct by initializing an existing struct.
// Specific to Table.
static void GetStructFieldOfTable(const FieldDef &field,
std::string *code_ptr) {
void GetStructFieldOfTable(const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
code += Indent + "public function get";
@@ -260,8 +296,7 @@ namespace php {
}
// Get the value of a string.
static void GetStringField(const FieldDef &field,
std::string *code_ptr) {
void GetStringField(const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
code += Indent + "public function get";
code += MakeCamel(field.name);
@@ -278,8 +313,7 @@ namespace php {
}
// Get the value of a union from an object.
static void GetUnionField(const FieldDef &field,
std::string *code_ptr) {
void GetUnionField(const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
code += Indent + "/**\n";
@@ -298,9 +332,8 @@ namespace php {
}
// Get the value of a vector's struct member.
static void GetMemberOfVectorOfStruct(const StructDef &struct_def,
const FieldDef &field,
std::string *code_ptr) {
void GetMemberOfVectorOfStruct(const StructDef &struct_def,
const FieldDef &field, std::string *code_ptr) {
std::string &code = *code_ptr;
auto vectortype = field.value.type.VectorType();
@@ -362,7 +395,7 @@ namespace php {
// Get the value of a vector's non-struct member. Uses a named return
// argument to conveniently set the zero value for the result.
static void GetMemberOfVectorOfNonStruct(const FieldDef &field,
void GetMemberOfVectorOfNonStruct(const FieldDef &field,
std::string *code_ptr) {
std::string &code = *code_ptr;
auto vectortype = field.value.type.VectorType();
@@ -603,9 +636,7 @@ namespace php {
}
// Get the offset of the end of a table.
static void GetEndOffsetOnTable(const Parser &parser,
const StructDef &struct_def,
std::string *code_ptr) {
void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
std::string &code = *code_ptr;
@@ -632,7 +663,7 @@ namespace php {
code += Indent + Indent + "return $o;\n";
code += Indent + "}\n";
if (parser.root_struct_def_ == &struct_def) {
if (parser_.root_struct_def_ == &struct_def) {
code += "\n";
code += Indent + "public static function finish";
code += struct_def.name;
@@ -640,16 +671,15 @@ namespace php {
code += Indent + "{\n";
code += Indent + Indent + "$builder->finish($offset";
if (parser.file_identifier_.length())
code += ", \"" + parser.file_identifier_ + "\"";
if (parser_.file_identifier_.length())
code += ", \"" + parser_.file_identifier_ + "\"";
code += ");\n";
code += Indent + "}\n";
}
}
// Generate a struct field, conditioned on its child type(s).
static void GenStructAccessor(const StructDef &struct_def,
const FieldDef &field,
void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
std::string *code_ptr) {
GenComment(field.doc_comment, code_ptr, nullptr);
@@ -696,9 +726,7 @@ namespace php {
}
// Generate table constructors, conditioned on its members' types.
static void GenTableBuilders(const Parser &parser,
const StructDef &struct_def,
std::string *code_ptr) {
void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
GetStartOfTable(struct_def, code_ptr);
for (auto it = struct_def.fields.vec.begin();
@@ -725,11 +753,11 @@ namespace php {
}
}
GetEndOffsetOnTable(parser, struct_def, code_ptr);
GetEndOffsetOnTable(struct_def, code_ptr);
}
// Generate struct or table methods.
static void GenStruct(const Parser &parser, const StructDef &struct_def,
void GenStruct(const StructDef &struct_def,
std::string *code_ptr) {
if (struct_def.generated) return;
@@ -744,13 +772,13 @@ namespace php {
std::string &code = *code_ptr;
if (!struct_def.fixed) {
if (parser.file_identifier_.length()) {
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 += parser_.file_identifier_ + "\";\n";
code += Indent + "}\n\n";
// Check if a buffer has the identifier.
@@ -763,12 +791,12 @@ namespace php {
code += Indent + "}\n\n";
}
if (parser.file_extension_.length()) {
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 += Indent + Indent + "return \"" + parser_.file_extension_;
code += "\";\n";
code += Indent + "}\n\n";
}
@@ -791,7 +819,7 @@ namespace php {
GenStructBuilder(struct_def, code_ptr);
} else {
// Create a set of functions that allow table construction.
GenTableBuilders(parser, struct_def, code_ptr);
GenTableBuilders(struct_def, code_ptr);
}
EndClass(code_ptr);
}
@@ -859,7 +887,7 @@ namespace php {
return ctypename[type.base_type];
}
static std::string GenDefaultValue(const Value &value) {
std::string GenDefaultValue(const Value &value) {
if (value.type.enum_def) {
if (auto val = value.type.enum_def->ReverseLookup(
atoi(value.constant.c_str()), false)) {
@@ -927,71 +955,7 @@ namespace php {
code += Indent + Indent + "return $builder->offset();\n";
code += Indent + "}\n";
}
class PhpGenerator : public BaseGenerator {
public:
PhpGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
: BaseGenerator(parser, path, file_name){};
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(parser_, 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 += "<?php\n";
code = code + "// " + FlatBuffersGeneratedWarning();
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("\\"), needs_imports, &code);
code += classcode;
std::string filename =
namespace_dir_ + kPathSeparator + def.name + ".php";
return SaveFile(filename.c_str(), code, false);
}
};
} // namespace php

View File

@@ -596,7 +596,8 @@ class PythonGenerator : public BaseGenerator {
public:
PythonGenerator(const Parser &parser, const std::string &path,
const std::string &file_name)
: BaseGenerator(parser, path, file_name){};
: BaseGenerator(parser, path, file_name, "" /* not used */,
"" /* not used */){};
bool generate() {
if (!generateEnums()) return false;
if (!generateStructs()) return false;
@@ -652,9 +653,10 @@ class PythonGenerator : public BaseGenerator {
}
std::string code = "";
BeginFile(LastNamespacePart(), needs_imports, &code);
BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
code += classcode;
std::string filename = namespace_dir_ + kPathSeparator + def.name + ".py";
std::string filename = NamespaceDir(*def.defined_namespace) +
kPathSeparator + def.name + ".py";
return SaveFile(filename.c_str(), code, false);
}
};

View File

@@ -17,6 +17,14 @@
#include <algorithm>
#include <list>
#ifdef _WIN32
#if !defined(_USE_MATH_DEFINES)
#define _USE_MATH_DEFINES // For M_PI.
#endif // !defined(_USE_MATH_DEFINES)
#endif // _WIN32
#include <math.h>
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
@@ -575,9 +583,9 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
FieldDef *typefield = nullptr;
if (type.base_type == BASE_TYPE_UNION) {
// For union fields, add a second auto-generated field to hold the type,
// with _type appended as the name.
ECHECK(AddField(struct_def, name + "_type", type.enum_def->underlying_type,
&typefield));
// with a special suffix.
ECHECK(AddField(struct_def, name + UnionTypeFieldSuffix(),
type.enum_def->underlying_type, &typefield));
}
FieldDef *field;
@@ -678,17 +686,45 @@ CheckedError Parser::ParseField(StructDef &struct_def) {
}
CheckedError Parser::ParseAnyValue(Value &val, FieldDef *field,
size_t parent_fieldn) {
size_t parent_fieldn,
const StructDef *parent_struct_def) {
switch (val.type.base_type) {
case BASE_TYPE_UNION: {
assert(field);
std::string constant;
if (!parent_fieldn ||
field_stack_.back().second->value.type.base_type != BASE_TYPE_UTYPE)
return Error("missing type field before this union value: " +
field->name);
field_stack_.back().second->value.type.base_type != BASE_TYPE_UTYPE) {
// 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.
auto type_name = field->name + UnionTypeFieldSuffix();
assert(parent_struct_def);
auto type_field = parent_struct_def->fields.Lookup(type_name);
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.
EXPECT(',');
auto next_name = attribute_;
if (Is(kTokenStringConstant)) {
NEXT();
} else {
EXPECT(kTokenIdentifier);
}
if (next_name != type_name)
return Error("missing type field after this union value: " +
type_name);
EXPECT(':');
Value type_val = type_field->value;
ECHECK(ParseAnyValue(type_val, type_field, 0, nullptr));
constant = type_val.constant;
// Got the information we needed, now rewind:
*static_cast<ParserState *>(this) = backup;
} else {
constant = field_stack_.back().first.constant;
}
uint8_t enum_idx;
ECHECK(atot(field_stack_.back().first.constant.c_str(), *this,
&enum_idx));
ECHECK(atot(constant.c_str(), *this, &enum_idx));
auto enum_val = val.type.enum_def->ReverseLookup(enum_idx);
if (!enum_val) return Error("illegal type id for: " + field->name);
ECHECK(ParseTable(*enum_val->struct_def, &val.constant, nullptr));
@@ -763,7 +799,7 @@ CheckedError Parser::ParseTable(const StructDef &struct_def, std::string *value,
NEXT(); // Ignore this field.
} else {
Value val = field->value;
ECHECK(ParseAnyValue(val, field, fieldn));
ECHECK(ParseAnyValue(val, field, fieldn, &struct_def));
size_t i = field_stack_.size();
// Hardcoded insertion-sort with error-check.
// If fields are specified in order, then this loop exits immediately.
@@ -862,7 +898,7 @@ CheckedError Parser::ParseVector(const Type &type, uoffset_t *ovalue) {
if ((!opts.strict_json || !count) && Is(']')) { NEXT(); break; }
Value val;
val.type = type;
ECHECK(ParseAnyValue(val, nullptr, 0));
ECHECK(ParseAnyValue(val, nullptr, 0, nullptr));
field_stack_.push_back(std::make_pair(val, nullptr));
count++;
if (Is(']')) { NEXT(); break; }
@@ -1004,8 +1040,30 @@ CheckedError Parser::ParseHash(Value &e, FieldDef* field) {
}
CheckedError Parser::ParseSingleValue(Value &e) {
// First check if this could be a string/identifier enum value:
if (e.type.base_type != BASE_TYPE_STRING &&
// First see if this could be a conversion function:
if (token_ == kTokenIdentifier && *cursor_ == '(') {
auto functionname = attribute_;
NEXT();
EXPECT('(');
ECHECK(ParseSingleValue(e));
EXPECT(')');
#define FLATBUFFERS_FN_DOUBLE(name, op) \
if (functionname == name) { \
auto x = strtod(e.constant.c_str(), nullptr); \
e.constant = NumToString(op); \
}
FLATBUFFERS_FN_DOUBLE("deg", x / M_PI * 180);
FLATBUFFERS_FN_DOUBLE("rad", x * M_PI / 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
// Then check if this could be a string/identifier enum value:
} else if (e.type.base_type != BASE_TYPE_STRING &&
e.type.base_type != BASE_TYPE_NONE &&
(token_ == kTokenIdentifier || token_ == kTokenStringConstant)) {
if (IsIdentifierStart(attribute_[0])) { // Enum value.
@@ -1150,7 +1208,13 @@ CheckedError Parser::ParseEnum(bool is_union, EnumDef **dest) {
auto full_name = value_name;
std::vector<std::string> value_comment = doc_comment_;
EXPECT(kTokenIdentifier);
if (is_union) ECHECK(ParseNamespacing(&full_name, &value_name));
if (is_union) {
ECHECK(ParseNamespacing(&full_name, &value_name));
// Since we can't namespace the actual enum identifiers, turn
// namespace parts into part of the identifier.
value_name = full_name;
std::replace(value_name.begin(), value_name.end(), '.', '_');
}
auto prevsize = enum_def.vals.vec.size();
auto value = enum_def.vals.vec.size()
? enum_def.vals.vec.back()->value + 1
@@ -1288,7 +1352,8 @@ CheckedError Parser::ParseDecl() {
}
}
ECHECK(CheckClash(fields, struct_def, "_type", BASE_TYPE_UNION));
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));
@@ -1358,6 +1423,10 @@ void Parser::MarkGenerated() {
it != structs_.vec.end(); ++it) {
(*it)->generated = true;
}
for (auto it = services_.vec.begin();
it != services_.vec.end(); ++it) {
(*it)->generated = true;
}
}
CheckedError Parser::ParseNamespace() {

View File

@@ -24,12 +24,14 @@ bool FileExistsRaw(const char *name) {
}
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);
(*buf).resize(static_cast<size_t>(ifs.tellg()));
auto size = ifs.tellg();
(*buf).resize(static_cast<size_t>(size));
ifs.seekg(0, std::ios::beg);
ifs.read(&(*buf)[0], (*buf).size());
} else {
@@ -54,6 +56,19 @@ bool FileExists(const char *name) {
return g_file_exists_function(name);
}
bool DirExists(const char *name) {
#ifdef _WIN32
#define flatbuffers_stat _stat
#define FLATBUFFERS_S_IFDIR _S_IFDIR
#else
#define flatbuffers_stat stat
#define FLATBUFFERS_S_IFDIR S_IFDIR
#endif
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;

View File

@@ -8,6 +8,7 @@ public enum Any : byte
NONE = 0,
Monster = 1,
TestSimpleTableWithEnum = 2,
MyGame_Example2_Monster = 3,
};

View File

@@ -6,4 +6,5 @@ const (
AnyNONE = 0
AnyMonster = 1
AnyTestSimpleTableWithEnum = 2
AnyMyGame_Example2_Monster = 3
)

View File

@@ -7,8 +7,9 @@ public final class Any {
public static final byte NONE = 0;
public static final byte Monster = 1;
public static final byte TestSimpleTableWithEnum = 2;
public static final byte MyGame_Example2_Monster = 3;
private static final String[] names = { "NONE", "Monster", "TestSimpleTableWithEnum", };
private static final String[] names = { "NONE", "Monster", "TestSimpleTableWithEnum", "MyGame_Example2_Monster", };
public static String name(int e) { return names[e]; }
};

View File

@@ -8,11 +8,13 @@ class Any
const NONE = 0;
const Monster = 1;
const TestSimpleTableWithEnum = 2;
const MyGame_Example2_Monster = 3;
private static $names = array(
"NONE",
"Monster",
"TestSimpleTableWithEnum",
"MyGame_Example2_Monster",
);
public static function Name($e)

View File

@@ -6,4 +6,5 @@ class Any(object):
NONE = 0
Monster = 1
TestSimpleTableWithEnum = 2
MyGame_Example2_Monster = 3

View File

@@ -78,8 +78,10 @@ public sealed class Monster : Table {
public bool MutateTestf2(float testf2) { int o = __offset(56); if (o != 0) { bb.PutFloat(o + bb_pos, testf2); return true; } else { return false; } }
public float Testf3 { get { int o = __offset(58); return o != 0 ? bb.GetFloat(o + bb_pos) : (float)0.0f; } }
public bool MutateTestf3(float testf3) { int o = __offset(58); if (o != 0) { bb.PutFloat(o + bb_pos, testf3); return true; } else { return false; } }
public string GetTestarrayofstring2(int j) { int o = __offset(60); return o != 0 ? __string(__vector(o) + j * 4) : null; }
public int Testarrayofstring2Length { get { int o = __offset(60); return o != 0 ? __vector_len(o) : 0; } }
public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(28); }
public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(29); }
public static void AddPos(FlatBufferBuilder builder, Offset<Vec3> posOffset) { builder.AddStruct(0, posOffset.Value, 0); }
public static void AddMana(FlatBufferBuilder builder, short mana) { builder.AddShort(1, mana, 150); }
public static void AddHp(FlatBufferBuilder builder, short hp) { builder.AddShort(2, hp, 100); }
@@ -118,6 +120,9 @@ public sealed class Monster : Table {
public static void AddTestf(FlatBufferBuilder builder, float testf) { builder.AddFloat(25, testf, 3.14159f); }
public static void AddTestf2(FlatBufferBuilder builder, float testf2) { builder.AddFloat(26, testf2, 3.0f); }
public static void AddTestf3(FlatBufferBuilder builder, float testf3) { builder.AddFloat(27, testf3, 0.0f); }
public static void AddTestarrayofstring2(FlatBufferBuilder builder, VectorOffset testarrayofstring2Offset) { builder.AddOffset(28, testarrayofstring2Offset.Value, 0); }
public static VectorOffset CreateTestarrayofstring2Vector(FlatBufferBuilder builder, StringOffset[] data) { builder.StartVector(4, data.Length, 4); for (int i = data.Length - 1; i >= 0; i--) builder.AddOffset(data[i].Value); return builder.EndVector(); }
public static void StartTestarrayofstring2Vector(FlatBufferBuilder builder, int numElems) { builder.StartVector(4, numElems, 4); }
public static Offset<Monster> EndMonster(FlatBufferBuilder builder) {
int o = builder.EndObject();
builder.Required(o, 10); // name

View File

@@ -337,7 +337,24 @@ func (rcv *Monster) Testf3() float32 {
return 0.0
}
func MonsterStart(builder *flatbuffers.Builder) { builder.StartObject(28) }
func (rcv *Monster) Testarrayofstring2(j int) []byte {
o := flatbuffers.UOffsetT(rcv._tab.Offset(60))
if o != 0 {
a := rcv._tab.Vector(o)
return rcv._tab.ByteVector(a + flatbuffers.UOffsetT(j * 4))
}
return nil
}
func (rcv *Monster) Testarrayofstring2Length() int {
o := flatbuffers.UOffsetT(rcv._tab.Offset(60))
if o != 0 {
return rcv._tab.VectorLen(o)
}
return 0
}
func MonsterStart(builder *flatbuffers.Builder) { builder.StartObject(29) }
func MonsterAddPos(builder *flatbuffers.Builder, pos flatbuffers.UOffsetT) { builder.PrependStructSlot(0, flatbuffers.UOffsetT(pos), 0) }
func MonsterAddMana(builder *flatbuffers.Builder, mana int16) { builder.PrependInt16Slot(1, mana, 150) }
func MonsterAddHp(builder *flatbuffers.Builder, hp int16) { builder.PrependInt16Slot(2, hp, 100) }
@@ -377,4 +394,7 @@ func MonsterStartTestarrayofboolsVector(builder *flatbuffers.Builder, numElems i
func MonsterAddTestf(builder *flatbuffers.Builder, testf float32) { builder.PrependFloat32Slot(25, testf, 3.14159) }
func MonsterAddTestf2(builder *flatbuffers.Builder, testf2 float32) { builder.PrependFloat32Slot(26, testf2, 3.0) }
func MonsterAddTestf3(builder *flatbuffers.Builder, testf3 float32) { builder.PrependFloat32Slot(27, testf3, 0.0) }
func MonsterAddTestarrayofstring2(builder *flatbuffers.Builder, testarrayofstring2 flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(28, flatbuffers.UOffsetT(testarrayofstring2), 0) }
func MonsterStartTestarrayofstring2Vector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { return builder.StartVector(4, numElems, 4)
}
func MonsterEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() }

View File

@@ -84,8 +84,10 @@ public final class Monster extends Table {
public boolean mutateTestf2(float testf2) { int o = __offset(56); if (o != 0) { bb.putFloat(o + bb_pos, testf2); return true; } else { return false; } }
public float testf3() { int o = __offset(58); return o != 0 ? bb.getFloat(o + bb_pos) : 0.0f; }
public boolean mutateTestf3(float testf3) { int o = __offset(58); if (o != 0) { bb.putFloat(o + bb_pos, testf3); return true; } else { return false; } }
public String testarrayofstring2(int j) { int o = __offset(60); return o != 0 ? __string(__vector(o) + j * 4) : null; }
public int testarrayofstring2Length() { int o = __offset(60); return o != 0 ? __vector_len(o) : 0; }
public static void startMonster(FlatBufferBuilder builder) { builder.startObject(28); }
public static void startMonster(FlatBufferBuilder builder) { builder.startObject(29); }
public static void addPos(FlatBufferBuilder builder, int posOffset) { builder.addStruct(0, posOffset, 0); }
public static void addMana(FlatBufferBuilder builder, short mana) { builder.addShort(1, mana, 150); }
public static void addHp(FlatBufferBuilder builder, short hp) { builder.addShort(2, hp, 100); }
@@ -124,6 +126,9 @@ public final class Monster extends Table {
public static void addTestf(FlatBufferBuilder builder, float testf) { builder.addFloat(25, testf, 3.14159f); }
public static void addTestf2(FlatBufferBuilder builder, float testf2) { builder.addFloat(26, testf2, 3.0f); }
public static void addTestf3(FlatBufferBuilder builder, float testf3) { builder.addFloat(27, testf3, 0.0f); }
public static void addTestarrayofstring2(FlatBufferBuilder builder, int testarrayofstring2Offset) { builder.addOffset(28, testarrayofstring2Offset, 0); }
public static int createTestarrayofstring2Vector(FlatBufferBuilder builder, int[] data) { builder.startVector(4, data.length, 4); for (int i = data.length - 1; i >= 0; i--) builder.addOffset(data[i]); return builder.endVector(); }
public static void startTestarrayofstring2Vector(FlatBufferBuilder builder, int numElems) { builder.startVector(4, numElems, 4); }
public static int endMonster(FlatBufferBuilder builder) {
int o = builder.endObject();
builder.required(o, 10); // name

View File

@@ -360,22 +360,41 @@ class Monster extends Table
return $o != 0 ? $this->bb->getFloat($o + $this->bb_pos) : 0.0;
}
/**
* @param int offset
* @return string
*/
public function getTestarrayofstring2($j)
{
$o = $this->__offset(60);
return $o != 0 ? $this->__string($this->__vector($o) + $j * 4) : 0;
}
/**
* @return int
*/
public function getTestarrayofstring2Length()
{
$o = $this->__offset(60);
return $o != 0 ? $this->__vector_len($o) : 0;
}
/**
* @param FlatBufferBuilder $builder
* @return void
*/
public static function startMonster(FlatBufferBuilder $builder)
{
$builder->StartObject(28);
$builder->StartObject(29);
}
/**
* @param FlatBufferBuilder $builder
* @return Monster
*/
public static function createMonster(FlatBufferBuilder $builder, $pos, $mana, $hp, $name, $inventory, $color, $test_type, $test, $test4, $testarrayofstring, $testarrayoftables, $enemy, $testnestedflatbuffer, $testempty, $testbool, $testhashs32_fnv1, $testhashu32_fnv1, $testhashs64_fnv1, $testhashu64_fnv1, $testhashs32_fnv1a, $testhashu32_fnv1a, $testhashs64_fnv1a, $testhashu64_fnv1a, $testarrayofbools, $testf, $testf2, $testf3)
public static function createMonster(FlatBufferBuilder $builder, $pos, $mana, $hp, $name, $inventory, $color, $test_type, $test, $test4, $testarrayofstring, $testarrayoftables, $enemy, $testnestedflatbuffer, $testempty, $testbool, $testhashs32_fnv1, $testhashu32_fnv1, $testhashs64_fnv1, $testhashu64_fnv1, $testhashs32_fnv1a, $testhashu32_fnv1a, $testhashs64_fnv1a, $testhashu64_fnv1a, $testarrayofbools, $testf, $testf2, $testf3, $testarrayofstring2)
{
$builder->startObject(28);
$builder->startObject(29);
self::addPos($builder, $pos);
self::addMana($builder, $mana);
self::addHp($builder, $hp);
@@ -403,6 +422,7 @@ class Monster extends Table
self::addTestf($builder, $testf);
self::addTestf2($builder, $testf2);
self::addTestf3($builder, $testf3);
self::addTestarrayofstring2($builder, $testarrayofstring2);
$o = $builder->endObject();
$builder->required($o, 10); // name
return $o;
@@ -817,6 +837,40 @@ class Monster extends Table
$builder->addFloatX(27, $testf3, 0.0);
}
/**
* @param FlatBufferBuilder $builder
* @param VectorOffset
* @return void
*/
public static function addTestarrayofstring2(FlatBufferBuilder $builder, $testarrayofstring2)
{
$builder->addOffsetX(28, $testarrayofstring2, 0);
}
/**
* @param FlatBufferBuilder $builder
* @param array offset array
* @return int vector offset
*/
public static function createTestarrayofstring2Vector(FlatBufferBuilder $builder, array $data)
{
$builder->startVector(4, count($data), 4);
for ($i = count($data) - 1; $i >= 0; $i--) {
$builder->addOffset($data[$i]);
}
return $builder->endVector();
}
/**
* @param FlatBufferBuilder $builder
* @param int $numElems
* @return void
*/
public static function startTestarrayofstring2Vector(FlatBufferBuilder $builder, $numElems)
{
$builder->startVector(4, $numElems, 4);
}
/**
* @param FlatBufferBuilder $builder
* @return int table offset

View File

@@ -283,7 +283,22 @@ class Monster(object):
return self._tab.Get(flatbuffers.number_types.Float32Flags, o + self._tab.Pos)
return 0.0
def MonsterStart(builder): builder.StartObject(28)
# Monster
def Testarrayofstring2(self, j):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(60))
if o != 0:
a = self._tab.Vector(o)
return self._tab.String(a + flatbuffers.number_types.UOffsetTFlags.py_type(j * 4))
return ""
# Monster
def Testarrayofstring2Length(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(60))
if o != 0:
return self._tab.VectorLen(o)
return 0
def MonsterStart(builder): builder.StartObject(29)
def MonsterAddPos(builder, pos): builder.PrependStructSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(pos), 0)
def MonsterAddMana(builder, mana): builder.PrependInt16Slot(1, mana, 150)
def MonsterAddHp(builder, hp): builder.PrependInt16Slot(2, hp, 100)
@@ -317,4 +332,6 @@ def MonsterStartTestarrayofboolsVector(builder, numElems): return builder.StartV
def MonsterAddTestf(builder, testf): builder.PrependFloat32Slot(25, testf, 3.14159)
def MonsterAddTestf2(builder, testf2): builder.PrependFloat32Slot(26, testf2, 3.0)
def MonsterAddTestf3(builder, testf3): builder.PrependFloat32Slot(27, testf3, 0.0)
def MonsterAddTestarrayofstring2(builder, testarrayofstring2): builder.PrependUOffsetTRelativeSlot(28, flatbuffers.number_types.UOffsetTFlags.py_type(testarrayofstring2), 0)
def MonsterStartTestarrayofstring2Vector(builder, numElems): return builder.StartVector(4, numElems, 4)
def MonsterEnd(builder): return builder.EndObject()

View File

@@ -0,0 +1,23 @@
// automatically generated by the FlatBuffers compiler, do not modify
namespace MyGame.Example2
{
using System;
using FlatBuffers;
public sealed class Monster : Table {
public static Monster GetRootAsMonster(ByteBuffer _bb) { return GetRootAsMonster(_bb, new Monster()); }
public static Monster GetRootAsMonster(ByteBuffer _bb, Monster obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
public Monster __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
public static void StartMonster(FlatBufferBuilder builder) { builder.StartObject(0); }
public static Offset<MyGame.Example2.Monster> EndMonster(FlatBufferBuilder builder) {
int o = builder.EndObject();
return new Offset<MyGame.Example2.Monster>(o);
}
};
}

View File

@@ -0,0 +1,18 @@
// automatically generated by the FlatBuffers compiler, do not modify
package Example2
import (
flatbuffers "github.com/google/flatbuffers/go"
)
type Monster struct {
_tab flatbuffers.Table
}
func (rcv *Monster) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
}
func MonsterStart(builder *flatbuffers.Builder) { builder.StartObject(0) }
func MonsterEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() }

View File

@@ -0,0 +1,23 @@
// automatically generated by the FlatBuffers compiler, do not modify
package MyGame.Example2;
import java.nio.*;
import java.lang.*;
import java.util.*;
import com.google.flatbuffers.*;
@SuppressWarnings("unused")
public final class Monster extends Table {
public static Monster getRootAsMonster(ByteBuffer _bb) { return getRootAsMonster(_bb, new Monster()); }
public static Monster getRootAsMonster(ByteBuffer _bb, Monster obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
public Monster __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
public static void startMonster(FlatBufferBuilder builder) { builder.startObject(0); }
public static int endMonster(FlatBufferBuilder builder) {
int o = builder.endObject();
return o;
}
};

View File

@@ -0,0 +1,79 @@
<?php
// automatically generated by the FlatBuffers compiler, do not modify
namespace MyGame\Example2;
use \Google\FlatBuffers\Struct;
use \Google\FlatBuffers\Table;
use \Google\FlatBuffers\ByteBuffer;
use \Google\FlatBuffers\FlatBufferBuilder;
class Monster extends Table
{
/**
* @param ByteBuffer $bb
* @return Monster
*/
public static function getRootAsMonster(ByteBuffer $bb)
{
$obj = new Monster();
return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
}
public static function MonsterIdentifier()
{
return "MONS";
}
public static function MonsterBufferHasIdentifier(ByteBuffer $buf)
{
return self::__has_identifier($buf, self::MonsterIdentifier());
}
public static function MonsterExtension()
{
return "mon";
}
/**
* @param int $_i offset
* @param ByteBuffer $_bb
* @return Monster
**/
public function init($_i, ByteBuffer $_bb)
{
$this->bb_pos = $_i;
$this->bb = $_bb;
return $this;
}
/**
* @param FlatBufferBuilder $builder
* @return void
*/
public static function startMonster(FlatBufferBuilder $builder)
{
$builder->StartObject(0);
}
/**
* @param FlatBufferBuilder $builder
* @return Monster
*/
public static function createMonster(FlatBufferBuilder $builder, )
{
$builder->startObject(0);
$o = $builder->endObject();
return $o;
}
/**
* @param FlatBufferBuilder $builder
* @return int table offset
*/
public static function endMonster(FlatBufferBuilder $builder)
{
$o = $builder->endObject();
return $o;
}
}

View File

@@ -0,0 +1,15 @@
# automatically generated by the FlatBuffers compiler, do not modify
# namespace: Example2
import flatbuffers
class Monster(object):
__slots__ = ['_tab']
# Monster
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)
def MonsterStart(builder): builder.StartObject(0)
def MonsterEnd(builder): return builder.EndObject()

View File

@@ -0,0 +1,20 @@
#!/bin/bash
#
# 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.
git clone https://chromium.googlesource.com/chromium/llvm-project/llvm/lib/Fuzzer
clang++ -c -g -O2 -std=c++11 Fuzzer/*.cpp -IFuzzer
ar ruv libFuzzer.a Fuzzer*.o
rm -rf Fuzzer *.o

View File

@@ -0,0 +1,20 @@
#!/bin/bash
#
# 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.
clang++ -fsanitize-coverage=edge -fsanitize=address -std=c++11 -stdlib=libstdc++ -I.. -I../../include flatbuffers_parser_fuzzer.cc ../../src/idl_parser.cpp ../../src/util.cpp libFuzzer.a -o fuzz_parser
mkdir -p parser_corpus
cp ../*.json ../*.fbs parser_corpus
./fuzz_parser parser_corpus

View File

@@ -0,0 +1,20 @@
#!/bin/bash
#
# 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.
clang++ -fsanitize-coverage=edge -fsanitize=address -std=c++11 -stdlib=libstdc++ -I.. -I../../include flatbuffers_verifier_fuzzer.cc libFuzzer.a -o fuzz_verifier
mkdir -p verifier_corpus
cp ../*.mon verifier_corpus
./fuzz_verifier verifier_corpus

View File

@@ -0,0 +1,16 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <stdint.h>
#include <string>
#include "flatbuffers/idl.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
flatbuffers::Parser parser;
// Guarantee 0-termination.
std::string s(reinterpret_cast<const char *>(data), size);
parser.Parse(s.c_str());
return 0;
}

View File

@@ -0,0 +1,14 @@
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <stdint.h>
#include <string>
#include "monster_test_generated.h"
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
flatbuffers::Verifier verifier(data, size);
MyGame::Example::VerifyMonsterBuffer(verifier);
return 0;
}

View File

@@ -12,6 +12,6 @@
:: See the License for the specific language governing permissions and
:: limitations under the License.
..\flatc.exe --cpp --java --csharp --go --binary --python --js --php --gen-mutable --no-includes monster_test.fbs monsterdata_test.json
..\flatc.exe --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --no-includes monster_test.fbs monsterdata_test.json
..\flatc.exe --cpp --java --csharp --go --binary --python --js --php --gen-mutable -o namespace_test namespace_test\namespace_test1.fbs namespace_test\namespace_test2.fbs
..\flatc.exe --binary --schema monster_test.fbs

View File

@@ -14,7 +14,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
../flatc --cpp --java --csharp --go --binary --python --js --php --gen-mutable --no-includes monster_test.fbs monsterdata_test.json
../flatc --cpp --java --csharp --go --binary --python --js --php --grpc --gen-mutable --no-includes monster_test.fbs monsterdata_test.json
../flatc --cpp --java --csharp --go --binary --python --js --php --gen-mutable -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
../flatc --binary --schema monster_test.fbs

Binary file not shown.

View File

@@ -2,13 +2,17 @@
include "include_test1.fbs";
namespace MyGame.Example2;
table Monster {} // Test having same name as below, but in different namespace.
namespace MyGame.Example;
attribute "priority";
enum Color:byte (bit_flags) { Red = 0, Green, Blue = 3, }
union Any { Monster, TestSimpleTableWithEnum } // TODO: add more elements
union Any { Monster, TestSimpleTableWithEnum, MyGame.Example2.Monster }
struct Test { a:short; b:byte; }
@@ -44,6 +48,7 @@ table Monster {
/// multiline too
testarrayoftables:[Monster] (id: 11);
testarrayofstring:[string] (id: 10);
testarrayofstring2:[string] (id: 28);
testarrayofbools:[bool] (id: 24);
enemy:MyGame.Example.Monster (id:12); // Test referring by full namespace.
test:Any (id: 8);
@@ -65,7 +70,7 @@ table Monster {
}
rpc_service MonsterStorage {
Store(Monster):Stat (stream);
Store(Monster):Stat (streaming: "none");
Retrieve(Stat):Monster (idempotent);
}

View File

@@ -0,0 +1,85 @@
// Generated by the gRPC protobuf plugin.
// If you make any local change, they will be lost.
// source: monster_test
#include "monster_test_generated.h"
#include "monster_test.grpc.fb.h"
#include "flatbuffers/grpc.h"
#include <grpc++/impl/codegen/async_stream.h>
#include <grpc++/impl/codegen/async_unary_call.h>
#include <grpc++/impl/codegen/channel_interface.h>
#include <grpc++/impl/codegen/client_unary_call.h>
#include <grpc++/impl/codegen/method_handler_impl.h>
#include <grpc++/impl/codegen/rpc_service_method.h>
#include <grpc++/impl/codegen/service_type.h>
#include <grpc++/impl/codegen/sync_stream.h>
namespace MyGame {
namespace Example {
static const char* MonsterStorage_method_names[] = {
"/MyGame.Example..MonsterStorage/Store",
"/MyGame.Example..MonsterStorage/Retrieve",
};
std::unique_ptr< MonsterStorage::Stub> MonsterStorage::NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options) {
std::unique_ptr< MonsterStorage::Stub> stub(new MonsterStorage::Stub(channel));
return stub;
}
MonsterStorage::Stub::Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel)
: channel_(channel) , rpcmethod_Store_(MonsterStorage_method_names[0], ::grpc::RpcMethod::NORMAL_RPC, channel)
, rpcmethod_Retrieve_(MonsterStorage_method_names[1], ::grpc::RpcMethod::NORMAL_RPC, channel)
{}
::grpc::Status MonsterStorage::Stub::Store(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, flatbuffers::BufferRef<Stat>* response) {
return ::grpc::BlockingUnaryCall(channel_.get(), rpcmethod_Store_, context, request, response);
}
::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Stat>>* MonsterStorage::Stub::AsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, ::grpc::CompletionQueue* cq) {
return new ::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Stat>>(channel_.get(), cq, rpcmethod_Store_, context, request);
}
::grpc::Status MonsterStorage::Stub::Retrieve(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, flatbuffers::BufferRef<Monster>* response) {
return ::grpc::BlockingUnaryCall(channel_.get(), rpcmethod_Retrieve_, context, request, response);
}
::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Monster>>* MonsterStorage::Stub::AsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, ::grpc::CompletionQueue* cq) {
return new ::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Monster>>(channel_.get(), cq, rpcmethod_Retrieve_, context, request);
}
MonsterStorage::Service::Service() {
(void)MonsterStorage_method_names;
AddMethod(new ::grpc::RpcServiceMethod(
MonsterStorage_method_names[0],
::grpc::RpcMethod::NORMAL_RPC,
new ::grpc::RpcMethodHandler< MonsterStorage::Service, flatbuffers::BufferRef<Monster>, flatbuffers::BufferRef<Stat>>(
std::mem_fn(&MonsterStorage::Service::Store), this)));
AddMethod(new ::grpc::RpcServiceMethod(
MonsterStorage_method_names[1],
::grpc::RpcMethod::NORMAL_RPC,
new ::grpc::RpcMethodHandler< MonsterStorage::Service, flatbuffers::BufferRef<Stat>, flatbuffers::BufferRef<Monster>>(
std::mem_fn(&MonsterStorage::Service::Retrieve), this)));
}
MonsterStorage::Service::~Service() {
}
::grpc::Status MonsterStorage::Service::Store(::grpc::ServerContext* context, const flatbuffers::BufferRef<Monster>* request, flatbuffers::BufferRef<Stat>* response) {
(void) context;
(void) request;
(void) response;
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
::grpc::Status MonsterStorage::Service::Retrieve(::grpc::ServerContext* context, const flatbuffers::BufferRef<Stat>* request, flatbuffers::BufferRef<Monster>* response) {
(void) context;
(void) request;
(void) response;
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
} // namespace MyGame
} // namespace Example

View File

@@ -0,0 +1,155 @@
// Generated by the gRPC protobuf plugin.
// If you make any local change, they will be lost.
// source: monster_test
#ifndef GRPC_monster_5ftest__INCLUDED
#define GRPC_monster_5ftest__INCLUDED
#include "monster_test_generated.h"
#include <grpc++/impl/codegen/async_stream.h>
#include <grpc++/impl/codegen/async_unary_call.h>
#include <grpc++/impl/codegen/proto_utils.h>
#include <grpc++/impl/codegen/rpc_method.h>
#include <grpc++/impl/codegen/service_type.h>
#include <grpc++/impl/codegen/status.h>
#include <grpc++/impl/codegen/stub_options.h>
#include <grpc++/impl/codegen/sync_stream.h>
namespace grpc {
class CompletionQueue;
class Channel;
class RpcService;
class ServerCompletionQueue;
class ServerContext;
} // namespace grpc
namespace MyGame {
namespace Example {
class MonsterStorage GRPC_FINAL {
public:
class StubInterface {
public:
virtual ~StubInterface() {}
virtual ::grpc::Status Store(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, flatbuffers::BufferRef<Stat>* response) = 0;
std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::BufferRef<Stat>>> AsyncStore(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::BufferRef<Stat>>>(AsyncStoreRaw(context, request, cq));
}
virtual ::grpc::Status Retrieve(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, flatbuffers::BufferRef<Monster>* response) = 0;
std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::BufferRef<Monster>>> AsyncRetrieve(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::BufferRef<Monster>>>(AsyncRetrieveRaw(context, request, cq));
}
private:
virtual ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::BufferRef<Stat>>* AsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, ::grpc::CompletionQueue* cq) = 0;
virtual ::grpc::ClientAsyncResponseReaderInterface< flatbuffers::BufferRef<Monster>>* AsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, ::grpc::CompletionQueue* cq) = 0;
};
class Stub GRPC_FINAL : public StubInterface {
public:
Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel);
::grpc::Status Store(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, flatbuffers::BufferRef<Stat>* response) GRPC_OVERRIDE;
std::unique_ptr< ::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Stat>>> AsyncStore(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Stat>>>(AsyncStoreRaw(context, request, cq));
}
::grpc::Status Retrieve(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, flatbuffers::BufferRef<Monster>* response) GRPC_OVERRIDE;
std::unique_ptr< ::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Monster>>> AsyncRetrieve(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, ::grpc::CompletionQueue* cq) {
return std::unique_ptr< ::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Monster>>>(AsyncRetrieveRaw(context, request, cq));
}
private:
std::shared_ptr< ::grpc::ChannelInterface> channel_;
::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Stat>>* AsyncStoreRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Monster>& request, ::grpc::CompletionQueue* cq) GRPC_OVERRIDE;
::grpc::ClientAsyncResponseReader< flatbuffers::BufferRef<Monster>>* AsyncRetrieveRaw(::grpc::ClientContext* context, const flatbuffers::BufferRef<Stat>& request, ::grpc::CompletionQueue* cq) GRPC_OVERRIDE;
const ::grpc::RpcMethod rpcmethod_Store_;
const ::grpc::RpcMethod rpcmethod_Retrieve_;
};
static std::unique_ptr<Stub> NewStub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, const ::grpc::StubOptions& options = ::grpc::StubOptions());
class Service : public ::grpc::Service {
public:
Service();
virtual ~Service();
virtual ::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::BufferRef<Monster>* request, flatbuffers::BufferRef<Stat>* response);
virtual ::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::BufferRef<Stat>* request, flatbuffers::BufferRef<Monster>* response);
};
template <class BaseClass>
class WithAsyncMethod_Store : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service *service) {}
public:
WithAsyncMethod_Store() {
::grpc::Service::MarkMethodAsync(0);
}
~WithAsyncMethod_Store() GRPC_OVERRIDE {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::BufferRef<Monster>* request, flatbuffers::BufferRef<Stat>* response) GRPC_FINAL GRPC_OVERRIDE {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
void RequestStore(::grpc::ServerContext* context, flatbuffers::BufferRef<Monster>* request, ::grpc::ServerAsyncResponseWriter< flatbuffers::BufferRef<Stat>>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
::grpc::Service::RequestAsyncUnary(0, context, request, response, new_call_cq, notification_cq, tag);
}
};
template <class BaseClass>
class WithAsyncMethod_Retrieve : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service *service) {}
public:
WithAsyncMethod_Retrieve() {
::grpc::Service::MarkMethodAsync(1);
}
~WithAsyncMethod_Retrieve() GRPC_OVERRIDE {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::BufferRef<Stat>* request, flatbuffers::BufferRef<Monster>* response) GRPC_FINAL GRPC_OVERRIDE {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
void RequestRetrieve(::grpc::ServerContext* context, flatbuffers::BufferRef<Stat>* request, ::grpc::ServerAsyncResponseWriter< flatbuffers::BufferRef<Monster>>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) {
::grpc::Service::RequestAsyncUnary(1, context, request, response, new_call_cq, notification_cq, tag);
}
};
typedef WithAsyncMethod_Store< WithAsyncMethod_Retrieve< Service > > AsyncService;
template <class BaseClass>
class WithGenericMethod_Store : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service *service) {}
public:
WithGenericMethod_Store() {
::grpc::Service::MarkMethodGeneric(0);
}
~WithGenericMethod_Store() GRPC_OVERRIDE {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status Store(::grpc::ServerContext* context, const flatbuffers::BufferRef<Monster>* request, flatbuffers::BufferRef<Stat>* response) GRPC_FINAL GRPC_OVERRIDE {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
};
template <class BaseClass>
class WithGenericMethod_Retrieve : public BaseClass {
private:
void BaseClassMustBeDerivedFromService(const Service *service) {}
public:
WithGenericMethod_Retrieve() {
::grpc::Service::MarkMethodGeneric(1);
}
~WithGenericMethod_Retrieve() GRPC_OVERRIDE {
BaseClassMustBeDerivedFromService(this);
}
// disable synchronous version of this method
::grpc::Status Retrieve(::grpc::ServerContext* context, const flatbuffers::BufferRef<Stat>* request, flatbuffers::BufferRef<Monster>* response) GRPC_FINAL GRPC_OVERRIDE {
abort();
return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, "");
}
};
};
} // namespace Example
} // namespace MyGame
#endif // GRPC_monster_5ftest__INCLUDED

View File

@@ -6,6 +6,12 @@
#include "flatbuffers/flatbuffers.h"
namespace MyGame {
namespace Example2 {
struct Monster;
} // namespace Example2
namespace Example {
struct Test;
@@ -22,8 +28,8 @@ enum Color {
Color_Red = 1,
Color_Green = 2,
Color_Blue = 8,
Color_MIN = Color_Red,
Color_MAX = Color_Blue
Color_NONE = 0,
Color_ANY = 11
};
inline const char **EnumNamesColor() {
@@ -37,12 +43,13 @@ enum Any {
Any_NONE = 0,
Any_Monster = 1,
Any_TestSimpleTableWithEnum = 2,
Any_MyGame_Example2_Monster = 3,
Any_MIN = Any_NONE,
Any_MAX = Any_TestSimpleTableWithEnum
Any_MAX = Any_MyGame_Example2_Monster
};
inline const char **EnumNamesAny() {
static const char *names[] = { "NONE", "Monster", "TestSimpleTableWithEnum", nullptr };
static const char *names[] = { "NONE", "Monster", "TestSimpleTableWithEnum", "MyGame_Example2_Monster", nullptr };
return names;
}
@@ -98,6 +105,37 @@ MANUALLY_ALIGNED_STRUCT(16) Vec3 FLATBUFFERS_FINAL_CLASS {
};
STRUCT_END(Vec3, 32);
} // namespace Example
namespace Example2 {
struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
verifier.EndTable();
}
};
struct MonsterBuilder {
flatbuffers::FlatBufferBuilder &fbb_;
flatbuffers::uoffset_t start_;
MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
MonsterBuilder &operator=(const MonsterBuilder &);
flatbuffers::Offset<Monster> Finish() {
auto o = flatbuffers::Offset<Monster>(fbb_.EndTable(start_, 0));
return o;
}
};
inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb) {
MonsterBuilder builder_(_fbb);
return builder_.Finish();
}
} // namespace Example2
namespace Example {
struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
VT_COLOR = 4
@@ -206,7 +244,8 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VT_TESTARRAYOFBOOLS = 52,
VT_TESTF = 54,
VT_TESTF2 = 56,
VT_TESTF3 = 58
VT_TESTF3 = 58,
VT_TESTARRAYOFSTRING2 = 60
};
const Vec3 *pos() const { return GetStruct<const Vec3 *>(VT_POS); }
Vec3 *mutable_pos() { return GetStruct<Vec3 *>(VT_POS); }
@@ -267,6 +306,8 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
bool mutate_testf2(float _testf2) { return SetField(VT_TESTF2, _testf2); }
float testf3() const { return GetField<float>(VT_TESTF3, 0.0f); }
bool mutate_testf3(float _testf3) { return SetField(VT_TESTF3, _testf3); }
const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *testarrayofstring2() const { return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_TESTARRAYOFSTRING2); }
flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *mutable_testarrayofstring2() { return GetPointer<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> *>(VT_TESTARRAYOFSTRING2); }
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyField<Vec3>(verifier, VT_POS) &&
@@ -308,6 +349,9 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VerifyField<float>(verifier, VT_TESTF) &&
VerifyField<float>(verifier, VT_TESTF2) &&
VerifyField<float>(verifier, VT_TESTF3) &&
VerifyField<flatbuffers::uoffset_t>(verifier, VT_TESTARRAYOFSTRING2) &&
verifier.Verify(testarrayofstring2()) &&
verifier.VerifyVectorOfStrings(testarrayofstring2()) &&
verifier.EndTable();
}
};
@@ -342,10 +386,11 @@ struct MonsterBuilder {
void add_testf(float testf) { fbb_.AddElement<float>(Monster::VT_TESTF, testf, 3.14159f); }
void add_testf2(float testf2) { fbb_.AddElement<float>(Monster::VT_TESTF2, testf2, 3.0f); }
void add_testf3(float testf3) { fbb_.AddElement<float>(Monster::VT_TESTF3, testf3, 0.0f); }
void add_testarrayofstring2(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> testarrayofstring2) { fbb_.AddOffset(Monster::VT_TESTARRAYOFSTRING2, testarrayofstring2); }
MonsterBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
MonsterBuilder &operator=(const MonsterBuilder &);
flatbuffers::Offset<Monster> Finish() {
auto o = flatbuffers::Offset<Monster>(fbb_.EndTable(start_, 28));
auto o = flatbuffers::Offset<Monster>(fbb_.EndTable(start_, 29));
fbb_.Required(o, Monster::VT_NAME); // name
return o;
}
@@ -378,12 +423,14 @@ inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> testarrayofbools = 0,
float testf = 3.14159f,
float testf2 = 3.0f,
float testf3 = 0.0f) {
float testf3 = 0.0f,
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>> testarrayofstring2 = 0) {
MonsterBuilder builder_(_fbb);
builder_.add_testhashu64_fnv1a(testhashu64_fnv1a);
builder_.add_testhashs64_fnv1a(testhashs64_fnv1a);
builder_.add_testhashu64_fnv1(testhashu64_fnv1);
builder_.add_testhashs64_fnv1(testhashs64_fnv1);
builder_.add_testarrayofstring2(testarrayofstring2);
builder_.add_testf3(testf3);
builder_.add_testf2(testf2);
builder_.add_testf(testf);
@@ -415,6 +462,7 @@ inline bool VerifyAny(flatbuffers::Verifier &verifier, const void *union_obj, An
case Any_NONE: return true;
case Any_Monster: return verifier.VerifyTable(reinterpret_cast<const Monster *>(union_obj));
case Any_TestSimpleTableWithEnum: return verifier.VerifyTable(reinterpret_cast<const TestSimpleTableWithEnum *>(union_obj));
case Any_MyGame_Example2_Monster: return verifier.VerifyTable(reinterpret_cast<const MyGame::Example2::Monster *>(union_obj));
default: return false;
}
}

View File

@@ -10,6 +10,11 @@ var MyGame = MyGame || {};
*/
MyGame.Example = MyGame.Example || {};
/**
* @const
*/
MyGame.Example2 = MyGame.Example2 || {};
/**
* @const
*/
@@ -30,7 +35,59 @@ MyGame.Example.Color = {
MyGame.Example.Any = {
NONE: 0,
Monster: 1,
TestSimpleTableWithEnum: 2
TestSimpleTableWithEnum: 2,
MyGame_Example2_Monster: 3
};
/**
* @constructor
*/
MyGame.Example2.Monster = function() {
/**
* @type {flatbuffers.ByteBuffer}
*/
this.bb = null;
/**
* @type {number}
*/
this.bb_pos = 0;
};
/**
* @param {number} i
* @param {flatbuffers.ByteBuffer} bb
* @returns {MyGame.Example2.Monster}
*/
MyGame.Example2.Monster.prototype.__init = function(i, bb) {
this.bb_pos = i;
this.bb = bb;
return this;
};
/**
* @param {flatbuffers.ByteBuffer} bb
* @param {MyGame.Example2.Monster=} obj
* @returns {MyGame.Example2.Monster}
*/
MyGame.Example2.Monster.getRootAsMonster = function(bb, obj) {
return (obj || new MyGame.Example2.Monster).__init(bb.readInt32(bb.position()) + bb.position(), bb);
};
/**
* @param {flatbuffers.Builder} builder
*/
MyGame.Example2.Monster.startMonster = function(builder) {
builder.startObject(0);
};
/**
* @param {flatbuffers.Builder} builder
* @returns {flatbuffers.Offset}
*/
MyGame.Example2.Monster.endMonster = function(builder) {
var offset = builder.endObject();
return offset;
};
/**
@@ -701,11 +758,29 @@ MyGame.Example.Monster.prototype.testf3 = function() {
return offset ? this.bb.readFloat32(this.bb_pos + offset) : 0.0;
};
/**
* @param {number} index
* @param {flatbuffers.Encoding=} optionalEncoding
* @returns {string|Uint8Array}
*/
MyGame.Example.Monster.prototype.testarrayofstring2 = function(index, optionalEncoding) {
var offset = this.bb.__offset(this.bb_pos, 60);
return offset ? this.bb.__string(this.bb.__vector(this.bb_pos + offset) + index * 4, optionalEncoding) : null;
};
/**
* @returns {number}
*/
MyGame.Example.Monster.prototype.testarrayofstring2Length = function() {
var offset = this.bb.__offset(this.bb_pos, 60);
return offset ? this.bb.__vector_len(this.bb_pos + offset) : 0;
};
/**
* @param {flatbuffers.Builder} builder
*/
MyGame.Example.Monster.startMonster = function(builder) {
builder.startObject(28);
builder.startObject(29);
};
/**
@@ -1037,6 +1112,35 @@ MyGame.Example.Monster.addTestf3 = function(builder, testf3) {
builder.addFieldFloat32(27, testf3, 0.0);
};
/**
* @param {flatbuffers.Builder} builder
* @param {flatbuffers.Offset} testarrayofstring2Offset
*/
MyGame.Example.Monster.addTestarrayofstring2 = function(builder, testarrayofstring2Offset) {
builder.addFieldOffset(28, testarrayofstring2Offset, 0);
};
/**
* @param {flatbuffers.Builder} builder
* @param {Array.<flatbuffers.Offset>} data
* @returns {flatbuffers.Offset}
*/
MyGame.Example.Monster.createTestarrayofstring2Vector = function(builder, data) {
builder.startVector(4, data.length, 4);
for (var i = data.length - 1; i >= 0; i--) {
builder.addOffset(data[i]);
}
return builder.endVector();
};
/**
* @param {flatbuffers.Builder} builder
* @param {number} numElems
*/
MyGame.Example.Monster.startTestarrayofstring2Vector = function(builder, numElems) {
builder.startVector(4, numElems, 4);
};
/**
* @param {flatbuffers.Builder} builder
* @returns {flatbuffers.Offset}

Binary file not shown.

View File

@@ -0,0 +1,38 @@
// automatically generated by the FlatBuffers compiler, do not modify
namespace NamespaceC
{
using System;
using FlatBuffers;
public sealed class TableInC : Table {
public static TableInC GetRootAsTableInC(ByteBuffer _bb) { return GetRootAsTableInC(_bb, new TableInC()); }
public static TableInC GetRootAsTableInC(ByteBuffer _bb, TableInC obj) { return (obj.__init(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
public TableInC __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
public NamespaceA.TableInFirstNS ReferToA1 { get { return GetReferToA1(new NamespaceA.TableInFirstNS()); } }
public NamespaceA.TableInFirstNS GetReferToA1(NamespaceA.TableInFirstNS obj) { int o = __offset(4); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
public SecondTableInA ReferToA2 { get { return GetReferToA2(new SecondTableInA()); } }
public SecondTableInA GetReferToA2(SecondTableInA obj) { int o = __offset(6); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
public static Offset<NamespaceC.TableInC> CreateTableInC(FlatBufferBuilder builder,
Offset<NamespaceA.TableInFirstNS> refer_to_a1Offset = default(Offset<NamespaceA.TableInFirstNS>),
Offset<SecondTableInA> refer_to_a2Offset = default(Offset<SecondTableInA>)) {
builder.StartObject(2);
TableInC.AddReferToA2(builder, refer_to_a2Offset);
TableInC.AddReferToA1(builder, refer_to_a1Offset);
return TableInC.EndTableInC(builder);
}
public static void StartTableInC(FlatBufferBuilder builder) { builder.StartObject(2); }
public static void AddReferToA1(FlatBufferBuilder builder, Offset<NamespaceA.TableInFirstNS> referToA1Offset) { builder.AddOffset(0, referToA1Offset.Value, 0); }
public static void AddReferToA2(FlatBufferBuilder builder, Offset<SecondTableInA> referToA2Offset) { builder.AddOffset(1, referToA2Offset.Value, 0); }
public static Offset<NamespaceC.TableInC> EndTableInC(FlatBufferBuilder builder) {
int o = builder.EndObject();
return new Offset<NamespaceC.TableInC>(o);
}
};
}

View File

@@ -0,0 +1,46 @@
// automatically generated by the FlatBuffers compiler, do not modify
package NamespaceC
import (
flatbuffers "github.com/google/flatbuffers/go"
)
type TableInC struct {
_tab flatbuffers.Table
}
func (rcv *TableInC) Init(buf []byte, i flatbuffers.UOffsetT) {
rcv._tab.Bytes = buf
rcv._tab.Pos = i
}
func (rcv *TableInC) ReferToA1(obj *TableInFirstNS) *TableInFirstNS {
o := flatbuffers.UOffsetT(rcv._tab.Offset(4))
if o != 0 {
x := rcv._tab.Indirect(o + rcv._tab.Pos)
if obj == nil {
obj = new(TableInFirstNS)
}
obj.Init(rcv._tab.Bytes, x)
return obj
}
return nil
}
func (rcv *TableInC) ReferToA2(obj *SecondTableInA) *SecondTableInA {
o := flatbuffers.UOffsetT(rcv._tab.Offset(6))
if o != 0 {
x := rcv._tab.Indirect(o + rcv._tab.Pos)
if obj == nil {
obj = new(SecondTableInA)
}
obj.Init(rcv._tab.Bytes, x)
return obj
}
return nil
}
func TableInCStart(builder *flatbuffers.Builder) { builder.StartObject(2) }
func TableInCAddReferToA1(builder *flatbuffers.Builder, referToA1 flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(referToA1), 0) }
func TableInCAddReferToA2(builder *flatbuffers.Builder, referToA2 flatbuffers.UOffsetT) { builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(referToA2), 0) }
func TableInCEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() }

View File

@@ -0,0 +1,38 @@
// automatically generated by the FlatBuffers compiler, do not modify
package NamespaceC;
import java.nio.*;
import java.lang.*;
import java.util.*;
import com.google.flatbuffers.*;
@SuppressWarnings("unused")
public final class TableInC extends Table {
public static TableInC getRootAsTableInC(ByteBuffer _bb) { return getRootAsTableInC(_bb, new TableInC()); }
public static TableInC getRootAsTableInC(ByteBuffer _bb, TableInC obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__init(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
public TableInC __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; return this; }
public NamespaceA.TableInFirstNS referToA1() { return referToA1(new NamespaceA.TableInFirstNS()); }
public NamespaceA.TableInFirstNS referToA1(NamespaceA.TableInFirstNS obj) { int o = __offset(4); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
public SecondTableInA referToA2() { return referToA2(new SecondTableInA()); }
public SecondTableInA referToA2(SecondTableInA obj) { int o = __offset(6); return o != 0 ? obj.__init(__indirect(o + bb_pos), bb) : null; }
public static int createTableInC(FlatBufferBuilder builder,
int refer_to_a1Offset,
int refer_to_a2Offset) {
builder.startObject(2);
TableInC.addReferToA2(builder, refer_to_a2Offset);
TableInC.addReferToA1(builder, refer_to_a1Offset);
return TableInC.endTableInC(builder);
}
public static void startTableInC(FlatBufferBuilder builder) { builder.startObject(2); }
public static void addReferToA1(FlatBufferBuilder builder, int referToA1Offset) { builder.addOffset(0, referToA1Offset, 0); }
public static void addReferToA2(FlatBufferBuilder builder, int referToA2Offset) { builder.addOffset(1, referToA2Offset, 0); }
public static int endTableInC(FlatBufferBuilder builder) {
int o = builder.endObject();
return o;
}
};

View File

@@ -0,0 +1,100 @@
<?php
// automatically generated by the FlatBuffers compiler, do not modify
namespace NamespaceC;
use \Google\FlatBuffers\Struct;
use \Google\FlatBuffers\Table;
use \Google\FlatBuffers\ByteBuffer;
use \Google\FlatBuffers\FlatBufferBuilder;
class TableInC extends Table
{
/**
* @param ByteBuffer $bb
* @return TableInC
*/
public static function getRootAsTableInC(ByteBuffer $bb)
{
$obj = new TableInC();
return ($obj->init($bb->getInt($bb->getPosition()) + $bb->getPosition(), $bb));
}
/**
* @param int $_i offset
* @param ByteBuffer $_bb
* @return TableInC
**/
public function init($_i, ByteBuffer $_bb)
{
$this->bb_pos = $_i;
$this->bb = $_bb;
return $this;
}
public function getReferToA1()
{
$obj = new TableInFirstNS();
$o = $this->__offset(4);
return $o != 0 ? $obj->init($this->__indirect($o + $this->bb_pos), $this->bb) : 0;
}
public function getReferToA2()
{
$obj = new SecondTableInA();
$o = $this->__offset(6);
return $o != 0 ? $obj->init($this->__indirect($o + $this->bb_pos), $this->bb) : 0;
}
/**
* @param FlatBufferBuilder $builder
* @return void
*/
public static function startTableInC(FlatBufferBuilder $builder)
{
$builder->StartObject(2);
}
/**
* @param FlatBufferBuilder $builder
* @return TableInC
*/
public static function createTableInC(FlatBufferBuilder $builder, $refer_to_a1, $refer_to_a2)
{
$builder->startObject(2);
self::addReferToA1($builder, $refer_to_a1);
self::addReferToA2($builder, $refer_to_a2);
$o = $builder->endObject();
return $o;
}
/**
* @param FlatBufferBuilder $builder
* @param int
* @return void
*/
public static function addReferToA1(FlatBufferBuilder $builder, $referToA1)
{
$builder->addOffsetX(0, $referToA1, 0);
}
/**
* @param FlatBufferBuilder $builder
* @param int
* @return void
*/
public static function addReferToA2(FlatBufferBuilder $builder, $referToA2)
{
$builder->addOffsetX(1, $referToA2, 0);
}
/**
* @param FlatBufferBuilder $builder
* @return int table offset
*/
public static function endTableInC(FlatBufferBuilder $builder)
{
$o = $builder->endObject();
return $o;
}
}

View File

@@ -0,0 +1,39 @@
# automatically generated by the FlatBuffers compiler, do not modify
# namespace: NamespaceC
import flatbuffers
class TableInC(object):
__slots__ = ['_tab']
# TableInC
def Init(self, buf, pos):
self._tab = flatbuffers.table.Table(buf, pos)
# TableInC
def ReferToA1(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
if o != 0:
x = self._tab.Indirect(o + self._tab.Pos)
from .TableInFirstNS import TableInFirstNS
obj = TableInFirstNS()
obj.Init(self._tab.Bytes, x)
return obj
return None
# TableInC
def ReferToA2(self):
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
if o != 0:
x = self._tab.Indirect(o + self._tab.Pos)
from .SecondTableInA import SecondTableInA
obj = SecondTableInA()
obj.Init(self._tab.Bytes, x)
return obj
return None
def TableInCStart(builder): builder.StartObject(2)
def TableInCAddReferToA1(builder, referToA1): builder.PrependUOffsetTRelativeSlot(0, flatbuffers.number_types.UOffsetTFlags.py_type(referToA1), 0)
def TableInCAddReferToA2(builder, referToA2): builder.PrependUOffsetTRelativeSlot(1, flatbuffers.number_types.UOffsetTFlags.py_type(referToA2), 0)
def TableInCEnd(builder): return builder.EndObject()

View File

@@ -23,10 +23,6 @@ namespace NamespaceA {
struct SecondTableInA;
} // namespace NamespaceA
namespace NamespaceA {
struct TableInFirstNS FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
VT_FOO_TABLE = 4,

View File

@@ -162,9 +162,10 @@ class TestFuzz(unittest.TestCase):
''' Low level stress/fuzz test: serialize/deserialize a variety of
different kinds of data in different combinations '''
ofInt32Bytes = compat.binary_type([0x83, 0x33, 0x33, 0x33])
ofInt64Bytes = compat.binary_type([0x84, 0x44, 0x44, 0x44,
0x44, 0x44, 0x44, 0x44])
binary_type = compat.binary_types[0] # this will always exist
ofInt32Bytes = binary_type([0x83, 0x33, 0x33, 0x33])
ofInt64Bytes = binary_type([0x84, 0x44, 0x44, 0x44,
0x44, 0x44, 0x44, 0x44])
overflowingInt32Val = flatbuffers.encode.Get(flatbuffers.packer.int32,
ofInt32Bytes, 0)
overflowingInt64Val = flatbuffers.encode.Get(flatbuffers.packer.int64,

View File

@@ -108,18 +108,23 @@ flatbuffers::unique_ptr_t CreateFlatBufferTest(std::string &buffer) {
mlocs[0] = mb1.Finish();
MonsterBuilder mb2(builder);
mb2.add_name(barney);
mb2.add_hp(1000);
mlocs[1] = mb2.Finish();
MonsterBuilder mb3(builder);
mb3.add_name(wilma);
mlocs[2] = mb3.Finish();
// Create an array of strings. Also test string pooling.
flatbuffers::Offset<flatbuffers::String> strings[4];
strings[0] = builder.CreateSharedString("bob");
strings[1] = builder.CreateSharedString("fred");
strings[2] = builder.CreateSharedString("bob");
strings[3] = builder.CreateSharedString("fred");
auto vecofstrings = builder.CreateVector(strings, 4);
// Create an array of strings. Also test string pooling, and lambdas.
const char *names[] = { "bob", "fred", "bob", "fred" };
auto vecofstrings =
builder.CreateVector<flatbuffers::Offset<flatbuffers::String>>(4,
[&](size_t i) {
return builder.CreateSharedString(names[i]);
});
// Creating vectors of strings in one convenient call.
std::vector<std::string> names2 = { "jane", "mary" };
auto vecofstrings2 = builder.CreateVectorOfStrings(names2);
// Create an array of sorted tables, can be used with binary search when read:
auto vecoftables = builder.CreateVectorOfSortedTables(mlocs, 3);
@@ -127,7 +132,9 @@ flatbuffers::unique_ptr_t CreateFlatBufferTest(std::string &buffer) {
// shortcut for creating monster with all fields set:
auto mloc = CreateMonster(builder, &vec, 150, 80, name, inventory, Color_Blue,
Any_Monster, mlocs[1].Union(), // Store a union.
testv, vecofstrings, vecoftables, 0);
testv, vecofstrings, vecoftables, 0, 0, 0, false,
0, 0, 0, 0, 0, 0, 0, 0, 0, 3.14159f, 3.0f, 0.0f,
vecofstrings2);
FinishMonsterBuffer(builder, mloc);
@@ -197,12 +204,20 @@ void AccessFlatBufferTest(const uint8_t *flatbuf, size_t length) {
TEST_EQ(vecofstrings->Get(0)->c_str(), vecofstrings->Get(2)->c_str());
TEST_EQ(vecofstrings->Get(1)->c_str(), vecofstrings->Get(3)->c_str());
auto vecofstrings2 = monster->testarrayofstring2();
if (vecofstrings2) {
TEST_EQ(vecofstrings2->Length(), 2U);
TEST_EQ_STR(vecofstrings2->Get(0)->c_str(), "jane");
TEST_EQ_STR(vecofstrings2->Get(1)->c_str(), "mary");
}
// Example of accessing a vector of tables:
auto vecoftables = monster->testarrayoftables();
TEST_EQ(vecoftables->Length(), 3U);
for (auto it = vecoftables->begin(); it != vecoftables->end(); ++it)
TEST_EQ(strlen(it->name()->c_str()) >= 4, true);
TEST_EQ_STR(vecoftables->Get(0)->name()->c_str(), "Barney");
TEST_EQ(vecoftables->Get(0)->hp(), 1000);
TEST_EQ_STR(vecoftables->Get(1)->name()->c_str(), "Fred");
TEST_EQ_STR(vecoftables->Get(2)->name()->c_str(), "Wilma");
TEST_NOTNULL(vecoftables->LookupByKey("Barney"));
@@ -260,6 +275,13 @@ void MutateFlatBuffersTest(uint8_t *flatbuf, std::size_t length) {
TEST_EQ(inventory->Get(9), 100);
inventory->Mutate(9, 9);
auto tables = monster->mutable_testarrayoftables();
auto first = tables->GetMutableObject(0);
TEST_EQ(first->hp(), 1000);
first->mutate_hp(0);
TEST_EQ(first->hp(), 0);
first->mutate_hp(1000);
// Run the verifier and the regular test to make sure we didn't trample on
// anything.
AccessFlatBufferTest(flatbuf, length);
@@ -761,7 +783,7 @@ void ErrorTest() {
TestError("table X { Y:int; Y:int; }", "field already");
TestError("struct X { Y:string; }", "only scalar");
TestError("struct X { Y:int (deprecated); }", "deprecate");
TestError("union Z { X } table X { Y:Z; } root_type X; { Y: {",
TestError("union Z { X } table X { Y:Z; } root_type X; { Y: {}, A:1 }",
"missing type field");
TestError("union Z { X } table X { Y:Z; } root_type X; { Y_type: 99, Y: {",
"type id");
@@ -792,20 +814,29 @@ void ErrorTest() {
TestError("table X { Y:byte; } root_type X; { Y:1, Y:2 }", "more than once");
}
// Additional parser testing not covered elsewhere.
void ScientificTest() {
float TestValue(const char *json) {
flatbuffers::Parser parser;
// Simple schema.
TEST_EQ(parser.Parse("table X { Y:float; } root_type X;"), true);
// Test scientific notation numbers.
TEST_EQ(parser.Parse("{ Y:0.0314159e+2 }"), true);
TEST_EQ(parser.Parse(json), true);
auto root = flatbuffers::GetRoot<float>(parser.builder_.GetBufferPointer());
// root will point to the table, which is a 32bit vtable offset followed
// by a float:
TEST_EQ(sizeof(flatbuffers::soffset_t) == 4 && // Test assumes 32bit offsets
fabs(root[1] - 3.14159) < 0.001, true);
TEST_EQ(sizeof(flatbuffers::soffset_t), 4); // Test assumes 32bit offsets
return root[1];
}
bool FloatCompare(float a, float b) { return fabs(a - b) < 0.001; }
// Additional parser testing not covered elsewhere.
void ValueTest() {
// Test scientific notation numbers.
TEST_EQ(FloatCompare(TestValue("{ Y:0.0314159e+2 }"), 3.14159), true);
// Test conversion functions.
TEST_EQ(FloatCompare(TestValue("{ Y:cos(rad(180)) }"), -1), true);
}
void EnumStringsTest() {
@@ -920,6 +951,16 @@ void UnknownFieldsTest() {
TEST_EQ(jsongen == "{str: \"test\",i: 10}", true);
}
void ParseUnionTest() {
// Unions must be parseable with the type field following the object.
flatbuffers::Parser parser;
TEST_EQ(parser.Parse("table T { A:int; }"
"union U { T }"
"table V { X:U; }"
"root_type V;"
"{ X:{ A:1 }, X_type: T }"), true);
}
int main(int /*argc*/, const char * /*argv*/[]) {
// Run our various test suites:
@@ -941,13 +982,14 @@ int main(int /*argc*/, const char * /*argv*/[]) {
FuzzTest2();
ErrorTest();
ScientificTest();
ValueTest();
EnumStringsTest();
IntegerOutOfRangeTest();
UnicodeTest();
UnicodeSurrogatesTest();
UnicodeInvalidSurrogatesTest();
UnknownFieldsTest();
ParseUnionTest();
if (!testing_fails) {
TEST_OUTPUT_LINE("ALL TESTS PASSED");