1 /*=============================================================================
2     Copyright (c) 2001-2011 Hartmut Kaiser
3     http://spirit.sourceforge.net/
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 #include <boost/config/warning_disable.hpp>
9 
10 //[customize_karma_use_as_container_includes
11 #include <boost/spirit/include/karma.hpp>
12 #include <iostream>
13 #include <string>
14 #include <vector>
15 //]
16 
17 ///////////////////////////////////////////////////////////////////////////////
18 //[customize_karma_use_as_container_data
19 namespace client
20 {
21     struct use_as_container
22     {
23         // Expose a pair holding a pointer to the use_as_container and to the
24         // current element as our iterator.
25         // We intentionally leave out having it a 'operator==()' to demonstrate
26         // the use of the 'compare_iterators' customization point.
27         struct iterator
28         {
iteratorclient::use_as_container::iterator29             iterator(use_as_container const* container, int const* current)
30               : container_(container), current_(current)
31             {}
32 
33             use_as_container const* container_;
34             int const* current_;
35         };
36 
37         // expose 'int' as the type of each generated element
38         typedef int type;
39 
use_as_containerclient::use_as_container40         use_as_container(int value1, int value2, int value3)
41           : value1_(value1), value2_(value2), value3_(value3)
42         {}
43 
44         int value1_;
45         std::string dummy1_;    // insert some unrelated data
46         int value2_;
47         std::string dummy2_;    // insert some more unrelated data
48         int value3_;
49     };
50 }
51 //]
52 
53 //[customize_karma_use_as_container_traits
54 // All specializations of attribute customization points have to be placed into
55 // the namespace boost::spirit::traits.
56 //
57 // Note that all templates below are specialized using the 'const' type.
58 // This is necessary as all attributes in Karma are 'const'.
59 namespace boost { namespace spirit { namespace traits
60 {
61     // The specialization of the template 'is_container<>' will tell the
62     // library to treat the type 'client::use_as_container' as a
63     // container holding the items to generate output from.
64     template <>
65     struct is_container<client::use_as_container const>
66       : mpl::true_
67     {};
68 
69     // The specialization of the template 'container_iterator<>' will be
70     // invoked by the library to evaluate the iterator type to be used
71     // for iterating the data elements in the container. We simply return
72     // the type of the iterator exposed by the embedded 'std::vector<int>'.
73     template <>
74     struct container_iterator<client::use_as_container const>
75     {
76         typedef client::use_as_container::iterator type;
77     };
78 
79     // The specialization of the templates 'begin_container<>' and
80     // 'end_container<>' below will be used by the library to get the iterators
81     // pointing to the begin and the end of the data to generate output from.
82     //
83     // The passed argument refers to the attribute instance passed to the list
84     // generator.
85     template <>
86     struct begin_container<client::use_as_container const>
87     {
88         static client::use_as_container::iterator
callboost::spirit::traits::begin_container89         call(client::use_as_container const& c)
90         {
91             return client::use_as_container::iterator(&c, &c.value1_);
92         }
93     };
94 
95     template <>
96     struct end_container<client::use_as_container const>
97     {
98         static client::use_as_container::iterator
callboost::spirit::traits::end_container99         call(client::use_as_container const& c)
100         {
101             return client::use_as_container::iterator(&c, (int const*)0);
102         }
103     };
104 }}}
105 //]
106 
107 //[customize_karma_use_as_container_iterator_traits
108 // All specializations of attribute customization points have to be placed into
109 // the namespace boost::spirit::traits.
110 namespace boost { namespace spirit { namespace traits
111 {
112     // The specialization of the template 'deref_iterator<>' will be used to
113     // dereference the iterator associated with our counter data structure.
114     template <>
115     struct deref_iterator<client::use_as_container::iterator>
116     {
117         typedef client::use_as_container::type type;
118 
callboost::spirit::traits::deref_iterator119         static type call(client::use_as_container::iterator const& it)
120         {
121             return *it.current_;
122         }
123     };
124 
125     template <>
126     struct next_iterator<client::use_as_container::iterator>
127     {
callboost::spirit::traits::next_iterator128         static void call(client::use_as_container::iterator& it)
129         {
130             if (it.current_ == &it.container_->value1_)
131                 it.current_ = &it.container_->value2_;
132             else if (it.current_ == &it.container_->value2_)
133                 it.current_ = &it.container_->value3_;
134             else
135                 it.current_ = 0;
136         }
137     };
138 
139     template <>
140     struct compare_iterators<client::use_as_container::iterator>
141     {
callboost::spirit::traits::compare_iterators142         static bool call(client::use_as_container::iterator const& it1
143           , client::use_as_container::iterator const& it2)
144         {
145             return it1.current_ == it2.current_ &&
146                    it1.container_ == it2.container_;
147         }
148     };
149 }}}
150 //]
151 
152 ///////////////////////////////////////////////////////////////////////////////
153 namespace karma = boost::spirit::karma;
154 
main()155 int main()
156 {
157     //[customize_karma_use_as_container
158     client::use_as_container d2 (1, 2, 3);
159     // use the instance of a 'client::use_as_container' instead of a STL vector
160     std::cout << karma::format(karma::int_ % ", ", d2) << std::endl;   // prints: '1, 2, 3'
161     //]
162     return 0;
163 }
164 
165