Exemplo n.º 1
0
        public void u16(u16 value, u8 numberOfBits)
        {
#if !NO_EXCEPTIONS
            if (numberOfBits <= 0)
            {
                Throw.ArgumentOutOfRange($"{nameof(numberOfBits)} should be positive", nameof(numberOfBits));
            }

            if (numberOfBits > 16) // Unsafe.Sizeof<u16>() * 8
            {
                Throw.ArgumentOutOfRange($"{nameof(numberOfBits)} should be less than or equal to 16", nameof(numberOfBits));
            }

            if (BitsWritten + numberOfBits > totalNumberBits)
            {
                Throw.InvalidOperation($"Writing {numberOfBits} bits will exceed maximal capacity of {totalNumberBits}, while {BitsWritten} bits written");
            }

            if (value > (u16)((1ul << numberOfBits) - 1))
            {
                Throw.Argument(nameof(value), $"{value} is too big, won't fit in requested {numberOfBits} number of bits");
            }
#endif
            var part = value & (u32)((1ul << numberOfBits) - 1);
            scratch         |= ((u64)part) << scratchUsedBits;
            scratchUsedBits += numberOfBits;
            SIndexInc();
        }
            public AsyncStreamPipe(Stream stream, PipeOptions sendPipeOptions, PipeOptions receivePipeOptions, bool read, bool write, string name)
            {
                if (sendPipeOptions == null)
                {
                    sendPipeOptions = PipeOptions.Default;
                }
                if (receivePipeOptions == null)
                {
                    receivePipeOptions = PipeOptions.Default;
                }
                if (stream == null)
                {
                    Throw.ArgumentNull(nameof(stream));
                }
                _inner = stream;
                if (!(read || write))
                {
                    Throw.Argument("At least one of read/write must be set");
                }
                if (read && write)
                {
                    string preamble = "";
                    switch (stream)
                    {
                    case MemoryStream ms:     // extra guidance in this case; there's a reaily available alternative
                        preamble = "You probably want `new Pipe()` instead - a `Pipe` is broadly comparable to a MemoryStream with separate read/write heads. ";
                        goto ThrowNonDuplexStream;

                    case FileStream fs:
                        // others here?
ThrowNonDuplexStream:
                        Throw.Argument(preamble + $"`{stream.GetType().Name}` is not a duplex stream and cannot be used in this context (you can still create a reader/writer).", nameof(stream));
                        return;
                    }
                }

                if (string.IsNullOrWhiteSpace(name))
                {
                    name = GetType().Name;
                }
                Name = name ?? GetType().Name;
                if (read)
                {
                    if (!stream.CanRead)
                    {
                        Throw.InvalidOperation("Cannot create a read pipe over a non-readable stream");
                    }
                    _readPipe = new Pipe(receivePipeOptions);
                    receivePipeOptions.ReaderScheduler.Schedule(obj => ((AsyncStreamPipe)obj).CopyFromStreamToReadPipe().PipelinesFireAndForget(), this);
                }
                if (write)
                {
                    if (!stream.CanWrite)
                    {
                        Throw.InvalidOperation("Cannot create a write pipe over a non-writable stream");
                    }
                    _writePipe = new Pipe(sendPipeOptions);
                    sendPipeOptions.WriterScheduler.Schedule(obj => ((AsyncStreamPipe)obj).CopyFromWritePipeToStream().PipelinesFireAndForget(), this);
                }
            }
Exemplo n.º 3
0
        public void u32(u32 value, u8 numberOfBits)
        {
#if !NO_EXCEPTIONS
            if (numberOfBits <= 0)
            {
                Throw.ArgumentOutOfRange($"{nameof(numberOfBits)} should be positive", nameof(numberOfBits));
            }

            if (numberOfBits > 32) // Unsafe.Sizeof<u32>() * 8
            {
                Throw.ArgumentOutOfRange($"{nameof(numberOfBits)} should be less than or equal to 32", nameof(numberOfBits));
            }

            if (BitsWritten + numberOfBits > totalNumberBits)
            {
                Throw.InvalidOperation($"Writing {numberOfBits} bits will exceed maximal capacity of {totalNumberBits}, while {BitsWritten} bits written");
            }

            if (value > (u32)((1ul << numberOfBits) - 1))
            {
                Throw.Argument(nameof(value), $"{value} is too big, won't fit in requested {numberOfBits} number of bits");
            }
#endif
            internalRaw(value, numberOfBits);
        }
Exemplo n.º 4
0
 /// <summary>
 /// Abort the current async operation (and prevent future operations)
 /// </summary>
 public void Abort(SocketError error = SocketError.OperationAborted)
 {
     if (error == SocketError.Success)
     {
         Throw.Argument(nameof(error));
     }
     _forcedError = error;
     OnCompleted(this);
 }
Exemplo n.º 5
0
 public RawBitWriter(TMemory chunks)
 {
     if (default(TMemory).Equals(chunks) || chunks.Length == 0)
     {
         Throw.Argument("Buffer should be non null or empty", nameof(chunks));
     }
     Chunks = chunks;
     Reset();
 }
        public void u32(u32 value, u32 min, u32 max)
        {
#if !NO_EXCEPTIONS
            if (min >= max)
            {
                Throw.Argument("min should be lower than max");
            }
            if (value < min || value > max)
            {
                Throw.ArgumentOutOfRange(nameof(value), $"Value should be withing provided {min} and {max} range");
            }
#endif
            var bits = BitBuffer.BitsRequired(min, max);
            u32(value - min, bits);
        }
        public u32 u32(u32 min, u32 max)
        {
#if !NO_EXCEPTIONS
            if (min > max)
            {
                Throw.Argument("min should not be not lower than max");
            }
#endif
            var bits = (u8)BitBuffer.BitsRequired(min, max);
#if !NO_EXCEPTIONS
            if (BitsRead + bits > totalNumberBits)
            {
                Throw.ArgumentOutOfRange("Reading too many bits for requested range");
            }
#endif
            return(u32(bits) + min);
        }
        public void u8(ReadOnlySpan <u8> value)
        {
            if (value.Length > config.U8SpanLengthMax)
            {
                Throw.Argument($"Byte array too big, raise the {nameof(config.U8SpanBitsLength)} value or split the array.");
            }

            if (value.Length + 9 > (totalNumberBits - BitsWritten))
            {
                Throw.InvalidOperation("Byte array too big for buffer.");
            }

            u32((u32)value.Length, config.U8SpanBitsLength);
            for (var index = 0; index < value.Length; index++)
            {
                u8(value[index]);
            }
        }
