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 #include <google/protobuf/wire_format_lite_inl.h>
40 
41 #if LANG_CXX11
42 #define PROTOBUF_CONSTEXPR constexpr
43 
44 // We require C++11 and Clang to use constexpr for variables, as GCC 4.8
45 // requires constexpr to be consistent between declarations of variables
46 // unnecessarily (see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58541).
47 // VS 2017 Update 3 also supports this usage of constexpr.
48 #if defined(__clang__) || (defined(_MSC_VER) && _MSC_VER >= 1911)
49 #define PROTOBUF_CONSTEXPR_VAR constexpr
50 #else  // !__clang__
51 #define PROTOBUF_CONSTEXPR_VAR
52 #endif  // !_clang
53 
54 #else
55 #define PROTOBUF_CONSTEXPR
56 #define PROTOBUF_CONSTEXPR_VAR
57 #endif
58 
59 namespace google {
60 namespace protobuf {
61 namespace internal {
62 
63 // Processing-type masks.
64 static PROTOBUF_CONSTEXPR const unsigned char kOneofMask = 0x40;
65 static PROTOBUF_CONSTEXPR const unsigned char kRepeatedMask = 0x20;
66 // Mask for the raw type: either a WireFormatLite::FieldType or one of the
67 // ProcessingTypes below, without the oneof or repeated flag.
68 static PROTOBUF_CONSTEXPR const unsigned char kTypeMask = 0x1f;
69 
70 // Wire type masks.
71 static PROTOBUF_CONSTEXPR const unsigned char kNotPackedMask = 0x10;
72 static PROTOBUF_CONSTEXPR const unsigned char kInvalidMask = 0x20;
73 
74 enum ProcessingTypes {
75   TYPE_STRING_CORD = 19,
76   TYPE_STRING_STRING_PIECE = 20,
77   TYPE_BYTES_CORD = 21,
78   TYPE_BYTES_STRING_PIECE = 22,
79   TYPE_MAP = 23,
80 };
81 
82 #if LANG_CXX11
83 static_assert(TYPE_MAP < kRepeatedMask, "Invalid enum");
84 #endif
85 
86 // TODO(ckennelly):  Add a static assertion to ensure that these masks do not
87 // conflict with wiretypes.
88 
89 // ParseTableField is kept small to help simplify instructions for computing
90 // offsets, as we will always need this information to parse a field.
91 // Additional data, needed for some types, is stored in
92 // AuxillaryParseTableField.
93 struct ParseTableField {
94   uint32 offset;
95   // The presence_index ordinarily represents a has_bit index, but for fields
96   // inside a oneof it represents the index in _oneof_case_.
97   uint32 presence_index;
98   unsigned char normal_wiretype;
99   unsigned char packed_wiretype;
100 
101   // processing_type is given by:
102   //   (FieldDescriptor->type() << 1) | FieldDescriptor->is_packed()
103   unsigned char processing_type;
104 
105   unsigned char tag_size;
106 };
107 
108 struct ParseTable;
109 
110 union AuxillaryParseTableField {
111   typedef bool (*EnumValidator)(int);
112 
113   // Enums
114   struct enum_aux {
115     EnumValidator validator;
116   };
117   enum_aux enums;
118   // Group, messages
119   struct message_aux {
120     // ExplicitlyInitialized<T> -> T requires a reinterpret_cast, which prevents
121     // the tables from being constructed as a constexpr.  We use void to avoid
122     // the cast.
123     const void* default_message_void;
default_messageAuxillaryParseTableField::message_aux124     const MessageLite* default_message() const {
125       return static_cast<const MessageLite*>(default_message_void);
126     }
127     const ParseTable* parse_table;
128   };
129   message_aux messages;
130   // Strings
131   struct string_aux {
132     const void* default_ptr;
133     const char* field_name;
134   };
135   string_aux strings;
136 
137   struct map_aux {
138     bool (*parse_map)(io::CodedInputStream*, void*);
139   };
140   map_aux maps;
141 
142 #if LANG_CXX11
143   AuxillaryParseTableField() = default;
144 #else
AuxillaryParseTableField()145   AuxillaryParseTableField() { }
146 #endif
AuxillaryParseTableField(AuxillaryParseTableField::enum_aux e)147   PROTOBUF_CONSTEXPR AuxillaryParseTableField(
148       AuxillaryParseTableField::enum_aux e) : enums(e) {}
AuxillaryParseTableField(AuxillaryParseTableField::message_aux m)149   PROTOBUF_CONSTEXPR AuxillaryParseTableField(
150       AuxillaryParseTableField::message_aux m) : messages(m) {}
AuxillaryParseTableField(AuxillaryParseTableField::string_aux s)151   PROTOBUF_CONSTEXPR AuxillaryParseTableField(
152       AuxillaryParseTableField::string_aux s) : strings(s) {}
AuxillaryParseTableField(AuxillaryParseTableField::map_aux m)153   PROTOBUF_CONSTEXPR AuxillaryParseTableField(
154       AuxillaryParseTableField::map_aux m)
155       : maps(m) {}
156 };
157 
158 struct ParseTable {
159   const ParseTableField* fields;
160   const AuxillaryParseTableField* aux;
161   int max_field_number;
162   // TODO(ckennelly): Do something with this padding.
163 
164   // TODO(ckennelly): Vet these for sign extension.
165   int64 has_bits_offset;
166   int64 oneof_case_offset;
167   int64 extension_offset;
168   int64 arena_offset;
169 
170   // ExplicitlyInitialized<T> -> T requires a reinterpret_cast, which prevents
171   // the tables from being constructed as a constexpr.  We use void to avoid
172   // the cast.
173   const void* default_instance_void;
default_instanceParseTable174   const MessageLite* default_instance() const {
175     return static_cast<const MessageLite*>(default_instance_void);
176   }
177 
178   bool unknown_field_set;
179 };
180 
181 // TODO(jhen): Remove the __NVCC__ check when we get a version of nvcc that
182 // supports these checks.
183 #if LANG_CXX11 && !defined(__NVCC__)
184 static_assert(sizeof(ParseTableField) <= 16, "ParseTableField is too large");
185 // The tables must be composed of POD components to ensure link-time
186 // initialization.
187 static_assert(std::is_pod<ParseTableField>::value, "");
188 static_assert(std::is_pod<AuxillaryParseTableField>::value, "");
189 static_assert(std::is_pod<AuxillaryParseTableField::enum_aux>::value, "");
190 static_assert(std::is_pod<AuxillaryParseTableField::message_aux>::value, "");
191 static_assert(std::is_pod<AuxillaryParseTableField::string_aux>::value, "");
192 static_assert(std::is_pod<ParseTable>::value, "");
193 #endif
194 
195 // TODO(ckennelly): Consolidate these implementations into a single one, using
196 // dynamic dispatch to the appropriate unknown field handler.
197 bool MergePartialFromCodedStream(MessageLite* msg, const ParseTable& table,
198                                  io::CodedInputStream* input);
199 bool MergePartialFromCodedStreamLite(MessageLite* msg, const ParseTable& table,
200                                  io::CodedInputStream* input);
201 
202 template <typename Entry>
ParseMap(io::CodedInputStream * input,void * map_field)203 bool ParseMap(io::CodedInputStream* input, void* map_field) {
204   typedef typename MapEntryToMapField<Entry>::MapFieldType MapFieldType;
205   typedef google::protobuf::Map<typename Entry::EntryKeyType,
206                       typename Entry::EntryValueType>
207       MapType;
208   typedef typename Entry::template Parser<MapFieldType, MapType> ParserType;
209 
210   ParserType parser(static_cast<MapFieldType*>(map_field));
211   return ::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(input,
212                                                                   &parser);
213 }
214 
215 }  // namespace internal
216 }  // namespace protobuf
217 
218 }  // namespace google
219 #endif  // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TABLE_DRIVEN_H__
220