function from_base()

in src/math/compute.php [117:163]


function from_base(string $number, int $from_base)[]: int {
  invariant(
    $number !== '',
    'Unexpected empty string, expected number in base %d',
    $from_base,
  );

  invariant(
    $from_base >= 2 && $from_base <= 36,
    'Expected $from_base to be between 2 and 36, got %d',
    $from_base,
  );

  $limit = int_div(\PHP_INT_MAX, $from_base);
  $result = 0;
  foreach (Str\chunk($number) as $digit) {
    /* This was benchmarked against value lookups using both dict and vec,
     * as well as nasty math magic to do it without branching.
     * In interpreted form, the dict lookup beats this by about 30%,
     * and in compiled form, the vec lookup beats this by about 1%.
     * However, this form does not rely on processor cache for the lookup table,
     * so is likely to be slightly faster out in the wild.
     * See D14491063 for details of benchmarks that were run.
     */
    $oval = \ord($digit);
    // Branches sorted by guesstimated frequency of use. */
    if      (/* '0' - '9' */ $oval <= 57 && $oval >=  48) { $dval = $oval - 48; }
    else if (/* 'a' - 'z' */ $oval >= 97 && $oval <= 122) { $dval = $oval - 87; }
    else if (/* 'A' - 'Z' */ $oval >= 65 && $oval <=  90) { $dval = $oval - 55; }
    else                                                  { $dval = 99; }
    invariant(
      $dval < $from_base,
      'Invalid digit %s in base %d',
      $digit,
      $from_base,
    );
    $oldval = $result;
    $result = $from_base * $result + $dval;
    invariant(
      $oldval <= $limit && $result >= $oldval,
      'Unexpected integer overflow parsing %s from base %d',
      $number,
      $from_base,
    );
  }
  return $result;
}