xref: /aosp_15_r20/external/libtextclassifier/native/utils/flatbuffers/mutable.h (revision 993b0882672172b81d12fad7a7ac0c3e5c824a12)
1*993b0882SAndroid Build Coastguard Worker /*
2*993b0882SAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*993b0882SAndroid Build Coastguard Worker  *
4*993b0882SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*993b0882SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*993b0882SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*993b0882SAndroid Build Coastguard Worker  *
8*993b0882SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*993b0882SAndroid Build Coastguard Worker  *
10*993b0882SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*993b0882SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*993b0882SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*993b0882SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*993b0882SAndroid Build Coastguard Worker  * limitations under the License.
15*993b0882SAndroid Build Coastguard Worker  */
16*993b0882SAndroid Build Coastguard Worker 
17*993b0882SAndroid Build Coastguard Worker #ifndef LIBTEXTCLASSIFIER_UTILS_FLATBUFFERS_MUTABLE_H_
18*993b0882SAndroid Build Coastguard Worker #define LIBTEXTCLASSIFIER_UTILS_FLATBUFFERS_MUTABLE_H_
19*993b0882SAndroid Build Coastguard Worker 
20*993b0882SAndroid Build Coastguard Worker #include <memory>
21*993b0882SAndroid Build Coastguard Worker #include <string>
22*993b0882SAndroid Build Coastguard Worker #include <unordered_map>
23*993b0882SAndroid Build Coastguard Worker 
24*993b0882SAndroid Build Coastguard Worker #include "annotator/model_generated.h"
25*993b0882SAndroid Build Coastguard Worker #include "utils/base/logging.h"
26*993b0882SAndroid Build Coastguard Worker #include "utils/flatbuffers/flatbuffers_generated.h"
27*993b0882SAndroid Build Coastguard Worker #include "utils/flatbuffers/reflection.h"
28*993b0882SAndroid Build Coastguard Worker #include "utils/strings/stringpiece.h"
29*993b0882SAndroid Build Coastguard Worker #include "utils/variant.h"
30*993b0882SAndroid Build Coastguard Worker #include "flatbuffers/flatbuffers.h"
31*993b0882SAndroid Build Coastguard Worker #include "flatbuffers/reflection.h"
32*993b0882SAndroid Build Coastguard Worker #include "flatbuffers/reflection_generated.h"
33*993b0882SAndroid Build Coastguard Worker 
34*993b0882SAndroid Build Coastguard Worker namespace libtextclassifier3 {
35*993b0882SAndroid Build Coastguard Worker 
36*993b0882SAndroid Build Coastguard Worker class MutableFlatbuffer;
37*993b0882SAndroid Build Coastguard Worker class RepeatedField;
38*993b0882SAndroid Build Coastguard Worker 
39*993b0882SAndroid Build Coastguard Worker template <typename T>
IsStringType()40*993b0882SAndroid Build Coastguard Worker constexpr bool IsStringType() {
41*993b0882SAndroid Build Coastguard Worker   return std::is_same<T, std::string>::value ||
42*993b0882SAndroid Build Coastguard Worker          std::is_same<T, StringPiece>::value ||
43*993b0882SAndroid Build Coastguard Worker          std::is_same<T, const char*>::value;
44*993b0882SAndroid Build Coastguard Worker }
45*993b0882SAndroid Build Coastguard Worker 
46*993b0882SAndroid Build Coastguard Worker // Checks whether a variant value type agrees with a field type.
47*993b0882SAndroid Build Coastguard Worker template <typename T>
IsMatchingType(const reflection::BaseType type)48*993b0882SAndroid Build Coastguard Worker bool IsMatchingType(const reflection::BaseType type) {
49*993b0882SAndroid Build Coastguard Worker   switch (type) {
50*993b0882SAndroid Build Coastguard Worker     case reflection::String:
51*993b0882SAndroid Build Coastguard Worker       return IsStringType<T>();
52*993b0882SAndroid Build Coastguard Worker     case reflection::Obj:
53*993b0882SAndroid Build Coastguard Worker       return std::is_same<T, MutableFlatbuffer>::value;
54*993b0882SAndroid Build Coastguard Worker     default:
55*993b0882SAndroid Build Coastguard Worker       return type == flatbuffers_base_type<T>::value;
56*993b0882SAndroid Build Coastguard Worker   }
57*993b0882SAndroid Build Coastguard Worker }
58*993b0882SAndroid Build Coastguard Worker 
59*993b0882SAndroid Build Coastguard Worker // A mutable flatbuffer that can be built using flatbuffer reflection data of
60*993b0882SAndroid Build Coastguard Worker // the schema. Normally, field information is hard-coded in code generated from
61*993b0882SAndroid Build Coastguard Worker // a flatbuffer schema. Here we lookup the necessary information for building a
62*993b0882SAndroid Build Coastguard Worker // flatbuffer from the provided reflection meta data. When serializing a
63*993b0882SAndroid Build Coastguard Worker // flatbuffer, the library requires that the sub messages are already
64*993b0882SAndroid Build Coastguard Worker // serialized, therefore we explicitly keep the field values and serialize the
65*993b0882SAndroid Build Coastguard Worker // message in (reverse) topological dependency order.
66*993b0882SAndroid Build Coastguard Worker class MutableFlatbuffer {
67*993b0882SAndroid Build Coastguard Worker  public:
MutableFlatbuffer(const reflection::Schema * schema,const reflection::Object * type)68*993b0882SAndroid Build Coastguard Worker   MutableFlatbuffer(const reflection::Schema* schema,
69*993b0882SAndroid Build Coastguard Worker                     const reflection::Object* type)
70*993b0882SAndroid Build Coastguard Worker       : schema_(schema), type_(type) {}
71*993b0882SAndroid Build Coastguard Worker 
72*993b0882SAndroid Build Coastguard Worker   // Gets the field information for a field name, returns nullptr if the
73*993b0882SAndroid Build Coastguard Worker   // field was not defined.
74*993b0882SAndroid Build Coastguard Worker   const reflection::Field* GetFieldOrNull(const StringPiece field_name) const;
75*993b0882SAndroid Build Coastguard Worker   const reflection::Field* GetFieldOrNull(const FlatbufferField* field) const;
76*993b0882SAndroid Build Coastguard Worker   const reflection::Field* GetFieldOrNull(const int field_offset) const;
77*993b0882SAndroid Build Coastguard Worker 
78*993b0882SAndroid Build Coastguard Worker   // Gets a nested field and the message it is defined on.
79*993b0882SAndroid Build Coastguard Worker   bool GetFieldWithParent(const FlatbufferFieldPath* field_path,
80*993b0882SAndroid Build Coastguard Worker                           MutableFlatbuffer** parent,
81*993b0882SAndroid Build Coastguard Worker                           reflection::Field const** field);
82*993b0882SAndroid Build Coastguard Worker 
83*993b0882SAndroid Build Coastguard Worker   // Sets a field to a specific value.
84*993b0882SAndroid Build Coastguard Worker   // Returns true if successful, and false if the field was not found or the
85*993b0882SAndroid Build Coastguard Worker   // expected type doesn't match.
86*993b0882SAndroid Build Coastguard Worker   template <typename T>
87*993b0882SAndroid Build Coastguard Worker   bool Set(StringPiece field_name, T value);
88*993b0882SAndroid Build Coastguard Worker 
89*993b0882SAndroid Build Coastguard Worker   // Sets a field to a specific value.
90*993b0882SAndroid Build Coastguard Worker   // Returns true if successful, and false if the expected type doesn't match.
91*993b0882SAndroid Build Coastguard Worker   // Expects `field` to be non-null.
92*993b0882SAndroid Build Coastguard Worker   template <typename T>
93*993b0882SAndroid Build Coastguard Worker   bool Set(const reflection::Field* field, T value);
94*993b0882SAndroid Build Coastguard Worker 
95*993b0882SAndroid Build Coastguard Worker   // Sets a field to a specific value. Field is specified by path.
96*993b0882SAndroid Build Coastguard Worker   template <typename T>
97*993b0882SAndroid Build Coastguard Worker   bool Set(const FlatbufferFieldPath* path, T value);
98*993b0882SAndroid Build Coastguard Worker 
99*993b0882SAndroid Build Coastguard Worker   // Sets an enum field from an enum value name.
100*993b0882SAndroid Build Coastguard Worker   // Returns true if the value could be successfully parsed.
101*993b0882SAndroid Build Coastguard Worker   bool SetFromEnumValueName(StringPiece field_name, StringPiece value_name);
102*993b0882SAndroid Build Coastguard Worker 
103*993b0882SAndroid Build Coastguard Worker   // Sets an enum field from an enum value name.
104*993b0882SAndroid Build Coastguard Worker   // Returns true if the value could be successfully parsed.
105*993b0882SAndroid Build Coastguard Worker   bool SetFromEnumValueName(const reflection::Field* field,
106*993b0882SAndroid Build Coastguard Worker                             StringPiece value_name);
107*993b0882SAndroid Build Coastguard Worker 
108*993b0882SAndroid Build Coastguard Worker   // Sets an enum field from an enum value name. Field is specified by path.
109*993b0882SAndroid Build Coastguard Worker   // Returns true if the value could be successfully parsed.
110*993b0882SAndroid Build Coastguard Worker   bool SetFromEnumValueName(const FlatbufferFieldPath* path,
111*993b0882SAndroid Build Coastguard Worker                             StringPiece value_name);
112*993b0882SAndroid Build Coastguard Worker 
113*993b0882SAndroid Build Coastguard Worker   // Sets sub-message field (if not set yet), and returns a pointer to it.
114*993b0882SAndroid Build Coastguard Worker   // Returns nullptr if the field was not found, or the field type was not a
115*993b0882SAndroid Build Coastguard Worker   // table.
116*993b0882SAndroid Build Coastguard Worker   MutableFlatbuffer* Mutable(StringPiece field_name);
117*993b0882SAndroid Build Coastguard Worker   MutableFlatbuffer* Mutable(const reflection::Field* field);
118*993b0882SAndroid Build Coastguard Worker 
119*993b0882SAndroid Build Coastguard Worker   // Sets a sub-message field (if not set yet) specified by path, and returns a
120*993b0882SAndroid Build Coastguard Worker   // pointer to it. Returns nullptr if the field was not found, or the field
121*993b0882SAndroid Build Coastguard Worker   // type was not a table.
122*993b0882SAndroid Build Coastguard Worker   MutableFlatbuffer* Mutable(const FlatbufferFieldPath* path);
123*993b0882SAndroid Build Coastguard Worker 
124*993b0882SAndroid Build Coastguard Worker   // Parses the value (according to the type) and sets a primitive field to the
125*993b0882SAndroid Build Coastguard Worker   // parsed value.
126*993b0882SAndroid Build Coastguard Worker   bool ParseAndSet(const reflection::Field* field, const std::string& value);
127*993b0882SAndroid Build Coastguard Worker   bool ParseAndSet(const FlatbufferFieldPath* path, const std::string& value);
128*993b0882SAndroid Build Coastguard Worker 
129*993b0882SAndroid Build Coastguard Worker   // Adds a primitive value to the repeated field.
130*993b0882SAndroid Build Coastguard Worker   template <typename T>
131*993b0882SAndroid Build Coastguard Worker   bool Add(StringPiece field_name, T value);
132*993b0882SAndroid Build Coastguard Worker 
133*993b0882SAndroid Build Coastguard Worker   // Add a sub-message to the repeated field.
134*993b0882SAndroid Build Coastguard Worker   MutableFlatbuffer* Add(StringPiece field_name);
135*993b0882SAndroid Build Coastguard Worker 
136*993b0882SAndroid Build Coastguard Worker   template <typename T>
137*993b0882SAndroid Build Coastguard Worker   bool Add(const reflection::Field* field, T value);
138*993b0882SAndroid Build Coastguard Worker 
139*993b0882SAndroid Build Coastguard Worker   MutableFlatbuffer* Add(const reflection::Field* field);
140*993b0882SAndroid Build Coastguard Worker 
141*993b0882SAndroid Build Coastguard Worker   // Gets the reflective flatbuffer for a repeated field.
142*993b0882SAndroid Build Coastguard Worker   // Returns nullptr if the field was not found, or the field type was not a
143*993b0882SAndroid Build Coastguard Worker   // vector.
144*993b0882SAndroid Build Coastguard Worker   RepeatedField* Repeated(StringPiece field_name);
145*993b0882SAndroid Build Coastguard Worker   RepeatedField* Repeated(const reflection::Field* field);
146*993b0882SAndroid Build Coastguard Worker 
147*993b0882SAndroid Build Coastguard Worker   // Gets a repeated field specified by path.
148*993b0882SAndroid Build Coastguard Worker   // Returns nullptr if the field was not found, or the field
149*993b0882SAndroid Build Coastguard Worker   // type was not a repeated field.
150*993b0882SAndroid Build Coastguard Worker   RepeatedField* Repeated(const FlatbufferFieldPath* path);
151*993b0882SAndroid Build Coastguard Worker 
152*993b0882SAndroid Build Coastguard Worker   // Serializes the flatbuffer.
153*993b0882SAndroid Build Coastguard Worker   flatbuffers::uoffset_t Serialize(
154*993b0882SAndroid Build Coastguard Worker       flatbuffers::FlatBufferBuilder* builder) const;
155*993b0882SAndroid Build Coastguard Worker   std::string Serialize() const;
156*993b0882SAndroid Build Coastguard Worker 
157*993b0882SAndroid Build Coastguard Worker   // Merges the fields from the given flatbuffer table into this flatbuffer.
158*993b0882SAndroid Build Coastguard Worker   // Scalar fields will be overwritten, if present in `from`.
159*993b0882SAndroid Build Coastguard Worker   // Embedded messages will be merged.
160*993b0882SAndroid Build Coastguard Worker   bool MergeFrom(const flatbuffers::Table* from);
161*993b0882SAndroid Build Coastguard Worker   bool MergeFromSerializedFlatbuffer(StringPiece from);
162*993b0882SAndroid Build Coastguard Worker 
163*993b0882SAndroid Build Coastguard Worker   // Flattens the flatbuffer as a flat map.
164*993b0882SAndroid Build Coastguard Worker   // (Nested) fields names are joined by `key_separator`.
165*993b0882SAndroid Build Coastguard Worker   std::map<std::string, Variant> AsFlatMap(
166*993b0882SAndroid Build Coastguard Worker       const std::string& key_separator = ".") const {
167*993b0882SAndroid Build Coastguard Worker     std::map<std::string, Variant> result;
168*993b0882SAndroid Build Coastguard Worker     AsFlatMap(key_separator, /*key_prefix=*/"", &result);
169*993b0882SAndroid Build Coastguard Worker     return result;
170*993b0882SAndroid Build Coastguard Worker   }
171*993b0882SAndroid Build Coastguard Worker 
172*993b0882SAndroid Build Coastguard Worker   // Converts the flatbuffer's content to a human-readable textproto
173*993b0882SAndroid Build Coastguard Worker   // representation.
174*993b0882SAndroid Build Coastguard Worker   std::string ToTextProto() const;
175*993b0882SAndroid Build Coastguard Worker 
HasExplicitlySetFields()176*993b0882SAndroid Build Coastguard Worker   bool HasExplicitlySetFields() const {
177*993b0882SAndroid Build Coastguard Worker     return !fields_.empty() || !children_.empty() || !repeated_fields_.empty();
178*993b0882SAndroid Build Coastguard Worker   }
179*993b0882SAndroid Build Coastguard Worker 
type()180*993b0882SAndroid Build Coastguard Worker   const reflection::Object* type() const { return type_; }
181*993b0882SAndroid Build Coastguard Worker 
182*993b0882SAndroid Build Coastguard Worker  private:
183*993b0882SAndroid Build Coastguard Worker   // Helper function for merging given repeated field from given flatbuffer
184*993b0882SAndroid Build Coastguard Worker   // table. Appends the elements.
185*993b0882SAndroid Build Coastguard Worker   template <typename T>
186*993b0882SAndroid Build Coastguard Worker   bool AppendFromVector(const flatbuffers::Table* from,
187*993b0882SAndroid Build Coastguard Worker                         const reflection::Field* field);
188*993b0882SAndroid Build Coastguard Worker 
189*993b0882SAndroid Build Coastguard Worker   // Flattens the flatbuffer as a flat map.
190*993b0882SAndroid Build Coastguard Worker   // (Nested) fields names are joined by `key_separator` and prefixed by
191*993b0882SAndroid Build Coastguard Worker   // `key_prefix`.
192*993b0882SAndroid Build Coastguard Worker   void AsFlatMap(const std::string& key_separator,
193*993b0882SAndroid Build Coastguard Worker                  const std::string& key_prefix,
194*993b0882SAndroid Build Coastguard Worker                  std::map<std::string, Variant>* result) const;
195*993b0882SAndroid Build Coastguard Worker 
196*993b0882SAndroid Build Coastguard Worker   const reflection::Schema* const schema_;
197*993b0882SAndroid Build Coastguard Worker   const reflection::Object* const type_;
198*993b0882SAndroid Build Coastguard Worker 
199*993b0882SAndroid Build Coastguard Worker   // Cached primitive fields (scalars and strings).
200*993b0882SAndroid Build Coastguard Worker   std::unordered_map<const reflection::Field*, Variant> fields_;
201*993b0882SAndroid Build Coastguard Worker 
202*993b0882SAndroid Build Coastguard Worker   // Cached sub-messages.
203*993b0882SAndroid Build Coastguard Worker   std::unordered_map<const reflection::Field*,
204*993b0882SAndroid Build Coastguard Worker                      std::unique_ptr<MutableFlatbuffer>>
205*993b0882SAndroid Build Coastguard Worker       children_;
206*993b0882SAndroid Build Coastguard Worker 
207*993b0882SAndroid Build Coastguard Worker   // Cached repeated fields.
208*993b0882SAndroid Build Coastguard Worker   std::unordered_map<const reflection::Field*, std::unique_ptr<RepeatedField>>
209*993b0882SAndroid Build Coastguard Worker       repeated_fields_;
210*993b0882SAndroid Build Coastguard Worker };
211*993b0882SAndroid Build Coastguard Worker 
212*993b0882SAndroid Build Coastguard Worker // A helper class to build flatbuffers based on schema reflection data.
213*993b0882SAndroid Build Coastguard Worker // Can be used to a `MutableFlatbuffer` for the root message of the
214*993b0882SAndroid Build Coastguard Worker // schema, or any defined table via name.
215*993b0882SAndroid Build Coastguard Worker class MutableFlatbufferBuilder {
216*993b0882SAndroid Build Coastguard Worker  public:
MutableFlatbufferBuilder(const reflection::Schema * schema)217*993b0882SAndroid Build Coastguard Worker   explicit MutableFlatbufferBuilder(const reflection::Schema* schema)
218*993b0882SAndroid Build Coastguard Worker       : schema_(schema), root_type_(schema->root_table()) {}
219*993b0882SAndroid Build Coastguard Worker   explicit MutableFlatbufferBuilder(const reflection::Schema* schema,
220*993b0882SAndroid Build Coastguard Worker                                     StringPiece root_type);
221*993b0882SAndroid Build Coastguard Worker 
222*993b0882SAndroid Build Coastguard Worker   // Starts a new root table message.
223*993b0882SAndroid Build Coastguard Worker   std::unique_ptr<MutableFlatbuffer> NewRoot() const;
224*993b0882SAndroid Build Coastguard Worker 
225*993b0882SAndroid Build Coastguard Worker   // Creates a new table message. Returns nullptr if no table with given name is
226*993b0882SAndroid Build Coastguard Worker   // found in the schema.
227*993b0882SAndroid Build Coastguard Worker   std::unique_ptr<MutableFlatbuffer> NewTable(
228*993b0882SAndroid Build Coastguard Worker       const StringPiece table_name) const;
229*993b0882SAndroid Build Coastguard Worker 
230*993b0882SAndroid Build Coastguard Worker   // Creates a new message for the given type id. Returns nullptr if the type is
231*993b0882SAndroid Build Coastguard Worker   // invalid.
232*993b0882SAndroid Build Coastguard Worker   std::unique_ptr<MutableFlatbuffer> NewTable(int type_id) const;
233*993b0882SAndroid Build Coastguard Worker 
234*993b0882SAndroid Build Coastguard Worker   // Creates a new message for the given type.
235*993b0882SAndroid Build Coastguard Worker   std::unique_ptr<MutableFlatbuffer> NewTable(
236*993b0882SAndroid Build Coastguard Worker       const reflection::Object* type) const;
237*993b0882SAndroid Build Coastguard Worker 
238*993b0882SAndroid Build Coastguard Worker  private:
239*993b0882SAndroid Build Coastguard Worker   const reflection::Schema* const schema_;
240*993b0882SAndroid Build Coastguard Worker   const reflection::Object* const root_type_;
241*993b0882SAndroid Build Coastguard Worker };
242*993b0882SAndroid Build Coastguard Worker 
243*993b0882SAndroid Build Coastguard Worker // Encapsulates a repeated field.
244*993b0882SAndroid Build Coastguard Worker // Serves as a common base class for repeated fields.
245*993b0882SAndroid Build Coastguard Worker class RepeatedField {
246*993b0882SAndroid Build Coastguard Worker  public:
RepeatedField(const reflection::Schema * const schema,const reflection::Field * field)247*993b0882SAndroid Build Coastguard Worker   RepeatedField(const reflection::Schema* const schema,
248*993b0882SAndroid Build Coastguard Worker                 const reflection::Field* field)
249*993b0882SAndroid Build Coastguard Worker       : schema_(schema),
250*993b0882SAndroid Build Coastguard Worker         field_(field),
251*993b0882SAndroid Build Coastguard Worker         is_primitive_(field->type()->element() != reflection::BaseType::Obj) {}
252*993b0882SAndroid Build Coastguard Worker 
253*993b0882SAndroid Build Coastguard Worker   template <typename T>
254*993b0882SAndroid Build Coastguard Worker   bool Add(const T value);
255*993b0882SAndroid Build Coastguard Worker 
256*993b0882SAndroid Build Coastguard Worker   MutableFlatbuffer* Add();
257*993b0882SAndroid Build Coastguard Worker 
258*993b0882SAndroid Build Coastguard Worker   template <typename T>
Get(int index)259*993b0882SAndroid Build Coastguard Worker   T Get(int index) const {
260*993b0882SAndroid Build Coastguard Worker     return items_.at(index).Value<T>();
261*993b0882SAndroid Build Coastguard Worker   }
262*993b0882SAndroid Build Coastguard Worker 
263*993b0882SAndroid Build Coastguard Worker   template <>
Get(int index)264*993b0882SAndroid Build Coastguard Worker   MutableFlatbuffer* Get(int index) const {
265*993b0882SAndroid Build Coastguard Worker     if (is_primitive_) {
266*993b0882SAndroid Build Coastguard Worker       TC3_LOG(ERROR) << "Trying to get primitive value out of non-primitive "
267*993b0882SAndroid Build Coastguard Worker                         "repeated field.";
268*993b0882SAndroid Build Coastguard Worker       return nullptr;
269*993b0882SAndroid Build Coastguard Worker     }
270*993b0882SAndroid Build Coastguard Worker     return object_items_.at(index).get();
271*993b0882SAndroid Build Coastguard Worker   }
272*993b0882SAndroid Build Coastguard Worker 
Size()273*993b0882SAndroid Build Coastguard Worker   int Size() const {
274*993b0882SAndroid Build Coastguard Worker     if (is_primitive_) {
275*993b0882SAndroid Build Coastguard Worker       return items_.size();
276*993b0882SAndroid Build Coastguard Worker     } else {
277*993b0882SAndroid Build Coastguard Worker       return object_items_.size();
278*993b0882SAndroid Build Coastguard Worker     }
279*993b0882SAndroid Build Coastguard Worker   }
280*993b0882SAndroid Build Coastguard Worker 
281*993b0882SAndroid Build Coastguard Worker   bool Extend(const flatbuffers::Table* from);
282*993b0882SAndroid Build Coastguard Worker 
283*993b0882SAndroid Build Coastguard Worker   flatbuffers::uoffset_t Serialize(
284*993b0882SAndroid Build Coastguard Worker       flatbuffers::FlatBufferBuilder* builder) const;
285*993b0882SAndroid Build Coastguard Worker 
286*993b0882SAndroid Build Coastguard Worker   std::string ToTextProto() const;
287*993b0882SAndroid Build Coastguard Worker 
288*993b0882SAndroid Build Coastguard Worker  private:
289*993b0882SAndroid Build Coastguard Worker   template <typename T>
290*993b0882SAndroid Build Coastguard Worker   bool AppendFromVector(const flatbuffers::Table* from);
291*993b0882SAndroid Build Coastguard Worker 
292*993b0882SAndroid Build Coastguard Worker   flatbuffers::uoffset_t SerializeString(
293*993b0882SAndroid Build Coastguard Worker       flatbuffers::FlatBufferBuilder* builder) const;
294*993b0882SAndroid Build Coastguard Worker   flatbuffers::uoffset_t SerializeObject(
295*993b0882SAndroid Build Coastguard Worker       flatbuffers::FlatBufferBuilder* builder) const;
296*993b0882SAndroid Build Coastguard Worker 
297*993b0882SAndroid Build Coastguard Worker   const reflection::Schema* const schema_;
298*993b0882SAndroid Build Coastguard Worker   const reflection::Field* field_;
299*993b0882SAndroid Build Coastguard Worker   bool is_primitive_;
300*993b0882SAndroid Build Coastguard Worker 
301*993b0882SAndroid Build Coastguard Worker   std::vector<Variant> items_;
302*993b0882SAndroid Build Coastguard Worker   std::vector<std::unique_ptr<MutableFlatbuffer>> object_items_;
303*993b0882SAndroid Build Coastguard Worker };
304*993b0882SAndroid Build Coastguard Worker 
305*993b0882SAndroid Build Coastguard Worker template <typename T>
Set(StringPiece field_name,T value)306*993b0882SAndroid Build Coastguard Worker bool MutableFlatbuffer::Set(StringPiece field_name, T value) {
307*993b0882SAndroid Build Coastguard Worker   if (const reflection::Field* field = GetFieldOrNull(field_name)) {
308*993b0882SAndroid Build Coastguard Worker     if (field->type()->base_type() == reflection::BaseType::Vector ||
309*993b0882SAndroid Build Coastguard Worker         field->type()->base_type() == reflection::BaseType::Obj) {
310*993b0882SAndroid Build Coastguard Worker       TC3_LOG(ERROR)
311*993b0882SAndroid Build Coastguard Worker           << "Trying to set a primitive value on a non-scalar field.";
312*993b0882SAndroid Build Coastguard Worker       return false;
313*993b0882SAndroid Build Coastguard Worker     }
314*993b0882SAndroid Build Coastguard Worker     return Set<T>(field, value);
315*993b0882SAndroid Build Coastguard Worker   }
316*993b0882SAndroid Build Coastguard Worker   TC3_LOG(ERROR) << "Couldn't find a field: " << field_name;
317*993b0882SAndroid Build Coastguard Worker   return false;
318*993b0882SAndroid Build Coastguard Worker }
319*993b0882SAndroid Build Coastguard Worker 
320*993b0882SAndroid Build Coastguard Worker template <typename T>
Set(const reflection::Field * field,T value)321*993b0882SAndroid Build Coastguard Worker bool MutableFlatbuffer::Set(const reflection::Field* field, T value) {
322*993b0882SAndroid Build Coastguard Worker   if (field == nullptr) {
323*993b0882SAndroid Build Coastguard Worker     TC3_LOG(ERROR) << "Expected non-null field.";
324*993b0882SAndroid Build Coastguard Worker     return false;
325*993b0882SAndroid Build Coastguard Worker   }
326*993b0882SAndroid Build Coastguard Worker   Variant variant_value(value);
327*993b0882SAndroid Build Coastguard Worker   if (!IsMatchingType<T>(field->type()->base_type())) {
328*993b0882SAndroid Build Coastguard Worker     TC3_LOG(ERROR) << "Type mismatch for field `" << field->name()->str()
329*993b0882SAndroid Build Coastguard Worker                    << "`, expected: "
330*993b0882SAndroid Build Coastguard Worker                    << EnumNameBaseType(field->type()->base_type())
331*993b0882SAndroid Build Coastguard Worker                    << ", got: " << variant_value.GetType();
332*993b0882SAndroid Build Coastguard Worker     return false;
333*993b0882SAndroid Build Coastguard Worker   }
334*993b0882SAndroid Build Coastguard Worker   fields_[field] = variant_value;
335*993b0882SAndroid Build Coastguard Worker   return true;
336*993b0882SAndroid Build Coastguard Worker }
337*993b0882SAndroid Build Coastguard Worker 
338*993b0882SAndroid Build Coastguard Worker template <typename T>
Set(const FlatbufferFieldPath * path,T value)339*993b0882SAndroid Build Coastguard Worker bool MutableFlatbuffer::Set(const FlatbufferFieldPath* path, T value) {
340*993b0882SAndroid Build Coastguard Worker   MutableFlatbuffer* parent;
341*993b0882SAndroid Build Coastguard Worker   const reflection::Field* field;
342*993b0882SAndroid Build Coastguard Worker   if (!GetFieldWithParent(path, &parent, &field)) {
343*993b0882SAndroid Build Coastguard Worker     return false;
344*993b0882SAndroid Build Coastguard Worker   }
345*993b0882SAndroid Build Coastguard Worker   return parent->Set<T>(field, value);
346*993b0882SAndroid Build Coastguard Worker }
347*993b0882SAndroid Build Coastguard Worker 
348*993b0882SAndroid Build Coastguard Worker template <typename T>
Add(StringPiece field_name,T value)349*993b0882SAndroid Build Coastguard Worker bool MutableFlatbuffer::Add(StringPiece field_name, T value) {
350*993b0882SAndroid Build Coastguard Worker   const reflection::Field* field = GetFieldOrNull(field_name);
351*993b0882SAndroid Build Coastguard Worker   if (field == nullptr) {
352*993b0882SAndroid Build Coastguard Worker     return false;
353*993b0882SAndroid Build Coastguard Worker   }
354*993b0882SAndroid Build Coastguard Worker 
355*993b0882SAndroid Build Coastguard Worker   if (field->type()->base_type() != reflection::BaseType::Vector) {
356*993b0882SAndroid Build Coastguard Worker     return false;
357*993b0882SAndroid Build Coastguard Worker   }
358*993b0882SAndroid Build Coastguard Worker 
359*993b0882SAndroid Build Coastguard Worker   return Add<T>(field, value);
360*993b0882SAndroid Build Coastguard Worker }
361*993b0882SAndroid Build Coastguard Worker 
362*993b0882SAndroid Build Coastguard Worker template <typename T>
Add(const reflection::Field * field,T value)363*993b0882SAndroid Build Coastguard Worker bool MutableFlatbuffer::Add(const reflection::Field* field, T value) {
364*993b0882SAndroid Build Coastguard Worker   if (field == nullptr) {
365*993b0882SAndroid Build Coastguard Worker     return false;
366*993b0882SAndroid Build Coastguard Worker   }
367*993b0882SAndroid Build Coastguard Worker   Repeated(field)->Add(value);
368*993b0882SAndroid Build Coastguard Worker   return true;
369*993b0882SAndroid Build Coastguard Worker }
370*993b0882SAndroid Build Coastguard Worker 
371*993b0882SAndroid Build Coastguard Worker template <typename T>
Add(const T value)372*993b0882SAndroid Build Coastguard Worker bool RepeatedField::Add(const T value) {
373*993b0882SAndroid Build Coastguard Worker   if (!is_primitive_ || !IsMatchingType<T>(field_->type()->element())) {
374*993b0882SAndroid Build Coastguard Worker     TC3_LOG(ERROR) << "Trying to add value of unmatching type.";
375*993b0882SAndroid Build Coastguard Worker     return false;
376*993b0882SAndroid Build Coastguard Worker   }
377*993b0882SAndroid Build Coastguard Worker   items_.push_back(Variant{value});
378*993b0882SAndroid Build Coastguard Worker   return true;
379*993b0882SAndroid Build Coastguard Worker }
380*993b0882SAndroid Build Coastguard Worker 
381*993b0882SAndroid Build Coastguard Worker template <typename T>
AppendFromVector(const flatbuffers::Table * from)382*993b0882SAndroid Build Coastguard Worker bool RepeatedField::AppendFromVector(const flatbuffers::Table* from) {
383*993b0882SAndroid Build Coastguard Worker   const flatbuffers::Vector<T>* values =
384*993b0882SAndroid Build Coastguard Worker       from->GetPointer<const flatbuffers::Vector<T>*>(field_->offset());
385*993b0882SAndroid Build Coastguard Worker   if (values == nullptr) {
386*993b0882SAndroid Build Coastguard Worker     return false;
387*993b0882SAndroid Build Coastguard Worker   }
388*993b0882SAndroid Build Coastguard Worker   for (const T element : *values) {
389*993b0882SAndroid Build Coastguard Worker     Add(element);
390*993b0882SAndroid Build Coastguard Worker   }
391*993b0882SAndroid Build Coastguard Worker   return true;
392*993b0882SAndroid Build Coastguard Worker }
393*993b0882SAndroid Build Coastguard Worker 
394*993b0882SAndroid Build Coastguard Worker template <>
395*993b0882SAndroid Build Coastguard Worker inline bool RepeatedField::AppendFromVector<std::string>(
396*993b0882SAndroid Build Coastguard Worker     const flatbuffers::Table* from) {
397*993b0882SAndroid Build Coastguard Worker   auto* values = from->GetPointer<
398*993b0882SAndroid Build Coastguard Worker       const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>>*>(
399*993b0882SAndroid Build Coastguard Worker       field_->offset());
400*993b0882SAndroid Build Coastguard Worker   if (values == nullptr) {
401*993b0882SAndroid Build Coastguard Worker     return false;
402*993b0882SAndroid Build Coastguard Worker   }
403*993b0882SAndroid Build Coastguard Worker   for (const flatbuffers::String* element : *values) {
404*993b0882SAndroid Build Coastguard Worker     Add(element->str());
405*993b0882SAndroid Build Coastguard Worker   }
406*993b0882SAndroid Build Coastguard Worker   return true;
407*993b0882SAndroid Build Coastguard Worker }
408*993b0882SAndroid Build Coastguard Worker 
409*993b0882SAndroid Build Coastguard Worker template <>
410*993b0882SAndroid Build Coastguard Worker inline bool RepeatedField::AppendFromVector<MutableFlatbuffer>(
411*993b0882SAndroid Build Coastguard Worker     const flatbuffers::Table* from) {
412*993b0882SAndroid Build Coastguard Worker   auto* values = from->GetPointer<const flatbuffers::Vector<
413*993b0882SAndroid Build Coastguard Worker       flatbuffers::Offset<const flatbuffers::Table>>*>(field_->offset());
414*993b0882SAndroid Build Coastguard Worker   if (values == nullptr) {
415*993b0882SAndroid Build Coastguard Worker     return false;
416*993b0882SAndroid Build Coastguard Worker   }
417*993b0882SAndroid Build Coastguard Worker   for (const flatbuffers::Table* const from_element : *values) {
418*993b0882SAndroid Build Coastguard Worker     MutableFlatbuffer* to_element = Add();
419*993b0882SAndroid Build Coastguard Worker     if (to_element == nullptr) {
420*993b0882SAndroid Build Coastguard Worker       return false;
421*993b0882SAndroid Build Coastguard Worker     }
422*993b0882SAndroid Build Coastguard Worker     to_element->MergeFrom(from_element);
423*993b0882SAndroid Build Coastguard Worker   }
424*993b0882SAndroid Build Coastguard Worker   return true;
425*993b0882SAndroid Build Coastguard Worker }
426*993b0882SAndroid Build Coastguard Worker 
427*993b0882SAndroid Build Coastguard Worker }  // namespace libtextclassifier3
428*993b0882SAndroid Build Coastguard Worker 
429*993b0882SAndroid Build Coastguard Worker #endif  // LIBTEXTCLASSIFIER_UTILS_FLATBUFFERS_MUTABLE_H_
430