Add CodeWriter utility class.

Helps simplify code generation code.  Instead of this:
  code += "inline const " + cpp_qualified_name + " *Get";
  code += name;
  code += "(const void *buf) {\n  return flatbuffers::GetRoot<";
  code += cpp_qualified_name + ">(buf);\n}\n\n";

You do this:
  code.SetValue("NAME", struct_def.name);
  code.SetValue("CPP_NAME", cpp_qualified_name);
  code += "inline const {{CPP_NAME}} *Get{{NAME}}(const void *buf) {";
  code += "  return flatbuffers::GetRoot<{{CPP_NAME}}>(buf);";
  code += "}";
  code += "";

Updated the CPP code generator to use the CodeWriter class.  Most of the
changes in the generated code are white-space changes, esp. around new
lines (since the code generator class automatically appends new lines
when appending a string).  Actual code changes include:

* Renamed "rehasher" to "_rehasher" for consistency with other args in
  Pack function.

* Renamed "union_obj" to "obj: in UnPack function.

* Always do "(void)_o;" to prevent unused variable warning in Create
  function (instead of only doing it if there are no fields) in order
  to avoid two-passes.

* Renamed padding variables from __paddingX to paddingX__.
  "Each name that contains a double underscore (_ _) [...] is reserved
   to the implementation for any use."  C++ standards 17.4.3.1.2.

* Add braces around switch cases.

* Calculate index as a separate statement in EnumName function, eg.
    const size_t index = ...;
    return EnumNamesX()[index];
  vs.
    return EnumNamesX()[...];

* Stored end table offset in variable in Finish() functions, eg.
    const auto end = fbb_.EndTable(start_, ...);
    auto o = flatbuffers::Offset<T>(end);
  vs.
    auto o = flatbuffers::Offset<T>(fbb_.EndTable(start, ...));

* Separate reinterpret_cast calls from function calls in Union
  functions, eg.
    auto ptr = reinterpret_cast<const T *>(obj);
    return ptr->UnPack(resolver);
  vs.
    return reinterpret_cast<const T *>(obj)->UnPack(resolver);

* Removed unecessary (void)(padding__X) no-ops from constructors, eg.
    Test(int16_t a, int8_t b) : ... {
      (void)__padding0;  // <-- Removed this line.
    }

In the idl_gen_cpp.cpp file itself, I refactored some code generation into
new functions: GenParam, GenNativeTable, GenVerifyCall, GenBuilders,
GenUnpackFieldStatement, and GenCreateParam.

