Author: Antonio Cuni <[email protected]>
Branch: faster-rstruct
Changeset: r80919:246229cd7f49
Date: 2015-11-25 00:57 +0100
http://bitbucket.org/pypy/pypy/changeset/246229cd7f49/

Log:    hg merge default

diff --git a/lib_pypy/cffi/api.py b/lib_pypy/cffi/api.py
--- a/lib_pypy/cffi/api.py
+++ b/lib_pypy/cffi/api.py
@@ -72,6 +72,7 @@
         self._cdefsources = []
         self._included_ffis = []
         self._windows_unicode = None
+        self._init_once_cache = {}
         if hasattr(backend, 'set_ffi'):
             backend.set_ffi(self)
         for name in backend.__dict__:
@@ -598,6 +599,30 @@
         return recompile(self, module_name, source, tmpdir=tmpdir,
                          source_extension=source_extension, **kwds)
 
+    def init_once(self, func, tag):
+        # Read _init_once_cache[tag], which is either (False, lock) if
+        # we're calling the function now in some thread, or (True, result).
+        # Don't call setdefault() in most cases, to avoid allocating and
+        # immediately freeing a lock; but still use setdefaut() to avoid
+        # races.
+        try:
+            x = self._init_once_cache[tag]
+        except KeyError:
+            x = self._init_once_cache.setdefault(tag, (False, allocate_lock()))
+        # Common case: we got (True, result), so we return the result.
+        if x[0]:
+            return x[1]
+        # Else, it's a lock.  Acquire it to serialize the following tests.
+        with x[1]:
+            # Read again from _init_once_cache the current status.
+            x = self._init_once_cache[tag]
+            if x[0]:
+                return x[1]
+            # Call the function and store the result back.
+            result = func()
+            self._init_once_cache[tag] = (True, result)
+        return result
+
 
 def _load_backend_lib(backend, name, flags):
     if name is None:
diff --git a/lib_pypy/cffi/parse_c_type.h b/lib_pypy/cffi/parse_c_type.h
--- a/lib_pypy/cffi/parse_c_type.h
+++ b/lib_pypy/cffi/parse_c_type.h
@@ -1,5 +1,6 @@
 
-/* See doc/misc/parse_c_type.rst in the source of CFFI for more information */
+/* This part is from file 'cffi/parse_c_type.h'.  It is copied at the
+   beginning of C sources generated by CFFI's ffi.set_source(). */
 
 typedef void *_cffi_opcode_t;
 
diff --git a/lib_pypy/datetime.py b/lib_pypy/datetime.py
--- a/lib_pypy/datetime.py
+++ b/lib_pypy/datetime.py
@@ -17,11 +17,12 @@
 """
 
 from __future__ import division
-import numbers as _numbers
 import time as _time
 import math as _math
 import struct as _struct
 
+_SENTINEL = object()
+
 def _cmp(x, y):
     return 0 if x == y else 1 if x > y else -1
 
@@ -32,6 +33,8 @@
 MAXYEAR = 9999
 _MINYEARFMT = 1900
 
+_MAX_DELTA_DAYS = 999999999
+
 # Utility functions, adapted from Python's Demo/classes/Dates.py, which
 # also assumes the current Gregorian calendar indefinitely extended in
 # both directions.  Difference:  Dates.py calls January 1 of year 0 day
@@ -96,6 +99,15 @@
 # pasting together 25 4-year cycles.
 assert _DI100Y == 25 * _DI4Y - 1
 
+_US_PER_US = 1
+_US_PER_MS = 1000
+_US_PER_SECOND = 1000000
+_US_PER_MINUTE = 60000000
+_SECONDS_PER_DAY = 24 * 3600
+_US_PER_HOUR = 3600000000
+_US_PER_DAY = 86400000000
+_US_PER_WEEK = 604800000000
+
 def _ord2ymd(n):
     "ordinal -> (year, month, day), considering 01-Jan-0001 as day 1."
 
@@ -417,6 +429,30 @@
         self.hour, self.minute, self.second = hour, minute, second
         self.microsecond = microsecond
 
+def _accum(tag, sofar, num, factor, leftover):
+    if isinstance(num, (int, long)):
+        prod = num * factor
+        rsum = sofar + prod
+        return rsum, leftover
+    if isinstance(num, float):
+        fracpart, intpart = _math.modf(num)
+        prod = int(intpart) * factor
+        rsum = sofar + prod
+        if fracpart == 0.0:
+            return rsum, leftover
+        assert isinstance(factor, (int, long))
+        fracpart, intpart = _math.modf(factor * fracpart)
+        rsum += int(intpart)
+        return rsum, leftover + fracpart
+    raise TypeError("unsupported type for timedelta %s component: %s" %
+                    (tag, type(num)))
+
+def _normalize_pair(hi, lo, factor):
+    if lo < 0 or lo >= factor:
+        inc, lo = divmod(lo, factor)
+        hi += inc
+    return hi, lo
+
 class timedelta(object):
     """Represent the difference between two datetime objects.
 
