예제 #1
0
 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));
     }
 }
예제 #2
0
        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);
        }