itoaごとき

C++で数値を文字列にするなんか造作ない:

 1 #include <sstream>
 2 #include <iostream>
 3 
 4 int main(void)
 5 {
 6     std::stringstream ss;
 7     ss << 10;
 8     std::string res(ss.str());
 9     std::cout << res << std::endl;
10 
11 /*文字列にする必要がないなら無論以下
12     std::cout << 10 << std::endl;
13  */
14     return 0;
15 }

が、このようなぬるま湯に浸かったまま数百万レコードを一気に処理するような「猛烈バッチ」を書くと、まぁまぁ困った事態になる。なんだかんだオーバヘッドが高く、遅い。

となると「itoa」が欲しくなるわけだが、「標準の」itoa なんかない、わけで。で、ワタシの場合なんだかんだ UNIX と Windows を頻繁に行き来する都合、「ifdef だらけのプログラムはやだなぁ」状態にすぐに陥る。VC のバージョンによるが、特に昔(VS 6.0)ほど「VCだけ異質で、しかるべきものがない」ことには随分苦しめられた。となれば「itoaごとき、作っちまえ」と思ってしまうのが人情と言うもの。

これ:

 1 //
 2 // int_to_ascii
 3 //
 4 #ifndef __INT_TO_ASCII_H_B60523C31AAC4482A753425514AE85D7__
 5 #define __INT_TO_ASCII_H_B60523C31AAC4482A753425514AE85D7__ /*DEFINED, BUT EMPTY*/
 6 
 7 //#include <type_traits> // for make_signed
 8 //make_signed short-cut version... (for VS8)
 9 template<typename UType_> struct _make_signed {
10 };
11 template<> struct _make_signed<char> {
12     typedef signed char type;
13 };
14 template<> struct _make_signed<unsigned char> {
15     typedef signed char type;
16 };
17 template<> struct _make_signed<unsigned short> {
18     typedef signed short type;
19 };
20 template<> struct _make_signed<unsigned int> {
21     typedef signed int type;
22 };
23 template<> struct _make_signed<unsigned long> {
24     typedef signed long type;
25 };
26 template<> struct _make_signed<unsigned long long> {
27     typedef signed long long type;
28 };
29 
30 #include <algorithm>
31 
32 namespace utils {
33 
34     template<typename ULongType_,
35              typename CharT_,
36              unsigned radix,
37              size_t bufsiz> inline
38         CharT_* int_to_ascii(ULongType_ val, CharT_ *buf, bool is_negative)
39     {
40         typedef typename _make_signed<ULongType_>::type LongType_;
41         CharT_ *p = buf;
42         size_t length = 0;
43         if (is_negative) {
44             *p++ = CharT_('-');
45             length++;
46             val = (ULongType_)(-(LongType_)val);
47         }
48         CharT_ *firstdig = p;
49         unsigned digval;
50         do {
51             digval = (unsigned) (val % radix);
52             val /= radix;
53             if (digval > 9) {
54                 *p++ = (CharT_) (digval - 10 + CharT_('a'));
55             } else {
56                 *p++ = (CharT_) (digval + CharT_('0'));
57             }
58             length++;
59         } while (val > 0 && length < bufsiz);
60         do {
61             std::swap(*--p, *firstdig++);
62         } while (firstdig < p);
63         return buf + length;
64     }
65 
66 }
67 
68 #endif // ifndef __INT_TO_ASCII_H_B60523C31AAC4482A753425514AE85D7__

itoaではなく「int_to_ascii」なんて名前にしとるし、「\0端」前提にしないし、とちょいと独特かもしれないけれど、実装の内容はごくごく普通。「C++流儀にしただけ」、と言っていい。だので説明しません。使いたい人はお好きにどーぞ。(C++ STL のストリームよりは十分に速く、C++ STL のストリームより遥かに低機能です。当たり前だよな。)