If you are not redirected automatically, click here.
+
+
+ EOF
+
+ - name: Deploy redirect page
+ uses: peaceiris/actions-gh-pages@v4
+ with:
+ github_token: ${{ inputs.github_token }}
+ publish_dir: ${{ inputs.temp_dir }}
+ destination_dir: ${{ inputs.destination_dir }}
+ publish_branch: ${{ inputs.docs_branch }}
+ keep_files: true
diff --git a/.github/actions/update-version-selector/action.yaml b/.github/actions/update-version-selector/action.yaml
new file mode 100644
index 0000000..e48c9cf
--- /dev/null
+++ b/.github/actions/update-version-selector/action.yaml
@@ -0,0 +1,56 @@
+name: "update-version-selector"
+description: "Updates version selector"
+inputs:
+ github_token:
+ description: "GitHub token"
+ required: true
+ temp_dir:
+ description: "Directory where version selector file will be generated"
+ required: false
+ default: "selector-dir"
+ file_name:
+ description: "Selector file name"
+ required: false
+ default: "version_selector.html"
+ selector_id:
+ description: "select element id"
+ required: false
+ default: "versionSelector"
+ docs_branch:
+ description: "Documentation branch"
+ required: false
+ default: "gh-pages"
+outputs:
+ versions_counter:
+ description: "Number of existing versions"
+ value: ${{ steps.discover-versions.outputs.counter }}
+
+runs:
+ using: "composite"
+ steps:
+ - name: Discover versions
+ id: discover-versions
+ shell: bash
+ run: |
+ git fetch origin ${{ inputs.docs_branch }}
+ dirs=$(git ls-tree --name-only -d origin/${{ inputs.docs_branch }} | sort -rV)
+ echo "counter=$(echo "$dirs" | wc -l | xargs)" >> $GITHUB_OUTPUT
+
+ mkdir ${{ inputs.temp_dir }}
+ # Create HTML
+ echo '' >> ${{ inputs.temp_dir }}/${{ inputs.file_name }}
+
+ - name: Deploy version selector
+ uses: peaceiris/actions-gh-pages@v4
+ with:
+ github_token: ${{ inputs.github_token }}
+ publish_dir: ${{ inputs.temp_dir }}
+ publish_branch: ${{ inputs.docs_branch }}
+ keep_files: true
diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml
index 148cd98..8e54a12 100644
--- a/.github/workflows/c-cpp.yml
+++ b/.github/workflows/c-cpp.yml
@@ -2,11 +2,31 @@ name: C/C++ CI
on:
push:
- branches: [ "main" ]
+ branches: ["main"]
pull_request:
- branches: [ "main" ]
+ branches: ["main"]
jobs:
+ windows-build:
+ runs-on: windows-latest
+
+ strategy:
+ matrix:
+ cpp_standard: [11, 17, 20, 23]
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@main
+
+ - name: Set up MSVC and build
+ run: |
+ set PATH=%PATH%;C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSVC\14.29.30037\bin\Hostx64\x64
+ mkdir build
+ cd build
+ cmake -DCMAKE_CXX_STANDARD=${{ matrix.cpp_standard }} ..
+ cmake --build . --config Release
+ ctest -j2 --output-on-failure
+
build_linux:
runs-on: ubuntu-latest
defaults:
@@ -19,14 +39,32 @@ jobs:
- { compiler: gcc, version: 9, build_type: Release, cppstd: 11 }
- { compiler: gcc, version: 9, build_type: Release, cppstd: 14 }
- { compiler: gcc, version: 9, build_type: Release, cppstd: 17 }
- - { compiler: gcc, version: 11, build_type: Debug, cppstd: 20 }
+ - { compiler: gcc, version: 10, build_type: Debug, cppstd: 20 }
- { compiler: gcc, version: 12, build_type: Release, cppstd: 20 }
- { compiler: clang, version: 11, build_type: Release, cppstd: 11 }
- { compiler: clang, version: 11, build_type: Release, cppstd: 14 }
- { compiler: clang, version: 11, build_type: Release, cppstd: 17 }
- - { compiler: clang, version: 11, build_type: Debug, cppstd: 17, asan: OFF }
- - { compiler: clang, version: 12, build_type: Debug, cppstd: 17, asan: OFF }
- - { compiler: clang, version: 15, build_type: Release, cppstd: 20, asan: OFF }
+ - {
+ compiler: clang,
+ version: 11,
+ build_type: Debug,
+ cppstd: 17,
+ asan: OFF,
+ }
+ - {
+ compiler: clang,
+ version: 12,
+ build_type: Debug,
+ cppstd: 17,
+ asan: OFF,
+ }
+ - {
+ compiler: clang,
+ version: 15,
+ build_type: Release,
+ cppstd: 20,
+ asan: OFF,
+ }
container:
image: ${{ matrix.config.compiler == 'clang' && 'teeks99/clang-ubuntu' || matrix.config.compiler }}:${{ matrix.config.version }}
name: "${{ matrix.config.compiler}} ${{ matrix.config.version }} (C++${{ matrix.config.cppstd }}, ${{ matrix.config.build_type }})"
diff --git a/.github/workflows/create-git-main-docs.yml b/.github/workflows/create-git-main-docs.yml
new file mode 100644
index 0000000..ccdd865
--- /dev/null
+++ b/.github/workflows/create-git-main-docs.yml
@@ -0,0 +1,38 @@
+name: Create git-main docs
+
+permissions:
+ contents: write
+
+on:
+ push:
+ branches:
+ - main
+
+jobs:
+ create-git-main-docs:
+ runs-on: ubuntu-22.04
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Build docs
+ id: build-docs
+ uses: ./.github/actions/build-docs
+ with:
+ cmake_target: "doc"
+ docs_dir: "doc/docs"
+ destination_dir: git-main
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Update version selector
+ id: update-version-selector
+ uses: ./.github/actions/update-version-selector
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Create redirect page if there are no releases
+ if: ${{ steps.update-version-selector.outputs.versions_counter == 1}}
+ uses: ./.github/actions/update-redirect-page
+ with:
+ github_token: ${{ secrets.GITHUB_TOKEN }}
+ target_url: git-main/index.html
diff --git a/.github/workflows/trunk-check.yml b/.github/workflows/trunk-check.yml
new file mode 100644
index 0000000..3f831eb
--- /dev/null
+++ b/.github/workflows/trunk-check.yml
@@ -0,0 +1,24 @@
+name: Push
+on: [push, pull_request, workflow_dispatch]
+concurrency:
+ group: ${{ github.head_ref || github.run_id }}
+ cancel-in-progress: true
+
+permissions: read-all
+
+jobs:
+ trunk_check:
+ name: Trunk Check Runner
+ runs-on: ubuntu-latest
+ permissions:
+ checks: write # For trunk to post annotations
+ contents: read # For repo checkout
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Trunk Check
+ uses: trunk-io/trunk-action@v1
+ with:
+ check-mode: all
diff --git a/.trunk/.gitignore b/.trunk/.gitignore
new file mode 100644
index 0000000..15966d0
--- /dev/null
+++ b/.trunk/.gitignore
@@ -0,0 +1,9 @@
+*out
+*logs
+*actions
+*notifications
+*tools
+plugins
+user_trunk.yaml
+user.yaml
+tmp
diff --git a/.trunk/configs/.clang-tidy b/.trunk/configs/.clang-tidy
new file mode 100644
index 0000000..e4bd819
--- /dev/null
+++ b/.trunk/configs/.clang-tidy
@@ -0,0 +1,39 @@
+Checks: >-
+ bugprone-*,
+ cppcoreguidelines-*,
+ google-*,
+ misc-*,
+ modernize-*,
+ performance-*,
+ readability-*,
+ -bugprone-lambda-function-name,
+ -bugprone-reserved-identifier,
+ -cppcoreguidelines-avoid-goto,
+ -cppcoreguidelines-avoid-magic-numbers,
+ -cppcoreguidelines-avoid-non-const-global-variables,
+ -cppcoreguidelines-pro-bounds-array-to-pointer-decay,
+ -cppcoreguidelines-pro-type-vararg,
+ -google-readability-braces-around-statements,
+ -google-readability-function-size,
+ -misc-no-recursion,
+ -modernize-return-braced-init-list,
+ -modernize-use-nodiscard,
+ -modernize-use-trailing-return-type,
+ -performance-unnecessary-value-param,
+ -readability-magic-numbers,
+
+CheckOptions:
+ - key: readability-function-cognitive-complexity.Threshold
+ value: 100
+ - key: readability-function-cognitive-complexity.IgnoreMacros
+ value: true
+ # Set naming conventions for your style below (there are dozens of naming settings possible):
+ # See https://clang.llvm.org/extra/clang-tidy/checks/readability/identifier-naming.html
+ # - key: readability-identifier-naming.ClassCase
+ # value: CamelCase
+ # - key: readability-identifier-naming.NamespaceCase
+ # value: lower_case
+ # - key: readability-identifier-naming.PrivateMemberSuffix
+ # value: _
+ # - key: readability-identifier-naming.StructCase
+ # value: CamelCase
diff --git a/.trunk/configs/.markdownlint.yaml b/.trunk/configs/.markdownlint.yaml
new file mode 100644
index 0000000..b40ee9d
--- /dev/null
+++ b/.trunk/configs/.markdownlint.yaml
@@ -0,0 +1,2 @@
+# Prettier friendly markdownlint config (all formatting rules disabled)
+extends: markdownlint/style/prettier
diff --git a/.trunk/configs/.shellcheckrc b/.trunk/configs/.shellcheckrc
new file mode 100644
index 0000000..8c7b1ad
--- /dev/null
+++ b/.trunk/configs/.shellcheckrc
@@ -0,0 +1,7 @@
+enable=all
+source-path=SCRIPTDIR
+disable=SC2154
+
+# If you're having issues with shellcheck following source, disable the errors via:
+# disable=SC1090
+# disable=SC1091
diff --git a/.trunk/configs/.yamllint.yaml b/.trunk/configs/.yamllint.yaml
new file mode 100644
index 0000000..184e251
--- /dev/null
+++ b/.trunk/configs/.yamllint.yaml
@@ -0,0 +1,7 @@
+rules:
+ quoted-strings:
+ required: only-when-needed
+ extra-allowed: ["{|}"]
+ key-duplicates: {}
+ octal-values:
+ forbid-implicit-octal: true
diff --git a/.trunk/setup-ci/action.yaml b/.trunk/setup-ci/action.yaml
new file mode 100644
index 0000000..3843930
--- /dev/null
+++ b/.trunk/setup-ci/action.yaml
@@ -0,0 +1,11 @@
+name: Trunk Check setup
+description: Set up dependencies for Trunk Check
+runs:
+ using: composite
+ steps:
+ - name: Configure Project
+ uses: threeal/cmake-action@main
+ with:
+ run-build: false
+ generator: Unix Makefiles
+ options: CMAKE_EXPORT_COMPILE_COMMANDS=ON
diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml
new file mode 100644
index 0000000..802326d
--- /dev/null
+++ b/.trunk/trunk.yaml
@@ -0,0 +1,41 @@
+# This file controls the behavior of Trunk: https://docs.trunk.io/cli
+# To learn more about the format of this file, see https://docs.trunk.io/reference/trunk-yaml
+version: 0.1
+cli:
+ version: 1.22.1
+# Trunk provides extensibility via plugins. (https://docs.trunk.io/plugins)
+plugins:
+ sources:
+ - id: trunk
+ ref: v1.5.0
+ uri: https://github.com/trunk-io/plugins
+# Many linters and tools depend on runtimes - configure them here. (https://docs.trunk.io/runtimes)
+runtimes:
+ enabled:
+ - go@1.21.0
+ - node@18.12.1
+ - python@3.10.8
+# This is the section where you manage your linters. (https://docs.trunk.io/check/configuration)
+lint:
+ enabled:
+ - cmake-format@0.6.13
+ - clang-format@16.0.3
+ - clang-tidy@16.0.3
+ - actionlint@1.7.1
+ - checkov@3.2.128
+ - git-diff-check
+ - markdownlint@0.41.0
+ - prettier@3.3.1
+ - shellcheck@0.10.0
+ - shfmt@3.6.0
+ - trivy@0.52.0
+ - trufflehog@3.78.0
+ - yamllint@1.35.1
+
+actions:
+ disabled:
+ - trunk-announce
+ - trunk-check-pre-push
+ - trunk-fmt-pre-commit
+ enabled:
+ - trunk-upgrade-available
diff --git a/.vscode/settings.json b/.vscode/settings.json
index abcce64..6f51dfa 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,6 +1,16 @@
{
- "files.associations": {
- "cmath": "cpp",
- "string_view": "cpp"
- }
-}
\ No newline at end of file
+ "files.associations": {
+ "cmath": "cpp",
+ "string_view": "cpp",
+ "sstream": "cpp",
+ "optional": "cpp",
+ "memory": "cpp",
+ "random": "cpp",
+ "array": "cpp",
+ "fstream": "cpp",
+ "tuple": "cpp",
+ "type_traits": "cpp",
+ "system_error": "cpp"
+ },
+ "cmake.generator": "Unix Makefiles"
+}
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 10a4c73..f5d5878 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,20 +1,99 @@
cmake_minimum_required(VERSION 3.14)
-project(enum_name_example VERSION 0.1 LANGUAGES CXX)
-set(CMAKE_CXX_STANDARD 17)
+project(
+ enum_name
+ VERSION 1.0
+ LANGUAGES CXX)
-include(FetchContent)
+# Define the library
+add_library(enum_name INTERFACE)
+add_library(mgutility::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
-FetchContent_Declare(
- DocTest
- GIT_REPOSITORY "https://github.com/onqtam/doctest"
- GIT_TAG "v2.4.11"
-)
+# Specify the include directories for the library
+target_include_directories(
+ enum_name INTERFACE $
+ $)
-FetchContent_MakeAvailable(DocTest)
+# Set the C++ standard
+target_compile_features(enum_name INTERFACE cxx_std_11)
-add_executable(${PROJECT_NAME} example/main.cpp)
-target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR}/include)
+if(CMAKE_SYSTEM_NAME STREQUAL Linux)
+ include(GNUInstallDirs)
+ set(include_install_dir ${CMAKE_INSTALL_INCLUDEDIR})
+ set(config_install_dir "${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}")
+else()
+ set(include_install_dir "include")
+ set(config_install_dir "lib/cmake/${PROJECT_NAME}")
+endif()
-enable_testing()
-add_subdirectory(test)
\ No newline at end of file
+# Create the package configuration files
+include(CMakePackageConfigHelpers)
+
+write_basic_package_version_file(
+ "${CMAKE_CURRENT_BINARY_DIR}/enum_nameConfigVersion.cmake"
+ VERSION ${PROJECT_VERSION}
+ COMPATIBILITY AnyNewerVersion)
+
+configure_package_config_file(
+ ${CMAKE_CURRENT_LIST_DIR}/cmake/enum_nameConfig.cmake.in
+ "${CMAKE_CURRENT_BINARY_DIR}/enum_nameConfig.cmake"
+ INSTALL_DESTINATION lib/cmake/enum_name)
+
+if(NOT ${ENUM_NAME_NO_INSTALL})
+ # Install the library
+ install(
+ TARGETS enum_name
+ EXPORT enum_nameTargets
+ INCLUDES
+ DESTINATION include)
+
+ install(
+ EXPORT enum_nameTargets
+ FILE enum_nameTargets.cmake
+ NAMESPACE mgutility::
+ DESTINATION lib/cmake/enum_name)
+
+ install(DIRECTORY include/ DESTINATION include)
+
+ install(FILES "${CMAKE_CURRENT_BINARY_DIR}/enum_nameConfig.cmake"
+ "${CMAKE_CURRENT_BINARY_DIR}/enum_nameConfigVersion.cmake"
+ DESTINATION lib/cmake/enum_name)
+
+ export(
+ EXPORT enum_nameTargets
+ FILE "${CMAKE_CURRENT_BINARY_DIR}/enum_nameTargets.cmake"
+ NAMESPACE mgutility::)
+endif()
+
+# Add example executable
+add_executable(example_enum_name example/main.cpp)
+
+# Link the example executable with the library
+target_link_libraries(example_enum_name PRIVATE mgutility::enum_name)
+
+if(NOT ${ENUM_NAME_NO_TESTS})
+ # Enable testing
+ enable_testing()
+
+ # FetchContent to get the Doctest testing framework
+ include(FetchContent)
+ FetchContent_Declare(
+ doctest
+ GIT_REPOSITORY https://github.com/doctest/doctest.git
+ GIT_TAG v2.4.11)
+ FetchContent_MakeAvailable(doctest)
+
+ # Add test executable
+ add_executable(test_enum_name tests/test_enum_name.cpp)
+
+ # Link the test executable with the library and Doctest
+ target_link_libraries(test_enum_name PRIVATE mgutility::enum_name
+ doctest::doctest)
+
+ # Add tests
+ add_test(NAME test_enum_name COMMAND test_enum_name)
+endif()
+
+if(${ENUM_NAME_BUILD_DOCS})
+ add_subdirectory(doc)
+endif()
diff --git a/README.md b/README.md
index 523b10c..d161fdb 100644
--- a/README.md
+++ b/README.md
@@ -1,91 +1,144 @@
# enum_name
+
Converting (scoped)enum values to/from string names written in C++>=11.
## Supported Compilers
-* Clang > 5
-* GCC > 8
-* MSVC > 2015
+
+- Clang > 5
+- GCC > 8
+- MSVC > 2015
## Features
-* Supports `enum` and `enum class`
-* Supports enums in namespaces, classes or structs even templated or not
-* Supports compile-time as much as possible using with C++14 and later
-* Changing enum range with template parameter (default range: `[0, 256)`) on each call or with your special function for types or adding specialized `enum_range` struct
-* Supports and automatically overloaded `operator<<` for Enum types to direct using with ostream objects
-* Supports custom enum name output by explicit specialization of `constexpr inline auto mgutility::detail::enum_type::name() noexcept` function
-* Supports iterate over enum (names and values) with `mgutility::enum_for_each()` class and it is compatible with standard ranges and views
+
+- Supports `enum` and `enum class`
+- Supports enums in namespaces, classes or structs even templated or not
+- Supports full compile-time with C++20 and later
+- Changing enum range with template parameter (default range: `[0, 256)`) on each call or with your special function for types or adding specialized `enum_range` struct
+- Supports and automatically overloaded `operator<<` and add `std::formatter` specialization for Enum types to direct using with ostream objects and `std::format` (If `fmtlib` is available, simply adding the specialization like this [`template <> struct fmt::formatter : ostream_formatter {};`] is enough.)
+- Supports custom enum name(s) input/output by explicit specialization of `template <> struct mgutility::custom_enum` with `static constexpr mgutility::flat_map map{{Enum, const char*},...}` variable.
+- Supports bitmasked enums and auto detect them
+- Supports iterate over enum (names and values) with `mgutility::enum_for_each()` class and it is compatible with standard ranges and views
## Limitations
-* Compiler versions
-* Wider range can increase compile time so user responsible to adjusting for enum's range
+- Compiler versions
+- Wider range can increase compile time so user responsible to adjusting for enum's range
-## Usage ([try it!](https://godbolt.org/z/YM5EvY1Y5))
-```C++
-#include
-#include "enum_name.hpp"
+## Fetch library with CMake
-num class rgb_color { red, green, blue, unknown = -1 };
+```CMake
+include(FetchContent)
-// specialize rgb_color::unknown to make output "UNKNOWN" instead of "unknown"
-template <>
-constexpr auto mgutility::detail::enum_type::name() noexcept
- -> string_view {
- return "UNKNOWN";
-}
+FetchContent_Declare(
+ enum_name
+ GIT_REPOSITORY https://github.com/mguludag/enum_name.git
+ GIT_TAG main # or the specific tag or branch you want to use
+)
-// you can specialize enum ranges with overload per enum types (option 1)
-template <>
-struct mgutility::enum_range {
- static constexpr auto min = -1;
- static constexpr auto max = 3;
-};
+FetchContent_MakeAvailable(enum_name)
-// you can specialize enum ranges with overload per enum types (option 2)
-auto enum_name = [](rgb_color c) { return mgutility::enum_name<-1, 3>(c); };
+#...
+
+target_link_libraries(${PROJECT_NAME} PRIVATE mgutility::enum_name)
+```
+
+## Example usage ([try it!](https://godbolt.org/z/5Ye185MWa))
+
+```C++
+#include
+
+#include "mgutility/reflection/enum_name.hpp"
#if defined(__cpp_lib_print)
#include
#include
#endif
+enum class Position {
+ Top = 1 << 0,
+ Right = 1 << 1,
+ Bottom = 1 << 2,
+ Left = 1 << 3
+};
+
+// Define bitwise OR operator for Position
+auto constexpr operator|(Position lhs, Position rhs) -> Position {
+ return static_cast(mgutility::enum_to_underlying(lhs) |
+ mgutility::enum_to_underlying(rhs));
+}
+
+// Define bitwise AND operator for Position
+auto constexpr operator&(Position lhs, Position rhs) -> Position {
+ return static_cast(mgutility::enum_to_underlying(lhs) &
+ mgutility::enum_to_underlying(rhs));
+}
+
+// Define the range for Position enum values (Option 1)
+template <>
+struct mgutility::enum_range {
+ static constexpr auto min = 0; // Minimum value
+ static constexpr auto max = 16; // Maximum value
+};
+
+// Specialize individual or all enum names
+template <>
+struct mgutility::custom_enum {
+ static constexpr mgutility::flat_map map{
+ {Position::Top, "TOP"},
+ {Position::Right, "RIGHT"},
+ {Position::Bottom, "BOTTOM"},
+ {Position::Left, "LEFT"},
+ {Position::Top | Position::Right | Position::Bottom | Position::Left,
+ "CENTER"}};
+};
int main() {
- auto x = rgb_color::blue;
- auto y = mgutility::to_enum("greenn");
+
+ // Specify enum range when call enum_name function (Option 2)
+ // Lambda function to get enum name
+ auto enum_name = [](Position c) { return mgutility::enum_name<0, 16>(c); };
+
+ auto x = Position::Left;
+ auto y = mgutility::to_enum("CENTER"); // Convert string to enum
+
+#if defined(__cpp_lib_constexpr_string)
+ static_assert(mgutility::enum_name(Position::Top | Position::Right) ==
+ "TOP|RIGHT"); // Compile-time check
+ static_assert(mgutility::to_enum("BOTTOM|LEFT") ==
+ (Position::Bottom | Position::Left)); // Compile-time check
+#endif
#if defined(__cpp_lib_print)
-// enum_for_each can usable with views and range algorithms
-auto colors = mgutility::enum_for_each() |
- std::ranges::views::filter(
- [](auto &&pair) { return pair.second != "UNKNOWN"; });
+ // Print each Position and its underlying value using ranges
+ auto positions =
+ mgutility::enum_for_each() |
+ std::ranges::views::filter([](auto &&pair) {
+ return !pair.second.empty() &&
+ pair.second.find('|') == mgutility::string_view::npos;
+ });
- std::ranges::for_each(colors, [](auto &&color) {
- std::println("{} \t: {}", color.second, mgutility::enum_to_underlying(color.first));
- });
+ std::ranges::for_each(positions, [](auto &&pos) {
+ std::println("{} \t: {}", mgutility::enum_to_underlying(pos.first),
+ pos.second);
+ });
#else
- for (auto&& e : mgutility::enum_for_each()) {
- if(e.second != "UNKNOWN"){
- std::cout << e.second << " \t: " << mgutility::enum_to_underlying(e.first) << '\n';
- }
- // std::pair {enum_type, name_of_enum}
+ // Print each Position and its underlying value using a for loop
+ for (auto &&e : mgutility::enum_for_each()) {
+ if (!e.second.empty() &&
+ e.second.find('|') == mgutility::string_view::npos) {
+ std::cout << mgutility::enum_to_underlying(e.first) << " \t: " << e.second
+ << '\n';
}
+ }
#endif
- // default signature: enum_name(Enum&&) Changing max_value to not too much greater than enum's
- // max value, it will compiles faster
- std::cout << mgutility::enum_name(x) << '\n'; // will print "blue" to output
- // or
- std::cout << x << '\n'; // will print "blue" to output
-
- // calling specialized enum ranges function for rgb_color type
- // will print "green" to output, if y can't convert to rgb_color prints
- // "UNKNOWN"
- std::cout << enum_name(y.value_or(rgb_color::unknown)) << '\n';
-}
+ // Print the value of x
+ std::cout << '\n' << x << '\n';
+ // Print the name of y or "TOP" if y is not valid
+ std::cout << y.value_or(Position::Top) << '\n';
+}
```
diff --git a/cmake/enum_nameConfig.cmake.in b/cmake/enum_nameConfig.cmake.in
new file mode 100644
index 0000000..5fbea33
--- /dev/null
+++ b/cmake/enum_nameConfig.cmake.in
@@ -0,0 +1,3 @@
+@PACKAGE_INIT@
+
+include("${CMAKE_CURRENT_LIST_DIR}/enum_nameTargets.cmake")
\ No newline at end of file
diff --git a/doc/CMakeLists.txt b/doc/CMakeLists.txt
new file mode 100644
index 0000000..f56bb54
--- /dev/null
+++ b/doc/CMakeLists.txt
@@ -0,0 +1,11 @@
+find_package(Doxygen REQUIRED)
+
+configure_file("main.md.in" "main.md" @ONLY)
+
+set(DOXYGEN_HTML_OUTPUT "${PROJECT_VERSION}")
+set(DOXYGEN_OUTPUT_DIRECTORY "docs")
+set(DOXYGEN_HTML_HEADER "header.html")
+set(DOXYGEN_HTML_EXTRA_FILES "version_selector_handler.js")
+set(DOXYGEN_USE_MDFILE_AS_MAINPAGE "${CMAKE_CURRENT_BINARY_DIR}/main.md")
+
+doxygen_add_docs(doc "${PROJECT_SOURCE_DIR}")
diff --git a/doc/header.html b/doc/header.html
new file mode 100644
index 0000000..6d97b6e
--- /dev/null
+++ b/doc/header.html
@@ -0,0 +1,102 @@
+
+
+
+
+
+
+
+
+
+ $projectname: $title
+
+
+ $title
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $treeview $search $mathjax $darkmode
+
+ $extrastylesheet
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $projectname
+
+
+
+
$projectbrief
+
+
+
+
+
+
+
$projectbrief
+
+
+
+
+
+
+
$searchbox
+
+
+
+
+
+
+
+
$searchbox
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc/main.md.in b/doc/main.md.in
new file mode 100644
index 0000000..8b5b604
--- /dev/null
+++ b/doc/main.md.in
@@ -0,0 +1,5 @@
+# Main page
+
+Converting (scoped)enum values to string names written in C++>=11
+
+Version: @PROJECT_VERSION@
\ No newline at end of file
diff --git a/doc/version_selector_handler.js b/doc/version_selector_handler.js
new file mode 100644
index 0000000..1f54973
--- /dev/null
+++ b/doc/version_selector_handler.js
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: MIT
+// Copyright (c) 2024, Oleksandr Koval
+
+$(function () {
+ var repoName = window.location.pathname.split("/")[1];
+ $.get("/" + repoName + "/version_selector.html", function (data) {
+ // Inject version selector HTML into the page
+ $("#projectnumber").html(data);
+
+ // Event listener to handle version selection
+ document
+ .getElementById("versionSelector")
+ .addEventListener("change", function () {
+ var selectedVersion = this.value;
+ window.location.href =
+ "/" + repoName + "/" + selectedVersion + "/index.html";
+ });
+
+ // Set the selected option based on the current version
+ var currentVersion = window.location.pathname.split("/")[2];
+ $("#versionSelector").val(currentVersion);
+ });
+});
diff --git a/example/main.cpp b/example/main.cpp
index 4f0b051..979c069 100644
--- a/example/main.cpp
+++ b/example/main.cpp
@@ -1,33 +1,94 @@
#include
-#include "enum_name.hpp"
+#include "mgutility/reflection/enum_name.hpp"
-enum class rgb_color { red, green, blue, unknown = -1};
+#if defined(__cpp_lib_print)
+#include
+#include
+#endif
-// you can specialize enum ranges with specialize struct per enum types (option 1)
-namespace mgutility{
- template<>
- struct enum_range
- {
- static constexpr auto min = -1;
- static constexpr auto max = 3;
- };
+enum class Position {
+ Top = 1 << 0,
+ Right = 1 << 1,
+ Bottom = 1 << 2,
+ Left = 1 << 3
+};
+
+// Define bitwise OR operator for Position
+auto constexpr operator|(Position lhs, Position rhs) -> Position {
+ return static_cast(mgutility::enum_to_underlying(lhs) |
+ mgutility::enum_to_underlying(rhs));
+}
+
+// Define bitwise AND operator for Position
+auto constexpr operator&(Position lhs, Position rhs) -> Position {
+ return static_cast(mgutility::enum_to_underlying(lhs) &
+ mgutility::enum_to_underlying(rhs));
}
-// you can specialize enum ranges with overload per enum types (option 2)
-auto enum_name = [](rgb_color c){ return mgutility::enum_name<-1, 3>(c); };
-
-
-int main()
-{
- auto x = rgb_color::blue;
- auto y = mgutility::to_enum("green");
-
- // default signature: enum_name(Enum&&)
- // Changing max_value to not too much greater than enum's max value, it will compiles faster
- std::cout << mgutility::enum_name(x) << '\n'; // will print "blue" to output
-
- // calling specialized enum ranges function for rgb_color type
- // will print "green" to output, if y can't convert to rgb_color prints "unknown"
- std::cout << enum_name(y.value_or(rgb_color::unknown)) << '\n';
+// Define the range for Position enum values (Option 1)
+template <> struct mgutility::enum_range {
+ static constexpr auto min = 0; // Minimum value
+ static constexpr auto max = 16; // Maximum value
+};
+
+// Specialize individual or all enum names
+template <> struct mgutility::custom_enum {
+ static constexpr mgutility::flat_map map{
+ {Position::Top, "TOP"},
+ {Position::Right, "RIGHT"},
+ {Position::Bottom, "BOTTOM"},
+ {Position::Left, "LEFT"},
+ {Position::Top | Position::Right | Position::Bottom | Position::Left,
+ "CENTER"}};
+};
+
+int main() {
+
+ // Specify enum range when call enum_name function (Option 2)
+ // Lambda function to get enum name
+ auto enum_name = [](Position c) { return mgutility::enum_name<0, 16>(c); };
+
+ auto x = Position::Left;
+ auto y = mgutility::to_enum("CENTER"); // Convert string to enum
+
+#if defined(__cpp_lib_constexpr_string) && defined(__GNUC__) && !defined(__clang__) && __GNUC__ > 11
+ static_assert(mgutility::enum_name(Position::Top | Position::Right) ==
+ "TOP|RIGHT"); // Compile-time check
+ static_assert(mgutility::to_enum("BOTTOM|LEFT") ==
+ (Position::Bottom | Position::Left)); // Compile-time check
+#endif
+
+#if defined(__cpp_lib_print)
+
+ // Print each Position and its underlying value using ranges
+ auto positions =
+ mgutility::enum_for_each() |
+ std::ranges::views::filter([](auto &&pair) {
+ return !pair.second.empty() &&
+ pair.second.find('|') == mgutility::string_view::npos;
+ });
+
+ std::ranges::for_each(positions, [](auto &&pos) {
+ std::println("{} \t: {}", mgutility::enum_to_underlying(pos.first),
+ pos.second);
+ });
+
+#else
+
+ // Print each Position and its underlying value using a for loop
+ for (auto &&e : mgutility::enum_for_each()) {
+ if (!e.second.empty() &&
+ e.second.find('|') == mgutility::string_view::npos) {
+ std::cout << mgutility::enum_to_underlying(e.first) << " \t: " << e.second
+ << '\n';
+ }
+ }
+#endif
+
+ // Print the value of x
+ std::cout << '\n' << x << '\n';
+
+ // Print the name of y or "TOP" if y is not valid
+ std::cout << y.value_or(Position::Top) << '\n';
}
\ No newline at end of file
diff --git a/include/enum_name.hpp b/include/enum_name.hpp
deleted file mode 100644
index c7ed6ab..0000000
--- a/include/enum_name.hpp
+++ /dev/null
@@ -1,504 +0,0 @@
-/*
- * MIT License
- *
- * Copyright (c) 2023 Muhammed Galib Uludag
- *
- * 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 MGUTILITY_ENUM_NAME_HPP
-#define MGUTILITY_ENUM_NAME_HPP
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#if defined(_MSC_VER) && _MSC_VER < 1910
-#error "Requires MSVC 2017 or newer!"
-#elif defined(__clang__) && __clang_major__ < 6
-#error "Requires clang 6 or newer!"
-#elif defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 9
-#error "Requires gcc 9 or newer!"
-#elif !defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__)
-#error "Your compiler is not supported!"
-#endif
-
-#ifdef _MSC_VER
-#define MG_ENUM_NAME_CPLUSPLUS _MSVC_LANG
-#else
-#define MG_ENUM_NAME_CPLUSPLUS __cplusplus
-#endif
-
-#if MG_ENUM_NAME_CPLUSPLUS == 201103L
-#define MG_ENUM_NAME_CNSTXPR
-#elif MG_ENUM_NAME_CPLUSPLUS > 201103L
-#define MG_ENUM_NAME_CNSTXPR constexpr
-#elif MG_ENUM_NAME_CPLUSPLUS < 201103L
-#error "Standards older than C++11 is not supported!"
-#endif
-
-#if MG_ENUM_NAME_CPLUSPLUS > 201702L
-#include
-#endif
-
-namespace mgutility {
-namespace detail {
-
-template
-struct is_scoped_enum {
- static constexpr auto value =
- std::is_enum::value &&
- !std::is_convertible::type>::value;
-};
-#if MG_ENUM_NAME_CPLUSPLUS > 201103L
-template
-static constexpr bool is_scoped_enum_v = is_scoped_enum::value;
-#endif
-
-template
-using underlying_type_t = typename std::underlying_type::type;
-
-template
-using remove_const_t = typename std::remove_const::type;
-
-#if MG_ENUM_NAME_CPLUSPLUS < 201703L
-
-template
-using enable_if_t = typename std::enable_if::type;
-
-constexpr auto strlen_constexpr(const char* str,
- size_t sz = 0) noexcept -> size_t {
- return str[sz] == '\0' ? sz : strlen_constexpr(str, ++sz);
-}
-
-template
-class basic_string_view {
- public:
- constexpr inline basic_string_view() noexcept : data_(""), size_(0) {}
- constexpr inline basic_string_view(const Char* str) noexcept
- : data_(str), size_(strlen_constexpr(str)) {}
- constexpr inline basic_string_view(const Char* str, size_t len) noexcept
- : data_(str), size_(len) {}
- constexpr inline basic_string_view(const basic_string_view& other)
- : data_(other.data_), size_(other.size_) {}
- constexpr inline basic_string_view(basic_string_view&& other) noexcept
- : data_(std::move(other.data_)), size_(std::move(other.size_)) {}
- MG_ENUM_NAME_CNSTXPR inline basic_string_view& operator=(
- const basic_string_view& other) noexcept {
- data_ = other.data_;
- size_ = other.size_;
- return *this;
- }
- MG_ENUM_NAME_CNSTXPR inline basic_string_view& operator=(
- basic_string_view&& other) noexcept {
- data_ = std::move(other.data_);
- size_ = std::move(other.size_);
- return *this;
- }
- constexpr inline const Char operator[](size_t index) const noexcept {
- return data_[index];
- }
- constexpr inline const Char* begin() const noexcept { return data_; }
- constexpr inline const Char* end() const noexcept {
- return (data_ + size_);
- }
- constexpr inline bool empty() const noexcept { return size_ < 1; }
- constexpr inline size_t size() const noexcept { return size_; }
- constexpr inline const Char* data() const noexcept { return data_; }
- constexpr inline basic_string_view substr(size_t begin,
- size_t len) const noexcept {
- return basic_string_view(data_ + begin, len);
- }
- constexpr inline size_t rfind(Char c, size_t pos = 0) const noexcept {
- return c == data_[pos] ? pos : rfind(c, --pos);
- }
-
- constexpr friend inline bool operator==(
- basic_string_view lhs, basic_string_view rhs) noexcept {
- return (lhs.size_ == rhs.size_) &&
- std::strncmp(lhs.data_, rhs.data_, lhs.size_) == 0;
- }
-
- constexpr friend inline bool operator==(basic_string_view lhs,
- const Char* rhs) noexcept {
- return (lhs.size_ == strlen_constexpr(rhs)) &&
- std::strncmp(lhs.data_, rhs, lhs.size_) == 0;
- }
-
- constexpr friend inline bool operator!=(
- basic_string_view lhs, basic_string_view rhs) noexcept {
- return !(lhs == rhs);
- }
-
- constexpr friend inline bool operator!=(basic_string_view lhs,
- const Char* rhs) noexcept {
- return !(lhs == rhs);
- }
-
- inline operator std::string() { return std::string(data_, size_); }
- inline operator std::string() const { return std::string(data_, size_); }
-
- friend inline std::ostream& operator<<(std::ostream& os,
- const basic_string_view& sv) {
- for (auto c : sv) {
- os << c;
- }
- return os;
- }
-
- private:
- size_t size_;
- const Char* data_;
-};
-
-using string_view = basic_string_view;
-
-struct bad_optional_access : public std::exception {
- const char* what() const noexcept { return "optional has no value"; }
-};
-
-struct nullopt_t;
-
-template
-class optional {
- public:
- MG_ENUM_NAME_CNSTXPR inline optional(nullopt_t&)
- : dummy_{0}, has_value_{false} {}
- MG_ENUM_NAME_CNSTXPR inline optional() : dummy_{0}, has_value_{false} {}
- template
- MG_ENUM_NAME_CNSTXPR inline optional(Args&&... args)
- : value_{T{std::forward(args)...}}, has_value_{true} {}
- MG_ENUM_NAME_CNSTXPR inline optional(T&& value)
- : value_{value}, has_value_{true} {}
- MG_ENUM_NAME_CNSTXPR inline optional(const optional& other)
- : value_{other.value_}, has_value_{other.has_value_} {}
- MG_ENUM_NAME_CNSTXPR inline optional(optional&& other)
- : value_{other.value_}, has_value_{other.has_value_} {
- other.reset();
- }
- inline ~optional() { has_value_ = false; }
- MG_ENUM_NAME_CNSTXPR inline optional& operator=(const optional& other) {
- value_ = other.value_;
- has_value_ = other.has_value_;
- return *this;
- }
- MG_ENUM_NAME_CNSTXPR inline optional& operator=(optional&& other) {
- value_ = other.value_;
- has_value_ = other.has_value_;
- other.reset();
- return *this;
- }
- MG_ENUM_NAME_CNSTXPR inline void swap(optional&& other) {
- auto val = std::move(other.value_);
- other.value_ = std::move(value_);
- value_ = std::move(val);
-
- auto hval = std::move(other.has_value_);
- other.has_value_ = std::move(has_value_);
- has_value_ = std::move(hval);
- }
- MG_ENUM_NAME_CNSTXPR inline T& operator*() { return value_; }
- MG_ENUM_NAME_CNSTXPR inline T& operator*() const { return value_; }
- MG_ENUM_NAME_CNSTXPR inline T& value() {
- if (!has_value_) throw detail::bad_optional_access();
- return value_;
- }
- MG_ENUM_NAME_CNSTXPR inline T& value() const {
- if (!has_value_) throw detail::bad_optional_access();
- return value_;
- }
- MG_ENUM_NAME_CNSTXPR inline T value_or(T&& value) {
- return has_value_ ? value_ : value;
- }
- MG_ENUM_NAME_CNSTXPR inline T value_or(T&& value) const {
- return has_value_ ? value_ : value;
- }
- MG_ENUM_NAME_CNSTXPR inline T value_or(const T& value) {
- return has_value_ ? value_ : value;
- }
- MG_ENUM_NAME_CNSTXPR inline T value_or(const T& value) const {
- return has_value_ ? value_ : value;
- }
- MG_ENUM_NAME_CNSTXPR inline void emplace(T value) {
- value_ = std::move(value);
- has_value_ = true;
- }
- template
- MG_ENUM_NAME_CNSTXPR inline void emplace(Args&&... args) {
- value_ = std::move(T{std::forward(args)...});
- has_value_ = true;
- }
- MG_ENUM_NAME_CNSTXPR inline bool has_value() const { return has_value_; }
-
-#if !(defined(__clang__) && __clang_major__ < 11)
- template ::value, bool> = true>
- MG_ENUM_NAME_CNSTXPR inline void reset() {
- T::~T();
- has_value_ = false;
- }
-#endif
- template ::value, bool> = true>
- MG_ENUM_NAME_CNSTXPR inline void reset() {
- value_ = T{};
- has_value_ = false;
- }
-
- MG_ENUM_NAME_CNSTXPR operator bool() { return has_value_; }
-
- private:
- union {
- T value_;
- char dummy_[sizeof(T)];
- };
- bool has_value_;
-};
-
-struct nullopt_t {
- template
- MG_ENUM_NAME_CNSTXPR operator optional() {
- return optional{};
- }
-};
-
-auto nullopt = nullopt_t{};
-
-#else
-
-template
-using optional = std::optional;
-inline constexpr auto nullopt{std::nullopt};
-using string_view = std::string_view;
-template
-using enable_if_t = std::enable_if_t;
-
-#endif
-
-template
-struct enum_sequence {};
-
-template
-struct enum_sequence_helper
- : enum_sequence_helper {};
-
-template
-struct enum_sequence_helper {
- using type = enum_sequence(Next)...>;
-};
-
-template
-using make_enum_sequence = typename enum_sequence_helper::type;
-
-struct enum_type {
-#if defined(_MSC_VER)
-#define __PRETTY_FUNCTION__ __FUNCSIG__
-#endif
- template <
- typename Enum, Enum e,
- detail::enable_if_t::value, bool> = true>
- MG_ENUM_NAME_CNSTXPR static inline auto name() noexcept
- -> detail::string_view {
- auto str = detail::string_view(__PRETTY_FUNCTION__);
- auto offset{lastidxenumname[0] + lastidxenumname[1]};
- auto index =
- std::max(str.rfind(lastidxenumname[2], str.size() - offset),
- str.rfind(lastidxenumname[3], str.size() - offset));
- auto result = str.substr(index + 1, str.size() - offset - index);
- return result[0] == '(' ? "" : result;
- }
-
- template <
- typename Enum, Enum e,
- detail::enable_if_t::value, bool> = true>
- MG_ENUM_NAME_CNSTXPR static inline auto name() noexcept
- -> detail::string_view {
- auto str = detail::string_view(__PRETTY_FUNCTION__);
- auto index =
- str.rfind(lastidxenumname[3], str.size() - lastidxenumname[0]) + 1;
- auto result =
- str.substr(index, str.size() - lastidxenumname[0] - index);
- return result.size() > 4 ? result[4] == lastidxenumname[4] ? "" : result
- : result;
- }
-
- private:
- static constexpr int lastidxenumname[] =
-#if defined(_MSC_VER)
- {22, 0, ',', ':', '<'};
-#elif defined(__clang__)
- {1, 1, ' ', ':', '('};
-#elif defined(__GNUC__)
- {
-#if MG_ENUM_NAME_CPLUSPLUS < 201703L
- 179,
-#else
- 165,
-#endif
- 5, ' ', ':', '('};
-#endif
-};
-
-template
-using enum_pair = std::pair;
-
-template
-inline auto get_enum_array(detail::enum_sequence) noexcept
- -> std::array {
- static std::array
- arr{"", enum_type::template name()...};
- return arr;
-}
-
-template
-inline auto to_enum_impl(detail::string_view str) noexcept
- -> detail::optional {
- auto arr = get_enum_array(detail::make_enum_sequence());
- const auto index{std::find(arr.begin() + 1, arr.end(), str)};
- return index == arr.end()
- ? detail::nullopt
- : detail::optional{static_cast(
- std::distance(arr.begin(), index) + Min - 1)};
-}
-
-template
-inline auto enum_name_impl(Enum e) noexcept -> detail::string_view {
- auto arr = get_enum_array(detail::make_enum_sequence());
- const auto index{std::abs(Min) + static_cast(e) + (Min < 0 ? 1 : 1)};
- return arr[(index < Min || index > arr.size() - 1) ? 0 : index];
-}
-} // namespace detail
-} // namespace mgutility
-
-namespace mgutility {
-template
-struct enum_range {
- static constexpr auto min{-128};
- static constexpr auto max{128};
-};
-
-template
-class enum_for_each {
- using value_type = const detail::enum_pair;
- using size_type = std::size_t;
-
- struct enum_iter {
- using const_iter_type = decltype(enum_range::min);
- using iter_type = detail::remove_const_t;
- using iterator_category = std::forward_iterator_tag;
- using value_type = const detail::enum_pair;
- using difference_type = std::ptrdiff_t;
- using pointer = value_type*;
- using reference = value_type&;
-
- enum_iter() : m_pos{} {}
- enum_iter(iter_type value) : m_pos{value} {}
-
- auto operator++() -> enum_iter& {
- ++m_pos;
- return *this;
- }
-
- auto operator++(int) -> enum_iter {
- m_pos++;
- return *this;
- }
-
- auto operator!=(const enum_iter& other) const -> bool {
- return m_pos != other.m_pos;
- }
-
- auto operator==(const enum_iter& other) const -> bool {
- return m_pos == other.m_pos;
- }
-
- auto operator*() const -> value_type;
-
- private:
- iter_type m_pos;
- };
-
- public:
- enum_for_each() {}
- auto begin() -> enum_iter& { return m_begin; }
- auto end() -> enum_iter& { return m_end; }
- auto size() -> std::size_t {
- return enum_range::max - enum_range::min;
- }
-
- private:
- enum_iter m_begin{enum_range::min};
- enum_iter m_end{enum_range::max};
-};
-
-template
-constexpr inline auto enum_to_underlying(Enum e) noexcept
- -> detail::underlying_type_t {
- static_assert(std::is_enum::value, "Value is not an Enum type!");
- return static_cast>(e);
-}
-
-template
-MG_ENUM_NAME_CNSTXPR inline auto enum_name(Enum e) noexcept
- -> detail::string_view {
- static_assert(Min < Max - 1, "Max must be greater than (Min + 1)!");
- static_assert(std::is_enum::value, "Value is not an Enum type!");
- return detail::enum_name_impl(e);
-}
-
-template ::min,
- int Max = enum_range::max>
-MG_ENUM_NAME_CNSTXPR inline auto enum_name(Enum e) noexcept
- -> detail::string_view {
- static_assert(Min < Max - 1, "Max must be greater than (Min + 1)!");
- static_assert(std::is_enum::value, "Value is not an Enum type!");
- return detail::enum_name_impl(e);
-}
-
-template
-auto enum_for_each::enum_iter::operator*() const -> value_type {
- auto value = static_cast(m_pos);
- return detail::enum_pair{value, enum_name(value)};
-}
-
-template ::min,
- int Max = enum_range::max>
-MG_ENUM_NAME_CNSTXPR inline auto to_enum(detail::string_view str) noexcept
- -> detail::optional {
- static_assert(Min < Max - 1, "Max must be greater than (Min + 1)!");
- static_assert(std::is_enum::value, "Type is not an Enum type!");
- return detail::to_enum_impl(str);
-}
-} // namespace mgutility
-
-template ::value, bool>::type = true>
-auto operator<<(std::ostream& os, Enum e) -> std::ostream& {
- static_assert(std::is_enum::value, "Value is not an Enum type!");
- os << mgutility::enum_name(e);
- return os;
-}
-
-#endif // MGUTILITY_ENUM_NAME_HPP
diff --git a/include/mgutility/_common/definitions.hpp b/include/mgutility/_common/definitions.hpp
new file mode 100644
index 0000000..cfa242d
--- /dev/null
+++ b/include/mgutility/_common/definitions.hpp
@@ -0,0 +1,86 @@
+/*
+MIT License
+
+Copyright (c) 2024 mguludag
+
+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 MGUTILITY_COMMON_DEFINITIONS_HPP
+#define MGUTILITY_COMMON_DEFINITIONS_HPP
+
+/**
+ * @file definitions.hpp
+ * @brief Defines macros for compiler and standard support detection.
+ */
+
+/**
+ * @brief Defines the MGUTILITY_CPLUSPLUS macro for MSVC and other compilers.
+ *
+ * For MSVC, it uses _MSVC_LANG. For other compilers, it uses __cplusplus.
+ */
+#ifdef _MSC_VER
+#define MGUTILITY_CPLUSPLUS _MSVC_LANG
+#else
+#define MGUTILITY_CPLUSPLUS __cplusplus
+#endif
+
+/**
+ * @brief Defines the MGUTILITY_CNSTXPR macro based on the C++ standard.
+ *
+ * If the C++ standard is C++11, MGUTILITY_CNSTXPR is defined as empty.
+ * If the C++ standard is newer than C++11, MGUTILITY_CNSTXPR is defined as
+ * constexpr. If the C++ standard is older than C++11, an error is raised.
+ */
+#if MGUTILITY_CPLUSPLUS == 201103L
+#define MGUTILITY_CNSTXPR
+#elif MGUTILITY_CPLUSPLUS > 201103L
+#define MGUTILITY_CNSTXPR constexpr
+#elif MGUTILITY_CPLUSPLUS < 201103L
+#error "Standards older than C++11 is not supported!"
+#endif
+
+/**
+ * @brief Defines the MGUTILITY_CNSTXPR_CLANG_WA macro based on the C++
+ * standard.
+ *
+ * If the C++ standard is newer than C++17 and the compiler is not Clang,
+ * MGUTILITY_CNSTXPR_CLANG_WA is defined as constexpr. Otherwise, it is defined
+ * as empty.
+ */
+#if MGUTILITY_CPLUSPLUS > 201703L && defined(__cpp_lib_constexpr_string)
+#define MGUTILITY_CNSTXPR_CLANG_WA constexpr
+#else
+#define MGUTILITY_CNSTXPR_CLANG_WA
+#endif
+
+
+/**
+ * @brief Defines the MGUTILITY_CNSTEVL macro based on the C++ standard.
+ *
+ * If the C++ standard is newer than C++17, MGUTILITY_CNSTEVL is defined as
+ * consteval. Otherwise, it is defined as empty.
+ */
+#if MGUTILITY_CPLUSPLUS > 201703L
+#define MGUTILITY_CNSTEVL consteval
+#else
+#define MGUTILITY_CNSTEVL
+#endif
+
+#endif // MGUTILITY_COMMON_DEFINITIONS_HPP
diff --git a/include/mgutility/reflection/detail/enum_for_each.hpp b/include/mgutility/reflection/detail/enum_for_each.hpp
new file mode 100644
index 0000000..1365189
--- /dev/null
+++ b/include/mgutility/reflection/detail/enum_for_each.hpp
@@ -0,0 +1,180 @@
+/*
+MIT License
+
+Copyright (c) 2024 mguludag
+
+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 DETAIL_ENUM_FOR_EACH_HPP
+#define DETAIL_ENUM_FOR_EACH_HPP
+
+#include "meta.hpp"
+#include "mgutility/std/string_view.hpp"
+
+#include
+#include
+
+namespace mgutility {
+namespace detail {
+/**
+ * @brief Alias template for a string or string view type based on the presence
+ * of a bitwise OR operator.
+ *
+ * If the type T supports the bitwise OR operator, the alias is a std::string.
+ * Otherwise, it is a mgutility::string_view.
+ *
+ * @tparam T The type to check.
+ */
+template
+using string_or_view_t =
+ typename std::conditional::value, std::string,
+ mgutility::string_view>::type;
+
+/**
+ * @brief A pair consisting of an enum value and its corresponding string or
+ * string view.
+ *
+ * @tparam Enum The enum type.
+ */
+template
+using enum_pair = std::pair>;
+} // namespace detail
+
+/**
+ * @brief A class template for iterating over enum values.
+ *
+ * @tparam Enum The enum type.
+ */
+template class enum_for_each {
+ using value_type = const detail::enum_pair;
+ using size_type = std::size_t;
+
+ /**
+ * @brief An iterator for enum values.
+ */
+ struct enum_iter {
+ using const_iter_type = decltype(enum_range::min);
+ using iter_type = detail::remove_const_t;
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = const detail::enum_pair;
+ using difference_type = std::ptrdiff_t;
+ using pointer = value_type *;
+ using reference = value_type &;
+
+ /**
+ * @brief Default constructor initializing the iterator to the default
+ * position.
+ */
+ enum_iter() : m_pos{} {}
+
+ /**
+ * @brief Constructor initializing the iterator to a specific position.
+ *
+ * @param value The initial position of the iterator.
+ */
+ enum_iter(iter_type value) : m_pos{value} {}
+
+ /**
+ * @brief Pre-increment operator.
+ *
+ * @return A reference to the incremented iterator.
+ */
+ auto operator++() -> enum_iter & {
+ ++m_pos;
+ return *this;
+ }
+
+ /**
+ * @brief Post-increment operator.
+ *
+ * @return A copy of the iterator before incrementing.
+ */
+ auto operator++(int) -> enum_iter {
+ m_pos++;
+ return *this;
+ }
+
+ /**
+ * @brief Inequality comparison operator.
+ *
+ * @param other The other iterator to compare with.
+ * @return True if the iterators are not equal, otherwise false.
+ */
+ auto operator!=(const enum_iter &other) const -> bool {
+ return m_pos != other.m_pos;
+ }
+
+ /**
+ * @brief Equality comparison operator.
+ *
+ * @param other The other iterator to compare with.
+ * @return True if the iterators are equal, otherwise false.
+ */
+ auto operator==(const enum_iter &other) const -> bool {
+ return m_pos == other.m_pos;
+ }
+
+ /**
+ * @brief Dereference operator.
+ *
+ * @return The current enum pair.
+ */
+ auto operator*() const -> value_type;
+
+ private:
+ iter_type m_pos; /**< The current position of the iterator. */
+ };
+
+public:
+ /**
+ * @brief Default constructor.
+ */
+ enum_for_each() = default;
+
+ /**
+ * @brief Returns an iterator to the beginning of the enum range.
+ *
+ * @return A reference to the beginning iterator.
+ */
+ auto begin() -> enum_iter & { return m_begin; }
+
+ /**
+ * @brief Returns an iterator to the end of the enum range.
+ *
+ * @return A reference to the end iterator.
+ */
+ auto end() -> enum_iter & { return m_end; }
+
+ /**
+ * @brief Returns the size of the enum range.
+ *
+ * @return The size of the enum range.
+ */
+ auto size() -> std::size_t {
+ return enum_range::max - enum_range::min;
+ }
+
+private:
+ enum_iter m_begin{enum_range::min}; /**< The beginning iterator. */
+ enum_iter m_end{enum_range::max}; /**< The end iterator. */
+};
+} // namespace mgutility
+
+#endif // DETAIL_ENUM_FOR_EACH_HPP
\ No newline at end of file
diff --git a/include/mgutility/reflection/detail/enum_name_impl.hpp b/include/mgutility/reflection/detail/enum_name_impl.hpp
new file mode 100644
index 0000000..e594678
--- /dev/null
+++ b/include/mgutility/reflection/detail/enum_name_impl.hpp
@@ -0,0 +1,320 @@
+/*
+MIT License
+
+Copyright (c) 2024 mguludag
+
+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 MGUTILITY_REFLECTION_DETAIL_ENUM_NAME_IMPL_HPP
+#define MGUTILITY_REFLECTION_DETAIL_ENUM_NAME_IMPL_HPP
+
+#include "enum_for_each.hpp"
+#include "mgutility/std/optional.hpp"
+#include "mgutility/std/string_view.hpp"
+
+#include
+#include
+
+/**
+ * @brief Checks for MSVC compiler version.
+ *
+ * If the MSVC version is less than 2017, an error is raised.
+ */
+#if defined(_MSC_VER) && _MSC_VER < 1910
+#error "Requires MSVC 2017 or newer!"
+/**
+ * @brief Checks for Clang compiler version.
+ *
+ * If the Clang version is less than 6, an error is raised.
+ */
+#elif defined(__clang__) && __clang_major__ < 6
+#error "Requires clang 6 or newer!"
+/**
+ * @brief Checks for GCC compiler version.
+ *
+ * If the GCC version is less than 9 and it is not Clang, an error is raised.
+ */
+#elif defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 9
+#error "Requires gcc 9 or newer!"
+/**
+ * @brief Checks for unsupported compilers.
+ *
+ * If the compiler is not MSVC, Clang, or GCC, an error is raised.
+ */
+#elif !defined(_MSC_VER) && !defined(__clang__) && !defined(__GNUC__)
+#error "Your compiler is not supported!"
+#endif
+
+/**
+ * @brief Defines the MGUTILITY_CPLUSPLUS macro for MSVC and other compilers.
+ *
+ * For MSVC, it uses _MSVC_LANG. For other compilers, it uses __cplusplus.
+ */
+#ifdef _MSC_VER
+#define __PRETTY_FUNCTION__ __FUNCSIG__
+#endif
+
+namespace mgutility {
+namespace detail {
+
+struct enum_type {
+ /**
+ * @brief Gets the name of an unscoped enum value.
+ *
+ * @tparam Enum The enum type.
+ * @tparam e The enum value.
+ * @return A string view representing the name of the enum value.
+ */
+ template <
+ typename Enum, Enum e,
+ detail::enable_if_t::value, bool> = true>
+ MGUTILITY_CNSTXPR static auto name() noexcept -> mgutility::string_view {
+ for (auto &pair : mgutility::custom_enum::map) {
+ if (pair.first == e) {
+ return pair.second;
+ }
+ }
+ MGUTILITY_CNSTXPR auto str = mgutility::string_view(__PRETTY_FUNCTION__);
+ MGUTILITY_CNSTXPR auto offset = lastidxenumname[0] + lastidxenumname[1];
+ MGUTILITY_CNSTXPR auto index =
+ std::max(str.rfind(lastidxenumname[2], str.size() - offset),
+ str.rfind(lastidxenumname[3], str.size() - offset));
+ MGUTILITY_CNSTXPR auto result =
+ str.substr(index + 1, str.size() - offset - index);
+ return result[0] == '(' ? "" : result;
+ }
+
+ /**
+ * @brief Gets the name of a scoped enum value.
+ *
+ * @tparam Enum The enum type.
+ * @tparam e The enum value.
+ * @return A string view representing the name of the enum value.
+ */
+ template <
+ typename Enum, Enum e,
+ detail::enable_if_t::value, bool> = true>
+ MGUTILITY_CNSTXPR static auto name() noexcept -> mgutility::string_view {
+ for (auto &pair : mgutility::custom_enum::map) {
+ if (pair.first == e) {
+ return pair.second;
+ }
+ }
+ MGUTILITY_CNSTXPR auto str = mgutility::string_view(__PRETTY_FUNCTION__);
+ MGUTILITY_CNSTXPR auto index =
+ str.rfind(lastidxenumname[3], str.size() - lastidxenumname[0]) + 1;
+ MGUTILITY_CNSTXPR auto result =
+ str.substr(index, str.size() - lastidxenumname[0] - index);
+ MGUTILITY_CNSTXPR auto is_invalid =
+ result.rfind(lastidxenumname[5]) != result.npos || (result.size() > 4 && result[4] == lastidxenumname[4]);
+ return is_invalid ? "" : result;
+ }
+
+private:
+ static constexpr int lastidxenumname[] =
+#if defined(__clang__)
+ {1, 1, ' ', ':', '(',
+#if __clang_major__ < 13
+ ','
+#else
+ ')'
+#endif
+ };
+#elif defined(_MSC_VER)
+ {21, 0, ',', ':', '<', ')'};
+#elif defined(__GNUC__)
+ {
+#if MGUTILITY_CPLUSPLUS < 201703L
+ 163,
+#else
+ 157,
+#endif
+ 5, ' ', ':', '(', ')'};
+#endif
+};
+
+/**
+ * @brief Generates an array of enum names.
+ *
+ * @tparam Enum The enum type.
+ * @tparam Is The enumeration values.
+ * @return An array of string views representing the enum names.
+ */
+template
+MGUTILITY_CNSTXPR inline auto
+get_enum_array(detail::enum_sequence /*unused*/) noexcept
+ -> std::array {
+ return std::array{
+ "", enum_type::template name()...};
+}
+
+/**
+ * @brief Generates an array of enum names.
+ *
+ * @tparam Enum The enum type.
+ * @tparam Min The minimum enum value.
+ * @tparam Max The maximum enum value.
+ * @return An array of string views representing the enum names.
+ */
+template ::min,
+ int Max = mgutility::enum_range::max>
+MGUTILITY_CNSTXPR inline auto get_enum_array() noexcept
+ -> std::array {
+ return get_enum_array(detail::make_enum_sequence());
+}
+
+/**
+ * @brief Converts a string to an enum value.
+ *
+ * @tparam Enum The enum type.
+ * @tparam Min The minimum enum value.
+ * @tparam Max The maximum enum value.
+ * @param str The string view representing the enum name.
+ * @return An optional enum value.
+ */
+template
+MGUTILITY_CNSTXPR inline auto to_enum_impl(mgutility::string_view str) noexcept
+ -> mgutility::optional {
+ MGUTILITY_CNSTXPR_CLANG_WA auto arr = get_enum_array();
+ const auto index{std::find(arr.begin() + 1, arr.end(), str)};
+ return index == arr.end() ? mgutility::nullopt
+ : mgutility::optional{static_cast(
+ std::distance(arr.begin(), index) + Min - 1)};
+}
+
+/**
+ * @brief Converts a string to an enum bitmask value.
+ *
+ * @tparam Enum The enum type.
+ * @tparam Min The minimum enum value.
+ * @tparam Max The maximum enum value.
+ * @param str The string view representing the enum name.
+ * @return An optional enum bitmask value.
+ */
+template
+MGUTILITY_CNSTXPR auto to_enum_bitmask_impl(mgutility::string_view str) noexcept
+ -> mgutility::optional {
+
+ // Check if the string contains a '|' character
+ if (str.find('|') == mgutility::string_view::npos) {
+ return to_enum_impl(str);
+ }
+
+ mgutility::optional result{mgutility::nullopt};
+ std::size_t index = 0;
+
+ for (std::size_t i = 0; i < str.size(); ++i) {
+ if (str[i] == '|') {
+ auto name = str.substr(index, i - index);
+ auto maybe_enum = to_enum_impl(name);
+
+ if (!name.empty() && maybe_enum) {
+ result.emplace(result ? static_cast(*result | *maybe_enum)
+ : *maybe_enum);
+ }
+
+ index = i + 1;
+ }
+ }
+
+ auto maybe_enum = to_enum_impl(str.substr(index));
+ if (result && maybe_enum) {
+ result.emplace(static_cast(*result | *maybe_enum));
+ } else {
+ result.reset();
+ }
+
+ return result;
+}
+
+/**
+ * @brief Gets the name of an enum value.
+ *
+ * @tparam Enum The enum type.
+ * @tparam Min The minimum enum value.
+ * @tparam Max The maximum enum value.
+ * @param e The enum value.
+ * @return A string view representing the name of the enum value.
+ */
+template ::value, bool> = true>
+MGUTILITY_CNSTXPR auto enum_name_impl(Enum e) noexcept
+ -> mgutility::string_view {
+ MGUTILITY_CNSTXPR auto arr = get_enum_array();
+ const auto index{(Min < 0 ? -Min : Min) + static_cast(e) + 1};
+ return arr[(index < Min || index > arr.size() - 1) ? 0 : index];
+}
+
+/**
+ * @brief Gets the name of an enum bitmask value.
+ *
+ * @tparam Enum The enum type.
+ * @tparam Min The minimum enum value.
+ * @tparam Max The maximum enum value.
+ * @param e The enum value.
+ * @return A string view or string representing the name of the enum bitmask
+ * value.
+ */
+template ::value, bool> = true>
+MGUTILITY_CNSTXPR_CLANG_WA inline auto enum_name_impl(Enum e) noexcept
+ -> detail::string_or_view_t {
+
+ // Get the array of enum names
+ MGUTILITY_CNSTXPR_CLANG_WA auto arr = get_enum_array();
+
+ // Calculate the index in the array
+ const auto index = (Min < 0 ? -Min : Min) + static_cast(e) + 1;
+ const auto name =
+ arr[(index < Min || index >= static_cast(arr.size())) ? 0 : index];
+
+ // Lambda to check if a character is a digit
+ const auto is_digit = [](char c) { return c >= '0' && c <= '9'; };
+
+ // Return the name if it's valid
+ if (!name.empty() && !is_digit(name[0])) {
+ return std::string{name};
+ }
+
+ // Construct bitmasked name
+ std::string bitmasked_name;
+ for (auto i = Min; i < Max; ++i) {
+ const auto idx = (Min < 0 ? -Min : Min) + i + 1;
+ if (idx >= 0 && idx < static_cast(arr.size()) && !arr[idx].empty() &&
+ !is_digit(arr[idx][0]) &&
+ (e & static_cast(i)) == static_cast(i)) {
+ bitmasked_name.append(arr[idx]).append("|");
+ }
+ }
+
+ // Remove the trailing '|' if present
+ if (!bitmasked_name.empty()) {
+ bitmasked_name.pop_back();
+ }
+
+ if (bitmasked_name.find('|') != std::string::npos) {
+ return bitmasked_name;
+ }
+ return std::string{""};
+}
+} // namespace detail
+} // namespace mgutility
+
+#endif // MGUTILITY_REFLECTION_DETAIL_ENUM_NAME_IMPL_HPP
\ No newline at end of file
diff --git a/include/mgutility/reflection/detail/meta.hpp b/include/mgutility/reflection/detail/meta.hpp
new file mode 100644
index 0000000..976e7ba
--- /dev/null
+++ b/include/mgutility/reflection/detail/meta.hpp
@@ -0,0 +1,183 @@
+/*
+MIT License
+
+Copyright (c) 2024 mguludag
+
+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 DETAIL_META_HPP
+#define DETAIL_META_HPP
+
+#include "mgutility/_common/definitions.hpp"
+#include
+#include
+#include
+
+namespace mgutility {
+namespace detail {
+/**
+ * @brief Trait to check if a type is a scoped enumeration.
+ *
+ * @tparam E The type to check.
+ */
+template struct is_scoped_enum {
+ /**
+ * @brief Boolean value indicating if the type is a scoped enumeration.
+ */
+ static constexpr auto value =
+ std::is_enum::value &&
+ !std::is_convertible::type>::value;
+};
+
+/**
+ * @brief Trait to check if a type supports the bitwise OR operator.
+ *
+ * @tparam T The type to check.
+ * @tparam Enable SFINAE parameter, default is void.
+ */
+template struct has_bit_or : std::false_type {};
+
+/**
+ * @brief Specialization of has_bit_or for types that support the bitwise OR
+ * operator.
+ *
+ * @tparam T The type to check.
+ */
+template
+struct has_bit_or : std::true_type {};
+
+#if MGUTILITY_CPLUSPLUS > 201103L
+/**
+ * @brief Helper variable template for is_scoped_enum.
+ *
+ * @tparam E The type to check.
+ */
+template
+static constexpr bool is_scoped_enum_v = is_scoped_enum::value;
+#endif
+
+/**
+ * @brief Alias template for std::enable_if.
+ *
+ * This template is used to conditionally enable a type `T` if the boolean
+ * constant `B` is true. It is a shorthand for `typename std::enable_if::type`.
+ *
+ * @tparam B The compile-time boolean condition.
+ * @tparam T The type to be enabled if `B` is true, default is void.
+ */
+template
+using enable_if_t = typename std::enable_if::type;
+
+/**
+ * @brief Alias template for std::underlying_type.
+ *
+ * @tparam T The enumeration type.
+ */
+template
+using underlying_type_t = typename std::underlying_type::type;
+
+/**
+ * @brief Alias template for std::remove_const.
+ *
+ * @tparam T The type to remove const from.
+ */
+template
+using remove_const_t = typename std::remove_const::type;
+
+/**
+ * @brief Represents a sequence of enumeration values.
+ *
+ * @tparam Enum The enumeration type.
+ * @tparam ...EnumValues The enumeration values in the sequence.
+ */
+template struct enum_sequence {};
+
+/**
+ * @brief Helper for generating a sequence of enumeration values.
+ *
+ * @tparam Enum The enumeration type.
+ * @tparam Min The minimum value in the sequence.
+ * @tparam Max The maximum value in the sequence.
+ * @tparam ...Next The next values in the sequence.
+ */
+template
+struct enum_sequence_helper
+ : enum_sequence_helper {};
+
+/**
+ * @brief Specialization of enum_sequence_helper for the end of the sequence.
+ *
+ * @tparam Enum The enumeration type.
+ * @tparam Min The minimum value in the sequence.
+ * @tparam ...Next The next values in the sequence.
+ */
+template
+struct enum_sequence_helper {
+ /**
+ * @brief The resulting sequence type.
+ */
+ using type = enum_sequence(Next)...>;
+};
+
+/**
+ * @brief Generates a sequence of enumeration values.
+ *
+ * @tparam Enum The enumeration type.
+ * @tparam Min The minimum value in the sequence.
+ * @tparam Max The maximum value in the sequence.
+ */
+template
+using make_enum_sequence = typename enum_sequence_helper::type;
+} // namespace detail
+
+/**
+ * @brief Provides the range for an enumeration type.
+ *
+ * @tparam T The enumeration type.
+ */
+template struct enum_range {
+ static constexpr auto min{0};
+ static constexpr auto max{256};
+};
+
+template struct pair {
+ T first;
+ U second;
+};
+
+template
+#if MGUTILITY_CPLUSPLUS > 201103L || defined(__GNUC__) && !defined(__clang__)
+using flat_map = std::initializer_list>;
+#else
+using flat_map = pair[];
+#endif
+
+/**
+ * @brief Provides the custom names map for an enumeration type.
+ *
+ * @tparam T The enumeration type.
+ */
+template struct custom_enum {
+ static constexpr flat_map map = {};
+};
+} // namespace mgutility
+
+#endif // DETAIL_META_HPP
\ No newline at end of file
diff --git a/include/mgutility/reflection/enum_name.hpp b/include/mgutility/reflection/enum_name.hpp
new file mode 100644
index 0000000..47c2df7
--- /dev/null
+++ b/include/mgutility/reflection/enum_name.hpp
@@ -0,0 +1,211 @@
+/*
+MIT License
+
+Copyright (c) 2023 mguludag
+
+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 MGUTILITY_ENUM_NAME_HPP
+#define MGUTILITY_ENUM_NAME_HPP
+
+#include "detail/enum_name_impl.hpp"
+
+namespace mgutility {
+
+/**
+ * @brief Converts an enum value to its underlying integer value.
+ *
+ * @tparam Enum The enum type.
+ * @param e The enum value.
+ * @return The underlying integer value of the enum.
+ */
+template
+constexpr auto enum_to_underlying(Enum e) noexcept
+ -> detail::underlying_type_t {
+ static_assert(std::is_enum::value, "Value is not an Enum type!");
+ return static_cast>(e);
+}
+
+/**
+ * @brief Gets the name of an enum value.
+ *
+ * @tparam Min The minimum enum value.
+ * @tparam Max The maximum enum value.
+ * @tparam Enum The enum type.
+ * @param e The enum value.
+ * @return A string view or string representing the name of the enum value.
+ */
+template
+MGUTILITY_CNSTXPR auto enum_name(Enum e) noexcept
+ -> detail::string_or_view_t {
+ static_assert(Min < Max - 1, "Max must be greater than (Min + 1)!");
+ static_assert(std::is_enum::value, "Value is not an Enum type!");
+ return detail::enum_name_impl(e);
+}
+
+/**
+ * @brief Gets the name of an enum value.
+ *
+ * @tparam Enum The enum type.
+ * @tparam Min The minimum enum value, default is enum_range::min.
+ * @tparam Max The maximum enum value, default is enum_range::max.
+ * @param e The enum value.
+ * @return A string view or string representing the name of the enum value.
+ */
+template ::min,
+ int Max = enum_range::max>
+MGUTILITY_CNSTXPR auto enum_name(Enum e) noexcept
+ -> detail::string_or_view_t {
+ static_assert(Min < Max - 1, "Max must be greater than (Min + 1)!");
+ static_assert(std::is_enum::value, "Value is not an Enum type!");
+ return detail::enum_name_impl(e);
+}
+
+/**
+ * @brief Gets the enum value and its name.
+ *
+ * @tparam Enum The enum type.
+ * @return A pair of the enum value and its name.
+ */
+template
+auto enum_for_each