@@ -436,100 +472,42 @@
     """
     __slots__ = '_days', '_seconds', '_microseconds', '_hashcode'
 
-    def __new__(cls, days=0, seconds=0, microseconds=0,
-                milliseconds=0, minutes=0, hours=0, weeks=0):
-        # Doing this efficiently and accurately in C is going to be difficult
-        # and error-prone, due to ubiquitous overflow possibilities, and that
-        # C double doesn't have enough bits of precision to represent
-        # microseconds over 10K years faithfully.  The code here tries to make
-        # explicit where go-fast assumptions can be relied on, in order to
-        # guide the C implementation; it's way more convoluted than speed-
-        # ignoring auto-overflow-to-long idiomatic Python could be.
+    def __new__(cls, days=_SENTINEL, seconds=_SENTINEL, microseconds=_SENTINEL,
+                milliseconds=_SENTINEL, minutes=_SENTINEL, hours=_SENTINEL, 
weeks=_SENTINEL):
+        x = 0
+        leftover = 0.0
+        if microseconds is not _SENTINEL:
+            x, leftover = _accum("microseconds", x, microseconds, _US_PER_US, 
leftover)
+        if milliseconds is not _SENTINEL:
+            x, leftover = _accum("milliseconds", x, milliseconds, _US_PER_MS, 
leftover)
+        if seconds is not _SENTINEL:
+            x, leftover = _accum("seconds", x, seconds, _US_PER_SECOND, 
leftover)
+        if minutes is not _SENTINEL:
+            x, leftover = _accum("minutes", x, minutes, _US_PER_MINUTE, 
leftover)
+        if hours is not _SENTINEL:
+            x, leftover = _accum("hours", x, hours, _US_PER_HOUR, leftover)
+        if days is not _SENTINEL:
+            x, leftover = _accum("days", x, days, _US_PER_DAY, leftover)
+        if weeks is not _SENTINEL:
+            x, leftover = _accum("weeks", x, weeks, _US_PER_WEEK, leftover)
+        if leftover != 0.0:
+            x += _round(leftover)
+        return cls._from_microseconds(x)
 
-        # XXX Check that all inputs are ints, longs or floats.
+    @classmethod
+    def _from_microseconds(cls, us):
+        s, us = divmod(us, _US_PER_SECOND)
+        d, s = divmod(s, _SECONDS_PER_DAY)
+        return cls._create(d, s, us, False)
 
-        # Final values, all integer.
-        # s and us fit in 32-bit signed ints; d isn't bounded.
-        d = s = us = 0
+    @classmethod
+    def _create(cls, d, s, us, normalize):
+        if normalize:
+            s, us = _normalize_pair(s, us, 1000000)
+            d, s = _normalize_pair(d, s, 24*3600)
 
-        # Normalize everything to days, seconds, microseconds.
-        days += weeks*7
-        seconds += minutes*60 + hours*3600
-        microseconds += milliseconds*1000
-
-        # Get rid of all fractions, and normalize s and us.
-        # Take a deep breath <wink>.
-        if isinstance(days, float):
-            dayfrac, days = _math.modf(days)
-            daysecondsfrac, daysecondswhole = _math.modf(dayfrac * (24.*3600.))
-            assert daysecondswhole == int(daysecondswhole)  # can't overflow
-            s = int(daysecondswhole)
-            assert days == int(days)
-            d = int(days)
-        else:
-            daysecondsfrac = 0.0
-            d = days
-        assert isinstance(daysecondsfrac, float)
-        assert abs(daysecondsfrac) <= 1.0
-        assert isinstance(d, _numbers.Integral)
-        assert abs(s) <= 24 * 3600
-        # days isn't referenced again before redefinition
-
-        if isinstance(seconds, float):
-            secondsfrac, seconds = _math.modf(seconds)
-            assert seconds == int(seconds)
-            seconds = int(seconds)
-            secondsfrac += daysecondsfrac
-            assert abs(secondsfrac) <= 2.0
-        else:
-            secondsfrac = daysecondsfrac
-        # daysecondsfrac isn't referenced again
-        assert isinstance(secondsfrac, float)
-        assert abs(secondsfrac) <= 2.0
-
-        assert isinstance(seconds, _numbers.Integral)
-        days, seconds = divmod(seconds, 24*3600)
-        d += days
-        s += int(seconds)    # can't overflow
-        assert isinstance(s, _numbers.Integral)
-        assert abs(s) <= 2 * 24 * 3600
-        # seconds isn't referenced again before redefinition
-
-        usdouble = secondsfrac * 1e6
-        assert abs(usdouble) < 2.1e6    # exact value not critical
-        # secondsfrac isn't referenced again
-
-        if isinstance(microseconds, float):
-            microseconds = _round(microseconds + usdouble)
-            seconds, microseconds = divmod(microseconds, 1000000)
-            days, seconds = divmod(seconds, 24*3600)
-            d += days
-            s += int(seconds)
-            microseconds = int(microseconds)
-        else:
-            microseconds = int(microseconds)
-            seconds, microseconds = divmod(microseconds, 1000000)
-            days, seconds = divmod(seconds, 24*3600)
-            d += days
-            s += int(seconds)
-            microseconds = _round(microseconds + usdouble)
-        assert isinstance(s, _numbers.Integral)
-        assert isinstance(microseconds, _numbers.Integral)
-        assert abs(s) <= 3 * 24 * 3600
-        assert abs(microseconds) < 3.1e6
-
-        # Just a little bit of carrying possible for microseconds and seconds.
-        seconds, us = divmod(microseconds, 1000000)
-        s += seconds
-        days, s = divmod(s, 24*3600)
-        d += days
-
-        assert isinstance(d, _numbers.Integral)
-        assert isinstance(s, _numbers.Integral) and 0 <= s < 24*3600
-        assert isinstance(us, _numbers.Integral) and 0 <= us < 1000000
-
-        if abs(d) > 999999999:
-            raise OverflowError("timedelta # of days is too large: %d" % d)
+        if not -_MAX_DELTA_DAYS <= d <= _MAX_DELTA_DAYS:
+            raise OverflowError("days=%d; must have magnitude <= %d" % (d, 
_MAX_DELTA_DAYS))
 
         self = object.__new__(cls)
         self._days = d
@@ -538,6 +516,10 @@
         self._hashcode = -1
         return self
 
+    def _to_microseconds(self):
+        return ((self._days * _SECONDS_PER_DAY + self._seconds) * 
_US_PER_SECOND +
+                self._microseconds)
+
     def __repr__(self):
         module = "datetime." if self.__class__ is timedelta else ""
         if self._microseconds:
@@ -565,8 +547,7 @@
 
     def total_seconds(self):
         """Total seconds in the duration."""
-        return ((self.days * 86400 + self.seconds) * 10**6 +
-                self.microseconds) / 10**6
+        return self._to_microseconds() / 10**6
 
     # Read-only field accessors
     @property
@@ -588,9 +569,10 @@
         if isinstance(other, timedelta):
             # for CPython compatibility, we cannot use
             # our __class__ here, but need a real timedelta
-            return timedelta(self._days + other._days,
-                             self._seconds + other._seconds,
-                             self._microseconds + other._microseconds)
+            return timedelta._create(self._days + other._days,
+                                     self._seconds + other._seconds,
+                                     self._microseconds + other._microseconds,
+                                     True)
         return NotImplemented
 
     __radd__ = __add__
@@ -599,9 +581,10 @@
         if isinstance(other, timedelta):
             # for CPython compatibility, we cannot use
             # our __class__ here, but need a real timedelta
-            return timedelta(self._days - other._days,
-                             self._seconds - other._seconds,
-                             self._microseconds - other._microseconds)
+            return timedelta._create(self._days - other._days,
+                                     self._seconds - other._seconds,
+                                     self._microseconds - other._microseconds,
+                                     True)
         return NotImplemented
 
     def __rsub__(self, other):
@@ -612,12 +595,18 @@
     def __neg__(self):
         # for CPython compatibility, we cannot use
         # our __class__ here, but need a real timedelta
-        return timedelta(-self._days,
-                         -self._seconds,
-                         -self._microseconds)
+        return timedelta._create(-self._days,
+                                 -self._seconds,
+                                 -self._microseconds,
+                                 True)
 
     def __pos__(self):
-        return self
+        # for CPython compatibility, we cannot use
+        # our __class__ here, but need a real timedelta
+        return timedelta._create(self._days,
+                                 self._seconds,
+                                 self._microseconds,
+                                 False)
 
     def __abs__(self):
         if self._days < 0:
@@ -626,25 +615,18 @@
             return self
 
     def __mul__(self, other):
-        if isinstance(other, (int, long)):
-            # for CPython compatibility, we cannot use
-            # our __class__ here, but need a real timedelta
-            return timedelta(self._days * other,
-                             self._seconds * other,
-                             self._microseconds * other)
-        return NotImplemented
+        if not isinstance(other, (int, long)):
+            return NotImplemented
+        usec = self._to_microseconds()
+        return timedelta._from_microseconds(usec * other)
 
     __rmul__ = __mul__
 
-    def _to_microseconds(self):
-        return ((self._days * (24*3600) + self._seconds) * 1000000 +
-                self._microseconds)
-
     def __div__(self, other):
         if not isinstance(other, (int, long)):
             return NotImplemented
         usec = self._to_microseconds()
-        return timedelta(0, 0, usec // other)
+        return timedelta._from_microseconds(usec // other)
 
     __floordiv__ = __div__
 
@@ -708,9 +690,8 @@
     def __reduce__(self):
         return (self.__class__, self._getstate())
 
-timedelta.min = timedelta(-999999999)
-timedelta.max = timedelta(days=999999999, hours=23, minutes=59, seconds=59,
-                          microseconds=999999)
+timedelta.min = timedelta(-_MAX_DELTA_DAYS)
+timedelta.max = timedelta(_MAX_DELTA_DAYS, 24*3600-1, 1000000-1)
 timedelta.resolution = timedelta(microseconds=1)
 
 class date(object):
@@ -972,11 +953,11 @@
     def __sub__(self, other):
         """Subtract two dates, or a date and a timedelta."""
         if isinstance(other, timedelta):
-            return self + timedelta(-other.days)
+            return self + timedelta._create(-other.days, 0, 0, False)
         if isinstance(other, date):
             days1 = self.toordinal()
             days2 = other.toordinal()
-            return timedelta(days1 - days2)
+            return timedelta._create(days1 - days2, 0, 0, False)
         return NotImplemented
 
     def weekday(self):
@@ -1343,7 +1324,7 @@
         offset = self._tzinfo.utcoffset(None)
         offset = _check_utc_offset("utcoffset", offset)
         if offset is not None:
-            offset = timedelta(minutes=offset)
+            offset = timedelta._create(0, offset * 60, 0, True)
         return offset
 
     # Return an integer (or None) instead of a timedelta (or None).
@@ -1381,7 +1362,7 @@
         offset = self._tzinfo.dst(None)
         offset = _check_utc_offset("dst", offset)
         if offset is not None:
-            offset = timedelta(minutes=offset)
+            offset = timedelta._create(0, offset * 60, 0, True)
         return offset
 
     # Return an integer (or None) instead of a timedelta (or None).
@@ -1508,18 +1489,24 @@
 
         A timezone info object may be passed in as well.
         """
