Merge pull request #3498 from ncpenke/gcc-4.4.3-support

Gcc 4.4.3 support
This commit is contained in:
Wouter van Oortmerssen 2016-01-19 10:27:57 -08:00
commit 6136dd490a
12 changed files with 166 additions and 90 deletions

View File

@ -33,11 +33,30 @@
#if __cplusplus <= 199711L && \
(!defined(_MSC_VER) || _MSC_VER < 1600) && \
(!defined(__GNUC__) || \
(__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40603))
#error A C++11 compatible compiler is required for FlatBuffers.
(__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 __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.
#ifndef nullptr_t
const class nullptr_t {
public:
template<class T> inline operator T*() const { return 0; }
private:
void operator&() const;
} nullptr = {};
#endif
#ifndef constexpr
#define constexpr const
#endif
#endif
// The wire format uses a little endian encoding (since that's efficient for
// the common platforms).
#if !defined(FLATBUFFERS_LITTLEENDIAN)
@ -154,7 +173,11 @@ template<typename T> size_t AlignOf() {
#ifdef _MSC_VER
return __alignof(T);
#else
return alignof(T);
#ifndef alignof
return __alignof__(T);
#else
return alignof(T);
#endif
#endif
}
@ -836,15 +859,20 @@ class FlatBufferBuilder FLATBUFFERS_FINAL_CLASS {
return CreateVectorOfStructs(v.data(), v.size());
}
template<typename T>
struct TableKeyComparator {
TableKeyComparator(vector_downward& buf) : buf_(buf) {}
bool operator()(const Offset<T> &a, const Offset<T> &b) const {
auto table_a = reinterpret_cast<T *>(buf_.data_at(a.o));
auto table_b = reinterpret_cast<T *>(buf_.data_at(b.o));
return table_a->KeyCompareLessThan(table_b);
}
vector_downward& buf_;
};
template<typename T> Offset<Vector<Offset<T>>> CreateVectorOfSortedTables(
Offset<T> *v, size_t len) {
std::sort(v, v + len,
[this](const Offset<T> &a, const Offset<T> &b) -> bool {
auto table_a = reinterpret_cast<T *>(buf_.data_at(a.o));
auto table_b = reinterpret_cast<T *>(buf_.data_at(b.o));
return table_a->KeyCompareLessThan(table_b);
}
);
std::sort(v, v + len, TableKeyComparator<T>(buf_));
return CreateVector(v, len);
}

View File

@ -20,6 +20,8 @@
#include <cstdint>
#include <cstring>
#include "flatbuffers/flatbuffers.h"
namespace flatbuffers {
template <typename T>
@ -36,8 +38,8 @@ struct FnvTraits<uint32_t> {
template <>
struct FnvTraits<uint64_t> {
static const uint64_t kFnvPrime = 0x00000100000001b3;
static const uint64_t kOffsetBasis = 0xcbf29ce484222645;
static const uint64_t kFnvPrime = 0x00000100000001b3ULL;
static const uint64_t kOffsetBasis = 0xcbf29ce484222645ULL;
};
template <typename T>

View File

@ -491,6 +491,10 @@ private:
FLATBUFFERS_CHECKED_ERROR DoParse(const char *_source,
const char **include_paths,
const char *source_filename);
FLATBUFFERS_CHECKED_ERROR CheckClash(std::vector<FieldDef*> &fields,
StructDef *struct_def,
const char *suffix,
BaseType baseType);
public:
SymbolTable<StructDef> structs_;

View File

@ -38,6 +38,8 @@
#include <limits.h>
#endif
#include "flatbuffers/flatbuffers.h"
namespace flatbuffers {
// Convert an integer or floating point value to a string.
@ -68,7 +70,7 @@ template<> inline std::string NumToString<double>(double t) {
auto p = s.find_last_not_of('0');
if (p != std::string::npos) {
s.resize(p + 1); // Strip trailing zeroes.
if (s.back() == '.')
if (s[s.size() - 1] == '.')
s.erase(s.size() - 1, 1); // Strip '.' if a whole number.
}
return s;
@ -197,8 +199,8 @@ inline std::string StripFileName(const std::string &filepath) {
inline std::string ConCatPathFileName(const std::string &path,
const std::string &filename) {
std::string filepath = path;
if (path.length() && path.back() != kPathSeparator &&
path.back() != kPosixPathSeparator)
if (path.length() && path[path.size() - 1] != kPathSeparator &&
path[path.size() - 1] != kPosixPathSeparator)
filepath += kPathSeparator;
filepath += filename;
return filepath;

View File

@ -65,7 +65,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VT_HP = 8,
VT_NAME = 10,
VT_INVENTORY = 14,
VT_COLOR = 16,
VT_COLOR = 16
};
const Vec3 *pos() const { return GetStruct<const Vec3 *>(VT_POS); }
Vec3 *mutable_pos() { return GetStruct<Vec3 *>(VT_POS); }

View File

@ -17,6 +17,7 @@
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
#include <limits>
static void Error(const std::string &err, bool usage = false,
bool show_exe_name = true);

View File

@ -267,16 +267,24 @@ static void GenTable(const Parser &parser, StructDef &struct_def,
// Generate field id constants.
if (struct_def.fields.vec.size() > 0) {
code += " enum {\n";
bool is_first_field = true; // track the first field that's not deprecated
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end();
++it) {
auto &field = **it;
if (!field.deprecated) { // Deprecated fields won't be accessible.
if (!is_first_field) {
// Add trailing comma and newline to previous element. Don't add trailing comma to
// last element since older versions of gcc complain about this.
code += ",\n";
} else {
is_first_field = false;
}
code += " " + GenFieldOffsetName(field) + " = ";
code += NumToString(field.value.offset) + ",\n";
code += NumToString(field.value.offset);
}
}
code += " };\n";
code += "\n };\n";
}
// Generate the accessors.
for (auto it = struct_def.fields.vec.begin();
@ -513,15 +521,32 @@ static void GenTable(const Parser &parser, StructDef &struct_def,
}
static void GenPadding(const FieldDef &field,
const std::function<void (int bits)> &f) {
std::string &code,
int &padding_id,
const std::function<void (int bits, std::string &code, int &padding_id)> &f) {
if (field.padding) {
for (int i = 0; i < 4; i++)
if (static_cast<int>(field.padding) & (1 << i))
f((1 << i) * 8);
f((1 << i) * 8, code, padding_id);
assert(!(field.padding & ~0xF));
}
}
static void PaddingDefinition(int bits, std::string &code, int &padding_id) {
code += " int" + NumToString(bits) +
"_t __padding" + NumToString(padding_id++) + ";\n";
}
static void PaddingDeclaration(int bits, std::string &code, int &padding_id) {
(void)bits;
code += " (void)__padding" + NumToString(padding_id++) + ";";
}
static void PaddingInitializer(int bits, std::string &code, int &padding_id) {
(void)bits;
code += ", __padding" + NumToString(padding_id++) + "(0)";
}
// Generate an accessor struct with constructor for a flatbuffers struct.
static void GenStruct(const Parser &parser, StructDef &struct_def,
std::string *code_ptr) {
@ -543,10 +568,7 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
auto &field = **it;
code += " " + GenTypeGet(parser, field.value.type, " ", "", " ", false);
code += field.name + "_;\n";
GenPadding(field, [&code, &padding_id](int bits) {
code += " int" + NumToString(bits) +
"_t __padding" + NumToString(padding_id++) + ";\n";
});
GenPadding(field, code, padding_id, PaddingDefinition);
}
// Generate a constructor that takes all fields as arguments.
@ -574,21 +596,16 @@ static void GenStruct(const Parser &parser, StructDef &struct_def,
} else {
code += "_" + field.name + ")";
}
GenPadding(field, [&code, &padding_id](int bits) {
(void)bits;
code += ", __padding" + NumToString(padding_id++) + "(0)";
});
GenPadding(field, code, padding_id, PaddingInitializer);
}
code += " {";
padding_id = 0;
for (auto it = struct_def.fields.vec.begin();
it != struct_def.fields.vec.end();
++it) {
auto &field = **it;
GenPadding(field, [&code, &padding_id](int bits) {
(void)bits;
code += " (void)__padding" + NumToString(padding_id++) + ";";
});
GenPadding(field, code, padding_id, PaddingDeclaration);
}
code += " }\n\n";
@ -642,6 +659,12 @@ void CloseNestedNameSpaces(Namespace *ns, std::string *code_ptr) {
} // namespace cpp
struct IsAlnum {
bool operator()(char c) {
return !isalnum(c);
}
};
// Iterate through all definitions we haven't generate code for (enums, structs,
// and tables) and output them to a single file.
std::string GenerateCPP(const Parser &parser,
@ -712,7 +735,7 @@ std::string GenerateCPP(const Parser &parser,
include_guard_ident.erase(
std::remove_if(include_guard_ident.begin(),
include_guard_ident.end(),
[](char c) { return !isalnum(c); }),
IsAlnum()),
include_guard_ident.end());
std::string include_guard = "FLATBUFFERS_GENERATED_" + include_guard_ident;
include_guard += "_";

View File

@ -1109,6 +1109,33 @@ CheckedError Parser::StartStruct(const std::string &name, StructDef **dest) {
return NoError();
}
CheckedError Parser::CheckClash(std::vector<FieldDef*> &fields,
StructDef *struct_def,
const char *suffix,
BaseType basetype) {
auto len = strlen(suffix);
for (auto it = fields.begin(); it != fields.end(); ++it) {
auto &fname = (*it)->name;
if (fname.length() > len &&
fname.compare(fname.length() - len, len, suffix) == 0 &&
(*it)->value.type.base_type != BASE_TYPE_UTYPE) {
auto field = struct_def->fields.Lookup(
fname.substr(0, fname.length() - len));
if (field && field->value.type.base_type == basetype)
return Error("Field " + fname +
" would clash with generated functions for field " +
field->name);
}
}
return NoError();
}
static bool compareFieldDefs(const FieldDef *a, const FieldDef *b) {
auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str());
auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str());
return a_id < b_id;
}
CheckedError Parser::ParseDecl() {
std::vector<std::string> dc = doc_comment_;
bool fixed = Is(kTokenStruct);
@ -1151,12 +1178,7 @@ CheckedError Parser::ParseDecl() {
"either all fields or no fields must have an 'id' attribute");
// Simply sort by id, then the fields are the same as if no ids had
// been specified.
std::sort(fields.begin(), fields.end(),
[](const FieldDef *a, const FieldDef *b) -> bool {
auto a_id = atoi(a->attributes.Lookup("id")->constant.c_str());
auto b_id = atoi(b->attributes.Lookup("id")->constant.c_str());
return a_id < b_id;
});
std::sort(fields.begin(), fields.end(), compareFieldDefs);
// Verify we have a contiguous set, and reassign vtable offsets.
for (int i = 0; i < static_cast<int>(fields.size()); i++) {
if (i != atoi(fields[i]->attributes.Lookup("id")->constant.c_str()))
@ -1166,34 +1188,13 @@ CheckedError Parser::ParseDecl() {
}
}
}
// Check that no identifiers clash with auto generated fields.
// This is not an ideal situation, but should occur very infrequently,
// and allows us to keep using very readable names for type & length fields
// without inducing compile errors.
auto CheckClash = [&fields, &struct_def, this](const char *suffix,
BaseType basetype) -> CheckedError {
auto len = strlen(suffix);
for (auto it = fields.begin(); it != fields.end(); ++it) {
auto &fname = (*it)->name;
if (fname.length() > len &&
fname.compare(fname.length() - len, len, suffix) == 0 &&
(*it)->value.type.base_type != BASE_TYPE_UTYPE) {
auto field = struct_def->fields.Lookup(
fname.substr(0, fname.length() - len));
if (field && field->value.type.base_type == basetype)
return Error("Field " + fname +
" would clash with generated functions for field " +
field->name);
}
}
return NoError();
};
ECHECK(CheckClash("_type", BASE_TYPE_UNION));
ECHECK(CheckClash("Type", BASE_TYPE_UNION));
ECHECK(CheckClash("_length", BASE_TYPE_VECTOR));
ECHECK(CheckClash("Length", BASE_TYPE_VECTOR));
ECHECK(CheckClash("_byte_vector", BASE_TYPE_STRING));
ECHECK(CheckClash("ByteVector", BASE_TYPE_STRING));
ECHECK(CheckClash(fields, struct_def, "_type", BASE_TYPE_UNION));
ECHECK(CheckClash(fields, struct_def, "Type", BASE_TYPE_UNION));
ECHECK(CheckClash(fields, struct_def, "_length", BASE_TYPE_VECTOR));
ECHECK(CheckClash(fields, struct_def, "Length", BASE_TYPE_VECTOR));
ECHECK(CheckClash(fields, struct_def, "_byte_vector", BASE_TYPE_STRING));
ECHECK(CheckClash(fields, struct_def, "ByteVector", BASE_TYPE_STRING));
EXPECT('}');
return NoError();
}
@ -1235,6 +1236,10 @@ CheckedError Parser::ParseNamespace() {
return NoError();
}
static bool compareEnumVals(const EnumVal *a, const EnumVal* b) {
return a->value < b->value;
}
// Best effort parsing of .proto declarations, with the aim to turn them
// in the closest corresponding FlatBuffer equivalent.
// We parse everything as identifiers instead of keywords, since we don't
@ -1285,9 +1290,8 @@ CheckedError Parser::ParseProtoDecl() {
if (Is(';')) NEXT();
// Protobuf allows them to be specified in any order, so sort afterwards.
auto &v = enum_def->vals.vec;
std::sort(v.begin(), v.end(), [](const EnumVal *a, const EnumVal *b) {
return a->value < b->value;
});
std::sort(v.begin(), v.end(), compareEnumVals);
// Temp: remove any duplicates, as .fbs files can't handle them.
for (auto it = v.begin(); it != v.end(); ) {
if (it != v.begin() && it[0]->value == it[-1]->value) it = v.erase(it);
@ -1735,11 +1739,14 @@ std::set<std::string> Parser::GetIncludedFilesRecursive(
// Schema serialization functionality:
template<typename T> bool compareName(const T* a, const T* b) {
return a->name < b->name;
}
template<typename T> void AssignIndices(const std::vector<T *> &defvec) {
// Pre-sort these vectors, such that we can set the correct indices for them.
auto vec = defvec;
std::sort(vec.begin(), vec.end(),
[](const T *a, const T *b) { return a->name < b->name; });
std::sort(vec.begin(), vec.end(), compareName<T>);
for (int i = 0; i < static_cast<int>(vec.size()); i++) vec[i]->index = i;
}

View File

@ -98,7 +98,7 @@ STRUCT_END(Vec3, 32);
struct TestSimpleTableWithEnum FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
VT_COLOR = 4,
VT_COLOR = 4
};
Color color() const { return static_cast<Color>(GetField<int8_t>(VT_COLOR, 2)); }
bool mutate_color(Color _color) { return SetField(VT_COLOR, static_cast<int8_t>(_color)); }
@ -132,7 +132,7 @@ struct Stat FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
VT_ID = 4,
VT_VAL = 6,
VT_COUNT = 8,
VT_COUNT = 8
};
const flatbuffers::String *id() const { return GetPointer<const flatbuffers::String *>(VT_ID); }
flatbuffers::String *mutable_id() { return GetPointer<flatbuffers::String *>(VT_ID); }
@ -201,7 +201,7 @@ struct Monster FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
VT_TESTHASHU32_FNV1A = 46,
VT_TESTHASHS64_FNV1A = 48,
VT_TESTHASHU64_FNV1A = 50,
VT_TESTARRAYOFBOOLS = 52,
VT_TESTARRAYOFBOOLS = 52
};
const Vec3 *pos() const { return GetStruct<const Vec3 *>(VT_POS); }
Vec3 *mutable_pos() { return GetStruct<Vec3 *>(VT_POS); }

View File

@ -43,7 +43,7 @@ STRUCT_END(StructInNestedNS, 8);
struct TableInNestedNS FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
VT_FOO = 4,
VT_FOO = 4
};
int32_t foo() const { return GetField<int32_t>(VT_FOO, 0); }
bool mutate_foo(int32_t _foo) { return SetField(VT_FOO, _foo); }

View File

@ -22,7 +22,7 @@ struct TableInFirstNS FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
VT_FOO_TABLE = 4,
VT_FOO_ENUM = 6,
VT_FOO_STRUCT = 8,
VT_FOO_STRUCT = 8
};
const NamespaceA::NamespaceB::TableInNestedNS *foo_table() const { return GetPointer<const NamespaceA::NamespaceB::TableInNestedNS *>(VT_FOO_TABLE); }
NamespaceA::NamespaceB::TableInNestedNS *mutable_foo_table() { return GetPointer<NamespaceA::NamespaceB::TableInNestedNS *>(VT_FOO_TABLE); }

View File

@ -478,8 +478,8 @@ void FuzzTest1() {
const uint16_t ushort_val = 0xFEEE;
const int32_t int_val = 0x83333333;
const uint32_t uint_val = 0xFDDDDDDD;
const int64_t long_val = 0x8444444444444444;
const uint64_t ulong_val = 0xFCCCCCCCCCCCCCCC;
const int64_t long_val = 0x8444444444444444LL;
const uint64_t ulong_val = 0xFCCCCCCCCCCCCCCCULL;
const float float_val = 3.14159f;
const double double_val = 3.14159265359;
@ -564,8 +564,28 @@ void FuzzTest2() {
struct RndDef {
std::string instances[instances_per_definition];
// Since we're generating schema and corresponding data in tandem,
// this convenience function adds strings to both at once.
static void Add(RndDef (&definitions_l)[num_definitions],
std::string &schema_l,
const int instances_per_definition_l,
const char *schema_add, const char *instance_add,
int definition) {
schema_l += schema_add;
for (int i = 0; i < instances_per_definition_l; i++)
definitions_l[definition].instances[i] += instance_add;
}
};
#define AddToSchemaAndInstances(schema_add, instance_add) \
RndDef::Add(definitions, schema, instances_per_definition, \
schema_add, instance_add, definition)
#define Dummy() \
RndDef::Add(definitions, schema, instances_per_definition, \
"byte", "1", definition)
RndDef definitions[num_definitions];
// We are going to generate num_definitions, the first
@ -577,17 +597,6 @@ void FuzzTest2() {
// being generated. We generate multiple instances such that when creating
// hierarchy, we get some variety by picking one randomly.
for (int definition = 0; definition < num_definitions; definition++) {
// Since we're generating schema & and corresponding data in tandem,
// this convenience function adds strings to both at once.
auto AddToSchemaAndInstances = [&](const char *schema_add,
const char *instance_add) {
schema += schema_add;
for (int i = 0; i < instances_per_definition; i++)
definitions[definition].instances[i] += instance_add;
};
// Generate a default type if we can't generate something else.
auto Dummy = [&]() { AddToSchemaAndInstances("byte", "1"); };
std::string definition_name = "D" + flatbuffers::NumToString(definition);
bool is_struct = definition < num_struct_definitions;