| OLD | NEW |
| 1 #region Copyright notice and license | 1 #region Copyright notice and license |
| 2 // Protocol Buffers - Google's data interchange format | 2 // Protocol Buffers - Google's data interchange format |
| 3 // Copyright 2015 Google Inc. All rights reserved. | 3 // Copyright 2015 Google Inc. All rights reserved. |
| 4 // https://developers.google.com/protocol-buffers/ | 4 // https://developers.google.com/protocol-buffers/ |
| 5 // | 5 // |
| 6 // Redistribution and use in source and binary forms, with or without | 6 // Redistribution and use in source and binary forms, with or without |
| 7 // modification, are permitted provided that the following conditions are | 7 // modification, are permitted provided that the following conditions are |
| 8 // met: | 8 // met: |
| 9 // | 9 // |
| 10 // * Redistributions of source code must retain the above copyright | 10 // * Redistributions of source code must retain the above copyright |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 31 #endregion | 31 #endregion |
| 32 | 32 |
| 33 using System; | 33 using System; |
| 34 using System.Collections; | 34 using System.Collections; |
| 35 using System.Collections.Generic; | 35 using System.Collections.Generic; |
| 36 using System.IO; | 36 using System.IO; |
| 37 using System.Text; |
| 37 | 38 |
| 38 namespace Google.Protobuf.Collections | 39 namespace Google.Protobuf.Collections |
| 39 { | 40 { |
| 40 /// <summary> | 41 /// <summary> |
| 41 /// The contents of a repeated field: essentially, a collection with some ex
tra | 42 /// The contents of a repeated field: essentially, a collection with some ex
tra |
| 42 /// restrictions (no null values) and capabilities (deep cloning). | 43 /// restrictions (no null values) and capabilities (deep cloning). |
| 43 /// </summary> | 44 /// </summary> |
| 44 /// <remarks> | 45 /// <remarks> |
| 45 /// This implementation does not generally prohibit the use of types which a
re not | 46 /// This implementation does not generally prohibit the use of types which a
re not |
| 46 /// supported by Protocol Buffers but nor does it guarantee that all operati
ons will work in such cases. | 47 /// supported by Protocol Buffers but nor does it guarantee that all operati
ons will work in such cases. |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 array = tmp; | 220 array = tmp; |
| 220 } | 221 } |
| 221 } | 222 } |
| 222 | 223 |
| 223 /// <summary> | 224 /// <summary> |
| 224 /// Adds the specified item to the collection. | 225 /// Adds the specified item to the collection. |
| 225 /// </summary> | 226 /// </summary> |
| 226 /// <param name="item">The item to add.</param> | 227 /// <param name="item">The item to add.</param> |
| 227 public void Add(T item) | 228 public void Add(T item) |
| 228 { | 229 { |
| 229 ProtoPreconditions.CheckNotNullUnconstrained(item, nameof(item)); | 230 if (item == null) |
| 231 { |
| 232 throw new ArgumentNullException("item"); |
| 233 } |
| 230 EnsureSize(count + 1); | 234 EnsureSize(count + 1); |
| 231 array[count++] = item; | 235 array[count++] = item; |
| 232 } | 236 } |
| 233 | 237 |
| 234 /// <summary> | 238 /// <summary> |
| 235 /// Removes all items from the collection. | 239 /// Removes all items from the collection. |
| 236 /// </summary> | 240 /// </summary> |
| 237 public void Clear() | 241 public void Clear() |
| 238 { | 242 { |
| 239 array = EmptyArray; | 243 array = EmptyArray; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 274 } | 278 } |
| 275 Array.Copy(array, index + 1, array, index, count - index - 1); | 279 Array.Copy(array, index + 1, array, index, count - index - 1); |
| 276 count--; | 280 count--; |
| 277 array[count] = default(T); | 281 array[count] = default(T); |
| 278 return true; | 282 return true; |
| 279 } | 283 } |
| 280 | 284 |
| 281 /// <summary> | 285 /// <summary> |
| 282 /// Gets the number of elements contained in the collection. | 286 /// Gets the number of elements contained in the collection. |
| 283 /// </summary> | 287 /// </summary> |
| 284 public int Count => count; | 288 public int Count { get { return count; } } |
| 285 | 289 |
| 286 /// <summary> | 290 /// <summary> |
| 287 /// Gets a value indicating whether the collection is read-only. | 291 /// Gets a value indicating whether the collection is read-only. |
| 288 /// </summary> | 292 /// </summary> |
| 289 public bool IsReadOnly => false; | 293 public bool IsReadOnly { get { return false; } } |
| 294 |
| 295 // TODO: Remove this overload and just handle it in the one below, at ex
ecution time? |
| 290 | 296 |
| 291 /// <summary> | 297 /// <summary> |
| 292 /// Adds all of the specified values into this collection. | 298 /// Adds all of the specified values into this collection. |
| 293 /// </summary> | 299 /// </summary> |
| 294 /// <param name="values">The values to add to this collection.</param> | 300 /// <param name="values">The values to add to this collection.</param> |
| 295 public void AddRange(IEnumerable<T> values) | 301 public void Add(RepeatedField<T> values) |
| 296 { | 302 { |
| 297 ProtoPreconditions.CheckNotNull(values, nameof(values)); | 303 if (values == null) |
| 304 { |
| 305 throw new ArgumentNullException("values"); |
| 306 } |
| 307 EnsureSize(count + values.count); |
| 308 // We know that all the values will be valid, because it's a Repeate
dField. |
| 309 Array.Copy(values.array, 0, array, count, values.count); |
| 310 count += values.count; |
| 311 } |
| 298 | 312 |
| 299 // Optimization 1: If the collection we're adding is already a Repea
tedField<T>, | 313 /// <summary> |
| 300 // we know the values are valid. | 314 /// Adds all of the specified values into this collection. |
| 301 var otherRepeatedField = values as RepeatedField<T>; | 315 /// </summary> |
| 302 if (otherRepeatedField != null) | 316 /// <param name="values">The values to add to this collection.</param> |
| 317 public void Add(IEnumerable<T> values) |
| 318 { |
| 319 if (values == null) |
| 303 { | 320 { |
| 304 EnsureSize(count + otherRepeatedField.count); | 321 throw new ArgumentNullException("values"); |
| 305 Array.Copy(otherRepeatedField.array, 0, array, count, otherRepea
tedField.count); | |
| 306 count += otherRepeatedField.count; | |
| 307 return; | |
| 308 } | 322 } |
| 309 | 323 // TODO: Check for ICollection and get the Count, to optimize? |
| 310 // Optimization 2: The collection is an ICollection, so we can expan
d | |
| 311 // just once and ask the collection to copy itself into the array. | |
| 312 var collection = values as ICollection; | |
| 313 if (collection != null) | |
| 314 { | |
| 315 var extraCount = collection.Count; | |
| 316 // For reference types and nullable value types, we need to chec
k that there are no nulls | |
| 317 // present. (This isn't a thread-safe approach, but we don't adv
ertise this is thread-safe.) | |
| 318 // We expect the JITter to optimize this test to true/false, so
it's effectively conditional | |
| 319 // specialization. | |
| 320 if (default(T) == null) | |
| 321 { | |
| 322 // TODO: Measure whether iterating once to check and then le
tting the collection copy | |
| 323 // itself is faster or slower than iterating and adding as w
e go. For large | |
| 324 // collections this will not be great in terms of cache usag
e... but the optimized | |
| 325 // copy may be significantly faster than doing it one at a t
ime. | |
| 326 foreach (var item in collection) | |
| 327 { | |
| 328 if (item == null) | |
| 329 { | |
| 330 throw new ArgumentException("Sequence contained null
element", nameof(values)); | |
| 331 } | |
| 332 } | |
| 333 } | |
| 334 EnsureSize(count + extraCount); | |
| 335 collection.CopyTo(array, count); | |
| 336 count += extraCount; | |
| 337 return; | |
| 338 } | |
| 339 | |
| 340 // We *could* check for ICollection<T> as well, but very very few co
llections implement | |
| 341 // ICollection<T> but not ICollection. (HashSet<T> does, for one...) | |
| 342 | |
| 343 // Fall back to a slower path of adding items one at a time. | |
| 344 foreach (T item in values) | 324 foreach (T item in values) |
| 345 { | 325 { |
| 346 Add(item); | 326 Add(item); |
| 347 } | 327 } |
| 348 } | 328 } |
| 349 | 329 |
| 350 /// <summary> | 330 /// <summary> |
| 351 /// Adds all of the specified values into this collection. This method i
s present to | |
| 352 /// allow repeated fields to be constructed from queries within collecti
on initializers. | |
| 353 /// Within non-collection-initializer code, consider using the equivalen
t <see cref="AddRange"/> | |
| 354 /// method instead for clarity. | |
| 355 /// </summary> | |
| 356 /// <param name="values">The values to add to this collection.</param> | |
| 357 public void Add(IEnumerable<T> values) | |
| 358 { | |
| 359 AddRange(values); | |
| 360 } | |
| 361 | |
| 362 /// <summary> | |
| 363 /// Returns an enumerator that iterates through the collection. | 331 /// Returns an enumerator that iterates through the collection. |
| 364 /// </summary> | 332 /// </summary> |
| 365 /// <returns> | 333 /// <returns> |
| 366 /// An enumerator that can be used to iterate through the collection. | 334 /// An enumerator that can be used to iterate through the collection. |
| 367 /// </returns> | 335 /// </returns> |
| 368 public IEnumerator<T> GetEnumerator() | 336 public IEnumerator<T> GetEnumerator() |
| 369 { | 337 { |
| 370 for (int i = 0; i < count; i++) | 338 for (int i = 0; i < count; i++) |
| 371 { | 339 { |
| 372 yield return array[i]; | 340 yield return array[i]; |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 443 } | 411 } |
| 444 | 412 |
| 445 /// <summary> | 413 /// <summary> |
| 446 /// Returns the index of the given item within the collection, or -1 if
the item is not | 414 /// Returns the index of the given item within the collection, or -1 if
the item is not |
| 447 /// present. | 415 /// present. |
| 448 /// </summary> | 416 /// </summary> |
| 449 /// <param name="item">The item to find in the collection.</param> | 417 /// <param name="item">The item to find in the collection.</param> |
| 450 /// <returns>The zero-based index of the item, or -1 if it is not found.
</returns> | 418 /// <returns>The zero-based index of the item, or -1 if it is not found.
</returns> |
| 451 public int IndexOf(T item) | 419 public int IndexOf(T item) |
| 452 { | 420 { |
| 453 ProtoPreconditions.CheckNotNullUnconstrained(item, nameof(item)); | 421 if (item == null) |
| 422 { |
| 423 throw new ArgumentNullException("item"); |
| 424 } |
| 454 EqualityComparer<T> comparer = EqualityComparer<T>.Default; | 425 EqualityComparer<T> comparer = EqualityComparer<T>.Default; |
| 455 for (int i = 0; i < count; i++) | 426 for (int i = 0; i < count; i++) |
| 456 { | 427 { |
| 457 if (comparer.Equals(array[i], item)) | 428 if (comparer.Equals(array[i], item)) |
| 458 { | 429 { |
| 459 return i; | 430 return i; |
| 460 } | 431 } |
| 461 } | 432 } |
| 462 return -1; | 433 return -1; |
| 463 } | 434 } |
| 464 | 435 |
| 465 /// <summary> | 436 /// <summary> |
| 466 /// Inserts the given item at the specified index. | 437 /// Inserts the given item at the specified index. |
| 467 /// </summary> | 438 /// </summary> |
| 468 /// <param name="index">The index at which to insert the item.</param> | 439 /// <param name="index">The index at which to insert the item.</param> |
| 469 /// <param name="item">The item to insert.</param> | 440 /// <param name="item">The item to insert.</param> |
| 470 public void Insert(int index, T item) | 441 public void Insert(int index, T item) |
| 471 { | 442 { |
| 472 ProtoPreconditions.CheckNotNullUnconstrained(item, nameof(item)); | 443 if (item == null) |
| 444 { |
| 445 throw new ArgumentNullException("item"); |
| 446 } |
| 473 if (index < 0 || index > count) | 447 if (index < 0 || index > count) |
| 474 { | 448 { |
| 475 throw new ArgumentOutOfRangeException(nameof(index)); | 449 throw new ArgumentOutOfRangeException("index"); |
| 476 } | 450 } |
| 477 EnsureSize(count + 1); | 451 EnsureSize(count + 1); |
| 478 Array.Copy(array, index, array, index + 1, count - index); | 452 Array.Copy(array, index, array, index + 1, count - index); |
| 479 array[index] = item; | 453 array[index] = item; |
| 480 count++; | 454 count++; |
| 481 } | 455 } |
| 482 | 456 |
| 483 /// <summary> | 457 /// <summary> |
| 484 /// Removes the item at the given index. | 458 /// Removes the item at the given index. |
| 485 /// </summary> | 459 /// </summary> |
| 486 /// <param name="index">The zero-based index of the item to remove.</par
am> | 460 /// <param name="index">The zero-based index of the item to remove.</par
am> |
| 487 public void RemoveAt(int index) | 461 public void RemoveAt(int index) |
| 488 { | 462 { |
| 489 if (index < 0 || index >= count) | 463 if (index < 0 || index >= count) |
| 490 { | 464 { |
| 491 throw new ArgumentOutOfRangeException(nameof(index)); | 465 throw new ArgumentOutOfRangeException("index"); |
| 492 } | 466 } |
| 493 Array.Copy(array, index + 1, array, index, count - index - 1); | 467 Array.Copy(array, index + 1, array, index, count - index - 1); |
| 494 count--; | 468 count--; |
| 495 array[count] = default(T); | 469 array[count] = default(T); |
| 496 } | 470 } |
| 497 | 471 |
| 498 /// <summary> | 472 /// <summary> |
| 499 /// Returns a string representation of this repeated field, in the same | 473 /// Returns a string representation of this repeated field, in the same |
| 500 /// way as it would be represented by the default JSON formatter. | 474 /// way as it would be represented by the default JSON formatter. |
| 501 /// </summary> | 475 /// </summary> |
| (...skipping 11 matching lines...) Expand all Loading... |
| 513 /// The element at the specified index. | 487 /// The element at the specified index. |
| 514 /// </value> | 488 /// </value> |
| 515 /// <param name="index">The zero-based index of the element to get or se
t.</param> | 489 /// <param name="index">The zero-based index of the element to get or se
t.</param> |
| 516 /// <returns>The item at the specified index.</returns> | 490 /// <returns>The item at the specified index.</returns> |
| 517 public T this[int index] | 491 public T this[int index] |
| 518 { | 492 { |
| 519 get | 493 get |
| 520 { | 494 { |
| 521 if (index < 0 || index >= count) | 495 if (index < 0 || index >= count) |
| 522 { | 496 { |
| 523 throw new ArgumentOutOfRangeException(nameof(index)); | 497 throw new ArgumentOutOfRangeException("index"); |
| 524 } | 498 } |
| 525 return array[index]; | 499 return array[index]; |
| 526 } | 500 } |
| 527 set | 501 set |
| 528 { | 502 { |
| 529 if (index < 0 || index >= count) | 503 if (index < 0 || index >= count) |
| 530 { | 504 { |
| 531 throw new ArgumentOutOfRangeException(nameof(index)); | 505 throw new ArgumentOutOfRangeException("index"); |
| 532 } | 506 } |
| 533 ProtoPreconditions.CheckNotNullUnconstrained(value, nameof(value
)); | 507 if (value == null) |
| 508 { |
| 509 throw new ArgumentNullException("value"); |
| 510 } |
| 534 array[index] = value; | 511 array[index] = value; |
| 535 } | 512 } |
| 536 } | 513 } |
| 537 | 514 |
| 538 #region Explicit interface implementation for IList and ICollection. | 515 #region Explicit interface implementation for IList and ICollection. |
| 539 bool IList.IsFixedSize => false; | 516 bool IList.IsFixedSize { get { return false; } } |
| 540 | 517 |
| 541 void ICollection.CopyTo(Array array, int index) | 518 void ICollection.CopyTo(Array array, int index) |
| 542 { | 519 { |
| 543 Array.Copy(this.array, 0, array, index, count); | 520 Array.Copy(this.array, 0, array, index, count); |
| 544 } | 521 } |
| 545 | 522 |
| 546 bool ICollection.IsSynchronized => false; | 523 bool ICollection.IsSynchronized { get { return false; } } |
| 547 | 524 |
| 548 object ICollection.SyncRoot => this; | 525 object ICollection.SyncRoot { get { return this; } } |
| 549 | 526 |
| 550 object IList.this[int index] | 527 object IList.this[int index] |
| 551 { | 528 { |
| 552 get { return this[index]; } | 529 get { return this[index]; } |
| 553 set { this[index] = (T)value; } | 530 set { this[index] = (T)value; } |
| 554 } | 531 } |
| 555 | 532 |
| 556 int IList.Add(object value) | 533 int IList.Add(object value) |
| 557 { | 534 { |
| 558 Add((T) value); | 535 Add((T) value); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 582 { | 559 { |
| 583 if (!(value is T)) | 560 if (!(value is T)) |
| 584 { | 561 { |
| 585 return; | 562 return; |
| 586 } | 563 } |
| 587 Remove((T)value); | 564 Remove((T)value); |
| 588 } | 565 } |
| 589 #endregion | 566 #endregion |
| 590 } | 567 } |
| 591 } | 568 } |
| OLD | NEW |