| 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>
|
|---|
| 7 | namespace proto = boost::proto;
|
|---|
| 8 |
|
|---|
| 9 | struct map_ {};
|
|---|
| 10 | boost::proto::terminal<map_>::type map = {};
|
|---|
| 11 |
|
|---|
| 12 | typedef std::map<std::string, std::string> string_map;
|
|---|
| 13 |
|
|---|
| 14 | // Recursive function used to fill the map
|
|---|
| 15 | template< class Expr >
|
|---|
| 16 | void 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
|
|---|
| 25 | void fill_map( boost::proto::terminal<map_>::type const &, string_map & )
|
|---|
| 26 | {}
|
|---|
| 27 |
|
|---|
| 28 | // The old format API that accepts a map of string substitutions
|
|---|
| 29 | std::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.
|
|---|
| 39 | template< class Expr >
|
|---|
| 40 | std::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
|
|---|
| 49 | struct 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.
|
|---|
| 67 | template< class Expr >
|
|---|
| 68 | std::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 |
|
|---|
| 80 | template< class Expr >
|
|---|
| 81 | std::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 |
|
|---|
| 88 | template< class Expr >
|
|---|
| 89 | std::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.
|
|---|
| 95 | template< class Expr >
|
|---|
| 96 | std::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 |
|
|---|
| 114 | int 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:
|
|---|
| 122 | map_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.
|
|---|
| 123 | Aborted
|
|---|
| 124 | */
|
|---|