• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 #ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DRIVEN_H__
32 #define GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DRIVEN_H__
33 
34 #include <google/protobuf/map.h>
35 #include <google/protobuf/map_entry_lite.h>
36 #include <google/protobuf/map_field_lite.h>
37 #include <google/protobuf/message_lite.h>
38 #include <google/protobuf/wire_format_lite.h>
39 
40 // We require C++11 and Clang to use constexpr for variables, as GCC 4.8
41 // requires constexpr to be consistent between declarations of variables
42 // unnecessarily (see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58541).
43 // VS 2017 Update 3 also supports this usage of constexpr.
44 #if defined(__clang__) || (defined(_MSC_VER) && _MSC_VER >= 1911)
45 #define PROTOBUF_CONSTEXPR_VAR constexpr
46 #else  // !__clang__
47 #define PROTOBUF_CONSTEXPR_VAR
48 #endif  // !_clang
49 
50 #ifdef SWIG
51 #error "You cannot SWIG proto headers"
52 #endif
53 
54 #include <google/protobuf/port_def.inc>
55 
56 namespace google {
57 namespace protobuf {
58 namespace internal {
59 
60 // Processing-type masks.
61 static constexpr const unsigned char kOneofMask = 0x40;
62 static constexpr const unsigned char kRepeatedMask = 0x20;
63 // Mask for the raw type: either a WireFormatLite::FieldType or one of the
64 // ProcessingTypes below, without the oneof or repeated flag.
65 static constexpr const unsigned char kTypeMask = 0x1f;
66 
67 // Wire type masks.
68 static constexpr const unsigned char kNotPackedMask = 0x10;
69 static constexpr const unsigned char kInvalidMask = 0x20;
70 
71 enum ProcessingTypes {
72   TYPE_STRING_CORD = 19,
73   TYPE_STRING_STRING_PIECE = 20,
74   TYPE_BYTES_CORD = 21,
75   TYPE_BYTES_STRING_PIECE = 22,
76   TYPE_STRING_INLINED = 23,
77   TYPE_BYTES_INLINED = 24,
78   TYPE_MAP = 25,
79 };
80 
81 static_assert(TYPE_MAP < kRepeatedMask, "Invalid enum");
82 
83 struct PROTOBUF_EXPORT FieldMetadata {
84   uint32 offset;  // offset of this field in the struct
85   uint32 tag;     // field * 8 + wire_type
86   // byte offset * 8 + bit_offset;
87   // if the high bit is set then this is the byte offset of the oneof_case
88   // for this field.
89   uint32 has_offset;
90   uint32 type;      // the type of this field.
91   const void* ptr;  // auxiliary data
92 
93   // From the serializer point of view each fundamental type can occur in
94   // 4 different ways. For simplicity we treat all combinations as a cartesion
95   // product although not all combinations are allowed.
96   enum FieldTypeClass {
97     kPresence,
98     kNoPresence,
99     kRepeated,
100     kPacked,
101     kOneOf,
102     kNumTypeClasses  // must be last enum
103   };
104   // C++ protobuf has 20 fundamental types, were we added Cord and StringPiece
105   // and also distinquish the same types if they have different wire format.
106   enum {
107     kCordType = 19,
108     kStringPieceType = 20,
109     kInlinedType = 21,
110     kNumTypes = 21,
111     kSpecial = kNumTypes * kNumTypeClasses,
112   };
113 
114   static int CalculateType(int fundamental_type, FieldTypeClass type_class);
115 };
116 
117 // TODO(ckennelly):  Add a static assertion to ensure that these masks do not
118 // conflict with wiretypes.
119 
120 // ParseTableField is kept small to help simplify instructions for computing
121 // offsets, as we will always need this information to parse a field.
122 // Additional data, needed for some types, is stored in
123 // AuxillaryParseTableField.
124 struct ParseTableField {
125   uint32 offset;
126   // The presence_index ordinarily represents a has_bit index, but for fields
127   // inside a oneof it represents the index in _oneof_case_.
128   uint32 presence_index;
129   unsigned char normal_wiretype;
130   unsigned char packed_wiretype;
131 
132   // processing_type is given by:
133   //   (FieldDescriptor->type() << 1) | FieldDescriptor->is_packed()
134   unsigned char processing_type;
135 
136   unsigned char tag_size;
137 };
138 
139 struct ParseTable;
140 
141 union AuxillaryParseTableField {
142   typedef bool (*EnumValidator)(int);
143 
144   // Enums
145   struct enum_aux {
146     EnumValidator validator;
147   };
148   enum_aux enums;
149   // Group, messages
150   struct message_aux {
151     // ExplicitlyInitialized<T> -> T requires a reinterpret_cast, which prevents
152     // the tables from being constructed as a constexpr.  We use void to avoid
153     // the cast.
154     const void* default_message_void;
default_messageAuxillaryParseTableField::message_aux155     const MessageLite* default_message() const {
156       return static_cast<const MessageLite*>(default_message_void);
157     }
158   };
159   message_aux messages;
160   // Strings
161   struct string_aux {
162     const void* default_ptr;
163     const char* field_name;
164   };
165   string_aux strings;
166 
167   struct map_aux {
168     bool (*parse_map)(io::CodedInputStream*, void*);
169   };
170   map_aux maps;
171 
172   AuxillaryParseTableField() = default;
AuxillaryParseTableField(AuxillaryParseTableField::enum_aux e)173   constexpr AuxillaryParseTableField(AuxillaryParseTableField::enum_aux e)
174       : enums(e) {}
AuxillaryParseTableField(AuxillaryParseTableField::message_aux m)175   constexpr AuxillaryParseTableField(AuxillaryParseTableField::message_aux m)
176       : messages(m) {}
AuxillaryParseTableField(AuxillaryParseTableField::string_aux s)177   constexpr AuxillaryParseTableField(AuxillaryParseTableField::string_aux s)
178       : strings(s) {}
AuxillaryParseTableField(AuxillaryParseTableField::map_aux m)179   constexpr AuxillaryParseTableField(AuxillaryParseTableField::map_aux m)
180       : maps(m) {}
181 };
182 
183 struct ParseTable {
184   const ParseTableField* fields;
185   const AuxillaryParseTableField* aux;
186   int max_field_number;
187   // TODO(ckennelly): Do something with this padding.
188 
189   // TODO(ckennelly): Vet these for sign extension.
190   int64 has_bits_offset;
191   int64 oneof_case_offset;
192   int64 extension_offset;
193   int64 arena_offset;
194 
195   // ExplicitlyInitialized<T> -> T requires a reinterpret_cast, which prevents
196   // the tables from being constructed as a constexpr.  We use void to avoid
197   // the cast.
198   const void* default_instance_void;
default_instanceParseTable199   const MessageLite* default_instance() const {
200     return static_cast<const MessageLite*>(default_instance_void);
201   }
202 
203   bool unknown_field_set;
204 };
205 
206 static_assert(sizeof(ParseTableField) <= 16, "ParseTableField is too large");
207 // The tables must be composed of POD components to ensure link-time
208 // initialization.
209 static_assert(std::is_pod<ParseTableField>::value, "");
210 static_assert(std::is_pod<AuxillaryParseTableField>::value, "");
211 static_assert(std::is_pod<AuxillaryParseTableField::enum_aux>::value, "");
212 static_assert(std::is_pod<AuxillaryParseTableField::message_aux>::value, "");
213 static_assert(std::is_pod<AuxillaryParseTableField::string_aux>::value, "");
214 static_assert(std::is_pod<ParseTable>::value, "");
215 
216 // TODO(ckennelly): Consolidate these implementations into a single one, using
217 // dynamic dispatch to the appropriate unknown field handler.
218 bool MergePartialFromCodedStream(MessageLite* msg, const ParseTable& table,
219                                  io::CodedInputStream* input);
220 bool MergePartialFromCodedStreamLite(MessageLite* msg, const ParseTable& table,
221                                      io::CodedInputStream* input);
222 
223 template <typename Entry>
ParseMap(io::CodedInputStream * input,void * map_field)224 bool ParseMap(io::CodedInputStream* input, void* map_field) {
225   typedef typename MapEntryToMapField<Entry>::MapFieldType MapFieldType;
226   typedef Map<typename Entry::EntryKeyType, typename Entry::EntryValueType>
227       MapType;
228   typedef typename Entry::template Parser<MapFieldType, MapType> ParserType;
229 
230   ParserType parser(static_cast<MapFieldType*>(map_field));
231   return WireFormatLite::ReadMessageNoVirtual(input, &parser);
232 }
233 
234 struct SerializationTable {
235   int num_fields;
236   const FieldMetadata* field_table;
237 };
238 
239 PROTOBUF_EXPORT void SerializeInternal(const uint8* base,
240                                        const FieldMetadata* table,
241                                        int32 num_fields,
242                                        io::CodedOutputStream* output);
243 
TableSerialize(const MessageLite & msg,const SerializationTable * table,io::CodedOutputStream * output)244 inline void TableSerialize(const MessageLite& msg,
245                            const SerializationTable* table,
246                            io::CodedOutputStream* output) {
247   const FieldMetadata* field_table = table->field_table;
248   int num_fields = table->num_fields - 1;
249   const uint8* base = reinterpret_cast<const uint8*>(&msg);
250   // TODO(gerbens) This skips the first test if we could use the fast
251   // array serialization path, we should make this
252   // int cached_size =
253   //    *reinterpret_cast<const int32*>(base + field_table->offset);
254   // SerializeWithCachedSize(msg, field_table + 1, num_fields, cached_size, ...)
255   // But we keep conformance with the old way for now.
256   SerializeInternal(base, field_table + 1, num_fields, output);
257 }
258 
259 uint8* SerializeInternalToArray(const uint8* base, const FieldMetadata* table,
260                                 int32 num_fields, bool is_deterministic,
261                                 uint8* buffer);
262 
TableSerializeToArray(const MessageLite & msg,const SerializationTable * table,bool is_deterministic,uint8 * buffer)263 inline uint8* TableSerializeToArray(const MessageLite& msg,
264                                     const SerializationTable* table,
265                                     bool is_deterministic, uint8* buffer) {
266   const uint8* base = reinterpret_cast<const uint8*>(&msg);
267   const FieldMetadata* field_table = table->field_table + 1;
268   int num_fields = table->num_fields - 1;
269   return SerializeInternalToArray(base, field_table, num_fields,
270                                   is_deterministic, buffer);
271 }
272 
273 template <typename T>
274 struct CompareHelper {
operatorCompareHelper275   bool operator()(const T& a, const T& b) const { return a < b; }
276 };
277 
278 template <>
279 struct CompareHelper<ArenaStringPtr> {
280   bool operator()(const ArenaStringPtr& a, const ArenaStringPtr& b) const {
281     return a.Get() < b.Get();
282   }
283 };
284 
285 struct CompareMapKey {
286   template <typename T>
287   bool operator()(const MapEntryHelper<T>& a,
288                   const MapEntryHelper<T>& b) const {
289     return Compare(a.key_, b.key_);
290   }
291   template <typename T>
292   bool Compare(const T& a, const T& b) const {
293     return CompareHelper<T>()(a, b);
294   }
295 };
296 
297 template <typename MapFieldType, const SerializationTable* table>
298 void MapFieldSerializer(const uint8* base, uint32 offset, uint32 tag,
299                         uint32 has_offset, io::CodedOutputStream* output) {
300   typedef MapEntryHelper<typename MapFieldType::EntryTypeTrait> Entry;
301   typedef typename MapFieldType::MapType::const_iterator Iter;
302 
303   const MapFieldType& map_field =
304       *reinterpret_cast<const MapFieldType*>(base + offset);
305   const SerializationTable* t =
306       table +
307       has_offset;  // has_offset is overloaded for maps to mean table offset
308   if (!output->IsSerializationDeterministic()) {
309     for (Iter it = map_field.GetMap().begin(); it != map_field.GetMap().end();
310          ++it) {
311       Entry map_entry(*it);
312       output->WriteVarint32(tag);
313       output->WriteVarint32(map_entry._cached_size_);
314       SerializeInternal(reinterpret_cast<const uint8*>(&map_entry),
315                         t->field_table, t->num_fields, output);
316     }
317   } else {
318     std::vector<Entry> v;
319     for (Iter it = map_field.GetMap().begin(); it != map_field.GetMap().end();
320          ++it) {
321       v.push_back(Entry(*it));
322     }
323     std::sort(v.begin(), v.end(), CompareMapKey());
324     for (int i = 0; i < v.size(); i++) {
325       output->WriteVarint32(tag);
326       output->WriteVarint32(v[i]._cached_size_);
327       SerializeInternal(reinterpret_cast<const uint8*>(&v[i]), t->field_table,
328                         t->num_fields, output);
329     }
330   }
331 }
332 
333 }  // namespace internal
334 }  // namespace protobuf
335 }  // namespace google
336 
337 #include <google/protobuf/port_undef.inc>
338 
339 #endif  // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DRIVEN_H__
340