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

Side by Side Diff: third_party/protobuf/java/core/src/main/java/com/google/protobuf/RepeatedFieldBuilderV3.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
(Empty)
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 package com.google.protobuf;
32
33 import java.util.AbstractList;
34 import java.util.ArrayList;
35 import java.util.Collection;
36 import java.util.Collections;
37 import java.util.List;
38
39 /**
40 * {@code RepeatedFieldBuilderV3} implements a structure that a protocol
41 * message uses to hold a repeated field of other protocol messages. It supports
42 * the classical use case of adding immutable {@link Message}'s to the
43 * repeated field and is highly optimized around this (no extra memory
44 * allocations and sharing of immutable arrays).
45 * <br>
46 * It also supports the additional use case of adding a {@link Message.Builder}
47 * to the repeated field and deferring conversion of that {@code Builder}
48 * to an immutable {@code Message}. In this way, it's possible to maintain
49 * a tree of {@code Builder}'s that acts as a fully read/write data
50 * structure.
51 * <br>
52 * Logically, one can think of a tree of builders as converting the entire tree
53 * to messages when build is called on the root or when any method is called
54 * that desires a Message instead of a Builder. In terms of the implementation,
55 * the {@code SingleFieldBuilderV3} and {@code RepeatedFieldBuilderV3}
56 * classes cache messages that were created so that messages only need to be
57 * created when some change occurred in its builder or a builder for one of its
58 * descendants.
59 *
60 * @param <MType> the type of message for the field
61 * @param <BType> the type of builder for the field
62 * @param <IType> the common interface for the message and the builder
63 *
64 * @author jonp@google.com (Jon Perlow)
65 */
66 public class RepeatedFieldBuilderV3
67 <MType extends AbstractMessage,
68 BType extends AbstractMessage.Builder,
69 IType extends MessageOrBuilder>
70 implements AbstractMessage.BuilderParent {
71
72 // Parent to send changes to.
73 private AbstractMessage.BuilderParent parent;
74
75 // List of messages. Never null. It may be immutable, in which case
76 // isMessagesListMutable will be false. See note below.
77 private List<MType> messages;
78
79 // Whether messages is an mutable array that can be modified.
80 private boolean isMessagesListMutable;
81
82 // List of builders. May be null, in which case, no nested builders were
83 // created. If not null, entries represent the builder for that index.
84 private List<SingleFieldBuilderV3<MType, BType, IType>> builders;
85
86 // Here are the invariants for messages and builders:
87 // 1. messages is never null and its count corresponds to the number of items
88 // in the repeated field.
89 // 2. If builders is non-null, messages and builders MUST always
90 // contain the same number of items.
91 // 3. Entries in either array can be null, but for any index, there MUST be
92 // either a Message in messages or a builder in builders.
93 // 4. If the builder at an index is non-null, the builder is
94 // authoritative. This is the case where a Builder was set on the index.
95 // Any message in the messages array MUST be ignored.
96 // t. If the builder at an index is null, the message in the messages
97 // list is authoritative. This is the case where a Message (not a Builder)
98 // was set directly for an index.
99
100 // Indicates that we've built a message and so we are now obligated
101 // to dispatch dirty invalidations. See AbstractMessage.BuilderListener.
102 private boolean isClean;
103
104 // A view of this builder that exposes a List interface of messages. This is
105 // initialized on demand. This is fully backed by this object and all changes
106 // are reflected in it. Access to any item converts it to a message if it
107 // was a builder.
108 private MessageExternalList<MType, BType, IType> externalMessageList;
109
110 // A view of this builder that exposes a List interface of builders. This is
111 // initialized on demand. This is fully backed by this object and all changes
112 // are reflected in it. Access to any item converts it to a builder if it
113 // was a message.
114 private BuilderExternalList<MType, BType, IType> externalBuilderList;
115
116 // A view of this builder that exposes a List interface of the interface
117 // implemented by messages and builders. This is initialized on demand. This
118 // is fully backed by this object and all changes are reflected in it.
119 // Access to any item returns either a builder or message depending on
120 // what is most efficient.
121 private MessageOrBuilderExternalList<MType, BType, IType>
122 externalMessageOrBuilderList;
123
124 /**
125 * Constructs a new builder with an empty list of messages.
126 *
127 * @param messages the current list of messages
128 * @param isMessagesListMutable Whether the messages list is mutable
129 * @param parent a listener to notify of changes
130 * @param isClean whether the builder is initially marked clean
131 */
132 public RepeatedFieldBuilderV3(
133 List<MType> messages,
134 boolean isMessagesListMutable,
135 AbstractMessage.BuilderParent parent,
136 boolean isClean) {
137 this.messages = messages;
138 this.isMessagesListMutable = isMessagesListMutable;
139 this.parent = parent;
140 this.isClean = isClean;
141 }
142
143 public void dispose() {
144 // Null out parent so we stop sending it invalidations.
145 parent = null;
146 }
147
148 /**
149 * Ensures that the list of messages is mutable so it can be updated. If it's
150 * immutable, a copy is made.
151 */
152 private void ensureMutableMessageList() {
153 if (!isMessagesListMutable) {
154 messages = new ArrayList<MType>(messages);
155 isMessagesListMutable = true;
156 }
157 }
158
159 /**
160 * Ensures that the list of builders is not null. If it's null, the list is
161 * created and initialized to be the same size as the messages list with
162 * null entries.
163 */
164 private void ensureBuilders() {
165 if (this.builders == null) {
166 this.builders =
167 new ArrayList<SingleFieldBuilderV3<MType, BType, IType>>(
168 messages.size());
169 for (int i = 0; i < messages.size(); i++) {
170 builders.add(null);
171 }
172 }
173 }
174
175 /**
176 * Gets the count of items in the list.
177 *
178 * @return the count of items in the list.
179 */
180 public int getCount() {
181 return messages.size();
182 }
183
184 /**
185 * Gets whether the list is empty.
186 *
187 * @return whether the list is empty
188 */
189 public boolean isEmpty() {
190 return messages.isEmpty();
191 }
192
193 /**
194 * Get the message at the specified index. If the message is currently stored
195 * as a {@code Builder}, it is converted to a {@code Message} by
196 * calling {@link Message.Builder#buildPartial} on it.
197 *
198 * @param index the index of the message to get
199 * @return the message for the specified index
200 */
201 public MType getMessage(int index) {
202 return getMessage(index, false);
203 }
204
205 /**
206 * Get the message at the specified index. If the message is currently stored
207 * as a {@code Builder}, it is converted to a {@code Message} by
208 * calling {@link Message.Builder#buildPartial} on it.
209 *
210 * @param index the index of the message to get
211 * @param forBuild this is being called for build so we want to make sure
212 * we SingleFieldBuilderV3.build to send dirty invalidations
213 * @return the message for the specified index
214 */
215 private MType getMessage(int index, boolean forBuild) {
216 if (this.builders == null) {
217 // We don't have any builders -- return the current Message.
218 // This is the case where no builder was created, so we MUST have a
219 // Message.
220 return messages.get(index);
221 }
222
223 SingleFieldBuilderV3<MType, BType, IType> builder = builders.get(index);
224 if (builder == null) {
225 // We don't have a builder -- return the current message.
226 // This is the case where no builder was created for the entry at index,
227 // so we MUST have a message.
228 return messages.get(index);
229
230 } else {
231 return forBuild ? builder.build() : builder.getMessage();
232 }
233 }
234
235 /**
236 * Gets a builder for the specified index. If no builder has been created for
237 * that index, a builder is created on demand by calling
238 * {@link Message#toBuilder}.
239 *
240 * @param index the index of the message to get
241 * @return The builder for that index
242 */
243 public BType getBuilder(int index) {
244 ensureBuilders();
245 SingleFieldBuilderV3<MType, BType, IType> builder = builders.get(index);
246 if (builder == null) {
247 MType message = messages.get(index);
248 builder = new SingleFieldBuilderV3<MType, BType, IType>(
249 message, this, isClean);
250 builders.set(index, builder);
251 }
252 return builder.getBuilder();
253 }
254
255 /**
256 * Gets the base class interface for the specified index. This may either be
257 * a builder or a message. It will return whatever is more efficient.
258 *
259 * @param index the index of the message to get
260 * @return the message or builder for the index as the base class interface
261 */
262 @SuppressWarnings("unchecked")
263 public IType getMessageOrBuilder(int index) {
264 if (this.builders == null) {
265 // We don't have any builders -- return the current Message.
266 // This is the case where no builder was created, so we MUST have a
267 // Message.
268 return (IType) messages.get(index);
269 }
270
271 SingleFieldBuilderV3<MType, BType, IType> builder = builders.get(index);
272 if (builder == null) {
273 // We don't have a builder -- return the current message.
274 // This is the case where no builder was created for the entry at index,
275 // so we MUST have a message.
276 return (IType) messages.get(index);
277
278 } else {
279 return builder.getMessageOrBuilder();
280 }
281 }
282
283 /**
284 * Sets a message at the specified index replacing the existing item at
285 * that index.
286 *
287 * @param index the index to set.
288 * @param message the message to set
289 * @return the builder
290 */
291 public RepeatedFieldBuilderV3<MType, BType, IType> setMessage(
292 int index, MType message) {
293 if (message == null) {
294 throw new NullPointerException();
295 }
296 ensureMutableMessageList();
297 messages.set(index, message);
298 if (builders != null) {
299 SingleFieldBuilderV3<MType, BType, IType> entry =
300 builders.set(index, null);
301 if (entry != null) {
302 entry.dispose();
303 }
304 }
305 onChanged();
306 incrementModCounts();
307 return this;
308 }
309
310 /**
311 * Appends the specified element to the end of this list.
312 *
313 * @param message the message to add
314 * @return the builder
315 */
316 public RepeatedFieldBuilderV3<MType, BType, IType> addMessage(
317 MType message) {
318 if (message == null) {
319 throw new NullPointerException();
320 }
321 ensureMutableMessageList();
322 messages.add(message);
323 if (builders != null) {
324 builders.add(null);
325 }
326 onChanged();
327 incrementModCounts();
328 return this;
329 }
330
331 /**
332 * Inserts the specified message at the specified position in this list.
333 * Shifts the element currently at that position (if any) and any subsequent
334 * elements to the right (adds one to their indices).
335 *
336 * @param index the index at which to insert the message
337 * @param message the message to add
338 * @return the builder
339 */
340 public RepeatedFieldBuilderV3<MType, BType, IType> addMessage(
341 int index, MType message) {
342 if (message == null) {
343 throw new NullPointerException();
344 }
345 ensureMutableMessageList();
346 messages.add(index, message);
347 if (builders != null) {
348 builders.add(index, null);
349 }
350 onChanged();
351 incrementModCounts();
352 return this;
353 }
354
355 /**
356 * Appends all of the messages in the specified collection to the end of
357 * this list, in the order that they are returned by the specified
358 * collection's iterator.
359 *
360 * @param values the messages to add
361 * @return the builder
362 */
363 public RepeatedFieldBuilderV3<MType, BType, IType> addAllMessages(
364 Iterable<? extends MType> values) {
365 for (final MType value : values) {
366 if (value == null) {
367 throw new NullPointerException();
368 }
369 }
370
371 // If we can inspect the size, we can more efficiently add messages.
372 int size = -1;
373 if (values instanceof Collection) {
374 @SuppressWarnings("unchecked") final
375 Collection<MType> collection = (Collection<MType>) values;
376 if (collection.size() == 0) {
377 return this;
378 }
379 size = collection.size();
380 }
381 ensureMutableMessageList();
382
383 if (size >= 0 && messages instanceof ArrayList) {
384 ((ArrayList<MType>) messages)
385 .ensureCapacity(messages.size() + size);
386 }
387
388 for (MType value : values) {
389 addMessage(value);
390 }
391
392 onChanged();
393 incrementModCounts();
394 return this;
395 }
396
397 /**
398 * Appends a new builder to the end of this list and returns the builder.
399 *
400 * @param message the message to add which is the basis of the builder
401 * @return the new builder
402 */
403 public BType addBuilder(MType message) {
404 ensureMutableMessageList();
405 ensureBuilders();
406 SingleFieldBuilderV3<MType, BType, IType> builder =
407 new SingleFieldBuilderV3<MType, BType, IType>(
408 message, this, isClean);
409 messages.add(null);
410 builders.add(builder);
411 onChanged();
412 incrementModCounts();
413 return builder.getBuilder();
414 }
415
416 /**
417 * Inserts a new builder at the specified position in this list.
418 * Shifts the element currently at that position (if any) and any subsequent
419 * elements to the right (adds one to their indices).
420 *
421 * @param index the index at which to insert the builder
422 * @param message the message to add which is the basis of the builder
423 * @return the builder
424 */
425 public BType addBuilder(int index, MType message) {
426 ensureMutableMessageList();
427 ensureBuilders();
428 SingleFieldBuilderV3<MType, BType, IType> builder =
429 new SingleFieldBuilderV3<MType, BType, IType>(
430 message, this, isClean);
431 messages.add(index, null);
432 builders.add(index, builder);
433 onChanged();
434 incrementModCounts();
435 return builder.getBuilder();
436 }
437
438 /**
439 * Removes the element at the specified position in this list. Shifts any
440 * subsequent elements to the left (subtracts one from their indices).
441 * Returns the element that was removed from the list.
442 *
443 * @param index the index at which to remove the message
444 */
445 public void remove(int index) {
446 ensureMutableMessageList();
447 messages.remove(index);
448 if (builders != null) {
449 SingleFieldBuilderV3<MType, BType, IType> entry =
450 builders.remove(index);
451 if (entry != null) {
452 entry.dispose();
453 }
454 }
455 onChanged();
456 incrementModCounts();
457 }
458
459 /**
460 * Removes all of the elements from this list.
461 * The list will be empty after this call returns.
462 */
463 public void clear() {
464 messages = Collections.emptyList();
465 isMessagesListMutable = false;
466 if (builders != null) {
467 for (SingleFieldBuilderV3<MType, BType, IType> entry :
468 builders) {
469 if (entry != null) {
470 entry.dispose();
471 }
472 }
473 builders = null;
474 }
475 onChanged();
476 incrementModCounts();
477 }
478
479 /**
480 * Builds the list of messages from the builder and returns them.
481 *
482 * @return an immutable list of messages
483 */
484 public List<MType> build() {
485 // Now that build has been called, we are required to dispatch
486 // invalidations.
487 isClean = true;
488
489 if (!isMessagesListMutable && builders == null) {
490 // We still have an immutable list and we never created a builder.
491 return messages;
492 }
493
494 boolean allMessagesInSync = true;
495 if (!isMessagesListMutable) {
496 // We still have an immutable list. Let's see if any of them are out
497 // of sync with their builders.
498 for (int i = 0; i < messages.size(); i++) {
499 Message message = messages.get(i);
500 SingleFieldBuilderV3<MType, BType, IType> builder = builders.get(i);
501 if (builder != null) {
502 if (builder.build() != message) {
503 allMessagesInSync = false;
504 break;
505 }
506 }
507 }
508 if (allMessagesInSync) {
509 // Immutable list is still in sync.
510 return messages;
511 }
512 }
513
514 // Need to make sure messages is up to date
515 ensureMutableMessageList();
516 for (int i = 0; i < messages.size(); i++) {
517 messages.set(i, getMessage(i, true));
518 }
519
520 // We're going to return our list as immutable so we mark that we can
521 // no longer update it.
522 messages = Collections.unmodifiableList(messages);
523 isMessagesListMutable = false;
524 return messages;
525 }
526
527 /**
528 * Gets a view of the builder as a list of messages. The returned list is live
529 * and will reflect any changes to the underlying builder.
530 *
531 * @return the messages in the list
532 */
533 public List<MType> getMessageList() {
534 if (externalMessageList == null) {
535 externalMessageList =
536 new MessageExternalList<MType, BType, IType>(this);
537 }
538 return externalMessageList;
539 }
540
541 /**
542 * Gets a view of the builder as a list of builders. This returned list is
543 * live and will reflect any changes to the underlying builder.
544 *
545 * @return the builders in the list
546 */
547 public List<BType> getBuilderList() {
548 if (externalBuilderList == null) {
549 externalBuilderList =
550 new BuilderExternalList<MType, BType, IType>(this);
551 }
552 return externalBuilderList;
553 }
554
555 /**
556 * Gets a view of the builder as a list of MessageOrBuilders. This returned
557 * list is live and will reflect any changes to the underlying builder.
558 *
559 * @return the builders in the list
560 */
561 public List<IType> getMessageOrBuilderList() {
562 if (externalMessageOrBuilderList == null) {
563 externalMessageOrBuilderList =
564 new MessageOrBuilderExternalList<MType, BType, IType>(this);
565 }
566 return externalMessageOrBuilderList;
567 }
568
569 /**
570 * Called when a the builder or one of its nested children has changed
571 * and any parent should be notified of its invalidation.
572 */
573 private void onChanged() {
574 if (isClean && parent != null) {
575 parent.markDirty();
576
577 // Don't keep dispatching invalidations until build is called again.
578 isClean = false;
579 }
580 }
581
582 @Override
583 public void markDirty() {
584 onChanged();
585 }
586
587 /**
588 * Increments the mod counts so that an ConcurrentModificationException can
589 * be thrown if calling code tries to modify the builder while its iterating
590 * the list.
591 */
592 private void incrementModCounts() {
593 if (externalMessageList != null) {
594 externalMessageList.incrementModCount();
595 }
596 if (externalBuilderList != null) {
597 externalBuilderList.incrementModCount();
598 }
599 if (externalMessageOrBuilderList != null) {
600 externalMessageOrBuilderList.incrementModCount();
601 }
602 }
603
604 /**
605 * Provides a live view of the builder as a list of messages.
606 *
607 * @param <MType> the type of message for the field
608 * @param <BType> the type of builder for the field
609 * @param <IType> the common interface for the message and the builder
610 */
611 private static class MessageExternalList<
612 MType extends AbstractMessage,
613 BType extends AbstractMessage.Builder,
614 IType extends MessageOrBuilder>
615 extends AbstractList<MType> implements List<MType> {
616
617 RepeatedFieldBuilderV3<MType, BType, IType> builder;
618
619 MessageExternalList(
620 RepeatedFieldBuilderV3<MType, BType, IType> builder) {
621 this.builder = builder;
622 }
623
624 @Override
625 public int size() {
626 return this.builder.getCount();
627 }
628
629 @Override
630 public MType get(int index) {
631 return builder.getMessage(index);
632 }
633
634 void incrementModCount() {
635 modCount++;
636 }
637 }
638
639 /**
640 * Provides a live view of the builder as a list of builders.
641 *
642 * @param <MType> the type of message for the field
643 * @param <BType> the type of builder for the field
644 * @param <IType> the common interface for the message and the builder
645 */
646 private static class BuilderExternalList<
647 MType extends AbstractMessage,
648 BType extends AbstractMessage.Builder,
649 IType extends MessageOrBuilder>
650 extends AbstractList<BType> implements List<BType> {
651
652 RepeatedFieldBuilderV3<MType, BType, IType> builder;
653
654 BuilderExternalList(
655 RepeatedFieldBuilderV3<MType, BType, IType> builder) {
656 this.builder = builder;
657 }
658
659 @Override
660 public int size() {
661 return this.builder.getCount();
662 }
663
664 @Override
665 public BType get(int index) {
666 return builder.getBuilder(index);
667 }
668
669 void incrementModCount() {
670 modCount++;
671 }
672 }
673
674 /**
675 * Provides a live view of the builder as a list of builders.
676 *
677 * @param <MType> the type of message for the field
678 * @param <BType> the type of builder for the field
679 * @param <IType> the common interface for the message and the builder
680 */
681 private static class MessageOrBuilderExternalList<
682 MType extends AbstractMessage,
683 BType extends AbstractMessage.Builder,
684 IType extends MessageOrBuilder>
685 extends AbstractList<IType> implements List<IType> {
686
687 RepeatedFieldBuilderV3<MType, BType, IType> builder;
688
689 MessageOrBuilderExternalList(
690 RepeatedFieldBuilderV3<MType, BType, IType> builder) {
691 this.builder = builder;
692 }
693
694 @Override
695 public int size() {
696 return this.builder.getCount();
697 }
698
699 @Override
700 public IType get(int index) {
701 return builder.getMessageOrBuilder(index);
702 }
703
704 void incrementModCount() {
705 modCount++;
706 }
707 }
708 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698