diff --git a/src/workerd/api/actor-state.c++ b/src/workerd/api/actor-state.c++ index 316be39cac5..db23d3a4c00 100644 --- a/src/workerd/api/actor-state.c++ +++ b/src/workerd/api/actor-state.c++ @@ -1010,7 +1010,7 @@ jsg::JsValue deserializeV8Value( kj::String actorId = getCurrentActorId().orDefault([]() { return kj::String(); }); KJ_FAIL_ASSERT("actor storage deserialization failed", "failed to deserialize stored value", actorId, exception.getHandle(js), key, buf.size(), - buf.slice(0, std::min(static_cast(3), buf.size()))); + buf.first(std::min(static_cast(3), buf.size()))); }); } catch (jsg::JsExceptionThrown&) { // We can occasionally hit an isolate termination here -- we prefix the error with jsg to avoid diff --git a/src/workerd/api/crypto/aes.c++ b/src/workerd/api/crypto/aes.c++ index 2704e2d8900..5ecf2ca6d1b 100644 --- a/src/workerd/api/crypto/aes.c++ +++ b/src/workerd/api/crypto/aes.c++ @@ -300,7 +300,7 @@ private: plainSize = 0; } - auto actualCipherText = cipherText.slice(0, cipherText.size() - tagLength / 8); + auto actualCipherText = cipherText.first(cipherText.size() - tagLength / 8); auto tagText = cipherText.slice(actualCipherText.size(), cipherText.size()); auto plainText = kj::heapArray(actualCipherText.size()); @@ -513,7 +513,7 @@ protected: // counter portion of the block back to zero. auto inputSizePart1 = BN_get_word(numBlocksUntilReset.get()) * AES_BLOCK_SIZE; - process(&cipher, data.slice(0, inputSizePart1), counter, result.asPtr()); + process(&cipher, data.first(inputSizePart1), counter, result.asPtr()); // Zero the counter bits of the block. Chromium creates a copy but we own our buffer. { diff --git a/src/workerd/api/crypto/digest.c++ b/src/workerd/api/crypto/digest.c++ index 08a11db1109..16674c13975 100644 --- a/src/workerd/api/crypto/digest.c++ +++ b/src/workerd/api/crypto/digest.c++ @@ -72,7 +72,7 @@ private: if (format == "jwk") { // This assert enforces that the slice logic to fill in `.alg` below is safe. - JSG_REQUIRE(keyAlgorithm.hash.name.slice(0, 4) == "SHA-"_kj, DOMNotSupportedError, + JSG_REQUIRE(keyAlgorithm.hash.name.first(4) == "SHA-"_kj, DOMNotSupportedError, "Unimplemented JWK key export format for key algorithm \"", keyAlgorithm.hash.name, "\"."); diff --git a/src/workerd/api/crypto/ec.c++ b/src/workerd/api/crypto/ec.c++ index c78ce6f016e..2613f31c610 100644 --- a/src/workerd/api/crypto/ec.c++ +++ b/src/workerd/api/crypto/ec.c++ @@ -338,7 +338,7 @@ public: return nullptr; } - auto r = signature.slice(0, rsSize); + auto r = signature.first(rsSize); auto s = signature.slice(rsSize, signature.size()); // Trim leading zeros. diff --git a/src/workerd/api/crypto/keys.c++ b/src/workerd/api/crypto/keys.c++ index e5fff2a9d63..d313275adf6 100644 --- a/src/workerd/api/crypto/keys.c++ +++ b/src/workerd/api/crypto/keys.c++ @@ -255,7 +255,7 @@ kj::Array AsymmetricKeyCryptoKeyImpl::sign( KJ_ASSERT(signatureSize <= signature.size()); if (signatureSize < signature.size()) { - signature = kj::heapArray(signature.slice(0, signatureSize)); + signature = kj::heapArray(signature.first(signatureSize)); } return signatureSslToWebCrypto(kj::mv(signature)); diff --git a/src/workerd/api/crypto/rsa.c++ b/src/workerd/api/crypto/rsa.c++ index 656b76b63cf..80b2c8d256b 100644 --- a/src/workerd/api/crypto/rsa.c++ +++ b/src/workerd/api/crypto/rsa.c++ @@ -168,7 +168,7 @@ kj::Array Rsa::sign(const kj::ArrayPtr data) const { // We did not fill the entire buffer, let's make sure we zero // out the rest of it so we don't leak any uninitialized data. signature.slice(signatureSize).fill(0); - return signature.slice(0, signatureSize).attach(kj::mv(signature)); + return signature.first(signatureSize).attach(kj::mv(signature)); } return kj::mv(signature); diff --git a/src/workerd/api/eventsource.c++ b/src/workerd/api/eventsource.c++ index 1e69c8e68fa..5384ebd4879 100644 --- a/src/workerd/api/eventsource.c++ +++ b/src/workerd/api/eventsource.c++ @@ -48,7 +48,7 @@ public: KJ_IF_SOME(found, findEndOfLine(input)) { auto prefix = kept.releaseAsArray(); // Feed the line into the processor. - feed(kj::str(prefix, input.slice(0, found.pos))); + feed(kj::str(prefix, input.first(found.pos))); input = found.remaining; // If we've reached the end of the input, input will == nullptr here. } else { @@ -168,7 +168,7 @@ private: }; KJ_IF_SOME(pos, line.findFirst(':')) { - handle(*this, line.slice(0, pos), line.slice(pos + 1)); + handle(*this, line.first(pos), line.slice(pos + 1)); } else { handle(*this, line, ""_kjc); } diff --git a/src/workerd/api/form-data.c++ b/src/workerd/api/form-data.c++ index aa5f07c3a00..05e86eebfec 100644 --- a/src/workerd/api/form-data.c++ +++ b/src/workerd/api/form-data.c++ @@ -122,7 +122,7 @@ void parseFormData(kj::Maybe js, // // TODO(soon): Read the Content-Type to support files. - auto headersText = kj::str(body.slice(0, match[0].second - body.begin())); + auto headersText = kj::str(body.first(match[0].second - body.begin())); body = body.slice(match[0].second - body.begin(), body.size()); kj::HttpHeaders headers(*formDataHeaderTable.table); @@ -163,7 +163,7 @@ void parseFormData(kj::Maybe js, if (message.size() > 0) { // If we skipped a CR, we must avoid including it in the message data. - message = message.slice(0, message.size() - uint(message.back() == '\r')); + message = message.first(message.size() - uint(message.back() == '\r')); } if (filename == kj::none || convertFilesToStrings) { diff --git a/src/workerd/api/global-scope.c++ b/src/workerd/api/global-scope.c++ index b04b9c9b142..44ca2649cce 100644 --- a/src/workerd/api/global-scope.c++ +++ b/src/workerd/api/global-scope.c++ @@ -675,7 +675,7 @@ jsg::JsString ServiceWorkerGlobalScope::btoa(jsg::Lock& js, jsg::JsValue data) { auto result = kj::heapArray(expected_length); auto written = simdutf::binary_to_base64( strArray.asChars().begin(), strArray.size(), result.asChars().begin()); - return js.str(result.slice(0, written).attach(kj::mv(result))); + return js.str(result.first(written).attach(kj::mv(result))); } jsg::JsString ServiceWorkerGlobalScope::atob(jsg::Lock& js, kj::String data) { auto decoded = kj::decodeBase64(data.asArray()); diff --git a/src/workerd/api/http.c++ b/src/workerd/api/http.c++ index 41f50a00527..a8e0fb1708d 100644 --- a/src/workerd/api/http.c++ +++ b/src/workerd/api/http.c++ @@ -85,7 +85,7 @@ jsg::ByteString normalizeHeaderValue(jsg::ByteString value) { slice = slice.slice(1, slice.size()); } while (slice.size() > 0 && isHttpWhitespace(slice.back())) { - slice = slice.slice(0, slice.size() - 1); + slice = slice.first(slice.size() - 1); } if (slice.size() == value.size()) { return kj::mv(value); diff --git a/src/workerd/api/http.h b/src/workerd/api/http.h index 8d02b7eec73..85b0ebfeaf0 100644 --- a/src/workerd/api/http.h +++ b/src/workerd/api/http.h @@ -293,7 +293,7 @@ class Body: public jsg::Object { : ownBytes(kj::refcounted(string.releaseArray().releaseAsBytes())), view([this] { auto bytesIncludingNull = ownBytes.get>()->bytes.asPtr(); - return bytesIncludingNull.slice(0, bytesIncludingNull.size() - 1); + return bytesIncludingNull.first(bytesIncludingNull.size() - 1); }()) {} Buffer(jsg::Ref blob) : ownBytes(kj::mv(blob)), diff --git a/src/workerd/api/node/buffer.c++ b/src/workerd/api/node/buffer.c++ index d503af6f774..6bce7f1221f 100644 --- a/src/workerd/api/node/buffer.c++ +++ b/src/workerd/api/node/buffer.c++ @@ -40,7 +40,7 @@ kj::Array decodeHexTruncated(kj::ArrayPtr text, bool strict = fa if (strict) { JSG_FAIL_REQUIRE(TypeError, "The text is not valid hex"); } - text = text.slice(0, text.size() - 1); + text = text.first(text.size() - 1); } auto vec = kj::Vector(text.size() / 2); @@ -159,7 +159,7 @@ kj::Array decodeStringImpl( auto len = result.written; auto dest = kj::heapArray(nbytes::Base64DecodedSize(buf.begin(), len)); len = nbytes::Base64Decode(dest.asChars().begin(), dest.size(), buf.begin(), buf.size()); - return dest.slice(0, len).attach(kj::mv(dest)); + return dest.first(len).attach(kj::mv(dest)); } case Encoding::HEX: { KJ_STACK_ARRAY(kj::byte, buf, length, 1024, 536870888); diff --git a/src/workerd/api/node/i18n.c++ b/src/workerd/api/node/i18n.c++ index fcad92d27b3..22f2262b954 100644 --- a/src/workerd/api/node/i18n.c++ +++ b/src/workerd/api/node/i18n.c++ @@ -60,7 +60,7 @@ kj::Maybe> TranscodeDefault( ucnv_convertEx(to.conv(), from.conv(), &target, target + limit, &source_, source_ + source.size(), nullptr, nullptr, nullptr, nullptr, true, true, &status); if (U_SUCCESS(status)) { - return out.slice(0, target - out.asChars().begin()).attach(kj::mv(out)); + return out.first(target - out.asChars().begin()).attach(kj::mv(out)); } return kj::none; @@ -82,7 +82,7 @@ kj::Maybe> TranscodeLatin1ToUTF16( return kj::none; } - return destbuf.slice(0, actual_length).asBytes().attach(kj::mv(destbuf)); + return destbuf.first(actual_length).asBytes().attach(kj::mv(destbuf)); } kj::Maybe> TranscodeFromUTF16( @@ -105,7 +105,7 @@ kj::Maybe> TranscodeFromUTF16( utf16_input.begin(), utf16_input.size(), &status); if (U_SUCCESS(status)) { - return destbuf.slice(0, len).asBytes().attach(kj::mv(destbuf)); + return destbuf.first(len).asBytes().attach(kj::mv(destbuf)); } return kj::none; diff --git a/src/workerd/api/streams/internal.c++ b/src/workerd/api/streams/internal.c++ index be19bb8c165..c451d9d3b7a 100644 --- a/src/workerd/api/streams/internal.c++ +++ b/src/workerd/api/streams/internal.c++ @@ -163,7 +163,7 @@ private: // In which case we want to add that subset to the parts list here before we exit // the loop. if (amount > 0) { - parts.add(bytes.slice(0, amount).attach(kj::mv(bytes))); + parts.add(bytes.first(amount).attach(kj::mv(bytes))); } break; } diff --git a/src/workerd/api/streams/standard.c++ b/src/workerd/api/streams/standard.c++ index 6355328a28d..86c1994f66b 100644 --- a/src/workerd/api/streams/standard.c++ +++ b/src/workerd/api/streams/standard.c++ @@ -2654,7 +2654,7 @@ public: jsg::Promise allText(jsg::Lock& js) { return loop(js).then(js, [this](auto& js, PartList&& partPtrs) { auto out = kj::heapArray(runningTotal + 1); - copyInto(out.slice(0, out.size() - 1).asBytes(), kj::mv(partPtrs)); + copyInto(out.first(out.size() - 1).asBytes(), kj::mv(partPtrs)); out.back() = '\0'; return kj::String(kj::mv(out)); }); diff --git a/src/workerd/api/streams/writable.c++ b/src/workerd/api/streams/writable.c++ index f8777392bc1..85478c0c014 100644 --- a/src/workerd/api/streams/writable.c++ +++ b/src/workerd/api/streams/writable.c++ @@ -469,7 +469,7 @@ public: KJ_DASSERT(ptr.size() > 0); KJ_DASSERT(piece.size() <= ptr.size()); if (piece.size() == 0) continue; - ptr.slice(0, piece.size()).copyFrom(piece); + ptr.first(piece.size()).copyFrom(piece); ptr = ptr.slice(piece.size()); } diff --git a/src/workerd/api/url.c++ b/src/workerd/api/url.c++ index 1142eab3868..9f710634eef 100644 --- a/src/workerd/api/url.c++ +++ b/src/workerd/api/url.c++ @@ -69,11 +69,11 @@ void normalizePort(kj::Url& url) { KJ_IF_SOME(colon, url.host.findFirst(':')) { if (url.host.size() == colon + 1) { // Remove trailing ':'. - url.host = kj::str(url.host.slice(0, colon)); + url.host = kj::str(url.host.first(colon)); } else KJ_IF_SOME(defaultPort, defaultPortForScheme(url.scheme)) { if (defaultPort == url.host.slice(colon + 1)) { // Remove scheme-default port. - url.host = kj::str(url.host.slice(0, colon)); + url.host = kj::str(url.host.first(colon)); } } } @@ -84,7 +84,7 @@ kj::Maybe> trySplit(kj::ArrayPtr& text, cha for (auto i: kj::indices(text)) { if (text[i] == c) { - kj::ArrayPtr result = text.slice(0, i); + kj::ArrayPtr result = text.first(i); text = text.slice(i + 1, text.size()); return result; } @@ -97,7 +97,7 @@ kj::ArrayPtr split(kj::StringPtr& text, const kj::parse::CharGroup_& for (auto i: kj::indices(text)) { if (chars.contains(text[i])) { - kj::ArrayPtr result = text.slice(0, i); + kj::ArrayPtr result = text.first(i); text = text.slice(i); return result; } @@ -239,7 +239,7 @@ kj::String URL::getProtocol() { } void URL::setProtocol(kj::String value) { KJ_IF_SOME(colon, value.findFirst(':')) { - value = kj::str(value.slice(0, colon)); + value = kj::str(value.first(colon)); } auto copy = url->clone(); @@ -333,14 +333,14 @@ void URL::setHost(kj::String value) { kj::String URL::getHostname() { KJ_IF_SOME(colon, url->host.findFirst(':')) { - return kj::str(url->host.slice(0, colon)); + return kj::str(url->host.first(colon)); } return kj::str(url->host); } void URL::setHostname(kj::String value) { // In contrast to the host setter, the hostname setter explicitly ignores any new port. We take // the hostname from the new value and the port from the old value. - auto hostnameString = value.slice(0, value.findFirst(':').orDefault(value.size())); + auto hostnameString = value.first(value.findFirst(':').orDefault(value.size())); auto portString = url->host.slice(url->host.findFirst(':').orDefault(url->host.size())); url->host = kj::str(hostnameString, portString); @@ -355,7 +355,7 @@ kj::String URL::getPort() { void URL::setPort(kj::String value) { KJ_IF_SOME(colon, url->host.findFirst(':')) { // Our url's host already has a port. Replace it. - value = kj::str(url->host.slice(0, colon + 1), kj::mv(value)); + value = kj::str(url->host.first(colon + 1), kj::mv(value)); } else { value = kj::str(url->host, ':', kj::mv(value)); } diff --git a/src/workerd/api/urlpattern.c++ b/src/workerd/api/urlpattern.c++ index 4e2a5f5351e..04f911c2141 100644 --- a/src/workerd/api/urlpattern.c++ +++ b/src/workerd/api/urlpattern.c++ @@ -197,7 +197,7 @@ kj::Maybe URLPattern::exec( return s.asPtr(); }))) { auto p = url.getProtocol(); - protocol = kj::str(p.slice(0, p.size() - 1)); + protocol = kj::str(p.first(p.size() - 1)); username = kj::str(url.getUsername()); password = kj::str(url.getPassword()); hostname = kj::str(url.getHostname()); diff --git a/src/workerd/api/util.c++ b/src/workerd/api/util.c++ index e99c1faf05c..4649c2a6fad 100644 --- a/src/workerd/api/util.c++ +++ b/src/workerd/api/util.c++ @@ -19,7 +19,7 @@ kj::ArrayPtr split(kj::ArrayPtr& text, char c) { for (auto i: kj::indices(text)) { if (text[i] == c) { - kj::ArrayPtr result = text.slice(0, i); + kj::ArrayPtr result = text.first(i); text = text.slice(i + 1, text.size()); return result; } @@ -235,7 +235,7 @@ kj::Array fastEncodeUtf16(kj::ArrayPtr bytes) { auto output = kj::heapArray(expected_length); auto actual_length = simdutf::convert_utf8_to_utf16(bytes.asChars().begin(), bytes.size(), output.begin()); - return output.slice(0, actual_length).attach(kj::mv(output)); + return output.first(actual_length).attach(kj::mv(output)); } } // namespace workerd::api diff --git a/src/workerd/io/trace.h b/src/workerd/io/trace.h index 0956bb0e3ed..f4c3142946c 100644 --- a/src/workerd/io/trace.h +++ b/src/workerd/io/trace.h @@ -449,7 +449,7 @@ class WorkerTracer final: public kj::Refcounted { // Helper function used when setting "truncated_script_id" tags. Truncates the scriptId to 10 // characters. inline kj::String truncateScriptId(kj::StringPtr id) { - auto truncatedId = id.slice(0, kj::min(id.size(), 10)); + auto truncatedId = id.first(kj::min(id.size(), 10)); return kj::str(truncatedId); } diff --git a/src/workerd/jsg/modules-new-test.c++ b/src/workerd/jsg/modules-new-test.c++ index 848f69a3284..8008d8d57c6 100644 --- a/src/workerd/jsg/modules-new-test.c++ +++ b/src/workerd/jsg/modules-new-test.c++ @@ -754,11 +754,11 @@ KJ_TEST("Attaching a module registry works") { ModuleBundle::BundleBuilder bundleBuilder; kj::String source = kj::str("export default 123; export const m = 'abc';"); // Done this way to avoid including the nullptr at the end... - bundleBuilder.addEsmModule("main", source.slice(0, source.size()).attach(kj::mv(source))); + bundleBuilder.addEsmModule("main", source.first(source.size()).attach(kj::mv(source))); kj::String mainSource = kj::str("import foo from 'main'; export default foo;"); bundleBuilder.addEsmModule("worker1", - mainSource.slice(0, mainSource.size()).attach(kj::mv(mainSource)), Module::Flags::MAIN); + mainSource.first(mainSource.size()).attach(kj::mv(mainSource)), Module::Flags::MAIN); registryBuilder.add(bundleBuilder.finish()); @@ -814,7 +814,7 @@ KJ_TEST("Basic types of modules work (text, data, json, wasm)") { auto json = kj::str("{\"foo\":123}"); bundleBuilder.addSyntheticModule( - "json", Module::newJsonModuleHandler(json.slice(0, json.size()).attach(kj::mv(json)))); + "json", Module::newJsonModuleHandler(json.first(json.size()).attach(kj::mv(json)))); auto wasm = kj::heapArray({ 0x00, @@ -868,7 +868,7 @@ KJ_TEST("Basic types of modules work (text, data, json, wasm)") { "export { default as wasm2 } from 'wasm?a';"); bundleBuilder.addEsmModule("worker", - mainSource2.slice(0, mainSource2.size()).attach(kj::mv(mainSource2)), Module::Flags::MAIN); + mainSource2.first(mainSource2.size()).attach(kj::mv(mainSource2)), Module::Flags::MAIN); registryBuilder.add(bundleBuilder.finish()); @@ -949,7 +949,7 @@ KJ_TEST("compileEvalFunction in synthetic module works") { auto source = kj::str("import 'abc'"); bundleBuilder.addEsmModule( - "main", source.slice(0, source.size()).attach(kj::mv(source)), Module::Flags::MAIN); + "main", source.first(source.size()).attach(kj::mv(source)), Module::Flags::MAIN); auto registry = ModuleRegistry::Builder(resolveObserver).add(bundleBuilder.finish()).finish(); @@ -971,10 +971,10 @@ KJ_TEST("import.meta works as expected") { ModuleBundle::BundleBuilder bundleBuilder; auto foo = kj::str("export default import.meta"); - bundleBuilder.addEsmModule("foo", foo.slice(0, foo.size()).attach(kj::mv(foo))); + bundleBuilder.addEsmModule("foo", foo.first(foo.size()).attach(kj::mv(foo))); auto bar = kj::str("export default import.meta"); bundleBuilder.addEsmModule( - "foo/././././bar", bar.slice(0, bar.size()).attach(kj::mv(bar)), Module::Flags::MAIN); + "foo/././././bar", bar.first(bar.size()).attach(kj::mv(bar)), Module::Flags::MAIN); auto registry = ModuleRegistry::Builder(ResolveObserver).add(bundleBuilder.finish()).finish(); auto attached = registry->attachToIsolate(js, compilationObserver); @@ -1040,7 +1040,7 @@ KJ_TEST("import specifiers with query params and hash fragments work") { ModuleBundle::BundleBuilder bundleBuilder; auto foo = kj::str("export default import.meta"); - bundleBuilder.addEsmModule("foo", foo.slice(0, foo.size()).attach(kj::mv(foo))); + bundleBuilder.addEsmModule("foo", foo.first(foo.size()).attach(kj::mv(foo))); auto registry = ModuleRegistry::Builder(ResolveObserver).add(bundleBuilder.finish()).finish(); @@ -1084,7 +1084,7 @@ KJ_TEST("Previously resolved modules not found with incompatible resolve context const auto foo = "foo:bar"_url; auto source = "export default 123;"_kjc; - builtinBuilder.addEsm(foo, source.slice(0, source.size()).attach(kj::mv(source))); + builtinBuilder.addEsm(foo, source.first(source.size()).attach(kj::mv(source))); ModuleBundle::BundleBuilder bundleBuilder; bundleBuilder.addSyntheticModule( @@ -1138,10 +1138,10 @@ KJ_TEST("Awaiting top-level dynamic import in synchronous require works as expec ModuleBundle::BundleBuilder bundleBuilder; auto foo = kj::str("export default (await import('bar')).default;"); - bundleBuilder.addEsmModule("foo", foo.slice(0, foo.size()).attach(kj::mv(foo))); + bundleBuilder.addEsmModule("foo", foo.first(foo.size()).attach(kj::mv(foo))); auto bar = kj::str("export default 123;"); - bundleBuilder.addEsmModule("bar", bar.slice(0, bar.size()).attach(kj::mv(bar))); + bundleBuilder.addEsmModule("bar", bar.first(bar.size()).attach(kj::mv(bar))); auto registry = ModuleRegistry::Builder(observer).add(bundleBuilder.finish()).finish(); @@ -1160,7 +1160,7 @@ KJ_TEST("Awaiting a never resolved promise in synchronous require fails as expec ModuleBundle::BundleBuilder bundleBuilder; auto foo = kj::str("const p = new Promise(() => {}); await p;"); - bundleBuilder.addEsmModule("foo", foo.slice(0, foo.size()).attach(kj::mv(foo))); + bundleBuilder.addEsmModule("foo", foo.first(foo.size()).attach(kj::mv(foo))); auto registry = ModuleRegistry::Builder(observer).add(bundleBuilder.finish()).finish(); @@ -1188,7 +1188,7 @@ KJ_TEST("Throwing an exception inside a ESM module works as expected") { ModuleBundle::BundleBuilder bundleBuilder; auto foo = kj::str("throw new Error('foo');"); - bundleBuilder.addEsmModule("foo", foo.slice(0, foo.size()).attach(kj::mv(foo))); + bundleBuilder.addEsmModule("foo", foo.first(foo.size()).attach(kj::mv(foo))); auto registry = ModuleRegistry::Builder(observer).add(bundleBuilder.finish()).finish(); @@ -1214,7 +1214,7 @@ KJ_TEST("Syntax error in ESM module is properly reported") { ModuleBundle::BundleBuilder bundleBuilder; auto foo = kj::str("export default 123; syntax error"); - bundleBuilder.addEsmModule("foo", foo.slice(0, foo.size()).attach(kj::mv(foo))); + bundleBuilder.addEsmModule("foo", foo.first(foo.size()).attach(kj::mv(foo))); auto registry = ModuleRegistry::Builder(observer).add(bundleBuilder.finish()).finish(); @@ -1264,11 +1264,11 @@ KJ_TEST("Invalid JSON syntax module throws exception as expected") { ModuleBundle::BundleBuilder bundleBuilder; auto json = kj::str("not valid json"); bundleBuilder.addSyntheticModule( - "foo", Module::newJsonModuleHandler(json.slice(0, json.size()).attach(kj::mv(json)))); + "foo", Module::newJsonModuleHandler(json.first(json.size()).attach(kj::mv(json)))); auto esm = kj::str("import foo from 'foo'"); bundleBuilder.addEsmModule( - "bar", esm.slice(0, esm.size()).attach(kj::mv(esm)), Module::Flags::MAIN); + "bar", esm.first(esm.size()).attach(kj::mv(esm)), Module::Flags::MAIN); auto registry = ModuleRegistry::Builder(observer).add(bundleBuilder.finish()).finish(); @@ -1313,7 +1313,7 @@ KJ_TEST("Recursive import works or fails as expected") { // A recursive import with an ESM works just fine... auto foo = kj::str("import foo from 'foo'; export default 123;"); - bundleBuilder.addEsmModule("foo", foo.slice(0, foo.size()).attach(kj::mv(foo))); + bundleBuilder.addEsmModule("foo", foo.first(foo.size()).attach(kj::mv(foo))); // A CommonJS-style module, however, does not allow recursive evaluation. bundleBuilder.addSyntheticModule("bar", @@ -1354,7 +1354,7 @@ KJ_TEST("Recursively require ESM from CJS required from ESM fails as expected (d kj::str("exports = require('bar');"), kj::str("foo"))); auto bar = kj::str("export default 123; await import('foo');"); - bundleBuilder.addEsmModule("bar", bar.slice(0, bar.size()).attach(kj::mv(bar))); + bundleBuilder.addEsmModule("bar", bar.first(bar.size()).attach(kj::mv(bar))); auto registry = ModuleRegistry::Builder(observer).add(bundleBuilder.finish()).finish(); @@ -1390,7 +1390,7 @@ KJ_TEST("Recursively require ESM from CJS required from ESM fails as expected (s kj::str("exports = require('bar');"), kj::str("foo"))); auto bar = kj::str("export default 123; import bar from 'foo';"); - bundleBuilder.addEsmModule("bar", bar.slice(0, bar.size()).attach(kj::mv(bar))); + bundleBuilder.addEsmModule("bar", bar.first(bar.size()).attach(kj::mv(bar))); auto registry = ModuleRegistry::Builder(observer).add(bundleBuilder.finish()).finish(); @@ -1428,7 +1428,7 @@ KJ_TEST("Resolution occurs relative to the referrer") { "export * as ghi from '../bar';" // file:///bar "export * as jkl from '/bar';" // file:///bar "export * as lmn from '../foo/bar';"); // file:///foo/bar - builder.addEsmModule("foo/", bar.slice(0, bar.size()).attach(kj::mv(bar))); + builder.addEsmModule("foo/", bar.first(bar.size()).attach(kj::mv(bar))); auto registry = registryBuilder.add(builder.finish()).finish(); @@ -1580,7 +1580,7 @@ KJ_TEST("Using a registry from multiple threads works") { ModuleBundle::BundleBuilder bundleBuilder; auto foo = kj::str("export default 123; for (let n = 0; n < 1000000; n++) {}"); - bundleBuilder.addEsmModule("foo", foo.slice(0, foo.size()).attach(kj::mv(foo))); + bundleBuilder.addEsmModule("foo", foo.first(foo.size()).attach(kj::mv(foo))); ResolveObserver resolveObserver; auto registry = ModuleRegistry::Builder(resolveObserver).add(bundleBuilder.finish()).finish(); @@ -1716,7 +1716,7 @@ KJ_TEST("Percent-encoding in specifiers is normalized properly") { "export { default as def } from 'foo/bar';" "export { default as ghi } from '%66oo/bar';" "export { default as jkl } from '%66oo%2fbar';"); - builder.addEsmModule("foo", foo.slice(0, foo.size()).attach(kj::mv(foo))); + builder.addEsmModule("foo", foo.first(foo.size()).attach(kj::mv(foo))); auto registry = ModuleRegistry::Builder(resolveObserver).add(builder.finish()).finish(); @@ -1763,7 +1763,7 @@ KJ_TEST("Aliased modules (import maps) work") { auto src = kj::str("export { default as abc } from 'bar';" "export { default as def } from 'http://example/%66oo';"); - builder.addEsmModule("qux", src.slice(0, src.size()).attach(kj::mv(src))); + builder.addEsmModule("qux", src.first(src.size()).attach(kj::mv(src))); auto registry = ModuleRegistry::Builder(resolveObserver).add(builder.finish()).finish(); @@ -1812,7 +1812,7 @@ KJ_TEST("Import attributes are currently unsupported") { ModuleBundle::BundleBuilder builder; auto foo = kj::str("import abc from 'foo' with { type: 'json' };"); - builder.addEsmModule("foo", foo.slice(0, foo.size()).attach(kj::mv(foo))); + builder.addEsmModule("foo", foo.first(foo.size()).attach(kj::mv(foo))); auto registry = ModuleRegistry::Builder(resolveObserver).add(builder.finish()).finish(); @@ -1836,7 +1836,7 @@ KJ_TEST("Using a deferred eval callback works") { ModuleBundle::BundleBuilder builder; auto foo = kj::str("export default 1;"); - builder.addEsmModule("foo", foo.slice(0, foo.size()).attach(kj::mv(foo))); + builder.addEsmModule("foo", foo.first(foo.size()).attach(kj::mv(foo))); bool called = false; auto registry = ModuleRegistry::Builder(resolveObserver) diff --git a/src/workerd/jsg/url-test.c++ b/src/workerd/jsg/url-test.c++ index cdd9ef8dd12..a8f8bdfa055 100644 --- a/src/workerd/jsg/url-test.c++ +++ b/src/workerd/jsg/url-test.c++ @@ -1367,8 +1367,7 @@ KJ_TEST("URLPattern - MDN example 3 - pathname: '/books/:id(\\d+)' with base") { KJ_CASE_ONEOF(pattern, UrlPattern) { auto url = KJ_ASSERT_NONNULL(Url::tryParse("https://example.com/books/123"_kj)); auto protocol = url.getProtocol(); - KJ_ASSERT( - testPattern(pattern.getProtocol().getRegex(), protocol.slice(0, protocol.size() - 1))); + KJ_ASSERT(testPattern(pattern.getProtocol().getRegex(), protocol.first(protocol.size() - 1))); KJ_ASSERT(testPattern(pattern.getHostname().getRegex(), url.getHostname())); KJ_ASSERT(testPattern( pattern.getPathname().getRegex(), url.getPathname(), kj::arr(kj::str("123")))); @@ -1922,7 +1921,7 @@ KJ_TEST("URLPattern - simple fuzzing") { kj::Array bufs = kj::heapArray(9 * n); RAND_bytes(bufs.begin(), 9 * n); // We don't care if the compiling passes or fails, we just don't want crashes. - KJ_SWITCH_ONEOF(UrlPattern::tryCompile({.protocol = kj::str(bufs.slice(0, n)), + KJ_SWITCH_ONEOF(UrlPattern::tryCompile({.protocol = kj::str(bufs.first(n)), .username = kj::str(bufs.slice(n, n * 2)), .password = kj::str(bufs.slice(n * 2, n * 3)), .hostname = kj::str(bufs.slice(n * 3, n * 4)), diff --git a/src/workerd/jsg/url.c++ b/src/workerd/jsg/url.c++ index 4f516915361..a9b6f3c88b0 100644 --- a/src/workerd/jsg/url.c++ +++ b/src/workerd/jsg/url.c++ @@ -539,7 +539,7 @@ kj::Maybe canonicalizeProtocol( auto input = kj::str(protocol, "://dummy.test"); KJ_IF_SOME(url, Url::tryParse(input.asPtr())) { auto result = url.getProtocol(); - return kj::str(result.slice(0, result.size() - 1)); + return kj::str(result.first(result.size() - 1)); } return kj::none; } @@ -644,7 +644,7 @@ kj::Maybe chooseStr(kj::Maybe str, kj::Maybe data) { if (data.back() == ':') { - return kj::str(data.slice(0, data.size() - 1)); + return kj::str(data.first(data.size() - 1)); } return kj::str(data); } @@ -2079,7 +2079,7 @@ UrlPattern::Result UrlPattern::processInit( KJ_IF_SOME(url, maybeBaseUrl) { auto basePathname = url.getPathname(); KJ_IF_SOME(index, basePathname.findLast('/')) { - result.pathname = kj::str(basePathname.slice(0, index + 1), pathname); + result.pathname = kj::str(basePathname.first(index + 1), pathname); } else { result.pathname = kj::str(basePathname); } diff --git a/src/workerd/jsg/util.c++ b/src/workerd/jsg/util.c++ index 889bcdc697b..a1634a0da56 100644 --- a/src/workerd/jsg/util.c++ +++ b/src/workerd/jsg/util.c++ @@ -84,7 +84,7 @@ kj::String typeName(const std::type_info& type) { // // TODO(someday): Maybe just strip namespaces from each arg? KJ_IF_SOME(pos, result.findFirst('<')) { - result = kj::str(result.slice(0, pos)); + result = kj::str(result.first(pos)); } return kj::mv(result); @@ -204,7 +204,7 @@ DecodedException decodeTunneledException( // Check for closing brace KJ_IF_SOME(closeParen, errorType.findFirst(')')) { auto& js = Lock::from(isolate); - auto errorName = kj::str(errorType.slice(0, closeParen)); + auto errorName = kj::str(errorType.first(closeParen)); auto message = appMessage(errorType.slice(1 + closeParen)); auto exception = js.domException(kj::mv(errorName), kj::str(message)); result.handle = KJ_ASSERT_NONNULL(exception.tryGetHandle(js)); diff --git a/src/workerd/server/server-test.c++ b/src/workerd/server/server-test.c++ index 83f93ad61e2..e21e86bfcb7 100644 --- a/src/workerd/server/server-test.c++ +++ b/src/workerd/server/server-test.c++ @@ -71,7 +71,7 @@ kj::String operator"" _blockquote(const char* str, size_t n) { while (text != nullptr) { // Add data from this line. auto nl = text.findFirst('\n').orDefault(text.size() - 1) + 1; - result.addAll(text.slice(0, nl)); + result.addAll(text.first(nl)); text = text.slice(nl); // Skip indent of next line, up to the expected indent size. diff --git a/src/workerd/server/workerd.c++ b/src/workerd/server/workerd.c++ index 95669b74e6f..e45eebebc38 100644 --- a/src/workerd/server/workerd.c++ +++ b/src/workerd/server/workerd.c++ @@ -903,7 +903,7 @@ public: }; Override parseOverride(kj::StringPtr str) { auto equalPos = KJ_UNWRAP_OR(str.findFirst('='), CLI_ERROR("Expected =")); - return {kj::str(str.slice(0, equalPos)), str.slice(equalPos + 1)}; + return {kj::str(str.first(equalPos)), str.slice(equalPos + 1)}; } void overrideSocketAddr(kj::StringPtr param) { @@ -1094,7 +1094,7 @@ public: for (;;) { auto dotPos = KJ_UNWRAP_OR(name.findFirst('.'), break); - auto parentName = name.slice(0, dotPos); + auto parentName = name.first(dotPos); parent = KJ_UNWRAP_OR(parent.findNested(kj::str(parentName)), CLI_ERROR("No such constant is defined in the config file (the parent scope '", parentName, "' does not exist).")); @@ -1122,7 +1122,7 @@ public: for (;;) { KJ_IF_SOME(pos, filter.findFirst(':')) { - parts.add(kj::str(filter.slice(0, pos))); + parts.add(kj::str(filter.first(pos))); filter = filter.slice(pos + 1); } else { parts.add(kj::str(filter)); @@ -1217,7 +1217,7 @@ public: static_assert(sizeof(uint64_t) + sizeof(COMPILED_MAGIC_SUFFIX) == sizeof(capnp::word) * 3); auto words = kj::heapArray(size + 3); words.asBytes().fill(0); - capnp::copyToUnchecked(config, words.slice(0, size)); + capnp::copyToUnchecked(config, words.first(size)); memcpy(&words[words.size() - 3], &size, sizeof(size)); memcpy(&words[words.size() - 2], COMPILED_MAGIC_SUFFIX, sizeof(COMPILED_MAGIC_SUFFIX)); diff --git a/src/workerd/util/mimetype.c++ b/src/workerd/util/mimetype.c++ index b8e7699009a..7af047c98fd 100644 --- a/src/workerd/util/mimetype.c++ +++ b/src/workerd/util/mimetype.c++ @@ -79,7 +79,7 @@ kj::ArrayPtr skipWhitespace(kj::ArrayPtr str) { kj::ArrayPtr trimWhitespace(kj::ArrayPtr str) { auto ptr = str.end(); while (ptr > str.begin() && isWhitespace(*(ptr - 1))) --ptr; - return str.slice(0, str.size() - (str.end() - ptr)); + return str.first(str.size() - (str.end() - ptr)); } constexpr bool hasInvalidCodepoints(kj::ArrayPtr str, auto predicate) { @@ -103,7 +103,7 @@ kj::String unescape(kj::ArrayPtr str) { auto result = kj::strTree(); while (str.size() > 0) { KJ_IF_SOME(pos, str.findFirst('\\')) { - result = kj::strTree(kj::mv(result), str.slice(0, pos)); + result = kj::strTree(kj::mv(result), str.first(pos)); str = str.slice(pos + 1, str.size()); } else { // No more backslashes @@ -132,7 +132,7 @@ kj::Maybe MimeType::tryParseImpl(kj::ArrayPtr input, Parse kj::Maybe maybeType; // Let's try to find the solidus that separates the type and subtype KJ_IF_SOME(n, input.findFirst('/')) { - auto typeCandidate = input.slice(0, n); + auto typeCandidate = input.first(n); if (typeCandidate.size() == 0 || hasInvalidCodepoints(typeCandidate, isTokenChar)) { return kj::none; } @@ -151,7 +151,7 @@ kj::Maybe MimeType::tryParseImpl(kj::ArrayPtr input, Parse KJ_IF_SOME(n, input.findFirst(';')) { // If a semi-colon is found, the subtype is everything up to that point // minus trailing whitespace. - auto subtypeCandidate = trimWhitespace(input.slice(0, n)); + auto subtypeCandidate = trimWhitespace(input.first(n)); if (subtypeCandidate.size() == 0 || hasInvalidCodepoints(subtypeCandidate, isTokenChar)) { return kj::none; } @@ -182,7 +182,7 @@ kj::Maybe MimeType::tryParseImpl(kj::ArrayPtr input, Parse continue; } KJ_ASSERT(input[n] == '='); - auto nameCandidate = input.slice(0, n); + auto nameCandidate = input.first(n); input = input.slice(n + 1); if (nameCandidate.size() == 0 || hasInvalidCodepoints(nameCandidate, isTokenChar)) { // The name is invalid, try skipping to the next... @@ -200,7 +200,7 @@ kj::Maybe MimeType::tryParseImpl(kj::ArrayPtr input, Parse // Our parameter value is quoted. Next we'll scan up until the next // quote or until the end of the string. KJ_IF_SOME(p, input.findFirst('"')) { - auto valueCandidate = input.slice(0, p); + auto valueCandidate = input.first(p); input = input.slice(p + 1); if (hasInvalidCodepoints(valueCandidate, isQuotedStringTokenChar)) { continue; @@ -217,7 +217,7 @@ kj::Maybe MimeType::tryParseImpl(kj::ArrayPtr input, Parse } else { // The parameter is not quoted. Let's scan ahead for the next semi-colon. KJ_IF_SOME(p, input.findFirst(';')) { - auto valueCandidate = trimWhitespace(input.slice(0, p)); + auto valueCandidate = trimWhitespace(input.first(p)); input = input.slice(p + 1); if (valueCandidate.size() > 0 && !hasInvalidCodepoints(valueCandidate, isQuotedStringTokenChar)) { @@ -313,7 +313,7 @@ void MimeType::paramsToString(MimeType::ToStringBuffer& buffer) const { buffer.append("\""); while (view.size() > 0) { KJ_IF_SOME(pos, view.findFirst('"')) { - buffer.append(view.slice(0, pos), "\\\""); + buffer.append(view.first(pos), "\\\""); view = view.slice(pos + 1); } else { buffer.append(view); @@ -461,7 +461,7 @@ kj::Maybe MimeType::extract(kj::StringPtr input) { while (input.size() > 0) { KJ_IF_SOME(pos, findNextSeparator(input)) { - auto part = input.slice(0, pos); + auto part = input.first(pos); input = input.slice(pos + 1); KJ_IF_SOME(parsed, processPart(mimeType, part)) { mimeType = kj::mv(parsed); diff --git a/src/workerd/util/perfetto-tracing.c++ b/src/workerd/util/perfetto-tracing.c++ index a10a5e8ad0a..e9051d3963a 100644 --- a/src/workerd/util/perfetto-tracing.c++ +++ b/src/workerd/util/perfetto-tracing.c++ @@ -68,7 +68,7 @@ kj::Array> PerfettoSession::parseCategories(kj::StringP kj::Vector> results; while (categories.size() > 0) { KJ_IF_SOME(pos, categories.findFirst(',')) { - results.add(categories.slice(0, pos)); + results.add(categories.first(pos)); categories = categories.slice(pos + 1); } else { results.add(categories); diff --git a/src/workerd/util/sqlite.c++ b/src/workerd/util/sqlite.c++ index f0f2e451bd8..814683faa6e 100644 --- a/src/workerd/util/sqlite.c++ +++ b/src/workerd/util/sqlite.c++ @@ -166,7 +166,7 @@ static kj::Path getPathFromWin32Handle(HANDLE handle) { KJ_FAIL_WIN32("GetFinalPathNameByHandleW", GetLastError()); } if (len < temp.size()) { - return kj::Path::parseWin32Api(temp.slice(0, len)); + return kj::Path::parseWin32Api(temp.first(len)); } // Try again with new length. tryLen = len; @@ -660,7 +660,7 @@ SqliteDatabase::IngestResult SqliteDatabase::ingestSql( if (!statementLength) break; // Slice off the next valid statement SQL - auto nextStatement = kj::str(sqlCode.slice(0, statementLength)); + auto nextStatement = kj::str(sqlCode.first(statementLength)); // Create a Query object, which will prepare & execute it auto q = Query(*this, regulator, nextStatement); diff --git a/src/workerd/util/strings.h b/src/workerd/util/strings.h index 6a230e8693e..d632295abf0 100644 --- a/src/workerd/util/strings.h +++ b/src/workerd/util/strings.h @@ -5,6 +5,8 @@ #include +#include + namespace workerd { enum CharAttributeFlag : uint8_t {