blob: c59f43aa6458033916e1d3d116dbf1e447fe54b8 [file] [log] [blame]
Jisi Liub0f66112015-08-21 11:18:45 -07001// 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#include <google/protobuf/util/field_mask_util.h>
32
33#include <google/protobuf/stubs/strutil.h>
34#include <google/protobuf/stubs/map_util.h>
35
36namespace google {
37namespace protobuf {
38namespace util {
39
40using google::protobuf::FieldMask;
41
42string FieldMaskUtil::ToString(const FieldMask& mask) {
43 return Join(mask.paths(), ",");
44}
45
Jisi Liu46e8ff62015-10-05 11:59:43 -070046void FieldMaskUtil::FromString(StringPiece str, FieldMask* out) {
Jisi Liub0f66112015-08-21 11:18:45 -070047 out->Clear();
48 vector<string> paths = Split(str, ",");
49 for (int i = 0; i < paths.size(); ++i) {
50 if (paths[i].empty()) continue;
51 out->add_paths(paths[i]);
52 }
53}
54
55bool FieldMaskUtil::InternalIsValidPath(const Descriptor* descriptor,
Jisi Liu46e8ff62015-10-05 11:59:43 -070056 StringPiece path) {
Jisi Liub0f66112015-08-21 11:18:45 -070057 vector<string> parts = Split(path, ".");
58 for (int i = 0; i < parts.size(); ++i) {
59 const string& field_name = parts[i];
60 if (descriptor == NULL) {
61 return false;
62 }
63 const FieldDescriptor* field = descriptor->FindFieldByName(field_name);
64 if (field == NULL) {
65 return false;
66 }
67 if (!field->is_repeated() &&
68 field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
69 descriptor = field->message_type();
70 } else {
71 descriptor = NULL;
72 }
73 }
74 return true;
75}
76
77void FieldMaskUtil::InternalGetFieldMaskForAllFields(
78 const Descriptor* descriptor, FieldMask* out) {
79 for (int i = 0; i < descriptor->field_count(); ++i) {
80 out->add_paths(descriptor->field(i)->name());
81 }
82}
83
84namespace {
85// A FieldMaskTree represents a FieldMask in a tree structure. For example,
86// given a FieldMask "foo.bar,foo.baz,bar.baz", the FieldMaskTree will be:
87//
88// [root] -+- foo -+- bar
89// | |
90// | +- baz
91// |
92// +- bar --- baz
93//
94// In the tree, each leaf node represents a field path.
95class FieldMaskTree {
96 public:
97 FieldMaskTree();
98 ~FieldMaskTree();
99
100 void MergeFromFieldMask(const FieldMask& mask);
101 void MergeToFieldMask(FieldMask* mask);
102
103 // Add a field path into the tree. In a FieldMask, each field path matches
104 // the specified field and also all its sub-fields. If the field path to
105 // add is a sub-path of an existing field path in the tree (i.e., a leaf
Dongjoon Hyun7a9040f2016-01-14 22:12:03 -0800106 // node), it means the tree already matches the given path so nothing will
Jisi Liub0f66112015-08-21 11:18:45 -0700107 // be added to the tree. If the path matches an existing non-leaf node in the
108 // tree, that non-leaf node will be turned into a leaf node with all its
109 // children removed because the path matches all the node's children.
110 void AddPath(const string& path);
111
112 // Calculate the intersection part of a field path with this tree and add
113 // the intersection field path into out.
114 void IntersectPath(const string& path, FieldMaskTree* out);
115
116 // Merge all fields specified by this tree from one message to another.
117 void MergeMessage(const Message& source,
118 const FieldMaskUtil::MergeOptions& options,
119 Message* destination) {
120 // Do nothing if the tree is empty.
121 if (root_.children.empty()) {
122 return;
123 }
124 MergeMessage(&root_, source, options, destination);
125 }
126
127 private:
128 struct Node {
129 Node() {}
130
131 ~Node() { ClearChildren(); }
132
133 void ClearChildren() {
134 for (map<string, Node*>::iterator it = children.begin();
135 it != children.end(); ++it) {
136 delete it->second;
137 }
138 children.clear();
139 }
140
141 map<string, Node*> children;
142
143 private:
144 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Node);
145 };
146
147 // Merge a sub-tree to mask. This method adds the field paths represented
148 // by all leaf nodes descended from "node" to mask.
149 void MergeToFieldMask(const string& prefix, const Node* node, FieldMask* out);
150
151 // Merge all leaf nodes of a sub-tree to another tree.
152 void MergeLeafNodesToTree(const string& prefix, const Node* node,
153 FieldMaskTree* out);
154
155 // Merge all fields specified by a sub-tree from one message to another.
156 void MergeMessage(const Node* node, const Message& source,
157 const FieldMaskUtil::MergeOptions& options,
158 Message* destination);
159
160 Node root_;
161
162 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldMaskTree);
163};
164
165FieldMaskTree::FieldMaskTree() {}
166
167FieldMaskTree::~FieldMaskTree() {}
168
169void FieldMaskTree::MergeFromFieldMask(const FieldMask& mask) {
170 for (int i = 0; i < mask.paths_size(); ++i) {
171 AddPath(mask.paths(i));
172 }
173}
174
175void FieldMaskTree::MergeToFieldMask(FieldMask* mask) {
176 MergeToFieldMask("", &root_, mask);
177}
178
179void FieldMaskTree::MergeToFieldMask(const string& prefix, const Node* node,
180 FieldMask* out) {
181 if (node->children.empty()) {
182 if (prefix.empty()) {
183 // This is the root node.
184 return;
185 }
186 out->add_paths(prefix);
187 return;
188 }
189 for (map<string, Node*>::const_iterator it = node->children.begin();
190 it != node->children.end(); ++it) {
191 string current_path = prefix.empty() ? it->first : prefix + "." + it->first;
192 MergeToFieldMask(current_path, it->second, out);
193 }
194}
195
196void FieldMaskTree::AddPath(const string& path) {
197 vector<string> parts = Split(path, ".");
198 if (parts.empty()) {
199 return;
200 }
201 bool new_branch = false;
202 Node* node = &root_;
203 for (int i = 0; i < parts.size(); ++i) {
204 if (!new_branch && node != &root_ && node->children.empty()) {
205 // Path matches an existing leaf node. This means the path is already
206 // coverred by this tree (for example, adding "foo.bar.baz" to a tree
207 // which already contains "foo.bar").
208 return;
209 }
210 const string& node_name = parts[i];
211 Node*& child = node->children[node_name];
212 if (child == NULL) {
213 new_branch = true;
214 child = new Node();
215 }
216 node = child;
217 }
218 if (!node->children.empty()) {
219 node->ClearChildren();
220 }
221}
222
223void FieldMaskTree::IntersectPath(const string& path, FieldMaskTree* out) {
224 vector<string> parts = Split(path, ".");
225 if (parts.empty()) {
226 return;
227 }
228 const Node* node = &root_;
229 for (int i = 0; i < parts.size(); ++i) {
230 if (node->children.empty()) {
231 if (node != &root_) {
232 out->AddPath(path);
233 }
234 return;
235 }
236 const string& node_name = parts[i];
237 const Node* result = FindPtrOrNull(node->children, node_name);
238 if (result == NULL) {
239 // No intersection found.
240 return;
241 }
242 node = result;
243 }
244 // Now we found a matching node with the given path. Add all leaf nodes
245 // to out.
246 MergeLeafNodesToTree(path, node, out);
247}
248
249void FieldMaskTree::MergeLeafNodesToTree(const string& prefix, const Node* node,
250 FieldMaskTree* out) {
251 if (node->children.empty()) {
252 out->AddPath(prefix);
253 }
254 for (map<string, Node*>::const_iterator it = node->children.begin();
255 it != node->children.end(); ++it) {
256 string current_path = prefix.empty() ? it->first : prefix + "." + it->first;
257 MergeLeafNodesToTree(current_path, it->second, out);
258 }
259}
260
261void FieldMaskTree::MergeMessage(const Node* node, const Message& source,
262 const FieldMaskUtil::MergeOptions& options,
263 Message* destination) {
264 GOOGLE_DCHECK(!node->children.empty());
265 const Reflection* source_reflection = source.GetReflection();
266 const Reflection* destination_reflection = destination->GetReflection();
267 const Descriptor* descriptor = source.GetDescriptor();
268 for (map<string, Node*>::const_iterator it = node->children.begin();
269 it != node->children.end(); ++it) {
270 const string& field_name = it->first;
271 const Node* child = it->second;
272 const FieldDescriptor* field = descriptor->FindFieldByName(field_name);
273 if (field == NULL) {
274 GOOGLE_LOG(ERROR) << "Cannot find field \"" << field_name << "\" in message "
275 << descriptor->full_name();
276 continue;
277 }
278 if (!child->children.empty()) {
279 // Sub-paths are only allowed for singular message fields.
280 if (field->is_repeated() ||
281 field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) {
282 GOOGLE_LOG(ERROR) << "Field \"" << field_name << "\" in message "
283 << descriptor->full_name()
284 << " is not a singular message field and cannot "
285 << "have sub-fields.";
286 continue;
287 }
288 MergeMessage(child, source_reflection->GetMessage(source, field), options,
289 destination_reflection->MutableMessage(destination, field));
290 continue;
291 }
292 if (!field->is_repeated()) {
293 switch (field->cpp_type()) {
294#define COPY_VALUE(TYPE, Name) \
295 case FieldDescriptor::CPPTYPE_##TYPE: { \
296 destination_reflection->Set##Name( \
297 destination, field, source_reflection->Get##Name(source, field)); \
298 break; \
299 }
300 COPY_VALUE(BOOL, Bool)
301 COPY_VALUE(INT32, Int32)
302 COPY_VALUE(INT64, Int64)
303 COPY_VALUE(UINT32, UInt32)
304 COPY_VALUE(UINT64, UInt64)
305 COPY_VALUE(FLOAT, Float)
306 COPY_VALUE(DOUBLE, Double)
307 COPY_VALUE(ENUM, Enum)
308 COPY_VALUE(STRING, String)
309#undef COPY_VALUE
310 case FieldDescriptor::CPPTYPE_MESSAGE: {
311 if (options.replace_message_fields()) {
312 destination_reflection->ClearField(destination, field);
313 }
314 if (source_reflection->HasField(source, field)) {
315 destination_reflection->MutableMessage(destination, field)
316 ->MergeFrom(source_reflection->GetMessage(source, field));
317 }
318 break;
319 }
320 }
321 } else {
322 if (options.replace_repeated_fields()) {
323 destination_reflection->ClearField(destination, field);
324 }
325 switch (field->cpp_type()) {
326#define COPY_REPEATED_VALUE(TYPE, Name) \
327 case FieldDescriptor::CPPTYPE_##TYPE: { \
328 int size = source_reflection->FieldSize(source, field); \
329 for (int i = 0; i < size; ++i) { \
330 destination_reflection->Add##Name( \
331 destination, field, \
332 source_reflection->GetRepeated##Name(source, field, i)); \
333 } \
334 break; \
335 }
336 COPY_REPEATED_VALUE(BOOL, Bool)
337 COPY_REPEATED_VALUE(INT32, Int32)
338 COPY_REPEATED_VALUE(INT64, Int64)
339 COPY_REPEATED_VALUE(UINT32, UInt32)
340 COPY_REPEATED_VALUE(UINT64, UInt64)
341 COPY_REPEATED_VALUE(FLOAT, Float)
342 COPY_REPEATED_VALUE(DOUBLE, Double)
343 COPY_REPEATED_VALUE(ENUM, Enum)
344 COPY_REPEATED_VALUE(STRING, String)
345#undef COPY_REPEATED_VALUE
346 case FieldDescriptor::CPPTYPE_MESSAGE: {
347 int size = source_reflection->FieldSize(source, field);
348 for (int i = 0; i < size; ++i) {
349 destination_reflection->AddMessage(destination, field)
350 ->MergeFrom(
351 source_reflection->GetRepeatedMessage(source, field, i));
352 }
353 break;
354 }
355 }
356 }
357 }
358}
359
360} // namespace
361
362void FieldMaskUtil::ToCanonicalForm(const FieldMask& mask, FieldMask* out) {
363 FieldMaskTree tree;
364 tree.MergeFromFieldMask(mask);
365 out->Clear();
366 tree.MergeToFieldMask(out);
367}
368
369void FieldMaskUtil::Union(const FieldMask& mask1, const FieldMask& mask2,
370 FieldMask* out) {
371 FieldMaskTree tree;
372 tree.MergeFromFieldMask(mask1);
373 tree.MergeFromFieldMask(mask2);
374 out->Clear();
375 tree.MergeToFieldMask(out);
376}
377
378void FieldMaskUtil::Intersect(const FieldMask& mask1, const FieldMask& mask2,
379 FieldMask* out) {
380 FieldMaskTree tree, intersection;
381 tree.MergeFromFieldMask(mask1);
382 for (int i = 0; i < mask2.paths_size(); ++i) {
383 tree.IntersectPath(mask2.paths(i), &intersection);
384 }
385 out->Clear();
386 intersection.MergeToFieldMask(out);
387}
388
Jisi Liu46e8ff62015-10-05 11:59:43 -0700389bool FieldMaskUtil::IsPathInFieldMask(StringPiece path, const FieldMask& mask) {
Jisi Liub0f66112015-08-21 11:18:45 -0700390 for (int i = 0; i < mask.paths_size(); ++i) {
391 const string& mask_path = mask.paths(i);
392 if (path == mask_path) {
393 return true;
394 } else if (mask_path.length() < path.length()) {
395 // Also check whether mask.paths(i) is a prefix of path.
Jisi Liu46e8ff62015-10-05 11:59:43 -0700396 if (path.substr(0, mask_path.length() + 1).compare(mask_path + ".") ==
397 0) {
Jisi Liub0f66112015-08-21 11:18:45 -0700398 return true;
399 }
400 }
401 }
402 return false;
403}
404
405void FieldMaskUtil::MergeMessageTo(const Message& source, const FieldMask& mask,
406 const MergeOptions& options,
407 Message* destination) {
408 GOOGLE_CHECK(source.GetDescriptor() == destination->GetDescriptor());
409 // Build a FieldMaskTree and walk through the tree to merge all specified
410 // fields.
411 FieldMaskTree tree;
412 tree.MergeFromFieldMask(mask);
413 tree.MergeMessage(source, options, destination);
414}
415
416} // namespace util
417} // namespace protobuf
418} // namespace google