digestForTemplateResult Lit Hashing

Benchmark created on


Setup

// --- Environment Setup ---
const digestSize = 16;
// Pre-calculate for the bitwise version. digestSize must be a power of two.
const digestMask = digestSize - 1; 
const NODE_MODE = false; // Simulates a browser environment where btoa is used

if (typeof Buffer === 'undefined') {
  globalThis.Buffer = { from: () => ({ toString: () => '' }) };
}

// --- Test Data Setup ---
const longString = ('abcdefghijklmnopqrstuvwxyz' + '0123456789').repeat(250);
const templateResult = {
  strings: [
    `some-component-header-class-with-dynamic-part-${Math.random()}`,
    longString,
    `some-static-separator`,
    longString.slice(0, 1000),
    `some-component-footer-class-with-another-part-${Math.random()}`,
  ],
};


// --- Hashing Function 1: Original (with Modulo) ---
// The original function. Modern JS engines will optimize `i % 16` to `i & 15`.
const digestForTemplateResult_Original = (templateResult, digestCache) => {
  let digest = digestCache.get(templateResult.strings);
  if (digest !== undefined) return digest;

  const hashes = new Uint32Array(digestSize).fill(5381);
  for (const s of templateResult.strings) {
    for (let i = 0; i < s.length; i++) {
      hashes[i % digestSize] = (hashes[i % digestSize] * 33) ^ s.charCodeAt(i);
    }
  }
  const str = String.fromCharCode(...new Uint8Array(hashes.buffer));
  digest = btoa(str);
  digestCache.set(templateResult.strings, digest);
  return digest;
};

// --- Hashing Function 2: Flawed (Wrapping Index) ---
// This version is slower due to branch prediction overhead and produces
// a DIFFERENT hash than the original, making it incorrect.
const digestForTemplateResult_Flawed = (templateResult, digestCache) => {
  let digest = digestCache.get(templateResult.strings);
  if (digest !== undefined) return digest;

  const hashes = new Uint32Array(digestSize).fill(5381);
  let h = 0;
  for (const s of templateResult.strings) {
    for (let i = 0; i < s.length; i++) {
      hashes[h] = (hashes[h] * 33) ^ s.charCodeAt(i);
      if (++h >= digestSize) {
        h = 0;
      }
    }
  }
  digest = btoa(String.fromCharCode(...new Uint8Array(hashes.buffer)));
  digestCache.set(templateResult.strings, digest);
  return digest;
};

// --- Hashing Function 3: Correctly Optimized (Bitwise AND with variable) ---
// This version explicitly uses the bitwise AND operation but introduces an
// intermediate variable, which may be what causes the slight slowdown.
const digestForTemplateResult_Bitwise = (templateResult, digestCache) => {
  let digest = digestCache.get(templateResult.strings);
  if (digest !== undefined) return digest;

  const hashes = new Uint32Array(digestSize).fill(5381);
  for (const s of templateResult.strings) {
    for (let i = 0; i < s.length; i++) {
      const index = i & digestMask;
      hashes[index] = (hashes[index] * 33) ^ s.charCodeAt(i);
    }
  }
  const str = String.fromCharCode(...new Uint8Array(hashes.buffer));
  digest = btoa(str);
  digestCache.set(templateResult.strings, digest);
  return digest;
};

// --- Hashing Function 4: Correctly Optimized (Bitwise AND Inlined) ---
// This version performs the bitwise AND directly in the array accessor,
// making it structurally identical to the original and the most likely
// candidate for fastest performance.
const digestForTemplateResult_Bitwise_Inlined = (templateResult, digestCache) => {
  let digest = digestCache.get(templateResult.strings);
  if (digest !== undefined) return digest;

  const hashes = new Uint32Array(digestSize).fill(5381);
  for (const s of templateResult.strings) {
    for (let i = 0; i < s.length; i++) {
      hashes[i & digestMask] = (hashes[i & digestMask] * 33) ^ s.charCodeAt(i);
    }
  }
  const str = String.fromCharCode(...new Uint8Array(hashes.buffer));
  digest = btoa(str);
  digestCache.set(templateResult.strings, digest);
  return digest;
};

Test runner

Ready to run.

Testing in
TestOps/sec
Original Hashing (Modulo).
const digestCache1 = new Map();
digestForTemplateResult_Original(templateResult, digestCache1);

ready
Optimized Hashing (Wrapping Index)
const digestCache2 = new Map();
digestForTemplateResult_Flawed(templateResult, digestCache2);

ready
Optimized Hashing (Bitwise AND)
const digestCache3 = new Map();
digestForTemplateResult_Bitwise(templateResult, digestCache3);
ready
Optimized Hashing (Bitwise AND Inlined)
const digestCache4 = new Map();
digestForTemplateResult_Bitwise_Inlined(templateResult, digestCache4);
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.