~verterok/ubuntu/lucid/protobuf/2.4.0a-backport

« back to all changes in this revision

Viewing changes to java/src/main/java/com/google/protobuf/FieldSet.java

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2011-05-31 14:41:47 UTC
  • mfrom: (2.2.8 sid)
  • Revision ID: james.westby@ubuntu.com-20110531144147-s41g5fozgvyo462l
Tags: 2.4.0a-2ubuntu1
* Merge with Debian; remaining changes:
  - Fix linking with -lpthread.

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
import java.util.ArrayList;
34
34
import java.util.Collections;
35
35
import java.util.Iterator;
36
 
import java.util.TreeMap;
37
36
import java.util.List;
38
37
import java.util.Map;
39
38
import java.io.IOException;
67
66
        MessageLite.Builder to, MessageLite from);
68
67
  }
69
68
 
70
 
  private Map<FieldDescriptorType, Object> fields;
 
69
  private final SmallSortedMap<FieldDescriptorType, Object> fields;
 
70
  private boolean isImmutable;
71
71
 
72
72
  /** Construct a new FieldSet. */
73
73
  private FieldSet() {
74
 
    // Use a TreeMap because fields need to be in canonical order when
75
 
    // serializing.
76
 
    // TODO(kenton):  Maybe use some sort of sparse array instead?  It would
77
 
    //   even make sense to store the first 16 or so tags in a flat array
78
 
    //   to make DynamicMessage faster.
79
 
    fields = new TreeMap<FieldDescriptorType, Object>();
 
74
    this.fields = SmallSortedMap.newFieldMap(16);
80
75
  }
81
76
 
82
77
  /**
84
79
   * DEFAULT_INSTANCE.
85
80
   */
86
81
  private FieldSet(final boolean dummy) {
87
 
    this.fields = Collections.emptyMap();
 
82
    this.fields = SmallSortedMap.newFieldMap(0);
 
83
    makeImmutable();
88
84
  }
89
85
 
90
86
  /** Construct a new FieldSet. */
105
101
  /** Make this FieldSet immutable from this point forward. */
106
102
  @SuppressWarnings("unchecked")
107
103
  public void makeImmutable() {
108
 
    for (final Map.Entry<FieldDescriptorType, Object> entry:
109
 
         fields.entrySet()) {
110
 
      if (entry.getKey().isRepeated()) {
111
 
        final List value = (List)entry.getValue();
112
 
        fields.put(entry.getKey(), Collections.unmodifiableList(value));
113
 
      }
114
 
    }
115
 
    fields = Collections.unmodifiableMap(fields);
 
104
    if (isImmutable) {
 
105
      return;
 
106
    }
 
107
    fields.makeImmutable();
 
108
    isImmutable = true;
 
109
  }
 
110
 
 
111
  /**
 
112
   * Retuns whether the FieldSet is immutable. This is true if it is the
 
113
   * {@link #emptySet} or if {@link #makeImmutable} were called.
 
114
   *
 
115
   * @return whether the FieldSet is immutable.
 
116
   */
 
117
  public boolean isImmutable() {
 
118
    return isImmutable;
 
119
  }
 
120
 
 
121
  /**
 
122
   * Clones the FieldSet. The returned FieldSet will be mutable even if the
 
123
   * original FieldSet was immutable.
 
124
   *
 
125
   * @return the newly cloned FieldSet
 
126
   */
 
127
  @Override
 
128
  public FieldSet<FieldDescriptorType> clone() {
 
129
    // We can't just call fields.clone because List objects in the map
 
130
    // should not be shared.
 
131
    FieldSet<FieldDescriptorType> clone = FieldSet.newFieldSet();
 
132
    for (int i = 0; i < fields.getNumArrayEntries(); i++) {
 
133
      Map.Entry<FieldDescriptorType, Object> entry = fields.getArrayEntryAt(i);
 
134
      FieldDescriptorType descriptor = entry.getKey();
 
135
      clone.setField(descriptor, entry.getValue());
 
136
    }
 
137
    for (Map.Entry<FieldDescriptorType, Object> entry :
 
138
             fields.getOverflowEntries()) {
 
139
      FieldDescriptorType descriptor = entry.getKey();
 
140
      clone.setField(descriptor, entry.getValue());
 
141
    }
 
142
    return clone;
116
143
  }
117
144
 
118
145
  // =================================================================
