diff --git a/stdlib/string.gr b/stdlib/string.gr index a03b63c21f..44a0025519 100644 --- a/stdlib/string.gr +++ b/stdlib/string.gr @@ -63,8 +63,8 @@ export let concat = (++) * * @since v0.1.0 */ -@disableGC -export let rec length = (string: String) => { +@unsafe +export let length = (string: String) => { let string = WasmI32.fromGrain(string) let size = WasmI32.load(string, 4n) @@ -80,18 +80,7 @@ export let rec length = (string: String) => { ptr = WasmI32.add(ptr, 1n) } - let ret = Conv.wasmI32ToNumber(len) - Memory.decRef(WasmI32.fromGrain(length)) - Memory.decRef(WasmI32.fromGrain(string)) - ret -} - -// @disableGC-safe wrapper -@disableGC -let wasmSafeLength = (s: String) => { - Memory.incRef(WasmI32.fromGrain(length)) - Memory.incRef(WasmI32.fromGrain(s)) - length(s) + Conv.wasmI32ToNumber(len) } /** @@ -104,21 +93,10 @@ let wasmSafeLength = (s: String) => { * * @since v0.1.0 */ -@disableGC -export let rec byteLength = (string: String) => { +@unsafe +export let byteLength = (string: String) => { let string = WasmI32.fromGrain(string) - let ret = Conv.wasmI32ToNumber(WasmI32.load(string, 4n)) - Memory.decRef(WasmI32.fromGrain(byteLength)) - Memory.decRef(WasmI32.fromGrain(string)) - ret -} - -// @disableGC-safe wrapper -@disableGC -let wasmSafeByteLength = (string: String) => { - Memory.incRef(WasmI32.fromGrain(byteLength)) - Memory.incRef(WasmI32.fromGrain(string)) - byteLength(string) + Conv.wasmI32ToNumber(WasmI32.load(string, 4n)) } /** @@ -132,8 +110,8 @@ let wasmSafeByteLength = (string: String) => { * * @since v0.3.0 */ -@disableGC -export let rec indexOf = (search: String, string: String) => { +@unsafe +export let indexOf = (search: String, string: String) => { let search = WasmI32.fromGrain(search) let string = WasmI32.fromGrain(string) @@ -147,10 +125,8 @@ export let rec indexOf = (search: String, string: String) => { let (-) = WasmI32.sub let (&) = WasmI32.and - let ret = if (psize > size) { - let none = None - Memory.incRef(WasmI32.fromGrain(none)) - none + if (psize > size) { + None } else { let mut idx = 0n let mut ptr = string + 8n @@ -178,18 +154,11 @@ export let rec indexOf = (search: String, string: String) => { } if (result == -1n) { - let none = None - Memory.incRef(WasmI32.fromGrain(none)) - none + None } else { - Memory.incRef(WasmI32.fromGrain(Some)) Some(tagSimpleNumber(result)) } } - Memory.decRef(WasmI32.fromGrain(search)) - Memory.decRef(WasmI32.fromGrain(string)) - Memory.decRef(WasmI32.fromGrain(indexOf)) - ret } @disableGC @@ -263,18 +232,9 @@ let getCodePoint = (ptr: WasmI32) => { * * @since v0.4.0 */ -@disableGC -export let rec charAt = (position, string: String) => { - Memory.incRef(WasmI32.fromGrain((<=))) - if ( - wasmSafeLength(string) <= position || - { - Memory.incRef(WasmI32.fromGrain((<))) - position < 0 - } - ) { - Memory.incRef(WasmI32.fromGrain((++))) - Memory.incRef(WasmI32.fromGrain(toString)) +@unsafe +export let charAt = (position, string: String) => { + if (length(string) <= position || position < 0) { fail "Invalid offset: " ++ toString(position) } // Implementation is similar to explodeHelp, but doesn't perform unneeded memory allocations @@ -283,7 +243,7 @@ export let rec charAt = (position, string: String) => { let (&) = WasmI32.and let (<) = WasmI32.ltU let (==) = WasmI32.eq - let size = WasmI32.fromGrain(wasmSafeByteLength(string)) >>> 1n + let size = WasmI32.fromGrain(byteLength(string)) >>> 1n let position = WasmI32.fromGrain(position) >>> 1n let string = WasmI32.fromGrain(string) let mut ptr = string + 8n @@ -311,12 +271,10 @@ export let rec charAt = (position, string: String) => { if (WasmI32.eqz(WasmI32.fromGrain(result))) { fail "charAt: should be impossible (please report)" } - Memory.decRef(WasmI32.fromGrain(string)) - Memory.decRef(WasmI32.fromGrain(charAt)) result } -@disableGC +@unsafe let explodeHelp = (s: String, chars) => { let (>>>) = WasmI32.shrU let (+) = WasmI32.add @@ -324,8 +282,8 @@ let explodeHelp = (s: String, chars) => { let (<) = WasmI32.ltU let (==) = WasmI32.eq - let size = WasmI32.fromGrain(wasmSafeByteLength(s)) >>> 1n - let len = WasmI32.fromGrain(wasmSafeLength(s)) >>> 1n + let size = WasmI32.fromGrain(byteLength(s)) >>> 1n + let len = WasmI32.fromGrain(length(s)) >>> 1n let s = WasmI32.fromGrain(s) @@ -373,15 +331,9 @@ let explodeHelp = (s: String, chars) => { * * @since v0.3.0 */ -@disableGC -export let rec explode = string => { - // `explodeHelp` and `string` do not need to be incRef'd as they are not - // decRef'd in `explodeHelp` - let ret = WasmI32.toGrain(explodeHelp(string, true)): Array - - Memory.decRef(WasmI32.fromGrain(string)) - Memory.decRef(WasmI32.fromGrain(explode)) - ret +@unsafe +export let explode = string => { + WasmI32.toGrain(explodeHelp(string, true)): Array } /** @@ -395,7 +347,7 @@ export let rec explode = string => { * @since v0.3.0 */ @unsafe -export let rec implode = (arr: Array) => { +export let implode = (arr: Array) => { let (+) = WasmI32.add let (-) = WasmI32.sub let (*) = WasmI32.mul @@ -500,8 +452,8 @@ export let reverse = string => { * * @example String.split(" ", "Hello world") == [> "Hello", "world"] */ -@disableGC -export let rec split = (separator: String, string: String) => { +@unsafe +export let split = (separator: String, string: String) => { let (+) = WasmI32.add let (-) = WasmI32.sub let (==) = WasmI32.eq @@ -511,16 +463,13 @@ export let rec split = (separator: String, string: String) => { let (>>) = WasmI32.shrS let (&) = WasmI32.and - let size = WasmI32.fromGrain(wasmSafeByteLength(string)) >> 1n - let psize = WasmI32.fromGrain(wasmSafeByteLength(separator)) >> 1n + let size = WasmI32.fromGrain(byteLength(string)) >> 1n + let psize = WasmI32.fromGrain(byteLength(separator)) >> 1n - let ret = if (psize == 0n) { + if (psize == 0n) { WasmI32.toGrain(explodeHelp(string, false)): Array } else if (psize > size) { - let string = WasmI32.fromGrain(string) - let ptr = allocateArray(1n) - WasmI32.store(ptr, Memory.incRef(string), 8n) - WasmI32.toGrain(ptr): Array + [> string] } else { let string = WasmI32.fromGrain(string) let separator = WasmI32.fromGrain(separator) @@ -583,10 +532,6 @@ export let rec split = (separator: String, string: String) => { WasmI32.toGrain(arr): Array } - Memory.decRef(WasmI32.fromGrain(separator)) - Memory.decRef(WasmI32.fromGrain(string)) - Memory.decRef(WasmI32.fromGrain(split)) - ret } /** @@ -601,8 +546,8 @@ export let rec split = (separator: String, string: String) => { * * @since v0.1.0 */ -@disableGC -export let rec slice = (start: Number, to: Number, string: String) => { +@unsafe +export let slice = (start: Number, to: Number, string: String) => { let (+) = WasmI32.add let (-) = WasmI32.sub let (==) = WasmI32.eq @@ -615,8 +560,8 @@ export let rec slice = (start: Number, to: Number, string: String) => { let startOrig = start let toOrig = to - let len = WasmI32.fromGrain(wasmSafeLength(string)) >> 1n - let size = WasmI32.fromGrain(wasmSafeByteLength(string)) >> 1n + let len = WasmI32.fromGrain(length(string)) >> 1n + let size = WasmI32.fromGrain(byteLength(string)) >> 1n let string = WasmI32.fromGrain(string) @@ -679,12 +624,7 @@ export let rec slice = (start: Number, to: Number, string: String) => { Memory.copy(newString + 8n, begin, newSize) - let ret = WasmI32.toGrain(newString): String - Memory.decRef(WasmI32.fromGrain(startOrig)) - Memory.decRef(WasmI32.fromGrain(toOrig)) - Memory.decRef(WasmI32.fromGrain(string)) - Memory.decRef(WasmI32.fromGrain(slice)) - ret + WasmI32.toGrain(newString): String } /** @@ -698,8 +638,8 @@ export let rec slice = (start: Number, to: Number, string: String) => { * * @since v0.1.0 */ -@disableGC -export let rec contains = (search: String, string: String) => { +@unsafe +export let contains = (search: String, string: String) => { // "Not So Naive" string search algorithm // searching phase in O(nm) time complexity // slightly (by coefficient) sub-linear in the average case @@ -716,8 +656,8 @@ export let rec contains = (search: String, string: String) => { let pOrig = search let sOrig = string - let n = WasmI32.fromGrain(wasmSafeByteLength(string)) >> 1n - let m = WasmI32.fromGrain(wasmSafeByteLength(search)) >> 1n + let n = WasmI32.fromGrain(byteLength(string)) >> 1n + let m = WasmI32.fromGrain(byteLength(search)) >> 1n let mut string = WasmI32.fromGrain(string) let mut search = WasmI32.fromGrain(search) @@ -727,7 +667,7 @@ export let rec contains = (search: String, string: String) => { let mut j = 0n, k = 0n, ell = 0n - let ret = if (m > n) { + if (m > n) { // Bail if pattern length is longer than input length false } else if (m < 2n) { @@ -775,10 +715,6 @@ export let rec contains = (search: String, string: String) => { } result } - Memory.decRef(WasmI32.fromGrain(pOrig)) - Memory.decRef(WasmI32.fromGrain(sOrig)) - Memory.decRef(WasmI32.fromGrain(contains)) - ret } /** @@ -792,8 +728,8 @@ export let rec contains = (search: String, string: String) => { * * @since v0.1.0 */ -@disableGC -export let rec startsWith = (search: String, string: String) => { +@unsafe +export let startsWith = (search: String, string: String) => { let (+) = WasmI32.add let (>) = WasmI32.gtU let (==) = WasmI32.eq @@ -810,15 +746,11 @@ export let rec startsWith = (search: String, string: String) => { search += 8n // Bail if pattern length is longer than input length - let ret = if (m > n) { + if (m > n) { false } else { Memory.compare(search, string, m) == 0n } - Memory.decRef(WasmI32.fromGrain(pOrig)) - Memory.decRef(WasmI32.fromGrain(sOrig)) - Memory.decRef(WasmI32.fromGrain(startsWith)) - ret } /** @@ -832,8 +764,8 @@ export let rec startsWith = (search: String, string: String) => { * * @since v0.1.0 */ -@disableGC -export let rec endsWith = (search: String, string: String) => { +@unsafe +export let endsWith = (search: String, string: String) => { let (+) = WasmI32.add let (-) = WasmI32.sub let (>) = WasmI32.gtU @@ -851,15 +783,11 @@ export let rec endsWith = (search: String, string: String) => { search += 8n // Bail if pattern length is longer than input length - let ret = if (m > n) { + if (m > n) { false } else { Memory.compare(search, string + n - m, m) == 0n } - Memory.decRef(WasmI32.fromGrain(pOrig)) - Memory.decRef(WasmI32.fromGrain(sOrig)) - Memory.decRef(WasmI32.fromGrain(endsWith)) - ret } // String->Byte encoding and helper functions: @@ -869,30 +797,22 @@ let _START_NAME = "start" let _SIZE_NAME = "size" let _OFFSET_NAME = "offset" -@disableGC +@unsafe let grainToWasmNumber = (num, name) => { let num = WasmI32.fromGrain(num) if (WasmI32.eqz(WasmI32.and(num, 1n))) { - Memory.incRef(WasmI32.fromGrain(name)) - Memory.incRef(WasmI32.fromGrain((++))) let str = " argument must be an integer" - Memory.incRef(WasmI32.fromGrain(str)) - Memory.incRef(WasmI32.fromGrain(Exception.InvalidArgument)) throw Exception.InvalidArgument(name ++ str) } let num = WasmI32.shrS(num, 1n) if (WasmI32.ltS(num, 0n)) { - Memory.incRef(WasmI32.fromGrain(name)) - Memory.incRef(WasmI32.fromGrain((++))) let str = " argument must be non-negative" - Memory.incRef(WasmI32.fromGrain(str)) - Memory.incRef(WasmI32.fromGrain(Exception.InvalidArgument)) throw Exception.InvalidArgument(name ++ str) } num } -@disableGC +@unsafe let utf16Length = (s: String) => { let (>>>) = WasmI32.shrU let (<<) = WasmI32.shl @@ -901,8 +821,8 @@ let utf16Length = (s: String) => { let (<) = WasmI32.ltU let (==) = WasmI32.eq - let size = WasmI32.fromGrain(wasmSafeByteLength(s)) >>> 1n - let len = WasmI32.fromGrain(wasmSafeLength(s)) >>> 1n + let size = WasmI32.fromGrain(byteLength(s)) >>> 1n + let len = WasmI32.fromGrain(length(s)) >>> 1n let s = WasmI32.fromGrain(s) @@ -932,38 +852,24 @@ let utf16Length = (s: String) => { tagSimpleNumber(size << 1n) } -@disableGC +@unsafe let encodedLength = (s: String, encoding) => { match (encoding) { - UTF32_BE => { - Memory.incRef(WasmI32.fromGrain((*))) - wasmSafeLength(s) * 4 - }, - UTF32_LE => { - Memory.incRef(WasmI32.fromGrain((*))) - wasmSafeLength(s) * 4 - }, + UTF32_BE => length(s) * 4, + UTF32_LE => length(s) * 4, UTF16_BE => utf16Length(s), UTF16_LE => utf16Length(s), - UTF8 => wasmSafeByteLength(s), + UTF8 => byteLength(s), } } -// hack to avoid incRef on this pointer -@disableGC -let mut _BYTES_SIZE_OFFSET = 1n -@disableGC -let mut _BYTES_OFFSET = 1n - -@disableGC -let initPtr = () => { - _BYTES_SIZE_OFFSET = 4n - _BYTES_OFFSET = 8n -} -initPtr() +@unsafe +let mut _BYTES_SIZE_OFFSET = 4n +@unsafe +let mut _BYTES_OFFSET = 8n -@disableGC -let rec encodeAtHelp = +@unsafe +let encodeAtHelp = ( string: String, encoding: Encoding, @@ -979,8 +885,8 @@ let rec encodeAtHelp = let (<=) = WasmI32.leU let (==) = WasmI32.eq let (+) = WasmI32.add - let byteSize = WasmI32.fromGrain(wasmSafeByteLength(string)) >>> 1n - let len = WasmI32.fromGrain(wasmSafeLength(string)) >>> 1n + let byteSize = WasmI32.fromGrain(byteLength(string)) >>> 1n + let len = WasmI32.fromGrain(length(string)) >>> 1n let string = WasmI32.fromGrain(string) @@ -1213,13 +1119,6 @@ let rec encodeAtHelp = }, } - Memory.decRef(WasmI32.fromGrain(string)) - Memory.decRef(WasmI32.fromGrain(encoding)) - Memory.decRef(WasmI32.fromGrain(includeBom)) - Memory.decRef(WasmI32.fromGrain(destPos)) - Memory.decRef(WasmI32.fromGrain(encodeAtHelp)) - - // We don't decRef `dest` because we're returning it dest } @@ -1253,9 +1152,8 @@ export let encodeAtWithBom = (string, encoding, dest, destPos) => { encodeAtHelp(string, encoding, true, dest, destPos) } -@disableGC -let rec encodeHelp = (string: String, encoding: Encoding, includeBom: Bool) => { - Memory.incRef(WasmI32.fromGrain((+))) +@unsafe +let encodeHelp = (string: String, encoding: Encoding, includeBom: Bool) => { let size = encodedLength(string, encoding) + (if (includeBom) { match (encoding) { @@ -1270,17 +1168,7 @@ let rec encodeHelp = (string: String, encoding: Encoding, includeBom: Bool) => { }) let (>>>) = WasmI32.shrU let bytes = WasmI32.toGrain(allocateBytes(WasmI32.fromGrain(size) >>> 1n)) - Memory.incRef(WasmI32.fromGrain(encodeAtHelp)) - Memory.incRef(WasmI32.fromGrain(string)) - Memory.incRef(WasmI32.fromGrain(encoding)) - Memory.incRef(WasmI32.fromGrain(includeBom)) - Memory.incRef(WasmI32.fromGrain(bytes)) - let ret = encodeAtHelp(string, encoding, includeBom, bytes, 0) - Memory.decRef(WasmI32.fromGrain(string)) - Memory.decRef(WasmI32.fromGrain(encoding)) - Memory.decRef(WasmI32.fromGrain(includeBom)) - Memory.decRef(WasmI32.fromGrain(encodeHelp)) - ret + encodeAtHelp(string, encoding, includeBom, bytes, 0) } /** @@ -1311,7 +1199,7 @@ export let encodeWithBom = (string: String, encoding: Encoding) => { // Byte->String decoding and helper functions: -@disableGC +@unsafe let writeUtf8CodePoint = (ptr, codePoint) => { let (>>>) = WasmI32.shrU let (-) = WasmI32.sub @@ -1368,7 +1256,7 @@ let writeUtf8CodePoint = (ptr, codePoint) => { } } -@disableGC +@unsafe let bytesHaveBom = (bytes: Bytes, encoding: Encoding, start: WasmI32) => { let (+) = WasmI32.add let (==) = WasmI32.eq @@ -1410,7 +1298,7 @@ let bytesHaveBom = (bytes: Bytes, encoding: Encoding, start: WasmI32) => { } } -@disableGC +@unsafe let decodedLength = ( bytes: Bytes, @@ -1579,8 +1467,8 @@ let decodedLength = } } -@disableGC -let rec decodeRangeHelp = +@unsafe +let decodeRangeHelp = ( bytes: Bytes, encoding: Encoding, @@ -1625,7 +1513,7 @@ let rec decodeRangeHelp = UTF32_BE => 4n, } } - let ret = if (stringSize == 0n) { + if (stringSize == 0n) { WasmI32.toGrain(str): String } else { match (encoding) { @@ -1706,12 +1594,6 @@ let rec decodeRangeHelp = } WasmI32.toGrain(str): String } - // bytes: Bytes, encoding: Encoding, skipBom: Bool, start: Number, size: Number - Memory.decRef(WasmI32.fromGrain(bytes)) - Memory.decRef(WasmI32.fromGrain(encoding)) - Memory.decRef(WasmI32.fromGrain(skipBom)) - Memory.decRef(WasmI32.fromGrain(decodeRangeHelp)) - ret } /** @@ -1756,24 +1638,11 @@ export let decodeRangeKeepBom = decodeRangeHelp(bytes, encoding, false, start, size) } -@disableGC -let rec decodeHelp = (bytes: Bytes, encoding: Encoding, skipBom: Bool) => { +@unsafe +let decodeHelp = (bytes: Bytes, encoding: Encoding, skipBom: Bool) => { let bytesPtr = WasmI32.fromGrain(bytes) let bytesSize = WasmI32.load(bytesPtr, 4n) - Memory.incRef(WasmI32.fromGrain(decodeRangeHelp)) - Memory.incRef(WasmI32.fromGrain(bytes)) - Memory.incRef(WasmI32.fromGrain(encoding)) - let ret = decodeRangeHelp( - bytes, - encoding, - skipBom, - 0, - tagSimpleNumber(bytesSize) - ) - Memory.incRef(WasmI32.fromGrain(bytes)) - Memory.incRef(WasmI32.fromGrain(encoding)) - Memory.incRef(WasmI32.fromGrain(decodeHelp)) - ret + decodeRangeHelp(bytes, encoding, skipBom, 0, tagSimpleNumber(bytesSize)) } /** @@ -1812,8 +1681,8 @@ export let decodeKeepBom = (bytes: Bytes, encoding: Encoding) => { * * @since v0.4.0 */ -@disableGC -export let rec forEachCodePoint = (fn: Number -> Void, str: String) => { +@unsafe +export let forEachCodePoint = (fn: Number -> Void, str: String) => { let (>>>) = WasmI32.shrU let (-) = WasmI32.sub let (&) = WasmI32.and @@ -1850,15 +1719,11 @@ export let rec forEachCodePoint = (fn: Number -> Void, str: String) => { // avoid heap allocations. `getCodePoint` will throw // MalformedUnicode exception for values exceeding this limit. let codePoint = getCodePoint(ptr) - Memory.incRef(WasmI32.fromGrain(fn)) fn(tagSimpleNumber(codePoint)) ptr += codePointByteCount idx += 1n } - Memory.decRef(WasmI32.fromGrain(fn)) - Memory.decRef(WasmI32.fromGrain(str)) - Memory.decRef(WasmI32.fromGrain(forEachCodePoint)) void } @@ -1874,12 +1739,8 @@ export let rec forEachCodePoint = (fn: Number -> Void, str: String) => { * * @since v0.4.0 */ -@disableGC -export let rec forEachCodePointi = - ( - fn: (Number, Number) -> Void, - str: String, - ) => { +@unsafe +export let forEachCodePointi = (fn: (Number, Number) -> Void, str: String) => { let (>>>) = WasmI32.shrU let (-) = WasmI32.sub let (&) = WasmI32.and @@ -1916,17 +1777,14 @@ export let rec forEachCodePointi = // avoid heap allocations. `getCodePoint` will throw // MalformedUnicode exception for values exceeding this limit. let codePoint = getCodePoint(ptr) - Memory.incRef(WasmI32.fromGrain(fn)) fn(tagSimpleNumber(codePoint), tagSimpleNumber(idx)) ptr += codePointByteCount idx += 1n } - Memory.decRef(WasmI32.fromGrain(fn)) - Memory.decRef(WasmI32.fromGrain(str)) - Memory.decRef(WasmI32.fromGrain(forEachCodePointi)) void } + let trimString = (str: String, end: Bool) => { let chars = explode(str), charsLength = length(str) let mut i = 0, offset = 1