Exemplo n.º 9
0
        /// <summary>
        /// Creates new instance with its own buffer.
        /// </summary>
        /// <param name="charSpanBitsLength">Bits used to store length of strings.</param>
        /// <param name="u8SpanBitsLength">Bits used to store length of byte arrays.</param>
        public BitBufferOptions(u8 charSpanBitsLength = DefaultCharSpanBitsLength, u8 u8SpanBitsLength = DefaultU8SpanBitsLength)
        {
            if (charSpanBitsLength <= 0)
            {
                Throw.Argument("Should be positive", nameof(charSpanBitsLength));
            }

            if (u8SpanBitsLength <= 0)
            {
                Throw.Argument("Should be positive", nameof(u8SpanBitsLength));
            }

            // one time setup
            this.u8SpanBitsLength   = u8SpanBitsLength;
            u8SpanLengthMax         = (u16)((1 << u8SpanBitsLength) - 1);
            this.charSpanBitsLength = charSpanBitsLength;
            charSpanLengthMax       = (u16)((1 << charSpanBitsLength) - 1);
        }
        public void f32(f32 value, f32 min, f32 max, u8 numberOfBits)
        {
#if !NO_EXCEPTIONS
            if (min >= max)
            {
                Throw.Argument("min should be lower than max");
            }
            if (value < min || value > max)
            {
                Throw.ArgumentOutOfRange(nameof(value), $"Value should be withing provided {min} and {max} range");
            }
#endif
            var   maxvalue     = (1 << numberOfBits) - 1;
            float range        = max - min;
            var   precision    = range / maxvalue;
            var   invPrecision = 1.0f / precision;
            f32   adjusted     = (value - min) * invPrecision;
            u32((u32)(adjusted + 0.5f), numberOfBits);
        }
        public void f32(f32 value, f32 min, f32 max, f32 precision)
        {
#if !NO_EXCEPTIONS
            if (min >= max)
            {
                Throw.Argument("min should be lower than max");
            }
            if (value < min || value > max)
            {
                Throw.ArgumentOutOfRange(nameof(value), $"Value should be withing provided {min} and {max} range");
            }
#endif
            float range        = max - min;
            float invPrecision = 1.0f / precision;
            float maxVal       = range * invPrecision;
            var   numberOfBits = (u8)(BitOperations.Log2((u32)(maxVal + 0.5f)) + 1);
            float adjusted     = (value - min) * invPrecision;
            u32((u32)(adjusted + 0.5f), numberOfBits);
        }
Exemplo n.º 12
0
 /// <summary>
 /// Gets a specific frame from <see cref="Icon" />. The <paramref name="size" /> parameter must be 16, 32 or 48.
 /// </summary>
 /// <param name="size">A <see cref="int" /> value representing the size of the frame to retrieve. The value must be 16, 32 or 48.</param>
 /// <returns>
 /// The frame from <see cref="Icon" />, specified by <paramref name="size" />.
 /// </returns>
 public Bitmap GetIcon(int size)
 {
     if (size == 16)
     {
         return(Icon16);
     }
     else if (size == 32)
     {
         return(Icon32);
     }
     else if (size == 48)
     {
         return(Icon48);
     }
     else
     {
         throw Throw.Argument(nameof(size), "Icon size must be 16, 32 or 48.");
     }
 }
Exemplo n.º 13
0
        public i32 u8(Span <u8> outputValue, i32 offset)
        {
            var length = (int)u32(config.U8SpanBitsLength);

            if (totalNumberBits - BitsRead < length * 8)
            {
                Throw.InvalidOperation("The length for this read is bigger than bitbuffer");
            }

            // 1                    1        0   OK
            // 1                    1        1   FAIL
            if (length > outputValue.Length - offset)
            {
                Throw.Argument(nameof(outputValue), "The supplied byte array is too small for requested read");
            }

            for (var index = offset; index < length; index++)
            {
                outputValue[index] = u8(); // TODO: can read faster if read by 4 bytes?
            }
            return(length);
        }
Exemplo n.º 14
0
        public void SetPosition(u32 bitsRead)
        {
#if !NO_EXCEPTIONS
            if (bitsRead < 0)
            {
                Throw.Argument("Pushing negative bits", nameof(bitsRead));
            }
            if (bitsRead > totalNumberBits)
            {
                Throw.Argument("Pushing too many bits", nameof(bitsRead));
            }
#endif
            chunkIndex      = (u16)(bitsRead / (4 * 8));
            scratchUsedBits = (i32)(bitsRead % 32u);
            if (scratchUsedBits != 0)
            {
                scratch     = ((u64)(chunks[chunkIndex])) >> scratchUsedBits;
                chunkIndex += 1;
            }
            else
            {
                scratch = 0;
            }
        }