126
153
   * Get a simple map containing all the fields.
127
154
   */
128
155
  public Map<FieldDescriptorType, Object> getAllFields() {
129
 
    return Collections.unmodifiableMap(fields);
 
156
    return fields.isImmutable() ? fields : Collections.unmodifiableMap(fields);
130
157
  }
131
158
 
132
159
  /**
133
 
   * Get an iterator to the field map.  This iterator should not be leaked
134
 
   * out of the protobuf library as it is not protected from mutation.
 
160
   * Get an iterator to the field map. This iterator should not be leaked out
 
161
   * of the protobuf library as it is not protected from mutation when
 
162
   * fields is not immutable.
135
163
   */
136
164
  public Iterator<Map.Entry<FieldDescriptorType, Object>> iterator() {
137
165
    return fields.entrySet().iterator();
210
238
    if (value == null) {
211
239
      return 0;
212
240
    } else {
213
 
      return ((List) value).size();
 
241
      return ((List<?>) value).size();
214
242
    }
215
243
  }
216
244
 
230
258
    if (value == null) {
231
259
      throw new IndexOutOfBoundsException();
232
260
    } else {
233
 
      return ((List) value).get(index);
 
261
      return ((List<?>) value).get(index);
234
262
    }
235
263
  }
236
264
 
336
364
   * aren't actually present in the set, it is up to the caller to check
337
365
   * that all required fields are present.
338
366
   */
339
 
  @SuppressWarnings("unchecked")
