From de7e032169eeea0498395fc7c0325290843e304e Mon Sep 17 00:00:00 2001 From: merryman Date: Thu, 21 Mar 2013 15:21:21 +0100 Subject: [PATCH 01/37] Implemented numeric_arrays, tests pass, translation wont. --- tests/objects/test_arrayobject.py | 11 + tests/objects/test_rangeobject.py | 6 + topaz/objects/arrayobject.py | 368 +++++++++++++++++++++++------- topaz/objects/rangeobject.py | 7 + topaz/objspace.py | 17 +- 5 files changed, 318 insertions(+), 91 deletions(-) diff --git a/tests/objects/test_arrayobject.py b/tests/objects/test_arrayobject.py index 0a8fd2afa..a6a79eee7 100644 --- a/tests/objects/test_arrayobject.py +++ b/tests/objects/test_arrayobject.py @@ -202,6 +202,17 @@ def test_dup(self, space): x, y = self.unwrap(space, w_res) assert x == [1, 2, 3, 4] assert y == [1, 2, 3] + + def test_dupf(self, space): + w_res = space.execute(""" + x = [1.0, 2.0, 3.0] + y = x.dup + x << 4 + return [x, y] + """) + x, y = self.unwrap(space, w_res) + assert x == [1.0, 2.0, 3.0, 4] + assert y == [1.0, 2.0, 3.0] def test_compact(self, space): w_res = space.execute("return ['a', nil, 'b', nil, 'c'].compact") diff --git a/tests/objects/test_rangeobject.py b/tests/objects/test_rangeobject.py index 6b4dd8abb..54d7d718a 100644 --- a/tests/objects/test_rangeobject.py +++ b/tests/objects/test_rangeobject.py @@ -86,3 +86,9 @@ def test_each_returns_self(self, space): return r.each {}.equal?(r) """) assert w_res is space.w_true + + def test_array_conversion(self, space): + w_res = space.execute(""" + return (1..4).to_a + """) + assert self.unwrap(space, w_res) == [1,2,3,4] diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 40b8123b1..53a8d9b7e 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -1,13 +1,15 @@ import copy from rpython.rlib.listsort import TimSort +from rpython.rlib.rerased import new_static_erasing_pair from topaz.coerce import Coerce from topaz.module import ClassDef, check_frozen from topaz.modules.enumerable import Enumerable from topaz.objects.objectobject import W_Object from topaz.utils.packing.pack import RPacker - +from topaz.objects.floatobject import W_FloatObject +from topaz.objects.intobject import W_FixnumObject class RubySorter(TimSort): def __init__(self, space, list, listlength=None, sortblock=None): @@ -27,23 +29,249 @@ def lt(self, a, b): ) else: return self.space.int_w(w_cmp_res) < 0 + +class IntSorter(RubySorter): + def lt(self, a, b): + if self.sortblock is None: + return a < b + else: + w_cmp_res = self.space.invoke_block(self.sortblock, + [self.space.newint(a), + self.space.newint(b)]) + if w_cmp_res is self.space.w_nil: + raise self.space.error( + self.space.w_ArgumentError, + "comparison of %s with %s failed" % (self.space.getclass(a).name, + self.space.getclass(b).name) + ) + else: + return self.space.int_w(w_cmp_res) < 0 +class FloatSorter(RubySorter): + def lt(self, a, b): + if self.sortblock is None: + return a < b + else: + w_cmp_res = self.space.invoke_block(self.sortblock, + [self.space.newfloat(a), + self.space.newfloat(b)]) + if w_cmp_res is self.space.w_nil: + raise self.space.error( + self.space.w_ArgumentError, + "comparison of %s with %s failed" % (self.space.getclass(a).name, + self.space.getclass(b).name) + ) + else: + return self.space.int_w(w_cmp_res) < 0 + +class ArrayStrategy(object): + + def __init__(self, space): + pass + + def __deepcopy__(self, memo): + memo[id(self)] = result = object.__new__(self.__class__) + return result + +class ArrayStrategyMixin(object): + + _mixin_ = True + + def length(self, a): + return len(self.unerase(a.array_storage)) + + def range_assign(self, space, a, start, end, w_obj): + assert end >= 0 + strategy = self + w_converted = space.convert_type(w_obj, space.w_array, "to_ary", raise_error=False) + if w_converted is space.w_nil: + rep_w = [w_obj] + self.verify_strategy(space, a, w_obj) + else: + rep_w = space.listview(w_converted) + for each in rep_w: + self.verify_strategy(space, a, each) + delta = (end - start) - len(rep_w) + storage = a.strategy.unerase(a.array_storage) + if delta < 0: + storage += [None] * -delta + lim = start + len(rep_w) + i = len(storage) - 1 + while i >= lim: + storage[i] = storage[i + delta] + i -= 1 + elif delta > 0: + del storage[start:start + delta] + storage[start:start + len(rep_w)] = [a.strategy.unwrap(space, r) for r in rep_w] + return strategy + + def slice(self, space, a, start, end): + return space.newarray(self.listview(space, a)[start:end]) + + def slice_i(self, space, a, start, end, as_range, nil): + if nil: + return space.w_nil + elif as_range: + start = min(max(start, 0), self.length(a)) + end = min(max(end, 0), self.length(a)) + delta = (end - start) + assert delta >= 0 + w_items = self.listview(space, a)[start:start + delta] + del self.unerase(a.array_storage)[start:start + delta] + return space.newarray(w_items) + else: + storage = self.unerase(a.array_storage) + w_item = storage[start] + del storage[start] + return w_item + + def shift(self, space, a, n): + if n < 0: + raise space.error(space.w_ArgumentError, "negative array size") + items_w = self.listview(space, a)[:n] + del self.unerase(a.array_storage)[:n] + return space.newarray(items_w) + + def clear(self, space, a): + del self.unerase(a.array_storage)[:] + + def pop_n(self, space, a, num): + pop_size = max(0, self.length(a) - num) + res_w = self.listview(space, a)[pop_size:] + del self.unerase(a.array_storage)[pop_size:] + return space.newarray(res_w) + + def replace(self, space, a, other_w): + for o in other_w: + if not self.checktype(o): + a.strategy = space.fromcache(ObjectArrayStrategy) + a.array_storage = a.strategy.store(space, other_w) + return + a.array_store = self.store(space, other_w) + + def verify_strategy(self, space, a, w_obj): + if not self.checktype(w_obj): + a.strategy = space.fromcache(ObjectArrayStrategy) + a.array_storage = a.strategy.erase(self.listview(space, a)) + + def store(self, space, items_w): + return self.erase([self.unwrap(space, o) for o in items_w]) + + def get_item(self, space, a, idx): + return self.wrap(space, self.unerase(a.array_storage)[idx]) + + def set_item(self, space, a, idx, w_obj): + self.verify_strategy(space, a, w_obj) + if self.checktype(w_obj): + self.unerase(a.array_storage)[idx] = self.unwrap(space, w_obj) + else: + a.strategy.unerase(a.array_storage)[idx] = a.strategy.unwrap(space, w_obj) + + def listview(self, space, a): + return [self.wrap(space, o) for o in self.unerase(a.array_storage)] + + def extend(self, space, a, other_w): + for o in other_w: + if not self.checktype(o): + a.strategy = space.fromcache(ObjectArrayStrategy) + a.array_storage = a.strategy.erase(self.listview(space, a)) + a.strategy.unerase(a.array_storage).extend(other_w) + return + self.unerase(a.array_storage).extend([self.unwrap(space, o) for o in other_w]) + + def append(self, space, a, w_obj): + self.verify_strategy(space, a, w_obj) + if self.checktype(w_obj): + self.unerase(a.array_storage).append(self.unwrap(space, w_obj)) + else: + a.strategy.unerase(a.array_storage).append(a.strategy.unwrap(space, w_obj)) + + def pop(self, space, a, idx): + storage = self.unerase(a.array_storage) + if storage: + return self.wrap(space, storage.pop(idx)) + else: + return space.w_nil + + def insert(self, space, a, idx, w_obj): + self.verify_strategy(space, a, w_obj) + if self.checktype(w_obj): + self.unerase(a.array_storage).insert(idx, self.unwrap(space, w_obj)) + else: + assert isinstance(a.strategy, ObjectArrayStrategy) + a.strategy.unerase(a.array_storage).insert(idx, a.strategy.unwrap(space, w_obj)) + +class ObjectArrayStrategy(ArrayStrategyMixin, ArrayStrategy): + + erase, unerase = new_static_erasing_pair("object") + + def verify_strategy(self, space, a, w_obj): + pass + + def wrap(self, space, w_obj): + return w_obj + + def unwrap(self, space, w_obj): + return w_obj + + def checktype(self, w_obj): + return True + + def sort(self, space, a, block): + RubySorter(space, self.unerase(a.array_storage), sortblock=block).sort() + +class FloatArrayStrategy(ArrayStrategyMixin, ArrayStrategy): + + erase, unerase = new_static_erasing_pair("float") + + def wrap(self, space, f): + return space.newfloat(f) + + def unwrap(self, space, w_f): + return space.float_w(w_f) + + def checktype(self, w_obj): + return isinstance(w_obj, W_FloatObject) + + def sort(self, space, a, block): + FloatSorter(space, self.unerase(a.array_storage), sortblock=block).sort() + +class FixnumArrayStrategy(ArrayStrategyMixin, ArrayStrategy): + + erase, unerase = new_static_erasing_pair("fixnum") + + def wrap(self, space, i): + return space.newint(i) + + def unwrap(self, space, w_i): + return space.int_w(w_i) + + def checktype(self, w_obj): + return isinstance(w_obj, W_FixnumObject) + + def sort(self, space, a, block): + IntSorter(space, self.unerase(a.array_storage), sortblock=block).sort() class W_ArrayObject(W_Object): classdef = ClassDef("Array", W_Object.classdef, filepath=__file__) classdef.include_module(Enumerable) - def __init__(self, space, items_w): + def __init__(self, space, strategy, items_w): W_Object.__init__(self, space) - self.items_w = items_w + self.strategy = strategy + self.array_storage = self.strategy.store(space, items_w) def __deepcopy__(self, memo): obj = super(W_ArrayObject, self).__deepcopy__(memo) - obj.items_w = copy.deepcopy(self.items_w, memo) + obj.strategy = copy.deepcopy(self.strategy, memo) + obj.array_storage = copy.deepcopy(self.array_storage, memo) return obj def listview(self, space): - return self.items_w + return self.strategy.listview(space, self) + + def length(self): + return self.strategy.length(self) @classdef.singleton_method("allocate") def singleton_method_allocate(self, space, args_w): @@ -57,23 +285,22 @@ def singleton_method_subscript(self, space, args_w): @classdef.method("replace", other_w="array") @check_frozen() def method_replace(self, space, other_w): - del self.items_w[:] - self.items_w.extend(other_w) + self.strategy.replace(space, self, other_w) return self @classdef.method("at") @classdef.method("[]") @classdef.method("slice") - def method_subscript(self, space, w_idx, w_count=None): - start, end, as_range, nil = space.subscript_access(len(self.items_w), w_idx, w_count=w_count) + def subscript(self, space, w_idx, w_count=None): + start, end, as_range, nil = space.subscript_access(self.length(), w_idx, w_count=w_count) if nil: return space.w_nil elif as_range: assert start >= 0 assert end >= 0 - return space.newarray(self.items_w[start:end]) + return self.strategy.slice(space, self, start, end) else: - return self.items_w[start] + return self.strategy.get_item(space, self, start) @classdef.method("[]=") def method_subscript_assign(self, space, w_idx, w_count_or_obj, w_obj=None): @@ -82,7 +309,7 @@ def method_subscript_assign(self, space, w_idx, w_count_or_obj, w_obj=None): w_count = w_count_or_obj else: w_obj = w_count_or_obj - start, end, as_range, nil = space.subscript_access(len(self.items_w), w_idx, w_count=w_count) + start, end, as_range, nil = space.subscript_access(self.length(), w_idx, w_count=w_count) if w_count and end < start: raise space.error(space.w_IndexError, @@ -91,112 +318,76 @@ def method_subscript_assign(self, space, w_idx, w_count_or_obj, w_obj=None): elif start < 0: raise space.error(space.w_IndexError, "index %d too small for array; minimum: %d" % ( - start - len(self.items_w), - -len(self.items_w) + start - self.length(), + -self.length() ) ) - elif start >= len(self.items_w): - self.items_w += [space.w_nil] * (start - len(self.items_w) + 1) - self.items_w[start] = w_obj + elif start >= self.length(): + self.strategy.extend(space, self, + [space.w_nil] * (start - self.length() + 1)) + self.strategy.set_item(space, self, start, w_obj) elif as_range: - assert end >= 0 - w_converted = space.convert_type(w_obj, space.w_array, "to_ary", raise_error=False) - if w_converted is space.w_nil: - rep_w = [w_obj] - else: - rep_w = space.listview(w_converted) - delta = (end - start) - len(rep_w) - if delta < 0: - self.items_w += [None] * -delta - lim = start + len(rep_w) - i = len(self.items_w) - 1 - while i >= lim: - self.items_w[i] = self.items_w[i + delta] - i -= 1 - elif delta > 0: - del self.items_w[start:start + delta] - self.items_w[start:start + len(rep_w)] = rep_w + self.strategy.range_assign(space, self, start, end, w_obj) else: - self.items_w[start] = w_obj + self.strategy.set_item(space, self, start, w_obj) return w_obj @classdef.method("slice!") @check_frozen() def method_slice_i(self, space, w_idx, w_count=None): - start, end, as_range, nil = space.subscript_access(len(self.items_w), w_idx, w_count=w_count) - - if nil: - return space.w_nil - elif as_range: - start = min(max(start, 0), len(self.items_w)) - end = min(max(end, 0), len(self.items_w)) - delta = (end - start) - assert delta >= 0 - w_items = self.items_w[start:start + delta] - del self.items_w[start:start + delta] - return space.newarray(w_items) - else: - w_item = self.items_w[start] - del self.items_w[start] - return w_item + start, end, as_range, nil = space.subscript_access(self.length(), w_idx, w_count=w_count) + return self.strategy.slice_i(space, self, start, end, as_range, nil) @classdef.method("size") @classdef.method("length") def method_length(self, space): - return space.newint(len(self.items_w)) + return space.newint(self.length()) @classdef.method("empty?") def method_emptyp(self, space): - return space.newbool(len(self.items_w) == 0) + return space.newbool(self.length() == 0) @classdef.method("+", other="array") def method_add(self, space, other): - return space.newarray(self.items_w + other) + return space.newarray(self.listview(space) + other) @classdef.method("<<") @check_frozen() def method_lshift(self, space, w_obj): - self.items_w.append(w_obj) + self.strategy.append(space, self, w_obj) return self @classdef.method("concat", other="array") @check_frozen() def method_concat(self, space, other): - self.items_w += other + self.strategy.extend(space, self, other) return self @classdef.method("push") @check_frozen() - def method_push(self, space, args_w): - self.items_w.extend(args_w) + def method_concat(self, space, args_w): + self.strategy.extend(space, self, args_w) return self @classdef.method("shift") @check_frozen() def method_shift(self, space, w_n=None): if w_n is None: - if self.items_w: - return self.items_w.pop(0) - else: - return space.w_nil + return self.strategy.pop(space, self, 0) n = space.int_w(space.convert_type(w_n, space.w_fixnum, "to_int")) - if n < 0: - raise space.error(space.w_ArgumentError, "negative array size") - items_w = self.items_w[:n] - del self.items_w[:n] - return space.newarray(items_w) + return self.strategy.shift(space, self, n) @classdef.method("unshift") @check_frozen() - def method_unshift(self, space, args_w): + def method_unshift(self, space, args_w): for i in xrange(len(args_w) - 1, -1, -1): w_obj = args_w[i] - self.items_w.insert(0, w_obj) + self.strategy.insert(space, self, 0, w_obj) return self @classdef.method("join") def method_join(self, space, w_sep=None): - if not self.items_w: + if not self.listview(space): return space.newstr_fromstr("") if w_sep is None: separator = "" @@ -208,7 +399,7 @@ def method_join(self, space, w_sep=None): ) return space.newstr_fromstr(separator.join([ space.str_w(space.send(w_o, space.newsymbol("to_s"))) - for w_o in self.items_w + for w_o in self.listview(space) ])) @classdef.singleton_method("try_convert") @@ -221,10 +412,7 @@ def method_try_convert(self, space, w_obj): @check_frozen() def method_pop(self, space, w_num=None): if w_num is None: - if self.items_w: - return self.items_w.pop() - else: - return space.w_nil + return self.strategy.pop(space, self, -1) else: num = space.int_w(space.convert_type( w_num, space.w_fixnum, "to_int" @@ -232,20 +420,17 @@ def method_pop(self, space, w_num=None): if num < 0: raise space.error(space.w_ArgumentError, "negative array size") else: - pop_size = max(0, len(self.items_w) - num) - res_w = self.items_w[pop_size:] - del self.items_w[pop_size:] - return space.newarray(res_w) + return self.strategy.pop_n(space, self, num) @classdef.method("delete_at", idx="int") @check_frozen() def method_delete_at(self, space, idx): if idx < 0: - idx += len(self.items_w) - if idx < 0 or idx >= len(self.items_w): + idx += self.length() + if idx < 0 or idx >= self.length(): return space.w_nil else: - return self.items_w.pop(idx) + return self.strategy.pop(space, self, idx) @classdef.method("last") def method_last(self, space, w_count=None): @@ -253,15 +438,15 @@ def method_last(self, space, w_count=None): count = Coerce.int(space, w_count) if count < 0: raise space.error(space.w_ArgumentError, "negative array size") - start = len(self.items_w) - count + start = self.length() - count if start < 0: start = 0 - return space.newarray(self.items_w[start:]) + return space.newarray(self.listview(space)[start:]) - if len(self.items_w) == 0: + if self.length() == 0: return space.w_nil else: - return self.items_w[len(self.items_w) - 1] + return self.listview(space)[self.length() - 1] @classdef.method("pack", template="str") def method_pack(self, space, template): @@ -275,10 +460,17 @@ def method_to_ary(self, space): @classdef.method("clear") @check_frozen() def method_clear(self, space): - del self.items_w[:] + self.strategy.clear(space, self) return self @classdef.method("sort!") def method_sort(self, space, block): - RubySorter(space, self.items_w, sortblock=block).sort() + self.strategy.sort(space, self, block) return self + + @classdef.method("dup") + def method_dup(self, space, block): + # this needs to be here, as the Kernel>>dup + # aparrently can not sucessfully copy arrays + # which are based on this new storage model + return space.newarray(self.listview(space)) diff --git a/topaz/objects/rangeobject.py b/topaz/objects/rangeobject.py index 40c9e7ff9..bace9cb03 100644 --- a/topaz/objects/rangeobject.py +++ b/topaz/objects/rangeobject.py @@ -26,3 +26,10 @@ def method_end(self, space): @classdef.method("exclude_end?") def method_exclude_end(self, space): return space.newbool(self.exclusive) + + @classdef.method("to_a") + def method_to_a(self, space): + start, end = space.int_w(self.w_start), space.int_w(self.w_end) + if not self.exclusive: + end += 1 + return space.newarray([space.newint(i) for i in range(start, end)]) diff --git a/topaz/objspace.py b/topaz/objspace.py index 848878789..d504fcf25 100644 --- a/topaz/objspace.py +++ b/topaz/objspace.py @@ -25,7 +25,7 @@ from topaz.modules.process import Process from topaz.modules.signal import Signal from topaz.modules.topaz import Topaz -from topaz.objects.arrayobject import W_ArrayObject +from topaz.objects.arrayobject import W_ArrayObject, ObjectArrayStrategy, FloatArrayStrategy, FixnumArrayStrategy, ArrayStrategy from topaz.objects.bignumobject import W_BignumObject from topaz.objects.bindingobject import W_BindingObject from topaz.objects.boolobject import W_TrueObject, W_FalseObject @@ -328,7 +328,18 @@ def newstr_fromstrs(self, strs_w): return W_StringObject.newstr_fromstrs(self, strs_w) def newarray(self, items_w): - return W_ArrayObject(self, items_w) + if items_w: + array_type = type(items_w[0]) + for item in items_w: + if not isinstance(item, array_type): + return W_ArrayObject(self, self.fromcache(ObjectArrayStrategy), items_w) + if array_type == W_FixnumObject: + return W_ArrayObject(self, self.fromcache(FixnumArrayStrategy), items_w) + elif array_type == W_FloatObject: + print array_type + return W_ArrayObject(self, self.fromcache(FloatArrayStrategy), items_w) + # unknown type, can not be optimized + return W_ArrayObject(self, self.fromcache(ObjectArrayStrategy), items_w) def newhash(self): return W_HashObject(self) @@ -531,7 +542,7 @@ def invoke_block(self, block, args_w, block_arg=None): isinstance(args_w[0], W_ArrayObject) and len(bc.arg_pos) >= 2): w_arg = args_w[0] assert isinstance(w_arg, W_ArrayObject) - args_w = w_arg.items_w + args_w = w_arg.listview(self) if len(bc.arg_pos) != 0 or bc.splat_arg_pos != -1 or bc.block_arg_pos != -1: frame.handle_block_args(self, bc, args_w, block_arg) assert len(block.cells) == len(bc.freevars) From d881ea02005564ce7a1cc83003bc05023b9817bc Mon Sep 17 00:00:00 2001 From: Toni Mattis Date: Tue, 26 Mar 2013 11:07:09 +0100 Subject: [PATCH 02/37] still not translating --- topaz/objects/arrayobject.py | 41 ++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 53a8d9b7e..c901e1ddf 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -92,6 +92,7 @@ def range_assign(self, space, a, start, end, w_obj): for each in rep_w: self.verify_strategy(space, a, each) delta = (end - start) - len(rep_w) + # storage can be of different array type after strategy is verified -> decorator ? ifs? storage = a.strategy.unerase(a.array_storage) if delta < 0: storage += [None] * -delta @@ -144,18 +145,24 @@ def pop_n(self, space, a, num): def replace(self, space, a, other_w): for o in other_w: if not self.checktype(o): - a.strategy = space.fromcache(ObjectArrayStrategy) - a.array_storage = a.strategy.store(space, other_w) + obj_strategy = space.fromcache(ObjectArrayStrategy) + a.array_storage = obj_strategy.store(space, other_w) + a.strategy = obj_strategy return a.array_store = self.store(space, other_w) def verify_strategy(self, space, a, w_obj): if not self.checktype(w_obj): - a.strategy = space.fromcache(ObjectArrayStrategy) - a.array_storage = a.strategy.erase(self.listview(space, a)) + obj_strategy = space.fromcache(ObjectArrayStrategy) + a.array_storage = obj_strategy.erase(self.listview(space, a)) + a.strategy = obj_strategy def store(self, space, items_w): - return self.erase([self.unwrap(space, o) for o in items_w]) + l = [] + for o in items_w: + assert self.checktype(o) + l.append(self.unwrap(space, o)) + return self.erase(l) def get_item(self, space, a, idx): return self.wrap(space, self.unerase(a.array_storage)[idx]) @@ -165,7 +172,8 @@ def set_item(self, space, a, idx, w_obj): if self.checktype(w_obj): self.unerase(a.array_storage)[idx] = self.unwrap(space, w_obj) else: - a.strategy.unerase(a.array_storage)[idx] = a.strategy.unwrap(space, w_obj) + obj_strategy = space.fromcache(ObjectArrayStrategy) + obj_strategy.unerase(a.array_storage)[idx] = obj_strategy.unwrap(space, w_obj) def listview(self, space, a): return [self.wrap(space, o) for o in self.unerase(a.array_storage)] @@ -173,18 +181,24 @@ def listview(self, space, a): def extend(self, space, a, other_w): for o in other_w: if not self.checktype(o): - a.strategy = space.fromcache(ObjectArrayStrategy) - a.array_storage = a.strategy.erase(self.listview(space, a)) - a.strategy.unerase(a.array_storage).extend(other_w) + obj_strategy = space.fromcache(ObjectArrayStrategy) + a.array_storage = obj_strategy.erase(self.listview(space, a)) + obj_strategy.unerase(a.array_storage).extend(other_w) + a.strategy = obj_strategy return - self.unerase(a.array_storage).extend([self.unwrap(space, o) for o in other_w]) + l = [] + for o in other_w: + assert self.checktype(o) + l.append(self.unwrap(space, o)) + self.unerase(a.array_storage).extend(l) def append(self, space, a, w_obj): self.verify_strategy(space, a, w_obj) if self.checktype(w_obj): self.unerase(a.array_storage).append(self.unwrap(space, w_obj)) else: - a.strategy.unerase(a.array_storage).append(a.strategy.unwrap(space, w_obj)) + obj_strategy = space.fromcache(ObjectArrayStrategy) + obj_strategy.unerase(a.array_storage).append(obj_strategy.unwrap(space, w_obj)) def pop(self, space, a, idx): storage = self.unerase(a.array_storage) @@ -198,8 +212,8 @@ def insert(self, space, a, idx, w_obj): if self.checktype(w_obj): self.unerase(a.array_storage).insert(idx, self.unwrap(space, w_obj)) else: - assert isinstance(a.strategy, ObjectArrayStrategy) - a.strategy.unerase(a.array_storage).insert(idx, a.strategy.unwrap(space, w_obj)) + obj_strategy = space.fromcache(ObjectArrayStrategy) + obj_strategy.unerase(a.array_storage).insert(idx, obj_strategy.unwrap(space, w_obj)) class ObjectArrayStrategy(ArrayStrategyMixin, ArrayStrategy): @@ -241,6 +255,7 @@ class FixnumArrayStrategy(ArrayStrategyMixin, ArrayStrategy): erase, unerase = new_static_erasing_pair("fixnum") def wrap(self, space, i): + assert isinstance(i, int) return space.newint(i) def unwrap(self, space, w_i): From c4a648a78ac9c7d189e75f887cc28c7f5f69ebc4 Mon Sep 17 00:00:00 2001 From: Toni Mattis Date: Tue, 26 Mar 2013 11:21:15 +0100 Subject: [PATCH 03/37] fixed faulty method extraction. --- topaz/objects/arrayobject.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index c901e1ddf..a536dfb5f 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -82,7 +82,6 @@ def length(self, a): def range_assign(self, space, a, start, end, w_obj): assert end >= 0 - strategy = self w_converted = space.convert_type(w_obj, space.w_array, "to_ary", raise_error=False) if w_converted is space.w_nil: rep_w = [w_obj] @@ -93,7 +92,10 @@ def range_assign(self, space, a, start, end, w_obj): self.verify_strategy(space, a, each) delta = (end - start) - len(rep_w) # storage can be of different array type after strategy is verified -> decorator ? ifs? - storage = a.strategy.unerase(a.array_storage) + a.strategy.padd_assign(space, a, delta, start, end, rep_w) + + def padd_assign(self, space, a, delta, start, end, rep_w): + storage = self.unerase(a.array_storage) if delta < 0: storage += [None] * -delta lim = start + len(rep_w) @@ -103,8 +105,7 @@ def range_assign(self, space, a, start, end, w_obj): i -= 1 elif delta > 0: del storage[start:start + delta] - storage[start:start + len(rep_w)] = [a.strategy.unwrap(space, r) for r in rep_w] - return strategy + storage[start:start + len(rep_w)] = [self.unwrap(space, r) for r in rep_w] def slice(self, space, a, start, end): return space.newarray(self.listview(space, a)[start:end]) From 376755f355251a10b6f32200c2946db0ef78765f Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 26 Mar 2013 11:40:07 +0100 Subject: [PATCH 04/37] nits --- topaz/objects/arrayobject.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 5f54982af..c542e237e 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -51,6 +51,7 @@ def __deepcopy__(self, memo): memo[id(self)] = result = object.__new__(self.__class__) return result + class ArrayStrategyMixin(object): _mixin_ = True @@ -193,8 +194,12 @@ def insert(self, space, a, idx, w_obj): obj_strategy = space.fromcache(ObjectArrayStrategy) obj_strategy.unerase(a.array_storage).insert(idx, obj_strategy.unwrap(space, w_obj)) -class ObjectArrayStrategy(ArrayStrategyMixin, ArrayStrategy): + def reverse_i(self, space, a): + storage = self.unerase(a.array_storage) + storage.reverse() + +class ObjectArrayStrategy(ArrayStrategyMixin, ArrayStrategy): erase, unerase = new_static_erasing_pair("object") def verify_strategy(self, space, a, w_obj): @@ -212,8 +217,8 @@ def checktype(self, w_obj): def sort(self, space, a, block): RubySorter(space, self.unerase(a.array_storage), sortblock=block).sort() -class FloatArrayStrategy(ArrayStrategyMixin, ArrayStrategy): +class FloatArrayStrategy(ArrayStrategyMixin, ArrayStrategy): erase, unerase = new_static_erasing_pair("float") def wrap(self, space, f): @@ -228,12 +233,11 @@ def checktype(self, w_obj): def sort(self, space, a, block): FloatSorter(space, self.unerase(a.array_storage), sortblock=block).sort() -class FixnumArrayStrategy(ArrayStrategyMixin, ArrayStrategy): +class FixnumArrayStrategy(ArrayStrategyMixin, ArrayStrategy): erase, unerase = new_static_erasing_pair("fixnum") def wrap(self, space, i): - assert isinstance(i, int) return space.newint(i) def unwrap(self, space, w_i): @@ -245,6 +249,7 @@ def checktype(self, w_obj): def sort(self, space, a, block): IntSorter(space, self.unerase(a.array_storage), sortblock=block).sort() + class W_ArrayObject(W_Object): classdef = ClassDef("Array", W_Object.classdef, filepath=__file__) classdef.include_module(Enumerable) From a98d169b00e0341f2614cd69eb21516761d93908 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 26 Mar 2013 13:31:12 +0100 Subject: [PATCH 05/37] refactor numeric array strategy --- topaz/frame.py | 2 +- topaz/objects/arrayobject.py | 133 ++++++++++++++++++----------------- topaz/objspace.py | 15 +--- 3 files changed, 70 insertions(+), 80 deletions(-) diff --git a/topaz/frame.py b/topaz/frame.py index b8bce101e..21ed532be 100644 --- a/topaz/frame.py +++ b/topaz/frame.py @@ -44,7 +44,7 @@ def handle_block_args(self, space, bytecode, args_w, block): isinstance(args_w[0], W_ArrayObject) and len(bytecode.arg_pos) >= 2): w_arg = args_w[0] assert isinstance(w_arg, W_ArrayObject) - args_w = w_arg.items_w + args_w = space.listview(w_arg) minargc = len(bytecode.arg_pos) - len(bytecode.defaults) if len(args_w) < minargc: args_w.extend([space.w_nil] * (minargc - len(args_w))) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index c542e237e..4a3d24f44 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -18,17 +18,17 @@ def __init__(self, space, list, listlength=None, sortblock=None): self.space = space self.sortblock = sortblock - def lt(self, a, b): + def lt(self, w_a, w_b): if self.sortblock is None: - w_cmp_res = self.space.send(a, self.space.newsymbol("<=>"), [b]) + w_cmp_res = self.space.send(w_a, self.space.newsymbol("<=>"), [w_b]) else: - w_cmp_res = self.space.invoke_block(self.sortblock, [a, b]) + w_cmp_res = self.space.invoke_block(self.sortblock, [w_a, w_b]) if w_cmp_res is self.space.w_nil: raise self.space.error( self.space.w_ArgumentError, "comparison of %s with %s failed" % - (self.space.obj_to_s(self.space.getclass(a)), - self.space.obj_to_s(self.space.getclass(b))) + (self.space.obj_to_s(self.space.getclass(w_a)), + self.space.obj_to_s(self.space.getclass(w_b))) ) else: return self.space.int_w(w_cmp_res) < 0 @@ -36,17 +36,20 @@ def lt(self, a, b): class IntSorter(RubySorter): def lt(self, a, b): - w_a, w_b = space.newint(a), space.newint(b) - RubySorter.lt(self, w_a, w_b) + w_a, w_b = self.space.newint(a), self.space.newint(b) + return RubySorter.lt(self, w_a, w_b) class FloatSorter(RubySorter): def lt(self, a, b): - w_a, w_b = space.newfloat(a), space.newfloat(b) - RubySorter.lt(self, w_a, w_b) + w_a, w_b = self.space.newfloat(a), self.space.newfloat(b) + return RubySorter.lt(self, w_a, w_b) class ArrayStrategy(object): + def __init__(self, space): + pass + def __deepcopy__(self, memo): memo[id(self)] = result = object.__new__(self.__class__) return result @@ -58,20 +61,6 @@ class ArrayStrategyMixin(object): def length(self, a): return len(self.unerase(a.array_storage)) - def range_assign(self, space, a, start, end, w_obj): - assert end >= 0 - w_converted = space.convert_type(w_obj, space.w_array, "to_ary", raise_error=False) - if w_converted is space.w_nil: - rep_w = [w_obj] - self.verify_strategy(space, a, w_obj) - else: - rep_w = space.listview(w_converted) - for each in rep_w: - self.verify_strategy(space, a, each) - delta = (end - start) - len(rep_w) - # storage can be of different array type after strategy is verified -> decorator ? ifs? - a.strategy.padd_assign(space, a, delta, start, end, rep_w) - def padd_assign(self, space, a, delta, start, end, rep_w): storage = self.unerase(a.array_storage) if delta < 0: @@ -122,37 +111,25 @@ def pop_n(self, space, a, num): return space.newarray(res_w) def replace(self, space, a, other_w): - for o in other_w: - if not self.checktype(o): - obj_strategy = space.fromcache(ObjectArrayStrategy) + for w_o in other_w: + if not self.checktype(w_o): a.array_storage = obj_strategy.store(space, other_w) - a.strategy = obj_strategy return - a.array_store = self.store(space, other_w) + a.array_storage = self.store(space, other_w) - def verify_strategy(self, space, a, w_obj): + def adapt(self, space, a, w_obj): if not self.checktype(w_obj): - obj_strategy = space.fromcache(ObjectArrayStrategy) - a.array_storage = obj_strategy.erase(self.listview(space, a)) - a.strategy = obj_strategy + self.to_object_strategy(space, a) def store(self, space, items_w): - l = [] - for o in items_w: - assert self.checktype(o) - l.append(self.unwrap(space, o)) + l = [self.unwrap(space, w_o) for w_o in items_w] return self.erase(l) def get_item(self, space, a, idx): return self.wrap(space, self.unerase(a.array_storage)[idx]) def set_item(self, space, a, idx, w_obj): - self.verify_strategy(space, a, w_obj) - if self.checktype(w_obj): - self.unerase(a.array_storage)[idx] = self.unwrap(space, w_obj) - else: - obj_strategy = space.fromcache(ObjectArrayStrategy) - obj_strategy.unerase(a.array_storage)[idx] = obj_strategy.unwrap(space, w_obj) + self.unerase(a.array_storage)[idx] = self.unwrap(space, w_obj) def listview(self, space, a): return [self.wrap(space, o) for o in self.unerase(a.array_storage)] @@ -172,12 +149,7 @@ def extend(self, space, a, other_w): self.unerase(a.array_storage).extend(l) def append(self, space, a, w_obj): - self.verify_strategy(space, a, w_obj) - if self.checktype(w_obj): - self.unerase(a.array_storage).append(self.unwrap(space, w_obj)) - else: - obj_strategy = space.fromcache(ObjectArrayStrategy) - obj_strategy.unerase(a.array_storage).append(obj_strategy.unwrap(space, w_obj)) + self.unerase(a.array_storage).append(self.unwrap(space, w_obj)) def pop(self, space, a, idx): storage = self.unerase(a.array_storage) @@ -187,12 +159,7 @@ def pop(self, space, a, idx): return space.w_nil def insert(self, space, a, idx, w_obj): - self.verify_strategy(space, a, w_obj) - if self.checktype(w_obj): - self.unerase(a.array_storage).insert(idx, self.unwrap(space, w_obj)) - else: - obj_strategy = space.fromcache(ObjectArrayStrategy) - obj_strategy.unerase(a.array_storage).insert(idx, obj_strategy.unwrap(space, w_obj)) + self.unerase(a.array_storage).insert(idx, self.unwrap(space, w_obj)) def reverse_i(self, space, a): storage = self.unerase(a.array_storage) @@ -202,9 +169,6 @@ def reverse_i(self, space, a): class ObjectArrayStrategy(ArrayStrategyMixin, ArrayStrategy): erase, unerase = new_static_erasing_pair("object") - def verify_strategy(self, space, a, w_obj): - pass - def wrap(self, space, w_obj): return w_obj @@ -217,8 +181,18 @@ def checktype(self, w_obj): def sort(self, space, a, block): RubySorter(space, self.unerase(a.array_storage), sortblock=block).sort() + def to_object_strategy(self, space, a): + pass + + +class SpecializedStrategy(ArrayStrategyMixin, ArrayStrategy): + def to_object_strategy(self, space, a): + obj_strategy = space.fromcache(ObjectArrayStrategy) + a.strategy = obj_strategy + a.array_storage = obj_strategy.erase(self.listview(space, a)) + -class FloatArrayStrategy(ArrayStrategyMixin, ArrayStrategy): +class FloatArrayStrategy(SpecializedStrategy): erase, unerase = new_static_erasing_pair("float") def wrap(self, space, f): @@ -234,7 +208,7 @@ def sort(self, space, a, block): FloatSorter(space, self.unerase(a.array_storage), sortblock=block).sort() -class FixnumArrayStrategy(ArrayStrategyMixin, ArrayStrategy): +class FixnumArrayStrategy(SpecializedStrategy): erase, unerase = new_static_erasing_pair("fixnum") def wrap(self, space, i): @@ -254,10 +228,10 @@ class W_ArrayObject(W_Object): classdef = ClassDef("Array", W_Object.classdef, filepath=__file__) classdef.include_module(Enumerable) - def __init__(self, space, strategy, items_w, klass=None): + def __init__(self, space, storage, strategy, klass=None): W_Object.__init__(self, space, klass) self.strategy = strategy - self.array_storage = self.strategy.store(space, items_w) + self.array_storage = storage def __deepcopy__(self, memo): obj = super(W_ArrayObject, self).__deepcopy__(memo) @@ -271,9 +245,25 @@ def listview(self, space): def length(self): return self.strategy.length(self) + @staticmethod + def newarray(space, items_w): + strategy = space.fromcache(ObjectArrayStrategy) + if items_w: + array_type = type(items_w[0]) + if array_type is W_FixnumObject: + strategy = space.fromcache(FixnumArrayStrategy) + elif array_type is W_FloatObject: + strategy = space.fromcache(FloatArrayStrategy) + for item in items_w: + if not isinstance(item, array_type): + strategy = space.fromcache(ObjectArrayStrategy) + break + storage = strategy.store(space, items_w) + return W_ArrayObject(space, storage, strategy) + @classdef.singleton_method("allocate") def singleton_method_allocate(self, space, args_w): - return W_ArrayObject(space, [], self) + return space.newarray([]) @classdef.method("initialize_copy", other_w="array") @classdef.method("replace", other_w="array") @@ -316,12 +306,21 @@ def method_subscript_assign(self, space, w_idx, w_count_or_obj, w_obj=None): ) ) elif start >= self.length(): - self.strategy.extend(space, self, - [space.w_nil] * (start - self.length() + 1)) + self.strategy.adapt(space, self, space.w_nil) + self.strategy.extend(space, self, [space.w_nil] * (start - self.length() + 1)) self.strategy.set_item(space, self, start, w_obj) elif as_range: - self.strategy.range_assign(space, self, start, end, w_obj) + w_ary = space.convert_type(w_obj, space.w_array, "to_ary", raise_error=False) + if w_ary is space.w_nil: + rep_w = [w_obj] + else: + rep_w = space.listview(w_ary) + for each in rep_w: + self.strategy.adapt(space, self, each) + delta = (end - start) - len(rep_w) + self.strategy.padd_assign(space, self, delta, start, end, rep_w) else: + self.strategy.adapt(space, self, w_obj) self.strategy.set_item(space, self, start, w_obj) return w_obj @@ -347,6 +346,7 @@ def method_add(self, space, other): @classdef.method("<<") @check_frozen() def method_lshift(self, space, w_obj): + self.strategy.adapt(space, self, w_obj) self.strategy.append(space, self, w_obj) return self @@ -375,6 +375,7 @@ def method_shift(self, space, w_n=None): def method_unshift(self, space, args_w): for i in xrange(len(args_w) - 1, -1, -1): w_obj = args_w[i] + self.strategy.adapt(space, self, w_obj) self.strategy.insert(space, self, 0, w_obj) return self @@ -464,5 +465,5 @@ def method_sort(self, space, block): @classdef.method("reverse!") @check_frozen() def method_reverse_i(self, space): - self.items_w.reverse() + self.strategy.reverse_i(space, self) return self diff --git a/topaz/objspace.py b/topaz/objspace.py index 6c321ed3b..ccaa5140a 100644 --- a/topaz/objspace.py +++ b/topaz/objspace.py @@ -30,7 +30,7 @@ from topaz.modules.process import Process from topaz.modules.signal import Signal from topaz.modules.topaz import Topaz -from topaz.objects.arrayobject import W_ArrayObject, ObjectArrayStrategy, FloatArrayStrategy, FixnumArrayStrategy, ArrayStrategy +from topaz.objects.arrayobject import W_ArrayObject from topaz.objects.bignumobject import W_BignumObject from topaz.objects.bindingobject import W_BindingObject from topaz.objects.boolobject import W_TrueObject, W_FalseObject @@ -372,18 +372,7 @@ def newstr_fromstrs(self, strs_w): return W_StringObject.newstr_fromstrs(self, strs_w) def newarray(self, items_w): - if items_w: - array_type = type(items_w[0]) - for item in items_w: - if not isinstance(item, array_type): - return W_ArrayObject(self, self.fromcache(ObjectArrayStrategy), items_w) - if array_type == W_FixnumObject: - return W_ArrayObject(self, self.fromcache(FixnumArrayStrategy), items_w) - elif array_type == W_FloatObject: - print array_type - return W_ArrayObject(self, self.fromcache(FloatArrayStrategy), items_w) - # unknown type, can not be optimized - return W_ArrayObject(self, self.fromcache(ObjectArrayStrategy), items_w) + return W_ArrayObject.newarray(self, items_w) def newhash(self): return W_HashObject(self) From d0b6ec14f1681bf28946ecde5134ed9cdb90c882 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 26 Mar 2013 13:59:05 +0100 Subject: [PATCH 06/37] fix translation for sorters --- topaz/objects/arrayobject.py | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 4a3d24f44..20a1b89c1 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -12,11 +12,8 @@ from topaz.objects.intobject import W_FixnumObject -class RubySorter(TimSort): - def __init__(self, space, list, listlength=None, sortblock=None): - TimSort.__init__(self, list, listlength=listlength) - self.space = space - self.sortblock = sortblock +class RubySorterMixin(object): + _mixin_ = True def lt(self, w_a, w_b): if self.sortblock is None: @@ -34,16 +31,25 @@ def lt(self, w_a, w_b): return self.space.int_w(w_cmp_res) < 0 -class IntSorter(RubySorter): - def lt(self, a, b): - w_a, w_b = self.space.newint(a), self.space.newint(b) - return RubySorter.lt(self, w_a, w_b) +class RubySorter(TimSort, RubySorterMixin): + def __init__(self, space, list, listlength=None, sortblock=None): + TimSort.__init__(self, list, listlength=listlength) + self.space = space + self.sortblock = sortblock -class FloatSorter(RubySorter): - def lt(self, a, b): - w_a, w_b = self.space.newfloat(a), self.space.newfloat(b) - return RubySorter.lt(self, w_a, w_b) +class FloatSorter(TimSort, RubySorterMixin): + def __init__(self, space, list, listlength=None, sortblock=None): + TimSort.__init__(self, list, listlength=listlength) + self.space = space + self.sortblock = sortblock + + +class IntSorter(TimSort, RubySorterMixin): + def __init__(self, space, list, listlength=None, sortblock=None): + TimSort.__init__(self, list, listlength=listlength) + self.space = space + self.sortblock = sortblock class ArrayStrategy(object): From 33710ce7ab1bde2589e734a343c259cfa309a6c5 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 26 Mar 2013 13:59:36 +0100 Subject: [PATCH 07/37] move choosing strategy and creating storage into W_ArrayObject --- topaz/objects/arrayobject.py | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 20a1b89c1..e745785e4 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -116,13 +116,6 @@ def pop_n(self, space, a, num): del self.unerase(a.array_storage)[pop_size:] return space.newarray(res_w) - def replace(self, space, a, other_w): - for w_o in other_w: - if not self.checktype(w_o): - a.array_storage = obj_strategy.store(space, other_w) - return - a.array_storage = self.store(space, other_w) - def adapt(self, space, a, w_obj): if not self.checktype(w_obj): self.to_object_strategy(space, a) @@ -253,19 +246,23 @@ def length(self): @staticmethod def newarray(space, items_w): - strategy = space.fromcache(ObjectArrayStrategy) + strategy = W_ArrayObject.strategy_for_list(space, items_w) + storage = strategy.store(space, items_w) + return W_ArrayObject(space, storage, strategy) + + @staticmethod + def strategy_for_list(space, items_w): if items_w: array_type = type(items_w[0]) - if array_type is W_FixnumObject: - strategy = space.fromcache(FixnumArrayStrategy) - elif array_type is W_FloatObject: - strategy = space.fromcache(FloatArrayStrategy) for item in items_w: if not isinstance(item, array_type): - strategy = space.fromcache(ObjectArrayStrategy) - break - storage = strategy.store(space, items_w) - return W_ArrayObject(space, storage, strategy) + return space.fromcache(ObjectArrayStrategy) + if array_type is W_FixnumObject: + return space.fromcache(FixnumArrayStrategy) + elif array_type is W_FloatObject: + return space.fromcache(FloatArrayStrategy) + else: + return space.fromcache(ObjectArrayStrategy) @classdef.singleton_method("allocate") def singleton_method_allocate(self, space, args_w): @@ -275,7 +272,8 @@ def singleton_method_allocate(self, space, args_w): @classdef.method("replace", other_w="array") @check_frozen() def method_replace(self, space, other_w): - self.strategy.replace(space, self, other_w) + self.strategy = W_ArrayObject.strategy_for_list(space, other_w) + self.array_storage = self.strategy.store(space, other_w) return self @classdef.method("[]") From 93940cd3d40c7757f531e5468eb1d7c3ee20fbe4 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 26 Mar 2013 13:59:57 +0100 Subject: [PATCH 08/37] fix UnionErrors when merging different prebuilt erase methods --- topaz/objects/arrayobject.py | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index e745785e4..7d791ca81 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -164,9 +164,14 @@ def reverse_i(self, space, a): storage = self.unerase(a.array_storage) storage.reverse() + def to_object_strategy(self, space, a): + obj_strategy = space.fromcache(ObjectArrayStrategy) + a.strategy = obj_strategy + a.array_storage = obj_strategy.erase(self.listview(space, a)) + class ObjectArrayStrategy(ArrayStrategyMixin, ArrayStrategy): - erase, unerase = new_static_erasing_pair("object") + _erase, _unerase = new_static_erasing_pair("object") def wrap(self, space, w_obj): return w_obj @@ -183,16 +188,15 @@ def sort(self, space, a, block): def to_object_strategy(self, space, a): pass + def erase(self, items): + return self._erase(items) -class SpecializedStrategy(ArrayStrategyMixin, ArrayStrategy): - def to_object_strategy(self, space, a): - obj_strategy = space.fromcache(ObjectArrayStrategy) - a.strategy = obj_strategy - a.array_storage = obj_strategy.erase(self.listview(space, a)) + def unerase(self, items): + return self._unerase(items) -class FloatArrayStrategy(SpecializedStrategy): - erase, unerase = new_static_erasing_pair("float") +class FloatArrayStrategy(ArrayStrategyMixin, ArrayStrategy): + _erase, _unerase = new_static_erasing_pair("float") def wrap(self, space, f): return space.newfloat(f) @@ -206,9 +210,15 @@ def checktype(self, w_obj): def sort(self, space, a, block): FloatSorter(space, self.unerase(a.array_storage), sortblock=block).sort() + def erase(self, items): + return self._erase(items) + + def unerase(self, items): + return self._unerase(items) -class FixnumArrayStrategy(SpecializedStrategy): - erase, unerase = new_static_erasing_pair("fixnum") + +class FixnumArrayStrategy(ArrayStrategyMixin, ArrayStrategy): + _erase, _unerase = new_static_erasing_pair("fixnum") def wrap(self, space, i): return space.newint(i) @@ -222,6 +232,12 @@ def checktype(self, w_obj): def sort(self, space, a, block): IntSorter(space, self.unerase(a.array_storage), sortblock=block).sort() + def erase(self, items): + return self._erase(items) + + def unerase(self, items): + return self._unerase(items) + class W_ArrayObject(W_Object): classdef = ClassDef("Array", W_Object.classdef, filepath=__file__) From 0750ca94da52d70b9594b5f959c321972dc89c2c Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 26 Mar 2013 14:48:05 +0100 Subject: [PATCH 09/37] fix translation --- topaz/objects/arrayobject.py | 99 ++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 55 deletions(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 7d791ca81..e44c79390 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -12,8 +12,11 @@ from topaz.objects.intobject import W_FixnumObject -class RubySorterMixin(object): - _mixin_ = True +class RubySorter(TimSort): + def __init__(self, space, list, listlength=None, sortblock=None): + TimSort.__init__(self, list, listlength=listlength) + self.space = space + self.sortblock = sortblock def lt(self, w_a, w_b): if self.sortblock is None: @@ -31,27 +34,6 @@ def lt(self, w_a, w_b): return self.space.int_w(w_cmp_res) < 0 -class RubySorter(TimSort, RubySorterMixin): - def __init__(self, space, list, listlength=None, sortblock=None): - TimSort.__init__(self, list, listlength=listlength) - self.space = space - self.sortblock = sortblock - - -class FloatSorter(TimSort, RubySorterMixin): - def __init__(self, space, list, listlength=None, sortblock=None): - TimSort.__init__(self, list, listlength=listlength) - self.space = space - self.sortblock = sortblock - - -class IntSorter(TimSort, RubySorterMixin): - def __init__(self, space, list, listlength=None, sortblock=None): - TimSort.__init__(self, list, listlength=listlength) - self.space = space - self.sortblock = sortblock - - class ArrayStrategy(object): def __init__(self, space): pass @@ -70,7 +52,7 @@ def length(self, a): def padd_assign(self, space, a, delta, start, end, rep_w): storage = self.unerase(a.array_storage) if delta < 0: - storage += [None] * -delta + storage += [self.padding_value] * -delta lim = start + len(rep_w) i = len(storage) - 1 while i >= lim: @@ -98,7 +80,7 @@ def slice_i(self, space, a, start, end, as_range, nil): storage = self.unerase(a.array_storage) w_item = storage[start] del storage[start] - return w_item + return self.wrap(space, w_item) def shift(self, space, a, n): if n < 0: @@ -120,10 +102,6 @@ def adapt(self, space, a, w_obj): if not self.checktype(w_obj): self.to_object_strategy(space, a) - def store(self, space, items_w): - l = [self.unwrap(space, w_o) for w_o in items_w] - return self.erase(l) - def get_item(self, space, a, idx): return self.wrap(space, self.unerase(a.array_storage)[idx]) @@ -134,18 +112,7 @@ def listview(self, space, a): return [self.wrap(space, o) for o in self.unerase(a.array_storage)] def extend(self, space, a, other_w): - for o in other_w: - if not self.checktype(o): - obj_strategy = space.fromcache(ObjectArrayStrategy) - a.array_storage = obj_strategy.erase(self.listview(space, a)) - obj_strategy.unerase(a.array_storage).extend(other_w) - a.strategy = obj_strategy - return - l = [] - for o in other_w: - assert self.checktype(o) - l.append(self.unwrap(space, o)) - self.unerase(a.array_storage).extend(l) + self.unerase(a.array_storage).extend([self.unwrap(space, w_o) for w_o in other_w]) def append(self, space, a, w_obj): self.unerase(a.array_storage).append(self.unwrap(space, w_obj)) @@ -172,6 +139,7 @@ def to_object_strategy(self, space, a): class ObjectArrayStrategy(ArrayStrategyMixin, ArrayStrategy): _erase, _unerase = new_static_erasing_pair("object") + padding_value = None def wrap(self, space, w_obj): return w_obj @@ -182,12 +150,13 @@ def unwrap(self, space, w_obj): def checktype(self, w_obj): return True - def sort(self, space, a, block): - RubySorter(space, self.unerase(a.array_storage), sortblock=block).sort() - def to_object_strategy(self, space, a): pass + def store(self, space, items_w): + l = [self.unwrap(space, w_o) for w_o in items_w] + return self.erase(l) + def erase(self, items): return self._erase(items) @@ -197,6 +166,7 @@ def unerase(self, items): class FloatArrayStrategy(ArrayStrategyMixin, ArrayStrategy): _erase, _unerase = new_static_erasing_pair("float") + padding_value = 0.0 def wrap(self, space, f): return space.newfloat(f) @@ -207,8 +177,9 @@ def unwrap(self, space, w_f): def checktype(self, w_obj): return isinstance(w_obj, W_FloatObject) - def sort(self, space, a, block): - FloatSorter(space, self.unerase(a.array_storage), sortblock=block).sort() + def store(self, space, items_w): + l = [self.unwrap(space, w_o) for w_o in items_w] + return self.erase(l) def erase(self, items): return self._erase(items) @@ -219,6 +190,7 @@ def unerase(self, items): class FixnumArrayStrategy(ArrayStrategyMixin, ArrayStrategy): _erase, _unerase = new_static_erasing_pair("fixnum") + padding_value = 0 def wrap(self, space, i): return space.newint(i) @@ -229,8 +201,9 @@ def unwrap(self, space, w_i): def checktype(self, w_obj): return isinstance(w_obj, W_FixnumObject) - def sort(self, space, a, block): - IntSorter(space, self.unerase(a.array_storage), sortblock=block).sort() + def store(self, space, items_w): + l = [self.unwrap(space, w_o) for w_o in items_w] + return self.erase(l) def erase(self, items): return self._erase(items) @@ -284,12 +257,15 @@ def strategy_for_list(space, items_w): def singleton_method_allocate(self, space, args_w): return space.newarray([]) + def replace(self, space, other_w): + self.strategy = W_ArrayObject.strategy_for_list(space, other_w) + self.array_storage = self.strategy.store(space, other_w) + @classdef.method("initialize_copy", other_w="array") @classdef.method("replace", other_w="array") @check_frozen() def method_replace(self, space, other_w): - self.strategy = W_ArrayObject.strategy_for_list(space, other_w) - self.array_storage = self.strategy.store(space, other_w) + self.replace(space, other_w) return self @classdef.method("[]") @@ -370,16 +346,23 @@ def method_lshift(self, space, w_obj): self.strategy.append(space, self, w_obj) return self + def concat(self, space, other_w): + strategy = self.strategy_for_list(space, other_w) + if self.strategy is not strategy: + self.array_storage = self.strategy.store(space, self.listview(space)) + self.strategy = strategy + self.strategy.extend(space, self, other_w) + @classdef.method("concat", other="array") @check_frozen() - def method_concat(self, space, other): - self.strategy.extend(space, self, other) + def method_concat(self, space, other_w): + self.concat(space, other_w) return self @classdef.method("push") @check_frozen() - def method_concat(self, space, args_w): - self.strategy.extend(space, self, args_w) + def method_push(self, space, args_w): + self.concat(space, args_w) return self @classdef.method("shift") @@ -479,7 +462,13 @@ def method_clear(self, space): @classdef.method("sort!") def method_sort(self, space, block): - self.strategy.sort(space, self, block) + strategy = self.strategy + if strategy is space.fromcache(ObjectArrayStrategy): + RubySorter(space, strategy.unerase(self.array_storage), sortblock=block).sort() + else: + items_w = self.listview(space) + RubySorter(space, items_w, sortblock=block).sort() + self.replace(space, items_w) return self @classdef.method("reverse!") From 33f49c0503df08ddc4d27f06893f64d76b401b0d Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 26 Mar 2013 14:57:06 +0100 Subject: [PATCH 10/37] fix tests --- topaz/objects/arrayobject.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index e44c79390..f77aca87d 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -250,8 +250,7 @@ def strategy_for_list(space, items_w): return space.fromcache(FixnumArrayStrategy) elif array_type is W_FloatObject: return space.fromcache(FloatArrayStrategy) - else: - return space.fromcache(ObjectArrayStrategy) + return space.fromcache(ObjectArrayStrategy) @classdef.singleton_method("allocate") def singleton_method_allocate(self, space, args_w): @@ -349,11 +348,11 @@ def method_lshift(self, space, w_obj): def concat(self, space, other_w): strategy = self.strategy_for_list(space, other_w) if self.strategy is not strategy: - self.array_storage = self.strategy.store(space, self.listview(space)) + self.array_storage = strategy.store(space, self.listview(space)) self.strategy = strategy self.strategy.extend(space, self, other_w) - @classdef.method("concat", other="array") + @classdef.method("concat", other_w="array") @check_frozen() def method_concat(self, space, other_w): self.concat(space, other_w) From a3e72ced47db4986d2f587c2722c588e702ace81 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 26 Mar 2013 16:12:30 +0100 Subject: [PATCH 11/37] refactor code to be closer to master, style nits --- topaz/objects/arrayobject.py | 120 ++++++++++++++++++----------------- 1 file changed, 62 insertions(+), 58 deletions(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index f77aca87d..d2858491e 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -46,11 +46,11 @@ def __deepcopy__(self, memo): class ArrayStrategyMixin(object): _mixin_ = True - def length(self, a): - return len(self.unerase(a.array_storage)) + def length(self, w_ary): + return len(self.unerase(w_ary.array_storage)) - def padd_assign(self, space, a, delta, start, end, rep_w): - storage = self.unerase(a.array_storage) + def padd_assign(self, space, w_ary, delta, start, end, rep_w): + storage = self.unerase(w_ary.array_storage) if delta < 0: storage += [self.padding_value] * -delta lim = start + len(rep_w) @@ -60,81 +60,61 @@ def padd_assign(self, space, a, delta, start, end, rep_w): i -= 1 elif delta > 0: del storage[start:start + delta] - storage[start:start + len(rep_w)] = [self.unwrap(space, r) for r in rep_w] + storage[start:start + len(rep_w)] = [self.unwrap(space, w_obj) for w_obj in rep_w] - def slice(self, space, a, start, end): - return space.newarray(self.listview(space, a)[start:end]) + def slice(self, space, w_ary, start, end): + items_w = self.listview(space, w_ary, start, end) + return space.newarray(items_w) - def slice_i(self, space, a, start, end, as_range, nil): - if nil: - return space.w_nil - elif as_range: - start = min(max(start, 0), self.length(a)) - end = min(max(end, 0), self.length(a)) - delta = (end - start) - assert delta >= 0 - w_items = self.listview(space, a)[start:start + delta] - del self.unerase(a.array_storage)[start:start + delta] - return space.newarray(w_items) - else: - storage = self.unerase(a.array_storage) - w_item = storage[start] - del storage[start] - return self.wrap(space, w_item) + def slice_i(self, space, w_ary, start, end): + w_items = self.slice(space, w_ary, start, end) + del self.unerase(a.array_storage)[start:end] + return w_items - def shift(self, space, a, n): - if n < 0: - raise space.error(space.w_ArgumentError, "negative array size") - items_w = self.listview(space, a)[:n] - del self.unerase(a.array_storage)[:n] - return space.newarray(items_w) + def shift(self, space, w_ary, n): + return self.slice_i(space, w_ary, 0, n) - def clear(self, space, a): - del self.unerase(a.array_storage)[:] + def clear(self, space, w_ary): + del self.unerase(w_ary.array_storage)[:] - def pop_n(self, space, a, num): - pop_size = max(0, self.length(a) - num) - res_w = self.listview(space, a)[pop_size:] - del self.unerase(a.array_storage)[pop_size:] - return space.newarray(res_w) + def pop_n(self, space, w_ary, num): + pop_size = max(0, self.length(w_ary) - num) + return self.slice_i(space, w_ary, pop_size, -1) def adapt(self, space, a, w_obj): if not self.checktype(w_obj): self.to_object_strategy(space, a) - def get_item(self, space, a, idx): + def get_item(self, space, w_ary, idx): return self.wrap(space, self.unerase(a.array_storage)[idx]) - def set_item(self, space, a, idx, w_obj): + def set_item(self, space, w_ary, idx, w_obj): self.unerase(a.array_storage)[idx] = self.unwrap(space, w_obj) - def listview(self, space, a): - return [self.wrap(space, o) for o in self.unerase(a.array_storage)] + def listview(self, space, w_ary, start=0, stop=-1): + return [self.wrap(space, o) for o in self.unerase(a.array_storage)[start:stop]] - def extend(self, space, a, other_w): - self.unerase(a.array_storage).extend([self.unwrap(space, w_o) for w_o in other_w]) + def extend(self, space, w_ary, other_w): + self.unerase(w_ary.array_storage).extend([self.unwrap(space, w_o) for w_o in other_w]) - def append(self, space, a, w_obj): - self.unerase(a.array_storage).append(self.unwrap(space, w_obj)) + def append(self, space, w_ary, w_obj): + self.unerase(w_ary.array_storage).append(self.unwrap(space, w_obj)) - def pop(self, space, a, idx): - storage = self.unerase(a.array_storage) - if storage: - return self.wrap(space, storage.pop(idx)) - else: - return space.w_nil + def pop(self, space, w_ary, idx): + storage = self.unerase(w_ary.array_storage) + return self.wrap(space, storage.pop(idx)) - def insert(self, space, a, idx, w_obj): - self.unerase(a.array_storage).insert(idx, self.unwrap(space, w_obj)) + def insert(self, space, w_ary, idx, w_obj): + self.unerase(w_ary.array_storage).insert(idx, self.unwrap(space, w_obj)) def reverse_i(self, space, a): storage = self.unerase(a.array_storage) storage.reverse() - def to_object_strategy(self, space, a): + def to_object_strategy(self, space, w_ary): obj_strategy = space.fromcache(ObjectArrayStrategy) - a.strategy = obj_strategy - a.array_storage = obj_strategy.erase(self.listview(space, a)) + w_ary.array_storage = obj_strategy.erase(self.listview(space, w_ary)) + w_ary.strategy = obj_strategy class ObjectArrayStrategy(ArrayStrategyMixin, ArrayStrategy): @@ -157,6 +137,12 @@ def store(self, space, items_w): l = [self.unwrap(space, w_o) for w_o in items_w] return self.erase(l) + def listview(self, space, w_ary, start=0, end=-1): + return self.unerase(w_ary.array_storage)[start:end] + + def extend(self, space, w_ary, other_w): + self.unerase(a.array_storage).extend(other_w) + def erase(self, items): return self._erase(items) @@ -323,7 +309,17 @@ def method_subscript_assign(self, space, w_idx, w_count_or_obj, w_obj=None): @check_frozen() def method_slice_i(self, space, w_idx, w_count=None): start, end, as_range, nil = space.subscript_access(self.length(), w_idx, w_count=w_count) - return self.strategy.slice_i(space, self, start, end, as_range, nil) + + if nil: + return space.w_nil + elif as_range: + start = min(max(start, 0), len(self.items_w)) + end = min(max(end, 0), len(self.items_w)) + delta = (end - start) + assert delta >= 0 + return self.strategy.slice_i(space, self, start, start + delta) + else: + return self.strategy.pop(space, self, start) @classdef.method("size") @classdef.method("length") @@ -368,8 +364,13 @@ def method_push(self, space, args_w): @check_frozen() def method_shift(self, space, w_n=None): if w_n is None: - return self.strategy.pop(space, self, 0) + if self.length() > 0: + return self.strategy.pop(space, self, 0) + else: + return space.w_nil n = space.int_w(space.convert_type(w_n, space.w_fixnum, "to_int")) + if n < 0: + raise space.error(space.w_ArgumentError, "negative array size") return self.strategy.shift(space, self, n) @classdef.method("unshift") @@ -408,7 +409,10 @@ def method_try_convert(self, space, w_obj): @check_frozen() def method_pop(self, space, w_num=None): if w_num is None: - return self.strategy.pop(space, self, -1) + if self.length() > 0: + return self.strategy.pop(space, self, -1) + else: + return space.w_nil else: num = space.int_w(space.convert_type( w_num, space.w_fixnum, "to_int" From b62eb842e4ba33ee62f19a684413fdacb8d48f02 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 26 Mar 2013 17:28:50 +0100 Subject: [PATCH 12/37] add EmptyArrayStrategy and fix tests --- topaz/objects/arrayobject.py | 62 +++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 15 deletions(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index d2858491e..5be4e7784 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -63,12 +63,13 @@ def padd_assign(self, space, w_ary, delta, start, end, rep_w): storage[start:start + len(rep_w)] = [self.unwrap(space, w_obj) for w_obj in rep_w] def slice(self, space, w_ary, start, end): - items_w = self.listview(space, w_ary, start, end) + items = self.unerase(w_ary.array_storage)[start:end] + items_w = [self.wrap(space, item) for item in items] return space.newarray(items_w) def slice_i(self, space, w_ary, start, end): w_items = self.slice(space, w_ary, start, end) - del self.unerase(a.array_storage)[start:end] + del self.unerase(w_ary.array_storage)[start:end] return w_items def shift(self, space, w_ary, n): @@ -79,20 +80,20 @@ def clear(self, space, w_ary): def pop_n(self, space, w_ary, num): pop_size = max(0, self.length(w_ary) - num) - return self.slice_i(space, w_ary, pop_size, -1) + return self.slice_i(space, w_ary, pop_size, self.length(w_ary)) - def adapt(self, space, a, w_obj): + def adapt(self, space, w_ary, w_obj): if not self.checktype(w_obj): - self.to_object_strategy(space, a) + self.to_object_strategy(space, w_ary) def get_item(self, space, w_ary, idx): - return self.wrap(space, self.unerase(a.array_storage)[idx]) + return self.wrap(space, self.unerase(w_ary.array_storage)[idx]) def set_item(self, space, w_ary, idx, w_obj): - self.unerase(a.array_storage)[idx] = self.unwrap(space, w_obj) + self.unerase(w_ary.array_storage)[idx] = self.unwrap(space, w_obj) - def listview(self, space, w_ary, start=0, stop=-1): - return [self.wrap(space, o) for o in self.unerase(a.array_storage)[start:stop]] + def listview(self, space, w_ary): + return [self.wrap(space, item) for item in self.unerase(w_ary.array_storage)] def extend(self, space, w_ary, other_w): self.unerase(w_ary.array_storage).extend([self.unwrap(space, w_o) for w_o in other_w]) @@ -107,8 +108,8 @@ def pop(self, space, w_ary, idx): def insert(self, space, w_ary, idx, w_obj): self.unerase(w_ary.array_storage).insert(idx, self.unwrap(space, w_obj)) - def reverse_i(self, space, a): - storage = self.unerase(a.array_storage) + def reverse_i(self, space, w_ary): + storage = self.unerase(w_ary.array_storage) storage.reverse() def to_object_strategy(self, space, w_ary): @@ -130,18 +131,18 @@ def unwrap(self, space, w_obj): def checktype(self, w_obj): return True - def to_object_strategy(self, space, a): + def to_object_strategy(self, space, w_ary): pass def store(self, space, items_w): l = [self.unwrap(space, w_o) for w_o in items_w] return self.erase(l) - def listview(self, space, w_ary, start=0, end=-1): - return self.unerase(w_ary.array_storage)[start:end] + def listview(self, space, w_ary): + return self.unerase(w_ary.array_storage) def extend(self, space, w_ary, other_w): - self.unerase(a.array_storage).extend(other_w) + self.unerase(w_ary.array_storage).extend(other_w) def erase(self, items): return self._erase(items) @@ -198,6 +199,35 @@ def unerase(self, items): return self._unerase(items) +class EmptyArrayStrategy(ArrayStrategyMixin, ArrayStrategy): + def wrap(self, space, i): + raise RuntimeError("should not be called") + + def unwrap(self, space, w_i): + raise RuntimeError("should not be called") + + def checktype(self, space, w_obj): + return False + + def store(self, space, items_w): + if items_w: + raise RuntimeError("EmptyArrayStrategy for non-empty list") + return None + + def erase(self, items): + return [] + + def unerase(self, items): + return [] + + def adapt(self, space, w_ary, w_obj): + self.to_strategy(space, w_ary, W_ArrayObject.strategy_for_list(space, [w_obj])) + + def to_strategy(self, space, w_ary, strategy): + w_ary.array_storage = strategy.erase([]) + w_ary.strategy = strategy + + class W_ArrayObject(W_Object): classdef = ClassDef("Array", W_Object.classdef, filepath=__file__) classdef.include_module(Enumerable) @@ -236,6 +266,8 @@ def strategy_for_list(space, items_w): return space.fromcache(FixnumArrayStrategy) elif array_type is W_FloatObject: return space.fromcache(FloatArrayStrategy) + else: + return space.fromcache(EmptyArrayStrategy) return space.fromcache(ObjectArrayStrategy) @classdef.singleton_method("allocate") From 0ae04b4a19e92f545289643e793e49ffbc26843d Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 26 Mar 2013 17:48:15 +0100 Subject: [PATCH 13/37] revert to empty strategy on clear and fix tests --- topaz/objects/arrayobject.py | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 5be4e7784..147bf3a4c 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -76,7 +76,7 @@ def shift(self, space, w_ary, n): return self.slice_i(space, w_ary, 0, n) def clear(self, space, w_ary): - del self.unerase(w_ary.array_storage)[:] + self.to_empty_strategy(space, w_ary) def pop_n(self, space, w_ary, num): pop_size = max(0, self.length(w_ary) - num) @@ -117,6 +117,10 @@ def to_object_strategy(self, space, w_ary): w_ary.array_storage = obj_strategy.erase(self.listview(space, w_ary)) w_ary.strategy = obj_strategy + def to_empty_strategy(self, space, w_ary): + w_ary.strategy = space.fromcache(EmptyArrayStrategy) + w_ary.array_storage = w_ary.strategy.erase(None) + class ObjectArrayStrategy(ArrayStrategyMixin, ArrayStrategy): _erase, _unerase = new_static_erasing_pair("object") @@ -200,6 +204,18 @@ def unerase(self, items): class EmptyArrayStrategy(ArrayStrategyMixin, ArrayStrategy): + _erase, _unerase = new_static_erasing_pair("empty") + + def slice(self, space, w_ary, start, end): + return space.newarray([]) + slice_i = slice + + def listview(self, space, w_ary): + return [] + + def length(self, w_ary): + return 0 + def wrap(self, space, i): raise RuntimeError("should not be called") @@ -210,23 +226,23 @@ def checktype(self, space, w_obj): return False def store(self, space, items_w): - if items_w: - raise RuntimeError("EmptyArrayStrategy for non-empty list") - return None + return self.erase(items_w) def erase(self, items): - return [] + assert not items + return self._erase(None) def unerase(self, items): - return [] + return self._unerase(items) def adapt(self, space, w_ary, w_obj): - self.to_strategy(space, w_ary, W_ArrayObject.strategy_for_list(space, [w_obj])) - - def to_strategy(self, space, w_ary, strategy): + strategy = W_ArrayObject.strategy_for_list(space, [w_obj]) w_ary.array_storage = strategy.erase([]) w_ary.strategy = strategy + def to_empty_strategy(self, space, w_ary): + pass + class W_ArrayObject(W_Object): classdef = ClassDef("Array", W_Object.classdef, filepath=__file__) From 435eb7abf4feabaffd50526bc8be615a43f2af57 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 26 Mar 2013 19:32:22 +0100 Subject: [PATCH 14/37] add NotImplementedError rasing to default methods --- topaz/objects/arrayobject.py | 197 ++++++++++++++++++++++------------- 1 file changed, 124 insertions(+), 73 deletions(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 147bf3a4c..f5b8223ac 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -42,13 +42,86 @@ def __deepcopy__(self, memo): memo[id(self)] = result = object.__new__(self.__class__) return result + def append(self, space, w_ary, w_obj): + raise NotImplementedError + + def checktype(self, space, w_obj): + raise NotImplementedError + + def clear(self, space, w_ary): + self.to_empty_strategy(space, w_ary) + + def extend(self, space, w_ary, other_w): + raise NotImplementedError + + def get_item(self, space, w_ary, idx): + raise NotImplementedError + + def insert(self, space, w_ary, idx, w_obj): + raise NotImplementedError + + def length(self, w_ary): + raise NotImplementedError + + def listview(self, space, w_ary): + raise NotImplementedError + + def padd_assign(self, space, w_ary, delta, start, end, rep_w): + raise NotImplementedError + + def pop(self, space, w_ary, idx): + raise NotImplementedError + + def pop_n(self, space, w_ary, num): + raise NotImplementedError + + def reverse_i(self, space, w_ary): + raise NotImplementedError + + def set_item(self, space, w_ary, idx, w_obj): + raise NotImplementedError + + def slice(self, space, w_ary, start, end): + raise NotImplementedError + + def slice_i(self, space, w_ary, start, end): + raise NotImplementedError + + def adapt(self, space, w_ary, w_obj): + if not self.checktype(w_obj): + self.to_object_strategy(space, w_ary) + + def to_object_strategy(self, space, w_ary): + obj_strategy = space.fromcache(ObjectArrayStrategy) + w_ary.array_storage = obj_strategy.erase(self.listview(space, w_ary)) + w_ary.strategy = obj_strategy -class ArrayStrategyMixin(object): + def to_empty_strategy(self, space, w_ary): + w_ary.strategy = space.fromcache(EmptyArrayStrategy) + w_ary.array_storage = w_ary.strategy.erase(None) + + +class ErasingArrayStrategyMixin(object): _mixin_ = True + def append(self, space, w_ary, w_obj): + self.unerase(w_ary.array_storage).append(self.unwrap(space, w_obj)) + + def extend(self, space, w_ary, other_w): + self.unerase(w_ary.array_storage).extend([self.unwrap(space, w_o) for w_o in other_w]) + + def get_item(self, space, w_ary, idx): + return self.wrap(space, self.unerase(w_ary.array_storage)[idx]) + + def insert(self, space, w_ary, idx, w_obj): + self.unerase(w_ary.array_storage).insert(idx, self.unwrap(space, w_obj)) + def length(self, w_ary): return len(self.unerase(w_ary.array_storage)) + def listview(self, space, w_ary): + return [self.wrap(space, item) for item in self.unerase(w_ary.array_storage)] + def padd_assign(self, space, w_ary, delta, start, end, rep_w): storage = self.unerase(w_ary.array_storage) if delta < 0: @@ -62,6 +135,21 @@ def padd_assign(self, space, w_ary, delta, start, end, rep_w): del storage[start:start + delta] storage[start:start + len(rep_w)] = [self.unwrap(space, w_obj) for w_obj in rep_w] + def pop(self, space, w_ary, idx): + storage = self.unerase(w_ary.array_storage) + return self.wrap(space, storage.pop(idx)) + + def pop_n(self, space, w_ary, num): + pop_size = max(0, self.length(w_ary) - num) + return self.slice_i(space, w_ary, pop_size, self.length(w_ary)) + + def reverse_i(self, space, w_ary): + storage = self.unerase(w_ary.array_storage) + storage.reverse() + + def set_item(self, space, w_ary, idx, w_obj): + self.unerase(w_ary.array_storage)[idx] = self.unwrap(space, w_obj) + def slice(self, space, w_ary, start, end): items = self.unerase(w_ary.array_storage)[start:end] items_w = [self.wrap(space, item) for item in items] @@ -75,54 +163,23 @@ def slice_i(self, space, w_ary, start, end): def shift(self, space, w_ary, n): return self.slice_i(space, w_ary, 0, n) - def clear(self, space, w_ary): - self.to_empty_strategy(space, w_ary) - - def pop_n(self, space, w_ary, num): - pop_size = max(0, self.length(w_ary) - num) - return self.slice_i(space, w_ary, pop_size, self.length(w_ary)) - - def adapt(self, space, w_ary, w_obj): - if not self.checktype(w_obj): - self.to_object_strategy(space, w_ary) - - def get_item(self, space, w_ary, idx): - return self.wrap(space, self.unerase(w_ary.array_storage)[idx]) - - def set_item(self, space, w_ary, idx, w_obj): - self.unerase(w_ary.array_storage)[idx] = self.unwrap(space, w_obj) - - def listview(self, space, w_ary): - return [self.wrap(space, item) for item in self.unerase(w_ary.array_storage)] - - def extend(self, space, w_ary, other_w): - self.unerase(w_ary.array_storage).extend([self.unwrap(space, w_o) for w_o in other_w]) - - def append(self, space, w_ary, w_obj): - self.unerase(w_ary.array_storage).append(self.unwrap(space, w_obj)) - - def pop(self, space, w_ary, idx): - storage = self.unerase(w_ary.array_storage) - return self.wrap(space, storage.pop(idx)) + def wrap(self, space, w_obj): + raise NotImplementedError - def insert(self, space, w_ary, idx, w_obj): - self.unerase(w_ary.array_storage).insert(idx, self.unwrap(space, w_obj)) + def unwrap(self, space, w_obj): + raise NotImplementedError - def reverse_i(self, space, w_ary): - storage = self.unerase(w_ary.array_storage) - storage.reverse() + def store(self, space, items_w): + raise NotImplementedError - def to_object_strategy(self, space, w_ary): - obj_strategy = space.fromcache(ObjectArrayStrategy) - w_ary.array_storage = obj_strategy.erase(self.listview(space, w_ary)) - w_ary.strategy = obj_strategy + def erase(self, items): + raise NotImplementedError - def to_empty_strategy(self, space, w_ary): - w_ary.strategy = space.fromcache(EmptyArrayStrategy) - w_ary.array_storage = w_ary.strategy.erase(None) + def unerase(self, items): + raise NotImplementedError -class ObjectArrayStrategy(ArrayStrategyMixin, ArrayStrategy): +class ObjectArrayStrategy(ErasingArrayStrategyMixin, ArrayStrategy): _erase, _unerase = new_static_erasing_pair("object") padding_value = None @@ -135,27 +192,27 @@ def unwrap(self, space, w_obj): def checktype(self, w_obj): return True - def to_object_strategy(self, space, w_ary): - pass - def store(self, space, items_w): l = [self.unwrap(space, w_o) for w_o in items_w] return self.erase(l) - def listview(self, space, w_ary): - return self.unerase(w_ary.array_storage) - - def extend(self, space, w_ary, other_w): - self.unerase(w_ary.array_storage).extend(other_w) - def erase(self, items): return self._erase(items) def unerase(self, items): return self._unerase(items) + def to_object_strategy(self, space, w_ary): + pass + + def listview(self, space, w_ary): + return self.unerase(w_ary.array_storage) + + def extend(self, space, w_ary, other_w): + self.unerase(w_ary.array_storage).extend(other_w) + -class FloatArrayStrategy(ArrayStrategyMixin, ArrayStrategy): +class FloatArrayStrategy(ErasingArrayStrategyMixin, ArrayStrategy): _erase, _unerase = new_static_erasing_pair("float") padding_value = 0.0 @@ -179,7 +236,7 @@ def unerase(self, items): return self._unerase(items) -class FixnumArrayStrategy(ArrayStrategyMixin, ArrayStrategy): +class FixnumArrayStrategy(ErasingArrayStrategyMixin, ArrayStrategy): _erase, _unerase = new_static_erasing_pair("fixnum") padding_value = 0 @@ -203,30 +260,20 @@ def unerase(self, items): return self._unerase(items) -class EmptyArrayStrategy(ArrayStrategyMixin, ArrayStrategy): +class EmptyArrayStrategy(ArrayStrategy): _erase, _unerase = new_static_erasing_pair("empty") - def slice(self, space, w_ary, start, end): - return space.newarray([]) - slice_i = slice - - def listview(self, space, w_ary): - return [] - def length(self, w_ary): return 0 - def wrap(self, space, i): - raise RuntimeError("should not be called") - - def unwrap(self, space, w_i): - raise RuntimeError("should not be called") + def listview(self, space, w_ary): + return [] def checktype(self, space, w_obj): return False def store(self, space, items_w): - return self.erase(items_w) + return self.erase(None) def erase(self, items): assert not items @@ -237,7 +284,7 @@ def unerase(self, items): def adapt(self, space, w_ary, w_obj): strategy = W_ArrayObject.strategy_for_list(space, [w_obj]) - w_ary.array_storage = strategy.erase([]) + w_ary.array_storage = strategy.store(space, []) w_ary.strategy = strategy def to_empty_strategy(self, space, w_ary): @@ -273,7 +320,9 @@ def newarray(space, items_w): @staticmethod def strategy_for_list(space, items_w): - if items_w: + if not items_w: + return space.fromcache(EmptyArrayStrategy) + else: array_type = type(items_w[0]) for item in items_w: if not isinstance(item, array_type): @@ -282,8 +331,6 @@ def strategy_for_list(space, items_w): return space.fromcache(FixnumArrayStrategy) elif array_type is W_FloatObject: return space.fromcache(FloatArrayStrategy) - else: - return space.fromcache(EmptyArrayStrategy) return space.fromcache(ObjectArrayStrategy) @classdef.singleton_method("allocate") @@ -307,6 +354,8 @@ def subscript(self, space, w_idx, w_count=None): start, end, as_range, nil = space.subscript_access(self.length(), w_idx, w_count=w_count) if nil: return space.w_nil + elif self.length() == 0: + return space.newarray([]) elif as_range: assert start >= 0 assert end >= 0 @@ -467,8 +516,10 @@ def method_pop(self, space, w_num=None): )) if num < 0: raise space.error(space.w_ArgumentError, "negative array size") - else: + elif self.length() > 0: return self.strategy.pop_n(space, self, num) + else: + return space.newarray([]) @classdef.method("delete_at", idx="int") @check_frozen() From 345512803a3f24ba2d5d87a35836b9b027d08965 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 26 Mar 2013 19:33:04 +0100 Subject: [PATCH 15/37] fix signature mismatch --- topaz/objects/arrayobject.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index f5b8223ac..33279d2f4 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -45,7 +45,7 @@ def __deepcopy__(self, memo): def append(self, space, w_ary, w_obj): raise NotImplementedError - def checktype(self, space, w_obj): + def checktype(self, w_obj): raise NotImplementedError def clear(self, space, w_ary): @@ -269,7 +269,7 @@ def length(self, w_ary): def listview(self, space, w_ary): return [] - def checktype(self, space, w_obj): + def checktype(self, w_obj): return False def store(self, space, items_w): From cfc4ccd8770f254443fdfb9de0d6a277863e519e Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 26 Mar 2013 19:34:24 +0100 Subject: [PATCH 16/37] fix forgotten path --- topaz/objects/arrayobject.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 33279d2f4..b042f0b50 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -410,8 +410,8 @@ def method_slice_i(self, space, w_idx, w_count=None): if nil: return space.w_nil elif as_range: - start = min(max(start, 0), len(self.items_w)) - end = min(max(end, 0), len(self.items_w)) + start = min(max(start, 0), self.length()) + end = min(max(end, 0), self.length()) delta = (end - start) assert delta >= 0 return self.strategy.slice_i(space, self, start, start + delta) From 8beb0905ac58478f0d2512fa3e143491ada973f2 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 20 Jul 2013 19:17:57 -0700 Subject: [PATCH 17/37] start of some cleanups --- tests/objects/test_arrayobject.py | 2 +- tests/objects/test_rangeobject.py | 4 +- topaz/objects/arrayobject.py | 208 +++++++----------------------- topaz/objects/rangeobject.py | 7 - 4 files changed, 50 insertions(+), 171 deletions(-) diff --git a/tests/objects/test_arrayobject.py b/tests/objects/test_arrayobject.py index f4e410c54..dffe446c0 100644 --- a/tests/objects/test_arrayobject.py +++ b/tests/objects/test_arrayobject.py @@ -202,7 +202,7 @@ def test_dup(self, space): x, y = self.unwrap(space, w_res) assert x == [1, 2, 3, 4] assert y == [1, 2, 3] - + def test_dupf(self, space): w_res = space.execute(""" x = [1.0, 2.0, 3.0] diff --git a/tests/objects/test_rangeobject.py b/tests/objects/test_rangeobject.py index 17235b5f9..5e59e5a83 100644 --- a/tests/objects/test_rangeobject.py +++ b/tests/objects/test_rangeobject.py @@ -84,9 +84,9 @@ def test_each_returns_self(self, space): return r.each {}.equal?(r) """) assert w_res is space.w_true - + def test_array_conversion(self, space): w_res = space.execute(""" return (1..4).to_a """) - assert self.unwrap(space, w_res) == [1,2,3,4] + assert self.unwrap(space, w_res) == [1, 2, 3, 4] diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 5fda216fb..f01477c3d 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -26,25 +26,11 @@ def __init__(self, space, list, listlength=None, sortblock=None): self.sortblock = sortblock def lt(self, w_a, w_b): - # NOTE(flaper87): Review - if self.sortblock is None: - w_cmp_res = self.space.send(w_a, self.space.newsymbol("<=>"), [w_b]) - else: - w_cmp_res = self.space.invoke_block(self.sortblock, [w_a, w_b]) - if w_cmp_res is self.space.w_nil: - raise self.space.error( - self.space.w_ArgumentError, - "comparison of %s with %s failed" % - (self.space.obj_to_s(self.space.getclass(w_a)), - self.space.obj_to_s(self.space.getclass(w_b))) - ) + w_cmp_res = self.space.compare(w_a, w_b, self.sortblock) + if self.space.is_kind_of(w_cmp_res, self.space.w_bignum): + return self.space.bigint_w(w_cmp_res).lt(rbigint.fromint(0)) else: return self.space.int_w(w_cmp_res) < 0 - #w_cmp_res = self.space.compare(w_a, w_b, self.sortblock) - #if self.space.is_kind_of(w_cmp_res, self.space.w_bignum): - # return self.space.bigint_w(w_cmp_res).lt(rbigint.fromint(0)) - #else: - # return self.space.int_w(w_cmp_res) < 0 class RubySortBy(BaseRubySortBy): @@ -61,59 +47,13 @@ def lt(self, w_a, w_b): return self.space.int_w(w_cmp_res) < 0 -class ArrayStrategy(object): +class BaseArrayStrategy(object): def __init__(self, space): pass - def __deepcopy__(self, memo): - memo[id(self)] = result = object.__new__(self.__class__) - return result - - def append(self, space, w_ary, w_obj): - raise NotImplementedError - - def checktype(self, w_obj): - raise NotImplementedError - def clear(self, space, w_ary): self.to_empty_strategy(space, w_ary) - def extend(self, space, w_ary, other_w): - raise NotImplementedError - - def get_item(self, space, w_ary, idx): - raise NotImplementedError - - def insert(self, space, w_ary, idx, w_obj): - raise NotImplementedError - - def length(self, w_ary): - raise NotImplementedError - - def listview(self, space, w_ary): - raise NotImplementedError - - def padd_assign(self, space, w_ary, delta, start, end, rep_w): - raise NotImplementedError - - def pop(self, space, w_ary, idx): - raise NotImplementedError - - def pop_n(self, space, w_ary, num): - raise NotImplementedError - - def reverse_i(self, space, w_ary): - raise NotImplementedError - - def set_item(self, space, w_ary, idx, w_obj): - raise NotImplementedError - - def slice(self, space, w_ary, start, end): - raise NotImplementedError - - def slice_i(self, space, w_ary, start, end): - raise NotImplementedError - def adapt(self, space, w_ary, w_obj): if not self.checktype(w_obj): self.to_object_strategy(space, w_ary) @@ -128,7 +68,7 @@ def to_empty_strategy(self, space, w_ary): w_ary.array_storage = w_ary.strategy.erase(None) -class ErasingArrayStrategyMixin(object): +class TypedArrayStrategyMixin(object): _mixin_ = True def append(self, space, w_ary, w_obj): @@ -137,7 +77,7 @@ def append(self, space, w_ary, w_obj): def extend(self, space, w_ary, other_w): self.unerase(w_ary.array_storage).extend([self.unwrap(space, w_o) for w_o in other_w]) - def get_item(self, space, w_ary, idx): + def getitem(self, space, w_ary, idx): return self.wrap(space, self.unerase(w_ary.array_storage)[idx]) def insert(self, space, w_ary, idx, w_obj): @@ -174,13 +114,12 @@ def reverse_i(self, space, w_ary): storage = self.unerase(w_ary.array_storage) storage.reverse() - def set_item(self, space, w_ary, idx, w_obj): + def setitem(self, space, w_ary, idx, w_obj): self.unerase(w_ary.array_storage)[idx] = self.unwrap(space, w_obj) def slice(self, space, w_ary, start, end): items = self.unerase(w_ary.array_storage)[start:end] - items_w = [self.wrap(space, item) for item in items] - return space.newarray(items_w) + return self.erase(items) def slice_i(self, space, w_ary, start, end): w_items = self.slice(space, w_ary, start, end) @@ -190,6 +129,9 @@ def slice_i(self, space, w_ary, start, end): def shift(self, space, w_ary, n): return self.slice_i(space, w_ary, 0, n) + def mul(self, w_ary, n): + return self.erase(self.unerase(w_ary.array_storage) * n) + def wrap(self, space, w_obj): raise NotImplementedError @@ -206,8 +148,8 @@ def unerase(self, items): raise NotImplementedError -class ObjectArrayStrategy(ErasingArrayStrategyMixin, ArrayStrategy): - _erase, _unerase = new_static_erasing_pair("object") +class ObjectArrayStrategy(BaseArrayStrategy, TypedArrayStrategyMixin): + erase, unerase = new_static_erasing_pair("object") padding_value = None def wrap(self, space, w_obj): @@ -223,12 +165,6 @@ def store(self, space, items_w): l = [self.unwrap(space, w_o) for w_o in items_w] return self.erase(l) - def erase(self, items): - return self._erase(items) - - def unerase(self, items): - return self._unerase(items) - def to_object_strategy(self, space, w_ary): pass @@ -239,8 +175,8 @@ def extend(self, space, w_ary, other_w): self.unerase(w_ary.array_storage).extend(other_w) -class FloatArrayStrategy(ErasingArrayStrategyMixin, ArrayStrategy): - _erase, _unerase = new_static_erasing_pair("float") +class FloatArrayStrategy(BaseArrayStrategy, TypedArrayStrategyMixin): + erase, unerase = new_static_erasing_pair("FloatArrayStrategy") padding_value = 0.0 def wrap(self, space, f): @@ -256,15 +192,9 @@ def store(self, space, items_w): l = [self.unwrap(space, w_o) for w_o in items_w] return self.erase(l) - def erase(self, items): - return self._erase(items) - def unerase(self, items): - return self._unerase(items) - - -class FixnumArrayStrategy(ErasingArrayStrategyMixin, ArrayStrategy): - _erase, _unerase = new_static_erasing_pair("fixnum") +class FixnumArrayStrategy(BaseArrayStrategy, TypedArrayStrategyMixin): + erase, unerase = new_static_erasing_pair("FixnumArrayStrategy") padding_value = 0 def wrap(self, space, i): @@ -280,15 +210,9 @@ def store(self, space, items_w): l = [self.unwrap(space, w_o) for w_o in items_w] return self.erase(l) - def erase(self, items): - return self._erase(items) - - def unerase(self, items): - return self._unerase(items) - -class EmptyArrayStrategy(ArrayStrategy): - _erase, _unerase = new_static_erasing_pair("empty") +class EmptyArrayStrategy(BaseArrayStrategy): + _erase, _unerase = new_static_erasing_pair("EmptyArrayStrategy") def length(self, w_ary): return 0 @@ -322,7 +246,7 @@ class W_ArrayObject(W_Object): classdef = ClassDef("Array", W_Object.classdef) classdef.include_module(Enumerable) - def __init__(self, space, storage, strategy, klass=None): + def __init__(self, space, strategy, storage, klass=None): W_Object.__init__(self, space, klass) self.strategy = strategy self.array_storage = storage @@ -343,30 +267,31 @@ def length(self): def newarray(space, items_w): strategy = W_ArrayObject.strategy_for_list(space, items_w) storage = strategy.store(space, items_w) - return W_ArrayObject(space, storage, strategy) + return W_ArrayObject(space, strategy, storage) @staticmethod def strategy_for_list(space, items_w): if not items_w: return space.fromcache(EmptyArrayStrategy) + + for w_item in items_w: + if not space.is_kind_of(w_item, space.w_fixnum): + break else: - array_type = type(items_w[0]) - for item in items_w: - if not isinstance(item, array_type): - return space.fromcache(ObjectArrayStrategy) - if array_type is W_FixnumObject: - return space.fromcache(FixnumArrayStrategy) - elif array_type is W_FloatObject: - return space.fromcache(FloatArrayStrategy) - return space.fromcache(ObjectArrayStrategy) + return space.fromcache(FixnumArrayStrategy) - def length(self): - return len(self.items_w) + for w_item in items_w: + if not space.is_kind_of(w_item, space.w_float): + break + else: + return space.fromcache(FloatArrayStrategy) + + return space.fromcache(ObjectArrayStrategy) @classdef.singleton_method("allocate") def singleton_method_allocate(self, space): - return W_ArrayObject(space, [], self) - #return space.newarray([]) + stragegy = space.fromcache(EmptyArrayStrategy) + return W_ArrayObject(space, stragegy, stragegy.erase(None), self) def replace(self, space, other_w): self.strategy = W_ArrayObject.strategy_for_list(space, other_w) @@ -390,11 +315,10 @@ def method_subscript(self, space, w_idx, w_count=None): elif as_range: assert start >= 0 assert end >= 0 - return self.strategy.slice(space, self, start, end) - # NOTE(flaper87): Use the strategy - #return W_ArrayObject(space, self.items_w[start:end], space.getnonsingletonclass(self)) + data = self.strategy.slice(space, self, start, end) + return W_ArrayObject(space, self.strategy, data, space.getnonsingletonclass(self)) else: - return self.strategy.get_item(space, self, start) + return self.strategy.getitem(space, self, start) @classdef.method("[]=") @check_frozen() @@ -420,11 +344,7 @@ def method_subscript_assign(self, space, w_idx, w_count_or_obj, w_obj=None): elif start >= self.length(): self.strategy.adapt(space, self, space.w_nil) self.strategy.extend(space, self, [space.w_nil] * (start - self.length() + 1)) - self.strategy.set_item(space, self, start, w_obj) - - # NOTE(flaper87): Use the strategy - #self.items_w += [space.w_nil] * (start - self.length() + 1) - #self.items_w[start] = w_obj + self.strategy.setitem(space, self, start, w_obj) elif as_range: w_converted = space.convert_type(w_obj, space.w_array, "to_ary", raise_error=False) if w_converted is space.w_nil: @@ -435,27 +355,11 @@ def method_subscript_assign(self, space, w_idx, w_count_or_obj, w_obj=None): self.strategy.adapt(space, self, each) delta = (end - start) - len(rep_w) self.strategy.padd_assign(space, self, delta, start, end, rep_w) - # NOTE(flaper87): USe the strategy - #self._subscript_assign_range(space, start, end, rep_w) else: self.strategy.adapt(space, self, w_obj) - self.strategy.set_item(space, self, start, w_obj) + self.strategy.setitem(space, self, start, w_obj) return w_obj - def _subscript_assign_range(self, space, start, end, rep_w): - assert end >= 0 - delta = (end - start) - len(rep_w) - if delta < 0: - self.items_w += [None] * -delta - lim = start + len(rep_w) - i = self.length() - 1 - while i >= lim: - self.items_w[i] = self.items_w[i + delta] - i -= 1 - elif delta > 0: - del self.items_w[start:start + delta] - self.items_w[start:start + len(rep_w)] = rep_w - @classdef.method("slice!") @check_frozen() def method_slice_i(self, space, w_idx, w_count=None): @@ -512,7 +416,7 @@ def method_times(self, space, w_other): n = space.int_w(space.convert_type(w_other, space.w_fixnum, "to_int")) if n < 0: raise space.error(space.w_ArgumentError, "Count cannot be negative") - w_res = W_ArrayObject(space, self.items_w * n, space.getnonsingletonclass(self)) + w_res = W_ArrayObject(space, self.strategy, self.strategy.mul(self, n), space.getnonsingletonclass(self)) space.infect(w_res, self, freeze=False) return w_res @@ -538,19 +442,14 @@ def method_shift(self, space, w_n=None): @classdef.method("unshift") @check_frozen() def method_unshift(self, space, args_w): - for i in xrange(len(args_w) - 1, -1, -1): - w_obj = args_w[i] + for w_obj in reversed(args_w): self.strategy.adapt(space, self, w_obj) self.strategy.insert(space, self, 0, w_obj) - # NOTE(flaper87): Use strategy, - # Review this code - #for w_obj in reversed(args_w): - # self.items_w.insert(0, w_obj) return self @classdef.method("join") def method_join(self, space, w_sep=None): - if not self.listview(space): + if not self.length(): return space.newstr_fromstr("") if w_sep is None: separator = "" @@ -561,14 +460,8 @@ def method_join(self, space, w_sep=None): "can't convert %s into String" % space.getclass(w_sep).name ) return space.newstr_fromstr(separator.join([ - space.str_w(space.send(w_o, space.newsymbol("to_s"))) + space.str_w(space.send(w_o, "to_s")) for w_o in self.listview(space) - - # NOTE(flaper87): The above seems right, - # It iterates over an unreased array and - # uses the strategy. - #space.str_w(space.send(w_o, "to_s")) - #for w_o in self.items_w ])) @classdef.method("pop") @@ -586,12 +479,8 @@ def method_pop(self, space, w_num=None): if num < 0: raise space.error(space.w_ArgumentError, "negative array size") elif self.length() > 0: - return self.strategy.pop_n(space, self, num) - # NOTE(flaper87): Use strategy - #pop_size = max(0, self.length() - num) - #res_w = self.items_w[pop_size:] - #del self.items_w[pop_size:] - #return space.newarray(res_w) + data = self.strategy.pop_n(space, self, num) + return W_ArrayObject(space, self.strategy, data, space.w_array) else: return space.newarray([]) @@ -619,10 +508,7 @@ def method_last(self, space, w_count=None): if self.length() == 0: return space.w_nil else: - return self.listview(space)[self.length() - 1] - # NOTE(flaper87): The above seems correct and - # uses strategy's storage - #return self.items_w[self.length() - 1] + return self.strategy.getitem(space, self, self.length() - 1) @classdef.method("pack") def method_pack(self, space, w_template): diff --git a/topaz/objects/rangeobject.py b/topaz/objects/rangeobject.py index 96568afb1..513de0ada 100644 --- a/topaz/objects/rangeobject.py +++ b/topaz/objects/rangeobject.py @@ -39,10 +39,3 @@ def method_end(self, space): @classdef.method("exclude_end?") def method_exclude_end(self, space): return space.newbool(self.exclusive) - - @classdef.method("to_a") - def method_to_a(self, space): - start, end = space.int_w(self.w_start), space.int_w(self.w_end) - if not self.exclusive: - end += 1 - return space.newarray([space.newint(i) for i in range(start, end)]) From c11c786294d63e74caa14cfe188337950dc7f176 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 20 Jul 2013 19:26:41 -0700 Subject: [PATCH 18/37] some type fixups --- topaz/objects/arrayobject.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index f01477c3d..082866120 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -122,9 +122,10 @@ def slice(self, space, w_ary, start, end): return self.erase(items) def slice_i(self, space, w_ary, start, end): - w_items = self.slice(space, w_ary, start, end) - del self.unerase(w_ary.array_storage)[start:end] - return w_items + storage = self.unerase(w_ary.array_storage) + items = storage[start:end] + del storage[start:end] + return self.erase(items) def shift(self, space, w_ary, n): return self.slice_i(space, w_ary, 0, n) @@ -372,7 +373,8 @@ def method_slice_i(self, space, w_idx, w_count=None): end = min(max(end, 0), self.length()) delta = (end - start) assert delta >= 0 - return self.strategy.slice_i(space, self, start, start + delta) + data = self.strategy.slice_i(space, self, start, start + delta) + return W_ArrayObject(space, self.strategy, data) else: return self.strategy.pop(space, self, start) @@ -437,7 +439,8 @@ def method_shift(self, space, w_n=None): n = space.int_w(space.convert_type(w_n, space.w_fixnum, "to_int")) if n < 0: raise space.error(space.w_ArgumentError, "negative array size") - return self.strategy.shift(space, self, n) + data = self.strategy.shift(space, self, n) + return W_ArrayObject(space, self.strategy, data) @classdef.method("unshift") @check_frozen() @@ -480,7 +483,7 @@ def method_pop(self, space, w_num=None): raise space.error(space.w_ArgumentError, "negative array size") elif self.length() > 0: data = self.strategy.pop_n(space, self, num) - return W_ArrayObject(space, self.strategy, data, space.w_array) + return W_ArrayObject(space, self.strategy, data) else: return space.newarray([]) From b237b93d803110eb2e4f0f9fde04ad5fd302a192 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 20 Jul 2013 19:42:36 -0700 Subject: [PATCH 19/37] start on some cleanup --- topaz/objects/arrayobject.py | 70 ++++++++++++------------------------ 1 file changed, 22 insertions(+), 48 deletions(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 082866120..35a8c6afa 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -1,7 +1,6 @@ import copy from rpython.rlib import jit -from rpython.rlib.listsort import TimSort from rpython.rlib.listsort import make_timsort_class from rpython.rlib.rerased import new_static_erasing_pair from rpython.rlib.rbigint import rbigint @@ -89,47 +88,21 @@ def length(self, w_ary): def listview(self, space, w_ary): return [self.wrap(space, item) for item in self.unerase(w_ary.array_storage)] - def padd_assign(self, space, w_ary, delta, start, end, rep_w): - storage = self.unerase(w_ary.array_storage) - if delta < 0: - storage += [self.padding_value] * -delta - lim = start + len(rep_w) - i = len(storage) - 1 - while i >= lim: - storage[i] = storage[i + delta] - i -= 1 - elif delta > 0: - del storage[start:start + delta] - storage[start:start + len(rep_w)] = [self.unwrap(space, w_obj) for w_obj in rep_w] - def pop(self, space, w_ary, idx): storage = self.unerase(w_ary.array_storage) return self.wrap(space, storage.pop(idx)) - def pop_n(self, space, w_ary, num): - pop_size = max(0, self.length(w_ary) - num) - return self.slice_i(space, w_ary, pop_size, self.length(w_ary)) - - def reverse_i(self, space, w_ary): + def reverse(self, space, w_ary): storage = self.unerase(w_ary.array_storage) storage.reverse() def setitem(self, space, w_ary, idx, w_obj): self.unerase(w_ary.array_storage)[idx] = self.unwrap(space, w_obj) - def slice(self, space, w_ary, start, end): + def getslice(self, space, w_ary, start, end): items = self.unerase(w_ary.array_storage)[start:end] return self.erase(items) - def slice_i(self, space, w_ary, start, end): - storage = self.unerase(w_ary.array_storage) - items = storage[start:end] - del storage[start:end] - return self.erase(items) - - def shift(self, space, w_ary, n): - return self.slice_i(space, w_ary, 0, n) - def mul(self, w_ary, n): return self.erase(self.unerase(w_ary.array_storage) * n) @@ -139,9 +112,6 @@ def wrap(self, space, w_obj): def unwrap(self, space, w_obj): raise NotImplementedError - def store(self, space, items_w): - raise NotImplementedError - def erase(self, items): raise NotImplementedError @@ -151,7 +121,6 @@ def unerase(self, items): class ObjectArrayStrategy(BaseArrayStrategy, TypedArrayStrategyMixin): erase, unerase = new_static_erasing_pair("object") - padding_value = None def wrap(self, space, w_obj): return w_obj @@ -178,7 +147,6 @@ def extend(self, space, w_ary, other_w): class FloatArrayStrategy(BaseArrayStrategy, TypedArrayStrategyMixin): erase, unerase = new_static_erasing_pair("FloatArrayStrategy") - padding_value = 0.0 def wrap(self, space, f): return space.newfloat(f) @@ -196,7 +164,6 @@ def store(self, space, items_w): class FixnumArrayStrategy(BaseArrayStrategy, TypedArrayStrategyMixin): erase, unerase = new_static_erasing_pair("FixnumArrayStrategy") - padding_value = 0 def wrap(self, space, i): return space.newint(i) @@ -352,15 +319,28 @@ def method_subscript_assign(self, space, w_idx, w_count_or_obj, w_obj=None): rep_w = [w_obj] else: rep_w = space.listview(w_converted) - for each in rep_w: - self.strategy.adapt(space, self, each) - delta = (end - start) - len(rep_w) - self.strategy.padd_assign(space, self, delta, start, end, rep_w) + self._subscript_assign_range(space, start, end, rep_w) else: self.strategy.adapt(space, self, w_obj) self.strategy.setitem(space, self, start, w_obj) return w_obj + def _subscript_assign_range(self, space, start, end, rep_w): + assert end >= 0 + delta = (end - start) - len(rep_w) + if delta < 0: + for i in xrange(-delta): + self.strategy.append_empty(self) + lim = start + len(rep_w) + i = self.length() - 1 + while i >= lim: + self.strategy.setitem(space, self, i, self.strategy.getitem(space, self, i + delta)) + i -= 1 + elif delta > 0: + self.strategy.delitems(space, self, start, start + delta) + for i, w_obj in enumerate(rep_w): + self.strategy.setitem(space, self, i + start, w_obj) + @classdef.method("slice!") @check_frozen() def method_slice_i(self, space, w_idx, w_count=None): @@ -534,13 +514,7 @@ def method_clear(self, space): @check_frozen() @classdef.method("sort!") def method_sort_i(self, space, block): - strategy = self.strategy - if strategy is space.fromcache(ObjectArrayStrategy): - RubySorter(space, strategy.unerase(self.array_storage), sortblock=block).sort() - else: - items_w = self.listview(space) - RubySorter(space, items_w, sortblock=block).sort() - self.replace(space, items_w) + self.strategy.sort(space, self, block) return self @classdef.method("sort_by!") @@ -548,13 +522,13 @@ def method_sort_i(self, space, block): def method_sort_by_i(self, space, block): if block is None: return space.send(self, "enum_for", [space.newsymbol("sort_by!")]) - RubySortBy(space, self.items_w, sortblock=block).sort() + self.strategy.sort_by(space, self, block) return self @classdef.method("reverse!") @check_frozen() def method_reverse_i(self, space): - self.strategy.reverse_i(space, self) + self.strategy.reverse(space, self) return self @classdef.method("rotate!", n="int") From 6bca7e7fd6fcdd08738e48a993cccdb7bd2d26fc Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 20 Jul 2013 21:46:55 -0700 Subject: [PATCH 20/37] more cleanups --- topaz/objects/arrayobject.py | 179 +++++++++++++++++++---------------- 1 file changed, 95 insertions(+), 84 deletions(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 35a8c6afa..90cfcd5a4 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -10,8 +10,6 @@ from topaz.modules.enumerable import Enumerable from topaz.objects.objectobject import W_Object from topaz.utils.packing.pack import RPacker -from topaz.objects.floatobject import W_FloatObject -from topaz.objects.intobject import W_FixnumObject BaseRubySorter = make_timsort_class() @@ -50,41 +48,54 @@ class BaseArrayStrategy(object): def __init__(self, space): pass - def clear(self, space, w_ary): - self.to_empty_strategy(space, w_ary) - - def adapt(self, space, w_ary, w_obj): - if not self.checktype(w_obj): - self.to_object_strategy(space, w_ary) - - def to_object_strategy(self, space, w_ary): + def switch_to_object_strategy(self, space, w_ary): obj_strategy = space.fromcache(ObjectArrayStrategy) w_ary.array_storage = obj_strategy.erase(self.listview(space, w_ary)) w_ary.strategy = obj_strategy - def to_empty_strategy(self, space, w_ary): - w_ary.strategy = space.fromcache(EmptyArrayStrategy) - w_ary.array_storage = w_ary.strategy.erase(None) - class TypedArrayStrategyMixin(object): _mixin_ = True - def append(self, space, w_ary, w_obj): - self.unerase(w_ary.array_storage).append(self.unwrap(space, w_obj)) + def get_empty_storage(self): + return self.erase([]) - def extend(self, space, w_ary, other_w): - self.unerase(w_ary.array_storage).extend([self.unwrap(space, w_o) for w_o in other_w]) + def length(self, w_ary): + return len(self.unerase(w_ary.array_storage)) def getitem(self, space, w_ary, idx): return self.wrap(space, self.unerase(w_ary.array_storage)[idx]) + def getslice(self, space, w_ary, start, end): + return self.erase(self.unerase(w_ary.array_storage)[start:end]) + + def setitem(self, space, w_ary, idx, w_obj): + if self.is_correct_type(space, w_obj): + self.unerase(w_ary.array_storage)[idx] = self.unwrap(space, w_obj) + else: + self.switch_to_object_strategy(space, w_ary) + w_ary.strategy.setitem(space, w_ary, idx, w_obj) + + def delslice(self, space, w_ary, start, end): + del self.unerase(w_ary.array_storage)[start:end] + + def append(self, space, w_ary, w_obj): + if self.is_correct_type(space, w_obj): + self.unerase(w_ary.array_storage).append(self.unwrap(space, w_obj)) + else: + self.switch_to_object_strategy(space, w_ary) + w_ary.append(space, w_obj) + + def append_empty(self, w_ary): + self.unerase(w_ary.array_storage).append(self.empty_value) + + def extend(self, space, w_ary, other_w): + for w_o in other_w: + w_ary.append(space, w_o) + def insert(self, space, w_ary, idx, w_obj): self.unerase(w_ary.array_storage).insert(idx, self.unwrap(space, w_obj)) - def length(self, w_ary): - return len(self.unerase(w_ary.array_storage)) - def listview(self, space, w_ary): return [self.wrap(space, item) for item in self.unerase(w_ary.array_storage)] @@ -96,16 +107,15 @@ def reverse(self, space, w_ary): storage = self.unerase(w_ary.array_storage) storage.reverse() - def setitem(self, space, w_ary, idx, w_obj): - self.unerase(w_ary.array_storage)[idx] = self.unwrap(space, w_obj) - - def getslice(self, space, w_ary, start, end): - items = self.unerase(w_ary.array_storage)[start:end] - return self.erase(items) + def clear(self, space, w_ary): + del self.unerase(w_ary.array_storage)[:] def mul(self, w_ary, n): return self.erase(self.unerase(w_ary.array_storage) * n) + def sort(self, space, w_ary, block): + raise space.error(space.w_NotImplementedError, "Array#sort") + def wrap(self, space, w_obj): raise NotImplementedError @@ -121,6 +131,7 @@ def unerase(self, items): class ObjectArrayStrategy(BaseArrayStrategy, TypedArrayStrategyMixin): erase, unerase = new_static_erasing_pair("object") + empty_value = None def wrap(self, space, w_obj): return w_obj @@ -128,13 +139,9 @@ def wrap(self, space, w_obj): def unwrap(self, space, w_obj): return w_obj - def checktype(self, w_obj): + def is_correct_type(self, space, w_obj): return True - def store(self, space, items_w): - l = [self.unwrap(space, w_o) for w_o in items_w] - return self.erase(l) - def to_object_strategy(self, space, w_ary): pass @@ -147,6 +154,7 @@ def extend(self, space, w_ary, other_w): class FloatArrayStrategy(BaseArrayStrategy, TypedArrayStrategyMixin): erase, unerase = new_static_erasing_pair("FloatArrayStrategy") + empty_value = 0.0 def wrap(self, space, f): return space.newfloat(f) @@ -154,16 +162,13 @@ def wrap(self, space, f): def unwrap(self, space, w_f): return space.float_w(w_f) - def checktype(self, w_obj): - return isinstance(w_obj, W_FloatObject) - - def store(self, space, items_w): - l = [self.unwrap(space, w_o) for w_o in items_w] - return self.erase(l) + def is_correct_type(self, space, w_obj): + return space.is_kind_of(w_obj, space.w_float) class FixnumArrayStrategy(BaseArrayStrategy, TypedArrayStrategyMixin): erase, unerase = new_static_erasing_pair("FixnumArrayStrategy") + empty_value = 0 def wrap(self, space, i): return space.newint(i) @@ -171,16 +176,25 @@ def wrap(self, space, i): def unwrap(self, space, w_i): return space.int_w(w_i) - def checktype(self, w_obj): - return isinstance(w_obj, W_FixnumObject) - - def store(self, space, items_w): - l = [self.unwrap(space, w_o) for w_o in items_w] - return self.erase(l) + def is_correct_type(self, space, w_obj): + return space.is_kind_of(w_obj, space.w_fixnum) class EmptyArrayStrategy(BaseArrayStrategy): - _erase, _unerase = new_static_erasing_pair("EmptyArrayStrategy") + erase, unerase = new_static_erasing_pair("EmptyArrayStrategy") + + def switch_to_correct_strategy(self, space, w_ary, w_obj): + if space.is_kind_of(w_obj, space.w_fixnum): + strategy = space.fromcache(FixnumArrayStrategy) + elif space.is_kind_of(w_obj, space.w_float): + strategy = space.fromcache(FloatArrayStrategy) + else: + strategy = space.fromcache(ObjectArrayStrategy) + w_ary.strategy = strategy + w_ary.array_storage = strategy.get_empty_storage() + + def get_empty_storage(self): + return self.erase(None) def length(self, w_ary): return 0 @@ -188,25 +202,25 @@ def length(self, w_ary): def listview(self, space, w_ary): return [] - def checktype(self, w_obj): + def is_correct_type(self, w_obj): return False - def store(self, space, items_w): - return self.erase(None) - - def erase(self, items): - assert not items - return self._erase(None) + def append(self, space, w_ary, w_obj): + self.switch_to_correct_strategy(space, w_ary, w_obj) + w_ary.strategy.append(space, w_ary, w_obj) - def unerase(self, items): - return self._unerase(items) + def insert(self, space, w_ary, idx, w_obj): + self.append(space, w_ary, w_obj) - def adapt(self, space, w_ary, w_obj): - strategy = W_ArrayObject.strategy_for_list(space, [w_obj]) - w_ary.array_storage = strategy.store(space, []) + def extend(self, space, w_ary, other_w): + if not other_w: + return + strategy = W_ArrayObject.strategy_for_list(space, other_w) w_ary.strategy = strategy + w_ary.array_storage = strategy.get_empty_storage() + w_ary.strategy.extend(space, w_ary, other_w) - def to_empty_strategy(self, space, w_ary): + def clear(self, space, w_ary): pass @@ -231,11 +245,15 @@ def listview(self, space): def length(self): return self.strategy.length(self) + def append(self, space, w_obj): + self.strategy.append(space, self, w_obj) + @staticmethod def newarray(space, items_w): - strategy = W_ArrayObject.strategy_for_list(space, items_w) - storage = strategy.store(space, items_w) - return W_ArrayObject(space, strategy, storage) + strategy = space.fromcache(EmptyArrayStrategy) + w_ary = W_ArrayObject(space, strategy, strategy.get_empty_storage()) + w_ary.strategy.extend(space, w_ary, items_w) + return w_ary @staticmethod def strategy_for_list(space, items_w): @@ -258,12 +276,13 @@ def strategy_for_list(space, items_w): @classdef.singleton_method("allocate") def singleton_method_allocate(self, space): - stragegy = space.fromcache(EmptyArrayStrategy) - return W_ArrayObject(space, stragegy, stragegy.erase(None), self) + strategy = space.fromcache(EmptyArrayStrategy) + return W_ArrayObject(space, strategy, strategy.get_empty_storage(), self) def replace(self, space, other_w): self.strategy = W_ArrayObject.strategy_for_list(space, other_w) - self.array_storage = self.strategy.store(space, other_w) + self.array_storage = self.strategy.get_empty_storage() + self.strategy.extend(space, self, other_w) @classdef.method("initialize_copy", other_w="array") @classdef.method("replace", other_w="array") @@ -283,7 +302,7 @@ def method_subscript(self, space, w_idx, w_count=None): elif as_range: assert start >= 0 assert end >= 0 - data = self.strategy.slice(space, self, start, end) + data = self.strategy.getslice(space, self, start, end) return W_ArrayObject(space, self.strategy, data, space.getnonsingletonclass(self)) else: return self.strategy.getitem(space, self, start) @@ -310,7 +329,6 @@ def method_subscript_assign(self, space, w_idx, w_count_or_obj, w_obj=None): ) ) elif start >= self.length(): - self.strategy.adapt(space, self, space.w_nil) self.strategy.extend(space, self, [space.w_nil] * (start - self.length() + 1)) self.strategy.setitem(space, self, start, w_obj) elif as_range: @@ -321,7 +339,6 @@ def method_subscript_assign(self, space, w_idx, w_count_or_obj, w_obj=None): rep_w = space.listview(w_converted) self._subscript_assign_range(space, start, end, rep_w) else: - self.strategy.adapt(space, self, w_obj) self.strategy.setitem(space, self, start, w_obj) return w_obj @@ -337,7 +354,7 @@ def _subscript_assign_range(self, space, start, end, rep_w): self.strategy.setitem(space, self, i, self.strategy.getitem(space, self, i + delta)) i -= 1 elif delta > 0: - self.strategy.delitems(space, self, start, start + delta) + self.strategy.delslice(space, self, start, start + delta) for i, w_obj in enumerate(rep_w): self.strategy.setitem(space, self, i + start, w_obj) @@ -374,21 +391,13 @@ def method_add(self, space, other): @classdef.method("<<") @check_frozen() def method_lshift(self, space, w_obj): - self.strategy.adapt(space, self, w_obj) - self.strategy.append(space, self, w_obj) + self.append(space, w_obj) return self - def concat(self, space, other_w): - strategy = self.strategy_for_list(space, other_w) - if self.strategy is not strategy: - self.array_storage = strategy.store(space, self.listview(space)) - self.strategy = strategy - self.strategy.extend(space, self, other_w) - @classdef.method("concat", other_w="array") @check_frozen() def method_concat(self, space, other_w): - self.concat(space, other_w) + self.strategy.extend(space, self, other_w) return self @classdef.method("*") @@ -405,7 +414,7 @@ def method_times(self, space, w_other): @classdef.method("push") @check_frozen() def method_push(self, space, args_w): - self.concat(space, args_w) + self.strategy.extend(space, self, args_w) return self @classdef.method("shift") @@ -419,14 +428,14 @@ def method_shift(self, space, w_n=None): n = space.int_w(space.convert_type(w_n, space.w_fixnum, "to_int")) if n < 0: raise space.error(space.w_ArgumentError, "negative array size") - data = self.strategy.shift(space, self, n) + data = self.strategy.getslice(space, self, 0, n) + self.strategy.delslice(space, self, 0, n) return W_ArrayObject(space, self.strategy, data) @classdef.method("unshift") @check_frozen() def method_unshift(self, space, args_w): for w_obj in reversed(args_w): - self.strategy.adapt(space, self, w_obj) self.strategy.insert(space, self, 0, w_obj) return self @@ -462,7 +471,9 @@ def method_pop(self, space, w_num=None): if num < 0: raise space.error(space.w_ArgumentError, "negative array size") elif self.length() > 0: - data = self.strategy.pop_n(space, self, num) + pop_size = max(0, self.length() - num) + data = self.strategy.getslice(space, self, pop_size, self.length()) + self.strategy.delslice(space, self, pop_size, self.length()) return W_ArrayObject(space, self.strategy, data) else: return space.newarray([]) @@ -557,7 +568,7 @@ def method_insert(self, space, i, args_w): length = self.length() if i > length: self._append_nils(space, i - length) - self.items_w.extend(args_w) + self.strategy.extend(space, self, args_w) return self if i < 0: if i < -length - 1: @@ -573,4 +584,4 @@ def method_insert(self, space, i, args_w): def _append_nils(self, space, num): for _ in xrange(num): - self.items_w.append(space.w_nil) + self.append(space, space.w_nil) From 96655c37ff45677c49e1a1d4cabd329ec5408f92 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 20 Jul 2013 21:53:24 -0700 Subject: [PATCH 21/37] fix --- topaz/objects/arrayobject.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 90cfcd5a4..128e16aa0 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -370,7 +370,8 @@ def method_slice_i(self, space, w_idx, w_count=None): end = min(max(end, 0), self.length()) delta = (end - start) assert delta >= 0 - data = self.strategy.slice_i(space, self, start, start + delta) + data = self.strategy.getslice(space, self, start, start + delta) + self.strategy.delslice(space, self, start, start + delta) return W_ArrayObject(space, self.strategy, data) else: return self.strategy.pop(space, self, start) From e22e6c54f8281688c89442d59c67702127f57262 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 20 Jul 2013 21:56:15 -0700 Subject: [PATCH 22/37] stub out --- topaz/objects/arrayobject.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 128e16aa0..54937520c 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -116,6 +116,9 @@ def mul(self, w_ary, n): def sort(self, space, w_ary, block): raise space.error(space.w_NotImplementedError, "Array#sort") + def sort_by(self, space, w_ary, block): + raise space.error(space.w_NotImplementedError, "Array#sort_by") + def wrap(self, space, w_obj): raise NotImplementedError From 86926dc10fde339e71897069a993042d0eb52881 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sat, 20 Jul 2013 22:06:51 -0700 Subject: [PATCH 23/37] remove the last of items_w --- topaz/objects/arrayobject.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 54937520c..20d72f291 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -93,6 +93,9 @@ def extend(self, space, w_ary, other_w): for w_o in other_w: w_ary.append(space, w_o) + def extend_from_storage(self, space, w_ary, data): + self.unerase(w_ary.array_storage).extend(self.unerase(data)) + def insert(self, space, w_ary, idx, w_obj): self.unerase(w_ary.array_storage).insert(idx, self.unwrap(space, w_obj)) @@ -559,8 +562,8 @@ def method_rotate_i(self, space, n=1): if n == 0: return self assert n >= 0 - self.items_w.extend(self.items_w[:n]) - del self.items_w[:n] + self.strategy.extend_from_storage(space, self, self.strategy.getslice(space, self, 0, n)) + self.strategy.delslice(space, self, 0, n) return self @classdef.method("insert", i="int") @@ -582,7 +585,7 @@ def method_insert(self, space, i, args_w): i += length + 1 assert i >= 0 for w_e in args_w: - self.items_w.insert(i, w_e) + self.strategy.insert(space, self, i, w_e) i += 1 return self From e6099134d6080e760a7a0be1ae980a29743b7f94 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 21 Jul 2013 11:13:36 -0700 Subject: [PATCH 24/37] make sorting work, still need the optimized version --- topaz/objects/arrayobject.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 20d72f291..e61b30e55 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -117,7 +117,10 @@ def mul(self, w_ary, n): return self.erase(self.unerase(w_ary.array_storage) * n) def sort(self, space, w_ary, block): - raise space.error(space.w_NotImplementedError, "Array#sort") + # TODO: this should use an unboxed sorter if <=> has not been + # overwritten on the appropriate type + self.switch_to_object_strategy(space, w_ary) + w_ary.strategy.sort(space, w_ary, block) def sort_by(self, space, w_ary, block): raise space.error(space.w_NotImplementedError, "Array#sort_by") @@ -148,15 +151,15 @@ def unwrap(self, space, w_obj): def is_correct_type(self, space, w_obj): return True - def to_object_strategy(self, space, w_ary): - pass - def listview(self, space, w_ary): return self.unerase(w_ary.array_storage) def extend(self, space, w_ary, other_w): self.unerase(w_ary.array_storage).extend(other_w) + def sort(self, space, w_ary, block): + RubySorter(space, self.unerase(w_ary.array_storage), sortblock=block).sort() + class FloatArrayStrategy(BaseArrayStrategy, TypedArrayStrategyMixin): erase, unerase = new_static_erasing_pair("FloatArrayStrategy") @@ -229,6 +232,9 @@ def extend(self, space, w_ary, other_w): def clear(self, space, w_ary): pass + def sort(self, space, w_ary, block): + pass + class W_ArrayObject(W_Object): classdef = ClassDef("Array", W_Object.classdef) From 3c165ec0c61a8a69abc6067ce2be43fdc44da64b Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 21 Jul 2013 11:26:16 -0700 Subject: [PATCH 25/37] fix types --- topaz/objects/arrayobject.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index e61b30e55..7000abc67 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -97,7 +97,11 @@ def extend_from_storage(self, space, w_ary, data): self.unerase(w_ary.array_storage).extend(self.unerase(data)) def insert(self, space, w_ary, idx, w_obj): - self.unerase(w_ary.array_storage).insert(idx, self.unwrap(space, w_obj)) + if self.is_correct_type(space, w_obj): + self.unerase(w_ary.array_storage).insert(idx, self.unwrap(space, w_obj)) + else: + self.switch_to_object_strategy(space, w_ary) + w_ary.strategy.insert(space, w_ary, idx, w_obj) def listview(self, space, w_ary): return [self.wrap(space, item) for item in self.unerase(w_ary.array_storage)] From a7b63c4037e91e42444921d86b082e6235b40f6c Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 21 Jul 2013 11:45:43 -0700 Subject: [PATCH 26/37] EmptyArrayStorage.mul --- topaz/objects/arrayobject.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 7000abc67..f56444bb9 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -239,6 +239,9 @@ def clear(self, space, w_ary): def sort(self, space, w_ary, block): pass + def mul(self, w_ary, n): + return w_ary.array_storage + class W_ArrayObject(W_Object): classdef = ClassDef("Array", W_Object.classdef) From 6fd533a03aea947525183d5ec3703701369a8a89 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 21 Jul 2013 12:02:53 -0700 Subject: [PATCH 27/37] EmptyArrayStorage.reverse --- topaz/objects/arrayobject.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index f56444bb9..58ef8cc6f 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -236,6 +236,9 @@ def extend(self, space, w_ary, other_w): def clear(self, space, w_ary): pass + def reverse(self, space, w_ary): + pass + def sort(self, space, w_ary, block): pass From 10ff4aeeb4bc239d483fdd52b2e61fdd81501f33 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 21 Jul 2013 12:13:30 -0700 Subject: [PATCH 28/37] EmptyArrayStorage.getslice --- topaz/objects/arrayobject.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 58ef8cc6f..5e8f5a094 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -218,6 +218,9 @@ def listview(self, space, w_ary): def is_correct_type(self, w_obj): return False + def getslice(self, space, w_ary, start, end): + return w_ary.array_storage + def append(self, space, w_ary, w_obj): self.switch_to_correct_strategy(space, w_ary, w_obj) w_ary.strategy.append(space, w_ary, w_obj) From 2e102831b9e18b84a0acb747038d67ed0e5f7a6c Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 21 Jul 2013 12:23:15 -0700 Subject: [PATCH 29/37] EmptyArrayStrategy.delslice --- topaz/objects/arrayobject.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 5e8f5a094..8214fd822 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -221,6 +221,9 @@ def is_correct_type(self, w_obj): def getslice(self, space, w_ary, start, end): return w_ary.array_storage + def delslice(self, space, w_ary, start, end): + pass + def append(self, space, w_ary, w_obj): self.switch_to_correct_strategy(space, w_ary, w_obj) w_ary.strategy.append(space, w_ary, w_obj) From 38221a4add84d77a68d68def8660f12628657370 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 21 Jul 2013 13:04:16 -0700 Subject: [PATCH 30/37] sort_by --- topaz/objects/arrayobject.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 8214fd822..7fe528977 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -127,7 +127,10 @@ def sort(self, space, w_ary, block): w_ary.strategy.sort(space, w_ary, block) def sort_by(self, space, w_ary, block): - raise space.error(space.w_NotImplementedError, "Array#sort_by") + # TODO: this should use an unboxed sorter if <=> has not been + # overwritten on the appropriate type + self.switch_to_object_strategy(space, w_ary) + w_ary.strategy.sort_by(space, w_ary, block) def wrap(self, space, w_obj): raise NotImplementedError @@ -164,6 +167,9 @@ def extend(self, space, w_ary, other_w): def sort(self, space, w_ary, block): RubySorter(space, self.unerase(w_ary.array_storage), sortblock=block).sort() + def sort_by(self, space, w_ary, block): + RubySortBy(space, self.unerase(w_ary.array_storage), sortblock=block).sort() + class FloatArrayStrategy(BaseArrayStrategy, TypedArrayStrategyMixin): erase, unerase = new_static_erasing_pair("FloatArrayStrategy") @@ -551,8 +557,8 @@ def method_clear(self, space): self.strategy.clear(space, self) return self - @check_frozen() @classdef.method("sort!") + @check_frozen() def method_sort_i(self, space, block): self.strategy.sort(space, self, block) return self From 0b66118054f67ba5aa94fd90a82f8298e664b795 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 21 Jul 2013 14:00:29 -0700 Subject: [PATCH 31/37] unroll this function --- topaz/objects/arrayobject.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 7fe528977..c779163b5 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -16,6 +16,10 @@ BaseRubySortBy = make_timsort_class() +def unroll_heuristic(items_w): + return jit.isconstant(len(items_w)) and len(items_w) <= 20 + + class RubySorter(BaseRubySorter): def __init__(self, space, list, listlength=None, sortblock=None): BaseRubySorter.__init__(self, list, listlength=listlength) @@ -290,6 +294,7 @@ def newarray(space, items_w): return w_ary @staticmethod + @jit.look_inside_iff(lambda space, items_w: unroll_heuristic(items_w)) def strategy_for_list(space, items_w): if not items_w: return space.fromcache(EmptyArrayStrategy) From 608e38d09fa50f97739c3e76e859230b7ef915f1 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 21 Jul 2013 14:25:55 -0700 Subject: [PATCH 32/37] unroll this --- topaz/objects/arrayobject.py | 1 + 1 file changed, 1 insertion(+) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index c779163b5..4591b83f4 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -93,6 +93,7 @@ def append(self, space, w_ary, w_obj): def append_empty(self, w_ary): self.unerase(w_ary.array_storage).append(self.empty_value) + @jit.look_inside_iff(lambda self, space, w_ary, other_w: unroll_heuristic(other_w)) def extend(self, space, w_ary, other_w): for w_o in other_w: w_ary.append(space, w_o) From 1d6dd9c359f828ed05d086c35cf5bb02458a4747 Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 21 Jul 2013 14:52:41 -0700 Subject: [PATCH 33/37] unroll --- topaz/objects/arrayobject.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 4591b83f4..201b3134a 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -2,6 +2,7 @@ from rpython.rlib import jit from rpython.rlib.listsort import make_timsort_class +from rpython.rlib.objectmodel import specialize from rpython.rlib.rerased import new_static_erasing_pair from rpython.rlib.rbigint import rbigint @@ -16,6 +17,7 @@ BaseRubySortBy = make_timsort_class() +@specialize.argtype(0) def unroll_heuristic(items_w): return jit.isconstant(len(items_w)) and len(items_w) <= 20 @@ -108,6 +110,7 @@ def insert(self, space, w_ary, idx, w_obj): self.switch_to_object_strategy(space, w_ary) w_ary.strategy.insert(space, w_ary, idx, w_obj) + @jit.look_inside_iff(lambda self, space, w_ary: unroll_heuristic(self.unerase(w_ary.array_storage))) def listview(self, space, w_ary): return [self.wrap(space, item) for item in self.unerase(w_ary.array_storage)] From 8fd9c78988f34938bec9de9ce20bc9b1435ef0ab Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 21 Jul 2013 15:16:12 -0700 Subject: [PATCH 34/37] try again --- topaz/objects/arrayobject.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index 201b3134a..a21a4b391 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -17,7 +17,7 @@ BaseRubySortBy = make_timsort_class() -@specialize.argtype(0) +@specialize.call_location() def unroll_heuristic(items_w): return jit.isconstant(len(items_w)) and len(items_w) <= 20 From 21bba2eeb70c8077af90adcc38ff496086bdb89f Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 21 Jul 2013 15:49:45 -0700 Subject: [PATCH 35/37] some changes --- topaz/objects/arrayobject.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/topaz/objects/arrayobject.py b/topaz/objects/arrayobject.py index a21a4b391..817eb7138 100644 --- a/topaz/objects/arrayobject.py +++ b/topaz/objects/arrayobject.py @@ -340,8 +340,6 @@ def method_subscript(self, space, w_idx, w_count=None): start, end, as_range, nil = space.subscript_access(self.length(), w_idx, w_count=w_count) if nil: return space.w_nil - elif self.length() == 0: - return space.newarray([]) elif as_range: assert start >= 0 assert end >= 0 @@ -465,7 +463,7 @@ def method_push(self, space, args_w): @check_frozen() def method_shift(self, space, w_n=None): if w_n is None: - if self.length() > 0: + if self.length(): return self.strategy.pop(space, self, 0) else: return space.w_nil @@ -504,7 +502,7 @@ def method_join(self, space, w_sep=None): @check_frozen() def method_pop(self, space, w_num=None): if w_num is None: - if self.length() > 0: + if self.length(): return self.strategy.pop(space, self, -1) else: return space.w_nil @@ -514,13 +512,11 @@ def method_pop(self, space, w_num=None): )) if num < 0: raise space.error(space.w_ArgumentError, "negative array size") - elif self.length() > 0: + else: pop_size = max(0, self.length() - num) data = self.strategy.getslice(space, self, pop_size, self.length()) self.strategy.delslice(space, self, pop_size, self.length()) return W_ArrayObject(space, self.strategy, data) - else: - return space.newarray([]) @classdef.method("delete_at", idx="int") @check_frozen() From a5b7b6b74051a21c74c2deb6680ca1677473f85c Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Sun, 21 Jul 2013 16:22:31 -0700 Subject: [PATCH 36/37] update JIT tests, they're a bit worse, not much we can do --- tests/jit/test_array.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/tests/jit/test_array.py b/tests/jit/test_array.py index abb207c40..74efe67af 100644 --- a/tests/jit/test_array.py +++ b/tests/jit/test_array.py @@ -8,39 +8,44 @@ def test_subscript_assign_simple(self, topaz, tmpdir): 10000.times { arr[0] = true } """) self.assert_matches(traces[0].loop, """ - label(p0, p1, p3, p4, p5, p6, p7, p8, p10, p13, i69, p21, p24, p26, p28, i40, p37, p51, p66, descr=TargetToken(4310782200)) + label(p0, p1, p3, p4, p5, p6, p7, p8, p10, p13, i74, p21, p24, p26, p28, i40, p37, p67, p56, p43, p42, p46, p53, p47, p45, p51, descr=TargetToken(4311183872)) debug_merge_point(0, 0, 'times at LOAD_DEREF') debug_merge_point(0, 0, 'times at LOAD_SELF') debug_merge_point(0, 0, 'times at SEND') setfield_gc(p28, 42, descr=) - guard_not_invalidated(descr=) - p72 = force_token() - i73 = int_lt(i69, i40) - guard_true(i73, descr=) + guard_not_invalidated(descr=) + p76 = force_token() + i77 = int_lt(i74, i40) + guard_true(i77, descr=) debug_merge_point(0, 0, 'times at JUMP_IF_FALSE') debug_merge_point(0, 0, 'times at LOAD_DEREF') debug_merge_point(0, 0, 'times at YIELD') - p74 = force_token() + p78 = force_token() debug_merge_point(1, 1, 'block in
at LOAD_DEREF') debug_merge_point(1, 1, 'block in
at LOAD_CONST') debug_merge_point(1, 1, 'block in
at BUILD_ARRAY') debug_merge_point(1, 1, 'block in
at LOAD_CONST') debug_merge_point(1, 1, 'block in
at BUILD_ARRAY') debug_merge_point(1, 1, 'block in
at SEND_SPLAT') - p75 = force_token() + p79 = force_token() + i80 = getfield_gc(p67, descr=) + i81 = int_ge(0, i80) + setfield_gc(p28, 20, descr=) + guard_false(i81, descr=) + p82 = getfield_gc(p67, descr=) debug_merge_point(1, 1, 'block in
at RETURN') debug_merge_point(0, 0, 'times at DISCARD_TOP') debug_merge_point(0, 0, 'times at LOAD_DEREF') debug_merge_point(0, 0, 'times at LOAD_CONST') debug_merge_point(0, 0, 'times at SEND') - p76 = force_token() - i77 = int_add(i69, 1) + p83 = force_token() + i84 = int_add(i74, 1) debug_merge_point(0, 0, 'times at STORE_DEREF') debug_merge_point(0, 0, 'times at DISCARD_TOP') debug_merge_point(0, 0, 'times at JUMP') debug_merge_point(0, 0, 'times at LOAD_DEREF') setfield_gc(p28, 63, descr=) - i78 = arraylen_gc(p51, descr=) - i79 = arraylen_gc(p66, descr=) - jump(p0, p1, p3, p4, p5, p6, p7, p8, p10, p13, i77, p21, p24, p26, p28, i40, p37, p51, p66, descr=TargetToken(4310782200)) + setarrayitem_gc(p82, 0, ConstPtr(ptr58), descr=) + i85 = arraylen_gc(p51, descr=) + jump(p0, p1, p3, p4, p5, p6, p7, p8, p10, p13, i84, p21, p24, p26, p28, i40, p37, p67, p56, p43, p42, p46, p53, p47, p45, p51, descr=TargetToken(4311183872)) """) From 92b1974ca92dcb21d528796933cc41bb67885b8b Mon Sep 17 00:00:00 2001 From: Alex Gaynor Date: Tue, 6 Aug 2013 09:24:59 -0700 Subject: [PATCH 37/37] Updated for the latest RPython. YOU MUST UPGRADE TO THE LAST RPYTHON --- topaz/frame.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/topaz/frame.py b/topaz/frame.py index 190fa1d43..03ea245da 100644 --- a/topaz/frame.py +++ b/topaz/frame.py @@ -14,7 +14,7 @@ def __init__(self): class Frame(BaseFrame): - _virtualizable2_ = [ + _virtualizable_ = [ "bytecode", "localsstack_w[*]", "stackpos", "w_self", "block", "cells[*]", "lastblock", "lexical_scope", "last_instr", "parent_interp", "top_parent_interp",