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); } }
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); }
/// <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); }
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]); } }
/// <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); }
/// <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."); } }
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); }
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; } }
/// <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}"); }