{"id":20297555,"url":"https://github.com/barncastle/bitskit","last_synced_at":"2025-04-11T12:14:57.784Z","repository":{"id":203359019,"uuid":"635301006","full_name":"barncastle/BitsKit","owner":"barncastle","description":"A C# library for efficient bit-level reading and writing also adding bit field support","archived":false,"fork":false,"pushed_at":"2024-11-19T09:27:20.000Z","size":278,"stargazers_count":54,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-06T06:16:50.816Z","etag":null,"topics":["bitfields","bits","csharp","dotnet"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/barncastle.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-05-02T12:02:54.000Z","updated_at":"2025-04-04T10:21:26.000Z","dependencies_parsed_at":null,"dependency_job_id":"7625c2c3-6731-4692-9491-48e48e3f9292","html_url":"https://github.com/barncastle/BitsKit","commit_stats":null,"previous_names":["barncastle/bitskit"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/barncastle%2FBitsKit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/barncastle%2FBitsKit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/barncastle%2FBitsKit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/barncastle%2FBitsKit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/barncastle","download_url":"https://codeload.github.com/barncastle/BitsKit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248399181,"owners_count":21097296,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bitfields","bits","csharp","dotnet"],"created_at":"2024-11-14T15:49:33.770Z","updated_at":"2025-04-11T12:14:57.774Z","avatar_url":"https://github.com/barncastle.png","language":"C#","readme":"# BitsKit\n[![NuGet Version](https://img.shields.io/nuget/v/BitsKit)](https://www.nuget.org/packages/BitsKit)\n\nBitsKit is a lightweight C# library that provides efficient bit-level reading, writing and manipulation. As well as adding bit-field support to C#, not dissimilar to [C/C++ languages](https://en.cppreference.com/w/cpp/language/bit_field).\n\nAll features support integral and memory types, as well as targeting both, Little Endian (LE) Least Significant Bit (LSB) and Big Endian (BE) Most Significant Bit (MSB).\n\n## Features\n- [BitPrimitives](#bitprimitives)\n- [Bit Fields](#bit-fields)\n- [IO Classes](#io-classes)\n- [Utility Methods](#utility-methods)\n\n## Usage\n\n### BitPrimitives\n`BitsKit.Primitives.BitPrimitives` is the workhorse of the library containing all of the read and write logic. This class is the bit equivalent of `System.Buffers.Binary.BinaryPrimitives` and contains a MSB and LSB read and write method for each of the below integral types:\n```\nsbyte, byte, short, ushort, int, uint, long, ulong, nint, nuint\n```\nEach type has two overloads allowing the source/destination to be either a `Span\u003cbyte\u003e` or `T` e.g.,\n\n```c#\n// reads a range of bits from a uint as MSB\nstatic uint ReadUInt32MSB(uint source, int bitOffset, int bitCount);\n\n// reads a range of bits from a span as MSB\nstatic uint ReadUInt32MSB(ReadOnlySpan\u003cbyte\u003e source, int bitOffset, int bitCount);\n\n// writes a range of bits to a uint as MSB\nstatic void WriteUInt32MSB(ref uint destination, int bitOffset, uint value, int bitCount);\n\n// writes a range of bits to a span as MSB\nstatic void WriteUInt32MSB(Span\u003cbyte\u003e destination, int bitOffset, uint value, int bitCount);\n```\nThis class also provides a `ReverseBitOrder` method for each integral type which inverts the bit order of each byte within the value, but not the order (endianness) of the bytes themselves e.g.\n```c#\n// reverses the bit order of each byte\nstatic uint ReverseBitOrder(uint value);\n\n//7......0 7......0      0......7 0......7\n0b11001000_00111011 =\u003e 0b00010011_11011100\n```\n\n### Bit Fields\nBitsKit provides the ability to generate bit-fields within types and aims to be as feature complete as the C and C++ implementations. This is achieved through the use of attributes applied to backing fields, which describe the structure and layout. These are converted into properties via a source generator. \n\nBit fields can be added to class, struct and record types, supporting all of their variants too e.g., `readonly struct`, `record struct` etc. Objects containing bit-fields are declared by the `[BitObjectAttribute(BitOrder)]` attribute which also declares the default bit order for the type. Types must be partial and not nested.\n\nDue to the nature of source generators, the user must generate the backing fields. Whilst this is more verbose than in C, it does provide much more granularity and control opening up some interesting dynamics. Backing fields must be a `field` and either; one of integral types above or one of the memory types below.\n\n`byte[], fixed byte[], byte*, Span\u003cbyte\u003e, ReadOnlySpan\u003cbyte\u003e, Memory\u003cbyte\u003e, ReadOnlyMemory\u003cbyte\u003e`\n\nBit fields are declared using the `[BitFieldAttribute]` attribute which describes their name, size, bit order and properties. Each attribute defines a new bit-field sequential from the previous. A backing field can have as many bit-fields as desired, limited only by field boundaries. \n\n**Notes:** \n- If the backing field is an integral type, the bit-field will be of the same type. Type Casting is supported via `FieldType`.\n- If the backing field is a memory type, the `FieldType` is required as it cannot be inferred.\n- If the backing field is `readonly` or represents a readonly type, the bit-field will also be readonly.\n- Inline Arrays with an integral member type are supported.\n\n```c#\n// Constructor for integral backed bit-fields\n[BitFieldAttribute(string name, byte size)]\n// Constructor for memory backed bit-fields\n[BitFieldAttribute(string name, byte size, BitFieldType fieldType)]\n\nFields:\n// The name of the bit-field\npublic string? Name { get; }\n// The number of bits the field occupies \npublic byte Size { get; }\n// The integral type of the field if backed by a memory type\npublic BitFieldType? FieldType { get; }\n// Uses the opposite bit order than declared on the type\npublic bool ReverseBitOrder { get; set; }\n// Modifiers that change the source generation\npublic BitFieldModifiers Modifiers { get; set; }\n```\n#### Padding Fields\nLike C, an unnamed bit-field generates a set of inaccessible \"padding\" bits. These are primarily used for alignment or to map reserved/unused bits. There is a constructor overload dedicated to these fields.\n```c#\n// Constructor for integral padding bit-fields\n[BitFieldAttribute(byte size)]\n// Constructor for boolean padding bit-fields\n[BooleanFieldAttribute]\n// Constructor for enum padding bit-fields\n[EnumFieldAttribute(byte size)]\n```\n\n#### Boolean Bit Fields\nBoolean bit-fields are supported by the `[BooleanFieldAttribute]` helper attribute. Boolean fields consume a single bit and return if it is set or not. This attribute can be applied to any valid backing field and inherits from the `[BitFieldAttribute]` attribute. Boolean fields can be mixed with integer and enum fields without incurring a new unit.\n```c#\n// Constructor for boolean bit-fields\n[BooleanFieldAttribute(string name)]\n```\n\n#### Enum Bit Fields\nEnum bit-fields are supported by the `[EnumFieldAttribute]` helper attribute. This attribute can be applied to any valid backing field and inherits from the `[BitFieldAttribute]` attribute. The enum type must be passed as a type argument i.e., `typeof(MyEnum)`. Enum fields can be mixed with integer and boolean fields without incurring a new unit.\n```c#\n// Constructor for enum bit-fields\n[EnumFieldAttribute(string name, byte size, Type enumType)]\n```\n\n#### Modifiers\nThe `BitFieldModifiers` enum allows alterations to the way that the source generator produces the bit-fields. By default all bit-fields are generated as a *public read/write* or *public readonly* properties relative to their backing field's accessibility. The `Modifiers` field allows control over this and provides the ability to change a bit-field's accessibility and if it is `readonly`, `init only` (.NET 6.0) and/or `required` (.NET 7.0).\n\n**Note:** Currently both the getter and setter share the same accessibility therefore you cannot have public bit-fields with private setters.\n\n#### Examples\nPutting this into action with the following C struct:\n```c++\nstruct S\n{\n    // occupies 2 bytes:\n    unsigned char b1 : 3;  // 1st 3 bits (in 1st byte) are b1\n    unsigned char    : 2;  // next 2 bits (in 1st byte) are unused \"padding\"\n    unsigned char b2 : 1;  // next 1 bit (in 1st byte) is b2\n    unsigned char b3 : 6;  // 6 bits for b3 - doesn't fit into the 1st byte =\u003e starts a 2nd\n    unsigned char b4 : 2;  // 2 bits for b4 - next (and final) bits in the 2nd byte\n};\n```\nConverted to it's BitsKit representation:\n```c#\n[BitObject(BitOrder.LeastSignificantBit)]\npublic partial struct S \n{\n    [BitField(\"b1\", 3)]     // 1st 3 bits (in 1st byte) are b1\n    [BitField(2)]           // next 2 bits (in 1st byte) are unused \"padding\"\n    [BitField(\"b2\", 1)]     // next 1 bit (in 1st byte) is b2\n    private byte _backingField1;\n    \n    [BitField(\"b3\", 6)]     // 6 bits for b3 - doesn't fit into the 1st byte =\u003e use a 2nd\n    [BitField(\"b4\", 2)]     // 2 bits for b4 - next (and final) bits in the 2nd byte\n    private byte _backingField2;\n}\n```\nWhich produces a new generated partial class containing:\n```c#\npublic partial struct S \n{\n    public byte b1 { get =\u003e ..; set =\u003e ..; }; // _backingField1 0..2\n    public byte b2 { get =\u003e ..; set =\u003e ..; }; // _backingField1 5\n    public byte b3 { get =\u003e ..; set =\u003e ..; }; // _backingField2 0..5\n    public byte b4 { get =\u003e ..; set =\u003e ..; }; // _backingField2 6..7\n}\n```\n\n#### Straddling Unit Boundaries\nSome C compilers support straddling storage-unit boundaries. An example of this would be the \"b3\" field in the above example occupying the last 2 bits in the first byte and the first 4 bits in the second byte. BitsKit enforces unit boundaries for integral types however memory types do allow this.\n```c#\n[BitObject(BitOrder.LeastSignificantBit)]\npublic unsafe partial struct S \n{\n    [BitField(\"b1\", 3)] // 1st 3 bits (in 1st byte) are b1\n    [BitField(2)]       // next 2 bits (in 1st byte) are unused \"padding\"\n    [BitField(\"b2\", 1)] // next 1 bit (in 1st byte) is b2\n    [BitField(\"b3\", 6)] // next (and final) 2 bits in 1st byte and 1st 4 bits in 2nd byte\n    [BitField(\"b4\", 4)] // 4 bits for b4 - next (and final) bits in the 2nd byte\n    private fixed byte _backingField[2];\n}\n```\n#### Errors\nBelow are the diagnostics BitsKit produces. Additionally, an `ArgumentOutOfRangeException` exception is thrown if the bit offset or count exceed the bounds of the backing field/source. \nRule ID | Severity | Notes\n--------|----------|--------------------\nBITSKIT001 | Error | BitsKit object must be partial\nBITSKIT002 | Error | BitsKit object must not be a nested type\nBITSKIT003 | Error | Cannot infer FieldType\nBITSKIT004 | Warning | Conflicting accessibility modifiers\nBITSKIT005 | Warning | Conflicting setter modifiers\nBITSKIT006 | Error | Enum type argument expected\n\n### IO Classes\nThere are a number of IO types available under the `BitsKit.IO` namespace built to sequentially read/write regions of bit data. Each of these classes expose all the `BitPrimitives` methods whilst supporting seeking and writing in-place.\n\n`BitReader/BitWriter` - Classes for reading/writing to a byte array.\n`MemoryBitReader/MemoryBitWriter` - Ref structs for reading/writing to a `Span\u003cbyte\u003e`.\n`BitStreamReader/BitStreamWriter` - Classes for reading/writing to a stream.\n\n**Notes:** \n- The array and span backed types support up to `int.MaxValue` bits as they use a signed integer for positioning to boost performance. This limits the source to being less than 0x10000000 bytes.\n- The `BitStreamWriter` class does support writing in-place however, the destination stream must be both readable and seekable to allowing buffering of the stream's existing data.\n\n### Utility Methods\nAdditional utilities for common bit processing tasks are provided under the `BitsKit.Utilities` namespace. Many of these functions have been taken from the awesome [Bit Twiddling Hacks](https://graphics.stanford.edu/~seander/bithacks.html) page created by Sean Eron Anderson.\n\n**BitUtilities.InterleaveBits ([See](https://graphics.stanford.edu/~seander/bithacks.html#InterleaveBMN))** Interleaves the bits of two integral numbers. This is also known as \"Morton numbers\" or \"Morton codes\" e.g.,\n```c#\nstatic uint InterleaveBits(ushort a, ushort b)\n\n//  a          b          baba_baba_baba\n0b00_1111, 0b10_0010 =\u003e 0b1000_0101_1101\n```\n**BitUtilities.MergeBits ([See](https://graphics.stanford.edu/~seander/bithacks.html#MaskedMerge))** Merges the bits of two integral numbers according to a mask. If the mask bit is a `0`, the bit is taken from `a` otherwise it is taken from `b` e.g.,\n```c#\nstatic uint MergeBits(uint a, uint b, uint mask)\n\n//   a           b          mask        bbbbaaaa\n0b10101110, 0b11001010, 0b11110000 =\u003e 0b11001110\n```\n**BitUtilities.NegateBits** Negates a range of bits within an integral number e.g.,\n```c#\nstatic uint NegateBits(uint value, int bitOffset, int bitCount)\n\n//  value   offset count      xxxx\n0b1100_1101   4     4    =\u003e 0b0011_1101\n```\n**BitUtilities.ReverseBits ([See](https://graphics.stanford.edu/~seander/bithacks.html#ReverseParallel))** Reverses both the bit and byte order (endian) of an integral number e.g.,\n```c#\nstatic uint ReverseBits(uint value)\n\n//   a        b             b        a\n//7......0 7......0      0......7 0......7\n0b11001000_00111011 =\u003e 0b11011100_00010011\n```\n**BitUtilities.SwapBits ([See](https://graphics.stanford.edu/~seander/bithacks.html#SwappingBitsXOR))** Swaps the positions of two ranges of bits within an integral number e.g.,\n```c#\nstatic uint SwapBits(uint value, int offsetA, int offsetB, int bitCount)\n\n//  value   offsetA offsetB bitCount       bbaa\n0b1100_1101    4       6       2      =\u003e 0b0011_1101\n```\n\n**ZigZag** An integer encoding used to convert signed integers to unsigned integers whilst maintaining a relative sized bit count. This is achieved by making the least significant bit the sign bit thus making the bit count proportional to the magnitude. This encoding is particularly useful for deltas with a small range e.g.,\n```c#\nstatic uint Encode(int value)\nstatic int Decode(uint value)\n\n//   -2         -1         0         1         2\n// Two's complement\n0b11111110 0b11111111 0b00000000 0b00000001 0b00000010\n// ZigZag Encoded\n0b00000011 0b00000001 0b00000000 0b00000010 0b00000100\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbarncastle%2Fbitskit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbarncastle%2Fbitskit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbarncastle%2Fbitskit/lists"}