Improve alias handling of enums and structs: (#305)

- Extend and unify alias handling on feature and extension enums
- Extend aliases of enums handling to accept two levels of aliasing
- Extend aliases of structures to allow mulitple aliases of the same structure
- Simplify forward declarations to just declare all structures and aliases
This commit is contained in:
Andreas Süßenbach
2019-03-18 20:48:10 +01:00
committed by Markus Tavenrath
parent cd8e5283c3
commit 48ceca69f3
3 changed files with 392 additions and 145 deletions

View File

@@ -1015,27 +1015,6 @@ std::string VulkanHppGenerator::generateCall(std::pair<std::string, CommandData>
return call.str();
}
std::set<std::string> VulkanHppGenerator::gatherForwardDeclarations()
{
// all structures in command parameters need to be forward declared
std::set<std::string> forwardDeclarations;
for (auto const& handle : m_handles)
{
for (auto const& command : handle.second.commands)
{
for (auto const& parameter : command.second.params)
{
auto structureIt = m_structures.find(parameter.type.type);
if (structureIt != m_structures.end())
{
forwardDeclarations.insert(parameter.type.type);
}
}
}
}
return forwardDeclarations;
}
std::string const& VulkanHppGenerator::getTypesafeCheck() const
{
return m_typesafeCheck;
@@ -1560,7 +1539,7 @@ void VulkanHppGenerator::readExtensionRequire(tinyxml2::XMLElement const* elemen
}
else if (value == "enum")
{
readExtensionRequireEnum(child, tag);
readRequireEnum(child, tag);
}
else if (value == "type")
{
@@ -1596,70 +1575,6 @@ void VulkanHppGenerator::readExtensionRequireCommand(tinyxml2::XMLElement const*
}
}
void VulkanHppGenerator::readExtensionRequireEnum(tinyxml2::XMLElement const* element, std::string const& tag)
{
std::map<std::string, std::string> attributes = getAttributes(element);
checkAttributes(attributes, element->GetLineNum(),
{
{ "name",{} }
},
{
{ "alias",{} },
{ "bitpos",{} },
{ "comment",{} },
{ "dir",{ "-" } },
{ "extends",{} },
{ "extnumber",{} },
{ "offset",{} },
{ "value",{} }
});
checkElements(getChildElements(element), {});
// TODO process enums which don't extend existing enums
auto extendsIt = attributes.find("extends");
if (extendsIt != attributes.end())
{
bool bitmask = false;
std::string extends = extendsIt->second;
auto enumIt = m_enums.find(extends);
if (enumIt == m_enums.end())
{
enumIt = m_bitmaskBits.find(extends);
assert(enumIt != m_bitmaskBits.end());
bitmask = true;
}
std::string prefix = getEnumPrefix(enumIt->first, bitmask);
std::string postfix = getEnumPostfix(enumIt->first, m_tags, prefix);
auto nameIt = attributes.find("name");
assert(nameIt != attributes.end());
auto aliasIt = attributes.find("alias");
if (aliasIt != attributes.end())
{
checkAttributes(attributes, element->GetLineNum(), { { "alias",{} },{ "extends",{} },{ "name",{} } }, { { "comment",{} } });
// look for the aliased enum value
std::string alias = createEnumValueName(aliasIt->second, prefix, postfix, bitmask, findTag(m_tags, aliasIt->second));
auto valueIt = std::find_if(enumIt->second.values.begin(), enumIt->second.values.end(), [&alias](std::pair<std::string, std::string> const& value) { return value.second == alias; });
assert(valueIt != enumIt->second.values.end());
std::string name = createEnumValueName(nameIt->second, prefix, postfix, bitmask, tag);
if (valueIt->second != name)
{
// only add an alias if it's different from the aliased name
enumIt->second.aliases.push_back(std::make_pair(nameIt->second, name));
}
}
else
{
assert((attributes.find("bitpos") != attributes.end()) + (attributes.find("offset") != attributes.end()) + (attributes.find("value") != attributes.end()) == 1);
enumIt->second.addEnumValue(nameIt->second, bitmask, prefix, postfix, tag);
}
}
}
void VulkanHppGenerator::readExtensionRequireType(tinyxml2::XMLElement const* element, std::string const& platform)
{
std::map<std::string, std::string> attributes = getAttributes(element);
@@ -1734,49 +1649,11 @@ void VulkanHppGenerator::readFeatureRequire(tinyxml2::XMLElement const* element)
std::string value = child->Value();
if (value == "enum")
{
readFeatureRequireEnum(child);
readRequireEnum(child, "");
}
}
}
void VulkanHppGenerator::readFeatureRequireEnum(tinyxml2::XMLElement const* element)
{
std::map<std::string, std::string> attributes = getAttributes(element);
checkAttributes(attributes, element->GetLineNum(),
{
{ "name",{} }
},
{
{ "bitpos",{} },
{ "comment",{} },
{ "dir", { "-" } },
{ "extends",{} },
{ "extnumber", {} },
{ "offset", {} },
{ "value",{} }
});
checkElements(getChildElements(element), {});
auto extendsAttribute = attributes.find("extends");
if (extendsAttribute != attributes.end())
{
bool bitmask = false;
assert(strncmp(extendsAttribute->second.c_str(), "Vk", 2) == 0);
std::string extends = extendsAttribute->second;
auto enumIt = m_enums.find(extends);
if (enumIt == m_enums.end())
{
enumIt = m_bitmaskBits.find(extends);
assert(enumIt != m_bitmaskBits.end());
bitmask = true;
}
std::string prefix = getEnumPrefix(enumIt->first, bitmask);
std::string postfix = getEnumPostfix(enumIt->first, m_tags, prefix);
enumIt->second.addEnumValue(attributes.find("name")->second, bitmask, prefix, postfix, "");
}
}
void VulkanHppGenerator::readFuncpointer(tinyxml2::XMLElement const* element, std::map<std::string, std::string> const& attributes)
{
checkAttributes(attributes, element->GetLineNum(), { { "category",{ "funcpointer" } } }, { { "requires",{} } });
@@ -1871,6 +1748,75 @@ void VulkanHppGenerator::readPlatforms(tinyxml2::XMLElement const* element)
}
}
void VulkanHppGenerator::readRequireEnum(tinyxml2::XMLElement const* element, std::string const& tag)
{
std::map<std::string, std::string> attributes = getAttributes(element);
checkAttributes(attributes, element->GetLineNum(),
{
{ "name",{} }
},
{
{ "alias",{} },
{ "bitpos",{} },
{ "comment",{} },
{ "dir",{ "-" } },
{ "extends",{} },
{ "extnumber",{} },
{ "offset",{} },
{ "value",{} }
});
checkElements(getChildElements(element), {});
// TODO process enums which don't extend existing enums
auto extendsIt = attributes.find("extends");
if (extendsIt != attributes.end())
{
bool bitmask = false;
std::string extends = extendsIt->second;
auto enumIt = m_enums.find(extends);
if (enumIt == m_enums.end())
{
enumIt = m_bitmaskBits.find(extends);
assert(enumIt != m_bitmaskBits.end());
bitmask = true;
}
std::string prefix = getEnumPrefix(enumIt->first, bitmask);
std::string postfix = getEnumPostfix(enumIt->first, m_tags, prefix);
auto nameIt = attributes.find("name");
assert(nameIt != attributes.end());
auto aliasIt = attributes.find("alias");
if (aliasIt != attributes.end())
{
checkAttributes(attributes, element->GetLineNum(), { { "alias",{} },{ "extends",{} },{ "name",{} } }, { { "comment",{} } });
// look for the aliased enum value
std::string alias = aliasIt->second;
auto valueIt = std::find_if(enumIt->second.values.begin(), enumIt->second.values.end(), [&alias](std::pair<std::string, std::string> const& value) { return value.first == alias; });
if (valueIt == enumIt->second.values.end())
{
// if the aliased enum value is not found in the values, look in the aliases as well!
valueIt = std::find_if(enumIt->second.aliases.begin(), enumIt->second.aliases.end(), [&alias](std::pair<std::string, std::string> const& value) { return value.first == alias; });
assert(valueIt != enumIt->second.aliases.end());
}
std::string name = createEnumValueName(nameIt->second, prefix, postfix, bitmask, tag);
if (valueIt->second != name)
{
// only add an alias if it's different from the aliased name
enumIt->second.aliases.push_back(std::make_pair(nameIt->second, name));
}
}
else
{
assert((attributes.find("bitpos") != attributes.end()) + (attributes.find("offset") != attributes.end()) + (attributes.find("value") != attributes.end()) == 1);
enumIt->second.addEnumValue(nameIt->second, bitmask, prefix, postfix, tag);
}
}
}
void VulkanHppGenerator::readStruct(tinyxml2::XMLElement const* element, bool isUnion, std::map<std::string, std::string> const& attributes)
{
checkAttributes(attributes, element->GetLineNum(),
@@ -1913,8 +1859,8 @@ void VulkanHppGenerator::readStructAlias(int lineNum, std::string const& name, s
checkAlias(m_structures, alias, lineNum);
auto structsIt = m_structures.find(alias);
assert((structsIt != m_structures.end()) && structsIt->second.alias.empty());
structsIt->second.alias = stripPrefix(name, "Vk");
assert((structsIt != m_structures.end()) && (std::find(structsIt->second.aliases.begin(), structsIt->second.aliases.end(), name) == structsIt->second.aliases.end()));
structsIt->second.aliases.push_back(name);
assert(m_structureAliases.find(name) == m_structureAliases.end());
m_structureAliases[name] = alias;
@@ -2598,20 +2544,18 @@ void VulkanHppGenerator::writeEnums(std::ostream & os) const
}
}
void VulkanHppGenerator::writeForwardDeclarations(std::ostream & os, std::set<std::string> const& forwardDeclarations) const
void VulkanHppGenerator::writeForwardDeclarations(std::ostream & os) const
{
os << std::endl;
for (auto const& fd : forwardDeclarations)
for (auto const& structure : m_structures)
{
auto structureIt = m_structures.find(fd);
assert(structureIt != m_structures.end());
enterProtect(os, structureIt->second.protect);
os << " " << (structureIt->second.isUnion ? "union" : "struct") << " " << stripPrefix(structureIt->first, "Vk") << ";" << std::endl;
if (!structureIt->second.alias.empty())
enterProtect(os, structure.second.protect);
os << " " << (structure.second.isUnion ? "union" : "struct") << " " << stripPrefix(structure.first, "Vk") << ";" << std::endl;
for (std::string const& alias : structure.second.aliases)
{
os << " using " << stripPrefix(structureIt->second.alias, "Vk") << " = " << stripPrefix(structureIt->first, "Vk") << ";" << std::endl;
os << " using " << stripPrefix(alias, "Vk") << " = " << stripPrefix(structure.first, "Vk") << ";" << std::endl;
}
leaveProtect(os, structureIt->second.protect);
leaveProtect(os, structure.second.protect);
}
}
@@ -3971,7 +3915,7 @@ void VulkanHppGenerator::writeStructureChainValidation(std::ostream & os)
errorString << extendName << " does not specify a struct in structextends field.";
// check if symbol name is an alias to a struct
auto itAlias = std::find_if(m_structures.begin(), m_structures.end(), [&extendName](std::pair<std::string, StructureData> const &it) -> bool {return it.second.alias == extendName; });
auto itAlias = std::find_if(m_structures.begin(), m_structures.end(), [&extendName](std::pair<std::string, StructureData> const &it) -> bool {return std::find(it.second.aliases.begin(), it.second.aliases.end(), extendName) != it.second.aliases.end(); });
if (itAlias != m_structures.end())
{
errorString << " The symbol is an alias and maps to " << itAlias->first << ".";
@@ -5100,8 +5044,6 @@ namespace std
generator.checkCorrectness();
std::set<std::string> forwardDeclarations = generator.gatherForwardDeclarations();
std::ofstream ofs(VULKAN_HPP_FILE);
ofs << generator.getVulkanLicenseHeader() << std::endl
<< includes
@@ -5143,7 +5085,7 @@ namespace std
generator.writeThrowExceptions(ofs);
ofs << "#endif" << std::endl;
ofs << structResultValue;
generator.writeForwardDeclarations(ofs, forwardDeclarations);
generator.writeForwardDeclarations(ofs);
generator.writeHandles(ofs);
generator.writeStructs(ofs);
generator.writeHandlesCommandDefintions(ofs);