yaml-cpp doesn't roundtrip with local tags - c++

When I YAML::Load a node with a local tag, the tag type and tag contents are not preserved.
Minimal example
I am using the 0.7.0 conan package.
auto x = YAML::Node(42);
YAML::Emitter e;
e << YAML::LocalTag("x") << x;
std::string s = e.c_str();
auto y = YAML::Load(s);
std::cout << "before: " << s << std::endl;
std::cout << "tag: " << y.Tag() << std::endl;
std::cout << "after: " << YAML::Dump(y) << std::endl;
prints
before: !x 42
tag: !x
after: !<!x> 42
Expected:
before: !x 42
tag: x
after: !x 42
I suppose two things are going wrong here:
The leading exclamation mark is added to the tag contents
The tag type changes from _Tag::Type::PrimaryHandle to _Tag::Type::Verbatim
So I have two questions:
Is this a bug or am I doing it wrong? I am not 100% sure I correctly understand the complicated yaml specs for tags...
Is there any way to set the _Tag::Type for an existing node as a workaround?
Note: I already posted this question as a Github issue. Please excuse the redundancy.

Your problem is this code:
void EmitFromEvents::EmitProps(const std::string& tag, anchor_t anchor) {
if (!tag.empty() && tag != "?" && tag != "!")
m_emitter << VerbatimTag(tag);
if (anchor)
m_emitter << Anchor(ToString(anchor));
}
The primary problem is that the default emitter always produces verbatim tags. The secondary problem is that the node doesn't remember the tag style.
To answer the question is this a bug: No. The YAML spec does not guarantee any form of round-tripping. An implementation is allowed to emit YAML in any style it wants as long as the output's semantics are correct.
To answer the question of whether a workaround is possible: Not with the existing emitter – as you can see, there's no settable option that modifies this behavior. You could theoretically write an own emitter that handles this to your liking; I am not entirely sure whether the API gives you enough access to internals to easily adapt the existing emitter.
In any case, that would be too involved for a SO answer.

Related

Why would fstream.fail() return true or false

