
/// ****************************************************************************
/// @file   
/// @author Dr.Neeton
/// @date   2002/X/X - 2015/11/13
/// 
/// @brief  文字列クラス関連。
/// 
/// ****************************************************************************

#include "../CPL_Core.h"

namespace CPL {
namespace Core {

  // _____________________________________________________________________________
  /// @brief UTF-8チェック
  /// 
  /// @retval true  : UTF8の可能性あり。
  /// @retval false : UTF8コードとしては不適合である。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  bool IsCharCode_UTF8( pin<char> in_str, _in<size_t> in_size )
  {
    auto t   = in_str;
    auto end = t + in_size;
    // BOMチェック。
    if( t[0] == (char)0xEF  &&  t[1] == (char)0xBB  &&  t[2] == (char)0xBF )
    {
      return true;
    }

    if( t < end )
    {
      auto byte = GetCharByte_UTF8( t );
      if( byte == -1 )
      {
        return false;
      }
      t += byte;
    }
    return true;
  }

  // _____________________________________________________________________________
  /// @brief UTF8の１文字のバイト数を取得
  /// 
  /// in_charには先頭のアドレスを指定。\n
  /// １文字のbyte数を返す。\n
  /// 違反している場合、-1を返す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  int GetCharByte_UTF8( pin<char> in_char )
  {
    U32 code = *(U32*)in_char;
    if( (code & zzz_::utf8::maskH1_) == zzz_::utf8::check1_ ) return 1;
    if( (code & zzz_::utf8::maskH2_) == zzz_::utf8::check2_ ) return 2;
    if( (code & zzz_::utf8::maskH3_) == zzz_::utf8::check3_ ) return 3;
    if( (code & zzz_::utf8::maskH4_) == zzz_::utf8::check4_ ) return 4;
    return -1;
  };
  
  // _____________________________________________________________________________
  /// @brief UTF8の1文字を32bitコード化した値を取得
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  U32 GetCharCode_UTF8( pin<char> in_str, rout<int> out_size )
  {
    out_size = GetCharByte_UTF8( in_str );
    if( out_size == -1 ) return (U32)-1;
    U32 code_ = *(U32*)in_str;
    code_ <<= (32 - out_size * 8);
    code_ >>= (32 - out_size * 8);
    return code_;
  }

  // _____________________________________________________________________________
  /// @brief UTF8の1文字をインデックス化した値を取得
  /// 
  /// @param[in]  in_str   : 文字のアドレスを指定します。
  /// @param[out] out_size : 文字のバイト数を返すためのint型オブジェクトを渡します。
  /// 
  /// @return
  /// 文字に対応するインデックスを返します。\n
  /// 不正なコードの場合-1を返します。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  U32 GetCharIndex_UTF8( pin<char> in_str, rout<int> out_size )
  {
    auto c = in_str;
    U32 code = *(U32*)c;
    if( (c[0] & zzz_::utf8::maskH1_) == zzz_::utf8::check1_ )
    {
      out_size = 1;
      return c[0] & zzz_::utf8::maskD1_;
    }
    if( (c[0] & zzz_::utf8::maskH2_) == zzz_::utf8::check2_ )
    {
      out_size = 2;
      return
        (c[0] & zzz_::utf8::maskD2_)
        + ((U32)(c[1] & zzz_::utf8::maskDX_) << 5);
    }
    if( (c[0] & zzz_::utf8::maskH3_) == zzz_::utf8::check3_ )
    {
      out_size = 3;
      return
        (c[0] & zzz_::utf8::maskD3_)
        + ((U32)(c[1] & zzz_::utf8::maskDX_) << 4)
        + ((U32)(c[2] & zzz_::utf8::maskDX_) << 10);
    }
    if( (code & zzz_::utf8::maskH4_) == zzz_::utf8::check4_ )
    {
      out_size = 4;
      return
        (c[0] & zzz_::utf8::maskD4_)
        + ((U32)(c[1] & zzz_::utf8::maskDX_) << 3)
        + ((U32)(c[2] & zzz_::utf8::maskDX_) << 9)
        + ((U32)(c[3] & zzz_::utf8::maskDX_) << 15);
    }
    return -1;
  }


  // _____________________________________________________________________________
  /// @brief Shift-JISチェック
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  bool IsCharCode_SJIS( pin<char> in_str, _in<size_t> in_size )
  {
    auto t   = in_str;
    auto end = t + in_size;
    while( t < end )
    {
      if( *t >= (char)0xf0 ) // Shift-JISでは0xf0以上はない（はず）
      {
        return false;
      }
      t += GetCharByte_SJIS( t );
    }
    return true;
  }


  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  U32 GetCharCode_UTF16( pin<wchar_t> in_char, rout<int> out_size )
  {
    if( !zzz_::utf16::is_surrogate_high_( in_char ) )
    {
      out_size = 1;
      return in_char[0];
    }
    if( zzz_::utf16::is_surrogate_low_( in_char + 1 ) )
    {
      out_size = 2;
      return *(U32*)in_char;
    }
    out_size = -1;
    return -1;
  }

  // _____________________________________________________________________________
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  U32 GetCharIndex_UTF16( pin<wchar_t> in_char, rout<int> out_size )
  {
    out_size = GetCharByte_UTF16( in_char );
    if( out_size == 1 )
    {
      return in_char[0];
    }
    if( out_size == 2 )
    {
      U32 low  = in_char[0] & 0x3FF;
      U32 high = in_char[1] & 0x3FF;
      return 0x10000 + low + high * 0x400;
    }
    return -1;
  }




