Ticket #7143: map_example2.cpp

File map_example2.cpp, 3.8 KB (added by anonymous, 10 years ago)
Line 
1#include <map>
2#include <string>
3#include <iostream>
4#include <boost/proto/proto.hpp>
5#include <boost/xpressive/xpressive.hpp>
6#include <boost/xpressive/regex_actions.hpp>
7namespace proto = boost::proto;
8
9struct map_ {};
10boost::proto::terminal<map_>::type map = {};
11
12typedef std::map<std::string, std::string> string_map;
13
14// Recursive function used to fill the map
15template< class Expr >
16void fill_map( Expr const & expr, string_map & subs )
17{
18 using boost::proto::value; // read a value from a terminal
19 using boost::proto::child_c; // get the Nth child of a non-terminal
20 subs[ value(child_c<1>( expr )) ] = value(child_c<2>(expr));
21 fill_map( child_c<0>(expr), subs );
22}
23
24// The 'map' terminal ends the recursion
25void fill_map( boost::proto::terminal<map_>::type const &, string_map & )
26{}
27
28// The old format API that accepts a map of string substitutions
29std::string format( std::string fmt, string_map & subs )
30{
31 namespace xp = boost::xpressive;
32 using namespace xp;
33 sregex const rx = '{' >> (s1= +_w) >> '}'; // like "{(\\w+)}"
34 return regex_replace(fmt, rx, xp::ref(subs)[s1]);
35}
36
37// The new format API that forwards to the old one
38/* Replaced by Validation 1.
39template< class Expr >
40std::string format( std::string fmt, Expr const & expr )
41{
42 string_map subs;
43 fill_map( expr, subs );
44 return format( fmt, subs );
45}
46*/
47
48// Define the grammar of map expressions
49struct MapGrammar
50 : proto::or_<
51 // A map expression is a map terminal, or
52 proto::terminal<map_>
53 // ... a ternary function non-terminal where the child nodes are
54 , proto::function<
55 // ... a map expression,
56 MapGrammar
57 // ... a narrow string terminal, and
58 , proto::terminal<char const *>
59 // ... another narrow string terminal.
60 , proto::terminal<char const *>
61 >
62 >
63{};
64
65// Validation version 1.
66/* replaced by Validation 2.
67template< class Expr >
68std::string format( std::string fmt, Expr const & expr )
69{
70 // Comment removed.
71 static_assert(
72 proto::matches<Expr, MapGrammar>::value
73 , "The map expression passed to format does not match MapGrammar");
74 string_map subs;
75 fill_map( expr, subs );
76 return format( fmt, subs );
77}
78*/
79
80template< class Expr >
81std::string format_impl( std::string fmt, Expr const & expr, boost::mpl::true_ )
82{
83 string_map subs;
84 fill_map( expr, subs );
85 return format( fmt, subs );
86}
87
88template< class Expr >
89std::string format_impl( std::string fmt, Expr const & expr, boost::mpl::false_ )
90{
91 return std::string(); // never called for valid imput
92}
93
94// Validation 2.
95template< class Expr >
96std::string format( std::string fmt, Expr const & expr )
97{
98 /* READ THIS IF YOUR COMPILE BREAKS ON THE FOLLOWING LINE
99 *
100 * You have passed to format an invalid map expression.
101 * They should be of the form:
102 * map("this", "that")("here", "there")
103 */
104 static_assert(
105 proto::matches<Expr, MapGrammar>::value
106 , "The map expression passed to format does not match MapGrammar");
107
108 /* Dispatch to the real implementation or a stub depending on
109 whether our parameters are valid or not.
110 */
111 return format_impl( fmt, expr, proto::matches<Expr, MapGrammar>() );
112}
113
114int main()
115{
116 std::cout << format("The home directory of {user} is {home}\n"
117 , map("user", "eric")
118 ("home", "/home/eric") );
119}
120
121/* error message:
122map_example2_cxx0x_clang31_libc++: boost_1_50_0/boost/xpressive/traits/cpp_regex_traits.hpp:273: void boost::xpressive::detail::cpp_regex_traits_base<char, 1>::imbue(const std::locale &) [Char = char, SizeOfChar = 1]: Assertion `0 == (this->masks_[i] & non_std_ctype_masks)' failed.
123Aborted
124*/