Introduce spaceship operator<=> on Flags with C++20, replacing all the relational operators

+ replace variables/struct members named "requires" with "requirements"
This commit is contained in:
asuessenbach 2020-02-26 14:24:58 +01:00 committed by Markus Tavenrath
parent 8983df9269
commit 1b22ac9658
3 changed files with 2192 additions and 38 deletions

View File

@ -838,9 +838,9 @@ void VulkanHppGenerator::appendBitmasks(std::string & str) const
{ {
for (auto const& bitmask : m_bitmasks) for (auto const& bitmask : m_bitmasks)
{ {
auto bitmaskBits = m_enums.find(bitmask.second.requires); auto bitmaskBits = m_enums.find(bitmask.second.requirements);
bool hasBits = (bitmaskBits != m_enums.end()); bool hasBits = (bitmaskBits != m_enums.end());
check(bitmask.second.requires.empty() || hasBits, bitmask.second.xmlLine, "bitmask <" + bitmask.first + "> references the undefined requires <" + bitmask.second.requires + ">"); check(bitmask.second.requirements.empty() || hasBits, bitmask.second.xmlLine, "bitmask <" + bitmask.first + "> references the undefined requires <" + bitmask.second.requirements + ">");
std::string strippedBitmaskName = stripPrefix(bitmask.first, "Vk"); std::string strippedBitmaskName = stripPrefix(bitmask.first, "Vk");
std::string strippedEnumName = hasBits ? stripPrefix(bitmaskBits->first, "Vk") : ""; std::string strippedEnumName = hasBits ? stripPrefix(bitmaskBits->first, "Vk") : "";
@ -1419,7 +1419,7 @@ void VulkanHppGenerator::appendEnum(std::string & str, std::pair<std::string, En
str += " enum class " + stripPrefix(enumData.first, "Vk"); str += " enum class " + stripPrefix(enumData.first, "Vk");
if (enumData.second.isBitmask) if (enumData.second.isBitmask)
{ {
auto bitmaskIt = std::find_if(m_bitmasks.begin(), m_bitmasks.end(), [&enumData](auto const& bitmask){ return bitmask.second.requires == enumData.first; }); auto bitmaskIt = std::find_if(m_bitmasks.begin(), m_bitmasks.end(), [&enumData](auto const& bitmask){ return bitmask.second.requirements == enumData.first; });
assert(bitmaskIt != m_bitmasks.end()); assert(bitmaskIt != m_bitmasks.end());
str += " : " + bitmaskIt->first; str += " : " + bitmaskIt->first;
} }
@ -2124,7 +2124,7 @@ void VulkanHppGenerator::appendFunctionHeaderArgumentEnhancedSimple(std::string
{ {
// get the enum corresponding to this flag, to check if it's empty // get the enum corresponding to this flag, to check if it's empty
std::string strippedBitmaskName = stripPrefix(bitmasksIt->first, "Vk"); std::string strippedBitmaskName = stripPrefix(bitmasksIt->first, "Vk");
std::map<std::string, EnumData>::const_iterator enumIt = m_enums.find(bitmasksIt->second.requires); std::map<std::string, EnumData>::const_iterator enumIt = m_enums.find(bitmasksIt->second.requirements);
assert((enumIt == m_enums.end()) || (enumIt->second.isBitmask)); assert((enumIt == m_enums.end()) || (enumIt->second.isBitmask));
if ((enumIt == m_enums.end()) || (enumIt->second.values.empty())) if ((enumIt == m_enums.end()) || (enumIt->second.values.empty()))
{ {
@ -2283,7 +2283,7 @@ bool VulkanHppGenerator::appendFunctionHeaderArgumentStandard(std::string & str,
{ {
// get the enum corresponding to this flag, to check if it's empty // get the enum corresponding to this flag, to check if it's empty
std::string strippedBitmaskName = stripPrefix(bitmasksIt->first, "Vk"); std::string strippedBitmaskName = stripPrefix(bitmasksIt->first, "Vk");
std::map<std::string, EnumData>::const_iterator enumIt = m_enums.find(bitmasksIt->second.requires); std::map<std::string, EnumData>::const_iterator enumIt = m_enums.find(bitmasksIt->second.requirements);
assert((enumIt == m_enums.end()) || (enumIt->second.isBitmask)); assert((enumIt == m_enums.end()) || (enumIt->second.isBitmask));
if ((enumIt == m_enums.end()) || (enumIt->second.values.empty())) if ((enumIt == m_enums.end()) || (enumIt->second.values.empty()))
{ {
@ -2509,6 +2509,9 @@ ${enter} class ${className}
return *this; return *this;
} }
#if defined(VULKAN_HPP_HAS_SPACESHIP_OPERATOR)
auto operator<=>( ${className} const& ) const = default;
#else
bool operator==( ${className} const & rhs ) const VULKAN_HPP_NOEXCEPT bool operator==( ${className} const & rhs ) const VULKAN_HPP_NOEXCEPT
{ {
return m_${memberName} == rhs.m_${memberName}; return m_${memberName} == rhs.m_${memberName};
@ -2523,6 +2526,7 @@ ${enter} class ${className}
{ {
return m_${memberName} < rhs.m_${memberName}; return m_${memberName} < rhs.m_${memberName};
} }
#endif
${commands} ${commands}
VULKAN_HPP_TYPESAFE_EXPLICIT operator Vk${className}() const VULKAN_HPP_NOEXCEPT VULKAN_HPP_TYPESAFE_EXPLICIT operator Vk${className}() const VULKAN_HPP_NOEXCEPT
{ {
@ -2760,6 +2764,9 @@ void VulkanHppGenerator::appendStructCompareOperators(std::string & str, std::pa
} }
static const std::string compareTemplate = R"( static const std::string compareTemplate = R"(
#if defined(VULKAN_HPP_HAS_SPACESHIP_OPERATOR)
auto operator<=>( ${name} const& ) const = default;
#else
bool operator==( ${name} const& rhs ) const VULKAN_HPP_NOEXCEPT bool operator==( ${name} const& rhs ) const VULKAN_HPP_NOEXCEPT
{ {
return ${compareMembers}; return ${compareMembers};
@ -2769,6 +2776,7 @@ void VulkanHppGenerator::appendStructCompareOperators(std::string & str, std::pa
{ {
return !operator==( rhs ); return !operator==( rhs );
} }
#endif
)"; )";
str += replaceWithMap(compareTemplate, { { "name", stripPrefix(structData.first, "Vk") }, { "compareMembers", compareMembers } }); str += replaceWithMap(compareTemplate, { { "name", stripPrefix(structData.first, "Vk") }, { "compareMembers", compareMembers } });
@ -3379,9 +3387,9 @@ void VulkanHppGenerator::checkCorrectness()
} }
for (auto const& bitmask : m_bitmasks) for (auto const& bitmask : m_bitmasks)
{ {
if (!bitmask.second.requires.empty()) if (!bitmask.second.requirements.empty())
{ {
check(m_enums.find(bitmask.second.requires) != m_enums.end(), bitmask.second.xmlLine, "bitmask requires unknown <" + bitmask.second.requires + ">"); check(m_enums.find(bitmask.second.requirements) != m_enums.end(), bitmask.second.xmlLine, "bitmask requires unknown <" + bitmask.second.requirements + ">");
} }
} }
for (auto const& extension : m_extensions) for (auto const& extension : m_extensions)
@ -3401,16 +3409,16 @@ void VulkanHppGenerator::checkCorrectness()
check((m_extensions.find(extension.second.promotedTo) != m_extensions.end()) || (m_features.find(extension.second.promotedTo) != m_features.end()) check((m_extensions.find(extension.second.promotedTo) != m_extensions.end()) || (m_features.find(extension.second.promotedTo) != m_features.end())
, extension.second.xmlLine, "extension promoted to unknown extension/version <" + extension.second.promotedTo + ">"); , extension.second.xmlLine, "extension promoted to unknown extension/version <" + extension.second.promotedTo + ">");
} }
for (auto const& require : extension.second.requires) for (auto const& require : extension.second.requirements)
{ {
check(m_extensions.find(require.first) != m_extensions.end(), require.second, "unknown extension requirement <" + require.first + ">"); check(m_extensions.find(require.first) != m_extensions.end(), require.second, "unknown extension requires <" + require.first + ">");
} }
} }
for (auto const& funcPointer : m_funcPointers) for (auto const& funcPointer : m_funcPointers)
{ {
if (!funcPointer.second.requires.empty()) if (!funcPointer.second.requirements.empty())
{ {
check(m_types.find(funcPointer.second.requires) != m_types.end(), funcPointer.second.xmlLine, "funcpointer requires unknown <" + funcPointer.second.requires + ">"); check(m_types.find(funcPointer.second.requirements) != m_types.end(), funcPointer.second.xmlLine, "funcpointer requires unknown <" + funcPointer.second.requirements + ">");
} }
} }
for (auto const& structure : m_structures) for (auto const& structure : m_structures)
@ -3761,12 +3769,12 @@ void VulkanHppGenerator::readBitmask(tinyxml2::XMLElement const* element, std::m
{ {
checkAttributes(line, attributes, { { "category",{ "bitmask" } } }, { { "requires",{} } }); checkAttributes(line, attributes, { { "category",{ "bitmask" } } }, { { "requires",{} } });
std::string requires; std::string requirements;
for (auto const& attribute : attributes) for (auto const& attribute : attributes)
{ {
if (attribute.first == "requires") if (attribute.first == "requires")
{ {
requires = attribute.second; requirements = attribute.second;
} }
} }
@ -3783,7 +3791,7 @@ void VulkanHppGenerator::readBitmask(tinyxml2::XMLElement const* element, std::m
check(m_commandToHandle.find(nameData.name) == m_commandToHandle.end(), line, "command <" + nameData.name + "> already specified"); check(m_commandToHandle.find(nameData.name) == m_commandToHandle.end(), line, "command <" + nameData.name + "> already specified");
m_bitmasks.insert(std::make_pair(nameData.name, BitmaskData(requires, line))); m_bitmasks.insert(std::make_pair(nameData.name, BitmaskData(requirements, line)));
check(m_types.insert(nameData.name).second, line, "bitmask <" + nameData.name + "> already specified as a type"); check(m_types.insert(nameData.name).second, line, "bitmask <" + nameData.name + "> already specified as a type");
} }
} }
@ -4179,10 +4187,10 @@ void VulkanHppGenerator::readEnums(tinyxml2::XMLElement const* element)
if (bitmask) if (bitmask)
{ {
// look for the corresponding bitmask and set the requirements if needed! // look for the corresponding bitmask and set the requirements if needed!
auto bitmaskIt = std::find_if(m_bitmasks.begin(), m_bitmasks.end(), [&name](auto const& bitmask) { return bitmask.second.requires == name; }); auto bitmaskIt = std::find_if(m_bitmasks.begin(), m_bitmasks.end(), [&name](auto const& bitmask) { return bitmask.second.requirements == name; });
if (bitmaskIt == m_bitmasks.end()) if (bitmaskIt == m_bitmasks.end())
{ {
warn(false, line, "enum <" + name + "> is not listed as an requirement for any bitmask in the types section"); warn(false, line, "enum <" + name + "> is not listed as an requires for any bitmask in the types section");
std::string bitmaskName = name; std::string bitmaskName = name;
size_t pos = bitmaskName.rfind("FlagBits"); size_t pos = bitmaskName.rfind("FlagBits");
@ -4191,8 +4199,8 @@ void VulkanHppGenerator::readEnums(tinyxml2::XMLElement const* element)
bitmaskIt = m_bitmasks.find(bitmaskName); bitmaskIt = m_bitmasks.find(bitmaskName);
check(bitmaskIt != m_bitmasks.end(), line, "enum <" + name + "> has not corresponding bitmask <" + bitmaskName + "> listed in the types section"); check(bitmaskIt != m_bitmasks.end(), line, "enum <" + name + "> has not corresponding bitmask <" + bitmaskName + "> listed in the types section");
assert(bitmaskIt->second.requires.empty()); assert(bitmaskIt->second.requirements.empty());
bitmaskIt->second.requires = name; bitmaskIt->second.requirements = name;
} }
} }
@ -4241,7 +4249,7 @@ void VulkanHppGenerator::readExtension(tinyxml2::XMLElement const* element)
checkElements(line, children, {}, { "require" }); checkElements(line, children, {}, { "require" });
std::string deprecatedBy, name, obsoletedBy, platform, promotedTo, supported; std::string deprecatedBy, name, obsoletedBy, platform, promotedTo, supported;
std::vector<std::string> requires; std::vector<std::string> requirements;
for (auto const& attribute : attributes) for (auto const& attribute : attributes)
{ {
if (attribute.first == "deprecatedby") if (attribute.first == "deprecatedby")
@ -4267,7 +4275,7 @@ void VulkanHppGenerator::readExtension(tinyxml2::XMLElement const* element)
} }
else if (attribute.first == "requires") else if (attribute.first == "requires")
{ {
requires = tokenize(attribute.second, ','); requirements = tokenize(attribute.second, ',');
} }
else if (attribute.first == "requiresCore") else if (attribute.first == "requiresCore")
{ {
@ -4296,15 +4304,15 @@ void VulkanHppGenerator::readExtension(tinyxml2::XMLElement const* element)
pitb.first->second.deprecatedBy = deprecatedBy; pitb.first->second.deprecatedBy = deprecatedBy;
pitb.first->second.obsoletedBy = obsoletedBy; pitb.first->second.obsoletedBy = obsoletedBy;
pitb.first->second.promotedTo = promotedTo; pitb.first->second.promotedTo = promotedTo;
for (auto const& r : requires) for (auto const& r : requirements)
{ {
check(pitb.first->second.requires.insert(std::make_pair(r, line)).second, line, "required extension <" + r + "> already listed"); check(pitb.first->second.requirements.insert(std::make_pair(r, line)).second, line, "required extension <" + r + "> already listed");
} }
std::string tag = extractTag(line, name, m_tags); std::string tag = extractTag(line, name, m_tags);
for (auto child : children) for (auto child : children)
{ {
readExtensionRequire(child, platform, tag, pitb.first->second.requires); readExtensionRequire(child, platform, tag, pitb.first->second.requirements);
} }
} }
} }
@ -4404,7 +4412,7 @@ void VulkanHppGenerator::readExtensionDisabledType(tinyxml2::XMLElement const* e
check(m_bitmasks.erase(name) + m_enums.erase(name) + m_structures.erase(name) == 1, line, "element <" + name + "> was removed from more than one set of elements"); check(m_bitmasks.erase(name) + m_enums.erase(name) + m_structures.erase(name) == 1, line, "element <" + name + "> was removed from more than one set of elements");
} }
void VulkanHppGenerator::readExtensionRequire(tinyxml2::XMLElement const* element, std::string const& platform, std::string const& tag, std::map<std::string, int> & requires) void VulkanHppGenerator::readExtensionRequire(tinyxml2::XMLElement const* element, std::string const& platform, std::string const& tag, std::map<std::string, int> & requirements)
{ {
int line = element->GetLineNum(); int line = element->GetLineNum();
std::map<std::string, std::string> attributes = getAttributes(element); std::map<std::string, std::string> attributes = getAttributes(element);
@ -4416,7 +4424,7 @@ void VulkanHppGenerator::readExtensionRequire(tinyxml2::XMLElement const* elemen
{ {
if (attribute.first == "extension") if (attribute.first == "extension")
{ {
check(requires.insert(std::make_pair(attribute.second, line)).second, line, "required extension <" + attribute.second + "> already listed"); check(requirements.insert(std::make_pair(attribute.second, line)).second, line, "required extension <" + attribute.second + "> already listed");
} }
else else
{ {
@ -4498,7 +4506,7 @@ void VulkanHppGenerator::readExtensionRequireType(tinyxml2::XMLElement const* el
{ {
check(bmit->second.platform.empty(), line, "platform already specified for bitmask <" + name + ">"); check(bmit->second.platform.empty(), line, "platform already specified for bitmask <" + name + ">");
bmit->second.platform = platform; bmit->second.platform = platform;
assert((m_enums.find(bmit->second.requires) == m_enums.end()) || (m_enums.find(bmit->second.requires)->second.isBitmask)); assert((m_enums.find(bmit->second.requirements) == m_enums.end()) || (m_enums.find(bmit->second.requirements)->second.isBitmask));
} }
else else
{ {
@ -4616,12 +4624,12 @@ void VulkanHppGenerator::readFuncpointer(tinyxml2::XMLElement const* element, st
std::vector<tinyxml2::XMLElement const*> children = getChildElements(element); std::vector<tinyxml2::XMLElement const*> children = getChildElements(element);
checkElements(line, children, { { "name", true } }, { "type" }); checkElements(line, children, { { "name", true } }, { "type" });
std::string requires; std::string requirements;
for (auto const& attribute : attributes) for (auto const& attribute : attributes)
{ {
if (attribute.first == "requires") if (attribute.first == "requires")
{ {
requires = attribute.second; requirements = attribute.second;
} }
} }
@ -4633,14 +4641,14 @@ void VulkanHppGenerator::readFuncpointer(tinyxml2::XMLElement const* element, st
{ {
std::string name = child->GetText(); std::string name = child->GetText();
check(!name.empty(), childLine, "funcpointer with empty name"); check(!name.empty(), childLine, "funcpointer with empty name");
check(m_funcPointers.insert(std::make_pair(name, FuncPointerData(requires, line))).second, childLine, "funcpointer <" + name + "> already specified"); check(m_funcPointers.insert(std::make_pair(name, FuncPointerData(requirements, line))).second, childLine, "funcpointer <" + name + "> already specified");
check(m_types.insert(name).second, childLine, "funcpointer <" + name + "> already specified as a type"); check(m_types.insert(name).second, childLine, "funcpointer <" + name + "> already specified as a type");
} }
else if (value == "type") else if (value == "type")
{ {
std::string type = child->GetText(); std::string type = child->GetText();
check(!type.empty(), childLine, "funcpointer argument with empty type"); check(!type.empty(), childLine, "funcpointer argument with empty type");
check((m_types.find(type) != m_types.end()) || (type == requires), childLine, "funcpointer argument of unknown type <" + type + ">"); check((m_types.find(type) != m_types.end()) || (type == requirements), childLine, "funcpointer argument of unknown type <" + type + ">");
} }
} }
} }
@ -5517,6 +5525,9 @@ int main(int argc, char **argv)
{} {}
// relational operators // relational operators
#if defined(VULKAN_HPP_HAS_SPACESHIP_OPERATOR)
auto operator<=>(Flags<BitType> const&) const = default;
#else
VULKAN_HPP_CONSTEXPR bool operator<(Flags<BitType> const& rhs) const VULKAN_HPP_NOEXCEPT VULKAN_HPP_CONSTEXPR bool operator<(Flags<BitType> const& rhs) const VULKAN_HPP_NOEXCEPT
{ {
return m_mask < rhs.m_mask; return m_mask < rhs.m_mask;
@ -5546,6 +5557,7 @@ int main(int argc, char **argv)
{ {
return m_mask != rhs.m_mask; return m_mask != rhs.m_mask;
} }
#endif
// logical operator // logical operator
VULKAN_HPP_CONSTEXPR bool operator!() const VULKAN_HPP_NOEXCEPT VULKAN_HPP_CONSTEXPR bool operator!() const VULKAN_HPP_NOEXCEPT
@ -5614,7 +5626,8 @@ int main(int argc, char **argv)
MaskType m_mask; MaskType m_mask;
}; };
// relational operators #if !defined(VULKAN_HPP_HAS_SPACESHIP_OPERATOR)
// relational operators only needed for pre C++20
template <typename BitType> template <typename BitType>
VULKAN_HPP_CONSTEXPR bool operator<(BitType bit, Flags<BitType> const& flags) VULKAN_HPP_NOEXCEPT VULKAN_HPP_CONSTEXPR bool operator<(BitType bit, Flags<BitType> const& flags) VULKAN_HPP_NOEXCEPT
{ {
@ -5650,6 +5663,7 @@ int main(int argc, char **argv)
{ {
return flags != bit; return flags != bit;
} }
#endif
// bitwise operators // bitwise operators
template <typename BitType> template <typename BitType>
@ -6407,6 +6421,13 @@ static const std::string constExpressionArrayCopy = R"(
# endif # endif
#endif #endif
#if 201711 <= __cpp_impl_three_way_comparison
# define VULKAN_HPP_HAS_SPACESHIP_OPERATOR
#endif
#if defined(VULKAN_HPP_HAS_SPACESHIP_OPERATOR)
# include <compare>
#endif
)"; )";
static const std::string is_error_code_enum = R"( static const std::string is_error_code_enum = R"(

View File

@ -57,11 +57,11 @@ class VulkanHppGenerator
struct BitmaskData struct BitmaskData
{ {
BitmaskData(std::string const& r, int line) BitmaskData(std::string const& r, int line)
: requires(r) : requirements(r)
, xmlLine(line) , xmlLine(line)
{} {}
std::string requires; // original vulkan name: VK*FlagBits std::string requirements; // original vulkan name: VK*FlagBits
std::string platform; std::string platform;
std::string alias; // original vulkan name std::string alias; // original vulkan name
int xmlLine; int xmlLine;
@ -149,18 +149,18 @@ class VulkanHppGenerator
std::string deprecatedBy; std::string deprecatedBy;
std::string obsoletedBy; std::string obsoletedBy;
std::string promotedTo; std::string promotedTo;
std::map<std::string, int> requires; std::map<std::string, int> requirements;
int xmlLine; int xmlLine;
}; };
struct FuncPointerData struct FuncPointerData
{ {
FuncPointerData(std::string const& r, int line) FuncPointerData(std::string const& r, int line)
: requires(r) : requirements(r)
, xmlLine(line) , xmlLine(line)
{} {}
std::string requires; std::string requirements;
int xmlLine; int xmlLine;
}; };
@ -297,7 +297,7 @@ class VulkanHppGenerator
void readExtensionDisabledEnum(std::string const& extensionName, tinyxml2::XMLElement const* element); void readExtensionDisabledEnum(std::string const& extensionName, tinyxml2::XMLElement const* element);
void readExtensionDisabledRequire(std::string const& extensionName, tinyxml2::XMLElement const* element); void readExtensionDisabledRequire(std::string const& extensionName, tinyxml2::XMLElement const* element);
void readExtensionDisabledType(tinyxml2::XMLElement const* element); void readExtensionDisabledType(tinyxml2::XMLElement const* element);
void readExtensionRequire(tinyxml2::XMLElement const* element, std::string const& platform, std::string const& tag, std::map<std::string, int> & requires); void readExtensionRequire(tinyxml2::XMLElement const* element, std::string const& platform, std::string const& tag, std::map<std::string, int> & requirements);
void readExtensionRequireCommand(tinyxml2::XMLElement const* element, std::string const& platform); void readExtensionRequireCommand(tinyxml2::XMLElement const* element, std::string const& platform);
void readExtensionRequireType(tinyxml2::XMLElement const* element, std::string const& platform); void readExtensionRequireType(tinyxml2::XMLElement const* element, std::string const& platform);
void readExtensions(tinyxml2::XMLElement const* element); void readExtensions(tinyxml2::XMLElement const* element);

File diff suppressed because it is too large Load Diff