[pypy-svn] r25669 - in pypy/dist/pypy/rpython: lltypesystem rctypes rctypes/test

arigo at codespeak.net arigo at codespeak.net
Mon Apr 10 17:43:29 CEST 2006


Author: arigo
Date: Mon Apr 10 17:43:27 2006
New Revision: 25669

Modified:
   pypy/dist/pypy/rpython/lltypesystem/lltype.py
   pypy/dist/pypy/rpython/rctypes/rchar_p.py
   pypy/dist/pypy/rpython/rctypes/test/test_rchar_p.py
   pypy/dist/pypy/rpython/rctypes/test/test_rfunc.py
Log:
Hack in lltype to allow __getitem__ just past the end of rpystrings
to return the hidden final \x00 character.  This allows some good
progress on string support in rctypes.


Modified: pypy/dist/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/dist/pypy/rpython/lltypesystem/lltype.py	(original)
+++ pypy/dist/pypy/rpython/lltypesystem/lltype.py	Mon Apr 10 17:43:27 2006
@@ -763,6 +763,11 @@
     def __getitem__(self, i): # ! can only return basic or ptr !
         if isinstance(self._T, (Array, FixedSizeArray)):
             if not (0 <= i < self._obj.getlength()):
+                if (self._T._hints.get('isrpystring', False) and
+                    i == self._obj.getlength()):
+                    # special hack for the null terminator
+                    assert self._T.OF == Char
+                    return '\x00'
                 raise IndexError("array index out of bounds")
             o = self._obj.getitem(i)
             return _expose(o, self._solid)
@@ -792,6 +797,12 @@
             return self._obj.getlength()
         raise TypeError("%r instance is not an array" % (self._T,))
 
+    def __iter__(self):
+        # this is a work-around for the 'isrpystring' hack in __getitem__,
+        # which otherwise causes list(p) to include the extra \x00 character.
+        for i in range(len(self)):
+            yield self[i]
+
     def __repr__(self):
         return '<%s>' % (self,)
 

Modified: pypy/dist/pypy/rpython/rctypes/rchar_p.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/rchar_p.py	(original)
+++ pypy/dist/pypy/rpython/rctypes/rchar_p.py	Mon Apr 10 17:43:27 2006
@@ -1,8 +1,9 @@
 from pypy.rpython import extregistry
 from pypy.rpython.lltypesystem import lltype, llmemory
-from pypy.rpython.rstr import string_repr
+from pypy.rpython.rstr import StringRepr, string_repr
 from pypy.rpython.rctypes.rmodel import CTypesValueRepr
 from pypy.annotation import model as annmodel
+from pypy.annotation.pairtype import pairtype
 
 from ctypes import c_char_p
 
@@ -41,6 +42,16 @@
         self.setstring(hop.llops, v_char_p, v_value)
 
 
+class __extend__(pairtype(StringRepr, CCharPRepr)):
+    def convert_from_to((r_from, r_to), v, llops):
+        # r_from could be char_repr: first convert it to string_repr
+        v = llops.convertvar(v, r_from, string_repr)
+        r_temp = r_to.r_memoryowner
+        v_owned_box = r_temp.allocate_instance(llops)
+        r_temp.setstring(llops, v_owned_box, v)
+        return llops.convertvar(v_owned_box, r_temp, r_to)
+
+
 CCHARP = llmemory.Address    # char *
 FIRSTITEMOFS = llmemory.ArrayItemsOffset(string_repr.lowleveltype.TO.chars)
 
@@ -62,7 +73,7 @@
 def ll_getstring(box):
     p = box.c_data.value
     if p:
-        if (box.keepalive_str and ll_str2charp(box.keepalive_str) == p):
+        if box.keepalive_str and ll_str2charp(box.keepalive_str) == p:
             maxlen = len(box.keepalive_str.chars)
             length = ll_strnlen(p, maxlen)
             if length == maxlen:

Modified: pypy/dist/pypy/rpython/rctypes/test/test_rchar_p.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/test/test_rchar_p.py	(original)
+++ pypy/dist/pypy/rpython/rctypes/test/test_rchar_p.py	Mon Apr 10 17:43:27 2006
@@ -16,7 +16,7 @@
 except ImportError:
     py.test.skip("this test needs ctypes installed")
 
-from ctypes import c_char_p
+from ctypes import c_char_p, pointer
 
 class Test_annotation:
     def test_annotate_c_char_p(self):
@@ -60,6 +60,28 @@
         res = interpret(func, [])
         assert ''.join(res.chars) == "hello"
 
+    def test_zero_terminates(self):
+        def func():
+            p = c_char_p('world')
+            p.value = "hello\x00world"
+            return p.value
+
+        res = interpret(func, [])
+        assert ''.join(res.chars) == "hello"
+
+    def test_pointer_access(self):
+        def func():
+            q = c_char_p('ka')
+            p = c_char_p('world')
+            pp = pointer(p)
+            pp[0] = q.value
+            return p.value
+
+        assert func() == 'ka'
+        res = interpret(func, [])
+        assert ''.join(res.chars) == 'ka'
+
+
 class Test_compilation:
     def test_compile_c_char_p(self):
         def func():

Modified: pypy/dist/pypy/rpython/rctypes/test/test_rfunc.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/test/test_rfunc.py	(original)
+++ pypy/dist/pypy/rpython/rctypes/test/test_rfunc.py	Mon Apr 10 17:43:27 2006
@@ -5,6 +5,7 @@
 from pypy.translator.c.test.test_genc import compile
 from pypy import conftest
 from pypy.rpython.rstr import string_repr
+from pypy.rpython.lltypesystem import lltype, llmemory
 
 from ctypes import c_int, c_long, c_char_p
 
@@ -19,14 +20,11 @@
 atoi = mylib.atoi
 atoi.restype = c_int
 atoi.argtypes = [c_char_p]
-def ll_atoi(s):
+def ll_atoi(s_addr):
     "Very approximative ll implementation of atoi(), for testing"
     i = result = 0
-    while i < len(s.chars):
-        if '0' <= s.chars[i] <= '9':
-            result = result * 10 + ord(s.chars[i]) - ord('0')
-        else:
-            break
+    while '0' <= s_addr.char[i] <= '9':
+        result = result * 10 + ord(s_addr.char[i]) - ord('0')
         i += 1
     return result
 atoi.llinterp_friendly_version = ll_atoi
@@ -39,10 +37,16 @@
     return labs(n)
 
 def test_ll_atoi():
-    assert ll_atoi(string_repr.convert_const("")) == 0
-    assert ll_atoi(string_repr.convert_const("42z7")) == 42
-    assert ll_atoi(string_repr.convert_const("blah")) == 0
-    assert ll_atoi(string_repr.convert_const("18238")) == 18238
+    keepalive = []
+    def str2addr(string):
+        llstring = string_repr.convert_const(string)
+        keepalive.append(llstring)
+        return (llmemory.cast_ptr_to_adr(llstring.chars) +
+                llmemory.ArrayItemsOffset(lltype.typeOf(llstring.chars).TO))
+    assert ll_atoi(str2addr("")) == 0
+    assert ll_atoi(str2addr("42z7")) == 42
+    assert ll_atoi(str2addr("blah")) == 0
+    assert ll_atoi(str2addr("18238")) == 18238
 
 class Test_annotation:
     def test_annotate_labs(self):
@@ -67,7 +71,6 @@
         assert res == 11
 
     def test_specialize_atoi(self):
-        py.test.skip("in-progress")
         choices = ["", "42z7", "blah", "18238"]
         def fn(n):
             return atoi(choices[n])



More information about the Pypy-commit mailing list