Formatの続き
早速つくってみました。
結構思ったとおりできたかも。。
使い方は簡単で
std::cout << Format("$1") % "abc" << std::endl;
のようにすれば$1が文字列のデフォルト書式"%s"に代わります。
std::cout << Format("$1") % 1 << std::endl;
なら"%d"です。
まーこのへんは適当でw
ちなみに"%03d"とかの指定はCustomForm関数をつかって
std::cout << Format("$1") % CustomForm(1,"%03d") << std::endl;
のようにします。
ただCustomForm使うと依然としてCustomForm("abc","%d")みたいなぶっ飛ぶ処理をいれられますので
この辺は注意が必要です(いみねーw
挙句に仕様のとおり$とか%の文字はそのまま送りますので
std::cout << Format("$1%") % 50 << std::endl; std::cout << Format("$1$1") % "です" << std::endl;//「$1です」と表示したい std::cout << Format("$$1です") % 1 % << std::endl;// こっちはOK
%はそのまま内部で呼ばれるsprintfに引っかかってぶっ飛ぶでしょう。
$文字自体は問題なく出力しますが$1のように後に数字がくると文字ではなく引数と解釈されるので「ですです」と出力されます。
$$1とかやっても$$->$という内部処理してないのでだめです。
↑のFormat("$$1です") は[$ $1 です]の$1が数字の1に変換されて
[$1です]に変化したものなので意味が違います。
一つの手としては$と%は最後に渡すくらいしかないでしょうね。
std::cout << Format("$1$2") % 50 %'%' << std::endl; //50% std::cout << Format("$2$1") % "です" %"$1" << std::endl; //$1です
で、手持ちのプロファイラで100回ループの速度チェックしてみました。
かなり遅くなりますね><
まぁ機能としてboostよりかなりしょぼいだけあって
若干速度でてるかなぁ・・・
時間の単位はマイクロセカンドです。1,000,000が1秒ですね。
2,830.8 (boost::format("%1% %2% %3$04d %4% %5%\n") %"abc" %3 %3 %c %ul).str(); 1,770.1 (Format("$1 $2 $3 $4 $5\n") %"abc" %3 %CustomForm(3,"%04d") %c %ul).Value(); 201.0 sprintf(buf,"%s %d %04d %c %d\n","abc",3,3,c,ul); 1,161.6 (boost::format("%1%\n") % "abc").str(); 340.7 (Format("$1\n") %"abc").Value(); 65.4 sprintf(buf,"%s\n","abc");
最後にソースを。
#include#include #include struct Format; template struct CustomFormat { CustomFormat(const T& t,const std::string& f) :ft(t),ff(f){} void Invoke(Format& f) const { f.SetFormat(ff); f % ft; } const T& ft; const std::string& ff; }; template CustomFormat CustomForm(const T& t,const std::string& f) { return CustomFormat (t,f); } struct Format { Format(const std::string& s) :fs(s),fi(0) { } #define DEFINE_FORMAT_OPERATOR(a,b,c,d)\ Format& operator%(a v)\ {\ ++fi;\ static const std::string cFormat( (b) );\ bool ShouldReplace=Check(ff.empty()?cFormat:ff);\ JAM_ASSERT(ShouldReplace);\ do\ {\ fbuf.reserve(fs.length()+1+(c));\ sprintf(&fbuf[0],fs.c_str(),(d));\ fs.assign(&fbuf[0]);\ }\ while(Check(ff.empty()?(b):ff));\ ff.clear();\ return *this;\ } DEFINE_FORMAT_OPERATOR(const std::string&,"%s",v.length(),v.c_str()) DEFINE_FORMAT_OPERATOR(char,"%c",64,v) DEFINE_FORMAT_OPERATOR(unsigned char,"%u",64,v) DEFINE_FORMAT_OPERATOR(short,"%d",64,v) DEFINE_FORMAT_OPERATOR(unsigned short,"%u",64,v) DEFINE_FORMAT_OPERATOR(int,"%d",64,v) DEFINE_FORMAT_OPERATOR(unsigned int,"%u",64,v) DEFINE_FORMAT_OPERATOR(long,"%d",64,v) DEFINE_FORMAT_OPERATOR(unsigned long,"%u",64,v) DEFINE_FORMAT_OPERATOR(long long,"%I64d",128,v) #undef DEFINE_FORMAT_OPERATOR template Format& operator%(const CustomFormat & v) { v.Invoke(*this); return *this; } void SetFormat(const std::string& format) { ff=format; } const std::string& Value() { return fs; } private: bool Check(const std::string& format) { static const std::string wArgTab[]= { "$1", "$2", "$3", "$4", "$5", "$6", "$7", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$16", "$17", "$18", "$19", "$20", }; std::string::size_type index=fs.find(wArgTab[fi-1]); if(index!=std::string::npos) { fs.replace(index,wArgTab[fi-1].length(),format); return true; } return false; } unsigned long fi; std::string fs; std::string ff; std::vector fbuf; }; template std::basic_ostream & operator<<(std::basic_ostream & o ,Format& f) { o << f.Value(); return o; }