Skip to content

Commit 298a8f1

Browse files
MaxGraeydcodeIO
authored andcommitted
Add String.fromCodePoint and 16-bit string compare (AssemblyScript#174)
1 parent 1ecf85b commit 298a8f1

15 files changed

+2064
-2067
lines changed

std/assembly/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ declare class String {
470470

471471
static fromCharCode(ls: i32, hs?: i32): string;
472472
static fromCharCodes(arr: u16[]): string;
473-
static fromCodePoint(cp: i32): string;
473+
static fromCodePoint(code: i32): string;
474474
static fromCodePoints(arr: i32[]): string;
475475

476476
readonly length: i32;

std/assembly/internal/string.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,3 +152,11 @@ export function parse<T>(str: String, radix: i32 = 0): T {
152152
}
153153
return sign * num;
154154
}
155+
156+
export function compareUTF16(ptr1: usize, ptr2: usize, len: usize): i32 {
157+
var cmp: i32 = 0;
158+
while (len && !(cmp = <i32>load<u16>(ptr1, HEADER_SIZE) - <i32>load<u16>(ptr2, HEADER_SIZE))) {
159+
--len, ++ptr1, ++ptr2;
160+
}
161+
return cmp;
162+
}

std/assembly/string.ts

Lines changed: 65 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
EMPTY,
55
clamp,
66
allocate,
7+
compareUTF16,
78
isWhiteSpaceOrLineTerminator,
89
CharCode,
910
parse
@@ -14,7 +15,9 @@ export class String {
1415

1516
readonly length: i32; // capped to [0, MAX_LENGTH]
1617

18+
// TODO Add and handle second argument
1719
static fromCharCode(code: i32): String {
20+
if (!code) return changetype<String>("\0");
1821
var out = allocate(1);
1922
store<u16>(
2023
changetype<usize>(out),
@@ -24,6 +27,30 @@ export class String {
2427
return out;
2528
}
2629

30+
static fromCodePoint(code: i32): String {
31+
assert(<u32>code <= 0x10FFFF); // Invalid code point range
32+
if (!code) return changetype<String>("\0");
33+
var sur = code > 0xFFFF;
34+
var out = allocate(<i32>sur + 1);
35+
if (!sur) {
36+
store<u16>(
37+
changetype<usize>(out),
38+
<u16>code,
39+
HEADER_SIZE
40+
);
41+
} else {
42+
code -= 0x10000;
43+
let hi: u32 = (code >>> 10) + 0xD800;
44+
let lo: u32 = (code & 0x3FF) + 0xDC00;
45+
store<u32>(
46+
changetype<usize>(out),
47+
(hi << 16) | lo,
48+
HEADER_SIZE
49+
);
50+
}
51+
return out;
52+
}
53+
2754
@operator("[]")
2855
charAt(pos: i32): String {
2956
assert(this !== null);
@@ -112,10 +139,10 @@ export class String {
112139
var searchLength: isize = searchString.length;
113140
var start: isize = end - searchLength;
114141
if (start < 0) return false;
115-
return !memory.compare(
116-
changetype<usize>(this) + HEADER_SIZE + (start << 1),
117-
changetype<usize>(searchString) + HEADER_SIZE,
118-
searchLength << 1
142+
return !compareUTF16(
143+
changetype<usize>(this) + (start << 1),
144+
changetype<usize>(searchString),
145+
searchLength
119146
);
120147
}
121148

@@ -127,10 +154,10 @@ export class String {
127154
var leftLength = left.length;
128155
if (leftLength != right.length) return false;
129156

130-
return !memory.compare(
131-
changetype<usize>(left) + HEADER_SIZE,
132-
changetype<usize>(right) + HEADER_SIZE,
133-
(<usize>leftLength << 1)
157+
return !compareUTF16(
158+
changetype<usize>(left),
159+
changetype<usize>(right),
160+
leftLength
134161
);
135162
}
136163

@@ -150,10 +177,10 @@ export class String {
150177
if (!rightLength) return true;
151178

152179
var length = <usize>min<i32>(leftLength, rightLength);
153-
return memory.compare(
154-
changetype<usize>(left) + HEADER_SIZE,
155-
changetype<usize>(right) + HEADER_SIZE,
156-
length << 1
180+
return compareUTF16(
181+
changetype<usize>(left),
182+
changetype<usize>(right),
183+
length
157184
) > 0;
158185
}
159186

@@ -169,10 +196,10 @@ export class String {
169196
if (!rightLength) return true;
170197

171198
var length = <usize>min<i32>(leftLength, rightLength);
172-
return memory.compare(
173-
changetype<usize>(left) + HEADER_SIZE,
174-
changetype<usize>(right) + HEADER_SIZE,
175-
length << 1
199+
return compareUTF16(
200+
changetype<usize>(left),
201+
changetype<usize>(right),
202+
length
176203
) >= 0;
177204
}
178205

@@ -187,10 +214,10 @@ export class String {
187214
if (!leftLength) return true;
188215

189216
var length = <usize>min<i32>(leftLength, rightLength);
190-
return memory.compare(
191-
changetype<usize>(left) + HEADER_SIZE,
192-
changetype<usize>(right) + HEADER_SIZE,
193-
length << 1
217+
return compareUTF16(
218+
changetype<usize>(left),
219+
changetype<usize>(right),
220+
length
194221
) < 0;
195222
}
196223

@@ -206,10 +233,10 @@ export class String {
206233
if (!leftLength) return true;
207234

208235
var length = <usize>min<i32>(leftLength, rightLength);
209-
return memory.compare(
210-
changetype<usize>(left) + HEADER_SIZE,
211-
changetype<usize>(right) + HEADER_SIZE,
212-
length << 1
236+
return compareUTF16(
237+
changetype<usize>(left),
238+
changetype<usize>(right),
239+
length
213240
) <= 0;
214241
}
215242

@@ -226,12 +253,11 @@ export class String {
226253
if (!len) return -1;
227254
var start = clamp<isize>(fromIndex, 0, len);
228255
len -= searchLen;
229-
// TODO: multiple char codes
230256
for (let k: isize = start; k <= len; ++k) {
231-
if (!memory.compare(
232-
changetype<usize>(this) + HEADER_SIZE + (k << 1),
233-
changetype<usize>(searchString) + HEADER_SIZE,
234-
searchLen << 1
257+
if (!compareUTF16(
258+
changetype<usize>(this) + (k << 1),
259+
changetype<usize>(searchString),
260+
searchLen
235261
)) {
236262
return <i32>k;
237263
}
@@ -250,10 +276,10 @@ export class String {
250276

251277
// TODO: multiple char codes
252278
for (let k = start; k >= 0; --k) {
253-
if (!memory.compare(
254-
changetype<usize>(this) + HEADER_SIZE + (k << 1),
255-
changetype<usize>(searchString) + HEADER_SIZE,
256-
searchLen << 1
279+
if (!compareUTF16(
280+
changetype<usize>(this) + (k << 1),
281+
changetype<usize>(searchString),
282+
searchLen
257283
)) {
258284
return <i32>k;
259285
}
@@ -269,13 +295,12 @@ export class String {
269295
var len: isize = this.length;
270296
var start = clamp<isize>(pos, 0, len);
271297
var searchLength: isize = searchString.length;
272-
if (searchLength + start > len) {
273-
return false;
274-
}
275-
return !memory.compare(
276-
changetype<usize>(this) + HEADER_SIZE + (start << 1),
277-
changetype<usize>(searchString) + HEADER_SIZE,
278-
searchLength << 1
298+
if (searchLength + start > len) return false;
299+
300+
return !compareUTF16(
301+
changetype<usize>(this) + (start << 1),
302+
changetype<usize>(searchString),
303+
searchLength
279304
);
280305
}
281306

std/portable/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ declare class String {
283283

284284
static fromCharCode(ls: i32, hs?: i32): string;
285285
static fromCharCodes(arr: u16[]): string;
286-
static fromCodePoint(cp: i32): string;
286+
static fromCodePoint(code: i32): string;
287287
static fromCodePoints(arr: i32[]): string;
288288

289289
readonly length: i32;

tests/compiler/object-literal.optimized.wat

Lines changed: 24 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -104,38 +104,26 @@
104104
(get_local $0)
105105
)
106106
)
107-
(func $~lib/memory/memcmp (; 3 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
107+
(func $~lib/internal/string/compareUTF16 (; 3 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
108108
(local $3 i32)
109-
(if
110-
(i32.eq
111-
(get_local $0)
112-
(get_local $1)
113-
)
114-
(return
115-
(i32.const 0)
116-
)
117-
)
118109
(loop $continue|0
119110
(if
120-
(tee_local $3
121-
(i32.ne
122-
(get_local $2)
123-
(i32.const 0)
124-
)
125-
)
126-
(set_local $3
127-
(i32.eq
128-
(i32.load8_u
129-
(get_local $0)
130-
)
131-
(i32.load8_u
132-
(get_local $1)
111+
(if (result i32)
112+
(get_local $2)
113+
(i32.eqz
114+
(tee_local $3
115+
(i32.sub
116+
(i32.load16_u offset=4
117+
(get_local $0)
118+
)
119+
(i32.load16_u offset=4
120+
(get_local $1)
121+
)
122+
)
133123
)
134124
)
125+
(get_local $2)
135126
)
136-
)
137-
(if
138-
(get_local $3)
139127
(block
140128
(set_local $2
141129
(i32.sub
@@ -159,29 +147,9 @@
159147
)
160148
)
161149
)
162-
(tee_local $0
163-
(if (result i32)
164-
(get_local $2)
165-
(i32.sub
166-
(i32.load8_u
167-
(get_local $0)
168-
)
169-
(i32.load8_u
170-
(get_local $1)
171-
)
172-
)
173-
(i32.const 0)
174-
)
175-
)
176-
)
177-
(func $~lib/memory/memory.compare (; 4 ;) (type $iiii) (param $0 i32) (param $1 i32) (param $2 i32) (result i32)
178-
(call $~lib/memory/memcmp
179-
(get_local $0)
180-
(get_local $1)
181-
(get_local $2)
182-
)
150+
(get_local $3)
183151
)
184-
(func $~lib/string/String.__eq (; 5 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
152+
(func $~lib/string/String.__eq (; 4 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
185153
(local $2 i32)
186154
(if
187155
(i32.eq
@@ -228,23 +196,14 @@
228196
)
229197
)
230198
(i32.eqz
231-
(call $~lib/memory/memory.compare
232-
(i32.add
233-
(get_local $0)
234-
(i32.const 4)
235-
)
236-
(i32.add
237-
(get_local $1)
238-
(i32.const 4)
239-
)
240-
(i32.shl
241-
(get_local $2)
242-
(i32.const 1)
243-
)
199+
(call $~lib/internal/string/compareUTF16
200+
(get_local $0)
201+
(get_local $1)
202+
(get_local $2)
244203
)
245204
)
246205
)
247-
(func $object-literal/bar (; 6 ;) (type $iv) (param $0 i32)
206+
(func $object-literal/bar (; 5 ;) (type $iv) (param $0 i32)
248207
(if
249208
(i32.ne
250209
(i32.load
@@ -282,7 +241,7 @@
282241
)
283242
)
284243
)
285-
(func $object-literal/bar2 (; 7 ;) (type $iv) (param $0 i32)
244+
(func $object-literal/bar2 (; 6 ;) (type $iv) (param $0 i32)
286245
(if
287246
(i32.ne
288247
(i32.load
@@ -301,7 +260,7 @@
301260
)
302261
)
303262
)
304-
(func $object-literal/Foo2#test (; 8 ;) (type $iv) (param $0 i32)
263+
(func $object-literal/Foo2#test (; 7 ;) (type $iv) (param $0 i32)
305264
(if
306265
(i32.ne
307266
(i32.load
@@ -320,7 +279,7 @@
320279
)
321280
)
322281
)
323-
(func $start (; 9 ;) (type $v)
282+
(func $start (; 8 ;) (type $v)
324283
(local $0 i32)
325284
(set_global $~lib/allocator/arena/startOffset
326285
(i32.const 80)

0 commit comments

Comments
 (0)