You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
772 lines
32 KiB
772 lines
32 KiB
#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.
|
|
#End Region
|
|
|
|
Imports Google.Protobuf.Reflection
|
|
Imports Microsoft.VisualBasic.Language
|
|
Imports System
|
|
Imports System.Collections
|
|
Imports System.Collections.Generic
|
|
Imports System.IO
|
|
Imports System.Linq
|
|
Imports System.Runtime.InteropServices
|
|
|
|
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 NotInheritable Class MapField(Of TKey, TValue)
|
|
Implements IDeepCloneable(Of MapField(Of TKey, TValue)), IDictionary(Of TKey, TValue), IEquatable(Of MapField(Of TKey, TValue)), IDictionary
|
|
' TODO: Don't create the map/list until we have an entry. (Assume many maps will be empty.)
|
|
Private ReadOnly map As Dictionary(Of TKey, LinkedListNode(Of KeyValuePair(Of TKey, TValue))) = New Dictionary(Of TKey, LinkedListNode(Of KeyValuePair(Of TKey, TValue)))()
|
|
Private ReadOnly list As LinkedList(Of KeyValuePair(Of TKey, TValue)) = New LinkedList(Of KeyValuePair(Of TKey, TValue))()
|
|
|
|
''' <summary>
|
|
''' Creates a deep clone of this object.
|
|
''' </summary>
|
|
''' <returns>
|
|
''' A deep clone of this object.
|
|
''' </returns>
|
|
Public Function Clone() As MapField(Of TKey, TValue) Implements IDeepCloneable(Of MapField(Of TKey, TValue)).Clone
|
|
Dim lClone = New MapField(Of TKey, TValue)()
|
|
' Keys are never cloneable. Values might be.
|
|
If GetType(IDeepCloneable(Of TValue)).IsAssignableFrom(GetType(TValue)) Then
|
|
For Each pair In list
|
|
lClone.Add(pair.Key, CType(pair.Value, IDeepCloneable(Of TValue)).Clone())
|
|
Next
|
|
Else
|
|
' Nothing is cloneable, so we don't need to worry.
|
|
lClone.Add(Me)
|
|
End If
|
|
|
|
Return lClone
|
|
End Function
|
|
|
|
''' <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 Sub Add(key As TKey, value As TValue) Implements IDictionary(Of TKey, TValue).Add
|
|
' Validation of arguments happens in ContainsKey and the indexer
|
|
If ContainsKey(key) Then
|
|
Throw New ArgumentException("Key already exists in map", NameOf(key))
|
|
End If
|
|
|
|
Me(key) = value
|
|
End Sub
|
|
|
|
''' <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 Function ContainsKey(key As TKey) As Boolean Implements IDictionary(Of TKey, TValue).ContainsKey
|
|
CheckNotNullUnconstrained(key, NameOf(key))
|
|
Return map.ContainsKey(key)
|
|
End Function
|
|
|
|
Private Function ContainsValue(value As TValue) As Boolean
|
|
Dim comparer = EqualityComparer(Of TValue).Default
|
|
Return list.Any(Function(pair) comparer.Equals(pair.Value, value))
|
|
End Function
|
|
|
|
''' <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 Function Remove(key As TKey) As Boolean Implements IDictionary(Of TKey, TValue).Remove
|
|
CheckNotNullUnconstrained(key, NameOf(key))
|
|
Dim node As LinkedListNode(Of KeyValuePair(Of TKey, TValue))
|
|
|
|
If map.TryGetValue(key, node) Then
|
|
map.Remove(key)
|
|
node.List.Remove(node)
|
|
Return True
|
|
Else
|
|
Return False
|
|
End If
|
|
End Function
|
|
|
|
''' <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 <paramrefname="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 Function TryGetValue(key As TKey, <Out> ByRef value As TValue) As Boolean Implements IDictionary(Of TKey, TValue).TryGetValue
|
|
Dim node As LinkedListNode(Of KeyValuePair(Of TKey, TValue))
|
|
|
|
If map.TryGetValue(key, node) Then
|
|
value = node.Value.Value
|
|
Return True
|
|
Else
|
|
value = Nothing
|
|
Return False
|
|
End If
|
|
End Function
|
|
|
|
''' <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>
|
|
Default Public Property Item(key As TKey) As TValue Implements IDictionary(Of TKey, TValue).Item
|
|
Get
|
|
CheckNotNullUnconstrained(key, NameOf(key))
|
|
Dim value As TValue
|
|
|
|
If TryGetValue(key, value) Then
|
|
Return value
|
|
End If
|
|
|
|
Throw New KeyNotFoundException()
|
|
End Get
|
|
Set(value As TValue)
|
|
CheckNotNullUnconstrained(key, NameOf(key))
|
|
' value == null check here is redundant, but avoids boxing.
|
|
If value Is Nothing Then
|
|
CheckNotNullUnconstrained(value, NameOf(value))
|
|
End If
|
|
|
|
Dim node As LinkedListNode(Of KeyValuePair(Of TKey, TValue))
|
|
Dim pair = New KeyValuePair(Of TKey, TValue)(key, value)
|
|
|
|
If map.TryGetValue(key, node) Then
|
|
node.Value = pair
|
|
Else
|
|
node = list.AddLast(pair)
|
|
map(key) = node
|
|
End If
|
|
End Set
|
|
End Property
|
|
|
|
''' <summary>
|
|
''' Gets a collection containing the keys in the map.
|
|
''' </summary>
|
|
Public ReadOnly Property KeysProp As ICollection(Of TKey) Implements IDictionary(Of TKey, TValue).Keys
|
|
Get
|
|
Return New MapView(Of TKey)(Me, Function(pair) pair.Key, AddressOf ContainsKey)
|
|
End Get
|
|
End Property
|
|
|
|
''' <summary>
|
|
''' Gets a collection containing the values in the map.
|
|
''' </summary>
|
|
Public ReadOnly Property ValuesProp As ICollection(Of TValue) Implements IDictionary(Of TKey, TValue).Values
|
|
Get
|
|
Return New MapView(Of TValue)(Me, Function(pair) pair.Value, AddressOf ContainsValue)
|
|
End Get
|
|
End Property
|
|
|
|
''' <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 Sub Add(entries As IDictionary(Of TKey, TValue))
|
|
CheckNotNull(entries, NameOf(entries))
|
|
|
|
For Each pair In entries
|
|
Add(pair.Key, pair.Value)
|
|
Next
|
|
End Sub
|
|
|
|
''' <summary>
|
|
''' Returns an enumerator that iterates through the collection.
|
|
''' </summary>
|
|
''' <returns>
|
|
''' An enumerator that can be used to iterate through the collection.
|
|
''' </returns>
|
|
Public Function GetEnumerator() As IEnumerator(Of KeyValuePair(Of TKey, TValue)) Implements IEnumerable(Of KeyValuePair(Of TKey, TValue)).GetEnumerator
|
|
Return list.GetEnumerator()
|
|
End Function
|
|
|
|
''' <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>
|
|
Private Function GetEnumerator1() As IEnumerator Implements IEnumerable.GetEnumerator
|
|
Return GetEnumerator()
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Adds the specified item to the map.
|
|
''' </summary>
|
|
''' <param name="item">The item to add to the map.</param>
|
|
Private Sub Add1(item As KeyValuePair(Of TKey, TValue)) Implements ICollection(Of KeyValuePair(Of TKey, TValue)).Add
|
|
Add(item.Key, item.Value)
|
|
End Sub
|
|
|
|
''' <summary>
|
|
''' Removes all items from the map.
|
|
''' </summary>
|
|
Public Sub Clear() Implements ICollection(Of KeyValuePair(Of TKey, TValue)).Clear, IDictionary.Clear
|
|
list.Clear()
|
|
map.Clear()
|
|
End Sub
|
|
|
|
''' <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>
|
|
Private Function Contains1(item As KeyValuePair(Of TKey, TValue)) As Boolean Implements ICollection(Of KeyValuePair(Of TKey, TValue)).Contains
|
|
Dim value As TValue
|
|
Return TryGetValue(item.Key, value) AndAlso EqualityComparer(Of TValue).Default.Equals(item.Value, value)
|
|
End Function
|
|
|
|
''' <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>
|
|
Private Sub CopyTo1(array As KeyValuePair(Of TKey, TValue)(), arrayIndex As Integer) Implements ICollection(Of KeyValuePair(Of TKey, TValue)).CopyTo
|
|
list.CopyTo(array, arrayIndex)
|
|
End Sub
|
|
|
|
''' <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>
|
|
Private Function Remove1(item As KeyValuePair(Of TKey, TValue)) As Boolean Implements ICollection(Of KeyValuePair(Of TKey, TValue)).Remove
|
|
If item.Key Is Nothing Then
|
|
Throw New ArgumentException("Key is null", NameOf(item))
|
|
End If
|
|
|
|
Dim node As LinkedListNode(Of KeyValuePair(Of TKey, TValue))
|
|
|
|
If map.TryGetValue(item.Key, node) AndAlso EqualityComparer(Of TValue).Default.Equals(item.Value, node.Value.Value) Then
|
|
map.Remove(item.Key)
|
|
node.List.Remove(node)
|
|
Return True
|
|
Else
|
|
Return False
|
|
End If
|
|
End Function
|
|
|
|
''' <summary>
|
|
''' Gets the number of elements contained in the map.
|
|
''' </summary>
|
|
Public ReadOnly Property Count As Integer Implements ICollection(Of KeyValuePair(Of TKey, TValue)).Count, ICollection.Count
|
|
Get
|
|
Return list.Count
|
|
End Get
|
|
End Property
|
|
|
|
''' <summary>
|
|
''' Gets a value indicating whether the map is read-only.
|
|
''' </summary>
|
|
Public ReadOnly Property IsReadOnly As Boolean Implements ICollection(Of KeyValuePair(Of TKey, TValue)).IsReadOnly, IDictionary.IsReadOnly
|
|
Get
|
|
Return False
|
|
End Get
|
|
End Property
|
|
|
|
''' <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 Overrides Function Equals(other As Object) As Boolean
|
|
Return Equals(TryCast(other, MapField(Of TKey, TValue)))
|
|
End Function
|
|
|
|
''' <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 Overrides Function GetHashCode() As Integer
|
|
Dim valueComparer = EqualityComparer(Of TValue).Default
|
|
Dim hash = 0
|
|
|
|
For Each pair In list
|
|
hash = hash Xor pair.Key.GetHashCode() * 31 + valueComparer.GetHashCode(pair.Value)
|
|
Next
|
|
|
|
Return hash
|
|
End Function
|
|
|
|
''' <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 <paramrefname="other"/> refers to an equal map; <c>false</c> otherwise.</returns>
|
|
Public Overloads Function Equals(other As MapField(Of TKey, TValue)) As Boolean Implements IEquatable(Of MapField(Of TKey, TValue)).Equals
|
|
If other Is Nothing Then
|
|
Return False
|
|
End If
|
|
|
|
If other Is Me Then
|
|
Return True
|
|
End If
|
|
|
|
If other.Count <> Count Then
|
|
Return False
|
|
End If
|
|
|
|
Dim valueComparer = EqualityComparer(Of TValue).Default
|
|
|
|
For Each pair In Me
|
|
Dim value As TValue
|
|
|
|
If Not other.TryGetValue(pair.Key, value) Then
|
|
Return False
|
|
End If
|
|
|
|
If Not valueComparer.Equals(value, pair.Value) Then
|
|
Return False
|
|
End If
|
|
Next
|
|
|
|
Return True
|
|
End Function
|
|
|
|
''' <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 Sub AddEntriesFrom(input As CodedInputStream, codec As Codec)
|
|
Dim adapter = New Codec.MessageAdapter(codec)
|
|
|
|
Do
|
|
adapter.Reset()
|
|
input.ReadMessage(adapter)
|
|
Me(adapter.Key) = adapter.Value
|
|
Loop While input.MaybeConsumeTag(codec.MapTag)
|
|
End Sub
|
|
|
|
''' <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 Sub WriteTo(output As CodedOutputStream, codec As Codec)
|
|
Dim message = New Codec.MessageAdapter(codec)
|
|
|
|
For Each entry In list
|
|
message.Key = entry.Key
|
|
message.Value = entry.Value
|
|
output.WriteTag(codec.MapTag)
|
|
output.WriteMessage(message)
|
|
Next
|
|
End Sub
|
|
|
|
''' <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 Function CalculateSize(codec As Codec) As Integer
|
|
If Count = 0 Then
|
|
Return 0
|
|
End If
|
|
|
|
Dim message = New Codec.MessageAdapter(codec)
|
|
Dim size = 0
|
|
|
|
For Each entry In list
|
|
message.Key = entry.Key
|
|
message.Value = entry.Value
|
|
size += CodedOutputStream.ComputeRawVarint32Size(codec.MapTag)
|
|
size += CodedOutputStream.ComputeMessageSize(message)
|
|
Next
|
|
|
|
Return size
|
|
End Function
|
|
|
|
''' <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 Overrides Function ToString() As String
|
|
Dim writer = New StringWriter()
|
|
JsonFormatter.Default.WriteDictionary(writer, Me)
|
|
Return writer.ToString()
|
|
End Function
|
|
|
|
#Region "IDictionary explicit interface implementation"
|
|
Private Sub Add2(key As Object, value As Object) Implements IDictionary.Add
|
|
Add(key, value)
|
|
End Sub
|
|
|
|
Private Function Contains2(key As Object) As Boolean Implements IDictionary.Contains
|
|
If Not (TypeOf key Is TKey) Then
|
|
Return False
|
|
End If
|
|
|
|
Return ContainsKey(key)
|
|
End Function
|
|
|
|
Private Function GetEnumerator2() As IDictionaryEnumerator Implements IDictionary.GetEnumerator
|
|
Return New DictionaryEnumerator(GetEnumerator())
|
|
End Function
|
|
|
|
Private Sub Remove2(key As Object) Implements IDictionary.Remove
|
|
CheckNotNull(key, NameOf(key))
|
|
|
|
If Not (TypeOf key Is TKey) Then
|
|
Return
|
|
End If
|
|
|
|
Remove(key)
|
|
End Sub
|
|
|
|
Private Sub CopyTo2(array As Array, index As Integer) Implements ICollection.CopyTo
|
|
' This is ugly and slow as heck, but with any luck it will never be used anyway.
|
|
Dim temp As ICollection = [Select](Function(pair) New DictionaryEntry(pair.Key, pair.Value)).ToList()
|
|
temp.CopyTo(array, index)
|
|
End Sub
|
|
|
|
Private ReadOnly Property IsFixedSize As Boolean Implements IDictionary.IsFixedSize
|
|
Get
|
|
Return False
|
|
End Get
|
|
End Property
|
|
|
|
Private ReadOnly Property Keys As ICollection Implements IDictionary.Keys
|
|
Get
|
|
Return CType(KeysProp, ICollection)
|
|
End Get
|
|
End Property
|
|
|
|
Private ReadOnly Property Values As ICollection Implements IDictionary.Values
|
|
Get
|
|
Return CType(ValuesProp, ICollection)
|
|
End Get
|
|
End Property
|
|
|
|
Private ReadOnly Property IsSynchronized As Boolean Implements ICollection.IsSynchronized
|
|
Get
|
|
Return False
|
|
End Get
|
|
End Property
|
|
|
|
Private ReadOnly Property SyncRoot As Object Implements ICollection.SyncRoot
|
|
Get
|
|
Return Me
|
|
End Get
|
|
End Property
|
|
|
|
Private Property Item1(key As Object) As Object Implements IDictionary.Item
|
|
Get
|
|
CheckNotNull(key, NameOf(key))
|
|
|
|
If Not (TypeOf key Is TKey) Then
|
|
Return Nothing
|
|
End If
|
|
|
|
Dim value As TValue
|
|
TryGetValue(key, value)
|
|
Return value
|
|
End Get
|
|
Set(value As Object)
|
|
Me(key) = CType(value, TValue)
|
|
End Set
|
|
End Property
|
|
#End Region
|
|
|
|
Private Class DictionaryEnumerator
|
|
Implements IDictionaryEnumerator
|
|
|
|
Private ReadOnly enumerator As IEnumerator(Of KeyValuePair(Of TKey, TValue))
|
|
|
|
Friend Sub New(enumerator As IEnumerator(Of KeyValuePair(Of TKey, TValue)))
|
|
Me.enumerator = enumerator
|
|
End Sub
|
|
|
|
Public Function MoveNext() As Boolean Implements IEnumerator.MoveNext
|
|
Return enumerator.MoveNext()
|
|
End Function
|
|
|
|
Public Sub Reset() Implements IEnumerator.Reset
|
|
enumerator.Reset()
|
|
End Sub
|
|
|
|
Public ReadOnly Property Current As Object Implements IEnumerator.Current
|
|
Get
|
|
Return Entry
|
|
End Get
|
|
End Property
|
|
|
|
Public ReadOnly Property Entry As DictionaryEntry Implements IDictionaryEnumerator.Entry
|
|
Get
|
|
Return New DictionaryEntry(Key, Value)
|
|
End Get
|
|
End Property
|
|
|
|
Public ReadOnly Property Key As Object Implements IDictionaryEnumerator.Key
|
|
Get
|
|
Return enumerator.Current.Key
|
|
End Get
|
|
End Property
|
|
|
|
Public ReadOnly Property Value As Object Implements IDictionaryEnumerator.Value
|
|
Get
|
|
Return enumerator.Current.Value
|
|
End Get
|
|
End Property
|
|
End Class
|
|
|
|
''' <summary>
|
|
''' A codec for a specific map field. This contains all the information required to encode and
|
|
''' decode the nested messages.
|
|
''' </summary>
|
|
Public NotInheritable Class Codec
|
|
Private ReadOnly keyCodec As FieldCodecType(Of TKey)
|
|
Private ReadOnly valueCodec As FieldCodecType(Of TValue)
|
|
Private ReadOnly mapTagField As UInteger
|
|
|
|
''' <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 Sub New(keyCodec As FieldCodecType(Of TKey), valueCodec As FieldCodecType(Of TValue), mapTag As UInteger)
|
|
Me.keyCodec = keyCodec
|
|
Me.valueCodec = valueCodec
|
|
mapTagField = mapTag
|
|
End Sub
|
|
|
|
''' <summary>
|
|
''' The tag used in the enclosing message to indicate map entries.
|
|
''' </summary>
|
|
Friend ReadOnly Property MapTag As UInteger
|
|
Get
|
|
Return mapTagField
|
|
End Get
|
|
End Property
|
|
|
|
''' <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>
|
|
Friend Class MessageAdapter
|
|
Implements IMessage
|
|
|
|
Private Shared ReadOnly ZeroLengthMessageStreamData As Byte() = New Byte() {0}
|
|
Private ReadOnly codec As Codec
|
|
Friend Property Key As TKey
|
|
Friend Property Value As TValue
|
|
|
|
Friend Sub New(codec As Codec)
|
|
Me.codec = codec
|
|
End Sub
|
|
|
|
Friend Sub Reset()
|
|
Key = codec.keyCodec.DefaultValue
|
|
Value = codec.valueCodec.DefaultValue
|
|
End Sub
|
|
|
|
Public Sub MergeFrom(input As CodedInputStream) Implements IMessage.MergeFrom
|
|
Dim tag As New Value(Of UInteger)
|
|
|
|
While ((tag = input.ReadTag())) <> 0
|
|
|
|
If tag.Value = codec.keyCodec.Tag Then
|
|
Key = codec.keyCodec.Read(input)
|
|
ElseIf tag.Value = codec.valueCodec.Tag Then
|
|
Value = codec.valueCodec.Read(input)
|
|
Else
|
|
input.SkipLastField()
|
|
End If
|
|
End While
|
|
|
|
' 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 Is Nothing Then
|
|
Value = codec.valueCodec.Read(New CodedInputStream(ZeroLengthMessageStreamData))
|
|
End If
|
|
End Sub
|
|
|
|
Public Sub WriteTo(output As CodedOutputStream) Implements IMessage.WriteTo
|
|
codec.keyCodec.WriteTagAndValue(output, Key)
|
|
codec.valueCodec.WriteTagAndValue(output, Value)
|
|
End Sub
|
|
|
|
Public Function CalculateSize() As Integer Implements IMessage.CalculateSize
|
|
Return codec.keyCodec.CalculateSizeWithTag(Key) + codec.valueCodec.CalculateSizeWithTag(Value)
|
|
End Function
|
|
|
|
Private ReadOnly Property Descriptor As MessageDescriptor Implements IMessage.Descriptor
|
|
Get
|
|
Return Nothing
|
|
End Get
|
|
End Property
|
|
End Class
|
|
End Class
|
|
|
|
Private Class MapView(Of T)
|
|
Implements ICollection(Of T), ICollection
|
|
|
|
Private ReadOnly parent As MapField(Of TKey, TValue)
|
|
Private ReadOnly projection As Func(Of KeyValuePair(Of TKey, TValue), T)
|
|
Private ReadOnly containsCheck As Func(Of T, Boolean)
|
|
|
|
Friend Sub New(parent As MapField(Of TKey, TValue), projection As Func(Of KeyValuePair(Of TKey, TValue), T), containsCheck As Func(Of T, Boolean))
|
|
Me.parent = parent
|
|
Me.projection = projection
|
|
Me.containsCheck = containsCheck
|
|
End Sub
|
|
|
|
Public ReadOnly Property Count As Integer Implements ICollection(Of T).Count, ICollection.Count
|
|
Get
|
|
Return parent.Count
|
|
End Get
|
|
End Property
|
|
|
|
Public ReadOnly Property IsReadOnly As Boolean Implements ICollection(Of T).IsReadOnly
|
|
Get
|
|
Return True
|
|
End Get
|
|
End Property
|
|
|
|
Public ReadOnly Property IsSynchronized As Boolean Implements ICollection.IsSynchronized
|
|
Get
|
|
Return False
|
|
End Get
|
|
End Property
|
|
|
|
Public ReadOnly Property SyncRoot As Object Implements ICollection.SyncRoot
|
|
Get
|
|
Return parent
|
|
End Get
|
|
End Property
|
|
|
|
Public Sub Add(item As T) Implements ICollection(Of T).Add
|
|
Throw New NotSupportedException()
|
|
End Sub
|
|
|
|
Public Sub Clear() Implements ICollection(Of T).Clear
|
|
Throw New NotSupportedException()
|
|
End Sub
|
|
|
|
Public Function Contains(item As T) As Boolean Implements ICollection(Of T).Contains
|
|
Return containsCheck(item)
|
|
End Function
|
|
|
|
Public Sub CopyTo(array As T(), arrayIndex As Integer) Implements ICollection(Of T).CopyTo
|
|
If arrayIndex < 0 Then
|
|
Throw New ArgumentOutOfRangeException(NameOf(arrayIndex))
|
|
End If
|
|
|
|
If arrayIndex + Count >= array.Length Then
|
|
Throw New ArgumentException("Not enough space in the array", NameOf(array))
|
|
End If
|
|
|
|
For Each item As T In Me
|
|
array(Math.Min(Threading.Interlocked.Increment(arrayIndex), arrayIndex - 1)) = item
|
|
Next
|
|
End Sub
|
|
|
|
Public Function GetEnumerator() As IEnumerator(Of T) Implements IEnumerable(Of T).GetEnumerator
|
|
Return Enumerable.Select(parent.list, projection).GetEnumerator()
|
|
End Function
|
|
|
|
Public Function Remove(item As T) As Boolean Implements ICollection(Of T).Remove
|
|
Throw New NotSupportedException()
|
|
End Function
|
|
|
|
Private Function GetEnumerator3() As IEnumerator Implements IEnumerable.GetEnumerator
|
|
Return GetEnumerator()
|
|
End Function
|
|
|
|
Public Sub CopyTo(array As Array, index As Integer) Implements ICollection.CopyTo
|
|
If index < 0 Then
|
|
Throw New ArgumentOutOfRangeException(NameOf(index))
|
|
End If
|
|
|
|
If index + Count >= array.Length Then
|
|
Throw New ArgumentException("Not enough space in the array", NameOf(array))
|
|
End If
|
|
|
|
For Each item As T In Me
|
|
array.SetValue(item, Math.Min(Threading.Interlocked.Increment(index), index - 1))
|
|
Next
|
|
End Sub
|
|
End Class
|
|
End Class
|
|
End Namespace
|