Exemplo n.º 15
0
        /// <summary>
        /// Copies data from array.
        /// </summary>
        public void CopyFrom(ReadOnlySpan <u8> data)
        {
            // may Throw.here as not hot path
            if (data.Length <= 0)
            {
                Throw.Argument("Should be positive", nameof(data.Length));
            }
            if (data.Length > System.UInt16.MaxValue * 4)
            {
                Throw.Argument($"Should be less or equal to {System.UInt16.MaxValue * 4}", nameof(data.Length));
            }


            var length = data.Length;

            Reset();
            var step      = Unsafe.SizeOf <u32>();
            var numChunks = (u16)((length / step) + 1);

            // TODO: move out this expansion from here
            if (chunks.Length < numChunks)
            {
                Chunks = new u32ArrayMemory(new u32[numChunks]); // call it once to stay expanded forever
            }

            // data must be 4 or 8 bytes i64 because 32 and 64 machines https://gafferongames.com/post/reading_and_writing_packets/
            // TODO: possible to optimize to avoid copy? some kind of unsafe cast?
            // TODO: try u64 for performance as most of devices will be 64 bit?
            // https://github.com/nxrighthere/NetStack/issues/1#issuecomment-475212246
            for (u16 i = 0; i < numChunks; i++)
            {
                i32 dataIdx = (i32)i * step;
                u32 chunk   = 0;
                // TODO: ref into data and do block copy of all 4bytes, copy only last 3 bytes by hand
                // may optimize by calculating variable her and doing zero init of remaining blocks
                // may reintepret unsafe as uint, and then if less than 3 then only read last as 1 2 3
                if (dataIdx < length)
                {
                    chunk = (u32)data[dataIdx];
                }

                if (dataIdx + 1 < length)
                {
                    chunk = chunk | (u32)data[dataIdx + 1] << 8;
                }

                if (dataIdx + 2 < length)
                {
                    chunk = chunk | (u32)data[dataIdx + 2] << 16;
                }

                if (dataIdx + 3 < length)
                {
                    chunk = chunk | (u32)data[dataIdx + 3] << 24;
                }

                chunks[i] = chunk;
            }

            // TODO: write sets 1 bit in the end. so we may read all remaining zeroes, minis 1 bit for flag, and make total less
            // TODO: should be do that at all? Consoder multiple buffers writing sequenctially or other length indicator (like prefix)
            // var leadingZeros = BitOperations.LeadingZeroCount(data[length - 1]);
            // totalNumberBits = 8 * length - leadingZeros - 1;
        }
        /// <summary>
        /// Indicates how much data was consumed, and how much examined, from a read operation
        /// </summary>
        public override void AdvanceTo(SequencePosition consumed, SequencePosition examined)
        {
            var cPage = (MappedPage)consumed.GetObject();
            var ePage = (MappedPage)examined.GetObject();

            if (cPage == null || ePage == null)
            {
                if (_first == null)
                {
                    return;                 // that's fine - means they called Advance on an empty EOF
                }
                Throw.Argument("Invalid position; consumed/examined must remain inside the buffer");
            }

            Debug.Assert(ePage != null, "No examined page");
            Debug.Assert(cPage != null, "No consumed page");

            MappedPage newKeep;
            var        cOffset = consumed.GetInteger();

            if (cOffset == cPage.Capacity)
            {
                newKeep = cPage.Next;
            }
            else
            {
                newKeep          = cPage;
                newKeep.Consumed = cOffset;
            }
            if (newKeep == null)
            {
                DebugLog($"Retaining nothing");
                _last = null;
            }
            else
            {
                DebugLog($"Retaining page {newKeep}");
            }

            // now drop any pages we don't need
            if (newKeep != _first)
            {
                var page = _first;
                while (page != null && page != newKeep)
                {
                    DebugLog($"Dropping page {page}");
                    page.Dispose();
                    page = page.Next;
                }
                _first = newKeep;
            }

            // check whether they looked at everything
            if (_last == null)
            {
                _loadMore = true; // definitely
            }
            else
            {
                var eOffset = examined.GetInteger();
                _loadMore = ePage == _last && eOffset == ePage.Capacity;
            }
            DebugLog($"After AdvanceTo, {CountAvailable(_first)} available bytes, {_remaining} remaining unloaded bytes, load more: {_loadMore}");
        }