mirror of
https://github.com/microsoft/HybridRow.git
synced 2026-01-23 03:13:22 +00:00
Copied dotnet code from CosmosDB repository
This commit is contained in:
114
dotnet/src/HybridRowGenerator/ByteConverter.cs
Normal file
114
dotnet/src/HybridRowGenerator/ByteConverter.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.Azure.Cosmos.Serialization.HybridRowGenerator
|
||||
{
|
||||
using System;
|
||||
using Microsoft.Azure.Cosmos.Core;
|
||||
|
||||
public static unsafe class ByteConverter
|
||||
{
|
||||
private static readonly byte[] DecodeTable =
|
||||
{
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
|
||||
};
|
||||
|
||||
private static readonly uint[] EncodeTable = ByteConverter.Initialize();
|
||||
|
||||
public static string ToHex(ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
int len = bytes.Length;
|
||||
string result = new string((char)0, len * 2);
|
||||
fixed (uint* lp = ByteConverter.EncodeTable)
|
||||
fixed (byte* bp = bytes)
|
||||
fixed (char* rp = result)
|
||||
{
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
((uint*)rp)[i] = lp[bp[i]];
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static byte[] ToBytes(string hexChars)
|
||||
{
|
||||
Contract.Requires(hexChars != null);
|
||||
Contract.Requires(hexChars.Length % 2 == 0);
|
||||
|
||||
int len = hexChars.Length;
|
||||
byte[] result = new byte[len / 2];
|
||||
fixed (byte* lp = ByteConverter.DecodeTable)
|
||||
fixed (char* cp = hexChars)
|
||||
fixed (byte* rp = result)
|
||||
{
|
||||
for (int i = 0; i < len; i += 2)
|
||||
{
|
||||
int c1 = cp[i];
|
||||
if ((c1 < 0) || (c1 > 255))
|
||||
{
|
||||
throw new Exception($"Invalid character: {c1}");
|
||||
}
|
||||
|
||||
byte b1 = lp[c1];
|
||||
if (b1 == 255)
|
||||
{
|
||||
throw new Exception($"Invalid character: {c1}");
|
||||
}
|
||||
|
||||
int c2 = cp[i + 1];
|
||||
if ((c2 < 0) || (c2 > 255))
|
||||
{
|
||||
throw new Exception($"Invalid character: {c2}");
|
||||
}
|
||||
|
||||
byte b2 = lp[c2];
|
||||
if (b2 == 255)
|
||||
{
|
||||
throw new Exception($"Invalid character: {c2}");
|
||||
}
|
||||
|
||||
rp[i / 2] = (byte)((b1 << 4) | b2);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static uint[] Initialize()
|
||||
{
|
||||
uint[] result = new uint[256];
|
||||
for (int i = 0; i < 256; i++)
|
||||
{
|
||||
string s = i.ToString("X2");
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
result[i] = ((uint)s[0]) + ((uint)s[1] << 16);
|
||||
}
|
||||
else
|
||||
{
|
||||
result[i] = ((uint)s[1]) + ((uint)s[0] << 16);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
36
dotnet/src/HybridRowGenerator/CharDistribution.cs
Normal file
36
dotnet/src/HybridRowGenerator/CharDistribution.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.Azure.Cosmos.Serialization.HybridRowGenerator
|
||||
{
|
||||
using Microsoft.Azure.Cosmos.Core;
|
||||
using Microsoft.Azure.Cosmos.Serialization.HybridRow;
|
||||
|
||||
public class CharDistribution
|
||||
{
|
||||
private readonly char min;
|
||||
private readonly char max;
|
||||
private readonly DistributionType type;
|
||||
|
||||
public CharDistribution(char min, char max, DistributionType type = DistributionType.Uniform)
|
||||
{
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public char Min => this.min;
|
||||
|
||||
public char Max => this.max;
|
||||
|
||||
public DistributionType Type => this.type;
|
||||
|
||||
public char Next(RandomGenerator rand)
|
||||
{
|
||||
Contract.Requires(this.type == DistributionType.Uniform);
|
||||
|
||||
return (char)rand.NextUInt16(this.min, this.max);
|
||||
}
|
||||
}
|
||||
}
|
||||
749
dotnet/src/HybridRowGenerator/DiagnosticConverter.cs
Normal file
749
dotnet/src/HybridRowGenerator/DiagnosticConverter.cs
Normal file
@@ -0,0 +1,749 @@
|
||||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.Azure.Cosmos.Serialization.HybridRowGenerator
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
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.IO;
|
||||
using Microsoft.Azure.Cosmos.Serialization.HybridRow.Layouts;
|
||||
|
||||
public static class DiagnosticConverter
|
||||
{
|
||||
public static Result ReaderToString(ref RowReader reader, out string str)
|
||||
{
|
||||
ReaderStringContext ctx = new ReaderStringContext(new StringBuilder());
|
||||
Result result = DiagnosticConverter.ReaderToString(ref reader, ctx);
|
||||
if (result != Result.Success)
|
||||
{
|
||||
str = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
str = ctx.Builder.ToString();
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
public static Result ReaderToDynamic(ref RowReader reader, out Dictionary<Utf8String, object> scope)
|
||||
{
|
||||
scope = new Dictionary<Utf8String, object>(SamplingUtf8StringComparer.Default);
|
||||
return DiagnosticConverter.ReaderToDynamic(ref reader, scope);
|
||||
}
|
||||
|
||||
private static Result ReaderToDynamic(ref RowReader reader, object scope)
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
Result r;
|
||||
switch (reader.Type.LayoutCode)
|
||||
{
|
||||
case LayoutCode.Null:
|
||||
{
|
||||
r = reader.ReadNull(out NullValue value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Boolean:
|
||||
{
|
||||
r = reader.ReadBool(out bool value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Int8:
|
||||
{
|
||||
r = reader.ReadInt8(out sbyte value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Int16:
|
||||
{
|
||||
r = reader.ReadInt16(out short value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Int32:
|
||||
{
|
||||
r = reader.ReadInt32(out int value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Int64:
|
||||
{
|
||||
r = reader.ReadInt64(out long value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.UInt8:
|
||||
{
|
||||
r = reader.ReadUInt8(out byte value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.UInt16:
|
||||
{
|
||||
r = reader.ReadUInt16(out ushort value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.UInt32:
|
||||
{
|
||||
r = reader.ReadUInt32(out uint value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.UInt64:
|
||||
{
|
||||
r = reader.ReadUInt64(out ulong value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.VarInt:
|
||||
{
|
||||
r = reader.ReadVarInt(out long value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.VarUInt:
|
||||
{
|
||||
r = reader.ReadVarUInt(out ulong value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Float32:
|
||||
{
|
||||
r = reader.ReadFloat32(out float value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Float64:
|
||||
{
|
||||
r = reader.ReadFloat64(out double value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Float128:
|
||||
{
|
||||
r = reader.ReadFloat128(out Float128 value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Decimal:
|
||||
{
|
||||
r = reader.ReadDecimal(out decimal value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.DateTime:
|
||||
{
|
||||
r = reader.ReadDateTime(out DateTime value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.UnixDateTime:
|
||||
{
|
||||
r = reader.ReadUnixDateTime(out UnixDateTime value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Guid:
|
||||
{
|
||||
r = reader.ReadGuid(out Guid value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.MongoDbObjectId:
|
||||
{
|
||||
r = reader.ReadMongoDbObjectId(out MongoDbObjectId value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Utf8:
|
||||
{
|
||||
r = reader.ReadString(out Utf8String value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Binary:
|
||||
{
|
||||
r = reader.ReadBinary(out byte[] value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, value);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.NullableScope:
|
||||
case LayoutCode.ImmutableNullableScope:
|
||||
{
|
||||
if (!reader.HasValue)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
goto case LayoutCode.TypedTupleScope;
|
||||
}
|
||||
|
||||
case LayoutCode.ObjectScope:
|
||||
case LayoutCode.ImmutableObjectScope:
|
||||
case LayoutCode.Schema:
|
||||
case LayoutCode.ImmutableSchema:
|
||||
{
|
||||
object childScope = new Dictionary<Utf8String, object>(SamplingUtf8StringComparer.Default);
|
||||
r = reader.ReadScope(childScope, DiagnosticConverter.ReaderToDynamic);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, childScope);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.ArrayScope:
|
||||
case LayoutCode.ImmutableArrayScope:
|
||||
case LayoutCode.TypedArrayScope:
|
||||
case LayoutCode.ImmutableTypedArrayScope:
|
||||
case LayoutCode.TypedSetScope:
|
||||
case LayoutCode.ImmutableTypedSetScope:
|
||||
case LayoutCode.TypedMapScope:
|
||||
case LayoutCode.ImmutableTypedMapScope:
|
||||
case LayoutCode.TupleScope:
|
||||
case LayoutCode.ImmutableTupleScope:
|
||||
case LayoutCode.TypedTupleScope:
|
||||
case LayoutCode.ImmutableTypedTupleScope:
|
||||
case LayoutCode.TaggedScope:
|
||||
case LayoutCode.ImmutableTaggedScope:
|
||||
case LayoutCode.Tagged2Scope:
|
||||
case LayoutCode.ImmutableTagged2Scope:
|
||||
{
|
||||
object childScope = new List<object>();
|
||||
r = reader.ReadScope(childScope, DiagnosticConverter.ReaderToDynamic);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
DiagnosticConverter.AddToScope(scope, reader.Path, childScope);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
Contract.Assert(false, $"Unknown type will be ignored: {reader.Type.LayoutCode}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private static void AddToScope(object scope, UtfAnyString path, object value)
|
||||
{
|
||||
if (scope is List<object> linearScope)
|
||||
{
|
||||
Contract.Assert(path.IsNull);
|
||||
linearScope.Add(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
Contract.Assert(!string.IsNullOrWhiteSpace(path.ToString()));
|
||||
((Dictionary<Utf8String, object>)scope)[path.ToUtf8String()] = value;
|
||||
}
|
||||
}
|
||||
|
||||
private static Result ReaderToString(ref RowReader reader, ReaderStringContext ctx)
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
string path = !reader.Path.IsNull ? $"\"{reader.Path}\"" : "null";
|
||||
ctx.Builder.Append(
|
||||
$"{new string(' ', ctx.Indent * 2)}Storage: {reader.Storage}, Path: {path}, Index: {reader.Index}, Type: {reader.Type.Name + reader.TypeArgs.ToString()}, Value: ");
|
||||
|
||||
Result r;
|
||||
switch (reader.Type.LayoutCode)
|
||||
{
|
||||
case LayoutCode.Null:
|
||||
{
|
||||
r = reader.ReadNull(out NullValue _);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ctx.Builder.AppendLine("null");
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Boolean:
|
||||
case LayoutCode.BooleanFalse:
|
||||
{
|
||||
r = reader.ReadBool(out bool value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ctx.Builder.Append(value);
|
||||
ctx.Builder.AppendLine();
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Int8:
|
||||
{
|
||||
r = reader.ReadInt8(out sbyte value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ctx.Builder.Append(value);
|
||||
ctx.Builder.AppendLine();
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Int16:
|
||||
{
|
||||
r = reader.ReadInt16(out short value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ctx.Builder.Append(value);
|
||||
ctx.Builder.AppendLine();
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Int32:
|
||||
{
|
||||
r = reader.ReadInt32(out int value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ctx.Builder.Append(value);
|
||||
ctx.Builder.AppendLine();
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Int64:
|
||||
{
|
||||
r = reader.ReadInt64(out long value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ctx.Builder.Append(value);
|
||||
ctx.Builder.AppendLine();
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.UInt8:
|
||||
{
|
||||
r = reader.ReadUInt8(out byte value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ctx.Builder.Append(value);
|
||||
ctx.Builder.AppendLine();
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.UInt16:
|
||||
{
|
||||
r = reader.ReadUInt16(out ushort value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ctx.Builder.Append(value);
|
||||
ctx.Builder.AppendLine();
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.UInt32:
|
||||
{
|
||||
r = reader.ReadUInt32(out uint value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ctx.Builder.Append(value);
|
||||
ctx.Builder.AppendLine();
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.UInt64:
|
||||
{
|
||||
r = reader.ReadUInt64(out ulong value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ctx.Builder.Append(value);
|
||||
ctx.Builder.AppendLine();
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.VarInt:
|
||||
{
|
||||
r = reader.ReadVarInt(out long value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ctx.Builder.Append(value);
|
||||
ctx.Builder.AppendLine();
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.VarUInt:
|
||||
{
|
||||
r = reader.ReadVarUInt(out ulong value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ctx.Builder.Append(value);
|
||||
ctx.Builder.AppendLine();
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Float32:
|
||||
{
|
||||
r = reader.ReadFloat32(out float value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ctx.Builder.Append(value);
|
||||
ctx.Builder.AppendLine();
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Float64:
|
||||
{
|
||||
r = reader.ReadFloat64(out double value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ctx.Builder.Append(value);
|
||||
ctx.Builder.AppendLine();
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Float128:
|
||||
{
|
||||
r = reader.ReadFloat128(out Float128 value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ctx.Builder.AppendFormat("High: {0}, Low: {1}\n", value.High, value.Low);
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Decimal:
|
||||
{
|
||||
r = reader.ReadDecimal(out decimal value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ctx.Builder.Append(value);
|
||||
ctx.Builder.AppendLine();
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.DateTime:
|
||||
{
|
||||
r = reader.ReadDateTime(out DateTime value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ctx.Builder.Append(value);
|
||||
ctx.Builder.AppendLine();
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.UnixDateTime:
|
||||
{
|
||||
r = reader.ReadUnixDateTime(out UnixDateTime value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ctx.Builder.Append(value.Milliseconds);
|
||||
ctx.Builder.AppendLine();
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Guid:
|
||||
{
|
||||
r = reader.ReadGuid(out Guid value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ctx.Builder.AppendLine(value.ToString());
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.MongoDbObjectId:
|
||||
{
|
||||
r = reader.ReadMongoDbObjectId(out MongoDbObjectId value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ReadOnlyMemory<byte> bytes = value.ToByteArray();
|
||||
ctx.Builder.AppendLine(ByteConverter.ToHex(bytes.Span));
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Utf8:
|
||||
{
|
||||
r = reader.ReadString(out Utf8String value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ctx.Builder.AppendLine(value.ToString());
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.Binary:
|
||||
{
|
||||
r = reader.ReadBinary(out ReadOnlySpan<byte> value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ctx.Builder.AppendLine(ByteConverter.ToHex(value));
|
||||
break;
|
||||
}
|
||||
|
||||
case LayoutCode.NullableScope:
|
||||
case LayoutCode.ImmutableNullableScope:
|
||||
{
|
||||
if (!reader.HasValue)
|
||||
{
|
||||
ctx.Builder.AppendLine("null");
|
||||
break;
|
||||
}
|
||||
|
||||
goto case LayoutCode.TypedTupleScope;
|
||||
}
|
||||
|
||||
case LayoutCode.ObjectScope:
|
||||
case LayoutCode.ImmutableObjectScope:
|
||||
case LayoutCode.ArrayScope:
|
||||
case LayoutCode.ImmutableArrayScope:
|
||||
case LayoutCode.TypedArrayScope:
|
||||
case LayoutCode.ImmutableTypedArrayScope:
|
||||
case LayoutCode.TypedSetScope:
|
||||
case LayoutCode.ImmutableTypedSetScope:
|
||||
case LayoutCode.TypedMapScope:
|
||||
case LayoutCode.ImmutableTypedMapScope:
|
||||
case LayoutCode.TupleScope:
|
||||
case LayoutCode.ImmutableTupleScope:
|
||||
case LayoutCode.TypedTupleScope:
|
||||
case LayoutCode.ImmutableTypedTupleScope:
|
||||
case LayoutCode.TaggedScope:
|
||||
case LayoutCode.ImmutableTaggedScope:
|
||||
case LayoutCode.Tagged2Scope:
|
||||
case LayoutCode.ImmutableTagged2Scope:
|
||||
case LayoutCode.Schema:
|
||||
case LayoutCode.ImmutableSchema:
|
||||
{
|
||||
ctx.Builder.AppendLine("{");
|
||||
r = reader.ReadScope(new ReaderStringContext(ctx.Builder, ctx.Indent + 1), DiagnosticConverter.ReaderToString);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
ctx.Builder.AppendLine($"{new string(' ', ctx.Indent * 2)}}}");
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
Contract.Assert(false, $"Unknown type will be ignored: {reader.Type.LayoutCode}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private readonly struct ReaderStringContext
|
||||
{
|
||||
public readonly int Indent;
|
||||
public readonly StringBuilder Builder;
|
||||
|
||||
public ReaderStringContext(StringBuilder builder, int indent = 0)
|
||||
{
|
||||
this.Indent = indent;
|
||||
this.Builder = builder;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
dotnet/src/HybridRowGenerator/DistributionType.cs
Normal file
11
dotnet/src/HybridRowGenerator/DistributionType.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.Azure.Cosmos.Serialization.HybridRowGenerator
|
||||
{
|
||||
public enum DistributionType
|
||||
{
|
||||
Uniform = 0,
|
||||
}
|
||||
}
|
||||
105
dotnet/src/HybridRowGenerator/HybridRowGeneratorConfig.cs
Normal file
105
dotnet/src/HybridRowGenerator/HybridRowGeneratorConfig.cs
Normal file
@@ -0,0 +1,105 @@
|
||||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.Azure.Cosmos.Serialization.HybridRowGenerator
|
||||
{
|
||||
using Microsoft.Azure.Cosmos.Serialization.HybridRow.Schemas;
|
||||
|
||||
public class HybridRowGeneratorConfig
|
||||
{
|
||||
/// <summary>The number of attempts to allocate a value given an exclusion list before aborting.</summary>
|
||||
private const int ConflictRetryAttemptsDefault = 100;
|
||||
|
||||
/// <summary>
|
||||
/// The rate at which the cardinality of substructures decays as a function of depth. This
|
||||
/// ensures that randomly generated values don't become infinitely large.
|
||||
/// </summary>
|
||||
private const double DepthDecayFactorDefault = -1.0D;
|
||||
|
||||
/// <summary>
|
||||
/// The length (in chars) of identifiers including namespace names, schema names, property
|
||||
/// names, etc.
|
||||
/// </summary>
|
||||
private static readonly IntDistribution IdentifierLengthDefault = new IntDistribution(1, 20);
|
||||
|
||||
/// <summary>
|
||||
/// The distribution of unicode characters used in constructing identifiers including
|
||||
/// namespace names, schema names, property names, etc.
|
||||
/// </summary>
|
||||
private static readonly CharDistribution IdentifierCharactersDefault = new CharDistribution('a', 'z');
|
||||
|
||||
/// <summary>The length (in chars) of annotation comments within the schema.</summary>
|
||||
private static readonly IntDistribution CommentLengthDefault = new IntDistribution(0, 50);
|
||||
|
||||
/// <summary>The length (in chars) of string values.</summary>
|
||||
private static readonly IntDistribution StringValueLengthDefault = new IntDistribution(0, 100);
|
||||
|
||||
/// <summary>The length (in bytes) of binary values.</summary>
|
||||
private static readonly IntDistribution BinaryValueLengthDefault = new IntDistribution(0, 100);
|
||||
|
||||
/// <summary>The length (in number of elements) of collection scopes.</summary>
|
||||
private static readonly IntDistribution CollectionValueLengthDefault = new IntDistribution(0, 10);
|
||||
|
||||
/// <summary>The distribution of unicode characters used in constructing Unicode field values.</summary>
|
||||
private static readonly CharDistribution UnicodeCharactersDefault = new CharDistribution('\u0001', char.MaxValue);
|
||||
|
||||
/// <summary>The space of SchemaId values assigned to schemas (table or UDT) within a single namespace.</summary>
|
||||
private static readonly IntDistribution SchemaIdsDefault = new IntDistribution(int.MinValue, int.MaxValue);
|
||||
|
||||
/// <summary>The number of properties (i.e. columns, fields) to appear in a table or UDT definition.</summary>
|
||||
private static readonly IntDistribution NumTablePropertiesDefault = new IntDistribution(1, 10);
|
||||
|
||||
/// <summary>The number of items to appear in a tuple field.</summary>
|
||||
private static readonly IntDistribution NumTupleItemsDefault = new IntDistribution(2, 5);
|
||||
|
||||
/// <summary>The number of items to appear in a tagged field.</summary>
|
||||
private static readonly IntDistribution NumTaggedItemsDefault = new IntDistribution(1, 2);
|
||||
|
||||
/// <summary>The length (in units, e.g. chars, bytes, etc.) of variable length primitive field values.</summary>
|
||||
private static readonly IntDistribution PrimitiveFieldValueLengthDefault = new IntDistribution(1, 1024);
|
||||
|
||||
/// <summary>The distribution of types for fields.</summary>
|
||||
private static readonly IntDistribution FieldTypeDefault = new IntDistribution((int)TypeKind.Null, (int)TypeKind.Schema);
|
||||
|
||||
/// <summary>The distribution of storage for fields.</summary>
|
||||
private static readonly IntDistribution FieldStorageDefault = new IntDistribution((int)StorageKind.Sparse, (int)StorageKind.Variable);
|
||||
|
||||
/// <summary>The distribution of initial sizes for RowBuffers.</summary>
|
||||
private static readonly IntDistribution RowBufferInitialCapacityDefault = new IntDistribution(0, 2 * 1024 * 1024);
|
||||
|
||||
public IntDistribution IdentifierLength { get; set; } = HybridRowGeneratorConfig.IdentifierLengthDefault;
|
||||
|
||||
public CharDistribution IdentifierCharacters { get; set; } = HybridRowGeneratorConfig.IdentifierCharactersDefault;
|
||||
|
||||
public IntDistribution CommentLength { get; set; } = HybridRowGeneratorConfig.CommentLengthDefault;
|
||||
|
||||
public IntDistribution StringValueLength { get; set; } = HybridRowGeneratorConfig.StringValueLengthDefault;
|
||||
|
||||
public IntDistribution BinaryValueLength { get; set; } = HybridRowGeneratorConfig.BinaryValueLengthDefault;
|
||||
|
||||
public IntDistribution CollectionValueLength { get; set; } = HybridRowGeneratorConfig.CollectionValueLengthDefault;
|
||||
|
||||
public CharDistribution UnicodeCharacters { get; set; } = HybridRowGeneratorConfig.UnicodeCharactersDefault;
|
||||
|
||||
public IntDistribution SchemaIds { get; set; } = HybridRowGeneratorConfig.SchemaIdsDefault;
|
||||
|
||||
public IntDistribution NumTableProperties { get; set; } = HybridRowGeneratorConfig.NumTablePropertiesDefault;
|
||||
|
||||
public IntDistribution NumTupleItems { get; set; } = HybridRowGeneratorConfig.NumTupleItemsDefault;
|
||||
|
||||
public IntDistribution NumTaggedItems { get; set; } = HybridRowGeneratorConfig.NumTaggedItemsDefault;
|
||||
|
||||
public IntDistribution PrimitiveFieldValueLength { get; set; } = HybridRowGeneratorConfig.PrimitiveFieldValueLengthDefault;
|
||||
|
||||
public IntDistribution FieldType { get; set; } = HybridRowGeneratorConfig.FieldTypeDefault;
|
||||
|
||||
public IntDistribution FieldStorage { get; set; } = HybridRowGeneratorConfig.FieldStorageDefault;
|
||||
|
||||
public IntDistribution RowBufferInitialCapacity { get; set; } = HybridRowGeneratorConfig.RowBufferInitialCapacityDefault;
|
||||
|
||||
public int ConflictRetryAttempts { get; set; } = HybridRowGeneratorConfig.ConflictRetryAttemptsDefault;
|
||||
|
||||
public double DepthDecayFactor { get; set; } = HybridRowGeneratorConfig.DepthDecayFactorDefault;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
36
dotnet/src/HybridRowGenerator/IntDistribution.cs
Normal file
36
dotnet/src/HybridRowGenerator/IntDistribution.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.Azure.Cosmos.Serialization.HybridRowGenerator
|
||||
{
|
||||
using Microsoft.Azure.Cosmos.Core;
|
||||
using Microsoft.Azure.Cosmos.Serialization.HybridRow;
|
||||
|
||||
public class IntDistribution
|
||||
{
|
||||
private readonly int min;
|
||||
private readonly int max;
|
||||
private readonly DistributionType type;
|
||||
|
||||
public IntDistribution(int min, int max, DistributionType type = DistributionType.Uniform)
|
||||
{
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public int Min => this.min;
|
||||
|
||||
public int Max => this.max;
|
||||
|
||||
public DistributionType Type => this.type;
|
||||
|
||||
public int Next(RandomGenerator rand)
|
||||
{
|
||||
Contract.Requires(this.type == DistributionType.Uniform);
|
||||
|
||||
return rand.NextInt32(this.min, this.max);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
|
||||
<ProjectGuid>{B3F04B26-800A-4097-95CE-EACECA9ACE23}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<SigningType>Test</SigningType>
|
||||
<RootNamespace>Microsoft.Azure.Cosmos.Serialization.HybridRowGenerator</RootNamespace>
|
||||
<AssemblyName>Microsoft.Azure.Cosmos.Serialization.HybridRowGenerator</AssemblyName>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
</PropertyGroup>
|
||||
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Build.props))\build.props" />
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" />
|
||||
<PackageReference Include="System.Memory" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Core\Core\Microsoft.Azure.Cosmos.Core.csproj" />
|
||||
<ProjectReference Include="..\HybridRow\Microsoft.Azure.Cosmos.Serialization.HybridRow.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
20
dotnet/src/HybridRowGenerator/Properties/AssemblyInfo.cs
Normal file
20
dotnet/src/HybridRowGenerator/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
//------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//------------------------------------------------------------
|
||||
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Microsoft.Azure.Cosmos.Serialization.HybridRowGenerator")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("B3F04B26-800A-4097-95CE-EACECA9ACE23")]
|
||||
131
dotnet/src/HybridRowGenerator/RandomGenerator.cs
Normal file
131
dotnet/src/HybridRowGenerator/RandomGenerator.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.Azure.Cosmos.Serialization.HybridRowGenerator
|
||||
{
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Azure.Cosmos.Core;
|
||||
|
||||
public class RandomGenerator
|
||||
{
|
||||
private readonly Random root;
|
||||
|
||||
public RandomGenerator(Random root)
|
||||
{
|
||||
this.root = root;
|
||||
}
|
||||
|
||||
/// <summary>Returns a uniformly distributed 8-bit signed integer in the range specified.</summary>
|
||||
/// <param name="min">The inclusive lower bound of the random number returned.</param>
|
||||
/// <param name="max">The inclusive upper bound of the random number returned.</param>
|
||||
/// <remarks>Requires <paramref name="min" /> < <paramref name="max" />.</remarks>
|
||||
public sbyte NextInt8(sbyte min = sbyte.MinValue, sbyte max = sbyte.MaxValue)
|
||||
{
|
||||
Contract.Requires(min <= max);
|
||||
|
||||
unchecked
|
||||
{
|
||||
sbyte result = (sbyte)(this.NextUInt8(0, (byte)(max - min)) + min);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Returns a uniformly distributed 16-bit signed integer in the range specified.</summary>
|
||||
/// <param name="min">The inclusive lower bound of the random number returned.</param>
|
||||
/// <param name="max">The inclusive upper bound of the random number returned.</param>
|
||||
/// <remarks>Requires <paramref name="min" /> < <paramref name="max" />.</remarks>
|
||||
public short NextInt16(short min = short.MinValue, short max = short.MaxValue)
|
||||
{
|
||||
Contract.Requires(min <= max);
|
||||
|
||||
unchecked
|
||||
{
|
||||
short result = (short)(this.NextUInt16(0, (ushort)(max - min)) + min);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Returns a uniformly distributed 32-bit signed integer in the range specified.</summary>
|
||||
/// <param name="min">The inclusive lower bound of the random number returned.</param>
|
||||
/// <param name="max">The inclusive upper bound of the random number returned.</param>
|
||||
/// <remarks>Requires <paramref name="min" /> < <paramref name="max" />.</remarks>
|
||||
public int NextInt32(int min = int.MinValue, int max = int.MaxValue)
|
||||
{
|
||||
Contract.Requires(min <= max);
|
||||
|
||||
unchecked
|
||||
{
|
||||
int result = (int)(this.NextUInt32(0, (uint)(max - min)) + min);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Returns a uniformly distributed 64-bit signed integer.</summary>
|
||||
public long NextInt64()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
long result = (long)this.NextUInt64();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Returns a uniformly distributed 8-bit unsigned integer in the range specified.</summary>
|
||||
/// <param name="min">The inclusive lower bound of the random number returned.</param>
|
||||
/// <param name="max">The inclusive upper bound of the random number returned.</param>
|
||||
/// <remarks>Requires <paramref name="min" /> < <paramref name="max" />.</remarks>
|
||||
public byte NextUInt8(byte min = byte.MinValue, byte max = byte.MaxValue)
|
||||
{
|
||||
Contract.Requires(min <= max);
|
||||
|
||||
ulong result = this.NextUInt64();
|
||||
unchecked
|
||||
{
|
||||
result = (result % (((ulong)max - (ulong)min) + 1)) + (ulong)min;
|
||||
return (byte)result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Returns a uniformly distributed 16-bit unsigned integer in the range specified.</summary>
|
||||
/// <param name="min">The inclusive lower bound of the random number returned.</param>
|
||||
/// <param name="max">The inclusive upper bound of the random number returned.</param>
|
||||
/// <remarks>Requires <paramref name="min" /> < <paramref name="max" />.</remarks>
|
||||
public ushort NextUInt16(ushort min = ushort.MinValue, ushort max = ushort.MaxValue)
|
||||
{
|
||||
Contract.Requires(min <= max);
|
||||
|
||||
ulong result = this.NextUInt64();
|
||||
unchecked
|
||||
{
|
||||
result = (result % (((ulong)max - (ulong)min) + 1)) + (ulong)min;
|
||||
return (ushort)result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Returns a uniformly distributed 32-bit unsigned integer in the range specified.</summary>
|
||||
/// <param name="min">The inclusive lower bound of the random number returned.</param>
|
||||
/// <param name="max">The inclusive upper bound of the random number returned.</param>
|
||||
/// <remarks>Requires <paramref name="min" /> < <paramref name="max" />.</remarks>
|
||||
public uint NextUInt32(uint min = uint.MinValue, uint max = uint.MaxValue)
|
||||
{
|
||||
Contract.Requires(min <= max);
|
||||
|
||||
ulong result = this.NextUInt64();
|
||||
unchecked
|
||||
{
|
||||
result = (result % (((ulong)max - (ulong)min) + 1)) + (ulong)min;
|
||||
return (uint)result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Returns a uniformly distributed 64-bit unsigned integer.</summary>
|
||||
public ulong NextUInt64()
|
||||
{
|
||||
Span<ulong> result = stackalloc ulong[1];
|
||||
this.root.NextBytes(MemoryMarshal.Cast<ulong, byte>(result));
|
||||
return result[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
277
dotnet/src/HybridRowGenerator/SchemaGenerator.cs
Normal file
277
dotnet/src/HybridRowGenerator/SchemaGenerator.cs
Normal file
@@ -0,0 +1,277 @@
|
||||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.Azure.Cosmos.Serialization.HybridRowGenerator
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Azure.Cosmos.Core;
|
||||
using Microsoft.Azure.Cosmos.Serialization.HybridRow;
|
||||
using Microsoft.Azure.Cosmos.Serialization.HybridRow.Schemas;
|
||||
|
||||
public class SchemaGenerator
|
||||
{
|
||||
private readonly RandomGenerator rand;
|
||||
private readonly HybridRowGeneratorConfig config;
|
||||
private readonly HybridRowValueGenerator generator;
|
||||
|
||||
public SchemaGenerator(RandomGenerator rand, HybridRowGeneratorConfig config, HybridRowValueGenerator generator)
|
||||
{
|
||||
this.rand = rand;
|
||||
this.config = config;
|
||||
this.generator = generator;
|
||||
}
|
||||
|
||||
public Namespace InitializeRandomNamespace()
|
||||
{
|
||||
Namespace ns = new Namespace()
|
||||
{
|
||||
Name = this.generator.GenerateIdentifier(),
|
||||
};
|
||||
|
||||
return ns;
|
||||
}
|
||||
|
||||
public Schema InitializeRandomSchema(Namespace ns, int depth)
|
||||
{
|
||||
string name = HybridRowValueGenerator.GenerateExclusive(
|
||||
this.generator.GenerateIdentifier,
|
||||
from s1 in ns.Schemas select s1.Name,
|
||||
this.config.ConflictRetryAttempts);
|
||||
|
||||
SchemaId sid = HybridRowValueGenerator.GenerateExclusive(
|
||||
this.generator.GenerateSchemaId,
|
||||
from s1 in ns.Schemas select s1.SchemaId,
|
||||
this.config.ConflictRetryAttempts);
|
||||
|
||||
// Allocate and insert the schema *before* recursing to allocate properties. This ensures that nested structure
|
||||
// doesn't conflict with name or id constraints.
|
||||
Schema s = new Schema()
|
||||
{
|
||||
Name = name,
|
||||
SchemaId = sid,
|
||||
Type = TypeKind.Schema,
|
||||
Comment = this.generator.GenerateComment(),
|
||||
Options = this.InitializeRandomSchemaOptions(),
|
||||
};
|
||||
|
||||
ns.Schemas.Add(s);
|
||||
|
||||
// Recurse and allocate its properties.
|
||||
s.Properties = this.InitializeRandomProperties(ns, TypeKind.Schema, depth);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
private List<Property> InitializeRandomProperties(Namespace ns, TypeKind scope, int depth)
|
||||
{
|
||||
int length = this.config.NumTableProperties.Next(this.rand);
|
||||
|
||||
// Introduce some decay rate for the number of properties in nested contexts
|
||||
// to limit the depth of schemas.
|
||||
if (depth > 0)
|
||||
{
|
||||
double scaled = Math.Floor(length * Math.Exp(depth * this.config.DepthDecayFactor));
|
||||
Contract.Assert(scaled <= length);
|
||||
length = (int)scaled;
|
||||
}
|
||||
|
||||
List<Property> properties = new List<Property>(length);
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
PropertyType propType = this.InitializeRandomPropertyType(ns, scope, depth);
|
||||
string path = HybridRowValueGenerator.GenerateExclusive(
|
||||
this.generator.GenerateIdentifier,
|
||||
from s1 in properties select s1.Path,
|
||||
this.config.ConflictRetryAttempts);
|
||||
Property prop = new Property()
|
||||
{
|
||||
Comment = this.generator.GenerateComment(),
|
||||
Path = path,
|
||||
PropertyType = propType,
|
||||
};
|
||||
|
||||
properties.Add(prop);
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
private PropertyType InitializeRandomPropertyType(Namespace ns, TypeKind scope, int depth)
|
||||
{
|
||||
TypeKind type = this.generator.GenerateTypeKind();
|
||||
PropertyType propType;
|
||||
switch (type)
|
||||
{
|
||||
case TypeKind.Object:
|
||||
propType = new ObjectPropertyType()
|
||||
{
|
||||
Immutable = this.generator.GenerateBool(),
|
||||
|
||||
// TODO: add properties to object scopes.
|
||||
// Properties = this.InitializeRandomProperties(ns, type, depth + 1),
|
||||
};
|
||||
|
||||
break;
|
||||
case TypeKind.Array:
|
||||
propType = new ArrayPropertyType()
|
||||
{
|
||||
Immutable = this.generator.GenerateBool(),
|
||||
Items = this.InitializeRandomPropertyType(ns, type, depth + 1),
|
||||
};
|
||||
|
||||
break;
|
||||
case TypeKind.Set:
|
||||
propType = new SetPropertyType()
|
||||
{
|
||||
Immutable = this.generator.GenerateBool(),
|
||||
Items = this.InitializeRandomPropertyType(ns, type, depth + 1),
|
||||
};
|
||||
|
||||
break;
|
||||
case TypeKind.Map:
|
||||
propType = new MapPropertyType()
|
||||
{
|
||||
Immutable = this.generator.GenerateBool(),
|
||||
Keys = this.InitializeRandomPropertyType(ns, type, depth + 1),
|
||||
Values = this.InitializeRandomPropertyType(ns, type, depth + 1),
|
||||
};
|
||||
|
||||
break;
|
||||
case TypeKind.Tuple:
|
||||
int numItems = this.config.NumTupleItems.Next(this.rand);
|
||||
List<PropertyType> itemTypes = new List<PropertyType>(numItems);
|
||||
for (int i = 0; i < numItems; i++)
|
||||
{
|
||||
itemTypes.Add(this.InitializeRandomPropertyType(ns, type, depth + 1));
|
||||
}
|
||||
|
||||
propType = new TuplePropertyType()
|
||||
{
|
||||
Immutable = this.generator.GenerateBool(),
|
||||
Items = itemTypes,
|
||||
};
|
||||
|
||||
break;
|
||||
case TypeKind.Tagged:
|
||||
int numTagged = this.config.NumTaggedItems.Next(this.rand);
|
||||
List<PropertyType> taggedItemTypes = new List<PropertyType>(numTagged);
|
||||
for (int i = 0; i < numTagged; i++)
|
||||
{
|
||||
taggedItemTypes.Add(this.InitializeRandomPropertyType(ns, type, depth + 1));
|
||||
}
|
||||
|
||||
propType = new TaggedPropertyType()
|
||||
{
|
||||
Immutable = this.generator.GenerateBool(),
|
||||
Items = taggedItemTypes,
|
||||
};
|
||||
|
||||
break;
|
||||
case TypeKind.Schema:
|
||||
Schema udt = this.InitializeRandomSchema(ns, depth + 1);
|
||||
propType = new UdtPropertyType()
|
||||
{
|
||||
Immutable = this.generator.GenerateBool(),
|
||||
Name = udt.Name,
|
||||
};
|
||||
|
||||
break;
|
||||
default:
|
||||
StorageKind storage = (scope == TypeKind.Schema) ? this.generator.GenerateStorageKind() : StorageKind.Sparse;
|
||||
switch (storage)
|
||||
{
|
||||
case StorageKind.Sparse:
|
||||
// All types are supported in Sparse.
|
||||
break;
|
||||
|
||||
case StorageKind.Fixed:
|
||||
switch (type)
|
||||
{
|
||||
case TypeKind.Null:
|
||||
case TypeKind.Boolean:
|
||||
case TypeKind.Int8:
|
||||
case TypeKind.Int16:
|
||||
case TypeKind.Int32:
|
||||
case TypeKind.Int64:
|
||||
case TypeKind.UInt8:
|
||||
case TypeKind.UInt16:
|
||||
case TypeKind.UInt32:
|
||||
case TypeKind.UInt64:
|
||||
case TypeKind.Float32:
|
||||
case TypeKind.Float64:
|
||||
case TypeKind.Float128:
|
||||
case TypeKind.Decimal:
|
||||
case TypeKind.DateTime:
|
||||
case TypeKind.UnixDateTime:
|
||||
case TypeKind.Guid:
|
||||
case TypeKind.MongoDbObjectId:
|
||||
case TypeKind.Utf8:
|
||||
case TypeKind.Binary:
|
||||
// Only these types are supported with fixed storage today.
|
||||
break;
|
||||
default:
|
||||
storage = StorageKind.Sparse;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case StorageKind.Variable:
|
||||
switch (type)
|
||||
{
|
||||
case TypeKind.Binary:
|
||||
case TypeKind.Utf8:
|
||||
case TypeKind.VarInt:
|
||||
case TypeKind.VarUInt:
|
||||
// Only these types are supported with variable storage today.
|
||||
break;
|
||||
|
||||
default:
|
||||
storage = StorageKind.Sparse;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
propType = new PrimitivePropertyType()
|
||||
{
|
||||
Length = storage == StorageKind.Sparse ? 0 : this.config.PrimitiveFieldValueLength.Next(this.rand),
|
||||
Storage = storage,
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
propType.ApiType = this.generator.GenerateIdentifier();
|
||||
propType.Type = type;
|
||||
switch (scope)
|
||||
{
|
||||
case TypeKind.Array:
|
||||
case TypeKind.Map:
|
||||
case TypeKind.Set:
|
||||
case TypeKind.Tuple:
|
||||
case TypeKind.Tagged:
|
||||
propType.Nullable = this.generator.GenerateBool();
|
||||
break;
|
||||
default:
|
||||
propType.Nullable = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return propType;
|
||||
}
|
||||
|
||||
private SchemaOptions InitializeRandomSchemaOptions()
|
||||
{
|
||||
SchemaOptions o = new SchemaOptions()
|
||||
{
|
||||
DisallowUnschematized = this.generator.GenerateBool(),
|
||||
};
|
||||
|
||||
return o;
|
||||
}
|
||||
}
|
||||
}
|
||||
330
dotnet/src/HybridRowGenerator/StreamingRowGenerator.cs
Normal file
330
dotnet/src/HybridRowGenerator/StreamingRowGenerator.cs
Normal file
@@ -0,0 +1,330 @@
|
||||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.Azure.Cosmos.Serialization.HybridRowGenerator
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Microsoft.Azure.Cosmos.Core;
|
||||
using Microsoft.Azure.Cosmos.Core.Utf8;
|
||||
using Microsoft.Azure.Cosmos.Serialization.HybridRow;
|
||||
using Microsoft.Azure.Cosmos.Serialization.HybridRow.IO;
|
||||
using Microsoft.Azure.Cosmos.Serialization.HybridRow.Layouts;
|
||||
|
||||
public ref struct StreamingRowGenerator
|
||||
{
|
||||
private RowBuffer row;
|
||||
|
||||
public StreamingRowGenerator(int capacity, Layout layout, LayoutResolver resolver, ISpanResizer<byte> resizer = default)
|
||||
{
|
||||
this.row = new RowBuffer(capacity, resizer);
|
||||
this.row.InitLayout(HybridRowVersion.V1, layout, resolver);
|
||||
}
|
||||
|
||||
public int Length => this.row.Length;
|
||||
|
||||
public byte[] ToArray() => this.row.ToArray();
|
||||
|
||||
public void WriteTo(Stream stream)
|
||||
{
|
||||
this.row.WriteTo(stream);
|
||||
}
|
||||
|
||||
public bool ReadFrom(Stream stream, int length)
|
||||
{
|
||||
return this.row.ReadFrom(stream, length, HybridRowVersion.V1, this.row.Resolver);
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Layout layout = this.row.Resolver.Resolve(this.row.Header.SchemaId);
|
||||
this.row.InitLayout(HybridRowVersion.V1, layout, this.row.Resolver);
|
||||
}
|
||||
|
||||
public RowReader GetReader()
|
||||
{
|
||||
return new RowReader(ref this.row);
|
||||
}
|
||||
|
||||
public Result WriteBuffer(Dictionary<Utf8String, object> value)
|
||||
{
|
||||
return RowWriter.WriteBuffer(
|
||||
ref this.row,
|
||||
value,
|
||||
(ref RowWriter writer, TypeArgument typeArg, Dictionary<Utf8String, object> dict) =>
|
||||
{
|
||||
Layout layout = writer.Resolver.Resolve(typeArg.TypeArgs.SchemaId);
|
||||
foreach (LayoutColumn c in layout.Columns)
|
||||
{
|
||||
Result result = StreamingRowGenerator.LayoutCodeSwitch(ref writer, c.Path, c.TypeArg, dict[c.Path]);
|
||||
if (result != Result.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
});
|
||||
}
|
||||
|
||||
private static Result LayoutCodeSwitch(ref RowWriter writer, Utf8String path, TypeArgument typeArg, object value)
|
||||
{
|
||||
switch (typeArg.Type.LayoutCode)
|
||||
{
|
||||
case LayoutCode.Null:
|
||||
return writer.WriteNull(path);
|
||||
|
||||
case LayoutCode.Boolean:
|
||||
return writer.WriteBool(path, value == null ? default : (bool)value);
|
||||
|
||||
case LayoutCode.Int8:
|
||||
return writer.WriteInt8(path, value == null ? default : (sbyte)value);
|
||||
|
||||
case LayoutCode.Int16:
|
||||
return writer.WriteInt16(path, value == null ? default : (short)value);
|
||||
|
||||
case LayoutCode.Int32:
|
||||
return writer.WriteInt32(path, value == null ? default : (int)value);
|
||||
|
||||
case LayoutCode.Int64:
|
||||
return writer.WriteInt64(path, value == null ? default : (long)value);
|
||||
|
||||
case LayoutCode.UInt8:
|
||||
return writer.WriteUInt8(path, value == null ? default : (byte)value);
|
||||
|
||||
case LayoutCode.UInt16:
|
||||
return writer.WriteUInt16(path, value == null ? default : (ushort)value);
|
||||
|
||||
case LayoutCode.UInt32:
|
||||
return writer.WriteUInt32(path, value == null ? default : (uint)value);
|
||||
|
||||
case LayoutCode.UInt64:
|
||||
return writer.WriteUInt64(path, value == null ? default : (ulong)value);
|
||||
|
||||
case LayoutCode.VarInt:
|
||||
return writer.WriteVarInt(path, value == null ? default : (long)value);
|
||||
|
||||
case LayoutCode.VarUInt:
|
||||
return writer.WriteVarUInt(path, value == null ? default : (ulong)value);
|
||||
|
||||
case LayoutCode.Float32:
|
||||
return writer.WriteFloat32(path, value == null ? default : (float)value);
|
||||
|
||||
case LayoutCode.Float64:
|
||||
return writer.WriteFloat64(path, value == null ? default : (double)value);
|
||||
|
||||
case LayoutCode.Float128:
|
||||
return writer.WriteFloat128(path, value == null ? default : (Float128)value);
|
||||
|
||||
case LayoutCode.Decimal:
|
||||
return writer.WriteDecimal(path, value == null ? default : (decimal)value);
|
||||
|
||||
case LayoutCode.DateTime:
|
||||
return writer.WriteDateTime(path, value == null ? default : (DateTime)value);
|
||||
|
||||
case LayoutCode.UnixDateTime:
|
||||
return writer.WriteUnixDateTime(path, value == null ? default : (UnixDateTime)value);
|
||||
|
||||
case LayoutCode.Guid:
|
||||
return writer.WriteGuid(path, value == null ? default : (Guid)value);
|
||||
|
||||
case LayoutCode.MongoDbObjectId:
|
||||
return writer.WriteMongoDbObjectId(path, value == null ? default : (MongoDbObjectId)value);
|
||||
|
||||
case LayoutCode.Utf8:
|
||||
return writer.WriteString(path, value == null ? default : (Utf8String)value);
|
||||
|
||||
case LayoutCode.Binary:
|
||||
return writer.WriteBinary(path, value == null ? default : (byte[])value);
|
||||
|
||||
case LayoutCode.ObjectScope:
|
||||
case LayoutCode.ImmutableObjectScope:
|
||||
return StreamingRowGenerator.DispatchObject(ref writer, path, typeArg, value);
|
||||
|
||||
case LayoutCode.TypedArrayScope:
|
||||
case LayoutCode.ImmutableTypedArrayScope:
|
||||
return StreamingRowGenerator.DispatchArray(ref writer, path, typeArg, value);
|
||||
|
||||
case LayoutCode.TypedSetScope:
|
||||
case LayoutCode.ImmutableTypedSetScope:
|
||||
return StreamingRowGenerator.DispatchSet(ref writer, path, typeArg, value);
|
||||
|
||||
case LayoutCode.TypedMapScope:
|
||||
case LayoutCode.ImmutableTypedMapScope:
|
||||
return StreamingRowGenerator.DispatchMap(ref writer, path, typeArg, value);
|
||||
|
||||
case LayoutCode.TupleScope:
|
||||
case LayoutCode.ImmutableTupleScope:
|
||||
case LayoutCode.TypedTupleScope:
|
||||
case LayoutCode.ImmutableTypedTupleScope:
|
||||
case LayoutCode.TaggedScope:
|
||||
case LayoutCode.ImmutableTaggedScope:
|
||||
case LayoutCode.Tagged2Scope:
|
||||
case LayoutCode.ImmutableTagged2Scope:
|
||||
return StreamingRowGenerator.DispatchTuple(ref writer, path, typeArg, value);
|
||||
|
||||
case LayoutCode.NullableScope:
|
||||
case LayoutCode.ImmutableNullableScope:
|
||||
return StreamingRowGenerator.DispatchNullable(ref writer, path, typeArg, value);
|
||||
|
||||
case LayoutCode.Schema:
|
||||
case LayoutCode.ImmutableSchema:
|
||||
return StreamingRowGenerator.DispatchUDT(ref writer, path, typeArg, value);
|
||||
|
||||
default:
|
||||
Contract.Assert(false, $"Unknown type will be ignored: {typeArg}");
|
||||
return Result.Failure;
|
||||
}
|
||||
}
|
||||
|
||||
private static Result DispatchObject(ref RowWriter writer, Utf8String path, TypeArgument typeArg, object value)
|
||||
{
|
||||
return writer.WriteScope(
|
||||
path,
|
||||
typeArg,
|
||||
(Dictionary<Utf8String, object>)value,
|
||||
(ref RowWriter writer2, TypeArgument typeArg2, Dictionary<Utf8String, object> value2) =>
|
||||
{
|
||||
// TODO: support properties in an object scope.
|
||||
return Result.Success;
|
||||
});
|
||||
}
|
||||
|
||||
private static Result DispatchArray(ref RowWriter writer, Utf8String path, TypeArgument typeArg, object value)
|
||||
{
|
||||
Contract.Requires(typeArg.TypeArgs.Count == 1);
|
||||
|
||||
return writer.WriteScope(
|
||||
path,
|
||||
typeArg,
|
||||
(List<object>)value,
|
||||
(ref RowWriter writer2, TypeArgument typeArg2, List<object> items2) =>
|
||||
{
|
||||
foreach (object item in items2)
|
||||
{
|
||||
Result r = StreamingRowGenerator.LayoutCodeSwitch(ref writer2, null, typeArg2.TypeArgs[0], item);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
});
|
||||
}
|
||||
|
||||
private static Result DispatchTuple(ref RowWriter writer, Utf8String path, TypeArgument typeArg, object value)
|
||||
{
|
||||
Contract.Requires(typeArg.TypeArgs.Count >= 2);
|
||||
List<object> items = (List<object>)value;
|
||||
Contract.Assert(items.Count == typeArg.TypeArgs.Count);
|
||||
|
||||
return writer.WriteScope(
|
||||
path,
|
||||
typeArg,
|
||||
items,
|
||||
(ref RowWriter writer2, TypeArgument typeArg2, List<object> items2) =>
|
||||
{
|
||||
for (int i = 0; i < items2.Count; i++)
|
||||
{
|
||||
object item = items2[i];
|
||||
Result r = StreamingRowGenerator.LayoutCodeSwitch(ref writer2, null, typeArg2.TypeArgs[i], item);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
});
|
||||
}
|
||||
|
||||
private static Result DispatchNullable(ref RowWriter writer, Utf8String path, TypeArgument typeArg, object value)
|
||||
{
|
||||
Contract.Requires(typeArg.TypeArgs.Count == 1);
|
||||
|
||||
RowWriter.WriterFunc<object> f0 = null;
|
||||
if (value != null)
|
||||
{
|
||||
f0 = (ref RowWriter writer2, TypeArgument typeArg2, object value2) =>
|
||||
StreamingRowGenerator.LayoutCodeSwitch(ref writer2, null, typeArg2.TypeArgs[0], value2);
|
||||
}
|
||||
|
||||
return writer.WriteScope(path, typeArg, value, f0);
|
||||
}
|
||||
|
||||
private static Result DispatchSet(ref RowWriter writer, Utf8String path, TypeArgument typeArg, object value)
|
||||
{
|
||||
Contract.Requires(typeArg.TypeArgs.Count == 1);
|
||||
|
||||
return writer.WriteScope(
|
||||
path,
|
||||
typeArg,
|
||||
(List<object>)value,
|
||||
(ref RowWriter writer2, TypeArgument typeArg2, List<object> items2) =>
|
||||
{
|
||||
foreach (object item in items2)
|
||||
{
|
||||
Result r = StreamingRowGenerator.LayoutCodeSwitch(ref writer2, null, typeArg2.TypeArgs[0], item);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
});
|
||||
}
|
||||
|
||||
private static Result DispatchMap(ref RowWriter writer, Utf8String path, TypeArgument typeArg, object value)
|
||||
{
|
||||
Contract.Requires(typeArg.TypeArgs.Count == 2);
|
||||
|
||||
return writer.WriteScope(
|
||||
path,
|
||||
typeArg,
|
||||
(List<object>)value,
|
||||
(ref RowWriter writer2, TypeArgument typeArg2, List<object> items2) =>
|
||||
{
|
||||
TypeArgument fieldType = new TypeArgument(
|
||||
typeArg2.Type.Immutable ? LayoutType.ImmutableTypedTuple : LayoutType.TypedTuple,
|
||||
typeArg2.TypeArgs);
|
||||
|
||||
foreach (object item in items2)
|
||||
{
|
||||
Result r = StreamingRowGenerator.DispatchTuple(ref writer2, null, fieldType, item);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
});
|
||||
}
|
||||
|
||||
private static Result DispatchUDT(ref RowWriter writer, Utf8String path, TypeArgument typeArg, object value)
|
||||
{
|
||||
return writer.WriteScope(
|
||||
path,
|
||||
typeArg,
|
||||
(Dictionary<Utf8String, object>)value,
|
||||
(ref RowWriter writer2, TypeArgument typeArg2, Dictionary<Utf8String, object> dict) =>
|
||||
{
|
||||
Layout udt = writer2.Resolver.Resolve(typeArg2.TypeArgs.SchemaId);
|
||||
foreach (LayoutColumn c in udt.Columns)
|
||||
{
|
||||
Result result = StreamingRowGenerator.LayoutCodeSwitch(ref writer2, c.Path, c.TypeArg, dict[c.Path]);
|
||||
if (result != Result.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
260
dotnet/src/HybridRowGenerator/VisitRowGenerator.cs
Normal file
260
dotnet/src/HybridRowGenerator/VisitRowGenerator.cs
Normal file
@@ -0,0 +1,260 @@
|
||||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.Azure.Cosmos.Serialization.HybridRowGenerator
|
||||
{
|
||||
using System;
|
||||
using Microsoft.Azure.Cosmos.Core;
|
||||
using Microsoft.Azure.Cosmos.Serialization.HybridRow;
|
||||
using Microsoft.Azure.Cosmos.Serialization.HybridRow.Layouts;
|
||||
using Microsoft.Azure.Cosmos.Serialization.HybridRow.Schemas;
|
||||
|
||||
public ref struct VisitRowGenerator
|
||||
{
|
||||
private readonly LayoutResolver resolver;
|
||||
private RowBuffer row;
|
||||
|
||||
public VisitRowGenerator(Span<byte> span, LayoutResolver resolver)
|
||||
{
|
||||
this.resolver = resolver;
|
||||
this.row = new RowBuffer(span, HybridRowVersion.V1, this.resolver);
|
||||
}
|
||||
|
||||
public int Length => this.row.Length;
|
||||
|
||||
public Result DispatchLayout(Layout layout)
|
||||
{
|
||||
RowCursor scope = RowCursor.Create(ref this.row);
|
||||
return this.DispatchLayout(ref scope, layout);
|
||||
}
|
||||
|
||||
private Result LayoutCodeSwitch(
|
||||
ref RowCursor scope,
|
||||
LayoutColumn col = default,
|
||||
TypeArgument typeArg = default)
|
||||
{
|
||||
if (col != null)
|
||||
{
|
||||
typeArg = col.TypeArg;
|
||||
}
|
||||
|
||||
switch (typeArg.Type.LayoutCode)
|
||||
{
|
||||
case LayoutCode.ObjectScope:
|
||||
case LayoutCode.ImmutableObjectScope:
|
||||
return this.DispatchObject(ref scope, typeArg);
|
||||
|
||||
case LayoutCode.TypedArrayScope:
|
||||
case LayoutCode.ImmutableTypedArrayScope:
|
||||
return this.DispatchArray(ref scope, typeArg);
|
||||
|
||||
case LayoutCode.TypedSetScope:
|
||||
case LayoutCode.ImmutableTypedSetScope:
|
||||
return this.DispatchSet(ref scope, typeArg);
|
||||
|
||||
case LayoutCode.TypedMapScope:
|
||||
case LayoutCode.ImmutableTypedMapScope:
|
||||
return this.DispatchMap(ref scope, typeArg);
|
||||
|
||||
case LayoutCode.TupleScope:
|
||||
case LayoutCode.ImmutableTupleScope:
|
||||
case LayoutCode.TypedTupleScope:
|
||||
case LayoutCode.ImmutableTypedTupleScope:
|
||||
case LayoutCode.TaggedScope:
|
||||
case LayoutCode.ImmutableTaggedScope:
|
||||
case LayoutCode.Tagged2Scope:
|
||||
case LayoutCode.ImmutableTagged2Scope:
|
||||
return this.DispatchTuple(ref scope, typeArg);
|
||||
|
||||
case LayoutCode.NullableScope:
|
||||
case LayoutCode.ImmutableNullableScope:
|
||||
return this.DispatchNullable(ref scope, typeArg);
|
||||
|
||||
case LayoutCode.Schema:
|
||||
case LayoutCode.ImmutableSchema:
|
||||
return this.DispatchUDT(ref scope, typeArg);
|
||||
|
||||
default:
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
|
||||
private Result DispatchObject(ref RowCursor scope, TypeArgument t)
|
||||
{
|
||||
Result r = t.TypeAs<LayoutObject>().ReadScope(ref this.row, ref scope, out RowCursor childScope);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
// TODO: support properties in an object scope.
|
||||
scope.Skip(ref this.row, ref childScope);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private Result DispatchArray(ref RowCursor scope, TypeArgument t)
|
||||
{
|
||||
Contract.Assert(t.TypeArgs.Count == 1);
|
||||
|
||||
Result r = t.TypeAs<LayoutTypedArray>().ReadScope(ref this.row, ref scope, out RowCursor childScope);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
while (childScope.MoveNext(ref this.row))
|
||||
{
|
||||
r = this.LayoutCodeSwitch(ref childScope, null, t.TypeArgs[0]);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
scope.Skip(ref this.row, ref childScope);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private Result DispatchTuple(ref RowCursor scope, TypeArgument t)
|
||||
{
|
||||
Contract.Assert(t.TypeArgs.Count >= 2);
|
||||
Result r = t.TypeAs<LayoutIndexedScope>().ReadScope(ref this.row, ref scope, out RowCursor childScope);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
while (childScope.MoveNext(ref this.row))
|
||||
{
|
||||
r = this.LayoutCodeSwitch(ref childScope, null, t.TypeArgs[childScope.Index]);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
scope.Skip(ref this.row, ref childScope);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private Result DispatchNullable(ref RowCursor scope, TypeArgument t)
|
||||
{
|
||||
Contract.Assert(t.TypeArgs.Count == 1);
|
||||
|
||||
Result r = t.TypeAs<LayoutNullable>().ReadScope(ref this.row, ref scope, out RowCursor childScope);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
if (childScope.MoveNext(ref this.row))
|
||||
{
|
||||
r = this.LayoutCodeSwitch(ref childScope, null, t.TypeArgs[0]);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
scope.Skip(ref this.row, ref childScope);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private Result DispatchSet(ref RowCursor scope, TypeArgument t)
|
||||
{
|
||||
Contract.Assert(t.TypeArgs.Count == 1);
|
||||
|
||||
Result r = t.TypeAs<LayoutTypedSet>().ReadScope(ref this.row, ref scope, out RowCursor childScope);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
while (childScope.MoveNext(ref this.row))
|
||||
{
|
||||
r = this.LayoutCodeSwitch(ref childScope, null, t.TypeArgs[0]);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
scope.Skip(ref this.row, ref childScope);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private Result DispatchMap(ref RowCursor scope, TypeArgument t)
|
||||
{
|
||||
Contract.Assert(t.TypeArgs.Count == 2);
|
||||
|
||||
Result r = t.TypeAs<LayoutUniqueScope>().ReadScope(ref this.row, ref scope, out RowCursor childScope);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
TypeArgument fieldType = t.TypeAs<LayoutUniqueScope>().FieldType(ref childScope);
|
||||
while (childScope.MoveNext(ref this.row))
|
||||
{
|
||||
r = this.LayoutCodeSwitch(ref childScope, null, fieldType);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
scope.Skip(ref this.row, ref childScope);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private Result DispatchUDT(ref RowCursor scope, TypeArgument t)
|
||||
{
|
||||
Result r = t.TypeAs<LayoutUDT>().ReadScope(ref this.row, ref scope, out RowCursor childScope);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
Layout layout = this.resolver.Resolve(t.TypeArgs.SchemaId);
|
||||
r = this.DispatchLayout(ref childScope, layout);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
scope.Skip(ref this.row, ref childScope);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private Result DispatchLayout(ref RowCursor scope, Layout layout)
|
||||
{
|
||||
// Process schematized segment.
|
||||
foreach (LayoutColumn c in layout.Columns)
|
||||
{
|
||||
if (c.Storage == StorageKind.Sparse)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
Result r = this.LayoutCodeSwitch(ref scope, c);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
// Process sparse segment.
|
||||
while (scope.MoveNext(ref this.row))
|
||||
{
|
||||
Result r = this.LayoutCodeSwitch(ref scope, null, scope.TypeArg);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
502
dotnet/src/HybridRowGenerator/WriteRowGenerator.cs
Normal file
502
dotnet/src/HybridRowGenerator/WriteRowGenerator.cs
Normal file
@@ -0,0 +1,502 @@
|
||||
// ------------------------------------------------------------
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// ------------------------------------------------------------
|
||||
|
||||
namespace Microsoft.Azure.Cosmos.Serialization.HybridRowGenerator
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.Azure.Cosmos.Core;
|
||||
using Microsoft.Azure.Cosmos.Core.Utf8;
|
||||
using Microsoft.Azure.Cosmos.Serialization.HybridRow;
|
||||
using Microsoft.Azure.Cosmos.Serialization.HybridRow.IO;
|
||||
using Microsoft.Azure.Cosmos.Serialization.HybridRow.Layouts;
|
||||
using Microsoft.Azure.Cosmos.Serialization.HybridRow.Schemas;
|
||||
|
||||
[SuppressMessage("Microsoft.StyleCop.CSharp.OrderingRules", "SA1401", Justification = "Test types.")]
|
||||
public ref struct WriteRowGenerator
|
||||
{
|
||||
private RowBuffer row;
|
||||
|
||||
public WriteRowGenerator(int capacity, Layout layout, LayoutResolver resolver)
|
||||
{
|
||||
this.row = new RowBuffer(capacity);
|
||||
this.row.InitLayout(HybridRowVersion.V1, layout, resolver);
|
||||
}
|
||||
|
||||
public int Length => this.row.Length;
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Layout layout = this.row.Resolver.Resolve(this.row.Header.SchemaId);
|
||||
this.row.InitLayout(HybridRowVersion.V1, layout, this.row.Resolver);
|
||||
}
|
||||
|
||||
public RowReader GetReader()
|
||||
{
|
||||
return new RowReader(ref this.row);
|
||||
}
|
||||
|
||||
public Result DispatchLayout(Layout layout, Dictionary<Utf8String, object> dict)
|
||||
{
|
||||
RowCursor scope = RowCursor.Create(ref this.row);
|
||||
return WriteRowGenerator.DispatchLayout(ref this.row, ref scope, layout, dict);
|
||||
}
|
||||
|
||||
private static Result LayoutCodeSwitch(
|
||||
ref RowBuffer row,
|
||||
ref RowCursor scope,
|
||||
LayoutColumn col = default,
|
||||
TypeArgument typeArg = default,
|
||||
object value = null)
|
||||
{
|
||||
if (col != null)
|
||||
{
|
||||
typeArg = col.TypeArg;
|
||||
}
|
||||
|
||||
// ReSharper disable MergeConditionalExpression
|
||||
// ReSharper disable SimplifyConditionalTernaryExpression
|
||||
// ReSharper disable RedundantTypeSpecificationInDefaultExpression
|
||||
#pragma warning disable IDE0034 // Simplify 'default' expression
|
||||
switch (typeArg.Type.LayoutCode)
|
||||
{
|
||||
case LayoutCode.Null:
|
||||
return WriteRowGenerator.Dispatch<LayoutNull, NullValue>(ref row, ref scope, col, typeArg.Type, NullValue.Default);
|
||||
|
||||
case LayoutCode.Boolean:
|
||||
return WriteRowGenerator.Dispatch<LayoutBoolean, bool>(
|
||||
ref row,
|
||||
ref scope,
|
||||
col,
|
||||
typeArg.Type,
|
||||
value == null ? default(bool) : (bool)value);
|
||||
|
||||
case LayoutCode.Int8:
|
||||
return WriteRowGenerator.Dispatch<LayoutInt8, sbyte>(
|
||||
ref row,
|
||||
ref scope,
|
||||
col,
|
||||
typeArg.Type,
|
||||
value == null ? default(sbyte) : (sbyte)value);
|
||||
|
||||
case LayoutCode.Int16:
|
||||
return WriteRowGenerator.Dispatch<LayoutInt16, short>(
|
||||
ref row,
|
||||
ref scope,
|
||||
col,
|
||||
typeArg.Type,
|
||||
value == null ? default(short) : (short)value);
|
||||
|
||||
case LayoutCode.Int32:
|
||||
return WriteRowGenerator.Dispatch<LayoutInt32, int>(
|
||||
ref row,
|
||||
ref scope,
|
||||
col,
|
||||
typeArg.Type,
|
||||
value == null ? default(int) : (int)value);
|
||||
|
||||
case LayoutCode.Int64:
|
||||
return WriteRowGenerator.Dispatch<LayoutInt64, long>(
|
||||
ref row,
|
||||
ref scope,
|
||||
col,
|
||||
typeArg.Type,
|
||||
value == null ? default(long) : (long)value);
|
||||
|
||||
case LayoutCode.UInt8:
|
||||
return WriteRowGenerator.Dispatch<LayoutUInt8, byte>(
|
||||
ref row,
|
||||
ref scope,
|
||||
col,
|
||||
typeArg.Type,
|
||||
value == null ? default(byte) : (byte)value);
|
||||
|
||||
case LayoutCode.UInt16:
|
||||
return WriteRowGenerator.Dispatch<LayoutUInt16, ushort>(
|
||||
ref row,
|
||||
ref scope,
|
||||
col,
|
||||
typeArg.Type,
|
||||
value == null ? default(ushort) : (ushort)value);
|
||||
|
||||
case LayoutCode.UInt32:
|
||||
return WriteRowGenerator.Dispatch<LayoutUInt32, uint>(
|
||||
ref row,
|
||||
ref scope,
|
||||
col,
|
||||
typeArg.Type,
|
||||
value == null ? default(uint) : (uint)value);
|
||||
|
||||
case LayoutCode.UInt64:
|
||||
return WriteRowGenerator.Dispatch<LayoutUInt64, ulong>(
|
||||
ref row,
|
||||
ref scope,
|
||||
col,
|
||||
typeArg.Type,
|
||||
value == null ? default(ulong) : (ulong)value);
|
||||
|
||||
case LayoutCode.VarInt:
|
||||
return WriteRowGenerator.Dispatch<LayoutVarInt, long>(
|
||||
ref row,
|
||||
ref scope,
|
||||
col,
|
||||
typeArg.Type,
|
||||
value == null ? default(long) : (long)value);
|
||||
|
||||
case LayoutCode.VarUInt:
|
||||
return WriteRowGenerator.Dispatch<LayoutVarUInt, ulong>(
|
||||
ref row,
|
||||
ref scope,
|
||||
col,
|
||||
typeArg.Type,
|
||||
value == null ? default(ulong) : (ulong)value);
|
||||
|
||||
case LayoutCode.Float32:
|
||||
return WriteRowGenerator.Dispatch<LayoutFloat32, float>(
|
||||
ref row,
|
||||
ref scope,
|
||||
col,
|
||||
typeArg.Type,
|
||||
value == null ? default(float) : (float)value);
|
||||
|
||||
case LayoutCode.Float64:
|
||||
return WriteRowGenerator.Dispatch<LayoutFloat64, double>(
|
||||
ref row,
|
||||
ref scope,
|
||||
col,
|
||||
typeArg.Type,
|
||||
value == null ? default(double) : (double)value);
|
||||
|
||||
case LayoutCode.Float128:
|
||||
return WriteRowGenerator.Dispatch<LayoutFloat128, Float128>(
|
||||
ref row,
|
||||
ref scope,
|
||||
col,
|
||||
typeArg.Type,
|
||||
value == null ? default(Float128) : (Float128)value);
|
||||
|
||||
case LayoutCode.Decimal:
|
||||
return WriteRowGenerator.Dispatch<LayoutDecimal, decimal>(
|
||||
ref row,
|
||||
ref scope,
|
||||
col,
|
||||
typeArg.Type,
|
||||
value == null ? default(decimal) : (decimal)value);
|
||||
|
||||
case LayoutCode.DateTime:
|
||||
return WriteRowGenerator.Dispatch<LayoutDateTime, DateTime>(
|
||||
ref row,
|
||||
ref scope,
|
||||
col,
|
||||
typeArg.Type,
|
||||
value == null ? default(DateTime) : (DateTime)value);
|
||||
|
||||
case LayoutCode.UnixDateTime:
|
||||
return WriteRowGenerator.Dispatch<LayoutUnixDateTime, UnixDateTime>(
|
||||
ref row,
|
||||
ref scope,
|
||||
col,
|
||||
typeArg.Type,
|
||||
value == null ? default(UnixDateTime) : (UnixDateTime)value);
|
||||
|
||||
case LayoutCode.Guid:
|
||||
return WriteRowGenerator.Dispatch<LayoutGuid, Guid>(
|
||||
ref row,
|
||||
ref scope,
|
||||
col,
|
||||
typeArg.Type,
|
||||
value == null ? default(Guid) : (Guid)value);
|
||||
|
||||
case LayoutCode.MongoDbObjectId:
|
||||
return WriteRowGenerator.Dispatch<LayoutMongoDbObjectId, MongoDbObjectId>(
|
||||
ref row,
|
||||
ref scope,
|
||||
col,
|
||||
typeArg.Type,
|
||||
value == null ? default(MongoDbObjectId) : (MongoDbObjectId)value);
|
||||
|
||||
case LayoutCode.Utf8:
|
||||
return WriteRowGenerator.Dispatch(ref row, ref scope, col, (Utf8String)value);
|
||||
|
||||
case LayoutCode.Binary:
|
||||
return WriteRowGenerator.Dispatch<LayoutBinary, byte[]>(
|
||||
ref row,
|
||||
ref scope,
|
||||
col,
|
||||
typeArg.Type,
|
||||
value == null ? default(byte[]) : (byte[])value);
|
||||
|
||||
case LayoutCode.ObjectScope:
|
||||
case LayoutCode.ImmutableObjectScope:
|
||||
return WriteRowGenerator.DispatchObject(ref row, ref scope, typeArg, value);
|
||||
|
||||
case LayoutCode.TypedArrayScope:
|
||||
case LayoutCode.ImmutableTypedArrayScope:
|
||||
return WriteRowGenerator.DispatchArray(ref row, ref scope, typeArg, value);
|
||||
|
||||
case LayoutCode.TypedSetScope:
|
||||
case LayoutCode.ImmutableTypedSetScope:
|
||||
return WriteRowGenerator.DispatchSet(ref row, ref scope, typeArg, value);
|
||||
|
||||
case LayoutCode.TypedMapScope:
|
||||
case LayoutCode.ImmutableTypedMapScope:
|
||||
return WriteRowGenerator.DispatchMap(ref row, ref scope, typeArg, value);
|
||||
|
||||
case LayoutCode.TupleScope:
|
||||
case LayoutCode.ImmutableTupleScope:
|
||||
case LayoutCode.TypedTupleScope:
|
||||
case LayoutCode.ImmutableTypedTupleScope:
|
||||
case LayoutCode.TaggedScope:
|
||||
case LayoutCode.ImmutableTaggedScope:
|
||||
case LayoutCode.Tagged2Scope:
|
||||
case LayoutCode.ImmutableTagged2Scope:
|
||||
return WriteRowGenerator.DispatchTuple(ref row, ref scope, typeArg, value);
|
||||
|
||||
case LayoutCode.NullableScope:
|
||||
case LayoutCode.ImmutableNullableScope:
|
||||
return WriteRowGenerator.DispatchNullable(ref row, ref scope, typeArg, value);
|
||||
|
||||
case LayoutCode.Schema:
|
||||
case LayoutCode.ImmutableSchema:
|
||||
return WriteRowGenerator.DispatchUDT(ref row, ref scope, typeArg, value);
|
||||
|
||||
default:
|
||||
Contract.Assert(false, $"Unknown type will be ignored: {typeArg.Type.LayoutCode}");
|
||||
return Result.Failure;
|
||||
}
|
||||
|
||||
// ReSharper restore SimplifyConditionalTernaryExpression
|
||||
// ReSharper restore MergeConditionalExpression
|
||||
// ReSharper restore RedundantTypeSpecificationInDefaultExpression
|
||||
#pragma warning restore IDE0034 // Simplify 'default' expression
|
||||
}
|
||||
|
||||
private static Result Dispatch<TLayout, TValue>(ref RowBuffer row, ref RowCursor root, LayoutColumn col, LayoutType t, TValue value)
|
||||
where TLayout : LayoutType<TValue>
|
||||
{
|
||||
switch (col?.Storage)
|
||||
{
|
||||
case StorageKind.Fixed:
|
||||
return t.TypeAs<TLayout>().WriteFixed(ref row, ref root, col, value);
|
||||
|
||||
case StorageKind.Variable:
|
||||
return t.TypeAs<TLayout>().WriteVariable(ref row, ref root, col, value);
|
||||
|
||||
default:
|
||||
return t.TypeAs<TLayout>().WriteSparse(ref row, ref root, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static Result Dispatch(ref RowBuffer row, ref RowCursor root, LayoutColumn col, Utf8String value)
|
||||
{
|
||||
switch (col?.Storage)
|
||||
{
|
||||
case StorageKind.Fixed:
|
||||
return LayoutType.Utf8.WriteFixed(ref row, ref root, col, value);
|
||||
|
||||
case StorageKind.Variable:
|
||||
return LayoutType.Utf8.WriteVariable(ref row, ref root, col, value);
|
||||
|
||||
default:
|
||||
return LayoutType.Utf8.WriteSparse(ref row, ref root, value);
|
||||
}
|
||||
}
|
||||
|
||||
private static Result DispatchObject(ref RowBuffer row, ref RowCursor scope, TypeArgument t, object value)
|
||||
{
|
||||
Result r = t.TypeAs<LayoutObject>().WriteScope(ref row, ref scope, t.TypeArgs, out RowCursor childScope);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
// TODO: support properties in an object scope.
|
||||
Dictionary<Utf8String, object> dict = (Dictionary<Utf8String, object>)value;
|
||||
Contract.Assert(dict.Count == 0);
|
||||
scope.Skip(ref row, ref childScope);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private static Result DispatchArray(ref RowBuffer row, ref RowCursor scope, TypeArgument t, object value)
|
||||
{
|
||||
Contract.Assert(t.TypeArgs.Count == 1);
|
||||
|
||||
Result r = t.TypeAs<LayoutTypedArray>().WriteScope(ref row, ref scope, t.TypeArgs, out RowCursor childScope);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
List<object> items = (List<object>)value;
|
||||
foreach (object item in items)
|
||||
{
|
||||
r = WriteRowGenerator.LayoutCodeSwitch(ref row, ref childScope, null, t.TypeArgs[0], item);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
childScope.MoveNext(ref row);
|
||||
}
|
||||
|
||||
scope.Skip(ref row, ref childScope);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private static Result DispatchTuple(ref RowBuffer row, ref RowCursor scope, TypeArgument t, object value)
|
||||
{
|
||||
Contract.Assert(t.TypeArgs.Count >= 2);
|
||||
|
||||
return t.TypeAs<LayoutIndexedScope>()
|
||||
.WriteScope(
|
||||
ref row,
|
||||
ref scope,
|
||||
t.TypeArgs,
|
||||
(List<object>)value,
|
||||
(ref RowBuffer row2, ref RowCursor childScope, List<object> items) =>
|
||||
{
|
||||
Contract.Assert(items.Count == childScope.ScopeTypeArgs.Count);
|
||||
for (int i = 0; i < items.Count; i++)
|
||||
{
|
||||
Result r = WriteRowGenerator.LayoutCodeSwitch(ref row2, ref childScope, null, childScope.ScopeTypeArgs[i], items[i]);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
childScope.MoveNext(ref row2);
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
});
|
||||
}
|
||||
|
||||
private static Result DispatchNullable(ref RowBuffer row, ref RowCursor scope, TypeArgument t, object value)
|
||||
{
|
||||
Contract.Assert(t.TypeArgs.Count == 1);
|
||||
|
||||
bool hasValue = value != null;
|
||||
Result r = t.TypeAs<LayoutNullable>().WriteScope(ref row, ref scope, t.TypeArgs, hasValue, out RowCursor childScope);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
if (hasValue)
|
||||
{
|
||||
r = WriteRowGenerator.LayoutCodeSwitch(ref row, ref childScope, null, t.TypeArgs[0], value);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
childScope.MoveNext(ref row);
|
||||
}
|
||||
|
||||
scope.Skip(ref row, ref childScope);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private static Result DispatchSet(ref RowBuffer row, ref RowCursor scope, TypeArgument t, object value)
|
||||
{
|
||||
Contract.Assert(t.TypeArgs.Count == 1);
|
||||
|
||||
return t.TypeAs<LayoutTypedSet>()
|
||||
.WriteScope(
|
||||
ref row,
|
||||
ref scope,
|
||||
t.TypeArgs,
|
||||
(List<object>)value,
|
||||
(ref RowBuffer row2, ref RowCursor childScope, List<object> items) =>
|
||||
{
|
||||
foreach (object item in items)
|
||||
{
|
||||
Result r = WriteRowGenerator.LayoutCodeSwitch(ref row2, ref childScope, null, childScope.ScopeTypeArgs[0], item);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
childScope.MoveNext(ref row2);
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
});
|
||||
}
|
||||
|
||||
private static Result DispatchMap(ref RowBuffer row, ref RowCursor scope, TypeArgument t, object value)
|
||||
{
|
||||
Contract.Assert(t.TypeArgs.Count == 2);
|
||||
return t.TypeAs<LayoutUniqueScope>()
|
||||
.WriteScope(
|
||||
ref row,
|
||||
ref scope,
|
||||
t.TypeArgs,
|
||||
(List<object>)value,
|
||||
(ref RowBuffer row2, ref RowCursor childScope, List<object> pairs) =>
|
||||
{
|
||||
TypeArgument fieldType = childScope.ScopeType.TypeAs<LayoutUniqueScope>().FieldType(ref childScope);
|
||||
foreach (object elm in pairs)
|
||||
{
|
||||
Result r = WriteRowGenerator.LayoutCodeSwitch(ref row2, ref childScope, null, fieldType, elm);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
childScope.MoveNext(ref row2);
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
});
|
||||
}
|
||||
|
||||
private static Result DispatchUDT(ref RowBuffer row, ref RowCursor scope, TypeArgument t, object value)
|
||||
{
|
||||
Result r = t.TypeAs<LayoutUDT>().WriteScope(ref row, ref scope, t.TypeArgs, out RowCursor childScope);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
Dictionary<Utf8String, object> dict = (Dictionary<Utf8String, object>)value;
|
||||
Layout layout = row.Resolver.Resolve(t.TypeArgs.SchemaId);
|
||||
r = WriteRowGenerator.DispatchLayout(ref row, ref childScope, layout, dict);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
scope.Skip(ref row, ref childScope);
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private static Result DispatchLayout(ref RowBuffer row, ref RowCursor scope, Layout layout, Dictionary<Utf8String, object> dict)
|
||||
{
|
||||
foreach (LayoutColumn c in layout.Columns)
|
||||
{
|
||||
if (c.Storage != StorageKind.Sparse)
|
||||
{
|
||||
Result r = WriteRowGenerator.LayoutCodeSwitch(ref row, ref scope, c, value: dict[c.Path]);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
scope.Find(ref row, c.Path);
|
||||
Result r = WriteRowGenerator.LayoutCodeSwitch(ref row, ref scope, null, c.TypeArg, dict[c.Path]);
|
||||
if (r != Result.Success)
|
||||
{
|
||||
return r;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Result.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user