public function parse(DateTimeParseContext $context, $text, $position)
 {
     $length = strlen($text);
     if ($position === $length) {
         return ~$position;
     }
     if ($position < 0 || $position >= $length) {
         throw new \OutOfRangeException();
     }
     $sign = $text[$position];
     $negative = false;
     $positive = false;
     if ($sign === $context->getDecimalStyle()->getPositiveSign()) {
         if ($this->signStyle->parse(true, $context->isStrict(), $this->minWidth === $this->maxWidth) === false) {
             return ~$position;
         }
         $positive = true;
         $position++;
     } else {
         if ($sign === $context->getDecimalStyle()->getNegativeSign()) {
             if ($this->signStyle->parse(false, $context->isStrict(), $this->minWidth === $this->maxWidth) === false) {
                 return ~$position;
             }
             $negative = true;
             $position++;
         } else {
             if ($this->signStyle == SignStyle::ALWAYS() && $context->isStrict()) {
                 return ~$position;
             }
         }
     }
     $effMinWidth = $context->isStrict() || $this->isFixedWidth($context) ? $this->minWidth : 1;
     $minEndPos = $position + $effMinWidth;
     if ($minEndPos > $length) {
         return ~$position;
     }
     $effMaxWidth = ($context->isStrict() || $this->isFixedWidth($context) ? $this->maxWidth : 9) + Math::max($this->subsequentWidth, 0);
     $total = 0;
     $totalBig = null;
     $pos = $position;
     for ($pass = 0; $pass < 2; $pass++) {
         $maxEndPos = Math::min($pos + $effMaxWidth, $length);
         while ($pos < $maxEndPos) {
             $ch = $text[$pos++];
             $digit = $context->getDecimalStyle()->convertToDigit($ch);
             if ($digit < 0) {
                 $pos--;
                 if ($pos < $minEndPos) {
                     return ~$position;
                     // need at least min width digits
                 }
                 break;
             }
             if ($pos - $position > 18) {
                 if ($totalBig === null) {
                     $totalBig = \gmp_init($total);
                 }
                 $totalBig = \gmp_add(\gmp_mul($totalBig, "10"), \gmp_init($digit));
             } else {
                 $total = $total * 10 + $digit;
             }
         }
         if ($this->subsequentWidth > 0 && $pass === 0) {
             // re-parse now we know the correct width
             $parseLen = $pos - $position;
             $effMaxWidth = Math::max($effMinWidth, $parseLen - $this->subsequentWidth);
             $pos = $position;
             $total = 0;
             $totalBig = null;
         } else {
             break;
         }
     }
     if ($negative) {
         if ($totalBig !== null) {
             if (\gmp_cmp($totalBig, "0") === 0 && $context->isStrict()) {
                 return ~($position - 1);
                 // minus zero not allowed
             }
             $totalBig = \gmp_neg($totalBig);
         } else {
             if ($total === 0 && $context->isStrict()) {
                 return ~($position - 1);
                 // minus zero not allowed
             }
             $total = -$total;
         }
     } else {
         if ($this->signStyle == SignStyle::EXCEEDS_PAD() && $context->isStrict()) {
             $parseLen = $pos - $position;
             if ($positive) {
                 if ($parseLen <= $this->minWidth) {
                     return ~($position - 1);
                     // '+' only parsed if minWidth exceeded
                 }
             } else {
                 if ($parseLen > $this->minWidth) {
                     return ~$position;
                     // '+' must be parsed if minWidth exceeded
                 }
             }
         }
     }
     if ($totalBig !== null) {
         if (gmp_cmp($totalBig, "-9223372036854775808") < 0 || gmp_cmp($totalBig, "9223372036854775807") > 0) {
             // overflow, parse 1 less digit
             $totalBig = gmp_div($totalBig, "10");
             $pos--;
         }
         return $this->setValue($context, gmp_intval($totalBig), $position, $pos);
     }
     return $this->setValue($context, $total, $position, $pos);
 }
 public function parse(DateTimeParseContext $context, $text, $position)
 {
     $effectiveMin = $context->isStrict() ? $this->minWidth : 0;
     $effectiveMax = $context->isStrict() ? $this->maxWidth : 9;
     $length = strlen($text);
     if ($position === $length) {
         // valid if whole field is optional, invalid if minimum width
         return $effectiveMin > 0 ? ~$position : $position;
     }
     if ($this->decimalPoint) {
         if ($text[$position] != $context->getDecimalStyle()->getDecimalSeparator()) {
             // valid if whole field is optional, invalid if minimum width
             return $effectiveMin > 0 ? ~$position : $position;
         }
         $position++;
     }
     $minEndPos = $position + $effectiveMin;
     if ($minEndPos > $length) {
         return ~$position;
         // need at least min width digits
     }
     $maxEndPos = Math::min($position + $effectiveMax, $length);
     $total = 0;
     // can use int because we are only parsing up to 9 digits
     $pos = $position;
     while ($pos < $maxEndPos) {
         $ch = $text[$pos++];
         $digit = $context->getDecimalStyle()->convertToDigit($ch);
         if ($digit < 0) {
             if ($pos < $minEndPos) {
                 return ~$position;
                 // need at least min width digits
             }
             $pos--;
             break;
         }
         $total = $total * 10 + $digit;
     }
     $div = 1 . str_repeat('0', 9 - ($pos - $position));
     $fraction = gmp_mul($total, $div);
     $value = $this->convertFromFraction($fraction);
     return $context->setParsedField($this->field, $value, $position, $pos);
 }