Using YAML-cpp, how to identify unknown keys? - yaml-cpp

The use case is stepping through a configuration file written in YAML. I need to check each key and parse its value accordingly. I like the idea of using random-access methods like doc["key"] >> value, but what I really need to do is warn the user of unrecognized keys in the config file, in case they, for example, misspelled a key. I don't know how to do that without iterating through the file.
I know I can do this using YAML::Iterator, like so
for (YAML::Iterator it=doc.begin(); it<doc.end(); ++it)
{
std::string key;
it.first() >> key;
if (key=="parameter") { /* do stuff, possibly iterating over nested keys */ }
} else if (/* */) {
} else {
std::cerr << "Warning: bad parameter" << std::endl;
}
}
but is there a simpler way to do this? My way seems to completely circumvent any error checking built into YAML-cpp, and it seems to undo all the simplicity of randomly accessing the keys.

If you're worried about a key not being there because the user misspelled it, you can just use FindValue:
if(const YAML::Node *pNode = doc.FindValue("parameter")) {
// do something
} else {
std::cerr << "Parameter missing\n";
}
If you genuinely want to get all keys in the map outside of your specific list, then you'll have to iterate through as you're doing.

Related

How to properly log Vulkan result type strings

Logging VkResult enum values
The VkResult enum contains a lot of values. Unfortunately though, they are C enums which aliases an integer, so I cannot easily just log their names to the console. For this purpose, I am envisioning a function which does something like this:
void graphics::log_vk_result(VkResult result)
{
switch (result)
{
case VK_SUCCESS:
log_core_debug("VK_SUCCESS"); return;
case VK_NOT_READY:
log_core_debug("VK_NOT_READY"); return;
[...]
}
But some of the enum values are only supported by certain extensions, as indicated here. An example: The extension VK_EXT_debug_report introduces the following value to the enumeration: VK_ERROR_VALIDATION_FAILED_EXT. So my idea for (potentially) more portable code would be something like this:
void graphics::log_vk_result(VkResult result)
{
switch (result)
{
[...]
#if defined(VK_EXT_DEBUG_REPORT_EXTENSION_NAME)
case VK_ERROR_VALIDATION_FAILED_EXT:
log_core_debug("VK_ERROR_VALIDATION_FAILED_EXT");
#endif
}
I found this name by looking at the extension manual page. I cannot easily see whether or not VK_EXT_DEBUG_REPORT_EXTENSION_NAME is a macro or an enum - it is a const char* but stated under the section "New Enum Constants". So checking for this particular value, for this particular extension, was my default choice.
[I do realize this extension is marked as deprecated, and I'm not using it! I only use it as an example here.]
I have two questions:
Is this needed?
Is this the correct way of doing this?
Thanks a lot!
All of this is unnecessary, since Vulkan SDK already includes the desired functionality:
#include <vulkan/vk_enum_string_helper.h>
void graphics::log_vk_result( const VkResult result ){
log_core_debug( string_VkResult(result) );
}

Does C++/WinRT provide mapping from enum symbol to string name?

I'm using C++/WinRT. The projection includes many enums. I find myself building my own table of enum values to string literals. This is not a big deal for enums with only a few defined values, but it's a pain when there are a lot of them.
What I really want is some form of compile-time or run-time reflection that converts an enum value into the string representation of the compile-time name that represents a given enum value. The code snippet below demonstrates. How can this be automated?
std::wostream& operator<< (
std::wostream& wout,
winrt::Windows::Graphics::DirectX::DirectXPixelFormat e)
{
// https://learn.microsoft.com/en-us/uwp/api/windows.graphics.directx.directxpixelformat
using winrt::Windows::Graphics::DirectX::DirectXPixelFormat;
switch (e) {
case DirectXPixelFormat::R8G8B8A8Int:
wout << L"R8G8B8A8Int";
break;
case DirectXPixelFormat::B8G8R8A8UIntNormalized:
wout << L"B8G8R8A8UIntNormalized";
break;
default:
// TODO: Many enums cases are missing.
// Find a way to compile-time-generate the string values from enum value.
wout << L"Unknown (" << std::to_wstring(static_cast<int32_t>(e)) << L")";
}
return wout;
}
I could build something that parses the winrt/*.h files to generate a header containing arrays of string literals, then #include the generated header. There probably exists sample code for doing this type of thing unrelated to C++/WinRT. But maybe C++/WinRT includes metadata in the SDK, which combined with one of the C++/WinRT command line tools, can easily do this for me? If it's there I have not found it.
I did find ApiInformation interface from winrt/Windows.Foundation.Metadata.h, as well as explanation of "Version Adaptive Code". I had hoped that OS COM interface behind ApiInformation has way to query a name for an enum value, but I was unable to find an answer there.
https://learn.microsoft.com/en-us/uwp/api/Windows.Foundation.Metadata.ApiInformation
how about this
https://learn.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/move-to-winrt-from-cx#tostring
namespace winrt
{
hstring to_hstring(StatusEnum status)
{
switch (status)
{
case StatusEnum::Success: return L"Success";
case StatusEnum::AccessDenied: return L"AccessDenied";
case StatusEnum::DisabledByPolicy: return L"DisabledByPolicy";
default: return to_hstring(static_cast<int>(status));
}
}
}

Is it safe to call sc_fifo::nb_write() from a SC_THREAD process?

I am converting some of my code from a SC_THREAD to a SC_METHOD. My question is, do I need to stop using the sc_fifo class? I realize an SC_METHOD should not call sc_fifo.write() because this uses a wait call which is not allowed for functions that cannot be suspended. However, sc_fifo provides non-blocking versions of various functions and potentially I could use these instead. Some of the documentation I've read indicates you should never use sc_fifo from a SC_METHOD at all but provided no justification.
Here is a sample of code I am currently using.
class Example : public sc_module {
public:
sc_fifo<int> myFifo;
sc_in<bool> clock_in;
SC_HAS_PROCESS(Example);
// constructor
Example(sc_module_name name) : sc_module(name) {
SC_METHOD(read);
sensitive << clock_in;
}
void read() {
int value = -1;
bool success = myFifo.nb_read(value);
if (success) { cout << "Read value " << value << endl; }
else { cout << "No read done but that's okay." << endl; }
}
};
int sc_main(int argc, char* argv[]) {
sc_clock clock("clock");
Example example("example");
example.clock_in(clock);
sc_start(10, SC_NS);
return 0;
}
This throws no errors even though I am calling an sc_fifo function from a SC_METHOD. Is it bad policy to use nb_read() from inside a SC_METHOD? If so why?
Using sc_fifo non-blocking calls from SC_METHOD should be fine.
I have not found any place in standard manual that prohibits it.
Neither nb_read, nor nb_write, as their names suggest, call wait internally so it's fine to use them from an SC_METHOD.
While your example code works, it's rather inefficient when things are put into the fifo infrequently. If you want your code to be more event driven, you could make the SC_METHOD sensitive to sc_fifo.data_written_event(); then it will only be called when something is actually written to the fifo (though it's still a good idea to check that nb_read returns true in case something else pulled from the same fifo). Of course, this would skip your "No read done but that's okay." prints.
Also, I think the title of your question probably meant to ask about calling nb_write from SC_METHOD rather than SC_THREAD.

How can I get fewer Techlog DataSelection events?

I wrote this test for DataSelection Event in my ternary plot in Techlog, and it gets too much data.
What am I doing wrong here?
In run method – subscribe to event:
void SetupTernaryPlot::run()
{
workspace.connect(Workspace::SelectionChanged, this, SLOT(onSelectionChanged(const Slb::Techlog::SelectionChangedArgs&)));
}
This is my event handler:
void SetupTernaryPlot::onSelectionChanged(const Slb::Techlog::SelectionChangedArgs args)
{
qWarning() << "TernaryPlot::onInteractiveSelectionChanged";
int i=0;
foreach (Selection selection, args.selectionsChanged())
{
qWarning() << "Interactive Selection " << i++ << selection.dataset().referenceVariable().rowCount() << endl; //selectlist;
}
}
My event handler is getting too many points. How can I know what has been selected?
It is indeed possible to achieve this, even though the solution is not very elegant at this point.
If you study the "setuplogview" sample (SetupLogview::onSelectionChanged) in the package, you can find that you may use using -1 to filter out non-selected indices.
(If you have access to WAT, there is a ticket created to enhance this https://wat.grabels-fr0235.slb.com/techlog/ticket/24300)

Complex check-methods with boost.test

I want to test different constructors of a string class. Therefore I wrote myself a test method that checks a couple standard things:
void checkStringStandards(String& s, size_t length, const char* text){
BOOST_CHECK_EQUAL(s.length(), length);
...
}
Then I added a test method
BOOST_AUTO_TEST_CASE(String_construct){
String s1;
checkStringStandards(s1, 0, "");
String s2("normal char");
checkStringStandards(s2, 11, "normal char");
}
The problem is, that when it fails, I only get the line- and file information from within checkStringStandards ! I can't know by the output whether the first or the second call caused this.
What's the common fix for that?
Cheers!
The solution to this problem is to write a custom predicate that performs the checks and use BOOST_REQUIRE(custom_predicate(args)) in the different test cases. A custom predicate can take any arguments you want and returns boost::test_tools::predicate_result, a type that is compatible with the assertion macros in Boost.Test into which you can build up a detailed diagnostic message during failure.
To use your example:
using namespace boost::test_tools;
predicate_result checkStringStandards(String& s, size_t length, const char* text) {
predicate_result result{true};
if (s.length() != length) {
result = false;
result.message() << "\nString " << s
<< " differs in length; expected: "
<< length << ", actual: " << s.length();
}
...
return result;
}
BOOST_AUTO_TEST_CASE(String_construct){
String s1;
BOOST_REQUIRE(checkStringStandards(s1, 0, ""));
String s2("normal char");
BOOST_REQUIRE(checkStringStandards(s2, 11, "normal char"));
}
The curious \n at the beginning of the message is so that when the diagnostic is printed, the text with "String ... differs in length" will be emitted on it's own line. If the predicate fails, it bubbles its failure up to BOOST_REQUIRE which will trigger the test failure and report the failure at the line invoking BOOST_REQUIRE instead of inside your custom predicate.
There is another yuckier alternative that also achieves the same result by making your custom assertions as gigantic megamacros, but I find that so horrid I'm not even going to show an example of how to do it :).
there is no common fix for that. these BOOST_CHECK_... macros exist by intention to avoid function calls where the line number gets lost (unless explicitely passed as param).
you can get round this problem by looping through the parameter set inside your test case.