Skip to content

Commit

Permalink
Implementation of Array.values_at, with tests.
Browse files Browse the repository at this point in the history
Signed-off-by: Ted Reed <ted.reed@gmail.com>
  • Loading branch information
dtm authored and treed committed Jul 25, 2009
1 parent 63aa1d8 commit cc4f210
Show file tree
Hide file tree
Showing 3 changed files with 135 additions and 1 deletion.
3 changes: 2 additions & 1 deletion Rakefile
Expand Up @@ -262,9 +262,10 @@ namespace :test do |ns|
test "array/sort.t"
test "array/to_s.t"
test "array/uniq.t"
test "array/values_at.t"
test "array/warray.t"

task :all => [:array, :at, :clear, :collect, :compact, :concat, :delete, :empty, :equals, :fill, :first, :flatten, :grep, :include, :index, :intersection, :join, :mathop, :pop, :reject, :reverse, :shift, :slice, :sort, :to_s, :uniq, :warray]
task :all => [:array, :at, :clear, :collect, :compact, :concat, :delete, :empty, :equals, :fill, :first, :flatten, :grep, :include, :index, :intersection, :join, :mathop, :pop, :reject, :reverse, :shift, :slice, :sort, :to_s, :uniq, :values_at, :warray]
end

namespace :file do
Expand Down
96 changes: 96 additions & 0 deletions src/classes/Array.pir
Expand Up @@ -1250,6 +1250,102 @@ The zip operator.
.return (zipped)
.end

=item values_at(INDEX, ...)

Retrieve elements from positions.

=cut

.sub 'values_at' :method
.param pmc args :slurpy
.local pmc values
.local pmc val
.local pmc item
.local int length

length = elements self

values = new 'CardinalArray'

loop_check:
unless args goto done

item = shift args

$I0 = isa item, 'CardinalRange'
if $I0 goto do_range

$I0=item

if $I0 < 0 goto negative

if $I0 >= length goto nil_item

valid:
val = self[$I0]
push_val:
values.'push'(val)
goto loop_check

nil_item:
val = get_hll_global 'nil'
goto push_val

negative:
$I0=$I0+length
if $I0 < 0 goto nil_item
if $I0 >= length goto nil_item
goto valid

do_range:
.local int beg, end, count

beg = item.'from'()
end = item.'to'()

if beg >= 0 goto skip_beg_neg
beg = beg + length
if beg < 0 goto range_outofrange

skip_beg_neg:

if end <= length goto skip_set_end
end = length

skip_set_end:

if end >= 0 goto skip_end_neg
end = end + length

skip_end_neg:
$P0 = getattribute item, '$!to_exclusive'
if $P0 goto skip_inc_end
inc end
skip_inc_end:
count = end - beg
if count >= 0 goto skip_neg_count
count = 0
skip_neg_count:

$I0 = 0
range_loop:
if $I0 >= count goto loop_check
$I1 = $I0 + beg
if $I1 == length goto range_outofrange
val = self[$I1]
values.'push'(val)
inc $I0
goto range_loop

range_outofrange:
val = get_hll_global 'nil'
values.'push'(val)
goto loop_check

done:
.return (values)
.end

.sub '_cmp' :vtable('cmp') :method
.param pmc other
.local int i, len, result
Expand Down
37 changes: 37 additions & 0 deletions t/array/values_at.t
@@ -0,0 +1,37 @@
require 'Test'
include Test
plan 18

a = [1,2,3,4,5]

is a.values_at(), [], 'values_at'

is a.values_at(0), [1], 'values_at'
is a.values_at(4), [5], 'values_at'
is a.values_at(5), [nil], 'values_at'

is a.values_at(-1), [5], 'values_at'
is a.values_at(-5), [1], 'values_at'
is a.values_at(-6), [nil], 'values_at'

is a.values_at(0,1), [1,2], 'values_at'
is a.values_at(4,5), [5,nil], 'values_at'
is a.values_at(5,6), [nil,nil], 'values_at'

is a.values_at(0..4), [1,2,3,4,5], 'values_at'
is a.values_at(0...4), [1,2,3,4], 'values_at'

is a.values_at(4..5), [5,nil], 'values_at'
is a.values_at(5..4), [], 'values_at'

is a.values_at(-5..-1), [1,2,3,4,5], 'values_at'
# TODO: verify correct:
is a.values_at(-5...0), [], 'values_at'

# from rubyspec /core/array/values_at_spec.rb
b=a.values_at(1..-2, 1...-2, -2..1)
is b, [2, 3, 4, 2, 3], 'values_at'

b = a.values_at(1, 0, 5, -1, -8, 10)
is b, [2, 1, nil, 5, nil, nil], 'values_at'

0 comments on commit cc4f210

Please sign in to comment.