  // _____________________________________________________________________________
  /// @brief 文字列長取得
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  size_t strfunc<T_STR>::str_len_( td_StrCPtr in_str )
  {
    td_StrCPtr p = in_str;
    for(; *p; ++p ){}
    return size_t(p-in_str);
  }

  // _____________________________________________________________________________
  /// @brief 文字列の連結
  /// 
  /// @param[in] io_str : 追加先の文字列バッファを指すポインタを指定します。
  /// @param[in] in_str : 追加する文字列を指定します。
  /// 
  /// @note io_strのバッファサイズは考慮されないので、十分な領域を確保しておくこと。
  /// 
  /// @return io_strが返る。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  T_STR* strfunc<T_STR>::str_cat_( td_StrPtr io_str, td_StrCPtr in_str )
  {
    td_StrPtr p = io_str + str_len_(io_str); // 終端のポインタを取得。
    for(
      ; *in_str
      ; ++in_str, ++p
      )
    {
      *p = *in_str;
    }
    *p = 0; // null文字
    return io_str;
  }

  // _____________________________________________________________________________
  /// @brief 文字列追加（追加元文字列サイズ指定バージョン）
  /// 
  /// @param[in] io_str : 追加先の文字列バッファを指すポインタを指定します。
  /// @param[in] in_old_length : io_str文字列の長さを指定します。
  /// @param[in] in_str : 追加する文字列セット。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  T_STR*
    strfunc<T_STR>::str_cat_length_
      ( td_StrPtr  io_str
      , size_t     in_old_length
      , td_StrCPtr in_str
      )
  {
    td_StrPtr p = io_str + in_old_length;
    for(
      ; *in_str
      ; ++in_str, ++p
      )
    {
      *p = *in_str;
    }
    *p = 0; // null文字
    return io_str;
  }

  // _____________________________________________________________________________
  /// @brief 文字列比較
  ///
  /// @param[in] in_str0 : １つ目の文字列。
  /// @param[in] in_str1 : ２つめの文字列。
  /// 
  /// @return 完全一致で0を返す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  int strfunc<T_STR>::str_cmp_( td_StrCPtr in_str0, td_StrCPtr in_str1 )
  {
    static T_STR const cpl_null_ = 0;
    if( !in_str0 ) in_str0 = &cpl_null_;
    if( !in_str1 ) in_str1 = &cpl_null_;

    td_StrCPtr
      p0 = in_str0,
      p1 = in_str1;
    for(;
      (*p0  &&  *p1  &&  (*p0==*p1));
      ++p0, ++p1 )
    {}
    return (int)*p0 - (int)*p1;
  }

  // _____________________________________________________________________________
  /// @brief 文字列比較（ワイルドカードバージョン）
  ///
  /// in_str0 と in_str1の比較。
  ///
  /// @param[in] in_str0 : 検索対象文字列。
  /// @param[in] in_str1 : 比較文字列。ワイルドカードが指定可能。
  ///
  /// @return 一致したら0、一致しなければ差分値を返す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  int strfunc<T_STR>::str_match_( td_StrCPtr in_str0, td_StrCPtr in_str1 )
  {
    switch( *in_str1 )
    {
    case '\0':
      return '\0' - *in_str0;

    case '*':
      if( str_match_( in_str0, in_str1+1 ) == 0 ) // 一致した場合
        return 0;
      else
      if( *in_str0 )
        return str_match_( in_str0+1, in_str1 );
      else
        return *in_str0 - *in_str1;

    case '?':
      if( *in_str0 )
        return str_match_( in_str0+1, in_str1+1 );
      else
        return *in_str0 - *in_str1;

    default:
      if( *in_str0 == *in_str1 )
        return str_match_( in_str0+1, in_str1+1 );
      else
        return *in_str0 - *in_str1;
    }
  }

  // _____________________________________________________________________________
  /// @brief 文字列コピー。
  ///
  /// @param[out] out_str : コピー先の文字列バッファ。
  /// @param[in]  in_str  : コピー元の文字列。
  ///
  /// @return out_ptrを返す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  T_STR* strfunc<T_STR>::str_cpy_( td_StrPtr out_str, td_StrCPtr in_str )
  {
    td_StrPtr  dt = out_str;
    td_StrCPtr sc = in_str;
    for(; *sc; ++sc, ++dt )
    {
      *dt = *sc;
    }
    *dt = 0; // null文字
    return out_str;
  }

  // _____________________________________________________________________________
  /// @brief 文字列比較。（比較文字数指定バージョン）
  /// @return 一致したら0、不一致なら0以外を返す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  int
    strfunc<T_STR>::str_ncmp_
      ( td_StrCPtr in_str0
      , td_StrCPtr in_str1
      , size_t     in_comp_num 
      )
  {
    if( in_comp_num == 0 )
    {
      return 0;
    }
    td_StrCPtr
      p0 = in_str0,
      p1 = in_str1;

    while( *p0 == *p1 )
    {
      --in_comp_num;
      if( in_comp_num == 0 ) break;
      ++p0;
      ++p1;
    }
    return *p1 - *p0;
  }

  // _____________________________________________________________________________
  /// @brief 指定文字数のコピー。
  ///
  /// @param[out] out_str     : コピー先の文字列バッファ。
  /// @param[in]  in_str      : コピー元の文字列。
  /// @param[in]  in_copy_num : コピーする文字数を指定。
  ///
  /// @return out_strが返る。
  ///
  /// @note
  /// in_copy_numがin_strの文字数以下の場合、out_strはin_copy_num+1以上のサイズが必要。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  T_STR*
    strfunc<T_STR>::str_ncpy_
      ( td_StrPtr  out_str
      , td_StrCPtr in_str
      , size_t   in_copy_num
      )
  {
    td_StrPtr  dt = out_str;
    td_StrCPtr sc = in_str;
    for(;
      (in_copy_num > 0)  &&  (*sc);
      ++dt, ++sc, --in_copy_num )
    {
      *dt = *sc;
    }
    *dt = 0; // null文字
    return out_str;
  }