+        _check_tzinfo_arg(tz)
+        converter = _time.localtime if tz is None else _time.gmtime
+        self = cls._from_timestamp(converter, timestamp, tz)
+        if tz is not None:
+            self = tz.fromutc(self)
+        return self
 
-        _check_tzinfo_arg(tz)
+    @classmethod
+    def utcfromtimestamp(cls, t):
+        "Construct a UTC datetime from a POSIX timestamp (like time.time())."
+        return cls._from_timestamp(_time.gmtime, t, None)
 
-        converter = _time.localtime if tz is None else _time.gmtime
-
-        if isinstance(timestamp, _numbers.Integral):
-            us = 0
-        else:
-            t_full = timestamp
-            timestamp = int(_math.floor(timestamp))
-            frac = t_full - timestamp
-            us = _round(frac * 1e6)
+    @classmethod
+    def _from_timestamp(cls, converter, timestamp, tzinfo):
+        t_full = timestamp
+        timestamp = int(_math.floor(timestamp))
+        frac = t_full - timestamp
+        us = _round(frac * 1e6)
 
         # If timestamp is less than one microsecond smaller than a
         # full second, us can be rounded up to 1000000.  In this case,
@@ -1530,32 +1517,7 @@
             us = 0
         y, m, d, hh, mm, ss, weekday, jday, dst = converter(timestamp)
         ss = min(ss, 59)    # clamp out leap seconds if the platform has them
-        result = cls(y, m, d, hh, mm, ss, us, tz)
-        if tz is not None:
-            result = tz.fromutc(result)
-        return result
-
-    @classmethod
-    def utcfromtimestamp(cls, t):
-        "Construct a UTC datetime from a POSIX timestamp (like time.time())."
-        if isinstance(t, _numbers.Integral):
-            us = 0
-        else:
-            t_full = t
-            t = int(_math.floor(t))
-            frac = t_full - t
-            us = _round(frac * 1e6)
-
-        # If timestamp is less than one microsecond smaller than a
-        # full second, us can be rounded up to 1000000.  In this case,
-        # roll over to seconds, otherwise, ValueError is raised
-        # by the constructor.
-        if us == 1000000:
-            t += 1
-            us = 0
-        y, m, d, hh, mm, ss, weekday, jday, dst = _time.gmtime(t)
-        ss = min(ss, 59)    # clamp out leap seconds if the platform has them
-        return cls(y, m, d, hh, mm, ss, us)
+        return cls(y, m, d, hh, mm, ss, us, tzinfo)
 
     @classmethod
     def now(cls, tz=None):
@@ -1733,7 +1695,7 @@
         offset = self._tzinfo.utcoffset(self)
         offset = _check_utc_offset("utcoffset", offset)
         if offset is not None:
