OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2007 Apple Inc. All rights reserved. | 2 * Copyright (C) 2007 Apple Inc. All rights reserved. |
3 * Copyright (C) 2012 Google Inc. All rights reserved. | 3 * Copyright (C) 2012 Google Inc. All rights reserved. |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
7 * are met: | 7 * are met: |
8 * | 8 * |
9 * 1. Redistributions of source code must retain the above copyright | 9 * 1. Redistributions of source code must retain the above copyright |
10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
(...skipping 18 matching lines...) Expand all Loading... |
29 | 29 |
30 // FIXME: This performance optimization should be moved to blink so that all dev
elopers could enjoy it. | 30 // FIXME: This performance optimization should be moved to blink so that all dev
elopers could enjoy it. |
31 // console is retrieved with V8Window.getAttribute method which is slow. Here we
copy it to a js variable for faster access. | 31 // console is retrieved with V8Window.getAttribute method which is slow. Here we
copy it to a js variable for faster access. |
32 console = console; | 32 console = console; |
33 console.__originalAssert = console.assert; | 33 console.__originalAssert = console.assert; |
34 console.assert = function(value, message) | 34 console.assert = function(value, message) |
35 { | 35 { |
36 if (value) | 36 if (value) |
37 return; | 37 return; |
38 console.__originalAssert(value, message); | 38 console.__originalAssert(value, message); |
39 } | 39 }; |
40 | 40 |
41 /** @typedef {Array|NodeList|Arguments|{length: number}} */ | 41 /** @typedef {Array|NodeList|Arguments|{length: number}} */ |
42 var ArrayLike; | 42 var ArrayLike; |
43 | 43 |
44 /** | 44 /** |
45 * @param {number} m | 45 * @param {number} m |
46 * @param {number} n | 46 * @param {number} n |
47 * @return {number} | 47 * @return {number} |
48 */ | 48 */ |
49 function mod(m, n) | 49 function mod(m, n) |
50 { | 50 { |
51 return ((m % n) + n) % n; | 51 return ((m % n) + n) % n; |
52 } | 52 } |
53 | 53 |
54 /** | 54 /** |
55 * @param {string} string | 55 * @param {string} string |
56 * @return {!Array.<number>} | 56 * @return {!Array.<number>} |
57 */ | 57 */ |
58 String.prototype.findAll = function(string) | 58 String.prototype.findAll = function(string) |
59 { | 59 { |
60 var matches = []; | 60 var matches = []; |
61 var i = this.indexOf(string); | 61 var i = this.indexOf(string); |
62 while (i !== -1) { | 62 while (i !== -1) { |
63 matches.push(i); | 63 matches.push(i); |
64 i = this.indexOf(string, i + string.length); | 64 i = this.indexOf(string, i + string.length); |
65 } | 65 } |
66 return matches; | 66 return matches; |
67 } | 67 }; |
68 | 68 |
69 /** | 69 /** |
70 * @return {string} | 70 * @return {string} |
71 */ | 71 */ |
72 String.prototype.replaceControlCharacters = function() | 72 String.prototype.replaceControlCharacters = function() |
73 { | 73 { |
74 // Replace C0 and C1 control character sets with printable character. | 74 // Replace C0 and C1 control character sets with printable character. |
75 // Do not replace '\t', \n' and '\r'. | 75 // Do not replace '\t', \n' and '\r'. |
76 return this.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u0080-\u009f]/g
, "�"); | 76 return this.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u0080-\u009f]/g
, "�"); |
77 } | 77 }; |
78 | 78 |
79 /** | 79 /** |
80 * @return {boolean} | 80 * @return {boolean} |
81 */ | 81 */ |
82 String.prototype.isWhitespace = function() | 82 String.prototype.isWhitespace = function() |
83 { | 83 { |
84 return /^\s*$/.test(this); | 84 return /^\s*$/.test(this); |
85 } | 85 }; |
86 | 86 |
87 /** | 87 /** |
88 * @return {!Array.<number>} | 88 * @return {!Array.<number>} |
89 */ | 89 */ |
90 String.prototype.computeLineEndings = function() | 90 String.prototype.computeLineEndings = function() |
91 { | 91 { |
92 var endings = this.findAll("\n"); | 92 var endings = this.findAll("\n"); |
93 endings.push(this.length); | 93 endings.push(this.length); |
94 return endings; | 94 return endings; |
95 } | 95 }; |
96 | 96 |
97 /** | 97 /** |
98 * @param {string} chars | 98 * @param {string} chars |
99 * @return {string} | 99 * @return {string} |
100 */ | 100 */ |
101 String.prototype.escapeCharacters = function(chars) | 101 String.prototype.escapeCharacters = function(chars) |
102 { | 102 { |
103 var foundChar = false; | 103 var foundChar = false; |
104 for (var i = 0; i < chars.length; ++i) { | 104 for (var i = 0; i < chars.length; ++i) { |
105 if (this.indexOf(chars.charAt(i)) !== -1) { | 105 if (this.indexOf(chars.charAt(i)) !== -1) { |
106 foundChar = true; | 106 foundChar = true; |
107 break; | 107 break; |
108 } | 108 } |
109 } | 109 } |
110 | 110 |
111 if (!foundChar) | 111 if (!foundChar) |
112 return String(this); | 112 return String(this); |
113 | 113 |
114 var result = ""; | 114 var result = ""; |
115 for (var i = 0; i < this.length; ++i) { | 115 for (var i = 0; i < this.length; ++i) { |
116 if (chars.indexOf(this.charAt(i)) !== -1) | 116 if (chars.indexOf(this.charAt(i)) !== -1) |
117 result += "\\"; | 117 result += "\\"; |
118 result += this.charAt(i); | 118 result += this.charAt(i); |
119 } | 119 } |
120 | 120 |
121 return result; | 121 return result; |
122 } | 122 }; |
123 | 123 |
124 /** | 124 /** |
125 * @return {string} | 125 * @return {string} |
126 */ | 126 */ |
127 String.regexSpecialCharacters = function() | 127 String.regexSpecialCharacters = function() |
128 { | 128 { |
129 return "^[]{}()\\.^$*+?|-,"; | 129 return "^[]{}()\\.^$*+?|-,"; |
130 } | 130 }; |
131 | 131 |
132 /** | 132 /** |
133 * @return {string} | 133 * @return {string} |
134 */ | 134 */ |
135 String.prototype.escapeForRegExp = function() | 135 String.prototype.escapeForRegExp = function() |
136 { | 136 { |
137 return this.escapeCharacters(String.regexSpecialCharacters()); | 137 return this.escapeCharacters(String.regexSpecialCharacters()); |
138 } | 138 }; |
139 | 139 |
140 /** | 140 /** |
141 * @return {string} | 141 * @return {string} |
142 */ | 142 */ |
143 String.prototype.escapeHTML = function() | 143 String.prototype.escapeHTML = function() |
144 { | 144 { |
145 return this.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">
").replace(/"/g, """); // " doublequotes just for editor | 145 return this.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">
").replace(/"/g, """); // " doublequotes just for editor |
146 } | 146 }; |
147 | 147 |
148 /** | 148 /** |
149 * @return {string} | 149 * @return {string} |
150 */ | 150 */ |
151 String.prototype.unescapeHTML = function() | 151 String.prototype.unescapeHTML = function() |
152 { | 152 { |
153 return this.replace(/</g, "<") | 153 return this.replace(/</g, "<") |
154 .replace(/>/g, ">") | 154 .replace(/>/g, ">") |
155 .replace(/:/g, ":") | 155 .replace(/:/g, ":") |
156 .replace(/"/g, "\"") | 156 .replace(/"/g, "\"") |
157 .replace(/</g, "<") | 157 .replace(/</g, "<") |
158 .replace(/>/g, ">") | 158 .replace(/>/g, ">") |
159 .replace(/&/g, "&"); | 159 .replace(/&/g, "&"); |
160 } | 160 }; |
161 | 161 |
162 /** | 162 /** |
163 * @return {string} | 163 * @return {string} |
164 */ | 164 */ |
165 String.prototype.collapseWhitespace = function() | 165 String.prototype.collapseWhitespace = function() |
166 { | 166 { |
167 return this.replace(/[\s\xA0]+/g, " "); | 167 return this.replace(/[\s\xA0]+/g, " "); |
168 } | 168 }; |
169 | 169 |
170 /** | 170 /** |
171 * @param {number} maxLength | 171 * @param {number} maxLength |
172 * @return {string} | 172 * @return {string} |
173 */ | 173 */ |
174 String.prototype.trimMiddle = function(maxLength) | 174 String.prototype.trimMiddle = function(maxLength) |
175 { | 175 { |
176 if (this.length <= maxLength) | 176 if (this.length <= maxLength) |
177 return String(this); | 177 return String(this); |
178 var leftHalf = maxLength >> 1; | 178 var leftHalf = maxLength >> 1; |
179 var rightHalf = maxLength - leftHalf - 1; | 179 var rightHalf = maxLength - leftHalf - 1; |
180 return this.substr(0, leftHalf) + "\u2026" + this.substr(this.length - right
Half, rightHalf); | 180 return this.substr(0, leftHalf) + "\u2026" + this.substr(this.length - right
Half, rightHalf); |
181 } | 181 }; |
182 | 182 |
183 /** | 183 /** |
184 * @param {number} maxLength | 184 * @param {number} maxLength |
185 * @return {string} | 185 * @return {string} |
186 */ | 186 */ |
187 String.prototype.trimEnd = function(maxLength) | 187 String.prototype.trimEnd = function(maxLength) |
188 { | 188 { |
189 if (this.length <= maxLength) | 189 if (this.length <= maxLength) |
190 return String(this); | 190 return String(this); |
191 return this.substr(0, maxLength - 1) + "\u2026"; | 191 return this.substr(0, maxLength - 1) + "\u2026"; |
192 } | 192 }; |
193 | 193 |
194 /** | 194 /** |
195 * @param {?string=} baseURLDomain | 195 * @param {?string=} baseURLDomain |
196 * @return {string} | 196 * @return {string} |
197 */ | 197 */ |
198 String.prototype.trimURL = function(baseURLDomain) | 198 String.prototype.trimURL = function(baseURLDomain) |
199 { | 199 { |
200 var result = this.replace(/^(https|http|file):\/\//i, ""); | 200 var result = this.replace(/^(https|http|file):\/\//i, ""); |
201 if (baseURLDomain) { | 201 if (baseURLDomain) { |
202 if (result.toLowerCase().startsWith(baseURLDomain.toLowerCase())) | 202 if (result.toLowerCase().startsWith(baseURLDomain.toLowerCase())) |
203 result = result.substr(baseURLDomain.length); | 203 result = result.substr(baseURLDomain.length); |
204 } | 204 } |
205 return result; | 205 return result; |
206 } | 206 }; |
207 | 207 |
208 /** | 208 /** |
209 * @return {string} | 209 * @return {string} |
210 */ | 210 */ |
211 String.prototype.toTitleCase = function() | 211 String.prototype.toTitleCase = function() |
212 { | 212 { |
213 return this.substring(0, 1).toUpperCase() + this.substring(1); | 213 return this.substring(0, 1).toUpperCase() + this.substring(1); |
214 } | 214 }; |
215 | 215 |
216 /** | 216 /** |
217 * @param {string} other | 217 * @param {string} other |
218 * @return {number} | 218 * @return {number} |
219 */ | 219 */ |
220 String.prototype.compareTo = function(other) | 220 String.prototype.compareTo = function(other) |
221 { | 221 { |
222 if (this > other) | 222 if (this > other) |
223 return 1; | 223 return 1; |
224 if (this < other) | 224 if (this < other) |
225 return -1; | 225 return -1; |
226 return 0; | 226 return 0; |
227 } | 227 }; |
228 | 228 |
229 /** | 229 /** |
230 * @return {string} | 230 * @return {string} |
231 */ | 231 */ |
232 String.prototype.removeURLFragment = function() | 232 String.prototype.removeURLFragment = function() |
233 { | 233 { |
234 var fragmentIndex = this.indexOf("#"); | 234 var fragmentIndex = this.indexOf("#"); |
235 if (fragmentIndex === -1) | 235 if (fragmentIndex === -1) |
236 fragmentIndex = this.length; | 236 fragmentIndex = this.length; |
237 return this.substring(0, fragmentIndex); | 237 return this.substring(0, fragmentIndex); |
238 } | 238 }; |
239 | 239 |
240 /** | 240 /** |
241 * @param {string|undefined} string | 241 * @param {string|undefined} string |
242 * @return {number} | 242 * @return {number} |
243 */ | 243 */ |
244 String.hashCode = function(string) | 244 String.hashCode = function(string) |
245 { | 245 { |
246 if (!string) | 246 if (!string) |
247 return 0; | 247 return 0; |
248 // Hash algorithm for substrings is described in "Über die Komplexität der M
ultiplikation in | 248 // Hash algorithm for substrings is described in "Über die Komplexität der M
ultiplikation in |
249 // eingeschränkten Branchingprogrammmodellen" by Woelfe. | 249 // eingeschränkten Branchingprogrammmodellen" by Woelfe. |
250 // http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#
SECTION00832000000000000000 | 250 // http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#
SECTION00832000000000000000 |
251 var p = ((1 << 30) * 4 - 5); // prime: 2^32 - 5 | 251 var p = ((1 << 30) * 4 - 5); // prime: 2^32 - 5 |
252 var z = 0x5033d967; // 32 bits from random.org | 252 var z = 0x5033d967; // 32 bits from random.org |
253 var z2 = 0x59d2f15d; // random odd 32 bit number | 253 var z2 = 0x59d2f15d; // random odd 32 bit number |
254 var s = 0; | 254 var s = 0; |
255 var zi = 1; | 255 var zi = 1; |
256 for (var i = 0; i < string.length; i++) { | 256 for (var i = 0; i < string.length; i++) { |
257 var xi = string.charCodeAt(i) * z2; | 257 var xi = string.charCodeAt(i) * z2; |
258 s = (s + zi * xi) % p; | 258 s = (s + zi * xi) % p; |
259 zi = (zi * z) % p; | 259 zi = (zi * z) % p; |
260 } | 260 } |
261 s = (s + zi * (p - 1)) % p; | 261 s = (s + zi * (p - 1)) % p; |
262 return Math.abs(s | 0); | 262 return Math.abs(s | 0); |
263 } | 263 }; |
264 | 264 |
265 /** | 265 /** |
266 * @param {string} string | 266 * @param {string} string |
267 * @param {number} index | 267 * @param {number} index |
268 * @return {boolean} | 268 * @return {boolean} |
269 */ | 269 */ |
270 String.isDigitAt = function(string, index) | 270 String.isDigitAt = function(string, index) |
271 { | 271 { |
272 var c = string.charCodeAt(index); | 272 var c = string.charCodeAt(index); |
273 return (48 <= c && c <= 57); | 273 return (48 <= c && c <= 57); |
274 } | 274 }; |
275 | 275 |
276 /** | 276 /** |
277 * @return {string} | 277 * @return {string} |
278 */ | 278 */ |
279 String.prototype.toBase64 = function() | 279 String.prototype.toBase64 = function() |
280 { | 280 { |
281 /** | 281 /** |
282 * @param {number} b | 282 * @param {number} b |
283 * @return {number} | 283 * @return {number} |
284 */ | 284 */ |
(...skipping 15 matching lines...) Expand all Loading... |
300 if (shift === 2) { | 300 if (shift === 2) { |
301 encoded += String.fromCharCode(encodeBits(v >>> 18 & 63), encodeBits
(v >>> 12 & 63), encodeBits(v >>> 6 & 63), encodeBits(v & 63)); | 301 encoded += String.fromCharCode(encodeBits(v >>> 18 & 63), encodeBits
(v >>> 12 & 63), encodeBits(v >>> 6 & 63), encodeBits(v & 63)); |
302 v = 0; | 302 v = 0; |
303 } | 303 } |
304 } | 304 } |
305 if (shift === 0) | 305 if (shift === 0) |
306 encoded += String.fromCharCode(encodeBits(v >>> 18 & 63), encodeBits(v >
>> 12 & 63), 61, 61); | 306 encoded += String.fromCharCode(encodeBits(v >>> 18 & 63), encodeBits(v >
>> 12 & 63), 61, 61); |
307 else if (shift === 1) | 307 else if (shift === 1) |
308 encoded += String.fromCharCode(encodeBits(v >>> 18 & 63), encodeBits(v >
>> 12 & 63), encodeBits(v >>> 6 & 63), 61); | 308 encoded += String.fromCharCode(encodeBits(v >>> 18 & 63), encodeBits(v >
>> 12 & 63), encodeBits(v >>> 6 & 63), 61); |
309 return encoded; | 309 return encoded; |
310 } | 310 }; |
311 | 311 |
312 /** | 312 /** |
313 * @param {string} a | 313 * @param {string} a |
314 * @param {string} b | 314 * @param {string} b |
315 * @return {number} | 315 * @return {number} |
316 */ | 316 */ |
317 String.naturalOrderComparator = function(a, b) | 317 String.naturalOrderComparator = function(a, b) |
318 { | 318 { |
319 var chunk = /^\d+|^\D+/; | 319 var chunk = /^\d+|^\D+/; |
320 var chunka, chunkb, anum, bnum; | 320 var chunka, chunkb, anum, bnum; |
(...skipping 23 matching lines...) Expand all Loading... |
344 if (!+chunka && !+chunkb) // chunks are strings of all 0s (speci
al case) | 344 if (!+chunka && !+chunkb) // chunks are strings of all 0s (speci
al case) |
345 return chunka.length - chunkb.length; | 345 return chunka.length - chunkb.length; |
346 else | 346 else |
347 return chunkb.length - chunka.length; | 347 return chunkb.length - chunka.length; |
348 } | 348 } |
349 } else if (chunka !== chunkb) | 349 } else if (chunka !== chunkb) |
350 return (chunka < chunkb) ? -1 : 1; | 350 return (chunka < chunkb) ? -1 : 1; |
351 a = a.substring(chunka.length); | 351 a = a.substring(chunka.length); |
352 b = b.substring(chunkb.length); | 352 b = b.substring(chunkb.length); |
353 } | 353 } |
354 } | 354 }; |
355 | 355 |
356 /** | 356 /** |
357 * @param {string} a | 357 * @param {string} a |
358 * @param {string} b | 358 * @param {string} b |
359 * @return {number} | 359 * @return {number} |
360 */ | 360 */ |
361 String.caseInsensetiveComparator = function(a, b) | 361 String.caseInsensetiveComparator = function(a, b) |
362 { | 362 { |
363 a = a.toUpperCase(); | 363 a = a.toUpperCase(); |
364 b = b.toUpperCase(); | 364 b = b.toUpperCase(); |
365 if (a === b) | 365 if (a === b) |
366 return 0; | 366 return 0; |
367 return a > b ? 1 : -1; | 367 return a > b ? 1 : -1; |
368 } | 368 }; |
369 | 369 |
370 /** | 370 /** |
371 * @param {number} num | 371 * @param {number} num |
372 * @param {number} min | 372 * @param {number} min |
373 * @param {number} max | 373 * @param {number} max |
374 * @return {number} | 374 * @return {number} |
375 */ | 375 */ |
376 Number.constrain = function(num, min, max) | 376 Number.constrain = function(num, min, max) |
377 { | 377 { |
378 if (num < min) | 378 if (num < min) |
379 num = min; | 379 num = min; |
380 else if (num > max) | 380 else if (num > max) |
381 num = max; | 381 num = max; |
382 return num; | 382 return num; |
383 } | 383 }; |
384 | 384 |
385 /** | 385 /** |
386 * @param {number} a | 386 * @param {number} a |
387 * @param {number} b | 387 * @param {number} b |
388 * @return {number} | 388 * @return {number} |
389 */ | 389 */ |
390 Number.gcd = function(a, b) | 390 Number.gcd = function(a, b) |
391 { | 391 { |
392 if (b === 0) | 392 if (b === 0) |
393 return a; | 393 return a; |
394 else | 394 else |
395 return Number.gcd(b, a % b); | 395 return Number.gcd(b, a % b); |
396 } | 396 }; |
397 | 397 |
398 /** | 398 /** |
399 * @param {string} value | 399 * @param {string} value |
400 * @return {string} | 400 * @return {string} |
401 */ | 401 */ |
402 Number.toFixedIfFloating = function(value) | 402 Number.toFixedIfFloating = function(value) |
403 { | 403 { |
404 if (!value || isNaN(value)) | 404 if (!value || isNaN(value)) |
405 return value; | 405 return value; |
406 var number = Number(value); | 406 var number = Number(value); |
407 return number % 1 ? number.toFixed(3) : String(number); | 407 return number % 1 ? number.toFixed(3) : String(number); |
408 } | 408 }; |
409 | 409 |
410 /** | 410 /** |
411 * @return {boolean} | 411 * @return {boolean} |
412 */ | 412 */ |
413 Date.prototype.isValid = function() | 413 Date.prototype.isValid = function() |
414 { | 414 { |
415 return !isNaN(this.getTime()) | 415 return !isNaN(this.getTime()); |
416 } | 416 }; |
417 | 417 |
418 /** | 418 /** |
419 * @return {string} | 419 * @return {string} |
420 */ | 420 */ |
421 Date.prototype.toISO8601Compact = function() | 421 Date.prototype.toISO8601Compact = function() |
422 { | 422 { |
423 /** | 423 /** |
424 * @param {number} x | 424 * @param {number} x |
425 * @return {string} | 425 * @return {string} |
426 */ | 426 */ |
427 function leadZero(x) | 427 function leadZero(x) |
428 { | 428 { |
429 return (x > 9 ? "" : "0") + x; | 429 return (x > 9 ? "" : "0") + x; |
430 } | 430 } |
431 return this.getFullYear() + | 431 return this.getFullYear() + |
432 leadZero(this.getMonth() + 1) + | 432 leadZero(this.getMonth() + 1) + |
433 leadZero(this.getDate()) + "T" + | 433 leadZero(this.getDate()) + "T" + |
434 leadZero(this.getHours()) + | 434 leadZero(this.getHours()) + |
435 leadZero(this.getMinutes()) + | 435 leadZero(this.getMinutes()) + |
436 leadZero(this.getSeconds()); | 436 leadZero(this.getSeconds()); |
437 } | 437 }; |
438 | 438 |
439 /** | 439 /** |
440 * @return {string} | 440 * @return {string} |
441 */ | 441 */ |
442 Date.prototype.toConsoleTime = function() | 442 Date.prototype.toConsoleTime = function() |
443 { | 443 { |
444 /** | 444 /** |
445 * @param {number} x | 445 * @param {number} x |
446 * @return {string} | 446 * @return {string} |
447 */ | 447 */ |
(...skipping 11 matching lines...) Expand all Loading... |
459 return "0".repeat(3 - x.toString().length) + x; | 459 return "0".repeat(3 - x.toString().length) + x; |
460 } | 460 } |
461 | 461 |
462 return this.getFullYear() + "-" + | 462 return this.getFullYear() + "-" + |
463 leadZero2(this.getMonth() + 1) + "-" + | 463 leadZero2(this.getMonth() + 1) + "-" + |
464 leadZero2(this.getDate()) + " " + | 464 leadZero2(this.getDate()) + " " + |
465 leadZero2(this.getHours()) + ":" + | 465 leadZero2(this.getHours()) + ":" + |
466 leadZero2(this.getMinutes()) + ":" + | 466 leadZero2(this.getMinutes()) + ":" + |
467 leadZero2(this.getSeconds()) + "." + | 467 leadZero2(this.getSeconds()) + "." + |
468 leadZero3(this.getMilliseconds()); | 468 leadZero3(this.getMilliseconds()); |
469 } | 469 }; |
470 | 470 |
471 Object.defineProperty(Array.prototype, "remove", { | 471 Object.defineProperty(Array.prototype, "remove", { |
472 /** | 472 /** |
473 * @param {!T} value | 473 * @param {!T} value |
474 * @param {boolean=} firstOnly | 474 * @param {boolean=} firstOnly |
475 * @return {boolean} | 475 * @return {boolean} |
476 * @this {Array.<!T>} | 476 * @this {Array.<!T>} |
477 * @template T | 477 * @template T |
478 */ | 478 */ |
479 value: function(value, firstOnly) | 479 value: function(value, firstOnly) |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
603 quickSortRange(array, comparator, left, pivotNewIndex - 1, s
ortWindowLeft, sortWindowRight); | 603 quickSortRange(array, comparator, left, pivotNewIndex - 1, s
ortWindowLeft, sortWindowRight); |
604 if (pivotNewIndex < sortWindowRight) | 604 if (pivotNewIndex < sortWindowRight) |
605 quickSortRange(array, comparator, pivotNewIndex + 1, right,
sortWindowLeft, sortWindowRight); | 605 quickSortRange(array, comparator, pivotNewIndex + 1, right,
sortWindowLeft, sortWindowRight); |
606 } | 606 } |
607 if (leftBound === 0 && rightBound === (this.length - 1) && sortWindo
wLeft === 0 && sortWindowRight >= rightBound) | 607 if (leftBound === 0 && rightBound === (this.length - 1) && sortWindo
wLeft === 0 && sortWindowRight >= rightBound) |
608 this.sort(comparator); | 608 this.sort(comparator); |
609 else | 609 else |
610 quickSortRange(this, comparator, leftBound, rightBound, sortWind
owLeft, sortWindowRight); | 610 quickSortRange(this, comparator, leftBound, rightBound, sortWind
owLeft, sortWindowRight); |
611 return this; | 611 return this; |
612 } | 612 } |
613 } | 613 }; |
614 Object.defineProperty(Array.prototype, "sortRange", sortRange); | 614 Object.defineProperty(Array.prototype, "sortRange", sortRange); |
615 Object.defineProperty(Uint32Array.prototype, "sortRange", sortRange); | 615 Object.defineProperty(Uint32Array.prototype, "sortRange", sortRange); |
616 })(); | 616 })(); |
617 | 617 |
618 Object.defineProperty(Array.prototype, "stableSort", { | 618 Object.defineProperty(Array.prototype, "stableSort", { |
619 /** | 619 /** |
620 * @param {function(?T, ?T): number=} comparator | 620 * @param {function(?T, ?T): number=} comparator |
621 * @return {!Array.<?T>} | 621 * @return {!Array.<?T>} |
622 * @this {Array.<?T>} | 622 * @this {Array.<?T>} |
623 * @template T | 623 * @template T |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
672 * @param {number} k | 672 * @param {number} k |
673 * @param {function(number, number): number=} comparator | 673 * @param {function(number, number): number=} comparator |
674 * @return {number|undefined} | 674 * @return {number|undefined} |
675 * @this {Array.<number>} | 675 * @this {Array.<number>} |
676 */ | 676 */ |
677 value: function(k, comparator) | 677 value: function(k, comparator) |
678 { | 678 { |
679 if (k < 0 || k >= this.length) | 679 if (k < 0 || k >= this.length) |
680 return; | 680 return; |
681 if (!comparator) | 681 if (!comparator) |
682 comparator = function(a, b) { return a - b; } | 682 comparator = function(a, b) { return a - b; }; |
683 | 683 |
684 var low = 0; | 684 var low = 0; |
685 var high = this.length - 1; | 685 var high = this.length - 1; |
686 for (;;) { | 686 for (;;) { |
687 var pivotPosition = this.partition(comparator, low, high, Math.floor
((high + low) / 2)); | 687 var pivotPosition = this.partition(comparator, low, high, Math.floor
((high + low) / 2)); |
688 if (pivotPosition === k) | 688 if (pivotPosition === k) |
689 return this[k]; | 689 return this[k]; |
690 else if (pivotPosition > k) | 690 else if (pivotPosition > k) |
691 high = pivotPosition - 1; | 691 high = pivotPosition - 1; |
692 else | 692 else |
(...skipping 193 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
886 })(); | 886 })(); |
887 | 887 |
888 /** | 888 /** |
889 * @param {string} format | 889 * @param {string} format |
890 * @param {...*} var_arg | 890 * @param {...*} var_arg |
891 * @return {string} | 891 * @return {string} |
892 */ | 892 */ |
893 String.sprintf = function(format, var_arg) | 893 String.sprintf = function(format, var_arg) |
894 { | 894 { |
895 return String.vsprintf(format, Array.prototype.slice.call(arguments, 1)); | 895 return String.vsprintf(format, Array.prototype.slice.call(arguments, 1)); |
896 } | 896 }; |
897 | 897 |
898 /** | 898 /** |
899 * @param {string} format | 899 * @param {string} format |
900 * @param {!Object.<string, function(string, ...):*>} formatters | 900 * @param {!Object.<string, function(string, ...):*>} formatters |
901 * @return {!Array.<!Object>} | 901 * @return {!Array.<!Object>} |
902 */ | 902 */ |
903 String.tokenizeFormatString = function(format, formatters) | 903 String.tokenizeFormatString = function(format, formatters) |
904 { | 904 { |
905 var tokens = []; | 905 var tokens = []; |
906 var substitutionIndex = 0; | 906 var substitutionIndex = 0; |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
967 | 967 |
968 addSpecifierToken(format[index], precision, substitutionIndex); | 968 addSpecifierToken(format[index], precision, substitutionIndex); |
969 | 969 |
970 ++substitutionIndex; | 970 ++substitutionIndex; |
971 ++index; | 971 ++index; |
972 } | 972 } |
973 | 973 |
974 addStringToken(format.substring(index)); | 974 addStringToken(format.substring(index)); |
975 | 975 |
976 return tokens; | 976 return tokens; |
977 } | 977 }; |
978 | 978 |
979 String.standardFormatters = { | 979 String.standardFormatters = { |
980 /** | 980 /** |
981 * @return {number} | 981 * @return {number} |
982 */ | 982 */ |
983 d: function(substitution) | 983 d: function(substitution) |
984 { | 984 { |
985 return !isNaN(substitution) ? substitution : 0; | 985 return !isNaN(substitution) ? substitution : 0; |
986 }, | 986 }, |
987 | 987 |
988 /** | 988 /** |
989 * @return {number} | 989 * @return {number} |
990 */ | 990 */ |
991 f: function(substitution, token) | 991 f: function(substitution, token) |
992 { | 992 { |
993 if (substitution && token.precision > -1) | 993 if (substitution && token.precision > -1) |
994 substitution = substitution.toFixed(token.precision); | 994 substitution = substitution.toFixed(token.precision); |
995 return !isNaN(substitution) ? substitution : (token.precision > -1 ? Num
ber(0).toFixed(token.precision) : 0); | 995 return !isNaN(substitution) ? substitution : (token.precision > -1 ? Num
ber(0).toFixed(token.precision) : 0); |
996 }, | 996 }, |
997 | 997 |
998 /** | 998 /** |
999 * @return {string} | 999 * @return {string} |
1000 */ | 1000 */ |
1001 s: function(substitution) | 1001 s: function(substitution) |
1002 { | 1002 { |
1003 return substitution; | 1003 return substitution; |
1004 } | 1004 } |
1005 } | 1005 }; |
1006 | 1006 |
1007 /** | 1007 /** |
1008 * @param {string} format | 1008 * @param {string} format |
1009 * @param {!Array.<*>} substitutions | 1009 * @param {!Array.<*>} substitutions |
1010 * @return {string} | 1010 * @return {string} |
1011 */ | 1011 */ |
1012 String.vsprintf = function(format, substitutions) | 1012 String.vsprintf = function(format, substitutions) |
1013 { | 1013 { |
1014 return String.format(format, substitutions, String.standardFormatters, "", f
unction(a, b) { return a + b; }).formattedResult; | 1014 return String.format(format, substitutions, String.standardFormatters, "", f
unction(a, b) { return a + b; }).formattedResult; |
1015 } | 1015 }; |
1016 | 1016 |
1017 /** | 1017 /** |
1018 * @param {string} format | 1018 * @param {string} format |
1019 * @param {?ArrayLike} substitutions | 1019 * @param {?ArrayLike} substitutions |
1020 * @param {!Object.<string, function(string, ...):Q>} formatters | 1020 * @param {!Object.<string, function(string, ...):Q>} formatters |
1021 * @param {!T} initialValue | 1021 * @param {!T} initialValue |
1022 * @param {function(T, Q): T|undefined} append | 1022 * @param {function(T, Q): T|undefined} append |
1023 * @param {!Array.<!Object>=} tokenizedFormat | 1023 * @param {!Array.<!Object>=} tokenizedFormat |
1024 * @return {!{formattedResult: T, unusedSubstitutions: ?ArrayLike}}; | 1024 * @return {!{formattedResult: T, unusedSubstitutions: ?ArrayLike}}; |
1025 * @template T, Q | 1025 * @template T, Q |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1082 } | 1082 } |
1083 | 1083 |
1084 var unusedSubstitutions = []; | 1084 var unusedSubstitutions = []; |
1085 for (var i = 0; i < substitutions.length; ++i) { | 1085 for (var i = 0; i < substitutions.length; ++i) { |
1086 if (i in usedSubstitutionIndexes) | 1086 if (i in usedSubstitutionIndexes) |
1087 continue; | 1087 continue; |
1088 unusedSubstitutions.push(substitutions[i]); | 1088 unusedSubstitutions.push(substitutions[i]); |
1089 } | 1089 } |
1090 | 1090 |
1091 return { formattedResult: result, unusedSubstitutions: unusedSubstitutions }
; | 1091 return { formattedResult: result, unusedSubstitutions: unusedSubstitutions }
; |
1092 } | 1092 }; |
1093 | 1093 |
1094 /** | 1094 /** |
1095 * @param {string} query | 1095 * @param {string} query |
1096 * @param {boolean} caseSensitive | 1096 * @param {boolean} caseSensitive |
1097 * @param {boolean} isRegex | 1097 * @param {boolean} isRegex |
1098 * @return {!RegExp} | 1098 * @return {!RegExp} |
1099 */ | 1099 */ |
1100 function createSearchRegex(query, caseSensitive, isRegex) | 1100 function createSearchRegex(query, caseSensitive, isRegex) |
1101 { | 1101 { |
1102 var regexFlags = caseSensitive ? "g" : "gi"; | 1102 var regexFlags = caseSensitive ? "g" : "gi"; |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1174 return spacesPadding(paddingLength) + numberString; | 1174 return spacesPadding(paddingLength) + numberString; |
1175 } | 1175 } |
1176 | 1176 |
1177 /** | 1177 /** |
1178 * @return {!Array.<T>} | 1178 * @return {!Array.<T>} |
1179 * @template T | 1179 * @template T |
1180 */ | 1180 */ |
1181 Set.prototype.valuesArray = function() | 1181 Set.prototype.valuesArray = function() |
1182 { | 1182 { |
1183 return Array.from(this.values()); | 1183 return Array.from(this.values()); |
1184 } | 1184 }; |
1185 | 1185 |
1186 /** | 1186 /** |
1187 * @param {!Iterable<T>|!Array<!T>} iterable | 1187 * @param {!Iterable<T>|!Array<!T>} iterable |
1188 * @template T | 1188 * @template T |
1189 */ | 1189 */ |
1190 Set.prototype.addAll = function(iterable) | 1190 Set.prototype.addAll = function(iterable) |
1191 { | 1191 { |
1192 for (var e of iterable) | 1192 for (var e of iterable) |
1193 this.add(e); | 1193 this.add(e); |
1194 } | 1194 }; |
1195 | 1195 |
1196 /** | 1196 /** |
1197 * @param {!Iterable<T>|!Array<!T>} iterable | 1197 * @param {!Iterable<T>|!Array<!T>} iterable |
1198 * @return {boolean} | 1198 * @return {boolean} |
1199 * @template T | 1199 * @template T |
1200 */ | 1200 */ |
1201 Set.prototype.containsAll = function(iterable) | 1201 Set.prototype.containsAll = function(iterable) |
1202 { | 1202 { |
1203 for (var e of iterable) { | 1203 for (var e of iterable) { |
1204 if (!this.has(e)) | 1204 if (!this.has(e)) |
1205 return false; | 1205 return false; |
1206 } | 1206 } |
1207 return true; | 1207 return true; |
1208 } | 1208 }; |
1209 | 1209 |
1210 /** | 1210 /** |
1211 * @return {T} | 1211 * @return {T} |
1212 * @template T | 1212 * @template T |
1213 */ | 1213 */ |
1214 Map.prototype.remove = function(key) | 1214 Map.prototype.remove = function(key) |
1215 { | 1215 { |
1216 var value = this.get(key); | 1216 var value = this.get(key); |
1217 this.delete(key); | 1217 this.delete(key); |
1218 return value; | 1218 return value; |
1219 } | 1219 }; |
1220 | 1220 |
1221 /** | 1221 /** |
1222 * @return {!Array<!VALUE>} | 1222 * @return {!Array<!VALUE>} |
1223 */ | 1223 */ |
1224 Map.prototype.valuesArray = function() | 1224 Map.prototype.valuesArray = function() |
1225 { | 1225 { |
1226 return Array.from(this.values()); | 1226 return Array.from(this.values()); |
1227 } | 1227 }; |
1228 | 1228 |
1229 /** | 1229 /** |
1230 * @return {!Array<!KEY>} | 1230 * @return {!Array<!KEY>} |
1231 */ | 1231 */ |
1232 Map.prototype.keysArray = function() | 1232 Map.prototype.keysArray = function() |
1233 { | 1233 { |
1234 return Array.from(this.keys()); | 1234 return Array.from(this.keys()); |
1235 } | 1235 }; |
1236 | 1236 |
1237 /** | 1237 /** |
1238 * @return {!Multimap<!KEY, !VALUE>} | 1238 * @return {!Multimap<!KEY, !VALUE>} |
1239 */ | 1239 */ |
1240 Map.prototype.inverse = function() | 1240 Map.prototype.inverse = function() |
1241 { | 1241 { |
1242 var result = new Multimap(); | 1242 var result = new Multimap(); |
1243 for (var key of this.keys()) { | 1243 for (var key of this.keys()) { |
1244 var value = this.get(key); | 1244 var value = this.get(key); |
1245 result.set(value, key); | 1245 result.set(value, key); |
1246 } | 1246 } |
1247 return result; | 1247 return result; |
1248 } | 1248 }; |
1249 | 1249 |
1250 /** | 1250 /** |
1251 * @constructor | 1251 * @constructor |
1252 * @template K, V | 1252 * @template K, V |
1253 */ | 1253 */ |
1254 var Multimap = function() | 1254 var Multimap = function() |
1255 { | 1255 { |
1256 /** @type {!Map.<K, !Set.<!V>>} */ | 1256 /** @type {!Map.<K, !Set.<!V>>} */ |
1257 this._map = new Map(); | 1257 this._map = new Map(); |
1258 } | 1258 }; |
1259 | 1259 |
1260 Multimap.prototype = { | 1260 Multimap.prototype = { |
1261 /** | 1261 /** |
1262 * @param {K} key | 1262 * @param {K} key |
1263 * @param {V} value | 1263 * @param {V} value |
1264 */ | 1264 */ |
1265 set: function(key, value) | 1265 set: function(key, value) |
1266 { | 1266 { |
1267 var set = this._map.get(key); | 1267 var set = this._map.get(key); |
1268 if (!set) { | 1268 if (!set) { |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1351 var keys = this.keysArray(); | 1351 var keys = this.keysArray(); |
1352 for (var i = 0; i < keys.length; ++i) | 1352 for (var i = 0; i < keys.length; ++i) |
1353 result.pushAll(this.get(keys[i]).valuesArray()); | 1353 result.pushAll(this.get(keys[i]).valuesArray()); |
1354 return result; | 1354 return result; |
1355 }, | 1355 }, |
1356 | 1356 |
1357 clear: function() | 1357 clear: function() |
1358 { | 1358 { |
1359 this._map.clear(); | 1359 this._map.clear(); |
1360 } | 1360 } |
1361 } | 1361 }; |
1362 | 1362 |
1363 /** | 1363 /** |
1364 * @param {string} url | 1364 * @param {string} url |
1365 * @return {!Promise.<string>} | 1365 * @return {!Promise.<string>} |
1366 */ | 1366 */ |
1367 function loadXHR(url) | 1367 function loadXHR(url) |
1368 { | 1368 { |
1369 return new Promise(load); | 1369 return new Promise(load); |
1370 | 1370 |
1371 function load(successCallback, failureCallback) | 1371 function load(successCallback, failureCallback) |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1445 _incomingCallback: function(userCallback) | 1445 _incomingCallback: function(userCallback) |
1446 { | 1446 { |
1447 console.assert(this._pendingIncomingCallbacksCount > 0); | 1447 console.assert(this._pendingIncomingCallbacksCount > 0); |
1448 if (userCallback) { | 1448 if (userCallback) { |
1449 var args = Array.prototype.slice.call(arguments, 1); | 1449 var args = Array.prototype.slice.call(arguments, 1); |
1450 userCallback.apply(null, args); | 1450 userCallback.apply(null, args); |
1451 } | 1451 } |
1452 if (!--this._pendingIncomingCallbacksCount && this._outgoingCallback) | 1452 if (!--this._pendingIncomingCallbacksCount && this._outgoingCallback) |
1453 this._outgoingCallback(); | 1453 this._outgoingCallback(); |
1454 } | 1454 } |
1455 } | 1455 }; |
1456 | 1456 |
1457 /** | 1457 /** |
1458 * @param {*} value | 1458 * @param {*} value |
1459 */ | 1459 */ |
1460 function suppressUnused(value) | 1460 function suppressUnused(value) |
1461 { | 1461 { |
1462 } | 1462 } |
1463 | 1463 |
1464 /** | 1464 /** |
1465 * @param {function()} callback | 1465 * @param {function()} callback |
1466 * @return {number} | 1466 * @return {number} |
1467 */ | 1467 */ |
1468 self.setImmediate = function(callback) | 1468 self.setImmediate = function(callback) |
1469 { | 1469 { |
1470 Promise.resolve().then(callback); | 1470 Promise.resolve().then(callback); |
1471 return 0; | 1471 return 0; |
1472 } | 1472 }; |
1473 | 1473 |
1474 /** | 1474 /** |
1475 * @param {function(...?)} callback | 1475 * @param {function(...?)} callback |
1476 * @return {!Promise.<T>} | 1476 * @return {!Promise.<T>} |
1477 * @template T | 1477 * @template T |
1478 */ | 1478 */ |
1479 Promise.prototype.spread = function(callback) | 1479 Promise.prototype.spread = function(callback) |
1480 { | 1480 { |
1481 return this.then(spreadPromise); | 1481 return this.then(spreadPromise); |
1482 | 1482 |
1483 function spreadPromise(arg) | 1483 function spreadPromise(arg) |
1484 { | 1484 { |
1485 return callback.apply(null, arg); | 1485 return callback.apply(null, arg); |
1486 } | 1486 } |
1487 } | 1487 }; |
1488 | 1488 |
1489 /** | 1489 /** |
1490 * @param {T} defaultValue | 1490 * @param {T} defaultValue |
1491 * @return {!Promise.<T>} | 1491 * @return {!Promise.<T>} |
1492 * @template T | 1492 * @template T |
1493 */ | 1493 */ |
1494 Promise.prototype.catchException = function(defaultValue) { | 1494 Promise.prototype.catchException = function(defaultValue) { |
1495 return this.catch(function(error) { | 1495 return this.catch(function(error) { |
1496 console.error(error); | 1496 console.error(error); |
1497 return defaultValue; | 1497 return defaultValue; |
1498 }); | 1498 }); |
1499 } | 1499 }; |
1500 | 1500 |
1501 /** | 1501 /** |
1502 * @param {!Map<number, ?>} other | 1502 * @param {!Map<number, ?>} other |
1503 * @param {function(!VALUE,?):boolean} isEqual | 1503 * @param {function(!VALUE,?):boolean} isEqual |
1504 * @return {!{removed: !Array<!VALUE>, added: !Array<?>, equal: !Array<!VALUE>}} | 1504 * @return {!{removed: !Array<!VALUE>, added: !Array<?>, equal: !Array<!VALUE>}} |
1505 * @this {Map<number, VALUE>} | 1505 * @this {Map<number, VALUE>} |
1506 */ | 1506 */ |
1507 Map.prototype.diff = function(other, isEqual) | 1507 Map.prototype.diff = function(other, isEqual) |
1508 { | 1508 { |
1509 var leftKeys = this.keysArray(); | 1509 var leftKeys = this.keysArray(); |
(...skipping 28 matching lines...) Expand all Loading... |
1538 removed.push(this.get(leftKey)); | 1538 removed.push(this.get(leftKey)); |
1539 } | 1539 } |
1540 while (rightIndex < rightKeys.length) { | 1540 while (rightIndex < rightKeys.length) { |
1541 var rightKey = rightKeys[rightIndex++]; | 1541 var rightKey = rightKeys[rightIndex++]; |
1542 added.push(other.get(rightKey)); | 1542 added.push(other.get(rightKey)); |
1543 } | 1543 } |
1544 return { | 1544 return { |
1545 added: added, | 1545 added: added, |
1546 removed: removed, | 1546 removed: removed, |
1547 equal: equal | 1547 equal: equal |
1548 } | 1548 }; |
1549 } | 1549 }; |
OLD | NEW |