  // _____________________________________________________________________________
  /// @brief 指定された文字が最初に出現する位置を取得。
  ///
  /// 見つからない場合はnullptrを返す。
  ///
  /// @param[in] in_str : 検索対象の文字列。
  /// @param[in] in_C   : 検索する文字。
  /// 
  /// @return
  /// 文字が見つかった場合、in_strが返る。\n
  /// 見つからなかった場合、nullptrが返る。
  ///
  /// @note 
  /// ※ 仕様上、null文字を検索することはできない。\n
  /// ※ マルチバイト非対応。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  T_STR* strfunc<T_STR>::str_chr_( td_StrCPtr in_str, int in_C )
  {
    while( *in_str  &&  *in_str != in_C )
    {
      ++in_str;
    }
    if( *in_str == '\0' )
    {
      return nullptr;
    }
    else
    {
      return const_cast<td_StrPtr>(in_str);
    }
  }

  // _____________________________________________________________________________
  /// @brief 指定された文字が最後に出現する位置を取得。
  ///
  /// @param[in] in_str : 検索対象の文字列。
  /// @param[in] in_C   : 検索する文字。
  ///
  /// @return
  /// 最後に一致した位置（ポインタ）を返す。\n
  /// 一致しなかった場合nullptrを返す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  T_STR* strfunc<T_STR>::str_rchr_( td_StrCPtr in_str, int in_C )
  {
    td_StrCPtr check = nullptr;
    while( *in_str )
    {
      if( *in_str == in_C )
      {
        check = in_str;
      }
      ++in_str;
    }
    return const_cast<td_StrPtr>(check);
  }

  // _____________________________________________________________________________
  /// @brief
  /// 文字列 in_str0 から文字列 in_str1 を探し、見つかったときにはその位置の
  /// ポインタを返す。見つからなかったときにはnullptrを返す。
  ///
  /// @param[in] in_str_source : 検索対象の文字列。
  /// @param[in] in_str_target : 検索文字列。
  ///
  /// @return
  /// 一致した位置（ポインタ）を返す。\n
  /// 一致しなかった場合nullptrを返す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  T_STR* strfunc<T_STR>::str_str_( td_StrCPtr in_str_source, td_StrCPtr in_str_target )
  {
    if( *in_str_source == '\0'  ||  *in_str_target == '\0' )
    {
      return nullptr;
    }

    size_t const comp_len = str_len_( in_str_target );
    td_StrCPtr ptr_source  = in_str_source;

    while( *ptr_source )
    {
      // 先頭文字一致検査
      if( *ptr_source == *in_str_target )
      {
        // 文字列一致検査
        if( str_ncmp_( ptr_source+1, in_str_target+1, comp_len-1 ) == 0 )
        {
          return const_cast<T_STR*>(ptr_source);
        }
      }

      ++ptr_source;
    }

    return nullptr;
  }
  
  // _____________________________________________________________________________
  /// @brief
  /// 文字列 in_str0 から文字列 in_str1 を検索し、in_N 番目(0基準)に一致した文字列
  /// のアドレスを返す。\n
  /// 一致文字列数が in_N に満たない場合、最後に見つかった文字列のアドレスを返す。\n
  /// 指定した文字列が見つからない場合はnullptrを返す。
  ///
  /// @param[in] in_str0 : 検索対象の文字列。
  /// @param[in] in_str1 : 検索文字列。
  /// @param[in] in_N    : 何番目を対象とするかを指定。
  ///
  /// @return
  /// in_N番目に一致した位置（ポインタ）を返す。\n
  /// １つも一致しない場合、nullptrを返す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  T_STR*
    strfunc<T_STR>::str_str_N_
      ( td_StrCPtr in_str0
      , td_StrCPtr in_str1
      , int      in_N
      )
  {
    if( *in_str0 == '\0'  ||  *in_str1 == '\0' )
    {
      return nullptr;
    }

    size_t const comp_len = str_len_( in_str1 );
    td_StrCPtr  ret_addr    = nullptr;
    td_StrCPtr  str_check_addr = str_str_( in_str0, in_str1 );

    while( str_check_addr )
    {
      ret_addr = str_check_addr;

      if( in_N == 0 )
      {
        return const_cast<td_StrPtr>(ret_addr);
      }
      --in_N;

      str_check_addr = str_str_( str_check_addr + comp_len, in_str1 );
    }

    return const_cast<td_StrPtr>(ret_addr);
  }


  // _____________________________________________________________________________
  /// @brief
  /// 文字列 in_str0 の末尾から文字列 in_str1 を探し、見つかったときにはその位置を
  /// ポインタで返し、見つからなかったときにはnullptrを返す。
  ///
  /// @param[in] in_str0 : 検索対象の文字列。
  /// @param[in] in_str1 : 検索文字列。
  ///
  /// @return 最初に一致した位置（ポインタ）を返す。一致しない場合nullptrを返す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  T_STR* strfunc<T_STR>::str_rstr_( td_StrCPtr in_str0, td_StrCPtr in_str1 )
  {
    if( *in_str0 == '\0'  ||  *in_str1 == '\0' )
    {
      return nullptr;
    }
    
    size_t const len0 = str_len_( in_str0 );
    size_t const len1 = str_len_( in_str1 );
    if( len0 < len1 )
    {
      return nullptr;
    }
    td_StrCPtr  str_last0      = in_str0 + len0 - 1;
    td_StrCPtr  str_last1      = in_str1 + len1 - 1;
    td_StrCPtr  str_check_end0 = in_str0 + len1 - 1;
    td_StrCPtr  str_check_adr0 = str_last0;
    td_StrCPtr  str_check_adr1 = str_last1;

    while( str_check_adr0 >= str_check_end0 )
    {
      if( *str_check_adr0 == *str_check_adr1 )
      {
        --str_check_adr1;

        if( str_check_adr1 < in_str1 ) // この時点でこの式が成り立つと完全一致
        {
          return const_cast<T_STR*>(str_check_adr0);
        }
      }
      else
      if( str_check_adr1 != str_last1 )
      {
        str_check_adr1 = str_last1; // 比較文字列ポインタリセット
      }

      --str_check_adr0;
    }

    return nullptr;
  }

