This commit is contained in:
neuecc 2017-03-09 23:38:13 +09:00
Родитель 23674873e0
Коммит bf5f2dd91b
28 изменённых файлов: 2301 добавлений и 104 удалений

Просмотреть файл

@ -16,6 +16,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{344DC89D-8
.gitignore = .gitignore
make_unity_symlink.bat = make_unity_symlink.bat
nuget\MessagePack.ImmutableCollection.nuspec = nuget\MessagePack.ImmutableCollection.nuspec
nuget\MessagePack.LZ4.nuspec = nuget\MessagePack.LZ4.nuspec
nuget\MessagePack.nuspec = nuget\MessagePack.nuspec
nuget\MessagePack.ReactiveProperty.nuspec = nuget\MessagePack.ReactiveProperty.nuspec
nuget\MessagePack.UnityShims.nuspec = nuget\MessagePack.UnityShims.nuspec

Просмотреть файл

@ -3,7 +3,7 @@ MessagePack for C#(.NET, .NET Core, Unity, Xamarin)
> TODO:Writing document now.
Extremely fast [MessagePack](http://msgpack.org/) serializer for C#, x10~20 faster than MsgPack-Cli and acquires best performance compared with all the other C# serializers. Performance is always important! for Game, Distributed Computing, MicroServices, Store Data to Redis, etc.
Extremely fast [MessagePack](http://msgpack.org/) serializer for C#, x10~20 faster than MsgPack-Cli and acquires best performance compared with all the other C# serializers. Built-in LZ4 compression extension can achieve super fast and small binary size. Performance is always important! for Game, Distributed Computing, MicroServices, Store Data to Redis, etc.
![image](https://cloud.githubusercontent.com/assets/46207/23487810/e263277a-ff2b-11e6-81a6-6b4ca7acd8e3.png)
@ -30,6 +30,7 @@ Install-Package MessagePackAnalyzer
Extension Packages(info is see extension section).
```
Install-Package MessagePack.LZ4
Install-Package MessagePack.ImmutableCollection
Install-Package MessagePack.ReactiveProperty
Install-Package MessagePack.UnityShims
@ -131,6 +132,8 @@ Performance
TODO:
// LZ4 result
Extensions
---

Просмотреть файл

@ -18,3 +18,7 @@ mklink ".\src\MessagePack.UnityClient\Assets\Scripts\MessagePack\Unity\Formatter
mklink ".\src\MessagePack.UnityClient\Assets\Scripts\MessagePack\UnsafeExtensions\UnityBlitResolver.cs" "..\..\..\..\..\MessagePack.UnityShims\Extension\UnityBlitResolver.cs"
mklink ".\src\MessagePack.UnityClient\Assets\Scripts\MessagePack\UnsafeExtensions\UnsafeBlitFormatter.cs" "..\..\..\..\..\MessagePack.UnityShims\Extension\UnsafeBlitFormatter.cs"
mklink ".\src\MessagePack.UnityClient\Assets\Scripts\Tests\Class1.cs" "..\..\..\..\..\sandbox\SharedData\Class1.cs"
mklink /D ".\src\MessagePack.UnityClient\Assets\Scripts\MessagePack\LZ4\Codec" "..\..\..\..\..\MessagePack.LZ4\LZ4\Codec"
mklink ".\src\MessagePack.UnityClient\Assets\Scripts\MessagePack\LZ4\LZ4MessagePackSerializer.cs" "..\..\..\..\..\MessagePack.LZ4\LZ4MessagePackSerializer.cs"
mklink ".\src\MessagePack.UnityClient\Assets\Scripts\MessagePack\LZ4\LZ4MessagePackSerializer.JSON.cs" "..\..\..\..\..\MessagePack.LZ4\LZ4MessagePackSerializer.JSON.cs"
mklink ".\src\MessagePack.UnityClient\Assets\Scripts\MessagePack\LZ4\LZ4MessagePackSerializer.NonGeneric.cs" "..\..\..\..\..\MessagePack.LZ4\LZ4MessagePackSerializer.NonGeneric.cs"

Просмотреть файл

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MessagePack.ImmutableCollection</id>
<version>0.7.2</version>
<version>0.8.1</version>
<title>MessagePack for C# Extension Support for ImmutableCollection</title>
<authors>neuecc</authors>
<owners>neuecc</owners>
@ -17,11 +17,11 @@
</frameworkAssemblies>
<dependencies>
<group targetFramework=".NETFramework4.5">
<dependency id="MessagePack" version="0.7.2" />
<dependency id="MessagePack" version="0.8.1" />
<dependency id="System.Collections.Immutable" version="1.3.1" />
</group>
<group targetFramework=".NETStandard1.4">
<dependency id="MessagePack" version="0.7.2" />
<dependency id="MessagePack" version="0.8.1" />
<dependency id="System.Collections.Immutable" version="1.3.1" />
</group>
</dependencies>

Просмотреть файл

@ -0,0 +1,33 @@
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MessagePack.LZ4</id>
<version>0.8.1</version>
<title>MessagePack for C#, LZ4 Compression Support</title>
<authors>neuecc</authors>
<owners>neuecc</owners>
<projectUrl>https://github.com/neuecc/MessagePack-CSharp/</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Extremely Fast MessagePack Serializer for C#(.NET, .NET Core, Unity), LZ4 Compression Support.</description>
<releaseNotes>Initial LZ4 Extension.</releaseNotes>
<tags>MsgPack, MessagePack, Serialization, Formatter, Serializer, LZ4, Compression</tags>
<frameworkAssemblies>
<frameworkAssembly assemblyName="System" targetFramework=".NETFramework4.5" />
<frameworkAssembly assemblyName="System.Core" targetFramework=".NETFramework4.5" />
</frameworkAssemblies>
<dependencies>
<group targetFramework=".NETFramework4.5">
<dependency id="MessagePack" version="0.8.1" />
</group>
<group targetFramework=".NETStandard1.4">
<dependency id="MessagePack" version="0.8.1" />
</group>
</dependencies>
</metadata>
<files>
<file src="..\src\MessagePack.LZ4\bin\Release\netstandard1.4\MessagePack.LZ4.dll" target="lib\net45" />
<file src="..\src\MessagePack.LZ4\bin\Release\netstandard1.4\MessagePack.LZ4.xml" target="lib\net45" />
<file src="..\src\MessagePack.LZ4\bin\Release\netstandard1.4\MessagePack.LZ4.dll" target="lib\netstandard1.4" />
<file src="..\src\MessagePack.LZ4\bin\Release\netstandard1.4\MessagePack.LZ4.xml" target="lib\netstandard1.4" />
</files>
</package>

Просмотреть файл

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MessagePack.ReactiveProperty</id>
<version>0.7.2</version>
<version>0.8.1</version>
<title>MessagePack for C# Extension Support for ReactiveProperty</title>
<authors>neuecc</authors>
<owners>neuecc</owners>
@ -17,11 +17,11 @@
</frameworkAssemblies>
<dependencies>
<group targetFramework=".NETFramework4.5">
<dependency id="MessagePack" version="0.7.2" />
<dependency id="MessagePack" version="0.8.1" />
<dependency id="ReactiveProperty" version="3.5.1" />
</group>
<group targetFramework=".NETStandard1.4">
<dependency id="MessagePack" version="0.7.2" />
<dependency id="MessagePack" version="0.8.1" />
<dependency id="ReactiveProperty" version="3.5.1" />
</group>
</dependencies>

Просмотреть файл

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MessagePack.UnityShims</id>
<version>0.7.2</version>
<version>0.8.1</version>
<title>MessagePack for C# Extension Support for Unity(add pseudo Vector type and fast Vectory[] extension formatter)</title>
<authors>neuecc</authors>
<owners>neuecc</owners>
@ -17,10 +17,10 @@
</frameworkAssemblies>
<dependencies>
<group targetFramework=".NETFramework4.5">
<dependency id="MessagePack" version="0.7.2" />
<dependency id="MessagePack" version="0.8.1" />
</group>
<group targetFramework=".NETStandard1.4">
<dependency id="MessagePack" version="0.7.2" />
<dependency id="MessagePack" version="0.8.1" />
</group>
</dependencies>
</metadata>

Просмотреть файл

@ -2,14 +2,14 @@
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
<metadata>
<id>MessagePack</id>
<version>0.7.2</version>
<version>0.8.1</version>
<title>MessagePack for C#</title>
<authors>neuecc</authors>
<owners>neuecc</owners>
<projectUrl>https://github.com/neuecc/MessagePack-CSharp/</projectUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Extremely Fast MessagePack Serializer for C#(.NET, .NET Core, Unity).</description>
<releaseNotes>improve code generator.</releaseNotes>
<releaseNotes>for supports LZ4.</releaseNotes>
<tags>MsgPack, MessagePack, Serialization, Formatter, Serializer</tags>
<frameworkAssemblies>
<frameworkAssembly assemblyName="System" targetFramework=".NETFramework4.5" />

Просмотреть файл

@ -2,4 +2,5 @@ nuget pack MessagePack.nuspec
nuget pack MessagePack.ImmutableCollection.nuspec
nuget pack MessagePack.ReactiveProperty.nuspec
nuget pack MessagePack.UnityShims.nuspec
nuget pack MessagePack.LZ4.nuspec
nuget pack MessagePackAnalyzer.nuspec

Просмотреть файл

@ -1,5 +1,6 @@
nuget push MessagePack.0.7.2.nupkg -Source https://www.nuget.org/api/v2/package
nuget push MessagePack.ImmutableCollection.0.7.2.nupkg -Source https://www.nuget.org/api/v2/package
nuget push MessagePack.ReactiveProperty.0.7.2.nupkg -Source https://www.nuget.org/api/v2/package
nuget push MessagePack.UnityShims.0.7.2.nupkg -Source https://www.nuget.org/api/v2/package
nuget push MessagePack.0.8.1.nupkg -Source https://www.nuget.org/api/v2/package
nuget push MessagePack.ImmutableCollection.0.8.1.nupkg -Source https://www.nuget.org/api/v2/package
nuget push MessagePack.ReactiveProperty.0.8.1.nupkg -Source https://www.nuget.org/api/v2/package
nuget push MessagePack.UnityShims.0.8.1.nupkg -Source https://www.nuget.org/api/v2/package
nuget push MessagePack.LZ4.0.8.1.nupkg -Source https://www.nuget.org/api/v2/package
REM nuget push MessagePackAnalyzer.1.3.0.nupkg -Source https://www.nuget.org/api/v2/package

Просмотреть файл

@ -120,11 +120,8 @@ namespace Sandbox
Benchmark(p);
Console.WriteLine();
Benchmark(l);
//var json = MessagePackSerializer.ToJson(MessagePackSerializer.NonGeneric.Serialize(typeof(Person), p));
//Console.WriteLine(json);
}
static void Benchmark<T>(T target)
{
const int Iteration = 10000; // 10000

Просмотреть файл

@ -0,0 +1,87 @@
#if ENABLE_UNSAFE_RESOLVER
using System;
namespace LZ4
{
internal static partial class LZ4Codec
{
public static int Encode(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, int outputLength)
{
if (IntPtr.Size == 4)
{
return LZ4Codec.Encode32(input, inputOffset, inputLength, output, outputOffset, outputLength);
}
else
{
return LZ4Codec.Encode64(input, inputOffset, inputLength, output, outputOffset, outputLength);
}
}
public static int Decode(byte[] input, int inputOffset, int inputLength, byte[] output, int outputOffset, int outputLength, bool knownOutputLength)
{
if (IntPtr.Size == 4)
{
return LZ4Codec.Decode32(input, inputOffset, inputLength, output, outputOffset, outputLength, knownOutputLength);
}
else
{
return LZ4Codec.Decode64(input, inputOffset, inputLength, output, outputOffset, outputLength, knownOutputLength);
}
}
internal unsafe static class Pool
{
[ThreadStatic]
static ushort[] ushortPool;
[ThreadStatic]
static uint[] uintPool;
[ThreadStatic]
static byte*[] bytePool;
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 byte*[] GetByteHashTablePool()
{
if (bytePool == null)
{
bytePool = new byte*[HASH_TABLESIZE];
}
else
{
Array.Clear(bytePool, 0, bytePool.Length);
}
return bytePool;
}
}
}
}
#endif

Просмотреть файл

@ -0,0 +1,397 @@
#if ENABLE_UNSAFE_RESOLVER
#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 LZ4
{
/// <summary>Unsafe LZ4 codec.</summary>
internal static partial class LZ4Codec
{
/// <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 BlockCopy(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--; */
}
}
#region Encode32
/// <summary>Encodes the specified input.</summary>
/// <param name="input">The input.</param>
/// <param name="output">The output.</param>
/// <param name="inputLength">Length of the input.</param>
/// <param name="outputLength">Length of the output.</param>
/// <returns>Number of bytes written.</returns>
public static unsafe int Encode32(
byte* input,
byte* output,
int inputLength,
int outputLength)
{
if (inputLength < LZ4_64KLIMIT)
{
var hashTable = Pool.GetUShortHashTablePool();
fixed (ushort* h = &hashTable[0])
{
return LZ4_compress64kCtx_32(h, input, output, inputLength, outputLength);
}
}
else
{
var hashTable = new byte*[HASH_TABLESIZE];
fixed (byte** h = &hashTable[0])
{
return LZ4_compressCtx_32(h, input, output, 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 unsafe int Encode32(
byte[] input,
int inputOffset,
int inputLength,
byte[] output,
int outputOffset,
int outputLength)
{
CheckArguments(
input, inputOffset, ref inputLength,
output, outputOffset, ref outputLength);
if (outputLength == 0) return 0;
fixed (byte* inputPtr = &input[inputOffset])
fixed (byte* outputPtr = &output[outputOffset])
{
return Encode32(inputPtr, outputPtr, 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>
/// <returns>Compressed buffer.</returns>
public static byte[] Encode32(byte[] input, int inputOffset, int inputLength)
{
if (inputLength < 0) inputLength = input.Length - inputOffset;
if (input == null) throw new ArgumentNullException("input");
if (inputOffset < 0 || inputOffset + inputLength > input.Length)
throw new ArgumentException("inputOffset and inputLength are invalid for given input");
var result = new byte[MaximumOutputLength(inputLength)];
var length = Encode32(input, inputOffset, inputLength, result, 0, result.Length);
if (length != result.Length)
{
if (length < 0)
throw new InvalidOperationException("Compression has been corrupted");
var buffer = new byte[length];
Buffer.BlockCopy(result, 0, buffer, 0, length);
return buffer;
}
return result;
}
#endregion
#region Decode32
/// <summary>Decodes the specified input.</summary>
/// <param name="input">The input.</param>
/// <param name="inputLength">Length of the input.</param>
/// <param name="output">The output.</param>
/// <param name="outputLength">Length of the output.</param>
/// <param name="knownOutputLength">Set it to <c>true</c> if output length is known.</param>
/// <returns>Number of bytes written.</returns>
public static unsafe int Decode32(
byte* input,
int inputLength,
byte* output,
int outputLength,
bool knownOutputLength)
{
if (knownOutputLength)
{
var length = LZ4_uncompress_32(input, output, outputLength);
if (length != inputLength)
throw new ArgumentException("LZ4 block is corrupted, or invalid length has been given.");
return outputLength;
}
else
{
throw new InvalidOperationException("MessagePack.LZ4 impl only supports 'true'.");
}
}
/// <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>
/// <param name="knownOutputLength">Set it to <c>true</c> if output length is known.</param>
/// <returns>Number of bytes written.</returns>
public static unsafe int Decode32(
byte[] input,
int inputOffset,
int inputLength,
byte[] output,
int outputOffset,
int outputLength,
bool knownOutputLength)
{
CheckArguments(
input, inputOffset, ref inputLength,
output, outputOffset, ref outputLength);
if (outputLength == 0) return 0;
fixed (byte* inputPtr = &input[inputOffset])
fixed (byte* outputPtr = &output[outputOffset])
{
return Decode32(inputPtr, inputLength, outputPtr, outputLength, knownOutputLength);
}
}
/// <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="outputLength">Length of the output.</param>
/// <returns>Decompressed buffer.</returns>
public static byte[] Decode32(byte[] input, int inputOffset, int inputLength, int outputLength)
{
if (inputLength < 0) inputLength = input.Length - inputOffset;
if (input == null) throw new ArgumentNullException("input");
if (inputOffset < 0 || inputOffset + inputLength > input.Length)
throw new ArgumentException("inputOffset and inputLength are invalid for given input");
var result = new byte[outputLength];
var length = Decode32(input, inputOffset, inputLength, result, 0, outputLength, true);
if (length != outputLength)
throw new ArgumentException("outputLength is not valid");
return result;
}
#endregion
#region Encode64
/// <summary>Encodes the specified input.</summary>
/// <param name="input">The input.</param>
/// <param name="output">The output.</param>
/// <param name="inputLength">Length of the input.</param>
/// <param name="outputLength">Length of the output.</param>
/// <returns>Number of bytes written.</returns>
public static unsafe int Encode64(
byte* input,
byte* output,
int inputLength,
int outputLength)
{
if (inputLength < LZ4_64KLIMIT)
{
var hashTable = Pool.GetUShortHashTablePool();
fixed (ushort* h = &hashTable[0])
{
return LZ4_compress64kCtx_64(h, input, output, inputLength, outputLength);
}
}
else
{
var hashTable = Pool.GetUIntHashTablePool();
fixed (uint* h = &hashTable[0])
{
return LZ4_compressCtx_64(h, input, output, 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 unsafe int Encode64(
byte[] input,
int inputOffset,
int inputLength,
byte[] output,
int outputOffset,
int outputLength)
{
CheckArguments(
input, inputOffset, ref inputLength,
output, outputOffset, ref outputLength);
if (outputLength == 0) return 0;
fixed (byte* inputPtr = &input[inputOffset])
fixed (byte* outputPtr = &output[outputOffset])
{
return Encode64(inputPtr, outputPtr, 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>
/// <returns>Compressed buffer.</returns>
public static byte[] Encode64(byte[] input, int inputOffset, int inputLength)
{
if (inputLength < 0) inputLength = input.Length - inputOffset;
if (input == null) throw new ArgumentNullException("input");
if (inputOffset < 0 || inputOffset + inputLength > input.Length)
throw new ArgumentException("inputOffset and inputLength are invalid for given input");
var result = new byte[MaximumOutputLength(inputLength)];
var length = Encode64(input, inputOffset, inputLength, result, 0, result.Length);
if (length != result.Length)
{
if (length < 0)
throw new InvalidOperationException("Compression has been corrupted");
var buffer = new byte[length];
Buffer.BlockCopy(result, 0, buffer, 0, length);
return buffer;
}
return result;
}
#endregion
#region Decode64
/// <summary>Decodes the specified input.</summary>
/// <param name="input">The input.</param>
/// <param name="inputLength">Length of the input.</param>
/// <param name="output">The output.</param>
/// <param name="outputLength">Length of the output.</param>
/// <param name="knownOutputLength">Set it to <c>true</c> if output length is known.</param>
/// <returns>Number of bytes written.</returns>
public static unsafe int Decode64(
byte* input,
int inputLength,
byte* output,
int outputLength,
bool knownOutputLength)
{
if (knownOutputLength)
{
var length = LZ4_uncompress_64(input, output, outputLength);
if (length != inputLength)
throw new ArgumentException("LZ4 block is corrupted, or invalid length has been given.");
return outputLength;
}
else
{
throw new InvalidOperationException("MessagePack.LZ4 impl only supports 'true'.");
}
}
/// <summary>Decode64s 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>
/// <param name="knownOutputLength">Set it to <c>true</c> if output length is known.</param>
/// <returns>Number of bytes written.</returns>
public static unsafe int Decode64(
byte[] input,
int inputOffset,
int inputLength,
byte[] output,
int outputOffset,
int outputLength,
bool knownOutputLength)
{
CheckArguments(
input, inputOffset, ref inputLength,
output, outputOffset, ref outputLength);
if (outputLength == 0) return 0;
fixed (byte* inputPtr = &input[inputOffset])
fixed (byte* outputPtr = &output[outputOffset])
{
return Decode64(inputPtr, inputLength, outputPtr, outputLength, knownOutputLength);
}
}
#endregion
}
}
#endif

Просмотреть файл

@ -0,0 +1,672 @@
#if ENABLE_UNSAFE_RESOLVER
#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
// ReSharper disable InconsistentNaming
// ReSharper disable TooWideLocalVariableScope
// ReSharper disable JoinDeclarationAndInitializer
namespace LZ4
{
internal static partial class LZ4Codec
{
#region LZ4_compressCtx_32
private static unsafe int LZ4_compressCtx_32(
byte** hash_table,
byte* src,
byte* dst,
int src_len,
int dst_maxlen)
{
byte* _p;
fixed (int* debruijn32 = &DEBRUIJN_TABLE_32[0])
{
// r93
var src_p = src;
const int src_base = 0;
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)] = (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] = (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;
BlockCopy(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)] = (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] = (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);
BlockCopy(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)
{
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;
BlockCopy(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);
BlockCopy(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)
{
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
BlockCopy(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
}
}
// ReSharper restore JoinDeclarationAndInitializer
// ReSharper restore TooWideLocalVariableScope
// ReSharper restore InconsistentNaming
#endif

Просмотреть файл

@ -0,0 +1,673 @@
#if ENABLE_UNSAFE_RESOLVER
#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
// ReSharper disable InconsistentNaming
// ReSharper disable TooWideLocalVariableScope
// ReSharper disable JoinDeclarationAndInitializer
namespace LZ4
{
internal static 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)
{
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;
BlockCopy(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);
BlockCopy(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)
{
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;
BlockCopy(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);
BlockCopy(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)
{
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
BlockCopy(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
}
}
// ReSharper restore JoinDeclarationAndInitializer
// ReSharper restore TooWideLocalVariableScope
// ReSharper restore InconsistentNaming
#endif

Просмотреть файл

@ -0,0 +1,162 @@
#if ENABLE_UNSAFE_RESOLVER
#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;
// ReSharper disable InconsistentNaming
namespace 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 = 14;
/// <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
// ReSharper disable once UnreachableCode
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 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
};
private const int MAX_NB_ATTEMPTS = 256;
private const int OPTIMAL_ML = (ML_MASK - 1) + MINMATCH;
#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, ref int inputLength,
byte[] output, int outputOffset, ref int outputLength)
{
if (inputLength < 0) inputLength = input.Length - inputOffset;
if (inputLength == 0)
{
outputLength = 0;
return;
}
if (input == null) throw new ArgumentNullException("input");
if (inputOffset < 0 || inputOffset + inputLength > input.Length)
throw new ArgumentException("inputOffset and inputLength are invalid for given input");
if (outputLength < 0) outputLength = output.Length - outputOffset;
if (output == null) throw new ArgumentNullException("output");
if (outputOffset < 0 || outputOffset + outputLength > output.Length)
throw new ArgumentException("outputOffset and outputLength are invalid for given output");
}
#endregion
}
}
// ReSharper restore InconsistentNaming
#endif

Просмотреть файл

@ -1,4 +1,6 @@
using System;
#if ENABLE_UNSAFE_RESOLVER
using System;
using System.Globalization;
using System.Text;
@ -37,7 +39,7 @@ namespace MessagePack
if (header.TypeCode == ExtensionTypeCode)
{
// decode lz4
var offset = checked((int)header.Length);
var offset = readSize;
var length = MessagePackBinary.ReadInt32(bytes, offset, out readSize);
offset += readSize;
@ -227,3 +229,5 @@ namespace MessagePack
}
}
}
#endif

Просмотреть файл

@ -1,4 +1,7 @@
using System;
#if ENABLE_UNSAFE_RESOLVER
#if NETSTANDARD1_4
using System;
using System.Linq;
using System.Reflection;
using System.IO;
@ -208,3 +211,6 @@ namespace MessagePack
}
}
}
#endif
#endif

Просмотреть файл

@ -1,61 +1,25 @@
using System;
#if ENABLE_UNSAFE_RESOLVER
using System;
using System.IO;
namespace MessagePack
{
/// <summary>
/// LZ4 Compressed special serializer.
/// LZ4 Compressed special serializer. Same API as MessagePackSerialzier but DefaultResolver is used MessagePackSerializer.DefaultResolver.
/// </summary>
public static partial class LZ4MessagePackSerializer
{
public const byte ExtensionTypeCode = 99;
public const sbyte ExtensionTypeCode = 99;
public const int MinSize = 50;
static IFormatterResolver defaultResolver;
/// <summary>
/// FormatterResolver that used resolver less overloads. If does not set it, used StandardResolver.
/// </summary>
public static IFormatterResolver DefaultResolver
{
get
{
if (defaultResolver == null)
{
defaultResolver = MessagePack.Resolvers.StandardResolver.Instance;
}
return defaultResolver;
}
}
/// <summary>
/// Is resolver decided?
/// </summary>
public static bool IsInitialized
{
get
{
return defaultResolver != null;
}
}
/// <summary>
/// Set default resolver of MessagePackSerializer APIs.
/// </summary>
/// <param name="resolver"></param>
public static void SetDefaultResolver(IFormatterResolver resolver)
{
defaultResolver = resolver;
}
public const int NotCompressionSize = 64;
/// <summary>
/// Serialize to binary with default resolver.
/// </summary>
public static byte[] Serialize<T>(T obj)
{
return Serialize(obj, defaultResolver);
return Serialize(obj, MessagePackSerializer.DefaultResolver);
}
/// <summary>
@ -63,7 +27,7 @@ namespace MessagePack
/// </summary>
public static byte[] Serialize<T>(T obj, IFormatterResolver resolver)
{
if (resolver == null) resolver = DefaultResolver;
if (resolver == null) resolver = MessagePackSerializer.DefaultResolver;
var buffer = SerializeCore(obj, resolver);
return MessagePackBinary.FastCloneWithResize(buffer.Array, buffer.Count);
@ -74,7 +38,7 @@ namespace MessagePack
/// </summary>
public static void Serialize<T>(Stream stream, T obj)
{
Serialize(stream, obj, defaultResolver);
Serialize(stream, obj, MessagePackSerializer.DefaultResolver);
}
/// <summary>
@ -82,7 +46,7 @@ namespace MessagePack
/// </summary>
public static void Serialize<T>(Stream stream, T obj, IFormatterResolver resolver)
{
if (resolver == null) resolver = DefaultResolver;
if (resolver == null) resolver = MessagePackSerializer.DefaultResolver;
var buffer = SerializeCore(obj, resolver);
stream.Write(buffer.Array, 0, buffer.Count);
@ -90,11 +54,9 @@ namespace MessagePack
static ArraySegment<byte> SerializeCore<T>(T obj, IFormatterResolver resolver)
{
var formatter = resolver.GetFormatterWithVerify<T>();
var serializedData = MessagePackSerializer.SerializeUnsafe(obj, resolver);
if (serializedData.Count < MinSize)
if (serializedData.Count < NotCompressionSize)
{
return serializedData;
}
@ -115,7 +77,7 @@ namespace MessagePack
offset += MessagePackBinary.WriteInt32ForceInt32Block(ref buffer, offset, serializedData.Count);
// write body
var lz4Length = global::LZ4.LZ4Codec.Encode(serializedData.Array, serializedData.Offset, serializedData.Count, buffer, offset, serializedData.Count);
var lz4Length = global::LZ4.LZ4Codec.Encode(serializedData.Array, serializedData.Offset, serializedData.Count, buffer, offset, buffer.Length - offset);
return new ArraySegment<byte>(buffer, 0, lz4Length + offset);
}
@ -123,56 +85,63 @@ namespace MessagePack
public static T Deserialize<T>(byte[] bytes)
{
return Deserialize<T>(bytes, defaultResolver);
return Deserialize<T>(bytes, MessagePackSerializer.DefaultResolver);
}
public static T Deserialize<T>(byte[] bytes, IFormatterResolver resolver)
{
if (resolver == null) resolver = DefaultResolver;
if (resolver == null) resolver = MessagePackSerializer.DefaultResolver;
return DeserializeCore<T>(new ArraySegment<byte>(bytes, 0, bytes.Length), resolver);
}
public static T Deserialize<T>(Stream stream)
{
return Deserialize<T>(stream, MessagePackSerializer.DefaultResolver);
}
public static T Deserialize<T>(Stream stream, IFormatterResolver resolver)
{
if (resolver == null) resolver = MessagePackSerializer.DefaultResolver;
var buffer = InternalMemoryPool.GetBuffer();
var len = FillFromStream(stream, ref buffer);
// note, current lz4impl needs to fit input byte[]...
var newBytes = MessagePackBinary.FastCloneWithResize(buffer, len);
return DeserializeCore<T>(new ArraySegment<byte>(newBytes, 0, newBytes.Length), resolver);
}
static T DeserializeCore<T>(ArraySegment<byte> bytes, IFormatterResolver resolver)
{
var formatter = resolver.GetFormatterWithVerify<T>();
int readSize;
if (MessagePackBinary.GetMessagePackType(bytes, 0) == MessagePackType.Extension)
if (MessagePackBinary.GetMessagePackType(bytes.Array, 0) == MessagePackType.Extension)
{
var header = MessagePackBinary.ReadExtensionFormatHeader(bytes, 0, out readSize);
var header = MessagePackBinary.ReadExtensionFormatHeader(bytes.Array, bytes.Offset, out readSize);
if (header.TypeCode == ExtensionTypeCode)
{
// decode lz4
var offset = readSize;
var length = MessagePackBinary.ReadInt32(bytes, offset, out readSize);
var offset = bytes.Offset + readSize;
var length = MessagePackBinary.ReadInt32(bytes.Array, offset, out readSize);
offset += readSize;
var buffer = InternalMemoryPool.GetBuffer();
if (!(buffer.Length < length))
if (buffer.Length < length)
{
buffer = new byte[length];
}
// LZ4 Decode
global::LZ4.LZ4Codec.Decode(bytes, offset, bytes.Length - offset, buffer, 0, length, true);
global::LZ4.LZ4Codec.Decode(bytes.Array, offset, bytes.Count - offset, buffer, 0, length, true);
return formatter.Deserialize(buffer, 0, resolver, out readSize);
}
}
return formatter.Deserialize(bytes, 0, resolver, out readSize);
}
public static T Deserialize<T>(Stream stream)
{
return Deserialize<T>(stream, defaultResolver);
}
public static T Deserialize<T>(Stream stream, IFormatterResolver resolver)
{
if (resolver == null) resolver = DefaultResolver;
var formatter = resolver.GetFormatterWithVerify<T>();
var buffer = InternalMemoryPool.GetBuffer();
FillFromStream(stream, ref buffer);
return Deserialize<T>(buffer, resolver);
return formatter.Deserialize(bytes.Array, bytes.Offset, resolver, out readSize);
}
static int FillFromStream(Stream input, ref byte[] buffer)
@ -207,3 +176,6 @@ namespace MessagePack
}
}
}
#endif

Просмотреть файл

@ -1,16 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard1.6</TargetFramework>
<TargetFramework>netstandard1.4</TargetFramework>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<DefineConstants>TRACE;RELEASE;NETSTANDARD1_6</DefineConstants>
<DefineConstants>TRACE;RELEASE;NETSTANDARD1_4;ENABLE_UNSAFE_RESOLVER;</DefineConstants>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<OutputPath>bin\Release\netstandard1.4\</OutputPath>
<DocumentationFile>bin\Release\netstandard1.4\MessagePack.LZ4.xml</DocumentationFile>
<NoWarn>1701;1702;1705;1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="lz4net" Version="1.0.11.93" />
</ItemGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<DefineConstants>TRACE;DEBUG;NETSTANDARD1_4;ENABLE_UNSAFE_RESOLVER;</DefineConstants>
<OutputPath>bin\Debug\netstandard1.4\</OutputPath>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MessagePack\MessagePack.csproj" />

Просмотреть файл

@ -0,0 +1 @@
../../../../../MessagePack.LZ4/LZ4/Codec

Просмотреть файл

@ -0,0 +1 @@
../../../../../MessagePack.LZ4/LZ4MessagePackSerializer.JSON.cs

Просмотреть файл

@ -0,0 +1 @@
../../../../../MessagePack.LZ4/LZ4MessagePackSerializer.NonGeneric.cs

Просмотреть файл

@ -0,0 +1 @@
../../../../../MessagePack.LZ4/LZ4MessagePackSerializer.cs

Просмотреть файл

@ -100,6 +100,14 @@
<Compile Include="Assets\Scripts\MessagePack\Internal\DynamicAssembly.cs" />
<Compile Include="Assets\Scripts\MessagePack\Internal\ILGeneratorExtensions.cs" />
<Compile Include="Assets\Scripts\MessagePack\Internal\ReflectionExtensions.cs" />
<Compile Include="Assets\Scripts\MessagePack\LZ4\Codec\LZ4Codec.Helper.cs" />
<Compile Include="Assets\Scripts\MessagePack\LZ4\Codec\LZ4Codec.Unsafe.cs" />
<Compile Include="Assets\Scripts\MessagePack\LZ4\Codec\LZ4Codec.Unsafe32.Dirty.cs" />
<Compile Include="Assets\Scripts\MessagePack\LZ4\Codec\LZ4Codec.Unsafe64.Dirty.cs" />
<Compile Include="Assets\Scripts\MessagePack\LZ4\Codec\LZ4Codec.cs" />
<Compile Include="Assets\Scripts\MessagePack\LZ4\LZ4MessagePackSerializer.JSON.cs" />
<Compile Include="Assets\Scripts\MessagePack\LZ4\LZ4MessagePackSerializer.NonGeneric.cs" />
<Compile Include="Assets\Scripts\MessagePack\LZ4\LZ4MessagePackSerializer.cs" />
<Compile Include="Assets\Scripts\MessagePack\MessagePackBinary.cs" />
<Compile Include="Assets\Scripts\MessagePack\MessagePackCode.cs" />
<Compile Include="Assets\Scripts\MessagePack\MessagePackSerializer.Json.cs" />

Просмотреть файл

@ -0,0 +1,88 @@
using SharedData;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xunit;
namespace MessagePack.Tests.ExtensionTests
{
public class LZ4Test
{
T Convert<T>(T value)
{
var resolver = new WithImmutableDefaultResolver();
return LZ4MessagePackSerializer.Deserialize<T>(LZ4MessagePackSerializer.Serialize(value, resolver), resolver);
}
[Fact]
public void TestSmall()
{
// small size binary don't use LZ4 Encode
MessagePackBinary.GetMessagePackType(LZ4MessagePackSerializer.Serialize(100), 0).Is(MessagePackType.Integer);
MessagePackBinary.GetMessagePackType(LZ4MessagePackSerializer.Serialize("test"), 0).Is(MessagePackType.String);
MessagePackBinary.GetMessagePackType(LZ4MessagePackSerializer.Serialize(false), 0).Is(MessagePackType.Boolean);
}
[Fact]
public void CompressionData()
{
var originalData = Enumerable.Range(1, 1000).Select(x => x).ToArray();
var lz4Data = LZ4MessagePackSerializer.Serialize(originalData);
MessagePackBinary.GetMessagePackType(lz4Data, 0).Is(MessagePackType.Extension);
int r;
var header = MessagePackBinary.ReadExtensionFormatHeader(lz4Data, 0, out r);
header.TypeCode.Is((sbyte)LZ4MessagePackSerializer.ExtensionTypeCode);
var decompress = LZ4MessagePackSerializer.Deserialize<int[]>(lz4Data);
decompress.Is(originalData);
}
[Fact]
public void NonGenericAPI()
{
var originalData = Enumerable.Range(1, 100).Select(x => new FirstSimpleData { Prop1 = x * x, Prop2 = "hoge", Prop3 = x }).ToArray();
var lz4Data = LZ4MessagePackSerializer.NonGeneric.Serialize(typeof(FirstSimpleData[]), originalData);
MessagePackBinary.GetMessagePackType(lz4Data, 0).Is(MessagePackType.Extension);
int r;
var header = MessagePackBinary.ReadExtensionFormatHeader(lz4Data, 0, out r);
header.TypeCode.Is((sbyte)LZ4MessagePackSerializer.ExtensionTypeCode);
var decompress = LZ4MessagePackSerializer.NonGeneric.Deserialize(typeof(FirstSimpleData[]), lz4Data);
decompress.IsStructuralEqual(originalData);
}
[Fact]
public void StreamAPI()
{
var originalData = Enumerable.Range(1, 100).Select(x => new FirstSimpleData { Prop1 = x * x, Prop2 = "hoge", Prop3 = x }).ToArray();
var ms = new MemoryStream();
LZ4MessagePackSerializer.NonGeneric.Serialize(typeof(FirstSimpleData[]), ms, originalData);
var lz4normal = LZ4MessagePackSerializer.NonGeneric.Serialize(typeof(FirstSimpleData[]), originalData);
ms.Position = 0;
lz4normal.SequenceEqual(ms.ToArray()).IsTrue();
var decompress1 = LZ4MessagePackSerializer.NonGeneric.Deserialize(typeof(FirstSimpleData[]), ms.ToArray());
var decompress2 = LZ4MessagePackSerializer.NonGeneric.Deserialize(typeof(FirstSimpleData[]), lz4normal);
var decompress3 = LZ4MessagePackSerializer.NonGeneric.Deserialize(typeof(FirstSimpleData[]), ms);
decompress1.IsStructuralEqual(originalData);
decompress2.IsStructuralEqual(originalData);
decompress3.IsStructuralEqual(originalData);
}
}
}

Просмотреть файл

@ -29,6 +29,7 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
@ -102,6 +103,7 @@
<Compile Include="CollectionTest.cs" />
<Compile Include="DictionaryTest.cs" />
<Compile Include="ExtensionTests\ImmutableCollectionTest.cs" />
<Compile Include="ExtensionTests\LZ4Test.cs" />
<Compile Include="ExtensionTests\ReactivePropertyTest.cs" />
<Compile Include="ExtensionTests\UnityShimTest.cs" />
<Compile Include="FormatterTest.cs" />
@ -129,6 +131,10 @@
<Project>{e066f547-7261-4561-aefc-e64dbfd874f8}</Project>
<Name>MessagePack.ImmutableCollection</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\MessagePack.LZ4\MessagePack.LZ4.csproj">
<Project>{6303cd14-f396-409c-bcbf-4da3105ec45c}</Project>
<Name>MessagePack.LZ4</Name>
</ProjectReference>
<ProjectReference Include="..\..\src\MessagePack.ReactiveProperty\MessagePack.ReactiveProperty.csproj">
<Project>{166a16c0-b89f-41af-956a-235c6ca62c25}</Project>
<Name>MessagePack.ReactiveProperty</Name>

Просмотреть файл

@ -41,5 +41,77 @@ namespace MessagePack.Tests
new[] { data1.Prop2, data2.Prop2, data3.Prop2, data4.Prop2 }.Distinct().Is(data.Prop2);
new[] { data1.Prop3, data2.Prop3, data3.Prop3, data4.Prop3 }.Distinct().Is(data.Prop3);
}
[Fact]
public void StreamAPI()
{
var originalData = Enumerable.Range(1, 100).Select(x => new FirstSimpleData { Prop1 = x * x, Prop2 = "hoge", Prop3 = x }).ToArray();
var ms = new MemoryStream();
MessagePackSerializer.NonGeneric.Serialize(typeof(FirstSimpleData[]), ms, originalData);
var normal = MessagePackSerializer.NonGeneric.Serialize(typeof(FirstSimpleData[]), originalData);
ms.Position = 0;
normal.SequenceEqual(ms.ToArray()).IsTrue();
var decompress1 = MessagePackSerializer.NonGeneric.Deserialize(typeof(FirstSimpleData[]), ms.ToArray());
var decompress2 = MessagePackSerializer.NonGeneric.Deserialize(typeof(FirstSimpleData[]), normal);
var decompress3 = MessagePackSerializer.NonGeneric.Deserialize(typeof(FirstSimpleData[]), ms);
ms.Position = 0;
var onmore = new NonMemoryStream(ms);
var decompress4 = MessagePackSerializer.NonGeneric.Deserialize(typeof(FirstSimpleData[]), onmore);
decompress1.IsStructuralEqual(originalData);
decompress2.IsStructuralEqual(originalData);
decompress3.IsStructuralEqual(originalData);
decompress4.IsStructuralEqual(originalData);
}
}
class NonMemoryStream : Stream
{
readonly MemoryStream stream;
public NonMemoryStream(MemoryStream stream)
{
this.stream = stream;
}
public override bool CanRead => stream.CanRead;
public override bool CanSeek => stream.CanSeek;
public override bool CanWrite => stream.CanWrite;
public override long Length => stream.Length;
public override long Position { get => stream.Position; set => stream.Position = value; }
public override void Flush()
{
stream.Flush();
}
public override int Read(byte[] buffer, int offset, int count)
{
return stream.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return stream.Seek(offset, origin);
}
public override void SetLength(long value)
{
stream.SetLength(value);
}
public override void Write(byte[] buffer, int offset, int count)
{
stream.Write(buffer, offset, count);
}
}
}