rubinius-core-api 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,118 @@
1
+ #--
2
+ # Be very careful about calling raise in here! Thread has its own
3
+ # raise which, if you're calling raise, you probably don't want. Use
4
+ # Kernel.raise to call the proper raise.
5
+ #++
6
+
7
+ class Thread
8
+
9
+ attr_reader :recursive_objects
10
+
11
+ # Implementation note: ideally, the recursive_objects
12
+ # lookup table would be different per method call.
13
+ # Currently it doesn't cause problems, but if ever
14
+ # a method :foo calls a method :bar which could
15
+ # recurse back to :foo, it could require making
16
+ # the tables independant.
17
+
18
+ def self.recursion_guard(obj)
19
+ id = obj.object_id
20
+ objects = current.recursive_objects
21
+ objects[id] = true
22
+
23
+ begin
24
+ yield
25
+ ensure
26
+ objects.delete id
27
+ end
28
+ end
29
+
30
+ def self.guarding?(obj)
31
+ current.recursive_objects[obj.object_id]
32
+ end
33
+
34
+ # detect_recursion will return if there's a recursion
35
+ # on obj (or the pair obj+paired_obj).
36
+ # If there is one, it returns true.
37
+ # Otherwise, it will yield once and return false.
38
+
39
+ def self.detect_recursion(obj, paired_obj=undefined)
40
+ id = obj.object_id
41
+ pair_id = paired_obj.object_id
42
+ objects = current.recursive_objects
43
+
44
+ case objects[id]
45
+
46
+ # Default case, we haven't seen +obj+ yet, so we add it and run the block.
47
+ when nil
48
+ objects[id] = pair_id
49
+ begin
50
+ yield
51
+ ensure
52
+ objects.delete id
53
+ end
54
+
55
+ # We've seen +obj+ before and it's got multiple paired objects associated
56
+ # with it, so check the pair and yield if there is no recursion.
57
+ when Rubinius::LookupTable
58
+ return true if objects[id][pair_id]
59
+ objects[id][pair_id] = true
60
+
61
+ begin
62
+ yield
63
+ ensure
64
+ objects[id].delete pair_id
65
+ end
66
+
67
+ # We've seen +obj+ with one paired object, so check the stored one for
68
+ # recursion.
69
+ #
70
+ # This promotes the value to a LookupTable since there is another new paired
71
+ # object.
72
+ else
73
+ previous = objects[id]
74
+ return true if previous == pair_id
75
+
76
+ objects[id] = Rubinius::LookupTable.new(previous => true, pair_id => true)
77
+
78
+ begin
79
+ yield
80
+ ensure
81
+ objects[id] = previous
82
+ end
83
+ end
84
+
85
+ false
86
+ end
87
+
88
+ # Similar to detect_recursion, but will short circuit all inner recursion
89
+ # levels (using a throw)
90
+
91
+ class InnerRecursionDetected < Exception; end
92
+
93
+ def self.detect_outermost_recursion(obj, paired_obj=undefined, &block)
94
+ rec = current.recursive_objects
95
+
96
+ if rec[:__detect_outermost_recursion__]
97
+ if detect_recursion(obj, paired_obj, &block)
98
+ raise InnerRecursionDetected.new
99
+ end
100
+ false
101
+ else
102
+ begin
103
+ rec[:__detect_outermost_recursion__] = true
104
+
105
+ begin
106
+ detect_recursion(obj, paired_obj, &block)
107
+ rescue InnerRecursionDetected
108
+ return true
109
+ end
110
+
111
+ return nil
112
+ ensure
113
+ rec.delete :__detect_outermost_recursion__
114
+ end
115
+ end
116
+ end
117
+
118
+ end
@@ -0,0 +1,148 @@
1
+ ##
2
+ # The tuple data type.
3
+ # A simple storage class. Created to contain a fixed number of elements.
4
+ #
5
+ # Not designed to be subclassed, as it does not call initialize
6
+ # on new instances.
7
+
8
+ module Rubinius
9
+ class Tuple
10
+
11
+ include Enumerable
12
+
13
+ def self.[](*args)
14
+ start = args.start
15
+ tot = args.size
16
+ return new(tot).copy_from(args.tuple, start, tot, 0)
17
+ end
18
+
19
+ def to_s
20
+ "#<#{self.class}:0x#{object_id.to_s(16)} #{fields} elements>"
21
+ end
22
+
23
+ def each
24
+ i = 0
25
+ t = fields
26
+ while i < t
27
+ yield at(i)
28
+ i += 1
29
+ end
30
+ self
31
+ end
32
+
33
+ def ==(tup)
34
+ return super unless tup.kind_of?(Tuple)
35
+
36
+ t = fields()
37
+
38
+ return false unless t == tup.size
39
+
40
+ i = 0
41
+ while i < t
42
+ return false unless at(i) == tup.at(i)
43
+ i += 1
44
+ end
45
+
46
+ return true
47
+ end
48
+
49
+ def +(o)
50
+ t = Tuple.new(size + o.size)
51
+ t.copy_from(self,0,size,0)
52
+ t.copy_from(o,0,o.size,size)
53
+ t
54
+ end
55
+
56
+ def inspect
57
+ str = "#<#{self.class}"
58
+ if fields == 0
59
+ str << " empty>"
60
+ else
61
+ str << ": #{join(", ", :inspect)}>"
62
+ end
63
+ return str
64
+ end
65
+
66
+ def join(sep, meth=:to_s)
67
+ join_upto(sep, fields, meth)
68
+ end
69
+
70
+ def join_upto(sep, count, meth=:to_s)
71
+ str = ""
72
+ return str if count == 0 or empty?
73
+
74
+ count = fields if count >= fields
75
+ count -= 1
76
+ i = 0
77
+ while i < count
78
+ str.append at(i).__send__(meth)
79
+ str.append sep.dup
80
+ i += 1
81
+ end
82
+
83
+ str.append at(count).__send__(meth)
84
+ return str
85
+ end
86
+
87
+ def ===(other)
88
+ return false unless Tuple === other and fields == other.fields
89
+ i = 0
90
+ while i < fields
91
+ return false unless at(i) === other.at(i)
92
+ i += 1
93
+ end
94
+ true
95
+ end
96
+
97
+ def to_a
98
+ ary = []
99
+ ary.tuple = dup
100
+ ary.total = fields
101
+ ary.start = 0
102
+ return ary
103
+ end
104
+
105
+ def shift
106
+ return self unless fields > 0
107
+ t = Tuple.new(fields-1)
108
+ t.copy_from self, 1, fields-1, 0
109
+ return t
110
+ end
111
+
112
+ # Swap elements of the two indexes.
113
+ def swap(a, b)
114
+ temp = at(a)
115
+ put a, at(b)
116
+ put b, temp
117
+ end
118
+
119
+ alias_method :size, :fields
120
+ alias_method :length, :fields
121
+
122
+ def empty?
123
+ size == 0
124
+ end
125
+
126
+ def first
127
+ at(0)
128
+ end
129
+
130
+ def last
131
+ at(fields - 1)
132
+ end
133
+
134
+ # Marshal support - _dump / _load are deprecated so eventually we should figure
135
+ # out a better way.
136
+ def _dump(depth)
137
+ # TODO use depth
138
+ Marshal.dump to_a
139
+ end
140
+
141
+ def self._load(str)
142
+ ary = Marshal.load(str)
143
+ t = new(ary.size)
144
+ ary.each_with_index { |obj, idx| t[idx] = obj }
145
+ return t
146
+ end
147
+ end
148
+ end
@@ -0,0 +1,114 @@
1
+ ##
2
+ # Namespace for coercion functions between various ruby objects.
3
+
4
+ module Rubinius
5
+ module Type
6
+
7
+ ##
8
+ # Returns an object of given class. If given object already is one, it is
9
+ # returned. Otherwise tries obj.meth and returns the result if it is of the
10
+ # right kind. TypeErrors are raised if the conversion method fails or the
11
+ # conversion result is wrong.
12
+ #
13
+ # Uses Rubinius::Type.object_kind_of to bypass type check overrides.
14
+ #
15
+ # Equivalent to MRI's rb_convert_type().
16
+
17
+ def self.coerce_to(obj, cls, meth)
18
+ return obj if object_kind_of?(obj, cls)
19
+
20
+ begin
21
+ ret = obj.__send__(meth)
22
+ rescue Exception => orig
23
+ raise TypeError,
24
+ "Coercion error: #{obj.inspect}.#{meth} => #{cls} failed",
25
+ orig
26
+ end
27
+
28
+ return ret if object_kind_of?(ret, cls)
29
+
30
+ msg = "Coercion error: obj.#{meth} did NOT return a #{cls} (was #{object_class(ret)})"
31
+ raise TypeError, msg
32
+ end
33
+
34
+ ##
35
+ # Same as coerce_to but returns nil if conversion fails.
36
+ # Corresponds to MRI's rb_check_convert_type()
37
+ #
38
+ def self.try_convert(obj, cls, meth)
39
+ return obj if object_kind_of?(obj, cls)
40
+ return nil unless obj.respond_to?(meth)
41
+
42
+ begin
43
+ ret = obj.__send__(meth)
44
+ rescue Exception
45
+ return nil
46
+ end
47
+
48
+ return ret if ret.nil? || object_kind_of?(ret, cls)
49
+
50
+ msg = "Coercion error: obj.#{meth} did NOT return a #{cls} (was #{object_class(ret)})"
51
+ raise TypeError, msg
52
+ end
53
+
54
+ def self.coerce_to_symbol(obj)
55
+ if object_kind_of?(obj, Fixnum)
56
+ raise ArgumentError, "Fixnums (#{obj}) cannot be used as symbols"
57
+ end
58
+ obj = obj.to_str if obj.respond_to?(:to_str)
59
+
60
+ coerce_to(obj, Symbol, :to_sym)
61
+ end
62
+
63
+ def self.coerce_to_comparison(a, b)
64
+ unless cmp = (a <=> b)
65
+ raise ArgumentError, "comparison of #{a.inspect} with #{b.inspect} failed"
66
+ end
67
+ cmp
68
+ end
69
+
70
+ # Maps to rb_num2long in MRI
71
+ def self.num2long(obj)
72
+ if obj == nil
73
+ raise TypeError, "no implicit conversion from nil to integer"
74
+ else
75
+ Integer(obj)
76
+ end
77
+ end
78
+
79
+ def self.each_ancestor(mod)
80
+ unless object_kind_of?(mod, Class) and singleton_class_object(mod)
81
+ yield mod
82
+ end
83
+
84
+ sup = mod.direct_superclass()
85
+ while sup
86
+ if object_kind_of?(sup, IncludedModule)
87
+ yield sup.module
88
+ elsif object_kind_of?(sup, Class)
89
+ yield sup unless singleton_class_object(sup)
90
+ else
91
+ yield sup
92
+ end
93
+ sup = sup.direct_superclass()
94
+ end
95
+ end
96
+
97
+ def self.ivar_validate(name)
98
+ # adapted from rb_to_id
99
+ case name
100
+ when String
101
+ return name.to_sym if name[0] == ?@
102
+ when Symbol
103
+ return name if name.is_ivar?
104
+ when Fixnum
105
+ raise ArgumentError, "#{name.inspect} is not a symbol"
106
+ else
107
+ name = Rubinius::Type.coerce_to(name, String, :to_str)
108
+ return name.to_sym if name[0] == ?@
109
+ end
110
+
111
+ raise NameError, "`#{name}' is not allowed as an instance variable name"
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ base_specification = proc do |s|
4
+ s.name = %q{rubinius-core-api}
5
+ s.version = "0.0.1"
6
+ s.authors = ["Charles Oliver Nutter"]
7
+ s.date = Time.now
8
+ s.description = "Cross-impl versions of interesting Rubinius core classes"
9
+ s.email = ["headius@headius.com"]
10
+ s.files = Dir['{lib,src}/**/*'] + Dir['{*.txt,*.gemspec,Rakefile}']
11
+ s.homepage = "http://github.com/rubinius/rubinius-core-api"
12
+ s.require_paths = ["lib"]
13
+ s.summary = "Cross-impl versions of interesting Rubinius core classes"
14
+ s.test_files = Dir["test/test*.rb"]
15
+ end
16
+
17
+ if defined?(JRUBY_VERSION)
18
+ Gem::Specification.new do |s|
19
+ s.tap(&base_specification)
20
+ s.platform = "java"
21
+ end
22
+ elsif defined?(RUBY_ENGINE) && RUBY_ENGINE == 'rbx'
23
+ Gem::Specification.new do |s|
24
+ s.tap(&base_specification)
25
+ end
26
+ else
27
+ raise "Only supported on JRuby right now."
28
+ end
@@ -0,0 +1,290 @@
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.Ruby;
32
+ import org.jruby.RubyClass;
33
+ import org.jruby.RubyFixnum;
34
+ import org.jruby.RubyObject;
35
+ import org.jruby.RubyString;
36
+ import org.jruby.anno.JRubyMethod;
37
+ import org.jruby.runtime.ObjectAllocator;
38
+ import org.jruby.runtime.ThreadContext;
39
+ import org.jruby.runtime.builtin.IRubyObject;
40
+ import org.jruby.util.ByteList;
41
+
42
+ public class RubiniusByteArray extends RubyObject {
43
+
44
+ private final byte[] bytes;
45
+
46
+ RubiniusByteArray(Ruby runtime, int size) {
47
+ // FIXME: need to store metaclass somewhere...
48
+ super(runtime, (RubyClass) runtime.getClassFromPath("Rubinius::ByteArray"));
49
+
50
+ bytes = new byte[size];
51
+ }
52
+
53
+ RubiniusByteArray(Ruby runtime, byte[] bytes) {
54
+ // FIXME: need to store metaclass somewhere...
55
+ super(runtime, (RubyClass) runtime.getClassFromPath("Rubinius::ByteArray"));
56
+
57
+ this.bytes = bytes;
58
+ }
59
+
60
+ public static void createByteArrayClass(Ruby runtime) {
61
+ RubyClass baClass = runtime.getOrCreateModule("Rubinius").defineClassUnder("ByteArray", runtime.getObject(), ObjectAllocator.NOT_ALLOCATABLE_ALLOCATOR);
62
+ baClass.setReifiedClass(RubiniusByteArray.class);
63
+
64
+ baClass.defineAnnotatedMethods(RubiniusByteArray.class);
65
+
66
+ // add "data" method to String for spec purposes; not recommended for use (raw byte[] access)
67
+ runtime.getString().defineAnnotatedMethods(RubiniusString.class);
68
+ }
69
+
70
+ static RubiniusByteArray create(ThreadContext context, int size) {
71
+ return new RubiniusByteArray(context.runtime, size);
72
+ }
73
+
74
+ private int size() {
75
+ return bytes.length;
76
+ }
77
+
78
+ @JRubyMethod(meta = true)
79
+ public static IRubyObject allocate(ThreadContext state, IRubyObject baClass, IRubyObject size) {
80
+ throw state.runtime.newTypeError("ByteArray cannot be created via allocate()");
81
+ }
82
+
83
+ @JRubyMethod(name = {"new", "allocate_sized"}, meta = true)
84
+ public static IRubyObject allocate_sized(ThreadContext state, IRubyObject baClass, IRubyObject bytes) {
85
+ long size = bytes.convertToInteger().getLongValue();
86
+ if(size < 0) {
87
+ RubiniusLibrary.argument_error(state, "negative byte array size");
88
+ } else if (size > Integer.MAX_VALUE) {
89
+ RubiniusLibrary.argument_error(state, "too large byte array size");
90
+ }
91
+ return RubiniusByteArray.create(state, (int)size);
92
+ }
93
+
94
+ @JRubyMethod
95
+ public IRubyObject fetch_bytes(ThreadContext state, IRubyObject start, IRubyObject count) {
96
+ long src = start.convertToInteger().getLongValue();
97
+ long cnt = count.convertToInteger().getLongValue();
98
+
99
+ if (src < 0) {
100
+ RubiniusLibrary.object_bounds_exceeded_error(state, "start less than zero");
101
+ } else if (cnt < 0) {
102
+ RubiniusLibrary.object_bounds_exceeded_error(state, "count less than zero");
103
+ } else if ((src + cnt) > size()) {
104
+ RubiniusLibrary.object_bounds_exceeded_error(state, "fetch is more than available bytes");
105
+ }
106
+
107
+ RubiniusByteArray ba = RubiniusByteArray.create(state, (int) cnt + 1);
108
+ System.arraycopy(this.bytes, (int) src, ba.bytes, 0, (int) cnt);
109
+ ba.bytes[(int) cnt] = 0;
110
+
111
+ return ba;
112
+ }
113
+
114
+ @JRubyMethod
115
+ public IRubyObject move_bytes(ThreadContext state, IRubyObject start, IRubyObject count, IRubyObject dest) {
116
+ long src = start.convertToInteger().getLongValue();
117
+ long cnt = count.convertToInteger().getLongValue();
118
+ long dst = dest.convertToInteger().getLongValue();
119
+
120
+ if (src < 0) {
121
+ RubiniusLibrary.object_bounds_exceeded_error(state, "start less than zero");
122
+ } else if (dst < 0) {
123
+ RubiniusLibrary.object_bounds_exceeded_error(state, "dest less than zero");
124
+ } else if (cnt < 0) {
125
+ RubiniusLibrary.object_bounds_exceeded_error(state, "count less than zero");
126
+ } else if ((dst + cnt) > size()) {
127
+ RubiniusLibrary.object_bounds_exceeded_error(state, "move is beyond end of bytearray");
128
+ } else if ((src + cnt) > size()) {
129
+ RubiniusLibrary.object_bounds_exceeded_error(state, "move is more than available bytes");
130
+ }
131
+
132
+ System.arraycopy(this.bytes, (int) src, this.bytes, (int) dst, (int) cnt);
133
+
134
+ return count;
135
+ }
136
+
137
+ @JRubyMethod
138
+ public IRubyObject get_byte(ThreadContext state, IRubyObject index) {
139
+ long idx = index.convertToInteger().getLongValue();
140
+
141
+ if (idx < 0 || idx >= size()) {
142
+ RubiniusLibrary.object_bounds_exceeded_error(state, "index out of bounds");
143
+ }
144
+
145
+ return RubyFixnum.newFixnum(state.runtime, this.bytes[(int) idx]);
146
+ }
147
+
148
+ @JRubyMethod
149
+ public IRubyObject set_byte(ThreadContext state, IRubyObject index, IRubyObject value) {
150
+ long idx = index.convertToInteger().getLongValue();
151
+
152
+ if (idx < 0 || idx >= size()) {
153
+ RubiniusLibrary.object_bounds_exceeded_error(state, "index out of bounds");
154
+ }
155
+
156
+ this.bytes[(int) idx] = (byte) value.convertToInteger().getLongValue();
157
+ return RubyFixnum.newFixnum(state.runtime, this.bytes[(int) idx]);
158
+ }
159
+
160
+ @JRubyMethod
161
+ public IRubyObject compare_bytes(ThreadContext state, IRubyObject _other, IRubyObject a, IRubyObject b) {
162
+ RubiniusByteArray other = (RubiniusByteArray) _other;
163
+ long slim = a.convertToInteger().getLongValue();
164
+ long olim = b.convertToInteger().getLongValue();
165
+
166
+ if (slim < 0) {
167
+ RubiniusLibrary.object_bounds_exceeded_error(state,
168
+ "bytes of self to compare is less than zero");
169
+ } else if (olim < 0) {
170
+ RubiniusLibrary.object_bounds_exceeded_error(state,
171
+ "bytes of other to compare is less than zero");
172
+ }
173
+
174
+ // clamp limits to actual sizes
175
+ long m = size() < slim ? size() : slim;
176
+ long n = other.size() < olim ? other.size() : olim;
177
+
178
+ // only compare the shortest string
179
+ long len = m < n ? m : n;
180
+
181
+ long cmp = ByteList.memcmp(this.bytes, 0, other.bytes, 0, (int) len);
182
+
183
+ // even if substrings are equal, check actual requested limits
184
+ // of comparison e.g. "xyz", "xyzZ"
185
+ if (cmp == 0) {
186
+ if (m < n) {
187
+ return RubyFixnum.minus_one(state.runtime);
188
+ } else if (m > n) {
189
+ return RubyFixnum.one(state.runtime);
190
+ } else {
191
+ return RubyFixnum.zero(state.runtime);
192
+ }
193
+ } else {
194
+ return cmp < 0 ? RubyFixnum.minus_one(state.runtime) : RubyFixnum.one(state.runtime);
195
+ }
196
+ }
197
+
198
+ @JRubyMethod
199
+ public IRubyObject size(ThreadContext state) {
200
+ return RubyFixnum.newFixnum(state.runtime, bytes.length);
201
+ }
202
+
203
+ @JRubyMethod
204
+ public IRubyObject dup() {
205
+ return super.dup();
206
+ }
207
+
208
+ @JRubyMethod
209
+ public IRubyObject locate(ThreadContext state, IRubyObject pattern, IRubyObject start, IRubyObject max_o) {
210
+ byte[] pat = pattern.convertToString().getByteList().bytes();
211
+ int len = pat.length;
212
+ long max = max_o.convertToInteger().getLongValue();
213
+
214
+ if (len == 0) {
215
+ return start;
216
+ }
217
+
218
+ if (max == 0 || max > size()) {
219
+ max = size();
220
+ }
221
+
222
+ max -= (len - 1);
223
+
224
+ for (int i = (int) start.convertToInteger().getLongValue(); i < max; i++) {
225
+ if (this.bytes[i] == pat[0]) {
226
+ int j;
227
+ // match the rest of the pattern string
228
+ for (j = 1; j < len; j++) {
229
+ if (this.bytes[i + j] != pat[j]) {
230
+ break;
231
+ }
232
+ }
233
+
234
+ // if the full pattern matched, return the index
235
+ // of the end of the pattern in 'this'.
236
+ if (j == len) {
237
+ return RubyFixnum.newFixnum(state.runtime, i + len);
238
+ }
239
+ }
240
+ }
241
+
242
+ return state.nil;
243
+ }
244
+
245
+ @JRubyMethod
246
+ public IRubyObject prepend(ThreadContext state, IRubyObject _str) {
247
+ RubyString str = _str.convertToString();
248
+ RubiniusByteArray ba = RubiniusByteArray.create(state, size() + str.size());
249
+
250
+ System.arraycopy(str.getByteList().unsafeBytes(), str.getByteList().getBegin(), ba.bytes, 0, str.size());
251
+ System.arraycopy(bytes, 0, ba.bytes, str.size(), size());
252
+
253
+ return ba;
254
+ }
255
+
256
+ @JRubyMethod
257
+ public IRubyObject utf8_char(ThreadContext state, IRubyObject offset) {
258
+ // not sure what this is supposed to return or best way to get it in JRuby yet
259
+ throw state.runtime.newNotImplementedError("ByteArray#utf8_char not implemented");
260
+ }
261
+
262
+ @JRubyMethod
263
+ public IRubyObject reverse(ThreadContext state, IRubyObject o_start, IRubyObject o_total) {
264
+ long start = o_start.convertToInteger().getLongValue();
265
+ long total = o_total.convertToInteger().getLongValue();
266
+
267
+ if (total <= 0 || start < 0 || start >= size()) {
268
+ return this;
269
+ }
270
+
271
+ int pos1 = (int) start;
272
+ int pos2 = (int) total - 1;
273
+ byte tmp;
274
+
275
+ while (pos1 < pos2) {
276
+ tmp = bytes[pos1];
277
+ bytes[pos1++] = bytes[pos2];
278
+ bytes[pos2--] = tmp;
279
+ }
280
+
281
+ return this;
282
+ }
283
+
284
+ public static class RubiniusString {
285
+ @JRubyMethod
286
+ public static IRubyObject data(ThreadContext context, IRubyObject string) {
287
+ return new RubiniusByteArray(context.runtime, ((RubyString)string).getByteList().getUnsafeBytes());
288
+ }
289
+ }
290
+ }