340
367
  public boolean isInitialized() {
341
 
    for (final Map.Entry<FieldDescriptorType, Object> entry:
342
 
         fields.entrySet()) {
343
 
      final FieldDescriptorType descriptor = entry.getKey();
344
 
      if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
345
 
        if (descriptor.isRepeated()) {
346
 
          for (final MessageLite element:
347
 
               (List<MessageLite>) entry.getValue()) {
348
 
            if (!element.isInitialized()) {
349
 
              return false;
350
 
            }
351
 
          }
352
 
        } else {
353
 
          if (!((MessageLite) entry.getValue()).isInitialized()) {
 
368
    for (int i = 0; i < fields.getNumArrayEntries(); i++) {
 
369
      if (!isInitialized(fields.getArrayEntryAt(i))) {
 
370
        return false;
 
371
      }
 
372
    }
 
373
    for (final Map.Entry<FieldDescriptorType, Object> entry :
 
374
             fields.getOverflowEntries()) {
 
375
      if (!isInitialized(entry)) {
 
376
        return false;
 
377
      }
 
378
    }
 
379
    return true;
 
380
  }
 
381
 
 
382
  @SuppressWarnings("unchecked")
 
383
  private boolean isInitialized(
 
384
      final Map.Entry<FieldDescriptorType, Object> entry) {
 
385
    final FieldDescriptorType descriptor = entry.getKey();
 
386
    if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
 
387
      if (descriptor.isRepeated()) {
 
388
        for (final MessageLite element:
 
389
                 (List<MessageLite>) entry.getValue()) {
 
390
          if (!element.isInitialized()) {
354
391
            return false;
355
392
          }
356
393
        }
 
394
      } else {
 
395
        if (!((MessageLite) entry.getValue()).isInitialized()) {
 
396
          return false;
 
397
        }
357
398
      }
358
399
    }
359
 
 
360
400
    return true;
361
401
  }
362
402
 
378
418
  /**
379
419
   * Like {@link #mergeFrom(Message)}, but merges from another {@link FieldSet}.
380
420
   */
381
 
  @SuppressWarnings("unchecked")
382
421
  public void mergeFrom(final FieldSet<FieldDescriptorType> other) {
383
 
    for (final Map.Entry<FieldDescriptorType, Object> entry:
384
 
         other.fields.entrySet()) {
385
 
      final FieldDescriptorType descriptor = entry.getKey();
386
 
      final Object otherValue = entry.getValue();
387
 
 
388
 
      if (descriptor.isRepeated()) {
389
 
        Object value = fields.get(descriptor);
390
 
        if (value == null) {
391
 
          // Our list is empty, but we still need to make a defensive copy of
392
 
          // the other list since we don't know if the other FieldSet is still
393
 
          // mutable.
394
 
          fields.put(descriptor, new ArrayList((List) otherValue));
395
 
        } else {
396
 
          // Concatenate the lists.
397
 
          ((List) value).addAll((List) otherValue);
398
 
        }
399
 
      } else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
400
 
        Object value = fields.get(descriptor);
401
 
        if (value == null) {
402
 
          fields.put(descriptor, otherValue);
403
 
        } else {
404
 
          // Merge the messages.
405
 
          fields.put(descriptor,
406
 
              descriptor.internalMergeFrom(
 
422
    for (int i = 0; i < other.fields.getNumArrayEntries(); i++) {
 
423
      mergeFromField(other.fields.getArrayEntryAt(i));
 
424
    }
 
425
    for (final Map.Entry<FieldDescriptorType, Object> entry :
 
426
             other.fields.getOverflowEntries()) {
 
427
      mergeFromField(entry);
 
428
    }
 
429
  }
 
430
 
 
431
  @SuppressWarnings("unchecked")
 
432
  private void mergeFromField(
 
433
      final Map.Entry<FieldDescriptorType, Object> entry) {
 
434
    final FieldDescriptorType descriptor = entry.getKey();
 
435
    final Object otherValue = entry.getValue();
 
436
 
 
437
    if (descriptor.isRepeated()) {
 
438
      Object value = fields.get(descriptor);
 
439
      if (value == null) {
 
440
        // Our list is empty, but we still need to make a defensive copy of
 
441
        // the other list since we don't know if the other FieldSet is still
 
442
        // mutable.
 
443
        fields.put(descriptor, new ArrayList((List) otherValue));
 
444
      } else {
 
445
        // Concatenate the lists.
 
446
        ((List) value).addAll((List) otherValue);
 
447
      }
 
448
    } else if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE) {
 
449
      Object value = fields.get(descriptor);
 
450
      if (value == null) {
 
451
        fields.put(descriptor, otherValue);
 
452
      } else {
 
453
        // Merge the messages.
 
454
        fields.put(
 
455
            descriptor,
 
456
            descriptor.internalMergeFrom(
407
457
                ((MessageLite) value).toBuilder(), (MessageLite) otherValue)
408
 
              .build());
409
 
        }
410
 
 
411
 
      } else {
412
 
        fields.put(descriptor, otherValue);
 
458
            .build());
413
459
      }
 
460
 
 
461
    } else {
 
462
      fields.put(descriptor, otherValue);
414
463
    }
415
464
  }
416
465
 
468
517
  /** See {@link Message#writeTo(CodedOutputStream)}. */
469
518
  public void writeTo(final CodedOutputStream output)
470
519
                      throws IOException {
471
 
    for (final Map.Entry<FieldDescriptorType, Object> entry:
472
 
         fields.entrySet()) {
 
520
    for (int i = 0; i < fields.getNumArrayEntries(); i++) {
 
521
      final Map.Entry<FieldDescriptorType, Object> entry =
 
522
          fields.getArrayEntryAt(i);
 
523
      writeField(entry.getKey(), entry.getValue(), output);
 
524
    }
 
525
    for (final Map.Entry<FieldDescriptorType, Object> entry :
 
526
         fields.getOverflowEntries()) {
473
527
      writeField(entry.getKey(), entry.getValue(), output);
474
528
    }
475
529
  }
479
533
   */
480
534
  public void writeMessageSetTo(final CodedOutputStream output)
481
535
                                throws IOException {
482
 
    for (final Map.Entry<FieldDescriptorType, Object> entry:
483
 
         fields.entrySet()) {
484
 
      final FieldDescriptorType descriptor = entry.getKey();
485
 
      if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
486
 
          !descriptor.isRepeated() && !descriptor.isPacked()) {
487
 
        output.writeMessageSetExtension(entry.getKey().getNumber(),
488
 
                                        (MessageLite) entry.getValue());
489
 
      } else {
490
 
        writeField(descriptor, entry.getValue(), output);
491
 
      }
 
536
    for (int i = 0; i < fields.getNumArrayEntries(); i++) {
 
537
      writeMessageSetTo(fields.getArrayEntryAt(i), output);
 
538
    }
 
539
    for (final Map.Entry<FieldDescriptorType, Object> entry :
 
540
             fields.getOverflowEntries()) {
 
541
      writeMessageSetTo(entry, output);
 
542
    }
 
543
  }
 
544
 
 
545
  private void writeMessageSetTo(
 
546
      final Map.Entry<FieldDescriptorType, Object> entry,
 
547
      final CodedOutputStream output) throws IOException {
 
548
    final FieldDescriptorType descriptor = entry.getKey();
 
549
    if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
 
550
        !descriptor.isRepeated() && !descriptor.isPacked()) {
 
551
      output.writeMessageSetExtension(entry.getKey().getNumber(),
 
552
                                      (MessageLite) entry.getValue());
 
553
    } else {
 
554
      writeField(descriptor, entry.getValue(), output);
492
555
    }
493
556
  }
494
557
 
564
627
    WireFormat.FieldType type = descriptor.getLiteType();
565
628
    int number = descriptor.getNumber();
566
629
    if (descriptor.isRepeated()) {
567
 
      final List valueList = (List)value;
 
630
      final List<?> valueList = (List<?>)value;
568
631
      if (descriptor.isPacked()) {
569
632
        output.writeTag(number, WireFormat.WIRETYPE_LENGTH_DELIMITED);
570
633
        // Compute the total data size so the length can be written.
593
656
   */
594
657
  public int getSerializedSize() {
595
658
    int size = 0;
596
 
    for (final Map.Entry<FieldDescriptorType, Object> entry:
597
 
         fields.entrySet()) {
 
659
    for (int i = 0; i < fields.getNumArrayEntries(); i++) {
 
660
      final Map.Entry<FieldDescriptorType, Object> entry =
 
661
          fields.getArrayEntryAt(i);
 
662
      size += computeFieldSize(entry.getKey(), entry.getValue());
 
663
    }
 
664
    for (final Map.Entry<FieldDescriptorType, Object> entry :
 
665
         fields.getOverflowEntries()) {
598
666
      size += computeFieldSize(entry.getKey(), entry.getValue());
599
667
    }
600
668
    return size;
605
673
   */
606
674
  public int getMessageSetSerializedSize() {
607
675
    int size = 0;
608
 
    for (final Map.Entry<FieldDescriptorType, Object> entry:
609
 
         fields.entrySet()) {
610
 
      final FieldDescriptorType descriptor = entry.getKey();
611
 
      if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
612
 
          !descriptor.isRepeated() && !descriptor.isPacked()) {
613
 
        size += CodedOutputStream.computeMessageSetExtensionSize(
614
 
                  entry.getKey().getNumber(), (MessageLite) entry.getValue());
615
 
      } else {
616
 
        size += computeFieldSize(descriptor, entry.getValue());
617
 
      }
 
676
    for (int i = 0; i < fields.getNumArrayEntries(); i++) {
 
677
      size += getMessageSetSerializedSize(fields.getArrayEntryAt(i));
 
678
    }
 
679
    for (final Map.Entry<FieldDescriptorType, Object> entry :
 
680
             fields.getOverflowEntries()) {
 
681
      size += getMessageSetSerializedSize(entry);
618
682
    }
619
683
    return size;
620
684
  }
621
685
 
 
686
  private int getMessageSetSerializedSize(
 
687
      final Map.Entry<FieldDescriptorType, Object> entry) {
 
688
    final FieldDescriptorType descriptor = entry.getKey();
 
689
    if (descriptor.getLiteJavaType() == WireFormat.JavaType.MESSAGE &&
 
690
        !descriptor.isRepeated() && !descriptor.isPacked()) {
 
691
      return CodedOutputStream.computeMessageSetExtensionSize(
 
692
          entry.getKey().getNumber(), (MessageLite) entry.getValue());
 
693
    } else {
 
694
      return computeFieldSize(descriptor, entry.getValue());
 
695
    }
 
696
  }
 
697
 
622
698
  /**
623
699
   * Compute the number of bytes that would be needed to encode a
624
700
   * single tag/value pair of arbitrary type.
692
768
    if (descriptor.isRepeated()) {
693
769
      if (descriptor.isPacked()) {
694
770
        int dataSize = 0;
695
 
        for (final Object element : (List)value) {
 
771
        for (final Object element : (List<?>)value) {
696
772
          dataSize += computeElementSizeNoTag(type, element);
697
773
        }
698
774
        return dataSize +
700
776
            CodedOutputStream.computeRawVarint32Size(dataSize);
701
777
      } else {
702
778
        int size = 0;
703
 
        for (final Object element : (List)value) {
 
779
        for (final Object element : (List<?>)value) {
704
780
          size += computeElementSize(type, number, element);
705
781
        }
706
782
        return size;