{"id":18284144,"url":"https://github.com/steinwurf/bitter","last_synced_at":"2025-04-05T07:31:17.006Z","repository":{"id":45429984,"uuid":"63076203","full_name":"steinwurf/bitter","owner":"steinwurf","description":"Is a lightweight API for reading an arbitrary amount of bits from a single input ","archived":false,"fork":false,"pushed_at":"2023-08-23T07:42:11.000Z","size":961,"stargazers_count":15,"open_issues_count":0,"forks_count":3,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-03-21T00:26:00.750Z","etag":null,"topics":["bit","bit-manipulation","bitmanagement"],"latest_commit_sha":null,"homepage":"https://steinwurf-bitter.netlify.app/latest/","language":"C++","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/steinwurf.png","metadata":{"files":{"readme":"README.rst","changelog":"NEWS.rst","contributing":null,"funding":null,"license":"LICENSE.rst","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":"2016-07-11T14:44:55.000Z","updated_at":"2023-07-08T08:55:01.000Z","dependencies_parsed_at":"2024-11-05T13:12:48.097Z","dependency_job_id":"834b278f-52e8-4345-b019-ec1073f5498b","html_url":"https://github.com/steinwurf/bitter","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steinwurf%2Fbitter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steinwurf%2Fbitter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steinwurf%2Fbitter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/steinwurf%2Fbitter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/steinwurf","download_url":"https://codeload.github.com/steinwurf/bitter/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247305413,"owners_count":20917197,"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":["bit","bit-manipulation","bitmanagement"],"created_at":"2024-11-05T13:12:20.315Z","updated_at":"2025-04-05T07:31:11.998Z","avatar_url":"https://github.com/steinwurf.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"Bitter\n======\n\n|Linux make-specs| |Windows make-specs| |MacOS make-specs| |Linux CMake| |Windows CMake| |MacOS CMake| |Valgrind| |No Assertions| |Clang Format| |Cppcheck|\n\n.. |Linux make-specs| image:: https://github.com/steinwurf/bitter/actions/workflows/linux_mkspecs.yml/badge.svg\n   :target: https://github.com/steinwurf/bitter/actions/workflows/linux_mkspecs.yml\n   \n.. |Windows make-specs| image:: https://github.com/steinwurf/bitter/actions/workflows/windows_mkspecs.yml/badge.svg\n   :target: https://github.com/steinwurf/bitter/actions/workflows/windows_mkspecs.yml\n\n.. |MacOS make-specs| image:: https://github.com/steinwurf/bitter/actions/workflows/macos_mkspecs.yml/badge.svg\n   :target: https://github.com/steinwurf/bitter/actions/workflows/macos_mkspecs.yml\n   \n.. |Linux CMake| image:: https://github.com/steinwurf/bitter/actions/workflows/linux_cmake.yml/badge.svg\n   :target: https://github.com/steinwurf/bitter/actions/workflows/linux_cmake.yml\n\n.. |Windows CMake| image:: https://github.com/steinwurf/bitter/actions/workflows/windows_cmake.yml/badge.svg\n   :target: https://github.com/steinwurf/bitter/actions/workflows/windows_cmake.yml\n   \n.. |MacOS CMake| image:: https://github.com/steinwurf/bitter/actions/workflows/macos_cmake.yml/badge.svg\n   :target: https://github.com/steinwurf/bitter/actions/workflows/macos_cmake.yml\n\n.. |Clang Format| image:: https://github.com/steinwurf/bitter/actions/workflows/clang-format.yml/badge.svg\n   :target: https://github.com/steinwurf/bitter/actions/workflows/clang-format.yml\n\n.. |No Assertions| image:: https://github.com/steinwurf/bitter/actions/workflows/nodebug.yml/badge.svg\n   :target: https://github.com/steinwurf/bitter/actions/workflows/nodebug.yml\n\n.. |Valgrind| image:: https://github.com/steinwurf/bitter/actions/workflows/valgrind.yml/badge.svg\n   :target: https://github.com/steinwurf/bitter/actions/workflows/valgrind.yml\n\n.. |Cppcheck| image:: https://github.com/steinwurf/bitter/actions/workflows/cppcheck.yml/badge.svg\n   :target: https://github.com/steinwurf/bitter/actions/workflows/cppcheck.yml\n\nIs a lightweight header only C++ API, for reading and writing single bit\nfields.\n\n.. contents:: Table of Contents:\n   :local:\n\nbitter can be used to read or write individual bits or groups of bits\ninside native data types.\n\nUsage\n-----\n\nbitter provides 4 different readers/writers::\n\n    bitter::lsb0_writer\u003cType, Fields...\u003e();\n    bitter::lsb0_reader\u003cType, Fields...\u003e();\n    bitter::msb0_writer\u003cType, Fields...\u003e();\n    bitter::msb0_reader\u003cType, Fields...\u003e();\n\nWhere ``Type`` is a unsigned integer type e.g. ``uint8_t``, ``uint16_t``,\n``uint32_t`` etc. (``uint8_t`` is short for unsigned 8 bit, these types\nare defined in the ``\u003cctdint\u003e`` header). ``Fields...`` is a variadic\ntemplate argument specifying the different bit fields. The curiously\nlooking ``lsb0`` and ``msb0`` specifies the \"bit numbering\" used. In some\nrare cases you may want to read e.g. 24 bits or 40 bits for which no\nstandard integer types are defined, however also for those you can use\nbitter see Section `Generic sized bit fields`_ further down.\n\nTo use bitter for reading/writing bit fields you need to first decide on\nwhat bit numbering scheme to use - if you never heard about this concept\nbefore you can jump to the \"Bit numbering (bit endianness)\" section further\ndown. Here's the quick TL;DR:\n\nbitter can be configured to place bit fields either from *left to right*\ncalled MSB 0 (Most Significant Bit 0) mode or *right to left* called LSB 0\n(Least Significant Bit 0) mode.\n\nExample::\n\n                   auto writer = bitter::lsb0_writer\u003cbitter::u8, 4, 4\u003e();\n                                          ^     ^         ^      ^  ^\n                                          |     |         |      |  |\n    LSB 0 mode (fields right-to-left) \u003c---+     |         |      |  |\n                                                |         |      |  |\n      We will write bits into a value \u003c---------+         |      |  |\n                                                          |      |  |\n           The data type of the value \u003c-------------------+      |  |\n                                                                 |  |\n         Field at index 0 with size 4 \u003c--------------------------+  |\n                                                                    |\n         Field at index 1 with size 4 \u003c-----------------------------+\n\nSince we use LSB 0 mode the field with index 0 will the the right half (\nbit 0-3) of the byte and the field with index 1 will be the left half (\nbit 4-7). In MSB 0 mode this would have been opposite.\n\nWriting a bit field\n-------------------\n\nLets say we want to write the four bytes of a 32 bit integer individually::\n\nLSB 0 mode\n..........\n\n::\n\n    // Using an uint32_t data type divided into 4 bit fields each 8 bits in\n    // size. The sum of the bit fields must match the number of bits in the\n    // data type.\n    auto writer = bitter::lsb0_writer\u003cuint32_t, 8, 8, 8, 8\u003e();\n\n    writer.field\u003c0\u003e(0x12); // Write bits 0-7\n    writer.field\u003c1\u003e(0x34); // Write bits 8-15\n    writer.field\u003c2\u003e(0x56); // Write bits 16-23\n    writer.field\u003c3\u003e(0x78); // Write bits 24-31\n\n    assert(writer.data() == 0x78563412);\n\nUse ``#include \u003cbitter/lsb0_writer.hpp\u003e`` to use the\n``bitter::lsb0_writer``.\n\nMSB 0 mode\n..........\n\n::\n\n    // Using an uint32_t data type divided into 4 bit fields each 8 bits in\n    // size. The sum of the bit fields must match the number of bits in the\n    // data type.\n    auto writer = bitter::msb0_writer\u003cuint32_t, 8, 8, 8, 8\u003e();\n\n    writer.field\u003c0\u003e(0x12); // Write bits 24-31\n    writer.field\u003c1\u003e(0x34); // Write bits 16-23\n    writer.field\u003c2\u003e(0x56); // Write bits 8-15\n    writer.field\u003c3\u003e(0x78); // Write bits 0-7\n\n    assert(writer.data() == 0x12345678);\n\nUse ``#include \u003cbitter/msb0_writer.hpp\u003e`` to use the\n``bitter::msb0_writer``.\n\nReading a bit field\n-------------------\n\nGiven a value we can also read the individual bit fields.\n\nLSB 0 mode\n..........\n\n::\n\n    auto reader = bitter::lsb0_reader\u003cuint32_t, 8, 8, 8, 8\u003e(0x12345678);\n\n    uint8_t value0 = reader.field\u003c0\u003e().as\u003cuint8_t\u003e(); // Read bits 0-7\n    uint8_t value1 = reader.field\u003c1\u003e().as\u003cuint8_t\u003e(); // Read bits 8-15\n    uint8_t value2 = reader.field\u003c2\u003e().as\u003cuint8_t\u003e(); // Read bits 16-23\n    uint8_t value3 = reader.field\u003c3\u003e().as\u003cuint8_t\u003e(); // Read bits 24-31\n\n    assert(value0 == 0x78);\n    assert(value1 == 0x56);\n    assert(value2 == 0x34);\n    assert(value3 == 0x12);\n\nUse ``#include \u003cbitter/lsb0_reader.hpp\u003e`` to use the\n``bitter::lsb0_reader``.\n\nMSB 0 mode\n..........\n\n::\n\n    auto reader = bitter::msb0_reader\u003cuint32_t, 8, 8, 8, 8\u003e(0x12345678);\n\n    uint8_t value0 = reader.field\u003c0\u003e().as\u003cuint8_t\u003e(); // Read bits 0-7\n    uint8_t value1 = reader.field\u003c1\u003e().as\u003cuint8_t\u003e(); // Read bits 8-15\n    uint8_t value2 = reader.field\u003c2\u003e().as\u003cuint8_t\u003e(); // Read bits 16-23\n    uint8_t value3 = reader.field\u003c3\u003e().as\u003cuint8_t\u003e(); // Read bits 24-31\n\n    assert(value0 == 0x12);\n    assert(value1 == 0x34);\n    assert(value2 == 0x56);\n    assert(value3 == 0x78);\n\nUse ``#include \u003cbitter/lsb0_reader.hpp\u003e`` to use the\n``bitter::lsb0_reader``.\n\n\nBit numbering (bit endianness)\n------------------------------\n\nBit numbering modes (also sometimes called endianess), say we have a\nsingle byte (8 bits)::\n\n       least significant +--------+\n       bit                        |\n                                  v\n    +-------------------------------+\n    | 0   1   0   1   1   1   0   0 |\n    +-------------------------------+\n      ^\n      |             most significant\n      +-----------+ bit\n\nThere are two common ways we can number the bits inside the byte (from\nhttps://en.wikipedia.org/wiki/Bit_numbering):\n\n1. MSB 0 bit numbering:\n   When the bit numbering starts at zero for the most significant bit\n   (MSB) the numbering scheme is called \"MSB 0\".\n2. LSB 0 bit numbering\n   When the bit numbering starts at zero for the least significant bit\n   (LSB) the numbering scheme is called \"LSB 0\".\n\nLets number the bits inside byte given earlier according to the LSB 0\nbit numbering::\n\n      7   6   5   4   3   2   1   0\n    +-------------------------------+\n    | 0   1   0   1   1   1   0   0 |\n    +-------------------------------+\n\nThis numbering scheme is the one we typically use when working with\nbinary numbers and when programming. E.g. to access bit at index 2 we\nhave to perform 2 right shifts.\n\nOn the other hand if we use MSB 0 bit numbering we have the most\nsignificant bit numbered zero. This is typically used in RFCs because\nit makes it possible to draw a protocol with bit numbering running\nconsecutively over a multi-byte value written in big endian.\n\nFor example take the first part of the IPv4 header\n(https://en.wikipedia.org/wiki/IPv4). The IPv4 header is MSB 0\nnumbered.\n\nThere are four bytes (32 bits) in the first chunk of the header. This\nis written to the wire in big endian format (most significant byte)\nfirst. As can be seen this is consistent with MSB 0 bit numbering\nsince bit 0 is the most significant bit::\n\n     0                   1                   2                   3\n     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1\n    +---------------------------------------------------------------+\n    |Version|  IHL  |Type of Service|          Total Length         |\n    +---------------------------------------------------------------+\n\nLets look at how we work with this in bitter. In bitter the fields\nlaid out from bit number 0.\n\nSo imagine we have the following bit reader::\n\n    auto reader = bitter::lsb0_reader\u003cuint8_t, 1, 2, 3, 2\u003e(0xdeadbeef);\n\nWe have four fields of size 1, 2, 3, 2 bits respectively (8 bits in\ntotal). We use the ``lsb0_reader`` to use LSB 0 bit numbering so we have\nthe following layout of the four fields inside the byte::\n\n      7   6   5   4   3   2   1   0\n    +-------+-----------+-------+---+\n    | 0   1 | 0   1   1 | 1   0 | 0 |\n    +-------+-----------+-------+---+\n                                  ^\n                                  |\n       least significant +--------+\n       bit\n\nSo the first field is at bit 0 which is the lest significant bit\ninside the byte.\n\nIf on the other hand we use the ``msb0_reader`` the example would be::\n\n    auto reader = bitter::msb0_reader\u003cuint8_t, 1, 2, 3, 2\u003e(0xdeadbeef);\n\nWe would have the following layout of the four fields inside the byte::\n\n      0   1   2   3   4   5   6   7\n    +---+-------+-----------+-------+\n    | 0 | 1   0 | 1   1   1 | 0   0 |\n    +---+-------+-----------+-------+\n      ^\n      |             most significant\n      +-----------+ bit\n\n\nGeneric sized bit fields\n------------------------\n\nIn some cases you may want to read/write an odd number of bytes e.g. 5\ncorresponding to 40 bits from//to a value. In that case you can use\nbitter's generic data types (defined in ``src/bitter/types.hpp``) such\nas ``u8``, ``u16``, ``u24``, ``u32``, ``u40`` etc.\n\nSmall example::\n\n    auto reader = bitter::msb0_reader\u003cbitter::u24, 4, 12, 8\u003e(0x123456U);\n\n    uint8_t value0 = reader.field\u003c0\u003e().as\u003cuint8_t\u003e(); // Read bits 0-3\n    uint16_t value1 = reader.field\u003c1\u003e().as\u003cuint16_t\u003e(); // Read bits 4-15\n    uint8_t value2 = reader.field\u003c2\u003e().as\u003cuint8_t\u003e(); // Read bits 16-23\n\n    assert(value0 == 0x1);\n    assert(value1 == 0x234);\n    assert(value2 == 0x56);\n\n\nByte endianness\n---------------\n\nWhile bitter allows us to conveniently pack bit-fields into a value. It\ndoes not deal with writing those values to memory according to a specific\nbyte order (endianess):\n\nhttps://en.wikipedia.org/wiki/Endianness\n\nTo do that you can use our ``endian`` library available here:\n\nhttps://github.com/steinwurf/endian\n\n\nUse as Dependency in CMake\n--------------------------\n\nTo depend on this project when using the CMake build system, add the following\nin your CMake build script::\n\n   add_subdirectory(\"/path/to/bitter\" bitter)\n   target_link_libraries(\u003cmy_target\u003e steinwurf::bitter)\n\nWhere ``\u003cmy_target\u003e`` is replaced by your target.\n\n\nLicense\n=======\n\nThe bitter library is released under the BSD license see the LICENSE.rst\nfile\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsteinwurf%2Fbitter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsteinwurf%2Fbitter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsteinwurf%2Fbitter/lists"}