• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "utils/flatbuffers/mutable.h"
18 
19 #include <vector>
20 
21 #include "utils/flatbuffers/reflection.h"
22 #include "utils/strings/numbers.h"
23 #include "utils/variant.h"
24 #include "flatbuffers/reflection_generated.h"
25 
26 namespace libtextclassifier3 {
27 namespace {
28 
Parse(const std::string & str_value,float * value)29 bool Parse(const std::string& str_value, float* value) {
30   double double_value;
31   if (!ParseDouble(str_value.data(), &double_value)) {
32     return false;
33   }
34   *value = static_cast<float>(double_value);
35   return true;
36 }
37 
Parse(const std::string & str_value,double * value)38 bool Parse(const std::string& str_value, double* value) {
39   return ParseDouble(str_value.data(), value);
40 }
41 
Parse(const std::string & str_value,int64 * value)42 bool Parse(const std::string& str_value, int64* value) {
43   return ParseInt64(str_value.data(), value);
44 }
45 
Parse(const std::string & str_value,int32 * value)46 bool Parse(const std::string& str_value, int32* value) {
47   return ParseInt32(str_value.data(), value);
48 }
49 
Parse(const std::string & str_value,std::string * value)50 bool Parse(const std::string& str_value, std::string* value) {
51   *value = str_value;
52   return true;
53 }
54 
55 template <typename T>
ParseAndSetField(const reflection::Field * field,const std::string & str_value,MutableFlatbuffer * buffer)56 bool ParseAndSetField(const reflection::Field* field,
57                       const std::string& str_value, MutableFlatbuffer* buffer) {
58   T value;
59   if (!Parse(str_value, &value)) {
60     TC3_LOG(ERROR) << "Could not parse '" << str_value << "'";
61     return false;
62   }
63   if (field->type()->base_type() == reflection::Vector) {
64     buffer->Repeated(field)->Add(value);
65     return true;
66   } else {
67     return buffer->Set<T>(field, value);
68   }
69 }
70 
71 }  // namespace
72 
MutableFlatbufferBuilder(const reflection::Schema * schema,StringPiece root_type)73 MutableFlatbufferBuilder::MutableFlatbufferBuilder(
74     const reflection::Schema* schema, StringPiece root_type)
75     : schema_(schema), root_type_(TypeForName(schema, root_type)) {}
76 
NewRoot() const77 std::unique_ptr<MutableFlatbuffer> MutableFlatbufferBuilder::NewRoot() const {
78   return NewTable(root_type_);
79 }
80 
NewTable(StringPiece table_name) const81 std::unique_ptr<MutableFlatbuffer> MutableFlatbufferBuilder::NewTable(
82     StringPiece table_name) const {
83   return NewTable(TypeForName(schema_, table_name));
84 }
85 
NewTable(const int type_id) const86 std::unique_ptr<MutableFlatbuffer> MutableFlatbufferBuilder::NewTable(
87     const int type_id) const {
88   if (type_id < 0 || type_id >= schema_->objects()->size()) {
89     TC3_LOG(ERROR) << "Invalid type id: " << type_id;
90     return nullptr;
91   }
92   return NewTable(schema_->objects()->Get(type_id));
93 }
94 
NewTable(const reflection::Object * type) const95 std::unique_ptr<MutableFlatbuffer> MutableFlatbufferBuilder::NewTable(
96     const reflection::Object* type) const {
97   if (type == nullptr) {
98     return nullptr;
99   }
100   return std::make_unique<MutableFlatbuffer>(schema_, type);
101 }
102 
GetFieldOrNull(const StringPiece field_name) const103 const reflection::Field* MutableFlatbuffer::GetFieldOrNull(
104     const StringPiece field_name) const {
105   return libtextclassifier3::GetFieldOrNull(type_, field_name);
106 }
107 
GetFieldOrNull(const FlatbufferField * field) const108 const reflection::Field* MutableFlatbuffer::GetFieldOrNull(
109     const FlatbufferField* field) const {
110   return libtextclassifier3::GetFieldOrNull(type_, field);
111 }
112 
GetFieldWithParent(const FlatbufferFieldPath * field_path,MutableFlatbuffer ** parent,reflection::Field const ** field)113 bool MutableFlatbuffer::GetFieldWithParent(
114     const FlatbufferFieldPath* field_path, MutableFlatbuffer** parent,
115     reflection::Field const** field) {
116   const auto* path = field_path->field();
117   if (path == nullptr || path->size() == 0) {
118     return false;
119   }
120 
121   for (int i = 0; i < path->size(); i++) {
122     *parent = (i == 0 ? this : (*parent)->Mutable(*field));
123     if (*parent == nullptr) {
124       return false;
125     }
126     *field = (*parent)->GetFieldOrNull(path->Get(i));
127     if (*field == nullptr) {
128       return false;
129     }
130   }
131 
132   return true;
133 }
134 
GetFieldOrNull(const int field_offset) const135 const reflection::Field* MutableFlatbuffer::GetFieldOrNull(
136     const int field_offset) const {
137   return libtextclassifier3::GetFieldOrNull(type_, field_offset);
138 }
139 
SetFromEnumValueName(const reflection::Field * field,StringPiece value_name)140 bool MutableFlatbuffer::SetFromEnumValueName(const reflection::Field* field,
141                                              StringPiece value_name) {
142   if (!IsEnum(field->type())) {
143     return false;
144   }
145   Variant variant_value = ParseEnumValue(schema_, field->type(), value_name);
146   if (!variant_value.HasValue()) {
147     return false;
148   }
149   fields_[field] = variant_value;
150   return true;
151 }
152 
SetFromEnumValueName(StringPiece field_name,StringPiece value_name)153 bool MutableFlatbuffer::SetFromEnumValueName(StringPiece field_name,
154                                              StringPiece value_name) {
155   if (const reflection::Field* field = GetFieldOrNull(field_name)) {
156     return SetFromEnumValueName(field, value_name);
157   }
158   return false;
159 }
160 
SetFromEnumValueName(const FlatbufferFieldPath * path,StringPiece value_name)161 bool MutableFlatbuffer::SetFromEnumValueName(const FlatbufferFieldPath* path,
162                                              StringPiece value_name) {
163   MutableFlatbuffer* parent;
164   const reflection::Field* field;
165   if (!GetFieldWithParent(path, &parent, &field)) {
166     return false;
167   }
168   return parent->SetFromEnumValueName(field, value_name);
169 }
170 
ParseAndSet(const reflection::Field * field,const std::string & value)171 bool MutableFlatbuffer::ParseAndSet(const reflection::Field* field,
172                                     const std::string& value) {
173   // Try parsing as an enum value.
174   if (IsEnum(field->type()) && SetFromEnumValueName(field, value)) {
175     return true;
176   }
177   switch (field->type()->base_type() == reflection::Vector
178               ? field->type()->element()
179               : field->type()->base_type()) {
180     case reflection::String:
181       return ParseAndSetField<std::string>(field, value, this);
182     case reflection::Int:
183       return ParseAndSetField<int32>(field, value, this);
184     case reflection::Long:
185       return ParseAndSetField<int64>(field, value, this);
186     case reflection::Float:
187       return ParseAndSetField<float>(field, value, this);
188     case reflection::Double:
189       return ParseAndSetField<double>(field, value, this);
190     default:
191       TC3_LOG(ERROR) << "Unhandled field type: " << field->type()->base_type();
192       return false;
193   }
194 }
195 
ParseAndSet(const FlatbufferFieldPath * path,const std::string & value)196 bool MutableFlatbuffer::ParseAndSet(const FlatbufferFieldPath* path,
197                                     const std::string& value) {
198   MutableFlatbuffer* parent;
199   const reflection::Field* field;
200   if (!GetFieldWithParent(path, &parent, &field)) {
201     return false;
202   }
203   return parent->ParseAndSet(field, value);
204 }
205 
Add(StringPiece field_name)206 MutableFlatbuffer* MutableFlatbuffer::Add(StringPiece field_name) {
207   const reflection::Field* field = GetFieldOrNull(field_name);
208   if (field == nullptr) {
209     return nullptr;
210   }
211 
212   if (field->type()->base_type() != reflection::BaseType::Vector) {
213     return nullptr;
214   }
215 
216   return Add(field);
217 }
218 
Add(const reflection::Field * field)219 MutableFlatbuffer* MutableFlatbuffer::Add(const reflection::Field* field) {
220   if (field == nullptr) {
221     return nullptr;
222   }
223   return Repeated(field)->Add();
224 }
225 
Mutable(const StringPiece field_name)226 MutableFlatbuffer* MutableFlatbuffer::Mutable(const StringPiece field_name) {
227   if (const reflection::Field* field = GetFieldOrNull(field_name)) {
228     return Mutable(field);
229   }
230   TC3_LOG(ERROR) << "Unknown field: " << field_name.ToString();
231   return nullptr;
232 }
233 
Mutable(const reflection::Field * field)234 MutableFlatbuffer* MutableFlatbuffer::Mutable(const reflection::Field* field) {
235   if (field->type()->base_type() != reflection::Obj) {
236     return nullptr;
237   }
238   const auto entry = children_.find(field);
239   if (entry != children_.end()) {
240     return entry->second.get();
241   }
242   const auto it = children_.insert(
243       /*hint=*/entry,
244       std::make_pair(
245           field,
246           std::unique_ptr<MutableFlatbuffer>(new MutableFlatbuffer(
247               schema_, schema_->objects()->Get(field->type()->index())))));
248   return it->second.get();
249 }
250 
Mutable(const FlatbufferFieldPath * path)251 MutableFlatbuffer* MutableFlatbuffer::Mutable(const FlatbufferFieldPath* path) {
252   const auto* field_path = path->field();
253   if (field_path == nullptr || field_path->size() == 0) {
254     return this;
255   }
256   MutableFlatbuffer* object = this;
257   for (int i = 0; i < field_path->size(); i++) {
258     const reflection::Field* field = object->GetFieldOrNull(field_path->Get(i));
259     if (field == nullptr) {
260       return nullptr;
261     }
262     object = object->Mutable(field);
263     if (object == nullptr) {
264       return nullptr;
265     }
266   }
267   return object;
268 }
269 
Repeated(StringPiece field_name)270 RepeatedField* MutableFlatbuffer::Repeated(StringPiece field_name) {
271   if (const reflection::Field* field = GetFieldOrNull(field_name)) {
272     return Repeated(field);
273   }
274   TC3_LOG(ERROR) << "Unknown field: " << field_name.ToString();
275   return nullptr;
276 }
277 
Repeated(const reflection::Field * field)278 RepeatedField* MutableFlatbuffer::Repeated(const reflection::Field* field) {
279   if (field->type()->base_type() != reflection::Vector) {
280     TC3_LOG(ERROR) << "Field is not of type Vector.";
281     return nullptr;
282   }
283 
284   // If the repeated field was already set, return its instance.
285   const auto entry = repeated_fields_.find(field);
286   if (entry != repeated_fields_.end()) {
287     return entry->second.get();
288   }
289 
290   // Otherwise, create a new instance and store it.
291   std::unique_ptr<RepeatedField> repeated_field(
292       new RepeatedField(schema_, field));
293   const auto it = repeated_fields_.insert(
294       /*hint=*/entry, std::make_pair(field, std::move(repeated_field)));
295   return it->second.get();
296 }
297 
Repeated(const FlatbufferFieldPath * path)298 RepeatedField* MutableFlatbuffer::Repeated(const FlatbufferFieldPath* path) {
299   MutableFlatbuffer* parent;
300   const reflection::Field* field;
301   if (!GetFieldWithParent(path, &parent, &field)) {
302     return nullptr;
303   }
304   return parent->Repeated(field);
305 }
306 
Serialize(flatbuffers::FlatBufferBuilder * builder) const307 flatbuffers::uoffset_t MutableFlatbuffer::Serialize(
308     flatbuffers::FlatBufferBuilder* builder) const {
309   // Build all children before we can start with this table.
310   std::vector<
311       std::pair</* field vtable offset */ int,
312                 /* field data offset in buffer */ flatbuffers::uoffset_t>>
313       offsets;
314   offsets.reserve(children_.size() + repeated_fields_.size());
315   for (const auto& it : children_) {
316     offsets.push_back({it.first->offset(), it.second->Serialize(builder)});
317   }
318 
319   // Create strings.
320   for (const auto& it : fields_) {
321     if (it.second.Has<std::string>()) {
322       offsets.push_back(
323           {it.first->offset(),
324            builder->CreateString(it.second.ConstRefValue<std::string>()).o});
325     }
326   }
327 
328   // Build the repeated fields.
329   for (const auto& it : repeated_fields_) {
330     offsets.push_back({it.first->offset(), it.second->Serialize(builder)});
331   }
332 
333   // Build the table now.
334   const flatbuffers::uoffset_t table_start = builder->StartTable();
335 
336   // Add scalar fields.
337   for (const auto& it : fields_) {
338     switch (it.second.GetType()) {
339       case Variant::TYPE_BOOL_VALUE:
340         builder->AddElement<uint8_t>(
341             it.first->offset(), static_cast<uint8_t>(it.second.Value<bool>()),
342             static_cast<uint8_t>(it.first->default_integer()));
343         continue;
344       case Variant::TYPE_INT8_VALUE:
345         builder->AddElement<int8_t>(
346             it.first->offset(), static_cast<int8_t>(it.second.Value<int8>()),
347             static_cast<int8_t>(it.first->default_integer()));
348         continue;
349       case Variant::TYPE_UINT8_VALUE:
350         builder->AddElement<uint8_t>(
351             it.first->offset(), static_cast<uint8_t>(it.second.Value<uint8>()),
352             static_cast<uint8_t>(it.first->default_integer()));
353         continue;
354       case Variant::TYPE_INT_VALUE:
355         builder->AddElement<int32>(
356             it.first->offset(), it.second.Value<int>(),
357             static_cast<int32>(it.first->default_integer()));
358         continue;
359       case Variant::TYPE_UINT_VALUE:
360         builder->AddElement<uint32>(
361             it.first->offset(), it.second.Value<uint>(),
362             static_cast<uint32>(it.first->default_integer()));
363         continue;
364       case Variant::TYPE_INT64_VALUE:
365         builder->AddElement<int64>(it.first->offset(), it.second.Value<int64>(),
366                                    it.first->default_integer());
367         continue;
368       case Variant::TYPE_UINT64_VALUE:
369         builder->AddElement<uint64>(it.first->offset(),
370                                     it.second.Value<uint64>(),
371                                     it.first->default_integer());
372         continue;
373       case Variant::TYPE_FLOAT_VALUE:
374         builder->AddElement<float>(
375             it.first->offset(), it.second.Value<float>(),
376             static_cast<float>(it.first->default_real()));
377         continue;
378       case Variant::TYPE_DOUBLE_VALUE:
379         builder->AddElement<double>(it.first->offset(),
380                                     it.second.Value<double>(),
381                                     it.first->default_real());
382         continue;
383       default:
384         continue;
385     }
386   }
387 
388   // Add strings, subtables and repeated fields.
389   for (const auto& it : offsets) {
390     builder->AddOffset(it.first, flatbuffers::Offset<void>(it.second));
391   }
392 
393   return builder->EndTable(table_start);
394 }
395 
Serialize() const396 std::string MutableFlatbuffer::Serialize() const {
397   flatbuffers::FlatBufferBuilder builder;
398   builder.Finish(flatbuffers::Offset<void>(Serialize(&builder)));
399   return std::string(reinterpret_cast<const char*>(builder.GetBufferPointer()),
400                      builder.GetSize());
401 }
402 
MergeFrom(const flatbuffers::Table * from)403 bool MutableFlatbuffer::MergeFrom(const flatbuffers::Table* from) {
404   // No fields to set.
405   if (type_->fields() == nullptr) {
406     return true;
407   }
408 
409   for (const reflection::Field* field : *type_->fields()) {
410     // Skip fields that are not explicitly set.
411     if (!from->CheckField(field->offset())) {
412       continue;
413     }
414     const reflection::BaseType type = field->type()->base_type();
415     switch (type) {
416       case reflection::Bool:
417         Set<bool>(field, from->GetField<uint8_t>(field->offset(),
418                                                  field->default_integer()));
419         break;
420       case reflection::Byte:
421         Set<int8_t>(field, from->GetField<int8_t>(field->offset(),
422                                                   field->default_integer()));
423         break;
424       case reflection::UByte:
425         Set<uint8_t>(field, from->GetField<uint8_t>(field->offset(),
426                                                     field->default_integer()));
427         break;
428       case reflection::Int:
429         Set<int32>(field, from->GetField<int32>(field->offset(),
430                                                 field->default_integer()));
431         break;
432       case reflection::UInt:
433         Set<uint32>(field, from->GetField<uint32>(field->offset(),
434                                                   field->default_integer()));
435         break;
436       case reflection::Long:
437         Set<int64>(field, from->GetField<int64>(field->offset(),
438                                                 field->default_integer()));
439         break;
440       case reflection::ULong:
441         Set<uint64>(field, from->GetField<uint64>(field->offset(),
442                                                   field->default_integer()));
443         break;
444       case reflection::Float:
445         Set<float>(field, from->GetField<float>(field->offset(),
446                                                 field->default_real()));
447         break;
448       case reflection::Double:
449         Set<double>(field, from->GetField<double>(field->offset(),
450                                                   field->default_real()));
451         break;
452       case reflection::String:
453         Set<std::string>(
454             field, from->GetPointer<const flatbuffers::String*>(field->offset())
455                        ->str());
456         break;
457       case reflection::Obj:
458         if (MutableFlatbuffer* nested_field = Mutable(field);
459             nested_field == nullptr ||
460             !nested_field->MergeFrom(
461                 from->GetPointer<const flatbuffers::Table* const>(
462                     field->offset()))) {
463           return false;
464         }
465         break;
466       case reflection::Vector: {
467         if (RepeatedField* repeated_field = Repeated(field);
468             repeated_field == nullptr || !repeated_field->Extend(from)) {
469           return false;
470         }
471         break;
472       }
473       default:
474         TC3_LOG(ERROR) << "Unsupported type: " << type
475                        << " for field: " << field->name()->str();
476         return false;
477     }
478   }
479   return true;
480 }
481 
MergeFromSerializedFlatbuffer(StringPiece from)482 bool MutableFlatbuffer::MergeFromSerializedFlatbuffer(StringPiece from) {
483   return MergeFrom(flatbuffers::GetAnyRoot(
484       reinterpret_cast<const unsigned char*>(from.data())));
485 }
486 
AsFlatMap(const std::string & key_separator,const std::string & key_prefix,std::map<std::string,Variant> * result) const487 void MutableFlatbuffer::AsFlatMap(
488     const std::string& key_separator, const std::string& key_prefix,
489     std::map<std::string, Variant>* result) const {
490   // Add direct fields.
491   for (const auto& it : fields_) {
492     (*result)[key_prefix + it.first->name()->str()] = it.second;
493   }
494 
495   // Add nested messages.
496   for (const auto& it : children_) {
497     it.second->AsFlatMap(key_separator,
498                          key_prefix + it.first->name()->str() + key_separator,
499                          result);
500   }
501 }
502 
ToTextProto() const503 std::string RepeatedField::ToTextProto() const {
504   std::string result = " [";
505   std::string current_field_separator;
506   for (int index = 0; index < Size(); index++) {
507     if (is_primitive_) {
508       result.append(current_field_separator + items_.at(index).ToString());
509     } else {
510       result.append(current_field_separator + "{" +
511                     Get<MutableFlatbuffer*>(index)->ToTextProto() + "}");
512     }
513     current_field_separator = ", ";
514   }
515   result.append("] ");
516   return result;
517 }
518 
ToTextProto() const519 std::string MutableFlatbuffer::ToTextProto() const {
520   std::string result;
521   std::string current_field_separator;
522   // Add direct fields.
523   for (const auto& field_value_pair : fields_) {
524     const std::string field_name = field_value_pair.first->name()->str();
525     const Variant& value = field_value_pair.second;
526     std::string quotes;
527     if (value.GetType() == Variant::TYPE_STRING_VALUE) {
528       quotes = "'";
529     }
530     result.append(current_field_separator + field_name + ": " + quotes +
531                   value.ToString() + quotes);
532     current_field_separator = ", ";
533   }
534 
535   // Add repeated message
536   for (const auto& repeated_fb_pair : repeated_fields_) {
537     result.append(current_field_separator +
538                   repeated_fb_pair.first->name()->c_str() + ": " +
539                   repeated_fb_pair.second->ToTextProto());
540     current_field_separator = ", ";
541   }
542 
543   // Add nested messages.
544   for (const auto& field_flatbuffer_pair : children_) {
545     const std::string field_name = field_flatbuffer_pair.first->name()->str();
546     result.append(current_field_separator + field_name + " {" +
547                   field_flatbuffer_pair.second->ToTextProto() + "}");
548     current_field_separator = ", ";
549   }
550 
551   return result;
552 }
553 
554 //
555 // Repeated field methods.
556 //
557 
Add()558 MutableFlatbuffer* RepeatedField::Add() {
559   if (is_primitive_) {
560     TC3_LOG(ERROR) << "Trying to add sub-message on a primitive-typed field.";
561     return nullptr;
562   }
563 
564   object_items_.emplace_back(new MutableFlatbuffer(
565       schema_, schema_->objects()->Get(field_->type()->index())));
566   return object_items_.back().get();
567 }
568 
569 namespace {
570 
571 template <typename T>
TypedSerialize(const std::vector<Variant> & values,flatbuffers::FlatBufferBuilder * builder)572 flatbuffers::uoffset_t TypedSerialize(const std::vector<Variant>& values,
573                                       flatbuffers::FlatBufferBuilder* builder) {
574   std::vector<T> typed_values;
575   typed_values.reserve(values.size());
576   for (const Variant& item : values) {
577     typed_values.push_back(item.Value<T>());
578   }
579   return builder->CreateVector(typed_values).o;
580 }
581 
582 }  // namespace
583 
Extend(const flatbuffers::Table * from)584 bool RepeatedField::Extend(const flatbuffers::Table* from) {
585   switch (field_->type()->element()) {
586     case reflection::Int:
587       AppendFromVector<int32>(from);
588       return true;
589     case reflection::UInt:
590       AppendFromVector<uint>(from);
591       return true;
592     case reflection::Long:
593       AppendFromVector<int64>(from);
594       return true;
595     case reflection::ULong:
596       AppendFromVector<uint64>(from);
597       return true;
598     case reflection::Byte:
599       AppendFromVector<int8_t>(from);
600       return true;
601     case reflection::UByte:
602       AppendFromVector<uint8_t>(from);
603       return true;
604     case reflection::String:
605       AppendFromVector<std::string>(from);
606       return true;
607     case reflection::Obj:
608       AppendFromVector<MutableFlatbuffer>(from);
609       return true;
610     case reflection::Double:
611       AppendFromVector<double>(from);
612       return true;
613     case reflection::Float:
614       AppendFromVector<float>(from);
615       return true;
616     default:
617       TC3_LOG(ERROR) << "Repeated unsupported type: "
618                      << field_->type()->element()
619                      << " for field: " << field_->name()->str();
620       return false;
621   }
622 }
623 
Serialize(flatbuffers::FlatBufferBuilder * builder) const624 flatbuffers::uoffset_t RepeatedField::Serialize(
625     flatbuffers::FlatBufferBuilder* builder) const {
626   switch (field_->type()->element()) {
627     case reflection::String:
628       return SerializeString(builder);
629       break;
630     case reflection::Obj:
631       return SerializeObject(builder);
632       break;
633     case reflection::Bool:
634       return TypedSerialize<bool>(items_, builder);
635       break;
636     case reflection::Byte:
637       return TypedSerialize<int8_t>(items_, builder);
638       break;
639     case reflection::UByte:
640       return TypedSerialize<uint8_t>(items_, builder);
641       break;
642     case reflection::Int:
643       return TypedSerialize<int>(items_, builder);
644       break;
645     case reflection::UInt:
646       return TypedSerialize<uint>(items_, builder);
647       break;
648     case reflection::Long:
649       return TypedSerialize<int64>(items_, builder);
650       break;
651     case reflection::ULong:
652       return TypedSerialize<uint64>(items_, builder);
653       break;
654     case reflection::Float:
655       return TypedSerialize<float>(items_, builder);
656       break;
657     case reflection::Double:
658       return TypedSerialize<double>(items_, builder);
659       break;
660     default:
661       TC3_LOG(FATAL) << "Unsupported type: " << field_->type()->element();
662       break;
663   }
664   TC3_LOG(FATAL) << "Invalid state.";
665   return 0;
666 }
667 
SerializeString(flatbuffers::FlatBufferBuilder * builder) const668 flatbuffers::uoffset_t RepeatedField::SerializeString(
669     flatbuffers::FlatBufferBuilder* builder) const {
670   std::vector<flatbuffers::Offset<flatbuffers::String>> offsets(items_.size());
671   for (int i = 0; i < items_.size(); i++) {
672     offsets[i] = builder->CreateString(items_[i].ConstRefValue<std::string>());
673   }
674   return builder->CreateVector(offsets).o;
675 }
676 
SerializeObject(flatbuffers::FlatBufferBuilder * builder) const677 flatbuffers::uoffset_t RepeatedField::SerializeObject(
678     flatbuffers::FlatBufferBuilder* builder) const {
679   std::vector<flatbuffers::Offset<void>> offsets(object_items_.size());
680   for (int i = 0; i < object_items_.size(); i++) {
681     offsets[i] = object_items_[i]->Serialize(builder);
682   }
683   return builder->CreateVector(offsets).o;
684 }
685 
686 }  // namespace libtextclassifier3
687