Attaching a Comment to a YAML::Node for Presentation in Output - c++11

I'm using yaml-cpp with C++11. I can create a YAML file using something simple like this:
#include <yaml-cpp/yaml.h>
#include <iostream>
int main(void)
{
YAML::Node topNode;
topNode["one"]["two"]["A"] = "foo";
topNode["one"]["two"]["B"] = 42;
std::cout << "%YAML 1.2\n---\n" << topNode;
return 0;
}
That will produce a YAML file like this:
%YAML 1.2
---
one:
two:
A: foo
B: 42
Lovely!
I can also produce exactly the same YAML file like this:
#include <yaml-cpp/yaml.h>
#include <iostream>
int main(void)
{
YAML::Emitter out;
out << YAML::BeginMap // document {
<< "one"
<< YAML::BeginMap // one {
<< "two"
<< YAML::BeginMap // two {
<< YAML::Key << "A" << YAML::Value << "foo"
<< YAML::Key << "B" << YAML::Value << 42
<< YAML::EndMap // two }
<< YAML::EndMap // one }
<< YAML::EndMap // document }
;
std::cout << "%YAML 1.2\n---\n"
<< out.c_str();
return 0;
}
The nice thing about the second approach is that I can also add comments into the output file:
#include <yaml-cpp/yaml.h>
#include <iostream>
int main(void)
{
YAML::Emitter out;
out << YAML::BeginMap // document {
<< "one"
<< YAML::BeginMap // one {
<< "two"
<< YAML::BeginMap // two {
<< YAML::Key << "A" << YAML::Value << "foo"
<< YAML::Comment("A should be 'foo'")
<< YAML::Key << "B" << YAML::Value << 42
<< YAML::Comment("B is meaningful")
<< YAML::EndMap // two }
<< YAML::EndMap // one }
<< YAML::EndMap // document }
;
std::cout << "%YAML 1.2\n---\n"
<< out.c_str();
return 0;
}
to produce:
%YAML 1.2
---
one:
two:
A: foo # A should be 'foo'
B: 42 # B is meaningful
My question if there is a way to add comments into the first approach? Perhaps something like this:
topNode["one"]["two"]["A"] = "foo";
topNode["one"]["two"]["A"].addComment("A should be 'foo'");
I could subclass YAML::Node, adding my addComment() method, but I don't want to re-write all of YAML::Emitter to get my comment appended appropriately. The code is there, but I don't know how to get to it. How? Can you point me to an example or an approach?
I understand that the YAML specification says that comments are not an integral part of a YAML file, and can be discarded. My users find them useful, so I don't relish a debate that begins with "Your question is stupid." :-)

That is not possible with the current API. The Emitter uses an EventHandler which, as you can see, is not able to emit comments.
The Emit function that creates the events does not create any comment events via other means either.
Since operator<< on Node will internally use the Emitter class, there's no way to emit comments by adding them to a node, unless you rewrite the emitter yourself.

Related

Boost.Fibers hosted by worker threads seem not to work – why?

I'd like to use Boost.Fibers hosted by worker threads instead of just threads. I think I've done everything as in the manual while writing the code shown below, but it seems not to work – "<anonymous> called" is missing in the output.
Does anyone have an idea why?
#include <boost/fiber/all.hpp>
#include <boost/thread/barrier.hpp>
#include <cstdint>
#include <cstdlib>
#include <iostream>
#include <thread>
#define RIGHTNOW (std::cerr << "[thread " << std::this_thread::get_id() << "] ")
static inline
void run_worker(uint32_t threads, boost::barrier& barrier) {
RIGHTNOW << "run_worker(" << threads << ", " << (void*)&barrier << ") called" << std::endl;
boost::fibers::use_scheduling_algorithm<boost::fibers::algo::work_stealing>(threads);
barrier.wait();
RIGHTNOW << "run_worker(" << threads << ", " << (void*)&barrier << ") awaited everything else" << std::endl;
boost::fibers::mutex mutex;
boost::fibers::condition_variable_any cv;
mutex.lock();
RIGHTNOW << "run_worker(" << threads << ", " << (void*)&barrier << ") locked mutex" << std::endl;
cv.wait(mutex);
RIGHTNOW << "run_worker(" << threads << ", " << (void*)&barrier << ") awaited CV" << std::endl;
mutex.unlock();
}
void start_engine(uint32_t threads) {
RIGHTNOW << "start_engine(" << threads << ") called" << std::endl;
if (threads < 1u) {
threads = 1;
}
boost::barrier barrier (threads + 1u);
auto scheduler ([threads, &barrier]() { run_worker(threads, barrier); });
for (auto i (threads); i; --i) {
std::thread(scheduler).detach();
}
barrier.wait();
RIGHTNOW << "start_engine(" << threads << ") awaited everything else" << std::endl;
}
int main() {
RIGHTNOW << "main() called" << std::endl;
start_engine(1);
boost::fibers::fiber([]() {
RIGHTNOW << "<anonymous> called" << std::endl;
_Exit(1);
}).detach();
RIGHTNOW << "main() waiting" << std::endl;
for (;;) {
}
}
clang++ -std=c++11 -I ~/homebrew/Cellar/boost/1.70.0/include -L ~/homebrew/Cellar/boost/1.70.0/lib -l boost_fiber-mt -l boost_context-mt -l boost_thread-mt -o fibers fibers.cpp
./fibers

