aboutsummaryrefslogtreecommitdiffhomepage
path: root/csharp/src/Google.Protobuf
diff options
context:
space:
mode:
authorGravatar Jon Skeet <skeet@pobox.com>2015-08-10 12:44:49 +0100
committerGravatar Jon Skeet <skeet@pobox.com>2015-08-10 12:44:49 +0100
commit29fe8d223e5f857c4b2949424c95a74c9f6901f0 (patch)
treef577cb5accd50e5c0c660be5ab32883297660ad4 /csharp/src/Google.Protobuf
parentc2c42053bcc50417228132108a58238e3db408a4 (diff)
parent4deea8c231254503e9b1a41db07ff2b7ae3965fd (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.cs99
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++);
+ }
+ }
+ }
}
}