Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
unicode.cc
Go to the documentation of this file.
1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "platform/unicode.h"
6
7#include "vm/allocation.h"
8#include "vm/globals.h"
9#include "vm/object.h"
10
11namespace dart {
12
13// A constant mask that can be 'and'ed with a word of data to determine if it
14// is all ASCII (with no Latin1 characters).
15#if defined(ARCH_IS_64_BIT)
16static constexpr uintptr_t kAsciiWordMask = DART_UINT64_C(0x8080808080808080);
17#else
18static constexpr uintptr_t kAsciiWordMask = 0x80808080u;
19#endif
20
21intptr_t Utf8::Length(const String& str) {
22 if (str.IsOneByteString()) {
23 // For 1-byte strings, all code points < 0x80 have single-byte UTF-8
24 // encodings and all >= 0x80 have two-byte encodings. To get the length,
25 // start with the number of code points and add the number of high bits in
26 // the bytes.
27 uintptr_t char_length = str.Length();
28 uintptr_t length = char_length;
29 NoSafepointScope no_safepoint;
30 const uintptr_t* data =
31 reinterpret_cast<const uintptr_t*>(OneByteString::DataStart(str));
32 uintptr_t i;
33 for (i = sizeof(uintptr_t); i <= char_length; i += sizeof(uintptr_t)) {
34 uintptr_t chunk = *data++;
35 chunk &= kAsciiWordMask;
36 if (chunk != 0) {
37// Shuffle the bits until we have a count of bits in the low nibble.
38#if defined(ARCH_IS_64_BIT)
39 chunk += chunk >> 32;
40#endif
41 chunk += chunk >> 16;
42 chunk += chunk >> 8;
43 length += (chunk >> 7) & 0xf;
44 }
45 }
46 // Take care of the tail of the string, the last length % wordsize chars.
47 i -= sizeof(uintptr_t);
48 for (; i < char_length; i++) {
49 if (str.CharAt(i) > kMaxOneByteChar) length++;
50 }
51 return length;
52 }
53
54 // Slow case for 2-byte strings that handles surrogate pairs and longer UTF-8
55 // encodings.
56 intptr_t length = 0;
58 while (it.Next()) {
59 int32_t ch = it.Current();
60 length += Utf8::Length(ch);
61 }
62 return length;
63}
64
65intptr_t Utf8::Encode(const String& src, char* dst, intptr_t len) {
66 uintptr_t array_len = len;
67 intptr_t pos = 0;
68 ASSERT(static_cast<intptr_t>(array_len) >= Length(src));
69 if (src.IsOneByteString()) {
70 // For 1-byte strings, all code points < 0x80 have single-byte UTF-8
71 // encodings and all >= 0x80 have two-byte encodings.
72 NoSafepointScope scope;
73 const uintptr_t* data =
74 reinterpret_cast<const uintptr_t*>(OneByteString::DataStart(src));
75 uintptr_t char_length = src.Length();
76 uintptr_t pos = 0;
77 ASSERT(kMaxOneByteChar + 1 == 0x80);
78 for (uintptr_t i = 0; i < char_length; i += sizeof(uintptr_t)) {
79 // Read the input one word at a time and just write it verbatim if it is
80 // plain ASCII, as determined by the mask.
81 if (i + sizeof(uintptr_t) <= char_length &&
82 (*data & kAsciiWordMask) == 0 &&
83 pos + sizeof(uintptr_t) <= array_len) {
84 StoreUnaligned(reinterpret_cast<uintptr_t*>(dst + pos), *data);
85 pos += sizeof(uintptr_t);
86 } else {
87 // Process up to one word of input that contains non-ASCII Latin1
88 // characters.
89 const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
90 const uint8_t* limit =
91 Utils::Minimum(p + sizeof(uintptr_t), p + (char_length - i));
92 for (; p < limit; p++) {
93 uint8_t c = *p;
94 // These calls to Length and Encode get inlined and the cases for 3
95 // and 4 byte sequences are removed.
96 intptr_t bytes = Length(c);
97 if (pos + bytes > array_len) {
98 return pos;
99 }
100 Encode(c, reinterpret_cast<char*>(dst) + pos);
101 pos += bytes;
102 }
103 }
104 data++;
105 }
106 } else {
107 // For two-byte strings, which can contain 3 and 4-byte UTF-8 encodings,
108 // which can result in surrogate pairs, use the more general code.
110 while (it.Next()) {
111 int32_t ch = it.Current();
113 if (Utf16::IsSurrogate(ch)) {
114 // Encode unpaired surrogates as replacement characters to ensure the
115 // output is valid UTF-8. Encoded size is the same (3), so the computed
116 // length is still valid.
118 }
119 intptr_t num_bytes = Utf8::Length(ch);
120 if (pos + num_bytes > len) {
121 break;
122 }
123 Utf8::Encode(ch, &dst[pos]);
124 pos += num_bytes;
125 }
126 }
127 return pos;
128}
129
130} // namespace dart
SkPoint pos
bool IsOneByteString() const
Definition object.h:10290
intptr_t Length() const
Definition object.h:10189
uint16_t CharAt(intptr_t index) const
Definition object.h:10238
static bool IsSurrogate(uint32_t ch)
Definition unicode.h:123
static intptr_t Length(int32_t ch)
Definition unicode.cc:98
static intptr_t Encode(int32_t ch, char *dst)
Definition unicode.cc:110
static constexpr int32_t kMaxOneByteChar
Definition unicode.h:86
static constexpr int32_t kReplacementChar
Definition unicode.h:21
static bool IsOutOfRange(int32_t code_point)
Definition unicode.h:36
static T Minimum(T x, T y)
Definition utils.h:21
#define ASSERT(E)
size_t length
static void StoreUnaligned(T *ptr, T value)
Definition unaligned.h:22
static int8_t data[kExtLength]
static constexpr uintptr_t kAsciiWordMask
Definition unicode.cc:18
#define DART_UINT64_C(x)
Definition globals.h:434