1# cython.* namespace for pure mode.
2from __future__ import absolute_import
3
4__version__ = "3.0.0a9"
5
6try:
7    from __builtin__ import basestring
8except ImportError:
9    basestring = str
10
11
12# BEGIN shameless copy from Cython/minivect/minitypes.py
13
14class _ArrayType(object):
15
16    is_array = True
17    subtypes = ['dtype']
18
19    def __init__(self, dtype, ndim, is_c_contig=False, is_f_contig=False,
20                 inner_contig=False, broadcasting=None):
21        self.dtype = dtype
22        self.ndim = ndim
23        self.is_c_contig = is_c_contig
24        self.is_f_contig = is_f_contig
25        self.inner_contig = inner_contig or is_c_contig or is_f_contig
26        self.broadcasting = broadcasting
27
28    def __repr__(self):
29        axes = [":"] * self.ndim
30        if self.is_c_contig:
31            axes[-1] = "::1"
32        elif self.is_f_contig:
33            axes[0] = "::1"
34
35        return "%s[%s]" % (self.dtype, ", ".join(axes))
36
37
38def index_type(base_type, item):
39    """
40    Support array type creation by slicing, e.g. double[:, :] specifies
41    a 2D strided array of doubles. The syntax is the same as for
42    Cython memoryviews.
43    """
44    class InvalidTypeSpecification(Exception):
45        pass
46
47    def verify_slice(s):
48        if s.start or s.stop or s.step not in (None, 1):
49            raise InvalidTypeSpecification(
50                "Only a step of 1 may be provided to indicate C or "
51                "Fortran contiguity")
52
53    if isinstance(item, tuple):
54        step_idx = None
55        for idx, s in enumerate(item):
56            verify_slice(s)
57            if s.step and (step_idx or idx not in (0, len(item) - 1)):
58                raise InvalidTypeSpecification(
59                    "Step may only be provided once, and only in the "
60                    "first or last dimension.")
61
62            if s.step == 1:
63                step_idx = idx
64
65        return _ArrayType(base_type, len(item),
66                          is_c_contig=step_idx == len(item) - 1,
67                          is_f_contig=step_idx == 0)
68    elif isinstance(item, slice):
69        verify_slice(item)
70        return _ArrayType(base_type, 1, is_c_contig=bool(item.step))
71    else:
72        # int[8] etc.
73        assert int(item) == item  # array size must be a plain integer
74        return array(base_type, item)
75
76# END shameless copy
77
78
79compiled = False
80
81_Unspecified = object()
82
83# Function decorators
84
85def _empty_decorator(x):
86    return x
87
88def locals(**arg_types):
89    return _empty_decorator
90
91def test_assert_path_exists(*paths):
92    return _empty_decorator
93
94def test_fail_if_path_exists(*paths):
95    return _empty_decorator
96
97class _EmptyDecoratorAndManager(object):
98    def __call__(self, x):
99        return x
100    def __enter__(self):
101        pass
102    def __exit__(self, exc_type, exc_value, traceback):
103        pass
104
105class _Optimization(object):
106    pass
107
108cclass = ccall = cfunc = _EmptyDecoratorAndManager()
109
110returns = wraparound = boundscheck = initializedcheck = nonecheck = \
111    embedsignature = cdivision = cdivision_warnings = \
112    always_allows_keywords = profile = linetrace = infer_types = \
113    unraisable_tracebacks = freelist = \
114        lambda _: _EmptyDecoratorAndManager()
115
116exceptval = lambda _=None, check=True: _EmptyDecoratorAndManager()
117
118overflowcheck = lambda _: _EmptyDecoratorAndManager()
119optimize = _Optimization()
120
121overflowcheck.fold = optimize.use_switch = \
122    optimize.unpack_method_calls = lambda arg: _EmptyDecoratorAndManager()
123
124final = internal = type_version_tag = no_gc_clear = no_gc = total_ordering = _empty_decorator
125
126binding = lambda _: _empty_decorator
127
128
129_cython_inline = None
130def inline(f, *args, **kwds):
131    if isinstance(f, basestring):
132        global _cython_inline
133        if _cython_inline is None:
134            from Cython.Build.Inline import cython_inline as _cython_inline
135        return _cython_inline(f, *args, **kwds)
136    else:
137        assert len(args) == len(kwds) == 0
138        return f
139
140
141def compile(f):
142    from Cython.Build.Inline import RuntimeCompiledFunction
143    return RuntimeCompiledFunction(f)
144
145
146# Special functions
147
148def cdiv(a, b):
149    if a < 0:
150        a = -a
151        b = -b
152    if b < 0:
153        return (a + b + 1) // b
154    return a // b
155
156def cmod(a, b):
157    r = a % b
158    if (a * b) < 0 and r:
159        r -= b
160    return r
161
162
163# Emulated language constructs
164
165def cast(t, *args, **kwargs):
166    kwargs.pop('typecheck', None)
167    assert not kwargs
168
169    if isinstance(t, typedef):
170        return t(*args)
171    elif isinstance(t, type):  # Doesn't work with old-style classes of Python 2.x
172        if len(args) != 1 or not (args[0] is None or isinstance(args[0], t)):
173            return t(*args)
174
175    return args[0]
176
177def sizeof(arg):
178    return 1
179
180def typeof(arg):
181    return arg.__class__.__name__
182    # return type(arg)
183
184def address(arg):
185    return pointer(type(arg))([arg])
186
187def _is_value_type(t):
188    if isinstance(t, typedef):
189        return _is_value_type(t._basetype)
190
191    return isinstance(t, type) and issubclass(t, (StructType, UnionType, ArrayType))
192
193def declare(t=None, value=_Unspecified, **kwds):
194    if value is not _Unspecified:
195        return cast(t, value)
196    elif _is_value_type(t):
197        return t()
198    else:
199        return None
200
201class _nogil(object):
202    """Support for 'with nogil' statement and @nogil decorator.
203    """
204    def __call__(self, x):
205        if callable(x):
206            # Used as function decorator => return the function unchanged.
207            return x
208        # Used as conditional context manager or to create an "@nogil(True/False)" decorator => keep going.
209        return self
210
211    def __enter__(self):
212        pass
213    def __exit__(self, exc_class, exc, tb):
214        return exc_class is None
215
216nogil = _nogil()
217gil = _nogil()
218del _nogil
219
220
221# Emulated types
222
223class CythonMetaType(type):
224
225    def __getitem__(type, ix):
226        return array(type, ix)
227
228CythonTypeObject = CythonMetaType('CythonTypeObject', (object,), {})
229
230class CythonType(CythonTypeObject):
231
232    def _pointer(self, n=1):
233        for i in range(n):
234            self = pointer(self)
235        return self
236
237class PointerType(CythonType):
238
239    def __init__(self, value=None):
240        if isinstance(value, (ArrayType, PointerType)):
241            self._items = [cast(self._basetype, a) for a in value._items]
242        elif isinstance(value, list):
243            self._items = [cast(self._basetype, a) for a in value]
244        elif value is None or value == 0:
245            self._items = []
246        else:
247            raise ValueError
248
249    def __getitem__(self, ix):
250        if ix < 0:
251            raise IndexError("negative indexing not allowed in C")
252        return self._items[ix]
253
254    def __setitem__(self, ix, value):
255        if ix < 0:
256            raise IndexError("negative indexing not allowed in C")
257        self._items[ix] = cast(self._basetype, value)
258
259    def __eq__(self, value):
260        if value is None and not self._items:
261            return True
262        elif type(self) != type(value):
263            return False
264        else:
265            return not self._items and not value._items
266
267    def __repr__(self):
268        return "%s *" % (self._basetype,)
269
270class ArrayType(PointerType):
271
272    def __init__(self, value=None):
273        if value is None:
274            self._items = [None] * self._n
275        else:
276            super(ArrayType, self).__init__(value)
277
278
279class StructType(CythonType):
280
281    def __init__(self, *posargs, **data):
282        if not (posargs or data):
283            return
284        if posargs and data:
285            raise ValueError('Cannot accept both positional and keyword arguments.')
286
287        # Allow 'cast_from' as single positional or keyword argument.
288        if data and len(data) == 1 and 'cast_from' in data:
289            cast_from = data.pop('cast_from')
290        elif len(posargs) == 1 and type(posargs[0]) is type(self):
291            cast_from, posargs = posargs[0], ()
292        elif posargs:
293            for key, arg in zip(self._members, posargs):
294                setattr(self, key, arg)
295            return
296        else:
297            for key, value in data.items():
298                if key not in self._members:
299                    raise ValueError("Invalid struct attribute for %s: %s" % (
300                        self.__class__.__name__, key))
301                setattr(self, key, value)
302            return
303
304        # do cast
305        if data:
306            raise ValueError('Cannot accept keyword arguments when casting.')
307        if type(cast_from) is not type(self):
308            raise ValueError('Cannot cast from %s' % cast_from)
309        for key, value in cast_from.__dict__.items():
310            setattr(self, key, value)
311
312    def __setattr__(self, key, value):
313        if key in self._members:
314            self.__dict__[key] = cast(self._members[key], value)
315        else:
316            raise AttributeError("Struct has no member '%s'" % key)
317
318
319class UnionType(CythonType):
320
321    def __init__(self, cast_from=_Unspecified, **data):
322        if cast_from is not _Unspecified:
323            # do type cast
324            if len(data) > 0:
325                raise ValueError('Cannot accept keyword arguments when casting.')
326            if isinstance(cast_from, dict):
327                datadict = cast_from
328            elif type(cast_from) is type(self):
329                datadict = cast_from.__dict__
330            else:
331                raise ValueError('Cannot cast from %s' % cast_from)
332        else:
333            datadict = data
334        if len(datadict) > 1:
335            raise AttributeError("Union can only store one field at a time.")
336        for key, value in datadict.items():
337            setattr(self, key, value)
338
339    def __setattr__(self, key, value):
340        if key in '__dict__':
341            CythonType.__setattr__(self, key, value)
342        elif key in self._members:
343            self.__dict__ = {key: cast(self._members[key], value)}
344        else:
345            raise AttributeError("Union has no member '%s'" % key)
346
347def pointer(basetype):
348    class PointerInstance(PointerType):
349        _basetype = basetype
350    return PointerInstance
351
352def array(basetype, n):
353    class ArrayInstance(ArrayType):
354        _basetype = basetype
355        _n = n
356    return ArrayInstance
357
358def struct(**members):
359    class StructInstance(StructType):
360        _members = members
361    for key in members:
362        setattr(StructInstance, key, None)
363    return StructInstance
364
365def union(**members):
366    class UnionInstance(UnionType):
367        _members = members
368    for key in members:
369        setattr(UnionInstance, key, None)
370    return UnionInstance
371
372class typedef(CythonType):
373
374    def __init__(self, type, name=None):
375        self._basetype = type
376        self.name = name
377
378    def __call__(self, *arg):
379        value = cast(self._basetype, *arg)
380        return value
381
382    def __repr__(self):
383        return self.name or str(self._basetype)
384
385    __getitem__ = index_type
386
387class _FusedType(CythonType):
388    pass
389
390
391def fused_type(*args):
392    if not args:
393        raise TypeError("Expected at least one type as argument")
394
395    # Find the numeric type with biggest rank if all types are numeric
396    rank = -1
397    for type in args:
398        if type not in (py_int, py_long, py_float, py_complex):
399            break
400
401        if type_ordering.index(type) > rank:
402            result_type = type
403    else:
404        return result_type
405
406    # Not a simple numeric type, return a fused type instance. The result
407    # isn't really meant to be used, as we can't keep track of the context in
408    # pure-mode. Casting won't do anything in this case.
409    return _FusedType()
410
411
412def _specialized_from_args(signatures, args, kwargs):
413    "Perhaps this should be implemented in a TreeFragment in Cython code"
414    raise Exception("yet to be implemented")
415
416
417py_int = typedef(int, "int")
418try:
419    py_long = typedef(long, "long")
420except NameError:  # Py3
421    py_long = typedef(int, "long")
422py_float = typedef(float, "float")
423py_complex = typedef(complex, "double complex")
424
425
426# Predefined types
427
428int_types = [
429    'char',
430    'short',
431    'Py_UNICODE',
432    'int',
433    'Py_UCS4',
434    'long',
435    'longlong',
436    'Py_hash_t',
437    'Py_ssize_t',
438    'size_t',
439]
440float_types = [
441    'longdouble',
442    'double',
443    'float',
444]
445complex_types = [
446    'longdoublecomplex',
447    'doublecomplex',
448    'floatcomplex',
449    'complex',
450]
451other_types = [
452    'bint',
453    'void',
454    'Py_tss_t',
455]
456
457to_repr = {
458    'longlong': 'long long',
459    'longdouble': 'long double',
460    'longdoublecomplex': 'long double complex',
461    'doublecomplex': 'double complex',
462    'floatcomplex': 'float complex',
463}.get
464
465gs = globals()
466
467# note: cannot simply name the unicode type here as 2to3 gets in the way and replaces it by str
468try:
469    import __builtin__ as builtins
470except ImportError:  # Py3
471    import builtins
472
473gs['unicode'] = typedef(getattr(builtins, 'unicode', str), 'unicode')
474del builtins
475
476for name in int_types:
477    reprname = to_repr(name, name)
478    gs[name] = typedef(py_int, reprname)
479    if name not in ('Py_UNICODE', 'Py_UCS4') and not name.endswith('size_t'):
480        gs['u'+name] = typedef(py_int, "unsigned " + reprname)
481        gs['s'+name] = typedef(py_int, "signed " + reprname)
482
483for name in float_types:
484    gs[name] = typedef(py_float, to_repr(name, name))
485
486for name in complex_types:
487    gs[name] = typedef(py_complex, to_repr(name, name))
488
489bint = typedef(bool, "bint")
490void = typedef(None, "void")
491Py_tss_t = typedef(None, "Py_tss_t")
492
493for t in int_types + float_types + complex_types + other_types:
494    for i in range(1, 4):
495        gs["%s_%s" % ('p'*i, t)] = gs[t]._pointer(i)
496
497NULL = gs['p_void'](0)
498
499# looks like 'gs' has some users out there by now...
500#del gs
501
502integral = floating = numeric = _FusedType()
503
504type_ordering = [py_int, py_long, py_float, py_complex]
505
506class CythonDotParallel(object):
507    """
508    The cython.parallel module.
509    """
510
511    __all__ = ['parallel', 'prange', 'threadid']
512
513    def parallel(self, num_threads=None):
514        return nogil
515
516    def prange(self, start=0, stop=None, step=1, nogil=False, schedule=None, chunksize=None, num_threads=None):
517        if stop is None:
518            stop = start
519            start = 0
520        return range(start, stop, step)
521
522    def threadid(self):
523        return 0
524
525    # def threadsavailable(self):
526        # return 1
527
528
529class CythonCImports(object):
530    """
531    Simplistic module mock to make cimports sort-of work in Python code.
532    """
533    def __init__(self, module):
534        self.__path__ = []
535        self.__file__ = None
536        self.__name__ = module
537        self.__package__ = module
538
539    def __getattr__(self, item):
540        if item.startswith('__') and item.endswith('__'):
541            raise AttributeError(item)
542        return __import__(item)
543
544
545import math, sys
546sys.modules['cython.parallel'] = CythonDotParallel()
547sys.modules['cython.cimports'] = CythonCImports('cython.cimports')
548sys.modules['cython.cimports.libc'] = CythonCImports('cython.cimports.libc')
549sys.modules['cython.cimports.libc.math'] = math
550del math, sys
551