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 |