<commit_before>my class X::Buf::AsStr { ... }
my class X::Buf::Pack { ... }
my class X::Buf::Pack::NonASCII { ... }

my role Blob[::T = uint8] does Positional[T] does Stringy is repr('VMArray') is array_type(T) {
    proto method new(|) { * }
    multi method new() {
        nqp::create(self)
    }
    multi method new(@values) {
        my $buf := nqp::create(self);
        my int $n = @values.elems;
        my int $i;
        nqp::setelems($buf, $n);
        while $i < $n {
            nqp::bindpos_i($buf, $i, @values.at_pos($i));
            $i = $i + 1;
        }
        $buf
    }
    multi method new(*@values) {
        self.new(@values)
    }
    
    multi method at_pos(Blob:D: $i) {
        nqp::atpos_i(self, $i.Int)
    }
    multi method at_pos(Blob:D: Int $i) {
        nqp::atpos_i(self, $i)
    }
    multi method at_pos(Blob:D: int $i) {
        nqp::atpos_i(self, $i)
    }
    
    multi method Bool(Blob:D:) {
        nqp::p6bool(nqp::elems(self));
    }

    method elems(Blob:D:) {
        nqp::p6box_i(nqp::elems(self));
    }
    method bytes(Blob:D:) {
        self.elems
    }
    method chars(Blob:D:)       { X::Buf::AsStr.new(method => 'chars').throw }
    multi method Str(Blob:D:)   { X::Buf::AsStr.new(method => 'Str'  ).throw }
    multi method Stringy(Blob:D:) { self }

    method Numeric(Blob:D:) { self.elems }
    method Int(Blob:D:)     { self.elems }
    
    method decode(Blob:D: $encoding = 'utf-8') {
        nqp::p6box_s(nqp::decode(self, NORMALIZE_ENCODING($encoding)))
    }
    
    method list(Blob:D:) {
        my @l;
        my int $n = nqp::elems(self);
        my int $i = 0;
        while $i < $n {
            @l[$i] = nqp::atpos_i(self, $i);
            $i = $i + 1;
        }
        @l;
    }

    multi method gist(Blob:D:) {
        'Buf:0x<' ~ self.list.fmt('%02x', ' ') ~ '>'
    }
    multi method perl(Blob:D:) {
        self.^name ~ '.new(' ~ self.list.join(', ') ~ ')';
    }
    
    method subbuf(Blob:D: $from = 0, $len is copy = self.elems - $from) {

        if ($len < 0) {
            X::OutOfRange.new(
                what => "Len element to subbuf",
                got  => $len,
                range => (0..self.elems)).fail;
        }


        my $ret := nqp::create(self);

        my int $ifrom = nqp::unbox_i(
            nqp::istype($from, Callable)
                ?? $from(nqp::p6box_i(self.elems))
                !! $from.Int);

        if ($ifrom < 0) {
            X::OutOfRange.new(
                what    => 'From argument to subbuf',
                got     => $from,
                range   => (0..self.elems),
                comment => "use *{$ifrom} if you want to index relative to the end"
            ).fail;
        }

        if ($ifrom > self.elems) {
            X::OutOfRange.new(
                what => 'From argument to subbuf',
                got  => $from,
                range => (0..self.elems),
            ).fail;
        }

        return $ret
            if $ifrom == self.elems;

        $len = self.elems - $ifrom
            if $len > self.elems;

        my int $llen = $len.Int;
        nqp::setelems($ret, $llen);
        my int $i = 0;
        while $i < $llen {
            nqp::bindpos_i($ret, $i, nqp::atpos_i(self, $ifrom));
            $i = $i + 1;
            $ifrom = $ifrom + 1;
        }
        $ret
    }
    
    method unpack(Blob:D: $template) {
        my @bytes = self.list;
        my @fields;
        for $template.comb(/<[a..zA..Z]>[\d+|'*']?/) -> $unit {
            my $directive = $unit.substr(0, 1);
            my $amount = $unit.substr(1);

            given $directive {
                when 'A' {
                    my $asciistring;
                    if $amount eq '*' {
                        $amount = @bytes.elems;
                    }
                    for ^$amount {
                        $asciistring ~= chr(shift @bytes);
                    }
                    @fields.push($asciistring);
                }
                when 'H' {
                    my $hexstring;
                    while @bytes {
                        my $byte = shift @bytes;
                        $hexstring ~= ($byte +> 4).fmt('%x')<commit_msg>add unpack directives "a" and "Z"<commit_after>my class X::Buf::AsStr { ... }
my class X::Buf::Pack { ... }
my class X::Buf::Pack::NonASCII { ... }

my role Blob[::T = uint8] does Positional[T] does Stringy is repr('VMArray') is array_type(T) {
    proto method new(|) { * }
    multi method new() {
        nqp::create(self)
    }
    multi method new(@values) {
        my $buf := nqp::create(self);
        my int $n = @values.elems;
        my int $i;
        nqp::setelems($buf, $n);
        while $i < $n {
            nqp::bindpos_i($buf, $i, @values.at_pos($i));
            $i = $i + 1;
        }
        $buf
    }
    multi method new(*@values) {
        self.new(@values)
    }
    
    multi method at_pos(Blob:D: $i) {
        nqp::atpos_i(self, $i.Int)
    }
    multi method at_pos(Blob:D: Int $i) {
        nqp::atpos_i(self, $i)
    }
    multi method at_pos(Blob:D: int $i) {
        nqp::atpos_i(self, $i)
    }
    
    multi method Bool(Blob:D:) {
        nqp::p6bool(nqp::elems(self));
    }

    method elems(Blob:D:) {
        nqp::p6box_i(nqp::elems(self));
    }
    method bytes(Blob:D:) {
        self.elems
    }
    method chars(Blob:D:)       { X::Buf::AsStr.new(method => 'chars').throw }
    multi method Str(Blob:D:)   { X::Buf::AsStr.new(method => 'Str'  ).throw }
    multi method Stringy(Blob:D:) { self }

    method Numeric(Blob:D:) { self.elems }
    method Int(Blob:D:)     { self.elems }
    
    method decode(Blob:D: $encoding = 'utf-8') {
        nqp::p6box_s(nqp::decode(self, NORMALIZE_ENCODING($encoding)))
    }
    
    method list(Blob:D:) {
        my @l;
        my int $n = nqp::elems(self);
        my int $i = 0;
        while $i < $n {
            @l[$i] = nqp::atpos_i(self, $i);
            $i = $i + 1;
        }
        @l;
    }

    multi method gist(Blob:D:) {
        'Buf:0x<' ~ self.list.fmt('%02x', ' ') ~ '>'
    }
    multi method perl(Blob:D:) {
        self.^name ~ '.new(' ~ self.list.join(', ') ~ ')';
    }
    
    method subbuf(Blob:D: $from = 0, $len is copy = self.elems - $from) {

        if ($len < 0) {
            X::OutOfRange.new(
                what => "Len element to subbuf",
                got  => $len,
                range => (0..self.elems)).fail;
        }


        my $ret := nqp::create(self);

        my int $ifrom = nqp::unbox_i(
            nqp::istype($from, Callable)
                ?? $from(nqp::p6box_i(self.elems))
                !! $from.Int);

        if ($ifrom < 0) {
            X::OutOfRange.new(
                what    => 'From argument to subbuf',
                got     => $from,
                range   => (0..self.elems),
                comment => "use *{$ifrom} if you want to index relative to the end"
            ).fail;
        }

        if ($ifrom > self.elems) {
            X::OutOfRange.new(
                what => 'From argument to subbuf',
                got  => $from,
                range => (0..self.elems),
            ).fail;
        }

        return $ret
            if $ifrom == self.elems;

        $len = self.elems - $ifrom
            if $len > self.elems;

        my int $llen = $len.Int;
        nqp::setelems($ret, $llen);
        my int $i = 0;
        while $i < $llen {
            nqp::bindpos_i($ret, $i, nqp::atpos_i(self, $ifrom));
            $i = $i + 1;
            $ifrom = $ifrom + 1;
        }
        $ret
    }
    
    method unpack(Blob:D: $template) {
        my @bytes = self.list;
        my @fields;
        for $template.comb(/<[a..zA..Z]>[\d+|'*']?/) -> $unit {
            my $directive = $unit.substr(0, 1);
            my $amount = $unit.substr(1);

            given $directive {
                when 'a' | 'A' | 'Z' {
                    my $asciistring;
                    if $amount eq '*' {
                        $amount = @bytes.elems;
                    }
                    for ^$amount {
                        $asciistring ~= chr(shift @bytes);
                    }
                    @fields.push($asciistring);
                }
                when 'H' {
                    my $hexstring;
                    while @bytes {
                        my $byte = shift @bytes;
                        $hexstring ~= ($byte +> 4).fmt('%x')
{'fraction_non_alphanumeric': 0.1660350544765514, 'fraction_numerical': 0.005921364282330649, 'mean_word_length': 1.3761958356781092, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 39, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '604823', 'n_tokens_mistral': 3008, 'n_tokens_neox': 2873, 'n_words': 610}