  // _____________________________________________________________________________
  /// @brief 
  /// 文字列 in_str0 から in_N 番目(0基準)にある文字列 in_str1 と一致する位置の
  /// アドレスを返す。\n
  /// 一致個数が in_N に満たない場合、最後に見つかった文字列のアドレスを返す。\n
  /// 指定した文字列が見つからない場合はnullptrを返す。
  ///
  /// @param[in] in_str0 : 検索対象の文字列。
  /// @param[in] in_str1 : 検索文字列。
  /// @param[in] in_N    : 何番目を対象とするかを指定。
  ///
  /// @return
  /// in_N番目に一致した位置（ポインタ）を返す。\n
  /// １つも一致しない場合、nullptrを返す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  T_STR*
    strfunc<T_STR>::str_rstr_N_
      ( td_StrCPtr in_str0
      , td_StrCPtr in_str1
      , int      in_N
      )
  {
    if( *in_str0 == '\0'  ||  *in_str1 == '\0' )
    {
      return nullptr;
    }

    size_t const len0 = str_len_( in_str0 );
    size_t const len1 = str_len_( in_str1 );
    if( len0 < len1 )
    {
      return nullptr;
    }
    td_StrCPtr  ret_addr       = nullptr;
    td_StrCPtr  str_last0      = in_str0 + len0 - 1;
    td_StrCPtr  str_last1      = in_str1 + len1 - 1;
    td_StrCPtr  str_check_end0 = in_str0 + len1 - 1;
    td_StrCPtr  str_check_adr0 = str_last0;
    td_StrCPtr  str_check_adr1 = str_last1;

    while( str_check_adr0 >= str_check_end0 )
    {
      if( *str_check_adr0 == *str_check_adr1 )
      {
        --str_check_adr1;

        if( str_check_adr1 < in_str1 ) // この時点でこの式が成り立つと完全一致
        {
          ret_addr = str_check_adr0;

          if( in_N == 0 )
          {
            return const_cast<td_StrPtr>(ret_addr);
          }
          --in_N;

          str_check_adr1 = str_last1; // 比較文字列ポインタリセット
        }
      }
      else
      if( str_check_adr1 != str_last1 )
      {
        str_check_adr1 = str_last1; // 比較文字列ポインタリセット
      }

      --str_check_adr0;
    }

    return const_cast<td_StrPtr>(ret_addr);
  }

  // _____________________________________________________________________________
  /// @brief 文字列の並びを反転させる。
  ///
  /// ※ out_str_dest == in_str_srcは動作するが、
  ///    それぞれの領域が重なる場合の動作は未定義。
  ///
  /// @param[out] out_str_dest : 変換先文字列用バッファ。
  /// @param[in]  in_str_src   : 変換前文字列。
  ///
  /// @return なし。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  void strfunc<T_STR>::str_reverse_( td_StrPtr out_str_dest, td_StrCPtr in_str_src )
  {
    if( *in_str_src == '\0' )
    {
      *out_str_dest = '\0';
      return;
    }

    auto len = str_len_( in_str_src );

    if( out_str_dest == in_str_src )
    {
      td_StrPtr str_src = out_str_dest + len - 1; // コピー開始先（終端のひとつ前）のアドレスを取得
      while( out_str_dest < str_src )
      {
        Swap( *out_str_dest, *str_src );

        ++out_str_dest;
        --str_src;
      }
    }
    else
    {
      td_StrCPtr str_src = in_str_src + len - 1; // コピー開始先（終端のひとつ前）のアドレスを取得
      td_StrCPtr str_end = out_str_dest + len; // 比較終端

      while( out_str_dest < str_end )
      {
        *out_str_dest = *str_src;

        ++out_str_dest;
        --str_src;
      }
    }
  }

  // _____________________________________________________________________________
  /// @brief 文字列 in_str0 の中に、文字列 in_str1 がいくつ含まれるか取得。
  ///
  /// @param[in] in_str0 : 検索対象の文字列。
  /// @param[in] in_str1 : 検索文字列。
  ///
  /// @return 文字列が一致した回数。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  int strfunc<T_STR>::str_count_( td_StrCPtr in_str0, td_StrCPtr in_str1 )
  {
    if( *in_str0 == '\0'  ||  *in_str1 == '\0' )
    {
      return -1;
    }

    const size_t comp_len    = str_len_( in_str1 );
    int       count          = 0;
    td_StrCPtr  str_check_addr = str_str_( in_str0, in_str1 );

    while( str_check_addr )
    {
      ++count;
      str_check_addr = str_str_( str_check_addr + comp_len, in_str1 );
    }

    return count;
  }


