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> basic_format(const Ch * s)28 basic_format<Ch, Tr, Alloc>:: basic_format(const Ch* s) 29 : style_(0), cur_arg_(0), num_args_(0), dumped_(false), 30 exceptions_(io::all_error_bits) 31 { 32 if( s) 33 parse( s ); 34 } 35 36 #if !defined(BOOST_NO_STD_LOCALE) 37 template< class Ch, class Tr, class Alloc> basic_format(const Ch * s,const std::locale & loc)38 basic_format<Ch, Tr, Alloc>:: basic_format(const Ch* s, const std::locale & loc) 39 : style_(0), cur_arg_(0), num_args_(0), dumped_(false), 40 exceptions_(io::all_error_bits), loc_(loc) 41 { 42 if(s) parse( s ); 43 } 44 45 template< class Ch, class Tr, class Alloc> basic_format(const string_type & s,const std::locale & loc)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 exceptions_(io::all_error_bits), loc_(loc) 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>:: getloc() const55 getloc() const { 56 return loc_ ? loc_.get() : io::detail::locale_t(); 57 } 58 59 template< class Ch, class Tr, class Alloc> basic_format(const string_type & s)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 basic_format(const basic_format & x)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_(x.dumped_), 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>:: operator =(const basic_format & x)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>:: swap(basic_format & x)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> exceptions() const98 unsigned char basic_format<Ch,Tr, Alloc>:: exceptions() const { 99 return exceptions_; 100 } 101 102 template< class Ch, class Tr, class Alloc> exceptions(unsigned char newexcept)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>:: make_or_reuse_data(std::size_t nbitems)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 prefix_.resize(0); 127 } 128 129 template< class Ch, class Tr, class Alloc> 130 basic_format<Ch,Tr, Alloc>& basic_format<Ch,Tr, Alloc>:: clear()131 clear () { 132 // empty the string buffers (except bound arguments) 133 // and make the format object ready for formatting a new set of arguments 134 135 BOOST_ASSERT( bound_.size()==0 || num_args_ == static_cast<int>(bound_.size()) ); 136 137 for(unsigned long i=0; i<items_.size(); ++i) { 138 // clear converted strings only if the corresponding argument is not bound : 139 if( bound_.size()==0 || items_[i].argN_<0 || !bound_[ items_[i].argN_ ] ) 140 items_[i].res_.resize(0); 141 } 142 cur_arg_=0; dumped_=false; 143 // maybe first arg is bound: 144 if(bound_.size() != 0) { 145 for(; cur_arg_ < num_args_ && bound_[cur_arg_]; ++cur_arg_) 146 {} 147 } 148 return *this; 149 } 150 151 template< class Ch, class Tr, class Alloc> 152 basic_format<Ch,Tr, Alloc>& basic_format<Ch,Tr, Alloc>:: clear_binds()153 clear_binds () { 154 // remove all binds, then clear() 155 bound_.resize(0); 156 clear(); 157 return *this; 158 } 159 160 template< class Ch, class Tr, class Alloc> 161 basic_format<Ch,Tr, Alloc>& basic_format<Ch,Tr, Alloc>:: clear_bind(int argN)162 clear_bind (int argN) { 163 // remove the bind of ONE argument then clear() 164 if(argN<1 || argN > num_args_ || bound_.size()==0 || !bound_[argN-1] ) { 165 if( exceptions() & io::out_of_range_bit) 166 boost::throw_exception(io::out_of_range(argN, 1, num_args_+1 ) ); 167 else return *this; 168 } 169 bound_[argN-1]=false; 170 clear(); 171 return *this; 172 } 173 174 template< class Ch, class Tr, class Alloc> 175 int basic_format<Ch,Tr, Alloc>:: bound_args() const176 bound_args() const { 177 if(bound_.size()==0) 178 return 0; 179 int n=0; 180 for(int i=0; i<num_args_ ; ++i) 181 if(bound_[i]) 182 ++n; 183 return n; 184 } 185 186 template< class Ch, class Tr, class Alloc> 187 int basic_format<Ch,Tr, Alloc>:: fed_args() const188 fed_args() const { 189 if(bound_.size()==0) 190 return cur_arg_; 191 int n=0; 192 for(int i=0; i<cur_arg_ ; ++i) 193 if(!bound_[i]) 194 ++n; 195 return n; 196 } 197 198 template< class Ch, class Tr, class Alloc> 199 int basic_format<Ch,Tr, Alloc>:: cur_arg() const200 cur_arg() const { 201 return cur_arg_+1; } 202 203 template< class Ch, class Tr, class Alloc> 204 int basic_format<Ch,Tr, Alloc>:: remaining_args() const205 remaining_args() const { 206 if(bound_.size()==0) 207 return num_args_-cur_arg_; 208 int n=0; 209 for(int i=cur_arg_; i<num_args_ ; ++i) 210 if(!bound_[i]) 211 ++n; 212 return n; 213 } 214 215 template< class Ch, class Tr, class Alloc> 216 typename basic_format<Ch, Tr, Alloc>::string_type 217 basic_format<Ch,Tr, Alloc>:: str() const218 str () const { 219 if(items_.size()==0) 220 return prefix_; 221 if( cur_arg_ < num_args_) 222 if( exceptions() & io::too_few_args_bit ) 223 // not enough variables supplied 224 boost::throw_exception(io::too_few_args(cur_arg_, num_args_)); 225 226 unsigned long i; 227 string_type res; 228 res.reserve(size()); 229 res += prefix_; 230 for(i=0; i < items_.size(); ++i) { 231 const format_item_t& item = items_[i]; 232 res += item.res_; 233 if( item.argN_ == format_item_t::argN_tabulation) { 234 BOOST_ASSERT( item.pad_scheme_ & format_item_t::tabulation); 235 if( static_cast<size_type>(item.fmtstate_.width_) > res.size() ) 236 res.append( static_cast<size_type>(item.fmtstate_.width_) - res.size(), 237 item.fmtstate_.fill_ ); 238 } 239 res += item.appendix_; 240 } 241 dumped_=true; 242 return res; 243 } 244 template< class Ch, class Tr, class Alloc> 245 typename std::basic_string<Ch, Tr, Alloc>::size_type basic_format<Ch,Tr, Alloc>:: size() const246 size () const { 247 #ifdef BOOST_MSVC 248 // If std::min<unsigned> or std::max<unsigned> are already instantiated 249 // at this point then we get a blizzard of warning messages when we call 250 // those templates with std::size_t as arguments. Weird and very annoyning... 251 #pragma warning(push) 252 #pragma warning(disable:4267) 253 #endif 254 BOOST_USING_STD_MAX(); 255 size_type sz = prefix_.size(); 256 unsigned long i; 257 for(i=0; i < items_.size(); ++i) { 258 const format_item_t& item = items_[i]; 259 sz += item.res_.size(); 260 if( item.argN_ == format_item_t::argN_tabulation) 261 sz = max BOOST_PREVENT_MACRO_SUBSTITUTION (sz, 262 static_cast<size_type>(item.fmtstate_.width_) ); 263 sz += item.appendix_.size(); 264 } 265 return sz; 266 #ifdef BOOST_MSVC 267 #pragma warning(pop) 268 #endif 269 } 270 271 namespace io { 272 namespace detail { 273 274 template<class Ch, class Tr, class Alloc, class T> 275 basic_format<Ch, Tr, Alloc>& bind_arg_body(basic_format<Ch,Tr,Alloc> & self,int argN,const T & val)276 bind_arg_body (basic_format<Ch, Tr, Alloc>& self, int argN, const T& val) { 277 // bind one argument to a fixed value 278 // this is persistent over clear() calls, thus also over str() and << 279 if(self.dumped_) 280 self.clear(); // needed because we will modify cur_arg_ 281 if(argN<1 || argN > self.num_args_) { 282 if( self.exceptions() & io::out_of_range_bit ) 283 boost::throw_exception(io::out_of_range(argN, 1, self.num_args_+1 ) ); 284 else return self; 285 } 286 if(self.bound_.size()==0) 287 self.bound_.assign(self.num_args_,false); 288 else 289 BOOST_ASSERT( self.num_args_ == static_cast<signed int>(self.bound_.size()) ); 290 int o_cur_arg = self.cur_arg_; 291 self.cur_arg_ = argN-1; // arrays begin at 0 292 293 self.bound_[self.cur_arg_]=false; // if already set, we unset and re-sets.. 294 self.operator%(val); // put val at the right place, because cur_arg is set 295 296 297 // Now re-position cur_arg before leaving : 298 self.cur_arg_ = o_cur_arg; 299 self.bound_[argN-1]=true; 300 if(self.cur_arg_ == argN-1 ) { 301 // hum, now this arg is bound, so move to next free arg 302 while(self.cur_arg_ < self.num_args_ && self.bound_[self.cur_arg_]) 303 ++self.cur_arg_; 304 } 305 // In any case, we either have all args, or are on an unbound arg : 306 BOOST_ASSERT( self.cur_arg_ >= self.num_args_ || ! self.bound_[self.cur_arg_]); 307 return self; 308 } 309 310 template<class Ch, class Tr, class Alloc, class T> basic_format<Ch, Tr, Alloc>& modify_item_body(basic_format<Ch,Tr,Alloc> & self,int itemN,T manipulator)311 modify_item_body (basic_format<Ch, Tr, Alloc>& self, int itemN, T manipulator) { 312 // applies a manipulator to the format_item describing a given directive. 313 // this is a permanent change, clear or reset won't cancel that. 314 if(itemN<1 || itemN > static_cast<signed int>(self.items_.size() )) { 315 if( self.exceptions() & io::out_of_range_bit ) 316 boost::throw_exception(io::out_of_range(itemN, 1, static_cast<int>(self.items_.size()) )); 317 else return self; 318 } 319 self.items_[itemN-1].fmtstate_. template apply_manip<T> ( manipulator ); 320 return self; 321 } 322 323 } // namespace detail 324 } // namespace io 325 } // namespace boost 326 327 328 329 #endif // BOOST_FORMAT_IMPLEMENTATION_HPP 330