1 // Boost.Range library
2 //
3 //  Copyright Neil Groves 2014.
4 //  Use, modification and distribution is subject to the Boost Software
5 //  License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 //  http://www.boost.org/LICENSE_1_0.txt)
7 //
8 // For more information, see http://www.boost.org/libs/range/
9 //
10 #ifndef BOOST_RANGE_ADAPTOR_FORMATTED_HPP_INCLUDED
11 #define BOOST_RANGE_ADAPTOR_FORMATTED_HPP_INCLUDED
12 
13 #include <boost/config.hpp>
14 #include <boost/range/concepts.hpp>
15 #include <boost/range/begin.hpp>
16 #include <boost/range/end.hpp>
17 #include <boost/range/iterator.hpp>
18 #include <boost/range/iterator_range_core.hpp>
19 #include <boost/mpl/if.hpp>
20 #include <boost/type_traits/is_array.hpp>
21 #include <boost/type_traits/remove_extent.hpp>
22 #include <ostream>
23 
24 namespace boost
25 {
26     namespace range_detail
27     {
28 
29 template<typename Sep, typename Prefix, typename Postfix>
30 struct formatted_holder
31 {
32     typedef typename boost::mpl::if_<
33         boost::is_array<Sep>,
34         const typename boost::remove_extent<Sep>::type*,
35         Sep
36     >::type separator_t;
37 
38     typedef typename boost::mpl::if_<
39         boost::is_array<Prefix>,
40         const typename boost::remove_extent<Prefix>::type*,
41         Prefix
42     >::type prefix_t;
43 
44     typedef typename boost::mpl::if_<
45         boost::is_array<Postfix>,
46         const typename boost::remove_extent<Postfix>::type*,
47         Postfix
48     >::type postfix_t;
49 
formatted_holderboost::range_detail::formatted_holder50     formatted_holder(
51         const separator_t& sep,
52         const prefix_t& prefix,
53         const postfix_t& postfix)
54         : m_sep(sep)
55         , m_prefix(prefix)
56         , m_postfix(postfix)
57     {
58     }
59 
60     separator_t m_sep;
61     prefix_t m_prefix;
62     postfix_t m_postfix;
63 };
64 
65 template<typename Iter, typename Sep, typename Prefix, typename Postfix>
66 class formatted_range
67         : public boost::iterator_range<Iter>
68 {
69     typedef formatted_holder<Sep,Prefix,Postfix> holder_t;
70 public:
formatted_range(Iter first,Iter last,const holder_t & holder)71     formatted_range(Iter first, Iter last, const holder_t& holder)
72         : boost::iterator_range<Iter>(first, last)
73         , m_holder(holder)
74     {
75     }
76 
77     template<typename OStream>
write(OStream & out) const78     void write(OStream& out) const
79     {
80         Iter it(this->begin());
81         out << m_holder.m_prefix;
82         if (it != this->end())
83         {
84             out << *it;
85             for (++it; it != this->end(); ++it)
86             {
87                 out << m_holder.m_sep << *it;
88             }
89         }
90         out << m_holder.m_postfix;
91     }
92 
93 private:
94     holder_t m_holder;
95 };
96 
97 template<
98     typename SinglePassRange,
99     typename Sep,
100     typename Prefix,
101     typename Postfix
102 >
103 inline range_detail::formatted_range<
104     typename range_iterator<const SinglePassRange>::type, Sep, Prefix, Postfix
105 >
operator |(const SinglePassRange & rng,const range_detail::formatted_holder<Sep,Prefix,Postfix> & holder)106 operator|(
107     const SinglePassRange& rng,
108     const range_detail::formatted_holder<Sep,Prefix,Postfix>& holder
109 )
110 {
111     typedef typename range_iterator<const SinglePassRange>::type iterator;
112     return range_detail::formatted_range<iterator, Sep, Prefix, Postfix>(
113         boost::begin(rng), boost::end(rng), holder);
114 }
115 
116 template<typename Char, typename Traits, typename Iter, typename Sep,
117     typename Prefix, typename Postfix>
118 std::basic_ostream<Char, Traits>&
operator <<(std::basic_ostream<Char,Traits> & out,const formatted_range<Iter,Sep,Prefix,Postfix> & writer)119 operator<<(
120         std::basic_ostream<Char, Traits>& out,
121         const formatted_range<Iter, Sep, Prefix, Postfix>& writer)
122 {
123     writer.write(out);
124     return out;
125 }
126 
127     } // namespace range_detail
128 
129     namespace adaptors
130     {
131 
132 template<typename Sep, typename Prefix, typename Postfix>
133 range_detail::formatted_holder<Sep, Prefix, Postfix>
formatted(const Sep & sep,const Prefix & prefix,const Postfix & postfix)134 formatted(const Sep& sep, const Prefix& prefix, const Postfix& postfix)
135 {
136     return range_detail::formatted_holder<Sep,Prefix,Postfix>(
137                 sep, prefix, postfix);
138 }
139 
140 template<typename Sep, typename Prefix>
141 range_detail::formatted_holder<Sep, Prefix, char>
formatted(const Sep & sep,const Prefix & prefix)142 formatted(const Sep& sep, const Prefix& prefix)
143 {
144     return range_detail::formatted_holder<Sep, Prefix, char>(sep, prefix, '}');
145 }
146 
147 template<typename Sep>
148 range_detail::formatted_holder<Sep, char, char>
formatted(const Sep & sep)149 formatted(const Sep& sep)
150 {
151     return range_detail::formatted_holder<Sep, char, char>(sep, '{', '}');
152 }
153 
154 inline range_detail::formatted_holder<char, char, char>
formatted()155 formatted()
156 {
157     return range_detail::formatted_holder<char, char, char>(',', '{', '}');
158 }
159 
160 using range_detail::formatted_range;
161 
162 template<typename SinglePassRange, typename Sep, typename Prefix,
163          typename Postfix>
164 inline boost::range_detail::formatted_range<
165     typename boost::range_iterator<const SinglePassRange>::type,
166     Sep, Prefix, Postfix
167 >
format(const SinglePassRange & rng,const Sep & sep,const Prefix & prefix,const Postfix & postfix)168 format(
169     const SinglePassRange& rng,
170     const Sep& sep,
171     const Prefix& prefix,
172     const Postfix& postfix
173 )
174 {
175     typedef typename boost::range_iterator<const SinglePassRange>::type
176                 iterator_t;
177 
178     typedef boost::range_detail::formatted_range<
179                 iterator_t, Sep, Prefix, Postfix>       result_t;
180 
181     typedef boost::range_detail::formatted_holder<Sep, Prefix, Postfix>
182                 holder_t;
183 
184     return result_t(boost::begin(rng), boost::end(rng),
185                     holder_t(sep, prefix, postfix));
186 }
187 
188 template<typename SinglePassRange, typename Sep, typename Prefix>
189 inline boost::range_detail::formatted_range<
190     typename boost::range_iterator<const SinglePassRange>::type,
191     Sep, Prefix, char
192 >
format(const SinglePassRange & rng,const Sep & sep,const Prefix & prefix)193 format(
194     const SinglePassRange& rng,
195     const Sep& sep,
196     const Prefix& prefix)
197 {
198     return adaptors::format<SinglePassRange, Sep, Prefix, char>(rng, sep, prefix, '}');
199 }
200 
201 template<typename SinglePassRange, typename Sep>
202 inline boost::range_detail::formatted_range<
203     typename boost::range_iterator<const SinglePassRange>::type,
204     Sep, char, char
205 >
format(const SinglePassRange & rng,const Sep & sep)206 format(const SinglePassRange& rng, const Sep& sep)
207 {
208     return adaptors::format<SinglePassRange, Sep, char, char>(rng, sep, '{', '}');
209 }
210 
211 template<typename SinglePassRange>
212 inline boost::range_detail::formatted_range<
213     typename boost::range_iterator<const SinglePassRange>::type,
214     char, char, char
215 >
format(const SinglePassRange & rng)216 format(const SinglePassRange& rng)
217 {
218     return adaptors::format<SinglePassRange, char, char, char>(rng, ',', '{', '}');
219 }
220 
221     } // namespace adaptors
222 
223     namespace range
224     {
225         using boost::range_detail::formatted_range;
226     } // namespace range
227 } // namespace boost
228 
229 #endif // include guard
230