Delete the in-tree cache, JsonKnownTypes and vendored MessagePack
Cut 8b, deletes first. The old authorities are removed, not demoted: - ServerShared/CultCache: CultCache.cs, DatabaseEntry.cs (root [Union], DatabaseLink, INamedEntry), RegisterResolver.cs, TypeFormatterResolver.cs, JsonConverters.cs, JsonKnownTypes/**. - Assets/Plugins/MessagePack/** and System.Runtime.CompilerServices.Unsafe.dll (org.gamecult.cultlib ships both). - GalaxyMapLayerData, PlayerData, GlobalSettingsAttribute. - The inspector attributes CultLib already carries or nothing reads. Kept and moved: MathFormatters.cs and MathResolver.cs to ServerShared/Serialization; GetAllChildClasses, SplitCamelCase, FormatTypeName, MaxBy and MinBy to Extensions.cs; Inspectable, PreferredInspectorAttribute and the five Aetheria drawer attributes to ServerShared/Attributes.cs. Aetheria.Shared.csproj drops the vendored MessagePack include and the Unsafe package; the asmdef drops MessagePack. Does not build: the data model moves onto CultLib in the next commit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
d3db1730ad
commit
b4c06b50cb
266 changed files with 67 additions and 33150 deletions
|
|
@ -3,7 +3,7 @@
|
|||
Compiles ServerShared and its dependencies from source with no Unity defines, so a successful build is the
|
||||
check that the simulation stays independent of the engine. Tools and test harnesses reference this project. -->
|
||||
<PropertyGroup>
|
||||
<!-- Unity compiles ServerShared against .NET Standard 2.1; newer targets also impose C# 11 ref-safety rules the vendored MessagePack predates -->
|
||||
<!-- Unity compiles ServerShared against .NET Standard 2.1 -->
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<LangVersion>9.0</LangVersion>
|
||||
<Nullable>disable</Nullable>
|
||||
|
|
@ -18,7 +18,6 @@
|
|||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="$(Assets)Scripts\ServerShared\**\*.cs" />
|
||||
<Compile Include="$(Assets)Plugins\MessagePack\**\*.cs" Exclude="$(Assets)Plugins\MessagePack\Unity\**" />
|
||||
<Compile Include="$(Assets)Plugins\UniRx\Scripts\**\*.cs" Exclude="$(Assets)Plugins\UniRx\Scripts\UnityEngineBridge\**;$(Assets)Plugins\UniRx\Scripts\UnityWinRTBridge\**;$(Assets)Plugins\UniRx\Scripts\InternalUtil\MicroCoroutine.cs" />
|
||||
<!-- The reactive collections live in UniRx's Unity bridge but fence their Unity parts behind UniRxLibrary -->
|
||||
<Compile Include="$(Assets)Plugins\UniRx\Scripts\UnityEngineBridge\ReactiveProperty.cs;$(Assets)Plugins\UniRx\Scripts\UnityEngineBridge\ReactiveCollection.cs;$(Assets)Plugins\UniRx\Scripts\UnityEngineBridge\ReactiveDictionary.cs" />
|
||||
|
|
@ -27,7 +26,5 @@
|
|||
<ItemGroup>
|
||||
<ProjectReference Include="$(CultLibRoot)\packages\cultmath\src\CultMath\CultMath.csproj" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<!-- Bundled by Unity; .NET Standard 2.1 lacks it -->
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 78d7ac1a75fbd3f4d91b72ac2de5f552
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 258cef354b8273b4ca696ab53c01327a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
|
||||
#pragma warning disable SA1649 // File name should match first type name
|
||||
|
||||
namespace MessagePack
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = true)]
|
||||
public class MessagePackObjectAttribute : Attribute
|
||||
{
|
||||
public bool KeyAsPropertyName { get; private set; }
|
||||
|
||||
public MessagePackObjectAttribute(bool keyAsPropertyName = false)
|
||||
{
|
||||
this.KeyAsPropertyName = keyAsPropertyName;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
|
||||
public class KeyAttribute : Attribute
|
||||
{
|
||||
public int? IntKey { get; private set; }
|
||||
|
||||
public string StringKey { get; private set; }
|
||||
|
||||
public KeyAttribute(int x)
|
||||
{
|
||||
this.IntKey = x;
|
||||
}
|
||||
|
||||
public KeyAttribute(string x)
|
||||
{
|
||||
this.StringKey = x;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
|
||||
public class IgnoreMemberAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
|
||||
public class UnionAttribute : Attribute
|
||||
{
|
||||
public int Key { get; private set; }
|
||||
|
||||
public Type SubType { get; private set; }
|
||||
|
||||
public UnionAttribute(int key, Type subType)
|
||||
{
|
||||
this.Key = key;
|
||||
this.SubType = subType;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = true)]
|
||||
public class SerializationConstructorAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Enum | AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
|
||||
public class MessagePackFormatterAttribute : Attribute
|
||||
{
|
||||
public Type FormatterType { get; private set; }
|
||||
|
||||
public object[] Arguments { get; private set; }
|
||||
|
||||
public MessagePackFormatterAttribute(Type formatterType)
|
||||
{
|
||||
this.FormatterType = formatterType;
|
||||
}
|
||||
|
||||
public MessagePackFormatterAttribute(Type formatterType, params object[] arguments)
|
||||
{
|
||||
this.FormatterType = formatterType;
|
||||
this.Arguments = arguments;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: db21d74c4f54408a9acd69873192155c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace MessagePack
|
||||
{
|
||||
public interface IMessagePackSerializationCallbackReceiver
|
||||
{
|
||||
void OnBeforeSerialize();
|
||||
|
||||
void OnAfterDeserialize();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ef32599edd0f43366891b8da5d4aed1e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
// <auto-generated />
|
||||
|
||||
#if !NETCOREAPP
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
// Some routines inspired by the Stanford Bit Twiddling Hacks by Sean Eron Anderson:
|
||||
// http://graphics.stanford.edu/~seander/bithacks.html
|
||||
|
||||
namespace System.Numerics
|
||||
{
|
||||
/// <summary>
|
||||
/// Utility methods for intrinsic bit-twiddling operations.
|
||||
/// The methods use hardware intrinsics when available on the underlying platform,
|
||||
/// otherwise they use optimized software fallbacks.
|
||||
/// </summary>
|
||||
internal static class BitOperations
|
||||
{
|
||||
/// <summary>
|
||||
/// Rotates the specified value left by the specified number of bits.
|
||||
/// Similar in behavior to the x86 instruction ROL.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to rotate.</param>
|
||||
/// <param name="offset">The number of bits to rotate by.
|
||||
/// Any value outside the range [0..31] is treated as congruent mod 32.</param>
|
||||
/// <returns>The rotated value.</returns>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint RotateLeft(uint value, int offset)
|
||||
=> (value << offset) | (value >> (32 - offset));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3c1e411a42f526567af32d094a9de348
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,260 +0,0 @@
|
|||
// <auto-generated /> // We want to keep this file as-is since it's shared with other repos.
|
||||
|
||||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Copyright (c) Andrew Arnott. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MessagePack
|
||||
{
|
||||
/// <summary>
|
||||
/// A fast access struct that wraps <see cref="IBufferWriter{T}"/>.
|
||||
/// </summary>
|
||||
internal ref struct BufferWriter
|
||||
{
|
||||
/// <summary>
|
||||
/// The underlying <see cref="IBufferWriter{T}"/>.
|
||||
/// </summary>
|
||||
private IBufferWriter<byte> _output;
|
||||
|
||||
/// <summary>
|
||||
/// The result of the last call to <see cref="IBufferWriter{T}.GetSpan(int)"/>, less any bytes already "consumed" with <see cref="Advance(int)"/>.
|
||||
/// Backing field for the <see cref="Span"/> property.
|
||||
/// </summary>
|
||||
private Span<byte> _span;
|
||||
|
||||
/// <summary>
|
||||
/// The result of the last call to <see cref="IBufferWriter{T}.GetMemory(int)"/>, less any bytes already "consumed" with <see cref="Advance(int)"/>.
|
||||
/// </summary>
|
||||
private ArraySegment<byte> _segment;
|
||||
|
||||
/// <summary>
|
||||
/// The number of uncommitted bytes (all the calls to <see cref="Advance(int)"/> since the last call to <see cref="Commit"/>).
|
||||
/// </summary>
|
||||
private int _buffered;
|
||||
|
||||
/// <summary>
|
||||
/// The total number of bytes written with this writer.
|
||||
/// Backing field for the <see cref="BytesCommitted"/> property.
|
||||
/// </summary>
|
||||
private long _bytesCommitted;
|
||||
|
||||
private SequencePool _sequencePool;
|
||||
|
||||
private SequencePool.Rental _rental;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BufferWriter"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="output">The <see cref="IBufferWriter{T}"/> to be wrapped.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public BufferWriter(IBufferWriter<byte> output)
|
||||
{
|
||||
_buffered = 0;
|
||||
_bytesCommitted = 0;
|
||||
_output = output ?? throw new ArgumentNullException(nameof(output));
|
||||
|
||||
_sequencePool = default;
|
||||
_rental = default;
|
||||
|
||||
var memory = _output.GetMemoryCheckResult();
|
||||
MemoryMarshal.TryGetArray(memory, out _segment);
|
||||
_span = memory.Span;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BufferWriter"/> struct.
|
||||
/// </summary>
|
||||
/// <param name="sequencePool">The pool from which to draw an <see cref="IBufferWriter{T}"/> if required..</param>
|
||||
/// <param name="array">An array to start with so we can avoid accessing the <paramref name="sequencePool"/> if possible.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
internal BufferWriter(SequencePool sequencePool, byte[] array)
|
||||
{
|
||||
_buffered = 0;
|
||||
_bytesCommitted = 0;
|
||||
_sequencePool = sequencePool ?? throw new ArgumentNullException(nameof(sequencePool));
|
||||
_rental = default;
|
||||
_output = null;
|
||||
|
||||
_segment = new ArraySegment<byte>(array);
|
||||
_span = _segment.AsSpan();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the result of the last call to <see cref="IBufferWriter{T}.GetSpan(int)"/>.
|
||||
/// </summary>
|
||||
public Span<byte> Span => _span;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total number of bytes written with this writer.
|
||||
/// </summary>
|
||||
public long BytesCommitted => _bytesCommitted;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IBufferWriter{T}"/> underlying this instance.
|
||||
/// </summary>
|
||||
internal IBufferWriter<byte> UnderlyingWriter => _output;
|
||||
|
||||
internal SequencePool.Rental SequenceRental => _rental;
|
||||
|
||||
public Span<byte> GetSpan(int sizeHint)
|
||||
{
|
||||
Ensure(sizeHint);
|
||||
return this.Span;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public ref byte GetPointer(int sizeHint)
|
||||
{
|
||||
Ensure(sizeHint);
|
||||
|
||||
if (_segment.Array != null)
|
||||
{
|
||||
return ref _segment.Array[_segment.Offset + _buffered];
|
||||
}
|
||||
else
|
||||
{
|
||||
return ref _span.GetPinnableReference();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls <see cref="IBufferWriter{T}.Advance(int)"/> on the underlying writer
|
||||
/// with the number of uncommitted bytes.
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Commit()
|
||||
{
|
||||
var buffered = _buffered;
|
||||
if (buffered > 0)
|
||||
{
|
||||
this.MigrateToSequence();
|
||||
|
||||
_bytesCommitted += buffered;
|
||||
_buffered = 0;
|
||||
_output.Advance(buffered);
|
||||
_span = default;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to indicate that part of the buffer has been written to.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of bytes written to.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Advance(int count)
|
||||
{
|
||||
_buffered += count;
|
||||
_span = _span.Slice(count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the caller's buffer into this writer and calls <see cref="Advance(int)"/> with the length of the source buffer.
|
||||
/// </summary>
|
||||
/// <param name="source">The buffer to copy in.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Write(ReadOnlySpan<byte> source)
|
||||
{
|
||||
if (_span.Length >= source.Length)
|
||||
{
|
||||
source.CopyTo(_span);
|
||||
Advance(source.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteMultiBuffer(source);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Acquires a new buffer if necessary to ensure that some given number of bytes can be written to a single buffer.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of bytes that must be allocated in a single buffer.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Ensure(int count = 1)
|
||||
{
|
||||
if (_span.Length < count)
|
||||
{
|
||||
EnsureMore(count);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the span to the bytes written if they were never committed to the underlying buffer writer.
|
||||
/// </summary>
|
||||
/// <param name="span"></param>
|
||||
/// <returns></returns>
|
||||
internal bool TryGetUncommittedSpan(out ReadOnlySpan<byte> span)
|
||||
{
|
||||
if (this._sequencePool != null)
|
||||
{
|
||||
span = _segment.AsSpan(0, _buffered);
|
||||
return true;
|
||||
}
|
||||
|
||||
span = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a fresh span to write to, with an optional minimum size.
|
||||
/// </summary>
|
||||
/// <param name="count">The minimum size for the next requested buffer.</param>
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
private void EnsureMore(int count = 0)
|
||||
{
|
||||
if (_buffered > 0)
|
||||
{
|
||||
Commit();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.MigrateToSequence();
|
||||
}
|
||||
|
||||
var memory = _output.GetMemoryCheckResult(count);
|
||||
MemoryMarshal.TryGetArray(memory, out _segment);
|
||||
_span = memory.Span;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the caller's buffer into this writer, potentially across multiple buffers from the underlying writer.
|
||||
/// </summary>
|
||||
/// <param name="source">The buffer to copy into this writer.</param>
|
||||
private void WriteMultiBuffer(ReadOnlySpan<byte> source)
|
||||
{
|
||||
int copiedBytes = 0;
|
||||
int bytesLeftToCopy = source.Length;
|
||||
while (bytesLeftToCopy > 0)
|
||||
{
|
||||
if (_span.Length == 0)
|
||||
{
|
||||
EnsureMore();
|
||||
}
|
||||
|
||||
var writable = Math.Min(bytesLeftToCopy, _span.Length);
|
||||
source.Slice(copiedBytes, writable).CopyTo(_span);
|
||||
copiedBytes += writable;
|
||||
bytesLeftToCopy -= writable;
|
||||
Advance(writable);
|
||||
}
|
||||
}
|
||||
|
||||
private void MigrateToSequence()
|
||||
{
|
||||
if (this._sequencePool != null)
|
||||
{
|
||||
// We were writing to our private scratch memory, so we have to copy it into the actual writer.
|
||||
_rental = _sequencePool.Rent();
|
||||
_output = _rental.Value;
|
||||
var realSpan = _output.GetSpan(_buffered);
|
||||
_segment.AsSpan(0, _buffered).CopyTo(realSpan);
|
||||
_sequencePool = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 91a2222860edec5ff9ee6e4fe1af7668
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace MessagePack
|
||||
{
|
||||
#if MESSAGEPACK_INTERNAL
|
||||
internal
|
||||
#else
|
||||
public
|
||||
#endif
|
||||
struct ExtensionHeader : IEquatable<ExtensionHeader>
|
||||
{
|
||||
public sbyte TypeCode { get; private set; }
|
||||
|
||||
public uint Length { get; private set; }
|
||||
|
||||
public ExtensionHeader(sbyte typeCode, uint length)
|
||||
{
|
||||
this.TypeCode = typeCode;
|
||||
this.Length = length;
|
||||
}
|
||||
|
||||
public ExtensionHeader(sbyte typeCode, int length)
|
||||
{
|
||||
this.TypeCode = typeCode;
|
||||
this.Length = (uint)length;
|
||||
}
|
||||
|
||||
public bool Equals(ExtensionHeader other) => this.TypeCode == other.TypeCode && this.Length == other.Length;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 92a76851178ab369fbc386556cb866ce
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
|
||||
namespace MessagePack
|
||||
{
|
||||
#if MESSAGEPACK_INTERNAL
|
||||
internal
|
||||
#else
|
||||
public
|
||||
#endif
|
||||
struct ExtensionResult
|
||||
{
|
||||
public ExtensionResult(sbyte typeCode, Memory<byte> data)
|
||||
{
|
||||
this.TypeCode = typeCode;
|
||||
this.Data = new ReadOnlySequence<byte>(data);
|
||||
}
|
||||
|
||||
public ExtensionResult(sbyte typeCode, ReadOnlySequence<byte> data)
|
||||
{
|
||||
this.TypeCode = typeCode;
|
||||
this.Data = data;
|
||||
}
|
||||
|
||||
public sbyte TypeCode { get; private set; }
|
||||
|
||||
public ReadOnlySequence<byte> Data { get; private set; }
|
||||
|
||||
public ExtensionHeader Header => new ExtensionHeader(this.TypeCode, (uint)this.Data.Length);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 153f71ac242b4218d9debb5971c7b5d4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4e7629820f4485c4790dbe9265bb2830
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f92b8946eec0ab476a689a0dfa8c2498
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides general helpers for creating collections (including dictionaries).
|
||||
/// </summary>
|
||||
/// <typeparam name="TCollection">The concrete type of collection to create.</typeparam>
|
||||
/// <typeparam name="TEqualityComparer">The type of equality comparer that we would hope to pass into the collection's constructor.</typeparam>
|
||||
internal static class CollectionHelpers<TCollection, TEqualityComparer>
|
||||
where TCollection : new()
|
||||
{
|
||||
/// <summary>
|
||||
/// The delegate that will create the collection, if the typical (int count, IEqualityComparer{T} equalityComparer) constructor was found.
|
||||
/// </summary>
|
||||
private static Func<int, TEqualityComparer, TCollection> collectionCreator;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes static members of the <see cref="CollectionHelpers{TCollection, TEqualityComparer}"/> class.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Initializes a delegate that is optimized to create a collection of a given size and using the given equality comparer, if possible.
|
||||
/// </remarks>
|
||||
static CollectionHelpers()
|
||||
{
|
||||
var ctor = typeof(TCollection).GetConstructor(new Type[] { typeof(int), typeof(TEqualityComparer) });
|
||||
if (ctor != null)
|
||||
{
|
||||
ParameterExpression param1 = Expression.Parameter(typeof(int), "count");
|
||||
ParameterExpression param2 = Expression.Parameter(typeof(TEqualityComparer), "equalityComparer");
|
||||
NewExpression body = Expression.New(ctor, param1, param2);
|
||||
collectionCreator = Expression.Lambda<Func<int, TEqualityComparer, TCollection>>(body, param1, param2).Compile();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <typeparamref name="TCollection"/> collection.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of elements the collection should be prepared to receive.</param>
|
||||
/// <param name="equalityComparer">The equality comparer to initialize the collection with.</param>
|
||||
/// <returns>The newly initialized collection.</returns>
|
||||
/// <remarks>
|
||||
/// Use of the <paramref name="count"/> and <paramref name="equalityComparer"/> are a best effort.
|
||||
/// If we can't find a constructor on the collection in the expected shape, we'll just instantiate the collection with its default constructor.
|
||||
/// </remarks>
|
||||
internal static TCollection CreateHashCollection(int count, TEqualityComparer equalityComparer) => collectionCreator != null ? collectionCreator.Invoke(count, equalityComparer) : new TCollection();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 25f9fe82ddb369c8f9600901293b80f8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
|
||||
#pragma warning disable SA1649 // File name should match first type name
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
/// <summary>
|
||||
/// Serialize by .NET native DateTime binary format.
|
||||
/// </summary>
|
||||
public sealed class NativeDateTimeFormatter : IMessagePackFormatter<DateTime>
|
||||
{
|
||||
public static readonly NativeDateTimeFormatter Instance = new NativeDateTimeFormatter();
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, DateTime value, MessagePackSerializerOptions options)
|
||||
{
|
||||
var dateData = value.ToBinary();
|
||||
writer.Write(dateData);
|
||||
}
|
||||
|
||||
public DateTime Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
var dateData = reader.ReadInt64();
|
||||
return DateTime.FromBinary(dateData);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class NativeDateTimeArrayFormatter : IMessagePackFormatter<DateTime[]>
|
||||
{
|
||||
public static readonly NativeDateTimeArrayFormatter Instance = new NativeDateTimeArrayFormatter();
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, DateTime[] value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteArrayHeader(value.Length);
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
{
|
||||
writer.Write(value[i].ToBinary());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DateTime[] Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var len = reader.ReadArrayHeader();
|
||||
var array = new DateTime[len];
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
var dateData = reader.ReadInt64();
|
||||
array[i] = DateTime.FromBinary(dateData);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e28b94bd9483c36efae78067f97c65cb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,280 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Reflection;
|
||||
|
||||
#pragma warning disable SA1649 // File name should match first type name
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
// unfortunately, can't use IDictionary<KVP> because supports IReadOnlyDictionary.
|
||||
public abstract class DictionaryFormatterBase<TKey, TValue, TIntermediate, TEnumerator, TDictionary> : IMessagePackFormatter<TDictionary>
|
||||
where TDictionary : IEnumerable<KeyValuePair<TKey, TValue>>
|
||||
where TEnumerator : IEnumerator<KeyValuePair<TKey, TValue>>
|
||||
{
|
||||
public void Serialize(ref MessagePackWriter writer, TDictionary value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
IFormatterResolver resolver = options.Resolver;
|
||||
IMessagePackFormatter<TKey> keyFormatter = resolver.GetFormatterWithVerify<TKey>();
|
||||
IMessagePackFormatter<TValue> valueFormatter = resolver.GetFormatterWithVerify<TValue>();
|
||||
|
||||
int count;
|
||||
{
|
||||
var col = value as ICollection<KeyValuePair<TKey, TValue>>;
|
||||
if (col != null)
|
||||
{
|
||||
count = col.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
var col2 = value as IReadOnlyCollection<KeyValuePair<TKey, TValue>>;
|
||||
if (col2 != null)
|
||||
{
|
||||
count = col2.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new MessagePackSerializationException("DictionaryFormatterBase's TDictionary supports only ICollection<KVP> or IReadOnlyCollection<KVP>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writer.WriteMapHeader(count);
|
||||
|
||||
TEnumerator e = this.GetSourceEnumerator(value);
|
||||
try
|
||||
{
|
||||
while (e.MoveNext())
|
||||
{
|
||||
writer.CancellationToken.ThrowIfCancellationRequested();
|
||||
KeyValuePair<TKey, TValue> item = e.Current;
|
||||
keyFormatter.Serialize(ref writer, item.Key, options);
|
||||
valueFormatter.Serialize(ref writer, item.Value, options);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
e.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public TDictionary Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return default(TDictionary);
|
||||
}
|
||||
else
|
||||
{
|
||||
IFormatterResolver resolver = options.Resolver;
|
||||
IMessagePackFormatter<TKey> keyFormatter = resolver.GetFormatterWithVerify<TKey>();
|
||||
IMessagePackFormatter<TValue> valueFormatter = resolver.GetFormatterWithVerify<TValue>();
|
||||
|
||||
var len = reader.ReadMapHeader();
|
||||
|
||||
TIntermediate dict = this.Create(len, options);
|
||||
options.Security.DepthStep(ref reader);
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
reader.CancellationToken.ThrowIfCancellationRequested();
|
||||
TKey key = keyFormatter.Deserialize(ref reader, options);
|
||||
|
||||
TValue value = valueFormatter.Deserialize(ref reader, options);
|
||||
|
||||
this.Add(dict, i, key, value, options);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Depth--;
|
||||
}
|
||||
|
||||
return this.Complete(dict);
|
||||
}
|
||||
}
|
||||
|
||||
// abstraction for serialize
|
||||
|
||||
// Some collections can use struct iterator, this is optimization path
|
||||
protected abstract TEnumerator GetSourceEnumerator(TDictionary source);
|
||||
|
||||
// abstraction for deserialize
|
||||
protected abstract TIntermediate Create(int count, MessagePackSerializerOptions options);
|
||||
|
||||
protected abstract void Add(TIntermediate collection, int index, TKey key, TValue value, MessagePackSerializerOptions options);
|
||||
|
||||
protected abstract TDictionary Complete(TIntermediate intermediateCollection);
|
||||
}
|
||||
|
||||
public abstract class DictionaryFormatterBase<TKey, TValue, TIntermediate, TDictionary> : DictionaryFormatterBase<TKey, TValue, TIntermediate, IEnumerator<KeyValuePair<TKey, TValue>>, TDictionary>
|
||||
where TDictionary : IEnumerable<KeyValuePair<TKey, TValue>>
|
||||
{
|
||||
protected override IEnumerator<KeyValuePair<TKey, TValue>> GetSourceEnumerator(TDictionary source)
|
||||
{
|
||||
return source.GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class DictionaryFormatterBase<TKey, TValue, TDictionary> : DictionaryFormatterBase<TKey, TValue, TDictionary, TDictionary>
|
||||
where TDictionary : IDictionary<TKey, TValue>
|
||||
{
|
||||
protected override TDictionary Complete(TDictionary intermediateCollection)
|
||||
{
|
||||
return intermediateCollection;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DictionaryFormatter<TKey, TValue> : DictionaryFormatterBase<TKey, TValue, Dictionary<TKey, TValue>, Dictionary<TKey, TValue>.Enumerator, Dictionary<TKey, TValue>>
|
||||
{
|
||||
protected override void Add(Dictionary<TKey, TValue> collection, int index, TKey key, TValue value, MessagePackSerializerOptions options)
|
||||
{
|
||||
collection.Add(key, value);
|
||||
}
|
||||
|
||||
protected override Dictionary<TKey, TValue> Complete(Dictionary<TKey, TValue> intermediateCollection)
|
||||
{
|
||||
return intermediateCollection;
|
||||
}
|
||||
|
||||
protected override Dictionary<TKey, TValue> Create(int count, MessagePackSerializerOptions options)
|
||||
{
|
||||
return new Dictionary<TKey, TValue>(count, options.Security.GetEqualityComparer<TKey>());
|
||||
}
|
||||
|
||||
protected override Dictionary<TKey, TValue>.Enumerator GetSourceEnumerator(Dictionary<TKey, TValue> source)
|
||||
{
|
||||
return source.GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class GenericDictionaryFormatter<TKey, TValue, TDictionary> : DictionaryFormatterBase<TKey, TValue, TDictionary>
|
||||
where TDictionary : IDictionary<TKey, TValue>, new()
|
||||
{
|
||||
protected override void Add(TDictionary collection, int index, TKey key, TValue value, MessagePackSerializerOptions options)
|
||||
{
|
||||
collection.Add(key, value);
|
||||
}
|
||||
|
||||
protected override TDictionary Create(int count, MessagePackSerializerOptions options)
|
||||
{
|
||||
return CollectionHelpers<TDictionary, IEqualityComparer<TKey>>.CreateHashCollection(count, options.Security.GetEqualityComparer<TKey>());
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class InterfaceDictionaryFormatter<TKey, TValue> : DictionaryFormatterBase<TKey, TValue, Dictionary<TKey, TValue>, IDictionary<TKey, TValue>>
|
||||
{
|
||||
protected override void Add(Dictionary<TKey, TValue> collection, int index, TKey key, TValue value, MessagePackSerializerOptions options)
|
||||
{
|
||||
collection.Add(key, value);
|
||||
}
|
||||
|
||||
protected override Dictionary<TKey, TValue> Create(int count, MessagePackSerializerOptions options)
|
||||
{
|
||||
return new Dictionary<TKey, TValue>(count, options.Security.GetEqualityComparer<TKey>());
|
||||
}
|
||||
|
||||
protected override IDictionary<TKey, TValue> Complete(Dictionary<TKey, TValue> intermediateCollection)
|
||||
{
|
||||
return intermediateCollection;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SortedListFormatter<TKey, TValue> : DictionaryFormatterBase<TKey, TValue, SortedList<TKey, TValue>>
|
||||
{
|
||||
protected override void Add(SortedList<TKey, TValue> collection, int index, TKey key, TValue value, MessagePackSerializerOptions options)
|
||||
{
|
||||
collection.Add(key, value);
|
||||
}
|
||||
|
||||
protected override SortedList<TKey, TValue> Create(int count, MessagePackSerializerOptions options)
|
||||
{
|
||||
return new SortedList<TKey, TValue>(count);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class SortedDictionaryFormatter<TKey, TValue> : DictionaryFormatterBase<TKey, TValue, SortedDictionary<TKey, TValue>, SortedDictionary<TKey, TValue>.Enumerator, SortedDictionary<TKey, TValue>>
|
||||
{
|
||||
protected override void Add(SortedDictionary<TKey, TValue> collection, int index, TKey key, TValue value, MessagePackSerializerOptions options)
|
||||
{
|
||||
collection.Add(key, value);
|
||||
}
|
||||
|
||||
protected override SortedDictionary<TKey, TValue> Complete(SortedDictionary<TKey, TValue> intermediateCollection)
|
||||
{
|
||||
return intermediateCollection;
|
||||
}
|
||||
|
||||
protected override SortedDictionary<TKey, TValue> Create(int count, MessagePackSerializerOptions options)
|
||||
{
|
||||
return new SortedDictionary<TKey, TValue>();
|
||||
}
|
||||
|
||||
protected override SortedDictionary<TKey, TValue>.Enumerator GetSourceEnumerator(SortedDictionary<TKey, TValue> source)
|
||||
{
|
||||
return source.GetEnumerator();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ReadOnlyDictionaryFormatter<TKey, TValue> : DictionaryFormatterBase<TKey, TValue, Dictionary<TKey, TValue>, ReadOnlyDictionary<TKey, TValue>>
|
||||
{
|
||||
protected override void Add(Dictionary<TKey, TValue> collection, int index, TKey key, TValue value, MessagePackSerializerOptions options)
|
||||
{
|
||||
collection.Add(key, value);
|
||||
}
|
||||
|
||||
protected override ReadOnlyDictionary<TKey, TValue> Complete(Dictionary<TKey, TValue> intermediateCollection)
|
||||
{
|
||||
return new ReadOnlyDictionary<TKey, TValue>(intermediateCollection);
|
||||
}
|
||||
|
||||
protected override Dictionary<TKey, TValue> Create(int count, MessagePackSerializerOptions options)
|
||||
{
|
||||
return new Dictionary<TKey, TValue>(count, options.Security.GetEqualityComparer<TKey>());
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class InterfaceReadOnlyDictionaryFormatter<TKey, TValue> : DictionaryFormatterBase<TKey, TValue, Dictionary<TKey, TValue>, IReadOnlyDictionary<TKey, TValue>>
|
||||
{
|
||||
protected override void Add(Dictionary<TKey, TValue> collection, int index, TKey key, TValue value, MessagePackSerializerOptions options)
|
||||
{
|
||||
collection.Add(key, value);
|
||||
}
|
||||
|
||||
protected override IReadOnlyDictionary<TKey, TValue> Complete(Dictionary<TKey, TValue> intermediateCollection)
|
||||
{
|
||||
return intermediateCollection;
|
||||
}
|
||||
|
||||
protected override Dictionary<TKey, TValue> Create(int count, MessagePackSerializerOptions options)
|
||||
{
|
||||
return new Dictionary<TKey, TValue>(count, options.Security.GetEqualityComparer<TKey>());
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ConcurrentDictionaryFormatter<TKey, TValue> : DictionaryFormatterBase<TKey, TValue, System.Collections.Concurrent.ConcurrentDictionary<TKey, TValue>>
|
||||
{
|
||||
protected override void Add(ConcurrentDictionary<TKey, TValue> collection, int index, TKey key, TValue value, MessagePackSerializerOptions options)
|
||||
{
|
||||
collection.TryAdd(key, value);
|
||||
}
|
||||
|
||||
protected override ConcurrentDictionary<TKey, TValue> Create(int count, MessagePackSerializerOptions options)
|
||||
{
|
||||
// concurrent dictionary can't access defaultConcurrecyLevel so does not use count overload.
|
||||
return new ConcurrentDictionary<TKey, TValue>(options.Security.GetEqualityComparer<TKey>());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3f0984a238b11bd2c97eb781371bb121
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,82 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
/// <summary>
|
||||
/// This formatter can serialize any value whose static type is <see cref="object"/>
|
||||
/// for which another resolver can provide a formatter for the runtime type.
|
||||
/// Its deserialization is limited to forwarding all calls to the <see cref="PrimitiveObjectFormatter"/>.
|
||||
/// </summary>
|
||||
public sealed class DynamicObjectTypeFallbackFormatter : IMessagePackFormatter<object>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<object> Instance = new DynamicObjectTypeFallbackFormatter();
|
||||
|
||||
private delegate void SerializeMethod(object dynamicFormatter, ref MessagePackWriter writer, object value, MessagePackSerializerOptions options);
|
||||
|
||||
private static readonly Internal.ThreadsafeTypeKeyHashTable<SerializeMethod> SerializerDelegates = new Internal.ThreadsafeTypeKeyHashTable<SerializeMethod>();
|
||||
|
||||
private DynamicObjectTypeFallbackFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, object value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value is null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
return;
|
||||
}
|
||||
|
||||
Type type = value.GetType();
|
||||
TypeInfo ti = type.GetTypeInfo();
|
||||
|
||||
if (type == typeof(object))
|
||||
{
|
||||
// serialize to empty map
|
||||
writer.WriteMapHeader(0);
|
||||
return;
|
||||
}
|
||||
|
||||
object formatter = options.Resolver.GetFormatterDynamicWithVerify(type);
|
||||
if (!SerializerDelegates.TryGetValue(type, out SerializeMethod serializerDelegate))
|
||||
{
|
||||
lock (SerializerDelegates)
|
||||
{
|
||||
if (!SerializerDelegates.TryGetValue(type, out serializerDelegate))
|
||||
{
|
||||
Type formatterType = typeof(IMessagePackFormatter<>).MakeGenericType(type);
|
||||
ParameterExpression param0 = Expression.Parameter(typeof(object), "formatter");
|
||||
ParameterExpression param1 = Expression.Parameter(typeof(MessagePackWriter).MakeByRefType(), "writer");
|
||||
ParameterExpression param2 = Expression.Parameter(typeof(object), "value");
|
||||
ParameterExpression param3 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options");
|
||||
|
||||
MethodInfo serializeMethodInfo = formatterType.GetRuntimeMethod("Serialize", new[] { typeof(MessagePackWriter).MakeByRefType(), type, typeof(MessagePackSerializerOptions) });
|
||||
|
||||
MethodCallExpression body = Expression.Call(
|
||||
Expression.Convert(param0, formatterType),
|
||||
serializeMethodInfo,
|
||||
param1,
|
||||
ti.IsValueType ? Expression.Unbox(param2, type) : Expression.Convert(param2, type),
|
||||
param3);
|
||||
|
||||
serializerDelegate = Expression.Lambda<SerializeMethod>(body, param0, param1, param2, param3).Compile();
|
||||
|
||||
SerializerDelegates.TryAdd(type, serializerDelegate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
serializerDelegate(formatter, ref writer, value, options);
|
||||
}
|
||||
|
||||
public object Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
return PrimitiveObjectFormatter.Instance.Deserialize(ref reader, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bc47abc7cd51279d9ac40fe1da6ffa1d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
// Note:This implementation is 'not' fastest, should more improve.
|
||||
public sealed class EnumAsStringFormatter<T> : IMessagePackFormatter<T>
|
||||
{
|
||||
private readonly IReadOnlyDictionary<string, T> nameValueMapping;
|
||||
private readonly IReadOnlyDictionary<T, string> valueNameMapping;
|
||||
private readonly IReadOnlyDictionary<string, string> clrToSerializationName;
|
||||
private readonly IReadOnlyDictionary<string, string> serializationToClrName;
|
||||
private readonly bool enumMemberOverridesPresent;
|
||||
private readonly bool isFlags;
|
||||
|
||||
public EnumAsStringFormatter()
|
||||
{
|
||||
this.isFlags = typeof(T).GetCustomAttribute<FlagsAttribute>() is object;
|
||||
|
||||
var fields = typeof(T).GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Static);
|
||||
var nameValueMapping = new Dictionary<string, T>(fields.Length);
|
||||
var valueNameMapping = new Dictionary<T, string>();
|
||||
Dictionary<string, string> clrToSerializationName = null;
|
||||
Dictionary<string, string> serializationToClrName = null;
|
||||
|
||||
foreach (FieldInfo enumValueMember in fields)
|
||||
{
|
||||
string name = enumValueMember.Name;
|
||||
T value = (T)enumValueMember.GetValue(null);
|
||||
|
||||
// Consider the case where the serialized form of the enum value is overridden via an attribute.
|
||||
var attribute = enumValueMember.GetCustomAttribute<EnumMemberAttribute>();
|
||||
if (attribute?.IsValueSetExplicitly ?? false)
|
||||
{
|
||||
clrToSerializationName = clrToSerializationName ?? new Dictionary<string, string>();
|
||||
serializationToClrName = serializationToClrName ?? new Dictionary<string, string>();
|
||||
|
||||
clrToSerializationName.Add(name, attribute.Value);
|
||||
serializationToClrName.Add(attribute.Value, name);
|
||||
|
||||
name = attribute.Value;
|
||||
this.enumMemberOverridesPresent = true;
|
||||
}
|
||||
|
||||
nameValueMapping[name] = value;
|
||||
valueNameMapping[value] = name;
|
||||
}
|
||||
|
||||
this.nameValueMapping = nameValueMapping;
|
||||
this.valueNameMapping = valueNameMapping;
|
||||
this.clrToSerializationName = clrToSerializationName;
|
||||
this.serializationToClrName = serializationToClrName;
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, T value, MessagePackSerializerOptions options)
|
||||
{
|
||||
// Enum.ToString() is slow, so avoid it when we can.
|
||||
if (!this.valueNameMapping.TryGetValue(value, out string valueString))
|
||||
{
|
||||
// fallback for flags, values with no name, etc
|
||||
valueString = this.GetSerializedNames(value.ToString());
|
||||
}
|
||||
|
||||
writer.Write(valueString);
|
||||
}
|
||||
|
||||
public T Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
string name = reader.ReadString();
|
||||
|
||||
// Avoid Enum.Parse when we can because it is too slow.
|
||||
if (!this.nameValueMapping.TryGetValue(name, out T value))
|
||||
{
|
||||
value = (T)Enum.Parse(typeof(T), this.GetClrNames(name));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private string GetClrNames(string serializedNames)
|
||||
{
|
||||
if (this.enumMemberOverridesPresent && this.isFlags && serializedNames.IndexOf(", ", StringComparison.Ordinal) >= 0)
|
||||
{
|
||||
return Translate(serializedNames, this.serializationToClrName);
|
||||
}
|
||||
|
||||
// We don't need to consider the trivial case of no commas because our caller would have found that in the lookup table and not called us.
|
||||
return serializedNames;
|
||||
}
|
||||
|
||||
private string GetSerializedNames(string clrNames)
|
||||
{
|
||||
if (this.enumMemberOverridesPresent && this.isFlags && clrNames.IndexOf(", ", StringComparison.Ordinal) >= 0)
|
||||
{
|
||||
return Translate(clrNames, this.clrToSerializationName);
|
||||
}
|
||||
|
||||
// We don't need to consider the trivial case of no commas because our caller would have found that in the lookup table and not called us.
|
||||
return clrNames;
|
||||
}
|
||||
|
||||
private static string Translate(string items, IReadOnlyDictionary<string, string> mapping)
|
||||
{
|
||||
string[] elements = items.Split(',');
|
||||
|
||||
for (int i = 0; i < elements.Length; i++)
|
||||
{
|
||||
// Trim the leading space if there is one (due to the delimiter being ", ").
|
||||
if (i > 0 && elements[i].Length > 0 && elements[i][0] == ' ')
|
||||
{
|
||||
elements[i] = elements[i].Substring(1);
|
||||
}
|
||||
|
||||
if (mapping.TryGetValue(elements[i], out string substituteValue))
|
||||
{
|
||||
elements[i] = substituteValue;
|
||||
}
|
||||
}
|
||||
|
||||
return string.Join(", ", elements);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f7cdc1e759af9873989648baa08f0350
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
public sealed class GenericEnumFormatter<T> : IMessagePackFormatter<T>
|
||||
where T : Enum
|
||||
{
|
||||
private delegate void EnumSerialize(ref MessagePackWriter writer, ref T value);
|
||||
|
||||
private delegate T EnumDeserialize(ref MessagePackReader reader);
|
||||
|
||||
private readonly EnumSerialize serializer;
|
||||
private readonly EnumDeserialize deserializer;
|
||||
|
||||
public GenericEnumFormatter()
|
||||
{
|
||||
var underlyingType = typeof(T).GetEnumUnderlyingType();
|
||||
switch (Type.GetTypeCode(underlyingType))
|
||||
{
|
||||
#pragma warning disable SA1107 // Avoid multiple statements on same line.
|
||||
case TypeCode.Byte:
|
||||
serializer = (ref MessagePackWriter writer, ref T value) => writer.Write(Unsafe.As<T, Byte>(ref value));
|
||||
deserializer = (ref MessagePackReader reader) => { var v = reader.ReadByte(); return Unsafe.As<Byte, T>(ref v); };
|
||||
break;
|
||||
case TypeCode.Int16:
|
||||
serializer = (ref MessagePackWriter writer, ref T value) => writer.Write(Unsafe.As<T, Int16>(ref value));
|
||||
deserializer = (ref MessagePackReader reader) => { var v = reader.ReadInt16(); return Unsafe.As<Int16, T>(ref v); };
|
||||
break;
|
||||
case TypeCode.Int32:
|
||||
serializer = (ref MessagePackWriter writer, ref T value) => writer.Write(Unsafe.As<T, Int32>(ref value));
|
||||
deserializer = (ref MessagePackReader reader) => { var v = reader.ReadInt32(); return Unsafe.As<Int32, T>(ref v); };
|
||||
break;
|
||||
case TypeCode.Int64:
|
||||
serializer = (ref MessagePackWriter writer, ref T value) => writer.Write(Unsafe.As<T, Int64>(ref value));
|
||||
deserializer = (ref MessagePackReader reader) => { var v = reader.ReadInt64(); return Unsafe.As<Int64, T>(ref v); };
|
||||
break;
|
||||
case TypeCode.SByte:
|
||||
serializer = (ref MessagePackWriter writer, ref T value) => writer.Write(Unsafe.As<T, SByte>(ref value));
|
||||
deserializer = (ref MessagePackReader reader) => { var v = reader.ReadSByte(); return Unsafe.As<SByte, T>(ref v); };
|
||||
break;
|
||||
case TypeCode.UInt16:
|
||||
serializer = (ref MessagePackWriter writer, ref T value) => writer.Write(Unsafe.As<T, UInt16>(ref value));
|
||||
deserializer = (ref MessagePackReader reader) => { var v = reader.ReadUInt16(); return Unsafe.As<UInt16, T>(ref v); };
|
||||
break;
|
||||
case TypeCode.UInt32:
|
||||
serializer = (ref MessagePackWriter writer, ref T value) => writer.Write(Unsafe.As<T, UInt32>(ref value));
|
||||
deserializer = (ref MessagePackReader reader) => { var v = reader.ReadUInt32(); return Unsafe.As<UInt32, T>(ref v); };
|
||||
break;
|
||||
case TypeCode.UInt64:
|
||||
serializer = (ref MessagePackWriter writer, ref T value) => writer.Write(Unsafe.As<T, UInt64>(ref value));
|
||||
deserializer = (ref MessagePackReader reader) => { var v = reader.ReadUInt64(); return Unsafe.As<UInt64, T>(ref v); };
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
#pragma warning restore SA1107 // Avoid multiple statements on same line.
|
||||
}
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, T value, MessagePackSerializerOptions options)
|
||||
{
|
||||
serializer(ref writer, ref value);
|
||||
}
|
||||
|
||||
public T Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
return deserializer(ref reader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7f3275d9a9f3275ec9cc43d6859964fe
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Buffers;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
#pragma warning disable SA1649 // File name should match first type name
|
||||
/// <summary>
|
||||
/// A base interface for <see cref="IMessagePackFormatter{T}"/> so that all generic implementations
|
||||
/// can be detected by a common base type.
|
||||
/// </summary>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public interface IMessagePackFormatter
|
||||
{
|
||||
}
|
||||
#pragma warning restore SA1649 // File name should match first type name
|
||||
|
||||
/// <summary>
|
||||
/// The contract for serialization of some specific type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to be serialized or deserialized.</typeparam>
|
||||
public interface IMessagePackFormatter<T> : IMessagePackFormatter
|
||||
{
|
||||
/// <summary>
|
||||
/// Serializes a value.
|
||||
/// </summary>
|
||||
/// <param name="writer">The writer to use when serializing the value.</param>
|
||||
/// <param name="value">The value to be serialized.</param>
|
||||
/// <param name="options">The serialization settings to use, including the resolver to use to obtain formatters for types that make up the composite type <typeparamref name="T"/>.</param>
|
||||
void Serialize(ref MessagePackWriter writer, T value, MessagePackSerializerOptions options);
|
||||
|
||||
/// <summary>
|
||||
/// Deserializes a value.
|
||||
/// </summary>
|
||||
/// <param name="reader">The reader to deserialize from.</param>
|
||||
/// <param name="options">The serialization settings to use, including the resolver to use to obtain formatters for types that make up the composite type <typeparamref name="T"/>.</param>
|
||||
/// <returns>The deserialized value.</returns>
|
||||
T Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cd75a2bcccf20dfb6824d447ec99a1fa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Buffers;
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
public sealed class IgnoreFormatter<T> : IMessagePackFormatter<T>
|
||||
{
|
||||
public void Serialize(ref MessagePackWriter writer, T value, MessagePackSerializerOptions options)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
|
||||
public T Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
reader.Skip();
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 64fa7163708478803a466c61cdb596d6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,293 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
#pragma warning disable SA1649 // File name should match first type name
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
/* multi dimensional array serialize to [i, j, [seq]] */
|
||||
|
||||
public sealed class TwoDimensionalArrayFormatter<T> : IMessagePackFormatter<T[,]>
|
||||
{
|
||||
private const int ArrayLength = 3;
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, T[,] value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
var i = value.GetLength(0);
|
||||
var j = value.GetLength(1);
|
||||
|
||||
IMessagePackFormatter<T> formatter = options.Resolver.GetFormatterWithVerify<T>();
|
||||
|
||||
writer.WriteArrayHeader(ArrayLength);
|
||||
writer.Write(i);
|
||||
writer.Write(j);
|
||||
|
||||
writer.WriteArrayHeader(value.Length);
|
||||
foreach (T item in value)
|
||||
{
|
||||
writer.CancellationToken.ThrowIfCancellationRequested();
|
||||
formatter.Serialize(ref writer, item, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public T[,] Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
IMessagePackFormatter<T> formatter = options.Resolver.GetFormatterWithVerify<T>();
|
||||
|
||||
var len = reader.ReadArrayHeader();
|
||||
if (len != ArrayLength)
|
||||
{
|
||||
throw new MessagePackSerializationException("Invalid T[,] format");
|
||||
}
|
||||
|
||||
var iLength = reader.ReadInt32();
|
||||
var jLength = reader.ReadInt32();
|
||||
var maxLen = reader.ReadArrayHeader();
|
||||
|
||||
var array = new T[iLength, jLength];
|
||||
|
||||
var i = 0;
|
||||
var j = -1;
|
||||
options.Security.DepthStep(ref reader);
|
||||
try
|
||||
{
|
||||
for (int loop = 0; loop < maxLen; loop++)
|
||||
{
|
||||
reader.CancellationToken.ThrowIfCancellationRequested();
|
||||
if (j < jLength - 1)
|
||||
{
|
||||
j++;
|
||||
}
|
||||
else
|
||||
{
|
||||
j = 0;
|
||||
i++;
|
||||
}
|
||||
|
||||
array[i, j] = formatter.Deserialize(ref reader, options);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Depth--;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ThreeDimensionalArrayFormatter<T> : IMessagePackFormatter<T[,,]>
|
||||
{
|
||||
private const int ArrayLength = 4;
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, T[,,] value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
var i = value.GetLength(0);
|
||||
var j = value.GetLength(1);
|
||||
var k = value.GetLength(2);
|
||||
|
||||
IMessagePackFormatter<T> formatter = options.Resolver.GetFormatterWithVerify<T>();
|
||||
|
||||
writer.WriteArrayHeader(ArrayLength);
|
||||
writer.Write(i);
|
||||
writer.Write(j);
|
||||
writer.Write(k);
|
||||
|
||||
writer.WriteArrayHeader(value.Length);
|
||||
foreach (T item in value)
|
||||
{
|
||||
writer.CancellationToken.ThrowIfCancellationRequested();
|
||||
formatter.Serialize(ref writer, item, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public T[,,] Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
IMessagePackFormatter<T> formatter = options.Resolver.GetFormatterWithVerify<T>();
|
||||
|
||||
var len = reader.ReadArrayHeader();
|
||||
if (len != ArrayLength)
|
||||
{
|
||||
throw new MessagePackSerializationException("Invalid T[,,] format");
|
||||
}
|
||||
|
||||
var iLength = reader.ReadInt32();
|
||||
var jLength = reader.ReadInt32();
|
||||
var kLength = reader.ReadInt32();
|
||||
var maxLen = reader.ReadArrayHeader();
|
||||
|
||||
var array = new T[iLength, jLength, kLength];
|
||||
|
||||
var i = 0;
|
||||
var j = 0;
|
||||
var k = -1;
|
||||
options.Security.DepthStep(ref reader);
|
||||
try
|
||||
{
|
||||
for (int loop = 0; loop < maxLen; loop++)
|
||||
{
|
||||
reader.CancellationToken.ThrowIfCancellationRequested();
|
||||
if (k < kLength - 1)
|
||||
{
|
||||
k++;
|
||||
}
|
||||
else if (j < jLength - 1)
|
||||
{
|
||||
k = 0;
|
||||
j++;
|
||||
}
|
||||
else
|
||||
{
|
||||
k = 0;
|
||||
j = 0;
|
||||
i++;
|
||||
}
|
||||
|
||||
array[i, j, k] = formatter.Deserialize(ref reader, options);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Depth--;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class FourDimensionalArrayFormatter<T> : IMessagePackFormatter<T[,,,]>
|
||||
{
|
||||
private const int ArrayLength = 5;
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, T[,,,] value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
var i = value.GetLength(0);
|
||||
var j = value.GetLength(1);
|
||||
var k = value.GetLength(2);
|
||||
var l = value.GetLength(3);
|
||||
|
||||
IMessagePackFormatter<T> formatter = options.Resolver.GetFormatterWithVerify<T>();
|
||||
|
||||
writer.WriteArrayHeader(ArrayLength);
|
||||
writer.Write(i);
|
||||
writer.Write(j);
|
||||
writer.Write(k);
|
||||
writer.Write(l);
|
||||
|
||||
writer.WriteArrayHeader(value.Length);
|
||||
foreach (T item in value)
|
||||
{
|
||||
writer.CancellationToken.ThrowIfCancellationRequested();
|
||||
formatter.Serialize(ref writer, item, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public T[,,,] Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
IMessagePackFormatter<T> formatter = options.Resolver.GetFormatterWithVerify<T>();
|
||||
|
||||
var len = reader.ReadArrayHeader();
|
||||
if (len != ArrayLength)
|
||||
{
|
||||
throw new MessagePackSerializationException("Invalid T[,,,] format");
|
||||
}
|
||||
|
||||
var iLength = reader.ReadInt32();
|
||||
var jLength = reader.ReadInt32();
|
||||
var kLength = reader.ReadInt32();
|
||||
var lLength = reader.ReadInt32();
|
||||
var maxLen = reader.ReadArrayHeader();
|
||||
var array = new T[iLength, jLength, kLength, lLength];
|
||||
|
||||
var i = 0;
|
||||
var j = 0;
|
||||
var k = 0;
|
||||
var l = -1;
|
||||
options.Security.DepthStep(ref reader);
|
||||
try
|
||||
{
|
||||
for (int loop = 0; loop < maxLen; loop++)
|
||||
{
|
||||
reader.CancellationToken.ThrowIfCancellationRequested();
|
||||
if (l < lLength - 1)
|
||||
{
|
||||
l++;
|
||||
}
|
||||
else if (k < kLength - 1)
|
||||
{
|
||||
l = 0;
|
||||
k++;
|
||||
}
|
||||
else if (j < jLength - 1)
|
||||
{
|
||||
l = 0;
|
||||
k = 0;
|
||||
j++;
|
||||
}
|
||||
else
|
||||
{
|
||||
l = 0;
|
||||
k = 0;
|
||||
j = 0;
|
||||
i++;
|
||||
}
|
||||
|
||||
array[i, j, k, l] = formatter.Deserialize(ref reader, options);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Depth--;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8a4af86ee0f0a74de9e88b1fe8c9826d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
public class NilFormatter : IMessagePackFormatter<Nil>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<Nil> Instance = new NilFormatter();
|
||||
|
||||
private NilFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, Nil value, MessagePackSerializerOptions options)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
|
||||
public Nil Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
return reader.ReadNil();
|
||||
}
|
||||
}
|
||||
|
||||
// NullableNil is same as Nil.
|
||||
public class NullableNilFormatter : IMessagePackFormatter<Nil?>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<Nil?> Instance = new NullableNilFormatter();
|
||||
|
||||
private NullableNilFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, Nil? value, MessagePackSerializerOptions options)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
|
||||
public Nil? Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
return reader.ReadNil();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 708c91d45dcbf19469504ec78aa2abee
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Buffers;
|
||||
|
||||
#pragma warning disable SA1649 // File name should match first type name
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
public sealed class NullableFormatter<T> : IMessagePackFormatter<T?>
|
||||
where T : struct
|
||||
{
|
||||
public void Serialize(ref MessagePackWriter writer, T? value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
options.Resolver.GetFormatterWithVerify<T>().Serialize(ref writer, value.Value, options);
|
||||
}
|
||||
}
|
||||
|
||||
public T? Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.IsNil)
|
||||
{
|
||||
reader.ReadNil();
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return options.Resolver.GetFormatterWithVerify<T>().Deserialize(ref reader, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class StaticNullableFormatter<T> : IMessagePackFormatter<T?>
|
||||
where T : struct
|
||||
{
|
||||
private readonly IMessagePackFormatter<T> underlyingFormatter;
|
||||
|
||||
public StaticNullableFormatter(IMessagePackFormatter<T> underlyingFormatter)
|
||||
{
|
||||
this.underlyingFormatter = underlyingFormatter;
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, T? value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.underlyingFormatter.Serialize(ref writer, value.Value, options);
|
||||
}
|
||||
}
|
||||
|
||||
public T? Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.underlyingFormatter.Deserialize(ref reader, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 88e906d65ee7d29d3ae1fb5865b8f6ab
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,337 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
public sealed class PrimitiveObjectFormatter : IMessagePackFormatter<object>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<object> Instance = new PrimitiveObjectFormatter();
|
||||
|
||||
private static readonly Dictionary<Type, int> TypeToJumpCode = new Dictionary<Type, int>()
|
||||
{
|
||||
// When adding types whose size exceeds 32-bits, add support in MessagePackSecurity.GetHashCollisionResistantEqualityComparer<T>()
|
||||
{ typeof(Boolean), 0 },
|
||||
{ typeof(Char), 1 },
|
||||
{ typeof(SByte), 2 },
|
||||
{ typeof(Byte), 3 },
|
||||
{ typeof(Int16), 4 },
|
||||
{ typeof(UInt16), 5 },
|
||||
{ typeof(Int32), 6 },
|
||||
{ typeof(UInt32), 7 },
|
||||
{ typeof(Int64), 8 },
|
||||
{ typeof(UInt64), 9 },
|
||||
{ typeof(Single), 10 },
|
||||
{ typeof(Double), 11 },
|
||||
{ typeof(DateTime), 12 },
|
||||
{ typeof(string), 13 },
|
||||
{ typeof(byte[]), 14 },
|
||||
};
|
||||
|
||||
private PrimitiveObjectFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
|
||||
public static bool IsSupportedType(Type type, TypeInfo typeInfo, object value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TypeToJumpCode.ContainsKey(type))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (typeInfo.IsEnum)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (value is System.Collections.IDictionary)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (value is System.Collections.ICollection)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, object value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
return;
|
||||
}
|
||||
|
||||
Type t = value.GetType();
|
||||
|
||||
int code;
|
||||
if (TypeToJumpCode.TryGetValue(t, out code))
|
||||
{
|
||||
switch (code)
|
||||
{
|
||||
case 0:
|
||||
writer.Write((bool)value);
|
||||
return;
|
||||
case 1:
|
||||
writer.Write((char)value);
|
||||
return;
|
||||
case 2:
|
||||
writer.WriteInt8((sbyte)value);
|
||||
return;
|
||||
case 3:
|
||||
writer.WriteUInt8((byte)value);
|
||||
return;
|
||||
case 4:
|
||||
writer.WriteInt16((Int16)value);
|
||||
return;
|
||||
case 5:
|
||||
writer.WriteUInt16((UInt16)value);
|
||||
return;
|
||||
case 6:
|
||||
writer.WriteInt32((Int32)value);
|
||||
return;
|
||||
case 7:
|
||||
writer.WriteUInt32((UInt32)value);
|
||||
return;
|
||||
case 8:
|
||||
writer.WriteInt64((Int64)value);
|
||||
return;
|
||||
case 9:
|
||||
writer.WriteUInt64((UInt64)value);
|
||||
return;
|
||||
case 10:
|
||||
writer.Write((Single)value);
|
||||
return;
|
||||
case 11:
|
||||
writer.Write((double)value);
|
||||
return;
|
||||
case 12:
|
||||
writer.Write((DateTime)value);
|
||||
return;
|
||||
case 13:
|
||||
writer.Write((string)value);
|
||||
return;
|
||||
case 14:
|
||||
writer.Write((byte[])value);
|
||||
return;
|
||||
default:
|
||||
throw new MessagePackSerializationException("Not supported primitive object resolver. type:" + t.Name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER && !NETFX_CORE
|
||||
if (t.IsEnum)
|
||||
#else
|
||||
if (t.GetTypeInfo().IsEnum)
|
||||
#endif
|
||||
{
|
||||
Type underlyingType = Enum.GetUnderlyingType(t);
|
||||
var code2 = TypeToJumpCode[underlyingType];
|
||||
switch (code2)
|
||||
{
|
||||
case 2:
|
||||
writer.WriteInt8((sbyte)value);
|
||||
return;
|
||||
case 3:
|
||||
writer.WriteUInt8((byte)value);
|
||||
return;
|
||||
case 4:
|
||||
writer.WriteInt16((Int16)value);
|
||||
return;
|
||||
case 5:
|
||||
writer.WriteUInt16((UInt16)value);
|
||||
return;
|
||||
case 6:
|
||||
writer.WriteInt32((Int32)value);
|
||||
return;
|
||||
case 7:
|
||||
writer.WriteUInt32((UInt32)value);
|
||||
return;
|
||||
case 8:
|
||||
writer.WriteInt64((Int64)value);
|
||||
return;
|
||||
case 9:
|
||||
writer.WriteUInt64((UInt64)value);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (value is System.Collections.IDictionary)
|
||||
{
|
||||
// check IDictionary first
|
||||
var d = value as System.Collections.IDictionary;
|
||||
writer.WriteMapHeader(d.Count);
|
||||
foreach (System.Collections.DictionaryEntry item in d)
|
||||
{
|
||||
this.Serialize(ref writer, item.Key, options);
|
||||
this.Serialize(ref writer, item.Value, options);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
else if (value is System.Collections.ICollection)
|
||||
{
|
||||
var c = value as System.Collections.ICollection;
|
||||
writer.WriteArrayHeader(c.Count);
|
||||
foreach (var item in c)
|
||||
{
|
||||
this.Serialize(ref writer, item, options);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw new MessagePackSerializationException("Not supported primitive object resolver. type:" + t.Name);
|
||||
}
|
||||
|
||||
public object Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
MessagePackType type = reader.NextMessagePackType;
|
||||
IFormatterResolver resolver = options.Resolver;
|
||||
switch (type)
|
||||
{
|
||||
case MessagePackType.Integer:
|
||||
var code = reader.NextCode;
|
||||
if (code >= MessagePackCode.MinNegativeFixInt && code <= MessagePackCode.MaxNegativeFixInt)
|
||||
{
|
||||
return reader.ReadSByte();
|
||||
}
|
||||
else if (code >= MessagePackCode.MinFixInt && code <= MessagePackCode.MaxFixInt)
|
||||
{
|
||||
return reader.ReadByte();
|
||||
}
|
||||
else if (code == MessagePackCode.Int8)
|
||||
{
|
||||
return reader.ReadSByte();
|
||||
}
|
||||
else if (code == MessagePackCode.Int16)
|
||||
{
|
||||
return reader.ReadInt16();
|
||||
}
|
||||
else if (code == MessagePackCode.Int32)
|
||||
{
|
||||
return reader.ReadInt32();
|
||||
}
|
||||
else if (code == MessagePackCode.Int64)
|
||||
{
|
||||
return reader.ReadInt64();
|
||||
}
|
||||
else if (code == MessagePackCode.UInt8)
|
||||
{
|
||||
return reader.ReadByte();
|
||||
}
|
||||
else if (code == MessagePackCode.UInt16)
|
||||
{
|
||||
return reader.ReadUInt16();
|
||||
}
|
||||
else if (code == MessagePackCode.UInt32)
|
||||
{
|
||||
return reader.ReadUInt32();
|
||||
}
|
||||
else if (code == MessagePackCode.UInt64)
|
||||
{
|
||||
return reader.ReadUInt64();
|
||||
}
|
||||
|
||||
throw new MessagePackSerializationException("Invalid primitive bytes.");
|
||||
case MessagePackType.Boolean:
|
||||
return reader.ReadBoolean();
|
||||
case MessagePackType.Float:
|
||||
if (reader.NextCode == MessagePackCode.Float32)
|
||||
{
|
||||
return reader.ReadSingle();
|
||||
}
|
||||
else
|
||||
{
|
||||
return reader.ReadDouble();
|
||||
}
|
||||
|
||||
case MessagePackType.String:
|
||||
return reader.ReadString();
|
||||
case MessagePackType.Binary:
|
||||
// We must copy the sequence returned by ReadBytes since the reader's sequence is only valid during deserialization.
|
||||
return reader.ReadBytes()?.ToArray();
|
||||
case MessagePackType.Extension:
|
||||
ExtensionHeader ext = reader.ReadExtensionFormatHeader();
|
||||
if (ext.TypeCode == ReservedMessagePackExtensionTypeCode.DateTime)
|
||||
{
|
||||
return reader.ReadDateTime(ext);
|
||||
}
|
||||
|
||||
throw new MessagePackSerializationException("Invalid primitive bytes.");
|
||||
case MessagePackType.Array:
|
||||
{
|
||||
var length = reader.ReadArrayHeader();
|
||||
|
||||
IMessagePackFormatter<object> objectFormatter = resolver.GetFormatter<object>();
|
||||
var array = new object[length];
|
||||
options.Security.DepthStep(ref reader);
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
array[i] = objectFormatter.Deserialize(ref reader, options);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Depth--;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
case MessagePackType.Map:
|
||||
{
|
||||
var length = reader.ReadMapHeader();
|
||||
|
||||
IMessagePackFormatter<object> objectFormatter = resolver.GetFormatter<object>();
|
||||
var hash = new Dictionary<object, object>(length, options.Security.GetEqualityComparer<object>());
|
||||
options.Security.DepthStep(ref reader);
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
var key = objectFormatter.Deserialize(ref reader, options);
|
||||
|
||||
var value = objectFormatter.Deserialize(ref reader, options);
|
||||
|
||||
hash.Add(key, value);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Depth--;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
case MessagePackType.Nil:
|
||||
reader.ReadNil();
|
||||
return null;
|
||||
default:
|
||||
throw new MessagePackSerializationException("Invalid primitive bytes.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d46d293dc804af1669409cc12690a3ad
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,599 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using MessagePack.Internal;
|
||||
|
||||
#pragma warning disable SA1649 // File name should match first type name
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
// NET40 -> BigInteger, Complex, Tuple
|
||||
|
||||
// byte[] is special. represents bin type.
|
||||
public sealed class ByteArrayFormatter : IMessagePackFormatter<byte[]>
|
||||
{
|
||||
public static readonly ByteArrayFormatter Instance = new ByteArrayFormatter();
|
||||
|
||||
private ByteArrayFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, byte[] value, MessagePackSerializerOptions options)
|
||||
{
|
||||
writer.Write(value);
|
||||
}
|
||||
|
||||
public byte[] Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
return reader.ReadBytes()?.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class NullableStringFormatter : IMessagePackFormatter<String>
|
||||
{
|
||||
public static readonly NullableStringFormatter Instance = new NullableStringFormatter();
|
||||
|
||||
private NullableStringFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, string value, MessagePackSerializerOptions options)
|
||||
{
|
||||
writer.Write(value);
|
||||
}
|
||||
|
||||
public string Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
return reader.ReadString();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class NullableStringArrayFormatter : IMessagePackFormatter<String[]>
|
||||
{
|
||||
public static readonly NullableStringArrayFormatter Instance = new NullableStringArrayFormatter();
|
||||
|
||||
private NullableStringArrayFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, String[] value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.WriteArrayHeader(value.Length);
|
||||
for (int i = 0; i < value.Length; i++)
|
||||
{
|
||||
writer.Write(value[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public String[] Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var len = reader.ReadArrayHeader();
|
||||
var array = new String[len];
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
array[i] = reader.ReadString();
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DecimalFormatter : IMessagePackFormatter<Decimal>
|
||||
{
|
||||
public static readonly DecimalFormatter Instance = new DecimalFormatter();
|
||||
|
||||
private DecimalFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, decimal value, MessagePackSerializerOptions options)
|
||||
{
|
||||
var dest = writer.GetSpan(MessagePackRange.MaxFixStringLength);
|
||||
if (System.Buffers.Text.Utf8Formatter.TryFormat(value, dest.Slice(1), out var written))
|
||||
{
|
||||
// write header
|
||||
dest[0] = (byte)(MessagePackCode.MinFixStr | written);
|
||||
writer.Advance(written + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// reset writer's span previously acquired that does not use
|
||||
writer.Advance(0);
|
||||
writer.Write(value.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
|
||||
public decimal Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (!(reader.ReadStringSequence() is ReadOnlySequence<byte> sequence))
|
||||
{
|
||||
throw new MessagePackSerializationException(string.Format("Unexpected msgpack code {0} ({1}) encountered.", MessagePackCode.Nil, MessagePackCode.ToFormatName(MessagePackCode.Nil)));
|
||||
}
|
||||
|
||||
if (sequence.IsSingleSegment)
|
||||
{
|
||||
var span = sequence.First.Span;
|
||||
if (System.Buffers.Text.Utf8Parser.TryParse(span, out decimal result, out var bytesConsumed))
|
||||
{
|
||||
if (span.Length != bytesConsumed)
|
||||
{
|
||||
throw new MessagePackSerializationException("Unexpected length of string.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// sequence.Length is not free
|
||||
var seqLen = (int)sequence.Length;
|
||||
if (seqLen < 128)
|
||||
{
|
||||
Span<byte> span = stackalloc byte[seqLen];
|
||||
sequence.CopyTo(span);
|
||||
if (System.Buffers.Text.Utf8Parser.TryParse(span, out decimal result, out var bytesConsumed))
|
||||
{
|
||||
if (seqLen != bytesConsumed)
|
||||
{
|
||||
throw new MessagePackSerializationException("Unexpected length of string.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var rentArray = ArrayPool<byte>.Shared.Rent(seqLen);
|
||||
try
|
||||
{
|
||||
sequence.CopyTo(rentArray);
|
||||
if (System.Buffers.Text.Utf8Parser.TryParse(rentArray.AsSpan(0, seqLen), out decimal result, out var bytesConsumed))
|
||||
{
|
||||
if (seqLen != bytesConsumed)
|
||||
{
|
||||
throw new MessagePackSerializationException("Unexpected length of string.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(rentArray);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new MessagePackSerializationException("Can't parse to decimal, input string was not in a correct format.");
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class TimeSpanFormatter : IMessagePackFormatter<TimeSpan>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<TimeSpan> Instance = new TimeSpanFormatter();
|
||||
|
||||
private TimeSpanFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, TimeSpan value, MessagePackSerializerOptions options)
|
||||
{
|
||||
writer.Write(value.Ticks);
|
||||
return;
|
||||
}
|
||||
|
||||
public TimeSpan Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
return new TimeSpan(reader.ReadInt64());
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class DateTimeOffsetFormatter : IMessagePackFormatter<DateTimeOffset>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<DateTimeOffset> Instance = new DateTimeOffsetFormatter();
|
||||
|
||||
private DateTimeOffsetFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, DateTimeOffset value, MessagePackSerializerOptions options)
|
||||
{
|
||||
writer.WriteArrayHeader(2);
|
||||
writer.Write(new DateTime(value.Ticks, DateTimeKind.Utc)); // current ticks as is
|
||||
writer.Write((short)value.Offset.TotalMinutes); // offset is normalized in minutes
|
||||
return;
|
||||
}
|
||||
|
||||
public DateTimeOffset Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
var count = reader.ReadArrayHeader();
|
||||
|
||||
if (count != 2)
|
||||
{
|
||||
throw new MessagePackSerializationException("Invalid DateTimeOffset format.");
|
||||
}
|
||||
|
||||
DateTime utc = reader.ReadDateTime();
|
||||
|
||||
var dtOffsetMinutes = reader.ReadInt16();
|
||||
|
||||
return new DateTimeOffset(utc.Ticks, TimeSpan.FromMinutes(dtOffsetMinutes));
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class GuidFormatter : IMessagePackFormatter<Guid>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<Guid> Instance = new GuidFormatter();
|
||||
|
||||
private GuidFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public unsafe void Serialize(ref MessagePackWriter writer, Guid value, MessagePackSerializerOptions options)
|
||||
{
|
||||
byte* pBytes = stackalloc byte[36];
|
||||
Span<byte> bytes = new Span<byte>(pBytes, 36);
|
||||
new GuidBits(ref value).Write(bytes);
|
||||
writer.WriteString(bytes);
|
||||
}
|
||||
|
||||
public Guid Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
ReadOnlySequence<byte> segment = reader.ReadStringSequence().Value;
|
||||
if (segment.Length != 36)
|
||||
{
|
||||
throw new MessagePackSerializationException("Unexpected length of string.");
|
||||
}
|
||||
|
||||
GuidBits result;
|
||||
if (segment.IsSingleSegment)
|
||||
{
|
||||
result = new GuidBits(segment.First.Span);
|
||||
}
|
||||
else
|
||||
{
|
||||
Span<byte> bytes = stackalloc byte[36];
|
||||
segment.CopyTo(bytes);
|
||||
result = new GuidBits(bytes);
|
||||
}
|
||||
|
||||
return result.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class UriFormatter : IMessagePackFormatter<Uri>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<Uri> Instance = new UriFormatter();
|
||||
|
||||
private UriFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, Uri value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(value.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public Uri Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Uri(reader.ReadString(), UriKind.RelativeOrAbsolute);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class VersionFormatter : IMessagePackFormatter<Version>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<Version> Instance = new VersionFormatter();
|
||||
|
||||
private VersionFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, Version value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(value.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public Version Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Version(reader.ReadString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class KeyValuePairFormatter<TKey, TValue> : IMessagePackFormatter<KeyValuePair<TKey, TValue>>
|
||||
{
|
||||
public void Serialize(ref MessagePackWriter writer, KeyValuePair<TKey, TValue> value, MessagePackSerializerOptions options)
|
||||
{
|
||||
writer.WriteArrayHeader(2);
|
||||
IFormatterResolver resolver = options.Resolver;
|
||||
resolver.GetFormatterWithVerify<TKey>().Serialize(ref writer, value.Key, options);
|
||||
resolver.GetFormatterWithVerify<TValue>().Serialize(ref writer, value.Value, options);
|
||||
return;
|
||||
}
|
||||
|
||||
public KeyValuePair<TKey, TValue> Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
var count = reader.ReadArrayHeader();
|
||||
|
||||
if (count != 2)
|
||||
{
|
||||
throw new MessagePackSerializationException("Invalid KeyValuePair format.");
|
||||
}
|
||||
|
||||
IFormatterResolver resolver = options.Resolver;
|
||||
options.Security.DepthStep(ref reader);
|
||||
try
|
||||
{
|
||||
TKey key = resolver.GetFormatterWithVerify<TKey>().Deserialize(ref reader, options);
|
||||
TValue value = resolver.GetFormatterWithVerify<TValue>().Deserialize(ref reader, options);
|
||||
return new KeyValuePair<TKey, TValue>(key, value);
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Depth--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class StringBuilderFormatter : IMessagePackFormatter<StringBuilder>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<StringBuilder> Instance = new StringBuilderFormatter();
|
||||
|
||||
private StringBuilderFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, StringBuilder value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write(value.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public StringBuilder Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new StringBuilder(reader.ReadString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class BitArrayFormatter : IMessagePackFormatter<BitArray>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<BitArray> Instance = new BitArrayFormatter();
|
||||
|
||||
private BitArrayFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, BitArray value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
var len = value.Length;
|
||||
writer.WriteArrayHeader(len);
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
writer.Write(value.Get(i));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public BitArray Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var len = reader.ReadArrayHeader();
|
||||
|
||||
var array = new BitArray(len);
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
array[i] = reader.ReadBoolean();
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class BigIntegerFormatter : IMessagePackFormatter<System.Numerics.BigInteger>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<System.Numerics.BigInteger> Instance = new BigIntegerFormatter();
|
||||
|
||||
private BigIntegerFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, System.Numerics.BigInteger value, MessagePackSerializerOptions options)
|
||||
{
|
||||
#if NETCOREAPP2_1
|
||||
if (!writer.OldSpec)
|
||||
{
|
||||
// try to get bin8 buffer.
|
||||
var span = writer.GetSpan(byte.MaxValue);
|
||||
if (value.TryWriteBytes(span.Slice(2), out var written))
|
||||
{
|
||||
span[0] = MessagePackCode.Bin8;
|
||||
span[1] = (byte)written;
|
||||
|
||||
writer.Advance(written + 2);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// reset writer's span previously acquired that does not use
|
||||
writer.Advance(0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
writer.Write(value.ToByteArray());
|
||||
return;
|
||||
}
|
||||
|
||||
public System.Numerics.BigInteger Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
ReadOnlySequence<byte> bytes = reader.ReadBytes().Value;
|
||||
#if NETCOREAPP2_1
|
||||
if (bytes.IsSingleSegment)
|
||||
{
|
||||
return new System.Numerics.BigInteger(bytes.First.Span);
|
||||
}
|
||||
else
|
||||
{
|
||||
byte[] bytesArray = ArrayPool<byte>.Shared.Rent((int)bytes.Length);
|
||||
try
|
||||
{
|
||||
bytes.CopyTo(bytesArray);
|
||||
return new System.Numerics.BigInteger(bytesArray.AsSpan(0, (int)bytes.Length));
|
||||
}
|
||||
finally
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(bytesArray);
|
||||
}
|
||||
}
|
||||
#else
|
||||
return new System.Numerics.BigInteger(bytes.ToArray());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ComplexFormatter : IMessagePackFormatter<System.Numerics.Complex>
|
||||
{
|
||||
public static readonly IMessagePackFormatter<System.Numerics.Complex> Instance = new ComplexFormatter();
|
||||
|
||||
private ComplexFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, System.Numerics.Complex value, MessagePackSerializerOptions options)
|
||||
{
|
||||
writer.WriteArrayHeader(2);
|
||||
writer.Write(value.Real);
|
||||
writer.Write(value.Imaginary);
|
||||
return;
|
||||
}
|
||||
|
||||
public System.Numerics.Complex Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
var count = reader.ReadArrayHeader();
|
||||
|
||||
if (count != 2)
|
||||
{
|
||||
throw new MessagePackSerializationException("Invalid Complex format.");
|
||||
}
|
||||
|
||||
var real = reader.ReadDouble();
|
||||
|
||||
var imaginary = reader.ReadDouble();
|
||||
|
||||
return new System.Numerics.Complex(real, imaginary);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class LazyFormatter<T> : IMessagePackFormatter<Lazy<T>>
|
||||
{
|
||||
public void Serialize(ref MessagePackWriter writer, Lazy<T> value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
}
|
||||
else
|
||||
{
|
||||
IFormatterResolver resolver = options.Resolver;
|
||||
resolver.GetFormatterWithVerify<T>().Serialize(ref writer, value.Value, options);
|
||||
}
|
||||
}
|
||||
|
||||
public Lazy<T> Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
else
|
||||
{
|
||||
options.Security.DepthStep(ref reader);
|
||||
try
|
||||
{
|
||||
// deserialize immediately(no delay, because capture byte[] causes memory leak)
|
||||
IFormatterResolver resolver = options.Resolver;
|
||||
T v = resolver.GetFormatterWithVerify<T>().Deserialize(ref reader, options);
|
||||
return new Lazy<T>(() => v);
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Depth--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6dc8f5f9191421c21bd1ba87f5a70d27
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,309 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text.RegularExpressions;
|
||||
using MessagePack.Internal;
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
/// <summary>
|
||||
/// For `object` field that holds derived from `object` value, ex: var arr = new object[] { 1, "a", new Model() };.
|
||||
/// </summary>
|
||||
public sealed class TypelessFormatter : IMessagePackFormatter<object>
|
||||
{
|
||||
private delegate void SerializeMethod(object dynamicContractlessFormatter, ref MessagePackWriter writer, object value, MessagePackSerializerOptions options);
|
||||
|
||||
private delegate object DeserializeMethod(object dynamicContractlessFormatter, ref MessagePackReader reader, MessagePackSerializerOptions options);
|
||||
|
||||
/// <summary>
|
||||
/// The singleton instance that can be used.
|
||||
/// </summary>
|
||||
public static readonly IMessagePackFormatter<object> Instance = new TypelessFormatter();
|
||||
|
||||
private readonly ThreadsafeTypeKeyHashTable<SerializeMethod> serializers = new ThreadsafeTypeKeyHashTable<SerializeMethod>();
|
||||
private readonly ThreadsafeTypeKeyHashTable<DeserializeMethod> deserializers = new ThreadsafeTypeKeyHashTable<DeserializeMethod>();
|
||||
private readonly ThreadsafeTypeKeyHashTable<byte[]> fullTypeNameCache = new ThreadsafeTypeKeyHashTable<byte[]>();
|
||||
private readonly ThreadsafeTypeKeyHashTable<byte[]> shortenedTypeNameCache = new ThreadsafeTypeKeyHashTable<byte[]>();
|
||||
private readonly AsymmetricKeyHashTable<byte[], ArraySegment<byte>, Type> typeCache = new AsymmetricKeyHashTable<byte[], ArraySegment<byte>, Type>(new StringArraySegmentByteAscymmetricEqualityComparer());
|
||||
|
||||
private static readonly HashSet<Type> UseBuiltinTypes = new HashSet<Type>
|
||||
{
|
||||
typeof(Boolean),
|
||||
////typeof(Char),
|
||||
typeof(SByte),
|
||||
typeof(Byte),
|
||||
typeof(Int16),
|
||||
typeof(UInt16),
|
||||
typeof(Int32),
|
||||
typeof(UInt32),
|
||||
typeof(Int64),
|
||||
typeof(UInt64),
|
||||
typeof(Single),
|
||||
typeof(Double),
|
||||
typeof(string),
|
||||
typeof(byte[]),
|
||||
|
||||
// array should save their types.
|
||||
////typeof(Boolean[]),
|
||||
////typeof(Char[]),
|
||||
////typeof(SByte[]),
|
||||
////typeof(Int16[]),
|
||||
////typeof(UInt16[]),
|
||||
////typeof(Int32[]),
|
||||
////typeof(UInt32[]),
|
||||
////typeof(Int64[]),
|
||||
////typeof(UInt64[]),
|
||||
////typeof(Single[]),
|
||||
////typeof(Double[]),
|
||||
////typeof(string[]),
|
||||
|
||||
typeof(Boolean?),
|
||||
////typeof(Char?),
|
||||
typeof(SByte?),
|
||||
typeof(Byte?),
|
||||
typeof(Int16?),
|
||||
typeof(UInt16?),
|
||||
typeof(Int32?),
|
||||
typeof(UInt32?),
|
||||
typeof(Int64?),
|
||||
typeof(UInt64?),
|
||||
typeof(Single?),
|
||||
typeof(Double?),
|
||||
};
|
||||
|
||||
//ForceSizePrimitiveObjectResolver.Instance,
|
||||
//ContractlessStandardResolverAllowPrivate.Instance);
|
||||
|
||||
// mscorlib or System.Private.CoreLib
|
||||
private static readonly bool IsMscorlib = typeof(int).AssemblyQualifiedName.Contains("mscorlib");
|
||||
|
||||
public TypelessFormatter()
|
||||
{
|
||||
this.serializers.TryAdd(typeof(object), _ => (object p1, ref MessagePackWriter p2, object p3, MessagePackSerializerOptions p4) => { });
|
||||
this.deserializers.TryAdd(typeof(object), _ => (object p1, ref MessagePackReader p2, MessagePackSerializerOptions p3) => new object());
|
||||
}
|
||||
|
||||
private string BuildTypeName(Type type, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (options.OmitAssemblyVersion)
|
||||
{
|
||||
string full = type.AssemblyQualifiedName;
|
||||
|
||||
var shortened = MessagePackSerializerOptions.AssemblyNameVersionSelectorRegex.Replace(full, string.Empty);
|
||||
if (Type.GetType(shortened, false) == null)
|
||||
{
|
||||
// if type cannot be found with shortened name - use full name
|
||||
shortened = full;
|
||||
}
|
||||
|
||||
return shortened;
|
||||
}
|
||||
else
|
||||
{
|
||||
return type.AssemblyQualifiedName;
|
||||
}
|
||||
}
|
||||
|
||||
public void Serialize(ref MessagePackWriter writer, object value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNil();
|
||||
return;
|
||||
}
|
||||
|
||||
Type type = value.GetType();
|
||||
|
||||
byte[] typeName;
|
||||
var typeNameCache = options.OmitAssemblyVersion ? this.shortenedTypeNameCache : this.fullTypeNameCache;
|
||||
if (!typeNameCache.TryGetValue(type, out typeName))
|
||||
{
|
||||
TypeInfo ti = type.GetTypeInfo();
|
||||
if (ti.IsAnonymous() || UseBuiltinTypes.Contains(type))
|
||||
{
|
||||
typeName = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
typeName = StringEncoding.UTF8.GetBytes(this.BuildTypeName(type, options));
|
||||
}
|
||||
|
||||
typeNameCache.TryAdd(type, typeName);
|
||||
}
|
||||
|
||||
if (typeName == null)
|
||||
{
|
||||
DynamicObjectTypeFallbackFormatter.Instance.Serialize(ref writer, value, options);
|
||||
return;
|
||||
}
|
||||
|
||||
var formatter = options.Resolver.GetFormatterDynamicWithVerify(type);
|
||||
|
||||
// don't use GetOrAdd for avoid closure capture.
|
||||
if (!this.serializers.TryGetValue(type, out SerializeMethod serializeMethod))
|
||||
{
|
||||
// double check locking...
|
||||
lock (this.serializers)
|
||||
{
|
||||
if (!this.serializers.TryGetValue(type, out serializeMethod))
|
||||
{
|
||||
TypeInfo ti = type.GetTypeInfo();
|
||||
|
||||
Type formatterType = typeof(IMessagePackFormatter<>).MakeGenericType(type);
|
||||
ParameterExpression param0 = Expression.Parameter(typeof(object), "formatter");
|
||||
ParameterExpression param1 = Expression.Parameter(typeof(MessagePackWriter).MakeByRefType(), "writer");
|
||||
ParameterExpression param2 = Expression.Parameter(typeof(object), "value");
|
||||
ParameterExpression param3 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options");
|
||||
|
||||
MethodInfo serializeMethodInfo = formatterType.GetRuntimeMethod("Serialize", new[] { typeof(MessagePackWriter).MakeByRefType(), type, typeof(MessagePackSerializerOptions) });
|
||||
|
||||
MethodCallExpression body = Expression.Call(
|
||||
Expression.Convert(param0, formatterType),
|
||||
serializeMethodInfo,
|
||||
param1,
|
||||
ti.IsValueType ? Expression.Unbox(param2, type) : Expression.Convert(param2, type),
|
||||
param3);
|
||||
|
||||
serializeMethod = Expression.Lambda<SerializeMethod>(body, param0, param1, param2, param3).Compile();
|
||||
|
||||
this.serializers.TryAdd(type, serializeMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mark will be written at the end, when size is known
|
||||
using (var scratchRental = SequencePool.Shared.Rent())
|
||||
{
|
||||
MessagePackWriter scratchWriter = writer.Clone(scratchRental.Value);
|
||||
scratchWriter.WriteString(typeName);
|
||||
serializeMethod(formatter, ref scratchWriter, value, options);
|
||||
scratchWriter.Flush();
|
||||
|
||||
// mark as extension with code 100
|
||||
writer.WriteExtensionFormat(new ExtensionResult((sbyte)ThisLibraryExtensionTypeCodes.TypelessFormatter, scratchRental.Value));
|
||||
}
|
||||
}
|
||||
|
||||
public object Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.TryReadNil())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (reader.NextMessagePackType == MessagePackType.Extension)
|
||||
{
|
||||
ExtensionHeader ext = reader.ReadExtensionFormatHeader();
|
||||
if (ext.TypeCode == ThisLibraryExtensionTypeCodes.TypelessFormatter)
|
||||
{
|
||||
// it has type name serialized
|
||||
ReadOnlySequence<byte> typeName = reader.ReadStringSequence().Value;
|
||||
ArraySegment<byte> typeNameArraySegment;
|
||||
byte[] rented = null;
|
||||
if (!typeName.IsSingleSegment || !MemoryMarshal.TryGetArray(typeName.First, out typeNameArraySegment))
|
||||
{
|
||||
rented = ArrayPool<byte>.Shared.Rent((int)typeName.Length);
|
||||
typeName.CopyTo(rented);
|
||||
typeNameArraySegment = new ArraySegment<byte>(rented, 0, (int)typeName.Length);
|
||||
}
|
||||
|
||||
var result = this.DeserializeByTypeName(typeNameArraySegment, ref reader, options);
|
||||
|
||||
if (rented != null)
|
||||
{
|
||||
ArrayPool<byte>.Shared.Return(rented);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// fallback
|
||||
return DynamicObjectTypeFallbackFormatter.Instance.Deserialize(ref reader, options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does not support deserializing of anonymous types
|
||||
/// Type should be covered by preceeding resolvers in complex/standard resolver.
|
||||
/// </summary>
|
||||
private object DeserializeByTypeName(ArraySegment<byte> typeName, ref MessagePackReader byteSequence, MessagePackSerializerOptions options)
|
||||
{
|
||||
// try get type with assembly name, throw if not found
|
||||
Type type;
|
||||
if (!this.typeCache.TryGetValue(typeName, out type))
|
||||
{
|
||||
var buffer = new byte[typeName.Count];
|
||||
Buffer.BlockCopy(typeName.Array, typeName.Offset, buffer, 0, buffer.Length);
|
||||
var str = StringEncoding.UTF8.GetString(buffer);
|
||||
type = options.LoadType(str);
|
||||
if (type == null)
|
||||
{
|
||||
if (IsMscorlib && str.Contains("System.Private.CoreLib"))
|
||||
{
|
||||
str = str.Replace("System.Private.CoreLib", "mscorlib");
|
||||
type = Type.GetType(str, true); // throw
|
||||
}
|
||||
else if (!IsMscorlib && str.Contains("mscorlib"))
|
||||
{
|
||||
str = str.Replace("mscorlib", "System.Private.CoreLib");
|
||||
type = Type.GetType(str, true); // throw
|
||||
}
|
||||
else
|
||||
{
|
||||
type = Type.GetType(str, true); // re-throw
|
||||
}
|
||||
}
|
||||
|
||||
this.typeCache.TryAdd(buffer, type);
|
||||
}
|
||||
|
||||
options.ThrowIfDeserializingTypeIsDisallowed(type);
|
||||
|
||||
var formatter = options.Resolver.GetFormatterDynamicWithVerify(type);
|
||||
|
||||
if (!this.deserializers.TryGetValue(type, out DeserializeMethod deserializeMethod))
|
||||
{
|
||||
lock (this.deserializers)
|
||||
{
|
||||
if (!this.deserializers.TryGetValue(type, out deserializeMethod))
|
||||
{
|
||||
TypeInfo ti = type.GetTypeInfo();
|
||||
|
||||
Type formatterType = typeof(IMessagePackFormatter<>).MakeGenericType(type);
|
||||
ParameterExpression param0 = Expression.Parameter(typeof(object), "formatter");
|
||||
ParameterExpression param1 = Expression.Parameter(typeof(MessagePackReader).MakeByRefType(), "reader");
|
||||
ParameterExpression param2 = Expression.Parameter(typeof(MessagePackSerializerOptions), "options");
|
||||
|
||||
MethodInfo deserializeMethodInfo = formatterType.GetRuntimeMethod("Deserialize", new[] { typeof(MessagePackReader).MakeByRefType(), typeof(MessagePackSerializerOptions) });
|
||||
|
||||
MethodCallExpression deserialize = Expression.Call(
|
||||
Expression.Convert(param0, formatterType),
|
||||
deserializeMethodInfo,
|
||||
param1,
|
||||
param2);
|
||||
|
||||
Expression body = deserialize;
|
||||
if (ti.IsValueType)
|
||||
{
|
||||
body = Expression.Convert(deserialize, typeof(object));
|
||||
}
|
||||
|
||||
deserializeMethod = Expression.Lambda<DeserializeMethod>(body, param0, param1, param2).Compile();
|
||||
|
||||
this.deserializers.TryAdd(type, deserializeMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return deserializeMethod(formatter, ref byteSequence, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fe17a811684aa2fa786684f83f7fbbe7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
|
||||
#pragma warning disable SA1649 // File name should match first type name
|
||||
|
||||
namespace MessagePack.Formatters
|
||||
{
|
||||
public sealed class NativeGuidFormatter : IMessagePackFormatter<Guid>
|
||||
{
|
||||
/// <summary>
|
||||
/// Unsafe binary Guid formatter. this is only allowed on LittleEndian environment.
|
||||
/// </summary>
|
||||
public static readonly IMessagePackFormatter<Guid> Instance = new NativeGuidFormatter();
|
||||
|
||||
private NativeGuidFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
/* Guid's underlying _a,...,_k field is sequential and same layout as .NET Framework and Mono(Unity).
|
||||
* But target machines must be same endian so restrict only for little endian. */
|
||||
|
||||
public unsafe void Serialize(ref MessagePackWriter writer, Guid value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
{
|
||||
throw new InvalidOperationException("NativeGuidFormatter only allows on little endian env.");
|
||||
}
|
||||
|
||||
var valueSpan = new ReadOnlySpan<byte>(&value, sizeof(Guid));
|
||||
writer.Write(valueSpan);
|
||||
}
|
||||
|
||||
public unsafe Guid Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
{
|
||||
throw new InvalidOperationException("NativeGuidFormatter only allows on little endian env.");
|
||||
}
|
||||
|
||||
ReadOnlySequence<byte> valueSequence = reader.ReadBytes().Value;
|
||||
if (valueSequence.Length != sizeof(Guid))
|
||||
{
|
||||
throw new MessagePackSerializationException("Invalid Guid Size.");
|
||||
}
|
||||
|
||||
Guid result;
|
||||
var resultSpan = new Span<byte>(&result, sizeof(Guid));
|
||||
valueSequence.CopyTo(resultSpan);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class NativeDecimalFormatter : IMessagePackFormatter<Decimal>
|
||||
{
|
||||
/// <summary>
|
||||
/// Unsafe binary Decimal formatter. this is only allows on LittleEndian environment.
|
||||
/// </summary>
|
||||
public static readonly IMessagePackFormatter<Decimal> Instance = new NativeDecimalFormatter();
|
||||
|
||||
private NativeDecimalFormatter()
|
||||
{
|
||||
}
|
||||
|
||||
/* decimal underlying "flags, hi, lo, mid" fields are sequential and same layuout with .NET Framework and Mono(Unity)
|
||||
* But target machines must be same endian so restrict only for little endian. */
|
||||
|
||||
public unsafe void Serialize(ref MessagePackWriter writer, Decimal value, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
{
|
||||
throw new InvalidOperationException("NativeDecimalFormatter only allows on little endian env.");
|
||||
}
|
||||
|
||||
var valueSpan = new ReadOnlySpan<byte>(&value, sizeof(Decimal));
|
||||
writer.Write(valueSpan);
|
||||
}
|
||||
|
||||
public unsafe Decimal Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (!BitConverter.IsLittleEndian)
|
||||
{
|
||||
throw new InvalidOperationException("NativeDecimalFormatter only allows on little endian env.");
|
||||
}
|
||||
|
||||
ReadOnlySequence<byte> valueSequence = reader.ReadBytes().Value;
|
||||
if (valueSequence.Length != sizeof(decimal))
|
||||
{
|
||||
throw new MessagePackSerializationException("Invalid decimal Size.");
|
||||
}
|
||||
|
||||
decimal result;
|
||||
var resultSpan = new Span<byte>(&result, sizeof(decimal));
|
||||
valueSequence.CopyTo(resultSpan);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2c4fcfc3f496806c7915aba0cdb3f1ba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,481 +0,0 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
// <auto-generated />
|
||||
|
||||
/*
|
||||
|
||||
The xxHash32 implementation is based on the code published by Yann Collet:
|
||||
https://raw.githubusercontent.com/Cyan4973/xxHash/5c174cfa4e45a42f94082dc0d4539b39696afea1/xxhash.c
|
||||
|
||||
xxHash - Fast Hash algorithm
|
||||
Copyright (C) 2012-2016, Yann Collet
|
||||
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- xxHash homepage: http://www.xxhash.com
|
||||
- xxHash source repository : https://github.com/Cyan4973/xxHash
|
||||
|
||||
*/
|
||||
|
||||
#if !NETCOREAPP
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace System
|
||||
{
|
||||
// xxHash32 is used for the hash code.
|
||||
// https://github.com/Cyan4973/xxHash
|
||||
|
||||
internal struct HashCode
|
||||
{
|
||||
private static readonly uint s_seed = GenerateGlobalSeed();
|
||||
|
||||
private const uint Prime1 = 2654435761U;
|
||||
private const uint Prime2 = 2246822519U;
|
||||
private const uint Prime3 = 3266489917U;
|
||||
private const uint Prime4 = 668265263U;
|
||||
private const uint Prime5 = 374761393U;
|
||||
|
||||
private uint _v1, _v2, _v3, _v4;
|
||||
private uint _queue1, _queue2, _queue3;
|
||||
private uint _length;
|
||||
|
||||
private static uint GenerateGlobalSeed()
|
||||
{
|
||||
var bytes = new byte[4];
|
||||
using (var rng = RandomNumberGenerator.Create())
|
||||
{
|
||||
rng.GetBytes(bytes);
|
||||
}
|
||||
|
||||
return BitConverter.ToUInt32(bytes, 0);
|
||||
}
|
||||
|
||||
public static int Combine<T1>(T1 value1)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
// Provide a way of diffusing bits from something with a limited
|
||||
// input hash space. For example, many enums only have a few
|
||||
// possible hashes, only using the bottom few bits of the code. Some
|
||||
// collections are built on the assumption that hashes are spread
|
||||
// over a larger space, so diffusing the bits may help the
|
||||
// collection work more efficiently.
|
||||
|
||||
uint hc1 = (uint)(value1?.GetHashCode() ?? 0);
|
||||
|
||||
uint hash = MixEmptyState();
|
||||
hash += 4;
|
||||
|
||||
hash = QueueRound(hash, hc1);
|
||||
|
||||
hash = MixFinal(hash);
|
||||
return (int)hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static int Combine<T1, T2>(T1 value1, T2 value2)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
uint hc1 = (uint)(value1?.GetHashCode() ?? 0);
|
||||
uint hc2 = (uint)(value2?.GetHashCode() ?? 0);
|
||||
|
||||
uint hash = MixEmptyState();
|
||||
hash += 8;
|
||||
|
||||
hash = QueueRound(hash, hc1);
|
||||
hash = QueueRound(hash, hc2);
|
||||
|
||||
hash = MixFinal(hash);
|
||||
return (int)hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static int Combine<T1, T2, T3>(T1 value1, T2 value2, T3 value3)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
uint hc1 = (uint)(value1?.GetHashCode() ?? 0);
|
||||
uint hc2 = (uint)(value2?.GetHashCode() ?? 0);
|
||||
uint hc3 = (uint)(value3?.GetHashCode() ?? 0);
|
||||
|
||||
uint hash = MixEmptyState();
|
||||
hash += 12;
|
||||
|
||||
hash = QueueRound(hash, hc1);
|
||||
hash = QueueRound(hash, hc2);
|
||||
hash = QueueRound(hash, hc3);
|
||||
|
||||
hash = MixFinal(hash);
|
||||
return (int)hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static int Combine<T1, T2, T3, T4>(T1 value1, T2 value2, T3 value3, T4 value4)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
uint hc1 = (uint)(value1?.GetHashCode() ?? 0);
|
||||
uint hc2 = (uint)(value2?.GetHashCode() ?? 0);
|
||||
uint hc3 = (uint)(value3?.GetHashCode() ?? 0);
|
||||
uint hc4 = (uint)(value4?.GetHashCode() ?? 0);
|
||||
|
||||
Initialize(out uint v1, out uint v2, out uint v3, out uint v4);
|
||||
|
||||
v1 = Round(v1, hc1);
|
||||
v2 = Round(v2, hc2);
|
||||
v3 = Round(v3, hc3);
|
||||
v4 = Round(v4, hc4);
|
||||
|
||||
uint hash = MixState(v1, v2, v3, v4);
|
||||
hash += 16;
|
||||
|
||||
hash = MixFinal(hash);
|
||||
return (int)hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static int Combine<T1, T2, T3, T4, T5>(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
uint hc1 = (uint)(value1?.GetHashCode() ?? 0);
|
||||
uint hc2 = (uint)(value2?.GetHashCode() ?? 0);
|
||||
uint hc3 = (uint)(value3?.GetHashCode() ?? 0);
|
||||
uint hc4 = (uint)(value4?.GetHashCode() ?? 0);
|
||||
uint hc5 = (uint)(value5?.GetHashCode() ?? 0);
|
||||
|
||||
Initialize(out uint v1, out uint v2, out uint v3, out uint v4);
|
||||
|
||||
v1 = Round(v1, hc1);
|
||||
v2 = Round(v2, hc2);
|
||||
v3 = Round(v3, hc3);
|
||||
v4 = Round(v4, hc4);
|
||||
|
||||
uint hash = MixState(v1, v2, v3, v4);
|
||||
hash += 20;
|
||||
|
||||
hash = QueueRound(hash, hc5);
|
||||
|
||||
hash = MixFinal(hash);
|
||||
return (int)hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static int Combine<T1, T2, T3, T4, T5, T6>(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
uint hc1 = (uint)(value1?.GetHashCode() ?? 0);
|
||||
uint hc2 = (uint)(value2?.GetHashCode() ?? 0);
|
||||
uint hc3 = (uint)(value3?.GetHashCode() ?? 0);
|
||||
uint hc4 = (uint)(value4?.GetHashCode() ?? 0);
|
||||
uint hc5 = (uint)(value5?.GetHashCode() ?? 0);
|
||||
uint hc6 = (uint)(value6?.GetHashCode() ?? 0);
|
||||
|
||||
Initialize(out uint v1, out uint v2, out uint v3, out uint v4);
|
||||
|
||||
v1 = Round(v1, hc1);
|
||||
v2 = Round(v2, hc2);
|
||||
v3 = Round(v3, hc3);
|
||||
v4 = Round(v4, hc4);
|
||||
|
||||
uint hash = MixState(v1, v2, v3, v4);
|
||||
hash += 24;
|
||||
|
||||
hash = QueueRound(hash, hc5);
|
||||
hash = QueueRound(hash, hc6);
|
||||
|
||||
hash = MixFinal(hash);
|
||||
return (int)hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static int Combine<T1, T2, T3, T4, T5, T6, T7>(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
uint hc1 = (uint)(value1?.GetHashCode() ?? 0);
|
||||
uint hc2 = (uint)(value2?.GetHashCode() ?? 0);
|
||||
uint hc3 = (uint)(value3?.GetHashCode() ?? 0);
|
||||
uint hc4 = (uint)(value4?.GetHashCode() ?? 0);
|
||||
uint hc5 = (uint)(value5?.GetHashCode() ?? 0);
|
||||
uint hc6 = (uint)(value6?.GetHashCode() ?? 0);
|
||||
uint hc7 = (uint)(value7?.GetHashCode() ?? 0);
|
||||
|
||||
Initialize(out uint v1, out uint v2, out uint v3, out uint v4);
|
||||
|
||||
v1 = Round(v1, hc1);
|
||||
v2 = Round(v2, hc2);
|
||||
v3 = Round(v3, hc3);
|
||||
v4 = Round(v4, hc4);
|
||||
|
||||
uint hash = MixState(v1, v2, v3, v4);
|
||||
hash += 28;
|
||||
|
||||
hash = QueueRound(hash, hc5);
|
||||
hash = QueueRound(hash, hc6);
|
||||
hash = QueueRound(hash, hc7);
|
||||
|
||||
hash = MixFinal(hash);
|
||||
return (int)hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static int Combine<T1, T2, T3, T4, T5, T6, T7, T8>(T1 value1, T2 value2, T3 value3, T4 value4, T5 value5, T6 value6, T7 value7, T8 value8)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
uint hc1 = (uint)(value1?.GetHashCode() ?? 0);
|
||||
uint hc2 = (uint)(value2?.GetHashCode() ?? 0);
|
||||
uint hc3 = (uint)(value3?.GetHashCode() ?? 0);
|
||||
uint hc4 = (uint)(value4?.GetHashCode() ?? 0);
|
||||
uint hc5 = (uint)(value5?.GetHashCode() ?? 0);
|
||||
uint hc6 = (uint)(value6?.GetHashCode() ?? 0);
|
||||
uint hc7 = (uint)(value7?.GetHashCode() ?? 0);
|
||||
uint hc8 = (uint)(value8?.GetHashCode() ?? 0);
|
||||
|
||||
Initialize(out uint v1, out uint v2, out uint v3, out uint v4);
|
||||
|
||||
v1 = Round(v1, hc1);
|
||||
v2 = Round(v2, hc2);
|
||||
v3 = Round(v3, hc3);
|
||||
v4 = Round(v4, hc4);
|
||||
|
||||
v1 = Round(v1, hc5);
|
||||
v2 = Round(v2, hc6);
|
||||
v3 = Round(v3, hc7);
|
||||
v4 = Round(v4, hc8);
|
||||
|
||||
uint hash = MixState(v1, v2, v3, v4);
|
||||
hash += 32;
|
||||
|
||||
hash = MixFinal(hash);
|
||||
return (int)hash;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void Initialize(out uint v1, out uint v2, out uint v3, out uint v4)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
v1 = s_seed + Prime1 + Prime2;
|
||||
v2 = s_seed + Prime2;
|
||||
v3 = s_seed;
|
||||
v4 = s_seed - Prime1;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static uint Round(uint hash, uint input)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return BitOperations.RotateLeft(hash + input * Prime2, 13) * Prime1;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static uint QueueRound(uint hash, uint queuedValue)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return BitOperations.RotateLeft(hash + queuedValue * Prime3, 17) * Prime4;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static uint MixState(uint v1, uint v2, uint v3, uint v4)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return BitOperations.RotateLeft(v1, 1) + BitOperations.RotateLeft(v2, 7) + BitOperations.RotateLeft(v3, 12) + BitOperations.RotateLeft(v4, 18);
|
||||
}
|
||||
}
|
||||
|
||||
private static uint MixEmptyState()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return s_seed + Prime5;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static uint MixFinal(uint hash)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
hash ^= hash >> 15;
|
||||
hash *= Prime2;
|
||||
hash ^= hash >> 13;
|
||||
hash *= Prime3;
|
||||
hash ^= hash >> 16;
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public void Add<T>(T value)
|
||||
{
|
||||
Add(value?.GetHashCode() ?? 0);
|
||||
}
|
||||
|
||||
public void Add<T>(T value, IEqualityComparer<T> comparer)
|
||||
{
|
||||
Add(comparer != null ? comparer.GetHashCode(value) : (value?.GetHashCode() ?? 0));
|
||||
}
|
||||
|
||||
private void Add(int value)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
// The original xxHash works as follows:
|
||||
// 0. Initialize immediately. We can't do this in a struct (no
|
||||
// default ctor).
|
||||
// 1. Accumulate blocks of length 16 (4 uints) into 4 accumulators.
|
||||
// 2. Accumulate remaining blocks of length 4 (1 uint) into the
|
||||
// hash.
|
||||
// 3. Accumulate remaining blocks of length 1 into the hash.
|
||||
|
||||
// There is no need for #3 as this type only accepts ints. _queue1,
|
||||
// _queue2 and _queue3 are basically a buffer so that when
|
||||
// ToHashCode is called we can execute #2 correctly.
|
||||
|
||||
// We need to initialize the xxHash32 state (_v1 to _v4) lazily (see
|
||||
// #0) nd the last place that can be done if you look at the
|
||||
// original code is just before the first block of 16 bytes is mixed
|
||||
// in. The xxHash32 state is never used for streams containing fewer
|
||||
// than 16 bytes.
|
||||
|
||||
// To see what's really going on here, have a look at the Combine
|
||||
// methods.
|
||||
|
||||
uint val = (uint)value;
|
||||
|
||||
// Storing the value of _length locally shaves of quite a few bytes
|
||||
// in the resulting machine code.
|
||||
uint previousLength = _length++;
|
||||
uint position = previousLength % 4;
|
||||
|
||||
// Switch can't be inlined.
|
||||
|
||||
if (position == 0)
|
||||
_queue1 = val;
|
||||
else if (position == 1)
|
||||
_queue2 = val;
|
||||
else if (position == 2)
|
||||
_queue3 = val;
|
||||
else // position == 3
|
||||
{
|
||||
if (previousLength == 3)
|
||||
Initialize(out _v1, out _v2, out _v3, out _v4);
|
||||
|
||||
_v1 = Round(_v1, _queue1);
|
||||
_v2 = Round(_v2, _queue2);
|
||||
_v3 = Round(_v3, _queue3);
|
||||
_v4 = Round(_v4, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int ToHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
// Storing the value of _length locally shaves of quite a few bytes
|
||||
// in the resulting machine code.
|
||||
uint length = _length;
|
||||
|
||||
// position refers to the *next* queue position in this method, so
|
||||
// position == 1 means that _queue1 is populated; _queue2 would have
|
||||
// been populated on the next call to Add.
|
||||
uint position = length % 4;
|
||||
|
||||
// If the length is less than 4, _v1 to _v4 don't contain anything
|
||||
// yet. xxHash32 treats this differently.
|
||||
|
||||
uint hash = length < 4 ? MixEmptyState() : MixState(_v1, _v2, _v3, _v4);
|
||||
|
||||
// _length is incremented once per Add(Int32) and is therefore 4
|
||||
// times too small (xxHash length is in bytes, not ints).
|
||||
|
||||
hash += length * 4;
|
||||
|
||||
// Mix what remains in the queue
|
||||
|
||||
// Switch can't be inlined right now, so use as few branches as
|
||||
// possible by manually excluding impossible scenarios (position > 1
|
||||
// is always false if position is not > 0).
|
||||
if (position > 0)
|
||||
{
|
||||
hash = QueueRound(hash, _queue1);
|
||||
if (position > 1)
|
||||
{
|
||||
hash = QueueRound(hash, _queue2);
|
||||
if (position > 2)
|
||||
hash = QueueRound(hash, _queue3);
|
||||
}
|
||||
}
|
||||
|
||||
hash = MixFinal(hash);
|
||||
return (int)hash;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning disable 0809
|
||||
// Obsolete member 'memberA' overrides non-obsolete member 'memberB'.
|
||||
// Disallowing GetHashCode and Equals is by design
|
||||
|
||||
// * We decided to not override GetHashCode() to produce the hash code
|
||||
// as this would be weird, both naming-wise as well as from a
|
||||
// behavioral standpoint (GetHashCode() should return the object's
|
||||
// hash code, not the one being computed).
|
||||
|
||||
// * Even though ToHashCode() can be called safely multiple times on
|
||||
// this implementation, it is not part of the contract. If the
|
||||
// implementation has to change in the future we don't want to worry
|
||||
// about people who might have incorrectly used this type.
|
||||
|
||||
[Obsolete("HashCode is a mutable struct and should not be compared with other HashCodes. Use ToHashCode to retrieve the computed hash code.", error: true)]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public override int GetHashCode() => throw new NotSupportedException();
|
||||
|
||||
[Obsolete("HashCode is a mutable struct and should not be compared with other HashCodes.", error: true)]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public override bool Equals(object obj) => throw new NotSupportedException();
|
||||
#pragma warning restore 0809
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9909e9074ddc955f18803bd2037102f7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.ExceptionServices;
|
||||
using MessagePack.Formatters;
|
||||
|
||||
namespace MessagePack
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows querying for a formatter for serializing or deserializing a particular <see cref="Type" />.
|
||||
/// </summary>
|
||||
public interface IFormatterResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets an <see cref="IMessagePackFormatter{T}"/> instance that can serialize or deserialize some type <typeparamref name="T"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of value to be serialized or deserialized.</typeparam>
|
||||
/// <returns>A formatter, if this resolver supplies one for type <typeparamref name="T"/>; otherwise <c>null</c>.</returns>
|
||||
IMessagePackFormatter<T> GetFormatter<T>();
|
||||
}
|
||||
|
||||
public static class FormatterResolverExtensions
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static IMessagePackFormatter<T> GetFormatterWithVerify<T>(this IFormatterResolver resolver)
|
||||
{
|
||||
if (resolver is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(resolver));
|
||||
}
|
||||
|
||||
IMessagePackFormatter<T> formatter;
|
||||
try
|
||||
{
|
||||
formatter = resolver.GetFormatter<T>();
|
||||
}
|
||||
catch (TypeInitializationException ex)
|
||||
{
|
||||
// The fact that we're using static constructors to initialize this is an internal detail.
|
||||
// Rethrow the inner exception if there is one.
|
||||
// Do it carefully so as to not stomp on the original callstack.
|
||||
Throw(ex);
|
||||
return default; // not reachable
|
||||
}
|
||||
|
||||
if (formatter == null)
|
||||
{
|
||||
Throw(typeof(T), resolver);
|
||||
}
|
||||
|
||||
return formatter;
|
||||
}
|
||||
|
||||
private static void Throw(TypeInitializationException ex)
|
||||
{
|
||||
ExceptionDispatchInfo.Capture(ex.InnerException ?? ex).Throw();
|
||||
}
|
||||
|
||||
private static void Throw(Type t, IFormatterResolver resolver)
|
||||
{
|
||||
throw new FormatterNotRegisteredException(t.FullName + " is not registered in resolver: " + resolver.GetType());
|
||||
}
|
||||
|
||||
public static object GetFormatterDynamic(this IFormatterResolver resolver, Type type)
|
||||
{
|
||||
if (resolver is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(resolver));
|
||||
}
|
||||
|
||||
if (type is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(type));
|
||||
}
|
||||
|
||||
MethodInfo methodInfo = typeof(IFormatterResolver).GetRuntimeMethod(nameof(IFormatterResolver.GetFormatter), Type.EmptyTypes);
|
||||
|
||||
var formatter = methodInfo.MakeGenericMethod(type).Invoke(resolver, null);
|
||||
return formatter;
|
||||
}
|
||||
|
||||
internal static object GetFormatterDynamicWithVerify(this IFormatterResolver resolver, Type type)
|
||||
{
|
||||
object result = GetFormatterDynamic(resolver, type);
|
||||
if (result == null)
|
||||
{
|
||||
Throw(type, resolver);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public class FormatterNotRegisteredException : MessagePackSerializationException
|
||||
{
|
||||
public FormatterNotRegisteredException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 51a5ebbfbdf12b0cc80f0f57550f61a0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7303cf02620047543873c4663322e112
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,302 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
|
||||
#pragma warning disable SA1649 // File name should match first type name
|
||||
|
||||
namespace MessagePack.Internal
|
||||
{
|
||||
/* Safe for multiple-read, single-write.
|
||||
* Add and Get Key is asymmetric. */
|
||||
|
||||
internal interface IAsymmetricEqualityComparer<TKey1, TKey2>
|
||||
{
|
||||
int GetHashCode(TKey1 key1);
|
||||
|
||||
int GetHashCode(TKey2 key2);
|
||||
|
||||
bool Equals(TKey1 x, TKey1 y); // when used rehash
|
||||
|
||||
bool Equals(TKey1 x, TKey2 y); // when used get
|
||||
}
|
||||
|
||||
internal class StringArraySegmentByteAscymmetricEqualityComparer : IAsymmetricEqualityComparer<byte[], ArraySegment<byte>>
|
||||
{
|
||||
private static readonly bool Is32Bit = IntPtr.Size == 4;
|
||||
|
||||
public bool Equals(byte[] x, byte[] y)
|
||||
{
|
||||
if (x.Length != y.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < x.Length; i++)
|
||||
{
|
||||
if (x[i] != y[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Equals(byte[] x, ArraySegment<byte> y)
|
||||
{
|
||||
return x.AsSpan().SequenceEqual(y);
|
||||
}
|
||||
|
||||
public int GetHashCode(byte[] key1)
|
||||
{
|
||||
return this.GetHashCode(new ArraySegment<byte>(key1, 0, key1.Length));
|
||||
}
|
||||
|
||||
public int GetHashCode(ArraySegment<byte> key2)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
if (Is32Bit)
|
||||
{
|
||||
return (int)FarmHash.Hash32(key2);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (int)FarmHash.Hash64(key2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class AsymmetricKeyHashTable<TKey1, TKey2, TValue>
|
||||
{
|
||||
private Entry[] buckets;
|
||||
private int size; // only use in writer lock
|
||||
|
||||
private readonly object writerLock = new object();
|
||||
private readonly float loadFactor;
|
||||
private readonly IAsymmetricEqualityComparer<TKey1, TKey2> comparer;
|
||||
|
||||
public AsymmetricKeyHashTable(IAsymmetricEqualityComparer<TKey1, TKey2> comparer)
|
||||
: this(4, 0.72f, comparer)
|
||||
{
|
||||
}
|
||||
|
||||
public AsymmetricKeyHashTable(int capacity, float loadFactor, IAsymmetricEqualityComparer<TKey1, TKey2> comparer)
|
||||
{
|
||||
var tableSize = CalculateCapacity(capacity, loadFactor);
|
||||
this.buckets = new Entry[tableSize];
|
||||
this.loadFactor = loadFactor;
|
||||
this.comparer = comparer;
|
||||
}
|
||||
|
||||
public TValue AddOrGet(TKey1 key1, Func<TKey1, TValue> valueFactory)
|
||||
{
|
||||
TValue v;
|
||||
this.TryAddInternal(key1, valueFactory, out v);
|
||||
return v;
|
||||
}
|
||||
|
||||
public bool TryAdd(TKey1 key, TValue value)
|
||||
{
|
||||
return this.TryAdd(key, _ => value); // closure capture
|
||||
}
|
||||
|
||||
public bool TryAdd(TKey1 key, Func<TKey1, TValue> valueFactory)
|
||||
{
|
||||
return this.TryAddInternal(key, valueFactory, out TValue _);
|
||||
}
|
||||
|
||||
private bool TryAddInternal(TKey1 key, Func<TKey1, TValue> valueFactory, out TValue resultingValue)
|
||||
{
|
||||
lock (this.writerLock)
|
||||
{
|
||||
var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor);
|
||||
|
||||
if (this.buckets.Length < nextCapacity)
|
||||
{
|
||||
// rehash
|
||||
var nextBucket = new Entry[nextCapacity];
|
||||
for (int i = 0; i < this.buckets.Length; i++)
|
||||
{
|
||||
Entry e = this.buckets[i];
|
||||
while (e != null)
|
||||
{
|
||||
var newEntry = new Entry { Key = e.Key, Value = e.Value, Hash = e.Hash };
|
||||
this.AddToBuckets(nextBucket, key, newEntry, null, out resultingValue);
|
||||
e = e.Next;
|
||||
}
|
||||
}
|
||||
|
||||
// add entry(if failed to add, only do resize)
|
||||
var successAdd = this.AddToBuckets(nextBucket, key, null, valueFactory, out resultingValue);
|
||||
|
||||
// replace field(threadsafe for read)
|
||||
VolatileWrite(ref this.buckets, nextBucket);
|
||||
|
||||
if (successAdd)
|
||||
{
|
||||
this.size++;
|
||||
}
|
||||
|
||||
return successAdd;
|
||||
}
|
||||
else
|
||||
{
|
||||
// add entry(insert last is thread safe for read)
|
||||
var successAdd = this.AddToBuckets(this.buckets, key, null, valueFactory, out resultingValue);
|
||||
if (successAdd)
|
||||
{
|
||||
this.size++;
|
||||
}
|
||||
|
||||
return successAdd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool AddToBuckets(Entry[] buckets, TKey1 newKey, Entry newEntryOrNull, Func<TKey1, TValue> valueFactory, out TValue resultingValue)
|
||||
{
|
||||
var h = (newEntryOrNull != null) ? newEntryOrNull.Hash : this.comparer.GetHashCode(newKey);
|
||||
if (buckets[h & (buckets.Length - 1)] == null)
|
||||
{
|
||||
if (newEntryOrNull != null)
|
||||
{
|
||||
resultingValue = newEntryOrNull.Value;
|
||||
VolatileWrite(ref buckets[h & (buckets.Length - 1)], newEntryOrNull);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultingValue = valueFactory(newKey);
|
||||
VolatileWrite(ref buckets[h & (buckets.Length - 1)], new Entry { Key = newKey, Value = resultingValue, Hash = h });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Entry searchLastEntry = buckets[h & (buckets.Length - 1)];
|
||||
while (true)
|
||||
{
|
||||
if (this.comparer.Equals(searchLastEntry.Key, newKey))
|
||||
{
|
||||
resultingValue = searchLastEntry.Value;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (searchLastEntry.Next == null)
|
||||
{
|
||||
if (newEntryOrNull != null)
|
||||
{
|
||||
resultingValue = newEntryOrNull.Value;
|
||||
VolatileWrite(ref searchLastEntry.Next, newEntryOrNull);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultingValue = valueFactory(newKey);
|
||||
VolatileWrite(ref searchLastEntry.Next, new Entry { Key = newKey, Value = resultingValue, Hash = h });
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
searchLastEntry = searchLastEntry.Next;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryGetValue(TKey2 key, out TValue value)
|
||||
{
|
||||
Entry[] table = this.buckets;
|
||||
var hash = this.comparer.GetHashCode(key);
|
||||
Entry entry = table[hash & table.Length - 1];
|
||||
|
||||
if (entry == null)
|
||||
{
|
||||
goto NOT_FOUND;
|
||||
}
|
||||
|
||||
if (this.comparer.Equals(entry.Key, key))
|
||||
{
|
||||
value = entry.Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
Entry next = entry.Next;
|
||||
while (next != null)
|
||||
{
|
||||
if (this.comparer.Equals(next.Key, key))
|
||||
{
|
||||
value = next.Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
next = next.Next;
|
||||
}
|
||||
|
||||
NOT_FOUND:
|
||||
value = default(TValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static int CalculateCapacity(int collectionSize, float loadFactor)
|
||||
{
|
||||
var initialCapacity = (int)(((float)collectionSize) / loadFactor);
|
||||
var capacity = 1;
|
||||
while (capacity < initialCapacity)
|
||||
{
|
||||
capacity <<= 1;
|
||||
}
|
||||
|
||||
if (capacity < 8)
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
return capacity;
|
||||
}
|
||||
|
||||
private static void VolatileWrite(ref Entry location, Entry value)
|
||||
{
|
||||
System.Threading.Volatile.Write(ref location, value);
|
||||
}
|
||||
|
||||
private static void VolatileWrite(ref Entry[] location, Entry[] value)
|
||||
{
|
||||
System.Threading.Volatile.Write(ref location, value);
|
||||
}
|
||||
|
||||
private class Entry
|
||||
{
|
||||
#pragma warning disable SA1401 // Fields should be private
|
||||
internal TKey1 Key;
|
||||
internal TValue Value;
|
||||
internal int Hash;
|
||||
internal Entry Next;
|
||||
#pragma warning restore SA1401 // Fields should be private
|
||||
|
||||
// from debugger only
|
||||
public override string ToString()
|
||||
{
|
||||
return "Count:" + this.Count;
|
||||
}
|
||||
|
||||
internal int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
var count = 1;
|
||||
Entry n = this;
|
||||
while (n.Next != null)
|
||||
{
|
||||
count++;
|
||||
n = n.Next;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6862254987b9738ab9482616a323c2b5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,504 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
#pragma warning disable SA1509 // Opening braces should not be preceded by blank line
|
||||
|
||||
namespace MessagePack.Internal
|
||||
{
|
||||
// Key = long, Value = int for UTF8String Dictionary
|
||||
|
||||
/// <remarks>
|
||||
/// This code is used by dynamically generated code as well as AOT generated code,
|
||||
/// and thus must be public for the "C# generated and compiled into saved assembly" scenario.
|
||||
/// </remarks>
|
||||
public class AutomataDictionary : IEnumerable<KeyValuePair<string, int>>
|
||||
{
|
||||
private readonly AutomataNode root;
|
||||
|
||||
public AutomataDictionary()
|
||||
{
|
||||
this.root = new AutomataNode(0);
|
||||
}
|
||||
|
||||
public void Add(string str, int value)
|
||||
{
|
||||
ReadOnlySpan<byte> bytes = Encoding.UTF8.GetBytes(str);
|
||||
AutomataNode node = this.root;
|
||||
|
||||
while (bytes.Length > 0)
|
||||
{
|
||||
var key = AutomataKeyGen.GetKey(ref bytes);
|
||||
|
||||
if (bytes.Length == 0)
|
||||
{
|
||||
node = node.Add(key, value, str);
|
||||
}
|
||||
else
|
||||
{
|
||||
node = node.Add(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryGetValue(in ReadOnlySequence<byte> bytes, out int value) => this.TryGetValue(bytes.ToArray(), out value);
|
||||
|
||||
public bool TryGetValue(ReadOnlySpan<byte> bytes, out int value)
|
||||
{
|
||||
AutomataNode node = this.root;
|
||||
|
||||
while (bytes.Length > 0 && node != null)
|
||||
{
|
||||
node = node.SearchNext(ref bytes);
|
||||
}
|
||||
|
||||
if (node == null)
|
||||
{
|
||||
value = -1;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = node.Value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// for debugging
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
ToStringCore(this.root.YieldChildren(), sb, 0);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static void ToStringCore(IEnumerable<AutomataNode> nexts, StringBuilder sb, int depth)
|
||||
{
|
||||
foreach (AutomataNode item in nexts)
|
||||
{
|
||||
if (depth != 0)
|
||||
{
|
||||
sb.Append(' ', depth * 2);
|
||||
}
|
||||
|
||||
sb.Append("[" + item.Key + "]");
|
||||
if (item.Value != -1)
|
||||
{
|
||||
sb.Append("(" + item.OriginalKey + ")");
|
||||
sb.Append(" = ");
|
||||
sb.Append(item.Value);
|
||||
}
|
||||
|
||||
sb.AppendLine();
|
||||
ToStringCore(item.YieldChildren(), sb, depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return this.GetEnumerator();
|
||||
}
|
||||
|
||||
public IEnumerator<KeyValuePair<string, int>> GetEnumerator()
|
||||
{
|
||||
return YieldCore(this.root.YieldChildren()).GetEnumerator();
|
||||
}
|
||||
|
||||
private static IEnumerable<KeyValuePair<string, int>> YieldCore(IEnumerable<AutomataNode> nexts)
|
||||
{
|
||||
foreach (AutomataNode item in nexts)
|
||||
{
|
||||
if (item.Value != -1)
|
||||
{
|
||||
yield return new KeyValuePair<string, int>(item.OriginalKey, item.Value);
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string, int> x in YieldCore(item.YieldChildren()))
|
||||
{
|
||||
yield return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* IL Emit */
|
||||
|
||||
#if !NET_STANDARD_2_0
|
||||
|
||||
public void EmitMatch(ILGenerator il, LocalBuilder bytesSpan, LocalBuilder key, Action<KeyValuePair<string, int>> onFound, Action onNotFound)
|
||||
{
|
||||
this.root.EmitSearchNext(il, bytesSpan, key, onFound, onNotFound);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
private class AutomataNode : IComparable<AutomataNode>
|
||||
{
|
||||
private static readonly AutomataNode[] EmptyNodes = new AutomataNode[0];
|
||||
private static readonly ulong[] EmptyKeys = new ulong[0];
|
||||
|
||||
#pragma warning disable SA1401 // Fields should be private
|
||||
internal ulong Key;
|
||||
internal int Value;
|
||||
internal string OriginalKey;
|
||||
#pragma warning restore SA1401 // Fields should be private
|
||||
|
||||
private AutomataNode[] nexts;
|
||||
private ulong[] nextKeys;
|
||||
private int count;
|
||||
|
||||
public bool HasChildren
|
||||
{
|
||||
get { return this.count != 0; }
|
||||
}
|
||||
|
||||
public AutomataNode(ulong key)
|
||||
{
|
||||
this.Key = key;
|
||||
this.Value = -1;
|
||||
this.nexts = EmptyNodes;
|
||||
this.nextKeys = EmptyKeys;
|
||||
this.count = 0;
|
||||
this.OriginalKey = null;
|
||||
}
|
||||
|
||||
public AutomataNode Add(ulong key)
|
||||
{
|
||||
var index = Array.BinarySearch(this.nextKeys, 0, this.count, key);
|
||||
if (index < 0)
|
||||
{
|
||||
if (this.nexts.Length == this.count)
|
||||
{
|
||||
Array.Resize<AutomataNode>(ref this.nexts, (this.count == 0) ? 4 : (this.count * 2));
|
||||
Array.Resize<ulong>(ref this.nextKeys, (this.count == 0) ? 4 : (this.count * 2));
|
||||
}
|
||||
|
||||
this.count++;
|
||||
|
||||
var nextNode = new AutomataNode(key);
|
||||
this.nexts[this.count - 1] = nextNode;
|
||||
this.nextKeys[this.count - 1] = key;
|
||||
Array.Sort(this.nexts, 0, this.count);
|
||||
Array.Sort(this.nextKeys, 0, this.count);
|
||||
return nextNode;
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.nexts[index];
|
||||
}
|
||||
}
|
||||
|
||||
public AutomataNode Add(ulong key, int value, string originalKey)
|
||||
{
|
||||
AutomataNode v = this.Add(key);
|
||||
v.Value = value;
|
||||
v.OriginalKey = originalKey;
|
||||
return v;
|
||||
}
|
||||
|
||||
public AutomataNode SearchNext(ref ReadOnlySpan<byte> value)
|
||||
{
|
||||
var key = AutomataKeyGen.GetKey(ref value);
|
||||
if (this.count < 4)
|
||||
{
|
||||
// linear search
|
||||
for (int i = 0; i < this.count; i++)
|
||||
{
|
||||
if (this.nextKeys[i] == key)
|
||||
{
|
||||
return this.nexts[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// binary search
|
||||
var index = BinarySearch(this.nextKeys, 0, this.count, key);
|
||||
if (index >= 0)
|
||||
{
|
||||
return this.nexts[index];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static int BinarySearch(ulong[] array, int index, int length, ulong value)
|
||||
{
|
||||
int lo = index;
|
||||
int hi = index + length - 1;
|
||||
while (lo <= hi)
|
||||
{
|
||||
int i = lo + ((hi - lo) >> 1);
|
||||
|
||||
var arrayValue = array[i];
|
||||
int order;
|
||||
if (arrayValue < value)
|
||||
{
|
||||
order = -1;
|
||||
}
|
||||
else if (arrayValue > value)
|
||||
{
|
||||
order = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
order = 0;
|
||||
}
|
||||
|
||||
if (order == 0)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
if (order < 0)
|
||||
{
|
||||
lo = i + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
hi = i - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ~lo;
|
||||
}
|
||||
|
||||
public int CompareTo(AutomataNode other)
|
||||
{
|
||||
return this.Key.CompareTo(other.Key);
|
||||
}
|
||||
|
||||
public IEnumerable<AutomataNode> YieldChildren()
|
||||
{
|
||||
for (int i = 0; i < this.count; i++)
|
||||
{
|
||||
yield return this.nexts[i];
|
||||
}
|
||||
}
|
||||
|
||||
#if !NET_STANDARD_2_0
|
||||
|
||||
// SearchNext(ref ReadOnlySpan<byte> bytes)
|
||||
public void EmitSearchNext(ILGenerator il, LocalBuilder bytesSpan, LocalBuilder key, Action<KeyValuePair<string, int>> onFound, Action onNotFound)
|
||||
{
|
||||
// key = AutomataKeyGen.GetKey(ref bytesSpan);
|
||||
il.EmitLdloca(bytesSpan);
|
||||
il.EmitCall(AutomataKeyGen.GetKeyMethod);
|
||||
il.EmitStloc(key);
|
||||
|
||||
// match children.
|
||||
EmitSearchNextCore(il, bytesSpan, key, onFound, onNotFound, this.nexts, this.count);
|
||||
}
|
||||
|
||||
private static void EmitSearchNextCore(ILGenerator il, LocalBuilder bytesSpan, LocalBuilder key, Action<KeyValuePair<string, int>> onFound, Action onNotFound, AutomataNode[] nexts, int count)
|
||||
{
|
||||
if (count < 4)
|
||||
{
|
||||
// linear-search
|
||||
AutomataNode[] valueExists = nexts.Take(count).Where(x => x.Value != -1).ToArray();
|
||||
AutomataNode[] childrenExists = nexts.Take(count).Where(x => x.HasChildren).ToArray();
|
||||
Label gotoSearchNext = il.DefineLabel();
|
||||
Label gotoNotFound = il.DefineLabel();
|
||||
|
||||
{
|
||||
// bytesSpan.Length
|
||||
il.EmitLdloca(bytesSpan);
|
||||
il.EmitCall(typeof(ReadOnlySpan<byte>).GetRuntimeProperty(nameof(ReadOnlySpan<byte>.Length)).GetMethod);
|
||||
if (childrenExists.Length != 0 && valueExists.Length == 0)
|
||||
{
|
||||
il.Emit(OpCodes.Brfalse, gotoNotFound); // if(bytesSpan.Length == 0)
|
||||
}
|
||||
else
|
||||
{
|
||||
il.Emit(OpCodes.Brtrue, gotoSearchNext); // if(bytesSpan.Length != 0)
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Label[] ifValueNexts = Enumerable.Range(0, Math.Max(valueExists.Length - 1, 0)).Select(_ => il.DefineLabel()).ToArray();
|
||||
for (int i = 0; i < valueExists.Length; i++)
|
||||
{
|
||||
Label notFoundLabel = il.DefineLabel();
|
||||
if (i != 0)
|
||||
{
|
||||
il.MarkLabel(ifValueNexts[i - 1]);
|
||||
}
|
||||
|
||||
il.EmitLdloc(key);
|
||||
il.EmitULong(valueExists[i].Key);
|
||||
il.Emit(OpCodes.Bne_Un, notFoundLabel);
|
||||
|
||||
// found
|
||||
onFound(new KeyValuePair<string, int>(valueExists[i].OriginalKey, valueExists[i].Value));
|
||||
|
||||
// notfound
|
||||
il.MarkLabel(notFoundLabel);
|
||||
if (i != valueExists.Length - 1)
|
||||
{
|
||||
il.Emit(OpCodes.Br, ifValueNexts[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
onNotFound();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
il.MarkLabel(gotoSearchNext);
|
||||
Label[] ifRecNext = Enumerable.Range(0, Math.Max(childrenExists.Length - 1, 0)).Select(_ => il.DefineLabel()).ToArray();
|
||||
for (int i = 0; i < childrenExists.Length; i++)
|
||||
{
|
||||
Label notFoundLabel = il.DefineLabel();
|
||||
if (i != 0)
|
||||
{
|
||||
il.MarkLabel(ifRecNext[i - 1]);
|
||||
}
|
||||
|
||||
il.EmitLdloc(key);
|
||||
il.EmitULong(childrenExists[i].Key);
|
||||
il.Emit(OpCodes.Bne_Un, notFoundLabel);
|
||||
|
||||
// found
|
||||
childrenExists[i].EmitSearchNext(il, bytesSpan, key, onFound, onNotFound);
|
||||
|
||||
// notfound
|
||||
il.MarkLabel(notFoundLabel);
|
||||
if (i != childrenExists.Length - 1)
|
||||
{
|
||||
il.Emit(OpCodes.Br, ifRecNext[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
onNotFound();
|
||||
}
|
||||
}
|
||||
|
||||
il.MarkLabel(gotoNotFound);
|
||||
onNotFound();
|
||||
}
|
||||
else
|
||||
{
|
||||
// binary-search
|
||||
var midline = count / 2;
|
||||
var mid = nexts[midline].Key;
|
||||
AutomataNode[] l = nexts.Take(count).Take(midline).ToArray();
|
||||
AutomataNode[] r = nexts.Take(count).Skip(midline).ToArray();
|
||||
|
||||
Label gotoRight = il.DefineLabel();
|
||||
|
||||
// if(key < mid)
|
||||
il.EmitLdloc(key);
|
||||
il.EmitULong(mid);
|
||||
il.Emit(OpCodes.Bge, gotoRight);
|
||||
EmitSearchNextCore(il, bytesSpan, key, onFound, onNotFound, l, l.Length);
|
||||
|
||||
// else
|
||||
il.MarkLabel(gotoRight);
|
||||
EmitSearchNextCore(il, bytesSpan, key, onFound, onNotFound, r, r.Length);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// This is used by dynamically generated code. It can be made internal after we enable our dynamic assemblies to access internals.
|
||||
/// But that trick may require net46, so maybe we should leave this as public.
|
||||
/// </remarks>
|
||||
public static class AutomataKeyGen
|
||||
{
|
||||
public static readonly MethodInfo GetKeyMethod = typeof(AutomataKeyGen).GetRuntimeMethod(nameof(GetKey), new[] { typeof(ReadOnlySpan<byte>).MakeByRefType() });
|
||||
|
||||
public static ulong GetKey(ref ReadOnlySpan<byte> span)
|
||||
{
|
||||
ulong key;
|
||||
|
||||
unchecked
|
||||
{
|
||||
if (span.Length >= 8)
|
||||
{
|
||||
key = MemoryMarshal.Cast<byte, ulong>(span)[0];
|
||||
span = span.Slice(8);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (span.Length)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
key = span[0];
|
||||
span = span.Slice(1);
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
key = MemoryMarshal.Cast<byte, ushort>(span)[0];
|
||||
span = span.Slice(2);
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
var a = span[0];
|
||||
var b = MemoryMarshal.Cast<byte, ushort>(span.Slice(1))[0];
|
||||
key = a | (ulong)b << 8;
|
||||
span = span.Slice(3);
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
{
|
||||
key = MemoryMarshal.Cast<byte, uint>(span)[0];
|
||||
span = span.Slice(4);
|
||||
break;
|
||||
}
|
||||
|
||||
case 5:
|
||||
{
|
||||
var a = span[0];
|
||||
var b = MemoryMarshal.Cast<byte, uint>(span.Slice(1))[0];
|
||||
key = a | (ulong)b << 8;
|
||||
span = span.Slice(5);
|
||||
break;
|
||||
}
|
||||
|
||||
case 6:
|
||||
{
|
||||
ulong a = MemoryMarshal.Cast<byte, ushort>(span)[0];
|
||||
ulong b = MemoryMarshal.Cast<byte, uint>(span.Slice(2))[0];
|
||||
key = a | (b << 16);
|
||||
span = span.Slice(6);
|
||||
break;
|
||||
}
|
||||
|
||||
case 7:
|
||||
{
|
||||
var a = span[0];
|
||||
var b = MemoryMarshal.Cast<byte, ushort>(span.Slice(1))[0];
|
||||
var c = MemoryMarshal.Cast<byte, uint>(span.Slice(3))[0];
|
||||
key = a | (ulong)b << 8 | (ulong)c << 24;
|
||||
span = span.Slice(7);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new MessagePackSerializationException("Not Supported Length");
|
||||
}
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fc94f4e5525f7ba44b4e68f3cdcb1050
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,193 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace MessagePack.Internal
|
||||
{
|
||||
// like ArraySegment<byte> hashtable.
|
||||
// Add is safe for construction phase only and requires capacity(does not do rehash)
|
||||
// and specialized for internal use(nongenerics, TValue is int)
|
||||
|
||||
// internal, but code generator requires this class
|
||||
// or at least PerfBenchmarkDotNet
|
||||
public class ByteArrayStringHashTable : IEnumerable<KeyValuePair<string, int>>
|
||||
{
|
||||
private readonly Entry[][] buckets; // immutable array(faster than linkedlist)
|
||||
private readonly ulong indexFor;
|
||||
|
||||
public ByteArrayStringHashTable(int capacity)
|
||||
: this(capacity, 0.42f) // default: 0.75f -> 0.42f
|
||||
{
|
||||
}
|
||||
|
||||
public ByteArrayStringHashTable(int capacity, float loadFactor)
|
||||
{
|
||||
var tableSize = CalculateCapacity(capacity, loadFactor);
|
||||
this.buckets = new Entry[tableSize][];
|
||||
this.indexFor = (ulong)this.buckets.Length - 1;
|
||||
}
|
||||
|
||||
public void Add(string key, int value)
|
||||
{
|
||||
if (!this.TryAddInternal(Encoding.UTF8.GetBytes(key), value))
|
||||
{
|
||||
throw new ArgumentException("Key was already exists. Key:" + key);
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(byte[] key, int value)
|
||||
{
|
||||
if (!this.TryAddInternal(key, value))
|
||||
{
|
||||
throw new ArgumentException("Key was already exists. Key:" + key);
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryAddInternal(byte[] key, int value)
|
||||
{
|
||||
var h = ByteArrayGetHashCode(key);
|
||||
var entry = new Entry { Key = key, Value = value };
|
||||
|
||||
Entry[] array = this.buckets[h & this.indexFor];
|
||||
if (array == null)
|
||||
{
|
||||
this.buckets[h & this.indexFor] = new[] { entry };
|
||||
}
|
||||
else
|
||||
{
|
||||
// check duplicate
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
byte[] e = array[i].Key;
|
||||
if (key.AsSpan().SequenceEqual(e))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var newArray = new Entry[array.Length + 1];
|
||||
Array.Copy(array, newArray, array.Length);
|
||||
array = newArray;
|
||||
array[array.Length - 1] = entry;
|
||||
this.buckets[h & this.indexFor] = array;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryGetValue(in ReadOnlySequence<byte> key, out int value) => this.TryGetValue(CodeGenHelpers.GetSpanFromSequence(key), out value);
|
||||
|
||||
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryGetValue(ReadOnlySpan<byte> key, out int value)
|
||||
{
|
||||
Entry[][] table = this.buckets;
|
||||
var hash = ByteArrayGetHashCode(key);
|
||||
Entry[] entry = table[hash & this.indexFor];
|
||||
|
||||
if (entry == null)
|
||||
{
|
||||
value = default(int);
|
||||
return false;
|
||||
}
|
||||
|
||||
ref Entry v = ref entry[0];
|
||||
if (key.SequenceEqual(v.Key))
|
||||
{
|
||||
value = v.Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return TryGetValueSlow(key, entry, out value);
|
||||
}
|
||||
|
||||
private bool TryGetValueSlow(ReadOnlySpan<byte> key, Entry[] entry, out int value)
|
||||
{
|
||||
for (int i = 1; i < entry.Length; i++)
|
||||
{
|
||||
ref Entry v = ref entry[i];
|
||||
if (key.SequenceEqual(v.Key))
|
||||
{
|
||||
value = v.Value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
value = default(int);
|
||||
return false;
|
||||
}
|
||||
|
||||
private static readonly bool Is32Bit = IntPtr.Size == 4;
|
||||
|
||||
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
|
||||
private static ulong ByteArrayGetHashCode(ReadOnlySpan<byte> x)
|
||||
{
|
||||
// FarmHash https://github.com/google/farmhash
|
||||
if (Is32Bit)
|
||||
{
|
||||
return (ulong)FarmHash.Hash32(x);
|
||||
}
|
||||
else
|
||||
{
|
||||
return FarmHash.Hash64(x);
|
||||
}
|
||||
}
|
||||
|
||||
private static int CalculateCapacity(int collectionSize, float loadFactor)
|
||||
{
|
||||
var initialCapacity = (int)(((float)collectionSize) / loadFactor);
|
||||
var capacity = 1;
|
||||
while (capacity < initialCapacity)
|
||||
{
|
||||
capacity <<= 1;
|
||||
}
|
||||
|
||||
if (capacity < 8)
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
return capacity;
|
||||
}
|
||||
|
||||
// only for Debug use
|
||||
public IEnumerator<KeyValuePair<string, int>> GetEnumerator()
|
||||
{
|
||||
Entry[][] b = this.buckets;
|
||||
|
||||
foreach (Entry[] item in b)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (Entry item2 in item)
|
||||
{
|
||||
yield return new KeyValuePair<string, int>(Encoding.UTF8.GetString(item2.Key), item2.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return this.GetEnumerator();
|
||||
}
|
||||
|
||||
private struct Entry
|
||||
{
|
||||
public byte[] Key;
|
||||
public int Value;
|
||||
|
||||
// for debugging
|
||||
public override string ToString()
|
||||
{
|
||||
return "(" + Encoding.UTF8.GetString(this.Key) + ", " + this.Value + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 28c84212e5b4fc4d7b4b66cdb741984d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace MessagePack.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// Helpers for generated code.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This code is used by dynamically generated code as well as AOT generated code,
|
||||
/// and thus must be public for the "C# generated and compiled into saved assembly" scenario.
|
||||
/// </remarks>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static class CodeGenHelpers
|
||||
{
|
||||
public static byte[] GetEncodedStringBytes(string value)
|
||||
{
|
||||
var byteCount = StringEncoding.UTF8.GetByteCount(value);
|
||||
if (byteCount <= MessagePackRange.MaxFixStringLength)
|
||||
{
|
||||
var bytes = new byte[byteCount + 1];
|
||||
bytes[0] = (byte)(MessagePackCode.MinFixStr | byteCount);
|
||||
StringEncoding.UTF8.GetBytes(value, 0, value.Length, bytes, 1);
|
||||
return bytes;
|
||||
}
|
||||
else if (byteCount <= byte.MaxValue)
|
||||
{
|
||||
var bytes = new byte[byteCount + 2];
|
||||
bytes[0] = MessagePackCode.Str8;
|
||||
bytes[1] = unchecked((byte)byteCount);
|
||||
StringEncoding.UTF8.GetBytes(value, 0, value.Length, bytes, 2);
|
||||
return bytes;
|
||||
}
|
||||
else if (byteCount <= ushort.MaxValue)
|
||||
{
|
||||
var bytes = new byte[byteCount + 3];
|
||||
bytes[0] = MessagePackCode.Str16;
|
||||
bytes[1] = unchecked((byte)(byteCount >> 8));
|
||||
bytes[2] = unchecked((byte)byteCount);
|
||||
StringEncoding.UTF8.GetBytes(value, 0, value.Length, bytes, 3);
|
||||
return bytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
var bytes = new byte[byteCount + 5];
|
||||
bytes[0] = MessagePackCode.Str32;
|
||||
bytes[1] = unchecked((byte)(byteCount >> 24));
|
||||
bytes[2] = unchecked((byte)(byteCount >> 16));
|
||||
bytes[3] = unchecked((byte)(byteCount >> 8));
|
||||
bytes[4] = unchecked((byte)byteCount);
|
||||
StringEncoding.UTF8.GetBytes(value, 0, value.Length, bytes, 5);
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<byte> GetSpanFromSequence(in ReadOnlySequence<byte> sequence)
|
||||
{
|
||||
if (sequence.IsSingleSegment)
|
||||
{
|
||||
return sequence.First.Span;
|
||||
}
|
||||
|
||||
return sequence.ToArray();
|
||||
}
|
||||
|
||||
public static ReadOnlySpan<byte> ReadStringSpan(ref MessagePackReader reader)
|
||||
{
|
||||
if (!reader.TryReadStringSpan(out ReadOnlySpan<byte> result))
|
||||
{
|
||||
return GetSpanFromSequence(reader.ReadStringSequence());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static byte[] GetArrayFromNullableSequence(in ReadOnlySequence<byte>? sequence) => sequence?.ToArray();
|
||||
|
||||
private static ReadOnlySpan<byte> GetSpanFromSequence(in ReadOnlySequence<byte>? sequence)
|
||||
{
|
||||
return sequence.HasValue ? GetSpanFromSequence(sequence.Value) : default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4f2dcc1d826e7ff7da02bd691c4dd6a0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace MessagePack.Internal
|
||||
{
|
||||
internal static class DateTimeConstants
|
||||
{
|
||||
internal const long BclSecondsAtUnixEpoch = 62135596800;
|
||||
internal const int NanosecondsPerTick = 100;
|
||||
internal static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a0cf18db43b878d71a216123e3309b65
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#if !(UNITY_2018_3_OR_NEWER && NET_STANDARD_2_0)
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
namespace MessagePack.Internal
|
||||
{
|
||||
internal class DynamicAssembly
|
||||
{
|
||||
#if NETFRAMEWORK // We don't ship a net472 target, but we might add one for debugging purposes
|
||||
private readonly string moduleName;
|
||||
#endif
|
||||
private readonly AssemblyBuilder assemblyBuilder;
|
||||
private readonly ModuleBuilder moduleBuilder;
|
||||
|
||||
// don't expose ModuleBuilder
|
||||
//// public ModuleBuilder ModuleBuilder { get { return moduleBuilder; } }
|
||||
|
||||
private readonly object gate = new object();
|
||||
|
||||
public DynamicAssembly(string moduleName)
|
||||
{
|
||||
#if NETFRAMEWORK // We don't ship a net472 target, but we might add one for debugging purposes
|
||||
AssemblyBuilderAccess builderAccess = AssemblyBuilderAccess.RunAndSave;
|
||||
this.moduleName = moduleName;
|
||||
#else
|
||||
AssemblyBuilderAccess builderAccess = AssemblyBuilderAccess.Run;
|
||||
#endif
|
||||
this.assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(moduleName), builderAccess);
|
||||
this.moduleBuilder = this.assemblyBuilder.DefineDynamicModule(moduleName + ".dll");
|
||||
}
|
||||
|
||||
/* requires lock on mono environment. see: https://github.com/neuecc/MessagePack-CSharp/issues/161 */
|
||||
|
||||
public TypeBuilder DefineType(string name, TypeAttributes attr)
|
||||
{
|
||||
lock (this.gate)
|
||||
{
|
||||
return this.moduleBuilder.DefineType(name, attr);
|
||||
}
|
||||
}
|
||||
|
||||
public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent)
|
||||
{
|
||||
lock (this.gate)
|
||||
{
|
||||
return this.moduleBuilder.DefineType(name, attr, parent);
|
||||
}
|
||||
}
|
||||
|
||||
public TypeBuilder DefineType(string name, TypeAttributes attr, Type parent, Type[] interfaces)
|
||||
{
|
||||
lock (this.gate)
|
||||
{
|
||||
return this.moduleBuilder.DefineType(name, attr, parent, interfaces);
|
||||
}
|
||||
}
|
||||
|
||||
#if NETFRAMEWORK
|
||||
|
||||
public AssemblyBuilder Save()
|
||||
{
|
||||
this.assemblyBuilder.Save(this.moduleName + ".dll");
|
||||
return this.assemblyBuilder;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f44ca64eddd25f5a896a2f72b21fcc9b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace MessagePack.Internal
|
||||
{
|
||||
internal static class ExpressionUtility
|
||||
{
|
||||
private static MethodInfo GetMethodInfoCore(LambdaExpression expression)
|
||||
{
|
||||
if (expression == null)
|
||||
{
|
||||
throw new ArgumentNullException("expression");
|
||||
}
|
||||
|
||||
return (expression.Body as MethodCallExpression).Method;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get MethodInfo from Expression for Static(with result) method.
|
||||
/// </summary>
|
||||
public static MethodInfo GetMethodInfo<T>(Expression<Func<T>> expression)
|
||||
{
|
||||
return GetMethodInfoCore(expression);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get MethodInfo from Expression for Static(void) method.
|
||||
/// </summary>
|
||||
public static MethodInfo GetMethodInfo(Expression<Action> expression)
|
||||
{
|
||||
return GetMethodInfoCore(expression);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get MethodInfo from Expression for Instance(with result) method.
|
||||
/// </summary>
|
||||
public static MethodInfo GetMethodInfo<T, TR>(Expression<Func<T, TR>> expression)
|
||||
{
|
||||
return GetMethodInfoCore(expression);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get MethodInfo from Expression for Instance(void) method.
|
||||
/// </summary>
|
||||
public static MethodInfo GetMethodInfo<T>(Expression<Action<T>> expression)
|
||||
{
|
||||
return GetMethodInfoCore(expression);
|
||||
}
|
||||
|
||||
// WithArgument(for ref, out) helper
|
||||
|
||||
/// <summary>
|
||||
/// Get MethodInfo from Expression for Instance(with result) method.
|
||||
/// </summary>
|
||||
public static MethodInfo GetMethodInfo<T, TArg1, TR>(Expression<Func<T, TArg1, TR>> expression)
|
||||
{
|
||||
return GetMethodInfoCore(expression);
|
||||
}
|
||||
|
||||
private static MemberInfo GetMemberInfoCore<T>(Expression<T> source)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new ArgumentNullException("source");
|
||||
}
|
||||
|
||||
var memberExpression = source.Body as MemberExpression;
|
||||
return memberExpression.Member;
|
||||
}
|
||||
|
||||
public static PropertyInfo GetPropertyInfo<T, TR>(Expression<Func<T, TR>> expression)
|
||||
{
|
||||
return GetMemberInfoCore(expression) as PropertyInfo;
|
||||
}
|
||||
|
||||
public static FieldInfo GetFieldInfo<T, TR>(Expression<Func<T, TR>> expression)
|
||||
{
|
||||
return GetMemberInfoCore(expression) as FieldInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1e2163b0f9d41a70599e1d5bd231a4b6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,601 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
#pragma warning disable SA1300 // Element should begin with uppercase letter
|
||||
#pragma warning disable SA1303 // Const field names should begin with uppercase letter
|
||||
#pragma warning disable SA1307 // (public) field names should begin with uppercase letter
|
||||
|
||||
namespace MessagePack.Internal
|
||||
{
|
||||
internal static class FarmHash
|
||||
{
|
||||
#region Hash32
|
||||
|
||||
// entry point of 32bit
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe uint Hash32(ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
if (bytes.Length <= 4)
|
||||
{
|
||||
return Hash32Len0to4(bytes);
|
||||
}
|
||||
|
||||
fixed (byte* p = bytes)
|
||||
{
|
||||
return Hash32(p, (uint)bytes.Length);
|
||||
}
|
||||
}
|
||||
|
||||
// port of farmhash.cc, 32bit only
|
||||
|
||||
// Magic numbers for 32-bit hashing. Copied from Murmur3.
|
||||
private const uint c1 = 0xcc9e2d51;
|
||||
private const uint c2 = 0x1b873593;
|
||||
|
||||
private static unsafe uint Fetch32(byte* p)
|
||||
{
|
||||
return *(uint*)p;
|
||||
}
|
||||
|
||||
private static uint Rotate32(uint val, int shift)
|
||||
{
|
||||
return shift == 0 ? val : ((val >> shift) | (val << (32 - shift)));
|
||||
}
|
||||
|
||||
// A 32-bit to 32-bit integer hash copied from Murmur3.
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static uint fmix(uint h)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
h ^= h >> 16;
|
||||
h *= 0x85ebca6b;
|
||||
h ^= h >> 13;
|
||||
h *= 0xc2b2ae35;
|
||||
h ^= h >> 16;
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static uint Mur(uint a, uint h)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
// Helper from Murmur3 for combining two 32-bit values.
|
||||
a *= c1;
|
||||
a = Rotate32(a, 17);
|
||||
a *= c2;
|
||||
h ^= a;
|
||||
h = Rotate32(h, 19);
|
||||
return (h * 5) + 0xe6546b64;
|
||||
}
|
||||
}
|
||||
|
||||
// 0-4
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static unsafe uint Hash32Len0to4(ReadOnlySpan<byte> s)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
uint b = 0;
|
||||
uint c = 9;
|
||||
for (int i = 0; i < s.Length; i++)
|
||||
{
|
||||
b = (b * c1) + s[i];
|
||||
c ^= b;
|
||||
}
|
||||
|
||||
return fmix(Mur(b, Mur((uint)s.Length, c)));
|
||||
}
|
||||
}
|
||||
|
||||
// 5-12
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static unsafe uint Hash32Len5to12(byte* s, uint len)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
uint a = len, b = len * 5, c = 9, d = b;
|
||||
a += Fetch32(s);
|
||||
b += Fetch32(s + len - 4);
|
||||
c += Fetch32(s + ((len >> 1) & 4));
|
||||
return fmix(Mur(c, Mur(b, Mur(a, d))));
|
||||
}
|
||||
}
|
||||
|
||||
// 13-24
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static unsafe uint Hash32Len13to24(byte* s, uint len)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
uint a = Fetch32(s - 4 + (len >> 1));
|
||||
uint b = Fetch32(s + 4);
|
||||
uint c = Fetch32(s + len - 8);
|
||||
uint d = Fetch32(s + (len >> 1));
|
||||
uint e = Fetch32(s);
|
||||
uint f = Fetch32(s + len - 4);
|
||||
uint h = (d * c1) + len;
|
||||
a = Rotate32(a, 12) + f;
|
||||
h = Mur(c, h) + a;
|
||||
a = Rotate32(a, 3) + c;
|
||||
h = Mur(e, h) + a;
|
||||
a = Rotate32(a + f, 12) + d;
|
||||
h = Mur(b, h) + a;
|
||||
return fmix(h);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static unsafe uint Hash32(byte* s, uint len)
|
||||
{
|
||||
if (len <= 24)
|
||||
{
|
||||
return len <= 12 ? Hash32Len5to12(s, len) : Hash32Len13to24(s, len);
|
||||
}
|
||||
|
||||
unchecked
|
||||
{
|
||||
// len > 24
|
||||
uint h = len, g = c1 * len, f = g;
|
||||
uint a0 = Rotate32(Fetch32(s + len - 4) * c1, 17) * c2;
|
||||
uint a1 = Rotate32(Fetch32(s + len - 8) * c1, 17) * c2;
|
||||
uint a2 = Rotate32(Fetch32(s + len - 16) * c1, 17) * c2;
|
||||
uint a3 = Rotate32(Fetch32(s + len - 12) * c1, 17) * c2;
|
||||
uint a4 = Rotate32(Fetch32(s + len - 20) * c1, 17) * c2;
|
||||
h ^= a0;
|
||||
h = Rotate32(h, 19);
|
||||
h = (h * 5) + 0xe6546b64;
|
||||
h ^= a2;
|
||||
h = Rotate32(h, 19);
|
||||
h = (h * 5) + 0xe6546b64;
|
||||
g ^= a1;
|
||||
g = Rotate32(g, 19);
|
||||
g = (g * 5) + 0xe6546b64;
|
||||
g ^= a3;
|
||||
g = Rotate32(g, 19);
|
||||
g = (g * 5) + 0xe6546b64;
|
||||
f += a4;
|
||||
f = Rotate32(f, 19) + 113;
|
||||
uint iters = (len - 1) / 20;
|
||||
do
|
||||
{
|
||||
uint a = Fetch32(s);
|
||||
uint b = Fetch32(s + 4);
|
||||
uint c = Fetch32(s + 8);
|
||||
uint d = Fetch32(s + 12);
|
||||
uint e = Fetch32(s + 16);
|
||||
h += a;
|
||||
g += b;
|
||||
f += c;
|
||||
h = Mur(d, h) + e;
|
||||
g = Mur(c, g) + a;
|
||||
f = Mur(b + (e * c1), f) + d;
|
||||
f += g;
|
||||
g += f;
|
||||
s += 20;
|
||||
}
|
||||
while (--iters != 0);
|
||||
g = Rotate32(g, 11) * c1;
|
||||
g = Rotate32(g, 17) * c1;
|
||||
f = Rotate32(f, 11) * c1;
|
||||
f = Rotate32(f, 17) * c1;
|
||||
h = Rotate32(h + g, 19);
|
||||
h = (h * 5) + 0xe6546b64;
|
||||
h = Rotate32(h, 17) * c1;
|
||||
h = Rotate32(h + f, 19);
|
||||
h = (h * 5) + 0xe6546b64;
|
||||
h = Rotate32(h, 17) * c1;
|
||||
return h;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region hash64
|
||||
|
||||
// entry point
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe ulong Hash64(ReadOnlySpan<byte> bytes)
|
||||
{
|
||||
fixed (byte* p = bytes)
|
||||
{
|
||||
return Hash64(p, (uint)bytes.Length);
|
||||
}
|
||||
}
|
||||
|
||||
/* port from farmhash.cc */
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static void swap(ref ulong x, ref ulong z)
|
||||
{
|
||||
var temp = z;
|
||||
z = x;
|
||||
x = temp;
|
||||
}
|
||||
|
||||
// Some primes between 2^63 and 2^64 for various uses.
|
||||
private const ulong k0 = 0xc3a5c85c97cb3127UL;
|
||||
private const ulong k1 = 0xb492b66fbe98f273UL;
|
||||
private const ulong k2 = 0x9ae16a3b2f90404fUL;
|
||||
|
||||
private static unsafe ulong Fetch64(byte* p)
|
||||
{
|
||||
return *(ulong*)p;
|
||||
}
|
||||
|
||||
private static ulong Rotate64(ulong val, int shift)
|
||||
{
|
||||
return shift == 0 ? val : (val >> shift) | (val << (64 - shift));
|
||||
}
|
||||
|
||||
// farmhashna.cc
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static ulong ShiftMix(ulong val)
|
||||
{
|
||||
return val ^ (val >> 47);
|
||||
}
|
||||
|
||||
// farmhashna.cc
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static ulong HashLen16(ulong u, ulong v, ulong mul)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
// Murmur-inspired hashing.
|
||||
ulong a = (u ^ v) * mul;
|
||||
a ^= a >> 47;
|
||||
ulong b = (v ^ a) * mul;
|
||||
b ^= b >> 47;
|
||||
b *= mul;
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
// farmhashxo.cc
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static unsafe ulong Hash64(byte* s, uint len)
|
||||
{
|
||||
if (len <= 16)
|
||||
{
|
||||
// farmhashna::
|
||||
return HashLen0to16(s, len);
|
||||
}
|
||||
|
||||
if (len <= 32)
|
||||
{
|
||||
// farmhashna::
|
||||
return HashLen17to32(s, len);
|
||||
}
|
||||
|
||||
if (len <= 64)
|
||||
{
|
||||
return HashLen33to64(s, len);
|
||||
}
|
||||
|
||||
if (len <= 96)
|
||||
{
|
||||
return HashLen65to96(s, len);
|
||||
}
|
||||
|
||||
if (len <= 256)
|
||||
{
|
||||
// farmhashna::
|
||||
return Hash64NA(s, len);
|
||||
}
|
||||
|
||||
// farmhashuo::
|
||||
return Hash64UO(s, len);
|
||||
}
|
||||
|
||||
// 0-16 farmhashna.cc
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static unsafe ulong HashLen0to16(byte* s, uint len)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
if (len >= 8)
|
||||
{
|
||||
ulong mul = k2 + (len * 2);
|
||||
ulong a = Fetch64(s) + k2;
|
||||
ulong b = Fetch64(s + len - 8);
|
||||
ulong c = (Rotate64(b, 37) * mul) + a;
|
||||
ulong d = (Rotate64(a, 25) + b) * mul;
|
||||
return HashLen16(c, d, mul);
|
||||
}
|
||||
|
||||
if (len >= 4)
|
||||
{
|
||||
ulong mul = k2 + (len * 2);
|
||||
ulong a = Fetch32(s);
|
||||
return HashLen16(len + (a << 3), Fetch32(s + len - 4), mul);
|
||||
}
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
ushort a = s[0];
|
||||
ushort b = s[len >> 1];
|
||||
ushort c = s[len - 1];
|
||||
uint y = a + ((uint)b << 8);
|
||||
uint z = len + ((uint)c << 2);
|
||||
return ShiftMix(y * k2 ^ z * k0) * k2;
|
||||
}
|
||||
|
||||
return k2;
|
||||
}
|
||||
}
|
||||
|
||||
// 17-32 farmhashna.cc
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static unsafe ulong HashLen17to32(byte* s, uint len)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
ulong mul = k2 + (len * 2);
|
||||
ulong a = Fetch64(s) * k1;
|
||||
ulong b = Fetch64(s + 8);
|
||||
ulong c = Fetch64(s + len - 8) * mul;
|
||||
ulong d = Fetch64(s + len - 16) * k2;
|
||||
return HashLen16(
|
||||
Rotate64(a + b, 43) + Rotate64(c, 30) + d,
|
||||
a + Rotate64(b + k2, 18) + c,
|
||||
mul);
|
||||
}
|
||||
}
|
||||
|
||||
// farmhashxo.cc
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static unsafe ulong H32(byte* s, uint len, ulong mul, ulong seed0 = 0, ulong seed1 = 0)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
ulong a = Fetch64(s) * k1;
|
||||
ulong b = Fetch64(s + 8);
|
||||
ulong c = Fetch64(s + len - 8) * mul;
|
||||
ulong d = Fetch64(s + len - 16) * k2;
|
||||
ulong u = Rotate64(a + b, 43) + Rotate64(c, 30) + d + seed0;
|
||||
ulong v = a + Rotate64(b + k2, 18) + c + seed1;
|
||||
a = ShiftMix((u ^ v) * mul);
|
||||
b = ShiftMix((v ^ a) * mul);
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
// 33-64 farmhashxo.cc
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static unsafe ulong HashLen33to64(byte* s, uint len)
|
||||
{
|
||||
const ulong mul0 = k2 - 30;
|
||||
|
||||
unchecked
|
||||
{
|
||||
ulong mul1 = k2 - 30 + (2 * len);
|
||||
ulong h0 = H32(s, 32, mul0);
|
||||
ulong h1 = H32(s + len - 32, 32, mul1);
|
||||
return ((h1 * mul1) + h0) * mul1;
|
||||
}
|
||||
}
|
||||
|
||||
// 65-96 farmhashxo.cc
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static unsafe ulong HashLen65to96(byte* s, uint len)
|
||||
{
|
||||
const ulong mul0 = k2 - 114;
|
||||
|
||||
unchecked
|
||||
{
|
||||
ulong mul1 = k2 - 114 + (2 * len);
|
||||
ulong h0 = H32(s, 32, mul0);
|
||||
ulong h1 = H32(s + 32, 32, mul1);
|
||||
ulong h2 = H32(s + len - 32, 32, mul1, h0, h1);
|
||||
return ((h2 * 9) + (h0 >> 17) + (h1 >> 21)) * mul1;
|
||||
}
|
||||
}
|
||||
|
||||
// farmhashna.cc
|
||||
// Return a 16-byte hash for 48 bytes. Quick and dirty.
|
||||
// Callers do best to use "random-looking" values for a and b.
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static unsafe void WeakHashLen32WithSeeds(ulong w, ulong x, ulong y, ulong z, ulong a, ulong b, out ulong first, out ulong second)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
a += w;
|
||||
b = Rotate64(b + a + z, 21);
|
||||
ulong c = a;
|
||||
a += x;
|
||||
a += y;
|
||||
b += Rotate64(a, 44);
|
||||
first = a + z;
|
||||
second = b + c;
|
||||
}
|
||||
}
|
||||
|
||||
// farmhashna.cc
|
||||
// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static unsafe void WeakHashLen32WithSeeds(byte* s, ulong a, ulong b, out ulong first, out ulong second)
|
||||
{
|
||||
WeakHashLen32WithSeeds(
|
||||
Fetch64(s),
|
||||
Fetch64(s + 8),
|
||||
Fetch64(s + 16),
|
||||
Fetch64(s + 24),
|
||||
a,
|
||||
b,
|
||||
out first,
|
||||
out second);
|
||||
}
|
||||
|
||||
// na(97-256) farmhashna.cc
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static unsafe ulong Hash64NA(byte* s, uint len)
|
||||
{
|
||||
const ulong seed = 81;
|
||||
|
||||
unchecked
|
||||
{
|
||||
// For strings over 64 bytes we loop. Internal state consists of
|
||||
// 56 bytes: v, w, x, y, and z.
|
||||
ulong x = seed;
|
||||
ulong y = (seed * k1) + 113;
|
||||
ulong z = ShiftMix((y * k2) + 113) * k2;
|
||||
ulong v_first = 0;
|
||||
ulong v_second = 0;
|
||||
ulong w_first = 0;
|
||||
ulong w_second = 0;
|
||||
x = (x * k2) + Fetch64(s);
|
||||
|
||||
// Set end so that after the loop we have 1 to 64 bytes left to process.
|
||||
byte* end = s + ((len - 1) / 64 * 64);
|
||||
byte* last64 = end + ((len - 1) & 63) - 63;
|
||||
|
||||
do
|
||||
{
|
||||
x = Rotate64(x + y + v_first + Fetch64(s + 8), 37) * k1;
|
||||
y = Rotate64(y + v_second + Fetch64(s + 48), 42) * k1;
|
||||
x ^= w_second;
|
||||
y += v_first + Fetch64(s + 40);
|
||||
z = Rotate64(z + w_first, 33) * k1;
|
||||
WeakHashLen32WithSeeds(s, v_second * k1, x + w_first, out v_first, out v_second);
|
||||
WeakHashLen32WithSeeds(s + 32, z + w_second, y + Fetch64(s + 16), out w_first, out w_second);
|
||||
swap(ref z, ref x);
|
||||
s += 64;
|
||||
}
|
||||
while (s != end);
|
||||
ulong mul = k1 + ((z & 0xff) << 1);
|
||||
|
||||
// Make s point to the last 64 bytes of input.
|
||||
s = last64;
|
||||
w_first += (len - 1) & 63;
|
||||
v_first += w_first;
|
||||
w_first += v_first;
|
||||
x = Rotate64(x + y + v_first + Fetch64(s + 8), 37) * mul;
|
||||
y = Rotate64(y + v_second + Fetch64(s + 48), 42) * mul;
|
||||
x ^= w_second * 9;
|
||||
y += (v_first * 9) + Fetch64(s + 40);
|
||||
z = Rotate64(z + w_first, 33) * mul;
|
||||
WeakHashLen32WithSeeds(s, v_second * mul, x + w_first, out v_first, out v_second);
|
||||
WeakHashLen32WithSeeds(s + 32, z + w_second, y + Fetch64(s + 16), out w_first, out w_second);
|
||||
swap(ref z, ref x);
|
||||
return HashLen16(HashLen16(v_first, w_first, mul) + (ShiftMix(y) * k0) + z, HashLen16(v_second, w_second, mul) + x, mul);
|
||||
}
|
||||
}
|
||||
|
||||
// farmhashuo.cc
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static ulong H(ulong x, ulong y, ulong mul, int r)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
ulong a = (x ^ y) * mul;
|
||||
a ^= a >> 47;
|
||||
ulong b = (y ^ a) * mul;
|
||||
return Rotate64(b, r) * mul;
|
||||
}
|
||||
}
|
||||
|
||||
// uo(257-) farmhashuo.cc, Hash64WithSeeds
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static unsafe ulong Hash64UO(byte* s, uint len)
|
||||
{
|
||||
const ulong seed0 = 81;
|
||||
const ulong seed1 = 0;
|
||||
|
||||
unchecked
|
||||
{
|
||||
// For strings over 64 bytes we loop. Internal state consists of
|
||||
// 64 bytes: u, v, w, x, y, and z.
|
||||
ulong x = seed0;
|
||||
ulong y = (seed1 * k2) + 113;
|
||||
ulong z = ShiftMix(y * k2) * k2;
|
||||
ulong v_first = seed0;
|
||||
ulong v_second = seed1;
|
||||
ulong w_first = 0;
|
||||
ulong w_second = 0;
|
||||
ulong u = x - z;
|
||||
x *= k2;
|
||||
ulong mul = k2 + (u & 0x82);
|
||||
|
||||
// Set end so that after the loop we have 1 to 64 bytes left to process.
|
||||
byte* end = s + ((len - 1) / 64 * 64);
|
||||
byte* last64 = end + ((len - 1) & 63) - 63;
|
||||
|
||||
do
|
||||
{
|
||||
ulong a0 = Fetch64(s);
|
||||
ulong a1 = Fetch64(s + 8);
|
||||
ulong a2 = Fetch64(s + 16);
|
||||
ulong a3 = Fetch64(s + 24);
|
||||
ulong a4 = Fetch64(s + 32);
|
||||
ulong a5 = Fetch64(s + 40);
|
||||
ulong a6 = Fetch64(s + 48);
|
||||
ulong a7 = Fetch64(s + 56);
|
||||
x += a0 + a1;
|
||||
y += a2;
|
||||
z += a3;
|
||||
v_first += a4;
|
||||
v_second += a5 + a1;
|
||||
w_first += a6;
|
||||
w_second += a7;
|
||||
|
||||
x = Rotate64(x, 26);
|
||||
x *= 9;
|
||||
y = Rotate64(y, 29);
|
||||
z *= mul;
|
||||
v_first = Rotate64(v_first, 33);
|
||||
v_second = Rotate64(v_second, 30);
|
||||
w_first ^= x;
|
||||
w_first *= 9;
|
||||
z = Rotate64(z, 32);
|
||||
z += w_second;
|
||||
w_second += z;
|
||||
z *= 9;
|
||||
swap(ref u, ref y);
|
||||
|
||||
z += a0 + a6;
|
||||
v_first += a2;
|
||||
v_second += a3;
|
||||
w_first += a4;
|
||||
w_second += a5 + a6;
|
||||
x += a1;
|
||||
y += a7;
|
||||
|
||||
y += v_first;
|
||||
v_first += x - y;
|
||||
v_second += w_first;
|
||||
w_first += v_second;
|
||||
w_second += x - y;
|
||||
x += w_second;
|
||||
w_second = Rotate64(w_second, 34);
|
||||
swap(ref u, ref z);
|
||||
s += 64;
|
||||
}
|
||||
while (s != end);
|
||||
|
||||
// Make s point to the last 64 bytes of input.
|
||||
s = last64;
|
||||
u *= 9;
|
||||
v_second = Rotate64(v_second, 28);
|
||||
v_first = Rotate64(v_first, 20);
|
||||
w_first += (len - 1) & 63;
|
||||
u += y;
|
||||
y += u;
|
||||
x = Rotate64(y - x + v_first + Fetch64(s + 8), 37) * mul;
|
||||
y = Rotate64(y ^ v_second ^ Fetch64(s + 48), 42) * mul;
|
||||
x ^= w_second * 9;
|
||||
y += v_first + Fetch64(s + 40);
|
||||
z = Rotate64(z + w_first, 33) * mul;
|
||||
WeakHashLen32WithSeeds(s, v_second * mul, x + w_first, out v_first, out v_second);
|
||||
WeakHashLen32WithSeeds(s + 32, z + w_second, y + Fetch64(s + 16), out w_first, out w_second);
|
||||
return H(HashLen16(v_first + x, w_first ^ y, mul) + z - u, H(v_second + y, w_second + z, k2, 30) ^ x, k2, 31);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fb5a050df97c09dd9b40337e9c0bbdcd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,391 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace MessagePack.Internal
|
||||
{
|
||||
[StructLayout(LayoutKind.Explicit, Pack = 1)]
|
||||
internal struct GuidBits
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public readonly Guid Value;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public readonly byte Byte0;
|
||||
[FieldOffset(1)]
|
||||
public readonly byte Byte1;
|
||||
[FieldOffset(2)]
|
||||
public readonly byte Byte2;
|
||||
[FieldOffset(3)]
|
||||
public readonly byte Byte3;
|
||||
[FieldOffset(4)]
|
||||
public readonly byte Byte4;
|
||||
[FieldOffset(5)]
|
||||
public readonly byte Byte5;
|
||||
[FieldOffset(6)]
|
||||
public readonly byte Byte6;
|
||||
[FieldOffset(7)]
|
||||
public readonly byte Byte7;
|
||||
[FieldOffset(8)]
|
||||
public readonly byte Byte8;
|
||||
[FieldOffset(9)]
|
||||
public readonly byte Byte9;
|
||||
[FieldOffset(10)]
|
||||
public readonly byte Byte10;
|
||||
[FieldOffset(11)]
|
||||
public readonly byte Byte11;
|
||||
[FieldOffset(12)]
|
||||
public readonly byte Byte12;
|
||||
[FieldOffset(13)]
|
||||
public readonly byte Byte13;
|
||||
[FieldOffset(14)]
|
||||
public readonly byte Byte14;
|
||||
[FieldOffset(15)]
|
||||
public readonly byte Byte15;
|
||||
|
||||
// string.Join(", ", Enumerable.Range(0, 256).Select(x => (int)BitConverter.ToString(new byte[] { (byte)x }).ToLower()[0]))
|
||||
private static byte[] byteToHexStringHigh = new byte[256] { 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 52, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 53, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 57, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 98, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 101, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102 };
|
||||
|
||||
// string.Join(", ", Enumerable.Range(0, 256).Select(x => (int)BitConverter.ToString(new byte[] { (byte)x }).ToLower()[1]))
|
||||
private static byte[] byteToHexStringLow = new byte[256] { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102 };
|
||||
|
||||
public GuidBits(ref Guid value)
|
||||
{
|
||||
this = default(GuidBits);
|
||||
this.Value = value;
|
||||
}
|
||||
|
||||
// 4-pattern, lower/upper and '-' or no
|
||||
public GuidBits(ReadOnlySpan<byte> utf8string)
|
||||
{
|
||||
this = default(GuidBits);
|
||||
|
||||
// 32
|
||||
if (utf8string.Length == 32)
|
||||
{
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
this.Byte0 = Parse(utf8string, 6);
|
||||
this.Byte1 = Parse(utf8string, 4);
|
||||
this.Byte2 = Parse(utf8string, 2);
|
||||
this.Byte3 = Parse(utf8string, 0);
|
||||
|
||||
this.Byte4 = Parse(utf8string, 10);
|
||||
this.Byte5 = Parse(utf8string, 8);
|
||||
|
||||
this.Byte6 = Parse(utf8string, 14);
|
||||
this.Byte7 = Parse(utf8string, 12);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Byte0 = Parse(utf8string, 0);
|
||||
this.Byte1 = Parse(utf8string, 2);
|
||||
this.Byte2 = Parse(utf8string, 4);
|
||||
this.Byte3 = Parse(utf8string, 6);
|
||||
|
||||
this.Byte4 = Parse(utf8string, 8);
|
||||
this.Byte5 = Parse(utf8string, 10);
|
||||
|
||||
this.Byte6 = Parse(utf8string, 12);
|
||||
this.Byte7 = Parse(utf8string, 14);
|
||||
}
|
||||
|
||||
this.Byte8 = Parse(utf8string, 16);
|
||||
this.Byte9 = Parse(utf8string, 18);
|
||||
|
||||
this.Byte10 = Parse(utf8string, 20);
|
||||
this.Byte11 = Parse(utf8string, 22);
|
||||
this.Byte12 = Parse(utf8string, 24);
|
||||
this.Byte13 = Parse(utf8string, 26);
|
||||
this.Byte14 = Parse(utf8string, 28);
|
||||
this.Byte15 = Parse(utf8string, 30);
|
||||
return;
|
||||
}
|
||||
else if (utf8string.Length == 36)
|
||||
{
|
||||
// '-' => 45
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
this.Byte0 = Parse(utf8string, 6);
|
||||
this.Byte1 = Parse(utf8string, 4);
|
||||
this.Byte2 = Parse(utf8string, 2);
|
||||
this.Byte3 = Parse(utf8string, 0);
|
||||
|
||||
if (utf8string[8] != '-')
|
||||
{
|
||||
goto ERROR;
|
||||
}
|
||||
|
||||
this.Byte4 = Parse(utf8string, 11);
|
||||
this.Byte5 = Parse(utf8string, 9);
|
||||
|
||||
if (utf8string[13] != '-')
|
||||
{
|
||||
goto ERROR;
|
||||
}
|
||||
|
||||
this.Byte6 = Parse(utf8string, 16);
|
||||
this.Byte7 = Parse(utf8string, 14);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.Byte0 = Parse(utf8string, 0);
|
||||
this.Byte1 = Parse(utf8string, 2);
|
||||
this.Byte2 = Parse(utf8string, 4);
|
||||
this.Byte3 = Parse(utf8string, 6);
|
||||
|
||||
if (utf8string[8] != '-')
|
||||
{
|
||||
goto ERROR;
|
||||
}
|
||||
|
||||
this.Byte4 = Parse(utf8string, 9);
|
||||
this.Byte5 = Parse(utf8string, 11);
|
||||
|
||||
if (utf8string[13] != '-')
|
||||
{
|
||||
goto ERROR;
|
||||
}
|
||||
|
||||
this.Byte6 = Parse(utf8string, 14);
|
||||
this.Byte7 = Parse(utf8string, 16);
|
||||
}
|
||||
|
||||
if (utf8string[18] != '-')
|
||||
{
|
||||
goto ERROR;
|
||||
}
|
||||
|
||||
this.Byte8 = Parse(utf8string, 19);
|
||||
this.Byte9 = Parse(utf8string, 21);
|
||||
|
||||
if (utf8string[23] != '-')
|
||||
{
|
||||
goto ERROR;
|
||||
}
|
||||
|
||||
this.Byte10 = Parse(utf8string, 24);
|
||||
this.Byte11 = Parse(utf8string, 26);
|
||||
this.Byte12 = Parse(utf8string, 28);
|
||||
this.Byte13 = Parse(utf8string, 30);
|
||||
this.Byte14 = Parse(utf8string, 32);
|
||||
this.Byte15 = Parse(utf8string, 34);
|
||||
return;
|
||||
}
|
||||
|
||||
ERROR:
|
||||
throw new MessagePackSerializationException("Invalid Guid Pattern.");
|
||||
}
|
||||
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
private static byte Parse(ReadOnlySpan<byte> bytes, int highOffset)
|
||||
{
|
||||
return unchecked((byte)((SwitchParse(bytes[highOffset]) * 16) + SwitchParse(bytes[highOffset + 1])));
|
||||
}
|
||||
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
|
||||
#endif
|
||||
private static byte SwitchParse(byte b)
|
||||
{
|
||||
// '0'(48) ~ '9'(57) => -48
|
||||
// 'A'(65) ~ 'F'(70) => -55
|
||||
// 'a'(97) ~ 'f'(102) => -87
|
||||
switch (b)
|
||||
{
|
||||
case 48:
|
||||
case 49:
|
||||
case 50:
|
||||
case 51:
|
||||
case 52:
|
||||
case 53:
|
||||
case 54:
|
||||
case 55:
|
||||
case 56:
|
||||
case 57:
|
||||
return unchecked((byte)(b - 48));
|
||||
case 65:
|
||||
case 66:
|
||||
case 67:
|
||||
case 68:
|
||||
case 69:
|
||||
case 70:
|
||||
return unchecked((byte)(b - 55));
|
||||
case 97:
|
||||
case 98:
|
||||
case 99:
|
||||
case 100:
|
||||
case 101:
|
||||
case 102:
|
||||
return unchecked((byte)(b - 87));
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 16:
|
||||
case 17:
|
||||
case 18:
|
||||
case 19:
|
||||
case 20:
|
||||
case 21:
|
||||
case 22:
|
||||
case 23:
|
||||
case 24:
|
||||
case 25:
|
||||
case 26:
|
||||
case 27:
|
||||
case 28:
|
||||
case 29:
|
||||
case 30:
|
||||
case 31:
|
||||
case 32:
|
||||
case 33:
|
||||
case 34:
|
||||
case 35:
|
||||
case 36:
|
||||
case 37:
|
||||
case 38:
|
||||
case 39:
|
||||
case 40:
|
||||
case 41:
|
||||
case 42:
|
||||
case 43:
|
||||
case 44:
|
||||
case 45:
|
||||
case 46:
|
||||
case 47:
|
||||
case 58:
|
||||
case 59:
|
||||
case 60:
|
||||
case 61:
|
||||
case 62:
|
||||
case 63:
|
||||
case 64:
|
||||
case 71:
|
||||
case 72:
|
||||
case 73:
|
||||
case 74:
|
||||
case 75:
|
||||
case 76:
|
||||
case 77:
|
||||
case 78:
|
||||
case 79:
|
||||
case 80:
|
||||
case 81:
|
||||
case 82:
|
||||
case 83:
|
||||
case 84:
|
||||
case 85:
|
||||
case 86:
|
||||
case 87:
|
||||
case 88:
|
||||
case 89:
|
||||
case 90:
|
||||
case 91:
|
||||
case 92:
|
||||
case 93:
|
||||
case 94:
|
||||
case 95:
|
||||
case 96:
|
||||
default:
|
||||
throw new MessagePackSerializationException("Invalid Guid Pattern.");
|
||||
}
|
||||
}
|
||||
|
||||
// 4(x2) - 2(x2) - 2(x2) - 2(x2) - 6(x2)
|
||||
public void Write(Span<byte> buffer)
|
||||
{
|
||||
if (BitConverter.IsLittleEndian)
|
||||
{
|
||||
// int(_a)
|
||||
buffer[6] = byteToHexStringHigh[this.Byte0];
|
||||
buffer[7] = byteToHexStringLow[this.Byte0];
|
||||
buffer[4] = byteToHexStringHigh[this.Byte1];
|
||||
buffer[5] = byteToHexStringLow[this.Byte1];
|
||||
buffer[2] = byteToHexStringHigh[this.Byte2];
|
||||
buffer[3] = byteToHexStringLow[this.Byte2];
|
||||
buffer[0] = byteToHexStringHigh[this.Byte3];
|
||||
buffer[1] = byteToHexStringLow[this.Byte3];
|
||||
|
||||
buffer[8] = (byte)'-';
|
||||
|
||||
// short(_b)
|
||||
buffer[11] = byteToHexStringHigh[this.Byte4];
|
||||
buffer[12] = byteToHexStringLow[this.Byte4];
|
||||
buffer[9] = byteToHexStringHigh[this.Byte5];
|
||||
buffer[10] = byteToHexStringLow[this.Byte5];
|
||||
|
||||
buffer[13] = (byte)'-';
|
||||
|
||||
// short(_c)
|
||||
buffer[16] = byteToHexStringHigh[this.Byte6];
|
||||
buffer[17] = byteToHexStringLow[this.Byte6];
|
||||
buffer[14] = byteToHexStringHigh[this.Byte7];
|
||||
buffer[15] = byteToHexStringLow[this.Byte7];
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[0] = byteToHexStringHigh[this.Byte0];
|
||||
buffer[1] = byteToHexStringLow[this.Byte0];
|
||||
buffer[2] = byteToHexStringHigh[this.Byte1];
|
||||
buffer[3] = byteToHexStringLow[this.Byte1];
|
||||
buffer[4] = byteToHexStringHigh[this.Byte2];
|
||||
buffer[5] = byteToHexStringLow[this.Byte2];
|
||||
buffer[6] = byteToHexStringHigh[this.Byte3];
|
||||
buffer[7] = byteToHexStringLow[this.Byte3];
|
||||
|
||||
buffer[8] = (byte)'-';
|
||||
|
||||
buffer[9] = byteToHexStringHigh[this.Byte4];
|
||||
buffer[10] = byteToHexStringLow[this.Byte4];
|
||||
buffer[11] = byteToHexStringHigh[this.Byte5];
|
||||
buffer[12] = byteToHexStringLow[this.Byte5];
|
||||
|
||||
buffer[13] = (byte)'-';
|
||||
|
||||
buffer[14] = byteToHexStringHigh[this.Byte6];
|
||||
buffer[15] = byteToHexStringLow[this.Byte6];
|
||||
buffer[16] = byteToHexStringHigh[this.Byte7];
|
||||
buffer[17] = byteToHexStringLow[this.Byte7];
|
||||
}
|
||||
|
||||
buffer[18] = (byte)'-';
|
||||
|
||||
buffer[19] = byteToHexStringHigh[this.Byte8];
|
||||
buffer[20] = byteToHexStringLow[this.Byte8];
|
||||
buffer[21] = byteToHexStringHigh[this.Byte9];
|
||||
buffer[22] = byteToHexStringLow[this.Byte9];
|
||||
|
||||
buffer[23] = (byte)'-';
|
||||
|
||||
buffer[24] = byteToHexStringHigh[this.Byte10];
|
||||
buffer[25] = byteToHexStringLow[this.Byte10];
|
||||
buffer[26] = byteToHexStringHigh[this.Byte11];
|
||||
buffer[27] = byteToHexStringLow[this.Byte11];
|
||||
buffer[28] = byteToHexStringHigh[this.Byte12];
|
||||
buffer[29] = byteToHexStringLow[this.Byte12];
|
||||
buffer[30] = byteToHexStringHigh[this.Byte13];
|
||||
buffer[31] = byteToHexStringLow[this.Byte13];
|
||||
buffer[32] = byteToHexStringHigh[this.Byte14];
|
||||
buffer[33] = byteToHexStringLow[this.Byte14];
|
||||
buffer[34] = byteToHexStringHigh[this.Byte15];
|
||||
buffer[35] = byteToHexStringLow[this.Byte15];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0bb83f98e290402db9fcb6da74f773ca
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,401 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#if !(UNITY_2018_3_OR_NEWER && NET_STANDARD_2_0)
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Reflection.Emit;
|
||||
|
||||
#pragma warning disable SA1649 // File name should match first type name
|
||||
|
||||
namespace MessagePack.Internal
|
||||
{
|
||||
internal struct ArgumentField
|
||||
{
|
||||
private readonly int i;
|
||||
private readonly bool @ref;
|
||||
private readonly ILGenerator il;
|
||||
|
||||
public ArgumentField(ILGenerator il, int i, bool @ref = false)
|
||||
{
|
||||
this.il = il;
|
||||
this.i = i;
|
||||
this.@ref = @ref;
|
||||
}
|
||||
|
||||
public ArgumentField(ILGenerator il, int i, Type type)
|
||||
{
|
||||
this.il = il;
|
||||
this.i = i;
|
||||
TypeInfo ti = type.GetTypeInfo();
|
||||
this.@ref = (ti.IsClass || ti.IsInterface || ti.IsAbstract) ? false : true;
|
||||
}
|
||||
|
||||
public void EmitLoad()
|
||||
{
|
||||
if (this.@ref)
|
||||
{
|
||||
this.il.EmitLdarga(this.i);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.il.EmitLdarg(this.i);
|
||||
}
|
||||
}
|
||||
|
||||
public void EmitLdarg()
|
||||
{
|
||||
this.il.EmitLdarg(this.i);
|
||||
}
|
||||
|
||||
public void EmitLdarga()
|
||||
{
|
||||
this.il.EmitLdarga(this.i);
|
||||
}
|
||||
|
||||
public void EmitStore()
|
||||
{
|
||||
this.il.EmitStarg(this.i);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides optimized generation code and helpers.
|
||||
/// </summary>
|
||||
internal static class ILGeneratorExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Loads the local variable at a specific index onto the evaluation stack.
|
||||
/// </summary>
|
||||
public static void EmitLdloc(this ILGenerator il, int index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
il.Emit(OpCodes.Ldloc_0);
|
||||
break;
|
||||
case 1:
|
||||
il.Emit(OpCodes.Ldloc_1);
|
||||
break;
|
||||
case 2:
|
||||
il.Emit(OpCodes.Ldloc_2);
|
||||
break;
|
||||
case 3:
|
||||
il.Emit(OpCodes.Ldloc_3);
|
||||
break;
|
||||
default:
|
||||
if (index <= 255)
|
||||
{
|
||||
il.Emit(OpCodes.Ldloc_S, (byte)index);
|
||||
}
|
||||
else
|
||||
{
|
||||
il.Emit(OpCodes.Ldloc, (short)index);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitLdloc(this ILGenerator il, LocalBuilder local)
|
||||
{
|
||||
EmitLdloc(il, local.LocalIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pops the current value from the top of the evaluation stack and stores it in a the local variable list at a specified index.
|
||||
/// </summary>
|
||||
public static void EmitStloc(this ILGenerator il, int index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
il.Emit(OpCodes.Stloc_0);
|
||||
break;
|
||||
case 1:
|
||||
il.Emit(OpCodes.Stloc_1);
|
||||
break;
|
||||
case 2:
|
||||
il.Emit(OpCodes.Stloc_2);
|
||||
break;
|
||||
case 3:
|
||||
il.Emit(OpCodes.Stloc_3);
|
||||
break;
|
||||
default:
|
||||
if (index <= 255)
|
||||
{
|
||||
il.Emit(OpCodes.Stloc_S, (byte)index);
|
||||
}
|
||||
else
|
||||
{
|
||||
il.Emit(OpCodes.Stloc, (short)index);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitStloc(this ILGenerator il, LocalBuilder local)
|
||||
{
|
||||
EmitStloc(il, local.LocalIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the address of the local variable at a specific index onto the evaluation statck.
|
||||
/// </summary>
|
||||
public static void EmitLdloca(this ILGenerator il, int index)
|
||||
{
|
||||
if (index <= 255)
|
||||
{
|
||||
il.Emit(OpCodes.Ldloca_S, (byte)index);
|
||||
}
|
||||
else
|
||||
{
|
||||
il.Emit(OpCodes.Ldloca, (short)index);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitLdloca(this ILGenerator il, LocalBuilder local)
|
||||
{
|
||||
EmitLdloca(il, local.LocalIndex);
|
||||
}
|
||||
|
||||
public static void EmitTrue(this ILGenerator il)
|
||||
{
|
||||
EmitBoolean(il, true);
|
||||
}
|
||||
|
||||
public static void EmitFalse(this ILGenerator il)
|
||||
{
|
||||
EmitBoolean(il, false);
|
||||
}
|
||||
|
||||
public static void EmitBoolean(this ILGenerator il, bool value)
|
||||
{
|
||||
EmitLdc_I4(il, value ? 1 : 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pushes a supplied value of type int32 onto the evaluation stack as an int32.
|
||||
/// </summary>
|
||||
public static void EmitLdc_I4(this ILGenerator il, int value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case -1:
|
||||
il.Emit(OpCodes.Ldc_I4_M1);
|
||||
break;
|
||||
case 0:
|
||||
il.Emit(OpCodes.Ldc_I4_0);
|
||||
break;
|
||||
case 1:
|
||||
il.Emit(OpCodes.Ldc_I4_1);
|
||||
break;
|
||||
case 2:
|
||||
il.Emit(OpCodes.Ldc_I4_2);
|
||||
break;
|
||||
case 3:
|
||||
il.Emit(OpCodes.Ldc_I4_3);
|
||||
break;
|
||||
case 4:
|
||||
il.Emit(OpCodes.Ldc_I4_4);
|
||||
break;
|
||||
case 5:
|
||||
il.Emit(OpCodes.Ldc_I4_5);
|
||||
break;
|
||||
case 6:
|
||||
il.Emit(OpCodes.Ldc_I4_6);
|
||||
break;
|
||||
case 7:
|
||||
il.Emit(OpCodes.Ldc_I4_7);
|
||||
break;
|
||||
case 8:
|
||||
il.Emit(OpCodes.Ldc_I4_8);
|
||||
break;
|
||||
default:
|
||||
if (value >= -128 && value <= 127)
|
||||
{
|
||||
il.Emit(OpCodes.Ldc_I4_S, (sbyte)value);
|
||||
}
|
||||
else
|
||||
{
|
||||
il.Emit(OpCodes.Ldc_I4, value);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitUnboxOrCast(this ILGenerator il, Type type)
|
||||
{
|
||||
if (type.GetTypeInfo().IsValueType)
|
||||
{
|
||||
il.Emit(OpCodes.Unbox_Any, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
il.Emit(OpCodes.Castclass, type);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitBoxOrDoNothing(this ILGenerator il, Type type)
|
||||
{
|
||||
if (type.GetTypeInfo().IsValueType)
|
||||
{
|
||||
il.Emit(OpCodes.Box, type);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitLdarg(this ILGenerator il, int index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
il.Emit(OpCodes.Ldarg_0);
|
||||
break;
|
||||
case 1:
|
||||
il.Emit(OpCodes.Ldarg_1);
|
||||
break;
|
||||
case 2:
|
||||
il.Emit(OpCodes.Ldarg_2);
|
||||
break;
|
||||
case 3:
|
||||
il.Emit(OpCodes.Ldarg_3);
|
||||
break;
|
||||
default:
|
||||
if (index <= 255)
|
||||
{
|
||||
il.Emit(OpCodes.Ldarg_S, (byte)index);
|
||||
}
|
||||
else
|
||||
{
|
||||
il.Emit(OpCodes.Ldarg, index);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitLoadThis(this ILGenerator il)
|
||||
{
|
||||
EmitLdarg(il, 0);
|
||||
}
|
||||
|
||||
public static void EmitLdarga(this ILGenerator il, int index)
|
||||
{
|
||||
if (index <= 255)
|
||||
{
|
||||
il.Emit(OpCodes.Ldarga_S, (byte)index);
|
||||
}
|
||||
else
|
||||
{
|
||||
il.Emit(OpCodes.Ldarga, index);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitStarg(this ILGenerator il, int index)
|
||||
{
|
||||
if (index <= 255)
|
||||
{
|
||||
il.Emit(OpCodes.Starg_S, (byte)index);
|
||||
}
|
||||
else
|
||||
{
|
||||
il.Emit(OpCodes.Starg, index);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper for Pop op.
|
||||
/// </summary>
|
||||
public static void EmitPop(this ILGenerator il, int count)
|
||||
{
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
il.Emit(OpCodes.Pop);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitCall(this ILGenerator il, MethodInfo methodInfo)
|
||||
{
|
||||
if (methodInfo.IsFinal || !methodInfo.IsVirtual)
|
||||
{
|
||||
il.Emit(OpCodes.Call, methodInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
il.Emit(OpCodes.Callvirt, methodInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EmitLdfld(this ILGenerator il, FieldInfo fieldInfo)
|
||||
{
|
||||
il.Emit(OpCodes.Ldfld, fieldInfo);
|
||||
}
|
||||
|
||||
public static void EmitLdsfld(this ILGenerator il, FieldInfo fieldInfo)
|
||||
{
|
||||
il.Emit(OpCodes.Ldsfld, fieldInfo);
|
||||
}
|
||||
|
||||
public static void EmitRet(this ILGenerator il)
|
||||
{
|
||||
il.Emit(OpCodes.Ret);
|
||||
}
|
||||
|
||||
public static void EmitIntZeroReturn(this ILGenerator il)
|
||||
{
|
||||
il.EmitLdc_I4(0);
|
||||
il.Emit(OpCodes.Ret);
|
||||
}
|
||||
|
||||
public static void EmitNullReturn(this ILGenerator il)
|
||||
{
|
||||
il.Emit(OpCodes.Ldnull);
|
||||
il.Emit(OpCodes.Ret);
|
||||
}
|
||||
|
||||
public static void EmitULong(this ILGenerator il, ulong value)
|
||||
{
|
||||
il.Emit(OpCodes.Ldc_I8, unchecked((long)value));
|
||||
}
|
||||
|
||||
public static void EmitThrowNotimplemented(this ILGenerator il)
|
||||
{
|
||||
il.Emit(OpCodes.Newobj, typeof(System.NotImplementedException).GetTypeInfo().DeclaredConstructors.First(x => x.GetParameters().Length == 0));
|
||||
il.Emit(OpCodes.Throw);
|
||||
}
|
||||
|
||||
/// <summary>for var i = 0, i ..., i++. </summary>
|
||||
public static void EmitIncrementFor(this ILGenerator il, LocalBuilder conditionGreater, Action<LocalBuilder> emitBody)
|
||||
{
|
||||
Label loopBegin = il.DefineLabel();
|
||||
Label condtionLabel = il.DefineLabel();
|
||||
|
||||
// var i = 0
|
||||
LocalBuilder forI = il.DeclareLocal(typeof(int));
|
||||
il.EmitLdc_I4(0);
|
||||
il.EmitStloc(forI);
|
||||
il.Emit(OpCodes.Br, condtionLabel);
|
||||
|
||||
il.MarkLabel(loopBegin);
|
||||
emitBody(forI);
|
||||
|
||||
// i++
|
||||
il.EmitLdloc(forI);
|
||||
il.EmitLdc_I4(1);
|
||||
il.Emit(OpCodes.Add);
|
||||
il.EmitStloc(forI);
|
||||
|
||||
//// i < ***
|
||||
il.MarkLabel(condtionLabel);
|
||||
il.EmitLdloc(forI);
|
||||
il.EmitLdloc(conditionGreater);
|
||||
il.Emit(OpCodes.Blt, loopBegin);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a7fcc89bc1ce33b46b7e5d8bcaa7f0fa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,49 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace MessagePack.Internal
|
||||
{
|
||||
internal static class ReflectionExtensions
|
||||
{
|
||||
public static bool IsNullable(this System.Reflection.TypeInfo type)
|
||||
{
|
||||
return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(System.Nullable<>);
|
||||
}
|
||||
|
||||
public static bool IsPublic(this System.Reflection.TypeInfo type)
|
||||
{
|
||||
return type.IsPublic;
|
||||
}
|
||||
|
||||
public static bool IsAnonymous(this System.Reflection.TypeInfo type)
|
||||
{
|
||||
return type.GetCustomAttribute<CompilerGeneratedAttribute>() != null
|
||||
&& type.IsGenericType && type.Name.Contains("AnonymousType")
|
||||
&& (type.Name.StartsWith("<>") || type.Name.StartsWith("VB$"))
|
||||
&& (type.Attributes & TypeAttributes.NotPublic) == TypeAttributes.NotPublic;
|
||||
}
|
||||
|
||||
public static bool IsIndexer(this System.Reflection.PropertyInfo propertyInfo)
|
||||
{
|
||||
return propertyInfo.GetIndexParameters().Length > 0;
|
||||
}
|
||||
|
||||
public static bool IsConstructedGenericType(this System.Reflection.TypeInfo type)
|
||||
{
|
||||
return type.AsType().IsConstructedGenericType;
|
||||
}
|
||||
|
||||
public static MethodInfo GetGetMethod(this PropertyInfo propInfo)
|
||||
{
|
||||
return propInfo.GetMethod;
|
||||
}
|
||||
|
||||
public static MethodInfo GetSetMethod(this PropertyInfo propInfo)
|
||||
{
|
||||
return propInfo.SetMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 82787207c36d0a4a98d7f53b49ba1576
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,573 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
/* Original license and copyright from file copied from https://github.com/AArnott/Nerdbank.Streams/blob/d656899be26d4d7c72c11c9232b4952c64a89bcb/src/Nerdbank.Streams/Sequence%601.cs
|
||||
* Copyright (c) Andrew Arnott. All rights reserved.
|
||||
* Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Nerdbank.Streams
|
||||
{
|
||||
/// <summary>
|
||||
/// Manages a sequence of elements, readily castable as a <see cref="ReadOnlySequence{T}"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of element stored by the sequence.</typeparam>
|
||||
/// <remarks>
|
||||
/// Instance members are not thread-safe.
|
||||
/// </remarks>
|
||||
[DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")]
|
||||
internal class Sequence<T> : IBufferWriter<T>, IDisposable
|
||||
{
|
||||
private static readonly int DefaultLengthFromArrayPool = 1 + (4095 / Marshal.SizeOf<T>());
|
||||
|
||||
private readonly Stack<SequenceSegment> segmentPool = new Stack<SequenceSegment>();
|
||||
|
||||
private readonly MemoryPool<T> memoryPool;
|
||||
|
||||
private readonly ArrayPool<T> arrayPool;
|
||||
|
||||
private SequenceSegment first;
|
||||
|
||||
private SequenceSegment last;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Sequence{T}"/> class
|
||||
/// that uses a private <see cref="ArrayPool{T}"/> for recycling arrays.
|
||||
/// </summary>
|
||||
public Sequence()
|
||||
: this(ArrayPool<T>.Create())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Sequence{T}"/> class.
|
||||
/// </summary>
|
||||
/// <param name="memoryPool">The pool to use for recycling backing arrays.</param>
|
||||
public Sequence(MemoryPool<T> memoryPool)
|
||||
{
|
||||
Requires.NotNull(memoryPool, nameof(memoryPool));
|
||||
this.memoryPool = memoryPool;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="Sequence{T}"/> class.
|
||||
/// </summary>
|
||||
/// <param name="arrayPool">The pool to use for recycling backing arrays.</param>
|
||||
public Sequence(ArrayPool<T> arrayPool)
|
||||
{
|
||||
Requires.NotNull(arrayPool, nameof(arrayPool));
|
||||
this.arrayPool = arrayPool;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the minimum length for any array allocated as a segment in the sequence.
|
||||
/// Any non-positive value allows the pool to determine the length of the array.
|
||||
/// </summary>
|
||||
/// <value>The default value is 0.</value>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// Each time <see cref="GetSpan(int)"/> or <see cref="GetMemory(int)"/> is called,
|
||||
/// previously allocated memory is used if it is large enough to satisfy the length demand.
|
||||
/// If new memory must be allocated, the argument to one of these methods typically dictate
|
||||
/// the length of array to allocate. When the caller uses very small values (just enough for its immediate need)
|
||||
/// but the high level scenario can predict that a large amount of memory will be ultimately required,
|
||||
/// it can be advisable to set this property to a value such that just a few larger arrays are allocated
|
||||
/// instead of many small ones.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// The <see cref="MemoryPool{T}"/> in use may itself have a minimum array length as well,
|
||||
/// in which case the higher of the two minimums dictate the minimum array size that will be allocated.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
public int MinimumSpanLength { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets this sequence expressed as a <see cref="ReadOnlySequence{T}"/>.
|
||||
/// </summary>
|
||||
/// <returns>A read only sequence representing the data in this object.</returns>
|
||||
public ReadOnlySequence<T> AsReadOnlySequence => this;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the length of the sequence.
|
||||
/// </summary>
|
||||
public long Length => this.AsReadOnlySequence.Length;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value to display in a debugger datatip.
|
||||
/// </summary>
|
||||
private string DebuggerDisplay => $"Length: {this.AsReadOnlySequence.Length}";
|
||||
|
||||
/// <summary>
|
||||
/// Expresses this sequence as a <see cref="ReadOnlySequence{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="sequence">The sequence to convert.</param>
|
||||
public static implicit operator ReadOnlySequence<T>(Sequence<T> sequence)
|
||||
{
|
||||
return sequence.first != null
|
||||
? new ReadOnlySequence<T>(sequence.first, sequence.first.Start, sequence.last, sequence.last.End)
|
||||
: ReadOnlySequence<T>.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all elements from the sequence from its beginning to the specified position,
|
||||
/// considering that data to have been fully processed.
|
||||
/// </summary>
|
||||
/// <param name="position">
|
||||
/// The position of the first element that has not yet been processed.
|
||||
/// This is typically <see cref="ReadOnlySequence{T}.End"/> after reading all elements from that instance.
|
||||
/// </param>
|
||||
public void AdvanceTo(SequencePosition position)
|
||||
{
|
||||
var firstSegment = (SequenceSegment)position.GetObject();
|
||||
int firstIndex = position.GetInteger();
|
||||
|
||||
// Before making any mutations, confirm that the block specified belongs to this sequence.
|
||||
var current = this.first;
|
||||
while (current != firstSegment && current != null)
|
||||
{
|
||||
current = current.Next;
|
||||
}
|
||||
|
||||
Requires.Argument(current != null, nameof(position), "Position does not represent a valid position in this sequence.");
|
||||
|
||||
// Also confirm that the position is not a prior position in the block.
|
||||
Requires.Argument(firstIndex >= current.Start, nameof(position), "Position must not be earlier than current position.");
|
||||
|
||||
// Now repeat the loop, performing the mutations.
|
||||
current = this.first;
|
||||
while (current != firstSegment)
|
||||
{
|
||||
current = this.RecycleAndGetNext(current);
|
||||
}
|
||||
|
||||
firstSegment.AdvanceTo(firstIndex);
|
||||
|
||||
if (firstSegment.Length == 0)
|
||||
{
|
||||
firstSegment = this.RecycleAndGetNext(firstSegment);
|
||||
}
|
||||
|
||||
this.first = firstSegment;
|
||||
|
||||
if (this.first == null)
|
||||
{
|
||||
this.last = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Advances the sequence to include the specified number of elements initialized into memory
|
||||
/// returned by a prior call to <see cref="GetMemory(int)"/>.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of elements written into memory.</param>
|
||||
public void Advance(int count)
|
||||
{
|
||||
SequenceSegment last = this.last;
|
||||
Verify.Operation(last != null, "Cannot advance before acquiring memory.");
|
||||
last.Advance(count);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets writable memory that can be initialized and added to the sequence via a subsequent call to <see cref="Advance(int)"/>.
|
||||
/// </summary>
|
||||
/// <param name="sizeHint">The size of the memory required, or 0 to just get a convenient (non-empty) buffer.</param>
|
||||
/// <returns>The requested memory.</returns>
|
||||
public Memory<T> GetMemory(int sizeHint) => this.GetSegment(sizeHint).RemainingMemory;
|
||||
|
||||
/// <summary>
|
||||
/// Gets writable memory that can be initialized and added to the sequence via a subsequent call to <see cref="Advance(int)"/>.
|
||||
/// </summary>
|
||||
/// <param name="sizeHint">The size of the memory required, or 0 to just get a convenient (non-empty) buffer.</param>
|
||||
/// <returns>The requested memory.</returns>
|
||||
public Span<T> GetSpan(int sizeHint) => this.GetSegment(sizeHint).RemainingSpan;
|
||||
|
||||
/// <summary>
|
||||
/// Clears the entire sequence, recycles associated memory into pools,
|
||||
/// and resets this instance for reuse.
|
||||
/// This invalidates any <see cref="ReadOnlySequence{T}"/> previously produced by this instance.
|
||||
/// </summary>
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public void Dispose() => this.Reset();
|
||||
|
||||
/// <summary>
|
||||
/// Clears the entire sequence and recycles associated memory into pools.
|
||||
/// This invalidates any <see cref="ReadOnlySequence{T}"/> previously produced by this instance.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
var current = this.first;
|
||||
while (current != null)
|
||||
{
|
||||
current = this.RecycleAndGetNext(current);
|
||||
}
|
||||
|
||||
this.first = this.last = null;
|
||||
}
|
||||
|
||||
private SequenceSegment GetSegment(int sizeHint)
|
||||
{
|
||||
Requires.Range(sizeHint >= 0, nameof(sizeHint));
|
||||
int? minBufferSize = null;
|
||||
if (sizeHint == 0)
|
||||
{
|
||||
if (this.last == null || this.last.WritableBytes == 0)
|
||||
{
|
||||
// We're going to need more memory. Take whatever size the pool wants to give us.
|
||||
minBufferSize = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sizeHint = Math.Max(this.MinimumSpanLength, sizeHint);
|
||||
if (this.last == null || this.last.WritableBytes < sizeHint)
|
||||
{
|
||||
minBufferSize = sizeHint;
|
||||
}
|
||||
}
|
||||
|
||||
if (minBufferSize.HasValue)
|
||||
{
|
||||
var segment = this.segmentPool.Count > 0 ? this.segmentPool.Pop() : new SequenceSegment();
|
||||
if (this.arrayPool != null)
|
||||
{
|
||||
segment.Assign(this.arrayPool.Rent(minBufferSize.Value == -1 ? DefaultLengthFromArrayPool : minBufferSize.Value));
|
||||
}
|
||||
else
|
||||
{
|
||||
segment.Assign(this.memoryPool.Rent(minBufferSize.Value));
|
||||
}
|
||||
|
||||
this.Append(segment);
|
||||
}
|
||||
|
||||
return this.last;
|
||||
}
|
||||
|
||||
private void Append(SequenceSegment segment)
|
||||
{
|
||||
if (this.last == null)
|
||||
{
|
||||
this.first = this.last = segment;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.last.Length > 0)
|
||||
{
|
||||
// Add a new block.
|
||||
this.last.SetNext(segment);
|
||||
}
|
||||
else
|
||||
{
|
||||
// The last block is completely unused. Replace it instead of appending to it.
|
||||
var current = this.first;
|
||||
if (this.first != this.last)
|
||||
{
|
||||
while (current.Next != this.last)
|
||||
{
|
||||
current = current.Next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.first = segment;
|
||||
}
|
||||
|
||||
current.SetNext(segment);
|
||||
this.RecycleAndGetNext(this.last);
|
||||
}
|
||||
|
||||
this.last = segment;
|
||||
}
|
||||
}
|
||||
|
||||
private SequenceSegment RecycleAndGetNext(SequenceSegment segment)
|
||||
{
|
||||
var recycledSegment = segment;
|
||||
segment = segment.Next;
|
||||
recycledSegment.ResetMemory(this.arrayPool);
|
||||
this.segmentPool.Push(recycledSegment);
|
||||
return segment;
|
||||
}
|
||||
|
||||
private class SequenceSegment : ReadOnlySequenceSegment<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// A value indicating whether the element is a value type.
|
||||
/// </summary>
|
||||
private static readonly bool IsValueTypeElement = typeof(T).GetTypeInfo().IsValueType;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the backing array, when using an <see cref="ArrayPool{T}"/> instead of a <see cref="MemoryPool{T}"/>.
|
||||
/// </summary>
|
||||
private T[] array;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the position within <see cref="ReadOnlySequenceSegment{T}.Memory"/> where the data starts.
|
||||
/// </summary>
|
||||
/// <remarks>This may be nonzero as a result of calling <see cref="Sequence{T}.AdvanceTo(SequencePosition)"/>.</remarks>
|
||||
internal int Start { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the position within <see cref="ReadOnlySequenceSegment{T}.Memory"/> where the data ends.
|
||||
/// </summary>
|
||||
internal int End { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tail of memory that has not yet been committed.
|
||||
/// </summary>
|
||||
internal Memory<T> RemainingMemory => this.AvailableMemory.Slice(this.End);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tail of memory that has not yet been committed.
|
||||
/// </summary>
|
||||
internal Span<T> RemainingSpan => this.AvailableMemory.Span.Slice(this.End);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tracker for the underlying array for this segment, which can be used to recycle the array when we're disposed of.
|
||||
/// Will be <c>null</c> if using an array pool, in which case the memory is held by <see cref="array"/>.
|
||||
/// </summary>
|
||||
internal IMemoryOwner<T> MemoryOwner { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the full memory owned by the <see cref="MemoryOwner"/>.
|
||||
/// </summary>
|
||||
internal Memory<T> AvailableMemory => this.array ?? this.MemoryOwner?.Memory ?? default;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of elements that are committed in this segment.
|
||||
/// </summary>
|
||||
internal int Length => this.End - this.Start;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the amount of writable bytes in this segment.
|
||||
/// It is the amount of bytes between <see cref="Length"/> and <see cref="End"/>.
|
||||
/// </summary>
|
||||
internal int WritableBytes => this.AvailableMemory.Length - this.End;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the next segment in the singly linked list of segments.
|
||||
/// </summary>
|
||||
internal new SequenceSegment Next
|
||||
{
|
||||
get => (SequenceSegment)base.Next;
|
||||
set => base.Next = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assigns this (recyclable) segment a new area in memory.
|
||||
/// </summary>
|
||||
/// <param name="memoryOwner">The memory and a means to recycle it.</param>
|
||||
internal void Assign(IMemoryOwner<T> memoryOwner)
|
||||
{
|
||||
this.MemoryOwner = memoryOwner;
|
||||
this.Memory = memoryOwner.Memory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Assigns this (recyclable) segment a new area in memory.
|
||||
/// </summary>
|
||||
/// <param name="array">An array drawn from an <see cref="ArrayPool{T}"/>.</param>
|
||||
internal void Assign(T[] array)
|
||||
{
|
||||
this.array = array;
|
||||
this.Memory = array;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all fields in preparation to recycle this instance.
|
||||
/// </summary>
|
||||
internal void ResetMemory(ArrayPool<T> arrayPool)
|
||||
{
|
||||
this.ClearReferences(this.Start, this.End);
|
||||
this.Memory = default;
|
||||
this.Next = null;
|
||||
this.RunningIndex = 0;
|
||||
this.Start = 0;
|
||||
this.End = 0;
|
||||
if (this.array != null)
|
||||
{
|
||||
arrayPool.Return(this.array);
|
||||
this.array = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.MemoryOwner?.Dispose();
|
||||
this.MemoryOwner = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new segment after this one.
|
||||
/// </summary>
|
||||
/// <param name="segment">The next segment in the linked list.</param>
|
||||
internal void SetNext(SequenceSegment segment)
|
||||
{
|
||||
Debug.Assert(segment != null, "Null not allowed.");
|
||||
this.Next = segment;
|
||||
segment.RunningIndex = this.RunningIndex + this.Start + this.Length;
|
||||
|
||||
// When setting Memory, we start with index 0 instead of this.Start because
|
||||
// the first segment has an explicit index set anyway,
|
||||
// and we don't want to double-count it here.
|
||||
this.Memory = this.AvailableMemory.Slice(0, this.Start + this.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Commits more elements as written in this segment.
|
||||
/// </summary>
|
||||
/// <param name="count">The number of elements written.</param>
|
||||
internal void Advance(int count)
|
||||
{
|
||||
Requires.Range(count >= 0 && this.End + count <= this.Memory.Length, nameof(count));
|
||||
this.End += count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes some elements from the start of this segment.
|
||||
/// </summary>
|
||||
/// <param name="offset">The number of elements to ignore from the start of the underlying array.</param>
|
||||
internal void AdvanceTo(int offset)
|
||||
{
|
||||
Debug.Assert(offset >= this.Start, "Trying to rewind.");
|
||||
this.ClearReferences(this.Start, offset - this.Start);
|
||||
this.Start = offset;
|
||||
}
|
||||
|
||||
private void ClearReferences(int startIndex, int length)
|
||||
{
|
||||
// If we store references, clear them to allow the objects to be GC'd.
|
||||
if (!IsValueTypeElement)
|
||||
{
|
||||
this.AvailableMemory.Span.Slice(startIndex, length).Fill(default);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static class Requires
|
||||
{
|
||||
/// <summary>
|
||||
/// Throws an <see cref="ArgumentOutOfRangeException"/> if a condition does not evaluate to true.
|
||||
/// </summary>
|
||||
[DebuggerStepThrough]
|
||||
public static void Range(bool condition, string parameterName, string message = null)
|
||||
{
|
||||
if (!condition)
|
||||
{
|
||||
FailRange(parameterName, message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an <see cref="ArgumentOutOfRangeException"/> if a condition does not evaluate to true.
|
||||
/// </summary>
|
||||
/// <returns>Nothing. This method always throws.</returns>
|
||||
[DebuggerStepThrough]
|
||||
public static Exception FailRange(string parameterName, string message = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(message))
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(parameterName);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(parameterName, message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception if the specified parameter's value is null.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the parameter.</typeparam>
|
||||
/// <param name="value">The value of the argument.</param>
|
||||
/// <param name="parameterName">The name of the parameter to include in any thrown exception.</param>
|
||||
/// <returns>The value of the parameter.</returns>
|
||||
/// <exception cref="ArgumentNullException">Thrown if <paramref name="value"/> is <c>null</c>.</exception>
|
||||
[DebuggerStepThrough]
|
||||
public static T NotNull<T>(T value, string parameterName)
|
||||
where T : class // ensures value-types aren't passed to a null checking method
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException(parameterName);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an ArgumentException if a condition does not evaluate to true.
|
||||
/// </summary>
|
||||
[DebuggerStepThrough]
|
||||
public static void Argument(bool condition, string parameterName, string message)
|
||||
{
|
||||
if (!condition)
|
||||
{
|
||||
throw new ArgumentException(message, parameterName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an ArgumentException if a condition does not evaluate to true.
|
||||
/// </summary>
|
||||
[DebuggerStepThrough]
|
||||
public static void Argument(bool condition, string parameterName, string message, object arg1)
|
||||
{
|
||||
if (!condition)
|
||||
{
|
||||
throw new ArgumentException(String.Format(message, arg1), parameterName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an ArgumentException if a condition does not evaluate to true.
|
||||
/// </summary>
|
||||
[DebuggerStepThrough]
|
||||
public static void Argument(bool condition, string parameterName, string message, object arg1, object arg2)
|
||||
{
|
||||
if (!condition)
|
||||
{
|
||||
throw new ArgumentException(String.Format(message, arg1, arg2), parameterName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an ArgumentException if a condition does not evaluate to true.
|
||||
/// </summary>
|
||||
[DebuggerStepThrough]
|
||||
public static void Argument(bool condition, string parameterName, string message, params object[] args)
|
||||
{
|
||||
if (!condition)
|
||||
{
|
||||
throw new ArgumentException(String.Format(message, args), parameterName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Common runtime checks that throw exceptions upon failure.
|
||||
/// </summary>
|
||||
internal static partial class Verify
|
||||
{
|
||||
/// <summary>
|
||||
/// Throws an <see cref="InvalidOperationException"/> if a condition is false.
|
||||
/// </summary>
|
||||
[DebuggerStepThrough]
|
||||
internal static void Operation(bool condition, string message)
|
||||
{
|
||||
if (!condition)
|
||||
{
|
||||
throw new InvalidOperationException(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 19e730b2bfc50b981bdcd41c703daab2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,246 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
#pragma warning disable SA1649 // File name should match first type name
|
||||
|
||||
namespace MessagePack.Internal
|
||||
{
|
||||
/// <summary>
|
||||
/// A dictionary where <see cref="Type"/> is the key, and a configurable <typeparamref name="TValue"/> type
|
||||
/// that is thread-safe to read and write, allowing concurrent reads and exclusive writes.
|
||||
/// </summary>
|
||||
/// <typeparam name="TValue">The type of value stored in the dictionary.</typeparam>
|
||||
internal class ThreadsafeTypeKeyHashTable<TValue>
|
||||
{
|
||||
private Entry[] buckets;
|
||||
private int size; // only use in writer lock
|
||||
|
||||
private readonly object writerLock = new object();
|
||||
private readonly float loadFactor;
|
||||
|
||||
// IEqualityComparer.Equals is overhead if key only Type, don't use it.
|
||||
//// readonly IEqualityComparer<TKey> comparer;
|
||||
|
||||
public ThreadsafeTypeKeyHashTable(int capacity = 4, float loadFactor = 0.75f)
|
||||
{
|
||||
var tableSize = CalculateCapacity(capacity, loadFactor);
|
||||
this.buckets = new Entry[tableSize];
|
||||
this.loadFactor = loadFactor;
|
||||
}
|
||||
|
||||
public bool TryAdd(Type key, TValue value)
|
||||
{
|
||||
return this.TryAdd(key, _ => value); // create lambda capture
|
||||
}
|
||||
|
||||
public bool TryAdd(Type key, Func<Type, TValue> valueFactory)
|
||||
{
|
||||
return this.TryAddInternal(key, valueFactory, out TValue _);
|
||||
}
|
||||
|
||||
private bool TryAddInternal(Type key, Func<Type, TValue> valueFactory, out TValue resultingValue)
|
||||
{
|
||||
lock (this.writerLock)
|
||||
{
|
||||
var nextCapacity = CalculateCapacity(this.size + 1, this.loadFactor);
|
||||
|
||||
if (this.buckets.Length < nextCapacity)
|
||||
{
|
||||
// rehash
|
||||
var nextBucket = new Entry[nextCapacity];
|
||||
for (int i = 0; i < this.buckets.Length; i++)
|
||||
{
|
||||
Entry e = this.buckets[i];
|
||||
while (e != null)
|
||||
{
|
||||
var newEntry = new Entry { Key = e.Key, Value = e.Value, Hash = e.Hash };
|
||||
this.AddToBuckets(nextBucket, key, newEntry, null, out resultingValue);
|
||||
e = e.Next;
|
||||
}
|
||||
}
|
||||
|
||||
// add entry(if failed to add, only do resize)
|
||||
var successAdd = this.AddToBuckets(nextBucket, key, null, valueFactory, out resultingValue);
|
||||
|
||||
// replace field(threadsafe for read)
|
||||
VolatileWrite(ref this.buckets, nextBucket);
|
||||
|
||||
if (successAdd)
|
||||
{
|
||||
this.size++;
|
||||
}
|
||||
|
||||
return successAdd;
|
||||
}
|
||||
else
|
||||
{
|
||||
// add entry(insert last is thread safe for read)
|
||||
var successAdd = this.AddToBuckets(this.buckets, key, null, valueFactory, out resultingValue);
|
||||
if (successAdd)
|
||||
{
|
||||
this.size++;
|
||||
}
|
||||
|
||||
return successAdd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool AddToBuckets(Entry[] buckets, Type newKey, Entry newEntryOrNull, Func<Type, TValue> valueFactory, out TValue resultingValue)
|
||||
{
|
||||
var h = (newEntryOrNull != null) ? newEntryOrNull.Hash : newKey.GetHashCode();
|
||||
if (buckets[h & (buckets.Length - 1)] == null)
|
||||
{
|
||||
if (newEntryOrNull != null)
|
||||
{
|
||||
resultingValue = newEntryOrNull.Value;
|
||||
VolatileWrite(ref buckets[h & (buckets.Length - 1)], newEntryOrNull);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultingValue = valueFactory(newKey);
|
||||
VolatileWrite(ref buckets[h & (buckets.Length - 1)], new Entry { Key = newKey, Value = resultingValue, Hash = h });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Entry searchLastEntry = buckets[h & (buckets.Length - 1)];
|
||||
while (true)
|
||||
{
|
||||
if (searchLastEntry.Key == newKey)
|
||||
{
|
||||
resultingValue = searchLastEntry.Value;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (searchLastEntry.Next == null)
|
||||
{
|
||||
if (newEntryOrNull != null)
|
||||
{
|
||||
resultingValue = newEntryOrNull.Value;
|
||||
VolatileWrite(ref searchLastEntry.Next, newEntryOrNull);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultingValue = valueFactory(newKey);
|
||||
VolatileWrite(ref searchLastEntry.Next, new Entry { Key = newKey, Value = resultingValue, Hash = h });
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
searchLastEntry = searchLastEntry.Next;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public bool TryGetValue(Type key, out TValue value)
|
||||
{
|
||||
Entry[] table = this.buckets;
|
||||
var hash = key.GetHashCode();
|
||||
Entry entry = table[hash & table.Length - 1];
|
||||
|
||||
while (entry != null)
|
||||
{
|
||||
if (entry.Key == key)
|
||||
{
|
||||
value = entry.Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
entry = entry.Next;
|
||||
}
|
||||
|
||||
value = default(TValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
public TValue GetOrAdd(Type key, Func<Type, TValue> valueFactory)
|
||||
{
|
||||
TValue v;
|
||||
if (this.TryGetValue(key, out v))
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
this.TryAddInternal(key, valueFactory, out v);
|
||||
return v;
|
||||
}
|
||||
|
||||
private static int CalculateCapacity(int collectionSize, float loadFactor)
|
||||
{
|
||||
var initialCapacity = (int)(((float)collectionSize) / loadFactor);
|
||||
var capacity = 1;
|
||||
while (capacity < initialCapacity)
|
||||
{
|
||||
capacity <<= 1;
|
||||
}
|
||||
|
||||
if (capacity < 8)
|
||||
{
|
||||
return 8;
|
||||
}
|
||||
|
||||
return capacity;
|
||||
}
|
||||
|
||||
private static void VolatileWrite(ref Entry location, Entry value)
|
||||
{
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
System.Threading.Volatile.Write(ref location, value);
|
||||
#elif UNITY_2018_3_OR_NEWER || NET_4_6
|
||||
System.Threading.Volatile.Write(ref location, value);
|
||||
#else
|
||||
System.Threading.Thread.MemoryBarrier();
|
||||
location = value;
|
||||
#endif
|
||||
}
|
||||
|
||||
private static void VolatileWrite(ref Entry[] location, Entry[] value)
|
||||
{
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
System.Threading.Volatile.Write(ref location, value);
|
||||
#elif UNITY_2018_3_OR_NEWER || NET_4_6
|
||||
System.Threading.Volatile.Write(ref location, value);
|
||||
#else
|
||||
System.Threading.Thread.MemoryBarrier();
|
||||
location = value;
|
||||
#endif
|
||||
}
|
||||
|
||||
private class Entry
|
||||
{
|
||||
#pragma warning disable SA1401 // Fields should be private
|
||||
internal Type Key;
|
||||
internal TValue Value;
|
||||
internal int Hash;
|
||||
internal Entry Next;
|
||||
#pragma warning restore SA1401 // Fields should be private
|
||||
|
||||
// debug only
|
||||
public override string ToString()
|
||||
{
|
||||
return this.Key + "(" + this.Count() + ")";
|
||||
}
|
||||
|
||||
private int Count()
|
||||
{
|
||||
var count = 1;
|
||||
Entry n = this;
|
||||
while (n.Next != null)
|
||||
{
|
||||
count++;
|
||||
n = n.Next;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 517dd6b1707013015b06ebfbeeea1f2c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,430 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
#pragma warning disable SA1649 // File name should match first type name
|
||||
|
||||
namespace MessagePack
|
||||
{
|
||||
/* simple, tiny JSON reader for MessagePackSerializer.FromJson.
|
||||
* this is simple, compact and enough fast but not optimized extremely. */
|
||||
|
||||
internal enum TinyJsonToken
|
||||
{
|
||||
None,
|
||||
StartObject, // {
|
||||
EndObject, // }
|
||||
StartArray, // [
|
||||
EndArray, // ]
|
||||
Number, // -0~9
|
||||
String, // "___"
|
||||
True, // true
|
||||
False, // false
|
||||
Null, // null
|
||||
}
|
||||
|
||||
internal enum ValueType : byte
|
||||
{
|
||||
Null,
|
||||
True,
|
||||
False,
|
||||
Double,
|
||||
Long,
|
||||
ULong,
|
||||
Decimal,
|
||||
String,
|
||||
}
|
||||
|
||||
public class TinyJsonException : MessagePackSerializationException
|
||||
{
|
||||
public TinyJsonException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
internal class TinyJsonReader : IDisposable
|
||||
{
|
||||
private readonly TextReader reader;
|
||||
private readonly bool disposeInnerReader;
|
||||
private StringBuilder reusableBuilder;
|
||||
|
||||
public TinyJsonToken TokenType { get; private set; }
|
||||
|
||||
public ValueType ValueType { get; private set; }
|
||||
|
||||
public double DoubleValue { get; private set; }
|
||||
|
||||
public long LongValue { get; private set; }
|
||||
|
||||
public ulong ULongValue { get; private set; }
|
||||
|
||||
public decimal DecimalValue { get; private set; }
|
||||
|
||||
public string StringValue { get; private set; }
|
||||
|
||||
public TinyJsonReader(TextReader reader, bool disposeInnerReader = true)
|
||||
{
|
||||
this.reader = reader;
|
||||
this.disposeInnerReader = disposeInnerReader;
|
||||
}
|
||||
|
||||
public bool Read()
|
||||
{
|
||||
this.ReadNextToken();
|
||||
this.ReadValue();
|
||||
return this.TokenType != TinyJsonToken.None;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (this.reader != null && this.disposeInnerReader)
|
||||
{
|
||||
this.reader.Dispose();
|
||||
}
|
||||
|
||||
this.TokenType = TinyJsonToken.None;
|
||||
this.ValueType = ValueType.Null;
|
||||
}
|
||||
|
||||
private void SkipWhiteSpace()
|
||||
{
|
||||
var c = this.reader.Peek();
|
||||
while (c != -1 && Char.IsWhiteSpace((char)c))
|
||||
{
|
||||
this.reader.Read();
|
||||
c = this.reader.Peek();
|
||||
}
|
||||
}
|
||||
|
||||
private char ReadChar()
|
||||
{
|
||||
return (char)this.reader.Read();
|
||||
}
|
||||
|
||||
private static bool IsWordBreak(char c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case ' ':
|
||||
case '{':
|
||||
case '}':
|
||||
case '[':
|
||||
case ']':
|
||||
case ',':
|
||||
case ':':
|
||||
case '\"':
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadNextToken()
|
||||
{
|
||||
this.SkipWhiteSpace();
|
||||
|
||||
var intChar = this.reader.Peek();
|
||||
if (intChar == -1)
|
||||
{
|
||||
this.TokenType = TinyJsonToken.None;
|
||||
return;
|
||||
}
|
||||
|
||||
var c = (char)intChar;
|
||||
switch (c)
|
||||
{
|
||||
case '{':
|
||||
this.TokenType = TinyJsonToken.StartObject;
|
||||
return;
|
||||
case '}':
|
||||
this.TokenType = TinyJsonToken.EndObject;
|
||||
return;
|
||||
case '[':
|
||||
this.TokenType = TinyJsonToken.StartArray;
|
||||
return;
|
||||
case ']':
|
||||
this.TokenType = TinyJsonToken.EndArray;
|
||||
return;
|
||||
case '"':
|
||||
this.TokenType = TinyJsonToken.String;
|
||||
return;
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
case '-':
|
||||
this.TokenType = TinyJsonToken.Number;
|
||||
return;
|
||||
case 't':
|
||||
this.TokenType = TinyJsonToken.True;
|
||||
return;
|
||||
case 'f':
|
||||
this.TokenType = TinyJsonToken.False;
|
||||
return;
|
||||
case 'n':
|
||||
this.TokenType = TinyJsonToken.Null;
|
||||
return;
|
||||
case ',':
|
||||
case ':':
|
||||
this.reader.Read();
|
||||
this.ReadNextToken();
|
||||
return;
|
||||
default:
|
||||
throw new TinyJsonException("Invalid String:" + c);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadValue()
|
||||
{
|
||||
this.ValueType = ValueType.Null;
|
||||
|
||||
switch (this.TokenType)
|
||||
{
|
||||
case TinyJsonToken.None:
|
||||
break;
|
||||
case TinyJsonToken.StartObject:
|
||||
case TinyJsonToken.EndObject:
|
||||
case TinyJsonToken.StartArray:
|
||||
case TinyJsonToken.EndArray:
|
||||
this.reader.Read();
|
||||
break;
|
||||
case TinyJsonToken.Number:
|
||||
this.ReadNumber();
|
||||
break;
|
||||
case TinyJsonToken.String:
|
||||
this.ReadString();
|
||||
break;
|
||||
case TinyJsonToken.True:
|
||||
if (this.ReadChar() != 't')
|
||||
{
|
||||
throw new TinyJsonException("Invalid Token");
|
||||
}
|
||||
|
||||
if (this.ReadChar() != 'r')
|
||||
{
|
||||
throw new TinyJsonException("Invalid Token");
|
||||
}
|
||||
|
||||
if (this.ReadChar() != 'u')
|
||||
{
|
||||
throw new TinyJsonException("Invalid Token");
|
||||
}
|
||||
|
||||
if (this.ReadChar() != 'e')
|
||||
{
|
||||
throw new TinyJsonException("Invalid Token");
|
||||
}
|
||||
|
||||
this.ValueType = ValueType.True;
|
||||
break;
|
||||
case TinyJsonToken.False:
|
||||
if (this.ReadChar() != 'f')
|
||||
{
|
||||
throw new TinyJsonException("Invalid Token");
|
||||
}
|
||||
|
||||
if (this.ReadChar() != 'a')
|
||||
{
|
||||
throw new TinyJsonException("Invalid Token");
|
||||
}
|
||||
|
||||
if (this.ReadChar() != 'l')
|
||||
{
|
||||
throw new TinyJsonException("Invalid Token");
|
||||
}
|
||||
|
||||
if (this.ReadChar() != 's')
|
||||
{
|
||||
throw new TinyJsonException("Invalid Token");
|
||||
}
|
||||
|
||||
if (this.ReadChar() != 'e')
|
||||
{
|
||||
throw new TinyJsonException("Invalid Token");
|
||||
}
|
||||
|
||||
this.ValueType = ValueType.False;
|
||||
break;
|
||||
case TinyJsonToken.Null:
|
||||
if (this.ReadChar() != 'n')
|
||||
{
|
||||
throw new TinyJsonException("Invalid Token");
|
||||
}
|
||||
|
||||
if (this.ReadChar() != 'u')
|
||||
{
|
||||
throw new TinyJsonException("Invalid Token");
|
||||
}
|
||||
|
||||
if (this.ReadChar() != 'l')
|
||||
{
|
||||
throw new TinyJsonException("Invalid Token");
|
||||
}
|
||||
|
||||
if (this.ReadChar() != 'l')
|
||||
{
|
||||
throw new TinyJsonException("Invalid Token");
|
||||
}
|
||||
|
||||
this.ValueType = ValueType.Null;
|
||||
break;
|
||||
default:
|
||||
throw new MessagePackSerializationException("InvalidTokenState:" + this.TokenType);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadNumber()
|
||||
{
|
||||
StringBuilder numberWord;
|
||||
if (this.reusableBuilder == null)
|
||||
{
|
||||
this.reusableBuilder = new StringBuilder();
|
||||
numberWord = this.reusableBuilder;
|
||||
}
|
||||
else
|
||||
{
|
||||
numberWord = this.reusableBuilder;
|
||||
numberWord.Length = 0; // Clear
|
||||
}
|
||||
|
||||
var isDouble = false;
|
||||
var intChar = this.reader.Peek();
|
||||
while (intChar != -1 && !IsWordBreak((char)intChar))
|
||||
{
|
||||
var c = this.ReadChar();
|
||||
numberWord.Append(c);
|
||||
if (c == '.' || c == 'e' || c == 'E')
|
||||
{
|
||||
isDouble = true;
|
||||
}
|
||||
|
||||
intChar = this.reader.Peek();
|
||||
}
|
||||
|
||||
var number = numberWord.ToString();
|
||||
if (isDouble)
|
||||
{
|
||||
double parsedDouble;
|
||||
Double.TryParse(number, NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite | NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint | NumberStyles.AllowThousands | NumberStyles.AllowExponent, System.Globalization.CultureInfo.InvariantCulture, out parsedDouble);
|
||||
this.ValueType = ValueType.Double;
|
||||
this.DoubleValue = parsedDouble;
|
||||
}
|
||||
else
|
||||
{
|
||||
long parsedInt;
|
||||
if (Int64.TryParse(number, NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out parsedInt))
|
||||
{
|
||||
this.ValueType = ValueType.Long;
|
||||
this.LongValue = parsedInt;
|
||||
return;
|
||||
}
|
||||
|
||||
ulong parsedULong;
|
||||
if (ulong.TryParse(number, NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out parsedULong))
|
||||
{
|
||||
this.ValueType = ValueType.ULong;
|
||||
this.ULongValue = parsedULong;
|
||||
return;
|
||||
}
|
||||
|
||||
Decimal parsedDecimal;
|
||||
if (decimal.TryParse(number, NumberStyles.Number, System.Globalization.CultureInfo.InvariantCulture, out parsedDecimal))
|
||||
{
|
||||
this.ValueType = ValueType.Decimal;
|
||||
this.DecimalValue = parsedDecimal;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ReadString()
|
||||
{
|
||||
this.reader.Read(); // skip ["]
|
||||
|
||||
StringBuilder sb;
|
||||
if (this.reusableBuilder == null)
|
||||
{
|
||||
this.reusableBuilder = new StringBuilder();
|
||||
sb = this.reusableBuilder;
|
||||
}
|
||||
else
|
||||
{
|
||||
sb = this.reusableBuilder;
|
||||
sb.Length = 0; // Clear
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (this.reader.Peek() == -1)
|
||||
{
|
||||
throw new TinyJsonException("Invalid Json String");
|
||||
}
|
||||
|
||||
var c = this.ReadChar();
|
||||
switch (c)
|
||||
{
|
||||
case '"': // endtoken
|
||||
goto END;
|
||||
case '\\': // escape character
|
||||
if (this.reader.Peek() == -1)
|
||||
{
|
||||
throw new TinyJsonException("Invalid Json String");
|
||||
}
|
||||
|
||||
c = this.ReadChar();
|
||||
switch (c)
|
||||
{
|
||||
case '"':
|
||||
case '\\':
|
||||
case '/':
|
||||
sb.Append(c);
|
||||
break;
|
||||
case 'b':
|
||||
sb.Append('\b');
|
||||
break;
|
||||
case 'f':
|
||||
sb.Append('\f');
|
||||
break;
|
||||
case 'n':
|
||||
sb.Append('\n');
|
||||
break;
|
||||
case 'r':
|
||||
sb.Append('\r');
|
||||
break;
|
||||
case 't':
|
||||
sb.Append('\t');
|
||||
break;
|
||||
case 'u':
|
||||
var hex = new char[4];
|
||||
hex[0] = this.ReadChar();
|
||||
hex[1] = this.ReadChar();
|
||||
hex[2] = this.ReadChar();
|
||||
hex[3] = this.ReadChar();
|
||||
sb.Append((char)Convert.ToInt32(new string(hex), 16));
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
default: // string
|
||||
sb.Append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
END:
|
||||
this.ValueType = ValueType.String;
|
||||
this.StringValue = sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: adc1157b80c30cf2d8845336b9c1cfc2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,170 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#if !UNITY_2018_3_OR_NEWER
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace MessagePack.Internal
|
||||
{
|
||||
/* for string key property name write optimization. */
|
||||
|
||||
public static class UnsafeMemory
|
||||
{
|
||||
public static readonly bool Is32Bit = IntPtr.Size == 4;
|
||||
}
|
||||
|
||||
public static partial class UnsafeMemory32
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe void WriteRaw1(ref MessagePackWriter writer, ReadOnlySpan<byte> src)
|
||||
{
|
||||
Span<byte> dst = writer.GetSpan(src.Length);
|
||||
|
||||
fixed (byte* pSrc = &src[0])
|
||||
fixed (byte* pDst = &dst[0])
|
||||
{
|
||||
*(byte*)pDst = *(byte*)pSrc;
|
||||
}
|
||||
|
||||
writer.Advance(src.Length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe void WriteRaw2(ref MessagePackWriter writer, ReadOnlySpan<byte> src)
|
||||
{
|
||||
Span<byte> dst = writer.GetSpan(src.Length);
|
||||
|
||||
fixed (byte* pSrc = &src[0])
|
||||
fixed (byte* pDst = &dst[0])
|
||||
{
|
||||
*(short*)pDst = *(short*)pSrc;
|
||||
}
|
||||
|
||||
writer.Advance(src.Length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe void WriteRaw3(ref MessagePackWriter writer, ReadOnlySpan<byte> src)
|
||||
{
|
||||
Span<byte> dst = writer.GetSpan(src.Length);
|
||||
|
||||
fixed (byte* pSrc = &src[0])
|
||||
fixed (byte* pDst = &dst[0])
|
||||
{
|
||||
*(byte*)pDst = *(byte*)pSrc;
|
||||
*(short*)(pDst + 1) = *(short*)(pSrc + 1);
|
||||
}
|
||||
|
||||
writer.Advance(src.Length);
|
||||
}
|
||||
}
|
||||
|
||||
public static partial class UnsafeMemory64
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe void WriteRaw1(ref MessagePackWriter writer, ReadOnlySpan<byte> src)
|
||||
{
|
||||
Span<byte> dst = writer.GetSpan(src.Length);
|
||||
|
||||
fixed (byte* pSrc = &src[0])
|
||||
fixed (byte* pDst = &dst[0])
|
||||
{
|
||||
*(byte*)pDst = *(byte*)pSrc;
|
||||
}
|
||||
|
||||
writer.Advance(src.Length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe void WriteRaw2(ref MessagePackWriter writer, ReadOnlySpan<byte> src)
|
||||
{
|
||||
Span<byte> dst = writer.GetSpan(src.Length);
|
||||
|
||||
fixed (byte* pSrc = &src[0])
|
||||
fixed (byte* pDst = &dst[0])
|
||||
{
|
||||
*(short*)pDst = *(short*)pSrc;
|
||||
}
|
||||
|
||||
writer.Advance(src.Length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe void WriteRaw3(ref MessagePackWriter writer, ReadOnlySpan<byte> src)
|
||||
{
|
||||
Span<byte> dst = writer.GetSpan(src.Length);
|
||||
|
||||
fixed (byte* pSrc = &src[0])
|
||||
fixed (byte* pDst = &dst[0])
|
||||
{
|
||||
*(byte*)pDst = *(byte*)pSrc;
|
||||
*(short*)(pDst + 1) = *(short*)(pSrc + 1);
|
||||
}
|
||||
|
||||
writer.Advance(src.Length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe void WriteRaw4(ref MessagePackWriter writer, ReadOnlySpan<byte> src)
|
||||
{
|
||||
Span<byte> dst = writer.GetSpan(src.Length);
|
||||
|
||||
fixed (byte* pSrc = &src[0])
|
||||
fixed (byte* pDst = &dst[0])
|
||||
{
|
||||
*(int*)(pDst + 0) = *(int*)(pSrc + 0);
|
||||
}
|
||||
|
||||
writer.Advance(src.Length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe void WriteRaw5(ref MessagePackWriter writer, ReadOnlySpan<byte> src)
|
||||
{
|
||||
Span<byte> dst = writer.GetSpan(src.Length);
|
||||
|
||||
fixed (byte* pSrc = &src[0])
|
||||
fixed (byte* pDst = &dst[0])
|
||||
{
|
||||
*(int*)(pDst + 0) = *(int*)(pSrc + 0);
|
||||
*(int*)(pDst + 1) = *(int*)(pSrc + 1);
|
||||
}
|
||||
|
||||
writer.Advance(src.Length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe void WriteRaw6(ref MessagePackWriter writer, ReadOnlySpan<byte> src)
|
||||
{
|
||||
Span<byte> dst = writer.GetSpan(src.Length);
|
||||
|
||||
fixed (byte* pSrc = &src[0])
|
||||
fixed (byte* pDst = &dst[0])
|
||||
{
|
||||
*(int*)(pDst + 0) = *(int*)(pSrc + 0);
|
||||
*(int*)(pDst + 2) = *(int*)(pSrc + 2);
|
||||
}
|
||||
|
||||
writer.Advance(src.Length);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static unsafe void WriteRaw7(ref MessagePackWriter writer, ReadOnlySpan<byte> src)
|
||||
{
|
||||
Span<byte> dst = writer.GetSpan(src.Length);
|
||||
|
||||
fixed (byte* pSrc = &src[0])
|
||||
fixed (byte* pDst = &dst[0])
|
||||
{
|
||||
*(int*)(pDst + 0) = *(int*)(pSrc + 0);
|
||||
*(int*)(pDst + 3) = *(int*)(pSrc + 3);
|
||||
}
|
||||
|
||||
writer.Advance(src.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2126473180c3a7d3a8860c4fd8aa4183
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c633d9a494df48a45b82671c008a72a1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace MessagePack.LZ4
|
||||
{
|
||||
internal partial class LZ4Codec
|
||||
{
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
|
||||
// use 'Safe' code for Unity because in IL2CPP gots strange behaviour.
|
||||
|
||||
public static int Encode(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, int outputLength)
|
||||
{
|
||||
if (IntPtr.Size == 4)
|
||||
{
|
||||
return LZ4Codec.Encode32Safe(input, inputOffset, inputLength, output, outputOffset, outputLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
return LZ4Codec.Encode64Safe(input, inputOffset, inputLength, output, outputOffset, outputLength);
|
||||
}
|
||||
}
|
||||
|
||||
public static int Decode(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, int outputLength)
|
||||
{
|
||||
if (IntPtr.Size == 4)
|
||||
{
|
||||
return LZ4Codec.Decode32Safe(input, inputOffset, inputLength, output, outputOffset, outputLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
return LZ4Codec.Decode64Safe(input, inputOffset, inputLength, output, outputOffset, outputLength);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
internal static class HashTablePool
|
||||
{
|
||||
[ThreadStatic]
|
||||
private static ushort[] ushortPool;
|
||||
|
||||
[ThreadStatic]
|
||||
private static uint[] uintPool;
|
||||
|
||||
[ThreadStatic]
|
||||
private static int[] intPool;
|
||||
|
||||
public static ushort[] GetUShortHashTablePool()
|
||||
{
|
||||
if (ushortPool == null)
|
||||
{
|
||||
ushortPool = new ushort[HASH64K_TABLESIZE];
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Clear(ushortPool, 0, ushortPool.Length);
|
||||
}
|
||||
|
||||
return ushortPool;
|
||||
}
|
||||
|
||||
public static uint[] GetUIntHashTablePool()
|
||||
{
|
||||
if (uintPool == null)
|
||||
{
|
||||
uintPool = new uint[HASH_TABLESIZE];
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Clear(uintPool, 0, uintPool.Length);
|
||||
}
|
||||
|
||||
return uintPool;
|
||||
}
|
||||
|
||||
public static int[] GetIntHashTablePool()
|
||||
{
|
||||
if (intPool == null)
|
||||
{
|
||||
intPool = new int[HASH_TABLESIZE];
|
||||
}
|
||||
else
|
||||
{
|
||||
Array.Clear(intPool, 0, intPool.Length);
|
||||
}
|
||||
|
||||
return intPool;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f33bc878911a8855d8df41dd514c5a42
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,467 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
|
||||
#region license
|
||||
|
||||
/*
|
||||
Copyright (c) 2013, Milosz Krajewski
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided
|
||||
that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions
|
||||
and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions
|
||||
and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace MessagePack.LZ4
|
||||
{
|
||||
/// <summary>Safe LZ4 codec.</summary>
|
||||
internal partial class LZ4Codec
|
||||
{
|
||||
#region Helper
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
private static void Assert(bool condition, string errorMessage)
|
||||
{
|
||||
if (!condition)
|
||||
{
|
||||
throw new ArgumentException(errorMessage);
|
||||
}
|
||||
|
||||
Debug.Assert(condition, errorMessage);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Byte manipulation
|
||||
|
||||
internal static void Poke2(byte[] buffer, int offset, ushort value)
|
||||
{
|
||||
buffer[offset] = (byte)value;
|
||||
buffer[offset + 1] = (byte)(value >> 8);
|
||||
}
|
||||
|
||||
internal static ushort Peek2(byte[] buffer, int offset)
|
||||
{
|
||||
// NOTE: It's faster than BitConverter.ToUInt16 (suprised? me too)
|
||||
return (ushort)(((uint)buffer[offset]) | ((uint)buffer[offset + 1] << 8));
|
||||
}
|
||||
|
||||
internal static uint Peek4(byte[] buffer, int offset)
|
||||
{
|
||||
// NOTE: It's faster than BitConverter.ToUInt32 (suprised? me too)
|
||||
return
|
||||
((uint)buffer[offset]) |
|
||||
((uint)buffer[offset + 1] << 8) |
|
||||
((uint)buffer[offset + 2] << 16) |
|
||||
((uint)buffer[offset + 3] << 24);
|
||||
}
|
||||
|
||||
private static uint Xor4(byte[] buffer, int offset1, int offset2)
|
||||
{
|
||||
// return Peek4(buffer, offset1) ^ Peek4(buffer, offset2);
|
||||
var value1 =
|
||||
((uint)buffer[offset1]) |
|
||||
((uint)buffer[offset1 + 1] << 8) |
|
||||
((uint)buffer[offset1 + 2] << 16) |
|
||||
((uint)buffer[offset1 + 3] << 24);
|
||||
var value2 =
|
||||
((uint)buffer[offset2]) |
|
||||
((uint)buffer[offset2 + 1] << 8) |
|
||||
((uint)buffer[offset2 + 2] << 16) |
|
||||
((uint)buffer[offset2 + 3] << 24);
|
||||
return value1 ^ value2;
|
||||
}
|
||||
|
||||
private static ulong Xor8(byte[] buffer, int offset1, int offset2)
|
||||
{
|
||||
// return Peek8(buffer, offset1) ^ Peek8(buffer, offset2);
|
||||
var value1 =
|
||||
((ulong)buffer[offset1]) |
|
||||
((ulong)buffer[offset1 + 1] << 8) |
|
||||
((ulong)buffer[offset1 + 2] << 16) |
|
||||
((ulong)buffer[offset1 + 3] << 24) |
|
||||
((ulong)buffer[offset1 + 4] << 32) |
|
||||
((ulong)buffer[offset1 + 5] << 40) |
|
||||
((ulong)buffer[offset1 + 6] << 48) |
|
||||
((ulong)buffer[offset1 + 7] << 56);
|
||||
var value2 =
|
||||
((ulong)buffer[offset2]) |
|
||||
((ulong)buffer[offset2 + 1] << 8) |
|
||||
((ulong)buffer[offset2 + 2] << 16) |
|
||||
((ulong)buffer[offset2 + 3] << 24) |
|
||||
((ulong)buffer[offset2 + 4] << 32) |
|
||||
((ulong)buffer[offset2 + 5] << 40) |
|
||||
((ulong)buffer[offset2 + 6] << 48) |
|
||||
((ulong)buffer[offset2 + 7] << 56);
|
||||
return value1 ^ value2;
|
||||
}
|
||||
|
||||
private static bool Equal2(byte[] buffer, int offset1, int offset2)
|
||||
{
|
||||
// return Peek2(buffer, offset1) == Peek2(buffer, offset2);
|
||||
if (buffer[offset1] != buffer[offset2])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return buffer[offset1 + 1] == buffer[offset2 + 1];
|
||||
}
|
||||
|
||||
private static bool Equal4(byte[] buffer, int offset1, int offset2)
|
||||
{
|
||||
// return Peek4(buffer, offset1) == Peek4(buffer, offset2);
|
||||
if (buffer[offset1] != buffer[offset2])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buffer[offset1 + 1] != buffer[offset2 + 1])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (buffer[offset1 + 2] != buffer[offset2 + 2])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return buffer[offset1 + 3] == buffer[offset2 + 3];
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Byte block copy
|
||||
|
||||
private static void Copy4(byte[] buf, int src, int dst)
|
||||
{
|
||||
Assert(dst > src, "Copying backwards is not implemented");
|
||||
buf[dst + 3] = buf[src + 3];
|
||||
buf[dst + 2] = buf[src + 2];
|
||||
buf[dst + 1] = buf[src + 1];
|
||||
buf[dst] = buf[src];
|
||||
}
|
||||
|
||||
private static void Copy8(byte[] buf, int src, int dst)
|
||||
{
|
||||
Assert(dst > src, "Copying backwards is not implemented");
|
||||
buf[dst + 7] = buf[src + 7];
|
||||
buf[dst + 6] = buf[src + 6];
|
||||
buf[dst + 5] = buf[src + 5];
|
||||
buf[dst + 4] = buf[src + 4];
|
||||
buf[dst + 3] = buf[src + 3];
|
||||
buf[dst + 2] = buf[src + 2];
|
||||
buf[dst + 1] = buf[src + 1];
|
||||
buf[dst] = buf[src];
|
||||
}
|
||||
|
||||
private static void BlockCopy(byte[] src, int src_0, byte[] dst, int dst_0, int len)
|
||||
{
|
||||
Assert(src != dst, "BlockCopy does not handle copying to the same buffer");
|
||||
|
||||
if (len >= BLOCK_COPY_LIMIT)
|
||||
{
|
||||
Buffer.BlockCopy(src, src_0, dst, dst_0, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (len >= 8)
|
||||
{
|
||||
dst[dst_0] = src[src_0];
|
||||
dst[dst_0 + 1] = src[src_0 + 1];
|
||||
dst[dst_0 + 2] = src[src_0 + 2];
|
||||
dst[dst_0 + 3] = src[src_0 + 3];
|
||||
dst[dst_0 + 4] = src[src_0 + 4];
|
||||
dst[dst_0 + 5] = src[src_0 + 5];
|
||||
dst[dst_0 + 6] = src[src_0 + 6];
|
||||
dst[dst_0 + 7] = src[src_0 + 7];
|
||||
len -= 8;
|
||||
src_0 += 8;
|
||||
dst_0 += 8;
|
||||
}
|
||||
|
||||
while (len >= 4)
|
||||
{
|
||||
dst[dst_0] = src[src_0];
|
||||
dst[dst_0 + 1] = src[src_0 + 1];
|
||||
dst[dst_0 + 2] = src[src_0 + 2];
|
||||
dst[dst_0 + 3] = src[src_0 + 3];
|
||||
len -= 4;
|
||||
src_0 += 4;
|
||||
dst_0 += 4;
|
||||
}
|
||||
|
||||
while (len-- > 0)
|
||||
{
|
||||
dst[dst_0++] = src[src_0++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int WildCopy(byte[] src, int src_0, byte[] dst, int dst_0, int dst_end)
|
||||
{
|
||||
var len = dst_end - dst_0;
|
||||
|
||||
Assert(src != dst, "BlockCopy does not handle copying to the same buffer");
|
||||
Assert(len > 0, "Length have to be greater than 0");
|
||||
|
||||
if (len >= BLOCK_COPY_LIMIT)
|
||||
{
|
||||
Buffer.BlockCopy(src, src_0, dst, dst_0, len);
|
||||
}
|
||||
else
|
||||
{
|
||||
// apparently (tested) this is an overkill
|
||||
// it seems to be faster without this 8-byte loop
|
||||
////while (len >= 8)
|
||||
////{
|
||||
//// dst[dst_0] = src[src_0];
|
||||
//// dst[dst_0 + 1] = src[src_0 + 1];
|
||||
//// dst[dst_0 + 2] = src[src_0 + 2];
|
||||
//// dst[dst_0 + 3] = src[src_0 + 3];
|
||||
//// dst[dst_0 + 4] = src[src_0 + 4];
|
||||
//// dst[dst_0 + 5] = src[src_0 + 5];
|
||||
//// dst[dst_0 + 6] = src[src_0 + 6];
|
||||
//// dst[dst_0 + 7] = src[src_0 + 7];
|
||||
//// len -= 8; src_0 += 8; dst_0 += 8;
|
||||
////}
|
||||
|
||||
while (len >= 4)
|
||||
{
|
||||
dst[dst_0] = src[src_0];
|
||||
dst[dst_0 + 1] = src[src_0 + 1];
|
||||
dst[dst_0 + 2] = src[src_0 + 2];
|
||||
dst[dst_0 + 3] = src[src_0 + 3];
|
||||
len -= 4;
|
||||
src_0 += 4;
|
||||
dst_0 += 4;
|
||||
}
|
||||
|
||||
while (len-- > 0)
|
||||
{
|
||||
dst[dst_0++] = src[src_0++];
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
private static int SecureCopy(byte[] buffer, int src, int dst, int dst_end)
|
||||
{
|
||||
var diff = dst - src;
|
||||
var length = dst_end - dst;
|
||||
var len = length;
|
||||
|
||||
Assert(diff >= 4, "Target must be at least 4 bytes further than source");
|
||||
Assert(BLOCK_COPY_LIMIT > 4, "This method requires BLOCK_COPY_LIMIT > 4");
|
||||
Assert(len > 0, "Length have to be greater than 0");
|
||||
|
||||
if (diff >= BLOCK_COPY_LIMIT)
|
||||
{
|
||||
if (diff >= length)
|
||||
{
|
||||
Buffer.BlockCopy(buffer, src, buffer, dst, length);
|
||||
return length; // done
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
Buffer.BlockCopy(buffer, src, buffer, dst, diff);
|
||||
src += diff;
|
||||
dst += diff;
|
||||
len -= diff;
|
||||
}
|
||||
while (len >= diff);
|
||||
}
|
||||
|
||||
// apparently (tested) this is an overkill
|
||||
// it seems to be faster without this 8-byte loop
|
||||
////while (len >= 8)
|
||||
////{
|
||||
//// buffer[dst] = buffer[src];
|
||||
//// buffer[dst + 1] = buffer[src + 1];
|
||||
//// buffer[dst + 2] = buffer[src + 2];
|
||||
//// buffer[dst + 3] = buffer[src + 3];
|
||||
//// buffer[dst + 4] = buffer[src + 4];
|
||||
//// buffer[dst + 5] = buffer[src + 5];
|
||||
//// buffer[dst + 6] = buffer[src + 6];
|
||||
//// buffer[dst + 7] = buffer[src + 7];
|
||||
//// dst += 8; src += 8; len -= 8;
|
||||
////}
|
||||
|
||||
while (len >= 4)
|
||||
{
|
||||
buffer[dst] = buffer[src];
|
||||
buffer[dst + 1] = buffer[src + 1];
|
||||
buffer[dst + 2] = buffer[src + 2];
|
||||
buffer[dst + 3] = buffer[src + 3];
|
||||
dst += 4;
|
||||
src += 4;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
while (len-- > 0)
|
||||
{
|
||||
buffer[dst++] = buffer[src++];
|
||||
}
|
||||
|
||||
return length; // done
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>Encodes the specified input.</summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="inputOffset">The input offset.</param>
|
||||
/// <param name="inputLength">Length of the input.</param>
|
||||
/// <param name="output">The output.</param>
|
||||
/// <param name="outputOffset">The output offset.</param>
|
||||
/// <param name="outputLength">Length of the output.</param>
|
||||
/// <returns>Number of bytes written.</returns>
|
||||
public static int Encode32Safe(
|
||||
byte[] input,
|
||||
int inputOffset,
|
||||
int inputLength,
|
||||
byte[] output,
|
||||
int outputOffset,
|
||||
int outputLength)
|
||||
{
|
||||
CheckArguments(input, inputOffset, inputLength, output, outputOffset, outputLength);
|
||||
if (outputLength == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (inputLength < LZ4_64KLIMIT)
|
||||
{
|
||||
var hashTable = HashTablePool.GetUShortHashTablePool();
|
||||
return LZ4_compress64kCtx_safe32(hashTable, input, output, inputOffset, outputOffset, inputLength, outputLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
var hashTable = HashTablePool.GetIntHashTablePool();
|
||||
return LZ4_compressCtx_safe32(hashTable, input, output, inputOffset, outputOffset, inputLength, outputLength);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Encodes the specified input.</summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="inputOffset">The input offset.</param>
|
||||
/// <param name="inputLength">Length of the input.</param>
|
||||
/// <param name="output">The output.</param>
|
||||
/// <param name="outputOffset">The output offset.</param>
|
||||
/// <param name="outputLength">Length of the output.</param>
|
||||
/// <returns>Number of bytes written.</returns>
|
||||
public static int Encode64Safe(
|
||||
byte[] input,
|
||||
int inputOffset,
|
||||
int inputLength,
|
||||
byte[] output,
|
||||
int outputOffset,
|
||||
int outputLength)
|
||||
{
|
||||
CheckArguments(input, inputOffset, inputLength, output, outputOffset, outputLength);
|
||||
if (outputLength == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (inputLength < LZ4_64KLIMIT)
|
||||
{
|
||||
var hashTable = HashTablePool.GetUShortHashTablePool();
|
||||
return LZ4_compress64kCtx_safe64(hashTable, input, output, inputOffset, outputOffset, inputLength, outputLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
var hashTable = HashTablePool.GetIntHashTablePool();
|
||||
return LZ4_compressCtx_safe64(hashTable, input, output, inputOffset, outputOffset, inputLength, outputLength);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Decodes the specified input.</summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="inputOffset">The input offset.</param>
|
||||
/// <param name="inputLength">Length of the input.</param>
|
||||
/// <param name="output">The output.</param>
|
||||
/// <param name="outputOffset">The output offset.</param>
|
||||
/// <param name="outputLength">Length of the output.</param>
|
||||
/// <returns>Number of bytes written.</returns>
|
||||
public static int Decode32Safe(
|
||||
byte[] input,
|
||||
int inputOffset,
|
||||
int inputLength,
|
||||
byte[] output,
|
||||
int outputOffset,
|
||||
int outputLength)
|
||||
{
|
||||
CheckArguments(input, inputOffset, inputLength, output, outputOffset, outputLength);
|
||||
|
||||
if (outputLength == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var length = LZ4_uncompress_safe32(input, output, inputOffset, outputOffset, outputLength);
|
||||
if (length != inputLength)
|
||||
{
|
||||
throw new MessagePackSerializationException("LZ4 block is corrupted, or invalid length has been given.");
|
||||
}
|
||||
|
||||
return outputLength;
|
||||
}
|
||||
|
||||
/// <summary>Decodes the specified input.</summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="inputOffset">The input offset.</param>
|
||||
/// <param name="inputLength">Length of the input.</param>
|
||||
/// <param name="output">The output.</param>
|
||||
/// <param name="outputOffset">The output offset.</param>
|
||||
/// <param name="outputLength">Length of the output.</param>
|
||||
/// <returns>Number of bytes written.</returns>
|
||||
public static int Decode64Safe(
|
||||
byte[] input,
|
||||
int inputOffset,
|
||||
int inputLength,
|
||||
byte[] output,
|
||||
int outputOffset,
|
||||
int outputLength)
|
||||
{
|
||||
CheckArguments(input, inputOffset, inputLength, output, outputOffset, outputLength);
|
||||
|
||||
if (outputLength == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var length = LZ4_uncompress_safe64(input, output, inputOffset, outputOffset, outputLength);
|
||||
if (length != inputLength)
|
||||
{
|
||||
throw new MessagePackSerializationException("LZ4 block is corrupted, or invalid length has been given.");
|
||||
}
|
||||
|
||||
return outputLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5fe9256cf4f62c6df8c144caef0ebc6a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,753 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
|
||||
#region LZ4 original
|
||||
|
||||
/*
|
||||
LZ4 - Fast LZ compression algorithm
|
||||
Copyright (C) 2011-2012, Yann Collet.
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#region LZ4 port
|
||||
|
||||
/*
|
||||
Copyright (c) 2013, Milosz Krajewski
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided
|
||||
that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions
|
||||
and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions
|
||||
and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#pragma warning disable SA1312 // Variable names should begin with lower-case letter
|
||||
|
||||
namespace MessagePack.LZ4
|
||||
{
|
||||
internal partial class LZ4Codec
|
||||
{
|
||||
#region LZ4_compressCtx
|
||||
|
||||
private static int LZ4_compressCtx_safe32(
|
||||
int[] hash_table,
|
||||
byte[] src,
|
||||
byte[] dst,
|
||||
int src_0,
|
||||
int dst_0,
|
||||
int src_len,
|
||||
int dst_maxlen)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var debruijn32 = DEBRUIJN_TABLE_32;
|
||||
int _i;
|
||||
|
||||
// ---- preprocessed source start here ----
|
||||
// r93
|
||||
var src_p = src_0;
|
||||
var src_base = src_0;
|
||||
var src_anchor = src_p;
|
||||
var src_end = src_p + src_len;
|
||||
var src_mflimit = src_end - MFLIMIT;
|
||||
|
||||
var dst_p = dst_0;
|
||||
var dst_end = dst_p + dst_maxlen;
|
||||
|
||||
var src_LASTLITERALS = src_end - LASTLITERALS;
|
||||
var src_LASTLITERALS_1 = src_LASTLITERALS - 1;
|
||||
|
||||
var src_LASTLITERALS_STEPSIZE_1 = src_LASTLITERALS - (STEPSIZE_32 - 1);
|
||||
var dst_LASTLITERALS_1 = dst_end - (1 + LASTLITERALS);
|
||||
var dst_LASTLITERALS_3 = dst_end - (2 + 1 + LASTLITERALS);
|
||||
|
||||
int length;
|
||||
|
||||
uint h, h_fwd;
|
||||
|
||||
// Init
|
||||
if (src_len < MINLENGTH)
|
||||
{
|
||||
goto _last_literals;
|
||||
}
|
||||
|
||||
// First Byte
|
||||
hash_table[(Peek4(src, src_p) * 2654435761u) >> HASH_ADJUST] = src_p - src_base;
|
||||
src_p++;
|
||||
h_fwd = (Peek4(src, src_p) * 2654435761u) >> HASH_ADJUST;
|
||||
|
||||
// Main Loop
|
||||
while (true)
|
||||
{
|
||||
var findMatchAttempts = (1 << SKIPSTRENGTH) + 3;
|
||||
var src_p_fwd = src_p;
|
||||
int src_ref;
|
||||
int dst_token;
|
||||
|
||||
// Find a match
|
||||
do
|
||||
{
|
||||
h = h_fwd;
|
||||
var step = findMatchAttempts++ >> SKIPSTRENGTH;
|
||||
src_p = src_p_fwd;
|
||||
src_p_fwd = src_p + step;
|
||||
|
||||
if (src_p_fwd > src_mflimit)
|
||||
{
|
||||
goto _last_literals;
|
||||
}
|
||||
|
||||
h_fwd = (Peek4(src, src_p_fwd) * 2654435761u) >> HASH_ADJUST;
|
||||
src_ref = src_base + hash_table[h];
|
||||
hash_table[h] = src_p - src_base;
|
||||
}
|
||||
while ((src_ref < src_p - MAX_DISTANCE) || (!Equal4(src, src_ref, src_p)));
|
||||
|
||||
// Catch up
|
||||
while ((src_p > src_anchor) && (src_ref > src_0) && (src[src_p - 1] == src[src_ref - 1]))
|
||||
{
|
||||
src_p--;
|
||||
src_ref--;
|
||||
}
|
||||
|
||||
// Encode Literal length
|
||||
length = src_p - src_anchor;
|
||||
dst_token = dst_p++;
|
||||
|
||||
if (dst_p + length + (length >> 8) > dst_LASTLITERALS_3)
|
||||
{
|
||||
return 0; // Check output limit
|
||||
}
|
||||
|
||||
if (length >= RUN_MASK)
|
||||
{
|
||||
var len = length - RUN_MASK;
|
||||
dst[dst_token] = RUN_MASK << ML_BITS;
|
||||
if (len > 254)
|
||||
{
|
||||
do
|
||||
{
|
||||
dst[dst_p++] = 255;
|
||||
len -= 255;
|
||||
}
|
||||
while (len > 254);
|
||||
dst[dst_p++] = (byte)len;
|
||||
BlockCopy(src, src_anchor, dst, dst_p, length);
|
||||
dst_p += length;
|
||||
goto _next_match;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[dst_p++] = (byte)len;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[dst_token] = (byte)(length << ML_BITS);
|
||||
}
|
||||
|
||||
// Copy Literals
|
||||
if (length > 0)
|
||||
{
|
||||
_i = dst_p + length;
|
||||
WildCopy(src, src_anchor, dst, dst_p, _i);
|
||||
dst_p = _i;
|
||||
}
|
||||
|
||||
_next_match:
|
||||
|
||||
// Encode Offset
|
||||
Poke2(dst, dst_p, (ushort)(src_p - src_ref));
|
||||
dst_p += 2;
|
||||
|
||||
// Start Counting
|
||||
src_p += MINMATCH;
|
||||
src_ref += MINMATCH; // MinMatch already verified
|
||||
src_anchor = src_p;
|
||||
|
||||
while (src_p < src_LASTLITERALS_STEPSIZE_1)
|
||||
{
|
||||
var diff = (int)Xor4(src, src_ref, src_p);
|
||||
if (diff == 0)
|
||||
{
|
||||
src_p += STEPSIZE_32;
|
||||
src_ref += STEPSIZE_32;
|
||||
continue;
|
||||
}
|
||||
|
||||
src_p += debruijn32[((uint)(diff & -diff) * 0x077CB531u) >> 27];
|
||||
goto _endCount;
|
||||
}
|
||||
|
||||
if ((src_p < src_LASTLITERALS_1) && Equal2(src, src_ref, src_p))
|
||||
{
|
||||
src_p += 2;
|
||||
src_ref += 2;
|
||||
}
|
||||
|
||||
if ((src_p < src_LASTLITERALS) && (src[src_ref] == src[src_p]))
|
||||
{
|
||||
src_p++;
|
||||
}
|
||||
|
||||
_endCount:
|
||||
|
||||
// Encode MatchLength
|
||||
length = src_p - src_anchor;
|
||||
|
||||
if (dst_p + (length >> 8) > dst_LASTLITERALS_1)
|
||||
{
|
||||
return 0; // Check output limit
|
||||
}
|
||||
|
||||
if (length >= ML_MASK)
|
||||
{
|
||||
dst[dst_token] += ML_MASK;
|
||||
length -= ML_MASK;
|
||||
for (; length > 509; length -= 510)
|
||||
{
|
||||
dst[dst_p++] = 255;
|
||||
dst[dst_p++] = 255;
|
||||
}
|
||||
|
||||
if (length > 254)
|
||||
{
|
||||
length -= 255;
|
||||
dst[dst_p++] = 255;
|
||||
}
|
||||
|
||||
dst[dst_p++] = (byte)length;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[dst_token] += (byte)length;
|
||||
}
|
||||
|
||||
// Test end of chunk
|
||||
if (src_p > src_mflimit)
|
||||
{
|
||||
src_anchor = src_p;
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill table
|
||||
hash_table[(Peek4(src, src_p - 2) * 2654435761u) >> HASH_ADJUST] = src_p - 2 - src_base;
|
||||
|
||||
// Test next position
|
||||
h = (Peek4(src, src_p) * 2654435761u) >> HASH_ADJUST;
|
||||
src_ref = src_base + hash_table[h];
|
||||
hash_table[h] = src_p - src_base;
|
||||
|
||||
if ((src_ref > src_p - (MAX_DISTANCE + 1)) && Equal4(src, src_ref, src_p))
|
||||
{
|
||||
dst_token = dst_p++;
|
||||
dst[dst_token] = 0;
|
||||
goto _next_match;
|
||||
}
|
||||
|
||||
// Prepare next loop
|
||||
src_anchor = src_p++;
|
||||
h_fwd = (Peek4(src, src_p) * 2654435761u) >> HASH_ADJUST;
|
||||
}
|
||||
|
||||
_last_literals:
|
||||
|
||||
// Encode Last Literals
|
||||
{
|
||||
var lastRun = src_end - src_anchor;
|
||||
|
||||
if (dst_p + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > dst_end)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lastRun >= RUN_MASK)
|
||||
{
|
||||
dst[dst_p++] = RUN_MASK << ML_BITS;
|
||||
lastRun -= RUN_MASK;
|
||||
for (; lastRun > 254; lastRun -= 255)
|
||||
{
|
||||
dst[dst_p++] = 255;
|
||||
}
|
||||
|
||||
dst[dst_p++] = (byte)lastRun;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[dst_p++] = (byte)(lastRun << ML_BITS);
|
||||
}
|
||||
|
||||
BlockCopy(src, src_anchor, dst, dst_p, src_end - src_anchor);
|
||||
dst_p += src_end - src_anchor;
|
||||
}
|
||||
|
||||
// End
|
||||
return dst_p - dst_0;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LZ4_compress64kCtx
|
||||
|
||||
private static int LZ4_compress64kCtx_safe32(
|
||||
ushort[] hash_table,
|
||||
byte[] src,
|
||||
byte[] dst,
|
||||
int src_0,
|
||||
int dst_0,
|
||||
int src_len,
|
||||
int dst_maxlen)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var debruijn32 = DEBRUIJN_TABLE_32;
|
||||
int _i;
|
||||
|
||||
// ---- preprocessed source start here ----
|
||||
// r93
|
||||
var src_p = src_0;
|
||||
var src_anchor = src_p;
|
||||
var src_base = src_p;
|
||||
var src_end = src_p + src_len;
|
||||
var src_mflimit = src_end - MFLIMIT;
|
||||
|
||||
var dst_p = dst_0;
|
||||
var dst_end = dst_p + dst_maxlen;
|
||||
|
||||
var src_LASTLITERALS = src_end - LASTLITERALS;
|
||||
var src_LASTLITERALS_1 = src_LASTLITERALS - 1;
|
||||
|
||||
var src_LASTLITERALS_STEPSIZE_1 = src_LASTLITERALS - (STEPSIZE_32 - 1);
|
||||
var dst_LASTLITERALS_1 = dst_end - (1 + LASTLITERALS);
|
||||
var dst_LASTLITERALS_3 = dst_end - (2 + 1 + LASTLITERALS);
|
||||
|
||||
int len, length;
|
||||
|
||||
uint h, h_fwd;
|
||||
|
||||
// Init
|
||||
if (src_len < MINLENGTH)
|
||||
{
|
||||
goto _last_literals;
|
||||
}
|
||||
|
||||
// First Byte
|
||||
src_p++;
|
||||
h_fwd = (Peek4(src, src_p) * 2654435761u) >> HASH64K_ADJUST;
|
||||
|
||||
// Main Loop
|
||||
while (true)
|
||||
{
|
||||
var findMatchAttempts = (1 << SKIPSTRENGTH) + 3;
|
||||
var src_p_fwd = src_p;
|
||||
int src_ref;
|
||||
int dst_token;
|
||||
|
||||
// Find a match
|
||||
do
|
||||
{
|
||||
h = h_fwd;
|
||||
var step = findMatchAttempts++ >> SKIPSTRENGTH;
|
||||
src_p = src_p_fwd;
|
||||
src_p_fwd = src_p + step;
|
||||
|
||||
if (src_p_fwd > src_mflimit)
|
||||
{
|
||||
goto _last_literals;
|
||||
}
|
||||
|
||||
h_fwd = (Peek4(src, src_p_fwd) * 2654435761u) >> HASH64K_ADJUST;
|
||||
src_ref = src_base + hash_table[h];
|
||||
hash_table[h] = (ushort)(src_p - src_base);
|
||||
}
|
||||
while (!Equal4(src, src_ref, src_p));
|
||||
|
||||
// Catch up
|
||||
while ((src_p > src_anchor) && (src_ref > src_0) && (src[src_p - 1] == src[src_ref - 1]))
|
||||
{
|
||||
src_p--;
|
||||
src_ref--;
|
||||
}
|
||||
|
||||
// Encode Literal length
|
||||
length = src_p - src_anchor;
|
||||
dst_token = dst_p++;
|
||||
|
||||
if (dst_p + length + (length >> 8) > dst_LASTLITERALS_3)
|
||||
{
|
||||
return 0; // Check output limit
|
||||
}
|
||||
|
||||
if (length >= RUN_MASK)
|
||||
{
|
||||
len = length - RUN_MASK;
|
||||
dst[dst_token] = RUN_MASK << ML_BITS;
|
||||
if (len > 254)
|
||||
{
|
||||
do
|
||||
{
|
||||
dst[dst_p++] = 255;
|
||||
len -= 255;
|
||||
}
|
||||
while (len > 254);
|
||||
dst[dst_p++] = (byte)len;
|
||||
BlockCopy(src, src_anchor, dst, dst_p, length);
|
||||
dst_p += length;
|
||||
goto _next_match;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[dst_p++] = (byte)len;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[dst_token] = (byte)(length << ML_BITS);
|
||||
}
|
||||
|
||||
// Copy Literals
|
||||
if (length > 0)
|
||||
{
|
||||
_i = dst_p + length;
|
||||
WildCopy(src, src_anchor, dst, dst_p, _i);
|
||||
dst_p = _i;
|
||||
}
|
||||
|
||||
_next_match:
|
||||
|
||||
// Encode Offset
|
||||
Poke2(dst, dst_p, (ushort)(src_p - src_ref));
|
||||
dst_p += 2;
|
||||
|
||||
// Start Counting
|
||||
src_p += MINMATCH;
|
||||
src_ref += MINMATCH; // MinMatch verified
|
||||
src_anchor = src_p;
|
||||
|
||||
while (src_p < src_LASTLITERALS_STEPSIZE_1)
|
||||
{
|
||||
var diff = (int)Xor4(src, src_ref, src_p);
|
||||
if (diff == 0)
|
||||
{
|
||||
src_p += STEPSIZE_32;
|
||||
src_ref += STEPSIZE_32;
|
||||
continue;
|
||||
}
|
||||
|
||||
src_p += debruijn32[((uint)(diff & -diff) * 0x077CB531u) >> 27];
|
||||
goto _endCount;
|
||||
}
|
||||
|
||||
if ((src_p < src_LASTLITERALS_1) && Equal2(src, src_ref, src_p))
|
||||
{
|
||||
src_p += 2;
|
||||
src_ref += 2;
|
||||
}
|
||||
|
||||
if ((src_p < src_LASTLITERALS) && (src[src_ref] == src[src_p]))
|
||||
{
|
||||
src_p++;
|
||||
}
|
||||
|
||||
_endCount:
|
||||
|
||||
// Encode MatchLength
|
||||
len = src_p - src_anchor;
|
||||
|
||||
if (dst_p + (len >> 8) > dst_LASTLITERALS_1)
|
||||
{
|
||||
return 0; // Check output limit
|
||||
}
|
||||
|
||||
if (len >= ML_MASK)
|
||||
{
|
||||
dst[dst_token] += ML_MASK;
|
||||
len -= ML_MASK;
|
||||
for (; len > 509; len -= 510)
|
||||
{
|
||||
dst[dst_p++] = 255;
|
||||
dst[dst_p++] = 255;
|
||||
}
|
||||
|
||||
if (len > 254)
|
||||
{
|
||||
len -= 255;
|
||||
dst[dst_p++] = 255;
|
||||
}
|
||||
|
||||
dst[dst_p++] = (byte)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[dst_token] += (byte)len;
|
||||
}
|
||||
|
||||
// Test end of chunk
|
||||
if (src_p > src_mflimit)
|
||||
{
|
||||
src_anchor = src_p;
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill table
|
||||
hash_table[(Peek4(src, src_p - 2) * 2654435761u) >> HASH64K_ADJUST] = (ushort)(src_p - 2 - src_base);
|
||||
|
||||
// Test next position
|
||||
h = (Peek4(src, src_p) * 2654435761u) >> HASH64K_ADJUST;
|
||||
src_ref = src_base + hash_table[h];
|
||||
hash_table[h] = (ushort)(src_p - src_base);
|
||||
|
||||
if (Equal4(src, src_ref, src_p))
|
||||
{
|
||||
dst_token = dst_p++;
|
||||
dst[dst_token] = 0;
|
||||
goto _next_match;
|
||||
}
|
||||
|
||||
// Prepare next loop
|
||||
src_anchor = src_p++;
|
||||
h_fwd = (Peek4(src, src_p) * 2654435761u) >> HASH64K_ADJUST;
|
||||
}
|
||||
|
||||
_last_literals:
|
||||
|
||||
// Encode Last Literals
|
||||
var lastRun = src_end - src_anchor;
|
||||
if (dst_p + lastRun + 1 + ((lastRun - RUN_MASK + 255) / 255) > dst_end)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lastRun >= RUN_MASK)
|
||||
{
|
||||
dst[dst_p++] = RUN_MASK << ML_BITS;
|
||||
lastRun -= RUN_MASK;
|
||||
for (; lastRun > 254; lastRun -= 255)
|
||||
{
|
||||
dst[dst_p++] = 255;
|
||||
}
|
||||
|
||||
dst[dst_p++] = (byte)lastRun;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[dst_p++] = (byte)(lastRun << ML_BITS);
|
||||
}
|
||||
|
||||
BlockCopy(src, src_anchor, dst, dst_p, src_end - src_anchor);
|
||||
dst_p += src_end - src_anchor;
|
||||
|
||||
// End
|
||||
return dst_p - dst_0;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LZ4_uncompress
|
||||
|
||||
private static int LZ4_uncompress_safe32(
|
||||
byte[] src,
|
||||
byte[] dst,
|
||||
int src_0,
|
||||
int dst_0,
|
||||
int dst_len)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var dec32table = DECODER_TABLE_32;
|
||||
int _i;
|
||||
|
||||
// ---- preprocessed source start here ----
|
||||
// r93
|
||||
var src_p = src_0;
|
||||
int dst_ref;
|
||||
|
||||
var dst_p = dst_0;
|
||||
var dst_end = dst_p + dst_len;
|
||||
int dst_cpy;
|
||||
|
||||
var dst_LASTLITERALS = dst_end - LASTLITERALS;
|
||||
var dst_COPYLENGTH = dst_end - COPYLENGTH;
|
||||
var dst_COPYLENGTH_STEPSIZE_4 = dst_end - COPYLENGTH - (STEPSIZE_32 - 4);
|
||||
|
||||
byte token;
|
||||
|
||||
// Main Loop
|
||||
while (true)
|
||||
{
|
||||
int length;
|
||||
|
||||
// get runlength
|
||||
token = src[src_p++];
|
||||
if ((length = token >> ML_BITS) == RUN_MASK)
|
||||
{
|
||||
int len;
|
||||
for (; (len = src[src_p++]) == 255; length += 255)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
length += len;
|
||||
}
|
||||
|
||||
// copy literals
|
||||
dst_cpy = dst_p + length;
|
||||
|
||||
if (dst_cpy > dst_COPYLENGTH)
|
||||
{
|
||||
if (dst_cpy != dst_end)
|
||||
{
|
||||
goto _output_error; // Error : not enough place for another match (min 4) + 5 literals
|
||||
}
|
||||
|
||||
BlockCopy(src, src_p, dst, dst_p, length);
|
||||
src_p += length;
|
||||
break; // EOF
|
||||
}
|
||||
|
||||
if (dst_p < dst_cpy)
|
||||
{
|
||||
_i = WildCopy(src, src_p, dst, dst_p, dst_cpy);
|
||||
src_p += _i;
|
||||
dst_p += _i;
|
||||
}
|
||||
|
||||
src_p -= dst_p - dst_cpy;
|
||||
dst_p = dst_cpy;
|
||||
|
||||
// get offset
|
||||
dst_ref = dst_cpy - Peek2(src, src_p);
|
||||
src_p += 2;
|
||||
if (dst_ref < dst_0)
|
||||
{
|
||||
goto _output_error; // Error : offset outside destination buffer
|
||||
}
|
||||
|
||||
// get matchlength
|
||||
if ((length = token & ML_MASK) == ML_MASK)
|
||||
{
|
||||
for (; src[src_p] == 255; length += 255)
|
||||
{
|
||||
src_p++;
|
||||
}
|
||||
|
||||
length += src[src_p++];
|
||||
}
|
||||
|
||||
// copy repeated sequence
|
||||
if ((dst_p - dst_ref) < STEPSIZE_32)
|
||||
{
|
||||
const int dec64 = 0;
|
||||
dst[dst_p + 0] = dst[dst_ref + 0];
|
||||
dst[dst_p + 1] = dst[dst_ref + 1];
|
||||
dst[dst_p + 2] = dst[dst_ref + 2];
|
||||
dst[dst_p + 3] = dst[dst_ref + 3];
|
||||
dst_p += 4;
|
||||
dst_ref += 4;
|
||||
dst_ref -= dec32table[dst_p - dst_ref];
|
||||
Copy4(dst, dst_ref, dst_p);
|
||||
dst_p += STEPSIZE_32 - 4;
|
||||
dst_ref -= dec64;
|
||||
}
|
||||
else
|
||||
{
|
||||
Copy4(dst, dst_ref, dst_p);
|
||||
dst_p += 4;
|
||||
dst_ref += 4;
|
||||
}
|
||||
|
||||
dst_cpy = dst_p + length - (STEPSIZE_32 - 4);
|
||||
|
||||
if (dst_cpy > dst_COPYLENGTH_STEPSIZE_4)
|
||||
{
|
||||
if (dst_cpy > dst_LASTLITERALS)
|
||||
{
|
||||
goto _output_error; // Error : last 5 bytes must be literals
|
||||
}
|
||||
|
||||
if (dst_p < dst_COPYLENGTH)
|
||||
{
|
||||
_i = SecureCopy(dst, dst_ref, dst_p, dst_COPYLENGTH);
|
||||
dst_ref += _i;
|
||||
dst_p += _i;
|
||||
}
|
||||
|
||||
while (dst_p < dst_cpy)
|
||||
{
|
||||
dst[dst_p++] = dst[dst_ref++];
|
||||
}
|
||||
|
||||
dst_p = dst_cpy;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dst_p < dst_cpy)
|
||||
{
|
||||
SecureCopy(dst, dst_ref, dst_p, dst_cpy);
|
||||
}
|
||||
|
||||
dst_p = dst_cpy; // correction
|
||||
}
|
||||
|
||||
// end of decoding
|
||||
return src_p - src_0;
|
||||
|
||||
// write overflow error detected
|
||||
_output_error:
|
||||
return -(src_p - src_0);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4e76c34fb36d14138b0196dbb3bdc544
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,774 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
|
||||
#region LZ4 original
|
||||
|
||||
/*
|
||||
LZ4 - Fast LZ compression algorithm
|
||||
Copyright (C) 2011-2012, Yann Collet.
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#region LZ4 port
|
||||
|
||||
/*
|
||||
Copyright (c) 2013, Milosz Krajewski
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided
|
||||
that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions
|
||||
and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions
|
||||
and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#pragma warning disable SA1312 // Variable names should begin with lower-case letter
|
||||
|
||||
namespace MessagePack.LZ4
|
||||
{
|
||||
internal partial class LZ4Codec
|
||||
{
|
||||
#region LZ4_compressCtx
|
||||
|
||||
private static int LZ4_compressCtx_safe64(
|
||||
int[] hash_table,
|
||||
byte[] src,
|
||||
byte[] dst,
|
||||
int src_0,
|
||||
int dst_0,
|
||||
int src_len,
|
||||
int dst_maxlen)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var debruijn64 = DEBRUIJN_TABLE_64;
|
||||
int _i;
|
||||
|
||||
// ---- preprocessed source start here ----
|
||||
// r93
|
||||
var src_p = src_0;
|
||||
var src_base = src_0;
|
||||
var src_anchor = src_p;
|
||||
var src_end = src_p + src_len;
|
||||
var src_mflimit = src_end - MFLIMIT;
|
||||
|
||||
var dst_p = dst_0;
|
||||
var dst_end = dst_p + dst_maxlen;
|
||||
|
||||
var src_LASTLITERALS = src_end - LASTLITERALS;
|
||||
var src_LASTLITERALS_1 = src_LASTLITERALS - 1;
|
||||
|
||||
var src_LASTLITERALS_3 = src_LASTLITERALS - 3;
|
||||
|
||||
var src_LASTLITERALS_STEPSIZE_1 = src_LASTLITERALS - (STEPSIZE_64 - 1);
|
||||
var dst_LASTLITERALS_1 = dst_end - (1 + LASTLITERALS);
|
||||
var dst_LASTLITERALS_3 = dst_end - (2 + 1 + LASTLITERALS);
|
||||
|
||||
int length;
|
||||
|
||||
uint h, h_fwd;
|
||||
|
||||
// Init
|
||||
if (src_len < MINLENGTH)
|
||||
{
|
||||
goto _last_literals;
|
||||
}
|
||||
|
||||
// First Byte
|
||||
hash_table[(Peek4(src, src_p) * 2654435761u) >> HASH_ADJUST] = src_p - src_base;
|
||||
src_p++;
|
||||
h_fwd = (Peek4(src, src_p) * 2654435761u) >> HASH_ADJUST;
|
||||
|
||||
// Main Loop
|
||||
while (true)
|
||||
{
|
||||
var findMatchAttempts = (1 << SKIPSTRENGTH) + 3;
|
||||
var src_p_fwd = src_p;
|
||||
int src_ref;
|
||||
int dst_token;
|
||||
|
||||
// Find a match
|
||||
do
|
||||
{
|
||||
h = h_fwd;
|
||||
var step = findMatchAttempts++ >> SKIPSTRENGTH;
|
||||
src_p = src_p_fwd;
|
||||
src_p_fwd = src_p + step;
|
||||
|
||||
if (src_p_fwd > src_mflimit)
|
||||
{
|
||||
goto _last_literals;
|
||||
}
|
||||
|
||||
h_fwd = (Peek4(src, src_p_fwd) * 2654435761u) >> HASH_ADJUST;
|
||||
src_ref = src_base + hash_table[h];
|
||||
hash_table[h] = src_p - src_base;
|
||||
}
|
||||
while ((src_ref < src_p - MAX_DISTANCE) || (!Equal4(src, src_ref, src_p)));
|
||||
|
||||
// Catch up
|
||||
while ((src_p > src_anchor) && (src_ref > src_0) && (src[src_p - 1] == src[src_ref - 1]))
|
||||
{
|
||||
src_p--;
|
||||
src_ref--;
|
||||
}
|
||||
|
||||
// Encode Literal length
|
||||
length = src_p - src_anchor;
|
||||
dst_token = dst_p++;
|
||||
|
||||
if (dst_p + length + (length >> 8) > dst_LASTLITERALS_3)
|
||||
{
|
||||
return 0; // Check output limit
|
||||
}
|
||||
|
||||
if (length >= RUN_MASK)
|
||||
{
|
||||
var len = length - RUN_MASK;
|
||||
dst[dst_token] = RUN_MASK << ML_BITS;
|
||||
if (len > 254)
|
||||
{
|
||||
do
|
||||
{
|
||||
dst[dst_p++] = 255;
|
||||
len -= 255;
|
||||
}
|
||||
while (len > 254);
|
||||
dst[dst_p++] = (byte)len;
|
||||
BlockCopy(src, src_anchor, dst, dst_p, length);
|
||||
dst_p += length;
|
||||
goto _next_match;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[dst_p++] = (byte)len;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[dst_token] = (byte)(length << ML_BITS);
|
||||
}
|
||||
|
||||
// Copy Literals
|
||||
if (length > 0)
|
||||
{
|
||||
_i = dst_p + length;
|
||||
WildCopy(src, src_anchor, dst, dst_p, _i);
|
||||
dst_p = _i;
|
||||
}
|
||||
|
||||
_next_match:
|
||||
|
||||
// Encode Offset
|
||||
Poke2(dst, dst_p, (ushort)(src_p - src_ref));
|
||||
dst_p += 2;
|
||||
|
||||
// Start Counting
|
||||
src_p += MINMATCH;
|
||||
src_ref += MINMATCH; // MinMatch already verified
|
||||
src_anchor = src_p;
|
||||
|
||||
while (src_p < src_LASTLITERALS_STEPSIZE_1)
|
||||
{
|
||||
var diff = (long)Xor8(src, src_ref, src_p);
|
||||
if (diff == 0)
|
||||
{
|
||||
src_p += STEPSIZE_64;
|
||||
src_ref += STEPSIZE_64;
|
||||
continue;
|
||||
}
|
||||
|
||||
src_p += debruijn64[((ulong)(diff & -diff) * 0x0218A392CDABBD3FL) >> 58];
|
||||
goto _endCount;
|
||||
}
|
||||
|
||||
if ((src_p < src_LASTLITERALS_3) && Equal4(src, src_ref, src_p))
|
||||
{
|
||||
src_p += 4;
|
||||
src_ref += 4;
|
||||
}
|
||||
|
||||
if ((src_p < src_LASTLITERALS_1) && Equal2(src, src_ref, src_p))
|
||||
{
|
||||
src_p += 2;
|
||||
src_ref += 2;
|
||||
}
|
||||
|
||||
if ((src_p < src_LASTLITERALS) && (src[src_ref] == src[src_p]))
|
||||
{
|
||||
src_p++;
|
||||
}
|
||||
|
||||
_endCount:
|
||||
|
||||
// Encode MatchLength
|
||||
length = src_p - src_anchor;
|
||||
|
||||
if (dst_p + (length >> 8) > dst_LASTLITERALS_1)
|
||||
{
|
||||
return 0; // Check output limit
|
||||
}
|
||||
|
||||
if (length >= ML_MASK)
|
||||
{
|
||||
dst[dst_token] += ML_MASK;
|
||||
length -= ML_MASK;
|
||||
for (; length > 509; length -= 510)
|
||||
{
|
||||
dst[dst_p++] = 255;
|
||||
dst[dst_p++] = 255;
|
||||
}
|
||||
|
||||
if (length > 254)
|
||||
{
|
||||
length -= 255;
|
||||
dst[dst_p++] = 255;
|
||||
}
|
||||
|
||||
dst[dst_p++] = (byte)length;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[dst_token] += (byte)length;
|
||||
}
|
||||
|
||||
// Test end of chunk
|
||||
if (src_p > src_mflimit)
|
||||
{
|
||||
src_anchor = src_p;
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill table
|
||||
hash_table[(Peek4(src, src_p - 2) * 2654435761u) >> HASH_ADJUST] = src_p - 2 - src_base;
|
||||
|
||||
// Test next position
|
||||
h = (Peek4(src, src_p) * 2654435761u) >> HASH_ADJUST;
|
||||
src_ref = src_base + hash_table[h];
|
||||
hash_table[h] = src_p - src_base;
|
||||
|
||||
if ((src_ref > src_p - (MAX_DISTANCE + 1)) && Equal4(src, src_ref, src_p))
|
||||
{
|
||||
dst_token = dst_p++;
|
||||
dst[dst_token] = 0;
|
||||
goto _next_match;
|
||||
}
|
||||
|
||||
// Prepare next loop
|
||||
src_anchor = src_p++;
|
||||
h_fwd = (Peek4(src, src_p) * 2654435761u) >> HASH_ADJUST;
|
||||
}
|
||||
|
||||
_last_literals:
|
||||
|
||||
// Encode Last Literals
|
||||
{
|
||||
var lastRun = src_end - src_anchor;
|
||||
|
||||
if (dst_p + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > dst_end)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lastRun >= RUN_MASK)
|
||||
{
|
||||
dst[dst_p++] = RUN_MASK << ML_BITS;
|
||||
lastRun -= RUN_MASK;
|
||||
for (; lastRun > 254; lastRun -= 255)
|
||||
{
|
||||
dst[dst_p++] = 255;
|
||||
}
|
||||
|
||||
dst[dst_p++] = (byte)lastRun;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[dst_p++] = (byte)(lastRun << ML_BITS);
|
||||
}
|
||||
|
||||
BlockCopy(src, src_anchor, dst, dst_p, src_end - src_anchor);
|
||||
dst_p += src_end - src_anchor;
|
||||
}
|
||||
|
||||
// End
|
||||
return dst_p - dst_0;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LZ4_compress64kCtx
|
||||
|
||||
private static int LZ4_compress64kCtx_safe64(
|
||||
ushort[] hash_table,
|
||||
byte[] src,
|
||||
byte[] dst,
|
||||
int src_0,
|
||||
int dst_0,
|
||||
int src_len,
|
||||
int dst_maxlen)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var debruijn64 = DEBRUIJN_TABLE_64;
|
||||
int _i;
|
||||
|
||||
// ---- preprocessed source start here ----
|
||||
// r93
|
||||
var src_p = src_0;
|
||||
var src_anchor = src_p;
|
||||
var src_base = src_p;
|
||||
var src_end = src_p + src_len;
|
||||
var src_mflimit = src_end - MFLIMIT;
|
||||
|
||||
var dst_p = dst_0;
|
||||
var dst_end = dst_p + dst_maxlen;
|
||||
|
||||
var src_LASTLITERALS = src_end - LASTLITERALS;
|
||||
var src_LASTLITERALS_1 = src_LASTLITERALS - 1;
|
||||
|
||||
var src_LASTLITERALS_3 = src_LASTLITERALS - 3;
|
||||
|
||||
var src_LASTLITERALS_STEPSIZE_1 = src_LASTLITERALS - (STEPSIZE_64 - 1);
|
||||
var dst_LASTLITERALS_1 = dst_end - (1 + LASTLITERALS);
|
||||
var dst_LASTLITERALS_3 = dst_end - (2 + 1 + LASTLITERALS);
|
||||
|
||||
int len, length;
|
||||
|
||||
uint h, h_fwd;
|
||||
|
||||
// Init
|
||||
if (src_len < MINLENGTH)
|
||||
{
|
||||
goto _last_literals;
|
||||
}
|
||||
|
||||
// First Byte
|
||||
src_p++;
|
||||
h_fwd = (Peek4(src, src_p) * 2654435761u) >> HASH64K_ADJUST;
|
||||
|
||||
// Main Loop
|
||||
while (true)
|
||||
{
|
||||
var findMatchAttempts = (1 << SKIPSTRENGTH) + 3;
|
||||
var src_p_fwd = src_p;
|
||||
int src_ref;
|
||||
int dst_token;
|
||||
|
||||
// Find a match
|
||||
do
|
||||
{
|
||||
h = h_fwd;
|
||||
var step = findMatchAttempts++ >> SKIPSTRENGTH;
|
||||
src_p = src_p_fwd;
|
||||
src_p_fwd = src_p + step;
|
||||
|
||||
if (src_p_fwd > src_mflimit)
|
||||
{
|
||||
goto _last_literals;
|
||||
}
|
||||
|
||||
h_fwd = (Peek4(src, src_p_fwd) * 2654435761u) >> HASH64K_ADJUST;
|
||||
src_ref = src_base + hash_table[h];
|
||||
hash_table[h] = (ushort)(src_p - src_base);
|
||||
}
|
||||
while (!Equal4(src, src_ref, src_p));
|
||||
|
||||
// Catch up
|
||||
while ((src_p > src_anchor) && (src_ref > src_0) && (src[src_p - 1] == src[src_ref - 1]))
|
||||
{
|
||||
src_p--;
|
||||
src_ref--;
|
||||
}
|
||||
|
||||
// Encode Literal length
|
||||
length = src_p - src_anchor;
|
||||
dst_token = dst_p++;
|
||||
|
||||
if (dst_p + length + (length >> 8) > dst_LASTLITERALS_3)
|
||||
{
|
||||
return 0; // Check output limit
|
||||
}
|
||||
|
||||
if (length >= RUN_MASK)
|
||||
{
|
||||
len = length - RUN_MASK;
|
||||
dst[dst_token] = RUN_MASK << ML_BITS;
|
||||
if (len > 254)
|
||||
{
|
||||
do
|
||||
{
|
||||
dst[dst_p++] = 255;
|
||||
len -= 255;
|
||||
}
|
||||
while (len > 254);
|
||||
dst[dst_p++] = (byte)len;
|
||||
BlockCopy(src, src_anchor, dst, dst_p, length);
|
||||
dst_p += length;
|
||||
goto _next_match;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[dst_p++] = (byte)len;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[dst_token] = (byte)(length << ML_BITS);
|
||||
}
|
||||
|
||||
// Copy Literals
|
||||
if (length > 0)
|
||||
{
|
||||
_i = dst_p + length;
|
||||
WildCopy(src, src_anchor, dst, dst_p, _i);
|
||||
dst_p = _i;
|
||||
}
|
||||
|
||||
_next_match:
|
||||
|
||||
// Encode Offset
|
||||
Poke2(dst, dst_p, (ushort)(src_p - src_ref));
|
||||
dst_p += 2;
|
||||
|
||||
// Start Counting
|
||||
src_p += MINMATCH;
|
||||
src_ref += MINMATCH; // MinMatch verified
|
||||
src_anchor = src_p;
|
||||
|
||||
while (src_p < src_LASTLITERALS_STEPSIZE_1)
|
||||
{
|
||||
var diff = (long)Xor8(src, src_ref, src_p);
|
||||
if (diff == 0)
|
||||
{
|
||||
src_p += STEPSIZE_64;
|
||||
src_ref += STEPSIZE_64;
|
||||
continue;
|
||||
}
|
||||
|
||||
src_p += debruijn64[((ulong)(diff & -diff) * 0x0218A392CDABBD3FL) >> 58];
|
||||
goto _endCount;
|
||||
}
|
||||
|
||||
if ((src_p < src_LASTLITERALS_3) && Equal4(src, src_ref, src_p))
|
||||
{
|
||||
src_p += 4;
|
||||
src_ref += 4;
|
||||
}
|
||||
|
||||
if ((src_p < src_LASTLITERALS_1) && Equal2(src, src_ref, src_p))
|
||||
{
|
||||
src_p += 2;
|
||||
src_ref += 2;
|
||||
}
|
||||
|
||||
if ((src_p < src_LASTLITERALS) && (src[src_ref] == src[src_p]))
|
||||
{
|
||||
src_p++;
|
||||
}
|
||||
|
||||
_endCount:
|
||||
|
||||
// Encode MatchLength
|
||||
len = src_p - src_anchor;
|
||||
|
||||
if (dst_p + (len >> 8) > dst_LASTLITERALS_1)
|
||||
{
|
||||
return 0; // Check output limit
|
||||
}
|
||||
|
||||
if (len >= ML_MASK)
|
||||
{
|
||||
dst[dst_token] += ML_MASK;
|
||||
len -= ML_MASK;
|
||||
for (; len > 509; len -= 510)
|
||||
{
|
||||
dst[dst_p++] = 255;
|
||||
dst[dst_p++] = 255;
|
||||
}
|
||||
|
||||
if (len > 254)
|
||||
{
|
||||
len -= 255;
|
||||
dst[dst_p++] = 255;
|
||||
}
|
||||
|
||||
dst[dst_p++] = (byte)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[dst_token] += (byte)len;
|
||||
}
|
||||
|
||||
// Test end of chunk
|
||||
if (src_p > src_mflimit)
|
||||
{
|
||||
src_anchor = src_p;
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill table
|
||||
hash_table[(Peek4(src, src_p - 2) * 2654435761u) >> HASH64K_ADJUST] = (ushort)(src_p - 2 - src_base);
|
||||
|
||||
// Test next position
|
||||
h = (Peek4(src, src_p) * 2654435761u) >> HASH64K_ADJUST;
|
||||
src_ref = src_base + hash_table[h];
|
||||
hash_table[h] = (ushort)(src_p - src_base);
|
||||
|
||||
if (Equal4(src, src_ref, src_p))
|
||||
{
|
||||
dst_token = dst_p++;
|
||||
dst[dst_token] = 0;
|
||||
goto _next_match;
|
||||
}
|
||||
|
||||
// Prepare next loop
|
||||
src_anchor = src_p++;
|
||||
h_fwd = (Peek4(src, src_p) * 2654435761u) >> HASH64K_ADJUST;
|
||||
}
|
||||
|
||||
_last_literals:
|
||||
|
||||
// Encode Last Literals
|
||||
{
|
||||
var lastRun = src_end - src_anchor;
|
||||
if (dst_p + lastRun + 1 + ((lastRun - RUN_MASK + 255) / 255) > dst_end)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lastRun >= RUN_MASK)
|
||||
{
|
||||
dst[dst_p++] = RUN_MASK << ML_BITS;
|
||||
lastRun -= RUN_MASK;
|
||||
for (; lastRun > 254; lastRun -= 255)
|
||||
{
|
||||
dst[dst_p++] = 255;
|
||||
}
|
||||
|
||||
dst[dst_p++] = (byte)lastRun;
|
||||
}
|
||||
else
|
||||
{
|
||||
dst[dst_p++] = (byte)(lastRun << ML_BITS);
|
||||
}
|
||||
|
||||
BlockCopy(src, src_anchor, dst, dst_p, src_end - src_anchor);
|
||||
dst_p += src_end - src_anchor;
|
||||
}
|
||||
|
||||
// End
|
||||
return dst_p - dst_0;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LZ4_uncompress
|
||||
|
||||
private static int LZ4_uncompress_safe64(
|
||||
byte[] src,
|
||||
byte[] dst,
|
||||
int src_0,
|
||||
int dst_0,
|
||||
int dst_len)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
var dec32table = DECODER_TABLE_32;
|
||||
var dec64table = DECODER_TABLE_64;
|
||||
int _i;
|
||||
|
||||
// ---- preprocessed source start here ----
|
||||
// r93
|
||||
var src_p = src_0;
|
||||
int dst_ref;
|
||||
|
||||
var dst_p = dst_0;
|
||||
var dst_end = dst_p + dst_len;
|
||||
int dst_cpy;
|
||||
|
||||
var dst_LASTLITERALS = dst_end - LASTLITERALS;
|
||||
var dst_COPYLENGTH = dst_end - COPYLENGTH;
|
||||
var dst_COPYLENGTH_STEPSIZE_4 = dst_end - COPYLENGTH - (STEPSIZE_64 - 4);
|
||||
|
||||
uint token;
|
||||
|
||||
// Main Loop
|
||||
while (true)
|
||||
{
|
||||
int length;
|
||||
|
||||
// get runlength
|
||||
token = src[src_p++];
|
||||
if ((length = (byte)(token >> ML_BITS)) == RUN_MASK)
|
||||
{
|
||||
int len;
|
||||
for (; (len = src[src_p++]) == 255; length += 255)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
length += len;
|
||||
}
|
||||
|
||||
// copy literals
|
||||
dst_cpy = dst_p + length;
|
||||
|
||||
if (dst_cpy > dst_COPYLENGTH)
|
||||
{
|
||||
if (dst_cpy != dst_end)
|
||||
{
|
||||
goto _output_error; // Error : not enough place for another match (min 4) + 5 literals
|
||||
}
|
||||
|
||||
BlockCopy(src, src_p, dst, dst_p, length);
|
||||
src_p += length;
|
||||
break; // EOF
|
||||
}
|
||||
|
||||
if (dst_p < dst_cpy)
|
||||
{
|
||||
_i = WildCopy(src, src_p, dst, dst_p, dst_cpy);
|
||||
src_p += _i;
|
||||
dst_p += _i;
|
||||
}
|
||||
|
||||
src_p -= dst_p - dst_cpy;
|
||||
dst_p = dst_cpy;
|
||||
|
||||
// get offset
|
||||
dst_ref = dst_cpy - Peek2(src, src_p);
|
||||
src_p += 2;
|
||||
if (dst_ref < dst_0)
|
||||
{
|
||||
goto _output_error; // Error : offset outside destination buffer
|
||||
}
|
||||
|
||||
// get matchlength
|
||||
if ((length = (byte)(token & ML_MASK)) == ML_MASK)
|
||||
{
|
||||
for (; src[src_p] == 255; length += 255)
|
||||
{
|
||||
src_p++;
|
||||
}
|
||||
|
||||
length += src[src_p++];
|
||||
}
|
||||
|
||||
// copy repeated sequence
|
||||
if ((dst_p - dst_ref) < STEPSIZE_64)
|
||||
{
|
||||
var dec64 = dec64table[dst_p - dst_ref];
|
||||
|
||||
dst[dst_p + 0] = dst[dst_ref + 0];
|
||||
dst[dst_p + 1] = dst[dst_ref + 1];
|
||||
dst[dst_p + 2] = dst[dst_ref + 2];
|
||||
dst[dst_p + 3] = dst[dst_ref + 3];
|
||||
dst_p += 4;
|
||||
dst_ref += 4;
|
||||
dst_ref -= dec32table[dst_p - dst_ref];
|
||||
Copy4(dst, dst_ref, dst_p);
|
||||
dst_p += STEPSIZE_64 - 4;
|
||||
dst_ref -= dec64;
|
||||
}
|
||||
else
|
||||
{
|
||||
Copy8(dst, dst_ref, dst_p);
|
||||
dst_p += 8;
|
||||
dst_ref += 8;
|
||||
}
|
||||
|
||||
dst_cpy = dst_p + length - (STEPSIZE_64 - 4);
|
||||
|
||||
if (dst_cpy > dst_COPYLENGTH_STEPSIZE_4)
|
||||
{
|
||||
if (dst_cpy > dst_LASTLITERALS)
|
||||
{
|
||||
goto _output_error; // Error : last 5 bytes must be literals
|
||||
}
|
||||
|
||||
if (dst_p < dst_COPYLENGTH)
|
||||
{
|
||||
_i = SecureCopy(dst, dst_ref, dst_p, dst_COPYLENGTH);
|
||||
dst_ref += _i;
|
||||
dst_p += _i;
|
||||
}
|
||||
|
||||
while (dst_p < dst_cpy)
|
||||
{
|
||||
dst[dst_p++] = dst[dst_ref++];
|
||||
}
|
||||
|
||||
dst_p = dst_cpy;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (dst_p < dst_cpy)
|
||||
{
|
||||
SecureCopy(dst, dst_ref, dst_p, dst_cpy);
|
||||
}
|
||||
|
||||
dst_p = dst_cpy; // correction
|
||||
}
|
||||
|
||||
// end of decoding
|
||||
return src_p - src_0;
|
||||
|
||||
_output_error:
|
||||
|
||||
// write overflow error detected
|
||||
return -(src_p - src_0);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 31798435f43678c67b458999c71cfbb3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#region license
|
||||
|
||||
/*
|
||||
Copyright (c) 2013, Milosz Krajewski
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided
|
||||
that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions
|
||||
and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions
|
||||
and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace MessagePack.LZ4
|
||||
{
|
||||
/// <summary>Unsafe LZ4 codec.</summary>
|
||||
internal partial class LZ4Codec
|
||||
{
|
||||
/// <summary>Encodes the specified input.</summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="output">The output.</param>
|
||||
/// <returns>Number of bytes written.</returns>
|
||||
public static unsafe int Encode(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
if (output.Length == 0)
|
||||
{
|
||||
throw new MessagePackSerializationException("Output is empty.");
|
||||
}
|
||||
|
||||
fixed (byte* inputPtr = input)
|
||||
fixed (byte* outputPtr = output)
|
||||
{
|
||||
if (input.Length < LZ4_64KLIMIT)
|
||||
{
|
||||
var uHashTable = HashTablePool.GetUShortHashTablePool();
|
||||
fixed (ushort* hash1 = &uHashTable[0])
|
||||
{
|
||||
if (IntPtr.Size == 4)
|
||||
{
|
||||
return LZ4_compress64kCtx_32(hash1, inputPtr, outputPtr, input.Length, output.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
return LZ4_compress64kCtx_64(hash1, inputPtr, outputPtr, input.Length, output.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var bHashTable = HashTablePool.GetUIntHashTablePool();
|
||||
fixed (uint* hash2 = &bHashTable[0])
|
||||
{
|
||||
if (IntPtr.Size == 4)
|
||||
{
|
||||
return LZ4_compressCtx_32(hash2, inputPtr, outputPtr, input.Length, output.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
return LZ4_compressCtx_64(hash2, inputPtr, outputPtr, input.Length, output.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Decodes the specified input.</summary>
|
||||
/// <param name="input">The input.</param>
|
||||
/// <param name="output">The output.</param>
|
||||
/// <returns>Number of bytes written.</returns>
|
||||
public static unsafe int Decode(ReadOnlySpan<byte> input, Span<byte> output)
|
||||
{
|
||||
if (output.Length == 0)
|
||||
{
|
||||
throw new MessagePackSerializationException("Output is empty.");
|
||||
}
|
||||
|
||||
fixed (byte* inputPtr = input)
|
||||
fixed (byte* outputPtr = output)
|
||||
{
|
||||
int length;
|
||||
if (IntPtr.Size == 4)
|
||||
{
|
||||
length = LZ4_uncompress_32(inputPtr, outputPtr, output.Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
length = LZ4_uncompress_64(inputPtr, outputPtr, output.Length);
|
||||
}
|
||||
|
||||
if (length != input.Length)
|
||||
{
|
||||
throw new MessagePackSerializationException("LZ4 block is corrupted, or invalid length has been given.");
|
||||
}
|
||||
|
||||
return output.Length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 719385c28cab29b71a262f02263f385e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,796 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#region LZ4 original
|
||||
|
||||
/*
|
||||
LZ4 - Fast LZ compression algorithm
|
||||
Copyright (C) 2011-2012, Yann Collet.
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#region LZ4 port
|
||||
|
||||
/*
|
||||
Copyright (c) 2013, Milosz Krajewski
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided
|
||||
that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions
|
||||
and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions
|
||||
and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#pragma warning disable SA1312 // Variable names should begin with lower-case letter
|
||||
|
||||
namespace MessagePack.LZ4
|
||||
{
|
||||
internal partial class LZ4Codec
|
||||
{
|
||||
#region LZ4_compressCtx_32
|
||||
|
||||
private static unsafe int LZ4_compressCtx_32(
|
||||
uint* hash_table,
|
||||
byte* src,
|
||||
byte* dst,
|
||||
int src_len,
|
||||
int dst_maxlen)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
byte* _p;
|
||||
|
||||
fixed (int* debruijn32 = &DEBRUIJN_TABLE_32[0])
|
||||
{
|
||||
// r93
|
||||
var src_p = src;
|
||||
var src_base = src_p;
|
||||
var src_anchor = src_p;
|
||||
var src_end = src_p + src_len;
|
||||
var src_mflimit = src_end - MFLIMIT;
|
||||
|
||||
var dst_p = dst;
|
||||
var dst_end = dst_p + dst_maxlen;
|
||||
|
||||
var src_LASTLITERALS = src_end - LASTLITERALS;
|
||||
var src_LASTLITERALS_1 = src_LASTLITERALS - 1;
|
||||
|
||||
var src_LASTLITERALS_STEPSIZE_1 = src_LASTLITERALS - (STEPSIZE_32 - 1);
|
||||
var dst_LASTLITERALS_1 = dst_end - (1 + LASTLITERALS);
|
||||
var dst_LASTLITERALS_3 = dst_end - (2 + 1 + LASTLITERALS);
|
||||
|
||||
int length;
|
||||
|
||||
uint h, h_fwd;
|
||||
|
||||
// Init
|
||||
if (src_len < MINLENGTH)
|
||||
{
|
||||
goto _last_literals;
|
||||
}
|
||||
|
||||
// First Byte
|
||||
hash_table[(*(uint*)src_p * 2654435761u) >> HASH_ADJUST] = (uint)(src_p - src_base);
|
||||
src_p++;
|
||||
h_fwd = (*(uint*)src_p * 2654435761u) >> HASH_ADJUST;
|
||||
|
||||
// Main Loop
|
||||
while (true)
|
||||
{
|
||||
var findMatchAttempts = (1 << SKIPSTRENGTH) + 3;
|
||||
var src_p_fwd = src_p;
|
||||
byte* xxx_ref;
|
||||
byte* xxx_token;
|
||||
|
||||
// Find a match
|
||||
do
|
||||
{
|
||||
h = h_fwd;
|
||||
var step = findMatchAttempts++ >> SKIPSTRENGTH;
|
||||
src_p = src_p_fwd;
|
||||
src_p_fwd = src_p + step;
|
||||
|
||||
if (src_p_fwd > src_mflimit)
|
||||
{
|
||||
goto _last_literals;
|
||||
}
|
||||
|
||||
h_fwd = (*(uint*)src_p_fwd * 2654435761u) >> HASH_ADJUST;
|
||||
xxx_ref = src_base + hash_table[h];
|
||||
hash_table[h] = (uint)(src_p - src_base);
|
||||
}
|
||||
while ((xxx_ref < src_p - MAX_DISTANCE) || ((*(uint*)xxx_ref) != (*(uint*)src_p)));
|
||||
|
||||
// Catch up
|
||||
while ((src_p > src_anchor) && (xxx_ref > src) && (src_p[-1] == xxx_ref[-1]))
|
||||
{
|
||||
src_p--;
|
||||
xxx_ref--;
|
||||
}
|
||||
|
||||
// Encode Literal length
|
||||
length = (int)(src_p - src_anchor);
|
||||
xxx_token = dst_p++;
|
||||
|
||||
if (dst_p + length + (length >> 8) > dst_LASTLITERALS_3)
|
||||
{
|
||||
return 0; // Check output limit
|
||||
}
|
||||
|
||||
if (length >= RUN_MASK)
|
||||
{
|
||||
var len = length - RUN_MASK;
|
||||
*xxx_token = RUN_MASK << ML_BITS;
|
||||
if (len > 254)
|
||||
{
|
||||
do
|
||||
{
|
||||
*dst_p++ = 255;
|
||||
len -= 255;
|
||||
}
|
||||
while (len > 254);
|
||||
*dst_p++ = (byte)len;
|
||||
BlockCopy32(src_anchor, dst_p, length);
|
||||
dst_p += length;
|
||||
goto _next_match;
|
||||
}
|
||||
|
||||
*dst_p++ = (byte)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*xxx_token = (byte)(length << ML_BITS);
|
||||
}
|
||||
|
||||
// Copy Literals
|
||||
_p = dst_p + length;
|
||||
do
|
||||
{
|
||||
*(uint*)dst_p = *(uint*)src_anchor;
|
||||
dst_p += 4;
|
||||
src_anchor += 4;
|
||||
*(uint*)dst_p = *(uint*)src_anchor;
|
||||
dst_p += 4;
|
||||
src_anchor += 4;
|
||||
}
|
||||
while (dst_p < _p);
|
||||
dst_p = _p;
|
||||
|
||||
_next_match:
|
||||
|
||||
// Encode Offset
|
||||
*(ushort*)dst_p = (ushort)(src_p - xxx_ref);
|
||||
dst_p += 2;
|
||||
|
||||
// Start Counting
|
||||
src_p += MINMATCH;
|
||||
xxx_ref += MINMATCH; // MinMatch already verified
|
||||
src_anchor = src_p;
|
||||
|
||||
while (src_p < src_LASTLITERALS_STEPSIZE_1)
|
||||
{
|
||||
var diff = (*(int*)xxx_ref) ^ (*(int*)src_p);
|
||||
if (diff == 0)
|
||||
{
|
||||
src_p += STEPSIZE_32;
|
||||
xxx_ref += STEPSIZE_32;
|
||||
continue;
|
||||
}
|
||||
|
||||
src_p += debruijn32[((uint)(diff & -diff) * 0x077CB531u) >> 27];
|
||||
goto _endCount;
|
||||
}
|
||||
|
||||
if ((src_p < src_LASTLITERALS_1) && ((*(ushort*)xxx_ref) == (*(ushort*)src_p)))
|
||||
{
|
||||
src_p += 2;
|
||||
xxx_ref += 2;
|
||||
}
|
||||
|
||||
if ((src_p < src_LASTLITERALS) && (*xxx_ref == *src_p))
|
||||
{
|
||||
src_p++;
|
||||
}
|
||||
|
||||
_endCount:
|
||||
|
||||
// Encode MatchLength
|
||||
length = (int)(src_p - src_anchor);
|
||||
|
||||
if (dst_p + (length >> 8) > dst_LASTLITERALS_1)
|
||||
{
|
||||
return 0; // Check output limit
|
||||
}
|
||||
|
||||
if (length >= ML_MASK)
|
||||
{
|
||||
*xxx_token += ML_MASK;
|
||||
length -= ML_MASK;
|
||||
for (; length > 509; length -= 510)
|
||||
{
|
||||
*dst_p++ = 255;
|
||||
*dst_p++ = 255;
|
||||
}
|
||||
|
||||
if (length > 254)
|
||||
{
|
||||
length -= 255;
|
||||
*dst_p++ = 255;
|
||||
}
|
||||
|
||||
*dst_p++ = (byte)length;
|
||||
}
|
||||
else
|
||||
{
|
||||
*xxx_token += (byte)length;
|
||||
}
|
||||
|
||||
// Test end of chunk
|
||||
if (src_p > src_mflimit)
|
||||
{
|
||||
src_anchor = src_p;
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill table
|
||||
hash_table[(*(uint*)(src_p - 2) * 2654435761u) >> HASH_ADJUST] = (uint)(src_p - 2 - src_base);
|
||||
|
||||
// Test next position
|
||||
h = (*(uint*)src_p * 2654435761u) >> HASH_ADJUST;
|
||||
xxx_ref = src_base + hash_table[h];
|
||||
hash_table[h] = (uint)(src_p - src_base);
|
||||
|
||||
if ((xxx_ref > src_p - (MAX_DISTANCE + 1)) && ((*(uint*)xxx_ref) == (*(uint*)src_p)))
|
||||
{
|
||||
xxx_token = dst_p++;
|
||||
*xxx_token = 0;
|
||||
goto _next_match;
|
||||
}
|
||||
|
||||
// Prepare next loop
|
||||
src_anchor = src_p++;
|
||||
h_fwd = (*(uint*)src_p * 2654435761u) >> HASH_ADJUST;
|
||||
}
|
||||
|
||||
_last_literals:
|
||||
|
||||
// Encode Last Literals
|
||||
{
|
||||
var lastRun = (int)(src_end - src_anchor);
|
||||
|
||||
if (dst_p + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > dst_end)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lastRun >= RUN_MASK)
|
||||
{
|
||||
*dst_p++ = RUN_MASK << ML_BITS;
|
||||
lastRun -= RUN_MASK;
|
||||
for (; lastRun > 254; lastRun -= 255)
|
||||
{
|
||||
*dst_p++ = 255;
|
||||
}
|
||||
|
||||
*dst_p++ = (byte)lastRun;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dst_p++ = (byte)(lastRun << ML_BITS);
|
||||
}
|
||||
|
||||
BlockCopy32(src_anchor, dst_p, (int)(src_end - src_anchor));
|
||||
dst_p += src_end - src_anchor;
|
||||
}
|
||||
|
||||
// End
|
||||
return (int)(dst_p - dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LZ4_compress64kCtx_32
|
||||
|
||||
private static unsafe int LZ4_compress64kCtx_32(
|
||||
ushort* hash_table,
|
||||
byte* src,
|
||||
byte* dst,
|
||||
int src_len,
|
||||
int dst_maxlen)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
byte* _p;
|
||||
fixed (int* debruijn32 = &DEBRUIJN_TABLE_32[0])
|
||||
{
|
||||
// r93
|
||||
var src_p = src;
|
||||
var src_anchor = src_p;
|
||||
var src_base = src_p;
|
||||
var src_end = src_p + src_len;
|
||||
var src_mflimit = src_end - MFLIMIT;
|
||||
|
||||
var dst_p = dst;
|
||||
var dst_end = dst_p + dst_maxlen;
|
||||
|
||||
var src_LASTLITERALS = src_end - LASTLITERALS;
|
||||
var src_LASTLITERALS_1 = src_LASTLITERALS - 1;
|
||||
|
||||
var src_LASTLITERALS_STEPSIZE_1 = src_LASTLITERALS - (STEPSIZE_32 - 1);
|
||||
var dst_LASTLITERALS_1 = dst_end - (1 + LASTLITERALS);
|
||||
var dst_LASTLITERALS_3 = dst_end - (2 + 1 + LASTLITERALS);
|
||||
|
||||
int len, length;
|
||||
|
||||
uint h, h_fwd;
|
||||
|
||||
// Init
|
||||
if (src_len < MINLENGTH)
|
||||
{
|
||||
goto _last_literals;
|
||||
}
|
||||
|
||||
// First Byte
|
||||
src_p++;
|
||||
h_fwd = (*(uint*)src_p * 2654435761u) >> HASH64K_ADJUST;
|
||||
|
||||
// Main Loop
|
||||
while (true)
|
||||
{
|
||||
var findMatchAttempts = (1 << SKIPSTRENGTH) + 3;
|
||||
var src_p_fwd = src_p;
|
||||
byte* xxx_ref;
|
||||
byte* xxx_token;
|
||||
|
||||
// Find a match
|
||||
do
|
||||
{
|
||||
h = h_fwd;
|
||||
var step = findMatchAttempts++ >> SKIPSTRENGTH;
|
||||
src_p = src_p_fwd;
|
||||
src_p_fwd = src_p + step;
|
||||
|
||||
if (src_p_fwd > src_mflimit)
|
||||
{
|
||||
goto _last_literals;
|
||||
}
|
||||
|
||||
h_fwd = (*(uint*)src_p_fwd * 2654435761u) >> HASH64K_ADJUST;
|
||||
xxx_ref = src_base + hash_table[h];
|
||||
hash_table[h] = (ushort)(src_p - src_base);
|
||||
}
|
||||
while ((*(uint*)xxx_ref) != (*(uint*)src_p));
|
||||
|
||||
// Catch up
|
||||
while ((src_p > src_anchor) && (xxx_ref > src) && (src_p[-1] == xxx_ref[-1]))
|
||||
{
|
||||
src_p--;
|
||||
xxx_ref--;
|
||||
}
|
||||
|
||||
// Encode Literal length
|
||||
length = (int)(src_p - src_anchor);
|
||||
xxx_token = dst_p++;
|
||||
|
||||
if (dst_p + length + (length >> 8) > dst_LASTLITERALS_3)
|
||||
{
|
||||
return 0; // Check output limit
|
||||
}
|
||||
|
||||
if (length >= RUN_MASK)
|
||||
{
|
||||
len = length - RUN_MASK;
|
||||
*xxx_token = RUN_MASK << ML_BITS;
|
||||
if (len > 254)
|
||||
{
|
||||
do
|
||||
{
|
||||
*dst_p++ = 255;
|
||||
len -= 255;
|
||||
}
|
||||
while (len > 254);
|
||||
*dst_p++ = (byte)len;
|
||||
BlockCopy32(src_anchor, dst_p, length);
|
||||
dst_p += length;
|
||||
goto _next_match;
|
||||
}
|
||||
|
||||
*dst_p++ = (byte)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*xxx_token = (byte)(length << ML_BITS);
|
||||
}
|
||||
|
||||
// Copy Literals
|
||||
_p = dst_p + length;
|
||||
do
|
||||
{
|
||||
*(uint*)dst_p = *(uint*)src_anchor;
|
||||
dst_p += 4;
|
||||
src_anchor += 4;
|
||||
*(uint*)dst_p = *(uint*)src_anchor;
|
||||
dst_p += 4;
|
||||
src_anchor += 4;
|
||||
}
|
||||
while (dst_p < _p);
|
||||
dst_p = _p;
|
||||
|
||||
_next_match:
|
||||
|
||||
// Encode Offset
|
||||
*(ushort*)dst_p = (ushort)(src_p - xxx_ref);
|
||||
dst_p += 2;
|
||||
|
||||
// Start Counting
|
||||
src_p += MINMATCH;
|
||||
xxx_ref += MINMATCH; // MinMatch verified
|
||||
src_anchor = src_p;
|
||||
|
||||
while (src_p < src_LASTLITERALS_STEPSIZE_1)
|
||||
{
|
||||
var diff = (*(int*)xxx_ref) ^ (*(int*)src_p);
|
||||
if (diff == 0)
|
||||
{
|
||||
src_p += STEPSIZE_32;
|
||||
xxx_ref += STEPSIZE_32;
|
||||
continue;
|
||||
}
|
||||
|
||||
src_p += debruijn32[((uint)(diff & -diff) * 0x077CB531u) >> 27];
|
||||
goto _endCount;
|
||||
}
|
||||
|
||||
if ((src_p < src_LASTLITERALS_1) && ((*(ushort*)xxx_ref) == (*(ushort*)src_p)))
|
||||
{
|
||||
src_p += 2;
|
||||
xxx_ref += 2;
|
||||
}
|
||||
|
||||
if ((src_p < src_LASTLITERALS) && (*xxx_ref == *src_p))
|
||||
{
|
||||
src_p++;
|
||||
}
|
||||
|
||||
_endCount:
|
||||
|
||||
// Encode MatchLength
|
||||
len = (int)(src_p - src_anchor);
|
||||
|
||||
if (dst_p + (len >> 8) > dst_LASTLITERALS_1)
|
||||
{
|
||||
return 0; // Check output limit
|
||||
}
|
||||
|
||||
if (len >= ML_MASK)
|
||||
{
|
||||
*xxx_token += ML_MASK;
|
||||
len -= ML_MASK;
|
||||
for (; len > 509; len -= 510)
|
||||
{
|
||||
*dst_p++ = 255;
|
||||
*dst_p++ = 255;
|
||||
}
|
||||
|
||||
if (len > 254)
|
||||
{
|
||||
len -= 255;
|
||||
*dst_p++ = 255;
|
||||
}
|
||||
|
||||
*dst_p++ = (byte)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*xxx_token += (byte)len;
|
||||
}
|
||||
|
||||
// Test end of chunk
|
||||
if (src_p > src_mflimit)
|
||||
{
|
||||
src_anchor = src_p;
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill table
|
||||
hash_table[(*(uint*)(src_p - 2) * 2654435761u) >> HASH64K_ADJUST] = (ushort)(src_p - 2 - src_base);
|
||||
|
||||
// Test next position
|
||||
h = (*(uint*)src_p * 2654435761u) >> HASH64K_ADJUST;
|
||||
xxx_ref = src_base + hash_table[h];
|
||||
hash_table[h] = (ushort)(src_p - src_base);
|
||||
|
||||
if ((*(uint*)xxx_ref) == (*(uint*)src_p))
|
||||
{
|
||||
xxx_token = dst_p++;
|
||||
*xxx_token = 0;
|
||||
goto _next_match;
|
||||
}
|
||||
|
||||
// Prepare next loop
|
||||
src_anchor = src_p++;
|
||||
h_fwd = (*(uint*)src_p * 2654435761u) >> HASH64K_ADJUST;
|
||||
}
|
||||
|
||||
_last_literals:
|
||||
|
||||
// Encode Last Literals
|
||||
{
|
||||
var lastRun = (int)(src_end - src_anchor);
|
||||
if (dst_p + lastRun + 1 + ((lastRun - RUN_MASK + 255) / 255) > dst_end)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lastRun >= RUN_MASK)
|
||||
{
|
||||
*dst_p++ = RUN_MASK << ML_BITS;
|
||||
lastRun -= RUN_MASK;
|
||||
for (; lastRun > 254; lastRun -= 255)
|
||||
{
|
||||
*dst_p++ = 255;
|
||||
}
|
||||
|
||||
*dst_p++ = (byte)lastRun;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dst_p++ = (byte)(lastRun << ML_BITS);
|
||||
}
|
||||
|
||||
BlockCopy32(src_anchor, dst_p, (int)(src_end - src_anchor));
|
||||
dst_p += src_end - src_anchor;
|
||||
}
|
||||
|
||||
// End
|
||||
return (int)(dst_p - dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LZ4_uncompress_32
|
||||
|
||||
private static unsafe int LZ4_uncompress_32(
|
||||
byte* src,
|
||||
byte* dst,
|
||||
int dst_len)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
fixed (int* dec32table = &DECODER_TABLE_32[0])
|
||||
{
|
||||
// r93
|
||||
var src_p = src;
|
||||
byte* xxx_ref;
|
||||
|
||||
var dst_p = dst;
|
||||
var dst_end = dst_p + dst_len;
|
||||
byte* dst_cpy;
|
||||
|
||||
var dst_LASTLITERALS = dst_end - LASTLITERALS;
|
||||
var dst_COPYLENGTH = dst_end - COPYLENGTH;
|
||||
var dst_COPYLENGTH_STEPSIZE_4 = dst_end - COPYLENGTH - (STEPSIZE_32 - 4);
|
||||
|
||||
uint xxx_token;
|
||||
|
||||
// Main Loop
|
||||
while (true)
|
||||
{
|
||||
int length;
|
||||
|
||||
// get runlength
|
||||
xxx_token = *src_p++;
|
||||
if ((length = (int)(xxx_token >> ML_BITS)) == RUN_MASK)
|
||||
{
|
||||
int len;
|
||||
for (; (len = *src_p++) == 255; length += 255)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
length += len;
|
||||
}
|
||||
|
||||
// copy literals
|
||||
dst_cpy = dst_p + length;
|
||||
|
||||
if (dst_cpy > dst_COPYLENGTH)
|
||||
{
|
||||
if (dst_cpy != dst_end)
|
||||
{
|
||||
goto _output_error; // Error : not enough place for another match (min 4) + 5 literals
|
||||
}
|
||||
|
||||
BlockCopy32(src_p, dst_p, length);
|
||||
src_p += length;
|
||||
break; // EOF
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
*(uint*)dst_p = *(uint*)src_p;
|
||||
dst_p += 4;
|
||||
src_p += 4;
|
||||
*(uint*)dst_p = *(uint*)src_p;
|
||||
dst_p += 4;
|
||||
src_p += 4;
|
||||
}
|
||||
while (dst_p < dst_cpy);
|
||||
src_p -= dst_p - dst_cpy;
|
||||
dst_p = dst_cpy;
|
||||
|
||||
// get offset
|
||||
xxx_ref = dst_cpy - (*(ushort*)src_p);
|
||||
src_p += 2;
|
||||
if (xxx_ref < dst)
|
||||
{
|
||||
goto _output_error; // Error : offset outside destination buffer
|
||||
}
|
||||
|
||||
// get matchlength
|
||||
if ((length = (int)(xxx_token & ML_MASK)) == ML_MASK)
|
||||
{
|
||||
for (; *src_p == 255; length += 255)
|
||||
{
|
||||
src_p++;
|
||||
}
|
||||
|
||||
length += *src_p++;
|
||||
}
|
||||
|
||||
// copy repeated sequence
|
||||
if ((dst_p - xxx_ref) < STEPSIZE_32)
|
||||
{
|
||||
const int dec64 = 0;
|
||||
|
||||
dst_p[0] = xxx_ref[0];
|
||||
dst_p[1] = xxx_ref[1];
|
||||
dst_p[2] = xxx_ref[2];
|
||||
dst_p[3] = xxx_ref[3];
|
||||
dst_p += 4;
|
||||
xxx_ref += 4;
|
||||
xxx_ref -= dec32table[dst_p - xxx_ref];
|
||||
*(uint*)dst_p = *(uint*)xxx_ref;
|
||||
dst_p += STEPSIZE_32 - 4;
|
||||
xxx_ref -= dec64;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(uint*)dst_p = *(uint*)xxx_ref;
|
||||
dst_p += 4;
|
||||
xxx_ref += 4;
|
||||
}
|
||||
|
||||
dst_cpy = dst_p + length - (STEPSIZE_32 - 4);
|
||||
|
||||
if (dst_cpy > dst_COPYLENGTH_STEPSIZE_4)
|
||||
{
|
||||
if (dst_cpy > dst_LASTLITERALS)
|
||||
{
|
||||
goto _output_error; // Error : last 5 bytes must be literals
|
||||
}
|
||||
|
||||
{
|
||||
do
|
||||
{
|
||||
*(uint*)dst_p = *(uint*)xxx_ref;
|
||||
dst_p += 4;
|
||||
xxx_ref += 4;
|
||||
*(uint*)dst_p = *(uint*)xxx_ref;
|
||||
dst_p += 4;
|
||||
xxx_ref += 4;
|
||||
}
|
||||
while (dst_p < dst_COPYLENGTH);
|
||||
}
|
||||
|
||||
while (dst_p < dst_cpy)
|
||||
{
|
||||
*dst_p++ = *xxx_ref++;
|
||||
}
|
||||
|
||||
dst_p = dst_cpy;
|
||||
continue;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
*(uint*)dst_p = *(uint*)xxx_ref;
|
||||
dst_p += 4;
|
||||
xxx_ref += 4;
|
||||
*(uint*)dst_p = *(uint*)xxx_ref;
|
||||
dst_p += 4;
|
||||
xxx_ref += 4;
|
||||
}
|
||||
while (dst_p < dst_cpy);
|
||||
dst_p = dst_cpy; // correction
|
||||
}
|
||||
|
||||
// end of decoding
|
||||
return (int)(src_p - src);
|
||||
|
||||
// write overflow error detected
|
||||
_output_error:
|
||||
return (int)-(src_p - src);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>Copies block of memory.</summary>
|
||||
/// <param name="src">The source.</param>
|
||||
/// <param name="dst">The destination.</param>
|
||||
/// <param name="len">The length (in bytes).</param>
|
||||
private static unsafe void BlockCopy32(byte* src, byte* dst, int len)
|
||||
{
|
||||
while (len >= 4)
|
||||
{
|
||||
*(uint*)dst = *(uint*)src;
|
||||
dst += 4;
|
||||
src += 4;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
if (len >= 2)
|
||||
{
|
||||
*(ushort*)dst = *(ushort*)src;
|
||||
dst += 2;
|
||||
src += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
if (len >= 1)
|
||||
{
|
||||
*dst = *src; /* d++; s++; l--; */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 44efef809614456e8a4d40559c526efa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,808 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#region LZ4 original
|
||||
|
||||
/*
|
||||
LZ4 - Fast LZ compression algorithm
|
||||
Copyright (C) 2011-2012, Yann Collet.
|
||||
BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
You can contact the author at :
|
||||
- LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
|
||||
- LZ4 source repository : http://code.google.com/p/lz4/
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#region LZ4 port
|
||||
|
||||
/*
|
||||
Copyright (c) 2013, Milosz Krajewski
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided
|
||||
that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions
|
||||
and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions
|
||||
and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
#pragma warning disable SA1312 // Variable names should begin with lower-case letter
|
||||
|
||||
namespace MessagePack.LZ4
|
||||
{
|
||||
internal partial class LZ4Codec
|
||||
{
|
||||
#region LZ4_compressCtx_64
|
||||
|
||||
private static unsafe int LZ4_compressCtx_64(
|
||||
uint* hash_table,
|
||||
byte* src,
|
||||
byte* dst,
|
||||
int src_len,
|
||||
int dst_maxlen)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
byte* _p;
|
||||
|
||||
fixed (int* debruijn64 = &DEBRUIJN_TABLE_64[0])
|
||||
{
|
||||
// r93
|
||||
var src_p = src;
|
||||
var src_base = src_p;
|
||||
var src_anchor = src_p;
|
||||
var src_end = src_p + src_len;
|
||||
var src_mflimit = src_end - MFLIMIT;
|
||||
|
||||
var dst_p = dst;
|
||||
var dst_end = dst_p + dst_maxlen;
|
||||
|
||||
var src_LASTLITERALS = src_end - LASTLITERALS;
|
||||
var src_LASTLITERALS_1 = src_LASTLITERALS - 1;
|
||||
|
||||
var src_LASTLITERALS_3 = src_LASTLITERALS - 3;
|
||||
var src_LASTLITERALS_STEPSIZE_1 = src_LASTLITERALS - (STEPSIZE_64 - 1);
|
||||
var dst_LASTLITERALS_1 = dst_end - (1 + LASTLITERALS);
|
||||
var dst_LASTLITERALS_3 = dst_end - (2 + 1 + LASTLITERALS);
|
||||
|
||||
int length;
|
||||
uint h, h_fwd;
|
||||
|
||||
// Init
|
||||
if (src_len < MINLENGTH)
|
||||
{
|
||||
goto _last_literals;
|
||||
}
|
||||
|
||||
// First Byte
|
||||
hash_table[(*(uint*)src_p * 2654435761u) >> HASH_ADJUST] = (uint)(src_p - src_base);
|
||||
src_p++;
|
||||
h_fwd = (*(uint*)src_p * 2654435761u) >> HASH_ADJUST;
|
||||
|
||||
// Main Loop
|
||||
while (true)
|
||||
{
|
||||
var findMatchAttempts = (1 << SKIPSTRENGTH) + 3;
|
||||
var src_p_fwd = src_p;
|
||||
byte* src_ref;
|
||||
byte* dst_token;
|
||||
|
||||
// Find a match
|
||||
do
|
||||
{
|
||||
h = h_fwd;
|
||||
var step = findMatchAttempts++ >> SKIPSTRENGTH;
|
||||
src_p = src_p_fwd;
|
||||
src_p_fwd = src_p + step;
|
||||
|
||||
if (src_p_fwd > src_mflimit)
|
||||
{
|
||||
goto _last_literals;
|
||||
}
|
||||
|
||||
h_fwd = (*(uint*)src_p_fwd * 2654435761u) >> HASH_ADJUST;
|
||||
src_ref = src_base + hash_table[h];
|
||||
hash_table[h] = (uint)(src_p - src_base);
|
||||
}
|
||||
while ((src_ref < src_p - MAX_DISTANCE) || ((*(uint*)src_ref) != (*(uint*)src_p)));
|
||||
|
||||
// Catch up
|
||||
while ((src_p > src_anchor) && (src_ref > src) && (src_p[-1] == src_ref[-1]))
|
||||
{
|
||||
src_p--;
|
||||
src_ref--;
|
||||
}
|
||||
|
||||
// Encode Literal length
|
||||
length = (int)(src_p - src_anchor);
|
||||
dst_token = dst_p++;
|
||||
|
||||
if (dst_p + length + (length >> 8) > dst_LASTLITERALS_3)
|
||||
{
|
||||
return 0; // Check output limit
|
||||
}
|
||||
|
||||
if (length >= RUN_MASK)
|
||||
{
|
||||
var len = length - RUN_MASK;
|
||||
*dst_token = RUN_MASK << ML_BITS;
|
||||
if (len > 254)
|
||||
{
|
||||
do
|
||||
{
|
||||
*dst_p++ = 255;
|
||||
len -= 255;
|
||||
}
|
||||
while (len > 254);
|
||||
*dst_p++ = (byte)len;
|
||||
BlockCopy64(src_anchor, dst_p, length);
|
||||
dst_p += length;
|
||||
goto _next_match;
|
||||
}
|
||||
|
||||
*dst_p++ = (byte)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dst_token = (byte)(length << ML_BITS);
|
||||
}
|
||||
|
||||
// Copy Literals
|
||||
_p = dst_p + length;
|
||||
{
|
||||
do
|
||||
{
|
||||
*(ulong*)dst_p = *(ulong*)src_anchor;
|
||||
dst_p += 8;
|
||||
src_anchor += 8;
|
||||
}
|
||||
while (dst_p < _p);
|
||||
}
|
||||
|
||||
dst_p = _p;
|
||||
|
||||
_next_match:
|
||||
|
||||
// Encode Offset
|
||||
*(ushort*)dst_p = (ushort)(src_p - src_ref);
|
||||
dst_p += 2;
|
||||
|
||||
// Start Counting
|
||||
src_p += MINMATCH;
|
||||
src_ref += MINMATCH; // MinMatch already verified
|
||||
src_anchor = src_p;
|
||||
|
||||
while (src_p < src_LASTLITERALS_STEPSIZE_1)
|
||||
{
|
||||
var diff = (*(long*)src_ref) ^ (*(long*)src_p);
|
||||
if (diff == 0)
|
||||
{
|
||||
src_p += STEPSIZE_64;
|
||||
src_ref += STEPSIZE_64;
|
||||
continue;
|
||||
}
|
||||
|
||||
src_p += debruijn64[((ulong)(diff & -diff) * 0x0218A392CDABBD3FL) >> 58];
|
||||
goto _endCount;
|
||||
}
|
||||
|
||||
if ((src_p < src_LASTLITERALS_3) && ((*(uint*)src_ref) == (*(uint*)src_p)))
|
||||
{
|
||||
src_p += 4;
|
||||
src_ref += 4;
|
||||
}
|
||||
|
||||
if ((src_p < src_LASTLITERALS_1) && ((*(ushort*)src_ref) == (*(ushort*)src_p)))
|
||||
{
|
||||
src_p += 2;
|
||||
src_ref += 2;
|
||||
}
|
||||
|
||||
if ((src_p < src_LASTLITERALS) && (*src_ref == *src_p))
|
||||
{
|
||||
src_p++;
|
||||
}
|
||||
|
||||
_endCount:
|
||||
|
||||
// Encode MatchLength
|
||||
length = (int)(src_p - src_anchor);
|
||||
|
||||
if (dst_p + (length >> 8) > dst_LASTLITERALS_1)
|
||||
{
|
||||
return 0; // Check output limit
|
||||
}
|
||||
|
||||
if (length >= ML_MASK)
|
||||
{
|
||||
*dst_token += ML_MASK;
|
||||
length -= ML_MASK;
|
||||
for (; length > 509; length -= 510)
|
||||
{
|
||||
*dst_p++ = 255;
|
||||
*dst_p++ = 255;
|
||||
}
|
||||
|
||||
if (length > 254)
|
||||
{
|
||||
length -= 255;
|
||||
*dst_p++ = 255;
|
||||
}
|
||||
|
||||
*dst_p++ = (byte)length;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dst_token += (byte)length;
|
||||
}
|
||||
|
||||
// Test end of chunk
|
||||
if (src_p > src_mflimit)
|
||||
{
|
||||
src_anchor = src_p;
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill table
|
||||
hash_table[(*(uint*)(src_p - 2) * 2654435761u) >> HASH_ADJUST] = (uint)(src_p - 2 - src_base);
|
||||
|
||||
// Test next position
|
||||
h = (*(uint*)src_p * 2654435761u) >> HASH_ADJUST;
|
||||
src_ref = src_base + hash_table[h];
|
||||
hash_table[h] = (uint)(src_p - src_base);
|
||||
|
||||
if ((src_ref > src_p - (MAX_DISTANCE + 1)) && ((*(uint*)src_ref) == (*(uint*)src_p)))
|
||||
{
|
||||
dst_token = dst_p++;
|
||||
*dst_token = 0;
|
||||
goto _next_match;
|
||||
}
|
||||
|
||||
// Prepare next loop
|
||||
src_anchor = src_p++;
|
||||
h_fwd = (*(uint*)src_p * 2654435761u) >> HASH_ADJUST;
|
||||
}
|
||||
|
||||
_last_literals:
|
||||
|
||||
// Encode Last Literals
|
||||
var lastRun = (int)(src_end - src_anchor);
|
||||
if (dst_p + lastRun + 1 + ((lastRun + 255 - RUN_MASK) / 255) > dst_end)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lastRun >= RUN_MASK)
|
||||
{
|
||||
*dst_p++ = RUN_MASK << ML_BITS;
|
||||
lastRun -= RUN_MASK;
|
||||
for (; lastRun > 254; lastRun -= 255)
|
||||
{
|
||||
*dst_p++ = 255;
|
||||
}
|
||||
|
||||
*dst_p++ = (byte)lastRun;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dst_p++ = (byte)(lastRun << ML_BITS);
|
||||
}
|
||||
|
||||
BlockCopy64(src_anchor, dst_p, (int)(src_end - src_anchor));
|
||||
dst_p += src_end - src_anchor;
|
||||
|
||||
// End
|
||||
return (int)(dst_p - dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LZ4_compress64kCtx_64
|
||||
|
||||
private static unsafe int LZ4_compress64kCtx_64(
|
||||
ushort* hash_table,
|
||||
byte* src,
|
||||
byte* dst,
|
||||
int src_len,
|
||||
int dst_maxlen)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
byte* _p;
|
||||
|
||||
fixed (int* debruijn64 = &DEBRUIJN_TABLE_64[0])
|
||||
{
|
||||
// r93
|
||||
var src_p = src;
|
||||
var src_anchor = src_p;
|
||||
var src_base = src_p;
|
||||
var src_end = src_p + src_len;
|
||||
var src_mflimit = src_end - MFLIMIT;
|
||||
|
||||
var dst_p = dst;
|
||||
var dst_end = dst_p + dst_maxlen;
|
||||
|
||||
var src_LASTLITERALS = src_end - LASTLITERALS;
|
||||
var src_LASTLITERALS_1 = src_LASTLITERALS - 1;
|
||||
|
||||
var src_LASTLITERALS_3 = src_LASTLITERALS - 3;
|
||||
|
||||
var src_LASTLITERALS_STEPSIZE_1 = src_LASTLITERALS - (STEPSIZE_64 - 1);
|
||||
var dst_LASTLITERALS_1 = dst_end - (1 + LASTLITERALS);
|
||||
var dst_LASTLITERALS_3 = dst_end - (2 + 1 + LASTLITERALS);
|
||||
|
||||
int len, length;
|
||||
|
||||
uint h, h_fwd;
|
||||
|
||||
// Init
|
||||
if (src_len < MINLENGTH)
|
||||
{
|
||||
goto _last_literals;
|
||||
}
|
||||
|
||||
// First Byte
|
||||
src_p++;
|
||||
h_fwd = (*(uint*)src_p * 2654435761u) >> HASH64K_ADJUST;
|
||||
|
||||
// Main Loop
|
||||
while (true)
|
||||
{
|
||||
var findMatchAttempts = (1 << SKIPSTRENGTH) + 3;
|
||||
var src_p_fwd = src_p;
|
||||
byte* src_ref;
|
||||
byte* dst_token;
|
||||
|
||||
// Find a match
|
||||
do
|
||||
{
|
||||
h = h_fwd;
|
||||
var step = findMatchAttempts++ >> SKIPSTRENGTH;
|
||||
src_p = src_p_fwd;
|
||||
src_p_fwd = src_p + step;
|
||||
|
||||
if (src_p_fwd > src_mflimit)
|
||||
{
|
||||
goto _last_literals;
|
||||
}
|
||||
|
||||
h_fwd = (*(uint*)src_p_fwd * 2654435761u) >> HASH64K_ADJUST;
|
||||
src_ref = src_base + hash_table[h];
|
||||
hash_table[h] = (ushort)(src_p - src_base);
|
||||
}
|
||||
while ((*(uint*)src_ref) != (*(uint*)src_p));
|
||||
|
||||
// Catch up
|
||||
while ((src_p > src_anchor) && (src_ref > src) && (src_p[-1] == src_ref[-1]))
|
||||
{
|
||||
src_p--;
|
||||
src_ref--;
|
||||
}
|
||||
|
||||
// Encode Literal length
|
||||
length = (int)(src_p - src_anchor);
|
||||
dst_token = dst_p++;
|
||||
|
||||
if (dst_p + length + (length >> 8) > dst_LASTLITERALS_3)
|
||||
{
|
||||
return 0; // Check output limit
|
||||
}
|
||||
|
||||
if (length >= RUN_MASK)
|
||||
{
|
||||
len = length - RUN_MASK;
|
||||
*dst_token = RUN_MASK << ML_BITS;
|
||||
if (len > 254)
|
||||
{
|
||||
do
|
||||
{
|
||||
*dst_p++ = 255;
|
||||
len -= 255;
|
||||
}
|
||||
while (len > 254);
|
||||
*dst_p++ = (byte)len;
|
||||
BlockCopy64(src_anchor, dst_p, length);
|
||||
dst_p += length;
|
||||
goto _next_match;
|
||||
}
|
||||
|
||||
*dst_p++ = (byte)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dst_token = (byte)(length << ML_BITS);
|
||||
}
|
||||
|
||||
// Copy Literals
|
||||
{
|
||||
_p = dst_p + length;
|
||||
{
|
||||
do
|
||||
{
|
||||
*(ulong*)dst_p = *(ulong*)src_anchor;
|
||||
dst_p += 8;
|
||||
src_anchor += 8;
|
||||
}
|
||||
while (dst_p < _p);
|
||||
}
|
||||
|
||||
dst_p = _p;
|
||||
}
|
||||
|
||||
_next_match:
|
||||
|
||||
// Encode Offset
|
||||
*(ushort*)dst_p = (ushort)(src_p - src_ref);
|
||||
dst_p += 2;
|
||||
|
||||
// Start Counting
|
||||
src_p += MINMATCH;
|
||||
src_ref += MINMATCH; // MinMatch verified
|
||||
src_anchor = src_p;
|
||||
|
||||
while (src_p < src_LASTLITERALS_STEPSIZE_1)
|
||||
{
|
||||
var diff = (*(long*)src_ref) ^ (*(long*)src_p);
|
||||
if (diff == 0)
|
||||
{
|
||||
src_p += STEPSIZE_64;
|
||||
src_ref += STEPSIZE_64;
|
||||
continue;
|
||||
}
|
||||
|
||||
src_p += debruijn64[((ulong)(diff & -diff) * 0x0218A392CDABBD3FL) >> 58];
|
||||
goto _endCount;
|
||||
}
|
||||
|
||||
if ((src_p < src_LASTLITERALS_3) && ((*(uint*)src_ref) == (*(uint*)src_p)))
|
||||
{
|
||||
src_p += 4;
|
||||
src_ref += 4;
|
||||
}
|
||||
|
||||
if ((src_p < src_LASTLITERALS_1) && ((*(ushort*)src_ref) == (*(ushort*)src_p)))
|
||||
{
|
||||
src_p += 2;
|
||||
src_ref += 2;
|
||||
}
|
||||
|
||||
if ((src_p < src_LASTLITERALS) && (*src_ref == *src_p))
|
||||
{
|
||||
src_p++;
|
||||
}
|
||||
|
||||
_endCount:
|
||||
|
||||
// Encode MatchLength
|
||||
len = (int)(src_p - src_anchor);
|
||||
|
||||
if (dst_p + (len >> 8) > dst_LASTLITERALS_1)
|
||||
{
|
||||
return 0; // Check output limit
|
||||
}
|
||||
|
||||
if (len >= ML_MASK)
|
||||
{
|
||||
*dst_token += ML_MASK;
|
||||
len -= ML_MASK;
|
||||
for (; len > 509; len -= 510)
|
||||
{
|
||||
*dst_p++ = 255;
|
||||
*dst_p++ = 255;
|
||||
}
|
||||
|
||||
if (len > 254)
|
||||
{
|
||||
len -= 255;
|
||||
*dst_p++ = 255;
|
||||
}
|
||||
|
||||
*dst_p++ = (byte)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dst_token += (byte)len;
|
||||
}
|
||||
|
||||
// Test end of chunk
|
||||
if (src_p > src_mflimit)
|
||||
{
|
||||
src_anchor = src_p;
|
||||
break;
|
||||
}
|
||||
|
||||
// Fill table
|
||||
hash_table[(*(uint*)(src_p - 2) * 2654435761u) >> HASH64K_ADJUST] = (ushort)(src_p - 2 - src_base);
|
||||
|
||||
// Test next position
|
||||
h = (*(uint*)src_p * 2654435761u) >> HASH64K_ADJUST;
|
||||
src_ref = src_base + hash_table[h];
|
||||
hash_table[h] = (ushort)(src_p - src_base);
|
||||
|
||||
if ((*(uint*)src_ref) == (*(uint*)src_p))
|
||||
{
|
||||
dst_token = dst_p++;
|
||||
*dst_token = 0;
|
||||
goto _next_match;
|
||||
}
|
||||
|
||||
// Prepare next loop
|
||||
src_anchor = src_p++;
|
||||
h_fwd = (*(uint*)src_p * 2654435761u) >> HASH64K_ADJUST;
|
||||
}
|
||||
|
||||
_last_literals:
|
||||
|
||||
// Encode Last Literals
|
||||
var lastRun = (int)(src_end - src_anchor);
|
||||
if (dst_p + lastRun + 1 + ((lastRun - RUN_MASK + 255) / 255) > dst_end)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (lastRun >= RUN_MASK)
|
||||
{
|
||||
*dst_p++ = RUN_MASK << ML_BITS;
|
||||
lastRun -= RUN_MASK;
|
||||
for (; lastRun > 254; lastRun -= 255)
|
||||
{
|
||||
*dst_p++ = 255;
|
||||
}
|
||||
|
||||
*dst_p++ = (byte)lastRun;
|
||||
}
|
||||
else
|
||||
{
|
||||
*dst_p++ = (byte)(lastRun << ML_BITS);
|
||||
}
|
||||
|
||||
BlockCopy64(src_anchor, dst_p, (int)(src_end - src_anchor));
|
||||
dst_p += src_end - src_anchor;
|
||||
|
||||
// End
|
||||
return (int)(dst_p - dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LZ4_uncompress_64
|
||||
|
||||
private static unsafe int LZ4_uncompress_64(
|
||||
byte* src,
|
||||
byte* dst,
|
||||
int dst_len)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
fixed (int* dec32table = &DECODER_TABLE_32[0])
|
||||
fixed (int* dec64table = &DECODER_TABLE_64[0])
|
||||
{
|
||||
// r93
|
||||
var src_p = src;
|
||||
byte* dst_ref;
|
||||
|
||||
var dst_p = dst;
|
||||
var dst_end = dst_p + dst_len;
|
||||
byte* dst_cpy;
|
||||
|
||||
var dst_LASTLITERALS = dst_end - LASTLITERALS;
|
||||
var dst_COPYLENGTH = dst_end - COPYLENGTH;
|
||||
var dst_COPYLENGTH_STEPSIZE_4 = dst_end - COPYLENGTH - (STEPSIZE_64 - 4);
|
||||
|
||||
byte token;
|
||||
|
||||
// Main Loop
|
||||
while (true)
|
||||
{
|
||||
int length;
|
||||
|
||||
// get runlength
|
||||
token = *src_p++;
|
||||
if ((length = token >> ML_BITS) == RUN_MASK)
|
||||
{
|
||||
int len;
|
||||
for (; (len = *src_p++) == 255; length += 255)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
length += len;
|
||||
}
|
||||
|
||||
// copy literals
|
||||
dst_cpy = dst_p + length;
|
||||
|
||||
if (dst_cpy > dst_COPYLENGTH)
|
||||
{
|
||||
if (dst_cpy != dst_end)
|
||||
{
|
||||
goto _output_error; // Error : not enough place for another match (min 4) + 5 literals
|
||||
}
|
||||
|
||||
BlockCopy64(src_p, dst_p, length);
|
||||
src_p += length;
|
||||
break; // EOF
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
*(ulong*)dst_p = *(ulong*)src_p;
|
||||
dst_p += 8;
|
||||
src_p += 8;
|
||||
}
|
||||
while (dst_p < dst_cpy);
|
||||
src_p -= dst_p - dst_cpy;
|
||||
dst_p = dst_cpy;
|
||||
|
||||
// get offset
|
||||
dst_ref = dst_cpy - (*(ushort*)src_p);
|
||||
src_p += 2;
|
||||
if (dst_ref < dst)
|
||||
{
|
||||
goto _output_error; // Error : offset outside destination buffer
|
||||
}
|
||||
|
||||
// get matchlength
|
||||
if ((length = token & ML_MASK) == ML_MASK)
|
||||
{
|
||||
for (; *src_p == 255; length += 255)
|
||||
{
|
||||
src_p++;
|
||||
}
|
||||
|
||||
length += *src_p++;
|
||||
}
|
||||
|
||||
// copy repeated sequence
|
||||
if ((dst_p - dst_ref) < STEPSIZE_64)
|
||||
{
|
||||
var dec64 = dec64table[dst_p - dst_ref];
|
||||
|
||||
dst_p[0] = dst_ref[0];
|
||||
dst_p[1] = dst_ref[1];
|
||||
dst_p[2] = dst_ref[2];
|
||||
dst_p[3] = dst_ref[3];
|
||||
dst_p += 4;
|
||||
dst_ref += 4;
|
||||
dst_ref -= dec32table[dst_p - dst_ref];
|
||||
*(uint*)dst_p = *(uint*)dst_ref;
|
||||
dst_p += STEPSIZE_64 - 4;
|
||||
dst_ref -= dec64;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(ulong*)dst_p = *(ulong*)dst_ref;
|
||||
dst_p += 8;
|
||||
dst_ref += 8;
|
||||
}
|
||||
|
||||
dst_cpy = dst_p + length - (STEPSIZE_64 - 4);
|
||||
|
||||
if (dst_cpy > dst_COPYLENGTH_STEPSIZE_4)
|
||||
{
|
||||
if (dst_cpy > dst_LASTLITERALS)
|
||||
{
|
||||
goto _output_error; // Error : last 5 bytes must be literals
|
||||
}
|
||||
|
||||
while (dst_p < dst_COPYLENGTH)
|
||||
{
|
||||
*(ulong*)dst_p = *(ulong*)dst_ref;
|
||||
dst_p += 8;
|
||||
dst_ref += 8;
|
||||
}
|
||||
|
||||
while (dst_p < dst_cpy)
|
||||
{
|
||||
*dst_p++ = *dst_ref++;
|
||||
}
|
||||
|
||||
dst_p = dst_cpy;
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
do
|
||||
{
|
||||
*(ulong*)dst_p = *(ulong*)dst_ref;
|
||||
dst_p += 8;
|
||||
dst_ref += 8;
|
||||
}
|
||||
while (dst_p < dst_cpy);
|
||||
}
|
||||
|
||||
dst_p = dst_cpy; // correction
|
||||
}
|
||||
|
||||
// end of decoding
|
||||
return (int)(src_p - src);
|
||||
|
||||
// write overflow error detected
|
||||
_output_error:
|
||||
return (int)-(src_p - src);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>Copies block of memory.</summary>
|
||||
/// <param name="src">The source.</param>
|
||||
/// <param name="dst">The destination.</param>
|
||||
/// <param name="len">The length (in bytes).</param>
|
||||
private static unsafe void BlockCopy64(byte* src, byte* dst, int len)
|
||||
{
|
||||
while (len >= 8)
|
||||
{
|
||||
*(ulong*)dst = *(ulong*)src;
|
||||
dst += 8;
|
||||
src += 8;
|
||||
len -= 8;
|
||||
}
|
||||
|
||||
if (len >= 4)
|
||||
{
|
||||
*(uint*)dst = *(uint*)src;
|
||||
dst += 4;
|
||||
src += 4;
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
if (len >= 2)
|
||||
{
|
||||
*(ushort*)dst = *(ushort*)src;
|
||||
dst += 2;
|
||||
src += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
if (len >= 1)
|
||||
{
|
||||
*dst = *src; /* d++; s++; l--; */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fa2e5105dcebe0410bb8ed76f622889f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,178 +0,0 @@
|
|||
// Copyright (c) All contributors. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
|
||||
#region license
|
||||
|
||||
/*
|
||||
Copyright (c) 2013, Milosz Krajewski
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided
|
||||
that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions
|
||||
and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions
|
||||
and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
|
||||
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
#pragma warning disable SA1310 // Field names should not contain underscore
|
||||
|
||||
namespace MessagePack.LZ4
|
||||
{
|
||||
internal static partial class LZ4Codec
|
||||
{
|
||||
#region configuration
|
||||
|
||||
/// <summary>
|
||||
/// Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
|
||||
/// Increasing memory usage improves compression ratio
|
||||
/// Reduced memory usage can improve speed, due to cache effect
|
||||
/// Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache.
|
||||
/// </summary>
|
||||
private const int MEMORY_USAGE = 12; // modified use 12.
|
||||
|
||||
/// <summary>
|
||||
/// Decreasing this value will make the algorithm skip faster data segments considered "incompressible"
|
||||
/// This may decrease compression ratio dramatically, but will be faster on incompressible data
|
||||
/// Increasing this value will make the algorithm search more before declaring a segment "incompressible"
|
||||
/// This could improve compression a bit, but will be slower on incompressible data
|
||||
/// The default value (6) is recommended.
|
||||
/// </summary>
|
||||
private const int NOTCOMPRESSIBLE_DETECTIONLEVEL = 6;
|
||||
|
||||
#endregion
|
||||
|
||||
#region consts
|
||||
|
||||
private const int MINMATCH = 4;
|
||||
|
||||
#pragma warning disable 162, 429
|
||||
|
||||
private const int SKIPSTRENGTH = NOTCOMPRESSIBLE_DETECTIONLEVEL > 2 ? NOTCOMPRESSIBLE_DETECTIONLEVEL : 2;
|
||||
#pragma warning restore 162, 429
|
||||
|
||||
private const int COPYLENGTH = 8;
|
||||
private const int LASTLITERALS = 5;
|
||||
private const int MFLIMIT = COPYLENGTH + MINMATCH;
|
||||
private const int MINLENGTH = MFLIMIT + 1;
|
||||
private const int MAXD_LOG = 16;
|
||||
private const int MAXD = 1 << MAXD_LOG;
|
||||
private const int MAXD_MASK = MAXD - 1;
|
||||
private const int MAX_DISTANCE = (1 << MAXD_LOG) - 1;
|
||||
private const int ML_BITS = 4;
|
||||
private const int ML_MASK = (1 << ML_BITS) - 1;
|
||||
private const int RUN_BITS = 8 - ML_BITS;
|
||||
private const int RUN_MASK = (1 << RUN_BITS) - 1;
|
||||
private const int STEPSIZE_64 = 8;
|
||||
private const int STEPSIZE_32 = 4;
|
||||
|
||||
private const int LZ4_64KLIMIT = (1 << 16) + (MFLIMIT - 1);
|
||||
|
||||
private const int HASH_LOG = MEMORY_USAGE - 2;
|
||||
private const int HASH_TABLESIZE = 1 << HASH_LOG;
|
||||
private const int HASH_ADJUST = (MINMATCH * 8) - HASH_LOG;
|
||||
|
||||
private const int HASH64K_LOG = HASH_LOG + 1;
|
||||
private const int HASH64K_TABLESIZE = 1 << HASH64K_LOG;
|
||||
private const int HASH64K_ADJUST = (MINMATCH * 8) - HASH64K_LOG;
|
||||
|
||||
private const int HASHHC_LOG = MAXD_LOG - 1;
|
||||
private const int HASHHC_TABLESIZE = 1 << HASHHC_LOG;
|
||||
private const int HASHHC_ADJUST = (MINMATCH * 8) - HASHHC_LOG;
|
||||
////private const int HASHHC_MASK = HASHHC_TABLESIZE - 1;
|
||||
|
||||
private const int MAX_NB_ATTEMPTS = 256;
|
||||
private const int OPTIMAL_ML = ML_MASK - 1 + MINMATCH;
|
||||
|
||||
private const int BLOCK_COPY_LIMIT = 16;
|
||||
|
||||
private static readonly int[] DECODER_TABLE_32 = { 0, 3, 2, 3, 0, 0, 0, 0 };
|
||||
private static readonly int[] DECODER_TABLE_64 = { 0, 0, 0, -1, 0, 1, 2, 3 };
|
||||
|
||||
private static readonly int[] DEBRUIJN_TABLE_32 =
|
||||
{
|
||||
0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1,
|
||||
3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1,
|
||||
};
|
||||
|
||||
private static readonly int[] DEBRUIJN_TABLE_64 =
|
||||
{
|
||||
0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7,
|
||||
0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7,
|
||||
7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6,
|
||||
7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7,
|
||||
};
|
||||
|
||||
#endregion
|
||||
|
||||
#region public interface (common)
|
||||
|
||||
/// <summary>Gets maximum the length of the output.</summary>
|
||||
/// <param name="inputLength">Length of the input.</param>
|
||||
/// <returns>Maximum number of bytes needed for compressed buffer.</returns>
|
||||
public static int MaximumOutputLength(int inputLength)
|
||||
{
|
||||
return inputLength + (inputLength / 255) + 16;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region internal interface (common)
|
||||
|
||||
internal static void CheckArguments(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, int outputLength)
|
||||
{
|
||||
if (inputLength == 0)
|
||||
{
|
||||
outputLength = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (input == null)
|
||||
{
|
||||
throw new ArgumentNullException("input");
|
||||
}
|
||||
|
||||
if ((uint)inputOffset > (uint)input.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("inputOffset");
|
||||
}
|
||||
|
||||
if ((uint)inputLength > (uint)input.Length - (uint)inputOffset)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("inputLength");
|
||||
}
|
||||
|
||||
if (output == null)
|
||||
{
|
||||
throw new ArgumentNullException("output");
|
||||
}
|
||||
|
||||
if ((uint)outputOffset > (uint)output.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("outputOffset");
|
||||
}
|
||||
|
||||
if ((uint)outputLength > (uint)output.Length - (uint)outputOffset)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("outputLength");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b67a7760eb98ee768b90af4f2d6d9dc4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue