Skip to content

Commit f8392f9

Browse files
committed
[Truffle] Implement Array#<=>, shim the Rubinius mirror, and move #permutation to Ruby.
1 parent 59b60b5 commit f8392f9

File tree

6 files changed

+135
-75
lines changed

6 files changed

+135
-75
lines changed

spec/truffle/tags/core/array/permutation_tags.txt

Lines changed: 0 additions & 12 deletions
This file was deleted.

truffle/src/main/java/org/jruby/truffle/nodes/core/ArrayNodes.java

Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2892,68 +2892,6 @@ protected boolean formatIsLStar(RubyArray array, RubyString format) {
28922892

28932893
}
28942894

2895-
@CoreMethod(names = "permutation", required = 1)
2896-
public abstract static class PermutationNode extends ArrayCoreMethodNode {
2897-
2898-
public PermutationNode(RubyContext context, SourceSection sourceSection) {
2899-
super(context, sourceSection);
2900-
}
2901-
2902-
public PermutationNode(PermutationNode prev) {
2903-
super(prev);
2904-
}
2905-
2906-
@Specialization
2907-
public RubyArray permutation(RubyArray array, int n) {
2908-
notDesignedForCompilation();
2909-
2910-
final List<RubyArray> permutations = new ArrayList<>();
2911-
permutationCommon(n, false, array.slowToArray(), permutations);
2912-
return new RubyArray(getContext().getCoreLibrary().getArrayClass(), permutations.toArray(), permutations.size());
2913-
}
2914-
2915-
// Apdapted from JRuby's RubyArray - see attribution there
2916-
2917-
private void permutationCommon(int r, boolean repeat, Object[] values, List<RubyArray> permutations) {
2918-
if (r == 0) {
2919-
permutations.add(new RubyArray(getContext().getCoreLibrary().getArrayClass(), null, 0));
2920-
} else if (r == 1) {
2921-
for (int i = 0; i < values.length; i++) {
2922-
permutations.add(new RubyArray(getContext().getCoreLibrary().getArrayClass(), values[i], 1));
2923-
}
2924-
} else if (r >= 0) {
2925-
int n = values.length;
2926-
permute(n, r,
2927-
new int[r], 0,
2928-
new boolean[n],
2929-
repeat,
2930-
values, permutations);
2931-
}
2932-
}
2933-
2934-
private void permute(int n, int r, int[]p, int index, boolean[]used, boolean repeat, Object[] values, List<RubyArray> permutations) {
2935-
for (int i = 0; i < n; i++) {
2936-
if (repeat || !used[i]) {
2937-
p[index] = i;
2938-
if (index < r - 1) {
2939-
used[i] = true;
2940-
permute(n, r, p, index + 1, used, repeat, values, permutations);
2941-
used[i] = false;
2942-
} else {
2943-
Object[] result = new Object[r];
2944-
2945-
for (int j = 0; j < r; j++) {
2946-
result[j] = values[p[j]];
2947-
}
2948-
2949-
permutations.add(new RubyArray(getContext().getCoreLibrary().getArrayClass(), result, r));
2950-
}
2951-
}
2952-
}
2953-
}
2954-
2955-
}
2956-
29572895
@CoreMethod(names = "pop")
29582896
public abstract static class PopNode extends ArrayCoreMethodNode {
29592897

truffle/src/main/java/org/jruby/truffle/translator/BodyTranslator.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1492,8 +1492,24 @@ public RubyNode visitInstAsgnNode(org.jruby.ast.InstAsgnNode node) {
14921492
@Override
14931493
public RubyNode visitInstVarNode(org.jruby.ast.InstVarNode node) {
14941494
final SourceSection sourceSection = translate(node.getPosition());
1495+
1496+
// TODO CS 6-Feb-15 - this appears to be the name *with* sigil - need to clarify this
1497+
14951498
final String nameWithoutSigil = node.getName();
14961499

1500+
/*
1501+
* Rubinius uses the instance variable @total to store the size of an array. In order to use code that
1502+
* expects that we'll replace it statically with a call to Array#size.
1503+
*/
1504+
1505+
if (sourceSection.getSource().getPath().equals("core:/jruby/truffle/core/rubinius/kernel/common/array.rb") && nameWithoutSigil.equals("@total")) {
1506+
return new RubyCallNode(context, sourceSection,
1507+
"size",
1508+
new SelfNode(context, sourceSection),
1509+
null,
1510+
false);
1511+
}
1512+
14971513
final RubyNode receiver = new SelfNode(context, sourceSection);
14981514

14991515
return new ReadInstanceVariableNode(context, sourceSection, nameWithoutSigil, receiver, false);

truffle/src/main/ruby/jruby/truffle/core.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
require_relative 'core/rubinius/api/kernel/common/type'
1313

1414
# Patch rubinius-core-api to make it work for us
15+
require_relative 'core/rubinius/api/shims/array'
1516
require_relative 'core/rubinius/api/shims/rubinius'
1617
require_relative 'core/rubinius/api/shims/lookuptable'
1718
require_relative 'core/rubinius/api/shims/thread'
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Copyright (c) 2015 Oracle and/or its affiliates. All rights reserved. This
2+
# code is released under a tri EPL/GPL/LGPL license. You can use it,
3+
# redistribute it and/or modify it under the terms of the:
4+
#
5+
# Eclipse Public License version 1.0
6+
# GNU General Public License version 2
7+
# GNU Lesser General Public License version 2.1
8+
9+
module Rubinius
10+
module Mirror
11+
class Array
12+
13+
def self.reflect(array)
14+
Array.new(array)
15+
end
16+
17+
def initialize(array)
18+
@array = array
19+
end
20+
21+
def total
22+
@array.size
23+
end
24+
25+
end
26+
end
27+
end

truffle/src/main/ruby/jruby/truffle/core/rubinius/kernel/common/array.rb

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626

2727
# Only part of Rubinius' array.rb
2828

29+
# Rubinius uses the instance variable @total to store the size. We replace this
30+
# in the translator with a call to size.
31+
2932
class Array
3033

3134
def self.[](*args)
@@ -150,4 +153,91 @@ def last(n=undefined)
150153
Array.new self[-n..-1]
151154
end
152155

153-
end
156+
def permutation(num=undefined, &block)
157+
return to_enum(:permutation, num) unless block_given?
158+
159+
if undefined.equal? num
160+
num = @total
161+
else
162+
num = Rubinius::Type.coerce_to_collection_index num
163+
end
164+
165+
if num < 0 || @total < num
166+
# no permutations, yield nothing
167+
elsif num == 0
168+
# exactly one permutation: the zero-length array
169+
yield []
170+
elsif num == 1
171+
# this is a special, easy case
172+
each { |val| yield [val] }
173+
else
174+
# this is the general case
175+
perm = Array.new(num)
176+
used = Array.new(@total, false)
177+
178+
if block
179+
# offensive (both definitions) copy.
180+
offensive = dup
181+
Rubinius.privately do
182+
offensive.__permute__(num, perm, 0, used, &block)
183+
end
184+
else
185+
__permute__(num, perm, 0, used, &block)
186+
end
187+
end
188+
189+
self
190+
end
191+
192+
def __permute__(num, perm, index, used, &block)
193+
# Recursively compute permutations of r elements of the set [0..n-1].
194+
# When we have a complete permutation of array indexes, copy the values
195+
# at those indexes into a new array and yield that array.
196+
#
197+
# num: the number of elements in each permutation
198+
# perm: the array (of size num) that we're filling in
199+
# index: what index we're filling in now
200+
# used: an array of booleans: whether a given index is already used
201+
#
202+
# Note: not as efficient as could be for big num.
203+
@total.times do |i|
204+
unless used[i]
205+
perm[index] = i
206+
if index < num-1
207+
used[i] = true
208+
__permute__(num, perm, index+1, used, &block)
209+
used[i] = false
210+
else
211+
yield values_at(*perm)
212+
end
213+
end
214+
end
215+
end
216+
private :__permute__
217+
218+
def <=>(other)
219+
other = Rubinius::Type.check_convert_type other, Array, :to_ary
220+
return 0 if equal? other
221+
return nil if other.nil?
222+
223+
total = Rubinius::Mirror::Array.reflect(other).total
224+
225+
Thread.detect_recursion self, other do
226+
i = 0
227+
count = total < @total ? total : @total
228+
229+
while i < count
230+
order = self[i] <=> other[i]
231+
return order unless order == 0
232+
233+
i += 1
234+
end
235+
end
236+
237+
# subtle: if we are recursing on that pair, then let's
238+
# no go any further down into that pair;
239+
# any difference will be found elsewhere if need be
240+
@total <=> total
241+
end
242+
243+
end

0 commit comments

Comments
 (0)