Cant Use Ranges on VkLayerProperties? - c++

I was trying out C++20 ranges while working on my Vulkan project, I decided I wanted to try to check if a layer was available before the client added it in my builder object.
I set up my layer properties vector like so:
//...
vkEnumerateInstanceLayerProperties(&amount_of_layers, nullptr);
std::vector<VkLayerProperties> layer_properties(amount_of_layers);
vkEnumerateInstanceLayerProperties(&amount_of_layers, layer_properties.data());
//...
If I print them out like so, it works just fine:
for(auto& current_properties : layer_properties)
std::cout << current_properties.layerName << "\n";
The problem comes when I tried to use ranges to filter them, this is not the original filter I tried to apply, but this has similar problems:
auto available_layers = layer_properties | std::views::filter(
[&](auto current_layer_properties) {
return std::string{current_layer_properties.layerName}.size() % 2 == 0;
}
);
I just need a count at this point, not to iterate so I just store it in available_layers.
However if I try to print out current_layer_properties.layerName I get the first few layer names, and then what looks like a bunch of data that is from the data segment of the Vulkan library binaries, it looks like JSON.
VK_LAYER_MESA_device_select
VK_LAYER_INTEL_nullhw
VK_LAYER_MESA_overlay
VK_LAYER_LUNARG_monitor
VK_LAYER_KHRONOS_synchronization2
VK_LAYER_LUNARG_api_dump
E_CREATE_NEW",
"label": "Log File Overwrite",
"description": "Specifies that log file initialization should overwrite an existing file when true, or append to an existing file when false.",
"type": "BOOL",
"default": true
}
]
}
]
}
]
}
//...
Same happens if I try to apply std::views::transform and turn layer_properties into a container/view of std::string the same thing happens.
Sometimes depending on my filter (I use a find to find a string in it, then omit the element if its not found) it goes on forever.
Am I doing something wrong with ranges? Or does this have something to do with Vulkan?
Does it have something to do with some sort of side effect these LunarG .gfxr/gfxrecon_capture log files I am seeing(the erroneous output looks related, but could be totally random)?
UPDATE[ 0 ]:
Someone in the comments requested I show how I print things, it has changed as I have debugged, but I will put it here (it also crashes without printing)
In the lambda for std::filter and/or std::transform I have put variations of the following:
std::cout << current_layer_properties.layerName << "\n";
std::cout << current_layer_properties << "\n"; //When I apply std::transform and turn it into a std::string or std::string_view
log<LogType::Debug>(std::cout, current_layer_properties);
Here is my log function
template<typename LogParameterType>
void log(
LogParameterType& log,
const std::string_view message,
const std::source_location location =
std::source_location::current()
)
{
if constexpr(DebugParameterConstant == true
&& LogParameterConstant == LogType::Debug)
return;
log << to_string(LogParameterConstant) << "::"
<< location.file_name() << "("
<< location.line() << ":"
<< location.column() << ")::"
<< location.function_name() << ": "
<< message << "\n";
}
My debug layer is not working but here is the function it is suppose to run:
//If anyone can think of a better way to do this please let me know :)
void vulkan_log(
VkDebugUtilsMessageSeverityFlagBitsEXT vulkan_log_type,
VkDebugUtilsMessageTypeFlagsEXT message_type,
const VkDebugUtilsMessengerCallbackDataEXT* callback_data
)
{
LogType log_type = LogType::Unkown;
std::string message_type_string = to_string(message_type);
switch(vulkan_log_type)
{
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT:
{
std::cerr << message_type_string;
log<LogType::Diagnostic>(std::cerr, callback_data->pMessage);
break;
}
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT:
{
std::cerr << message_type_string;
log<LogType::Error>(std::cerr, callback_data->pMessage);
break;
}
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT:
{
std::cerr << message_type_string;
log<LogType::Warning>(std::cerr, callback_data->pMessage);
break;
}
case VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT:
{
std::cout << message_type_string;
log<LogType::Note>(std::cout, callback_data->pMessage);
break;
}
default:
break;
}
}
Thanks!
TFB

Related

no instance of overloaded function AddSnapshotListener matches the argument list

i am trying to use Firebase cpp SDK in my win32 application. i used code from documentation
db->Collection("cities")
.WhereEqualTo("state", FieldValue::String("CA"))
.AddSnapshotListener([](const QuerySnapshot& snapshot, Error error) {
if (error == Error::kErrorOk) {
for (const DocumentChange& dc : snapshot.DocumentChanges()) {
switch (dc.type()) {
case DocumentChange::Type::kAdded:
std::cout << "New city: "
<< dc.document().Get("name").string_value() << '\n';
break;
case DocumentChange::Type::kModified:
std::cout << "Modified city: "
<< dc.document().Get("name").string_value() << '\n';
break;
case DocumentChange::Type::kRemoved:
std::cout << "Removed city: "
<< dc.document().Get("name").string_value() << '\n';
break;
}
}
} else {
std::cout << "Listen failed: " << error << '\n';
}
});
from : https://cloud.google.com/firestore/docs/query-data/listen#c++_4
but it gives me following error:
no instance of overloaded function "firebase::firestore::Query::AddSnapshotListener" matches the argument list
is there a way to solve this?
The documentation says the callback for Query::AddSnapshotListener takes 3 arguments, whereas your implementation accepts only two.
The proper signature would be:
.AddSnapshotListener([](const QuerySnapshot& snapshot, Error error, const std::string& error_msg) {
// ...
});
Edit:
The inconsistency between the code in your link and the offical API reference weirded me out a bit, so I dug a bit more. It looks like the third argument was added about 8 months ago, and the user guide just hasn't been update to reflect that yet.
That's really unfortunate.

