PageRenderTime 67ms CodeModel.GetById 17ms app.highlight 43ms RepoModel.GetById 1ms app.codeStats 0ms

/thirdparty/breakpad/third_party/protobuf/protobuf/java/src/main/java/com/google/protobuf/RepeatedFieldBuilder.java

http://github.com/tomahawk-player/tomahawk
Java | 696 lines | 348 code | 64 blank | 284 comment | 74 complexity | a08a44901a775658f8ac82c26d29b0ec MD5 | raw file
  1// Protocol Buffers - Google's data interchange format
  2// Copyright 2008 Google Inc.  All rights reserved.
  3// http://code.google.com/p/protobuf/
  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
 31package com.google.protobuf;
 32
 33import java.util.AbstractList;
 34import java.util.ArrayList;
 35import java.util.Collection;
 36import java.util.Collections;
 37import java.util.List;
 38
 39/**
 40 * <code>RepeatedFieldBuilder</code> 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</code>
 48 * to an immutable <code>Message</code>. In this way, it's possible to maintain
 49 * a tree of <code>Builder</code>'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>SingleFieldBuilder</code> and <code>RepeatedFieldBuilder</code>
 56 * classes cache messages that were created so that messages only need to be
 57 * created when some change occured 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 */
 66public class RepeatedFieldBuilder
 67    <MType extends GeneratedMessage,
 68     BType extends GeneratedMessage.Builder,
 69     IType extends MessageOrBuilder>
 70    implements GeneratedMessage.BuilderParent {
 71
 72  // Parent to send changes to.
 73  private GeneratedMessage.BuilderParent parent;
 74
 75  // List of messages. Never null. It may be immutable, in which case
 76  // isMessagesListImmutable will be true. 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<SingleFieldBuilder<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 GeneratedMessage.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 RepeatedFieldBuilder(
133      List<MType> messages,
134      boolean isMessagesListMutable,
135      GeneratedMessage.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<SingleFieldBuilder<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</code>, it is converted to a <code>Message</code> 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</code>, it is converted to a <code>Message</code> 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 SingleFieldBuilder.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    SingleFieldBuilder<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    SingleFieldBuilder<MType, BType, IType> builder = builders.get(index);
246    if (builder == null) {
247      MType message = messages.get(index);
248      builder = new SingleFieldBuilder<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    SingleFieldBuilder<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 RepeatedFieldBuilder<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      SingleFieldBuilder<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 RepeatedFieldBuilder<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 RepeatedFieldBuilder<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 RepeatedFieldBuilder<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    if (values instanceof Collection) {
371      @SuppressWarnings("unchecked") final
372      Collection<MType> collection = (Collection<MType>) values;
373      if (collection.size() == 0) {
374        return this;
375      }
376      ensureMutableMessageList();
377      for (MType value : values) {
378        addMessage(value);
379      }
380    } else {
381      ensureMutableMessageList();
382      for (MType value : values) {
383        addMessage(value);
384      }
385    }
386    onChanged();
387    incrementModCounts();
388    return this;
389  }
390
391  /**
392   * Appends a new builder to the end of this list and returns the builder.
393   *
394   * @param message the message to add which is the basis of the builder
395   * @return the new builder
396   */
397  public BType addBuilder(MType message) {
398    ensureMutableMessageList();
399    ensureBuilders();
400    SingleFieldBuilder<MType, BType, IType> builder =
401        new SingleFieldBuilder<MType, BType, IType>(
402            message, this, isClean);
403    messages.add(null);
404    builders.add(builder);
405    onChanged();
406    incrementModCounts();
407    return builder.getBuilder();
408  }
409
410  /**
411   * Inserts a new builder at the specified position in this list.
412   * Shifts the element currently at that position (if any) and any subsequent
413   * elements to the right (adds one to their indices).
414   *
415   * @param index the index at which to insert the builder
416   * @param message the message to add which is the basis of the builder
417   * @return the builder
418   */
419  public BType addBuilder(int index, MType message) {
420    ensureMutableMessageList();
421    ensureBuilders();
422    SingleFieldBuilder<MType, BType, IType> builder =
423        new SingleFieldBuilder<MType, BType, IType>(
424            message, this, isClean);
425    messages.add(index, null);
426    builders.add(index, builder);
427    onChanged();
428    incrementModCounts();
429    return builder.getBuilder();
430  }
431
432  /**
433   * Removes the element at the specified position in this list. Shifts any
434   * subsequent elements to the left (subtracts one from their indices).
435   * Returns the element that was removed from the list.
436   *
437   * @param index the index at which to remove the message
438   */
439  public void remove(int index) {
440    ensureMutableMessageList();
441    messages.remove(index);
442    if (builders != null) {
443      SingleFieldBuilder<MType, BType, IType> entry =
444          builders.remove(index);
445      if (entry != null) {
446        entry.dispose();
447      }
448    }
449    onChanged();
450    incrementModCounts();
451  }
452
453  /**
454   * Removes all of the elements from this list.
455   * The list will be empty after this call returns.
456   */
457  public void clear() {
458    messages = Collections.emptyList();
459    isMessagesListMutable = false;
460    if (builders != null) {
461      for (SingleFieldBuilder<MType, BType, IType> entry :
462          builders) {
463        if (entry != null) {
464          entry.dispose();
465        }
466      }
467      builders = null;
468    }
469    onChanged();
470    incrementModCounts();
471  }
472
473  /**
474   * Builds the list of messages from the builder and returns them.
475   *
476   * @return an immutable list of messages
477   */
478  public List<MType> build() {
479    // Now that build has been called, we are required to dispatch
480    // invalidations.
481    isClean = true;
482
483    if (!isMessagesListMutable && builders == null) {
484      // We still have an immutable list and we never created a builder.
485      return messages;
486    }
487
488    boolean allMessagesInSync = true;
489    if (!isMessagesListMutable) {
490      // We still have an immutable list. Let's see if any of them are out
491      // of sync with their builders.
492      for (int i = 0; i < messages.size(); i++) {
493        Message message = messages.get(i);
494        SingleFieldBuilder<MType, BType, IType> builder = builders.get(i);
495        if (builder != null) {
496          if (builder.build() != message) {
497            allMessagesInSync = false;
498            break;
499          }
500        }
501      }
502      if (allMessagesInSync) {
503        // Immutable list is still in sync.
504        return messages;
505      }
506    }
507
508    // Need to make sure messages is up to date
509    ensureMutableMessageList();
510    for (int i = 0; i < messages.size(); i++) {
511      messages.set(i, getMessage(i, true));
512    }
513
514    // We're going to return our list as immutable so we mark that we can
515    // no longer update it.
516    messages = Collections.unmodifiableList(messages);
517    isMessagesListMutable = false;
518    return messages;
519  }
520
521  /**
522   * Gets a view of the builder as a list of messages. The returned list is live
523   * and will reflect any changes to the underlying builder.
524   *
525   * @return the messages in the list
526   */
527  public List<MType> getMessageList() {
528    if (externalMessageList == null) {
529      externalMessageList =
530          new MessageExternalList<MType, BType, IType>(this);
531    }
532    return externalMessageList;
533  }
534
535  /**
536   * Gets a view of the builder as a list of builders. This returned list is
537   * live and will reflect any changes to the underlying builder.
538   *
539   * @return the builders in the list
540   */
541  public List<BType> getBuilderList() {
542    if (externalBuilderList == null) {
543      externalBuilderList =
544          new BuilderExternalList<MType, BType, IType>(this);
545    }
546    return externalBuilderList;
547  }
548
549  /**
550   * Gets a view of the builder as a list of MessageOrBuilders. This returned
551   * list is live and will reflect any changes to the underlying builder.
552   *
553   * @return the builders in the list
554   */
555  public List<IType> getMessageOrBuilderList() {
556    if (externalMessageOrBuilderList == null) {
557      externalMessageOrBuilderList =
558          new MessageOrBuilderExternalList<MType, BType, IType>(this);
559    }
560    return externalMessageOrBuilderList;
561  }
562
563  /**
564   * Called when a the builder or one of its nested children has changed
565   * and any parent should be notified of its invalidation.
566   */
567  private void onChanged() {
568    if (isClean && parent != null) {
569      parent.markDirty();
570
571      // Don't keep dispatching invalidations until build is called again.
572      isClean = false;
573    }
574  }
575
576  //@Override (Java 1.6 override semantics, but we must support 1.5)
577  public void markDirty() {
578    onChanged();
579  }
580
581  /**
582   * Increments the mod counts so that an ConcurrentModificationException can
583   * be thrown if calling code tries to modify the builder while its iterating
584   * the list.
585   */
586  private void incrementModCounts() {
587    if (externalMessageList != null) {
588      externalMessageList.incrementModCount();
589    }
590    if (externalBuilderList != null) {
591      externalBuilderList.incrementModCount();
592    }
593    if (externalMessageOrBuilderList != null) {
594      externalMessageOrBuilderList.incrementModCount();
595    }
596  }
597
598  /**
599   * Provides a live view of the builder as a list of messages.
600   *
601   * @param <MType> the type of message for the field
602   * @param <BType> the type of builder for the field
603   * @param <IType> the common interface for the message and the builder
604   */
605  private static class MessageExternalList<
606      MType extends GeneratedMessage,
607      BType extends GeneratedMessage.Builder,
608      IType extends MessageOrBuilder>
609      extends AbstractList<MType> implements List<MType> {
610
611    RepeatedFieldBuilder<MType, BType, IType> builder;
612
613    MessageExternalList(
614        RepeatedFieldBuilder<MType, BType, IType> builder) {
615      this.builder = builder;
616    }
617
618    public int size() {
619      return this.builder.getCount();
620    }
621
622    public MType get(int index) {
623      return builder.getMessage(index);
624    }
625
626    void incrementModCount() {
627      modCount++;
628    }
629  }
630
631  /**
632   * Provides a live view of the builder as a list of builders.
633   *
634   * @param <MType> the type of message for the field
635   * @param <BType> the type of builder for the field
636   * @param <IType> the common interface for the message and the builder
637   */
638  private static class BuilderExternalList<
639      MType extends GeneratedMessage,
640      BType extends GeneratedMessage.Builder,
641      IType extends MessageOrBuilder>
642      extends AbstractList<BType> implements List<BType> {
643
644    RepeatedFieldBuilder<MType, BType, IType> builder;
645
646    BuilderExternalList(
647        RepeatedFieldBuilder<MType, BType, IType> builder) {
648      this.builder = builder;
649    }
650
651    public int size() {
652      return this.builder.getCount();
653    }
654
655    public BType get(int index) {
656      return builder.getBuilder(index);
657    }
658
659    void incrementModCount() {
660      modCount++;
661    }
662  }
663
664  /**
665   * Provides a live view of the builder as a list of builders.
666   *
667   * @param <MType> the type of message for the field
668   * @param <BType> the type of builder for the field
669   * @param <IType> the common interface for the message and the builder
670   */
671  private static class MessageOrBuilderExternalList<
672      MType extends GeneratedMessage,
673      BType extends GeneratedMessage.Builder,
674      IType extends MessageOrBuilder>
675      extends AbstractList<IType> implements List<IType> {
676
677    RepeatedFieldBuilder<MType, BType, IType> builder;
678
679    MessageOrBuilderExternalList(
680        RepeatedFieldBuilder<MType, BType, IType> builder) {
681      this.builder = builder;
682    }
683
684    public int size() {
685      return this.builder.getCount();
686    }
687
688    public IType get(int index) {
689      return builder.getMessageOrBuilder(index);
690    }
691
692    void incrementModCount() {
693      modCount++;
694    }
695  }
696}