utils.ts 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  1. export const chainPromises = <T>(
  2. promises: Promise<T>[],
  3. reducer = (p1: Promise<T>, p2: Promise<T>) => p1.then(() => p2),
  4. initialValue?: T
  5. ) =>
  6. promises.reduce(reducer, Promise.resolve(initialValue));
  7. const splitBigNumAt = (num: string, at: number) =>
  8. num.replace(RegExp(String.raw`^([+-]?)(\d+)(\d{${at}})$`), '$1$2,$1$3')
  9. .replace(/^([^,]*)$/, '0,$1').split(',')
  10. .map(Number);
  11. const bigNumPlus = (num1: string, num2: string) => {
  12. let [high, low] = [splitBigNumAt(num1, 15), splitBigNumAt(num2, 15)]
  13. .reduce((a, b) => [a[0] + b[0], a[1] + b[1]]);
  14. const [highSign, lowSign] = [high, low].map(Math.sign);
  15. if (highSign === 0) return low.toString();
  16. if (highSign !== lowSign) {
  17. [high, low] = [high - highSign, low - lowSign * 10 ** 15];
  18. } else {
  19. [high, low] = [high + Math.trunc(low / 10 ** 15), low % 10 ** 15];
  20. }
  21. if (high === 0) return low.toString();
  22. return `${high}${Math.abs(low).toString().padStart(15, '0')}`;
  23. };
  24. const bigNumCompare = (num1: string, num2: string) =>
  25. Math.sign(Number(bigNumPlus(
  26. num1,
  27. num2.replace(/^([+-]?)(\d+)/, (_, $1, $2) => `${$1 === '-' ? '' : '-'}${$2}`)
  28. )));
  29. const bigNumMin = (...nums: string[]) => {
  30. if (!nums || !nums.length) return undefined;
  31. let min = nums[0];
  32. for (let i = 1; i < nums.length; i++) {
  33. if (bigNumCompare(nums[i], min) < 0) min = nums[i];
  34. }
  35. return min;
  36. };
  37. const bigNumLShift = (num: string, by: number) => {
  38. if (by < 0) throw Error('cannot perform right shift');
  39. const at = Math.trunc((52 - by) / 10) * 3;
  40. const [high, low] = splitBigNumAt(num, at).map(n => n * 2 ** by);
  41. return bigNumPlus(high + '0'.repeat(at), low.toString());
  42. };
  43. const parseBigNum = (str: string) => (str?.match(/^-?\d+$/) || [''])[0].replace(/^(-)?0*/, '$1');
  44. export const BigNumOps = {
  45. splitAt: splitBigNumAt,
  46. plus: bigNumPlus,
  47. compare: bigNumCompare,
  48. min: bigNumMin,
  49. lShift: bigNumLShift,
  50. parse: parseBigNum,
  51. };