-            offset = timedelta(minutes=offset)
+            offset = timedelta._create(0, offset * 60, 0, True)
         return offset
 
     # Return an integer (or None) instead of a timedelta (or None).
@@ -1771,7 +1733,7 @@
         offset = self._tzinfo.dst(self)
         offset = _check_utc_offset("dst", offset)
         if offset is not None:
-            offset = timedelta(minutes=offset)
+            offset = timedelta._create(0, offset * 60, 0, True)
         return offset
 
     # Return an integer (or None) instead of a timedelta (or None).
@@ -1888,13 +1850,12 @@
                 return self + -other
             return NotImplemented
 
-        days1 = self.toordinal()
-        days2 = other.toordinal()
-        secs1 = self._second + self._minute * 60 + self._hour * 3600
-        secs2 = other._second + other._minute * 60 + other._hour * 3600
-        base = timedelta(days1 - days2,
-                         secs1 - secs2,
-                         self._microsecond - other._microsecond)
+        delta_d = self.toordinal() - other.toordinal()
+        delta_s = (self._hour - other._hour) * 3600 + \
+                  (self._minute - other._minute) * 60 + \
+                  (self._second - other._second)
+        delta_us = self._microsecond - other._microsecond
+        base = timedelta._create(delta_d, delta_s, delta_us, True)
         if self._tzinfo is other._tzinfo:
             return base
         myoff = self._utcoffset()
