diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7273628 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "restructuredtext.confPath": "${workspaceFolder}\\docs" +} \ No newline at end of file diff --git a/docs/Acknowledgements.md b/docs/Acknowledgements.md deleted file mode 100644 index f4dd85b..0000000 --- a/docs/Acknowledgements.md +++ /dev/null @@ -1,22 +0,0 @@ -# Acknowledgements - -## Citations - -- Wikipedia on Endianness - - > Wikipedia contributors. (2019, October 10). Endianness. In Wikipedia, The Free Encyclopedia. Retrieved 18:31, October 13, 2019, from [https://en.wikipedia.org/w/index.php?title=Endianness&oldid=920566520](https://en.wikipedia.org/w/index.php?title=Endianness&oldid=920566520). - - -- ["Simply Explained" comic](http://geek-and-poke.com/geekandpoke/2011/9/7/simply-explained.html) - - > Widder, O. (2011, September 7). Simply Explained. Retrieved October 13, 2019, from [http://geek-and-poke.com/geekandpoke/2011/9/7/simply-explained.html](http://geek-and-poke.com/geekandpoke/2011/9/7/simply-explained.html). - - -- [Gulliver logo](https://commons.wikimedia.org/wiki/File:Gullivers_travels.jpg) - - > https://commons.wikimedia.org/wiki/File:Gullivers_travels.jpg - > - > This work is in the public domain in its country of origin and other countries and areas where the copyright term is the author's life plus 70 years or fewer. - > - > U.S. work public domain in the U.S. for unspecified reason but presumably because it was published in the U.S. before 1924. - > This work has been identified as being free of known restrictions under copyright law, including all related and neighboring rights. diff --git a/docs/Acknowledgements.rst b/docs/Acknowledgements.rst new file mode 100644 index 0000000..f62ca04 --- /dev/null +++ b/docs/Acknowledgements.rst @@ -0,0 +1,28 @@ + +Acknowledgements +################ + +Citations +********* + +Wikipedia on Endianness +======================= + + Wikipedia contributors. (2019, October 10). Endianness. In Wikipedia, The Free Encyclopedia. Retrieved 18:31, October 13, 2019, from `https://en.wikipedia.org/w/index.php?title=Endianness&oldid=920566520 `_. + +"Simply Explained" comic +======================== + +`"Simply Explained" comic `_ + + Widder, O. (2011, September 7). Simply Explained. Retrieved October 13, 2019, from ``_. + +Gulliver logo +============= + +`Title page of first edition of Gulliver's Travels by Jonathan Swift. `_ + + This work is in the public domain in its country of origin and other countries and areas where the copyright term is the author's life plus 70 years or fewer. + + U.S. work public domain in the U.S. for unspecified reason but presumably because it was published in the U.S. before 1924. + This work has been identified as being free of known restrictions under copyright law, including all related and neighboring rights. diff --git a/docs/Bitwise-Byte-Array-Operations.md b/docs/Bitwise-Byte-Array-Operations.md deleted file mode 100644 index f11a3cf..0000000 --- a/docs/Bitwise-Byte-Array-Operations.md +++ /dev/null @@ -1,511 +0,0 @@ -# Bitwise Byte Array Operations - -The various Bitwise byte array operations provided by Gulliver implement the standard expected bitwise operations that should fit the needs of most developers. In some cases these methods are endian aware such that byte arrays of differing lengths may be appropriately lined up for operations. - -Unless otherwise stated the following methods are statically defined in the `ByteArrayUtils` class and do not modify their input. - -## Addressing - -The various addressing methods allow for the easy retrieval of individual byte, or bit data within the given byte array. - -### Byte Array as Bit Array - -Byte arrays are great, but sometimes what we really need are bit (or `boolean`) arrays instead. `ByteArrayUtils.AddressBit` method takes an array of `bytes` treats it as if it were an array of bits instead returning the bit value at the given bit index `index`. - -Keep in mind there are 8 bit in a byte. - -```c# -public static bool ByteArrayUtils.AddressBit(this byte[] bytes, int index) -``` - -```c# -public static class Addressing -{ - #region AddressBit - public static void AddressBitExample() - { - // Setup - var input = new byte[] { 0xC0, 0x1D }; - var bitLength = input.Length * 8; - // Act - IEnumerable result = Enumerable.Range(0, bitLength - 1) - .Select(i => - { - var bit = input.AddressBit(i); - return (i, b: bit ? 1 : 0); - }) - .Select(x => $"[{x.i}]:{x.b}") - .Skip(4) - .Take(bitLength - 8) - .ToList(); - // Conclusion - Console.WriteLine("AddressBit Example"); - Console.WriteLine($"input:\t{input.ToString("H")}"); - Console.WriteLine($"input:\t{input.ToString("b")}"); - Console.WriteLine($"result:\t{string.Join(", ", result)}"); - Console.WriteLine(string.Empty); - } - #endregion end: AddressBit -} -``` - -```none -AddressBit Example -input: C0 1D -input: 11000000 00011101 -result: [4]:0, [5]:0, [6]:1, [7]:1, [8]:1, [9]:0, [10]:1, [11]:1 -``` - -## Boolean Operations - -Boolean operations include the standard NOT, AND, OR, and XOR. - -XNOR, and the remaining 11 truth functions were deemed unnecessary. But remember, as an exercise for the developer, a XNOR may be created by using a NOT on the result of an OR operation, and given the principal of [Functional Completeness](https://en.wikipedia.org/wiki/Functional_completeness) each of the [16 truth functions](https://en.wikipedia.org/wiki/Truth_table#Binary_operations) can be built using your newly created gate. - -### NOT - -`ByteArrayUtils.BitwiseNot` will return the inverse of the provided `bytes` - -Due to its unary nature the `ByteArrayUtils.BitwiseNot` operation is endian agnostic. - -```c# -public static byte[] ByteArrayUtils.BitwiseNot(byte[] bytes) -``` - -```c# -public static void BitwiseNotExample() -{ - // Setup - var input = new byte[] { 0x00, 0x11, 0xAC, 0xFF }; - // Act - var result = ByteArrayUtils.BitwiseNot(input); - // Conclusion - Console.WriteLine("BitwiseNot Example"); - Console.WriteLine($"input:\t{input.ToString("H")}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); - Console.WriteLine(string.Empty); - Console.WriteLine($"input:\t{input.ToString("b")}"); - Console.WriteLine($"result:\t{result.ToString("b")}"); - Console.WriteLine(string.Empty); -} -``` - -```none -BitwiseNot Example -input: 00 11 AC FF -result: FF EE 53 00 - -input: 00000000 00010001 10101100 11111111 -result: 11111111 11101110 01010011 00000000 -``` - -### AND - -`ByteArrayUtils.BitwiseAndBigEndian` and `ByteArrayUtils.BitwiseAndLittleEndian` will return the logical AND of the `left` and `right` byte arrays. In the case where the input byte arrays are not of the same length the shortest array will be padded by the appropriate count of `0x00` most significant bytes so that comparisons may appropriately take place. - -#### Big Endian - -```c# -public static byte[] ByteArrayUtils.BitwiseAndBigEndian(byte[] left, byte[] right) -``` - -```c# -public static void BitwiseAndBigEndianExample() -{ - // Setup - var lhs = new byte[] { 0xC0, 0xDE }; - var rhs = new byte[] { 0xC0, 0xFF, 0xEE }; - // Act - var result = ByteArrayUtils.BitwiseAndBigEndian(lhs, rhs); - // Conclusion - Console.WriteLine("BitwiseAndBigEndian Example"); - Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); - Console.WriteLine(string.Empty); - Console.WriteLine($"lhs:\t{lhs.ToString("b")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("b")}"); - Console.WriteLine($"result:\t{result.ToString("b")}"); - Console.WriteLine(string.Empty); -} -``` - -```none -BitwiseAndBigEndian Example -lhs: C0 DE -rhs: C0 FF EE -result: 00 C0 CE - -lhs: 11000000 11011110 -rhs: 11000000 11111111 11101110 -result: 00000000 11000000 11001110 -``` - -#### Little Endian - -```c# -public static byte[] ByteArrayUtils.BitwiseAndLittleEndian(byte[] left, byte[] right) -``` - -```c# -public static void BitwiseAndLittleEndianExample() -{ - // Setup - var lhs = new byte[] { 0xC0, 0xDE }; - var rhs = new byte[] { 0xC0, 0xFF, 0xEE }; - // Act - var result = ByteArrayUtils.BitwiseAndLittleEndian(lhs, rhs); - // Conclusion - Console.WriteLine("BitwiseAndLittleEndian Example"); - Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); - Console.WriteLine(string.Empty); - Console.WriteLine($"lhs:\t{lhs.ToString("b")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("b")}"); - Console.WriteLine($"result:\t{result.ToString("b")}"); - Console.WriteLine(string.Empty); -} -``` - -```none -BitwiseAndLittleEndian Example -lhs: C0 DE -rhs: C0 FF EE -result: C0 DE 00 - -lhs: 11000000 11011110 -rhs: 11000000 11111111 11101110 -result: 11000000 11011110 00000000 -``` - -### OR - -`ByteArrayUtils.BitwiseOrBigEndian` and `ByteArrayUtils.BitwiseOrLittleEndian`will return the logical OR of the `left` and `right` byte arrays. In the case where the input byte arrays are not of the same length the shortest array will be padded by the appropriate count of `0x00` most significant bytes so that comparisons may appropriately take place. - -#### Big Endian - -```c# -public static byte[] ByteArrayUtils.BitwiseOrBigEndian(byte[] left, byte[] right) -``` - -```c# -public static void BitwiseOrBigEndianExample() -{ - // Setup - var lhs = new byte[] { 0xC0, 0xDE }; - var rhs = new byte[] { 0xC0, 0xFF, 0xEE }; - // Act - var result = ByteArrayUtils.BitwiseOrBigEndian(lhs, rhs); - // Conclusion - Console.WriteLine("BitwiseOrBigEndian Example"); - Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); - Console.WriteLine(string.Empty); - Console.WriteLine($"lhs:\t{lhs.ToString("b")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("b")}"); - Console.WriteLine($"result:\t{result.ToString("b")}"); - Console.WriteLine(string.Empty); -} -``` - -```none -BitwiseOrBigEndian Example -lhs: C0 DE -rhs: C0 FF EE -result: C0 FF FE - -lhs: 11000000 11011110 -rhs: 11000000 11111111 11101110 -result: 11000000 11111111 11111110 -``` - -#### Little Endian - -```c# -public static byte[] ByteArrayUtils.BitwiseOrLittleEndian(byte[] left, byte[] right) -``` - -```c# -public static void BitwiseOrLittleEndianExample() -{ - // Setup - var lhs = new byte[] { 0xC0, 0xDE }; - var rhs = new byte[] { 0xC0, 0xFF, 0xEE }; - // Act - var result = ByteArrayUtils.BitwiseOrLittleEndian(lhs, rhs); - // Conclusion - Console.WriteLine("BitwiseOrLittleEndian Example"); - Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); - Console.WriteLine(string.Empty); - Console.WriteLine($"lhs:\t{lhs.ToString("b")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("b")}"); - Console.WriteLine($"result:\t{result.ToString("b")}"); - Console.WriteLine(string.Empty); -} -``` - -```none -BitwiseOrLittleEndian Example -lhs: C0 DE -rhs: C0 FF EE -result: C0 FF EE - -lhs: 11000000 11011110 -rhs: 11000000 11111111 11101110 -result: 11000000 11111111 11101110 -``` - -### XOR - -`ByteArrayUtils.BitwiseXorBigEndian` and `ByteArrayUtils.BitwiseXorLittleEndian` will return the logical Exclusive Or of the `left` and `right` byte arrays. In the case where the input byte arrays are not of the same length the shortest array will be padded by the appropriate count of `0x00` most significant bytes so that comparisons may appropriately take place. - -#### Big Endian - -```c# -public static byte[] ByteArrayUtils.BitwiseXorBigEndian(byte[] left, byte[] right) -``` - -```c# -public static void BitwiseXorBigEndianExample() -{ - // Setup - var lhs = new byte[] { 0xC0, 0xDE }; - var rhs = new byte[] { 0xC0, 0xFF, 0xEE }; - // Act - var result = ByteArrayUtils.BitwiseXorBigEndian(lhs, rhs); - // Conclusion - Console.WriteLine("BitwiseXorBigEndian Example"); - Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); - Console.WriteLine(string.Empty); - Console.WriteLine($"lhs:\t{lhs.ToString("b")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("b")}"); - Console.WriteLine($"result:\t{result.ToString("b")}"); - Console.WriteLine(string.Empty); -} -``` - -```none -BitwiseXorBigEndian Example -lhs: C0 DE -rhs: C0 FF EE -result: C0 3F 30 - -lhs: 11000000 11011110 -rhs: 11000000 11111111 11101110 -result: 11000000 00111111 00110000 -``` - -#### Little Endian - -```c# -public static byte[] ByteArrayUtils.BitwiseXorLittleEndian(byte[] left, byte[] right) -``` - -```c# -public static void BitwiseXorLittleEndianExample() -{ - // Setup - var lhs = new byte[] { 0xC0, 0xDE }; - var rhs = new byte[] { 0xC0, 0xFF, 0xEE }; - // Act - var result = ByteArrayUtils.BitwiseXorLittleEndian(lhs, rhs); - // Conclusion - Console.WriteLine("BitwiseXorLittleEndian Example"); - Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); - Console.WriteLine(string.Empty); - Console.WriteLine($"lhs:\t{lhs.ToString("b")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("b")}"); - Console.WriteLine($"result:\t{result.ToString("b")}"); - Console.WriteLine(string.Empty); -} -``` - -```none -BitwiseXorLittleEndian Example -lhs: C0 DE -rhs: C0 FF EE -result: 00 21 EE - -lhs: 11000000 11011110 -rhs: 11000000 11111111 11101110 -result: 00000000 00100001 11101110 -``` - -## Bitshifting - -Bitshifting allows for the shifting of the underlying bit values of bytes in the desired direction. - -Bitshifting operations are endian agnostic. - -### Shift Right - -`ByteArrayUtils.ShiftBitsRight` is an arithmetic bit shift that returns the value of `bytes` with its underlying bits shifted `shift` indexes to the right. If the `carry` value is desired there exists an overload, shown below, that outs the result. - -```c# -public static byte[] ByteArrayUtils.ShiftBitsRight(this byte[] bytes, int shift) -``` - -```c# -public static void ShiftBitsRightExample() -{ - // Setup - var input = new byte[] { 0xAD, 0x0B, 0xEC, 0x0F, 0xFE, 0xE0 }; - const int shift = 5; - - // Act - var result = input.ShiftBitsRight(shift); - - // Conclusion - Console.WriteLine("ShiftBitsRight Example"); - Console.WriteLine($"shift:\t{shift}"); - Console.WriteLine($"input:\t{input.ToString("H")}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); - Console.WriteLine(string.Empty); - Console.WriteLine($"input:\t{input.ToString("b")}"); - Console.WriteLine($"result:\t{result.ToString("b")}"); - Console.WriteLine(string.Empty); -} - -``` - -```none -ShiftBitsRight Example -shift: 5 -input: AD 0B EC 0F FE E0 -result: 05 68 5F 60 7F F7 - -input: 10101101 00001011 11101100 00001111 11111110 11100000 -result: 00000101 01101000 01011111 01100000 01111111 11110111 -``` - -#### With Carry - -An overload to the above `ByteArrayUtils.ShiftBitsRight` that provides the `carry` result of the operation. - -```c# -public static byte[] ByteArrayUtils.ShiftBitsRight(this byte[] bytes, int shift, out byte[] carry) -``` - -```c# -public static void ShiftBitsRightCarryExample() -{ - // Setup - var input = new byte[] { 0xAD, 0x0B, 0xEC, 0x0F, 0xFE, 0xE0 }; - const int shift = 5; - - // Act - var result = input.ShiftBitsRight(shift, out var carry); - - // Conclusion - Console.WriteLine("ShiftBitsRight Carry Example"); - Console.WriteLine($"input:\t{input.ToString("H")}"); - Console.WriteLine($"shift:\t{shift}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); - Console.WriteLine($"carry:\t{carry.ToString("H")}"); - Console.WriteLine(string.Empty); - Console.WriteLine($"input:\t{input.ToString("b")}"); - Console.WriteLine($"result:\t{result.ToString("b")}"); - Console.WriteLine($"carry:\t{carry.ToString("b")}"); - Console.WriteLine(string.Empty); -} -``` - -```none -ShiftBitsRight Carry Example -input: AD 0B EC 0F FE E0 -shift: 5 -result: 05 68 5F 60 7F F7 -carry: 00 - -input: 10101101 00001011 11101100 00001111 11111110 11100000 -result: 00000101 01101000 01011111 01100000 01111111 11110111 -carry: 00000000 -``` - -### Shift Left - -`ByteArrayUtils.ShiftBitsLeft` is an arithmetic bit shift that returns the value of `bytes` with its underlying bits shifted `shift` indexes to the left. If the `carry` value is desired there exists an overload, shown below, that outs the result. - -```c# -public static byte[] ByteArrayUtils.ShiftBitsLeft(this byte[] bytes, int shift) -``` - -```c# -public static void ShiftBitsLeftExample() -{ - // Setup - var input = new byte[] { 0xAD, 0x0B, 0xEC, 0x0F, 0xFE, 0xE0 }; - const int shift = 5; - // Act - var result = input.ShiftBitsLeft(shift); - // Conclusion - Console.WriteLine("ShiftBitsLeft Example"); - Console.WriteLine($"input:\t{input.ToString("H")}"); - Console.WriteLine($"shift:\t{shift}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); - Console.WriteLine(string.Empty); - Console.WriteLine($"input:\t{input.ToString("b")}"); - Console.WriteLine($"result:\t{result.ToString("b")}"); - Console.WriteLine(string.Empty); -} -``` - -```none -ShiftBitsLeft Example -input: AD 0B EC 0F FE E0 -shift: 5 -result: A1 7D 81 FF DC 00 - -input: 10101101 00001011 11101100 00001111 11111110 11100000 -result: 10100001 01111101 10000001 11111111 11011100 00000000 -``` - -#### With Carry - -An overload to the above `ByteArrayUtils.ShiftBitsLeft` that provides the `carry` result of the operation. - -```c# -public static byte[] ByteArrayUtils.ShiftBitsLeft(this byte[] bytes, int shift, out byte[] carry) -``` - -```c# -public static void ShiftBitsLeftCarryExample() -{ - // Setup - var input = new byte[] { 0xAD, 0x0B, 0xEC, 0x0F, 0xFE, 0xE0 }; - const int shift = 5; - // Act - var result = input.ShiftBitsLeft(shift, out var carry); - // Conclusion - Console.WriteLine("ShiftBitsLeft Carry Example"); - Console.WriteLine($"input:\t{input.ToString("H")}"); - Console.WriteLine($"shift:\t{shift}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); - Console.WriteLine($"carry:\t{carry.ToString("H")}"); - Console.WriteLine(string.Empty); - Console.WriteLine($"input:\t{input.ToString("b")}"); - Console.WriteLine($"result:\t{result.ToString("b")}"); - Console.WriteLine($"carry:\t{carry.ToString("b")}"); - Console.WriteLine(string.Empty); -} -``` - -```none -ShiftBitsLeft Carry Example -input: AD 0B EC 0F FE E0 -shift: 5 -result: A1 7D 81 FF DC 00 -carry: 15 - -input: 10101101 00001011 11101100 00001111 11111110 11100000 -result: 10100001 01111101 10000001 11111111 11011100 00000000 -carry: 00010101 -``` diff --git a/docs/Bitwise-Byte-Array-Operations.rst b/docs/Bitwise-Byte-Array-Operations.rst new file mode 100644 index 0000000..f81778d --- /dev/null +++ b/docs/Bitwise-Byte-Array-Operations.rst @@ -0,0 +1,583 @@ +Bitwise Byte Array Operations +############################# + +The various Bitwise byte array operations provided by Gulliver implement the standard expected bitwise operations that should fit the needs of most developers. In some cases these methods are endian aware such that byte arrays of differing lengths may be appropriately lined up for operations. + +Unless otherwise stated the following methods are statically defined in the ``ByteArrayUtils`` class and do not modify their input. + +Addressing +********** + +The various addressing methods allow for the easy retrieval of individual byte, or bit data within the given byte array. + +Byte Array as Bit Array +======================= + +Byte arrays are great, but sometimes what we really need are bit (or ``boolean``) arrays instead. ``ByteArrayUtils.AddressBit`` method takes an array of ``byte`` treats it as if it were an array of bits instead returning the bit value at the given bit index ``index``. + +Keep in mind there are 8 bits in a byte. + +.. code-block:: c# + + public static bool ByteArrayUtils.AddressBit(this byte[] bytes, int index) + +.. code-block:: c# + :emphasize-lines: 13 + :caption: AddressBit Example + :name: AddressBit Example + + public static class Addressing + { + public static void AddressBitExample() + { + // Setup + var input = new byte[] { 0xC0, 0x1D }; + var bitLength = input.Length * 8; + + // Act + IEnumerable result = Enumerable.Range(0, bitLength - 1) + .Select(i => + { + var bit = input.AddressBit(i); + return (i, b: bit ? 1 : 0); + }) + .Select(x => $"[{x.i}]:{x.b}") + .Skip(4) + .Take(bitLength - 8) + .ToList(); + + // Conclusion + Console.WriteLine("AddressBit Example"); + Console.WriteLine($"input:\t{input.ToString("H")}"); + Console.WriteLine($"input:\t{input.ToString("b")}"); + Console.WriteLine($"result:\t{string.Join(", ", result)}"); + Console.WriteLine(string.Empty); + } + } + +.. code-block:: none + + AddressBit Example + input: C0 1D + input: 11000000 00011101 + result: [4]:0, [5]:0, [6]:1, [7]:1, [8]:1, [9]:0, [10]:1, [11]:1 + +Boolean Operations +****************** + +Boolean operations include the standard **NOT**, **AND**, **OR**, and **XOR**. + +**XNOR**, and the remaining 11 truth functions were deemed unnecessary. But remember, as an exercise for the developer, a **XNOR** may be created by using a **NOT** on the result of an **OR** operation, and given the principal of `Functional Completeness `_ each of the `16 truth functions `_ can be built using your newly created gate. + +NOT +=== + +``ByteArrayUtils.BitwiseNot`` will return the inverse of the provided ``bytes`` + +.. note:: Due to its unary nature the ``ByteArrayUtils.BitwiseNot`` operation is endian agnostic. + +.. code-block:: c# + + public static byte[] ByteArrayUtils.BitwiseNot(byte[] bytes) + +.. code-block:: c# + :emphasize-lines: 7 + :caption: Bitwise NOT Example + :name: Bitwise NOT Example + + public static void BitwiseNotExample() + { + // Setup + var input = new byte[] { 0x00, 0x11, 0xAC, 0xFF }; + // Act + + var result = ByteArrayUtils.BitwiseNot(input); + + // Conclusion + Console.WriteLine("BitwiseNot Example"); + Console.WriteLine($"input:\t{input.ToString("H")}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + Console.WriteLine(string.Empty); + Console.WriteLine($"input:\t{input.ToString("b")}"); + Console.WriteLine($"result:\t{result.ToString("b")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + BitwiseNot Example + input: 00 11 AC FF + result: FF EE 53 00 + + input: 00000000 00010001 10101100 11111111 + result: 11111111 11101110 01010011 00000000 + +AND +=== + +``ByteArrayUtils.BitwiseAndBigEndian`` and ``ByteArrayUtils.BitwiseAndLittleEndian`` will return the logical AND of the ``left`` and ``right`` byte arrays. In the case where the input byte arrays are not of the same length the shortest array will be padded by the appropriate count of ``0x00`` most significant bytes so that comparisons may appropriately take place. + +Big Endian +---------- + +.. code-block:: c# + + public static byte[] ByteArrayUtils.BitwiseAndBigEndian(byte[] left, byte[] right) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Bitwise AND Big-Endian Example + :name: Bitwise AND Big-Endian Example + + public static void BitwiseAndBigEndianExample() + { + // Setup + var lhs = new byte[] { 0xC0, 0xDE }; + var rhs = new byte[] { 0xC0, 0xFF, 0xEE }; + + // Act + var result = ByteArrayUtils.BitwiseAndBigEndian(lhs, rhs); + + // Conclusion + Console.WriteLine("BitwiseAndBigEndian Example"); + Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + Console.WriteLine(string.Empty); + Console.WriteLine($"lhs:\t{lhs.ToString("b")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("b")}"); + Console.WriteLine($"result:\t{result.ToString("b")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + BitwiseAndBigEndian Example + lhs: C0 DE + rhs: C0 FF EE + result: 00 C0 CE + + lhs: 11000000 11011110 + rhs: 11000000 11111111 11101110 + result: 00000000 11000000 11001110 + +Little Endian +------------- + +.. code-block:: c# + + public static byte[] ByteArrayUtils.BitwiseAndLittleEndian(byte[] left, byte[] right) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Bitwise AND Little-Endian Example + :name: Bitwise AND Little-Endian Example + + public static void BitwiseAndLittleEndianExample() + { + // Setup + var lhs = new byte[] { 0xC0, 0xDE }; + var rhs = new byte[] { 0xC0, 0xFF, 0xEE }; + + // Act + var result = ByteArrayUtils.BitwiseAndLittleEndian(lhs, rhs); + + // Conclusion + Console.WriteLine("BitwiseAndLittleEndian Example"); + Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + Console.WriteLine(string.Empty); + Console.WriteLine($"lhs:\t{lhs.ToString("b")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("b")}"); + Console.WriteLine($"result:\t{result.ToString("b")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + BitwiseAndLittleEndian Example + lhs: C0 DE + rhs: C0 FF EE + result: C0 DE 00 + + lhs: 11000000 11011110 + rhs: 11000000 11111111 11101110 + result: 11000000 11011110 00000000 + +OR +== + +``ByteArrayUtils.BitwiseOrBigEndian`` and ``ByteArrayUtils.BitwiseOrLittleEndian``will return the logical OR of the ``left`` and ``right`` byte arrays. In the case where the input byte arrays are not of the same length the shortest array will be padded by the appropriate count of ``0x00`` most significant bytes so that comparisons may appropriately take place. + +Big Endian +---------- + +.. code-block:: c# + + public static byte[] ByteArrayUtils.BitwiseOrBigEndian(byte[] left, byte[] right) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Bitwise OR Big-Endian Example + :name: Bitwise OR Big-Endian Example + + public static void BitwiseOrBigEndianExample() + { + // Setup + var lhs = new byte[] { 0xC0, 0xDE }; + var rhs = new byte[] { 0xC0, 0xFF, 0xEE }; + + // Act + var result = ByteArrayUtils.BitwiseOrBigEndian(lhs, rhs); + + // Conclusion + Console.WriteLine("BitwiseOrBigEndian Example"); + Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + Console.WriteLine(string.Empty); + Console.WriteLine($"lhs:\t{lhs.ToString("b")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("b")}"); + Console.WriteLine($"result:\t{result.ToString("b")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + BitwiseOrBigEndian Example + lhs: C0 DE + rhs: C0 FF EE + result: C0 FF FE + + lhs: 11000000 11011110 + rhs: 11000000 11111111 11101110 + result: 11000000 11111111 11111110 + +Little Endian +------------- + +.. code-block:: c# + + public static byte[] ByteArrayUtils.BitwiseOrLittleEndian(byte[] left, byte[] right) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Bitwise OR Little-Endian Example + :name: Bitwise OR Little-Endian Example + + public static void BitwiseOrLittleEndianExample() + { + // Setup + var lhs = new byte[] { 0xC0, 0xDE }; + var rhs = new byte[] { 0xC0, 0xFF, 0xEE }; + + // Act + var result = ByteArrayUtils.BitwiseOrLittleEndian(lhs, rhs); + + // Conclusion + Console.WriteLine("BitwiseOrLittleEndian Example"); + Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + Console.WriteLine(string.Empty); + Console.WriteLine($"lhs:\t{lhs.ToString("b")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("b")}"); + Console.WriteLine($"result:\t{result.ToString("b")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + BitwiseOrLittleEndian Example + lhs: C0 DE + rhs: C0 FF EE + result: C0 FF EE + + lhs: 11000000 11011110 + rhs: 11000000 11111111 11101110 + result: 11000000 11111111 11101110 + +XOR +=== + +``ByteArrayUtils.BitwiseXorBigEndian`` and ``ByteArrayUtils.BitwiseXorLittleEndian`` will return the logical Exclusive Or of the ``left`` and ``right`` byte arrays. In the case where the input byte arrays are not of the same length the shortest array will be padded by the appropriate count of ``0x00`` most significant bytes so that comparisons may appropriately take place. + +Big Endian +---------- + +.. code-block:: c# + + public static byte[] ByteArrayUtils.BitwiseXorBigEndian(byte[] left, byte[] right) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Bitwise XOR Big-Endian Example + :name: Bitwise XOR Big-Endian Example + + public static void BitwiseXorBigEndianExample() + { + // Setup + var lhs = new byte[] { 0xC0, 0xDE }; + var rhs = new byte[] { 0xC0, 0xFF, 0xEE }; + + // Act + var result = ByteArrayUtils.BitwiseXorBigEndian(lhs, rhs); + + // Conclusion + Console.WriteLine("BitwiseXorBigEndian Example"); + Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + Console.WriteLine(string.Empty); + Console.WriteLine($"lhs:\t{lhs.ToString("b")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("b")}"); + Console.WriteLine($"result:\t{result.ToString("b")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + BitwiseXorBigEndian Example + lhs: C0 DE + rhs: C0 FF EE + result: C0 3F 30 + + lhs: 11000000 11011110 + rhs: 11000000 11111111 11101110 + result: 11000000 00111111 00110000 + +Little Endian +------------- + +.. code-block:: c# + + public static byte[] ByteArrayUtils.BitwiseXorLittleEndian(byte[] left, byte[] right) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Bitwise XOR Little-Endian Example + :name: Bitwise XOR Little-Endian Example + + public static void BitwiseXorLittleEndianExample() + { + // Setup + var lhs = new byte[] { 0xC0, 0xDE }; + var rhs = new byte[] { 0xC0, 0xFF, 0xEE }; + + // Act + var result = ByteArrayUtils.BitwiseXorLittleEndian(lhs, rhs); + + // Conclusion + Console.WriteLine("BitwiseXorLittleEndian Example"); + Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + Console.WriteLine(string.Empty); + Console.WriteLine($"lhs:\t{lhs.ToString("b")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("b")}"); + Console.WriteLine($"result:\t{result.ToString("b")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + BitwiseXorLittleEndian Example + lhs: C0 DE + rhs: C0 FF EE + result: 00 21 EE + + lhs: 11000000 11011110 + rhs: 11000000 11111111 11101110 + result: 00000000 00100001 11101110 + +Bitshifting +*********** + +Bitshifting allows for the shifting of the underlying bit values of bytes in the desired direction. + +Bitshifting operations are endian agnostic. + +Shift Right +=========== + +``ByteArrayUtils.ShiftBitsRight`` is an arithmetic bit shift that returns the value of ``bytes`` with its underlying bits shifted ``shift`` indexes to the right. If the ``carry`` value is desired there exists an overload, shown below, that outs the result. + +.. code-block:: c# + + public static byte[] ByteArrayUtils.ShiftBitsRight(this byte[] bytes, int shift) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Shift Bits Right Example + :name: Shift Bits Right Example + + public static void ShiftBitsRightExample() + { + // Setup + var input = new byte[] { 0xAD, 0x0B, 0xEC, 0x0F, 0xFE, 0xE0 }; + const int shift = 5; + + // Act + var result = input.ShiftBitsRight(shift); + + // Conclusion + Console.WriteLine("ShiftBitsRight Example"); + Console.WriteLine($"shift:\t{shift}"); + Console.WriteLine($"input:\t{input.ToString("H")}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + Console.WriteLine(string.Empty); + Console.WriteLine($"input:\t{input.ToString("b")}"); + Console.WriteLine($"result:\t{result.ToString("b")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + ShiftBitsRight Example + shift: 5 + input: AD 0B EC 0F FE E0 + result: 05 68 5F 60 7F F7 + + input: 10101101 00001011 11101100 00001111 11111110 11100000 + result: 00000101 01101000 01011111 01100000 01111111 11110111 + +With Carry +---------- + +An overload to the above ``ByteArrayUtils.ShiftBitsRight`` that provides the ``carry`` result of the operation. + +.. code-block:: c# + + public static byte[] ByteArrayUtils.ShiftBitsRight(this byte[] bytes, int shift, out byte[] carry) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Shift Bits Right Carry Example + :name: Shift Bits Right Carry Example + + public static void ShiftBitsRightCarryExample() + { + // Setup + var input = new byte[] { 0xAD, 0x0B, 0xEC, 0x0F, 0xFE, 0xE0 }; + const int shift = 5; + + // Act + var result = input.ShiftBitsRight(shift, out var carry); + + // Conclusion + Console.WriteLine("ShiftBitsRight Carry Example"); + Console.WriteLine($"input:\t{input.ToString("H")}"); + Console.WriteLine($"shift:\t{shift}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + Console.WriteLine($"carry:\t{carry.ToString("H")}"); + Console.WriteLine(string.Empty); + Console.WriteLine($"input:\t{input.ToString("b")}"); + Console.WriteLine($"result:\t{result.ToString("b")}"); + Console.WriteLine($"carry:\t{carry.ToString("b")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + ShiftBitsRight Carry Example + input: AD 0B EC 0F FE E0 + shift: 5 + result: 05 68 5F 60 7F F7 + carry: 00 + + input: 10101101 00001011 11101100 00001111 11111110 11100000 + result: 00000101 01101000 01011111 01100000 01111111 11110111 + carry: 00000000 + +Shift Left +========== + +``ByteArrayUtils.ShiftBitsLeft`` is an arithmetic bit shift that returns the value of ``bytes`` with its underlying bits shifted ``shift`` indexes to the left. If the ``carry`` value is desired there exists an overload, shown below, that outs the result. + +.. code-block:: c# + + public static byte[] ByteArrayUtils.ShiftBitsLeft(this byte[] bytes, int shift) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Shift Bits Left Example + :name: Shift Bits Left Example + + public static void ShiftBitsLeftExample() + { + // Setup + var input = new byte[] { 0xAD, 0x0B, 0xEC, 0x0F, 0xFE, 0xE0 }; + const int shift = 5; + + // Act + var result = input.ShiftBitsLeft(shift); + + // Conclusion + Console.WriteLine("ShiftBitsLeft Example"); + Console.WriteLine($"input:\t{input.ToString("H")}"); + Console.WriteLine($"shift:\t{shift}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + Console.WriteLine(string.Empty); + Console.WriteLine($"input:\t{input.ToString("b")}"); + Console.WriteLine($"result:\t{result.ToString("b")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + ShiftBitsLeft Example + input: AD 0B EC 0F FE E0 + shift: 5 + result: A1 7D 81 FF DC 00 + + input: 10101101 00001011 11101100 00001111 11111110 11100000 + result: 10100001 01111101 10000001 11111111 11011100 00000000 + +With Carry +---------- + +An overload to the above ``ByteArrayUtils.ShiftBitsLeft`` that provides the ``carry`` result of the operation. + +.. code-block:: c# + + public static byte[] ByteArrayUtils.ShiftBitsLeft(this byte[] bytes, int shift, out byte[] carry) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Shift Bits Left Carry Example + :name: Shift Bits Left Carry Example + + public static void ShiftBitsLeftCarryExample() + { + // Setup + var input = new byte[] { 0xAD, 0x0B, 0xEC, 0x0F, 0xFE, 0xE0 }; + const int shift = 5; + + // Act + var result = input.ShiftBitsLeft(shift, out var carry); + + // Conclusion + Console.WriteLine("ShiftBitsLeft Carry Example"); + Console.WriteLine($"input:\t{input.ToString("H")}"); + Console.WriteLine($"shift:\t{shift}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + Console.WriteLine($"carry:\t{carry.ToString("H")}"); + Console.WriteLine(string.Empty); + Console.WriteLine($"input:\t{input.ToString("b")}"); + Console.WriteLine($"result:\t{result.ToString("b")}"); + Console.WriteLine($"carry:\t{carry.ToString("b")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + ShiftBitsLeft Carry Example + input: AD 0B EC 0F FE E0 + shift: 5 + result: A1 7D 81 FF DC 00 + carry: 15 + + input: 10101101 00001011 11101100 00001111 11111110 11100000 + result: 10100001 01111101 10000001 11111111 11011100 00000000 + carry: 00010101 diff --git a/docs/Building.rst b/docs/Building.rst new file mode 100644 index 0000000..f7a07bf --- /dev/null +++ b/docs/Building.rst @@ -0,0 +1,97 @@ +How to Build Gulliver +##################### + +.. note:: Make sure you clone the latest version of Gulliver's master branch from Github `https://github.com/sandialabs/Gulliver.git `_. + +Building with psake +******************* + +Gulliver uses `psake `_, *a build automation tool written in PowerShell*, to aid in the build, but it isn't explicitly necessary. To use psake follow the `"How to get started" `_ guide on their site, adding it to your path. + +If you'd rather not use psake jump ahead to see the manual way of doing things. + +psake tasks +=========== + +The psake tasks are defined in the ``pasake.ps1`` PowerShell script in the project root directory. + +.. note:: If you're using `Visual Studio Code `_, and if you're not you should be, the psake tasks are available in the Task Explorer. The tasks are referenced in the ``.vscode\tasks.json`` in the root directly of Gulliver. + +.. warning:: Before attempting to run any of the psake tasks make sure you have the appropriate prerequisites in place. + +The tasks of most concern are as follows: + +:``clean``: Cleans the C# portion of the project by removing the various ``obj`` and ``bin`` folders. +:``build_src``: Cleans and builds the C# source. +:``test``: Runs the Gulliver unit tests. +:``pack_debug``: Create a ``Gulliver.nuget`` and ``Gulliver.nuspec`` debug packages. + +:``build_docs``: Builds the Sphinx Documentation as HTML. + +C# Code +******* + +Setup Your C# Environment +========================= + +Gulliver is built with C#, if you want to build Gulliver you'll want to set yourself up to build C# code. + +#. Install the `.NET Core SDK `_ appropriate for your environment. +#. Consider installing `Visual Studio `_ and/or `Visual Studio Code `_. +#. Everything you want to do here on out can be done with `dotnet `_ command line tool. + + - To build + + .. code-block:: PowerShell + + dotnet build path\to\gulliver\src\Gulliver.sln + + - To test + + .. code-block:: PowerShell + + dotnet test path\to\gulliver\src\Gulliver.Tests\Gulliver.Tests.csproj + + - To package + + .. code-block:: PowerShell + + dotnet pack path\to\gulliver\src\Gulliver\Gulliver.csproj + +Build The Documentation +*********************** + +First Things First +================== + +.. note:: Before you can run, first you must walk. Likewise, before you can build docs fist you must do some Python stuff. + +The documentation relies on `Sphinx `_ and `Python `_ and a number of Python packages. + +#. Install `Python 3.7+ `_ +#. Install Sphinx 2.2.0+ via the Python package manager *pip* + + .. code-block:: PowerShell + + pip install sphinx + +#. Install the `Sphinx RTD Theme `_ via *pip* + + .. code-block:: PowerShell + + pip install sphinx_rtd_theme + +Build +===== + +Once you have all the perquisites in place building the documentation, as HTML [#SphinxBuilds]_, is as simple as locating the ``make.bat`` in the Gulliver ``docs`` folder. Then simply execute + + .. code-block:: PowerShell + + path\to\gulliver\docs\make.bat html + +Once complete the documentation will be present in the ``_build`` sub folder of ``docs``. + +.. rubric:: footnotes + +.. [#SphinxBuilds] You don't have to stick with HTML builds, Sphinx provides other artifacts types as well, take a look at their `Invocation of sphinx-build `_ for other options. diff --git a/docs/Community.md b/docs/Community.md deleted file mode 100644 index 3b5a1ed..0000000 --- a/docs/Community.md +++ /dev/null @@ -1,13 +0,0 @@ -# Community - -## GitHub - -[![GitHub Stars](https://img.shields.io/github/stars/sandialabs/gulliver?style=social)](https://github.com/sandialabs/Gulliver/stargazers) -[![GitHub Watchers](https://img.shields.io/github/watchers/sandialabs/gulliver?style=social)](https://github.com/sandialabs/Gulliver/watchers) - -Source Code available on [Gulliver GitHub](https://github.com/sandialabs/Gulliver) - -## File an Issue - -Issues should be filed on the Gulliver GitHub [Issue Tracker](https://github.com/sandialabs/Gulliver/issues). - diff --git a/docs/Community.rst b/docs/Community.rst new file mode 100644 index 0000000..f2c6713 --- /dev/null +++ b/docs/Community.rst @@ -0,0 +1,18 @@ +Community +######### + +GitHub +****** + +.. image:: https://img.shields.io/github/stars/sandialabs/gulliver?style=social + :alt: GitHub Stars + :target: https://github.com/sandialabs/Gulliver/stargazers + +.. image:: https://img.shields.io/github/watchers/sandialabs/gulliver?style=social + :alt: GitHub Watchers + :target: https://github.com/sandialabs/Gulliver/watchers + +File an Issue +************* + +Issues should be filed on the Gulliver GitHub `Issue Tracker `_. diff --git a/docs/Concurent-Endian-Byte-Enumerables.md b/docs/Concurent-Endian-Byte-Enumerables.md deleted file mode 100644 index 93087bc..0000000 --- a/docs/Concurent-Endian-Byte-Enumerables.md +++ /dev/null @@ -1,10 +0,0 @@ -# Concurent Endian Byte Enumerables - -`ConcurrentBigEndianByteEnumerable` and `ConcurrentLittleEndianByteEnumerable` allows for ease in parallel indexing a pair of byte arrays, that may not be of the same length, in the desired endianness. This comes in particularly useful when running bitwise or mathematical operations. - -This topic will be further expounded upon at a later date. In the meantime please feel free to browse the source code available: - - [GitHub/Gulliver](https://github.com/sandialabs/gulliver) - - [IConcurrentByteEnumerable](https://github.com/sandialabs/Gulliver/blob/master/src/Gulliver/Enumerables/IConcurrentByteEnumerable.cs) - - [AbstractConcurrentByteEnumerable](https://github.com/sandialabs/Gulliver/blob/master/src/Gulliver/Enumerables/AbstractConcurrentByteEnumerable.cs) - - [ConcurrentBigEndianByteEnumerable](https://github.com/sandialabs/Gulliver/blob/master/src/Gulliver/Enumerables/ConcurrentBigEndianByteEnumerable.cs) - - [ConcurrentLittleEndianByteEnumerable](https://github.com/sandialabs/Gulliver/blob/master/src/Gulliver/Enumerables/ConcurrentLittleEndianByteEnumerable.cs) diff --git a/docs/Concurent-Endian-Byte-Enumerables.rst b/docs/Concurent-Endian-Byte-Enumerables.rst new file mode 100644 index 0000000..a9590bd --- /dev/null +++ b/docs/Concurent-Endian-Byte-Enumerables.rst @@ -0,0 +1,15 @@ +Concurrent Endian Byte Enumerables +################################## + +``ConcurrentBigEndianByteEnumerable`` and ``ConcurrentLittleEndianByteEnumerable`` allows for ease in parallel indexing a pair of byte arrays, that may not be of the same length, in the desired endianness. This comes in particularly useful when running bitwise or mathematical operations. + +.. warning:: This topic will be further expounded upon at a later date. In the meantime please feel free to browse the source code available: + + - `GitHub/Gulliver `_ + + - `IConcurrentByteEnumerable `_ + + - `AbstractConcurrentByteEnumerable `_ + + - `ConcurrentBigEndianByteEnumerable `_ + - `ConcurrentLittleEndianByteEnumerable `_ diff --git a/docs/Endian-Byte-Enumerables.md b/docs/Endian-Byte-Enumerables.md deleted file mode 100644 index 57e1dd5..0000000 --- a/docs/Endian-Byte-Enumerables.md +++ /dev/null @@ -1,10 +0,0 @@ -# Endian Byte Enumerables - -The `LittleEndianByteEnumerable` and `BigEndianByteEnumerable` gives access to more cleanly treat little-endian and big-endian byte arrays as enumerables in an expected indexable manner regardless of the underlying endianness ignoring `0x00` valued most significant bytes and managing indexing of the most significant byte at the 0th index. - -This topic will be further expounded upon at a later date. In the meantime please feel free to browse the source code available: - - [GitHub/Gulliver](https://github.com/sandialabs/gulliver) - - [IByteEnumerable](https://github.com/sandialabs/Gulliver/blob/master/src/Gulliver/Enumerables/IByteEnumerable.cs) - - [AbstractByteEnumerable](https://github.com/sandialabs/Gulliver/blob/master/src/Gulliver/Enumerables/AbstractByteEnumerable.cs) - - [BigEndianByteEnumerable](https://github.com/sandialabs/Gulliver/blob/master/src/Gulliver/Enumerables/BigEndianByteEnumerable.cs) - - [LittleEndianByteEnumerable](https://github.com/sandialabs/Gulliver/blob/master/src/Gulliver/Enumerables/LittleEndianByteEnumerable.cs) diff --git a/docs/Endian-Byte-Enumerables.rst b/docs/Endian-Byte-Enumerables.rst new file mode 100644 index 0000000..01936fb --- /dev/null +++ b/docs/Endian-Byte-Enumerables.rst @@ -0,0 +1,15 @@ +Endian Byte Enumerables +####################### + +The ``LittleEndianByteEnumerable`` and ``BigEndianByteEnumerable`` gives access to more cleanly treat little-endian and big-endian byte arrays as enumerables in an expected indexable manner regardless of the underlying endianness ignoring ``0x00`` valued most significant bytes and managing indexing of the most significant byte at the 0th index. + +.. warning:: This topic will be further expounded upon at a later date. In the meantime please feel free to browse the source code available: + + - `GitHub/Gulliver `_ + + - `IByteEnumerable `_ + + - `AbstractByteEnumerable `_ + + - `BigEndianByteEnumerable `_ + - `LittleEndianByteEnumerable `_ diff --git a/docs/FAQ.md b/docs/FAQ.md deleted file mode 100644 index df952df..0000000 --- a/docs/FAQ.md +++ /dev/null @@ -1,3 +0,0 @@ -# Frequently Asked Questions - -No questions have been asked, frequently or otherwise. diff --git a/docs/FAQ.rst b/docs/FAQ.rst new file mode 100644 index 0000000..3d48a16 --- /dev/null +++ b/docs/FAQ.rst @@ -0,0 +1,4 @@ +Frequently Asked Questions +########################## + +.. note:: No questions have been asked, frequently or otherwise. diff --git a/docs/FixedBytes.md b/docs/FixedBytes.md deleted file mode 100644 index 300de73..0000000 --- a/docs/FixedBytes.md +++ /dev/null @@ -1,39 +0,0 @@ -# FixedBytes - -The `FixedBytes` class brings many of these operations together allowing developers to treat a `byte[]` as a more complex object without the need to explicitly call helper or extension methods. It acts as a wrapper around an array of bytes in BigEndian byte order. - -`FixedBytes` implements - - `IFormattable,` - - `IReadOnlyCollection` - - `IEquatable` - - `IEquatable>` - - `IComparable` - - `IComparable>` - - `IComparable` - -Operator overloads provided by `FixedBytes`: - - For bitwise operations - - `|` - OR - - `&` - AND - - `^` - XOR - - `!` - NOT - - `<<` - Shift Left - - `>>` - Shift Right -- Mathematical Operations (Unsigned by defined endianness) - - `+` - Addition - - `-` - Subtraction - - `>` - Greater Than - - `<` - Less Than - - `>=` - Greater Than or Equal - - `<=` - Less Than or Equal - - `==` - Equals - - `!=` - Not Equals -- Explicit Conversion (cast from) - - `byte[]` - - `List` -- Implicit Conversion (cast to) - - `byte[]` - -This topic will be further expounded upon at a later date. In the mean time please feel free to browse the source code available - - [GitHub/Gulliver](https://github.com/sandialabs/gulliver) - - [FixedBytes](https://github.com/sandialabs/Gulliver/blob/master/src/Gulliver/FixedBytes.cs) diff --git a/docs/FixedBytes.rst b/docs/FixedBytes.rst new file mode 100644 index 0000000..79693a6 --- /dev/null +++ b/docs/FixedBytes.rst @@ -0,0 +1,63 @@ +FixedBytes +########## + +The ``FixedBytes`` class brings many of these operations together allowing developers to treat a ``byte[]`` as a more complex object without the need to explicitly call helper or extension methods. It acts as a wrapper around an array of bytes in BigEndian byte order. + +Implements +********** + +- ``IFormattable`` +- ``IReadOnlyCollection`` +- ``IEquatable`` +- ``IEquatable>`` +- ``IComparable`` +- ``IComparable>`` +- ``IComparable`` + +Operators +********* + +.. note:: Operators, where pertinent, treat ``FixedBytes`` as unsigned big-endian integers + +Bitwise +======= + +- ``|`` - OR +- ``&`` - AND +- ``^`` - XOR +- ``!`` - NOT +- ``<<`` - Shift Left +- ``>>`` - Shift Right + +Mathematical +============ + +- ``+`` - Addition +- ``-`` - Subtraction + +Comparison +========== + +- ``>`` - Greater Than +- ``<`` - Less Than +- ``>=`` - Greater Than or Equal +- ``<=`` - Less Than or Equal +- ``==`` - Equals +- ``!=`` - Not Equals + +Explicit Conversion (cast from) +=============================== + +- ``byte[]`` +- ``List`` + +Implicit Conversion (cast to) +============================= + +- ``byte[]`` + +.. warning:: This topic will be further expounded upon at a later date. In the mean time please feel free to browse the source code available + + - `GitHub/Gulliver `_ + + - `FixedBytes `_ diff --git a/docs/General-Operations.md b/docs/General-Operations.md deleted file mode 100644 index 8401646..0000000 --- a/docs/General-Operations.md +++ /dev/null @@ -1,414 +0,0 @@ -# General Byte Array Operations - -There exist a number of operations one may want to do on an array of bytes that don't directly relate to explicit higher order mathematical operations or typical bitwise operations, baring any other name space we're considering these general operations. Typically their about building, transforming, mutating, or gathering meta data. - -Unless otherwise stated the following methods are statically defined in the `ByteArrayUtils` class and do not modify their input. - -## Byte Array Creation and Population - -It is usually easy enough to new up a new byte array, however sometimes something a little more exotic than an array of `0x00` bytes are desired. - -### Create - -It can be necessary to create a byte array filled with a known value. In this case `ByteArrayUtils.CreateByteArray` can be used to create a byte array of a given `length` filled with an optional `element` value. - -```c# -public static byte[] ByteArrayUtils.CreateByteArray(int length, byte element = 0x00) -``` - -In the following example a byte array of length `10` is filled with the the repeated byte value of `0x42`: - -```c# -public static void CreateByteArrayExample() -{ - // Setup - const int length = 10; - const byte element = 0x42; // optional, defaults to 0x00 - - // Act - // creates a byte array of length 10, filled with bytes of 0x42 - var result = ByteArrayUtils.CreateByteArray(length, element); - - // Conclusion - Console.WriteLine("CreateByteArray example"); - Console.WriteLine($"length:\t{length}"); - Console.WriteLine($"element:\t{element}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); -} -``` - -```none -CreateByteArray example -length: 10 -element: 66 -result: 42 42 42 42 42 42 42 42 42 42 -``` - -Creates a byte array `resultBytes` with a value of `[0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42]`. - -## Byte Array Mutation - -Byte arrays often need to be altered in some way to process them, the addition of needing to be concerned with endiness can make this a bit less straightforward. - -### Trimming - -Leading zero byte trimming works similarly for both big and little endian byte arrays. In both cases leading, or most significant, zero value bytes are removed. For big endian those bytes starting at the 0th index are removed, whereas for little endian zero bytes are removed from the tail of the array. - -If a byte array has no most significant zero valued bytes then a copy of the original will be returned. - -#### Big Endian - -To trim all `0x00` bytes starting at the 0th index of the byte array - -```c# -public static byte[] ByteArrayUtils.TrimBigEndianLeadingZeroBytes(this byte[] input) -``` - -The following example trims the array `[0x00, 0x00, 0x2A, 0x00]` returning `[0x2A, 0x00`]: - -```c# -public static void TrimBigEndianLeadingZeroBytes() -{ - // Setup - var input = new byte[] { 0x00, 0x00, 0x2A, 0x00 }; - - // Act - var result = input.TrimBigEndianLeadingZeroBytes(); - - // Conclusion - Console.WriteLine("TrimBigEndianLeadingZeroBytes example"); - Console.WriteLine($"input:\t{input.ToString("H")}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); -} -``` - -```none -TrimBigEndianLeadingZeroBytes example -input: 00 00 2A 00 -result: 2A 00 -``` - -Note that the final `0x00` value was not removed as we were only trimming most significant zero values. - -#### Little Endian - -To trim all `0x00` bytes starting at the end of the byte array - -```c# -public static byte[] ByteArrayUtils.TrimLittleEndianLeadingZeroBytes(this byte[] input) -``` - -```c# -public static void TrimLittleEndianLeadingZeroBytes() -{ - // Setup - var input = new byte[] { 0x2A, 0xFF, 0x2A, 0x00 }; - - // Act - var result = input.TrimLittleEndianLeadingZeroBytes(); - - // Conclusion - Console.WriteLine("TrimLittleEndianLeadingZeroBytes"); - Console.WriteLine($"input:\t{input.ToString("H")}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); -} -``` - -```none -TrimLittleEndianLeadingZeroBytes -input: 2A FF 2A 00 -result: 2A FF 2A -``` - -### Padding - -When padding a byte array, if the the given array length is equal to or larger than `finalLength` a copy of the original array will be returned. Otherwise bytes with the value of `element` will be padded in the most significant value place. - -#### Big Endian - -```c# -public static byte[] ByteArrayUtils.PadBigEndianMostSignificantBytes(this byte[] source, int finalLength, byte element = 0x00) -``` - -```c# -public static void PadBigEndianMostSignificantBytesExample() -{ - // Setup - var bytes = new byte[] { 0xDE, 0xFA, 0xCE, 0xC0, 0xDE }; - const int finalLength = 6; - // Act - var result = bytes.PadBigEndianMostSignificantBytes(finalLength); - // Conclusion - Console.WriteLine("PadBigEndianMostSignificantBytes Short Example"); - Console.WriteLine($"input:\t{bytes.ToString("H")}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); - Console.WriteLine(string.Empty); -} -``` - -```none -PadBigEndianMostSignificantBytes Short Example -input: DE FA CE C0 DE -result: 00 DE FA CE C0 DE -``` - -#### Little Endian - -```c# -public static byte[] ByteArrayUtils.PadLittleEndianMostSignificantBytes(this byte[] source, int finalLength, byte element = 0x00) -``` - -```c# -public static void PadLittleEndianMostSignificantBytesExample() -{ - // Setup - var input = new byte[] { 0xDE, 0xFA, 0xCE, 0xC0, 0xDE }; - const int finalLength = 6; - // Act - var result = input.PadLittleEndianMostSignificantBytes(finalLength); - // Conclusion - Console.WriteLine("PadLittleEndianMostSignificantBytes Example"); - Console.WriteLine($"input:\t{input.ToString("H")}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); - Console.WriteLine(string.Empty); -} -``` - -```none -PadLittleEndianMostSignificantBytes Example -input: DE FA CE C0 DE -result: DE FA CE C0 DE 00 -``` - -### Appending - -Appending operations are endian agnostic, new byte values will appear after the highest order index of the input array. - -#### Append Bytes - -The `ByteArrayUtils.AppendBytes` operation simply adds `count` bytes to the end of the value provided by the `source` array. The optional `element` parameter may be provided to use a byte value other than the default `0x00`. - -```c# -public static byte[] ByteArrayUtils.AppendBytes(this byte[] source, int count, byte element = 0x00) -``` - -```c# -public static void AppendBytesExample() -{ - // Setup - var input = new byte[] { 0xC0, 0xC0, 0xCA, 0xFE }; - const int count = 4; - // Act - var result = input.AppendBytes(count); - // Conclusion - Console.WriteLine("AppendBytes Example"); - Console.WriteLine($"input:\t{input.ToString("H")}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); - Console.WriteLine(string.Empty); -} -``` - -```none -AppendBytes Example -input: C0 C0 CA FE -result: C0 C0 CA FE 00 00 00 00 -``` - -#### Append Shortest - -`ByteArrayUtils.AppendShortest` works much like `ByteArrayUtils.AppendBytes`, except instead of providing a desired byte count, the two input arrays lengths are compared and the shortest array is returned, along with the the longest array, with enough `0x00` bytes such that both byte arrays are now the same length. - -Effectively this adds most significant `0x00` bytes to the shortest little endian byte array, but may be useful for big endian arrays as well. - -```c# -public static (byte[] left, byte[] right) ByteArrayUtils.AppendShortest(byte[] left, byte[] right) -``` - -```c# -public static void AppendShortestExample() -{ - // Setup - var lhs = new byte[] { 0xDE, 0xCA, 0xF0 }; - var rhs = new byte[] { 0xCA, 0xFE, 0xC0, 0xFF, 0xEE }; - // Act - var (lhsResult, rhsResult) = ByteArrayUtils.AppendShortest(lhs, rhs); - // Conclusion - Console.WriteLine("AppendShortest Example"); - Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); - Console.WriteLine($"lhsResult:\t{lhsResult.ToString("H")}"); - Console.WriteLine($"lhsResult:\t{rhsResult.ToString("H")}"); - Console.WriteLine(string.Empty); -} -``` - -```none -AppendShortest Example -lhs: DE CA F0 -rhs: CA FE C0 FF EE -lhsResult: DE CA F0 00 00 -lhsResult: CA FE C0 FF EE -``` - -### Prepend - -Prepending operations are endian agnostic, new byte values will appear after the lowest order index of the input array. - -#### Prepend Bytes - -The `ByteArrayUtils.PrependBytes` operation simply adds `count` bytes to the start of the value provided by the `source` array. The optional `element` parameter may be provided to use a byte value other than the default `0x00`. This is essentially the inverse of `ByteArrayUtils.AppendBytes` operation. - -```c# -public static byte[] ByteArrayUtils.PrependBytes(this byte[] source, int count, byte element = 0x00) -``` - -```c# -public static void PrependBytesExample() -{ - // Setup - var input = new byte[] { 0xC0, 0xC0, 0xCA, 0xFE }; - const int count = 4; - // Act - var result = input.PrependBytes(count); - // Conclusion - Console.WriteLine("PrependBytes Example"); - Console.WriteLine($"input:\t{input.ToString("H")}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); - Console.WriteLine(string.Empty); -} -``` - -```none -PrependBytes Example -input: C0 C0 CA FE -result: 00 00 00 00 C0 C0 CA FE -``` - -#### Prepend Shortest - -`ByteArrayUtils.PrependShortest` works much like `ByteArrayUtils.PrependBytes`, except instead of providing a desired byte count, the two input arrays lengths are compared and the shortest array is returned, along with the the longest array, with enough `0x00` bytes such that both byte arrays are now the same length. - -Effectively this adds most significant `0x00` bytes to the shortest big endian byte array, but may be useful for little endian arrays as well. - -```c# -public static (byte[] left, byte[] right) ByteArrayUtils.PrependShortest(byte[] left, byte[] right) -``` - -```c# -public static void PrependShortestExample() -{ - // Setup - var lhs = new byte[] { 0xDE, 0xCA, 0xF0 }; - var rhs = new byte[] { 0xCA, 0xFE, 0xC0, 0xFF, 0xEE }; - // Act - var (lhsResult, rhsResult) = ByteArrayUtils.PrependShortest(lhs, rhs); - // Conclusion - Console.WriteLine("PrependShortest Example"); - Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); - Console.WriteLine($"lhsResult:\t{lhsResult.ToString("H")}"); - Console.WriteLine($"lhsResult:\t{rhsResult.ToString("H")}"); - Console.WriteLine(string.Empty); -} -``` - -```none -PrependShortest Example -lhs: DE CA F0 -rhs: CA FE C0 FF EE -lhsResult: 00 00 DE CA F0 -lhsResult: CA FE C0 FF EE -``` - -### Reversing - -Unsurprisingly, hopefully, `ByteArrayUtils.ReverseBytes` returns the reverse of the provided `bytes` byte array. - -The `ReverseBytes` operation is endian agnostic. - -```c# -public static byte[] ByteArrayUtils.ReverseBytes(this byte[] bytes) -``` - -```c# -public static void ReverseBytesExample() -{ - // Setup - var input = new byte[] { 0xC0, 0x1D, 0xC0, 0xFF, 0xEE }; - // Act - var result = input.ReverseBytes(); - // Conclusion - Console.WriteLine("ReverseBytes example"); - Console.WriteLine($"input:\t{input.ToString("H")}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); - Console.WriteLine(string.Empty); -} -``` - -```none -ReverseBytes example -input: C0 1D C0 FF EE -result: EE FF C0 1D C0 -``` - -## Effective Length - -Effective length provides the ability to count the number of non-most significant bytes within a byte array. Eg. the length of meaningful bytes within the array. - -### Big Endian - -`ByteArrayUtils.BigEndianEffectiveLength` returns an `int` representing the byte length of the given `input` disregarding the `0x00` bytes at the beginning of the array. - -```c# -public static int ByteArrayUtils.BigEndianEffectiveLength(this byte[] input) -``` - -```c# -public static void BigEndianEffectiveLengthExample() -{ - // Setup - var input = new byte[] { 0x00, 0x00, 0x00, 0xDA, 0xBD, 0xAD }; - // Act - var result = input.BigEndianEffectiveLength(); - // Conclusion - Console.WriteLine("BigEndianEffectiveLength Example"); - Console.WriteLine($"input:\t{input.ToString("H")}"); - Console.WriteLine($"result:\t{result}"); - Console.WriteLine(string.Empty); -} -``` - -```none -BigEndianEffectiveLength Example -input: 00 00 00 DA BD AD -result: 3 -``` - -### Little Endian - -`ByteArrayUtils.LittleEndianEffectiveLength` returns an `int` representing the byte length of the given `input` disregarding the `0x00` bytes at the end of the array. - -```c# -public static int ByteArrayUtils.LittleEndianEffectiveLength(this byte[] input) -``` - -```c# -public static void LittleEndianEffectiveLengthExample() -{ - // Setup - var input = new byte[] { 0xDA, 0xB0, 0x00, 0x00, 0x00, 0x00 }; - // Act - var result = input.LittleEndianEffectiveLength(); - // Conclusion - Console.WriteLine("LittleEndianEffectiveLength Example"); - Console.WriteLine($"input:\t{input.ToString("H")}"); - Console.WriteLine($"result:\t{result}"); - Console.WriteLine(string.Empty); -} -``` - -```none -LittleEndianEffectiveLength Example -input: DA B0 00 00 00 00 -result: 2 -``` diff --git a/docs/General-Operations.rst b/docs/General-Operations.rst new file mode 100644 index 0000000..ece9956 --- /dev/null +++ b/docs/General-Operations.rst @@ -0,0 +1,488 @@ +General Byte Array Operations +############################# + +There exist a number of operations one may want to do on an array of bytes that don't directly relate to explicit higher order mathematical operations or typical bitwise operations, baring any other name space we're considering these general operations. Typically their about building, transforming, mutating, or gathering meta data. + +Unless otherwise stated the following methods are statically defined in the ``ByteArrayUtils`` class and do not modify their input. + +Byte Array Creation and Population +********************************** + +It is usually easy enough to new up a new byte array, however sometimes something a little more exotic than an array of ``0x00`` bytes are desired. + +Create +====== + +It can be necessary to create a byte array filled with a known value. In this case ``ByteArrayUtils.CreateByteArray`` can be used to create a byte array of a given ``length`` filled with an optional ``element`` value. + +.. code-block:: c# + + public static byte[] ByteArrayUtils.CreateByteArray(int length, byte element = 0x00) + +In the following example a byte array of length ``10`` is filled with the the repeated byte value of ``0x42``: + +.. code-block:: c# + :emphasize-lines: 9 + :caption: Create Byte Array Example + :name: Create Byte Array Example + + public static void CreateByteArrayExample() + { + // Setup + const int length = 10; + const byte element = 0x42; // optional, defaults to 0x00 + + // Act + // creates a byte array of length 10, filled with bytes of 0x42 + var result = ByteArrayUtils.CreateByteArray(length, element); + + // Conclusion + Console.WriteLine("CreateByteArray example"); + Console.WriteLine($"length:\t{length}"); + Console.WriteLine($"element:\t{element}"); + Console.WriteLine(\$"result:\t{result.ToString("H")}"); + } + +.. code-block:: none + + CreateByteArray example + length: 10 + element: 66 + result: 42 42 42 42 42 42 42 42 42 42 + +Creates a byte array ``resultBytes`` with a value of ``[0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42]``. + +Byte Array Mutation +******************* + +Byte arrays often need to be altered in some way to process them, the addition of needing to be concerned with endiness can make this a bit less straightforward. + +Trimming +======== + +Leading zero byte trimming works similarly for both big and little endian byte arrays. In both cases leading, or most significant, zero value bytes are removed. For big endian those bytes starting at the 0th index are removed, whereas for little endian zero bytes are removed from the tail of the array. + +If a byte array has no most significant zero valued bytes then a copy of the original will be returned. + +Big Endian +---------- + +To trim all ``0x00`` bytes starting at the 0th index of the byte array + +.. code-block:: c# + + public static byte[] ByteArrayUtils.TrimBigEndianLeadingZeroBytes(this byte[] input) + +The following example trims the array ``[0x00, 0x00, 0x2A, 0x00]`` returning ``[0x2A, 0x00``]: + +.. code-block:: c# + :emphasize-lines: 7 + :caption: Trim Big-Endian Leading Zero Bytes + :name: Trim Big-Endian Leading Zero Bytes + + public static void TrimBigEndianLeadingZeroBytes() + { + // Setup + var input = new byte[] { 0x00, 0x00, 0x2A, 0x00 }; + + // Act + var result = input.TrimBigEndianLeadingZeroBytes(); + + // Conclusion + Console.WriteLine("TrimBigEndianLeadingZeroBytes example"); + Console.WriteLine($"input:\t{input.ToString("H")}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + } + +.. code-block:: none + + TrimBigEndianLeadingZeroBytes example + input: 00 00 2A 00 + result: 2A 00 + +Note that the final ``0x00`` value was not removed as we were only trimming most significant zero values. + +Little Endian +------------- + +To trim all ``0x00`` bytes starting at the end of the byte array + +.. code-block:: c# + + public static byte[] ByteArrayUtils.TrimLittleEndianLeadingZeroBytes(this byte[] input) + +.. code-block:: c# + :emphasize-lines: 7 + :caption: Trim Little-Endian Leading Zero Bytes + :name: Trim Little-Endian Leading Zero Bytes + + public static void TrimLittleEndianLeadingZeroBytes() + { + // Setup + var input = new byte[] { 0x2A, 0xFF, 0x2A, 0x00 }; + + // Act + var result = input.TrimLittleEndianLeadingZeroBytes(); + + // Conclusion + Console.WriteLine("TrimLittleEndianLeadingZeroBytes"); + Console.WriteLine($"input:\t{input.ToString("H")}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + } + +.. code-block:: none + + TrimLittleEndianLeadingZeroBytes + input: 2A FF 2A 00 + result: 2A FF 2A + +Padding +======= + +When padding a byte array, if the the given array length is equal to or larger than ``finalLength`` a copy of the original array will be returned. Otherwise bytes with the value of ``element`` will be padded in the most significant value place. + +Big Endian +---------- + +.. code-block:: c# + + public static byte[] ByteArrayUtils.PadBigEndianMostSignificantBytes(this byte[] source, int finalLength, byte element = 0x00) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Pad Big-Endian Most Significant Bytes Example + :name: Pad Big-Endian Most Significant Bytes Example + + public static void PadBigEndianMostSignificantBytesExample() + { + // Setup + var bytes = new byte[] { 0xDE, 0xFA, 0xCE, 0xC0, 0xDE }; + const int finalLength = 6; + + // Act + var result = bytes.PadBigEndianMostSignificantBytes(finalLength); + + // Conclusion + Console.WriteLine("PadBigEndianMostSignificantBytes Short Example"); + Console.WriteLine($"input:\t{bytes.ToString("H")}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + PadBigEndianMostSignificantBytes Short Example + input: DE FA CE C0 DE + result: 00 DE FA CE C0 DE + +Little Endian +------------- + +.. code-block:: c# + + public static byte[] ByteArrayUtils.PadLittleEndianMostSignificantBytes(this byte[] source, int finalLength, byte element = 0x00) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Pad Little-Endian Most Significant Bytes Example + :name: Pad Little-Endian Most Significant Bytes Example + + public static void PadLittleEndianMostSignificantBytesExample() + { + // Setup + var input = new byte[] { 0xDE, 0xFA, 0xCE, 0xC0, 0xDE }; + const int finalLength = 6; + + // Act + var result = input.PadLittleEndianMostSignificantBytes(finalLength); + + // Conclusion + Console.WriteLine("PadLittleEndianMostSignificantBytes Example"); + Console.WriteLine($"input:\t{input.ToString("H")}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + PadLittleEndianMostSignificantBytes Example + input: DE FA CE C0 DE + result: DE FA CE C0 DE 00 + +Appending +========= + +Appending operations are endian agnostic, new byte values will appear after the highest order index of the input array. + +Append Bytes +------------ + +The ``ByteArrayUtils.AppendBytes`` operation simply adds ``count`` bytes to the end of the value provided by the ``source`` array. The optional ``element`` parameter may be provided to use a byte value other than the default ``0x00``. + +.. code-block:: c# + + public static byte[] ByteArrayUtils.AppendBytes(this byte[] source, int count, byte element = 0x00) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Append Bytes Example + :name: Append Bytes Example + + public static void AppendBytesExample() + { + // Setup + var input = new byte[] { 0xC0, 0xC0, 0xCA, 0xFE }; + const int count = 4; + + // Act + var result = input.AppendBytes(count); + + // Conclusion + Console.WriteLine("AppendBytes Example"); + Console.WriteLine($"input:\t{input.ToString("H")}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + AppendBytes Example + input: C0 C0 CA FE + result: C0 C0 CA FE 00 00 00 00 + +Append Shortest +--------------- + +``ByteArrayUtils.AppendShortest`` works much like ``ByteArrayUtils.AppendBytes``, except instead of providing a desired byte count, the two input arrays lengths are compared and the shortest array is returned, along with the the longest array, with enough ``0x00`` bytes such that both byte arrays are now the same length. + +Effectively this adds most significant ``0x00`` bytes to the shortest little endian byte array, but may be useful for big endian arrays as well. + +.. code-block:: c# + + public static (byte[] left, byte[] right) ByteArrayUtils.AppendShortest(byte[] left, byte[] right) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Append Shortest Example + :name: Append Shortest Example + + public static void AppendShortestExample() + { + // Setup + var lhs = new byte[] { 0xDE, 0xCA, 0xF0 }; + var rhs = new byte[] { 0xCA, 0xFE, 0xC0, 0xFF, 0xEE }; + + // Act + var (lhsResult, rhsResult) = ByteArrayUtils.AppendShortest(lhs, rhs); + + // Conclusion + Console.WriteLine("AppendShortest Example"); + Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); + Console.WriteLine($"lhsResult:\t{lhsResult.ToString("H")}"); + Console.WriteLine($"lhsResult:\t{rhsResult.ToString("H")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + AppendShortest Example + lhs: DE CA F0 + rhs: CA FE C0 FF EE + lhsResult: DE CA F0 00 00 + lhsResult: CA FE C0 FF EE + +Prepend +======= + +Prepending operations are endian agnostic, new byte values will appear after the lowest order index of the input array. + +Prepend Bytes +------------- + +The ``ByteArrayUtils.PrependBytes`` operation simply adds ``count`` bytes to the start of the value provided by the ``source`` array. The optional ``element`` parameter may be provided to use a byte value other than the default ``0x00``. This is essentially the inverse of ``ByteArrayUtils.AppendBytes`` operation. + +.. code-block:: c# + + public static byte[] ByteArrayUtils.PrependBytes(this byte[] source, int count, byte element = 0x00) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Prepend Bytes Example + :name: Prepend Bytes Example + + public static void PrependBytesExample() + { + // Setup + var input = new byte[] { 0xC0, 0xC0, 0xCA, 0xFE }; + const int count = 4; + + // Act + var result = input.PrependBytes(count); + + // Conclusion + Console.WriteLine("PrependBytes Example"); + Console.WriteLine($"input:\t{input.ToString("H")}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + PrependBytes Example + input: C0 C0 CA FE + result: 00 00 00 00 C0 C0 CA FE + +Prepend Shortest +---------------- + +``ByteArrayUtils.PrependShortest`` works much like ``ByteArrayUtils.PrependBytes``, except instead of providing a desired byte count, the two input arrays lengths are compared and the shortest array is returned, along with the the longest array, with enough ``0x00`` bytes such that both byte arrays are now the same length. + +Effectively this adds most significant ``0x00`` bytes to the shortest big endian byte array, but may be useful for little endian arrays as well. + +.. code-block:: c# + + public static (byte[] left, byte[] right) ByteArrayUtils.PrependShortest(byte[] left, byte[] right) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Prepend Shortest Example + :name: Prepend Shortest Example + + public static void PrependShortestExample() + { + // Setup + var lhs = new byte[] { 0xDE, 0xCA, 0xF0 }; + var rhs = new byte[] { 0xCA, 0xFE, 0xC0, 0xFF, 0xEE }; + + // Act + var (lhsResult, rhsResult) = ByteArrayUtils.PrependShortest(lhs, rhs); + + // Conclusion + Console.WriteLine("PrependShortest Example"); + Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); + Console.WriteLine($"lhsResult:\t{lhsResult.ToString("H")}"); + Console.WriteLine($"lhsResult:\t{rhsResult.ToString("H")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + PrependShortest Example + lhs: DE CA F0 + rhs: CA FE C0 FF EE + lhsResult: 00 00 DE CA F0 + lhsResult: CA FE C0 FF EE + +Reversing +========= + +Unsurprisingly, hopefully, ``ByteArrayUtils.ReverseBytes`` returns the reverse of the provided ``bytes`` byte array. + +.. note:: The ``ReverseBytes`` operation is endian agnostic. + +.. code-block:: c# + + public static byte[] ByteArrayUtils.ReverseBytes(this byte[] bytes) + +.. code-block:: c# + :emphasize-lines: 7 + :caption: Reverse Bytes Example + :name: Reverse Bytes Example + + public static void ReverseBytesExample() + { + // Setup + var input = new byte[] { 0xC0, 0x1D, 0xC0, 0xFF, 0xEE }; + + // Act + var result = input.ReverseBytes(); + + // Conclusion + Console.WriteLine("ReverseBytes example"); + Console.WriteLine($"input:\t{input.ToString("H")}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + ReverseBytes example + input: C0 1D C0 FF EE + result: EE FF C0 1D C0 + +Effective Length +**************** + +Effective length provides the ability to count the number of non-most significant bytes within a byte array. Eg. the length of meaningful bytes within the array. + +Big Endian +========== + +``ByteArrayUtils.BigEndianEffectiveLength`` returns an ``int`` representing the byte length of the given ``input`` disregarding the ``0x00`` bytes at the beginning of the array. + +.. code-block:: c# + + public static int ByteArrayUtils.BigEndianEffectiveLength(this byte[] input) + +.. code-block:: c# + :emphasize-lines: 7 + :caption: Big-Endian Effective Length Example + :name: Big-Endian Effective Length Example + + public static void BigEndianEffectiveLengthExample() + { + // Setup + var input = new byte[] { 0x00, 0x00, 0x00, 0xDA, 0xBD, 0xAD }; + + // Act + var result = input.BigEndianEffectiveLength(); + + // Conclusion + Console.WriteLine("BigEndianEffectiveLength Example"); + Console.WriteLine($"input:\t{input.ToString("H")}"); + Console.WriteLine($"result:\t{result}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + BigEndianEffectiveLength Example + input: 00 00 00 DA BD AD + result: 3 + +Little Endian +============= + +``ByteArrayUtils.LittleEndianEffectiveLength`` returns an ``int`` representing the byte length of the given ``input`` disregarding the ``0x00`` bytes at the end of the array. + +.. code-block:: c# + + public static int ByteArrayUtils.LittleEndianEffectiveLength(this byte[] input) + +.. code-block:: c# + :emphasize-lines: 7 + :caption: Little-Endian Effective Length Example + :name: Little-Endian Effective Length Example + + public static void LittleEndianEffectiveLengthExample() + { + // Setup + var input = new byte[] { 0xDA, 0xB0, 0x00, 0x00, 0x00, 0x00 }; + + // Act + var result = input.LittleEndianEffectiveLength(); + + // Conclusion + Console.WriteLine("LittleEndianEffectiveLength Example"); + Console.WriteLine($"input:\t{input.ToString("H")}"); + Console.WriteLine($"result:\t{result}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + LittleEndianEffectiveLength Example + input: DA B0 00 00 00 00 + result: 2 diff --git a/docs/Stringification.rst b/docs/Stringification.rst index da091cd..5952ec7 100644 --- a/docs/Stringification.rst +++ b/docs/Stringification.rst @@ -1,7 +1,7 @@ Stringification -=============== +############### -What can be better than making byte arrays slightly more human readable!? We provide a number of ways to format a byte array that will hopefully meet your needs. Because ``byte[]`` don't implement ``IFormattable`` you have to be explicit about calling ``ByteArrayUtils.ToString`` and cannot rely on string interpolation or ``string.Format`` and the typical format provider. +What can be better than making byte arrays slightly more human readable!? We provide a number of ways to format a byte array that will hopefully meet your needs. Because ``byte[]`` doesn't implement ``IFormattable`` you have to be explicit about calling ``ByteArrayUtils.ToString`` and cannot rely on string interpolation or ``string.Format`` and the typical format provider. .. code-block:: c# @@ -14,31 +14,33 @@ Implemented ``format`` values :header-rows: 1 .. code-block:: c# + :caption: Stringification Example + :name: Stringification Example public static void StringificationExample() { // Setup var input = new byte[] { 0xC0, 0xFF, 0xEE, 0xC0, 0xDE }; - + // Conclusion Console.WriteLine("Stringification Example"); Console.WriteLine($"input:\t{input.ToString("H")}"); - + Console.WriteLine("Hexadecimal Formats"); Console.WriteLine($"H:\t\"{input.ToString("H")}\""); Console.WriteLine($"h:\t\"{input.ToString("h")}\""); Console.WriteLine($"HC:\t\"{input.ToString("HC")}\""); Console.WriteLine($"hc:\t\"{input.ToString("hc")}\""); - + Console.WriteLine("Binary Formats"); Console.WriteLine($"b:\t\"{input.ToString("b")}\""); Console.WriteLine($"bc:\t\"{input.ToString("bc")}\""); - + Console.WriteLine("Integer Formats"); Console.WriteLine($"d:\t\"{input.ToString("d")}\""); Console.WriteLine($"IBE:\t\"{input.ToString("IBE")}\""); Console.WriteLine($"ILE:\t\"{input.ToString("ILE")}\""); - + Console.WriteLine(string.Empty); } @@ -57,4 +59,4 @@ Implemented ``format`` values Integer Formats d: "192 255 238 192 222" IBE: "828927557854" - ILE: "956719628224" \ No newline at end of file + ILE: "956719628224" diff --git a/docs/Unsigned-Arithmetic-Operations.md b/docs/Unsigned-Arithmetic-Operations.md deleted file mode 100644 index a148371..0000000 --- a/docs/Unsigned-Arithmetic-Operations.md +++ /dev/null @@ -1,337 +0,0 @@ -# Unsigned Arithmetic Operations - -For now arithmetic operations within Gulliver have been limited to those involving the treatment of byte arrays as unsigned integer values. Negative numbers and floating point values are out of scope for the needs of this library at the moment. - -Unless otherwise stated the following methods are statically defined in the `ByteArrayUtils` class and do not modify their input. - -## Addition - -Both the `ByteArrayUtils.AddUnsignedBigEndian` and `ByteArrayUtils.AddUnsignedLittleEndian` methods return the addition result of the provided `right` and `left` byte arrays accounting for the appropriate endiness of the input. - -### Big Endian - -```c# -public static byte[] ByteArrayUtils.AddUnsignedBigEndian(byte[] right, byte[] left) -``` - -```c# -public static void AddUnsignedBigEndianExample() -{ - // Setup - var lhs = new byte[] { 0xAD, 0xDE, 0xD0 }; - var rhs = new byte[] { 0xC0, 0xDE }; - // Act - var result = ByteArrayUtils.AddUnsignedBigEndian(lhs, rhs); - // Conclusion - Console.WriteLine("AddUnsignedBigEndian Example"); - Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); - Console.WriteLine(string.Empty); - Console.WriteLine($"lhs:\t{lhs.ToString("IBE")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("IBE")}"); - Console.WriteLine($"result:\t{result.ToString("IBE")}"); - Console.WriteLine(string.Empty); -} -``` - -```none -AddUnsignedBigEndian Example -lhs: AD DE D0 -rhs: C0 DE -result: AE 9F AE - -lhs: 11394768 -rhs: 49374 -result: 11444142 -``` - -### Little Endian - -```c# -public static byte[] ByteArrayUtils.AddUnsignedLittleEndian(byte[] left, byte[] right) -``` - -```c# -public static void AddUnsignedLittleEndianExample() -{ - // Setup - var lhs = new byte[] { 0xAD, 0xDE, 0xD0 }; - var rhs = new byte[] { 0xC0, 0xDE }; - // Act - var result = ByteArrayUtils.AddUnsignedLittleEndian(lhs, rhs); - // Conclusion - Console.WriteLine("AddUnsignedLittleEndian Example"); - Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); - Console.WriteLine(string.Empty); - Console.WriteLine($"lhs:\t{lhs.ToString("ILE")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("ILE")}"); - Console.WriteLine($"result:\t{result.ToString("ILE")}"); - Console.WriteLine(string.Empty); -} -``` - -```none -AddUnsignedLittleEndian Example -lhs: AD DE D0 -rhs: C0 DE -result: 6D BD D1 - -lhs: 13688493 -rhs: 57024 -result: 13745517 -``` - -## Subtraction - -Both the `ByteArrayUtils.SubtractUnsignedBigEndian` and `ByteArrayUtils.SubtractUnsignedLittleEndian` methods return the subtraction result of the provided `right` (minuend) and `left` (subtrahend) byte arrays accounting for the appropriate endiness of the input. - -If the operation would result in a negative value, given we're only dealing with unsigned integer operations, the execution will throw an `InvalidOperationException`. - -### Big Endian - -```c# -public static byte[] ByteArrayUtils.SubtractUnsignedBigEndian(byte[] left, byte[] right) -``` - -```c# -public static void SubtractUnsignedBigEndianExample() -{ - // Setup - var lhs = new byte[] { 0xDE, 0x1E, 0x7E, 0xD0 }; - var rhs = new byte[] { 0xC0, 0xDE }; - // Act - var result = ByteArrayUtils.SubtractUnsignedBigEndian(lhs, rhs); - // Conclusion - Console.WriteLine("SubtractUnsignedBigEndian Example"); - Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); - Console.WriteLine(string.Empty); - Console.WriteLine($"lhs:\t{lhs.ToString("IBE")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("IBE")}"); - Console.WriteLine($"result:\t{result.ToString("IBE")}"); - Console.WriteLine(string.Empty); -} -``` - -```none -SubtractUnsignedBigEndian Example -lhs: DE 1E 7E D0 -rhs: C0 DE -result: DE 1D BD F2 - -lhs: 3726540496 -rhs: 49374 -result: 3726491122 -``` - -### Little Endian - -```c# -public static byte[] ByteArrayUtils.SubtractUnsignedLittleEndian(byte[] left, byte[] right) -``` - -```c# -public static void SubtractUnsignedLittleEndianExample() -{ - // Setup - var lhs = new byte[] { 0xDE, 0x1E, 0x7E, 0xD0 }; - var rhs = new byte[] { 0xC0, 0xDE }; - // Act - var result = ByteArrayUtils.SubtractUnsignedLittleEndian(lhs, rhs); - // Conclusion - Console.WriteLine("SubtractUnsignedLittleEndian Example"); - Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); - Console.WriteLine(string.Empty); - Console.WriteLine($"lhs:\t{lhs.ToString("ILE")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("ILE")}"); - Console.WriteLine($"result:\t{result.ToString("ILE")}"); - Console.WriteLine(string.Empty); -``` - -```none -SubtractUnsignedLittleEndian Example -lhs: DE 1E 7E D0 -rhs: C0 DE -result: 1E 40 7D D0 - -lhs: 3497926366 -rhs: 57024 -result: 3497869342 -``` - -## Safe Summation - -Safe summation allows for the the safe addition or subtraction of a `long` values `delta` from the given `source` byte array input. This is useful for iterating or decrementing byte arrays. - -Both the `ByteArrayUtils.TrySumBigEndian` and `ByteArrayUtils.TrySumLittleEndian` methods return a `bool` stating if the operation was successful, and will out a non-null value of `result` on success. - -### Big Endian - -```c# -public static bool ByteArrayUtils.TrySumBigEndian(byte[] source, long delta, out byte[] result) -``` -```c# -public static void TrySumBigEndianExample() -{ - // Setup - var bytes = new byte[] { 0xAD, 0xDE, 0xD0 }; - const long delta = 42L; - // Act - var success = ByteArrayUtils.TrySumBigEndian(bytes, delta, out var result); - // Conclusion - Console.WriteLine("TrySumBigEndian Example"); - Console.WriteLine($"bytes:\t{bytes.ToString("H")}"); - Console.WriteLine($"delta:\t{delta}"); - Console.WriteLine($"success:\t{success}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); - Console.WriteLine(string.Empty); - Console.WriteLine($"bytes:\t{bytes.ToString("IBE")}"); - Console.WriteLine($"result:\t{result.ToString("IBE")}"); - Console.WriteLine(string.Empty); -} -``` - -```none -TrySumBigEndian Example -bytes: AD DE D0 -delta: 42 -success: True -result: AD DE FA - -bytes: 11394768 -result: 11394810 -``` - -### Little Endian - -```c# -public static bool ByteArrayUtils.TrySumLittleEndian(byte[] source, long delta, out byte[] result) -``` - -```c# -public static void TrySumLittleEndianExample() -{ - // Setup - var bytes = new byte[] { 0xAD, 0xDE, 0xD0 }; - const long delta = 42L; - // Act - var success = ByteArrayUtils.TrySumLittleEndian(bytes, delta, out var result); - // Conclusion - Console.WriteLine("TryLittleEndian Subtraction Example"); - Console.WriteLine($"bytes:\t{bytes.ToString("H")}"); - Console.WriteLine($"delta:\t{delta}"); - Console.WriteLine($"success:\t{success}"); - Console.WriteLine($"result:\t{result.ToString("H")}"); - Console.WriteLine(string.Empty); - Console.WriteLine($"bytes:\t{bytes.ToString("ILE")}"); - Console.WriteLine($"result:\t{result.ToString("ILE")}"); - Console.WriteLine(string.Empty); -} -``` - -```none -TrySumLittleEndian Example -bytes: AD DE D0 -delta: -42 -success: True -result: 83 DE D0 - -bytes: 13688493 -result: 13688451 -``` - -#### Safe Subtraction - -Seemingly conspicuously absent are the `TrySubtractBigEndian` and `TrySubtractLittleEndian` equivalents of the `TrySumBigEndian` and `TrySumLittleEndian` methods. In actuality the various TrySum methods allow for a negative `delta` and therefore are functionally equivalent for safe subtraction. - -## Comparison - -It is often not enough to simply compare the lengths of two arbitrary byte arrays to determine the equality or the largest / smallest unsigned integer value encoded as bytes. - -Both `ByteArrayUtils.CompareUnsignedBigEndian` and `ByteArrayUtils.CompareUnsignedLittleEndian` provide the ability to easily compare byte arrays as their unsigned integer values. - -The result is similar to that of `IComparer.Compare(left, right)`. The signed integer indicates the relative values of `left` and `right`: -- If 0, `left` equals `right` -- If less than 0, `left` is less than 'right' -- If greater than 0, `right` is greater than `left` - -### Big Endian - -```c# -public static int ByteArrayUtils.CompareUnsignedBigEndian(byte[] left, byte[] right) -``` - -```c# -public static void CompareUnsignedBigEndianExample() -{ - // Setup - var lhs = new byte[] { 0xB1, 0x66, 0xE5, 0x70 }; - var rhs = new byte[] { 0x5A, 0x11 }; - // Act - var result = ByteArrayUtils.CompareUnsignedBigEndian(lhs, rhs); - // Conclusion - Console.WriteLine("CompareUnsignedBigEndian Example"); - Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); - Console.WriteLine($"result:\t{result}"); - Console.WriteLine(string.Empty); - Console.WriteLine($"lhs:\t{lhs.ToString("IBE")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("IBE")}"); - Console.WriteLine($"result:\t{result}"); - Console.WriteLine(string.Empty); -} -``` - -```none -lhs: B1 66 E5 70 -rhs: 5A 11 -result: 1 - -lhs: 2976310640 -rhs: 23057 -result: 1 -``` - -### Little Endian - -```c# -public static int ByteArrayUtils.CompareUnsignedLittleEndian(byte[] left, byte[] right) -``` - -```c# -public static void CompareUnsignedLittleEndianExample() -{ - // Setup - var lhs = new byte[] { 0xB1, 0x66, 0xE5, 0x70 }; - var rhs = new byte[] { 0x5A, 0x11 }; - // Act - var result = ByteArrayUtils.CompareUnsignedLittleEndian(lhs, rhs); - // Conclusion - Console.WriteLine("CompareUnsignedLittleEndian Example"); - Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); - Console.WriteLine($"result:\t{result}"); - Console.WriteLine(string.Empty); - Console.WriteLine($"lhs:\t{lhs.ToString("ILE")}"); - Console.WriteLine($"rhs:\t{rhs.ToString("ILE")}"); - Console.WriteLine($"result:\t{result}"); - Console.WriteLine(string.Empty); -} -``` - -```none -CompareUnsignedLittleEndian Example -lhs: B1 66 E5 70 -rhs: 5A 11 -result: 1 - -lhs: 1894082225 -rhs: 4442 -result: 1 -``` diff --git a/docs/Unsigned-Arithmetic-Operations.rst b/docs/Unsigned-Arithmetic-Operations.rst new file mode 100644 index 0000000..290fa84 --- /dev/null +++ b/docs/Unsigned-Arithmetic-Operations.rst @@ -0,0 +1,394 @@ +Unsigned Arithmetic Operations +############################## + +For now arithmetic operations within Gulliver have been limited to those involving the treatment of byte arrays as unsigned integer values. Negative numbers and floating point values are (for the moment) out of scope for the needs of this library. + +.. note:: Unless otherwise stated the following methods are statically defined in the ``ByteArrayUtils`` class and do not modify their input. + +Addition +******** + +Both the ``ByteArrayUtils.AddUnsignedBigEndian`` and ``ByteArrayUtils.AddUnsignedLittleEndian`` methods return the addition result of the provided ``right`` and ``left`` byte arrays accounting for the appropriate endiness of the input. + +Big Endian +========== + +.. code-block:: c# + + public static byte[] ByteArrayUtils.AddUnsignedBigEndian(byte[] right, byte[] left) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Add Unsigned Big-Endian Example + :name: Add Unsigned Big-Endian Example + + public static void AddUnsignedBigEndianExample() + { + // Setup + var lhs = new byte[] { 0xAD, 0xDE, 0xD0 }; + var rhs = new byte[] { 0xC0, 0xDE }; + + // Act + var result = ByteArrayUtils.AddUnsignedBigEndian(lhs, rhs); + + // Conclusion + Console.WriteLine("AddUnsignedBigEndian Example"); + Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + Console.WriteLine(string.Empty); + Console.WriteLine($"lhs:\t{lhs.ToString("IBE")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("IBE")}"); + Console.WriteLine($"result:\t{result.ToString("IBE")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + AddUnsignedBigEndian Example + lhs: AD DE D0 + rhs: C0 DE + result: AE 9F AE + + lhs: 11394768 + rhs: 49374 + result: 11444142 + +Little Endian +============= + +.. code-block:: c# + + public static byte[] ByteArrayUtils.AddUnsignedLittleEndian(byte[] left, byte[] right) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Add Unsigned-Little Endian Example + :name: Add Unsigned-Little Endian Example + + public static void AddUnsignedLittleEndianExample() + { + // Setup + var lhs = new byte[] { 0xAD, 0xDE, 0xD0 }; + var rhs = new byte[] { 0xC0, 0xDE }; + + // Act + var result = ByteArrayUtils.AddUnsignedLittleEndian(lhs, rhs); + + // Conclusion + Console.WriteLine("AddUnsignedLittleEndian Example"); + Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + Console.WriteLine(string.Empty); + Console.WriteLine($"lhs:\t{lhs.ToString("ILE")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("ILE")}"); + Console.WriteLine($"result:\t{result.ToString("ILE")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + AddUnsignedLittleEndian Example + lhs: AD DE D0 + rhs: C0 DE + result: 6D BD D1 + + lhs: 13688493 + rhs: 57024 + result: 13745517 + +Subtraction +*********** + +Both the ``ByteArrayUtils.SubtractUnsignedBigEndian`` and ``ByteArrayUtils.SubtractUnsignedLittleEndian`` methods return the subtraction result of the provided ``right`` (minuend) and ``left`` (subtrahend) byte arrays accounting for the appropriate endiness of the input. + +.. warning:: If the operation would result in a negative value, given we're only dealing with unsigned integer operations, the execution will throw an ``InvalidOperationException``. + +Big Endian +========== + +.. code-block:: c# + + public static byte[] ByteArrayUtils.SubtractUnsignedBigEndian(byte[] left, byte[] right) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Subtract Unsigned Big-Endian Example + :name: Subtract Unsigned Big-Endian Example + + public static void SubtractUnsignedBigEndianExample() + { + // Setup + var lhs = new byte[] { 0xDE, 0x1E, 0x7E, 0xD0 }; + var rhs = new byte[] { 0xC0, 0xDE }; + + // Act + var result = ByteArrayUtils.SubtractUnsignedBigEndian(lhs, rhs); + + // Conclusion + Console.WriteLine("SubtractUnsignedBigEndian Example"); + Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + Console.WriteLine(string.Empty); + Console.WriteLine($"lhs:\t{lhs.ToString("IBE")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("IBE")}"); + Console.WriteLine($"result:\t{result.ToString("IBE")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + SubtractUnsignedBigEndian Example + lhs: DE 1E 7E D0 + rhs: C0 DE + result: DE 1D BD F2 + + lhs: 3726540496 + rhs: 49374 + result: 3726491122 + +Little Endian +============= + +.. code-block:: c# + + public static byte[] ByteArrayUtils.SubtractUnsignedLittleEndian(byte[] left, byte[] right) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Subtract Unsigned Little-Endian Example + :name: Subtract Unsigned Little-Endian Example + + public static void SubtractUnsignedLittleEndianExample() + { + // Setup + var lhs = new byte[] { 0xDE, 0x1E, 0x7E, 0xD0 }; + var rhs = new byte[] { 0xC0, 0xDE }; + + // Act + var result = ByteArrayUtils.SubtractUnsignedLittleEndian(lhs, rhs); + + // Conclusion + Console.WriteLine("SubtractUnsignedLittleEndian Example"); + Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + Console.WriteLine(string.Empty); + Console.WriteLine($"lhs:\t{lhs.ToString("ILE")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("ILE")}"); + Console.WriteLine($"result:\t{result.ToString("ILE")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + SubtractUnsignedLittleEndian Example + lhs: DE 1E 7E D0 + rhs: C0 DE + result: 1E 40 7D D0 + + lhs: 3497926366 + rhs: 57024 + result: 3497869342 + +Safe Summation +************** + +Safe summation allows for the the safe addition or subtraction of a ``long`` values ``delta`` from the given ``source`` byte array input. This is useful for iterating or decrementing byte arrays. + +Both the ``ByteArrayUtils.TrySumBigEndian`` and ``ByteArrayUtils.TrySumLittleEndian`` methods return a ``bool`` stating if the operation was successful, and will out a non-null value of ``result`` on success. + +Big Endian +========== + +.. code-block:: c# + + public static bool ByteArrayUtils.TrySumBigEndian(byte[] source, long delta, out byte[] result) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Try Sum Big-Endian Example + :name: Try Sum Big-Endian Example + + public static void TrySumBigEndianExample() + { + // Setup + var bytes = new byte[] { 0xAD, 0xDE, 0xD0 }; + const long delta = 42L; + + // Act + var success = ByteArrayUtils.TrySumBigEndian(bytes, delta, out var result); + + // Conclusion + Console.WriteLine("TrySumBigEndian Example"); + Console.WriteLine($"bytes:\t{bytes.ToString("H")}"); + Console.WriteLine($"delta:\t{delta}"); + Console.WriteLine($"success:\t{success}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + Console.WriteLine(string.Empty); + Console.WriteLine($"bytes:\t{bytes.ToString("IBE")}"); + Console.WriteLine($"result:\t{result.ToString("IBE")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + TrySumBigEndian Example + bytes: AD DE D0 + delta: 42 + success: True + result: AD DE FA + + bytes: 11394768 + result: 11394810 + +Little Endian +============= + +.. code-block:: c# + + public static bool ByteArrayUtils.TrySumLittleEndian(byte[] source, long delta, out byte[] result) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Try Sum Little-Endian Example + :name: Try Sum Little-Endian Example + + public static void TrySumLittleEndianExample() + { + // Setup + var bytes = new byte[] { 0xAD, 0xDE, 0xD0 }; + const long delta = 42L; + + // Act + var success = ByteArrayUtils.TrySumLittleEndian(bytes, delta, out var result); + + // Conclusion + Console.WriteLine("TryLittleEndian Subtraction Example"); + Console.WriteLine($"bytes:\t{bytes.ToString("H")}"); + Console.WriteLine($"delta:\t{delta}"); + Console.WriteLine($"success:\t{success}"); + Console.WriteLine($"result:\t{result.ToString("H")}"); + Console.WriteLine(string.Empty); + Console.WriteLine($"bytes:\t{bytes.ToString("ILE")}"); + Console.WriteLine($"result:\t{result.ToString("ILE")}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + TrySumLittleEndian Example + bytes: AD DE D0 + delta: -42 + success: True + result: 83 DE D0 + + bytes: 13688493 + result: 13688451 + +Safe Subtraction +---------------- + +.. note:: Seemingly conspicuously absent are the ``TrySubtractBigEndian`` and ``TrySubtractLittleEndian`` equivalents of the ``TrySumBigEndian`` and ``TrySumLittleEndian`` methods. In actuality the various TrySum methods allow for a negative ``delta`` and therefore are functionally equivalent for safe subtraction. + +Comparison +********** + +It is often not enough to simply compare the lengths of two arbitrary byte arrays to determine the equality or the largest / smallest unsigned integer value encoded as bytes. + +Both ``ByteArrayUtils.CompareUnsignedBigEndian`` and ``ByteArrayUtils.CompareUnsignedLittleEndian`` provide the ability to easily compare byte arrays as their unsigned integer values. + +The result is similar to that of ``IComparer.Compare(left, right)``. The signed integer indicates the relative values of ``left`` and ``right``: + +- If 0, ``left`` equals ``right`` +- If less than 0, ``left`` is less than 'right' +- If greater than 0, ``right`` is greater than ``left`` + +Big Endian +========== + +.. code-block:: c# + + public static int ByteArrayUtils.CompareUnsignedBigEndian(byte[] left, byte[] right) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Compare Unsigned Big-Endian Example + :name: Compare Unsigned Big-Endian Example + + public static void CompareUnsignedBigEndianExample() + { + // Setup + var lhs = new byte[] { 0xB1, 0x66, 0xE5, 0x70 }; + var rhs = new byte[] { 0x5A, 0x11 }; + + // Act + var result = ByteArrayUtils.CompareUnsignedBigEndian(lhs, rhs); + + // Conclusion + Console.WriteLine("CompareUnsignedBigEndian Example"); + Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); + Console.WriteLine($"result:\t{result}"); + Console.WriteLine(string.Empty); + Console.WriteLine($"lhs:\t{lhs.ToString("IBE")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("IBE")}"); + Console.WriteLine($"result:\t{result}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + lhs: B1 66 E5 70 + rhs: 5A 11 + result: 1 + + lhs: 2976310640 + rhs: 23057 + result: 1 + +Little Endian +============= + +.. code-block:: c# + + public static int ByteArrayUtils.CompareUnsignedLittleEndian(byte[] left, byte[] right) + +.. code-block:: c# + :emphasize-lines: 8 + :caption: Compare Unsigned Little-Endian Example + :name: Compare Unsigned Little-Endian Example + + public static void CompareUnsignedLittleEndianExample() + { + // Setup + var lhs = new byte[] { 0xB1, 0x66, 0xE5, 0x70 }; + var rhs = new byte[] { 0x5A, 0x11 }; + + // Act + var result = ByteArrayUtils.CompareUnsignedLittleEndian(lhs, rhs); + + // Conclusion + Console.WriteLine("CompareUnsignedLittleEndian Example"); + Console.WriteLine($"lhs:\t{lhs.ToString("H")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("H")}"); + Console.WriteLine($"result:\t{result}"); + Console.WriteLine(string.Empty); + Console.WriteLine($"lhs:\t{lhs.ToString("ILE")}"); + Console.WriteLine($"rhs:\t{rhs.ToString("ILE")}"); + Console.WriteLine($"result:\t{result}"); + Console.WriteLine(string.Empty); + } + +.. code-block:: none + + CompareUnsignedLittleEndian Example + lhs: B1 66 E5 70 + rhs: 5A 11 + result: 1 + + lhs: 1894082225 + rhs: 4442 + result: 1 diff --git a/docs/What-is-Endianness.md b/docs/What-is-Endianness.md deleted file mode 100644 index e57c150..0000000 --- a/docs/What-is-Endianness.md +++ /dev/null @@ -1,31 +0,0 @@ -# What is Endianness - -Endianness, at least as far as computing is concerned, is the ordering of bytes within a binary representation of data. The most common representations of endianness are [Big-Endian](#Big-Endian) and [Little-Endian](#Little-Endian). There exist other forms, such as Middle-Endian, but those are beyond the scope of this document. - -!["Simply Explained." Comic by Oliver Widder Released under Attribution 3.0 Unported (CC BY 3.0)](/img/endianpig.png) - -## Entomology - -The Computer Science terms Big-Endian and Little-Endian were introduced by [Danny Cohen](https://en.wikipedia.org/wiki/Danny_Cohen_(computer_scientist)) in 1980. The key term *endian* has its roots in the novel [Gulliver’s Travels](https://en.wikipedia.org/wiki/Gulliver%27s_Travels) by [Jonathan Swift](https://en.wikipedia.org/wiki/Jonathan_Swift) where within a war occurs between two factions who are fighting over which end of a boiled egg should be opened for eating. The big end or the little end. Unsurprisingly, the same said book was the inspiration for the naming of the [Gulliver](https://github.com/sandialabs/gulliver) library. - -## Big-Endian - -Big-Endian, often referred to as *Network Byte Order*, ordering is left-to-right. Given the representation of an unsigned number in bytes the further to the left that a byte exists the more significant it is. - -For example, the decimal value of the unsigned integer `6060842` may be represented as `0x5C7B2A` in hexadecimal. This hexadecimal value is composed of the three bytes `0x5C`, `0x7B`, and `0x28`. As such the value `6060842` may be represented in Big-Endian as a byte stream of `[0x5C, 0x7B, 0x2A]`. - -Big-Endian integer representation likely comes as second nature to developers familiar with right-to-left [Arabic numerals]( https://en.wikipedia.org/wiki/Arabic_numerals) representation. - -## Little-Endian - -Little-Endian ordering is right-to-left. Given the representation of an unsigned number in bytes the further to the right a byte exists the more significant it is. - -For example, the decimal value of the unsigned integer `8675309` may be represented as `0x85BF7D` in hexadecimal. This hexadecimal value is composed of the three bytes `0x85`, `0xBF`, and `0x7D`. As such the value `8675309` may be represented in Little-Endian as a byte stream of `[0x7D, 0xBFm 0x85]`. - -To developers most affiliated with right-to-left natural languages Little-Endian may seem backwards. - -## Citations - -Wikipedia contributors. (2019, October 10). Endianness. In Wikipedia, The Free Encyclopedia. Retrieved 18:31, October 13, 2019, from [https://en.wikipedia.org/w/index.php?title=Endianness&oldid=920566520](https://en.wikipedia.org/w/index.php?title=Endianness&oldid=920566520). - -Widder, O. (2011, September 7). Simply Explained. Retrieved October 13, 2019, from [http://geek-and-poke.com/geekandpoke/2011/9/7/simply-explained.html](http://geek-and-poke.com/geekandpoke/2011/9/7/simply-explained.html). diff --git a/docs/What-is-Endianness.rst b/docs/What-is-Endianness.rst new file mode 100644 index 0000000..9be9a8d --- /dev/null +++ b/docs/What-is-Endianness.rst @@ -0,0 +1,52 @@ +What is Endianness +################## + +Endianness [#Endianness]_, at least as far as computing is concerned, is the ordering of bytes within a binary representation of data. The most common representations of endianness are :ref:`big-endian` and :ref:`little-endian`. There exist other forms, such as Middle-Endian, but those are beyond the scope of this document. + +.. figure:: /img/endianpig.png + :align: center + :alt: alternate text + :target: http://geek-and-poke.com/geekandpoke/2011/9/7/simply-explained.html + + `"Simply Explained" `_ + + Comic by `Oliver Widder `_ Released under `Attribution 3.0 Unported (CC BY 3.0) `_. + +Entomology +********** + +The Computer Science terms Big-Endian and Little-Endian were introduced by Danny Cohen [#CohenDanny]_ in 1980. The key term *endian* has its roots in the novel Gulliver’s Travels [#GulliversTravels]_ by Jonathan Swift [#SwiftJonathan]_ where within a war occurs between two factions who are fighting over which end of a boiled egg should be opened for eating. The big end or the little end. Unsurprisingly, the same said book was the inspiration for the naming of the `Gulliver `_ library. + +.. _big-endian: + +Big-Endian +********** + +Big-Endian, often referred to as *Network Byte Order*, ordering is left-to-right. Given the representation of an unsigned number in bytes the further to the left that a byte exists the more significant it is. + +For example, the decimal value of the unsigned integer :math:`8675309_{10}` may be represented as :math:`0x845FED_{16}` in hexadecimal. This hexadecimal value is composed of the three bytes :math:`0x84_{16}`, :math:`0x5F_{16}`, and :math:`0xED_{16}`. As such the value :math:`8675309_{10}` may be represented in Big-Endian as a byte stream of :math:`[0x5C_{16}, 0x7B_{16}, 0x2A_{16}]`. + +Big-Endian integer representation likely comes as second nature to developers familiar with right-to-left Arabic numerals [#ArabicNumerals]_ representation. + +.. _little-endian: + +Little-Endian +************* + +Little-Endian ordering is right-to-left. Given the representation of an unsigned number in bytes the further to the right a byte exists the more significant it is. + +For example, the decimal value of the unsigned integer :math:`8675309_{10}` may be represented as :math:`0x845FED_{16}` in hexadecimal. This hexadecimal value is composed of the three bytes :math:`0x84_{16}`, :math:`0x5F_{16}`, and :math:`0xED_{16}`. But because little-endian byte order is left to right :math:`8675309_{10}` may be represented in Little-Endian as a byte stream of :math:`[0xED_{16}, 0x5F_{16}, 0x84_{16}]`. + +To developers most affiliated with right-to-left natural languages Little-Endian may seem backwards. + +.. rubric:: Footnotes + +.. [#Endianness] Wikipedia contributors. (2019, October 10). Endianness. In Wikipedia, The Free Encyclopedia. Retrieved 18:31, October 13, 2019, from `https://en.wikipedia.org/w/index.php?title=Endianness&oldid=920566520 `_. + +.. [#CohenDanny] `Cohen, Danny `_ the computer scientist that termed the phrase "endian" referring to byte order. + +.. [#GulliversTravels] `Gulliver's Travels `_ a book. + +.. [#SwiftJonathan] `Swift, Jonathan `_, author of Gulliver's Travels. + +.. [#ArabicNumerals] `Arabic numerals `_ are the typical digital number format used in the English language. diff --git a/docs/_static/custom.css b/docs/_static/custom.css new file mode 100644 index 0000000..3d682e7 --- /dev/null +++ b/docs/_static/custom.css @@ -0,0 +1,8 @@ +/* +"fix"screen width. Based on https: //github.com/readthedocs/sphinx_rtd_theme/issues/295#issuecomment-455226058 +*/ +@media only screen and (min-width: 769px) { + .wy-nav-content { + max-width: 100%; + } +} \ No newline at end of file diff --git a/docs/conf.py b/docs/conf.py index 4884397..e61f4ab 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -19,7 +19,7 @@ project = u'Gulliver' copyright = u'Copyright 2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. Government retains certain rights in this software.' -author = u'Robert H. Engelhardt, Andrew Steele' +author = u'Sandia National Laboratories' # -- General configuration --------------------------------------------------- @@ -27,7 +27,7 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = ['recommonmark'] +extensions = [] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -58,3 +58,18 @@ # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] + +# If true, Sphinx will warn about all references where the target cannot be +# found. Default is False. You can activate this mode temporarily using the +# - n command-line switch. +nitpicky = True + +# A list of(type, target) tuples(by default empty) that should be ignored +# when generating warnings in “nitpicky mode”. Note that type should include +# the domain name if present. Example entries would be('py:func', 'int') or +# ('envvar', 'LD_LIBRARY_PATH'). +nitpick_ignore = [] + + +def setup(app): + app.add_css_file("custom.css") diff --git a/docs/index.rst b/docs/index.rst index 893fde8..760262a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,5 +1,6 @@ Gulliver -======== +######## + .. image:: https://img.shields.io/nuget/vpre/gulliver?logo=nuget :alt: Nuget (with prereleases) :target: https://www.nuget.org/packages/Gulliver/ @@ -41,6 +42,7 @@ The API surfaced by Gulliver is not outwardly complex, and the intention is to k .. toctree:: :maxdepth: 2 :caption: Development - + Community + Building Acknowledgements diff --git a/docs/notes.tmp.txt b/docs/notes.tmp.txt new file mode 100644 index 0000000..ca2adfe --- /dev/null +++ b/docs/notes.tmp.txt @@ -0,0 +1 @@ +Regex search "(?= 0.6.0 sphinx >= 2.2.0 sphinx_rtd_theme >=0.4.3