How to keep all properties of graph read by boost::read_graphviz? - graphviz

Suppose you want to read in a .dot graph into boost where there could be properties you do not recognize. It is easy to ignore them (by passing ignore_other_properties to the dynamic_properties constructor) but what if you wanted all the properties added to dynamic_properties instead?
The below code demonstrates the problem. The handle_custom_properties is a copy of ignore_other_properties and the code will compile / run, reporting "3 vertices, 2 edges." What needs to be added to handle_custom_properties so that, on return, dp will contain a property "label" and node A will have value "x" for the label property?
#include <iostream>
#include <string>
#include <boost/graph/graphviz.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/exception/exception.hpp>
#include <boost/exception/diagnostic_information.hpp>
struct vertex_p {
std::string node_id;
};
typedef boost::adjacency_list < boost::vecS, boost::vecS, boost::undirectedS, vertex_p> graph_t;
boost::shared_ptr<boost::dynamic_property_map>
handle_custom_properties(const std::string& s,
const boost::any& k,
const boost::any& v) {
// What goes in here to add dynamic property map for property "s" which key-value pair <k,v>?
// What ignore_other_properties does
return boost::shared_ptr<boost::dynamic_property_map>();
}
int main() {
std::string str(R"(graph {
A [ label="x" ]
B
C
A -- B
A -- C
}
)");
try {
graph_t g;
boost::dynamic_properties dp{handle_custom_properties};
dp.property("node_id", get(&vertex_p::node_id, g));
if (boost::read_graphviz(str, g, dp)) {
std::cout << "read_graphviz returned success" << std::endl;
std::cout << "graph stats:" << std::endl;
std::cout << " " << g.m_vertices.size() << " vertices" << std::endl;
std::cout << " " << g.m_edges.size() << " edges" << std::endl;
}
else {
std::cout << "read_graphviz returned failure" << std::endl;
}
}
catch (std::exception& e) {
std::cerr << e.what() << std::endl;
}
catch (boost::exception& e) {
std::cerr << boost::diagnostic_information(e) << std::endl;
}
}

I was not able to find an existing class to solve this but implementing a dynamic_property_map in terms of a std::map worked:
template<typename TKey, typename TValue>
class dynamic_property_map_impl : public boost::dynamic_property_map {
std::map<TKey, TValue> map_;
public:
boost::any get(const boost::any& key) override { return map_[boost::any_cast<TKey>(key)]; }
std::string get_string(const boost::any& key) override { std::ostringstream s; s << map_[boost::any_cast<TKey>(key)]; return s.str(); }
void put(const boost::any& key, const boost::any& value) override { map_[boost::any_cast<TKey>(key)] = boost::any_cast<TValue>(value); }
const std::type_info& key() const override { return typeid(TKey); }
const std::type_info& value() const override { return typeid(TValue); }
};
boost::shared_ptr<boost::dynamic_property_map>
handle_custom_properties(const std::string&,
const boost::any&,
const boost::any&) {
return boost::make_shared<dynamic_property_map_impl<unsigned, std::string>>();
}
Changing the graph and printing out the properties shows all the property maps were added:
std::string str(R"(graph {
A [ label="x", stuff="y" ]
B
C [ happy="yes" ]
A -- B
A -- C
}
)");
...
std::cout << "properties:" << std::endl;
for (const auto& p : dp) {
std::cout << " " << p.first << std::endl;
}
Outputs
read_graphviz returned success
graph stats:
3 vertices
2 edges
properties:
happy
label
node_id
stuff

Related

Begin was not declared in the scope for Generic Array Template Class

#include <iostream>
#include <string>
template <typename T, int N>
class Array {
int size{N};
T values{N};
friend std::ostream &operator<<(std::ostream &os, const Array<T, N> &arr) {
os << "[";
for (const auto &val: arr.values)
os << val << " ";
os << "]" << std::endl;
return os;
}
public:
Array() = default;
Array(T value_added) {
for(auto &value: values)
value = value_added;
}
void fill(T data_value) {
for (auto &value: values)
value = data_value;
}
int get_size() const {
return size;
}
T &operator[](int index) {
return values[index];
}
};
int main () {
Array<int,2> nums;
std::cout << "The size of nums is: " << nums.get_size() << std::endl;
std::cout << nums << std::endl;
}
I am trying to create a generic array template class but I get the error Begin was not declared in the scope and it says it is due to the for (const auto &val: arr.values) loop.

