| 1 | // ---------------------------------------------------------------------------- | 
|---|
| 2 | // format_implementation.hpp  Implementation of the basic_format class | 
|---|
| 3 | // ---------------------------------------------------------------------------- | 
|---|
| 4 |  | 
|---|
| 5 | //  Copyright Samuel Krempp 2003. Use, modification, and distribution are | 
|---|
| 6 | //  subject to the Boost Software License, Version 1.0. (See accompanying | 
|---|
| 7 | //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | 
|---|
| 8 |  | 
|---|
| 9 | //  See http://www.boost.org/libs/format for library home page | 
|---|
| 10 |  | 
|---|
| 11 |  | 
|---|
| 12 | // ---------------------------------------------------------------------------- | 
|---|
| 13 |  | 
|---|
| 14 | #ifndef BOOST_FORMAT_IMPLEMENTATION_HPP | 
|---|
| 15 | #define BOOST_FORMAT_IMPLEMENTATION_HPP | 
|---|
| 16 |  | 
|---|
| 17 | #include <boost/config.hpp> | 
|---|
| 18 | #include <boost/throw_exception.hpp> | 
|---|
| 19 | #include <boost/assert.hpp> | 
|---|
| 20 | #include <boost/format/format_class.hpp> | 
|---|
| 21 | #include <algorithm> // std::swap | 
|---|
| 22 |  | 
|---|
| 23 | namespace boost { | 
|---|
| 24 |  | 
|---|
| 25 | // ---  basic_format implementation -----------------------------------------// | 
|---|
| 26 |  | 
|---|
| 27 |     template< class Ch, class Tr, class Alloc> | 
|---|
| 28 |     basic_format<Ch, Tr, Alloc>:: basic_format(const Ch* str) | 
|---|
| 29 |         : style_(0), cur_arg_(0), num_args_(0), dumped_(false), | 
|---|
| 30 |           exceptions_(io::all_error_bits) | 
|---|
| 31 |     { | 
|---|
| 32 |         if( str) | 
|---|
| 33 |             parse( str ); | 
|---|
| 34 |     } | 
|---|
| 35 |  | 
|---|
| 36 | #if !defined(BOOST_NO_STD_LOCALE) | 
|---|
| 37 |     template< class Ch, class Tr, class Alloc> | 
|---|
| 38 |     basic_format<Ch, Tr, Alloc>:: basic_format(const Ch* str, const std::locale & loc) | 
|---|
| 39 |         : style_(0), cur_arg_(0), num_args_(0), dumped_(false), | 
|---|
| 40 |           loc_(loc), exceptions_(io::all_error_bits) | 
|---|
| 41 |     { | 
|---|
| 42 |         if(str) parse( str ); | 
|---|
| 43 |     } | 
|---|
| 44 |  | 
|---|
| 45 |     template< class Ch, class Tr, class Alloc> | 
|---|
| 46 |     basic_format<Ch, Tr, Alloc>:: basic_format(const string_type& s, const std::locale & loc) | 
|---|
| 47 |         : style_(0), cur_arg_(0), num_args_(0), dumped_(false), | 
|---|
| 48 |           loc_(loc), exceptions_(io::all_error_bits) | 
|---|
| 49 |     { | 
|---|
| 50 |         parse(s);   | 
|---|
| 51 |     } | 
|---|
| 52 | #endif // ! BOOST_NO_STD_LOCALE | 
|---|
| 53 |     template< class Ch, class Tr, class Alloc> | 
|---|
| 54 |     io::detail::locale_t basic_format<Ch, Tr, Alloc>::  | 
|---|
| 55 |     getloc() const { | 
|---|
| 56 |         return loc_ ? loc_.get() : io::detail::locale_t();  | 
|---|
| 57 |     } | 
|---|
| 58 |  | 
|---|
| 59 |     template< class Ch, class Tr, class Alloc> | 
|---|
| 60 |     basic_format<Ch, Tr, Alloc>:: basic_format(const string_type& s) | 
|---|
| 61 |         : style_(0), cur_arg_(0), num_args_(0), dumped_(false), | 
|---|
| 62 |           exceptions_(io::all_error_bits) | 
|---|
| 63 |     { | 
|---|
| 64 |         parse(s);   | 
|---|
| 65 |     } | 
|---|
| 66 |  | 
|---|
| 67 |     template< class Ch, class Tr, class Alloc> // just don't copy the buf_ member | 
|---|
| 68 |     basic_format<Ch, Tr, Alloc>:: basic_format(const basic_format& x) | 
|---|
| 69 |         : items_(x.items_), bound_(x.bound_), style_(x.style_), | 
|---|
| 70 |           cur_arg_(x.cur_arg_), num_args_(x.num_args_), dumped_(false), | 
|---|
| 71 |           prefix_(x.prefix_), exceptions_(x.exceptions_), loc_(x.loc_) | 
|---|
| 72 |     { | 
|---|
| 73 |     } | 
|---|
| 74 |  | 
|---|
| 75 |     template< class Ch, class Tr, class Alloc>  // just don't copy the buf_ member | 
|---|
| 76 |     basic_format<Ch, Tr, Alloc>& basic_format<Ch, Tr, Alloc>::  | 
|---|
| 77 |     operator= (const basic_format& x) { | 
|---|
| 78 |         if(this == &x) | 
|---|
| 79 |             return *this; | 
|---|
| 80 |         (basic_format<Ch, Tr, Alloc>(x)).swap(*this); | 
|---|
| 81 |         return *this; | 
|---|
| 82 |     } | 
|---|
| 83 |     template< class Ch, class Tr, class Alloc> | 
|---|
| 84 |     void  basic_format<Ch, Tr, Alloc>::  | 
|---|
| 85 |     swap (basic_format & x) { | 
|---|
| 86 |         std::swap(exceptions_, x.exceptions_); | 
|---|
| 87 |         std::swap(style_, x.style_);  | 
|---|
| 88 |         std::swap(cur_arg_, x.cur_arg_);  | 
|---|
| 89 |         std::swap(num_args_, x.num_args_); | 
|---|
| 90 |         std::swap(dumped_, x.dumped_); | 
|---|
| 91 |  | 
|---|
| 92 |         items_.swap(x.items_); | 
|---|
| 93 |         prefix_.swap(x.prefix_); | 
|---|
| 94 |         bound_.swap(x.bound_); | 
|---|
| 95 |     } | 
|---|
| 96 |  | 
|---|
| 97 |     template< class Ch, class Tr, class Alloc> | 
|---|
| 98 |     unsigned char basic_format<Ch,Tr, Alloc>:: exceptions() const { | 
|---|
| 99 |         return exceptions_;  | 
|---|
| 100 |     } | 
|---|
| 101 |  | 
|---|
| 102 |     template< class Ch, class Tr, class Alloc> | 
|---|
| 103 |     unsigned char basic_format<Ch,Tr, Alloc>:: exceptions(unsigned char newexcept) {  | 
|---|
| 104 |         unsigned char swp = exceptions_;  | 
|---|
| 105 |         exceptions_ = newexcept;  | 
|---|
| 106 |         return swp;  | 
|---|
| 107 |     } | 
|---|
| 108 |  | 
|---|
| 109 |     template<class Ch, class Tr, class Alloc> | 
|---|
| 110 |     void basic_format<Ch, Tr, Alloc>::  | 
|---|
| 111 |     make_or_reuse_data (std::size_t nbitems) { | 
|---|
| 112 | #if !defined(BOOST_NO_STD_LOCALE) | 
|---|
| 113 |         Ch fill = ( BOOST_USE_FACET(std::ctype<Ch>, getloc()) ). widen(' '); | 
|---|
| 114 | #else | 
|---|
| 115 |         Ch fill = ' '; | 
|---|
| 116 | #endif | 
|---|
| 117 |         if(items_.size() == 0) | 
|---|
| 118 |             items_.assign( nbitems, format_item_t(fill) ); | 
|---|
| 119 |         else { | 
|---|
| 120 |             if(nbitems>items_.size()) | 
|---|
| 121 |                 items_.resize(nbitems, format_item_t(fill)); | 
|---|
| 122 |             bound_.resize(0); | 
|---|
| 123 |             for(std::size_t i=0; i < nbitems; ++i) | 
|---|
| 124 |                 items_[i].reset(fill); //  strings are resized, instead of reallocated | 
|---|
| 125 |         } | 
|---|
| 126 |     } | 
|---|
| 127 |  | 
|---|
| 128 |     template< class Ch, class Tr, class Alloc> | 
|---|
| 129 |     basic_format<Ch,Tr, Alloc>& basic_format<Ch,Tr, Alloc>::  | 
|---|
| 130 |     clear () { | 
|---|
| 131 |         // empty the string buffers (except bound arguments) | 
|---|
| 132 |         // and make the format object ready for formatting a new set of arguments | 
|---|
| 133 |  | 
|---|
| 134 |         BOOST_ASSERT( bound_.size()==0 || num_args_ == static_cast<int>(bound_.size()) ); | 
|---|
| 135 |  | 
|---|
| 136 |         for(unsigned long i=0; i<items_.size(); ++i) { | 
|---|
| 137 |             // clear converted strings only if the corresponding argument is not  bound : | 
|---|
| 138 |             if( bound_.size()==0 || items_[i].argN_<0 || !bound_[ items_[i].argN_ ] ) | 
|---|
| 139 |                 items_[i].res_.resize(0); | 
|---|
| 140 |         } | 
|---|
| 141 |         cur_arg_=0; dumped_=false; | 
|---|
| 142 |         // maybe first arg is bound: | 
|---|
| 143 |         if(bound_.size() != 0) { | 
|---|
| 144 |             for(; cur_arg_ < num_args_ && bound_[cur_arg_]; ++cur_arg_) | 
|---|
| 145 |                 {} | 
|---|
| 146 |         } | 
|---|
| 147 |         return *this; | 
|---|
| 148 |     } | 
|---|
| 149 |  | 
|---|
| 150 |     template< class Ch, class Tr, class Alloc> | 
|---|
| 151 |     basic_format<Ch,Tr, Alloc>& basic_format<Ch,Tr, Alloc>::  | 
|---|
| 152 |     clear_binds () { | 
|---|
| 153 |         // remove all binds, then clear() | 
|---|
| 154 |         bound_.resize(0); | 
|---|
| 155 |         clear(); | 
|---|
| 156 |         return *this; | 
|---|
| 157 |     } | 
|---|
| 158 |  | 
|---|
| 159 |     template< class Ch, class Tr, class Alloc> | 
|---|
| 160 |     basic_format<Ch,Tr, Alloc>& basic_format<Ch,Tr, Alloc>::  | 
|---|
| 161 |     clear_bind (int argN) { | 
|---|
| 162 |         // remove the bind of ONE argument then clear() | 
|---|
| 163 |         if(argN<1 || argN > num_args_ || bound_.size()==0 || !bound_[argN-1] ) { | 
|---|
| 164 |             if( exceptions() & io::out_of_range_bit) | 
|---|
| 165 |                 boost::throw_exception(io::out_of_range(argN, 1, num_args_+1 ) );  | 
|---|
| 166 |             else return *this; | 
|---|
| 167 |         } | 
|---|
| 168 |         bound_[argN-1]=false; | 
|---|
| 169 |         clear(); | 
|---|
| 170 |         return *this; | 
|---|
| 171 |     } | 
|---|
| 172 |  | 
|---|
| 173 |     template< class Ch, class Tr, class Alloc> | 
|---|
| 174 |     typename basic_format<Ch, Tr, Alloc>::string_type  | 
|---|
| 175 |     basic_format<Ch,Tr, Alloc>::  | 
|---|
| 176 |     str () const { | 
|---|
| 177 |         if(items_.size()==0) | 
|---|
| 178 |             return prefix_; | 
|---|
| 179 |         if( cur_arg_ < num_args_) | 
|---|
| 180 |             if( exceptions() & io::too_few_args_bit ) | 
|---|
| 181 |                 // not enough variables supplied | 
|---|
| 182 |                 boost::throw_exception(io::too_few_args(cur_arg_, num_args_));  | 
|---|
| 183 |  | 
|---|
| 184 |         unsigned long i; | 
|---|
| 185 |         string_type res; | 
|---|
| 186 |         res.reserve(size()); | 
|---|
| 187 |         res += prefix_; | 
|---|
| 188 |         for(i=0; i < items_.size(); ++i) { | 
|---|
| 189 |             const format_item_t& item = items_[i]; | 
|---|
| 190 |             res += item.res_; | 
|---|
| 191 |             if( item.argN_ == format_item_t::argN_tabulation) {  | 
|---|
| 192 |                 BOOST_ASSERT( item.pad_scheme_ & format_item_t::tabulation); | 
|---|
| 193 |                 if( static_cast<size_type>(item.fmtstate_.width_) > res.size() ) | 
|---|
| 194 |                     res.append( static_cast<size_type>(item.fmtstate_.width_) - res.size(), | 
|---|
| 195 |                                         item.fmtstate_.fill_ ); | 
|---|
| 196 |             } | 
|---|
| 197 |             res += item.appendix_; | 
|---|
| 198 |         } | 
|---|
| 199 |         dumped_=true; | 
|---|
| 200 |         return res; | 
|---|
| 201 |     } | 
|---|
| 202 |     template< class Ch, class Tr, class Alloc> | 
|---|
| 203 |     typename std::basic_string<Ch, Tr, Alloc>::size_type  basic_format<Ch,Tr, Alloc>::  | 
|---|
| 204 |     size () const { | 
|---|
| 205 |         BOOST_USING_STD_MAX(); | 
|---|
| 206 |         size_type sz = prefix_.size(); | 
|---|
| 207 |         unsigned long i; | 
|---|
| 208 |         for(i=0; i < items_.size(); ++i) { | 
|---|
| 209 |             const format_item_t& item = items_[i]; | 
|---|
| 210 |             sz += item.res_.size(); | 
|---|
| 211 |             if( item.argN_ == format_item_t::argN_tabulation) | 
|---|
| 212 |                 sz = max BOOST_PREVENT_MACRO_SUBSTITUTION (sz, | 
|---|
| 213 |                                         static_cast<size_type>(item.fmtstate_.width_) ); | 
|---|
| 214 |             sz += item.appendix_.size(); | 
|---|
| 215 |         } | 
|---|
| 216 |         return sz; | 
|---|
| 217 |     } | 
|---|
| 218 |  | 
|---|
| 219 | namespace io { | 
|---|
| 220 | namespace detail { | 
|---|
| 221 |  | 
|---|
| 222 |     template<class Ch, class Tr, class Alloc, class T>  | 
|---|
| 223 |     basic_format<Ch, Tr, Alloc>&   | 
|---|
| 224 |     bind_arg_body (basic_format<Ch, Tr, Alloc>& self, int argN, const T& val) { | 
|---|
| 225 |         // bind one argument to a fixed value | 
|---|
| 226 |         // this is persistent over clear() calls, thus also over str() and << | 
|---|
| 227 |         if(self.dumped_)  | 
|---|
| 228 |             self.clear(); // needed because we will modify cur_arg_ | 
|---|
| 229 |         if(argN<1 || argN > self.num_args_) { | 
|---|
| 230 |             if( self.exceptions() & io::out_of_range_bit ) | 
|---|
| 231 |                 boost::throw_exception(io::out_of_range(argN, 1, self.num_args_+1 ) ); | 
|---|
| 232 |             else return self; | 
|---|
| 233 |         } | 
|---|
| 234 |         if(self.bound_.size()==0)  | 
|---|
| 235 |             self.bound_.assign(self.num_args_,false); | 
|---|
| 236 |         else  | 
|---|
| 237 |             BOOST_ASSERT( self.num_args_ == static_cast<signed int>(self.bound_.size()) ); | 
|---|
| 238 |         int o_cur_arg = self.cur_arg_; | 
|---|
| 239 |         self.cur_arg_ = argN-1; // arrays begin at 0 | 
|---|
| 240 |  | 
|---|
| 241 |         self.bound_[self.cur_arg_]=false; // if already set, we unset and re-sets.. | 
|---|
| 242 |         self.operator%(val); // put val at the right place, because cur_arg is set | 
|---|
| 243 |      | 
|---|
| 244 |  | 
|---|
| 245 |         // Now re-position cur_arg before leaving : | 
|---|
| 246 |         self.cur_arg_ = o_cur_arg;  | 
|---|
| 247 |         self.bound_[argN-1]=true; | 
|---|
| 248 |         if(self.cur_arg_ == argN-1 ) { | 
|---|
| 249 |             // hum, now this arg is bound, so move to next free arg | 
|---|
| 250 |             while(self.cur_arg_ < self.num_args_ && self.bound_[self.cur_arg_])    | 
|---|
| 251 |                 ++self.cur_arg_; | 
|---|
| 252 |         } | 
|---|
| 253 |         // In any case, we either have all args, or are on a non-binded arg : | 
|---|
| 254 |         BOOST_ASSERT( self.cur_arg_ >= self.num_args_ || ! self.bound_[self.cur_arg_]); | 
|---|
| 255 |         return self; | 
|---|
| 256 |     } | 
|---|
| 257 |  | 
|---|
| 258 |     template<class Ch, class Tr, class Alloc, class T> basic_format<Ch, Tr, Alloc>& | 
|---|
| 259 |     modify_item_body (basic_format<Ch, Tr, Alloc>& self, int itemN, T manipulator) { | 
|---|
| 260 |         // applies a manipulator to the format_item describing a given directive. | 
|---|
| 261 |         // this is a permanent change, clear or reset won't cancel that. | 
|---|
| 262 |         if(itemN<1 || itemN > static_cast<signed int>(self.items_.size() )) { | 
|---|
| 263 |             if( self.exceptions() & io::out_of_range_bit )  | 
|---|
| 264 |                 boost::throw_exception(io::out_of_range(itemN, 1, self.items_.size() )); | 
|---|
| 265 |             else return self; | 
|---|
| 266 |         } | 
|---|
| 267 |         self.items_[itemN-1].fmtstate_. template apply_manip<T> ( manipulator ); | 
|---|
| 268 |         return self; | 
|---|
| 269 |     } | 
|---|
| 270 |  | 
|---|
| 271 | } // namespace detail | 
|---|
| 272 | } // namespace io | 
|---|
| 273 | } // namespace boost | 
|---|
| 274 |  | 
|---|
| 275 |  | 
|---|
| 276 |  | 
|---|
| 277 | #endif  // BOOST_FORMAT_IMPLEMENTATION_HPP | 
|---|