Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(22)

Side by Side Diff: third_party/protobuf/java/util/src/main/java/com/google/protobuf/util/FieldMaskTree.java

Issue 2495533002: third_party/protobuf: Update to HEAD (83d681ee2c) (Closed)
Patch Set: Make chrome settings proto generated file a component Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 20 matching lines...) Expand all
31 package com.google.protobuf.util; 31 package com.google.protobuf.util;
32 32
33 import com.google.protobuf.Descriptors.Descriptor; 33 import com.google.protobuf.Descriptors.Descriptor;
34 import com.google.protobuf.Descriptors.FieldDescriptor; 34 import com.google.protobuf.Descriptors.FieldDescriptor;
35 import com.google.protobuf.FieldMask; 35 import com.google.protobuf.FieldMask;
36 import com.google.protobuf.Message; 36 import com.google.protobuf.Message;
37 37
38 import java.util.ArrayList; 38 import java.util.ArrayList;
39 import java.util.List; 39 import java.util.List;
40 import java.util.Map.Entry; 40 import java.util.Map.Entry;
41 import java.util.SortedMap;
41 import java.util.TreeMap; 42 import java.util.TreeMap;
42 import java.util.logging.Logger; 43 import java.util.logging.Logger;
43 44
44 /** 45 /**
45 * A tree representation of a FieldMask. Each leaf node in this tree represent 46 * A tree representation of a FieldMask. Each leaf node in this tree represent
46 * a field path in the FieldMask. 47 * a field path in the FieldMask.
47 * 48 *
48 * <p>For example, FieldMask "foo.bar,foo.baz,bar.baz" as a tree will be: 49 * <p>For example, FieldMask "foo.bar,foo.baz,bar.baz" as a tree will be:
49 * <pre> 50 * <pre>
50 * [root] -+- foo -+- bar 51 * [root] -+- foo -+- bar
51 * | | 52 * | |
52 * | +- baz 53 * | +- baz
53 * | 54 * |
54 * +- bar --- baz 55 * +- bar --- baz
55 * </pre> 56 * </pre>
56 * 57 *
57 * <p>By representing FieldMasks with this tree structure we can easily convert 58 * <p>By representing FieldMasks with this tree structure we can easily convert
58 * a FieldMask to a canonical form, merge two FieldMasks, calculate the 59 * a FieldMask to a canonical form, merge two FieldMasks, calculate the
59 * intersection to two FieldMasks and traverse all fields specified by the 60 * intersection to two FieldMasks and traverse all fields specified by the
60 * FieldMask in a message tree. 61 * FieldMask in a message tree.
61 */ 62 */
62 class FieldMaskTree { 63 final class FieldMaskTree {
63 private static final Logger logger = Logger.getLogger(FieldMaskTree.class.getN ame()); 64 private static final Logger logger = Logger.getLogger(FieldMaskTree.class.getN ame());
64 65
65 private static final String FIELD_PATH_SEPARATOR_REGEX = "\\."; 66 private static final String FIELD_PATH_SEPARATOR_REGEX = "\\.";
66 67
67 private static class Node { 68 private static final class Node {
68 public TreeMap<String, Node> children = new TreeMap<String, Node>(); 69 final SortedMap<String, Node> children = new TreeMap<String, Node>();
69 } 70 }
70 71
71 private final Node root = new Node(); 72 private final Node root = new Node();
72 73
73 /** Creates an empty FieldMaskTree. */ 74 /**
74 public FieldMaskTree() {} 75 * Creates an empty FieldMaskTree.
76 */
77 FieldMaskTree() {}
75 78
76 /** Creates a FieldMaskTree for a given FieldMask. */ 79 /**
77 public FieldMaskTree(FieldMask mask) { 80 * Creates a FieldMaskTree for a given FieldMask.
81 */
82 FieldMaskTree(FieldMask mask) {
78 mergeFromFieldMask(mask); 83 mergeFromFieldMask(mask);
79 } 84 }
80 85
81 @Override 86 @Override
82 public String toString() { 87 public String toString() {
83 return FieldMaskUtil.toString(toFieldMask()); 88 return FieldMaskUtil.toString(toFieldMask());
84 } 89 }
85 90
86 /** 91 /**
87 * Adds a field path to the tree. In a FieldMask, every field path matches the 92 * Adds a field path to the tree. In a FieldMask, every field path matches the
88 * specified field as well as all its sub-fields. For example, a field path 93 * specified field as well as all its sub-fields. For example, a field path
89 * "foo.bar" matches field "foo.bar" and also "foo.bar.baz", etc. When adding 94 * "foo.bar" matches field "foo.bar" and also "foo.bar.baz", etc. When adding
90 * a field path to the tree, redundant sub-paths will be removed. That is, 95 * a field path to the tree, redundant sub-paths will be removed. That is,
91 * after adding "foo.bar" to the tree, "foo.bar.baz" will be removed if it 96 * after adding "foo.bar" to the tree, "foo.bar.baz" will be removed if it
92 * exists, which will turn the tree node for "foo.bar" to a leaf node. 97 * exists, which will turn the tree node for "foo.bar" to a leaf node.
93 * Likewise, if the field path to add is a sub-path of an existing leaf node, 98 * Likewise, if the field path to add is a sub-path of an existing leaf node,
94 * nothing will be changed in the tree. 99 * nothing will be changed in the tree.
95 */ 100 */
96 public FieldMaskTree addFieldPath(String path) { 101 FieldMaskTree addFieldPath(String path) {
97 String[] parts = path.split(FIELD_PATH_SEPARATOR_REGEX); 102 String[] parts = path.split(FIELD_PATH_SEPARATOR_REGEX);
98 if (parts.length == 0) { 103 if (parts.length == 0) {
99 return this; 104 return this;
100 } 105 }
101 Node node = root; 106 Node node = root;
102 boolean createNewBranch = false; 107 boolean createNewBranch = false;
103 // Find the matching node in the tree. 108 // Find the matching node in the tree.
104 for (String part : parts) { 109 for (String part : parts) {
105 // Check whether the path matches an existing leaf node. 110 // Check whether the path matches an existing leaf node.
106 if (!createNewBranch && node != root && node.children.isEmpty()) { 111 if (!createNewBranch && node != root && node.children.isEmpty()) {
(...skipping 10 matching lines...) Expand all
117 } 122 }
118 } 123 }
119 // Turn the matching node into a leaf node (i.e., remove sub-paths). 124 // Turn the matching node into a leaf node (i.e., remove sub-paths).
120 node.children.clear(); 125 node.children.clear();
121 return this; 126 return this;
122 } 127 }
123 128
124 /** 129 /**
125 * Merges all field paths in a FieldMask into this tree. 130 * Merges all field paths in a FieldMask into this tree.
126 */ 131 */
127 public FieldMaskTree mergeFromFieldMask(FieldMask mask) { 132 FieldMaskTree mergeFromFieldMask(FieldMask mask) {
128 for (String path : mask.getPathsList()) { 133 for (String path : mask.getPathsList()) {
129 addFieldPath(path); 134 addFieldPath(path);
130 } 135 }
131 return this; 136 return this;
132 } 137 }
133 138
134 /** Converts this tree to a FieldMask. */ 139 /**
135 public FieldMask toFieldMask() { 140 * Converts this tree to a FieldMask.
141 */
142 FieldMask toFieldMask() {
136 if (root.children.isEmpty()) { 143 if (root.children.isEmpty()) {
137 return FieldMask.getDefaultInstance(); 144 return FieldMask.getDefaultInstance();
138 } 145 }
139 List<String> paths = new ArrayList<String>(); 146 List<String> paths = new ArrayList<String>();
140 getFieldPaths(root, "", paths); 147 getFieldPaths(root, "", paths);
141 return FieldMask.newBuilder().addAllPaths(paths).build(); 148 return FieldMask.newBuilder().addAllPaths(paths).build();
142 } 149 }
143 150
144 /** Gathers all field paths in a sub-tree. */ 151 /**
152 * Gathers all field paths in a sub-tree.
153 */
145 private void getFieldPaths(Node node, String path, List<String> paths) { 154 private void getFieldPaths(Node node, String path, List<String> paths) {
146 if (node.children.isEmpty()) { 155 if (node.children.isEmpty()) {
147 paths.add(path); 156 paths.add(path);
148 return; 157 return;
149 } 158 }
150 for (Entry<String, Node> entry : node.children.entrySet()) { 159 for (Entry<String, Node> entry : node.children.entrySet()) {
151 String childPath = path.isEmpty() ? entry.getKey() : path + "." + entry.ge tKey(); 160 String childPath = path.isEmpty() ? entry.getKey() : path + "." + entry.ge tKey();
152 getFieldPaths(entry.getValue(), childPath, paths); 161 getFieldPaths(entry.getValue(), childPath, paths);
153 } 162 }
154 } 163 }
155 164
156 /** 165 /**
157 * Adds the intersection of this tree with the given {@code path} to 166 * Adds the intersection of this tree with the given {@code path} to {@code ou tput}.
158 * {@code output}.
159 */ 167 */
160 public void intersectFieldPath(String path, FieldMaskTree output) { 168 void intersectFieldPath(String path, FieldMaskTree output) {
161 if (root.children.isEmpty()) { 169 if (root.children.isEmpty()) {
162 return; 170 return;
163 } 171 }
164 String[] parts = path.split(FIELD_PATH_SEPARATOR_REGEX); 172 String[] parts = path.split(FIELD_PATH_SEPARATOR_REGEX);
165 if (parts.length == 0) { 173 if (parts.length == 0) {
166 return; 174 return;
167 } 175 }
168 Node node = root; 176 Node node = root;
169 for (String part : parts) { 177 for (String part : parts) {
170 if (node != root && node.children.isEmpty()) { 178 if (node != root && node.children.isEmpty()) {
(...skipping 10 matching lines...) Expand all
181 // We found a matching node for the path. All leaf children of this matching 189 // We found a matching node for the path. All leaf children of this matching
182 // node is in the intersection. 190 // node is in the intersection.
183 List<String> paths = new ArrayList<String>(); 191 List<String> paths = new ArrayList<String>();
184 getFieldPaths(node, path, paths); 192 getFieldPaths(node, path, paths);
185 for (String value : paths) { 193 for (String value : paths) {
186 output.addFieldPath(value); 194 output.addFieldPath(value);
187 } 195 }
188 } 196 }
189 197
190 /** 198 /**
191 * Merges all fields specified by this FieldMaskTree from {@code source} to 199 * Merges all fields specified by this FieldMaskTree from {@code source} to {@ code destination}.
192 * {@code destination}.
193 */ 200 */
194 public void merge( 201 void merge(Message source, Message.Builder destination, FieldMaskUtil.MergeOpt ions options) {
195 Message source, Message.Builder destination, FieldMaskUtil.MergeOptions op tions) {
196 if (source.getDescriptorForType() != destination.getDescriptorForType()) { 202 if (source.getDescriptorForType() != destination.getDescriptorForType()) {
197 throw new IllegalArgumentException("Cannot merge messages of different typ es."); 203 throw new IllegalArgumentException("Cannot merge messages of different typ es.");
198 } 204 }
199 if (root.children.isEmpty()) { 205 if (root.children.isEmpty()) {
200 return; 206 return;
201 } 207 }
202 merge(root, "", source, destination, options); 208 merge(root, "", source, destination, options);
203 } 209 }
204 210
205 /** Merges all fields specified by a sub-tree from {@code source} to 211 /**
206 * {@code destination}. 212 * Merges all fields specified by a sub-tree from {@code source} to {@code des tination}.
207 */ 213 */
208 private void merge( 214 private void merge(
209 Node node, 215 Node node,
210 String path, 216 String path,
211 Message source, 217 Message source,
212 Message.Builder destination, 218 Message.Builder destination,
213 FieldMaskUtil.MergeOptions options) { 219 FieldMaskUtil.MergeOptions options) {
214 assert source.getDescriptorForType() == destination.getDescriptorForType(); 220 if (source.getDescriptorForType() != destination.getDescriptorForType()) {
221 throw new IllegalArgumentException(
222 String.format(
223 "source (%s) and destination (%s) descriptor must be equal",
224 source.getDescriptorForType(), destination.getDescriptorForType()) );
225 }
215 226
216 Descriptor descriptor = source.getDescriptorForType(); 227 Descriptor descriptor = source.getDescriptorForType();
217 for (Entry<String, Node> entry : node.children.entrySet()) { 228 for (Entry<String, Node> entry : node.children.entrySet()) {
218 FieldDescriptor field = descriptor.findFieldByName(entry.getKey()); 229 FieldDescriptor field = descriptor.findFieldByName(entry.getKey());
219 if (field == null) { 230 if (field == null) {
220 logger.warning( 231 logger.warning(
221 "Cannot find field \"" 232 "Cannot find field \""
222 + entry.getKey() 233 + entry.getKey()
223 + "\" in message type " 234 + "\" in message type "
224 + descriptor.getFullName()); 235 + descriptor.getFullName());
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 if (source.hasField(field) || !options.replacePrimitiveFields()) { 278 if (source.hasField(field) || !options.replacePrimitiveFields()) {
268 destination.setField(field, source.getField(field)); 279 destination.setField(field, source.getField(field));
269 } else { 280 } else {
270 destination.clearField(field); 281 destination.clearField(field);
271 } 282 }
272 } 283 }
273 } 284 }
274 } 285 }
275 } 286 }
276 } 287 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698