Merge pull request #110 from asuessenbach/DataResult

Introduced define VK_CPP_NO_EXCEPTIONS, to support calling vk-functions without throwing exceptions on error conditions. Now, depending on that define, some functions can return a struct containing the vk::Result and some generated value.
This commit is contained in:
Markus Tavenrath 2016-05-19 15:14:54 +02:00
commit 73a3833628
3 changed files with 3308 additions and 3352 deletions

View File

@ -141,7 +141,6 @@ parameter matches the handle. In addition to this we made a few changes to the s
* ```const T *``` has been replaced by ```const T &``` to allow temporary objects. This is useful to pass small structures like ```vk::ClearColorValue``` or ```vk::Extent*``` * ```const T *``` has been replaced by ```const T &``` to allow temporary objects. This is useful to pass small structures like ```vk::ClearColorValue``` or ```vk::Extent*```
```commandBuffer.clearColorImage(image, layout, std::array<float, 4>{1.0f, 1.0f, 1.0f, 1.0f}, {...});``` ```commandBuffer.clearColorImage(image, layout, std::array<float, 4>{1.0f, 1.0f, 1.0f, 1.0f}, {...});```
Optional parameters are being replaced by ```Optional<T>``` which accept a type of ```const T```, ```T```, or ```const std::string```. ```nullptr``` can be used to initialize an empty ```Optional<T>```. Optional parameters are being replaced by ```Optional<T>``` which accept a type of ```const T```, ```T```, or ```const std::string```. ```nullptr``` can be used to initialize an empty ```Optional<T>```.
* The wrapper will throw a ```std::system_error``` if a ```vk::Result``` return value is not an success code. If there's only a single success code it's not returned at all. In this case functions with a single output value do return this output value instead.
Here are a few code examples: Here are a few code examples:
```c++ ```c++
@ -176,6 +175,24 @@ Here are a few code examples:
std::cerr << "Vulkan failure: " << e.what() << std::endl; std::cerr << "Vulkan failure: " << e.what() << std::endl;
} }
``` ```
# Exceptions and return types
The wrapper functions will throw a ```std::system_error``` if the result of the wrapped function is not a success code.
By defining ```VK_CPP_NO_EXCEPTIONS``` before include vk_cpp.hpp, this can be disabled.
Depending on exceptions being enabled or disabled, the return type of some functions change.
With exceptions enabled (the default) there are four different cases on the return types:
* Just one possible success code
* * no output value -> return type is ```void```
* * one output value -> return type is T, which is the type of the output value
* Multiple possible success codes
* * no output value -> return type is ```vk::Result```
* * one output value -> return type is a structure ```vk::ResultValue<T>``` with a member ```result``` of type ```vk::Result``` holding the actual result code, and a member ```value``` of type T, which is the type of the output value, holding that output value.
With exceptions disabled, the return type of those wrapper functions where the wrapped function has just one possible success code is different:
* no output value -> return type is ```vk::Result```
* one output value -> return type is ```vk::ResultValue<T>```, as described above.
Note: With exceptions disabled, it is the user's responsibility to check for errors!
# Usage # Usage
To start with the C++ version of the Vulkan API download header from GIT, put it in a vulkan subdirectory and add To start with the C++ version of the Vulkan API download header from GIT, put it in a vulkan subdirectory and add

View File

@ -319,6 +319,99 @@ std::string const versionCheckHeader = (
"\n" "\n"
); );
std::string const resultValueHeader = (
" template <typename T>\n"
" struct ResultValue\n"
" {\n"
" ResultValue( Result r, T & v )\n"
" : result( r )\n"
" , value( v )\n"
" {}\n"
"\n"
" Result result;\n"
" T value;\n"
" };\n"
"\n"
" template <typename T>\n"
" struct ResultValueType\n"
" {\n"
"#ifdef VK_CPP_NO_EXCEPTIONS\n"
" typedef ResultValue<T> type;\n"
"#else\n"
" typedef T type;\n"
"#endif\n"
" };\n"
"\n"
" template <>"
" struct ResultValueType<void>\n"
" {\n"
"#ifdef VK_CPP_NO_EXCEPTIONS\n"
" typedef Result type;\n"
"#else\n"
" typedef void type;\n"
"#endif\n"
" };\n"
"\n"
);
std::string const createResultValueHeader = (
" inline ResultValueType<void>::type createResultValue( Result result, char const * message )\n"
" {\n"
"#ifdef VK_CPP_NO_EXCEPTIONS\n"
" assert( result == Result::eSuccess );\n"
" return result;\n"
"#else\n"
" if ( result != Result::eSuccess )\n"
" {\n"
" throw std::system_error( result, message );\n"
" }\n"
"#endif\n"
" }\n"
"\n"
" template <typename T>\n"
" inline typename ResultValueType<T>::type createResultValue( Result result, T & data, char const * message )\n"
" {\n"
"#ifdef VK_CPP_NO_EXCEPTIONS\n"
" assert( result == Result::eSuccess );\n"
" return ResultValue<T>( result, data );\n"
"#else\n"
" if ( result != Result::eSuccess )\n"
" {\n"
" throw std::system_error( result, message );\n"
" }\n"
" return data;\n"
"#endif\n"
" }\n"
"\n"
" inline Result createResultValue( Result result, char const * message, std::initializer_list<Result> successCodes )\n"
" {\n"
"#ifdef VK_CPP_NO_EXCEPTIONS\n"
" assert( std::find( successCodes.begin(), successCodes.end(), result ) != successCodes.end() );\n"
"#else\n"
" if ( std::find( successCodes.begin(), successCodes.end(), result ) == successCodes.end() )\n"
" {\n"
" throw std::system_error( result, message );\n"
" }\n"
"#endif\n"
" return result;\n"
" }\n"
"\n"
" template <typename T>\n"
" inline ResultValue<T> createResultValue( Result result, T & data, char const * message, std::initializer_list<Result> successCodes )\n"
" {\n"
"#ifdef VK_CPP_NO_EXCEPTIONS\n"
" assert( std::find( successCodes.begin(), successCodes.end(), result ) != successCodes.end() );\n"
"#else\n"
" if ( std::find( successCodes.begin(), successCodes.end(), result ) == successCodes.end() )\n"
" {\n"
" throw std::system_error( result, message );\n"
" }\n"
"#endif\n"
" return ResultValue<T>( result, data );\n"
" }\n"
"\n"
);
// trim from end // trim from end
std::string trimEnd(std::string const& input) std::string trimEnd(std::string const& input)
{ {
@ -656,17 +749,21 @@ std::string extractTag(std::string const& name)
size_t findReturnIndex(CommandData const& commandData, std::map<size_t,size_t> const& vectorParameters) size_t findReturnIndex(CommandData const& commandData, std::map<size_t,size_t> const& vectorParameters)
{ {
for (size_t i = 0; i < commandData.arguments.size(); i++) if ((commandData.returnType == "Result") || (commandData.returnType == "void"))
{ {
if ((commandData.arguments[i].type.find('*') != std::string::npos) && (commandData.arguments[i].type.find("const") == std::string::npos) && !isVectorSizeParameter(vectorParameters, i)) for (size_t i = 0; i < commandData.arguments.size(); i++)
{ {
#if !defined(NDEBUG) if ((commandData.arguments[i].type.find('*') != std::string::npos) && (commandData.arguments[i].type.find("const") == std::string::npos) && !isVectorSizeParameter(vectorParameters, i)
for (size_t j = i + 1; j < commandData.arguments.size(); j++) && ((vectorParameters.find(i) == vectorParameters.end()) || commandData.twoStep || (commandData.successCodes.size() == 1)))
{ {
assert((commandData.arguments[j].type.find('*') == std::string::npos) || (commandData.arguments[j].type.find("const") != std::string::npos)); #if !defined(NDEBUG)
} for (size_t j = i + 1; j < commandData.arguments.size(); j++)
{
assert((commandData.arguments[j].type.find('*') == std::string::npos) || (commandData.arguments[j].type.find("const") != std::string::npos));
}
#endif #endif
return i; return i;
}
} }
} }
return ~0; return ~0;
@ -1827,10 +1924,14 @@ void writeFunctionBody(std::ofstream & ofs, std::string const& indentation, std:
{ {
if ((it1->first != returnIndex) && (it0->second == it1->second)) if ((it1->first != returnIndex) && (it0->second == it1->second))
{ {
ofs << indentation << " if ( " << reduceName(commandData.arguments[it0->first].name) << ".size() != " << reduceName(commandData.arguments[it1->first].name) << ".size() )" << std::endl ofs << "#ifdef VK_CPP_NO_EXCEPTIONS" << std::endl
<< indentation << " assert( " << reduceName(commandData.arguments[it0->first].name) << ".size() == " << reduceName(commandData.arguments[it1->first].name) << ".size() );" << std::endl
<< "#else" << std::endl
<< indentation << " if ( " << reduceName(commandData.arguments[it0->first].name) << ".size() != " << reduceName(commandData.arguments[it1->first].name) << ".size() )" << std::endl
<< indentation << " {" << std::endl << indentation << " {" << std::endl
<< indentation << " throw std::logic_error( \"vk::" << className << "::" << functionName << ": " << reduceName(commandData.arguments[it0->first].name) << ".size() != " << reduceName(commandData.arguments[it1->first].name) << ".size()\" );" << std::endl << indentation << " throw std::logic_error( \"vk::" << className << "::" << functionName << ": " << reduceName(commandData.arguments[it0->first].name) << ".size() != " << reduceName(commandData.arguments[it1->first].name) << ".size()\" );" << std::endl
<< indentation << " }" << std::endl; << indentation << " }" << std::endl
<< "#endif // VK_CPP_NO_EXCEPTIONS" << std::endl;
} }
} }
} }
@ -1838,36 +1939,43 @@ void writeFunctionBody(std::ofstream & ofs, std::string const& indentation, std:
} }
// write the local variable to hold a returned value // write the local variable to hold a returned value
if ((returnIndex != ~0) && (commandData.returnType != returnType)) if (returnIndex != ~0)
{ {
ofs << indentation << " " << returnType << " " << reduceName(commandData.arguments[returnIndex].name); if (commandData.returnType != returnType)
std::map<size_t, size_t>::const_iterator it = vectorParameters.find(returnIndex);
if (it != vectorParameters.end() && !commandData.twoStep)
{ {
std::string size; ofs << indentation << " " << returnType << " " << reduceName(commandData.arguments[returnIndex].name);
if ((it->second == ~0) && !commandData.arguments[returnIndex].len.empty())
std::map<size_t, size_t>::const_iterator it = vectorParameters.find(returnIndex);
if (it != vectorParameters.end() && !commandData.twoStep)
{ {
size = reduceName(commandData.arguments[returnIndex].len); std::string size;
size_t pos = size.find("->"); if ((it->second == ~0) && !commandData.arguments[returnIndex].len.empty())
assert(pos != std::string::npos);
size.replace(pos, 2, ".");
}
else
{
for (std::map<size_t, size_t>::const_iterator sit = vectorParameters.begin(); sit != vectorParameters.end(); ++sit)
{ {
if ((sit->first != returnIndex) && (sit->second == it->second)) size = reduceName(commandData.arguments[returnIndex].len);
size_t pos = size.find("->");
assert(pos != std::string::npos);
size.replace(pos, 2, ".");
}
else
{
for (std::map<size_t, size_t>::const_iterator sit = vectorParameters.begin(); sit != vectorParameters.end(); ++sit)
{ {
size = reduceName(commandData.arguments[sit->first].name) + ".size()"; if ((sit->first != returnIndex) && (sit->second == it->second))
break; {
size = reduceName(commandData.arguments[sit->first].name) + ".size()";
break;
}
} }
} }
assert(!size.empty());
ofs << "( " << size << " )";
} }
assert(!size.empty()); ofs << ";" << std::endl;
ofs << "( " << size << " )"; }
else if (1 < commandData.successCodes.size())
{
ofs << indentation << " " << commandData.arguments[returnIndex].pureType << " " << reduceName(commandData.arguments[returnIndex].name) << ";" << std::endl;
} }
ofs << ";" << std::endl;
} }
// local count variable to hold the size of the vector to fill // local count variable to hold the size of the vector to fill
@ -1950,23 +2058,32 @@ void writeFunctionBody(std::ofstream & ofs, std::string const& indentation, std:
{ {
ofs << indentation << " } while ( result == Result::eIncomplete );" << std::endl; ofs << indentation << " } while ( result == Result::eIncomplete );" << std::endl;
} }
writeExceptionCheck(ofs, indentation, className, functionName, {"eSuccess"});
} }
} }
else if ((commandData.returnType == "Result") || !commandData.successCodes.empty())
{
writeExceptionCheck(ofs, indentation, className, functionName, commandData.successCodes);
}
// return the returned value if ((commandData.returnType == "Result") || !commandData.successCodes.empty())
if ((returnIndex != ~0) && (commandData.returnType != returnType)) {
ofs << indentation << " return createResultValue( result, ";
if (returnIndex != ~0)
{
ofs << reduceName(commandData.arguments[returnIndex].name) << ", ";
}
ofs << "\"vk::" << (className.empty() ? "" : className + "::") << functionName << "\"";
if (1 < commandData.successCodes.size() && !commandData.twoStep)
{
ofs << ", { Result::" << commandData.successCodes[0];
for (size_t i = 1; i < commandData.successCodes.size(); i++)
{
ofs << ", Result::" << commandData.successCodes[i];
}
ofs << " }";
}
ofs << " );" << std::endl;
}
else if ((returnIndex != ~0) && (commandData.returnType != returnType))
{ {
ofs << indentation << " return " << reduceName(commandData.arguments[returnIndex].name) << ";" << std::endl; ofs << indentation << " return " << reduceName(commandData.arguments[returnIndex].name) << ";" << std::endl;
} }
else if (returnType == "Result")
{
ofs << indentation << " return result;" << std::endl;
}
ofs << indentation << "}" << std::endl; ofs << indentation << "}" << std::endl;
} }
@ -1987,7 +2104,7 @@ void writeFunctionHeader(std::ofstream & ofs, std::string const& indentation, st
assert(commandData.arguments[3].name == "dataSize"); assert(commandData.arguments[3].name == "dataSize");
skippedArguments.insert(3); skippedArguments.insert(3);
} }
if ((returnIndex != ~0) && (commandData.returnType != returnType)) if (returnIndex != ~0)
{ {
skippedArguments.insert(returnIndex); skippedArguments.insert(returnIndex);
} }
@ -2004,12 +2121,30 @@ void writeFunctionHeader(std::ofstream & ofs, std::string const& indentation, st
assert((returnType.substr(0, 12) == "std::vector<") && (returnType.find(',') != std::string::npos) && (12 < returnType.find(','))); assert((returnType.substr(0, 12) == "std::vector<") && (returnType.find(',') != std::string::npos) && (12 < returnType.find(',')));
ofs << "template <typename Allocator = std::allocator<" << returnType.substr(12,returnType.find(',')-12) << ">>" << std::endl ofs << "template <typename Allocator = std::allocator<" << returnType.substr(12,returnType.find(',')-12) << ">>" << std::endl
<< indentation; << indentation;
if ((returnType != commandData.returnType) && (commandData.returnType != "void"))
{
ofs << "typename ";
}
} }
else if (!commandData.handleCommand) else if (!commandData.handleCommand)
{ {
ofs << "inline "; ofs << "inline ";
} }
ofs << returnType << " " << reduceName(name) << "("; if ((returnType != commandData.returnType) && (commandData.returnType != "void"))
{
assert(commandData.returnType == "Result");
ofs << "ResultValueType<" << returnType << ">::type ";
}
else if ((returnIndex != ~0) && (1 < commandData.successCodes.size()))
{
assert(commandData.returnType == "Result");
ofs << "ResultValue<" << commandData.arguments[returnIndex].pureType << "> ";
}
else
{
ofs << returnType << " ";
}
ofs << reduceName(name) << "(";
if (skippedArguments.size() + (commandData.handleCommand ? 1 : 0) < commandData.arguments.size()) if (skippedArguments.size() + (commandData.handleCommand ? 1 : 0) < commandData.arguments.size())
{ {
size_t lastArgument = ~0; size_t lastArgument = ~0;
@ -2891,7 +3026,9 @@ int main( int argc, char **argv )
<< "}" << std::endl << "}" << std::endl
<< std::endl << std::endl
<< "namespace vk" << std::endl << "namespace vk" << std::endl
<< "{" << std::endl; << "{" << std::endl
<< resultValueHeader
<< createResultValueHeader;
writeTypes(ofs, vkData, defaultValues); writeTypes(ofs, vkData, defaultValues);
writeEnumsToString(ofs, vkData); writeEnumsToString(ofs, vkData);

File diff suppressed because it is too large Load Diff