Squashed 'third_party/flatbuffers/' content from commit acc9990ab

Change-Id: I48550d40d78fea996ebe74e9723a5d1f910de491
git-subtree-dir: third_party/flatbuffers
git-subtree-split: acc9990abd2206491480291b0f85f925110102ea
diff --git a/src/idl_gen_kotlin.cpp b/src/idl_gen_kotlin.cpp
new file mode 100644
index 0000000..3ced7b3
--- /dev/null
+++ b/src/idl_gen_kotlin.cpp
@@ -0,0 +1,1527 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// independent from idl_parser, since this code is not needed for most clients
+
+#include <functional>
+#include <unordered_set>
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+#if defined(FLATBUFFERS_CPP98_STL)
+#include <cctype>
+#endif  // defined(FLATBUFFERS_CPP98_STL)
+
+namespace flatbuffers {
+
+namespace kotlin {
+
+typedef std::map<std::string, std::pair<std::string, std::string> > FbbParamMap;
+static TypedFloatConstantGenerator KotlinFloatGen("Double.", "Float.", "NaN",
+                                                  "POSITIVE_INFINITY",
+                                                  "NEGATIVE_INFINITY");
+
+static const CommentConfig comment_config = {"/**", " *", " */"};
+static const std::string ident_pad = "    ";
+static const char *keywords[] = {
+    "package",  "as",     "typealias", "class",  "this",   "super",
+    "val",      "var",    "fun",       "for",    "null",   "true",
+    "false",    "is",     "in",        "throw",  "return", "break",
+    "continue", "object", "if",        "try",    "else",   "while",
+    "do",       "when",   "interface", "typeof", "Any",    "Character"};
+
+// Escape Keywords
+static std::string Esc(const std::string &name) {
+  for (size_t i = 0; i < sizeof(keywords) / sizeof(keywords[0]); i++) {
+    if (name == keywords[i]) {
+      return MakeCamel(name + "_", false);
+    }
+  }
+
+  return MakeCamel(name, false);
+}
+
+class KotlinGenerator : public BaseGenerator {
+ public:
+  KotlinGenerator(const Parser &parser, const std::string &path,
+                  const std::string &file_name)
+      : BaseGenerator(parser, path, file_name, "", "."),
+        cur_name_space_(nullptr) {}
+
+  KotlinGenerator &operator=(const KotlinGenerator &);
+  bool generate() FLATBUFFERS_OVERRIDE {
+    std::string one_file_code;
+
+    cur_name_space_ = parser_.current_namespace_;
+    for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+         ++it) {
+      CodeWriter enumWriter(ident_pad);
+      auto &enum_def = **it;
+      if (!parser_.opts.one_file) cur_name_space_ = enum_def.defined_namespace;
+      GenEnum(enum_def, enumWriter);
+      if (parser_.opts.one_file) {
+        one_file_code += enumWriter.ToString();
+      } else {
+        if (!SaveType(enum_def.name, *enum_def.defined_namespace,
+                      enumWriter.ToString(), false))
+          return false;
+      }
+    }
+
+    for (auto it = parser_.structs_.vec.begin();
+         it != parser_.structs_.vec.end(); ++it) {
+      CodeWriter structWriter(ident_pad);
+      auto &struct_def = **it;
+      if (!parser_.opts.one_file)
+        cur_name_space_ = struct_def.defined_namespace;
+      GenStruct(struct_def, structWriter);
+      if (parser_.opts.one_file) {
+        one_file_code += structWriter.ToString();
+      } else {
+        if (!SaveType(struct_def.name, *struct_def.defined_namespace,
+                      structWriter.ToString(), true))
+          return false;
+      }
+    }
+
+    if (parser_.opts.one_file) {
+      return SaveType(file_name_, *parser_.current_namespace_, one_file_code,
+                      true);
+    }
+    return true;
+  }
+
+  // Save out the generated code for a single class while adding
+  // declaration boilerplate.
+  bool SaveType(const std::string &defname, const Namespace &ns,
+                const std::string &classcode, bool needs_includes) const {
+    if (!classcode.length()) return true;
+
+    std::string code =
+        "// " + std::string(FlatBuffersGeneratedWarning()) + "\n\n";
+
+    std::string namespace_name = FullNamespace(".", ns);
+    if (!namespace_name.empty()) {
+      code += "package " + namespace_name;
+      code += "\n\n";
+    }
+    if (needs_includes) {
+      code += "import java.nio.*\n";
+      code += "import kotlin.math.sign\n";
+      code += "import com.google.flatbuffers.*\n\n";
+    }
+    code += classcode;
+    auto filename = NamespaceDir(ns) + defname + ".kt";
+    return SaveFile(filename.c_str(), code, false);
+  }
+
+  const Namespace *CurrentNameSpace() const FLATBUFFERS_OVERRIDE {
+    return cur_name_space_;
+  }
+
+  static bool IsEnum(const Type &type) {
+    return type.enum_def != nullptr && IsInteger(type.base_type);
+  }
+
+  static std::string GenTypeBasic(const BaseType &type) {
+    // clang-format off
+        static const char * const kotlin_typename[] = {
+    #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+        CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
+    #KTYPE,
+        FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+    #undef FLATBUFFERS_TD
+        };
+        return kotlin_typename[type];
+
+    }
+
+    std::string GenTypePointer(const Type &type) const {
+        switch (type.base_type) {
+        case BASE_TYPE_STRING:
+            return "String";
+        case BASE_TYPE_VECTOR:
+            return GenTypeGet(type.VectorType());
+        case BASE_TYPE_STRUCT:
+            return WrapInNameSpace(*type.struct_def);
+        default:
+            return "Table";
+        }
+    }
+
+    std::string GenTypeGet(const Type &type) const {
+        return IsScalar(type.base_type) ? GenTypeBasic(type.base_type)
+                                        : GenTypePointer(type);
+    }
+
+    std::string GenEnumDefaultValue(const FieldDef &field) const {
+        auto &value = field.value;
+        FLATBUFFERS_ASSERT(value.type.enum_def);
+        auto &enum_def = *value.type.enum_def;
+        auto enum_val = enum_def.FindByValue(value.constant);
+        return enum_val ? (WrapInNameSpace(enum_def) + "." + enum_val->name)
+                        : value.constant;
+    }
+
+
+     // Generate default values to compare against a default value when
+     // `force_defaults` is `false`.
+     // Main differences are:
+     // - Floats are upcasted to doubles
+     // - Unsigned are casted to signed
+    std::string GenFBBDefaultValue(const FieldDef &field) const {
+        auto out = GenDefaultValue(field, true);
+        // All FlatBufferBuilder default floating point values are doubles
+        if (field.value.type.base_type == BASE_TYPE_FLOAT) {
+            if (out.find("Float") != std::string::npos) {
+                out.replace(0, 5, "Double");
+            }
+        }
+        //Guarantee all values are doubles
+        if (out.back() == 'f')
+            out.pop_back();
+        return out;
+    }
+
+
+    // FlatBufferBuilder only store signed types, so this function
+    // returns a cast for unsigned values
+    std::string GenFBBValueCast(const FieldDef &field) const {
+        if (IsUnsigned(field.value.type.base_type)) {
+            return CastToSigned(field.value.type);
+        }
+        return "";
+    }
+
+    std::string GenDefaultValue(const FieldDef &field,
+                                bool force_signed = false) const {
+        auto &value = field.value;
+        auto base_type = field.value.type.base_type;
+        if (IsFloat(base_type)) {
+            auto val = KotlinFloatGen.GenFloatConstant(field);
+            if (base_type == BASE_TYPE_DOUBLE &&
+                    val.back() == 'f') {
+                val.pop_back();
+            }
+            return val;
+        }
+
+        if (base_type  == BASE_TYPE_BOOL) {
+            return value.constant == "0" ? "false" : "true";
+        }
+
+        std::string suffix = "";
+
+        if (base_type == BASE_TYPE_LONG || !force_signed) {
+            suffix = LiteralSuffix(base_type);
+        }
+        return value.constant + suffix;
+    }
+
+    void GenEnum(EnumDef &enum_def, CodeWriter &writer) const {
+        if (enum_def.generated) return;
+
+        GenerateComment(enum_def.doc_comment, writer, &comment_config);
+
+        writer += "@Suppress(\"unused\")";
+        writer += "@ExperimentalUnsignedTypes";
+        writer += "class " + Esc(enum_def.name) + " private constructor() {";
+        writer.IncrementIdentLevel();
+
+        GenerateCompanionObject(writer, [&](){
+            // Write all properties
+            auto vals = enum_def.Vals();
+            for (auto it = vals.begin(); it != vals.end(); ++it) {
+                auto &ev = **it;
+                auto field_type = GenTypeBasic(enum_def.underlying_type.base_type);
+                auto val = enum_def.ToString(ev);
+                auto suffix = LiteralSuffix(enum_def.underlying_type.base_type);
+                writer.SetValue("name", Esc(ev.name));
+                writer.SetValue("type", field_type);
+                writer.SetValue("val", val + suffix);
+                GenerateComment(ev.doc_comment, writer, &comment_config);
+                writer += "const val {{name}}: {{type}} = {{val}}";
+            }
+
+            // Generate a generate string table for enum values.
+            // Problem is, if values are very sparse that could generate really
+            // big tables. Ideally in that case we generate a map lookup
+            // instead, but for the moment we simply don't output a table at all.
+            auto range = enum_def.Distance();
+            // Average distance between values above which we consider a table
+            // "too sparse". Change at will.
+            static const uint64_t kMaxSparseness = 5;
+            if (range / static_cast<uint64_t>(enum_def.size()) < kMaxSparseness) {
+                GeneratePropertyOneLine(writer, "names", "Array<String>",
+                               [&](){
+                    writer += "arrayOf(\\";
+                    auto val = enum_def.Vals().front();
+                    for (auto it = vals.begin(); it != vals.end(); ++it) {
+                        auto ev = *it;
+                        for (auto k = enum_def.Distance(val, ev); k > 1; --k)
+                            writer += "\"\", \\";
+                        val = ev;
+                        writer += "\"" + (*it)->name + "\"\\";
+                        if (it+1 != vals.end()) {
+                            writer += ", \\";
+                        }
+                    }
+                    writer += ")";
+                });
+                GenerateFunOneLine(writer, "name", "e: Int", "String", [&](){
+                    writer += "names[e\\";
+                    if (enum_def.MinValue()->IsNonZero())
+                        writer += " - " + enum_def.MinValue()->name + ".toInt()\\";
+                    writer += "]";
+                });
+            }
+        });
+        writer.DecrementIdentLevel();
+        writer += "}";
+    }
+
+    // Returns the function name that is able to read a value of the given type.
+    std::string ByteBufferGetter(const Type &type, std::string bb_var_name) const {
+        switch (type.base_type) {
+        case BASE_TYPE_STRING:
+            return "__string";
+        case BASE_TYPE_STRUCT:
+            return "__struct";
+        case BASE_TYPE_UNION:
+            return "__union";
+        case BASE_TYPE_VECTOR:
+            return ByteBufferGetter(type.VectorType(), bb_var_name);
+        case BASE_TYPE_INT:
+        case BASE_TYPE_UINT:
+            return bb_var_name + ".getInt";
+        case BASE_TYPE_SHORT:
+        case BASE_TYPE_USHORT:
+            return bb_var_name + ".getShort";
+        case BASE_TYPE_ULONG:
+        case BASE_TYPE_LONG:
+            return bb_var_name + ".getLong";
+        case BASE_TYPE_FLOAT:
+            return bb_var_name + ".getFloat";
+        case BASE_TYPE_DOUBLE:
+            return bb_var_name + ".getDouble";
+        case BASE_TYPE_CHAR:
+        case BASE_TYPE_UCHAR:
+        case BASE_TYPE_NONE:
+        case BASE_TYPE_UTYPE:
+            return bb_var_name + ".get";
+        case BASE_TYPE_BOOL:
+            return "0.toByte() != " + bb_var_name + ".get";
+        default:
+            return bb_var_name + ".get" + MakeCamel(GenTypeBasic(type.base_type));
+        }
+    }
+
+    std::string ByteBufferSetter(const Type &type) const {
+        if (IsScalar(type.base_type)) {
+            switch (type.base_type) {
+            case BASE_TYPE_INT:
+            case BASE_TYPE_UINT:
+                return "bb.putInt";
+            case BASE_TYPE_SHORT:
+            case BASE_TYPE_USHORT:
+                return "bb.putShort";
+            case BASE_TYPE_ULONG:
+            case BASE_TYPE_LONG:
+                return "bb.putLong";
+            case BASE_TYPE_FLOAT:
+                return "bb.putFloat";
+            case BASE_TYPE_DOUBLE:
+                return "bb.putDouble";
+            case BASE_TYPE_CHAR:
+            case BASE_TYPE_UCHAR:
+            case BASE_TYPE_BOOL:
+            case BASE_TYPE_NONE:
+            case BASE_TYPE_UTYPE:
+                return "bb.put";
+            default:
+                return "bb.put" + MakeCamel(GenTypeBasic(type.base_type));
+            }
+        }
+        return "";
+    }
+
+    // Returns the function name that is able to read a value of the given type.
+    std::string GenLookupByKey(flatbuffers::FieldDef *key_field,
+                               const std::string &bb_var_name,
+                               const char *num = nullptr) const {
+        auto type = key_field->value.type;
+        return ByteBufferGetter(type, bb_var_name) + "(" + GenOffsetGetter(key_field, num) + ")";
+
+    }
+
+    // Returns the method name for use with add/put calls.
+    static std::string GenMethod(const Type &type) {
+        return IsScalar(type.base_type) ? ToSignedType(type)
+                                        : (IsStruct(type) ? "Struct" : "Offset");
+    }
+
+    // Recursively generate arguments for a constructor, to deal with nested
+    // structs.
+    static void GenStructArgs(const StructDef &struct_def, CodeWriter &writer,
+                              const char *nameprefix) {
+        for (auto it = struct_def.fields.vec.begin();
+             it != struct_def.fields.vec.end(); ++it) {
+            auto &field = **it;
+            if (IsStruct(field.value.type)) {
+                // Generate arguments for a struct inside a struct. To ensure
+                // names don't clash, and to make it obvious these arguments are
+                // constructing a nested struct, prefix the name with the field
+                // name.
+                GenStructArgs(*field.value.type.struct_def, writer,
+                              (nameprefix + (field.name + "_")).c_str());
+            } else {
+                writer += std::string(", ") + nameprefix + "\\";
+                writer += MakeCamel(field.name) + ": \\";
+                writer += GenTypeBasic(field.value.type.base_type) + "\\";
+            }
+        }
+    }
+
+    // Recusively generate struct construction statements of the form:
+    // builder.putType(name);
+    // and insert manual padding.
+    static void GenStructBody(const StructDef &struct_def, CodeWriter &writer,
+                              const char *nameprefix) {
+        writer.SetValue("align", NumToString(struct_def.minalign));
+        writer.SetValue("size", NumToString(struct_def.bytesize));
+        writer += "builder.prep({{align}}, {{size}})";
+        auto fields_vec = struct_def.fields.vec;
+        for (auto it = fields_vec.rbegin(); it != fields_vec.rend(); ++it) {
+            auto &field = **it;
+
+            if (field.padding) {
+                writer.SetValue("pad", NumToString(field.padding));
+                writer += "builder.pad({{pad}})";
+            }
+            if (IsStruct(field.value.type)) {
+                GenStructBody(*field.value.type.struct_def, writer,
+                              (nameprefix + (field.name + "_")).c_str());
+            } else {
+                writer.SetValue("type", GenMethod(field.value.type));
+                writer.SetValue("argname", nameprefix +
+                              MakeCamel(field.name, false));
+                writer.SetValue("cast", CastToSigned(field.value.type));
+                writer += "builder.put{{type}}({{argname}}{{cast}})";
+            }
+        }
+    }
+
+    std::string GenByteBufferLength(const char *bb_name) const {
+        std::string bb_len = bb_name;
+        bb_len += ".capacity()";
+        return bb_len;
+    }
+
+    std::string GenOffsetGetter(flatbuffers::FieldDef *key_field,
+                                const char *num = nullptr) const {
+        std::string key_offset = "__offset(" +
+                NumToString(key_field->value.offset) + ", ";
+        if (num) {
+            key_offset += num;
+            key_offset += ", _bb)";
+        } else {
+            key_offset += GenByteBufferLength("bb");
+            key_offset += " - tableOffset, bb)";
+        }
+        return key_offset;
+    }
+
+    void GenStruct(StructDef &struct_def, CodeWriter &writer) const {
+        if (struct_def.generated) return;
+
+        GenerateComment(struct_def.doc_comment, writer, &comment_config);
+        auto fixed = struct_def.fixed;
+
+        writer.SetValue("struct_name", Esc(struct_def.name));
+        writer.SetValue("superclass", fixed ? "Struct" : "Table");
+
+        writer += "@Suppress(\"unused\")";
+        writer += "@ExperimentalUnsignedTypes";
+        writer += "class {{struct_name}} : {{superclass}}() {\n";
+
+        writer.IncrementIdentLevel();
+
+        {
+            // Generate the __init() method that sets the field in a pre-existing
+            // accessor object. This is to allow object reuse.
+            GenerateFun(writer, "__init", "_i: Int, _bb: ByteBuffer", "", [&]() {
+                writer += "__reset(_i, _bb)";
+            });
+
+            // Generate assign method
+            GenerateFun(writer, "__assign", "_i: Int, _bb: ByteBuffer",
+                        Esc(struct_def.name), [&]() {
+                writer += "__init(_i, _bb)";
+                writer += "return this";
+            });
+
+            // Generate all getters
+            GenerateStructGetters(struct_def, writer);
+
+            // Generate Static Fields
+            GenerateCompanionObject(writer, [&](){
+
+                if (!struct_def.fixed) {
+                    FieldDef *key_field = nullptr;
+
+                    // Generate verson check method.
+                    // Force compile time error if not using the same version
+                    // runtime.
+                    GenerateFunOneLine(writer, "validateVersion", "", "", [&](){
+                        writer += "Constants.FLATBUFFERS_1_11_1()";
+                    });
+
+                    GenerateGetRootAsAccessors(Esc(struct_def.name), writer);
+                    GenerateBufferHasIdentifier(struct_def, writer);
+                    GenerateTableCreator(struct_def, writer);
+
+                    GenerateStartStructMethod(struct_def, writer);
+
+                    // Static Add for fields
+                    auto fields = struct_def.fields.vec;
+                    int field_pos = -1;
+                    for (auto it = fields.begin(); it != fields.end(); ++it) {
+                        auto &field = **it;
+                        field_pos++;
+                        if (field.deprecated) continue;
+                        if (field.key) key_field = &field;
+                        GenerateAddField(NumToString(field_pos), field, writer);
+
+                        if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+                            auto vector_type = field.value.type.VectorType();
+                            if (!IsStruct(vector_type)) {
+                                GenerateCreateVectorField(field, writer);
+                            }
+                            GenerateStartVectorField(field, writer);
+                        }
+                    }
+
+                    GenerateEndStructMethod(struct_def, writer);
+                    auto file_identifier = parser_.file_identifier_;
+                    if (parser_.root_struct_def_ == &struct_def) {
+                        GenerateFinishStructBuffer(struct_def,
+                                                   file_identifier,
+                                                   writer);
+                        GenerateFinishSizePrefixed(struct_def,
+                                                   file_identifier,
+                                                   writer);
+                    }
+
+                    if (struct_def.has_key) {
+                        GenerateLookupByKey(key_field, struct_def, writer);
+                    }
+                } else {
+                    GenerateStaticConstructor(struct_def, writer);
+                }
+            });
+        }
+
+        // class closing
+        writer.DecrementIdentLevel();
+        writer += "}";
+    }
+
+    // TODO: move key_field to reference instead of pointer
+    void GenerateLookupByKey(FieldDef *key_field, StructDef &struct_def,
+                             CodeWriter &writer) const {
+        std::stringstream params;
+        params << "obj: " << Esc(struct_def.name) << "?" << ", ";
+        params << "vectorLocation: Int, ";
+        params << "key: " <<  GenTypeGet(key_field->value.type) << ", ";
+        params << "bb: ByteBuffer";
+
+        auto statements = [&]() {
+            auto base_type = key_field->value.type.base_type;
+            writer.SetValue("struct_name", Esc(struct_def.name));
+            if (base_type == BASE_TYPE_STRING) {
+                writer += "val byteKey = key."
+                        "toByteArray(Table.UTF8_CHARSET.get()!!)";
+            }
+            writer += "var span = bb.getInt(vectorLocation - 4)";
+            writer += "var start = 0";
+            writer += "while (span != 0) {";
+            writer.IncrementIdentLevel();
+            writer += "var middle = span / 2";
+            writer += "val tableOffset = __indirect(vector"
+                    "Location + 4 * (start + middle), bb)";
+            if (key_field->value.type.base_type == BASE_TYPE_STRING) {
+                writer += "val comp = compareStrings(\\";
+                writer += GenOffsetGetter(key_field) + "\\";
+                writer += ", byteKey, bb)";
+            } else {
+                auto cast = CastToUsigned(key_field->value.type);
+                auto get_val = GenLookupByKey(key_field, "bb");
+                writer += "val value = " + get_val + cast;
+                writer += "val comp = value.compareTo(key)";
+            }
+            writer += "when {";
+            writer.IncrementIdentLevel();
+            writer += "comp > 0 -> span = middle";
+            writer += "comp < 0 -> {";
+            writer.IncrementIdentLevel();
+            writer += "middle++";
+            writer += "start += middle";
+            writer += "span -= middle";
+            writer.DecrementIdentLevel();
+            writer += "}"; // end comp < 0
+            writer += "else -> {";
+            writer.IncrementIdentLevel();
+            writer += "return (obj ?: {{struct_name}}()).__assign(tableOffset, bb)";
+            writer.DecrementIdentLevel();
+            writer += "}"; // end else
+            writer.DecrementIdentLevel();
+            writer += "}"; // end when
+            writer.DecrementIdentLevel();
+            writer += "}"; // end while
+            writer += "return null";
+        };
+        GenerateFun(writer, "__lookup_by_key",
+                    params.str(),
+                    Esc(struct_def.name) + "?",
+                    statements);
+    }
+
+    void GenerateFinishSizePrefixed(StructDef &struct_def,
+                                                const std::string &identifier,
+                                                CodeWriter &writer) const {
+        auto id = identifier.length() > 0  ? ", \"" + identifier + "\"" : "";
+        auto params = "builder: FlatBufferBuilder, offset: Int";
+        auto method_name = "finishSizePrefixed" + Esc(struct_def.name) + "Buffer";
+        GenerateFunOneLine(writer, method_name, params, "", [&]() {
+            writer += "builder.finishSizePrefixed(offset" + id  + ")";
+        });
+    }
+    void GenerateFinishStructBuffer(StructDef &struct_def,
+                                    const std::string &identifier,
+                                    CodeWriter &writer) const {
+        auto id = identifier.length() > 0  ? ", \"" + identifier + "\"" : "";
+        auto params = "builder: FlatBufferBuilder, offset: Int";
+        auto method_name = "finish" + Esc(struct_def.name) + "Buffer";
+        GenerateFunOneLine(writer, method_name, params, "", [&]() {
+            writer += "builder.finish(offset" + id + ")";
+        });
+    }
+
+    void GenerateEndStructMethod(StructDef &struct_def, CodeWriter &writer) const {
+        // Generate end{{TableName}}(builder: FlatBufferBuilder) method
+        auto name = "end" + Esc(struct_def.name);
+        auto params = "builder: FlatBufferBuilder";
+        auto returns = "Int";
+        auto field_vec = struct_def.fields.vec;
+
+        GenerateFun(writer, name, params, returns, [&](){
+            writer += "val o = builder.endTable()";
+            writer.IncrementIdentLevel();
+            for (auto it = field_vec.begin(); it != field_vec.end(); ++it) {
+                auto &field = **it;
+                if (field.deprecated || !field.required) {
+                    continue;
+                }
+                writer.SetValue("offset", NumToString(field.value.offset));
+                writer += "builder.required(o, {{offset}})";
+            }
+            writer.DecrementIdentLevel();
+            writer += "return o";
+        });
+    }
+
+    // Generate a method to create a vector from a Kotlin array.
+    void GenerateCreateVectorField(FieldDef &field, CodeWriter &writer) const {
+        auto vector_type = field.value.type.VectorType();
+        auto method_name = "create" + MakeCamel(Esc(field.name)) + "Vector";
+        auto params = "builder: FlatBufferBuilder, data: " +
+                GenTypeBasic(vector_type.base_type) + "Array";
+        writer.SetValue("size", NumToString(InlineSize(vector_type)));
+        writer.SetValue("align", NumToString(InlineAlignment(vector_type)));
+        writer.SetValue("root", GenMethod(vector_type));
+        writer.SetValue("cast", CastToSigned(vector_type));
+
+        GenerateFun(writer, method_name, params, "Int", [&](){
+            writer += "builder.startVector({{size}}, data.size, {{align}})";
+            writer += "for (i in data.size - 1 downTo 0) {";
+            writer.IncrementIdentLevel();
+            writer += "builder.add{{root}}(data[i]{{cast}})";
+            writer.DecrementIdentLevel();
+            writer += "}";
+            writer += "return builder.endVector()";
+        });
+    }
+
+    void GenerateStartVectorField(FieldDef &field, CodeWriter &writer) const {
+        // Generate a method to start a vector, data to be added manually
+        // after.
+        auto vector_type = field.value.type.VectorType();
+        auto params = "builder: FlatBufferBuilder, numElems: Int";
+        writer.SetValue("size", NumToString(InlineSize(vector_type)));
+        writer.SetValue("align", NumToString(InlineAlignment(vector_type)));
+
+        GenerateFunOneLine(writer,
+                           "start" + MakeCamel(Esc(field.name) + "Vector", true),
+                           params,
+                           "",
+                           [&]() {
+            writer += "builder.startVector({{size}}, numElems, {{align}})";
+        });
+    }
+
+    void GenerateAddField(std::string field_pos, FieldDef &field,
+                          CodeWriter &writer) const {
+        auto field_type = GenTypeBasic(field.value.type.base_type);
+        auto secondArg = MakeCamel(Esc(field.name), false) + ": " + field_type;
+        GenerateFunOneLine(writer, "add" + MakeCamel(Esc(field.name), true),
+                           "builder: FlatBufferBuilder, " + secondArg, "", [&](){
+            auto method = GenMethod(field.value.type);
+            writer.SetValue("field_name", MakeCamel(Esc(field.name), false));
+            writer.SetValue("method_name", method);
+            writer.SetValue("pos", field_pos);
+            writer.SetValue("default", GenFBBDefaultValue(field));
+            writer.SetValue("cast", GenFBBValueCast(field));
+
+            writer += "builder.add{{method_name}}({{pos}}, \\";
+            writer += "{{field_name}}{{cast}}, {{default}})";
+        });
+    }
+
+    static std::string ToSignedType(const Type & type) {
+        switch(type.base_type) {
+        case BASE_TYPE_UINT:
+            return GenTypeBasic(BASE_TYPE_INT);
+        case BASE_TYPE_ULONG:
+            return GenTypeBasic(BASE_TYPE_LONG);
+        case BASE_TYPE_UCHAR:
+        case BASE_TYPE_NONE:
+        case BASE_TYPE_UTYPE:
+            return GenTypeBasic(BASE_TYPE_CHAR);
+        case BASE_TYPE_USHORT:
+            return GenTypeBasic(BASE_TYPE_SHORT);
+        case BASE_TYPE_VECTOR:
+            return ToSignedType(type.VectorType());
+        default:
+            return GenTypeBasic(type.base_type);
+        }
+    }
+
+    static std::string FlexBufferBuilderCast(const std::string &method,
+                                      FieldDef &field,
+                                      bool isFirst) {
+        auto field_type = GenTypeBasic(field.value.type.base_type);
+        std::string to_type;
+        if (method == "Boolean")
+            to_type = "Boolean";
+        else if (method == "Long")
+            to_type = "Long";
+        else if (method == "Int" || method == "Offset" || method == "Struct")
+            to_type = "Int";
+        else if (method == "Byte" || method.empty())
+            to_type =  isFirst ? "Byte" : "Int";
+        else if (method == "Short")
+            to_type =  isFirst ? "Short" : "Int";
+        else if (method == "Double")
+            to_type =  "Double";
+        else if (method == "Float")
+            to_type =  isFirst ? "Float" : "Double";
+        else if (method == "UByte")
+
+        if (field_type != to_type)
+            return ".to" + to_type + "()";
+        return "";
+    }
+
+    // fun startMonster(builder: FlatBufferBuilder) = builder.startTable(11)
+    void GenerateStartStructMethod(StructDef &struct_def, CodeWriter &code) const {
+        GenerateFunOneLine(code, "start" + Esc(struct_def.name),
+                           "builder: FlatBufferBuilder", "", [&] () {
+            code += "builder.startTable("+ NumToString(struct_def.fields.vec.size()) + ")";
+        });
+    }
+
+    void GenerateTableCreator(StructDef &struct_def, CodeWriter &writer) const {
+        // Generate a method that creates a table in one go. This is only possible
+        // when the table has no struct fields, since those have to be created
+        // inline, and there's no way to do so in Java.
+        bool has_no_struct_fields = true;
+        int num_fields = 0;
+        auto fields_vec = struct_def.fields.vec;
+
+        for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
+            auto &field = **it;
+            if (field.deprecated) continue;
+            if (IsStruct(field.value.type)) {
+                has_no_struct_fields = false;
+            } else {
+                num_fields++;
+            }
+        }
+        // JVM specifications restrict default constructor params to be < 255.
+        // Longs and doubles take up 2 units, so we set the limit to be < 127.
+        if (has_no_struct_fields && num_fields && num_fields < 127) {
+            // Generate a table constructor of the form:
+            // public static int createName(FlatBufferBuilder builder, args...)
+
+            auto name = "create" + Esc(struct_def.name);
+            std::stringstream params;
+            params << "builder: FlatBufferBuilder";
+            for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
+                auto &field = **it;
+                if (field.deprecated) continue;
+                params << ", " << MakeCamel(Esc(field.name), false);
+                if (!IsScalar(field.value.type.base_type)){
+                    params << "Offset: ";
+                } else {
+                    params << ": ";
+                }
+                params << GenTypeBasic(field.value.type.base_type);
+            }
+
+            GenerateFun(writer, name, params.str(), "Int", [&]() {
+                writer.SetValue("vec_size", NumToString(fields_vec.size()));
+
+                writer += "builder.startTable({{vec_size}})";
+
+                auto sortbysize = struct_def.sortbysize;
+                auto largest = sortbysize ? sizeof(largest_scalar_t) : 1;
+                for (size_t size = largest; size; size /= 2) {
+                    for (auto it = fields_vec.rbegin(); it != fields_vec.rend();
+                         ++it) {
+                        auto &field = **it;
+                        auto base_type_size = SizeOf(field.value.type.base_type);
+                        if (!field.deprecated &&
+                                (!sortbysize || size == base_type_size)) {
+                            writer.SetValue("camel_field_name",
+                                          MakeCamel(Esc(field.name), true));
+                            writer.SetValue("field_name",
+                                          MakeCamel(Esc(field.name), false));
+
+                            writer += "add{{camel_field_name}}(builder, {{field_name}}\\";
+                            if (!IsScalar(field.value.type.base_type)){
+                                writer += "Offset\\";
+                            }
+                            writer += ")";
+                        }
+                    }
+                }
+              writer += "return end{{struct_name}}(builder)";
+            });
+        }
+
+    }
+    void GenerateBufferHasIdentifier(StructDef &struct_def,
+                                     CodeWriter &writer) const {
+        auto file_identifier = parser_.file_identifier_;
+        // Check if a buffer has the identifier.
+        if (parser_.root_struct_def_ != &struct_def || !file_identifier.length())
+            return;
+        auto name = MakeCamel(Esc(struct_def.name), false);
+        GenerateFunOneLine(writer, name + "BufferHasIdentifier",
+                           "_bb: ByteBuffer",
+                           "Boolean",
+                           [&]() {
+            writer += "__has_identifier(_bb, \"" + file_identifier + "\")";
+        });
+    }
+
+    void GenerateStructGetters(StructDef &struct_def, CodeWriter &writer) const {
+        auto fields_vec = struct_def.fields.vec;
+        FieldDef *key_field = nullptr;
+        for (auto it = fields_vec.begin(); it != fields_vec.end(); ++it) {
+            auto &field = **it;
+            if (field.deprecated) continue;
+            if (field.key) key_field = &field;
+
+            GenerateComment(field.doc_comment, writer, &comment_config);
+
+            auto field_name = MakeCamel(Esc(field.name), false);
+            auto field_type = GenTypeGet(field.value.type);
+            auto field_default_value = GenDefaultValue(field);
+            auto return_type = GenTypeGet(field.value.type);
+            auto bbgetter = ByteBufferGetter(field.value.type, "bb");
+            auto ucast = CastToUsigned(field);
+            auto offset_val = NumToString(field.value.offset);
+            auto offset_prefix = "val o = __offset(" + offset_val
+                                 + "); return o != 0 ? ";
+            auto value_base_type = field.value.type.base_type;
+            // Most field accessors need to retrieve and test the field offset
+            // first, this is the offset value for that:
+            writer.SetValue("offset", NumToString(field.value.offset));
+            writer.SetValue("return_type", return_type);
+            writer.SetValue("field_type", field_type);
+            writer.SetValue("field_name", field_name);
+            writer.SetValue("field_default", field_default_value);
+            writer.SetValue("bbgetter", bbgetter);
+            writer.SetValue("ucast", ucast);
+
+            auto opt_ret_type = return_type + "?";
+            // Generate the accessors that don't do object reuse.
+            if (value_base_type == BASE_TYPE_STRUCT) {
+                // Calls the accessor that takes an accessor object with a
+                // new object.
+                // val pos
+                //     get() = pos(Vec3())
+                GenerateGetterOneLine(writer, field_name, opt_ret_type, [&](){
+                    writer += "{{field_name}}({{field_type}}())";
+                });
+            } else if (value_base_type == BASE_TYPE_VECTOR &&
+                       field.value.type.element == BASE_TYPE_STRUCT) {
+                // Accessors for vectors of structs also take accessor objects,
+                // this generates a variant without that argument.
+                // ex: fun weapons(j: Int) = weapons(Weapon(), j)
+                GenerateFunOneLine(writer, field_name, "j: Int", opt_ret_type, [&](){
+                    writer += "{{field_name}}({{return_type}}(), j)";
+                });
+            }
+
+            if (IsScalar(value_base_type)) {
+                if (struct_def.fixed) {
+                    GenerateGetterOneLine(writer, field_name, return_type, [&](){
+                        writer += "{{bbgetter}}(bb_pos + {{offset}}){{ucast}}";
+                    });
+                } else {
+                    GenerateGetter(writer, field_name, return_type, [&](){
+                        writer += "val o = __offset({{offset}})";
+                        writer += "return if(o != 0) {{bbgetter}}"
+                                  "(o + bb_pos){{ucast}} else "
+                                  "{{field_default}}";
+                    });
+                }
+            } else {
+                switch (value_base_type) {
+                case BASE_TYPE_STRUCT:
+                    if (struct_def.fixed) {
+                        // create getter with object reuse
+                        // ex:
+                        // fun pos(obj: Vec3) : Vec3? = obj.__assign(bb_pos + 4, bb)
+                        // ? adds nullability annotation
+                        GenerateFunOneLine(writer,
+                                           field_name, "obj: " + field_type ,
+                                           return_type + "?", [&](){
+                            writer += "obj.__assign(bb_pos + {{offset}}, bb)";
+                        });
+                    } else {
+                        // create getter with object reuse
+                        // ex:
+                        //  fun pos(obj: Vec3) : Vec3? {
+                        //      val o = __offset(4)
+                        //      return if(o != 0) {
+                        //          obj.__assign(o + bb_pos, bb)
+                        //      else {
+                        //          null
+                        //      }
+                        //  }
+                        // ? adds nullability annotation
+                        GenerateFun(writer, field_name, "obj: " + field_type,
+                                    return_type + "?", [&](){
+                            auto fixed = field.value.type.struct_def->fixed;
+
+                            writer.SetValue("seek", Indirect("o + bb_pos", fixed));
+                            OffsetWrapper(writer,
+                                          offset_val,
+                                          [&]() { writer += "obj.__assign({{seek}}, bb)"; },
+                                          [&]() { writer += "null"; });
+                        });
+                    }
+                    break;
+                case BASE_TYPE_STRING:
+                    // create string getter
+                    // e.g.
+                    // val Name : String?
+                    //     get() = {
+                    //         val o = __offset(10)
+                    //         return if (o != 0) __string(o + bb_pos) else null
+                    //     }
+                    // ? adds nullability annotation
+                    GenerateGetter(writer, field_name, return_type + "?", [&](){
+
+                        writer += "val o = __offset({{offset}})";
+                        writer += "return if (o != 0) __string(o + bb_pos) else null";
+                    });
+                    break;
+                case BASE_TYPE_VECTOR: {
+                    // e.g.
+                    // fun inventory(j: Int) : UByte {
+                    //     val o = __offset(14)
+                    //     return if (o != 0) {
+                    //         bb.get(__vector(o) + j * 1).toUByte()
+                    //     } else {
+                    //        0
+                    //     }
+                    // }
+
+                    auto vectortype = field.value.type.VectorType();
+                    std::string params = "j: Int";
+                    std::string nullable = IsScalar(vectortype.base_type) ? ""
+                                                                          : "?";
+
+                    if (vectortype.base_type == BASE_TYPE_STRUCT ||
+                            vectortype.base_type == BASE_TYPE_UNION) {
+                        params = "obj: " + field_type + ", j: Int";
+                    }
+
+
+                    writer.SetValue("toType", "YYYYY");
+
+                    auto ret_type = return_type + nullable;
+                    GenerateFun(writer, field_name, params, ret_type, [&](){
+                        auto inline_size = NumToString(InlineSize(vectortype));
+                        auto index = "__vector(o) + j * " + inline_size;
+                        auto not_found = NotFoundReturn(field.value.type.element);
+                        auto found = "";
+                        writer.SetValue("index", index);
+                        switch(vectortype.base_type) {
+                        case BASE_TYPE_STRUCT: {
+                            bool fixed = vectortype.struct_def->fixed;
+                            writer.SetValue("index", Indirect(index, fixed));
+                            found = "obj.__assign({{index}}, bb)";
+                            break;
+                        }
+                        case BASE_TYPE_UNION:
+                            found = "{{bbgetter}}(obj, {{index}} - bb_pos){{ucast}}";
+                            break;
+                        default:
+                            found = "{{bbgetter}}({{index}}){{ucast}}";
+                        }
+                        OffsetWrapper(writer, offset_val,
+                                      [&]() { writer += found; } ,
+                                      [&]() { writer += not_found; });
+                    });
+                    break;
+                }
+                case BASE_TYPE_UNION:
+                    GenerateFun(writer, field_name, "obj: " + field_type,
+                                return_type + "?", [&](){
+                        writer += OffsetWrapperOneLine(offset_val,
+                                                       bbgetter + "(obj, o)",
+                                                       "null");
+                    });
+                    break;
+                default:
+                    FLATBUFFERS_ASSERT(0);
+                }
+            }
+
+            if (value_base_type == BASE_TYPE_VECTOR) {
+                // Generate Lenght functions for vectors
+                GenerateGetter(writer, field_name + "Length", "Int", [&](){
+                    writer += OffsetWrapperOneLine(offset_val,
+                                                   "__vector_len(o)", "0");
+                });
+
+                // See if we should generate a by-key accessor.
+                if (field.value.type.element == BASE_TYPE_STRUCT &&
+                        !field.value.type.struct_def->fixed) {
+                    auto &sd = *field.value.type.struct_def;
+                    auto &fields = sd.fields.vec;
+                    for (auto kit = fields.begin(); kit != fields.end(); ++kit) {
+                        auto &kfield = **kit;
+                        if (kfield.key) {
+                            auto qualified_name = WrapInNameSpace(sd);
+                            auto name = MakeCamel(Esc(field.name), false) + "ByKey";
+                            auto params = "key: " + GenTypeGet(kfield.value.type);
+                            auto rtype = qualified_name + "?";
+                            GenerateFun(writer, name, params, rtype, [&] () {
+                                OffsetWrapper(writer, offset_val,
+                                [&] () {
+                                    writer += qualified_name +
+                                    ".__lookup_by_key(null, __vector(o), key, bb)";
+                                },
+                                [&] () {
+                                    writer += "null";
+                                });
+                            });
+
+                            auto param2 = "obj: " + qualified_name +
+                                    ", key: " +
+                                    GenTypeGet(kfield.value.type);
+                            GenerateFun(writer, name, param2, rtype, [&](){
+                                OffsetWrapper(writer, offset_val,
+                                [&] () {
+                                    writer += qualified_name +
+                                    ".__lookup_by_key(obj, __vector(o), key, bb)";
+                                },
+                                [&]() { writer += "null"; });
+                            });
+
+                            break;
+                        }
+                    }
+                }
+            }
+
+            if ((value_base_type == BASE_TYPE_VECTOR &&
+                 IsScalar(field.value.type.VectorType().base_type)) ||
+                    value_base_type == BASE_TYPE_STRING) {
+
+                auto end_idx = NumToString(value_base_type == BASE_TYPE_STRING
+                                           ? 1
+                                           : InlineSize(field.value.type.VectorType()));
+                // Generate a ByteBuffer accessor for strings & vectors of scalars.
+                // e.g.
+                // val inventoryByteBuffer: ByteBuffer
+                //     get =  __vector_as_bytebuffer(14, 1)
+
+                GenerateGetterOneLine(writer, field_name + "AsByteBuffer",
+                                      "ByteBuffer", [&](){
+                    writer.SetValue("end", end_idx);
+                    writer += "__vector_as_bytebuffer({{offset}}, {{end}})";
+                });
+
+                // Generate a ByteBuffer accessor for strings & vectors of scalars.
+                // e.g.
+                // fun inventoryInByteBuffer(_bb: Bytebuffer):
+                //     ByteBuffer = __vector_as_bytebuffer(_bb, 14, 1)
+                GenerateFunOneLine(writer, field_name + "InByteBuffer",
+                                   "_bb: ByteBuffer", "ByteBuffer", [&](){
+                    writer.SetValue("end", end_idx);
+                    writer += "__vector_in_bytebuffer(_bb, {{offset}}, {{end}})";
+                });
+            }
+
+            // generate object accessors if is nested_flatbuffer
+            //fun testnestedflatbufferAsMonster() : Monster?
+            //{ return testnestedflatbufferAsMonster(new Monster()); }
+
+            if (field.nested_flatbuffer) {
+                auto nested_type_name = WrapInNameSpace(*field.nested_flatbuffer);
+                auto nested_method_name =
+                        field_name + "As" +
+                        field.nested_flatbuffer->name;
+
+                GenerateGetterOneLine(writer,
+                                      nested_method_name,
+                                      nested_type_name + "?", [&](){
+                    writer += nested_method_name + "(" + nested_type_name + "())";
+                });
+
+                GenerateFun(writer,
+                            nested_method_name,
+                            "obj: " + nested_type_name,
+                            nested_type_name + "?", [&](){
+                    OffsetWrapper(writer, offset_val,
+                                  [&]() { writer += "obj.__assign(__indirect(__vector(o)), bb)"; },
+                                  [&]() { writer += "null";});
+                });
+            }
+
+            // Generate mutators for scalar fields or vectors of scalars.
+            if (parser_.opts.mutable_buffer) {
+                auto value_type = field.value.type;
+                auto underlying_type = value_base_type == BASE_TYPE_VECTOR
+                        ? value_type.VectorType()
+                        : value_type;
+                auto name = "mutate" + MakeCamel(Esc(field.name), true);
+                auto size = NumToString(InlineSize(underlying_type));
+                auto params = Esc(field.name) + ": " + GenTypeGet(underlying_type);
+                // A vector mutator also needs the index of the vector element it should
+                // mutate.
+                if (value_base_type == BASE_TYPE_VECTOR)
+                    params.insert(0, "j: Int, ");
+
+                // Boolean parameters have to be explicitly converted to byte
+                // representation.
+                auto setter_parameter = underlying_type.base_type == BASE_TYPE_BOOL
+                        ? "(if(" + Esc(field.name) + ") 1 else 0).toByte()"
+                        : Esc(field.name);
+
+                auto setter_index = value_base_type == BASE_TYPE_VECTOR
+                        ? "__vector(o) + j * " + size
+                        : (struct_def.fixed
+                           ? "bb_pos + " + offset_val
+                           : "o + bb_pos");
+                if (IsScalar(value_base_type) || (value_base_type == BASE_TYPE_VECTOR &&
+                         IsScalar(value_type.VectorType().base_type))) {
+
+                    auto statements = [&] () {
+                        writer.SetValue("bbsetter", ByteBufferSetter(underlying_type));
+                        writer.SetValue("index", setter_index);
+                        writer.SetValue("params", setter_parameter);
+                        writer.SetValue("cast", CastToSigned(field));
+                        if (struct_def.fixed) {
+                            writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})";
+                        } else {
+                            OffsetWrapper(writer, offset_val, [&](){
+                                writer += "{{bbsetter}}({{index}}, {{params}}{{cast}})";
+                                writer += "true";
+                            }, [&](){ writer += "false";});
+                        }
+                    };
+
+                    if (struct_def.fixed) {
+                        GenerateFunOneLine(writer, name, params, "ByteBuffer",
+                                    statements);
+                    } else {
+                        GenerateFun(writer, name, params, "Boolean",
+                                    statements);
+                    }
+                }
+            }
+        }
+        if (struct_def.has_key && !struct_def.fixed) {
+            // Key Comparison method
+            GenerateOverrideFun(
+                        writer,
+                        "keysCompare",
+                        "o1: Int, o2: Int, _bb: ByteBuffer", "Int", [&]() {
+                if (key_field->value.type.base_type == BASE_TYPE_STRING) {
+                    writer.SetValue("offset", NumToString(key_field->value.offset));
+                    writer += " return compareStrings(__offset({{offset}}, o1, "
+                            "_bb), __offset({{offset}}, o2, _bb), _bb)";
+
+                } else {
+                    auto getter1 = GenLookupByKey(key_field, "_bb", "o1");
+                    auto getter2 = GenLookupByKey(key_field, "_bb", "o2");
+                    writer += "val val_1 = " + getter1;
+                    writer += "val val_2 = " + getter2;
+                    writer += "return (val_1 - val_2).sign";
+                }
+            });
+        }
+    }
+
+    static std::string CastToUsigned(const FieldDef &field) {
+        return CastToUsigned(field.value.type);
+    }
+
+    static std::string CastToUsigned(const Type type) {
+        switch (type.base_type) {
+        case BASE_TYPE_UINT:
+            return ".toUInt()";
+        case BASE_TYPE_UCHAR:
+        case BASE_TYPE_UTYPE:
+            return ".toUByte()";
+        case BASE_TYPE_USHORT:
+            return ".toUShort()";
+        case BASE_TYPE_ULONG:
+            return ".toULong()";
+        case BASE_TYPE_VECTOR:
+            return CastToUsigned(type.VectorType());
+        default:
+            return "";
+        }
+    }
+
+    static std::string CastToSigned(const FieldDef &field) {
+        return CastToSigned(field.value.type);
+    }
+
+    static std::string CastToSigned(const Type type) {
+        switch (type.base_type) {
+        case BASE_TYPE_UINT:
+            return ".toInt()";
+        case BASE_TYPE_UCHAR:
+        case BASE_TYPE_UTYPE:
+            return ".toByte()";
+        case BASE_TYPE_USHORT:
+            return ".toShort()";
+        case BASE_TYPE_ULONG:
+            return ".toLong()";
+        case BASE_TYPE_VECTOR:
+            return CastToSigned(type.VectorType());
+        default:
+            return "";
+        }
+    }
+
+    static std::string LiteralSuffix(const BaseType type) {
+        switch (type) {
+        case BASE_TYPE_UINT:
+        case BASE_TYPE_UCHAR:
+        case BASE_TYPE_UTYPE:
+        case BASE_TYPE_USHORT:
+            return "u";
+        case BASE_TYPE_ULONG:
+            return "UL";
+        case BASE_TYPE_LONG:
+            return "L";
+        default:
+            return "";
+        }
+    }
+
+    void GenerateCompanionObject(CodeWriter &code,
+                                 const std::function<void()> &callback) const {
+        code += "companion object {";
+        code.IncrementIdentLevel();
+        callback();
+        code.DecrementIdentLevel();
+        code += "}";
+    }
+
+    // Generate a documentation comment, if available.
+    void GenerateComment(const std::vector<std::string> &dc, CodeWriter &writer,
+                    const CommentConfig *config) const {
+      if (dc.begin() == dc.end()) {
+        // Don't output empty comment blocks with 0 lines of comment content.
+        return;
+      }
+
+      if (config != nullptr && config->first_line != nullptr) {
+        writer += std::string(config->first_line);
+      }
+      std::string line_prefix =
+          ((config != nullptr && config->content_line_prefix != nullptr)
+               ? config->content_line_prefix
+               : "///");
+      for (auto it = dc.begin(); it != dc.end(); ++it) {
+        writer += line_prefix + *it;
+      }
+      if (config != nullptr && config->last_line != nullptr) {
+        writer += std::string(config->last_line);
+      }
+    }
+
+    static void GenerateGetRootAsAccessors(const std::string &struct_name,
+                                           CodeWriter &writer) {
+        // Generate a special accessor for the table that when used as the root
+        // ex: fun getRootAsMonster(_bb: ByteBuffer): Monster {...}
+        writer.SetValue("gr_name", struct_name);
+        writer.SetValue("gr_method", "getRootAs" + struct_name);
+
+        // create convenience method that doesn't require an existing object
+        writer += "fun {{gr_method}}(_bb: ByteBuffer): {{gr_name}} = \\";
+        writer += "{{gr_method}}(_bb, {{gr_name}}())";
+
+        // create method that allows object reuse
+        // ex: fun Monster getRootAsMonster(_bb: ByteBuffer, obj: Monster) {...}
+        writer += "fun {{gr_method}}"
+                 "(_bb: ByteBuffer, obj: {{gr_name}}): {{gr_name}} {";
+        writer.IncrementIdentLevel();
+        writer += "_bb.order(ByteOrder.LITTLE_ENDIAN)";
+        writer += "return (obj.__assign(_bb.getInt(_bb.position())"
+                 " + _bb.position(), _bb))";
+        writer.DecrementIdentLevel();
+        writer += "}";
+    }
+
+    static void GenerateStaticConstructor(const StructDef &struct_def,
+                                          CodeWriter &code) {
+        // create a struct constructor function
+        auto params = StructConstructorParams(struct_def);
+        GenerateFun(code, "create" + Esc(struct_def.name), params, "Int", [&](){
+            GenStructBody(struct_def, code, "");
+            code += "return builder.offset()";
+        });
+    }
+
+    static std::string StructConstructorParams(const StructDef &struct_def,
+                                               const std::string &prefix = "") {
+        //builder: FlatBufferBuilder
+        std::stringstream out;
+        auto field_vec = struct_def.fields.vec;
+        if (prefix.empty()) {
+            out << "builder: FlatBufferBuilder";
+        }
+        for (auto it = field_vec.begin(); it != field_vec.end(); ++it) {
+            auto &field = **it;
+            if (IsStruct(field.value.type)) {
+                // Generate arguments for a struct inside a struct. To ensure
+                // names don't clash, and to make it obvious these arguments are
+                // constructing a nested struct, prefix the name with the field
+                // name.
+                out << StructConstructorParams(*field.value.type.struct_def,
+                                              prefix + (Esc(field.name) + "_"));
+            } else {
+                out << ", " << prefix << MakeCamel(Esc(field.name), false)
+                    << ": "
+                    << GenTypeBasic(field.value.type.base_type);
+            }
+        }
+        return out.str();
+    }
+
+    static void GeneratePropertyOneLine(CodeWriter &writer,
+                               const std::string &name,
+                               const std::string &type,
+                               const std::function<void()> &body) {
+        // Generates Kotlin getter for properties
+        // e.g.:
+        // val prop: Mytype = x
+        writer.SetValue("_name", name);
+        writer.SetValue("_type", type);
+        writer += "val {{_name}} : {{_type}} = \\";
+        body();
+    }
+    static void GenerateGetterOneLine(CodeWriter &writer,
+                               const std::string &name,
+                               const std::string &type,
+                               const std::function<void()> &body) {
+        // Generates Kotlin getter for properties
+        // e.g.:
+        // val prop: Mytype get() = x
+        writer.SetValue("_name", name);
+        writer.SetValue("_type", type);
+        writer += "val {{_name}} : {{_type}} get() = \\";
+        body();
+    }
+
+    static void GenerateGetter(CodeWriter &writer,
+                               const std::string &name,
+                               const std::string &type,
+                               const std::function<void()> &body) {
+        // Generates Kotlin getter for properties
+        // e.g.:
+        // val prop: Mytype
+        //     get() = {
+        //       return x
+        //     }
+        writer.SetValue("name", name);
+        writer.SetValue("type", type);
+        writer += "val {{name}} : {{type}}";
+        writer.IncrementIdentLevel();
+        writer += "get() {";
+        writer.IncrementIdentLevel();
+        body();
+        writer.DecrementIdentLevel();
+        writer += "}";
+        writer.DecrementIdentLevel();
+    }
+
+    static void GenerateFun(CodeWriter &writer,
+                            const std::string &name,
+                            const std::string &params,
+                            const std::string &returnType,
+                            const std::function<void()> &body) {
+        // Generates Kotlin function
+        // e.g.:
+        // fun path(j: Int): Vec3 {
+        //     return path(Vec3(), j)
+        // }
+        auto noreturn = returnType.empty();
+        writer.SetValue("name", name);
+        writer.SetValue("params", params);
+        writer.SetValue("return_type", noreturn ? "" : ": " + returnType);
+        writer += "fun {{name}}({{params}}) {{return_type}} {";
+        writer.IncrementIdentLevel();
+        body();
+        writer.DecrementIdentLevel();
+        writer += "}";
+    }
+
+    static void GenerateFunOneLine(CodeWriter &writer,
+                                   const std::string &name,
+                                   const std::string &params,
+                                   const std::string &returnType,
+                                   const std::function<void()> &body) {
+        // Generates Kotlin function
+        // e.g.:
+        // fun path(j: Int): Vec3 = return path(Vec3(), j)
+        writer.SetValue("name", name);
+        writer.SetValue("params", params);
+        writer.SetValue("return_type_p", returnType.empty() ? "" :
+                                                          " : " + returnType);
+        writer += "fun {{name}}({{params}}){{return_type_p}} = \\";
+        body();
+    }
+
+    static void GenerateOverrideFun(CodeWriter &writer,
+                                   const std::string &name,
+                                   const std::string &params,
+                                   const std::string &returnType,
+                                   const std::function<void()> &body) {
+        // Generates Kotlin function
+        // e.g.:
+        // override fun path(j: Int): Vec3 = return path(Vec3(), j)
+        writer += "override \\";
+        GenerateFun(writer, name, params, returnType, body);
+    }
+
+    static void GenerateOverrideFunOneLine(CodeWriter &writer,
+                                   const std::string &name,
+                                   const std::string &params,
+                                   const std::string &returnType,
+                                   const std::string &statement) {
+        // Generates Kotlin function
+        // e.g.:
+        // override fun path(j: Int): Vec3 = return path(Vec3(), j)
+        writer.SetValue("name", name);
+        writer.SetValue("params", params);
+        writer.SetValue("return_type", returnType.empty() ? "" :
+                                                          " : " + returnType);
+        writer += "override fun {{name}}({{params}}){{return_type}} = \\";
+        writer += statement;
+    }
+
+    static std::string OffsetWrapperOneLine(const std::string &offset,
+                                            const std::string &found,
+                                            const std::string &not_found) {
+        return "val o = __offset(" + offset + "); return if (o != 0) " + found +
+                " else " + not_found;
+    }
+
+    static void OffsetWrapper(CodeWriter &code,
+                       const std::string &offset,
+                       const std::function<void()> &found,
+                       const std::function<void()> &not_found) {
+        code += "val o = __offset(" + offset + ")";
+        code +="return if (o != 0) {";
+        code.IncrementIdentLevel();
+        found();
+        code.DecrementIdentLevel();
+        code += "} else {";
+        code.IncrementIdentLevel();
+        not_found();
+        code.DecrementIdentLevel();
+        code += "}";
+    }
+
+    static std::string Indirect(const std::string &index, bool fixed) {
+        // We apply __indirect() and struct is not fixed.
+        if (!fixed)
+            return "__indirect(" + index + ")";
+        return index;
+    }
+
+    static std::string NotFoundReturn(BaseType el) {
+        switch (el) {
+        case BASE_TYPE_FLOAT:
+           return "0.0f";
+         case BASE_TYPE_DOUBLE:
+            return "0.0";
+        case BASE_TYPE_BOOL:
+            return "false";
+        case BASE_TYPE_LONG:
+        case BASE_TYPE_INT:
+        case BASE_TYPE_CHAR:
+        case BASE_TYPE_SHORT:
+            return "0";
+        case BASE_TYPE_UINT:
+        case BASE_TYPE_UCHAR:
+        case BASE_TYPE_USHORT:
+        case BASE_TYPE_UTYPE:
+            return "0u";
+        case BASE_TYPE_ULONG:
+            return "0uL";
+        default:
+            return "null";
+        }
+    }
+
+    // This tracks the current namespace used to determine if a type need to be
+    // prefixed by its namespace
+    const Namespace *cur_name_space_;
+};
+}  // namespace kotlin
+
+bool GenerateKotlin(const Parser &parser, const std::string &path,
+                    const std::string &file_name) {
+    kotlin::KotlinGenerator generator(parser, path, file_name);
+    return generator.generate();
+}
+}  // namespace flatbuffers