├── .bazelignore ├── .bazelrc ├── .bazelversion ├── .cmake-format ├── .dockerignore ├── .github ├── dependabot.yml └── workflows │ ├── bzlmod-archive.yml │ ├── macos.yml │ ├── scorecard.yml │ ├── ubuntu.yml │ ├── ubuntu_test_installed_version.yml │ └── windows.yml ├── .gitignore ├── BUILD.bazel ├── CMakeLists.txt ├── Dockerfile ├── LICENSE ├── MODULE.bazel ├── README.md ├── SECURITY.md ├── WORKSPACE.bazel ├── cmake └── GenPkgConfig │ ├── GenPkgConfig.cmake │ ├── ReadMe.md │ ├── UNLICENSE │ └── buildTimeScripts │ └── getObjectFilesBaseNames.cmake ├── doc ├── limitations.md └── reference.md ├── example ├── CMakeLists.txt ├── enum_flag_example.cpp ├── example.cpp ├── example_containers_array.cpp ├── example_containers_bitset.cpp ├── example_containers_set.cpp ├── example_custom_name.cpp ├── example_nonascii_name.cpp └── example_switch.cpp ├── include └── magic_enum │ ├── magic_enum.hpp │ ├── magic_enum_all.hpp │ ├── magic_enum_containers.hpp │ ├── magic_enum_flags.hpp │ ├── magic_enum_format.hpp │ ├── magic_enum_fuse.hpp │ ├── magic_enum_iostream.hpp │ ├── magic_enum_switch.hpp │ └── magic_enum_utility.hpp ├── meson.build ├── meson_options.txt ├── module └── magic_enum.cppm ├── package.xml ├── test ├── .bazelrc ├── 3rdparty │ └── Catch2 │ │ ├── LICENSE │ │ └── include │ │ └── catch2 │ │ └── catch.hpp ├── BUILD.bazel ├── CMakeLists.txt ├── MODULE.bazel ├── WORKSPACE.bazel ├── meson.build ├── test.cpp ├── test_aliases.cpp ├── test_containers.cpp ├── test_flags.cpp ├── test_nonascii.cpp └── test_wchar_t.cpp └── test_installed_version.bash /.bazelignore: -------------------------------------------------------------------------------- 1 | .git 2 | .github 3 | test 4 | doc 5 | cmake 6 | -------------------------------------------------------------------------------- /.bazelrc: -------------------------------------------------------------------------------- 1 | common --enable_bzlmod 2 | build --enable_platform_specific_config 3 | build --enable_runfiles 4 | build --incompatible_strict_action_env 5 | 6 | common:ci --announce_rc 7 | test:ci --test_output=errors 8 | build:ci --curses=no 9 | -------------------------------------------------------------------------------- /.bazelversion: -------------------------------------------------------------------------------- 1 | 6.3.2 2 | -------------------------------------------------------------------------------- /.cmake-format: -------------------------------------------------------------------------------- 1 | format: 2 | tab_size: 2 3 | line_width: 100 4 | dangle_parens: true 5 | 6 | parse: 7 | additional_commands: 8 | cpmaddpackage: 9 | pargs: 10 | nargs: '*' 11 | flags: [] 12 | spelling: CPMAddPackage 13 | kwargs: &cpmaddpackagekwargs 14 | NAME: 1 15 | FORCE: 1 16 | VERSION: 1 17 | GIT_TAG: 1 18 | DOWNLOAD_ONLY: 1 19 | GITHUB_REPOSITORY: 1 20 | GITLAB_REPOSITORY: 1 21 | GIT_REPOSITORY: 1 22 | SVN_REPOSITORY: 1 23 | SVN_REVISION: 1 24 | SOURCE_DIR: 1 25 | DOWNLOAD_COMMAND: 1 26 | FIND_PACKAGE_ARGUMENTS: 1 27 | NO_CACHE: 1 28 | GIT_SHALLOW: 1 29 | URL: 1 30 | URL_HASH: 1 31 | URL_MD5: 1 32 | DOWNLOAD_NAME: 1 33 | DOWNLOAD_NO_EXTRACT: 1 34 | HTTP_USERNAME: 1 35 | HTTP_PASSWORD: 1 36 | OPTIONS: + 37 | cpmfindpackage: 38 | pargs: 39 | nargs: '*' 40 | flags: [] 41 | spelling: CPMFindPackage 42 | kwargs: *cpmaddpackagekwargs 43 | packageproject: 44 | pargs: 45 | nargs: '*' 46 | flags: [] 47 | spelling: packageProject 48 | kwargs: 49 | NAME: 1 50 | VERSION: 1 51 | NAMESPACE: 1 52 | INCLUDE_DIR: 1 53 | INCLUDE_DESTINATION: 1 54 | BINARY_DIR: 1 55 | COMPATIBILITY: 1 56 | VERSION_HEADER: 1 57 | DEPENDENCIES: + 58 | 59 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | build*/ 2 | .cache/ 3 | .git/ 4 | .github/ 5 | compile_commands.json 6 | .dockerignore 7 | Dockerfile 8 | install_dir/ 9 | 10 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "monthly" 7 | groups: 8 | github-actions: 9 | patterns: 10 | - "*" 11 | -------------------------------------------------------------------------------- /.github/workflows/bzlmod-archive.yml: -------------------------------------------------------------------------------- 1 | name: Bzlmod Archive 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | # A release archive is required for bzlmod 9 | # See: https://blog.bazel.build/2023/02/15/github-archive-checksum.html 10 | upload-archive: 11 | runs-on: ubuntu-latest 12 | permissions: 13 | contents: write 14 | steps: 15 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 16 | - run: git archive -o "${{ format('{0}-{1}.tar.gz', github.event.repository.name, github.event.release.tag_name) }}" HEAD 17 | - run: gh release upload ${{ github.event.release.tag_name }} *.tar.gz 18 | env: 19 | GH_TOKEN: ${{ github.token }} 20 | -------------------------------------------------------------------------------- /.github/workflows/macos.yml: -------------------------------------------------------------------------------- 1 | name: macos 2 | 3 | on: [push, pull_request] 4 | 5 | permissions: read-all 6 | 7 | jobs: 8 | build: 9 | runs-on: ${{ matrix.config.os }} 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | config: 14 | - { os: macos-13 } # https://github.com/actions/virtual-environments/blob/main/images/macos/macos-13-Readme.md#xcode 15 | - { os: macos-14 } # https://github.com/actions/virtual-environments/blob/main/images/macos/macos-14-Readme.md#xcode 16 | 17 | name: "${{ matrix.config.os }}" 18 | steps: 19 | - uses: actions/checkout@v4 20 | 21 | - name: Build Release 22 | run: | 23 | rm -rf build 24 | mkdir build 25 | cd build 26 | cmake .. -DCMAKE_BUILD_TYPE=Release 27 | cmake --build . -j 4 --config Release 28 | ctest --output-on-failure -C Release 29 | 30 | - name: Build Debug 31 | run: | 32 | rm -rf build 33 | mkdir build 34 | cd build 35 | cmake .. -DCMAKE_BUILD_TYPE=Debug 36 | cmake --build . -j 4 --config Debug 37 | ctest --output-on-failure -C Debug 38 | 39 | - name: Bazel Test 40 | working-directory: test 41 | run: bazelisk test //... --config=ci 42 | -------------------------------------------------------------------------------- /.github/workflows/scorecard.yml: -------------------------------------------------------------------------------- 1 | name: Scorecard supply-chain security 2 | on: 3 | # For Branch-Protection check. Only the default branch is supported. See 4 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection 5 | branch_protection_rule: 6 | # To guarantee Maintained check is occasionally updated. See 7 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained 8 | schedule: 9 | - cron: '42 15 * * 4' 10 | push: 11 | branches: [ "master" ] 12 | 13 | # Declare default permissions as read only. 14 | permissions: read-all 15 | 16 | jobs: 17 | analysis: 18 | name: Scorecard analysis 19 | runs-on: ubuntu-latest 20 | permissions: 21 | # Needed to upload the results to code-scanning dashboard. 22 | security-events: write 23 | # Needed to publish results and get a badge (see publish_results below). 24 | id-token: write 25 | 26 | steps: 27 | - name: "Checkout code" 28 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 29 | with: 30 | persist-credentials: false 31 | 32 | - name: "Run analysis" 33 | uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 34 | with: 35 | results_file: results.sarif 36 | results_format: sarif 37 | # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: 38 | # - you want to enable the Branch-Protection check and you prefer not to use the new Repo Rules 39 | # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. 40 | # repo_token: ${{ secrets.SCORECARD_TOKEN }} 41 | 42 | # - Publish results to OpenSSF REST API for easy access by consumers 43 | # - Allows the repository to include the Scorecard badge. 44 | # - See https://github.com/ossf/scorecard-action#publishing-results. 45 | publish_results: true 46 | 47 | # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF 48 | # format to the repository Actions tab. 49 | - name: "Upload artifact" 50 | uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 51 | with: 52 | name: SARIF file 53 | path: results.sarif 54 | retention-days: 5 55 | 56 | # Upload the results to GitHub's code scanning dashboard. 57 | - name: "Upload to code-scanning" 58 | uses: github/codeql-action/upload-sarif@dd746615b3b9d728a6a37ca2045b68ca76d4841a # v3.28.8 59 | with: 60 | sarif_file: results.sarif 61 | -------------------------------------------------------------------------------- /.github/workflows/ubuntu.yml: -------------------------------------------------------------------------------- 1 | name: ubuntu 2 | 3 | on: [push, pull_request] 4 | 5 | permissions: read-all 6 | 7 | jobs: 8 | ubuntu: 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | compiler: 13 | - { cc: "gcc-10", cxx: "g++-10", os: "ubuntu-20.04", nonascii: "TRUE" } 14 | - { cc: "gcc-10", cxx: "g++-10", os: "ubuntu-20.04", nonascii: "FALSE" } 15 | - { cc: "gcc-11", cxx: "g++-11", os: "ubuntu-22.04", nonascii: "TRUE" } 16 | - { cc: "gcc-11", cxx: "g++-11", os: "ubuntu-22.04", nonascii: "FALSE" } 17 | - { cc: "gcc-12", cxx: "g++-12", os: "ubuntu-22.04", nonascii: "FALSE" } 18 | - { cc: "gcc-13", cxx: "g++-13", os: "ubuntu-24.04", nonascii: "FALSE" } 19 | - { cc: "gcc-14", cxx: "g++-14", os: "ubuntu-24.04", nonascii: "FALSE" } 20 | - { cc: "clang-10", cxx: "clang++-10", os: "ubuntu-20.04", nonascii: "FALSE" } 21 | - { cc: "clang-11", cxx: "clang++-11", os: "ubuntu-20.04", nonascii: "FALSE" } 22 | - { cc: "clang-12", cxx: "clang++-12", os: "ubuntu-22.04", nonascii: "FALSE" } 23 | - { cc: "clang-13", cxx: "clang++-13", os: "ubuntu-22.04", nonascii: "FALSE" } 24 | - { cc: "clang-14", cxx: "clang++-14", os: "ubuntu-22.04", nonascii: "FALSE" } 25 | - { cc: "clang-15", cxx: "clang++-15", os: "ubuntu-22.04", nonascii: "FALSE" } 26 | - { cc: "clang-16", cxx: "clang++-16", os: "ubuntu-24.04", nonascii: "FALSE" } 27 | 28 | name: "${{ format('{0} NONASCII={1}', matrix.compiler.cc, matrix.compiler.nonascii) }}" 29 | runs-on: ${{ matrix.compiler.os }} 30 | steps: 31 | - uses: actions/checkout@v4 32 | 33 | - name: Configure clang 34 | run: | 35 | if [[ "${{ matrix.compiler.cc }}" == "clang"* ]]; then 36 | sudo apt update 37 | sudo apt install ${{ matrix.compiler.cc }} -y 38 | fi 39 | 40 | - name: Configure gcc 41 | run: | 42 | if [[ "${{ matrix.compiler.cc }}" == "gcc"* ]]; then 43 | sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y 44 | sudo apt update 45 | sudo apt install ${{ matrix.compiler.cxx }} -y 46 | fi 47 | 48 | - name: Build Release 49 | run: | 50 | rm -rf build 51 | mkdir build 52 | cd build 53 | cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=${{ matrix.compiler.cxx }} -DMAGIC_ENUM_OPT_ENABLE_NONASCII:BOOL=${{ matrix.compiler.nonascii }} 54 | cmake --build . -j 4 --config Release 55 | ctest --output-on-failure -C Release 56 | 57 | - name: Build Debug 58 | run: | 59 | rm -rf build 60 | mkdir build 61 | cd build 62 | cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=${{ matrix.compiler.cxx }} -DMAGIC_ENUM_OPT_ENABLE_NONASCII:BOOL=${{ matrix.compiler.nonascii }} 63 | cmake --build . -j 4 --config Debug 64 | ctest --output-on-failure -C Debug 65 | 66 | - name: Bazel Test 67 | working-directory: test 68 | run: bazelisk test //... --config=ci 69 | -------------------------------------------------------------------------------- /.github/workflows/ubuntu_test_installed_version.yml: -------------------------------------------------------------------------------- 1 | name: ubuntu_test_installed_version.yml 2 | 3 | 4 | on: 5 | push: 6 | branches: 7 | - master 8 | - main 9 | pull_request: 10 | branches: 11 | - master 12 | - main 13 | 14 | env: 15 | CTEST_OUTPUT_ON_FAILURE: 1 16 | CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm_modules 17 | 18 | jobs: 19 | build: 20 | runs-on: ubuntu-latest 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | 25 | - uses: actions/cache@v4 26 | with: 27 | path: "**/cpm_modules" 28 | key: ${{ github.workflow }}-cpm-modules-${{ hashFiles('**/CMakeLists.txt', '**/*.cmake') }} 29 | 30 | - name: install library 31 | run: | 32 | cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release --log-level=DEBUG -DCMAKE_INSTALL_PREFIX=./install_dir 33 | cmake --build ./build -j$(nproc) 34 | cmake --install ./build --prefix ./install_dir 35 | rm -rf build 36 | 37 | - name: configure with installed version via cmake 38 | run: CMAKE_PREFIX_PATH="./install_dir" cmake -S. -Bbuild2 -DMAGIC_ENUM_OPT_TEST_INSTALLED_VERSION=1 --log-level=DEBUG 39 | 40 | - name: build with installed version via cmake 41 | run: cmake --build build2 --config Debug -j$(nproc) --verbose 42 | 43 | - name: test 44 | run: | 45 | cd build2 46 | ctest --build-config Debug -j$(nproc) 47 | 48 | - name: clear 49 | run: rm -rf build2 50 | 51 | - name: configure with installed version via pkgconfig 52 | run: CMAKE_PREFIX_PATH="./install_dir" cmake -S. -Bbuild3 -DMAGIC_ENUM_OPT_TEST_INSTALLED_VERSION_PKGCONFIG=1 -DPKG_CONFIG_USE_CMAKE_PREFIX_PATH=1 --log-level=DEBUG 53 | 54 | - name: build with installed version via pkgconfig 55 | run: cmake --build build3 --config Debug -j$(nproc) --verbose 56 | 57 | - name: test 58 | run: | 59 | cd build3 60 | ctest --build-config Debug -j$(nproc) 61 | -------------------------------------------------------------------------------- /.github/workflows/windows.yml: -------------------------------------------------------------------------------- 1 | name: windows 2 | 3 | on: [push, pull_request] 4 | 5 | permissions: read-all 6 | 7 | jobs: 8 | build: 9 | runs-on: ${{ matrix.config.os }} 10 | strategy: 11 | fail-fast: false 12 | matrix: 13 | config: 14 | - { os: windows-2019, vs: "Visual Studio 2019" } # https://github.com/actions/virtual-environments/blob/main/images/win/Windows2019-Readme.md#visual-studio-enterprise-2019 15 | - { os: windows-2022, vs: "Visual Studio 2022" } # https://github.com/actions/virtual-environments/blob/main/images/win/Windows2022-Readme.md#visual-studio-enterprise-2022 16 | 17 | name: "${{ matrix.config.vs }}" 18 | steps: 19 | - uses: actions/checkout@v4 20 | 21 | - name: Build Win32 22 | shell: bash 23 | run: | 24 | rm -rf build 25 | mkdir build 26 | cd build 27 | cmake .. -A Win32 28 | cmake --build . -j 4 --config Release 29 | ctest --output-on-failure -C Release 30 | cmake --build . -j 4 --config Debug 31 | ctest --output-on-failure -C Debug 32 | 33 | - name: Build x64 34 | shell: bash 35 | run: | 36 | rm -rf build 37 | mkdir build 38 | cd build 39 | cmake .. -A x64 40 | cmake --build . -j 4 --config Release 41 | ctest --output-on-failure -C Release 42 | cmake --build . -j 4 --config Debug 43 | ctest --output-on-failure -C Debug 44 | 45 | - name: Bazel Test 46 | working-directory: test 47 | run: bazelisk test //... --config=ci 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build*/ 2 | cmake_build*/ 3 | install_dir/ 4 | .vscode/ 5 | .vs/ 6 | 7 | ### C++ gitignore ### 8 | # Prerequisites 9 | *.d 10 | 11 | # Compiled Object files 12 | *.slo 13 | *.lo 14 | *.o 15 | *.obj 16 | 17 | # Precompiled Headers 18 | *.gch 19 | *.pch 20 | 21 | # Compiled Dynamic libraries 22 | *.so 23 | *.dylib 24 | *.dll 25 | 26 | # Fortran module files 27 | *.mod 28 | *.smod 29 | 30 | # Compiled Static libraries 31 | *.lai 32 | *.la 33 | *.a 34 | *.lib 35 | 36 | # Executables 37 | *.exe 38 | *.out 39 | *.app 40 | 41 | ### CMake gitignore ### 42 | CMakeLists.txt.user 43 | CMakeCache.txt 44 | CMakeFiles 45 | CMakeScripts 46 | Testing 47 | Makefile 48 | cmake_install.cmake 49 | install_manifest.txt 50 | compile_commands.json 51 | CTestTestfile.cmake 52 | _deps 53 | 54 | ### Bazel build artifacts ### 55 | /bazel-* 56 | /test/bazel-* 57 | -------------------------------------------------------------------------------- /BUILD.bazel: -------------------------------------------------------------------------------- 1 | licenses(["notice"]) 2 | 3 | exports_files(["LICENSE"]) 4 | 5 | package(default_visibility = ["//visibility:public"]) 6 | 7 | cc_library( 8 | name = "magic_enum", 9 | hdrs = glob(["include/magic_enum/*.hpp"]), 10 | includes = ["include"], 11 | ) 12 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | 3 | project( 4 | magic_enum 5 | VERSION "0.9.7" 6 | HOMEPAGE_URL "https://github.com/Neargye/magic_enum" 7 | DESCRIPTION 8 | "A library that provides static reflection for enums, work with any enum type without any macro or boilerplate code." 9 | LANGUAGES CXX 10 | ) 11 | set(CPACK_PACKAGE_VENDOR "Daniil Goncharov") 12 | 13 | include(GNUInstallDirs) 14 | 15 | set(ADDITIONAL_MODULES_DIR "${CMAKE_CURRENT_LIST_DIR}/cmake") 16 | list(APPEND CMAKE_MODULE_PATH "${ADDITIONAL_MODULES_DIR}") 17 | 18 | if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) 19 | set(IS_TOPLEVEL_PROJECT TRUE) 20 | else() 21 | set(IS_TOPLEVEL_PROJECT FALSE) 22 | endif() 23 | 24 | option(MAGIC_ENUM_OPT_BUILD_EXAMPLES "Build magic_enum examples" ${IS_TOPLEVEL_PROJECT}) 25 | option(MAGIC_ENUM_OPT_BUILD_TESTS "Build and perform magic_enum tests" ${IS_TOPLEVEL_PROJECT}) 26 | option(MAGIC_ENUM_OPT_INSTALL "Generate and install magic_enum target" ${IS_TOPLEVEL_PROJECT}) 27 | option(MAGIC_ENUM_OPT_INSTALL_PACKAGE_XML "Include package.xml when installing" 28 | ${MAGIC_ENUM_OPT_INSTALL} 29 | ) 30 | option(MAGIC_ENUM_OPT_TEST_INSTALLED_VERSION "When configuring tests, try use 31 | a local magic_enum." NO 32 | ) 33 | option(MAGIC_ENUM_OPT_TEST_INSTALLED_VERSION_PKGCONFIG "When configuring tests, try use 34 | a local magic_enum via pkgconfig" NO 35 | ) 36 | 37 | if(${MAGIC_ENUM_OPT_TEST_INSTALLED_VERSION} OR ${MAGIC_ENUM_OPT_TEST_INSTALLED_VERSION_PKGCONFIG}) 38 | add_subdirectory(test) 39 | return() 40 | endif() 41 | 42 | set(INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/include/magic_enum") 43 | set(EXPORT_NAMESPACE "${PROJECT_NAME}::") 44 | 45 | add_library(${PROJECT_NAME} INTERFACE) 46 | add_library(${EXPORT_NAMESPACE}${PROJECT_NAME} ALIAS ${PROJECT_NAME}) 47 | target_include_directories( 48 | ${PROJECT_NAME} INTERFACE $ 49 | $ 50 | ) 51 | 52 | if(MAGIC_ENUM_OPT_BUILD_EXAMPLES) 53 | add_subdirectory(example) 54 | endif() 55 | 56 | if(MAGIC_ENUM_OPT_BUILD_TESTS) 57 | enable_testing() 58 | add_subdirectory(test) 59 | endif() 60 | 61 | if(MAGIC_ENUM_OPT_INSTALL) 62 | list(APPEND CMAKE_MODULE_PATH "${ADDITIONAL_MODULES_DIR}/GenPkgConfig") 63 | include(GenPkgConfig) 64 | include(CPackComponent) 65 | include(CMakePackageConfigHelpers) 66 | 67 | install( 68 | TARGETS "${PROJECT_NAME}" 69 | EXPORT ${PROJECT_NAME} 70 | INCLUDES 71 | DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" 72 | # COMPONENT "${SDK_COMPONENT_NAME}" # component is not allowed for 73 | # includes! 74 | # Headers are installed separately! Includes only marks the headers for 75 | # export 76 | ) 77 | 78 | if(NOT DEFINED PROJECT_INCLUDE_HEADER_PATTERN) 79 | set(PROJECT_INCLUDE_HEADER_PATTERN "*") 80 | endif() 81 | 82 | install( 83 | DIRECTORY ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME} 84 | DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" 85 | FILES_MATCHING 86 | PATTERN "${PROJECT_INCLUDE_HEADER_PATTERN}" 87 | ) 88 | 89 | set(CPACK_PACKAGE_NAME "${PROJECT_NAME}") 90 | set(CPACK_PACKAGE_DESCRIPTION "${PROJECT_DESCRIPTION}") 91 | set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "all") 92 | set(CPACK_DEBIAN_PACKAGE_NAME "libmagicenum-dev") 93 | set(CPACK_RPM_PACKAGE_NAME "libmagicenum-devel") 94 | set(CPACK_PACKAGE_HOMEPAGE_URL "${PROJECT_HOMEPAGE_URL}") 95 | set(CPACK_PACKAGE_MAINTAINER "${CPACK_PACKAGE_VENDOR}") 96 | set(CPACK_DEBIAN_PACKAGE_DEPENDS "") 97 | set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${CPACK_PACKAGE_MAINTAINER}") 98 | set(CPACK_PACKAGE_MAINTAINER "${CPACK_PACKAGE_VENDOR}") 99 | set(CPACK_DEB_COMPONENT_INSTALL ON) 100 | set(CPACK_RPM_COMPONENT_INSTALL ON) 101 | set(CPACK_NSIS_COMPONENT_INSTALL ON) 102 | set(CPACK_DEBIAN_COMPRESSION_TYPE "xz") 103 | 104 | set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") 105 | set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md") 106 | 107 | set(CMAKE_CONFIG_FILE_BASENAME "${PROJECT_NAME}Config.cmake") 108 | set(CMAKE_EXPORT_FILE_BASENAME "${PROJECT_NAME}Export.cmake") 109 | set(CMAKE_CONFIG_VERSION_FILE_BASENAME "${PROJECT_NAME}ConfigVersion.cmake") 110 | set(CMAKE_CONFIG_VERSION_FILE_NAME 111 | "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CONFIG_VERSION_FILE_BASENAME}" 112 | ) 113 | 114 | export( 115 | TARGETS "${PROJECT_NAME}" 116 | NAMESPACE "${EXPORT_NAMESPACE}" 117 | FILE "${CMAKE_EXPORT_FILE_BASENAME}" 118 | EXPORT_LINK_INTERFACE_LIBRARIES 119 | ) 120 | 121 | install( 122 | EXPORT "${PROJECT_NAME}" 123 | FILE "${CMAKE_CONFIG_FILE_BASENAME}" 124 | NAMESPACE "${EXPORT_NAMESPACE}" 125 | DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/cmake/${PROJECT_NAME}" 126 | ) 127 | 128 | write_basic_package_version_file( 129 | "${CMAKE_CONFIG_VERSION_FILE_NAME}" 130 | # VERSION "100500.100500.100500" # any version of same bitness suits. CMake cannot compare to 131 | # infinity, so use a large number we expect to be greater than any future version 132 | VERSION ${_VERSION} 133 | COMPATIBILITY AnyNewerVersion ARCH_INDEPENDENT 134 | ) 135 | install(FILES "${CMAKE_CONFIG_VERSION_FILE_NAME}" 136 | DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/cmake/${PROJECT_NAME}" 137 | ) 138 | 139 | configure_pkg_config_file( 140 | "${PROJECT_NAME}" 141 | NAME 142 | "${PROJECT_NAME}" 143 | VERSION 144 | "${PROJECT_VERSION}" 145 | DESCRIPTION 146 | "${CPACK_PACKAGE_DESCRIPTION}" 147 | URL 148 | "${CPACK_PACKAGE_HOMEPAGE_URL}" 149 | INSTALL_LIB_DIR 150 | "${CMAKE_INSTALL_DATAROOTDIR}" 151 | INSTALL_INCLUDE_DIR 152 | "${CMAKE_INSTALL_INCLUDEDIR}" 153 | ) 154 | 155 | if(MAGIC_ENUM_OPT_INSTALL_PACKAGE_XML) 156 | install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/package.xml 157 | DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME} 158 | ) 159 | endif() 160 | 161 | include(CPack) 162 | endif() 163 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM gentoo/stage3:latest 2 | 3 | RUN echo "Updating Gentoo index registry..." 4 | RUN emerge-webrsync 5 | 6 | 7 | RUN echo "Setting up package manager" 8 | # Allow emerge newer versions of cmake. We need it because vcpkg wants it. 9 | RUN echo "dev-build/cmake ~amd64" >> /etc/portage/package.accept_keywords/unmask 10 | # # Get some packages as binaries and don't compile them. Actually, it allows to not compile only zip :( 11 | # RUN rm -rf /etc/portage/binrepos.conf/* 12 | # RUN echo -e "[binhost]\npriority = 9999\nsync-uri = https://gentoo.osuosl.org/experimental/amd64/binpkg/default/linux/17.1/x86-64/" >> /etc/portage/binrepos.conf/osuosl.conf 13 | # RUN cat /etc/portage/binrepos.conf/* 14 | # Arguments that going to be added automatically to `emerge` command. `man emerge` in help. Or read https://wiki.gentoo.org/wiki/Binary_package_guide/en#Installing_binary_packages . 15 | # RUN echo 'EMERGE_DEFAULT_OPTS="${EMERGE_DEFAULT_OPTS} --binpkg-respect-use=y --getbinpkg=y --verbose --verbose-conflicts "' >> /etc/portage/make.conf 16 | 17 | RUN echo "Installing dependencies..." 18 | 19 | RUN emerge --quiet --verbose --tree --verbose-conflicts --jobs=2 dev-vcs/git dev-build/cmake zip 20 | 21 | # RUN echo "Installing vcpkg..." 22 | # RUN git clone https://github.com/Microsoft/vcpkg.git && \ 23 | # ./vcpkg/bootstrap-vcpkg.sh -disableMetrics 24 | # 25 | # COPY ./vcpkg.json ./vcpkg.json 26 | # 27 | # RUN echo "Installing dependencies using vcpkg" 28 | # RUN ./vcpkg/vcpkg install 29 | 30 | WORKDIR /backend 31 | 32 | RUN echo "Copy sources of the project" 33 | COPY . . 34 | RUN ls -lah 35 | 36 | # expected to be mounted at runtime as volume. 37 | # COPY resources/ ./resources/ 38 | 39 | 40 | RUN echo "Configuring project..." 41 | RUN cmake -S ./ -B ./build --log-level DEBUG 42 | 43 | 44 | # RUN echo "Building project..." 45 | # RUN cmake --build ./build --parallel $(nproc) --verbose 46 | 47 | RUN echo "really installing" 48 | RUN cmake --install ./build 49 | 50 | RUN echo "checking cmake-cmake" 51 | RUN cmake -S. -B build2 -DMAGIC_ENUM_OPT_TEST_INSTALLED_VERSION=1 --log-level=DEBUG 52 | RUN cmake --build build2 -j $(nproc) --verbose 53 | 54 | RUN echo "checking pkgconfig-cmake" 55 | RUN cat "/usr/local/share/pkgconfig/magic_enum.pc" 56 | RUN cmake -S. -B build3 -DMAGIC_ENUM_OPT_TEST_INSTALLED_VERSION_PKGCONFIG=1 --log-level=DEBUG 57 | RUN cmake --build build3 -j $(nproc) --verbose 58 | 59 | 60 | 61 | # RUN echo "what's with linking?" 62 | # RUN ls -lahR /usr/local/lib64 63 | # RUN lddtree /usr/local/lib64/libArby.so 64 | # RUN lddtree /usr/local/bin/Arby 65 | 66 | # CMD ./build/Backend 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 - 2024 Daniil Goncharov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MODULE.bazel: -------------------------------------------------------------------------------- 1 | module( 2 | name = "magic_enum", 3 | version = "0.9.7", 4 | compatibility_level = 0, 5 | ) 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Github releases](https://img.shields.io/github/release/Neargye/magic_enum.svg)](https://github.com/Neargye/magic_enum/releases) 2 | [![Conan package](https://img.shields.io/badge/Conan-package-blueviolet)](https://conan.io/center/recipes/magic_enum) 3 | [![Vcpkg package](https://img.shields.io/badge/Vcpkg-package-blueviolet)](https://github.com/microsoft/vcpkg/tree/master/ports/magic-enum) 4 | [![Build2 package](https://img.shields.io/badge/Build2-package-blueviolet)](https://www.cppget.org/magic_enum?q=magic_enum) 5 | [![Meson wrap](https://img.shields.io/badge/Meson-wrap-blueviolet)](https://github.com/mesonbuild/wrapdb/blob/master/subprojects/magic_enum.wrap) 6 | [![License](https://img.shields.io/github/license/Neargye/magic_enum.svg)](LICENSE) 7 | [![Compiler explorer](https://img.shields.io/badge/compiler_explorer-online-blue.svg)](https://godbolt.org/z/feqcPa5G6) 8 | [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/Neargye/magic_enum/badge)](https://securityscorecards.dev/viewer/?uri=github.com/Neargye/magic_enum) 9 | [![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua) 10 | 11 | # Magic Enum C++ 12 | 13 | Header-only C++17 library provides static reflection for enums, work with any enum type without any macro or boilerplate code. 14 | 15 | If you like this project, please consider donating to one of the funds that help victims of the war in Ukraine: https://u24.gov.ua. 16 | 17 | ## Documentation 18 | 19 | * [Reference](doc/reference.md) 20 | * [Limitations](doc/limitations.md) 21 | * [Integration](#Integration) 22 | 23 | ## [Features & Examples](example/) 24 | 25 | * Basic 26 | 27 | ```cpp 28 | #include 29 | #include 30 | 31 | enum class Color : { RED = -10, BLUE = 0, GREEN = 10 }; 32 | 33 | int main() { 34 | Color c1 = Color::RED; 35 | std::cout << magic_enum::enum_name(c1) << std::endl; // RED 36 | return 0; 37 | } 38 | ``` 39 | 40 | * Enum value to string 41 | 42 | ```cpp 43 | Color color = Color::RED; 44 | auto color_name = magic_enum::enum_name(color); 45 | // color_name -> "RED" 46 | ``` 47 | 48 | * String to enum value 49 | 50 | ```cpp 51 | std::string color_name{"GREEN"}; 52 | auto color = magic_enum::enum_cast(color_name); 53 | if (color.has_value()) { 54 | // color.value() -> Color::GREEN 55 | } 56 | 57 | // case insensitive enum_cast 58 | auto color = magic_enum::enum_cast(value, magic_enum::case_insensitive); 59 | 60 | // enum_cast with BinaryPredicate 61 | auto color = magic_enum::enum_cast(value, [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); } 62 | 63 | // enum_cast with default 64 | auto color_or_default = magic_enum::enum_cast(value).value_or(Color::NONE); 65 | ``` 66 | 67 | * Integer to enum value 68 | 69 | ```cpp 70 | int color_integer = 2; 71 | auto color = magic_enum::enum_cast(color_integer); 72 | if (color.has_value()) { 73 | // color.value() -> Color::BLUE 74 | } 75 | 76 | auto color_or_default = magic_enum::enum_cast(value).value_or(Color::NONE); 77 | ``` 78 | 79 | * Indexed access to enum value 80 | 81 | ```cpp 82 | std::size_t i = 0; 83 | Color color = magic_enum::enum_value(i); 84 | // color -> Color::RED 85 | ``` 86 | 87 | * Enum value sequence 88 | 89 | ```cpp 90 | constexpr auto colors = magic_enum::enum_values(); 91 | // colors -> {Color::RED, Color::BLUE, Color::GREEN} 92 | // colors[0] -> Color::RED 93 | ``` 94 | 95 | * Number of enum elements 96 | 97 | ```cpp 98 | constexpr std::size_t color_count = magic_enum::enum_count(); 99 | // color_count -> 3 100 | ``` 101 | 102 | * Enum value to integer 103 | 104 | ```cpp 105 | Color color = Color::RED; 106 | auto color_integer = magic_enum::enum_integer(color); // or magic_enum::enum_underlying(color); 107 | // color_integer -> 1 108 | ``` 109 | 110 | * Enum names sequence 111 | 112 | ```cpp 113 | constexpr auto color_names = magic_enum::enum_names(); 114 | // color_names -> {"RED", "BLUE", "GREEN"} 115 | // color_names[0] -> "RED" 116 | ``` 117 | 118 | * Enum entries sequence 119 | 120 | ```cpp 121 | constexpr auto color_entries = magic_enum::enum_entries(); 122 | // color_entries -> {{Color::RED, "RED"}, {Color::BLUE, "BLUE"}, {Color::GREEN, "GREEN"}} 123 | // color_entries[0].first -> Color::RED 124 | // color_entries[0].second -> "RED" 125 | ``` 126 | 127 | * Enum fusion for multi-level switch/case statements 128 | 129 | ```cpp 130 | switch (magic_enum::enum_fuse(color, direction).value()) { 131 | case magic_enum::enum_fuse(Color::RED, Directions::Up).value(): // ... 132 | case magic_enum::enum_fuse(Color::BLUE, Directions::Down).value(): // ... 133 | // ... 134 | } 135 | ``` 136 | 137 | * Enum switch runtime value as constexpr constant 138 | ```cpp 139 | Color color = Color::RED; 140 | magic_enum::enum_switch([] (auto val) { 141 | constexpr Color c_color = val; 142 | // ... 143 | }, color); 144 | ``` 145 | 146 | * Enum iterate for each enum as constexpr constant 147 | ```cpp 148 | magic_enum::enum_for_each([] (auto val) { 149 | constexpr Color c_color = val; 150 | // ... 151 | }); 152 | ``` 153 | 154 | * Check if enum contains 155 | 156 | ```cpp 157 | magic_enum::enum_contains(Color::GREEN); // -> true 158 | magic_enum::enum_contains(2); // -> true 159 | magic_enum::enum_contains(123); // -> false 160 | magic_enum::enum_contains("GREEN"); // -> true 161 | magic_enum::enum_contains("fda"); // -> false 162 | ``` 163 | 164 | * Enum index in sequence 165 | 166 | ```cpp 167 | constexpr auto color_index = magic_enum::enum_index(Color::BLUE); 168 | // color_index.value() -> 1 169 | // color_index.has_value() -> true 170 | ``` 171 | 172 | * Functions for flags 173 | 174 | ```cpp 175 | enum Directions : std::uint64_t { 176 | Left = 1, 177 | Down = 2, 178 | Up = 4, 179 | Right = 8, 180 | }; 181 | template <> 182 | struct magic_enum::customize::enum_range { 183 | static constexpr bool is_flags = true; 184 | }; 185 | 186 | magic_enum::enum_flags_name(Directions::Up | Directions::Right); // -> "Directions::Up|Directions::Right" 187 | magic_enum::enum_flags_contains(Directions::Up | Directions::Right); // -> true 188 | magic_enum::enum_flags_cast(3); // -> "Directions::Left|Directions::Down" 189 | ``` 190 | 191 | * Enum type name 192 | 193 | ```cpp 194 | Color color = Color::RED; 195 | auto type_name = magic_enum::enum_type_name(); 196 | // type_name -> "Color" 197 | ``` 198 | 199 | * IOstream operator for enum 200 | 201 | ```cpp 202 | using magic_enum::iostream_operators::operator<<; // out-of-the-box ostream operators for enums. 203 | Color color = Color::BLUE; 204 | std::cout << color << std::endl; // "BLUE" 205 | ``` 206 | 207 | ```cpp 208 | using magic_enum::iostream_operators::operator>>; // out-of-the-box istream operators for enums. 209 | Color color; 210 | std::cin >> color; 211 | ``` 212 | 213 | * Bitwise operator for enum 214 | 215 | ```cpp 216 | enum class Flags { A = 1 << 0, B = 1 << 1, C = 1 << 2, D = 1 << 3 }; 217 | using namespace magic_enum::bitwise_operators; // out-of-the-box bitwise operators for enums. 218 | // Support operators: ~, |, &, ^, |=, &=, ^=. 219 | Flags flags = Flags::A | Flags::B & ~Flags::C; 220 | ``` 221 | 222 | * Checks whether type is an [Unscoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Unscoped_enumeration). 223 | 224 | ```cpp 225 | enum color { red, green, blue }; 226 | enum class direction { left, right }; 227 | 228 | magic_enum::is_unscoped_enum::value -> true 229 | magic_enum::is_unscoped_enum::value -> false 230 | magic_enum::is_unscoped_enum::value -> false 231 | 232 | // Helper variable template. 233 | magic_enum::is_unscoped_enum_v -> true 234 | ``` 235 | 236 | * Checks whether type is an [Scoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Scoped_enumerations). 237 | 238 | ```cpp 239 | enum color { red, green, blue }; 240 | enum class direction { left, right }; 241 | 242 | magic_enum::is_scoped_enum::value -> false 243 | magic_enum::is_scoped_enum::value -> true 244 | magic_enum::is_scoped_enum::value -> false 245 | 246 | // Helper variable template. 247 | magic_enum::is_scoped_enum_v -> true 248 | ``` 249 | 250 | * Static storage enum variable to string 251 | This version is much lighter on the compile times and is not restricted to the enum_range [limitation](doc/limitations.md). 252 | 253 | ```cpp 254 | constexpr Color color = Color::BLUE; 255 | constexpr auto color_name = magic_enum::enum_name(); 256 | // color_name -> "BLUE" 257 | ``` 258 | 259 | * `containers::array` array container for enums. 260 | 261 | ```cpp 262 | magic_enum::containers::array color_rgb_array {}; 263 | color_rgb_array[Color::RED] = {255, 0, 0}; 264 | color_rgb_array[Color::GREEN] = {0, 255, 0}; 265 | color_rgb_array[Color::BLUE] = {0, 0, 255}; 266 | magic_enum::containers::get(color_rgb_array) // -> RGB{0, 0, 255} 267 | ``` 268 | 269 | * `containers::bitset` bitset container for enums. 270 | 271 | ```cpp 272 | constexpr magic_enum::containers::bitset color_bitset_red_green {Color::RED|Color::GREEN}; 273 | bool all = color_bitset_red_green.all(); 274 | // all -> false 275 | // Color::BLUE is missing 276 | bool test = color_bitset_red_green.test(Color::RED); 277 | // test -> true 278 | ``` 279 | 280 | * `containers::set` set container for enums. 281 | 282 | ```cpp 283 | auto color_set = magic_enum::containers::set(); 284 | bool empty = color_set.empty(); 285 | // empty -> true 286 | color_set.insert(Color::GREEN); 287 | color_set.insert(Color::BLUE); 288 | color_set.insert(Color::RED); 289 | std::size_t size = color_set.size(); 290 | // size -> 3 291 | ``` 292 | 293 | * Improved UB-free "SFINAE-friendly" [underlying_type](https://en.cppreference.com/w/cpp/types/underlying_type). 294 | 295 | ```cpp 296 | magic_enum::underlying_type::type -> int 297 | 298 | // Helper types. 299 | magic_enum::underlying_type_t -> int 300 | ``` 301 | ## Remarks 302 | 303 | * `magic_enum` does not pretend to be a silver bullet for reflection for enums, it was originally designed for small enum. 304 | 305 | * Before use, read the [limitations](doc/limitations.md) of functionality. 306 | 307 | ## Integration 308 | 309 | * You should add the required file [magic_enum.hpp](include/magic_enum/magic_enum.hpp), and optionally other headers from [include dir](include/) or [release archive](https://github.com/Neargye/magic_enum/releases/latest). Alternatively, you can build the library with CMake. 310 | 311 | * If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project for external dependencies, then you can use the [magic-enum package](https://github.com/microsoft/vcpkg/tree/master/ports/magic-enum). 312 | 313 | * If you are using [Conan](https://www.conan.io/) to manage your dependencies, merely add `magic_enum/x.y.z` to your conan's requires, where `x.y.z` is the release version you want to use. 314 | 315 | * If you are using [Build2](https://build2.org/) to build and manage your dependencies, add `depends: magic_enum ^x.y.z` to the manifest file where `x.y.z` is the release version you want to use. You can then import the target using `magic_enum%lib{magic_enum}`. 316 | 317 | * Alternatively, you can use something like [CPM](https://github.com/TheLartians/CPM) which is based on CMake's `Fetch_Content` module. 318 | 319 | ```cmake 320 | CPMAddPackage( 321 | NAME magic_enum 322 | GITHUB_REPOSITORY Neargye/magic_enum 323 | GIT_TAG x.y.z # Where `x.y.z` is the release version you want to use. 324 | ) 325 | ``` 326 | 327 | * Bazel is also supported, simply add to your WORKSPACE file: 328 | 329 | ``` 330 | http_archive( 331 | name = "magic_enum", 332 | strip_prefix = "magic_enum-", 333 | urls = ["https://github.com/Neargye/magic_enum/archive/.zip"], 334 | ) 335 | ``` 336 | 337 | To use bazel inside the repository it's possible to do: 338 | 339 | ``` 340 | bazel build //... 341 | bazel test //... 342 | bazel run //example 343 | ``` 344 | 345 | (Note that you must use a supported compiler or specify it with `export CC= `.) 346 | 347 | * If you are using [Ros](https://www.ros.org/), you can include this package by adding `magic_enum` to your package.xml and include this package in your workspace. In your CMakeLists.txt add the following: 348 | ```cmake 349 | find_package(magic_enum CONFIG REQUIRED) 350 | ... 351 | target_link_libraries(your_executable magic_enum::magic_enum) 352 | ``` 353 | 354 | ## Compiler compatibility 355 | 356 | * Clang/LLVM >= 5 357 | * MSVC++ >= 14.11 / Visual Studio >= 2017 358 | * Xcode >= 10 359 | * GCC >= 9 360 | * MinGW >= 9 361 | 362 | ## Licensed under the [MIT License](LICENSE) 363 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Security updates are applied only to the latest release. 6 | 7 | ## Reporting a Vulnerability 8 | 9 | If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released. 10 | 11 | Please disclose it at [security advisory](https://github.com/Neargye/magic_enum/security/advisories/new). 12 | 13 | This project is maintained by a team of volunteers on a reasonable-effort basis. As such, vulnerabilities will be disclosed in a best effort base. 14 | -------------------------------------------------------------------------------- /WORKSPACE.bazel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Neargye/magic_enum/a413fcc9c46a020a746907136a384c227f3cd095/WORKSPACE.bazel -------------------------------------------------------------------------------- /cmake/GenPkgConfig/GenPkgConfig.cmake: -------------------------------------------------------------------------------- 1 | #[=======================================================================[.rst: 2 | 3 | GenPkgConfig 4 | ------------ 5 | 6 | This is the library helping you to generate and install pkg-config files. 7 | 8 | Unlicense 9 | ^^^^^^^^^ 10 | 11 | This is free and unencumbered software released into the public domain. 12 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. 13 | In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | For more information, please refer to 16 | 17 | Warning 18 | ^^^^^^^ 19 | 20 | CMake is currently merging a built-in impl of pkg-config file generator! https://gitlab.kitware.com/cmake/cmake/-/merge_requests/6363 21 | 22 | Functions 23 | ^^^^^^^^^ 24 | .. command:: configure_pkg_config_file 25 | 26 | .. versionadded:: 3.22 27 | 28 | Generates a pkg-config file for 29 | 30 | :: 31 | 32 | configure_pkg_config_file( 33 | NAME 34 | VERSION 35 | DESCRIPTION 36 | URL 37 | COMPONENT 38 | INSTALL_LIB_DIR 39 | INSTALL_INCLUDE_DIR 40 | REQUIRES ... ... 41 | REQUIRES ... ... 42 | ) 43 | 44 | The arguments are optional and usually are not needed to be set if global (not component-specific) CPACK vars have been set before. 45 | 46 | Generation is done in build time using packaging expressions. 47 | 48 | #]=======================================================================] 49 | 50 | set("GEN_PKG_CONFIG_WORKAROUNDS_BUILD_TIME_SCRIPTS" "${CMAKE_CURRENT_LIST_DIR}/buildTimeScripts") 51 | 52 | cmake_policy(SET CMP0070 NEW) 53 | 54 | function(configure_pkg_config_file TARGET) 55 | cmake_parse_arguments("" 56 | "" # options 57 | "NAME;VERSION;DESCRIPTION;URL;COMPONENT;INSTALL_LIB_DIR;INSTALL_INCLUDE_DIR" # one_value_keywords 58 | "REQUIRES;CONFLICTS" # multi_value_keywords 59 | ${ARGN} 60 | ) 61 | 62 | configure_pkg_config_file_vars("${TARGET}" "${_NAME}" "${_INSTALL_LIB_DIR}" "${_INSTALL_INCLUDE_DIR}" "${_COMPONENT}" "${_DESCRIPTION}" "${_URL}" "${_VERSION}" "${_REQUIRES}" "${_CONFLICTS}") 63 | endfunction() 64 | 65 | function(ge_expr_basename inputExpr outVar) 66 | set("${outVar}" "$" PARENT_SCOPE) 67 | endfunction() 68 | 69 | function(configure_pkg_config_file_vars TARGET _NAME _INSTALL_LIB_DIR _INSTALL_INCLUDE_DIR _COMPONENT _DESCRIPTION _URL _VERSION _REQUIRES _CONFLICTS) 70 | #$ 71 | #INTERFACE_LINK_DIRECTORIES 72 | #INTERFACE_LINK_LIBRARIES 73 | #INTERFACE_LINK_OPTIONS 74 | 75 | if(_NAME) 76 | else() 77 | set(_NAME "$") 78 | endif() 79 | 80 | if(_DESCRIPTION) 81 | else() 82 | set(_DESCRIPTION "${CPACK_PACKAGE_DESCRIPTION}") 83 | endif() 84 | 85 | if(_VERSION) 86 | else() 87 | set(_VERSION "${CPACK_PACKAGE_VERSION}") 88 | endif() 89 | 90 | if(_URL) 91 | else() 92 | set(_URL "${CPACK_PACKAGE_HOMEPAGE_URL}") 93 | endif() 94 | 95 | if(INSTALL_INCLUDE_DIR) 96 | else() 97 | set(INSTALL_INCLUDE_DIR "${CMAKE_INSTALL_INCLUDEDIR}") 98 | endif() 99 | 100 | if(INSTALL_LIB_DIR) 101 | else() 102 | set(INSTALL_LIB_DIR "${CMAKE_INSTALL_LIBDIR}") 103 | endif() 104 | 105 | set(PKG_CONFIG_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/${_NAME}.pc") 106 | 107 | set(PUBLIC_INCLUDES "$") 108 | set(PUBLIC_LIBS "$") 109 | set(PUBLIC_COMPILE_FLAGS "$") 110 | 111 | set("IS_INTERFACE" "$,INTERFACE_LIBRARY>") 112 | set("IS_OBJECT" "$,OBJECT_LIBRARY>") 113 | get_target_property(CONFIGURE_TIME_TARGET_TYPE "${TARGET}" TYPE) 114 | if(CONFIGURE_TIME_TARGET_TYPE STREQUAL OBJECT_LIBRARY) 115 | set(CONFIGURE_TIME_IS_OBJECT ON) # Special measures have to be taken!!! 116 | endif() 117 | 118 | set("NEEDS_LIBS" "$,$>") 119 | set("NEEDS_LIB_DIR" "$") 120 | string(REPLACE "," "$" NEEDS_LIBS_ESCAPED "${NEEDS_LIBS}") 121 | string(REPLACE ">" "$" NEEDS_LIBS_ESCAPED "${NEEDS_LIBS_ESCAPED}") 122 | 123 | # Only use prefix if paths are not absolute like they are with nix 124 | # See also: https://github.com/NixOS/nixpkgs/issues/144170 125 | if(NOT(IS_ABSOLUTE ${INSTALL_LIB_DIR} AND IS_ABSOLUTE ${INSTALL_INCLUDE_DIR})) 126 | list(APPEND header "prefix=${CMAKE_INSTALL_PREFIX}") 127 | endif() 128 | 129 | if(IS_ABSOLUTE ${INSTALL_LIB_DIR}) 130 | list(APPEND header "$,${NEEDS_LIB_DIR}>,libdir=${INSTALL_LIB_DIR},>") 131 | else() 132 | list(APPEND header "$,${NEEDS_LIB_DIR}>,libdir=\${prefix}/${INSTALL_LIB_DIR},>") 133 | endif() 134 | 135 | if(IS_ABSOLUTE ${INSTALL_INCLUDE_DIR}) 136 | list(APPEND header "$,includedir=${INSTALL_INCLUDE_DIR},>") 137 | else() 138 | list(APPEND header "$,includedir=\${prefix}/${INSTALL_INCLUDE_DIR},>") 139 | endif() 140 | 141 | list(APPEND libSpecific "Name: ${_NAME}") 142 | if(_DESCRIPTION) 143 | list(APPEND libSpecific "Description: ${_DESCRIPTION}") 144 | endif() 145 | if(_URL) 146 | list(APPEND libSpecific "URL: ${_URL}") 147 | endif() 148 | if(_VERSION) 149 | list(APPEND libSpecific "Version: ${_VERSION}") 150 | endif() 151 | if(_REQUIRES) 152 | list(APPEND libSpecific "Requires: ${_REQUIRES}") 153 | endif() 154 | if(_CONFLICTS) 155 | list(APPEND libSpecific "Conflicts: ${_CONFLICTS}") 156 | endif() 157 | 158 | set(OTHER_INCLUDE_FLAGS "-I$, -I>") # Not needed, we can only get build interface flags here. Insert them after -I\${includedir} if you find a way to fix/workaround it 159 | 160 | # Here is a workaround to inability to use TARGET_LINKER_FILE_NAME for targets not involving library generation. 161 | # Strangely $<") # A hack because there is no escape for `$` or `<` or `$<`. So we just disrupt $< into pieces 166 | set(CURRENT_LIB_ESCAPED_BINARY_NAME "${ESCAPED_GENEXPR_BEGINNING}TARGET_LINKER_FILE_NAME:${TARGET}$") 167 | set(LINK_CURRENT_LIB_FLAG "$>") 168 | 169 | if(CONFIGURE_TIME_IS_OBJECT) 170 | set(IS_TARGET_OBJECTS_CONFIGURE_TIME_UNAVAILABLE ON) 171 | if(IS_TARGET_OBJECTS_CONFIGURE_TIME_UNAVAILABLE) 172 | message(WARNING "CMake is shit: There is (at least was at the time of writing of this code) no generator expression to get only basenames of object files. They are also unavailable at configure stage. And there were no CMake generator expressions for making replacements in strings. So we workaround this.") 173 | set(TARGET_OBJECTS_FILE "${TARGET}.obj_list") 174 | set(OBJECTS_FILE_RETRIEVAL_TARGET_NAME "${TARGET}_get_objects_list") 175 | 176 | set(PKGCONFIG_DUMMY_UNFINISHED_GEN_TARGET_NAME "${TARGET}_pkgconfig_unfinished") 177 | set(PKGCONFIG_PATCH_TARGET_NAME "${TARGET}_patch_pkgconfig") 178 | 179 | set(PKG_CONFIG_FILE_NAME_FINISHED "${PKG_CONFIG_FILE_NAME}") 180 | set(PKG_CONFIG_FILE_NAME_UNFINISHED "${PKG_CONFIG_FILE_NAME_FINISHED}.unfinished") 181 | 182 | file(GENERATE OUTPUT "${TARGET_OBJECTS_FILE}" CONTENT "$") 183 | 184 | add_custom_command( 185 | OUTPUT "${TARGET_OBJECTS_FILE}" 186 | COMMENT "A dummy command to workaround cmake limitations" 187 | ) 188 | add_custom_target("${OBJECTS_FILE_RETRIEVAL_TARGET_NAME}" 189 | DEPENDS "${TARGET_OBJECTS_FILE}" 190 | ) 191 | 192 | add_custom_command( 193 | OUTPUT "${PKG_CONFIG_FILE_NAME_FINISHED}" 194 | PRE_BUILD COMMAND ${CMAKE_COMMAND} "-DobjectsFile=\"${TARGET_OBJECTS_FILE}\"" "-DpkgConfigFileUnlinished=\"${PKG_CONFIG_FILE_NAME_UNFINISHED}\"" "-DpkgConfigFileFinal=\"${PKG_CONFIG_FILE_NAME_FINISHED}\"" "-P" "${GEN_PKG_CONFIG_WORKAROUNDS_BUILD_TIME_SCRIPTS}/getObjectFilesBaseNames.cmake" 195 | MAIN_DEPENDENCY "${TARGET_OBJECTS_FILE}" 196 | DEPENDS "${PKG_CONFIG_FILE_NAME_UNFINISHED}" 197 | COMMENT "Working around CMake limitations about getting list of basenames of object files and about lack of generator expressions to modify strings: ${PKG_CONFIG_FILE_NAME_UNFINISHED} + ${TARGET_OBJECTS_FILE} -> ${PKG_CONFIG_FILE_NAME_FINISHED}" 198 | ) 199 | add_custom_target("${PKGCONFIG_PATCH_TARGET_NAME}" ALL 200 | DEPENDS "${PKG_CONFIG_FILE_NAME_FINISHED}" 201 | ) 202 | add_dependencies("${PKGCONFIG_PATCH_TARGET_NAME}" "${OBJECTS_FILE_RETRIEVAL_TARGET_NAME}" "${PKGCONFIG_DUMMY_UNFINISHED_GEN_TARGET_NAME}") 203 | 204 | set(PROPERLY_JOINED_TARGET_OBJECTS "@PROPERLY_JOINED_TARGET_OBJECTS@") 205 | else() 206 | set("RAW_TARGET_OBJECTS" "$") 207 | message(FATAL_ERROR "This branch is unimplemented because CMake lacked the needed functionality at the time") 208 | set(PROPERLY_JOINED_TARGET_OBJECTS "${RAW_TARGET_OBJECTS}") 209 | endif() 210 | endif() 211 | 212 | set(LINK_CURRENT_OBJECT_FLAG "$") 213 | 214 | list(APPEND libSpecific "$,${NEEDS_LIBS},${IS_OBJECT}>,Libs: -L\${libdir} ${LINK_CURRENT_LIB_FLAG} ${LINK_CURRENT_OBJECT_FLAG} $,-l$, -l>,>,>\n$,$>,Cflags: -I\${includedir} $,>,>") 215 | 216 | 217 | list(JOIN header "\n" header) 218 | list(JOIN libSpecific "\n" libSpecific) 219 | set(libSpecific "${header}\n\n${libSpecific}") 220 | 221 | if(CONFIGURE_TIME_IS_OBJECT) 222 | file(GENERATE OUTPUT "${PKG_CONFIG_FILE_NAME_UNFINISHED}" 223 | CONTENT "${libSpecific}" 224 | ) 225 | 226 | # Dummy target for generated files 227 | add_custom_command( 228 | OUTPUT "${PKG_CONFIG_FILE_NAME_UNFINISHED}" 229 | COMMENT "A dummy command to workaround cmake limitations" 230 | ) 231 | add_custom_target("${PKGCONFIG_DUMMY_UNFINISHED_GEN_TARGET_NAME}" 232 | DEPENDS "${PKG_CONFIG_FILE_NAME_UNFINISHED}" 233 | ) 234 | 235 | 236 | install(FILES "${PKG_CONFIG_FILE_NAME_FINISHED}" 237 | DESTINATION "${_INSTALL_LIB_DIR}/pkgconfig" 238 | COMPONENT "${_COMPONENT}" 239 | ) 240 | else() 241 | file(GENERATE OUTPUT "${PKG_CONFIG_FILE_NAME}" 242 | CONTENT "${libSpecific}" 243 | ) 244 | 245 | 246 | install(FILES "${PKG_CONFIG_FILE_NAME}" 247 | DESTINATION "${_INSTALL_LIB_DIR}/pkgconfig" 248 | COMPONENT "${_COMPONENT}" 249 | ) 250 | endif() 251 | endfunction() 252 | 253 | -------------------------------------------------------------------------------- /cmake/GenPkgConfig/ReadMe.md: -------------------------------------------------------------------------------- 1 | GenPkgConfig.cmake 2 | =================== 3 | 4 | A script generating pkg-config files. 5 | 6 | WARNING: CMake [is currently merging own built-in pkgconfig generation implementation](https://gitlab.kitware.com/cmake/cmake/-/merge_requests/6363)! 7 | 8 | If you require such a new version of CMake, you probably should use the built-in impl instead. 9 | 10 | Syntax 11 | ------ 12 | 13 | ```cmake 14 | configure_pkg_config_file( 15 | NAME 16 | VERSION 17 | DESCRIPTION 18 | URL 19 | COMPONENT 20 | INSTALL_LIB_DIR 21 | INSTALL_INCLUDE_DIR 22 | REQUIRES ... ... 23 | REQUIRES ... ... 24 | ) 25 | ``` 26 | 27 | Issuees 28 | ------- 29 | 30 | 1. For `OBJECT` targets we have run into big issues. CMake 31 | 1. Doesn't allow to get the list of object files at configure time 32 | 2. Allows to get a list of object files as a generator exression ... 33 | 3. BUT ... the path to them is full, but we need only file name! 34 | 4. CMake doesn't allow to strip directory path via generator expression 35 | 5. ... neither it allows string editing within generator expressions ... 36 | 37 | so ... we have to create a custom target using a custom CMake script executed separately, but ... 38 | 39 | 6. `file(GENERATE` doesn't properly register dependencies 40 | ... so we have to use `add_custom_command` to say CMake that these files are generated 41 | 42 | 7. And CMake `install(FILES` doesn't mean that the targets generating these files are automatically executed, 43 | 44 | So we have to use `ALL` in `add_custom_target`. 45 | 46 | -------------------------------------------------------------------------------- /cmake/GenPkgConfig/UNLICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /cmake/GenPkgConfig/buildTimeScripts/getObjectFilesBaseNames.cmake: -------------------------------------------------------------------------------- 1 | 2 | message(STATUS "objectsFile ${objectsFile}") 3 | message(STATUS "pkgConfigFileFinal ${pkgConfigFileFinal}") 4 | message(STATUS "pkgConfigFileUnlinished ${pkgConfigFileUnlinished}") 5 | 6 | file(READ "${objectsFile}" TARGET_OBJECTS) 7 | 8 | set(PROPERLY_JOINED_TARGET_OBJECTS "") 9 | 10 | foreach(objFullPath ${TARGET_OBJECTS}) 11 | get_filename_component(objFullPath "${objFullPath}" NAME) 12 | list(APPEND PROPERLY_JOINED_TARGET_OBJECTS "${objFullPath}") 13 | endforeach() 14 | list(JOIN PROPERLY_JOINED_TARGET_OBJECTS " " PROPERLY_JOINED_TARGET_OBJECTS) 15 | 16 | message(STATUS "PROPERLY_JOINED_TARGET_OBJECTS AFTER ${PROPERLY_JOINED_TARGET_OBJECTS}") 17 | 18 | configure_file("${pkgConfigFileUnlinished}" "${pkgConfigFileFinal}" @ONLY) 19 | -------------------------------------------------------------------------------- /doc/limitations.md: -------------------------------------------------------------------------------- 1 | # Limitations 2 | 3 | * This library uses a compiler-specific hack based on `__PRETTY_FUNCTION__` / `__FUNCSIG__`. 4 | 5 | * To check if magic_enum is supported with your compiler, use macro `MAGIC_ENUM_SUPPORTED` or constexpr constant `magic_enum::is_magic_enum_supported`. 6 | If magic_enum is used on an unsupported compiler, a compilation error will occur. 7 | To suppress the error, define macro `MAGIC_ENUM_NO_CHECK_SUPPORT`. 8 | 9 | * magic_enum can't reflect if the enum is a forward declaration. 10 | 11 | ## Enum Flags 12 | 13 | * For enum flags, add `is_flags` to specialization `enum_range` for necessary enum type. Specializations of `enum_range` must be injected in `namespace magic_enum::customize`. 14 | ```cpp 15 | enum class Directions { Up = 1 << 0, Down = 1 << 1, Right = 1 << 2, Left = 1 << 3 }; 16 | template <> 17 | struct magic_enum::customize::enum_range { 18 | static constexpr bool is_flags = true; 19 | }; 20 | ``` 21 | 22 | * `MAGIC_ENUM_RANGE_MAX` / `MAGIC_ENUM_RANGE_MIN` does not affect the maximum number of enum flags. 23 | 24 | * If an enum is declared as a flag enum, its zero value will not be reflected. 25 | 26 | ## Enum Range 27 | 28 | * Enum values must be in the range `[MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX]`. 29 | 30 | * By default, `MAGIC_ENUM_RANGE_MIN = -128`, `MAGIC_ENUM_RANGE_MAX = 127`. 31 | 32 | * If you need a different range for all enum types by default, redefine the macro `MAGIC_ENUM_RANGE_MIN` and `MAGIC_ENUM_RANGE_MAX`: 33 | 34 | ```cpp 35 | #define MAGIC_ENUM_RANGE_MIN 0 36 | #define MAGIC_ENUM_RANGE_MAX 256 37 | #include 38 | ``` 39 | 40 | * If you need a different range for a specific enum type, add the specialization `enum_range` for the enum type. Specializations of `enum_range` must be injected in `namespace magic_enum::customize`. 41 | 42 | ```cpp 43 | #include 44 | 45 | enum class number { one = 100, two = 200, three = 300 }; 46 | 47 | template <> 48 | struct magic_enum::customize::enum_range { 49 | static constexpr int min = 100; 50 | static constexpr int max = 300; 51 | // (max - min) must be less than UINT16_MAX. 52 | }; 53 | ``` 54 | 55 | ## Aliasing 56 | 57 | magic_enum [won't work if a value is aliased](https://github.com/Neargye/magic_enum/issues/68). How magic_enum works with aliases is compiler-implementation-defined. 58 | 59 | ```cpp 60 | enum ShapeKind { 61 | ConvexBegin = 0, 62 | Box = 0, // Won't work. 63 | Sphere = 1, 64 | ConvexEnd = 2, 65 | Donut = 2, // Won't work too. 66 | Banana = 3, 67 | COUNT = 4 68 | }; 69 | // magic_enum::enum_cast("Box") -> nullopt 70 | // magic_enum::enum_name(ShapeKind::Box) -> "ConvexBegin" 71 | ``` 72 | 73 | One possible workaround for the issue is to define the enum values you want reflected before their aliases: 74 | 75 | ```cpp 76 | enum ShapeKind { 77 | // Convex shapes, see ConvexBegin and ConvexEnd below. 78 | Box = 0, 79 | Sphere = 1, 80 | 81 | // Non-convex shapes. 82 | Donut = 2, 83 | Banana = 3, 84 | 85 | COUNT = Banana + 1, 86 | 87 | // Non-reflected aliases. 88 | ConvexBegin = Box, 89 | ConvexEnd = Sphere + 1 90 | }; 91 | // magic_enum::enum_cast("Box") -> ShapeKind::Box 92 | // magic_enum::enum_name(ShapeKind::Box) -> "Box" 93 | 94 | // Non-reflected aliases. 95 | // magic_enum::enum_cast("ConvexBegin") -> nullopt 96 | // magic_enum::enum_name(ShapeKind::ConvexBegin) -> "Box" 97 | ``` 98 | 99 | On some compilers, enum aliases are not supported, [for example Visual Studio 2017](https://github.com/Neargye/magic_enum/issues/36), macro `MAGIC_ENUM_SUPPORTED_ALIASES` will be undefined. 100 | 101 | ```cpp 102 | enum Number { 103 | one = 1, 104 | ONE = 1 105 | }; 106 | // magic_enum::enum_cast("one") -> nullopt 107 | // magic_enum::enum_name(Number::one) -> "" 108 | // magic_enum::enum_cast("ONE") -> nullopt 109 | // magic_enum::enum_name(Number::ONE) -> "" 110 | ``` 111 | 112 | ## Other Compiler Issues 113 | 114 | * If you hit a message like this: 115 | 116 | ```text 117 | [...] 118 | note: constexpr evaluation hit maximum step limit; possible infinite loop? 119 | ``` 120 | 121 | Change the limit for the number of constexpr evaluated: 122 | * MSVC: `/constexpr:depthN`, `/constexpr:stepsN` 123 | * Clang: `-fconstexpr-depth=N`, `-fconstexpr-steps=N` 124 | * GCC: `-fconstexpr-depth=N`, `-fconstexpr-loop-limit=N`, `-fconstexpr-ops-limit=N` 125 | 126 | * Visual Studio's Intellisense may have some problems analyzing magic_enum. 127 | 128 | * Enums in templates may not work correctly (especially on Сlang). 129 | See [#164](https://github.com/Neargye/magic_enum/issues/164), [#65](https://github.com/Neargye/magic_enum/issues/65) 130 | -------------------------------------------------------------------------------- /doc/reference.md: -------------------------------------------------------------------------------- 1 | # Reference 2 | 3 | * [`enum_cast` obtains enum value from string or integer.](#enum_cast) 4 | * [`enum_value` returns enum value at specified index.](#enum_value) 5 | * [`enum_values` obtains enum value sequence.](#enum_values) 6 | * [`enum_count` returns number of enum values.](#enum_count) 7 | * [`enum_integer` obtains integer value from enum value.](#enum_integer) 8 | * [`enum_name` returns name from enum value.](#enum_name) 9 | * [`enum_names` obtains string enum name sequence.](#enum_names) 10 | * [`enum_entries` obtains pair (value enum, string enum name) sequence.](#enum_entries) 11 | * [`enum_index` obtains index in enum value sequence from enum value.](#enum_index) 12 | * [`enum_contains` checks whether enum contains enumerator with such value.](#enum_contains) 13 | * [`enum_reflected` returns true if the enum value is in the range of values that can be reflected..](#enum_reflected) 14 | * [`enum_type_name` returns type name of enum.](#enum_type_name) 15 | * [`enum_fuse` returns a bijective mix of enum values.](#enum_fuse) 16 | * [`enum_switch` allows runtime enum value transformation to constexpr context.](#enum_switch) 17 | * [`enum_for_each` calls a function with all enum constexpr value.](#enum_for_each) 18 | * [`enum_flags_*` functions for flags.](#enum_flags) 19 | * [`is_unscoped_enum` checks whether type is an Unscoped enumeration.](#is_unscoped_enum) 20 | * [`is_scoped_enum` checks whether type is an Scoped enumeration.](#is_scoped_enum) 21 | * [`underlying_type` improved UB-free "SFINAE-friendly" underlying_type.](#underlying_type) 22 | * [`ostream_operators` ostream operators for enums.](#ostream_operators) 23 | * [`istream_operators` istream operators for enums.](#istream_operators) 24 | * [`bitwise_operators` bitwise operators for enums.](#bitwise_operators) 25 | * [`containers::array` array container for enums.](#containersarray) 26 | * [`containers::bitset` bitset container for enums.](#containersbitset) 27 | * [`containers::set` set container for enums.](#containersset) 28 | 29 | ## Synopsis 30 | 31 | * Before use, read the [limitations](limitations.md) of functionality. 32 | 33 | * To check is magic_enum supported compiler use macro `MAGIC_ENUM_SUPPORTED` or constexpr constant `magic_enum::is_magic_enum_supported`.
34 | If magic_enum used on unsupported compiler, occurs the compilation error. To suppress error define macro `MAGIC_ENUM_NO_CHECK_SUPPORT`. 35 | 36 | * To add custom enum or type names see the [example](../example/example_custom_name.cpp). 37 | 38 | * To change the type of strings or optional, use special macros: 39 | 40 | ```cpp 41 | #include 42 | #include 43 | #define MAGIC_ENUM_USING_ALIAS_STRING using string = my_lib::String; 44 | #define MAGIC_ENUM_USING_ALIAS_STRING_VIEW using string_view = my_lib::StringView; 45 | #define MAGIC_ENUM_USING_ALIAS_OPTIONAL template using optional = my_lib::Optional; 46 | #include 47 | ``` 48 | 49 | * Optionally define `MAGIC_ENUM_CONFIG_FILE` i.e., in your build system, with path to header file with defined 50 | macros or constants, for example: 51 | 52 | ```cpp 53 | #define MAGIC_ENUM_CONFIG_FILE "my_magic_enum_cfg.hpp" 54 | ``` 55 | my_magic_enum_cfg.hpp: 56 | ```cpp 57 | #include 58 | #include 59 | #define MAGIC_ENUM_USING_ALIAS_STRING using string = my_lib::String; 60 | #define MAGIC_ENUM_USING_ALIAS_STRING_VIEW using string_view = my_lib::StringView; 61 | #define MAGIC_ENUM_USING_ALIAS_OPTIONAL template using optional = my_lib::Optional; 62 | #define MAGIC_ENUM_RANGE_MIN 0 63 | #define MAGIC_ENUM_RANGE_MAX 255 64 | ``` 65 | 66 | ## `enum_cast` 67 | 68 | ```cpp 69 | template 70 | constexpr optional enum_cast(underlying_type_t value) noexcept; 71 | 72 | template 73 | constexpr optional enum_cast(string_view value) noexcept; 74 | 75 | template 76 | constexpr optional enum_cast(string_view value, BinaryPredicate p) noexcept(is_nothrow_invocable_v); 77 | ``` 78 | 79 | * Defined in header `` 80 | 81 | * Obtains enum value from string or integer. 82 | 83 | * Returns `optional`, using `has_value()` to check contains enum value and `value()` to get the enum value. 84 | 85 | * If argument does not enum value, returns empty `optional`. 86 | 87 | * Examples 88 | 89 | * String to enum value. 90 | 91 | ```cpp 92 | string color_name{"GREEN"}; 93 | auto color = magic_enum::enum_cast(color_name); 94 | if (color.has_value()) { 95 | // color.value() -> Color::GREEN 96 | } 97 | 98 | // case insensitive enum_cast 99 | auto color = magic_enum::enum_cast(value, magic_enum::case_insensitive); 100 | 101 | // enum_cast with BinaryPredicate 102 | auto color = magic_enum::enum_cast(value, [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); } 103 | 104 | // enum_cast with default 105 | auto color_or_default = magic_enum::enum_cast(value).value_or(Color::NONE); 106 | ``` 107 | 108 | * Integer to enum value. 109 | 110 | ```cpp 111 | int color_integer = 2; 112 | auto color = magic_enum::enum_cast(color_integer); 113 | if (color.has_value()) { 114 | // color.value() -> Color::RED 115 | } 116 | 117 | auto color_or_default = magic_enum::enum_cast(value).value_or(Color::NONE); 118 | ``` 119 | 120 | ## `enum_value` 121 | 122 | ```cpp 123 | template 124 | constexpr E enum_value(size_t index) noexcept; 125 | 126 | template 127 | constexpr E enum_value() noexcept; 128 | ``` 129 | 130 | * Defined in header `` 131 | 132 | * Returns enum value at specified index. 133 | * `enum_value(value)` no bounds checking is performed: the behavior is undefined if `index >= number of enum values`. 134 | * `enum_value()` check if `I >= number of enum values`, occurs the compilation error `magic_enum::enum_value out of range`. 135 | 136 | * Examples 137 | 138 | ```cpp 139 | int i = 1; 140 | Color color = magic_enum::enum_value(i); 141 | // color -> Color::BLUE 142 | ``` 143 | 144 | ```cpp 145 | Color color = magic_enum::enum_value(); 146 | // color -> Color::BLUE 147 | ``` 148 | 149 | ## `enum_values` 150 | 151 | ```cpp 152 | template 153 | constexpr array enum_values() noexcept; 154 | ``` 155 | 156 | * Defined in header `` 157 | 158 | * Returns `array` with all enum values where `N = number of enum values`, sorted by enum value. 159 | 160 | * Examples 161 | 162 | ```cpp 163 | constexpr auto colors = magic_enum::enum_values(); 164 | // colors -> {Color::RED, Color::BLUE, Color::GREEN} 165 | // colors[0] -> Color::RED 166 | ``` 167 | 168 | ## `enum_count` 169 | 170 | ```cpp 171 | template 172 | constexpr size_t enum_count() noexcept; 173 | ``` 174 | 175 | * Defined in header `` 176 | 177 | * Returns number of enum values. 178 | 179 | * Examples 180 | 181 | ```cpp 182 | constexpr auto color_count = magic_enum::enum_count(); 183 | // color_count -> 3 184 | ``` 185 | 186 | ## `enum_integer` 187 | 188 | ```cpp 189 | template 190 | constexpr underlying_type_t enum_integer(E value) noexcept; 191 | 192 | template 193 | constexpr underlying_type_t enum_underlying(E value) noexcept; 194 | ``` 195 | 196 | * Defined in header `` 197 | 198 | * Returns integer value from enum value. 199 | 200 | * Examples 201 | 202 | ```cpp 203 | Color color = Color::RED; 204 | auto color_integer = magic_enum::enum_integer(color); 205 | // color -> 2 206 | ``` 207 | 208 | ## `enum_name` 209 | 210 | ```cpp 211 | template 212 | constexpr string_view enum_name(E value) noexcept; 213 | 214 | template 215 | constexpr string_view enum_name() noexcept; 216 | ``` 217 | 218 | * Defined in header `` 219 | 220 | * Returns name from enum value as `string_view` with null-terminated string. 221 | * If enum value does not have name or [out of range](limitations.md), `enum_name(value)` returns empty string. 222 | * If enum value does not have name, `enum_name()` occurs the compilation error `magic_enum::enum_name enum value does not have a name`. 223 | 224 | * `enum_name()` is much lighter on the compile times and is not restricted to the enum_range [limitation](limitations.md). 225 | 226 | * Examples 227 | 228 | ```cpp 229 | Color color = Color::RED; 230 | auto color_name = magic_enum::enum_name(color); 231 | // color_name -> "RED" 232 | ``` 233 | 234 | ```cpp 235 | constexpr Color color = Color::BLUE; 236 | constexpr auto color_name = magic_enum::enum_name(); 237 | // color_name -> "BLUE" 238 | ``` 239 | 240 | ## `enum_names` 241 | 242 | ```cpp 243 | template 244 | constexpr array enum_names() noexcept; 245 | ``` 246 | 247 | * Defined in header `` 248 | 249 | * Returns `array` with all names where `N = number of enum values`, sorted by enum value. 250 | 251 | * Examples 252 | 253 | ```cpp 254 | constexpr auto color_names = magic_enum::enum_names(); 255 | // color_names -> {"RED", "BLUE", "GREEN"} 256 | // color_names[0] -> "RED" 257 | ``` 258 | 259 | ## `enum_entries` 260 | 261 | ```cpp 262 | template 263 | constexpr array, N> enum_entries() noexcept; 264 | ``` 265 | 266 | * Defined in header `` 267 | 268 | * Returns `array, N>` with all pairs (value, name) where `N = number of enum values`, sorted by enum value. 269 | 270 | * Examples 271 | 272 | ```cpp 273 | constexpr auto color_entries = magic_enum::enum_entries(); 274 | // color_entries -> {{Color::RED, "RED"}, {Color::BLUE, "BLUE"}, {Color::GREEN, "GREEN"}} 275 | // color_entries[0].first -> Color::RED 276 | // color_entries[0].second -> "RED" 277 | ``` 278 | 279 | ## `enum_index` 280 | 281 | ```cpp 282 | template 283 | constexpr optional enum_index(E value) noexcept; 284 | 285 | template 286 | constexpr size_t enum_index() noexcept; 287 | ``` 288 | 289 | * Defined in header `` 290 | 291 | * Obtains index in enum values from enum value. 292 | * `enum_index(value)` returns `optional` with index. 293 | * `enum_index()` returns index. If enum value does not have a index, occurs the compilation error `magic_enum::enum_index enum value does not have a index`. 294 | 295 | * Examples 296 | 297 | ```cpp 298 | constexpr auto color_index = magic_enum::enum_index(Color::BLUE); 299 | // color_index.value() -> 1 300 | // color_index.has_value() -> true 301 | ``` 302 | 303 | ```cpp 304 | constexpr auto color_index = magic_enum::enum_index(); 305 | // color_index -> 1 306 | ``` 307 | 308 | ## `enum_contains` 309 | 310 | ```cpp 311 | template 312 | constexpr bool enum_contains(E value) noexcept; 313 | 314 | template 315 | constexpr bool enum_contains(underlying_type_t value) noexcept; 316 | 317 | template 318 | constexpr bool enum_contains(string_view value) noexcept; 319 | 320 | template 321 | constexpr bool enum_contains(string_view value, BinaryPredicate p) noexcept(is_nothrow_invocable_v); 322 | ``` 323 | 324 | * Defined in header `` 325 | 326 | * Checks whether enum contains enumerator with such value. 327 | 328 | * Returns true is enum contains value, otherwise false. 329 | 330 | * Examples 331 | 332 | ```cpp 333 | magic_enum::enum_contains(Color::GREEN); // -> true 334 | magic_enum::enum_contains(2); // -> true 335 | magic_enum::enum_contains(123); // -> false 336 | magic_enum::enum_contains("GREEN"); // -> true 337 | magic_enum::enum_contains("fda"); // -> false 338 | ``` 339 | 340 | ## `enum_reflected` 341 | 342 | ```cpp 343 | template 344 | constexpr bool enum_reflected(E value) noexcept; 345 | 346 | template 347 | constexpr bool enum_reflected(underlying_type_t value) noexcept; 348 | ``` 349 | 350 | * Defined in header `` 351 | 352 | * Returns true if the enum value is in the range of values that can be reflected. 353 | 354 | ## `enum_type_name` 355 | 356 | ```cpp 357 | template 358 | constexpr string_view enum_type_name() noexcept; 359 | ``` 360 | 361 | * Defined in header `` 362 | 363 | * Returns type name of enum as `string_view` null-terminated string. 364 | 365 | * Examples 366 | 367 | ```cpp 368 | Color color = Color::RED; 369 | auto type_name = magic_enum::enum_type_name(); 370 | // type_name -> "Color" 371 | ``` 372 | 373 | ## `enum_fuse` 374 | 375 | ```cpp 376 | template 377 | constexpr optional enum_fuse(Es... values) noexcept; 378 | ``` 379 | 380 | * Defined in header `` 381 | 382 | * Returns a typesafe bijective mix of several enum values. This can be used to emulate 2D switch/case statements. 383 | 384 | * Return type is `optional` where `enum_fuse_t` is an incomplete enum, it is unique for any given combination of `Es...`. 385 | 386 | * Switch/case statement over an incomplete enum is a Visual Studio warning C4064 387 | * You have to silent (/wd4064) or ignore it. 388 | * Alternatively, define `MAGIC_ENUM_NO_TYPESAFE_ENUM_FUSE` to disable type-safety (`enum_fuse_t` equals `uintmax_t`). 389 | 390 | * Examples 391 | 392 | ```cpp 393 | switch (magic_enum::enum_fuse(color, direction).value()) { 394 | case magic_enum::enum_fuse(Color::RED, Directions::Up).value(): // ... 395 | case magic_enum::enum_fuse(Color::BLUE, Directions::Down).value(): // ... 396 | case magic_enum::enum_fuse(Directions::BLUE, Color::Down).value(): // Compilation error 397 | // ... 398 | } 399 | ``` 400 | 401 | ## `enum_switch` 402 | 403 | ```cpp 404 | template 405 | constexpr Result enum_switch(Lambda&& lambda, E value); 406 | 407 | template 408 | constexpr Result enum_switch(Lambda&& lambda, E value, Result&& result); 409 | ``` 410 | 411 | * Defined in header `` 412 | 413 | * Examples 414 | 415 | ```cpp 416 | Color color = Color::RED; 417 | 418 | magic_enum::enum_switch([] (auto val) { 419 | constexpr Color c_color = val; 420 | // ... 421 | }, color); 422 | ``` 423 | 424 | ## `enum_for_each` 425 | 426 | ```cpp 427 | template 428 | constexpr auto enum_for_each(Lambda&& lambda); 429 | ``` 430 | 431 | * Defined in header `` 432 | 433 | * Examples 434 | 435 | ```cpp 436 | underlying_type_t sum{}; 437 | enum_for_each([&sum](auto val) { 438 | constexpr underlying_type_t v = enum_integer(val()); 439 | sum += v; 440 | }); 441 | ``` 442 | 443 | ## `enum_flags` 444 | 445 | ```cpp 446 | template 447 | string enum_flags_name(E value); 448 | 449 | template 450 | constexpr optional enum_flags_cast(underlying_type_t value) noexcept; 451 | 452 | template 453 | constexpr optional enum_flags_cast(string_view value) noexcept; 454 | 455 | template 456 | constexpr optional enum_flags_cast(string_view value, BinaryPredicate p) noexcept(is_nothrow_invocable_v); 457 | 458 | template 459 | constexpr bool enum_flags_contains(E value) noexcept; 460 | 461 | template 462 | constexpr bool enum_flags_contains(underlying_type_t value) noexcept; 463 | 464 | template 465 | constexpr bool enum_flags_contains(string_view value) noexcept; 466 | 467 | template 468 | constexpr bool enum_flags_contains(string_view value, BinaryPredicate p) noexcept(is_nothrow_invocable_v); 469 | ``` 470 | 471 | * Defined in header `` 472 | 473 | * For enum-flags add `is_flags` to specialization `enum_range` for necessary enum type. Specialization of `enum_range` must be injected in `namespace magic_enum::customize`. 474 | ```cpp 475 | enum class Directions { Up = 1 << 1, Down = 1 << 2, Right = 1 << 3, Left = 1 << 4 }; 476 | template <> 477 | struct magic_enum::customize::enum_range { 478 | static constexpr bool is_flags = true; 479 | }; 480 | ``` 481 | 482 | * `MAGIC_ENUM_RANGE_MAX/MAGIC_ENUM_RANGE_MIN` does not affect the maximum amount of flags. 483 | 484 | * If enum is declared as flags, then it will not reflect the value of zero and is logically AND. 485 | 486 | * Examples 487 | 488 | ```cpp 489 | enum Directions : std::uint64_t { 490 | Left = 1, 491 | Down = 2, 492 | Up = 4, 493 | Right = 8, 494 | LeftAndDown = 3 495 | }; 496 | template <> 497 | struct magic_enum::customize::enum_range { 498 | static constexpr bool is_flags = true; 499 | }; 500 | 501 | magic_enum::enum_flags_name(Directions::Up | Directions::Right); // -> "Directions::Up|Directions::Right" 502 | magic_enum::enum_flags_name(Directions::LeftAndDown); // -> "Directions::Left|Directions::Down" 503 | 504 | magic_enum::enum_flags_contains(Directions::Up | Directions::Right); // -> true 505 | magic_enum::enum_flags_contains(Directions::LeftAndDown); // -> false 506 | 507 | magic_enum::enum_flags_cast(3); // -> "Directions::Left|Directions::Down" 508 | 509 | magic_enum::enum_flags_test(Left|Down, Down); // -> "true" 510 | magic_enum::enum_flags_test(Left|Down, Right); // -> "false" 511 | 512 | magic_enum::enum_flags_test_any(Left|Down|Right, Down|Right); // -> "true" 513 | ``` 514 | 515 | ## `is_unscoped_enum` 516 | 517 | ```cpp 518 | template 519 | struct is_unscoped_enum; 520 | 521 | template 522 | inline constexpr bool is_unscoped_enum_v = is_unscoped_enum::value; 523 | ``` 524 | 525 | * Defined in header `` 526 | 527 | * Checks whether type is an [Unscoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Unscoped_enumeration). 528 | 529 | * Provides the member constant value which is equal to true, if T is an [Unscoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Unscoped_enumeration) type.
530 | Otherwise, value is equal to false. 531 | 532 | * Examples 533 | 534 | ```cpp 535 | magic_enum::is_unscoped_enum::value -> true 536 | magic_enum::is_unscoped_enum::value -> false 537 | 538 | // Helper variable template. 539 | magic_enum::is_unscoped_enum_v -> true 540 | ``` 541 | 542 | ## `is_scoped_enum` 543 | 544 | ```cpp 545 | template 546 | struct is_scoped_enum; 547 | 548 | template 549 | inline constexpr bool is_scoped_enum_v = is_scoped_enum::value; 550 | ``` 551 | 552 | * Defined in header `` 553 | 554 | * Checks whether type is an [Scoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Scoped_enumerations). 555 | 556 | * Provides the member constant value which is equal to true, if T is an [Scoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Scoped_enumerations) type.
557 | Otherwise, value is equal to false. 558 | 559 | * Examples 560 | 561 | ```cpp 562 | magic_enum::is_scoped_enum::value -> false 563 | magic_enum::is_scoped_enum::value -> true 564 | 565 | // Helper variable template. 566 | magic_enum::is_scoped_enum_v -> true 567 | ``` 568 | 569 | ## `underlying_type` 570 | 571 | ```cpp 572 | template 573 | struct underlying_type; 574 | 575 | template 576 | using underlying_type_t = typename underlying_type::type; 577 | ``` 578 | 579 | * Defined in header `` 580 | 581 | * Improved UB-free "SFINAE-friendly" [underlying_type](https://en.cppreference.com/w/cpp/types/underlying_type). 582 | 583 | * If T is a complete enumeration type, provides a member typedef type that names the underlying type of T.
584 | Otherwise, if T is not an enumeration type, there is no member type.
585 | Otherwise (T is an incomplete enumeration type), the program is ill-formed. 586 | 587 | * Examples 588 | 589 | ```cpp 590 | magic_enum::underlying_type::type -> int 591 | 592 | // Helper types. 593 | magic_enum::underlying_type_t -> int 594 | ``` 595 | 596 | ## `ostream_operators` 597 | 598 | ```cpp 599 | template 600 | basic_ostream& operator<<(basic_ostream& os, E value); 601 | 602 | template 603 | basic_ostream& operator<<(basic_ostream& os, optional value); 604 | ``` 605 | 606 | * Defined in header `` 607 | 608 | * Out-of-the-box ostream operators for all enums. 609 | 610 | * Examples 611 | 612 | ```cpp 613 | using magic_enum::iostream_operators::operator<<; // out-of-the-box ostream operators for enums. 614 | Color color = Color::BLUE; 615 | std::cout << color << std::endl; // "BLUE" 616 | ``` 617 | 618 | ## `istream_operators` 619 | 620 | ```cpp 621 | template 622 | basic_istream& operator>>(basic_istream& is, E& value); 623 | ``` 624 | 625 | * Defined in header `` 626 | 627 | * Out-of-the-box istream operators for all enums. 628 | 629 | * Examples 630 | 631 | ```cpp 632 | using magic_enum::iostream_operators::operator>>; // out-of-the-box istream operators for enums. 633 | Color color; 634 | std::cin >> color; 635 | ``` 636 | 637 | ## `bitwise_operators` 638 | 639 | ```cpp 640 | template 641 | constexpr E operator~(E rhs) noexcept; 642 | 643 | template 644 | constexpr E operator|(E lhs, E rhs) noexcept; 645 | 646 | template 647 | constexpr E operator&(E lhs, E rhs) noexcept; 648 | 649 | template 650 | constexpr E operator^(E lhs, E rhs) noexcept; 651 | 652 | template 653 | constexpr E& operator|=(E& lhs, E rhs) noexcept; 654 | 655 | template 656 | constexpr E& operator&=(E& lhs, E rhs) noexcept; 657 | 658 | template 659 | constexpr E& operator^=(E& lhs, E rhs) noexcept; 660 | ``` 661 | 662 | * Defined in header `` 663 | 664 | * Out-of-the-box bitwise operators for all enums. 665 | 666 | * Examples 667 | 668 | ```cpp 669 | enum class Flags { A = 1 << 0, B = 1 << 1, C = 1 << 2, D = 1 << 3 }; 670 | using namespace magic_enum::bitwise_operators; // out-of-the-box bitwise operators for enums. 671 | // Support operators: ~, |, &, ^, |=, &=, ^=. 672 | Flags flags = Flags::A | Flags::B & ~Flags::C; 673 | ``` 674 | 675 | ## `containers::array` 676 | 677 | ```cpp 678 | template > 679 | struct array { 680 | 681 | constexpr reference at(E pos); 682 | 683 | constexpr const_reference at(E pos) const; 684 | 685 | constexpr reference operator[](E pos) noexcept; 686 | 687 | constexpr const_reference operator[](E pos) const noexcept; 688 | 689 | constexpr reference front() noexcept; 690 | 691 | constexpr const_reference front() const noexcept; 692 | 693 | constexpr reference back() noexcept; 694 | 695 | constexpr const_reference back() const noexcept; 696 | 697 | constexpr pointer data() noexcept; 698 | 699 | constexpr const_pointer data() const noexcept; 700 | 701 | constexpr iterator begin() noexcept; 702 | 703 | constexpr const_iterator begin() const noexcept; 704 | 705 | constexpr const_iterator cbegin() const noexcept; 706 | 707 | constexpr iterator end() noexcept; 708 | 709 | constexpr const_iterator end() const noexcept; 710 | 711 | constexpr const_iterator cend() const noexcept; 712 | 713 | constexpr iterator rbegin() noexcept; 714 | 715 | constexpr const_iterator rbegin() const noexcept; 716 | 717 | constexpr const_iterator crbegin() const noexcept; 718 | 719 | constexpr iterator rend() noexcept; 720 | 721 | constexpr const_iterator rend() const noexcept; 722 | 723 | constexpr const_iterator crend() const noexcept; 724 | 725 | constexpr bool empty() const noexcept; 726 | 727 | constexpr size_type size() const noexcept; 728 | 729 | constexpr size_type max_size() const noexcept; 730 | 731 | constexpr void fill(const V& value); 732 | 733 | constexpr void swap(array& other) noexcept(std::is_nothrow_swappable_v); 734 | 735 | friend constexpr bool operator==(const array& a1, const array& a2); 736 | 737 | friend constexpr bool operator!=(const array& a1, const array& a2); 738 | 739 | friend constexpr bool operator<(const array& a1, const array& a2); 740 | 741 | friend constexpr bool operator<=(const array& a1, const array& a2); 742 | 743 | friend constexpr bool operator>(const array& a1, const array& a2); 744 | 745 | friend constexpr bool operator>=(const array& a1, const array& a2); 746 | } 747 | ``` 748 | 749 | * Defined in header `` 750 | 751 | * STL like array for all enums. 752 | 753 | * Examples 754 | 755 | ```cpp 756 | constexpr magic_enum::containers::array color_rgb_array {{{{255, 0, 0}, {0, 255, 0}, {0, 0, 255}}}}; 757 | ``` 758 | 759 | ```cpp 760 | magic_enum::containers::array color_rgb_array {}; 761 | color_rgb_array[Color::RED] = {255, 0, 0}; 762 | color_rgb_array[Color::GREEN] = {0, 255, 0}; 763 | color_rgb_array[Color::BLUE] = {0, 0, 255}; 764 | magic_enum::containers::get(color_rgb_array) // -> RGB{0, 0, 255} 765 | ``` 766 | 767 | ## `containers::bitset` 768 | 769 | ```cpp 770 | template > 771 | class bitset { 772 | 773 | constexpr explicit bitset(detail::raw_access_t = raw_access) noexcept; 774 | 775 | constexpr explicit bitset(detail::raw_access_t, unsigned long long val); 776 | 777 | constexpr explicit bitset(detail::raw_access_t, 778 | string_view sv, 779 | string_view::size_type pos = 0, 780 | string_view::size_type n = string_view::npos, 781 | char_type zero = '0', 782 | char_type one = '1'); 783 | 784 | constexpr explicit bitset(detail::raw_access_t, 785 | const char_type* str, 786 | std::size_t n = ~std::size_t{}, 787 | char_type zero = '0', 788 | char_type one = '1'); 789 | 790 | constexpr bitset(std::initializer_list starters); 791 | 792 | constexpr explicit bitset(E starter); 793 | 794 | template > 795 | constexpr explicit bitset(string_view sv, 796 | Cmp&& cmp = {}, 797 | char_type sep = '|'); 798 | 799 | friend constexpr bool operator==(const bitset& lhs, const bitset& rhs) noexcept; 800 | 801 | friend constexpr bool operator!=(const bitset& lhs, const bitset& rhs) noexcept; 802 | 803 | constexpr bool operator[](E pos) const noexcept; 804 | 805 | constexpr reference operator[](E pos) noexcept; 806 | 807 | constexpr bool test(E pos) const; 808 | 809 | constexpr bool all() const noexcept; 810 | 811 | constexpr bool any() const noexcept; 812 | 813 | constexpr bool none() const noexcept; 814 | 815 | constexpr std::size_t count() const noexcept; 816 | 817 | constexpr std::size_t size() const noexcept; 818 | 819 | constexpr std::size_t max_size() const noexcept; 820 | 821 | constexpr bitset& operator&= (const bitset& other) noexcept; 822 | 823 | constexpr bitset& operator|= (const bitset& other) noexcept; 824 | 825 | constexpr bitset& operator^= (const bitset& other) noexcept; 826 | 827 | constexpr bitset operator~() const noexcept; 828 | 829 | constexpr bitset& set() noexcept; 830 | 831 | constexpr bitset& set(E pos, bool value = true); 832 | 833 | constexpr bitset& reset() noexcept; 834 | 835 | constexpr bitset& reset(E pos); 836 | 837 | constexpr bitset& flip() noexcept; 838 | 839 | friend constexpr bitset operator&(const bitset& lhs, const bitset& rhs) noexcept; 840 | 841 | friend constexpr bitset operator|(const bitset& lhs, const bitset& rhs) noexcept; 842 | 843 | friend constexpr bitset operator^(const bitset& lhs, const bitset& rhs) noexcept; 844 | 845 | constexpr explicit operator E() const; 846 | 847 | string to_string(char_type sep = '|') const; 848 | 849 | string to_string(detail::raw_access_t, 850 | char_type zero = '0', 851 | char_type one = '1') const; 852 | 853 | constexpr unsigned long long to_ullong(detail::raw_access_t raw) const; 854 | 855 | constexpr unsigned long long to_ulong(detail::raw_access_t raw) const; 856 | 857 | friend std::ostream& operator<<(std::ostream& o, const bitset& bs); 858 | 859 | friend std::istream& operator>>(std::istream& i, bitset& bs); 860 | } 861 | ``` 862 | 863 | * Defined in header `` 864 | 865 | * STL like bitset for all enums. 866 | 867 | * Examples 868 | 869 | ```cpp 870 | constexpr magic_enum::containers::bitset color_bitset_red_green {Color::RED|Color::GREEN}; 871 | bool all = color_bitset_red_green.all(); 872 | // all -> false 873 | // Color::BLUE is missing 874 | bool test = color_bitset_red_green.test(Color::RED); 875 | // test -> true 876 | ``` 877 | 878 | ```cpp 879 | auto color_bitset = magic_enum::containers::bitset(); 880 | color_bitset.set(Color::GREEN); 881 | color_bitset.set(Color::BLUE); 882 | std::string to_string = color_bitset.to_string(); 883 | // to_string -> "GREEN|BLUE" 884 | ``` 885 | 886 | ## `containers::set` 887 | 888 | ```cpp 889 | template > 890 | class set { 891 | 892 | constexpr set() noexcept = default; 893 | 894 | template 895 | constexpr set(InputIt first, InputIt last); 896 | 897 | constexpr set(std::initializer_list ilist); 898 | 899 | constexpr explicit set(E starter); 900 | 901 | constexpr set(const set&) noexcept = default; 902 | 903 | constexpr set(set&&) noexcept = default; 904 | 905 | constexpr set& operator=(const set&) noexcept = default; 906 | 907 | constexpr set& operator=(set&&) noexcept = default; 908 | 909 | constexpr set& operator=(std::initializer_list ilist); 910 | 911 | constexpr const_iterator begin() const noexcept; 912 | 913 | constexpr const_iterator end() const noexcept; 914 | 915 | constexpr const_iterator cbegin() const noexcept; 916 | 917 | constexpr const_iterator cend() const noexcept; 918 | 919 | constexpr const_reverse_iterator rbegin() const noexcept; 920 | 921 | constexpr const_reverse_iterator rend() const noexcept; 922 | 923 | constexpr const_reverse_iterator crbegin() const noexcept; 924 | 925 | constexpr const_reverse_iterator crend() const noexcept; 926 | 927 | constexpr bool empty() const noexcept; 928 | 929 | constexpr size_type size() const noexcept; 930 | 931 | constexpr size_type max_size() const noexcept; 932 | 933 | constexpr void clear() noexcept; 934 | 935 | constexpr std::pair insert(const value_type& value) noexcept; 936 | 937 | constexpr std::pair insert(value_type&& value) noexcept; 938 | 939 | constexpr iterator insert(const_iterator, const value_type& value) noexcept; 940 | 941 | constexpr iterator insert(const_iterator hint, value_type&& value) noexcept; 942 | 943 | template 944 | constexpr void insert(InputIt first, InputIt last) noexcept; 945 | 946 | constexpr void insert(std::initializer_list ilist) noexcept; 947 | 948 | template 949 | constexpr std::pair emplace(Args&&... args) noexcept; 950 | 951 | template 952 | constexpr iterator emplace_hint(const_iterator, Args&&... args) noexcept; 953 | 954 | constexpr iterator erase(const_iterator pos) noexcept; 955 | 956 | constexpr iterator erase(const_iterator first, const_iterator last) noexcept; 957 | 958 | constexpr size_type erase(const key_type& key) noexcept; 959 | 960 | template 961 | constexpr std::enable_if_t, size_type> erase(K&& x) noexcept; 962 | 963 | void swap(set& other) noexcept; 964 | 965 | constexpr size_type count(const key_type& key) const noexcept; 966 | 967 | template 968 | constexpr std::enable_if_t, size_type> count(const K& x) const; 969 | 970 | constexpr const_iterator find(const key_type & key) const noexcept; 971 | 972 | template 973 | constexpr std::enable_if_t, const_iterator> find(const K& x) const; 974 | 975 | constexpr bool contains(const key_type& key) const noexcept; 976 | 977 | template 978 | constexpr std::enable_if_t, bool> contains(const K& x) const noexcept; 979 | 980 | constexpr std::pair equal_range(const key_type& key) const noexcept; 981 | 982 | template 983 | constexpr std::enable_if_t, std::pair> equal_range(const K& x) const noexcept; 984 | 985 | constexpr const_iterator lower_bound(const key_type& key) const noexcept; 986 | 987 | template 988 | constexpr std::enable_if_t, const_iterator> lower_bound(const K& x) const noexcept; 989 | 990 | constexpr const_iterator upper_bound(const key_type& key) const noexcept; 991 | 992 | template 993 | constexpr std::enable_if_t, const_iterator> upper_bound(const K& x) const noexcept; 994 | 995 | constexpr key_compare key_comp() const; 996 | 997 | constexpr value_compare value_comp() const; 998 | 999 | constexpr friend bool operator==(const set& lhs, const set& rhs) noexcept; 1000 | 1001 | constexpr friend bool operator!=(const set& lhs, const set& rhs) noexcept; 1002 | 1003 | constexpr friend bool operator<(const set& lhs, const set& rhs) noexcept; 1004 | 1005 | constexpr friend bool operator<=(const set& lhs, const set& rhs) noexcept; 1006 | 1007 | constexpr friend bool operator>(const set& lhs, const set& rhs) noexcept; 1008 | 1009 | constexpr friend bool operator>=(const set& lhs, const set& rhs) noexcept; 1010 | 1011 | template 1012 | size_type erase_if(Pred pred); 1013 | } 1014 | ``` 1015 | 1016 | * Defined in header `` 1017 | 1018 | * STL like set for all enums. 1019 | 1020 | * Examples 1021 | 1022 | ```cpp 1023 | constexpr magic_enum::containers::set color_set_filled = {Color::RED, Color::GREEN, Color::BLUE}; 1024 | ``` 1025 | 1026 | ```cpp 1027 | auto color_set = magic_enum::containers::set(); 1028 | bool empty = color_set.empty(); 1029 | // empty -> true 1030 | color_set.insert(Color::GREEN); 1031 | color_set.insert(Color::BLUE); 1032 | color_set.insert(Color::RED); 1033 | std::size_t size = color_set.size(); 1034 | // size -> 3 1035 | ``` 1036 | -------------------------------------------------------------------------------- /example/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(CheckCXXCompilerFlag) 2 | 3 | set(CMAKE_CXX_STANDARD 17) 4 | if((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) 5 | set(OPTIONS -Wall -Wextra -Wshadow -pedantic-errors -Werror) 6 | elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") 7 | set(OPTIONS /W4 /WX) 8 | if(HAS_PERMISSIVE_FLAG) 9 | set(OPTIONS ${OPTIONS} /permissive-) 10 | endif() 11 | endif() 12 | 13 | function(make_example target) 14 | add_executable(${target} ${target}.cpp) 15 | set_target_properties(${target} PROPERTIES CXX_EXTENSIONS OFF) 16 | target_compile_features(${target} PRIVATE cxx_std_17) 17 | target_compile_options(${target} PRIVATE ${OPTIONS}) 18 | target_link_libraries(${target} PRIVATE ${CMAKE_PROJECT_NAME}) 19 | endfunction() 20 | 21 | make_example(example) 22 | make_example(enum_flag_example) 23 | make_example(example_containers_array) 24 | make_example(example_containers_bitset) 25 | make_example(example_containers_set) 26 | make_example(example_custom_name) 27 | make_example(example_switch) 28 | if(MAGIC_ENUM_OPT_ENABLE_NONASCII) 29 | make_example(example_nonascii_name) 30 | endif() 31 | -------------------------------------------------------------------------------- /example/enum_flag_example.cpp: -------------------------------------------------------------------------------- 1 | // Licensed under the MIT License . 2 | // SPDX-License-Identifier: MIT 3 | // Copyright (c) 2019 - 2024 Daniil Goncharov . 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | #include 24 | #include 25 | 26 | #include 27 | #include 28 | 29 | enum class AnimalFlags : std::uint64_t { HasClaws = 1 << 10, CanFly = 1 << 20, EatsFish = 1 << 30, Endangered = std::uint64_t{1} << 40 }; 30 | // Add specialization `is_flags` to define that enum are flags. 31 | template <> 32 | struct magic_enum::customize::enum_range { 33 | static constexpr bool is_flags = true; 34 | }; 35 | 36 | int main() { 37 | // Enum-flags variable to string name. 38 | AnimalFlags f1 = AnimalFlags::Endangered; 39 | auto f1_name = magic_enum::enum_name(f1); 40 | std::cout << f1_name << std::endl; // Endangered 41 | 42 | // String enum-flags name sequence. 43 | constexpr auto names = magic_enum::enum_names(); 44 | std::cout << "AnimalFlags names:"; 45 | for (const auto& n : names) { 46 | std::cout << " " << n; 47 | } 48 | std::cout << std::endl; 49 | // AnimalFlags names: HasClaws CanFly EatsFish Endangered 50 | 51 | // String name to enum-flags value. 52 | auto f2 = magic_enum::enum_flags_cast("EatsFish|CanFly"); 53 | if (f2.has_value()) { 54 | std::cout << "EatsFish|CanFly = " << magic_enum::enum_integer(f2.value()) << std::endl; // CanFly|EatsFish = 1074790400 55 | } 56 | 57 | // Integer value to enum-flags value. 58 | auto f3 = magic_enum::enum_cast(1073742848); 59 | if (f3.has_value()) { 60 | std::cout << magic_enum::enum_flags_name(f3.value()) << " = " << magic_enum::enum_integer(f3.value()) << std::endl; // HasClaws|EatsFish = 1073742848 61 | } 62 | 63 | // Enum-flags value to integer value. 64 | auto f4_integer = magic_enum::enum_integer(AnimalFlags::HasClaws); 65 | std::cout << "HasClaws = " << f4_integer << std::endl; // HasClaws = 1024 66 | 67 | using magic_enum::iostream_operators::operator<<; // out-of-the-box ostream operator for enum-flags. 68 | // Ostream operator for enum-flags. 69 | std::cout << f1 << " " << f2 << " " << f3 << std::endl; // Endangered CanFly|EatsFish HasClaws|EatsFish 70 | 71 | // Number of enum-flags values. 72 | std::cout << "AnimalFlags enum size: " << magic_enum::enum_count() << std::endl; // AnimalFlags enum size: 4 73 | 74 | // Indexed access to enum-flags value. 75 | std::cout << "AnimalFlags[0] = " << magic_enum::enum_value(0) << std::endl; // AnimalFlags[0] = HasClaws 76 | 77 | // Enum-flags value sequence. 78 | constexpr auto values = magic_enum::enum_values(); 79 | std::cout << "AnimalFlags values:"; 80 | for (const auto f : values) { 81 | std::cout << " " << f; // Ostream operator for enum-flags. 82 | } 83 | std::cout << std::endl; 84 | // AnimalFlags values: HasClaws CanFly EatsFish Endangered 85 | 86 | using namespace magic_enum::bitwise_operators; // out-of-the-box bitwise operators for all enums. 87 | // Support operators: ~, |, &, ^, |=, &=, ^=. 88 | AnimalFlags flag = AnimalFlags::HasClaws | AnimalFlags::CanFly; 89 | std::cout << flag << std::endl; // HasClaws|CanFly 90 | 91 | // Enum-flags pair (value, string name) sequence. 92 | constexpr auto entries = magic_enum::enum_entries(); 93 | std::cout << "AnimalFlags entries:"; 94 | for (const auto& e : entries) { 95 | std::cout << " " << e.second << " = " << magic_enum::enum_integer(e.first); 96 | } 97 | std::cout << std::endl; 98 | // AnimalFlags entries: AnimalFlags entries: HasClaws = 1024 CanFly = 1048576 EatsFish = 1073741824 Endangered = 1099511627776 99 | 100 | return 0; 101 | } 102 | -------------------------------------------------------------------------------- /example/example.cpp: -------------------------------------------------------------------------------- 1 | // Licensed under the MIT License . 2 | // SPDX-License-Identifier: MIT 3 | // Copyright (c) 2019 - 2024 Daniil Goncharov . 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | #include 24 | 25 | #include 26 | #include 27 | 28 | enum class Color : int { RED = -10, BLUE = 0, GREEN = 10 }; 29 | 30 | template 31 | auto to_integer(magic_enum::Enum value) { 32 | // magic_enum::Enum - C++17 Concept for enum type. 33 | return static_cast>(value); 34 | } 35 | 36 | int main() { 37 | // Enum variable to string name. 38 | Color c1 = Color::RED; 39 | auto c1_name = magic_enum::enum_name(c1); 40 | std::cout << c1_name << std::endl; // RED 41 | 42 | // String enum name sequence. 43 | constexpr auto names = magic_enum::enum_names(); 44 | std::cout << "Color names:"; 45 | for (const auto& n : names) { 46 | std::cout << " " << n; 47 | } 48 | std::cout << std::endl; 49 | // Color names: RED BLUE GREEN 50 | 51 | // String name to enum value. 52 | auto c2 = magic_enum::enum_cast("BLUE"); 53 | if (c2.has_value()) { 54 | std::cout << "BLUE = " << to_integer(c2.value()) << std::endl; // BLUE = 0 55 | } 56 | 57 | // Case insensitive enum_cast. 58 | c2 = magic_enum::enum_cast("blue", magic_enum::case_insensitive); 59 | if (c2.has_value()) { 60 | std::cout << "BLUE = " << to_integer(c2.value()) << std::endl; // BLUE = 0 61 | } 62 | 63 | // Integer value to enum value. 64 | auto c3 = magic_enum::enum_cast(10); 65 | if (c3.has_value()) { 66 | std::cout << "GREEN = " << magic_enum::enum_integer(c3.value()) << std::endl; // GREEN = 10 67 | } 68 | 69 | // Enum value to integer value. 70 | auto c4_integer = magic_enum::enum_integer(Color::RED); 71 | std::cout << "RED = " << c4_integer << std::endl; // RED = -10 72 | 73 | using magic_enum::iostream_operators::operator<<; // out-of-the-box ostream operator for all enums. 74 | // Ostream operator for enum. 75 | std::cout << "Color: " << c1 << " " << c2 << " " << c3 << std::endl; // Color: RED BLUE GREEN 76 | 77 | // Number of enum values. 78 | std::cout << "Color enum size: " << magic_enum::enum_count() << std::endl; // Color size: 3 79 | 80 | // Indexed access to enum value. 81 | std::cout << "Color[0] = " << magic_enum::enum_value(0) << std::endl; // Color[0] = RED 82 | 83 | // Enum value sequence. 84 | constexpr auto values = magic_enum::enum_values(); 85 | std::cout << "Colors values:"; 86 | for (const auto c : values) { 87 | std::cout << " " << c; // Ostream operator for enum. 88 | } 89 | std::cout << std::endl; 90 | // Color values: RED BLUE GREEN 91 | 92 | enum class Flags { A = 1, B = 2, C = 4, D = 8 }; 93 | using namespace magic_enum::bitwise_operators; // out-of-the-box bitwise operators for all enums. 94 | // Support operators: ~, |, &, ^, |=, &=, ^=. 95 | Flags flag = Flags::A | Flags::C; 96 | std::cout << flag << std::endl; // 5 97 | 98 | enum color { red, green, blue }; 99 | 100 | // Checks whether type is an Unscoped enumeration. 101 | static_assert(magic_enum::is_unscoped_enum_v); 102 | static_assert(!magic_enum::is_unscoped_enum_v); 103 | static_assert(!magic_enum::is_unscoped_enum_v); 104 | 105 | // Checks whether type is an Scoped enumeration. 106 | static_assert(!magic_enum::is_scoped_enum_v); 107 | static_assert(magic_enum::is_scoped_enum_v); 108 | static_assert(magic_enum::is_scoped_enum_v); 109 | 110 | // Enum pair (value enum, string enum name) sequence. 111 | constexpr auto entries = magic_enum::enum_entries(); 112 | std::cout << "Colors entries:"; 113 | for (const auto& e : entries) { 114 | std::cout << " " << e.second << " = " << static_cast(e.first); 115 | } 116 | std::cout << std::endl; 117 | // Color entries: RED = -10 BLUE = 0 GREEN = 10 118 | 119 | return 0; 120 | } 121 | -------------------------------------------------------------------------------- /example/example_containers_array.cpp: -------------------------------------------------------------------------------- 1 | // Licensed under the MIT License . 2 | // SPDX-License-Identifier: MIT 3 | // Copyright (c) 2019 - 2024 Daniil Goncharov . 4 | // Copyright (c) 2022 - 2023 Bela Schaum . 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | #include 25 | 26 | #include 27 | 28 | enum class Color { RED = 1, GREEN = 2, BLUE = 4 }; 29 | template <> 30 | struct magic_enum::customize::enum_range { 31 | static constexpr bool is_flags = true; 32 | }; 33 | 34 | struct RGB { 35 | 36 | std::uint8_t r {}; 37 | std::uint8_t g {}; 38 | std::uint8_t b {}; 39 | 40 | [[nodiscard]] constexpr bool empty() { return std::equal_to{}(r, g) && std::equal_to{}(g, b) && std::equal_to{}(b, 0); } 41 | 42 | [[nodiscard]] constexpr bool operator==(RGB rgb) const noexcept { return std::equal_to{}(r, rgb.r) && std::equal_to{}(g, rgb.g) && std::equal_to{}(b, rgb.b); } 43 | 44 | friend std::ostream& operator<<(std::ostream& ostream, RGB rgb) { 45 | ostream << "R=" << static_cast(rgb.r) << " G=" << static_cast(rgb.g) << " B=" << static_cast(rgb.b); 46 | return ostream; 47 | } 48 | }; 49 | 50 | constexpr std::uint8_t color_max = std::numeric_limits::max(); 51 | 52 | int main() { 53 | 54 | constexpr magic_enum::containers::array color_rgb_initializer {{{{color_max, 0, 0}, {0, color_max, 0}, {0, 0, color_max}}}}; 55 | 56 | std::cout << magic_enum::containers::get<0>(color_rgb_initializer) << std::endl; // R=255 G=0 B=0 57 | std::cout << magic_enum::containers::get<1>(color_rgb_initializer) << std::endl; // R=0 G=255 B=0 58 | std::cout << magic_enum::containers::get<2>(color_rgb_initializer) << std::endl; // R=0 G=0 B=255 59 | 60 | std::cout << magic_enum::containers::get(color_rgb_initializer) << std::endl; // R=255 G=0 B=0 61 | std::cout << magic_enum::containers::get(color_rgb_initializer) << std::endl; // R=0 G=255 B=0 62 | std::cout << magic_enum::containers::get(color_rgb_initializer) << std::endl; // R=0 G=0 B=255 63 | 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /example/example_containers_bitset.cpp: -------------------------------------------------------------------------------- 1 | // Licensed under the MIT License . 2 | // SPDX-License-Identifier: MIT 3 | // Copyright (c) 2019 - 2024 Daniil Goncharov . 4 | // Copyright (c) 2022 - 2023 Bela Schaum . 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | #if defined(_MSC_VER) 25 | # pragma warning(push) 26 | # pragma warning(disable : 4244) // warning C4244: 'argument': conversion from 'const T' to 'unsigned int', possible loss of data. 27 | #endif 28 | 29 | #include 30 | 31 | #include 32 | 33 | enum class Color { RED = 1, GREEN = 2, BLUE = 4 }; 34 | template <> 35 | struct magic_enum::customize::enum_range { 36 | static constexpr bool is_flags = true; 37 | }; 38 | 39 | int main() { 40 | 41 | auto color_bitset = magic_enum::containers::bitset(); 42 | color_bitset.set(Color::GREEN); 43 | color_bitset.set(Color::BLUE); 44 | 45 | std::cout << std::boolalpha; 46 | std::cout << color_bitset.size() << std::endl; // 3 == magic_enum::enum_count() 47 | std::cout << color_bitset.all() << std::endl; // false 48 | std::cout << color_bitset.any() << std::endl; // true 49 | std::cout << color_bitset.none() << std::endl; // false 50 | std::cout << color_bitset.count() << std::endl; // 2 51 | std::cout << color_bitset.test(Color::RED) << std::endl; // false 52 | std::cout << color_bitset.test(Color::GREEN) << std::endl; // true 53 | std::cout << color_bitset.test(Color::BLUE) << std::endl; // true 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /example/example_containers_set.cpp: -------------------------------------------------------------------------------- 1 | // Licensed under the MIT License . 2 | // SPDX-License-Identifier: MIT 3 | // Copyright (c) 2019 - 2024 Daniil Goncharov . 4 | // Copyright (c) 2022 - 2023 Bela Schaum . 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | #if defined(_MSC_VER) 25 | # pragma warning(push) 26 | # pragma warning(disable : 4244) // warning C4244: 'argument': conversion from 'const T' to 'unsigned int', possible loss of data. 27 | #endif 28 | 29 | #include 30 | 31 | #include 32 | 33 | enum class Color { RED = 1, GREEN = 2, BLUE = 4 }; 34 | template <> 35 | struct magic_enum::customize::enum_range { 36 | static constexpr bool is_flags = true; 37 | }; 38 | 39 | int main() { 40 | 41 | std::cout << std::boolalpha; 42 | magic_enum::containers::set color_set {Color::RED, Color::GREEN, Color::BLUE}; 43 | std::cout << color_set.empty() << std::endl; // false 44 | std::cout << color_set.size() << std::endl; // 3 45 | 46 | color_set.clear(); 47 | std::cout << color_set.empty() << std::endl; // true 48 | std::cout << color_set.size() << std::endl; // 0 49 | 50 | color_set.insert(Color::GREEN); 51 | color_set.insert(Color::BLUE); 52 | std::cout << color_set.empty() << std::endl; // false 53 | std::cout << color_set.size() << std::endl; // 2 54 | 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /example/example_custom_name.cpp: -------------------------------------------------------------------------------- 1 | // Licensed under the MIT License . 2 | // SPDX-License-Identifier: MIT 3 | // Copyright (c) 2020 - 2024 Daniil Goncharov . 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | #include 24 | 25 | #include 26 | 27 | enum class Color : int { RED = -10, BLUE = 0, GREEN = 10 }; 28 | 29 | // Сustom definitions of names for enum. 30 | // Specialization of `enum_name` must be injected in `namespace magic_enum::customize`. 31 | template <> 32 | constexpr magic_enum::customize::customize_t magic_enum::customize::enum_name(Color value) noexcept { 33 | switch (value) { 34 | case Color::RED: 35 | return "the red color"; 36 | case Color::BLUE: 37 | return "The BLUE"; 38 | case Color::GREEN: 39 | return invalid_tag; 40 | } 41 | return default_tag; 42 | } 43 | 44 | enum class Numbers : int { One, Two, Three }; 45 | 46 | // Сustom definitions of names for enum. 47 | // Specialization of `enum_name` must be injected in `namespace magic_enum::customize`. 48 | template <> 49 | constexpr magic_enum::customize::customize_t magic_enum::customize::enum_name(Numbers value) noexcept { 50 | switch (value) { 51 | case Numbers::One: 52 | return "the one"; 53 | default: 54 | return default_tag; 55 | } 56 | } 57 | 58 | int main() { 59 | std::cout << magic_enum::enum_name(Color::RED) << std::endl; // 'the red color' 60 | std::cout << magic_enum::enum_name(Color::BLUE) << std::endl; // 'The BLUE' 61 | std::cout << magic_enum::enum_name(Color::GREEN) << std::endl; // '' 62 | 63 | std::cout << std::boolalpha; 64 | std::cout << (magic_enum::enum_cast("the red color").value() == Color::RED) << std::endl; // true 65 | 66 | std::cout << magic_enum::enum_name(Numbers::One) << std::endl; // 'the one' 67 | std::cout << magic_enum::enum_name(Numbers::Two) << std::endl; // 'Two' 68 | std::cout << magic_enum::enum_name(Numbers::Three) << std::endl; // 'Three' 69 | 70 | return 0; 71 | } 72 | -------------------------------------------------------------------------------- /example/example_nonascii_name.cpp: -------------------------------------------------------------------------------- 1 | // Licensed under the MIT License . 2 | // SPDX-License-Identifier: MIT 3 | // Copyright (c) 2020 - 2024 Daniil Goncharov . 4 | // Copyright (c) 2020 - 2023 Uruha Komachin . 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | #include 25 | 26 | #include 27 | 28 | enum class Language : int { 29 | 日本語 = 10, 30 | 한국어 = 20, 31 | English = 30, 32 | 😃 = 40, 33 | }; 34 | 35 | int main() { 36 | std::cout << magic_enum::enum_name(Language::日本語) << std::endl; // Japanese 37 | std::cout << magic_enum::enum_name(Language::한국어) << std::endl; // Korean 38 | std::cout << magic_enum::enum_name(Language::English) << std::endl; // English 39 | std::cout << magic_enum::enum_name(Language::😃) << std::endl; // Emoji 40 | 41 | std::cout << std::boolalpha; 42 | std::cout << (magic_enum::enum_cast("日本語").value() == Language::日本語) << std::endl; // true 43 | 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /example/example_switch.cpp: -------------------------------------------------------------------------------- 1 | // Licensed under the MIT License . 2 | // SPDX-License-Identifier: MIT 3 | // Copyright (c) 2019 - 2024 Daniil Goncharov . 4 | // Copyright (c) 2022 - 2023 Bela Schaum . 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | #include 25 | 26 | #define MAGIC_ENUM_ENABLE_HASH 27 | #include 28 | 29 | enum class Color { RED, BLUE, GREEN }; 30 | 31 | template 32 | constexpr std::string_view DoWork() { 33 | return "default"; 34 | } 35 | 36 | template <> 37 | constexpr std::string_view DoWork() { 38 | return "override"; 39 | } 40 | 41 | // Helper type for the visitor pattern. 42 | template struct overloaded : Ts... { using Ts::operator()...; }; 43 | template overloaded(Ts...) -> overloaded; 44 | 45 | int main() { 46 | Color c = Color::RED; 47 | 48 | auto lambda = [] (auto value) { 49 | std::cout << DoWork() << std::endl; 50 | }; 51 | 52 | magic_enum::enum_switch(lambda, c); // prints "default" 53 | 54 | c = Color::GREEN; 55 | 56 | magic_enum::enum_switch(lambda, c); // prints "override" 57 | 58 | // with object, explicit enum type 59 | auto switcher1 = overloaded{ 60 | [] (magic_enum::enum_constant) { 61 | std::cout << "Blue" << std::endl; 62 | }, 63 | [] (magic_enum::enum_constant) { 64 | std::cout << "Red" << std::endl; 65 | } 66 | }; 67 | 68 | magic_enum::enum_switch(switcher1, Color::GREEN); // prints nothing 69 | magic_enum::enum_switch(switcher1, Color::BLUE); // prints "Blue" 70 | magic_enum::enum_switch(switcher1, Color::RED); // prints "Red" 71 | 72 | // explicit result type 73 | auto switcher2 = overloaded{ 74 | [] (magic_enum::enum_constant) { 75 | return "called with green argument"; 76 | }, 77 | [] (Color other) { // default case 78 | auto name = magic_enum::enum_name(other); // not empty 79 | return "default: " + std::string{name}; 80 | } 81 | }; 82 | 83 | std::cout << magic_enum::enum_switch(switcher2, Color::GREEN) << std::endl; // prints "called with green argument" 84 | std::cout << magic_enum::enum_switch(switcher2, Color::RED) << std::endl; // prints "default: RED" 85 | 86 | auto empty = magic_enum::enum_switch(switcher2, static_cast(-3)); // returns an empty string 87 | assert(empty.empty()); 88 | 89 | // result with default object 90 | std::cout << magic_enum::enum_switch(switcher2, static_cast(-3), "unrecognized") << std::endl; // prints "unrecognized" 91 | 92 | auto switcher3 = overloaded{ 93 | [] (magic_enum::enum_constant) -> std::optional { 94 | return "red result"; 95 | }, 96 | [] (magic_enum::enum_constant) -> std::optional { 97 | return std::nullopt; 98 | } 99 | }; 100 | 101 | std::cout << std::boolalpha; 102 | std::cout << magic_enum::enum_switch(switcher3, Color::GREEN, std::make_optional("cica")).value() << std::endl; // prints default: "cica" 103 | std::cout << magic_enum::enum_switch(switcher3, Color::RED, std::make_optional("cica")).value() << std::endl; // prints: "red result" 104 | std::cout << magic_enum::enum_switch(switcher3, Color::BLUE, std::make_optional("cica")).has_value() << std::endl; // prints: false 105 | 106 | return 0; 107 | } 108 | -------------------------------------------------------------------------------- /include/magic_enum/magic_enum_all.hpp: -------------------------------------------------------------------------------- 1 | // __ __ _ ______ _____ 2 | // | \/ | (_) | ____| / ____|_ _ 3 | // | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ 4 | // | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| 5 | // | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| 6 | // |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| 7 | // __/ | https://github.com/Neargye/magic_enum 8 | // |___/ version 0.9.7 9 | // 10 | // Licensed under the MIT License . 11 | // SPDX-License-Identifier: MIT 12 | // Copyright (c) 2019 - 2024 Daniil Goncharov . 13 | // 14 | // Permission is hereby granted, free of charge, to any person obtaining a copy 15 | // of this software and associated documentation files (the "Software"), to deal 16 | // in the Software without restriction, including without limitation the rights 17 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | // copies of the Software, and to permit persons to whom the Software is 19 | // furnished to do so, subject to the following conditions: 20 | // 21 | // The above copyright notice and this permission notice shall be included in all 22 | // copies or substantial portions of the Software. 23 | // 24 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 | // SOFTWARE. 31 | 32 | #ifndef NEARGYE_MAGIC_ENUM_ALL_HPP 33 | #define NEARGYE_MAGIC_ENUM_ALL_HPP 34 | 35 | #include "magic_enum.hpp" 36 | #include "magic_enum_containers.hpp" 37 | #include "magic_enum_flags.hpp" 38 | #include "magic_enum_format.hpp" 39 | #include "magic_enum_fuse.hpp" 40 | #include "magic_enum_iostream.hpp" 41 | #include "magic_enum_switch.hpp" 42 | #include "magic_enum_utility.hpp" 43 | 44 | #endif // NEARGYE_MAGIC_ENUM_ALL_HPP 45 | -------------------------------------------------------------------------------- /include/magic_enum/magic_enum_flags.hpp: -------------------------------------------------------------------------------- 1 | // __ __ _ ______ _____ 2 | // | \/ | (_) | ____| / ____|_ _ 3 | // | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ 4 | // | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| 5 | // | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| 6 | // |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| 7 | // __/ | https://github.com/Neargye/magic_enum 8 | // |___/ version 0.9.7 9 | // 10 | // Licensed under the MIT License . 11 | // SPDX-License-Identifier: MIT 12 | // Copyright (c) 2019 - 2024 Daniil Goncharov . 13 | // 14 | // Permission is hereby granted, free of charge, to any person obtaining a copy 15 | // of this software and associated documentation files (the "Software"), to deal 16 | // in the Software without restriction, including without limitation the rights 17 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | // copies of the Software, and to permit persons to whom the Software is 19 | // furnished to do so, subject to the following conditions: 20 | // 21 | // The above copyright notice and this permission notice shall be included in all 22 | // copies or substantial portions of the Software. 23 | // 24 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 | // SOFTWARE. 31 | 32 | #ifndef NEARGYE_MAGIC_ENUM_FLAGS_HPP 33 | #define NEARGYE_MAGIC_ENUM_FLAGS_HPP 34 | 35 | #include "magic_enum.hpp" 36 | 37 | #if defined(__clang__) 38 | # pragma clang diagnostic push 39 | #elif defined(__GNUC__) 40 | # pragma GCC diagnostic push 41 | # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'. 42 | #elif defined(_MSC_VER) 43 | # pragma warning(push) 44 | #endif 45 | 46 | namespace magic_enum { 47 | 48 | namespace detail { 49 | 50 | template > 51 | constexpr U values_ors() noexcept { 52 | static_assert(S == enum_subtype::flags, "magic_enum::detail::values_ors requires valid subtype."); 53 | 54 | auto ors = U{0}; 55 | for (std::size_t i = 0; i < count_v; ++i) { 56 | ors |= static_cast(values_v[i]); 57 | } 58 | 59 | return ors; 60 | } 61 | 62 | } // namespace magic_enum::detail 63 | 64 | // Returns name from enum-flags value. 65 | // If enum-flags value does not have name or value out of range, returns empty string. 66 | template 67 | [[nodiscard]] auto enum_flags_name(E value, char_type sep = static_cast('|')) -> detail::enable_if_t { 68 | using D = std::decay_t; 69 | using U = underlying_type_t; 70 | constexpr auto S = detail::enum_subtype::flags; 71 | static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); 72 | 73 | string name; 74 | auto check_value = U{0}; 75 | for (std::size_t i = 0; i < detail::count_v; ++i) { 76 | if (const auto v = static_cast(enum_value(i)); (static_cast(value) & v) != 0) { 77 | if (const auto n = detail::names_v[i]; !n.empty()) { 78 | check_value |= v; 79 | if (!name.empty()) { 80 | name.append(1, sep); 81 | } 82 | name.append(n.data(), n.size()); 83 | } else { 84 | return {}; // Value out of range. 85 | } 86 | } 87 | } 88 | 89 | if (check_value != 0 && check_value == static_cast(value)) { 90 | return name; 91 | } 92 | return {}; // Invalid value or out of range. 93 | } 94 | 95 | // Obtains enum-flags value from integer value. 96 | // Returns optional with enum-flags value. 97 | template 98 | [[nodiscard]] constexpr auto enum_flags_cast(underlying_type_t value) noexcept -> detail::enable_if_t>> { 99 | using D = std::decay_t; 100 | using U = underlying_type_t; 101 | constexpr auto S = detail::enum_subtype::flags; 102 | static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); 103 | 104 | if constexpr (detail::count_v == 0) { 105 | static_cast(value); 106 | return {}; // Empty enum. 107 | } else { 108 | if constexpr (detail::is_sparse_v) { 109 | auto check_value = U{0}; 110 | for (std::size_t i = 0; i < detail::count_v; ++i) { 111 | if (const auto v = static_cast(enum_value(i)); (value & v) != 0) { 112 | check_value |= v; 113 | } 114 | } 115 | 116 | if (check_value != 0 && check_value == value) { 117 | return static_cast(value); 118 | } 119 | } else { 120 | constexpr auto min = detail::min_v; 121 | constexpr auto max = detail::values_ors(); 122 | 123 | if (value >= min && value <= max) { 124 | return static_cast(value); 125 | } 126 | } 127 | return {}; // Invalid value or out of range. 128 | } 129 | } 130 | 131 | // Obtains enum-flags value from name. 132 | // Returns optional with enum-flags value. 133 | template > 134 | [[nodiscard]] constexpr auto enum_flags_cast(string_view value, [[maybe_unused]] BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable()) -> detail::enable_if_t>, BinaryPredicate> { 135 | using D = std::decay_t; 136 | using U = underlying_type_t; 137 | constexpr auto S = detail::enum_subtype::flags; 138 | static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); 139 | 140 | if constexpr (detail::count_v == 0) { 141 | static_cast(value); 142 | return {}; // Empty enum. 143 | } else { 144 | auto result = U{0}; 145 | while (!value.empty()) { 146 | const auto d = detail::find(value, '|'); 147 | const auto s = (d == string_view::npos) ? value : value.substr(0, d); 148 | auto f = U{0}; 149 | for (std::size_t i = 0; i < detail::count_v; ++i) { 150 | if (detail::cmp_equal(s, detail::names_v[i], p)) { 151 | f = static_cast(enum_value(i)); 152 | result |= f; 153 | break; 154 | } 155 | } 156 | if (f == U{0}) { 157 | return {}; // Invalid value or out of range. 158 | } 159 | value.remove_prefix((d == string_view::npos) ? value.size() : d + 1); 160 | } 161 | 162 | if (result != U{0}) { 163 | return static_cast(result); 164 | } 165 | return {}; // Invalid value or out of range. 166 | } 167 | } 168 | 169 | // Checks whether enum-flags contains value with such value. 170 | template 171 | [[nodiscard]] constexpr auto enum_flags_contains(E value) noexcept -> detail::enable_if_t { 172 | using D = std::decay_t; 173 | using U = underlying_type_t; 174 | 175 | return static_cast(enum_flags_cast(static_cast(value))); 176 | } 177 | 178 | // Checks whether enum-flags contains value with such integer value. 179 | template 180 | [[nodiscard]] constexpr auto enum_flags_contains(underlying_type_t value) noexcept -> detail::enable_if_t { 181 | using D = std::decay_t; 182 | 183 | return static_cast(enum_flags_cast(value)); 184 | } 185 | 186 | // Checks whether enum-flags contains enumerator with such name. 187 | template > 188 | [[nodiscard]] constexpr auto enum_flags_contains(string_view value, BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable()) -> detail::enable_if_t { 189 | using D = std::decay_t; 190 | 191 | return static_cast(enum_flags_cast(value, std::move(p))); 192 | } 193 | 194 | // Checks whether `flags set` contains `flag`. 195 | // Note: If `flag` equals 0, it returns false, as 0 is not a flag. 196 | template 197 | constexpr auto enum_flags_test(E flags, E flag) noexcept -> detail::enable_if_t { 198 | using U = underlying_type_t; 199 | 200 | return static_cast(flag) && ((static_cast(flags) & static_cast(flag)) == static_cast(flag)); 201 | } 202 | 203 | // Checks whether `lhs flags set` and `rhs flags set` have common flags. 204 | // Note: If `lhs flags set` or `rhs flags set` equals 0, it returns false, as 0 is not a flag, and therfore cannot have any matching flag. 205 | template 206 | constexpr auto enum_flags_test_any(E lhs, E rhs) noexcept -> detail::enable_if_t { 207 | using U = underlying_type_t; 208 | 209 | return (static_cast(lhs) & static_cast(rhs)) != 0; 210 | } 211 | 212 | } // namespace magic_enum 213 | 214 | #if defined(__clang__) 215 | # pragma clang diagnostic pop 216 | #elif defined(__GNUC__) 217 | # pragma GCC diagnostic pop 218 | #elif defined(_MSC_VER) 219 | # pragma warning(pop) 220 | #endif 221 | 222 | #endif // NEARGYE_MAGIC_ENUM_FLAGS_HPP 223 | -------------------------------------------------------------------------------- /include/magic_enum/magic_enum_format.hpp: -------------------------------------------------------------------------------- 1 | // __ __ _ ______ _____ 2 | // | \/ | (_) | ____| / ____|_ _ 3 | // | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ 4 | // | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| 5 | // | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| 6 | // |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| 7 | // __/ | https://github.com/Neargye/magic_enum 8 | // |___/ version 0.9.7 9 | // 10 | // Licensed under the MIT License . 11 | // SPDX-License-Identifier: MIT 12 | // Copyright (c) 2019 - 2024 Daniil Goncharov . 13 | // 14 | // Permission is hereby granted, free of charge, to any person obtaining a copy 15 | // of this software and associated documentation files (the "Software"), to deal 16 | // in the Software without restriction, including without limitation the rights 17 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | // copies of the Software, and to permit persons to whom the Software is 19 | // furnished to do so, subject to the following conditions: 20 | // 21 | // The above copyright notice and this permission notice shall be included in all 22 | // copies or substantial portions of the Software. 23 | // 24 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 | // SOFTWARE. 31 | 32 | #ifndef NEARGYE_MAGIC_ENUM_FORMAT_HPP 33 | #define NEARGYE_MAGIC_ENUM_FORMAT_HPP 34 | 35 | #include "magic_enum.hpp" 36 | #include "magic_enum_flags.hpp" 37 | 38 | namespace magic_enum::detail { 39 | 40 | template >, int> = 0> 41 | std::string format_as(E e) { 42 | using D = std::decay_t; 43 | static_assert(std::is_same_v, "magic_enum::formatter requires string_view::value_type type same as char."); 44 | if constexpr (magic_enum::detail::supported::value) { 45 | if constexpr (magic_enum::detail::subtype_v == magic_enum::detail::enum_subtype::flags) { 46 | if (const auto name = magic_enum::enum_flags_name(e); !name.empty()) { 47 | return {name.data(), name.size()}; 48 | } 49 | } else { 50 | if (const auto name = magic_enum::enum_name(e); !name.empty()) { 51 | return {name.data(), name.size()}; 52 | } 53 | } 54 | } 55 | return std::to_string(magic_enum::enum_integer(e)); 56 | } 57 | 58 | } // namespace magic_enum::format 59 | 60 | #if defined(__cpp_lib_format) 61 | 62 | template 63 | struct std::formatter>, char>> : std::formatter { 64 | template 65 | auto format(E e, FormatContext& ctx) const { 66 | return std::formatter::format(magic_enum::detail::format_as(e), ctx); 67 | } 68 | }; 69 | 70 | #endif 71 | 72 | #if defined(FMT_VERSION) 73 | 74 | template 75 | struct fmt::formatter>, char>> : fmt::formatter { 76 | template 77 | auto format(E e, FormatContext& ctx) const { 78 | return fmt::formatter::format(magic_enum::detail::format_as(e), ctx); 79 | } 80 | }; 81 | 82 | #endif 83 | 84 | #endif // NEARGYE_MAGIC_ENUM_FORMAT_HPP 85 | -------------------------------------------------------------------------------- /include/magic_enum/magic_enum_fuse.hpp: -------------------------------------------------------------------------------- 1 | // __ __ _ ______ _____ 2 | // | \/ | (_) | ____| / ____|_ _ 3 | // | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ 4 | // | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| 5 | // | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| 6 | // |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| 7 | // __/ | https://github.com/Neargye/magic_enum 8 | // |___/ version 0.9.7 9 | // 10 | // Licensed under the MIT License . 11 | // SPDX-License-Identifier: MIT 12 | // Copyright (c) 2019 - 2024 Daniil Goncharov . 13 | // 14 | // Permission is hereby granted, free of charge, to any person obtaining a copy 15 | // of this software and associated documentation files (the "Software"), to deal 16 | // in the Software without restriction, including without limitation the rights 17 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | // copies of the Software, and to permit persons to whom the Software is 19 | // furnished to do so, subject to the following conditions: 20 | // 21 | // The above copyright notice and this permission notice shall be included in all 22 | // copies or substantial portions of the Software. 23 | // 24 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 | // SOFTWARE. 31 | 32 | #ifndef NEARGYE_MAGIC_ENUM_FUSE_HPP 33 | #define NEARGYE_MAGIC_ENUM_FUSE_HPP 34 | 35 | #include "magic_enum.hpp" 36 | 37 | namespace magic_enum { 38 | 39 | namespace detail { 40 | 41 | template 42 | constexpr optional fuse_one_enum(optional hash, E value) noexcept { 43 | if (hash) { 44 | if (const auto index = enum_index(value)) { 45 | return (*hash << log2((enum_count() << 1) - 1)) | *index; 46 | } 47 | } 48 | return {}; 49 | } 50 | 51 | template 52 | constexpr optional fuse_enum(E value) noexcept { 53 | return fuse_one_enum(0, value); 54 | } 55 | 56 | template 57 | constexpr optional fuse_enum(E head, Es... tail) noexcept { 58 | return fuse_one_enum(fuse_enum(tail...), head); 59 | } 60 | 61 | template 62 | constexpr auto typesafe_fuse_enum(Es... values) noexcept { 63 | enum class enum_fuse_t : std::uintmax_t; 64 | const auto fuse = fuse_enum(values...); 65 | if (fuse) { 66 | return optional{static_cast(*fuse)}; 67 | } 68 | return optional{}; 69 | } 70 | 71 | } // namespace magic_enum::detail 72 | 73 | // Returns a bijective mix of several enum values. This can be used to emulate 2D switch/case statements. 74 | template 75 | [[nodiscard]] constexpr auto enum_fuse(Es... values) noexcept { 76 | static_assert((std::is_enum_v> && ...), "magic_enum::enum_fuse requires enum type."); 77 | static_assert(sizeof...(Es) >= 2, "magic_enum::enum_fuse requires at least 2 values."); 78 | static_assert((detail::log2(enum_count>() + 1) + ...) <= (sizeof(std::uintmax_t) * 8), "magic_enum::enum_fuse does not work for large enums"); 79 | #if defined(MAGIC_ENUM_NO_TYPESAFE_ENUM_FUSE) 80 | const auto fuse = detail::fuse_enum...>(values...); 81 | #else 82 | const auto fuse = detail::typesafe_fuse_enum...>(values...); 83 | #endif 84 | return MAGIC_ENUM_ASSERT(fuse), fuse; 85 | } 86 | 87 | } // namespace magic_enum 88 | 89 | #endif // NEARGYE_MAGIC_ENUM_FUSE_HPP 90 | -------------------------------------------------------------------------------- /include/magic_enum/magic_enum_iostream.hpp: -------------------------------------------------------------------------------- 1 | // __ __ _ ______ _____ 2 | // | \/ | (_) | ____| / ____|_ _ 3 | // | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ 4 | // | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| 5 | // | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| 6 | // |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| 7 | // __/ | https://github.com/Neargye/magic_enum 8 | // |___/ version 0.9.7 9 | // 10 | // Licensed under the MIT License . 11 | // SPDX-License-Identifier: MIT 12 | // Copyright (c) 2019 - 2024 Daniil Goncharov . 13 | // 14 | // Permission is hereby granted, free of charge, to any person obtaining a copy 15 | // of this software and associated documentation files (the "Software"), to deal 16 | // in the Software without restriction, including without limitation the rights 17 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | // copies of the Software, and to permit persons to whom the Software is 19 | // furnished to do so, subject to the following conditions: 20 | // 21 | // The above copyright notice and this permission notice shall be included in all 22 | // copies or substantial portions of the Software. 23 | // 24 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 | // SOFTWARE. 31 | 32 | #ifndef NEARGYE_MAGIC_ENUM_IOSTREAM_HPP 33 | #define NEARGYE_MAGIC_ENUM_IOSTREAM_HPP 34 | 35 | #include "magic_enum.hpp" 36 | #include "magic_enum_flags.hpp" 37 | 38 | #ifndef MAGIC_ENUM_USE_STD_MODULE 39 | #include 40 | #endif 41 | 42 | namespace magic_enum { 43 | 44 | namespace ostream_operators { 45 | 46 | template = 0> 47 | std::basic_ostream& operator<<(std::basic_ostream& os, E value) { 48 | using D = std::decay_t; 49 | using U = underlying_type_t; 50 | 51 | if constexpr (detail::supported::value) { 52 | if constexpr (detail::subtype_v == detail::enum_subtype::flags) { 53 | if (const auto name = enum_flags_name(value); !name.empty()) { 54 | for (const auto c : name) { 55 | os.put(c); 56 | } 57 | return os; 58 | } 59 | } else { 60 | if (const auto name = enum_name(value); !name.empty()) { 61 | for (const auto c : name) { 62 | os.put(c); 63 | } 64 | return os; 65 | } 66 | } 67 | } 68 | return (os << static_cast(value)); 69 | } 70 | 71 | template = 0> 72 | std::basic_ostream& operator<<(std::basic_ostream& os, optional value) { 73 | return value ? (os << *value) : os; 74 | } 75 | 76 | } // namespace magic_enum::ostream_operators 77 | 78 | namespace istream_operators { 79 | 80 | template = 0> 81 | std::basic_istream& operator>>(std::basic_istream& is, E& value) { 82 | using D = std::decay_t; 83 | 84 | std::basic_string s; 85 | is >> s; 86 | if constexpr (detail::supported::value) { 87 | if constexpr (detail::subtype_v == detail::enum_subtype::flags) { 88 | if (const auto v = enum_flags_cast(s)) { 89 | value = *v; 90 | } else { 91 | is.setstate(std::basic_ios::failbit); 92 | } 93 | } else { 94 | if (const auto v = enum_cast(s)) { 95 | value = *v; 96 | } else { 97 | is.setstate(std::basic_ios::failbit); 98 | } 99 | } 100 | } else { 101 | is.setstate(std::basic_ios::failbit); 102 | } 103 | return is; 104 | } 105 | 106 | } // namespace magic_enum::istream_operators 107 | 108 | namespace iostream_operators { 109 | 110 | using magic_enum::ostream_operators::operator<<; 111 | using magic_enum::istream_operators::operator>>; 112 | 113 | } // namespace magic_enum::iostream_operators 114 | 115 | } // namespace magic_enum 116 | 117 | #endif // NEARGYE_MAGIC_ENUM_IOSTREAM_HPP 118 | -------------------------------------------------------------------------------- /include/magic_enum/magic_enum_switch.hpp: -------------------------------------------------------------------------------- 1 | // __ __ _ ______ _____ 2 | // | \/ | (_) | ____| / ____|_ _ 3 | // | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ 4 | // | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| 5 | // | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| 6 | // |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| 7 | // __/ | https://github.com/Neargye/magic_enum 8 | // |___/ version 0.9.7 9 | // 10 | // Licensed under the MIT License . 11 | // SPDX-License-Identifier: MIT 12 | // Copyright (c) 2019 - 2024 Daniil Goncharov . 13 | // 14 | // Permission is hereby granted, free of charge, to any person obtaining a copy 15 | // of this software and associated documentation files (the "Software"), to deal 16 | // in the Software without restriction, including without limitation the rights 17 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | // copies of the Software, and to permit persons to whom the Software is 19 | // furnished to do so, subject to the following conditions: 20 | // 21 | // The above copyright notice and this permission notice shall be included in all 22 | // copies or substantial portions of the Software. 23 | // 24 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 | // SOFTWARE. 31 | 32 | #ifndef NEARGYE_MAGIC_ENUM_SWITCH_HPP 33 | #define NEARGYE_MAGIC_ENUM_SWITCH_HPP 34 | 35 | #include "magic_enum.hpp" 36 | 37 | namespace magic_enum { 38 | 39 | namespace detail { 40 | 41 | struct default_result_type {}; 42 | 43 | template 44 | struct identity { 45 | using type = T; 46 | }; 47 | 48 | struct nonesuch {}; 49 | 50 | template > 51 | struct invoke_result : identity {}; 52 | 53 | template 54 | struct invoke_result : std::invoke_result {}; 55 | 56 | template 57 | using invoke_result_t = typename invoke_result::type; 58 | 59 | template 60 | constexpr auto common_invocable(std::index_sequence) noexcept { 61 | static_assert(std::is_enum_v, "magic_enum::detail::invocable_index requires enum type."); 62 | 63 | if constexpr (count_v == 0) { 64 | return identity{}; 65 | } else { 66 | return std::common_type[I]>>...>{}; 67 | } 68 | } 69 | 70 | template 71 | constexpr auto result_type() noexcept { 72 | static_assert(std::is_enum_v, "magic_enum::detail::result_type requires enum type."); 73 | 74 | constexpr auto seq = std::make_index_sequence>{}; 75 | using R = typename decltype(common_invocable(seq))::type; 76 | if constexpr (std::is_same_v) { 77 | if constexpr (std::is_same_v) { 78 | return identity{}; 79 | } else { 80 | return identity{}; 81 | } 82 | } else { 83 | if constexpr (std::is_convertible_v) { 84 | return identity{}; 85 | } else if constexpr (std::is_convertible_v) { 86 | return identity{}; 87 | } else { 88 | return identity{}; 89 | } 90 | } 91 | } 92 | 93 | template , typename R = typename decltype(result_type())::type> 94 | using result_t = std::enable_if_t && !std::is_same_v, R>; 95 | 96 | #if !defined(MAGIC_ENUM_ENABLE_HASH) && !defined(MAGIC_ENUM_ENABLE_HASH_SWITCH) 97 | 98 | template 99 | inline constexpr auto default_result_type_lambda = []() noexcept(std::is_nothrow_default_constructible_v) { return T{}; }; 100 | 101 | template <> 102 | inline constexpr auto default_result_type_lambda = []() noexcept {}; 103 | 104 | template 105 | constexpr decltype(auto) constexpr_switch_impl(F&& f, E value, Def&& def) { 106 | if constexpr(I < End) { 107 | constexpr auto v = enum_constant()>{}; 108 | if (value == v) { 109 | if constexpr (std::is_invocable_r_v) { 110 | return static_cast(std::forward(f)(v)); 111 | } else { 112 | return def(); 113 | } 114 | } else { 115 | return constexpr_switch_impl(std::forward(f), value, std::forward(def)); 116 | } 117 | } else { 118 | return def(); 119 | } 120 | } 121 | 122 | template 123 | constexpr decltype(auto) constexpr_switch(F&& f, E value, Def&& def) { 124 | static_assert(is_enum_v, "magic_enum::detail::constexpr_switch requires enum type."); 125 | 126 | if constexpr (count_v == 0) { 127 | return def(); 128 | } else { 129 | return constexpr_switch_impl<0, count_v, R, E, S>(std::forward(f), value, std::forward(def)); 130 | } 131 | } 132 | #endif 133 | 134 | } // namespace magic_enum::detail 135 | 136 | template , typename F, typename R = detail::result_t> 137 | constexpr decltype(auto) enum_switch(F&& f, E value) { 138 | using D = std::decay_t; 139 | static_assert(std::is_enum_v, "magic_enum::enum_switch requires enum type."); 140 | static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); 141 | 142 | #if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH) 143 | return detail::constexpr_switch<&detail::values_v, detail::case_call_t::value>( 144 | std::forward(f), 145 | value, 146 | detail::default_result_type_lambda); 147 | #else 148 | return detail::constexpr_switch( 149 | std::forward(f), 150 | value, 151 | detail::default_result_type_lambda); 152 | #endif 153 | } 154 | 155 | template > 156 | constexpr decltype(auto) enum_switch(F&& f, E value) { 157 | return enum_switch(std::forward(f), value); 158 | } 159 | 160 | template , typename F, typename R = detail::result_t> 161 | constexpr decltype(auto) enum_switch(F&& f, E value, Result&& result) { 162 | using D = std::decay_t; 163 | static_assert(std::is_enum_v, "magic_enum::enum_switch requires enum type."); 164 | static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); 165 | 166 | #if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH) 167 | return detail::constexpr_switch<&detail::values_v, detail::case_call_t::value>( 168 | std::forward(f), 169 | value, 170 | [&result]() -> R { return std::forward(result); }); 171 | #else 172 | return detail::constexpr_switch( 173 | std::forward(f), 174 | value, 175 | [&result]() -> R { return std::forward(result); }); 176 | #endif 177 | } 178 | 179 | template > 180 | constexpr decltype(auto) enum_switch(F&& f, E value, Result&& result) { 181 | return enum_switch(std::forward(f), value, std::forward(result)); 182 | } 183 | 184 | } // namespace magic_enum 185 | 186 | template <> 187 | struct std::common_type : magic_enum::detail::identity {}; 188 | 189 | template 190 | struct std::common_type : magic_enum::detail::identity {}; 191 | 192 | template 193 | struct std::common_type : magic_enum::detail::identity {}; 194 | 195 | #endif // NEARGYE_MAGIC_ENUM_SWITCH_HPP 196 | -------------------------------------------------------------------------------- /include/magic_enum/magic_enum_utility.hpp: -------------------------------------------------------------------------------- 1 | // __ __ _ ______ _____ 2 | // | \/ | (_) | ____| / ____|_ _ 3 | // | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ 4 | // | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| 5 | // | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| 6 | // |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| 7 | // __/ | https://github.com/Neargye/magic_enum 8 | // |___/ version 0.9.7 9 | // 10 | // Licensed under the MIT License . 11 | // SPDX-License-Identifier: MIT 12 | // Copyright (c) 2019 - 2024 Daniil Goncharov . 13 | // 14 | // Permission is hereby granted, free of charge, to any person obtaining a copy 15 | // of this software and associated documentation files (the "Software"), to deal 16 | // in the Software without restriction, including without limitation the rights 17 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 18 | // copies of the Software, and to permit persons to whom the Software is 19 | // furnished to do so, subject to the following conditions: 20 | // 21 | // The above copyright notice and this permission notice shall be included in all 22 | // copies or substantial portions of the Software. 23 | // 24 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 25 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 26 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 27 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 28 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 29 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 | // SOFTWARE. 31 | 32 | #ifndef NEARGYE_MAGIC_ENUM_UTILITY_HPP 33 | #define NEARGYE_MAGIC_ENUM_UTILITY_HPP 34 | 35 | #include "magic_enum.hpp" 36 | 37 | namespace magic_enum { 38 | 39 | namespace detail { 40 | 41 | template 42 | constexpr auto for_each(F&& f, std::index_sequence) { 43 | constexpr bool has_void_return = (std::is_void_v[I]>>> || ...); 44 | constexpr bool all_same_return = (std::is_same_v[0]>>, std::invoke_result_t[I]>>> && ...); 45 | 46 | if constexpr (has_void_return) { 47 | (f(enum_constant[I]>{}), ...); 48 | } else if constexpr (all_same_return) { 49 | return std::array{f(enum_constant[I]>{})...}; 50 | } else { 51 | return std::tuple{f(enum_constant[I]>{})...}; 52 | } 53 | } 54 | 55 | template 56 | constexpr bool all_invocable(std::index_sequence) { 57 | if constexpr (count_v == 0) { 58 | return false; 59 | } else { 60 | return (std::is_invocable_v[I]>> && ...); 61 | } 62 | } 63 | 64 | } // namespace magic_enum::detail 65 | 66 | template , typename F, detail::enable_if_t = 0> 67 | constexpr auto enum_for_each(F&& f) { 68 | using D = std::decay_t; 69 | static_assert(std::is_enum_v, "magic_enum::enum_for_each requires enum type."); 70 | static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); 71 | constexpr auto sep = std::make_index_sequence>{}; 72 | 73 | if constexpr (detail::all_invocable(sep)) { 74 | return detail::for_each(std::forward(f), sep); 75 | } else { 76 | static_assert(detail::always_false_v, "magic_enum::enum_for_each requires invocable of all enum value."); 77 | } 78 | } 79 | 80 | template > 81 | [[nodiscard]] constexpr auto enum_next_value(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t>> { 82 | using D = std::decay_t; 83 | constexpr std::ptrdiff_t count = detail::count_v; 84 | 85 | if (const auto i = enum_index(value)) { 86 | const std::ptrdiff_t index = (static_cast(*i) + n); 87 | if (index >= 0 && index < count) { 88 | return enum_value(static_cast(index)); 89 | } 90 | } 91 | return {}; 92 | } 93 | 94 | template > 95 | [[nodiscard]] constexpr auto enum_next_value_circular(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t> { 96 | using D = std::decay_t; 97 | constexpr std::ptrdiff_t count = detail::count_v; 98 | 99 | if (const auto i = enum_index(value)) { 100 | const std::ptrdiff_t index = ((((static_cast(*i) + n) % count) + count) % count); 101 | if (index >= 0 && index < count) { 102 | return enum_value(static_cast(index)); 103 | } 104 | } 105 | return MAGIC_ENUM_ASSERT(false), value; 106 | } 107 | 108 | template > 109 | [[nodiscard]] constexpr auto enum_prev_value(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t>> { 110 | using D = std::decay_t; 111 | constexpr std::ptrdiff_t count = detail::count_v; 112 | 113 | if (const auto i = enum_index(value)) { 114 | const std::ptrdiff_t index = (static_cast(*i) - n); 115 | if (index >= 0 && index < count) { 116 | return enum_value(static_cast(index)); 117 | } 118 | } 119 | return {}; 120 | } 121 | 122 | template > 123 | [[nodiscard]] constexpr auto enum_prev_value_circular(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t> { 124 | using D = std::decay_t; 125 | constexpr std::ptrdiff_t count = detail::count_v; 126 | 127 | if (const auto i = enum_index(value)) { 128 | const std::ptrdiff_t index = ((((static_cast(*i) - n) % count) + count) % count); 129 | if (index >= 0 && index < count) { 130 | return enum_value(static_cast(index)); 131 | } 132 | } 133 | return MAGIC_ENUM_ASSERT(false), value; 134 | } 135 | 136 | } // namespace magic_enum 137 | 138 | #endif // NEARGYE_MAGIC_ENUM_UTILITY_HPP 139 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project( 2 | 'magic_enum', ['cpp'], 3 | default_options: ['cpp_std=c++17'], 4 | version: '0.9.7', 5 | ) 6 | 7 | magic_enum_include = include_directories('include') 8 | 9 | magic_enum_args = [] 10 | 11 | if get_option('hash') 12 | magic_enum_args += '-DMAGIC_ENUM_ENABLE_HASH' 13 | endif 14 | 15 | magic_enum_dep = declare_dependency( 16 | include_directories: magic_enum_include, 17 | compile_args: magic_enum_args, 18 | ) 19 | 20 | # install header and pkg-config file 21 | install_subdir('include/magic_enum', install_dir: get_option('includedir')) 22 | pkg = import('pkgconfig') 23 | pkg.generate( 24 | name: 'magic_enum', 25 | description: 'A library that provides static reflection for enums, work with any enum type without any macro or boilerplate code.', 26 | url: 'https://github.com/Neargye/magic_enum', 27 | extra_cflags: magic_enum_args, 28 | ) 29 | 30 | if get_option('test') 31 | subdir('test') 32 | endif 33 | -------------------------------------------------------------------------------- /meson_options.txt: -------------------------------------------------------------------------------- 1 | option( 2 | 'test', 3 | type : 'boolean', 4 | value : true, 5 | description : 'Build and run tests' 6 | ) 7 | 8 | option( 9 | 'hash', 10 | type : 'boolean', 11 | value : false, 12 | description : 'Do hashing at build time - longer build times, but O(1) string lookup' 13 | ) 14 | -------------------------------------------------------------------------------- /module/magic_enum.cppm: -------------------------------------------------------------------------------- 1 | module; 2 | 3 | #include 4 | #ifndef MAGIC_ENUM_USE_STD_MODULE 5 | #include 6 | #endif 7 | 8 | export module magic_enum; 9 | 10 | #ifdef MAGIC_ENUM_USE_STD_MODULE 11 | import std; 12 | 13 | extern "C++" { 14 | #pragma clang diagnostic push 15 | #pragma clang diagnostic ignored "-Winclude-angled-in-module-purview" 16 | #include 17 | #pragma clang diagnostic pop 18 | } 19 | #endif 20 | 21 | export namespace magic_enum { 22 | namespace customize { 23 | using customize::enum_range; 24 | } 25 | 26 | namespace iostream_operators { 27 | using iostream_operators::operator<<; 28 | using iostream_operators::operator>>; 29 | } 30 | 31 | namespace bitwise_operators { 32 | using bitwise_operators::operator~; 33 | using bitwise_operators::operator|; 34 | using bitwise_operators::operator&; 35 | using bitwise_operators::operator^; 36 | using bitwise_operators::operator|=; 37 | using bitwise_operators::operator&=; 38 | using bitwise_operators::operator^=; 39 | } 40 | 41 | namespace containers { 42 | using containers::array; 43 | using containers::bitset; 44 | using containers::set; 45 | } 46 | 47 | using magic_enum::enum_name; 48 | using magic_enum::enum_cast; 49 | using magic_enum::enum_value; 50 | using magic_enum::enum_values; 51 | using magic_enum::enum_count; 52 | using magic_enum::enum_integer; 53 | using magic_enum::enum_names; 54 | using magic_enum::enum_entries; 55 | using magic_enum::enum_fuse; 56 | using magic_enum::enum_switch; 57 | using magic_enum::enum_for_each; 58 | using magic_enum::enum_contains; 59 | using magic_enum::enum_index; 60 | using magic_enum::enum_flags_name; 61 | using magic_enum::enum_flags_contains; 62 | using magic_enum::enum_flags_cast; 63 | using magic_enum::enum_type_name; 64 | using magic_enum::is_unscoped_enum; 65 | using magic_enum::is_unscoped_enum_v; 66 | using magic_enum::is_scoped_enum; 67 | using magic_enum::is_scoped_enum_v; 68 | using magic_enum::underlying_type; 69 | using magic_enum::underlying_type_t; 70 | } 71 | 72 | #if defined(__cpp_lib_format) 73 | export namespace std { 74 | using std::formatter; 75 | } 76 | #endif 77 | -------------------------------------------------------------------------------- /package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | magic_enum 8 | 0.9.7 9 | 10 | Static reflection for enums (to string, from string, iteration) for modern C++, 11 | work with any enum type without any macro or boilerplate code 12 | 13 | 14 | Neargye 15 | MIT 16 | 17 | cmake 18 | 19 | 20 | cmake 21 | 22 | 23 | -------------------------------------------------------------------------------- /test/.bazelrc: -------------------------------------------------------------------------------- 1 | import %workspace%/../.bazelrc 2 | 3 | -------------------------------------------------------------------------------- /test/3rdparty/Catch2/LICENSE: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /test/BUILD.bazel: -------------------------------------------------------------------------------- 1 | _TESTS = [ 2 | "test", 3 | "test_flags", 4 | ] 5 | 6 | _MSVC_FLAGS = ["/std:c++17", "/permissive-"] 7 | _COPTS = select({ 8 | "//conditions:default": ["-std=c++17"], 9 | "@rules_cc//cc/compiler:msvc-cl": _MSVC_FLAGS, 10 | "@rules_cc//cc/compiler:clang-cl": _MSVC_FLAGS, 11 | }) 12 | [cc_test( 13 | name = test, 14 | srcs = ["{}.cpp".format(test)], 15 | deps = ["@magic_enum", ":catch2"], 16 | copts = _COPTS, 17 | ) for test in _TESTS] 18 | 19 | # bazel central registry has a catch2 module, but is newer than the one included 20 | # in this repository 21 | cc_library( 22 | name = "catch2", 23 | includes = ["3rdparty/Catch2/include"], 24 | hdrs = ["3rdparty/Catch2/include/catch2/catch.hpp"], 25 | ) 26 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(CheckCXXCompilerFlag) 2 | 3 | if(${MAGIC_ENUM_OPT_TEST_INSTALLED_VERSION}) 4 | find_package(magic_enum REQUIRED magic_enum) 5 | endif() 6 | 7 | if(${MAGIC_ENUM_OPT_TEST_INSTALLED_VERSION_PKGCONFIG}) 8 | find_package(PkgConfig) 9 | pkg_check_modules(magic_enum magic_enum) 10 | if(NOT magic_enum_FOUND) 11 | message( 12 | WARNING 13 | "magic_enum via pkgconfig is not found. \ 14 | Next code will try check possible places for some platforms, \ 15 | but there's no guarantee. \ 16 | If you know where the magic_enum pkgconfig files (.pc) are, \ 17 | then specify yourself variable \$\{CMAKE_PREFIX_PATH\} \ 18 | with folder like /a/path/to/magic_enum (for POSIX-like pathes), \ 19 | where in the folder exists share/pkgconfig/magic_enum.pc ." 20 | ) 21 | if(UNIX AND EXISTS "/usr/local/share/pkgconfig/magic_enum.pc") 22 | message(DEBUG "\$\{CMAKE_PREFIX_PATH\} : ${CMAKE_PREFIX_PATH} ") 23 | set(CMAKE_PREFIX_PATH "/usr/local") 24 | message(DEBUG "\$\{CMAKE_PREFIX_PATH\} : ${CMAKE_PREFIX_PATH} ") 25 | pkg_check_modules(magic_enum magic_enum) 26 | endif() 27 | # code place for future workarounds for other platforms... 28 | if(NOT magic_enum_FOUND) 29 | message(FATAL_ERROR "Could not find magic_enum's config. Read a warning above.") 30 | endif() 31 | endif() 32 | message(DEBUG "magic_enum_FOUND : ${magic_enum_FOUND}") 33 | message(DEBUG "magic_enum_LIBRARIES: ${magic_enum_LIBRARIES}") 34 | message(DEBUG "magic_enum_LINK_LIBRARIES: ${magic_enum_LINK_LIBRARIES}") 35 | message(DEBUG "magic_enum_LIBRARY_DIRS: ${magic_enum_LIBRARY_DIRS}") 36 | message(DEBUG "magic_enum_INCLUDE_DIRS: ${magic_enum_INCLUDE_DIRS}") 37 | message(DEBUG "magic_enum_INCLUDE_DIR: ${magic_enum_INCLUDE_DIR}") 38 | message(DEBUG "magic_enum_LDFLAGS: ${magic_enum_LDFLAGS}") 39 | message(DEBUG "magic_enum_LDFLAGS_OTHER: ${magic_enum_LDFLAGS_OTHER}") 40 | message(DEBUG "magic_enum_CFLAGS: ${magic_enum_CFLAGS}") 41 | message(DEBUG "magic_enum_CFLAGS_OTHER: ${magic_enum_CFLAGS_OTHER}") 42 | message(DEBUG "magic_enum_INCLUDEDIR: ${magic_enum_INCLUDEDIR}") 43 | message(DEBUG "magic_enum_LIBDIR: ${magic_enum_LIBDIR}") 44 | message(DEBUG "magic_enum_PREFIX: ${magic_enum_PREFIX}") 45 | endif() 46 | 47 | if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") 48 | set(OPTIONS /W4 /WX) 49 | check_cxx_compiler_flag(/permissive HAS_PERMISSIVE_FLAG) 50 | if(HAS_PERMISSIVE_FLAG) 51 | set(OPTIONS ${OPTIONS} /permissive-) 52 | endif() 53 | 54 | check_cxx_compiler_flag(/std:c++20 HAS_CPP20_FLAG) 55 | check_cxx_compiler_flag(/std:c++23 HAS_CPP23_FLAG) 56 | check_cxx_compiler_flag(/std:c++latest HAS_CPPLATEST_FLAG) 57 | elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") 58 | set(CMAKE_VERBOSE_MAKEFILE ON) 59 | set(OPTIONS -Wall -Wextra -Wshadow -pedantic-errors -Werror) 60 | 61 | check_cxx_compiler_flag(-std=c++20 HAS_CPP20_FLAG) 62 | check_cxx_compiler_flag(-std=c++23 HAS_CPP23_FLAG) 63 | endif() 64 | 65 | function(make_test src target std) 66 | add_executable(${target} ${src}) 67 | target_compile_options(${target} PRIVATE ${OPTIONS}) 68 | target_include_directories(${target} PRIVATE 3rdparty/Catch2/include) 69 | if(${MAGIC_ENUM_OPT_TEST_INSTALLED_VERSION_PKGCONFIG}) 70 | target_include_directories(${target} PRIVATE ${magic_enum_INCLUDE_DIRS}) 71 | else() 72 | target_link_libraries(${target} PRIVATE magic_enum::magic_enum) 73 | endif() 74 | set_target_properties(${target} PROPERTIES CXX_EXTENSIONS OFF) 75 | if(std) 76 | if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") 77 | target_compile_options(${target} PRIVATE /std:${std}) 78 | else() 79 | target_compile_options(${target} PRIVATE -std=${std}) 80 | endif() 81 | endif() 82 | add_test(NAME ${target} COMMAND ${target}) 83 | endfunction() 84 | 85 | make_test(test.cpp test-cpp17 c++17) 86 | make_test(test_flags.cpp test_flags-cpp17 c++17) 87 | make_test(test_aliases.cpp test_aliases-cpp17 c++17) 88 | make_test(test_containers.cpp test_containers-cpp17 c++17) 89 | make_test(test_wchar_t.cpp test_wchar_t-cpp17 c++17) 90 | 91 | if(MAGIC_ENUM_OPT_ENABLE_NONASCII) 92 | make_test(test_nonascii.cpp test_nonascii-cpp17 c++17) 93 | endif() 94 | 95 | if(HAS_CPP20_FLAG) 96 | make_test(test.cpp test-cpp20 c++20) 97 | make_test(test_flags.cpp test_flags-cpp20 c++20) 98 | make_test(test_aliases.cpp test_aliases-cpp20 c++20) 99 | make_test(test_containers.cpp test_containers-cpp20 c++20) 100 | make_test(test_wchar_t.cpp test_wchar_t-cpp20 c++20) 101 | if(MAGIC_ENUM_OPT_ENABLE_NONASCII) 102 | make_test(test_nonascii.cpp test_nonascii-cpp20 c++20) 103 | endif() 104 | endif() 105 | 106 | if(HAS_CPP23_FLAG) 107 | make_test(test.cpp test-cpp23 c++23) 108 | make_test(test_flags.cpp test_flags-cpp23 c++23) 109 | make_test(test_aliases.cpp test_aliases-cpp23 c++23) 110 | make_test(test_containers.cpp test_containers-cpp23 c++23) 111 | make_test(test_wchar_t.cpp test_wchar_t-cpp23 c++23) 112 | if(MAGIC_ENUM_OPT_ENABLE_NONASCII) 113 | make_test(test_nonascii.cpp test_nonascii-cpp23 c++23) 114 | endif() 115 | endif() 116 | 117 | if(HAS_CPPLATEST_FLAG) 118 | make_test(test.cpp test-cpplatest c++latest) 119 | make_test(test_flags.cpp test_flags-cpplatest c++latest) 120 | make_test(test_aliases.cpp test_aliases-cpplatest c++latest) 121 | make_test(test_containers.cpp test_containers-cpplatest c++latest) 122 | make_test(test_wchar_t.cpp test_wchar_t-cpplatest c++latest) 123 | if(MAGIC_ENUM_OPT_ENABLE_NONASCII) 124 | make_test(test_nonascii.cpp test_nonascii-cpplatest c++latest) 125 | endif() 126 | endif() 127 | -------------------------------------------------------------------------------- /test/MODULE.bazel: -------------------------------------------------------------------------------- 1 | module(name = "magic_enum_tests") 2 | 3 | bazel_dep(name = "magic_enum") 4 | local_path_override(module_name = "magic_enum", path = "..") 5 | 6 | bazel_dep(name = "rules_cc", version = "0.0.8") 7 | -------------------------------------------------------------------------------- /test/WORKSPACE.bazel: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Neargye/magic_enum/a413fcc9c46a020a746907136a384c227f3cd095/test/WORKSPACE.bazel -------------------------------------------------------------------------------- /test/meson.build: -------------------------------------------------------------------------------- 1 | catch2_dep = declare_dependency(include_directories: '3rdparty/Catch2/include') 2 | 3 | test_files = { 4 | 'basic test': files('test.cpp'), 5 | 'flags test': files('test_flags.cpp'), 6 | } 7 | 8 | foreach test_name, test_src : test_files 9 | test_exe = executable( 10 | test_name.underscorify(), 11 | test_src, 12 | 13 | dependencies: [magic_enum_dep, catch2_dep], 14 | ) 15 | 16 | test(test_name, test_exe) 17 | endforeach 18 | -------------------------------------------------------------------------------- /test/test_aliases.cpp: -------------------------------------------------------------------------------- 1 | // Licensed under the MIT License . 2 | // SPDX-License-Identifier: MIT 3 | // Copyright (c) 2019 - 2024 Daniil Goncharov . 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | #define CATCH_CONFIG_MAIN 28 | #include 29 | 30 | template 31 | struct MyOpt { 32 | constexpr MyOpt() : mHasValue{false}, val{} {} // required 33 | constexpr MyOpt(const T& v) : mHasValue{true}, val{v} {} // required 34 | constexpr const T& operator*() const { return val; } // required 35 | constexpr explicit operator bool() const { return mHasValue; } // required 36 | 37 | constexpr bool has_value() const { return mHasValue; } 38 | constexpr const T& value() const { return val; } 39 | 40 | private: 41 | bool mHasValue; 42 | T val; 43 | }; 44 | 45 | struct MyString { 46 | using value_type = char; // required 47 | static constexpr auto npos = std::string_view::npos; // required 48 | 49 | MyString() : str{} {} // required 50 | MyString(const char* s, std::size_t l) : str{s, l} {} // required 51 | bool empty() const { return str.empty(); } // required 52 | auto begin() const { return str.begin(); } // required 53 | auto end() const { return str.end(); } // required 54 | void append(std::size_t count, char c) { str.append(count, c); } // required 55 | void append(const char* s, std::size_t size) { str.append(s, size); } // required 56 | 57 | std::size_t size() const { return str.size(); } 58 | int compare(const char* s) const { return str.compare(s); } 59 | 60 | private: 61 | std::string str; 62 | }; 63 | 64 | struct MyStringView { 65 | using value_type = char; // required 66 | static constexpr auto npos = std::string_view::npos; // required 67 | 68 | constexpr MyStringView() : str{} {} // required 69 | constexpr MyStringView(const char* cstr, std::size_t size) : str{cstr, size} {} // required 70 | constexpr bool empty() const { return str.empty(); } // required 71 | constexpr std::size_t size() const { return str.size(); } // required 72 | constexpr const char* data() const { return str.data(); } // required 73 | constexpr const char& operator[](std::size_t i) const { return str[i]; } // required 74 | constexpr auto begin() const { return str.begin(); } // required 75 | constexpr auto end() const { return str.end(); } // required 76 | constexpr std::size_t find(char c) const { return str.find(c); } // required 77 | constexpr MyStringView substr(std::size_t p, std::size_t n) { return str.substr(p, n); } // required 78 | constexpr void remove_prefix(std::size_t n) { str.remove_prefix(n); } // required 79 | constexpr void remove_suffix(std::size_t n) { str.remove_suffix(n); } // required 80 | friend constexpr bool operator==(MyStringView lhs, MyStringView rhs); // required 81 | 82 | constexpr MyStringView(const char* cstr) : str{ cstr } {} 83 | constexpr int compare(const char* s) const { return str.compare(s); } 84 | 85 | private: 86 | std::string_view str; 87 | 88 | constexpr MyStringView(std::string_view s) : str{s} {} 89 | }; 90 | 91 | constexpr bool operator==(MyStringView lhs, MyStringView rhs) { 92 | return lhs.str == rhs.str; 93 | } 94 | 95 | #define MAGIC_ENUM_USING_ALIAS_OPTIONAL template using optional = MyOpt; 96 | #define MAGIC_ENUM_USING_ALIAS_STRING using string = MyString; 97 | #define MAGIC_ENUM_USING_ALIAS_STRING_VIEW using string_view = MyStringView; 98 | 99 | #include 100 | #include 101 | using namespace magic_enum; 102 | using namespace magic_enum::bitwise_operators; 103 | 104 | enum class Color { RED = 1, GREEN = 2, BLUE = 4 }; 105 | 106 | TEST_CASE("optional") { 107 | constexpr auto cr = enum_cast("RED"); 108 | REQUIRE(cr.has_value()); 109 | REQUIRE(cr.value() == Color::RED); 110 | 111 | constexpr auto cn = enum_cast("NONE"); 112 | REQUIRE_FALSE(cn.has_value()); 113 | } 114 | 115 | TEST_CASE("string") { 116 | auto cr = enum_flags_name(Color::RED); 117 | REQUIRE_FALSE(cr.empty()); 118 | REQUIRE(cr.compare("RED") == 0); 119 | 120 | auto crg = enum_flags_name(Color::RED | Color::GREEN); 121 | REQUIRE_FALSE(crg.empty()); 122 | REQUIRE(crg.compare("RED|GREEN") == 0); 123 | 124 | auto cn = enum_flags_name(Color{0}); 125 | REQUIRE(cn.empty()); 126 | REQUIRE(cn.size() == 0); 127 | } 128 | 129 | TEST_CASE("string_view") { 130 | auto cr = enum_name(Color::RED); 131 | REQUIRE_FALSE(cr.empty()); 132 | REQUIRE(cr.compare("RED") == 0); 133 | 134 | auto cn = enum_name(Color{0}); 135 | REQUIRE(cn.empty()); 136 | REQUIRE(cn.size() == 0); 137 | } 138 | -------------------------------------------------------------------------------- /test/test_containers.cpp: -------------------------------------------------------------------------------- 1 | // Licensed under the MIT License . 2 | // SPDX-License-Identifier: MIT 3 | // Copyright (c) 2019 - 2024 Daniil Goncharov . 4 | // Copyright (c) 2022 - 2023 Bela Schaum . 5 | // 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in all 14 | // copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | // SOFTWARE. 23 | 24 | #if defined(__clang__) 25 | # pragma clang diagnostic push 26 | #elif defined(__GNUC__) 27 | # pragma GCC diagnostic push 28 | #elif defined(_MSC_VER) 29 | # pragma warning(push) 30 | # pragma warning(disable : 4244) // warning C4244: 'argument': conversion from 'const T' to 'unsigned int', possible loss of data. 31 | #endif 32 | 33 | #define CATCH_CONFIG_MAIN 34 | #include 35 | 36 | #include 37 | #include 38 | 39 | #include 40 | 41 | enum class Color { RED = 1, GREEN = 2, BLUE = 4 }; 42 | template <> 43 | struct magic_enum::customize::enum_range { 44 | static constexpr bool is_flags = true; 45 | }; 46 | 47 | enum class Empty {}; 48 | 49 | struct RGB { 50 | 51 | std::uint8_t r {}; 52 | std::uint8_t g {}; 53 | std::uint8_t b {}; 54 | 55 | [[nodiscard]] constexpr bool empty() { return std::equal_to{}(r, g) && std::equal_to{}(g, b) && std::equal_to{}(b, 0); } 56 | 57 | [[nodiscard]] constexpr bool operator==(RGB rgb) const noexcept { return std::equal_to{}(r, rgb.r) && std::equal_to{}(g, rgb.g) && std::equal_to{}(b, rgb.b); } 58 | 59 | friend std::ostream& operator<<(std::ostream& ostream, RGB rgb) { 60 | 61 | ostream << "R=" << static_cast(rgb.r) << " G=" << static_cast(rgb.g) << " B=" << static_cast(rgb.b); 62 | return ostream; 63 | } 64 | }; 65 | 66 | template bool check_const([[maybe_unused]]T& element) { return false; } 67 | template bool check_const([[maybe_unused]]T const& element) { return true; } 68 | 69 | constexpr std::uint8_t color_max = std::numeric_limits::max(); 70 | 71 | TEST_CASE("containers_array") { 72 | 73 | using namespace magic_enum::bitwise_operators; 74 | using namespace magic_enum::ostream_operators; 75 | 76 | constexpr magic_enum::containers::array color_rgb_initializer {{{{color_max, 0, 0}, {0, color_max, 0}, {0, 0, color_max}}}}; 77 | REQUIRE(color_rgb_initializer.at(Color::RED) == RGB{color_max, 0, 0}); 78 | REQUIRE(color_rgb_initializer.at(Color::GREEN) == RGB{0, color_max, 0}); 79 | REQUIRE(color_rgb_initializer.at(Color::BLUE) == RGB{0, 0, color_max}); 80 | 81 | /* BUG: a sort will not survive the data integration */ 82 | magic_enum::containers::array color_rgb_container_int{{1U, 4U, 2U}}; 83 | 84 | // ENC: Direct convert to std::array 85 | // std::array compare_before {1U, 4U, 2U}; 86 | constexpr magic_enum::containers::array compare_before{{1U, 4U, 2U}}; 87 | REQUIRE(color_rgb_container_int == compare_before); 88 | 89 | constexpr auto colors = magic_enum::enum_values(); 90 | 91 | std::ignore = magic_enum::containers::get<0>(compare_before); 92 | std::ignore = magic_enum::containers::get<1>(compare_before); 93 | std::ignore = magic_enum::containers::get<2>(compare_before); 94 | 95 | std::ignore = magic_enum::containers::get(compare_before); 96 | std::ignore = magic_enum::containers::get(compare_before); 97 | std::ignore = magic_enum::containers::get(compare_before); 98 | 99 | REQUIRE(std::make_pair(colors[0], color_rgb_container_int[colors[0]]) == std::make_pair(Color::RED, 1U)); 100 | REQUIRE(std::make_pair(colors[1], color_rgb_container_int[colors[1]]) == std::make_pair(Color::GREEN, 4U)); 101 | REQUIRE(std::make_pair(colors[2], color_rgb_container_int[colors[2]]) == std::make_pair(Color::BLUE, 2U)); 102 | 103 | std::sort(std::begin(color_rgb_container_int), std::end(color_rgb_container_int)); 104 | 105 | // Missing: Direct convert to std::array 106 | // std::array compare_after {1U, 2U, 4U}; 107 | constexpr magic_enum::containers::array compare_after{{1U, 2U, 4U}}; 108 | REQUIRE(color_rgb_container_int == compare_after); 109 | 110 | std::ignore = magic_enum::containers::get<0>(compare_after); 111 | std::ignore = magic_enum::containers::get<1>(compare_after); 112 | std::ignore = magic_enum::containers::get<2>(compare_after); 113 | 114 | std::ignore = magic_enum::containers::get(compare_after); 115 | std::ignore = magic_enum::containers::get(compare_after); 116 | std::ignore = magic_enum::containers::get(compare_after); 117 | 118 | REQUIRE(std::make_pair(colors[0], color_rgb_container_int[colors[0]]) == std::make_pair(Color::RED, 1U)); 119 | REQUIRE(std::make_pair(colors[1], color_rgb_container_int[colors[1]]) == std::make_pair(Color::GREEN, 2U)); 120 | REQUIRE(std::make_pair(colors[2], color_rgb_container_int[colors[2]]) == std::make_pair(Color::BLUE, 4U)); 121 | 122 | auto color_rgb_container = magic_enum::containers::array(); 123 | REQUIRE_FALSE(color_rgb_container.empty()); 124 | REQUIRE(color_rgb_container.size() == 3); 125 | REQUIRE(magic_enum::enum_count() == color_rgb_container.size()); 126 | 127 | REQUIRE(color_rgb_container.at(Color::RED).empty()); 128 | REQUIRE(color_rgb_container.at(Color::GREEN).empty()); 129 | REQUIRE(color_rgb_container.at(Color::BLUE).empty()); 130 | REQUIRE_THROWS(color_rgb_container.at(Color::BLUE|Color::GREEN).empty()); 131 | 132 | color_rgb_container[Color::RED] = {color_max, 0, 0}; 133 | color_rgb_container[Color::GREEN] = {0, color_max, 0}; 134 | color_rgb_container[Color::BLUE] = {0, 0, color_max}; 135 | 136 | REQUIRE(color_rgb_container.at(Color::RED) == RGB{color_max, 0, 0}); 137 | REQUIRE(color_rgb_container.at(Color::GREEN) == RGB{0, color_max, 0}); 138 | REQUIRE(color_rgb_container.at(Color::BLUE) == RGB{0, 0, color_max}); 139 | 140 | REQUIRE(color_rgb_container.front() == RGB{color_max, 0, 0}); 141 | REQUIRE(color_rgb_container.back() == RGB{0, 0, color_max}); 142 | 143 | REQUIRE(magic_enum::containers::get(color_rgb_container) == RGB{color_max, 0, 0}); 144 | REQUIRE(magic_enum::containers::get(color_rgb_container) == RGB{0, color_max, 0}); 145 | REQUIRE(magic_enum::containers::get(color_rgb_container) == RGB{0, 0, color_max}); 146 | 147 | auto iterator = color_rgb_container.begin(); 148 | REQUIRE_FALSE(check_const(iterator)); 149 | REQUIRE(check_const(color_rgb_container.begin())); 150 | REQUIRE(check_const(color_rgb_container.cbegin())); 151 | 152 | auto color_rgb_container_compare = magic_enum::containers::array(); 153 | color_rgb_container_compare.fill({color_max, color_max, color_max}); 154 | REQUIRE_FALSE(color_rgb_container == color_rgb_container_compare); 155 | 156 | color_rgb_container_compare[Color::RED] = {color_max, 0, 0}; 157 | color_rgb_container_compare[Color::GREEN] = {0, color_max, 0}; 158 | color_rgb_container_compare[Color::BLUE] = {0, 0, color_max}; 159 | REQUIRE(color_rgb_container == color_rgb_container_compare); 160 | 161 | constexpr auto from_to_array = magic_enum::containers::to_array({{color_max, 0, 0}, {0, color_max, 0}, {0, 0, color_max}}); 162 | REQUIRE(from_to_array.at(Color::RED) == RGB{color_max, 0, 0}); 163 | REQUIRE(from_to_array.at(Color::GREEN) == RGB{0, color_max, 0}); 164 | REQUIRE(from_to_array.at(Color::BLUE) == RGB{0, 0, color_max}); 165 | } 166 | 167 | TEST_CASE("containers_bitset") { 168 | 169 | using namespace magic_enum::bitwise_operators; 170 | 171 | auto color_bitset = magic_enum::containers::bitset(); 172 | REQUIRE(color_bitset.to_string().empty()); 173 | REQUIRE(color_bitset.size() == 3); 174 | REQUIRE(magic_enum::enum_count() == color_bitset.size()); 175 | REQUIRE_FALSE(color_bitset.all()); 176 | REQUIRE_FALSE(color_bitset.any()); 177 | REQUIRE(color_bitset.none()); 178 | REQUIRE(color_bitset.count() == 0); 179 | 180 | color_bitset.set(Color::GREEN); 181 | REQUIRE_FALSE(color_bitset.all()); 182 | REQUIRE(color_bitset.any()); 183 | REQUIRE_FALSE(color_bitset.none()); 184 | REQUIRE(color_bitset.count() == 1); 185 | REQUIRE_FALSE(color_bitset.test(Color::RED)); 186 | REQUIRE(color_bitset.test(Color::GREEN)); 187 | REQUIRE_FALSE(color_bitset.test(Color::BLUE)); 188 | 189 | color_bitset.set(Color::BLUE); 190 | REQUIRE_FALSE(color_bitset.all()); 191 | REQUIRE(color_bitset.any()); 192 | REQUIRE_FALSE(color_bitset.none()); 193 | REQUIRE(color_bitset.count() == 2); 194 | REQUIRE_FALSE(color_bitset.test(Color::RED)); 195 | REQUIRE(color_bitset.test(Color::GREEN)); 196 | REQUIRE(color_bitset.test(Color::BLUE)); 197 | 198 | color_bitset.set(Color::RED); 199 | REQUIRE(color_bitset.all()); 200 | REQUIRE(color_bitset.any()); 201 | REQUIRE_FALSE(color_bitset.none()); 202 | REQUIRE(color_bitset.count() == 3); 203 | REQUIRE(color_bitset.test(Color::RED)); 204 | REQUIRE(color_bitset.test(Color::GREEN)); 205 | REQUIRE(color_bitset.test(Color::BLUE)); 206 | 207 | color_bitset.reset(); 208 | REQUIRE_FALSE(color_bitset.all()); 209 | REQUIRE_FALSE(color_bitset.any()); 210 | REQUIRE(color_bitset.none()); 211 | REQUIRE(color_bitset.count() == 0); 212 | REQUIRE_FALSE(color_bitset.test(Color::RED)); 213 | REQUIRE_FALSE(color_bitset.test(Color::GREEN)); 214 | REQUIRE_FALSE(color_bitset.test(Color::BLUE)); 215 | 216 | color_bitset.set(Color::RED); 217 | REQUIRE(color_bitset.test(Color::RED)); 218 | REQUIRE_FALSE(color_bitset.test(Color::GREEN)); 219 | REQUIRE_FALSE(color_bitset.test(Color::BLUE)); 220 | 221 | color_bitset.flip(); 222 | REQUIRE_FALSE(color_bitset.test(Color::RED)); 223 | REQUIRE(color_bitset.test(Color::GREEN)); 224 | REQUIRE(color_bitset.test(Color::BLUE)); 225 | 226 | constexpr magic_enum::containers::bitset color_bitset_all {Color::RED|Color::GREEN|Color::BLUE}; 227 | REQUIRE(color_bitset_all.to_string() == "RED|GREEN|BLUE"); 228 | REQUIRE(color_bitset_all.to_string( {}, '0', '1' ) == "111"); 229 | REQUIRE(color_bitset_all.to_ulong( {} ) == 7); 230 | REQUIRE(color_bitset_all.to_ullong( {} ) == 7); 231 | REQUIRE(color_bitset_all.all()); 232 | REQUIRE(color_bitset_all.any()); 233 | REQUIRE_FALSE(color_bitset_all.none()); 234 | 235 | constexpr magic_enum::containers::bitset color_bitset_red_green {Color::RED|Color::GREEN}; 236 | REQUIRE(color_bitset_red_green.to_string() == "RED|GREEN"); 237 | REQUIRE(color_bitset_red_green.to_string( {}, '0', '1' ) == "110"); 238 | REQUIRE(color_bitset_red_green.to_ulong( {} ) == 3); 239 | REQUIRE(color_bitset_red_green.to_ullong( {} ) == 3); 240 | REQUIRE_FALSE(color_bitset_red_green.all()); 241 | REQUIRE(color_bitset_red_green.any()); 242 | REQUIRE_FALSE(color_bitset_red_green.none()); 243 | } 244 | 245 | TEST_CASE("containers_set") { 246 | 247 | using namespace magic_enum::bitwise_operators; 248 | using namespace magic_enum::ostream_operators; 249 | 250 | auto color_set = magic_enum::containers::set(); 251 | REQUIRE(color_set.empty()); 252 | REQUIRE(color_set.size() == 0); 253 | REQUIRE_FALSE(magic_enum::enum_count() == color_set.size()); 254 | 255 | color_set.insert(Color::RED); 256 | std::ignore = color_set.insert(Color::RED); 257 | color_set.insert(Color::GREEN); 258 | color_set.insert(Color::BLUE); 259 | color_set.insert(Color::RED); 260 | color_set.insert(Color::RED|Color::GREEN); 261 | color_set.insert(Color::RED|Color::BLUE); 262 | color_set.insert(Color::GREEN|Color::BLUE); 263 | color_set.insert(Color::RED|Color::GREEN|Color::BLUE); 264 | 265 | REQUIRE_FALSE(color_set.empty()); 266 | REQUIRE(color_set.size() == 3); 267 | REQUIRE(magic_enum::enum_count() == color_set.size()); 268 | color_set.erase(Color::RED); 269 | color_set.erase(Color::GREEN); 270 | REQUIRE(magic_enum::enum_count() - 2 == color_set.size()); 271 | REQUIRE(color_set.count(Color::RED) == 0); 272 | REQUIRE_FALSE(color_set.contains(Color::GREEN)); 273 | REQUIRE(color_set.contains(Color::BLUE)); 274 | 275 | auto color_set_compare = magic_enum::containers::set(); 276 | color_set_compare.insert(Color::BLUE); 277 | color_set_compare.insert(Color::RED); 278 | color_set_compare.insert(Color::GREEN); 279 | 280 | constexpr magic_enum::containers::set color_set_filled = {Color::RED, Color::GREEN, Color::BLUE}; 281 | REQUIRE_FALSE(color_set_filled.empty()); 282 | REQUIRE(color_set_filled.size() == 3); 283 | REQUIRE(magic_enum::enum_count() == color_set_filled.size()); 284 | 285 | magic_enum::containers::set color_set_not_const = {Color::RED, Color::GREEN, Color::BLUE}; 286 | REQUIRE_FALSE(color_set_not_const.empty()); 287 | REQUIRE(color_set_not_const.size() == 3); 288 | REQUIRE(magic_enum::enum_count() == color_set_not_const.size()); 289 | color_set_not_const.clear(); 290 | REQUIRE(color_set_not_const.empty()); 291 | REQUIRE(color_set_not_const.size() == 0); 292 | REQUIRE_FALSE(magic_enum::enum_count() == color_set_not_const.size()); 293 | } 294 | 295 | TEST_CASE("map_like_container") { 296 | 297 | using namespace magic_enum::ostream_operators; 298 | 299 | std::vector> map {{Color::GREEN, {0, color_max, 0}}, {Color::BLUE, {0, 0, color_max}}, {Color::RED, {color_max, 0, 0}}}; 300 | for (auto [key, value] : map) { 301 | 302 | std::cout << "Key=" << key << " Value=" << value << std::endl; 303 | } 304 | auto compare = [](std::pair& lhs, 305 | std::pair& rhs) { 306 | return static_cast(lhs.first) < static_cast(rhs.first); 307 | }; 308 | std::sort(std::begin(map), std::end(map), compare); 309 | for (auto [key, value] : map) { 310 | 311 | std::cout << "Key=" << key << " Value=" << value << std::endl; 312 | } 313 | } 314 | -------------------------------------------------------------------------------- /test/test_nonascii.cpp: -------------------------------------------------------------------------------- 1 | // Licensed under the MIT License . 2 | // SPDX-License-Identifier: MIT 3 | // Copyright (c) 2019 - 2024 Daniil Goncharov . 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | #define CATCH_CONFIG_MAIN 24 | #include 25 | 26 | #undef MAGIC_ENUM_RANGE_MIN 27 | #define MAGIC_ENUM_RANGE_MIN -120 28 | #undef MAGIC_ENUM_RANGE_MAX 29 | #define MAGIC_ENUM_RANGE_MAX 120 30 | #include 31 | #include 32 | #include 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | enum class Language : int { 日本語 = 10, 한국어 = 20, English = 30, 😃 = 40, TVÅ = 50 }; 40 | 41 | enum class LanguageFlag : int { 42 | 日本語 = 1 << 1, 43 | 한국어 = 1 << 2, 44 | English = 1 << 3, 45 | 😃 = 1 << 4 46 | }; 47 | 48 | using namespace magic_enum; 49 | 50 | static_assert(is_magic_enum_supported, "magic_enum: Unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility)."); 51 | 52 | TEST_CASE("enum_cast") { 53 | SECTION("string") { 54 | constexpr auto lang = enum_cast("日本語"); 55 | REQUIRE(enum_cast("한국어").value() == Language::한국어); 56 | REQUIRE(enum_cast("English").value() == Language::English); 57 | REQUIRE(lang.value() == Language::日本語); 58 | REQUIRE(enum_cast("😃").value() == Language::😃); 59 | REQUIRE(enum_cast("TVÅ").value() == Language::TVÅ); 60 | REQUIRE_FALSE(enum_cast("Französisch").has_value()); 61 | } 62 | 63 | SECTION("integer") { 64 | constexpr auto lang = enum_cast(10); 65 | REQUIRE(enum_cast(20).value() == Language::한국어); 66 | REQUIRE(enum_cast(30).value() == Language::English); 67 | REQUIRE(lang.value() == Language::日本語); 68 | REQUIRE(enum_cast(40).value() == Language::😃); 69 | REQUIRE_FALSE(enum_cast(0).has_value()); 70 | } 71 | } 72 | 73 | TEST_CASE("enum_integer") { 74 | constexpr auto lang = enum_integer(Language::日本語); 75 | Language korean = Language::한국어; 76 | REQUIRE(enum_integer(korean) == 20); 77 | REQUIRE(enum_integer(Language::English) == 30); 78 | REQUIRE(enum_integer(Language::😃) == 40); 79 | REQUIRE(lang == 10); 80 | REQUIRE(enum_integer(static_cast(0)) == 0); 81 | } 82 | 83 | TEST_CASE("enum_index") { 84 | constexpr auto lang = enum_index(Language::日本語); 85 | Language korean = Language::한국어; 86 | REQUIRE(enum_index(korean) == 1); 87 | REQUIRE(enum_index(Language::English).value() == 2); 88 | REQUIRE(enum_index(Language::😃) == 3); 89 | REQUIRE(lang.value() == 0); 90 | REQUIRE_FALSE(enum_index(static_cast(0)).has_value()); 91 | } 92 | 93 | TEST_CASE("enum_contains") { 94 | SECTION("value") { 95 | constexpr auto lang = enum_contains(Language::日本語); 96 | Language korean = Language::한국어; 97 | REQUIRE(enum_contains(korean)); 98 | REQUIRE(enum_contains(Language::English)); 99 | REQUIRE(enum_contains(Language::😃)); 100 | REQUIRE(lang); 101 | } 102 | 103 | SECTION("integer") { 104 | constexpr auto lang = enum_integer(Language::日本語); 105 | REQUIRE(enum_contains(lang)); 106 | REQUIRE(enum_contains(Language::한국어)); 107 | REQUIRE(enum_contains(Language::😃)); 108 | REQUIRE_FALSE(enum_contains(static_cast(0))); 109 | } 110 | 111 | SECTION("string") { 112 | auto lang = std::string{"日本語"}; 113 | REQUIRE(enum_contains("한국어")); 114 | REQUIRE(enum_contains("English")); 115 | REQUIRE(enum_contains(lang)); 116 | REQUIRE(enum_contains("😃")); 117 | REQUIRE_FALSE(enum_contains("None")); 118 | } 119 | } 120 | 121 | TEST_CASE("enum_value") { 122 | constexpr auto lang = enum_value(3); 123 | REQUIRE(enum_value(0) == Language::日本語); 124 | REQUIRE(enum_value(1) == Language::한국어); 125 | REQUIRE(enum_value(2) == Language::English); 126 | REQUIRE(lang == Language::😃); 127 | } 128 | 129 | TEST_CASE("enum_values") { 130 | constexpr auto& s7 = enum_values(); 131 | REQUIRE(s7 == std::array{{Language::日本語, Language::한국어, Language::English, Language::😃, Language::TVÅ}}); 132 | } 133 | 134 | TEST_CASE("enum_count") { 135 | constexpr auto s7 = enum_count(); 136 | REQUIRE(s7 == 5); 137 | } 138 | 139 | TEST_CASE("enum_name") { 140 | SECTION("automatic storage") { 141 | constexpr Language lang = Language::日本語; 142 | constexpr auto lang_name = enum_name(lang); 143 | Language lk = Language::한국어; 144 | REQUIRE(enum_name(lk) == "한국어"); 145 | REQUIRE(enum_name(Language::English) == "English"); 146 | REQUIRE(lang_name == "日本語"); 147 | REQUIRE(enum_name(Language::😃) == "😃"); 148 | REQUIRE(enum_name(Language::TVÅ) == "TVÅ"); 149 | REQUIRE(enum_name(static_cast(0)).empty()); 150 | } 151 | 152 | SECTION("static storage") { 153 | constexpr Language lang = Language::日本語; 154 | constexpr auto lang_name = enum_name(); 155 | REQUIRE(enum_name() == "한국어"); 156 | REQUIRE(enum_name() == "English"); 157 | REQUIRE(lang_name == "日本語"); 158 | REQUIRE(enum_name() == "😃"); 159 | } 160 | } 161 | 162 | TEST_CASE("enum_names") { 163 | constexpr auto& s5 = enum_names(); 164 | REQUIRE(s5 == std::array{{"日本語", "한국어", "English", "😃", "TVÅ"}}); 165 | } 166 | 167 | TEST_CASE("enum_entries") { 168 | constexpr auto& s5 = enum_entries(); 169 | REQUIRE(s5 == std::array, 5>{{{Language::日本語, "日本語"}, {Language::한국어, "한국어"}, {Language::English, "English"}, {Language::😃, "😃"}, {Language::TVÅ, "TVÅ"}}}); 170 | } 171 | 172 | TEST_CASE("ostream_operators") { 173 | auto test_ostream = [](auto e, std::string name) { 174 | using namespace magic_enum::ostream_operators; 175 | std::stringstream ss; 176 | ss << e; 177 | REQUIRE(ss); 178 | REQUIRE(ss.str() == name); 179 | }; 180 | 181 | test_ostream(std::make_optional(Language::日本語), "日本語"); 182 | test_ostream(Language::한국어, "한국어"); 183 | test_ostream(Language::English, "English"); 184 | test_ostream(Language::😃, "😃"); 185 | test_ostream(static_cast(0), "0"); 186 | test_ostream(std::make_optional(static_cast(0)), "0"); 187 | } 188 | 189 | TEST_CASE("istream_operators") { 190 | auto test_istream = [](const auto e, std::string name) { 191 | using namespace magic_enum::istream_operators; 192 | std::istringstream ss(name); 193 | std::decay_t v; 194 | ss >> v; 195 | REQUIRE(ss); 196 | REQUIRE(v == e); 197 | }; 198 | 199 | test_istream(Language::한국어, "한국어"); 200 | test_istream(Language::English, "English"); 201 | test_istream(Language::😃, "😃"); 202 | } 203 | 204 | TEST_CASE("bitwise_operators") { 205 | using namespace magic_enum::bitwise_operators; 206 | 207 | SECTION("operator^") { 208 | REQUIRE(enum_integer(~Language::日本語) == ~enum_integer(Language::日本語)); 209 | } 210 | 211 | SECTION("operator|") { 212 | REQUIRE(enum_integer(Language::日本語 | Language::한국어) == (enum_integer(Language::日本語) | enum_integer(Language::한국어))); 213 | } 214 | 215 | SECTION("operator&") { 216 | REQUIRE(enum_integer(Language::日本語 & Language::한국어) == (enum_integer(Language::日本語) & enum_integer(Language::한국어))); 217 | 218 | } 219 | 220 | SECTION("operator^") { 221 | REQUIRE(enum_integer(Language::日本語 ^ Language::한국어) == (enum_integer(Language::日本語) ^ enum_integer(Language::한국어))); 222 | } 223 | 224 | SECTION("operator|=") { 225 | Language x5 = Language::日本語; 226 | x5 |= Language::한국어; 227 | REQUIRE(enum_integer(x5) == (enum_integer(Language::日本語) | enum_integer(Language::한국어))); 228 | } 229 | 230 | SECTION("operator&=") { 231 | Language x5 = Language::日本語; 232 | x5 &= Language::한국어; 233 | REQUIRE(enum_integer(x5) == (enum_integer(Language::日本語) & enum_integer(Language::한국어))); 234 | } 235 | 236 | SECTION("operator^=") { 237 | Language x5 = Language::日本語; 238 | x5 ^= Language::한국어; 239 | REQUIRE(enum_integer(x5) == (enum_integer(Language::日本語) ^ enum_integer(Language::한국어))); 240 | } 241 | } 242 | TEST_CASE("type_traits") { 243 | REQUIRE_FALSE(is_unscoped_enum_v); 244 | } 245 | 246 | TEST_CASE("enum_type_name") { 247 | REQUIRE(enum_type_name() == "Language"); 248 | } 249 | 250 | TEST_CASE("extrema") { 251 | SECTION("min") { 252 | REQUIRE(magic_enum::customize::enum_range::min == MAGIC_ENUM_RANGE_MIN); 253 | REQUIRE(magic_enum::detail::reflected_min>() == MAGIC_ENUM_RANGE_MIN); 254 | REQUIRE(magic_enum::detail::min_v> == 10); 255 | } 256 | 257 | SECTION("max") { 258 | REQUIRE(magic_enum::customize::enum_range::max == MAGIC_ENUM_RANGE_MAX); 259 | REQUIRE(magic_enum::detail::reflected_max>() == MAGIC_ENUM_RANGE_MAX); 260 | REQUIRE(magic_enum::detail::max_v> == 50); 261 | } 262 | } 263 | 264 | /* LanguageFlag tests */ 265 | TEST_CASE("flag enum_cast") { 266 | SECTION("string") { 267 | constexpr auto lang = enum_cast("日本語"); 268 | REQUIRE(enum_cast("한국어").value() == LanguageFlag::한국어); 269 | REQUIRE(enum_cast("English").value() == LanguageFlag::English); 270 | REQUIRE(lang.value() == LanguageFlag::日本語); 271 | REQUIRE(enum_cast("😃").value() == LanguageFlag::😃); 272 | REQUIRE_FALSE(enum_cast("None").has_value()); 273 | } 274 | 275 | SECTION("integer") { 276 | constexpr auto lang = enum_cast(1 << 1); 277 | REQUIRE(enum_cast(1 << 2).value() == LanguageFlag::한국어); 278 | REQUIRE(enum_cast(1 << 3).value() == LanguageFlag::English); 279 | REQUIRE(lang.value() == LanguageFlag::日本語); 280 | REQUIRE(enum_cast(1 << 4).value() == LanguageFlag::😃); 281 | REQUIRE_FALSE(enum_cast(0).has_value()); 282 | } 283 | } 284 | 285 | TEST_CASE("flag enum_index") { 286 | constexpr auto lang = enum_index(LanguageFlag::日本語); 287 | LanguageFlag korean = LanguageFlag::한국어; 288 | REQUIRE(enum_index(korean).value() == 1); 289 | REQUIRE(enum_index(LanguageFlag::English).value() == 2); 290 | REQUIRE(enum_index(LanguageFlag::😃).value() == 3); 291 | REQUIRE(lang.value() == 0); 292 | REQUIRE_FALSE(enum_index(static_cast(0)).has_value()); 293 | } 294 | 295 | TEST_CASE("flag enum_contains") { 296 | SECTION("value") { 297 | constexpr auto lang = enum_index(LanguageFlag::日本語); 298 | LanguageFlag korean = LanguageFlag::한국어; 299 | REQUIRE(enum_contains(korean)); 300 | REQUIRE(enum_contains(LanguageFlag::English)); 301 | REQUIRE(enum_contains(LanguageFlag::😃)); 302 | REQUIRE(lang); 303 | REQUIRE_FALSE(enum_contains(static_cast(0))); 304 | } 305 | 306 | SECTION("integer") { 307 | constexpr auto lang = enum_contains(1 << 1); 308 | REQUIRE(lang); 309 | REQUIRE(enum_contains(1 << 2)); 310 | REQUIRE(enum_contains(1 << 3)); 311 | REQUIRE(enum_contains(1 << 4)); 312 | REQUIRE_FALSE(enum_contains(static_cast(0))); 313 | } 314 | 315 | SECTION("string") { 316 | auto lang = std::string{"日本語"}; 317 | REQUIRE(enum_contains("한국어")); 318 | REQUIRE(enum_contains("English")); 319 | REQUIRE(enum_contains(lang)); 320 | REQUIRE(enum_contains("😃")); 321 | REQUIRE_FALSE(enum_contains("None")); 322 | } 323 | } 324 | 325 | 326 | TEST_CASE("flag enum_value") { 327 | constexpr auto lang = enum_value(3); 328 | REQUIRE(enum_value(0) == LanguageFlag::日本語); 329 | REQUIRE(enum_value(1) == LanguageFlag::한국어); 330 | REQUIRE(enum_value(2) == LanguageFlag::English); 331 | REQUIRE(lang == LanguageFlag::😃); 332 | } 333 | 334 | TEST_CASE("flag enum_values") { 335 | constexpr auto& s5 = enum_values(); 336 | REQUIRE(s5 == std::array{{LanguageFlag::日本語, LanguageFlag::한국어, LanguageFlag::English, LanguageFlag::😃}}); 337 | } 338 | 339 | TEST_CASE("flag enum_count") { 340 | constexpr auto s5 = enum_count(); 341 | REQUIRE(s5 == 4); 342 | } 343 | 344 | TEST_CASE("flag enum_name") { 345 | SECTION("automatic storage") { 346 | constexpr LanguageFlag lang = LanguageFlag::日本語; 347 | constexpr auto lang_name = enum_name(lang); 348 | LanguageFlag lk = LanguageFlag::한국어; 349 | REQUIRE(enum_name(lk) == "한국어"); 350 | REQUIRE(enum_name(LanguageFlag::English) == "English"); 351 | REQUIRE(lang_name == "日本語"); 352 | REQUIRE(enum_name(LanguageFlag::😃) == "😃"); 353 | REQUIRE(enum_name(static_cast(0)).empty()); 354 | } 355 | } 356 | 357 | TEST_CASE("flag enum_flags_name") { 358 | constexpr LanguageFlag lang = LanguageFlag::日本語; 359 | auto lang_name = enum_flags_name(lang); 360 | LanguageFlag lk = LanguageFlag::한국어; 361 | REQUIRE(enum_flags_name(lk) == "한국어"); 362 | REQUIRE(enum_flags_name(LanguageFlag::English) == "English"); 363 | REQUIRE(lang_name == "日本語"); 364 | REQUIRE(enum_flags_name(LanguageFlag::😃) == "😃"); 365 | REQUIRE(enum_flags_name(static_cast(0)).empty()); 366 | } 367 | 368 | TEST_CASE("flag enum_names") { 369 | constexpr auto& s5 = enum_names(); 370 | REQUIRE(s5 == std::array{{"日本語", "한국어", "English", "😃"}}); 371 | } 372 | 373 | TEST_CASE("flag enum_entries") { 374 | constexpr auto& s5 = enum_entries(); 375 | REQUIRE(s5 == std::array, 4>{{{LanguageFlag::日本語, "日本語"}, {LanguageFlag::한국어, "한국어"}, {LanguageFlag::English, "English"}, {LanguageFlag::😃, "😃"}}}); 376 | } 377 | 378 | TEST_CASE("flag ostream_operators") { 379 | auto test_ostream = [](auto e, std::string name) { 380 | using namespace magic_enum::ostream_operators; 381 | std::stringstream ss; 382 | ss << e; 383 | REQUIRE(ss.str() == name); 384 | }; 385 | 386 | test_ostream(std::make_optional(LanguageFlag::日本語), "日本語"); 387 | test_ostream(LanguageFlag::한국어, "한국어"); 388 | test_ostream(LanguageFlag::English, "English"); 389 | test_ostream(LanguageFlag::😃, "😃"); 390 | test_ostream(static_cast(0), "0"); 391 | test_ostream(std::make_optional(static_cast(0)), "0"); 392 | } 393 | 394 | TEST_CASE("flag istream_operators") { 395 | auto test_istream = [](const auto e, std::string name) { 396 | using namespace magic_enum::istream_operators; 397 | std::istringstream ss(name); 398 | std::decay_t v; 399 | ss >> v; 400 | REQUIRE(v == e); 401 | REQUIRE(ss); 402 | }; 403 | 404 | test_istream(LanguageFlag::한국어, "한국어"); 405 | test_istream(LanguageFlag::English, "English"); 406 | test_istream(LanguageFlag::😃, "😃"); 407 | } 408 | 409 | 410 | TEST_CASE("flag bitwise_operators") { 411 | using namespace magic_enum::bitwise_operators; 412 | SECTION("operator~") { 413 | REQUIRE(enum_integer(~LanguageFlag::日本語) == ~enum_integer(LanguageFlag::日本語)); 414 | } 415 | 416 | SECTION("operator|") { 417 | REQUIRE(enum_integer(LanguageFlag::日本語 | LanguageFlag::한국어) == (enum_integer(LanguageFlag::日本語) | enum_integer(LanguageFlag::한국어))); 418 | } 419 | 420 | SECTION("operator&") { 421 | REQUIRE(enum_integer(LanguageFlag::日本語 & LanguageFlag::한국어) == (enum_integer(LanguageFlag::日本語) & enum_integer(LanguageFlag::한국어))); 422 | } 423 | 424 | SECTION("operator^") { 425 | REQUIRE(enum_integer(LanguageFlag::日本語 ^ LanguageFlag::한국어) == (enum_integer(LanguageFlag::日本語) ^ enum_integer(LanguageFlag::한국어))); 426 | } 427 | 428 | SECTION("operator|=") { 429 | LanguageFlag x5 = LanguageFlag::日本語; 430 | x5 |= LanguageFlag::한국어; 431 | REQUIRE(enum_integer(x5) == (enum_integer(LanguageFlag::日本語) | enum_integer(LanguageFlag::한국어))); 432 | } 433 | 434 | SECTION("operator&=") { 435 | LanguageFlag x5 = LanguageFlag::日本語; 436 | x5 &= LanguageFlag::한국어; 437 | REQUIRE(enum_integer(x5) == (enum_integer(LanguageFlag::日本語) & enum_integer(LanguageFlag::한국어))); 438 | } 439 | 440 | SECTION("operator^=") { 441 | LanguageFlag x5 = LanguageFlag::日本語; 442 | x5 ^= LanguageFlag::한국어; 443 | REQUIRE(enum_integer(x5) == (enum_integer(LanguageFlag::日本語) ^ enum_integer(LanguageFlag::한국어))); 444 | } 445 | } 446 | -------------------------------------------------------------------------------- /test/test_wchar_t.cpp: -------------------------------------------------------------------------------- 1 | // Licensed under the MIT License . 2 | // SPDX-License-Identifier: MIT 3 | // Copyright (c) 2019 - 2024 Daniil Goncharov . 4 | // 5 | // Permission is hereby granted, free of charge, to any person obtaining a copy 6 | // of this software and associated documentation files (the "Software"), to deal 7 | // in the Software without restriction, including without limitation the rights 8 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | // copies of the Software, and to permit persons to whom the Software is 10 | // furnished to do so, subject to the following conditions: 11 | // 12 | // The above copyright notice and this permission notice shall be included in all 13 | // copies or substantial portions of the Software. 14 | // 15 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | // SOFTWARE. 22 | 23 | #define CATCH_CONFIG_MAIN 24 | #include 25 | 26 | #define MAGIC_ENUM_USING_ALIAS_STRING_VIEW using string_view = std::wstring_view; 27 | #define MAGIC_ENUM_USING_ALIAS_STRING using string = std::wstring; 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | enum class Color { RED = -12, GREEN = 7, BLUE = 15 }; 37 | template <> 38 | constexpr magic_enum::customize::customize_t magic_enum::customize::enum_name(Color value) noexcept { 39 | switch (value) { 40 | case Color::RED: 41 | return L"red"; 42 | default: 43 | return default_tag; 44 | } 45 | } 46 | 47 | using namespace magic_enum; 48 | 49 | static_assert(is_magic_enum_supported, "magic_enum: Unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility)."); 50 | 51 | TEST_CASE("enum_cast") { 52 | SECTION("string") { 53 | constexpr auto cr = enum_cast(L"red"); 54 | REQUIRE(cr.value() == Color::RED); 55 | REQUIRE(enum_cast(L"GREEN").value() == Color::GREEN); 56 | REQUIRE(enum_cast(L"blue", [](wchar_t lhs, wchar_t rhs) { return std::tolower(lhs) == std::tolower(rhs); }).value() == Color::BLUE); 57 | REQUIRE_FALSE(enum_cast(L"None").has_value()); 58 | } 59 | 60 | SECTION("integer") { 61 | Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE}; 62 | constexpr auto cr = enum_cast(-12); 63 | REQUIRE(cr.value() == Color::RED); 64 | REQUIRE(enum_cast(7).value() == Color::GREEN); 65 | REQUIRE(enum_cast(static_cast(cm[2])).value() == Color::BLUE); 66 | REQUIRE_FALSE(enum_cast(0).has_value()); 67 | } 68 | } 69 | 70 | TEST_CASE("enum_values") { 71 | REQUIRE(std::is_same_v()), const std::array&>); 72 | 73 | constexpr auto& s1 = enum_values(); 74 | REQUIRE(s1 == std::array{{Color::RED, Color::GREEN, Color::BLUE}}); 75 | } 76 | 77 | TEST_CASE("enum_count") { 78 | constexpr auto s1 = enum_count(); 79 | REQUIRE(s1 == 3); 80 | } 81 | 82 | TEST_CASE("enum_name") { 83 | SECTION("automatic storage") { 84 | constexpr Color cr = Color::RED; 85 | constexpr auto cr_name = enum_name(cr); 86 | Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE}; 87 | Color cb = Color::BLUE; 88 | REQUIRE(cr_name == L"red"); 89 | REQUIRE(enum_name(cb) == L"BLUE"); 90 | REQUIRE(enum_name>(cm[1]) == L"GREEN"); 91 | REQUIRE(enum_name>(cm[1]) == L"GREEN"); 92 | REQUIRE(enum_name>(static_cast(0)).empty()); 93 | } 94 | 95 | SECTION("static storage") { 96 | constexpr Color cr = Color::RED; 97 | constexpr auto cr_name = enum_name(); 98 | constexpr Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE}; 99 | REQUIRE(cr_name == L"red"); 100 | REQUIRE(enum_name() == L"BLUE"); 101 | REQUIRE(enum_name() == L"GREEN"); 102 | } 103 | } 104 | 105 | TEST_CASE("enum_names") { 106 | REQUIRE(std::is_same_v()), const std::array&>); 107 | 108 | constexpr auto& s1 = enum_names(); 109 | REQUIRE(s1 == std::array{{L"red", L"GREEN", L"BLUE"}}); 110 | } 111 | 112 | TEST_CASE("enum_entries") { 113 | REQUIRE(std::is_same_v()), const std::array, 3>&>); 114 | 115 | constexpr auto& s1 = enum_entries(); 116 | REQUIRE(s1 == std::array, 3>{{{Color::RED, L"red"}, {Color::GREEN, L"GREEN"}, {Color::BLUE, L"BLUE"}}}); 117 | } 118 | 119 | TEST_CASE("ostream_operators") { 120 | auto test_ostream = [](auto e, std::wstring name) { 121 | using namespace magic_enum::ostream_operators; 122 | std::wstringstream ss; 123 | ss << e; 124 | REQUIRE(ss); 125 | REQUIRE(ss.str() == name); 126 | }; 127 | 128 | test_ostream(std::make_optional(Color::RED), L"red"); 129 | test_ostream(Color::GREEN, L"GREEN"); 130 | test_ostream(Color::BLUE, L"BLUE"); 131 | test_ostream(static_cast(0), L"0"); 132 | test_ostream(std::make_optional(static_cast(0)), L"0"); 133 | } 134 | 135 | TEST_CASE("istream_operators") { 136 | auto test_istream = [](const auto e, std::wstring name) { 137 | using namespace magic_enum::istream_operators; 138 | std::wistringstream ss(name); 139 | std::decay_t v; 140 | ss >> v; 141 | REQUIRE(ss); 142 | REQUIRE(v == e); 143 | }; 144 | 145 | test_istream(Color::GREEN, L"GREEN"); 146 | test_istream(Color::BLUE, L"BLUE"); 147 | } 148 | -------------------------------------------------------------------------------- /test_installed_version.bash: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | rm -rf ./build 3 | rm -rf ./build2 4 | rm -rf ./build3 5 | rm -rf ./install_dir/ 6 | cmake -S . -B ./build -DCMAKE_BUILD_TYPE=Release --log-level=DEBUG -DCMAKE_INSTALL_PREFIX=install_dir 7 | cmake --build ./build -j$(nproc) 8 | cmake --install ./build/ --prefix ./install_dir 9 | CMAKE_PREFIX_PATH="./install_dir" cmake -S. -Bbuild2 -DMAGIC_ENUM_OPT_TEST_INSTALLED_VERSION=1 --log-level=DEBUG 10 | cmake --build build2 --config Debug -j$(nproc) --verbose 11 | CMAKE_PREFIX_PATH="./install_dir" cmake -S. -Bbuild3 -DMAGIC_ENUM_OPT_TEST_INSTALLED_VERSION_PKGCONFIG=1 --log-level=DEBUG 12 | cmake --build build3 --config Debug -j$(nproc) --verbose 13 | 14 | --------------------------------------------------------------------------------