Add a wrapper around flatbuffers::TypeTable

So I can implement it on top of a Schema too.

Change-Id: I56502593e302c186cf48d3e2b42233a48202176d
diff --git a/aos/json_to_flatbuffer.cc b/aos/json_to_flatbuffer.cc
index 036ae01..f64991d 100644
--- a/aos/json_to_flatbuffer.cc
+++ b/aos/json_to_flatbuffer.cc
@@ -17,19 +17,6 @@
 // one is and how to test it.  So everything rejects it.
 
 namespace aos {
-
-// Finds the field index in the table given the name.
-int FieldIndex(const flatbuffers::TypeTable *typetable,
-               const char *field_name) {
-  CHECK(typetable->values == nullptr);
-  for (size_t i = 0; i < typetable->num_elems; ++i) {
-    if (strcmp(field_name, typetable->names[i]) == 0) {
-      return i;
-    }
-  }
-  return -1;
-}
-
 namespace {
 
 // Class to hold one of the 3 json types for an array.
@@ -77,30 +64,29 @@
 
 // Adds a single element.  This assumes that vectors have been dealt with
 // already.  Returns true on success.
-bool AddSingleElement(const flatbuffers::TypeTable *typetable,
-                      const FieldElement &field_element,
+bool AddSingleElement(FlatbufferType type, const FieldElement &field_element,
                       ::std::vector<bool> *fields_in_use,
                       flatbuffers::FlatBufferBuilder *fbb);
-bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
-                      int64_t int_value, flatbuffers::FlatBufferBuilder *fbb);
-bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
-                      double double_value, flatbuffers::FlatBufferBuilder *fbb);
-bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
+bool AddSingleElement(FlatbufferType type, int field_index, int64_t int_value,
+                      flatbuffers::FlatBufferBuilder *fbb);
+bool AddSingleElement(FlatbufferType type, int field_index, double double_value,
+                      flatbuffers::FlatBufferBuilder *fbb);
+bool AddSingleElement(FlatbufferType type, int field_index,
                       flatbuffers::Offset<flatbuffers::String> offset_element,
                       flatbuffers::FlatBufferBuilder *fbb);
 
-// Writes an array of FieldElement (with the definition in the type
-// table) to the builder.  Returns the offset of the table.
-flatbuffers::uoffset_t WriteTable(const flatbuffers::TypeTable *typetable,
+// Writes an array of FieldElement (with the definition in "type") to the
+// builder.  Returns the offset of the resulting table.
+flatbuffers::uoffset_t WriteTable(FlatbufferType type,
                                   const ::std::vector<FieldElement> &elements,
                                   flatbuffers::FlatBufferBuilder *fbb) {
   // End of a nested struct!  Add it.
   const flatbuffers::uoffset_t start = fbb->StartTable();
 
-  ::std::vector<bool> fields_in_use(typetable->num_elems, false);
+  ::std::vector<bool> fields_in_use(type.NumberFields(), false);
 
   for (const FieldElement &field_element : elements) {
-    AddSingleElement(typetable, field_element, &fields_in_use, fbb);
+    AddSingleElement(type, field_element, &fields_in_use, fbb);
   }
 
   return fbb->EndTable(start);
@@ -123,10 +109,10 @@
 
   // Parses the json into a flatbuffer.  Returns either an empty vector on
   // error, or a vector with the flatbuffer data in it.
-  flatbuffers::Offset<flatbuffers::Table> Parse(
-      const std::string_view data, const flatbuffers::TypeTable *typetable) {
+  flatbuffers::Offset<flatbuffers::Table> Parse(const std::string_view data,
+                                                FlatbufferType type) {
     flatbuffers::uoffset_t end = 0;
-    bool result = DoParse(typetable, data, &end);
+    bool result = DoParse(type, data, &end);
 
     if (result) {
       // On success, finish the table and build the vector.
@@ -143,8 +129,8 @@
 
   // Parses the flatbuffer.  This is a second method so we can do easier
   // cleanup at the top level.  Returns true on success.
-  bool DoParse(const flatbuffers::TypeTable *typetable,
-               const std::string_view data, flatbuffers::uoffset_t *table_end);
+  bool DoParse(FlatbufferType type, const std::string_view data,
+               flatbuffers::uoffset_t *table_end);
 
   // Adds *_value for the provided field.  If we are in a vector, queues the
   // data up in vector_elements.  Returns true on success.
@@ -169,7 +155,7 @@
   // nested structures.
   struct FlatBufferContext {
     // Type of the current type.
-    const flatbuffers::TypeTable *typetable;
+    FlatbufferType type;
     // If true, we are parsing a vector.
     bool in_vector;
     // The field index of the current field.
@@ -194,10 +180,9 @@
   ::std::vector<FlatBufferContext> stack_;
 };
 
-bool JsonParser::DoParse(const flatbuffers::TypeTable *typetable,
-                         const std::string_view data,
+bool JsonParser::DoParse(FlatbufferType type, const std::string_view data,
                          flatbuffers::uoffset_t *table_end) {
-  ::std::vector<const flatbuffers::TypeTable *> stack;
+  ::std::vector<FlatbufferType> stack;
 
   Tokenizer t(data);
 
@@ -220,23 +205,22 @@
 
       case Tokenizer::TokenType::kStartObject:  // {
         if (stack_.size() == 0) {
-          stack_.push_back({typetable, false, -1, "", {}, {}});
+          stack_.push_back({type, false, -1, "", {}, {}});
         } else {
           int field_index = stack_.back().field_index;
 
-          const flatbuffers::TypeCode &type_code =
-              stack_.back().typetable->type_codes[field_index];
-
-          if (type_code.base_type != flatbuffers::ET_SEQUENCE) {
+          if (!stack_.back().type.FieldIsSequence(field_index)) {
             fprintf(stderr, "Field '%s' is not a sequence\n",
                     stack_.back().field_name.c_str());
             return false;
           }
 
-          flatbuffers::TypeFunction type_function =
-              stack_.back().typetable->type_refs[type_code.sequence_ref];
-
-          stack_.push_back({type_function(), false, -1, "", {}, {}});
+          stack_.push_back({stack_.back().type.FieldType(field_index),
+                            false,
+                            -1,
+                            "",
+                            {},
+                            {}});
         }
         break;
       case Tokenizer::TokenType::kEndObject:  // }
@@ -247,7 +231,7 @@
         } else {
           // End of a nested struct!  Add it.
           const flatbuffers::uoffset_t end =
-              WriteTable(stack_.back().typetable, stack_.back().elements, fbb_);
+              WriteTable(stack_.back().type, stack_.back().elements, fbb_);
 
           // We now want to talk about the parent structure.  Pop the child.
           stack_.pop_back();
@@ -335,8 +319,8 @@
       case Tokenizer::TokenType::kField:  // field name
       {
         stack_.back().field_name = t.field_name();
-        stack_.back().field_index = FieldIndex(
-            stack_.back().typetable, stack_.back().field_name.c_str());
+        stack_.back().field_index =
+            stack_.back().type.FieldIndex(stack_.back().field_name.c_str());
 
         if (stack_.back().field_index == -1) {
           fprintf(stderr, "Invalid field name '%s'\n",
@@ -350,10 +334,7 @@
 }
 
 bool JsonParser::AddElement(int field_index, int64_t int_value) {
-  flatbuffers::TypeCode type_code =
-      stack_.back().typetable->type_codes[field_index];
-
-  if (type_code.is_repeating != in_vector()) {
+  if (stack_.back().type.FieldIsRepeating(field_index) != in_vector()) {
     fprintf(stderr, "Type and json disagree on if we are in a vector or not\n");
     return false;
   }
@@ -367,10 +348,7 @@
 }
 
 bool JsonParser::AddElement(int field_index, double double_value) {
-  flatbuffers::TypeCode type_code =
-      stack_.back().typetable->type_codes[field_index];
-
-  if (type_code.is_repeating != in_vector()) {
+  if (stack_.back().type.FieldIsRepeating(field_index) != in_vector()) {
     fprintf(stderr, "Type and json disagree on if we are in a vector or not\n");
     return false;
   }
@@ -384,16 +362,13 @@
 }
 
 bool JsonParser::AddElement(int field_index, const ::std::string &data) {
-  flatbuffers::TypeCode type_code =
-      stack_.back().typetable->type_codes[field_index];
-
-  if (type_code.is_repeating != in_vector()) {
+  if (stack_.back().type.FieldIsRepeating(field_index) != in_vector()) {
     fprintf(stderr, "Type and json disagree on if we are in a vector or not\n");
     return false;
   }
 
   const flatbuffers::ElementaryType elementary_type =
-      static_cast<flatbuffers::ElementaryType>(type_code.base_type);
+      stack_.back().type.FieldElementaryType(field_index);
   switch (elementary_type) {
     case flatbuffers::ET_CHAR:
     case flatbuffers::ET_UCHAR:
@@ -403,40 +378,25 @@
     case flatbuffers::ET_UINT:
     case flatbuffers::ET_LONG:
     case flatbuffers::ET_ULONG:
-      if (type_code.sequence_ref != -1) {
+      if (stack_.back().type.FieldIsEnum(field_index)) {
         // We have an enum.
-        const flatbuffers::TypeTable *type_table = stack_.back().typetable;
-        flatbuffers::TypeFunction type_function =
-            type_table->type_refs[type_code.sequence_ref];
+        const FlatbufferType type = stack_.back().type;
+        const FlatbufferType enum_type = type.FieldType(field_index);
+        CHECK(enum_type.IsEnum());
 
-        const flatbuffers::TypeTable *enum_type_table = type_function();
+        const std::optional<int64_t> int_value = enum_type.EnumValue(data);
 
-        CHECK_EQ(enum_type_table->st, flatbuffers::ST_ENUM);
-
-        int64_t int_value = 0;
-        bool found = false;
-        for (size_t i = 0; i < enum_type_table->num_elems; ++i) {
-          if (data == enum_type_table->names[i]) {
-            if (enum_type_table->values) {
-              int_value = enum_type_table->values[i];
-            } else {
-              int_value = i;
-            }
-            found = true;
-            break;
-          }
-        }
-
-        if (!found) {
-          fprintf(stderr, "Enum value '%s' not found for field '%s'\n",
-                  data.c_str(), type_table->names[field_index]);
+        if (!int_value) {
+          const std::string_view name = type.FieldName(field_index);
+          fprintf(stderr, "Enum value '%s' not found for field '%.*s'\n",
+                  data.c_str(), static_cast<int>(name.size()), name.data());
           return false;
         }
 
         if (in_vector()) {
-          stack_.back().vector_elements.emplace_back(int_value);
+          stack_.back().vector_elements.emplace_back(*int_value);
         } else {
-          stack_.back().elements.emplace_back(field_index, int_value);
+          stack_.back().elements.emplace_back(field_index, *int_value);
         }
         return true;
       }
@@ -457,13 +417,13 @@
   return true;
 }
 
-bool AddSingleElement(const flatbuffers::TypeTable *typetable,
-                      const FieldElement &field_element,
+bool AddSingleElement(FlatbufferType type, const FieldElement &field_element,
                       ::std::vector<bool> *fields_in_use,
                       flatbuffers::FlatBufferBuilder *fbb) {
   if ((*fields_in_use)[field_element.field_index]) {
-    fprintf(stderr, "Duplicate field: '%s'\n",
-            typetable->names[field_element.field_index]);
+    const std::string_view name = type.FieldName(field_element.field_index);
+    fprintf(stderr, "Duplicate field: '%.*s'\n", static_cast<int>(name.size()),
+            name.data());
     return false;
   }
 
@@ -471,29 +431,27 @@
 
   switch (field_element.element.type) {
     case Element::ElementType::INT:
-      return AddSingleElement(typetable, field_element.field_index,
+      return AddSingleElement(type, field_element.field_index,
                               field_element.element.int_element, fbb);
     case Element::ElementType::DOUBLE:
-      return AddSingleElement(typetable, field_element.field_index,
+      return AddSingleElement(type, field_element.field_index,
                               field_element.element.double_element, fbb);
     case Element::ElementType::OFFSET:
-      return AddSingleElement(typetable, field_element.field_index,
+      return AddSingleElement(type, field_element.field_index,
                               field_element.element.offset_element, fbb);
   }
   return false;
 }
 
-bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
-                      int64_t int_value, flatbuffers::FlatBufferBuilder *fbb
+bool AddSingleElement(FlatbufferType type, int field_index, int64_t int_value,
+                      flatbuffers::FlatBufferBuilder *fbb
 
 ) {
   flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
       static_cast<flatbuffers::voffset_t>(field_index));
 
-  flatbuffers::TypeCode type_code = typetable->type_codes[field_index];
-
   const flatbuffers::ElementaryType elementary_type =
-      static_cast<flatbuffers::ElementaryType>(type_code.base_type);
+      type.FieldElementaryType(field_index);
   switch (elementary_type) {
     case flatbuffers::ET_BOOL:
       fbb->AddElement<bool>(field_offset, int_value, 0);
@@ -530,25 +488,25 @@
       return true;
     case flatbuffers::ET_STRING:
     case flatbuffers::ET_UTYPE:
-    case flatbuffers::ET_SEQUENCE:
-      fprintf(
-          stderr, "Mismatched type for field '%s'. Got: integer, expected %s\n",
-          typetable->names[field_index], ElementaryTypeName(elementary_type));
+    case flatbuffers::ET_SEQUENCE: {
+      const std::string_view name = type.FieldName(field_index);
+      fprintf(stderr,
+              "Mismatched type for field '%.*s'. Got: integer, expected %s\n",
+              static_cast<int>(name.size()), name.data(),
+              ElementaryTypeName(elementary_type));
       return false;
+    }
   };
   return false;
 }
 
-bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
-                      double double_value,
+bool AddSingleElement(FlatbufferType type, int field_index, double double_value,
                       flatbuffers::FlatBufferBuilder *fbb) {
   flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
       static_cast<flatbuffers::voffset_t>(field_index));
 
-  flatbuffers::TypeCode type_code = typetable->type_codes[field_index];
-
   const flatbuffers::ElementaryType elementary_type =
-      static_cast<flatbuffers::ElementaryType>(type_code.base_type);
+      type.FieldElementaryType(field_index);
   switch (elementary_type) {
     case flatbuffers::ET_UTYPE:
     case flatbuffers::ET_BOOL:
@@ -561,11 +519,14 @@
     case flatbuffers::ET_LONG:
     case flatbuffers::ET_ULONG:
     case flatbuffers::ET_STRING:
-    case flatbuffers::ET_SEQUENCE:
-      fprintf(
-          stderr, "Mismatched type for field '%s'. Got: double, expected %s\n",
-          typetable->names[field_index], ElementaryTypeName(elementary_type));
+    case flatbuffers::ET_SEQUENCE: {
+      const std::string_view name = type.FieldName(field_index);
+      fprintf(stderr,
+              "Mismatched type for field '%.*s'. Got: double, expected %s\n",
+              static_cast<int>(name.size()), name.data(),
+              ElementaryTypeName(elementary_type));
       return false;
+    }
     case flatbuffers::ET_FLOAT:
       fbb->AddElement<float>(field_offset, double_value, 0);
       return true;
@@ -575,22 +536,20 @@
   }
   return false;
 }
-bool AddSingleElement(const flatbuffers::TypeTable *typetable, int field_index,
+bool AddSingleElement(FlatbufferType type, int field_index,
                       flatbuffers::Offset<flatbuffers::String> offset_element,
                       flatbuffers::FlatBufferBuilder *fbb) {
-  flatbuffers::TypeCode type_code = typetable->type_codes[field_index];
-
   flatbuffers::voffset_t field_offset = flatbuffers::FieldIndexToOffset(
       static_cast<flatbuffers::voffset_t>(field_index));
 
   // Vectors will always be Offset<>'s.
-  if (type_code.is_repeating) {
+  if (type.FieldIsRepeating(field_index)) {
     fbb->AddOffset(field_offset, offset_element);
     return true;
   }
 
   const flatbuffers::ElementaryType elementary_type =
-      static_cast<flatbuffers::ElementaryType>(type_code.base_type);
+      type.FieldElementaryType(field_index);
   switch (elementary_type) {
     case flatbuffers::ET_CHAR:
     case flatbuffers::ET_UCHAR:
@@ -603,16 +562,15 @@
     case flatbuffers::ET_UTYPE:
     case flatbuffers::ET_BOOL:
     case flatbuffers::ET_FLOAT:
-    case flatbuffers::ET_DOUBLE:
-      fprintf(
-          stderr, "Mismatched type for field '%s'. Got: string, expected %s\n",
-          typetable->names[field_index], ElementaryTypeName(elementary_type));
-      CHECK_EQ(type_code.sequence_ref, -1)
-          << ": Field name " << typetable->names[field_index]
-          << " Got string expected " << ElementaryTypeName(elementary_type);
+    case flatbuffers::ET_DOUBLE: {
+      const std::string_view name = type.FieldName(field_index);
+      fprintf(stderr,
+              "Mismatched type for field '%.*s'. Got: string, expected %s\n",
+              static_cast<int>(name.size()), name.data(),
+              ElementaryTypeName(elementary_type));
       return false;
+    }
     case flatbuffers::ET_STRING:
-      CHECK_EQ(type_code.sequence_ref, -1);
     case flatbuffers::ET_SEQUENCE:
       fbb->AddOffset(field_offset, offset_element);
       return true;
@@ -621,16 +579,12 @@
 }
 
 bool JsonParser::FinishVector(int field_index) {
-  flatbuffers::TypeCode type_code =
-      stack_.back().typetable->type_codes[field_index];
+  // Vectors have a start (unfortunately which needs to know the size)
+  fbb_->StartVector(stack_.back().vector_elements.size(),
+                    stack_.back().type.FieldInlineSize(field_index));
 
   const flatbuffers::ElementaryType elementary_type =
-      static_cast<flatbuffers::ElementaryType>(type_code.base_type);
-
-  // Vectors have a start (unfortunately which needs to know the size)
-  fbb_->StartVector(
-      stack_.back().vector_elements.size(),
-      flatbuffers::InlineSize(elementary_type, stack_.back().typetable));
+      stack_.back().type.FieldElementaryType(field_index);
 
   // Then the data (in reverse order for some reason...)
   for (size_t i = stack_.back().vector_elements.size(); i > 0;) {
@@ -640,8 +594,6 @@
         if (!PushElement(elementary_type, element.int_element)) return false;
         break;
       case Element::ElementType::DOUBLE:
-        CHECK_EQ(type_code.sequence_ref, -1)
-            << ": Field index is " << field_index;
         if (!PushElement(elementary_type, element.double_element)) return false;
         break;
       case Element::ElementType::OFFSET:
@@ -768,19 +720,19 @@
 }  // namespace
 
 flatbuffers::Offset<flatbuffers::Table> JsonToFlatbuffer(
-    const std::string_view data, const flatbuffers::TypeTable *typetable,
+    const std::string_view data, FlatbufferType type,
     flatbuffers::FlatBufferBuilder *fbb) {
   JsonParser p(fbb);
-  return p.Parse(data, typetable);
+  return p.Parse(data, type);
 }
 
-flatbuffers::DetachedBuffer JsonToFlatbuffer(
-    const std::string_view data, const flatbuffers::TypeTable *typetable) {
+flatbuffers::DetachedBuffer JsonToFlatbuffer(const std::string_view data,
+                                             FlatbufferType type) {
   flatbuffers::FlatBufferBuilder fbb;
   fbb.ForceDefaults(true);
 
   const flatbuffers::Offset<flatbuffers::Table> result =
-      JsonToFlatbuffer(data, typetable, &fbb);
+      JsonToFlatbuffer(data, type, &fbb);
   if (result.o != 0) {
     fbb.Finish(result);