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