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