Change-Id: I727b1bd8719d05b7ce33cbce00eb58fda817b25d
parent 1a21b545
......@@ -30,6 +30,7 @@ set(FlatBuffers_Library_SRCS
include/flatbuffers/util.h
include/flatbuffers/reflection.h
include/flatbuffers/reflection_generated.h
src/code_generators.cpp
src/idl_parser.cpp
src/idl_gen_text.cpp
src/reflection.cpp
......@@ -62,7 +63,6 @@ set(FlatHash_SRCS
set(FlatBuffers_Tests_SRCS
${FlatBuffers_Library_SRCS}
src/idl_gen_fbs.cpp
src/idl_gen_general.cpp
tests/test.cpp
# file generate by running compiler on tests/monster_test.fbs
${CMAKE_CURRENT_BINARY_DIR}/tests/monster_test_generated.h
......@@ -76,13 +76,7 @@ set(FlatBuffers_Sample_Binary_SRCS
)
set(FlatBuffers_Sample_Text_SRCS
include/flatbuffers/flatbuffers.h
include/flatbuffers/hash.h
include/flatbuffers/idl.h
include/flatbuffers/util.h
src/idl_parser.cpp
src/idl_gen_text.cpp
src/util.cpp
${FlatBuffers_Library_SRCS}
samples/sample_text.cpp
# file generated by running compiler on samples/monster.fbs
${CMAKE_CURRENT_BINARY_DIR}/samples/monster_generated.h
......
......@@ -17,25 +17,63 @@
#ifndef FLATBUFFERS_CODE_GENERATORS_H_
#define FLATBUFFERS_CODE_GENERATORS_H_
#include <map>
#include <sstream>
#include "flatbuffers/idl.h"
namespace flatbuffers {
// Utility class to assist in generating code through use of text templates.
//
// Example code:
// CodeWriter code;
// code.SetValue("NAME", "Foo");
// code += "void {{NAME}}() { printf("%s", "{{NAME}}"); }";
// code.SetValue("NAME", "Bar");
// code += "void {{NAME}}() { printf("%s", "{{NAME}}"); }";
// std::cout << code.ToString() << std::endl;
//
// Output:
// void Foo() { printf("%s", "Foo"); }
// void Bar() { printf("%s", "Bar"); }
class CodeWriter {
public:
CodeWriter() {}
// Clears the current "written" code.
void Clear() {
stream_.str("");
stream_.clear();
}
// Associates a key with a value. All subsequent calls to operator+=, where
// the specified key is contained in {{ and }} delimiters will be replaced by
// the given value.
void SetValue(const std::string& key, const std::string& value) {
value_map_[key] = value;
}
// Appends the given text to the generated code as well as a newline
// character. Any text within {{ and }} delimeters is replaced by values
// previously stored in the CodeWriter by calling SetValue above. The newline
// will be suppressed if the text ends with the \\ character.
void operator+=(std::string text);
// Returns the current contents of the CodeWriter as a std::string.
std::string ToString() const { return stream_.str(); }
private:
std::map<std::string, std::string> value_map_;
std::stringstream stream_;
};
class BaseGenerator {
public:
virtual bool generate() = 0;
static std::string NamespaceDir(const Parser &parser,
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 = ns.components;
for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
namespace_dir += *it + kPathSeparator;
EnsureDirExists(namespace_dir.c_str());
}
return namespace_dir;
}
const Namespace &ns);
protected:
BaseGenerator(const Parser &parser, const std::string &path,
......@@ -53,43 +91,15 @@ class BaseGenerator {
BaseGenerator &operator=(const BaseGenerator &);
BaseGenerator(const BaseGenerator &);
std::string NamespaceDir(const Namespace &ns) const {
return BaseGenerator::NamespaceDir(parser_, path_, ns);
}
std::string NamespaceDir(const Namespace &ns) const;
const char *FlatBuffersGeneratedWarning() {
return "automatically generated by the FlatBuffers compiler,"
" do not modify\n\n";
}
static const char *FlatBuffersGeneratedWarning();
bool IsEverythingGenerated() const {
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
++it) {
if (!(*it)->generated) return false;
}
for (auto it = parser_.structs_.vec.begin();
it != parser_.structs_.vec.end(); ++it) {
if (!(*it)->generated) return false;
}
return true;
}
bool IsEverythingGenerated() const;
static std::string FullNamespace(const char *separator, const Namespace &ns) {
std::string namespace_name;
auto &namespaces = ns.components;
for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
if (namespace_name.length()) namespace_name += separator;
namespace_name += *it;
}
return namespace_name;
}
static std::string FullNamespace(const char *separator, const Namespace &ns);
static std::string LastNamespacePart(const Namespace &ns) {
if (!ns.components.empty())
return ns.components.back();
else
return std::string("");
}
static std::string LastNamespacePart(const Namespace &ns);
// tracks the current namespace for early exit in WrapInNameSpace
// c++, java and csharp returns a different namespace from
......@@ -100,17 +110,9 @@ class BaseGenerator {
// 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) const {
if (CurrentNameSpace() == ns) return name;
std::string qualified_name = qualifying_start_;
for (auto it = ns->components.begin(); it != ns->components.end(); ++it)
qualified_name += *it + qualifying_separator_;
return qualified_name + name;
}
const std::string &name) const;
std::string WrapInNameSpace(const Definition &def) const {
return WrapInNameSpace(def.defined_namespace, def.name);
}
std::string WrapInNameSpace(const Definition &def) const;
const Parser &parser_;
const std::string &path_;
......@@ -119,6 +121,17 @@ class BaseGenerator {
const std::string qualifying_separator_;
};
struct CommentConfig {
const char *first_line;
const char *content_line_prefix;
const char *last_line;
};
extern void GenComment(const std::vector<std::string> &dc,
std::string *code_ptr,
const CommentConfig *config,
const char *prefix = "");
} // namespace flatbuffers
#endif // FLATBUFFERS_CODE_GENERATORS_H_
......@@ -592,13 +592,6 @@ private:
extern std::string MakeCamel(const std::string &in, bool first = true);
struct CommentConfig;
extern void GenComment(const std::vector<std::string> &dc,
std::string *code_ptr,
const CommentConfig *config,
const char *prefix = "");
// Generate text (JSON) from a given FlatBuffer, and a given Parser
// object that has been populated with the corresponding schema.
// If ident_step is 0, no indentation will be generated. Additionally,
......
This diff is collapsed.
This diff is collapsed.
/*
* Copyright 2016 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "flatbuffers/code_generators.h"
#include <assert.h>
#include "flatbuffers/util.h"
namespace flatbuffers {
void CodeWriter::operator+=(std::string text) {
while (true) {
auto begin = text.find("{{");
if (begin == std::string::npos) {
break;
}
auto end = text.find("}}");
if (end == std::string::npos || end < begin) {
break;
}
// Write all the text before the first {{ into the stream.
stream_.write(text.c_str(), begin);
// The key is between the {{ and }}.
const std::string key = text.substr(begin + 2, end - begin - 2);
// Find the value associated with the key. If it exists, write the
// value into the stream, otherwise write the key itself into the stream.
auto iter = value_map_.find(key);
if (iter != value_map_.end()) {
const std::string &value = iter->second;
stream_ << value;
} else {
assert(false && "could not find key");
stream_ << key;
}
// Update the text to everything after the }}.
text = text.substr(end + 2);
}
if (!text.empty() && text.back() == '\\') {
text.pop_back();
stream_ << text;
} else {
stream_ << text << std::endl;
}
}
const char *BaseGenerator::FlatBuffersGeneratedWarning() {
return "automatically generated by the FlatBuffers compiler,"
" do not modify\n\n";
}
std::string BaseGenerator::NamespaceDir(const Parser &parser,
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 = ns.components;
for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
namespace_dir += *it + kPathSeparator;
EnsureDirExists(namespace_dir.c_str());
}
return namespace_dir;
}
std::string BaseGenerator::NamespaceDir(const Namespace &ns) const {
return BaseGenerator::NamespaceDir(parser_, path_, ns);
}
bool BaseGenerator::IsEverythingGenerated() const {
for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
++it) {
if (!(*it)->generated) return false;
}
for (auto it = parser_.structs_.vec.begin();
it != parser_.structs_.vec.end(); ++it) {
if (!(*it)->generated) return false;
}
return true;
}
std::string BaseGenerator::FullNamespace(const char *separator,
const Namespace &ns) {
std::string namespace_name;
auto &namespaces = ns.components;
for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
if (namespace_name.length()) namespace_name += separator;
namespace_name += *it;
}
return namespace_name;
}
std::string BaseGenerator::LastNamespacePart(const Namespace &ns) {
if (!ns.components.empty())
return ns.components.back();
else
return std::string("");
}
// Ensure that a type is prefixed with its namespace whenever it is used
// outside of its namespace.
std::string BaseGenerator::WrapInNameSpace(const Namespace *ns,
const std::string &name) const {
if (CurrentNameSpace() == ns) return name;
std::string qualified_name = qualifying_start_;
for (auto it = ns->components.begin(); it != ns->components.end(); ++it)
qualified_name += *it + qualifying_separator_;
return qualified_name + name;
}
std::string BaseGenerator::WrapInNameSpace(const Definition &def) const {
return WrapInNameSpace(def.defined_namespace, def.name);
}
// Generate a documentation comment, if available.
void GenComment(const std::vector<std::string> &dc, std::string *code_ptr,
const CommentConfig *config, const char *prefix) {
if (dc.begin() == dc.end()) {
// Don't output empty comment blocks with 0 lines of comment content.
return;
}
std::string &code = *code_ptr;
if (config != nullptr && config->first_line != nullptr) {
code += std::string(prefix) + std::string(config->first_line) + "\n";
}
std::string line_prefix = std::string(prefix) +
((config != nullptr && config->content_line_prefix != nullptr) ?
config->content_line_prefix : "///");
for (auto it = dc.begin();
it != dc.end();
++it) {
code += line_prefix + *it + "\n";
}
if (config != nullptr && config->last_line != nullptr) {
code += std::string(prefix) + std::string(config->last_line) + "\n";
}
}
} // namespace flatbuffers
This diff is collapsed.
......@@ -19,6 +19,7 @@
#include "flatbuffers/flatbuffers.h"
#include "flatbuffers/idl.h"
#include "flatbuffers/util.h"
#include "flatbuffers/code_generators.h"
namespace flatbuffers {
......
......@@ -39,37 +39,6 @@ std::string MakeCamel(const std::string &in, bool first) {
return s;
}
struct CommentConfig {
const char *first_line;
const char *content_line_prefix;
const char *last_line;
};
// Generate a documentation comment, if available.
void GenComment(const std::vector<std::string> &dc, std::string *code_ptr,
const CommentConfig *config, const char *prefix) {
if (dc.begin() == dc.end()) {
// Don't output empty comment blocks with 0 lines of comment content.
return;
}
std::string &code = *code_ptr;
if (config != nullptr && config->first_line != nullptr) {
code += std::string(prefix) + std::string(config->first_line) + "\n";
}
std::string line_prefix = std::string(prefix) +
((config != nullptr && config->content_line_prefix != nullptr) ?
config->content_line_prefix : "///");
for (auto it = dc.begin();
it != dc.end();
++it) {
code += line_prefix + *it + "\n";
}
if (config != nullptr && config->last_line != nullptr) {
code += std::string(prefix) + std::string(config->last_line) + "\n";
}
}
// These arrays need to correspond to the IDLOptions::k enum.
struct LanguageParameters {
......@@ -495,7 +464,7 @@ std::string GenDefaultValue(const Value &value, bool enableLangOverrides) {
switch (value.type.base_type) {
case BASE_TYPE_FLOAT: return value.constant + "f";
case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
case BASE_TYPE_ULONG:
case BASE_TYPE_ULONG:
{
if (lang_.language != IDLOptions::kJava)
return value.constant;
......
This diff is collapsed.
// automatically generated by the FlatBuffers compiler, do not modify
#ifndef FLATBUFFERS_GENERATED_NAMESPACETEST1_NAMESPACEA_NAMESPACEB_H_
#define FLATBUFFERS_GENERATED_NAMESPACETEST1_NAMESPACEA_NAMESPACEB_H_
......@@ -21,11 +22,19 @@ enum EnumInNestedNS {
};
inline const char **EnumNamesEnumInNestedNS() {
static const char *names[] = { "A", "B", "C", nullptr };
static const char *names[] = {
"A",
"B",
"C",
nullptr
};
return names;
}
inline const char *EnumNameEnumInNestedNS(EnumInNestedNS e) { return EnumNamesEnumInNestedNS()[static_cast<int>(e)]; }
inline const char *EnumNameEnumInNestedNS(EnumInNestedNS e) {
const size_t index = static_cast<int>(e);
return EnumNamesEnumInNestedNS()[index];
}
MANUALLY_ALIGNED_STRUCT(4) StructInNestedNS FLATBUFFERS_FINAL_CLASS {
private:
......@@ -33,15 +42,28 @@ MANUALLY_ALIGNED_STRUCT(4) StructInNestedNS FLATBUFFERS_FINAL_CLASS {
int32_t b_;
public:
StructInNestedNS() { memset(this, 0, sizeof(StructInNestedNS)); }
StructInNestedNS(const StructInNestedNS &_o) { memcpy(this, &_o, sizeof(StructInNestedNS)); }
StructInNestedNS() {
memset(this, 0, sizeof(StructInNestedNS));
}
StructInNestedNS(const StructInNestedNS &_o) {
memcpy(this, &_o, sizeof(StructInNestedNS));
}
StructInNestedNS(int32_t _a, int32_t _b)
: a_(flatbuffers::EndianScalar(_a)), b_(flatbuffers::EndianScalar(_b)) { }
int32_t a() const { return flatbuffers::EndianScalar(a_); }
void mutate_a(int32_t _a) { flatbuffers::WriteScalar(&a_, _a); }
int32_t b() const { return flatbuffers::EndianScalar(b_); }
void mutate_b(int32_t _b) { flatbuffers::WriteScalar(&b_, _b); }
: a_(flatbuffers::EndianScalar(_a)),
b_(flatbuffers::EndianScalar(_b)) {
}
int32_t a() const {
return flatbuffers::EndianScalar(a_);
}
void mutate_a(int32_t _a) {
flatbuffers::WriteScalar(&a_, _a);
}
int32_t b() const {
return flatbuffers::EndianScalar(b_);
}
void mutate_b(int32_t _b) {
flatbuffers::WriteScalar(&b_, _b);
}
};
STRUCT_END(StructInNestedNS, 8);
......@@ -49,8 +71,12 @@ struct TableInNestedNS FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
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); }
int32_t foo() const {
return GetField<int32_t>(VT_FOO, 0);
}
bool mutate_foo(int32_t _foo) {
return SetField(VT_FOO, _foo);
}
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyField<int32_t>(verifier, VT_FOO) &&
......@@ -64,15 +90,20 @@ struct TableInNestedNSBuilder {
void add_foo(int32_t foo) {
fbb_.AddElement<int32_t>(TableInNestedNS::VT_FOO, foo, 0);
}
TableInNestedNSBuilder(flatbuffers::FlatBufferBuilder &_fbb) : fbb_(_fbb) { start_ = fbb_.StartTable(); }
TableInNestedNSBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
TableInNestedNSBuilder &operator=(const TableInNestedNSBuilder &);
flatbuffers::Offset<TableInNestedNS> Finish() {
auto o = flatbuffers::Offset<TableInNestedNS>(fbb_.EndTable(start_, 1));
const auto end = fbb_.EndTable(start_, 1);
auto o = flatbuffers::Offset<TableInNestedNS>(end);
return o;
}
};
inline flatbuffers::Offset<TableInNestedNS> CreateTableInNestedNS(flatbuffers::FlatBufferBuilder &_fbb,
inline flatbuffers::Offset<TableInNestedNS> CreateTableInNestedNS(
flatbuffers::FlatBufferBuilder &_fbb,
int32_t foo = 0) {
TableInNestedNSBuilder builder_(_fbb);
builder_.add_foo(foo);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment