C++98 (stlport) support for core FlatBuffers and FlexBuffers.

* Added internal - limited - implementation of flatbuffers::unique_ptr
  for STLs that don't ship with std::unique_ptr.  In C++11 and beyond
  this is just an alias for std::unique_ptr.
* Aliased used type traits structs is_scalar is_floating_point is_unsigned
  into flatbuffers namespace so they can be replaced in C++98 implementations.
  Right now these point at stlport's TR1 implementations.
* Wrapped vector::data() in vector_data().
* Wrapped vector::emplace_back() in vector_emplace_back().
* Wrapper string::back() in string_back().
* Added variants of FlatBufferBuilder::CreateVector() and
  FlatBufferBuilder::CreateVectorOfStructs() that allow the use of plain
  function pointers.
  Generated code has also been modified to use plain functions to build objects
  rather than std::function() so all generated code will work in C++98
  applications.
* Added flexbuffers::Builder::Vector(), flexbuffers::Builder::TypedVector()
  and flexbuffers::Builder::Map() methods that allow the use of plain function
  pointers.
* Changed Parser to internally use plain function pointers when parsing table
  and vector delimiters.
* Added specializations of NumToString() for 64-bit types that aren't supported
  by stringstream in stlport.
* Overloaded numeric_limits for 64-bit types not supported by stlport.
* Replaced build_apk.sh (which was broken by deprecation of the
  "android" tool in the Android SDK) with build.gradle and the
  appropriate gradle wrapper to build an APK.
* Switched Android build to build against all STL variants.
* Updated travis configuration to build Android test and sample.

Tested:
* Verified all tests continue to work on Linux, OSX and Android.
* Verified Travis build is green.

Change-Id: I9e634363793f85b9f141d21454b10686020a2065
This commit is contained in:
Stewart Miles
2017-07-13 06:27:39 -07:00
parent 2e2063cbeb
commit a892322203
41 changed files with 1445 additions and 1246 deletions

Binary file not shown.

View File

@@ -18,6 +18,18 @@
"properties" : {
}
},
"MyGame_OtherNameSpace_TableB" : {
"type" : "object",
"properties" : {
"a" : { "$ref" : "#/definitions/TableA" }
}
},
"TableA" : {
"type" : "object",
"properties" : {
"b" : { "$ref" : "#/definitions/MyGame_OtherNameSpace_TableB" }
}
},
"MyGame_Example2_Monster" : {
"type" : "object",
"properties" : {

View File

@@ -137,6 +137,7 @@ struct AnyUnion {
void Reset();
#ifndef FLATBUFFERS_CPP98_STL
template <typename T>
void Set(T&& val) {
Reset();
@@ -145,6 +146,7 @@ struct AnyUnion {
value = new T(std::forward<T>(val));
}
}
#endif // FLATBUFFERS_CPP98_STL
static void *UnPack(const void *obj, Any type, const flatbuffers::resolver_function_t *resolver);
flatbuffers::Offset<void> Pack(flatbuffers::FlatBufferBuilder &_fbb, const flatbuffers::rehasher_function_t *_rehasher = nullptr) const;
@@ -516,7 +518,7 @@ flatbuffers::Offset<Stat> CreateStat(flatbuffers::FlatBufferBuilder &_fbb, const
struct MonsterT : public flatbuffers::NativeTable {
typedef Monster TableType;
std::unique_ptr<Vec3> pos;
flatbuffers::unique_ptr<Vec3> pos;
int16_t mana;
int16_t hp;
std::string name;
@@ -525,10 +527,10 @@ struct MonsterT : public flatbuffers::NativeTable {
AnyUnion test;
std::vector<Test> test4;
std::vector<std::string> testarrayofstring;
std::vector<std::unique_ptr<MonsterT>> testarrayoftables;
std::unique_ptr<MonsterT> enemy;
std::vector<flatbuffers::unique_ptr<MonsterT>> testarrayoftables;
flatbuffers::unique_ptr<MonsterT> enemy;
std::vector<uint8_t> testnestedflatbuffer;
std::unique_ptr<StatT> testempty;
flatbuffers::unique_ptr<StatT> testempty;
bool testbool;
int32_t testhashs32_fnv1;
uint32_t testhashu32_fnv1;
@@ -1134,6 +1136,7 @@ inline flatbuffers::Offset<Monster> Monster::Pack(flatbuffers::FlatBufferBuilder
inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
(void)_rehasher;
(void)_o;
struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MonsterT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
return MyGame::Example2::CreateMonster(
_fbb);
}
@@ -1161,6 +1164,7 @@ inline flatbuffers::Offset<TestSimpleTableWithEnum> TestSimpleTableWithEnum::Pac
inline flatbuffers::Offset<TestSimpleTableWithEnum> CreateTestSimpleTableWithEnum(flatbuffers::FlatBufferBuilder &_fbb, const TestSimpleTableWithEnumT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
(void)_rehasher;
(void)_o;
struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const TestSimpleTableWithEnumT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
auto _color = _o->color;
return MyGame::Example::CreateTestSimpleTableWithEnum(
_fbb,
@@ -1188,6 +1192,7 @@ inline flatbuffers::Offset<Stat> Stat::Pack(flatbuffers::FlatBufferBuilder &_fbb
inline flatbuffers::Offset<Stat> CreateStat(flatbuffers::FlatBufferBuilder &_fbb, const StatT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
(void)_rehasher;
(void)_o;
struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const StatT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
auto _id = _o->id.size() ? _fbb.CreateString(_o->id) : 0;
auto _val = _o->val;
auto _count = _o->count;
@@ -1207,7 +1212,7 @@ inline MonsterT *Monster::UnPack(const flatbuffers::resolver_function_t *_resolv
inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function_t *_resolver) const {
(void)_o;
(void)_resolver;
{ auto _e = pos(); if (_e) _o->pos = std::unique_ptr<Vec3>(new Vec3(*_e)); };
{ auto _e = pos(); if (_e) _o->pos = flatbuffers::unique_ptr<Vec3>(new Vec3(*_e)); };
{ auto _e = mana(); _o->mana = _e; };
{ auto _e = hp(); _o->hp = _e; };
{ auto _e = name(); if (_e) _o->name = _e->str(); };
@@ -1217,10 +1222,10 @@ inline void Monster::UnPackTo(MonsterT *_o, const flatbuffers::resolver_function
{ auto _e = test(); if (_e) _o->test.value = AnyUnion::UnPack(_e, test_type(), _resolver); };
{ auto _e = test4(); if (_e) { _o->test4.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->test4[_i] = *_e->Get(_i); } } };
{ auto _e = testarrayofstring(); if (_e) { _o->testarrayofstring.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayofstring[_i] = _e->Get(_i)->str(); } } };
{ auto _e = testarrayoftables(); if (_e) { _o->testarrayoftables.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayoftables[_i] = std::unique_ptr<MonsterT>(_e->Get(_i)->UnPack(_resolver)); } } };
{ auto _e = enemy(); if (_e) _o->enemy = std::unique_ptr<MonsterT>(_e->UnPack(_resolver)); };
{ auto _e = testarrayoftables(); if (_e) { _o->testarrayoftables.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testarrayoftables[_i] = flatbuffers::unique_ptr<MonsterT>(_e->Get(_i)->UnPack(_resolver)); } } };
{ auto _e = enemy(); if (_e) _o->enemy = flatbuffers::unique_ptr<MonsterT>(_e->UnPack(_resolver)); };
{ auto _e = testnestedflatbuffer(); if (_e) { _o->testnestedflatbuffer.resize(_e->size()); for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->testnestedflatbuffer[_i] = _e->Get(_i); } } };
{ auto _e = testempty(); if (_e) _o->testempty = std::unique_ptr<StatT>(_e->UnPack(_resolver)); };
{ auto _e = testempty(); if (_e) _o->testempty = flatbuffers::unique_ptr<StatT>(_e->UnPack(_resolver)); };
{ auto _e = testbool(); _o->testbool = _e; };
{ auto _e = testhashs32_fnv1(); _o->testhashs32_fnv1 = _e; };
{ auto _e = testhashu32_fnv1(); _o->testhashu32_fnv1 = _e; };
@@ -1246,6 +1251,7 @@ inline flatbuffers::Offset<Monster> Monster::Pack(flatbuffers::FlatBufferBuilder
inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder &_fbb, const MonsterT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
(void)_rehasher;
(void)_o;
struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MonsterT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
auto _pos = _o->pos ? _o->pos.get() : 0;
auto _mana = _o->mana;
auto _hp = _o->hp;
@@ -1256,7 +1262,7 @@ inline flatbuffers::Offset<Monster> CreateMonster(flatbuffers::FlatBufferBuilder
auto _test = _o->test.Pack(_fbb);
auto _test4 = _o->test4.size() ? _fbb.CreateVectorOfStructs(_o->test4) : 0;
auto _testarrayofstring = _o->testarrayofstring.size() ? _fbb.CreateVectorOfStrings(_o->testarrayofstring) : 0;
auto _testarrayoftables = _o->testarrayoftables.size() ? _fbb.CreateVector<flatbuffers::Offset<Monster>>(_o->testarrayoftables.size(), [&](size_t i) { return CreateMonster(_fbb, _o->testarrayoftables[i].get(), _rehasher); }) : 0;
auto _testarrayoftables = _o->testarrayoftables.size() ? _fbb.CreateVector<flatbuffers::Offset<Monster>> (_o->testarrayoftables.size(), [](size_t i, _VectorArgs *__va) { return CreateMonster(*__va->__fbb, __va->__o->testarrayoftables[i].get(), __va->__rehasher); }, &_va ) : 0;
auto _enemy = _o->enemy ? CreateMonster(_fbb, _o->enemy.get(), _rehasher) : 0;
auto _testnestedflatbuffer = _o->testnestedflatbuffer.size() ? _fbb.CreateVector(_o->testnestedflatbuffer) : 0;
auto _testempty = _o->testempty ? CreateStat(_fbb, _o->testempty.get(), _rehasher) : 0;
@@ -1452,10 +1458,10 @@ inline void FinishMonsterBuffer(
fbb.Finish(root, MonsterIdentifier());
}
inline std::unique_ptr<MonsterT> UnPackMonster(
inline flatbuffers::unique_ptr<MonsterT> UnPackMonster(
const void *buf,
const flatbuffers::resolver_function_t *res = nullptr) {
return std::unique_ptr<MonsterT>(GetMonster(buf)->UnPack(res));
return flatbuffers::unique_ptr<MonsterT>(GetMonster(buf)->UnPack(res));
}
} // namespace Example

View File

@@ -121,12 +121,13 @@ flatbuffers::DetachedBuffer CreateFlatBufferTest(std::string &buffer) {
mlocs[2] = mb3.Finish();
// 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]);
});
[](size_t i, flatbuffers::FlatBufferBuilder *b)
-> flatbuffers::Offset<flatbuffers::String> {
static const char *names[] = { "bob", "fred", "bob", "fred" };
return b->CreateSharedString(names[i]);
}, &builder);
// Creating vectors of strings in one convenient call.
std::vector<std::string> names2;
@@ -541,7 +542,7 @@ void ParseAndGenerateTextTest() {
TEST_EQ(result, true);
if (jsongen != jsonfile) {
printf("%s----------------\n%s", jsongen.c_str(), jsonfile.c_str());
TEST_OUTPUT_LINE("%s----------------\n%s", jsongen.c_str(), jsonfile.c_str());
TEST_NOTNULL(NULL);
}
@@ -671,8 +672,8 @@ void ReflectionTest(uint8_t *flatbuf, size_t length) {
// Get the root.
// This time we wrap the result from GetAnyRoot in a smartpointer that
// will keep rroot valid as resizingbuf resizes.
auto rroot = flatbuffers::piv(flatbuffers::GetAnyRoot(resizingbuf.data()),
resizingbuf);
auto rroot = flatbuffers::piv(flatbuffers::GetAnyRoot(
flatbuffers::vector_data(resizingbuf)), resizingbuf);
SetString(schema, "totally new string", GetFieldS(**rroot, name_field),
&resizingbuf);
// Here resizingbuf has changed, but rroot is still valid.
@@ -718,12 +719,14 @@ void ReflectionTest(uint8_t *flatbuf, size_t length) {
TEST_EQ_STR(rtestarrayofstring->Get(2)->c_str(), "hank");
// Test integrity of all resize operations above.
flatbuffers::Verifier resize_verifier(
reinterpret_cast<const uint8_t *>(resizingbuf.data()),
reinterpret_cast<const uint8_t *>(
flatbuffers::vector_data(resizingbuf)),
resizingbuf.size());
TEST_EQ(VerifyMonsterBuffer(resize_verifier), true);
// Test buffer is valid using reflection as well
TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(), resizingbuf.data(),
TEST_EQ(flatbuffers::Verify(schema, *schema.root_table(),
flatbuffers::vector_data(resizingbuf),
resizingbuf.size()), true);
// As an additional test, also set it on the name field.
@@ -778,7 +781,7 @@ void ParseProtoTest() {
TEST_EQ(parser2.Parse(fbs.c_str(), nullptr), true);
if (fbs != goldenfile) {
printf("%s----------------\n%s", fbs.c_str(), goldenfile.c_str());
TEST_OUTPUT_LINE("%s----------------\n%s", fbs.c_str(), goldenfile.c_str());
TEST_NOTNULL(NULL);
}
}
@@ -1039,17 +1042,17 @@ void FuzzTest2() {
i -= std::min(static_cast<size_t>(10), i); // show some context;
size_t end = std::min(len, i + 20);
for (; i < end; i++)
printf("at %d: found \"%c\", expected \"%c\"\n",
static_cast<int>(i), jsongen[i], json[i]);
TEST_OUTPUT_LINE("at %d: found \"%c\", expected \"%c\"\n",
static_cast<int>(i), jsongen[i], json[i]);
break;
}
}
TEST_NOTNULL(NULL);
}
printf("%dk schema tested with %dk of json\n",
static_cast<int>(schema.length() / 1024),
static_cast<int>(json.length() / 1024));
TEST_OUTPUT_LINE("%dk schema tested with %dk of json\n",
static_cast<int>(schema.length() / 1024),
static_cast<int>(json.length() / 1024));
}
// Test that parser errors are actually generated.
@@ -1526,18 +1529,20 @@ void ConformTest() {
flatbuffers::Parser parser;
TEST_EQ(parser.Parse("table T { A:int; } enum E:byte { A }"), true);
auto test_conform = [&](const char *test, const char *expected_err) {
auto test_conform = [](flatbuffers::Parser &parser1,
const char *test, const char *expected_err) {
flatbuffers::Parser parser2;
TEST_EQ(parser2.Parse(test), true);
auto err = parser2.ConformTo(parser);
auto err = parser2.ConformTo(parser1);
TEST_NOTNULL(strstr(err.c_str(), expected_err));
};
test_conform("table T { A:byte; }", "types differ for field");
test_conform("table T { B:int; A:int; }", "offsets differ for field");
test_conform("table T { A:int = 1; }", "defaults differ for field");
test_conform("table T { B:float; }", "field renamed to different type");
test_conform("enum E:byte { B, A }", "values differ for enum");
test_conform(parser, "table T { A:byte; }", "types differ for field");
test_conform(parser, "table T { B:int; A:int; }", "offsets differ for field");
test_conform(parser, "table T { A:int = 1; }", "defaults differ for field");
test_conform(parser, "table T { B:float; }",
"field renamed to different type");
test_conform(parser, "enum E:byte { B, A }", "values differ for enum");
}
void ParseProtoBufAsciiTest() {
@@ -1566,6 +1571,8 @@ void FlexBuffersTest() {
// Write the equivalent of:
// { vec: [ -100, "Fred", 4.0 ], bar: [ 1, 2, 3 ], foo: 100 }
#ifndef FLATBUFFERS_CPP98_STL
// It's possible to do this without std::function support as well.
slb.Map([&]() {
slb.Vector("vec", [&]() {
slb += -100; // Equivalent to slb.Add(-100) or slb.Int(-100);
@@ -1581,9 +1588,27 @@ void FlexBuffersTest() {
});
});
slb.Finish();
#else
// It's possible to do this without std::function support as well.
slb.Map([](flexbuffers::Builder& slb2) {
slb2.Vector("vec", [](flexbuffers::Builder& slb3) {
slb3 += -100; // Equivalent to slb.Add(-100) or slb.Int(-100);
slb3 += "Fred";
slb3.IndirectFloat(4.0f);
}, slb2);
int ints[] = { 1, 2, 3 };
slb2.Vector("bar", ints, 3);
slb2.FixedTypedVector("bar3", ints, 3);
slb2.Double("foo", 100);
slb2.Map("mymap", [](flexbuffers::Builder& slb3) {
slb3.String("foo", "Fred"); // Testing key and string reuse.
}, slb2);
}, slb);
slb.Finish();
#endif // FLATBUFFERS_CPP98_STL
for (size_t i = 0; i < slb.GetBuffer().size(); i++)
printf("%d ", slb.GetBuffer().data()[i]);
printf("%d ", flatbuffers::vector_data(slb.GetBuffer())[i]);
printf("\n");
auto map = flexbuffers::GetRoot(slb.GetBuffer()).AsMap();
@@ -1641,7 +1666,11 @@ int main(int /*argc*/, const char * /*argv*/[]) {
std::string rawbuf;
auto flatbuf1 = CreateFlatBufferTest(rawbuf);
#if !defined(FLATBUFFERS_CPP98_STL)
auto flatbuf = std::move(flatbuf1); // Test move assignment.
#else
auto &flatbuf = flatbuf1;
#endif // !defined(FLATBUFFERS_CPP98_STL)
AccessFlatBufferTest(reinterpret_cast<const uint8_t *>(rawbuf.c_str()),
rawbuf.length());
AccessFlatBufferTest(flatbuf.data(), flatbuf.size());
@@ -1692,4 +1721,3 @@ int main(int /*argc*/, const char * /*argv*/[]) {
return 1;
}
}

View File

@@ -364,6 +364,7 @@ inline flatbuffers::Offset<Attacker> Attacker::Pack(flatbuffers::FlatBufferBuild
inline flatbuffers::Offset<Attacker> CreateAttacker(flatbuffers::FlatBufferBuilder &_fbb, const AttackerT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
(void)_rehasher;
(void)_o;
struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const AttackerT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
auto _sword_attack_damage = _o->sword_attack_damage;
return CreateAttacker(
_fbb,
@@ -392,10 +393,11 @@ inline flatbuffers::Offset<Movie> Movie::Pack(flatbuffers::FlatBufferBuilder &_f
inline flatbuffers::Offset<Movie> CreateMovie(flatbuffers::FlatBufferBuilder &_fbb, const MovieT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
(void)_rehasher;
(void)_o;
struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MovieT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
auto _main_character_type = _o->main_character.type;
auto _main_character = _o->main_character.Pack(_fbb);
auto _characters_type = _o->characters.size() ? _fbb.CreateVector<uint8_t>(_o->characters.size(), [&](size_t i) { return static_cast<uint8_t>(_o->characters[i].type); }) : 0;
auto _characters = _o->characters.size() ? _fbb.CreateVector<flatbuffers::Offset<void>>(_o->characters.size(), [&](size_t i) { return _o->characters[i].Pack(_fbb, _rehasher); }) : 0;
auto _characters_type = _o->characters.size() ? _fbb.CreateVector<uint8_t>(_o->characters.size(), [](size_t i, _VectorArgs *__va) { return static_cast<uint8_t>(__va->__o->characters[i].type); }, &_va) : 0;
auto _characters = _o->characters.size() ? _fbb.CreateVector<flatbuffers::Offset<void>>(_o->characters.size(), [](size_t i, _VectorArgs *__va) { return __va->__o->characters[i].Pack(*__va->__fbb, __va->__rehasher); }, &_va) : 0;
return CreateMovie(
_fbb,
_main_character_type,
@@ -602,10 +604,10 @@ inline void FinishMovieBuffer(
fbb.Finish(root, MovieIdentifier());
}
inline std::unique_ptr<MovieT> UnPackMovie(
inline flatbuffers::unique_ptr<MovieT> UnPackMovie(
const void *buf,
const flatbuffers::resolver_function_t *res = nullptr) {
return std::unique_ptr<MovieT>(GetMovie(buf)->UnPack(res));
return flatbuffers::unique_ptr<MovieT>(GetMovie(buf)->UnPack(res));
}
#endif // FLATBUFFERS_GENERATED_UNIONVECTOR_H_