C++でC風ライブラリを作る(文字列長編)
高木です。こんばんは。
深夜ですが、日曜日は終日出かける予定なので今のうちに投稿しておくことにします。
今回のテーマは文字列の長さです。
標準Cライブラリには文字列の長さを求める関数として、strlen
関数とwcslen
関数が用意されています。
また、標準C++ライブラリにはstd::basic_string
クラステンプレートのlength
およびsize
メンバ関数、それからstd::char_traits
クラステンプレートのlength
メンバ関数も備わっています。
用途ごとに関数は用意されているのですが、関数名がいろいろで統一感がありません。
こういう記憶力に負荷をかける仕様は私にとっては辛いので、すべてを統一的に利用できるようにライブラリを設計したいと思います。
まずは一番基本となる文字型へのポインタを渡して文字列の長さ、すなわち先頭からナル文字までの距離を求める関数です。
これにはstd::char_traits
クラステンプレートのlength
メンバ関数を用いることにします。
1 2 3 4 5 6 7 8 | namespace cloverfield { template <typename charT> inline std::size_t strlen(charT const* s) { return std::char_traits<charT>::length(s); } } |
ところで、char
型とwchar_t
型については、それぞれ専用の関数を用いる方が処理系が上手く最適化してくれているかもしれません。
念のため、それらの多重定義を行っておくことにしましょう。
1 2 3 4 5 6 7 8 9 10 11 12 | namespace cloverfield { inline std::size_t strlen(char const* s) { return std::strlen(s); } inline std::size_t strlen(wchar_t const* s) { return std::wcslen(s); } } |
ところでPOSIXにはstrnlen
関数というのがあります。
範囲指定がまったくないままナル文字を探索するのは怖いので、こういう関数があるのでしょう。
事前に範囲が分かっているのであれば、探索範囲の上限を指定できたほうがいいでしょうね。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | namespace cloverfield { template <typename charT> inline std::size_t strlen(charT const* s, std::size_t n) { return std::find(s, s + n, charT(0)) - s; } inline std::size_t strlen(char const* s, std::size_t n) { if (auto ss = static_cast<char const*>(std::memchr(s, '\0', n))) return ss - s; return n; } inline std::size_t strlen(wchar_t const* s, std::size_t n) { if (auto ss = static_cast<wchar_t const*>(std::wmemchr(s, L'\0', n))) return ss - s; return n; } } |
最後にstd::basic_string
を引数に取る場合も多重定義します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | namespace cloverfield { template <typename charT, typename traits, typename Allocator> inline std::size_t strlen(std::basic_string<charT, traits, Allocator> const& s) { return s.length(); } template <typename charT, typename traits, typename Allocator> inline std::size_t strlen(std::basic_string<charT, traits, Allocator> const& s, std::size_t n) { return std::min(s.length(), n); } } |
これで一通り完成なのですが、ひとつだけ心残りがあります。
引数に配列を指定した場合、配列の要素数を自動的にナル文字の探索範囲にできなかったことです。
これについては次回にもう少し考えてみることにします。