From 2346f5a01561f695a2b2ba7655359d5020105077 Mon Sep 17 00:00:00 2001 From: Carmi Grushko Date: Wed, 22 Feb 2017 16:15:07 -0500 Subject: Upgrade //third_party/protobuf to v3.2.0 with some backports from HEAD (:java_toolchain, internal_gen_well_known_protos_java) Change-Id: I54be8809f411ec8cb02203b478f699e1fccb5f62 --- .../src/Google.Protobuf/Collections/MapField.cs | 760 +++++++++++++++++++++ .../Collections/ReadOnlyDictionary.cs | 147 ++++ .../Google.Protobuf/Collections/RepeatedField.cs | 591 ++++++++++++++++ 3 files changed, 1498 insertions(+) create mode 100644 third_party/protobuf/3.2.0/csharp/src/Google.Protobuf/Collections/MapField.cs create mode 100644 third_party/protobuf/3.2.0/csharp/src/Google.Protobuf/Collections/ReadOnlyDictionary.cs create mode 100644 third_party/protobuf/3.2.0/csharp/src/Google.Protobuf/Collections/RepeatedField.cs (limited to 'third_party/protobuf/3.2.0/csharp/src/Google.Protobuf/Collections') diff --git a/third_party/protobuf/3.2.0/csharp/src/Google.Protobuf/Collections/MapField.cs b/third_party/protobuf/3.2.0/csharp/src/Google.Protobuf/Collections/MapField.cs new file mode 100644 index 0000000000..537ce261a4 --- /dev/null +++ b/third_party/protobuf/3.2.0/csharp/src/Google.Protobuf/Collections/MapField.cs @@ -0,0 +1,760 @@ +#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 +{ + /// + /// Representation of a map field in a Protocol Buffer message. + /// + /// Key type in the map. Must be a type supported by Protocol Buffer map keys. + /// Value type in the map. Must be a type supported by Protocol Buffers. + /// + /// + /// For string keys, the equality comparison is provided by . + /// + /// + /// 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. + /// + /// + /// 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 byte) but nor does it guarantee + /// that all operations will work in such cases. + /// + /// + /// The order in which entries are returned when iterating over this object is undefined, and may change + /// in future versions. + /// + /// + public sealed class MapField : IDeepCloneable>, IDictionary, IEquatable>, IDictionary + { + // TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.) + private readonly Dictionary>> map = + new Dictionary>>(); + private readonly LinkedList> list = new LinkedList>(); + + /// + /// Creates a deep clone of this object. + /// + /// + /// A deep clone of this object. + /// + public MapField Clone() + { + var clone = new MapField(); + // Keys are never cloneable. Values might be. + if (typeof(IDeepCloneable).IsAssignableFrom(typeof(TValue))) + { + foreach (var pair in list) + { + clone.Add(pair.Key, ((IDeepCloneable)pair.Value).Clone()); + } + } + else + { + // Nothing is cloneable, so we don't need to worry. + clone.Add(this); + } + return clone; + } + + /// + /// Adds the specified key/value pair to the map. + /// + /// + /// This operation fails if the key already exists in the map. To replace an existing entry, use the indexer. + /// + /// The key to add + /// The value to add. + /// The given key already exists in map. + 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; + } + + /// + /// Determines whether the specified key is present in the map. + /// + /// The key to check. + /// true if the map contains the given key; false otherwise. + public bool ContainsKey(TKey key) + { + ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key)); + return map.ContainsKey(key); + } + + private bool ContainsValue(TValue value) + { + var comparer = EqualityComparer.Default; + return list.Any(pair => comparer.Equals(pair.Value, value)); + } + + /// + /// Removes the entry identified by the given key from the map. + /// + /// The key indicating the entry to remove from the map. + /// true if the map contained the given key before the entry was removed; false otherwise. + public bool Remove(TKey key) + { + ProtoPreconditions.CheckNotNullUnconstrained(key, nameof(key)); + LinkedListNode> node; + if (map.TryGetValue(key, out node)) + { + map.Remove(key); + node.List.Remove(node); + return true; + } + else + { + return false; + } + } + + /// + /// Gets the value associated with the specified key. + /// + /// The key whose value to get. + /// 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 parameter. + /// This parameter is passed uninitialized. + /// true if the map contains an element with the specified key; otherwise, false. + public bool TryGetValue(TKey key, out TValue value) + { + LinkedListNode> node; + if (map.TryGetValue(key, out node)) + { + value = node.Value.Value; + return true; + } + else + { + value = default(TValue); + return false; + } + } + + /// + /// Gets or sets the value associated with the specified key. + /// + /// The key of the value to get or set. + /// The property is retrieved and key does not exist in the collection. + /// The value associated with the specified key. If the specified key is not found, + /// a get operation throws a , and a set operation creates a new element with the specified key. + 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> node; + var pair = new KeyValuePair(key, value); + if (map.TryGetValue(key, out node)) + { + node.Value = pair; + } + else + { + node = list.AddLast(pair); + map[key] = node; + } + } + } + + /// + /// Gets a collection containing the keys in the map. + /// + public ICollection Keys { get { return new MapView(this, pair => pair.Key, ContainsKey); } } + + /// + /// Gets a collection containing the values in the map. + /// + public ICollection Values { get { return new MapView(this, pair => pair.Value, ContainsValue); } } + + /// + /// Adds the specified entries to the map. The keys and values are not automatically cloned. + /// + /// The entries to add to the map. + public void Add(IDictionary entries) + { + ProtoPreconditions.CheckNotNull(entries, nameof(entries)); + foreach (var pair in entries) + { + Add(pair.Key, pair.Value); + } + } + + /// + /// Returns an enumerator that iterates through the collection. + /// + /// + /// An enumerator that can be used to iterate through the collection. + /// + public IEnumerator> GetEnumerator() + { + return list.GetEnumerator(); + } + + /// + /// Returns an enumerator that iterates through a collection. + /// + /// + /// An object that can be used to iterate through the collection. + /// + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// Adds the specified item to the map. + /// + /// The item to add to the map. + void ICollection>.Add(KeyValuePair item) + { + Add(item.Key, item.Value); + } + + /// + /// Removes all items from the map. + /// + public void Clear() + { + list.Clear(); + map.Clear(); + } + + /// + /// Determines whether map contains an entry equivalent to the given key/value pair. + /// + /// The key/value pair to find. + /// + bool ICollection>.Contains(KeyValuePair item) + { + TValue value; + return TryGetValue(item.Key, out value) + && EqualityComparer.Default.Equals(item.Value, value); + } + + /// + /// Copies the key/value pairs in this map to an array. + /// + /// The array to copy the entries into. + /// The index of the array at which to start copying values. + void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex) + { + list.CopyTo(array, arrayIndex); + } + + /// + /// Removes the specified key/value pair from the map. + /// + /// Both the key and the value must be found for the entry to be removed. + /// The key/value pair to remove. + /// true if the key/value pair was found and removed; false otherwise. + bool ICollection>.Remove(KeyValuePair item) + { + if (item.Key == null) + { + throw new ArgumentException("Key is null", nameof(item)); + } + LinkedListNode> node; + if (map.TryGetValue(item.Key, out node) && + EqualityComparer.Default.Equals(item.Value, node.Value.Value)) + { + map.Remove(item.Key); + node.List.Remove(node); + return true; + } + else + { + return false; + } + } + + /// + /// Gets the number of elements contained in the map. + /// + public int Count { get { return list.Count; } } + + /// + /// Gets a value indicating whether the map is read-only. + /// + public bool IsReadOnly { get { return false; } } + + /// + /// Determines whether the specified , is equal to this instance. + /// + /// The to compare with this instance. + /// + /// true if the specified is equal to this instance; otherwise, false. + /// + public override bool Equals(object other) + { + return Equals(other as MapField); + } + + /// + /// Returns a hash code for this instance. + /// + /// + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + /// + public override int GetHashCode() + { + var valueComparer = EqualityComparer.Default; + int hash = 0; + foreach (var pair in list) + { + hash ^= pair.Key.GetHashCode() * 31 + valueComparer.GetHashCode(pair.Value); + } + return hash; + } + + /// + /// Compares this map with another for equality. + /// + /// + /// The order of the key/value pairs in the maps is not deemed significant in this comparison. + /// + /// The map to compare this with. + /// true if refers to an equal map; false otherwise. + public bool Equals(MapField other) + { + if (other == null) + { + return false; + } + if (other == this) + { + return true; + } + if (other.Count != this.Count) + { + return false; + } + var valueComparer = EqualityComparer.Default; + 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; + } + + /// + /// Adds entries to the map from the given stream. + /// + /// + /// 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. + /// + /// Stream to read from + /// Codec describing how the key/value pairs are encoded + 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)); + } + + /// + /// Writes the contents of this map to the given coded output stream, using the specified codec + /// to encode each entry. + /// + /// The output stream to write to. + /// The codec to use for each entry. + 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); + } + } + + /// + /// Calculates the size of this map based on the given entry codec. + /// + /// The codec to use to encode each entry. + /// + 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; + } + + /// + /// Returns a string representation of this repeated field, in the same + /// way as it would be represented by the default JSON formatter. + /// + 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 + + private class DictionaryEnumerator : IDictionaryEnumerator + { + private readonly IEnumerator> enumerator; + + internal DictionaryEnumerator(IEnumerator> 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; } } + } + + /// + /// A codec for a specific map field. This contains all the information required to encode and + /// decode the nested messages. + /// + public sealed class Codec + { + private readonly FieldCodec keyCodec; + private readonly FieldCodec valueCodec; + private readonly uint mapTag; + + /// + /// Creates a new entry codec based on a separate key codec and value codec, + /// and the tag to use for each map entry. + /// + /// The key codec. + /// The value codec. + /// The map tag to use to introduce each map entry. + public Codec(FieldCodec keyCodec, FieldCodec valueCodec, uint mapTag) + { + this.keyCodec = keyCodec; + this.valueCodec = valueCodec; + this.mapTag = mapTag; + } + + /// + /// The tag used in the enclosing message to indicate map entries. + /// + internal uint MapTag { get { return mapTag; } } + + /// + /// A mutable message class, used for parsing and serializing. This + /// delegates the work to a codec, but implements the interface + /// for interop with and . + /// 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. + /// + 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 : ICollection, ICollection + { + private readonly MapField parent; + private readonly Func, T> projection; + private readonly Func containsCheck; + + internal MapView( + MapField parent, + Func, T> projection, + Func 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 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/third_party/protobuf/3.2.0/csharp/src/Google.Protobuf/Collections/ReadOnlyDictionary.cs b/third_party/protobuf/3.2.0/csharp/src/Google.Protobuf/Collections/ReadOnlyDictionary.cs new file mode 100644 index 0000000000..84360667d8 --- /dev/null +++ b/third_party/protobuf/3.2.0/csharp/src/Google.Protobuf/Collections/ReadOnlyDictionary.cs @@ -0,0 +1,147 @@ +#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 +{ + /// + /// Read-only wrapper around another dictionary. + /// + internal sealed class ReadOnlyDictionary : IDictionary + { + private readonly IDictionary wrapped; + + public ReadOnlyDictionary(IDictionary 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 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 Values + { + get { return wrapped.Values; } + } + + public TValue this[TKey key] + { + get { return wrapped[key]; } + set { throw new InvalidOperationException(); } + } + + public void Add(KeyValuePair item) + { + throw new InvalidOperationException(); + } + + public void Clear() + { + throw new InvalidOperationException(); + } + + public bool Contains(KeyValuePair item) + { + return wrapped.Contains(item); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + wrapped.CopyTo(array, arrayIndex); + } + + public int Count + { + get { return wrapped.Count; } + } + + public bool IsReadOnly + { + get { return true; } + } + + public bool Remove(KeyValuePair item) + { + throw new InvalidOperationException(); + } + + public IEnumerator> 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/third_party/protobuf/3.2.0/csharp/src/Google.Protobuf/Collections/RepeatedField.cs b/third_party/protobuf/3.2.0/csharp/src/Google.Protobuf/Collections/RepeatedField.cs new file mode 100644 index 0000000000..7bb5644801 --- /dev/null +++ b/third_party/protobuf/3.2.0/csharp/src/Google.Protobuf/Collections/RepeatedField.cs @@ -0,0 +1,591 @@ +#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 +{ + /// + /// The contents of a repeated field: essentially, a collection with some extra + /// restrictions (no null values) and capabilities (deep cloning). + /// + /// + /// 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. + /// + /// The element type of the repeated field. + public sealed class RepeatedField : IList, IList, IDeepCloneable>, IEquatable> + { + private static readonly T[] EmptyArray = new T[0]; + private const int MinArraySize = 8; + + private T[] array = EmptyArray; + private int count = 0; + + /// + /// Creates a deep clone of this repeated field. + /// + /// + /// 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. + /// + /// A deep clone of this repeated field. + public RepeatedField Clone() + { + RepeatedField clone = new RepeatedField(); + if (array != EmptyArray) + { + clone.array = (T[])array.Clone(); + IDeepCloneable[] cloneableArray = clone.array as IDeepCloneable[]; + if (cloneableArray != null) + { + for (int i = 0; i < count; i++) + { + clone.array[i] = cloneableArray[i].Clone(); + } + } + } + clone.count = count; + return clone; + } + + /// + /// Adds the entries from the given input stream, decoding them with the specified codec. + /// + /// The input stream to read from. + /// The codec to use in order to read each entry. + public void AddEntriesFrom(CodedInputStream input, FieldCodec 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.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)); + } + } + + /// + /// Calculates the size of this collection based on the given codec. + /// + /// The codec to use when encoding each field. + /// The number of bytes that would be written to a by , + /// using the same codec. + public int CalculateSize(FieldCodec 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 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; + } + } + + /// + /// Writes the contents of this collection to the given , + /// encoding each value using the specified codec. + /// + /// The output stream to write to. + /// The codec to use when encoding each value. + public void WriteTo(CodedOutputStream output, FieldCodec 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; + } + } + + /// + /// Adds the specified item to the collection. + /// + /// The item to add. + public void Add(T item) + { + ProtoPreconditions.CheckNotNullUnconstrained(item, nameof(item)); + EnsureSize(count + 1); + array[count++] = item; + } + + /// + /// Removes all items from the collection. + /// + public void Clear() + { + array = EmptyArray; + count = 0; + } + + /// + /// Determines whether this collection contains the given item. + /// + /// The item to find. + /// true if this collection contains the given item; false otherwise. + public bool Contains(T item) + { + return IndexOf(item) != -1; + } + + /// + /// Copies this collection to the given array. + /// + /// The array to copy to. + /// The first index of the array to copy to. + public void CopyTo(T[] array, int arrayIndex) + { + Array.Copy(this.array, 0, array, arrayIndex, count); + } + + /// + /// Removes the specified item from the collection + /// + /// The item to remove. + /// true if the item was found and removed; false otherwise. + 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; + } + + /// + /// Gets the number of elements contained in the collection. + /// + public int Count => count; + + /// + /// Gets a value indicating whether the collection is read-only. + /// + public bool IsReadOnly => false; + + /// + /// Adds all of the specified values into this collection. + /// + /// The values to add to this collection. + public void AddRange(IEnumerable values) + { + ProtoPreconditions.CheckNotNull(values, nameof(values)); + + // Optimization 1: If the collection we're adding is already a RepeatedField, + // we know the values are valid. + var otherRepeatedField = values as RepeatedField; + 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 as well, but very very few collections implement + // ICollection but not ICollection. (HashSet does, for one...) + + // Fall back to a slower path of adding items one at a time. + foreach (T item in values) + { + Add(item); + } + } + + /// + /// 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 + /// method instead for clarity. + /// + /// The values to add to this collection. + public void Add(IEnumerable values) + { + AddRange(values); + } + + /// + /// Returns an enumerator that iterates through the collection. + /// + /// + /// An enumerator that can be used to iterate through the collection. + /// + public IEnumerator GetEnumerator() + { + for (int i = 0; i < count; i++) + { + yield return array[i]; + } + } + + /// + /// Determines whether the specified , is equal to this instance. + /// + /// The to compare with this instance. + /// + /// true if the specified is equal to this instance; otherwise, false. + /// + public override bool Equals(object obj) + { + return Equals(obj as RepeatedField); + } + + /// + /// Returns an enumerator that iterates through a collection. + /// + /// + /// An object that can be used to iterate through the collection. + /// + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// Returns a hash code for this instance. + /// + /// + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + /// + public override int GetHashCode() + { + int hash = 0; + for (int i = 0; i < count; i++) + { + hash = hash * 31 + array[i].GetHashCode(); + } + return hash; + } + + /// + /// Compares this repeated field with another for equality. + /// + /// The repeated field to compare this with. + /// true if refers to an equal repeated field; false otherwise. + public bool Equals(RepeatedField other) + { + if (ReferenceEquals(other, null)) + { + return false; + } + if (ReferenceEquals(other, this)) + { + return true; + } + if (other.Count != this.Count) + { + return false; + } + EqualityComparer comparer = EqualityComparer.Default; + for (int i = 0; i < count; i++) + { + if (!comparer.Equals(array[i], other.array[i])) + { + return false; + } + } + return true; + } + + /// + /// Returns the index of the given item within the collection, or -1 if the item is not + /// present. + /// + /// The item to find in the collection. + /// The zero-based index of the item, or -1 if it is not found. + public int IndexOf(T item) + { + ProtoPreconditions.CheckNotNullUnconstrained(item, nameof(item)); + EqualityComparer comparer = EqualityComparer.Default; + for (int i = 0; i < count; i++) + { + if (comparer.Equals(array[i], item)) + { + return i; + } + } + return -1; + } + + /// + /// Inserts the given item at the specified index. + /// + /// The index at which to insert the item. + /// The item to insert. + 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++; + } + + /// + /// Removes the item at the given index. + /// + /// The zero-based index of the item to remove. + 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); + } + + /// + /// Returns a string representation of this repeated field, in the same + /// way as it would be represented by the default JSON formatter. + /// + public override string ToString() + { + var writer = new StringWriter(); + JsonFormatter.Default.WriteList(writer, this); + return writer.ToString(); + } + + /// + /// Gets or sets the item at the specified index. + /// + /// + /// The element at the specified index. + /// + /// The zero-based index of the element to get or set. + /// The item at the specified index. + 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 + } +} -- cgit v1.2.3