@@ -471,8 +471,15 @@ template <typename type> class type_caster<std::reference_wrapper<type>> : publi
471
471
template <typename _T> using cast_op_type = pybind11::detail::cast_op_type<_T>
472
472
473
473
474
+ template <typename CharT> using is_std_char_type = any_of<
475
+ std::is_same<CharT, char >, /* std::string */
476
+ std::is_same<CharT, char16_t >, /* std::u16string */
477
+ std::is_same<CharT, char32_t >, /* std::u32string */
478
+ std::is_same<CharT, wchar_t > /* std::wstring */
479
+ >;
480
+
474
481
template <typename T>
475
- struct type_caster <T, enable_if_t <std::is_arithmetic<T>::value>> {
482
+ struct type_caster <T, enable_if_t <std::is_arithmetic<T>::value && !is_std_char_type<T>::value >> {
476
483
typedef typename std::conditional<sizeof (T) <= sizeof (long ), long , long long >::type _py_type_0;
477
484
typedef typename std::conditional<std::is_signed<T>::value, _py_type_0, typename std::make_unsigned<_py_type_0>::type>::type _py_type_1;
478
485
typedef typename std::conditional<std::is_floating_point<T>::value, double , _py_type_1>::type py_type;
@@ -613,41 +620,24 @@ template <> class type_caster<bool> {
613
620
PYBIND11_TYPE_CASTER (bool , _(" bool" ));
614
621
};
615
622
616
- template <> class type_caster <std::string> {
617
- public:
618
- bool load (handle src, bool ) {
619
- object temp;
620
- handle load_src = src;
621
- if (!src) {
622
- return false ;
623
- } else if (PyUnicode_Check (load_src.ptr ())) {
624
- temp = reinterpret_steal<object>(PyUnicode_AsUTF8String (load_src.ptr ()));
625
- if (!temp) { PyErr_Clear (); return false ; } // UnicodeEncodeError
626
- load_src = temp;
627
- }
628
- char *buffer;
629
- ssize_t length;
630
- int err = PYBIND11_BYTES_AS_STRING_AND_SIZE (load_src.ptr (), &buffer, &length);
631
- if (err == -1 ) { PyErr_Clear (); return false ; } // TypeError
632
- value = std::string (buffer, (size_t ) length);
633
- success = true ;
634
- return true ;
635
- }
623
+ // Helper class for UTF-{8,16,32} strings:
624
+ template <typename CharT, class Traits , class Allocator >
625
+ struct type_caster <std::basic_string<CharT, Traits, Allocator>, enable_if_t <is_std_char_type<CharT>::value>> {
626
+ static constexpr unsigned int UTF_N =
627
+ std::is_same<CharT, char >::value ? 8 :
628
+ std::is_same<CharT, char16_t >::value ? 16 :
629
+ std::is_same<CharT, char32_t >::value ? 32 :
630
+ (sizeof (CharT) == 2 ? 16 : 32 ); /* std::wstring is UTF-16 on Windows, UTF-32 everywhere else */
636
631
637
- static handle cast (const std::string &src, return_value_policy /* policy */ , handle /* parent */ ) {
638
- handle s = PyUnicode_FromStringAndSize (src.c_str (), (ssize_t ) src.length ());
639
- if (!s)
640
- throw error_already_set ();
641
- return s;
642
- }
632
+ static constexpr const char *encoding = UTF_N == 8 ? " utf8" : UTF_N == 16 ? " utf16" : " utf32" ;
643
633
644
- PYBIND11_TYPE_CASTER (std::string, _(PYBIND11_STRING_NAME));
645
- protected:
646
- bool success = false ;
647
- };
634
+ // C++ only requires char/char16_t/char32_t to be at least 8/16/32 bits, but Python's encoding
635
+ // assumes exactly 1/2/4 bytes:
636
+ static_assert (sizeof (CharT) == UTF_N / 8 ,
637
+ " Internal error: string type_caster requires 1/2/4-sized character types" );
638
+
639
+ using StringType = std::basic_string<CharT, Traits, Allocator>;
648
640
649
- template <> class type_caster <std::wstring> {
650
- public:
651
641
bool load (handle src, bool ) {
652
642
object temp;
653
643
handle load_src = src;
@@ -658,78 +648,60 @@ template <> class type_caster<std::wstring> {
658
648
if (!temp) { PyErr_Clear (); return false ; }
659
649
load_src = temp;
660
650
}
661
- wchar_t *buffer = nullptr ;
662
- ssize_t length = -1 ;
663
- #if PY_MAJOR_VERSION >= 3
664
- buffer = PyUnicode_AsWideCharString (load_src.ptr (), &length);
665
- #else
666
- temp = reinterpret_steal<object>(PyUnicode_AsEncodedString (
667
- load_src.ptr (), sizeof (wchar_t ) == sizeof (short )
668
- ? " utf16" : " utf32" , nullptr ));
669
-
670
- if (temp) {
671
- int err = PYBIND11_BYTES_AS_STRING_AND_SIZE (temp.ptr (), (char **) &buffer, &length);
672
- if (err == -1 ) { buffer = nullptr ; } // TypeError
673
- length = length / (ssize_t ) sizeof (wchar_t ) - 1 ; ++buffer; // Skip BOM
674
- }
675
- #endif
676
- if (!buffer) { PyErr_Clear (); return false ; }
677
- value = std::wstring (buffer, (size_t ) length);
651
+
652
+ object utfNbytes = reinterpret_steal<object>(PyUnicode_AsEncodedString (
653
+ load_src.ptr (), encoding, nullptr ));
654
+ if (!utfNbytes) { PyErr_Clear (); return false ; }
655
+
656
+ const CharT *buffer = reinterpret_cast <const CharT *>(PYBIND11_BYTES_AS_STRING (utfNbytes.ptr ()));
657
+ size_t length = (size_t ) PYBIND11_BYTES_SIZE (utfNbytes.ptr ()) / sizeof (CharT);
658
+ if (UTF_N > 8 ) { buffer++; length--; } // Skip BOM for UTF-16/32
659
+ value = StringType (buffer, length);
678
660
success = true ;
679
661
return true ;
680
662
}
681
663
682
- static handle cast (const std::wstring &src, return_value_policy /* policy */ , handle /* parent */ ) {
683
- return PyUnicode_FromWideChar (src.c_str (), (ssize_t ) src.length ());
664
+ static handle cast (const StringType &src, return_value_policy /* policy */ , handle /* parent */ ) {
665
+ const char *buffer = reinterpret_cast <const char *>(src.c_str ());
666
+ ssize_t nbytes = ssize_t (src.size () * sizeof (CharT));
667
+ handle s = PyUnicode_Decode (buffer, nbytes, encoding, nullptr );
668
+ if (!s) throw error_already_set ();
669
+ return s;
684
670
}
685
671
686
- PYBIND11_TYPE_CASTER (std::wstring , _(PYBIND11_STRING_NAME));
672
+ PYBIND11_TYPE_CASTER (StringType , _(PYBIND11_STRING_NAME));
687
673
protected:
688
674
bool success = false ;
689
675
};
690
676
691
- template <> class type_caster <char > : public type_caster<std::string> {
677
+ template <typename CharT> struct type_caster <CharT, enable_if_t <is_std_char_type<CharT>::value>>
678
+ : type_caster<std::basic_string<CharT>> {
679
+ using StringType = std::basic_string<CharT>;
680
+ using StringCaster = type_caster<StringType>;
681
+ using StringCaster::success;
682
+ using StringCaster::value;
692
683
public:
693
684
bool load (handle src, bool convert) {
694
685
if (src.is_none ()) return true ;
695
- return type_caster<std::string> ::load (src, convert);
686
+ return StringCaster ::load (src, convert);
696
687
}
697
688
698
- static handle cast (const char *src, return_value_policy /* policy */ , handle /* parent */ ) {
689
+ static handle cast (const CharT *src, return_value_policy policy, handle parent) {
699
690
if (src == nullptr ) return none ().inc_ref ();
700
- return PyUnicode_FromString ( src);
691
+ return StringCaster::cast ( StringType ( src), policy, parent );
701
692
}
702
693
703
- static handle cast (char src, return_value_policy /* policy */ , handle /* parent */ ) {
704
- char str[2 ] = { src, ' \0 ' };
705
- return PyUnicode_DecodeLatin1 (str, 1 , nullptr );
706
- }
707
-
708
- operator char *() { return success ? (char *) value.c_str () : nullptr ; }
709
- operator char &() { return value[0 ]; }
710
-
711
- static PYBIND11_DESCR name () { return type_descr (_ (PYBIND11_STRING_NAME)); }
712
- };
713
-
714
- template <> class type_caster <wchar_t > : public type_caster<std::wstring> {
715
- public:
716
- bool load (handle src, bool convert) {
717
- if (src.is_none ()) return true ;
718
- return type_caster<std::wstring>::load (src, convert);
719
- }
720
-
721
- static handle cast (const wchar_t *src, return_value_policy /* policy */ , handle /* parent */ ) {
722
- if (src == nullptr ) return none ().inc_ref ();
723
- return PyUnicode_FromWideChar (src, (ssize_t ) wcslen (src));
724
- }
725
-
726
- static handle cast (wchar_t src, return_value_policy /* policy */ , handle /* parent */ ) {
727
- wchar_t wstr[2 ] = { src, L' \0 ' };
728
- return PyUnicode_FromWideChar (wstr, 1 );
694
+ static handle cast (CharT src, return_value_policy policy, handle parent) {
695
+ if (std::is_same<char , CharT>::value) {
696
+ handle s = PyUnicode_DecodeLatin1 ((const char *) &src, 1 , nullptr );
697
+ if (!s) throw error_already_set ();
698
+ return s;
699
+ }
700
+ return StringCaster::cast (StringType (1 , src), policy, parent);
729
701
}
730
702
731
- operator wchar_t *() { return success ? (wchar_t *) value.c_str () : nullptr ; }
732
- operator wchar_t &() { return value[0 ]; }
703
+ operator CharT *() { return success ? (CharT *) value.c_str () : nullptr ; }
704
+ operator CharT &() { return value[0 ]; }
733
705
734
706
static PYBIND11_DESCR name () { return type_descr (_ (PYBIND11_STRING_NAME)); }
735
707
};
0 commit comments