started transition to vulkan-hpp

This commit is contained in:
Mars 2024-09-29 20:12:56 -04:00
parent bda0032e44
commit 12c4d95aff
Signed by untrusted user: pupbrained
GPG key ID: 0FF5B8826803F895
3 changed files with 124 additions and 182 deletions

View file

@ -41,7 +41,6 @@
vulkan-extension-layer vulkan-extension-layer
vulkan-memory-allocator vulkan-memory-allocator
vulkan-utility-libraries vulkan-utility-libraries
vulkan-headers
vulkan-loader vulkan-loader
vulkan-tools vulkan-tools
]; ];

View file

@ -1,3 +1,6 @@
#define VULKAN_HPP_NO_CONSTRUCTORS
#include <vulkan/vulkan.hpp>
#define GLFW_INCLUDE_NONE #define GLFW_INCLUDE_NONE
#define GLFW_INCLUDE_VULKAN #define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
@ -11,7 +14,6 @@
#include <set> #include <set>
#include <span> #include <span>
#include <stdexcept> #include <stdexcept>
#include <vulkan/vulkan_core.h>
#include "util/magic_enum.hpp" #include "util/magic_enum.hpp"
#include "util/types.h" #include "util/types.h"
@ -144,44 +146,41 @@ class Application {
if (enableValidationLayers && !checkValidationLayerSupport()) if (enableValidationLayers && !checkValidationLayerSupport())
throw std::runtime_error("validation layers requested, but not available!"); throw std::runtime_error("validation layers requested, but not available!");
VkApplicationInfo appInfo {}; vk::ApplicationInfo appInfo { .pApplicationName = "Hello Triangle",
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; .applicationVersion = 1,
appInfo.pApplicationName = "Hello Triangle"; .pEngineName = "No Engine",
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0); .engineVersion = 1,
appInfo.pEngineName = "No Engine"; .apiVersion = VK_API_VERSION_1_1 };
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_0;
VkInstanceCreateInfo createInfo {}; vk::InstanceCreateInfo createInfo { .pApplicationInfo = &appInfo };
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pApplicationInfo = &appInfo;
// Retrieve extensions using custom function
std::vector<const char*> extensions = getRequiredExtensions(); std::vector<const char*> extensions = getRequiredExtensions();
VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo {}; vk::DebugUtilsMessengerCreateInfoEXT debugCreateInfo {};
if (enableValidationLayers) { if (enableValidationLayers) {
createInfo.enabledLayerCount = static_cast<u32>(validationLayers.size()); createInfo.setEnabledLayerCount(static_cast<uint32_t>(validationLayers.size()))
createInfo.ppEnabledLayerNames = validationLayers.data(); .setPpEnabledLayerNames(validationLayers.data());
populateDebugMessengerCreateInfo(debugCreateInfo); populateDebugMessengerCreateInfo(debugCreateInfo);
createInfo.pNext = static_cast<VkDebugUtilsMessengerCreateInfoEXT*>(&debugCreateInfo); createInfo.setPNext(&debugCreateInfo);
} else { } else {
createInfo.enabledLayerCount = 0; createInfo.setEnabledLayerCount(0).setPNext(nullptr);
createInfo.pNext = nullptr;
} }
extensions.emplace_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME); // Enable the portability extension and set flags
extensions.push_back(VK_KHR_PORTABILITY_ENUMERATION_EXTENSION_NAME);
createInfo.flags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR; createInfo.setEnabledExtensionCount(static_cast<uint32_t>(extensions.size()))
.setPpEnabledExtensionNames(extensions.data())
createInfo.enabledExtensionCount = static_cast<u32>(extensions.size()); .setFlags(vk::InstanceCreateFlagBits::eEnumeratePortabilityKHR);
createInfo.ppEnabledExtensionNames = extensions.data();
for (const char* extension : extensions) std::cout << extension << std::endl; for (const char* extension : extensions) std::cout << extension << std::endl;
if (vkCreateInstance(&createInfo, nullptr, &mInstance) != VK_SUCCESS) try {
throw std::runtime_error("failed to create instance!"); mInstance = vk::createInstance(createInfo);
} catch (const vk::SystemError& err) {
throw std::runtime_error("Failed to create instance: " + std::string(err.what()));
}
} }
static fn populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) -> void { static fn populateDebugMessengerCreateInfo(VkDebugUtilsMessengerCreateInfoEXT& createInfo) -> void {

View file

@ -78,16 +78,15 @@
#elif defined(__GNUC__) #elif defined(__GNUC__)
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'. #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'.
#pragma GCC diagnostic ignored "-Wuseless-cast" // suppresses 'static_cast<char_type>('\0')' for #pragma GCC diagnostic ignored "-Wuseless-cast" // suppresses 'static_cast<char_type>('\0')' for
// char_type = char (common on Linux). // char_type = char (common on Linux).
#elif defined(_MSC_VER) #elif defined(_MSC_VER)
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 26495) // Variable 'static_str<N>::chars_' is uninitialized. #pragma warning(disable : 26495) // Variable 'static_str<N>::chars_' is uninitialized.
#pragma warning(disable : 28020) // Arithmetic overflow: Using operator '-' on a 4 byte value and #pragma warning(disable : 28020) // Arithmetic overflow: Using operator '-' on a 4 byte value and
// then casting the result to a 8 byte value. // then casting the result to a 8 byte value.
#pragma warning(disable : 26451 \ #pragma warning(disable : 26451) // The expression '0<=_Param_(1)&&_Param_(1)<=1-1' is not true at this call.
) // The expression '0<=_Param_(1)&&_Param_(1)<=1-1' is not true at this call. #pragma warning(disable : 4514) // Unreferenced inline function has been removed.
#pragma warning(disable : 4514) // Unreferenced inline function has been removed.
#endif #endif
// Checks magic_enum compiler compatibility. // Checks magic_enum compiler compatibility.
@ -163,10 +162,8 @@ namespace magic_enum {
static_assert( static_assert(
[] { [] {
if constexpr (std::is_same_v<char_type, wchar_t>) { if constexpr (std::is_same_v<char_type, wchar_t>) {
constexpr const char c[] = constexpr const char c[] = "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|";
"abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|"; constexpr const wchar_t wc[] = L"abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|";
constexpr const wchar_t wc[] =
L"abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|";
static_assert( static_assert(
std::size(c) == std::size(wc), std::size(c) == std::size(wc),
"magic_enum::customize identifier characters are multichars in wchar_t." "magic_enum::customize identifier characters are multichars in wchar_t."
@ -209,8 +206,7 @@ namespace magic_enum {
class customize_t : public std::pair<detail::customize_tag, string_view> { class customize_t : public std::pair<detail::customize_tag, string_view> {
public: public:
constexpr customize_t(string_view srt) constexpr customize_t(string_view srt)
: std::pair<detail::customize_tag, string_view> { detail::customize_tag::custom_tag, srt } { : std::pair<detail::customize_tag, string_view> { detail::customize_tag::custom_tag, srt } {}
}
constexpr customize_t(const char_type* srt) : customize_t { string_view { srt } } {} constexpr customize_t(const char_type* srt) : customize_t { string_view { srt } } {}
constexpr customize_t(detail::customize_tag tag) constexpr customize_t(detail::customize_tag tag)
: std::pair<detail::customize_tag, string_view> { tag, string_view {} } { : std::pair<detail::customize_tag, string_view> { tag, string_view {} } {
@ -249,10 +245,7 @@ namespace magic_enum {
}; };
#endif #endif
template < template <auto V, typename E = std::decay_t<decltype(V)>, std::enable_if_t<std::is_enum_v<E>, int> = 0>
auto V,
typename E = std::decay_t<decltype(V)>,
std::enable_if_t<std::is_enum_v<E>, int> = 0>
using enum_constant = std::integral_constant<E, V>; using enum_constant = std::integral_constant<E, V>;
template <typename... T> template <typename... T>
@ -263,26 +256,22 @@ namespace magic_enum {
template <typename T> template <typename T>
struct has_is_flags<T, std::void_t<decltype(customize::enum_range<T>::is_flags)>> struct has_is_flags<T, std::void_t<decltype(customize::enum_range<T>::is_flags)>>
: std::bool_constant< : std::bool_constant<std::is_same_v<bool, std::decay_t<decltype(customize::enum_range<T>::is_flags)>>> {
std::is_same_v<bool, std::decay_t<decltype(customize::enum_range<T>::is_flags)>>> {}; };
template <typename T, typename = void> template <typename T, typename = void>
struct range_min : std::integral_constant<int, MAGIC_ENUM_RANGE_MIN> {}; struct range_min : std::integral_constant<int, MAGIC_ENUM_RANGE_MIN> {};
template <typename T> template <typename T>
struct range_min<T, std::void_t<decltype(customize::enum_range<T>::min)>> struct range_min<T, std::void_t<decltype(customize::enum_range<T>::min)>>
: std::integral_constant< : std::integral_constant<decltype(customize::enum_range<T>::min), customize::enum_range<T>::min> {};
decltype(customize::enum_range<T>::min),
customize::enum_range<T>::min> {};
template <typename T, typename = void> template <typename T, typename = void>
struct range_max : std::integral_constant<int, MAGIC_ENUM_RANGE_MAX> {}; struct range_max : std::integral_constant<int, MAGIC_ENUM_RANGE_MAX> {};
template <typename T> template <typename T>
struct range_max<T, std::void_t<decltype(customize::enum_range<T>::max)>> struct range_max<T, std::void_t<decltype(customize::enum_range<T>::max)>>
: std::integral_constant< : std::integral_constant<decltype(customize::enum_range<T>::max), customize::enum_range<T>::max> {};
decltype(customize::enum_range<T>::max),
customize::enum_range<T>::max> {};
struct str_view { struct str_view {
const char* str_ = nullptr; const char* str_ = nullptr;
@ -340,9 +329,7 @@ namespace magic_enum {
class case_insensitive { class case_insensitive {
static constexpr char_type to_lower(char_type c) noexcept { static constexpr char_type to_lower(char_type c) noexcept {
return (c >= static_cast<char_type>('A') && c <= static_cast<char_type>('Z')) return (c >= static_cast<char_type>('A') && c <= static_cast<char_type>('Z'))
? static_cast<char_type>( ? static_cast<char_type>(c + (static_cast<char_type>('a') - static_cast<char_type>('A')))
c + (static_cast<char_type>('a') - static_cast<char_type>('A'))
)
: c; : c;
} }
@ -381,8 +368,7 @@ namespace magic_enum {
template <typename BinaryPredicate> template <typename BinaryPredicate>
constexpr bool is_default_predicate() noexcept { constexpr bool is_default_predicate() noexcept {
return std:: return std::is_same_v<std::decay_t<BinaryPredicate>, std::equal_to<string_view::value_type>> ||
is_same_v<std::decay_t<BinaryPredicate>, std::equal_to<string_view::value_type>> ||
std::is_same_v<std::decay_t<BinaryPredicate>, std::equal_to<>>; std::is_same_v<std::decay_t<BinaryPredicate>, std::equal_to<>>;
} }
@ -393,11 +379,9 @@ namespace magic_enum {
} }
template <typename BinaryPredicate> template <typename BinaryPredicate>
constexpr bool cmp_equal( constexpr bool cmp_equal(string_view lhs, string_view rhs, [[maybe_unused]] BinaryPredicate&& p) noexcept(
string_view lhs, is_nothrow_invocable<BinaryPredicate>()
string_view rhs, ) {
[[maybe_unused]] BinaryPredicate&& p
) noexcept(is_nothrow_invocable<BinaryPredicate>()) {
#if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__) #if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__)
// https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html
// https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html // https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html
@ -427,8 +411,7 @@ namespace magic_enum {
template <typename L, typename R> template <typename L, typename R>
constexpr bool cmp_less(L lhs, R rhs) noexcept { constexpr bool cmp_less(L lhs, R rhs) noexcept {
static_assert( static_assert(
std::is_integral_v<L> && std::is_integral_v<R>, std::is_integral_v<L> && std::is_integral_v<R>, "magic_enum::detail::cmp_less requires integral type."
"magic_enum::detail::cmp_less requires integral type."
); );
if constexpr (std::is_signed_v<L> == std::is_signed_v<R>) { if constexpr (std::is_signed_v<L> == std::is_signed_v<R>) {
@ -465,8 +448,7 @@ namespace magic_enum {
#define MAGIC_ENUM_ARRAY_CONSTEXPR 1 #define MAGIC_ENUM_ARRAY_CONSTEXPR 1
#else #else
template <typename T, std::size_t N, std::size_t... I> template <typename T, std::size_t N, std::size_t... I>
constexpr std::array<std::remove_cv_t<T>, N> constexpr std::array<std::remove_cv_t<T>, N> to_array(T (&a)[N], std::index_sequence<I...>) noexcept {
to_array(T (&a)[N], std::index_sequence<I...>) noexcept {
return { { a[I]... } }; return { { a[I]... } };
} }
#endif #endif
@ -561,14 +543,11 @@ namespace magic_enum {
if constexpr (supported<decltype(V)>::value) { if constexpr (supported<decltype(V)>::value) {
#if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN) #if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN)
constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V); constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V);
auto name = auto name = name_ptr ? str_view { name_ptr, std::char_traits<char>::length(name_ptr) } : str_view {};
name_ptr ? str_view { name_ptr, std::char_traits<char>::length(name_ptr) } : str_view {};
#elif defined(__clang__) #elif defined(__clang__)
str_view name; str_view name;
if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) { if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) {
static_assert( static_assert(always_false_v<decltype(V)>, "magic_enum::detail::n requires __PRETTY_FUNCTION__.");
always_false_v<decltype(V)>, "magic_enum::detail::n requires __PRETTY_FUNCTION__."
);
return str_view {}; return str_view {};
} else { } else {
name.size_ = sizeof(__PRETTY_FUNCTION__) - 36; name.size_ = sizeof(__PRETTY_FUNCTION__) - 36;
@ -579,16 +558,13 @@ namespace magic_enum {
name.size_ -= 23; name.size_ -= 23;
name.str_ += 23; name.str_ += 23;
} }
if (name.str_[0] == '(' || name.str_[0] == '-' || if (name.str_[0] == '(' || name.str_[0] == '-' || (name.str_[0] >= '0' && name.str_[0] <= '9')) {
(name.str_[0] >= '0' && name.str_[0] <= '9')) {
name = str_view {}; name = str_view {};
} }
#elif defined(__GNUC__) #elif defined(__GNUC__)
auto name = str_view { __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1 }; auto name = str_view { __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1 };
if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) { if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) {
static_assert( static_assert(always_false_v<decltype(V)>, "magic_enum::detail::n requires __PRETTY_FUNCTION__.");
always_false_v<decltype(V)>, "magic_enum::detail::n requires __PRETTY_FUNCTION__."
);
return str_view {}; return str_view {};
} else if (name.str_[name.size_ - 1] == ']') { } else if (name.str_[name.size_ - 1] == ']') {
name.size_ -= 55; name.size_ -= 55;
@ -640,8 +616,7 @@ namespace magic_enum {
#if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN) #if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN)
constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V); constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V);
auto name = auto name = name_ptr ? str_view { name_ptr, std::char_traits<char>::length(name_ptr) } : str_view {};
name_ptr ? str_view { name_ptr, std::char_traits<char>::length(name_ptr) } : str_view {};
#else #else
// CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284). // CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284).
str_view name; str_view name;
@ -658,8 +633,7 @@ namespace magic_enum {
name.size_ -= p; name.size_ -= p;
name.str_ += p; name.str_ += p;
} }
if (name.str_[0] == '(' || name.str_[0] == '-' || if (name.str_[0] == '(' || name.str_[0] == '-' || (name.str_[0] >= '0' && name.str_[0] <= '9')) {
(name.str_[0] >= '0' && name.str_[0] <= '9')) {
name = str_view {}; name = str_view {};
} }
return name; return name;
@ -775,32 +749,29 @@ namespace magic_enum {
} }
} }
#define MAGIC_ENUM_FOR_EACH_256(T) \ #define MAGIC_ENUM_FOR_EACH_256(T) \
T(0) \ T(0) \
T(1) T(2) T(3) T(4) T(5) T(6) T(7) T(8) T(9) T(10) T(11) T(12) T(13) T(14) T(15) T(16) T(17) \ T(1) \
T(18) T(19) T(20) T(21) T(22) T(23) T(24) T(25) T(26) T(27) T(28) T(29) T(30) T(31) T(32) \ T(2) T(3) T(4) T(5) T(6) T(7) T(8) T(9) T(10) T(11) T(12) T(13) T(14) T(15) T(16) T(17) T(18) T(19) T(20) \
T(33) T(34) T(35) T(36) T(37) T(38) T(39) T(40) T(41) T(42) T(43) T(44) T(45) T(46) T(47) \ T(21) T(22) T(23) T(24) T(25) T(26) T(27) T(28) T(29) T(30) T(31) T(32) T(33) T(34) T(35) T(36) T(37) \
T(48) T(49) T(50) T(51) T(52) T(53) T(54) T(55) T(56) T(57) T(58) T(59) T(60) T(61) T(62) \ T(38) T(39) T(40) T(41) T(42) T(43) T(44) T(45) T(46) T(47) T(48) T(49) T(50) T(51) T(52) T(53) T(54) \
T(63) T(64) T(65) T(66) T(67) T(68) T(69) T(70) T(71) T(72) T(73) T(74) T(75) T(76) \ T(55) T(56) T(57) T(58) T(59) T(60) T(61) T(62) T(63) T(64) T(65) T(66) T(67) T(68) T(69) T(70) \
T(77) T(78) T(79) T(80) T(81) T(82) T(83) T(84) T(85) T(86) T(87) T(88) T(89) T(90) \ T(71) T(72) T(73) T(74) T(75) T(76) T(77) T(78) T(79) T(80) T(81) T(82) T(83) T(84) T(85) T(86) \
T(91) T(92) T(93) T(94) T(95) T(96) T(97) T(98) T(99) T(100) T(101) T(102) T(103) \ T(87) T(88) T(89) T(90) T(91) T(92) T(93) T(94) T(95) T(96) T(97) T(98) T(99) T(100) T(101) \
T(104) T(105) T(106) T(107) T(108) T(109) T(110) T(111) T(112) T(113) T(114) \ T(102) T(103) T(104) T(105) T(106) T(107) T(108) T(109) T(110) T(111) T(112) T(113) T(114) \
T(115) T(116) T(117) T(118) T(119) T(120) T(121) T(122) T(123) T(124) T(125) \ T(115) T(116) T(117) T(118) T(119) T(120) T(121) T(122) T(123) T(124) T(125) T(126) T(127) \
T(126) T(127) T(128) T(129) T(130) T(131) T(132) T(133) T(134) T(135) T(136) \ T(128) T(129) T(130) T(131) T(132) T(133) T(134) T(135) T(136) T(137) T(138) T(139) T(140) \
T(137) T(138) T(139) T(140) T(141) T(142) T(143) T(144) T(145) T(146) T(147) \ T(141) T(142) T(143) T(144) T(145) T(146) T(147) T(148) T(149) T(150) T(151) T(152) \
T(148) T(149) T(150) T(151) T(152) T(153) T(154) T(155) T(156) T(157) \ T(153) T(154) T(155) T(156) T(157) T(158) T(159) T(160) T(161) T(162) T(163) T(164) \
T(158) T(159) T(160) T(161) T(162) T(163) T(164) T(165) T(166) T(167) \ T(165) T(166) T(167) T(168) T(169) T(170) T(171) T(172) T(173) T(174) T(175) T(176) \
T(168) T(169) T(170) T(171) T(172) T(173) T(174) T(175) T(176) T(177) \ T(177) T(178) T(179) T(180) T(181) T(182) T(183) T(184) T(185) T(186) T(187) \
T(178) T(179) T(180) T(181) T(182) T(183) T(184) T(185) T(186) \ T(188) T(189) T(190) T(191) T(192) T(193) T(194) T(195) T(196) T(197) T(198) \
T(187) T(188) T(189) T(190) T(191) T(192) T(193) T(194) T(195) \ T(199) T(200) T(201) T(202) T(203) T(204) T(205) T(206) T(207) T(208) T(209) \
T(196) T(197) T(198) T(199) T(200) T(201) T(202) T(203) T(204) \ T(210) T(211) T(212) T(213) T(214) T(215) T(216) T(217) T(218) T(219) T(220) \
T(205) T(206) T(207) T(208) T(209) T(210) T(211) T(212) T(213) \ T(221) T(222) T(223) T(224) T(225) T(226) T(227) T(228) T(229) T(230) \
T(214) T(215) T(216) T(217) T(218) T(219) T(220) T(221) \ T(231) T(232) T(233) T(234) T(235) T(236) T(237) T(238) T(239) T(240) \
T(222) T(223) T(224) T(225) T(226) T(227) T(228) T(229) \ T(241) T(242) T(243) T(244) T(245) T(246) T(247) T(248) T(249) T(250) \
T(230) T(231) T(232) T(233) T(234) T(235) T(236) T(237) \ T(251) T(252) T(253) T(254) T(255)
T(238) T(239) T(240) T(241) T(242) T(243) T(244) \
T(245) T(246) T(247) T(248) T(249) T(250) T(251) \
T(252) T(253) T(254) T(255)
template <typename E, enum_subtype S, std::size_t Size, int Min, std::size_t I> template <typename E, enum_subtype S, std::size_t Size, int Min, std::size_t I>
constexpr void valid_count(bool* valid, std::size_t& count) noexcept { constexpr void valid_count(bool* valid, std::size_t& count) noexcept {
@ -913,12 +884,10 @@ namespace magic_enum {
inline constexpr auto count_v = values_v<E, S>.size(); inline constexpr auto count_v = values_v<E, S>.size();
template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>> template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
inline constexpr auto min_v = inline constexpr auto min_v = (count_v<E, S> > 0) ? static_cast<U>(values_v<E, S>.front()) : U { 0 };
(count_v<E, S> > 0) ? static_cast<U>(values_v<E, S>.front()) : U { 0 };
template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>> template <typename E, enum_subtype S, typename U = std::underlying_type_t<E>>
inline constexpr auto max_v = inline constexpr auto max_v = (count_v<E, S> > 0) ? static_cast<U>(values_v<E, S>.back()) : U { 0 };
(count_v<E, S> > 0) ? static_cast<U>(values_v<E, S>.back()) : U { 0 };
template <typename E, enum_subtype S, std::size_t... I> template <typename E, enum_subtype S, std::size_t... I>
constexpr auto names(std::index_sequence<I...>) noexcept { constexpr auto names(std::index_sequence<I...>) noexcept {
@ -1094,9 +1063,8 @@ namespace magic_enum {
constexpr std::uint32_t operator()(string_view value) const noexcept { constexpr std::uint32_t operator()(string_view value) const noexcept {
auto acc = static_cast<std::uint64_t>(2166136261ULL); auto acc = static_cast<std::uint64_t>(2166136261ULL);
for (const auto c : value) { for (const auto c : value) {
acc = acc = ((acc ^ static_cast<std::uint64_t>(c)) * static_cast<std::uint64_t>(16777619ULL)) &
((acc ^ static_cast<std::uint64_t>(c)) * static_cast<std::uint64_t>(16777619ULL)) & (std::numeric_limits<std::uint32_t>::max)();
(std::numeric_limits<std::uint32_t>::max)();
} }
return static_cast<std::uint32_t>(acc); return static_cast<std::uint32_t>(acc);
} }
@ -1140,8 +1108,7 @@ namespace magic_enum {
} }
template <typename R, typename F, typename... Args> template <typename R, typename F, typename... Args>
constexpr R constexpr R invoke_r(F&& f, Args&&... args) noexcept(std::is_nothrow_invocable_r_v<R, F, Args...>) {
invoke_r(F&& f, Args&&... args) noexcept(std::is_nothrow_invocable_r_v<R, F, Args...>) {
if constexpr (std::is_void_v<R>) { if constexpr (std::is_void_v<R>) {
std::forward<F>(f)(std::forward<Args>(args)...); std::forward<F>(f)(std::forward<Args>(args)...);
} else { } else {
@ -1181,47 +1148,41 @@ namespace magic_enum {
return true; return true;
} }
#define MAGIC_ENUM_CASE(val) \ #define MAGIC_ENUM_CASE(val) \
case cases[val]: \ case cases[val]: \
if constexpr ((val) + Page < size) { \ if constexpr ((val) + Page < size) { \
if (!pred(values[val + Page], searched)) { \ if (!pred(values[val + Page], searched)) { \
break; \ break; \
} \ } \
if constexpr (CallValue == case_call_t::index) { \ if constexpr (CallValue == case_call_t::index) { \
if constexpr (std::is_invocable_r_v< \ if constexpr (std::is_invocable_r_v< \
result_t, \ result_t, \
Lambda, \ Lambda, \
std::integral_constant<std::size_t, val + Page>>) { \ std::integral_constant<std::size_t, val + Page>>) { \
return detail::invoke_r<result_t>( \ return detail::invoke_r<result_t>( \
std::forward<Lambda>(lambda), std::integral_constant<std::size_t, val + Page> {} \ std::forward<Lambda>(lambda), std::integral_constant<std::size_t, val + Page> {} \
); \ ); \
} else if constexpr (std::is_invocable_v< \ } else if constexpr (std::is_invocable_v<Lambda, std::integral_constant<std::size_t, val + Page>>) { \
Lambda, \ MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \
std::integral_constant<std::size_t, val + Page>>) { \ } \
MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \ } else if constexpr (CallValue == case_call_t::value) { \
} \ if constexpr (std::is_invocable_r_v<result_t, Lambda, enum_constant<values[val + Page]>>) { \
} else if constexpr (CallValue == case_call_t::value) { \ return detail::invoke_r<result_t>( \
if constexpr (std:: \ std::forward<Lambda>(lambda), enum_constant<values[val + Page]> {} \
is_invocable_r_v<result_t, Lambda, enum_constant<values[val + Page]>>) { \ ); \
return detail::invoke_r<result_t>( \ } else if constexpr (std::is_invocable_r_v<result_t, Lambda, enum_constant<values[val + Page]>>) { \
std::forward<Lambda>(lambda), enum_constant<values[val + Page]> {} \ MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \
); \ } \
} else if constexpr (std::is_invocable_r_v< \ } \
result_t, \ break; \
Lambda, \ } else \
enum_constant<values[val + Page]>>) { \
MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \
} \
} \
break; \
} else \
[[fallthrough]]; [[fallthrough]];
template < template <
auto* GlobValues, auto* GlobValues,
case_call_t CallValue, case_call_t CallValue,
std::size_t Page = 0, std::size_t Page = 0,
typename Hash = constexpr_hash_t<typename std::decay_t<decltype(*GlobValues)>::value_type>, typename Hash = constexpr_hash_t<typename std::decay_t<decltype(*GlobValues)>::value_type>,
typename BinaryPredicate = std::equal_to<>, typename BinaryPredicate = std::equal_to<>,
typename Lambda, typename Lambda,
typename ResultGetterType> typename ResultGetterType>
@ -1328,8 +1289,8 @@ namespace magic_enum {
if constexpr (detail::is_sparse_v<D, S>) { if constexpr (detail::is_sparse_v<D, S>) {
return MAGIC_ENUM_ASSERT(index < detail::count_v<D, S>), detail::values_v<D, S>[index]; return MAGIC_ENUM_ASSERT(index < detail::count_v<D, S>), detail::values_v<D, S>[index];
} else { } else {
constexpr auto min = (S == detail::enum_subtype::flags) ? detail::log2(detail::min_v<D, S>) constexpr auto min =
: detail::min_v<D, S>; (S == detail::enum_subtype::flags) ? detail::log2(detail::min_v<D, S>) : detail::min_v<D, S>;
return MAGIC_ENUM_ASSERT(index < detail::count_v<D, S>), detail::value<D, min, S>(index); return MAGIC_ENUM_ASSERT(index < detail::count_v<D, S>), detail::value<D, min, S>(index);
} }
@ -1349,8 +1310,7 @@ namespace magic_enum {
// Returns std::array with enum values, sorted by enum value. // Returns std::array with enum values, sorted by enum value.
template <typename E, detail::enum_subtype S = detail::subtype_v<E>> template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_values() noexcept [[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_t<E, detail::values_t<E, S>> {
-> detail::enable_if_t<E, detail::values_t<E, S>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
static_assert( static_assert(
detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min." detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min."
@ -1376,8 +1336,7 @@ namespace magic_enum {
// Obtains index in enum values from enum value. // Obtains index in enum values from enum value.
// Returns optional with index. // Returns optional with index.
template <typename E, detail::enum_subtype S = detail::subtype_v<E>> template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_index(E value [[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t<E, optional<std::size_t>> {
) noexcept -> detail::enable_if_t<E, optional<std::size_t>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
using U = underlying_type_t<D>; using U = underlying_type_t<D>;
static_assert( static_assert(
@ -1410,8 +1369,7 @@ namespace magic_enum {
// Obtains index in enum values from enum value. // Obtains index in enum values from enum value.
// Returns optional with index. // Returns optional with index.
template <detail::enum_subtype S, typename E> template <detail::enum_subtype S, typename E>
[[nodiscard]] constexpr auto enum_index(E value [[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t<E, optional<std::size_t>> {
) noexcept -> detail::enable_if_t<E, optional<std::size_t>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
static_assert( static_assert(
detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min." detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min."
@ -1422,8 +1380,7 @@ namespace magic_enum {
// Obtains index in enum values from static storage enum variable. // Obtains index in enum values from static storage enum variable.
template <auto V, detail::enum_subtype S = detail::subtype_v<std::decay_t<decltype(V)>>> template <auto V, detail::enum_subtype S = detail::subtype_v<std::decay_t<decltype(V)>>>
[[nodiscard]] constexpr auto enum_index() noexcept [[nodiscard]] constexpr auto enum_index() noexcept -> detail::enable_if_t<decltype(V), std::size_t> {
-> detail::enable_if_t<decltype(V), std::size_t> {
using D = std::decay_t<decltype(V)>; using D = std::decay_t<decltype(V)>;
static_assert( static_assert(
detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min." detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min."
@ -1438,8 +1395,7 @@ namespace magic_enum {
// This version is much lighter on the compile times and is not restricted to the enum_range // This version is much lighter on the compile times and is not restricted to the enum_range
// limitation. // limitation.
template <auto V> template <auto V>
[[nodiscard]] constexpr auto enum_name() noexcept [[nodiscard]] constexpr auto enum_name() noexcept -> detail::enable_if_t<decltype(V), string_view> {
-> detail::enable_if_t<decltype(V), string_view> {
constexpr string_view name = detail::enum_name_v<std::decay_t<decltype(V)>, V>; constexpr string_view name = detail::enum_name_v<std::decay_t<decltype(V)>, V>;
static_assert(!name.empty(), "magic_enum::enum_name enum value does not have a name."); static_assert(!name.empty(), "magic_enum::enum_name enum value does not have a name.");
@ -1475,8 +1431,7 @@ namespace magic_enum {
// Returns std::array with names, sorted by enum value. // Returns std::array with names, sorted by enum value.
template <typename E, detail::enum_subtype S = detail::subtype_v<E>> template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_names() noexcept [[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_t<E, detail::names_t<E, S>> {
-> detail::enable_if_t<E, detail::names_t<E, S>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
static_assert( static_assert(
detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min." detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min."
@ -1487,8 +1442,7 @@ namespace magic_enum {
// Returns std::array with pairs (value, name), sorted by enum value. // Returns std::array with pairs (value, name), sorted by enum value.
template <typename E, detail::enum_subtype S = detail::subtype_v<E>> template <typename E, detail::enum_subtype S = detail::subtype_v<E>>
[[nodiscard]] constexpr auto enum_entries() noexcept [[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_t<E, detail::entries_t<E, S>> {
-> detail::enable_if_t<E, detail::entries_t<E, S>> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
static_assert( static_assert(
detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min." detail::is_reflected_v<D, S>, "magic_enum requires enum implementation and valid max and min."
@ -1538,10 +1492,8 @@ namespace magic_enum {
typename E, typename E,
detail::enum_subtype S = detail::subtype_v<E>, detail::enum_subtype S = detail::subtype_v<E>,
typename BinaryPredicate = std::equal_to<>> typename BinaryPredicate = std::equal_to<>>
[[nodiscard]] constexpr auto enum_cast( [[nodiscard]] constexpr auto enum_cast(string_view value, [[maybe_unused]] BinaryPredicate p = {}) noexcept(
string_view value, detail::is_nothrow_invocable<BinaryPredicate>()
[[maybe_unused]] BinaryPredicate p = {}
) noexcept(detail::is_nothrow_invocable<BinaryPredicate>()
) -> detail::enable_if_t<E, optional<std::decay_t<E>>, BinaryPredicate> { ) -> detail::enable_if_t<E, optional<std::decay_t<E>>, BinaryPredicate> {
using D = std::decay_t<E>; using D = std::decay_t<E>;
static_assert( static_assert(
@ -1638,12 +1590,10 @@ namespace magic_enum {
} }
template <bool AsFlags = true> template <bool AsFlags = true>
inline constexpr auto as_flags = inline constexpr auto as_flags = AsFlags ? detail::enum_subtype::flags : detail::enum_subtype::common;
AsFlags ? detail::enum_subtype::flags : detail::enum_subtype::common;
template <bool AsFlags = true> template <bool AsFlags = true>
inline constexpr auto as_common = inline constexpr auto as_common = AsFlags ? detail::enum_subtype::common : detail::enum_subtype::flags;
AsFlags ? detail::enum_subtype::common : detail::enum_subtype::flags;
namespace bitwise_operators { namespace bitwise_operators {
@ -1654,23 +1604,17 @@ namespace magic_enum {
template <typename E, detail::enable_if_t<E, int> = 0> template <typename E, detail::enable_if_t<E, int> = 0>
constexpr E operator|(E lhs, E rhs) noexcept { constexpr E operator|(E lhs, E rhs) noexcept {
return static_cast<E>( return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) | static_cast<underlying_type_t<E>>(rhs));
static_cast<underlying_type_t<E>>(lhs) | static_cast<underlying_type_t<E>>(rhs)
);
} }
template <typename E, detail::enable_if_t<E, int> = 0> template <typename E, detail::enable_if_t<E, int> = 0>
constexpr E operator&(E lhs, E rhs) noexcept { constexpr E operator&(E lhs, E rhs) noexcept {
return static_cast<E>( return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) & static_cast<underlying_type_t<E>>(rhs));
static_cast<underlying_type_t<E>>(lhs) & static_cast<underlying_type_t<E>>(rhs)
);
} }
template <typename E, detail::enable_if_t<E, int> = 0> template <typename E, detail::enable_if_t<E, int> = 0>
constexpr E operator^(E lhs, E rhs) noexcept { constexpr E operator^(E lhs, E rhs) noexcept {
return static_cast<E>( return static_cast<E>(static_cast<underlying_type_t<E>>(lhs) ^ static_cast<underlying_type_t<E>>(rhs));
static_cast<underlying_type_t<E>>(lhs) ^ static_cast<underlying_type_t<E>>(rhs)
);
} }
template <typename E, detail::enable_if_t<E, int> = 0> template <typename E, detail::enable_if_t<E, int> = 0>