/// <summary>Delete the first N bytes of the buffer, and shift the remaining to the front</summary>
        /// <param name="bytes">Number of bytes to remove at the head of the buffer</param>
        /// <returns>New size of the buffer (or 0 if it is empty)</returns>
        /// <remarks>This should be called after every successfull write to the underlying stream, to update the buffer.</remarks>
        public int Flush(int bytes)
        {
            if (bytes == 0)
            {
                return(this.Position);
            }
            if (bytes < 0)
            {
                throw new ArgumentOutOfRangeException("bytes");
            }

            if (bytes < this.Position)
            {             // copy the left over data to the start of the buffer
                int remaining = this.Position - bytes;
                SliceHelpers.CopyBytesUnsafe(this.Buffer, 0, this.Buffer, bytes, remaining);
                this.Position = remaining;
                return(remaining);
            }
            else
            {
                //REVIEW: should we throw if there are less bytes in the buffer than we want to flush ?
                this.Position = 0;
                return(0);
            }
        }
        /// <summary>Writes a length-prefixed byte array, and advances the cursor</summary>
        public void WriteVarbytes(Slice value)
        {
            //REVIEW: what should we do for Slice.Nil ?

            SliceHelpers.EnsureSliceIsValid(ref value);
            int n = value.Count;

            if (n < 128)
            {
                EnsureBytes(n + 1);
                var buffer = this.Buffer;
                int p      = this.Position;
                // write the count (single byte)
                buffer[p] = (byte)n;
                // write the bytes
                if (n > 0)
                {
                    SliceHelpers.CopyBytesUnsafe(buffer, p + 1, value.Array, value.Offset, n);
                }
                this.Position = p + n + 1;
            }
            else
            {
                // write the count
                WriteVarint32((uint)value.Count);
                // write the bytes
                SliceHelpers.CopyBytesUnsafe(this.Buffer, this.Position, value.Array, value.Offset, n);
                this.Position += n;
            }
        }
        /// <summary>Copy the content of a byte segment into another. CAUTION: The arguments are NOT in the same order as Buffer.BlockCopy() or Array.Copy() !</summary>
        /// <param name="dst">Destination buffer</param>
        /// <param name="dstOffset">Offset in destination buffer</param>
        /// <param name="src">Source buffer</param>
        /// <param name="srcOffset">Offset in source buffer</param>
        /// <param name="count">Number of bytes to copy</param>
        /// <remarks>CAUTION: THE ARGUMENTS ARE REVERSED! They are in the same order as memcpy() and memmove(), with destination first, and source second!</remarks>
        public static void CopyBytes(byte[] dst, int dstOffset, byte[] src, int srcOffset, int count)
        {
            SliceHelpers.EnsureBufferIsValid(dst, dstOffset, count);
            SliceHelpers.EnsureBufferIsValid(src, srcOffset, count);

            CopyBytesUnsafe(dst, dstOffset, src, srcOffset, count);
        }
        /// <summary>Creates a new binary buffer, initialized by copying pre-existing data</summary>
        /// <param name="prefix">Data that will be copied at the start of the buffer</param>
        /// <param name="capacity">Optional initial capacity of the buffer</param>
        /// <remarks>The cursor will already be placed at the end of the prefix</remarks>
        public SliceWriter(Slice prefix, int capacity = 0)
        {
            if (capacity < 0)
            {
                throw new ArgumentException("Capacity must be a positive integer.", "capacity");
            }

            int n = prefix.Count;

            Contract.Assert(n >= 0);

            if (capacity == 0)
            {             // most frequent usage is to add a packed integer at the end of a prefix
                capacity = SliceHelpers.Align(n + 8);
            }
            else
            {
                capacity = Math.Max(capacity, n);
            }

            var buffer = new byte[capacity];

            if (n > 0)
            {
                prefix.CopyTo(buffer, 0);
            }

            this.Buffer   = buffer;
            this.Position = n;
        }
        /// <summary>Compare two byte segments lexicographically</summary>
        /// <param name="left">Left buffer</param>
        /// <param name="leftOffset">Start offset in left buffer</param>
        /// <param name="leftCount">Number of bytes in left buffer</param>
        /// <param name="right">Right buffer</param>
        /// <param name="rightOffset">Start offset in right buffer</param>
        /// <param name="rightCount">Number of bytes in right buffer</param>
        /// <returns>Returns zero if segments are identical (same bytes), a negative value if left is lexicographically less than right, or a positive value if left is lexicographically greater than right</returns>
        /// <remarks>The comparison algorithm respect the following:
        /// * "A" &lt; "B"
        /// * "A" &lt; "AA"
        /// * "AA" &lt; "B"</remarks>
        public static int CompareBytes(byte[] left, int leftOffset, int leftCount, byte[] right, int rightOffset, int rightCount)
        {
            SliceHelpers.EnsureBufferIsValid(left, leftOffset, leftCount);
            SliceHelpers.EnsureBufferIsValid(right, rightOffset, rightCount);

            return(CompareBytesUnsafe(left, leftOffset, leftCount, right, rightOffset, rightCount));
        }
 /// <summary>Computes the hash code of a slice</summary>
 /// <param name="obj">A slice</param>
 /// <returns>A 32-bit signed hash coded calculated from all the bytes in the slice</returns>
 public int GetHashCode(Slice obj)
 {
     if (obj.Array == null)
     {
         return(0);
     }
     return(SliceHelpers.ComputeHashCode(obj.Array, obj.Offset, obj.Count));
 }
Example #7
0
        /// <summary>Compute the hash code of a byte segment</summary>
        /// <param name="bytes">Buffer</param>
        /// <param name="offset">Offset of the start of the segment in the buffer</param>
        /// <param name="count">Number of bytes in the segment</param>
        /// <returns>A 32-bit signed hash code calculated from all the bytes in the segment.</returns>
        public static int ComputeHashCode([NotNull] byte[] bytes, int offset, int count)
        {
            if (bytes == null || offset < 0 || count < 0 || offset + count > bytes.Length)
            {
                SliceHelpers.ThrowMalformedBuffer(bytes, offset, count);
            }

            return(ComputeHashCodeUnsafe(bytes, offset, count));
        }
        internal void UnsafeWriteBytes(byte[] data, int offset, int count)
        {
            Contract.Requires(this.Buffer != null && this.Position >= 0 && data != null && count >= 0 && this.Position + count <= this.Buffer.Length && offset >= 0 && offset + count <= data.Length);

            if (count > 0)
            {
                SliceHelpers.CopyBytesUnsafe(this.Buffer, this.Position, data, offset, count);
                this.Position += count;
            }
        }
Example #9
0
        /// <summary>Compare two byte segments for equality</summary>
        /// <param name="left">Left buffer</param>
        /// <param name="leftOffset">Start offset in left buffer</param>
        /// <param name="right">Right buffer</param>
        /// <param name="rightOffset">Start offset in right buffer</param>
        /// <param name="count">Number of bytes to compare</param>
        /// <returns>true if all bytes are the same in both segments</returns>
        public static bool SameBytes(byte[] left, int leftOffset, byte[] right, int rightOffset, int count)
        {
            SliceHelpers.EnsureBufferIsValid(left, leftOffset, count);
            SliceHelpers.EnsureBufferIsValid(right, rightOffset, count);

            if (left == null || right == null)
            {
                return(left == right);
            }
            return(SameBytesUnsafe(left, leftOffset, right, rightOffset, count));
        }
 /// <summary>Set the value of a network option on the database handler</summary>
 private static FdbError SetNetworkOption(FdbNetworkOption option, Slice value)
 {
     SliceHelpers.EnsureSliceIsValid(ref value);
     unsafe
     {
         fixed(byte *ptr = value.Array)
         {
             return(FdbNative.NetworkSetOption(option, ptr + value.Offset, value.Count));
         }
     }
 }
        /// <summary>Append a chunk of a byte array to the end of the buffer</summary>
        /// <param name="data"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        public void WriteBytes(byte[] data, int offset, int count)
        {
            SliceHelpers.EnsureBufferIsValid(data, offset, count);

            if (count > 0)
            {
                EnsureBytes(count);
                SliceHelpers.CopyBytesUnsafe(this.Buffer, this.Position, data, offset, count);
                this.Position += count;
            }
        }
        internal unsafe void UnsafeWriteBytes(byte *data, int count)
        {
            if (count <= 0)
            {
                return;
            }

            Contract.Requires(this.Buffer != null && this.Position >= 0 && data != null && count >= 0 && this.Position + count <= this.Buffer.Length);

            SliceHelpers.CopyBytesUnsafe(this.Buffer, this.Position, data, count);
            this.Position += count;
        }
 /// <summary>Lexicographically compare two slices and returns an indication of their relative sort order.</summary>
 /// <param name="x">Slice compared with <paramref name="y"/></param>
 /// <param name="y">Slice compared with <paramref name="x"/></param>
 /// <returns>Returns a NEGATIVE value if <paramref name="x"/> is LESS THAN <paramref name="y"/>, ZERO if <paramref name="x"/> is EQUAL TO <paramref name="y"/>, and a POSITIVE value if <paramref name="x"/> is GREATER THAN <paramref name="y"/>.</returns>
 /// <remarks>
 /// <para>If both <paramref name="x"/> and <paramref name="y"/> are nil or empty, the comparison will return ZERO. If only <paramref name="y"/> is nil or empty, it will return a NEGATIVE value. If only <paramref name="x"/> is nil or empty, it will return a POSITIVE value.</para>
 /// <para>There are no guarantees that non-zero results will be exactly -1 or +1. You should always use comparison operators or the sign of the returned value, instead of testing for equality with -1 or +1.</para>
 /// </remarks>
 public int Compare(Slice x, Slice y)
 {
     //REVIEW: cmp(Nil, Empty) returns 0 but Nil != Empty ?
     if (x.Count == 0)
     {
         return(y.Count == 0 ? 0 : -1);
     }
     if (y.Count == 0)
     {
         return(+1);
     }
     return(SliceHelpers.CompareBytes(x.Array, x.Offset, x.Count, y.Array, y.Offset, y.Count));
 }
        public byte[] GetBytes()
        {
            Contract.Requires(this.Position >= 0);

            var bytes = new byte[this.Position];

            if (this.Position > 0)
            {
                Contract.Assert(this.Buffer != null && this.Buffer.Length >= this.Position);
                SliceHelpers.CopyBytesUnsafe(bytes, 0, this.Buffer, 0, bytes.Length);
            }
            return(bytes);
        }
        /// <summary>Append a segment of bytes to the end of the buffer</summary>
        public void WriteBytes(Slice data)
        {
            SliceHelpers.EnsureSliceIsValid(ref data);

            int n = data.Count;

            if (n > 0)
            {
                EnsureBytes(n);
                SliceHelpers.CopyBytesUnsafe(this.Buffer, this.Position, data.Array, data.Offset, n);
                this.Position += n;
            }
        }
        /// <summary>Resize a buffer by doubling its capacity</summary>
        /// <param name="buffer">Reference to the variable holding the buffer to create/resize. If null, a new buffer will be allocated. If not, the content of the buffer will be copied into the new buffer.</param>
        /// <param name="minimumCapacity">Mininum guaranteed buffer size after resizing.</param>
        /// <remarks>The buffer will be resized to the maximum betweeb the previous size multiplied by 2, and <paramref name="minimumCapacity"/>. The capacity will always be rounded to a multiple of 16 to reduce memory fragmentation</remarks>
        public static void GrowBuffer(ref byte[] buffer, int minimumCapacity = 0)
        {
            Contract.Requires(minimumCapacity >= 0);

            // double the size of the buffer, or use the minimum required
            long newSize = Math.Max(buffer == null ? 0 : (((long)buffer.Length) << 1), minimumCapacity);

            // .NET (as of 4.5) cannot allocate an array with more than 2^31 - 1 items...
            if (newSize > 0x7fffffffL)
            {
                FailCannotGrowBuffer();
            }

            // round up to 16 bytes, to reduce fragmentation
            int size = SliceHelpers.Align((int)newSize);

            Array.Resize(ref buffer, size);
        }
 /// <summary>Empties the current buffer after a succesfull write</summary>
 /// <remarks>Shrink the buffer if a lot of memory is wated</remarks>
 public void Reset()
 {
     if (this.Position > 0)
     {
         // reduce size ?
         // If the buffer exceeds 4K and we used less than 1/8 of it the last time, we will "shrink" the buffer
         if (this.Buffer.Length > 4096 && (this.Position << 3) <= Buffer.Length)
         {                 // Shrink it
             Buffer = new byte[SliceHelpers.NextPowerOfTwo(this.Position)];
         }
         else
         {                 // Clear it
             //TODO: native memset() ?
             Array.Clear(Buffer, 0, this.Position);
         }
         this.Position = 0;
     }
 }
        /// <summary>Append a chunk of memory to the end of the buffer</summary>
        public unsafe void WriteBytesUnsafe(byte *data, int count)
        {
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }
            if (count < 0)
            {
                throw new ArgumentOutOfRangeException("count");
            }

            if (count > 0)
            {
                EnsureBytes(count);
                SliceHelpers.CopyBytesUnsafe(this.Buffer, this.Position, data, count);
                this.Position += count;
            }
        }
        internal unsafe void WriteBytes(byte *data, int count)
        {
            if (count == 0)
            {
                return;
            }
            if (data == null)
            {
                throw new ArgumentNullException("data");
            }
            if (count < 0)
            {
                throw new ArgumentException("count");
            }

            EnsureBytes(count);
            Contract.Assert(this.Buffer != null && this.Position >= 0 && this.Position + count <= this.Buffer.Length);

            SliceHelpers.CopyBytesUnsafe(this.Buffer, this.Position, data, count);
            this.Position += count;
        }
Example #20
0
        /// <summary>Fill the content of a managed segment with the same byte repeated</summary>
        public static void SetBytes(byte[] bytes, int offset, int count, byte value)
        {
            SliceHelpers.EnsureBufferIsValid(bytes, offset, count);

            if (count <= 8)
            {             // for very small keys, the cost of pinning and marshalling may be to high
                while (count-- > 0)
                {
                    bytes[offset++] = value;
                }
            }
            else
            {
                unsafe
                {
                    fixed(byte *ptr = bytes)
                    {
                        SetMemoryUnsafe(ptr + offset, value, count);
                    }
                }
            }
        }
 /// <summary>Checks if two slices are equal.</summary>
 /// <param name="x">Slice compared with <paramref name="y"/></param>
 /// <param name="y">Slice compared with <paramref name="x"/></param>
 /// <returns>true if <paramref name="x"/> and <paramref name="y"/> have the same size and contain the same sequence of bytes; otherwise, false.</returns>
 public bool Equals(Slice x, Slice y)
 {
     return(x.Count == y.Count && SliceHelpers.SameBytes(x.Array, x.Offset, y.Array, y.Offset, y.Count));
 }