utils.ts 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657
  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. return `${high}${Math.abs(low).toString().padStart(15, '0')}`;
  22. };
  23. const bigNumCompare = (num1: string, num2: string) =>
  24. Math.sign(Number(bigNumPlus(
  25. num1,
  26. num2.replace(/^([+-]?)(\d+)/, (_, $1, $2) => `${$1 === '-' ? '' : '-'}${$2}`)
  27. )));
  28. const bigNumMin = (...nums: string[]) => {
  29. if (!nums || !nums.length) return undefined;
  30. let min = nums[0];
  31. for (let i = 1; i < nums.length; i++) {
  32. if (bigNumCompare(nums[i], min) < 0) min = nums[i];
  33. }
  34. return min;
  35. };
  36. const bigNumLShift = (num: string, by: number) => {
  37. if (by < 0) throw Error('cannot perform right shift');
  38. const at = Math.trunc((52 - by) / 10) * 3;
  39. const [high, low] = splitBigNumAt(num, at).map(n => n * 2 ** by);
  40. return bigNumPlus(high + '0'.repeat(at), low.toString());
  41. };
  42. const parseBigNum = (str: string) => (str?.match(/^-?\d+$/) || [''])[0].replace(/^(-)?0*/, '$1');
  43. export const BigNumOps = {
  44. splitAt: splitBigNumAt,
  45. plus: bigNumPlus,
  46. compare: bigNumCompare,
  47. min: bigNumMin,
  48. lShift: bigNumLShift,
  49. parse: parseBigNum,
  50. };