diff options
author | Jon Skeet <skeet@pobox.com> | 2015-08-10 12:44:49 +0100 |
---|---|---|
committer | Jon Skeet <skeet@pobox.com> | 2015-08-10 12:44:49 +0100 |
commit | 29fe8d223e5f857c4b2949424c95a74c9f6901f0 (patch) | |
tree | f577cb5accd50e5c0c660be5ab32883297660ad4 /csharp/src/Google.Protobuf | |
parent | c2c42053bcc50417228132108a58238e3db408a4 (diff) | |
parent | 4deea8c231254503e9b1a41db07ff2b7ae3965fd (diff) |
Merge pull request #701 from jskeet/map-views
Implement Keys and Values as views in MapField
Diffstat (limited to 'csharp/src/Google.Protobuf')
-rw-r--r-- | csharp/src/Google.Protobuf/Collections/MapField.cs | 99 |
1 files changed, 95 insertions, 4 deletions
diff --git a/csharp/src/Google.Protobuf/Collections/MapField.cs b/csharp/src/Google.Protobuf/Collections/MapField.cs index dc4b04cb..0fa63bef 100644 --- a/csharp/src/Google.Protobuf/Collections/MapField.cs +++ b/csharp/src/Google.Protobuf/Collections/MapField.cs @@ -136,6 +136,12 @@ namespace Google.Protobuf.Collections return map.ContainsKey(key); } + private bool ContainsValue(TValue value) + { + var comparer = EqualityComparer<TValue>.Default; + return list.Any(pair => comparer.Equals(pair.Value, value)); + } + /// <summary> /// Removes the entry identified by the given key from the map. /// </summary> @@ -221,17 +227,15 @@ namespace Google.Protobuf.Collections } } - // TODO: Make these views? - /// <summary> /// Gets a collection containing the keys in the map. /// </summary> - public ICollection<TKey> Keys { get { return list.Select(t => t.Key).ToList(); } } + public ICollection<TKey> Keys { get { return new MapView<TKey>(this, pair => pair.Key, ContainsKey); } } /// <summary> /// Gets a collection containing the values in the map. /// </summary> - public ICollection<TValue> Values { get { return list.Select(t => t.Value).ToList(); } } + public ICollection<TValue> Values { get { return new MapView<TValue>(this, pair => pair.Value, ContainsValue); } } /// <summary> /// Adds the specified entries to the map. @@ -658,5 +662,92 @@ namespace Google.Protobuf.Collections MessageDescriptor IMessage.Descriptor { get { return null; } } } } + + private class MapView<T> : ICollection<T>, ICollection + { + private readonly MapField<TKey, TValue> parent; + private readonly Func<KeyValuePair<TKey, TValue>, T> projection; + private readonly Func<T, bool> containsCheck; + + internal MapView( + MapField<TKey, TValue> parent, + Func<KeyValuePair<TKey, TValue>, T> projection, + Func<T, bool> containsCheck) + { + this.parent = parent; + this.projection = projection; + this.containsCheck = containsCheck; + } + + public int Count { get { return parent.Count; } } + + public bool IsReadOnly { get { return true; } } + + public bool IsSynchronized { get { return false; } } + + public object SyncRoot { get { return parent; } } + + public void Add(T item) + { + throw new NotSupportedException(); + } + + public void Clear() + { + throw new NotSupportedException(); + } + + public bool Contains(T item) + { + return containsCheck(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + if (arrayIndex < 0) + { + throw new ArgumentOutOfRangeException("arrayIndex"); + } + if (arrayIndex + Count >= array.Length) + { + throw new ArgumentException("Not enough space in the array", "array"); + } + foreach (var item in this) + { + array[arrayIndex++] = item; + } + } + + public IEnumerator<T> GetEnumerator() + { + return parent.list.Select(projection).GetEnumerator(); + } + + public bool Remove(T item) + { + throw new NotSupportedException(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void CopyTo(Array array, int index) + { + if (index < 0) + { + throw new ArgumentOutOfRangeException("index"); + } + if (index + Count >= array.Length) + { + throw new ArgumentException("Not enough space in the array", "array"); + } + foreach (var item in this) + { + array.SetValue(item, index++); + } + } + } } } |