Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(314)

Side by Side Diff: third_party/protobuf/csharp/src/Google.Protobuf/Collections/MapField.cs

Issue 1842653006: Update //third_party/protobuf to version 3. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: merge Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 #region Copyright notice and license
2 // Protocol Buffers - Google's data interchange format
3 // Copyright 2015 Google Inc. All rights reserved.
4 // https://developers.google.com/protocol-buffers/
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are
8 // met:
9 //
10 // * Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 // * Redistributions in binary form must reproduce the above
13 // copyright notice, this list of conditions and the following disclaimer
14 // in the documentation and/or other materials provided with the
15 // distribution.
16 // * Neither the name of Google Inc. nor the names of its
17 // contributors may be used to endorse or promote products derived from
18 // this software without specific prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
31 #endregion
32
33 using Google.Protobuf.Reflection;
34 using System;
35 using System.Collections;
36 using System.Collections.Generic;
37 using System.Linq;
38 using System.Text;
39 using Google.Protobuf.Compatibility;
40
41 namespace Google.Protobuf.Collections
42 {
43 /// <summary>
44 /// Representation of a map field in a Protocol Buffer message.
45 /// </summary>
46 /// <typeparam name="TKey">Key type in the map. Must be a type supported by Protocol Buffer map keys.</typeparam>
47 /// <typeparam name="TValue">Value type in the map. Must be a type supported by Protocol Buffers.</typeparam>
48 /// <remarks>
49 /// <para>
50 /// This implementation preserves insertion order for simplicity of testing
51 /// code using maps fields. Overwriting an existing entry does not change th e
52 /// position of that entry within the map. Equality is not order-sensitive.
53 /// For string keys, the equality comparison is provided by <see cref="Strin gComparer.Ordinal" />.
54 /// </para>
55 /// <para>
56 /// This implementation does not generally prohibit the use of key/value typ es which are not
57 /// supported by Protocol Buffers (e.g. using a key type of <code>byte</code >) but nor does it guarantee
58 /// that all operations will work in such cases.
59 /// </para>
60 /// </remarks>
61 public sealed class MapField<TKey, TValue> : IDeepCloneable<MapField<TKey, T Value>>, IDictionary<TKey, TValue>, IEquatable<MapField<TKey, TValue>>, IDiction ary
62 {
63 // TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.)
64 private readonly bool allowNullValues;
65 private readonly Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TVal ue>>> map =
66 new Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>();
67 private readonly LinkedList<KeyValuePair<TKey, TValue>> list = new Linke dList<KeyValuePair<TKey, TValue>>();
68
69 /// <summary>
70 /// Constructs a new map field, defaulting the value nullability to only allow null values for message types
71 /// and non-nullable value types.
72 /// </summary>
73 public MapField() : this(typeof(IMessage).IsAssignableFrom(typeof(TValue )) || Nullable.GetUnderlyingType(typeof(TValue)) != null)
74 {
75 }
76
77 /// <summary>
78 /// Constructs a new map field, overriding the choice of whether null va lues are permitted in the map.
79 /// This is used by wrapper types, where maps with string and bytes wrap pers as the value types
80 /// support null values.
81 /// </summary>
82 /// <param name="allowNullValues">Whether null values are permitted in t he map or not.</param>
83 public MapField(bool allowNullValues)
84 {
85 if (allowNullValues && typeof(TValue).IsValueType() && Nullable.GetU nderlyingType(typeof(TValue)) == null)
86 {
87 throw new ArgumentException("allowNullValues", "Non-nullable val ue types do not support null values");
88 }
89 this.allowNullValues = allowNullValues;
90 }
91
92 /// <summary>
93 /// Creates a deep clone of this object.
94 /// </summary>
95 /// <returns>
96 /// A deep clone of this object.
97 /// </returns>
98 public MapField<TKey, TValue> Clone()
99 {
100 var clone = new MapField<TKey, TValue>(allowNullValues);
101 // Keys are never cloneable. Values might be.
102 if (typeof(IDeepCloneable<TValue>).IsAssignableFrom(typeof(TValue)))
103 {
104 foreach (var pair in list)
105 {
106 clone.Add(pair.Key, pair.Value == null ? pair.Value : ((IDee pCloneable<TValue>)pair.Value).Clone());
107 }
108 }
109 else
110 {
111 // Nothing is cloneable, so we don't need to worry.
112 clone.Add(this);
113 }
114 return clone;
115 }
116
117 /// <summary>
118 /// Adds the specified key/value pair to the map.
119 /// </summary>
120 /// <remarks>
121 /// This operation fails if the key already exists in the map. To replac e an existing entry, use the indexer.
122 /// </remarks>
123 /// <param name="key">The key to add</param>
124 /// <param name="value">The value to add.</param>
125 /// <exception cref="System.ArgumentException">The given key already exi sts in map.</exception>
126 public void Add(TKey key, TValue value)
127 {
128 // Validation of arguments happens in ContainsKey and the indexer
129 if (ContainsKey(key))
130 {
131 throw new ArgumentException("Key already exists in map", "key");
132 }
133 this[key] = value;
134 }
135
136 /// <summary>
137 /// Determines whether the specified key is present in the map.
138 /// </summary>
139 /// <param name="key">The key to check.</param>
140 /// <returns><c>true</c> if the map contains the given key; <c>false</c> otherwise.</returns>
141 public bool ContainsKey(TKey key)
142 {
143 Preconditions.CheckNotNullUnconstrained(key, "key");
144 return map.ContainsKey(key);
145 }
146
147 private bool ContainsValue(TValue value)
148 {
149 var comparer = EqualityComparer<TValue>.Default;
150 return list.Any(pair => comparer.Equals(pair.Value, value));
151 }
152
153 /// <summary>
154 /// Removes the entry identified by the given key from the map.
155 /// </summary>
156 /// <param name="key">The key indicating the entry to remove from the ma p.</param>
157 /// <returns><c>true</c> if the map contained the given key before the e ntry was removed; <c>false</c> otherwise.</returns>
158 public bool Remove(TKey key)
159 {
160 Preconditions.CheckNotNullUnconstrained(key, "key");
161 LinkedListNode<KeyValuePair<TKey, TValue>> node;
162 if (map.TryGetValue(key, out node))
163 {
164 map.Remove(key);
165 node.List.Remove(node);
166 return true;
167 }
168 else
169 {
170 return false;
171 }
172 }
173
174 /// <summary>
175 /// Gets the value associated with the specified key.
176 /// </summary>
177 /// <param name="key">The key whose value to get.</param>
178 /// <param name="value">When this method returns, the value associated w ith the specified key, if the key is found;
179 /// otherwise, the default value for the type of the <paramref name="val ue"/> parameter.
180 /// This parameter is passed uninitialized.</param>
181 /// <returns><c>true</c> if the map contains an element with the specifi ed key; otherwise, <c>false</c>.</returns>
182 public bool TryGetValue(TKey key, out TValue value)
183 {
184 LinkedListNode<KeyValuePair<TKey, TValue>> node;
185 if (map.TryGetValue(key, out node))
186 {
187 value = node.Value.Value;
188 return true;
189 }
190 else
191 {
192 value = default(TValue);
193 return false;
194 }
195 }
196
197 /// <summary>
198 /// Gets or sets the value associated with the specified key.
199 /// </summary>
200 /// <param name="key">The key of the value to get or set.</param>
201 /// <exception cref="KeyNotFoundException">The property is retrieved and key does not exist in the collection.</exception>
202 /// <returns>The value associated with the specified key. If the specifi ed key is not found,
203 /// a get operation throws a <see cref="KeyNotFoundException"/>, and a s et operation creates a new element with the specified key.</returns>
204 public TValue this[TKey key]
205 {
206 get
207 {
208 Preconditions.CheckNotNullUnconstrained(key, "key");
209 TValue value;
210 if (TryGetValue(key, out value))
211 {
212 return value;
213 }
214 throw new KeyNotFoundException();
215 }
216 set
217 {
218 Preconditions.CheckNotNullUnconstrained(key, "key");
219 // value == null check here is redundant, but avoids boxing.
220 if (value == null && !allowNullValues)
221 {
222 Preconditions.CheckNotNullUnconstrained(value, "value");
223 }
224 LinkedListNode<KeyValuePair<TKey, TValue>> node;
225 var pair = new KeyValuePair<TKey, TValue>(key, value);
226 if (map.TryGetValue(key, out node))
227 {
228 node.Value = pair;
229 }
230 else
231 {
232 node = list.AddLast(pair);
233 map[key] = node;
234 }
235 }
236 }
237
238 /// <summary>
239 /// Gets a collection containing the keys in the map.
240 /// </summary>
241 public ICollection<TKey> Keys { get { return new MapView<TKey>(this, pai r => pair.Key, ContainsKey); } }
242
243 /// <summary>
244 /// Gets a collection containing the values in the map.
245 /// </summary>
246 public ICollection<TValue> Values { get { return new MapView<TValue>(thi s, pair => pair.Value, ContainsValue); } }
247
248 /// <summary>
249 /// Adds the specified entries to the map.
250 /// </summary>
251 /// <param name="entries">The entries to add to the map.</param>
252 public void Add(IDictionary<TKey, TValue> entries)
253 {
254 Preconditions.CheckNotNull(entries, "entries");
255 foreach (var pair in entries)
256 {
257 Add(pair.Key, pair.Value);
258 }
259 }
260
261 /// <summary>
262 /// Returns an enumerator that iterates through the collection.
263 /// </summary>
264 /// <returns>
265 /// An enumerator that can be used to iterate through the collection.
266 /// </returns>
267 public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
268 {
269 return list.GetEnumerator();
270 }
271
272 /// <summary>
273 /// Returns an enumerator that iterates through a collection.
274 /// </summary>
275 /// <returns>
276 /// An <see cref="T:System.Collections.IEnumerator" /> object that can b e used to iterate through the collection.
277 /// </returns>
278 IEnumerator IEnumerable.GetEnumerator()
279 {
280 return GetEnumerator();
281 }
282
283 /// <summary>
284 /// Adds the specified item to the map.
285 /// </summary>
286 /// <param name="item">The item to add to the map.</param>
287 void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TVal ue> item)
288 {
289 Add(item.Key, item.Value);
290 }
291
292 /// <summary>
293 /// Removes all items from the map.
294 /// </summary>
295 public void Clear()
296 {
297 list.Clear();
298 map.Clear();
299 }
300
301 /// <summary>
302 /// Determines whether map contains an entry equivalent to the given key /value pair.
303 /// </summary>
304 /// <param name="item">The key/value pair to find.</param>
305 /// <returns></returns>
306 bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
307 {
308 TValue value;
309 return TryGetValue(item.Key, out value)
310 && EqualityComparer<TValue>.Default.Equals(item.Value, value);
311 }
312
313 /// <summary>
314 /// Copies the key/value pairs in this map to an array.
315 /// </summary>
316 /// <param name="array">The array to copy the entries into.</param>
317 /// <param name="arrayIndex">The index of the array at which to start co pying values.</param>
318 void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, T Value>[] array, int arrayIndex)
319 {
320 list.CopyTo(array, arrayIndex);
321 }
322
323 /// <summary>
324 /// Removes the specified key/value pair from the map.
325 /// </summary>
326 /// <remarks>Both the key and the value must be found for the entry to b e removed.</remarks>
327 /// <param name="item">The key/value pair to remove.</param>
328 /// <returns><c>true</c> if the key/value pair was found and removed; <c >false</c> otherwise.</returns>
329 bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, T Value> item)
330 {
331 if (item.Key == null)
332 {
333 throw new ArgumentException("Key is null", "item");
334 }
335 LinkedListNode<KeyValuePair<TKey, TValue>> node;
336 if (map.TryGetValue(item.Key, out node) &&
337 EqualityComparer<TValue>.Default.Equals(item.Value, node.Value.V alue))
338 {
339 map.Remove(item.Key);
340 node.List.Remove(node);
341 return true;
342 }
343 else
344 {
345 return false;
346 }
347 }
348
349 /// <summary>
350 /// Returns whether or not this map allows values to be null.
351 /// </summary>
352 public bool AllowsNullValues { get { return allowNullValues; } }
353
354 /// <summary>
355 /// Gets the number of elements contained in the map.
356 /// </summary>
357 public int Count { get { return list.Count; } }
358
359 /// <summary>
360 /// Gets a value indicating whether the map is read-only.
361 /// </summary>
362 public bool IsReadOnly { get { return false; } }
363
364 /// <summary>
365 /// Determines whether the specified <see cref="System.Object" />, is eq ual to this instance.
366 /// </summary>
367 /// <param name="other">The <see cref="System.Object" /> to compare with this instance.</param>
368 /// <returns>
369 /// <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
370 /// </returns>
371 public override bool Equals(object other)
372 {
373 return Equals(other as MapField<TKey, TValue>);
374 }
375
376 /// <summary>
377 /// Returns a hash code for this instance.
378 /// </summary>
379 /// <returns>
380 /// A hash code for this instance, suitable for use in hashing algorithm s and data structures like a hash table.
381 /// </returns>
382 public override int GetHashCode()
383 {
384 var valueComparer = EqualityComparer<TValue>.Default;
385 int hash = 0;
386 foreach (var pair in list)
387 {
388 hash ^= pair.Key.GetHashCode() * 31 + valueComparer.GetHashCode( pair.Value);
389 }
390 return hash;
391 }
392
393 /// <summary>
394 /// Compares this map with another for equality.
395 /// </summary>
396 /// <remarks>
397 /// The order of the key/value pairs in the maps is not deemed significa nt in this comparison.
398 /// </remarks>
399 /// <param name="other">The map to compare this with.</param>
400 /// <returns><c>true</c> if <paramref name="other"/> refers to an equal map; <c>false</c> otherwise.</returns>
401 public bool Equals(MapField<TKey, TValue> other)
402 {
403 if (other == null)
404 {
405 return false;
406 }
407 if (other == this)
408 {
409 return true;
410 }
411 if (other.Count != this.Count)
412 {
413 return false;
414 }
415 var valueComparer = EqualityComparer<TValue>.Default;
416 foreach (var pair in this)
417 {
418 TValue value;
419 if (!other.TryGetValue(pair.Key, out value))
420 {
421 return false;
422 }
423 if (!valueComparer.Equals(value, pair.Value))
424 {
425 return false;
426 }
427 }
428 return true;
429 }
430
431 /// <summary>
432 /// Adds entries to the map from the given stream.
433 /// </summary>
434 /// <remarks>
435 /// It is assumed that the stream is initially positioned after the tag specified by the codec.
436 /// This method will continue reading entries from the stream until the end is reached, or
437 /// a different tag is encountered.
438 /// </remarks>
439 /// <param name="input">Stream to read from</param>
440 /// <param name="codec">Codec describing how the key/value pairs are enc oded</param>
441 public void AddEntriesFrom(CodedInputStream input, Codec codec)
442 {
443 var adapter = new Codec.MessageAdapter(codec);
444 do
445 {
446 adapter.Reset();
447 input.ReadMessage(adapter);
448 this[adapter.Key] = adapter.Value;
449 } while (input.MaybeConsumeTag(codec.MapTag));
450 }
451
452 /// <summary>
453 /// Writes the contents of this map to the given coded output stream, us ing the specified codec
454 /// to encode each entry.
455 /// </summary>
456 /// <param name="output">The output stream to write to.</param>
457 /// <param name="codec">The codec to use for each entry.</param>
458 public void WriteTo(CodedOutputStream output, Codec codec)
459 {
460 var message = new Codec.MessageAdapter(codec);
461 foreach (var entry in list)
462 {
463 message.Key = entry.Key;
464 message.Value = entry.Value;
465 output.WriteTag(codec.MapTag);
466 output.WriteMessage(message);
467 }
468 }
469
470 /// <summary>
471 /// Calculates the size of this map based on the given entry codec.
472 /// </summary>
473 /// <param name="codec">The codec to use to encode each entry.</param>
474 /// <returns></returns>
475 public int CalculateSize(Codec codec)
476 {
477 if (Count == 0)
478 {
479 return 0;
480 }
481 var message = new Codec.MessageAdapter(codec);
482 int size = 0;
483 foreach (var entry in list)
484 {
485 message.Key = entry.Key;
486 message.Value = entry.Value;
487 size += CodedOutputStream.ComputeRawVarint32Size(codec.MapTag);
488 size += CodedOutputStream.ComputeMessageSize(message);
489 }
490 return size;
491 }
492
493 /// <summary>
494 /// Returns a string representation of this repeated field, in the same
495 /// way as it would be represented by the default JSON formatter.
496 /// </summary>
497 public override string ToString()
498 {
499 var builder = new StringBuilder();
500 JsonFormatter.Default.WriteDictionary(builder, this);
501 return builder.ToString();
502 }
503
504 #region IDictionary explicit interface implementation
505 void IDictionary.Add(object key, object value)
506 {
507 Add((TKey)key, (TValue)value);
508 }
509
510 bool IDictionary.Contains(object key)
511 {
512 if (!(key is TKey))
513 {
514 return false;
515 }
516 return ContainsKey((TKey)key);
517 }
518
519 IDictionaryEnumerator IDictionary.GetEnumerator()
520 {
521 return new DictionaryEnumerator(GetEnumerator());
522 }
523
524 void IDictionary.Remove(object key)
525 {
526 Preconditions.CheckNotNull(key, "key");
527 if (!(key is TKey))
528 {
529 return;
530 }
531 Remove((TKey)key);
532 }
533
534 void ICollection.CopyTo(Array array, int index)
535 {
536 // This is ugly and slow as heck, but with any luck it will never be used anyway.
537 ICollection temp = this.Select(pair => new DictionaryEntry(pair.Key, pair.Value)).ToList();
538 temp.CopyTo(array, index);
539 }
540
541 bool IDictionary.IsFixedSize { get { return false; } }
542
543 ICollection IDictionary.Keys { get { return (ICollection)Keys; } }
544
545 ICollection IDictionary.Values { get { return (ICollection)Values; } }
546
547 bool ICollection.IsSynchronized { get { return false; } }
548
549 object ICollection.SyncRoot { get { return this; } }
550
551 object IDictionary.this[object key]
552 {
553 get
554 {
555 Preconditions.CheckNotNull(key, "key");
556 if (!(key is TKey))
557 {
558 return null;
559 }
560 TValue value;
561 TryGetValue((TKey)key, out value);
562 return value;
563 }
564
565 set
566 {
567 this[(TKey)key] = (TValue)value;
568 }
569 }
570 #endregion
571
572 private class DictionaryEnumerator : IDictionaryEnumerator
573 {
574 private readonly IEnumerator<KeyValuePair<TKey, TValue>> enumerator;
575
576 internal DictionaryEnumerator(IEnumerator<KeyValuePair<TKey, TValue> > enumerator)
577 {
578 this.enumerator = enumerator;
579 }
580
581 public bool MoveNext()
582 {
583 return enumerator.MoveNext();
584 }
585
586 public void Reset()
587 {
588 enumerator.Reset();
589 }
590
591 public object Current { get { return Entry; } }
592 public DictionaryEntry Entry { get { return new DictionaryEntry(Key, Value); } }
593 public object Key { get { return enumerator.Current.Key; } }
594 public object Value { get { return enumerator.Current.Value; } }
595 }
596
597 /// <summary>
598 /// A codec for a specific map field. This contains all the information required to encode and
599 /// decode the nested messages.
600 /// </summary>
601 public sealed class Codec
602 {
603 private readonly FieldCodec<TKey> keyCodec;
604 private readonly FieldCodec<TValue> valueCodec;
605 private readonly uint mapTag;
606
607 /// <summary>
608 /// Creates a new entry codec based on a separate key codec and valu e codec,
609 /// and the tag to use for each map entry.
610 /// </summary>
611 /// <param name="keyCodec">The key codec.</param>
612 /// <param name="valueCodec">The value codec.</param>
613 /// <param name="mapTag">The map tag to use to introduce each map en try.</param>
614 public Codec(FieldCodec<TKey> keyCodec, FieldCodec<TValue> valueCode c, uint mapTag)
615 {
616 this.keyCodec = keyCodec;
617 this.valueCodec = valueCodec;
618 this.mapTag = mapTag;
619 }
620
621 /// <summary>
622 /// The tag used in the enclosing message to indicate map entries.
623 /// </summary>
624 internal uint MapTag { get { return mapTag; } }
625
626 /// <summary>
627 /// A mutable message class, used for parsing and serializing. This
628 /// delegates the work to a codec, but implements the <see cref="IMe ssage"/> interface
629 /// for interop with <see cref="CodedInputStream"/> and <see cref="C odedOutputStream"/>.
630 /// This is nested inside Codec as it's tightly coupled to the assoc iated codec,
631 /// and it's simpler if it has direct access to all its fields.
632 /// </summary>
633 internal class MessageAdapter : IMessage
634 {
635 private readonly Codec codec;
636 internal TKey Key { get; set; }
637 internal TValue Value { get; set; }
638
639 internal MessageAdapter(Codec codec)
640 {
641 this.codec = codec;
642 }
643
644 internal void Reset()
645 {
646 Key = codec.keyCodec.DefaultValue;
647 Value = codec.valueCodec.DefaultValue;
648 }
649
650 public void MergeFrom(CodedInputStream input)
651 {
652 uint tag;
653 while ((tag = input.ReadTag()) != 0)
654 {
655 if (tag == codec.keyCodec.Tag)
656 {
657 Key = codec.keyCodec.Read(input);
658 }
659 else if (tag == codec.valueCodec.Tag)
660 {
661 Value = codec.valueCodec.Read(input);
662 }
663 else
664 {
665 input.SkipLastField();
666 }
667 }
668 }
669
670 public void WriteTo(CodedOutputStream output)
671 {
672 codec.keyCodec.WriteTagAndValue(output, Key);
673 codec.valueCodec.WriteTagAndValue(output, Value);
674 }
675
676 public int CalculateSize()
677 {
678 return codec.keyCodec.CalculateSizeWithTag(Key) + codec.valu eCodec.CalculateSizeWithTag(Value);
679 }
680
681 MessageDescriptor IMessage.Descriptor { get { return null; } }
682 }
683 }
684
685 private class MapView<T> : ICollection<T>, ICollection
686 {
687 private readonly MapField<TKey, TValue> parent;
688 private readonly Func<KeyValuePair<TKey, TValue>, T> projection;
689 private readonly Func<T, bool> containsCheck;
690
691 internal MapView(
692 MapField<TKey, TValue> parent,
693 Func<KeyValuePair<TKey, TValue>, T> projection,
694 Func<T, bool> containsCheck)
695 {
696 this.parent = parent;
697 this.projection = projection;
698 this.containsCheck = containsCheck;
699 }
700
701 public int Count { get { return parent.Count; } }
702
703 public bool IsReadOnly { get { return true; } }
704
705 public bool IsSynchronized { get { return false; } }
706
707 public object SyncRoot { get { return parent; } }
708
709 public void Add(T item)
710 {
711 throw new NotSupportedException();
712 }
713
714 public void Clear()
715 {
716 throw new NotSupportedException();
717 }
718
719 public bool Contains(T item)
720 {
721 return containsCheck(item);
722 }
723
724 public void CopyTo(T[] array, int arrayIndex)
725 {
726 if (arrayIndex < 0)
727 {
728 throw new ArgumentOutOfRangeException("arrayIndex");
729 }
730 if (arrayIndex + Count >= array.Length)
731 {
732 throw new ArgumentException("Not enough space in the array", "array");
733 }
734 foreach (var item in this)
735 {
736 array[arrayIndex++] = item;
737 }
738 }
739
740 public IEnumerator<T> GetEnumerator()
741 {
742 return parent.list.Select(projection).GetEnumerator();
743 }
744
745 public bool Remove(T item)
746 {
747 throw new NotSupportedException();
748 }
749
750 IEnumerator IEnumerable.GetEnumerator()
751 {
752 return GetEnumerator();
753 }
754
755 public void CopyTo(Array array, int index)
756 {
757 if (index < 0)
758 {
759 throw new ArgumentOutOfRangeException("index");
760 }
761 if (index + Count >= array.Length)
762 {
763 throw new ArgumentException("Not enough space in the array", "array");
764 }
765 foreach (var item in this)
766 {
767 array.SetValue(item, index++);
768 }
769 }
770 }
771 }
772 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698