diff --git a/pypy/module/_cffi_backend/ffi_obj.py 
b/pypy/module/_cffi_backend/ffi_obj.py
--- a/pypy/module/_cffi_backend/ffi_obj.py
+++ b/pypy/module/_cffi_backend/ffi_obj.py
@@ -49,6 +49,8 @@
     ACCEPT_CDATA  = ACCEPT_CDATA
 
     w_gc_wref_remove = None
+    w_init_once_cache = None
+    jit_init_once_cache = None
 
     @jit.dont_look_inside
     def __init__(self, space, src_ctx):
@@ -585,6 +587,59 @@
         return w_result
 
 
+    def descr_init_once(self, w_func, w_tag):
+        """XXX document me"""
+        #
+        # first, a fast-path for the JIT which only works if the very
+        # same w_tag object is passed; then it turns into no code at all
+        try:
+            return self._init_once_elidable(w_tag)
+        except KeyError:
+            return self._init_once_slowpath(w_func, w_tag)
+
+    @jit.elidable
+    def _init_once_elidable(self, w_tag):
+        jit_cache = self.jit_init_once_cache
+        if jit_cache is not None:
+            return jit_cache[w_tag]
+        else:
+            raise KeyError
+
+    @jit.dont_look_inside
+    def _init_once_slowpath(self, w_func, w_tag):
+        space = self.space
+        w_cache = self.w_init_once_cache
+        if w_cache is None:
+            w_cache = self.space.newdict()
+            jit_cache = {}
+            self.w_init_once_cache = w_cache
+            self.jit_init_once_cache = jit_cache
+        #
+        # get the lock or result from cache[tag]
+        w_res = space.finditem(w_cache, w_tag)
+        if w_res is None:
+            w_res = W_InitOnceLock(space)
+            w_res = space.call_method(w_cache, 'setdefault', w_tag, w_res)
+        if not isinstance(w_res, W_InitOnceLock):
+            return w_res
+        with w_res.lock:
+            w_res = space.finditem(w_cache, w_tag)
+            if w_res is None or isinstance(w_res, W_InitOnceLock):
+                w_res = space.call_function(w_func)
+                self.jit_init_once_cache[w_tag] = w_res
+                space.setitem(w_cache, w_tag, w_res)
+            else:
+                # the real result was put in the dict while we were
+                # waiting for lock.__enter__() above
+                pass
+        return w_res
+
+
+class W_InitOnceLock(W_Root):
+    def __init__(self, space):
+        self.lock = space.allocate_lock()
+
+
 @jit.dont_look_inside
 def make_plain_ffi_object(space, w_ffitype=None):
     if w_ffitype is None:
@@ -641,6 +696,7 @@
         from_handle = interp2app(W_FFIObject.descr_from_handle),
         gc          = interp2app(W_FFIObject.descr_gc),
         getctype    = interp2app(W_FFIObject.descr_getctype),
+        init_once   = interp2app(W_FFIObject.descr_init_once),
         integer_const = interp2app(W_FFIObject.descr_integer_const),
         memmove     = interp2app(W_FFIObject.descr_memmove),
         new         = interp2app(W_FFIObject.descr_new),
diff --git a/pypy/module/_cffi_backend/test/test_ffi_obj.py 
b/pypy/module/_cffi_backend/test/test_ffi_obj.py
--- a/pypy/module/_cffi_backend/test/test_ffi_obj.py
+++ b/pypy/module/_cffi_backend/test/test_ffi_obj.py
@@ -447,3 +447,19 @@
                 assert int(ffi.cast("_Bool", ffi.cast(type, 42))) == 1
                 assert int(ffi.cast("bool", ffi.cast(type, 42))) == 1
                 assert int(ffi.cast("_Bool", ffi.cast(type, 0))) == 0
