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
56namespace google {
57namespace protobuf {
58namespace internal {
59
60// Processing-type masks.
61static constexpr const unsigned char kOneofMask = 0x40;
62static 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.
65static constexpr const unsigned char kTypeMask = 0x1f;
66
67// Wire type masks.
68static constexpr const unsigned char kNotPackedMask = 0x10;
69static constexpr const unsigned char kInvalidMask = 0x20;
70
71enum 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
81static_assert(TYPE_MAP < kRepeatedMask, "Invalid enum");
82
83struct 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.
124struct 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
139struct ParseTable;
140
141union 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;
155 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;
173 constexpr AuxillaryParseTableField(AuxillaryParseTableField::enum_aux e)
174 : enums(e) {}
175 constexpr AuxillaryParseTableField(AuxillaryParseTableField::message_aux m)
176 : messages(m) {}
177 constexpr AuxillaryParseTableField(AuxillaryParseTableField::string_aux s)
178 : strings(s) {}
179 constexpr AuxillaryParseTableField(AuxillaryParseTableField::map_aux m)
180 : maps(m) {}
181};
182
183struct 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;
199 const MessageLite* default_instance() const {
200 return static_cast<const MessageLite*>(default_instance_void);
201 }
202
203 bool unknown_field_set;
204};
205
206static_assert(sizeof(ParseTableField) <= 16, "ParseTableField is too large");
207// The tables must be composed of POD components to ensure link-time
208// initialization.
209static_assert(std::is_pod<ParseTableField>::value, "");
210static_assert(std::is_pod<AuxillaryParseTableField>::value, "");
211static_assert(std::is_pod<AuxillaryParseTableField::enum_aux>::value, "");
212static_assert(std::is_pod<AuxillaryParseTableField::message_aux>::value, "");
213static_assert(std::is_pod<AuxillaryParseTableField::string_aux>::value, "");
214static_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.
218bool MergePartialFromCodedStream(MessageLite* msg, const ParseTable& table,
219 io::CodedInputStream* input);
220bool MergePartialFromCodedStreamLite(MessageLite* msg, const ParseTable& table,
221 io::CodedInputStream* input);
222
223template <typename Entry>
224bool 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
234struct SerializationTable {
235 int num_fields;
236 const FieldMetadata* field_table;
237};
238
239PROTOBUF_EXPORT void SerializeInternal(const uint8* base,
240 const FieldMetadata* table,
241 int32 num_fields,
242 io::CodedOutputStream* output);
243
244inline 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, table: field_table + 1, num_fields, output);
257}
258
259uint8* SerializeInternalToArray(const uint8* base, const FieldMetadata* table,
260 int32 num_fields, bool is_deterministic,
261 uint8* buffer);
262
263inline 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, table: field_table, num_fields,
270 is_deterministic, buffer);
271}
272
273template <typename T>
274struct CompareHelper {
275 bool operator()(const T& a, const T& b) const { return a < b; }
276};
277
278template <>
279struct CompareHelper<ArenaStringPtr> {
280 bool operator()(const ArenaStringPtr& a, const ArenaStringPtr& b) const {
281 return a.Get() < b.Get();
282 }
283};
284
285struct 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
297template <typename MapFieldType, const SerializationTable* table>
298void 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(value: tag);
313 output->WriteVarint32(value: map_entry._cached_size_);
314 SerializeInternal(base: reinterpret_cast<const uint8*>(&map_entry),
315 table: t->field_table, num_fields: 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(value: tag);
326 output->WriteVarint32(value: v[i]._cached_size_);
327 SerializeInternal(base: reinterpret_cast<const uint8*>(&v[i]), table: t->field_table,
328 num_fields: 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

source code of include/google/protobuf/generated_message_table_driven.h