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