Cython 3.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- Cython/Build/BuildExecutable.py +169 -0
- Cython/Build/Cache.py +199 -0
- Cython/Build/Cythonize.py +323 -0
- Cython/Build/Dependencies.py +1306 -0
- Cython/Build/Distutils.py +1 -0
- Cython/Build/Inline.py +463 -0
- Cython/Build/IpythonMagic.py +560 -0
- Cython/Build/SharedModule.py +76 -0
- Cython/Build/Tests/TestCyCache.py +194 -0
- Cython/Build/Tests/TestCythonizeArgsParser.py +481 -0
- Cython/Build/Tests/TestDependencies.py +133 -0
- Cython/Build/Tests/TestInline.py +177 -0
- Cython/Build/Tests/TestIpythonMagic.py +287 -0
- Cython/Build/Tests/TestRecythonize.py +212 -0
- Cython/Build/Tests/TestStripLiterals.py +155 -0
- Cython/Build/Tests/__init__.py +1 -0
- Cython/Build/__init__.py +8 -0
- Cython/CodeWriter.py +811 -0
- Cython/Compiler/AnalysedTreeTransforms.py +97 -0
- Cython/Compiler/Annotate.py +326 -0
- Cython/Compiler/AutoDocTransforms.py +320 -0
- Cython/Compiler/Buffer.py +680 -0
- Cython/Compiler/Builtin.py +934 -0
- Cython/Compiler/CmdLine.py +259 -0
- Cython/Compiler/Code.pxd +148 -0
- Cython/Compiler/Code.py +3375 -0
- Cython/Compiler/CodeGeneration.py +33 -0
- Cython/Compiler/CythonScope.py +187 -0
- Cython/Compiler/Dataclass.py +868 -0
- Cython/Compiler/DebugFlags.py +24 -0
- Cython/Compiler/Errors.py +295 -0
- Cython/Compiler/ExprNodes.py +15267 -0
- Cython/Compiler/FlowControl.pxd +97 -0
- Cython/Compiler/FlowControl.py +1455 -0
- Cython/Compiler/FusedNode.py +1002 -0
- Cython/Compiler/Future.py +16 -0
- Cython/Compiler/Interpreter.py +57 -0
- Cython/Compiler/Lexicon.py +340 -0
- Cython/Compiler/LineTable.py +114 -0
- Cython/Compiler/Main.py +853 -0
- Cython/Compiler/MatchCaseNodes.py +259 -0
- Cython/Compiler/MemoryView.py +922 -0
- Cython/Compiler/ModuleNode.py +4024 -0
- Cython/Compiler/Naming.py +374 -0
- Cython/Compiler/Nodes.py +10826 -0
- Cython/Compiler/Optimize.py +5256 -0
- Cython/Compiler/Options.py +835 -0
- Cython/Compiler/ParseTreeTransforms.pxd +77 -0
- Cython/Compiler/ParseTreeTransforms.py +4509 -0
- Cython/Compiler/Parsing.pxd +9 -0
- Cython/Compiler/Parsing.py +4789 -0
- Cython/Compiler/Pipeline.py +439 -0
- Cython/Compiler/PyrexTypes.py +5762 -0
- Cython/Compiler/Pythran.py +232 -0
- Cython/Compiler/Scanning.pxd +40 -0
- Cython/Compiler/Scanning.py +577 -0
- Cython/Compiler/StringEncoding.py +347 -0
- Cython/Compiler/Symtab.py +3080 -0
- Cython/Compiler/Tests/TestBuffer.py +105 -0
- Cython/Compiler/Tests/TestBuiltin.py +72 -0
- Cython/Compiler/Tests/TestCmdLine.py +586 -0
- Cython/Compiler/Tests/TestCode.py +86 -0
- Cython/Compiler/Tests/TestFlowControl.py +65 -0
- Cython/Compiler/Tests/TestGrammar.py +202 -0
- Cython/Compiler/Tests/TestMemView.py +71 -0
- Cython/Compiler/Tests/TestParseTreeTransforms.py +285 -0
- Cython/Compiler/Tests/TestScanning.py +134 -0
- Cython/Compiler/Tests/TestSignatureMatching.py +73 -0
- Cython/Compiler/Tests/TestStringEncoding.py +33 -0
- Cython/Compiler/Tests/TestTreeFragment.py +63 -0
- Cython/Compiler/Tests/TestTreePath.py +103 -0
- Cython/Compiler/Tests/TestTypes.py +75 -0
- Cython/Compiler/Tests/TestUtilityLoad.py +112 -0
- Cython/Compiler/Tests/TestVisitor.py +61 -0
- Cython/Compiler/Tests/Utils.py +36 -0
- Cython/Compiler/Tests/__init__.py +1 -0
- Cython/Compiler/TreeFragment.py +278 -0
- Cython/Compiler/TreePath.py +303 -0
- Cython/Compiler/TypeInference.py +584 -0
- Cython/Compiler/TypeSlots.py +1181 -0
- Cython/Compiler/UFuncs.py +311 -0
- Cython/Compiler/UtilNodes.py +389 -0
- Cython/Compiler/UtilityCode.py +344 -0
- Cython/Compiler/Version.py +8 -0
- Cython/Compiler/Visitor.pxd +53 -0
- Cython/Compiler/Visitor.py +861 -0
- Cython/Compiler/__init__.py +1 -0
- Cython/Coverage.py +448 -0
- Cython/Debugger/Cygdb.py +175 -0
- Cython/Debugger/DebugWriter.py +82 -0
- Cython/Debugger/Tests/TestLibCython.py +275 -0
- Cython/Debugger/Tests/__init__.py +1 -0
- Cython/Debugger/Tests/cfuncs.c +8 -0
- Cython/Debugger/Tests/codefile +49 -0
- Cython/Debugger/Tests/test_libcython_in_gdb.py +578 -0
- Cython/Debugger/Tests/test_libpython_in_gdb.py +90 -0
- Cython/Debugger/__init__.py +1 -0
- Cython/Debugger/libcython.py +1548 -0
- Cython/Debugger/libpython.py +2821 -0
- Cython/Debugging.py +20 -0
- Cython/Distutils/__init__.py +2 -0
- Cython/Distutils/build_ext.py +139 -0
- Cython/Distutils/extension.py +96 -0
- Cython/Distutils/old_build_ext.py +351 -0
- Cython/Includes/cpython/__init__.pxd +173 -0
- Cython/Includes/cpython/array.pxd +174 -0
- Cython/Includes/cpython/bool.pxd +37 -0
- Cython/Includes/cpython/buffer.pxd +112 -0
- Cython/Includes/cpython/bytearray.pxd +33 -0
- Cython/Includes/cpython/bytes.pxd +200 -0
- Cython/Includes/cpython/cellobject.pxd +35 -0
- Cython/Includes/cpython/ceval.pxd +8 -0
- Cython/Includes/cpython/codecs.pxd +121 -0
- Cython/Includes/cpython/complex.pxd +60 -0
- Cython/Includes/cpython/contextvars.pxd +145 -0
- Cython/Includes/cpython/conversion.pxd +36 -0
- Cython/Includes/cpython/datetime.pxd +395 -0
- Cython/Includes/cpython/descr.pxd +26 -0
- Cython/Includes/cpython/dict.pxd +187 -0
- Cython/Includes/cpython/exc.pxd +263 -0
- Cython/Includes/cpython/fileobject.pxd +57 -0
- Cython/Includes/cpython/float.pxd +47 -0
- Cython/Includes/cpython/function.pxd +65 -0
- Cython/Includes/cpython/genobject.pxd +25 -0
- Cython/Includes/cpython/getargs.pxd +12 -0
- Cython/Includes/cpython/instance.pxd +25 -0
- Cython/Includes/cpython/iterator.pxd +36 -0
- Cython/Includes/cpython/iterobject.pxd +24 -0
- Cython/Includes/cpython/list.pxd +92 -0
- Cython/Includes/cpython/long.pxd +149 -0
- Cython/Includes/cpython/longintrepr.pxd +14 -0
- Cython/Includes/cpython/mapping.pxd +63 -0
- Cython/Includes/cpython/marshal.pxd +66 -0
- Cython/Includes/cpython/mem.pxd +120 -0
- Cython/Includes/cpython/memoryview.pxd +50 -0
- Cython/Includes/cpython/method.pxd +49 -0
- Cython/Includes/cpython/module.pxd +208 -0
- Cython/Includes/cpython/number.pxd +258 -0
- Cython/Includes/cpython/object.pxd +433 -0
- Cython/Includes/cpython/pycapsule.pxd +143 -0
- Cython/Includes/cpython/pylifecycle.pxd +68 -0
- Cython/Includes/cpython/pyport.pxd +8 -0
- Cython/Includes/cpython/pystate.pxd +95 -0
- Cython/Includes/cpython/pythread.pxd +53 -0
- Cython/Includes/cpython/ref.pxd +67 -0
- Cython/Includes/cpython/sequence.pxd +134 -0
- Cython/Includes/cpython/set.pxd +119 -0
- Cython/Includes/cpython/slice.pxd +70 -0
- Cython/Includes/cpython/time.pxd +129 -0
- Cython/Includes/cpython/tuple.pxd +72 -0
- Cython/Includes/cpython/type.pxd +53 -0
- Cython/Includes/cpython/unicode.pxd +639 -0
- Cython/Includes/cpython/version.pxd +32 -0
- Cython/Includes/cpython/weakref.pxd +78 -0
- Cython/Includes/libc/__init__.pxd +1 -0
- Cython/Includes/libc/complex.pxd +35 -0
- Cython/Includes/libc/errno.pxd +127 -0
- Cython/Includes/libc/float.pxd +43 -0
- Cython/Includes/libc/limits.pxd +28 -0
- Cython/Includes/libc/locale.pxd +46 -0
- Cython/Includes/libc/math.pxd +209 -0
- Cython/Includes/libc/setjmp.pxd +10 -0
- Cython/Includes/libc/signal.pxd +64 -0
- Cython/Includes/libc/stddef.pxd +9 -0
- Cython/Includes/libc/stdint.pxd +105 -0
- Cython/Includes/libc/stdio.pxd +80 -0
- Cython/Includes/libc/stdlib.pxd +72 -0
- Cython/Includes/libc/string.pxd +50 -0
- Cython/Includes/libc/threads.pxd +84 -0
- Cython/Includes/libc/time.pxd +51 -0
- Cython/Includes/libcpp/__init__.pxd +4 -0
- Cython/Includes/libcpp/algorithm.pxd +320 -0
- Cython/Includes/libcpp/any.pxd +16 -0
- Cython/Includes/libcpp/atomic.pxd +59 -0
- Cython/Includes/libcpp/barrier.pxd +22 -0
- Cython/Includes/libcpp/bit.pxd +29 -0
- Cython/Includes/libcpp/cast.pxd +12 -0
- Cython/Includes/libcpp/cmath.pxd +518 -0
- Cython/Includes/libcpp/complex.pxd +106 -0
- Cython/Includes/libcpp/deque.pxd +165 -0
- Cython/Includes/libcpp/exception.pxd +86 -0
- Cython/Includes/libcpp/execution.pxd +15 -0
- Cython/Includes/libcpp/forward_list.pxd +63 -0
- Cython/Includes/libcpp/functional.pxd +26 -0
- Cython/Includes/libcpp/future.pxd +103 -0
- Cython/Includes/libcpp/iterator.pxd +34 -0
- Cython/Includes/libcpp/latch.pxd +17 -0
- Cython/Includes/libcpp/limits.pxd +61 -0
- Cython/Includes/libcpp/list.pxd +117 -0
- Cython/Includes/libcpp/map.pxd +252 -0
- Cython/Includes/libcpp/memory.pxd +115 -0
- Cython/Includes/libcpp/mutex.pxd +130 -0
- Cython/Includes/libcpp/numbers.pxd +15 -0
- Cython/Includes/libcpp/numeric.pxd +131 -0
- Cython/Includes/libcpp/optional.pxd +34 -0
- Cython/Includes/libcpp/pair.pxd +1 -0
- Cython/Includes/libcpp/queue.pxd +25 -0
- Cython/Includes/libcpp/random.pxd +166 -0
- Cython/Includes/libcpp/semaphore.pxd +44 -0
- Cython/Includes/libcpp/set.pxd +228 -0
- Cython/Includes/libcpp/shared_mutex.pxd +72 -0
- Cython/Includes/libcpp/span.pxd +87 -0
- Cython/Includes/libcpp/stack.pxd +11 -0
- Cython/Includes/libcpp/stop_token.pxd +105 -0
- Cython/Includes/libcpp/string.pxd +355 -0
- Cython/Includes/libcpp/string_view.pxd +181 -0
- Cython/Includes/libcpp/typeindex.pxd +15 -0
- Cython/Includes/libcpp/typeinfo.pxd +10 -0
- Cython/Includes/libcpp/unordered_map.pxd +193 -0
- Cython/Includes/libcpp/unordered_set.pxd +152 -0
- Cython/Includes/libcpp/utility.pxd +30 -0
- Cython/Includes/libcpp/vector.pxd +186 -0
- Cython/Includes/openmp.pxd +50 -0
- Cython/Includes/posix/__init__.pxd +1 -0
- Cython/Includes/posix/dlfcn.pxd +14 -0
- Cython/Includes/posix/fcntl.pxd +86 -0
- Cython/Includes/posix/ioctl.pxd +4 -0
- Cython/Includes/posix/mman.pxd +101 -0
- Cython/Includes/posix/resource.pxd +57 -0
- Cython/Includes/posix/select.pxd +21 -0
- Cython/Includes/posix/signal.pxd +73 -0
- Cython/Includes/posix/stat.pxd +98 -0
- Cython/Includes/posix/stdio.pxd +37 -0
- Cython/Includes/posix/stdlib.pxd +29 -0
- Cython/Includes/posix/strings.pxd +9 -0
- Cython/Includes/posix/time.pxd +71 -0
- Cython/Includes/posix/types.pxd +30 -0
- Cython/Includes/posix/uio.pxd +26 -0
- Cython/Includes/posix/unistd.pxd +271 -0
- Cython/Includes/posix/wait.pxd +38 -0
- Cython/Plex/Actions.pxd +24 -0
- Cython/Plex/Actions.py +119 -0
- Cython/Plex/DFA.pxd +14 -0
- Cython/Plex/DFA.py +164 -0
- Cython/Plex/Errors.py +48 -0
- Cython/Plex/Lexicons.py +178 -0
- Cython/Plex/Machines.pxd +36 -0
- Cython/Plex/Machines.py +238 -0
- Cython/Plex/Regexps.py +539 -0
- Cython/Plex/Scanners.pxd +47 -0
- Cython/Plex/Scanners.py +360 -0
- Cython/Plex/Transitions.pxd +14 -0
- Cython/Plex/Transitions.py +239 -0
- Cython/Plex/__init__.py +34 -0
- Cython/Runtime/__init__.py +1 -0
- Cython/Runtime/refnanny.pyx +237 -0
- Cython/Shadow.py +690 -0
- Cython/Shadow.pyi +521 -0
- Cython/StringIOTree.py +170 -0
- Cython/Tempita/__init__.py +4 -0
- Cython/Tempita/_looper.py +154 -0
- Cython/Tempita/_tempita.py +1091 -0
- Cython/TestUtils.py +410 -0
- Cython/Tests/TestCodeWriter.py +128 -0
- Cython/Tests/TestCythonUtils.py +202 -0
- Cython/Tests/TestJediTyper.py +223 -0
- Cython/Tests/TestShadow.py +114 -0
- Cython/Tests/TestStringIOTree.py +67 -0
- Cython/Tests/TestTestUtils.py +90 -0
- Cython/Tests/__init__.py +1 -0
- Cython/Tests/xmlrunner.py +390 -0
- Cython/Utility/AsyncGen.c +1002 -0
- Cython/Utility/Buffer.c +875 -0
- Cython/Utility/BufferFormatFromTypeInfo.pxd +2 -0
- Cython/Utility/Builtins.c +776 -0
- Cython/Utility/CConvert.pyx +134 -0
- Cython/Utility/CMath.c +104 -0
- Cython/Utility/CommonStructures.c +118 -0
- Cython/Utility/Complex.c +378 -0
- Cython/Utility/Coroutine.c +2206 -0
- Cython/Utility/CpdefEnums.pyx +103 -0
- Cython/Utility/CppConvert.pyx +279 -0
- Cython/Utility/CppSupport.cpp +143 -0
- Cython/Utility/CythonFunction.c +1794 -0
- Cython/Utility/Dataclasses.c +185 -0
- Cython/Utility/Dataclasses.py +112 -0
- Cython/Utility/Embed.c +125 -0
- Cython/Utility/Exceptions.c +1012 -0
- Cython/Utility/ExtensionTypes.c +809 -0
- Cython/Utility/FunctionArguments.c +965 -0
- Cython/Utility/ImportExport.c +987 -0
- Cython/Utility/Lock.c +136 -0
- Cython/Utility/MemoryView.pxd +187 -0
- Cython/Utility/MemoryView.pyx +1481 -0
- Cython/Utility/MemoryView_C.c +1046 -0
- Cython/Utility/ModuleSetupCode.c +3059 -0
- Cython/Utility/NumpyImportArray.c +46 -0
- Cython/Utility/ObjectHandling.c +3342 -0
- Cython/Utility/Optimize.c +1589 -0
- Cython/Utility/Overflow.c +404 -0
- Cython/Utility/Printing.c +86 -0
- Cython/Utility/Profile.c +709 -0
- Cython/Utility/StringTools.c +1259 -0
- Cython/Utility/TestCyUtilityLoader.pyx +8 -0
- Cython/Utility/TestCythonScope.pyx +75 -0
- Cython/Utility/TestUtilityLoader.c +12 -0
- Cython/Utility/TypeConversion.c +1284 -0
- Cython/Utility/UFuncs.pyx +50 -0
- Cython/Utility/UFuncs_C.c +89 -0
- Cython/Utility/__init__.py +28 -0
- Cython/Utility/arrayarray.h +148 -0
- Cython/Utils.py +687 -0
- Cython/__init__.py +10 -0
- Cython/__init__.pyi +7 -0
- Cython/py.typed +0 -0
- cython-3.1.0.dist-info/COPYING.txt +19 -0
- cython-3.1.0.dist-info/LICENSE.txt +176 -0
- cython-3.1.0.dist-info/METADATA +636 -0
- cython-3.1.0.dist-info/RECORD +316 -0
- cython-3.1.0.dist-info/WHEEL +5 -0
- cython-3.1.0.dist-info/entry_points.txt +4 -0
- cython-3.1.0.dist-info/top_level.txt +3 -0
- cython.py +29 -0
- pyximport/__init__.py +4 -0
- pyximport/pyxbuild.py +160 -0
- pyximport/pyximport.py +482 -0
|
@@ -0,0 +1,1481 @@
|
|
|
1
|
+
#################### View.MemoryView ####################
|
|
2
|
+
|
|
3
|
+
# cython: language_level=3
|
|
4
|
+
# cython: binding=False
|
|
5
|
+
|
|
6
|
+
# This utility provides cython.array and cython.view.memoryview
|
|
7
|
+
|
|
8
|
+
from __future__ import absolute_import
|
|
9
|
+
|
|
10
|
+
cimport cython
|
|
11
|
+
|
|
12
|
+
# from cpython cimport ...
|
|
13
|
+
cdef extern from "Python.h":
|
|
14
|
+
ctypedef struct PyObject
|
|
15
|
+
int PyIndex_Check(object)
|
|
16
|
+
PyObject *PyExc_IndexError
|
|
17
|
+
PyObject *PyExc_ValueError
|
|
18
|
+
|
|
19
|
+
cdef extern from "pythread.h":
|
|
20
|
+
ctypedef void *PyThread_type_lock
|
|
21
|
+
|
|
22
|
+
PyThread_type_lock PyThread_allocate_lock()
|
|
23
|
+
void PyThread_free_lock(PyThread_type_lock)
|
|
24
|
+
|
|
25
|
+
cdef extern from "<string.h>":
|
|
26
|
+
void *memset(void *b, int c, size_t len)
|
|
27
|
+
|
|
28
|
+
cdef extern from *:
|
|
29
|
+
bint __PYX_CYTHON_ATOMICS_ENABLED()
|
|
30
|
+
bint __PYX_GET_CYTHON_COMPILING_IN_CPYTHON_FREETHREADING()
|
|
31
|
+
int PyObject_GetBuffer(object, Py_buffer *, int) except -1
|
|
32
|
+
void PyBuffer_Release(Py_buffer *)
|
|
33
|
+
|
|
34
|
+
ctypedef struct PyObject
|
|
35
|
+
ctypedef Py_ssize_t Py_intptr_t
|
|
36
|
+
void Py_INCREF(PyObject *)
|
|
37
|
+
void Py_DECREF(PyObject *)
|
|
38
|
+
|
|
39
|
+
void* PyMem_Malloc(size_t n)
|
|
40
|
+
void PyMem_Free(void *p)
|
|
41
|
+
void* PyObject_Malloc(size_t n)
|
|
42
|
+
void PyObject_Free(void *p)
|
|
43
|
+
|
|
44
|
+
cdef struct __pyx_memoryview "__pyx_memoryview_obj":
|
|
45
|
+
Py_buffer view
|
|
46
|
+
PyObject *obj
|
|
47
|
+
const __Pyx_TypeInfo *typeinfo
|
|
48
|
+
|
|
49
|
+
ctypedef struct {{memviewslice_name}}:
|
|
50
|
+
__pyx_memoryview *memview
|
|
51
|
+
char *data
|
|
52
|
+
Py_ssize_t shape[{{max_dims}}]
|
|
53
|
+
Py_ssize_t strides[{{max_dims}}]
|
|
54
|
+
Py_ssize_t suboffsets[{{max_dims}}]
|
|
55
|
+
|
|
56
|
+
void __PYX_INC_MEMVIEW({{memviewslice_name}} *memslice, int have_gil)
|
|
57
|
+
void __PYX_XCLEAR_MEMVIEW({{memviewslice_name}} *memslice, int have_gil)
|
|
58
|
+
|
|
59
|
+
ctypedef struct __pyx_buffer "Py_buffer":
|
|
60
|
+
PyObject *obj
|
|
61
|
+
|
|
62
|
+
PyObject *Py_None
|
|
63
|
+
|
|
64
|
+
cdef enum:
|
|
65
|
+
PyBUF_C_CONTIGUOUS,
|
|
66
|
+
PyBUF_F_CONTIGUOUS,
|
|
67
|
+
PyBUF_ANY_CONTIGUOUS
|
|
68
|
+
PyBUF_FORMAT
|
|
69
|
+
PyBUF_WRITABLE
|
|
70
|
+
PyBUF_STRIDES
|
|
71
|
+
PyBUF_INDIRECT
|
|
72
|
+
PyBUF_ND
|
|
73
|
+
PyBUF_RECORDS
|
|
74
|
+
PyBUF_RECORDS_RO
|
|
75
|
+
|
|
76
|
+
ctypedef struct __Pyx_TypeInfo:
|
|
77
|
+
pass
|
|
78
|
+
|
|
79
|
+
cdef extern from *:
|
|
80
|
+
ctypedef int __pyx_atomic_int_type
|
|
81
|
+
{{memviewslice_name}} slice_copy_contig "__pyx_memoryview_copy_new_contig"(
|
|
82
|
+
{{memviewslice_name}} *from_mvs,
|
|
83
|
+
const char *mode, int ndim,
|
|
84
|
+
size_t sizeof_dtype, int contig_flag,
|
|
85
|
+
bint dtype_is_object) except * nogil
|
|
86
|
+
bint slice_is_contig "__pyx_memviewslice_is_contig" (
|
|
87
|
+
{{memviewslice_name}} mvs, char order, int ndim) nogil
|
|
88
|
+
bint slices_overlap "__pyx_slices_overlap" ({{memviewslice_name}} *slice1,
|
|
89
|
+
{{memviewslice_name}} *slice2,
|
|
90
|
+
int ndim, size_t itemsize) nogil
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
cdef extern from "<stdlib.h>":
|
|
94
|
+
void *malloc(size_t) nogil
|
|
95
|
+
void free(void *) nogil
|
|
96
|
+
void *memcpy(void *dest, void *src, size_t n) nogil
|
|
97
|
+
|
|
98
|
+
# the sequence abstract base class
|
|
99
|
+
cdef object __pyx_collections_abc_Sequence "__pyx_collections_abc_Sequence"
|
|
100
|
+
try:
|
|
101
|
+
__pyx_collections_abc_Sequence = __import__("collections.abc").abc.Sequence
|
|
102
|
+
except:
|
|
103
|
+
# it isn't a big problem if this fails
|
|
104
|
+
__pyx_collections_abc_Sequence = None
|
|
105
|
+
|
|
106
|
+
#
|
|
107
|
+
### cython.array class
|
|
108
|
+
#
|
|
109
|
+
|
|
110
|
+
@cython.collection_type("sequence")
|
|
111
|
+
@cname("__pyx_array")
|
|
112
|
+
cdef class array:
|
|
113
|
+
|
|
114
|
+
cdef:
|
|
115
|
+
char *data
|
|
116
|
+
Py_ssize_t len
|
|
117
|
+
char *format
|
|
118
|
+
int ndim
|
|
119
|
+
Py_ssize_t *_shape
|
|
120
|
+
Py_ssize_t *_strides
|
|
121
|
+
Py_ssize_t itemsize
|
|
122
|
+
unicode mode # FIXME: this should have been a simple 'char'
|
|
123
|
+
bytes _format
|
|
124
|
+
void (*callback_free_data)(void *data) noexcept
|
|
125
|
+
# cdef object _memview
|
|
126
|
+
cdef bint free_data
|
|
127
|
+
cdef bint dtype_is_object
|
|
128
|
+
|
|
129
|
+
def __cinit__(array self, tuple shape, Py_ssize_t itemsize, format not None,
|
|
130
|
+
mode="c", bint allocate_buffer=True):
|
|
131
|
+
|
|
132
|
+
cdef int idx
|
|
133
|
+
cdef Py_ssize_t dim
|
|
134
|
+
|
|
135
|
+
self.ndim = <int> len(shape)
|
|
136
|
+
self.itemsize = itemsize
|
|
137
|
+
|
|
138
|
+
if not self.ndim:
|
|
139
|
+
raise ValueError, "Empty shape tuple for cython.array"
|
|
140
|
+
|
|
141
|
+
if itemsize <= 0:
|
|
142
|
+
raise ValueError, "itemsize <= 0 for cython.array"
|
|
143
|
+
|
|
144
|
+
if not isinstance(format, bytes):
|
|
145
|
+
format = format.encode('ASCII')
|
|
146
|
+
self._format = format # keep a reference to the byte string
|
|
147
|
+
self.format = self._format
|
|
148
|
+
|
|
149
|
+
# use single malloc() for both shape and strides
|
|
150
|
+
self._shape = <Py_ssize_t *> PyObject_Malloc(sizeof(Py_ssize_t)*self.ndim*2)
|
|
151
|
+
self._strides = self._shape + self.ndim
|
|
152
|
+
|
|
153
|
+
if not self._shape:
|
|
154
|
+
raise MemoryError, "unable to allocate shape and strides."
|
|
155
|
+
|
|
156
|
+
# cdef Py_ssize_t dim, stride
|
|
157
|
+
for idx, dim in enumerate(shape):
|
|
158
|
+
if dim <= 0:
|
|
159
|
+
raise ValueError, f"Invalid shape in axis {idx}: {dim}."
|
|
160
|
+
self._shape[idx] = dim
|
|
161
|
+
|
|
162
|
+
cdef char order
|
|
163
|
+
if mode == 'c':
|
|
164
|
+
order = b'C'
|
|
165
|
+
self.mode = u'c'
|
|
166
|
+
elif mode == 'fortran':
|
|
167
|
+
order = b'F'
|
|
168
|
+
self.mode = u'fortran'
|
|
169
|
+
else:
|
|
170
|
+
raise ValueError, f"Invalid mode, expected 'c' or 'fortran', got {mode}"
|
|
171
|
+
|
|
172
|
+
self.len = fill_contig_strides_array(self._shape, self._strides, itemsize, self.ndim, order)
|
|
173
|
+
|
|
174
|
+
self.free_data = allocate_buffer
|
|
175
|
+
self.dtype_is_object = format == b'O'
|
|
176
|
+
|
|
177
|
+
if allocate_buffer:
|
|
178
|
+
_allocate_buffer(self)
|
|
179
|
+
|
|
180
|
+
@cname('getbuffer')
|
|
181
|
+
def __getbuffer__(self, Py_buffer *info, int flags):
|
|
182
|
+
cdef int bufmode = -1
|
|
183
|
+
if flags & (PyBUF_C_CONTIGUOUS | PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS):
|
|
184
|
+
if self.mode == u"c":
|
|
185
|
+
bufmode = PyBUF_C_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS
|
|
186
|
+
elif self.mode == u"fortran":
|
|
187
|
+
bufmode = PyBUF_F_CONTIGUOUS | PyBUF_ANY_CONTIGUOUS
|
|
188
|
+
if not (flags & bufmode):
|
|
189
|
+
raise ValueError, "Can only create a buffer that is contiguous in memory."
|
|
190
|
+
info.buf = self.data
|
|
191
|
+
info.len = self.len
|
|
192
|
+
|
|
193
|
+
if flags & PyBUF_STRIDES:
|
|
194
|
+
info.ndim = self.ndim
|
|
195
|
+
info.shape = self._shape
|
|
196
|
+
info.strides = self._strides
|
|
197
|
+
else:
|
|
198
|
+
info.ndim = 1
|
|
199
|
+
info.shape = &self.len if flags & PyBUF_ND else NULL
|
|
200
|
+
info.strides = NULL
|
|
201
|
+
|
|
202
|
+
info.suboffsets = NULL
|
|
203
|
+
info.itemsize = self.itemsize
|
|
204
|
+
info.readonly = 0
|
|
205
|
+
info.format = self.format if flags & PyBUF_FORMAT else NULL
|
|
206
|
+
info.obj = self
|
|
207
|
+
|
|
208
|
+
def __dealloc__(array self):
|
|
209
|
+
if self.callback_free_data != NULL:
|
|
210
|
+
self.callback_free_data(self.data)
|
|
211
|
+
elif self.free_data and self.data is not NULL:
|
|
212
|
+
if self.dtype_is_object:
|
|
213
|
+
refcount_objects_in_slice(self.data, self._shape, self._strides, self.ndim, inc=False)
|
|
214
|
+
free(self.data)
|
|
215
|
+
PyObject_Free(self._shape)
|
|
216
|
+
|
|
217
|
+
@property
|
|
218
|
+
def memview(self):
|
|
219
|
+
return self.get_memview()
|
|
220
|
+
|
|
221
|
+
@cname('get_memview')
|
|
222
|
+
cdef get_memview(self):
|
|
223
|
+
flags = PyBUF_ANY_CONTIGUOUS|PyBUF_FORMAT|PyBUF_WRITABLE
|
|
224
|
+
return memoryview(self, flags, self.dtype_is_object)
|
|
225
|
+
|
|
226
|
+
def __len__(self):
|
|
227
|
+
return self._shape[0]
|
|
228
|
+
|
|
229
|
+
def __getattr__(self, attr):
|
|
230
|
+
return getattr(self.memview, attr)
|
|
231
|
+
|
|
232
|
+
def __getitem__(self, item):
|
|
233
|
+
return self.memview[item]
|
|
234
|
+
|
|
235
|
+
def __setitem__(self, item, value):
|
|
236
|
+
self.memview[item] = value
|
|
237
|
+
|
|
238
|
+
# Sequence methods
|
|
239
|
+
try:
|
|
240
|
+
count = __pyx_collections_abc_Sequence.count
|
|
241
|
+
index = __pyx_collections_abc_Sequence.index
|
|
242
|
+
except:
|
|
243
|
+
pass
|
|
244
|
+
|
|
245
|
+
@cname("__pyx_array_allocate_buffer")
|
|
246
|
+
cdef int _allocate_buffer(array self) except -1:
|
|
247
|
+
# use malloc() for backwards compatibility
|
|
248
|
+
# in case external code wants to change the data pointer
|
|
249
|
+
cdef Py_ssize_t i
|
|
250
|
+
cdef PyObject **p
|
|
251
|
+
|
|
252
|
+
self.free_data = True
|
|
253
|
+
self.data = <char *>malloc(self.len)
|
|
254
|
+
if not self.data:
|
|
255
|
+
raise MemoryError, "unable to allocate array data."
|
|
256
|
+
|
|
257
|
+
if self.dtype_is_object:
|
|
258
|
+
p = <PyObject **> self.data
|
|
259
|
+
for i in range(self.len // self.itemsize):
|
|
260
|
+
p[i] = Py_None
|
|
261
|
+
Py_INCREF(Py_None)
|
|
262
|
+
return 0
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
@cname("__pyx_array_new")
|
|
266
|
+
cdef array array_cwrapper(tuple shape, Py_ssize_t itemsize, char *format, const char *c_mode, char *buf):
|
|
267
|
+
cdef array result
|
|
268
|
+
cdef str mode = "fortran" if c_mode[0] == b'f' else "c" # this often comes from a constant C string.
|
|
269
|
+
|
|
270
|
+
if buf is NULL:
|
|
271
|
+
result = array.__new__(array, shape, itemsize, format, mode)
|
|
272
|
+
else:
|
|
273
|
+
result = array.__new__(array, shape, itemsize, format, mode, allocate_buffer=False)
|
|
274
|
+
result.data = buf
|
|
275
|
+
|
|
276
|
+
return result
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
#
|
|
280
|
+
### Memoryview constants and cython.view.memoryview class
|
|
281
|
+
#
|
|
282
|
+
|
|
283
|
+
# Disable generic_contiguous, as it makes trouble verifying contiguity:
|
|
284
|
+
# - 'contiguous' or '::1' means the dimension is contiguous with dtype
|
|
285
|
+
# - 'indirect_contiguous' means a contiguous list of pointers
|
|
286
|
+
# - dtype contiguous must be contiguous in the first or last dimension
|
|
287
|
+
# from the start, or from the dimension following the last indirect dimension
|
|
288
|
+
#
|
|
289
|
+
# e.g.
|
|
290
|
+
# int[::indirect_contiguous, ::contiguous, :]
|
|
291
|
+
#
|
|
292
|
+
# is valid (list of pointers to 2d fortran-contiguous array), but
|
|
293
|
+
#
|
|
294
|
+
# int[::generic_contiguous, ::contiguous, :]
|
|
295
|
+
#
|
|
296
|
+
# would mean you'd have assert dimension 0 to be indirect (and pointer contiguous) at runtime.
|
|
297
|
+
# So it doesn't bring any performance benefit, and it's only confusing.
|
|
298
|
+
|
|
299
|
+
@cname('__pyx_MemviewEnum')
|
|
300
|
+
cdef class Enum(object):
|
|
301
|
+
cdef object name
|
|
302
|
+
def __init__(self, name):
|
|
303
|
+
self.name = name
|
|
304
|
+
def __repr__(self):
|
|
305
|
+
return self.name
|
|
306
|
+
|
|
307
|
+
cdef generic = Enum("<strided and direct or indirect>")
|
|
308
|
+
cdef strided = Enum("<strided and direct>") # default
|
|
309
|
+
cdef indirect = Enum("<strided and indirect>")
|
|
310
|
+
# Disable generic_contiguous, as it is a troublemaker
|
|
311
|
+
#cdef generic_contiguous = Enum("<contiguous and direct or indirect>")
|
|
312
|
+
cdef contiguous = Enum("<contiguous and direct>")
|
|
313
|
+
cdef indirect_contiguous = Enum("<contiguous and indirect>")
|
|
314
|
+
|
|
315
|
+
# 'follow' is implied when the first or last axis is ::1
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
# pre-allocate thread locks for reuse
|
|
319
|
+
## note that this could be implemented in a more beautiful way in "normal" Cython,
|
|
320
|
+
## but this code gets merged into the user module and not everything works there.
|
|
321
|
+
cdef int __pyx_memoryview_thread_locks_used = 0
|
|
322
|
+
cdef PyThread_type_lock[{{THREAD_LOCKS_PREALLOCATED}}] __pyx_memoryview_thread_locks = [
|
|
323
|
+
{{for _ in range(THREAD_LOCKS_PREALLOCATED)}}
|
|
324
|
+
PyThread_allocate_lock(),
|
|
325
|
+
{{endfor}}
|
|
326
|
+
]
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
@cname('__pyx_memoryview')
|
|
330
|
+
cdef class memoryview:
|
|
331
|
+
|
|
332
|
+
cdef object obj
|
|
333
|
+
cdef object _size
|
|
334
|
+
cdef object _array_interface
|
|
335
|
+
cdef PyThread_type_lock lock
|
|
336
|
+
cdef __pyx_atomic_int_type acquisition_count
|
|
337
|
+
cdef Py_buffer view
|
|
338
|
+
cdef int flags
|
|
339
|
+
cdef bint dtype_is_object
|
|
340
|
+
cdef const __Pyx_TypeInfo *typeinfo
|
|
341
|
+
|
|
342
|
+
def __cinit__(memoryview self, object obj, int flags, bint dtype_is_object=False):
|
|
343
|
+
self.obj = obj
|
|
344
|
+
self.flags = flags
|
|
345
|
+
if type(self) is memoryview or obj is not None:
|
|
346
|
+
PyObject_GetBuffer(obj, &self.view, flags)
|
|
347
|
+
if <PyObject *> self.view.obj == NULL:
|
|
348
|
+
(<__pyx_buffer *> &self.view).obj = Py_None
|
|
349
|
+
Py_INCREF(Py_None)
|
|
350
|
+
|
|
351
|
+
if not __PYX_CYTHON_ATOMICS_ENABLED():
|
|
352
|
+
global __pyx_memoryview_thread_locks_used
|
|
353
|
+
if (__pyx_memoryview_thread_locks_used < {{THREAD_LOCKS_PREALLOCATED}} and
|
|
354
|
+
# preallocated locks cannot be made thread-safe in freethreading
|
|
355
|
+
not __PYX_GET_CYTHON_COMPILING_IN_CPYTHON_FREETHREADING()):
|
|
356
|
+
self.lock = __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used]
|
|
357
|
+
__pyx_memoryview_thread_locks_used += 1
|
|
358
|
+
if self.lock is NULL:
|
|
359
|
+
self.lock = PyThread_allocate_lock()
|
|
360
|
+
if self.lock is NULL:
|
|
361
|
+
raise MemoryError
|
|
362
|
+
|
|
363
|
+
if flags & PyBUF_FORMAT:
|
|
364
|
+
self.dtype_is_object = (self.view.format[0] == b'O' and self.view.format[1] == b'\0')
|
|
365
|
+
else:
|
|
366
|
+
self.dtype_is_object = dtype_is_object
|
|
367
|
+
|
|
368
|
+
assert <Py_intptr_t><void*>(&self.acquisition_count) % sizeof(__pyx_atomic_int_type) == 0
|
|
369
|
+
self.typeinfo = NULL
|
|
370
|
+
|
|
371
|
+
def __dealloc__(memoryview self):
|
|
372
|
+
if self.obj is not None:
|
|
373
|
+
PyBuffer_Release(&self.view)
|
|
374
|
+
elif (<__pyx_buffer *> &self.view).obj == Py_None:
|
|
375
|
+
# Undo the incref in __cinit__() above.
|
|
376
|
+
(<__pyx_buffer *> &self.view).obj = NULL
|
|
377
|
+
Py_DECREF(Py_None)
|
|
378
|
+
|
|
379
|
+
cdef int i
|
|
380
|
+
global __pyx_memoryview_thread_locks_used
|
|
381
|
+
if self.lock != NULL:
|
|
382
|
+
for i in range(0 if __PYX_GET_CYTHON_COMPILING_IN_CPYTHON_FREETHREADING() else __pyx_memoryview_thread_locks_used):
|
|
383
|
+
if __pyx_memoryview_thread_locks[i] is self.lock:
|
|
384
|
+
__pyx_memoryview_thread_locks_used -= 1
|
|
385
|
+
if i != __pyx_memoryview_thread_locks_used:
|
|
386
|
+
__pyx_memoryview_thread_locks[i], __pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used] = (
|
|
387
|
+
__pyx_memoryview_thread_locks[__pyx_memoryview_thread_locks_used], __pyx_memoryview_thread_locks[i])
|
|
388
|
+
break
|
|
389
|
+
else:
|
|
390
|
+
PyThread_free_lock(self.lock)
|
|
391
|
+
|
|
392
|
+
cdef char *get_item_pointer(memoryview self, object index) except NULL:
|
|
393
|
+
cdef Py_ssize_t dim
|
|
394
|
+
cdef char *itemp = <char *> self.view.buf
|
|
395
|
+
|
|
396
|
+
for dim, idx in enumerate(index):
|
|
397
|
+
itemp = pybuffer_index(&self.view, itemp, idx, dim)
|
|
398
|
+
|
|
399
|
+
return itemp
|
|
400
|
+
|
|
401
|
+
#@cname('__pyx_memoryview_getitem')
|
|
402
|
+
def __getitem__(memoryview self, object index):
|
|
403
|
+
if index is Ellipsis:
|
|
404
|
+
return self
|
|
405
|
+
|
|
406
|
+
have_slices, indices = _unellipsify(index, self.view.ndim)
|
|
407
|
+
|
|
408
|
+
cdef char *itemp
|
|
409
|
+
if have_slices:
|
|
410
|
+
return memview_slice(self, indices)
|
|
411
|
+
else:
|
|
412
|
+
itemp = self.get_item_pointer(indices)
|
|
413
|
+
return self.convert_item_to_object(itemp)
|
|
414
|
+
|
|
415
|
+
def __setitem__(memoryview self, object index, object value):
|
|
416
|
+
if self.view.readonly:
|
|
417
|
+
raise TypeError, "Cannot assign to read-only memoryview"
|
|
418
|
+
|
|
419
|
+
have_slices, index = _unellipsify(index, self.view.ndim)
|
|
420
|
+
|
|
421
|
+
if have_slices:
|
|
422
|
+
obj = self.is_slice(value)
|
|
423
|
+
if obj is not None:
|
|
424
|
+
self.setitem_slice_assignment(self[index], obj)
|
|
425
|
+
else:
|
|
426
|
+
self.setitem_slice_assign_scalar(self[index], value)
|
|
427
|
+
else:
|
|
428
|
+
self.setitem_indexed(index, value)
|
|
429
|
+
|
|
430
|
+
cdef is_slice(self, obj):
|
|
431
|
+
if not isinstance(obj, memoryview):
|
|
432
|
+
try:
|
|
433
|
+
obj = memoryview(obj, self.flags & ~PyBUF_WRITABLE | PyBUF_ANY_CONTIGUOUS,
|
|
434
|
+
self.dtype_is_object)
|
|
435
|
+
except TypeError:
|
|
436
|
+
return None
|
|
437
|
+
|
|
438
|
+
return obj
|
|
439
|
+
|
|
440
|
+
cdef setitem_slice_assignment(self, dst, src):
|
|
441
|
+
cdef {{memviewslice_name}} dst_slice
|
|
442
|
+
cdef {{memviewslice_name}} src_slice
|
|
443
|
+
cdef {{memviewslice_name}} msrc = get_slice_from_memview(src, &src_slice)[0]
|
|
444
|
+
cdef {{memviewslice_name}} mdst = get_slice_from_memview(dst, &dst_slice)[0]
|
|
445
|
+
|
|
446
|
+
memoryview_copy_contents(msrc, mdst, src.ndim, dst.ndim, self.dtype_is_object)
|
|
447
|
+
|
|
448
|
+
cdef setitem_slice_assign_scalar(self, memoryview dst, value):
|
|
449
|
+
cdef int array[128]
|
|
450
|
+
cdef void *tmp = NULL
|
|
451
|
+
cdef void *item
|
|
452
|
+
|
|
453
|
+
cdef {{memviewslice_name}} *dst_slice
|
|
454
|
+
cdef {{memviewslice_name}} tmp_slice
|
|
455
|
+
dst_slice = get_slice_from_memview(dst, &tmp_slice)
|
|
456
|
+
|
|
457
|
+
if <size_t>self.view.itemsize > sizeof(array):
|
|
458
|
+
tmp = PyMem_Malloc(self.view.itemsize)
|
|
459
|
+
if tmp == NULL:
|
|
460
|
+
raise MemoryError
|
|
461
|
+
item = tmp
|
|
462
|
+
else:
|
|
463
|
+
item = <void *> array
|
|
464
|
+
|
|
465
|
+
try:
|
|
466
|
+
if self.dtype_is_object:
|
|
467
|
+
(<PyObject **> item)[0] = <PyObject *> value
|
|
468
|
+
else:
|
|
469
|
+
self.assign_item_from_object(<char *> item, value)
|
|
470
|
+
|
|
471
|
+
# It would be easy to support indirect dimensions, but it's easier
|
|
472
|
+
# to disallow :)
|
|
473
|
+
if self.view.suboffsets != NULL:
|
|
474
|
+
assert_direct_dimensions(self.view.suboffsets, self.view.ndim)
|
|
475
|
+
slice_assign_scalar(dst_slice, dst.view.ndim, self.view.itemsize,
|
|
476
|
+
item, self.dtype_is_object)
|
|
477
|
+
finally:
|
|
478
|
+
PyMem_Free(tmp)
|
|
479
|
+
|
|
480
|
+
cdef setitem_indexed(self, index, value):
|
|
481
|
+
cdef char *itemp = self.get_item_pointer(index)
|
|
482
|
+
self.assign_item_from_object(itemp, value)
|
|
483
|
+
|
|
484
|
+
cdef convert_item_to_object(self, char *itemp):
|
|
485
|
+
"""Only used if instantiated manually by the user, or if Cython doesn't
|
|
486
|
+
know how to convert the type"""
|
|
487
|
+
import struct
|
|
488
|
+
cdef bytes bytesitem
|
|
489
|
+
# Do a manual and complete check here instead of this easy hack
|
|
490
|
+
bytesitem = itemp[:self.view.itemsize]
|
|
491
|
+
try:
|
|
492
|
+
result = struct.unpack(self.view.format, bytesitem)
|
|
493
|
+
except struct.error:
|
|
494
|
+
raise ValueError, "Unable to convert item to object"
|
|
495
|
+
else:
|
|
496
|
+
if len(self.view.format) == 1:
|
|
497
|
+
return result[0]
|
|
498
|
+
return result
|
|
499
|
+
|
|
500
|
+
cdef assign_item_from_object(self, char *itemp, object value):
|
|
501
|
+
"""Only used if instantiated manually by the user, or if Cython doesn't
|
|
502
|
+
know how to convert the type"""
|
|
503
|
+
import struct
|
|
504
|
+
cdef char c
|
|
505
|
+
cdef bytes bytesvalue
|
|
506
|
+
cdef Py_ssize_t i
|
|
507
|
+
|
|
508
|
+
if isinstance(value, tuple):
|
|
509
|
+
bytesvalue = struct.pack(self.view.format, *value)
|
|
510
|
+
else:
|
|
511
|
+
bytesvalue = struct.pack(self.view.format, value)
|
|
512
|
+
|
|
513
|
+
for i, c in enumerate(bytesvalue):
|
|
514
|
+
itemp[i] = c
|
|
515
|
+
|
|
516
|
+
@cname('getbuffer')
|
|
517
|
+
def __getbuffer__(self, Py_buffer *info, int flags):
|
|
518
|
+
if flags & PyBUF_WRITABLE and self.view.readonly:
|
|
519
|
+
raise ValueError, "Cannot create writable memory view from read-only memoryview"
|
|
520
|
+
|
|
521
|
+
if flags & PyBUF_ND:
|
|
522
|
+
info.shape = self.view.shape
|
|
523
|
+
else:
|
|
524
|
+
info.shape = NULL
|
|
525
|
+
|
|
526
|
+
if flags & PyBUF_STRIDES:
|
|
527
|
+
info.strides = self.view.strides
|
|
528
|
+
else:
|
|
529
|
+
info.strides = NULL
|
|
530
|
+
|
|
531
|
+
if flags & PyBUF_INDIRECT:
|
|
532
|
+
info.suboffsets = self.view.suboffsets
|
|
533
|
+
else:
|
|
534
|
+
info.suboffsets = NULL
|
|
535
|
+
|
|
536
|
+
if flags & PyBUF_FORMAT:
|
|
537
|
+
info.format = self.view.format
|
|
538
|
+
else:
|
|
539
|
+
info.format = NULL
|
|
540
|
+
|
|
541
|
+
info.buf = self.view.buf
|
|
542
|
+
info.ndim = self.view.ndim
|
|
543
|
+
info.itemsize = self.view.itemsize
|
|
544
|
+
info.len = self.view.len
|
|
545
|
+
info.readonly = self.view.readonly
|
|
546
|
+
info.obj = self
|
|
547
|
+
|
|
548
|
+
# Some properties that have the same semantics as in NumPy
|
|
549
|
+
@property
|
|
550
|
+
def T(self):
|
|
551
|
+
cdef _memoryviewslice result = memoryview_copy(self)
|
|
552
|
+
transpose_memslice(&result.from_slice)
|
|
553
|
+
return result
|
|
554
|
+
|
|
555
|
+
@property
|
|
556
|
+
def base(self):
|
|
557
|
+
return self._get_base()
|
|
558
|
+
|
|
559
|
+
cdef _get_base(self):
|
|
560
|
+
return self.obj
|
|
561
|
+
|
|
562
|
+
@property
|
|
563
|
+
def shape(self):
|
|
564
|
+
return tuple([length for length in self.view.shape[:self.view.ndim]])
|
|
565
|
+
|
|
566
|
+
@property
|
|
567
|
+
def strides(self):
|
|
568
|
+
if self.view.strides == NULL:
|
|
569
|
+
# Note: we always ask for strides, so if this is not set it's a bug
|
|
570
|
+
raise ValueError, "Buffer view does not expose strides"
|
|
571
|
+
|
|
572
|
+
return tuple([stride for stride in self.view.strides[:self.view.ndim]])
|
|
573
|
+
|
|
574
|
+
@property
|
|
575
|
+
def suboffsets(self):
|
|
576
|
+
if self.view.suboffsets == NULL:
|
|
577
|
+
return (-1,) * self.view.ndim
|
|
578
|
+
|
|
579
|
+
return tuple([suboffset for suboffset in self.view.suboffsets[:self.view.ndim]])
|
|
580
|
+
|
|
581
|
+
@property
|
|
582
|
+
def ndim(self):
|
|
583
|
+
return self.view.ndim
|
|
584
|
+
|
|
585
|
+
@property
|
|
586
|
+
def itemsize(self):
|
|
587
|
+
return self.view.itemsize
|
|
588
|
+
|
|
589
|
+
@property
|
|
590
|
+
def nbytes(self):
|
|
591
|
+
return self.size * self.view.itemsize
|
|
592
|
+
|
|
593
|
+
@property
|
|
594
|
+
def size(self):
|
|
595
|
+
if self._size is None:
|
|
596
|
+
result = 1
|
|
597
|
+
|
|
598
|
+
for length in self.view.shape[:self.view.ndim]:
|
|
599
|
+
result *= length
|
|
600
|
+
|
|
601
|
+
self._size = result
|
|
602
|
+
|
|
603
|
+
return self._size
|
|
604
|
+
|
|
605
|
+
def __len__(self):
|
|
606
|
+
if self.view.ndim >= 1:
|
|
607
|
+
return self.view.shape[0]
|
|
608
|
+
|
|
609
|
+
return 0
|
|
610
|
+
|
|
611
|
+
def __repr__(self):
|
|
612
|
+
return "<MemoryView of %r at 0x%x>" % (self.base.__class__.__name__,
|
|
613
|
+
id(self))
|
|
614
|
+
|
|
615
|
+
def __str__(self):
|
|
616
|
+
return "<MemoryView of %r object>" % (self.base.__class__.__name__,)
|
|
617
|
+
|
|
618
|
+
# Support the same attributes as memoryview slices
|
|
619
|
+
def is_c_contig(self):
|
|
620
|
+
cdef {{memviewslice_name}} *mslice
|
|
621
|
+
cdef {{memviewslice_name}} tmp
|
|
622
|
+
mslice = get_slice_from_memview(self, &tmp)
|
|
623
|
+
return slice_is_contig(mslice[0], 'C', self.view.ndim)
|
|
624
|
+
|
|
625
|
+
def is_f_contig(self):
|
|
626
|
+
cdef {{memviewslice_name}} *mslice
|
|
627
|
+
cdef {{memviewslice_name}} tmp
|
|
628
|
+
mslice = get_slice_from_memview(self, &tmp)
|
|
629
|
+
return slice_is_contig(mslice[0], 'F', self.view.ndim)
|
|
630
|
+
|
|
631
|
+
def copy(self):
|
|
632
|
+
cdef {{memviewslice_name}} mslice
|
|
633
|
+
cdef int flags = self.flags & ~PyBUF_F_CONTIGUOUS
|
|
634
|
+
|
|
635
|
+
slice_copy(self, &mslice)
|
|
636
|
+
mslice = slice_copy_contig(&mslice, "c", self.view.ndim,
|
|
637
|
+
self.view.itemsize,
|
|
638
|
+
flags|PyBUF_C_CONTIGUOUS,
|
|
639
|
+
self.dtype_is_object)
|
|
640
|
+
|
|
641
|
+
return memoryview_copy_from_slice(self, &mslice)
|
|
642
|
+
|
|
643
|
+
def copy_fortran(self):
|
|
644
|
+
cdef {{memviewslice_name}} src, dst
|
|
645
|
+
cdef int flags = self.flags & ~PyBUF_C_CONTIGUOUS
|
|
646
|
+
|
|
647
|
+
slice_copy(self, &src)
|
|
648
|
+
dst = slice_copy_contig(&src, "fortran", self.view.ndim,
|
|
649
|
+
self.view.itemsize,
|
|
650
|
+
flags|PyBUF_F_CONTIGUOUS,
|
|
651
|
+
self.dtype_is_object)
|
|
652
|
+
|
|
653
|
+
return memoryview_copy_from_slice(self, &dst)
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
@cname('__pyx_memoryview_new')
|
|
657
|
+
cdef memoryview_cwrapper(object o, int flags, bint dtype_is_object, const __Pyx_TypeInfo *typeinfo):
|
|
658
|
+
cdef memoryview result = memoryview(o, flags, dtype_is_object)
|
|
659
|
+
result.typeinfo = typeinfo
|
|
660
|
+
return result
|
|
661
|
+
|
|
662
|
+
@cname('__pyx_memoryview_check')
|
|
663
|
+
cdef inline bint memoryview_check(object o) noexcept:
|
|
664
|
+
return isinstance(o, memoryview)
|
|
665
|
+
|
|
666
|
+
cdef tuple _unellipsify(object index, int ndim):
|
|
667
|
+
"""
|
|
668
|
+
Replace all ellipses with full slices and fill incomplete indices with
|
|
669
|
+
full slices.
|
|
670
|
+
"""
|
|
671
|
+
cdef Py_ssize_t idx
|
|
672
|
+
tup = <tuple>index if isinstance(index, tuple) else (index,)
|
|
673
|
+
|
|
674
|
+
result = [slice(None)] * ndim
|
|
675
|
+
have_slices = False
|
|
676
|
+
seen_ellipsis = False
|
|
677
|
+
idx = 0
|
|
678
|
+
for item in tup:
|
|
679
|
+
if item is Ellipsis:
|
|
680
|
+
if not seen_ellipsis:
|
|
681
|
+
idx += ndim - len(tup)
|
|
682
|
+
seen_ellipsis = True
|
|
683
|
+
have_slices = True
|
|
684
|
+
else:
|
|
685
|
+
if isinstance(item, slice):
|
|
686
|
+
have_slices = True
|
|
687
|
+
elif not PyIndex_Check(item):
|
|
688
|
+
raise TypeError, f"Cannot index with type '{type(item)}'"
|
|
689
|
+
result[idx] = item
|
|
690
|
+
idx += 1
|
|
691
|
+
|
|
692
|
+
nslices = ndim - idx
|
|
693
|
+
return have_slices or nslices, tuple(result)
|
|
694
|
+
|
|
695
|
+
cdef int assert_direct_dimensions(Py_ssize_t *suboffsets, int ndim) except -1:
|
|
696
|
+
for suboffset in suboffsets[:ndim]:
|
|
697
|
+
if suboffset >= 0:
|
|
698
|
+
raise ValueError, "Indirect dimensions not supported"
|
|
699
|
+
return 0 # return type just used as an error flag
|
|
700
|
+
|
|
701
|
+
#
|
|
702
|
+
### Slicing a memoryview
|
|
703
|
+
#
|
|
704
|
+
|
|
705
|
+
@cname('__pyx_memview_slice')
|
|
706
|
+
cdef memoryview memview_slice(memoryview memview, object indices):
|
|
707
|
+
cdef int new_ndim = 0, suboffset_dim = -1, dim
|
|
708
|
+
cdef bint negative_step
|
|
709
|
+
cdef {{memviewslice_name}} src, dst
|
|
710
|
+
cdef {{memviewslice_name}} *p_src
|
|
711
|
+
|
|
712
|
+
# dst is copied by value in memoryview_fromslice -- initialize it
|
|
713
|
+
# src is never copied
|
|
714
|
+
memset(&dst, 0, sizeof(dst))
|
|
715
|
+
|
|
716
|
+
cdef _memoryviewslice memviewsliceobj
|
|
717
|
+
|
|
718
|
+
assert memview.view.ndim > 0
|
|
719
|
+
|
|
720
|
+
if isinstance(memview, _memoryviewslice):
|
|
721
|
+
memviewsliceobj = memview
|
|
722
|
+
p_src = &memviewsliceobj.from_slice
|
|
723
|
+
else:
|
|
724
|
+
slice_copy(memview, &src)
|
|
725
|
+
p_src = &src
|
|
726
|
+
|
|
727
|
+
# Note: don't use variable src at this point
|
|
728
|
+
# SubNote: we should be able to declare variables in blocks...
|
|
729
|
+
|
|
730
|
+
# memoryview_fromslice() will inc our dst slice
|
|
731
|
+
dst.memview = p_src.memview
|
|
732
|
+
dst.data = p_src.data
|
|
733
|
+
|
|
734
|
+
# Put everything in temps to avoid this bloody warning:
|
|
735
|
+
# "Argument evaluation order in C function call is undefined and
|
|
736
|
+
# may not be as expected"
|
|
737
|
+
cdef {{memviewslice_name}} *p_dst = &dst
|
|
738
|
+
cdef int *p_suboffset_dim = &suboffset_dim
|
|
739
|
+
cdef Py_ssize_t start, stop, step, cindex
|
|
740
|
+
cdef bint have_start, have_stop, have_step
|
|
741
|
+
|
|
742
|
+
for dim, index in enumerate(indices):
|
|
743
|
+
if PyIndex_Check(index):
|
|
744
|
+
cindex = index
|
|
745
|
+
slice_memviewslice(
|
|
746
|
+
p_dst, p_src.shape[dim], p_src.strides[dim], p_src.suboffsets[dim],
|
|
747
|
+
dim, new_ndim, p_suboffset_dim,
|
|
748
|
+
cindex, 0, 0, # start, stop, step
|
|
749
|
+
0, 0, 0, # have_{start,stop,step}
|
|
750
|
+
False)
|
|
751
|
+
elif index is None:
|
|
752
|
+
p_dst.shape[new_ndim] = 1
|
|
753
|
+
p_dst.strides[new_ndim] = 0
|
|
754
|
+
p_dst.suboffsets[new_ndim] = -1
|
|
755
|
+
new_ndim += 1
|
|
756
|
+
else:
|
|
757
|
+
start = index.start or 0
|
|
758
|
+
stop = index.stop or 0
|
|
759
|
+
step = index.step or 0
|
|
760
|
+
|
|
761
|
+
have_start = index.start is not None
|
|
762
|
+
have_stop = index.stop is not None
|
|
763
|
+
have_step = index.step is not None
|
|
764
|
+
|
|
765
|
+
slice_memviewslice(
|
|
766
|
+
p_dst, p_src.shape[dim], p_src.strides[dim], p_src.suboffsets[dim],
|
|
767
|
+
dim, new_ndim, p_suboffset_dim,
|
|
768
|
+
start, stop, step,
|
|
769
|
+
have_start, have_stop, have_step,
|
|
770
|
+
True)
|
|
771
|
+
new_ndim += 1
|
|
772
|
+
|
|
773
|
+
if isinstance(memview, _memoryviewslice):
|
|
774
|
+
return memoryview_fromslice(dst, new_ndim,
|
|
775
|
+
memviewsliceobj.to_object_func,
|
|
776
|
+
memviewsliceobj.to_dtype_func,
|
|
777
|
+
memview.dtype_is_object)
|
|
778
|
+
else:
|
|
779
|
+
return memoryview_fromslice(dst, new_ndim, NULL, NULL,
|
|
780
|
+
memview.dtype_is_object)
|
|
781
|
+
|
|
782
|
+
|
|
783
|
+
#
|
|
784
|
+
### Slicing in a single dimension of a memoryviewslice
|
|
785
|
+
#
|
|
786
|
+
|
|
787
|
+
@cname('__pyx_memoryview_slice_memviewslice')
|
|
788
|
+
cdef int slice_memviewslice(
|
|
789
|
+
{{memviewslice_name}} *dst,
|
|
790
|
+
Py_ssize_t shape, Py_ssize_t stride, Py_ssize_t suboffset,
|
|
791
|
+
int dim, int new_ndim, int *suboffset_dim,
|
|
792
|
+
Py_ssize_t start, Py_ssize_t stop, Py_ssize_t step,
|
|
793
|
+
int have_start, int have_stop, int have_step,
|
|
794
|
+
bint is_slice) except -1 nogil:
|
|
795
|
+
"""
|
|
796
|
+
Create a new slice dst given slice src.
|
|
797
|
+
|
|
798
|
+
dim - the current src dimension (indexing will make dimensions
|
|
799
|
+
disappear)
|
|
800
|
+
new_dim - the new dst dimension
|
|
801
|
+
suboffset_dim - pointer to a single int initialized to -1 to keep track of
|
|
802
|
+
where slicing offsets should be added
|
|
803
|
+
"""
|
|
804
|
+
|
|
805
|
+
cdef Py_ssize_t new_shape
|
|
806
|
+
cdef bint negative_step
|
|
807
|
+
|
|
808
|
+
if not is_slice:
|
|
809
|
+
# index is a normal integer-like index
|
|
810
|
+
if start < 0:
|
|
811
|
+
start += shape
|
|
812
|
+
if not 0 <= start < shape:
|
|
813
|
+
_err_dim(PyExc_IndexError, "Index out of bounds (axis %d)", dim)
|
|
814
|
+
else:
|
|
815
|
+
# index is a slice
|
|
816
|
+
if have_step:
|
|
817
|
+
negative_step = step < 0
|
|
818
|
+
if step == 0:
|
|
819
|
+
_err_dim(PyExc_ValueError, "Step may not be zero (axis %d)", dim)
|
|
820
|
+
else:
|
|
821
|
+
negative_step = False
|
|
822
|
+
step = 1
|
|
823
|
+
|
|
824
|
+
# check our bounds and set defaults
|
|
825
|
+
if have_start:
|
|
826
|
+
if start < 0:
|
|
827
|
+
start += shape
|
|
828
|
+
if start < 0:
|
|
829
|
+
start = 0
|
|
830
|
+
elif start >= shape:
|
|
831
|
+
if negative_step:
|
|
832
|
+
start = shape - 1
|
|
833
|
+
else:
|
|
834
|
+
start = shape
|
|
835
|
+
else:
|
|
836
|
+
if negative_step:
|
|
837
|
+
start = shape - 1
|
|
838
|
+
else:
|
|
839
|
+
start = 0
|
|
840
|
+
|
|
841
|
+
if have_stop:
|
|
842
|
+
if stop < 0:
|
|
843
|
+
stop += shape
|
|
844
|
+
if stop < 0:
|
|
845
|
+
stop = 0
|
|
846
|
+
elif stop > shape:
|
|
847
|
+
stop = shape
|
|
848
|
+
else:
|
|
849
|
+
if negative_step:
|
|
850
|
+
stop = -1
|
|
851
|
+
else:
|
|
852
|
+
stop = shape
|
|
853
|
+
|
|
854
|
+
# len = ceil( (stop - start) / step )
|
|
855
|
+
with cython.cdivision(True):
|
|
856
|
+
new_shape = (stop - start) // step
|
|
857
|
+
|
|
858
|
+
if (stop - start) - step * new_shape:
|
|
859
|
+
new_shape += 1
|
|
860
|
+
|
|
861
|
+
if new_shape < 0:
|
|
862
|
+
new_shape = 0
|
|
863
|
+
|
|
864
|
+
# shape/strides/suboffsets
|
|
865
|
+
dst.strides[new_ndim] = stride * step
|
|
866
|
+
dst.shape[new_ndim] = new_shape
|
|
867
|
+
dst.suboffsets[new_ndim] = suboffset
|
|
868
|
+
|
|
869
|
+
# Add the slicing or indexing offsets to the right suboffset or base data *
|
|
870
|
+
if suboffset_dim[0] < 0:
|
|
871
|
+
dst.data += start * stride
|
|
872
|
+
else:
|
|
873
|
+
dst.suboffsets[suboffset_dim[0]] += start * stride
|
|
874
|
+
|
|
875
|
+
if suboffset >= 0:
|
|
876
|
+
if not is_slice:
|
|
877
|
+
if new_ndim == 0:
|
|
878
|
+
dst.data = (<char **> dst.data)[0] + suboffset
|
|
879
|
+
else:
|
|
880
|
+
_err_dim(PyExc_IndexError, "All dimensions preceding dimension %d "
|
|
881
|
+
"must be indexed and not sliced", dim)
|
|
882
|
+
else:
|
|
883
|
+
suboffset_dim[0] = new_ndim
|
|
884
|
+
|
|
885
|
+
return 0
|
|
886
|
+
|
|
887
|
+
#
|
|
888
|
+
### Index a memoryview
|
|
889
|
+
#
|
|
890
|
+
@cname('__pyx_pybuffer_index')
|
|
891
|
+
cdef char *pybuffer_index(Py_buffer *view, char *bufp, Py_ssize_t index,
|
|
892
|
+
Py_ssize_t dim) except NULL:
|
|
893
|
+
cdef Py_ssize_t shape, stride, suboffset = -1
|
|
894
|
+
cdef Py_ssize_t itemsize = view.itemsize
|
|
895
|
+
cdef char *resultp
|
|
896
|
+
|
|
897
|
+
if view.ndim == 0:
|
|
898
|
+
shape = view.len // itemsize
|
|
899
|
+
stride = itemsize
|
|
900
|
+
else:
|
|
901
|
+
shape = view.shape[dim]
|
|
902
|
+
stride = view.strides[dim]
|
|
903
|
+
if view.suboffsets != NULL:
|
|
904
|
+
suboffset = view.suboffsets[dim]
|
|
905
|
+
|
|
906
|
+
if index < 0:
|
|
907
|
+
index += view.shape[dim]
|
|
908
|
+
if index < 0:
|
|
909
|
+
raise IndexError, f"Out of bounds on buffer access (axis {dim})"
|
|
910
|
+
|
|
911
|
+
if index >= shape:
|
|
912
|
+
raise IndexError, f"Out of bounds on buffer access (axis {dim})"
|
|
913
|
+
|
|
914
|
+
resultp = bufp + index * stride
|
|
915
|
+
if suboffset >= 0:
|
|
916
|
+
resultp = (<char **> resultp)[0] + suboffset
|
|
917
|
+
|
|
918
|
+
return resultp
|
|
919
|
+
|
|
920
|
+
#
|
|
921
|
+
### Transposing a memoryviewslice
|
|
922
|
+
#
|
|
923
|
+
@cname('__pyx_memslice_transpose')
|
|
924
|
+
cdef int transpose_memslice({{memviewslice_name}} *memslice) except -1 nogil:
|
|
925
|
+
cdef int ndim = memslice.memview.view.ndim
|
|
926
|
+
|
|
927
|
+
cdef Py_ssize_t *shape = memslice.shape
|
|
928
|
+
cdef Py_ssize_t *strides = memslice.strides
|
|
929
|
+
|
|
930
|
+
# reverse strides and shape
|
|
931
|
+
cdef int i, j
|
|
932
|
+
for i in range(ndim // 2):
|
|
933
|
+
j = ndim - 1 - i
|
|
934
|
+
strides[i], strides[j] = strides[j], strides[i]
|
|
935
|
+
shape[i], shape[j] = shape[j], shape[i]
|
|
936
|
+
|
|
937
|
+
if memslice.suboffsets[i] >= 0 or memslice.suboffsets[j] >= 0:
|
|
938
|
+
_err(PyExc_ValueError, "Cannot transpose memoryview with indirect dimensions")
|
|
939
|
+
|
|
940
|
+
return 0
|
|
941
|
+
|
|
942
|
+
#
|
|
943
|
+
### Creating new memoryview objects from slices and memoryviews
|
|
944
|
+
#
|
|
945
|
+
@cython.collection_type("sequence")
|
|
946
|
+
@cname('__pyx_memoryviewslice')
|
|
947
|
+
cdef class _memoryviewslice(memoryview):
|
|
948
|
+
"Internal class for passing memoryview slices to Python"
|
|
949
|
+
|
|
950
|
+
# We need this to keep our shape/strides/suboffset pointers valid
|
|
951
|
+
cdef {{memviewslice_name}} from_slice
|
|
952
|
+
# We need this only to print it's class' name
|
|
953
|
+
cdef object from_object
|
|
954
|
+
|
|
955
|
+
cdef object (*to_object_func)(char *)
|
|
956
|
+
cdef int (*to_dtype_func)(char *, object) except 0
|
|
957
|
+
|
|
958
|
+
def __dealloc__(self):
|
|
959
|
+
__PYX_XCLEAR_MEMVIEW(&self.from_slice, 1)
|
|
960
|
+
|
|
961
|
+
cdef convert_item_to_object(self, char *itemp):
|
|
962
|
+
if self.to_object_func != NULL:
|
|
963
|
+
return self.to_object_func(itemp)
|
|
964
|
+
else:
|
|
965
|
+
return memoryview.convert_item_to_object(self, itemp)
|
|
966
|
+
|
|
967
|
+
cdef assign_item_from_object(self, char *itemp, object value):
|
|
968
|
+
if self.to_dtype_func != NULL:
|
|
969
|
+
self.to_dtype_func(itemp, value)
|
|
970
|
+
else:
|
|
971
|
+
memoryview.assign_item_from_object(self, itemp, value)
|
|
972
|
+
|
|
973
|
+
cdef _get_base(self):
|
|
974
|
+
return self.from_object
|
|
975
|
+
|
|
976
|
+
# Sequence methods
|
|
977
|
+
try:
|
|
978
|
+
count = __pyx_collections_abc_Sequence.count
|
|
979
|
+
index = __pyx_collections_abc_Sequence.index
|
|
980
|
+
except:
|
|
981
|
+
pass
|
|
982
|
+
|
|
983
|
+
try:
|
|
984
|
+
if __pyx_collections_abc_Sequence:
|
|
985
|
+
# The main value of registering _memoryviewslice as a
|
|
986
|
+
# Sequence is that it can be used in structural pattern
|
|
987
|
+
# matching in Python 3.10+
|
|
988
|
+
__pyx_collections_abc_Sequence.register(_memoryviewslice)
|
|
989
|
+
__pyx_collections_abc_Sequence.register(array)
|
|
990
|
+
except:
|
|
991
|
+
pass # ignore failure, it's a minor issue
|
|
992
|
+
|
|
993
|
+
@cname('__pyx_memoryview_fromslice')
|
|
994
|
+
cdef memoryview_fromslice({{memviewslice_name}} memviewslice,
|
|
995
|
+
int ndim,
|
|
996
|
+
object (*to_object_func)(char *),
|
|
997
|
+
int (*to_dtype_func)(char *, object) except 0,
|
|
998
|
+
bint dtype_is_object):
|
|
999
|
+
|
|
1000
|
+
cdef _memoryviewslice result
|
|
1001
|
+
|
|
1002
|
+
if <PyObject *> memviewslice.memview == Py_None:
|
|
1003
|
+
return None
|
|
1004
|
+
|
|
1005
|
+
# assert 0 < ndim <= memviewslice.memview.view.ndim, (
|
|
1006
|
+
# ndim, memviewslice.memview.view.ndim)
|
|
1007
|
+
|
|
1008
|
+
result = _memoryviewslice.__new__(_memoryviewslice, None, 0, dtype_is_object)
|
|
1009
|
+
|
|
1010
|
+
result.from_slice = memviewslice
|
|
1011
|
+
__PYX_INC_MEMVIEW(&memviewslice, 1)
|
|
1012
|
+
|
|
1013
|
+
result.from_object = (<memoryview> memviewslice.memview)._get_base()
|
|
1014
|
+
result.typeinfo = memviewslice.memview.typeinfo
|
|
1015
|
+
|
|
1016
|
+
result.view = memviewslice.memview.view
|
|
1017
|
+
result.view.buf = <void *> memviewslice.data
|
|
1018
|
+
result.view.ndim = ndim
|
|
1019
|
+
(<__pyx_buffer *> &result.view).obj = Py_None
|
|
1020
|
+
Py_INCREF(Py_None)
|
|
1021
|
+
|
|
1022
|
+
if (<memoryview>memviewslice.memview).flags & PyBUF_WRITABLE:
|
|
1023
|
+
result.flags = PyBUF_RECORDS
|
|
1024
|
+
else:
|
|
1025
|
+
result.flags = PyBUF_RECORDS_RO
|
|
1026
|
+
|
|
1027
|
+
result.view.shape = <Py_ssize_t *> result.from_slice.shape
|
|
1028
|
+
result.view.strides = <Py_ssize_t *> result.from_slice.strides
|
|
1029
|
+
|
|
1030
|
+
# only set suboffsets if actually used, otherwise set to NULL to improve compatibility
|
|
1031
|
+
result.view.suboffsets = NULL
|
|
1032
|
+
for suboffset in result.from_slice.suboffsets[:ndim]:
|
|
1033
|
+
if suboffset >= 0:
|
|
1034
|
+
result.view.suboffsets = <Py_ssize_t *> result.from_slice.suboffsets
|
|
1035
|
+
break
|
|
1036
|
+
|
|
1037
|
+
result.view.len = result.view.itemsize
|
|
1038
|
+
for length in result.view.shape[:ndim]:
|
|
1039
|
+
result.view.len *= length
|
|
1040
|
+
|
|
1041
|
+
result.to_object_func = to_object_func
|
|
1042
|
+
result.to_dtype_func = to_dtype_func
|
|
1043
|
+
|
|
1044
|
+
return result
|
|
1045
|
+
|
|
1046
|
+
@cname('__pyx_memoryview_get_slice_from_memoryview')
|
|
1047
|
+
cdef {{memviewslice_name}} *get_slice_from_memview(memoryview memview,
|
|
1048
|
+
{{memviewslice_name}} *mslice) except NULL:
|
|
1049
|
+
cdef _memoryviewslice obj
|
|
1050
|
+
if isinstance(memview, _memoryviewslice):
|
|
1051
|
+
obj = memview
|
|
1052
|
+
return &obj.from_slice
|
|
1053
|
+
else:
|
|
1054
|
+
slice_copy(memview, mslice)
|
|
1055
|
+
return mslice
|
|
1056
|
+
|
|
1057
|
+
@cname('__pyx_memoryview_slice_copy')
|
|
1058
|
+
cdef void slice_copy(memoryview memview, {{memviewslice_name}} *dst) noexcept:
|
|
1059
|
+
cdef int dim
|
|
1060
|
+
cdef (Py_ssize_t*) shape, strides, suboffsets
|
|
1061
|
+
|
|
1062
|
+
shape = memview.view.shape
|
|
1063
|
+
strides = memview.view.strides
|
|
1064
|
+
suboffsets = memview.view.suboffsets
|
|
1065
|
+
|
|
1066
|
+
dst.memview = <__pyx_memoryview *> memview
|
|
1067
|
+
dst.data = <char *> memview.view.buf
|
|
1068
|
+
|
|
1069
|
+
for dim in range(memview.view.ndim):
|
|
1070
|
+
dst.shape[dim] = shape[dim]
|
|
1071
|
+
dst.strides[dim] = strides[dim]
|
|
1072
|
+
dst.suboffsets[dim] = suboffsets[dim] if suboffsets else -1
|
|
1073
|
+
|
|
1074
|
+
@cname('__pyx_memoryview_copy_object')
|
|
1075
|
+
cdef memoryview_copy(memoryview memview):
|
|
1076
|
+
"Create a new memoryview object"
|
|
1077
|
+
cdef {{memviewslice_name}} memviewslice
|
|
1078
|
+
slice_copy(memview, &memviewslice)
|
|
1079
|
+
return memoryview_copy_from_slice(memview, &memviewslice)
|
|
1080
|
+
|
|
1081
|
+
@cname('__pyx_memoryview_copy_object_from_slice')
|
|
1082
|
+
cdef memoryview_copy_from_slice(memoryview memview, {{memviewslice_name}} *memviewslice):
|
|
1083
|
+
"""
|
|
1084
|
+
Create a new memoryview object from a given memoryview object and slice.
|
|
1085
|
+
"""
|
|
1086
|
+
cdef object (*to_object_func)(char *)
|
|
1087
|
+
cdef int (*to_dtype_func)(char *, object) except 0
|
|
1088
|
+
|
|
1089
|
+
if isinstance(memview, _memoryviewslice):
|
|
1090
|
+
to_object_func = (<_memoryviewslice> memview).to_object_func
|
|
1091
|
+
to_dtype_func = (<_memoryviewslice> memview).to_dtype_func
|
|
1092
|
+
else:
|
|
1093
|
+
to_object_func = NULL
|
|
1094
|
+
to_dtype_func = NULL
|
|
1095
|
+
|
|
1096
|
+
return memoryview_fromslice(memviewslice[0], memview.view.ndim,
|
|
1097
|
+
to_object_func, to_dtype_func,
|
|
1098
|
+
memview.dtype_is_object)
|
|
1099
|
+
|
|
1100
|
+
|
|
1101
|
+
#
|
|
1102
|
+
### Copy the contents of a memoryview slices
|
|
1103
|
+
#
|
|
1104
|
+
cdef Py_ssize_t abs_py_ssize_t(Py_ssize_t arg) noexcept nogil:
|
|
1105
|
+
return -arg if arg < 0 else arg
|
|
1106
|
+
|
|
1107
|
+
@cname('__pyx_get_best_slice_order')
|
|
1108
|
+
cdef char get_best_order({{memviewslice_name}} *mslice, int ndim) noexcept nogil:
|
|
1109
|
+
"""
|
|
1110
|
+
Figure out the best memory access order for a given slice.
|
|
1111
|
+
"""
|
|
1112
|
+
cdef int i
|
|
1113
|
+
cdef Py_ssize_t c_stride = 0
|
|
1114
|
+
cdef Py_ssize_t f_stride = 0
|
|
1115
|
+
|
|
1116
|
+
for i in range(ndim - 1, -1, -1):
|
|
1117
|
+
if mslice.shape[i] > 1:
|
|
1118
|
+
c_stride = mslice.strides[i]
|
|
1119
|
+
break
|
|
1120
|
+
|
|
1121
|
+
for i in range(ndim):
|
|
1122
|
+
if mslice.shape[i] > 1:
|
|
1123
|
+
f_stride = mslice.strides[i]
|
|
1124
|
+
break
|
|
1125
|
+
|
|
1126
|
+
if abs_py_ssize_t(c_stride) <= abs_py_ssize_t(f_stride):
|
|
1127
|
+
return 'C'
|
|
1128
|
+
else:
|
|
1129
|
+
return 'F'
|
|
1130
|
+
|
|
1131
|
+
@cython.cdivision(True)
|
|
1132
|
+
cdef void _copy_strided_to_strided(char *src_data, Py_ssize_t *src_strides,
|
|
1133
|
+
char *dst_data, Py_ssize_t *dst_strides,
|
|
1134
|
+
Py_ssize_t *src_shape, Py_ssize_t *dst_shape,
|
|
1135
|
+
int ndim, size_t itemsize) noexcept nogil:
|
|
1136
|
+
# Note: src_extent is 1 if we're broadcasting
|
|
1137
|
+
# dst_extent always >= src_extent as we don't do reductions
|
|
1138
|
+
cdef Py_ssize_t i
|
|
1139
|
+
cdef Py_ssize_t src_extent = src_shape[0]
|
|
1140
|
+
cdef Py_ssize_t dst_extent = dst_shape[0]
|
|
1141
|
+
cdef Py_ssize_t src_stride = src_strides[0]
|
|
1142
|
+
cdef Py_ssize_t dst_stride = dst_strides[0]
|
|
1143
|
+
|
|
1144
|
+
if ndim == 1:
|
|
1145
|
+
if (src_stride > 0 and dst_stride > 0 and
|
|
1146
|
+
<size_t> src_stride == itemsize == <size_t> dst_stride):
|
|
1147
|
+
memcpy(dst_data, src_data, itemsize * dst_extent)
|
|
1148
|
+
else:
|
|
1149
|
+
for i in range(dst_extent):
|
|
1150
|
+
memcpy(dst_data, src_data, itemsize)
|
|
1151
|
+
src_data += src_stride
|
|
1152
|
+
dst_data += dst_stride
|
|
1153
|
+
else:
|
|
1154
|
+
for i in range(dst_extent):
|
|
1155
|
+
_copy_strided_to_strided(src_data, src_strides + 1,
|
|
1156
|
+
dst_data, dst_strides + 1,
|
|
1157
|
+
src_shape + 1, dst_shape + 1,
|
|
1158
|
+
ndim - 1, itemsize)
|
|
1159
|
+
src_data += src_stride
|
|
1160
|
+
dst_data += dst_stride
|
|
1161
|
+
|
|
1162
|
+
cdef void copy_strided_to_strided({{memviewslice_name}} *src,
|
|
1163
|
+
{{memviewslice_name}} *dst,
|
|
1164
|
+
int ndim, size_t itemsize) noexcept nogil:
|
|
1165
|
+
_copy_strided_to_strided(src.data, src.strides, dst.data, dst.strides,
|
|
1166
|
+
src.shape, dst.shape, ndim, itemsize)
|
|
1167
|
+
|
|
1168
|
+
@cname('__pyx_memoryview_slice_get_size')
|
|
1169
|
+
cdef Py_ssize_t slice_get_size({{memviewslice_name}} *src, int ndim) noexcept nogil:
|
|
1170
|
+
"Return the size of the memory occupied by the slice in number of bytes"
|
|
1171
|
+
cdef Py_ssize_t shape, size = src.memview.view.itemsize
|
|
1172
|
+
|
|
1173
|
+
for shape in src.shape[:ndim]:
|
|
1174
|
+
size *= shape
|
|
1175
|
+
|
|
1176
|
+
return size
|
|
1177
|
+
|
|
1178
|
+
@cname('__pyx_fill_contig_strides_array')
|
|
1179
|
+
cdef Py_ssize_t fill_contig_strides_array(
|
|
1180
|
+
Py_ssize_t *shape, Py_ssize_t *strides, Py_ssize_t stride,
|
|
1181
|
+
int ndim, char order) noexcept nogil:
|
|
1182
|
+
"""
|
|
1183
|
+
Fill the strides array for a slice with C or F contiguous strides.
|
|
1184
|
+
This is like PyBuffer_FillContiguousStrides, but compatible with py < 2.6
|
|
1185
|
+
"""
|
|
1186
|
+
cdef int idx
|
|
1187
|
+
|
|
1188
|
+
if order == 'F':
|
|
1189
|
+
for idx in range(ndim):
|
|
1190
|
+
strides[idx] = stride
|
|
1191
|
+
stride *= shape[idx]
|
|
1192
|
+
else:
|
|
1193
|
+
for idx in range(ndim - 1, -1, -1):
|
|
1194
|
+
strides[idx] = stride
|
|
1195
|
+
stride *= shape[idx]
|
|
1196
|
+
|
|
1197
|
+
return stride
|
|
1198
|
+
|
|
1199
|
+
@cname('__pyx_memoryview_copy_data_to_temp')
|
|
1200
|
+
cdef void *copy_data_to_temp({{memviewslice_name}} *src,
|
|
1201
|
+
{{memviewslice_name}} *tmpslice,
|
|
1202
|
+
char order,
|
|
1203
|
+
int ndim) except NULL nogil:
|
|
1204
|
+
"""
|
|
1205
|
+
Copy a direct slice to temporary contiguous memory. The caller should free
|
|
1206
|
+
the result when done.
|
|
1207
|
+
"""
|
|
1208
|
+
cdef int i
|
|
1209
|
+
cdef void *result
|
|
1210
|
+
|
|
1211
|
+
cdef size_t itemsize = src.memview.view.itemsize
|
|
1212
|
+
cdef size_t size = slice_get_size(src, ndim)
|
|
1213
|
+
|
|
1214
|
+
result = malloc(size)
|
|
1215
|
+
if not result:
|
|
1216
|
+
_err_no_memory()
|
|
1217
|
+
|
|
1218
|
+
# tmpslice[0] = src
|
|
1219
|
+
tmpslice.data = <char *> result
|
|
1220
|
+
tmpslice.memview = src.memview
|
|
1221
|
+
for i in range(ndim):
|
|
1222
|
+
tmpslice.shape[i] = src.shape[i]
|
|
1223
|
+
tmpslice.suboffsets[i] = -1
|
|
1224
|
+
|
|
1225
|
+
fill_contig_strides_array(&tmpslice.shape[0], &tmpslice.strides[0], itemsize, ndim, order)
|
|
1226
|
+
|
|
1227
|
+
# We need to broadcast strides again
|
|
1228
|
+
for i in range(ndim):
|
|
1229
|
+
if tmpslice.shape[i] == 1:
|
|
1230
|
+
tmpslice.strides[i] = 0
|
|
1231
|
+
|
|
1232
|
+
if slice_is_contig(src[0], order, ndim):
|
|
1233
|
+
memcpy(result, src.data, size)
|
|
1234
|
+
else:
|
|
1235
|
+
copy_strided_to_strided(src, tmpslice, ndim, itemsize)
|
|
1236
|
+
|
|
1237
|
+
return result
|
|
1238
|
+
|
|
1239
|
+
# Use 'with gil' functions and avoid 'with gil' blocks, as the code within the blocks
|
|
1240
|
+
# has temporaries that need the GIL to clean up
|
|
1241
|
+
@cname('__pyx_memoryview_err_extents')
|
|
1242
|
+
cdef int _err_extents(int i, Py_ssize_t extent1,
|
|
1243
|
+
Py_ssize_t extent2) except -1 with gil:
|
|
1244
|
+
raise ValueError, f"got differing extents in dimension {i} (got {extent1} and {extent2})"
|
|
1245
|
+
|
|
1246
|
+
@cname('__pyx_memoryview_err_dim')
|
|
1247
|
+
cdef int _err_dim(PyObject *error, str msg, int dim) except -1 with gil:
|
|
1248
|
+
raise <object>error, msg % dim
|
|
1249
|
+
|
|
1250
|
+
@cname('__pyx_memoryview_err')
|
|
1251
|
+
cdef int _err(PyObject *error, str msg) except -1 with gil:
|
|
1252
|
+
raise <object>error, msg
|
|
1253
|
+
|
|
1254
|
+
@cname('__pyx_memoryview_err_no_memory')
|
|
1255
|
+
cdef int _err_no_memory() except -1 with gil:
|
|
1256
|
+
raise MemoryError
|
|
1257
|
+
|
|
1258
|
+
|
|
1259
|
+
@cname('__pyx_memoryview_copy_contents')
|
|
1260
|
+
cdef int memoryview_copy_contents({{memviewslice_name}} src,
|
|
1261
|
+
{{memviewslice_name}} dst,
|
|
1262
|
+
int src_ndim, int dst_ndim,
|
|
1263
|
+
bint dtype_is_object) except -1 nogil:
|
|
1264
|
+
"""
|
|
1265
|
+
Copy memory from slice src to slice dst.
|
|
1266
|
+
Check for overlapping memory and verify the shapes.
|
|
1267
|
+
"""
|
|
1268
|
+
cdef void *tmpdata = NULL
|
|
1269
|
+
cdef size_t itemsize = src.memview.view.itemsize
|
|
1270
|
+
cdef int i
|
|
1271
|
+
cdef char order = get_best_order(&src, src_ndim)
|
|
1272
|
+
cdef bint broadcasting = False
|
|
1273
|
+
cdef bint direct_copy = False
|
|
1274
|
+
cdef {{memviewslice_name}} tmp
|
|
1275
|
+
|
|
1276
|
+
if src_ndim < dst_ndim:
|
|
1277
|
+
broadcast_leading(&src, src_ndim, dst_ndim)
|
|
1278
|
+
elif dst_ndim < src_ndim:
|
|
1279
|
+
broadcast_leading(&dst, dst_ndim, src_ndim)
|
|
1280
|
+
|
|
1281
|
+
cdef int ndim = max(src_ndim, dst_ndim)
|
|
1282
|
+
|
|
1283
|
+
for i in range(ndim):
|
|
1284
|
+
if src.shape[i] != dst.shape[i]:
|
|
1285
|
+
if src.shape[i] == 1:
|
|
1286
|
+
broadcasting = True
|
|
1287
|
+
src.strides[i] = 0
|
|
1288
|
+
else:
|
|
1289
|
+
_err_extents(i, dst.shape[i], src.shape[i])
|
|
1290
|
+
|
|
1291
|
+
if src.suboffsets[i] >= 0:
|
|
1292
|
+
_err_dim(PyExc_ValueError, "Dimension %d is not direct", i)
|
|
1293
|
+
|
|
1294
|
+
if slices_overlap(&src, &dst, ndim, itemsize):
|
|
1295
|
+
# slices overlap, copy to temp, copy temp to dst
|
|
1296
|
+
if not slice_is_contig(src, order, ndim):
|
|
1297
|
+
order = get_best_order(&dst, ndim)
|
|
1298
|
+
|
|
1299
|
+
tmpdata = copy_data_to_temp(&src, &tmp, order, ndim)
|
|
1300
|
+
src = tmp
|
|
1301
|
+
|
|
1302
|
+
if not broadcasting:
|
|
1303
|
+
# See if both slices have equal contiguity, in that case perform a
|
|
1304
|
+
# direct copy. This only works when we are not broadcasting.
|
|
1305
|
+
if slice_is_contig(src, 'C', ndim):
|
|
1306
|
+
direct_copy = slice_is_contig(dst, 'C', ndim)
|
|
1307
|
+
elif slice_is_contig(src, 'F', ndim):
|
|
1308
|
+
direct_copy = slice_is_contig(dst, 'F', ndim)
|
|
1309
|
+
|
|
1310
|
+
if direct_copy:
|
|
1311
|
+
# Contiguous slices with same order
|
|
1312
|
+
refcount_copying(&dst, dtype_is_object, ndim, inc=False)
|
|
1313
|
+
memcpy(dst.data, src.data, slice_get_size(&src, ndim))
|
|
1314
|
+
refcount_copying(&dst, dtype_is_object, ndim, inc=True)
|
|
1315
|
+
free(tmpdata)
|
|
1316
|
+
return 0
|
|
1317
|
+
|
|
1318
|
+
if order == 'F' == get_best_order(&dst, ndim):
|
|
1319
|
+
# see if both slices have Fortran order, transpose them to match our
|
|
1320
|
+
# C-style indexing order
|
|
1321
|
+
transpose_memslice(&src)
|
|
1322
|
+
transpose_memslice(&dst)
|
|
1323
|
+
|
|
1324
|
+
refcount_copying(&dst, dtype_is_object, ndim, inc=False)
|
|
1325
|
+
copy_strided_to_strided(&src, &dst, ndim, itemsize)
|
|
1326
|
+
refcount_copying(&dst, dtype_is_object, ndim, inc=True)
|
|
1327
|
+
|
|
1328
|
+
free(tmpdata)
|
|
1329
|
+
return 0
|
|
1330
|
+
|
|
1331
|
+
@cname('__pyx_memoryview_broadcast_leading')
|
|
1332
|
+
cdef void broadcast_leading({{memviewslice_name}} *mslice,
|
|
1333
|
+
int ndim,
|
|
1334
|
+
int ndim_other) noexcept nogil:
|
|
1335
|
+
cdef int i
|
|
1336
|
+
cdef int offset = ndim_other - ndim
|
|
1337
|
+
|
|
1338
|
+
for i in range(ndim - 1, -1, -1):
|
|
1339
|
+
mslice.shape[i + offset] = mslice.shape[i]
|
|
1340
|
+
mslice.strides[i + offset] = mslice.strides[i]
|
|
1341
|
+
mslice.suboffsets[i + offset] = mslice.suboffsets[i]
|
|
1342
|
+
|
|
1343
|
+
for i in range(offset):
|
|
1344
|
+
mslice.shape[i] = 1
|
|
1345
|
+
mslice.strides[i] = mslice.strides[0]
|
|
1346
|
+
mslice.suboffsets[i] = -1
|
|
1347
|
+
|
|
1348
|
+
#
|
|
1349
|
+
### Take care of refcounting the objects in slices. Do this separately from any copying,
|
|
1350
|
+
### to minimize acquiring the GIL
|
|
1351
|
+
#
|
|
1352
|
+
|
|
1353
|
+
@cname('__pyx_memoryview_refcount_copying')
|
|
1354
|
+
cdef void refcount_copying({{memviewslice_name}} *dst, bint dtype_is_object, int ndim, bint inc) noexcept nogil:
|
|
1355
|
+
# incref or decref the objects in the destination slice if the dtype is object
|
|
1356
|
+
if dtype_is_object:
|
|
1357
|
+
refcount_objects_in_slice_with_gil(dst.data, dst.shape, dst.strides, ndim, inc)
|
|
1358
|
+
|
|
1359
|
+
@cname('__pyx_memoryview_refcount_objects_in_slice_with_gil')
|
|
1360
|
+
cdef void refcount_objects_in_slice_with_gil(char *data, Py_ssize_t *shape,
|
|
1361
|
+
Py_ssize_t *strides, int ndim,
|
|
1362
|
+
bint inc) noexcept with gil:
|
|
1363
|
+
refcount_objects_in_slice(data, shape, strides, ndim, inc)
|
|
1364
|
+
|
|
1365
|
+
@cname('__pyx_memoryview_refcount_objects_in_slice')
|
|
1366
|
+
cdef void refcount_objects_in_slice(char *data, Py_ssize_t *shape,
|
|
1367
|
+
Py_ssize_t *strides, int ndim, bint inc) noexcept:
|
|
1368
|
+
cdef Py_ssize_t i
|
|
1369
|
+
cdef Py_ssize_t stride = strides[0]
|
|
1370
|
+
|
|
1371
|
+
for i in range(shape[0]):
|
|
1372
|
+
if ndim == 1:
|
|
1373
|
+
if inc:
|
|
1374
|
+
Py_INCREF((<PyObject **> data)[0])
|
|
1375
|
+
else:
|
|
1376
|
+
Py_DECREF((<PyObject **> data)[0])
|
|
1377
|
+
else:
|
|
1378
|
+
refcount_objects_in_slice(data, shape + 1, strides + 1, ndim - 1, inc)
|
|
1379
|
+
|
|
1380
|
+
data += stride
|
|
1381
|
+
|
|
1382
|
+
#
|
|
1383
|
+
### Scalar to slice assignment
|
|
1384
|
+
#
|
|
1385
|
+
@cname('__pyx_memoryview_slice_assign_scalar')
|
|
1386
|
+
cdef void slice_assign_scalar({{memviewslice_name}} *dst, int ndim,
|
|
1387
|
+
size_t itemsize, void *item,
|
|
1388
|
+
bint dtype_is_object) noexcept nogil:
|
|
1389
|
+
refcount_copying(dst, dtype_is_object, ndim, inc=False)
|
|
1390
|
+
_slice_assign_scalar(dst.data, dst.shape, dst.strides, ndim, itemsize, item)
|
|
1391
|
+
refcount_copying(dst, dtype_is_object, ndim, inc=True)
|
|
1392
|
+
|
|
1393
|
+
|
|
1394
|
+
@cname('__pyx_memoryview__slice_assign_scalar')
|
|
1395
|
+
cdef void _slice_assign_scalar(char *data, Py_ssize_t *shape,
|
|
1396
|
+
Py_ssize_t *strides, int ndim,
|
|
1397
|
+
size_t itemsize, void *item) noexcept nogil:
|
|
1398
|
+
cdef Py_ssize_t i
|
|
1399
|
+
cdef Py_ssize_t stride = strides[0]
|
|
1400
|
+
cdef Py_ssize_t extent = shape[0]
|
|
1401
|
+
|
|
1402
|
+
if ndim == 1:
|
|
1403
|
+
for i in range(extent):
|
|
1404
|
+
memcpy(data, item, itemsize)
|
|
1405
|
+
data += stride
|
|
1406
|
+
else:
|
|
1407
|
+
for i in range(extent):
|
|
1408
|
+
_slice_assign_scalar(data, shape + 1, strides + 1, ndim - 1, itemsize, item)
|
|
1409
|
+
data += stride
|
|
1410
|
+
|
|
1411
|
+
|
|
1412
|
+
############### BufferFormatFromTypeInfo ###############
|
|
1413
|
+
cdef extern from *:
|
|
1414
|
+
ctypedef struct __Pyx_StructField
|
|
1415
|
+
|
|
1416
|
+
cdef enum:
|
|
1417
|
+
__PYX_BUF_FLAGS_PACKED_STRUCT
|
|
1418
|
+
__PYX_BUF_FLAGS_INTEGER_COMPLEX
|
|
1419
|
+
|
|
1420
|
+
ctypedef struct __Pyx_TypeInfo:
|
|
1421
|
+
char* name
|
|
1422
|
+
const __Pyx_StructField* fields
|
|
1423
|
+
size_t size
|
|
1424
|
+
size_t arraysize[8]
|
|
1425
|
+
int ndim
|
|
1426
|
+
char typegroup
|
|
1427
|
+
char is_unsigned
|
|
1428
|
+
int flags
|
|
1429
|
+
|
|
1430
|
+
ctypedef struct __Pyx_StructField:
|
|
1431
|
+
const __Pyx_TypeInfo* type
|
|
1432
|
+
char* name
|
|
1433
|
+
size_t offset
|
|
1434
|
+
|
|
1435
|
+
ctypedef struct __Pyx_BufFmt_StackElem:
|
|
1436
|
+
const __Pyx_StructField* field
|
|
1437
|
+
size_t parent_offset
|
|
1438
|
+
|
|
1439
|
+
#ctypedef struct __Pyx_BufFmt_Context:
|
|
1440
|
+
# __Pyx_StructField root
|
|
1441
|
+
__Pyx_BufFmt_StackElem* head
|
|
1442
|
+
|
|
1443
|
+
struct __pyx_typeinfo_string:
|
|
1444
|
+
char string[3]
|
|
1445
|
+
|
|
1446
|
+
__pyx_typeinfo_string __Pyx_TypeInfoToFormat(const __Pyx_TypeInfo *)
|
|
1447
|
+
|
|
1448
|
+
|
|
1449
|
+
@cname('__pyx_format_from_typeinfo')
|
|
1450
|
+
cdef bytes format_from_typeinfo(const __Pyx_TypeInfo *type):
|
|
1451
|
+
cdef const __Pyx_StructField *field
|
|
1452
|
+
cdef __pyx_typeinfo_string fmt
|
|
1453
|
+
cdef bytes part, result
|
|
1454
|
+
cdef Py_ssize_t i
|
|
1455
|
+
|
|
1456
|
+
if type.typegroup == 'S':
|
|
1457
|
+
assert type.fields != NULL
|
|
1458
|
+
assert type.fields.type != NULL
|
|
1459
|
+
|
|
1460
|
+
if type.flags & __PYX_BUF_FLAGS_PACKED_STRUCT:
|
|
1461
|
+
alignment = b'^'
|
|
1462
|
+
else:
|
|
1463
|
+
alignment = b''
|
|
1464
|
+
|
|
1465
|
+
parts = [b"T{"]
|
|
1466
|
+
field = type.fields
|
|
1467
|
+
|
|
1468
|
+
while field.type:
|
|
1469
|
+
part = format_from_typeinfo(field.type)
|
|
1470
|
+
parts.append(part + b':' + field.name + b':')
|
|
1471
|
+
field += 1
|
|
1472
|
+
|
|
1473
|
+
result = alignment.join(parts) + b'}'
|
|
1474
|
+
else:
|
|
1475
|
+
fmt = __Pyx_TypeInfoToFormat(type)
|
|
1476
|
+
result = fmt.string
|
|
1477
|
+
if type.arraysize[0]:
|
|
1478
|
+
extents = [f"{type.arraysize[i]}" for i in range(type.ndim)]
|
|
1479
|
+
result = f"({u','.join(extents)})".encode('ascii') + result
|
|
1480
|
+
|
|
1481
|
+
return result
|