  // _____________________________________________________________________________
  /// @brief 文字の置換
  /// 
  /// 置換可能な文字はシングル文字のみ（マルチバイトなら1byte, utf16なら2byte）
  ///
  /// @param[in] io_str_begin : 検索対象の文字列の先頭のポインタを指定します。
  /// @param[in] io_str_end   : 検索対象の文字列の末尾のポインタを指定します。
  /// @param[in] in_char_from : 置換対象の文字を指定します。
  /// @param[in] in_char_to   : 置換後の文字を指定します。
  /// 
  /// @return
  /// 置換した文字の数を返す。\n
  /// 見つからない場合は0, 置換後のサイズがオーバーフローする場合は-1を返す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  int
    strfunc<T_STR>::char_replace_
      ( td_StrPtr io_str_begin
      , td_StrPtr io_str_end
      , int       in_char_from
      , int       in_char_to
      )
  {
    auto p = io_str_begin;
    int  n = 0;
    while( *p  &&  p < io_str_end )
    {
      if( *p == in_char_from )
      {
        *p = static_cast<td_StrType>(in_char_to);
        ++n;
      }
      ++p;
    }
    return n;
  }


  // _____________________________________________________________________________
  /// @brief 最初の文字の置換
  /// 
  /// 置換可能な文字はシングル文字のみ（マルチバイトなら1byte, utf16なら2byte）
  ///
  /// @param[in] io_str_begin : 検索対象の文字列の先頭のポインタを指定します。
  /// @param[in] io_str_end   : 検索対象の文字列の末尾のポインタを指定します。
  /// @param[in] in_char_from : 置換対象の文字を指定します。
  /// @param[in] in_char_to   : 置換後の文字を指定します。
  /// 
  /// @return
  /// 置換した文字の数を返す。\n
  /// 見つからない場合は0, 置換後のサイズがオーバーフローする場合は-1を返す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  int
    strfunc<T_STR>::char_replace_first_
      ( td_StrPtr io_str_begin
      , td_StrPtr io_str_end
      , int       in_char_from
      , int       in_char_to
      )
  {
    auto p = io_str_begin;
    while( *p  &&  p < io_str_end )
    {
      if( *p == in_char_from )
      {
        *p = static_cast<td_StrType>(in_char_to);
        return 1;
      }
      ++p;
    }
    return 0;
  }


  // _____________________________________________________________________________
  /// @brief 最後の文字の置換
  /// 
  /// 置換可能な文字はシングル文字のみ（マルチバイトなら1byte, utf16なら2byte）
  ///
  /// @param[in] io_str_begin : 検索対象の文字列の先頭のポインタを指定します。
  /// @param[in] io_str_end   : 検索対象の文字列の末尾のポインタを指定します。
  /// @param[in] in_char_from : 置換対象の文字を指定します。
  /// @param[in] in_char_to   : 置換後の文字を指定します。
  /// 
  /// @return
  /// 置換した文字の数を返す。\n
  /// 見つからない場合は0, 置換後のサイズがオーバーフローする場合は-1を返す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  int
    strfunc<T_STR>::char_replace_last_
      ( td_StrPtr io_str_begin
      , td_StrPtr io_str_end
      , int       in_char_from
      , int       in_char_to
      )
  {
    auto p = io_str_end - 1;
    while( *p  &&  p >= io_str_begin )
    {
      if( *p == in_char_from )
      {
        *p = static_cast<td_StrType>(in_char_to);
        return 1;
      }
      --p;
    }
    return 0;
  }



  // _____________________________________________________________________________
  /// @brief 文字列の置換
  ///
  /// @return
  /// 置換した文字列の数を返す。\n
  /// 見つからない場合は0, 置換後のサイズがオーバーフローする場合は-1を返す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  int
    strfunc<T_STR>::str_replace_
      ( td_StrPtr  io_str
      , td_StrCPtr in_str_from
      , td_StrCPtr in_str_to
      , size_t     in_capacity
      )
  {
    auto len_from = str_len_( in_str_from );
    if( len_from == 0 )
    {
      return 0;
    }
    auto len_to = str_len_( in_str_to );
    int n = 0;

    if( len_from == len_to )
    {
      auto addr_hit = str_find_( io_str, in_str_from );
      while( addr_hit )
      {
        memcpy( addr_hit, in_str_to, len_to );
        ++n;
        addr_hit = str_find_( addr_hit + len_to, in_str_from );
      }
    }
    else if( len_from > len_to )
    {
      auto addr_hit = str_find_( io_str, in_str_from );
      auto* p_src  = addr_hit;
      auto* p_dest = addr_hit;
      while( addr_hit )
      {
        memcpy( p_dest, in_str_to, len_to );
        p_dest += len_to;
        p_src  += len_from;
        addr_hit = str_find_( p_src, in_str_from );
        if( addr_hit )
        {
          auto size = addr_hit - p_src;
          memcpy( p_dest, p_src, size );
          p_dest += size;
          p_src  += size;
          ++n;
        }
      }
      //return p_dest - io_str + str_len_()
    }
    else // len_from < len_to
    {
/*      // reverse string manager
      struct RevStr {
                td_StrPtr s; //start
                td_StrPtr e; //end  先頭ポインタ-1
        mutable td_StrPtr p; //pos
        RevStr( td_StrPtr start_, td_StrPtr end_ )
          : s(start_), e(end_), p(start_)
        {}
        RevStr( cref<RevStr> rs )
          : s(rs.s), e(rs.e), p(rs.p)
        {}
        operator td_StrPtr(){ return p > e ? p : nullptr; }
        RevStr& operator ++()   { return --p; }
        RevStr& operator ++(int){ return p--; }
        RevStr& operator --()   { return ++p; }
        RevStr& operator --(int){ return p++; }
        void reset(){ p = s; }
        bool operator == ( RevStr rs ) const
        {
          for( RevStr my(*this); *my && *rs && *my == *rs; ++my, ++rs ){}
          return (*my == nullptr) && (*rs == nullptr);
        }
      };

      // count
      auto count = str_count_( io_str, in_str_from );
      auto size_old = str_len_( io_str );
      auto size_new = size_old + count * (len_to - len_from);
      if( size_new > in_capacity ) // バッファサイズチェック
      {
        return -1;
      }

      // 最後尾から検索、置換。
      auto offs   = size_new - size_old;
      RevStr rs_src( io_str, io_str + len_old );
      RevStr rs_dest( io_str, io_str + len_new );
      RevStr rs_key( in_str_from, len_from );
      // 
      while( rs_src )
      {
        if( rs_src == rs_key )
        --p_src;
      }

      auto addr_hit = str_find_R_( io_str, in_str_from );
      auto* p_src   = addr_hit;
      auto* p_dest  = addr_hit;
      while( addr_hit )
      {
        memcpy( p_dest, in_str_to, len_to );
        p_dest += len_to;
        p_src  += len_from;
        addr_hit = str_find_( p_src, in_str_form );
        if( addr_hit )
        {
          auto size = addr_hit - p_src;
          memcpy( p_dest, p_src, offs );
          p_dest += size;
          p_src  += size;
        }
      }*/
    }
    return n;
  }

  // _____________________________________________________________________________
  /// @brief 文字列検索用汎用関数（順方向）
  ///
  /// @param[in] in_str_source : 検索対象文字列。
  /// @param[in] in_str_key    : 検索文字列。
  ///
  /// @return 最初に一致した位置（ポインタ）を返す。一致しなければnullptrを返す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR> template<class Ts>
  Ts*
    strfunc<T_STR>::str_find_
      ( Ts*        in_str_source
      , td_StrCPtr in_str_key
      )
  {
    if( !in_str_source  ||  !*in_str_source ) return nullptr;
    if( !in_str_key     ||  !*in_str_key    ) return nullptr;

    auto p_src = in_str_source;
    auto p_key = in_str_key;

    const size_t key_length = String_X_<T_STR>::str_len_( in_str_key );


    while( *p_src )
    {
      if( *p_src == *p_key )
      {
        ++p_src;
        ++p_key;
      }
      else
      if( *p_key == '\0' ) // この時点で終端の場合、完全一致。
      {
        return p_src - key_length;
      }
      else
      {
        p_key = in_str_key;
        ++p_src;
      }
    }
    // この時点で双方のポインタが0なら完全一致
    if( *p_src == '\0'  &&  *p_key == '\0' )
    {
      return p_src - key_length;
    }

    return nullptr;
  }

  
  // _____________________________________________________________________________
  /// @brief 文字列検索用汎用関数（逆方向）
  ///
  /// @param[in] in_str_source : 検索対象の文字列。
  /// @param[in] in_str_key    : 検査文字列。
  ///
  /// @return 一致した一致（ポインタ）を返す。一致しない場合nullptrを返す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR> template<class Ts>
  Ts*
    strfunc<T_STR>::str_find_R_
      ( Ts*        in_str_source
      , td_StrCPtr in_str_key
      )
  {
    if( !in_str_source  ||  !*in_str_source ) return nullptr;
    if( !in_str_key  ||  !*in_str_key ) return nullptr;

    const size_t len_src = String_X_<T_STR>::str_len_( in_str_source );
    const size_t len_key = String_X_<T_STR>::str_len_( in_str_key );

    auto p_src_end = in_str_source - 1;
    auto p_key_end = in_str_key - 1;
    auto p_key_st  = p_key_end + len_key;
    auto p_src = p_src_end + len_src;
    auto p_key = p_key_st;

    while( p_src > p_src_end )
    {
      if( *p_src == *p_key )
      {
        --p_key;
      }
      else
      {
        p_src += p_key_st - p_key; // 戻す
        p_key = p_key_st;
      }

      if( p_key == p_key_end ) // この時点でキーが終端に達している場合完全一致
      {
        return p_src;
      }
      --p_src;
    }

    return nullptr;
  }

