Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/boost/format/feed_args.hpp @ 29

Last change on this file since 29 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

File size: 10.9 KB
Line 
1// ----------------------------------------------------------------------------
2//  feed_args.hpp :  functions for processing each argument
3//                      (feed, feed_manip, and distribute)
4// ----------------------------------------------------------------------------
5
6//  Copyright Samuel Krempp 2003. Use, modification, and distribution are
7//  subject to the Boost Software License, Version 1.0. (See accompanying
8//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9
10//  See http://www.boost.org/libs/format for library home page
11
12// ----------------------------------------------------------------------------
13
14#ifndef BOOST_FORMAT_FEED_ARGS_HPP
15#define BOOST_FORMAT_FEED_ARGS_HPP
16
17#include <boost/config.hpp>
18#include <boost/assert.hpp>
19#include <boost/throw_exception.hpp>
20
21#include <boost/format/format_class.hpp>
22#include <boost/format/group.hpp>
23#include <boost/format/detail/msvc_disambiguater.hpp>
24
25namespace boost {
26namespace io {
27namespace detail {
28
29    template<class Ch, class Tr, class Alloc>
30    void mk_str( std::basic_string<Ch,Tr, Alloc> & res, 
31                 const Ch * beg,
32                 typename std::basic_string<Ch,Tr,Alloc>::size_type size,
33                 std::streamsize w, 
34                 const Ch fill_char,
35                 std::ios_base::fmtflags f, 
36                 const Ch prefix_space, // 0 if no space-padding
37                 bool center) 
38    // applies centered/left/right  padding  to the string  [beg, beg+size[
39    // Effects : the result is placed in res.
40    {
41        typedef typename std::basic_string<Ch,Tr,Alloc>::size_type size_type;
42        res.resize(0);
43        if(w<=0 || static_cast<size_type>(w) <=size) {
44            // no need to pad.
45            res.reserve(size + !!prefix_space);
46            if(prefix_space) 
47              res.append(1, prefix_space);
48            if (size)
49              res.append(beg, size);
50        }
51        else { 
52            std::streamsize n=static_cast<std::streamsize>(w-size-!!prefix_space);
53            std::streamsize n_after = 0, n_before = 0; 
54            res.reserve(w); // allocate once for the 2 inserts
55            if(center) 
56                n_after = n/2, n_before = n - n_after; 
57            else 
58                if(f & std::ios_base::left)
59                    n_after = n;
60                else
61                    n_before = n;
62            // now make the res string :
63            if(n_before) res.append(n_before, fill_char);
64            if(prefix_space) 
65              res.append(1, prefix_space);
66            if (size) 
67              res.append(beg, size);
68            if(n_after) res.append(n_after, fill_char);
69        }
70    } // -mk_str(..)
71
72
73#if BOOST_WORKAROUND( BOOST_MSVC, <= 1300) || \
74    BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(60590042))
75// MSVC needs to be tricked to disambiguate this simple overload..
76// the trick is in "boost/format/msvc_disambiguater.hpp"
77 
78    template< class Ch, class Tr, class T> inline
79    void put_head (BOOST_IO_STD basic_ostream<Ch, Tr> & os, const T& x ) {
80        disambiguater<Ch, Tr, T>::put_head(os, x, 1L);
81    }
82    template< class Ch, class Tr, class T> inline
83    void put_last (BOOST_IO_STD basic_ostream<Ch, Tr> & os, const T& x ) {
84        disambiguater<Ch, Tr, T>::put_last(os, x, 1L);
85    }
86
87#else 
88
89    template< class Ch, class Tr, class T> inline
90    void put_head (BOOST_IO_STD basic_ostream<Ch, Tr> &, const T& ) {
91    }
92
93    template< class Ch, class Tr, class T> inline
94    void put_head( BOOST_IO_STD basic_ostream<Ch, Tr> & os, const group1<T>& x ) {
95        os << group_head(x.a1_); // send the first N-1 items, not the last
96    }
97
98    template< class Ch, class Tr, class T> inline
99    void put_last( BOOST_IO_STD basic_ostream<Ch, Tr> & os, const T& x ) {
100        os << x ;
101    }
102
103    template< class Ch, class Tr, class T> inline
104    void put_last( BOOST_IO_STD basic_ostream<Ch, Tr> & os, const group1<T>& x ) {
105        os << group_last(x.a1_); // this selects the last element
106    }
107
108#ifndef BOOST_NO_OVERLOAD_FOR_NON_CONST
109    template< class Ch, class Tr, class T> inline
110    void put_head( BOOST_IO_STD basic_ostream<Ch, Tr> &, T& ) {
111    }
112
113    template< class Ch, class Tr, class T> inline
114    void put_last( BOOST_IO_STD basic_ostream<Ch, Tr> & os, T& x) {
115        os << x ;
116    }
117#endif
118#endif  // -msvc workaround
119
120
121    template< class Ch, class Tr, class Alloc, class T> 
122    void put( T x, 
123              const format_item<Ch, Tr, Alloc>& specs, 
124              typename basic_format<Ch, Tr, Alloc>::string_type& res, 
125              typename basic_format<Ch, Tr, Alloc>::internal_streambuf_t & buf,
126              io::detail::locale_t *loc_p = NULL)
127    {
128        // does the actual conversion of x, with given params, into a string
129        // using the supplied stringbuf.
130
131        typedef typename basic_format<Ch, Tr, Alloc>::string_type   string_type;
132        typedef typename basic_format<Ch, Tr, Alloc>::format_item_t format_item_t;
133        typedef typename string_type::size_type size_type;
134
135        basic_oaltstringstream<Ch, Tr, Alloc>  oss( &buf);
136        specs.fmtstate_.apply_on(oss, loc_p);
137
138        // the stream format state can be modified by manipulators in the argument :
139        put_head( oss, x );
140        // in case x is a group, apply the manip part of it,
141        // in order to find width
142
143        const std::ios_base::fmtflags fl=oss.flags();
144        const bool internal = (fl & std::ios_base::internal) != 0;
145        const std::streamsize w = oss.width();
146        const bool two_stepped_padding= internal && (w!=0);
147     
148        res.resize(0);
149        if(! two_stepped_padding) {
150            if(w>0) // handle padding via mk_str, not natively in stream
151                oss.width(0);
152            put_last( oss, x);
153            const Ch * res_beg = buf.pbase();
154            Ch prefix_space = 0;
155            if(specs.pad_scheme_ & format_item_t::spacepad)
156                if(buf.pcount()== 0 || 
157                   (res_beg[0] !=oss.widen('+') && res_beg[0] !=oss.widen('-')  ))
158                    prefix_space = oss.widen(' ');
159            size_type res_size = (std::min)(
160                static_cast<size_type>(specs.truncate_ - !!prefix_space), 
161                buf.pcount() );
162            mk_str(res, res_beg, res_size, w, oss.fill(), fl, 
163                   prefix_space, (specs.pad_scheme_ & format_item_t::centered) !=0 );
164        }
165        else  { // 2-stepped padding
166            // internal can be implied by zeropad, or user-set.
167            // left, right, and centered alignment overrule internal,
168            // but spacepad or truncate might be mixed with internal (using manipulator)
169            put_last( oss, x); // may pad
170            const Ch * res_beg = buf.pbase();
171            size_type res_size = buf.pcount();
172            bool prefix_space=false;
173            if(specs.pad_scheme_ & format_item_t::spacepad)
174                if(buf.pcount()== 0 || 
175                   (res_beg[0] !=oss.widen('+') && res_beg[0] !=oss.widen('-')  ))
176                    prefix_space = true;
177            if(res_size == static_cast<size_type>(w) && w<=specs.truncate_ && !prefix_space) {
178                // okay, only one thing was printed and padded, so res is fine
179                res.assign(res_beg, res_size);
180            }
181            else { //   length w exceeded
182                // either it was multi-output with first output padding up all width..
183                // either it was one big arg and we are fine.
184                // Note that res_size<w is possible  (in case of bad user-defined formatting)
185                res.assign(res_beg, res_size);
186                res_beg=NULL;  // invalidate pointers.
187               
188                // make a new stream, to start re-formatting from scratch :
189                buf.clear_buffer();
190                basic_oaltstringstream<Ch, Tr, Alloc>  oss2( &buf);
191                specs.fmtstate_.apply_on(oss2, loc_p);
192                put_head( oss2, x );
193
194                oss2.width(0);
195                if(prefix_space)
196                    oss2 << ' ';
197                put_last(oss2, x );
198                if(buf.pcount()==0 && specs.pad_scheme_ & format_item_t::spacepad) {
199                    prefix_space =true;
200                    oss2 << ' ';
201                }
202                // we now have the minimal-length output
203                const Ch * tmp_beg = buf.pbase();
204                size_type tmp_size = (std::min)(static_cast<size_type>(specs.truncate_),
205                                                buf.pcount() );
206                                                   
207               
208                if(static_cast<size_type>(w) <= tmp_size) { 
209                    // minimal length is already >= w, so no padding (cool!)
210                        res.assign(tmp_beg, tmp_size);
211                }
212                else { // hum..  we need to pad (multi_output, or spacepad present)
213                    //find where we should pad
214                    size_type sz = (std::min)(res_size+prefix_space, tmp_size);
215                    size_type i = prefix_space;
216                    for(; i<sz && tmp_beg[i] == res[i-prefix_space]; ++i) {}
217                    if(i>=tmp_size) i=prefix_space;
218                    res.assign(tmp_beg, i);
219                                        std::streamsize d = w - static_cast<std::streamsize>(tmp_size);
220                                        BOOST_ASSERT(d>0);
221                    res.append(static_cast<size_type>( d ), oss2.fill());
222                    res.append(tmp_beg+i, tmp_size-i);
223                    BOOST_ASSERT(i+(tmp_size-i)+(std::max)(d,(std::streamsize)0) 
224                                 == static_cast<size_type>(w));
225                    BOOST_ASSERT(res.size() == static_cast<size_type>(w));
226                }
227            }
228        }
229        buf.clear_buffer();
230    } // end- put(..)
231
232
233    template< class Ch, class Tr, class Alloc, class T> 
234    void distribute (basic_format<Ch,Tr, Alloc>& self, T x) {
235        // call put(x, ..) on every occurence of the current argument :
236        if(self.cur_arg_ >= self.num_args_)  {
237            if( self.exceptions() & too_many_args_bit )
238                boost::throw_exception(too_many_args(self.cur_arg_, self.num_args_)); 
239            else return;
240        }
241        for(unsigned long i=0; i < self.items_.size(); ++i) {
242            if(self.items_[i].argN_ == self.cur_arg_) {
243                put<Ch, Tr, Alloc, T> (x, self.items_[i], self.items_[i].res_, 
244                                self.buf_, boost::get_pointer(self.loc_) );
245            }
246        }
247    }
248
249    template<class Ch, class Tr, class Alloc, class T> 
250    basic_format<Ch, Tr, Alloc>& 
251    feed (basic_format<Ch,Tr, Alloc>& self, T x) {
252        if(self.dumped_) self.clear();
253        distribute<Ch, Tr, Alloc, T> (self, x);
254        ++self.cur_arg_;
255        if(self.bound_.size() != 0) {
256                while( self.cur_arg_ < self.num_args_ && self.bound_[self.cur_arg_] )
257                    ++self.cur_arg_;
258        }
259        return self;
260    }
261   
262} // namespace detail
263} // namespace io
264} // namespace boost
265
266
267#endif //  BOOST_FORMAT_FEED_ARGS_HPP
Note: See TracBrowser for help on using the repository browser.