Implement generalized table lookups for upper, lower, and character

traits.

To the best of my knowledge, this will not break the ABI for Apple.
However, it does introduce three publicly visible (although with
reserved name) functions that will fail to link against the just-shipped
Apple version of libc++. Since they are not used in any inline
functions, no actual breakage should occur.

If Howard doesn't want to put undefined functions (even internal ones)
into a header, they could be surrounded by additional conditional
compilation.

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@134781 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Sean Hunt 2011-07-09 00:56:23 +00:00
parent 043fe1d931
commit 62a6ac33a2
3 changed files with 66 additions and 69 deletions

View File

@ -302,7 +302,11 @@ locale::operator()(const basic_string<_CharT, _Traits, _Allocator>& __x,
class _LIBCPP_VISIBLE ctype_base class _LIBCPP_VISIBLE ctype_base
{ {
public: public:
#ifdef __GLIBC__
typedef unsigned short mask;
#else
typedef __uint32_t mask; typedef __uint32_t mask;
#endif
#if __APPLE__ #if __APPLE__
static const mask space = _CTYPE_S; static const mask space = _CTYPE_S;
@ -537,6 +541,8 @@ public:
#endif #endif
_LIBCPP_ALWAYS_INLINE const mask* table() const _NOEXCEPT {return __tab_;} _LIBCPP_ALWAYS_INLINE const mask* table() const _NOEXCEPT {return __tab_;}
static const mask* classic_table() _NOEXCEPT; static const mask* classic_table() _NOEXCEPT;
static const int* __classic_upper_table() _NOEXCEPT;
static const int* __classic_lower_table() _NOEXCEPT;
protected: protected:
~ctype(); ~ctype();

View File

@ -192,6 +192,9 @@ template <class charT> class messages_byname;
_LIBCPP_BEGIN_NAMESPACE_STD _LIBCPP_BEGIN_NAMESPACE_STD
// Get the C locale object
locale_t __cloc();
// OSX has nice foo_l() functions that let you turn off use of the global // OSX has nice foo_l() functions that let you turn off use of the global
// locale. Linux, not so much. The following functions avoid the locale when // locale. Linux, not so much. The following functions avoid the locale when
// that's possible and otherwise do the wrong thing. FIXME. // that's possible and otherwise do the wrong thing. FIXME.

View File

@ -116,6 +116,18 @@ namespace with_locale { namespace {
_LIBCPP_BEGIN_NAMESPACE_STD _LIBCPP_BEGIN_NAMESPACE_STD
locale_t __cloc() {
// In theory this could create a race condition. In practice
// the race condition is non-fatal since it will just create
// a little resource leak. Better approach would be appreciated.
#ifdef __APPLE__
return 0;
#else
static locale_t result = newlocale(LC_ALL_MASK, "C", 0);
return result;
#endif
}
namespace { namespace {
struct release struct release
@ -767,93 +779,64 @@ ctype<wchar_t>::~ctype()
bool bool
ctype<wchar_t>::do_is(mask m, char_type c) const ctype<wchar_t>::do_is(mask m, char_type c) const
{ {
#ifdef __APPLE__ return isascii(c) ? ctype<char>::classic_table()[c] & m : false;
return isascii(c) ? _DefaultRuneLocale.__runetype[c] & m : false;
#else
return false;
#endif
} }
const wchar_t* const wchar_t*
ctype<wchar_t>::do_is(const char_type* low, const char_type* high, mask* vec) const ctype<wchar_t>::do_is(const char_type* low, const char_type* high, mask* vec) const
{ {
#ifdef __APPLE__
for (; low != high; ++low, ++vec) for (; low != high; ++low, ++vec)
*vec = static_cast<mask>(isascii(*low) ? _DefaultRuneLocale.__runetype[*low] : 0); *vec = static_cast<mask>(isascii(*low) ?
ctype<char>::classic_table()[*low] : 0);
return low; return low;
#else
return NULL;
#endif
} }
const wchar_t* const wchar_t*
ctype<wchar_t>::do_scan_is(mask m, const char_type* low, const char_type* high) const ctype<wchar_t>::do_scan_is(mask m, const char_type* low, const char_type* high) const
{ {
#ifdef __APPLE__
for (; low != high; ++low) for (; low != high; ++low)
if (isascii(*low) && (_DefaultRuneLocale.__runetype[*low] & m)) if (isascii(*low) && (ctype<char>::classic_table()[*low] & m))
break; break;
return low; return low;
#else
return NULL;
#endif
} }
const wchar_t* const wchar_t*
ctype<wchar_t>::do_scan_not(mask m, const char_type* low, const char_type* high) const ctype<wchar_t>::do_scan_not(mask m, const char_type* low, const char_type* high) const
{ {
#ifdef __APPLE__
for (; low != high; ++low) for (; low != high; ++low)
if (!(isascii(*low) && (_DefaultRuneLocale.__runetype[*low] & m))) if (!(isascii(*low) && (ctype<char>::classic_table()[*low] & m)))
break; break;
return low; return low;
#else
return NULL;
#endif
} }
wchar_t wchar_t
ctype<wchar_t>::do_toupper(char_type c) const ctype<wchar_t>::do_toupper(char_type c) const
{ {
#ifdef __APPLE__ return isascii(c) ? ctype<char>::__classic_upper_table()[c] : c;
return isascii(c) ? _DefaultRuneLocale.__mapupper[c] : c;
#else
return 0;
#endif
} }
const wchar_t* const wchar_t*
ctype<wchar_t>::do_toupper(char_type* low, const char_type* high) const ctype<wchar_t>::do_toupper(char_type* low, const char_type* high) const
{ {
#ifdef __APPLE__
for (; low != high; ++low) for (; low != high; ++low)
*low = isascii(*low) ? _DefaultRuneLocale.__mapupper[*low] : *low; *low = isascii(*low) ? ctype<char>::__classic_upper_table()[*low]
: *low;
return low; return low;
#else
return NULL;
#endif
} }
wchar_t wchar_t
ctype<wchar_t>::do_tolower(char_type c) const ctype<wchar_t>::do_tolower(char_type c) const
{ {
#ifdef __APPLE__ return isascii(c) ? ctype<char>::__classic_lower_table()[c] : c;
return isascii(c) ? _DefaultRuneLocale.__maplower[c] : c;
#else
return 0;
#endif
} }
const wchar_t* const wchar_t*
ctype<wchar_t>::do_tolower(char_type* low, const char_type* high) const ctype<wchar_t>::do_tolower(char_type* low, const char_type* high) const
{ {
#ifdef __APPLE__
for (; low != high; ++low) for (; low != high; ++low)
*low = isascii(*low) ? _DefaultRuneLocale.__maplower[*low] : *low; *low = isascii(*low) ? ctype<char>::__classic_lower_table()[*low]
: *low;
return low; return low;
#else
return NULL;
#endif
} }
wchar_t wchar_t
@ -898,10 +881,8 @@ ctype<char>::ctype(const mask* tab, bool del, size_t refs)
__tab_(tab), __tab_(tab),
__del_(del) __del_(del)
{ {
#ifdef __APPLE__ if (__tab_ == 0)
if (__tab_ == 0) __tab_ = classic_table();
__tab_ = _DefaultRuneLocale.__runetype;
#endif
} }
ctype<char>::~ctype() ctype<char>::~ctype()
@ -913,45 +894,29 @@ ctype<char>::~ctype()
char char
ctype<char>::do_toupper(char_type c) const ctype<char>::do_toupper(char_type c) const
{ {
#ifdef __APPLE__ return isascii(c) ? __classic_upper_table()[c] : c;
return isascii(c) ? _DefaultRuneLocale.__mapupper[c] : c;
#else
return 0;
#endif
} }
const char* const char*
ctype<char>::do_toupper(char_type* low, const char_type* high) const ctype<char>::do_toupper(char_type* low, const char_type* high) const
{ {
#ifdef __APPLE__
for (; low != high; ++low) for (; low != high; ++low)
*low = isascii(*low) ? _DefaultRuneLocale.__mapupper[*low] : *low; *low = isascii(*low) ? __classic_upper_table()[*low] : *low;
return low; return low;
#else
return NULL;
#endif
} }
char char
ctype<char>::do_tolower(char_type c) const ctype<char>::do_tolower(char_type c) const
{ {
#ifdef __APPLE__ return isascii(c) ? __classic_lower_table()[c] : c;
return isascii(c) ? _DefaultRuneLocale.__maplower[c] : c;
#else
return 0;
#endif
} }
const char* const char*
ctype<char>::do_tolower(char_type* low, const char_type* high) const ctype<char>::do_tolower(char_type* low, const char_type* high) const
{ {
#ifdef __APPLE__
for (; low != high; ++low) for (; low != high; ++low)
*low = isascii(*low) ? _DefaultRuneLocale.__maplower[*low] : *low; *low = isascii(*low) ? __classic_lower_table()[*low] : *low;
return low; return low;
#else
return NULL;
#endif
} }
char char
@ -992,6 +957,33 @@ ctype<char>::classic_table() _NOEXCEPT
{ {
#ifdef __APPLE__ #ifdef __APPLE__
return _DefaultRuneLocale.__runetype; return _DefaultRuneLocale.__runetype;
#elif defined(__GLIBC__)
return __cloc()->__ctype_b;
// This is assumed to be safe.
#else
return NULL;
#endif
}
const int*
ctype<char>::__classic_lower_table() _NOEXCEPT
{
#ifdef __APPLE__
return _DefaultRuneLocale.__maplower;
#elif defined(__GLIBC__)
return __cloc()->__ctype_tolower;
#else
return NULL;
#endif
}
const int*
ctype<char>::__classic_upper_table() _NOEXCEPT
{
#ifdef __APPLE__
return _DefaultRuneLocale.__mapupper;
#elif defined(__GLIBC__)
return __cloc()->__ctype_toupper;
#else #else
return NULL; return NULL;
#endif #endif
@ -1092,11 +1084,10 @@ ctype_byname<wchar_t>::do_is(mask m, char_type c) const
const wchar_t* const wchar_t*
ctype_byname<wchar_t>::do_is(const char_type* low, const char_type* high, mask* vec) const ctype_byname<wchar_t>::do_is(const char_type* low, const char_type* high, mask* vec) const
{ {
#ifdef __APPLE__
for (; low != high; ++low, ++vec) for (; low != high; ++low, ++vec)
{ {
if (isascii(*low)) if (isascii(*low))
*vec = static_cast<mask>(_DefaultRuneLocale.__runetype[*low]); *vec = static_cast<mask>(ctype<char>::classic_table()[*low]);
else else
{ {
*vec = 0; *vec = 0;
@ -1121,9 +1112,6 @@ ctype_byname<wchar_t>::do_is(const char_type* low, const char_type* high, mask*
} }
} }
return low; return low;
#else
return NULL;
#endif
} }
const wchar_t* const wchar_t*