  // _____________________________________________________________________________
  /// @brief 文字列リスト検索用汎用関数（順方向）
  ///
  /// @param[in] in_str_source   : 検索対象文字列。
  /// @param[in] in_str_key_list : 検索文字列リスト。
  /// @param[out] out_ptr_idx_key
  ///   : 最初に一致した位置のインデックスが格納されます。\n
  ///   : 必要ない場合は省略またはnullptrを渡すことができます。
  ///
  /// @return 最初に一致した位置（ポインタ）を返す。一致しなければnullptrを返す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  T_STR const*
    strfunc<T_STR>::str_find_pkg_
      ( _in <td_StrCPtr             > in_str_source
      , _in <std::vector<td_StrCPtr>> in_str_key_list
      , pout<int                    > out_ptr_idx_key
      )
  {
    if( in_str_key_list.empty() )
    {
      return nullptr;
    }

    td_StrCPtr hit_first = (td_StrCPtr)-1;

    //for( auto& str : in_str_key_list )
    auto n = in_str_key_list.size();
    for( decltype(n) i = 0; i < n; ++i )
    {
      auto& str = in_str_key_list[ i ];
      auto* hit = str_find_( in_str_source, str );
      if( hit  &&  hit < hit_first )
      {
        hit_first = hit;
        if( out_ptr_idx_key )
        {
          *out_ptr_idx_key = (int)i;
        }
      }
    }

    return (hit_first == (td_StrCPtr)-1) ? nullptr : hit_first;
  }

  
  // _____________________________________________________________________________
  /// @brief 文字列リスト検索用汎用関数（逆方向）
  ///
  /// @param[in] in_str_source   : 検索対象の文字列。
  /// @param[in] in_str_key_list : 検査文字列リスト。
  /// @param[out] out_ptr_idx_key
  ///   : 最初に一致した位置のインデックスが格納されます。\n
  ///   : 必要ない場合は省略またはnullptrを渡すことができます。
  ///
  /// @return 一致した一致（ポインタ）を返す。一致しない場合nullptrを返す。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  T_STR const*
    strfunc<T_STR>::str_find_pkg_R_
      ( _in <td_StrCPtr             > in_str_source
      , _in <std::vector<td_StrCPtr>> in_str_key_list
      , pout<int                    > out_ptr_idx_key
      )
  {
    if( in_str_key_list.empty() )
    {
      return nullptr;
    }

    td_StrCPtr hit_last = nullptr;

    //for( auto& str : in_str_key_list )
    auto n = in_str_key_list.size();
    for( decltype(n) i = 0; i < n; ++i )
    {
      auto& str = in_str_key_list[ i ];
      auto* hit = str_find_R_( in_str_source, str );
      if( hit  &&  hit > hit_last )
      {
        hit_last = hit;
        if( out_ptr_idx_key )
        {
          *out_ptr_idx_key = (int)i;
        }
      }
    }

    return hit_last;
  }


  
  // _____________________________________________________________________________
  /// @brief 符号あり整数を文字列に変換。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<> void
    strfunc<char>::i_to_str( td_StrPtr out_str, size_t in_buf_length, S32 N )
  {
    sprintf_s(out_str, in_buf_length, "%d", N);
  }
  template<> void
    strfunc<char>::i_to_str( td_StrPtr out_str, size_t in_buf_length, S64 N )
  {
    sprintf_s(out_str, in_buf_length, "%I64d", N);
  }
  template<> void
    strfunc<wchar_t>::i_to_str( td_StrPtr out_str, size_t in_buf_length, S32 N )
  {
    swprintf_s(out_str, in_buf_length, L"%d", N);
  }
  template<> void
    strfunc<wchar_t>::i_to_str( td_StrPtr out_str, size_t in_buf_length, S64 N )
  {
    swprintf_s(out_str, in_buf_length, L"%I64d", N);
  }

  // _____________________________________________________________________________
  /// @brief 符号なし整数を文字列に変換。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<> void strfunc<char>::u_to_str
    ( td_StrPtr out_str, size_t in_buf_length, U32 N )
  {
    sprintf_s(out_str, in_buf_length, "%u", N);
  }
  template<> void strfunc<char>::u_to_str
    ( td_StrPtr out_str, size_t in_buf_length, U64 N )
  {
    sprintf_s(out_str, in_buf_length, "%I64u", N);
  }
  template<> void strfunc<wchar_t>::u_to_str
    ( td_StrPtr out_str, size_t in_buf_length, U32 N )
  {
    swprintf_s(out_str, in_buf_length, L"%u", N);
  }
  template<> void strfunc<wchar_t>::u_to_str
    ( td_StrPtr out_str, size_t in_buf_length, U64 N )
  {
    swprintf_s(out_str, in_buf_length, L"%I64u", N);
  }

  // _____________________________________________________________________________
  /// @brief 実数(float)を文字列に変換。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<> void strfunc<char>::f_to_str
    ( td_StrPtr out_str, size_t in_buf_length, float N )
  {
    sprintf_s(out_str, in_buf_length, "%f", N);
  }
  template<> void strfunc<wchar_t>::f_to_str
    ( td_StrPtr out_str, size_t in_buf_length, float N )
  {
    swprintf_s(out_str, in_buf_length, L"%f", N);
  }

  // _____________________________________________________________________________
  /// @brief 実数(double)を文字列に変換。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<> void strfunc<char>::d_to_str
    ( td_StrPtr out_str, size_t in_buf_length, double N )
  {
    sprintf_s(out_str, in_buf_length, "%lf", N);
  }
  template<> void strfunc<wchar_t>::d_to_str
    ( td_StrPtr out_str, size_t in_buf_length, double N )
  {
    swprintf_s(out_str, in_buf_length, L"%lf", N);
  }


  // _____________________________________________________________________________
  /// @brief バイナリから16進文字列化。
  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  template<class T_STR>
  void
    strfunc<T_STR>::binary_to_x16
      ( td_StrPtr   out_str
      , size_t    out_str_length
      , void_cptr in_buf_ptr
      , size_t    in_buf_size
      )
  {
    const T_STR NtoC[] = {
      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F',
    };

    td_StrPtr dest_ptr = out_str;
    U8_cptr src = reinterpret_cast<U8_cptr>(in_buf_ptr);
    U8_cptr src_end = src + (int)Min( out_str_length/2-1, in_buf_size );

    while( src < src_end )
    {
      *dest_ptr++ = NtoC[ *src >> 4 ];
      *dest_ptr++ = NtoC[ *src & 0xf ];

      ++src;
    }
    *dest_ptr = 0;
  }


