{"id":13729903,"url":"https://github.com/oliora/bitmask","last_synced_at":"2025-05-08T02:30:51.825Z","repository":{"id":149062397,"uuid":"64471809","full_name":"oliora/bitmask","owner":"oliora","description":"A generic implementation of the BitmaskType C++ concept","archived":false,"fork":false,"pushed_at":"2020-09-04T20:10:52.000Z","size":119,"stargazers_count":85,"open_issues_count":0,"forks_count":7,"subscribers_count":7,"default_branch":"master","last_synced_at":"2024-11-14T20:38:40.353Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/oliora.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE_1_0.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":"2016-07-29T10:15:26.000Z","updated_at":"2024-09-04T15:14:40.000Z","dependencies_parsed_at":null,"dependency_job_id":"97222f14-52f7-4ffd-a8fd-4db70a7c07a0","html_url":"https://github.com/oliora/bitmask","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oliora%2Fbitmask","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oliora%2Fbitmask/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oliora%2Fbitmask/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/oliora%2Fbitmask/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/oliora","download_url":"https://codeload.github.com/oliora/bitmask/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252986617,"owners_count":21836196,"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":[],"created_at":"2024-08-03T02:01:07.246Z","updated_at":"2025-05-08T02:30:51.812Z","avatar_url":"https://github.com/oliora.png","language":"C++","readme":"# bitmask\nA generic implementation of the [BitmaskType](https://en.cppreference.com/w/cpp/named_req/BitmaskType) C++ concept.\n\nThe library is a tiny single header without any dependencies except the standard library. And yes, it's pure C++11 and constexpr.\n\nTo start using it just download [the latest version of `bitmask.hpp`](include/bitmask/bitmask.hpp) and put it somewhere in your project. (Check for other options [below](#how-to-use-bitmask-library-in-your-project)).\n\n## Warm up example\n\n```cpp\n#include \u003cbitmask/bitmask.hpp\u003e\n\n// 1. Define possible flags\nenum class open_mode {\n    binary = 0x01,\n    app    = 0x02,\n    in     = 0x04,\n    out    = 0x08,\n    trunc  = 0x10,\n    ate    = 0x20,\n    \n    // 2. Define max bitmask value\n    _bitmask_max_element = ate\n};\n\n// 3. Enable bitmask features for the enum\nBITMASK_DEFINE(open_mode)\n\n// 4. Now you can use defined bitmask:\nFile open_file(const char *filename, bitmask::bitmask\u003copen_mode\u003e mode);\n\nauto f = open_file(\"test.txt\", open_mode::out | open_mode::binary | open_mode::trunk);\n```\n## Intro\n\n`bitmask::bitmask\u003cT\u003e` class template is an implementation of [BitmaskType](http://en.cppreference.com/w/cpp/concept/BitmaskType) concept.\nIn short, a bitmask is a finite set of distinct non-zero constant values (you can think of them as \"named bits\"). It is usually used to implement a set of flags that can be passed to the function.\n\nThe implementation has one significant divergences from the concept: a bitmask value and the bitmask itself (i.e. a combination of bitmask values) are two different types.\nSo far I can't see any disadvantage because of this. Also the class provides extra operations in addition to ones required by the concept.\n\nUnlike `std::bitset\u003cN\u003e`, `bitmask::bitmask\u003cT\u003e` is \"tied\" to enum `T` and `bitmask\u003cT\u003e` ensures the type and value safety in respect to `T` as following:\n\n1) Only values of `T` (or convertible to) can be used to set bitmask bits:\n```cpp\nbitmask::bitmask\u003copen_mode\u003e mode = read_flags::optimized; // Compilation error\n```\n2) Bit operations (binary ones complement in particular) keep the bitmask value in the domain of the bitmask.\n```cpp\n// Non-contigious bitmask values (details are below)\nenum class open_mode: unsigned char {\n    binary = 0x01,\n    out    = 0x02,\n    app    = 0x08,\n    \n    _bitmask_value_mask = 0x0B // = 0x01 | 0x02 | 0x08\n};\n\nBITMASK_DEFINE(open_mode)\n\nauto open_mode_flags = ~open_mode::app | open_mode::out;\n    // open_mode_flags set to 0x03 (i.e. open_mode::binary | open_mode::out) rather than 0xF7 which would be\n    // outside of the domain of bitmask\u003copen_mode\u003e\n```\n\n`bitmask::bitmask\u003cT\u003e` is simple to use thanks to implicit conversion from `T` to `bitmask\u003cT\u003e` and overloaded operators provided (more details are below).\n\n`bitmask\u003cT\u003e` is the same size as `T` itself. It has a single field of type `std::underlying_type\u003cT\u003e::type`.\n\n## All the ways to define a bitmask\n\nThe bitmask can be defined in the ways described below.\nAny way of definition can be used with any kind of [enumeration](http://en.cppreference.com/w/cpp/language/enum): unscoped, scoped, relaxed and strongly typed ones.\nThe non-intrusive way of bitmask definition is specially designed to be used with an exisiting enum type when its definition may not be altered.\n\n### Contiguous bitmask values\n\nIf bitmask values are contigious bits that starts from the first bit i.e. `0x1`, `0x2`, `0x4`, `0x8` etc then defining the bitmask is as simple as specifying\nits max value (let's call it *max element*).\n\nIntrusive definition:\n\n```cpp\nenum class open_mode_1 {\n  app = 0x01,\n  in =  0x02,\n  out = 0x04,\n  \n  // Specify maximum bitmask value\n  _bitmask_max_element = out\n};\n\n// Enable bitmask features for the enum\nBITMASK_DEFINE(open_mode_1)\n```\n\nNon-intrusive definition:\n\n```cpp\n// Note that enum definition has nothing special to support bitmask thus any pre-existing enum type can be used\nenum class open_mode_2 {\n  app = 0x01,\n  in =  0x02,\n  out = 0x04,\n};\n\n// Specify maximum bitmask value and enable bitmask features for the enum\nBITMASK_DEFINE_MAX_ELEMENT(open_mode_2, out)\n```\n\n### Noncontiguous bitmask values\n\nIf bitmask values are non-contigious bits then you have to provide a bit-mask of all possible values.\n\nIntrusive definition:\n\n```cpp\nenum class open_mode_3 {\n  app = 0x02,\n  in =  0x08,\n  out = 0x10,\n  \n  // Specify bitmask values mask\n  _bitmask_value_mask = 0x1A // = 0x02 | 0x08 | 0x10\n};\n\n// Enable bitmask features for the enum\nBITMASK_DEFINE(open_mode_3)\n```\n\nNon-intrusive definition:\n\n```cpp\n// Note that enum definition has nothing special to support bitmask thus any pre-existing enum type can be used\nenum class open_mode_4 {\n  app = 0x02,\n  in =  0x08,\n  out = 0x10,\n};\n\n// Specify bitmask values mask and enable bitmask features for the enum\nBITMASK_DEFINE_VALUE_MASK(open_mode_4, 0x1A)  // 0x1A == 0x02 | 0x08 | 0x10\n```\n\n### Non-distinct enum values\n\nNote that `bitmask` doesn't require that all enum values are distinct bits. The enum can contain bit combinations as well.\nIt works fine as long as `bitmask` is defined properly (i.e. all distinct bits are provided).\n\n```cpp\n// Note that enum definition has nothing special to support bitmask thus any pre-existing enum type can be used\nenum open_mode {\n  open_mode_app = 0x01,\n  open_mode_in =  0x02,\n  open_mode_out = 0x04,\n  open_mode_binary = 0x08,\n  open_mode_binary_out = open_mode_binary | open_mode_out // Not a distinct bit but a combination of other bits\n};\n\n// Note that we use `open_mode_binary` rather than `open_mode_binary_out` because\n// former is the maximum distinct bit (i.e. a bitmask value) while latter is not.\nBITMASK_DEFINE_MAX_ELEMENT(open_mode, open_mode_binary)\n\nauto f = open_file(\"test.txt\", open_mode_binary_out | open_mode_app);\n```\n\n## Available operations\n\nThere is an overview of operations available for bitmask. Please check [`bitmask.hpp`](include/bitmask/bitmask.hpp) for all the details.\nNote that you can't instantiate and use `bitmask\u003cT\u003e` prior defining a bitmask for `T` with one of the `BITMASK_DEFINE...` macros described above.\n\nAll bitmask operations are `constexpr` (Have I told this already?) and most of them are `noexcept`.\n\n### Bitwise operations\n\nBitwise operations `|`, `\u0026`, `^` and `~` are available for both bitmask value and `bitmask\u003cT\u003e` types.\nBitwise assignment operators `|=`, `\u0026=` and `^=` are available for `bitmask\u003cT\u003e` only.\n\n```cpp\nenum class flags {\n    binary = 0x01,\n    app    = 0x02,\n    in     = 0x04,\n    out    = 0x08,\n};\nBITMASK_DEFINE_MAX_ELEMENT(flags, out)\n\nauto x = flags::binary | flags::app \u0026 (~flags::in ^ flags::out);\nauto y = ~x ^ flags::binary;\n// both x and y are of type bitmask\u003cflags\u003e\n\ny \u0026= flags::binary;\n```\n\n### Equality comparison\n\nOperators `==` and `!=` are available to compare two `bitmask\u003cT\u003e`, `bitmask\u003cT\u003e` with its bitmask value `T`, and `bitmask\u003cT\u003e` with its underlying integral type.\n\n```cpp\nbitmask\u003cflags\u003e x = flags::binary | flags::app;\nbitmask\u003cflags\u003e y = flags::binary | flags::in;\n\nif (flags::binary == x) ...\nif (y != flags::binary | flags::app) ...\nif (x == y) ...\nif (y == 0x12) ...\n```\n### Operator bool\n\n`bitmask\u003cT\u003e` has an explicit operator bool. One returns true if bitmask is non-zero and false otherwise.\n\n```cpp\nbitmask\u003cflags\u003e y;\nbitmask\u003cflags\u003e x = flags::binary | flags::app;\n\nif (y) ...                     // false\nif (!y) ...                    // true\nif (x \u0026 flags::binary) ...     // true\nif (!(x \u0026 flags::binary)) ...  // false\n```\n\n### Less than\n\nThere is operator `\u003c` defined for `bitmask\u003cT\u003e` so its instances can be ordered.\n\n### `std::hash\u003cbitmask\u003cT\u003e\u003e`\n\nThere is an `std::hash` specialization for `bitmask\u003cT\u003e` defined thus one can be used as an unordered container key.\n\n### Bit acccess\n\nFree function `bits()` is available for both bitmask value and `bitmask\u003cT\u003e` types.\n`bitmask\u003cT\u003e` also has a member function `bits()`.\n\n```cpp\nauto b1 = bits(flags::binary);\nauto b2 = bits(flags::binary | flags::in);\nauto b3 = (flags::binary | flags::in).bits();\n// All b1, b2 and b3 are of type std::underlying_type\u003cflags\u003e::type.\n```\n\n## How to build and run tests\n\nIt's easy: you only need to install CMake 3.1 and download the library sources.\n\n```\ngit clone https://github.com/oliora/bitmask.git\ncd bitmask\nmkdir build\ncd build\ncmake ..\nmake\nmake test\n```\n\n## How to use Bitmask library in your project\n\nThe simplest way is to download [the lastest version of `bitmask.hpp`](include/bitmask/bitmask.hpp) and place it into your project source tree, preferable under `bitmask` directory.\n\nIf you want to keep the library separated, you can build and install the library:\n\n```\ngit clone https://github.com/oliora/bitmask.git\ncd bitmask\nmkdir build\ncd build\ncmake [-DCMAKE_INSTALL_PREFIX=\u003cprefix\u003e] ..\nmake\nmake install\n```\n\nWhen installed, the library can be simply used in any CMake project as following:\n\n```\nfind_package(bitmask)\nadd_executable(\u003cyour_app\u003e ...)\ntarget_link_libraries(\u003cyour_app\u003e bitmask)\n```\n\n## Acknowledgement\n\n- LLVM libc++ for inspiring `std::regex_constants` implementation.\n- [Jonathan Müller](https://twitter.com/foonathan) for great post https://foonathan.github.io/blog/2016/09/09/cpp14-concepts.html that inspired me to add compile-time tests (yet in progress).\n\n## Tested compilers\n\n- MacOS: Apple Clang 7.3.0\n- Linux: G++ 4.8.5 and G++ 5.4.0\n- Windows: Visual C++ 2015 (14.0) Update 3.\n  *Note that some tests and compile time checks are disabled because VC++ has a limited support for expression SFINAE.*\n\n## License\nThe library released under [Boost Software License v1.0](http://www.boost.org/LICENSE_1_0.txt).\n","funding_links":[],"categories":["C++"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foliora%2Fbitmask","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Foliora%2Fbitmask","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Foliora%2Fbitmask/lists"}