示例#1
0
        /// <summary>
        /// StreamWrite takes a native unsigned integer value value depending on OS,
        /// plus a number of bits and writes the least significant ValueBits of that value
        /// into the bit field array.
        /// The variant that takes a TEncodedBitFieldDescriptor will perform automatic
        /// native to encoded null value conversion and deal with subtracting the minvalue
        /// from the descriptor in the encoded value.
        /// The variant that take an exact number of value bits is a raw version of the write method that
        /// just writes the given value in the given bits.
        /// </summary>
        /// <param name="value"></param>
        /// <param name="descriptor"></param>
        public void StreamWrite(long value, EncodedBitFieldDescriptor descriptor)
        {
            // Writing occurs in three stages:
            // 1: Fill the remaining unwritten bits in the element referenced by FStreamWritePos
            // 2: If there are still more than N_BITS_TO_READ_AT_A_TIME remaining bits to be written, then write
            //    individual elements from value into Storage until the remaining number of bits
            //    to be written is less than N_BITS_TO_READ_AT_A_TIME
            // 3: If there are still (less than N_BITS_TO_READ_AT_A_TIME) bits to be written, then write the remainder
            //    of the bits into the most significant bits of the next empty element in Storage

            int ValueBits = descriptor.RequiredBits;

            if (ValueBits == 0) // There's nothing to do!
            {
                return;
            }

            value = descriptor.Nullable && value == descriptor.NativeNullValue
              ? descriptor.EncodedNullValue - descriptor.MinValue
              : value - descriptor.MinValue;

            // Be paranoid! Ensure there are no bits set in the high order bits above the least significant valueBits in Value
            value &= (1L << ValueBits) - 1;

            int StoragePointer = StreamWriteBitPos >> BIT_LOCATION_TO_BLOCK_SHIFT;
            int AvailBitsInCurrentStorageElement = N_BITS_TO_READ_AT_A_TIME - unchecked ((byte)(StreamWriteBitPos & BITS_REMAINING_IN_STORAGE_BLOCK_MASK));

            // Write initial bits into storage element
            if (AvailBitsInCurrentStorageElement >= ValueBits)
            {
                Storage[StoragePointer] |= unchecked ((ulong)value) << (AvailBitsInCurrentStorageElement - ValueBits);
                StreamWriteBitPos       += ValueBits; // Advance the current bit position pointer;
                return;
            }

            // There are more bits than can fit in AvailBitsInCurrentStorageElement
            // Step 1: Fill remaining bits
            int RemainingBitsToWrite = ValueBits - AvailBitsInCurrentStorageElement;

            Storage[StoragePointer] |= unchecked ((ulong)value) >> RemainingBitsToWrite;

            /* When using long elements, there can never be a value stored that is larger that the storage element
             * // Step 2: Write whole elements
             * while (RemainingBitsToWrite > N_BITS_TO_READ_AT_A_TIME)
             * {
             *  RemainingBitsToWrite -= N_BITS_TO_READ_AT_A_TIME;
             *  Storage[++StoragePointer] = (byte)(value >> RemainingBitsToWrite); // Peel of the next element and place it into storage
             * }
             */

            // Step 3: Write remaining bits into next element in Storage
            if (RemainingBitsToWrite > 0) // Mask out the bits we want...
            {
                Storage[StoragePointer + 1] = (unchecked ((ulong)value) & (((ulong)1 << RemainingBitsToWrite) - 1)) << (N_BITS_TO_READ_AT_A_TIME - RemainingBitsToWrite);
            }

            StreamWriteBitPos += ValueBits;   // Advance the current bit position pointer;
        }
示例#2
0
        /// <summary>
        /// ReadBitField reads a single bit-field from the bitfield array. The bitfield is
        /// identified by the bit location and number of bits in the value to be read.
        /// Once the value has been read the value of bitLocation is set to the next bit after
        /// the end of the value just read.
        /// The variant that takes a TEncodedBitFieldDescriptor will perform automatic
        /// encoded to native null value conversion and deal with adding the minvalue
        /// from the descriptor in the read value.
        /// The variant that take an exact number of value bits is a raw version of the read method that
        /// just reads the value from the given bits.
        /// </summary>
        /// <param name="bitLocation"></param>
        /// <param name="descriptor"></param>
        /// <returns></returns>
        public long ReadBitField(ref int bitLocation, EncodedBitFieldDescriptor descriptor)
        {
            // Reading occurs in three stages:
            // 1: Read the remaining bits in the element referenced by bitLocation
            // 2: If there are still more than N_BITS_TO_READ_AT_A_TIME remaining bits to be read, then read
            //    individual elements from Storage into Result until the remaining number of bits
            //    to be read is less than N_BITS_TO_READ_AT_A_TIME
            // 3: If there are still (less than N_BITS_TO_READ_AT_A_TIME) bits to be read, then read the remainder
            //    of the bits from the most significant bits of the next element in Storage

            int valueBits = descriptor.RequiredBits;

            if (valueBits == 0) // There's nothing to do!
            {
                return(descriptor.AllValuesAreNull ? descriptor.NativeNullValue : descriptor.MinValue);
            }

            int  BlockPointer = bitLocation >> BIT_LOCATION_TO_BLOCK_SHIFT;
            int  RemainingBitsInCurrentStorageBlock = N_BITS_TO_READ_AT_A_TIME - (bitLocation & BITS_REMAINING_IN_STORAGE_BLOCK_MASK);
            long Result;

            // Read initial bits from storage element
            if (RemainingBitsInCurrentStorageBlock >= valueBits)
            {
                Result = unchecked ((long)(Storage[BlockPointer] >> (RemainingBitsInCurrentStorageBlock - valueBits)) & ((1L << valueBits) - 1));
            }
            else
            {
                // There are more bits than can fit in RemainingBitsInCurrentStorageElement
                // Step 1: Fill remaining bits
                Result = unchecked ((long)Storage[BlockPointer] & ((1 << RemainingBitsInCurrentStorageBlock) - 1));
                int BitsToRead = valueBits - RemainingBitsInCurrentStorageBlock;

                /* When using long elements, there can never be a value stored that is larger that the storage element
                 * // Step 2: Read whole elements
                 * while (BitsToRead > BitFieldArray.N_BITS_TO_READ_AT_A_TIME)
                 * {
                 *  BitsToRead -= BitFieldArray.N_BITS_TO_READ_AT_A_TIME;
                 *  Result = (Result << BitFieldArray.N_BITS_TO_READ_AT_A_TIME) | Storage[++BlockPointer]; // Add the next element from storage and put it in result
                 * }
                 */

                // Step 3: Read remaining bits from next block in Storage
                Result = unchecked ((long)((unchecked ((ulong)Result) << BitsToRead) | (Storage[BlockPointer + 1] >> (N_BITS_TO_READ_AT_A_TIME - BitsToRead))));
            }

            // Compute the true result of the read by taking nullability and the offset of MinValue into account
            Result = descriptor.Nullable && Result == descriptor.EncodedNullValue - descriptor.MinValue ? descriptor.NativeNullValue : Result + descriptor.MinValue;

            bitLocation += valueBits; // Advance the current bit position pointer;

            return(Result);
        }
示例#3
0
        /// <summary>
        /// Writes a consolidated vector of bit fields.
        /// </summary>
        /// <param name="bitLocation">The start bit index in the BitFieldArray to begin writing from</param>
        /// <param name="numValues">The number of values to be written to the vector</param>
        /// <param name="values">The array of values to provide the values written to the vector. This array must be at least as large as the number of value requested from the vector</param>
        public void WriteBitFieldVector(ref int bitLocation, EncodedBitFieldDescriptor descriptor, int numValues, long[] values)
        {
            if (values == null || numValues > values.Length)
            {
                throw new ArgumentException($"Supplied values array is null or not large enough to provide value vector of {numValues} values");
            }

            // Check the bit field array allocated storage can receive enough values
            if (bitLocation + numValues * descriptor.RequiredBits > NumBits)
            {
                throw new ArgumentException($"Insufficient storage present to satisfy a write for {numValues} values from bit location {bitLocation}");
            }

            // Writing occurs in three stages:
            // 1: Fill the remaining unwritten bits in the element referenced by FStreamWritePos
            // 2: If there are still more than N_BITS_TO_READ_AT_A_TIME remaining bits to be written, then write
            //    individual elements from value into Storage until the remaining number of bits
            //    to be written is less than N_BITS_TO_READ_AT_A_TIME
            // 3: If there are still (less than N_BITS_TO_READ_AT_A_TIME) bits to be written, then write the remainder
            //    of the bits into the most significant bits of the next empty element in Storage

            int valueBits = descriptor.RequiredBits;

            if (valueBits == 0) // There's nothing to do!
            {
                return;
            }

            int   StoragePointer = bitLocation >> BIT_LOCATION_TO_BLOCK_SHIFT;
            ulong blockValue     = Storage[StoragePointer];

            int  AvailBitsInCurrentStorageElement = N_BITS_TO_READ_AT_A_TIME - (StreamWriteBitPos & BITS_REMAINING_IN_STORAGE_BLOCK_MASK);
            long valueMask = (1L << valueBits) - 1;

            for (int i = 0; i < numValues; i++)
            {
                long value = descriptor.Nullable && values[i] == descriptor.NativeNullValue
                             ? descriptor.EncodedNullValue - descriptor.MinValue
                             : values[i] - descriptor.MinValue;

                // Be paranoid! Ensure there are no bits set in the high order bits above the least significant valueBits in Value
                value &= valueMask;

                // Write initial bits into storage element
                if (AvailBitsInCurrentStorageElement >= valueBits)
                {
                    blockValue        |= (unchecked ((ulong)value) << (AvailBitsInCurrentStorageElement - valueBits));
                    StreamWriteBitPos += valueBits; // Advance the current bit position pointer;
                    AvailBitsInCurrentStorageElement -= valueBits;
                    continue;
                }

                // There are more bits than can fit in AvailBitsInCurrentStorageElement
                // Step 1: Fill remaining bits
                int RemainingBitsToWrite = valueBits - AvailBitsInCurrentStorageElement;
                blockValue |= (unchecked ((ulong)value) >> RemainingBitsToWrite);
                Storage[StoragePointer++] = blockValue;

                AvailBitsInCurrentStorageElement = N_BITS_TO_READ_AT_A_TIME - RemainingBitsToWrite;

                // Step 3: Write remaining bits into next element in Storage
                if (RemainingBitsToWrite > 0) // Mask out the bits we want...
                {
                    blockValue = (unchecked ((ulong)value) & ((1UL << RemainingBitsToWrite) - 1)) << AvailBitsInCurrentStorageElement;
                }
            }

            if (StoragePointer < Storage.Length)
            {
                Storage[StoragePointer] = blockValue;
            }

            bitLocation += valueBits * numValues; // Advance the current bit position pointer;
        }