  // 明示的なインスタンス生成
  template class strfunc<char>;
  template class strfunc<wchar_t>;
  //template class String_X_<char>;
  //template class String_X_<wchar_t>;
  //template class NumStringT<char>;
  //template class NumStringT<wchar_t>;




// _____________________________________________________________________________
/// @brief UTF-16 -> MultiByte
/// 
/// @param[out] out_strA : 変換した文字列を格納する文字列クラスへの参照。
/// @param[in]  in_strW  : 変換元の文字列が格納された文字列クラス。
/// 
/// @return out_strAへのconst参照が返る。
/// 
/// @exception 失敗したら、例外(errno_t)を投げる。
///
/// @note 
/// 事前に、\n
/// setlocale( LC_CTYPE, "JPN" ) ※ Shift-JIS？\n
/// setlocale( LC_CTYPE, "ja_JP.UTF-8" ) としておく。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cref<StringA>
  ChangeCodeStringsWtoA( rout<StringA> out_strA, pin<wchar_t> in_strW )
{
  // 最大バッファサイズの計算。
  size_t length = StringW::str_len_( &in_strW[0] );
  int size_ucs = static_cast<int>(length * 4) + 1; // 最大と思われるバッファサイズ。
  // バッファ確保。
  out_strA.resize( size_ucs );
  // 変換。
  size_t size_mbs = 0;
  auto f_error =
    wcstombs_s
      ( &size_mbs
      , &out_strA[0], size_ucs
      , &in_strW[0], _TRUNCATE
      );
  if( f_error )
  {
    throw f_error;
  }
  out_strA.resize( size_mbs );
  //int res =
  //  ::WideCharToMultiByte(
  //      CP_THREAD_ACP, 0, in_strW, -1,
  //      &out_strA[0],
  //      size_ucs,
  //      nullptr, nullptr );
  //if( res == 0 )
  //{
  //  throw 0;
  //}

  return out_strA;
}

// _____________________________________________________________________________
/// @brief UTF-16 -> MultiByte
/// 
/// @param[out] out_strA : 変換した文字列を格納する文字列クラスへの参照。
/// @param[in]  in_strW  : 変換元の文字列が格納された文字列。
/// 
/// @return out_strAへのconst参照が返る。
/// 
/// @exception 失敗したら、例外(errno_t)を投げる。
///
/// @note 
/// 事前に、\n
/// setlocale( LC_CTYPE, "JPN" ) ※ Shift-JIS？\n
/// setlocale( LC_CTYPE, "ja_JP.UTF-8" ) としておく。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cref<std::string>
  ChangeCodeStringsWtoA( rout<std::string> out_strA, pin<wchar_t> in_strW )
{
  // サイズ取得。
  size_t length = StringW::str_len_( &in_strW[0] );
  int size_ucs = static_cast<int>(length * 4) + 1; // 最大と思われるバッファサイズ。
  // バッファ確保。
  out_strA.resize( size_ucs );
  // 変換。
  size_t size_mbs = 0;
  auto f_error =
    wcstombs_s
      ( &size_mbs
      , &out_strA[0], size_ucs
      , &in_strW[0], _TRUNCATE
      );
  if( f_error )
  {
    throw f_error;
  }
  out_strA.resize( size_mbs-1 ); // std::stringのsize()はnullを含まないため-1。
  //int res =
  //  ::WideCharToMultiByte(
  //      CP_THREAD_ACP, 0, &in_strW[0], -1,
  //      &out_strA[0],
  //      size_ucs,
  //      nullptr, nullptr );
  //if( res == 0 )
  //{
  //  throw 0;
  //}

  return out_strA;
}





// _____________________________________________________________________________
/// MultiByte -> UTF-16
/// 
/// @param[out] out_strW : 変換した文字列を格納する文字列クラスへの参照。
/// @param[in]  in_strA  : 変換元の文字列が格納された文字列。
/// 
/// @return out_strAへのconst参照が返る。
/// 
/// @exception 失敗したら、例外(errno_t)を投げる。
///
/// @note 
/// 事前に、\n
/// setlocale( LC_CTYPE, "JPN" ) ※ Shift-JIS？\n
/// setlocale( LC_CTYPE, "ja_JP.UTF-8" ) としておく。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cref<StringW>
  ChangeCodeStringsAtoW( rout<StringW> out_strW, pin<char> in_strA )
{
  // 長さを取得。
  int size_mbs = (int)StringA::str_len_( &in_strA[0] ) + 1;
  // バッファリサイズ。
  out_strW.resize( size_mbs );
  // 変換。
  size_t size_ucs = 0;
  auto f_error =
    mbstowcs_s
      ( &size_ucs
      , &out_strW[0], size_mbs
      , &in_strA[0], _TRUNCATE
      );
  if( f_error )
  {
    throw f_error;
  }
  //int res =
  //  ::MultiByteToWideChar(
  //      CP_THREAD_ACP, 0, in_strA, -1,
  //      &out_strW[0],
  //      size_mbs );
  //if( res == 0 )
  //{
  //  throw 0;
  //}

  return out_strW;
}

// _____________________________________________________________________________
/// MultiByte -> UTF-16
/// 
/// @param[out] out_strW : 変換した文字列を格納する文字列クラスへの参照。
/// @param[in]  in_strA  : 変換元の文字列が格納された文字列。
/// 
/// @return out_strAへのconst参照が返る。
/// 
/// @exception 失敗したら、例外(errno_t)を投げる。
///
/// @note 
/// 事前に、\n
/// setlocale( LC_CTYPE, "JPN" ) ※ Shift-JIS？\n
/// setlocale( LC_CTYPE, "ja_JP.UTF-8" ) としておく。
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cref<std::wstring>
  ChangeCodeStringsAtoW( rout<std::wstring> out_strW, pin<char> in_strA )
{
  // 長さを取得。
  int size_mbs = (int)StringA::str_len_( &in_strA[0] ) + 1;
  // バッファリサイズ。
  out_strW.resize( size_mbs );
  // 変換。
  size_t size_ucs = 0;
  auto f_error =
    mbstowcs_s
      ( &size_ucs
      , &out_strW[0], size_mbs
      , &in_strA[0], _TRUNCATE
      );
  if( f_error )
  {
    throw f_error;
  }
  //int res =
  //  ::MultiByteToWideChar(
  //      CP_THREAD_ACP, 0, &in_strA[0], -1,
  //      &out_strW[0],
  //      size_mbs );
  //if( res == 0 )
  //{
  //  throw 0;
  //}

  return out_strW;
}


} // namespace Core
} // namespace CPL
