All Projects → m-peko → Bitflags

m-peko / Bitflags

Licence: mit
Single-header header-only C++11 / C++14 / C++17 library for easily managing set of auto-generated type-safe flags.

Programming Languages

cpp
1120 projects
cplusplus
227 projects

Labels

Projects that are alternatives of or similar to Bitflags

argum
Parse incoming arguments in to structure
Stars: ✭ 18 (-70%)
Mutual labels:  flags
Grumble
A powerful modern CLI and SHELL
Stars: ✭ 277 (+361.67%)
Mutual labels:  flags
World countries
Constantly updated lists of world countries and their associated alpha-2, alpha-3 and numeric country codes as defined by the ISO 3166 standard, available in CSV, JSON , PHP and SQL formats, in multiple languages and with national flags included
Stars: ✭ 598 (+896.67%)
Mutual labels:  flags
flags-brazil
Bandeiras dos Estados Federativos do Brasil feitas com CSS
Stars: ✭ 18 (-70%)
Mutual labels:  flags
football-team-flags
Flags from national teams made with css 🏳
Stars: ✭ 19 (-68.33%)
Mutual labels:  flags
Flagphonenumber
A formatted phone number UITextField with country flag picker.
Stars: ✭ 371 (+518.33%)
Mutual labels:  flags
react-flagkit
🇺🇦 React wrapper for FlagKit Flag Icons
Stars: ✭ 21 (-65%)
Mutual labels:  flags
Flags
🇸🇪 Flag extension make flag emoji, image
Stars: ✭ 28 (-53.33%)
Mutual labels:  flags
flagfillr
Use flags as fills for ggplot2 maps. (WIP)
Stars: ✭ 23 (-61.67%)
Mutual labels:  flags
Kong
Kong is a command-line parser for Go
Stars: ✭ 481 (+701.67%)
Mutual labels:  flags
jest-launchdarkly-mock
Easily unit test LaunchDarkly feature flagged components with jest
Stars: ✭ 14 (-76.67%)
Mutual labels:  flags
countriesNowAPI
CountriesNow is an Open source API for retrieving geo-information for countries, including their states, cities, population, etc. 🌎
Stars: ✭ 78 (+30%)
Mutual labels:  flags
Mri
Quickly scan for CLI flags and arguments
Stars: ✭ 394 (+556.67%)
Mutual labels:  flags
Utility.CommandLine.Arguments
A C# .NET class library containing tools for parsing the command line arguments of console applications.
Stars: ✭ 105 (+75%)
Mutual labels:  flags
Flaggy
Idiomatic Go input parsing with subcommands, positional values, and flags at any position. No required project or package layout and no external dependencies.
Stars: ✭ 711 (+1085%)
Mutual labels:  flags
pflag
Generic PHP command line flags parse library
Stars: ✭ 14 (-76.67%)
Mutual labels:  flags
Name Suggestion Index
Canonical common brand names, operators, transit and flags for OpenStreetMap.
Stars: ✭ 332 (+453.33%)
Mutual labels:  flags
Unpuzzled
A colorful CLI library with variable provenance.
Stars: ✭ 57 (-5%)
Mutual labels:  flags
Famfamfam Flags Wpf
famfamfam flag icons for WPF
Stars: ✭ 17 (-71.67%)
Mutual labels:  flags
Args
Toolkit for building command line interfaces
Stars: ✭ 399 (+565%)
Mutual labels:  flags

Single-header header-only C++11 / C++14 / C++17 library for easily managing set of auto-generated type-safe flags.

License Build Status Codecov Standard Standard Standard Compiler explorer

Quick start

#include <bitflags/bitflags.hpp>

BEGIN_BITFLAGS(Flags)
    FLAG(none)
    FLAG(flag_a)
    FLAG(flag_b)
    FLAG(flag_c)
END_BITFLAGS(Flags)

int main() {
    Flags flags = Flags::flag_a | Flags::flag_b;

    if (flags & Flags::flag_a) {
        std::cout << "flag_a is set" << std::endl;
    } else {
        std::cout << "flag_a is not set" << std::endl;
    }

    flags.toggle(Flags::flag_a);

    // ...

    return 0;
}

Table of Contents

Motivation

Inspiration for writing this bitflags library I got from the homonymous Rust's crate that you may find here.

Some people may ask: Why not just use enum class and assign binary literals?

Following example presents using enum class with std::uint8_t as underlying type (so that max number of flags is 9):

enum class Flags : std::uint8_t {
    none   = 0b0000,
    flag_a = 0b0001,
    flag_b = 0b0010,
    flag_c = 0b0010
};

Nothing is wrong with above usage, right?