+
+    def test_init_once(self):
+        import _cffi_backend as _cffi1_backend
+        def do_init():
+            seen.append(1)
+            return 42
+        ffi = _cffi1_backend.FFI()
+        seen = []
+        for i in range(3):
+            res = ffi.init_once(do_init, "tag1")
+            assert res == 42
+            assert seen == [1]
+        for i in range(3):
+            res = ffi.init_once(do_init, "tag2")
+            assert res == 42
+            assert seen == [1, 1]
diff --git a/pypy/module/micronumpy/compile.py 
b/pypy/module/micronumpy/compile.py
--- a/pypy/module/micronumpy/compile.py
+++ b/pypy/module/micronumpy/compile.py
@@ -8,6 +8,7 @@
 from pypy.interpreter.error import OperationError
 from rpython.rlib.objectmodel import specialize, instantiate
 from rpython.rlib.nonconst import NonConstant
+from rpython.rlib.rarithmetic import base_int
 from pypy.module.micronumpy import boxes, ufuncs
 from pypy.module.micronumpy.arrayops import where
 from pypy.module.micronumpy.ndarray import W_NDimArray
@@ -178,7 +179,7 @@
             return BoolObject(obj)
         elif isinstance(obj, int):
             return IntObject(obj)
-        elif isinstance(obj, long):
+        elif isinstance(obj, base_int):
             return LongObject(obj)
         elif isinstance(obj, W_Root):
             return obj
@@ -196,31 +197,31 @@
         return self.float(f)
 
     def le(self, w_obj1, w_obj2):
-        assert isinstance(w_obj1, boxes.W_GenericBox) 
-        assert isinstance(w_obj2, boxes.W_GenericBox) 
+        assert isinstance(w_obj1, boxes.W_GenericBox)
+        assert isinstance(w_obj2, boxes.W_GenericBox)
         return w_obj1.descr_le(self, w_obj2)
 
     def lt(self, w_obj1, w_obj2):
-        assert isinstance(w_obj1, boxes.W_GenericBox) 
-        assert isinstance(w_obj2, boxes.W_GenericBox) 
+        assert isinstance(w_obj1, boxes.W_GenericBox)
+        assert isinstance(w_obj2, boxes.W_GenericBox)
         return w_obj1.descr_lt(self, w_obj2)
 
     def ge(self, w_obj1, w_obj2):
-        assert isinstance(w_obj1, boxes.W_GenericBox) 
-        assert isinstance(w_obj2, boxes.W_GenericBox) 
+        assert isinstance(w_obj1, boxes.W_GenericBox)
+        assert isinstance(w_obj2, boxes.W_GenericBox)
         return w_obj1.descr_ge(self, w_obj2)
 
     def add(self, w_obj1, w_obj2):
-        assert isinstance(w_obj1, boxes.W_GenericBox) 
-        assert isinstance(w_obj2, boxes.W_GenericBox) 
+        assert isinstance(w_obj1, boxes.W_GenericBox)
+        assert isinstance(w_obj2, boxes.W_GenericBox)
         return w_obj1.descr_add(self, w_obj2)
 
     def sub(self, w_obj1, w_obj2):
         return self.wrap(1)
 
     def mul(self, w_obj1, w_obj2):
-        assert isinstance(w_obj1, boxes.W_GenericBox) 
-        assert isinstance(w_obj2, boxes.W_GenericBox) 
+        assert isinstance(w_obj1, boxes.W_GenericBox)
+        assert isinstance(w_obj2, boxes.W_GenericBox)
         return w_obj1.descr_mul(self, w_obj2)
 
     def pow(self, w_obj1, w_obj2, _):
@@ -836,7 +837,7 @@
             elif self.name == 'reshape':
                 w_arg = self.args[1]
                 assert isinstance(w_arg, ArrayConstant)
-                order = -1 
+                order = -1
                 w_res = arr.reshape(interp.space, w_arg.wrap(interp.space), 
order)
             else:
                 assert False
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py 
b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/backend_tests.py
@@ -1810,3 +1810,35 @@
         assert lib.EE1 == 0
         assert lib.EE2 == 0
         assert lib.EE3 == 1