Reading Json file's root in c++ with jsoncpp

File:
{
"somestring":{
"a":1,
"b":7,
"c":17,
"d":137,
"e":"Republic"
},
}
how can I read the somestring value by jsoncpp?
Use the getMemberNames() method.
Json::Value root;
root << jsonString;
Json::Value::Members propNames = root.getMemberNames();
std::string firstProp = propNames[0];
std::cout << firstProp << '\n'; // should print somestring
If you want to see all the properties, you can loop through it using an iterator:
for (auto it: propNames) {
cout << "Property: " << *it << " Value: " << root[*it].asString() << "\n";
}
This simple loop will only work for properties whose values are strings. If you want to handle nested objects, like in your example, you'll need to make it recursive, which I'm leaving as an exercise for the reader.

Converting DriverVersion to Human readable format

I have searched high and low for it, could not find any documentation, I am able to get the DriverVersion as described Here. Creating and enumerating the device drives is working so there is no need to look there. The DriverVersion is a type of "DWORDLONG". I need to convert this to Human readable format like 20.xx.xx.xx. There ain't any documentation on MSDN, or anywhere I have searched.
Any help will be appreciated.
Example value of "DriverVersion" : 1688863374327808
Code snippet, if at all its required,
SP_DEVINFO_DATA devInfo;
devInfo.cbSize = sizeof(SP_DEVINFO_DATA);
if (SetupDiEnumDeviceInfo(handle, 0, &devInfo))
{
if(SetupDiBuildDriverInfoList(handle,&devInfo,SPDIT_COMPATDRIVER))
{
SP_DRVINFO_DATA drvInfo;
drvInfo.cbSize = sizeof(SP_DRVINFO_DATA);
int i=0;
while(1)
{
try
{
if (SetupDiEnumDriverInfo(handle, &devInfo, SPDIT_COMPATDRIVER, i++, &drvInfo))
{
cout<<"Version :"<<drvInfo.DriverVersion<<endl; // Need Human Readable version here.
}
else
break;
}
catch(std::exception ex)
{
break;
}
}
}
}
You could use a ULARGE_INTEGER union, the HIWORD/LOWORD macros and string formatting utils like boost::format to do the following (untested code):
SP_DRVINFO_DATA driverInfoData;
ULARGE_INTEGER version;
version.QuadPart = driverInfoData.DriverVersion;
std::string versionStr = (boost::format("%s.%s.%s.%s")
% HIWORD(version.HighPart)
% LOWORD(version.HighPart)
% HIWORD(version.LowPart)
% LOWORD(version.LowPart)).str();
Following your code and to get rid of boost simply do:
std::cout << "Version: "
<< std::to_string(HIWORD(version.HighPart)) << "."
<< std::to_string(LOWORD(version.HighPart)) << "."
<< std::to_string(HIWORD(version.LowPart)) << "."
<< std::to_string(LOWORD(version.LowPart)) << std::endl;

Parse JSON array using casablanca

I am trying to read from a JSON response in Casablanca. The sent data looks like this:
{
"devices":[
{"id":"id1",
"type":"type1"},
{"id":"id2",
"type":"type2"}
]
}
Does anyone know how to do this? Casablanca tutorials only seem to care about creating such arrays and not about reading from them.
Let's assume you got your json as an http response:
web::json::value json;
web::http::http_request request;
//fill the request properly, then send it:
client
.request(request)
.then([&json](web::http::http_response response)
{
json = response.extract_json().get();
})
.wait();
Note that no error checking is done here, so let's assume everything works fine (--if not,see the Casablanca documentation and examples).
The returned json can then be read via the at(utility::string_t) function. In your case it is an array (you either know that or check it via is_array()):
auto array = json.at(U("devices")).as_array();
for(int i=0; i<array.size(); ++i)
{
auto id = array[i].at(U("id")).as_string();
auto type = array[i].at(U("type")).as_string();
}
With this you get the entries of the json response stored in string variables.
In reality, you further might want to check whether the response has the coresponding fields, e.g. via has_field(U("id")), and if so, check whether the entries are not null via is_null() -- otherwise, the as_string() function throws an exception.
The following is a recursive function I made for parsing JSON values in cpprestsdk, if you would like additional info or elaboration feel free to ask.
std::string DisplayJSONValue(web::json::value v)
{
std::stringstream ss;
try
{
if (!v.is_null())
{
if(v.is_object())
{
// Loop over each element in the object
for (auto iter = v.as_object().cbegin(); iter != v.as_object().cend(); ++iter)
{
// It is necessary to make sure that you get the value as const reference
// in order to avoid copying the whole JSON value recursively (too expensive for nested objects)
const utility::string_t &str = iter->first;
const web::json::value &value = iter->second;
if (value.is_object() || value.is_array())
{
ss << "Parent: " << str << std::endl;
ss << DisplayJSONValue(value);
ss << "End of Parent: " << str << std::endl;
}
else
{
ss << "str: " << str << ", Value: " << value.serialize() << std::endl;
}
}
}
else if(v.is_array())
{
// Loop over each element in the array
for (size_t index = 0; index < v.as_array().size(); ++index)
{
const web::json::value &value = v.as_array().at(index);
ss << "Array: " << index << std::endl;
ss << DisplayJSONValue(value);
}
}
else
{
ss << "Value: " << v.serialize() << std::endl;
}
}
}
catch (const std::exception& e)
{
std::cout << e.what() << std::endl;
ss << "Value: " << v.serialize() << std::endl;
}
return ss.str();
}

