初始化内容
This commit is contained in:
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
.git
|
||||
.github
|
||||
test
|
||||
doc
|
||||
cmake
|
||||
Vendored
+8
@@ -0,0 +1,8 @@
|
||||
common --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
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
6.3.2
|
||||
Vendored
+58
@@ -0,0 +1,58 @@
|
||||
format:
|
||||
tab_size: 2
|
||||
line_width: 100
|
||||
dangle_parens: true
|
||||
|
||||
parse:
|
||||
additional_commands:
|
||||
cpmaddpackage:
|
||||
pargs:
|
||||
nargs: '*'
|
||||
flags: []
|
||||
spelling: CPMAddPackage
|
||||
kwargs: &cpmaddpackagekwargs
|
||||
NAME: 1
|
||||
FORCE: 1
|
||||
VERSION: 1
|
||||
GIT_TAG: 1
|
||||
DOWNLOAD_ONLY: 1
|
||||
GITHUB_REPOSITORY: 1
|
||||
GITLAB_REPOSITORY: 1
|
||||
GIT_REPOSITORY: 1
|
||||
SVN_REPOSITORY: 1
|
||||
SVN_REVISION: 1
|
||||
SOURCE_DIR: 1
|
||||
DOWNLOAD_COMMAND: 1
|
||||
FIND_PACKAGE_ARGUMENTS: 1
|
||||
NO_CACHE: 1
|
||||
GIT_SHALLOW: 1
|
||||
URL: 1
|
||||
URL_HASH: 1
|
||||
URL_MD5: 1
|
||||
DOWNLOAD_NAME: 1
|
||||
DOWNLOAD_NO_EXTRACT: 1
|
||||
HTTP_USERNAME: 1
|
||||
HTTP_PASSWORD: 1
|
||||
OPTIONS: +
|
||||
cpmfindpackage:
|
||||
pargs:
|
||||
nargs: '*'
|
||||
flags: []
|
||||
spelling: CPMFindPackage
|
||||
kwargs: *cpmaddpackagekwargs
|
||||
packageproject:
|
||||
pargs:
|
||||
nargs: '*'
|
||||
flags: []
|
||||
spelling: packageProject
|
||||
kwargs:
|
||||
NAME: 1
|
||||
VERSION: 1
|
||||
NAMESPACE: 1
|
||||
INCLUDE_DIR: 1
|
||||
INCLUDE_DESTINATION: 1
|
||||
BINARY_DIR: 1
|
||||
COMPATIBILITY: 1
|
||||
VERSION_HEADER: 1
|
||||
DEPENDENCIES: +
|
||||
|
||||
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
build*/
|
||||
.cache/
|
||||
.git/
|
||||
.github/
|
||||
compile_commands.json
|
||||
.dockerignore
|
||||
Dockerfile
|
||||
install_dir/
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
groups:
|
||||
github-actions:
|
||||
patterns:
|
||||
- "*"
|
||||
@@ -0,0 +1,19 @@
|
||||
name: 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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- 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 }}
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
name: 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
|
||||
@@ -0,0 +1,60 @@
|
||||
name: 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@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
|
||||
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@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.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@662472033e021d55d94146f66f6058822b0b39fd # v3.27.0
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
name: 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
|
||||
@@ -0,0 +1,60 @@
|
||||
name: ubuntu_test_installed_version.yml
|
||||
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
|
||||
env:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
CPM_SOURCE_CACHE: ${{ github.workspace }}/cpm_modules
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: "**/cpm_modules"
|
||||
key: ${{ github.workflow }}-cpm-modules-${{ hashFiles('**/CMakeLists.txt', '**/*.cmake') }}
|
||||
|
||||
- name: install library
|
||||
run: |
|
||||
cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release --log-level=DEBUG -DCMAKE_INSTALL_PREFIX=./install_dir
|
||||
cmake --build ./build -j$(nproc)
|
||||
cmake --install ./build --prefix ./install_dir
|
||||
rm -rf build
|
||||
|
||||
- name: configure with installed version via cmake
|
||||
run: CMAKE_PREFIX_PATH="./install_dir" cmake -S. -Bbuild2 -DMAGIC_ENUM_OPT_TEST_INSTALLED_VERSION=1 --log-level=DEBUG
|
||||
|
||||
- name: build with installed version via cmake
|
||||
run: cmake --build build2 --config Debug -j$(nproc) --verbose
|
||||
|
||||
- name: test
|
||||
run: |
|
||||
cd build2
|
||||
ctest --build-config Debug -j$(nproc)
|
||||
|
||||
- name: clear
|
||||
run: rm -rf build2
|
||||
|
||||
- name: configure with installed version via pkgconfig
|
||||
run: CMAKE_PREFIX_PATH="./install_dir" cmake -S. -Bbuild3 -DMAGIC_ENUM_OPT_TEST_INSTALLED_VERSION_PKGCONFIG=1 -DPKG_CONFIG_USE_CMAKE_PREFIX_PATH=1 --log-level=DEBUG
|
||||
|
||||
- name: build with installed version via pkgconfig
|
||||
run: cmake --build build3 --config Debug -j$(nproc) --verbose
|
||||
|
||||
- name: test
|
||||
run: |
|
||||
cd build3
|
||||
ctest --build-config Debug -j$(nproc)
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
name: 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
|
||||
Vendored
+56
@@ -0,0 +1,56 @@
|
||||
build*/
|
||||
cmake_build*/
|
||||
install_dir/
|
||||
.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-*
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
licenses(["notice"])
|
||||
|
||||
exports_files(["LICENSE"])
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
cc_library(
|
||||
name = "magic_enum",
|
||||
hdrs = glob(["include/magic_enum/*.hpp"]),
|
||||
includes = ["include"],
|
||||
)
|
||||
Vendored
+162
@@ -0,0 +1,162 @@
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
|
||||
project(
|
||||
magic_enum
|
||||
VERSION "0.9.7"
|
||||
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}
|
||||
)
|
||||
option(MAGIC_ENUM_OPT_TEST_INSTALLED_VERSION "When configuring tests, try use
|
||||
a local magic_enum." NO
|
||||
)
|
||||
option(MAGIC_ENUM_OPT_TEST_INSTALLED_VERSION_PKGCONFIG "When configuring tests, try use
|
||||
a local magic_enum via pkgconfig" NO
|
||||
)
|
||||
|
||||
if(${MAGIC_ENUM_OPT_TEST_INSTALLED_VERSION} OR ${MAGIC_ENUM_OPT_TEST_INSTALLED_VERSION_PKGCONFIG})
|
||||
add_subdirectory(test)
|
||||
return()
|
||||
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 $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
|
||||
if(MAGIC_ENUM_OPT_BUILD_EXAMPLES)
|
||||
add_subdirectory(example)
|
||||
endif()
|
||||
|
||||
if(MAGIC_ENUM_OPT_BUILD_TESTS)
|
||||
enable_testing()
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
if(NOT DEFINED PROJECT_INCLUDE_HEADER_PATTERN)
|
||||
set(PROJECT_INCLUDE_HEADER_PATTERN "*")
|
||||
endif()
|
||||
|
||||
install(
|
||||
DIRECTORY ${PROJECT_SOURCE_DIR}/include/${PROJECT_NAME}
|
||||
DESTINATION include
|
||||
FILES_MATCHING
|
||||
PATTERN "${PROJECT_INCLUDE_HEADER_PATTERN}"
|
||||
)
|
||||
|
||||
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_DATAROOTDIR}/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_DATAROOTDIR}/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_DATAROOTDIR}"
|
||||
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()
|
||||
Vendored
+71
@@ -0,0 +1,71 @@
|
||||
FROM gentoo/stage3:latest
|
||||
|
||||
RUN echo "Updating Gentoo index registry..."
|
||||
RUN emerge-webrsync
|
||||
|
||||
|
||||
RUN echo "Setting up package manager"
|
||||
# Allow emerge newer versions of cmake. We need it because vcpkg wants it.
|
||||
RUN echo "dev-build/cmake ~amd64" >> /etc/portage/package.accept_keywords/unmask
|
||||
# # Get some packages as binaries and don't compile them. Actually, it allows to not compile only zip :(
|
||||
# RUN rm -rf /etc/portage/binrepos.conf/*
|
||||
# RUN echo -e "[binhost]\npriority = 9999\nsync-uri = https://gentoo.osuosl.org/experimental/amd64/binpkg/default/linux/17.1/x86-64/" >> /etc/portage/binrepos.conf/osuosl.conf
|
||||
# RUN cat /etc/portage/binrepos.conf/*
|
||||
# Arguments that going to be added automatically to `emerge` command. `man emerge` in help. Or read https://wiki.gentoo.org/wiki/Binary_package_guide/en#Installing_binary_packages .
|
||||
# RUN echo 'EMERGE_DEFAULT_OPTS="${EMERGE_DEFAULT_OPTS} --binpkg-respect-use=y --getbinpkg=y --verbose --verbose-conflicts "' >> /etc/portage/make.conf
|
||||
|
||||
RUN echo "Installing dependencies..."
|
||||
|
||||
RUN emerge --quiet --verbose --tree --verbose-conflicts --jobs=2 dev-vcs/git dev-build/cmake zip
|
||||
|
||||
# RUN echo "Installing vcpkg..."
|
||||
# RUN git clone https://github.com/Microsoft/vcpkg.git && \
|
||||
# ./vcpkg/bootstrap-vcpkg.sh -disableMetrics
|
||||
#
|
||||
# COPY ./vcpkg.json ./vcpkg.json
|
||||
#
|
||||
# RUN echo "Installing dependencies using vcpkg"
|
||||
# RUN ./vcpkg/vcpkg install
|
||||
|
||||
WORKDIR /backend
|
||||
|
||||
RUN echo "Copy sources of the project"
|
||||
COPY . .
|
||||
RUN ls -lah
|
||||
|
||||
# expected to be mounted at runtime as volume.
|
||||
# COPY resources/ ./resources/
|
||||
|
||||
|
||||
RUN echo "Configuring project..."
|
||||
RUN cmake -S ./ -B ./build --log-level DEBUG
|
||||
|
||||
|
||||
# RUN echo "Building project..."
|
||||
# RUN cmake --build ./build --parallel $(nproc) --verbose
|
||||
|
||||
RUN echo "really installing"
|
||||
RUN cmake --install ./build
|
||||
|
||||
RUN echo "checking cmake-cmake"
|
||||
RUN cmake -S. -B build2 -DMAGIC_ENUM_OPT_TEST_INSTALLED_VERSION=1 --log-level=DEBUG
|
||||
RUN cmake --build build2 -j $(nproc) --verbose
|
||||
|
||||
RUN echo "checking pkgconfig-cmake"
|
||||
RUN cat "/usr/local/share/pkgconfig/magic_enum.pc"
|
||||
RUN cmake -S. -B build3 -DMAGIC_ENUM_OPT_TEST_INSTALLED_VERSION_PKGCONFIG=1 --log-level=DEBUG
|
||||
RUN cmake --build build3 -j $(nproc) --verbose
|
||||
|
||||
|
||||
|
||||
# RUN echo "what's with linking?"
|
||||
# RUN ls -lahR /usr/local/lib64
|
||||
# RUN lddtree /usr/local/lib64/libArby.so
|
||||
# RUN lddtree /usr/local/bin/Arby
|
||||
|
||||
# CMD ./build/Backend
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Vendored
+21
@@ -0,0 +1,21 @@
|
||||
MIT 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.
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
module(
|
||||
name = "magic_enum",
|
||||
version = "0.9.7",
|
||||
compatibility_level = 0,
|
||||
)
|
||||
Vendored
+347
@@ -0,0 +1,347 @@
|
||||
[](https://github.com/Neargye/magic_enum/releases)
|
||||
[](https://conan.io/center/recipes/magic_enum)
|
||||
[](https://github.com/microsoft/vcpkg/tree/master/ports/magic-enum)
|
||||
[](https://www.cppget.org/magic_enum?q=magic_enum)
|
||||
[](https://github.com/mesonbuild/wrapdb/blob/master/subprojects/magic_enum.wrap)
|
||||
[](LICENSE)
|
||||
[](https://godbolt.org/z/feqcPa5G6)
|
||||
[](https://securityscorecards.dev/viewer/?uri=github.com/Neargye/magic_enum)
|
||||
[](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>(color_name);
|
||||
if (color.has_value()) {
|
||||
// color.value() -> Color::GREEN
|
||||
}
|
||||
|
||||
// case insensitive enum_cast
|
||||
auto color = magic_enum::enum_cast<Color>(value, magic_enum::case_insensitive);
|
||||
|
||||
// enum_cast with BinaryPredicate
|
||||
auto color = magic_enum::enum_cast<Color>(value, [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }
|
||||
|
||||
// enum_cast with default
|
||||
auto color_or_default = magic_enum::enum_cast<Color>(value).value_or(Color::NONE);
|
||||
```
|
||||
|
||||
* Integer to enum value
|
||||
|
||||
```cpp
|
||||
int color_integer = 2;
|
||||
auto color = magic_enum::enum_cast<Color>(color_integer);
|
||||
if (color.has_value()) {
|
||||
// color.value() -> Color::BLUE
|
||||
}
|
||||
|
||||
auto color_or_default = magic_enum::enum_cast<Color>(value).value_or(Color::NONE);
|
||||
```
|
||||
|
||||
* Indexed access to enum value
|
||||
|
||||
```cpp
|
||||
std::size_t i = 0;
|
||||
Color color = magic_enum::enum_value<Color>(i);
|
||||
// color -> Color::RED
|
||||
```
|
||||
|
||||
* Enum value sequence
|
||||
|
||||
```cpp
|
||||
constexpr auto colors = magic_enum::enum_values<Color>();
|
||||
// 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>();
|
||||
// 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>();
|
||||
// color_names -> {"RED", "BLUE", "GREEN"}
|
||||
// color_names[0] -> "RED"
|
||||
```
|
||||
|
||||
* Enum entries sequence
|
||||
|
||||
```cpp
|
||||
constexpr auto color_entries = magic_enum::enum_entries<Color>();
|
||||
// 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<Color>([] (auto val) {
|
||||
constexpr Color c_color = val;
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
* Check if enum contains
|
||||
|
||||
```cpp
|
||||
magic_enum::enum_contains(Color::GREEN); // -> true
|
||||
magic_enum::enum_contains<Color>(2); // -> true
|
||||
magic_enum::enum_contains<Color>(123); // -> false
|
||||
magic_enum::enum_contains<Color>("GREEN"); // -> true
|
||||
magic_enum::enum_contains<Color>("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<Directions> {
|
||||
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<decltype(color)>();
|
||||
// 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<color>::value -> true
|
||||
magic_enum::is_unscoped_enum<direction>::value -> false
|
||||
magic_enum::is_unscoped_enum<int>::value -> false
|
||||
|
||||
// Helper variable template.
|
||||
magic_enum::is_unscoped_enum_v<color> -> 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<color>::value -> false
|
||||
magic_enum::is_scoped_enum<direction>::value -> true
|
||||
magic_enum::is_scoped_enum<int>::value -> false
|
||||
|
||||
// Helper variable template.
|
||||
magic_enum::is_scoped_enum_v<direction> -> 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>();
|
||||
// color_name -> "BLUE"
|
||||
```
|
||||
|
||||
* `containers::array` array container for enums.
|
||||
|
||||
```cpp
|
||||
magic_enum::containers::array<Color, RGB> 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::BLUE>(color_rgb_array) // -> RGB{0, 0, 255}
|
||||
```
|
||||
|
||||
* `containers::bitset` bitset container for enums.
|
||||
|
||||
```cpp
|
||||
constexpr magic_enum::containers::bitset<Color> 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<Color>();
|
||||
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<color>::type -> int
|
||||
|
||||
// Helper types.
|
||||
magic_enum::underlying_type_t<Direction> -> 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-<commit>",
|
||||
urls = ["https://github.com/Neargye/magic_enum/archive/<commit>.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= <compiler>`.)
|
||||
|
||||
* If you are using [Ros](https://www.ros.org/), you can include this package by adding `<depend>magic_enum</depend>` 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)
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,239 @@
|
||||
#[=======================================================================[.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 <https://unlicense.org/>
|
||||
|
||||
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(<targetName>
|
||||
NAME <name of the package>
|
||||
VERSION <version to be written into the package>
|
||||
DESCRIPTION <description to be written into the package>
|
||||
URL <homepage URL to be written into the package>
|
||||
COMPONENT <install as the component>
|
||||
INSTALL_LIB_DIR <path to something like CMAKE_INSTALL_LIBDIR>
|
||||
INSTALL_INCLUDE_DIR <path to something like CMAKE_INSTALL_INCLUDEDIR>
|
||||
REQUIRES ... <list of pkg-config packages this one depends on> ...
|
||||
REQUIRES ... <list of pkg-config packages this one conflicts with> ...
|
||||
)
|
||||
|
||||
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}" "$<TARGET_PROPERTY:${inputExpr}>" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(configure_pkg_config_file_vars TARGET _NAME _INSTALL_LIB_DIR _INSTALL_INCLUDE_DIR _COMPONENT _DESCRIPTION _URL _VERSION _REQUIRES _CONFLICTS)
|
||||
#$<TARGET_PROPERTY:${TARGET},NAME>
|
||||
#INTERFACE_LINK_DIRECTORIES
|
||||
#INTERFACE_LINK_LIBRARIES
|
||||
#INTERFACE_LINK_OPTIONS
|
||||
|
||||
if(_NAME)
|
||||
else()
|
||||
set(_NAME "$<TARGET_PROPERTY:${TARGET},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 "$<TARGET_PROPERTY:${TARGET},INTERFACE_INCLUDE_DIRECTORIES>")
|
||||
set(PUBLIC_LIBS "$<TARGET_PROPERTY:${TARGET},INTERFACE_LINK_LIBRARIES>")
|
||||
set(PUBLIC_COMPILE_FLAGS "$<TARGET_PROPERTY:${TARGET},INTERFACE_COMPILE_DEFINITIONS>")
|
||||
|
||||
set("IS_INTERFACE" "$<STREQUAL:$<TARGET_PROPERTY:${TARGET},TYPE>,INTERFACE_LIBRARY>")
|
||||
set("IS_OBJECT" "$<STREQUAL:$<TARGET_PROPERTY:${TARGET},TYPE>,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" "$<AND:$<NOT:${IS_INTERFACE}>,$<NOT:${IS_OBJECT}>>")
|
||||
set("NEEDS_LIB_DIR" "$<NOT:${IS_INTERFACE}>")
|
||||
string(REPLACE "," "$<COMMA>" NEEDS_LIBS_ESCAPED "${NEEDS_LIBS}")
|
||||
string(REPLACE ">" "$<ANGLE-R>" NEEDS_LIBS_ESCAPED "${NEEDS_LIBS_ESCAPED}")
|
||||
|
||||
list(APPEND header "prefix=${CMAKE_INSTALL_PREFIX}")
|
||||
list(APPEND header "$<IF:$<OR:$<BOOL:${PUBLIC_LIBS}>,${NEEDS_LIB_DIR}>,libdir=\${prefix}/${INSTALL_LIB_DIR},>")
|
||||
list(APPEND header "$<IF:$<BOOL:${PUBLIC_INCLUDES}>,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$<JOIN:$<REMOVE_DUPLICATES:${PUBLIC_INCLUDES}>, -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 $<IF evaluates both branches, not only the one taken, which causes an error
|
||||
# We workaround it by generating the subexpression source using $<IF and then evaluating it using $<GENEX_EVAL
|
||||
# Of course we could have used conditional expressions on CMake script part, but I have decided to implement it in generator expressions part, so hypthetically all the expressions can be merged into a single file and this function can be made simple
|
||||
|
||||
set(ESCAPED_GENEXPR_BEGINNING "$<1:$><") # 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}$<ANGLE-R>")
|
||||
set(LINK_CURRENT_LIB_FLAG "$<GENEX_EVAL:$<IF:${NEEDS_LIBS},-l:${CURRENT_LIB_ESCAPED_BINARY_NAME},>>")
|
||||
|
||||
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 "$<TARGET_OBJECTS:${TARGET}>")
|
||||
|
||||
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" "$<TARGET_OBJECTS:${TARGET}>")
|
||||
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 "$<IF:${IS_OBJECT},${PROPERLY_JOINED_TARGET_OBJECTS},>")
|
||||
|
||||
list(APPEND libSpecific "$<IF:$<OR:$<BOOL:${PUBLIC_LIBS}>,${NEEDS_LIBS},${IS_OBJECT}>,Libs: -L\${libdir} ${LINK_CURRENT_LIB_FLAG} ${LINK_CURRENT_OBJECT_FLAG} $<IF:$<BOOL:${PUBLIC_LIBS}>,-l$<JOIN:$<REMOVE_DUPLICATES:${PUBLIC_LIBS}>, -l>,>,>\n$<IF:$<OR:$<BOOL:${PUBLIC_INCLUDES}>,$<BOOL:${PUBLIC_COMPILE_FLAGS}>>,Cflags: -I\${includedir} $<JOIN:$<REMOVE_DUPLICATES:${PUBLIC_COMPILE_FLAGS}>,>,>")
|
||||
|
||||
|
||||
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()
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
GenPkgConfig.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(<targetName>
|
||||
NAME <name of the pkgconfig package>
|
||||
VERSION <version to be written into the package>
|
||||
DESCRIPTION <description to be written into the package>
|
||||
URL <homepage URL to be written into the package>
|
||||
COMPONENT <install as the component>
|
||||
INSTALL_LIB_DIR <path to something like CMAKE_INSTALL_LIBDIR>
|
||||
INSTALL_INCLUDE_DIR <path to something like CMAKE_INSTALL_INCLUDEDIR>
|
||||
REQUIRES ... <list of pkg-config packages this one depends on> ...
|
||||
REQUIRES ... <list of pkg-config packages this one conflicts with> ...
|
||||
)
|
||||
```
|
||||
|
||||
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`.
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
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 <https://unlicense.org/>
|
||||
Vendored
+129
@@ -0,0 +1,129 @@
|
||||
# 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<Directions> {
|
||||
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 <magic_enum.hpp>
|
||||
```
|
||||
|
||||
* 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 <magic_enum.hpp>
|
||||
|
||||
enum class number { one = 100, two = 200, three = 300 };
|
||||
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<number> {
|
||||
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<ShapeKind>("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<ShapeKind>("Box") -> ShapeKind::Box
|
||||
// magic_enum::enum_name(ShapeKind::Box) -> "Box"
|
||||
|
||||
// Non-reflected aliases.
|
||||
// magic_enum::enum_cast<ShapeKind>("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<Number>("one") -> nullopt
|
||||
// magic_enum::enum_name(Number::one) -> ""
|
||||
// magic_enum::enum_cast<Number>("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` <https://docs.microsoft.com/en-us/cpp/build/reference/constexpr-control-constexpr-evaluation>
|
||||
* Clang: `-fconstexpr-depth=N`, `-fconstexpr-steps=N` <https://clang.llvm.org/docs/UsersManual.html#controlling-implementation-limits>
|
||||
* GCC: `-fconstexpr-depth=N`, `-fconstexpr-loop-limit=N`, `-fconstexpr-ops-limit=N` <https://gcc.gnu.org/onlinedocs/gcc-9.2.0/gcc/C_002b_002b-Dialect-Options.html>
|
||||
|
||||
* 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)
|
||||
Vendored
+995
@@ -0,0 +1,995 @@
|
||||
# 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`.</br>
|
||||
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 <my_lib/string.hpp>
|
||||
#include <my_lib/string_view.hpp>
|
||||
#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 <typename T> using optional = my_lib::Optional<T>;
|
||||
#include <magic_enum.hpp>
|
||||
```
|
||||
|
||||
* 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 <my_lib/string.hpp>
|
||||
#include <my_lib/string_view.hpp>
|
||||
#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 <typename T> using optional = my_lib::Optional<T>;
|
||||
#define MAGIC_ENUM_RANGE_MIN 0
|
||||
#define MAGIC_ENUM_RANGE_MAX 255
|
||||
```
|
||||
|
||||
## `enum_cast`
|
||||
|
||||
```cpp
|
||||
template <typename E>
|
||||
constexpr optional<E> enum_cast(underlying_type_t<E> value) noexcept;
|
||||
|
||||
template <typename E>
|
||||
constexpr optional<E> enum_cast(string_view value) noexcept;
|
||||
|
||||
template <typename E, typename BinaryPredicate>
|
||||
constexpr optional<E> enum_cast(string_view value, BinaryPredicate p) noexcept(is_nothrow_invocable_v<BinaryPredicate>);
|
||||
```
|
||||
|
||||
* Obtains enum value from string or integer.
|
||||
|
||||
* Returns `optional<E>`, 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>(color_name);
|
||||
if (color.has_value()) {
|
||||
// color.value() -> Color::GREEN
|
||||
}
|
||||
|
||||
// case insensitive enum_cast
|
||||
auto color = magic_enum::enum_cast<Color>(value, magic_enum::case_insensitive);
|
||||
|
||||
// enum_cast with BinaryPredicate
|
||||
auto color = magic_enum::enum_cast<Color>(value, [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }
|
||||
|
||||
// enum_cast with default
|
||||
auto color_or_default = magic_enum::enum_cast<Color>(value).value_or(Color::NONE);
|
||||
```
|
||||
|
||||
* Integer to enum value.
|
||||
|
||||
```cpp
|
||||
int color_integer = 2;
|
||||
auto color = magic_enum::enum_cast<Color>(color_integer);
|
||||
if (color.has_value()) {
|
||||
// color.value() -> Color::RED
|
||||
}
|
||||
|
||||
auto color_or_default = magic_enum::enum_cast<Color>(value).value_or(Color::NONE);
|
||||
```
|
||||
|
||||
## `enum_value`
|
||||
|
||||
```cpp
|
||||
template <typename E>
|
||||
constexpr E enum_value(size_t index) noexcept;
|
||||
|
||||
template <typename E, size_t I>
|
||||
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<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<Color>(i);
|
||||
// color -> Color::BLUE
|
||||
```
|
||||
|
||||
```cpp
|
||||
Color color = magic_enum::enum_value<Color, 1>();
|
||||
// color -> Color::BLUE
|
||||
```
|
||||
|
||||
## `enum_values`
|
||||
|
||||
```cpp
|
||||
template <typename E>
|
||||
constexpr array<E, N> enum_values() noexcept;
|
||||
```
|
||||
|
||||
* Returns `array<E, N>` with all enum values where `N = number of enum values`, sorted by enum value.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
constexpr auto colors = magic_enum::enum_values<Color>();
|
||||
// colors -> {Color::RED, Color::BLUE, Color::GREEN}
|
||||
// colors[0] -> Color::RED
|
||||
```
|
||||
|
||||
## `enum_count`
|
||||
|
||||
```cpp
|
||||
template <typename E>
|
||||
constexpr size_t enum_count() noexcept;
|
||||
```
|
||||
|
||||
* Returns number of enum values.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
constexpr auto color_count = magic_enum::enum_count<Color>();
|
||||
// color_count -> 3
|
||||
```
|
||||
|
||||
## `enum_integer`
|
||||
|
||||
```cpp
|
||||
template <typename E>
|
||||
constexpr underlying_type_t<E> enum_integer(E value) noexcept;
|
||||
|
||||
template <typename E>
|
||||
constexpr underlying_type_t<E> 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 <typename E>
|
||||
constexpr string_view enum_name(E value) noexcept;
|
||||
|
||||
template <auto V>
|
||||
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<value>()` occurs the compilation error `magic_enum::enum_name enum value does not have a name`.
|
||||
|
||||
* `enum_name<value>()` 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>();
|
||||
// color_name -> "BLUE"
|
||||
```
|
||||
|
||||
## `enum_names`
|
||||
|
||||
```cpp
|
||||
template <typename E>
|
||||
constexpr array<string_view, N> enum_names() noexcept;
|
||||
```
|
||||
|
||||
* Returns `array<string_view, N>` with all names where `N = number of enum values`, sorted by enum value.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
constexpr auto color_names = magic_enum::enum_names<Color>();
|
||||
// color_names -> {"RED", "BLUE", "GREEN"}
|
||||
// color_names[0] -> "RED"
|
||||
```
|
||||
|
||||
## `enum_entries`
|
||||
|
||||
```cpp
|
||||
template <typename E>
|
||||
constexpr array<pair<E, string_view>, N> enum_entries() noexcept;
|
||||
```
|
||||
|
||||
* Returns `array<pair<E, string_view>, 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>();
|
||||
// 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 <typename E>
|
||||
constexpr optional<size_t> enum_index(E value) noexcept;
|
||||
|
||||
template <auto V>
|
||||
constexpr size_t enum_index() noexcept;
|
||||
```
|
||||
|
||||
* Obtains index in enum values from enum value.
|
||||
* `enum_index(value)` returns `optional<size_t>` with index.
|
||||
* `enum_index<value>()` 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::BLUE>();
|
||||
// color_index -> 1
|
||||
```
|
||||
|
||||
## `enum_contains`
|
||||
|
||||
```cpp
|
||||
template <typename E>
|
||||
constexpr bool enum_contains(E value) noexcept;
|
||||
|
||||
template <typename E>
|
||||
constexpr bool enum_contains(underlying_type_t<E> value) noexcept;
|
||||
|
||||
template <typename E>
|
||||
constexpr bool enum_contains(string_view value) noexcept;
|
||||
|
||||
template <typename E, typename BinaryPredicate>
|
||||
constexpr bool enum_contains(string_view value, BinaryPredicate p) noexcept(is_nothrow_invocable_v<BinaryPredicate>);
|
||||
```
|
||||
|
||||
* 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<Color>(2); // -> true
|
||||
magic_enum::enum_contains<Color>(123); // -> false
|
||||
magic_enum::enum_contains<Color>("GREEN"); // -> true
|
||||
magic_enum::enum_contains<Color>("fda"); // -> false
|
||||
```
|
||||
|
||||
## `enum_reflected`
|
||||
|
||||
```cpp
|
||||
template <typename E>
|
||||
constexpr bool enum_reflected(E value) noexcept;
|
||||
|
||||
template <typename E>
|
||||
constexpr bool enum_reflected(underlying_type_t<E> value) noexcept;
|
||||
```
|
||||
|
||||
* Returns true if the enum value is in the range of values that can be reflected.
|
||||
|
||||
## `enum_type_name`
|
||||
|
||||
```cpp
|
||||
template <typename E>
|
||||
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<decltype(color)>();
|
||||
// type_name -> "Color"
|
||||
```
|
||||
|
||||
## `enum_fuse`
|
||||
|
||||
```cpp
|
||||
template <typename... Es>
|
||||
constexpr optional<enum_fuse_t> enum_fuse(Es... values) noexcept;
|
||||
```
|
||||
|
||||
* You should add the required file `<magic_enum_fuse.hpp>`.
|
||||
|
||||
* Returns a typesafe bijective mix of several enum values. This can be used to emulate 2D switch/case statements.
|
||||
|
||||
* Return type is `optional<enum_fuse_t>` 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 <typename Result = void, typename E, typename Lambda>
|
||||
constexpr Result enum_switch(Lambda&& lambda, E value);
|
||||
|
||||
template <typename Result, typename E, typename Lambda>
|
||||
constexpr Result enum_switch(Lambda&& lambda, E value, Result&& result);
|
||||
```
|
||||
|
||||
* You should add the required file `<magic_enum_switch.hpp>`.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
Color color = Color::RED;
|
||||
|
||||
magic_enum::enum_switch([] (auto val) {
|
||||
constexpr Color c_color = val;
|
||||
// ...
|
||||
}, color);
|
||||
```
|
||||
|
||||
## `enum_for_each`
|
||||
|
||||
```cpp
|
||||
template <typename E, typename Lambda>
|
||||
constexpr auto enum_for_each(Lambda&& lambda);
|
||||
```
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
underlying_type_t<Color> sum{};
|
||||
enum_for_each<Color>([&sum](auto val) {
|
||||
constexpr underlying_type_t<Color> v = enum_integer(val());
|
||||
sum += v;
|
||||
});
|
||||
```
|
||||
|
||||
## `enum_flags`
|
||||
|
||||
```cpp
|
||||
template <typename E>
|
||||
string enum_flags_name(E value);
|
||||
|
||||
template <typename E>
|
||||
constexpr optional<E> enum_flags_cast(underlying_type_t<E> value) noexcept;
|
||||
|
||||
template <typename E>
|
||||
constexpr optional<E> enum_flags_cast(string_view value) noexcept;
|
||||
|
||||
template <typename E, typename BinaryPredicate>
|
||||
constexpr optional<E> enum_flags_cast(string_view value, BinaryPredicate p) noexcept(is_nothrow_invocable_v<BinaryPredicate>);
|
||||
|
||||
template <typename E>
|
||||
constexpr bool enum_flags_contains(E value) noexcept;
|
||||
|
||||
template <typename E>
|
||||
constexpr bool enum_flags_contains(underlying_type_t<E> value) noexcept;
|
||||
|
||||
template <typename E>
|
||||
constexpr bool enum_flags_contains(string_view value) noexcept;
|
||||
|
||||
template <typename E, typename BinaryPredicate>
|
||||
constexpr bool enum_flags_contains(string_view value, BinaryPredicate p) noexcept(is_nothrow_invocable_v<BinaryPredicate>);
|
||||
```
|
||||
|
||||
* You should add the required file `<magic_enum_flags.hpp>`.
|
||||
|
||||
* 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<Directions> {
|
||||
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<Directions> {
|
||||
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 <typename T>
|
||||
struct is_unscoped_enum;
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool is_unscoped_enum_v = is_unscoped_enum<T>::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.</br>
|
||||
Otherwise, value is equal to false.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
magic_enum::is_unscoped_enum<color>::value -> true
|
||||
magic_enum::is_unscoped_enum<Direction>::value -> false
|
||||
|
||||
// Helper variable template.
|
||||
magic_enum::is_unscoped_enum_v<color> -> true
|
||||
```
|
||||
|
||||
## `is_scoped_enum`
|
||||
|
||||
```cpp
|
||||
template <typename T>
|
||||
struct is_scoped_enum;
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool is_scoped_enum_v = is_scoped_enum<T>::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.</br>
|
||||
Otherwise, value is equal to false.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
magic_enum::is_scoped_enum<color>::value -> false
|
||||
magic_enum::is_scoped_enum<Direction>::value -> true
|
||||
|
||||
// Helper variable template.
|
||||
magic_enum::is_scoped_enum_v<Direction> -> true
|
||||
```
|
||||
|
||||
## `underlying_type`
|
||||
|
||||
```cpp
|
||||
template <typename T>
|
||||
struct underlying_type;
|
||||
|
||||
template <typename T>
|
||||
using underlying_type_t = typename underlying_type<T>::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.</br>
|
||||
Otherwise, if T is not an enumeration type, there is no member type.</br>
|
||||
Otherwise (T is an incomplete enumeration type), the program is ill-formed.
|
||||
|
||||
* Examples
|
||||
|
||||
```cpp
|
||||
magic_enum::underlying_type<color>::type -> int
|
||||
|
||||
// Helper types.
|
||||
magic_enum::underlying_type_t<Direction> -> int
|
||||
```
|
||||
|
||||
## `ostream_operators`
|
||||
|
||||
```cpp
|
||||
template <typename Char, typename Traits, typename E>
|
||||
basic_ostream<Char, Traits>& operator<<(basic_ostream<Char, Traits>& os, E value);
|
||||
|
||||
template <typename Char, typename Traits, typename E>
|
||||
basic_ostream<Char, Traits>& operator<<(basic_ostream<Char, Traits>& os, optional<E> value);
|
||||
```
|
||||
|
||||
* You should add the required file `<magic_enum_iostream.hpp>`.
|
||||
|
||||
* 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 <typename Char, typename Traits, typename E>
|
||||
basic_istream<Char, Traits>& operator>>(basic_istream<Char, Traits>& is, E& value);
|
||||
```
|
||||
|
||||
* You should add the required file `<magic_enum_iostream.hpp>`.
|
||||
|
||||
* 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 <typename E>
|
||||
constexpr E operator~(E rhs) noexcept;
|
||||
|
||||
template <typename E>
|
||||
constexpr E operator|(E lhs, E rhs) noexcept;
|
||||
|
||||
template <typename E>
|
||||
constexpr E operator&(E lhs, E rhs) noexcept;
|
||||
|
||||
template <typename E>
|
||||
constexpr E operator^(E lhs, E rhs) noexcept;
|
||||
|
||||
template <typename E>
|
||||
constexpr E& operator|=(E& lhs, E rhs) noexcept;
|
||||
|
||||
template <typename E>
|
||||
constexpr E& operator&=(E& lhs, E rhs) noexcept;
|
||||
|
||||
template <typename E>
|
||||
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 <typename E, typename V, typename Index = default_indexing<E>>
|
||||
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<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> color_rgb_array {{{{255, 0, 0}, {0, 255, 0}, {0, 0, 255}}}};
|
||||
```
|
||||
|
||||
```cpp
|
||||
magic_enum::containers::array<Color, RGB> 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::BLUE>(color_rgb_array) // -> RGB{0, 0, 255}
|
||||
```
|
||||
|
||||
## `containers::bitset`
|
||||
|
||||
```cpp
|
||||
template <typename E, typename Index = default_indexing<E>>
|
||||
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<E> starters);
|
||||
|
||||
constexpr explicit bitset(E starter);
|
||||
|
||||
template <typename Cmp = std::equal_to<>>
|
||||
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> 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>();
|
||||
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 <typename E, typename CExprLess = std::less<E>>
|
||||
class set {
|
||||
|
||||
constexpr set() noexcept = default;
|
||||
|
||||
template <typename InputIt>
|
||||
constexpr set(InputIt first, InputIt last);
|
||||
|
||||
constexpr set(std::initializer_list<E> 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<E> 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<iterator,bool> insert(const value_type& value) noexcept;
|
||||
|
||||
constexpr std::pair<iterator,bool> 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 <typename InputIt>
|
||||
constexpr void insert(InputIt first, InputIt last) noexcept;
|
||||
|
||||
constexpr void insert(std::initializer_list<value_type> ilist) noexcept;
|
||||
|
||||
template <typename... Args>
|
||||
constexpr std::pair<iterator, bool> emplace(Args&&... args) noexcept;
|
||||
|
||||
template <typename... Args>
|
||||
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 <typename K, typename KC = key_compare>
|
||||
constexpr std::enable_if_t<detail::is_transparent_v<KC>, size_type> erase(K&& x) noexcept;
|
||||
|
||||
void swap(set& other) noexcept;
|
||||
|
||||
constexpr size_type count(const key_type& key) const noexcept;
|
||||
|
||||
template <typename K, typename KC = key_compare>
|
||||
constexpr std::enable_if_t<detail::is_transparent_v<KC>, size_type> count(const K& x) const;
|
||||
|
||||
constexpr const_iterator find(const key_type & key) const noexcept;
|
||||
|
||||
template <typename K, typename KC = key_compare>
|
||||
constexpr std::enable_if_t<detail::is_transparent_v<KC>, const_iterator> find(const K& x) const;
|
||||
|
||||
constexpr bool contains(const key_type& key) const noexcept;
|
||||
|
||||
template <typename K, typename KC = key_compare>
|
||||
constexpr std::enable_if_t<detail::is_transparent_v<KC>, bool> contains(const K& x) const noexcept;
|
||||
|
||||
constexpr std::pair<const_iterator,const_iterator> equal_range(const key_type& key) const noexcept;
|
||||
|
||||
template <typename K, typename KC = key_compare>
|
||||
constexpr std::enable_if_t<detail::is_transparent_v<KC>, std::pair<const_iterator,const_iterator>> equal_range(const K& x) const noexcept;
|
||||
|
||||
constexpr const_iterator lower_bound(const key_type& key) const noexcept;
|
||||
|
||||
template <typename K, typename KC = key_compare>
|
||||
constexpr std::enable_if_t<detail::is_transparent_v<KC>, const_iterator> lower_bound(const K& x) const noexcept;
|
||||
|
||||
constexpr const_iterator upper_bound(const key_type& key) const noexcept;
|
||||
|
||||
template <typename K, typename KC = key_compare>
|
||||
constexpr std::enable_if_t<detail::is_transparent_v<KC>, 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 <typename Pred>
|
||||
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<Color>();
|
||||
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
|
||||
```
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
include(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()
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// 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 <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
#include <magic_enum/magic_enum_iostream.hpp>
|
||||
|
||||
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<AnimalFlags> {
|
||||
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<AnimalFlags>();
|
||||
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<AnimalFlags>("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<AnimalFlags>(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<AnimalFlags>() << std::endl; // AnimalFlags enum size: 4
|
||||
|
||||
// Indexed access to enum-flags value.
|
||||
std::cout << "AnimalFlags[0] = " << magic_enum::enum_value<AnimalFlags>(0) << std::endl; // AnimalFlags[0] = HasClaws
|
||||
|
||||
// Enum-flags value sequence.
|
||||
constexpr auto values = magic_enum::enum_values<AnimalFlags>();
|
||||
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<AnimalFlags>();
|
||||
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;
|
||||
}
|
||||
Vendored
+120
@@ -0,0 +1,120 @@
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// 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 <iostream>
|
||||
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
#include <magic_enum/magic_enum_iostream.hpp>
|
||||
|
||||
enum class Color : int { RED = -10, BLUE = 0, GREEN = 10 };
|
||||
|
||||
template <typename E>
|
||||
auto to_integer(magic_enum::Enum<E> value) {
|
||||
// magic_enum::Enum<E> - C++17 Concept for enum type.
|
||||
return static_cast<magic_enum::underlying_type_t<E>>(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<Color>();
|
||||
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<Color>("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<Color>("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<Color>(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<Color>() << std::endl; // Color size: 3
|
||||
|
||||
// Indexed access to enum value.
|
||||
std::cout << "Color[0] = " << magic_enum::enum_value<Color>(0) << std::endl; // Color[0] = RED
|
||||
|
||||
// Enum value sequence.
|
||||
constexpr auto values = magic_enum::enum_values<Color>();
|
||||
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<color>);
|
||||
static_assert(!magic_enum::is_unscoped_enum_v<Color>);
|
||||
static_assert(!magic_enum::is_unscoped_enum_v<Flags>);
|
||||
|
||||
// Checks whether type is an Scoped enumeration.
|
||||
static_assert(!magic_enum::is_scoped_enum_v<color>);
|
||||
static_assert(magic_enum::is_scoped_enum_v<Color>);
|
||||
static_assert(magic_enum::is_scoped_enum_v<Flags>);
|
||||
|
||||
// Enum pair (value enum, string enum name) sequence.
|
||||
constexpr auto entries = magic_enum::enum_entries<Color>();
|
||||
std::cout << "Colors entries:";
|
||||
for (const auto& e : entries) {
|
||||
std::cout << " " << e.second << " = " << static_cast<int>(e.first);
|
||||
}
|
||||
std::cout << std::endl;
|
||||
// Color entries: RED = -10 BLUE = 0 GREEN = 10
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2022 - 2023 Bela Schaum <schaumb@gmail.com>.
|
||||
//
|
||||
// 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 <iostream>
|
||||
|
||||
#include <magic_enum/magic_enum_containers.hpp>
|
||||
|
||||
enum class Color { RED = 1, GREEN = 2, BLUE = 4 };
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<Color> {
|
||||
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<std::uint32_t>(rgb.r) << " G=" << static_cast<std::uint32_t>(rgb.g) << " B=" << static_cast<std::uint32_t>(rgb.b);
|
||||
return ostream;
|
||||
}
|
||||
};
|
||||
|
||||
constexpr std::uint8_t color_max = std::numeric_limits<std::uint8_t>::max();
|
||||
|
||||
int main() {
|
||||
|
||||
constexpr magic_enum::containers::array<Color, RGB> 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::RED>(color_rgb_initializer) << std::endl; // R=255 G=0 B=0
|
||||
std::cout << magic_enum::containers::get<Color::GREEN>(color_rgb_initializer) << std::endl; // R=0 G=255 B=0
|
||||
std::cout << magic_enum::containers::get<Color::BLUE>(color_rgb_initializer) << std::endl; // R=0 G=0 B=255
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2022 - 2023 Bela Schaum <schaumb@gmail.com>.
|
||||
//
|
||||
// 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 <iostream>
|
||||
|
||||
#include <magic_enum/magic_enum_containers.hpp>
|
||||
|
||||
enum class Color { RED = 1, GREEN = 2, BLUE = 4 };
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<Color> {
|
||||
static constexpr bool is_flags = true;
|
||||
};
|
||||
|
||||
int main() {
|
||||
|
||||
auto color_bitset = magic_enum::containers::bitset<Color>();
|
||||
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<Color>()
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2022 - 2023 Bela Schaum <schaumb@gmail.com>.
|
||||
//
|
||||
// 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 <iostream>
|
||||
|
||||
#include <magic_enum/magic_enum_containers.hpp>
|
||||
|
||||
enum class Color { RED = 1, GREEN = 2, BLUE = 4 };
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<Color> {
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// 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 <iostream>
|
||||
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
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>(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>(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<Color>("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;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2020 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2020 - 2023 Uruha Komachin <uruhakomachin@gmail.com>.
|
||||
//
|
||||
// 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 <iostream>
|
||||
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
|
||||
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<Language>("日本語").value() == Language::日本語) << std::endl; // true
|
||||
|
||||
return 0;
|
||||
}
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2022 - 2023 Bela Schaum <schaumb@gmail.com>.
|
||||
//
|
||||
// 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 <iostream>
|
||||
|
||||
#define MAGIC_ENUM_ENABLE_HASH
|
||||
#include <magic_enum/magic_enum_switch.hpp>
|
||||
|
||||
enum class Color { RED, BLUE, GREEN };
|
||||
|
||||
template <Color C>
|
||||
constexpr std::string_view DoWork() {
|
||||
return "default";
|
||||
}
|
||||
|
||||
template <>
|
||||
constexpr std::string_view DoWork<Color::GREEN>() {
|
||||
return "override";
|
||||
}
|
||||
|
||||
// Helper type for the visitor pattern.
|
||||
template <typename... Ts> struct overloaded : Ts... { using Ts::operator()...; };
|
||||
template <typename... Ts> overloaded(Ts...) -> overloaded<Ts...>;
|
||||
|
||||
int main() {
|
||||
Color c = Color::RED;
|
||||
|
||||
auto lambda = [] (auto value) {
|
||||
std::cout << DoWork<value>() << 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<Color::BLUE>) {
|
||||
std::cout << "Blue" << std::endl;
|
||||
},
|
||||
[] (magic_enum::enum_constant<Color::RED>) {
|
||||
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<Color::GREEN>) {
|
||||
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<std::string>(switcher2, Color::GREEN) << std::endl; // prints "called with green argument"
|
||||
std::cout << magic_enum::enum_switch<std::string>(switcher2, Color::RED) << std::endl; // prints "default: RED"
|
||||
|
||||
auto empty = magic_enum::enum_switch<std::string>(switcher2, static_cast<Color>(-3)); // returns an empty string
|
||||
assert(empty.empty());
|
||||
|
||||
// result with default object
|
||||
std::cout << magic_enum::enum_switch<std::string>(switcher2, static_cast<Color>(-3), "unrecognized") << std::endl; // prints "unrecognized"
|
||||
|
||||
auto switcher3 = overloaded{
|
||||
[] (magic_enum::enum_constant<Color::RED>) -> std::optional<std::string> {
|
||||
return "red result";
|
||||
},
|
||||
[] (magic_enum::enum_constant<Color::BLUE>) -> std::optional<std::string> {
|
||||
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;
|
||||
}
|
||||
+1508
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,44 @@
|
||||
// __ __ _ ______ _____
|
||||
// | \/ | (_) | ____| / ____|_ _
|
||||
// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_
|
||||
// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|
|
||||
// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|
|
||||
// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|
|
||||
// __/ | https://github.com/Neargye/magic_enum
|
||||
// |___/ version 0.9.7
|
||||
//
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// 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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,222 @@
|
||||
// __ __ _ ______ _____
|
||||
// | \/ | (_) | ____| / ____|_ _
|
||||
// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_
|
||||
// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|
|
||||
// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|
|
||||
// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|
|
||||
// __/ | https://github.com/Neargye/magic_enum
|
||||
// |___/ version 0.9.7
|
||||
//
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// 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 <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
|
||||
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<E, S>; ++i) {
|
||||
ors |= static_cast<U>(values_v<E, S>[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 <typename E>
|
||||
[[nodiscard]] auto enum_flags_name(E value, char_type sep = static_cast<char_type>('|')) -> detail::enable_if_t<E, string> {
|
||||
using D = std::decay_t<E>;
|
||||
using U = underlying_type_t<D>;
|
||||
constexpr auto S = detail::enum_subtype::flags;
|
||||
static_assert(detail::is_reflected_v<D, S>, "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<D, S>; ++i) {
|
||||
if (const auto v = static_cast<U>(enum_value<D, S>(i)); (static_cast<U>(value) & v) != 0) {
|
||||
if (const auto n = detail::names_v<D, S>[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<U>(value)) {
|
||||
return name;
|
||||
}
|
||||
return {}; // Invalid value or out of range.
|
||||
}
|
||||
|
||||
// Obtains enum-flags value from integer value.
|
||||
// Returns optional with enum-flags value.
|
||||
template <typename E>
|
||||
[[nodiscard]] constexpr auto enum_flags_cast(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, optional<std::decay_t<E>>> {
|
||||
using D = std::decay_t<E>;
|
||||
using U = underlying_type_t<D>;
|
||||
constexpr auto S = detail::enum_subtype::flags;
|
||||
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
|
||||
|
||||
if constexpr (detail::count_v<D, S> == 0) {
|
||||
static_cast<void>(value);
|
||||
return {}; // Empty enum.
|
||||
} else {
|
||||
if constexpr (detail::is_sparse_v<D, S>) {
|
||||
auto check_value = U{0};
|
||||
for (std::size_t i = 0; i < detail::count_v<D, S>; ++i) {
|
||||
if (const auto v = static_cast<U>(enum_value<D, S>(i)); (value & v) != 0) {
|
||||
check_value |= v;
|
||||
}
|
||||
}
|
||||
|
||||
if (check_value != 0 && check_value == value) {
|
||||
return static_cast<D>(value);
|
||||
}
|
||||
} else {
|
||||
constexpr auto min = detail::min_v<D, S>;
|
||||
constexpr auto max = detail::values_ors<D, S>();
|
||||
|
||||
if (value >= min && value <= max) {
|
||||
return static_cast<D>(value);
|
||||
}
|
||||
}
|
||||
return {}; // Invalid value or out of range.
|
||||
}
|
||||
}
|
||||
|
||||
// Obtains enum-flags value from name.
|
||||
// Returns optional with enum-flags value.
|
||||
template <typename E, typename BinaryPredicate = std::equal_to<>>
|
||||
[[nodiscard]] constexpr auto enum_flags_cast(string_view value, [[maybe_unused]] BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, optional<std::decay_t<E>>, BinaryPredicate> {
|
||||
using D = std::decay_t<E>;
|
||||
using U = underlying_type_t<D>;
|
||||
constexpr auto S = detail::enum_subtype::flags;
|
||||
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
|
||||
|
||||
if constexpr (detail::count_v<D, S> == 0) {
|
||||
static_cast<void>(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<D, S>; ++i) {
|
||||
if (detail::cmp_equal(s, detail::names_v<D, S>[i], p)) {
|
||||
f = static_cast<U>(enum_value<D, S>(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<D>(result);
|
||||
}
|
||||
return {}; // Invalid value or out of range.
|
||||
}
|
||||
}
|
||||
|
||||
// Checks whether enum-flags contains value with such value.
|
||||
template <typename E>
|
||||
[[nodiscard]] constexpr auto enum_flags_contains(E value) noexcept -> detail::enable_if_t<E, bool> {
|
||||
using D = std::decay_t<E>;
|
||||
using U = underlying_type_t<D>;
|
||||
|
||||
return static_cast<bool>(enum_flags_cast<D>(static_cast<U>(value)));
|
||||
}
|
||||
|
||||
// Checks whether enum-flags contains value with such integer value.
|
||||
template <typename E>
|
||||
[[nodiscard]] constexpr auto enum_flags_contains(underlying_type_t<E> value) noexcept -> detail::enable_if_t<E, bool> {
|
||||
using D = std::decay_t<E>;
|
||||
|
||||
return static_cast<bool>(enum_flags_cast<D>(value));
|
||||
}
|
||||
|
||||
// Checks whether enum-flags contains enumerator with such name.
|
||||
template <typename E, typename BinaryPredicate = std::equal_to<>>
|
||||
[[nodiscard]] constexpr auto enum_flags_contains(string_view value, BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()) -> detail::enable_if_t<E, bool, BinaryPredicate> {
|
||||
using D = std::decay_t<E>;
|
||||
|
||||
return static_cast<bool>(enum_flags_cast<D>(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 <typename E>
|
||||
constexpr auto enum_flags_test(E flags, E flag) noexcept -> detail::enable_if_t<E, bool> {
|
||||
using U = underlying_type_t<E>;
|
||||
|
||||
return static_cast<U>(flag) && ((static_cast<U>(flags) & static_cast<U>(flag)) == static_cast<U>(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 <typename E>
|
||||
constexpr auto enum_flags_test_any(E lhs, E rhs) noexcept -> detail::enable_if_t<E, bool> {
|
||||
using U = underlying_type_t<E>;
|
||||
|
||||
return (static_cast<U>(lhs) & static_cast<U>(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
|
||||
@@ -0,0 +1,114 @@
|
||||
// __ __ _ ______ _____
|
||||
// | \/ | (_) | ____| / ____|_ _
|
||||
// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_
|
||||
// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|
|
||||
// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|
|
||||
// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|
|
||||
// __/ | https://github.com/Neargye/magic_enum
|
||||
// |___/ version 0.9.7
|
||||
//
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// 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 <typename E>
|
||||
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 <format>
|
||||
#endif
|
||||
|
||||
template <typename E>
|
||||
struct std::formatter<E, std::enable_if_t<std::is_enum_v<std::decay_t<E>> && magic_enum::customize::enum_format_enabled<E>(), char>> : std::formatter<std::string_view, char> {
|
||||
template <class FormatContext>
|
||||
auto format(E e, FormatContext& ctx) const {
|
||||
static_assert(std::is_same_v<char, string_view::value_type>, "formatter requires string_view::value_type type same as char.");
|
||||
using D = std::decay_t<E>;
|
||||
|
||||
if constexpr (magic_enum::detail::supported<D>::value) {
|
||||
if constexpr (magic_enum::detail::subtype_v<D> == magic_enum::detail::enum_subtype::flags) {
|
||||
if (const auto name = magic_enum::enum_flags_name<D>(e); !name.empty()) {
|
||||
return formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);
|
||||
}
|
||||
} else {
|
||||
if (const auto name = magic_enum::enum_name<D>(e); !name.empty()) {
|
||||
return formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
return formatter<std::string_view, char>::format(std::to_string(magic_enum::enum_integer<D>(e)), ctx);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(FMT_VERSION)
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
template <typename E>
|
||||
struct fmt::formatter<E, std::enable_if_t<std::is_enum_v<std::decay_t<E>> && magic_enum::customize::enum_format_enabled<E>(), char>> : fmt::formatter<std::string_view> {
|
||||
template <class FormatContext>
|
||||
auto format(E e, FormatContext& ctx) const {
|
||||
static_assert(std::is_same_v<char, string_view::value_type>, "formatter requires string_view::value_type type same as char.");
|
||||
using D = std::decay_t<E>;
|
||||
|
||||
if constexpr (magic_enum::detail::supported<D>::value) {
|
||||
if constexpr (magic_enum::detail::subtype_v<D> == magic_enum::detail::enum_subtype::flags) {
|
||||
if (const auto name = magic_enum::enum_flags_name<D>(e); !name.empty()) {
|
||||
return formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);
|
||||
}
|
||||
} else {
|
||||
if (const auto name = magic_enum::enum_name<D>(e); !name.empty()) {
|
||||
return formatter<std::string_view, char>::format(std::string_view{name.data(), name.size()}, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
return formatter<std::string_view, char>::format(std::to_string(magic_enum::enum_integer<D>(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
|
||||
@@ -0,0 +1,89 @@
|
||||
// __ __ _ ______ _____
|
||||
// | \/ | (_) | ____| / ____|_ _
|
||||
// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_
|
||||
// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|
|
||||
// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|
|
||||
// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|
|
||||
// __/ | https://github.com/Neargye/magic_enum
|
||||
// |___/ version 0.9.7
|
||||
//
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// 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 <typename E>
|
||||
constexpr optional<std::uintmax_t> fuse_one_enum(optional<std::uintmax_t> hash, E value) noexcept {
|
||||
if (hash) {
|
||||
if (const auto index = enum_index(value)) {
|
||||
return (*hash << log2((enum_count<E>() << 1) - 1)) | *index;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename E>
|
||||
constexpr optional<std::uintmax_t> fuse_enum(E value) noexcept {
|
||||
return fuse_one_enum(0, value);
|
||||
}
|
||||
|
||||
template <typename E, typename... Es>
|
||||
constexpr optional<std::uintmax_t> fuse_enum(E head, Es... tail) noexcept {
|
||||
return fuse_one_enum(fuse_enum(tail...), head);
|
||||
}
|
||||
|
||||
template <typename... Es>
|
||||
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<enum_fuse_t>{static_cast<enum_fuse_t>(*fuse)};
|
||||
}
|
||||
return optional<enum_fuse_t>{};
|
||||
}
|
||||
|
||||
} // namespace magic_enum::detail
|
||||
|
||||
// Returns a bijective mix of several enum values. This can be used to emulate 2D switch/case statements.
|
||||
template <typename... Es>
|
||||
[[nodiscard]] constexpr auto enum_fuse(Es... values) noexcept {
|
||||
static_assert((std::is_enum_v<std::decay_t<Es>> && ...), "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<std::decay_t<Es>>() + 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<std::decay_t<Es>...>(values...);
|
||||
#else
|
||||
const auto fuse = detail::typesafe_fuse_enum<std::decay_t<Es>...>(values...);
|
||||
#endif
|
||||
return MAGIC_ENUM_ASSERT(fuse), fuse;
|
||||
}
|
||||
|
||||
} // namespace magic_enum
|
||||
|
||||
#endif // NEARGYE_MAGIC_ENUM_FUSE_HPP
|
||||
@@ -0,0 +1,117 @@
|
||||
// __ __ _ ______ _____
|
||||
// | \/ | (_) | ____| / ____|_ _
|
||||
// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_
|
||||
// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|
|
||||
// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|
|
||||
// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|
|
||||
// __/ | https://github.com/Neargye/magic_enum
|
||||
// |___/ version 0.9.7
|
||||
//
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// 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 <iosfwd>
|
||||
#endif
|
||||
|
||||
namespace magic_enum {
|
||||
|
||||
namespace ostream_operators {
|
||||
|
||||
template <typename Char, typename Traits, typename E, detail::enable_if_t<E, int> = 0>
|
||||
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, E value) {
|
||||
using D = std::decay_t<E>;
|
||||
using U = underlying_type_t<D>;
|
||||
|
||||
if constexpr (detail::supported<D>::value) {
|
||||
if constexpr (detail::subtype_v<D> == detail::enum_subtype::flags) {
|
||||
if (const auto name = enum_flags_name<D>(value); !name.empty()) {
|
||||
for (const auto c : name) {
|
||||
os.put(c);
|
||||
}
|
||||
return os;
|
||||
}
|
||||
} else {
|
||||
if (const auto name = enum_name<D>(value); !name.empty()) {
|
||||
for (const auto c : name) {
|
||||
os.put(c);
|
||||
}
|
||||
return os;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (os << static_cast<U>(value));
|
||||
}
|
||||
|
||||
template <typename Char, typename Traits, typename E, detail::enable_if_t<E, int> = 0>
|
||||
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, optional<E> value) {
|
||||
return value ? (os << *value) : os;
|
||||
}
|
||||
|
||||
} // namespace magic_enum::ostream_operators
|
||||
|
||||
namespace istream_operators {
|
||||
|
||||
template <typename Char, typename Traits, typename E, detail::enable_if_t<E, int> = 0>
|
||||
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& is, E& value) {
|
||||
using D = std::decay_t<E>;
|
||||
|
||||
std::basic_string<Char, Traits> s;
|
||||
is >> s;
|
||||
if constexpr (detail::supported<D>::value) {
|
||||
if constexpr (detail::subtype_v<D> == detail::enum_subtype::flags) {
|
||||
if (const auto v = enum_flags_cast<D>(s)) {
|
||||
value = *v;
|
||||
} else {
|
||||
is.setstate(std::basic_ios<Char>::failbit);
|
||||
}
|
||||
} else {
|
||||
if (const auto v = enum_cast<D>(s)) {
|
||||
value = *v;
|
||||
} else {
|
||||
is.setstate(std::basic_ios<Char>::failbit);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
is.setstate(std::basic_ios<Char>::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
|
||||
@@ -0,0 +1,195 @@
|
||||
// __ __ _ ______ _____
|
||||
// | \/ | (_) | ____| / ____|_ _
|
||||
// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_
|
||||
// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|
|
||||
// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|
|
||||
// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|
|
||||
// __/ | https://github.com/Neargye/magic_enum
|
||||
// |___/ version 0.9.7
|
||||
//
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// 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 <typename T>
|
||||
struct identity {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
struct nonesuch {};
|
||||
|
||||
template <typename F, typename V, bool = std::is_invocable_v<F, V>>
|
||||
struct invoke_result : identity<nonesuch> {};
|
||||
|
||||
template <typename F, typename V>
|
||||
struct invoke_result<F, V, true> : std::invoke_result<F, V> {};
|
||||
|
||||
template <typename F, typename V>
|
||||
using invoke_result_t = typename invoke_result<F, V>::type;
|
||||
|
||||
template <typename E, enum_subtype S, typename F, std::size_t... I>
|
||||
constexpr auto common_invocable(std::index_sequence<I...>) noexcept {
|
||||
static_assert(std::is_enum_v<E>, "magic_enum::detail::invocable_index requires enum type.");
|
||||
|
||||
if constexpr (count_v<E, S> == 0) {
|
||||
return identity<nonesuch>{};
|
||||
} else {
|
||||
return std::common_type<invoke_result_t<F, enum_constant<values_v<E, S>[I]>>...>{};
|
||||
}
|
||||
}
|
||||
|
||||
template <typename E, enum_subtype S, typename Result, typename F>
|
||||
constexpr auto result_type() noexcept {
|
||||
static_assert(std::is_enum_v<E>, "magic_enum::detail::result_type requires enum type.");
|
||||
|
||||
constexpr auto seq = std::make_index_sequence<count_v<E, S>>{};
|
||||
using R = typename decltype(common_invocable<E, S, F>(seq))::type;
|
||||
if constexpr (std::is_same_v<Result, default_result_type>) {
|
||||
if constexpr (std::is_same_v<R, nonesuch>) {
|
||||
return identity<void>{};
|
||||
} else {
|
||||
return identity<R>{};
|
||||
}
|
||||
} else {
|
||||
if constexpr (std::is_convertible_v<R, Result>) {
|
||||
return identity<Result>{};
|
||||
} else if constexpr (std::is_convertible_v<Result, R>) {
|
||||
return identity<R>{};
|
||||
} else {
|
||||
return identity<nonesuch>{};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename E, enum_subtype S, typename Result, typename F, typename D = std::decay_t<E>, typename R = typename decltype(result_type<D, S, Result, F>())::type>
|
||||
using result_t = std::enable_if_t<std::is_enum_v<D> && !std::is_same_v<R, nonesuch>, R>;
|
||||
|
||||
#if !defined(MAGIC_ENUM_ENABLE_HASH) && !defined(MAGIC_ENUM_ENABLE_HASH_SWITCH)
|
||||
|
||||
template <typename T = void>
|
||||
inline constexpr auto default_result_type_lambda = []() noexcept(std::is_nothrow_default_constructible_v<T>) { return T{}; };
|
||||
|
||||
template <>
|
||||
inline constexpr auto default_result_type_lambda<void> = []() noexcept {};
|
||||
|
||||
template <std::size_t I, std::size_t End, typename R, typename E, enum_subtype S, typename F, typename Def>
|
||||
constexpr decltype(auto) constexpr_switch_impl(F&& f, E value, Def&& def) {
|
||||
if constexpr(I < End) {
|
||||
constexpr auto v = enum_constant<enum_value<E, I, S>()>{};
|
||||
if (value == v) {
|
||||
if constexpr (std::is_invocable_r_v<R, F, decltype(v)>) {
|
||||
return static_cast<R>(std::forward<F>(f)(v));
|
||||
} else {
|
||||
return def();
|
||||
}
|
||||
} else {
|
||||
return constexpr_switch_impl<I + 1, End, R, E, S>(std::forward<F>(f), value, std::forward<Def>(def));
|
||||
}
|
||||
} else {
|
||||
return def();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename R, typename E, enum_subtype S, typename F, typename Def>
|
||||
constexpr decltype(auto) constexpr_switch(F&& f, E value, Def&& def) {
|
||||
static_assert(is_enum_v<E>, "magic_enum::detail::constexpr_switch requires enum type.");
|
||||
|
||||
if constexpr (count_v<E, S> == 0) {
|
||||
return def();
|
||||
} else {
|
||||
return constexpr_switch_impl<0, count_v<E, S>, R, E, S>(std::forward<F>(f), value, std::forward<Def>(def));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace magic_enum::detail
|
||||
|
||||
template <typename Result = detail::default_result_type, typename E, detail::enum_subtype S = detail::subtype_v<E>, typename F, typename R = detail::result_t<E, S, Result, F>>
|
||||
constexpr decltype(auto) enum_switch(F&& f, E value) {
|
||||
using D = std::decay_t<E>;
|
||||
static_assert(std::is_enum_v<D>, "magic_enum::enum_switch requires enum type.");
|
||||
static_assert(detail::is_reflected_v<D, S>, "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<D, S>, detail::case_call_t::value>(
|
||||
std::forward<F>(f),
|
||||
value,
|
||||
detail::default_result_type_lambda<R>);
|
||||
#else
|
||||
return detail::constexpr_switch<R, D, S>(
|
||||
std::forward<F>(f),
|
||||
value,
|
||||
detail::default_result_type_lambda<R>);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Result = detail::default_result_type, detail::enum_subtype S, typename E, typename F, typename R = detail::result_t<E, S, Result, F>>
|
||||
constexpr decltype(auto) enum_switch(F&& f, E value) {
|
||||
return enum_switch<Result, E, S>(std::forward<F>(f), value);
|
||||
}
|
||||
|
||||
template <typename Result, typename E, detail::enum_subtype S = detail::subtype_v<E>, typename F, typename R = detail::result_t<E, S, Result, F>>
|
||||
constexpr decltype(auto) enum_switch(F&& f, E value, Result&& result) {
|
||||
using D = std::decay_t<E>;
|
||||
static_assert(std::is_enum_v<D>, "magic_enum::enum_switch requires enum type.");
|
||||
static_assert(detail::is_reflected_v<D, S>, "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<D, S>, detail::case_call_t::value>(
|
||||
std::forward<F>(f),
|
||||
value,
|
||||
[&result]() -> R { return std::forward<Result>(result); });
|
||||
#else
|
||||
return detail::constexpr_switch<R, D, S>(
|
||||
std::forward<F>(f),
|
||||
value,
|
||||
[&result]() -> R { return std::forward<Result>(result); });
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename Result, detail::enum_subtype S, typename E, typename F, typename R = detail::result_t<E, S, Result, F>>
|
||||
constexpr decltype(auto) enum_switch(F&& f, E value, Result&& result) {
|
||||
return enum_switch<Result, E, S>(std::forward<F>(f), value, std::forward<Result>(result));
|
||||
}
|
||||
|
||||
} // namespace magic_enum
|
||||
|
||||
template <>
|
||||
struct std::common_type<magic_enum::detail::nonesuch, magic_enum::detail::nonesuch> : magic_enum::detail::identity<magic_enum::detail::nonesuch> {};
|
||||
|
||||
template <typename T>
|
||||
struct std::common_type<T, magic_enum::detail::nonesuch> : magic_enum::detail::identity<T> {};
|
||||
|
||||
template <typename T>
|
||||
struct std::common_type<magic_enum::detail::nonesuch, T> : magic_enum::detail::identity<T> {};
|
||||
|
||||
#endif // NEARGYE_MAGIC_ENUM_SWITCH_HPP
|
||||
@@ -0,0 +1,138 @@
|
||||
// __ __ _ ______ _____
|
||||
// | \/ | (_) | ____| / ____|_ _
|
||||
// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_
|
||||
// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _|
|
||||
// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_|
|
||||
// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____|
|
||||
// __/ | https://github.com/Neargye/magic_enum
|
||||
// |___/ version 0.9.7
|
||||
//
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// 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 <typename E, enum_subtype S, typename F, std::size_t... I>
|
||||
constexpr auto for_each(F&& f, std::index_sequence<I...>) {
|
||||
constexpr bool has_void_return = (std::is_void_v<std::invoke_result_t<F, enum_constant<values_v<E, S>[I]>>> || ...);
|
||||
constexpr bool all_same_return = (std::is_same_v<std::invoke_result_t<F, enum_constant<values_v<E, S>[0]>>, std::invoke_result_t<F, enum_constant<values_v<E, S>[I]>>> && ...);
|
||||
|
||||
if constexpr (has_void_return) {
|
||||
(f(enum_constant<values_v<E, S>[I]>{}), ...);
|
||||
} else if constexpr (all_same_return) {
|
||||
return std::array{f(enum_constant<values_v<E, S>[I]>{})...};
|
||||
} else {
|
||||
return std::tuple{f(enum_constant<values_v<E, S>[I]>{})...};
|
||||
}
|
||||
}
|
||||
|
||||
template <typename E, enum_subtype S, typename F,std::size_t... I>
|
||||
constexpr bool all_invocable(std::index_sequence<I...>) {
|
||||
if constexpr (count_v<E, S> == 0) {
|
||||
return false;
|
||||
} else {
|
||||
return (std::is_invocable_v<F, enum_constant<values_v<E, S>[I]>> && ...);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace magic_enum::detail
|
||||
|
||||
template <typename E, detail::enum_subtype S = detail::subtype_v<E>, typename F, detail::enable_if_t<E, int> = 0>
|
||||
constexpr auto enum_for_each(F&& f) {
|
||||
using D = std::decay_t<E>;
|
||||
static_assert(std::is_enum_v<D>, "magic_enum::enum_for_each requires enum type.");
|
||||
static_assert(detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min.");
|
||||
constexpr auto sep = std::make_index_sequence<detail::count_v<D, S>>{};
|
||||
|
||||
if constexpr (detail::all_invocable<D, S, F>(sep)) {
|
||||
return detail::for_each<D, S>(std::forward<F>(f), sep);
|
||||
} else {
|
||||
static_assert(detail::always_false_v<D>, "magic_enum::enum_for_each requires invocable of all enum value.");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_next_value(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t<E, optional<std::decay_t<E>>> {
|
||||
using D = std::decay_t<E>;
|
||||
constexpr std::ptrdiff_t count = detail::count_v<D, S>;
|
||||
|
||||
if (const auto i = enum_index<D, S>(value)) {
|
||||
const std::ptrdiff_t index = (static_cast<std::ptrdiff_t>(*i) + n);
|
||||
if (index >= 0 && index < count) {
|
||||
return enum_value<D, S>(static_cast<std::size_t>(index));
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_next_value_circular(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t<E, std::decay_t<E>> {
|
||||
using D = std::decay_t<E>;
|
||||
constexpr std::ptrdiff_t count = detail::count_v<D, S>;
|
||||
|
||||
if (const auto i = enum_index<D, S>(value)) {
|
||||
const std::ptrdiff_t index = ((((static_cast<std::ptrdiff_t>(*i) + n) % count) + count) % count);
|
||||
if (index >= 0 && index < count) {
|
||||
return enum_value<D, S>(static_cast<std::size_t>(index));
|
||||
}
|
||||
}
|
||||
return MAGIC_ENUM_ASSERT(false), value;
|
||||
}
|
||||
|
||||
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_prev_value(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t<E, optional<std::decay_t<E>>> {
|
||||
using D = std::decay_t<E>;
|
||||
constexpr std::ptrdiff_t count = detail::count_v<D, S>;
|
||||
|
||||
if (const auto i = enum_index<D, S>(value)) {
|
||||
const std::ptrdiff_t index = (static_cast<std::ptrdiff_t>(*i) - n);
|
||||
if (index >= 0 && index < count) {
|
||||
return enum_value<D, S>(static_cast<std::size_t>(index));
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
|
||||
[[nodiscard]] constexpr auto enum_prev_value_circular(E value, std::ptrdiff_t n = 1) noexcept -> detail::enable_if_t<E, std::decay_t<E>> {
|
||||
using D = std::decay_t<E>;
|
||||
constexpr std::ptrdiff_t count = detail::count_v<D, S>;
|
||||
|
||||
if (const auto i = enum_index<D, S>(value)) {
|
||||
const std::ptrdiff_t index = ((((static_cast<std::ptrdiff_t>(*i) - n) % count) + count) % count);
|
||||
if (index >= 0 && index < count) {
|
||||
return enum_value<D, S>(static_cast<std::size_t>(index));
|
||||
}
|
||||
}
|
||||
return MAGIC_ENUM_ASSERT(false), value;
|
||||
}
|
||||
|
||||
} // namespace magic_enum
|
||||
|
||||
#endif // NEARGYE_MAGIC_ENUM_UTILITY_HPP
|
||||
Vendored
+32
@@ -0,0 +1,32 @@
|
||||
project(
|
||||
'magic_enum', ['cpp'],
|
||||
default_options: ['cpp_std=c++17'],
|
||||
version: '0.9.7',
|
||||
)
|
||||
|
||||
magic_enum_include = include_directories('include')
|
||||
|
||||
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,
|
||||
)
|
||||
|
||||
# install header and pkg-config file
|
||||
install_subdir('include/magic_enum', install_dir: get_option('includedir'))
|
||||
pkg = import('pkgconfig')
|
||||
pkg.generate(
|
||||
name: 'magic_enum',
|
||||
description: 'A library that provides static reflection for enums, work with any enum type without any macro or boilerplate code.',
|
||||
url: 'https://github.com/Neargye/magic_enum',
|
||||
extra_cflags: magic_enum_args,
|
||||
)
|
||||
|
||||
if get_option('test')
|
||||
subdir('test')
|
||||
endif
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
option(
|
||||
'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'
|
||||
)
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
module;
|
||||
|
||||
#include <version>
|
||||
#ifndef MAGIC_ENUM_USE_STD_MODULE
|
||||
#include <magic_enum/magic_enum_all.hpp>
|
||||
#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 <magic_enum/magic_enum_all.hpp>
|
||||
#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
|
||||
Vendored
+22
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
|
||||
<!-- A package.xml in the root of a cmake projects allows it to be built using catkin or colcon (the ROS build system) -->
|
||||
|
||||
<package format="2">
|
||||
<name>magic_enum</name>
|
||||
<version>0.9.7</version>
|
||||
<description>
|
||||
Static reflection for enums (to string, from string, iteration) for modern C++,
|
||||
work with any enum type without any macro or boilerplate code
|
||||
</description>
|
||||
|
||||
<maintainer email="neargye@gmail.com">Neargye</maintainer>
|
||||
<license>MIT</license>
|
||||
|
||||
<buildtool_depend>cmake</buildtool_depend>
|
||||
|
||||
<export>
|
||||
<build_type>cmake</build_type>
|
||||
</export>
|
||||
</package>
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
import %workspace%/../.bazelrc
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
Boost 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.
|
||||
File diff suppressed because it is too large
Load Diff
Vendored
+25
@@ -0,0 +1,25 @@
|
||||
_TESTS = [
|
||||
"test",
|
||||
"test_flags",
|
||||
]
|
||||
|
||||
_MSVC_FLAGS = ["/std:c++17", "/permissive-"]
|
||||
_COPTS = select({
|
||||
"//conditions:default": ["-std=c++17"],
|
||||
"@rules_cc//cc/compiler:msvc-cl": _MSVC_FLAGS,
|
||||
"@rules_cc//cc/compiler:clang-cl": _MSVC_FLAGS,
|
||||
})
|
||||
[cc_test(
|
||||
name = test,
|
||||
srcs = ["{}.cpp".format(test)],
|
||||
deps = ["@magic_enum", ":catch2"],
|
||||
copts = _COPTS,
|
||||
) for test in _TESTS]
|
||||
|
||||
# bazel central registry has a catch2 module, but is newer than the one included
|
||||
# in this repository
|
||||
cc_library(
|
||||
name = "catch2",
|
||||
includes = ["3rdparty/Catch2/include"],
|
||||
hdrs = ["3rdparty/Catch2/include/catch2/catch.hpp"],
|
||||
)
|
||||
Vendored
+126
@@ -0,0 +1,126 @@
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
if(${MAGIC_ENUM_OPT_TEST_INSTALLED_VERSION})
|
||||
find_package(magic_enum REQUIRED magic_enum)
|
||||
endif()
|
||||
|
||||
if(${MAGIC_ENUM_OPT_TEST_INSTALLED_VERSION_PKGCONFIG})
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(magic_enum magic_enum)
|
||||
if(NOT magic_enum_FOUND)
|
||||
message(
|
||||
WARNING
|
||||
"magic_enum via pkgconfig is not found. \
|
||||
Next code will try check possible places for some platforms, \
|
||||
but there's no guarantee. \
|
||||
If you know where the magic_enum pkgconfig files (.pc) are, \
|
||||
then specify yourself variable \$\{CMAKE_PREFIX_PATH\} \
|
||||
with folder like /a/path/to/magic_enum (for POSIX-like pathes), \
|
||||
where in the folder exists share/pkgconfig/magic_enum.pc ."
|
||||
)
|
||||
if(UNIX AND EXISTS "/usr/local/share/pkgconfig/magic_enum.pc")
|
||||
message(DEBUG "\$\{CMAKE_PREFIX_PATH\} : ${CMAKE_PREFIX_PATH} ")
|
||||
set(CMAKE_PREFIX_PATH "/usr/local")
|
||||
message(DEBUG "\$\{CMAKE_PREFIX_PATH\} : ${CMAKE_PREFIX_PATH} ")
|
||||
pkg_check_modules(magic_enum magic_enum)
|
||||
endif()
|
||||
# code place for future workarounds for other platforms...
|
||||
if(NOT magic_enum_FOUND)
|
||||
message(FATAL_ERROR "Could not find magic_enum's config. Read a warning above.")
|
||||
endif()
|
||||
endif()
|
||||
message(DEBUG "magic_enum_FOUND : ${magic_enum_FOUND}")
|
||||
message(DEBUG "magic_enum_LIBRARIES: ${magic_enum_LIBRARIES}")
|
||||
message(DEBUG "magic_enum_LINK_LIBRARIES: ${magic_enum_LINK_LIBRARIES}")
|
||||
message(DEBUG "magic_enum_LIBRARY_DIRS: ${magic_enum_LIBRARY_DIRS}")
|
||||
message(DEBUG "magic_enum_INCLUDE_DIRS: ${magic_enum_INCLUDE_DIRS}")
|
||||
message(DEBUG "magic_enum_INCLUDE_DIR: ${magic_enum_INCLUDE_DIR}")
|
||||
message(DEBUG "magic_enum_LDFLAGS: ${magic_enum_LDFLAGS}")
|
||||
message(DEBUG "magic_enum_LDFLAGS_OTHER: ${magic_enum_LDFLAGS_OTHER}")
|
||||
message(DEBUG "magic_enum_CFLAGS: ${magic_enum_CFLAGS}")
|
||||
message(DEBUG "magic_enum_CFLAGS_OTHER: ${magic_enum_CFLAGS_OTHER}")
|
||||
message(DEBUG "magic_enum_INCLUDEDIR: ${magic_enum_INCLUDEDIR}")
|
||||
message(DEBUG "magic_enum_LIBDIR: ${magic_enum_LIBDIR}")
|
||||
message(DEBUG "magic_enum_PREFIX: ${magic_enum_PREFIX}")
|
||||
endif()
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
set(OPTIONS /W4 /WX)
|
||||
check_cxx_compiler_flag(/permissive HAS_PERMISSIVE_FLAG)
|
||||
if(HAS_PERMISSIVE_FLAG)
|
||||
set(OPTIONS ${OPTIONS} /permissive-)
|
||||
endif()
|
||||
|
||||
check_cxx_compiler_flag(/std:c++20 HAS_CPP20_FLAG)
|
||||
check_cxx_compiler_flag(/std:c++23 HAS_CPP23_FLAG)
|
||||
check_cxx_compiler_flag(/std:c++latest HAS_CPPLATEST_FLAG)
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||
set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
set(OPTIONS -Wall -Wextra -Wshadow -pedantic-errors -Werror)
|
||||
|
||||
check_cxx_compiler_flag(-std=c++20 HAS_CPP20_FLAG)
|
||||
check_cxx_compiler_flag(-std=c++23 HAS_CPP23_FLAG)
|
||||
endif()
|
||||
|
||||
function(make_test src target std)
|
||||
add_executable(${target} ${src})
|
||||
target_compile_options(${target} PRIVATE ${OPTIONS})
|
||||
target_include_directories(${target} PRIVATE 3rdparty/Catch2/include)
|
||||
if(${MAGIC_ENUM_OPT_TEST_INSTALLED_VERSION_PKGCONFIG})
|
||||
target_include_directories(${target} PRIVATE ${magic_enum_INCLUDE_DIRS})
|
||||
else()
|
||||
target_link_libraries(${target} PRIVATE magic_enum::magic_enum)
|
||||
endif()
|
||||
set_target_properties(${target} PROPERTIES CXX_EXTENSIONS OFF)
|
||||
if(std)
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
target_compile_options(${target} PRIVATE /std:${std})
|
||||
else()
|
||||
target_compile_options(${target} PRIVATE -std=${std})
|
||||
endif()
|
||||
endif()
|
||||
add_test(NAME ${target} COMMAND ${target})
|
||||
endfunction()
|
||||
|
||||
make_test(test.cpp test-cpp17 c++17)
|
||||
make_test(test_flags.cpp test_flags-cpp17 c++17)
|
||||
make_test(test_aliases.cpp test_aliases-cpp17 c++17)
|
||||
make_test(test_containers.cpp test_containers-cpp17 c++17)
|
||||
make_test(test_wchar_t.cpp test_wchar_t-cpp17 c++17)
|
||||
|
||||
if(MAGIC_ENUM_OPT_ENABLE_NONASCII)
|
||||
make_test(test_nonascii.cpp test_nonascii-cpp17 c++17)
|
||||
endif()
|
||||
|
||||
if(HAS_CPP20_FLAG)
|
||||
make_test(test.cpp test-cpp20 c++20)
|
||||
make_test(test_flags.cpp test_flags-cpp20 c++20)
|
||||
make_test(test_aliases.cpp test_aliases-cpp20 c++20)
|
||||
make_test(test_containers.cpp test_containers-cpp20 c++20)
|
||||
make_test(test_wchar_t.cpp test_wchar_t-cpp20 c++20)
|
||||
if(MAGIC_ENUM_OPT_ENABLE_NONASCII)
|
||||
make_test(test_nonascii.cpp test_nonascii-cpp20 c++20)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(HAS_CPP23_FLAG)
|
||||
make_test(test.cpp test-cpp23 c++23)
|
||||
make_test(test_flags.cpp test_flags-cpp23 c++23)
|
||||
make_test(test_aliases.cpp test_aliases-cpp23 c++23)
|
||||
make_test(test_containers.cpp test_containers-cpp23 c++23)
|
||||
make_test(test_wchar_t.cpp test_wchar_t-cpp23 c++23)
|
||||
if(MAGIC_ENUM_OPT_ENABLE_NONASCII)
|
||||
make_test(test_nonascii.cpp test_nonascii-cpp23 c++23)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(HAS_CPPLATEST_FLAG)
|
||||
make_test(test.cpp test-cpplatest c++latest)
|
||||
make_test(test_flags.cpp test_flags-cpplatest c++latest)
|
||||
make_test(test_aliases.cpp test_aliases-cpplatest c++latest)
|
||||
make_test(test_containers.cpp test_containers-cpplatest c++latest)
|
||||
make_test(test_wchar_t.cpp test_wchar_t-cpplatest c++latest)
|
||||
if(MAGIC_ENUM_OPT_ENABLE_NONASCII)
|
||||
make_test(test_nonascii.cpp test_nonascii-cpplatest c++latest)
|
||||
endif()
|
||||
endif()
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
module(name = "magic_enum_tests")
|
||||
|
||||
bazel_dep(name = "magic_enum")
|
||||
local_path_override(module_name = "magic_enum", path = "..")
|
||||
|
||||
bazel_dep(name = "rules_cc", version = "0.0.8")
|
||||
Vendored
+17
@@ -0,0 +1,17 @@
|
||||
catch2_dep = declare_dependency(include_directories: '3rdparty/Catch2/include')
|
||||
|
||||
test_files = {
|
||||
'basic test': files('test.cpp'),
|
||||
'flags test': files('test_flags.cpp'),
|
||||
}
|
||||
|
||||
foreach test_name, test_src : test_files
|
||||
test_exe = executable(
|
||||
test_name.underscorify(),
|
||||
test_src,
|
||||
|
||||
dependencies: [magic_enum_dep, catch2_dep],
|
||||
)
|
||||
|
||||
test(test_name, test_exe)
|
||||
endforeach
|
||||
Vendored
+1288
File diff suppressed because it is too large
Load Diff
+137
@@ -0,0 +1,137 @@
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// 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 <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
template <typename T>
|
||||
struct MyOpt {
|
||||
constexpr MyOpt() : mHasValue{false}, val{} {} // required
|
||||
constexpr MyOpt(const T& v) : mHasValue{true}, val{v} {} // required
|
||||
constexpr const T& operator*() const { return val; } // required
|
||||
constexpr explicit operator bool() const { return mHasValue; } // required
|
||||
|
||||
constexpr bool has_value() const { return mHasValue; }
|
||||
constexpr const T& value() const { return val; }
|
||||
|
||||
private:
|
||||
bool mHasValue;
|
||||
T val;
|
||||
};
|
||||
|
||||
struct MyString {
|
||||
using value_type = char; // required
|
||||
static constexpr auto npos = std::string_view::npos; // required
|
||||
|
||||
MyString() : str{} {} // required
|
||||
MyString(const char* s, std::size_t l) : str{s, l} {} // required
|
||||
bool empty() const { return str.empty(); } // required
|
||||
auto begin() const { return str.begin(); } // required
|
||||
auto end() const { return str.end(); } // required
|
||||
void append(std::size_t count, char c) { str.append(count, c); } // required
|
||||
void append(const char* s, std::size_t size) { str.append(s, size); } // required
|
||||
|
||||
std::size_t size() const { return str.size(); }
|
||||
int compare(const char* s) const { return str.compare(s); }
|
||||
|
||||
private:
|
||||
std::string str;
|
||||
};
|
||||
|
||||
struct MyStringView {
|
||||
using value_type = char; // required
|
||||
static constexpr auto npos = std::string_view::npos; // required
|
||||
|
||||
constexpr MyStringView() : str{} {} // required
|
||||
constexpr MyStringView(const char* cstr, std::size_t size) : str{cstr, size} {} // required
|
||||
constexpr bool empty() const { return str.empty(); } // required
|
||||
constexpr std::size_t size() const { return str.size(); } // required
|
||||
constexpr const char* data() const { return str.data(); } // required
|
||||
constexpr const char& operator[](std::size_t i) const { return str[i]; } // required
|
||||
constexpr auto begin() const { return str.begin(); } // required
|
||||
constexpr auto end() const { return str.end(); } // required
|
||||
constexpr std::size_t find(char c) const { return str.find(c); } // required
|
||||
constexpr MyStringView substr(std::size_t p, std::size_t n) { return str.substr(p, n); } // required
|
||||
constexpr void remove_prefix(std::size_t n) { str.remove_prefix(n); } // required
|
||||
constexpr void remove_suffix(std::size_t n) { str.remove_suffix(n); } // required
|
||||
friend constexpr bool operator==(MyStringView lhs, MyStringView rhs); // required
|
||||
|
||||
constexpr MyStringView(const char* cstr) : str{ cstr } {}
|
||||
constexpr int compare(const char* s) const { return str.compare(s); }
|
||||
|
||||
private:
|
||||
std::string_view str;
|
||||
|
||||
constexpr MyStringView(std::string_view s) : str{s} {}
|
||||
};
|
||||
|
||||
constexpr bool operator==(MyStringView lhs, MyStringView rhs) {
|
||||
return lhs.str == rhs.str;
|
||||
}
|
||||
|
||||
#define MAGIC_ENUM_USING_ALIAS_OPTIONAL template<typename T> using optional = MyOpt<T>;
|
||||
#define MAGIC_ENUM_USING_ALIAS_STRING using string = MyString;
|
||||
#define MAGIC_ENUM_USING_ALIAS_STRING_VIEW using string_view = MyStringView;
|
||||
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
#include <magic_enum/magic_enum_flags.hpp>
|
||||
using namespace magic_enum;
|
||||
using namespace magic_enum::bitwise_operators;
|
||||
|
||||
enum class Color { RED = 1, GREEN = 2, BLUE = 4 };
|
||||
|
||||
TEST_CASE("optional") {
|
||||
constexpr auto cr = enum_cast<Color>("RED");
|
||||
REQUIRE(cr.has_value());
|
||||
REQUIRE(cr.value() == Color::RED);
|
||||
|
||||
constexpr auto cn = enum_cast<Color>("NONE");
|
||||
REQUIRE_FALSE(cn.has_value());
|
||||
}
|
||||
|
||||
TEST_CASE("string") {
|
||||
auto cr = enum_flags_name(Color::RED);
|
||||
REQUIRE_FALSE(cr.empty());
|
||||
REQUIRE(cr.compare("RED") == 0);
|
||||
|
||||
auto crg = enum_flags_name(Color::RED | Color::GREEN);
|
||||
REQUIRE_FALSE(crg.empty());
|
||||
REQUIRE(crg.compare("RED|GREEN") == 0);
|
||||
|
||||
auto cn = enum_flags_name(Color{0});
|
||||
REQUIRE(cn.empty());
|
||||
REQUIRE(cn.size() == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("string_view") {
|
||||
auto cr = enum_name(Color::RED);
|
||||
REQUIRE_FALSE(cr.empty());
|
||||
REQUIRE(cr.compare("RED") == 0);
|
||||
|
||||
auto cn = enum_name(Color{0});
|
||||
REQUIRE(cn.empty());
|
||||
REQUIRE(cn.size() == 0);
|
||||
}
|
||||
+313
@@ -0,0 +1,313 @@
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
// Copyright (c) 2022 - 2023 Bela Schaum <schaumb@gmail.com>.
|
||||
//
|
||||
// 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(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
#elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
#elif 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
|
||||
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <magic_enum/magic_enum_containers.hpp>
|
||||
#include <magic_enum/magic_enum_iostream.hpp>
|
||||
|
||||
#include <functional>
|
||||
|
||||
enum class Color { RED = 1, GREEN = 2, BLUE = 4 };
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<Color> {
|
||||
static constexpr bool is_flags = true;
|
||||
};
|
||||
|
||||
enum class Empty {};
|
||||
|
||||
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<std::uint32_t>(rgb.r) << " G=" << static_cast<std::uint32_t>(rgb.g) << " B=" << static_cast<std::uint32_t>(rgb.b);
|
||||
return ostream;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> bool check_const([[maybe_unused]]T& element) { return false; }
|
||||
template <typename T> bool check_const([[maybe_unused]]T const& element) { return true; }
|
||||
|
||||
constexpr std::uint8_t color_max = std::numeric_limits<std::uint8_t>::max();
|
||||
|
||||
TEST_CASE("containers_array") {
|
||||
|
||||
using namespace magic_enum::bitwise_operators;
|
||||
using namespace magic_enum::ostream_operators;
|
||||
|
||||
constexpr magic_enum::containers::array<Color, RGB> color_rgb_initializer {{{{color_max, 0, 0}, {0, color_max, 0}, {0, 0, color_max}}}};
|
||||
REQUIRE(color_rgb_initializer.at(Color::RED) == RGB{color_max, 0, 0});
|
||||
REQUIRE(color_rgb_initializer.at(Color::GREEN) == RGB{0, color_max, 0});
|
||||
REQUIRE(color_rgb_initializer.at(Color::BLUE) == RGB{0, 0, color_max});
|
||||
|
||||
/* BUG: a sort will not survive the data integration */
|
||||
magic_enum::containers::array<Color, std::uint8_t> color_rgb_container_int{{1U, 4U, 2U}};
|
||||
|
||||
// ENC: Direct convert to std::array
|
||||
// std::array compare_before {1U, 4U, 2U};
|
||||
constexpr magic_enum::containers::array<Color, std::uint8_t> compare_before{{1U, 4U, 2U}};
|
||||
REQUIRE(color_rgb_container_int == compare_before);
|
||||
|
||||
constexpr auto colors = magic_enum::enum_values<Color>();
|
||||
|
||||
std::ignore = magic_enum::containers::get<0>(compare_before);
|
||||
std::ignore = magic_enum::containers::get<1>(compare_before);
|
||||
std::ignore = magic_enum::containers::get<2>(compare_before);
|
||||
|
||||
std::ignore = magic_enum::containers::get<Color::RED>(compare_before);
|
||||
std::ignore = magic_enum::containers::get<Color::GREEN>(compare_before);
|
||||
std::ignore = magic_enum::containers::get<Color::BLUE>(compare_before);
|
||||
|
||||
REQUIRE(std::make_pair(colors[0], color_rgb_container_int[colors[0]]) == std::make_pair<Color, std::uint8_t>(Color::RED, 1U));
|
||||
REQUIRE(std::make_pair(colors[1], color_rgb_container_int[colors[1]]) == std::make_pair<Color, std::uint8_t>(Color::GREEN, 4U));
|
||||
REQUIRE(std::make_pair(colors[2], color_rgb_container_int[colors[2]]) == std::make_pair<Color, std::uint8_t>(Color::BLUE, 2U));
|
||||
|
||||
std::sort(std::begin(color_rgb_container_int), std::end(color_rgb_container_int));
|
||||
|
||||
// Missing: Direct convert to std::array
|
||||
// std::array compare_after {1U, 2U, 4U};
|
||||
constexpr magic_enum::containers::array<Color, std::uint8_t> compare_after{{1U, 2U, 4U}};
|
||||
REQUIRE(color_rgb_container_int == compare_after);
|
||||
|
||||
std::ignore = magic_enum::containers::get<0>(compare_after);
|
||||
std::ignore = magic_enum::containers::get<1>(compare_after);
|
||||
std::ignore = magic_enum::containers::get<2>(compare_after);
|
||||
|
||||
std::ignore = magic_enum::containers::get<Color::RED>(compare_after);
|
||||
std::ignore = magic_enum::containers::get<Color::GREEN>(compare_after);
|
||||
std::ignore = magic_enum::containers::get<Color::BLUE>(compare_after);
|
||||
|
||||
REQUIRE(std::make_pair(colors[0], color_rgb_container_int[colors[0]]) == std::make_pair<Color, std::uint8_t>(Color::RED, 1U));
|
||||
REQUIRE(std::make_pair(colors[1], color_rgb_container_int[colors[1]]) == std::make_pair<Color, std::uint8_t>(Color::GREEN, 2U));
|
||||
REQUIRE(std::make_pair(colors[2], color_rgb_container_int[colors[2]]) == std::make_pair<Color, std::uint8_t>(Color::BLUE, 4U));
|
||||
|
||||
auto color_rgb_container = magic_enum::containers::array<Color, RGB>();
|
||||
REQUIRE_FALSE(color_rgb_container.empty());
|
||||
REQUIRE(color_rgb_container.size() == 3);
|
||||
REQUIRE(magic_enum::enum_count<Color>() == color_rgb_container.size());
|
||||
|
||||
REQUIRE(color_rgb_container.at(Color::RED).empty());
|
||||
REQUIRE(color_rgb_container.at(Color::GREEN).empty());
|
||||
REQUIRE(color_rgb_container.at(Color::BLUE).empty());
|
||||
REQUIRE_THROWS(color_rgb_container.at(Color::BLUE|Color::GREEN).empty());
|
||||
|
||||
color_rgb_container[Color::RED] = {color_max, 0, 0};
|
||||
color_rgb_container[Color::GREEN] = {0, color_max, 0};
|
||||
color_rgb_container[Color::BLUE] = {0, 0, color_max};
|
||||
|
||||
REQUIRE(color_rgb_container.at(Color::RED) == RGB{color_max, 0, 0});
|
||||
REQUIRE(color_rgb_container.at(Color::GREEN) == RGB{0, color_max, 0});
|
||||
REQUIRE(color_rgb_container.at(Color::BLUE) == RGB{0, 0, color_max});
|
||||
|
||||
REQUIRE(color_rgb_container.front() == RGB{color_max, 0, 0});
|
||||
REQUIRE(color_rgb_container.back() == RGB{0, 0, color_max});
|
||||
|
||||
REQUIRE(magic_enum::containers::get<Color::RED>(color_rgb_container) == RGB{color_max, 0, 0});
|
||||
REQUIRE(magic_enum::containers::get<Color::GREEN>(color_rgb_container) == RGB{0, color_max, 0});
|
||||
REQUIRE(magic_enum::containers::get<Color::BLUE>(color_rgb_container) == RGB{0, 0, color_max});
|
||||
|
||||
auto iterator = color_rgb_container.begin();
|
||||
REQUIRE_FALSE(check_const(iterator));
|
||||
REQUIRE(check_const(color_rgb_container.begin()));
|
||||
REQUIRE(check_const(color_rgb_container.cbegin()));
|
||||
|
||||
auto color_rgb_container_compare = magic_enum::containers::array<Color, RGB>();
|
||||
color_rgb_container_compare.fill({color_max, color_max, color_max});
|
||||
REQUIRE_FALSE(color_rgb_container == color_rgb_container_compare);
|
||||
|
||||
color_rgb_container_compare[Color::RED] = {color_max, 0, 0};
|
||||
color_rgb_container_compare[Color::GREEN] = {0, color_max, 0};
|
||||
color_rgb_container_compare[Color::BLUE] = {0, 0, color_max};
|
||||
REQUIRE(color_rgb_container == color_rgb_container_compare);
|
||||
|
||||
constexpr auto from_to_array = magic_enum::containers::to_array<Color, RGB>({{color_max, 0, 0}, {0, color_max, 0}, {0, 0, color_max}});
|
||||
REQUIRE(from_to_array.at(Color::RED) == RGB{color_max, 0, 0});
|
||||
REQUIRE(from_to_array.at(Color::GREEN) == RGB{0, color_max, 0});
|
||||
REQUIRE(from_to_array.at(Color::BLUE) == RGB{0, 0, color_max});
|
||||
}
|
||||
|
||||
TEST_CASE("containers_bitset") {
|
||||
|
||||
using namespace magic_enum::bitwise_operators;
|
||||
|
||||
auto color_bitset = magic_enum::containers::bitset<Color>();
|
||||
REQUIRE(color_bitset.to_string().empty());
|
||||
REQUIRE(color_bitset.size() == 3);
|
||||
REQUIRE(magic_enum::enum_count<Color>() == color_bitset.size());
|
||||
REQUIRE_FALSE(color_bitset.all());
|
||||
REQUIRE_FALSE(color_bitset.any());
|
||||
REQUIRE(color_bitset.none());
|
||||
REQUIRE(color_bitset.count() == 0);
|
||||
|
||||
color_bitset.set(Color::GREEN);
|
||||
REQUIRE_FALSE(color_bitset.all());
|
||||
REQUIRE(color_bitset.any());
|
||||
REQUIRE_FALSE(color_bitset.none());
|
||||
REQUIRE(color_bitset.count() == 1);
|
||||
REQUIRE_FALSE(color_bitset.test(Color::RED));
|
||||
REQUIRE(color_bitset.test(Color::GREEN));
|
||||
REQUIRE_FALSE(color_bitset.test(Color::BLUE));
|
||||
|
||||
color_bitset.set(Color::BLUE);
|
||||
REQUIRE_FALSE(color_bitset.all());
|
||||
REQUIRE(color_bitset.any());
|
||||
REQUIRE_FALSE(color_bitset.none());
|
||||
REQUIRE(color_bitset.count() == 2);
|
||||
REQUIRE_FALSE(color_bitset.test(Color::RED));
|
||||
REQUIRE(color_bitset.test(Color::GREEN));
|
||||
REQUIRE(color_bitset.test(Color::BLUE));
|
||||
|
||||
color_bitset.set(Color::RED);
|
||||
REQUIRE(color_bitset.all());
|
||||
REQUIRE(color_bitset.any());
|
||||
REQUIRE_FALSE(color_bitset.none());
|
||||
REQUIRE(color_bitset.count() == 3);
|
||||
REQUIRE(color_bitset.test(Color::RED));
|
||||
REQUIRE(color_bitset.test(Color::GREEN));
|
||||
REQUIRE(color_bitset.test(Color::BLUE));
|
||||
|
||||
color_bitset.reset();
|
||||
REQUIRE_FALSE(color_bitset.all());
|
||||
REQUIRE_FALSE(color_bitset.any());
|
||||
REQUIRE(color_bitset.none());
|
||||
REQUIRE(color_bitset.count() == 0);
|
||||
REQUIRE_FALSE(color_bitset.test(Color::RED));
|
||||
REQUIRE_FALSE(color_bitset.test(Color::GREEN));
|
||||
REQUIRE_FALSE(color_bitset.test(Color::BLUE));
|
||||
|
||||
color_bitset.set(Color::RED);
|
||||
REQUIRE(color_bitset.test(Color::RED));
|
||||
REQUIRE_FALSE(color_bitset.test(Color::GREEN));
|
||||
REQUIRE_FALSE(color_bitset.test(Color::BLUE));
|
||||
|
||||
color_bitset.flip();
|
||||
REQUIRE_FALSE(color_bitset.test(Color::RED));
|
||||
REQUIRE(color_bitset.test(Color::GREEN));
|
||||
REQUIRE(color_bitset.test(Color::BLUE));
|
||||
|
||||
constexpr magic_enum::containers::bitset<Color> color_bitset_all {Color::RED|Color::GREEN|Color::BLUE};
|
||||
REQUIRE(color_bitset_all.to_string() == "RED|GREEN|BLUE");
|
||||
REQUIRE(color_bitset_all.to_string( {}, '0', '1' ) == "111");
|
||||
REQUIRE(color_bitset_all.to_ulong( {} ) == 7);
|
||||
REQUIRE(color_bitset_all.to_ullong( {} ) == 7);
|
||||
REQUIRE(color_bitset_all.all());
|
||||
REQUIRE(color_bitset_all.any());
|
||||
REQUIRE_FALSE(color_bitset_all.none());
|
||||
|
||||
constexpr magic_enum::containers::bitset<Color> color_bitset_red_green {Color::RED|Color::GREEN};
|
||||
REQUIRE(color_bitset_red_green.to_string() == "RED|GREEN");
|
||||
REQUIRE(color_bitset_red_green.to_string( {}, '0', '1' ) == "110");
|
||||
REQUIRE(color_bitset_red_green.to_ulong( {} ) == 3);
|
||||
REQUIRE(color_bitset_red_green.to_ullong( {} ) == 3);
|
||||
REQUIRE_FALSE(color_bitset_red_green.all());
|
||||
REQUIRE(color_bitset_red_green.any());
|
||||
REQUIRE_FALSE(color_bitset_red_green.none());
|
||||
}
|
||||
|
||||
TEST_CASE("containers_set") {
|
||||
|
||||
using namespace magic_enum::bitwise_operators;
|
||||
using namespace magic_enum::ostream_operators;
|
||||
|
||||
auto color_set = magic_enum::containers::set<Color>();
|
||||
REQUIRE(color_set.empty());
|
||||
REQUIRE(color_set.size() == 0);
|
||||
REQUIRE_FALSE(magic_enum::enum_count<Color>() == color_set.size());
|
||||
|
||||
color_set.insert(Color::RED);
|
||||
std::ignore = color_set.insert(Color::RED);
|
||||
color_set.insert(Color::GREEN);
|
||||
color_set.insert(Color::BLUE);
|
||||
color_set.insert(Color::RED);
|
||||
color_set.insert(Color::RED|Color::GREEN);
|
||||
color_set.insert(Color::RED|Color::BLUE);
|
||||
color_set.insert(Color::GREEN|Color::BLUE);
|
||||
color_set.insert(Color::RED|Color::GREEN|Color::BLUE);
|
||||
|
||||
REQUIRE_FALSE(color_set.empty());
|
||||
REQUIRE(color_set.size() == 3);
|
||||
REQUIRE(magic_enum::enum_count<Color>() == color_set.size());
|
||||
color_set.erase(Color::RED);
|
||||
color_set.erase(Color::GREEN);
|
||||
REQUIRE(magic_enum::enum_count<Color>() - 2 == color_set.size());
|
||||
REQUIRE(color_set.count(Color::RED) == 0);
|
||||
REQUIRE_FALSE(color_set.contains(Color::GREEN));
|
||||
REQUIRE(color_set.contains(Color::BLUE));
|
||||
|
||||
auto color_set_compare = magic_enum::containers::set<Color>();
|
||||
color_set_compare.insert(Color::BLUE);
|
||||
color_set_compare.insert(Color::RED);
|
||||
color_set_compare.insert(Color::GREEN);
|
||||
|
||||
constexpr magic_enum::containers::set color_set_filled = {Color::RED, Color::GREEN, Color::BLUE};
|
||||
REQUIRE_FALSE(color_set_filled.empty());
|
||||
REQUIRE(color_set_filled.size() == 3);
|
||||
REQUIRE(magic_enum::enum_count<Color>() == color_set_filled.size());
|
||||
|
||||
magic_enum::containers::set color_set_not_const = {Color::RED, Color::GREEN, Color::BLUE};
|
||||
REQUIRE_FALSE(color_set_not_const.empty());
|
||||
REQUIRE(color_set_not_const.size() == 3);
|
||||
REQUIRE(magic_enum::enum_count<Color>() == color_set_not_const.size());
|
||||
color_set_not_const.clear();
|
||||
REQUIRE(color_set_not_const.empty());
|
||||
REQUIRE(color_set_not_const.size() == 0);
|
||||
REQUIRE_FALSE(magic_enum::enum_count<Color>() == color_set_not_const.size());
|
||||
}
|
||||
|
||||
TEST_CASE("map_like_container") {
|
||||
|
||||
using namespace magic_enum::ostream_operators;
|
||||
|
||||
std::vector<std::pair<Color, RGB>> map {{Color::GREEN, {0, color_max, 0}}, {Color::BLUE, {0, 0, color_max}}, {Color::RED, {color_max, 0, 0}}};
|
||||
for (auto [key, value] : map) {
|
||||
|
||||
std::cout << "Key=" << key << " Value=" << value << std::endl;
|
||||
}
|
||||
auto compare = [](std::pair<Color, RGB>& lhs,
|
||||
std::pair<Color, RGB>& rhs) {
|
||||
return static_cast<std::int32_t>(lhs.first) < static_cast<std::int32_t>(rhs.first);
|
||||
};
|
||||
std::sort(std::begin(map), std::end(map), compare);
|
||||
for (auto [key, value] : map) {
|
||||
|
||||
std::cout << "Key=" << key << " Value=" << value << std::endl;
|
||||
}
|
||||
}
|
||||
Vendored
+834
@@ -0,0 +1,834 @@
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// 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(__clang__)
|
||||
# pragma clang diagnostic push
|
||||
#elif defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
#elif 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
|
||||
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
#include <magic_enum/magic_enum_flags.hpp>
|
||||
#include <magic_enum/magic_enum_fuse.hpp>
|
||||
#include <magic_enum/magic_enum_iostream.hpp>
|
||||
#include <magic_enum/magic_enum_utility.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <cctype>
|
||||
#include <string_view>
|
||||
#include <sstream>
|
||||
|
||||
enum class Color { RED = 1, GREEN = 2, BLUE = 4 };
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<Color> {
|
||||
static constexpr bool is_flags = true;
|
||||
};
|
||||
|
||||
enum class Numbers : int {
|
||||
none = 0,
|
||||
one = 1 << 1,
|
||||
two = 1 << 2,
|
||||
three = 1 << 3,
|
||||
many = 1 << 30,
|
||||
};
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<Numbers> {
|
||||
static constexpr bool is_flags = true;
|
||||
};
|
||||
|
||||
enum Directions : std::uint64_t {
|
||||
NoDirection = 0,
|
||||
Left = std::uint64_t{1} << 10,
|
||||
Down = std::uint64_t{1} << 20,
|
||||
Up = std::uint64_t{1} << 31,
|
||||
Right = std::uint64_t{1} << 63,
|
||||
};
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<Directions> {
|
||||
static constexpr bool is_flags = true;
|
||||
};
|
||||
|
||||
enum number : unsigned long {
|
||||
no_number = 0,
|
||||
one = 1 << 1,
|
||||
two = 1 << 2,
|
||||
three = 1 << 3,
|
||||
four = 1 << 4,
|
||||
#if defined(MAGIC_ENUM_SUPPORTED_ALIASES)
|
||||
_1 = one,
|
||||
_2 = two,
|
||||
_3 = three,
|
||||
_4 = four
|
||||
#endif
|
||||
};
|
||||
template <>
|
||||
struct magic_enum::customize::enum_range<number> {
|
||||
static constexpr bool is_flags = true;
|
||||
};
|
||||
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
#include <magic_enum/magic_enum_fuse.hpp>
|
||||
|
||||
using namespace magic_enum;
|
||||
using namespace magic_enum::bitwise_operators;
|
||||
|
||||
TEST_CASE("enum_cast") {
|
||||
SECTION("string") {
|
||||
constexpr auto cr = enum_cast<Color>("RED");
|
||||
REQUIRE(cr.value() == Color::RED);
|
||||
REQUIRE(enum_cast<Color&>("GREEN").value() == Color::GREEN);
|
||||
REQUIRE(enum_cast<Color>("blue", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }).value() == Color::BLUE);
|
||||
REQUIRE_FALSE(enum_cast<Color&>("blue|RED", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }).has_value());
|
||||
REQUIRE_FALSE(enum_cast<Color&>("GREEN|RED").has_value());
|
||||
REQUIRE_FALSE(enum_cast<Color&>("GREEN|RED|RED").has_value());
|
||||
REQUIRE_FALSE(enum_cast<Color&>("GREEN|RED|None").has_value());
|
||||
REQUIRE_FALSE(enum_cast<Color>("None").has_value());
|
||||
|
||||
REQUIRE(enum_flags_cast<Color&>("GREEN").value() == Color::GREEN);
|
||||
REQUIRE(enum_flags_cast<Color>("blue", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }).value() == Color::BLUE);
|
||||
REQUIRE(enum_flags_cast<Color&>("blue|RED", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }).value() == (Color::BLUE | Color::RED));
|
||||
REQUIRE(enum_flags_cast<Color&>("GREEN|RED").value() == (Color::GREEN | Color::RED));
|
||||
REQUIRE(enum_flags_cast<Color&>("GREEN|RED|RED").value() == (Color::GREEN | Color::RED));
|
||||
REQUIRE_FALSE(enum_flags_cast<Color&>("GREEN|RED|None").has_value());
|
||||
REQUIRE_FALSE(enum_flags_cast<Color>("None").has_value());
|
||||
|
||||
constexpr auto no = enum_cast<Numbers>("one");
|
||||
REQUIRE(no.value() == Numbers::one);
|
||||
REQUIRE(enum_cast<Numbers>("two").value() == Numbers::two);
|
||||
REQUIRE(enum_cast<Numbers>("three").value() == Numbers::three);
|
||||
REQUIRE(enum_cast<Numbers>("many") == Numbers::many);
|
||||
REQUIRE_FALSE(enum_cast<Numbers>("None").has_value());
|
||||
|
||||
constexpr auto dr = enum_cast<Directions>("Right");
|
||||
REQUIRE(enum_cast<Directions&>("Up").value() == Directions::Up);
|
||||
REQUIRE(enum_cast<const Directions>("Down").value() == Directions::Down);
|
||||
REQUIRE(dr.value() == Directions::Right);
|
||||
REQUIRE(enum_cast<Directions>("Left").value() == Directions::Left);
|
||||
REQUIRE_FALSE(enum_cast<Directions>("None").has_value());
|
||||
|
||||
constexpr auto nto = enum_flags_cast<number>("three|one");
|
||||
REQUIRE(enum_cast<number>("one").value() == number::one);
|
||||
REQUIRE(enum_cast<number>("two").value() == number::two);
|
||||
REQUIRE(enum_cast<number>("three").value() == number::three);
|
||||
REQUIRE(enum_cast<number>("four") == number::four);
|
||||
REQUIRE(nto.value() == (number::three | number::one));
|
||||
REQUIRE_FALSE(enum_cast<number>("None").has_value());
|
||||
}
|
||||
|
||||
SECTION("integer") {
|
||||
Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
|
||||
constexpr auto cr = enum_cast<Color>(1);
|
||||
REQUIRE(cr.value() == Color::RED);
|
||||
REQUIRE(enum_cast<Color&>(2).value() == Color::GREEN);
|
||||
REQUIRE(enum_cast<Color>(static_cast<int>(cm[2])).value() == Color::BLUE);
|
||||
REQUIRE_FALSE(enum_cast<Color>(1 | 2).has_value());
|
||||
REQUIRE_FALSE(enum_cast<Color>(1 | 2 | 1).has_value());
|
||||
REQUIRE_FALSE(enum_cast<Color>(1 | 2 | 8).has_value());
|
||||
REQUIRE_FALSE(enum_cast<Color>(0).has_value());
|
||||
|
||||
REQUIRE(enum_flags_cast<Color&>(2).value() == Color::GREEN);
|
||||
REQUIRE(enum_flags_cast<Color>(static_cast<int>(cm[2])).value() == Color::BLUE);
|
||||
REQUIRE(enum_flags_cast<Color>(1 | 2).value() == (Color::GREEN | Color::RED));
|
||||
REQUIRE(enum_flags_cast<Color>(1 | 2 | 1).value() == (Color::GREEN | Color::RED));
|
||||
REQUIRE_FALSE(enum_flags_cast<Color>(1 | 2 | 8).has_value());
|
||||
REQUIRE_FALSE(enum_flags_cast<Color>(0).has_value());
|
||||
|
||||
constexpr auto no = enum_cast<Numbers>(2);
|
||||
REQUIRE(no.value() == Numbers::one);
|
||||
REQUIRE(enum_cast<Numbers>(4).value() == Numbers::two);
|
||||
REQUIRE(enum_cast<Numbers>(8).value() == Numbers::three);
|
||||
REQUIRE(enum_cast<Numbers>(1 << 30).value() == Numbers::many);
|
||||
REQUIRE_FALSE(enum_cast<Numbers>(127).has_value());
|
||||
REQUIRE_FALSE(enum_cast<Numbers>(0).has_value());
|
||||
|
||||
constexpr auto dr = enum_cast<Directions>(std::uint64_t{1} << 63);
|
||||
REQUIRE(enum_cast<Directions&>(std::uint64_t{1} << 31).value() == Directions::Up);
|
||||
REQUIRE(enum_cast<const Directions>(std::uint64_t{1} << 20).value() == Directions::Down);
|
||||
REQUIRE(dr.value() == Directions::Right);
|
||||
REQUIRE(enum_cast<Directions>(std::uint64_t{1} << 10).value() == Directions::Left);
|
||||
REQUIRE_FALSE(enum_cast<Directions>(0).has_value());
|
||||
|
||||
constexpr auto nto = enum_flags_cast<number>(2 | 8);
|
||||
REQUIRE(enum_cast<number>(1 << 1).value() == number::one);
|
||||
REQUIRE(enum_cast<number>(1 << 2).value() == number::two);
|
||||
REQUIRE(enum_cast<number>(1 << 3).value() == number::three);
|
||||
REQUIRE(enum_cast<number>(1 << 4).value() == number::four);
|
||||
REQUIRE(nto.value() == (number::three | number::one));
|
||||
REQUIRE_FALSE(enum_cast<number>(0).has_value());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("enum_index") {
|
||||
Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
|
||||
constexpr auto cr = enum_index(Color::RED);
|
||||
Color cg = Color::GREEN;
|
||||
REQUIRE(cr.value() == 0);
|
||||
REQUIRE(enum_index<Color&>(cg).value() == 1);
|
||||
REQUIRE(enum_index(cm[2]).value() == 2);
|
||||
REQUIRE_FALSE(enum_index<Color>(Color::RED | Color::GREEN).has_value());
|
||||
REQUIRE_FALSE(enum_index<Color>(Color::RED | Color::GREEN | Color::RED).has_value());
|
||||
REQUIRE_FALSE(enum_index<Color>(Color::RED | Color{8}).has_value());
|
||||
REQUIRE_FALSE(enum_index(static_cast<Color>(0)).has_value());
|
||||
|
||||
constexpr auto no = enum_index(Numbers::one);
|
||||
REQUIRE(no.value() == 0);
|
||||
REQUIRE(enum_index(Numbers::two).value() == 1);
|
||||
REQUIRE(enum_index(Numbers::three).value() == 2);
|
||||
REQUIRE(enum_index(Numbers::many).value() == 3);
|
||||
REQUIRE_FALSE(enum_index(static_cast<Numbers>(0)).has_value());
|
||||
|
||||
constexpr auto dr = enum_index(Directions::Right);
|
||||
Directions dl = Directions::Left;
|
||||
REQUIRE(enum_index<Directions&>(dl).value() == 0);
|
||||
REQUIRE(enum_index<const Directions>(Directions::Down).value() == 1);
|
||||
REQUIRE(enum_index(Directions::Up).value() == 2);
|
||||
REQUIRE(dr.value() == 3);
|
||||
REQUIRE_FALSE(enum_index(static_cast<Directions>(0)).has_value());
|
||||
|
||||
constexpr auto nto = enum_index(number::three | number::one);
|
||||
REQUIRE(enum_index(number::one).value() == 0);
|
||||
REQUIRE(enum_index(number::two).value() == 1);
|
||||
REQUIRE(enum_index(number::three).value() == 2);
|
||||
REQUIRE(enum_index(number::four).value() == 3);
|
||||
REQUIRE_FALSE(nto.has_value());
|
||||
REQUIRE_FALSE(enum_index(static_cast<number>(0)).has_value());
|
||||
}
|
||||
|
||||
TEST_CASE("enum_contains") {
|
||||
SECTION("value") {
|
||||
Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
|
||||
constexpr auto cr = enum_contains(Color::RED);
|
||||
Color cg = Color::GREEN;
|
||||
REQUIRE(cr);
|
||||
REQUIRE(enum_contains<Color&>(cg));
|
||||
REQUIRE(enum_contains(cm[2]));
|
||||
REQUIRE_FALSE(enum_contains(static_cast<Color>(0)));
|
||||
|
||||
REQUIRE(enum_flags_contains<Color&>(cg));
|
||||
REQUIRE(enum_flags_contains(cm[2]));
|
||||
REQUIRE(enum_flags_contains<Color>(Color::RED | Color::GREEN));
|
||||
REQUIRE(enum_flags_contains<Color>(Color::RED | Color::GREEN | Color::GREEN));
|
||||
REQUIRE_FALSE(enum_flags_contains<Color>(Color::RED | Color{8}));
|
||||
REQUIRE_FALSE(enum_flags_contains(static_cast<Color>(0)));
|
||||
|
||||
constexpr auto no = enum_contains(Numbers::one);
|
||||
REQUIRE(no);
|
||||
REQUIRE(enum_contains(Numbers::two));
|
||||
REQUIRE(enum_contains(Numbers::three));
|
||||
REQUIRE(enum_contains(Numbers::many));
|
||||
REQUIRE_FALSE(enum_contains(static_cast<Numbers>(0)));
|
||||
|
||||
constexpr auto dr = enum_contains(Directions::Right);
|
||||
Directions dl = Directions::Left;
|
||||
REQUIRE(enum_contains<Directions&>(dl));
|
||||
REQUIRE(enum_contains<const Directions>(Directions::Down));
|
||||
REQUIRE(enum_contains(Directions::Up));
|
||||
REQUIRE(dr);
|
||||
REQUIRE_FALSE(enum_contains(static_cast<Directions>(0)));
|
||||
|
||||
constexpr auto nto = enum_contains(number::three | number::one);
|
||||
REQUIRE(enum_contains(number::one));
|
||||
REQUIRE(enum_contains<number&>(number::two));
|
||||
REQUIRE(enum_contains(number::one));
|
||||
REQUIRE(enum_contains(number::four));
|
||||
REQUIRE_FALSE(nto);
|
||||
REQUIRE_FALSE(enum_contains(static_cast<number>(0)));
|
||||
|
||||
REQUIRE(enum_flags_contains(number::three | number::one));
|
||||
}
|
||||
|
||||
SECTION("integer") {
|
||||
REQUIRE(enum_contains<Color>(1));
|
||||
REQUIRE(enum_contains<Color&>(2));
|
||||
REQUIRE(enum_contains<const Color>(4));
|
||||
REQUIRE_FALSE(enum_contains<Color>(0));
|
||||
|
||||
REQUIRE(enum_flags_contains<Color>(1));
|
||||
REQUIRE(enum_flags_contains<Color&>(2));
|
||||
REQUIRE(enum_flags_contains<Color>(4));
|
||||
REQUIRE(enum_flags_contains<Color>(1 | 2));
|
||||
REQUIRE(enum_flags_contains<Color>(1 | 2 | 1));
|
||||
REQUIRE_FALSE(enum_flags_contains<Color>(1 | 2 | 8));
|
||||
REQUIRE_FALSE(enum_flags_contains<Color>(0));
|
||||
|
||||
constexpr auto no = enum_contains<Numbers>(1 << 1);
|
||||
REQUIRE(no);
|
||||
REQUIRE(enum_contains<Numbers>(1 << 2));
|
||||
REQUIRE(enum_contains<Numbers>(1 << 3));
|
||||
REQUIRE(enum_contains<Numbers>(1 << 30));
|
||||
|
||||
constexpr auto dr = enum_contains<Directions&>(std::uint64_t{1} << 63);
|
||||
REQUIRE(dr);
|
||||
REQUIRE(enum_contains<const Directions>(std::uint64_t{1} << 10));
|
||||
REQUIRE(enum_contains<Directions>(std::uint64_t{1} << 20));
|
||||
REQUIRE(enum_contains<Directions>(std::uint64_t{1} << 31));
|
||||
REQUIRE_FALSE(enum_contains<Directions>(static_cast<Directions>(0)));
|
||||
|
||||
constexpr auto nto = enum_contains<number>(8 | 2);
|
||||
REQUIRE(enum_contains<number>(1 << 1));
|
||||
REQUIRE(enum_contains<number>(1 << 2));
|
||||
REQUIRE(enum_contains<number>(1 << 3));
|
||||
REQUIRE(enum_contains<number>(1 << 4));
|
||||
REQUIRE_FALSE(enum_contains<number>(8 | 2 | 16));
|
||||
REQUIRE_FALSE(enum_contains<number>(8 | 16 | 16));
|
||||
REQUIRE_FALSE(nto);
|
||||
REQUIRE_FALSE(enum_contains<number>(8 | 64));
|
||||
REQUIRE_FALSE(enum_contains<number>(0));
|
||||
}
|
||||
|
||||
SECTION("string") {
|
||||
constexpr auto cr = "RED";
|
||||
REQUIRE(enum_contains<Color>(cr));
|
||||
REQUIRE(enum_contains<Color&>("GREEN"));
|
||||
REQUIRE(enum_contains<const Color>("blue", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }));
|
||||
REQUIRE_FALSE(enum_contains<Color&>("blue|RED", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }));
|
||||
REQUIRE_FALSE(enum_contains<Color&>("GREEN|RED"));
|
||||
REQUIRE_FALSE(enum_contains<Color&>("GREEN|RED|RED"));
|
||||
REQUIRE_FALSE(enum_contains<Color>("GREEN|RED|None"));
|
||||
REQUIRE_FALSE(enum_contains<Color>("None"));
|
||||
|
||||
REQUIRE(enum_flags_contains<Color&>("GREEN"));
|
||||
REQUIRE(enum_flags_contains<Color>("blue", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }));
|
||||
REQUIRE(enum_flags_contains<Color>("blue|RED", [](char lhs, char rhs) { return std::tolower(lhs) == std::tolower(rhs); }));
|
||||
REQUIRE(enum_flags_contains<Color>("GREEN|RED"));
|
||||
REQUIRE(enum_flags_contains<Color>("GREEN|RED|RED"));
|
||||
REQUIRE_FALSE(enum_flags_contains<Color>("GREEN|RED|None"));
|
||||
REQUIRE_FALSE(enum_flags_contains<Color>("None"));
|
||||
|
||||
constexpr auto no = std::string_view{"one"};
|
||||
REQUIRE(enum_contains<Numbers>(no));
|
||||
REQUIRE(enum_contains<Numbers>("two"));
|
||||
REQUIRE(enum_contains<Numbers>("three"));
|
||||
REQUIRE(enum_contains<Numbers>("many"));
|
||||
REQUIRE_FALSE(enum_contains<Numbers>("None"));
|
||||
|
||||
auto dr = std::string{"Right"};
|
||||
REQUIRE(enum_contains<Directions&>("Up"));
|
||||
REQUIRE(enum_contains<Directions>("Down"));
|
||||
REQUIRE(enum_contains<const Directions>(dr));
|
||||
REQUIRE(enum_contains<Directions>("Left"));
|
||||
REQUIRE_FALSE(enum_contains<Directions>("None"));
|
||||
|
||||
constexpr auto nto = enum_contains<number>("three|one");
|
||||
REQUIRE(enum_contains<number>("one"));
|
||||
REQUIRE(enum_contains<number>("two"));
|
||||
REQUIRE(enum_contains<number>("three"));
|
||||
REQUIRE(enum_contains<number>("four"));
|
||||
REQUIRE_FALSE(nto);
|
||||
REQUIRE_FALSE(enum_contains<number>("None"));
|
||||
|
||||
REQUIRE(enum_flags_contains<number>("three|one"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("enum_value") {
|
||||
constexpr auto cr = enum_value<Color>(0);
|
||||
REQUIRE(cr == Color::RED);
|
||||
REQUIRE(enum_value<Color&>(1) == Color::GREEN);
|
||||
REQUIRE(enum_value<Color>(2) == Color::BLUE);
|
||||
|
||||
REQUIRE(enum_value<Color, 0>() == Color::RED);
|
||||
REQUIRE(enum_value<Color, 1>() == Color::GREEN);
|
||||
REQUIRE(enum_value<Color, 2>() == Color::BLUE);
|
||||
|
||||
constexpr auto no = enum_value<Numbers>(0);
|
||||
REQUIRE(no == Numbers::one);
|
||||
REQUIRE(enum_value<Numbers>(1) == Numbers::two);
|
||||
REQUIRE(enum_value<Numbers>(2) == Numbers::three);
|
||||
REQUIRE(enum_value<Numbers>(3) == Numbers::many);
|
||||
|
||||
REQUIRE(enum_value<Numbers, 0>() == Numbers::one);
|
||||
REQUIRE(enum_value<Numbers, 1>() == Numbers::two);
|
||||
REQUIRE(enum_value<Numbers, 2>() == Numbers::three);
|
||||
REQUIRE(enum_value<Numbers, 3>() == Numbers::many);
|
||||
|
||||
constexpr auto dr = enum_value<Directions>(3);
|
||||
REQUIRE(enum_value<Directions&>(0) == Directions::Left);
|
||||
REQUIRE(enum_value<const Directions>(1) == Directions::Down);
|
||||
REQUIRE(enum_value<Directions>(2) == Directions::Up);
|
||||
REQUIRE(dr == Directions::Right);
|
||||
|
||||
REQUIRE(enum_value<Directions, 0>() == Directions::Left);
|
||||
REQUIRE(enum_value<Directions, 1>() == Directions::Down);
|
||||
REQUIRE(enum_value<Directions, 2>() == Directions::Up);
|
||||
REQUIRE(enum_value<Directions, 3>() == Directions::Right);
|
||||
|
||||
constexpr auto nt = enum_value<number>(2);
|
||||
REQUIRE(enum_value<number>(0) == number::one);
|
||||
REQUIRE(enum_value<number>(1) == number::two);
|
||||
REQUIRE(nt == number::three);
|
||||
REQUIRE(enum_value<number>(3) == number::four);
|
||||
|
||||
REQUIRE(enum_value<number, 0>() == number::one);
|
||||
REQUIRE(enum_value<number, 1>() == number::two);
|
||||
REQUIRE(enum_value<number, 2>() == number::three);
|
||||
REQUIRE(enum_value<number, 3>() == number::four);
|
||||
}
|
||||
|
||||
TEST_CASE("enum_values") {
|
||||
REQUIRE(std::is_same_v<decltype(enum_values<Color>()), const std::array<Color, 3>&>);
|
||||
|
||||
constexpr auto& s1 = enum_values<Color&>();
|
||||
REQUIRE(s1 == std::array<Color, 3>{{Color::RED, Color::GREEN, Color::BLUE}});
|
||||
|
||||
constexpr auto& s2 = enum_values<Numbers>();
|
||||
REQUIRE(s2 == std::array<Numbers, 4>{{Numbers::one, Numbers::two, Numbers::three, Numbers::many}});
|
||||
|
||||
constexpr auto& s3 = enum_values<const Directions>();
|
||||
REQUIRE(s3 == std::array<Directions, 4>{{Directions::Left, Directions::Down, Directions::Up, Directions::Right}});
|
||||
|
||||
constexpr auto& s4 = enum_values<number>();
|
||||
REQUIRE(s4 == std::array<number, 4>{{number::one, number::two, number::three, number::four}});
|
||||
}
|
||||
|
||||
TEST_CASE("enum_count") {
|
||||
constexpr auto s1 = enum_count<Color&>();
|
||||
REQUIRE(s1 == 3);
|
||||
|
||||
constexpr auto s2 = enum_count<Numbers>();
|
||||
REQUIRE(s2 == 4);
|
||||
|
||||
constexpr auto s3 = enum_count<const Directions>();
|
||||
REQUIRE(s3 == 4);
|
||||
|
||||
constexpr auto s4 = enum_count<number>();
|
||||
REQUIRE(s4 == 4);
|
||||
}
|
||||
|
||||
TEST_CASE("enum_name") {
|
||||
SECTION("automatic storage") {
|
||||
constexpr Color cr = Color::RED;
|
||||
constexpr auto cr_name = enum_name(cr);
|
||||
Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
|
||||
Color cb = Color::BLUE;
|
||||
REQUIRE(cr_name == "RED");
|
||||
REQUIRE(enum_name<Color&>(cb) == "BLUE");
|
||||
REQUIRE(enum_name(cm[1]) == "GREEN");
|
||||
REQUIRE(enum_name(Color::RED | Color{0}) == "RED");
|
||||
REQUIRE(enum_name(Color::RED | Color::GREEN).empty());
|
||||
REQUIRE(enum_name(Color::RED | Color{8}).empty());
|
||||
REQUIRE(enum_name(static_cast<Color>(0)).empty());
|
||||
|
||||
constexpr Numbers no = Numbers::one;
|
||||
constexpr auto no_name = enum_name(no);
|
||||
REQUIRE(no_name == "one");
|
||||
REQUIRE(enum_name(Numbers::two) == "two");
|
||||
REQUIRE(enum_name(Numbers::three) == "three");
|
||||
REQUIRE(enum_name(Numbers::many) == "many");
|
||||
REQUIRE(enum_name(Numbers::many | Numbers::two).empty());
|
||||
REQUIRE(enum_name(static_cast<Numbers>(0)).empty());
|
||||
|
||||
constexpr Directions dr = Directions::Right;
|
||||
constexpr auto dr_name = enum_name(dr);
|
||||
Directions du = Directions::Up;
|
||||
REQUIRE(enum_name<Directions&>(du) == "Up");
|
||||
REQUIRE(enum_name<const Directions>(Directions::Down) == "Down");
|
||||
REQUIRE(dr_name == "Right");
|
||||
REQUIRE(enum_name(Directions::Left) == "Left");
|
||||
REQUIRE(enum_name(Directions::Right | Directions::Up | Directions::Left | Directions::Down).empty());
|
||||
REQUIRE(enum_name(static_cast<Directions>(0)).empty());
|
||||
|
||||
constexpr number nto = number::three | number::one;
|
||||
constexpr auto nto_name = enum_name(nto);
|
||||
REQUIRE(enum_name(number::one) == "one");
|
||||
REQUIRE(enum_name(number::two) == "two");
|
||||
REQUIRE(enum_name(number::three) == "three");
|
||||
REQUIRE(enum_name(number::four) == "four");
|
||||
REQUIRE(nto_name.empty());
|
||||
REQUIRE(enum_name(static_cast<number>(0)).empty());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("enum_flags_name") {
|
||||
constexpr Color cr = Color::RED;
|
||||
auto cr_name = enum_flags_name(cr);
|
||||
Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
|
||||
Color cb = Color::BLUE;
|
||||
REQUIRE(cr_name == "RED");
|
||||
REQUIRE(enum_flags_name<Color&>(cb) == "BLUE");
|
||||
REQUIRE(enum_flags_name(cm[1]) == "GREEN");
|
||||
REQUIRE(enum_flags_name(Color::RED | Color{0}) == "RED");
|
||||
REQUIRE(enum_flags_name(Color::RED | Color::GREEN) == "RED|GREEN");
|
||||
REQUIRE(enum_flags_name(Color::RED | Color{8}).empty());
|
||||
REQUIRE(enum_flags_name(static_cast<Color>(0)).empty());
|
||||
|
||||
constexpr Numbers no = Numbers::one;
|
||||
auto no_name = enum_flags_name(no);
|
||||
REQUIRE(no_name == "one");
|
||||
REQUIRE(enum_flags_name(Numbers::two) == "two");
|
||||
REQUIRE(enum_flags_name(Numbers::three) == "three");
|
||||
REQUIRE(enum_flags_name(Numbers::many) == "many");
|
||||
REQUIRE(enum_flags_name(Numbers::many | Numbers::two) == "two|many");
|
||||
REQUIRE(enum_flags_name(static_cast<Numbers>(0)).empty());
|
||||
|
||||
constexpr Directions dr = Directions::Right;
|
||||
auto dr_name = enum_flags_name(dr);
|
||||
Directions du = Directions::Up;
|
||||
REQUIRE(enum_flags_name<Directions&>(du) == "Up");
|
||||
REQUIRE(enum_flags_name<const Directions>(Directions::Down) == "Down");
|
||||
REQUIRE(dr_name == "Right");
|
||||
REQUIRE(enum_flags_name(Directions::Left) == "Left");
|
||||
REQUIRE(enum_flags_name(Directions::Right | Directions::Up | Directions::Left | Directions::Down) == "Left|Down|Up|Right");
|
||||
REQUIRE(enum_flags_name(static_cast<Directions>(0)).empty());
|
||||
|
||||
constexpr number nto = number::three | number::one;
|
||||
auto nto_name = enum_flags_name(nto);
|
||||
REQUIRE(enum_flags_name(number::one) == "one");
|
||||
REQUIRE(enum_flags_name(number::two) == "two");
|
||||
REQUIRE(enum_flags_name(number::three) == "three");
|
||||
REQUIRE(enum_flags_name(number::four) == "four");
|
||||
REQUIRE(nto_name == "one|three");
|
||||
REQUIRE(enum_flags_name(static_cast<number>(0)).empty());
|
||||
}
|
||||
|
||||
TEST_CASE("enum_names") {
|
||||
REQUIRE(std::is_same_v<decltype(enum_names<Color>()), const std::array<std::string_view, 3>&>);
|
||||
|
||||
constexpr auto& s1 = enum_names<Color&>();
|
||||
REQUIRE(s1 == std::array<std::string_view, 3>{{"RED", "GREEN", "BLUE"}});
|
||||
|
||||
constexpr auto& s2 = enum_names<Numbers>();
|
||||
REQUIRE(s2 == std::array<std::string_view, 4>{{"one", "two", "three", "many"}});
|
||||
|
||||
constexpr auto& s3 = enum_names<const Directions>();
|
||||
REQUIRE(s3 == std::array<std::string_view, 4>{{"Left", "Down", "Up", "Right"}});
|
||||
|
||||
constexpr auto& s4 = enum_names<number>();
|
||||
REQUIRE(s4 == std::array<std::string_view, 4>{{"one", "two", "three", "four"}});
|
||||
}
|
||||
|
||||
TEST_CASE("enum_entries") {
|
||||
REQUIRE(std::is_same_v<decltype(enum_entries<Color>()), const std::array<std::pair<Color, std::string_view>, 3>&>);
|
||||
|
||||
constexpr auto& s1 = enum_entries<Color&>();
|
||||
REQUIRE(s1 == std::array<std::pair<Color, std::string_view>, 3>{{{Color::RED, "RED"}, {Color::GREEN, "GREEN"}, {Color::BLUE, "BLUE"}}});
|
||||
|
||||
constexpr auto& s2 = enum_entries<Numbers>();
|
||||
REQUIRE(s2 == std::array<std::pair<Numbers, std::string_view>, 4>{{{Numbers::one, "one"}, {Numbers::two, "two"}, {Numbers::three, "three"}, {Numbers::many, "many"}}});
|
||||
|
||||
constexpr auto& s3 = enum_entries<Directions&>();
|
||||
REQUIRE(s3 == std::array<std::pair<Directions, std::string_view>, 4>{{{Directions::Left, "Left"}, {Directions::Down, "Down"}, {Directions::Up, "Up"}, {Directions::Right, "Right"}}});
|
||||
|
||||
constexpr auto& s4 = enum_entries<number>();
|
||||
REQUIRE(s4 == std::array<std::pair<number, std::string_view>, 4>{{{number::one, "one"}, {number::two, "two"}, {number::three, "three"}, {number::four, "four"}}});
|
||||
}
|
||||
|
||||
TEST_CASE("ostream_operators") {
|
||||
auto test_ostream = [](auto e, std::string name) {
|
||||
using namespace magic_enum::ostream_operators;
|
||||
std::stringstream ss;
|
||||
ss << e;
|
||||
REQUIRE(ss.str() == name);
|
||||
};
|
||||
|
||||
test_ostream(std::make_optional(Color::RED), "RED");
|
||||
test_ostream(Color::GREEN, "GREEN");
|
||||
test_ostream(Color::BLUE, "BLUE");
|
||||
test_ostream(Color::BLUE | Color::RED, "RED|BLUE");
|
||||
test_ostream(Color::BLUE | Color::RED | Color::RED, "RED|BLUE");
|
||||
test_ostream(static_cast<Color>(0), "0");
|
||||
test_ostream(std::make_optional(static_cast<Color>(0)), "0");
|
||||
|
||||
test_ostream(std::make_optional(Numbers::one), "one");
|
||||
test_ostream(Numbers::two, "two");
|
||||
test_ostream(Numbers::three, "three");
|
||||
test_ostream(Numbers::many, "many");
|
||||
test_ostream(static_cast<Numbers>(0), "0");
|
||||
test_ostream(std::make_optional(static_cast<Numbers>(0)), "0");
|
||||
|
||||
test_ostream(std::make_optional(Directions::Up), "Up");
|
||||
test_ostream(Directions::Down, "Down");
|
||||
test_ostream(Directions::Right, "Right");
|
||||
test_ostream(Directions::Left, "Left");
|
||||
test_ostream(Directions::Right | Directions::Left, "Left|Right");
|
||||
test_ostream(static_cast<Directions>(0), "0");
|
||||
test_ostream(std::make_optional(static_cast<Directions>(0)), "0");
|
||||
|
||||
test_ostream(std::make_optional(number::one), "one");
|
||||
test_ostream(number::two, "two");
|
||||
test_ostream(number::three, "three");
|
||||
test_ostream(number::four, "four");
|
||||
test_ostream(number::four | number::one, "one|four");
|
||||
test_ostream(static_cast<number>(0), "0");
|
||||
test_ostream(std::make_optional(static_cast<number>(0)), "0");
|
||||
}
|
||||
|
||||
TEST_CASE("istream_operators") {
|
||||
auto test_istream = [](const auto e, std::string name) {
|
||||
using namespace magic_enum::istream_operators;
|
||||
std::istringstream ss(name);
|
||||
std::decay_t<decltype(e)> v;
|
||||
ss >> v;
|
||||
REQUIRE(v == e);
|
||||
REQUIRE(ss);
|
||||
};
|
||||
|
||||
test_istream(Color::GREEN, "GREEN");
|
||||
test_istream(Color::BLUE, "BLUE");
|
||||
test_istream(Color::BLUE | Color::RED, "RED|BLUE");
|
||||
test_istream(Color::BLUE | Color::RED | Color::RED, "RED|BLUE");
|
||||
|
||||
test_istream(Numbers::two, "two");
|
||||
test_istream(Numbers::three, "three");
|
||||
test_istream(Numbers::many, "many");
|
||||
|
||||
test_istream(Directions::Down, "Down");
|
||||
test_istream(Directions::Right, "Right");
|
||||
test_istream(Directions::Left, "Left");
|
||||
test_istream(Directions::Right | Directions::Left, "Left|Right");
|
||||
|
||||
test_istream(number::two, "two");
|
||||
test_istream(number::three, "three");
|
||||
test_istream(number::four, "four");
|
||||
test_istream(number::four | number::one, "one|four");
|
||||
}
|
||||
|
||||
TEST_CASE("bitwise_operators") {
|
||||
SECTION("operator^") {
|
||||
REQUIRE(enum_integer(~Color::RED) == ~enum_integer(Color::RED));
|
||||
REQUIRE(enum_integer(~Numbers::one) == ~enum_integer(Numbers::one));
|
||||
REQUIRE(enum_integer(~Directions::Up) == ~enum_integer(Directions::Up));
|
||||
REQUIRE(enum_integer(~number::one) == ~enum_integer(number::one));
|
||||
}
|
||||
|
||||
SECTION("operator|") {
|
||||
REQUIRE(enum_integer(Color::RED | Color::BLUE) == (enum_integer(Color::RED) | enum_integer(Color::BLUE)));
|
||||
REQUIRE(enum_integer(Numbers::one | Numbers::two) == (enum_integer(Numbers::one) | enum_integer(Numbers::two)));
|
||||
REQUIRE(enum_integer(Directions::Up | Directions::Down) == (enum_integer(Directions::Up) | enum_integer(Directions::Down)));
|
||||
REQUIRE(enum_integer(number::one | number::two) == (enum_integer(number::one) | enum_integer(number::two)));
|
||||
}
|
||||
|
||||
SECTION("operator&") {
|
||||
REQUIRE(enum_integer(Color::RED & Color::BLUE) == (enum_integer(Color::RED) & enum_integer(Color::BLUE)));
|
||||
REQUIRE(enum_integer(Numbers::one & Numbers::two) == (enum_integer(Numbers::one) & enum_integer(Numbers::two)));
|
||||
REQUIRE(enum_integer(Directions::Up & Directions::Down) == (enum_integer(Directions::Up) & enum_integer(Directions::Down)));
|
||||
REQUIRE(enum_integer(number::one & number::two) == (enum_integer(number::one) & enum_integer(number::two)));
|
||||
}
|
||||
|
||||
SECTION("operator^") {
|
||||
REQUIRE(enum_integer(Color::RED ^ Color::BLUE) == (enum_integer(Color::RED) ^ enum_integer(Color::BLUE)));
|
||||
REQUIRE(enum_integer(Numbers::one ^ Numbers::two) == (enum_integer(Numbers::one) ^ enum_integer(Numbers::two)));
|
||||
REQUIRE(enum_integer(Directions::Up ^ Directions::Down) == (enum_integer(Directions::Up) ^ enum_integer(Directions::Down)));
|
||||
REQUIRE(enum_integer(number::one ^ number::two) == (enum_integer(number::one) ^ enum_integer(number::two)));
|
||||
}
|
||||
|
||||
SECTION("operator|=") {
|
||||
Color x1 = Color::RED;
|
||||
x1 |= Color::BLUE;
|
||||
REQUIRE(enum_integer(x1) == (enum_integer(Color::RED) | enum_integer(Color::BLUE)));
|
||||
|
||||
Numbers x2 = Numbers::one;
|
||||
x2 |= Numbers::two;
|
||||
REQUIRE(enum_integer(x2) == (enum_integer(Numbers::one) | enum_integer(Numbers::two)));
|
||||
|
||||
Directions x3 = Directions::Up;
|
||||
x3 |= Directions::Down;
|
||||
REQUIRE(enum_integer(x3) == (enum_integer(Directions::Up) | enum_integer(Directions::Down)));
|
||||
|
||||
number x4 = number::one;
|
||||
x4 |= number::two;
|
||||
REQUIRE(enum_integer(x4) == (enum_integer(number::one) | enum_integer(number::two)));
|
||||
}
|
||||
|
||||
SECTION("operator&=") {
|
||||
Color x1 = Color::RED;
|
||||
x1 &= Color::BLUE;
|
||||
REQUIRE(enum_integer(x1) == (enum_integer(Color::RED) & enum_integer(Color::BLUE)));
|
||||
|
||||
Numbers x2 = Numbers::one;
|
||||
x2 &= Numbers::two;
|
||||
REQUIRE(enum_integer(x2) == (enum_integer(Numbers::one) & enum_integer(Numbers::two)));
|
||||
|
||||
Directions x3 = Directions::Up;
|
||||
x3 &= Directions::Down;
|
||||
REQUIRE(enum_integer(x3) == (enum_integer(Directions::Up) & enum_integer(Directions::Down)));
|
||||
|
||||
number x4 = number::one;
|
||||
x4 &= number::two;
|
||||
REQUIRE(enum_integer(x4) == (enum_integer(number::one) & enum_integer(number::two)));
|
||||
}
|
||||
|
||||
SECTION("operator^=") {
|
||||
Color x1 = Color::RED;
|
||||
x1 ^= Color::BLUE;
|
||||
REQUIRE(enum_integer(x1) == (enum_integer(Color::RED) ^ enum_integer(Color::BLUE)));
|
||||
|
||||
Numbers x2 = Numbers::one;
|
||||
x2 ^= Numbers::two;
|
||||
REQUIRE(enum_integer(x2) == (enum_integer(Numbers::one) ^ enum_integer(Numbers::two)));
|
||||
|
||||
Directions x3 = Directions::Up;
|
||||
x3 ^= Directions::Down;
|
||||
REQUIRE(enum_integer(x3) == (enum_integer(Directions::Up) ^ enum_integer(Directions::Down)));
|
||||
|
||||
number x4 = number::one;
|
||||
x4 ^= number::two;
|
||||
REQUIRE(enum_integer(x4) == (enum_integer(number::one) ^ enum_integer(number::two)));
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1920
|
||||
# define MAGIC_ENUM_SUPPORTED_CONSTEXPR_FOR 1
|
||||
#endif
|
||||
|
||||
#if defined(MAGIC_ENUM_SUPPORTED_CONSTEXPR_FOR)
|
||||
|
||||
// from https://artificial-mind.net/blog/2020/10/31/constexpr-for
|
||||
template <auto Start, auto End, auto Inc, class F>
|
||||
constexpr void constexpr_for(F&& f) {
|
||||
if constexpr (Start < End) {
|
||||
f(std::integral_constant<decltype(Start), Start>());
|
||||
constexpr_for<Start + Inc, End, Inc>(f);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename E, E V>
|
||||
struct Foo {};
|
||||
|
||||
TEST_CASE("constexpr_for") {
|
||||
constexpr_for<0, magic_enum::enum_count<Color>(), 1>([](auto i) {
|
||||
[[maybe_unused]] Foo<Color, magic_enum::enum_value<Color, i>()> bar{};
|
||||
});
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cpp_lib_format)
|
||||
|
||||
#include <magic_enum/magic_enum_format.hpp>
|
||||
|
||||
TEST_CASE("format-base") {
|
||||
REQUIRE(std::format("Test-{:~^11}.", Color::RED | Color::GREEN) == "Test-~RED|GREEN~.");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
TEST_CASE("enum_flags_test") {
|
||||
REQUIRE(enum_flags_test(Color::RED|Color::GREEN, Color::RED));
|
||||
REQUIRE_FALSE(enum_flags_test(Color::RED|Color::GREEN, Color::BLUE));
|
||||
|
||||
REQUIRE_FALSE(enum_flags_test(Numbers::none, Numbers::none));
|
||||
REQUIRE_FALSE(enum_flags_test(Numbers::none, Numbers::one));
|
||||
REQUIRE(enum_flags_test(Numbers::one|Numbers::two|Numbers::many, Numbers::many));
|
||||
REQUIRE_FALSE(enum_flags_test(Numbers::one|Numbers::two|Numbers::many, Numbers::three));
|
||||
REQUIRE_FALSE(enum_flags_test(Numbers::one|Numbers::two|Numbers::many, Numbers::none));
|
||||
|
||||
REQUIRE_FALSE(enum_flags_test(Left|Right, NoDirection));
|
||||
REQUIRE(enum_flags_test(Left|Right|Up|Down, Right));
|
||||
REQUIRE_FALSE(enum_flags_test(Left|Up|Down, Right));
|
||||
|
||||
REQUIRE(enum_flags_test(number::one|number::two|number::four, number::one));
|
||||
REQUIRE_FALSE(enum_flags_test(number::one|number::two|number::four, number::three));
|
||||
REQUIRE_FALSE(enum_flags_test(number::one|number::two|number::four, number::no_number));
|
||||
}
|
||||
|
||||
TEST_CASE("enum_flags_test_any") {
|
||||
REQUIRE(enum_flags_test_any(Color::RED|Color::GREEN, Color::RED));
|
||||
REQUIRE_FALSE(enum_flags_test_any(Color::RED|Color::GREEN, Color::BLUE));
|
||||
|
||||
REQUIRE_FALSE(enum_flags_test_any(Numbers::none, Numbers::none));
|
||||
REQUIRE_FALSE(enum_flags_test_any(Numbers::none, Numbers::one));
|
||||
REQUIRE(enum_flags_test_any(Numbers::one|Numbers::two|Numbers::many, Numbers::many));
|
||||
REQUIRE_FALSE(enum_flags_test_any(Numbers::one|Numbers::two|Numbers::many, Numbers::three));
|
||||
REQUIRE_FALSE(enum_flags_test_any(Numbers::one|Numbers::two|Numbers::many, Numbers::none));
|
||||
|
||||
REQUIRE_FALSE(enum_flags_test_any(Left|Right, NoDirection));
|
||||
REQUIRE(enum_flags_test_any(Left|Right|Up|Down, Right));
|
||||
REQUIRE_FALSE(enum_flags_test_any(Left|Up|Down, Right));
|
||||
|
||||
REQUIRE(enum_flags_test_any(number::one|number::two|number::four, number::one));
|
||||
REQUIRE(enum_flags_test_any(number::one|number::two|number::four, number::one|number::two));
|
||||
REQUIRE_FALSE(enum_flags_test_any(number::one|number::two|number::four, number::three));
|
||||
REQUIRE_FALSE(enum_flags_test_any(number::one|number::two|number::four, number::no_number));
|
||||
|
||||
REQUIRE(enum_flags_test(Numbers::none, Numbers::none) == enum_flags_test_any(Numbers::none, Numbers::none));
|
||||
REQUIRE(enum_flags_test(Numbers::one, Numbers::none) == enum_flags_test_any(Numbers::one, Numbers::none));
|
||||
REQUIRE(enum_flags_test(Numbers::none, Numbers::one) == enum_flags_test_any(Numbers::none, Numbers::one));
|
||||
}
|
||||
|
||||
TEST_CASE("enum_next_value") {
|
||||
REQUIRE(enum_next_value(Color::RED) == Color::GREEN);
|
||||
REQUIRE(enum_next_value(Color::RED, 2) == Color::BLUE);
|
||||
REQUIRE(enum_next_value(Color::RED, 1) == Color::GREEN);
|
||||
REQUIRE(enum_next_value(Color::RED, 0) == Color::RED);
|
||||
REQUIRE(enum_next_value(Color::BLUE, -2) == Color::RED);
|
||||
REQUIRE(enum_next_value(Color::BLUE, -1) == Color::GREEN);
|
||||
REQUIRE_FALSE(enum_next_value(Color::BLUE).has_value());
|
||||
REQUIRE_FALSE(enum_next_value(Color::RED, -1).has_value());
|
||||
REQUIRE_FALSE(enum_next_value(Color::RED, 10).has_value());
|
||||
}
|
||||
|
||||
TEST_CASE("enum_next_value_circular") {
|
||||
REQUIRE(enum_next_value_circular(Color::RED) == Color::GREEN);
|
||||
REQUIRE(enum_next_value_circular(Color::RED, 2) == Color::BLUE);
|
||||
REQUIRE(enum_next_value_circular(Color::RED, 1) == Color::GREEN);
|
||||
REQUIRE(enum_next_value_circular(Color::RED, 0) == Color::RED);
|
||||
REQUIRE(enum_next_value_circular(Color::BLUE, -2) == Color::RED);
|
||||
REQUIRE(enum_next_value_circular(Color::BLUE, -1) == Color::GREEN);
|
||||
REQUIRE(enum_next_value_circular(Color::BLUE) == Color::RED);
|
||||
REQUIRE(enum_next_value_circular(Color::BLUE, 4) == Color::RED);
|
||||
REQUIRE(enum_next_value_circular(Color::BLUE, 3) == Color::BLUE);
|
||||
REQUIRE(enum_next_value_circular(Color::BLUE, 2) == Color::GREEN);
|
||||
REQUIRE(enum_next_value_circular(Color::BLUE, 1) == Color::RED);
|
||||
REQUIRE(enum_next_value_circular(Color::BLUE, 0) == Color::BLUE);
|
||||
REQUIRE(enum_next_value_circular(Color::RED, -1) == Color::BLUE);
|
||||
REQUIRE(enum_next_value_circular(Color::RED, -2) == Color::GREEN);
|
||||
REQUIRE(enum_next_value_circular(Color::RED, -3) == Color::RED);
|
||||
REQUIRE(enum_next_value_circular(Color::RED, -4) == Color::BLUE);
|
||||
}
|
||||
|
||||
TEST_CASE("enum_prev_value") {
|
||||
REQUIRE(enum_prev_value(Color::BLUE) == Color::GREEN);
|
||||
REQUIRE(enum_prev_value(Color::BLUE, 2) == Color::RED);
|
||||
REQUIRE(enum_prev_value(Color::BLUE, 1) == Color::GREEN);
|
||||
REQUIRE(enum_prev_value(Color::RED, -2) == Color::BLUE);
|
||||
REQUIRE(enum_prev_value(Color::RED, -1) == Color::GREEN);
|
||||
REQUIRE(enum_prev_value(Color::BLUE, 0) == Color::BLUE);
|
||||
REQUIRE_FALSE(enum_prev_value(Color::RED).has_value());
|
||||
REQUIRE_FALSE(enum_prev_value(Color::BLUE, -1).has_value());
|
||||
REQUIRE_FALSE(enum_prev_value(Color::BLUE, 10).has_value());
|
||||
}
|
||||
|
||||
TEST_CASE("enum_prev_value_circular") {
|
||||
REQUIRE(enum_prev_value_circular(Color::RED) == Color::BLUE);
|
||||
REQUIRE(enum_prev_value_circular(Color::RED, 2) == Color::GREEN);
|
||||
REQUIRE(enum_prev_value_circular(Color::RED, 1) == Color::BLUE);
|
||||
REQUIRE(enum_prev_value_circular(Color::RED, 0) == Color::RED);
|
||||
REQUIRE(enum_prev_value_circular(Color::BLUE, -2) == Color::GREEN);
|
||||
REQUIRE(enum_prev_value_circular(Color::BLUE, -1) == Color::RED);
|
||||
REQUIRE(enum_prev_value_circular(Color::BLUE) == Color::GREEN);
|
||||
REQUIRE(enum_prev_value_circular(Color::BLUE, 4) == Color::GREEN);
|
||||
REQUIRE(enum_prev_value_circular(Color::BLUE, 3) == Color::BLUE);
|
||||
REQUIRE(enum_prev_value_circular(Color::BLUE, 2) == Color::RED);
|
||||
REQUIRE(enum_prev_value_circular(Color::BLUE, 1) == Color::GREEN);
|
||||
REQUIRE(enum_prev_value_circular(Color::BLUE, 0) == Color::BLUE);
|
||||
REQUIRE(enum_prev_value_circular(Color::RED, -1) == Color::GREEN);
|
||||
REQUIRE(enum_prev_value_circular(Color::RED, -2) == Color::BLUE);
|
||||
REQUIRE(enum_prev_value_circular(Color::RED, -3) == Color::RED);
|
||||
REQUIRE(enum_prev_value_circular(Color::RED, -4) == Color::GREEN);
|
||||
}
|
||||
+445
@@ -0,0 +1,445 @@
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#undef MAGIC_ENUM_RANGE_MIN
|
||||
#define MAGIC_ENUM_RANGE_MIN -120
|
||||
#undef MAGIC_ENUM_RANGE_MAX
|
||||
#define MAGIC_ENUM_RANGE_MAX 120
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
#include <magic_enum/magic_enum_fuse.hpp>
|
||||
#include <magic_enum/magic_enum_iostream.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <cctype>
|
||||
#include <string_view>
|
||||
#include <sstream>
|
||||
|
||||
enum class Language : int { 日本語 = 10, 한국어 = 20, English = 30, 😃 = 40, TVÅ = 50 };
|
||||
|
||||
enum class LanguageFlag : int {
|
||||
日本語 = 1 << 1,
|
||||
한국어 = 1 << 2,
|
||||
English = 1 << 3,
|
||||
😃 = 1 << 4
|
||||
};
|
||||
|
||||
using namespace magic_enum;
|
||||
|
||||
static_assert(is_magic_enum_supported, "magic_enum: Unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
|
||||
|
||||
TEST_CASE("enum_cast") {
|
||||
SECTION("string") {
|
||||
constexpr auto lang = enum_cast<Language>("日本語");
|
||||
REQUIRE(enum_cast<Language&>("한국어").value() == Language::한국어);
|
||||
REQUIRE(enum_cast<const Language>("English").value() == Language::English);
|
||||
REQUIRE(lang.value() == Language::日本語);
|
||||
REQUIRE(enum_cast<Language>("😃").value() == Language::😃);
|
||||
REQUIRE(enum_cast<Language>("TVÅ").value() == Language::TVÅ);
|
||||
REQUIRE_FALSE(enum_cast<Language>("Französisch").has_value());
|
||||
}
|
||||
|
||||
SECTION("integer") {
|
||||
constexpr auto lang = enum_cast<Language>(10);
|
||||
REQUIRE(enum_cast<Language&>(20).value() == Language::한국어);
|
||||
REQUIRE(enum_cast<const Language>(30).value() == Language::English);
|
||||
REQUIRE(lang.value() == Language::日本語);
|
||||
REQUIRE(enum_cast<Language>(40).value() == Language::😃);
|
||||
REQUIRE_FALSE(enum_cast<Language>(0).has_value());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("enum_integer") {
|
||||
constexpr auto lang = enum_integer(Language::日本語);
|
||||
Language korean = Language::한국어;
|
||||
REQUIRE(enum_integer<Language&>(korean) == 20);
|
||||
REQUIRE(enum_integer<const Language>(Language::English) == 30);
|
||||
REQUIRE(enum_integer(Language::😃) == 40);
|
||||
REQUIRE(lang == 10);
|
||||
REQUIRE(enum_integer(static_cast<Language>(0)) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("enum_index") {
|
||||
constexpr auto lang = enum_index<Language>(Language::日本語);
|
||||
Language korean = Language::한국어;
|
||||
REQUIRE(enum_index<Language&>(korean) == 1);
|
||||
REQUIRE(enum_index<const Language>(Language::English).value() == 2);
|
||||
REQUIRE(enum_index(Language::😃) == 3);
|
||||
REQUIRE(lang.value() == 0);
|
||||
REQUIRE_FALSE(enum_index(static_cast<Language>(0)).has_value());
|
||||
}
|
||||
|
||||
TEST_CASE("enum_contains") {
|
||||
SECTION("value") {
|
||||
constexpr auto lang = enum_contains(Language::日本語);
|
||||
Language korean = Language::한국어;
|
||||
REQUIRE(enum_contains<Language&>(korean));
|
||||
REQUIRE(enum_contains<const Language>(Language::English));
|
||||
REQUIRE(enum_contains(Language::😃));
|
||||
REQUIRE(lang);
|
||||
}
|
||||
|
||||
SECTION("integer") {
|
||||
constexpr auto lang = enum_integer(Language::日本語);
|
||||
REQUIRE(enum_contains<Language&>(lang));
|
||||
REQUIRE(enum_contains<const Language>(Language::한국어));
|
||||
REQUIRE(enum_contains<Language>(Language::😃));
|
||||
REQUIRE_FALSE(enum_contains<Language>(static_cast<Language>(0)));
|
||||
}
|
||||
|
||||
SECTION("string") {
|
||||
auto lang = std::string{"日本語"};
|
||||
REQUIRE(enum_contains<Language&>("한국어"));
|
||||
REQUIRE(enum_contains<Language>("English"));
|
||||
REQUIRE(enum_contains<const Language>(lang));
|
||||
REQUIRE(enum_contains<Language>("😃"));
|
||||
REQUIRE_FALSE(enum_contains<Language>("None"));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("enum_value") {
|
||||
constexpr auto lang = enum_value<Language>(3);
|
||||
REQUIRE(enum_value<Language&>(0) == Language::日本語);
|
||||
REQUIRE(enum_value<const Language>(1) == Language::한국어);
|
||||
REQUIRE(enum_value<Language>(2) == Language::English);
|
||||
REQUIRE(lang == Language::😃);
|
||||
}
|
||||
|
||||
TEST_CASE("enum_values") {
|
||||
constexpr auto& s7 = enum_values<const Language>();
|
||||
REQUIRE(s7 == std::array<Language, 5>{{Language::日本語, Language::한국어, Language::English, Language::😃, Language::TVÅ}});
|
||||
}
|
||||
|
||||
TEST_CASE("enum_count") {
|
||||
constexpr auto s7 = enum_count<Language>();
|
||||
REQUIRE(s7 == 5);
|
||||
}
|
||||
|
||||
TEST_CASE("enum_name") {
|
||||
SECTION("automatic storage") {
|
||||
constexpr Language lang = Language::日本語;
|
||||
constexpr auto lang_name = enum_name(lang);
|
||||
Language lk = Language::한국어;
|
||||
REQUIRE(enum_name<Language&>(lk) == "한국어");
|
||||
REQUIRE(enum_name<const Language>(Language::English) == "English");
|
||||
REQUIRE(lang_name == "日本語");
|
||||
REQUIRE(enum_name(Language::😃) == "😃");
|
||||
REQUIRE(enum_name(Language::TVÅ) == "TVÅ");
|
||||
REQUIRE(enum_name(static_cast<Language>(0)).empty());
|
||||
}
|
||||
|
||||
SECTION("static storage") {
|
||||
constexpr Language lang = Language::日本語;
|
||||
constexpr auto lang_name = enum_name<lang>();
|
||||
REQUIRE(enum_name<Language::한국어>() == "한국어");
|
||||
REQUIRE(enum_name<Language::English>() == "English");
|
||||
REQUIRE(lang_name == "日本語");
|
||||
REQUIRE(enum_name<Language::😃>() == "😃");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("enum_names") {
|
||||
constexpr auto& s5 = enum_names<const Language>();
|
||||
REQUIRE(s5 == std::array<std::string_view, 5>{{"日本語", "한국어", "English", "😃", "TVÅ"}});
|
||||
}
|
||||
|
||||
TEST_CASE("enum_entries") {
|
||||
constexpr auto& s5 = enum_entries<const Language>();
|
||||
REQUIRE(s5 == std::array<std::pair<Language, std::string_view>, 5>{{{Language::日本語, "日本語"}, {Language::한국어, "한국어"}, {Language::English, "English"}, {Language::😃, "😃"}, {Language::TVÅ, "TVÅ"}}});
|
||||
}
|
||||
|
||||
TEST_CASE("ostream_operators") {
|
||||
auto test_ostream = [](auto e, std::string name) {
|
||||
using namespace magic_enum::ostream_operators;
|
||||
std::stringstream ss;
|
||||
ss << e;
|
||||
REQUIRE(ss);
|
||||
REQUIRE(ss.str() == name);
|
||||
};
|
||||
|
||||
test_ostream(std::make_optional(Language::日本語), "日本語");
|
||||
test_ostream(Language::한국어, "한국어");
|
||||
test_ostream(Language::English, "English");
|
||||
test_ostream(Language::😃, "😃");
|
||||
test_ostream(static_cast<Language>(0), "0");
|
||||
test_ostream(std::make_optional(static_cast<Language>(0)), "0");
|
||||
}
|
||||
|
||||
TEST_CASE("istream_operators") {
|
||||
auto test_istream = [](const auto e, std::string name) {
|
||||
using namespace magic_enum::istream_operators;
|
||||
std::istringstream ss(name);
|
||||
std::decay_t<decltype(e)> v;
|
||||
ss >> v;
|
||||
REQUIRE(ss);
|
||||
REQUIRE(v == e);
|
||||
};
|
||||
|
||||
test_istream(Language::한국어, "한국어");
|
||||
test_istream(Language::English, "English");
|
||||
test_istream(Language::😃, "😃");
|
||||
}
|
||||
|
||||
TEST_CASE("bitwise_operators") {
|
||||
using namespace magic_enum::bitwise_operators;
|
||||
|
||||
SECTION("operator^") {
|
||||
REQUIRE(enum_integer(~Language::日本語) == ~enum_integer(Language::日本語));
|
||||
}
|
||||
|
||||
SECTION("operator|") {
|
||||
REQUIRE(enum_integer(Language::日本語 | Language::한국어) == (enum_integer(Language::日本語) | enum_integer(Language::한국어)));
|
||||
}
|
||||
|
||||
SECTION("operator&") {
|
||||
REQUIRE(enum_integer(Language::日本語 & Language::한국어) == (enum_integer(Language::日本語) & enum_integer(Language::한국어)));
|
||||
|
||||
}
|
||||
|
||||
SECTION("operator^") {
|
||||
REQUIRE(enum_integer(Language::日本語 ^ Language::한국어) == (enum_integer(Language::日本語) ^ enum_integer(Language::한국어)));
|
||||
}
|
||||
|
||||
SECTION("operator|=") {
|
||||
Language x5 = Language::日本語;
|
||||
x5 |= Language::한국어;
|
||||
REQUIRE(enum_integer(x5) == (enum_integer(Language::日本語) | enum_integer(Language::한국어)));
|
||||
}
|
||||
|
||||
SECTION("operator&=") {
|
||||
Language x5 = Language::日本語;
|
||||
x5 &= Language::한국어;
|
||||
REQUIRE(enum_integer(x5) == (enum_integer(Language::日本語) & enum_integer(Language::한국어)));
|
||||
}
|
||||
|
||||
SECTION("operator^=") {
|
||||
Language x5 = Language::日本語;
|
||||
x5 ^= Language::한국어;
|
||||
REQUIRE(enum_integer(x5) == (enum_integer(Language::日本語) ^ enum_integer(Language::한국어)));
|
||||
}
|
||||
}
|
||||
TEST_CASE("type_traits") {
|
||||
REQUIRE_FALSE(is_unscoped_enum_v<Language>);
|
||||
}
|
||||
|
||||
TEST_CASE("enum_type_name") {
|
||||
REQUIRE(enum_type_name<const Language&>() == "Language");
|
||||
}
|
||||
|
||||
TEST_CASE("extrema") {
|
||||
SECTION("min") {
|
||||
REQUIRE(magic_enum::customize::enum_range<Language>::min == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::reflected_min<Language, as_common<>>() == MAGIC_ENUM_RANGE_MIN);
|
||||
REQUIRE(magic_enum::detail::min_v<Language, as_common<>> == 10);
|
||||
}
|
||||
|
||||
SECTION("max") {
|
||||
REQUIRE(magic_enum::customize::enum_range<Language>::max == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::reflected_max<Language, as_common<>>() == MAGIC_ENUM_RANGE_MAX);
|
||||
REQUIRE(magic_enum::detail::max_v<Language, as_common<>> == 50);
|
||||
}
|
||||
}
|
||||
|
||||
/* LanguageFlag tests */
|
||||
TEST_CASE("flag enum_cast") {
|
||||
SECTION("string") {
|
||||
constexpr auto lang = enum_cast<LanguageFlag>("日本語");
|
||||
REQUIRE(enum_cast<LanguageFlag&>("한국어").value() == LanguageFlag::한국어);
|
||||
REQUIRE(enum_cast<const LanguageFlag>("English").value() == LanguageFlag::English);
|
||||
REQUIRE(lang.value() == LanguageFlag::日本語);
|
||||
REQUIRE(enum_cast<LanguageFlag>("😃").value() == LanguageFlag::😃);
|
||||
REQUIRE_FALSE(enum_cast<LanguageFlag>("None").has_value());
|
||||
}
|
||||
|
||||
SECTION("integer") {
|
||||
constexpr auto lang = enum_cast<LanguageFlag>(1 << 1);
|
||||
REQUIRE(enum_cast<LanguageFlag&>(1 << 2).value() == LanguageFlag::한국어);
|
||||
REQUIRE(enum_cast<const LanguageFlag>(1 << 3).value() == LanguageFlag::English);
|
||||
REQUIRE(lang.value() == LanguageFlag::日本語);
|
||||
REQUIRE(enum_cast<LanguageFlag>(1 << 4).value() == LanguageFlag::😃);
|
||||
REQUIRE_FALSE(enum_cast<LanguageFlag>(0).has_value());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("flag enum_index") {
|
||||
constexpr auto lang = enum_index<LanguageFlag>(LanguageFlag::日本語);
|
||||
LanguageFlag korean = LanguageFlag::한국어;
|
||||
REQUIRE(enum_index<LanguageFlag&>(korean).value() == 1);
|
||||
REQUIRE(enum_index<const LanguageFlag>(LanguageFlag::English).value() == 2);
|
||||
REQUIRE(enum_index(LanguageFlag::😃).value() == 3);
|
||||
REQUIRE(lang.value() == 0);
|
||||
REQUIRE_FALSE(enum_index(static_cast<LanguageFlag>(0)).has_value());
|
||||
}
|
||||
|
||||
TEST_CASE("flag enum_contains") {
|
||||
SECTION("value") {
|
||||
constexpr auto lang = enum_index<LanguageFlag>(LanguageFlag::日本語);
|
||||
LanguageFlag korean = LanguageFlag::한국어;
|
||||
REQUIRE(enum_contains<LanguageFlag&>(korean));
|
||||
REQUIRE(enum_contains<const LanguageFlag>(LanguageFlag::English));
|
||||
REQUIRE(enum_contains(LanguageFlag::😃));
|
||||
REQUIRE(lang);
|
||||
REQUIRE_FALSE(enum_contains(static_cast<LanguageFlag>(0)));
|
||||
}
|
||||
|
||||
SECTION("integer") {
|
||||
constexpr auto lang = enum_contains<LanguageFlag&>(1 << 1);
|
||||
REQUIRE(lang);
|
||||
REQUIRE(enum_contains<const LanguageFlag>(1 << 2));
|
||||
REQUIRE(enum_contains<LanguageFlag>(1 << 3));
|
||||
REQUIRE(enum_contains<LanguageFlag>(1 << 4));
|
||||
REQUIRE_FALSE(enum_contains(static_cast<LanguageFlag>(0)));
|
||||
}
|
||||
|
||||
SECTION("string") {
|
||||
auto lang = std::string{"日本語"};
|
||||
REQUIRE(enum_contains<LanguageFlag&>("한국어"));
|
||||
REQUIRE(enum_contains<LanguageFlag>("English"));
|
||||
REQUIRE(enum_contains<const LanguageFlag>(lang));
|
||||
REQUIRE(enum_contains<LanguageFlag>("😃"));
|
||||
REQUIRE_FALSE(enum_contains<LanguageFlag>("None"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("flag enum_value") {
|
||||
constexpr auto lang = enum_value<LanguageFlag>(3);
|
||||
REQUIRE(enum_value<LanguageFlag&>(0) == LanguageFlag::日本語);
|
||||
REQUIRE(enum_value<const LanguageFlag>(1) == LanguageFlag::한국어);
|
||||
REQUIRE(enum_value<LanguageFlag>(2) == LanguageFlag::English);
|
||||
REQUIRE(lang == LanguageFlag::😃);
|
||||
}
|
||||
|
||||
TEST_CASE("flag enum_values") {
|
||||
constexpr auto& s5 = enum_values<const LanguageFlag>();
|
||||
REQUIRE(s5 == std::array<LanguageFlag, 4>{{LanguageFlag::日本語, LanguageFlag::한국어, LanguageFlag::English, LanguageFlag::😃}});
|
||||
}
|
||||
|
||||
TEST_CASE("flag enum_count") {
|
||||
constexpr auto s5 = enum_count<LanguageFlag>();
|
||||
REQUIRE(s5 == 4);
|
||||
}
|
||||
|
||||
TEST_CASE("flag enum_name") {
|
||||
SECTION("automatic storage") {
|
||||
constexpr LanguageFlag lang = LanguageFlag::日本語;
|
||||
constexpr auto lang_name = enum_name(lang);
|
||||
LanguageFlag lk = LanguageFlag::한국어;
|
||||
REQUIRE(enum_name<LanguageFlag&>(lk) == "한국어");
|
||||
REQUIRE(enum_name<const LanguageFlag>(LanguageFlag::English) == "English");
|
||||
REQUIRE(lang_name == "日本語");
|
||||
REQUIRE(enum_name(LanguageFlag::😃) == "😃");
|
||||
REQUIRE(enum_name(static_cast<LanguageFlag>(0)).empty());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("flag enum_flags_name") {
|
||||
constexpr LanguageFlag lang = LanguageFlag::日本語;
|
||||
auto lang_name = enum_flags_name(lang);
|
||||
LanguageFlag lk = LanguageFlag::한국어;
|
||||
REQUIRE(enum_flags_name<LanguageFlag&>(lk) == "한국어");
|
||||
REQUIRE(enum_flags_name<const LanguageFlag>(LanguageFlag::English) == "English");
|
||||
REQUIRE(lang_name == "日本語");
|
||||
REQUIRE(enum_flags_name(LanguageFlag::😃) == "😃");
|
||||
REQUIRE(enum_flags_name(static_cast<LanguageFlag>(0)).empty());
|
||||
}
|
||||
|
||||
TEST_CASE("flag enum_names") {
|
||||
constexpr auto& s5 = enum_names<const LanguageFlag>();
|
||||
REQUIRE(s5 == std::array<std::string_view, 4>{{"日本語", "한국어", "English", "😃"}});
|
||||
}
|
||||
|
||||
TEST_CASE("flag enum_entries") {
|
||||
constexpr auto& s5 = enum_entries<const LanguageFlag>();
|
||||
REQUIRE(s5 == std::array<std::pair<LanguageFlag, std::string_view>, 4>{{{LanguageFlag::日本語, "日本語"}, {LanguageFlag::한국어, "한국어"}, {LanguageFlag::English, "English"}, {LanguageFlag::😃, "😃"}}});
|
||||
}
|
||||
|
||||
TEST_CASE("flag ostream_operators") {
|
||||
auto test_ostream = [](auto e, std::string name) {
|
||||
using namespace magic_enum::ostream_operators;
|
||||
std::stringstream ss;
|
||||
ss << e;
|
||||
REQUIRE(ss.str() == name);
|
||||
};
|
||||
|
||||
test_ostream(std::make_optional(LanguageFlag::日本語), "日本語");
|
||||
test_ostream(LanguageFlag::한국어, "한국어");
|
||||
test_ostream(LanguageFlag::English, "English");
|
||||
test_ostream(LanguageFlag::😃, "😃");
|
||||
test_ostream(static_cast<LanguageFlag>(0), "0");
|
||||
test_ostream(std::make_optional(static_cast<LanguageFlag>(0)), "0");
|
||||
}
|
||||
|
||||
TEST_CASE("flag istream_operators") {
|
||||
auto test_istream = [](const auto e, std::string name) {
|
||||
using namespace magic_enum::istream_operators;
|
||||
std::istringstream ss(name);
|
||||
std::decay_t<decltype(e)> v;
|
||||
ss >> v;
|
||||
REQUIRE(v == e);
|
||||
REQUIRE(ss);
|
||||
};
|
||||
|
||||
test_istream(LanguageFlag::한국어, "한국어");
|
||||
test_istream(LanguageFlag::English, "English");
|
||||
test_istream(LanguageFlag::😃, "😃");
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("flag bitwise_operators") {
|
||||
using namespace magic_enum::bitwise_operators;
|
||||
SECTION("operator~") {
|
||||
REQUIRE(enum_integer(~LanguageFlag::日本語) == ~enum_integer(LanguageFlag::日本語));
|
||||
}
|
||||
|
||||
SECTION("operator|") {
|
||||
REQUIRE(enum_integer(LanguageFlag::日本語 | LanguageFlag::한국어) == (enum_integer(LanguageFlag::日本語) | enum_integer(LanguageFlag::한국어)));
|
||||
}
|
||||
|
||||
SECTION("operator&") {
|
||||
REQUIRE(enum_integer(LanguageFlag::日本語 & LanguageFlag::한국어) == (enum_integer(LanguageFlag::日本語) & enum_integer(LanguageFlag::한국어)));
|
||||
}
|
||||
|
||||
SECTION("operator^") {
|
||||
REQUIRE(enum_integer(LanguageFlag::日本語 ^ LanguageFlag::한국어) == (enum_integer(LanguageFlag::日本語) ^ enum_integer(LanguageFlag::한국어)));
|
||||
}
|
||||
|
||||
SECTION("operator|=") {
|
||||
LanguageFlag x5 = LanguageFlag::日本語;
|
||||
x5 |= LanguageFlag::한국어;
|
||||
REQUIRE(enum_integer(x5) == (enum_integer(LanguageFlag::日本語) | enum_integer(LanguageFlag::한국어)));
|
||||
}
|
||||
|
||||
SECTION("operator&=") {
|
||||
LanguageFlag x5 = LanguageFlag::日本語;
|
||||
x5 &= LanguageFlag::한국어;
|
||||
REQUIRE(enum_integer(x5) == (enum_integer(LanguageFlag::日本語) & enum_integer(LanguageFlag::한국어)));
|
||||
}
|
||||
|
||||
SECTION("operator^=") {
|
||||
LanguageFlag x5 = LanguageFlag::日本語;
|
||||
x5 ^= LanguageFlag::한국어;
|
||||
REQUIRE(enum_integer(x5) == (enum_integer(LanguageFlag::日本語) ^ enum_integer(LanguageFlag::한국어)));
|
||||
}
|
||||
}
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
|
||||
//
|
||||
// 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.
|
||||
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#define MAGIC_ENUM_USING_ALIAS_STRING_VIEW using string_view = std::wstring_view;
|
||||
#define MAGIC_ENUM_USING_ALIAS_STRING using string = std::wstring;
|
||||
#include <magic_enum/magic_enum.hpp>
|
||||
#include <magic_enum/magic_enum_iostream.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <cctype>
|
||||
#include <string_view>
|
||||
#include <sstream>
|
||||
|
||||
enum class Color { RED = -12, GREEN = 7, BLUE = 15 };
|
||||
template <>
|
||||
constexpr magic_enum::customize::customize_t magic_enum::customize::enum_name<Color>(Color value) noexcept {
|
||||
switch (value) {
|
||||
case Color::RED:
|
||||
return L"red";
|
||||
default:
|
||||
return default_tag;
|
||||
}
|
||||
}
|
||||
|
||||
using namespace magic_enum;
|
||||
|
||||
static_assert(is_magic_enum_supported, "magic_enum: Unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility).");
|
||||
|
||||
TEST_CASE("enum_cast") {
|
||||
SECTION("string") {
|
||||
constexpr auto cr = enum_cast<Color>(L"red");
|
||||
REQUIRE(cr.value() == Color::RED);
|
||||
REQUIRE(enum_cast<Color&>(L"GREEN").value() == Color::GREEN);
|
||||
REQUIRE(enum_cast<Color>(L"blue", [](wchar_t lhs, wchar_t rhs) { return std::tolower(lhs) == std::tolower(rhs); }).value() == Color::BLUE);
|
||||
REQUIRE_FALSE(enum_cast<Color>(L"None").has_value());
|
||||
}
|
||||
|
||||
SECTION("integer") {
|
||||
Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
|
||||
constexpr auto cr = enum_cast<Color>(-12);
|
||||
REQUIRE(cr.value() == Color::RED);
|
||||
REQUIRE(enum_cast<Color&>(7).value() == Color::GREEN);
|
||||
REQUIRE(enum_cast<Color>(static_cast<int>(cm[2])).value() == Color::BLUE);
|
||||
REQUIRE_FALSE(enum_cast<Color>(0).has_value());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("enum_values") {
|
||||
REQUIRE(std::is_same_v<decltype(enum_values<Color>()), const std::array<Color, 3>&>);
|
||||
|
||||
constexpr auto& s1 = enum_values<Color&>();
|
||||
REQUIRE(s1 == std::array<Color, 3>{{Color::RED, Color::GREEN, Color::BLUE}});
|
||||
}
|
||||
|
||||
TEST_CASE("enum_count") {
|
||||
constexpr auto s1 = enum_count<Color&>();
|
||||
REQUIRE(s1 == 3);
|
||||
}
|
||||
|
||||
TEST_CASE("enum_name") {
|
||||
SECTION("automatic storage") {
|
||||
constexpr Color cr = Color::RED;
|
||||
constexpr auto cr_name = enum_name(cr);
|
||||
Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
|
||||
Color cb = Color::BLUE;
|
||||
REQUIRE(cr_name == L"red");
|
||||
REQUIRE(enum_name<Color&>(cb) == L"BLUE");
|
||||
REQUIRE(enum_name<as_flags<false>>(cm[1]) == L"GREEN");
|
||||
REQUIRE(enum_name<as_common<true>>(cm[1]) == L"GREEN");
|
||||
REQUIRE(enum_name<as_flags<false>>(static_cast<Color>(0)).empty());
|
||||
}
|
||||
|
||||
SECTION("static storage") {
|
||||
constexpr Color cr = Color::RED;
|
||||
constexpr auto cr_name = enum_name<cr>();
|
||||
constexpr Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
|
||||
REQUIRE(cr_name == L"red");
|
||||
REQUIRE(enum_name<Color::BLUE>() == L"BLUE");
|
||||
REQUIRE(enum_name<cm[1]>() == L"GREEN");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("enum_names") {
|
||||
REQUIRE(std::is_same_v<decltype(enum_names<Color>()), const std::array<std::wstring_view, 3>&>);
|
||||
|
||||
constexpr auto& s1 = enum_names<Color&>();
|
||||
REQUIRE(s1 == std::array<std::wstring_view, 3>{{L"red", L"GREEN", L"BLUE"}});
|
||||
}
|
||||
|
||||
TEST_CASE("enum_entries") {
|
||||
REQUIRE(std::is_same_v<decltype(enum_entries<Color>()), const std::array<std::pair<Color, std::wstring_view>, 3>&>);
|
||||
|
||||
constexpr auto& s1 = enum_entries<Color&>();
|
||||
REQUIRE(s1 == std::array<std::pair<Color, std::wstring_view>, 3>{{{Color::RED, L"red"}, {Color::GREEN, L"GREEN"}, {Color::BLUE, L"BLUE"}}});
|
||||
}
|
||||
|
||||
TEST_CASE("ostream_operators") {
|
||||
auto test_ostream = [](auto e, std::wstring name) {
|
||||
using namespace magic_enum::ostream_operators;
|
||||
std::wstringstream ss;
|
||||
ss << e;
|
||||
REQUIRE(ss);
|
||||
REQUIRE(ss.str() == name);
|
||||
};
|
||||
|
||||
test_ostream(std::make_optional(Color::RED), L"red");
|
||||
test_ostream(Color::GREEN, L"GREEN");
|
||||
test_ostream(Color::BLUE, L"BLUE");
|
||||
test_ostream(static_cast<Color>(0), L"0");
|
||||
test_ostream(std::make_optional(static_cast<Color>(0)), L"0");
|
||||
}
|
||||
|
||||
TEST_CASE("istream_operators") {
|
||||
auto test_istream = [](const auto e, std::wstring name) {
|
||||
using namespace magic_enum::istream_operators;
|
||||
std::wistringstream ss(name);
|
||||
std::decay_t<decltype(e)> v;
|
||||
ss >> v;
|
||||
REQUIRE(ss);
|
||||
REQUIRE(v == e);
|
||||
};
|
||||
|
||||
test_istream(Color::GREEN, L"GREEN");
|
||||
test_istream(Color::BLUE, L"BLUE");
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
rm -rf ./build
|
||||
rm -rf ./build2
|
||||
rm -rf ./build3
|
||||
rm -rf ./install_dir/
|
||||
cmake -S . -B ./build -DCMAKE_BUILD_TYPE=Release --log-level=DEBUG -DCMAKE_INSTALL_PREFIX=install_dir
|
||||
cmake --build ./build -j$(nproc)
|
||||
cmake --install ./build/ --prefix ./install_dir
|
||||
CMAKE_PREFIX_PATH="./install_dir" cmake -S. -Bbuild2 -DMAGIC_ENUM_OPT_TEST_INSTALLED_VERSION=1 --log-level=DEBUG
|
||||
cmake --build build2 --config Debug -j$(nproc) --verbose
|
||||
CMAKE_PREFIX_PATH="./install_dir" cmake -S. -Bbuild3 -DMAGIC_ENUM_OPT_TEST_INSTALLED_VERSION_PKGCONFIG=1 --log-level=DEBUG
|
||||
cmake --build build3 --config Debug -j$(nproc) --verbose
|
||||
|
||||
Reference in New Issue
Block a user