OLD | NEW |
1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
2 // Copyright 2008 Google Inc. All rights reserved. | 2 // Copyright 2008 Google Inc. All rights reserved. |
3 // https://developers.google.com/protocol-buffers/ | 3 // https://developers.google.com/protocol-buffers/ |
4 // | 4 // |
5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
7 // met: | 7 // met: |
8 // | 8 // |
9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
(...skipping 27 matching lines...) Expand all Loading... |
38 namespace util { | 38 namespace util { |
39 | 39 |
40 using google::protobuf::FieldMask; | 40 using google::protobuf::FieldMask; |
41 | 41 |
42 string FieldMaskUtil::ToString(const FieldMask& mask) { | 42 string FieldMaskUtil::ToString(const FieldMask& mask) { |
43 return Join(mask.paths(), ","); | 43 return Join(mask.paths(), ","); |
44 } | 44 } |
45 | 45 |
46 void FieldMaskUtil::FromString(StringPiece str, FieldMask* out) { | 46 void FieldMaskUtil::FromString(StringPiece str, FieldMask* out) { |
47 out->Clear(); | 47 out->Clear(); |
48 vector<string> paths = Split(str, ","); | 48 std::vector<string> paths = Split(str, ","); |
49 for (int i = 0; i < paths.size(); ++i) { | 49 for (int i = 0; i < paths.size(); ++i) { |
50 if (paths[i].empty()) continue; | 50 if (paths[i].empty()) continue; |
51 out->add_paths(paths[i]); | 51 out->add_paths(paths[i]); |
52 } | 52 } |
53 } | 53 } |
54 | 54 |
55 bool FieldMaskUtil::SnakeCaseToCamelCase(StringPiece input, string* output) { | 55 bool FieldMaskUtil::SnakeCaseToCamelCase(StringPiece input, string* output) { |
56 output->clear(); | 56 output->clear(); |
57 bool after_underscore = false; | 57 bool after_underscore = false; |
58 for (int i = 0; i < input.size(); ++i) { | 58 for (int i = 0; i < input.size(); ++i) { |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 if (i > 0) { | 109 if (i > 0) { |
110 out->push_back(','); | 110 out->push_back(','); |
111 } | 111 } |
112 out->append(camelcase_path); | 112 out->append(camelcase_path); |
113 } | 113 } |
114 return true; | 114 return true; |
115 } | 115 } |
116 | 116 |
117 bool FieldMaskUtil::FromJsonString(StringPiece str, FieldMask* out) { | 117 bool FieldMaskUtil::FromJsonString(StringPiece str, FieldMask* out) { |
118 out->Clear(); | 118 out->Clear(); |
119 vector<string> paths = Split(str, ","); | 119 std::vector<string> paths = Split(str, ","); |
120 for (int i = 0; i < paths.size(); ++i) { | 120 for (int i = 0; i < paths.size(); ++i) { |
121 if (paths[i].empty()) continue; | 121 if (paths[i].empty()) continue; |
122 string snakecase_path; | 122 string snakecase_path; |
123 if (!CamelCaseToSnakeCase(paths[i], &snakecase_path)) { | 123 if (!CamelCaseToSnakeCase(paths[i], &snakecase_path)) { |
124 return false; | 124 return false; |
125 } | 125 } |
126 out->add_paths(snakecase_path); | 126 out->add_paths(snakecase_path); |
127 } | 127 } |
128 return true; | 128 return true; |
129 } | 129 } |
130 | 130 |
131 bool FieldMaskUtil::InternalIsValidPath(const Descriptor* descriptor, | 131 bool FieldMaskUtil::GetFieldDescriptors( |
132 StringPiece path) { | 132 const Descriptor* descriptor, StringPiece path, |
133 vector<string> parts = Split(path, "."); | 133 std::vector<const FieldDescriptor*>* field_descriptors) { |
| 134 if (field_descriptors != NULL) { |
| 135 field_descriptors->clear(); |
| 136 } |
| 137 std::vector<string> parts = Split(path, "."); |
134 for (int i = 0; i < parts.size(); ++i) { | 138 for (int i = 0; i < parts.size(); ++i) { |
135 const string& field_name = parts[i]; | 139 const string& field_name = parts[i]; |
136 if (descriptor == NULL) { | 140 if (descriptor == NULL) { |
137 return false; | 141 return false; |
138 } | 142 } |
139 const FieldDescriptor* field = descriptor->FindFieldByName(field_name); | 143 const FieldDescriptor* field = descriptor->FindFieldByName(field_name); |
140 if (field == NULL) { | 144 if (field == NULL) { |
141 return false; | 145 return false; |
142 } | 146 } |
| 147 if (field_descriptors != NULL) { |
| 148 field_descriptors->push_back(field); |
| 149 } |
143 if (!field->is_repeated() && | 150 if (!field->is_repeated() && |
144 field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { | 151 field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
145 descriptor = field->message_type(); | 152 descriptor = field->message_type(); |
146 } else { | 153 } else { |
147 descriptor = NULL; | 154 descriptor = NULL; |
148 } | 155 } |
149 } | 156 } |
150 return true; | 157 return true; |
151 } | 158 } |
152 | 159 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
193 void MergeMessage(const Message& source, | 200 void MergeMessage(const Message& source, |
194 const FieldMaskUtil::MergeOptions& options, | 201 const FieldMaskUtil::MergeOptions& options, |
195 Message* destination) { | 202 Message* destination) { |
196 // Do nothing if the tree is empty. | 203 // Do nothing if the tree is empty. |
197 if (root_.children.empty()) { | 204 if (root_.children.empty()) { |
198 return; | 205 return; |
199 } | 206 } |
200 MergeMessage(&root_, source, options, destination); | 207 MergeMessage(&root_, source, options, destination); |
201 } | 208 } |
202 | 209 |
| 210 // Trims all fields not specified by this tree from the given message. |
| 211 void TrimMessage(Message* message) { |
| 212 // Do nothing if the tree is empty. |
| 213 if (root_.children.empty()) { |
| 214 return; |
| 215 } |
| 216 TrimMessage(&root_, message); |
| 217 } |
| 218 |
203 private: | 219 private: |
204 struct Node { | 220 struct Node { |
205 Node() {} | 221 Node() {} |
206 | 222 |
207 ~Node() { ClearChildren(); } | 223 ~Node() { ClearChildren(); } |
208 | 224 |
209 void ClearChildren() { | 225 void ClearChildren() { |
210 for (map<string, Node*>::iterator it = children.begin(); | 226 for (std::map<string, Node*>::iterator it = children.begin(); |
211 it != children.end(); ++it) { | 227 it != children.end(); ++it) { |
212 delete it->second; | 228 delete it->second; |
213 } | 229 } |
214 children.clear(); | 230 children.clear(); |
215 } | 231 } |
216 | 232 |
217 map<string, Node*> children; | 233 std::map<string, Node*> children; |
218 | 234 |
219 private: | 235 private: |
220 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Node); | 236 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Node); |
221 }; | 237 }; |
222 | 238 |
223 // Merge a sub-tree to mask. This method adds the field paths represented | 239 // Merge a sub-tree to mask. This method adds the field paths represented |
224 // by all leaf nodes descended from "node" to mask. | 240 // by all leaf nodes descended from "node" to mask. |
225 void MergeToFieldMask(const string& prefix, const Node* node, FieldMask* out); | 241 void MergeToFieldMask(const string& prefix, const Node* node, FieldMask* out); |
226 | 242 |
227 // Merge all leaf nodes of a sub-tree to another tree. | 243 // Merge all leaf nodes of a sub-tree to another tree. |
228 void MergeLeafNodesToTree(const string& prefix, const Node* node, | 244 void MergeLeafNodesToTree(const string& prefix, const Node* node, |
229 FieldMaskTree* out); | 245 FieldMaskTree* out); |
230 | 246 |
231 // Merge all fields specified by a sub-tree from one message to another. | 247 // Merge all fields specified by a sub-tree from one message to another. |
232 void MergeMessage(const Node* node, const Message& source, | 248 void MergeMessage(const Node* node, const Message& source, |
233 const FieldMaskUtil::MergeOptions& options, | 249 const FieldMaskUtil::MergeOptions& options, |
234 Message* destination); | 250 Message* destination); |
235 | 251 |
| 252 // Trims all fields not specified by this sub-tree from the given message. |
| 253 void TrimMessage(const Node* node, Message* message); |
| 254 |
236 Node root_; | 255 Node root_; |
237 | 256 |
238 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldMaskTree); | 257 GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldMaskTree); |
239 }; | 258 }; |
240 | 259 |
241 FieldMaskTree::FieldMaskTree() {} | 260 FieldMaskTree::FieldMaskTree() {} |
242 | 261 |
243 FieldMaskTree::~FieldMaskTree() {} | 262 FieldMaskTree::~FieldMaskTree() {} |
244 | 263 |
245 void FieldMaskTree::MergeFromFieldMask(const FieldMask& mask) { | 264 void FieldMaskTree::MergeFromFieldMask(const FieldMask& mask) { |
246 for (int i = 0; i < mask.paths_size(); ++i) { | 265 for (int i = 0; i < mask.paths_size(); ++i) { |
247 AddPath(mask.paths(i)); | 266 AddPath(mask.paths(i)); |
248 } | 267 } |
249 } | 268 } |
250 | 269 |
251 void FieldMaskTree::MergeToFieldMask(FieldMask* mask) { | 270 void FieldMaskTree::MergeToFieldMask(FieldMask* mask) { |
252 MergeToFieldMask("", &root_, mask); | 271 MergeToFieldMask("", &root_, mask); |
253 } | 272 } |
254 | 273 |
255 void FieldMaskTree::MergeToFieldMask(const string& prefix, const Node* node, | 274 void FieldMaskTree::MergeToFieldMask(const string& prefix, const Node* node, |
256 FieldMask* out) { | 275 FieldMask* out) { |
257 if (node->children.empty()) { | 276 if (node->children.empty()) { |
258 if (prefix.empty()) { | 277 if (prefix.empty()) { |
259 // This is the root node. | 278 // This is the root node. |
260 return; | 279 return; |
261 } | 280 } |
262 out->add_paths(prefix); | 281 out->add_paths(prefix); |
263 return; | 282 return; |
264 } | 283 } |
265 for (map<string, Node*>::const_iterator it = node->children.begin(); | 284 for (std::map<string, Node*>::const_iterator it = node->children.begin(); |
266 it != node->children.end(); ++it) { | 285 it != node->children.end(); ++it) { |
267 string current_path = prefix.empty() ? it->first : prefix + "." + it->first; | 286 string current_path = prefix.empty() ? it->first : prefix + "." + it->first; |
268 MergeToFieldMask(current_path, it->second, out); | 287 MergeToFieldMask(current_path, it->second, out); |
269 } | 288 } |
270 } | 289 } |
271 | 290 |
272 void FieldMaskTree::AddPath(const string& path) { | 291 void FieldMaskTree::AddPath(const string& path) { |
273 vector<string> parts = Split(path, "."); | 292 std::vector<string> parts = Split(path, "."); |
274 if (parts.empty()) { | 293 if (parts.empty()) { |
275 return; | 294 return; |
276 } | 295 } |
277 bool new_branch = false; | 296 bool new_branch = false; |
278 Node* node = &root_; | 297 Node* node = &root_; |
279 for (int i = 0; i < parts.size(); ++i) { | 298 for (int i = 0; i < parts.size(); ++i) { |
280 if (!new_branch && node != &root_ && node->children.empty()) { | 299 if (!new_branch && node != &root_ && node->children.empty()) { |
281 // Path matches an existing leaf node. This means the path is already | 300 // Path matches an existing leaf node. This means the path is already |
282 // coverred by this tree (for example, adding "foo.bar.baz" to a tree | 301 // coverred by this tree (for example, adding "foo.bar.baz" to a tree |
283 // which already contains "foo.bar"). | 302 // which already contains "foo.bar"). |
284 return; | 303 return; |
285 } | 304 } |
286 const string& node_name = parts[i]; | 305 const string& node_name = parts[i]; |
287 Node*& child = node->children[node_name]; | 306 Node*& child = node->children[node_name]; |
288 if (child == NULL) { | 307 if (child == NULL) { |
289 new_branch = true; | 308 new_branch = true; |
290 child = new Node(); | 309 child = new Node(); |
291 } | 310 } |
292 node = child; | 311 node = child; |
293 } | 312 } |
294 if (!node->children.empty()) { | 313 if (!node->children.empty()) { |
295 node->ClearChildren(); | 314 node->ClearChildren(); |
296 } | 315 } |
297 } | 316 } |
298 | 317 |
299 void FieldMaskTree::IntersectPath(const string& path, FieldMaskTree* out) { | 318 void FieldMaskTree::IntersectPath(const string& path, FieldMaskTree* out) { |
300 vector<string> parts = Split(path, "."); | 319 std::vector<string> parts = Split(path, "."); |
301 if (parts.empty()) { | 320 if (parts.empty()) { |
302 return; | 321 return; |
303 } | 322 } |
304 const Node* node = &root_; | 323 const Node* node = &root_; |
305 for (int i = 0; i < parts.size(); ++i) { | 324 for (int i = 0; i < parts.size(); ++i) { |
306 if (node->children.empty()) { | 325 if (node->children.empty()) { |
307 if (node != &root_) { | 326 if (node != &root_) { |
308 out->AddPath(path); | 327 out->AddPath(path); |
309 } | 328 } |
310 return; | 329 return; |
311 } | 330 } |
312 const string& node_name = parts[i]; | 331 const string& node_name = parts[i]; |
313 const Node* result = FindPtrOrNull(node->children, node_name); | 332 const Node* result = FindPtrOrNull(node->children, node_name); |
314 if (result == NULL) { | 333 if (result == NULL) { |
315 // No intersection found. | 334 // No intersection found. |
316 return; | 335 return; |
317 } | 336 } |
318 node = result; | 337 node = result; |
319 } | 338 } |
320 // Now we found a matching node with the given path. Add all leaf nodes | 339 // Now we found a matching node with the given path. Add all leaf nodes |
321 // to out. | 340 // to out. |
322 MergeLeafNodesToTree(path, node, out); | 341 MergeLeafNodesToTree(path, node, out); |
323 } | 342 } |
324 | 343 |
325 void FieldMaskTree::MergeLeafNodesToTree(const string& prefix, const Node* node, | 344 void FieldMaskTree::MergeLeafNodesToTree(const string& prefix, const Node* node, |
326 FieldMaskTree* out) { | 345 FieldMaskTree* out) { |
327 if (node->children.empty()) { | 346 if (node->children.empty()) { |
328 out->AddPath(prefix); | 347 out->AddPath(prefix); |
329 } | 348 } |
330 for (map<string, Node*>::const_iterator it = node->children.begin(); | 349 for (std::map<string, Node*>::const_iterator it = node->children.begin(); |
331 it != node->children.end(); ++it) { | 350 it != node->children.end(); ++it) { |
332 string current_path = prefix.empty() ? it->first : prefix + "." + it->first; | 351 string current_path = prefix.empty() ? it->first : prefix + "." + it->first; |
333 MergeLeafNodesToTree(current_path, it->second, out); | 352 MergeLeafNodesToTree(current_path, it->second, out); |
334 } | 353 } |
335 } | 354 } |
336 | 355 |
337 void FieldMaskTree::MergeMessage(const Node* node, const Message& source, | 356 void FieldMaskTree::MergeMessage(const Node* node, const Message& source, |
338 const FieldMaskUtil::MergeOptions& options, | 357 const FieldMaskUtil::MergeOptions& options, |
339 Message* destination) { | 358 Message* destination) { |
340 GOOGLE_DCHECK(!node->children.empty()); | 359 GOOGLE_DCHECK(!node->children.empty()); |
341 const Reflection* source_reflection = source.GetReflection(); | 360 const Reflection* source_reflection = source.GetReflection(); |
342 const Reflection* destination_reflection = destination->GetReflection(); | 361 const Reflection* destination_reflection = destination->GetReflection(); |
343 const Descriptor* descriptor = source.GetDescriptor(); | 362 const Descriptor* descriptor = source.GetDescriptor(); |
344 for (map<string, Node*>::const_iterator it = node->children.begin(); | 363 for (std::map<string, Node*>::const_iterator it = node->children.begin(); |
345 it != node->children.end(); ++it) { | 364 it != node->children.end(); ++it) { |
346 const string& field_name = it->first; | 365 const string& field_name = it->first; |
347 const Node* child = it->second; | 366 const Node* child = it->second; |
348 const FieldDescriptor* field = descriptor->FindFieldByName(field_name); | 367 const FieldDescriptor* field = descriptor->FindFieldByName(field_name); |
349 if (field == NULL) { | 368 if (field == NULL) { |
350 GOOGLE_LOG(ERROR) << "Cannot find field \"" << field_name << "\" in messag
e " | 369 GOOGLE_LOG(ERROR) << "Cannot find field \"" << field_name << "\" in messag
e " |
351 << descriptor->full_name(); | 370 << descriptor->full_name(); |
352 continue; | 371 continue; |
353 } | 372 } |
354 if (!child->children.empty()) { | 373 if (!child->children.empty()) { |
355 // Sub-paths are only allowed for singular message fields. | 374 // Sub-paths are only allowed for singular message fields. |
356 if (field->is_repeated() || | 375 if (field->is_repeated() || |
357 field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { | 376 field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { |
358 GOOGLE_LOG(ERROR) << "Field \"" << field_name << "\" in message " | 377 GOOGLE_LOG(ERROR) << "Field \"" << field_name << "\" in message " |
359 << descriptor->full_name() | 378 << descriptor->full_name() |
360 << " is not a singular message field and cannot " | 379 << " is not a singular message field and cannot " |
361 << "have sub-fields."; | 380 << "have sub-fields."; |
362 continue; | 381 continue; |
363 } | 382 } |
364 MergeMessage(child, source_reflection->GetMessage(source, field), options, | 383 MergeMessage(child, source_reflection->GetMessage(source, field), options, |
365 destination_reflection->MutableMessage(destination, field)); | 384 destination_reflection->MutableMessage(destination, field)); |
366 continue; | 385 continue; |
367 } | 386 } |
368 if (!field->is_repeated()) { | 387 if (!field->is_repeated()) { |
369 switch (field->cpp_type()) { | 388 switch (field->cpp_type()) { |
370 #define COPY_VALUE(TYPE, Name) \ | 389 #define COPY_VALUE(TYPE, Name) \ |
371 case FieldDescriptor::CPPTYPE_##TYPE: { \ | 390 case FieldDescriptor::CPPTYPE_##TYPE: { \ |
372 destination_reflection->Set##Name( \ | 391 if (source_reflection->HasField(source, field)) { \ |
373 destination, field, source_reflection->Get##Name(source, field)); \ | 392 destination_reflection->Set##Name( \ |
374 break; \ | 393 destination, field, source_reflection->Get##Name(source, field)); \ |
| 394 } else { \ |
| 395 destination_reflection->ClearField(destination, field); \ |
| 396 } \ |
| 397 break; \ |
375 } | 398 } |
376 COPY_VALUE(BOOL, Bool) | 399 COPY_VALUE(BOOL, Bool) |
377 COPY_VALUE(INT32, Int32) | 400 COPY_VALUE(INT32, Int32) |
378 COPY_VALUE(INT64, Int64) | 401 COPY_VALUE(INT64, Int64) |
379 COPY_VALUE(UINT32, UInt32) | 402 COPY_VALUE(UINT32, UInt32) |
380 COPY_VALUE(UINT64, UInt64) | 403 COPY_VALUE(UINT64, UInt64) |
381 COPY_VALUE(FLOAT, Float) | 404 COPY_VALUE(FLOAT, Float) |
382 COPY_VALUE(DOUBLE, Double) | 405 COPY_VALUE(DOUBLE, Double) |
383 COPY_VALUE(ENUM, Enum) | 406 COPY_VALUE(ENUM, Enum) |
384 COPY_VALUE(STRING, String) | 407 COPY_VALUE(STRING, String) |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
426 ->MergeFrom( | 449 ->MergeFrom( |
427 source_reflection->GetRepeatedMessage(source, field, i)); | 450 source_reflection->GetRepeatedMessage(source, field, i)); |
428 } | 451 } |
429 break; | 452 break; |
430 } | 453 } |
431 } | 454 } |
432 } | 455 } |
433 } | 456 } |
434 } | 457 } |
435 | 458 |
| 459 void FieldMaskTree::TrimMessage(const Node* node, Message* message) { |
| 460 GOOGLE_DCHECK(!node->children.empty()); |
| 461 const Reflection* reflection = message->GetReflection(); |
| 462 const Descriptor* descriptor = message->GetDescriptor(); |
| 463 const int32 field_count = descriptor->field_count(); |
| 464 for (int index = 0; index < field_count; ++index) { |
| 465 const FieldDescriptor* field = descriptor->field(index); |
| 466 map<string, Node*>::const_iterator it = node->children.find(field->name()); |
| 467 if (it == node->children.end()) { |
| 468 reflection->ClearField(message, field); |
| 469 } else { |
| 470 if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { |
| 471 Node* child = it->second; |
| 472 if (!child->children.empty()) { |
| 473 TrimMessage(child, reflection->MutableMessage(message, field)); |
| 474 } |
| 475 } |
| 476 } |
| 477 } |
| 478 } |
| 479 |
436 } // namespace | 480 } // namespace |
437 | 481 |
438 void FieldMaskUtil::ToCanonicalForm(const FieldMask& mask, FieldMask* out) { | 482 void FieldMaskUtil::ToCanonicalForm(const FieldMask& mask, FieldMask* out) { |
439 FieldMaskTree tree; | 483 FieldMaskTree tree; |
440 tree.MergeFromFieldMask(mask); | 484 tree.MergeFromFieldMask(mask); |
441 out->Clear(); | 485 out->Clear(); |
442 tree.MergeToFieldMask(out); | 486 tree.MergeToFieldMask(out); |
443 } | 487 } |
444 | 488 |
445 void FieldMaskUtil::Union(const FieldMask& mask1, const FieldMask& mask2, | 489 void FieldMaskUtil::Union(const FieldMask& mask1, const FieldMask& mask2, |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
482 const MergeOptions& options, | 526 const MergeOptions& options, |
483 Message* destination) { | 527 Message* destination) { |
484 GOOGLE_CHECK(source.GetDescriptor() == destination->GetDescriptor()); | 528 GOOGLE_CHECK(source.GetDescriptor() == destination->GetDescriptor()); |
485 // Build a FieldMaskTree and walk through the tree to merge all specified | 529 // Build a FieldMaskTree and walk through the tree to merge all specified |
486 // fields. | 530 // fields. |
487 FieldMaskTree tree; | 531 FieldMaskTree tree; |
488 tree.MergeFromFieldMask(mask); | 532 tree.MergeFromFieldMask(mask); |
489 tree.MergeMessage(source, options, destination); | 533 tree.MergeMessage(source, options, destination); |
490 } | 534 } |
491 | 535 |
| 536 void FieldMaskUtil::TrimMessage(const FieldMask& mask, Message* destination) { |
| 537 // Build a FieldMaskTree and walk through the tree to merge all specified |
| 538 // fields. |
| 539 FieldMaskTree tree; |
| 540 tree.MergeFromFieldMask(mask); |
| 541 tree.TrimMessage(GOOGLE_CHECK_NOTNULL(destination)); |
| 542 } |
| 543 |
492 } // namespace util | 544 } // namespace util |
493 } // namespace protobuf | 545 } // namespace protobuf |
494 } // namespace google | 546 } // namespace google |
OLD | NEW |