Displaying custom failure message in UnitTest++?

I've got a UnitTest++ test class, which allows me to test that a class is parsing some strings correctly. Before running the test, I create a fixture that contain several strings to be tested by various functions in a loop. It seems to work fine, but the problem is that, in case of error, UnitTest++ will always give me the same error line, so I won't know which string exactly is causing the issue.
For example, it will output:
"[UnitTest++] ..\trunk\tests\Test_ChineseUtil.cpp(46): error: Failure in ParsePinyinT: ChineseUtil::parsePinyinT(pinyinT) == pinyinN"
But that doesn't tell me which string is not being parsed correctly.
So what I would like is to set some custom error message when a test fails (in that particular case, I would give it the first item in my array). Basically, I need something like:
CHECK(theTest, "my error message")
Is there such function in UnitTest++? Or maybe there is a better way to do what I'm trying to do?
For information, here is the code of my class:
#include <third_party/unittest++/UnitTest++.h>
#include <Application.h>
#include <ChineseUtil.h>
using namespace hanzi;
namespace chineseUtilTests {
class PinyinFixture {
public:
PinyinFixture() {
ChineseUtil::initialize();
testData << "third tone" << QString::fromUtf8("wo3") << QString::fromUtf8("wǒ");
testData << "no tone" << QString::fromUtf8("wo") << QString::fromUtf8("wo");
testData << "second tone" << QString::fromUtf8("guo2") << QString::fromUtf8("guó");
testData << "first tone" << QString::fromUtf8("jia1") << QString::fromUtf8("jiā");
testData << "fifth tone" << QString::fromUtf8("jia5") << QString::fromUtf8("jia");
testData << "two dots" << QString::fromUtf8("nu:") << QString::fromUtf8("nü");
testData << "two dots and tone" << QString::fromUtf8("nu:3") << QString::fromUtf8("nǚ");
}
~PinyinFixture() {
}
QStringList testData;
};
TEST_FIXTURE(PinyinFixture, ParsePinyinN) {
for (int i = 0; i < testData.size(); i++) {
QString pinyinN = testData[i][1];
QString pinyinT = testData[i][2];
CHECK(ChineseUtil::parsePinyinN(pinyinN) == pinyinT);
}
}
TEST_FIXTURE(PinyinFixture, ParsePinyinT) {
for (int i = 0; i < testData.size(); i++) {
QString pinyinN = testData[i][1];
QString pinyinT = testData[i][2];
CHECK(ChineseUtil::parsePinyinT(pinyinT) == pinyinN);
}
}
} // chineseUtilTests
If your class has an equality operator, you should be able to, instead of typing
CHECK(something == something_else);
use
CHECK_EQUAL( something, something_else);
The fact that your classes allow a == makes me thing you can do this. If the test fails, you should get something along the lines of "Expected something but got something else".
If you need more information, there are a couple other things you can do.
One is to add your own custom output in the test. If you need to know the value of i specifically, you can add a printout of i before each CHECK. However, this output may be too lengthy for large loops, so you can add your check a second time.
CHECK(ChineseUtil::parsePinyinN(pinyinN) == pinyinT);
if ( ChineseUtil::parsePinyinN(pinyinN) != pinyinT )
{
cout << "Your own custom message " << i << endl;
}
Another possibility is to modify the source code of UnitTest++ itself, then recompile the library. While I don't know the exact steps to do what you want to do, I've modified UnitTest++/src/Checks.h to improve the output of CHECK_ARRAY2D_CLOSE so it was more readable.
I have not compiled or tested the following, but the gist of it is to copy the UnitTest++ CHECK macro and expand it to take a message parameter that is std::string and combine that with the string representing the stringified version of value.
#define CHECK_MESSAGE(value, message) \
do \
{ \
try { \
if (!UnitTest::Check(value)) \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), (std::string(#value)+message).c_str()); \
} \
catch (...) { \
UnitTest::CurrentTest::Results()->OnTestFailure(UnitTest::TestDetails(*UnitTest::CurrentTest::Details(), __LINE__), \
(std::string("Unhandled exception in CHECK(" #value)+message+std::string(", ")+message+std::string(")")).c_str()); \
} \
} while (0)