Oh... you might not have noticed that both Flags::flag_b and Flags::flag_c have the same value assigned! That's the exact same mistake that developers make in everyday work... This mistake happened with std::uint8_t as underlying type but imagine how often would be mistakes if the underlying value is std::uint32_t or even std::uint64_t.

You got the point?

Assigning binary literals to flags is manual and error-prone process, especially if there is lots of flags and if developers change them over time.

So, why should I use bitflags library?

bitflags library provides you decently safe way of specifying your flags with 2 core features:

  • auto - generated flag values
  • auto - detected underlying type

Getting Started

bitflags is a single-header header-only C++11 / C++14 / C++17 library for easily managing set of auto-generated type-safe flags.

Raw flags vs flags?

bitflags library provides you with 2 flag types:

  • raw_flag without its string representation (sort of lightweight version)
  • flag with its string representation

How to Declare Set of Flags?

In order to declare a set of auto-generated flags, there are few helper macros that hide kind of "ugly" declaration syntax and provide auto-generated value for each flag.

Macros for creating set of raw flags, i.e. flags without string representation:

  • BEGIN_RAW_BITFLAGS(NAME)

    • NAME - name of set of raw flags
  • RAW_FLAG(NAME)

    • NAME - name of specific raw flag
  • END_RAW_BITFLAGS(NAME)

    • NAME - name of set of raw flags

Macros for creating set of ordinary flags, i.e. flags with string representation:

  • BEGIN_BITFLAGS(NAME)

    • NAME - name of set of flags
  • FLAG(NAME)

    • NAME - name of specific flag
  • END_BITFLAGS(NAME)

    • NAME - name of set of flags

Following snippet shows the use case of the above macros:

BEGIN_BITFLAGS(Flags)
    FLAG(none)
    FLAG(flag_a)
    FLAG(flag_b)
    FLAG(flag_c)
END_BITFLAGS()

and is translated into:

template <typename T>
struct FlagsImpl {
    using flag = bf::internal::flag<FlagsImpl, T>
    static constexpr flag none{ 0b0000, "none" };
    static constexpr flag flag_a{ 0b0001, "flag_a" };
    static constexpr flag flag_b{ 0b0010, "flag_b" };
    static constexpr flag flag_c{ 0b0100, "flag_c" };
};

using Flags = bf::bitflags<
    FlagsImpl<
        bf::bitflags<
            FlagsImpl<std::uint8_t>
        >::underlying_type
    >
>;

Usage is basically the same for raw_flags.

Bits and Names

While bits are part of both raw_flag and flag, names are part of flag type only.

Once the flags are specified, it is possible to get bits representing each flag as well as string representation of each flag:

BEGIN_RAW_BITFLAGS(RawFlags)
    RAW_FLAG(none)
    RAW_FLAG(flag_a)
    RAW_FLAG(flag_b)
END_RAW_BITFLAGS(RawFlags)

std::cout << RawFlags::flag_a.bits << std::endl;

and

BEGIN_BITFLAGS(Flags)
    FLAG(none)
    FLAG(flag_a)
    FLAG(flag_b)
END_BITFLAGS(Flags)

std::cout << Flags::flag_a.bits << " - " << Flags::flag_a.name << std::endl;

Bitwise Operators

The following binary operators are implemented for the generated flags:

  • NOT (~) operator
  • AND (&) operator
  • OR (|) operator
  • XOR (^) operator

Is Specific Flag Set?

In case we want to check whether specific flag is set or not, we have 2 options:

  1. use AND operator
BEGIN_BITFLAGS(Flags)
    FLAG(none)
    FLAG(flag_a)
    FLAG(flag_b)
END_BITFLAGS(Flags)

Flags flags = Flags::flag_a;

std::cout << static_cast<bool>(flags & Flags::flag_a) << std::endl; // true
std::cout << static_cast<bool>(flags & Flags::flag_b) << std::endl; // false
  1. use contains member function
BEGIN_BITFLAGS(Flags)
    FLAG(none)
    FLAG(flag_a)
    FLAG(flag_b)
    FLAG(flag_c)
END_BITFLAGS(Flags)

Flags flags_1 = Flags::flag_a;

std::cout << flags_1.contains(Flags::flag_a) << std::endl; // true
std::cout << flags_1.contains(Flags::flag_b) << std::endl; // false

Flags flags_2 = Flags::flag_a | Flags::flag_b;

std::cout << flags_2.contains(Flags::flag_a, Flags::flag_b) << std::endl; // true
std::cout << flags_2.contains(Flags::flag_a, Flags::flag_c) << std::endl; // false

All or Empty

Following member functions are available for setting all the flags or setting no flag:

  1. all / is_all
BEGIN_BITFLAGS(Flags)
    FLAG(none)
    FLAG(flag_a)
    FLAG(flag_b)
END_BITFLAGS(Flags)

Flags flags = Flags::all();

std::cout << flags.is_all() << std::endl;                // true
std::cout << flags.contains(Flags::flag_a) << std::endl; // true
std::cout << flags.contains(Flags::flag_b) << std::endl; // true
std::cout << flags.is_empty() << std::endl;              // false
  1. empty / is_empty
BEGIN_BITFLAGS(Flags)
    FLAG(none)
    FLAG(flag_a)
    FLAG(flag_b)
END_BITFLAGS(Flags)

Flags flags = Flags::empty();

std::cout << flags.is_all() << std::endl;                // false
std::cout << flags.contains(Flags::flag_a) << std::endl; // false
std::cout << flags.contains(Flags::flag_b) << std::endl; // false
std::cout << flags.is_empty() << std::endl;              // true

Set and Remove Specific Flag

Not only that one can set and remove specific flag by using bitwise operators, but there are also special member functions set and remove that have the same purpose.

BEGIN_BITFLAGS(Flags)
    FLAG(none)
    FLAG(flag_a)
    FLAG(flag_b)
END_BITFLAGS(Flags)

Flags flags = Flags::empty();

std::cout << flags.contains(Flags::flag_a) << std::endl; // false
std::cout << flags.contains(Flags::flag_b) << std::endl; // false

flags.set(Flags::flag_a);
flags.set(Flags::flag_b);

std::cout << flags.contains(Flags::flag_a) << std::endl; // true
std::cout << flags.contains(Flags::flag_b) << std::endl; // true

flags.remove(Flags::flag_a);

std::cout << flags.contains(Flags::flag_a) << std::endl; // false
std::cout << flags.contains(Flags::flag_b) << std::endl; // true

Toggle Flags

It is possible to toggle specific flag, i.e. if the flag is not already set, it will be set. On the other hand, if the flag is already set, it will be unset.

BEGIN_BITFLAGS(Flags)
    FLAG(none)
    FLAG(flag_a)
    FLAG(flag_b)
END_BITFLAGS(Flags)

Flags flags = Flags::flag_a;

std::cout << flags.contains(Flags::flag_a) << std::endl; // true
flags.toggle(Flags::flag_a);
std::cout << flags.contains(Flags::flag_a) << std::endl; // false

std::cout << flags.contains(Flags::flag_b) << std::endl; // false
flags.toggle(Flags::flag_b);
std::cout << flags.contains(Flags::flag_b) << std::endl; // true

Clear Flags

In order to clear all the flags currently set, one can use clear member function.

BEGIN_BITFLAGS(Flags)
    FLAG(none)
    FLAG(flag_a)
    FLAG(flag_b)
    FLAG(flag_c)
END_BITFLAGS(Flags)

Flags flags = Flags::flag_a | Flags::flag_b;

std::cout << flags.contains(Flags::flag_a) << std::endl; // true
std::cout << flags.contains(Flags::flag_b) << std::endl; // true
std::cout << flags.contains(Flags::flag_c) << std::endl; // false

flags.clear();

std::cout << flags.contains(Flags::flag_a) << std::endl; // false
std::cout << flags.contains(Flags::flag_b) << std::endl; // false
std::cout << flags.contains(Flags::flag_c) << std::endl; // false

Benchmark

As you can see from the following chart, using raw_flags is as fast as using std::bitset. However, using ordinary flags (i.e. flags with string representation) is a bit slower (as it is expected because of additional feature of having string representation).

If you want to run the benchmark yourself, you can use plot.py script like:

$ python3 plot.py --benchmarks-dir <benchmark-json-dir>

Building Samples and Tests

$ git clone https://github.com/m-peko/bitflags
$ cd bitflags

$ # create the build directory
$ mkdir build
$ cd build

$ # configure the project
$ cmake -DBITFLAGS_BUILD_SAMPLES=ON -DBITFLAGS_BUILD_TESTS=ON ..

$ # compile
$ make

$ # compile tests
$ make tests

$ # run tests
$ make test

Compiler Compatibility

  • Clang/LLVM >= 5
  • MSVC++ >= 14.11 / Visual Studio >= 2017
  • GCC >= 7.3

There are no 3rd party dependencies.

Contributing

Feel free to contribute.

If you find that any of the tests fail, please create a ticket in the issue tracker indicating the following information:

  • platform
  • architecture
  • library version
  • minimal reproducible example

License

The project is available under the MIT license.

Support

If you like the work bitflags library is doing, please consider supporting it:

Buy Me A Coffee

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].