[pypy-commit] pypy strbufobject: backout c74e33eeef0d: undelete W_StringBufferObject and withstrbuf config option
rlamy
pypy.commits at gmail.com
Sat May 20 16:10:45 EDT 2017
Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: strbufobject
Changeset: r91354:8c65231e844b
Date: 2017-05-20 21:09 +0100
http://bitbucket.org/pypy/pypy/changeset/8c65231e844b/
Log: backout c74e33eeef0d: undelete W_StringBufferObject and withstrbuf
config option
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -220,6 +220,9 @@
BoolOption("withsmalllong", "use a version of 'long' in a C long long",
default=False),
+ BoolOption("withstrbuf", "use strings optimized for addition (ver 2)",
+ default=False),
+
BoolOption("withspecialisedtuple",
"use specialised tuples",
default=False),
diff --git a/pypy/objspace/std/bytesobject.py b/pypy/objspace/std/bytesobject.py
--- a/pypy/objspace/std/bytesobject.py
+++ b/pypy/objspace/std/bytesobject.py
@@ -611,31 +611,55 @@
return mod_format(space, w_values, self, do_unicode=False)
def descr_eq(self, space, w_other):
+ if space.config.objspace.std.withstrbuf:
+ from pypy.objspace.std.strbufobject import W_StringBufferObject
+ if isinstance(w_other, W_StringBufferObject):
+ return space.newbool(self._value == w_other.force())
if not isinstance(w_other, W_BytesObject):
return space.w_NotImplemented
return space.newbool(self._value == w_other._value)
def descr_ne(self, space, w_other):
+ if space.config.objspace.std.withstrbuf:
+ from pypy.objspace.std.strbufobject import W_StringBufferObject
+ if isinstance(w_other, W_StringBufferObject):
+ return space.newbool(self._value != w_other.force())
if not isinstance(w_other, W_BytesObject):
return space.w_NotImplemented
return space.newbool(self._value != w_other._value)
def descr_lt(self, space, w_other):
+ if space.config.objspace.std.withstrbuf:
+ from pypy.objspace.std.strbufobject import W_StringBufferObject
+ if isinstance(w_other, W_StringBufferObject):
+ return space.newbool(self._value < w_other.force())
if not isinstance(w_other, W_BytesObject):
return space.w_NotImplemented
return space.newbool(self._value < w_other._value)
def descr_le(self, space, w_other):
+ if space.config.objspace.std.withstrbuf:
+ from pypy.objspace.std.strbufobject import W_StringBufferObject
+ if isinstance(w_other, W_StringBufferObject):
+ return space.newbool(self._value <= w_other.force())
if not isinstance(w_other, W_BytesObject):
return space.w_NotImplemented
return space.newbool(self._value <= w_other._value)
def descr_gt(self, space, w_other):
+ if space.config.objspace.std.withstrbuf:
+ from pypy.objspace.std.strbufobject import W_StringBufferObject
+ if isinstance(w_other, W_StringBufferObject):
+ return space.newbool(self._value > w_other.force())
if not isinstance(w_other, W_BytesObject):
return space.w_NotImplemented
return space.newbool(self._value > w_other._value)
def descr_ge(self, space, w_other):
+ if space.config.objspace.std.withstrbuf:
+ from pypy.objspace.std.strbufobject import W_StringBufferObject
+ if isinstance(w_other, W_StringBufferObject):
+ return space.newbool(self._value >= w_other.force())
if not isinstance(w_other, W_BytesObject):
return space.w_NotImplemented
return space.newbool(self._value >= w_other._value)
@@ -653,6 +677,18 @@
from .bytearrayobject import W_BytearrayObject, _make_data
self_as_bytearray = W_BytearrayObject(_make_data(self._value))
return space.add(self_as_bytearray, w_other)
+ if space.config.objspace.std.withstrbuf:
+ from pypy.objspace.std.strbufobject import W_StringBufferObject
+ try:
+ other = self._op_val(space, w_other)
+ except OperationError as e:
+ if e.match(space, space.w_TypeError):
+ return space.w_NotImplemented
+ raise
+ builder = StringBuilder()
+ builder.append(self._value)
+ builder.append(other)
+ return W_StringBufferObject(builder)
return self._StringMethods_descr_add(space, w_other)
_StringMethods__startswith = _startswith
diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py
--- a/pypy/objspace/std/objspace.py
+++ b/pypy/objspace/std/objspace.py
@@ -16,7 +16,7 @@
from pypy.objspace.std.boolobject import W_BoolObject
from pypy.objspace.std.bufferobject import W_Buffer
from pypy.objspace.std.bytearrayobject import W_BytearrayObject
-from pypy.objspace.std.bytesobject import W_BytesObject
+from pypy.objspace.std.bytesobject import W_AbstractBytesObject, W_BytesObject
from pypy.objspace.std.complexobject import W_ComplexObject
from pypy.objspace.std.dictmultiobject import W_DictMultiObject, W_DictObject
from pypy.objspace.std.floatobject import W_FloatObject
@@ -81,6 +81,9 @@
W_TypeObject.typedef: W_TypeObject,
W_UnicodeObject.typedef: W_UnicodeObject,
}
+ if self.config.objspace.std.withstrbuf:
+ builtin_type_classes[W_BytesObject.typedef] = W_AbstractBytesObject
+
self.builtin_types = {}
self._interplevel_classes = {}
for typedef, cls in builtin_type_classes.items():
@@ -282,7 +285,7 @@
return W_LongObject.fromint(self, val)
@specialize.argtype(1)
- def newlong_from_rarith_int(self, val): # val is an rarithmetic type
+ def newlong_from_rarith_int(self, val): # val is an rarithmetic type
return W_LongObject.fromrarith_int(val)
def newlong_from_rbigint(self, val):
diff --git a/pypy/objspace/std/strbufobject.py b/pypy/objspace/std/strbufobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/objspace/std/strbufobject.py
@@ -0,0 +1,96 @@
+import inspect
+
+import py
+
+from pypy.objspace.std.bytesobject import W_AbstractBytesObject, W_BytesObject
+from pypy.interpreter.gateway import interp2app, unwrap_spec
+from pypy.interpreter.buffer import SimpleView, StringBuffer
+from pypy.interpreter.error import OperationError
+from rpython.rlib.rstring import StringBuilder
+
+
+class W_StringBufferObject(W_AbstractBytesObject):
+ w_str = None
+
+ def __init__(self, builder):
+ self.builder = builder # StringBuilder
+ self.length = builder.getlength()
+
+ def force(self):
+ if self.w_str is None:
+ s = self.builder.build()
+ if self.length < len(s):
+ s = s[:self.length]
+ self.w_str = W_BytesObject(s)
+ return s
+ else:
+ return self.w_str._value
+
+ def __repr__(self):
+ """ representation for debugging purposes """
+ return "%s(%r[:%d])" % (
+ self.__class__.__name__, self.builder, self.length)
+
+ def unwrap(self, space):
+ return self.force()
+
+ def str_w(self, space):
+ return self.force()
+
+ def buffer_w(self, space, flags):
+ return SimpleView(StringBuffer(self.force()))
+
+ def descr_len(self, space):
+ return space.newint(self.length)
+
+ def descr_add(self, space, w_other):
+ try:
+ other = W_BytesObject._op_val(space, w_other)
+ except OperationError as e:
+ if e.match(space, space.w_TypeError):
+ return space.w_NotImplemented
+ raise
+ if self.builder.getlength() != self.length:
+ builder = StringBuilder()
+ builder.append(self.force())
+ else:
+ builder = self.builder
+ builder.append(other)
+ return W_StringBufferObject(builder)
+
+ def descr_str(self, space):
+ # you cannot get subclasses of W_StringBufferObject here
+ assert type(self) is W_StringBufferObject
+ return self
+
+
+delegation_dict = {}
+for key, value in W_BytesObject.typedef.rawdict.iteritems():
+ if not isinstance(value, interp2app):
+ continue
+ if key in ('__len__', '__add__', '__str__'):
+ continue
+
+ func = value._code._bltin
+ args = inspect.getargs(func.func_code)
+ if args.varargs or args.keywords:
+ raise TypeError("Varargs and keywords not supported in unwrap_spec")
+ argspec = ', '.join([arg for arg in args.args[1:]])
+ func_code = py.code.Source("""
+ def f(self, %(args)s):
+ self.force()
+ return self.w_str.%(func_name)s(%(args)s)
+ """ % {'args': argspec, 'func_name': func.func_name})
+ d = {}
+ exec func_code.compile() in d
+ f = d['f']
+ f.func_defaults = func.func_defaults
+ f.__module__ = func.__module__
+ # necessary for unique identifiers for pickling
+ f.func_name = func.func_name
+ unwrap_spec_ = getattr(func, 'unwrap_spec', None)
+ if unwrap_spec_ is not None:
+ f = unwrap_spec(**unwrap_spec_)(f)
+ setattr(W_StringBufferObject, func.func_name, f)
+
+W_StringBufferObject.typedef = W_BytesObject.typedef
diff --git a/pypy/objspace/std/test/test_stdobjspace.py b/pypy/objspace/std/test/test_stdobjspace.py
--- a/pypy/objspace/std/test/test_stdobjspace.py
+++ b/pypy/objspace/std/test/test_stdobjspace.py
@@ -57,6 +57,13 @@
cls = space._get_interplevel_cls(w_sequenceiterator)
assert cls is W_AbstractSeqIterObject
+ def test_withstrbuf_fastpath_isinstance(self):
+ from pypy.objspace.std.bytesobject import W_AbstractBytesObject
+
+ space = gettestobjspace(withstrbuf=True)
+ cls = space._get_interplevel_cls(space.w_bytes)
+ assert cls is W_AbstractBytesObject
+
def test_wrap_various_unsigned_types(self):
import sys
from rpython.rlib.rarithmetic import r_uint
diff --git a/pypy/objspace/std/test/test_strbufobject.py b/pypy/objspace/std/test/test_strbufobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/objspace/std/test/test_strbufobject.py
@@ -0,0 +1,85 @@
+import py
+
+from pypy.objspace.std.test import test_bytesobject
+
+class AppTestStringObject(test_bytesobject.AppTestBytesObject):
+ spaceconfig = {"objspace.std.withstrbuf": True}
+
+ def test_basic(self):
+ import __pypy__
+ # cannot do "Hello, " + "World!" because cpy2.5 optimises this
+ # away on AST level
+ s = "Hello, ".__add__("World!")
+ assert type(s) is str
+ assert 'W_StringBufferObject' in __pypy__.internal_repr(s)
+
+ def test_add_twice(self):
+ x = "a".__add__("b")
+ y = x + "c"
+ c = x + "d"
+ assert y == "abc"
+ assert c == "abd"
+
+ def test_add(self):
+ import __pypy__
+ all = ""
+ for i in range(20):
+ all += str(i)
+ assert 'W_StringBufferObject' in __pypy__.internal_repr(all)
+ assert all == "012345678910111213141516171819"
+
+ def test_hash(self):
+ import __pypy__
+ def join(s): return s[:len(s) // 2] + s[len(s) // 2:]
+ t = 'a' * 101
+ s = join(t)
+ assert 'W_StringBufferObject' in __pypy__.internal_repr(s)
+ assert hash(s) == hash(t)
+
+ def test_len(self):
+ s = "a".__add__("b")
+ r = "c".__add__("d")
+ t = s + r
+ assert len(s) == 2
+ assert len(r) == 2
+ assert len(t) == 4
+
+ def test_buffer(self):
+ s = b'a'.__add__(b'b')
+ assert buffer(s) == buffer(b'ab')
+ assert memoryview(s) == b'ab'
+
+ def test_add_strbuf(self):
+ # make three strbuf objects
+ s = 'a'.__add__('b')
+ t = 'x'.__add__('c')
+ u = 'y'.__add__('d')
+
+ # add two different strbufs to the same string
+ v = s + t
+ w = s + u
+
+ # check that insanity hasn't resulted.
+ assert v == "abxc"
+ assert w == "abyd"
+
+ def test_more_adding_fun(self):
+ s = 'a'.__add__('b') # s is a strbuf now
+ t = s + 'c'
+ u = s + 'd'
+ v = s + 'e'
+ assert v == 'abe'
+ assert u == 'abd'
+ assert t == 'abc'
+
+ def test_buh_even_more(self):
+ a = 'a'.__add__('b')
+ b = a + 'c'
+ c = '0'.__add__('1')
+ x = c + a
+ assert x == '01ab'
+
+ def test_add_non_string(self):
+ a = 'a'
+ a += 'b'
+ raises(TypeError, "a += 5")
More information about the pypy-commit
mailing list