diff --git a/.vscode/settings.json b/.vscode/settings.json
index abcce64..0d05ad4 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,6 +1,15 @@
{
- "files.associations": {
- "cmath": "cpp",
- "string_view": "cpp"
- }
+ "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"
+ }
}
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 10a4c73..4a073e5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,15 +1,17 @@
cmake_minimum_required(VERSION 3.14)
-project(enum_name_example VERSION 0.1 LANGUAGES CXX)
+project(
+ enum_name_example
+ VERSION 0.1
+ LANGUAGES CXX)
-set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD 20)
include(FetchContent)
FetchContent_Declare(
- DocTest
- GIT_REPOSITORY "https://github.com/onqtam/doctest"
- GIT_TAG "v2.4.11"
-)
+ DocTest
+ GIT_REPOSITORY "https://github.com/onqtam/doctest"
+ GIT_TAG "v2.4.11")
FetchContent_MakeAvailable(DocTest)
@@ -17,4 +19,4 @@ add_executable(${PROJECT_NAME} example/main.cpp)
target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR}/include)
enable_testing()
-add_subdirectory(test)
\ No newline at end of file
+add_subdirectory(test)
diff --git a/README.md b/README.md
index 523b10c..ac10478 100644
--- a/README.md
+++ b/README.md
@@ -9,10 +9,11 @@ Converting (scoped)enum values to/from string names written in C++>=11.
## 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
+* Supports compile-time as much as possible using with C++17 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 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
@@ -20,16 +21,32 @@ Converting (scoped)enum values to/from string names written in C++>=11.
* Wider range can increase compile time so user responsible to adjusting for enum's range
-## Usage ([try it!](https://godbolt.org/z/YM5EvY1Y5))
+## Usage ([try it!](https://godbolt.org/z/dfeYxscvT))
```C++
#include
#include "enum_name.hpp"
-num class rgb_color { red, green, blue, unknown = -1 };
+enum class rgb_color {
+ red = 1 << 0,
+ green = 1 << 1,
+ blue = 1 << 2,
+ unknown = -1
+};
+
+auto operator|(rgb_color lhs, rgb_color rhs) -> rgb_color {
+ return static_cast(mgutility::enum_to_underlying(lhs) |
+ mgutility::enum_to_underlying(rhs));
+}
+
+auto operator&(rgb_color lhs, rgb_color rhs) -> rgb_color {
+ return static_cast(mgutility::enum_to_underlying(lhs) &
+ mgutility::enum_to_underlying(rhs));
+}
// specialize rgb_color::unknown to make output "UNKNOWN" instead of "unknown"
template <>
-constexpr auto mgutility::detail::enum_type::name() noexcept
+constexpr inline auto
+mgutility::detail::enum_type::name() noexcept
-> string_view {
return "UNKNOWN";
}
@@ -38,38 +55,41 @@ constexpr auto mgutility::detail::enum_type::name
template <>
struct mgutility::enum_range {
static constexpr auto min = -1;
- static constexpr auto max = 3;
+ static constexpr auto max = 5;
};
// 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); };
+auto enum_name = [](rgb_color c) { return mgutility::enum_name<-1, 5>(c); };
#if defined(__cpp_lib_print)
#include
#include
#endif
-
int main() {
auto x = rgb_color::blue;
- auto y = mgutility::to_enum("greenn");
+ auto y = mgutility::to_enum("green|red");
#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"; });
+ // 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.empty() && pair.second != "UNKNOWN";
+ });
std::ranges::for_each(colors, [](auto &&color) {
- std::println("{} \t: {}", color.second, mgutility::enum_to_underlying(color.first));
+ std::println("{} \t: {}", color.second,
+ mgutility::enum_to_underlying(color.first));
});
#else
for (auto&& e : mgutility::enum_for_each()) {
- if(e.second != "UNKNOWN"){
- std::cout << e.second << " \t: " << mgutility::enum_to_underlying(e.first) << '\n';
+ if (!e.second.empty() && e.second != "UNKNOWN") {
+ std::cout << e.second
+ << " \t: " << mgutility::enum_to_underlying(e.first)
+ << '\n';
}
// std::pair {enum_type, name_of_enum}
}
@@ -78,8 +98,6 @@ auto colors = mgutility::enum_for_each() |
// 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
diff --git a/example/main.cpp b/example/main.cpp
index 4f0b051..771fa1e 100644
--- a/example/main.cpp
+++ b/example/main.cpp
@@ -1,33 +1,80 @@
-#include
#include "enum_name.hpp"
+#include
+enum class rgb_color {
+ red = 1 << 0,
+ green = 1 << 1,
+ blue = 1 << 2,
+ unknown = -1
+};
+
+auto constexpr operator|(rgb_color lhs, rgb_color rhs) -> rgb_color {
+ return static_cast(mgutility::enum_to_underlying(lhs) |
+ mgutility::enum_to_underlying(rhs));
+}
-enum class rgb_color { red, green, blue, unknown = -1};
+auto constexpr operator&(rgb_color lhs, rgb_color rhs) -> rgb_color {
+ return static_cast(mgutility::enum_to_underlying(lhs) &
+ mgutility::enum_to_underlying(rhs));
+}
-// 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;
- };
+// specialize rgb_color::unknown to make output "UNKNOWN" instead of "unknown"
+template <>
+constexpr auto
+mgutility::detail::enum_type::name() noexcept
+ -> mgutility::string_view {
+ return "UNKNOWN";
}
+// 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 = 5;
+};
+
// 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';
+auto enum_name = [](rgb_color c) { return mgutility::enum_name<-1, 5>(c); };
+
+#if defined(__cpp_lib_print)
+#include
+#include
+#endif
+
+int main() {
+ auto x = rgb_color::blue;
+ auto y = mgutility::to_enum("green|red");
+
+#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.empty() && pair.second != "UNKNOWN";
+ });
+
+ std::ranges::for_each(colors, [](auto &&color) {
+ std::println("{} \t: {}", color.second,
+ mgutility::enum_to_underlying(color.first));
+ });
+
+#else
+
+ for (auto &&e : mgutility::enum_for_each()) {
+ if (!e.second.empty() && e.second != "UNKNOWN") {
+ std::cout << e.second << " \t: " << mgutility::enum_to_underlying(e.first)
+ << '\n';
+ }
+ // std::pair {enum_type, name_of_enum}
+ }
+#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 << 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';
}
\ No newline at end of file
diff --git a/include/detail/definitions.hpp b/include/detail/definitions.hpp
new file mode 100644
index 0000000..055a693
--- /dev/null
+++ b/include/detail/definitions.hpp
@@ -0,0 +1,114 @@
+/*
+MIT License
+
+© 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_DEFINITIONS_HPP
+#define DETAIL_DEFINITIONS_HPP
+
+/**
+ * @file detail_definitions.hpp
+ * @brief Defines macros for compiler and standard support detection.
+ */
+
+/**
+ * @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 MGUTILITY_CPLUSPLUS _MSVC_LANG
+#define __PRETTY_FUNCTION__ __FUNCSIG__
+#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(__clang__)
+#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 // DETAIL_DEFINITIONS_HPP
\ No newline at end of file
diff --git a/include/detail/enum_for_each.hpp b/include/detail/enum_for_each.hpp
new file mode 100644
index 0000000..d40f55c
--- /dev/null
+++ b/include/detail/enum_for_each.hpp
@@ -0,0 +1,190 @@
+/*
+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 "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/detail/enum_name_impl.hpp b/include/detail/enum_name_impl.hpp
new file mode 100644
index 0000000..d2f7dfc
--- /dev/null
+++ b/include/detail/enum_name_impl.hpp
@@ -0,0 +1,268 @@
+/*
+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_NAME_IMPL_HPP
+#define DETAIL_ENUM_NAME_IMPL_HPP
+
+#include "detail/enum_for_each.hpp"
+#include "detail/optional.hpp"
+#include "detail/string_view.hpp"
+
+#include
+#include
+
+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
+ {
+ auto str = mgutility::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;
+ }
+
+ /**
+ * @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
+ {
+ auto str = mgutility::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;
+ }
+
+ private:
+ static constexpr int lastidxenumname[] =
+#if defined(_MSC_VER)
+ {21, 0, ',', ':', '<'};
+#elif defined(__clang__)
+ {1, 1, ' ', ':', '('};
+#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 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 auto arr =
+ get_enum_array(detail::make_enum_sequence());
+ 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(detail::make_enum_sequence());
+ const auto index{(Min < 0 ? Min * -1 : 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 auto arr =
+ get_enum_array(detail::make_enum_sequence());
+
+ // 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();
+ }
+
+ return bitmasked_name.find('|') != std::string::npos ? bitmasked_name
+ : std::string{""};
+ }
+ } // namespace detail
+} // namespace mgutility
+
+#endif // DETAIL_ENUM_NAME_IMPL_HPP
\ No newline at end of file
diff --git a/include/detail/meta.hpp b/include/detail/meta.hpp
new file mode 100644
index 0000000..8cfa451
--- /dev/null
+++ b/include/detail/meta.hpp
@@ -0,0 +1,165 @@
+/*
+MIT License
+
+© 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 "definitions.hpp"
+#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{-128};
+ static constexpr auto max{128};
+ };
+} // namespace mgutility
+
+#endif // DETAIL_META_HPP
\ No newline at end of file
diff --git a/include/detail/optional.hpp b/include/detail/optional.hpp
new file mode 100644
index 0000000..252ecb8
--- /dev/null
+++ b/include/detail/optional.hpp
@@ -0,0 +1,355 @@
+/*
+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_OPTIONAL_HPP
+#define DETAIL_OPTIONAL_HPP
+
+#include "definitions.hpp"
+#include "meta.hpp"
+
+#include
+
+#if MGUTILITY_CPLUSPLUS >= 201703L
+#include
+#endif
+
+namespace mgutility
+{
+
+#if MGUTILITY_CPLUSPLUS < 201703L
+
+ /**
+ * @brief Exception thrown when accessing an empty optional.
+ */
+ struct bad_optional_access : public std::exception
+ {
+ /**
+ * @brief Returns the exception message.
+ *
+ * @return A C-string with the exception message.
+ */
+ const char *what() const noexcept { return "optional has no value"; }
+ };
+
+ struct nullopt_t;
+
+ /**
+ * @brief A class template that provides optional (nullable) objects.
+ *
+ * @tparam T The type of the value.
+ */
+ template
+ class optional
+ {
+ public:
+ /**
+ * @brief Constructs an empty optional.
+ */
+ MGUTILITY_CNSTXPR inline optional(nullopt_t &)
+ : dummy_{0}, has_value_{false} {}
+
+ /**
+ * @brief Constructs an empty optional.
+ */
+ MGUTILITY_CNSTXPR inline optional() : dummy_{0}, has_value_{false} {}
+
+ /**
+ * @brief Constructs an optional with a value.
+ *
+ * @tparam Args The types of the arguments.
+ * @param args The arguments to construct the value.
+ */
+ template
+ MGUTILITY_CNSTXPR inline optional(Args &&...args)
+ : value_{T{std::forward(args)...}}, has_value_{true} {}
+
+ /**
+ * @brief Constructs an optional with a value.
+ *
+ * @param value The value to initialize with.
+ */
+ MGUTILITY_CNSTXPR inline optional(T &&value)
+ : value_{value}, has_value_{true} {}
+
+ /**
+ * @brief Copy constructor.
+ *
+ * @param other The other optional to copy.
+ */
+ MGUTILITY_CNSTXPR inline optional(const optional &other)
+ : value_{other.value_}, has_value_{other.has_value_} {}
+
+ /**
+ * @brief Move constructor.
+ *
+ * @param other The other optional to move.
+ */
+ MGUTILITY_CNSTXPR inline optional(optional &&other)
+ : value_{other.value_}, has_value_{other.has_value_}
+ {
+ other.reset();
+ }
+
+ /**
+ * @brief Destructor.
+ */
+ inline ~optional() { has_value_ = false; }
+
+ /**
+ * @brief Copy assignment operator.
+ *
+ * @param other The other optional to copy.
+ * @return A reference to this optional.
+ */
+ MGUTILITY_CNSTXPR inline optional &operator=(const optional &other)
+ {
+ value_ = other.value_;
+ has_value_ = other.has_value_;
+ return *this;
+ }
+
+ /**
+ * @brief Move assignment operator.
+ *
+ * @param other The other optional to move.
+ * @return A reference to this optional.
+ */
+ MGUTILITY_CNSTXPR inline optional &operator=(optional &&other)
+ {
+ value_ = other.value_;
+ has_value_ = other.has_value_;
+ other.reset();
+ return *this;
+ }
+
+ /**
+ * @brief Swaps the contents of this optional with another.
+ *
+ * @param other The other optional to swap with.
+ */
+ MGUTILITY_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);
+ }
+
+ /**
+ * @brief Dereferences the stored value.
+ *
+ * @return A reference to the stored value.
+ */
+ MGUTILITY_CNSTXPR inline T &operator*() { return value_; }
+
+ /**
+ * @brief Dereferences the stored value (const version).
+ *
+ * @return A reference to the stored value.
+ */
+ MGUTILITY_CNSTXPR inline T &operator*() const { return value_; }
+
+ /**
+ * @brief Accesses the stored value.
+ *
+ * @return A reference to the stored value.
+ * @throws bad_optional_access if the optional has no value.
+ */
+ MGUTILITY_CNSTXPR inline T &value()
+ {
+ if (!has_value_)
+ throw bad_optional_access();
+ return value_;
+ }
+
+ /**
+ * @brief Accesses the stored value (const version).
+ *
+ * @return A reference to the stored value.
+ * @throws bad_optional_access if the optional has no value.
+ */
+ MGUTILITY_CNSTXPR inline T &value() const
+ {
+ if (!has_value_)
+ throw bad_optional_access();
+ return value_;
+ }
+
+ /**
+ * @brief Returns the stored value or a default value if empty.
+ *
+ * @param value The default value to return if empty.
+ * @return The stored value or the default value.
+ */
+ MGUTILITY_CNSTXPR inline T value_or(T &&value)
+ {
+ return has_value_ ? value_ : value;
+ }
+
+ /**
+ * @brief Returns the stored value or a default value if empty (const version).
+ *
+ * @param value The default value to return if empty.
+ * @return The stored value or the default value.
+ */
+ MGUTILITY_CNSTXPR inline T value_or(T &&value) const
+ {
+ return has_value_ ? value_ : value;
+ }
+
+ /**
+ * @brief Returns the stored value or a default value if empty.
+ *
+ * @param value The default value to return if empty.
+ * @return The stored value or the default value.
+ */
+ MGUTILITY_CNSTXPR inline T value_or(const T &value)
+ {
+ return has_value_ ? value_ : value;
+ }
+
+ /**
+ * @brief Returns the stored value or a default value if empty (const version).
+ *
+ * @param value The default value to return if empty.
+ * @return The stored value or the default value.
+ */
+ MGUTILITY_CNSTXPR inline T value_or(const T &value) const
+ {
+ return has_value_ ? value_ : value;
+ }
+
+ /**
+ * @brief Constructs the value in-place.
+ *
+ * @param value The value to emplace.
+ */
+ MGUTILITY_CNSTXPR inline void emplace(T value)
+ {
+ value_ = std::move(value);
+ has_value_ = true;
+ }
+
+ /**
+ * @brief Constructs the value in-place with arguments.
+ *
+ * @tparam Args The types of the arguments.
+ * @param args The arguments to construct the value.
+ */
+ template
+ MGUTILITY_CNSTXPR inline void emplace(Args &&...args)
+ {
+ value_ = std::move(T{std::forward(args)...});
+ has_value_ = true;
+ }
+
+ /**
+ * @brief Checks if the optional has a value.
+ *
+ * @return True if the optional has a value, otherwise false.
+ */
+ MGUTILITY_CNSTXPR inline bool has_value() const { return has_value_; }
+
+ /**
+ * @brief Resets the optional, making it empty.
+ */
+ template ::value, bool> = true>
+ MGUTILITY_CNSTXPR inline void reset()
+ {
+ value_ = T{};
+ has_value_ = false;
+ }
+
+ /**
+ * @brief Resets the optional, making it empty.
+ */
+ template ::value, bool> = true>
+ MGUTILITY_CNSTXPR inline void reset()
+ {
+ value_.~T();
+ has_value_ = false;
+ }
+
+ /**
+ * @brief Checks if the optional has a value.
+ *
+ * @return True if the optional has a value, otherwise false.
+ */
+ MGUTILITY_CNSTXPR operator bool() { return has_value_; }
+
+ private:
+ union
+ {
+ T value_;
+ char dummy_[sizeof(T)];
+ };
+ bool has_value_;
+ };
+
+ /**
+ * @brief Represents a null optional.
+ */
+ struct nullopt_t
+ {
+ /**
+ * @brief Converts nullopt_t to an empty optional.
+ *
+ * @tparam T The type of the optional.
+ * @return An empty optional.
+ */
+ template
+ MGUTILITY_CNSTXPR operator optional()
+ {
+ return optional{};
+ }
+ };
+
+ /**
+ * @brief A global instance of nullopt_t to represent null optional.
+ */
+ auto nullopt = nullopt_t{};
+
+#else
+ /**
+ * @brief Alias template for std::optional.
+ *
+ * @tparam T The type of the value.
+ */
+ template
+ using optional = std::optional;
+
+ /**
+ * @brief A global constant representing a null optional.
+ */
+ inline constexpr auto nullopt{std::nullopt};
+
+#endif
+}
+
+#endif // DETAIL_OPTIONAL_HPP
\ No newline at end of file
diff --git a/include/detail/string_view.hpp b/include/detail/string_view.hpp
new file mode 100644
index 0000000..65e62d2
--- /dev/null
+++ b/include/detail/string_view.hpp
@@ -0,0 +1,323 @@
+/*
+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 STRING_STRING_VIEW_HPP
+#define STRING_STRING_VIEW_HPP
+
+#include
+#include
+#include
+
+#include "definitions.hpp"
+
+namespace mgutility
+{
+
+#if MGUTILITY_CPLUSPLUS < 201703L
+
+ namespace detail
+ {
+ /**
+ * @brief Computes the length of a C-string at compile-time.
+ *
+ * @param str The C-string.
+ * @param sz The initial size, default is 0.
+ * @return The length of the C-string.
+ */
+ constexpr auto strlen_constexpr(const char *str, size_t sz = 0) noexcept
+ -> size_t
+ {
+ return str[sz] == '\0' ? sz : strlen_constexpr(str, ++sz);
+ }
+ } // namespace detail
+
+ /**
+ * @brief A basic string view class template.
+ *
+ * @tparam Char The character type, default is char.
+ */
+ template
+ class basic_string_view
+ {
+ public:
+ /**
+ * @brief Default constructor.
+ */
+ constexpr inline basic_string_view() noexcept : data_(""), size_(0) {}
+
+ /**
+ * @brief Constructs a basic_string_view from a C-string.
+ *
+ * @param str The C-string.
+ */
+ constexpr inline basic_string_view(const Char *str) noexcept
+ : data_(str), size_(detail::strlen_constexpr(str)) {}
+
+ /**
+ * @brief Constructs a basic_string_view from a C-string and length.
+ *
+ * @param str The C-string.
+ * @param len The length of the string.
+ */
+ constexpr inline basic_string_view(const Char *str, size_t len) noexcept
+ : data_(str), size_(len) {}
+
+ /**
+ * @brief Copy constructor.
+ *
+ * @param other The other basic_string_view to copy.
+ */
+ constexpr inline basic_string_view(const basic_string_view &other)
+ : data_(other.data_), size_(other.size_) {}
+
+ /**
+ * @brief Move constructor.
+ *
+ * @param other The other basic_string_view to move.
+ */
+ constexpr inline basic_string_view(basic_string_view &&other) noexcept
+ : data_(std::move(other.data_)), size_(std::move(other.size_)) {}
+
+ /**
+ * @brief Copy assignment operator.
+ *
+ * @param other The other basic_string_view to copy.
+ * @return A reference to this object.
+ */
+ MGUTILITY_CNSTXPR inline basic_string_view &
+ operator=(const basic_string_view &other) noexcept
+ {
+ data_ = other.data_;
+ size_ = other.size_;
+ return *this;
+ }
+
+ /**
+ * @brief Move assignment operator.
+ *
+ * @param other The other basic_string_view to move.
+ * @return A reference to this object.
+ */
+ MGUTILITY_CNSTXPR inline basic_string_view &
+ operator=(basic_string_view &&other) noexcept
+ {
+ data_ = std::move(other.data_);
+ size_ = std::move(other.size_);
+ return *this;
+ }
+
+ /**
+ * @brief Accesses the character at the given index.
+ *
+ * @param index The index.
+ * @return The character at the index.
+ */
+ constexpr inline const Char operator[](size_t index) const noexcept
+ {
+ return data_[index];
+ }
+
+ /**
+ * @brief Returns an iterator to the beginning of the string.
+ *
+ * @return A pointer to the first character.
+ */
+ constexpr inline const Char *begin() const noexcept { return data_; }
+
+ /**
+ * @brief Returns an iterator to the end of the string.
+ *
+ * @return A pointer to one past the last character.
+ */
+ constexpr inline const Char *end() const noexcept { return (data_ + size_); }
+
+ /**
+ * @brief Checks if the string is empty.
+ *
+ * @return True if the string is empty, otherwise false.
+ */
+ constexpr inline bool empty() const noexcept { return size_ < 1; }
+
+ /**
+ * @brief Returns the size of the string.
+ *
+ * @return The size of the string.
+ */
+ constexpr inline size_t size() const noexcept { return size_; }
+
+ /**
+ * @brief Returns a pointer to the underlying data.
+ *
+ * @return A pointer to the data.
+ */
+ constexpr inline const Char *data() const noexcept { return data_; }
+
+ /**
+ * @brief Returns a substring view.
+ *
+ * @param begin The starting position.
+ * @param len The length of the substring.
+ * @return A basic_string_view representing the substring.
+ */
+ constexpr inline basic_string_view substr(size_t begin,
+ size_t len = 0U) const noexcept
+ {
+ return basic_string_view(data_ + begin, len == 0U ? size_ - begin : len);
+ }
+
+ /**
+ * @brief Finds the last occurrence of a character.
+ *
+ * @param c The character to find.
+ * @param pos The position to start from, default is npos.
+ * @return The position of the character or npos if not found.
+ */
+ constexpr inline size_t rfind(Char c, size_t pos = npos) const noexcept
+ {
+ return (pos == npos ? pos = size_ : pos = pos), c == data_[pos] ? pos
+ : pos == 0U
+ ? npos
+ : rfind(c, --pos);
+ }
+
+ /**
+ * @brief Finds the first occurrence of a character.
+ *
+ * @param c The character to find.
+ * @param pos The position to start from, default is 0.
+ * @return The position of the character or npos if not found.
+ */
+ constexpr inline size_t find(Char c, size_t pos = 0) const noexcept
+ {
+ return c == data_[pos] ? pos : pos < size_ ? find(c, ++pos)
+ : npos;
+ }
+
+ /**
+ * @brief Equality operator.
+ *
+ * @param lhs The left-hand side basic_string_view.
+ * @param rhs The right-hand side basic_string_view.
+ * @return True if the strings are equal, otherwise false.
+ */
+ 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;
+ }
+
+ /**
+ * @brief Equality operator.
+ *
+ * @param lhs The left-hand side basic_string_view.
+ * @param rhs The right-hand side C-string.
+ * @return True if the strings are equal, otherwise false.
+ */
+ constexpr friend inline bool operator==(basic_string_view lhs,
+ const Char *rhs) noexcept
+ {
+ return (lhs.size_ == detail::strlen_constexpr(rhs)) &&
+ std::strncmp(lhs.data_, rhs, lhs.size_) == 0;
+ }
+
+ /**
+ * @brief Inequality operator.
+ *
+ * @param lhs The left-hand side basic_string_view.
+ * @param rhs The right-hand side basic_string_view.
+ * @return True if the strings are not equal, otherwise false.
+ */
+ constexpr friend inline bool
+ operator!=(basic_string_view lhs,
+ basic_string_view rhs) noexcept
+ {
+ return !(lhs == rhs);
+ }
+
+ /**
+ * @brief Inequality operator.
+ *
+ * @param lhs The left-hand side basic_string_view.
+ * @param rhs The right-hand side C-string.
+ * @return True if the strings are not equal, otherwise false.
+ */
+ constexpr friend inline bool operator!=(basic_string_view lhs,
+ const Char *rhs) noexcept
+ {
+ return !(lhs == rhs);
+ }
+
+ /**
+ * @brief Converts the string view to an std::string.
+ *
+ * @return An std::string representing the same string.
+ */
+ inline operator std::string() { return std::string(data_, size_); }
+
+ /**
+ * @brief Converts the string view to an std::string (const version).
+ *
+ * @return An std::string representing the same string.
+ */
+ inline operator std::string() const { return std::string(data_, size_); }
+
+ /**
+ * @brief Stream insertion operator.
+ *
+ * @param os The output stream.
+ * @param sv The basic_string_view.
+ * @return A reference to the output stream.
+ */
+ friend inline std::ostream &operator<<(std::ostream &os,
+ const basic_string_view &sv)
+ {
+ for (auto c : sv)
+ {
+ os << c;
+ }
+ return os;
+ }
+
+ static constexpr auto npos = -1;
+
+ private:
+ size_t size_;
+ const Char *data_;
+ };
+
+ using string_view = basic_string_view;
+
+#else
+#include
+
+ using string_view = std::string_view;
+
+#endif
+
+
+} // namespace mgutility
+
+#endif // STRING_STRING_VIEW_HPP
\ No newline at end of file
diff --git a/include/enum_name.hpp b/include/enum_name.hpp
index c7ed6ab..755b602 100644
--- a/include/enum_name.hpp
+++ b/include/enum_name.hpp
@@ -25,480 +25,176 @@
#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 {
+#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);
-}
-
-template
-MG_ENUM_NAME_CNSTXPR inline auto enum_name(Enum e) noexcept
- -> detail::string_view {
+ }
+
+ /**
+ * @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);
-}
-
-template ::min,
- int Max = enum_range::max>
-MG_ENUM_NAME_CNSTXPR inline auto enum_name(Enum e) noexcept
- -> detail::string_view {
+ }
+
+ /**
+ * @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);
-}
-
-template
-auto enum_for_each::enum_iter::operator*() const -> value_type {
+ }
+
+ /**
+ * @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::enum_iter::operator*() const -> value_type
+ {
auto value = static_cast(m_pos);
return detail::enum_pair