aboutsummaryrefslogtreecommitdiff
path: root/csharp/src/Google.Protobuf/Collections
diff options
context:
space:
mode:
Diffstat (limited to 'csharp/src/Google.Protobuf/Collections')
-rw-r--r--csharp/src/Google.Protobuf/Collections/Lists.cs89
-rw-r--r--csharp/src/Google.Protobuf/Collections/MapField.cs771
-rw-r--r--csharp/src/Google.Protobuf/Collections/ProtobufEqualityComparers.cs130
-rw-r--r--csharp/src/Google.Protobuf/Collections/ReadOnlyDictionary.cs147
-rwxr-xr-xcsharp/src/Google.Protobuf/Collections/RepeatedField.cs595
5 files changed, 0 insertions, 1732 deletions
diff --git a/csharp/src/Google.Protobuf/Collections/Lists.cs b/csharp/src/Google.Protobuf/Collections/Lists.cs
deleted file mode 100644
index 860795ce..00000000
--- a/csharp/src/Google.Protobuf/Collections/Lists.cs
+++ /dev/null
@@ -1,89 +0,0 @@
-#region Copyright notice and license
-// Protocol Buffers - Google's data interchange format
-// Copyright 2017 Google Inc. All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#endregion
-
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-
-namespace Google.Protobuf.Collections
-{
- /// <summary>
- /// Utility to compare if two Lists are the same, and the hash code
- /// of a List.
- /// </summary>
- public static class Lists
- {
- /// <summary>
- /// Checks if two lists are equal.
- /// </summary>
- public static bool Equals<T>(List<T> left, List<T> right)
- {
- if (left == right)
- {
- return true;
- }
- if (left == null || right == null)
- {
- return false;
- }
- if (left.Count != right.Count)
- {
- return false;
- }
- IEqualityComparer<T> comparer = EqualityComparer<T>.Default;
- for (int i = 0; i < left.Count; i++)
- {
- if (!comparer.Equals(left[i], right[i]))
- {
- return false;
- }
- }
- return true;
- }
-
- /// <summary>
- /// Gets the list's hash code.
- /// </summary>
- public static int GetHashCode<T>(List<T> list)
- {
- if (list == null)
- {
- return 0;
- }
- int hash = 31;
- foreach (T element in list)
- {
- hash = hash * 29 + element.GetHashCode();
- }
- return hash;
- }
- }
-} \ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Collections/MapField.cs b/csharp/src/Google.Protobuf/Collections/MapField.cs
deleted file mode 100644
index dbbcc148..00000000
--- a/csharp/src/Google.Protobuf/Collections/MapField.cs
+++ /dev/null
@@ -1,771 +0,0 @@
-#region Copyright notice and license
-// Protocol Buffers - Google's data interchange format
-// Copyright 2015 Google Inc. All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#endregion
-
-using Google.Protobuf.Compatibility;
-using Google.Protobuf.Reflection;
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-
-namespace Google.Protobuf.Collections
-{
- /// <summary>
- /// Representation of a map field in a Protocol Buffer message.
- /// </summary>
- /// <typeparam name="TKey">Key type in the map. Must be a type supported by Protocol Buffer map keys.</typeparam>
- /// <typeparam name="TValue">Value type in the map. Must be a type supported by Protocol Buffers.</typeparam>
- /// <remarks>
- /// <para>
- /// For string keys, the equality comparison is provided by <see cref="StringComparer.Ordinal" />.
- /// </para>
- /// <para>
- /// Null values are not permitted in the map, either for wrapper types or regular messages.
- /// If a map is deserialized from a data stream and the value is missing from an entry, a default value
- /// is created instead. For primitive types, that is the regular default value (0, the empty string and so
- /// on); for message types, an empty instance of the message is created, as if the map entry contained a 0-length
- /// encoded value for the field.
- /// </para>
- /// <para>
- /// This implementation does not generally prohibit the use of key/value types which are not
- /// supported by Protocol Buffers (e.g. using a key type of <code>byte</code>) but nor does it guarantee
- /// that all operations will work in such cases.
- /// </para>
- /// <para>
- /// The order in which entries are returned when iterating over this object is undefined, and may change
- /// in future versions.
- /// </para>
- /// </remarks>
- public sealed class MapField<TKey, TValue> : IDeepCloneable<MapField<TKey, TValue>>, IDictionary<TKey, TValue>, IEquatable<MapField<TKey, TValue>>, IDictionary
-#if !NET35
- , IReadOnlyDictionary<TKey, TValue>
-#endif
- {
- private static readonly EqualityComparer<TValue> ValueEqualityComparer = ProtobufEqualityComparers.GetEqualityComparer<TValue>();
- private static readonly EqualityComparer<TKey> KeyEqualityComparer = ProtobufEqualityComparers.GetEqualityComparer<TKey>();
-
- // TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.)
- private readonly Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>> map =
- new Dictionary<TKey, LinkedListNode<KeyValuePair<TKey, TValue>>>(KeyEqualityComparer);
- private readonly LinkedList<KeyValuePair<TKey, TValue>> list = new LinkedList<KeyValuePair<TKey, TValue>>();
-
- /// <summary>
- /// Creates a deep clone of this object.
- /// </summary>
- /// <returns>
- /// A deep clone of this object.
- /// </returns>
- public MapField<TKey, TValue> Clone()
- {
- var clone = new MapField<TKey, TValue>();
- // Keys are never cloneable. Values might be.
- if (typeof(IDeepCloneable<TValue>).IsAssignableFrom(typeof(TValue)))
- {
- foreach (var pair in list)
- {
- clone.Add(pair.Key, ((IDeepCloneable<TValue>)pair.Value).Clone());
- }
- }
- else
- {
- // Nothing is cloneable, so we don't need to worry.
- clone.Add(this);
- }
- return clone;
- }
-
- /// <summary>
- /// Adds the specified key/value pair to the map.
- /// </summary>
- /// <remarks>
- /// This operation fails if the key already exists in the map. To replace an existing entry, use the indexer.
- /// </remarks>
- /// <param name="key">The key to add</param>
- /// <param name="value">The value to add.</param>
- /// <exception cref="System.ArgumentException">The given key already exists in map.</exception>
- public void Add(TKey key, TValue value)
- {
- // Validation of arguments happens in ContainsKey and the indexer
- if (ContainsKey(key))
- {
- throw new ArgumentException("Key already exists in map", nameof(key));
- }
- this[key] = value;
- }
-
- /// <summary>
- /// Determines whether the specified key is present in the map.
- /// </summary>
- /// <param name="key">The key to check.</param>
- /// <returns><c>true</c> if the map contains the given key; <c>false</c> otherwise.</returns>
- public bool ContainsKey(TKey key)
- {
- ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key));
- return map.ContainsKey(key);
- }
-
- private bool ContainsValue(TValue value) =>
- list.Any(pair => ValueEqualityComparer.Equals(pair.Value, value));
-
- /// <summary>
- /// Removes the entry identified by the given key from the map.
- /// </summary>
- /// <param name="key">The key indicating the entry to remove from the map.</param>
- /// <returns><c>true</c> if the map contained the given key before the entry was removed; <c>false</c> otherwise.</returns>
- public bool Remove(TKey key)
- {
- ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key));
- LinkedListNode<KeyValuePair<TKey, TValue>> node;
- if (map.TryGetValue(key, out node))
- {
- map.Remove(key);
- node.List.Remove(node);
- return true;
- }
- else
- {
- return false;
- }
- }
-
- /// <summary>
- /// Gets the value associated with the specified key.
- /// </summary>
- /// <param name="key">The key whose value to get.</param>
- /// <param name="value">When this method returns, the value associated with the specified key, if the key is found;
- /// otherwise, the default value for the type of the <paramref name="value"/> parameter.
- /// This parameter is passed uninitialized.</param>
- /// <returns><c>true</c> if the map contains an element with the specified key; otherwise, <c>false</c>.</returns>
- public bool TryGetValue(TKey key, out TValue value)
- {
- LinkedListNode<KeyValuePair<TKey, TValue>> node;
- if (map.TryGetValue(key, out node))
- {
- value = node.Value.Value;
- return true;
- }
- else
- {
- value = default(TValue);
- return false;
- }
- }
-
- /// <summary>
- /// Gets or sets the value associated with the specified key.
- /// </summary>
- /// <param name="key">The key of the value to get or set.</param>
- /// <exception cref="KeyNotFoundException">The property is retrieved and key does not exist in the collection.</exception>
- /// <returns>The value associated with the specified key. If the specified key is not found,
- /// a get operation throws a <see cref="KeyNotFoundException"/>, and a set operation creates a new element with the specified key.</returns>
- public TValue this[TKey key]
- {
- get
- {
- ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key));
- TValue value;
- if (TryGetValue(key, out value))
- {
- return value;
- }
- throw new KeyNotFoundException();
- }
- set
- {
- ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key));
- // value == null check here is redundant, but avoids boxing.
- if (value == null)
- {
- ProtoPreconditions.CheckNotNullUnconstrained(value, nameof(value));
- }
- LinkedListNode<KeyValuePair<TKey, TValue>> node;
- var pair = new KeyValuePair<TKey, TValue>(key, value);
- if (map.TryGetValue(key, out node))
- {
- node.Value = pair;
- }
- else
- {
- node = list.AddLast(pair);
- map[key] = node;
- }
- }
- }
-
- /// <summary>
- /// Gets a collection containing the keys in the map.
- /// </summary>
- 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 new MapView<TValue>(this, pair => pair.Value, ContainsValue); } }
-
- /// <summary>
- /// Adds the specified entries to the map. The keys and values are not automatically cloned.
- /// </summary>
- /// <param name="entries">The entries to add to the map.</param>
- public void Add(IDictionary<TKey, TValue> entries)
- {
- ProtoPreconditions.CheckNotNull(entries, nameof(entries));
- foreach (var pair in entries)
- {
- Add(pair.Key, pair.Value);
- }
- }
-
- /// <summary>
- /// Returns an enumerator that iterates through the collection.
- /// </summary>
- /// <returns>
- /// An enumerator that can be used to iterate through the collection.
- /// </returns>
- public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
- {
- return list.GetEnumerator();
- }
-
- /// <summary>
- /// Returns an enumerator that iterates through a collection.
- /// </summary>
- /// <returns>
- /// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
- /// </returns>
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
-
- /// <summary>
- /// Adds the specified item to the map.
- /// </summary>
- /// <param name="item">The item to add to the map.</param>
- void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
- {
- Add(item.Key, item.Value);
- }
-
- /// <summary>
- /// Removes all items from the map.
- /// </summary>
- public void Clear()
- {
- list.Clear();
- map.Clear();
- }
-
- /// <summary>
- /// Determines whether map contains an entry equivalent to the given key/value pair.
- /// </summary>
- /// <param name="item">The key/value pair to find.</param>
- /// <returns></returns>
- bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
- {
- TValue value;
- return TryGetValue(item.Key, out value) && ValueEqualityComparer.Equals(item.Value, value);
- }
-
- /// <summary>
- /// Copies the key/value pairs in this map to an array.
- /// </summary>
- /// <param name="array">The array to copy the entries into.</param>
- /// <param name="arrayIndex">The index of the array at which to start copying values.</param>
- void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
- {
- list.CopyTo(array, arrayIndex);
- }
-
- /// <summary>
- /// Removes the specified key/value pair from the map.
- /// </summary>
- /// <remarks>Both the key and the value must be found for the entry to be removed.</remarks>
- /// <param name="item">The key/value pair to remove.</param>
- /// <returns><c>true</c> if the key/value pair was found and removed; <c>false</c> otherwise.</returns>
- bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
- {
- if (item.Key == null)
- {
- throw new ArgumentException("Key is null", nameof(item));
- }
- LinkedListNode<KeyValuePair<TKey, TValue>> node;
- if (map.TryGetValue(item.Key, out node) &&
- EqualityComparer<TValue>.Default.Equals(item.Value, node.Value.Value))
- {
- map.Remove(item.Key);
- node.List.Remove(node);
- return true;
- }
- else
- {
- return false;
- }
- }
-
- /// <summary>
- /// Gets the number of elements contained in the map.
- /// </summary>
- public int Count { get { return list.Count; } }
-
- /// <summary>
- /// Gets a value indicating whether the map is read-only.
- /// </summary>
- public bool IsReadOnly { get { return false; } }
-
- /// <summary>
- /// Determines whether the specified <see cref="System.Object" />, is equal to this instance.
- /// </summary>
- /// <param name="other">The <see cref="System.Object" /> to compare with this instance.</param>
- /// <returns>
- /// <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
- /// </returns>
- public override bool Equals(object other)
- {
- return Equals(other as MapField<TKey, TValue>);
- }
-
- /// <summary>
- /// Returns a hash code for this instance.
- /// </summary>
- /// <returns>
- /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
- /// </returns>
- public override int GetHashCode()
- {
- var keyComparer = KeyEqualityComparer;
- var valueComparer = ValueEqualityComparer;
- int hash = 0;
- foreach (var pair in list)
- {
- hash ^= keyComparer.GetHashCode(pair.Key) * 31 + valueComparer.GetHashCode(pair.Value);
- }
- return hash;
- }
-
- /// <summary>
- /// Compares this map with another for equality.
- /// </summary>
- /// <remarks>
- /// The order of the key/value pairs in the maps is not deemed significant in this comparison.
- /// </remarks>
- /// <param name="other">The map to compare this with.</param>
- /// <returns><c>true</c> if <paramref name="other"/> refers to an equal map; <c>false</c> otherwise.</returns>
- public bool Equals(MapField<TKey, TValue> other)
- {
- if (other == null)
- {
- return false;
- }
- if (other == this)
- {
- return true;
- }
- if (other.Count != this.Count)
- {
- return false;
- }
- var valueComparer = ValueEqualityComparer;
- foreach (var pair in this)
- {
- TValue value;
- if (!other.TryGetValue(pair.Key, out value))
- {
- return false;
- }
- if (!valueComparer.Equals(value, pair.Value))
- {
- return false;
- }
- }
- return true;
- }
-
- /// <summary>
- /// Adds entries to the map from the given stream.
- /// </summary>
- /// <remarks>
- /// It is assumed that the stream is initially positioned after the tag specified by the codec.
- /// This method will continue reading entries from the stream until the end is reached, or
- /// a different tag is encountered.
- /// </remarks>
- /// <param name="input">Stream to read from</param>
- /// <param name="codec">Codec describing how the key/value pairs are encoded</param>
- public void AddEntriesFrom(CodedInputStream input, Codec codec)
- {
- var adapter = new Codec.MessageAdapter(codec);
- do
- {
- adapter.Reset();
- input.ReadMessage(adapter);
- this[adapter.Key] = adapter.Value;
- } while (input.MaybeConsumeTag(codec.MapTag));
- }
-
- /// <summary>
- /// Writes the contents of this map to the given coded output stream, using the specified codec
- /// to encode each entry.
- /// </summary>
- /// <param name="output">The output stream to write to.</param>
- /// <param name="codec">The codec to use for each entry.</param>
- public void WriteTo(CodedOutputStream output, Codec codec)
- {
- var message = new Codec.MessageAdapter(codec);
- foreach (var entry in list)
- {
- message.Key = entry.Key;
- message.Value = entry.Value;
- output.WriteTag(codec.MapTag);
- output.WriteMessage(message);
- }
- }
-
- /// <summary>
- /// Calculates the size of this map based on the given entry codec.
- /// </summary>
- /// <param name="codec">The codec to use to encode each entry.</param>
- /// <returns></returns>
- public int CalculateSize(Codec codec)
- {
- if (Count == 0)
- {
- return 0;
- }
- var message = new Codec.MessageAdapter(codec);
- int size = 0;
- foreach (var entry in list)
- {
- message.Key = entry.Key;
- message.Value = entry.Value;
- size += CodedOutputStream.ComputeRawVarint32Size(codec.MapTag);
- size += CodedOutputStream.ComputeMessageSize(message);
- }
- return size;
- }
-
- /// <summary>
- /// Returns a string representation of this repeated field, in the same
- /// way as it would be represented by the default JSON formatter.
- /// </summary>
- public override string ToString()
- {
- var writer = new StringWriter();
- JsonFormatter.Default.WriteDictionary(writer, this);
- return writer.ToString();
- }
-
- #region IDictionary explicit interface implementation
- void IDictionary.Add(object key, object value)
- {
- Add((TKey)key, (TValue)value);
- }
-
- bool IDictionary.Contains(object key)
- {
- if (!(key is TKey))
- {
- return false;
- }
- return ContainsKey((TKey)key);
- }
-
- IDictionaryEnumerator IDictionary.GetEnumerator()
- {
- return new DictionaryEnumerator(GetEnumerator());
- }
-
- void IDictionary.Remove(object key)
- {
- ProtoPreconditions.CheckNotNull(key, nameof(key));
- if (!(key is TKey))
- {
- return;
- }
- Remove((TKey)key);
- }
-
- void ICollection.CopyTo(Array array, int index)
- {
- // This is ugly and slow as heck, but with any luck it will never be used anyway.
- ICollection temp = this.Select(pair => new DictionaryEntry(pair.Key, pair.Value)).ToList();
- temp.CopyTo(array, index);
- }
-
- bool IDictionary.IsFixedSize { get { return false; } }
-
- ICollection IDictionary.Keys { get { return (ICollection)Keys; } }
-
- ICollection IDictionary.Values { get { return (ICollection)Values; } }
-
- bool ICollection.IsSynchronized { get { return false; } }
-
- object ICollection.SyncRoot { get { return this; } }
-
- object IDictionary.this[object key]
- {
- get
- {
- ProtoPreconditions.CheckNotNull(key, nameof(key));
- if (!(key is TKey))
- {
- return null;
- }
- TValue value;
- TryGetValue((TKey)key, out value);
- return value;
- }
-
- set
- {
- this[(TKey)key] = (TValue)value;
- }
- }
- #endregion
-
- #region IReadOnlyDictionary explicit interface implementation
-#if !NET35
- IEnumerable<TKey> IReadOnlyDictionary<TKey, TValue>.Keys => Keys;
-
- IEnumerable<TValue> IReadOnlyDictionary<TKey, TValue>.Values => Values;
-#endif
- #endregion
-
- private class DictionaryEnumerator : IDictionaryEnumerator
- {
- private readonly IEnumerator<KeyValuePair<TKey, TValue>> enumerator;
-
- internal DictionaryEnumerator(IEnumerator<KeyValuePair<TKey, TValue>> enumerator)
- {
- this.enumerator = enumerator;
- }
-
- public bool MoveNext()
- {
- return enumerator.MoveNext();
- }
-
- public void Reset()
- {
- enumerator.Reset();
- }
-
- public object Current { get { return Entry; } }
- public DictionaryEntry Entry { get { return new DictionaryEntry(Key, Value); } }
- public object Key { get { return enumerator.Current.Key; } }
- public object Value { get { return enumerator.Current.Value; } }
- }
-
- /// <summary>
- /// A codec for a specific map field. This contains all the information required to encode and
- /// decode the nested messages.
- /// </summary>
- public sealed class Codec
- {
- private readonly FieldCodec<TKey> keyCodec;
- private readonly FieldCodec<TValue> valueCodec;
- private readonly uint mapTag;
-
- /// <summary>
- /// Creates a new entry codec based on a separate key codec and value codec,
- /// and the tag to use for each map entry.
- /// </summary>
- /// <param name="keyCodec">The key codec.</param>
- /// <param name="valueCodec">The value codec.</param>
- /// <param name="mapTag">The map tag to use to introduce each map entry.</param>
- public Codec(FieldCodec<TKey> keyCodec, FieldCodec<TValue> valueCodec, uint mapTag)
- {
- this.keyCodec = keyCodec;
- this.valueCodec = valueCodec;
- this.mapTag = mapTag;
- }
-
- /// <summary>
- /// The tag used in the enclosing message to indicate map entries.
- /// </summary>
- internal uint MapTag { get { return mapTag; } }
-
- /// <summary>
- /// A mutable message class, used for parsing and serializing. This
- /// delegates the work to a codec, but implements the <see cref="IMessage"/> interface
- /// for interop with <see cref="CodedInputStream"/> and <see cref="CodedOutputStream"/>.
- /// This is nested inside Codec as it's tightly coupled to the associated codec,
- /// and it's simpler if it has direct access to all its fields.
- /// </summary>
- internal class MessageAdapter : IMessage
- {
- private static readonly byte[] ZeroLengthMessageStreamData = new byte[] { 0 };
-
- private readonly Codec codec;
- internal TKey Key { get; set; }
- internal TValue Value { get; set; }
-
- internal MessageAdapter(Codec codec)
- {
- this.codec = codec;
- }
-
- internal void Reset()
- {
- Key = codec.keyCodec.DefaultValue;
- Value = codec.valueCodec.DefaultValue;
- }
-
- public void MergeFrom(CodedInputStream input)
- {
- uint tag;
- while ((tag = input.ReadTag()) != 0)
- {
- if (tag == codec.keyCodec.Tag)
- {
- Key = codec.keyCodec.Read(input);
- }
- else if (tag == codec.valueCodec.Tag)
- {
- Value = codec.valueCodec.Read(input);
- }
- else
- {
- input.SkipLastField();
- }
- }
-
- // Corner case: a map entry with a key but no value, where the value type is a message.
- // Read it as if we'd seen an input stream with no data (i.e. create a "default" message).
- if (Value == null)
- {
- Value = codec.valueCodec.Read(new CodedInputStream(ZeroLengthMessageStreamData));
- }
- }
-
- public void WriteTo(CodedOutputStream output)
- {
- codec.keyCodec.WriteTagAndValue(output, Key);
- codec.valueCodec.WriteTagAndValue(output, Value);
- }
-
- public int CalculateSize()
- {
- return codec.keyCodec.CalculateSizeWithTag(Key) + codec.valueCodec.CalculateSizeWithTag(Value);
- }
-
- 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(nameof(arrayIndex));
- }
- if (arrayIndex + Count > array.Length)
- {
- throw new ArgumentException("Not enough space in the array", nameof(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(nameof(index));
- }
- if (index + Count > array.Length)
- {
- throw new ArgumentException("Not enough space in the array", nameof(array));
- }
- foreach (var item in this)
- {
- array.SetValue(item, index++);
- }
- }
- }
- }
-}
diff --git a/csharp/src/Google.Protobuf/Collections/ProtobufEqualityComparers.cs b/csharp/src/Google.Protobuf/Collections/ProtobufEqualityComparers.cs
deleted file mode 100644
index 13ef60fc..00000000
--- a/csharp/src/Google.Protobuf/Collections/ProtobufEqualityComparers.cs
+++ /dev/null
@@ -1,130 +0,0 @@
-#region Copyright notice and license
-// Protocol Buffers - Google's data interchange format
-// Copyright 2017 Google Inc. All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#endregion
-
-using System;
-using System.Collections.Generic;
-
-namespace Google.Protobuf.Collections
-{
- /// <summary>
- /// Provides a central place to implement equality comparisons, primarily for bitwise float/double equality.
- /// </summary>
- public static class ProtobufEqualityComparers
- {
- /// <summary>
- /// Returns an equality comparer for <typeparamref name="T"/> suitable for Protobuf equality comparisons.
- /// This is usually just the default equality comparer for the type, but floating point numbers are compared
- /// bitwise.
- /// </summary>
- /// <typeparam name="T">The type of equality comparer to return.</typeparam>
- /// <returns>The equality comparer.</returns>
- public static EqualityComparer<T> GetEqualityComparer<T>()
- {
- return typeof(T) == typeof(double) ? (EqualityComparer<T>) (object) BitwiseDoubleEqualityComparer
- : typeof(T) == typeof(float) ? (EqualityComparer<T>) (object) BitwiseSingleEqualityComparer
- : typeof(T) == typeof(double?) ? (EqualityComparer<T>) (object) BitwiseNullableDoubleEqualityComparer
- : typeof(T) == typeof(float?) ? (EqualityComparer<T>) (object) BitwiseNullableSingleEqualityComparer
- : EqualityComparer<T>.Default;
- }
-
- /// <summary>
- /// Returns an equality comparer suitable for comparing 64-bit floating point values, by bitwise comparison.
- /// (NaN values are considered equal, but only when they have the same representation.)
- /// </summary>
- public static EqualityComparer<double> BitwiseDoubleEqualityComparer { get; } = new BitwiseDoubleEqualityComparerImpl();
-
- /// <summary>
- /// Returns an equality comparer suitable for comparing 32-bit floating point values, by bitwise comparison.
- /// (NaN values are considered equal, but only when they have the same representation.)
- /// </summary>
- public static EqualityComparer<float> BitwiseSingleEqualityComparer { get; } = new BitwiseSingleEqualityComparerImpl();
-
- /// <summary>
- /// Returns an equality comparer suitable for comparing nullable 64-bit floating point values, by bitwise comparison.
- /// (NaN values are considered equal, but only when they have the same representation.)
- /// </summary>
- public static EqualityComparer<double?> BitwiseNullableDoubleEqualityComparer { get; } = new BitwiseNullableDoubleEqualityComparerImpl();
-
- /// <summary>
- /// Returns an equality comparer suitable for comparing nullable 32-bit floating point values, by bitwise comparison.
- /// (NaN values are considered equal, but only when they have the same representation.)
- /// </summary>
- public static EqualityComparer<float?> BitwiseNullableSingleEqualityComparer { get; } = new BitwiseNullableSingleEqualityComparerImpl();
-
- private class BitwiseDoubleEqualityComparerImpl : EqualityComparer<double>
- {
- public override bool Equals(double x, double y) =>
- BitConverter.DoubleToInt64Bits(x) == BitConverter.DoubleToInt64Bits(y);
-
- public override int GetHashCode(double obj) =>
- BitConverter.DoubleToInt64Bits(obj).GetHashCode();
- }
-
- private class BitwiseSingleEqualityComparerImpl : EqualityComparer<float>
- {
- // Just promote values to double and use BitConverter.DoubleToInt64Bits,
- // as there's no BitConverter.SingleToInt32Bits, unfortunately.
-
- public override bool Equals(float x, float y) =>
- BitConverter.DoubleToInt64Bits(x) == BitConverter.DoubleToInt64Bits(y);
-
- public override int GetHashCode(float obj) =>
- BitConverter.DoubleToInt64Bits(obj).GetHashCode();
- }
-
- private class BitwiseNullableDoubleEqualityComparerImpl : EqualityComparer<double?>
- {
- public override bool Equals(double? x, double? y) =>
- x == null && y == null ? true
- : x == null || y == null ? false
- : BitwiseDoubleEqualityComparer.Equals(x.Value, y.Value);
-
- // The hash code for null is just a constant which is at least *unlikely* to be used
- // elsewhere. (Compared with 0, say.)
- public override int GetHashCode(double? obj) =>
- obj == null ? 293864 : BitwiseDoubleEqualityComparer.GetHashCode(obj.Value);
- }
-
- private class BitwiseNullableSingleEqualityComparerImpl : EqualityComparer<float?>
- {
- public override bool Equals(float? x, float? y) =>
- x == null && y == null ? true
- : x == null || y == null ? false
- : BitwiseSingleEqualityComparer.Equals(x.Value, y.Value);
-
- // The hash code for null is just a constant which is at least *unlikely* to be used
- // elsewhere. (Compared with 0, say.)
- public override int GetHashCode(float? obj) =>
- obj == null ? 293864 : BitwiseSingleEqualityComparer.GetHashCode(obj.Value);
- }
- }
-}
diff --git a/csharp/src/Google.Protobuf/Collections/ReadOnlyDictionary.cs b/csharp/src/Google.Protobuf/Collections/ReadOnlyDictionary.cs
deleted file mode 100644
index 84360667..00000000
--- a/csharp/src/Google.Protobuf/Collections/ReadOnlyDictionary.cs
+++ /dev/null
@@ -1,147 +0,0 @@
-#region Copyright notice and license
-// Protocol Buffers - Google's data interchange format
-// Copyright 2008 Google Inc. All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#endregion
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-
-namespace Google.Protobuf.Collections
-{
- /// <summary>
- /// Read-only wrapper around another dictionary.
- /// </summary>
- internal sealed class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
- {
- private readonly IDictionary<TKey, TValue> wrapped;
-
- public ReadOnlyDictionary(IDictionary<TKey, TValue> wrapped)
- {
- this.wrapped = wrapped;
- }
-
- public void Add(TKey key, TValue value)
- {
- throw new InvalidOperationException();
- }
-
- public bool ContainsKey(TKey key)
- {
- return wrapped.ContainsKey(key);
- }
-
- public ICollection<TKey> Keys
- {
- get { return wrapped.Keys; }
- }
-
- public bool Remove(TKey key)
- {
- throw new InvalidOperationException();
- }
-
- public bool TryGetValue(TKey key, out TValue value)
- {
- return wrapped.TryGetValue(key, out value);
- }
-
- public ICollection<TValue> Values
- {
- get { return wrapped.Values; }
- }
-
- public TValue this[TKey key]
- {
- get { return wrapped[key]; }
- set { throw new InvalidOperationException(); }
- }
-
- public void Add(KeyValuePair<TKey, TValue> item)
- {
- throw new InvalidOperationException();
- }
-
- public void Clear()
- {
- throw new InvalidOperationException();
- }
-
- public bool Contains(KeyValuePair<TKey, TValue> item)
- {
- return wrapped.Contains(item);
- }
-
- public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
- {
- wrapped.CopyTo(array, arrayIndex);
- }
-
- public int Count
- {
- get { return wrapped.Count; }
- }
-
- public bool IsReadOnly
- {
- get { return true; }
- }
-
- public bool Remove(KeyValuePair<TKey, TValue> item)
- {
- throw new InvalidOperationException();
- }
-
- public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
- {
- return wrapped.GetEnumerator();
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return ((IEnumerable) wrapped).GetEnumerator();
- }
-
- public override bool Equals(object obj)
- {
- return wrapped.Equals(obj);
- }
-
- public override int GetHashCode()
- {
- return wrapped.GetHashCode();
- }
-
- public override string ToString()
- {
- return wrapped.ToString();
- }
- }
-} \ No newline at end of file
diff --git a/csharp/src/Google.Protobuf/Collections/RepeatedField.cs b/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
deleted file mode 100755
index c18b63e2..00000000
--- a/csharp/src/Google.Protobuf/Collections/RepeatedField.cs
+++ /dev/null
@@ -1,595 +0,0 @@
-#region Copyright notice and license
-// Protocol Buffers - Google's data interchange format
-// Copyright 2015 Google Inc. All rights reserved.
-// https://developers.google.com/protocol-buffers/
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#endregion
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.IO;
-
-namespace Google.Protobuf.Collections
-{
- /// <summary>
- /// The contents of a repeated field: essentially, a collection with some extra
- /// restrictions (no null values) and capabilities (deep cloning).
- /// </summary>
- /// <remarks>
- /// This implementation does not generally prohibit the use of types which are not
- /// supported by Protocol Buffers but nor does it guarantee that all operations will work in such cases.
- /// </remarks>
- /// <typeparam name="T">The element type of the repeated field.</typeparam>
- public sealed class RepeatedField<T> : IList<T>, IList, IDeepCloneable<RepeatedField<T>>, IEquatable<RepeatedField<T>>
-#if !NET35
- , IReadOnlyList<T>
-#endif
- {
- private static readonly EqualityComparer<T> EqualityComparer = ProtobufEqualityComparers.GetEqualityComparer<T>();
- private static readonly T[] EmptyArray = new T[0];
- private const int MinArraySize = 8;
-
- private T[] array = EmptyArray;
- private int count = 0;
-
- /// <summary>
- /// Creates a deep clone of this repeated field.
- /// </summary>
- /// <remarks>
- /// If the field type is
- /// a message type, each element is also cloned; otherwise, it is
- /// assumed that the field type is primitive (including string and
- /// bytes, both of which are immutable) and so a simple copy is
- /// equivalent to a deep clone.
- /// </remarks>
- /// <returns>A deep clone of this repeated field.</returns>
- public RepeatedField<T> Clone()
- {
- RepeatedField<T> clone = new RepeatedField<T>();
- if (array != EmptyArray)
- {
- clone.array = (T[])array.Clone();
- IDeepCloneable<T>[] cloneableArray = clone.array as IDeepCloneable<T>[];
- if (cloneableArray != null)
- {
- for (int i = 0; i < count; i++)
- {
- clone.array[i] = cloneableArray[i].Clone();
- }
- }
- }
- clone.count = count;
- return clone;
- }
-
- /// <summary>
- /// Adds the entries from the given input stream, decoding them with the specified codec.
- /// </summary>
- /// <param name="input">The input stream to read from.</param>
- /// <param name="codec">The codec to use in order to read each entry.</param>
- public void AddEntriesFrom(CodedInputStream input, FieldCodec<T> codec)
- {
- // TODO: Inline some of the Add code, so we can avoid checking the size on every
- // iteration.
- uint tag = input.LastTag;
- var reader = codec.ValueReader;
- // Non-nullable value types can be packed or not.
- if (FieldCodec<T>.IsPackedRepeatedField(tag))
- {
- int length = input.ReadLength();
- if (length > 0)
- {
- int oldLimit = input.PushLimit(length);
- while (!input.ReachedLimit)
- {
- Add(reader(input));
- }
- input.PopLimit(oldLimit);
- }
- // Empty packed field. Odd, but valid - just ignore.
- }
- else
- {
- // Not packed... (possibly not packable)
- do
- {
- Add(reader(input));
- } while (input.MaybeConsumeTag(tag));
- }
- }
-
- /// <summary>
- /// Calculates the size of this collection based on the given codec.
- /// </summary>
- /// <param name="codec">The codec to use when encoding each field.</param>
- /// <returns>The number of bytes that would be written to a <see cref="CodedOutputStream"/> by <see cref="WriteTo"/>,
- /// using the same codec.</returns>
- public int CalculateSize(FieldCodec<T> codec)
- {
- if (count == 0)
- {
- return 0;
- }
- uint tag = codec.Tag;
- if (codec.PackedRepeatedField)
- {
- int dataSize = CalculatePackedDataSize(codec);
- return CodedOutputStream.ComputeRawVarint32Size(tag) +
- CodedOutputStream.ComputeLengthSize(dataSize) +
- dataSize;
- }
- else
- {
- var sizeCalculator = codec.ValueSizeCalculator;
- int size = count * CodedOutputStream.ComputeRawVarint32Size(tag);
- for (int i = 0; i < count; i++)
- {
- size += sizeCalculator(array[i]);
- }
- return size;
- }
- }
-
- private int CalculatePackedDataSize(FieldCodec<T> codec)
- {
- int fixedSize = codec.FixedSize;
- if (fixedSize == 0)
- {
- var calculator = codec.ValueSizeCalculator;
- int tmp = 0;
- for (int i = 0; i < count; i++)
- {
- tmp += calculator(array[i]);
- }
- return tmp;
- }
- else
- {
- return fixedSize * Count;
- }
- }
-
- /// <summary>
- /// Writes the contents of this collection to the given <see cref="CodedOutputStream"/>,
- /// encoding each value using the specified codec.
- /// </summary>
- /// <param name="output">The output stream to write to.</param>
- /// <param name="codec">The codec to use when encoding each value.</param>
- public void WriteTo(CodedOutputStream output, FieldCodec<T> codec)
- {
- if (count == 0)
- {
- return;
- }
- var writer = codec.ValueWriter;
- var tag = codec.Tag;
- if (codec.PackedRepeatedField)
- {
- // Packed primitive type
- uint size = (uint)CalculatePackedDataSize(codec);
- output.WriteTag(tag);
- output.WriteRawVarint32(size);
- for (int i = 0; i < count; i++)
- {
- writer(output, array[i]);
- }
- }
- else
- {
- // Not packed: a simple tag/value pair for each value.
- // Can't use codec.WriteTagAndValue, as that omits default values.
- for (int i = 0; i < count; i++)
- {
- output.WriteTag(tag);
- writer(output, array[i]);
- }
- }
- }
-
- private void EnsureSize(int size)
- {
- if (array.Length < size)
- {
- size = Math.Max(size, MinArraySize);
- int newSize = Math.Max(array.Length * 2, size);
- var tmp = new T[newSize];
- Array.Copy(array, 0, tmp, 0, array.Length);
- array = tmp;
- }
- }
-
- /// <summary>
- /// Adds the specified item to the collection.
- /// </summary>
- /// <param name="item">The item to add.</param>
- public void Add(T item)
- {
- ProtoPreconditions.CheckNotNullUnconstrained(item, nameof(item));
- EnsureSize(count + 1);
- array[count++] = item;
- }
-
- /// <summary>
- /// Removes all items from the collection.
- /// </summary>
- public void Clear()
- {
- array = EmptyArray;
- count = 0;
- }
-
- /// <summary>
- /// Determines whether this collection contains the given item.
- /// </summary>
- /// <param name="item">The item to find.</param>
- /// <returns><c>true</c> if this collection contains the given item; <c>false</c> otherwise.</returns>
- public bool Contains(T item)
- {
- return IndexOf(item) != -1;
- }
-
- /// <summary>
- /// Copies this collection to the given array.
- /// </summary>
- /// <param name="array">The array to copy to.</param>
- /// <param name="arrayIndex">The first index of the array to copy to.</param>
- public void CopyTo(T[] array, int arrayIndex)
- {
- Array.Copy(this.array, 0, array, arrayIndex, count);
- }
-
- /// <summary>
- /// Removes the specified item from the collection
- /// </summary>
- /// <param name="item">The item to remove.</param>
- /// <returns><c>true</c> if the item was found and removed; <c>false</c> otherwise.</returns>
- public bool Remove(T item)
- {
- int index = IndexOf(item);
- if (index == -1)
- {
- return false;
- }
- Array.Copy(array, index + 1, array, index, count - index - 1);
- count--;
- array[count] = default(T);
- return true;
- }
-
- /// <summary>
- /// Gets the number of elements contained in the collection.
- /// </summary>
- public int Count => count;
-
- /// <summary>
- /// Gets a value indicating whether the collection is read-only.
- /// </summary>
- public bool IsReadOnly => false;
-
- /// <summary>
- /// Adds all of the specified values into this collection.
- /// </summary>
- /// <param name="values">The values to add to this collection.</param>
- public void AddRange(IEnumerable<T> values)
- {
- ProtoPreconditions.CheckNotNull(values, nameof(values));
-
- // Optimization 1: If the collection we're adding is already a RepeatedField<T>,
- // we know the values are valid.
- var otherRepeatedField = values as RepeatedField<T>;
- if (otherRepeatedField != null)
- {
- EnsureSize(count + otherRepeatedField.count);
- Array.Copy(otherRepeatedField.array, 0, array, count, otherRepeatedField.count);
- count += otherRepeatedField.count;
- return;
- }
-
- // Optimization 2: The collection is an ICollection, so we can expand
- // just once and ask the collection to copy itself into the array.
- var collection = values as ICollection;
- if (collection != null)
- {
- var extraCount = collection.Count;
- // For reference types and nullable value types, we need to check that there are no nulls
- // present. (This isn't a thread-safe approach, but we don't advertise this is thread-safe.)
- // We expect the JITter to optimize this test to true/false, so it's effectively conditional
- // specialization.
- if (default(T) == null)
- {
- // TODO: Measure whether iterating once to check and then letting the collection copy
- // itself is faster or slower than iterating and adding as we go. For large
- // collections this will not be great in terms of cache usage... but the optimized
- // copy may be significantly faster than doing it one at a time.
- foreach (var item in collection)
- {
- if (item == null)
- {
- throw new ArgumentException("Sequence contained null element", nameof(values));
- }
- }
- }
- EnsureSize(count + extraCount);
- collection.CopyTo(array, count);
- count += extraCount;
- return;
- }
-
- // We *could* check for ICollection<T> as well, but very very few collections implement
- // ICollection<T> but not ICollection. (HashSet<T> does, for one...)
-
- // Fall back to a slower path of adding items one at a time.
- foreach (T item in values)
- {
- Add(item);
- }
- }
-
- /// <summary>
- /// Adds all of the specified values into this collection. This method is present to
- /// allow repeated fields to be constructed from queries within collection initializers.
- /// Within non-collection-initializer code, consider using the equivalent <see cref="AddRange"/>
- /// method instead for clarity.
- /// </summary>
- /// <param name="values">The values to add to this collection.</param>
- public void Add(IEnumerable<T> values)
- {
- AddRange(values);
- }
-
- /// <summary>
- /// Returns an enumerator that iterates through the collection.
- /// </summary>
- /// <returns>
- /// An enumerator that can be used to iterate through the collection.
- /// </returns>
- public IEnumerator<T> GetEnumerator()
- {
- for (int i = 0; i < count; i++)
- {
- yield return array[i];
- }
- }
-
- /// <summary>
- /// Determines whether the specified <see cref="System.Object" />, is equal to this instance.
- /// </summary>
- /// <param name="obj">The <see cref="System.Object" /> to compare with this instance.</param>
- /// <returns>
- /// <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
- /// </returns>
- public override bool Equals(object obj)
- {
- return Equals(obj as RepeatedField<T>);
- }
-
- /// <summary>
- /// Returns an enumerator that iterates through a collection.
- /// </summary>
- /// <returns>
- /// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
- /// </returns>
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
-
- /// <summary>
- /// Returns a hash code for this instance.
- /// </summary>
- /// <returns>
- /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
- /// </returns>
- public override int GetHashCode()
- {
- int hash = 0;
- for (int i = 0; i < count; i++)
- {
- hash = hash * 31 + array[i].GetHashCode();
- }
- return hash;
- }
-
- /// <summary>
- /// Compares this repeated field with another for equality.
- /// </summary>
- /// <param name="other">The repeated field to compare this with.</param>
- /// <returns><c>true</c> if <paramref name="other"/> refers to an equal repeated field; <c>false</c> otherwise.</returns>
- public bool Equals(RepeatedField<T> other)
- {
- if (ReferenceEquals(other, null))
- {
- return false;
- }
- if (ReferenceEquals(other, this))
- {
- return true;
- }
- if (other.Count != this.Count)
- {
- return false;
- }
- EqualityComparer<T> comparer = EqualityComparer;
- for (int i = 0; i < count; i++)
- {
- if (!comparer.Equals(array[i], other.array[i]))
- {
- return false;
- }
- }
- return true;
- }
-
- /// <summary>
- /// Returns the index of the given item within the collection, or -1 if the item is not
- /// present.
- /// </summary>
- /// <param name="item">The item to find in the collection.</param>
- /// <returns>The zero-based index of the item, or -1 if it is not found.</returns>
- public int IndexOf(T item)
- {
- ProtoPreconditions.CheckNotNullUnconstrained(item, nameof(item));
- EqualityComparer<T> comparer = EqualityComparer;
- for (int i = 0; i < count; i++)
- {
- if (comparer.Equals(array[i], item))
- {
- return i;
- }
- }
- return -1;
- }
-
- /// <summary>
- /// Inserts the given item at the specified index.
- /// </summary>
- /// <param name="index">The index at which to insert the item.</param>
- /// <param name="item">The item to insert.</param>
- public void Insert(int index, T item)
- {
- ProtoPreconditions.CheckNotNullUnconstrained(item, nameof(item));
- if (index < 0 || index > count)
- {
- throw new ArgumentOutOfRangeException(nameof(index));
- }
- EnsureSize(count + 1);
- Array.Copy(array, index, array, index + 1, count - index);
- array[index] = item;
- count++;
- }
-
- /// <summary>
- /// Removes the item at the given index.
- /// </summary>
- /// <param name="index">The zero-based index of the item to remove.</param>
- public void RemoveAt(int index)
- {
- if (index < 0 || index >= count)
- {
- throw new ArgumentOutOfRangeException(nameof(index));
- }
- Array.Copy(array, index + 1, array, index, count - index - 1);
- count--;
- array[count] = default(T);
- }
-
- /// <summary>
- /// Returns a string representation of this repeated field, in the same
- /// way as it would be represented by the default JSON formatter.
- /// </summary>
- public override string ToString()
- {
- var writer = new StringWriter();
- JsonFormatter.Default.WriteList(writer, this);
- return writer.ToString();
- }
-
- /// <summary>
- /// Gets or sets the item at the specified index.
- /// </summary>
- /// <value>
- /// The element at the specified index.
- /// </value>
- /// <param name="index">The zero-based index of the element to get or set.</param>
- /// <returns>The item at the specified index.</returns>
- public T this[int index]
- {
- get
- {
- if (index < 0 || index >= count)
- {
- throw new ArgumentOutOfRangeException(nameof(index));
- }
- return array[index];
- }
- set
- {
- if (index < 0 || index >= count)
- {
- throw new ArgumentOutOfRangeException(nameof(index));
- }
- ProtoPreconditions.CheckNotNullUnconstrained(value, nameof(value));
- array[index] = value;
- }
- }
-
- #region Explicit interface implementation for IList and ICollection.
- bool IList.IsFixedSize => false;
-
- void ICollection.CopyTo(Array array, int index)
- {
- Array.Copy(this.array, 0, array, index, count);
- }
-
- bool ICollection.IsSynchronized => false;
-
- object ICollection.SyncRoot => this;
-
- object IList.this[int index]
- {
- get { return this[index]; }
- set { this[index] = (T)value; }
- }
-
- int IList.Add(object value)
- {
- Add((T) value);
- return count - 1;
- }
-
- bool IList.Contains(object value)
- {
- return (value is T && Contains((T)value));
- }
-
- int IList.IndexOf(object value)
- {
- if (!(value is T))
- {
- return -1;
- }
- return IndexOf((T)value);
- }
-
- void IList.Insert(int index, object value)
- {
- Insert(index, (T) value);
- }
-
- void IList.Remove(object value)
- {
- if (!(value is T))
- {
- return;
- }
- Remove((T)value);
- }
- #endregion
- }
-}