Here are a better set of patches for Rakudo. They don't duplicate the check
for $p < 0, and they avoid calling nqp::elems(), by assuming that nqp::atpos()
safely return nql::null() for indices beyond the end of the array.
(Which Parrot does. Is any of this spec'd anywhere?)

The NQP patches remain fine.

On Sun, Feb 10, 2013 at 09:19:22PM +0000, Nicholas Clark wrote:

> I've no idea if the coding style is appropriate. Whether the indentation is
> crazy. Whether one should be using Mu. etc

This still holds. Style-wise, it would be possible to avoid using return-rw
by using a nested ?? !! - which is considered better?

Nicholas Clark
>From b0c5f0c175bed831b8e89808b237d4484425b2ae Mon Sep 17 00:00:00 2001
From: Nicholas Clark <n...@ccl4.org>
Date: Sun, 10 Feb 2013 18:44:59 +0100
Subject: [PATCH 1/4] Move the test for negative indices from postcircumfix:<[ ]> to at_pos().

at_pos() shouldn't accept negative indices when called directly either.
Having the check in two places duplicates work.
---
 src/core/Any.pm     |   13 +------------
 src/core/Array.pm   |    4 ++++
 src/core/Buf.pm     |    1 +
 src/core/Capture.pm |    1 +
 src/core/List.pm    |    1 +
 src/core/LoL.pm     |    1 +
 6 files changed, 9 insertions(+), 12 deletions(-)

diff --git a/src/core/Any.pm b/src/core/Any.pm
index 2bca541..e6f6b58 100644
--- a/src/core/Any.pm
+++ b/src/core/Any.pm
@@ -153,7 +153,6 @@ my class Any {
         X::Bind::ZenSlice.new(type => self.WHAT).throw
     }
     multi method postcircumfix:<[ ]>(\SELF: $pos) is rw {
-        fail "Cannot use negative index $pos on {SELF.WHAT.perl}" if $pos < 0;
         SELF.at_pos($pos)
     }
     multi method postcircumfix:<[ ]>($pos, Mu :$BIND! is parcel) is rw {
@@ -161,19 +160,15 @@ my class Any {
         self.bind_pos($pos, $BIND)
     }
     multi method postcircumfix:<[ ]>($pos, :$p!) is rw {
-        fail "Cannot use negative index $pos on {self.WHAT.perl}" if $pos < 0;
         $p ?? RWPAIR($pos, self.at_pos($pos)) !! self.at_pos($pos)
     }
     multi method postcircumfix:<[ ]>($pos, :$kv!) is rw {
-        fail "Cannot use negative index $pos on {self.WHAT.perl}" if $pos < 0;
         $kv ?? ($pos, self.at_pos($pos)) !! self.at_pos($pos)
     }
     multi method postcircumfix:<[ ]>($pos, :$k!) is rw {
-        fail "Cannot use negative index $pos on {self.WHAT.perl}" if $pos < 0;
         $k ?? $pos !! self.at_pos($pos)
     }
     multi method postcircumfix:<[ ]>(\SELF: int $pos) is rw {
-        fail "Cannot use negative index $pos on {SELF.WHAT.perl}" if $pos < 0;
         SELF.at_pos($pos)
     }
     multi method postcircumfix:<[ ]>(int $pos, Mu :$BIND! is parcel) is rw {
@@ -181,20 +176,16 @@ my class Any {
         self.bind_pos($pos, $BIND)
     }
     multi method postcircumfix:<[ ]>(int $pos, :$p!) is rw {
-        fail "Cannot use negative index $pos on {self.WHAT.perl}" if $pos < 0;
         $p ?? RWPAIR($pos, self.at_pos($pos)) !! self.at_pos($pos)
     }
     multi method postcircumfix:<[ ]>(int $pos, :$kv!) is rw {
-        fail "Cannot use negative index $pos on {self.WHAT.perl}" if $pos < 0;
         $kv ?? ($pos, self.at_pos($pos)) !! self.at_pos($pos)
     }
     multi method postcircumfix:<[ ]>(int $pos, :$k!) is rw {
-        fail "Cannot use negative index $pos on {self.WHAT.perl}" if $pos < 0;
         $k ?? $pos !! self.at_pos($pos)
     }
     multi method postcircumfix:<[ ]>(\SELF: Positional \pos) is rw {
         if nqp::iscont(pos) {
-            fail "Cannot use negative index {pos} on {SELF.WHAT.perl}" if pos < 0;
             return SELF.at_pos(pos)
         }
         my $list = pos.flat;
@@ -205,7 +196,6 @@ my class Any {
     }
     multi method postcircumfix:<[ ]>(\SELF: Positional \pos, :$p!) is rw {
         if nqp::iscont(pos) {
-            fail "Cannot use negative index {pos} on {SELF.WHAT.perl}" if pos < 0;
             return RWPAIR(pos, SELF.at_pos(pos))
         }
         my $list = pos.flat;
@@ -214,7 +204,6 @@ my class Any {
     }
     multi method postcircumfix:<[ ]>(\SELF: Positional \pos, :$kv!) is rw {
         if nqp::iscont(pos) {
-            fail "Cannot use negative index {pos} on {SELF.WHAT.perl}" if pos < 0;
             return (pos, SELF.at_pos(pos))
         }
         my $list = pos.flat;
@@ -232,7 +221,6 @@ my class Any {
     }
     multi method postcircumfix:<[ ]>(\SELF: Positional \pos, :$v!) is rw {
         if nqp::iscont(pos) {
-            fail "Cannot use negative index {pos} on {SELF.WHAT.perl}" if pos < 0;
             SELF.at_pos(pos)
         }
         my $list = pos.flat;
@@ -283,6 +271,7 @@ my class Any {
         self;
     }
     multi method at_pos(Any:U \SELF: $pos) is rw {
+        fail "Cannot use negative index $pos on {SELF.WHAT.perl}" if $pos < 0;
         pir::setattribute__0PPsP(my $v, Scalar, '$!whence',
             -> { SELF.defined || &infix:<=>(SELF, Array.new);
                  SELF.bind_pos($pos, $v) });
diff --git a/src/core/Array.pm b/src/core/Array.pm
index cb67207..17083d3 100644
--- a/src/core/Array.pm
+++ b/src/core/Array.pm
@@ -13,6 +13,7 @@ class Array {
         if nqp::isnanorinf($pos) {
             X::Item.new(aggregate => self, index => $pos).throw;
         }
+        fail "Cannot use negative index $pos on {self.WHAT.perl}" if $pos < 0;
         my int $p = nqp::unbox_i($pos.Int);
         my Mu $items := nqp::p6listitems(self);
         # hotpath check for element existence (RT #111848)
@@ -24,6 +25,7 @@ class Array {
                  -> { nqp::bindpos($items, $p, $v) } )
     }
     multi method at_pos(Array:D: int $pos) is rw {
+        fail "Cannot use negative index $pos on {self.WHAT.perl}" if $pos < 0;
         my Mu $items := nqp::p6listitems(self);
         # hotpath check for element existence (RT #111848)
         nqp::existspos($items, $pos)
@@ -106,6 +108,7 @@ class Array {
 
     my role TypedArray[::TValue] does Positional[TValue] {
         multi method at_pos($pos is copy, TValue $v? is copy) is rw {
+            fail "Cannot use negative index $pos on {self.WHAT.perl}" if $pos < 0;
             $pos = $pos.Int;
             self.exists($pos)
               ?? nqp::atpos(nqp::getattr(self, List, '$!items'), nqp::unbox_i($pos))
@@ -113,6 +116,7 @@ class Array {
                      -> { nqp::bindpos(nqp::getattr(self, List, '$!items'), nqp::unbox_i($pos), $v) } )
         }
         multi method at_pos(int $pos, TValue $v? is copy) is rw {
+            fail "Cannot use negative index $pos on {self.WHAT.perl}" if $pos < 0;
             self.exists($pos)
               ?? nqp::atpos(nqp::getattr(self, List, '$!items'), $pos)
               !! pir::setattribute__0PPsP($v, Scalar, '$!whence',
diff --git a/src/core/Buf.pm b/src/core/Buf.pm
index 9560b26..7b58450 100644
--- a/src/core/Buf.pm
+++ b/src/core/Buf.pm
@@ -31,6 +31,7 @@ my class Buf does Positional {
     }
 
     method at_pos(Buf:D: Int:D $idx) {
+        fail "Cannot use negative index $idx on {self.WHAT.perl}" if $idx < 0;
         nqp::p6box_i(nqp::ord(nqp::substr($!buffer, nqp::unbox_i($idx), 1)));
     }
 
diff --git a/src/core/Capture.pm b/src/core/Capture.pm
index 20458c2..d21630b 100644
--- a/src/core/Capture.pm
+++ b/src/core/Capture.pm
@@ -17,6 +17,7 @@ my class Capture {
     }
 
     method at_pos(Capture:D: $pos is copy) {
+        fail "Cannot use negative index $pos on {self.WHAT.perl}" if $pos < 0;
         $pos = $pos.Int;
         nqp::existspos($!list, nqp::unbox_i($pos))
           ?? nqp::atpos($!list, nqp::unbox_i($pos))
diff --git a/src/core/List.pm b/src/core/List.pm
index 84f7eff..c7428c5 100644
--- a/src/core/List.pm
+++ b/src/core/List.pm
@@ -73,6 +73,7 @@ my class List does Positional {
 
     multi method at_pos(List:D: $pos is copy) is rw {
         $pos = $pos.Int;
+        fail "Cannot use negative index $pos on {self.WHAT.perl}" if $pos < 0;
         self.exists($pos)
           ?? nqp::atpos($!items, nqp::unbox_i($pos))
           !! Nil
diff --git a/src/core/LoL.pm b/src/core/LoL.pm
index f57f613..3c2798d 100644
--- a/src/core/LoL.pm
+++ b/src/core/LoL.pm
@@ -9,6 +9,7 @@ class LoL {
     }
     
     method at_pos($pos is copy) {
+        fail "Cannot use negative index $pos on {self.WHAT.perl}" if $pos < 0;
         $pos = $pos.Int;
         self.exists($pos)
           ?? nqp::findmethod(List, 'at_pos')(self, $pos)
-- 
1.7.2.5

>From af14e5132c8829553cb1d2448655fbf11c14decc Mon Sep 17 00:00:00 2001
From: Nicholas Clark <n...@ccl4.org>
Date: Sun, 10 Feb 2013 20:09:50 +0100
Subject: [PATCH 2/4] Refactor Array.at_pos() to remove the use of nqp::existspos().

---
 src/core/Array.pm |   14 ++++++++------
 1 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/src/core/Array.pm b/src/core/Array.pm
index 17083d3..0169b74 100644
--- a/src/core/Array.pm
+++ b/src/core/Array.pm
@@ -17,9 +17,10 @@ class Array {
         my int $p = nqp::unbox_i($pos.Int);
         my Mu $items := nqp::p6listitems(self);
         # hotpath check for element existence (RT #111848)
-        nqp::existspos($items, $p)
-              || nqp::getattr(self, List, '$!nextiter').defined
-                  && self.exists($p)
+        my Mu $item := nqp::atpos($items, $p);
+        return-rw $item
+            if !nqp::isnull($item);
+        nqp::getattr(self, List, '$!nextiter').defined && self.exists($p)
           ?? nqp::atpos($items, $p)
           !! pir::setattribute__0PPsP(my $v, Scalar, '$!whence',
                  -> { nqp::bindpos($items, $p, $v) } )
@@ -28,9 +29,10 @@ class Array {
         fail "Cannot use negative index $pos on {self.WHAT.perl}" if $pos < 0;
         my Mu $items := nqp::p6listitems(self);
         # hotpath check for element existence (RT #111848)
-        nqp::existspos($items, $pos)
-              || nqp::getattr(self, List, '$!nextiter').defined
-                  && self.exists($pos)
+        my Mu $item := nqp::atpos($items, $pos);
+        return-rw $item
+            if !nqp::isnull($item);
+        nqp::getattr(self, List, '$!nextiter').defined && self.exists($pos)
           ?? nqp::atpos($items, $pos)
           !! pir::setattribute__0PPsP(my $v, Scalar, '$!whence',
                  -> { nqp::bindpos($items, $pos, $v) } )
-- 
1.7.2.5

>From 885d25afff4422f63f58823e9cdbf0455f64b206 Mon Sep 17 00:00:00 2001
From: Nicholas Clark <n...@ccl4.org>
Date: Sun, 10 Feb 2013 20:30:22 +0100
Subject: [PATCH 3/4] Refactor List.exists() and .shift() to remove the use of nqp::existspos().

---
 src/core/List.pm |    6 ++++--
 1 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/core/List.pm b/src/core/List.pm
index c7428c5..d3b8691 100644
--- a/src/core/List.pm
+++ b/src/core/List.pm
@@ -95,7 +95,9 @@ my class List does Positional {
 
     method exists(\pos) {
         self.gimme(pos + 1);
-        nqp::p6bool(nqp::existspos($!items, nqp::unbox_i(pos)))
+        my Mu $count := nqp::elems($!items);
+        return False if pos < 0 || pos > $count;
+        nqp::p6bool(!nqp::isnull(nqp::atpos($!items, nqp::unbox_i(pos))))
     }
 
     method gimme($n, :$sink) {
@@ -217,7 +219,7 @@ my class List does Positional {
 
     method shift() is rw {
         # make sure we have at least one item, then shift+return it
-        nqp::islist($!items) && nqp::existspos($!items, 0) || self.gimme(1)
+        nqp::islist($!items) && !nqp::isnull(nqp::atpos($!items, 0)) || self.gimme(1)
           ?? nqp::shift($!items) 
           !! fail 'Element shifted from empty list';
     }
-- 
1.7.2.5

>From 7d85d02d2bc9254dcfe36bc71c8b579eb103ed2e Mon Sep 17 00:00:00 2001
From: Nicholas Clark <n...@ccl4.org>
Date: Sun, 10 Feb 2013 20:44:37 +0100
Subject: [PATCH 4/4] Refactor Capture::at_pos() to remove the use of nqp::existspos().

---
 src/core/Capture.pm |    7 ++++---
 1 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/src/core/Capture.pm b/src/core/Capture.pm
index d21630b..8933847 100644
--- a/src/core/Capture.pm
+++ b/src/core/Capture.pm
@@ -19,9 +19,10 @@ my class Capture {
     method at_pos(Capture:D: $pos is copy) {
         fail "Cannot use negative index $pos on {self.WHAT.perl}" if $pos < 0;
         $pos = $pos.Int;
-        nqp::existspos($!list, nqp::unbox_i($pos))
-          ?? nqp::atpos($!list, nqp::unbox_i($pos))
-          !! Any
+        my Mu $item := nqp::atpos($!list, nqp::unbox_i($pos));
+        nqp::isnull($item)
+          ?? Any
+          !! $item
     }
 
     method hash(Capture:D:) {
-- 
1.7.2.5

Reply via email to