Commit 729c95b3 authored by Jan Wilken Dörrie's avatar Jan Wilken Dörrie Committed by Chromium LUCI CQ

[base] Change non-Windows base::string16 to std::u16string

This change modifies base::string16 to be an alias for std::u16string
on non-Windows platforms. This allows the removal of a custom
std::char_traits specialization for uint16_t, and now also allows
the creation of base::string16s from char literals on all platforms,
removing most of the need for helpers like base::ASCIIToUTF16.

Lastly, this change also updates blink::WebUChar, ensuring it continues
to be the exact same type as base::char16.

Bug: 911896
Change-Id: Ifef35543e10cfee2b25f11984be289553532626e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2586354Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org>
Cr-Commit-Position: refs/heads/master@{#841439}
parent 0b405995
......@@ -4,86 +4,28 @@
#include "base/strings/string16.h"
#if defined(WCHAR_T_IS_UTF16) && !defined(_AIX)
#include <string>
#error This file should not be used on 2-byte wchar_t systems
// If this winds up being needed on 2-byte wchar_t systems, either the
// definitions below can be used, or the host system's wide character
// functions like wmemcmp can be wrapped.
#include "base/strings/utf_string_conversions.h"
#elif defined(WCHAR_T_IS_UTF32)
#include <string.h>
#include <ostream>
#include "base/strings/string_piece.h"
#if defined(WCHAR_T_IS_UTF32)
std::ostream& std::operator<<(std::ostream& out, const std::u16string& str16) {
return out << base::UTF16ToUTF8(str16);
}
#endif
namespace base {
int c16memcmp(const char16* s1, const char16* s2, size_t n) {
// We cannot call memcmp because that changes the semantics.
while (n-- > 0) {
if (*s1 != *s2) {
// We cannot use (*s1 - *s2) because char16 is unsigned.
return ((*s1 < *s2) ? -1 : 1);
}
++s1;
++s2;
}
return 0;
return std::char_traits<char16>::compare(s1, s2, n);
}
size_t c16len(const char16* s) {
const char16 *s_orig = s;
while (*s) {
++s;
}
return s - s_orig;
}
const char16* c16memchr(const char16* s, char16 c, size_t n) {
while (n-- > 0) {
if (*s == c) {
return s;
}
++s;
}
return nullptr;
}
char16* c16memmove(char16* s1, const char16* s2, size_t n) {
return static_cast<char16*>(memmove(s1, s2, n * sizeof(char16)));
return std::char_traits<char16>::length(s);
}
char16* c16memcpy(char16* s1, const char16* s2, size_t n) {
return static_cast<char16*>(memcpy(s1, s2, n * sizeof(char16)));
}
char16* c16memset(char16* s, char16 c, size_t n) {
char16 *s_orig = s;
while (n-- > 0) {
*s = c;
++s;
}
return s_orig;
return std::char_traits<char16>::copy(s1, s2, n);
}
namespace string16_internals {
std::ostream& operator<<(std::ostream& out, const string16& str) {
return out << base::StringPiece16(str);
}
void PrintTo(const string16& str, std::ostream* out) {
*out << str;
}
} // namespace string16_internals
} // namespace base
template class std::
basic_string<base::char16, base::string16_internals::string16_char_traits>;
#endif // WCHAR_T_IS_UTF32
......@@ -31,6 +31,7 @@
#include <stdio.h>
#include <functional>
#include <ostream>
#include <string>
#include "base/base_export.h"
......@@ -42,188 +43,40 @@
// a literal string. This indirection allows for an easier migration of
// base::char16 to char16_t on platforms where WCHAR_T_IS_UTF16, as only a one
// character change to the macro will be necessary.
// This macro does not exist when WCHAR_T_IS_UTF32, as it is currently not
// possible to create a char array form a literal in this case.
// TODO(https://crbug.com/911896): Remove this macro once base::char16 is
// char16_t on all platforms.
#define STRING16_LITERAL(x) L##x
namespace base {
using string16 = std::wstring;
} // namespace base
#else
typedef wchar_t char16;
typedef std::wstring string16;
#define STRING16_LITERAL(x) u##x
namespace base {
using string16 = std::u16string;
} // namespace base
#elif defined(WCHAR_T_IS_UTF32)
// TODO(crbug.com/911896): Move this logging logic to base/logging.h.
namespace std {
BASE_EXPORT std::ostream& operator<<(std::ostream& out,
const std::u16string& str16);
} // namespace std
#include <wchar.h> // for mbstate_t
#endif // WCHAR_T_IS_UTF16
namespace base {
typedef uint16_t char16;
using char16 = ::base::string16::value_type;
// char16 versions of the functions required by string16_char_traits; these
// are based on the wide character functions of similar names ("w" or "wcs"
// instead of "c16").
// TODO(crbug.com/911896): Remove these functions in favor of using
// std::char_traits<base::char16> directly.
BASE_EXPORT int c16memcmp(const char16* s1, const char16* s2, size_t n);
BASE_EXPORT size_t c16len(const char16* s);
BASE_EXPORT const char16* c16memchr(const char16* s, char16 c, size_t n);
BASE_EXPORT char16* c16memmove(char16* s1, const char16* s2, size_t n);
BASE_EXPORT char16* c16memcpy(char16* s1, const char16* s2, size_t n);
BASE_EXPORT char16* c16memset(char16* s, char16 c, size_t n);
// This namespace contains the implementation of base::string16 along with
// things that need to be found via argument-dependent lookup from a
// base::string16.
namespace string16_internals {
struct string16_char_traits {
typedef char16 char_type;
typedef int int_type;
// int_type needs to be able to hold each possible value of char_type, and in
// addition, the distinct value of eof().
static_assert(sizeof(int_type) > sizeof(char_type),
"int must be larger than 16 bits wide");
typedef std::streamoff off_type;
typedef mbstate_t state_type;
typedef std::fpos<state_type> pos_type;
static void assign(char_type& c1, const char_type& c2) {
c1 = c2;
}
static bool eq(const char_type& c1, const char_type& c2) {
return c1 == c2;
}
static bool lt(const char_type& c1, const char_type& c2) {
return c1 < c2;
}
static int compare(const char_type* s1, const char_type* s2, size_t n) {
return c16memcmp(s1, s2, n);
}
static size_t length(const char_type* s) {
return c16len(s);
}
static const char_type* find(const char_type* s, size_t n,
const char_type& a) {
return c16memchr(s, a, n);
}
static char_type* move(char_type* s1, const char_type* s2, size_t n) {
return c16memmove(s1, s2, n);
}
static char_type* copy(char_type* s1, const char_type* s2, size_t n) {
return c16memcpy(s1, s2, n);
}
static char_type* assign(char_type* s, size_t n, char_type a) {
return c16memset(s, a, n);
}
static int_type not_eof(const int_type& c) {
return eq_int_type(c, eof()) ? 0 : c;
}
static char_type to_char_type(const int_type& c) {
return char_type(c);
}
static int_type to_int_type(const char_type& c) {
return int_type(c);
}
static bool eq_int_type(const int_type& c1, const int_type& c2) {
return c1 == c2;
}
static int_type eof() {
return static_cast<int_type>(EOF);
}
};
} // namespace string16_internals
typedef std::basic_string<char16,
base::string16_internals::string16_char_traits>
string16;
namespace string16_internals {
BASE_EXPORT extern std::ostream& operator<<(std::ostream& out,
const string16& str);
// This is required by googletest to print a readable output on test failures.
BASE_EXPORT extern void PrintTo(const string16& str, std::ostream* out);
} // namespace string16_internals
} // namespace base
// The string class will be explicitly instantiated only once, in string16.cc.
//
// std::basic_string<> in GNU libstdc++ contains a static data member,
// _S_empty_rep_storage, to represent empty strings. When an operation such
// as assignment or destruction is performed on a string, causing its existing
// data member to be invalidated, it must not be freed if this static data
// member is being used. Otherwise, it counts as an attempt to free static
// (and not allocated) data, which is a memory error.
//
// Generally, due to C++ template magic, _S_empty_rep_storage will be marked
// as a coalesced symbol, meaning that the linker will combine multiple
// instances into a single one when generating output.
//
// If a string class is used by multiple shared libraries, a problem occurs.
// Each library will get its own copy of _S_empty_rep_storage. When strings
// are passed across a library boundary for alteration or destruction, memory
// errors will result. GNU libstdc++ contains a configuration option,
// --enable-fully-dynamic-string (_GLIBCXX_FULLY_DYNAMIC_STRING), which
// disables the static data member optimization, but it's a good optimization
// and non-STL code is generally at the mercy of the system's STL
// configuration. Fully-dynamic strings are not the default for GNU libstdc++
// libstdc++ itself or for the libstdc++ installations on the systems we care
// about, such as Mac OS X and relevant flavors of Linux.
//
// See also http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24196 .
//
// To avoid problems, string classes need to be explicitly instantiated only
// once, in exactly one library. All other string users see it via an "extern"
// declaration. This is precisely how GNU libstdc++ handles
// std::basic_string<char> (string) and std::basic_string<wchar_t> (wstring).
//
// This also works around a Mac OS X linker bug in ld64-85.2.1 (Xcode 3.1.2),
// in which the linker does not fully coalesce symbols when dead code
// stripping is enabled. This bug causes the memory errors described above
// to occur even when a std::basic_string<> does not cross shared library
// boundaries, such as in statically-linked executables.
//
// TODO(mark): File this bug with Apple and update this note with a bug number.
extern template class BASE_EXPORT
std::basic_string<base::char16,
base::string16_internals::string16_char_traits>;
// Specialize std::hash for base::string16. Although the style guide forbids
// this in general, it is necessary for consistency with WCHAR_T_IS_UTF16
// platforms, where base::string16 is a type alias for std::wstring.
namespace std {
template <>
struct hash<base::string16> {
std::size_t operator()(const base::string16& s) const {
std::size_t result = 0;
for (base::char16 c : s)
result = (result * 131) + c;
return result;
}
};
} // namespace std
#endif // WCHAR_T_IS_UTF32
#endif // BASE_STRINGS_STRING16_H_
......@@ -13,13 +13,15 @@
namespace base {
#if defined(WCHAR_T_IS_UTF16)
TEST(String16Test, String16Literal) {
static constexpr char16 kHelloWorld[] = STRING16_LITERAL("Hello, World");
constexpr StringPiece16 kPiece = kHelloWorld;
static_assert(kHelloWorld == kPiece, "");
static_assert(kHelloWorld == kPiece.data(), "");
string16 hello_world = kHelloWorld;
EXPECT_EQ(kHelloWorld, hello_world);
}
#endif
// We define a custom operator<< for string16 so we can use it with logging.
// This tests that conversion.
......
......@@ -89,7 +89,7 @@ typedef int32_t WebUChar32;
#if defined(WIN32)
typedef wchar_t WebUChar;
#else
typedef uint16_t WebUChar;
typedef char16_t WebUChar;
#endif
// Latin-1 character type
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment