Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Introduce IO::Path/Handle.comb
You can comb for:
- all characters (.comb or .comb(""))
- strings (.comb("foo"))
- blocks of characters (.comb(1024))
- regexes (.comb(/.e./)
  • Loading branch information
lizmat committed Oct 24, 2015
1 parent cd77669 commit e8d7577
Show file tree
Hide file tree
Showing 4 changed files with 241 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/core/Cool.pm
Expand Up @@ -273,6 +273,7 @@ my class Cool { # declared in BOOTSTRAP
self.Stringy.match($target, |%adverbs)
}

proto method comb(|) { * }
multi method comb() { self.Str.comb() }
multi method comb(Regex $matcher, $limit = Inf) { self.Str.comb($matcher, $limit) }
multi method comb(Str $matcher, $limit = Inf) { self.Str.comb($matcher, $limit) }
Expand Down
226 changes: 226 additions & 0 deletions src/core/IO/Handle.pm
Expand Up @@ -136,6 +136,232 @@ my class IO::Handle does IO {
$c;
}

proto method comb(|) { * }
multi method comb(IO::Handle:D: :$close = False) {
self.split(:$close,:COMB)
}
multi method comb(IO::Handle:D: Int:D $size, :$close = False) {
return self.split(:$close,:COMB) if $size <= 1;

Seq.new(class :: does Iterator {
has Mu $!handle;
has Mu $!size;
has int $!close;
has str $!str;
has str $!left;
has Mu $!strings;
has int $!elems;
has int $!done;

submethod BUILD(\handle, \size, \close) {
$!handle := handle;
$!size = size.Int;
$!close = close;
$!left = '';
self!next-chunk until $!elems || $!done;
self
}
method new(\handle, \size, \close) {
nqp::create(self).BUILD(handle, size, close);
}
method !readcharsfh() {
my Mu $PIO := nqp::getattr($!handle, IO::Handle, '$!PIO');
#?if jvm
my Buf $buf := Buf.new; # nqp::readcharsfh doesn't work on the JVM
# we only get half the number of chars, but that's ok
nqp::readfh($PIO, $buf, 65536); # optimize for ASCII
nqp::unbox_s($buf.decode);
#?endif
#?if !jvm
nqp::readcharsfh($PIO, 65536); # optimize for ASCII
#?endif
}

method !next-chunk(--> Nil) {
my int $chars = nqp::chars($!left);
$!str = nqp::concat($!left,self!readcharsfh);
if nqp::chars($!str) == $chars { # nothing read anymore
$!done = 2 - ($chars == 0);
}
else {
$!strings := nqp::list();
my int $pos;
my int $found;
my int $chars = nqp::chars($!str);
while $pos + $size <= $chars {
nqp::push($!strings,nqp::substr($!str,$pos,$size));
$pos = $pos + $size;
}
$!left = nqp::substr($!str,$pos);
$!elems = nqp::elems($!strings);
}
Nil
}
method pull-one() {
if $!elems {
$!elems = $!elems - 1;
nqp::p6box_s(nqp::shift($!strings));
}
else {
self!next-chunk until $!elems || $!done;
if $!elems {
$!elems = $!elems - 1;
nqp::p6box_s(nqp::shift($!strings));
}
elsif $!done = 2 {
$!done = 1;
nqp::p6box_s($!str);
}
else {
$!handle.close if $!close;
IterationEnd;
}
}
}
method push-all($target) {
while $!elems {
while $!elems {
$target.push(nqp::p6box_s(nqp::shift($!strings)));
$!elems = $!elems - 1;
}
self!next-chunk until $!elems || $!done;
}
$target.push(nqp::p6box_s($!str)) if $!done == 2;
$!handle.close if $!close;
IterationEnd
}
method count-only() {
my int $found;
while $!elems {
$found = $found + $!elems;
$!elems = 0;
self!next-chunk until $!elems || $!done;
}
$found = $found + ($!done == 2);
$!handle.close if $!close;
nqp::p6box_i($found)
}
}.new(self, $size, +$close));
}
multi method comb(IO::Handle:D: $comber, :$close = False) {
return self.split(:$close,:COMB)
if nqp::istype($comber,Cool) && $comber.Str.chars == 0;

Seq.new(class :: does Iterator {
has Mu $!handle;
has Mu $!regex;
has str $!comber;
has int $!close;
has str $!str;
has str $!left;
has Mu $!strings;
has int $!elems;
has int $!done;

submethod BUILD(\handle, \comber, \close) {
$!handle := handle;
nqp::istype(comber,Regex)
?? ($!regex := comber)
!! ($!comber = nqp::unbox_s(comber.Str));
$!close = close;
$!left = '';
self!next-chunk until $!elems || $!done;
self
}
method new(\handle, \comber, \close) {
nqp::create(self).BUILD(handle, comber, close);
}
method !readcharsfh() {
my Mu $PIO := nqp::getattr($!handle, IO::Handle, '$!PIO');
#?if jvm
my Buf $buf := Buf.new; # nqp::readcharsfh doesn't work on the JVM
# we only get half the number of chars, but that's ok
nqp::readfh($PIO, $buf, 65536); # optimize for ASCII
nqp::unbox_s($buf.decode);
#?endif
#?if !jvm
nqp::readcharsfh($PIO, 65536); # optimize for ASCII
#?endif
}

method !next-chunk(--> Nil) {
my int $chars = nqp::chars($!left);
$!str = nqp::concat($!left,self!readcharsfh);
if nqp::chars($!str) == $chars { # nothing read anymore
$!done = 1;
}
else {
$!strings := nqp::list();
with $!regex {
my \matches = $!str.match($!regex, :g);
$!elems = matches.elems;
nqp::setelems($!strings,$!elems);
my int $i;
my int $from;
my int $to;
my Mu $match;
while $i < $!elems {
$match := matches[$i];
$from = $match.from;
$to = $match.to;
nqp::bindpos($!strings,$i,
nqp::substr($!str,$from,$to - $from));
$i = $i + 1;
}
$!left = nqp::substr($!str,$to);
}
else {
my int $pos;
my int $found;
nqp::push($!strings,$comber)
while ($found = nqp::index($!str,$!comber,$pos)) > 0;
$!left = nqp::substr($!str,$pos);
$!elems = nqp::elems($!strings);
}
}
Nil
}
method pull-one() {
if $!elems {
$!elems = $!elems - 1;
nqp::p6box_s(nqp::shift($!strings));
}
else {
self!next-chunk until $!elems || $!done;
if $!elems {
$!elems = $!elems - 1;
nqp::p6box_s(nqp::shift($!strings));
}
else {
$!handle.close if $!close;
IterationEnd;
}
}
}
method push-all($target) {
while $!elems {
while $!elems {
$target.push(nqp::p6box_s(nqp::shift($!strings)));
$!elems = $!elems - 1;
}
self!next-chunk until $!elems || $!done;
}
$!handle.close if $!close;
IterationEnd
}
method count-only() {
my int $found;
while $!elems {
$found = $found + $!elems;
$!elems = 0;
self!next-chunk until $!elems || $!done;
}
$!handle.close if $!close;
nqp::p6box_i($found)
}
}.new(self, $comber, +$close));
}

multi method split(IO::Handle:D: :$close = False, :$COMB) {
Seq.new(class :: does Iterator {
has Mu $!handle;
Expand Down
14 changes: 14 additions & 0 deletions src/core/IO/Path.pm
Expand Up @@ -513,6 +513,20 @@ my class IO::Path is Cool {
$handle && $handle.lines(:close);
}

proto method comb(|) { * }
multi method comb(IO::Path:D: Cool:D $comber = "", |c) {
my $handle = self.open(|c);
$handle && $handle.comb($comber, :close);
}
multi method comb(IO::Path:D: Int:D $size, |c) {
my $handle = self.open(|c);
$handle && $handle.comb($size, :close);
}
multi method comb(IO::Path:D: Regex:D $comber, |c) {
my $handle = self.open(|c);
$handle && $handle.comb($comber, :close);
}

multi method split(IO::Path:D: Str:D $splitter = "", |c) {
my $handle = self.open(|c);
$handle && $handle.split($splitter, :close);
Expand Down
1 change: 0 additions & 1 deletion src/core/Mu.pm
Expand Up @@ -45,7 +45,6 @@ Please refactor this code using the new Iterator / Seq interface.
}

proto method split(|) { * }
proto method comb(|) { * }

method take {
take self;
Expand Down

0 comments on commit e8d7577

Please sign in to comment.