+
+    def test_init_once(self):
+        def do_init():
+            seen.append(1)
+            return 42
+        ffi = FFI()
+        seen = []
+        for i in range(3):
+            res = ffi.init_once(do_init, "tag1")
+            assert res == 42
+            assert seen == [1]
+        for i in range(3):
+            res = ffi.init_once(do_init, "tag2")
+            assert res == 42
+            assert seen == [1, 1]
+
+    def test_init_once_multithread(self):
+        import thread, time
+        def do_init():
+            seen.append('init!')
+            time.sleep(1)
+            seen.append('init done')
+            return 7
+        ffi = FFI()
+        seen = []
+        for i in range(6):
+            def f():
+                res = ffi.init_once(do_init, "tag")
+                seen.append(res)
+            thread.start_new_thread(f, ())
+        time.sleep(1.5)
+        assert seen == ['init!', 'init done'] + 6 * [7]
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_function.py 
b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_function.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_function.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi0/test_function.py
@@ -487,7 +487,7 @@
         ffi = FFI(backend=self.Backend())
         ffi.cdef("double __stdcall sin(double x);")     # stdcall ignored
         m = ffi.dlopen(lib_m)
-        if (sys.platform == 'win32' and sys.maxint < 2**32 and 
+        if (sys.platform == 'win32' and sys.maxsize < 2**32 and 
                 self.Backend is not CTypesBackend):
             assert "double(__stdcall *)(double)" in str(ffi.typeof(m.sin))
         else:
diff --git a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_ffi_obj.py 
b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_ffi_obj.py
--- a/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_ffi_obj.py
+++ b/pypy/module/test_lib_pypy/cffi_tests/cffi1/test_ffi_obj.py
@@ -194,6 +194,11 @@
     yp = ffi.new_handle([6, 4, 2])
     assert ffi.from_handle(yp) == [6, 4, 2]
 
+def test_handle_unique():
+    ffi = _cffi1_backend.FFI()
+    assert ffi.new_handle(None) is not ffi.new_handle(None)
+    assert ffi.new_handle(None) != ffi.new_handle(None)
+
 def test_ffi_cast():
     ffi = _cffi1_backend.FFI()
     assert ffi.cast("int(*)(int)", 0) == ffi.NULL
@@ -416,3 +421,37 @@
             assert int(ffi.cast("_Bool", ffi.cast(type, 42))) == 1
             assert int(ffi.cast("bool", ffi.cast(type, 42))) == 1
             assert int(ffi.cast("_Bool", ffi.cast(type, 0))) == 0
+
+def test_init_once():
+    def do_init():
+        seen.append(1)
+        return 42
+    ffi = _cffi1_backend.FFI()
+    seen = []
+    for i in range(3):
+        res = ffi.init_once(do_init, "tag1")
+        assert res == 42
+        assert seen == [1]
+    for i in range(3):
+        res = ffi.init_once(do_init, "tag2")
+        assert res == 42
+        assert seen == [1, 1]
+
+def test_init_once_multithread():
+    import thread, time
+    def do_init():
+        print 'init!'
+        seen.append('init!')
+        time.sleep(1)
+        seen.append('init done')
+        print 'init done'
+        return 7
+    ffi = _cffi1_backend.FFI()
+    seen = []
+    for i in range(6):
+        def f():
+            res = ffi.init_once(do_init, "tag")
+            seen.append(res)
+        thread.start_new_thread(f, ())
+    time.sleep(1.5)
+    assert seen == ['init!', 'init done'] + 6 * [7]
diff --git a/pypy/module/test_lib_pypy/test_datetime.py 
b/pypy/module/test_lib_pypy/test_datetime.py
--- a/pypy/module/test_lib_pypy/test_datetime.py
+++ b/pypy/module/test_lib_pypy/test_datetime.py
@@ -309,6 +309,12 @@
         assert td_div_int_newint == td_div_newint_newint
         assert td_div_newint_int == td_div_newint_newint
 
+    def test_return_types(self):
+        td = datetime.timedelta(5)
+        assert type(td.total_seconds()) is float
+        class sub(datetime.timedelta): pass
+        assert type(+sub()) is datetime.timedelta
+
 
 class TestDatetimeHost(BaseTestDatetime):
     def setup_class(cls):
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to