示例#4
0
        /// <summary>
        /// Reads a consolidated vector of bit fields.
        /// </summary>
        /// <param name="descriptor"></param>
        /// <param name="bitLocation">The start bit index in the BitFieldArray to begin reading from</param>
        /// <param name="numValues">The number of values to be read from the vector</param>
        /// <param name="values">The array of values to receive the values read from the vector. This array must be at least as large as the number of value requested from the vector</param>
        public void ReadBitFieldVector(ref int bitLocation, EncodedBitFieldDescriptor descriptor, int numValues, long[] values)
        {
            // Check the array is big enough
            if (values == null || numValues > values.Length)
            {
                throw new ArgumentException($"Supplied values array is null or not large enough to accept value vector of {numValues} values");
            }

            int valueBits = descriptor.RequiredBits;

            // Check the bit field array allocated storage contains enough values
            if (bitLocation + numValues * valueBits > NumBits)
            {
                throw new ArgumentException($"Insufficient values present to satisfy a read for {numValues} values from bit location {bitLocation}");
            }

            // Reading occurs in three stages:
            // 1: Read the remaining bits in the element referenced by bitLocation
            // 2: If there are still more than N_BITS_TO_READ_AT_A_TIME remaining bits to be read, then read
            //    individual elements from Storage into Result until the remaining number of bits
            //    to be read is less than N_BITS_TO_READ_AT_A_TIME
            // 3: If there are still (less than N_BITS_TO_READ_AT_A_TIME) bits to be read, then read the remainder
            //    of the bits from the most significant bits of the next element in Storage

            if (valueBits == 0) // There's nothing to do!
            {
                return;
            }

            int BlockPointer = bitLocation >> BIT_LOCATION_TO_BLOCK_SHIFT;
            int RemainingBitsInCurrentStorageBlock = N_BITS_TO_READ_AT_A_TIME - (bitLocation & BITS_REMAINING_IN_STORAGE_BLOCK_MASK);

            // Read the first block containing the first value
            ulong blockValue = Storage[BlockPointer];
            ulong valueMask  = (1UL << valueBits) - 1;

            for (int i = 0; i < numValues; i++)
            {
                if (RemainingBitsInCurrentStorageBlock >= valueBits)
                {
                    values[i] = (long)((blockValue >> (RemainingBitsInCurrentStorageBlock - valueBits)) & valueMask);
                    RemainingBitsInCurrentStorageBlock -= valueBits;
                }
                else
                {
                    // Work out the bits to be read from the next block
                    int BitsToRead = valueBits - RemainingBitsInCurrentStorageBlock;

                    // There are more bits than can fit in RemainingBitsInCurrentStorageElement
                    // Step 1: Fill remaining bits
                    long Result = unchecked ((long)(blockValue & ((1UL << RemainingBitsInCurrentStorageBlock) - 1)) <<
                                             BitsToRead);

                    blockValue = Storage[++BlockPointer];
                    RemainingBitsInCurrentStorageBlock = N_BITS_TO_READ_AT_A_TIME - BitsToRead;

                    // Step 3: Read remaining bits from next block in Storage
                    values[i] = Result | unchecked ((long)(blockValue >> RemainingBitsInCurrentStorageBlock));
                }

                // Compute the true result of the read by taking nullability and the offset of MinValue into account
                values[i] = descriptor.Nullable && values[i] == descriptor.EncodedNullValue - descriptor.MinValue
              ? descriptor.NativeNullValue
              : values[i] + descriptor.MinValue;
            }

            bitLocation += valueBits * numValues; // Advance the current bit position pointer;
        }