I'm working through some work with some code already provided. There is an if statement that includes 2 fstream.fails(). The code is continually returning true and I'm not sure if it's because of a problem with the provided code or if I am missing something.
I've googled around to try and better understand what could be going on, but due to me being new to C++, I'm finding it hard to find an answer that helps me understand what might be going on.
The provided code where I think might be a problem.
bool Navigation::BuildNetwork(const string &fileNamePlaces, const string &fileNameLinks)
{
fstream finPlaces(fileNamePlaces);
fstream finLinks(fileNameLinks);
if (finPlaces.fail() || finLinks.fail()) return false;
ifstream();
// Add your code here
}
Where the "Build network" function is called
ACW_Wrapper wrapper("log.txt");
// Build Navigation
wrapper.startTimer();
Navigation nav;
if (nav.BuildNetwork("Places.csv", "Links.csv")) {
const auto elapsed = wrapper.stopTimer();
std::cout << std::fixed << std::setprecision(1) << "BuildNetwork - " << elapsed << " microseconds" << std::endl;
}
else {
std::cout << "\n*** Error *** BuildNetwork" << std::endl;
}
I would expect it to return false since this is provided code, but I'm unsure if I need to add something that would give me the expected outcome.
From the ios::fail documentation:
true if badbit (Read/writing error on I/O operation) and/or failbit (Logical error on i/o operation) are set.
which suggests that at least one of the two files is not opened successfully.
The problem is not in the code, the problem is with your program trying to open files that are not probably found (or it doesn't have permissions to).
Copy the files to the same workspace (folder) with your executable, and try again.

sf::String put into std::map key doesn't work - the vaule is not saved into map [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
as I wrote in the topic - I try to put sf::String into map first argument and it does not work. Here's the code:
void Flashcards::add(sf::String sf_string) {
std::string text = sf_string.toAnsiString();
std::pair<std::string,std::string> pairr = std::make_pair(text,"<Polish translation>");
std::cout << "Inserting: " << pairr.first << std::endl;
all_words.insert(pairr); //std::map<std::string, std::string> variable
void Flashcards::show() {
std::cout << "Flashcards:\n";
for (std::map<std::string, std::string>::iterator it = all_words.begin(); it != all_words.end(); it++)
{
std::cout << "English word: " << it->first
<< " " << "Polish word: " << it->second << std::endl;
}
The result in console is:
Inserting: //a word//
Flashcards:
Polish word: <Polish translation>
Instead of needed:
Inserting: hello
Flashcards:
English word: //a word// Polish word: <Polish translation>
Here are the variations I have already tried:
1) I switched the arguments so it looked like this: std::make_pair("<Polish translation>",text); and it works - hardcoded key and the value are both showed in the console (but I don't want hardcoding, what is obvious).
2) Note that this line: std::cout << "Inserting: " << pairr.first << std::endl; shows that the key value is converted into std::string correctly - calling this will show value we have just typed on the keyboard.
3) I tried to send the sf::String value directly to the std::make_pair() method, it works exactly the same as putting std::string there.
Can somebody say how to make this work?
The string you are providing as an argument to the add method obviously ends with a \r (carriage return) character, probably because you are reading it from a Windows text file using a Unix/Linux execution environment. If you capture the output of your program in a file and look at it with a hexdumper (such as hd), you should immediately see what is going on.
It certainly has nothing to do with your use of the C++ standard library. However, you don't need to go to all that work to insert an entry into a std::map. Just do this:
all_words[key] = value;
As long as key has the right type (or there is an automatic conversion), that will do precisely what you want in a single line easily-understood line, and probably more efficiently as well.

C++ RedisClient : how does RedisValue.toInt() work?

This is about RedisClient, which is a C++ client.
I know that you can't store integers in Redis (that are internally converted).
RedisSyncClient::command itself does not support integers as RedisBuffer can't be initialized with int, so:
redis->command("SET", "mykey", 1);
won't compile (you need to add numbers as string).
However RedisValue can be initialized with int (not sure when it is used) and it contains a public "toInt()" method:
redis->command("SET", "mykey", "1");
result = redis->command("GET", "mykey");
cout << "INT: " << result.toInt() << " , STR: " << result.toString() << endl;
INT: 0 , STR : 1
At first I thought that internally strings were being converted to int, but it always return "0". Testing "RedisValue.isInt()" it seems it fails to recognize numbers as it returns "false".
What is the intention of "toInt()" if numbers are only seen (by this library) as strings?
Am I using it incorrectly?
Is this a work-in-progress feature?
Now things make sense to me...
It seems that it may be used for redis responses like:
result = redis->command("EXISTS", "mykey");
cout << "? " << result.isInt() << endl;
? 1
In this case toInt() works as expected.
I just need to look into redis documentation and see which commands return int. It is not designed to be used with "normal" values.
(sorry to answer my own question, I would be happy to accept other answers if they cover things I missed out).

Determining the location of C++11 regular expression matches

How do I efficiently determine the location of a capture group inside a searched string? Getting the location of the entire match is easy, but I see no obvious ways to get at capture groups beyond the first.
This is a simplified example, lets presume "a*" and "b*" are complicated regexes that are expensive to run.
#include <iostream>
#include <regex>
#include <string>
using namespace std;
int main()
{
regex matcher("a*(needle)b*");
smatch findings;
string haystack("aaaaaaaaneedlebbbbbbbbbbbbbb");
if( regex_match(haystack, findings, matcher) )
{
// What do I put here to know how the offset of "needle" in the
// string haystack?
// This is the position of the entire, which is
// always 0 with regex_match, with regex_search
cout << "smatch::position - " << findings.position() << endl;
// Is this just a string or what? Are there member functions
// That can be called?
cout << "Needle - " << findings[1] << endl;
}
return 0;
}
If it helps I built this question in Coliru: http://coliru.stacked-crooked.com/a/885a6b694d32d9b5
I will not mark this as and answer until 72 hours have passed and no better answers are present.
Before asking this I presumed smatch::position took no arguments I cared about, because when I read the cppreference page the "sub" parameter was not obviously an index into the container of matches. I thought it had something to do with "sub"strings and the offset value of the whole match.
So my answer is:
cout << "Needle Position- " << findings.position(1) << endl;
Any explanation on this design, or other issues my line of thinking may have caused would be appreciated.
According to the documentation, you can access the iterator pointing to the beginning and the end of the captured text via match[n].first and match[n].second. To get the start and end indices, just do pointer arithmetic with haystack.begin().
if (findings[1].matched) {
cout << "[" << findings[1].first - haystack.begin() << "-"
<< findings[1].second - haystack.begin() << "] "
<< findings[1] << endl;
}
Except for the main match (index 0), capturing groups may or may not capture anything. In such cases, first and second will point to the end of the string.
I also demonstrate the matched property of sub_match object. While it's unnecessary in this case, in general, if you want to print out the indices of the capturing groups, it's necessary to check whether the capturing group matches anything first.

Reading text file by scanning for keywords

As part of a bigger application I am working on a class for reading input from a text file for use in the initialization of the program. Now I am myself fairly new to programming, and I only started to learn C++ in December, so I would be very grateful for some hints and ideas on how to get started! I apologise in advance for a rather long wall of text.
The text file format is "keyword-driven" in the following way:
There are a rather small number of main/section keywords (currently 8) that need to be written in a given order. Some of them are optional, but if they are included they should adhere to the given ordering.
Example:
Suppose there are 3 potential keywords ordered like as follows:
"KEY1" (required)
"KEY2" (optional)
"KEY3" (required)
If the input file only includes the required ones, the ordering should be:
"KEY1"
"KEY3"
Otherwise it should be:
"KEY1"
"KEY2"
"KEY3"
If all the required keywords are present, and the total ordering is ok, the program should proceed by reading each section in the sequence given by the ordering.
Each section will include a (possibly large) amount of subkeywords, some of which are optional and some of which are not, but here the order does NOT matter.
Lines starting with characters '*' or '--' signify commented lines, and they should be ignored (as well as empty lines).
A line containing a keyword should (preferably) include nothing else than the keyword. At the very least, the keyword must be the first word appearing there.
I have already implemented parts of the framework, but I feel my approach so far has been rather ad-hoc. Currently I have manually created one method per section/main keyword , and the first task of the program is to scan the file for to locate these keywords and pass the necessary information on to the methods.
I first scan through the file using an std::ifstream object, removing empty and/or commented lines and storing the remaining lines in an object of type std::vector<std::string>.
Do you think this is an ok approach?
Moreover, I store the indices where each of the keywords start and stop (in two integer arrays) in this vector. This is the input to the above-mentioned methods, and it would look something like this:
bool readMAINKEY(int start, int stop);
Now I have already done this, and even though I do not find it very elegant, I guess I can keep it for the time being.
However, I feel that I need a better approach for handling the reading inside of each section, and my main issue is how should I store the keywords here? Should they be stored as arrays within a local namespace in the input class or maybe as static variables in the class? Or should they be defined locally inside relevant functions? Should I use enums? The questions are many!
Now I've started by defining the sub-keywords locally inside each readMAINKEY() method, but I found this to be less than optimal. Ideally I want to reuse as much code as possible inside each of these methods, calling upon a common readSECTION() method, and my current approach seems to lead to much code duplication and potential for error in programming. I guess the smartest thing to do would simply be to remove all the (currently 8) different readMAINKEY() methods, and use the same function for handling all kinds of keywords. There is also the possibility for having sub-sub-keywords etc. as well (i.e. a more general nested approach), so I think maybe this is the way to go, but I am unsure on how it would be best to implement it?
Once I've processed a keyword at the "bottom level", the program will expect a particular format of the following lines depending on the actual keyword. In principle each keyword will be handled differently, but here there is also potential for some code reuse by defining different "types" of keywords depending on what the program expects to do after triggering the reading of it. Common task include e.g. parsing an integer or a double array, but in principle it could be anything!
If a keyword for some reason cannot be correctly processed, the program should attempt as far as possible to use default values instead of terminating the program (if reasonable), but an error message should be written to a logfile. For optional keywords, default values will of course also be used.
In order to summarise, therefore, my main questions are the following:
1. Do you think think my approach of storing the relevant lines in a std::vector<std::string> to be reasonable?
This will of course require me to do a lot of "indexing work" to keep track of where in the vector the different keywords are located. Or should I work more "directly" with the original std::ifstream object? Or something else?
2. Given such a vector storing the lines of the text file, how I can I best go about detecting the keywords and start reading the information following them?
Here I will need to take account of possible ordering and whether a keyword is required or not. Also, I need to check if the lines following each "bottom level" keyword is in the format expected in each case.
One idea I've had is to store the keywords in different containers depending on whether they are optional or not (or maybe use object(s) of type std::map<std::string,bool>), and then remove them from the container(s) if correctly processed, but I am not sure exactly how I should go about it..
I guess there is really a thousand different ways one could answer these questions, but I would be grateful if someone more experienced could share some ideas on how to proceed. Is there e.g. a "standard" way of doing such things? Of course, a lot of details will also depend on the concrete application, but I think the general format indicated here can be used in a lot of different applications without a lot of tinkering if programmed in a good way!
UPDATE
Ok, so let my try to be more concrete. My current application is supposed to be a reservoir simulator, so as part of the input I need information about the grid/mesh, about rock and fluid properties, about wells/boundary conditions throughout the simulation and so on. At the moment I've been thinking about using (almost) the same set-up as the commercial Eclipse simulator when it comes to input, for details see
http://petrofaq.org/wiki/Eclipse_Input_Data.
However, I will probably change things a bit, so nothing is set in stone. Also, I am interested in making a more general "KeywordReader" class that with slight modifications can be adapted for use in other applications as well, at least it can be done in a reasonable amount of time.
As an example, I can post the current code that does the initial scan of the text file and locates the positions of the main keywords. As I said, I don't really like my solution very much, but it seems to work for what it needs to do.
At the top of the .cpp file I have the following namespace:
//Keywords used for reading input:
namespace KEYWORDS{
/*
* Main keywords and corresponding boolean values to signify whether or not they are required as input.
*/
enum MKEY{RUNSPEC = 0, GRID = 1, EDIT = 2, PROPS = 3, REGIONS = 4, SOLUTION = 5, SUMMARY =6, SCHEDULE = 7};
std::string mainKeywords[] = {std::string("RUNSPEC"), std::string("GRID"), std::string("EDIT"), std::string("PROPS"),
std::string("REGIONS"), std::string("SOLUTION"), std::string("SUMMARY"), std::string("SCHEDULE")};
bool required[] = {true,true,false,true,false,true,false,true};
const int n_key = 8;
}//end KEYWORDS namespace
Then further down I have the following function. I am not sure how understandable it is though..
bool InputReader::scanForMainKeywords(){
logfile << "Opening file.." << std::endl;
std::ifstream infile(filename);
//Test if file was opened. If not, write error message:
if(!infile.is_open()){
logfile << "ERROR: Could not open file! Unable to proceed!" << std::endl;
std::cout << "ERROR: Could not open file! Unable to proceed!" << std::endl;
return false;
}
else{
logfile << "Scanning for main keywords..." << std::endl;
int nkey = KEYWORDS::n_key;
//Initially no keywords have been found:
startIndex = std::vector<int>(nkey, -1);
stopIndex = std::vector<int>(nkey, -1);
//Variable used to control that the keywords are written in the correct order:
int foundIndex = -1;
//STATISTICS:
int lineCount = 0;//number of non-comment lines in text file
int commentCount = 0;//number of commented lines in text file
int emptyCount = 0;//number of empty lines in text file
//Create lines vector:
lines = std::vector<std::string>();
//Remove comments and empty lines from text file and store the result in the variable file_lines:
std::string str;
while(std::getline(infile,str)){
if(str.size()>=1 && str.at(0)=='*'){
commentCount++;
}
else if(str.size()>=2 && str.at(0)=='-' && str.at(1)=='-'){
commentCount++;
}
else if(str.size()==0){
emptyCount++;
}
else{
//Found a non-empty, non-comment line.
lines.push_back(str);//store in std::vector
//Start by checking if the first word of the line is one of the main keywords. If so, store the location of the keyword:
std::string fw = IO::getFirstWord(str);
for(int i=0;i<nkey;i++){
if(fw.compare(KEYWORDS::mainKeywords[i])==0){
if(i > foundIndex){
//Found a valid keyword!
foundIndex = i;
startIndex[i] = lineCount;//store where the keyword was found!
//logfile << "Keyword " << fw << " found at line " << lineCount << " in lines array!" << std::endl;
//std::cout << "Keyword " << fw << " found at line " << lineCount << " in lines array!" << std::endl;
break;//fw cannot equal several different keywords at the same time!
}
else{
//we have found a keyword, but in the wrong order... Terminate program:
std::cout << "ERROR: Keywords have been entered in the wrong order or been repeated! Cannot continue initialisation!" << std::endl;
logfile << "ERROR: Keywords have been entered in the wrong order or been repeated! Cannot continue initialisation!" << std::endl;
return false;
}
}
}//end for loop
lineCount++;
}//end else (found non-comment, non-empty line)
}//end while (reading ifstream)
logfile << "\n";
logfile << "FILE STATISTICS:" << std::endl;
logfile << "Number of commented lines: " << commentCount << std::endl;
logfile << "Number of non-commented lines: " << lineCount << std::endl;
logfile << "Number of empty lines: " << emptyCount << std::endl;
logfile << "\n";
/*
Print lines vector to screen:
for(int i=0;i<lines.size();i++){
std:: cout << "Line nr. " << i << " : " << lines[i] << std::endl;
}*/
/*
* So far, no keywords have been entered in the wrong order, but have all the necessary ones been found?
* Otherwise return false.
*/
for(int i=0;i<nkey;i++){
if(KEYWORDS::required[i] && startIndex[i] == -1){
logfile << "ERROR: Incorrect input of required keywords! At least " << KEYWORDS::mainKeywords[i] << " is missing!" << std::endl;;
logfile << "Cannot proceed with initialisation!" << std::endl;
std::cout << "ERROR: Incorrect input of required keywords! At least " << KEYWORDS::mainKeywords[i] << " is missing!" << std::endl;
std::cout << "Cannot proceed with initialisation!" << std::endl;
return false;
}
}
//If everything is in order, we also initialise the stopIndex array correctly:
int counter = 0;
//Find first existing keyword:
while(counter < nkey && startIndex[counter] == -1){
//Keyword doesn't exist. Leave stopindex at -1!
counter++;
}
//Store stop index of each keyword:
while(counter<nkey){
int offset = 1;
//Find next existing keyword:
while(counter+offset < nkey && startIndex[counter+offset] == -1){
offset++;
}
if(counter+offset < nkey){
stopIndex[counter] = startIndex[counter+offset]-1;
}
else{
//reached the end of array!
stopIndex[counter] = lines.size()-1;
}
counter += offset;
}//end while
/*
//Print out start/stop-index arrays to screen:
for(int i=0;i<nkey;i++){
std::cout << "Start index of " << KEYWORDS::mainKeywords[i] << " is : " << startIndex[i] << std::endl;
std::cout << "Stop index of " << KEYWORDS::mainKeywords[i] << " is : " << stopIndex[i] << std::endl;
}
*/
return true;
}//end else (file opened properly)
}//end scanForMainKeywords()
You say your purpose is to read initialization data from a text file.
Seems you need to parse (syntax analyze) this file and store the data under the right keys.
If the syntax is fixed and each construction starts with a keyword, you could write a recursive descent (LL1) parser creating a tree (each node is a stl vector of sub-branches) to store your data.
If the syntax is free, you might pick JSON or XML and use an existing parsing library.