How to make recursive Spirit X3 parser with a separate visitor class

A parser application where I’m working on calls for recursive rules. Besides looking into the Recursive AST tutorial examples of Boost Spirit X3 which can be found here:
https://www.boost.org/doc/libs/develop/libs/spirit/doc/x3/html/index.html, I was looking for a solution with a std::variant of some types as well as a std::vector of that same
variant type.
In the StackOverflow post titled: Recursive rule in Spirit.X3, I found the code from the answer from sehe a decent starting point for my parser.
I have repeated the code here but I have limited the input strings to be tested. Because the full list from the original is not relevant for this question here.
//#define BOOST_SPIRIT_X3_DEBUG
#include <iostream>
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/home/x3.hpp>
#include <string>
#include <vector>
#include <variant>
struct value: std::variant<int,float,std::vector<value>>
{
using base_type = std::variant<int,float,std::vector<value>>;
using base_type::variant;
friend std::ostream& operator<<(std::ostream& os, base_type const& v) {
struct {
std::ostream& operator()(float const& f) const { return _os << "float:" << f; }
std::ostream& operator()(int const& i) const { return _os << "int:" << i; }
std::ostream& operator()(std::vector<value> const& v) const {
_os << "tuple: [";
for (auto& el : v) _os << el << ",";
return _os << ']';
}
std::ostream& _os;
} vis { os };
return std::visit(vis, v);
}
};
namespace parser {
namespace x3 = boost::spirit::x3;
x3::rule<struct value_class, value> const value_ = "value";
x3::rule<struct o_tuple_class, std::vector<value> > o_tuple_ = "tuple";
x3::real_parser<float, x3::strict_real_policies<float> > float_;
const auto o_tuple__def = "tuple" >> x3::lit(':') >> ("[" >> value_ % "," >> "]");
const auto value__def
= "float" >> (':' >> float_)
| "int" >> (':' >> x3::int_)
| o_tuple_
;
BOOST_SPIRIT_DEFINE(value_, o_tuple_)
const auto entry_point = x3::skip(x3::space) [ value_ ];
}
int main()
{
for (std::string const str : {
"float: 3.14",
"int: 3",
"tuple: [float: 3.14,int: 3]",
"tuple: [float: 3.14,int: 3,tuple: [float: 4.14,int: 4]]"
}) {
std::cout << "============ '" << str << "'\n";
//using boost::spirit::x3::parse;
auto first = str.begin(), last = str.end();
value val;
if (parse(first, last, parser::entry_point, val))
std::cout << "Parsed '" << val << "'\n";
else
std::cout << "Parse failed\n";
if (first != last)
std::cout << "Remaining input: '" << std::string(first, last) << "'\n";
}
}
However I would like to use a traditional visitor class rather than making ostream a friend in the variant class. You know just a struct/class with a bunch of function objects for each type you encounter in the variant and a "for loop" for the vector that calls std::visit for each
element.
My goal for the traditional visitor class is to be able to maintain a state machine during printing.
My own attempts to write this visitor class did fail because I ran into an issue with my GCC 8.1 compiler. With GCC during compilation std::variant happens to be std::variant_size somehow and I got the following error:
error: incomplete type 'std::variant_size' used in nested name specifier
More about this here:
Using std::visit on a class inheriting from std::variant - libstdc++ vs libc++
Is it possible giving this constraint on GCC to write a visitor class for the code example I included, so that the ostream stuff can be removed?
Is it possible giving this constraint on GCC to write a visitor class for the code example I included, so that the ostream stuff can be removed?
Sure. Basically, I see three approaches:
1. Add the template machinery
You can specialize the implementation details accidentally required by GCC:
struct value: std::variant<int,float,std::vector<value>> {
using base_type = std::variant<int,float,std::vector<value>>;
using base_type::variant;
};
namespace std {
template <> struct variant_size<value> :
std::variant_size<value::base_type> {};
template <size_t I> struct variant_alternative<I, value> :
std::variant_alternative<I, value::base_type> {};
}
See it live on Wandbox (GCC 8.1)
2. Don't (again live)
Extending the std namespace is fraught (though I think it's legal for
user-defined types). So, you can employ my favorite pattern and hide th
estd::visit dispatch in the function object itself:
template <typename... El>
void operator()(std::variant<El...> const& v) const { std::visit(*this, v); }
Now you can simply call the functor and it will automatically dispatch
on your own variant-derived type because that operator() overload does
NOT have the problems that GCC stdlib has:
if (parse(first, last, parser::entry_point, val))
{
display_visitor display { std::cout };
std::cout << "Parsed '";
display(val);
std::cout << "'\n";
}
3. Make things explicit
I like this the least, but it does have merit: there's no magic and no
tricks:
struct value: std::variant<int,float,std::vector<value>> {
using base_type = std::variant<int,float,std::vector<value>>;
using base_type::variant;
base_type const& as_variant() const { return *this; }
base_type& as_variant() { return *this; }
};
struct display_visitor {
void operator()(value const& v) const { std::visit(*this, v.as_variant()); }
// ...
Again, live
SUMMARY
After thinking a bit more, I'd recommend the last approach, due to the relative simplicity. Clever is often a code-smell :)
Full listing for future visitors:
//#define BOOST_SPIRIT_X3_DEBUG
#include <iostream>
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/home/x3.hpp>
#include <string>
#include <vector>
#include <variant>
struct value: std::variant<int,float,std::vector<value>> {
using base_type = std::variant<int,float,std::vector<value>>;
using base_type::variant;
base_type const& as_variant() const { return *this; }
base_type& as_variant() { return *this; }
};
struct display_visitor {
std::ostream& _os;
void operator()(value const& v) const { std::visit(*this, v.as_variant()); }
void operator()(float const& f) const { _os << "float:" << f; }
void operator()(int const& i) const { _os << "int:" << i; }
void operator()(std::vector<value> const& v) const {
_os << "tuple: [";
for (auto& el : v) {
operator()(el);
_os << ",";
}
_os << ']';
}
};
namespace parser {
namespace x3 = boost::spirit::x3;
x3::rule<struct value_class, value> const value_ = "value";
x3::rule<struct o_tuple_class, std::vector<value> > o_tuple_ = "tuple";
x3::real_parser<float, x3::strict_real_policies<float> > float_;
const auto o_tuple__def = "tuple" >> x3::lit(':') >> ("[" >> value_ % "," >> "]");
const auto value__def
= "float" >> (':' >> float_)
| "int" >> (':' >> x3::int_)
| o_tuple_
;
BOOST_SPIRIT_DEFINE(value_, o_tuple_)
const auto entry_point = x3::skip(x3::space) [ value_ ];
}
int main()
{
for (std::string const str : {
"float: 3.14",
"int: 3",
"tuple: [float: 3.14,int: 3]",
"tuple: [float: 3.14,int: 3,tuple: [float: 4.14,int: 4]]"
}) {
std::cout << "============ '" << str << "'\n";
//using boost::spirit::x3::parse;
auto first = str.begin(), last = str.end();
value val;
if (parse(first, last, parser::entry_point, val))
{
display_visitor display { std::cout };
std::cout << "Parsed '";
display(val);
std::cout << "'\n";
}
else
std::cout << "Parse failed\n";
if (first != last)
std::cout << "Remaining input: '" << std::string(first, last) << "'\n";
}
}

push_back() binary tree into vector

I'm trying to put all the elements from a binary search tree into a vector, in order. Here is the function:
edit: adding instructions for clarity.
Write a class for implementing a simple binary search tree capable of storing numbers. The class should have member functions:
void insert(double x)
bool search(double x)
void inorder(vector <double> & v)
The insert function should not use recursion directly or indirectly by calling a recursive function. The search function should work by calling a private recursive member function
bool search(double x, <double> & v )
The inorder function is passed an initially empty vector v; if fills v with the inorder list of numbers stored in the binary search tree. Demonstrate the operation of the class using a suitable driver program.
EDIT: Added full code for clarity.
#include "stdafx.h"
#include <iostream>
#include <vector>
class BinaryTree {
private:
struct TreeNode {
double value;
TreeNode *left;
TreeNode *right;
TreeNode(double value1,
TreeNode *left1 = nullptr,
TreeNode *right1 = nullptr) {
value = value1;
left = left1;
right = right1;
}
};
TreeNode *root; //pointer to the root of the tree
bool search(double x, TreeNode *t) {
while (t) {
std::cout << "running through t." << std::endl;
if (t->value == x) {
return true;
}
else if (x < t->value) {
std::cout << "wasn't found, moving left." << std::endl;
search(x, t->left);
}
else {
std::cout << "wasn't found, moving right." << std::endl;
search(x, t->right);
}
}
std::cout << "wasn't found." << std::endl;
return false;
}
public:
std::vector<TreeNode> v;
BinaryTree() {
root = nullptr;
}
void insert(double x) {
TreeNode *tree = root;
if (!tree) {
std::cout << "Creating tree." << x << std::endl;
root = new TreeNode(x);
return;
}
while (tree) {
std::cout << "Adding next value." << std::endl;
if (tree->value == x) return;
if (x < tree->value) {
tree = tree->left;
tree->value = x;
}
else {
tree = tree->right;
tree->value = x;
}
}
}
bool search(double x) {
return search(x, root);
}
void inOrder(std::vector <double> & v) {
{
if (left)
left->inOrder(v);
v.push_back(value);
if (right)
right->inOrder(v);
}
}
TreeNode* left = nullptr;
TreeNode* right = nullptr;
double value;
};
int main() {
BinaryTree t;
std::cout << "Inserting the numbers 5, 8, 3, 12, and 9." << std::endl;
t.insert(5);
t.insert(8);
t.insert(3);
t.insert(12);
t.insert(9);
std::cout << "Looking for 12 in tree." << std::endl;
if (t.search(12)) {
std::cout << "12 was found." << std::endl;
}
std::cout << "Here are the numbers in order." << std::endl;
return 0;
}
I'm unable to get the values to push into the vector. Any ideas as to how I can accomplish this?
You would normally do this recursively:
#include <vector>
class TreeNode {
void inOrder(std::vector<double>& v) const
{
if (left)
left->inOrder(v);
v.push_back(value);
if (right)
right->inOrder(v);
}
TreeNode* left = nullptr;
TreeNode* right = nullptr;
double value;
};
Edit: added #include <vector>
Edit2: That is how I would do it. Feel free to ask any questions:
#include <iostream>
#include <vector>
class BinaryTree {
private:
struct TreeNode {
double value;
TreeNode *left = nullptr;
TreeNode *right = nullptr;
TreeNode(double value1)
: value(value1)
{}
void inOrder(std::vector <double> & v) {
if (left)
left->inOrder(v);
v.push_back(value);
if (right)
right->inOrder(v);
}
};
TreeNode *root = nullptr; //pointer to the root of the tree
bool search(double x, TreeNode *t) {
while (t) {
std::cout << "running through t." << std::endl;
if (t->value == x) {
return true;
}
else if (x < t->value) {
std::cout << "wasn't found, moving left." << std::endl;
return search(x, t->left);
}
else {
std::cout << "wasn't found, moving right." << std::endl;
return search(x, t->right);
}
}
std::cout << "wasn't found." << std::endl;
return false;
}
public:
BinaryTree() {}
void insert(double x) {
TreeNode *tree = root;
if (!tree) {
std::cout << "Creating tree." << x << std::endl;
root = new TreeNode(x);
return;
}
while (tree) {
std::cout << "Adding next value." << std::endl;
if (tree->value == x) return;
if (x < tree->value) {
if (!tree->left)
{
tree->left = new TreeNode(x);
return;
}
tree = tree->left;
}
else {
if (!tree->right)
{
tree->right = new TreeNode(x);
return;
}
tree = tree->right;
}
}
}
bool search(double x) {
return search(x, root);
}
void inOrder(std::vector<double>& v)
{
root->inOrder(v);
}
};
int main() {
BinaryTree t;
std::cout << "Inserting the numbers 5, 8, 3, 12, and 9." << std::endl;
t.insert(5);
t.insert(8);
t.insert(3);
t.insert(12);
t.insert(9);
std::cout << "Looking for 12 in tree." << std::endl;
if (t.search(12)) {
std::cout << "12 was found." << std::endl;
}
std::cout << "Here are the numbers in order." << std::endl;
std::vector<double> v;
t.inOrder(v);
std::cout << "values in order:";
for (double val : v)
{
std::cout << " " << val;
}
std::cout << std::endl;
return 0;
}

How to get error object? when use member function in deadline_timer

I use boost::asio::deadline_timer using a member function as a handler (callback function).
If I cancel a timer, how to get error object in print() member function?
class printer
{
public:
printer(boost::asio::io_service& io)
: timer_(io, boost::posix_time::seconds(1)),
count_(0)
{
timer_.async_wait(boost::bind(&printer::print, this));
}
~printer()
{
std::cout << "Final count is " << count_ << "\n";
}
void print()
{
if (count_ < 5)
{
std::cout << count_ << "\n";
++count_;
timer_.expires_at(timer_.expires_at() + boost::posix_time::seconds(1));
timer_.async_wait(boost::bind(&printer::print, this));
}
}
private:
boost::asio::deadline_timer timer_;
int count_;
};
int main()
{
boost::asio::io_service io;
printer p(io);
io.run();
return 0;
}
I try to set error object using bind in async_wait(), but it's compile error
timer_.async_wait(boost::bind(&printer::print, this, boost::asio::placeholders::error));
As long as your method signature matches, it should be no problem:
void print(boost::system::error_code const ec)
// and
boost::bind(&printer::print, this, boost::asio::placeholders::error)
See it Live On Coliru:
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <iostream>
class printer
{
public:
printer(boost::asio::io_service& io)
: timer_(io, boost::posix_time::seconds(1)),
count_(0)
{
timer_.async_wait(boost::bind(&printer::print, this, boost::asio::placeholders::error));
}
~printer()
{
std::cout << "Final count is " << count_ << "\n";
}
void print(boost::system::error_code const ec)
{
if (ec)
std::cout << "Error: " << ec.message() << "\n";
if (count_ < 5)
{
std::cout << count_ << "\n";
++count_;
timer_.expires_at(timer_.expires_at() + boost::posix_time::seconds(1));
timer_.async_wait(boost::bind(&printer::print, this, boost::asio::placeholders::error));
}
}
private:
boost::asio::deadline_timer timer_;
int count_;
};
int main()
{
boost::asio::io_service io;
printer p(io);
io.run();
}

Error: Identifier "PrintGuessesRemaining" , "PrintWordSpaceDelinated" , "PrintWordsRemainingIsUndefined"

I have Created a Print Class where I have created all of those functions.
When I attempt to call these functions, I get the Identifier Error. I am sure I have incorrectly set up my class. Please Help construct Print Class
Code attached:
// Print.cpp - Print Class implementation
// Written by Varun Patel
#include "Print.h"
Print::Print()
{
}
Print::Print(const string& word)
{
Word = word;
}
void Print::PrintWordsRemaining(set<string>& possibleWords_, bool displayNumberOfWordsRemaining_)
{
if(displayNumberOfWordsRemaining_)
{
cout << "There are " << possibleWords_.size() << " possible words left." << endl;
}
else
{
//Do nothing
}
}
void Print::PrintWordSpaceDelinated(string word_)
{
for (size_t i = 0; i < word_.size(); i++)
{
cout << word_[i] << " ";
}
cout << endl;
}
void Print::PrintGuessesRemaining(int guessesRemaining_)
{
cout << "You have " << guessesRemaining_ << " guesses remaining." << endl;
}
Here is how i try to call one of the functions:
#include "UpdateGuessesRemaining.h"
void UpdateGuessesRemaining(set<string>& newPossibleWords, int& guessesRemaining,
char guessChar, string& guessedWord)
{
set<string>::iterator wordPtr = newPossibleWords.begin();
if (wordPtr->find(guessChar) == -1)
{
cout << "Sorry, incorrect guess. ";
PrintGuessesRemaining(--guessesRemaining);
}
else
{
cout << "Correct! The word contains " << guessChar << "." << endl;
}
}
Here is my header File:
// Print.h - Print Class declaration
// Written by Varun Patel
#pragma once
#include <iostream>
#include <set>
#include <string>
#include "PromptForGuessesRemaining.h"
using namespace std;
class Print
{
public:
// Default constructor
Print();
Print(const string& word);
void PrintWordsRemaining(set<string>& possibleWords, bool displayNumberOfWordsRemaining);
void PrintWordSpaceDelinated(string word);
void PrintGuessesRemaining(int guessesRemaining);
private:
string Word;
};
Thanks For Your Help,
Varun

Resources