[pypy-commit] pypy default: merge a major refactoring of parts of cpyext to default
mattip
pypy.commits at gmail.com
Wed Apr 27 11:17:12 EDT 2016
Author: Matti Picus <matti.picus at gmail.com>
Branch:
Changeset: r83988:26e1999e0803
Date: 2016-04-27 18:16 +0300
http://bitbucket.org/pypy/pypy/changeset/26e1999e0803/
Log: merge a major refactoring of parts of cpyext to default
diff too long, truncating to 2000 out of 8378 lines
diff --git a/TODO b/TODO
new file mode 100644
--- /dev/null
+++ b/TODO
@@ -0,0 +1,3 @@
+* python setup.py install in numpy does not somehow tell setuptools
+ it's installed (I bet it's about the py27 tag)
+* reduce size of generated c code from slot definitions in slotdefs.
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -22,3 +22,24 @@
JIT: use bitstrings to compress the lists of read or written descrs
that we attach to EffectInfo. Fixes a problem we had in
remove-objspace-options.
+
+.. branch: cpyext-for-merge
+Update cpyext C-API support:
+ - allow c-snippet tests to be run with -A so we can verify we are compatible
+ - fix many edge cases exposed by fixing tests to run with -A
+ - issequence() logic matches cpython
+ - make PyStringObject and PyUnicodeObject field names compatible with cpython
+ - add prelminary support for PyDateTime_*
+ - support PyComplexObject, PyFloatObject, PyDict_Merge, PyDictProxy,
+ PyMemoryView_*, _Py_HashDouble, PyFile_AsFile, PyFile_FromFile,
+ - PyAnySet_CheckExact, PyUnicode_Concat
+ - improve support for PyGILState_Ensure, PyGILState_Release, and thread
+ primitives, also find a case where CPython will allow thread creation
+ before PyEval_InitThreads is run, dissallow on PyPy
+ - create a PyObject-specific list strategy
+ - rewrite slot assignment for typeobjects
+ - improve tracking of PyObject to rpython object mapping
+ - support tp_as_{number, sequence, mapping, buffer} slots
+After this branch, we are almost able to support upstream numpy via cpyext, so
+we created (yet another) fork of numpy at github.com/pypy/numpy with the needed
+changes
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1176,7 +1176,27 @@
return self.w_False
def issequence_w(self, w_obj):
- return (self.findattr(w_obj, self.wrap("__getitem__")) is not None)
+ if self.is_oldstyle_instance(w_obj):
+ return (self.findattr(w_obj, self.wrap('__getitem__')) is not None)
+ flag = self.type(w_obj).flag_map_or_seq
+ if flag == 'M':
+ return False
+ elif flag == 'S':
+ return True
+ else:
+ return (self.lookup(w_obj, '__getitem__') is not None)
+
+ def ismapping_w(self, w_obj):
+ if self.is_oldstyle_instance(w_obj):
+ return (self.findattr(w_obj, self.wrap('__getitem__')) is not None)
+ flag = self.type(w_obj).flag_map_or_seq
+ if flag == 'M':
+ return True
+ elif flag == 'S':
+ return False
+ else:
+ return (self.lookup(w_obj, '__getitem__') is not None and
+ self.lookup(w_obj, '__getslice__') is None)
# The code below only works
# for the simple case (new-style instance).
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -37,6 +37,8 @@
from rpython.tool.sourcetools import func_with_new_name
from rpython.rtyper.lltypesystem.lloperation import llop
from rpython.rlib import rawrefcount
+from rpython.rlib import rthread
+from rpython.rlib.debug import fatalerror_notb
DEBUG_WRAPPER = True
@@ -85,11 +87,13 @@
FILEP = rffi.COpaquePtr('FILE')
if sys.platform == 'win32':
- fileno = rffi.llexternal('_fileno', [FILEP], rffi.INT)
+ dash = '_'
else:
- fileno = rffi.llexternal('fileno', [FILEP], rffi.INT)
-
+ dash = ''
+fileno = rffi.llexternal(dash + 'fileno', [FILEP], rffi.INT)
fopen = rffi.llexternal('fopen', [CONST_STRING, CONST_STRING], FILEP)
+fdopen = rffi.llexternal(dash + 'fdopen', [rffi.INT, CONST_STRING],
+ FILEP, save_err=rffi.RFFI_SAVE_ERRNO)
_fclose = rffi.llexternal('fclose', [FILEP], rffi.INT)
def fclose(fp):
@@ -119,16 +123,18 @@
def is_valid_fp(fp):
return is_valid_fd(fileno(fp))
+pypy_decl = 'pypy_decl.h'
+
constant_names = """
Py_TPFLAGS_READY Py_TPFLAGS_READYING Py_TPFLAGS_HAVE_GETCHARBUFFER
-METH_COEXIST METH_STATIC METH_CLASS
+METH_COEXIST METH_STATIC METH_CLASS Py_TPFLAGS_BASETYPE
METH_NOARGS METH_VARARGS METH_KEYWORDS METH_O
Py_TPFLAGS_HEAPTYPE Py_TPFLAGS_HAVE_CLASS
Py_LT Py_LE Py_EQ Py_NE Py_GT Py_GE Py_TPFLAGS_CHECKTYPES
""".split()
for name in constant_names:
setattr(CConfig_constants, name, rffi_platform.ConstantInteger(name))
-udir.join('pypy_decl.h').write("/* Will be filled later */\n")
+udir.join(pypy_decl).write("/* Will be filled later */\n")
udir.join('pypy_structmember_decl.h').write("/* Will be filled later */\n")
udir.join('pypy_macros.h').write("/* Will be filled later */\n")
globals().update(rffi_platform.configure(CConfig_constants))
@@ -144,7 +150,7 @@
target.chmod(0444) # make the file read-only, to make sure that nobody
# edits it by mistake
-def copy_header_files(dstdir):
+def copy_header_files(dstdir, copy_numpy_headers):
# XXX: 20 lines of code to recursively copy a directory, really??
assert dstdir.check(dir=True)
headers = include_dir.listdir('*.h') + include_dir.listdir('*.inl')
@@ -152,6 +158,18 @@
headers.append(udir.join(name))
_copy_header_files(headers, dstdir)
+ if copy_numpy_headers:
+ try:
+ dstdir.mkdir('numpy')
+ except py.error.EEXIST:
+ pass
+ numpy_dstdir = dstdir / 'numpy'
+
+ numpy_include_dir = include_dir / 'numpy'
+ numpy_headers = numpy_include_dir.listdir('*.h') + numpy_include_dir.listdir('*.inl')
+ _copy_header_files(numpy_headers, numpy_dstdir)
+
+
class NotSpecified(object):
pass
_NOT_SPECIFIED = NotSpecified()
@@ -177,6 +195,61 @@
# exceptions generate a OperationError(w_SystemError); and the funtion returns
# the error value specifed in the API.
#
+# Handling of the GIL
+# -------------------
+#
+# We add a global variable 'cpyext_glob_tid' that contains a thread
+# id. Invariant: this variable always contain 0 when the PyPy GIL is
+# released. It should also contain 0 when regular RPython code
+# executes. In non-cpyext-related code, it will thus always be 0.
+#
+# **make_generic_cpy_call():** RPython to C, with the GIL held. Before
+# the call, must assert that the global variable is 0 and set the
+# current thread identifier into the global variable. After the call,
+# assert that the global variable still contains the current thread id,
+# and reset it to 0.
+#
+# **make_wrapper():** C to RPython; by default assume that the GIL is
+# held, but accepts gil="acquire", "release", "around",
+# "pygilstate_ensure", "pygilstate_release".
+#
+# When a wrapper() is called:
+#
+# * "acquire": assert that the GIL is not currently held, i.e. the
+# global variable does not contain the current thread id (otherwise,
+# deadlock!). Acquire the PyPy GIL. After we acquired it, assert
+# that the global variable is 0 (it must be 0 according to the
+# invariant that it was 0 immediately before we acquired the GIL,
+# because the GIL was released at that point).
+#
+# * gil=None: we hold the GIL already. Assert that the current thread
+# identifier is in the global variable, and replace it with 0.
+#
+# * "pygilstate_ensure": if the global variable contains the current
+# thread id, replace it with 0 and set the extra arg to 0. Otherwise,
+# do the "acquire" and set the extra arg to 1. Then we'll call
+# pystate.py:PyGILState_Ensure() with this extra arg, which will do
+# the rest of the logic.
+#
+# When a wrapper() returns, first assert that the global variable is
+# still 0, and then:
+#
+# * "release": release the PyPy GIL. The global variable was 0 up to
+# and including at the point where we released the GIL, but afterwards
+# it is possible that the GIL is acquired by a different thread very
+# quickly.
+#
+# * gil=None: we keep holding the GIL. Set the current thread
+# identifier into the global variable.
+#
+# * "pygilstate_release": if the argument is PyGILState_UNLOCKED,
+# release the PyPy GIL; otherwise, set the current thread identifier
+# into the global variable. The rest of the logic of
+# PyGILState_Release() should be done before, in pystate.py.
+
+cpyext_glob_tid_ptr = lltype.malloc(rffi.CArray(lltype.Signed), 1,
+ flavor='raw', immortal=True, zero=True)
+
cpyext_namespace = NameManager('cpyext_')
@@ -196,6 +269,9 @@
argnames, varargname, kwargname = pycode.cpython_code_signature(callable.func_code)
assert argnames[0] == 'space'
+ if gil == 'pygilstate_ensure':
+ assert argnames[-1] == 'previous_state'
+ del argnames[-1]
self.argnames = argnames[1:]
assert len(self.argnames) == len(self.argtypes)
self.gil = gil
@@ -414,15 +490,14 @@
'PyThread_acquire_lock', 'PyThread_release_lock',
'PyThread_create_key', 'PyThread_delete_key', 'PyThread_set_key_value',
'PyThread_get_key_value', 'PyThread_delete_key_value',
- 'PyThread_ReInitTLS',
+ 'PyThread_ReInitTLS', 'PyThread_init_thread',
+ 'PyThread_start_new_thread',
'PyStructSequence_InitType', 'PyStructSequence_New',
'PyStructSequence_UnnamedField',
'PyFunction_Type', 'PyMethod_Type', 'PyRange_Type', 'PyTraceBack_Type',
- 'PyArray_Type', '_PyArray_FILLWBYTE', '_PyArray_ZEROS', '_PyArray_CopyInto',
-
'Py_DebugFlag', 'Py_VerboseFlag', 'Py_InteractiveFlag', 'Py_InspectFlag',
'Py_OptimizeFlag', 'Py_NoSiteFlag', 'Py_BytesWarningFlag', 'Py_UseClassExceptionsFlag',
'Py_FrozenFlag', 'Py_TabcheckFlag', 'Py_UnicodeFlag', 'Py_IgnoreEnvironmentFlag',
@@ -431,11 +506,11 @@
]
TYPES = {}
GLOBALS = { # this needs to include all prebuilt pto, otherwise segfaults occur
- '_Py_NoneStruct#': ('PyObject*', 'space.w_None'),
- '_Py_TrueStruct#': ('PyIntObject*', 'space.w_True'),
- '_Py_ZeroStruct#': ('PyIntObject*', 'space.w_False'),
- '_Py_NotImplementedStruct#': ('PyObject*', 'space.w_NotImplemented'),
- '_Py_EllipsisObject#': ('PyObject*', 'space.w_Ellipsis'),
+ '_Py_NoneStruct#%s' % pypy_decl: ('PyObject*', 'space.w_None'),
+ '_Py_TrueStruct#%s' % pypy_decl: ('PyIntObject*', 'space.w_True'),
+ '_Py_ZeroStruct#%s' % pypy_decl: ('PyIntObject*', 'space.w_False'),
+ '_Py_NotImplementedStruct#%s' % pypy_decl: ('PyObject*', 'space.w_NotImplemented'),
+ '_Py_EllipsisObject#%s' % pypy_decl: ('PyObject*', 'space.w_Ellipsis'),
'PyDateTimeAPI': ('PyDateTime_CAPI*', 'None'),
}
FORWARD_DECLS = []
@@ -461,6 +536,7 @@
"PyUnicode_Type": "space.w_unicode",
"PyBaseString_Type": "space.w_basestring",
"PyDict_Type": "space.w_dict",
+ "PyDictProxy_Type": "cpyext.dictobject.make_frozendict(space)",
"PyTuple_Type": "space.w_tuple",
"PyList_Type": "space.w_list",
"PySet_Type": "space.w_set",
@@ -484,7 +560,7 @@
'PyCFunction_Type': 'space.gettypeobject(cpyext.methodobject.W_PyCFunctionObject.typedef)',
'PyWrapperDescr_Type': 'space.gettypeobject(cpyext.methodobject.W_PyCMethodObject.typedef)'
}.items():
- GLOBALS['%s#' % (cpyname, )] = ('PyTypeObject*', pypyexpr)
+ GLOBALS['%s#%s' % (cpyname, pypy_decl)] = ('PyTypeObject*', pypyexpr)
for cpyname in '''PyMethodObject PyListObject PyLongObject
PyDictObject PyClassObject'''.split():
@@ -602,7 +678,14 @@
fatal_value = callable.api_func.restype._defl()
gil_acquire = (gil == "acquire" or gil == "around")
gil_release = (gil == "release" or gil == "around")
- assert gil is None or gil_acquire or gil_release
+ pygilstate_ensure = (gil == "pygilstate_ensure")
+ pygilstate_release = (gil == "pygilstate_release")
+ assert (gil is None or gil_acquire or gil_release
+ or pygilstate_ensure or pygilstate_release)
+ deadlock_error = ("GIL deadlock detected when a CPython C extension "
+ "module calls %r" % (callable.__name__,))
+ no_gil_error = ("GIL not held when a CPython C extension "
+ "module calls %r" % (callable.__name__,))
@specialize.ll()
def wrapper(*args):
@@ -610,8 +693,27 @@
from pypy.module.cpyext.pyobject import as_pyobj
# we hope that malloc removal removes the newtuple() that is
# inserted exactly here by the varargs specializer
+
+ # see "Handling of the GIL" above (careful, we don't have the GIL here)
+ tid = rthread.get_or_make_ident()
if gil_acquire:
+ if cpyext_glob_tid_ptr[0] == tid:
+ fatalerror_notb(deadlock_error)
rgil.acquire()
+ assert cpyext_glob_tid_ptr[0] == 0
+ elif pygilstate_ensure:
+ from pypy.module.cpyext import pystate
+ if cpyext_glob_tid_ptr[0] == tid:
+ cpyext_glob_tid_ptr[0] = 0
+ args += (pystate.PyGILState_LOCKED,)
+ else:
+ rgil.acquire()
+ args += (pystate.PyGILState_UNLOCKED,)
+ else:
+ if cpyext_glob_tid_ptr[0] != tid:
+ fatalerror_notb(no_gil_error)
+ cpyext_glob_tid_ptr[0] = 0
+
rffi.stackcounter.stacks_counter += 1
llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py
retval = fatal_value
@@ -620,7 +722,8 @@
try:
if not we_are_translated() and DEBUG_WRAPPER:
print >>sys.stderr, callable,
- assert len(args) == len(callable.api_func.argtypes)
+ assert len(args) == (len(callable.api_func.argtypes) +
+ pygilstate_ensure)
for i, (typ, is_wrapped) in argtypes_enum_ui:
arg = args[i]
if is_PyObject(typ) and is_wrapped:
@@ -629,6 +732,8 @@
else:
arg_conv = arg
boxed_args += (arg_conv, )
+ if pygilstate_ensure:
+ boxed_args += (args[-1], )
state = space.fromcache(State)
try:
result = callable(space, *boxed_args)
@@ -688,8 +793,20 @@
pypy_debug_catch_fatal_exception()
assert False
rffi.stackcounter.stacks_counter -= 1
- if gil_release:
+
+ # see "Handling of the GIL" above
+ assert cpyext_glob_tid_ptr[0] == 0
+ if pygilstate_release:
+ from pypy.module.cpyext import pystate
+ arg = rffi.cast(lltype.Signed, args[-1])
+ unlock = (arg == pystate.PyGILState_UNLOCKED)
+ else:
+ unlock = gil_release
+ if unlock:
rgil.release()
+ else:
+ cpyext_glob_tid_ptr[0] = tid
+
return retval
callable._always_inline_ = 'try'
wrapper.__name__ = "wrapper for %r" % (callable, )
@@ -782,6 +899,9 @@
structindex = {}
for header, header_functions in FUNCTIONS_BY_HEADER.iteritems():
for name, func in header_functions.iteritems():
+ if not func:
+ # added only for the macro, not the decl
+ continue
restype, args = c_function_signature(db, func)
members.append('%s (*%s)(%s);' % (restype, name, args))
structindex[name] = len(structindex)
@@ -798,7 +918,7 @@
global_objects = []
for name, (typ, expr) in GLOBALS.iteritems():
- if "#" in name:
+ if '#' in name:
continue
if typ == 'PyDateTime_CAPI*':
continue
@@ -822,7 +942,7 @@
'\n' +
'\n'.join(functions))
- eci = build_eci(True, export_symbols, code)
+ eci = build_eci(True, export_symbols, code, use_micronumpy)
eci = eci.compile_shared_lib(
outputfilename=str(udir / "module_cache" / "pypyapi"))
modulename = py.path.local(eci.libraries[-1])
@@ -834,7 +954,7 @@
ob = rawrefcount.next_dead(PyObject)
if not ob:
break
- print ob
+ print 'deallocating PyObject', ob
decref(space, ob)
print 'dealloc_trigger DONE'
return "RETRY"
@@ -853,8 +973,8 @@
for name, (typ, expr) in GLOBALS.iteritems():
from pypy.module import cpyext # for the eval() below
w_obj = eval(expr)
- if name.endswith('#'):
- name = name[:-1]
+ if '#' in name:
+ name = name.split('#')[0]
isptr = False
else:
isptr = True
@@ -899,7 +1019,7 @@
# ctypes.c_void_p)
for header, header_functions in FUNCTIONS_BY_HEADER.iteritems():
for name, func in header_functions.iteritems():
- if name.startswith('cpyext_'): # XXX hack
+ if name.startswith('cpyext_') or func is None: # XXX hack
continue
pypyAPI[structindex[name]] = ctypes.cast(
ll2ctypes.lltype2ctypes(func.get_llhelper(space)),
@@ -952,6 +1072,8 @@
cpyext_type_init = self.cpyext_type_init
self.cpyext_type_init = None
for pto, w_type in cpyext_type_init:
+ if space.is_w(w_type, space.w_str):
+ pto.c_tp_itemsize = 1
finish_type_1(space, pto)
finish_type_2(space, pto, w_type)
@@ -969,10 +1091,14 @@
pypy_macros = []
renamed_symbols = []
for name in export_symbols:
- name = name.replace("#", "")
+ if '#' in name:
+ name,header = name.split('#')
+ else:
+ header = pypy_decl
newname = mangle_name(prefix, name)
assert newname, name
- pypy_macros.append('#define %s %s' % (name, newname))
+ if header == pypy_decl:
+ pypy_macros.append('#define %s %s' % (name, newname))
if name.startswith("PyExc_"):
pypy_macros.append('#define _%s _%s' % (name, newname))
renamed_symbols.append(newname)
@@ -1001,7 +1127,7 @@
# implement function callbacks and generate function decls
functions = []
decls = {}
- pypy_decls = decls['pypy_decl.h'] = []
+ pypy_decls = decls[pypy_decl] = []
pypy_decls.append('#define Signed long /* xxx temporary fix */\n')
pypy_decls.append('#define Unsigned unsigned long /* xxx temporary fix */\n')
@@ -1017,6 +1143,8 @@
header = decls[header_name]
for name, func in sorted(header_functions.iteritems()):
+ if not func:
+ continue
if header == DEFAULT_HEADER:
_name = name
else:
@@ -1042,12 +1170,15 @@
functions.append(header + '\n{return va_arg(*vp, %s);}\n' % name)
for name, (typ, expr) in GLOBALS.iteritems():
- if name.endswith('#'):
- name = name.replace("#", "")
+ if '#' in name:
+ name, header = name.split("#")
typ = typ.replace("*", "")
elif name.startswith('PyExc_'):
typ = 'PyObject*'
- pypy_decls.append('PyAPI_DATA(%s) %s;' % (typ, name))
+ header = pypy_decl
+ if header != pypy_decl:
+ decls[header].append('#define %s %s' % (name, mangle_name(prefix, name)))
+ decls[header].append('PyAPI_DATA(%s) %s;' % (typ, name))
for header_name in FUNCTIONS_BY_HEADER.keys():
header = decls[header_name]
@@ -1075,9 +1206,10 @@
source_dir / "pysignals.c",
source_dir / "pythread.c",
source_dir / "missing.c",
+ source_dir / "pymem.c",
]
-def build_eci(building_bridge, export_symbols, code):
+def build_eci(building_bridge, export_symbols, code, use_micronumpy=False):
"NOT_RPYTHON"
# Build code and get pointer to the structure
kwds = {}
@@ -1099,9 +1231,11 @@
# Generate definitions for global structures
structs = ["#include <Python.h>"]
+ if use_micronumpy:
+ structs.append('#include <pypy_numpy.h> /* api.py line 1223 */')
for name, (typ, expr) in GLOBALS.iteritems():
- if name.endswith('#'):
- structs.append('%s %s;' % (typ[:-1], name[:-1]))
+ if '#' in name:
+ structs.append('%s %s;' % (typ[:-1], name.split('#')[0]))
elif name.startswith('PyExc_'):
structs.append('PyTypeObject _%s;' % (name,))
structs.append('PyObject* %s = (PyObject*)&_%s;' % (name, name))
@@ -1142,11 +1276,12 @@
use_micronumpy = space.config.objspace.usemodules.micronumpy
if not use_micronumpy:
return use_micronumpy
- # import to register api functions by side-effect
- import pypy.module.cpyext.ndarrayobject
- global GLOBALS, SYMBOLS_C, separate_module_files
- GLOBALS["PyArray_Type#"]= ('PyTypeObject*', "space.gettypeobject(W_NDimArray.typedef)")
- SYMBOLS_C += ['PyArray_Type', '_PyArray_FILLWBYTE', '_PyArray_ZEROS']
+ # import registers api functions by side-effect, we also need HEADER
+ from pypy.module.cpyext.ndarrayobject import HEADER
+ global GLOBALS, FUNCTIONS_BY_HEADER, separate_module_files
+ for func_name in ['PyArray_Type', '_PyArray_FILLWBYTE', '_PyArray_ZEROS']:
+ FUNCTIONS_BY_HEADER.setdefault(HEADER, {})[func_name] = None
+ GLOBALS["PyArray_Type#%s" % HEADER] = ('PyTypeObject*', "space.gettypeobject(W_NDimArray.typedef)")
separate_module_files.append(source_dir / "ndarrayobject.c")
return use_micronumpy
@@ -1156,14 +1291,18 @@
export_symbols = sorted(FUNCTIONS) + sorted(SYMBOLS_C) + sorted(GLOBALS)
from rpython.translator.c.database import LowLevelDatabase
db = LowLevelDatabase()
+ prefix = 'PyPy'
- generate_macros(export_symbols, prefix='PyPy')
+ generate_macros(export_symbols, prefix=prefix)
functions = generate_decls_and_callbacks(db, [], api_struct=False,
- prefix='PyPy')
- code = "#include <Python.h>\n" + "\n".join(functions)
+ prefix=prefix)
+ code = "#include <Python.h>\n"
+ if use_micronumpy:
+ code += "#include <pypy_numpy.h> /* api.py line 1290 */"
+ code += "\n".join(functions)
- eci = build_eci(False, export_symbols, code)
+ eci = build_eci(False, export_symbols, code, use_micronumpy)
space.fromcache(State).install_dll(eci)
@@ -1175,9 +1314,14 @@
lines = ['PyObject *pypy_static_pyobjs[] = {\n']
include_lines = ['RPY_EXTERN PyObject *pypy_static_pyobjs[];\n']
for name, (typ, expr) in sorted(GLOBALS.items()):
- if name.endswith('#'):
+ if '#' in name:
+ name, header = name.split('#')
assert typ in ('PyObject*', 'PyTypeObject*', 'PyIntObject*')
- typ, name = typ[:-1], name[:-1]
+ typ = typ[:-1]
+ if header != pypy_decl:
+ # since the #define is not in pypy_macros, do it here
+ mname = mangle_name(prefix, name)
+ include_lines.append('#define %s %s\n' % (name, mname))
elif name.startswith('PyExc_'):
typ = 'PyTypeObject'
name = '_' + name
@@ -1204,6 +1348,8 @@
for header, header_functions in FUNCTIONS_BY_HEADER.iteritems():
for name, func in header_functions.iteritems():
+ if not func:
+ continue
newname = mangle_name('PyPy', name) or name
deco = entrypoint_lowlevel("cpyext", func.argtypes, newname,
relax=True)
@@ -1211,7 +1357,7 @@
setup_init_functions(eci, translating=True)
trunk_include = pypydir.dirpath() / 'include'
- copy_header_files(trunk_include)
+ copy_header_files(trunk_include, use_micronumpy)
def init_static_data_translated(space):
builder = space.fromcache(StaticObjectBuilder)
@@ -1348,10 +1494,17 @@
arg = as_pyobj(space, arg)
boxed_args += (arg,)
+ # see "Handling of the GIL" above
+ tid = rthread.get_ident()
+ assert cpyext_glob_tid_ptr[0] == 0
+ cpyext_glob_tid_ptr[0] = tid
+
try:
# Call the function
result = call_external_function(func, *boxed_args)
finally:
+ assert cpyext_glob_tid_ptr[0] == tid
+ cpyext_glob_tid_ptr[0] = 0
keepalive_until_here(*keepalives)
if is_PyObject(RESULT_TYPE):
diff --git a/pypy/module/cpyext/bytesobject.py b/pypy/module/cpyext/bytesobject.py
--- a/pypy/module/cpyext/bytesobject.py
+++ b/pypy/module/cpyext/bytesobject.py
@@ -2,11 +2,11 @@
from rpython.rtyper.lltypesystem import rffi, lltype
from pypy.module.cpyext.api import (
cpython_api, cpython_struct, bootstrap_function, build_type_checkers,
- PyObjectFields, Py_ssize_t, CONST_STRING, CANNOT_FAIL)
+ PyObjectFields, PyVarObjectFields, Py_ssize_t, CONST_STRING, CANNOT_FAIL)
from pypy.module.cpyext.pyerrors import PyErr_BadArgument
from pypy.module.cpyext.pyobject import (
PyObject, PyObjectP, Py_DecRef, make_ref, from_ref, track_reference,
- make_typedescr, get_typedescr)
+ make_typedescr, get_typedescr, as_pyobj, Py_IncRef)
##
## Implementation of PyStringObject
@@ -27,7 +27,7 @@
## Solution
## --------
##
-## PyStringObject contains two additional members: the size and a pointer to a
+## PyStringObject contains two additional members: the ob_size and a pointer to a
## char buffer; it may be NULL.
##
## - A string allocated by pypy will be converted into a PyStringObject with a
@@ -36,7 +36,7 @@
##
## - A string allocated with PyString_FromStringAndSize(NULL, size) will
## allocate a PyStringObject structure, and a buffer with the specified
-## size, but the reference won't be stored in the global map; there is no
+## size+1, but the reference won't be stored in the global map; there is no
## corresponding object in pypy. When from_ref() or Py_INCREF() is called,
## the pypy string is created, and added to the global map of tracked
## objects. The buffer is then supposed to be immutable.
@@ -52,8 +52,8 @@
PyStringObjectStruct = lltype.ForwardReference()
PyStringObject = lltype.Ptr(PyStringObjectStruct)
-PyStringObjectFields = PyObjectFields + \
- (("buffer", rffi.CCHARP), ("size", Py_ssize_t))
+PyStringObjectFields = PyVarObjectFields + \
+ (("ob_shash", rffi.LONG), ("ob_sstate", rffi.INT), ("buffer", rffi.CCHARP))
cpython_struct("PyStringObject", PyStringObjectFields, PyStringObjectStruct)
@bootstrap_function
@@ -78,10 +78,11 @@
py_str = rffi.cast(PyStringObject, py_obj)
buflen = length + 1
- py_str.c_size = length
+ py_str.c_ob_size = length
py_str.c_buffer = lltype.malloc(rffi.CCHARP.TO, buflen,
flavor='raw', zero=True,
add_memory_pressure=True)
+ py_str.c_ob_sstate = rffi.cast(rffi.INT, 0) # SSTATE_NOT_INTERNED
return py_str
def string_attach(space, py_obj, w_obj):
@@ -90,8 +91,10 @@
buffer must not be modified.
"""
py_str = rffi.cast(PyStringObject, py_obj)
- py_str.c_size = len(space.str_w(w_obj))
+ py_str.c_ob_size = len(space.str_w(w_obj))
py_str.c_buffer = lltype.nullptr(rffi.CCHARP.TO)
+ py_str.c_ob_shash = space.hash_w(w_obj)
+ py_str.c_ob_sstate = rffi.cast(rffi.INT, 1) # SSTATE_INTERNED_MORTAL
def string_realize(space, py_obj):
"""
@@ -99,8 +102,13 @@
be modified after this call.
"""
py_str = rffi.cast(PyStringObject, py_obj)
- s = rffi.charpsize2str(py_str.c_buffer, py_str.c_size)
+ if not py_str.c_buffer:
+ py_str.c_buffer = lltype.malloc(rffi.CCHARP.TO, py_str.c_ob_size + 1,
+ flavor='raw', zero=True)
+ s = rffi.charpsize2str(py_str.c_buffer, py_str.c_ob_size)
w_obj = space.wrap(s)
+ py_str.c_ob_shash = space.hash_w(w_obj)
+ py_str.c_ob_sstate = rffi.cast(rffi.INT, 1) # SSTATE_INTERNED_MORTAL
track_reference(space, py_obj, w_obj)
return w_obj
@@ -169,12 +177,12 @@
ref_str.c_buffer = rffi.str2charp(s)
buffer[0] = ref_str.c_buffer
if length:
- length[0] = ref_str.c_size
+ length[0] = ref_str.c_ob_size
else:
i = 0
while ref_str.c_buffer[i] != '\0':
i += 1
- if i != ref_str.c_size:
+ if i != ref_str.c_ob_size:
raise OperationError(space.w_TypeError, space.wrap(
"expected string without null bytes"))
return 0
@@ -183,7 +191,7 @@
def PyString_Size(space, ref):
if from_ref(space, rffi.cast(PyObject, ref.c_ob_type)) is space.w_str:
ref = rffi.cast(PyStringObject, ref)
- return ref.c_size
+ return ref.c_ob_size
else:
w_obj = from_ref(space, ref)
return space.len_w(w_obj)
@@ -212,7 +220,7 @@
ref[0] = lltype.nullptr(PyObject.TO)
raise
to_cp = newsize
- oldsize = py_str.c_size
+ oldsize = py_str.c_ob_size
if oldsize < newsize:
to_cp = oldsize
for i in range(to_cp):
@@ -236,15 +244,16 @@
if not ref[0]:
return
- if w_newpart is None or not PyString_Check(space, ref[0]) or \
- not PyString_Check(space, w_newpart):
+ if w_newpart is None or not PyString_Check(space, ref[0]) or not \
+ (space.isinstance_w(w_newpart, space.w_str) or
+ space.isinstance_w(w_newpart, space.w_unicode)):
Py_DecRef(space, ref[0])
ref[0] = lltype.nullptr(PyObject.TO)
return
w_str = from_ref(space, ref[0])
w_newstr = space.add(w_str, w_newpart)
- Py_DecRef(space, ref[0])
ref[0] = make_ref(space, w_newstr)
+ Py_IncRef(space, ref[0])
@cpython_api([PyObjectP, PyObject], lltype.Void)
def PyString_ConcatAndDel(space, ref, newpart):
diff --git a/pypy/module/cpyext/cdatetime.py b/pypy/module/cpyext/cdatetime.py
--- a/pypy/module/cpyext/cdatetime.py
+++ b/pypy/module/cpyext/cdatetime.py
@@ -42,9 +42,15 @@
return datetimeAPI
-PyDateTime_Date = PyObject
-PyDateTime_Time = PyObject
-PyDateTime_DateTime = PyObject
+PyDateTime_DateStruct = lltype.ForwardReference()
+PyDateTime_TimeStruct = lltype.ForwardReference()
+PyDateTime_DateTimeStruct = lltype.ForwardReference()
+cpython_struct("PyDateTime_Date", PyObjectFields, PyDateTime_DateStruct)
+PyDateTime_Date = lltype.Ptr(PyDateTime_DateStruct)
+cpython_struct("PyDateTime_Time", PyObjectFields, PyDateTime_TimeStruct)
+PyDateTime_Time = lltype.Ptr(PyDateTime_TimeStruct)
+cpython_struct("PyDateTime_DateTime", PyObjectFields, PyDateTime_DateTimeStruct)
+PyDateTime_DateTime = lltype.Ptr(PyDateTime_DateTimeStruct)
PyDeltaObjectStruct = lltype.ForwardReference()
cpython_struct("PyDateTime_Delta", PyObjectFields, PyDeltaObjectStruct)
diff --git a/pypy/module/cpyext/complexobject.py b/pypy/module/cpyext/complexobject.py
--- a/pypy/module/cpyext/complexobject.py
+++ b/pypy/module/cpyext/complexobject.py
@@ -1,16 +1,51 @@
from rpython.rtyper.lltypesystem import lltype, rffi
-from pypy.module.cpyext.api import (
+from pypy.module.cpyext.api import (PyObjectFields, bootstrap_function,
cpython_api, cpython_struct, PyObject, build_type_checkers)
+from pypy.module.cpyext.pyobject import (
+ make_typedescr, track_reference, from_ref)
from pypy.module.cpyext.floatobject import PyFloat_AsDouble
from pypy.objspace.std.complexobject import W_ComplexObject
from pypy.interpreter.error import OperationError
PyComplex_Check, PyComplex_CheckExact = build_type_checkers("Complex")
-Py_complex_t = lltype.ForwardReference()
+Py_complex_t = rffi.CStruct('Py_complex_t',
+ ('real', rffi.DOUBLE),
+ ('imag', rffi.DOUBLE),
+ hints={'size': 2 * rffi.sizeof(rffi.DOUBLE)})
Py_complex_ptr = lltype.Ptr(Py_complex_t)
-Py_complex_fields = (("real", rffi.DOUBLE), ("imag", rffi.DOUBLE))
-cpython_struct("Py_complex", Py_complex_fields, Py_complex_t)
+
+PyComplexObjectStruct = lltype.ForwardReference()
+PyComplexObject = lltype.Ptr(PyComplexObjectStruct)
+PyComplexObjectFields = PyObjectFields + \
+ (("cval", Py_complex_t),)
+cpython_struct("PyComplexObject", PyComplexObjectFields, PyComplexObjectStruct)
+
+ at bootstrap_function
+def init_complexobject(space):
+ "Type description of PyComplexObject"
+ make_typedescr(space.w_complex.layout.typedef,
+ basestruct=PyComplexObject.TO,
+ attach=complex_attach,
+ realize=complex_realize)
+
+def complex_attach(space, py_obj, w_obj):
+ """
+ Fills a newly allocated PyComplexObject with the given complex object. The
+ value must not be modified.
+ """
+ assert isinstance(w_obj, W_ComplexObject)
+ py_obj = rffi.cast(PyComplexObject, py_obj)
+ py_obj.c_cval.c_real = w_obj.realval
+ py_obj.c_cval.c_imag = w_obj.imagval
+
+def complex_realize(space, obj):
+ py_obj = rffi.cast(PyComplexObject, obj)
+ w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
+ w_obj = space.allocate_instance(W_ComplexObject, w_type)
+ w_obj.__init__(py_obj.c_cval.c_real, py_obj.c_cval.c_imag)
+ track_reference(space, obj, w_obj)
+ return w_obj
@cpython_api([lltype.Float, lltype.Float], PyObject)
diff --git a/pypy/module/cpyext/dictobject.py b/pypy/module/cpyext/dictobject.py
--- a/pypy/module/cpyext/dictobject.py
+++ b/pypy/module/cpyext/dictobject.py
@@ -23,6 +23,7 @@
# NOTE: this works so far because all our dict strategies store
# *values* as full objects, which stay alive as long as the dict is
# alive and not modified. So we can return a borrowed ref.
+ # XXX this is wrong with IntMutableCell. Hope it works...
return w_res
@cpython_api([PyObject, PyObject, PyObject], rffi.INT_real, error=-1)
@@ -62,6 +63,7 @@
# NOTE: this works so far because all our dict strategies store
# *values* as full objects, which stay alive as long as the dict is
# alive and not modified. So we can return a borrowed ref.
+ # XXX this is wrong with IntMutableCell. Hope it works...
return w_res
@cpython_api([PyObject, CONST_STRING], rffi.INT_real, error=-1)
@@ -104,6 +106,32 @@
"""
return space.call_method(space.w_dict, "copy", w_obj)
+def _has_val(space, w_dict, w_key):
+ try:
+ w_val = space.getitem(w_dict, w_key)
+ except OperationError as e:
+ if e.match(space, space.w_KeyError):
+ return False
+ else:
+ raise
+ return True
+
+ at cpython_api([PyObject, PyObject, rffi.INT_real], rffi.INT_real, error=-1)
+def PyDict_Merge(space, w_a, w_b, override):
+ """Iterate over mapping object b adding key-value pairs to dictionary a.
+ b may be a dictionary, or any object supporting PyMapping_Keys()
+ and PyObject_GetItem(). If override is true, existing pairs in a
+ will be replaced if a matching key is found in b, otherwise pairs will
+ only be added if there is not a matching key in a. Return 0 on
+ success or -1 if an exception was raised.
+ """
+ override = rffi.cast(lltype.Signed, override)
+ w_keys = space.call_method(w_b, "keys")
+ for w_key in space.iteriterable(w_keys):
+ if not _has_val(space, w_a, w_key) or override != 0:
+ space.setitem(w_a, w_key, space.getitem(w_b, w_key))
+ return 0
+
@cpython_api([PyObject, PyObject], rffi.INT_real, error=-1)
def PyDict_Update(space, w_obj, w_other):
"""This is the same as PyDict_Merge(a, b, 1) in C, or a.update(b) in
@@ -204,6 +232,12 @@
@specialize.memo()
def make_frozendict(space):
+ if space not in _frozendict_cache:
+ _frozendict_cache[space] = _make_frozendict(space)
+ return _frozendict_cache[space]
+
+_frozendict_cache = {}
+def _make_frozendict(space):
return space.appexec([], '''():
import _abcoll
class FrozenDict(_abcoll.Mapping):
@@ -222,3 +256,15 @@
w_frozendict = make_frozendict(space)
return space.call_function(w_frozendict, w_dict)
+ at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
+def PyDictProxy_Check(space, w_obj):
+ w_typ = make_frozendict(space)
+ #print 'check', w_typ, space.type(w_obj)
+ return space.isinstance_w(w_obj, w_typ)
+
+ at cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
+def PyDictProxy_CheckExact(space, w_obj):
+ w_typ = make_frozendict(space)
+ #print 'exact', w_typ, w_obj
+ return space.is_w(space.type(w_obj), w_typ)
+
diff --git a/pypy/module/cpyext/floatobject.py b/pypy/module/cpyext/floatobject.py
--- a/pypy/module/cpyext/floatobject.py
+++ b/pypy/module/cpyext/floatobject.py
@@ -1,8 +1,42 @@
from rpython.rtyper.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import (
+from pypy.module.cpyext.api import (PyObjectFields, bootstrap_function,
+ cpython_struct,
CANNOT_FAIL, cpython_api, PyObject, build_type_checkers, CONST_STRING)
+from pypy.module.cpyext.pyobject import (
+ make_typedescr, track_reference, from_ref)
from pypy.interpreter.error import OperationError
from rpython.rlib.rstruct import runpack
+from pypy.objspace.std.floatobject import W_FloatObject
+
+PyFloatObjectStruct = lltype.ForwardReference()
+PyFloatObject = lltype.Ptr(PyFloatObjectStruct)
+PyFloatObjectFields = PyObjectFields + \
+ (("ob_fval", rffi.DOUBLE),)
+cpython_struct("PyFloatObject", PyFloatObjectFields, PyFloatObjectStruct)
+
+ at bootstrap_function
+def init_floatobject(space):
+ "Type description of PyFloatObject"
+ make_typedescr(space.w_float.layout.typedef,
+ basestruct=PyFloatObject.TO,
+ attach=float_attach,
+ realize=float_realize)
+
+def float_attach(space, py_obj, w_obj):
+ """
+ Fills a newly allocated PyFloatObject with the given float object. The
+ value must not be modified.
+ """
+ py_float = rffi.cast(PyFloatObject, py_obj)
+ py_float.c_ob_fval = space.float_w(w_obj)
+
+def float_realize(space, obj):
+ floatval = rffi.cast(lltype.Float, rffi.cast(PyFloatObject, obj).c_ob_fval)
+ w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
+ w_obj = space.allocate_instance(W_FloatObject, w_type)
+ w_obj.__init__(floatval)
+ track_reference(space, obj, w_obj)
+ return w_obj
PyFloat_Check, PyFloat_CheckExact = build_type_checkers("Float")
diff --git a/pypy/module/cpyext/include/Python.h b/pypy/module/cpyext/include/Python.h
--- a/pypy/module/cpyext/include/Python.h
+++ b/pypy/module/cpyext/include/Python.h
@@ -112,9 +112,11 @@
#include "dictobject.h"
#include "intobject.h"
#include "listobject.h"
+#include "longobject.h"
#include "unicodeobject.h"
#include "compile.h"
#include "frameobject.h"
+#include "memoryobject.h"
#include "eval.h"
#include "pymem.h"
#include "pycobject.h"
diff --git a/pypy/module/cpyext/include/complexobject.h b/pypy/module/cpyext/include/complexobject.h
--- a/pypy/module/cpyext/include/complexobject.h
+++ b/pypy/module/cpyext/include/complexobject.h
@@ -6,14 +6,16 @@
extern "C" {
#endif
-/* fake PyComplexObject so that code that doesn't do direct field access works */
-#define PyComplexObject PyObject
-
typedef struct Py_complex_t {
double real;
double imag;
} Py_complex;
+typedef struct {
+ PyObject_HEAD
+ Py_complex cval;
+} PyComplexObject;
+
/* generated function */
PyAPI_FUNC(int) _PyComplex_AsCComplex(PyObject *, Py_complex *);
PyAPI_FUNC(PyObject *) _PyComplex_FromCComplex(Py_complex *);
diff --git a/pypy/module/cpyext/include/datetime.h b/pypy/module/cpyext/include/datetime.h
--- a/pypy/module/cpyext/include/datetime.h
+++ b/pypy/module/cpyext/include/datetime.h
@@ -24,6 +24,18 @@
PyObject_HEAD
} PyDateTime_Delta;
+typedef struct {
+ PyObject_HEAD
+} PyDateTime_Date;
+
+typedef struct {
+ PyObject_HEAD
+} PyDateTime_Time;
+
+typedef struct {
+ PyObject_HEAD
+} PyDateTime_DateTime;
+
#ifdef __cplusplus
}
#endif
diff --git a/pypy/module/cpyext/include/descrobject.h b/pypy/module/cpyext/include/descrobject.h
--- a/pypy/module/cpyext/include/descrobject.h
+++ b/pypy/module/cpyext/include/descrobject.h
@@ -12,4 +12,34 @@
} PyGetSetDef;
+#define PyDescr_COMMON \
+ PyObject_HEAD \
+ PyTypeObject *d_type; \
+ PyObject *d_name
+
+typedef struct {
+ PyDescr_COMMON;
+} PyDescrObject;
+
+typedef struct {
+ PyDescr_COMMON;
+ PyMethodDef *d_method;
+} PyMethodDescrObject;
+
+typedef struct {
+ PyDescr_COMMON;
+ struct PyMemberDef *d_member;
+} PyMemberDescrObject;
+
+typedef struct {
+ PyDescr_COMMON;
+ PyGetSetDef *d_getset;
+} PyGetSetDescrObject;
+
+typedef struct {
+ PyDescr_COMMON;
+ struct wrapperbase *d_base;
+ void *d_wrapped; /* This can be any function pointer */
+} PyWrapperDescrObject;
+
#endif
diff --git a/pypy/module/cpyext/include/floatobject.h b/pypy/module/cpyext/include/floatobject.h
--- a/pypy/module/cpyext/include/floatobject.h
+++ b/pypy/module/cpyext/include/floatobject.h
@@ -3,10 +3,22 @@
#ifndef Py_FLOATOBJECT_H
#define Py_FLOATOBJECT_H
+
+#ifdef _MSC_VER
+#include <math.h>
+#include <float.h>
+#define copysign _copysign
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
+typedef struct {
+ PyObject_HEAD
+ double ob_fval;
+} PyFloatObject;
+
#define PyFloat_STR_PRECISION 12
#ifdef Py_NAN
diff --git a/pypy/module/cpyext/include/longobject.h b/pypy/module/cpyext/include/longobject.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/longobject.h
@@ -0,0 +1,21 @@
+#ifndef Py_LONGOBJECT_H
+#define Py_LONGOBJECT_H
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* why does cpython redefine these, and even supply an implementation in mystrtoul.c?
+PyAPI_FUNC(unsigned long) PyOS_strtoul(const char *, char **, int);
+PyAPI_FUNC(long) PyOS_strtol(const char *, char **, int);
+*/
+
+#define PyOS_strtoul strtoul
+#define PyOS_strtol strtoul
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_LONGOBJECT_H */
diff --git a/pypy/module/cpyext/include/memoryobject.h b/pypy/module/cpyext/include/memoryobject.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/memoryobject.h
@@ -0,0 +1,14 @@
+#ifndef Py_MEMORYOBJECT_H
+#define Py_MEMORYOBJECT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_MEMORYOBJECT_H */
diff --git a/pypy/module/cpyext/include/numpy/README b/pypy/module/cpyext/include/numpy/README
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/numpy/README
@@ -0,0 +1,8 @@
+headers for the micronumpy multiarray and umath modules,
+as used by https://bitbucket.org/pypy/numpy. They are needed by
+downstream packages that depend on numpy, like matplotlib, but can
+be slightly non-compatible with traditional numpy C-API use cases.
+
+The trick to including these headers is in get_include, located in
+numpy/lib/utils.py. They will be ignored by an upstream build of numpy
+since the <site-packages>/numpy/core/include path will be used instead
diff --git a/pypy/module/cpyext/include/numpy/__multiarray_api.h b/pypy/module/cpyext/include/numpy/__multiarray_api.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/numpy/__multiarray_api.h
@@ -0,0 +1,11 @@
+
+
+typedef struct {
+ PyObject_HEAD
+ npy_bool obval;
+} PyBoolScalarObject;
+
+static int import_array(){return 0;};
+static int _import_array(){return 0;};
+static int _import_math(){return 0;};
+
diff --git a/pypy/module/cpyext/include/numpy/arrayobject.h b/pypy/module/cpyext/include/numpy/arrayobject.h
--- a/pypy/module/cpyext/include/numpy/arrayobject.h
+++ b/pypy/module/cpyext/include/numpy/arrayobject.h
@@ -1,6 +1,8 @@
-/* NDArray object interface - S. H. Muller, 2013/07/26 */
-/* For testing ndarrayobject only */
+/* NDArray object interface - S. H. Muller, 2013/07/26
+ * It will be copied by numpy/core/setup.py by install_data to
+ * site-packages/numpy/core/includes/numpy
+*/
#ifndef Py_NDARRAYOBJECT_H
#define Py_NDARRAYOBJECT_H
@@ -8,8 +10,14 @@
extern "C" {
#endif
+#include "pypy_numpy.h"
+#include "old_defines.h"
#include "npy_common.h"
-#include "ndarraytypes.h"
+#include "__multiarray_api.h"
+
+#define NPY_UNUSED(x) x
+#define PyArray_MAX(a,b) (((a)>(b))?(a):(b))
+#define PyArray_MIN(a,b) (((a)<(b))?(a):(b))
/* fake PyArrayObject so that code that doesn't do direct field access works */
#define PyArrayObject PyObject
@@ -17,20 +25,206 @@
PyAPI_DATA(PyTypeObject) PyArray_Type;
-#define PyArray_SimpleNew _PyArray_SimpleNew
-#define PyArray_ZEROS _PyArray_ZEROS
-#define PyArray_CopyInto _PyArray_CopyInto
-#define PyArray_FILLWBYTE _PyArray_FILLWBYTE
#define NPY_MAXDIMS 32
-/* functions defined in ndarrayobject.c*/
+#ifndef NDARRAYTYPES_H
+typedef struct {
+ npy_intp *ptr;
+ int len;
+} PyArray_Dims;
+
+/* data types copied from numpy/ndarraytypes.h
+ * keep numbers in sync with micronumpy.interp_dtype.DTypeCache
+ */
+enum NPY_TYPES { NPY_BOOL=0,
+ NPY_BYTE, NPY_UBYTE,
+ NPY_SHORT, NPY_USHORT,
+ NPY_INT, NPY_UINT,
+ NPY_LONG, NPY_ULONG,
+ NPY_LONGLONG, NPY_ULONGLONG,
+ NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE,
+ NPY_CFLOAT, NPY_CDOUBLE, NPY_CLONGDOUBLE,
+ NPY_OBJECT=17,
+ NPY_STRING, NPY_UNICODE,
+ NPY_VOID,
+ /*
+ * New 1.6 types appended, may be integrated
+ * into the above in 2.0.
+ */
+ NPY_DATETIME, NPY_TIMEDELTA, NPY_HALF,
+
+ NPY_NTYPES,
+ NPY_NOTYPE,
+ NPY_CHAR, /* special flag */
+ NPY_USERDEF=256, /* leave room for characters */
+
+ /* The number of types not including the new 1.6 types */
+ NPY_NTYPES_ABI_COMPATIBLE=21
+};
+
+#define PyTypeNum_ISBOOL(type) ((type) == NPY_BOOL)
+#define PyTypeNum_ISINTEGER(type) (((type) >= NPY_BYTE) && \
+ ((type) <= NPY_ULONGLONG))
+#define PyTypeNum_ISFLOAT(type) ((((type) >= NPY_FLOAT) && \
+ ((type) <= NPY_LONGDOUBLE)) || \
+ ((type) == NPY_HALF))
+#define PyTypeNum_ISCOMPLEX(type) (((type) >= NPY_CFLOAT) && \
+ ((type) <= NPY_CLONGDOUBLE))
+
+#define PyArray_ISBOOL(arr) (PyTypeNum_ISBOOL(PyArray_TYPE(arr)))
+#define PyArray_ISINTEGER(arr) (PyTypeNum_ISINTEGER(PyArray_TYPE(arr)))
+#define PyArray_ISFLOAT(arr) (PyTypeNum_ISFLOAT(PyArray_TYPE(arr)))
+#define PyArray_ISCOMPLEX(arr) (PyTypeNum_ISCOMPLEX(PyArray_TYPE(arr)))
+
+
+/* flags */
+#define NPY_ARRAY_C_CONTIGUOUS 0x0001
+#define NPY_ARRAY_F_CONTIGUOUS 0x0002
+#define NPY_ARRAY_OWNDATA 0x0004
+#define NPY_ARRAY_FORCECAST 0x0010
+#define NPY_ARRAY_ENSURECOPY 0x0020
+#define NPY_ARRAY_ENSUREARRAY 0x0040
+#define NPY_ARRAY_ELEMENTSTRIDES 0x0080
+#define NPY_ARRAY_ALIGNED 0x0100
+#define NPY_ARRAY_NOTSWAPPED 0x0200
+#define NPY_ARRAY_WRITEABLE 0x0400
+#define NPY_ARRAY_UPDATEIFCOPY 0x1000
+
+#define NPY_ARRAY_BEHAVED (NPY_ARRAY_ALIGNED | \
+ NPY_ARRAY_WRITEABLE)
+#define NPY_ARRAY_BEHAVED_NS (NPY_ARRAY_ALIGNED | \
+ NPY_ARRAY_WRITEABLE | \
+ NPY_ARRAY_NOTSWAPPED)
+#define NPY_ARRAY_CARRAY (NPY_ARRAY_C_CONTIGUOUS | \
+ NPY_ARRAY_BEHAVED)
+#define NPY_ARRAY_CARRAY_RO (NPY_ARRAY_C_CONTIGUOUS | \
+ NPY_ARRAY_ALIGNED)
+#define NPY_ARRAY_FARRAY (NPY_ARRAY_F_CONTIGUOUS | \
+ NPY_ARRAY_BEHAVED)
+#define NPY_ARRAY_FARRAY_RO (NPY_ARRAY_F_CONTIGUOUS | \
+ NPY_ARRAY_ALIGNED)
+#define NPY_ARRAY_DEFAULT (NPY_ARRAY_CARRAY)
+#define NPY_ARRAY_IN_ARRAY (NPY_ARRAY_CARRAY_RO)
+#define NPY_ARRAY_OUT_ARRAY (NPY_ARRAY_CARRAY)
+#define NPY_ARRAY_INOUT_ARRAY (NPY_ARRAY_CARRAY | \
+ NPY_ARRAY_UPDATEIFCOPY)
+#define NPY_ARRAY_IN_FARRAY (NPY_ARRAY_FARRAY_RO)
+#define NPY_ARRAY_OUT_FARRAY (NPY_ARRAY_FARRAY)
+#define NPY_ARRAY_INOUT_FARRAY (NPY_ARRAY_FARRAY | \
+ NPY_ARRAY_UPDATEIFCOPY)
+
+#define NPY_ARRAY_UPDATE_ALL (NPY_ARRAY_C_CONTIGUOUS | \
+ NPY_ARRAY_F_CONTIGUOUS | \
+ NPY_ARRAY_ALIGNED)
+
+#define NPY_FARRAY NPY_ARRAY_FARRAY
+#define NPY_CARRAY NPY_ARRAY_CARRAY
+
+#define PyArray_CHKFLAGS(m, flags) (PyArray_FLAGS(m) & (flags))
+
+#define PyArray_ISCONTIGUOUS(m) PyArray_CHKFLAGS(m, NPY_ARRAY_C_CONTIGUOUS)
+#define PyArray_ISWRITEABLE(m) PyArray_CHKFLAGS(m, NPY_ARRAY_WRITEABLE)
+#define PyArray_ISALIGNED(m) PyArray_CHKFLAGS(m, NPY_ARRAY_ALIGNED)
+
+#define PyArray_IS_C_CONTIGUOUS(m) PyArray_CHKFLAGS(m, NPY_ARRAY_C_CONTIGUOUS)
+#define PyArray_IS_F_CONTIGUOUS(m) PyArray_CHKFLAGS(m, NPY_ARRAY_F_CONTIGUOUS)
+
+#define PyArray_FLAGSWAP(m, flags) (PyArray_CHKFLAGS(m, flags) && \
+ PyArray_ISNOTSWAPPED(m))
+
+#define PyArray_ISCARRAY(m) PyArray_FLAGSWAP(m, NPY_ARRAY_CARRAY)
+#define PyArray_ISCARRAY_RO(m) PyArray_FLAGSWAP(m, NPY_ARRAY_CARRAY_RO)
+#define PyArray_ISFARRAY(m) PyArray_FLAGSWAP(m, NPY_ARRAY_FARRAY)
+#define PyArray_ISFARRAY_RO(m) PyArray_FLAGSWAP(m, NPY_ARRAY_FARRAY_RO)
+#define PyArray_ISBEHAVED(m) PyArray_FLAGSWAP(m, NPY_ARRAY_BEHAVED)
+#define PyArray_ISBEHAVED_RO(m) PyArray_FLAGSWAP(m, NPY_ARRAY_ALIGNED)
+
+#define PyArray_ISONESEGMENT(arr) (1)
+#define PyArray_ISNOTSWAPPED(arr) (1)
+#define PyArray_ISBYTESWAPPED(arr) (0)
+
+#endif
+
+#define NPY_INT8 NPY_BYTE
+#define NPY_UINT8 NPY_UBYTE
+#define NPY_INT16 NPY_SHORT
+#define NPY_UINT16 NPY_USHORT
+#define NPY_INT32 NPY_INT
+#define NPY_UINT32 NPY_UINT
+#define NPY_INT64 NPY_LONG
+#define NPY_UINT64 NPY_ULONG
+#define NPY_FLOAT32 NPY_FLOAT
+#define NPY_FLOAT64 NPY_DOUBLE
+#define NPY_COMPLEX32 NPY_CFLOAT
+#define NPY_COMPLEX64 NPY_CDOUBLE
+
+
+/* functions */
+#ifndef PyArray_NDIM
+
+#define PyArray_Check _PyArray_Check
+#define PyArray_CheckExact _PyArray_CheckExact
+#define PyArray_FLAGS _PyArray_FLAGS
+
+#define PyArray_NDIM _PyArray_NDIM
+#define PyArray_DIM _PyArray_DIM
+#define PyArray_STRIDE _PyArray_STRIDE
+#define PyArray_SIZE _PyArray_SIZE
+#define PyArray_ITEMSIZE _PyArray_ITEMSIZE
+#define PyArray_NBYTES _PyArray_NBYTES
+#define PyArray_TYPE _PyArray_TYPE
+#define PyArray_DATA _PyArray_DATA
+
+#define PyArray_Size PyArray_SIZE
+#define PyArray_BYTES(arr) ((char *)PyArray_DATA(arr))
+
+#define PyArray_FromAny _PyArray_FromAny
+#define PyArray_FromObject _PyArray_FromObject
+#define PyArray_ContiguousFromObject PyArray_FromObject
+#define PyArray_ContiguousFromAny PyArray_FromObject
+
+#define PyArray_FROMANY(obj, typenum, min, max, requirements) (obj)
+#define PyArray_FROM_OTF(obj, typenum, requirements) \
+ PyArray_FromObject(obj, typenum, 0, 0)
+
+#define PyArray_New _PyArray_New
+#define PyArray_SimpleNew _PyArray_SimpleNew
+#define PyArray_SimpleNewFromData _PyArray_SimpleNewFromData
+#define PyArray_SimpleNewFromDataOwning _PyArray_SimpleNewFromDataOwning
+
+#define PyArray_EMPTY(nd, dims, type_num, fortran) \
+ PyArray_SimpleNew(nd, dims, type_num)
PyAPI_FUNC(void) _PyArray_FILLWBYTE(PyObject* obj, int val);
PyAPI_FUNC(PyObject *) _PyArray_ZEROS(int nd, npy_intp* dims, int type_num, int fortran);
-PyAPI_FUNC(int) _PyArray_CopyInto(PyArrayObject* dest, PyArrayObject* src);
+#define PyArray_FILLWBYTE _PyArray_FILLWBYTE
+#define PyArray_ZEROS _PyArray_ZEROS
+#define PyArray_Resize(self, newshape, refcheck, fortran) (NULL)
+
+/* Don't use these in loops! */
+
+#define PyArray_GETPTR1(obj, i) ((void *)(PyArray_BYTES(obj) + \
+ (i)*PyArray_STRIDE(obj,0)))
+
+#define PyArray_GETPTR2(obj, i, j) ((void *)(PyArray_BYTES(obj) + \
+ (i)*PyArray_STRIDE(obj,0) + \
+ (j)*PyArray_STRIDE(obj,1)))
+
+#define PyArray_GETPTR3(obj, i, j, k) ((void *)(PyArray_BYTES(obj) + \
+ (i)*PyArray_STRIDE(obj,0) + \
+ (j)*PyArray_STRIDE(obj,1) + \
+ (k)*PyArray_STRIDE(obj,2)))
+
+#define PyArray_GETPTR4(obj, i, j, k, l) ((void *)(PyArray_BYTES(obj) + \
+ (i)*PyArray_STRIDE(obj,0) + \
+ (j)*PyArray_STRIDE(obj,1) + \
+ (k)*PyArray_STRIDE(obj,2) + \
+ (l)*PyArray_STRIDE(obj,3)))
+
+#endif
#ifdef __cplusplus
}
diff --git a/pypy/module/cpyext/include/numpy/ndarraytypes.h b/pypy/module/cpyext/include/numpy/ndarraytypes.h
--- a/pypy/module/cpyext/include/numpy/ndarraytypes.h
+++ b/pypy/module/cpyext/include/numpy/ndarraytypes.h
@@ -1,9 +1,69 @@
#ifndef NDARRAYTYPES_H
#define NDARRAYTYPES_H
-/* For testing ndarrayobject only */
+#include "numpy/npy_common.h"
+//#include "npy_endian.h"
+//#include "npy_cpu.h"
+//#include "utils.h"
-#include "numpy/npy_common.h"
+//for pypy - numpy has lots of typedefs
+//for pypy - make life easier, less backward support
+#define NPY_1_8_API_VERSION 0x00000008
+#define NPY_NO_DEPRECATED_API NPY_1_8_API_VERSION
+#undef NPY_1_8_API_VERSION
+
+#define NPY_ENABLE_SEPARATE_COMPILATION 1
+#define NPY_VISIBILITY_HIDDEN
+
+#ifdef NPY_ENABLE_SEPARATE_COMPILATION
+ #define NPY_NO_EXPORT NPY_VISIBILITY_HIDDEN
+#else
+ #define NPY_NO_EXPORT static
+#endif
+
+/* Only use thread if configured in config and python supports it */
+#if defined WITH_THREAD && !NPY_NO_SMP
+ #define NPY_ALLOW_THREADS 1
+#else
+ #define NPY_ALLOW_THREADS 0
+#endif
+
+
+
+/*
+ * There are several places in the code where an array of dimensions
+ * is allocated statically. This is the size of that static
+ * allocation.
+ *
+ * The array creation itself could have arbitrary dimensions but all
+ * the places where static allocation is used would need to be changed
+ * to dynamic (including inside of several structures)
+ */
+
+#define NPY_MAXDIMS 32
+#define NPY_MAXARGS 32
+
+/* Used for Converter Functions "O&" code in ParseTuple */
+#define NPY_FAIL 0
+#define NPY_SUCCEED 1
+
+/*
+ * Binary compatibility version number. This number is increased
+ * whenever the C-API is changed such that binary compatibility is
+ * broken, i.e. whenever a recompile of extension modules is needed.
+ */
+#define NPY_VERSION NPY_ABI_VERSION
+
+/*
+ * Minor API version. This number is increased whenever a change is
+ * made to the C-API -- whether it breaks binary compatibility or not.
+ * Some changes, such as adding a function pointer to the end of the
+ * function table, can be made without breaking binary compatibility.
+ * In this case, only the NPY_FEATURE_VERSION (*not* NPY_VERSION)
+ * would be increased. Whenever binary compatibility is broken, both
+ * NPY_VERSION and NPY_FEATURE_VERSION should be increased.
+ */
+#define NPY_FEATURE_VERSION NPY_API_VERSION
enum NPY_TYPES { NPY_BOOL=0,
NPY_BYTE, NPY_UBYTE,
@@ -31,6 +91,18 @@
NPY_NTYPES_ABI_COMPATIBLE=21
};
+/* basetype array priority */
+#define NPY_PRIORITY 0.0
+
+/* default subtype priority */
+#define NPY_SUBTYPE_PRIORITY 1.0
+
+/* default scalar priority */
+#define NPY_SCALAR_PRIORITY -1000000.0
+
+/* How many floating point types are there (excluding half) */
+#define NPY_NUM_FLOATTYPE 3
+
/*
* These characters correspond to the array type and the struct
* module
@@ -85,6 +157,27 @@
};
typedef enum {
+ NPY_QUICKSORT=0,
+ NPY_HEAPSORT=1,
+ NPY_MERGESORT=2
+} NPY_SORTKIND;
+#define NPY_NSORTS (NPY_MERGESORT + 1)
+
+
+typedef enum {
+ NPY_INTROSELECT=0,
+} NPY_SELECTKIND;
+#define NPY_NSELECTS (NPY_INTROSELECT + 1)
+
+
+typedef enum {
+ NPY_SEARCHLEFT=0,
+ NPY_SEARCHRIGHT=1
+} NPY_SEARCHSIDE;
+#define NPY_NSEARCHSIDES (NPY_SEARCHRIGHT + 1)
+
+
+typedef enum {
NPY_NOSCALAR=-1,
NPY_BOOL_SCALAR,
NPY_INTPOS_SCALAR,
@@ -93,6 +186,7 @@
NPY_COMPLEX_SCALAR,
NPY_OBJECT_SCALAR
} NPY_SCALARKIND;
+#define NPY_NSCALARKINDS (NPY_OBJECT_SCALAR + 1)
/* For specifying array memory layout or iteration order */
typedef enum {
@@ -106,6 +200,729 @@
NPY_KEEPORDER=2
} NPY_ORDER;
+/* For specifying allowed casting in operations which support it */
+typedef enum {
+ /* Only allow identical types */
+ NPY_NO_CASTING=0,
+ /* Allow identical and byte swapped types */
+ NPY_EQUIV_CASTING=1,
+ /* Only allow safe casts */
+ NPY_SAFE_CASTING=2,
+ /* Allow safe casts or casts within the same kind */
+ NPY_SAME_KIND_CASTING=3,
+ /* Allow any casts */
+ NPY_UNSAFE_CASTING=4,
+
+ /*
+ * Temporary internal definition only, will be removed in upcoming
+ * release, see below
+ * */
+ NPY_INTERNAL_UNSAFE_CASTING_BUT_WARN_UNLESS_SAME_KIND = 100,
+} NPY_CASTING;
+
+typedef enum {
+ NPY_CLIP=0,
+ NPY_WRAP=1,
+ NPY_RAISE=2
+} NPY_CLIPMODE;
+
+/* The special not-a-time (NaT) value */
+#define NPY_DATETIME_NAT NPY_MIN_INT64
+
+/*
+ * Upper bound on the length of a DATETIME ISO 8601 string
+ * YEAR: 21 (64-bit year)
+ * MONTH: 3
+ * DAY: 3
+ * HOURS: 3
+ * MINUTES: 3
+ * SECONDS: 3
+ * ATTOSECONDS: 1 + 3*6
+ * TIMEZONE: 5
+ * NULL TERMINATOR: 1
+ */
+#define NPY_DATETIME_MAX_ISO8601_STRLEN (21+3*5+1+3*6+6+1)
+
+typedef enum {
+ NPY_FR_Y = 0, /* Years */
+ NPY_FR_M = 1, /* Months */
+ NPY_FR_W = 2, /* Weeks */
+ /* Gap where 1.6 NPY_FR_B (value 3) was */
+ NPY_FR_D = 4, /* Days */
+ NPY_FR_h = 5, /* hours */
+ NPY_FR_m = 6, /* minutes */
+ NPY_FR_s = 7, /* seconds */
+ NPY_FR_ms = 8, /* milliseconds */
+ NPY_FR_us = 9, /* microseconds */
+ NPY_FR_ns = 10,/* nanoseconds */
+ NPY_FR_ps = 11,/* picoseconds */
+ NPY_FR_fs = 12,/* femtoseconds */
+ NPY_FR_as = 13,/* attoseconds */
+ NPY_FR_GENERIC = 14 /* Generic, unbound units, can convert to anything */
+} NPY_DATETIMEUNIT;
+
+/*
+ * NOTE: With the NPY_FR_B gap for 1.6 ABI compatibility, NPY_DATETIME_NUMUNITS
+ * is technically one more than the actual number of units.
+ */
+#define NPY_DATETIME_NUMUNITS (NPY_FR_GENERIC + 1)
+#define NPY_DATETIME_DEFAULTUNIT NPY_FR_GENERIC
+
+/*
+ * Business day conventions for mapping invalid business
+ * days to valid business days.
+ */
+typedef enum {
+ /* Go forward in time to the following business day. */
+ NPY_BUSDAY_FORWARD,
+ NPY_BUSDAY_FOLLOWING = NPY_BUSDAY_FORWARD,
+ /* Go backward in time to the preceding business day. */
+ NPY_BUSDAY_BACKWARD,
+ NPY_BUSDAY_PRECEDING = NPY_BUSDAY_BACKWARD,
+ /*
+ * Go forward in time to the following business day, unless it
+ * crosses a month boundary, in which case go backward
+ */
+ NPY_BUSDAY_MODIFIEDFOLLOWING,
+ /*
+ * Go backward in time to the preceding business day, unless it
+ * crosses a month boundary, in which case go forward.
+ */
+ NPY_BUSDAY_MODIFIEDPRECEDING,
+ /* Produce a NaT for non-business days. */
+ NPY_BUSDAY_NAT,
+ /* Raise an exception for non-business days. */
+ NPY_BUSDAY_RAISE
+} NPY_BUSDAY_ROLL;
+
+/************************************************************
+ * NumPy Auxiliary Data for inner loops, sort functions, etc.
+ ************************************************************/
+
+/*
+ * When creating an auxiliary data struct, this should always appear
+ * as the first member, like this:
+ *
+ * typedef struct {
+ * NpyAuxData base;
+ * double constant;
+ * } constant_multiplier_aux_data;
+ */
+typedef struct NpyAuxData_tag NpyAuxData;
+
+/* Function pointers for freeing or cloning auxiliary data */
+typedef void (NpyAuxData_FreeFunc) (NpyAuxData *);
+typedef NpyAuxData *(NpyAuxData_CloneFunc) (NpyAuxData *);
+
+struct NpyAuxData_tag {
+ NpyAuxData_FreeFunc *free;
+ NpyAuxData_CloneFunc *clone;
+ /* To allow for a bit of expansion without breaking the ABI */
+ void *reserved[2];
+};
+
+/* Macros to use for freeing and cloning auxiliary data */
+#define NPY_AUXDATA_FREE(auxdata) \
+ do { \
+ if ((auxdata) != NULL) { \
+ (auxdata)->free(auxdata); \
+ } \
+ } while(0)
+#define NPY_AUXDATA_CLONE(auxdata) \
+ ((auxdata)->clone(auxdata))
+
+#define NPY_ERR(str) fprintf(stderr, #str); fflush(stderr);
+#define NPY_ERR2(str) fprintf(stderr, str); fflush(stderr);
+
+#define NPY_STRINGIFY(x) #x
+#define NPY_TOSTRING(x) NPY_STRINGIFY(x)
+
+ /*
+ * Macros to define how array, and dimension/strides data is
+ * allocated.
+ */
+
+ /* Data buffer - PyDataMem_NEW/FREE/RENEW are in multiarraymodule.c */
+
+#define NPY_USE_PYMEM 1
+
+#if NPY_USE_PYMEM == 1
+#define PyArray_malloc PyMem_Malloc
+#define PyArray_free PyMem_Free
+#define PyArray_realloc PyMem_Realloc
+#else
+#define PyArray_malloc malloc
+#define PyArray_free free
+#define PyArray_realloc realloc
+#endif
+
+/* Dimensions and strides */
+#define PyDimMem_NEW(size) \
+ ((npy_intp *)PyArray_malloc(size*sizeof(npy_intp)))
+
+#define PyDimMem_FREE(ptr) PyArray_free(ptr)
+
+#define PyDimMem_RENEW(ptr,size) \
+ ((npy_intp *)PyArray_realloc(ptr,size*sizeof(npy_intp)))
+
+/* forward declaration */
+struct _PyArray_Descr;
+
+/* These must deal with unaligned and swapped data if necessary */
+typedef PyObject * (PyArray_GetItemFunc) (void *, void *);
+typedef int (PyArray_SetItemFunc)(PyObject *, void *, void *);
+
+typedef void (PyArray_CopySwapNFunc)(void *, npy_intp, void *, npy_intp,
+ npy_intp, int, void *);
+
+typedef void (PyArray_CopySwapFunc)(void *, void *, int, void *);
+typedef npy_bool (PyArray_NonzeroFunc)(void *, void *);
+
+
+/*
+ * These assume aligned and notswapped data -- a buffer will be used
+ * before or contiguous data will be obtained
+ */
+
+typedef int (PyArray_CompareFunc)(const void *, const void *, void *);
+typedef int (PyArray_ArgFunc)(void*, npy_intp, npy_intp*, void *);
+
+typedef void (PyArray_DotFunc)(void *, npy_intp, void *, npy_intp, void *,
+ npy_intp, void *);
+
+typedef void (PyArray_VectorUnaryFunc)(void *, void *, npy_intp, void *,
+ void *);
+
+/*
+ * XXX the ignore argument should be removed next time the API version
+ * is bumped. It used to be the separator.
+ */
+typedef int (PyArray_ScanFunc)(FILE *fp, void *dptr,
+ char *ignore, struct _PyArray_Descr *);
+typedef int (PyArray_FromStrFunc)(char *s, void *dptr, char **endptr,
+ struct _PyArray_Descr *);
+
+typedef int (PyArray_FillFunc)(void *, npy_intp, void *);
+
+typedef int (PyArray_SortFunc)(void *, npy_intp, void *);
+typedef int (PyArray_ArgSortFunc)(void *, npy_intp *, npy_intp, void *);
+typedef int (PyArray_PartitionFunc)(void *, npy_intp, npy_intp,
+ npy_intp *, npy_intp *,
+ void *);
+typedef int (PyArray_ArgPartitionFunc)(void *, npy_intp *, npy_intp, npy_intp,
+ npy_intp *, npy_intp *,
+ void *);
+
+typedef int (PyArray_FillWithScalarFunc)(void *, npy_intp, void *, void *);
+
+typedef int (PyArray_ScalarKindFunc)(void *);
+
+typedef void (PyArray_FastClipFunc)(void *in, npy_intp n_in, void *min,
+ void *max, void *out);
+typedef void (PyArray_FastPutmaskFunc)(void *in, void *mask, npy_intp n_in,
+ void *values, npy_intp nv);
+typedef int (PyArray_FastTakeFunc)(void *dest, void *src, npy_intp *indarray,
+ npy_intp nindarray, npy_intp n_outer,
+ npy_intp m_middle, npy_intp nelem,
+ NPY_CLIPMODE clipmode);
+
+typedef struct {
+ npy_intp *ptr;
+ int len;
+} PyArray_Dims;
+
+typedef struct {
+ /*
+ * Functions to cast to most other standard types
+ * Can have some NULL entries. The types
+ * DATETIME, TIMEDELTA, and HALF go into the castdict
+ * even though they are built-in.
+ */
+ PyArray_VectorUnaryFunc *cast[NPY_NTYPES_ABI_COMPATIBLE];
+
+ /* The next four functions *cannot* be NULL */
+
+ /*
+ * Functions to get and set items with standard Python types
+ * -- not array scalars
+ */
+ PyArray_GetItemFunc *getitem;
+ PyArray_SetItemFunc *setitem;
+
+ /*
+ * Copy and/or swap data. Memory areas may not overlap
+ * Use memmove first if they might
+ */
+ PyArray_CopySwapNFunc *copyswapn;
+ PyArray_CopySwapFunc *copyswap;
+
+ /*
+ * Function to compare items
+ * Can be NULL
+ */
+ PyArray_CompareFunc *compare;
+
+ /*
+ * Function to select largest
+ * Can be NULL
+ */
+ PyArray_ArgFunc *argmax;
+
+ /*
+ * Function to compute dot product
+ * Can be NULL
+ */
+ PyArray_DotFunc *dotfunc;
+
+ /*
+ * Function to scan an ASCII file and
+ * place a single value plus possible separator
+ * Can be NULL
+ */
+ PyArray_ScanFunc *scanfunc;
+
+ /*
+ * Function to read a single value from a string
+ * and adjust the pointer; Can be NULL
+ */
+ PyArray_FromStrFunc *fromstr;
+
+ /*
+ * Function to determine if data is zero or not
+ * If NULL a default version is
+ * used at Registration time.
+ */
+ PyArray_NonzeroFunc *nonzero;
+
+ /*
+ * Used for arange.
+ * Can be NULL.
+ */
+ PyArray_FillFunc *fill;
+
+ /*
+ * Function to fill arrays with scalar values
+ * Can be NULL
+ */
+ PyArray_FillWithScalarFunc *fillwithscalar;
+
+ /*
+ * Sorting functions
+ * Can be NULL
+ */
+ PyArray_SortFunc *sort[NPY_NSORTS];
+ PyArray_ArgSortFunc *argsort[NPY_NSORTS];
+
+ /*
+ * Dictionary of additional casting functions
+ * PyArray_VectorUnaryFuncs
+ * which can be populated to support casting
+ * to other registered types. Can be NULL
+ */
+ PyObject *castdict;
+
+ /*
+ * Functions useful for generalizing
+ * the casting rules.
+ * Can be NULL;
+ */
+ PyArray_ScalarKindFunc *scalarkind;
+ int **cancastscalarkindto;
+ int *cancastto;
+
+ PyArray_FastClipFunc *fastclip;
+ PyArray_FastPutmaskFunc *fastputmask;
+ PyArray_FastTakeFunc *fasttake;
+
+ /*
+ * Function to select smallest
+ * Can be NULL
+ */
+ PyArray_ArgFunc *argmin;
+
+} PyArray_ArrFuncs;
+
+/* The item must be reference counted when it is inserted or extracted. */
+#define NPY_ITEM_REFCOUNT 0x01
+/* Same as needing REFCOUNT */
+#define NPY_ITEM_HASOBJECT 0x01
+/* Convert to list for pickling */
+#define NPY_LIST_PICKLE 0x02
+/* The item is a POINTER */
+#define NPY_ITEM_IS_POINTER 0x04
+/* memory needs to be initialized for this data-type */
+#define NPY_NEEDS_INIT 0x08
+/* operations need Python C-API so don't give-up thread. */
+#define NPY_NEEDS_PYAPI 0x10
+/* Use f.getitem when extracting elements of this data-type */
+#define NPY_USE_GETITEM 0x20
+/* Use f.setitem when setting creating 0-d array from this data-type.*/
+#define NPY_USE_SETITEM 0x40
+/* A sticky flag specifically for structured arrays */
+#define NPY_ALIGNED_STRUCT 0x80
+
+/*
+ *These are inherited for global data-type if any data-types in the
+ * field have them
+ */
+#define NPY_FROM_FIELDS (NPY_NEEDS_INIT | NPY_LIST_PICKLE | \
+ NPY_ITEM_REFCOUNT | NPY_NEEDS_PYAPI)
+
+#define NPY_OBJECT_DTYPE_FLAGS (NPY_LIST_PICKLE | NPY_USE_GETITEM | \
+ NPY_ITEM_IS_POINTER | NPY_ITEM_REFCOUNT | \
+ NPY_NEEDS_INIT | NPY_NEEDS_PYAPI)
+
+#define PyDataType_FLAGCHK(dtype, flag) \
+ (((dtype)->flags & (flag)) == (flag))
+
+#define PyDataType_REFCHK(dtype) \
+ PyDataType_FLAGCHK(dtype, NPY_ITEM_REFCOUNT)
+
+typedef struct _PyArray_Descr {
+ PyObject_HEAD
+ /*
+ * the type object representing an
+ * instance of this type -- should not
+ * be two type_numbers with the same type
+ * object.
+ */
+ PyTypeObject *typeobj;
+ /* kind for this type */
+ char kind;
+ /* unique-character representing this type */
+ char type;
+ /*
+ * '>' (big), '<' (little), '|'
+ * (not-applicable), or '=' (native).
+ */
+ char byteorder;
+ /* flags describing data type */
+ char flags;
+ /* number representing this type */
+ int type_num;
+ /* element size (itemsize) for this type */
+ int elsize;
+ /* alignment needed for this type */
+ int alignment;
+ /*
+ * Non-NULL if this type is
+ * is an array (C-contiguous)
+ * of some other type
+ */
+ struct _arr_descr *subarray;
+ /*
+ * The fields dictionary for this type
+ * For statically defined descr this
+ * is always Py_None
+ */
+ PyObject *fields;
+ /*
+ * An ordered tuple of field names or NULL
+ * if no fields are defined
+ */
+ PyObject *names;
+ /*
+ * a table of functions specific for each
+ * basic data descriptor
+ */
+ PyArray_ArrFuncs *f;
+ /* Metadata about this dtype */
+ PyObject *metadata;
+ /*
+ * Metadata specific to the C implementation
+ * of the particular dtype. This was added
+ * for NumPy 1.7.0.
+ */
+ NpyAuxData *c_metadata;
+} PyArray_Descr;
+
+typedef struct _arr_descr {
+ PyArray_Descr *base;
+ PyObject *shape; /* a tuple */
+} PyArray_ArrayDescr;
+
+/*
+ * The main array object structure.
+ *
+ * It has been recommended to use the inline functions defined below
+ * (PyArray_DATA and friends) to access fields here for a number of
+ * releases. Direct access to the members themselves is deprecated.
+ * To ensure that your code does not use deprecated access,
+ * #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
+ * (or NPY_1_8_API_VERSION or higher as required).
+ */
+/* This struct will be moved to a private header in a future release */
+typedef struct tagPyArrayObject_fields {
+ PyObject_HEAD
+ /* Pointer to the raw data buffer */
+ char *data;
+ /* The number of dimensions, also called 'ndim' */
+ int nd;
+ /* The size in each dimension, also called 'shape' */
+ npy_intp *dimensions;
+ /*
+ * Number of bytes to jump to get to the
+ * next element in each dimension
+ */
+ npy_intp *strides;
+ /*
+ * This object is decref'd upon
+ * deletion of array. Except in the
+ * case of UPDATEIFCOPY which has
+ * special handling.
+ *
+ * For views it points to the original
+ * array, collapsed so no chains of
+ * views occur.
+ *
+ * For creation from buffer object it
+ * points to an object that shold be
+ * decref'd on deletion
+ *
+ * For UPDATEIFCOPY flag this is an
+ * array to-be-updated upon deletion
+ * of this one
More information about the pypy-commit
mailing list