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_MAP = 23,
77 };
78
79 static_assert(TYPE_MAP < kRepeatedMask, "Invalid enum");
80
81 struct PROTOBUF_EXPORT FieldMetadata {
82 uint32 offset; // offset of this field in the struct
83 uint32 tag; // field * 8 + wire_type
84 // byte offset * 8 + bit_offset;
85 // if the high bit is set then this is the byte offset of the oneof_case
86 // for this field.
87 uint32 has_offset;
88 uint32 type; // the type of this field.
89 const void* ptr; // auxiliary data
90
91 // From the serializer point of view each fundamental type can occur in
92 // 4 different ways. For simplicity we treat all combinations as a cartesion
93 // product although not all combinations are allowed.
94 enum FieldTypeClass {
95 kPresence,
96 kNoPresence,
97 kRepeated,
98 kPacked,
99 kOneOf,
100 kNumTypeClasses // must be last enum
101 };
102 // C++ protobuf has 20 fundamental types, were we added Cord and StringPiece
103 // and also distinguish the same types if they have different wire format.
104 enum {
105 kCordType = 19,
106 kStringPieceType = 20,
107 kNumTypes = 20,
108 kSpecial = kNumTypes * kNumTypeClasses,
109 };
110
111 static int CalculateType(int fundamental_type, FieldTypeClass type_class);
112 };
113
114 // TODO(ckennelly): Add a static assertion to ensure that these masks do not
115 // conflict with wiretypes.
116
117 // ParseTableField is kept small to help simplify instructions for computing
118 // offsets, as we will always need this information to parse a field.
119 // Additional data, needed for some types, is stored in
120 // AuxiliaryParseTableField.
121 struct ParseTableField {
122 uint32 offset;
123 // The presence_index ordinarily represents a has_bit index, but for fields
124 // inside a oneof it represents the index in _oneof_case_.
125 uint32 presence_index;
126 unsigned char normal_wiretype;
127 unsigned char packed_wiretype;
128
129 // processing_type is given by:
130 // (FieldDescriptor->type() << 1) | FieldDescriptor->is_packed()
131 unsigned char processing_type;
132
133 unsigned char tag_size;
134 };
135
136 struct ParseTable;
137
138 union AuxiliaryParseTableField {
139 typedef bool (*EnumValidator)(int);
140
141 // Enums
142 struct enum_aux {
143 EnumValidator validator;
144 };
145 enum_aux enums;
146 // Group, messages
147 struct message_aux {
148 // ExplicitlyInitialized<T> -> T requires a reinterpret_cast, which prevents
149 // the tables from being constructed as a constexpr. We use void to avoid
150 // the cast.
151 const void* default_message_void;
default_messageAuxiliaryParseTableField::message_aux152 const MessageLite* default_message() const {
153 return static_cast<const MessageLite*>(default_message_void);
154 }
155 };
156 message_aux messages;
157 // Strings
158 struct string_aux {
159 const void* default_ptr;
160 const char* field_name;
161 };
162 string_aux strings;
163
164 struct map_aux {
165 bool (*parse_map)(io::CodedInputStream*, void*);
166 };
167 map_aux maps;
168
169 AuxiliaryParseTableField() = default;
AuxiliaryParseTableField(AuxiliaryParseTableField::enum_aux e)170 constexpr AuxiliaryParseTableField(AuxiliaryParseTableField::enum_aux e)
171 : enums(e) {}
AuxiliaryParseTableField(AuxiliaryParseTableField::message_aux m)172 constexpr AuxiliaryParseTableField(AuxiliaryParseTableField::message_aux m)
173 : messages(m) {}
AuxiliaryParseTableField(AuxiliaryParseTableField::string_aux s)174 constexpr AuxiliaryParseTableField(AuxiliaryParseTableField::string_aux s)
175 : strings(s) {}
AuxiliaryParseTableField(AuxiliaryParseTableField::map_aux m)176 constexpr AuxiliaryParseTableField(AuxiliaryParseTableField::map_aux m)
177 : maps(m) {}
178 };
179
180 struct ParseTable {
181 const ParseTableField* fields;
182 const AuxiliaryParseTableField* aux;
183 int max_field_number;
184 // TODO(ckennelly): Do something with this padding.
185
186 // TODO(ckennelly): Vet these for sign extension.
187 int64 has_bits_offset;
188 int64 oneof_case_offset;
189 int64 extension_offset;
190 int64 arena_offset;
191
192 // ExplicitlyInitialized<T> -> T requires a reinterpret_cast, which prevents
193 // the tables from being constructed as a constexpr. We use void to avoid
194 // the cast.
195 const void* default_instance_void;
default_instanceParseTable196 const MessageLite* default_instance() const {
197 return static_cast<const MessageLite*>(default_instance_void);
198 }
199
200 bool unknown_field_set;
201 };
202
203 static_assert(sizeof(ParseTableField) <= 16, "ParseTableField is too large");
204 // The tables must be composed of POD components to ensure link-time
205 // initialization.
206 static_assert(std::is_pod<ParseTableField>::value, "");
207 static_assert(std::is_pod<AuxiliaryParseTableField>::value, "");
208 static_assert(std::is_pod<AuxiliaryParseTableField::enum_aux>::value, "");
209 static_assert(std::is_pod<AuxiliaryParseTableField::message_aux>::value, "");
210 static_assert(std::is_pod<AuxiliaryParseTableField::string_aux>::value, "");
211 static_assert(std::is_pod<ParseTable>::value, "");
212
213 // TODO(ckennelly): Consolidate these implementations into a single one, using
214 // dynamic dispatch to the appropriate unknown field handler.
215 bool MergePartialFromCodedStream(MessageLite* msg, const ParseTable& table,
216 io::CodedInputStream* input);
217 bool MergePartialFromCodedStreamLite(MessageLite* msg, const ParseTable& table,
218 io::CodedInputStream* input);
219
220 template <typename Entry>
ParseMap(io::CodedInputStream * input,void * map_field)221 bool ParseMap(io::CodedInputStream* input, void* map_field) {
222 typedef typename MapEntryToMapField<Entry>::MapFieldType MapFieldType;
223 typedef Map<typename Entry::EntryKeyType, typename Entry::EntryValueType>
224 MapType;
225 typedef typename Entry::template Parser<MapFieldType, MapType> ParserType;
226
227 ParserType parser(static_cast<MapFieldType*>(map_field));
228 return WireFormatLite::ReadMessageNoVirtual(input, &parser);
229 }
230
231 struct SerializationTable {
232 int num_fields;
233 const FieldMetadata* field_table;
234 };
235
236 PROTOBUF_EXPORT void SerializeInternal(const uint8* base,
237 const FieldMetadata* table,
238 int32 num_fields,
239 io::CodedOutputStream* output);
240
TableSerialize(const MessageLite & msg,const SerializationTable * table,io::CodedOutputStream * output)241 inline void TableSerialize(const MessageLite& msg,
242 const SerializationTable* table,
243 io::CodedOutputStream* output) {
244 const FieldMetadata* field_table = table->field_table;
245 int num_fields = table->num_fields - 1;
246 const uint8* base = reinterpret_cast<const uint8*>(&msg);
247 // TODO(gerbens) This skips the first test if we could use the fast
248 // array serialization path, we should make this
249 // int cached_size =
250 // *reinterpret_cast<const int32*>(base + field_table->offset);
251 // SerializeWithCachedSize(msg, field_table + 1, num_fields, cached_size, ...)
252 // But we keep conformance with the old way for now.
253 SerializeInternal(base, field_table + 1, num_fields, output);
254 }
255
256 uint8* SerializeInternalToArray(const uint8* base, const FieldMetadata* table,
257 int32 num_fields, bool is_deterministic,
258 uint8* buffer);
259
TableSerializeToArray(const MessageLite & msg,const SerializationTable * table,bool is_deterministic,uint8 * buffer)260 inline uint8* TableSerializeToArray(const MessageLite& msg,
261 const SerializationTable* table,
262 bool is_deterministic, uint8* buffer) {
263 const uint8* base = reinterpret_cast<const uint8*>(&msg);
264 const FieldMetadata* field_table = table->field_table + 1;
265 int num_fields = table->num_fields - 1;
266 return SerializeInternalToArray(base, field_table, num_fields,
267 is_deterministic, buffer);
268 }
269
270 template <typename T>
271 struct CompareHelper {
operatorCompareHelper272 bool operator()(const T& a, const T& b) const { return a < b; }
273 };
274
275 template <>
276 struct CompareHelper<ArenaStringPtr> {
277 bool operator()(const ArenaStringPtr& a, const ArenaStringPtr& b) const {
278 return a.Get() < b.Get();
279 }
280 };
281
282 struct CompareMapKey {
283 template <typename T>
284 bool operator()(const MapEntryHelper<T>& a,
285 const MapEntryHelper<T>& b) const {
286 return Compare(a.key_, b.key_);
287 }
288 template <typename T>
289 bool Compare(const T& a, const T& b) const {
290 return CompareHelper<T>()(a, b);
291 }
292 };
293
294 template <typename MapFieldType, const SerializationTable* table>
295 void MapFieldSerializer(const uint8* base, uint32 offset, uint32 tag,
296 uint32 has_offset, io::CodedOutputStream* output) {
297 typedef MapEntryHelper<typename MapFieldType::EntryTypeTrait> Entry;
298 typedef typename MapFieldType::MapType::const_iterator Iter;
299
300 const MapFieldType& map_field =
301 *reinterpret_cast<const MapFieldType*>(base + offset);
302 const SerializationTable* t =
303 table +
304 has_offset; // has_offset is overloaded for maps to mean table offset
305 if (!output->IsSerializationDeterministic()) {
306 for (Iter it = map_field.GetMap().begin(); it != map_field.GetMap().end();
307 ++it) {
308 Entry map_entry(*it);
309 output->WriteVarint32(tag);
310 output->WriteVarint32(map_entry._cached_size_);
311 SerializeInternal(reinterpret_cast<const uint8*>(&map_entry),
312 t->field_table, t->num_fields, output);
313 }
314 } else {
315 std::vector<Entry> v;
316 for (Iter it = map_field.GetMap().begin(); it != map_field.GetMap().end();
317 ++it) {
318 v.push_back(Entry(*it));
319 }
320 std::sort(v.begin(), v.end(), CompareMapKey());
321 for (int i = 0; i < v.size(); i++) {
322 output->WriteVarint32(tag);
323 output->WriteVarint32(v[i]._cached_size_);
324 SerializeInternal(reinterpret_cast<const uint8*>(&v[i]), t->field_table,
325 t->num_fields, output);
326 }
327 }
328 }
329
330 } // namespace internal
331 } // namespace protobuf
332 } // namespace google
333
334 #include <google/protobuf/port_undef.inc>
335
336 #endif // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DRIVEN_H__
337