11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_cifunction run_repeated(n, fn) {
31cb0ef41Sopenharmony_ci  const res = [];
41cb0ef41Sopenharmony_ci  for (let i = 0; i < n; i++) res.push(fn());
51cb0ef41Sopenharmony_ci  return res;
61cb0ef41Sopenharmony_ci}
71cb0ef41Sopenharmony_ci
81cb0ef41Sopenharmony_ciconst INT_MAX = 0x7fffffff;
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ci// from src/js/collection.js
111cb0ef41Sopenharmony_ci// key must be a signed 32-bit number!
121cb0ef41Sopenharmony_cifunction ComputeIntegerHash(key/*, seed*/) {
131cb0ef41Sopenharmony_ci  let hash = key;
141cb0ef41Sopenharmony_ci  hash = hash ^ 0/*seed*/;
151cb0ef41Sopenharmony_ci  hash = ~hash + (hash << 15);  // hash = (hash << 15) - hash - 1;
161cb0ef41Sopenharmony_ci  hash = hash ^ (hash >>> 12);
171cb0ef41Sopenharmony_ci  hash = hash + (hash << 2);
181cb0ef41Sopenharmony_ci  hash = hash ^ (hash >>> 4);
191cb0ef41Sopenharmony_ci  hash = (hash * 2057) | 0;  // hash = (hash + (hash << 3)) + (hash << 11);
201cb0ef41Sopenharmony_ci  hash = hash ^ (hash >>> 16);
211cb0ef41Sopenharmony_ci  return hash & 0x3fffffff;
221cb0ef41Sopenharmony_ci}
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ciconst kNofHashBitFields = 2;
251cb0ef41Sopenharmony_ciconst kHashShift = kNofHashBitFields;
261cb0ef41Sopenharmony_ciconst kHashBitMask = 0xffffffff >>> kHashShift;
271cb0ef41Sopenharmony_ciconst kZeroHash = 27;
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_cifunction string_to_array(str) {
301cb0ef41Sopenharmony_ci  const res = new Array(str.length);
311cb0ef41Sopenharmony_ci  for (let i = 0; i < str.length; i++) {
321cb0ef41Sopenharmony_ci    res[i] = str.charCodeAt(i);
331cb0ef41Sopenharmony_ci  }
341cb0ef41Sopenharmony_ci  return res;
351cb0ef41Sopenharmony_ci}
361cb0ef41Sopenharmony_ci
371cb0ef41Sopenharmony_cifunction gen_specialized_hasher(str) {
381cb0ef41Sopenharmony_ci  const str_arr = string_to_array(str);
391cb0ef41Sopenharmony_ci  return Function('seed', `
401cb0ef41Sopenharmony_ci    var running_hash = seed;
411cb0ef41Sopenharmony_ci    ${str_arr.map((c) => `
421cb0ef41Sopenharmony_ci      running_hash += ${c};
431cb0ef41Sopenharmony_ci      running_hash &= 0xffffffff;
441cb0ef41Sopenharmony_ci      running_hash += (running_hash << 10);
451cb0ef41Sopenharmony_ci      running_hash &= 0xffffffff;
461cb0ef41Sopenharmony_ci      running_hash ^= (running_hash >>> 6);
471cb0ef41Sopenharmony_ci      running_hash &= 0xffffffff;
481cb0ef41Sopenharmony_ci    `).join('')}
491cb0ef41Sopenharmony_ci    running_hash += (running_hash << 3);
501cb0ef41Sopenharmony_ci    running_hash &= 0xffffffff;
511cb0ef41Sopenharmony_ci    running_hash ^= (running_hash >>> 11);
521cb0ef41Sopenharmony_ci    running_hash &= 0xffffffff;
531cb0ef41Sopenharmony_ci    running_hash += (running_hash << 15);
541cb0ef41Sopenharmony_ci    running_hash &= 0xffffffff;
551cb0ef41Sopenharmony_ci    if ((running_hash & ${kHashBitMask}) == 0) {
561cb0ef41Sopenharmony_ci      return ${kZeroHash};
571cb0ef41Sopenharmony_ci    }
581cb0ef41Sopenharmony_ci    return running_hash;
591cb0ef41Sopenharmony_ci  `);
601cb0ef41Sopenharmony_ci}
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci// adapted from HashToEntry
631cb0ef41Sopenharmony_cifunction hash_to_bucket(hash, numBuckets) {
641cb0ef41Sopenharmony_ci  return (hash & ((numBuckets) - 1));
651cb0ef41Sopenharmony_ci}
661cb0ef41Sopenharmony_ci
671cb0ef41Sopenharmony_cifunction time_set_lookup(set, value) {
681cb0ef41Sopenharmony_ci  const t1 = process.hrtime();
691cb0ef41Sopenharmony_ci  for (let i = 0; i < 100; i++) {
701cb0ef41Sopenharmony_ci    // annoyingly, SetHas() is JS code and therefore potentially optimizable.
711cb0ef41Sopenharmony_ci    // However, SetHas() looks up the table using native code, and it seems like
721cb0ef41Sopenharmony_ci    // that's sufficient to prevent the optimizer from doing anything?
731cb0ef41Sopenharmony_ci    set.has(value);
741cb0ef41Sopenharmony_ci  }
751cb0ef41Sopenharmony_ci  const t = process.hrtime(t1);
761cb0ef41Sopenharmony_ci  const secs = t[0];
771cb0ef41Sopenharmony_ci  const nanos = t[1];
781cb0ef41Sopenharmony_ci  return secs * 1e9 + nanos;
791cb0ef41Sopenharmony_ci}
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci// Set with 256 buckets; bucket 0 full, others empty
821cb0ef41Sopenharmony_ciconst tester_set_buckets = 256;
831cb0ef41Sopenharmony_ciconst tester_set = new Set();
841cb0ef41Sopenharmony_cilet tester_set_treshold;
851cb0ef41Sopenharmony_ci(function() {
861cb0ef41Sopenharmony_ci  // fill bucket 0 and find extra numbers mapping to bucket 0 and a different
871cb0ef41Sopenharmony_ci  // bucket `capacity == numBuckets * 2`
881cb0ef41Sopenharmony_ci  let needed = Math.floor(tester_set_buckets * 1.5) + 1;
891cb0ef41Sopenharmony_ci  let positive_test_value;
901cb0ef41Sopenharmony_ci  let negative_test_value;
911cb0ef41Sopenharmony_ci  for (let i = 0; true; i++) {
921cb0ef41Sopenharmony_ci    if (i > INT_MAX) throw new Error('i too high');
931cb0ef41Sopenharmony_ci    if (hash_to_bucket(ComputeIntegerHash(i), tester_set_buckets) !== 0) {
941cb0ef41Sopenharmony_ci      negative_test_value = i;
951cb0ef41Sopenharmony_ci      break;
961cb0ef41Sopenharmony_ci    }
971cb0ef41Sopenharmony_ci  }
981cb0ef41Sopenharmony_ci  for (let i = 0; needed > 0; i++) {
991cb0ef41Sopenharmony_ci    if (i > INT_MAX) throw new Error('i too high');
1001cb0ef41Sopenharmony_ci    if (hash_to_bucket(ComputeIntegerHash(i), tester_set_buckets) === 0) {
1011cb0ef41Sopenharmony_ci      needed--;
1021cb0ef41Sopenharmony_ci      if (needed == 0) {
1031cb0ef41Sopenharmony_ci        positive_test_value = i;
1041cb0ef41Sopenharmony_ci      } else {
1051cb0ef41Sopenharmony_ci        tester_set.add(i);
1061cb0ef41Sopenharmony_ci      }
1071cb0ef41Sopenharmony_ci    }
1081cb0ef41Sopenharmony_ci  }
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_ci  // calibrate Set access times for accessing the full bucket / an empty bucket
1111cb0ef41Sopenharmony_ci  const pos_time =
1121cb0ef41Sopenharmony_ci    Math.min(...run_repeated(10000, time_set_lookup.bind(null, tester_set,
1131cb0ef41Sopenharmony_ci                                                         positive_test_value)));
1141cb0ef41Sopenharmony_ci  const neg_time =
1151cb0ef41Sopenharmony_ci    Math.min(...run_repeated(10000, time_set_lookup.bind(null, tester_set,
1161cb0ef41Sopenharmony_ci                                                         negative_test_value)));
1171cb0ef41Sopenharmony_ci  tester_set_treshold = (pos_time + neg_time) / 2;
1181cb0ef41Sopenharmony_ci  // console.log(`pos_time: ${pos_time}, neg_time: ${neg_time},`,
1191cb0ef41Sopenharmony_ci  //             `threshold: ${tester_set_treshold}`);
1201cb0ef41Sopenharmony_ci})();
1211cb0ef41Sopenharmony_ci
1221cb0ef41Sopenharmony_ci// determine hash seed
1231cb0ef41Sopenharmony_ciconst slow_str_gen = (function*() {
1241cb0ef41Sopenharmony_ci  let strgen_i = 0;
1251cb0ef41Sopenharmony_ci  outer:
1261cb0ef41Sopenharmony_ci  while (1) {
1271cb0ef41Sopenharmony_ci    const str = `#${strgen_i++}`;
1281cb0ef41Sopenharmony_ci    for (let i = 0; i < 1000; i++) {
1291cb0ef41Sopenharmony_ci      if (time_set_lookup(tester_set, str) < tester_set_treshold)
1301cb0ef41Sopenharmony_ci        continue outer;
1311cb0ef41Sopenharmony_ci    }
1321cb0ef41Sopenharmony_ci    yield str;
1331cb0ef41Sopenharmony_ci  }
1341cb0ef41Sopenharmony_ci})();
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_ciconst first_slow_str = slow_str_gen.next().value;
1371cb0ef41Sopenharmony_ci// console.log('first slow string:', first_slow_str);
1381cb0ef41Sopenharmony_ciconst first_slow_str_special_hasher = gen_specialized_hasher(first_slow_str);
1391cb0ef41Sopenharmony_cilet seed_candidates = [];
1401cb0ef41Sopenharmony_ci//var t_before_first_seed_brute = performance.now();
1411cb0ef41Sopenharmony_cifor (let seed_candidate = 0; seed_candidate < 0x100000000; seed_candidate++) {
1421cb0ef41Sopenharmony_ci  if (hash_to_bucket(first_slow_str_special_hasher(seed_candidate),
1431cb0ef41Sopenharmony_ci                     tester_set_buckets) == 0) {
1441cb0ef41Sopenharmony_ci    seed_candidates.push(seed_candidate);
1451cb0ef41Sopenharmony_ci  }
1461cb0ef41Sopenharmony_ci}
1471cb0ef41Sopenharmony_ci// console.log(`got ${seed_candidates.length} candidates`);
1481cb0ef41Sopenharmony_ci//  after ${performance.now()-t_before_first_seed_brute}
1491cb0ef41Sopenharmony_ciwhile (seed_candidates.length > 1) {
1501cb0ef41Sopenharmony_ci  const slow_str = slow_str_gen.next().value;
1511cb0ef41Sopenharmony_ci  const special_hasher = gen_specialized_hasher(slow_str);
1521cb0ef41Sopenharmony_ci  const new_seed_candidates = [];
1531cb0ef41Sopenharmony_ci  for (const seed_candidate of seed_candidates) {
1541cb0ef41Sopenharmony_ci    if (hash_to_bucket(special_hasher(seed_candidate), tester_set_buckets) ==
1551cb0ef41Sopenharmony_ci        0) {
1561cb0ef41Sopenharmony_ci      new_seed_candidates.push(seed_candidate);
1571cb0ef41Sopenharmony_ci    }
1581cb0ef41Sopenharmony_ci  }
1591cb0ef41Sopenharmony_ci  seed_candidates = new_seed_candidates;
1601cb0ef41Sopenharmony_ci  // console.log(`reduced to ${seed_candidates.length} candidates`);
1611cb0ef41Sopenharmony_ci}
1621cb0ef41Sopenharmony_ciif (seed_candidates.length != 1)
1631cb0ef41Sopenharmony_ci  throw new Error('no candidates remaining');
1641cb0ef41Sopenharmony_ciconst seed = seed_candidates[0];
1651cb0ef41Sopenharmony_ciconsole.log(seed);
166