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 * str)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> basic_format(const Ch * str,const std::locale & loc)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> 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 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>:: 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_(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>:: 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 } 127 128 template< class Ch, class Tr, class Alloc> 129 basic_format<Ch,Tr, Alloc>& basic_format<Ch,Tr, Alloc>:: clear()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 || !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>:: clear_binds()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>:: clear_bind(int argN)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>:: str() const176 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>:: size() const204 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>& bind_arg_body(basic_format<Ch,Tr,Alloc> & self,int argN,const T & val)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>& modify_item_body(basic_format<Ch,Tr,Alloc> & self,int itemN,T manipulator)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 278