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 | // Author: kenton@google.com (Kenton Varda) |
32 | // Based on original Protocol Buffers design by |
33 | // Sanjay Ghemawat, Jeff Dean, and others. |
34 | // |
35 | // Defines an implementation of Message which can emulate types which are not |
36 | // known at compile-time. |
37 | |
38 | #ifndef GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__ |
39 | #define GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__ |
40 | |
41 | |
42 | #include <algorithm> |
43 | #include <memory> |
44 | #include <unordered_map> |
45 | #include <vector> |
46 | |
47 | #include <google/protobuf/stubs/common.h> |
48 | #include <google/protobuf/stubs/mutex.h> |
49 | #include <google/protobuf/message.h> |
50 | #include <google/protobuf/reflection.h> |
51 | #include <google/protobuf/repeated_field.h> |
52 | |
53 | #ifdef SWIG |
54 | #error "You cannot SWIG proto headers" |
55 | #endif |
56 | |
57 | // Must be included last. |
58 | #include <google/protobuf/port_def.inc> |
59 | |
60 | namespace google { |
61 | namespace protobuf { |
62 | |
63 | // Defined in other files. |
64 | class Descriptor; // descriptor.h |
65 | class DescriptorPool; // descriptor.h |
66 | |
67 | // Constructs implementations of Message which can emulate types which are not |
68 | // known at compile-time. |
69 | // |
70 | // Sometimes you want to be able to manipulate protocol types that you don't |
71 | // know about at compile time. It would be nice to be able to construct |
72 | // a Message object which implements the message type given by any arbitrary |
73 | // Descriptor. DynamicMessage provides this. |
74 | // |
75 | // As it turns out, a DynamicMessage needs to construct extra |
76 | // information about its type in order to operate. Most of this information |
77 | // can be shared between all DynamicMessages of the same type. But, caching |
78 | // this information in some sort of global map would be a bad idea, since |
79 | // the cached information for a particular descriptor could outlive the |
80 | // descriptor itself. To avoid this problem, DynamicMessageFactory |
81 | // encapsulates this "cache". All DynamicMessages of the same type created |
82 | // from the same factory will share the same support data. Any Descriptors |
83 | // used with a particular factory must outlive the factory. |
84 | class PROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory { |
85 | public: |
86 | // Construct a DynamicMessageFactory that will search for extensions in |
87 | // the DescriptorPool in which the extendee is defined. |
88 | DynamicMessageFactory(); |
89 | |
90 | // Construct a DynamicMessageFactory that will search for extensions in |
91 | // the given DescriptorPool. |
92 | // |
93 | // DEPRECATED: Use CodedInputStream::SetExtensionRegistry() to tell the |
94 | // parser to look for extensions in an alternate pool. However, note that |
95 | // this is almost never what you want to do. Almost all users should use |
96 | // the zero-arg constructor. |
97 | DynamicMessageFactory(const DescriptorPool* pool); |
98 | |
99 | ~DynamicMessageFactory() override; |
100 | |
101 | // Call this to tell the DynamicMessageFactory that if it is given a |
102 | // Descriptor d for which: |
103 | // d->file()->pool() == DescriptorPool::generated_pool(), |
104 | // then it should delegate to MessageFactory::generated_factory() instead |
105 | // of constructing a dynamic implementation of the message. In theory there |
106 | // is no down side to doing this, so it may become the default in the future. |
107 | void SetDelegateToGeneratedFactory(bool enable) { |
108 | delegate_to_generated_factory_ = enable; |
109 | } |
110 | |
111 | // implements MessageFactory --------------------------------------- |
112 | |
113 | // Given a Descriptor, constructs the default (prototype) Message of that |
114 | // type. You can then call that message's New() method to construct a |
115 | // mutable message of that type. |
116 | // |
117 | // Calling this method twice with the same Descriptor returns the same |
118 | // object. The returned object remains property of the factory and will |
119 | // be destroyed when the factory is destroyed. Also, any objects created |
120 | // by calling the prototype's New() method share some data with the |
121 | // prototype, so these must be destroyed before the DynamicMessageFactory |
122 | // is destroyed. |
123 | // |
124 | // The given descriptor must outlive the returned message, and hence must |
125 | // outlive the DynamicMessageFactory. |
126 | // |
127 | // The method is thread-safe. |
128 | const Message* GetPrototype(const Descriptor* type) override; |
129 | |
130 | private: |
131 | const DescriptorPool* pool_; |
132 | bool delegate_to_generated_factory_; |
133 | |
134 | struct TypeInfo; |
135 | std::unordered_map<const Descriptor*, const TypeInfo*> prototypes_; |
136 | mutable internal::WrappedMutex prototypes_mutex_; |
137 | |
138 | friend class DynamicMessage; |
139 | const Message* GetPrototypeNoLock(const Descriptor* type); |
140 | |
141 | GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessageFactory); |
142 | }; |
143 | |
144 | // Helper for computing a sorted list of map entries via reflection. |
145 | class PROTOBUF_EXPORT DynamicMapSorter { |
146 | public: |
147 | static std::vector<const Message*> Sort(const Message& message, int map_size, |
148 | const Reflection* reflection, |
149 | const FieldDescriptor* field) { |
150 | std::vector<const Message*> result; |
151 | result.reserve(n: map_size); |
152 | RepeatedFieldRef<Message> map_field = |
153 | reflection->GetRepeatedFieldRef<Message>(message, field); |
154 | for (auto it = map_field.begin(); it != map_field.end(); ++it) { |
155 | result.push_back(x: &*it); |
156 | } |
157 | MapEntryMessageComparator comparator(field->message_type()); |
158 | std::stable_sort(first: result.begin(), last: result.end(), comp: comparator); |
159 | // Complain if the keys aren't in ascending order. |
160 | #ifndef NDEBUG |
161 | for (size_t j = 1; j < static_cast<size_t>(map_size); j++) { |
162 | if (!comparator(result[j - 1], result[j])) { |
163 | GOOGLE_LOG(ERROR) << (comparator(result[j], result[j - 1]) |
164 | ? "internal error in map key sorting" |
165 | : "map keys are not unique" ); |
166 | } |
167 | } |
168 | #endif |
169 | return result; |
170 | } |
171 | |
172 | private: |
173 | class PROTOBUF_EXPORT MapEntryMessageComparator { |
174 | public: |
175 | explicit MapEntryMessageComparator(const Descriptor* descriptor) |
176 | : field_(descriptor->field(index: 0)) {} |
177 | |
178 | bool operator()(const Message* a, const Message* b) { |
179 | const Reflection* reflection = a->GetReflection(); |
180 | switch (field_->cpp_type()) { |
181 | case FieldDescriptor::CPPTYPE_BOOL: { |
182 | bool first = reflection->GetBool(message: *a, field: field_); |
183 | bool second = reflection->GetBool(message: *b, field: field_); |
184 | return first < second; |
185 | } |
186 | case FieldDescriptor::CPPTYPE_INT32: { |
187 | int32_t first = reflection->GetInt32(message: *a, field: field_); |
188 | int32_t second = reflection->GetInt32(message: *b, field: field_); |
189 | return first < second; |
190 | } |
191 | case FieldDescriptor::CPPTYPE_INT64: { |
192 | int64_t first = reflection->GetInt64(message: *a, field: field_); |
193 | int64_t second = reflection->GetInt64(message: *b, field: field_); |
194 | return first < second; |
195 | } |
196 | case FieldDescriptor::CPPTYPE_UINT32: { |
197 | uint32_t first = reflection->GetUInt32(message: *a, field: field_); |
198 | uint32_t second = reflection->GetUInt32(message: *b, field: field_); |
199 | return first < second; |
200 | } |
201 | case FieldDescriptor::CPPTYPE_UINT64: { |
202 | uint64_t first = reflection->GetUInt64(message: *a, field: field_); |
203 | uint64_t second = reflection->GetUInt64(message: *b, field: field_); |
204 | return first < second; |
205 | } |
206 | case FieldDescriptor::CPPTYPE_STRING: { |
207 | std::string first = reflection->GetString(message: *a, field: field_); |
208 | std::string second = reflection->GetString(message: *b, field: field_); |
209 | return first < second; |
210 | } |
211 | default: |
212 | GOOGLE_LOG(DFATAL) << "Invalid key for map field." ; |
213 | return true; |
214 | } |
215 | } |
216 | |
217 | private: |
218 | const FieldDescriptor* field_; |
219 | }; |
220 | }; |
221 | |
222 | } // namespace protobuf |
223 | } // namespace google |
224 | |
225 | #include <google/protobuf/port_undef.inc> |
226 | |
227 | #endif // GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__ |
228 | |