mirror of
https://github.com/microsoft/HybridRow.git
synced 2026-01-23 19:33:16 +00:00
Copied dotnet code from CosmosDB repository
This commit is contained in:
635
dotnet/src/HybridRowGenerator/HybridRowValueGenerator.cs
Normal file
635
dotnet/src/HybridRowGenerator/HybridRowValueGenerator.cs
Normal file
@@ -0,0 +1,635 @@
|
||||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
#pragma warning disable SA1137 // Elements should have the same indentation
|
||||
|
||||
namespace Microsoft.Azure.Cosmos.Serialization.HybridRowGenerator
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.Azure.Cosmos.Core;
|
||||
using Microsoft.Azure.Cosmos.Core.Utf8;
|
||||
using Microsoft.Azure.Cosmos.Serialization.HybridRow;
|
||||
using Microsoft.Azure.Cosmos.Serialization.HybridRow.Layouts;
|
||||
using Microsoft.Azure.Cosmos.Serialization.HybridRow.Schemas;
|
||||
|
||||
public class HybridRowValueGenerator
|
||||
{
|
||||
private readonly RandomGenerator rand;
|
||||
private readonly HybridRowGeneratorConfig config;
|
||||
|
||||
public HybridRowValueGenerator(RandomGenerator rand, HybridRowGeneratorConfig config)
|
||||
{
|
||||
this.rand = rand;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public static bool DynamicTypeArgumentEquals(LayoutResolver resolver, object left, object right, TypeArgument typeArg)
|
||||
{
|
||||
if (object.ReferenceEquals(left, null))
|
||||
{
|
||||
return object.ReferenceEquals(null, right);
|
||||
}
|
||||
|
||||
if (object.ReferenceEquals(null, right))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (typeArg.Type.LayoutCode)
|
||||
{
|
||||
case LayoutCode.Null:
|
||||
case LayoutCode.Boolean:
|
||||
case LayoutCode.Int8:
|
||||
case LayoutCode.Int16:
|
||||
case LayoutCode.Int32:
|
||||
case LayoutCode.Int64:
|
||||
case LayoutCode.UInt8:
|
||||
case LayoutCode.UInt16:
|
||||
case LayoutCode.UInt32:
|
||||
case LayoutCode.UInt64:
|
||||
case LayoutCode.VarInt:
|
||||
case LayoutCode.VarUInt:
|
||||
case LayoutCode.Float32:
|
||||
case LayoutCode.Float64:
|
||||
case LayoutCode.Float128:
|
||||
case LayoutCode.Decimal:
|
||||
case LayoutCode.DateTime:
|
||||
case LayoutCode.UnixDateTime:
|
||||
case LayoutCode.Guid:
|
||||
case LayoutCode.MongoDbObjectId:
|
||||
case LayoutCode.Utf8:
|
||||
return object.Equals(left, right);
|
||||
case LayoutCode.Binary:
|
||||
return ((byte[])left).SequenceEqual((byte[])right);
|
||||
|
||||
case LayoutCode.ObjectScope:
|
||||
case LayoutCode.ImmutableObjectScope:
|
||||
{
|
||||
Dictionary<Utf8String, object> leftDict = (Dictionary<Utf8String, object>)left;
|
||||
Dictionary<Utf8String, object> rightDict = (Dictionary<Utf8String, object>)right;
|
||||
if (leftDict.Count != rightDict.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: add properties to an object scope.
|
||||
return true;
|
||||
}
|
||||
|
||||
case LayoutCode.TypedArrayScope:
|
||||
case LayoutCode.ImmutableTypedArrayScope:
|
||||
{
|
||||
List<object> leftList = (List<object>)left;
|
||||
List<object> rightList = (List<object>)right;
|
||||
if (leftList.Count != rightList.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < leftList.Count; i++)
|
||||
{
|
||||
if (!HybridRowValueGenerator.DynamicTypeArgumentEquals(resolver, leftList[i], rightList[i], typeArg.TypeArgs[0]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case LayoutCode.TypedSetScope:
|
||||
case LayoutCode.ImmutableTypedSetScope:
|
||||
{
|
||||
List<object> leftList = (List<object>)left;
|
||||
List<object> rightList = (List<object>)right;
|
||||
if (leftList.Count != rightList.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
List<object> working = new List<object>(leftList);
|
||||
foreach (object rightItem in rightList)
|
||||
{
|
||||
int i = HybridRowValueGenerator.SetContains(resolver, working, rightItem, typeArg);
|
||||
if (i == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
working.RemoveAt(i);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case LayoutCode.TypedMapScope:
|
||||
case LayoutCode.ImmutableTypedMapScope:
|
||||
{
|
||||
List<List<object>> leftList = (List<List<object>>)left;
|
||||
List<List<object>> rightList = (List<List<object>>)right;
|
||||
if (leftList.Count != rightList.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
List<List<object>> working = new List<List<object>>(leftList);
|
||||
foreach (List<object> rightItem in rightList)
|
||||
{
|
||||
int i = HybridRowValueGenerator.MapContains(resolver, working, rightItem[0], typeArg);
|
||||
if (i == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
List<object> leftItem = working[i];
|
||||
if (!HybridRowValueGenerator.DynamicTypeArgumentEquals(resolver, leftItem[1], rightItem[1], typeArg.TypeArgs[1]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
working.RemoveAt(i);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case LayoutCode.TupleScope:
|
||||
case LayoutCode.ImmutableTupleScope:
|
||||
case LayoutCode.TypedTupleScope:
|
||||
case LayoutCode.ImmutableTypedTupleScope:
|
||||
case LayoutCode.TaggedScope:
|
||||
case LayoutCode.ImmutableTaggedScope:
|
||||
case LayoutCode.Tagged2Scope:
|
||||
case LayoutCode.ImmutableTagged2Scope:
|
||||
{
|
||||
List<object> leftList = (List<object>)left;
|
||||
List<object> rightList = (List<object>)right;
|
||||
if (leftList.Count != rightList.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Contract.Assert(leftList.Count == typeArg.TypeArgs.Count);
|
||||
for (int i = 0; i < leftList.Count; i++)
|
||||
{
|
||||
if (!HybridRowValueGenerator.DynamicTypeArgumentEquals(resolver, leftList[i], rightList[i], typeArg.TypeArgs[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case LayoutCode.NullableScope:
|
||||
case LayoutCode.ImmutableNullableScope:
|
||||
{
|
||||
Contract.Assert(typeArg.TypeArgs.Count == 1);
|
||||
return HybridRowValueGenerator.DynamicTypeArgumentEquals(resolver, left, right, typeArg.TypeArgs[0]);
|
||||
}
|
||||
|
||||
case LayoutCode.Schema:
|
||||
case LayoutCode.ImmutableSchema:
|
||||
{
|
||||
SchemaId schemaId = typeArg.TypeArgs.SchemaId;
|
||||
Contract.Assert(schemaId != SchemaId.Invalid);
|
||||
Layout layout = resolver.Resolve(schemaId);
|
||||
Contract.Assert(layout != null);
|
||||
|
||||
Dictionary<Utf8String, object> leftDict = (Dictionary<Utf8String, object>)left;
|
||||
Dictionary<Utf8String, object> rightDict = (Dictionary<Utf8String, object>)right;
|
||||
if (leftDict.Count != rightDict.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<Utf8String, object> pair in leftDict)
|
||||
{
|
||||
if (!rightDict.TryGetValue(pair.Key, out object rightValue))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Contract.Requires(layout.TryFind(pair.Key, out LayoutColumn c));
|
||||
return HybridRowValueGenerator.DynamicTypeArgumentEquals(
|
||||
resolver,
|
||||
pair.Value,
|
||||
rightValue,
|
||||
new TypeArgument(c.Type, c.TypeArgs));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
Contract.Assert(false, $"Unknown type will be ignored: {typeArg}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static T GenerateExclusive<T>(Func<T> op, IEnumerable<T> exclusions, int maxCandidates)
|
||||
{
|
||||
HashSet<T> exclusionSet = new HashSet<T>(exclusions);
|
||||
T candidate;
|
||||
|
||||
int retryCount = 0;
|
||||
do
|
||||
{
|
||||
if (retryCount >= maxCandidates)
|
||||
{
|
||||
throw new Exception(
|
||||
$"Max Candidates Reached: {maxCandidates} : " +
|
||||
string.Join(",", from e in exclusions select e.ToString()));
|
||||
}
|
||||
|
||||
candidate = op();
|
||||
retryCount++;
|
||||
}
|
||||
while (exclusionSet.Contains(candidate));
|
||||
|
||||
return candidate;
|
||||
}
|
||||
|
||||
public string GenerateIdentifier()
|
||||
{
|
||||
int length = this.config.IdentifierLength.Next(this.rand);
|
||||
CharDistribution distribution = this.config.IdentifierCharacters;
|
||||
return this.GenerateString(length, distribution);
|
||||
}
|
||||
|
||||
public unsafe string GenerateString(int length, CharDistribution distribution)
|
||||
{
|
||||
if (length == 0)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
char* result = stackalloc char[length];
|
||||
int trim;
|
||||
do
|
||||
{
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
result[i] = distribution.Next(this.rand);
|
||||
}
|
||||
|
||||
// Drop characters until we are under the encoded length.
|
||||
trim = length;
|
||||
while ((trim > 0) && Encoding.UTF8.GetByteCount(result, trim) > length)
|
||||
{
|
||||
trim--;
|
||||
result[trim] = '\0';
|
||||
}
|
||||
}
|
||||
while (trim == 0);
|
||||
|
||||
// Pad with zero's if the resulting encoding is too short.
|
||||
while (Encoding.UTF8.GetByteCount(result, trim) < length)
|
||||
{
|
||||
trim++;
|
||||
}
|
||||
|
||||
Contract.Assert(Encoding.UTF8.GetByteCount(result, trim) == length);
|
||||
return new string(result, 0, trim);
|
||||
}
|
||||
|
||||
public byte[] GenerateBinary(int length)
|
||||
{
|
||||
byte[] result = new byte[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
result[i] = this.rand.NextUInt8();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public SchemaId GenerateSchemaId()
|
||||
{
|
||||
return new SchemaId(this.config.SchemaIds.Next(this.rand));
|
||||
}
|
||||
|
||||
public StorageKind GenerateStorageKind()
|
||||
{
|
||||
return (StorageKind)this.config.FieldStorage.Next(this.rand);
|
||||
}
|
||||
|
||||
public TypeKind GenerateTypeKind()
|
||||
{
|
||||
return (TypeKind)this.config.FieldType.Next(this.rand);
|
||||
}
|
||||
|
||||
public string GenerateComment()
|
||||
{
|
||||
int length = this.config.CommentLength.Next(this.rand);
|
||||
CharDistribution distribution = this.config.UnicodeCharacters;
|
||||
return this.GenerateString(length, distribution);
|
||||
}
|
||||
|
||||
public bool GenerateBool()
|
||||
{
|
||||
return this.rand.NextInt32(0, 1) != 0;
|
||||
}
|
||||
|
||||
public object GenerateLayoutType(
|
||||
LayoutResolver resolver,
|
||||
TypeArgument typeArg,
|
||||
bool nullable = false,
|
||||
int length = 0,
|
||||
StorageKind storage = StorageKind.Sparse)
|
||||
{
|
||||
switch (typeArg.Type.LayoutCode)
|
||||
{
|
||||
case LayoutCode.Null:
|
||||
return nullable && this.GenerateBool() ? (object)null : NullValue.Default;
|
||||
case LayoutCode.Boolean:
|
||||
return nullable && this.GenerateBool() ? (object)null : this.GenerateBool();
|
||||
case LayoutCode.Int8:
|
||||
return nullable && this.GenerateBool() ? (object)null : this.rand.NextInt8();
|
||||
case LayoutCode.Int16:
|
||||
return nullable && this.GenerateBool() ? (object)null : this.rand.NextInt16();
|
||||
case LayoutCode.Int32:
|
||||
return nullable && this.GenerateBool() ? (object)null : this.rand.NextInt32();
|
||||
case LayoutCode.Int64:
|
||||
return nullable && this.GenerateBool() ? (object)null : this.rand.NextInt64();
|
||||
case LayoutCode.UInt8:
|
||||
return nullable && this.GenerateBool() ? (object)null : this.rand.NextUInt8();
|
||||
case LayoutCode.UInt16:
|
||||
return nullable && this.GenerateBool() ? (object)null : this.rand.NextUInt16();
|
||||
case LayoutCode.UInt32:
|
||||
return nullable && this.GenerateBool() ? (object)null : this.rand.NextUInt32();
|
||||
case LayoutCode.UInt64:
|
||||
return nullable && this.GenerateBool() ? (object)null : this.rand.NextUInt64();
|
||||
case LayoutCode.VarInt:
|
||||
return nullable && this.GenerateBool() ? (object)null : this.rand.NextInt64();
|
||||
case LayoutCode.VarUInt:
|
||||
return nullable && this.GenerateBool() ? (object)null : this.rand.NextUInt64();
|
||||
case LayoutCode.Float32:
|
||||
return nullable && this.GenerateBool() ? (object)null : (float)this.rand.NextInt32();
|
||||
case LayoutCode.Float64:
|
||||
return nullable && this.GenerateBool() ? (object)null : (double)this.rand.NextInt64();
|
||||
case LayoutCode.Float128:
|
||||
return nullable && this.GenerateBool() ? (object)null : new Float128(this.rand.NextInt64(), this.rand.NextInt64());
|
||||
case LayoutCode.Decimal:
|
||||
return nullable && this.GenerateBool()
|
||||
? (object)null
|
||||
: new decimal(
|
||||
this.rand.NextInt32(),
|
||||
this.rand.NextInt32(),
|
||||
this.rand.NextInt32(),
|
||||
this.GenerateBool(),
|
||||
this.rand.NextUInt8(0, 28));
|
||||
case LayoutCode.DateTime:
|
||||
{
|
||||
Contract.Assert(DateTime.MinValue.Ticks == 0);
|
||||
long ticks = unchecked((long)(this.rand.NextUInt64() % (ulong)(DateTime.MaxValue.Ticks + 1)));
|
||||
return nullable && this.GenerateBool() ? (object)null : new DateTime(ticks);
|
||||
}
|
||||
|
||||
case LayoutCode.UnixDateTime:
|
||||
{
|
||||
return nullable && this.GenerateBool() ? (object)null : new UnixDateTime(this.rand.NextInt64());
|
||||
}
|
||||
|
||||
case LayoutCode.Guid:
|
||||
return nullable && this.GenerateBool()
|
||||
? (object)null
|
||||
: new Guid(
|
||||
this.rand.NextInt32(),
|
||||
this.rand.NextInt16(),
|
||||
this.rand.NextInt16(),
|
||||
this.rand.NextUInt8(),
|
||||
this.rand.NextUInt8(),
|
||||
this.rand.NextUInt8(),
|
||||
this.rand.NextUInt8(),
|
||||
this.rand.NextUInt8(),
|
||||
this.rand.NextUInt8(),
|
||||
this.rand.NextUInt8(),
|
||||
this.rand.NextUInt8());
|
||||
|
||||
case LayoutCode.MongoDbObjectId:
|
||||
{
|
||||
return nullable && this.GenerateBool() ? (object)null : new MongoDbObjectId(this.rand.NextUInt32(), this.rand.NextUInt64());
|
||||
}
|
||||
|
||||
case LayoutCode.Utf8:
|
||||
{
|
||||
if (nullable && this.GenerateBool())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (storage)
|
||||
{
|
||||
case StorageKind.Variable:
|
||||
length = this.rand.NextInt32(0, length == 0 ? this.config.StringValueLength.Next(this.rand) : length);
|
||||
break;
|
||||
case StorageKind.Sparse:
|
||||
length = this.config.StringValueLength.Next(this.rand);
|
||||
break;
|
||||
}
|
||||
|
||||
CharDistribution distribution = this.config.UnicodeCharacters;
|
||||
return Utf8String.TranscodeUtf16(this.GenerateString(length, distribution));
|
||||
}
|
||||
|
||||
case LayoutCode.Binary:
|
||||
{
|
||||
if (nullable && this.GenerateBool())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (storage)
|
||||
{
|
||||
case StorageKind.Variable:
|
||||
length = this.rand.NextInt32(0, length == 0 ? this.config.StringValueLength.Next(this.rand) : length);
|
||||
break;
|
||||
case StorageKind.Sparse:
|
||||
length = this.config.StringValueLength.Next(this.rand);
|
||||
break;
|
||||
}
|
||||
|
||||
return this.GenerateBinary(length);
|
||||
}
|
||||
|
||||
case LayoutCode.ObjectScope:
|
||||
case LayoutCode.ImmutableObjectScope:
|
||||
{
|
||||
if (nullable && this.GenerateBool())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Dictionary<Utf8String, object> dict = new Dictionary<Utf8String, object>(SamplingUtf8StringComparer.Default);
|
||||
|
||||
// TODO: add properties to an object scope.
|
||||
return dict;
|
||||
}
|
||||
|
||||
case LayoutCode.TypedArrayScope:
|
||||
case LayoutCode.ImmutableTypedArrayScope:
|
||||
{
|
||||
if (nullable && this.GenerateBool())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Contract.Assert(typeArg.TypeArgs.Count == 1);
|
||||
length = this.config.CollectionValueLength.Next(this.rand);
|
||||
List<object> arrayValue = new List<object>(length);
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
arrayValue.Add(this.GenerateLayoutType(resolver, typeArg.TypeArgs[0]));
|
||||
}
|
||||
|
||||
return arrayValue;
|
||||
}
|
||||
|
||||
case LayoutCode.TypedSetScope:
|
||||
case LayoutCode.ImmutableTypedSetScope:
|
||||
{
|
||||
if (nullable && this.GenerateBool())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Contract.Assert(typeArg.TypeArgs.Count == 1);
|
||||
length = this.config.CollectionValueLength.Next(this.rand);
|
||||
List<object> setValue = new List<object>(length);
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
object value = this.GenerateLayoutType(resolver, typeArg.TypeArgs[0]);
|
||||
if (HybridRowValueGenerator.SetContains(resolver, setValue, value, typeArg) == -1)
|
||||
{
|
||||
setValue.Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
return setValue;
|
||||
}
|
||||
|
||||
case LayoutCode.TypedMapScope:
|
||||
case LayoutCode.ImmutableTypedMapScope:
|
||||
{
|
||||
if (nullable && this.GenerateBool())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Contract.Assert(typeArg.TypeArgs.Count == 2);
|
||||
length = this.config.CollectionValueLength.Next(this.rand);
|
||||
List<List<object>> mapValue = new List<List<object>>(length);
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
object key = this.GenerateLayoutType(resolver, typeArg.TypeArgs[0]);
|
||||
if (HybridRowValueGenerator.MapContains(resolver, mapValue, key, typeArg) == -1)
|
||||
{
|
||||
object value = this.GenerateLayoutType(resolver, typeArg.TypeArgs[1]);
|
||||
mapValue.Add(new List<object> { key, value });
|
||||
}
|
||||
}
|
||||
|
||||
return mapValue;
|
||||
}
|
||||
|
||||
case LayoutCode.TupleScope:
|
||||
case LayoutCode.ImmutableTupleScope:
|
||||
case LayoutCode.TypedTupleScope:
|
||||
case LayoutCode.ImmutableTypedTupleScope:
|
||||
case LayoutCode.TaggedScope:
|
||||
case LayoutCode.ImmutableTaggedScope:
|
||||
case LayoutCode.Tagged2Scope:
|
||||
case LayoutCode.ImmutableTagged2Scope:
|
||||
{
|
||||
if (nullable && this.GenerateBool())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
List<object> tupleValue = new List<object>(typeArg.TypeArgs.Count);
|
||||
foreach (TypeArgument t in typeArg.TypeArgs)
|
||||
{
|
||||
tupleValue.Add(this.GenerateLayoutType(resolver, t));
|
||||
}
|
||||
|
||||
return tupleValue;
|
||||
}
|
||||
|
||||
case LayoutCode.NullableScope:
|
||||
case LayoutCode.ImmutableNullableScope:
|
||||
{
|
||||
if (this.GenerateBool())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.GenerateLayoutType(resolver, typeArg.TypeArgs[0]);
|
||||
}
|
||||
|
||||
case LayoutCode.Schema:
|
||||
case LayoutCode.ImmutableSchema:
|
||||
{
|
||||
if (nullable && this.GenerateBool())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
SchemaId schemaId = typeArg.TypeArgs.SchemaId;
|
||||
Contract.Assert(schemaId != SchemaId.Invalid);
|
||||
Layout layout = resolver.Resolve(schemaId);
|
||||
Contract.Assert(layout != null);
|
||||
|
||||
Dictionary<Utf8String, object> dict = new Dictionary<Utf8String, object>(SamplingUtf8StringComparer.Default);
|
||||
foreach (LayoutColumn c in layout.Columns)
|
||||
{
|
||||
dict[c.Path] = this.GenerateLayoutType(
|
||||
resolver,
|
||||
new TypeArgument(c.Type, c.TypeArgs),
|
||||
length: c.Size,
|
||||
storage: c.Storage);
|
||||
}
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
default:
|
||||
Contract.Assert(false, $"Unknown type will be ignored: {typeArg}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static int SetContains(LayoutResolver resolver, List<object> set, object right, TypeArgument typeArg)
|
||||
{
|
||||
for (int i = 0; i < set.Count; i++)
|
||||
{
|
||||
object left = set[i];
|
||||
if (HybridRowValueGenerator.DynamicTypeArgumentEquals(resolver, left, right, typeArg.TypeArgs[0]))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static int MapContains(LayoutResolver resolver, List<List<object>> map, object right, TypeArgument typeArg)
|
||||
{
|
||||
for (int i = 0; i < map.Count; i++)
|
||||
{
|
||||
List<object> pair = map[i];
|
||||
Contract.Assert(pair.Count == 2);
|
||||
if (HybridRowValueGenerator.DynamicTypeArgumentEquals(resolver, pair[0], right, typeArg.TypeArgs[0]))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user