my class X::Assignment::RO { ... } my class X::Buf::AsStr { ... } my class X::Buf::Pack { ... } my class X::Buf::Pack::NonASCII { ... } my class X::Experimental { ... } # externalize the endian indicators enum Endian ( NativeEndian => nqp::box_i(nqp::const::BINARY_ENDIAN_NATIVE,Int), LittleEndian => nqp::box_i(nqp::const::BINARY_ENDIAN_LITTLE,Int), BigEndian => nqp::box_i(nqp::const::BINARY_ENDIAN_BIG,Int), ); my role Blob[::T = uint8] does Positional[T] does Stringy is repr('VMArray') is array_type(T) { ... } #- start of generated part of Blob Signed role ------------------------------- #- Generated on 2022-03-08T14:31:37+01:00 by ./tools/build/makeBLOB_ROLES.raku #- PLEASE DON'T CHANGE ANYTHING BELOW THIS LINE my role SignedBlob[::T] is repr('VMArray') is array_type(T) is implementation-detail { method !push-List(str $action, ::?CLASS:D $to, \from) { my Mu $reified := nqp::getattr(from,List,'$!reified'); if nqp::isconcrete($reified) { my int $elems = nqp::elems($reified); my int $j = nqp::elems($to); nqp::setelems($to, $j + $elems); # presize for efficiency my int $i = -1; nqp::while( nqp::islt_i(++$i,$elems), nqp::stmts( (my $got = nqp::hllize(nqp::atpos($reified,$i))), nqp::if( nqp::istype($got,Int), nqp::bindpos_i($to,$j++,$got), self!throw-typecheck-element($action, $i, $got) ) ) ); } $to } method !push-iterator(str $action, ::?CLASS:D $to, Iterator:D $iter) { my int $i; nqp::until( nqp::eqaddr((my $got := $iter.pull-one),IterationEnd), nqp::if( nqp::istype(nqp::hllize($got),Int), nqp::stmts( nqp::push_i($to,$got), ++$i ), self!throw-typecheck-element($action,$i,$got) ) ); $to } method !push-list(str $action, ::?CLASS:D $to, \from) { nqp::istype(from,List) ?? self!push-List($action, $to, from) !! self!push-iterator($action, $to, from.iterator) } method !spread-rest( int $i is copy, int $elems is copy, int $values, ::?CLASS:D $to, \from ) { --$i; # went one too far $elems = $elems + $values; my int $j = -1; if from.^array_type.^unsigned { nqp::bindpos_i($to,$i,nqp::atpos_u(from, ++$j % $values)) while nqp::islt_i(++$i,$elems); } else { nqp::bindpos_i($to,$i,nqp::atpos_i(from, ++$j % $values)) while nqp::islt_i(++$i,$elems); } $to } method !spread(::?CLASS:D $to, \from) { my int $values = nqp::elems(from); my int $elems = nqp::elems($to) - $values; my int $i = -$values; nqp::splice($to,from,$i,$values) while nqp::isle_i($i = $i + $values,$elems); nqp::isgt_i($i,$elems) # something left to init ?? self!spread-rest($i, $elems, $values, $to, from) !! $to } multi method allocate(::?CLASS:U: Int:D $elements, int $value) { my int $elems = $elements; my $blob := nqp::setelems(nqp::create(self),$elems); my int $i = -1; nqp::bindpos_i($blob,$i,$value) while nqp::islt_i(++$i,$elems); $blob } multi method AT-POS(::?ROLE:D: uint $pos) { nqp::isge_i($pos,nqp::elems(self)) ?? self!fail-range($pos) !! nqp::atpos_i(self,$pos) } multi method AT-POS(::?ROLE:D: Int:D $pos) { nqp::isge_i($pos,nqp::elems(self)) || nqp::islt_i($pos,0) ?? self!fail-range($pos) !! nqp::atpos_i(self,$pos) } multi method list(::?ROLE:D:) { my int $elems = nqp::elems(self); # presize memory, but keep it empty, so we can just push my $buffer := nqp::setelems( nqp::setelems(nqp::create(IterationBuffer),$elems), 0 ); my int $i = -1; nqp::push($buffer,nqp::atpos_i(self,$i)) while nqp::islt_i(++$i,$elems); $buffer.List } method reverse(::?CLASS:D:) { my int $elems = nqp::elems(self); my int $last = nqp::sub_i($elems,1); my $reversed := nqp::setelems(nqp::create(self),$elems); my int $i = -1; nqp::bindpos_i($reversed,nqp::sub_i($last,$i), nqp::atpos_i(self,$i)) while nqp::islt_i(++$i,$elems); $reversed } method COMPARE(::?CLASS:D: ::?CLASS:D \other) is implementation-detail { nqp::unless( nqp::cmp_i( (my int $elems = nqp::elems(self)), nqp::elems(my $other := nqp::decont(other)) ), nqp::stmts( # same number of elements (my int $i = -1), nqp::while( nqp::islt_i(++$i,$elems) && nqp::not_i( nqp::cmp_i(nqp::atpos_i(self,$i),nqp::atpos_i($other,$i)) ), nqp::null ), nqp::if( nqp::isne_i($i,$elems), nqp::cmp_i(nqp::atpos_i(self,$i),nqp::atpos_i($other,$i)) ) ) ) } method SAME(::?CLASS:D: Blob:D \other) is implementation-detail { nqp::if( nqp::iseq_i( (my int $elems = nqp::elems(self)), nqp::elems(my $other := nqp::decont(other)) ), nqp::stmts( # same number of elements (my int $i = -1), nqp::while( nqp::islt_i(++$i,$elems) && nqp::iseq_i(nqp::atpos_i(self,$i),nqp::atpos_i($other,$i)), nqp::null ), nqp::iseq_i($i,$elems) ) ) } method join(::?CLASS:D: $delim = '') { my int $elems = nqp::elems(self); my int $i = -1; my $list := nqp::setelems(nqp::setelems(nqp::list_s,$elems),0); nqp::push_s($list,nqp::atpos_i(self,$i)) while nqp::islt_i(++$i,$elems); nqp::join($delim.Str,$list) } } #- PLEASE DON'T CHANGE ANYTHING ABOVE THIS LINE #- end of generated part of Blob Signed role --------------------------------- #- start of generated part of Blob Unsigned role ------------------------------- #- Generated on 2022-03-08T14:31:37+01:00 by ./tools/build/makeBLOB_ROLES.raku #- PLEASE DON'T CHANGE ANYTHING BELOW THIS LINE my role UnsignedBlob[::T] is repr('VMArray') is array_type(T) is implementation-detail { method !push-List(str $action, ::?CLASS:D $to, \from) { my Mu $reified := nqp::getattr(from,List,'$!reified'); if nqp::isconcrete($reified) { my int $elems = nqp::elems($reified); my int $j = nqp::elems($to); nqp::setelems($to, $j + $elems); # presize for efficiency my int $i = -1; nqp::while( nqp::islt_i(++$i,$elems), nqp::stmts( (my $got = nqp::hllize(nqp::atpos($reified,$i))), nqp::if( nqp::istype($got,Int), nqp::bindpos_u($to,$j++,$got), self!throw-typecheck-element($action, $i, $got) ) ) ); } $to } method !push-iterator(str $action, ::?CLASS:D $to, Iterator:D $iter) { my int $i; nqp::until( nqp::eqaddr((my $got := $iter.pull-one),IterationEnd), nqp::if( nqp::istype(nqp::hllize($got),Int), nqp::stmts( nqp::push_i($to,my $ = $got), ++$i ), self!throw-typecheck-element($action,$i,$got) ) ); $to } method !push-list(str $action, ::?CLASS:D $to, \from) { nqp::istype(from,List) ?? self!push-List($action, $to, from) !! self!push-iterator($action, $to, from.iterator) } method !spread-rest( int $i is copy, int $elems is copy, int $values, ::?CLASS:D $to, \from ) { --$i; # went one too far $elems = $elems + $values; my int $j = -1; if from.^array_type.^unsigned { nqp::bindpos_u($to,$i,nqp::atpos_u(from, ++$j % $values)) while nqp::islt_i(++$i,$elems); } else { nqp::bindpos_u($to,$i,nqp::atpos_i(from, ++$j % $values)) while nqp::islt_i(++$i,$elems); } $to } method !spread(::?CLASS:D $to, \from) { my int $values = nqp::elems(from); my int $elems = nqp::elems($to) - $values; my int $i = -$values; nqp::splice($to,from,$i,$values) while nqp::isle_i($i = $i + $values,$elems); nqp::isgt_i($i,$elems) # something left to init ?? self!spread-rest($i, $elems, $values, $to, from) !! $to } multi method allocate(::?CLASS:U: Int:D $elements, int $value) { my int $elems = $elements; my $blob := nqp::setelems(nqp::create(self),$elems); my int $i = -1; nqp::bindpos_u($blob,$i,$value) while nqp::islt_i(++$i,$elems); $blob } multi method AT-POS(::?ROLE:D: uint $pos) { nqp::isge_i($pos,nqp::elems(self)) ?? self!fail-range($pos) !! nqp::atpos_u(self,$pos) } multi method AT-POS(::?ROLE:D: Int:D $pos) { nqp::isge_i($pos,nqp::elems(self)) || nqp::islt_i($pos,0) ?? self!fail-range($pos) !! nqp::atpos_u(self,$pos) } multi method list(::?ROLE:D:) { my int $elems = nqp::elems(self); # presize memory, but keep it empty, so we can just push my $buffer := nqp::setelems( nqp::setelems(nqp::create(IterationBuffer),$elems), 0 ); my int $i = -1; nqp::push($buffer,nqp::atpos_u(self,$i)) while nqp::islt_i(++$i,$elems); $buffer.List } method reverse(::?CLASS:D:) { my int $elems = nqp::elems(self); my int $last = nqp::sub_i($elems,1); my $reversed := nqp::setelems(nqp::create(self),$elems); my int $i = -1; nqp::bindpos_u($reversed,nqp::sub_i($last,$i), nqp::atpos_u(self,$i)) while nqp::islt_i(++$i,$elems); $reversed } method COMPARE(::?CLASS:D: ::?CLASS:D \other) is implementation-detail { nqp::unless( nqp::cmp_i( (my int $elems = nqp::elems(self)), nqp::elems(my $other := nqp::decont(other)) ), nqp::stmts( # same number of elements (my int $i = -1), nqp::while( nqp::islt_i(++$i,$elems) && nqp::not_i( nqp::cmp_i(nqp::atpos_u(self,$i),nqp::atpos_u($other,$i)) ), nqp::null ), nqp::if( nqp::isne_i($i,$elems), nqp::cmp_i(nqp::atpos_u(self,$i),nqp::atpos_u($other,$i)) ) ) ) } method SAME(::?CLASS:D: Blob:D \other) is implementation-detail { nqp::if( nqp::iseq_i( (my int $elems = nqp::elems(self)), nqp::elems(my $other := nqp::decont(other)) ), nqp::stmts( # same number of elements (my int $i = -1), nqp::while( nqp::islt_i(++$i,$elems) && nqp::iseq_i(nqp::atpos_u(self,$i),nqp::atpos_u($other,$i)), nqp::null ), nqp::iseq_i($i,$elems) ) ) } method join(::?CLASS:D: $delim = '') { my int $elems = nqp::elems(self); my int $i = -1; my $list := nqp::setelems(nqp::setelems(nqp::list_s,$elems),0); nqp::push_s($list,nqp::atpos_u(self,$i)) while nqp::islt_i(++$i,$elems); nqp::join($delim.Str,$list) } } #- PLEASE DON'T CHANGE ANYTHING ABOVE THIS LINE #- end of generated part of Blob Unsigned role --------------------------------- my role Blob[::T = uint8] does Positional[T] does Stringy is repr('VMArray') is array_type(T) { die "Can only parameterize with native int types, not '{T.^name}'." unless nqp::objprimspec(T) == 1 || (nqp::objprimspec(T) >= 4 && nqp::objprimspec(T) <= 10); $?CLASS.^add_role(T.^unsigned ?? UnsignedBlob.^parameterize(T) !! SignedBlob.^parameterize(T)); # other then *8 not supported yet my int $bpe = try { #?if jvm # https://colabti.org/irclogger/irclogger_log/perl6-dev?date=2017-01-20#l202 CATCH { default { Nil } } #?endif (T.^nativesize / 8).Int } // 1; multi method WHICH(Blob:D: --> ValueObjAt:D) { nqp::box_s( nqp::concat( nqp::if( nqp::eqaddr(self.WHAT,Blob), 'Blob|', nqp::concat(nqp::unbox_s(self.^name), '|') ), nqp::sha1(self.decode("latin-1")) ), ValueObjAt ) } multi method new(Blob:) { nqp::create(self) } multi method new(Blob: Blob:D $blob) is default { nqp::splice(nqp::create(self),$blob,0,0) } multi method new(Blob: int @values) { nqp::splice(nqp::create(self),@values,0,0) } multi method new(Blob: @values) { nqp::create(self).STORE(@values, :INITIALIZE) } multi method new(Blob: *@values) { nqp::create(self).STORE(@values, :INITIALIZE) } # Because it is (apparently) impossible to stub the Buf role in the # setting, the lookup for Buf needs to be done at runtime, hence the # :: rather than just Buf. method Buf(Blob:D:) { (nqp::eqaddr(T,uint8) ?? :: !! ::.^parameterize(T)).new: self } proto method STORE(Blob:D: |) {*} multi method STORE(Blob:D: Iterable:D \iterable, :$INITIALIZE) { $INITIALIZE ?? iterable.is-lazy ?? self.throw-iterator-cannot-be-lazy('store') !! self!push-list("initializ",self,iterable) !! X::Assignment::RO.new(:value(self)).throw } multi method STORE(Blob:D: Any:D \non-iterable, :$INITIALIZE) { X::Assignment::RO.new(:value(self)).throw unless $INITIALIZE; my int $elems = non-iterable.elems; nqp::push_i(self,my $ = non-iterable.AT-POS($_)) for ^$elems; #FIXME needs to handle unsigned with push_u self } proto method allocate(|) {*} multi method allocate(Blob:U: Int:D $elements) { nqp::setelems(nqp::create(self),$elements) } multi method allocate(Blob:U: Int:D $elements, Int:D \value) { my int $value = value; self.allocate($elements,$value) } multi method allocate(Blob:U: Int:D $elements, Mu:D $got) { self!fail-typecheck('allocate',$got) } multi method allocate(Blob:U: Int:D $elements, int @values) { self!spread(nqp::setelems(nqp::create(self),$elements),@values) } multi method allocate(Blob:U: Int:D $elements, Blob:D $blob) { self!spread(nqp::setelems(nqp::create(self),$elements),$blob) } multi method allocate(Blob:U: Int:D $elements, @values) { self!spread(nqp::setelems(nqp::create(self),$elements),Blob.new(@values)) } multi method EXISTS-POS(Blob:D: int \pos) { nqp::hllbool( nqp::islt_i(pos,nqp::elems(self)) && nqp::isge_i(pos,0) ); } multi method EXISTS-POS(Blob:D: Int:D \pos) { nqp::hllbool( nqp::islt_i(pos,nqp::elems(self)) && nqp::isge_i(pos,0) ); } #?if moar # for simplicity's sake, these are not multis method read-int8(::?ROLE:D: int $offset, Endian $? --> int) is raw { nqp::readint(self,$offset, nqp::bitor_i( nqp::const::BINARY_SIZE_8_BIT, nqp::const::BINARY_ENDIAN_NATIVE ) ) } method read-int16(::?ROLE:D: int $offset, Endian $endian = NativeEndian --> int ) is raw { nqp::readint(self,$offset, nqp::bitor_i(nqp::const::BINARY_SIZE_16_BIT,$endian)) } method read-int32(::?ROLE:D: int $offset, Endian $endian = NativeEndian --> int ) is raw { nqp::readint(self,$offset, nqp::bitor_i(nqp::const::BINARY_SIZE_32_BIT,$endian)) } method read-int64(::?ROLE:D: int $offset, Endian $endian = NativeEndian --> int ) is raw { nqp::readint(self,$offset, nqp::bitor_i(nqp::const::BINARY_SIZE_64_BIT,$endian)) } method read-int128(::?ROLE:D: int $offset, Endian $endian = NativeEndian --> Int ) is raw { my \unsigned := self.read-uint128($offset,$endian); unsigned >= 1 +< 127 ?? unsigned - 1 +< 128 !! unsigned } method read-uint8(::?ROLE:D: int $offset, Endian $? --> uint) is raw { nqp::readuint(self,$offset, nqp::bitor_i( nqp::const::BINARY_SIZE_8_BIT, nqp::const::BINARY_ENDIAN_NATIVE ) ) } method read-uint16(::?ROLE:D: int $offset, Endian $endian = NativeEndian --> uint ) is raw { nqp::readuint(self,$offset, nqp::bitor_i(nqp::const::BINARY_SIZE_16_BIT,$endian)) } method read-uint32(::?ROLE:D: int $offset, Endian $endian = NativeEndian --> uint ) is raw { nqp::readuint(self,$offset, nqp::bitor_i(nqp::const::BINARY_SIZE_32_BIT,$endian)) } method read-uint64(::?ROLE:D: int $offset, Endian $endian = NativeEndian --> uint ) is raw { my \signed := nqp::readuint(self,$offset, nqp::bitor_i(nqp::const::BINARY_SIZE_64_BIT,$endian)); signed < 0 ?? signed + 1 +< 64 !! signed } method read-uint128(::?ROLE:D: int $offset, Endian $endian = NativeEndian --> uint ) is raw { my \first := self.read-uint64($offset, $endian); my \second := self.read-uint64($offset + 8, $endian); $endian == BigEndian || ($endian == NativeEndian && Kernel.endian == BigEndian) ?? first +< 64 +| second !! second +< 64 +| first } method read-num32(::?ROLE:D: int $offset, Endian $endian = NativeEndian --> num ) is raw { nqp::readnum(self,$offset, nqp::bitor_i(nqp::const::BINARY_SIZE_32_BIT,$endian)) } method read-num64(::?ROLE:D: int $offset, Endian $endian = NativeEndian --> num ) is raw { nqp::readnum(self,$offset, nqp::bitor_i(nqp::const::BINARY_SIZE_64_BIT,$endian)) } #?endif method read-bits(::?ROLE:D \SELF: int $pos, Int:D $bits --> Int:D) { my $result := SELF.read-ubits($pos, $bits); $result > 1 +< ($bits - 1) - 1 ?? $result - 1 +< $bits !! $result } method read-ubits(::?ROLE:D \SELF: int $pos, Int:D $bits --> UInt:D) { # sanity checking die "Can only read from position 0..{ nqp::elems(self) * 8 - 1 } in buffer{ " '" ~ SELF.VAR.name ~ "'" if nqp::iscont(SELF) }, you tried: $pos" if $pos < 0; die "Can only read 1..{ nqp::elems(self) * 8 - $pos } bits from position $pos in buffer{ " '" ~ SELF.VAR.name ~ "'" if nqp::iscont(SELF) }, you tried: $bits" if ($pos + $bits - 1) +> 3 >= nqp::elems(self); # set up stuff to work with my int $first-bit = $pos +& 7; # 0 = left-aligned my int $last-bit = ($pos + $bits) +& 7; # 0 = right-aligned my int $first-byte = $pos +> 3; my int $last-byte = ($pos + $bits - 1) +> 3; # l=least significant byte, m=most significant byte # 00010010 00110100 01011100 01111000 10011010 # ________ mmmmmmmm llllllll ________ ________ 8,16 mmmmmmmm llllllll # ________ __mmmmmm llllllll ________ ________ 8,16 mmmmmm llllllll # ________ mmmmmmll llllll__ ________ ________ 8,16 mmmmmm llllllll # ________ __mmmmmm mmllllll ll______ ________ 10,16 mmmmmmmm llllllll # ________ ________ ______ll lll_____ ________ 21, 5 lllll # ________ ________ ________ __lllll_ ________ 26, 5 lllll nqp::if( nqp::iseq_i($first-byte,$last-byte), (my $result := self.AT-POS($first-byte)), nqp::stmts( ($result := 0), (my int $i = $first-byte - 1), nqp::while( nqp::isle_i(++$i,$last-byte), ($result := nqp::bitshiftl_I($result,8,Int) +| self.AT-POS($i)) ) ) ); $last-bit ?? ($result +> (8 - $last-bit)) # not right-aligned, so +& (1 +< $bits - 1) # shift and mask !! $first-bit # right-aligned ?? $result +& (1 +< $bits - 1) # but not left-aligned, so mask !! $result # also left-aligned, already done } multi method Bool(Blob:D:) { nqp::hllbool(nqp::elems(self)) } method Capture(Blob:D:) { self.List.Capture } multi method elems(Blob:D:) { nqp::elems(self) } method Numeric(Blob:D:) { nqp::p6box_i(nqp::elems(self)) } method Int(Blob:D:) { nqp::p6box_i(nqp::elems(self)) } method bytes(Blob:D:) { nqp::mul_i(nqp::elems(self),$bpe) } method chars(Blob:D:) { X::Buf::AsStr.new(object => self, method => 'chars').throw } method codes(Blob:D:) { X::Buf::AsStr.new(object => self, method => 'codes').throw } multi method Str(Blob:D:) { X::Buf::AsStr.new(object => self, method => 'Str' ).throw } multi method Stringy(Blob:D:) { X::Buf::AsStr.new(object => self, method => 'Stringy' ).throw } proto method decode(|) {*} multi method decode(Blob:D: $encoding = self.encoding // "utf-8") { nqp::p6box_s( nqp::decode(self, Rakudo::Internals.NORMALIZE_ENCODING($encoding)) ) } #?if !jvm multi method decode(Blob:D: $encoding, Str :$replacement!, Bool:D :$strict = False) { nqp::p6box_s( nqp::decoderepconf(self, Rakudo::Internals.NORMALIZE_ENCODING($encoding), $replacement.defined ?? $replacement !! nqp::null_s(), $strict ?? 0 !! 1)) } multi method decode(Blob:D: $encoding, Bool:D :$strict = False) { nqp::p6box_s( nqp::decodeconf(self, Rakudo::Internals.NORMALIZE_ENCODING($encoding), $strict ?? 0 !! 1)) } #?endif #?if jvm multi method decode(Blob:D: $encoding, Bool:D :$strict = False) { nqp::p6box_s( nqp::decode(self, Rakudo::Internals.NORMALIZE_ENCODING($encoding))) } multi method decode(Blob:D: $encoding, Str:D :$replacement!, Bool:D :$strict = False) { NYI('decode-with-replacement').throw; } #?endif my $char := nqp::list_s( '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' ); multi method gist(Blob:D:) { # (u)int don't have a nativesize, so just assume 64-bit for them my int $nativesize = nqp::div_i(T.^nativesize // $?BITS, 4) || 1; my int $todo = nqp::elems(self) min nqp::div_i(200,$nativesize); my int $i = -1; my $chunks := nqp::list_s; my int $unsigned = T.^unsigned; my int $elem; nqp::while( nqp::islt_i(++$i,$todo), nqp::stmts( nqp::if( $unsigned, ($elem = nqp::atpos_u(self,$i)), ($elem = nqp::atpos_i(self,$i)) ), (my $chunk := nqp::list_s), (my int $size = $nativesize), nqp::while( nqp::isgt_i($size,0), nqp::stmts( nqp::unshift_s( $chunk, nqp::atpos_s($char,nqp::bitand_i($elem,0xF)) ), ($elem = nqp::bitshiftr_i($elem,4)), ($size = nqp::sub_i($size,1)) ) ), nqp::push_s($chunks,nqp::join('',$chunk)) ) ); nqp::push_s($chunks,"...") if nqp::isgt_i(nqp::elems(self),$todo); nqp::join('',nqp::list_s(self.^name,':0x<',nqp::join(" ",$chunks),'>')) } multi method raku(Blob:D:) { self.^name ~ '.new(' ~ self.join(',') ~ ')'; } # Made this a sub instead of a private method so that the optimizer # doesn't need to put in IntLexRef's for the native int parameters. # Since we're not using any attributes, just self, that was an easy # choice to make. sub subbuf-end(\SELF, int $start, int $end, int $elems) { nqp::if( nqp::islt_i($start,0) || nqp::isgt_i($start,$elems), X::OutOfRange.new( what => '"From argument to subbuf', got => $start, range => "0.." ~ $elems ).Failure, nqp::if( nqp::isle_i( (my int $last = nqp::if(nqp::isge_i($end,$elems),$elems-1,$end)), $start - 1 ), # 0 elements to return nqp::create(SELF), # just create a new one nqp::slice(SELF,$start,$last) # do the actual slice ) ) } sub subbuf-length(\SELF, int $from, int $length, int $elems) { nqp::islt_i($length,0) ?? X::OutOfRange.new( what => 'Len element to subbuf', got => $length, range => "0.." ~ $elems ).Failure !! subbuf-end(SELF, $from, $from + $length - 1, $elems) } proto method subbuf(|) {*} multi method subbuf(Blob:D: Range:D $fromto) { nqp::if( nqp::getattr_i(nqp::decont($fromto),Range,'$!is-int'), nqp::stmts( (my int $start = nqp::add_i( nqp::unbox_i(nqp::getattr(nqp::decont($fromto),Range,'$!min')), nqp::getattr_i(nqp::decont($fromto),Range,'$!excludes-min') )), (my int $end = nqp::sub_i( nqp::unbox_i(nqp::getattr(nqp::decont($fromto),Range,'$!max')), nqp::getattr_i(nqp::decont($fromto),Range,'$!excludes-max') )), subbuf-end(self, $start, $end, nqp::elems(self)) ), X::AdHoc.new( payload => "Must specify a Range with integer bounds to subbuf" ).Failure ) } multi method subbuf(Blob:D: Int:D $From) { my int $elems = nqp::elems(self); my int $from = $From; subbuf-end(self, $from, $elems, $elems) } multi method subbuf(Blob:D: &From) { my int $elems = nqp::elems(self); my int $from = From(nqp::box_i($elems,Int)); subbuf-end(self, $from, $elems, $elems) } multi method subbuf(Blob:D: Int:D $From, Int:D $Length) { my int $from = $From; my int $length = $Length; subbuf-length(self, $from, $length, nqp::elems(self)) } multi method subbuf(Blob:D: Int:D $From, &End) { my int $elems = nqp::elems(self); my int $from = $From; my int $end = End(nqp::box_i($elems,Int)); subbuf-end(self, $from, $end, $elems) } multi method subbuf(Blob:D: &From, Int:D $Length) { my int $elems = nqp::elems(self); my int $from = From(nqp::box_i($elems,Int)); my int $length = $Length; subbuf-length(self, $from, $length, $elems) } multi method subbuf(Blob:D: &From, &End) { my int $elems = nqp::elems(self); my int $from = From(nqp::box_i($elems,Int)); my int $end = End(nqp::box_i($elems,Int)); subbuf-end(self, $from, $end, $elems) } multi method subbuf(Blob:D: \from, Whatever) { self.subbuf(from) } multi method subbuf(Blob:D: \from, Numeric \length) { length == Inf ?? self.subbuf(from) !! self.subbuf(from,length.Int) } proto method unpack(|) {*} multi method unpack(Blob:D: Str:D $template) { nqp::isnull(nqp::getlexcaller('EXPERIMENTAL-PACK')) ?? X::Experimental.new( feature => "the 'unpack' method", use => "pack" ).throw !! self.unpack($template.comb(/<[a..zA..Z]>[\d+|'*']?/)) } multi method unpack(Blob:D: @template) { nqp::isnull(nqp::getlexcaller('EXPERIMENTAL-PACK')) ?? X::Experimental.new( feature => "the 'unpack' method", use => "pack" ).throw !! nqp::getlexcaller('EXPERIMENTAL-PACK')(self, @template) } # XXX: the pack.t spectest file seems to require this method # not sure if it should be changed to list there... method contents(Blob:D:) { self.list } method encoding() { Any } method !unshift-list(\action,\to,\from) { if nqp::istype(from,List) { my Mu $from := nqp::getattr(from,List,'$!reified'); if nqp::defined($from) { my int $i = nqp::elems($from); nqp::istype((my $got = nqp::atpos($from,$i)),Int) ?? nqp::unshift_i(to,$got) !! self!fail-typecheck-element(action,$i,$got).throw while nqp::isge_i(--$i,0); } to } else { nqp::splice(to,self!push-list(action,nqp::create(self),from),0,0) } } method !fail-range($got) { X::OutOfRange.new( :what($*INDEX // 'Index'), :$got, :range("0..{nqp::elems(self)-1}") ).Failure } method !typecheck($action, $got) { X::TypeCheck.new( operation => $action ~ " to " ~ self.^name, got => $got, expected => T, ) } method !fail-typecheck($action,$got) { self!typecheck($action, $got).Failure } method !typecheck-element($action, $i, $got) { self!typecheck($action ~ "ing element #" ~ $i, $got) } method !fail-typecheck-element($action, $i, $got) { self!typecheck-element($action, $i, $got).Failure } method !throw-typecheck-element($action, $i, $got) { self!typecheck-element($action, $i, $got).throw } multi method ACCEPTS(Blob:D: Blob:D \Other) { nqp::hllbool( nqp::unless( nqp::eqaddr(self,my \other := nqp::decont(Other)), nqp::if( nqp::iseq_i( (my int $elems = nqp::elems(self)), nqp::elems(other) ), nqp::stmts( (my int $i = -1), nqp::while( nqp::islt_i(++$i,$elems) && (self[$i] == other[$i]), nqp::null ), nqp::iseq_i($i,$elems) ) ) ) ) } } constant blob8 = Blob[uint8]; constant blob16 = Blob[uint16]; constant blob32 = Blob[uint32]; constant blob64 = Blob[uint64]; my class utf8 does Blob[uint8] is repr('VMArray') { method encoding(--> "utf-8") { } multi method Str(utf8:D:) { self.decode } multi method Stringy(utf8:D:) { self.decode } } my class utf16 does Blob[uint16] is repr('VMArray') { method encoding(--> "utf-16") { } multi method Str(utf16:D:) { self.decode } multi method Stringy(utf16:D:) { self.decode } } my class utf32 does Blob[uint32] is repr('VMArray') { method encoding(--> "utf-32") { } multi method Str(utf32:D:) { self.decode } multi method Stringy(utf32:D:) { self.decode } } my role Buf[::T = uint8] does Blob[T] is repr('VMArray') is array_type(T) { #- start of generated part of Buf Signed role -------------------------------- #- Generated on 2022-02-17T17:11:17+01:00 by ./tools/build/makeBUF_ROLES.raku #- PLEASE DON'T CHANGE ANYTHING BELOW THIS LINE my role SignedBuf[::T] is repr('VMArray') is array_type(T) is implementation-detail { multi method AT-POS(::?ROLE:D: uint $pos) is raw is default { nqp::atposref_i(self,$pos) } multi method AT-POS(::?ROLE:D: Int:D $pos) is raw is default { nqp::islt_i($pos,0) ?? self!fail-range($pos) !! nqp::atposref_i(self,$pos) } multi method ASSIGN-POS(::?ROLE:D: uint $pos, Mu \assignee) { nqp::bindpos_i(self,$pos,assignee) } multi method ASSIGN-POS(::?ROLE:D: Int:D $pos, Mu \assignee) { nqp::islt_i($pos,0) ?? self!fail-range($pos) !! nqp::bindpos_i(self,$pos,assignee) } multi method list(::?ROLE:D:) is default { my int $elems = nqp::elems(self); # presize memory, but keep it empty, so we can just push my $buffer := nqp::setelems( nqp::setelems(nqp::create(IterationBuffer),$elems), 0 ); my int $i = -1; nqp::while( nqp::islt_i(++$i,$elems), nqp::push($buffer,nqp::atposref_i(self,$i)) ); $buffer.List } method write-ubits(::?ROLE \SELF: int $pos, Int:D $bits, UInt:D \value ) is raw { # sanity check POS-OOR(SELF, $pos) if $pos < 0; my $self := nqp::isconcrete(self) ?? self !! nqp::create(self); # set up basic info my int $first-bit = $pos +& 7; my int $last-bit = ($pos + $bits) +& 7; my int $first-byte = $pos +> 3; my int $last-byte = ($pos + $bits - 1) +> 3; my $value := value +& (1 +< $bits - 1); # mask valid part $value := $value +< (8 - $last-bit) if $last-bit; # move into position my int $lmask = nqp::sub_i(1 +< $first-bit,1) +< (8 - $first-bit) if $first-bit; my int $rmask = 1 +< nqp::sub_i(8 - $last-bit,1) if $last-bit; # all done in a single byte if $first-byte == $last-byte { nqp::bindpos_i($self,$first-byte, $value +| (nqp::atpos_i($self,$first-byte) +& ($lmask +| $rmask)) ); } # spread over multiple bytes else { my int $i = $last-byte; # process last byte first if it is a partial if $last-bit { nqp::bindpos_i($self,$i, ($value +& 255) +| (nqp::atpos_i($self,$i) +& $rmask) ); $value := $value +> 8; } # not a partial, so make sure we process last byte later else { ++$i; } # walk from right to left, exclude left-most is partial my int $last = $first-byte + nqp::isgt_i($first-bit,0); nqp::while( nqp::isge_i(--$i,$last), nqp::stmts( nqp::bindpos_i($self,$i,($value +& 255)), ($value := $value +> 8) ) ); # process last byte if it was a partial nqp::bindpos_i($self,$i,($value +& 255) +| (nqp::atpos_i($self,$i) +& $lmask)) if $first-bit; } $self } } #- PLEASE DON'T CHANGE ANYTHING ABOVE THIS LINE #- end of generated part of Buf Signed role ---------------------------------- #- start of generated part of Buf Unsigned role -------------------------------- #- Generated on 2022-02-17T17:11:17+01:00 by ./tools/build/makeBUF_ROLES.raku #- PLEASE DON'T CHANGE ANYTHING BELOW THIS LINE my role UnsignedBuf[::T] is repr('VMArray') is array_type(T) is implementation-detail { multi method AT-POS(::?ROLE:D: uint $pos) is raw is default { nqp::atposref_u(self,$pos) } multi method AT-POS(::?ROLE:D: Int:D $pos) is raw is default { nqp::islt_i($pos,0) ?? self!fail-range($pos) !! nqp::atposref_u(self,$pos) } multi method ASSIGN-POS(::?ROLE:D: uint $pos, Mu \assignee) { nqp::bindpos_u(self,$pos,assignee) } multi method ASSIGN-POS(::?ROLE:D: Int:D $pos, Mu \assignee) { nqp::islt_i($pos,0) ?? self!fail-range($pos) !! nqp::bindpos_u(self,$pos,assignee) } multi method list(::?ROLE:D:) is default { my int $elems = nqp::elems(self); # presize memory, but keep it empty, so we can just push my $buffer := nqp::setelems( nqp::setelems(nqp::create(IterationBuffer),$elems), 0 ); my int $i = -1; nqp::while( nqp::islt_i(++$i,$elems), nqp::push($buffer,nqp::atposref_u(self,$i)) ); $buffer.List } method write-ubits(::?ROLE \SELF: int $pos, Int:D $bits, UInt:D \value ) is raw { # sanity check POS-OOR(SELF, $pos) if $pos < 0; my $self := nqp::isconcrete(self) ?? self !! nqp::create(self); # set up basic info my int $first-bit = $pos +& 7; my int $last-bit = ($pos + $bits) +& 7; my int $first-byte = $pos +> 3; my int $last-byte = ($pos + $bits - 1) +> 3; my $value := value +& (1 +< $bits - 1); # mask valid part $value := $value +< (8 - $last-bit) if $last-bit; # move into position my int $lmask = nqp::sub_i(1 +< $first-bit,1) +< (8 - $first-bit) if $first-bit; my int $rmask = 1 +< nqp::sub_i(8 - $last-bit,1) if $last-bit; # all done in a single byte if $first-byte == $last-byte { nqp::bindpos_u($self,$first-byte, $value +| (nqp::atpos_u($self,$first-byte) +& ($lmask +| $rmask)) ); } # spread over multiple bytes else { my int $i = $last-byte; # process last byte first if it is a partial if $last-bit { nqp::bindpos_u($self,$i, ($value +& 255) +| (nqp::atpos_u($self,$i) +& $rmask) ); $value := $value +> 8; } # not a partial, so make sure we process last byte later else { ++$i; } # walk from right to left, exclude left-most is partial my int $last = $first-byte + nqp::isgt_i($first-bit,0); nqp::while( nqp::isge_i(--$i,$last), nqp::stmts( nqp::bindpos_u($self,$i,($value +& 255)), ($value := $value +> 8) ) ); # process last byte if it was a partial nqp::bindpos_u($self,$i,($value +& 255) +| (nqp::atpos_u($self,$i) +& $lmask)) if $first-bit; } $self } } #- PLEASE DON'T CHANGE ANYTHING ABOVE THIS LINE #- end of generated part of Buf Unsigned role ---------------------------------- $?CLASS.^add_role(T.^unsigned ?? UnsignedBuf[T] !! SignedBuf[T]); multi method WHICH(Buf:D:) { self.Mu::WHICH } method Blob(Blob:D:) { (nqp::eqaddr(T,uint8) ?? Blob !! Blob.^parameterize(T)).new: self } multi method STORE(Buf:D: Blob:D $blob) { nqp::splice(nqp::setelems(self,0),$blob,0,0) } # The "is default" is needed to prevent runtime dispatch errors multi method STORE(Buf:D: int @values) is default { nqp::splice(nqp::setelems(self,0),@values,0,0) } multi method STORE(Buf:D: Iterable:D \iterable) { iterable.is-lazy ?? self.throw-iterator-cannot-be-lazy('store') !! self!push-list("initializ",nqp::setelems(self,0),iterable); } multi method STORE(Buf:D: Any:D \non-iterable) { my int $elems = non-iterable.elems; nqp::setelems(self,0); nqp::push_i(self,my $ = non-iterable.AT-POS($_)) for ^$elems; #FIXME needs to handle unsigned with push_u self } #?if moar # for simplicity's sake, these are not multis method write-int8(::?ROLE: int $offset, int8 $value, Endian $endian = NativeEndian ) is raw { my $self := nqp::isconcrete(self) ?? self !! nqp::create(self); nqp::writeint($self,$offset,$value, nqp::bitor_i(nqp::const::BINARY_SIZE_8_BIT,$endian)); $self } method write-int16(::?ROLE: int $offset, int16 $value, Endian $endian = NativeEndian ) is raw { my $self := nqp::isconcrete(self) ?? self !! nqp::create(self); nqp::writeint($self,$offset,$value, nqp::bitor_i(nqp::const::BINARY_SIZE_16_BIT,$endian)); $self } method write-int32(::?ROLE: int $offset, int32 $value, Endian $endian = NativeEndian ) is raw { my $self := nqp::isconcrete(self) ?? self !! nqp::create(self); nqp::writeint($self,$offset,$value, nqp::bitor_i(nqp::const::BINARY_SIZE_32_BIT,$endian)); $self } method write-int64(::?ROLE: int $offset, Int:D $value, Endian $endian = NativeEndian ) is raw { my $self := nqp::isconcrete(self) ?? self !! nqp::create(self); nqp::writeint($self,$offset,$value, nqp::bitor_i(nqp::const::BINARY_SIZE_64_BIT,$endian)); $self } method write-int128(::?ROLE: int $offset, Int:D $value, Endian $endian = NativeEndian ) is raw { # These uints are intentional to keep the value within 64 bits my uint $first = ($value +> 64) +& (1 +< 64 - 1); my uint $second = $value +& (1 +< 64 - 1); my $be = $endian == BigEndian || ($endian == NativeEndian && Kernel.endian == BigEndian); my $self := nqp::isconcrete(self) ?? self !! nqp::create(self); $self.write-uint64($offset, $be ?? $first !! $second, $endian); $self.write-uint64($offset + 8, $be ?? $second !! $first, $endian); $self } method write-uint8(::?ROLE: int $offset, uint8 $value, Endian $endian = NativeEndian ) is raw { my $self := nqp::isconcrete(self) ?? self !! nqp::create(self); nqp::writeuint($self,$offset,$value, nqp::bitor_i(nqp::const::BINARY_SIZE_8_BIT,$endian)); $self } method write-uint16(::?ROLE: int $offset, uint16 $value, Endian $endian = NativeEndian ) is raw { my $self := nqp::isconcrete(self) ?? self !! nqp::create(self); nqp::writeuint($self,$offset,$value, nqp::bitor_i(nqp::const::BINARY_SIZE_16_BIT,$endian)); $self } method write-uint32(::?ROLE: int $offset, uint32 $value, Endian $endian = NativeEndian ) is raw { my $self := nqp::isconcrete(self) ?? self !! nqp::create(self); nqp::writeuint($self,$offset,$value, nqp::bitor_i(nqp::const::BINARY_SIZE_32_BIT,$endian)); $self } method write-uint64(::?ROLE: int $offset, UInt:D $value, Endian $endian = NativeEndian ) is raw { my $self := nqp::isconcrete(self) ?? self !! nqp::create(self); nqp::writeuint($self,$offset,$value, nqp::bitor_i(nqp::const::BINARY_SIZE_64_BIT,$endian)); $self } method write-uint128(::?ROLE: int $offset, UInt:D $value, Endian $endian = NativeEndian ) is raw { my \first := $value +> 64; my \second := $value +& ( 1 +< 64 - 1 ); my $be = $endian == BigEndian || ($endian == NativeEndian && Kernel.endian == BigEndian); my $self := nqp::isconcrete(self) ?? self !! nqp::create(self); $self.write-uint64($offset, $be ?? first !! second, $endian); $self.write-uint64($offset + 8, $be ?? second !! first, $endian); $self } method write-num32(::?ROLE: int $offset, num32 $value, Endian $endian = NativeEndian ) is raw { my $self := nqp::isconcrete(self) ?? self !! nqp::create(self); nqp::writenum($self,$offset,$value, nqp::bitor_i(nqp::const::BINARY_SIZE_32_BIT,$endian)); $self } method write-num64(::?ROLE: int $offset, num64 $value, Endian $endian = NativeEndian ) is raw { my $self := nqp::isconcrete(self) ?? self !! nqp::create(self); nqp::writenum($self,$offset,$value, nqp::bitor_i(nqp::const::BINARY_SIZE_64_BIT,$endian)); $self } #?endif sub POS-OOR(\SELF, int $pos --> Nil) is hidden-from-backtrace { die "Can only write from position 0..* in buffer{ " '" ~ SELF.VAR.name ~ "'" if nqp::iscont(SELF) }, you tried: $pos" } method write-bits(::?ROLE \SELF: int $pos, Int:D $bits, Int:D \value ) is raw { SELF.write-ubits($pos, $bits, value +& (1 +< $bits - 1)) } proto method pop(|) { * } multi method pop(Buf:D:) { nqp::elems(self) ?? nqp::pop_i(self) !! self.fail-cannot-be-empty('pop') } proto method shift(|) { * } multi method shift(Buf:D:) { nqp::elems(self) ?? nqp::shift_i(self) !! self.fail-cannot-be-empty('shift') } method reallocate(Buf:D: Int:D $elements) { nqp::setelems(self,$elements) } my $empty := nqp::list_i; proto method splice(|) { * } multi method splice(Buf:D \SELF:) { my $buf = SELF; SELF = Buf.new; $buf } multi method splice(Buf:D: Int:D $offset, $size = Whatever) { my int $remove = self!remove($offset,$size); my $result := $remove ?? self.subbuf($offset,$remove) # until something smarter !! nqp::create(self); nqp::splice(self,$empty,$offset,$remove); $result } multi method splice(Buf:D: Int:D $offset, $size, int $got) { self!splice-native($offset,$size,$got) } multi method splice(Buf:D: Int:D $offset, $size, Int:D $got) { self!splice-native($offset,$size,$got) } multi method splice(Buf:D: Int:D $offset, $size, Mu:D $got) { self!fail-typecheck('splice',$got) } multi method splice(Buf:D: Int:D $offset, $size, Buf:D $buf) { self!splice-native($offset,$size,$buf) } multi method splice(Buf:D: Int:D $offset, $size, int @values) { self!splice-native($offset,$size,@values) } multi method splice(Buf:D: Int:D $offset, $size, @values) { self!splice-native($offset,$size, self!push-list("splic",nqp::create(self),@values)) } method !remove(\offset,\size) { nqp::istype(size,Whatever) ?? nqp::elems(self) - offset !! nqp::istype(size,Int) ?? size !! size.Int } method !splice-native(Buf:D: Int:D $offset, $size, \x) { my int $remove = self!remove($offset,$size); my $result := $remove ?? self.subbuf($offset,$remove) # until something smarter !! nqp::create(self); nqp::splice( self,nqp::islist(x) ?? x !! nqp::list_i(x),$offset,$remove); $result } proto method push(|) { * } multi method push(Buf:D: int $got) { nqp::push_i(self,$got); self } multi method push(Buf:D: Int:D $got) { nqp::push_i(self,$got); self } multi method push(Buf:D: Mu:D $got) { self!fail-typecheck('push',$got) } multi method push(Buf:D: Blob:D $buf) { nqp::splice(self,$buf,nqp::elems(self),0) } multi method push(Buf:D: **@values) { self!pend(@values,'push') } proto method append(|) { * } multi method append(Buf:D: int $got) { nqp::push_i(self,$got); self } multi method append(Buf:D: Int:D $got) { nqp::push_i(self,$got); self } multi method append(Buf:D: Mu:D $got) { self!fail-typecheck('append',$got) } multi method append(Buf:D: Blob:D $buf) { nqp::splice(self,$buf,nqp::elems(self),0) } multi method append(Buf:D: int @values) { nqp::splice(self,@values,nqp::elems(self),0) } multi method append(Buf:D: @values) { self!pend(@values,'append') } multi method append(Buf:D: *@values) { self!pend(@values,'append') } proto method unshift(|) { * } multi method unshift(Buf:D: int $got) { nqp::unshift_i(self,$got); self } multi method unshift(Buf:D: Int:D $got) { nqp::unshift_i(self,$got); self } multi method unshift(Buf:D: Mu:D $got) { self!fail-typecheck('unshift',$got) } multi method unshift(Buf:D: Blob:D $buf) { nqp::splice(self,$buf,0,0) } multi method unshift(Buf:D: **@values) { self!pend(@values,'unshift') } proto method prepend(|) { * } multi method prepend(Buf:D: int $got) { nqp::unshift_i(self,$got); self } multi method prepend(Buf:D: Int:D $got) { nqp::unshift_i(self,$got); self } multi method prepend(Buf:D: Mu:D $got) { self!fail-typecheck('prepend',$got) } multi method prepend(Buf:D: Blob:D $buf) { nqp::splice(self,$buf,0,0) } multi method prepend(Buf:D: int @values) { nqp::splice(self,@values,0,0) } multi method prepend(Buf:D: @values) { self!pend(@values,'prepend') } multi method prepend(Buf:D: *@values) { self!pend(@values,'prepend') } method !pend(Buf:D: @values, $action) { @values.is-lazy ?? self.fail-iterator-cannot-be-lazy($action) !! $action eq 'push' || $action eq 'append' ?? self!push-list($action,self,@values) !! self!unshift-list($action,self,@values) } method subbuf-rw($from = 0, $elems = self.elems - $from) is rw { my Blob $subbuf = self.subbuf($from, $elems); Proxy.new( FETCH => sub ($) { $subbuf }, STORE => sub ($, Blob:D $new) { nqp::splice(self,nqp::decont($new),$from,$elems) } ); } } constant buf8 = Buf[uint8]; constant buf16 = Buf[uint16]; constant buf32 = Buf[uint32]; constant buf64 = Buf[uint64]; multi sub prefix:<~>(Blob:D \a) { X::Buf::AsStr.new(object => a, method => '~' ).throw } multi sub infix:<~>(Blob:D $a) { $a } multi sub infix:<~>(Blob:D $a, Blob:D $b) { my $res := nqp::create(nqp::eqaddr($a.WHAT,$b.WHAT) ?? $a !! Buf.^pun); my $adc := nqp::decont($a); my $bdc := nqp::decont($b); my int $alen = nqp::elems($adc); my int $blen = nqp::elems($bdc); nqp::setelems($res, $alen + $blen); nqp::splice($res, $adc, 0, $alen); nqp::splice($res, $bdc, $alen, $blen); } multi sub prefix:<~^>(UnsignedBlob:D $a) { my int $elems = nqp::elems($a); my $r := nqp::create($a); nqp::setelems($a,$elems); my int $i = -1; nqp::bindpos_u($r,$i,nqp::bitneg_i(nqp::atpos_u($a,$i))) while nqp::islt_i(++$i,$elems); $r } multi sub prefix:<~^>(SignedBlob:D $a) { my int $elems = nqp::elems($a); my $r := nqp::create($a); nqp::setelems($a,$elems); my int $i = -1; nqp::bindpos_i($r,$i,nqp::bitneg_i(nqp::atpos_i($a,$i))) while nqp::islt_i(++$i,$elems); $r } multi sub infix:<~&>(UnsignedBlob:D $a, UnsignedBlob:D $b) { my int $elemsa = nqp::elems($a); my int $elemsb = nqp::elems($b); my int $do = $elemsa > $elemsb ?? $elemsb !! $elemsa; my int $max = $elemsa > $elemsb ?? $elemsa !! $elemsb; my $r := nqp::create($a); nqp::setelems($r,$max); my int $i = -1; nqp::bindpos_u($r,$i, nqp::bitand_i(nqp::atpos_u($a,$i),nqp::atpos_u($b,$i))) while nqp::islt_i(++$i,$do); --$i; # went one too far nqp::bindpos_u($r,$i,0) while nqp::islt_i(++$i,$max); $r } multi sub infix:<~&>(UnsignedBlob:D $a, SignedBlob:D $b) { my int $elemsa = nqp::elems($a); my int $elemsb = nqp::elems($b); my int $do = $elemsa > $elemsb ?? $elemsb !! $elemsa; my int $max = $elemsa > $elemsb ?? $elemsa !! $elemsb; my $r := nqp::create($a); nqp::setelems($r,$max); my int $i = -1; nqp::bindpos_u($r,$i, nqp::bitand_i(nqp::atpos_u($a,$i),nqp::atpos_i($b,$i))) while nqp::islt_i(++$i,$do); --$i; # went one too far nqp::bindpos_u($r,$i,0) while nqp::islt_i(++$i,$max); $r } multi sub infix:<~&>(SignedBlob:D $a, UnsignedBlob:D $b) { my int $elemsa = nqp::elems($a); my int $elemsb = nqp::elems($b); my int $do = $elemsa > $elemsb ?? $elemsb !! $elemsa; my int $max = $elemsa > $elemsb ?? $elemsa !! $elemsb; my $r := nqp::create($a); nqp::setelems($r,$max); my int $i = -1; nqp::bindpos_i($r,$i, nqp::bitand_i(nqp::atpos_i($a,$i),nqp::atpos_u($b,$i))) while nqp::islt_i(++$i,$do); --$i; # went one too far nqp::bindpos_u($r,$i,0) while nqp::islt_i(++$i,$max); $r } multi sub infix:<~&>(SignedBlob:D $a, SignedBlob:D $b) { my int $elemsa = nqp::elems($a); my int $elemsb = nqp::elems($b); my int $do = $elemsa > $elemsb ?? $elemsb !! $elemsa; my int $max = $elemsa > $elemsb ?? $elemsa !! $elemsb; my $r := nqp::create($a); nqp::setelems($r,$max); my int $i = -1; nqp::bindpos_i($r,$i, nqp::bitand_i(nqp::atpos_i($a,$i),nqp::atpos_i($b,$i))) while nqp::islt_i(++$i,$do); --$i; # went one too far nqp::bindpos_u($r,$i,0) while nqp::islt_i(++$i,$max); $r } multi sub infix:<~|>(UnsignedBlob:D $a, UnsignedBlob:D $b) { my int $elemsa = nqp::elems($a); my int $elemsb = nqp::elems($b); my int $do = $elemsa > $elemsb ?? $elemsb !! $elemsa; my int $max = $elemsa > $elemsb ?? $elemsa !! $elemsb; my $from := $elemsa > $elemsb ?? $a !! $b; my $r := nqp::create($a); nqp::setelems($r,$max); my int $i = -1; nqp::bindpos_u($r,$i, nqp::bitor_i(nqp::atpos_u($a,$i),nqp::atpos_u($b,$i))) while nqp::islt_i(++$i,$do); $i = $i - 1; # went one too far nqp::bindpos_u($r,$i,nqp::atpos_u($from,$i)) while nqp::islt_i(++$i,$max); $r } multi sub infix:<~|>(UnsignedBlob:D $a, SignedBlob:D $b) { my int $elemsa = nqp::elems($a); my int $elemsb = nqp::elems($b); my int $do = $elemsa > $elemsb ?? $elemsb !! $elemsa; my int $max = $elemsa > $elemsb ?? $elemsa !! $elemsb; my $r := nqp::create($a); nqp::setelems($r,$max); my int $i = -1; nqp::bindpos_u($r,$i, nqp::bitor_i(nqp::atpos_u($a,$i),nqp::atpos_i($b,$i))) while nqp::islt_i(++$i,$do); $i = $i - 1; # went one too far if $elemsa > $elemsb { nqp::bindpos_u($r,$i,nqp::atpos_u($a,$i)) while nqp::islt_i(++$i,$max); } else { nqp::bindpos_u($r,$i,nqp::atpos_i($b,$i)) while nqp::islt_i(++$i,$max); } $r } multi sub infix:<~|>(SignedBlob:D $a, UnsignedBlob:D $b) { my int $elemsa = nqp::elems($a); my int $elemsb = nqp::elems($b); my int $do = $elemsa > $elemsb ?? $elemsb !! $elemsa; my int $max = $elemsa > $elemsb ?? $elemsa !! $elemsb; my $r := nqp::create($a); nqp::setelems($r,$max); my int $i = -1; nqp::bindpos_i($r,$i, nqp::bitor_i(nqp::atpos_i($a,$i),nqp::atpos_u($b,$i))) while nqp::islt_i(++$i,$do); $i = $i - 1; # went one too far if $elemsa > $elemsb { nqp::bindpos_i($r,$i,nqp::atpos_i($a,$i)) while nqp::islt_i(++$i,$max); } else { nqp::bindpos_i($r,$i,nqp::atpos_u($b,$i)) while nqp::islt_i(++$i,$max); } $r } multi sub infix:<~|>(SignedBlob:D $a, SignedBlob:D $b) { my int $elemsa = nqp::elems($a); my int $elemsb = nqp::elems($b); my int $do = $elemsa > $elemsb ?? $elemsb !! $elemsa; my int $max = $elemsa > $elemsb ?? $elemsa !! $elemsb; my $from := $elemsa > $elemsb ?? $a !! $b; my $r := nqp::create($a); nqp::setelems($r,$max); my int $i = -1; nqp::bindpos_i($r,$i, nqp::bitor_i(nqp::atpos_i($a,$i),nqp::atpos_i($b,$i))) while nqp::islt_i(++$i,$do); $i = $i - 1; # went one too far nqp::bindpos_u($r,$i,nqp::atpos_i($from,$i)) while nqp::islt_i(++$i,$max); $r } multi sub infix:<~^>(UnsignedBlob:D $a, UnsignedBlob:D $b) { my int $elemsa = nqp::elems($a); my int $elemsb = nqp::elems($b); my int $do = $elemsa > $elemsb ?? $elemsb !! $elemsa; my int $max = $elemsa > $elemsb ?? $elemsa !! $elemsb; my $from := $elemsa > $elemsb ?? $a !! $b; my $r := nqp::create($a); nqp::setelems($r,$max); my int $i = -1; nqp::bindpos_u($r,$i, nqp::bitxor_i(nqp::atpos_u($a,$i),nqp::atpos_u($b,$i))) while nqp::islt_i(++$i,$do); --$i; # went one too far nqp::bindpos_u($r,$i,nqp::atpos_u($from,$i)) while nqp::islt_i(++$i,$max); $r } multi sub infix:<~^>(UnsignedBlob:D $a, SignedBlob:D $b) { my int $elemsa = nqp::elems($a); my int $elemsb = nqp::elems($b); my int $do = $elemsa > $elemsb ?? $elemsb !! $elemsa; my int $max = $elemsa > $elemsb ?? $elemsa !! $elemsb; my $from := $elemsa > $elemsb ?? $a !! $b; my $r := nqp::create($a); nqp::setelems($r,$max); my int $i = -1; nqp::bindpos_u($r,$i, nqp::bitxor_i(nqp::atpos_u($a,$i),nqp::atpos_i($b,$i))) while nqp::islt_i(++$i,$do); --$i; # went one too far if $elemsa > $elemsb { nqp::bindpos_u($r,$i,nqp::atpos_u($a,$i)) while nqp::islt_i(++$i,$max); } else { nqp::bindpos_u($r,$i,nqp::atpos_i($b,$i)) while nqp::islt_i(++$i,$max); } $r } multi sub infix:<~^>(SignedBlob:D $a, UnsignedBlob:D $b) { my int $elemsa = nqp::elems($a); my int $elemsb = nqp::elems($b); my int $do = $elemsa > $elemsb ?? $elemsb !! $elemsa; my int $max = $elemsa > $elemsb ?? $elemsa !! $elemsb; my $from := $elemsa > $elemsb ?? $a !! $b; my $r := nqp::create($a); nqp::setelems($r,$max); my int $i = -1; nqp::bindpos_i($r,$i, nqp::bitxor_i(nqp::atpos_i($a,$i),nqp::atpos_u($b,$i))) while nqp::islt_i(++$i,$do); --$i; # went one too far if $elemsa > $elemsb { nqp::bindpos_i($r,$i,nqp::atpos_i($a,$i)) while nqp::islt_i(++$i,$max); } else { nqp::bindpos_i($r,$i,nqp::atpos_u($b,$i)) while nqp::islt_i(++$i,$max); } $r } multi sub infix:<~^>(SignedBlob:D $a, SignedBlob:D $b) { my int $elemsa = nqp::elems($a); my int $elemsb = nqp::elems($b); my int $do = $elemsa > $elemsb ?? $elemsb !! $elemsa; my int $max = $elemsa > $elemsb ?? $elemsa !! $elemsb; my $from := $elemsa > $elemsb ?? $a !! $b; my $r := nqp::create($a); nqp::setelems($r,$max); my int $i = -1; nqp::bindpos_i($r,$i, nqp::bitxor_i(nqp::atpos_i($a,$i),nqp::atpos_i($b,$i))) while nqp::islt_i(++$i,$do); --$i; # went one too far nqp::bindpos_i($r,$i,nqp::atpos_i($from,$i)) while nqp::islt_i(++$i,$max); $r } multi sub infix:(Blob:D $a, Blob:D $b --> Bool:D) { nqp::hllbool( nqp::eqaddr($a,$b) || (nqp::eqaddr($a.WHAT,$b.WHAT) && $a.SAME($b)) ) } multi sub infix:(Blob:D $a, Blob:D $b) { ORDER($a.COMPARE($b)) } multi sub infix: (Blob:D $a, Blob:D $b --> Bool:D) { nqp::hllbool(nqp::eqaddr($a,$b) || $a.SAME($b)) } multi sub infix: (Blob:D $a, Blob:D $b --> Bool:D) { nqp::hllbool( nqp::not_i(nqp::eqaddr($a,$b) || $a.SAME($b)) ) } multi sub infix: (Blob:D $a, Blob:D $b) { nqp::hllbool(nqp::iseq_i($a.COMPARE($b),-1)) } multi sub infix: (Blob:D $a, Blob:D $b) { nqp::hllbool(nqp::iseq_i($a.COMPARE($b),1)) } multi sub infix: (Blob:D $a, Blob:D $b) { nqp::hllbool(nqp::isne_i($a.COMPARE($b),1)) } multi sub infix: (Blob:D $a, Blob:D $b) { nqp::hllbool(nqp::isne_i($a.COMPARE($b),-1)) } proto sub subbuf-rw($, $?, $?, *%) {*} multi sub subbuf-rw(Buf:D $b) is rw { $b.subbuf-rw(0, $b.elems); } multi sub subbuf-rw(Buf:D $b, Int() $from) is rw { $b.subbuf-rw($from, $b.elems - $from) } multi sub subbuf-rw(Buf:D $b, $from, $elems) is rw { $b.subbuf-rw($from, $elems) } # vim: expandtab shiftwidth=4