Skip to content

merlotqi/enum_flags

Repository files navigation

Enum Flags

A modern C++ library for type-safe flag operations on enum types.

Features

  • Type-safe flag operations: Perform bitwise operations on enum types without losing type safety
  • Modern C++ support: C++17 baseline; C++20-era features are enabled when the compiler and standard library expose the matching feature macros
  • Minimal overhead: Zero-cost abstractions with compile-time optimizations
  • Comprehensive API: Complete set of flag manipulation functions and operators

Quick Start

Enable Flag Operations

To enable flag operations for an enum type, add a declaration:

enum class MyFlags {
    None = 0,
    Flag1 = 1 << 0,
    Flag2 = 1 << 1,
    Flag3 = 1 << 2
};

// Enable flag operations for MyFlags
enum_flags::enable_flag_ops flag_enable(MyFlags);

Basic Usage

#include "enum_flags.hpp"

enum class Permissions {
    None = 0,
    Read = 1 << 0,
    Write = 1 << 1,
    Execute = 1 << 2
};

enum_flags::enable_flag_ops flag_enable(Permissions);

int main() {
    // Combine flags using bitwise OR
    auto perms = Permissions::Read | Permissions::Write;
    
    // Test if a flag is set
    bool has_read = enum_flags::test(perms, Permissions::Read);
    
    // Set a flag
    perms = enum_flags::set_flag(perms, Permissions::Execute);
    
    // Clear a flag
    perms = enum_flags::clear_flag(perms, Permissions::Write);
    
    // Toggle a flag
    perms = enum_flags::toggle_flag(perms, Permissions::Read);
    
    return 0;
}

API Reference

Flag Operations

  • set_flag(value, flag, on = true) - Set or clear a flag
  • clear_flag(value, flag) - Clear a flag
  • toggle_flag(value, flag) - Toggle a flag
  • set_assign(value, flag, on = true) - Assignment version of set_flag
  • clear_assign(value, flag) - Assignment version of clear_flag
  • toggle_assign(value, flag) - Assignment version of toggle_flag

Query Operations

  • any(value) - Check if any flags are set
  • none(value) - Check if no flags are set
  • test(value, mask) - True if any bit in mask is set in value (i.e. (value & mask) != 0); mask may combine several flags
  • all(value, mask) - True if every bit in mask is set in value
  • count(value) - Count the number of set flags

Bitwise Operators

When flag operations are enabled for an enum type, the following operators are automatically available:

  • operator| - Bitwise OR (combine flags)
  • operator& - Bitwise AND (intersection)
  • operator^ - Bitwise XOR (difference)
  • operator~ - Bitwise NOT on the full underlying type (may set bits that are not named enumerators)
  • operator|= - Compound OR assignment
  • operator&= - Compound AND assignment
  • operator^= - Compound XOR assignment

Requirements

  • C++17 or later is required for the library itself.
  • Optional capabilities are detected independently (you can have one without the other, depending on the toolchain):
    • When __cpp_concepts >= 201907L, the library uses C++20 concepts (FlagEnum) and concept-based constraints on the bitwise operators.
    • When __cpp_lib_int_pow2 >= 202002L, <bit> is available and enum_flags::count uses std::popcount; otherwise it uses a portable popcount loop.

Most C++20 standard libraries provide both; C++17 mode uses neither.

Installation

Vendoring: Copy enum_flags.hpp into your tree, add its directory to your include path, then:

#include "enum_flags.hpp"

Adjust the include form ("enum_flags.hpp" vs <...>) to match how you expose headers.

CMake (this repository): After add_subdirectory(enum_flags) or equivalent, link the interface target:

target_link_libraries(your_target PRIVATE enum_flags::enum_flags)

That adds the directory containing enum_flags.hpp as a usage requirement. You can also install the header and CMake package (see INSTALL.md) and use find_package(enum_flags CONFIG).

Building and testing

From the repository root, with a C++17-capable compiler:

cmake -S . -B build -DENUM_FLAGS_BUILD_TESTS=ON
cmake --build build
ctest --test-dir build --output-on-failure

To compile the bundled tests as C++20 (e.g. to exercise concepts in your toolchain), set -DENUM_FLAGS_TEST_CXX_STANDARD=20 when configuring.

To use this project as a subdirectory without building its tests: -DENUM_FLAGS_BUILD_TESTS=OFF.

Design Philosophy

This library follows several key principles:

  1. Type Safety: All operations maintain enum type safety and prevent accidental mixing of different enum types
  2. Zero Cost: Operations are optimized away at compile time when possible
  3. Explicit Opt-in: Flag operations must be explicitly enabled for each enum type
  4. Modern C++: Uses newer language and library features when feature macros indicate they are available, without raising the baseline above C++17

Examples

File Permissions

enum class FileMode {
    None = 0,
    Read = 1 << 0,
    Write = 1 << 1,
    Execute = 1 << 2,
    Append = 1 << 3
};

enum_flags::enable_flag_ops flag_enable(FileMode);

void set_file_mode(FileMode& mode, FileMode flags) {
    mode |= flags;
}

bool has_permission(FileMode mode, FileMode permission) {
    return enum_flags::test(mode, permission);
}

UI State Flags

enum class WidgetState {
    None = 0,
    Enabled = 1 << 0,
    Visible = 1 << 1,
    Focused = 1 << 2,
    Hovered = 1 << 3
};

enum_flags::enable_flag_ops flag_enable(WidgetState);

class Widget {
    WidgetState state_ = WidgetState::None;
    
public:
    void set_enabled(bool enabled) {
        enum_flags::set_assign(state_, WidgetState::Enabled, enabled);
    }
    
    bool is_enabled() const {
        return enum_flags::test(state_, WidgetState::Enabled);
    }
    
    void set_visible(bool visible) {
        enum_flags::set_assign(state_, WidgetState::Visible, visible);
    }
    
    bool is_visible() const {
        return enum_flags::test(state_, WidgetState::Visible);
    }
};

License

This project is licensed under the MIT License - see the LICENSE file for details.

About

modern C++ library for type-safe flag operations on enum types.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors