Introduce overloads for destroy* and free* functions (#180)

This commit is contained in:
Andreas Süßenbach 2018-02-14 11:49:48 +01:00 committed by Markus Tavenrath
parent bae68b49aa
commit 818dc27d06
3 changed files with 866 additions and 996 deletions

View File

@ -698,6 +698,83 @@ const std::string uniqueHandleHeader = R"(
)"; )";
const std::string deleterClassString = R"(
struct AllocationCallbacks;
template <typename OwnerType>
class ObjectDeleter
{
public:
ObjectDeleter(OwnerType owner = OwnerType(), Optional<const AllocationCallbacks> allocator = nullptr)
: m_owner(owner)
, m_allocator(allocator)
{}
OwnerType getOwner() const { return m_owner; }
Optional<const AllocationCallbacks> getAllocator() const { return m_allocator; }
protected:
template <typename T>
void destroy(T t)
{
m_owner.destroy(t, m_allocator);
}
private:
OwnerType m_owner;
Optional<const AllocationCallbacks> m_allocator;
};
class NoParent;
template <>
class ObjectDeleter<NoParent>
{
public:
ObjectDeleter( Optional<const AllocationCallbacks> allocator = nullptr )
: m_allocator( allocator )
{}
Optional<const AllocationCallbacks> getAllocator() const { return m_allocator; }
protected:
template <typename T>
void destroy(T t)
{
t.destroy( m_allocator );
}
private:
Optional<const AllocationCallbacks> m_allocator;
};
template <typename OwnerType, typename PoolType>
class PoolDeleter
{
public:
PoolDeleter(OwnerType owner = OwnerType(), PoolType pool = PoolType())
: m_owner(owner)
, m_pool(pool)
{}
OwnerType getOwner() const { return m_owner; }
PoolType getPool() const { return m_pool; }
protected:
template <typename T>
void destroy(T t)
{
m_owner.free(m_pool, t);
}
private:
OwnerType m_owner;
PoolType m_pool;
};
)";
std::string replaceWithMap(std::string const &input, std::map<std::string, std::string> replacements) std::string replaceWithMap(std::string const &input, std::map<std::string, std::string> replacements)
{ {
// This will match ${someVariable} and contain someVariable in match group 1 // This will match ${someVariable} and contain someVariable in match group 1
@ -3015,175 +3092,6 @@ void VulkanHppGenerator::writeEnumsToString(std::ostream & os, EnumData const& e
os << std::endl; os << std::endl;
} }
void VulkanHppGenerator::writeDeleterClasses(std::ostream & os, std::pair<std::string, std::set<std::string>> const& deleterTypes)
{
// A Deleter class for each of the Unique* classes... but only if smart handles are not switched off
os << "#ifndef VULKAN_HPP_NO_SMART_HANDLE" << std::endl;
bool first = true;
// get type and name of the parent (holder) type
std::string parentType = deleterTypes.first;
std::string parentName = parentType.empty() ? "" : startLowerCase(parentType);
// iterate over the deleter types parented by this type
for (auto const& deleterType : deleterTypes.second)
{
std::string deleterName = startLowerCase(deleterType);
bool standardDeleter = !parentType.empty() && (deleterType != "Device"); // this detects the 'standard' case for a deleter
// if this Deleter is pooled, make such a pool the last argument, otherwise an Optional allocator
auto const& dd = m_deleters.find(deleterType);
assert(dd != m_deleters.end());
std::string poolName = (dd->second.pool.empty() ? "" : startLowerCase(dd->second.pool));
if (!first)
{
os << std::endl;
}
first = false;
os << " class " << deleterType << "Deleter" << std::endl
<< " {" << std::endl
<< " public:" << std::endl
<< " " << deleterType << "Deleter( ";
if (standardDeleter)
{
// the standard deleter gets a parent type in the constructor
os << parentType << " " << parentName << " = " << parentType << "(), ";
}
if (poolName.empty())
{
os << "Optional<const AllocationCallbacks> allocator = nullptr )" << std::endl;
}
else
{
assert(!dd->second.pool.empty());
os << dd->second.pool << " " << poolName << " = " << dd->second.pool << "() )" << std::endl;
}
// now the initializer list of the Deleter constructor
os << " : ";
if (standardDeleter)
{
// the standard deleter has a parent type as a member
os << "m_" << parentName << "( " << parentName << " )" << std::endl
<< " , ";
}
if (poolName.empty())
{
// non-pooled deleter have an allocator as a member
os << "m_allocator( allocator )" << std::endl;
}
else
{
// pooled deleter have a pool as a member
os << "m_" << poolName << "( " << poolName << " )" << std::endl;
}
// besides that, the constructor is empty
os << " {}" << std::endl
<< std::endl;
// getter for the parent type
if (standardDeleter)
{
os << " " << parentType << " get" << parentType << "() const { return m_" << parentName << "; }\n";
}
// getter for pool
if (!poolName.empty())
{
os << " " << dd->second.pool << " get" << dd->second.pool << "() const { return m_" << poolName << "; }\n";
}
else // getter for allocator
{
os << " Optional<const AllocationCallbacks> getAllocator() const { return m_allocator; }\n";
}
os << "\n";
// the operator() calls the delete/destroy function
os << " protected:\n"
<< " void destroy( " << deleterType << " " << deleterName << " )\n"
<< " {\n";
// the delete/destroy function is either part of the parent member of the deleter argument
if (standardDeleter)
{
os << " m_" << parentName << ".";
}
else
{
os << " " << deleterName << ".";
}
os << dd->second.call << "( ";
if (!poolName.empty())
{
// pooled Deleter gets the pool as the first argument
os << "m_" << poolName << ", ";
}
if (standardDeleter)
{
// the standard deleter gets the deleter argument as an argument
os << deleterName;
}
// the non-pooled deleter get the allocate as an argument (potentially after the deleterName
if (poolName.empty())
{
if (standardDeleter)
{
os << ", ";
}
os << "m_allocator";
}
os << " );" << std::endl
<< " }" << std::endl
<< std::endl;
// now the members of the Deleter class
os << " private:" << std::endl;
if (standardDeleter)
{
// the parentType for the standard deleter
os << " " << parentType << " m_" << parentName << ";" << std::endl;
}
// the allocator for the non-pooled deleters, the pool for the pooled ones
if (poolName.empty())
{
os << " Optional<const AllocationCallbacks> m_allocator;" << std::endl;
}
else
{
os << " " << dd->second.pool << " m_" << poolName << ";" << std::endl;
}
os << " };" << std::endl;
}
os << "#endif /*VULKAN_HPP_NO_SMART_HANDLE*/" << std::endl
<< std::endl;
}
void VulkanHppGenerator::writeDeleterForwardDeclarations(std::ostream &os, std::pair<std::string, std::set<std::string>> const& deleterTypes)
{
// if smart handles are supported, all the Deleter classes need to be forward declared
os << "#ifndef VULKAN_HPP_NO_SMART_HANDLE" << std::endl;
bool first = true;
std::string firstName = deleterTypes.first.empty() ? "" : startLowerCase(deleterTypes.first);
for (auto const& dt : deleterTypes.second)
{
os << " class " << dt << "Deleter;" << std::endl;
os << " template <> class UniqueHandleTraits<" << dt << "> {public: using deleter = " << dt << "Deleter; };\n";
os << " using Unique" << dt << " = UniqueHandle<" << dt << ">;" << std::endl;
}
os << "#endif /*VULKAN_HPP_NO_SMART_HANDLE*/" << std::endl
<< std::endl;
}
// Intended only for `enum class Result`! // Intended only for `enum class Result`!
void VulkanHppGenerator::writeExceptionsForEnum(std::ostream & os, EnumData const& enumData) void VulkanHppGenerator::writeExceptionsForEnum(std::ostream & os, EnumData const& enumData)
{ {
@ -3256,7 +3164,7 @@ ${i} ${typeVariable}s.reserve( ${vectorSize} );
${i} ${type}* buffer = reinterpret_cast<${type}*>( reinterpret_cast<char*>( ${typeVariable}s.data() ) + ${vectorSize} * ( sizeof( Unique${type} ) - sizeof( ${type} ) ) ); ${i} ${type}* buffer = reinterpret_cast<${type}*>( reinterpret_cast<char*>( ${typeVariable}s.data() ) + ${vectorSize} * ( sizeof( Unique${type} ) - sizeof( ${type} ) ) );
${i} Result result = static_cast<Result>(d.vk${command}( m_device, ${arguments}, reinterpret_cast<Vk${type}*>( buffer ) ) ); ${i} Result result = static_cast<Result>(d.vk${command}( m_device, ${arguments}, reinterpret_cast<Vk${type}*>( buffer ) ) );
${i} ${type}Deleter deleter( *this, ${deleterArg} ); ${i} ${Deleter}<${DeleterTemplate}> deleter( *this, ${deleterArg} );
${i} for ( size_t i=0 ; i<${vectorSize} ; i++ ) ${i} for ( size_t i=0 ; i<${vectorSize} ; i++ )
${i} { ${i} {
${i} ${typeVariable}s.push_back( Unique${type}( buffer[i], deleter ) ); ${i} ${typeVariable}s.push_back( Unique${type}( buffer[i], deleter ) );
@ -3282,6 +3190,8 @@ ${i} return createResultValue( result, ${typeVariable}s, "VULKAN_HPP_NAMESPACE:
{ "vectorSize", isCreateFunction ? "createInfos.size()" : "allocateInfo." + typeVariable + "Count" }, { "vectorSize", isCreateFunction ? "createInfos.size()" : "allocateInfo." + typeVariable + "Count" },
{ "command", startUpperCase(commandData.fullName) }, { "command", startUpperCase(commandData.fullName) },
{ "arguments", arguments.str() }, { "arguments", arguments.str() },
{ "Deleter", ddit->second.pool.empty() ? "ObjectDeleter" : "PoolDeleter" },
{ "DeleterTemplate", ddit->second.pool.empty() ? type : commandData.className + "," + ddit->second.pool },
{ "deleterArg", ddit->second.pool.empty() ? "allocator" : "allocateInfo." + startLowerCase(ddit->second.pool) }, { "deleterArg", ddit->second.pool.empty() ? "allocator" : "allocateInfo." + startLowerCase(ddit->second.pool) },
{ "class", commandData.className }, { "class", commandData.className },
{ "function", commandData.reducedName } { "function", commandData.reducedName }
@ -3571,28 +3481,12 @@ void VulkanHppGenerator::writeFunctionBodyEnhancedReturnResultValue(std::ostream
if (unique) if (unique)
{ {
// the unique version needs a Deleter object for destruction of the newly created stuff // the unique version needs a Deleter object for destruction of the newly created stuff
os << std::endl
<< indentation << " " << type << "Deleter deleter( ";
if (m_deleters.find(commandData.className) != m_deleters.end())
{
// if the Deleter is specific to the command's class, add '*this' to the deleter
os << "*this, ";
}
// get the DeleterData corresponding to the returned type // get the DeleterData corresponding to the returned type
std::map<std::string, DeleterData>::const_iterator ddit = m_deleters.find(type); std::map<std::string, DeleterData>::const_iterator ddit = m_deleters.find(type);
assert(ddit != m_deleters.end()); assert(ddit != m_deleters.end() && ddit->second.pool.empty());
if (ddit->second.pool.empty())
{ os << std::endl
// if this type isn't pooled, use the allocator (provided as a function argument) << indentation << " ObjectDeleter<" << (commandData.className.empty() ? "NoParent" : commandData.className) << "> deleter( " << (commandData.className.empty() ? "" : "*this, ") << "allocator );" << std::endl;
os << "allocator";
}
else
{
// otherwise use the pool, which always is a member of the second argument
os << startLowerCase(strip(commandData.params[1].name, "p")) << "." << startLowerCase(ddit->second.pool);
}
os << " );" << std::endl;
} }
// if the return type is "Result" or there is at least one success code, create the Result/Value construct to return // if the return type is "Result" or there is at least one success code, create the Result/Value construct to return
@ -4288,9 +4182,8 @@ void VulkanHppGenerator::writeTypeCommand(std::ostream & os, DependencyData cons
auto deleterTypesIt = m_deleterTypes.find(""); auto deleterTypesIt = m_deleterTypes.find("");
assert((deleterTypesIt != m_deleterTypes.end()) && (deleterTypesIt->second.size() == 1)); assert((deleterTypesIt != m_deleterTypes.end()) && (deleterTypesIt->second.size() == 1));
writeDeleterForwardDeclarations(os, *deleterTypesIt); writeUniqueTypes(os, *deleterTypesIt);
writeTypeCommand(os, " ", commandData, false); writeTypeCommand(os, " ", commandData, false);
writeDeleterClasses(os, *deleterTypesIt);
} }
else else
{ {
@ -4397,7 +4290,7 @@ void VulkanHppGenerator::writeTypeHandle(std::ostream & os, DependencyData const
std::map<std::string, std::set<std::string>>::const_iterator deleterTypesIt = m_deleterTypes.find(dependencyData.name); std::map<std::string, std::set<std::string>>::const_iterator deleterTypesIt = m_deleterTypes.find(dependencyData.name);
if (deleterTypesIt != m_deleterTypes.end()) if (deleterTypesIt != m_deleterTypes.end())
{ {
writeDeleterForwardDeclarations(os, *deleterTypesIt); writeUniqueTypes(os, *deleterTypesIt);
} }
const std::string memberName = startLowerCase(dependencyData.name); const std::string memberName = startLowerCase(dependencyData.name);
@ -4475,10 +4368,17 @@ ${commands}
// now list all the commands that are mapped to members of this class // now list all the commands that are mapped to members of this class
for (size_t i = 0; i < handleData.commands.size(); i++) for (size_t i = 0; i < handleData.commands.size(); i++)
{ {
std::string commandName = handleData.commands[i]; std::map<std::string, CommandData>::const_iterator cit = m_commands.find(handleData.commands[i]);
std::map<std::string, CommandData>::const_iterator cit = m_commands.find(commandName);
assert((cit != m_commands.end()) && !cit->second.className.empty()); assert((cit != m_commands.end()) && !cit->second.className.empty());
writeTypeCommand(commands, " ", cit->second, false); writeTypeCommand(commands, " ", cit->second, false);
// special handling for destroy functions
if (((cit->second.fullName.substr(0, 7) == "destroy") && (cit->second.reducedName != "destroy")) || (cit->second.fullName.substr(0, 4) == "free"))
{
CommandData shortenedCommand = cit->second;
shortenedCommand.reducedName = (cit->second.fullName.substr(0, 7) == "destroy") ? "destroy" : "free";
writeTypeCommand(commands, " ", shortenedCommand, false);
}
} }
os << replaceWithMap(templateString, { os << replaceWithMap(templateString, {
@ -4487,13 +4387,6 @@ ${commands}
{ "commands", commands.str() } { "commands", commands.str() }
}); });
// then the actual Deleter classes can be listed
deleterTypesIt = m_deleterTypes.find(dependencyData.name);
if (deleterTypesIt != m_deleterTypes.end())
{
writeDeleterClasses(os, *deleterTypesIt);
}
// and finally the commands, that are member functions of this handle // and finally the commands, that are member functions of this handle
for (size_t i = 0; i < handleData.commands.size(); i++) for (size_t i = 0; i < handleData.commands.size(); i++)
{ {
@ -4503,6 +4396,14 @@ ${commands}
std::list<DependencyData>::const_iterator dep = std::find_if(m_dependencies.begin(), m_dependencies.end(), [commandName](DependencyData const& dd) { return dd.name == commandName; }); std::list<DependencyData>::const_iterator dep = std::find_if(m_dependencies.begin(), m_dependencies.end(), [commandName](DependencyData const& dd) { return dd.name == commandName; });
assert(dep != m_dependencies.end() && (dep->name == cit->second.fullName)); assert(dep != m_dependencies.end() && (dep->name == cit->second.fullName));
writeTypeCommand(os, " ", cit->second, true); writeTypeCommand(os, " ", cit->second, true);
// special handling for destroy functions
if (((cit->second.fullName.substr(0, 7) == "destroy") && (cit->second.reducedName != "destroy")) || (cit->second.fullName.substr(0, 4) == "free"))
{
CommandData shortenedCommand = cit->second;
shortenedCommand.reducedName = (cit->second.fullName.substr(0, 7) == "destroy") ? "destroy" : "free";
writeTypeCommand(os, " ", shortenedCommand, true);
}
} }
if (!handleData.alias.empty()) if (!handleData.alias.empty())
@ -4670,6 +4571,28 @@ void VulkanHppGenerator::writeTypeStruct(std::ostream & os, DependencyData const
os << std::endl; os << std::endl;
} }
void VulkanHppGenerator::writeUniqueTypes(std::ostream &os, std::pair<std::string, std::set<std::string>> const& deleterTypes)
{
os << "#ifndef VULKAN_HPP_NO_SMART_HANDLE" << std::endl;
if (!deleterTypes.first.empty())
{
os << " class " << deleterTypes.first << ";" << std::endl;
}
os << std::endl;
bool first = true;
for (auto const& dt : deleterTypes.second)
{
auto ddit = m_deleters.find(dt);
assert(ddit != m_deleters.end());
os << " template <> class UniqueHandleTraits<" << dt << "> {public: using deleter = " << (ddit->second.pool.empty() ? "Object" : "Pool") << "Deleter<" << (deleterTypes.first.empty() ? "NoParent" : deleterTypes.first) << (ddit->second.pool.empty() ? "" : ", " + ddit->second.pool) << ">; };\n";
os << " using Unique" << dt << " = UniqueHandle<" << dt << ">;" << std::endl;
}
os << "#endif /*VULKAN_HPP_NO_SMART_HANDLE*/" << std::endl
<< std::endl;
}
void VulkanHppGenerator::writeTypeUnion(std::ostream & os, DependencyData const& dependencyData, std::map<std::string, std::string> const& defaultValues) void VulkanHppGenerator::writeTypeUnion(std::ostream & os, DependencyData const& dependencyData, std::map<std::string, std::string> const& defaultValues)
{ {
std::map<std::string, StructData>::const_iterator it = m_structs.find(dependencyData.name); std::map<std::string, StructData>::const_iterator it = m_structs.find(dependencyData.name);
@ -5068,7 +4991,8 @@ int main( int argc, char **argv )
<< "namespace VULKAN_HPP_NAMESPACE" << std::endl << "namespace VULKAN_HPP_NAMESPACE" << std::endl
<< "{" << std::endl << "{" << std::endl
<< resultValueHeader << resultValueHeader
<< createResultValueHeader; << createResultValueHeader
<< deleterClassString;
generator.writeDelegationClassStatic(ofs); generator.writeDelegationClassStatic(ofs);

View File

@ -246,8 +246,6 @@ class VulkanHppGenerator
void writeCallVectorParameter(std::ostream & os, CommandData const& commandData, bool firstCall, bool singular, std::map<size_t, size_t>::const_iterator it); void writeCallVectorParameter(std::ostream & os, CommandData const& commandData, bool firstCall, bool singular, std::map<size_t, size_t>::const_iterator it);
void writeCallVulkanTypeParameter(std::ostream & os, ParamData const& paramData); void writeCallVulkanTypeParameter(std::ostream & os, ParamData const& paramData);
void writeEnumsToString(std::ostream & os, EnumData const& enumData); void writeEnumsToString(std::ostream & os, EnumData const& enumData);
void writeDeleterClasses(std::ostream & os, std::pair<std::string, std::set<std::string>> const& deleterTypes);
void writeDeleterForwardDeclarations(std::ostream &os, std::pair<std::string, std::set<std::string>> const& deleterTypes);
void writeExceptionsForEnum(std::ostream & os, EnumData const& enumData); void writeExceptionsForEnum(std::ostream & os, EnumData const& enumData);
void writeFunction(std::ostream & os, std::string const& indentation, CommandData const& commandData, bool definition, bool enhanced, bool singular, bool unique, bool isStructureChain); void writeFunction(std::ostream & os, std::string const& indentation, CommandData const& commandData, bool definition, bool enhanced, bool singular, bool unique, bool isStructureChain);
void writeFunctionBodyEnhanced(std::ostream & os, std::string const& indentation, CommandData const& commandData, bool singular, bool unique, bool isStructureChain); void writeFunctionBodyEnhanced(std::ostream & os, std::string const& indentation, CommandData const& commandData, bool singular, bool unique, bool isStructureChain);
@ -280,6 +278,7 @@ class VulkanHppGenerator
void writeTypeScalar(std::ostream & os, DependencyData const& dependencyData); void writeTypeScalar(std::ostream & os, DependencyData const& dependencyData);
void writeTypeStruct(std::ostream & os, DependencyData const& dependencyData, std::map<std::string, std::string> const& defaultValues); void writeTypeStruct(std::ostream & os, DependencyData const& dependencyData, std::map<std::string, std::string> const& defaultValues);
void writeTypeUnion(std::ostream & os, DependencyData const& dependencyData, std::map<std::string, std::string> const& defaultValues); void writeTypeUnion(std::ostream & os, DependencyData const& dependencyData, std::map<std::string, std::string> const& defaultValues);
void writeUniqueTypes(std::ostream &os, std::pair<std::string, std::set<std::string>> const& deleterTypes);
#if !defined(NDEBUG) #if !defined(NDEBUG)
void skipVendorID(tinyxml2::XMLElement const* element); void skipVendorID(tinyxml2::XMLElement const* element);
#endif #endif

File diff suppressed because it is too large Load Diff