is this a bug in the eigen matrix log() implementation?

This simple test program...
#include <iostream>
#include <Eigen/Dense>
#include <unsupported/Eigen/MatrixFunctions>
using namespace Eigen;
int main()
{
Matrix<double,1,1> m11;
Matrix<double,2,2> m22;
Matrix<double,3,3> m33;
Matrix<double,4,4> m44;
m22.setZero();
m33.setZero();
m44.setZero();
std::cout << "Eigen version: " << EIGEN_WORLD_VERSION << "."
<< EIGEN_MAJOR_VERSION << "." << EIGEN_MINOR_VERSION << "\n";
std::cout << "11: " << m11.log() << "\n";
std::cout << "22: " << m22.log() << "\n";
std::cout << "33: " << m33.log() << "\n";
std::cout << "44: " << m44.log() << "\n";
}
hangs apparently while calculating m33.log(), giving the output:
Eigen version: 3.3.5
11: -728.932
22: -nan -nan
-nan -nan
[hangs here at 100% cpu]
with
g++ --version
g++ (GCC) 7.3.1 20180712 (Red Hat 7.3.1-6)
and also with
clang++ --version
clang version 5.0.2 (tags/RELEASE_502/final)
so I know it's invalid, but maybe a failure would be better than a hang, or do I really always need to check isInvertible() && all the eigenvalues before calling log() ?

std::binary_search returns different result than std::find

Actually I couldn't see what's my mistake in my code but std::binary_search returns false for the element that have already added to vec_barcode. For comparison I tried std::find method & it works properly.
std::find(vec_barcode.begin(), vec_barcode.end(), "LOGUS") != vec_barcode.end() ? std::cout << "yes" << std::endl : std::cout << "no" << std::endl;
std::binary_search(vec_barcode.begin(), vec_barcode.end(), "LOGUS") ? std::cout << "yes" << std::endl : std::cout << "no" << std::endl;
Any help is appreciated.

Ruby Regex: efficient way of capturing and deleting simultaneously

I am deleting comments from a code file using regular expressions in ruby. The code is C++ (but i think this is not relevant) and the file contains something like:
/*
Hello! I'm a comment!
*/
int main(int argc, char* argv[])
{
Foo foo;
foo.bar();
return 0;
}
My goal is to remove the comments from the code and, at the same time, to parse them, which for now I can achieve by doing capture and then deleting:
text.scan(UGLY_COMMENTS_REGEX).each do |m|
m.method_for_printing_matched_comment
end
text = text.gsub(UGLY_COMMENTS_REGEX,'');
Another alternative that occurs to me is doing the gsub for each regex match instead of doing it with the full regex, something like:
text.scan(UGLY_COMMENTS_REGEX).each do |m|
m.method_for_printing_matched_comment
text = text.gsub(m,'');
end
The problem with this (also suboptimal) alternative is that it is not straightforward when the match contains "groups", e.g m[0], m[1]...
As doing this seems extremely inefficient I was wondering if there is any way of doing the match just once (for both capturing and deleting).
String#gsub! (and other String#gsub, String#sub!, String#sub) accepts an optional block (which will be called with a matched string). So you can do something like this:
text.gsub!(UGLY_COMMENTS_REGEX) { |m|
puts m # to print the matched comment / OR m.method_for_printing_matched_comment
'' # Return value is used as a replacement string; effectively remove the comment
}
I believe the following should work.
Code
def strip_comments(str)
comments = []
[str.split(/[ \t]*\/\*|\*\/(?:[ \t]*\n?/)
.select.with_index {|ar,i| i.even? ? true : (comments << ar.strip; false)}
.join,
comments]
end
Example
str =<<_
/*
Hello! I'm a comment!
*/
int main(int argc, char* argv[])
{
Foo foo;
/* Let's get this one too */
foo.bar();
return 0;
}
_
cleaned_code, comments = strip_comments(str)
puts cleaned_code
# int main(int argc, char* argv[])
# {
# Foo foo;
# foo.bar();
# return 0;
# }
puts comments
# Hello! I'm a comment!
# Let's get this one too
Explanation
For the example above.
comments = []
Splitting the string on /* or */ will create an array in which every other element is the text of a comment. The first element of the array will be text to retain, which will equal "" if the string begins with a comment. To retain correct formatting (I hope), I'm also stripping any spaces or tabs (but not newlines) that precede /* and any tabs or spaces followed by a newline, following */.
b = str.split(/[ \t]*\/\*|\*\/(?:[ \t]*\n)?/)
#=> ["",
# "\n Hello! I'm a comment!\n",
# "\nint main(int argc, char* argv[])\n{\n Foo foo;\n",
# " Let's get this one too ",
# " foo.bar();\n return 0;\n}\n"]
We wish to select the elements that are not comments, and at the same time keep the latter:
enum0 = b.select
#=> #<Enumerator: [
# "",
# "\n Hello! I'm a comment!\n",
# "\nint main(int argc, char* argv[])\n{\n Foo foo;\n",
# " Let's get this one too ",
# " foo.bar();\n return 0;\n}\n"]:select>
Add the index so we'll be able to figure out which elements are comments:
enum1 = enum0.with_index
#=> #<Enumerator: #<Enumerator: [
# "",
# "\n Hello! I'm a comment!\n",
# "\nint main(int argc, char* argv[])\n{\n Foo foo;\n",
# " Let's get this one too ",
# " foo.bar();\n return 0;\n}\n"]:select>:with_index>
You might think of enum1 as a "compound enumerator". To see what elements it will pass into its block, convert it to an array:
enum1.to_a
#=> [["", 0],
# ["\n Hello! I'm a comment!\n", 1],
# ["\nint main(int argc, char* argv[])\n{\n Foo foo;\n", 2],
# [" Let's get this one too ", 3],
# [" foo.bar();\n return 0;\n}\n", 4]]
Execute the enumerator with its block using Array#each:
c = enum1.each {|ar,i| i.even? ? true : (comments << ar.strip; false)}
#=> ["",
# "\nint main(int argc, char* argv[])\n{\n Foo foo;\n",
# " foo.bar();\n return 0;\n}\n"]
Confirm comments was constructed correctly:
puts comments
# Hello! I'm a comment!
# Let's get this one too
Join the elements of c:
cleaned_text = c.join
#=> "\nint main(int argc, char* argv[])\n{\n Foo foo;\n foo.bar();\n return 0;\n}\n"
and return:
[cleaned_text, comments]
as shown above.
Edit: a little better, I think:
def strip_comments(str)
a = str.split(/[ \t]*\/\*|\*\/(?:[ \t]*\n)?/)
a << "" if a.size.odd?
cleaned, comments = a.each_pair.transpose
[cleaned.join, comments.map(&:strip)]
end

c++11 type_traits: different result in INTEL 2013 and GCC 4.7.2

For the following class, INTEL 2013 (update 3) and GCC 4.7.2 give different type_traits results. Which one is right?
#include <iostream>
#include <type_traits>
using namespace std;
class A
{
public:
A() = default;
private:
double t_;
};
int main()
{
cout << boolalpha;
cout << "is_trivial<A> : " << is_trivial<A>::value << endl;
cout << "is_compound<A> : " << is_compound<A>::value << endl;
cout << "is_pod<A> : " << is_pod<A>::value << endl;
cout << "is_standard_layout<A> : " << is_standard_layout<A>::value << endl;
cout << "is_literal_type<A> : " << is_literal_type<A>::value << endl;
return 0;
}
INTEL output:
is_trivial<A> : true
is_compound<A> : true
is_pod<A> : false
is_standard_layout<A> : true
is_literal_type<A> : false
GCC output:
is_trivial<A> : true
is_compound<A> : true
is_pod<A> : true
is_standard_layout<A> : true
is_literal_type<A> : true
I would say GCC is correct. is_pod is true if it's both is_trivial and is_standard_layout: http://en.cppreference.com/w/cpp/types/is_pod . Intel compiler doesn't comply with this. is_literal_type should also be true since all the conditions seem valid for A: http://en.cppreference.com/w/cpp/types/is_literal_type

Resources