## This file generated by InlineX::C2XS (version 0.26) using Inline::C (version 0.79_001)
package Math::Ryu;
use warnings;
use strict;
use Config;
BEGIN {
  # In this BEGIN{} block we check for the presence of a
  # perl bug that can set the POK flag when it should not.
  use B qw(svref_2object);

  if($] < 5.035010) {
    my %flags;
    {
      no strict 'refs';
      for my $flag (qw(
        SVf_IOK
        SVf_NOK
        SVf_POK
        SVp_IOK
        SVp_NOK
        SVp_POK
                )) {
        if (defined &{'B::'.$flag}) {
          $flags{$flag} = &{'B::'.$flag};
        }
      }
    }

    my $test_nv = 1.3;
    my $buggery = "$test_nv";
    my $flags = B::svref_2object(\$test_nv)->FLAGS;
    my $fstr = join ' ', sort grep $flags & $flags{$_}, keys %flags;

    if($fstr =~ /SVf_POK/) {
      $Math::Ryu::PV_NV_BUG = 1;
    }
    else {
      $Math::Ryu::PV_NV_BUG = 0;
    }
  } # close if{} block
  else {
    $Math::Ryu::PV_NV_BUG = 0;
  }
};  # close BEGIN{} block

BEGIN {
  if($Config{nvsize} == 8)               { $::max_dig = 17 }
  elsif($Config{nvtype} eq '__float128') { $::max_dig = 36 }
  elsif(defined($Config{longdblkind})
        && $Config{longdblkind} < 3)     { $::max_dig = 36 }
  else                                   { $::max_dig = 21 }

};  # close BEGIN{} block

use constant PV_NV_BUG   => $Math::Ryu::PV_NV_BUG;
use constant IVSIZE      => $Config{ivsize};
use constant MAX_DEC_DIG => $::max_dig; # set in second BEGIN{} block

require Exporter;
*import = \&Exporter::import;
require DynaLoader;

our $VERSION = '1.0';

DynaLoader::bootstrap Math::Ryu $VERSION;

my @tagged = qw(
  d2s ld2s q2s nv2s
  n2s
  s2d
  fmtpy
  ryu_lln
  );

@Math::Ryu::EXPORT = ();
@Math::Ryu::EXPORT_OK = @tagged;
%Math::Ryu::EXPORT_TAGS = (all => \@tagged);

sub dl_load_flags {0} # Prevent DynaLoader from complaining and croaking

sub nv2s {
  my $nv = shift;
  return fmtpy( d2s($nv)) if MAX_DEC_DIG == 17;
  return fmtpy(ld2s($nv)) if MAX_DEC_DIG == 21;
  return fmtpy( q2s($nv));
}

sub n2s {
  my $arg = shift;
  my $ref = ref($arg);
  die "n2s() does not currently handle  \"$ref\" references"
    if $ref;
  return "$arg" if _SvIOK($arg);
  if(PV_NV_BUG && _SvPOK($arg)) {
    # perl might have set the POK flag when it should not
    return nv2s($arg) if (_SvNOK($arg) && !_SvIOKp($arg));
  }
  return nv2s($arg) if _SvNOK($arg);
  # $arg is neither integer nor float nor reference.
  # If the numified $arg fits into an IV, return the
  # stringification of that value.
  # Else, return nv2s($arg), which will coerce $arg
  # to an NV.
  if(_SvIOK($arg + 0)) {
    my $ret = $arg + 0;
    return "$ret";
  }
  return nv2s($arg);
}

sub fmtpy {
  # Format the string returned by ld2s according to the way
  # that python3 does it.

  my $sinput = shift;
  return $sinput unless $sinput =~ /E|N/i;

  if($sinput =~ /inf|nan/i) {
    $sinput =~ s/inity?//i;
    return lc($sinput);
  }
  if($sinput =~ /^\-?0E0$/) {
    $sinput =~ s/E/./;
    return $sinput;
  }

  my ($man, $exp) = split /E/i, $sinput;

  my $sign = '';
  # Remove the leading '-' and reinstate it later.
  $sign = '-' if $man =~ s/^\-//;

  return $sign . _fmt($man, $exp);
}

sub _fmt {

  my ($man, $exp, $ret) = (shift, shift, 0);
  return $man if !$exp;

  # Note that $man, as called by fmtjs() and fmtpy()
  # has no leading '-' or '+' sign.

  if($man =~ /\./) {
    my @parts = split /\./, $man;
    $exp -= length($parts[1]);
    $man = $parts[0] . $parts[1]
  }

  # $man is now an integer and "${man}e${exp}" represents
  # the absolute value of the original string.

  #my $critical = $exp; # Formatting is based around the value of $exp;
  my $man_len = length($man);

  if($exp < -3) {
    #print "DEBUG: BLOCK 1 $man $exp\n";
    my $leading_zeros = $man_len + $exp;
    if($leading_zeros <= 0 && $leading_zeros >= -3) {
      return '0.' . ('0' x abs($leading_zeros)) . $man;
    }

    # Present scientific notation MANeEXP
    if(abs($exp) < $man_len - 1) {
      substr($man, $exp, 0, '.');
      return $man;
    }
    elsif($man_len > 1) {
      # insert decimal point
      substr($man, 1, 0, '.');
      $exp += $man_len - 1;
    }
    return $man . sprintf "e%03d", $exp;
  }

  if($exp <= 0) {
    # Show no exponent - just M
    #print "DEBUG: BLOCK 2 $man $exp\n";
    if(!$exp) {$man .= '.0'}
    else {substr($man, $exp, 0, '.')}
    $man =~ s/^\./0./;
    return $man;
  }

  if($exp < MAX_DEC_DIG) {
    # Present scientific notation MANeEXP or
    # VAL.0 when appropriate.
    # insert decimal point.
    #print "DEBUG: BLOCK 3 $man $exp\n";
    my $zero_pad = 0;
    $zero_pad = $exp if $exp + $man_len < MAX_DEC_DIG;
    if($zero_pad > 0) {
     return $man . ('0' x $zero_pad) . '.0';
    }
    $exp += $man_len - 1;
    substr($man, 1, 0, '.');
  }
  elsif($man_len != 1) {
    $exp += $man_len - 1;
    substr($man, 1, 0, '.');
    #print "DEBUG: BLOCK 4\n";
  }

  #print "DEBUG: BLOCK 5\n";
  return $man . 'e+' . $exp;
}

1;
