pax_global_header00006660000000000000000000000064146400135000014503gustar00rootroot0000000000000052 comment=adc7d2ba57e142b6ad018e01057233478a74c1e8 magic_enum-0.9.6/000077500000000000000000000000001464001350000136235ustar00rootroot00000000000000magic_enum-0.9.6/.bazelignore000066400000000000000000000000341464001350000161220ustar00rootroot00000000000000.git .github test doc cmake magic_enum-0.9.6/.bazelrc000066400000000000000000000003111464001350000152410ustar00rootroot00000000000000common --enable_bzlmod build --enable_platform_specific_config build --enable_runfiles build --incompatible_strict_action_env common:ci --announce_rc test:ci --test_output=errors build:ci --curses=no magic_enum-0.9.6/.bazelversion000066400000000000000000000000061464001350000163230ustar00rootroot000000000000006.3.2 magic_enum-0.9.6/.github/000077500000000000000000000000001464001350000151635ustar00rootroot00000000000000magic_enum-0.9.6/.github/dependabot.yml000066400000000000000000000002731464001350000200150ustar00rootroot00000000000000version: 2 updates: - package-ecosystem: "github-actions" directory: "/" schedule: interval: "monthly" groups: github-actions: patterns: - "*" magic_enum-0.9.6/.github/workflows/000077500000000000000000000000001464001350000172205ustar00rootroot00000000000000magic_enum-0.9.6/.github/workflows/bzlmod-archive.yml000066400000000000000000000011541464001350000226520ustar00rootroot00000000000000name: Bzlmod Archive on: release: types: [published] jobs: # A release archive is required for bzlmod # See: https://blog.bazel.build/2023/02/15/github-archive-checksum.html upload-archive: runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - run: git archive -o "${{ format('{0}-{1}.tar.gz', github.event.repository.name, github.event.release.tag_name) }}" HEAD - run: gh release upload ${{ github.event.release.tag_name }} *.tar.gz env: GH_TOKEN: ${{ github.token }} magic_enum-0.9.6/.github/workflows/macos.yml000066400000000000000000000020521464001350000210440ustar00rootroot00000000000000name: macos on: [push, pull_request] permissions: read-all jobs: build: runs-on: ${{ matrix.config.os }} strategy: fail-fast: false matrix: config: - { os: macos-13 } # https://github.com/actions/virtual-environments/blob/main/images/macos/macos-13-Readme.md#xcode - { os: macos-14 } # https://github.com/actions/virtual-environments/blob/main/images/macos/macos-14-Readme.md#xcode name: "${{ matrix.config.os }}" steps: - uses: actions/checkout@v4 - name: Build Release run: | rm -rf build mkdir build cd build cmake .. -DCMAKE_BUILD_TYPE=Release cmake --build . -j 4 --config Release ctest --output-on-failure -C Release - name: Build Debug run: | rm -rf build mkdir build cd build cmake .. -DCMAKE_BUILD_TYPE=Debug cmake --build . -j 4 --config Debug ctest --output-on-failure -C Debug - name: Bazel Test working-directory: test run: bazelisk test //... --config=ci magic_enum-0.9.6/.github/workflows/scorecard.yml000066400000000000000000000045651464001350000217220ustar00rootroot00000000000000name: Scorecard supply-chain security on: # For Branch-Protection check. Only the default branch is supported. See # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection branch_protection_rule: # To guarantee Maintained check is occasionally updated. See # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained schedule: - cron: '42 15 * * 4' push: branches: [ "master" ] # Declare default permissions as read only. permissions: read-all jobs: analysis: name: Scorecard analysis runs-on: ubuntu-latest permissions: # Needed to upload the results to code-scanning dashboard. security-events: write # Needed to publish results and get a badge (see publish_results below). id-token: write steps: - name: "Checkout code" uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 with: persist-credentials: false - name: "Run analysis" uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.3.3 with: results_file: results.sarif results_format: sarif # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: # - you want to enable the Branch-Protection check and you prefer not to use the new Repo Rules # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. # repo_token: ${{ secrets.SCORECARD_TOKEN }} # - Publish results to OpenSSF REST API for easy access by consumers # - Allows the repository to include the Scorecard badge. # - See https://github.com/ossf/scorecard-action#publishing-results. publish_results: true # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF # format to the repository Actions tab. - name: "Upload artifact" uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 with: name: SARIF file path: results.sarif retention-days: 5 # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" uses: github/codeql-action/upload-sarif@f079b8493333aace61c81488f8bd40919487bd9f # v3.25.7 with: sarif_file: results.sarif magic_enum-0.9.6/.github/workflows/ubuntu.yml000066400000000000000000000053441464001350000212730ustar00rootroot00000000000000name: ubuntu on: [push, pull_request] permissions: read-all jobs: ubuntu: strategy: fail-fast: false matrix: compiler: - { cc: "gcc-10", cxx: "g++-10", os: "ubuntu-20.04", nonascii: "TRUE" } - { cc: "gcc-10", cxx: "g++-10", os: "ubuntu-20.04", nonascii: "FALSE" } - { cc: "gcc-11", cxx: "g++-11", os: "ubuntu-22.04", nonascii: "TRUE" } - { cc: "gcc-11", cxx: "g++-11", os: "ubuntu-22.04", nonascii: "FALSE" } - { cc: "gcc-12", cxx: "g++-12", os: "ubuntu-22.04", nonascii: "FALSE" } - { cc: "gcc-13", cxx: "g++-13", os: "ubuntu-24.04", nonascii: "FALSE" } - { cc: "gcc-14", cxx: "g++-14", os: "ubuntu-24.04", nonascii: "FALSE" } - { cc: "clang-10", cxx: "clang++-10", os: "ubuntu-20.04", nonascii: "FALSE" } - { cc: "clang-11", cxx: "clang++-11", os: "ubuntu-20.04", nonascii: "FALSE" } - { cc: "clang-12", cxx: "clang++-12", os: "ubuntu-22.04", nonascii: "FALSE" } - { cc: "clang-13", cxx: "clang++-13", os: "ubuntu-22.04", nonascii: "FALSE" } - { cc: "clang-14", cxx: "clang++-14", os: "ubuntu-22.04", nonascii: "FALSE" } - { cc: "clang-15", cxx: "clang++-15", os: "ubuntu-22.04", nonascii: "FALSE" } - { cc: "clang-16", cxx: "clang++-16", os: "ubuntu-24.04", nonascii: "FALSE" } name: "${{ format('{0} NONASCII={1}', matrix.compiler.cc, matrix.compiler.nonascii) }}" runs-on: ${{ matrix.compiler.os }} steps: - uses: actions/checkout@v4 - name: Configure clang run: | if [[ "${{ matrix.compiler.cc }}" == "clang"* ]]; then sudo apt update sudo apt install ${{ matrix.compiler.cc }} -y fi - name: Configure gcc run: | if [[ "${{ matrix.compiler.cc }}" == "gcc"* ]]; then sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y sudo apt update sudo apt install ${{ matrix.compiler.cxx }} -y fi - name: Build Release run: | rm -rf build mkdir build cd build cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=${{ matrix.compiler.cxx }} -DMAGIC_ENUM_OPT_ENABLE_NONASCII:BOOL=${{ matrix.compiler.nonascii }} cmake --build . -j 4 --config Release ctest --output-on-failure -C Release - name: Build Debug run: | rm -rf build mkdir build cd build cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=${{ matrix.compiler.cxx }} -DMAGIC_ENUM_OPT_ENABLE_NONASCII:BOOL=${{ matrix.compiler.nonascii }} cmake --build . -j 4 --config Debug ctest --output-on-failure -C Debug - name: Bazel Test working-directory: test run: bazelisk test //... --config=ci magic_enum-0.9.6/.github/workflows/windows.yml000066400000000000000000000025101464001350000214330ustar00rootroot00000000000000name: windows on: [push, pull_request] permissions: read-all jobs: build: runs-on: ${{ matrix.config.os }} strategy: fail-fast: false matrix: config: - { os: windows-2019, vs: "Visual Studio 2019" } # https://github.com/actions/virtual-environments/blob/main/images/win/Windows2019-Readme.md#visual-studio-enterprise-2019 - { os: windows-2022, vs: "Visual Studio 2022" } # https://github.com/actions/virtual-environments/blob/main/images/win/Windows2022-Readme.md#visual-studio-enterprise-2022 name: "${{ matrix.config.vs }}" steps: - uses: actions/checkout@v4 - name: Build Win32 shell: bash run: | rm -rf build mkdir build cd build cmake .. -A Win32 cmake --build . -j 4 --config Release ctest --output-on-failure -C Release cmake --build . -j 4 --config Debug ctest --output-on-failure -C Debug - name: Build x64 shell: bash run: | rm -rf build mkdir build cd build cmake .. -A x64 cmake --build . -j 4 --config Release ctest --output-on-failure -C Release cmake --build . -j 4 --config Debug ctest --output-on-failure -C Debug - name: Bazel Test working-directory: test run: bazelisk test //... --config=ci magic_enum-0.9.6/.gitignore000066400000000000000000000010561464001350000156150ustar00rootroot00000000000000build/ .vscode/ .vs/ ### C++ gitignore ### # Prerequisites *.d # Compiled Object files *.slo *.lo *.o *.obj # Precompiled Headers *.gch *.pch # Compiled Dynamic libraries *.so *.dylib *.dll # Fortran module files *.mod *.smod # Compiled Static libraries *.lai *.la *.a *.lib # Executables *.exe *.out *.app ### CMake gitignore ### CMakeLists.txt.user CMakeCache.txt CMakeFiles CMakeScripts Testing Makefile cmake_install.cmake install_manifest.txt compile_commands.json CTestTestfile.cmake _deps ### Bazel build artifacts ### /bazel-* /test/bazel-* magic_enum-0.9.6/BUILD.bazel000066400000000000000000000003461464001350000155040ustar00rootroot00000000000000licenses(["notice"]) exports_files(["LICENSE"]) package(default_visibility = ["//visibility:public"]) cc_library( name = "magic_enum", hdrs = glob(["include/magic_enum/*.hpp"]), includes = ["include/magic_enum"], ) magic_enum-0.9.6/CMakeLists.txt000066400000000000000000000121471464001350000163700ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.14) project(magic_enum VERSION "0.9.6" HOMEPAGE_URL "https://github.com/Neargye/magic_enum" DESCRIPTION "A library that provides static reflection for enums, work with any enum type without any macro or boilerplate code." LANGUAGES CXX ) set(CPACK_PACKAGE_VENDOR "Daniil Goncharov") include(GNUInstallDirs) set(ADDITIONAL_MODULES_DIR "${CMAKE_CURRENT_LIST_DIR}/cmake") list(APPEND CMAKE_MODULE_PATH "${ADDITIONAL_MODULES_DIR}") if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) set(IS_TOPLEVEL_PROJECT TRUE) else() set(IS_TOPLEVEL_PROJECT FALSE) endif() option(MAGIC_ENUM_OPT_BUILD_EXAMPLES "Build magic_enum examples" ${IS_TOPLEVEL_PROJECT}) option(MAGIC_ENUM_OPT_BUILD_TESTS "Build and perform magic_enum tests" ${IS_TOPLEVEL_PROJECT}) option(MAGIC_ENUM_OPT_INSTALL "Generate and install magic_enum target" ${IS_TOPLEVEL_PROJECT}) option(MAGIC_ENUM_OPT_INSTALL_PACKAGE_XML "Include package.xml when installing" ${MAGIC_ENUM_OPT_INSTALL}) if(MAGIC_ENUM_OPT_BUILD_EXAMPLES) add_subdirectory(example) endif() if(MAGIC_ENUM_OPT_BUILD_TESTS) enable_testing() add_subdirectory(test) endif() set(INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/include/magic_enum") set(EXPORT_NAMESPACE "${PROJECT_NAME}::") add_library(${PROJECT_NAME} INTERFACE) add_library(${EXPORT_NAMESPACE}${PROJECT_NAME} ALIAS ${PROJECT_NAME}) target_include_directories(${PROJECT_NAME} INTERFACE $ $) if(MAGIC_ENUM_OPT_INSTALL) list(APPEND CMAKE_MODULE_PATH "${ADDITIONAL_MODULES_DIR}/GenPkgConfig") include(GenPkgConfig) include(CPackComponent) include(CMakePackageConfigHelpers) install(TARGETS "${PROJECT_NAME}" EXPORT ${PROJECT_NAME} INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" # COMPONENT "${SDK_COMPONENT_NAME}" # component is not allowed for includes! Headers are installed separately! Includes only marks the headers for export ) file(GLOB_RECURSE HEADERS "${INCLUDES}/*.h" "${INCLUDES}/*.hxx" "${INCLUDES}/*.hpp") string(REPLACE "/${CMAKE_LIBRARY_ARCHITECTURE}" "" CMAKE_INSTALL_LIBDIR_ARCHIND "${CMAKE_INSTALL_LIBDIR}") foreach(headerFile ${HEADERS}) get_filename_component(headerFileParentDir "${headerFile}" DIRECTORY) file(RELATIVE_PATH headerFileRelParentDir "${INCLUDES}" "${headerFileParentDir}") install(FILES "${headerFile}" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${headerFileRelParentDir}" ) endforeach() set(CPACK_PACKAGE_NAME "${PROJECT_NAME}") set(CPACK_PACKAGE_DESCRIPTION "${PROJECT_DESCRIPTION}") set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "all") set(CPACK_DEBIAN_PACKAGE_NAME "libmagicenum-dev") set(CPACK_RPM_PACKAGE_NAME "libmagicenum-devel") set(CPACK_PACKAGE_HOMEPAGE_URL "${PROJECT_HOMEPAGE_URL}") set(CPACK_PACKAGE_MAINTAINER "${CPACK_PACKAGE_VENDOR}") set(CPACK_DEBIAN_PACKAGE_DEPENDS "") set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${CPACK_PACKAGE_MAINTAINER}") set(CPACK_PACKAGE_MAINTAINER "${CPACK_PACKAGE_VENDOR}") set(CPACK_DEB_COMPONENT_INSTALL ON) set(CPACK_RPM_COMPONENT_INSTALL ON) set(CPACK_NSIS_COMPONENT_INSTALL ON) set(CPACK_DEBIAN_COMPRESSION_TYPE "xz") set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE") set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md") set(CMAKE_CONFIG_FILE_BASENAME "${PROJECT_NAME}Config.cmake") set(CMAKE_EXPORT_FILE_BASENAME "${PROJECT_NAME}Export.cmake") set(CMAKE_CONFIG_VERSION_FILE_BASENAME "${PROJECT_NAME}ConfigVersion.cmake") set(CMAKE_CONFIG_VERSION_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CONFIG_VERSION_FILE_BASENAME}") export(TARGETS "${PROJECT_NAME}" NAMESPACE "${EXPORT_NAMESPACE}" FILE "${CMAKE_EXPORT_FILE_BASENAME}" EXPORT_LINK_INTERFACE_LIBRARIES ) install(EXPORT "${PROJECT_NAME}" FILE "${CMAKE_CONFIG_FILE_BASENAME}" NAMESPACE "${EXPORT_NAMESPACE}" DESTINATION "${CMAKE_INSTALL_LIBDIR_ARCHIND}/cmake/${PROJECT_NAME}" ) write_basic_package_version_file( "${CMAKE_CONFIG_VERSION_FILE_NAME}" #VERSION "100500.100500.100500" # any version of same bitness suits. CMake cannot compare to infinity, so use a large number we expect to be greater than any future version VERSION ${_VERSION} COMPATIBILITY AnyNewerVersion ARCH_INDEPENDENT ) install(FILES "${CMAKE_CONFIG_VERSION_FILE_NAME}" DESTINATION "${CMAKE_INSTALL_LIBDIR_ARCHIND}/cmake/${PROJECT_NAME}" ) configure_pkg_config_file("${PROJECT_NAME}" NAME "${PROJECT_NAME}" VERSION "${PROJECT_VERSION}" DESCRIPTION "${CPACK_PACKAGE_DESCRIPTION}" URL "${CPACK_PACKAGE_HOMEPAGE_URL}" INSTALL_LIB_DIR "${CMAKE_INSTALL_LIBDIR_ARCHIND}" INSTALL_INCLUDE_DIR "${CMAKE_INSTALL_INCLUDEDIR}" ) if (MAGIC_ENUM_OPT_INSTALL_PACKAGE_XML) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/package.xml DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/${PROJECT_NAME}) endif() include(CPack) endif() magic_enum-0.9.6/LICENSE000066400000000000000000000020701464001350000146270ustar00rootroot00000000000000MIT License Copyright (c) 2019 - 2024 Daniil Goncharov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 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 OR COPYRIGHT HOLDERS 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. magic_enum-0.9.6/MODULE.bazel000066400000000000000000000001271464001350000156270ustar00rootroot00000000000000module( name = "magic_enum", version = "0.9.6", compatibility_level = 0, ) magic_enum-0.9.6/README.md000066400000000000000000000257051464001350000151130ustar00rootroot00000000000000[![Github releases](https://img.shields.io/github/release/Neargye/magic_enum.svg)](https://github.com/Neargye/magic_enum/releases) [![Conan package](https://img.shields.io/badge/Conan-package-blueviolet)](https://conan.io/center/recipes/magic_enum) [![Vcpkg package](https://img.shields.io/badge/Vcpkg-package-blueviolet)](https://github.com/microsoft/vcpkg/tree/master/ports/magic-enum) [![Build2 package](https://img.shields.io/badge/Build2-package-blueviolet)](https://www.cppget.org/magic_enum?q=magic_enum) [![Meson wrap](https://img.shields.io/badge/Meson-wrap-blueviolet)](https://github.com/mesonbuild/wrapdb/blob/master/subprojects/magic_enum.wrap) [![License](https://img.shields.io/github/license/Neargye/magic_enum.svg)](LICENSE) [![Compiler explorer](https://img.shields.io/badge/compiler_explorer-online-blue.svg)](https://godbolt.org/z/feqcPa5G6) [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/Neargye/magic_enum/badge)](https://securityscorecards.dev/viewer/?uri=github.com/Neargye/magic_enum) [![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua) # Magic Enum C++ Header-only C++17 library provides static reflection for enums, work with any enum type without any macro or boilerplate code. 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. ## Documentation * [Reference](doc/reference.md) * [Limitations](doc/limitations.md) * [Integration](#Integration) ## [Features & Examples](example/) * Enum value to string ```cpp Color color = Color::RED; auto color_name = magic_enum::enum_name(color); // color_name -> "RED" ``` * String to enum value ```cpp std::string color_name{"GREEN"}; auto color = magic_enum::enum_cast(color_name); if (color.has_value()) { // color.value() -> Color::GREEN } // case insensitive enum_cast auto color = magic_enum::enum_cast(value, magic_enum::case_insensitive); // enum_cast with BinaryPredicate auto color = magic_enum::enum_cast(value, [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); } // enum_cast with default auto color_or_default = magic_enum::enum_cast(value).value_or(Color::NONE); ``` * Integer to enum value ```cpp int color_integer = 2; auto color = magic_enum::enum_cast(color_integer); if (color.has_value()) { // color.value() -> Color::BLUE } auto color_or_default = magic_enum::enum_cast(value).value_or(Color::NONE); ``` * Indexed access to enum value ```cpp std::size_t i = 0; Color color = magic_enum::enum_value(i); // color -> Color::RED ``` * Enum value sequence ```cpp constexpr auto colors = magic_enum::enum_values(); // colors -> {Color::RED, Color::BLUE, Color::GREEN} // colors[0] -> Color::RED ``` * Number of enum elements ```cpp constexpr std::size_t color_count = magic_enum::enum_count(); // color_count -> 3 ``` * Enum value to integer ```cpp Color color = Color::RED; auto color_integer = magic_enum::enum_integer(color); // or magic_enum::enum_underlying(color); // color_integer -> 1 ``` * Enum names sequence ```cpp constexpr auto color_names = magic_enum::enum_names(); // color_names -> {"RED", "BLUE", "GREEN"} // color_names[0] -> "RED" ``` * Enum entries sequence ```cpp constexpr auto color_entries = magic_enum::enum_entries(); // color_entries -> {{Color::RED, "RED"}, {Color::BLUE, "BLUE"}, {Color::GREEN, "GREEN"}} // color_entries[0].first -> Color::RED // color_entries[0].second -> "RED" ``` * Enum fusion for multi-level switch/case statements ```cpp switch (magic_enum::enum_fuse(color, direction).value()) { case magic_enum::enum_fuse(Color::RED, Directions::Up).value(): // ... case magic_enum::enum_fuse(Color::BLUE, Directions::Down).value(): // ... // ... } ``` * Enum switch runtime value as constexpr constant ```cpp Color color = Color::RED; magic_enum::enum_switch([] (auto val) { constexpr Color c_color = val; // ... }, color); ``` * Enum iterate for each enum as constexpr constant ```cpp magic_enum::enum_for_each([] (auto val) { constexpr Color c_color = val; // ... }); ``` * Check if enum contains ```cpp magic_enum::enum_contains(Color::GREEN); // -> true magic_enum::enum_contains(2); // -> true magic_enum::enum_contains(123); // -> false magic_enum::enum_contains("GREEN"); // -> true magic_enum::enum_contains("fda"); // -> false ``` * Enum index in sequence ```cpp constexpr auto color_index = magic_enum::enum_index(Color::BLUE); // color_index.value() -> 1 // color_index.has_value() -> true ``` * Functions for flags ```cpp enum Directions : std::uint64_t { Left = 1, Down = 2, Up = 4, Right = 8, }; template <> struct magic_enum::customize::enum_range { static constexpr bool is_flags = true; }; magic_enum::enum_flags_name(Directions::Up | Directions::Right); // -> "Directions::Up|Directions::Right" magic_enum::enum_flags_contains(Directions::Up | Directions::Right); // -> true magic_enum::enum_flags_cast(3); // -> "Directions::Left|Directions::Down" ``` * Enum type name ```cpp Color color = Color::RED; auto type_name = magic_enum::enum_type_name(); // type_name -> "Color" ``` * IOstream operator for enum ```cpp using magic_enum::iostream_operators::operator<<; // out-of-the-box ostream operators for enums. Color color = Color::BLUE; std::cout << color << std::endl; // "BLUE" ``` ```cpp using magic_enum::iostream_operators::operator>>; // out-of-the-box istream operators for enums. Color color; std::cin >> color; ``` * Bitwise operator for enum ```cpp enum class Flags { A = 1 << 0, B = 1 << 1, C = 1 << 2, D = 1 << 3 }; using namespace magic_enum::bitwise_operators; // out-of-the-box bitwise operators for enums. // Support operators: ~, |, &, ^, |=, &=, ^=. Flags flags = Flags::A | Flags::B & ~Flags::C; ``` * Checks whether type is an [Unscoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Unscoped_enumeration). ```cpp enum color { red, green, blue }; enum class direction { left, right }; magic_enum::is_unscoped_enum::value -> true magic_enum::is_unscoped_enum::value -> false magic_enum::is_unscoped_enum::value -> false // Helper variable template. magic_enum::is_unscoped_enum_v -> true ``` * Checks whether type is an [Scoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Scoped_enumerations). ```cpp enum color { red, green, blue }; enum class direction { left, right }; magic_enum::is_scoped_enum::value -> false magic_enum::is_scoped_enum::value -> true magic_enum::is_scoped_enum::value -> false // Helper variable template. magic_enum::is_scoped_enum_v -> true ``` * Static storage enum variable to string This version is much lighter on the compile times and is not restricted to the enum_range [limitation](doc/limitations.md). ```cpp constexpr Color color = Color::BLUE; constexpr auto color_name = magic_enum::enum_name(); // color_name -> "BLUE" ``` * `containers::array` array container for enums. ```cpp magic_enum::containers::array color_rgb_array {}; color_rgb_array[Color::RED] = {255, 0, 0}; color_rgb_array[Color::GREEN] = {0, 255, 0}; color_rgb_array[Color::BLUE] = {0, 0, 255}; magic_enum::containers::get(color_rgb_array) // -> RGB{0, 0, 255} ``` * `containers::bitset` bitset container for enums. ```cpp constexpr magic_enum::containers::bitset color_bitset_red_green {Color::RED|Color::GREEN}; bool all = color_bitset_red_green.all(); // all -> false // Color::BLUE is missing bool test = color_bitset_red_green.test(Color::RED); // test -> true ``` * `containers::set` set container for enums. ```cpp auto color_set = magic_enum::containers::set(); bool empty = color_set.empty(); // empty -> true color_set.insert(Color::GREEN); color_set.insert(Color::BLUE); color_set.insert(Color::RED); std::size_t size = color_set.size(); // size -> 3 ``` * Improved UB-free "SFINAE-friendly" [underlying_type](https://en.cppreference.com/w/cpp/types/underlying_type). ```cpp magic_enum::underlying_type::type -> int // Helper types. magic_enum::underlying_type_t -> int ``` ## Remarks * `magic_enum` does not pretend to be a silver bullet for reflection for enums, it was originally designed for small enum. * Before use, read the [limitations](doc/limitations.md) of functionality. ## Integration * You should add the required file [magic_enum.hpp](include/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. * 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). * 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. * 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}`. * Alternatively, you can use something like [CPM](https://github.com/TheLartians/CPM) which is based on CMake's `Fetch_Content` module. ```cmake CPMAddPackage( NAME magic_enum GITHUB_REPOSITORY Neargye/magic_enum GIT_TAG x.y.z # Where `x.y.z` is the release version you want to use. ) ``` * Bazel is also supported, simply add to your WORKSPACE file: ``` http_archive( name = "magic_enum", strip_prefix = "magic_enum-", urls = ["https://github.com/Neargye/magic_enum/archive/.zip"], ) ``` To use bazel inside the repository it's possible to do: ``` bazel build //... bazel test //... bazel run //example ``` (Note that you must use a supported compiler or specify it with `export CC= `.) * 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: ```cmake find_package(magic_enum CONFIG REQUIRED) ... target_link_libraries(your_executable magic_enum::magic_enum) ``` ## Compiler compatibility * Clang/LLVM >= 5 * MSVC++ >= 14.11 / Visual Studio >= 2017 * Xcode >= 10 * GCC >= 9 * MinGW >= 9 ## Licensed under the [MIT License](LICENSE) magic_enum-0.9.6/SECURITY.md000066400000000000000000000012431464001350000154140ustar00rootroot00000000000000# Security Policy ## Supported Versions Security updates are applied only to the latest release. ## Reporting a Vulnerability 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. Please disclose it at [security advisory](https://github.com/Neargye/magic_enum/security/advisories/new). 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. magic_enum-0.9.6/WORKSPACE.bazel000066400000000000000000000000001464001350000161660ustar00rootroot00000000000000magic_enum-0.9.6/cmake/000077500000000000000000000000001464001350000147035ustar00rootroot00000000000000magic_enum-0.9.6/cmake/GenPkgConfig/000077500000000000000000000000001464001350000172045ustar00rootroot00000000000000magic_enum-0.9.6/cmake/GenPkgConfig/GenPkgConfig.cmake000066400000000000000000000247431464001350000225210ustar00rootroot00000000000000#[=======================================================================[.rst: GenPkgConfig ------------ This is the library helping you to generate and install pkg-config files. Unlicense ^^^^^^^^^ This is free and unencumbered software released into the public domain. 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. 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. 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. For more information, please refer to Warning ^^^^^^^ CMake is currently merging a built-in impl of pkg-config file generator! https://gitlab.kitware.com/cmake/cmake/-/merge_requests/6363 Functions ^^^^^^^^^ .. command:: configure_pkg_config_file .. versionadded:: 3.22 Generates a pkg-config file for :: configure_pkg_config_file( NAME VERSION DESCRIPTION URL COMPONENT INSTALL_LIB_DIR INSTALL_INCLUDE_DIR REQUIRES ... ... REQUIRES ... ... ) The arguments are optional and usually are not needed to be set if global (not component-specific) CPACK vars have been set before. Generation is done in build time using packaging expressions. #]=======================================================================] set("GEN_PKG_CONFIG_WORKAROUNDS_BUILD_TIME_SCRIPTS" "${CMAKE_CURRENT_LIST_DIR}/buildTimeScripts") cmake_policy(SET CMP0070 NEW) function(configure_pkg_config_file TARGET) cmake_parse_arguments("" "" # options "NAME;VERSION;DESCRIPTION;URL;COMPONENT;INSTALL_LIB_DIR;INSTALL_INCLUDE_DIR" # one_value_keywords "REQUIRES;CONFLICTS" # multi_value_keywords ${ARGN} ) configure_pkg_config_file_vars("${TARGET}" "${_NAME}" "${_INSTALL_LIB_DIR}" "${_INSTALL_INCLUDE_DIR}" "${_COMPONENT}" "${_DESCRIPTION}" "${_URL}" "${_VERSION}" "${_REQUIRES}" "${_CONFLICTS}") endfunction() function(ge_expr_basename inputExpr outVar) set("${outVar}" "$" PARENT_SCOPE) endfunction() function(configure_pkg_config_file_vars TARGET _NAME _INSTALL_LIB_DIR _INSTALL_INCLUDE_DIR _COMPONENT _DESCRIPTION _URL _VERSION _REQUIRES _CONFLICTS) #$ #INTERFACE_LINK_DIRECTORIES #INTERFACE_LINK_LIBRARIES #INTERFACE_LINK_OPTIONS if(_NAME) else() set(_NAME "$") endif() if(_DESCRIPTION) else() set(_DESCRIPTION "${CPACK_PACKAGE_DESCRIPTION}") endif() if(_VERSION) else() set(_VERSION "${CPACK_PACKAGE_VERSION}") endif() if(_URL) else() set(_URL "${CPACK_PACKAGE_HOMEPAGE_URL}") endif() if(INSTALL_INCLUDE_DIR) else() set(INSTALL_INCLUDE_DIR "${CMAKE_INSTALL_INCLUDEDIR}") endif() if(INSTALL_LIB_DIR) else() set(INSTALL_LIB_DIR "${CMAKE_INSTALL_LIBDIR}") endif() set(PKG_CONFIG_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/${_NAME}.pc") set(PUBLIC_INCLUDES "$") set(PUBLIC_LIBS "$") set(PUBLIC_COMPILE_FLAGS "$") set("IS_INTERFACE" "$,INTERFACE_LIBRARY>") set("IS_OBJECT" "$,OBJECT_LIBRARY>") get_target_property(CONFIGURE_TIME_TARGET_TYPE "${TARGET}" TYPE) if(CONFIGURE_TIME_TARGET_TYPE STREQUAL OBJECT_LIBRARY) set(CONFIGURE_TIME_IS_OBJECT ON) # Special measures have to be taken!!! endif() set("NEEDS_LIBS" "$,$>") set("NEEDS_LIB_DIR" "$") string(REPLACE "," "$" NEEDS_LIBS_ESCAPED "${NEEDS_LIBS}") string(REPLACE ">" "$" NEEDS_LIBS_ESCAPED "${NEEDS_LIBS_ESCAPED}") list(APPEND header "prefix=${CMAKE_INSTALL_PREFIX}") list(APPEND header "$,${NEEDS_LIB_DIR}>,libdir=\${prefix}/${INSTALL_LIB_DIR},>") list(APPEND header "$,includedir=\${prefix}/${INSTALL_INCLUDE_DIR},>") list(APPEND libSpecific "Name: ${_NAME}") if(_DESCRIPTION) list(APPEND libSpecific "Description: ${_DESCRIPTION}") endif() if(_URL) list(APPEND libSpecific "URL: ${_URL}") endif() if(_VERSION) list(APPEND libSpecific "Version: ${_VERSION}") endif() if(_REQUIRES) list(APPEND libSpecific "Requires: ${_REQUIRES}") endif() if(_CONFLICTS) list(APPEND libSpecific "Conflicts: ${_CONFLICTS}") endif() 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 # Here is a workaround to inability to use TARGET_LINKER_FILE_NAME for targets not involving library generation. # Strangely $<") # A hack because there is no escape for `$` or `<` or `$<`. So we just disrupt $< into pieces set(CURRENT_LIB_ESCAPED_BINARY_NAME "${ESCAPED_GENEXPR_BEGINNING}TARGET_LINKER_FILE_NAME:${TARGET}$") set(LINK_CURRENT_LIB_FLAG "$>") if(CONFIGURE_TIME_IS_OBJECT) set(IS_TARGET_OBJECTS_CONFIGURE_TIME_UNAVAILABLE ON) if(IS_TARGET_OBJECTS_CONFIGURE_TIME_UNAVAILABLE) 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.") set(TARGET_OBJECTS_FILE "${TARGET}.obj_list") set(OBJECTS_FILE_RETRIEVAL_TARGET_NAME "${TARGET}_get_objects_list") set(PKGCONFIG_DUMMY_UNFINISHED_GEN_TARGET_NAME "${TARGET}_pkgconfig_unfinished") set(PKGCONFIG_PATCH_TARGET_NAME "${TARGET}_patch_pkgconfig") set(PKG_CONFIG_FILE_NAME_FINISHED "${PKG_CONFIG_FILE_NAME}") set(PKG_CONFIG_FILE_NAME_UNFINISHED "${PKG_CONFIG_FILE_NAME_FINISHED}.unfinished") file(GENERATE OUTPUT "${TARGET_OBJECTS_FILE}" CONTENT "$") add_custom_command( OUTPUT "${TARGET_OBJECTS_FILE}" COMMENT "A dummy command to workaround cmake limitations" ) add_custom_target("${OBJECTS_FILE_RETRIEVAL_TARGET_NAME}" DEPENDS "${TARGET_OBJECTS_FILE}" ) add_custom_command( OUTPUT "${PKG_CONFIG_FILE_NAME_FINISHED}" 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" MAIN_DEPENDENCY "${TARGET_OBJECTS_FILE}" DEPENDS "${PKG_CONFIG_FILE_NAME_UNFINISHED}" 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}" ) add_custom_target("${PKGCONFIG_PATCH_TARGET_NAME}" ALL DEPENDS "${PKG_CONFIG_FILE_NAME_FINISHED}" ) add_dependencies("${PKGCONFIG_PATCH_TARGET_NAME}" "${OBJECTS_FILE_RETRIEVAL_TARGET_NAME}" "${PKGCONFIG_DUMMY_UNFINISHED_GEN_TARGET_NAME}") set(PROPERLY_JOINED_TARGET_OBJECTS "@PROPERLY_JOINED_TARGET_OBJECTS@") else() set("RAW_TARGET_OBJECTS" "$") message(FATAL_ERROR "This branch is unimplemented because CMake lacked the needed functionality at the time") set(PROPERLY_JOINED_TARGET_OBJECTS "${RAW_TARGET_OBJECTS}") endif() endif() set(LINK_CURRENT_OBJECT_FLAG "$") list(APPEND libSpecific "$,${NEEDS_LIBS},${IS_OBJECT}>,Libs: -L\${libdir} ${LINK_CURRENT_LIB_FLAG} ${LINK_CURRENT_OBJECT_FLAG} $,-l$, -l>,>,>\n$,$>,Cflags: -I\${includedir} $,>,>") list(JOIN header "\n" header) list(JOIN libSpecific "\n" libSpecific) set(libSpecific "${header}\n\n${libSpecific}") if(CONFIGURE_TIME_IS_OBJECT) file(GENERATE OUTPUT "${PKG_CONFIG_FILE_NAME_UNFINISHED}" CONTENT "${libSpecific}" ) # Dummy target for generated files add_custom_command( OUTPUT "${PKG_CONFIG_FILE_NAME_UNFINISHED}" COMMENT "A dummy command to workaround cmake limitations" ) add_custom_target("${PKGCONFIG_DUMMY_UNFINISHED_GEN_TARGET_NAME}" DEPENDS "${PKG_CONFIG_FILE_NAME_UNFINISHED}" ) install(FILES "${PKG_CONFIG_FILE_NAME_FINISHED}" DESTINATION "${_INSTALL_LIB_DIR}/pkgconfig" COMPONENT "${_COMPONENT}" ) else() file(GENERATE OUTPUT "${PKG_CONFIG_FILE_NAME}" CONTENT "${libSpecific}" ) install(FILES "${PKG_CONFIG_FILE_NAME}" DESTINATION "${_INSTALL_LIB_DIR}/pkgconfig" COMPONENT "${_COMPONENT}" ) endif() endfunction() magic_enum-0.9.6/cmake/GenPkgConfig/ReadMe.md000066400000000000000000000033221464001350000206630ustar00rootroot00000000000000GenPkgConfig.cmake =================== A script generating pkg-config files. WARNING: CMake [is currently merging own built-in pkgconfig generation implementation](https://gitlab.kitware.com/cmake/cmake/-/merge_requests/6363)! If you require such a new version of CMake, you probably should use the built-in impl instead. Syntax ------ ```cmake configure_pkg_config_file( NAME VERSION DESCRIPTION URL COMPONENT INSTALL_LIB_DIR INSTALL_INCLUDE_DIR REQUIRES ... ... REQUIRES ... ... ) ``` Issuees ------- 1. For `OBJECT` targets we have run into big issues. CMake 1. Doesn't allow to get the list of object files at configure time 2. Allows to get a list of object files as a generator exression ... 3. BUT ... the path to them is full, but we need only file name! 4. CMake doesn't allow to strip directory path via generator expression 5. ... neither it allows string editing within generator expressions ... so ... we have to create a custom target using a custom CMake script executed separately, but ... 6. `file(GENERATE` doesn't properly register dependencies ... so we have to use `add_custom_command` to say CMake that these files are generated 7. And CMake `install(FILES` doesn't mean that the targets generating these files are automatically executed, So we have to use `ALL` in `add_custom_target`. magic_enum-0.9.6/cmake/GenPkgConfig/UNLICENSE000066400000000000000000000022741464001350000204610ustar00rootroot00000000000000This is free and unencumbered software released into the public domain. 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. 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. 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. For more information, please refer to magic_enum-0.9.6/cmake/GenPkgConfig/buildTimeScripts/000077500000000000000000000000001464001350000224725ustar00rootroot00000000000000magic_enum-0.9.6/cmake/GenPkgConfig/buildTimeScripts/getObjectFilesBaseNames.cmake000066400000000000000000000012471464001350000301500ustar00rootroot00000000000000 message(STATUS "objectsFile ${objectsFile}") message(STATUS "pkgConfigFileFinal ${pkgConfigFileFinal}") message(STATUS "pkgConfigFileUnlinished ${pkgConfigFileUnlinished}") file(READ "${objectsFile}" TARGET_OBJECTS) set(PROPERLY_JOINED_TARGET_OBJECTS "") foreach(objFullPath ${TARGET_OBJECTS}) get_filename_component(objFullPath "${objFullPath}" NAME) list(APPEND PROPERLY_JOINED_TARGET_OBJECTS "${objFullPath}") endforeach() list(JOIN PROPERLY_JOINED_TARGET_OBJECTS " " PROPERLY_JOINED_TARGET_OBJECTS) message(STATUS "PROPERLY_JOINED_TARGET_OBJECTS AFTER ${PROPERLY_JOINED_TARGET_OBJECTS}") configure_file("${pkgConfigFileUnlinished}" "${pkgConfigFileFinal}" @ONLY) magic_enum-0.9.6/doc/000077500000000000000000000000001464001350000143705ustar00rootroot00000000000000magic_enum-0.9.6/doc/limitations.md000066400000000000000000000105531464001350000172520ustar00rootroot00000000000000# Limitations * This library uses a compiler-specific hack based on `__PRETTY_FUNCTION__` / `__FUNCSIG__`. * To check if magic_enum is supported with your compiler, use macro `MAGIC_ENUM_SUPPORTED` or constexpr constant `magic_enum::is_magic_enum_supported`. If magic_enum is used on an unsupported compiler, a compilation error will occur. To suppress the error, define macro `MAGIC_ENUM_NO_CHECK_SUPPORT`. * magic_enum can't reflect if the enum is a forward declaration. ## Enum Flags * 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`. ```cpp enum class Directions { Up = 1 << 0, Down = 1 << 1, Right = 1 << 2, Left = 1 << 3 }; template <> struct magic_enum::customize::enum_range { static constexpr bool is_flags = true; }; ``` * `MAGIC_ENUM_RANGE_MAX` / `MAGIC_ENUM_RANGE_MIN` does not affect the maximum number of enum flags. * If an enum is declared as a flag enum, its zero value will not be reflected. ## Enum Range * Enum values must be in the range `[MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX]`. * By default, `MAGIC_ENUM_RANGE_MIN = -128`, `MAGIC_ENUM_RANGE_MAX = 127`. * If you need a different range for all enum types by default, redefine the macro `MAGIC_ENUM_RANGE_MIN` and `MAGIC_ENUM_RANGE_MAX`: ```cpp #define MAGIC_ENUM_RANGE_MIN 0 #define MAGIC_ENUM_RANGE_MAX 256 #include ``` * 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`. ```cpp #include enum class number { one = 100, two = 200, three = 300 }; template <> struct magic_enum::customize::enum_range { static constexpr int min = 100; static constexpr int max = 300; // (max - min) must be less than UINT16_MAX. }; ``` ## Aliasing 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. ```cpp enum ShapeKind { ConvexBegin = 0, Box = 0, // Won't work. Sphere = 1, ConvexEnd = 2, Donut = 2, // Won't work too. Banana = 3, COUNT = 4 }; // magic_enum::enum_cast("Box") -> nullopt // magic_enum::enum_name(ShapeKind::Box) -> "ConvexBegin" ``` One possible workaround for the issue is to define the enum values you want reflected before their aliases: ```cpp enum ShapeKind { // Convex shapes, see ConvexBegin and ConvexEnd below. Box = 0, Sphere = 1, // Non-convex shapes. Donut = 2, Banana = 3, COUNT = Banana + 1, // Non-reflected aliases. ConvexBegin = Box, ConvexEnd = Sphere + 1 }; // magic_enum::enum_cast("Box") -> ShapeKind::Box // magic_enum::enum_name(ShapeKind::Box) -> "Box" // Non-reflected aliases. // magic_enum::enum_cast("ConvexBegin") -> nullopt // magic_enum::enum_name(ShapeKind::ConvexBegin) -> "Box" ``` 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. ```cpp enum Number { one = 1, ONE = 1 }; // magic_enum::enum_cast("one") -> nullopt // magic_enum::enum_name(Number::one) -> "" // magic_enum::enum_cast("ONE") -> nullopt // magic_enum::enum_name(Number::ONE) -> "" ``` ## Other Compiler Issues * If you hit a message like this: ```text [...] note: constexpr evaluation hit maximum step limit; possible infinite loop? ``` Change the limit for the number of constexpr evaluated: * MSVC: `/constexpr:depthN`, `/constexpr:stepsN` * Clang: `-fconstexpr-depth=N`, `-fconstexpr-steps=N` * GCC: `-fconstexpr-depth=N`, `-fconstexpr-loop-limit=N`, `-fconstexpr-ops-limit=N` * Visual Studio's Intellisense may have some problems analyzing magic_enum. * Enums in templates may not work correctly (especially on Сlang). See [#164](https://github.com/Neargye/magic_enum/issues/164), [#65](https://github.com/Neargye/magic_enum/issues/65) magic_enum-0.9.6/doc/reference.md000066400000000000000000000716551464001350000166660ustar00rootroot00000000000000# Reference * [`enum_cast` obtains enum value from string or integer.](#enum_cast) * [`enum_value` returns enum value at specified index.](#enum_value) * [`enum_values` obtains enum value sequence.](#enum_values) * [`enum_count` returns number of enum values.](#enum_count) * [`enum_integer` obtains integer value from enum value.](#enum_integer) * [`enum_name` returns name from enum value.](#enum_name) * [`enum_names` obtains string enum name sequence.](#enum_names) * [`enum_entries` obtains pair (value enum, string enum name) sequence.](#enum_entries) * [`enum_index` obtains index in enum value sequence from enum value.](#enum_index) * [`enum_contains` checks whether enum contains enumerator with such value.](#enum_contains) * [`enum_reflected` returns true if the enum value is in the range of values that can be reflected..](#enum_reflected) * [`enum_type_name` returns type name of enum.](#enum_type_name) * [`enum_fuse` returns a bijective mix of enum values.](#enum_fuse) * [`enum_switch` allows runtime enum value transformation to constexpr context.](#enum_switch) * [`enum_for_each` calls a function with all enum constexpr value.](#enum_for_each) * [`enum_flags_*` functions for flags.](#enum_flags) * [`is_unscoped_enum` checks whether type is an Unscoped enumeration.](#is_unscoped_enum) * [`is_scoped_enum` checks whether type is an Scoped enumeration.](#is_scoped_enum) * [`underlying_type` improved UB-free "SFINAE-friendly" underlying_type.](#underlying_type) * [`ostream_operators` ostream operators for enums.](#ostream_operators) * [`istream_operators` istream operators for enums.](#istream_operators) * [`bitwise_operators` bitwise operators for enums.](#bitwise_operators) * [`containers::array` array container for enums.](#containersarray) * [`containers::bitset` bitset container for enums.](#containersbitset) * [`containers::set` set container for enums.](#containersset) ## Synopsis * Before use, read the [limitations](limitations.md) of functionality. * To check is magic_enum supported compiler use macro `MAGIC_ENUM_SUPPORTED` or constexpr constant `magic_enum::is_magic_enum_supported`.
If magic_enum used on unsupported compiler, occurs the compilation error. To suppress error define macro `MAGIC_ENUM_NO_CHECK_SUPPORT`. * To add custom enum or type names see the [example](../example/example_custom_name.cpp). * To change the type of strings or optional, use special macros: ```cpp #include #include #define MAGIC_ENUM_USING_ALIAS_STRING using string = my_lib::String; #define MAGIC_ENUM_USING_ALIAS_STRING_VIEW using string_view = my_lib::StringView; #define MAGIC_ENUM_USING_ALIAS_OPTIONAL template using optional = my_lib::Optional; #include ``` * Optionally define `MAGIC_ENUM_CONFIG_FILE` i.e., in your build system, with path to header file with defined macros or constants, for example: ```cpp #define MAGIC_ENUM_CONFIG_FILE "my_magic_enum_cfg.hpp" ``` my_magic_enum_cfg.hpp: ```cpp #include #include #define MAGIC_ENUM_USING_ALIAS_STRING using string = my_lib::String; #define MAGIC_ENUM_USING_ALIAS_STRING_VIEW using string_view = my_lib::StringView; #define MAGIC_ENUM_USING_ALIAS_OPTIONAL template using optional = my_lib::Optional; #define MAGIC_ENUM_RANGE_MIN 0 #define MAGIC_ENUM_RANGE_MAX 255 ``` ## `enum_cast` ```cpp template constexpr optional enum_cast(underlying_type_t value) noexcept; template constexpr optional enum_cast(string_view value) noexcept; template constexpr optional enum_cast(string_view value, BinaryPredicate p) noexcept(is_nothrow_invocable_v); ``` * Obtains enum value from string or integer. * Returns `optional`, using `has_value()` to check contains enum value and `value()` to get the enum value. * If argument does not enum value, returns empty `optional`. * Examples * String to enum value. ```cpp string color_name{"GREEN"}; auto color = magic_enum::enum_cast(color_name); if (color.has_value()) { // color.value() -> Color::GREEN } // case insensitive enum_cast auto color = magic_enum::enum_cast(value, magic_enum::case_insensitive); // enum_cast with BinaryPredicate auto color = magic_enum::enum_cast(value, [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); } // enum_cast with default auto color_or_default = magic_enum::enum_cast(value).value_or(Color::NONE); ``` * Integer to enum value. ```cpp int color_integer = 2; auto color = magic_enum::enum_cast(color_integer); if (color.has_value()) { // color.value() -> Color::RED } auto color_or_default = magic_enum::enum_cast(value).value_or(Color::NONE); ``` ## `enum_value` ```cpp template constexpr E enum_value(size_t index) noexcept; template constexpr E enum_value() noexcept; ``` * Returns enum value at specified index. * `enum_value(value)` no bounds checking is performed: the behavior is undefined if `index >= number of enum values`. * `enum_value()` check if `I >= number of enum values`, occurs the compilation error `magic_enum::enum_value out of range`. * Examples ```cpp int i = 1; Color color = magic_enum::enum_value(i); // color -> Color::BLUE ``` ```cpp Color color = magic_enum::enum_value(); // color -> Color::BLUE ``` ## `enum_values` ```cpp template constexpr array enum_values() noexcept; ``` * Returns `array` with all enum values where `N = number of enum values`, sorted by enum value. * Examples ```cpp constexpr auto colors = magic_enum::enum_values(); // colors -> {Color::RED, Color::BLUE, Color::GREEN} // colors[0] -> Color::RED ``` ## `enum_count` ```cpp template constexpr size_t enum_count() noexcept; ``` * Returns number of enum values. * Examples ```cpp constexpr auto color_count = magic_enum::enum_count(); // color_count -> 3 ``` ## `enum_integer` ```cpp template constexpr underlying_type_t enum_integer(E value) noexcept; template constexpr underlying_type_t enum_underlying(E value) noexcept; ``` * Returns integer value from enum value. * Examples ```cpp Color color = Color::RED; auto color_integer = magic_enum::enum_integer(color); // color -> 2 ``` ## `enum_name` ```cpp template constexpr string_view enum_name(E value) noexcept; template constexpr string_view enum_name() noexcept; ``` * Returns name from enum value as `string_view` with null-terminated string. * If enum value does not have name or [out of range](limitations.md), `enum_name(value)` returns empty string. * If enum value does not have name, `enum_name()` occurs the compilation error `magic_enum::enum_name enum value does not have a name`. * `enum_name()` is much lighter on the compile times and is not restricted to the enum_range [limitation](limitations.md). * Examples ```cpp Color color = Color::RED; auto color_name = magic_enum::enum_name(color); // color_name -> "RED" ``` ```cpp constexpr Color color = Color::BLUE; constexpr auto color_name = magic_enum::enum_name(); // color_name -> "BLUE" ``` ## `enum_names` ```cpp template constexpr array enum_names() noexcept; ``` * Returns `array` with all names where `N = number of enum values`, sorted by enum value. * Examples ```cpp constexpr auto color_names = magic_enum::enum_names(); // color_names -> {"RED", "BLUE", "GREEN"} // color_names[0] -> "RED" ``` ## `enum_entries` ```cpp template constexpr array, N> enum_entries() noexcept; ``` * Returns `array, N>` with all pairs (value, name) where `N = number of enum values`, sorted by enum value. * Examples ```cpp constexpr auto color_entries = magic_enum::enum_entries(); // color_entries -> {{Color::RED, "RED"}, {Color::BLUE, "BLUE"}, {Color::GREEN, "GREEN"}} // color_entries[0].first -> Color::RED // color_entries[0].second -> "RED" ``` ## `enum_index` ```cpp template constexpr optional enum_index(E value) noexcept; template constexpr size_t enum_index() noexcept; ``` * Obtains index in enum values from enum value. * `enum_index(value)` returns `optional` with index. * `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`. * Examples ```cpp constexpr auto color_index = magic_enum::enum_index(Color::BLUE); // color_index.value() -> 1 // color_index.has_value() -> true ``` ```cpp constexpr auto color_index = magic_enum::enum_index(); // color_index -> 1 ``` ## `enum_contains` ```cpp template constexpr bool enum_contains(E value) noexcept; template constexpr bool enum_contains(underlying_type_t value) noexcept; template constexpr bool enum_contains(string_view value) noexcept; template constexpr bool enum_contains(string_view value, BinaryPredicate p) noexcept(is_nothrow_invocable_v); ``` * Checks whether enum contains enumerator with such value. * Returns true is enum contains value, otherwise false. * Examples ```cpp magic_enum::enum_contains(Color::GREEN); // -> true magic_enum::enum_contains(2); // -> true magic_enum::enum_contains(123); // -> false magic_enum::enum_contains("GREEN"); // -> true magic_enum::enum_contains("fda"); // -> false ``` ## `enum_reflected` ```cpp template constexpr bool enum_contains(E value) noexcept; template constexpr bool enum_contains(underlying_type_t value) noexcept; template constexpr bool enum_contains(string_view value) noexcept; ``` * Returns true if the enum value is in the range of values that can be reflected. ## `enum_type_name` ```cpp template constexpr string_view enum_type_name() noexcept; ``` * Returns type name of enum as `string_view` null-terminated string. * Examples ```cpp Color color = Color::RED; auto type_name = magic_enum::enum_type_name(); // type_name -> "Color" ``` ## `enum_fuse` ```cpp template constexpr optional enum_fuse(Es... values) noexcept; ``` * You should add the required file ``. * Returns a typesafe bijective mix of several enum values. This can be used to emulate 2D switch/case statements. * Return type is `optional` where `enum_fuse_t` is an incomplete enum, it is unique for any given combination of `Es...`. * Switch/case statement over an incomplete enum is a Visual Studio warning C4064 * You have to silent (/wd4064) or ignore it. * Alternatively, define `MAGIC_ENUM_NO_TYPESAFE_ENUM_FUSE` to disable type-safety (`enum_fuse_t` equals `uintmax_t`). * Examples ```cpp switch (magic_enum::enum_fuse(color, direction).value()) { case magic_enum::enum_fuse(Color::RED, Directions::Up).value(): // ... case magic_enum::enum_fuse(Color::BLUE, Directions::Down).value(): // ... case magic_enum::enum_fuse(Directions::BLUE, Color::Down).value(): // Compilation error // ... } ``` ## `enum_switch` ```cpp template constexpr Result enum_switch(Lambda&& lambda, E value); template constexpr Result enum_switch(Lambda&& lambda, E value, Result&& result); ``` * You should add the required file ``. * Examples ```cpp Color color = Color::RED; magic_enum::enum_switch([] (auto val) { constexpr Color c_color = val; // ... }, color); ``` ## `enum_for_each` ```cpp template constexpr auto enum_for_each(Lambda&& lambda); ``` * Examples ```cpp underlying_type_t sum{}; enum_for_each([&sum](auto val) { constexpr underlying_type_t v = enum_integer(val()); sum += v; }); ``` ## `enum_flags` ```cpp template string enum_flags_name(E value); template constexpr optional enum_flags_cast(underlying_type_t value) noexcept; template constexpr optional enum_flags_cast(string_view value) noexcept; template constexpr optional enum_flags_cast(string_view value, BinaryPredicate p) noexcept(is_nothrow_invocable_v); template constexpr bool enum_flags_contains(E value) noexcept; template constexpr bool enum_flags_contains(underlying_type_t value) noexcept; template constexpr bool enum_flags_contains(string_view value) noexcept; template constexpr bool enum_flags_contains(string_view value, BinaryPredicate p) noexcept(is_nothrow_invocable_v); ``` * You should add the required file ``. * 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`. ```cpp enum class Directions { Up = 1 << 1, Down = 1 << 2, Right = 1 << 3, Left = 1 << 4 }; template <> struct magic_enum::customize::enum_range { static constexpr bool is_flags = true; }; ``` * `MAGIC_ENUM_RANGE_MAX/MAGIC_ENUM_RANGE_MIN` does not affect the maximum amount of flags. * If enum is declared as flags, then it will not reflect the value of zero and is logically AND. * Examples ```cpp enum Directions : std::uint64_t { Left = 1, Down = 2, Up = 4, Right = 8, LeftAndDown = 3 }; template <> struct magic_enum::customize::enum_range { static constexpr bool is_flags = true; }; magic_enum::enum_flags_name(Directions::Up | Directions::Right); // -> "Directions::Up|Directions::Right" magic_enum::enum_flags_name(Directions::LeftAndDown); // -> "Directions::Left|Directions::Down" magic_enum::enum_flags_contains(Directions::Up | Directions::Right); // -> true magic_enum::enum_flags_contains(Directions::LeftAndDown); // -> false magic_enum::enum_flags_cast(3); // -> "Directions::Left|Directions::Down" magic_enum::enum_flags_test(Left|Down, Down); // -> "true" magic_enum::enum_flags_test(Left|Down, Right); // -> "false" magic_enum::enum_flags_test_any(Left|Down|Right, Down|Right); // -> "true" ``` ## `is_unscoped_enum` ```cpp template struct is_unscoped_enum; template inline constexpr bool is_unscoped_enum_v = is_unscoped_enum::value; ``` * Checks whether type is an [Unscoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Unscoped_enumeration). * 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.
Otherwise, value is equal to false. * Examples ```cpp magic_enum::is_unscoped_enum::value -> true magic_enum::is_unscoped_enum::value -> false // Helper variable template. magic_enum::is_unscoped_enum_v -> true ``` ## `is_scoped_enum` ```cpp template struct is_scoped_enum; template inline constexpr bool is_scoped_enum_v = is_scoped_enum::value; ``` * Checks whether type is an [Scoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Scoped_enumerations). * 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.
Otherwise, value is equal to false. * Examples ```cpp magic_enum::is_scoped_enum::value -> false magic_enum::is_scoped_enum::value -> true // Helper variable template. magic_enum::is_scoped_enum_v -> true ``` ## `underlying_type` ```cpp template struct underlying_type; template using underlying_type_t = typename underlying_type::type; ``` * Improved UB-free "SFINAE-friendly" [underlying_type](https://en.cppreference.com/w/cpp/types/underlying_type). * If T is a complete enumeration type, provides a member typedef type that names the underlying type of T.
Otherwise, if T is not an enumeration type, there is no member type.
Otherwise (T is an incomplete enumeration type), the program is ill-formed. * Examples ```cpp magic_enum::underlying_type::type -> int // Helper types. magic_enum::underlying_type_t -> int ``` ## `ostream_operators` ```cpp template basic_ostream& operator<<(basic_ostream& os, E value); template basic_ostream& operator<<(basic_ostream& os, optional value); ``` * You should add the required file ``. * Out-of-the-box ostream operators for all enums. * Examples ```cpp using magic_enum::iostream_operators::operator<<; // out-of-the-box ostream operators for enums. Color color = Color::BLUE; std::cout << color << std::endl; // "BLUE" ``` ## `istream_operators` ```cpp template basic_istream& operator>>(basic_istream& is, E& value); ``` * You should add the required file ``. * Out-of-the-box istream operators for all enums. * Examples ```cpp using magic_enum::iostream_operators::operator>>; // out-of-the-box istream operators for enums. Color color; std::cin >> color; ``` ## `bitwise_operators` ```cpp template constexpr E operator~(E rhs) noexcept; template constexpr E operator|(E lhs, E rhs) noexcept; template constexpr E operator&(E lhs, E rhs) noexcept; template constexpr E operator^(E lhs, E rhs) noexcept; template constexpr E& operator|=(E& lhs, E rhs) noexcept; template constexpr E& operator&=(E& lhs, E rhs) noexcept; template constexpr E& operator^=(E& lhs, E rhs) noexcept; ``` * Out-of-the-box bitwise operators for all enums. * Examples ```cpp enum class Flags { A = 1 << 0, B = 1 << 1, C = 1 << 2, D = 1 << 3 }; using namespace magic_enum::bitwise_operators; // out-of-the-box bitwise operators for enums. // Support operators: ~, |, &, ^, |=, &=, ^=. Flags flags = Flags::A | Flags::B & ~Flags::C; ``` ## `containers::array` ```cpp template > struct array { constexpr reference at(E pos); constexpr const_reference at(E pos) const; constexpr reference operator[](E pos) noexcept; constexpr const_reference operator[](E pos) const noexcept; constexpr reference front() noexcept; constexpr const_reference front() const noexcept; constexpr reference back() noexcept; constexpr const_reference back() const noexcept; constexpr pointer data() noexcept; constexpr const_pointer data() const noexcept; constexpr iterator begin() noexcept; constexpr const_iterator begin() const noexcept; constexpr const_iterator cbegin() const noexcept; constexpr iterator end() noexcept; constexpr const_iterator end() const noexcept; constexpr const_iterator cend() const noexcept; constexpr iterator rbegin() noexcept; constexpr const_iterator rbegin() const noexcept; constexpr const_iterator crbegin() const noexcept; constexpr iterator rend() noexcept; constexpr const_iterator rend() const noexcept; constexpr const_iterator crend() const noexcept; constexpr bool empty() const noexcept; constexpr size_type size() const noexcept; constexpr size_type max_size() const noexcept; constexpr void fill(const V& value); constexpr void swap(array& other) noexcept(std::is_nothrow_swappable_v); friend constexpr bool operator==(const array& a1, const array& a2); friend constexpr bool operator!=(const array& a1, const array& a2); friend constexpr bool operator<(const array& a1, const array& a2); friend constexpr bool operator<=(const array& a1, const array& a2); friend constexpr bool operator>(const array& a1, const array& a2); friend constexpr bool operator>=(const array& a1, const array& a2); } ``` * STL like array for all enums. * Examples ```cpp constexpr magic_enum::containers::array color_rgb_array {{{{255, 0, 0}, {0, 255, 0}, {0, 0, 255}}}}; ``` ```cpp magic_enum::containers::array color_rgb_array {}; color_rgb_array[Color::RED] = {255, 0, 0}; color_rgb_array[Color::GREEN] = {0, 255, 0}; color_rgb_array[Color::BLUE] = {0, 0, 255}; magic_enum::containers::get(color_rgb_array) // -> RGB{0, 0, 255} ``` ## `containers::bitset` ```cpp template > class bitset { constexpr explicit bitset(detail::raw_access_t = raw_access) noexcept; constexpr explicit bitset(detail::raw_access_t, unsigned long long val); constexpr explicit bitset(detail::raw_access_t, string_view sv, string_view::size_type pos = 0, string_view::size_type n = string_view::npos, char_type zero = '0', char_type one = '1'); constexpr explicit bitset(detail::raw_access_t, const char_type* str, std::size_t n = ~std::size_t{}, char_type zero = '0', char_type one = '1'); constexpr bitset(std::initializer_list starters); constexpr explicit bitset(E starter); template > constexpr explicit bitset(string_view sv, Cmp&& cmp = {}, char_type sep = '|'); friend constexpr bool operator==(const bitset& lhs, const bitset& rhs) noexcept; friend constexpr bool operator!=(const bitset& lhs, const bitset& rhs) noexcept; constexpr bool operator[](E pos) const noexcept; constexpr reference operator[](E pos) noexcept; constexpr bool test(E pos) const; constexpr bool all() const noexcept; constexpr bool any() const noexcept; constexpr bool none() const noexcept; constexpr std::size_t count() const noexcept; constexpr std::size_t size() const noexcept; constexpr std::size_t max_size() const noexcept; constexpr bitset& operator&= (const bitset& other) noexcept; constexpr bitset& operator|= (const bitset& other) noexcept; constexpr bitset& operator^= (const bitset& other) noexcept; constexpr bitset operator~() const noexcept; constexpr bitset& set() noexcept; constexpr bitset& set(E pos, bool value = true); constexpr bitset& reset() noexcept; constexpr bitset& reset(E pos); constexpr bitset& flip() noexcept; friend constexpr bitset operator&(const bitset& lhs, const bitset& rhs) noexcept; friend constexpr bitset operator|(const bitset& lhs, const bitset& rhs) noexcept; friend constexpr bitset operator^(const bitset& lhs, const bitset& rhs) noexcept; constexpr explicit operator E() const; string to_string(char_type sep = '|') const; string to_string(detail::raw_access_t, char_type zero = '0', char_type one = '1') const; constexpr unsigned long long to_ullong(detail::raw_access_t raw) const; constexpr unsigned long long to_ulong(detail::raw_access_t raw) const; friend std::ostream& operator<<(std::ostream& o, const bitset& bs); friend std::istream& operator>>(std::istream& i, bitset& bs); } ``` * STL like bitset for all enums. * Examples ```cpp constexpr magic_enum::containers::bitset color_bitset_red_green {Color::RED|Color::GREEN}; bool all = color_bitset_red_green.all(); // all -> false // Color::BLUE is missing bool test = color_bitset_red_green.test(Color::RED); // test -> true ``` ```cpp auto color_bitset = magic_enum::containers::bitset(); color_bitset.set(Color::GREEN); color_bitset.set(Color::BLUE); std::string to_string = color_bitset.to_string(); // to_string -> "GREEN|BLUE" ``` ## `containers::set` ```cpp template > class set { constexpr set() noexcept = default; template constexpr set(InputIt first, InputIt last); constexpr set(std::initializer_list ilist); constexpr explicit set(E starter); constexpr set(const set&) noexcept = default; constexpr set(set&&) noexcept = default; constexpr set& operator=(const set&) noexcept = default; constexpr set& operator=(set&&) noexcept = default; constexpr set& operator=(std::initializer_list ilist); constexpr const_iterator begin() const noexcept; constexpr const_iterator end() const noexcept; constexpr const_iterator cbegin() const noexcept; constexpr const_iterator cend() const noexcept; constexpr const_reverse_iterator rbegin() const noexcept; constexpr const_reverse_iterator rend() const noexcept; constexpr const_reverse_iterator crbegin() const noexcept; constexpr const_reverse_iterator crend() const noexcept; constexpr bool empty() const noexcept; constexpr size_type size() const noexcept; constexpr size_type max_size() const noexcept; constexpr void clear() noexcept; constexpr std::pair insert(const value_type& value) noexcept; constexpr std::pair insert(value_type&& value) noexcept; constexpr iterator insert(const_iterator, const value_type& value) noexcept; constexpr iterator insert(const_iterator hint, value_type&& value) noexcept; template constexpr void insert(InputIt first, InputIt last) noexcept; constexpr void insert(std::initializer_list ilist) noexcept; template constexpr std::pair emplace(Args&&... args) noexcept; template constexpr iterator emplace_hint(const_iterator, Args&&... args) noexcept; constexpr iterator erase(const_iterator pos) noexcept; constexpr iterator erase(const_iterator first, const_iterator last) noexcept; constexpr size_type erase(const key_type& key) noexcept; template constexpr std::enable_if_t, size_type> erase(K&& x) noexcept; void swap(set& other) noexcept; constexpr size_type count(const key_type& key) const noexcept; template constexpr std::enable_if_t, size_type> count(const K& x) const; constexpr const_iterator find(const key_type & key) const noexcept; template constexpr std::enable_if_t, const_iterator> find(const K& x) const; constexpr bool contains(const key_type& key) const noexcept; template constexpr std::enable_if_t, bool> contains(const K& x) const noexcept; constexpr std::pair equal_range(const key_type& key) const noexcept; template constexpr std::enable_if_t, std::pair> equal_range(const K& x) const noexcept; constexpr const_iterator lower_bound(const key_type& key) const noexcept; template constexpr std::enable_if_t, const_iterator> lower_bound(const K& x) const noexcept; constexpr const_iterator upper_bound(const key_type& key) const noexcept; template constexpr std::enable_if_t, const_iterator> upper_bound(const K& x) const noexcept; constexpr key_compare key_comp() const; constexpr value_compare value_comp() const; constexpr friend bool operator==(const set& lhs, const set& rhs) noexcept; constexpr friend bool operator!=(const set& lhs, const set& rhs) noexcept; constexpr friend bool operator<(const set& lhs, const set& rhs) noexcept; constexpr friend bool operator<=(const set& lhs, const set& rhs) noexcept; constexpr friend bool operator>(const set& lhs, const set& rhs) noexcept; constexpr friend bool operator>=(const set& lhs, const set& rhs) noexcept; template size_type erase_if(Pred pred); } ``` * STL like set for all enums. * Examples ```cpp constexpr magic_enum::containers::set color_set_filled = {Color::RED, Color::GREEN, Color::BLUE}; ``` ```cpp auto color_set = magic_enum::containers::set(); bool empty = color_set.empty(); // empty -> true color_set.insert(Color::GREEN); color_set.insert(Color::BLUE); color_set.insert(Color::RED); std::size_t size = color_set.size(); // size -> 3 ``` magic_enum-0.9.6/example/000077500000000000000000000000001464001350000152565ustar00rootroot00000000000000magic_enum-0.9.6/example/CMakeLists.txt000066400000000000000000000020021464001350000200100ustar00rootroot00000000000000include(CheckCXXCompilerFlag) set(CMAKE_CXX_STANDARD 17) if((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) set(OPTIONS -Wall -Wextra -Wshadow -pedantic-errors -Werror) elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") set(OPTIONS /W4 /WX) if(HAS_PERMISSIVE_FLAG) set(OPTIONS ${OPTIONS} /permissive-) endif() endif() function(make_example target) add_executable(${target} ${target}.cpp) set_target_properties(${target} PROPERTIES CXX_EXTENSIONS OFF) target_compile_features(${target} PRIVATE cxx_std_17) target_compile_options(${target} PRIVATE ${OPTIONS}) target_link_libraries(${target} PRIVATE ${CMAKE_PROJECT_NAME}) endfunction() make_example(example) make_example(enum_flag_example) make_example(example_containers_array) make_example(example_containers_bitset) make_example(example_containers_set) make_example(example_custom_name) make_example(example_switch) if(MAGIC_ENUM_OPT_ENABLE_NONASCII) make_example(example_nonascii_name) endif() magic_enum-0.9.6/example/enum_flag_example.cpp000066400000000000000000000106611464001350000214360ustar00rootroot00000000000000// Licensed under the MIT License . // SPDX-License-Identifier: MIT // Copyright (c) 2019 - 2024 Daniil Goncharov . // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // 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 OR COPYRIGHT HOLDERS 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. #include #include #include #include enum class AnimalFlags : std::uint64_t { HasClaws = 1 << 10, CanFly = 1 << 20, EatsFish = 1 << 30, Endangered = std::uint64_t{1} << 40 }; // Add specialization `is_flags` to define that enum are flags. template <> struct magic_enum::customize::enum_range { static constexpr bool is_flags = true; }; int main() { // Enum-flags variable to string name. AnimalFlags f1 = AnimalFlags::Endangered; auto f1_name = magic_enum::enum_name(f1); std::cout << f1_name << std::endl; // Endangered // String enum-flags name sequence. constexpr auto names = magic_enum::enum_names(); std::cout << "AnimalFlags names:"; for (const auto& n : names) { std::cout << " " << n; } std::cout << std::endl; // AnimalFlags names: HasClaws CanFly EatsFish Endangered // String name to enum-flags value. auto f2 = magic_enum::enum_flags_cast("EatsFish|CanFly"); if (f2.has_value()) { std::cout << "EatsFish|CanFly = " << magic_enum::enum_integer(f2.value()) << std::endl; // CanFly|EatsFish = 1074790400 } // Integer value to enum-flags value. auto f3 = magic_enum::enum_cast(1073742848); if (f3.has_value()) { std::cout << magic_enum::enum_flags_name(f3.value()) << " = " << magic_enum::enum_integer(f3.value()) << std::endl; // HasClaws|EatsFish = 1073742848 } // Enum-flags value to integer value. auto f4_integer = magic_enum::enum_integer(AnimalFlags::HasClaws); std::cout << "HasClaws = " << f4_integer << std::endl; // HasClaws = 1024 using magic_enum::iostream_operators::operator<<; // out-of-the-box ostream operator for enum-flags. // Ostream operator for enum-flags. std::cout << f1 << " " << f2 << " " << f3 << std::endl; // Endangered CanFly|EatsFish HasClaws|EatsFish // Number of enum-flags values. std::cout << "AnimalFlags enum size: " << magic_enum::enum_count() << std::endl; // AnimalFlags enum size: 4 // Indexed access to enum-flags value. std::cout << "AnimalFlags[0] = " << magic_enum::enum_value(0) << std::endl; // AnimalFlags[0] = HasClaws // Enum-flags value sequence. constexpr auto values = magic_enum::enum_values(); std::cout << "AnimalFlags values:"; for (const auto f : values) { std::cout << " " << f; // Ostream operator for enum-flags. } std::cout << std::endl; // AnimalFlags values: HasClaws CanFly EatsFish Endangered using namespace magic_enum::bitwise_operators; // out-of-the-box bitwise operators for all enums. // Support operators: ~, |, &, ^, |=, &=, ^=. AnimalFlags flag = AnimalFlags::HasClaws | AnimalFlags::CanFly; std::cout << flag << std::endl; // HasClaws|CanFly // Enum-flags pair (value, string name) sequence. constexpr auto entries = magic_enum::enum_entries(); std::cout << "AnimalFlags entries:"; for (const auto& e : entries) { std::cout << " " << e.second << " = " << magic_enum::enum_integer(e.first); } std::cout << std::endl; // AnimalFlags entries: AnimalFlags entries: HasClaws = 1024 CanFly = 1048576 EatsFish = 1073741824 Endangered = 1099511627776 return 0; } magic_enum-0.9.6/example/example.cpp000066400000000000000000000110741464001350000174200ustar00rootroot00000000000000// Licensed under the MIT License . // SPDX-License-Identifier: MIT // Copyright (c) 2019 - 2024 Daniil Goncharov . // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // 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 OR COPYRIGHT HOLDERS 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. #include #include #include enum class Color : int { RED = -10, BLUE = 0, GREEN = 10 }; template auto to_integer(magic_enum::Enum value) { // magic_enum::Enum - C++17 Concept for enum type. return static_cast>(value); } int main() { // Enum variable to string name. Color c1 = Color::RED; auto c1_name = magic_enum::enum_name(c1); std::cout << c1_name << std::endl; // RED // String enum name sequence. constexpr auto names = magic_enum::enum_names(); std::cout << "Color names:"; for (const auto& n : names) { std::cout << " " << n; } std::cout << std::endl; // Color names: RED BLUE GREEN // String name to enum value. auto c2 = magic_enum::enum_cast("BLUE"); if (c2.has_value()) { std::cout << "BLUE = " << to_integer(c2.value()) << std::endl; // BLUE = 0 } // Case insensitive enum_cast. c2 = magic_enum::enum_cast("blue", magic_enum::case_insensitive); if (c2.has_value()) { std::cout << "BLUE = " << to_integer(c2.value()) << std::endl; // BLUE = 0 } // Integer value to enum value. auto c3 = magic_enum::enum_cast(10); if (c3.has_value()) { std::cout << "GREEN = " << magic_enum::enum_integer(c3.value()) << std::endl; // GREEN = 10 } // Enum value to integer value. auto c4_integer = magic_enum::enum_integer(Color::RED); std::cout << "RED = " << c4_integer << std::endl; // RED = -10 using magic_enum::iostream_operators::operator<<; // out-of-the-box ostream operator for all enums. // Ostream operator for enum. std::cout << "Color: " << c1 << " " << c2 << " " << c3 << std::endl; // Color: RED BLUE GREEN // Number of enum values. std::cout << "Color enum size: " << magic_enum::enum_count() << std::endl; // Color size: 3 // Indexed access to enum value. std::cout << "Color[0] = " << magic_enum::enum_value(0) << std::endl; // Color[0] = RED // Enum value sequence. constexpr auto values = magic_enum::enum_values(); std::cout << "Colors values:"; for (const auto c : values) { std::cout << " " << c; // Ostream operator for enum. } std::cout << std::endl; // Color values: RED BLUE GREEN enum class Flags { A = 1, B = 2, C = 4, D = 8 }; using namespace magic_enum::bitwise_operators; // out-of-the-box bitwise operators for all enums. // Support operators: ~, |, &, ^, |=, &=, ^=. Flags flag = Flags::A | Flags::C; std::cout << flag << std::endl; // 5 enum color { red, green, blue }; // Checks whether type is an Unscoped enumeration. static_assert(magic_enum::is_unscoped_enum_v); static_assert(!magic_enum::is_unscoped_enum_v); static_assert(!magic_enum::is_unscoped_enum_v); // Checks whether type is an Scoped enumeration. static_assert(!magic_enum::is_scoped_enum_v); static_assert(magic_enum::is_scoped_enum_v); static_assert(magic_enum::is_scoped_enum_v); // Enum pair (value enum, string enum name) sequence. constexpr auto entries = magic_enum::enum_entries(); std::cout << "Colors entries:"; for (const auto& e : entries) { std::cout << " " << e.second << " = " << static_cast(e.first); } std::cout << std::endl; // Color entries: RED = -10 BLUE = 0 GREEN = 10 return 0; } magic_enum-0.9.6/example/example_containers_array.cpp000066400000000000000000000057611464001350000230510ustar00rootroot00000000000000// Licensed under the MIT License . // SPDX-License-Identifier: MIT // Copyright (c) 2019 - 2024 Daniil Goncharov . // Copyright (c) 2022 - 2023 Bela Schaum . // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // 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 OR COPYRIGHT HOLDERS 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. #include #include enum class Color { RED = 1, GREEN = 2, BLUE = 4 }; template <> struct magic_enum::customize::enum_range { static constexpr bool is_flags = true; }; struct RGB { std::uint8_t r {}; std::uint8_t g {}; std::uint8_t b {}; [[nodiscard]] constexpr bool empty() { return std::equal_to{}(r, g) && std::equal_to{}(g, b) && std::equal_to{}(b, 0); } [[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); } friend std::ostream& operator<<(std::ostream& ostream, RGB rgb) { ostream << "R=" << static_cast(rgb.r) << " G=" << static_cast(rgb.g) << " B=" << static_cast(rgb.b); return ostream; } }; constexpr std::uint8_t color_max = std::numeric_limits::max(); int main() { constexpr magic_enum::containers::array color_rgb_initializer {{{{color_max, 0, 0}, {0, color_max, 0}, {0, 0, color_max}}}}; std::cout << magic_enum::containers::get<0>(color_rgb_initializer) << std::endl; // R=255 G=0 B=0 std::cout << magic_enum::containers::get<1>(color_rgb_initializer) << std::endl; // R=0 G=255 B=0 std::cout << magic_enum::containers::get<2>(color_rgb_initializer) << std::endl; // R=0 G=0 B=255 std::cout << magic_enum::containers::get(color_rgb_initializer) << std::endl; // R=255 G=0 B=0 std::cout << magic_enum::containers::get(color_rgb_initializer) << std::endl; // R=0 G=255 B=0 std::cout << magic_enum::containers::get(color_rgb_initializer) << std::endl; // R=0 G=0 B=255 return 0; } magic_enum-0.9.6/example/example_containers_bitset.cpp000066400000000000000000000046411464001350000232210ustar00rootroot00000000000000// Licensed under the MIT License . // SPDX-License-Identifier: MIT // Copyright (c) 2019 - 2024 Daniil Goncharov . // Copyright (c) 2022 - 2023 Bela Schaum . // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // 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 OR COPYRIGHT HOLDERS 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. #if defined(_MSC_VER) # pragma warning(push) # pragma warning(disable : 4244) // warning C4244: 'argument': conversion from 'const T' to 'unsigned int', possible loss of data. #endif #include #include enum class Color { RED = 1, GREEN = 2, BLUE = 4 }; template <> struct magic_enum::customize::enum_range { static constexpr bool is_flags = true; }; int main() { auto color_bitset = magic_enum::containers::bitset(); color_bitset.set(Color::GREEN); color_bitset.set(Color::BLUE); std::cout << std::boolalpha; std::cout << color_bitset.size() << std::endl; // 3 == magic_enum::enum_count() std::cout << color_bitset.all() << std::endl; // false std::cout << color_bitset.any() << std::endl; // true std::cout << color_bitset.none() << std::endl; // false std::cout << color_bitset.count() << std::endl; // 2 std::cout << color_bitset.test(Color::RED) << std::endl; // false std::cout << color_bitset.test(Color::GREEN) << std::endl; // true std::cout << color_bitset.test(Color::BLUE) << std::endl; // true return 0; } magic_enum-0.9.6/example/example_containers_set.cpp000066400000000000000000000044011464001350000225140ustar00rootroot00000000000000// Licensed under the MIT License . // SPDX-License-Identifier: MIT // Copyright (c) 2019 - 2024 Daniil Goncharov . // Copyright (c) 2022 - 2023 Bela Schaum . // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // 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 OR COPYRIGHT HOLDERS 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. #if defined(_MSC_VER) # pragma warning(push) # pragma warning(disable : 4244) // warning C4244: 'argument': conversion from 'const T' to 'unsigned int', possible loss of data. #endif #include #include enum class Color { RED = 1, GREEN = 2, BLUE = 4 }; template <> struct magic_enum::customize::enum_range { static constexpr bool is_flags = true; }; int main() { std::cout << std::boolalpha; magic_enum::containers::set color_set {Color::RED, Color::GREEN, Color::BLUE}; std::cout << color_set.empty() << std::endl; // false std::cout << color_set.size() << std::endl; // 3 color_set.clear(); std::cout << color_set.empty() << std::endl; // true std::cout << color_set.size() << std::endl; // 0 color_set.insert(Color::GREEN); color_set.insert(Color::BLUE); std::cout << color_set.empty() << std::endl; // false std::cout << color_set.size() << std::endl; // 2 return 0; } magic_enum-0.9.6/example/example_custom_name.cpp000066400000000000000000000055071464001350000220160ustar00rootroot00000000000000// Licensed under the MIT License . // SPDX-License-Identifier: MIT // Copyright (c) 2020 - 2024 Daniil Goncharov . // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // 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 OR COPYRIGHT HOLDERS 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. #include #include enum class Color : int { RED = -10, BLUE = 0, GREEN = 10 }; // Сustom definitions of names for enum. // Specialization of `enum_name` must be injected in `namespace magic_enum::customize`. template <> constexpr magic_enum::customize::customize_t magic_enum::customize::enum_name(Color value) noexcept { switch (value) { case Color::RED: return "the red color"; case Color::BLUE: return "The BLUE"; case Color::GREEN: return invalid_tag; } return default_tag; } enum class Numbers : int { One, Two, Three }; // Сustom definitions of names for enum. // Specialization of `enum_name` must be injected in `namespace magic_enum::customize`. template <> constexpr magic_enum::customize::customize_t magic_enum::customize::enum_name(Numbers value) noexcept { switch (value) { case Numbers::One: return "the one"; default: return default_tag; } } int main() { std::cout << magic_enum::enum_name(Color::RED) << std::endl; // 'the red color' std::cout << magic_enum::enum_name(Color::BLUE) << std::endl; // 'The BLUE' std::cout << magic_enum::enum_name(Color::GREEN) << std::endl; // '' std::cout << std::boolalpha; std::cout << (magic_enum::enum_cast("the red color").value() == Color::RED) << std::endl; // true std::cout << magic_enum::enum_name(Numbers::One) << std::endl; // 'the one' std::cout << magic_enum::enum_name(Numbers::Two) << std::endl; // 'Two' std::cout << magic_enum::enum_name(Numbers::Three) << std::endl; // 'Three' return 0; } magic_enum-0.9.6/example/example_nonascii_name.cpp000066400000000000000000000037331464001350000223060ustar00rootroot00000000000000// Licensed under the MIT License . // SPDX-License-Identifier: MIT // Copyright (c) 2020 - 2024 Daniil Goncharov . // Copyright (c) 2020 - 2023 Uruha Komachin . // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // 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 OR COPYRIGHT HOLDERS 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. #include #include enum class Language : int { 日本語 = 10, 한국어 = 20, English = 30, 😃 = 40, }; int main() { std::cout << magic_enum::enum_name(Language::日本語) << std::endl; // Japanese std::cout << magic_enum::enum_name(Language::한국어) << std::endl; // Korean std::cout << magic_enum::enum_name(Language::English) << std::endl; // English std::cout << magic_enum::enum_name(Language::😃) << std::endl; // Emoji std::cout << std::boolalpha; std::cout << (magic_enum::enum_cast("日本語").value() == Language::日本語) << std::endl; // true return 0; } magic_enum-0.9.6/example/example_switch.cpp000066400000000000000000000101051464001350000207730ustar00rootroot00000000000000// Licensed under the MIT License . // SPDX-License-Identifier: MIT // Copyright (c) 2019 - 2024 Daniil Goncharov . // Copyright (c) 2022 - 2023 Bela Schaum . // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // 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 OR COPYRIGHT HOLDERS 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. #include #define MAGIC_ENUM_ENABLE_HASH #include enum class Color { RED, BLUE, GREEN }; template constexpr std::string_view DoWork() { return "default"; } template <> constexpr std::string_view DoWork() { return "override"; } // Helper type for the visitor pattern. template struct overloaded : Ts... { using Ts::operator()...; }; template overloaded(Ts...) -> overloaded; int main() { Color c = Color::RED; auto lambda = [] (auto value) { std::cout << DoWork() << std::endl; }; magic_enum::enum_switch(lambda, c); // prints "default" c = Color::GREEN; magic_enum::enum_switch(lambda, c); // prints "override" // with object, explicit enum type auto switcher1 = overloaded{ [] (magic_enum::enum_constant) { std::cout << "Blue" << std::endl; }, [] (magic_enum::enum_constant) { std::cout << "Red" << std::endl; } }; magic_enum::enum_switch(switcher1, Color::GREEN); // prints nothing magic_enum::enum_switch(switcher1, Color::BLUE); // prints "Blue" magic_enum::enum_switch(switcher1, Color::RED); // prints "Red" // explicit result type auto switcher2 = overloaded{ [] (magic_enum::enum_constant) { return "called with green argument"; }, [] (Color other) { // default case auto name = magic_enum::enum_name(other); // not empty return "default: " + std::string{name}; } }; std::cout << magic_enum::enum_switch(switcher2, Color::GREEN) << std::endl; // prints "called with green argument" std::cout << magic_enum::enum_switch(switcher2, Color::RED) << std::endl; // prints "default: RED" auto empty = magic_enum::enum_switch(switcher2, static_cast(-3)); // returns an empty string assert(empty.empty()); // result with default object std::cout << magic_enum::enum_switch(switcher2, static_cast(-3), "unrecognized") << std::endl; // prints "unrecognized" auto switcher3 = overloaded{ [] (magic_enum::enum_constant) -> std::optional { return "red result"; }, [] (magic_enum::enum_constant) -> std::optional { return std::nullopt; } }; std::cout << std::boolalpha; std::cout << magic_enum::enum_switch(switcher3, Color::GREEN, std::make_optional("cica")).value() << std::endl; // prints default: "cica" std::cout << magic_enum::enum_switch(switcher3, Color::RED, std::make_optional("cica")).value() << std::endl; // prints: "red result" std::cout << magic_enum::enum_switch(switcher3, Color::BLUE, std::make_optional("cica")).has_value() << std::endl; // prints: false return 0; } magic_enum-0.9.6/include/000077500000000000000000000000001464001350000152465ustar00rootroot00000000000000magic_enum-0.9.6/include/magic_enum/000077500000000000000000000000001464001350000173525ustar00rootroot00000000000000magic_enum-0.9.6/include/magic_enum/magic_enum.hpp000066400000000000000000001714771464001350000222100ustar00rootroot00000000000000// __ __ _ ______ _____ // | \/ | (_) | ____| / ____|_ _ // | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ // | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| // | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| // |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| // __/ | https://github.com/Neargye/magic_enum // |___/ version 0.9.6 // // Licensed under the MIT License . // SPDX-License-Identifier: MIT // Copyright (c) 2019 - 2024 Daniil Goncharov . // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // 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 OR COPYRIGHT HOLDERS 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. #ifndef NEARGYE_MAGIC_ENUM_HPP #define NEARGYE_MAGIC_ENUM_HPP #define MAGIC_ENUM_VERSION_MAJOR 0 #define MAGIC_ENUM_VERSION_MINOR 9 #define MAGIC_ENUM_VERSION_PATCH 6 #ifndef MAGIC_ENUM_USE_STD_MODULE #include #include #include #include #include #include #include #endif #if defined(MAGIC_ENUM_CONFIG_FILE) # include MAGIC_ENUM_CONFIG_FILE #endif #ifndef MAGIC_ENUM_USE_STD_MODULE #if !defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL) # include #endif #if !defined(MAGIC_ENUM_USING_ALIAS_STRING) # include #endif #if !defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW) # include #endif #endif #if defined(MAGIC_ENUM_NO_ASSERT) # define MAGIC_ENUM_ASSERT(...) static_cast(0) #elif !defined(MAGIC_ENUM_ASSERT) # include # define MAGIC_ENUM_ASSERT(...) assert((__VA_ARGS__)) #endif #if defined(__clang__) # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wunknown-warning-option" # pragma clang diagnostic ignored "-Wenum-constexpr-conversion" # pragma clang diagnostic ignored "-Wuseless-cast" // suppresses 'static_cast('\0')' for char_type = char (common on Linux). #elif defined(__GNUC__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'. # pragma GCC diagnostic ignored "-Wuseless-cast" // suppresses 'static_cast('\0')' for char_type = char (common on Linux). #elif defined(_MSC_VER) # pragma warning(push) # pragma warning(disable : 26495) // Variable 'static_str::chars_' is uninitialized. # pragma warning(disable : 28020) // Arithmetic overflow: Using operator '-' on a 4 byte value and then casting the result to a 8 byte value. # pragma warning(disable : 26451) // The expression '0<=_Param_(1)&&_Param_(1)<=1-1' is not true at this call. # pragma warning(disable : 4514) // Unreferenced inline function has been removed. #endif // Checks magic_enum compiler compatibility. #if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1910 || defined(__RESHARPER__) # undef MAGIC_ENUM_SUPPORTED # define MAGIC_ENUM_SUPPORTED 1 #endif // Checks magic_enum compiler aliases compatibility. #if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1920 # undef MAGIC_ENUM_SUPPORTED_ALIASES # define MAGIC_ENUM_SUPPORTED_ALIASES 1 #endif // Enum value must be greater or equals than MAGIC_ENUM_RANGE_MIN. By default MAGIC_ENUM_RANGE_MIN = -128. // If need another min range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN. #if !defined(MAGIC_ENUM_RANGE_MIN) # define MAGIC_ENUM_RANGE_MIN -128 #endif // Enum value must be less or equals than MAGIC_ENUM_RANGE_MAX. By default MAGIC_ENUM_RANGE_MAX = 128. // If need another max range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MAX. #if !defined(MAGIC_ENUM_RANGE_MAX) # define MAGIC_ENUM_RANGE_MAX 127 #endif // Improve ReSharper C++ intellisense performance with builtins, avoiding unnecessary template instantiations. #if defined(__RESHARPER__) # undef MAGIC_ENUM_GET_ENUM_NAME_BUILTIN # undef MAGIC_ENUM_GET_TYPE_NAME_BUILTIN # if __RESHARPER__ >= 20230100 # define MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V) __rscpp_enumerator_name(V) # define MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(T) __rscpp_type_name() # else # define MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V) nullptr # define MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(T) nullptr # endif #endif namespace magic_enum { // If need another optional type, define the macro MAGIC_ENUM_USING_ALIAS_OPTIONAL. #if defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL) MAGIC_ENUM_USING_ALIAS_OPTIONAL #else using std::optional; #endif // If need another string_view type, define the macro MAGIC_ENUM_USING_ALIAS_STRING_VIEW. #if defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW) MAGIC_ENUM_USING_ALIAS_STRING_VIEW #else using std::string_view; #endif // If need another string type, define the macro MAGIC_ENUM_USING_ALIAS_STRING. #if defined(MAGIC_ENUM_USING_ALIAS_STRING) MAGIC_ENUM_USING_ALIAS_STRING #else using std::string; #endif using char_type = string_view::value_type; static_assert(std::is_same_v, "magic_enum::customize requires same string_view::value_type and string::value_type"); static_assert([] { if constexpr (std::is_same_v) { constexpr const char c[] = "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|"; constexpr const wchar_t wc[] = L"abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|"; static_assert(std::size(c) == std::size(wc), "magic_enum::customize identifier characters are multichars in wchar_t."); for (std::size_t i = 0; i < std::size(c); ++i) { if (c[i] != wc[i]) { return false; } } } return true; } (), "magic_enum::customize wchar_t is not compatible with ASCII."); namespace customize { // Enum value must be in range [MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX]. By default MAGIC_ENUM_RANGE_MIN = -128, MAGIC_ENUM_RANGE_MAX = 128. // If need another range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN and MAGIC_ENUM_RANGE_MAX. // If need another range for specific enum type, add specialization enum_range for necessary enum type. template struct enum_range { static constexpr int min = MAGIC_ENUM_RANGE_MIN; static constexpr int max = MAGIC_ENUM_RANGE_MAX; }; static_assert(MAGIC_ENUM_RANGE_MAX > MAGIC_ENUM_RANGE_MIN, "MAGIC_ENUM_RANGE_MAX must be greater than MAGIC_ENUM_RANGE_MIN."); namespace detail { enum class customize_tag { default_tag, invalid_tag, custom_tag }; } // namespace magic_enum::customize::detail class customize_t : public std::pair { public: constexpr customize_t(string_view srt) : std::pair{detail::customize_tag::custom_tag, srt} {} constexpr customize_t(const char_type* srt) : customize_t{string_view{srt}} {} constexpr customize_t(detail::customize_tag tag) : std::pair{tag, string_view{}} { MAGIC_ENUM_ASSERT(tag != detail::customize_tag::custom_tag); } }; // Default customize. inline constexpr auto default_tag = customize_t{detail::customize_tag::default_tag}; // Invalid customize. inline constexpr auto invalid_tag = customize_t{detail::customize_tag::invalid_tag}; // If need custom names for enum, add specialization enum_name for necessary enum type. template constexpr customize_t enum_name(E) noexcept { return default_tag; } // If need custom type name for enum, add specialization enum_type_name for necessary enum type. template constexpr customize_t enum_type_name() noexcept { return default_tag; } } // namespace magic_enum::customize namespace detail { template struct supported #if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED || defined(MAGIC_ENUM_NO_CHECK_SUPPORT) : std::true_type {}; #else : std::false_type {}; #endif template , std::enable_if_t, int> = 0> using enum_constant = std::integral_constant; template inline constexpr bool always_false_v = false; template struct has_is_flags : std::false_type {}; template struct has_is_flags::is_flags)>> : std::bool_constant::is_flags)>>> {}; template struct range_min : std::integral_constant {}; template struct range_min::min)>> : std::integral_constant::min), customize::enum_range::min> {}; template struct range_max : std::integral_constant {}; template struct range_max::max)>> : std::integral_constant::max), customize::enum_range::max> {}; struct str_view { const char* str_ = nullptr; std::size_t size_ = 0; }; template class static_str { public: constexpr explicit static_str(str_view str) noexcept : static_str{str.str_, std::make_integer_sequence{}} { MAGIC_ENUM_ASSERT(str.size_ == N); } constexpr explicit static_str(string_view str) noexcept : static_str{str.data(), std::make_integer_sequence{}} { MAGIC_ENUM_ASSERT(str.size() == N); } constexpr const char_type* data() const noexcept { return chars_; } constexpr std::uint16_t size() const noexcept { return N; } constexpr operator string_view() const noexcept { return {data(), size()}; } private: template constexpr static_str(const char* str, std::integer_sequence) noexcept : chars_{static_cast(str[I])..., static_cast('\0')} {} template constexpr static_str(string_view str, std::integer_sequence) noexcept : chars_{str[I]..., static_cast('\0')} {} char_type chars_[static_cast(N) + 1]; }; template <> class static_str<0> { public: constexpr explicit static_str() = default; constexpr explicit static_str(str_view) noexcept {} constexpr explicit static_str(string_view) noexcept {} constexpr const char_type* data() const noexcept { return nullptr; } constexpr std::uint16_t size() const noexcept { return 0; } constexpr operator string_view() const noexcept { return {}; } }; template > class case_insensitive { static constexpr char_type to_lower(char_type c) noexcept { return (c >= static_cast('A') && c <= static_cast('Z')) ? static_cast(c + (static_cast('a') - static_cast('A'))) : c; } public: template constexpr auto operator()(L lhs, R rhs) const noexcept -> std::enable_if_t, char_type> && std::is_same_v, char_type>, bool> { return Op{}(to_lower(lhs), to_lower(rhs)); } }; constexpr std::size_t find(string_view str, char_type c) noexcept { #if defined(__clang__) && __clang_major__ < 9 && defined(__GLIBCXX__) || defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__) // https://stackoverflow.com/questions/56484834/constexpr-stdstring-viewfind-last-of-doesnt-work-on-clang-8-with-libstdc // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html constexpr bool workaround = true; #else constexpr bool workaround = false; #endif if constexpr (workaround) { for (std::size_t i = 0; i < str.size(); ++i) { if (str[i] == c) { return i; } } return string_view::npos; } else { return str.find(c); } } template constexpr bool is_default_predicate() noexcept { return std::is_same_v, std::equal_to> || std::is_same_v, std::equal_to<>>; } template constexpr bool is_nothrow_invocable() { return is_default_predicate() || std::is_nothrow_invocable_r_v; } template constexpr bool cmp_equal(string_view lhs, string_view rhs, [[maybe_unused]] BinaryPredicate&& p) noexcept(is_nothrow_invocable()) { #if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__) // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html // https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html constexpr bool workaround = true; #else constexpr bool workaround = false; #endif if constexpr (!is_default_predicate() || workaround) { if (lhs.size() != rhs.size()) { return false; } const auto size = lhs.size(); for (std::size_t i = 0; i < size; ++i) { if (!p(lhs[i], rhs[i])) { return false; } } return true; } else { return lhs == rhs; } } template constexpr bool cmp_less(L lhs, R rhs) noexcept { static_assert(std::is_integral_v && std::is_integral_v, "magic_enum::detail::cmp_less requires integral type."); if constexpr (std::is_signed_v == std::is_signed_v) { // If same signedness (both signed or both unsigned). return lhs < rhs; } else if constexpr (std::is_same_v) { // bool special case return static_cast(lhs) < rhs; } else if constexpr (std::is_same_v) { // bool special case return lhs < static_cast(rhs); } else if constexpr (std::is_signed_v) { // If 'right' is negative, then result is 'false', otherwise cast & compare. return rhs > 0 && lhs < static_cast>(rhs); } else { // If 'left' is negative, then result is 'true', otherwise cast & compare. return lhs < 0 || static_cast>(lhs) < rhs; } } template constexpr I log2(I value) noexcept { static_assert(std::is_integral_v, "magic_enum::detail::log2 requires integral type."); if constexpr (std::is_same_v) { // bool special case return MAGIC_ENUM_ASSERT(false), value; } else { auto ret = I{0}; for (; value > I{1}; value >>= I{1}, ++ret) {} return ret; } } #if defined(__cpp_lib_array_constexpr) && __cpp_lib_array_constexpr >= 201603L # define MAGIC_ENUM_ARRAY_CONSTEXPR 1 #else template constexpr std::array, N> to_array(T (&a)[N], std::index_sequence) noexcept { return {{a[I]...}}; } #endif template inline constexpr bool is_enum_v = std::is_enum_v && std::is_same_v>; template constexpr auto n() noexcept { static_assert(is_enum_v, "magic_enum::detail::n requires enum type."); if constexpr (supported::value) { #if defined(MAGIC_ENUM_GET_TYPE_NAME_BUILTIN) constexpr auto name_ptr = MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(E); constexpr auto name = name_ptr ? str_view{name_ptr, std::char_traits::length(name_ptr)} : str_view{}; #elif defined(__clang__) str_view name; if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) { static_assert(always_false_v, "magic_enum::detail::n requires __PRETTY_FUNCTION__."); return str_view{}; } else { name.size_ = sizeof(__PRETTY_FUNCTION__) - 36; name.str_ = __PRETTY_FUNCTION__ + 34; } #elif defined(__GNUC__) auto name = str_view{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1}; if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) { static_assert(always_false_v, "magic_enum::detail::n requires __PRETTY_FUNCTION__."); return str_view{}; } else if (name.str_[name.size_ - 1] == ']') { name.size_ -= 50; name.str_ += 49; } else { name.size_ -= 40; name.str_ += 37; } #elif defined(_MSC_VER) // CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284). str_view name; name.str_ = __FUNCSIG__; name.str_ += 40; name.size_ += sizeof(__FUNCSIG__) - 57; #else auto name = str_view{}; #endif std::size_t p = 0; for (std::size_t i = name.size_; i > 0; --i) { if (name.str_[i] == ':') { p = i + 1; break; } } if (p > 0) { name.size_ -= p; name.str_ += p; } return name; } else { return str_view{}; // Unsupported compiler or Invalid customize. } } template constexpr auto type_name() noexcept { [[maybe_unused]] constexpr auto custom = customize::enum_type_name(); static_assert(std::is_same_v, customize::customize_t>, "magic_enum::customize requires customize_t type."); if constexpr (custom.first == customize::detail::customize_tag::custom_tag) { constexpr auto name = custom.second; static_assert(!name.empty(), "magic_enum::customize requires not empty string."); return static_str{name}; } else if constexpr (custom.first == customize::detail::customize_tag::invalid_tag) { return static_str<0>{}; } else if constexpr (custom.first == customize::detail::customize_tag::default_tag) { constexpr auto name = n(); return static_str{name}; } else { static_assert(always_false_v, "magic_enum::customize invalid."); } } template inline constexpr auto type_name_v = type_name(); template constexpr auto n() noexcept { static_assert(is_enum_v, "magic_enum::detail::n requires enum type."); if constexpr (supported::value) { #if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN) constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V); auto name = name_ptr ? str_view{name_ptr, std::char_traits::length(name_ptr)} : str_view{}; #elif defined(__clang__) str_view name; if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) { static_assert(always_false_v, "magic_enum::detail::n requires __PRETTY_FUNCTION__."); return str_view{}; } else { name.size_ = sizeof(__PRETTY_FUNCTION__) - 36; name.str_ = __PRETTY_FUNCTION__ + 34; } if (name.size_ > 22 && name.str_[0] == '(' && name.str_[1] == 'a' && name.str_[10] == ' ' && name.str_[22] == ':') { name.size_ -= 23; name.str_ += 23; } if (name.str_[0] == '(' || name.str_[0] == '-' || (name.str_[0] >= '0' && name.str_[0] <= '9')) { name = str_view{}; } #elif defined(__GNUC__) auto name = str_view{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1}; if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) { static_assert(always_false_v, "magic_enum::detail::n requires __PRETTY_FUNCTION__."); return str_view{}; } else if (name.str_[name.size_ - 1] == ']') { name.size_ -= 55; name.str_ += 54; } else { name.size_ -= 40; name.str_ += 37; } if (name.str_[0] == '(') { name = str_view{}; } #elif defined(_MSC_VER) str_view name; if ((__FUNCSIG__[5] == '_' && __FUNCSIG__[35] != '(') || (__FUNCSIG__[5] == 'c' && __FUNCSIG__[41] != '(')) { // CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284). name.str_ = __FUNCSIG__; name.str_ += 35; name.size_ = sizeof(__FUNCSIG__) - 52; } #else auto name = str_view{}; #endif std::size_t p = 0; for (std::size_t i = name.size_; i > 0; --i) { if (name.str_[i] == ':') { p = i + 1; break; } } if (p > 0) { name.size_ -= p; name.str_ += p; } return name; } else { return str_view{}; // Unsupported compiler or Invalid customize. } } #if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER < 1920 # define MAGIC_ENUM_VS_2017_WORKAROUND 1 #endif #if defined(MAGIC_ENUM_VS_2017_WORKAROUND) template constexpr auto n() noexcept { static_assert(is_enum_v, "magic_enum::detail::n requires enum type."); # if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN) constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V); auto name = name_ptr ? str_view{name_ptr, std::char_traits::length(name_ptr)} : str_view{}; # else // CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284). str_view name; name.str_ = __FUNCSIG__; name.size_ = sizeof(__FUNCSIG__) - 17; std::size_t p = 0; for (std::size_t i = name.size_; i > 0; --i) { if (name.str_[i] == ',' || name.str_[i] == ':') { p = i + 1; break; } } if (p > 0) { name.size_ -= p; name.str_ += p; } if (name.str_[0] == '(' || name.str_[0] == '-' || (name.str_[0] >= '0' && name.str_[0] <= '9')) { name = str_view{}; } return name; # endif } #endif template constexpr auto enum_name() noexcept { [[maybe_unused]] constexpr auto custom = customize::enum_name(V); static_assert(std::is_same_v, customize::customize_t>, "magic_enum::customize requires customize_t type."); if constexpr (custom.first == customize::detail::customize_tag::custom_tag) { constexpr auto name = custom.second; static_assert(!name.empty(), "magic_enum::customize requires not empty string."); return static_str{name}; } else if constexpr (custom.first == customize::detail::customize_tag::invalid_tag) { return static_str<0>{}; } else if constexpr (custom.first == customize::detail::customize_tag::default_tag) { #if defined(MAGIC_ENUM_VS_2017_WORKAROUND) constexpr auto name = n(); #else constexpr auto name = n(); #endif return static_str{name}; } else { static_assert(always_false_v, "magic_enum::customize invalid."); } } template inline constexpr auto enum_name_v = enum_name(); template constexpr bool is_valid() noexcept { #if defined(__clang__) && __clang_major__ >= 16 // https://reviews.llvm.org/D130058, https://reviews.llvm.org/D131307 constexpr E v = __builtin_bit_cast(E, V); #else constexpr E v = static_cast(V); #endif [[maybe_unused]] constexpr auto custom = customize::enum_name(v); static_assert(std::is_same_v, customize::customize_t>, "magic_enum::customize requires customize_t type."); if constexpr (custom.first == customize::detail::customize_tag::custom_tag) { constexpr auto name = custom.second; static_assert(!name.empty(), "magic_enum::customize requires not empty string."); return name.size() != 0; } else if constexpr (custom.first == customize::detail::customize_tag::default_tag) { #if defined(MAGIC_ENUM_VS_2017_WORKAROUND) return n().size_ != 0; #else return n().size_ != 0; #endif } else { return false; } } enum class enum_subtype { common, flags }; template > constexpr U ualue(std::size_t i) noexcept { if constexpr (std::is_same_v) { // bool special case static_assert(O == 0, "magic_enum::detail::ualue requires valid offset."); return static_cast(i); } else if constexpr (S == enum_subtype::flags) { return static_cast(U{1} << static_cast(static_cast(i) + O)); } else { return static_cast(static_cast(i) + O); } } template > constexpr E value(std::size_t i) noexcept { return static_cast(ualue(i)); } template > constexpr int reflected_min() noexcept { if constexpr (S == enum_subtype::flags) { return 0; } else { constexpr auto lhs = range_min::value; constexpr auto rhs = (std::numeric_limits::min)(); if constexpr (cmp_less(rhs, lhs)) { return lhs; } else { return rhs; } } } template > constexpr int reflected_max() noexcept { if constexpr (S == enum_subtype::flags) { return std::numeric_limits::digits - 1; } else { constexpr auto lhs = range_max::value; constexpr auto rhs = (std::numeric_limits::max)(); if constexpr (cmp_less(lhs, rhs)) { return lhs; } else { return rhs; } } } #define MAGIC_ENUM_FOR_EACH_256(T) \ T( 0)T( 1)T( 2)T( 3)T( 4)T( 5)T( 6)T( 7)T( 8)T( 9)T( 10)T( 11)T( 12)T( 13)T( 14)T( 15)T( 16)T( 17)T( 18)T( 19)T( 20)T( 21)T( 22)T( 23)T( 24)T( 25)T( 26)T( 27)T( 28)T( 29)T( 30)T( 31) \ T( 32)T( 33)T( 34)T( 35)T( 36)T( 37)T( 38)T( 39)T( 40)T( 41)T( 42)T( 43)T( 44)T( 45)T( 46)T( 47)T( 48)T( 49)T( 50)T( 51)T( 52)T( 53)T( 54)T( 55)T( 56)T( 57)T( 58)T( 59)T( 60)T( 61)T( 62)T( 63) \ T( 64)T( 65)T( 66)T( 67)T( 68)T( 69)T( 70)T( 71)T( 72)T( 73)T( 74)T( 75)T( 76)T( 77)T( 78)T( 79)T( 80)T( 81)T( 82)T( 83)T( 84)T( 85)T( 86)T( 87)T( 88)T( 89)T( 90)T( 91)T( 92)T( 93)T( 94)T( 95) \ T( 96)T( 97)T( 98)T( 99)T(100)T(101)T(102)T(103)T(104)T(105)T(106)T(107)T(108)T(109)T(110)T(111)T(112)T(113)T(114)T(115)T(116)T(117)T(118)T(119)T(120)T(121)T(122)T(123)T(124)T(125)T(126)T(127) \ T(128)T(129)T(130)T(131)T(132)T(133)T(134)T(135)T(136)T(137)T(138)T(139)T(140)T(141)T(142)T(143)T(144)T(145)T(146)T(147)T(148)T(149)T(150)T(151)T(152)T(153)T(154)T(155)T(156)T(157)T(158)T(159) \ T(160)T(161)T(162)T(163)T(164)T(165)T(166)T(167)T(168)T(169)T(170)T(171)T(172)T(173)T(174)T(175)T(176)T(177)T(178)T(179)T(180)T(181)T(182)T(183)T(184)T(185)T(186)T(187)T(188)T(189)T(190)T(191) \ T(192)T(193)T(194)T(195)T(196)T(197)T(198)T(199)T(200)T(201)T(202)T(203)T(204)T(205)T(206)T(207)T(208)T(209)T(210)T(211)T(212)T(213)T(214)T(215)T(216)T(217)T(218)T(219)T(220)T(221)T(222)T(223) \ T(224)T(225)T(226)T(227)T(228)T(229)T(230)T(231)T(232)T(233)T(234)T(235)T(236)T(237)T(238)T(239)T(240)T(241)T(242)T(243)T(244)T(245)T(246)T(247)T(248)T(249)T(250)T(251)T(252)T(253)T(254)T(255) template constexpr void valid_count(bool* valid, std::size_t& count) noexcept { #define MAGIC_ENUM_V(O) \ if constexpr ((I + O) < Size) { \ if constexpr (is_valid(I + O)>()) { \ valid[I + O] = true; \ ++count; \ } \ } MAGIC_ENUM_FOR_EACH_256(MAGIC_ENUM_V) if constexpr ((I + 256) < Size) { valid_count(valid, count); } #undef MAGIC_ENUM_V } template struct valid_count_t { std::size_t count = 0; bool valid[N] = {}; }; template constexpr auto valid_count() noexcept { valid_count_t vc; valid_count(vc.valid, vc.count); return vc; } template constexpr auto values() noexcept { constexpr auto vc = valid_count(); if constexpr (vc.count > 0) { #if defined(MAGIC_ENUM_ARRAY_CONSTEXPR) std::array values = {}; #else E values[vc.count] = {}; #endif for (std::size_t i = 0, v = 0; v < vc.count; ++i) { if (vc.valid[i]) { values[v++] = value(i); } } #if defined(MAGIC_ENUM_ARRAY_CONSTEXPR) return values; #else return to_array(values, std::make_index_sequence{}); #endif } else { return std::array{}; } } template > constexpr auto values() noexcept { constexpr auto min = reflected_min(); constexpr auto max = reflected_max(); constexpr auto range_size = max - min + 1; static_assert(range_size > 0, "magic_enum::enum_range requires valid size."); return values(); } template > constexpr enum_subtype subtype(std::true_type) noexcept { if constexpr (std::is_same_v) { // bool special case return enum_subtype::common; } else if constexpr (has_is_flags::value) { return customize::enum_range::is_flags ? enum_subtype::flags : enum_subtype::common; } else { #if defined(MAGIC_ENUM_AUTO_IS_FLAGS) constexpr auto flags_values = values(); constexpr auto default_values = values(); if (flags_values.size() == 0 || default_values.size() > flags_values.size()) { return enum_subtype::common; } for (std::size_t i = 0; i < default_values.size(); ++i) { const auto v = static_cast(default_values[i]); if (v != 0 && (v & (v - 1)) != 0) { return enum_subtype::common; } } return enum_subtype::flags; #else return enum_subtype::common; #endif } } template constexpr enum_subtype subtype(std::false_type) noexcept { // For non-enum type return default common subtype. return enum_subtype::common; } template > inline constexpr auto subtype_v = subtype(std::is_enum{}); template inline constexpr auto values_v = values(); template > using values_t = decltype((values_v)); template inline constexpr auto count_v = values_v.size(); template > inline constexpr auto min_v = (count_v > 0) ? static_cast(values_v.front()) : U{0}; template > inline constexpr auto max_v = (count_v > 0) ? static_cast(values_v.back()) : U{0}; template constexpr auto names(std::index_sequence) noexcept { constexpr auto names = std::array{{enum_name_v[I]>...}}; return names; } template inline constexpr auto names_v = names(std::make_index_sequence>{}); template > using names_t = decltype((names_v)); template constexpr auto entries(std::index_sequence) noexcept { constexpr auto entries = std::array, sizeof...(I)>{{{values_v[I], enum_name_v[I]>}...}}; return entries; } template inline constexpr auto entries_v = entries(std::make_index_sequence>{}); template > using entries_t = decltype((entries_v)); template > constexpr bool is_sparse() noexcept { if constexpr (count_v == 0) { return false; } else if constexpr (std::is_same_v) { // bool special case return false; } else { constexpr auto max = (S == enum_subtype::flags) ? log2(max_v) : max_v; constexpr auto min = (S == enum_subtype::flags) ? log2(min_v) : min_v; constexpr auto range_size = max - min + 1; return range_size != count_v; } } template > inline constexpr bool is_sparse_v = is_sparse(); template struct is_reflected #if defined(MAGIC_ENUM_NO_CHECK_REFLECTED_ENUM) : std::true_type {}; #else : std::bool_constant && (count_v != 0)> {}; #endif template inline constexpr bool is_reflected_v = is_reflected, S>{}; template struct enable_if_enum {}; template struct enable_if_enum { using type = R; static_assert(supported::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility)."); }; template , typename D = std::decay_t> using enable_if_t = typename enable_if_enum && std::is_invocable_r_v, R>::type; template >, int> = 0> using enum_concept = T; template > struct is_scoped_enum : std::false_type {}; template struct is_scoped_enum : std::bool_constant>> {}; template > struct is_unscoped_enum : std::false_type {}; template struct is_unscoped_enum : std::bool_constant>> {}; template >> struct underlying_type {}; template struct underlying_type : std::underlying_type> {}; #if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH) template struct constexpr_hash_t; template struct constexpr_hash_t>> { constexpr auto operator()(Value value) const noexcept { using U = typename underlying_type::type; if constexpr (std::is_same_v) { // bool special case return static_cast(value); } else { return static_cast(value); } } using secondary_hash = constexpr_hash_t; }; template struct constexpr_hash_t>> { static constexpr std::uint32_t crc_table[256] { 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL }; constexpr std::uint32_t operator()(string_view value) const noexcept { auto crc = static_cast(0xffffffffL); for (const auto c : value) { crc = (crc >> 8) ^ crc_table[(crc ^ static_cast(c)) & 0xff]; } return crc ^ 0xffffffffL; } struct secondary_hash { constexpr std::uint32_t operator()(string_view value) const noexcept { auto acc = static_cast(2166136261ULL); for (const auto c : value) { acc = ((acc ^ static_cast(c)) * static_cast(16777619ULL)) & (std::numeric_limits::max)(); } return static_cast(acc); } }; }; template inline constexpr Hash hash_v{}; template constexpr auto calculate_cases(std::size_t Page) noexcept { constexpr std::array values = *GlobValues; constexpr std::size_t size = values.size(); using switch_t = std::invoke_result_t; static_assert(std::is_integral_v && !std::is_same_v); const std::size_t values_to = (std::min)(static_cast(256), size - Page); std::array result{}; auto fill = result.begin(); { auto first = values.begin() + static_cast(Page); auto last = values.begin() + static_cast(Page + values_to); while (first != last) { *fill++ = hash_v(*first++); } } // dead cases, try to avoid case collisions for (switch_t last_value = result[values_to - 1]; fill != result.end() && last_value != (std::numeric_limits::max)(); *fill++ = ++last_value) { } { auto it = result.begin(); auto last_value = (std::numeric_limits::min)(); for (; fill != result.end(); *fill++ = last_value++) { while (last_value == *it) { ++last_value, ++it; } } } return result; } template constexpr R invoke_r(F&& f, Args&&... args) noexcept(std::is_nothrow_invocable_r_v) { if constexpr (std::is_void_v) { std::forward(f)(std::forward(args)...); } else { return static_cast(std::forward(f)(std::forward(args)...)); } } enum class case_call_t { index, value }; template inline constexpr auto default_result_type_lambda = []() noexcept(std::is_nothrow_default_constructible_v) { return T{}; }; template <> inline constexpr auto default_result_type_lambda = []() noexcept {}; template constexpr bool has_duplicate() noexcept { using value_t = std::decay_t; using hash_value_t = std::invoke_result_t; std::arraysize()> hashes{}; std::size_t size = 0; for (auto elem : *Arr) { hashes[size] = hash_v(elem); for (auto i = size++; i > 0; --i) { if (hashes[i] < hashes[i - 1]) { auto tmp = hashes[i]; hashes[i] = hashes[i - 1]; hashes[i - 1] = tmp; } else if (hashes[i] == hashes[i - 1]) { return false; } else { break; } } } return true; } #define MAGIC_ENUM_CASE(val) \ case cases[val]: \ if constexpr ((val) + Page < size) { \ if (!pred(values[val + Page], searched)) { \ break; \ } \ if constexpr (CallValue == case_call_t::index) { \ if constexpr (std::is_invocable_r_v>) { \ return detail::invoke_r(std::forward(lambda), std::integral_constant{}); \ } else if constexpr (std::is_invocable_v>) { \ MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \ } \ } else if constexpr (CallValue == case_call_t::value) { \ if constexpr (std::is_invocable_r_v>) { \ return detail::invoke_r(std::forward(lambda), enum_constant{}); \ } else if constexpr (std::is_invocable_r_v>) { \ MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \ } \ } \ break; \ } else [[fallthrough]]; template ::value_type>, typename BinaryPredicate = std::equal_to<>, typename Lambda, typename ResultGetterType> constexpr decltype(auto) constexpr_switch( Lambda&& lambda, typename std::decay_t::value_type searched, ResultGetterType&& def, BinaryPredicate&& pred = {}) { using result_t = std::invoke_result_t; using hash_t = std::conditional_t(), Hash, typename Hash::secondary_hash>; static_assert(has_duplicate(), "magic_enum::detail::constexpr_switch duplicated hash found, please report it: https://github.com/Neargye/magic_enum/issues."); constexpr std::array values = *GlobValues; constexpr std::size_t size = values.size(); constexpr std::array cases = calculate_cases(Page); switch (hash_v(searched)) { MAGIC_ENUM_FOR_EACH_256(MAGIC_ENUM_CASE) default: if constexpr (size > 256 + Page) { return constexpr_switch(std::forward(lambda), searched, std::forward(def)); } break; } return def(); } #undef MAGIC_ENUM_CASE #endif } // namespace magic_enum::detail // Checks is magic_enum supported compiler. inline constexpr bool is_magic_enum_supported = detail::supported::value; template using Enum = detail::enum_concept; // Checks whether T is an Unscoped enumeration type. // 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. Otherwise, value is equal to false. template struct is_unscoped_enum : detail::is_unscoped_enum {}; template inline constexpr bool is_unscoped_enum_v = is_unscoped_enum::value; // Checks whether T is an Scoped enumeration type. // 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. Otherwise, value is equal to false. template struct is_scoped_enum : detail::is_scoped_enum {}; template inline constexpr bool is_scoped_enum_v = is_scoped_enum::value; // If T is a complete enumeration type, provides a member typedef type that names the underlying type of T. // Otherwise, if T is not an enumeration type, there is no member type. Otherwise (T is an incomplete enumeration type), the program is ill-formed. template struct underlying_type : detail::underlying_type {}; template using underlying_type_t = typename underlying_type::type; template using enum_constant = detail::enum_constant; // Returns type name of enum. template [[nodiscard]] constexpr auto enum_type_name() noexcept -> detail::enable_if_t { constexpr string_view name = detail::type_name_v>; static_assert(!name.empty(), "magic_enum::enum_type_name enum type does not have a name."); return name; } // Returns number of enum values. template > [[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_t { return detail::count_v, S>; } // Returns enum value at specified index. // No bounds checking is performed: the behavior is undefined if index >= number of enum values. template > [[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_t> { using D = std::decay_t; static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); if constexpr (detail::is_sparse_v) { return MAGIC_ENUM_ASSERT(index < detail::count_v), detail::values_v[index]; } else { constexpr auto min = (S == detail::enum_subtype::flags) ? detail::log2(detail::min_v) : detail::min_v; return MAGIC_ENUM_ASSERT(index < detail::count_v), detail::value(index); } } // Returns enum value at specified index. template > [[nodiscard]] constexpr auto enum_value() noexcept -> detail::enable_if_t> { using D = std::decay_t; static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); static_assert(I < detail::count_v, "magic_enum::enum_value out of range."); return enum_value(I); } // Returns std::array with enum values, sorted by enum value. template > [[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_t> { using D = std::decay_t; static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); return detail::values_v; } // Returns integer value from enum value. template [[nodiscard]] constexpr auto enum_integer(E value) noexcept -> detail::enable_if_t> { return static_cast>(value); } // Returns underlying value from enum value. template [[nodiscard]] constexpr auto enum_underlying(E value) noexcept -> detail::enable_if_t> { return static_cast>(value); } // Obtains index in enum values from enum value. // Returns optional with index. template > [[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t> { using D = std::decay_t; using U = underlying_type_t; static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); if constexpr (detail::is_sparse_v || (S == detail::enum_subtype::flags)) { #if defined(MAGIC_ENUM_ENABLE_HASH) return detail::constexpr_switch<&detail::values_v, detail::case_call_t::index>( [](std::size_t i) { return optional{i}; }, value, detail::default_result_type_lambda>); #else for (std::size_t i = 0; i < detail::count_v; ++i) { if (enum_value(i) == value) { return i; } } return {}; // Invalid value or out of range. #endif } else { const auto v = static_cast(value); if (v >= detail::min_v && v <= detail::max_v) { return static_cast(v - detail::min_v); } return {}; // Invalid value or out of range. } } // Obtains index in enum values from enum value. // Returns optional with index. template [[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t> { using D = std::decay_t; static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); return enum_index(value); } // Obtains index in enum values from static storage enum variable. template >> [[nodiscard]] constexpr auto enum_index() noexcept -> detail::enable_if_t {\ using D = std::decay_t; static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); constexpr auto index = enum_index(V); static_assert(index, "magic_enum::enum_index enum value does not have a index."); return *index; } // Returns name from static storage enum variable. // This version is much lighter on the compile times and is not restricted to the enum_range limitation. template [[nodiscard]] constexpr auto enum_name() noexcept -> detail::enable_if_t { constexpr string_view name = detail::enum_name_v, V>; static_assert(!name.empty(), "magic_enum::enum_name enum value does not have a name."); return name; } // Returns name from enum value. // If enum value does not have name or value out of range, returns empty string. template > [[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_t { using D = std::decay_t; static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); if (const auto i = enum_index(value)) { return detail::names_v[*i]; } return {}; } // Returns name from enum value. // If enum value does not have name or value out of range, returns empty string. template [[nodiscard]] constexpr auto enum_name(E value) -> detail::enable_if_t { using D = std::decay_t; static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); return enum_name(value); } // Returns std::array with names, sorted by enum value. template > [[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_t> { using D = std::decay_t; static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); return detail::names_v; } // Returns std::array with pairs (value, name), sorted by enum value. template > [[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_t> { using D = std::decay_t; static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); return detail::entries_v; } // Allows you to write magic_enum::enum_cast("bar", magic_enum::case_insensitive); inline constexpr auto case_insensitive = detail::case_insensitive<>{}; // Obtains enum value from integer value. // Returns optional with enum value. template > [[nodiscard]] constexpr auto enum_cast(underlying_type_t value) noexcept -> detail::enable_if_t>> { using D = std::decay_t; static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); if constexpr (detail::is_sparse_v || (S == detail::enum_subtype::flags)) { #if defined(MAGIC_ENUM_ENABLE_HASH) return detail::constexpr_switch<&detail::values_v, detail::case_call_t::value>( [](D v) { return optional{v}; }, static_cast(value), detail::default_result_type_lambda>); #else for (std::size_t i = 0; i < detail::count_v; ++i) { if (value == static_cast>(enum_value(i))) { return static_cast(value); } } return {}; // Invalid value or out of range. #endif } else { if (value >= detail::min_v && value <= detail::max_v) { return static_cast(value); } return {}; // Invalid value or out of range. } } // Obtains enum value from name. // Returns optional with enum value. template , typename BinaryPredicate = std::equal_to<>> [[nodiscard]] constexpr auto enum_cast(string_view value, [[maybe_unused]] BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable()) -> detail::enable_if_t>, BinaryPredicate> { using D = std::decay_t; static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); #if defined(MAGIC_ENUM_ENABLE_HASH) if constexpr (detail::is_default_predicate()) { return detail::constexpr_switch<&detail::names_v, detail::case_call_t::index>( [](std::size_t i) { return optional{detail::values_v[i]}; }, value, detail::default_result_type_lambda>, [&p](string_view lhs, string_view rhs) { return detail::cmp_equal(lhs, rhs, p); }); } #endif for (std::size_t i = 0; i < detail::count_v; ++i) { if (detail::cmp_equal(value, detail::names_v[i], p)) { return enum_value(i); } } return {}; // Invalid value or out of range. } // Checks whether enum contains value with such value. template > [[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t { using D = std::decay_t; using U = underlying_type_t; return static_cast(enum_cast(static_cast(value))); } // Checks whether enum contains value with such value. template [[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t { using D = std::decay_t; using U = underlying_type_t; return static_cast(enum_cast(static_cast(value))); } // Checks whether enum contains value with such integer value. template > [[nodiscard]] constexpr auto enum_contains(underlying_type_t value) noexcept -> detail::enable_if_t { using D = std::decay_t; return static_cast(enum_cast(value)); } // Checks whether enum contains enumerator with such name. template , typename BinaryPredicate = std::equal_to<>> [[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable()) -> detail::enable_if_t { using D = std::decay_t; return static_cast(enum_cast(value, std::move(p))); } // Returns true if the enum integer value is in the range of values that can be reflected. template > [[nodiscard]] constexpr auto enum_reflected(underlying_type_t value) noexcept -> detail::enable_if_t { using D = std::decay_t; if constexpr (detail::is_reflected_v) { constexpr auto min = detail::reflected_min(); constexpr auto max = detail::reflected_max(); return value >= min && value <= max; } else { return false; } } // Returns true if the enum value is in the range of values that can be reflected. template > [[nodiscard]] constexpr auto enum_reflected(E value) noexcept -> detail::enable_if_t { using D = std::decay_t; return enum_reflected(static_cast>(value)); } // Returns true if the enum value is in the range of values that can be reflected. template [[nodiscard]] constexpr auto enum_reflected(E value) noexcept -> detail::enable_if_t { using D = std::decay_t; return enum_reflected(value); } template inline constexpr auto as_flags = AsFlags ? detail::enum_subtype::flags : detail::enum_subtype::common; template inline constexpr auto as_common = AsFlags ? detail::enum_subtype::common : detail::enum_subtype::flags; namespace bitwise_operators { template = 0> constexpr E operator~(E rhs) noexcept { return static_cast(~static_cast>(rhs)); } template = 0> constexpr E operator|(E lhs, E rhs) noexcept { return static_cast(static_cast>(lhs) | static_cast>(rhs)); } template = 0> constexpr E operator&(E lhs, E rhs) noexcept { return static_cast(static_cast>(lhs) & static_cast>(rhs)); } template = 0> constexpr E operator^(E lhs, E rhs) noexcept { return static_cast(static_cast>(lhs) ^ static_cast>(rhs)); } template = 0> constexpr E& operator|=(E& lhs, E rhs) noexcept { return lhs = (lhs | rhs); } template = 0> constexpr E& operator&=(E& lhs, E rhs) noexcept { return lhs = (lhs & rhs); } template = 0> constexpr E& operator^=(E& lhs, E rhs) noexcept { return lhs = (lhs ^ rhs); } } // namespace magic_enum::bitwise_operators } // namespace magic_enum #if defined(__clang__) # pragma clang diagnostic pop #elif defined(__GNUC__) # pragma GCC diagnostic pop #elif defined(_MSC_VER) # pragma warning(pop) #endif #undef MAGIC_ENUM_GET_ENUM_NAME_BUILTIN #undef MAGIC_ENUM_GET_TYPE_NAME_BUILTIN #undef MAGIC_ENUM_VS_2017_WORKAROUND #undef MAGIC_ENUM_ARRAY_CONSTEXPR #undef MAGIC_ENUM_FOR_EACH_256 #endif // NEARGYE_MAGIC_ENUM_HPP magic_enum-0.9.6/include/magic_enum/magic_enum_all.hpp000066400000000000000000000042551464001350000230250ustar00rootroot00000000000000// __ __ _ ______ _____ // | \/ | (_) | ____| / ____|_ _ // | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ // | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| // | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| // |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| // __/ | https://github.com/Neargye/magic_enum // |___/ version 0.9.6 // // Licensed under the MIT License . // SPDX-License-Identifier: MIT // Copyright (c) 2019 - 2024 Daniil Goncharov . // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // 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 OR COPYRIGHT HOLDERS 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. #ifndef NEARGYE_MAGIC_ENUM_ALL_HPP #define NEARGYE_MAGIC_ENUM_ALL_HPP #include "magic_enum.hpp" #include "magic_enum_containers.hpp" #include "magic_enum_flags.hpp" #include "magic_enum_format.hpp" #include "magic_enum_fuse.hpp" #include "magic_enum_iostream.hpp" #include "magic_enum_switch.hpp" #include "magic_enum_utility.hpp" #endif // NEARGYE_MAGIC_ENUM_ALL_HPP magic_enum-0.9.6/include/magic_enum/magic_enum_containers.hpp000066400000000000000000001226301464001350000244200ustar00rootroot00000000000000// __ __ _ ______ _____ // | \/ | (_) | ____| / ____|_ _ // | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ // | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| // | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| // |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| // __/ | https://github.com/Neargye/magic_enum // |___/ version 0.9.6 // // Licensed under the MIT License . // SPDX-License-Identifier: MIT // Copyright (c) 2019 - 2024 Daniil Goncharov . // Copyright (c) 2022 - 2023 Bela Schaum . // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // 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 OR COPYRIGHT HOLDERS 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. #ifndef NEARGYE_MAGIC_ENUM_CONTAINERS_HPP #define NEARGYE_MAGIC_ENUM_CONTAINERS_HPP #include "magic_enum.hpp" #if !defined(MAGIC_ENUM_NO_EXCEPTION) && (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) #ifndef MAGIC_ENUM_USE_STD_MODULE # include #endif # define MAGIC_ENUM_THROW(...) throw (__VA_ARGS__) #else #ifndef MAGIC_ENUM_USE_STD_MODULE # include #endif # define MAGIC_ENUM_THROW(...) std::abort() #endif namespace magic_enum::containers { namespace detail { template static constexpr bool is_transparent_v{}; template static constexpr bool is_transparent_v>{true}; template , typename T1, typename T2> constexpr bool equal(T1&& t1, T2&& t2, Eq&& eq = {}) { auto first1 = t1.begin(); auto last1 = t1.end(); auto first2 = t2.begin(); auto last2 = t2.end(); for (; first1 != last1; ++first1, ++first2) { if (first2 == last2 || !eq(*first1, *first2)) { return false; } } return first2 == last2; } template , typename T1, typename T2> constexpr bool lexicographical_compare(T1&& t1, T2&& t2, Cmp&& cmp = {}) noexcept { auto first1 = t1.begin(); auto last1 = t1.end(); auto first2 = t2.begin(); auto last2 = t2.end(); // copied from std::lexicographical_compare for (; (first1 != last1) && (first2 != last2); ++first1, (void)++first2) { if (cmp(*first1, *first2)) { return true; } if (cmp(*first2, *first1)) { return false; } } return (first1 == last1) && (first2 != last2); } template constexpr std::size_t popcount(T x) noexcept { std::size_t c = 0; while (x > 0) { c += x & 1; x >>= 1; } return c; } template , typename ForwardIt, typename E> constexpr ForwardIt lower_bound(ForwardIt first, ForwardIt last, E&& e, Cmp&& comp = {}) { auto count = std::distance(first, last); for (auto it = first; count > 0;) { auto step = count / 2; std::advance(it, step); if (comp(*it, e)) { first = ++it; count -= step + 1; } else { count = step; } } return first; } template , typename BidirIt, typename E> constexpr auto equal_range(BidirIt begin, BidirIt end, E&& e, Cmp&& comp = {}) { const auto first = lower_bound(begin, end, e, comp); return std::pair{first, lower_bound(std::make_reverse_iterator(end), std::make_reverse_iterator(first), e, [&comp](auto&& lhs, auto&& rhs) { return comp(rhs, lhs); }).base()}; } template , typename = void> class indexing { [[nodiscard]] static constexpr auto get_indices() noexcept { // reverse result index mapping std::array()> rev_res{}; // std::iota for (std::size_t i = 0; i < enum_count(); ++i) { rev_res[i] = i; } constexpr auto orig_values = enum_values(); constexpr Cmp cmp{}; // ~std::sort for (std::size_t i = 0; i < enum_count(); ++i) { for (std::size_t j = i + 1; j < enum_count(); ++j) { if (cmp(orig_values[rev_res[j]], orig_values[rev_res[i]])) { auto tmp = rev_res[i]; rev_res[i] = rev_res[j]; rev_res[j] = tmp; } } } std::array()> sorted_values{}; // reverse the sorted indices std::array()> res{}; for (std::size_t i = 0; i < enum_count(); ++i) { res[rev_res[i]] = i; sorted_values[i] = orig_values[rev_res[i]]; } return std::pair{sorted_values, res}; } static constexpr auto indices = get_indices(); public: [[nodiscard]] static constexpr const E* begin() noexcept { return indices.first.data(); } [[nodiscard]] static constexpr const E* end() noexcept { return indices.first.data() + indices.first.size(); } [[nodiscard]] static constexpr const E* it(std::size_t i) noexcept { return indices.first.data() + i; } [[nodiscard]] static constexpr optional at(E val) noexcept { if (auto i = enum_index(val)) { return indices.second[*i]; } return {}; } }; template class indexing> && (std::is_same_v> || std::is_same_v>)>> { static constexpr auto& values = enum_values(); public: [[nodiscard]] static constexpr const E* begin() noexcept { return values.data(); } [[nodiscard]] static constexpr const E* end() noexcept { return values.data() + values.size(); } [[nodiscard]] static constexpr const E* it(std::size_t i) noexcept { return values.data() + i; } [[nodiscard]] static constexpr optional at(E val) noexcept { return enum_index(val); } }; template struct indexing { using is_transparent = std::true_type; template [[nodiscard]] static constexpr optional at(E val) noexcept { return indexing::at(val); } }; template , typename = void> struct name_sort_impl { [[nodiscard]] constexpr bool operator()(E e1, E e2) const noexcept { return Cmp{}(enum_name(e1), enum_name(e2)); } }; template struct name_sort_impl { using is_transparent = std::true_type; template struct FullCmp : C {}; template struct FullCmp && std::is_invocable_v>> { [[nodiscard]] constexpr bool operator()(string_view s1, string_view s2) const noexcept { return lexicographical_compare(s1, s2); } }; template [[nodiscard]] constexpr std::enable_if_t< // at least one of need to be an enum type (std::is_enum_v> || std::is_enum_v>) && // if both is enum, only accept if the same enum (!std::is_enum_v> || !std::is_enum_v> || std::is_same_v) && // is invocable with comparator (std::is_invocable_r_v, std::conditional_t>, string_view, E1>, std::conditional_t>, string_view, E2>>), bool> operator()(E1 e1, E2 e2) const noexcept { using D1 = std::decay_t; using D2 = std::decay_t; constexpr FullCmp<> cmp{}; if constexpr (std::is_enum_v && std::is_enum_v) { return cmp(enum_name(e1), enum_name(e2)); } else if constexpr (std::is_enum_v) { return cmp(enum_name(e1), e2); } else /* if constexpr (std::is_enum_v) */ { return cmp(e1, enum_name(e2)); } } }; struct raw_access_t {}; template struct FilteredIterator { Parent parent; Iterator first; Iterator last; Iterator current; Getter getter; Predicate predicate; using iterator_category = std::bidirectional_iterator_tag; using value_type = std::remove_reference_t>; using difference_type = std::ptrdiff_t; using pointer = value_type*; using reference = value_type&; constexpr FilteredIterator() noexcept = default; constexpr FilteredIterator(const FilteredIterator&) = default; constexpr FilteredIterator& operator=(const FilteredIterator&) = default; constexpr FilteredIterator(FilteredIterator&&) noexcept = default; constexpr FilteredIterator& operator=(FilteredIterator&&) noexcept = default; template && std::is_convertible_v>*> constexpr explicit FilteredIterator(const FilteredIterator& other) : parent(other.parent), first(other.first), last(other.last), current(other.current), getter(other.getter), predicate(other.predicate) {} constexpr FilteredIterator(Parent p, Iterator begin, Iterator end, Iterator curr, Getter get = {}, Predicate pred = {}) : parent(p), first(std::move(begin)), last(std::move(end)), current(std::move(curr)), getter{std::move(get)}, predicate{std::move(pred)} { if (current == first && !predicate(parent, current)) { ++*this; } } [[nodiscard]] constexpr reference operator*() const { return getter(parent, current); } [[nodiscard]] constexpr pointer operator->() const { return std::addressof(**this); } constexpr FilteredIterator& operator++() { do { ++current; } while (current != last && !predicate(parent, current)); return *this; } [[nodiscard]] constexpr FilteredIterator operator++(int) { FilteredIterator cp = *this; ++*this; return cp; } constexpr FilteredIterator& operator--() { do { --current; } while (current != first && !predicate(parent, current)); return *this; } [[nodiscard]] constexpr FilteredIterator operator--(int) { FilteredIterator cp = *this; --*this; return cp; } [[nodiscard]] friend constexpr bool operator==(const FilteredIterator& lhs, const FilteredIterator& rhs) { return lhs.current == rhs.current; } [[nodiscard]] friend constexpr bool operator!=(const FilteredIterator& lhs, const FilteredIterator& rhs) { return lhs.current != rhs.current; } }; } // namespace detail template using name_less = detail::name_sort_impl; template using name_greater = detail::name_sort_impl>; using name_less_case_insensitive = detail::name_sort_impl>>; using name_greater_case_insensitive = detail::name_sort_impl>>; template using default_indexing = detail::indexing; template > using comparator_indexing = detail::indexing; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // ARRAY // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template > struct array { static_assert(std::is_enum_v); static_assert(std::is_trivially_constructible_v); static_assert(enum_count() > 0 && Index::at(enum_values().front())); using index_type = Index; using container_type = std::array()>; using value_type = typename container_type::value_type; using size_type = typename container_type::size_type; using difference_type = typename container_type::difference_type; using reference = typename container_type::reference; using const_reference = typename container_type::const_reference; using pointer = typename container_type::pointer; using const_pointer = typename container_type::const_pointer; using iterator = typename container_type::iterator; using const_iterator = typename container_type::const_iterator; using reverse_iterator = typename container_type::reverse_iterator; using const_reverse_iterator = typename container_type::const_reverse_iterator; constexpr reference at(E pos) { if (auto index = index_type::at(pos)) { return a[*index]; } MAGIC_ENUM_THROW(std::out_of_range("magic_enum::containers::array::at Unrecognized position")); } constexpr const_reference at(E pos) const { if (auto index = index_type::at(pos)) { return a[*index]; } MAGIC_ENUM_THROW(std::out_of_range("magic_enum::containers::array::at: Unrecognized position")); } [[nodiscard]] constexpr reference operator[](E pos) { auto i = index_type::at(pos); return MAGIC_ENUM_ASSERT(i), a[*i]; } [[nodiscard]] constexpr const_reference operator[](E pos) const { auto i = index_type::at(pos); return MAGIC_ENUM_ASSERT(i), a[*i]; } [[nodiscard]] constexpr reference front() noexcept { return a.front(); } [[nodiscard]] constexpr const_reference front() const noexcept { return a.front(); } [[nodiscard]] constexpr reference back() noexcept { return a.back(); } [[nodiscard]] constexpr const_reference back() const noexcept { return a.back(); } [[nodiscard]] constexpr pointer data() noexcept { return a.data(); } [[nodiscard]] constexpr const_pointer data() const noexcept { return a.data(); } [[nodiscard]] constexpr iterator begin() noexcept { return a.begin(); } [[nodiscard]] constexpr const_iterator begin() const noexcept { return a.begin(); } [[nodiscard]] constexpr const_iterator cbegin() const noexcept { return a.cbegin(); } [[nodiscard]] constexpr iterator end() noexcept { return a.end(); } [[nodiscard]] constexpr const_iterator end() const noexcept { return a.end(); } [[nodiscard]] constexpr const_iterator cend() const noexcept { return a.cend(); } [[nodiscard]] constexpr iterator rbegin() noexcept { return a.rbegin(); } [[nodiscard]] constexpr const_iterator rbegin() const noexcept { return a.rbegin(); } [[nodiscard]] constexpr const_iterator crbegin() const noexcept { return a.crbegin(); } [[nodiscard]] constexpr iterator rend() noexcept { return a.rend(); } [[nodiscard]] constexpr const_iterator rend() const noexcept { return a.rend(); } [[nodiscard]] constexpr const_iterator crend() const noexcept { return a.crend(); } [[nodiscard]] constexpr bool empty() const noexcept { return a.empty(); } [[nodiscard]] constexpr size_type size() const noexcept { return a.size(); } [[nodiscard]] constexpr size_type max_size() const noexcept { return a.max_size(); } constexpr void fill(const V& value) { for (auto& v : a) { v = value; } } constexpr void swap(array& other) noexcept(std::is_nothrow_swappable_v) { for (std::size_t i = 0; i < a.size(); ++i) { auto v = std::move(other.a[i]); other.a[i] = std::move(a[i]); a[i] = std::move(v); } } [[nodiscard]] friend constexpr bool operator==(const array& a1, const array& a2) { return detail::equal(a1, a2); } [[nodiscard]] friend constexpr bool operator!=(const array& a1, const array& a2) { return !detail::equal(a1, a2); } [[nodiscard]] friend constexpr bool operator<(const array& a1, const array& a2) { return detail::lexicographical_compare(a1, a2); } [[nodiscard]] friend constexpr bool operator<=(const array& a1, const array& a2) { return !detail::lexicographical_compare(a2, a1); } [[nodiscard]] friend constexpr bool operator>(const array& a1, const array& a2) { return detail::lexicographical_compare(a2, a1); } [[nodiscard]] friend constexpr bool operator>=(const array& a1, const array& a2) { return !detail::lexicographical_compare(a1, a2); } container_type a; }; namespace detail { template constexpr array> to_array_impl(T (&a)[N], std::index_sequence) { return {{a[I]...}}; } template constexpr array> to_array_impl(T(&&a)[N], std::index_sequence) { return {{std::move(a[I])...}}; } } // namespace detail template constexpr std::enable_if_t<(enum_count() == N), array>> to_array(T (&a)[N]) { return detail::to_array_impl(a, std::make_index_sequence{}); } template constexpr std::enable_if_t<(enum_count() == N), array>> to_array(T(&&a)[N]) { return detail::to_array_impl(std::move(a), std::make_index_sequence{}); } template constexpr std::enable_if_t<(enum_count() == sizeof...(Ts)), array>>> make_array(Ts&&... ts) { return {{std::forward(ts)...}}; } inline constexpr detail::raw_access_t raw_access{}; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // BITSET // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template > class bitset { static_assert(std::is_enum_v); static_assert(std::is_trivially_constructible_v); static_assert(enum_count() > 0 && Index::at(enum_values().front())); using base_type = std::conditional_t() <= 8, std::uint_least8_t, std::conditional_t() <= 16, std::uint_least16_t, std::conditional_t() <= 32, std::uint_least32_t, std::uint_least64_t>>>; static constexpr std::size_t bits_per_base = sizeof(base_type) * 8; static constexpr std::size_t base_type_count = (enum_count() > 0 ? (enum_count() - 1) / bits_per_base + 1 : 0); static constexpr std::size_t not_interested = base_type_count * bits_per_base - enum_count(); static constexpr base_type last_value_max = (base_type{1} << (bits_per_base - not_interested)) - 1; template class reference_impl { friend class bitset; parent_t parent; std::size_t num_index; base_type bit_index; constexpr reference_impl(parent_t p, std::size_t i) noexcept : reference_impl(p, std::pair{i / bits_per_base, base_type{1} << (i % bits_per_base)}) {} constexpr reference_impl(parent_t p, std::pair i) noexcept : parent(p), num_index(std::get<0>(i)), bit_index(std::get<1>(i)) {} public: constexpr reference_impl& operator=(bool v) noexcept { if (v) { parent->a[num_index] |= bit_index; } else { parent->a[num_index] &= ~bit_index; } return *this; } constexpr reference_impl& operator=(const reference_impl& v) noexcept { if (this == &v) { return *this; } *this = static_cast(v); return *this; } [[nodiscard]] constexpr operator bool() const noexcept { return (parent->a[num_index] & bit_index) > 0; } [[nodiscard]] constexpr bool operator~() const noexcept { return !static_cast(*this); } constexpr reference_impl& flip() noexcept { *this = ~*this; return *this; } }; template [[nodiscard]] constexpr T to_(detail::raw_access_t) const { T res{}; T flag{1}; for (std::size_t i = 0; i < size(); ++i, flag <<= 1) { if (const_reference{this, i}) { if (i >= sizeof(T) * 8) { MAGIC_ENUM_THROW(std::overflow_error("magic_enum::containers::bitset::to: Cannot represent enum in this type")); } res |= flag; } } return res; } public: using index_type = Index; using container_type = std::array; using reference = reference_impl<>; using const_reference = reference_impl; constexpr explicit bitset(detail::raw_access_t = raw_access) noexcept : a{{}} {} constexpr explicit bitset(detail::raw_access_t, unsigned long long val) : a{{}} { unsigned long long bit{1}; for (std::size_t i = 0; i < (sizeof(val) * 8); ++i, bit <<= 1) { if ((val & bit) > 0) { if (i >= enum_count()) { MAGIC_ENUM_THROW(std::out_of_range("magic_enum::containers::bitset::constructor: Upper bit set in raw number")); } reference{this, i} = true; } } } constexpr explicit bitset(detail::raw_access_t, string_view sv, string_view::size_type pos = 0, string_view::size_type n = string_view::npos, char_type zero = static_cast('0'), char_type one = static_cast('1')) : a{{}} { std::size_t i = 0; for (auto c : sv.substr(pos, n)) { if (c == one) { if (i >= enum_count()) { MAGIC_ENUM_THROW(std::out_of_range("magic_enum::containers::bitset::constructor: Upper bit set in raw string")); } reference{this, i} = true; } else if (c != zero) { MAGIC_ENUM_THROW(std::invalid_argument("magic_enum::containers::bitset::constructor: Unrecognized character in raw string")); } ++i; } } constexpr explicit bitset(detail::raw_access_t, const char_type* str, std::size_t n = ~std::size_t{0}, char_type zero = static_cast('0'), char_type one = static_cast('1')) : bitset(string_view{str, (std::min)(std::char_traits::length(str), n)}, 0, n, zero, one) {} constexpr bitset(std::initializer_list starters) : a{{}} { if constexpr (magic_enum::detail::subtype_v == magic_enum::detail::enum_subtype::flags) { for (auto& f : starters) { *this |= bitset(f); } } else { for (auto& f : starters) { set(f); } } } template && magic_enum::detail::subtype_v == magic_enum::detail::enum_subtype::flags, int> = 0> constexpr explicit bitset(V starter) : a{{}} { auto u = enum_underlying(starter); for (E v : enum_values()) { if (auto ul = enum_underlying(v); (ul & u) != 0) { u &= ~ul; (*this)[v] = true; } } if (u != 0) { MAGIC_ENUM_THROW(std::invalid_argument("magic_enum::containers::bitset::constructor: Unrecognized enum value in flag")); } } template > constexpr explicit bitset(string_view sv, Cmp&& cmp = {}, char_type sep = static_cast('|')) { for (std::size_t to = 0; (to = magic_enum::detail::find(sv, sep)) != string_view::npos; sv.remove_prefix(to + 1)) { if (auto v = enum_cast(sv.substr(0, to), cmp)) { set(v); } else { MAGIC_ENUM_THROW(std::invalid_argument("magic_enum::containers::bitset::constructor: Unrecognized enum value in string")); } } if (!sv.empty()) { if (auto v = enum_cast(sv, cmp)) { set(v); } else { MAGIC_ENUM_THROW(std::invalid_argument("magic_enum::containers::bitset::constructor: Unrecognized enum value in string")); } } } [[nodiscard]] friend constexpr bool operator==(const bitset& lhs, const bitset& rhs) noexcept { return detail::equal(lhs.a, rhs.a); } [[nodiscard]] friend constexpr bool operator!=(const bitset& lhs, const bitset& rhs) noexcept { return !detail::equal(lhs.a, rhs.a); } [[nodiscard]] constexpr bool operator[](E pos) const { auto i = index_type::at(pos); return MAGIC_ENUM_ASSERT(i), static_cast(const_reference(this, *i)); } [[nodiscard]] constexpr reference operator[](E pos) { auto i = index_type::at(pos); return MAGIC_ENUM_ASSERT(i), reference{this, *i}; } constexpr bool test(E pos) const { if (auto i = index_type::at(pos)) { return static_cast(const_reference(this, *i)); } MAGIC_ENUM_THROW(std::out_of_range("magic_enum::containers::bitset::test: Unrecognized position")); } [[nodiscard]] constexpr bool all() const noexcept { if constexpr (base_type_count == 0) { return true; } for (std::size_t i = 0; i < base_type_count - (not_interested > 0); ++i) { auto check = ~a[i]; if (check) { return false; } } if constexpr (not_interested > 0) { return a[base_type_count - 1] == last_value_max; } } [[nodiscard]] constexpr bool any() const noexcept { for (auto& v : a) { if (v > 0) { return true; } } return false; } [[nodiscard]] constexpr bool none() const noexcept { return !any(); } [[nodiscard]] constexpr std::size_t count() const noexcept { std::size_t c = 0; for (auto& v : a) { c += detail::popcount(v); } return c; } [[nodiscard]] constexpr std::size_t size() const noexcept { return enum_count(); } [[nodiscard]] constexpr std::size_t max_size() const noexcept { return enum_count(); } constexpr bitset& operator&=(const bitset& other) noexcept { for (std::size_t i = 0; i < base_type_count; ++i) { a[i] &= other.a[i]; } return *this; } constexpr bitset& operator|=(const bitset& other) noexcept { for (std::size_t i = 0; i < base_type_count; ++i) { a[i] |= other.a[i]; } return *this; } constexpr bitset& operator^=(const bitset& other) noexcept { for (std::size_t i = 0; i < base_type_count; ++i) { a[i] ^= other.a[i]; } return *this; } [[nodiscard]] constexpr bitset operator~() const noexcept { bitset res; for (std::size_t i = 0; i < base_type_count - (not_interested > 0); ++i) { res.a[i] = ~a[i]; } if constexpr (not_interested > 0) { res.a[base_type_count - 1] = ~a[base_type_count - 1] & last_value_max; } return res; } constexpr bitset& set() noexcept { for (std::size_t i = 0; i < base_type_count - (not_interested > 0); ++i) { a[i] = ~base_type{0}; } if constexpr (not_interested > 0) { a[base_type_count - 1] = last_value_max; } return *this; } constexpr bitset& set(E pos, bool value = true) { if (auto i = index_type::at(pos)) { reference{this, *i} = value; return *this; } MAGIC_ENUM_THROW(std::out_of_range("magic_enum::containers::bitset::set: Unrecognized position")); } constexpr bitset& reset() noexcept { return *this = bitset{}; } constexpr bitset& reset(E pos) { if (auto i = index_type::at(pos)) { reference{this, *i} = false; return *this; } MAGIC_ENUM_THROW(std::out_of_range("magic_enum::containers::bitset::reset: Unrecognized position")); } constexpr bitset& flip() noexcept { return *this = ~*this; } [[nodiscard]] friend constexpr bitset operator&(const bitset& lhs, const bitset& rhs) noexcept { bitset cp = lhs; cp &= rhs; return cp; } [[nodiscard]] friend constexpr bitset operator|(const bitset& lhs, const bitset& rhs) noexcept { bitset cp = lhs; cp |= rhs; return cp; } [[nodiscard]] friend constexpr bitset operator^(const bitset& lhs, const bitset& rhs) noexcept { bitset cp = lhs; cp ^= rhs; return cp; } template [[nodiscard]] constexpr explicit operator std::enable_if_t == magic_enum::detail::enum_subtype::flags, E>() const { E res{}; for (const auto& e : enum_values()) { if (test(e)) { res |= e; } } return res; } [[nodiscard]] string to_string(char_type sep = static_cast('|')) const { string name; for (const auto& e : enum_values()) { if (test(e)) { if (!name.empty()) { name.append(1, sep); } auto n = enum_name(e); name.append(n.data(), n.size()); } } return name; } [[nodiscard]] string to_string(detail::raw_access_t, char_type zero = static_cast('0'), char_type one = static_cast('1')) const { string name; name.reserve(size()); for (std::size_t i = 0; i < size(); ++i) { name.append(1, const_reference{this, i} ? one : zero); } return name; } [[nodiscard]] constexpr unsigned long long to_ullong(detail::raw_access_t raw) const { return to_(raw); } [[nodiscard]] constexpr unsigned long long to_ulong(detail::raw_access_t raw) const { return to_(raw); } friend std::ostream& operator<<(std::ostream& o, const bitset& bs) { return o << bs.to_string(); } friend std::istream& operator>>(std::istream& i, bitset& bs) { string s; if (i >> s; !s.empty()) { bs = bitset(string_view{s}); } return i; } private: container_type a; }; template explicit bitset(V starter) -> bitset; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // SET // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// template > class set { using index_type = detail::indexing; struct Getter { constexpr const E& operator()(const set*, const E* p) const noexcept { return *p; } }; struct Predicate { constexpr bool operator()(const set* h, const E* e) const noexcept { return h->a[*e]; } }; public: using container_type = bitset; using key_type = E; using value_type = E; using size_type = std::size_t; using difference_type = std::ptrdiff_t; using key_compare = Cmp; using value_compare = Cmp; using reference = value_type&; using const_reference = const value_type&; using pointer = value_type*; using const_pointer = const value_type*; using iterator = detail::FilteredIterator; using const_iterator = detail::FilteredIterator; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; constexpr set() noexcept = default; template constexpr set(InputIt first, InputIt last) { while (first != last) { insert(*first++); } } constexpr set(std::initializer_list ilist) { for (auto e : ilist) { insert(e); } } template && magic_enum::detail::subtype_v == magic_enum::detail::enum_subtype::flags, int> = 0> constexpr explicit set(V starter) { auto u = enum_underlying(starter); for (E v : enum_values()) { if ((enum_underlying(v) & u) != 0) { insert(v); } } } constexpr set(const set&) noexcept = default; constexpr set(set&&) noexcept = default; constexpr set& operator=(const set&) noexcept = default; constexpr set& operator=(set&&) noexcept = default; constexpr set& operator=(std::initializer_list ilist) { for (auto e : ilist) { insert(e); } } constexpr const_iterator begin() const noexcept { return const_iterator{this, index_type::begin(), index_type::end(), index_type::begin()}; } constexpr const_iterator end() const noexcept { return const_iterator{this, index_type::begin(), index_type::end(), index_type::end()}; } constexpr const_iterator cbegin() const noexcept { return begin(); } constexpr const_iterator cend() const noexcept { return end(); } constexpr const_reverse_iterator rbegin() const noexcept { return {end()}; } constexpr const_reverse_iterator rend() const noexcept { return {begin()}; } constexpr const_reverse_iterator crbegin() const noexcept { return rbegin(); } constexpr const_reverse_iterator crend() const noexcept { return rend(); } [[nodiscard]] constexpr bool empty() const noexcept { return s == 0; } [[nodiscard]] constexpr size_type size() const noexcept { return s; } [[nodiscard]] constexpr size_type max_size() const noexcept { return a.max_size(); } constexpr void clear() noexcept { a.reset(); s = 0; } constexpr std::pair insert(const value_type& value) noexcept { if (auto i = index_type::at(value)) { typename container_type::reference ref = a[value]; bool r = !ref; if (r) { ref = true; ++s; } return {iterator{this, index_type::begin(), index_type::end(), index_type::it(*i)}, r}; } return {end(), false}; } constexpr std::pair insert(value_type&& value) noexcept { return insert(value); } constexpr iterator insert(const_iterator, const value_type& value) noexcept { return insert(value).first; } constexpr iterator insert(const_iterator hint, value_type&& value) noexcept { return insert(hint, value); } template constexpr void insert(InputIt first, InputIt last) noexcept { while (first != last) { insert(*first++); } } constexpr void insert(std::initializer_list ilist) noexcept { for (auto v : ilist) { insert(v); } } template constexpr std::pair emplace(Args&&... args) noexcept { return insert({std::forward(args)...}); } template constexpr iterator emplace_hint(const_iterator, Args&&... args) noexcept { return emplace(std::forward(args)...).first; } constexpr iterator erase(const_iterator pos) noexcept { erase(*pos++); return pos; } constexpr iterator erase(const_iterator first, const_iterator last) noexcept { while ((first = erase(first)) != last) { } return first; } constexpr size_type erase(const key_type& key) noexcept { typename container_type::reference ref = a[key]; bool res = ref; if (res) { --s; } ref = false; return res; } template constexpr std::enable_if_t, size_type> erase(K&& x) noexcept { size_type c = 0; for (auto [first, last] = detail::equal_range(index_type::begin(), index_type::end(), x, key_compare{}); first != last;) { c += erase(*first++); } return c; } void swap(set& other) noexcept { set cp = *this; *this = other; other = cp; } [[nodiscard]] constexpr size_type count(const key_type& key) const noexcept { return index_type::at(key) && a[key]; } template [[nodiscard]] constexpr std::enable_if_t, size_type> count(const K& x) const { size_type c = 0; for (auto [first, last] = detail::equal_range(index_type::begin(), index_type::end(), x, key_compare{}); first != last; ++first) { c += count(*first); } return c; } [[nodiscard]] constexpr const_iterator find(const key_type& key) const noexcept { if (auto i = index_type::at(key); i && a.test(key)) { return const_iterator{this, index_type::begin(), index_type::end(), index_type::it(*i)}; } return end(); } template [[nodiscard]] constexpr std::enable_if_t, const_iterator> find(const K& x) const { for (auto [first, last] = detail::equal_range(index_type::begin(), index_type::end(), x, key_compare{}); first != last; ++first) { if (a.test(*first)) { return find(*first); } } return end(); } [[nodiscard]] constexpr bool contains(const key_type& key) const noexcept { return count(key); } template [[nodiscard]] constexpr std::enable_if_t, bool> contains(const K& x) const noexcept { return count(x) > 0; } [[nodiscard]] constexpr std::pair equal_range(const key_type& key) const noexcept { return {lower_bound(key), upper_bound(key)}; } template [[nodiscard]] constexpr std::enable_if_t, std::pair> equal_range(const K& x) const noexcept { return {lower_bound(x), upper_bound(x)}; } [[nodiscard]] constexpr const_iterator lower_bound(const key_type& key) const noexcept { if (auto i = index_type::at(key)) { auto it = const_iterator{this, index_type::begin(), index_type::end(), index_type::it(*i)}; return a.test(key) ? it : std::next(it); } return end(); } template [[nodiscard]] constexpr std::enable_if_t, const_iterator> lower_bound(const K& x) const noexcept { auto [first, last] = detail::equal_range(index_type::begin(), index_type::end(), x, key_compare{}); return first != last ? lower_bound(*first) : end(); } [[nodiscard]] constexpr const_iterator upper_bound(const key_type& key) const noexcept { if (auto i = index_type::at(key)) { return std::next(const_iterator{this, index_type::begin(), index_type::end(), index_type::it(*i)}); } return end(); } template [[nodiscard]] constexpr std::enable_if_t, const_iterator> upper_bound(const K& x) const noexcept { auto [first, last] = detail::equal_range(index_type::begin(), index_type::end(), x, key_compare{}); return first != last ? upper_bound(*std::prev(last)) : end(); } [[nodiscard]] constexpr key_compare key_comp() const { return {}; } [[nodiscard]] constexpr value_compare value_comp() const { return {}; } [[nodiscard]] constexpr friend bool operator==(const set& lhs, const set& rhs) noexcept { return lhs.a == rhs.a; } [[nodiscard]] constexpr friend bool operator!=(const set& lhs, const set& rhs) noexcept { return lhs.a != rhs.a; } [[nodiscard]] constexpr friend bool operator<(const set& lhs, const set& rhs) noexcept { if (lhs.s < rhs.s) { return true; } if (rhs.s < lhs.s) { return false; } for (auto it = index_type::begin(); it != index_type::end(); ++it) { if (auto c = rhs.contains(*it); c != lhs.contains(*it)) { return c; } } return false; } [[nodiscard]] constexpr friend bool operator<=(const set& lhs, const set& rhs) noexcept { return !(rhs < lhs); } [[nodiscard]] constexpr friend bool operator>(const set& lhs, const set& rhs) noexcept { return rhs < lhs; } [[nodiscard]] constexpr friend bool operator>=(const set& lhs, const set& rhs) noexcept { return !(lhs < rhs); } template size_type erase_if(Pred pred) { auto old_size = size(); for (auto i = begin(), last = end(); i != last;) { if (pred(*i)) { i = erase(i); } else { ++i; } } return old_size - size(); } private: container_type a; std::size_t s = 0; }; template explicit set(V starter) -> set; template constexpr std::enable_if_t<(std::is_integral_v && I < enum_count()), V&> get(array& a) noexcept { return a.a[I]; } template constexpr std::enable_if_t<(std::is_integral_v && I < enum_count()), V&&> get(array&& a) noexcept { return std::move(a.a[I]); } template constexpr std::enable_if_t<(std::is_integral_v && I < enum_count()), const V&> get(const array& a) noexcept { return a.a[I]; } template constexpr std::enable_if_t<(std::is_integral_v && I < enum_count()), const V&&> get(const array&& a) noexcept { return std::move(a.a[I]); } template constexpr std::enable_if_t && enum_contains(Enum), V&> get(array& a) { return a[Enum]; } template constexpr std::enable_if_t && enum_contains(Enum), V&&> get(array&& a) { return std::move(a[Enum]); } template constexpr std::enable_if_t && enum_contains(Enum), const V&> get(const array& a) { return a[Enum]; } template constexpr std::enable_if_t && enum_contains(Enum), const V&&> get(const array&& a) { return std::move(a[Enum]); } } // namespace magic_enum::containers #endif // NEARGYE_MAGIC_ENUM_CONTAINERS_HPP magic_enum-0.9.6/include/magic_enum/magic_enum_flags.hpp000066400000000000000000000205231464001350000233450ustar00rootroot00000000000000// __ __ _ ______ _____ // | \/ | (_) | ____| / ____|_ _ // | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ // | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| // | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| // |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| // __/ | https://github.com/Neargye/magic_enum // |___/ version 0.9.6 // // Licensed under the MIT License . // SPDX-License-Identifier: MIT // Copyright (c) 2019 - 2024 Daniil Goncharov . // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // 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 OR COPYRIGHT HOLDERS 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. #ifndef NEARGYE_MAGIC_ENUM_FLAGS_HPP #define NEARGYE_MAGIC_ENUM_FLAGS_HPP #include "magic_enum.hpp" #if defined(__clang__) # pragma clang diagnostic push #elif defined(__GNUC__) # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'. #elif defined(_MSC_VER) # pragma warning(push) #endif namespace magic_enum { namespace detail { template > constexpr U values_ors() noexcept { static_assert(S == enum_subtype::flags, "magic_enum::detail::values_ors requires valid subtype."); auto ors = U{0}; for (std::size_t i = 0; i < count_v; ++i) { ors |= static_cast(values_v[i]); } return ors; } } // namespace magic_enum::detail // Returns name from enum-flags value. // If enum-flags value does not have name or value out of range, returns empty string. template [[nodiscard]] auto enum_flags_name(E value, char_type sep = static_cast('|')) -> detail::enable_if_t { using D = std::decay_t; using U = underlying_type_t; constexpr auto S = detail::enum_subtype::flags; static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); string name; auto check_value = U{0}; for (std::size_t i = 0; i < detail::count_v; ++i) { if (const auto v = static_cast(enum_value(i)); (static_cast(value) & v) != 0) { if (const auto n = detail::names_v[i]; !n.empty()) { check_value |= v; if (!name.empty()) { name.append(1, sep); } name.append(n.data(), n.size()); } else { return {}; // Value out of range. } } } if (check_value != 0 && check_value == static_cast(value)) { return name; } return {}; // Invalid value or out of range. } // Obtains enum-flags value from integer value. // Returns optional with enum-flags value. template [[nodiscard]] constexpr auto enum_flags_cast(underlying_type_t value) noexcept -> detail::enable_if_t>> { using D = std::decay_t; using U = underlying_type_t; constexpr auto S = detail::enum_subtype::flags; static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); if constexpr (detail::count_v == 0) { static_cast(value); return {}; // Empty enum. } else { if constexpr (detail::is_sparse_v) { auto check_value = U{0}; for (std::size_t i = 0; i < detail::count_v; ++i) { if (const auto v = static_cast(enum_value(i)); (value & v) != 0) { check_value |= v; } } if (check_value != 0 && check_value == value) { return static_cast(value); } } else { constexpr auto min = detail::min_v; constexpr auto max = detail::values_ors(); if (value >= min && value <= max) { return static_cast(value); } } return {}; // Invalid value or out of range. } } // Obtains enum-flags value from name. // Returns optional with enum-flags value. template > [[nodiscard]] constexpr auto enum_flags_cast(string_view value, [[maybe_unused]] BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable()) -> detail::enable_if_t>, BinaryPredicate> { using D = std::decay_t; using U = underlying_type_t; constexpr auto S = detail::enum_subtype::flags; static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); if constexpr (detail::count_v == 0) { static_cast(value); return {}; // Empty enum. } else { auto result = U{0}; while (!value.empty()) { const auto d = detail::find(value, '|'); const auto s = (d == string_view::npos) ? value : value.substr(0, d); auto f = U{0}; for (std::size_t i = 0; i < detail::count_v; ++i) { if (detail::cmp_equal(s, detail::names_v[i], p)) { f = static_cast(enum_value(i)); result |= f; break; } } if (f == U{0}) { return {}; // Invalid value or out of range. } value.remove_prefix((d == string_view::npos) ? value.size() : d + 1); } if (result != U{0}) { return static_cast(result); } return {}; // Invalid value or out of range. } } // Checks whether enum-flags contains value with such value. template [[nodiscard]] constexpr auto enum_flags_contains(E value) noexcept -> detail::enable_if_t { using D = std::decay_t; using U = underlying_type_t; return static_cast(enum_flags_cast(static_cast(value))); } // Checks whether enum-flags contains value with such integer value. template [[nodiscard]] constexpr auto enum_flags_contains(underlying_type_t value) noexcept -> detail::enable_if_t { using D = std::decay_t; return static_cast(enum_flags_cast(value)); } // Checks whether enum-flags contains enumerator with such name. template > [[nodiscard]] constexpr auto enum_flags_contains(string_view value, BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable()) -> detail::enable_if_t { using D = std::decay_t; return static_cast(enum_flags_cast(value, std::move(p))); } // Checks whether `flags set` contains `flag`. // Note: If `flag` equals 0, it returns false, as 0 is not a flag. template constexpr auto enum_flags_test(E flags, E flag) noexcept -> detail::enable_if_t { using U = underlying_type_t; return static_cast(flag) && ((static_cast(flags) & static_cast(flag)) == static_cast(flag)); } // Checks whether `lhs flags set` and `rhs flags set` have common flags. // 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. template constexpr auto enum_flags_test_any(E lhs, E rhs) noexcept -> detail::enable_if_t { using U = underlying_type_t; return (static_cast(lhs) & static_cast(rhs)) != 0; } } // namespace magic_enum #if defined(__clang__) # pragma clang diagnostic pop #elif defined(__GNUC__) # pragma GCC diagnostic pop #elif defined(_MSC_VER) # pragma warning(pop) #endif #endif // NEARGYE_MAGIC_ENUM_FLAGS_HPP magic_enum-0.9.6/include/magic_enum/magic_enum_format.hpp000066400000000000000000000116021464001350000235370ustar00rootroot00000000000000// __ __ _ ______ _____ // | \/ | (_) | ____| / ____|_ _ // | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ // | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| // | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| // |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| // __/ | https://github.com/Neargye/magic_enum // |___/ version 0.9.6 // // Licensed under the MIT License . // SPDX-License-Identifier: MIT // Copyright (c) 2019 - 2024 Daniil Goncharov . // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // 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 OR COPYRIGHT HOLDERS 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. #ifndef NEARGYE_MAGIC_ENUM_FORMAT_HPP #define NEARGYE_MAGIC_ENUM_FORMAT_HPP #include "magic_enum.hpp" #include "magic_enum_flags.hpp" #if !defined(MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT) # define MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT 1 # define MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT_AUTO_DEFINE #endif namespace magic_enum::customize { // customize enum to enable/disable automatic std::format template constexpr bool enum_format_enabled() noexcept { return MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT; } } // magic_enum::customize #if defined(__cpp_lib_format) #ifndef MAGIC_ENUM_USE_STD_MODULE #include #endif template struct std::formatter> && magic_enum::customize::enum_format_enabled(), char>> : std::formatter { auto format(E e, format_context& ctx) const { static_assert(std::is_same_v, "formatter requires string_view::value_type type same as char."); using D = std::decay_t; if constexpr (magic_enum::detail::supported::value) { if constexpr (magic_enum::detail::subtype_v == magic_enum::detail::enum_subtype::flags) { if (const auto name = magic_enum::enum_flags_name(e); !name.empty()) { return formatter::format(std::string_view{name.data(), name.size()}, ctx); } } else { if (const auto name = magic_enum::enum_name(e); !name.empty()) { return formatter::format(std::string_view{name.data(), name.size()}, ctx); } } } return formatter::format(std::to_string(magic_enum::enum_integer(e)), ctx); } }; #endif #if defined(FMT_VERSION) #include template struct fmt::formatter> && magic_enum::customize::enum_format_enabled(), char>> : fmt::formatter { auto format(E e, format_context& ctx) const { static_assert(std::is_same_v, "formatter requires string_view::value_type type same as char."); using D = std::decay_t; if constexpr (magic_enum::detail::supported::value) { if constexpr (magic_enum::detail::subtype_v == magic_enum::detail::enum_subtype::flags) { if (const auto name = magic_enum::enum_flags_name(e); !name.empty()) { return formatter::format(std::string_view{name.data(), name.size()}, ctx); } } else { if (const auto name = magic_enum::enum_name(e); !name.empty()) { return formatter::format(std::string_view{name.data(), name.size()}, ctx); } } } return formatter::format(std::to_string(magic_enum::enum_integer(e)), ctx); } }; #endif #if defined(MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT_AUTO_DEFINE) # undef MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT # undef MAGIC_ENUM_DEFAULT_ENABLE_ENUM_FORMAT_AUTO_DEFINE #endif #endif // NEARGYE_MAGIC_ENUM_FORMAT_HPP magic_enum-0.9.6/include/magic_enum/magic_enum_fuse.hpp000066400000000000000000000072521464001350000232170ustar00rootroot00000000000000// __ __ _ ______ _____ // | \/ | (_) | ____| / ____|_ _ // | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ // | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| // | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| // |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| // __/ | https://github.com/Neargye/magic_enum // |___/ version 0.9.6 // // Licensed under the MIT License . // SPDX-License-Identifier: MIT // Copyright (c) 2019 - 2024 Daniil Goncharov . // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // 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 OR COPYRIGHT HOLDERS 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. #ifndef NEARGYE_MAGIC_ENUM_FUSE_HPP #define NEARGYE_MAGIC_ENUM_FUSE_HPP #include "magic_enum.hpp" namespace magic_enum { namespace detail { template constexpr optional fuse_one_enum(optional hash, E value) noexcept { if (hash) { if (const auto index = enum_index(value)) { return (*hash << log2(enum_count() + 1)) | *index; } } return {}; } template constexpr optional fuse_enum(E value) noexcept { return fuse_one_enum(0, value); } template constexpr optional fuse_enum(E head, Es... tail) noexcept { return fuse_one_enum(fuse_enum(tail...), head); } template constexpr auto typesafe_fuse_enum(Es... values) noexcept { enum class enum_fuse_t : std::uintmax_t; const auto fuse = fuse_enum(values...); if (fuse) { return optional{static_cast(*fuse)}; } return optional{}; } } // namespace magic_enum::detail // Returns a bijective mix of several enum values. This can be used to emulate 2D switch/case statements. template [[nodiscard]] constexpr auto enum_fuse(Es... values) noexcept { static_assert((std::is_enum_v> && ...), "magic_enum::enum_fuse requires enum type."); static_assert(sizeof...(Es) >= 2, "magic_enum::enum_fuse requires at least 2 values."); static_assert((detail::log2(enum_count>() + 1) + ...) <= (sizeof(std::uintmax_t) * 8), "magic_enum::enum_fuse does not work for large enums"); #if defined(MAGIC_ENUM_NO_TYPESAFE_ENUM_FUSE) const auto fuse = detail::fuse_enum...>(values...); #else const auto fuse = detail::typesafe_fuse_enum...>(values...); #endif return MAGIC_ENUM_ASSERT(fuse), fuse; } } // namespace magic_enum #endif // NEARGYE_MAGIC_ENUM_FUSE_HPP magic_enum-0.9.6/include/magic_enum/magic_enum_iostream.hpp000066400000000000000000000102031464001350000240660ustar00rootroot00000000000000// __ __ _ ______ _____ // | \/ | (_) | ____| / ____|_ _ // | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ // | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| // | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| // |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| // __/ | https://github.com/Neargye/magic_enum // |___/ version 0.9.6 // // Licensed under the MIT License . // SPDX-License-Identifier: MIT // Copyright (c) 2019 - 2024 Daniil Goncharov . // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // 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 OR COPYRIGHT HOLDERS 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. #ifndef NEARGYE_MAGIC_ENUM_IOSTREAM_HPP #define NEARGYE_MAGIC_ENUM_IOSTREAM_HPP #include "magic_enum.hpp" #include "magic_enum_flags.hpp" #ifndef MAGIC_ENUM_USE_STD_MODULE #include #endif namespace magic_enum { namespace ostream_operators { template = 0> std::basic_ostream& operator<<(std::basic_ostream& os, E value) { using D = std::decay_t; using U = underlying_type_t; if constexpr (detail::supported::value) { if constexpr (detail::subtype_v == detail::enum_subtype::flags) { if (const auto name = enum_flags_name(value); !name.empty()) { for (const auto c : name) { os.put(c); } return os; } } else { if (const auto name = enum_name(value); !name.empty()) { for (const auto c : name) { os.put(c); } return os; } } } return (os << static_cast(value)); } template = 0> std::basic_ostream& operator<<(std::basic_ostream& os, optional value) { return value ? (os << *value) : os; } } // namespace magic_enum::ostream_operators namespace istream_operators { template = 0> std::basic_istream& operator>>(std::basic_istream& is, E& value) { using D = std::decay_t; std::basic_string s; is >> s; if constexpr (detail::supported::value) { if constexpr (detail::subtype_v == detail::enum_subtype::flags) { if (const auto v = enum_flags_cast(s)) { value = *v; } else { is.setstate(std::basic_ios::failbit); } } else { if (const auto v = enum_cast(s)) { value = *v; } else { is.setstate(std::basic_ios::failbit); } } } else { is.setstate(std::basic_ios::failbit); } return is; } } // namespace magic_enum::istream_operators namespace iostream_operators { using magic_enum::ostream_operators::operator<<; using magic_enum::istream_operators::operator>>; } // namespace magic_enum::iostream_operators } // namespace magic_enum #endif // NEARGYE_MAGIC_ENUM_IOSTREAM_HPP magic_enum-0.9.6/include/magic_enum/magic_enum_switch.hpp000066400000000000000000000175471464001350000235660ustar00rootroot00000000000000// __ __ _ ______ _____ // | \/ | (_) | ____| / ____|_ _ // | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ // | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| // | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| // |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| // __/ | https://github.com/Neargye/magic_enum // |___/ version 0.9.6 // // Licensed under the MIT License . // SPDX-License-Identifier: MIT // Copyright (c) 2019 - 2024 Daniil Goncharov . // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // 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 OR COPYRIGHT HOLDERS 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. #ifndef NEARGYE_MAGIC_ENUM_SWITCH_HPP #define NEARGYE_MAGIC_ENUM_SWITCH_HPP #include "magic_enum.hpp" namespace magic_enum { namespace detail { struct default_result_type {}; template struct identity { using type = T; }; struct nonesuch {}; template > struct invoke_result : identity {}; template struct invoke_result : std::invoke_result {}; template using invoke_result_t = typename invoke_result::type; template constexpr auto common_invocable(std::index_sequence) noexcept { static_assert(std::is_enum_v, "magic_enum::detail::invocable_index requires enum type."); if constexpr (count_v == 0) { return identity{}; } else { return std::common_type[I]>>...>{}; } } template constexpr auto result_type() noexcept { static_assert(std::is_enum_v, "magic_enum::detail::result_type requires enum type."); constexpr auto seq = std::make_index_sequence>{}; using R = typename decltype(common_invocable(seq))::type; if constexpr (std::is_same_v) { if constexpr (std::is_same_v) { return identity{}; } else { return identity{}; } } else { if constexpr (std::is_convertible_v) { return identity{}; } else if constexpr (std::is_convertible_v) { return identity{}; } else { return identity{}; } } } template , typename R = typename decltype(result_type())::type> using result_t = std::enable_if_t && !std::is_same_v, R>; #if !defined(MAGIC_ENUM_ENABLE_HASH) && !defined(MAGIC_ENUM_ENABLE_HASH_SWITCH) template inline constexpr auto default_result_type_lambda = []() noexcept(std::is_nothrow_default_constructible_v) { return T{}; }; template <> inline constexpr auto default_result_type_lambda = []() noexcept {}; template constexpr decltype(auto) constexpr_switch_impl(F&& f, E value, Def&& def) { if constexpr(I < End) { constexpr auto v = enum_constant()>{}; if (value == v) { if constexpr (std::is_invocable_r_v) { return static_cast(std::forward(f)(v)); } else { return def(); } } else { return constexpr_switch_impl(std::forward(f), value, std::forward(def)); } } else { return def(); } } template constexpr decltype(auto) constexpr_switch(F&& f, E value, Def&& def) { static_assert(is_enum_v, "magic_enum::detail::constexpr_switch requires enum type."); if constexpr (count_v == 0) { return def(); } else { return constexpr_switch_impl<0, count_v, R, E, S>(std::forward(f), value, std::forward(def)); } } #endif } // namespace magic_enum::detail template , typename F, typename R = detail::result_t> constexpr decltype(auto) enum_switch(F&& f, E value) { using D = std::decay_t; static_assert(std::is_enum_v, "magic_enum::enum_switch requires enum type."); static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); #if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH) return detail::constexpr_switch<&detail::values_v, detail::case_call_t::value>( std::forward(f), value, detail::default_result_type_lambda); #else return detail::constexpr_switch( std::forward(f), value, detail::default_result_type_lambda); #endif } template > constexpr decltype(auto) enum_switch(F&& f, E value) { return enum_switch(std::forward(f), value); } template , typename F, typename R = detail::result_t> constexpr decltype(auto) enum_switch(F&& f, E value, Result&& result) { using D = std::decay_t; static_assert(std::is_enum_v, "magic_enum::enum_switch requires enum type."); static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); #if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH) return detail::constexpr_switch<&detail::values_v, detail::case_call_t::value>( std::forward(f), value, [&result]() -> R { return std::forward(result); }); #else return detail::constexpr_switch( std::forward(f), value, [&result]() -> R { return std::forward(result); }); #endif } template > constexpr decltype(auto) enum_switch(F&& f, E value, Result&& result) { return enum_switch(std::forward(f), value, std::forward(result)); } } // namespace magic_enum template <> struct std::common_type : magic_enum::detail::identity {}; template struct std::common_type : magic_enum::detail::identity {}; template struct std::common_type : magic_enum::detail::identity {}; #endif // NEARGYE_MAGIC_ENUM_SWITCH_HPP magic_enum-0.9.6/include/magic_enum/magic_enum_utility.hpp000066400000000000000000000137021464001350000237550ustar00rootroot00000000000000// __ __ _ ______ _____ // | \/ | (_) | ____| / ____|_ _ // | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ // | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| // | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| // |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| // __/ | https://github.com/Neargye/magic_enum // |___/ version 0.9.6 // // Licensed under the MIT License . // SPDX-License-Identifier: MIT // Copyright (c) 2019 - 2024 Daniil Goncharov . // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // 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 OR COPYRIGHT HOLDERS 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. #ifndef NEARGYE_MAGIC_ENUM_UTILITY_HPP #define NEARGYE_MAGIC_ENUM_UTILITY_HPP #include "magic_enum.hpp" namespace magic_enum { namespace detail { template constexpr auto for_each(F&& f, std::index_sequence) { constexpr bool has_void_return = (std::is_void_v[I]>>> || ...); constexpr bool all_same_return = (std::is_same_v[0]>>, std::invoke_result_t[I]>>> && ...); if constexpr (has_void_return) { (f(enum_constant[I]>{}), ...); } else if constexpr (all_same_return) { return std::array{f(enum_constant[I]>{})...}; } else { return std::tuple{f(enum_constant[I]>{})...}; } } template constexpr bool all_invocable(std::index_sequence) { if constexpr (count_v == 0) { return false; } else { return (std::is_invocable_v[I]>> && ...); } } } // namespace magic_enum::detail template , typename F, detail::enable_if_t = 0> constexpr auto enum_for_each(F&& f) { using D = std::decay_t; static_assert(std::is_enum_v, "magic_enum::enum_for_each requires enum type."); static_assert(detail::is_reflected_v, "magic_enum requires enum implementation and valid max and min."); constexpr auto sep = std::make_index_sequence>{}; if constexpr (detail::all_invocable(sep)) { return detail::for_each(std::forward(f), sep); } else { static_assert(detail::always_false_v, "magic_enum::enum_for_each requires invocable of all enum value."); } } template > [[nodiscard]] constexpr auto enum_next_value(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t>> { using D = std::decay_t; constexpr std::ptrdiff_t count = detail::count_v; if (const auto i = enum_index(value)) { const std::ptrdiff_t index = (static_cast(*i) + n); if (index >= 0 && index < count) { return enum_value(static_cast(index)); } } return {}; } template > [[nodiscard]] constexpr auto enum_next_value_circular(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t> { using D = std::decay_t; constexpr std::ptrdiff_t count = detail::count_v; if (const auto i = enum_index(value)) { const std::ptrdiff_t index = ((((static_cast(*i) + n) % count) + count) % count); if (index >= 0 && index < count) { return enum_value(static_cast(index)); } } return MAGIC_ENUM_ASSERT(false), value; } template > [[nodiscard]] constexpr auto enum_prev_value(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t>> { using D = std::decay_t; constexpr std::ptrdiff_t count = detail::count_v; if (const auto i = enum_index(value)) { const std::ptrdiff_t index = (static_cast(*i) - n); if (index >= 0 && index < count) { return enum_value(static_cast(index)); } } return {}; } template > [[nodiscard]] constexpr auto enum_prev_value_circular(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t> { using D = std::decay_t; constexpr std::ptrdiff_t count = detail::count_v; if (const auto i = enum_index(value)) { const std::ptrdiff_t index = ((((static_cast(*i) - n) % count) + count) % count); if (index >= 0 && index < count) { return enum_value(static_cast(index)); } } return MAGIC_ENUM_ASSERT(false), value; } } // namespace magic_enum #endif // NEARGYE_MAGIC_ENUM_UTILITY_HPP magic_enum-0.9.6/meson.build000066400000000000000000000006611464001350000157700ustar00rootroot00000000000000project( 'magic_enum', ['cpp'], default_options: ['cpp_std=c++17'], version: '0.9.6', ) magic_enum_include = include_directories('include/magic_enum') magic_enum_args = [] if get_option('hash') magic_enum_args += '-DMAGIC_ENUM_ENABLE_HASH' endif magic_enum_dep = declare_dependency( include_directories: magic_enum_include, compile_args: magic_enum_args, ) if get_option('test') subdir('test') endif magic_enum-0.9.6/meson_options.txt000066400000000000000000000004001464001350000172520ustar00rootroot00000000000000option( 'test', type : 'boolean', value : true, description : 'Build and run tests' ) option( 'hash', type : 'boolean', value : false, description : 'Do hashing at build time - longer build times, but O(1) string lookup' ) magic_enum-0.9.6/module/000077500000000000000000000000001464001350000151105ustar00rootroot00000000000000magic_enum-0.9.6/module/magic_enum.cppm000066400000000000000000000036141464001350000201010ustar00rootroot00000000000000module; #include #ifndef MAGIC_ENUM_USE_STD_MODULE #include #endif export module magic_enum; #ifdef MAGIC_ENUM_USE_STD_MODULE import std; extern "C++" { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Winclude-angled-in-module-purview" #include #pragma clang diagnostic pop } #endif export namespace magic_enum { namespace customize { using customize::enum_range; } namespace iostream_operators { using iostream_operators::operator<<; using iostream_operators::operator>>; } namespace bitwise_operators { using bitwise_operators::operator~; using bitwise_operators::operator|; using bitwise_operators::operator&; using bitwise_operators::operator^; using bitwise_operators::operator|=; using bitwise_operators::operator&=; using bitwise_operators::operator^=; } namespace containers { using containers::array; using containers::bitset; using containers::set; } using magic_enum::enum_name; using magic_enum::enum_cast; using magic_enum::enum_value; using magic_enum::enum_values; using magic_enum::enum_count; using magic_enum::enum_integer; using magic_enum::enum_names; using magic_enum::enum_entries; using magic_enum::enum_fuse; using magic_enum::enum_switch; using magic_enum::enum_for_each; using magic_enum::enum_contains; using magic_enum::enum_index; using magic_enum::enum_flags_name; using magic_enum::enum_flags_contains; using magic_enum::enum_flags_cast; using magic_enum::enum_type_name; using magic_enum::is_unscoped_enum; using magic_enum::is_unscoped_enum_v; using magic_enum::is_scoped_enum; using magic_enum::is_scoped_enum_v; using magic_enum::underlying_type; using magic_enum::underlying_type_t; } #if defined(__cpp_lib_format) export namespace std { using std::formatter; } #endif magic_enum-0.9.6/package.xml000066400000000000000000000013271464001350000157430ustar00rootroot00000000000000 magic_enum 0.9.6 Static reflection for enums (to string, from string, iteration) for modern C++, work with any enum type without any macro or boilerplate code Neargye MIT cmake cmake magic_enum-0.9.6/test/000077500000000000000000000000001464001350000146025ustar00rootroot00000000000000magic_enum-0.9.6/test/.bazelrc000066400000000000000000000000401464001350000162170ustar00rootroot00000000000000import %workspace%/../.bazelrc magic_enum-0.9.6/test/3rdparty/000077500000000000000000000000001464001350000163525ustar00rootroot00000000000000magic_enum-0.9.6/test/3rdparty/Catch2/000077500000000000000000000000001464001350000174565ustar00rootroot00000000000000magic_enum-0.9.6/test/3rdparty/Catch2/LICENSE000066400000000000000000000024721464001350000204700ustar00rootroot00000000000000Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. magic_enum-0.9.6/test/3rdparty/Catch2/include/000077500000000000000000000000001464001350000211015ustar00rootroot00000000000000magic_enum-0.9.6/test/3rdparty/Catch2/include/catch2/000077500000000000000000000000001464001350000222455ustar00rootroot00000000000000magic_enum-0.9.6/test/3rdparty/Catch2/include/catch2/catch.hpp000066400000000000000000024027541464001350000240560ustar00rootroot00000000000000/* * Catch v2.13.5 * Generated: 2021-04-10 23:43:17.560525 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2021 Two Blue Cubes Ltd. All rights reserved. * * Distributed under the Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) */ #ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED #define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED // start catch.hpp #define CATCH_VERSION_MAJOR 2 #define CATCH_VERSION_MINOR 13 #define CATCH_VERSION_PATCH 5 #ifdef __clang__ # pragma clang system_header #elif defined __GNUC__ # pragma GCC system_header #endif // start catch_suppress_warnings.h #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro # pragma warning(push) # pragma warning(disable: 161 1682) # else // __ICC # pragma clang diagnostic push # pragma clang diagnostic ignored "-Wpadded" # pragma clang diagnostic ignored "-Wswitch-enum" # pragma clang diagnostic ignored "-Wcovered-switch-default" # endif #elif defined __GNUC__ // Because REQUIREs trigger GCC's -Wparentheses, and because still // supported version of g++ have only buggy support for _Pragmas, // Wparentheses have to be suppressed globally. # pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wunused-variable" # pragma GCC diagnostic ignored "-Wpadded" #endif // end catch_suppress_warnings.h #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) # define CATCH_IMPL # define CATCH_CONFIG_ALL_PARTS #endif // In the impl file, we want to have access to all parts of the headers // Can also be used to sanely support PCHs #if defined(CATCH_CONFIG_ALL_PARTS) # define CATCH_CONFIG_EXTERNAL_INTERFACES # if defined(CATCH_CONFIG_DISABLE_MATCHERS) # undef CATCH_CONFIG_DISABLE_MATCHERS # endif # if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) # define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER # endif #endif #if !defined(CATCH_CONFIG_IMPL_ONLY) // start catch_platform.h // See e.g.: // https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html #ifdef __APPLE__ # include # if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \ (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1) # define CATCH_PLATFORM_MAC # elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1) # define CATCH_PLATFORM_IPHONE # endif #elif defined(linux) || defined(__linux) || defined(__linux__) # define CATCH_PLATFORM_LINUX #elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) # define CATCH_PLATFORM_WINDOWS #endif // end catch_platform.h #ifdef CATCH_IMPL # ifndef CLARA_CONFIG_MAIN # define CLARA_CONFIG_MAIN_NOT_DEFINED # define CLARA_CONFIG_MAIN # endif #endif // start catch_user_interfaces.h namespace Catch { unsigned int rngSeed(); } // end catch_user_interfaces.h // start catch_tag_alias_autoregistrar.h // start catch_common.h // start catch_compiler_capabilities.h // Detect a number of compiler features - by compiler // The following features are defined: // // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? // CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? // CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? // CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? // **************** // Note to maintainers: if new toggles are added please document them // in configuration.md, too // **************** // In general each macro has a _NO_ form // (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. // Many features, at point of detection, define an _INTERNAL_ macro, so they // can be combined, en-mass, with the _NO_ forms later. #ifdef __cplusplus # if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) # define CATCH_CPP14_OR_GREATER # endif # if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) # define CATCH_CPP17_OR_GREATER # endif #endif // Only GCC compiler should be used in this block, so other compilers trying to // mask themselves as GCC should be ignored. #if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) #endif #if defined(__clang__) # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) // As of this writing, IBM XL's implementation of __builtin_constant_p has a bug // which results in calls to destructors being emitted for each temporary, // without a matching initialization. In practice, this can result in something // like `std::string::~string` being called on an uninitialized value. // // For example, this code will likely segfault under IBM XL: // ``` // REQUIRE(std::string("12") + "34" == "1234") // ``` // // Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. # if !defined(__ibmxl__) && !defined(__CUDACC__) # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ # endif # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) # define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) # define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) # define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) #endif // __clang__ //////////////////////////////////////////////////////////////////////////////// // Assume that non-Windows platforms support posix signals by default #if !defined(CATCH_PLATFORM_WINDOWS) #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS #endif //////////////////////////////////////////////////////////////////////////////// // We know some environments not to support full POSIX signals #if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS #endif #ifdef __OS400__ # define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS # define CATCH_CONFIG_COLOUR_NONE #endif //////////////////////////////////////////////////////////////////////////////// // Android somehow still does not support std::to_string #if defined(__ANDROID__) # define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING # define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE #endif //////////////////////////////////////////////////////////////////////////////// // Not all Windows environments support SEH properly #if defined(__MINGW32__) # define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH #endif //////////////////////////////////////////////////////////////////////////////// // PS4 #if defined(__ORBIS__) # define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE #endif //////////////////////////////////////////////////////////////////////////////// // Cygwin #ifdef __CYGWIN__ // Required for some versions of Cygwin to declare gettimeofday // see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin # define _BSD_SOURCE // some versions of cygwin (most) do not support std::to_string. Use the libstd check. // https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 # if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) # define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING # endif #endif // __CYGWIN__ //////////////////////////////////////////////////////////////////////////////// // Visual C++ #if defined(_MSC_VER) # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) // Universal Windows platform does not support SEH // Or console colours (or console at all...) # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) # define CATCH_CONFIG_COLOUR_NONE # else # define CATCH_INTERNAL_CONFIG_WINDOWS_SEH # endif // MSVC traditional preprocessor needs some workaround for __VA_ARGS__ // _MSVC_TRADITIONAL == 0 means new conformant preprocessor // _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor # if !defined(__clang__) // Handle Clang masquerading for msvc # if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) # define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR # endif // MSVC_TRADITIONAL # endif // __clang__ #endif // _MSC_VER #if defined(_REENTRANT) || defined(_MSC_VER) // Enable async processing, as -pthread is specified or no additional linking is required # define CATCH_INTERNAL_CONFIG_USE_ASYNC #endif // _MSC_VER //////////////////////////////////////////////////////////////////////////////// // Check if we are compiled with -fno-exceptions or equivalent #if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) # define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED #endif //////////////////////////////////////////////////////////////////////////////// // DJGPP #ifdef __DJGPP__ # define CATCH_INTERNAL_CONFIG_NO_WCHAR #endif // __DJGPP__ //////////////////////////////////////////////////////////////////////////////// // Embarcadero C++Build #if defined(__BORLANDC__) #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN #endif //////////////////////////////////////////////////////////////////////////////// // Use of __COUNTER__ is suppressed during code analysis in // CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly // handled by it. // Otherwise all supported compilers support COUNTER macro, // but user still might want to turn it off #if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) #define CATCH_INTERNAL_CONFIG_COUNTER #endif //////////////////////////////////////////////////////////////////////////////// // RTX is a special version of Windows that is real time. // This means that it is detected as Windows, but does not provide // the same set of capabilities as real Windows does. #if defined(UNDER_RTSS) || defined(RTX64_BUILD) #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH #define CATCH_INTERNAL_CONFIG_NO_ASYNC #define CATCH_CONFIG_COLOUR_NONE #endif #if !defined(_GLIBCXX_USE_C99_MATH_TR1) #define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER #endif // Various stdlib support checks that require __has_include #if defined(__has_include) // Check if string_view is available and usable #if __has_include() && defined(CATCH_CPP17_OR_GREATER) # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW #endif // Check if optional is available and usable # if __has_include() && defined(CATCH_CPP17_OR_GREATER) # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) // Check if byte is available and usable # if __has_include() && defined(CATCH_CPP17_OR_GREATER) # include # if __cpp_lib_byte > 0 # define CATCH_INTERNAL_CONFIG_CPP17_BYTE # endif # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) // Check if variant is available and usable # if __has_include() && defined(CATCH_CPP17_OR_GREATER) # if defined(__clang__) && (__clang_major__ < 8) // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 // fix should be in clang 8, workaround in libstdc++ 8.2 # include # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) # define CATCH_CONFIG_NO_CPP17_VARIANT # else # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) # else # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT # endif // defined(__clang__) && (__clang_major__ < 8) # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) #endif // defined(__has_include) #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) # define CATCH_CONFIG_COUNTER #endif #if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) # define CATCH_CONFIG_WINDOWS_SEH #endif // This is set by default, because we assume that unix compilers are posix-signal-compatible by default. #if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) # define CATCH_CONFIG_POSIX_SIGNALS #endif // This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. #if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) # define CATCH_CONFIG_WCHAR #endif #if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) # define CATCH_CONFIG_CPP11_TO_STRING #endif #if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) # define CATCH_CONFIG_CPP17_OPTIONAL #endif #if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) # define CATCH_CONFIG_CPP17_STRING_VIEW #endif #if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) # define CATCH_CONFIG_CPP17_VARIANT #endif #if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) # define CATCH_CONFIG_CPP17_BYTE #endif #if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) # define CATCH_INTERNAL_CONFIG_NEW_CAPTURE #endif #if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) # define CATCH_CONFIG_NEW_CAPTURE #endif #if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) # define CATCH_CONFIG_DISABLE_EXCEPTIONS #endif #if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) # define CATCH_CONFIG_POLYFILL_ISNAN #endif #if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) # define CATCH_CONFIG_USE_ASYNC #endif #if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) # define CATCH_CONFIG_ANDROID_LOGWRITE #endif #if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) # define CATCH_CONFIG_GLOBAL_NEXTAFTER #endif // Even if we do not think the compiler has that warning, we still have // to provide a macro that can be used by the code. #if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION #endif #if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION #endif #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS #endif // The goal of this macro is to avoid evaluation of the arguments, but // still have the compiler warn on problems inside... #if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) # define CATCH_INTERNAL_IGNORE_BUT_WARN(...) #endif #if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) # undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #elif defined(__clang__) && (__clang_major__ < 5) # undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #endif #if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) # define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #endif #if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) #define CATCH_TRY if ((true)) #define CATCH_CATCH_ALL if ((false)) #define CATCH_CATCH_ANON(type) if ((false)) #else #define CATCH_TRY try #define CATCH_CATCH_ALL catch (...) #define CATCH_CATCH_ANON(type) catch (type) #endif #if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) #define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #endif // end catch_compiler_capabilities.h #define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line #define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) #ifdef CATCH_CONFIG_COUNTER # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) #else # define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) #endif #include #include #include // We need a dummy global operator<< so we can bring it into Catch namespace later struct Catch_global_namespace_dummy {}; std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); namespace Catch { struct CaseSensitive { enum Choice { Yes, No }; }; class NonCopyable { NonCopyable( NonCopyable const& ) = delete; NonCopyable( NonCopyable && ) = delete; NonCopyable& operator = ( NonCopyable const& ) = delete; NonCopyable& operator = ( NonCopyable && ) = delete; protected: NonCopyable(); virtual ~NonCopyable(); }; struct SourceLineInfo { SourceLineInfo() = delete; SourceLineInfo( char const* _file, std::size_t _line ) noexcept : file( _file ), line( _line ) {} SourceLineInfo( SourceLineInfo const& other ) = default; SourceLineInfo& operator = ( SourceLineInfo const& ) = default; SourceLineInfo( SourceLineInfo&& ) noexcept = default; SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; bool empty() const noexcept { return file[0] == '\0'; } bool operator == ( SourceLineInfo const& other ) const noexcept; bool operator < ( SourceLineInfo const& other ) const noexcept; char const* file; std::size_t line; }; std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); // Bring in operator<< from global namespace into Catch namespace // This is necessary because the overload of operator<< above makes // lookup stop at namespace Catch using ::operator<<; // Use this in variadic streaming macros to allow // >> +StreamEndStop // as well as // >> stuff +StreamEndStop struct StreamEndStop { std::string operator+() const; }; template T const& operator + ( T const& value, StreamEndStop ) { return value; } } #define CATCH_INTERNAL_LINEINFO \ ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) // end catch_common.h namespace Catch { struct RegistrarForTagAliases { RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); }; } // end namespace Catch #define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION // end catch_tag_alias_autoregistrar.h // start catch_test_registry.h // start catch_interfaces_testcase.h #include namespace Catch { class TestSpec; struct ITestInvoker { virtual void invoke () const = 0; virtual ~ITestInvoker(); }; class TestCase; struct IConfig; struct ITestCaseRegistry { virtual ~ITestCaseRegistry(); virtual std::vector const& getAllTests() const = 0; virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; }; bool isThrowSafe( TestCase const& testCase, IConfig const& config ); bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); std::vector const& getAllTestCasesSorted( IConfig const& config ); } // end catch_interfaces_testcase.h // start catch_stringref.h #include #include #include #include namespace Catch { /// A non-owning string class (similar to the forthcoming std::string_view) /// Note that, because a StringRef may be a substring of another string, /// it may not be null terminated. class StringRef { public: using size_type = std::size_t; using const_iterator = const char*; private: static constexpr char const* const s_empty = ""; char const* m_start = s_empty; size_type m_size = 0; public: // construction constexpr StringRef() noexcept = default; StringRef( char const* rawChars ) noexcept; constexpr StringRef( char const* rawChars, size_type size ) noexcept : m_start( rawChars ), m_size( size ) {} StringRef( std::string const& stdString ) noexcept : m_start( stdString.c_str() ), m_size( stdString.size() ) {} explicit operator std::string() const { return std::string(m_start, m_size); } public: // operators auto operator == ( StringRef const& other ) const noexcept -> bool; auto operator != (StringRef const& other) const noexcept -> bool { return !(*this == other); } auto operator[] ( size_type index ) const noexcept -> char { assert(index < m_size); return m_start[index]; } public: // named queries constexpr auto empty() const noexcept -> bool { return m_size == 0; } constexpr auto size() const noexcept -> size_type { return m_size; } // Returns the current start pointer. If the StringRef is not // null-terminated, throws std::domain_exception auto c_str() const -> char const*; public: // substrings and searches // Returns a substring of [start, start + length). // If start + length > size(), then the substring is [start, size()). // If start > size(), then the substring is empty. auto substr( size_type start, size_type length ) const noexcept -> StringRef; // Returns the current start pointer. May not be null-terminated. auto data() const noexcept -> char const*; constexpr auto isNullTerminated() const noexcept -> bool { return m_start[m_size] == '\0'; } public: // iterators constexpr const_iterator begin() const { return m_start; } constexpr const_iterator end() const { return m_start + m_size; } }; auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { return StringRef( rawChars, size ); } } // namespace Catch constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { return Catch::StringRef( rawChars, size ); } // end catch_stringref.h // start catch_preprocessor.hpp #define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ #define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) #define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) #define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) #define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) #define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) #ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ // MSVC needs more evaluations #define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) #define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) #else #define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) #endif #define CATCH_REC_END(...) #define CATCH_REC_OUT #define CATCH_EMPTY() #define CATCH_DEFER(id) id CATCH_EMPTY() #define CATCH_REC_GET_END2() 0, CATCH_REC_END #define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 #define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 #define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT #define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) #define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) #define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) #define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) #define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) #define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) #define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) #define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) // Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, // and passes userdata as the first parameter to each invocation, // e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) #define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) #define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) #define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) #define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ #define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ #define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF #define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ #define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) #else // MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF #define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) #define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ #define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) #endif #define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ #define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) #define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) #define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) #else #define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) #define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) #endif #define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) #define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) #define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) #define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) #define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) #define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) #define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) #define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6) #define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) #define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) #define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) #define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) #define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N #define INTERNAL_CATCH_TYPE_GEN\ template struct TypeList {};\ template\ constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ template class...> struct TemplateTypeList{};\ template class...Cs>\ constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ template\ struct append;\ template\ struct rewrap;\ template class, typename...>\ struct create;\ template class, typename>\ struct convert;\ \ template \ struct append { using type = T; };\ template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ template< template class L1, typename...E1, typename...Rest>\ struct append, TypeList, Rest...> { using type = L1; };\ \ template< template class Container, template class List, typename...elems>\ struct rewrap, List> { using type = TypeList>; };\ template< template class Container, template class List, class...Elems, typename...Elements>\ struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ \ template