Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Clean Array by using a Reflector (simple mirror)

Array left it's guts exposed to deal with the way that data has to be
exposed in ruby. To clean things up, I've introduce a Reflector class
which is a simple mirror. This can easily access the internal data of an
object. Additionally, rather than using instance_variable_[get|set] the
JIT can make access quite fast because it doesn't have to deal with any
edgecases.
  • Loading branch information...
commit 0b96773469c0bb174d98e8de470c3bddcf34856b 1 parent 2dd95c3
@evanphx evanphx authored
View
3  kernel/bootstrap/array.rb
@@ -1,8 +1,7 @@
# -*- encoding: us-ascii -*-
class Array
- attr_accessor :tuple
- attr_accessor :start
+ attr_reader :tuple
attr_reader_specific :total, :size
alias_method :length, :size
View
8 kernel/bootstrap/array18.rb
@@ -5,21 +5,19 @@ class Array
# each element in self to the supplied block.
def map
return dup unless block_given?
- out = Array.new size
+ tup = Rubinius::Tuple.new size
i = @start
total = i + @total
tuple = @tuple
- out_tuple = out.tuple
-
j = 0
while i < total
- out_tuple[j] = yield tuple.at(i)
+ tup[j] = yield tuple.at(i)
i += 1
j += 1
end
- out
+ Array.wrap tup, size
end
end
View
8 kernel/bootstrap/array19.rb
@@ -5,21 +5,19 @@ class Array
# each element in self to the supplied block.
def map
return to_enum :map unless block_given?
- out = Array.new size
+ out = Rubinius::Tuple.new size
i = @start
total = i + @total
tuple = @tuple
- out_tuple = out.tuple
-
j = 0
while i < total
- out_tuple[j] = yield tuple.at(i)
+ out[j] = yield tuple.at(i)
i += 1
j += 1
end
- out
+ Array.wrap out, size
end
end
View
1  kernel/bootstrap/load_order18.txt
@@ -29,6 +29,7 @@ process.rbc
regexp.rbc
rubinius.rbc
constant_scope.rbc
+reflector.rbc
string.rbc
symbol.rbc
thread.rbc
View
1  kernel/bootstrap/load_order19.txt
@@ -32,6 +32,7 @@ regexp.rbc
regexp19.rbc
rubinius.rbc
constant_scope.rbc
+reflector.rbc
string.rbc
string19.rbc
symbol.rbc
View
19 kernel/bootstrap/reflector.rb
@@ -0,0 +1,19 @@
+module Rubinius
+ class Reflector
+
+ def self.new(target)
+ Rubinius.primitive :reflector_create
+ raise PrimitiveFailure, "Reflector.new failed"
+ end
+
+ def get(ivar)
+ Rubinius.primitive :reflector_get
+ raise PrimitiveFailure, "Reflector#get failed"
+ end
+
+ def set(ivar, name)
+ Rubinius.primitive :reflector_set
+ raise TypeError, "'#{name}' is not a ivar name"
+ end
+ end
+end
View
24 kernel/common/array.rb
@@ -34,8 +34,10 @@ def initialize(size_or_array=undefined, obj=undefined)
if size_or_array.respond_to? :to_ary
ary = Rubinius::Type.coerce_to size_or_array, Array, :to_ary
- @tuple = ary.tuple.dup
- @start = ary.start
+ ref = Rubinius::Reflector.new ary
+
+ @tuple = ref.get(:@tuple).dup
+ @start = ref.get :@start
@total = ary.size
return self
@@ -70,9 +72,11 @@ def replace(other)
other = Rubinius::Type.coerce_to other, Array, :to_ary
- @tuple = other.tuple.dup
+ ref = Rubinius::Reflector.new other
+
+ @tuple = ref.get(:@tuple).dup
+ @start = ref.get(:@start)
@total = other.size
- @start = other.start
Rubinius::Type.infect(self, other)
self
@@ -249,11 +253,13 @@ def ==(other)
return false unless size == other.size
Thread.detect_recursion self, other do
+ ref = Rubinius::Reflector.new other
+
md = @tuple
- od = other.tuple
+ od = ref.get :@tuple
i = @start
- j = other.start
+ j = ref.get :@start
total = i + @total
@@ -1077,9 +1083,11 @@ def recursively_flatten(array, out, max_levels = -1)
max_levels -= 1
recursion = Thread.detect_recursion(array) do
- i = array.start
+ ref = Rubinius::Reflector.new array
+
+ i = ref.get :@start
total = i + array.size
- tuple = array.tuple
+ tuple = ref.get :@tuple
while i < total
o = tuple.at i
View
35 kernel/common/array18.rb
@@ -122,7 +122,8 @@ def set_index(index, ent, fin=undefined)
when 0
# nothing
else
- new_tuple.copy_from(replacement.tuple, replacement.start,
+ ref = Rubinius::Reflector.new replacement
+ new_tuple.copy_from(ref.get(:@tuple), ref.get(:@start),
replace_count, index)
end
@@ -150,7 +151,8 @@ def set_index(index, ent, fin=undefined)
when 0
# nothing
else
- @tuple.copy_from(replacement.tuple, replacement.start,
+ ref = Rubinius::Reflector.new replacement
+ @tuple.copy_from(ref.get(:@tuple), ref.get(:@start),
replace_count, @start + index)
end
@@ -466,8 +468,11 @@ def uniq!
Rubinius.check_frozen
array = im.to_array
- @tuple = array.tuple
- @start = array.start
+
+ ref = Rubinius::Reflector.new array
+
+ @tuple = ref.get :@tuple
+ @start = ref.get :@start
@total = array.size
self
@@ -496,19 +501,27 @@ def unshift(*values)
Rubinius.check_frozen
- if @start > values.size
+ sz = values.size
+
+ if @start > sz
# fit the new values in between 0 and @start if possible
- @start -= values.size
- @tuple.copy_from(values.tuple, 0, values.size, @start)
+ @start -= sz
+ if sz == 1
+ @tuple.put @start, values.at(0)
+ else
+ ref = Rubinius::Reflector.new values
+ @tuple.copy_from(ref.get(:@tuple), 0, sz, @start)
+ end
else
- new_tuple = Rubinius::Tuple.new @total + values.size
- new_tuple.copy_from values.tuple, 0, values.size, 0
- new_tuple.copy_from @tuple, @start, @total, values.size
+ ref = Rubinius::Reflector.new values
+ new_tuple = Rubinius::Tuple.new @total + sz
+ new_tuple.copy_from ref.get(:@tuple), 0, sz, 0
+ new_tuple.copy_from @tuple, @start, @total, sz
@start = 0
@tuple = new_tuple
end
- @total += values.size
+ @total += sz
self
end
end
View
42 kernel/common/array19.rb
@@ -97,7 +97,9 @@ def set_index(index, ent, fin=undefined)
when 0
# nothing
else
- new_tuple.copy_from(replacement.tuple, replacement.start,
+ ref = Rubinius::Reflector.new replacement
+
+ new_tuple.copy_from(ref.get(:@tuple), ref.get(:@start),
replace_count, index)
end
@@ -125,7 +127,9 @@ def set_index(index, ent, fin=undefined)
when 0
# nothing
else
- @tuple.copy_from(replacement.tuple, replacement.start,
+ ref = Rubinius::Reflector.new(replacement)
+
+ @tuple.copy_from(ref.get(:@tuple), ref.get(:@start),
replace_count, @start + index)
end
@@ -461,11 +465,14 @@ def sample(*args)
return at(random_generator.rand(size)) unless n
n = size if n > size
+
result = Array.new(self)
+ ref = Rubinius::Reflector.new(result)
+ tuple = ref.get(:@tuple)
n.times do |i|
r = i + random_generator.rand(size - i)
- result.tuple.swap(i, r)
+ tuple.swap(i, r)
end
result[n..size] = []
@@ -629,8 +636,11 @@ def uniq!(&block)
return if im.size == size
array = im.to_array
- @tuple = array.tuple
- @start = array.start
+
+ ref = Rubinius::Reflector.new array
+
+ @tuple = ref.get(:@tuple)
+ @start = ref.get(:@start)
@total = array.size
self
@@ -667,19 +677,27 @@ def unshift(*values)
return self if values.empty?
- if @start > values.size
+ sz = values.size
+
+ if @start > sz
# fit the new values in between 0 and @start if possible
- @start -= values.size
- @tuple.copy_from(values.tuple, 0, values.size, @start)
+ @start -= sz
+ if sz == 1
+ @tuple.put @start, values.at(0)
+ else
+ ref = Rubinius::Reflector.new values
+ @tuple.copy_from(ref.get(:@tuple), 0, sz, @start)
+ end
else
- new_tuple = Rubinius::Tuple.new @total + values.size
- new_tuple.copy_from values.tuple, 0, values.size, 0
- new_tuple.copy_from @tuple, @start, @total, values.size
+ ref = Rubinius::Reflector.new values
+ new_tuple = Rubinius::Tuple.new @total + sz
+ new_tuple.copy_from ref.get(:@tuple), 0, sz, 0
+ new_tuple.copy_from @tuple, @start, @total, sz
@start = 0
@tuple = new_tuple
end
- @total += values.size
+ @total += sz
self
end
end
View
7 kernel/common/tuple.rb
@@ -13,9 +13,12 @@ class Tuple
include Enumerable
def self.[](*args)
- start = args.start
+ ref = Rubinius::Reflector.new args
+ start = ref.get(:@start)
+ tuple = ref.get(:@tuple)
+
tot = args.size
- return new(tot).copy_from(args.tuple, start, tot, 0)
+ return new(tot).copy_from(tuple, start, tot, 0)
end
def to_s
View
1  rakelib/vm.rake
@@ -110,6 +110,7 @@ field_extract_headers = %w[
vm/builtin/cache.hpp
vm/builtin/atomic.hpp
vm/builtin/character.hpp
+ vm/builtin/reflector.hpp
]
transcoders_src_dir = File.expand_path "../../vendor/oniguruma/enc/trans", __FILE__
View
41 vm/builtin/reflector.cpp
@@ -0,0 +1,41 @@
+#include "vm.hpp"
+#include "vm/object_utils.hpp"
+
+#include "builtin/object.hpp"
+
+#include "builtin/reflector.hpp"
+
+#include "ontology.hpp"
+#include "builtin/class.hpp"
+#include "builtin/symbol.hpp"
+#include "primitives.hpp"
+
+namespace rubinius {
+ void Reflector::init(STATE) {
+ GO(reflector).set(ontology::new_class(state, "Reflector",
+ G(object), G(rubinius)));
+ G(reflector)->set_object_type(state, Reflector::type);
+ }
+
+ Reflector* Reflector::create(STATE, Object* target) {
+ Reflector* ref = state->new_object<Reflector>(G(reflector));
+ ref->target(state, target);
+ return ref;
+ }
+
+ Object* Reflector::get(STATE, Symbol* name) {
+ if(name->is_ivar_p(state)->false_p()) return cNil;
+ return target_->get_ivar(state, name);
+ }
+
+ Object* Reflector::set(STATE, Symbol* name, Object* val) {
+ if(name->is_ivar_p(state)->false_p()) {
+ return Primitives::failure();
+ }
+
+ target_->check_frozen(state);
+ target_->set_ivar(state, name, val);
+
+ return val;
+ }
+}
View
36 vm/builtin/reflector.hpp
@@ -0,0 +1,36 @@
+#ifndef RBX_BUILTIN_REFLECTOR_HPP
+#define RBX_BUILTIN_REFLECTOR_HPP
+
+#include "builtin/object.hpp"
+#include "type_info.hpp"
+
+#include "virtual.hpp" // ObjectCallback
+#include "gc/root.hpp" // TypedRoot
+
+#include "builtin/thread.hpp"
+
+namespace rubinius {
+ class Reflector : public Object {
+ public:
+ static void init(STATE);
+
+ const static object_type type = ReflectorType;
+
+ private:
+ Object* target_;
+
+ public:
+ attr_accessor(target, Object);
+
+ // Rubinius.primitive :reflector_create
+ static Reflector* create(STATE, Object* obj);
+
+ // Rubinius.primitive :reflector_get
+ Object* get(STATE, Symbol* name);
+
+ // Rubinius.primitive :reflector_set
+ Object* set(STATE, Symbol* name, Object* val);
+ };
+}
+
+#endif
View
4 vm/globals.hpp
@@ -113,6 +113,7 @@ namespace rubinius {
TypedRoot<Module*> type;
TypedRoot<Class*> vm_class;
TypedRoot<Class*> atomic_ref;
+ TypedRoot<Class*> reflector;
/* Add new globals above this line. */
@@ -223,7 +224,8 @@ namespace rubinius {
encoding(&roots),
type(&roots),
vm_class(&roots),
- atomic_ref(&roots)
+ atomic_ref(&roots),
+ reflector(&roots)
/* Add initialize of globals above this line. */
{ }
View
3  vm/ontology.cpp
@@ -51,6 +51,7 @@
#include "builtin/module.hpp"
#include "builtin/class.hpp"
#include "builtin/atomic.hpp"
+#include "builtin/reflector.hpp"
#include "environment.hpp"
#include "configuration.hpp"
@@ -338,6 +339,8 @@ namespace rubinius {
Encoding::init(state);
kcode::init(state);
+
+ Reflector::init(state);
}
// @todo document all the sections of bootstrap_ontology
Please sign in to comment.
Something went wrong with that request. Please try again.