@@ -11,6 +11,7 @@ import Memory from "runtime/unsafe/memory"
1111import Exception from "runtime/exception"
1212import Conv from "runtime/unsafe/conv"
1313import {
14+ untagSimpleNumber,
1415 tagSimpleNumber,
1516 tagChar,
1617 untagChar,
@@ -100,7 +101,7 @@ export let byteLength = (string: String) => {
100101}
101102
102103/**
103- * Finds the position of a substring in the input string.
104+ * Finds the first position of a substring in the input string.
104105 *
105106 * @param search: The substring to find
106107 * @param string: The string to inspect
@@ -161,6 +162,65 @@ export let indexOf = (search: String, string: String) => {
161162 }
162163}
163164
165+ /**
166+ * Finds the last position of a substring in the input string.
167+ *
168+ * @param search: The substring to find
169+ * @param string: The string to inspect
170+ * @returns `Some(position)` containing the starting position of the substring if found or `None` otherwise
171+ *
172+ * @example String.lastIndexOf("world", "Hello world world") == Some(12)
173+ *
174+ * @since v0.5.3
175+ */
176+ @unsafe
177+ export let lastIndexOf = (search: String, string: String) => {
178+ // The last possible index in the string given the length of the search
179+ let lastIndex = length(string) - length(search)
180+
181+ let (>) = WasmI32.gtU
182+ let (>=) = WasmI32.geU
183+ let (==) = WasmI32.eq
184+ let (!=) = WasmI32.ne
185+ let (+) = WasmI32.add
186+ let (-) = WasmI32.sub
187+ let (&) = WasmI32.and
188+
189+ let search = WasmI32.fromGrain(search)
190+ let string = WasmI32.fromGrain(string)
191+ let searchSize = WasmI32.load(search, 4n)
192+ let stringSize = WasmI32.load(string, 4n)
193+ if (searchSize > stringSize) {
194+ None
195+ } else {
196+ let mut matchIndex = -1n
197+ let mut stringIndex = untagSimpleNumber(lastIndex)
198+ let searchPtr = search + 8n
199+ let stringStartPtr = string + 8n
200+ for (
201+ let mut stringPtr = stringStartPtr + stringSize - searchSize;
202+ stringPtr >= stringStartPtr;
203+ stringPtr -= 1n
204+ ) {
205+ let byte = WasmI32.load8U(stringPtr, 0n)
206+ if ((byte & 0xC0n) == 0x80n) {
207+ // We're not at the start of a codepoint, so move on
208+ continue
209+ }
210+ if (Memory.compare(stringPtr, searchPtr, searchSize) == 0n) {
211+ matchIndex = stringIndex
212+ break
213+ }
214+ stringIndex -= 1n
215+ }
216+ if (matchIndex == -1n) {
217+ None
218+ } else {
219+ Some(tagSimpleNumber(matchIndex))
220+ }
221+ }
222+ }
223+
164224@disableGC
165225let getCodePoint = (ptr: WasmI32) => {
166226 // Algorithm from https://encoding.spec.whatwg.org/#utf-8-decoder
0 commit comments