mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
Add regression test for rope string slice performance (issue #26682)
String.prototype.slice() currently has O(n) complexity on rope strings, causing O(n²) overall complexity when iterating through a concatenated string with slice operations. The tests are marked as todo until the WebKit fix is merged: https://github.com/oven-sh/WebKit/pull/154 Once the WebKit PR is merged and the commit hash is updated in cmake/tools/SetupWebKit.cmake, these tests should be enabled. Fixes #26682 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
78
test/regression/issue/026682.test.ts
Normal file
78
test/regression/issue/026682.test.ts
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
import { expect, test } from "bun:test";
|
||||||
|
|
||||||
|
// Test for https://github.com/oven-sh/bun/issues/26682
|
||||||
|
// String.prototype.slice() should have O(1) complexity on rope strings,
|
||||||
|
// not O(n) which causes O(n²) overall when iterating through a concatenated string.
|
||||||
|
//
|
||||||
|
// The fix for this issue is in the WebKit fork: https://github.com/oven-sh/WebKit/pull/154
|
||||||
|
// These tests are marked as todo until the WebKit fix is merged and the commit hash is updated.
|
||||||
|
|
||||||
|
test.todo("rope string slice should be efficient (not O(n²))", () => {
|
||||||
|
// Create a rope string by concatenation
|
||||||
|
// Using 50,000 iterations - enough to detect O(n²) behavior
|
||||||
|
const iterations = 50000;
|
||||||
|
let s = "";
|
||||||
|
for (let i = 0; i < iterations; i++) s += "A";
|
||||||
|
|
||||||
|
// Test slice performance
|
||||||
|
const start = performance.now();
|
||||||
|
const m = new Map();
|
||||||
|
for (let i = 0; i < iterations; i++) {
|
||||||
|
const k = s.slice(i, i + 1);
|
||||||
|
m.set(k, 1);
|
||||||
|
}
|
||||||
|
const elapsed = performance.now() - start;
|
||||||
|
|
||||||
|
// With O(n²) complexity, this would take several seconds (>5000ms)
|
||||||
|
// With O(n) complexity, this should complete in under 500ms
|
||||||
|
// We use a generous threshold to avoid flakiness while still catching the regression
|
||||||
|
expect(elapsed).toBeLessThan(2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.todo("rope string slice across multiple fibers should be efficient", () => {
|
||||||
|
// Create a rope string with multiple concatenations to ensure multiple fibers
|
||||||
|
const chunkSize = 10000;
|
||||||
|
let s = "";
|
||||||
|
for (let i = 0; i < 5; i++) {
|
||||||
|
let chunk = "";
|
||||||
|
for (let j = 0; j < chunkSize; j++) {
|
||||||
|
chunk += String.fromCharCode(65 + i); // A, B, C, D, E
|
||||||
|
}
|
||||||
|
s += chunk;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test slices that cross fiber boundaries
|
||||||
|
const start = performance.now();
|
||||||
|
const slices: string[] = [];
|
||||||
|
|
||||||
|
// Take slices near fiber boundaries (every 10000 chars)
|
||||||
|
for (let i = 0; i < s.length - 100; i += 1000) {
|
||||||
|
slices.push(s.slice(i, i + 100));
|
||||||
|
}
|
||||||
|
const elapsed = performance.now() - start;
|
||||||
|
|
||||||
|
// Verify correctness
|
||||||
|
expect(slices.length).toBeGreaterThan(0);
|
||||||
|
expect(slices[0].length).toBe(100);
|
||||||
|
|
||||||
|
// Performance check - should be fast
|
||||||
|
expect(elapsed).toBeLessThan(1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("rope string charAt and bracket notation should be efficient", () => {
|
||||||
|
// This test verifies that charAt and bracket notation remain efficient
|
||||||
|
// (they were not affected by the bug, but we should ensure they stay fast)
|
||||||
|
const iterations = 50000;
|
||||||
|
let s = "";
|
||||||
|
for (let i = 0; i < iterations; i++) s += "A";
|
||||||
|
|
||||||
|
const start = performance.now();
|
||||||
|
let count = 0;
|
||||||
|
for (let i = 0; i < iterations; i++) {
|
||||||
|
if (s[i] === "A") count++;
|
||||||
|
}
|
||||||
|
const elapsed = performance.now() - start;
|
||||||
|
|
||||||
|
expect(count).toBe(iterations);
|
||||||
|
expect(elapsed).toBeLessThan(500);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user