1 /*=============================================================================
2     Copyright (c) 2001-2014 Joel de Guzman
3     Copyright (c) 2001-2011 Hartmut Kaiser
4 
5     Distributed under the Boost Software License, Version 1.0. (See accompanying
6     file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 ================================================_==============================*/
8 #if !defined(BOOST_SPIRIT_X3_PRINT_ATTRIBUTE_JANUARY_20_2013_0814AM)
9 #define BOOST_SPIRIT_X3_PRINT_ATTRIBUTE_JANUARY_20_2013_0814AM
10 
11 #include <boost/variant.hpp>
12 #include <boost/optional/optional.hpp>
13 #include <boost/fusion/include/is_sequence.hpp>
14 #include <boost/fusion/include/for_each.hpp>
15 #include <boost/spirit/home/x3/support/traits/attribute_category.hpp>
16 #include <boost/spirit/home/x3/support/traits/is_variant.hpp>
17 
18 namespace boost { namespace spirit { namespace x3 { namespace traits
19 {
20     template <typename Out, typename T>
21     void print_attribute(Out& out, T const& val);
22 
23     template <typename Out>
print_attribute(Out &,unused_type)24     inline void print_attribute(Out&, unused_type) {}
25 
26     ///////////////////////////////////////////////////////////////////////////
27     namespace detail
28     {
29         template <typename Out>
30         struct print_fusion_sequence
31         {
print_fusion_sequenceboost::spirit::x3::traits::detail::print_fusion_sequence32             print_fusion_sequence(Out& out)
33               : out(out), is_first(true) {}
34 
35             typedef void result_type;
36 
37             template <typename T>
operator ()boost::spirit::x3::traits::detail::print_fusion_sequence38             void operator()(T const& val) const
39             {
40                 if (is_first)
41                     is_first = false;
42                 else
43                     out << ", ";
44                 x3::traits::print_attribute(out, val);
45             }
46 
47             Out& out;
48             mutable bool is_first;
49         };
50 
51         // print elements in a variant
52         template <typename Out>
53         struct print_visitor : static_visitor<>
54         {
print_visitorboost::spirit::x3::traits::detail::print_visitor55             print_visitor(Out& out) : out(out) {}
56 
57             template <typename T>
operator ()boost::spirit::x3::traits::detail::print_visitor58             void operator()(T const& val) const
59             {
60                 x3::traits::print_attribute(out, val);
61             }
62 
63             Out& out;
64         };
65     }
66 
67     template <typename Out, typename T, typename Enable = void>
68     struct print_attribute_debug
69     {
70         // for plain data types
71         template <typename T_>
callboost::spirit::x3::traits::print_attribute_debug72         static void call(Out& out, T_ const& val, unused_attribute)
73         {
74             out << "unused";
75         }
76 
77         // for plain data types
78         template <typename T_>
callboost::spirit::x3::traits::print_attribute_debug79         static void call(Out& out, T_ const& val, plain_attribute)
80         {
81             out << val;
82         }
83 
84         // for fusion data types
85         template <typename T_>
callboost::spirit::x3::traits::print_attribute_debug86         static void call(Out& out, T_ const& val, tuple_attribute)
87         {
88             out << '[';
89             fusion::for_each(val, detail::print_fusion_sequence<Out>(out));
90             out << ']';
91         }
92 
93         // stl container
94         template <typename T_>
callboost::spirit::x3::traits::print_attribute_debug95         static void call(Out& out, T_ const& val, container_attribute)
96         {
97             out << '[';
98             if (!traits::is_empty(val))
99             {
100                 bool first = true;
101                 typename container_iterator<T_ const>::type iend = traits::end(val);
102                 for (typename container_iterator<T_ const>::type i = traits::begin(val);
103                      !traits::compare(i, iend); traits::next(i))
104                 {
105                     if (!first)
106                         out << ", ";
107                     first = false;
108                     x3::traits::print_attribute(out, traits::deref(i));
109                 }
110             }
111             out << ']';
112         }
113 
114         // for variant types
115         template <typename T_>
callboost::spirit::x3::traits::print_attribute_debug116         static void call(Out& out, T_ const& val, variant_attribute)
117         {
118             apply_visitor(detail::print_visitor<Out>(out), val);
119         }
120 
121         // for optional types
122         template <typename T_>
callboost::spirit::x3::traits::print_attribute_debug123         static void call(Out& out, T_ const& val, optional_attribute)
124         {
125             if (val)
126                 x3::traits::print_attribute(out, *val);
127             else
128                 out << "[empty]";
129         }
130 
131         // main entry point
callboost::spirit::x3::traits::print_attribute_debug132         static void call(Out& out, T const& val)
133         {
134             call(out, val, typename attribute_category<T>::type());
135         }
136     };
137 
138     ///////////////////////////////////////////////////////////////////////////
139     template <typename Out, typename T>
print_attribute(Out & out,T const & val)140     inline void print_attribute(Out& out, T const& val)
141     {
142         print_attribute_debug<Out, T>::call(out, val);
143     }
144 }}}}
145 
146 #endif
147