Boost:Spirit:Karma: How to get current position of output? - c++

I want to generate some formatted output. For this some indention is needed. So at some point during generation I would like to get the current position, to have the following lines indented with that amount.
Here is a minimal example. Please assume, that we don't know how long the output of karma::lit("Some text: ") is during compile time. In fact, this leading text may be generated by several rules.
#include <iostream>
#include <iterator>
#include <string>
#include <vector>
#include <boost/spirit/include/karma.hpp>
using namespace std;
int main() {
vector<int> v { 0, 1, 2, 3 };
{
namespace karma = boost::spirit::karma;
karma::rule<ostream_iterator<char>, std::vector<int>() > myRule =
karma::lit("Some text: ") << (karma::int_ % karma::eol);
karma::generate(ostream_iterator<char>(cout), myRule, v);
}
return 0;
}
This produces
Some text: 0
1
2
3
I would like the result:
Some text: 0
1
2
3
To achieve this, one needs to know the current position, right before the vector gets generated. So, something like an equivalent for qi::raw[]?
Update: A pointer to the up to this point generated output, would also do.

I believe this approach is similar to the one you described in the comments. It assumes that the only information you can get from the iterator is the total count of characters written. It could be simplified further if you had access to the current column by modifying the header files as mentioned in the other answer.
Edit: Modified the code with the approach Mike M suggested in the comments. Now it has a better interface. Tested with g++ 4.8.1 and clang 3.2 using boost 1.54.0.
In order to use you need to first define two terminals of type position_getter:
std::size_t start=0, end=0;
position_getter start_(start), end_(end);
Then you simply put start_ at the start of a line, and end_ at the point where you want to know in which column you are. After that you can use end - start to calculate that column. Since this calculation needs to be done at parse time (not compile time) you need to use phx::ref(end) - phx::ref(start).
With the modifications mentioned in the other answer, you could simply define one terminal:
std::size_t column=0;
position_getter column_(column);
And then use it in rule like this:
myRule = karma::lit("Some text: ")
<< column_
<< karma::int_ %
(karma::eol << karma::repeat(phx::ref(column))[karma::char_(" ")]);
#include <iostream>
#include <string>
#include <vector>
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/phoenix.hpp>
//START OF CURRENT_POS.HPP
#include <boost/spirit/include/karma_generate.hpp>
///////////////////////////////////////////////////////////////////////////////
// definition the place holder
namespace custom_generator {
BOOST_SPIRIT_TERMINAL_EX(current_pos);
struct position_getter: boost::spirit::terminal<
boost::spirit::tag::stateful_tag<std::size_t&, tag::current_pos> > {
typedef boost::spirit::tag::stateful_tag<std::size_t&, tag::current_pos> tag_type;
position_getter(std::size_t& p)
: boost::spirit::terminal<tag_type>(p) {
}
};
}
///////////////////////////////////////////////////////////////////////////////
// implementation the enabler
namespace boost {
namespace spirit {
// enables a terminal of type position_getter
template<>
struct use_terminal<karma::domain,
tag::stateful_tag<std::size_t&, custom_generator::tag::current_pos> > : mpl::true_ {
};
}
}
///////////////////////////////////////////////////////////////////////////////
// implementation of the generator
namespace custom_generator {
struct current_pos_generator: boost::spirit::karma::primitive_generator<
current_pos_generator> {
current_pos_generator(std::size_t& pos_)
: pos(pos_) {
}
// Define required output iterator properties
typedef typename boost::mpl::int_<
boost::spirit::karma::generator_properties::tracking> properties;
// Define the attribute type exposed by this parser component
template<typename Context, typename Unused>
struct attribute {
typedef boost::spirit::unused_type type;
};
// This function is called during the actual output generation process.
// It stores information about the position in the output stream in
// the variable you used to construct position_getter
template<typename OutputIterator, typename Context, typename Delimiter,
typename Attribute>
bool generate(OutputIterator& sink, Context& ctx,
Delimiter const& delimiter, Attribute const& attr) const {
std::size_t column = sink.get_out_count();
// This would only work if you comment "private:" in line 82 of
// boost/spirit/home/karma/detail/output_iterator.hpp
// std::size_t column = sink.track_position_data.get_column()-1;
pos = column;
return true;
}
// This function is called during error handling to create
// a human readable string for the error context.
template<typename Context>
boost::spirit::info what(Context& ctx) const {
return boost::spirit::info("current_pos");
}
std::size_t& pos;
};
}
///////////////////////////////////////////////////////////////////////////////
// instantiation of the generator
namespace boost {
namespace spirit {
namespace karma {
template<typename Modifiers>
struct make_primitive<
tag::stateful_tag<std::size_t&, custom_generator::tag::current_pos>,
Modifiers> {
typedef custom_generator::current_pos_generator result_type;
template<typename Terminal>
result_type operator()(Terminal& term, unused_type) const {
typedef tag::stateful_tag<std::size_t&,
custom_generator::tag::current_pos> tag_type;
using spirit::detail::get_stateful_data;
return result_type(get_stateful_data<tag_type>::call(term));
}
};
}
}
}
//END OF CURRENT_POS.HPP
int main() {
std::vector<int> v { 0, 1, 2, 3 };
{
namespace karma = boost::spirit::karma;
namespace phx = boost::phoenix;
using custom_generator::position_getter;
std::size_t start = 0, end = 0;
position_getter start_(start), end_(end);
karma::rule<std::ostream_iterator<char>, std::vector<int>()> myRule =
start_
<< karma::lit("Some text: ")
<< end_
<< karma::int_ % (karma::eol
<< karma::repeat(phx::ref(end) - phx::ref(start))[karma::char_(
" ")]);
karma::generate(std::ostream_iterator<char>(std::cout), myRule, v);
std::cout << std::endl;
karma::rule<std::ostream_iterator<char>, std::vector<int>()> myRuleThatAlsoWorks =
karma::lit(":)")
<< karma::eol
<< start_
<< karma::lit("Some text: ")
<< end_
<< karma::int_ % (karma::eol
<< karma::repeat(phx::ref(end) - phx::ref(start))[karma::char_(
" ")]);
karma::generate(std::ostream_iterator<char>(std::cout), myRuleThatAlsoWorks,
v);
}
return 0;
}

