Chris@16: // ---------------------------------------------------------------------------- Chris@16: // format_implementation.hpp Implementation of the basic_format class Chris@16: // ---------------------------------------------------------------------------- Chris@16: Chris@16: // Copyright Samuel Krempp 2003. Use, modification, and distribution are Chris@16: // subject to the Boost Software License, Version 1.0. (See accompanying Chris@16: // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: // See http://www.boost.org/libs/format for library home page Chris@16: Chris@16: Chris@16: // ---------------------------------------------------------------------------- Chris@16: Chris@16: #ifndef BOOST_FORMAT_IMPLEMENTATION_HPP Chris@16: #define BOOST_FORMAT_IMPLEMENTATION_HPP Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include // std::swap Chris@16: Chris@16: namespace boost { Chris@16: Chris@16: // --- basic_format implementation -----------------------------------------// Chris@16: Chris@16: template< class Ch, class Tr, class Alloc> Chris@16: basic_format:: basic_format(const Ch* s) Chris@16: : style_(0), cur_arg_(0), num_args_(0), dumped_(false), Chris@16: exceptions_(io::all_error_bits) Chris@16: { Chris@16: if( s) Chris@16: parse( s ); Chris@16: } Chris@16: Chris@16: #if !defined(BOOST_NO_STD_LOCALE) Chris@16: template< class Ch, class Tr, class Alloc> Chris@16: basic_format:: basic_format(const Ch* s, const std::locale & loc) Chris@16: : style_(0), cur_arg_(0), num_args_(0), dumped_(false), Chris@16: exceptions_(io::all_error_bits), loc_(loc) Chris@16: { Chris@16: if(s) parse( s ); Chris@16: } Chris@16: Chris@16: template< class Ch, class Tr, class Alloc> Chris@16: basic_format:: basic_format(const string_type& s, const std::locale & loc) Chris@16: : style_(0), cur_arg_(0), num_args_(0), dumped_(false), Chris@16: exceptions_(io::all_error_bits), loc_(loc) Chris@16: { Chris@16: parse(s); Chris@16: } Chris@16: #endif // ! BOOST_NO_STD_LOCALE Chris@16: template< class Ch, class Tr, class Alloc> Chris@16: io::detail::locale_t basic_format:: Chris@16: getloc() const { Chris@16: return loc_ ? loc_.get() : io::detail::locale_t(); Chris@16: } Chris@16: Chris@16: template< class Ch, class Tr, class Alloc> Chris@16: basic_format:: basic_format(const string_type& s) Chris@16: : style_(0), cur_arg_(0), num_args_(0), dumped_(false), Chris@16: exceptions_(io::all_error_bits) Chris@16: { Chris@16: parse(s); Chris@16: } Chris@16: Chris@16: template< class Ch, class Tr, class Alloc> // just don't copy the buf_ member Chris@16: basic_format:: basic_format(const basic_format& x) Chris@16: : items_(x.items_), bound_(x.bound_), style_(x.style_), Chris@16: cur_arg_(x.cur_arg_), num_args_(x.num_args_), dumped_(x.dumped_), Chris@16: prefix_(x.prefix_), exceptions_(x.exceptions_), loc_(x.loc_) Chris@16: { Chris@16: } Chris@16: Chris@16: template< class Ch, class Tr, class Alloc> // just don't copy the buf_ member Chris@16: basic_format& basic_format:: Chris@16: operator= (const basic_format& x) { Chris@16: if(this == &x) Chris@16: return *this; Chris@16: (basic_format(x)).swap(*this); Chris@16: return *this; Chris@16: } Chris@16: template< class Ch, class Tr, class Alloc> Chris@16: void basic_format:: Chris@16: swap (basic_format & x) { Chris@16: std::swap(exceptions_, x.exceptions_); Chris@16: std::swap(style_, x.style_); Chris@16: std::swap(cur_arg_, x.cur_arg_); Chris@16: std::swap(num_args_, x.num_args_); Chris@16: std::swap(dumped_, x.dumped_); Chris@16: Chris@16: items_.swap(x.items_); Chris@16: prefix_.swap(x.prefix_); Chris@16: bound_.swap(x.bound_); Chris@16: } Chris@16: Chris@16: template< class Ch, class Tr, class Alloc> Chris@16: unsigned char basic_format:: exceptions() const { Chris@16: return exceptions_; Chris@16: } Chris@16: Chris@16: template< class Ch, class Tr, class Alloc> Chris@16: unsigned char basic_format:: exceptions(unsigned char newexcept) { Chris@16: unsigned char swp = exceptions_; Chris@16: exceptions_ = newexcept; Chris@16: return swp; Chris@16: } Chris@16: Chris@16: template Chris@16: void basic_format:: Chris@16: make_or_reuse_data (std::size_t nbitems) { Chris@16: #if !defined(BOOST_NO_STD_LOCALE) Chris@16: Ch fill = ( BOOST_USE_FACET(std::ctype, getloc()) ). widen(' '); Chris@16: #else Chris@16: Ch fill = ' '; Chris@16: #endif Chris@16: if(items_.size() == 0) Chris@16: items_.assign( nbitems, format_item_t(fill) ); Chris@16: else { Chris@16: if(nbitems>items_.size()) Chris@16: items_.resize(nbitems, format_item_t(fill)); Chris@16: bound_.resize(0); Chris@16: for(std::size_t i=0; i < nbitems; ++i) Chris@16: items_[i].reset(fill); // strings are resized, instead of reallocated Chris@16: } Chris@16: prefix_.resize(0); Chris@16: } Chris@16: Chris@16: template< class Ch, class Tr, class Alloc> Chris@16: basic_format& basic_format:: Chris@16: clear () { Chris@16: // empty the string buffers (except bound arguments) Chris@16: // and make the format object ready for formatting a new set of arguments Chris@16: Chris@16: BOOST_ASSERT( bound_.size()==0 || num_args_ == static_cast(bound_.size()) ); Chris@16: Chris@16: for(unsigned long i=0; i Chris@16: basic_format& basic_format:: Chris@16: clear_binds () { Chris@16: // remove all binds, then clear() Chris@16: bound_.resize(0); Chris@16: clear(); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template< class Ch, class Tr, class Alloc> Chris@16: basic_format& basic_format:: Chris@16: clear_bind (int argN) { Chris@16: // remove the bind of ONE argument then clear() Chris@16: if(argN<1 || argN > num_args_ || bound_.size()==0 || !bound_[argN-1] ) { Chris@16: if( exceptions() & io::out_of_range_bit) Chris@16: boost::throw_exception(io::out_of_range(argN, 1, num_args_+1 ) ); Chris@16: else return *this; Chris@16: } Chris@16: bound_[argN-1]=false; Chris@16: clear(); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: template< class Ch, class Tr, class Alloc> Chris@16: int basic_format:: Chris@16: bound_args() const { Chris@16: if(bound_.size()==0) Chris@16: return 0; Chris@16: int n=0; Chris@16: for(int i=0; i Chris@16: int basic_format:: Chris@16: fed_args() const { Chris@16: if(bound_.size()==0) Chris@16: return cur_arg_; Chris@16: int n=0; Chris@16: for(int i=0; i Chris@16: int basic_format:: Chris@16: cur_arg() const { Chris@16: return cur_arg_+1; } Chris@16: Chris@16: template< class Ch, class Tr, class Alloc> Chris@16: int basic_format:: Chris@16: remaining_args() const { Chris@16: if(bound_.size()==0) Chris@16: return num_args_-cur_arg_; Chris@16: int n=0; Chris@16: for(int i=cur_arg_; i Chris@16: typename basic_format::string_type Chris@16: basic_format:: Chris@16: str () const { Chris@16: if(items_.size()==0) Chris@16: return prefix_; Chris@16: if( cur_arg_ < num_args_) Chris@16: if( exceptions() & io::too_few_args_bit ) Chris@16: // not enough variables supplied Chris@16: boost::throw_exception(io::too_few_args(cur_arg_, num_args_)); Chris@16: Chris@16: unsigned long i; Chris@16: string_type res; Chris@16: res.reserve(size()); Chris@16: res += prefix_; Chris@16: for(i=0; i < items_.size(); ++i) { Chris@16: const format_item_t& item = items_[i]; Chris@16: res += item.res_; Chris@16: if( item.argN_ == format_item_t::argN_tabulation) { Chris@16: BOOST_ASSERT( item.pad_scheme_ & format_item_t::tabulation); Chris@16: if( static_cast(item.fmtstate_.width_) > res.size() ) Chris@16: res.append( static_cast(item.fmtstate_.width_) - res.size(), Chris@16: item.fmtstate_.fill_ ); Chris@16: } Chris@16: res += item.appendix_; Chris@16: } Chris@16: dumped_=true; Chris@16: return res; Chris@16: } Chris@16: template< class Ch, class Tr, class Alloc> Chris@16: typename std::basic_string::size_type basic_format:: Chris@16: size () const { Chris@16: #ifdef BOOST_MSVC Chris@16: // If std::min or std::max are already instantiated Chris@16: // at this point then we get a blizzard of warning messages when we call Chris@16: // those templates with std::size_t as arguments. Weird and very annoyning... Chris@16: #pragma warning(push) Chris@16: #pragma warning(disable:4267) Chris@16: #endif Chris@16: BOOST_USING_STD_MAX(); Chris@16: size_type sz = prefix_.size(); Chris@16: unsigned long i; Chris@16: for(i=0; i < items_.size(); ++i) { Chris@16: const format_item_t& item = items_[i]; Chris@16: sz += item.res_.size(); Chris@16: if( item.argN_ == format_item_t::argN_tabulation) Chris@16: sz = max BOOST_PREVENT_MACRO_SUBSTITUTION (sz, Chris@16: static_cast(item.fmtstate_.width_) ); Chris@16: sz += item.appendix_.size(); Chris@16: } Chris@16: return sz; Chris@16: #ifdef BOOST_MSVC Chris@16: #pragma warning(pop) Chris@16: #endif Chris@16: } Chris@16: Chris@16: namespace io { Chris@16: namespace detail { Chris@16: Chris@16: template Chris@16: basic_format& Chris@16: bind_arg_body (basic_format& self, int argN, const T& val) { Chris@16: // bind one argument to a fixed value Chris@16: // this is persistent over clear() calls, thus also over str() and << Chris@16: if(self.dumped_) Chris@16: self.clear(); // needed because we will modify cur_arg_ Chris@16: if(argN<1 || argN > self.num_args_) { Chris@16: if( self.exceptions() & io::out_of_range_bit ) Chris@16: boost::throw_exception(io::out_of_range(argN, 1, self.num_args_+1 ) ); Chris@16: else return self; Chris@16: } Chris@16: if(self.bound_.size()==0) Chris@16: self.bound_.assign(self.num_args_,false); Chris@16: else Chris@16: BOOST_ASSERT( self.num_args_ == static_cast(self.bound_.size()) ); Chris@16: int o_cur_arg = self.cur_arg_; Chris@16: self.cur_arg_ = argN-1; // arrays begin at 0 Chris@16: Chris@16: self.bound_[self.cur_arg_]=false; // if already set, we unset and re-sets.. Chris@16: self.operator%(val); // put val at the right place, because cur_arg is set Chris@16: Chris@16: Chris@16: // Now re-position cur_arg before leaving : Chris@16: self.cur_arg_ = o_cur_arg; Chris@16: self.bound_[argN-1]=true; Chris@16: if(self.cur_arg_ == argN-1 ) { Chris@16: // hum, now this arg is bound, so move to next free arg Chris@16: while(self.cur_arg_ < self.num_args_ && self.bound_[self.cur_arg_]) Chris@16: ++self.cur_arg_; Chris@16: } Chris@16: // In any case, we either have all args, or are on an unbound arg : Chris@16: BOOST_ASSERT( self.cur_arg_ >= self.num_args_ || ! self.bound_[self.cur_arg_]); Chris@16: return self; Chris@16: } Chris@16: Chris@16: template basic_format& Chris@16: modify_item_body (basic_format& self, int itemN, T manipulator) { Chris@16: // applies a manipulator to the format_item describing a given directive. Chris@16: // this is a permanent change, clear or reset won't cancel that. Chris@16: if(itemN<1 || itemN > static_cast(self.items_.size() )) { Chris@16: if( self.exceptions() & io::out_of_range_bit ) Chris@16: boost::throw_exception(io::out_of_range(itemN, 1, static_cast(self.items_.size()) )); Chris@16: else return self; Chris@16: } Chris@16: self.items_[itemN-1].fmtstate_. template apply_manip ( manipulator ); Chris@16: return self; Chris@16: } Chris@16: Chris@16: } // namespace detail Chris@16: } // namespace io Chris@16: } // namespace boost Chris@16: Chris@16: Chris@16: Chris@16: #endif // BOOST_FORMAT_IMPLEMENTATION_HPP