Skip to content

Instantly share code, notes, and snippets.

@lizmat
Created February 21, 2015 22:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lizmat/695c8187f5279ab41c88 to your computer and use it in GitHub Desktop.
Save lizmat/695c8187f5279ab41c88 to your computer and use it in GitHub Desktop.
make substr-rw work like substr, but make substr 2.5x as slow
diff --git a/src/core/Str.pm b/src/core/Str.pm
index 0cb832a..57bf2cf 100644
--- a/src/core/Str.pm
+++ b/src/core/Str.pm
@@ -1556,64 +1556,79 @@ sub chrs(*@c) returns Str:D {
@c.map({.chr}).join;
}
-sub substr(Str() \what, \from, $chars?) {
- my str $str = nqp::unbox_s(what);
- my int $max = nqp::chars($str);
- my int $from = nqp::unbox_i(
- nqp::istype(from, Callable) ?? (from)(nqp::p6box_i($max)) !! from.Int
+sub SUBSTR-SANITY(Str \what, \start, \chars, \from, \length) {
+ my str $str = nqp::unbox_s(what);
+ my int $max = nqp::chars($str);
+ from = nqp::unbox_i(
+ nqp::istype(start, Callable) ?? (start)(nqp::p6box_i($max)) !! start.Int
);
- if $from < 0 {
- if nqp::istype(from, Callable) || -$from > $max {
+ if from < 0 {
+ if nqp::istype(from, Callable) || -from > $max {
X::OutOfRange.new(
- :what<Start argument to substr>,:got($from),:range("0..$max"),
+ :what<Start argument to substr>,:got(from),:range("0..$max"),
).fail;
}
else {
X::OutOfRange.new(
:what<Start argument to substr>,:got(from),:range<0..Inf>,
- :comment("use *$from if you want to index relative to the end")
+ :comment("use *{from} if you want to index relative to the end")
).fail;
}
}
- elsif $from > $max {
+ elsif from > $max {
X::OutOfRange.new(
- :what<Start of substr>,:got($from),:range("0..$max"),
+ :what<Start of substr>,:got(from),:range("0..$max"),
).fail;
}
- my int $length = nqp::unbox_i(
- $chars.defined
- ?? $chars === Inf
- ?? $max - $from
- !! nqp::istype($chars,Callable)
- ?? $chars($max - $from)
- !! (nqp::istype($chars,Int) ?? $chars !! $chars.Int)
- !! $max - $from
+ length = nqp::unbox_i(
+ chars.defined
+ ?? chars === Inf
+ ?? $max - from
+ !! nqp::istype(chars,Callable)
+ ?? (chars)($max - from)
+ !! (nqp::istype(chars,Int) ?? chars !! chars.Int)
+ !! $max - from
);
X::OutOfRange.new(
- :what<Length argument to substr>,:got($chars),:range<0..Inf>,
- :comment("use *$length if you want to index relative to the end")
- ).fail if $length < 0;
+ :what<Length argument to substr>,:got(chars),:range<0..Inf>,
+ :comment("use *{length} if you want to index relative to the end")
+ ).fail if length < 0;
+ 1;
+}
- nqp::p6box_s(nqp::substr($str, $from, $length));
+sub substr(Str() \what, \from, $chars?) {
+
+ # should really be int, but \ then doesn't work for rw access
+ my $r := SUBSTR-SANITY( what, from, $chars, my Int $from, my Int $length);
+ return $r.defined
+ ?? nqp::p6box_s(nqp::substr(
+ nqp::unbox_s(what),nqp::unbox_i($from),nqp::unbox_i($length)
+ ))
+ !! $r;
}
-sub substr-rw(Str() $s is rw, $from, $length?) {
- my str $str = nqp::unbox_s($s);
- my int $chars = nqp::unbox_i(
- nqp::defined($length) ?? $length !! $from - nqp::chars($str)
- );
- my str $substr = nqp::substr($str,$from,$chars);
+sub substr-rw(Str() \what, \from, $chars?) {
+
+ # should really be int, but \ then doesn't work for rw access
+ my $r := SUBSTR-SANITY( what, from, $chars, my Int $from, my Int $length);
+ return $r unless $r.defined;
+
Proxy.new(
- FETCH => sub ($) { nqp::p6box_s($substr) },
- STORE => sub ($, $new) {
- $s = nqp::p6box_s(
- nqp::substr($str,0,$from)
- ~ nqp::unbox_s($new)
- ~ nqp::substr($str,$from + $chars)
- );
- }
+ FETCH => sub ($) {
+ nqp::p6box_s(nqp::substr(
+ nqp::unbox_s(what), nqp::unbox_i($from), nqp::unbox_i($length)
+ ));
+ },
+ STORE => sub ($, $new) {
+ my $str = nqp::unbox_s(what);
+ what = nqp::p6box_s(
+ nqp::substr($str,0,$from)
+ ~ nqp::unbox_s($new)
+ ~ nqp::substr($str,$from + $length)
+ );
+ },
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment