rubinius-core-api 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }