1package Git::PurePerl::PackIndex::Version2;
2use Moose;
3use MooseX::StrictConstructor;
4use namespace::autoclean;
5
6extends 'Git::PurePerl::PackIndex';
7
8my $FanOutCount   = 256;
9my $SHA1Size      = 20;
10my $IdxOffsetSize = 4;
11my $OffsetSize    = 4;
12my $CrcSize       = 4;
13my $OffsetStart   = $FanOutCount * $IdxOffsetSize;
14my $SHA1Start     = $OffsetStart + $OffsetSize;
15my $EntrySize     = $OffsetSize + $SHA1Size;
16my $EntrySizeV2   = $SHA1Size + $CrcSize + $OffsetSize;
17
18sub global_offset {
19    return 8;
20}
21
22sub all_sha1s {
23    my ( $self, $want_sha1 ) = @_;
24    my $fh = $self->fh;
25    my @sha1s;
26    my @data;
27
28    my $pos = $OffsetStart;
29    $fh->seek( $pos + $self->global_offset, 0 ) || die $!;
30    foreach my $i ( 0 .. $self->size - 1 ) {
31        $fh->read( my $sha1, $SHA1Size ) || die $!;
32        $data[$i] = [ unpack( 'H*', $sha1 ), 0, 0 ];
33        $pos += $SHA1Size;
34    }
35    $fh->seek( $pos + $self->global_offset, 0 ) || die $!;
36    foreach my $i ( 0 .. $self->size - 1 ) {
37        $fh->read( my $crc, $CrcSize ) || die $!;
38        $data[$i]->[1] = unpack( 'H*', $crc );
39        $pos += $CrcSize;
40    }
41    $fh->seek( $pos + $self->global_offset, 0 ) || die $!;
42    foreach my $i ( 0 .. $self->size - 1 ) {
43        $fh->read( my $offset, $OffsetSize ) || die $!;
44        $data[$i]->[2] = unpack( 'N', $offset );
45        $pos += $OffsetSize;
46    }
47    foreach my $data (@data) {
48        my ( $sha1, $crc, $offset ) = @$data;
49        push @sha1s, $sha1;
50    }
51
52    return @sha1s;
53}
54
55sub get_object_offset {
56    my ( $self, $want_sha1 ) = @_;
57    my @offsets = $self->offsets;
58    my $fh      = $self->fh;
59
60    my $slot = unpack( 'C', pack( 'H*', $want_sha1 ) );
61    return unless defined $slot;
62
63    my ( $first, $last ) = @offsets[ $slot, $slot + 1 ];
64
65    while ( $first < $last ) {
66        my $mid = int( ( $first + $last ) / 2 );
67
68        $fh->seek( $self->global_offset + $OffsetStart + ( $mid * $SHA1Size ),
69            0 )
70            || die $!;
71        $fh->read( my $data, $SHA1Size ) || die $!;
72        my $midsha1 = unpack( 'H*', $data );
73        if ( $midsha1 lt $want_sha1 ) {
74            $first = $mid + 1;
75        } elsif ( $midsha1 gt $want_sha1 ) {
76            $last = $mid;
77        } else {
78            my $pos
79                = $self->global_offset
80                + $OffsetStart
81                + ( $self->size * ( $SHA1Size + $CrcSize ) )
82                + ( $mid * $OffsetSize );
83            $fh->seek( $pos, 0 ) || die $!;
84            $fh->read( my $data, $OffsetSize ) || die $!;
85            my $offset = unpack( 'N', $data );
86            return $offset;
87        }
88    }
89    return;
90}
91
92__PACKAGE__->meta->make_immutable;
93
94