Boost logo

Boost :

From: James S. Adelman (j.adelman_at_[hidden])
Date: 2002-02-09 18:11:59


It's manipulator-like; it can work for user-defined types. Currently,
though, it is expensive. It needs a seperator between units, because in
general there is no way to know what is and is not a manipulator. Pretty
much safe. It's only meant to be a proof of concept at present. Any
interest?

// -- test.cpp --

#include "format.hpp"

#include <iostream>
#include <string>
#include <complex>

int main()
{
  int x=6;
  double y=5;
  std::complex<double> y2(5,0.5);
  std::string s="foo";
  std::cout<<format<char>("%1 %0 ")<<y2<<endi<<y<<endi<<x<<endf<<"\n";
  std::cout<<"back to normal"<<std::endl;
  std::cout<<y2<<std::endl;
  std::cout<<format<char>("%1 %2 %0")<<y2<<endi<<y<<endf<<std::endl;
}

// -- end
// -- format.hpp --

#ifndef JSA_FORMAT_H
#define JSA_FORMAT_H

#include <streambuf>
#include <string>
#include <ostream>
#include <vector>
#include <cctype>
#include <iostream>
#include <cstddef>

template <typename Ch,typename Tr=std::char_traits<Ch> >
struct format
{
  format(const std::basic_string<Ch,Tr>&s):
    s_(s)
  {}

  std::basic_string<Ch,Tr> s_;
};

template <typename Ch, typename Tr=std::char_traits<Ch> >
struct formatbuf: std::basic_streambuf<Ch,Tr>
{
  public:

  formatbuf(std::basic_ostream<Ch,Tr>* os,
            std::basic_streambuf<Ch,Tr>* old,
            const format<Ch,Tr>& s):
    os_(os),osb_(old),shutdown_(false),which_(0),howm_(0)
  {
    std::basic_string<Ch,Tr>::const_iterator p=s.s_.begin(),q=s.s_.end(),r=p;
    for(;p!=q;++p)
    {
      std::cerr<<"foo"<<std::endl;
      if(*p!='%') continue;
      out_.push_back(std::basic_string<Ch,Tr>(r,p++));
      std::size_t j=0;
      while((p!=q)&&std::isdigit(*p)) j=j*10+*p++-'0';
      if(j>=order_.size()) order_.resize(j+1);
      if(*p=='$') ++p;
      if(*p!='%') order_[j]=howm_++;
      r=p;
      if(p==q) break;
    }
    out_.push_back(std::basic_string<Ch,Tr>(r,p));
    order_.push_back(howm_);
    std::cerr<<"bar"<<std::endl;
  }

  formatbuf* shutdown()
  {
    std::cerr<<which_<<"()()"<<std::endl;;
    if(!shutdown_){
    for(std::vector<std::basic_string<Ch,Tr> >::iterator
          p=out_.begin(),q=out_.end();
        p!=q; ++p)
    {
      osb_->sputn(p->data(),p->length());
    }
    os_->rdbuf(osb_);
    shutdown_=true;
    }
    return this;
  }

  void next()
  {
    ++which_;
    if(which_==howm_) {std::cerr<<"^y^";shutdown();}
  }

  protected:

  std::streamsize xsputn(const Ch* p, std::streamsize n)
  {
    out_[order_[which_]].append(p,n);
    return n;
  }

  typename Tr::int_type overflow(typename Tr::int_type c=Tr::eof())
  {
    if(!Tr::eq_int_type(c,Tr::eof()))
    {
      out_[order_[which_]].push_back(c);
      return c;
    }
    return Tr::not_eof(c);
  }

  private:

  std::basic_ostream<Ch,Tr> *os_;
  std::basic_streambuf<Ch,Tr> *osb_;
  std::vector<std::basic_string<Ch,Tr> > out_;
  std::vector<int> order_;
  bool shutdown_;
  int which_,howm_;
};

template <typename Ch,typename Tr>
std::basic_ostream<Ch,Tr>& operator<<(std::basic_ostream<Ch,Tr>&os,
  const format<Ch,Tr>& ft)
{
  os.rdbuf(new formatbuf<Ch,Tr>(&os,os.rdbuf(),ft));
  return os;
}

template <typename Ch,typename Tr>
std::basic_ostream<Ch,Tr>& endi(std::basic_ostream<Ch,Tr>& os)
{
  if(formatbuf<Ch,Tr>* p=dynamic_cast<formatbuf<Ch,Tr>*>(os.rdbuf()))
p->next();
  return os;
}

template <typename Ch,typename Tr>
std::basic_ostream<Ch,Tr>& endf(std::basic_ostream<Ch,Tr>& os)
{
  if(formatbuf<Ch,Tr>* p=dynamic_cast<formatbuf<Ch,Tr>*>(os.rdbuf())) delete
p->shutdown();
  return os;
}

#endif

// -- end

--
James S. Adelman

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk