public unsafe int Write(DateTime[] value, ref DirectBuffer destination, uint offset = 0, MemoryStream temporaryStream = null, CompressionMethod compression = CompressionMethod.DefaultOrNone) { if (compression == CompressionMethod.DefaultOrNone) { Debug.Assert(temporaryStream == null); var length = 8 + value.Length * 8; if (destination.Length < offset + length) { return((int)BinaryConverterErrorCode.NotEnoughCapacity); } for (var i = 0; i < value.Length; i++) { *(DateTime *)(destination.Data + (int)offset + 8 + i * 8) = value[i]; } destination.WriteInt32(offset, length); destination.WriteByte(offset + 4, Version); return(length); } else { return(CompressedArrayBinaryConverter <DateTime> .Instance.Write(value, 0, value.Length, ref destination, offset, temporaryStream, compression)); } }
public unsafe int Write(TElement[] value, int valueOffset, int valueCount, ref DirectBuffer destination, uint destinationOffset = 0u, MemoryStream temporaryStream = null, CompressionMethod compression = CompressionMethod.DefaultOrNone) { if (value == null) { throw new ArgumentNullException(nameof(value)); } if (temporaryStream != null) { var len = temporaryStream.Length; if (destination.Length < destinationOffset + len) { return((int)BinaryConverterErrorCode.NotEnoughCapacity); } temporaryStream.WriteToPtr(destination.Data + (int)destinationOffset); temporaryStream.Dispose(); return(checked ((int)len)); } bool isDiffable = false; var compressionMethod = compression == CompressionMethod.DefaultOrNone ? BloscSettings.defaultCompressionMethod : (compression == CompressionMethod.LZ4 ? "lz4" : "zstd"); var position = 8; if (valueCount > 0) { int compressedSize; if (ItemSize > 0) { if (typeof(TElement) == typeof(DateTime)) { var buffer = BufferPool <byte> .Rent(valueCount * 8); var dtArray = (DateTime[])(object)value; fixed(byte *srcPtr = &buffer[0]) { for (var i = 0; i < valueCount; i++) { *(DateTime *)(srcPtr + i * 8) = dtArray[i + valueOffset]; } compressedSize = BloscMethods.blosc_compress_ctx( new IntPtr(9), // max compression 9 new IntPtr(1), // do byte shuffle 1 new UIntPtr((uint)ItemSize), // type size new UIntPtr((uint)(valueCount * ItemSize)), // number of input bytes (IntPtr)srcPtr, destination.Data + position, // destination new UIntPtr((uint)(destination.Length - position)), // destination length compressionMethod, new UIntPtr((uint)0), // default block size BloscMethods.ProcessorCount // ); } BufferPool <byte> .Return(buffer); } else if (value[0] is IDiffable <TElement> diffableFirst) { isDiffable = true; // TODO (!) this is probably inefficient... some generic method caching or dynamic dispatch? // however there is only a single pattern match with IDiffable boxing var first = value[0]; var buffer = BufferPool <byte> .Rent(valueCount *ItemSize); fixed(byte *srcPtr = &buffer[0]) { Unsafe.Write(srcPtr, first); for (var i = 1; i < valueCount; i++) { var current = value[i]; var diff = diffableFirst.GetDelta(current); Unsafe.Write(srcPtr + i * ItemSize, diff); } compressedSize = BloscMethods.blosc_compress_ctx( new IntPtr(9), // max compression 9 new IntPtr(1), // do byte shuffle 1 new UIntPtr((uint)ItemSize), // type size new UIntPtr((uint)(valueCount * ItemSize)), // number of input bytes (IntPtr)srcPtr, destination.Data + position, // destination new UIntPtr((uint)(destination.Length - position)), // destination length compressionMethod, new UIntPtr((uint)0), // default block size BloscMethods.ProcessorCount // ); } BufferPool <byte> .Return(buffer); } else { var pinnedArray = GCHandle.Alloc(value, GCHandleType.Pinned); var srcPtr = Marshal.UnsafeAddrOfPinnedArrayElement(value, valueOffset); compressedSize = BloscMethods.blosc_compress_ctx( new IntPtr(9), // max compression 9 new IntPtr(1), // do byte shuffle 1 new UIntPtr((uint)ItemSize), // type size new UIntPtr((uint)(valueCount * ItemSize)), // number of input bytes srcPtr, destination.Data + position, // destination new UIntPtr((uint)(destination.Length - position)), // destination length compressionMethod, new UIntPtr((uint)0), // default block size BloscMethods.ProcessorCount // ); pinnedArray.Free(); } } else { MemoryStream tempStream; var bytesSize = BinarySerializer.SizeOf(new ArraySegment <TElement>(value, valueOffset, valueCount), out tempStream, compression); var buffer = BufferPool <byte> .Rent(bytesSize); var writtenBytes = BinarySerializer.Write(new ArraySegment <TElement>(value, valueOffset, valueCount), buffer, 0, tempStream); tempStream?.Dispose(); Debug.Assert(bytesSize == writtenBytes); compressedSize = CompressedArrayBinaryConverter <byte> .Instance.Write(buffer, 0, writtenBytes, ref destination, destinationOffset, null, compression); BufferPool <byte> .Return(buffer); } if (compressedSize > 0) { position += compressedSize; } else { return((int)BinaryConverterErrorCode.NotEnoughCapacity); } } // length destination.WriteInt32(0, position); // include all headers // version & flags destination.WriteByte(4, (byte)((Version << 4) | (isDiffable ? 0b0000_0011 : 0b0000_0001))); return(position); }