Here is a custom directive heavily based on the explanations here.
Unfortunately due to the fact that the information you need is contained in a private member of the iterator, this only works with the really simple example that you posted. If you output anything else before everythings gets misaligned. You can work around this if you are willing to modify slightly the code in detail/output_iterator.hpp. You can either comment the "private:" in position_policy or simply add a member function get_out_column in the same vein as get_out_count.
In order to use it you need to change your:
karma::int_ % karma::eol;
to:
custom_generator::align_list_to_current_position[karma::int_];
As you can see the custom directive requires a lot of boilerplate but big part of this code is common to every directive. In fact, besides changing the names, I have only needed to change three things:
Make sure that tracking is in the set of required properties:
typedef typename boost::mpl::int_<
Subject::properties::value | karma::generator_properties::tracking
> properties;
Make the attribute of the directive be the same as the one a list(%) would have(by looking here):
template <typename Context, typename Iterator>
struct attribute
: boost::spirit::traits::build_std_vector<
typename boost::spirit::traits::attribute_of<Subject, Context, Iterator>::type
>
{};
And finally change the generate function. In this function I simply build a list that has as its left member whatever you passed to the directive and as its right one the concatenation of karma::eol and as many spaces are as needed to be aligned.
#include <iostream>
#include <string>
#include <vector>
#include <boost/spirit/include/karma.hpp>
//START OF ALIGN_LIST_TO_CURRENT_POSITION.HPP
#include <boost/spirit/include/karma_generate.hpp>
///////////////////////////////////////////////////////////////////////////////
// definition the place holder
namespace custom_generator
{
BOOST_SPIRIT_TERMINAL(align_list_to_current_position);
}
///////////////////////////////////////////////////////////////////////////////
// implementation the enabler
namespace boost { namespace spirit
{
// We want custom_generator::align_list_to_current_position to be usable as a directive only,
// and only for generator expressions (karma::domain).
template <>
struct use_directive<karma::domain, custom_generator::tag::align_list_to_current_position>
: mpl::true_ {};
}}
///////////////////////////////////////////////////////////////////////////////
// implementation of the generator
namespace custom_generator
{
// That's the actual columns generator
template <typename Subject>
struct align_list_to_current_position_generator
: boost::spirit::karma::unary_generator<
align_list_to_current_position_generator<Subject> >
{
// Define required output iterator properties: take the properties needed by the subject and add tracking
typedef typename boost::mpl::int_<Subject::properties::value | boost::spirit::karma::generator_properties::tracking> properties;
// Define the attribute type exposed by this parser component
template <typename Context, typename Iterator>
struct attribute
: boost::spirit::traits::build_std_vector<
typename boost::spirit::traits::attribute_of<Subject, Context, Iterator>::type>
{};
align_list_to_current_position_generator(Subject const& s)
: subject(s)
{}
// This function is called during the actual output generation process.
// It dispatches to the embedded generator while supplying a new
// delimiter to use
template <typename OutputIterator, typename Context
, typename Delimiter, typename Attribute>
bool generate(OutputIterator& sink, Context& ctx
, Delimiter const& delimiter, Attribute const& attr) const
{
using boost::spirit::karma::repeat;
using boost::spirit::karma::char_;
using boost::spirit::karma::eol;
using boost::spirit::karma::domain;
std::size_t column = sink.get_out_count();
//This would only work if you comment "private:" in line 82 of boost/spirit/home/karma/detail/output_iterator.hpp
// std::size_t column = sink.track_position_data.get_column()-1;
return boost::spirit::compile<domain>(subject%(eol << repeat(column)[char_(" ")])).generate(sink, ctx, delimiter, attr);
}
// This function is called during error handling to create
// a human readable string for the error context.
template <typename Context>
boost::spirit::info what(Context& ctx) const
{
return boost::spirit::info("align_list_to_current_position", subject.what(ctx));
}
Subject subject;
};
}
///////////////////////////////////////////////////////////////////////////////
// instantiation of the generator
namespace boost { namespace spirit { namespace karma
{
// This is the factory function object invoked in order to create
// an instance of our align_list_to_current_position_generator.
template <typename Subject, typename Modifiers>
struct make_directive<custom_generator::tag::align_list_to_current_position, Subject, Modifiers>
{
typedef custom_generator::align_list_to_current_position_generator<Subject> result_type;
result_type operator()(unused_type, Subject const& s, unused_type) const
{
return result_type(s);
}
};
}}}
//END OF ALIGN_LIST_TO_CURRENT_POSITION.HPP
int main() {
std::vector<int> v { 0, 1, 2, 3 };
{
namespace karma = boost::spirit::karma;
using custom_generator::align_list_to_current_position;
karma::rule<std::ostream_iterator<char>, std::vector<int>() > myRule =
karma::lit("Some text: ") << align_list_to_current_position[karma::int_];
karma::generate(std::ostream_iterator<char>(std::cout), myRule, v);
std::cout << std::endl;
//This rule would work if you make the changes mentioned in align_list_to_current_position_generator::generate
karma::rule<std::ostream_iterator<char>, std::vector<int>() > myRuleThatFails =
karma::lit(":_(") << karma::eol << karma::lit("Some text: ") << align_list_to_current_position[karma::int_ << karma::int_];
karma::generate(std::ostream_iterator<char>(std::cout), myRuleThatFails, v);
}
return 0;
}

