Skip to content

Commit 38a2fab

Browse files
committed
fixup! Refine the jsonResponse bench a bit more
1 parent fb81688 commit 38a2fab

File tree

2 files changed

+17
-100
lines changed

2 files changed

+17
-100
lines changed

src/workerd/api/headers.c++

Lines changed: 15 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -74,22 +74,11 @@ static constexpr size_t MAX_COMMON_HEADER_ID =
7474
// and must be kept in sync with the ordinal values defined in http-over-capnp.capnp). Since
7575
// it is extremely unlikely that those will change often, we hardcode them here for runtime
7676
// efficiency.
77-
#define V(Name) Name,
78-
static constexpr const char* COMMON_HEADER_NAMES[] = {nullptr, // 0: invalid
77+
#define V(Name) Name##_kj,
78+
static constexpr kj::StringPtr COMMON_HEADER_NAMES[] = {nullptr, // 0: invalid
7979
COMMON_HEADERS(V)};
8080
#undef V
8181

82-
constexpr size_t constexprStrlen(const char* str) {
83-
return *str ? 1 + constexprStrlen(str + 1) : 0;
84-
}
85-
86-
// Helper to avoid recalculating lengths of common headers at runtime repeatedly
87-
static constexpr size_t COMMON_HEADER_NAME_LENGTHS[] = {0, // 0: invalid (nullptr)
88-
#define V(n) constexprStrlen(n),
89-
COMMON_HEADERS(V)
90-
#undef V
91-
};
92-
9382
inline constexpr kj::StringPtr getCommonHeaderName(uint id) {
9483
KJ_ASSERT(id > 0 && id <= MAX_COMMON_HEADER_ID, "Invalid common header ID");
9584
kj::StringPtr name = COMMON_HEADER_NAMES[id];
@@ -107,8 +96,8 @@ constexpr kj::Maybe<uint> getCommonHeaderId(kj::StringPtr name) {
10796
for (uint i = 1; i <= MAX_COMMON_HEADER_ID; ++i) {
10897
KJ_DASSERT(COMMON_HEADER_NAMES[i] != nullptr);
10998
// If the lengths don't match or the first character doesn't match, skip full comparison
110-
if (len != COMMON_HEADER_NAME_LENGTHS[i]) continue;
111-
if (strncasecmp(name.begin(), COMMON_HEADER_NAMES[i], len) == 0) {
99+
if (len != COMMON_HEADER_NAMES[i].size()) continue;
100+
if (strncasecmp(name.begin(), COMMON_HEADER_NAMES[i].begin(), len) == 0) {
112101
return i;
113102
}
114103
}
@@ -240,40 +229,22 @@ inline void requireValidHeaderValue(kj::StringPtr value) {
240229
}
241230
} // namespace
242231

243-
Headers::UncommonHeaderKey::UncommonHeaderKey(kj::String name)
244-
: name(kj::mv(name)),
245-
hash(kj::hashCode(this->name)) {}
246-
247-
Headers::UncommonHeaderKey::UncommonHeaderKey(kj::StringPtr name)
248-
: name(kj::str(name)),
249-
hash(kj::hashCode(this->name)) {}
250-
251-
bool Headers::UncommonHeaderKey::operator==(const UncommonHeaderKey& other) const {
252-
// The same hash code is a necessary but not sufficient condition for equality.
253-
return hash == other.hash && name == other.name;
254-
}
255-
256-
bool Headers::UncommonHeaderKey::operator==(kj::StringPtr otherName) const {
257-
if (name.size() != otherName.size()) return false;
258-
return strncasecmp(name.begin(), otherName.begin(), name.size()) == 0;
259-
}
260-
261232
Headers::HeaderKey Headers::getHeaderKeyFor(kj::StringPtr name) {
262233
KJ_IF_SOME(commonId, getCommonHeaderId(name)) {
263234
return commonId;
264235
}
265236

266237
// Not a common header, so allocate lowercase copy for uncommon header
267-
return UncommonHeaderKey(toLower(name));
238+
return toLower(name);
268239
}
269240

270241
Headers::HeaderKey Headers::cloneHeaderKey(const HeaderKey& key) {
271242
KJ_SWITCH_ONEOF(key) {
272243
KJ_CASE_ONEOF(commonId, uint) {
273244
return commonId;
274245
}
275-
KJ_CASE_ONEOF(uncommonKey, UncommonHeaderKey) {
276-
return uncommonKey.clone();
246+
KJ_CASE_ONEOF(uncommonKey, kj::String) {
247+
return kj::str(uncommonKey);
277248
}
278249
}
279250
KJ_UNREACHABLE;
@@ -284,7 +255,7 @@ bool Headers::isSetCookie(const HeaderKey& key) {
284255
KJ_CASE_ONEOF(commonId, uint) {
285256
return commonId == static_cast<uint>(capnp::CommonHeaderName::SET_COOKIE);
286257
}
287-
KJ_CASE_ONEOF(uncommonKey, UncommonHeaderKey) {
258+
KJ_CASE_ONEOF(uncommonKey, kj::String) {
288259
// This case really shouldn't happen since "set-cookie" is a common header,
289260
// but just in case...
290261
return uncommonKey == "set-cookie";
@@ -294,21 +265,7 @@ bool Headers::isSetCookie(const HeaderKey& key) {
294265
}
295266

296267
bool Headers::headerKeyEquals(const HeaderKey& a, const HeaderKey& b) {
297-
KJ_SWITCH_ONEOF(a) {
298-
KJ_CASE_ONEOF(aCommonId, uint) {
299-
KJ_IF_SOME(bCommonId, b.tryGet<uint>()) {
300-
return aCommonId == bCommonId;
301-
}
302-
return false;
303-
}
304-
KJ_CASE_ONEOF(aUncommonKey, UncommonHeaderKey) {
305-
KJ_IF_SOME(bUncommonKey, b.tryGet<UncommonHeaderKey>()) {
306-
return aUncommonKey == bUncommonKey;
307-
}
308-
return false;
309-
}
310-
}
311-
KJ_UNREACHABLE;
268+
return a == b;
312269
}
313270

314271
Headers::Header::Header(jsg::ByteString name, kj::Vector<jsg::ByteString> values)
@@ -354,8 +311,8 @@ kj::StringPtr Headers::Header::Header::getKeyName() const {
354311
KJ_CASE_ONEOF(commonId, uint) {
355312
return COMMON_HEADER_NAMES[commonId];
356313
}
357-
KJ_CASE_ONEOF(uncommonKey, UncommonHeaderKey) {
358-
return uncommonKey.getName();
314+
KJ_CASE_ONEOF(uncommonKey, kj::String) {
315+
return uncommonKey;
359316
}
360317
}
361318
KJ_UNREACHABLE;
@@ -394,15 +351,15 @@ kj::uint Headers::HeaderCallbacks::hashCode(const HeaderKey& key) {
394351
KJ_CASE_ONEOF(commonId, uint) {
395352
return kj::hashCode(commonId);
396353
}
397-
KJ_CASE_ONEOF(uncommonKey, UncommonHeaderKey) {
398-
return uncommonKey.hashCode();
354+
KJ_CASE_ONEOF(uncommonKey, kj::String) {
355+
return kj::hashCode(uncommonKey);
399356
}
400357
}
401358
KJ_UNREACHABLE;
402359
}
403360

404361
kj::uint Headers::HeaderCallbacks::hashCode(capnp::CommonHeaderName commondId) {
405-
return kj::hashCode(static_cast<uint>(commondId));
362+
return kj::hashCode(commondId);
406363
}
407364

408365
Headers::Headers(jsg::Lock& js, jsg::Dict<jsg::ByteString, jsg::ByteString> dict)
@@ -776,7 +733,7 @@ void Headers::serialize(jsg::Lock& js, jsg::Serializer& serializer) {
776733
KJ_CASE_ONEOF(commonId, uint) {
777734
serializer.writeRawUint32(commonId);
778735
}
779-
KJ_CASE_ONEOF(uncommonKey, UncommonHeaderKey) {
736+
KJ_CASE_ONEOF(_, kj::String) {
780737
serializer.writeRawUint32(0);
781738
serializer.writeLengthDelimited(header.getHeaderName());
782739
}

src/workerd/api/headers.h

Lines changed: 2 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -164,50 +164,10 @@ class Headers final: public jsg::Object {
164164
void visitForMemoryInfo(jsg::MemoryTracker& tracker) const;
165165

166166
private:
167-
// The header key can be stored either as a common header ID (uint) or an an
168-
// UncommonHeaderKey. This class encapsulates the lower-cased header name and
169-
// precomputed hash code for efficient comparisons. It is used for any header
170-
// name that is not in the common header list.
171-
class UncommonHeaderKey final {
172-
public:
173-
UncommonHeaderKey(UncommonHeaderKey&&) = default;
174-
UncommonHeaderKey& operator=(UncommonHeaderKey&&) = default;
175-
KJ_DISALLOW_COPY(UncommonHeaderKey);
176-
177-
inline bool operator==(const UncommonHeaderKey& other) const;
178-
inline bool operator==(kj::StringPtr otherName) const;
179-
180-
inline uint hashCode() const { return hash; }
181-
inline kj::StringPtr getName() const { return name; }
182-
183-
JSG_MEMORY_INFO(UncommonHeaderKey) {
184-
tracker.trackField("name", name);
185-
}
186-
187-
inline UncommonHeaderKey clone() const {
188-
return UncommonHeaderKey(kj::str(name), hash);
189-
}
190-
191-
private:
192-
// The name is expected to be stored in lower-case form, but we do not
193-
// enforce that actually within the struct. It is the responsibility of
194-
// the caller to ensure it is appropriately lower-cased.
195-
kj::String name;
196-
kj::uint hash;
197-
198-
// Critically, because of hash collisions, we must still compare the full string
199-
// to determine equality but we can use the hash code to avoid unnecessary string
200-
// comparisons.
201-
inline UncommonHeaderKey(kj::String name);
202-
inline UncommonHeaderKey(kj::StringPtr name);
203-
inline UncommonHeaderKey(kj::String name, kj::uint hash): name(kj::mv(name)), hash(hash) {}
204-
friend class Headers;
205-
};
206-
207167
// A header is identified by either a common header ID or an uncommon header name.
208168
// The header key name is always identifed in lower-case form, while the original
209169
// casing is preserved in the actual Header struct to support case-preserving display.
210-
using HeaderKey = kj::OneOf<uint, UncommonHeaderKey>;
170+
using HeaderKey = kj::OneOf<uint, kj::String>;
211171

212172
static HeaderKey getHeaderKeyFor(kj::StringPtr name);
213173
static bool headerKeyEquals(const HeaderKey& a, const HeaderKey& b);
@@ -249,7 +209,7 @@ class Headers final: public jsg::Object {
249209
Header clone() const;
250210

251211
JSG_MEMORY_INFO(Header) {
252-
tracker.trackField("key", key.tryGet<UncommonHeaderKey>());
212+
tracker.trackField("key", key.tryGet<kj::String>());
253213
tracker.trackField("name", name);
254214
for (const auto& value : values) {
255215
tracker.trackField(nullptr, value);

0 commit comments

Comments
 (0)