rubinius-core-api 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.txt +20 -0
- data/Rakefile +36 -0
- data/lib/rubinius/core-api.rb +16 -0
- data/lib/rubinius/kernel/bootstrap/channel.rb +106 -0
- data/lib/rubinius/kernel/common/bytearray.rb +26 -0
- data/lib/rubinius/kernel/common/channel.rb +21 -0
- data/lib/rubinius/kernel/common/env.rb +239 -0
- data/lib/rubinius/kernel/common/thread.rb +118 -0
- data/lib/rubinius/kernel/common/tuple.rb +148 -0
- data/lib/rubinius/kernel/common/type.rb +114 -0
- data/rubinius-core-api.gemspec +28 -0
- data/src/org/jruby/ext/rubinius/RubiniusByteArray.java +290 -0
- data/src/org/jruby/ext/rubinius/RubiniusChannel.java +115 -0
- data/src/org/jruby/ext/rubinius/RubiniusEnvironmentAccess.java +57 -0
- data/src/org/jruby/ext/rubinius/RubiniusKernel.java +42 -0
- data/src/org/jruby/ext/rubinius/RubiniusLibrary.java +111 -0
- data/src/org/jruby/ext/rubinius/RubiniusTuple.java +302 -0
- data/src/org/jruby/ext/rubinius/RubiniusType.java +43 -0
- metadata +85 -0
@@ -0,0 +1,115 @@
|
|
1
|
+
/*
|
2
|
+
**** BEGIN LICENSE BLOCK *****
|
3
|
+
* Version: CPL 1.0/GPL 2.0/LGPL 2.1
|
4
|
+
*
|
5
|
+
* The contents of this file are subject to the Common Public
|
6
|
+
* License Version 1.0 (the "License"); you may not use this file
|
7
|
+
* except in compliance with the License. You may obtain a copy of
|
8
|
+
* the License at http://www.eclipse.org/legal/cpl-v10.html
|
9
|
+
*
|
10
|
+
* Software distributed under the License is distributed on an "AS
|
11
|
+
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
12
|
+
* implied. See the License for the specific language governing
|
13
|
+
* rights and limitations under the License.
|
14
|
+
*
|
15
|
+
* Copyright (C) 2011 Charles O Nutter <headius@headius.com>
|
16
|
+
*
|
17
|
+
* Alternatively, the contents of this file may be used under the terms of
|
18
|
+
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
19
|
+
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
20
|
+
* in which case the provisions of the GPL or the LGPL are applicable instead
|
21
|
+
* of those above. If you wish to allow use of your version of this file only
|
22
|
+
* under the terms of either the GPL or the LGPL, and not to allow others to
|
23
|
+
* use your version of this file under the terms of the CPL, indicate your
|
24
|
+
* decision by deleting the provisions above and replace them with the notice
|
25
|
+
* and other provisions required by the GPL or the LGPL. If you do not delete
|
26
|
+
* the provisions above, a recipient may use your version of this file under
|
27
|
+
* the terms of any one of the CPL, the GPL or the LGPL.
|
28
|
+
***** END LICENSE BLOCK *****/
|
29
|
+
package org.jruby.ext.rubinius;
|
30
|
+
|
31
|
+
import java.util.concurrent.LinkedBlockingQueue;
|
32
|
+
import java.util.concurrent.TimeUnit;
|
33
|
+
import org.jruby.Ruby;
|
34
|
+
import org.jruby.RubyClass;
|
35
|
+
import org.jruby.RubyFixnum;
|
36
|
+
import org.jruby.RubyFloat;
|
37
|
+
import org.jruby.RubyObject;
|
38
|
+
import org.jruby.anno.JRubyMethod;
|
39
|
+
import org.jruby.runtime.ObjectAllocator;
|
40
|
+
import org.jruby.runtime.ThreadContext;
|
41
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
42
|
+
|
43
|
+
public class RubiniusChannel extends RubyObject {
|
44
|
+
private final LinkedBlockingQueue<IRubyObject> queue = new LinkedBlockingQueue();
|
45
|
+
|
46
|
+
public RubiniusChannel(Ruby runtime, RubyClass metaclass) {
|
47
|
+
super(runtime, metaclass);
|
48
|
+
}
|
49
|
+
|
50
|
+
public static void createChannelClass(Ruby runtime) {
|
51
|
+
RubyClass channelClass = runtime
|
52
|
+
.getOrCreateModule("Rubinius")
|
53
|
+
.defineClassUnder("Channel", runtime.getObject(), new ObjectAllocator() {
|
54
|
+
public IRubyObject allocate(Ruby runtime, RubyClass klazz) {
|
55
|
+
return new RubiniusChannel(runtime, klazz);
|
56
|
+
}
|
57
|
+
});
|
58
|
+
channelClass.setReifiedClass(RubiniusChannel.class);
|
59
|
+
|
60
|
+
channelClass.defineAnnotatedMethods(RubiniusChannel.class);
|
61
|
+
}
|
62
|
+
|
63
|
+
@JRubyMethod(name = "new", meta = true)
|
64
|
+
public static IRubyObject rbNew(ThreadContext context, IRubyObject channelClass) {
|
65
|
+
return new RubiniusChannel(context.runtime, (RubyClass)channelClass);
|
66
|
+
}
|
67
|
+
|
68
|
+
@JRubyMethod(name = {"send", "<<"})
|
69
|
+
public IRubyObject send(ThreadContext context, IRubyObject value) {
|
70
|
+
queue.add(value);
|
71
|
+
return context.nil;
|
72
|
+
}
|
73
|
+
|
74
|
+
@JRubyMethod
|
75
|
+
public IRubyObject receive(ThreadContext context) {
|
76
|
+
try {
|
77
|
+
return queue.take();
|
78
|
+
} catch (InterruptedException ie) {
|
79
|
+
return context.runtime.getFalse();
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
private static final int NANOSECONDS = 1000000;
|
84
|
+
|
85
|
+
@JRubyMethod
|
86
|
+
public IRubyObject receive_timeout(ThreadContext context, IRubyObject timeout) {
|
87
|
+
long time = 0;
|
88
|
+
if (timeout instanceof RubyFixnum) {
|
89
|
+
time = ((RubyFixnum)timeout).getLongValue() * NANOSECONDS;
|
90
|
+
} else if (timeout instanceof RubyFloat) {
|
91
|
+
time = (long)(((RubyFloat)timeout).getDoubleValue() * NANOSECONDS);
|
92
|
+
} else if (timeout.isNil()) {
|
93
|
+
time = -1;
|
94
|
+
} else {
|
95
|
+
throw context.runtime.newTypeError("expected Fixnum or Float to Channel#receive_timeout");
|
96
|
+
}
|
97
|
+
|
98
|
+
try {
|
99
|
+
if (time == -1) {
|
100
|
+
return queue.take();
|
101
|
+
} else {
|
102
|
+
return queue.poll(time, TimeUnit.NANOSECONDS);
|
103
|
+
}
|
104
|
+
} catch (InterruptedException ie) {
|
105
|
+
return context.runtime.getFalse();
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
@JRubyMethod
|
110
|
+
public IRubyObject try_receive(ThreadContext context) {
|
111
|
+
IRubyObject result = queue.poll();
|
112
|
+
if (result == null) return context.nil;
|
113
|
+
return result;
|
114
|
+
}
|
115
|
+
}
|
@@ -0,0 +1,57 @@
|
|
1
|
+
/*
|
2
|
+
**** BEGIN LICENSE BLOCK *****
|
3
|
+
* Version: CPL 1.0/GPL 2.0/LGPL 2.1
|
4
|
+
*
|
5
|
+
* The contents of this file are subject to the Common Public
|
6
|
+
* License Version 1.0 (the "License"); you may not use this file
|
7
|
+
* except in compliance with the License. You may obtain a copy of
|
8
|
+
* the License at http://www.eclipse.org/legal/cpl-v10.html
|
9
|
+
*
|
10
|
+
* Software distributed under the License is distributed on an "AS
|
11
|
+
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
12
|
+
* implied. See the License for the specific language governing
|
13
|
+
* rights and limitations under the License.
|
14
|
+
*
|
15
|
+
* Copyright (C) 2011 Charles O Nutter <headius@headius.com>
|
16
|
+
*
|
17
|
+
* Alternatively, the contents of this file may be used under the terms of
|
18
|
+
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
19
|
+
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
20
|
+
* in which case the provisions of the GPL or the LGPL are applicable instead
|
21
|
+
* of those above. If you wish to allow use of your version of this file only
|
22
|
+
* under the terms of either the GPL or the LGPL, and not to allow others to
|
23
|
+
* use your version of this file under the terms of the CPL, indicate your
|
24
|
+
* decision by deleting the provisions above and replace them with the notice
|
25
|
+
* and other provisions required by the GPL or the LGPL. If you do not delete
|
26
|
+
* the provisions above, a recipient may use your version of this file under
|
27
|
+
* the terms of any one of the CPL, the GPL or the LGPL.
|
28
|
+
***** END LICENSE BLOCK *****/
|
29
|
+
package org.jruby.ext.rubinius;
|
30
|
+
|
31
|
+
import org.jruby.RubyHash;
|
32
|
+
import org.jruby.anno.JRubyMethod;
|
33
|
+
import org.jruby.runtime.ThreadContext;
|
34
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
35
|
+
|
36
|
+
public class RubiniusEnvironmentAccess {
|
37
|
+
|
38
|
+
@JRubyMethod(module = true)
|
39
|
+
public static IRubyObject getenv(ThreadContext context, IRubyObject self, IRubyObject name) {
|
40
|
+
return getEnv(context).op_aref(context, name);
|
41
|
+
}
|
42
|
+
|
43
|
+
@JRubyMethod(module = true)
|
44
|
+
public static IRubyObject setenv(ThreadContext context, IRubyObject self, IRubyObject name, IRubyObject value) {
|
45
|
+
return getEnv(context).op_aset(context, name, value);
|
46
|
+
}
|
47
|
+
|
48
|
+
@JRubyMethod(module = true)
|
49
|
+
public static IRubyObject environ_as_hash(ThreadContext context, IRubyObject self) {
|
50
|
+
return getEnv(context).dup();
|
51
|
+
}
|
52
|
+
|
53
|
+
private static RubyHash getEnv(ThreadContext context) {
|
54
|
+
return context.runtime.getENV();
|
55
|
+
}
|
56
|
+
|
57
|
+
}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
/*
|
2
|
+
**** BEGIN LICENSE BLOCK *****
|
3
|
+
* Version: CPL 1.0/GPL 2.0/LGPL 2.1
|
4
|
+
*
|
5
|
+
* The contents of this file are subject to the Common Public
|
6
|
+
* License Version 1.0 (the "License"); you may not use this file
|
7
|
+
* except in compliance with the License. You may obtain a copy of
|
8
|
+
* the License at http://www.eclipse.org/legal/cpl-v10.html
|
9
|
+
*
|
10
|
+
* Software distributed under the License is distributed on an "AS
|
11
|
+
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
12
|
+
* implied. See the License for the specific language governing
|
13
|
+
* rights and limitations under the License.
|
14
|
+
*
|
15
|
+
* Copyright (C) 2011 Charles O Nutter <headius@headius.com>
|
16
|
+
*
|
17
|
+
* Alternatively, the contents of this file may be used under the terms of
|
18
|
+
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
19
|
+
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
20
|
+
* in which case the provisions of the GPL or the LGPL are applicable instead
|
21
|
+
* of those above. If you wish to allow use of your version of this file only
|
22
|
+
* under the terms of either the GPL or the LGPL, and not to allow others to
|
23
|
+
* use your version of this file under the terms of the CPL, indicate your
|
24
|
+
* decision by deleting the provisions above and replace them with the notice
|
25
|
+
* and other provisions required by the GPL or the LGPL. If you do not delete
|
26
|
+
* the provisions above, a recipient may use your version of this file under
|
27
|
+
* the terms of any one of the CPL, the GPL or the LGPL.
|
28
|
+
***** END LICENSE BLOCK *****/
|
29
|
+
package org.jruby.ext.rubinius;
|
30
|
+
|
31
|
+
import org.jruby.anno.JRubyMethod;
|
32
|
+
import org.jruby.runtime.ThreadContext;
|
33
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
34
|
+
|
35
|
+
public class RubiniusKernel {
|
36
|
+
|
37
|
+
@JRubyMethod(module = true)
|
38
|
+
public static IRubyObject StringValue(ThreadContext context, IRubyObject self, IRubyObject arg) {
|
39
|
+
return arg.convertToString();
|
40
|
+
}
|
41
|
+
|
42
|
+
}
|
@@ -0,0 +1,111 @@
|
|
1
|
+
/*
|
2
|
+
**** BEGIN LICENSE BLOCK *****
|
3
|
+
* Version: CPL 1.0/GPL 2.0/LGPL 2.1
|
4
|
+
*
|
5
|
+
* The contents of this file are subject to the Common Public
|
6
|
+
* License Version 1.0 (the "License"); you may not use this file
|
7
|
+
* except in compliance with the License. You may obtain a copy of
|
8
|
+
* the License at http://www.eclipse.org/legal/cpl-v10.html
|
9
|
+
*
|
10
|
+
* Software distributed under the License is distributed on an "AS
|
11
|
+
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
12
|
+
* implied. See the License for the specific language governing
|
13
|
+
* rights and limitations under the License.
|
14
|
+
*
|
15
|
+
* Copyright (C) 2011 Charles O Nutter <headius@headius.com>
|
16
|
+
*
|
17
|
+
* Alternatively, the contents of this file may be used under the terms of
|
18
|
+
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
19
|
+
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
20
|
+
* in which case the provisions of the GPL or the LGPL are applicable instead
|
21
|
+
* of those above. If you wish to allow use of your version of this file only
|
22
|
+
* under the terms of either the GPL or the LGPL, and not to allow others to
|
23
|
+
* use your version of this file under the terms of the CPL, indicate your
|
24
|
+
* decision by deleting the provisions above and replace them with the notice
|
25
|
+
* and other provisions required by the GPL or the LGPL. If you do not delete
|
26
|
+
* the provisions above, a recipient may use your version of this file under
|
27
|
+
* the terms of any one of the CPL, the GPL or the LGPL.
|
28
|
+
***** END LICENSE BLOCK *****/
|
29
|
+
package org.jruby.ext.rubinius;
|
30
|
+
|
31
|
+
import java.io.IOException;
|
32
|
+
import org.jruby.Ruby;
|
33
|
+
import org.jruby.RubyClass;
|
34
|
+
import org.jruby.RubyModule;
|
35
|
+
import org.jruby.RubyObject;
|
36
|
+
import org.jruby.exceptions.RaiseException;
|
37
|
+
import org.jruby.internal.runtime.methods.JavaMethod;
|
38
|
+
import org.jruby.runtime.ObjectAllocator;
|
39
|
+
import org.jruby.runtime.ThreadContext;
|
40
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
41
|
+
import org.jruby.runtime.load.Library;
|
42
|
+
import static org.jruby.runtime.Visibility.*;
|
43
|
+
|
44
|
+
/**
|
45
|
+
* This extension defines a number of classes/modules and modifications to core
|
46
|
+
* that are used by parts of Rubinius's kernel and libraries. The intent here is
|
47
|
+
* to provide as many of those Rubinius-borne features as possible to allow
|
48
|
+
* users to write to those APIs (for their own libraries or for extending JRuby)
|
49
|
+
* and eventually to share more of Rubinius's core class implementations with
|
50
|
+
* JRuby.
|
51
|
+
*/
|
52
|
+
public class RubiniusLibrary implements Library {
|
53
|
+
public void load(final Ruby runtime, boolean wrap) throws IOException {
|
54
|
+
RubyModule rubinius = runtime.getOrCreateModule("Rubinius");
|
55
|
+
|
56
|
+
final IRubyObject undefined = new RubyObject(runtime, runtime.getObject());
|
57
|
+
runtime.getKernel().addMethod("undefined", new JavaMethod.JavaMethodZero(runtime.getKernel(), PRIVATE) {
|
58
|
+
@Override
|
59
|
+
public IRubyObject call(ThreadContext context, IRubyObject self, RubyModule clazz, String name) {
|
60
|
+
return undefined;
|
61
|
+
}
|
62
|
+
});
|
63
|
+
|
64
|
+
// Tuple class
|
65
|
+
RubiniusTuple.createTupleClass(runtime);
|
66
|
+
runtime.getLoadService().require("rubinius/kernel/common/tuple.rb");
|
67
|
+
|
68
|
+
// Type module
|
69
|
+
RubyModule type = runtime.defineModule("Type");
|
70
|
+
type.defineAnnotatedMethods(RubiniusType.class);
|
71
|
+
runtime.getLoadService().require("rubinius/kernel/common/type.rb");
|
72
|
+
|
73
|
+
// LookupTable is just Hash for now
|
74
|
+
rubinius.setConstant("LookupTable", runtime.getHash());
|
75
|
+
|
76
|
+
// EnvironmentAccess
|
77
|
+
RubyModule envAccess = rubinius.defineModuleUnder("EnvironmentAccess");
|
78
|
+
envAccess.defineAnnotatedMethods(RubiniusEnvironmentAccess.class);
|
79
|
+
runtime.getLoadService().require("rubinius/kernel/common/env.rb");
|
80
|
+
|
81
|
+
// Thread-borne recursion detector stuff
|
82
|
+
runtime.getLoadService().require("rubinius/kernel/common/thread.rb");
|
83
|
+
|
84
|
+
// Extensions to Kernel
|
85
|
+
runtime.getKernel().defineAnnotatedMethods(RubiniusKernel.class);
|
86
|
+
|
87
|
+
// Channel class; we require bootstrap, overwrite it, and then require common
|
88
|
+
runtime.getLoadService().require("rubinius/kernel/bootstrap/channel.rb");
|
89
|
+
RubiniusChannel.createChannelClass(runtime);
|
90
|
+
runtime.getLoadService().require("rubinius/kernel/common/channel.rb");
|
91
|
+
|
92
|
+
// Rubinius exception types
|
93
|
+
RubyClass vmException = rubinius.defineClassUnder("VMException", runtime.getException(), runtime.getException().getAllocator());
|
94
|
+
rubinius.defineClassUnder("ObjectBoundsExceededError", vmException, vmException.getAllocator());
|
95
|
+
rubinius.defineClassUnder("AssertionError", vmException, vmException.getAllocator());
|
96
|
+
|
97
|
+
// ByteArray
|
98
|
+
RubiniusByteArray.createByteArrayClass(runtime);
|
99
|
+
runtime.getLoadService().require("rubinius/kernel/common/bytearray.rb");
|
100
|
+
}
|
101
|
+
|
102
|
+
public static RaiseException object_bounds_exceeded_error(ThreadContext context, String message) {
|
103
|
+
throw context.runtime.newRaiseException(
|
104
|
+
(RubyClass)context.runtime.getClassFromPath("Rubinius::ObjectBoundsExceededError"),
|
105
|
+
message);
|
106
|
+
}
|
107
|
+
|
108
|
+
public static RaiseException argument_error(ThreadContext context, String message) {
|
109
|
+
throw context.runtime.newArgumentError(message);
|
110
|
+
}
|
111
|
+
}
|
@@ -0,0 +1,302 @@
|
|
1
|
+
/*
|
2
|
+
**** BEGIN LICENSE BLOCK *****
|
3
|
+
* Version: CPL 1.0/GPL 2.0/LGPL 2.1
|
4
|
+
*
|
5
|
+
* The contents of this file are subject to the Common Public
|
6
|
+
* License Version 1.0 (the "License"); you may not use this file
|
7
|
+
* except in compliance with the License. You may obtain a copy of
|
8
|
+
* the License at http://www.eclipse.org/legal/cpl-v10.html
|
9
|
+
*
|
10
|
+
* Software distributed under the License is distributed on an "AS
|
11
|
+
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
12
|
+
* implied. See the License for the specific language governing
|
13
|
+
* rights and limitations under the License.
|
14
|
+
*
|
15
|
+
* Copyright (C) 2010 Charles O Nutter <headius@headius.com>
|
16
|
+
*
|
17
|
+
* Alternatively, the contents of this file may be used under the terms of
|
18
|
+
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
19
|
+
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
20
|
+
* in which case the provisions of the GPL or the LGPL are applicable instead
|
21
|
+
* of those above. If you wish to allow use of your version of this file only
|
22
|
+
* under the terms of either the GPL or the LGPL, and not to allow others to
|
23
|
+
* use your version of this file under the terms of the CPL, indicate your
|
24
|
+
* decision by deleting the provisions above and replace them with the notice
|
25
|
+
* and other provisions required by the GPL or the LGPL. If you do not delete
|
26
|
+
* the provisions above, a recipient may use your version of this file under
|
27
|
+
* the terms of any one of the CPL, the GPL or the LGPL.
|
28
|
+
***** END LICENSE BLOCK *****/
|
29
|
+
package org.jruby.ext.rubinius;
|
30
|
+
|
31
|
+
import java.util.Arrays;
|
32
|
+
import org.jruby.Ruby;
|
33
|
+
import org.jruby.RubyArray;
|
34
|
+
import org.jruby.RubyClass;
|
35
|
+
import org.jruby.RubyFixnum;
|
36
|
+
import org.jruby.RubyObject;
|
37
|
+
import org.jruby.anno.JRubyMethod;
|
38
|
+
import org.jruby.javasupport.util.RuntimeHelpers;
|
39
|
+
import org.jruby.runtime.ObjectAllocator;
|
40
|
+
import org.jruby.runtime.ThreadContext;
|
41
|
+
import org.jruby.runtime.builtin.IRubyObject;
|
42
|
+
import org.jruby.util.ArraysUtil;
|
43
|
+
|
44
|
+
public class RubiniusTuple extends RubyObject {
|
45
|
+
|
46
|
+
private IRubyObject[] ary;
|
47
|
+
|
48
|
+
public RubiniusTuple(Ruby runtime, int size) {
|
49
|
+
super(runtime, (RubyClass) runtime.getClassFromPath("Rubinius::Tuple"));
|
50
|
+
|
51
|
+
this.ary = new IRubyObject[size];
|
52
|
+
RuntimeHelpers.fillNil(ary, runtime);
|
53
|
+
}
|
54
|
+
|
55
|
+
public RubiniusTuple(Ruby runtime, int size, IRubyObject fill) {
|
56
|
+
super(runtime, (RubyClass) runtime.getClassFromPath("Rubinius::Tuple"));
|
57
|
+
|
58
|
+
this.ary = new IRubyObject[size];
|
59
|
+
if (fill == runtime.getNil()) {
|
60
|
+
RuntimeHelpers.fillNil(ary, runtime);
|
61
|
+
} else {
|
62
|
+
Arrays.fill(this.ary, fill);
|
63
|
+
}
|
64
|
+
}
|
65
|
+
|
66
|
+
public static void createTupleClass(Ruby runtime) {
|
67
|
+
RubyClass tupleClass = runtime.getOrCreateModule("Rubinius").defineClassUnder("Tuple", runtime.getObject(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
|
68
|
+
tupleClass.setReifiedClass(RubiniusTuple.class);
|
69
|
+
|
70
|
+
tupleClass.defineAnnotatedMethods(RubiniusTuple.class);
|
71
|
+
}
|
72
|
+
|
73
|
+
public int num_fields() {
|
74
|
+
return ary.length;
|
75
|
+
}
|
76
|
+
|
77
|
+
public IRubyObject field(int index) {
|
78
|
+
return ary[index];
|
79
|
+
}
|
80
|
+
|
81
|
+
private void bounds_exceeded_error(ThreadContext state, String method, long index) {
|
82
|
+
throw RubiniusLibrary.object_bounds_exceeded_error(state, method + ": index " + index + " out of bounds for size " + ary.length);
|
83
|
+
}
|
84
|
+
|
85
|
+
static RubiniusTuple create(ThreadContext context, int size) {
|
86
|
+
return new RubiniusTuple(context.runtime, size);
|
87
|
+
}
|
88
|
+
|
89
|
+
static RubiniusTuple create(ThreadContext context, int size, IRubyObject fill) {
|
90
|
+
return new RubiniusTuple(context.runtime, size, fill);
|
91
|
+
}
|
92
|
+
|
93
|
+
@JRubyMethod(meta = true)
|
94
|
+
public static IRubyObject allocate(ThreadContext state, IRubyObject baClass, IRubyObject size) {
|
95
|
+
throw state.runtime.newTypeError("Tuple cannot be created via allocate()");
|
96
|
+
}
|
97
|
+
|
98
|
+
@JRubyMethod(name = "new", meta = true)
|
99
|
+
public static IRubyObject rbNew(ThreadContext state, IRubyObject tupleCls, IRubyObject fields) {
|
100
|
+
long size = fields.convertToInteger().getLongValue();
|
101
|
+
if (size < 0) {
|
102
|
+
RubiniusLibrary.argument_error(state, "negative tuple size");
|
103
|
+
} else if (size > Integer.MAX_VALUE) {
|
104
|
+
RubiniusLibrary.argument_error(state, "too large tuple size");
|
105
|
+
}
|
106
|
+
return RubiniusTuple.create(state, (int) size);
|
107
|
+
}
|
108
|
+
|
109
|
+
@JRubyMethod(meta = true)
|
110
|
+
public static IRubyObject pattern(ThreadContext state, IRubyObject size, IRubyObject obj) {
|
111
|
+
long cnt = size.convertToInteger().getLongValue();
|
112
|
+
|
113
|
+
if (cnt < 0) {
|
114
|
+
RubiniusLibrary.argument_error(state, "negative tuple size");
|
115
|
+
} else if (cnt > Integer.MAX_VALUE) {
|
116
|
+
RubiniusLibrary.argument_error(state, "too large tuple size");
|
117
|
+
}
|
118
|
+
|
119
|
+
return RubiniusTuple.create(state, (int) cnt, obj);
|
120
|
+
}
|
121
|
+
|
122
|
+
@JRubyMethod(name = {"[]", "at"})
|
123
|
+
public IRubyObject op_aref(ThreadContext state, IRubyObject index) {
|
124
|
+
long idx = index.convertToInteger().getLongValue();
|
125
|
+
|
126
|
+
if (idx < 0 || num_fields() <= idx) {
|
127
|
+
bounds_exceeded_error(state, "Tuple::put_prim", idx);
|
128
|
+
}
|
129
|
+
|
130
|
+
return ary[(int) idx];
|
131
|
+
}
|
132
|
+
|
133
|
+
@JRubyMethod(name = {"[]=", "put"})
|
134
|
+
public IRubyObject op_aset(ThreadContext state, IRubyObject index, IRubyObject val) {
|
135
|
+
long idx = index.convertToInteger().getLongValue();
|
136
|
+
|
137
|
+
if (idx < 0 || num_fields() <= idx) {
|
138
|
+
bounds_exceeded_error(state, "Tuple::put_prim", idx);
|
139
|
+
}
|
140
|
+
|
141
|
+
this.ary[(int) idx] = val;
|
142
|
+
return val;
|
143
|
+
}
|
144
|
+
|
145
|
+
@JRubyMethod
|
146
|
+
public IRubyObject fields(ThreadContext state) {
|
147
|
+
return RubyFixnum.newFixnum(state.runtime, ary.length);
|
148
|
+
}
|
149
|
+
|
150
|
+
@JRubyMethod(required = 4)
|
151
|
+
public IRubyObject copy_from(ThreadContext state, IRubyObject[] args) {
|
152
|
+
IRubyObject _other = args[0];
|
153
|
+
IRubyObject start = args[1];
|
154
|
+
IRubyObject length = args[2];
|
155
|
+
IRubyObject dest = args[3];
|
156
|
+
|
157
|
+
RubiniusTuple other = (RubiniusTuple) _other;
|
158
|
+
int osize = other.num_fields();
|
159
|
+
int size = this.num_fields();
|
160
|
+
|
161
|
+
long src_start = start.convertToInteger().getLongValue();
|
162
|
+
long dst_start = dest.convertToInteger().getLongValue();
|
163
|
+
long len = length.convertToInteger().getLongValue();
|
164
|
+
|
165
|
+
// left end should be within range
|
166
|
+
if (src_start < 0 || src_start > osize) {
|
167
|
+
other.bounds_exceeded_error(state, "Tuple::copy_from", src_start);
|
168
|
+
}
|
169
|
+
|
170
|
+
if (dst_start < 0 || dst_start > size) {
|
171
|
+
bounds_exceeded_error(state, "Tuple::copy_from", dst_start);
|
172
|
+
}
|
173
|
+
|
174
|
+
// length can not be negative and must fit in src/dest
|
175
|
+
if (len < 0) {
|
176
|
+
other.bounds_exceeded_error(state, "Tuple::copy_from", len);
|
177
|
+
}
|
178
|
+
|
179
|
+
if ((src_start + len) > osize) {
|
180
|
+
other.bounds_exceeded_error(state, "Tuple::copy_from", src_start + len);
|
181
|
+
}
|
182
|
+
|
183
|
+
if (len > (size - dst_start)) {
|
184
|
+
bounds_exceeded_error(state, "Tuple::copy_from", len);
|
185
|
+
}
|
186
|
+
|
187
|
+
// A memmove within the tuple
|
188
|
+
if (other == this) {
|
189
|
+
// No movement, no work!
|
190
|
+
if (src_start == dst_start) {
|
191
|
+
return this;
|
192
|
+
}
|
193
|
+
// right shift
|
194
|
+
if (src_start < dst_start) {
|
195
|
+
for (long dest_idx = dst_start + len - 1,
|
196
|
+
src_idx = src_start + len - 1;
|
197
|
+
src_idx >= src_start;
|
198
|
+
src_idx--, dest_idx--) {
|
199
|
+
this.ary[(int) dest_idx] = this.ary[(int) src_idx];
|
200
|
+
}
|
201
|
+
} else {
|
202
|
+
// left shift
|
203
|
+
for (long dest_idx = dst_start,
|
204
|
+
src_idx = src_start;
|
205
|
+
src_idx < src_start + len;
|
206
|
+
src_idx++, dest_idx++) {
|
207
|
+
this.ary[(int) dest_idx] = this.ary[(int) src_idx];
|
208
|
+
}
|
209
|
+
}
|
210
|
+
|
211
|
+
} else {
|
212
|
+
for (long src = src_start, dst = dst_start;
|
213
|
+
src < (src_start + len);
|
214
|
+
++src, ++dst) {
|
215
|
+
// Since we have carefully checked the bounds we don't need
|
216
|
+
// to do it in at/put
|
217
|
+
IRubyObject obj = other.ary[(int) src];
|
218
|
+
this.ary[(int) dst] = obj;
|
219
|
+
}
|
220
|
+
}
|
221
|
+
|
222
|
+
return this;
|
223
|
+
}
|
224
|
+
|
225
|
+
@JRubyMethod
|
226
|
+
public IRubyObject dup() {
|
227
|
+
return super.dup();
|
228
|
+
}
|
229
|
+
|
230
|
+
@JRubyMethod
|
231
|
+
public IRubyObject delete(ThreadContext state, IRubyObject start, IRubyObject length, IRubyObject obj) {
|
232
|
+
int size = this.num_fields();
|
233
|
+
long len = length.convertToInteger().getLongValue();
|
234
|
+
long lend = start.convertToInteger().getLongValue();
|
235
|
+
long rend = lend + len;
|
236
|
+
|
237
|
+
if (size == 0 || len == 0) {
|
238
|
+
return RubyFixnum.zero(state.runtime);
|
239
|
+
}
|
240
|
+
if (lend < 0 || lend >= size) {
|
241
|
+
bounds_exceeded_error(state, "Tuple::delete_inplace", lend);
|
242
|
+
}
|
243
|
+
|
244
|
+
if (rend < 0 || rend > size) {
|
245
|
+
bounds_exceeded_error(state, "Tuple::delete_inplace", rend);
|
246
|
+
}
|
247
|
+
|
248
|
+
int i = (int) lend;
|
249
|
+
while (i < rend) {
|
250
|
+
if (this.ary[i] == obj) {
|
251
|
+
int j = i;
|
252
|
+
++i;
|
253
|
+
while (i < rend) {
|
254
|
+
IRubyObject val = this.ary[i];
|
255
|
+
if (val != obj) {
|
256
|
+
// no need to set write_barrier since it's already
|
257
|
+
// referenced to this object
|
258
|
+
this.ary[j] = val;
|
259
|
+
++j;
|
260
|
+
}
|
261
|
+
++i;
|
262
|
+
}
|
263
|
+
// cleanup all the bins after
|
264
|
+
i = j;
|
265
|
+
while (i < rend) {
|
266
|
+
this.ary[i] = state.nil;
|
267
|
+
++i;
|
268
|
+
}
|
269
|
+
return RubyFixnum.newFixnum(state.runtime, rend - j);
|
270
|
+
}
|
271
|
+
++i;
|
272
|
+
}
|
273
|
+
return RubyFixnum.zero(state.runtime);
|
274
|
+
}
|
275
|
+
|
276
|
+
@JRubyMethod
|
277
|
+
public IRubyObject reverse(ThreadContext state, IRubyObject o_start, IRubyObject o_total) {
|
278
|
+
long start = o_start.convertToInteger().getLongValue();
|
279
|
+
long total = o_total.convertToInteger().getLongValue();
|
280
|
+
|
281
|
+
if (total <= 0 || start < 0 || start >= num_fields()) {
|
282
|
+
return this;
|
283
|
+
}
|
284
|
+
|
285
|
+
long end = start + total - 1;
|
286
|
+
if (end >= num_fields()) {
|
287
|
+
end = num_fields() - 1;
|
288
|
+
}
|
289
|
+
|
290
|
+
int pos1 = (int) start;
|
291
|
+
int pos2 = (int) end;
|
292
|
+
|
293
|
+
IRubyObject tmp;
|
294
|
+
while (pos1 < pos2) {
|
295
|
+
tmp = ary[pos1];
|
296
|
+
ary[pos1++] = ary[pos2];
|
297
|
+
ary[pos2--] = tmp;
|
298
|
+
}
|
299
|
+
|
300
|
+
return this;
|
301
|
+
}
|
302
|
+
}
|