Related

C++ if (false) condition evaluated?

I'm learning about template in C++, and my set of C++ terminology is somewhat limited, so I couldn't google this problem.I'm trying to implement a custom dict type based on std::unordered_map. My goal is to be able to instantiate the class dict in ways like the following:
dict<std::string, long> d; // OR
dict<std::string, std::set<std::string>> d; // OR
dict<std::string, std::map<char, float>> d; // OR
dict<std::string, std::vector<std::string>> d; // OR
dict<std::string, std::vector<double>> d;
So here's the code, I'm using:
utils.h
#include <fstream>
#include <unordered_map>
#include <set>
#include <vector>
#include <algorithm>
#include <type_traits>
// for bravity
using namespace std;
// to check for stl vector
// slightly modified version of: https://stackoverflow.com/a/31105859
namespace is_container {
template <typename T> struct stl_vector : false_type{};
template <typename T> struct stl_vector<std::vector<T>> : true_type{};
}
namespace StringOps {
// generaic function to split based on many delimiters:
// source: https://stackoverflow.com/a/9676623
vector<string> split(const string& str, const string& delimiters = " ,") {
vector<string> v;
unsigned start = 0;
auto pos = str.find_first_of(delimiters, start);
while(pos != string::npos) {
if(pos != start) // ignore empty tokens
v.emplace_back(str, start, pos - start);
start = pos + 1;
pos = str.find_first_of(delimiters, start);
}
if(start < str.length()) // ignore trailing delimiter
v.emplace_back(str, start, str.length() - start); // add what's left of the string
return v;
}
}
template<class Key, template <class...> class Value, typename T, class = void>
class dict {
public:
Value<T> t;
};
template<class Key, template <class...> class Value, typename T> // detect container types with ::iterator
class dict<Key, Value, T, void_t<typename Value<T>::iterator>> : true_type {
private:
unordered_map<Key, Value<T>> content;
bool is_vector = false;
string line;
unordered_map<Key, Value<T>> load(ifstream& file) {
while (getline(file, line)) {
if (!line.empty()) {
// remove trailling \n if exists
if (line[line.length()-1] == '\n')
line.erase(line.length() - 1);
vector<string> tokens = StringOps::split(line);
Value<T> result;
(tokens[i]));
if (is_vector) {
for (unsigned i = 1; i < tokens.size(); i++) {
result.emplace_back(static_cast<T>(tokens[i]));
}
}
if(false) { // should never be looked into
auto it = result.cend();
for (unsigned i = 1; i < tokens.size(); i++) {
result.emplace_hint(it, static_cast<T>(tokens[i]));
}
}
content[static_cast<Key>(tokens[0])] = result;
}
}
return content;
}
public:
constexpr Value<T>& operator[](Key k) {
return content[k];
}
dict(const string& path) {
// detect vector type
if(is_container::stl_vector<decay_t<Value<T>>>::value)
is_vector = true;
ifstream file(path);
content = load(file);
}
constexpr unsigned size() {
return content.size();
}
};
template<class Key, template <class...T> class Value, typename T> // detect arithmatic types
class dict<Key, Value, T, typename enable_if<is_arithmetic<Value<T>>::value>::type> {
public:
dict() {
// we'll come to you later..
}
};
main.cpp
#include <iostream>
#include "utils.h"
int main() {
dict<string, vector, string> d("/home/path/to/some/file");
cout << d.size();
}
results:
error: no member named 'emplace_hint' in 'std::vector<std::__cxx11::basic_string<char>, std::allocator<std::__cxx11::basic_string<char> > >'
result.emplace_hint(it, static_cast<T>(tokens[i]));
questions:
1 - why on earth if (false) condition is reached in the first place?
2 - how could this be tweaked to achieve the desired instantiation style?
if (false) doesn't mean the code isn't compiled; it simply means the code inside is not executed at runtime, but it still has to be valid.
There are (at least) three kinds of conditional constructs in C++:
Preprocessor conditions. This tells the preprocessor not to pass the code to the compiler if if the condition is not met. Therefore, the code can be completely gibberish as long as it consists of valid preprocessor tokens. For example, the following is a well-formed C++ program with defined behavior:
#include <iostream>
int main()
{
#if 0
YYMJBNvOldLdK8rC0PTXH8DHJ58FQpP0MisPZECDuYHDJ7xL9G
#else
std::cout << "Hello world!\n";
#endif
}
Runtime selection statements. Such code is still parsed by the compiler and must still be valid code regardless of whether the compiler is capable of proving unreachable code — the compiler cannot even find the terminating } if it doesn't parse the code. This is partly because compilers cannot evaluate arbitrary expressions at runtime — if you don't specify explicitly (see next bullet), then evaluation defaults to be runtime. Therefore, the code above becomes ill-formed if you replace #if 0 – #else – #endif with if (false) { – } else { – }. However, runtime errors (i.e., undefined behavior) within unreachable code are fine. Therefore, the following is a well-formed C++ program with defined behavior: (some compilers may generate warnings, but that's irrelevant)
#include <iostream>
#include <climits>
int main()
{
if (false) {
volatile int x = 42/0;
x = *static_cast<int*>(nullptr);
const int y = INT_MAX + 1;
} else {
std::cout << "Hello world!\n";
}
}
(Since C++17) if constexpr. The rule for this one is a bit complex. The condition has to be known at compile time, and the false branch is discarded. The discarded branch is still required to be valid, except that it is not instantiated. Therefore, the code above is still valid code if you change if to if constexpr. The following is also a well-formed C++ program with defined behavior:
#include <iostream>
#include <type_traits>
template <typename T>
void print(T x)
{
if constexpr (std::is_same_v<T, int>) {
std::cout << static_cast<typename T::template stack<T>::overflow>(x);
} else {
std::cout << x;
}
}
int main()
{
print("Hello world!\n");
}
The typename and template are still necessary to make the code syntactically valid, but the nonexistent type const char*::stack<const char*>::overflow is not formed.
In your case, you can write a trait class to determine whether a type is a specialization of the class template std::vector: (here I use the standard traits convention)
template <typename C>
struct is_std_vector :std::false_type {};
template <typename T, typename A>
struct is_std_vector<std::vector<T, A>> :std::true_type {};
template <typename C>
inline constexpr bool is_std_vector_v = is_std_vector<C>::value;
Then use it in if constexpr to dispatch: (don't forget to replace Container with the container type you are examining)
if constexpr (is_std_vector_v<Container>) {
// do std::vector specific things
} else {
// do other things
}

Boost Spirit: how to count occurences of certain characters and then put the result in AST?

I would like to parse the following text:
group RGB
group RRGB
group GBBB
group RRGGG
The resulting AST would be a struct that represents counts of each character:
struct group
{
int r;
int g;
int b;
};
For the inputs above it would be 1,1,1, 2,1,1, 0,1,3, 2,3,0.
I can't come with any grammar that would conveniently count characters and enforce their order (GBR should fail the parse).
https://www.boost.org/doc/libs/develop/libs/spirit/doc/x3/html/spirit_x3/quick_reference/directive.html
There is x3::repeat parser but in only enfoces certain count of characters, it's attribute is a container.
x3::matches[a] has bool attribute but I don't know how many times a character may appear
There is no parser that would count appearance and return number of matches. I want a grammar like x3::lit("group") >> count['R'] >> count['G'] >> count['B'], but have no idea how count should be defined.
Right now the only working solution I can think of would be x3::lit("group") >> (*x3::char_['R'] >> *x3::char_['G'] >> *x3::char_['B'])[func] which then calls func that would just operate on the string. IMO this is not a clean solution and it requires semantic actions and creates unnecessary strings.
Slightly modifying "x3/directive/matches.hpp" you can get something like this:
#include <boost/spirit/home/x3/core/parser.hpp>
#include <boost/spirit/home/x3/support/traits/move_to.hpp>
#include <boost/spirit/home/x3/support/unused.hpp>
namespace not_boost { namespace not_spirit { namespace not_x3
{
template <typename Subject>
struct count_directive : boost::spirit::x3::unary_parser<Subject, count_directive<Subject>>
{
using base_type = boost::spirit::x3::unary_parser<Subject, count_directive<Subject>>;
static bool const has_attribute = true;
using attribute_type = int;
count_directive(Subject const& subject) : base_type(subject) {}
template <typename Iterator, typename Context
, typename RContext, typename Attribute>
bool parse(Iterator& first, Iterator const& last
, Context const& context, RContext& rcontext, Attribute& attr) const
{
int count=0;
while(this->subject.parse(first, last, context, rcontext, boost::spirit::x3::unused))
{
count++;
}
boost::spirit::x3::traits::move_to(count, attr);
return true;
}
};
struct count_gen
{
template <typename Subject>
count_directive<typename boost::spirit::x3::extension::as_parser<Subject>::value_type>
operator[](Subject const& subject) const
{
return { boost::spirit::x3::as_parser(subject) };
}
};
auto const count = count_gen{};
}}}
Running on Wandbox

How do you create a generic parser using qi?

I am attempting to create generic parser-elements using qi as I unfortunately (MSVC must be supported) can not use X3.
The idea is to have a templated struct:
template<class T> struct parse_type;
Which I could use like this:
template<class T> T from_string(std::string const& s)
{
T res;
parse_type<T> t;
...
if (phrase_parse(...,parse_type<T>(),...,t))
}
or specialise like this
template<class T,class Alloc>
struct parse_type<std::vector<T,Alloc>>
{
// Parse a vector using rule '[' >> parse_type<T> % ',' > ']';
}
The primary purpose is to allow for easy parsing of e.g. std::tuple, boost::optional and boost::variant (The last one can not be automatic due to the greedy nature of qi).
I would appreciate feedback as to how approach this. Currently I base my struct on qi::grammar, but grammar is not supported in X3 and I would like to use X3 when MSVC compiles this, and I am also a little bit uncomfortable with having to provide the skipper.
An alternative would be to have a static function in parse_type that returns the appropriate rule. I am considering if this is a cleaner approach?
Any feedback will be appreciated.
Update2: Replaced code-snippet with compilable example that fails at runtime. Here is the code:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <string>
#include <string>
#include <iostream>
#include <iostream>
// Support to simplify
using iter = std::string::const_iterator;
void print(std::vector<int> const& v)
{
std::cout << '[';
for (auto i: v) std::cout << i << ',';
std::cout << "]";
}
namespace qi = boost::spirit::qi;
// My rule factory - quite useless if you do not specialise
template<class T> struct ps_rule;
// An example of using the factory
template<class T>
T from_string(std::string const& s)
{
T result;
iter first { std::begin(s) };
auto rule = ps_rule<T>::get();
phrase_parse(first,std::end(s),rule,qi::space,result);
return result;
}
// Specialising rule for int
template<>
struct ps_rule<int>
{
static qi::rule<iter,int()> get() { return qi::int_; }
};
// ... and for std::vector (where the elements must have rules)
template<class T,class Alloc>
struct ps_rule<std::vector<T,Alloc>>
{
static qi::rule<iter,std::vector<T,Alloc>()> get()
{
qi::rule<iter,std::vector<T,Alloc>()> res;
res.name("Vector");
res =
qi::lit('{')
>> ps_rule<T>::get() % ','
>> '}';
return res;
}
};
int main()
{
// This one works like a charm.
std::cout << ((from_string<int>("100") == 100) ? "OK\n":"Failed\n");
std::vector<int> v {1,2,3,4,5,6};
// This one fails
std::cout << ((from_string<std::vector<int>>("{1,2,3,4,5,6}") == v) ? "OK\n":"Failed\n");
}
The code fails in boost/function_template.hpp line 766:
result_type operator()(BOOST_FUNCTION_PARMS) const
{
if (this->empty())
boost::throw_exception(bad_function_call());
return get_vtable()->invoker
(this->functor BOOST_FUNCTION_COMMA BOOST_FUNCTION_ARGS);
}
This code is a member function in boost::function4
,boost::fusion::vector0 > &
,boost::spirit::unused_type const&>
and the problem is that get_vtable returns an invalid pointer.
Your main problem is that the copy constructor for qi::rule takes a reference to the original rule, which in your case is a local variable. One way you can avoid this problem is by using qi::rule's copy member function but this requires changing slightly the return type of your specialization of ps_rule.
static typename boost::proto::terminal<qi::rule<iter,std::vector<T,Alloc>()>>::type get()
{
//[...] (same as before)
return res.copy();
}
Once you do that, the same problem arises with your ps_rule<int> even though it seemed to work in isolation. You could do something analogous but in this case the rule is not required, it would be better (even from a performance point of view) to just use something like:
static qi::int_type get() { return qi::int_; }
Full Sample (Running on WandBox)
#include <boost/spirit/include/qi.hpp>
#include <string>
#include <iostream>
// Support to simplify
using iter = std::string::const_iterator;
void print(std::vector<int> const& v)
{
std::cout << '[';
for (auto i: v) std::cout << i << ',';
std::cout << "]";
}
namespace qi = boost::spirit::qi;
// My rule factory - quite useless if you do not specialise
template<class T> struct ps_rule;
// An example of using the factory
template<class T>
T from_string(std::string const& s)
{
T result;
iter first { std::begin(s) };
auto rule = ps_rule<T>::get();
qi::phrase_parse(first,std::end(s),rule,qi::space,result);
return result;
}
// Specialising rule for int
template<>
struct ps_rule<int>
{
static qi::int_type get() { return qi::int_; }
};
// ... and for std::vector (where the elements must have rules)
template<class T,class Alloc>
struct ps_rule<std::vector<T,Alloc>>
{
static typename boost::proto::terminal<qi::rule<iter,std::vector<T,Alloc>()>>::type get()
{
qi::rule<iter,std::vector<T,Alloc>()> res;
res.name("Vector");
res =
qi::lit('{')
>> ps_rule<T>::get() % ','
>> '}';
return res.copy();
}
};
int main()
{
// This one works like a charm.
std::cout << ((from_string<int>("100") == 100) ? "OK\n":"Failed\n");
std::vector<int> v {1,2,3,4,5,6};
std::cout << ((from_string<std::vector<int>>("{1,2,3,4,5,6}") == v) ? "OK\n":"Failed\n");
std::vector<std::vector<int> > vv {{1,2,3},{4,5,6}};
std::cout << ((from_string<std::vector<std::vector<int>>>("{{1,2,3},{4,5,6}}") == vv) ? "OK\n":"Failed\n");
}
PS: You can save lots of specializations if you use Spirit's own machinery to create parsers automatically in your primary template. Here is an example.

boost::fusion::map allows duplicate keys

According to the boost::fusion::map docs:
A map may contain at most one element for each key.
In practice, it is easy to violate this.
I am able to define the following type:
using map_type = fusion::map<
fusion::pair<int, char>
, fusion::pair<int, char>
, fusion::pair<int, char>>;
and instantiate it with these duplicate keys:
map_type m(
fusion::make_pair<int>('X')
, fusion::make_pair<int>('Y')
, fusion::make_pair<int>('Z'));
Iterating over the map using fusion::for_each shows the data structure does indeed contain 3 pairs, and each of the keys is of type int:
struct Foo
{
template<typename Pair>
void operator()(const Pair& p) const
{
std::cout << typeid(typename Pair::first_type).name() << "=" << p.second << '\n';
}
};
fusion::for_each(m, Foo {});
Output:
i=X
i=Y
i=Z
I would have expected a static_assert on key uniqueness, but this is obviously not the case.
Why is this?
How can I ensure that no one can instantiate a fusion::map with duplicate keys?
Full working example: (on coliru)
#include <boost/fusion/container.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <iostream>
namespace fusion = ::boost::fusion;
struct Foo
{
template<typename Pair>
void operator()(const Pair& p) const
{
std::cout << typeid(typename Pair::first_type).name() << "=" << p.second << '\n';
}
};
int main()
{
using map_type = fusion::map<
fusion::pair<int, char>
, fusion::pair<int, char>
, fusion::pair<int, char>>;
map_type m(
fusion::make_pair<int>('X')
, fusion::make_pair<int>('Y')
, fusion::make_pair<int>('Z'));
fusion::for_each(m, Foo {});
return 0;
}
Due to comments below, here are some further details on what I'm actually trying to achieve.
The idea is to automatically generate FIX serialisation code.
A given field type can only exist once in any given FIX message - hence wanting the static_assert
Motivating example: (on coliru)
#include <boost/fusion/container.hpp>
#include <boost/fusion/sequence.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/mpl/transform.hpp>
#include <iostream>
namespace fusion = ::boost::fusion;
namespace mpl = ::boost::mpl;
template<class Field>
struct MakePair
{
using type = typename fusion::result_of::make_pair<Field, typename Field::Type>::type;
};
template<class Fields>
struct Map
{
using pair_sequence = typename mpl::transform<Fields, MakePair<mpl::_1>>::type;
using type = typename fusion::result_of::as_map<pair_sequence>::type;
};
///////////////////////////
template<typename... Fields>
class Message
{
public:
template<class Field>
void set(const typename Field::Type& val)
{
fusion::at_key<Field>(_fields) = val;
}
void serialise()
{
fusion::for_each(_fields, Serialiser {});
}
private:
struct Serialiser
{
template<typename Pair>
void operator()(const Pair& pair) const
{
using Field = typename Pair::first_type;
std::cout << Field::Tag << "=" << pair.second << "|";
}
};
using FieldsVector = fusion::vector<Fields...>;
using FieldsMap = typename Map<FieldsVector>::type;
FieldsMap _fields;
static_assert(fusion::result_of::size<FieldsMap>::value == fusion::result_of::size<FieldsVector>::value,
"message must be constructed from unique types"); // this assertion doesn't work
};
///////////////////////////
#define MSG_FIELD(NAME, TYPE, TAG) \
struct NAME \
{ \
using Type = TYPE; \
static const int Tag = TAG; \
};
MSG_FIELD(MsgType, char, 35)
MSG_FIELD(Qty, int, 14)
MSG_FIELD(Price, double, 44)
using Quote = Message<MsgType, Qty, Price>;
///////////////////////////
int main()
{
Quote q;
q.set<MsgType>('a');
q.set<Qty>(5);
q.set<Price>(1.23);
q.serialise();
return 0;
}
From the docs on associative containers:
... Keys are not checked for uniqueness.
As alluded to by Richard Hodges, this is likely by design
wouldn't that static_assert involve a geometric template expansion each time it was encountered?
Nonetheless, it is possible to use boost::mpl to reduce the sequence provided to the fusion::map into a unique sequence, and static_assert on the sequence lengths being the same.
First we create a struct which iterates over the list of types and creates a sequence of unique types
// given a sequence, returns a new sequence with no duplicates
// equivalent to:
// vector UniqueSeq(vector Seq)
// vector newSeq = {}
// set uniqueElems = {}
// for (elem : Seq)
// if (!uniqueElems.find(elem))
// newSeq += elem
// uniqueElems += elem
// return newSeq
template<class Seq>
struct UniqueSeq
{
using type = typename mpl::accumulate<
Seq,
mpl::pair<typename mpl::clear<Seq>::type, mpl::set0<> >,
mpl::if_<
mpl::contains<mpl::second<mpl::_1>, mpl::_2>,
mpl::_1,
mpl::pair<
mpl::push_back<mpl::first<mpl::_1>, mpl::_2>,
mpl::insert<mpl::second<mpl::_1>, mpl::_2>
>
>
>::type::first;
};
Then we change the definition of Map to use UniqueSeq::type to generate pair_sequence:
// given a sequence of fields, returns a fusion map which maps (Field -> Field's associate type)
template<class Fields>
struct Map
{
using unique_fields = typename UniqueSeq<Fields>::type;
using pair_sequence = typename mpl::transform<unique_fields, MakePair<mpl::_1>>::type;
using type = typename fusion::result_of::as_map<pair_sequence>::type;
};
So given a list of fields, we can create a fusion::vector and a fusion::map with the result of UniqueSeq<Fields>, and assert the size of each is the same:
using FieldsVector = fusion::vector<Fields...>;
using FieldsMap = typename Map<FieldsVector>::type;
static_assert(fusion::result_of::size<FieldsMap>::value == fusion::result_of::size<FieldsVector>::value,
"message must be constructed from unique types");
Passing duplicated fields now causes a compilation error:
static assertion failed: message must be constructed from unique types
scratch/main.cpp: In instantiation of ‘class Message<Qty, Price, Qty>’:
scratch/main.cpp:129:23: required from here
scratch/main.cpp:96:5: error: static assertion failed: message must be constructed from unique types
static_assert(fusion::result_of::size<FieldsMap>::value == fusion::result_of::size<FieldsVector>::value,
^
Full example on coliru
It is not an answer (OP already provided an answer), but a response to request to clarify some of my comments.
One way of achieving key uniqueness would be thrugh raw mpl usage. For example, taking FIX message as our domain, following piece of code should illustrate the idea. The code was not compiled and provided as generic illustration example only.
template <class ValueType, int FieldTag>
struct FixField {
using value_t = ValueType;
static const short tag = FieldTag;
};
using CumQty = FixField<double, 14>;
using Price = FixField<double, 44>;
using inherit = boost::mpl::inherit<boost::mpl::placeholders::_1, boost::mpl::placeholders::_2>;
template <class list>
using inherit_linearly = boost::mpl::inherit_linearly<list, inherit>::type;
template <class Members>
struct FixMessage : iherit_linearly<Members> {
using members_t = Members;
template <class T> T& get() { return static_cast<T&>(*this); } // const ver as well
};
struct ExecutionReport : public FixMessage<boost::mpl::set<CumQty, Price> > {
static constexpr char const* name = "ExecutionReport";
};
Now you have all the instrospection into execution report you want. You can easily serialize it with boost::mpl::for_each, or you can deserialze any message and get strongly-typed FixMessage.
I am not sure if you going to get a compilation error if you use the same type twice, but I am sure that you will only see the type once when iterating.

Name expressions in Boost Spirit without assignment to a rule

Is it possible to name an expression in Boost Spirit without its assignment to a rule?
I know you can name it by assignment to a rule like:
using boost::spirit::standard::char_;
boost::spirit::qi::rule<> number = char_("0") | (char_("1-9") >> *char_("0-9"));
number.name("number");
Which makes debugging of syntax errors easier as you can already have the particular part named in the right way.
But is it possible to do this inline in such a way?
using boost::spirit::standard::char_;
boost::spirit::qi::rule<> twoDigits = char_("0-9") > name(char_("0-9"), "digit");
So that the exception would say that it expected a "digit" at position 2 if it got an input like "3a" (it is not really important here that it is position 2).
The alternative way to express this would be:
using boost::spirit::standard::char_;
boost::spirit::qi::rule<> digit = char_("0-9");
digit.name("digit");
boost::spirit::qi::rule<> twoDigits = digit > digit;
I already checked the source and found out that the expression have a function called what(), which returns a boost::spirit::info object from which the string representation can be retrieved. But I was not able to overwrite that as I am not familier with Boost Proto and the internals of Boost Spirit.
Here is an approach using a custom directive. You can see a very good explanation of how to do something similar (it's a parser, not a directive) here.
The process of creating a custom parser/directive can be divided in four parts:
Defining/creating a terminal to use in a Spirit expression. Usually you'll use BOOST_SPIRIT_TERMINAL unless you need your parser/directive to be of the form parser(whatever)/directive(whatever)[subject]. In this case you'll need to use BOOST_SPIRIT_TERMINAL_EX. This case is specially strange in that you need state associated with your terminal, and so you need to define a struct deriving from terminal<tag::stateful_tag,...>. This is usually not required. I've decided to put all this in namespace custom_directive but you could also put it inside boost::spirit::qi.
Enabling your parser/directive. Here you need to specialize either use_terminal(for parsers) or use_directive(for directives) inside namespace boost::spirit.
Creating the actual parser/directive. This parser/directive requires three things: a attribute<Context,Iterator>::type associated metafunction that states what the attribute of your parser is(in this case I have simply passed the attribute of the subject parser through); a parse member function with the appropiate signature that does the real parsing (again I have deferred to the subject parser), and a what member function that is what we really are interested in modifying that returns whatever you have associated with the terminal on construction. Again I have decided to use namespace custom_directive but you could also put it inside boost::spirit::qi.
Connecting the terminal with your actual parser/directive. This needs to be inside boost::spirit::qi and requires that you specialize either make_directive or make_primitive with your terminal tag and instatiate your actual parser/directive.
Live on coliru
#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
//START OF expression_renamer.hpp
namespace custom_directive
{
BOOST_SPIRIT_TERMINAL(rename_expression);
struct expression_renamer: boost::spirit::terminal<boost::spirit::tag::stateful_tag<std::string, tag::rename_expression> >
{
typedef boost::spirit::tag::stateful_tag<std::string, tag::rename_expression> tag_type;
expression_renamer(std::string const& p) : boost::spirit::terminal<tag_type>(p) {}
};
}
namespace boost { namespace spirit
{
template <>
struct use_directive<qi::domain, boost::spirit::tag::stateful_tag<std::string, custom_directive::tag::rename_expression> > // enables expression_renamer[p]
: mpl::true_ {};
}}
namespace custom_directive
{
template <typename Subject, typename Data>
struct rename_directive : boost::spirit::qi::unary_parser<rename_directive<Subject,Data> >
{
typedef Subject subject_type;
rename_directive(Subject const& subject_, Data const& data_)
: subject(subject_),data(data_) {}
template <typename Context, typename Iterator>
struct attribute
{
typedef typename
boost::spirit::traits::attribute_of<subject_type, Context, Iterator>::type
type;
};
template <typename Iterator, typename Context
, typename Skipper, typename Attribute>
bool parse(Iterator& first, Iterator const& last, Context& context, Skipper const& skipper, Attribute& attr_) const
{
return subject.parse(first, last, context, skipper, attr_);
}
template <typename Context>
boost::spirit::info what(Context& context) const
{
return boost::spirit::info(data);
}
Subject subject;
Data data;
};
}
// instantiation of the parser
namespace boost { namespace spirit { namespace qi
{
template<typename Data, typename Subject,typename Modifiers>
struct make_directive<tag::stateful_tag<Data, custom_directive::tag::rename_expression>, Subject, Modifiers>
{
typedef custom_directive::rename_directive<Subject,Data> result_type;
template<typename Terminal>
result_type operator()(Terminal& term, Subject const& subject, unused_type) const
{
typedef tag::stateful_tag<Data,
custom_directive::tag::rename_expression> tag_type;
using spirit::detail::get_stateful_data;
return result_type(subject,get_stateful_data<tag_type>::call(term));
}
};
}}}
//END OF expression_renamer.hpp
template <typename Parser>
void parse(std::string const& str, Parser const& parser)
{
std::cout << "Parsing: \"" << str << "\"" << " with `digit` `point` `digit`" << std::endl;
std::string::const_iterator iter=str.begin(),end=str.end();
boost::spirit::qi::parse(iter,end,parser);
}
int main()
{
custom_directive::expression_renamer point("point");
custom_directive::expression_renamer digit("digit");
boost::spirit::qi::char_type char_;
boost::spirit::qi::rule<std::string::const_iterator> twoDigitsWithPoint = char_("0-9") > point[char_('.')] > digit[char_("0-9")];
boost::spirit::qi::on_error<boost::spirit::qi::fail>
(
twoDigitsWithPoint
, std::cout
<< boost::phoenix::val("Error! Expecting ")
<< boost::spirit::qi::_4 // what failed?
<< std::endl
);
parse("33",twoDigitsWithPoint);
parse("3.a",twoDigitsWithPoint);
}
You can group using auto. But debug names can only be attached to the non-terminals: qi::rule<> and qi::grammar<> (other "groupings" aren't traced anyways, not even with attr_cast<>, which is semantically close to the attribute propagation semantics of a rule<>).
There is a big caveat related to using auto:
Proto expression trees need to be deep copied. Recent Qi defines qi::copy() to do just that.