Convert-Binary-C

 view release on metacpan or  search on metacpan

lib/Convert/Binary/C/Cached.pm  view on Meta::CPAN

  my $self = shift;
  my $fh = IO::File->new;

  unless (-e $self->{cache} and -s _) {
    $ENV{CBCC_DEBUG} and print STDERR "CBCC: cache file '$self->{cache}' doesn't exist or is empty\n";
    return 0;
  }

  unless ($fh->open($self->{cache})) {
    $^W and carp "Cannot open '$self->{cache}': $!";
    $ENV{CBCC_DEBUG} and print STDERR "CBCC: cannot open cache file '$self->{cache}'\n";
    return 0;
  }

  my @warnings;
  my @config = do {
    my $config;
    unless (defined($config = <$fh>)) {
      $ENV{CBCC_DEBUG} and print STDERR "CBCC: cannot read configuration\n";
      return 0;
    }
    unless ($config =~ /^#if\s+0/) {
      $ENV{CBCC_DEBUG} and print STDERR "CBCC: invalid configuration\n";
      return 0;
    }
    local $/ = $/.'#endif';
    chomp($config = <$fh>);
    $config =~ s/^\*//gms;
    local $SIG{__WARN__} = sub { push @warnings, $_[0] };
    eval $config;
  };

  # corrupt config
  if ($@ or @warnings or @config % 2) {
    $ENV{CBCC_DEBUG} and print STDERR "CBCC: broken configuration\n";
    return 0;
  }

  my %config = @config;

  my $what = exists $self->{code} ? 'code' : 'file';

  unless (exists $config{$what} and
          $config{$what} eq $self->{$what} and
          __reccmp($config{cfg}, $self->configure)) {
    if ($ENV{CBCC_DEBUG}) {
      print STDERR "CBCC: configuration has changed\n";
      print STDERR "CBCC: what='$what', \$config{$what}='$config{$what}' \$self->{$what}='$self->{$what}'\n";
      my $dump = Data::Dumper->Dump([$config{cfg}, $self->configure], ['config', 'self']);
      $dump =~ s/^/CBCC: /mg;
      print STDERR $dump;
    }
    return 0;
  }

  while (my($file, $spec) = each %{$config{files}}) {
    unless (-e $file) {
      $ENV{CBCC_DEBUG} and print STDERR "CBCC: file '$file' deleted\n";
      return 0;
    }
    my($size, $mtime, $ctime) = (stat(_))[7,9,10];
    unless ($spec->{size} == $size and
            $spec->{mtime} == $mtime and
            $spec->{ctime} == $ctime) {
      $ENV{CBCC_DEBUG} and print STDERR "CBCC: size/mtime/ctime of '$file' changed\n";
      return 0;
    }
  }

  $self->{files} = $config{files};

  $ENV{CBCC_DEBUG} and print STDERR "CBCC: '$self->{cache}' is usable\n";
  return 1;
}

sub __save_cache
{
  my $self = shift;
  my $fh = IO::File->new;

  $fh->open(">$self->{cache}") or croak "Cannot open '$self->{cache}': $!";

  my $what = exists $self->{code} ? 'code' : 'file';

  my $config = Data::Dumper->new([{ $what => $self->{$what},
                                    cfg   => $self->configure,
                                    files => scalar $self->SUPER::dependencies,
                                 }], ['*'])->Indent(1)->Dump;
  $config =~ s/[^(]*//;
  $config =~ s/^/*/gms;

  print $fh "#if 0\n", $config, "#endif\n\n",
            do { local $^W; $self->sourcify({ Context => 1 }) };
}

sub __reccmp
{
  my($ref, $val) = @_;

  !defined($ref) && !defined($val) and return 1;
  !defined($ref) || !defined($val) and return 0;

  ref $ref or return $ref eq $val;

  if (ref $ref eq 'ARRAY') {
    @$ref == @$val or return 0;
    for (0..$#$ref) {
      __reccmp($ref->[$_], $val->[$_]) or return 0;
    }
  }
  elsif (ref $ref eq 'HASH') {
    keys %$ref == keys %$val or return 0;
    for (keys %$ref) {
      __reccmp($ref->{$_}, $val->{$_}) or return 0;
    }
  }
  else { return 0 }

  return 1;
}



( run in 1.401 second using v1.01-cache-2.11-cpan-39bf76dae61 )