Videre
This commit is contained in:
@@ -0,0 +1,253 @@
|
||||
"""
|
||||
Expose top-level symbols that are safe for import *
|
||||
"""
|
||||
|
||||
import platform
|
||||
import re
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
|
||||
# ---------------------- WARNING WARNING WARNING ----------------------------
|
||||
# THIS MUST RUN FIRST, DO NOT MOVE... SEE DOCSTRING IN _ensure_critical_deps
|
||||
def _ensure_critical_deps():
|
||||
"""
|
||||
Make sure the Python, NumPy and SciPy present are supported versions.
|
||||
This has to be done _before_ importing anything from Numba such that
|
||||
incompatible versions can be reported to the user. If this occurs _after_
|
||||
importing things from Numba and there's an issue in e.g. a Numba c-ext, a
|
||||
SystemError might have occurred which prevents reporting the likely cause of
|
||||
the problem (incompatible versions of critical dependencies).
|
||||
"""
|
||||
#NOTE THIS CODE SHOULD NOT IMPORT ANYTHING FROM NUMBA!
|
||||
|
||||
def extract_version(mod):
|
||||
return tuple(map(int, mod.__version__.split('.')[:2]))
|
||||
|
||||
PYVERSION = sys.version_info[:2]
|
||||
|
||||
if PYVERSION < (3, 10):
|
||||
msg = ("Numba needs Python 3.10 or greater. Got Python "
|
||||
f"{PYVERSION[0]}.{PYVERSION[1]}.")
|
||||
raise ImportError(msg)
|
||||
|
||||
import numpy as np
|
||||
numpy_version = extract_version(np)
|
||||
|
||||
if numpy_version < (1, 22):
|
||||
msg = (f"Numba needs NumPy 1.22 or greater. Got NumPy "
|
||||
f"{numpy_version[0]}.{numpy_version[1]}.")
|
||||
raise ImportError(msg)
|
||||
|
||||
if numpy_version > (2, 4):
|
||||
msg = (f"Numba needs NumPy 2.4 or less. Got NumPy "
|
||||
f"{numpy_version[0]}.{numpy_version[1]}.")
|
||||
raise ImportError(msg)
|
||||
|
||||
try:
|
||||
import scipy
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
sp_version = extract_version(scipy)
|
||||
if sp_version < (1, 0):
|
||||
msg = ("Numba requires SciPy version 1.0 or greater. Got SciPy "
|
||||
f"{scipy.__version__}.")
|
||||
raise ImportError(msg)
|
||||
|
||||
|
||||
_ensure_critical_deps()
|
||||
# END DO NOT MOVE
|
||||
# ---------------------- WARNING WARNING WARNING ----------------------------
|
||||
|
||||
|
||||
from ._version import get_versions
|
||||
from numba.misc.init_utils import generate_version_info
|
||||
|
||||
__version__ = get_versions()['version']
|
||||
version_info = generate_version_info(__version__)
|
||||
del get_versions
|
||||
del generate_version_info
|
||||
|
||||
|
||||
from numba.core import config
|
||||
from numba.core import types, errors
|
||||
|
||||
# Re-export typeof
|
||||
from numba.misc.special import (
|
||||
typeof, prange, pndindex, gdb, gdb_breakpoint, gdb_init,
|
||||
literally, literal_unroll,
|
||||
)
|
||||
|
||||
# Re-export error classes
|
||||
from numba.core.errors import *
|
||||
|
||||
# Re-export types itself
|
||||
import numba.core.types as types
|
||||
|
||||
# Re-export all type names
|
||||
from numba.core.types import *
|
||||
|
||||
# Re-export decorators
|
||||
from numba.core.decorators import (cfunc, jit, njit, stencil,
|
||||
jit_module)
|
||||
|
||||
# Re-export vectorize decorators and the thread layer querying function
|
||||
from numba.np.ufunc import (vectorize, guvectorize, threading_layer,
|
||||
get_num_threads, set_num_threads,
|
||||
set_parallel_chunksize, get_parallel_chunksize,
|
||||
get_thread_id)
|
||||
|
||||
# Re-export Numpy helpers
|
||||
from numba.np.numpy_support import carray, farray, from_dtype
|
||||
|
||||
# Re-export experimental
|
||||
from numba import experimental
|
||||
|
||||
# Initialize withcontexts
|
||||
import numba.core.withcontexts
|
||||
from numba.core.withcontexts import objmode_context as objmode
|
||||
from numba.core.withcontexts import parallel_chunksize
|
||||
|
||||
# Initialize target extensions
|
||||
import numba.core.target_extension
|
||||
|
||||
# Initialize typed containers
|
||||
import numba.typed
|
||||
|
||||
# Keep this for backward compatibility.
|
||||
def test(argv, **kwds):
|
||||
# To speed up the import time, avoid importing `unittest` and other test
|
||||
# dependencies unless the user is actually trying to run tests.
|
||||
from numba.testing import _runtests as runtests
|
||||
return runtests.main(argv, **kwds)
|
||||
|
||||
__all__ = """
|
||||
cfunc
|
||||
from_dtype
|
||||
guvectorize
|
||||
jit
|
||||
experimental
|
||||
njit
|
||||
stencil
|
||||
jit_module
|
||||
typeof
|
||||
prange
|
||||
gdb
|
||||
gdb_breakpoint
|
||||
gdb_init
|
||||
vectorize
|
||||
objmode
|
||||
literal_unroll
|
||||
get_num_threads
|
||||
set_num_threads
|
||||
set_parallel_chunksize
|
||||
get_parallel_chunksize
|
||||
parallel_chunksize
|
||||
""".split() + types.__all__ + errors.__all__
|
||||
|
||||
|
||||
_min_llvmlite_version = (0, 47, 0)
|
||||
_min_llvm_version = (14, 0, 0)
|
||||
|
||||
def _ensure_llvm():
|
||||
"""
|
||||
Make sure llvmlite is operational.
|
||||
"""
|
||||
import warnings
|
||||
import llvmlite
|
||||
|
||||
# Only look at the major, minor and bugfix version numbers.
|
||||
# Ignore other stuffs
|
||||
regex = re.compile(r'(\d+)\.(\d+).(\d+)')
|
||||
m = regex.match(llvmlite.__version__)
|
||||
if m:
|
||||
ver = tuple(map(int, m.groups()))
|
||||
if ver < _min_llvmlite_version:
|
||||
msg = ("Numba requires at least version %d.%d.%d of llvmlite.\n"
|
||||
"Installed version is %s.\n"
|
||||
"Please update llvmlite." %
|
||||
(_min_llvmlite_version + (llvmlite.__version__,)))
|
||||
raise ImportError(msg)
|
||||
else:
|
||||
# Not matching?
|
||||
warnings.warn("llvmlite version format not recognized!")
|
||||
|
||||
from llvmlite.binding import llvm_version_info, check_jit_execution
|
||||
|
||||
if llvm_version_info < _min_llvm_version:
|
||||
msg = ("Numba requires at least version %d.%d.%d of LLVM.\n"
|
||||
"Installed llvmlite is built against version %d.%d.%d.\n"
|
||||
"Please update llvmlite." %
|
||||
(_min_llvm_version + llvm_version_info))
|
||||
raise ImportError(msg)
|
||||
|
||||
check_jit_execution()
|
||||
|
||||
|
||||
def _try_enable_svml():
|
||||
"""
|
||||
Tries to enable SVML if configuration permits use and the library is found.
|
||||
"""
|
||||
if not config.DISABLE_INTEL_SVML:
|
||||
try:
|
||||
if sys.platform.startswith('linux'):
|
||||
llvmlite.binding.load_library_permanently("libsvml.so")
|
||||
elif sys.platform.startswith('darwin'):
|
||||
llvmlite.binding.load_library_permanently("libsvml.dylib")
|
||||
elif sys.platform.startswith('win'):
|
||||
llvmlite.binding.load_library_permanently("svml_dispmd")
|
||||
else:
|
||||
return False
|
||||
# The SVML library is loaded, therefore SVML *could* be supported.
|
||||
# Now see if LLVM has been compiled with the SVML support patch.
|
||||
# If llvmlite has the checking function `has_svml` and it returns
|
||||
# True, then LLVM was compiled with SVML support and the setup
|
||||
# for SVML can proceed. We err on the side of caution and if the
|
||||
# checking function is missing, regardless of that being fine for
|
||||
# most 0.23.{0,1} llvmlite instances (i.e. conda or pip installed),
|
||||
# we assume that SVML was not compiled in. llvmlite 0.23.2 is a
|
||||
# bugfix release with the checking function present that will always
|
||||
# produce correct behaviour. For context see: #3006.
|
||||
try:
|
||||
if not getattr(llvmlite.binding.targets, "has_svml")():
|
||||
# has detection function, but no svml compiled in, therefore
|
||||
# disable SVML
|
||||
return False
|
||||
except AttributeError:
|
||||
if platform.machine() == 'x86_64' and config.DEBUG:
|
||||
msg = ("SVML was found but llvmlite >= 0.23.2 is "
|
||||
"needed to support it.")
|
||||
warnings.warn(msg)
|
||||
# does not have detection function, cannot detect reliably,
|
||||
# disable SVML.
|
||||
return False
|
||||
|
||||
# All is well, detection function present and reports SVML is
|
||||
# compiled in, set the vector library to SVML.
|
||||
llvmlite.binding.set_option('SVML', '-vector-library=SVML')
|
||||
return True
|
||||
except Exception:
|
||||
if platform.machine() == 'x86_64' and config.DEBUG:
|
||||
warnings.warn("SVML was not found/could not be loaded.")
|
||||
return False
|
||||
|
||||
_ensure_llvm()
|
||||
|
||||
# we know llvmlite is working as the above tests passed, import it now as SVML
|
||||
# needs to mutate runtime options (sets the `-vector-library`).
|
||||
import llvmlite
|
||||
|
||||
"""
|
||||
Is set to True if Intel SVML is in use.
|
||||
"""
|
||||
config.USING_SVML = _try_enable_svml()
|
||||
|
||||
|
||||
# ---------------------- WARNING WARNING WARNING ----------------------------
|
||||
# The following imports occur below here (SVML init) because somewhere in their
|
||||
# import sequence they have a `@njit` wrapped function. This triggers too early
|
||||
# a bind to the underlying LLVM libraries which then irretrievably sets the LLVM
|
||||
# SVML state to "no SVML". See https://github.com/numba/numba/issues/4689 for
|
||||
# context.
|
||||
# ---------------------- WARNING WARNING WARNING ----------------------------
|
||||
@@ -0,0 +1,6 @@
|
||||
"""Expose Numba command via ``python -m numba``."""
|
||||
import sys
|
||||
from numba.misc.numba_entry import main
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,21 @@
|
||||
#ifndef NUMBA_ARYSTRUCT_H_
|
||||
#define NUMBA_ARYSTRUCT_H_
|
||||
/*
|
||||
* Fill in the *arystruct* with information from the Numpy array *obj*.
|
||||
* *arystruct*'s layout is defined in numba.targets.arrayobj (look
|
||||
* for the ArrayTemplate class).
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
void *meminfo; /* see _nrt_python.c and nrt.h in numba/core/runtime */
|
||||
PyObject *parent;
|
||||
npy_intp nitems;
|
||||
npy_intp itemsize;
|
||||
void *data;
|
||||
|
||||
npy_intp shape_and_strides[];
|
||||
} arystruct_t;
|
||||
|
||||
|
||||
#endif /* NUMBA_ARYSTRUCT_H_ */
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
#ifndef NUMBA_DEVICEARRAY_H_
|
||||
#define NUMBA_DEVICEARRAY_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* These definitions should only be used by consumers of the Device Array API.
|
||||
* Consumers access the API through the opaque pointer stored in
|
||||
* _devicearray._DEVICEARRAY_API. We don't want these definitions in
|
||||
* _devicearray.cpp itself because they would conflict with the actual
|
||||
* implementations there.
|
||||
*/
|
||||
#ifndef NUMBA_IN_DEVICEARRAY_CPP_
|
||||
|
||||
extern void **DeviceArray_API;
|
||||
#define DeviceArrayType (*(PyTypeObject*)DeviceArray_API[0])
|
||||
|
||||
#endif /* ndef NUMBA_IN_DEVICEARRAY_CPP */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NUMBA_DEVICEARRAY_H_ */
|
||||
Binary file not shown.
552
linedance-app/venv/lib/python3.12/site-packages/numba/_dynfunc.c
Normal file
552
linedance-app/venv/lib/python3.12/site-packages/numba/_dynfunc.c
Normal file
@@ -0,0 +1,552 @@
|
||||
/*
|
||||
* Definition of Environment and Closure objects.
|
||||
* This module is included by _dynfuncmod.c and by pycc-compiled modules.
|
||||
*/
|
||||
|
||||
#include "_pymodule.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// if python version is 3.13
|
||||
#if ((PY_MAJOR_VERSION == 3) && ((PY_MINOR_VERSION == 13) || PY_MINOR_VERSION == 14))
|
||||
#include "pythoncapi_compat.h"
|
||||
#define _Py_IsFinalizing Py_IsFinalizing
|
||||
#endif
|
||||
/* NOTE: EnvironmentObject and ClosureObject must be kept in sync with
|
||||
* the definitions in numba/targets/base.py (EnvBody and ClosureBody).
|
||||
*/
|
||||
|
||||
/*
|
||||
* EnvironmentObject hosts data needed for execution of compiled functions.
|
||||
*/
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyObject *globals;
|
||||
/* Assorted "constants" that are needed at runtime to execute
|
||||
the compiled function. This can include frozen closure variables,
|
||||
lifted loops, etc. */
|
||||
PyObject *consts;
|
||||
} EnvironmentObject;
|
||||
|
||||
|
||||
static PyMemberDef env_members[] = {
|
||||
{"globals", T_OBJECT, offsetof(EnvironmentObject, globals), READONLY, NULL},
|
||||
{"consts", T_OBJECT, offsetof(EnvironmentObject, consts), READONLY, NULL},
|
||||
{NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
static int
|
||||
env_traverse(EnvironmentObject *env, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(env->globals);
|
||||
Py_VISIT(env->consts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
env_clear(EnvironmentObject *env)
|
||||
{
|
||||
Py_CLEAR(env->globals);
|
||||
Py_CLEAR(env->consts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
env_dealloc(EnvironmentObject *env)
|
||||
{
|
||||
PyObject_GC_UnTrack((PyObject *) env);
|
||||
env_clear(env);
|
||||
Py_TYPE(env)->tp_free((PyObject *) env);
|
||||
}
|
||||
|
||||
static EnvironmentObject *
|
||||
env_new_empty(PyTypeObject* type)
|
||||
{
|
||||
return (EnvironmentObject *) PyType_GenericNew(type, NULL, NULL);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
env_new(PyTypeObject* type, PyObject* args, PyObject* kwds)
|
||||
{
|
||||
PyObject *globals;
|
||||
EnvironmentObject *env;
|
||||
static char *kwlist[] = {"globals", 0};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(
|
||||
args, kwds, "O!:function", kwlist,
|
||||
&PyDict_Type, &globals))
|
||||
return NULL;
|
||||
|
||||
env = env_new_empty(type);
|
||||
if (env == NULL)
|
||||
return NULL;
|
||||
Py_INCREF(globals);
|
||||
env->globals = globals;
|
||||
env->consts = PyList_New(0);
|
||||
if (!env->consts) {
|
||||
Py_DECREF(env);
|
||||
return NULL;
|
||||
}
|
||||
return (PyObject *) env;
|
||||
}
|
||||
|
||||
|
||||
static PyTypeObject EnvironmentType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_dynfunc.Environment", /* tp_name */
|
||||
sizeof(EnvironmentObject), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
(destructor) env_dealloc, /* tp_dealloc */
|
||||
0, /* tp_vectorcall_offset */
|
||||
0, /* tp_getattr*/
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_as_async */
|
||||
0, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
(traverseproc) env_traverse, /* tp_traverse */
|
||||
(inquiry) env_clear, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
env_members, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
env_new, /* tp_new */
|
||||
0, /* tp_free */
|
||||
0, /* tp_is_gc */
|
||||
0, /* tp_bases */
|
||||
0, /* tp_mro */
|
||||
0, /* tp_cache */
|
||||
0, /* tp_subclasses */
|
||||
0, /* tp_weaklist */
|
||||
0, /* tp_del */
|
||||
0, /* tp_version_tag */
|
||||
0, /* tp_finalize */
|
||||
0, /* tp_vectorcall */
|
||||
#if (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION >= 12)
|
||||
/* This was introduced first in 3.12
|
||||
* https://github.com/python/cpython/issues/91051
|
||||
*/
|
||||
0, /* tp_watched */
|
||||
#endif
|
||||
#if (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION >= 13)
|
||||
/* This was introduced in 3.13
|
||||
* https://github.com/python/cpython/pull/114900
|
||||
*/
|
||||
0, /* tp_versions_used */
|
||||
#endif
|
||||
|
||||
/* WARNING: Do not remove this, only modify it! It is a version guard to
|
||||
* act as a reminder to update this struct on Python version update! */
|
||||
#if (PY_MAJOR_VERSION == 3)
|
||||
#if ! (NB_SUPPORTED_PYTHON_MINOR)
|
||||
#error "Python minor version is not supported."
|
||||
#endif
|
||||
#else
|
||||
#error "Python major version is not supported."
|
||||
#endif
|
||||
/* END WARNING*/
|
||||
};
|
||||
|
||||
/* A closure object is created for each call to make_function(), and stored
|
||||
as the resulting PyCFunction object's "self" pointer. It points to an
|
||||
EnvironmentObject which is constructed during compilation. This allows
|
||||
for two things:
|
||||
- lifetime management of dependent data (e.g. lifted loop dispatchers)
|
||||
- access to the execution environment by the compiled function
|
||||
(for example the globals module)
|
||||
*/
|
||||
|
||||
/* Closure is a variable-sized object for binary compatibility with
|
||||
Generator (see below). */
|
||||
#define CLOSURE_HEAD \
|
||||
PyObject_VAR_HEAD \
|
||||
EnvironmentObject *env;
|
||||
|
||||
typedef struct {
|
||||
CLOSURE_HEAD
|
||||
/* The dynamically-filled method definition for the PyCFunction object
|
||||
using this closure. */
|
||||
PyMethodDef def;
|
||||
/* Arbitrary object to keep alive during the closure's lifetime.
|
||||
(put a tuple to put several objects alive).
|
||||
In practice, this helps keep the LLVM module and its generated
|
||||
code alive. */
|
||||
PyObject *keepalive;
|
||||
PyObject *weakreflist;
|
||||
} ClosureObject;
|
||||
|
||||
|
||||
static int
|
||||
closure_traverse(ClosureObject *clo, visitproc visit, void *arg)
|
||||
{
|
||||
Py_VISIT(clo->env);
|
||||
Py_VISIT(clo->keepalive);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
closure_dealloc(ClosureObject *clo)
|
||||
{
|
||||
PyObject_GC_UnTrack((PyObject *) clo);
|
||||
if (clo->weakreflist != NULL)
|
||||
PyObject_ClearWeakRefs((PyObject *) clo);
|
||||
PyObject_Free((void *) clo->def.ml_name);
|
||||
PyObject_Free((void *) clo->def.ml_doc);
|
||||
Py_XDECREF(clo->env);
|
||||
Py_XDECREF(clo->keepalive);
|
||||
Py_TYPE(clo)->tp_free((PyObject *) clo);
|
||||
}
|
||||
|
||||
static PyTypeObject ClosureType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_dynfunc._Closure", /* tp_name */
|
||||
sizeof(ClosureObject), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
(destructor) closure_dealloc, /* tp_dealloc */
|
||||
0, /* tp_vectorcall_offset */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_as_async */
|
||||
0, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call */
|
||||
0, /* tp_str */
|
||||
0, /* tp_getattro */
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
|
||||
0, /* tp_doc */
|
||||
(traverseproc) closure_traverse, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
offsetof(ClosureObject, weakreflist), /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
0, /* tp_new */
|
||||
0, /* tp_free */
|
||||
0, /* tp_is_gc */
|
||||
0, /* tp_bases */
|
||||
0, /* tp_mro */
|
||||
0, /* tp_cache */
|
||||
0, /* tp_subclasses */
|
||||
0, /* tp_weaklist */
|
||||
0, /* tp_del */
|
||||
0, /* tp_version_tag */
|
||||
0, /* tp_finalize */
|
||||
0, /* tp_vectorcall */
|
||||
#if (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION >= 12)
|
||||
/* This was introduced first in 3.12
|
||||
* https://github.com/python/cpython/issues/91051
|
||||
*/
|
||||
0, /* tp_watched */
|
||||
#endif
|
||||
#if (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION >= 13)
|
||||
/* This was introduced in 3.13
|
||||
* https://github.com/python/cpython/pull/114900
|
||||
*/
|
||||
0, /* tp_versions_used */
|
||||
#endif
|
||||
|
||||
/* WARNING: Do not remove this, only modify it! It is a version guard to
|
||||
* act as a reminder to update this struct on Python version update! */
|
||||
#if (PY_MAJOR_VERSION == 3)
|
||||
#if ! (NB_SUPPORTED_PYTHON_MINOR)
|
||||
#error "Python minor version is not supported."
|
||||
#endif
|
||||
#else
|
||||
#error "Python major version is not supported."
|
||||
#endif
|
||||
/* END WARNING*/
|
||||
};
|
||||
|
||||
|
||||
/* Return an owned piece of character data duplicating a Python string
|
||||
object's value. */
|
||||
static char *
|
||||
dup_string(PyObject *strobj)
|
||||
{
|
||||
const char *tmp = NULL;
|
||||
char *str;
|
||||
tmp = PyString_AsString(strobj);
|
||||
if (tmp == NULL)
|
||||
return NULL;
|
||||
/* Using PyObject_Malloc allows this memory to be tracked for
|
||||
leaks. */
|
||||
str = PyObject_Malloc(strlen(tmp) + 1);
|
||||
if (str == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return NULL;
|
||||
}
|
||||
strcpy(str, tmp);
|
||||
return str;
|
||||
}
|
||||
|
||||
/* Create and initialize a new Closure object */
|
||||
static ClosureObject *
|
||||
closure_new(PyObject *name, PyObject *doc, PyCFunction fnaddr,
|
||||
EnvironmentObject *env, PyObject *keepalive)
|
||||
{
|
||||
ClosureObject *clo = (ClosureObject *) PyType_GenericAlloc(&ClosureType, 0);
|
||||
if (clo == NULL)
|
||||
return NULL;
|
||||
|
||||
clo->def.ml_name = dup_string(name);
|
||||
if (!clo->def.ml_name) {
|
||||
Py_DECREF(clo);
|
||||
return NULL;
|
||||
}
|
||||
clo->def.ml_meth = fnaddr;
|
||||
clo->def.ml_flags = METH_VARARGS | METH_KEYWORDS;
|
||||
clo->def.ml_doc = dup_string(doc);
|
||||
if (!clo->def.ml_doc) {
|
||||
Py_DECREF(clo);
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(env);
|
||||
clo->env = env;
|
||||
Py_XINCREF(keepalive);
|
||||
clo->keepalive = keepalive;
|
||||
return clo;
|
||||
}
|
||||
|
||||
/* Create a new PyCFunction object wrapping a closure defined by
|
||||
the given arguments. */
|
||||
static PyObject *
|
||||
pycfunction_new(PyObject *module, PyObject *name, PyObject *doc,
|
||||
PyCFunction fnaddr, EnvironmentObject *env, PyObject *keepalive)
|
||||
{
|
||||
PyObject *funcobj;
|
||||
PyObject *modname = NULL;
|
||||
ClosureObject *closure = NULL;
|
||||
|
||||
closure = closure_new(name, doc, fnaddr, env, keepalive);
|
||||
if (closure == NULL) goto FAIL;
|
||||
|
||||
modname = PyObject_GetAttrString(module, "__name__");
|
||||
if (modname == NULL) goto FAIL;
|
||||
|
||||
funcobj = PyCFunction_NewEx(&closure->def, (PyObject *) closure, modname);
|
||||
Py_DECREF(closure);
|
||||
Py_DECREF(modname);
|
||||
|
||||
return funcobj;
|
||||
|
||||
FAIL:
|
||||
Py_XDECREF(closure);
|
||||
Py_XDECREF(modname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Python-facing wrapper for Numba-compiled generator.
|
||||
* Note the Environment's offset inside the struct is the same as in the
|
||||
* Closure object. This is required to simplify generation of Python wrappers.
|
||||
*/
|
||||
|
||||
typedef void (*gen_finalizer_t)(void *);
|
||||
|
||||
typedef struct {
|
||||
CLOSURE_HEAD
|
||||
PyCFunctionWithKeywords nextfunc;
|
||||
gen_finalizer_t finalizer;
|
||||
PyObject *weakreflist;
|
||||
union {
|
||||
double dummy; /* Force alignment */
|
||||
char state[0];
|
||||
};
|
||||
} GeneratorObject;
|
||||
|
||||
static int
|
||||
generator_traverse(GeneratorObject *gen, visitproc visit, void *arg)
|
||||
{
|
||||
/* XXX this doesn't traverse the state, which can own references to
|
||||
PyObjects */
|
||||
Py_VISIT(gen->env);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
generator_clear(GeneratorObject *gen)
|
||||
{
|
||||
if (gen->finalizer != NULL) {
|
||||
gen->finalizer(gen->state);
|
||||
gen->finalizer = NULL;
|
||||
}
|
||||
Py_CLEAR(gen->env);
|
||||
gen->nextfunc = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
generator_dealloc(GeneratorObject *gen)
|
||||
{
|
||||
PyObject_GC_UnTrack((PyObject *) gen);
|
||||
if (gen->weakreflist != NULL)
|
||||
PyObject_ClearWeakRefs((PyObject *) gen);
|
||||
/* XXX The finalizer may be called after the LLVM module has been
|
||||
destroyed (typically at interpreter shutdown) */
|
||||
if (!_Py_IsFinalizing())
|
||||
if (gen->finalizer != NULL)
|
||||
gen->finalizer(gen->state);
|
||||
Py_XDECREF(gen->env);
|
||||
Py_TYPE(gen)->tp_free((PyObject *) gen);
|
||||
}
|
||||
|
||||
static PyObject *
|
||||
generator_iternext(GeneratorObject *gen)
|
||||
{
|
||||
PyObject *res, *args;
|
||||
if (gen->nextfunc == NULL) {
|
||||
PyErr_SetString(PyExc_RuntimeError,
|
||||
"cannot call next() on finalized generator");
|
||||
return NULL;
|
||||
}
|
||||
args = PyTuple_Pack(1, (PyObject *) gen);
|
||||
if (args == NULL)
|
||||
return NULL;
|
||||
res = (*gen->nextfunc)((PyObject *) gen, args, NULL);
|
||||
Py_DECREF(args);
|
||||
return res;
|
||||
}
|
||||
|
||||
static PyTypeObject GeneratorType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_dynfunc._Generator", /* tp_name*/
|
||||
offsetof(GeneratorObject, state), /* tp_basicsize*/
|
||||
1, /* tp_itemsize*/
|
||||
(destructor) generator_dealloc, /* tp_dealloc*/
|
||||
0, /* tp_vectorcall_offset*/
|
||||
0, /* tp_getattr*/
|
||||
0, /* tp_setattr*/
|
||||
0, /* tp_as_async*/
|
||||
0, /* tp_repr*/
|
||||
0, /* tp_as_number*/
|
||||
0, /* tp_as_sequence*/
|
||||
0, /* tp_as_mapping*/
|
||||
0, /* tp_hash */
|
||||
0, /* tp_call*/
|
||||
0, /* tp_str*/
|
||||
0, /* tp_getattro*/
|
||||
0, /* tp_setattro*/
|
||||
0, /* tp_as_buffer*/
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC
|
||||
| Py_TPFLAGS_BASETYPE, /* tp_flags*/
|
||||
0, /* tp_doc */
|
||||
(traverseproc) generator_traverse, /* tp_traverse */
|
||||
(inquiry) generator_clear, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
offsetof(GeneratorObject, weakreflist), /* tp_weaklistoffset */
|
||||
PyObject_SelfIter, /* tp_iter */
|
||||
(iternextfunc) generator_iternext, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
0, /* tp_new */
|
||||
0, /* tp_free */
|
||||
0, /* tp_is_gc */
|
||||
0, /* tp_bases */
|
||||
0, /* tp_mro */
|
||||
0, /* tp_cache */
|
||||
0, /* tp_subclasses */
|
||||
0, /* tp_weaklist */
|
||||
0, /* tp_del */
|
||||
0, /* tp_version_tag */
|
||||
0, /* tp_finalize */
|
||||
0, /* tp_vectorcall */
|
||||
#if (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION >= 12)
|
||||
/* This was introduced first in 3.12
|
||||
* https://github.com/python/cpython/issues/91051
|
||||
*/
|
||||
0, /* tp_watched */
|
||||
#endif
|
||||
#if (PY_MAJOR_VERSION == 3) && (PY_MINOR_VERSION >= 13)
|
||||
/* This was introduced in 3.13
|
||||
* https://github.com/python/cpython/pull/114900
|
||||
*/
|
||||
0, /* tp_versions_used */
|
||||
#endif
|
||||
|
||||
/* WARNING: Do not remove this, only modify it! It is a version guard to
|
||||
* act as a reminder to update this struct on Python version update! */
|
||||
#if (PY_MAJOR_VERSION == 3)
|
||||
#if ! (NB_SUPPORTED_PYTHON_MINOR)
|
||||
#error "Python minor version is not supported."
|
||||
#endif
|
||||
#else
|
||||
#error "Python major version is not supported."
|
||||
#endif
|
||||
/* END WARNING*/
|
||||
};
|
||||
|
||||
/* Dynamically create a new generator object */
|
||||
static PyObject *
|
||||
Numba_make_generator(Py_ssize_t gen_state_size,
|
||||
void *initial_state,
|
||||
PyCFunctionWithKeywords nextfunc,
|
||||
gen_finalizer_t finalizer,
|
||||
EnvironmentObject *env)
|
||||
{
|
||||
GeneratorObject *gen;
|
||||
gen = (GeneratorObject *) PyType_GenericAlloc(&GeneratorType, gen_state_size);
|
||||
if (gen == NULL)
|
||||
return NULL;
|
||||
memcpy(gen->state, initial_state, gen_state_size);
|
||||
gen->nextfunc = nextfunc;
|
||||
Py_XINCREF(env);
|
||||
gen->env = env;
|
||||
gen->finalizer = finalizer;
|
||||
return (PyObject *) gen;
|
||||
}
|
||||
|
||||
/* Initialization subroutine for use by modules including this */
|
||||
static int
|
||||
init_dynfunc_module(PyObject *module)
|
||||
{
|
||||
if (PyType_Ready(&ClosureType))
|
||||
return -1;
|
||||
if (PyType_Ready(&EnvironmentType))
|
||||
return -1;
|
||||
if (PyType_Ready(&GeneratorType))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,93 @@
|
||||
#include "_dynfunc.c"
|
||||
|
||||
/* Python-facing function to dynamically create a new C function object */
|
||||
static PyObject*
|
||||
make_function(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *module, *fname, *fdoc, *fnaddrobj;
|
||||
void *fnaddr;
|
||||
EnvironmentObject *env;
|
||||
PyObject *keepalive;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "OOOOO!|O",
|
||||
&module, &fname, &fdoc, &fnaddrobj, &EnvironmentType, &env,
|
||||
&keepalive)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fnaddr = PyLong_AsVoidPtr(fnaddrobj);
|
||||
if (fnaddr == NULL && PyErr_Occurred())
|
||||
return NULL;
|
||||
|
||||
return pycfunction_new(module, fname, fdoc, fnaddr, env, keepalive);
|
||||
}
|
||||
|
||||
static PyMethodDef ext_methods[] = {
|
||||
#define declmethod(func) { #func , ( PyCFunction )func , METH_VARARGS , NULL }
|
||||
declmethod(make_function),
|
||||
{ NULL },
|
||||
#undef declmethod
|
||||
};
|
||||
|
||||
|
||||
static PyObject *
|
||||
build_c_helpers_dict(void)
|
||||
{
|
||||
PyObject *dct = PyDict_New();
|
||||
if (dct == NULL)
|
||||
goto error;
|
||||
|
||||
#define _declpointer(name, value) do { \
|
||||
PyObject *o = PyLong_FromVoidPtr(value); \
|
||||
if (o == NULL) goto error; \
|
||||
if (PyDict_SetItemString(dct, name, o)) { \
|
||||
Py_DECREF(o); \
|
||||
goto error; \
|
||||
} \
|
||||
Py_DECREF(o); \
|
||||
} while (0)
|
||||
|
||||
#define declmethod(func) _declpointer(#func, &Numba_##func)
|
||||
|
||||
#define declpointer(ptr) _declpointer(#ptr, &ptr)
|
||||
|
||||
declmethod(make_generator);
|
||||
|
||||
#undef declmethod
|
||||
return dct;
|
||||
error:
|
||||
Py_XDECREF(dct);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MOD_INIT(_dynfunc) {
|
||||
PyObject *m, *impl_info;
|
||||
|
||||
MOD_DEF(m, "_dynfunc", "No docs", ext_methods)
|
||||
if (m == NULL)
|
||||
return MOD_ERROR_VAL;
|
||||
|
||||
if (init_dynfunc_module(m))
|
||||
return MOD_ERROR_VAL;
|
||||
|
||||
impl_info = Py_BuildValue(
|
||||
"{snsnsn}",
|
||||
"offsetof_closure_body", offsetof(ClosureObject, env),
|
||||
"offsetof_env_body", offsetof(EnvironmentObject, globals),
|
||||
"offsetof_generator_state", offsetof(GeneratorObject, state)
|
||||
);
|
||||
if (impl_info == NULL)
|
||||
return MOD_ERROR_VAL;
|
||||
PyModule_AddObject(m, "_impl_info", impl_info);
|
||||
|
||||
Py_INCREF(&ClosureType);
|
||||
PyModule_AddObject(m, "_Closure", (PyObject *) (&ClosureType));
|
||||
Py_INCREF(&EnvironmentType);
|
||||
PyModule_AddObject(m, "Environment", (PyObject *) (&EnvironmentType));
|
||||
Py_INCREF(&GeneratorType);
|
||||
PyModule_AddObject(m, "_Generator", (PyObject *) (&GeneratorType));
|
||||
|
||||
PyModule_AddObject(m, "c_helpers", build_c_helpers_dict());
|
||||
|
||||
return MOD_SUCCESS_VAL(m);
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* See _hashtable.c for more information about this file.
|
||||
*/
|
||||
|
||||
#ifndef Py_HASHTABLE_H
|
||||
#define Py_HASHTABLE_H
|
||||
|
||||
/* The whole API is private */
|
||||
#ifndef Py_LIMITED_API
|
||||
|
||||
typedef struct _Py_slist_item_s {
|
||||
struct _Py_slist_item_s *next;
|
||||
} _Py_slist_item_t;
|
||||
|
||||
typedef struct {
|
||||
_Py_slist_item_t *head;
|
||||
} _Py_slist_t;
|
||||
|
||||
#define _Py_SLIST_ITEM_NEXT(ITEM) (((_Py_slist_item_t *)ITEM)->next)
|
||||
|
||||
#define _Py_SLIST_HEAD(SLIST) (((_Py_slist_t *)SLIST)->head)
|
||||
|
||||
typedef struct {
|
||||
/* used by _Numba_hashtable_t.buckets to link entries */
|
||||
_Py_slist_item_t _Py_slist_item;
|
||||
|
||||
const void *key;
|
||||
Py_uhash_t key_hash;
|
||||
|
||||
/* data follows */
|
||||
} _Numba_hashtable_entry_t;
|
||||
|
||||
#define _Numba_HASHTABLE_ENTRY_DATA(ENTRY) \
|
||||
((char *)(ENTRY) + sizeof(_Numba_hashtable_entry_t))
|
||||
|
||||
#define _Numba_HASHTABLE_ENTRY_DATA_AS_VOID_P(ENTRY) \
|
||||
(*(void **)_Numba_HASHTABLE_ENTRY_DATA(ENTRY))
|
||||
|
||||
#define _Numba_HASHTABLE_ENTRY_READ_DATA(TABLE, DATA, DATA_SIZE, ENTRY) \
|
||||
do { \
|
||||
assert((DATA_SIZE) == (TABLE)->data_size); \
|
||||
memcpy(DATA, _Numba_HASHTABLE_ENTRY_DATA(ENTRY), DATA_SIZE); \
|
||||
} while (0)
|
||||
|
||||
typedef Py_uhash_t (*_Numba_hashtable_hash_func) (const void *key);
|
||||
typedef int (*_Numba_hashtable_compare_func) (const void *key, const _Numba_hashtable_entry_t *he);
|
||||
typedef void* (*_Numba_hashtable_copy_data_func)(void *data);
|
||||
typedef void (*_Numba_hashtable_free_data_func)(void *data);
|
||||
typedef size_t (*_Numba_hashtable_get_data_size_func)(void *data);
|
||||
|
||||
typedef struct {
|
||||
/* allocate a memory block */
|
||||
void* (*malloc) (size_t size);
|
||||
|
||||
/* release a memory block */
|
||||
void (*free) (void *ptr);
|
||||
} _Numba_hashtable_allocator_t;
|
||||
|
||||
typedef struct {
|
||||
size_t num_buckets;
|
||||
size_t entries; /* Total number of entries in the table. */
|
||||
_Py_slist_t *buckets;
|
||||
size_t data_size;
|
||||
|
||||
_Numba_hashtable_hash_func hash_func;
|
||||
_Numba_hashtable_compare_func compare_func;
|
||||
_Numba_hashtable_copy_data_func copy_data_func;
|
||||
_Numba_hashtable_free_data_func free_data_func;
|
||||
_Numba_hashtable_get_data_size_func get_data_size_func;
|
||||
_Numba_hashtable_allocator_t alloc;
|
||||
} _Numba_hashtable_t;
|
||||
|
||||
/* hash and compare functions for integers and pointers */
|
||||
extern "C" PyAPI_FUNC(Py_uhash_t) _Numba_hashtable_hash_ptr(const void *key);
|
||||
extern "C" PyAPI_FUNC(Py_uhash_t) _Numba_hashtable_hash_int(const void *key);
|
||||
extern "C" PyAPI_FUNC(int) _Numba_hashtable_compare_direct(const void *key, const _Numba_hashtable_entry_t *entry);
|
||||
|
||||
extern "C" PyAPI_FUNC(_Numba_hashtable_t *) _Numba_hashtable_new(
|
||||
size_t data_size,
|
||||
_Numba_hashtable_hash_func hash_func,
|
||||
_Numba_hashtable_compare_func compare_func);
|
||||
extern "C" PyAPI_FUNC(_Numba_hashtable_t *) _Numba_hashtable_new_full(
|
||||
size_t data_size,
|
||||
size_t init_size,
|
||||
_Numba_hashtable_hash_func hash_func,
|
||||
_Numba_hashtable_compare_func compare_func,
|
||||
_Numba_hashtable_copy_data_func copy_data_func,
|
||||
_Numba_hashtable_free_data_func free_data_func,
|
||||
_Numba_hashtable_get_data_size_func get_data_size_func,
|
||||
_Numba_hashtable_allocator_t *allocator);
|
||||
extern "C" PyAPI_FUNC(_Numba_hashtable_t *) _Numba_hashtable_copy(_Numba_hashtable_t *src);
|
||||
extern "C" PyAPI_FUNC(void) _Numba_hashtable_clear(_Numba_hashtable_t *ht);
|
||||
extern "C" PyAPI_FUNC(void) _Numba_hashtable_destroy(_Numba_hashtable_t *ht);
|
||||
|
||||
typedef int (*_Numba_hashtable_foreach_func) (_Numba_hashtable_entry_t *entry, void *arg);
|
||||
|
||||
extern "C" PyAPI_FUNC(int) _Numba_hashtable_foreach(
|
||||
_Numba_hashtable_t *ht,
|
||||
_Numba_hashtable_foreach_func func, void *arg);
|
||||
extern "C" PyAPI_FUNC(size_t) _Numba_hashtable_size(_Numba_hashtable_t *ht);
|
||||
|
||||
extern "C" PyAPI_FUNC(_Numba_hashtable_entry_t*) _Numba_hashtable_get_entry(
|
||||
_Numba_hashtable_t *ht,
|
||||
const void *key);
|
||||
extern "C" PyAPI_FUNC(int) _Numba_hashtable_set(
|
||||
_Numba_hashtable_t *ht,
|
||||
const void *key,
|
||||
void *data,
|
||||
size_t data_size);
|
||||
extern "C" PyAPI_FUNC(int) _Numba_hashtable_get(
|
||||
_Numba_hashtable_t *ht,
|
||||
const void *key,
|
||||
void *data,
|
||||
size_t data_size);
|
||||
extern "C" PyAPI_FUNC(int) _Numba_hashtable_pop(
|
||||
_Numba_hashtable_t *ht,
|
||||
const void *key,
|
||||
void *data,
|
||||
size_t data_size);
|
||||
extern "C" PyAPI_FUNC(void) _Numba_hashtable_delete(
|
||||
_Numba_hashtable_t *ht,
|
||||
const void *key);
|
||||
|
||||
#define _Numba_HASHTABLE_SET(TABLE, KEY, DATA) \
|
||||
_Numba_hashtable_set(TABLE, KEY, &(DATA), sizeof(DATA))
|
||||
|
||||
#define _Numba_HASHTABLE_GET(TABLE, KEY, DATA) \
|
||||
_Numba_hashtable_get(TABLE, KEY, &(DATA), sizeof(DATA))
|
||||
|
||||
#endif /* Py_LIMITED_API */
|
||||
|
||||
#endif
|
||||
1251
linedance-app/venv/lib/python3.12/site-packages/numba/_helperlib.c
Normal file
1251
linedance-app/venv/lib/python3.12/site-packages/numba/_helperlib.c
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -0,0 +1,2 @@
|
||||
def _import_cython_function(module_name: str, function_name: str):
|
||||
...
|
||||
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
Expose all functions as pointers in a dedicated C extension.
|
||||
*/
|
||||
#include "cext/cext.h"
|
||||
/* Import _pymodule.h first, for a recent _POSIX_C_SOURCE */
|
||||
#include "_pymodule.h"
|
||||
|
||||
#include <math.h>
|
||||
#ifdef _MSC_VER
|
||||
#define false 0
|
||||
#define true 1
|
||||
#define bool int
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
Include C-extension here
|
||||
*/
|
||||
#include "cext/cext.h"
|
||||
|
||||
/* Numba C helpers */
|
||||
#include "_helperlib.c"
|
||||
|
||||
static PyObject *
|
||||
build_c_helpers_dict(void)
|
||||
{
|
||||
PyObject *dct = PyDict_New();
|
||||
if (dct == NULL)
|
||||
goto error;
|
||||
|
||||
#define _declpointer(name, value) do { \
|
||||
PyObject *o = PyLong_FromVoidPtr(value); \
|
||||
if (o == NULL) goto error; \
|
||||
if (PyDict_SetItemString(dct, name, o)) { \
|
||||
Py_DECREF(o); \
|
||||
goto error; \
|
||||
} \
|
||||
Py_DECREF(o); \
|
||||
} while (0)
|
||||
|
||||
#define declmethod(func) _declpointer(#func, &numba_##func)
|
||||
|
||||
#define declpointer(ptr) _declpointer(#ptr, &numba_##ptr)
|
||||
|
||||
declmethod(fixed_fmod);
|
||||
declmethod(fixed_fmodf);
|
||||
declmethod(set_fnclex);
|
||||
|
||||
declmethod(sdiv);
|
||||
declmethod(srem);
|
||||
declmethod(udiv);
|
||||
declmethod(urem);
|
||||
declmethod(frexp);
|
||||
declmethod(frexpf);
|
||||
declmethod(ldexp);
|
||||
declmethod(ldexpf);
|
||||
declmethod(cpow);
|
||||
declmethod(cpowf);
|
||||
declmethod(erf);
|
||||
declmethod(erff);
|
||||
declmethod(erfc);
|
||||
declmethod(erfcf);
|
||||
declmethod(gamma);
|
||||
declmethod(gammaf);
|
||||
declmethod(lgamma);
|
||||
declmethod(lgammaf);
|
||||
declmethod(nextafter);
|
||||
declmethod(nextafterf);
|
||||
declmethod(complex_adaptor);
|
||||
declmethod(adapt_ndarray);
|
||||
declmethod(ndarray_new);
|
||||
declmethod(extract_record_data);
|
||||
declmethod(get_buffer);
|
||||
declmethod(adapt_buffer);
|
||||
declmethod(release_buffer);
|
||||
declmethod(extract_np_datetime);
|
||||
declmethod(create_np_datetime);
|
||||
declmethod(extract_np_timedelta);
|
||||
declmethod(create_np_timedelta);
|
||||
declmethod(recreate_record);
|
||||
declmethod(fptoui);
|
||||
declmethod(fptouif);
|
||||
declmethod(gil_ensure);
|
||||
declmethod(gil_release);
|
||||
declmethod(fatal_error);
|
||||
declmethod(py_type);
|
||||
declmethod(unpack_slice);
|
||||
declmethod(do_raise);
|
||||
declmethod(unpickle);
|
||||
declmethod(runtime_build_excinfo_struct);
|
||||
declmethod(attempt_nocopy_reshape);
|
||||
declmethod(get_pyobject_private_data);
|
||||
declmethod(set_pyobject_private_data);
|
||||
declmethod(reset_pyobject_private_data);
|
||||
|
||||
/* BLAS / LAPACK */
|
||||
declmethod(xxgemm);
|
||||
declmethod(xxgemv);
|
||||
declmethod(xxdot);
|
||||
declmethod(xxgetrf);
|
||||
declmethod(ez_xxgetri);
|
||||
declmethod(xxpotrf);
|
||||
declmethod(ez_rgeev);
|
||||
declmethod(ez_cgeev);
|
||||
declmethod(ez_xxxevd);
|
||||
declmethod(ez_gesdd);
|
||||
declmethod(ez_geqrf);
|
||||
declmethod(ez_xxgqr);
|
||||
declmethod(ez_gelsd);
|
||||
declmethod(xgesv);
|
||||
declmethod(xxnrm2);
|
||||
|
||||
/* PRNG support */
|
||||
declmethod(get_py_random_state);
|
||||
declmethod(get_np_random_state);
|
||||
declmethod(get_internal_random_state);
|
||||
declmethod(rnd_shuffle);
|
||||
declmethod(rnd_init);
|
||||
declmethod(poisson_ptrs);
|
||||
|
||||
/* Unicode string support */
|
||||
declmethod(extract_unicode);
|
||||
declmethod(gettyperecord);
|
||||
declmethod(get_PyUnicode_ExtendedCase);
|
||||
|
||||
/* for gdb breakpoint */
|
||||
declmethod(gdb_breakpoint);
|
||||
|
||||
/* for dictionary support */
|
||||
declmethod(test_dict);
|
||||
declmethod(dict_new_sized);
|
||||
declmethod(dict_set_method_table);
|
||||
declmethod(dict_free);
|
||||
declmethod(dict_length);
|
||||
declmethod(dict_lookup);
|
||||
declmethod(dict_insert);
|
||||
declmethod(dict_insert_ez);
|
||||
declmethod(dict_delitem);
|
||||
declmethod(dict_popitem);
|
||||
declmethod(dict_iter_sizeof);
|
||||
declmethod(dict_iter);
|
||||
declmethod(dict_iter_next);
|
||||
declmethod(dict_dump);
|
||||
|
||||
/* for list support */
|
||||
declmethod(test_list);
|
||||
declmethod(list_new);
|
||||
declmethod(list_set_method_table);
|
||||
declmethod(list_free);
|
||||
declmethod(list_base_ptr);
|
||||
declmethod(list_size_address);
|
||||
declmethod(list_length);
|
||||
declmethod(list_allocated);
|
||||
declmethod(list_is_mutable);
|
||||
declmethod(list_set_is_mutable);
|
||||
declmethod(list_setitem);
|
||||
declmethod(list_getitem);
|
||||
declmethod(list_append);
|
||||
declmethod(list_delitem);
|
||||
declmethod(list_delete_slice);
|
||||
declmethod(list_iter_sizeof);
|
||||
declmethod(list_iter);
|
||||
declmethod(list_iter_next);
|
||||
|
||||
#define MATH_UNARY(F, R, A) declmethod(F);
|
||||
#define MATH_BINARY(F, R, A, B) declmethod(F);
|
||||
#include "mathnames.h"
|
||||
#undef MATH_UNARY
|
||||
#undef MATH_BINARY
|
||||
|
||||
#undef declmethod
|
||||
return dct;
|
||||
error:
|
||||
Py_XDECREF(dct);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Helper to deal with flushing stdout
|
||||
*/
|
||||
PyAPI_FUNC(void) _numba_flush_stdout(void) ;
|
||||
|
||||
void
|
||||
_numba_flush_stdout(void) {
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef ext_methods[] = {
|
||||
{ "rnd_get_state", (PyCFunction) _numba_rnd_get_state, METH_O, NULL },
|
||||
{ "rnd_get_py_state_ptr", (PyCFunction) _numba_rnd_get_py_state_ptr, METH_NOARGS, NULL },
|
||||
{ "rnd_get_np_state_ptr", (PyCFunction) _numba_rnd_get_np_state_ptr, METH_NOARGS, NULL },
|
||||
{ "rnd_seed", (PyCFunction) _numba_rnd_seed, METH_VARARGS, NULL },
|
||||
{ "rnd_set_state", (PyCFunction) _numba_rnd_set_state, METH_VARARGS, NULL },
|
||||
{ "rnd_shuffle", (PyCFunction) _numba_rnd_shuffle, METH_O, NULL },
|
||||
{ "_import_cython_function", (PyCFunction) _numba_import_cython_function, METH_VARARGS, NULL },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
/*
|
||||
* These functions are exported by the module's DLL, to exercise ctypes / cffi
|
||||
* without relying on libc availability (see https://bugs.python.org/issue23606)
|
||||
*/
|
||||
|
||||
PyAPI_FUNC(double) _numba_test_sin(double x);
|
||||
PyAPI_FUNC(double) _numba_test_cos(double x);
|
||||
PyAPI_FUNC(double) _numba_test_exp(double x);
|
||||
PyAPI_FUNC(void) _numba_test_vsquare(int n, double *x, double *out);
|
||||
PyAPI_FUNC(double) _numba_test_funcptr(double (*func)(double));
|
||||
PyAPI_FUNC(bool) _numba_test_boolean(void);
|
||||
|
||||
double _numba_test_sin(double x)
|
||||
{
|
||||
return sin(x);
|
||||
}
|
||||
|
||||
double _numba_test_cos(double x)
|
||||
{
|
||||
return cos(x);
|
||||
}
|
||||
|
||||
double _numba_test_exp(double x)
|
||||
{
|
||||
return exp(x);
|
||||
}
|
||||
|
||||
void _numba_test_vsquare(int n, double *x, double *out)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n; i++)
|
||||
out[i] = pow(x[i], 2.0);
|
||||
}
|
||||
|
||||
void _numba_test_vcube(int n, double *x, double *out)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n; i++)
|
||||
out[i] = pow(x[i], 3.0);
|
||||
}
|
||||
|
||||
double _numba_test_funcptr(double (*func)(double))
|
||||
{
|
||||
return func(1.5);
|
||||
}
|
||||
|
||||
bool _numba_test_boolean()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
MOD_INIT(_helperlib) {
|
||||
PyObject *m;
|
||||
MOD_DEF(m, "_helperlib", "No docs", ext_methods)
|
||||
if (m == NULL)
|
||||
return MOD_ERROR_VAL;
|
||||
|
||||
import_array();
|
||||
|
||||
PyModule_AddObject(m, "c_helpers", build_c_helpers_dict());
|
||||
PyModule_AddIntConstant(m, "long_min", LONG_MIN);
|
||||
PyModule_AddIntConstant(m, "long_max", LONG_MAX);
|
||||
PyModule_AddIntConstant(m, "py_buffer_size", sizeof(Py_buffer));
|
||||
PyModule_AddIntConstant(m, "py_gil_state_size", sizeof(PyGILState_STATE));
|
||||
PyModule_AddIntConstant(m, "py_unicode_1byte_kind", PyUnicode_1BYTE_KIND);
|
||||
PyModule_AddIntConstant(m, "py_unicode_2byte_kind", PyUnicode_2BYTE_KIND);
|
||||
PyModule_AddIntConstant(m, "py_unicode_4byte_kind", PyUnicode_4BYTE_KIND);
|
||||
#if (PY_MAJOR_VERSION == 3)
|
||||
#if ((PY_MINOR_VERSION == 10) || (PY_MINOR_VERSION == 11))
|
||||
PyModule_AddIntConstant(m, "py_unicode_wchar_kind", PyUnicode_WCHAR_KIND);
|
||||
#endif
|
||||
#endif
|
||||
numba_rnd_ensure_global_init();
|
||||
|
||||
return MOD_SUCCESS_VAL(m);
|
||||
}
|
||||
1946
linedance-app/venv/lib/python3.12/site-packages/numba/_lapack.c
Normal file
1946
linedance-app/venv/lib/python3.12/site-packages/numba/_lapack.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,43 @@
|
||||
#ifndef NUMBA_COMMON_H_
|
||||
#define NUMBA_COMMON_H_
|
||||
|
||||
/* __has_attribute() is a clang / gcc-5 macro */
|
||||
#ifndef __has_attribute
|
||||
# define __has_attribute(x) 0
|
||||
#endif
|
||||
|
||||
/* This attribute marks symbols that can be shared across C objects
|
||||
* but are not exposed outside of a shared library or executable.
|
||||
* Note this is default behaviour for global symbols under Windows.
|
||||
*/
|
||||
#if defined(_MSC_VER)
|
||||
#define VISIBILITY_HIDDEN
|
||||
#define VISIBILITY_GLOBAL __declspec(dllexport)
|
||||
#elif (__has_attribute(visibility) || (defined(__GNUC__) && __GNUC__ >= 4))
|
||||
#define VISIBILITY_HIDDEN __attribute__ ((visibility("hidden")))
|
||||
#define VISIBILITY_GLOBAL __attribute__ ((visibility("default")))
|
||||
#else
|
||||
#define VISIBILITY_HIDDEN
|
||||
#define VISIBILITY_GLOBAL
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Numba's version of the PyArray_DescrCheck macro from NumPy, use it as a
|
||||
* direct replacement of NumPy's PyArray_DescrCheck to ensure binary
|
||||
* compatibility.
|
||||
*
|
||||
* Details of why this is needed:
|
||||
* NumPy 1.18 changed the definition of the PyArray_DescrCheck macro here:
|
||||
* https://github.com/numpy/numpy/commit/6108b5d1e138d07e3c9f2a4e3b1933749ad0e698
|
||||
* the result of this being that building against NumPy <1.18 would prevent
|
||||
* Numba running against NumPy >= 1.20 as noted here:
|
||||
* https://github.com/numba/numba/issues/6041#issuecomment-665132199
|
||||
*
|
||||
* This macro definition is copied from:
|
||||
* https://github.com/numpy/numpy/commit/6108b5d1e138d07e3c9f2a4e3b1933749ad0e698#diff-ad2213da23136c5fc5883d9eb2d88666R26
|
||||
*
|
||||
* NOTE: This is the NumPy 1.18 and above version of the macro.
|
||||
*/
|
||||
#define NUMBA_PyArray_DescrCheck(op) PyObject_TypeCheck(op, &PyArrayDescr_Type)
|
||||
|
||||
#endif /* NUMBA_COMMON_H_ */
|
||||
@@ -0,0 +1,51 @@
|
||||
#ifndef NUMBA_PY_MODULE_H_
|
||||
#define NUMBA_PY_MODULE_H_
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
|
||||
#include "Python.h"
|
||||
#include "structmember.h"
|
||||
#include "frameobject.h"
|
||||
|
||||
/*
|
||||
* Macro to handle GIL/free-threading at module level. Call on a newly created
|
||||
* module returned by a call to PyModule_Create().
|
||||
*/
|
||||
#ifdef Py_GIL_DISABLED
|
||||
#define MOD_NOGIL(m) \
|
||||
do { \
|
||||
PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED); \
|
||||
} while(0)
|
||||
#else
|
||||
#define MOD_NOGIL(m) do {} while(0)
|
||||
#endif
|
||||
|
||||
#define MOD_ERROR_VAL NULL
|
||||
#define MOD_SUCCESS_VAL(val) val
|
||||
#define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)
|
||||
#define MOD_DEF(ob, name, doc, methods) { \
|
||||
static struct PyModuleDef moduledef = { \
|
||||
PyModuleDef_HEAD_INIT, name, doc, -1, methods, NULL, NULL, NULL, NULL }; \
|
||||
ob = PyModule_Create(&moduledef); \
|
||||
if (ob == NULL) { return MOD_ERROR_VAL; } \
|
||||
MOD_NOGIL(ob); \
|
||||
}
|
||||
#define MOD_INIT_EXEC(name) PyInit_##name();
|
||||
|
||||
#define PyString_AsString PyUnicode_AsUTF8
|
||||
#define PyString_Check PyUnicode_Check
|
||||
#define PyString_FromFormat PyUnicode_FromFormat
|
||||
#define PyString_FromString PyUnicode_FromString
|
||||
#define PyString_InternFromString PyUnicode_InternFromString
|
||||
#define PyInt_Type PyLong_Type
|
||||
#define PyInt_Check PyLong_Check
|
||||
#define PyInt_CheckExact PyLong_CheckExact
|
||||
#define SetAttrStringFromVoidPointer(m, name) do { \
|
||||
PyObject *tmp = PyLong_FromVoidPtr((void *) &name); \
|
||||
PyObject_SetAttrString(m, #name, tmp); \
|
||||
Py_DECREF(tmp); } while (0)
|
||||
|
||||
|
||||
#define NB_SUPPORTED_PYTHON_MINOR ((PY_MINOR_VERSION == 10) || (PY_MINOR_VERSION == 11) || (PY_MINOR_VERSION == 12) || (PY_MINOR_VERSION == 13) || (PY_MINOR_VERSION == 14))
|
||||
|
||||
#endif /* NUMBA_PY_MODULE_H_ */
|
||||
492
linedance-app/venv/lib/python3.12/site-packages/numba/_random.c
Normal file
492
linedance-app/venv/lib/python3.12/site-packages/numba/_random.c
Normal file
@@ -0,0 +1,492 @@
|
||||
/*
|
||||
* PRNG support.
|
||||
*/
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define HAVE_PTHREAD_ATFORK 0
|
||||
#else
|
||||
#define HAVE_PTHREAD_ATFORK 1
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
|
||||
/* Magic Mersenne Twister constants */
|
||||
#define MT_N 624
|
||||
#define MT_M 397
|
||||
#define MT_MATRIX_A 0x9908b0dfU
|
||||
#define MT_UPPER_MASK 0x80000000U
|
||||
#define MT_LOWER_MASK 0x7fffffffU
|
||||
|
||||
/*
|
||||
* Note this structure is accessed in numba.targets.randomimpl,
|
||||
* any changes here should be reflected there too.
|
||||
*/
|
||||
typedef struct {
|
||||
int index;
|
||||
/* unsigned int is sufficient on modern machines as we only need 32 bits */
|
||||
unsigned int mt[MT_N];
|
||||
int has_gauss;
|
||||
double gauss;
|
||||
int is_initialized;
|
||||
} rnd_state_t;
|
||||
|
||||
/* Some code portions below from CPython's _randommodule.c, some others
|
||||
from Numpy's and Jean-Sebastien Roy's randomkit.c. */
|
||||
|
||||
NUMBA_EXPORT_FUNC(void)
|
||||
numba_rnd_shuffle(rnd_state_t *state)
|
||||
{
|
||||
int i;
|
||||
unsigned int y;
|
||||
|
||||
for (i = 0; i < MT_N - MT_M; i++) {
|
||||
y = (state->mt[i] & MT_UPPER_MASK) | (state->mt[i+1] & MT_LOWER_MASK);
|
||||
state->mt[i] = state->mt[i+MT_M] ^ (y >> 1) ^
|
||||
(-(int) (y & 1) & MT_MATRIX_A);
|
||||
}
|
||||
for (; i < MT_N - 1; i++) {
|
||||
y = (state->mt[i] & MT_UPPER_MASK) | (state->mt[i+1] & MT_LOWER_MASK);
|
||||
state->mt[i] = state->mt[i+(MT_M-MT_N)] ^ (y >> 1) ^
|
||||
(-(int) (y & 1) & MT_MATRIX_A);
|
||||
}
|
||||
y = (state->mt[MT_N - 1] & MT_UPPER_MASK) | (state->mt[0] & MT_LOWER_MASK);
|
||||
state->mt[MT_N - 1] = state->mt[MT_M - 1] ^ (y >> 1) ^
|
||||
(-(int) (y & 1) & MT_MATRIX_A);
|
||||
}
|
||||
|
||||
/* Initialize mt[] with an integer seed */
|
||||
NUMBA_EXPORT_FUNC(void)
|
||||
numba_rnd_init(rnd_state_t *state, unsigned int seed)
|
||||
{
|
||||
unsigned int pos;
|
||||
seed &= 0xffffffffU;
|
||||
|
||||
/* Knuth's PRNG as used in the Mersenne Twister reference implementation */
|
||||
for (pos = 0; pos < MT_N; pos++) {
|
||||
state->mt[pos] = seed;
|
||||
seed = (1812433253U * (seed ^ (seed >> 30)) + pos + 1) & 0xffffffffU;
|
||||
}
|
||||
state->index = MT_N;
|
||||
state->has_gauss = 0;
|
||||
state->gauss = 0.0;
|
||||
state->is_initialized = 1;
|
||||
}
|
||||
|
||||
/* Perturb mt[] with a key array */
|
||||
static void
|
||||
rnd_init_by_array(rnd_state_t *state, unsigned int init_key[], size_t key_length)
|
||||
{
|
||||
size_t i, j, k;
|
||||
unsigned int *mt = state->mt;
|
||||
|
||||
numba_rnd_init(state, 19650218U);
|
||||
i = 1; j = 0;
|
||||
k = (MT_N > key_length ? MT_N : key_length);
|
||||
for (; k; k--) {
|
||||
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1664525U))
|
||||
+ init_key[j] + (unsigned int) j; /* non linear */
|
||||
mt[i] &= 0xffffffffU;
|
||||
i++; j++;
|
||||
if (i >= MT_N) { mt[0] = mt[MT_N - 1]; i = 1; }
|
||||
if (j >= key_length) j = 0;
|
||||
}
|
||||
for (k = MT_N - 1; k; k--) {
|
||||
mt[i] = (mt[i] ^ ((mt[i-1] ^ (mt[i-1] >> 30)) * 1566083941U))
|
||||
- (unsigned int) i; /* non linear */
|
||||
mt[i] &= 0xffffffffU;
|
||||
i++;
|
||||
if (i >= MT_N) { mt[0] = mt[MT_N - 1]; i=1; }
|
||||
}
|
||||
|
||||
mt[0] = 0x80000000U; /* MSB is 1; ensuring non-zero initial array */
|
||||
state->index = MT_N;
|
||||
state->has_gauss = 0;
|
||||
state->gauss = 0.0;
|
||||
state->is_initialized = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Management of thread-local random state.
|
||||
*/
|
||||
|
||||
static int rnd_globally_initialized;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define THREAD_LOCAL(ty) __declspec(thread) ty
|
||||
#else
|
||||
/* Non-standard C99 extension that's understood by gcc and clang */
|
||||
#define THREAD_LOCAL(ty) __thread ty
|
||||
#endif
|
||||
|
||||
static THREAD_LOCAL(rnd_state_t) numba_py_random_state;
|
||||
static THREAD_LOCAL(rnd_state_t) numba_np_random_state;
|
||||
static THREAD_LOCAL(rnd_state_t) numba_internal_random_state;
|
||||
|
||||
/* Seed the state with random bytes */
|
||||
static int
|
||||
rnd_seed_with_bytes(rnd_state_t *state, Py_buffer *buf)
|
||||
{
|
||||
unsigned int *keys;
|
||||
unsigned char *bytes;
|
||||
size_t i, nkeys;
|
||||
|
||||
nkeys = buf->len / sizeof(unsigned int);
|
||||
keys = (unsigned int *) PyMem_Malloc(nkeys * sizeof(unsigned int));
|
||||
if (keys == NULL) {
|
||||
PyBuffer_Release(buf);
|
||||
return -1;
|
||||
}
|
||||
bytes = (unsigned char *) buf->buf;
|
||||
/* Convert input bytes to int32 keys, without violating alignment
|
||||
* constraints.
|
||||
*/
|
||||
for (i = 0; i < nkeys; i++, bytes += 4) {
|
||||
keys[i] =
|
||||
((unsigned int)bytes[3] << 24) +
|
||||
((unsigned int)bytes[2] << 16) +
|
||||
((unsigned int)bytes[1] << 8) +
|
||||
((unsigned int)bytes[0] << 0);
|
||||
}
|
||||
PyBuffer_Release(buf);
|
||||
rnd_init_by_array(state, keys, nkeys);
|
||||
PyMem_Free(keys);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if HAVE_PTHREAD_ATFORK
|
||||
/* After a fork(), the child should reseed its random states.
|
||||
* Since only the main thread survives in the child, it's enough to mark
|
||||
* the current thread-local states as uninitialized.
|
||||
*/
|
||||
static void
|
||||
rnd_atfork_child(void)
|
||||
{
|
||||
numba_py_random_state.is_initialized = 0;
|
||||
numba_np_random_state.is_initialized = 0;
|
||||
numba_internal_random_state.is_initialized = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Global initialization routine. It must be called as early as possible.
|
||||
*/
|
||||
NUMBA_EXPORT_FUNC(void)
|
||||
numba_rnd_ensure_global_init(void)
|
||||
{
|
||||
if (!rnd_globally_initialized) {
|
||||
#if HAVE_PTHREAD_ATFORK
|
||||
pthread_atfork(NULL, NULL, rnd_atfork_child);
|
||||
#endif
|
||||
numba_py_random_state.is_initialized = 0;
|
||||
numba_np_random_state.is_initialized = 0;
|
||||
numba_internal_random_state.is_initialized = 0;
|
||||
rnd_globally_initialized = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* First-time init a random state */
|
||||
static void
|
||||
rnd_implicit_init(rnd_state_t *state)
|
||||
{
|
||||
/* Initialize with random bytes. The easiest way to get good-quality
|
||||
* cross-platform random bytes is still to call os.urandom()
|
||||
* using the Python interpreter...
|
||||
*/
|
||||
PyObject *module, *bufobj;
|
||||
Py_buffer buf;
|
||||
PyGILState_STATE gilstate = PyGILState_Ensure();
|
||||
|
||||
module = PyImport_ImportModule("os");
|
||||
if (module == NULL)
|
||||
goto error;
|
||||
/* Read as many bytes as necessary to get the full entropy
|
||||
* exploitable by the MT generator.
|
||||
*/
|
||||
bufobj = PyObject_CallMethod(module, "urandom", "i",
|
||||
(int) (MT_N * sizeof(unsigned int)));
|
||||
Py_DECREF(module);
|
||||
if (bufobj == NULL)
|
||||
goto error;
|
||||
if (PyObject_GetBuffer(bufobj, &buf, PyBUF_SIMPLE))
|
||||
goto error;
|
||||
Py_DECREF(bufobj);
|
||||
if (rnd_seed_with_bytes(state, &buf))
|
||||
goto error;
|
||||
/* state->is_initialized is set now */
|
||||
|
||||
PyGILState_Release(gilstate);
|
||||
return;
|
||||
|
||||
error:
|
||||
/* In normal conditions, os.urandom() and PyMem_Malloc() shouldn't fail,
|
||||
* and we don't want the caller to deal with errors, so just bail out.
|
||||
*/
|
||||
if (PyErr_Occurred())
|
||||
PyErr_Print();
|
||||
Py_FatalError(NULL);
|
||||
}
|
||||
|
||||
/* Functions returning the thread-local random state pointer.
|
||||
* The LLVM JIT doesn't support thread-local variables so we rely
|
||||
* on the C compiler instead.
|
||||
*/
|
||||
|
||||
NUMBA_EXPORT_FUNC(rnd_state_t *)
|
||||
numba_get_py_random_state(void)
|
||||
{
|
||||
rnd_state_t *state = &numba_py_random_state;
|
||||
if (!state->is_initialized)
|
||||
rnd_implicit_init(state);
|
||||
return state;
|
||||
}
|
||||
|
||||
NUMBA_EXPORT_FUNC(rnd_state_t *)
|
||||
numba_get_np_random_state(void)
|
||||
{
|
||||
rnd_state_t *state = &numba_np_random_state;
|
||||
if (!state->is_initialized)
|
||||
rnd_implicit_init(state);
|
||||
return state;
|
||||
}
|
||||
|
||||
NUMBA_EXPORT_FUNC(rnd_state_t *)
|
||||
numba_get_internal_random_state(void)
|
||||
{
|
||||
rnd_state_t *state = &numba_internal_random_state;
|
||||
if (!state->is_initialized)
|
||||
rnd_implicit_init(state);
|
||||
return state;
|
||||
}
|
||||
|
||||
/*
|
||||
* Python-exposed helpers for state management and testing.
|
||||
*/
|
||||
static int
|
||||
rnd_state_converter(PyObject *obj, rnd_state_t **state)
|
||||
{
|
||||
*state = (rnd_state_t *) PyLong_AsVoidPtr(obj);
|
||||
return (*state != NULL || !PyErr_Occurred());
|
||||
}
|
||||
|
||||
NUMBA_EXPORT_FUNC(PyObject *)
|
||||
_numba_rnd_get_py_state_ptr(PyObject *self)
|
||||
{
|
||||
return PyLong_FromVoidPtr(numba_get_py_random_state());
|
||||
}
|
||||
|
||||
NUMBA_EXPORT_FUNC(PyObject *)
|
||||
_numba_rnd_get_np_state_ptr(PyObject *self)
|
||||
{
|
||||
return PyLong_FromVoidPtr(numba_get_np_random_state());
|
||||
}
|
||||
|
||||
NUMBA_EXPORT_FUNC(PyObject *)
|
||||
_numba_rnd_shuffle(PyObject *self, PyObject *arg)
|
||||
{
|
||||
rnd_state_t *state;
|
||||
if (!rnd_state_converter(arg, &state))
|
||||
return NULL;
|
||||
numba_rnd_shuffle(state);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
NUMBA_EXPORT_FUNC(PyObject *)
|
||||
_numba_rnd_set_state(PyObject *self, PyObject *args)
|
||||
{
|
||||
int i, index;
|
||||
rnd_state_t *state;
|
||||
PyObject *tuplearg, *intlist;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O&O!:rnd_set_state",
|
||||
rnd_state_converter, &state,
|
||||
&PyTuple_Type, &tuplearg))
|
||||
return NULL;
|
||||
if (!PyArg_ParseTuple(tuplearg, "iO!", &index, &PyList_Type, &intlist))
|
||||
return NULL;
|
||||
if (PyList_GET_SIZE(intlist) != MT_N) {
|
||||
PyErr_SetString(PyExc_ValueError, "list object has wrong size");
|
||||
return NULL;
|
||||
}
|
||||
state->index = index;
|
||||
for (i = 0; i < MT_N; i++) {
|
||||
PyObject *v = PyList_GET_ITEM(intlist, i);
|
||||
unsigned long x = PyLong_AsUnsignedLong(v);
|
||||
if (x == (unsigned long) -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
state->mt[i] = (unsigned int) x;
|
||||
}
|
||||
state->has_gauss = 0;
|
||||
state->gauss = 0.0;
|
||||
state->is_initialized = 1;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
NUMBA_EXPORT_FUNC(PyObject *)
|
||||
_numba_rnd_get_state(PyObject *self, PyObject *arg)
|
||||
{
|
||||
PyObject *intlist;
|
||||
int i;
|
||||
rnd_state_t *state;
|
||||
if (!rnd_state_converter(arg, &state))
|
||||
return NULL;
|
||||
|
||||
intlist = PyList_New(MT_N);
|
||||
if (intlist == NULL)
|
||||
return NULL;
|
||||
for (i = 0; i < MT_N; i++) {
|
||||
PyObject *v = PyLong_FromUnsignedLong(state->mt[i]);
|
||||
if (v == NULL) {
|
||||
Py_DECREF(intlist);
|
||||
return NULL;
|
||||
}
|
||||
PyList_SET_ITEM(intlist, i, v);
|
||||
}
|
||||
return Py_BuildValue("iN", state->index, intlist);
|
||||
}
|
||||
|
||||
NUMBA_EXPORT_FUNC(PyObject *)
|
||||
_numba_rnd_seed(PyObject *self, PyObject *args)
|
||||
{
|
||||
unsigned int seed;
|
||||
rnd_state_t *state;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O&I:rnd_seed",
|
||||
rnd_state_converter, &state, &seed)) {
|
||||
/* rnd_seed_*(bytes-like object) */
|
||||
Py_buffer buf;
|
||||
|
||||
PyErr_Clear();
|
||||
if (!PyArg_ParseTuple(args, "O&s*:rnd_seed",
|
||||
rnd_state_converter, &state, &buf))
|
||||
return NULL;
|
||||
|
||||
if (rnd_seed_with_bytes(state, &buf))
|
||||
return NULL;
|
||||
else
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
else {
|
||||
/* rnd_seed_*(int32) */
|
||||
numba_rnd_init(state, seed);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Random distribution helpers.
|
||||
* Most code straight from Numpy's distributions.c.
|
||||
*/
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846264338328
|
||||
#endif
|
||||
|
||||
NUMBA_EXPORT_FUNC(unsigned int)
|
||||
get_next_int32(rnd_state_t *state)
|
||||
{
|
||||
unsigned int y;
|
||||
|
||||
if (state->index == MT_N) {
|
||||
numba_rnd_shuffle(state);
|
||||
state->index = 0;
|
||||
}
|
||||
y = state->mt[state->index++];
|
||||
/* Tempering */
|
||||
y ^= (y >> 11);
|
||||
y ^= (y << 7) & 0x9d2c5680U;
|
||||
y ^= (y << 15) & 0xefc60000U;
|
||||
y ^= (y >> 18);
|
||||
return y;
|
||||
}
|
||||
|
||||
NUMBA_EXPORT_FUNC(double)
|
||||
get_next_double(rnd_state_t *state)
|
||||
{
|
||||
double a = get_next_int32(state) >> 5;
|
||||
double b = get_next_int32(state) >> 6;
|
||||
return (a * 67108864.0 + b) / 9007199254740992.0;
|
||||
}
|
||||
|
||||
NUMBA_EXPORT_FUNC(double)
|
||||
loggam(double x)
|
||||
{
|
||||
double x0, x2, xp, gl, gl0;
|
||||
long k, n;
|
||||
|
||||
static double a[10] = {8.333333333333333e-02,-2.777777777777778e-03,
|
||||
7.936507936507937e-04,-5.952380952380952e-04,
|
||||
8.417508417508418e-04,-1.917526917526918e-03,
|
||||
6.410256410256410e-03,-2.955065359477124e-02,
|
||||
1.796443723688307e-01,-1.39243221690590e+00};
|
||||
x0 = x;
|
||||
n = 0;
|
||||
if ((x == 1.0) || (x == 2.0))
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
else if (x <= 7.0)
|
||||
{
|
||||
n = (long)(7 - x);
|
||||
x0 = x + n;
|
||||
}
|
||||
x2 = 1.0/(x0*x0);
|
||||
xp = 2*M_PI;
|
||||
gl0 = a[9];
|
||||
for (k=8; k>=0; k--)
|
||||
{
|
||||
gl0 *= x2;
|
||||
gl0 += a[k];
|
||||
}
|
||||
gl = gl0/x0 + 0.5*log(xp) + (x0-0.5)*log(x0) - x0;
|
||||
if (x <= 7.0)
|
||||
{
|
||||
for (k=1; k<=n; k++)
|
||||
{
|
||||
gl -= log(x0-1.0);
|
||||
x0 -= 1.0;
|
||||
}
|
||||
}
|
||||
return gl;
|
||||
}
|
||||
|
||||
|
||||
NUMBA_EXPORT_FUNC(int64_t)
|
||||
numba_poisson_ptrs(rnd_state_t *state, double lam)
|
||||
{
|
||||
/* This method is invoked only if the parameter lambda of this
|
||||
* distribution is big enough ( >= 10 ). The algorithm used is
|
||||
* described in "Hörmann, W. 1992. 'The Transformed Rejection
|
||||
* Method for Generating Poisson Random Variables'.
|
||||
* The implementation comes straight from Numpy.
|
||||
*/
|
||||
int64_t k;
|
||||
double U, V, slam, loglam, a, b, invalpha, vr, us;
|
||||
|
||||
slam = sqrt(lam);
|
||||
loglam = log(lam);
|
||||
b = 0.931 + 2.53*slam;
|
||||
a = -0.059 + 0.02483*b;
|
||||
invalpha = 1.1239 + 1.1328/(b-3.4);
|
||||
vr = 0.9277 - 3.6224/(b-2);
|
||||
|
||||
while (1)
|
||||
{
|
||||
U = get_next_double(state) - 0.5;
|
||||
V = get_next_double(state);
|
||||
us = 0.5 - fabs(U);
|
||||
k = (int64_t) floor((2*a/us + b)*U + lam + 0.43);
|
||||
if ((us >= 0.07) && (V <= vr))
|
||||
{
|
||||
return k;
|
||||
}
|
||||
if ((k < 0) ||
|
||||
((us < 0.013) && (V > us)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ((log(V) + log(invalpha) - log(a/(us*us)+b)) <=
|
||||
(-lam + (double) k*loglam - loggam((double) k+1)))
|
||||
{
|
||||
return k;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef NUMBA_TYPEOF_H_
|
||||
#define NUMBA_TYPEOF_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern PyObject *typeof_init(PyObject *self, PyObject *args);
|
||||
extern int typeof_typecode(PyObject *dispatcher, PyObject *val);
|
||||
extern PyObject *typeof_compute_fingerprint(PyObject *val);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NUMBA_TYPEOF_H_ */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,21 @@
|
||||
|
||||
# This file was generated by 'versioneer.py' (0.28) from
|
||||
# revision-control system data, or from the parent directory name of an
|
||||
# unpacked source archive. Distribution tarballs contain a pre-generated copy
|
||||
# of this file.
|
||||
|
||||
import json
|
||||
|
||||
version_json = '''
|
||||
{
|
||||
"date": "2026-03-31T12:27:00-0700",
|
||||
"dirty": false,
|
||||
"error": null,
|
||||
"full-revisionid": "6ebcd9ef0a0372b6c124a6917c39498ffc923868",
|
||||
"version": "0.65.0"
|
||||
}
|
||||
''' # END VERSION_JSON
|
||||
|
||||
|
||||
def get_versions():
|
||||
return json.loads(version_json)
|
||||
@@ -0,0 +1,23 @@
|
||||
"""
|
||||
Utilities for getting information about Numba C extensions
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
|
||||
def get_extension_libs():
|
||||
"""Return the .c files in the `numba.cext` directory.
|
||||
"""
|
||||
libs = []
|
||||
base = get_path()
|
||||
for fn in os.listdir(base):
|
||||
if fn.endswith('.c'):
|
||||
fn = os.path.join(base, fn)
|
||||
libs.append(fn)
|
||||
return libs
|
||||
|
||||
|
||||
def get_path():
|
||||
"""Returns the path to the directory for `numba.cext`.
|
||||
"""
|
||||
return os.path.abspath(os.path.join(os.path.dirname(__file__)))
|
||||
Binary file not shown.
@@ -0,0 +1,21 @@
|
||||
#ifndef NUMBA_EXTENSION_HELPER_H_
|
||||
#define NUMBA_EXTENSION_HELPER_H_
|
||||
|
||||
#include "Python.h"
|
||||
#include "../_numba_common.h"
|
||||
|
||||
/* Define all runtime-required symbols in this C module, but do not
|
||||
export them outside the shared library if possible. */
|
||||
#define NUMBA_EXPORT_FUNC(_rettype) VISIBILITY_HIDDEN _rettype
|
||||
#define NUMBA_EXPORT_DATA(_vartype) VISIBILITY_HIDDEN _vartype
|
||||
|
||||
/* Use to declare a symbol as exported (global). */
|
||||
#define NUMBA_GLOBAL_FUNC(_rettype) VISIBILITY_GLOBAL _rettype
|
||||
|
||||
NUMBA_EXPORT_FUNC(Py_ssize_t)
|
||||
aligned_size(Py_ssize_t sz);
|
||||
|
||||
#include "dictobject.h"
|
||||
#include "listobject.h"
|
||||
|
||||
#endif // end NUMBA_EXTENSION_HELPER_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,228 @@
|
||||
/* Adapted from CPython3.7 Objects/dict-common.h */
|
||||
#include "cext.h"
|
||||
|
||||
#ifndef NUMBA_DICT_COMMON_H
|
||||
#define NUMBA_DICT_COMMON_H
|
||||
|
||||
typedef struct {
|
||||
/* Uses Py_ssize_t instead of Py_hash_t to guarantee word size alignment */
|
||||
Py_ssize_t hash;
|
||||
char keyvalue[];
|
||||
} NB_DictEntry;
|
||||
|
||||
|
||||
typedef int (*dict_key_comparator_t)(const char *lhs, const char *rhs);
|
||||
typedef void (*dict_refcount_op_t)(const void*);
|
||||
|
||||
|
||||
typedef struct {
|
||||
dict_key_comparator_t key_equal;
|
||||
dict_refcount_op_t key_incref;
|
||||
dict_refcount_op_t key_decref;
|
||||
dict_refcount_op_t value_incref;
|
||||
dict_refcount_op_t value_decref;
|
||||
} type_based_methods_table;
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* hash table size */
|
||||
Py_ssize_t size;
|
||||
/* Usable size of the hash table.
|
||||
Also, size of the entries */
|
||||
Py_ssize_t usable;
|
||||
/* hash table used entries */
|
||||
Py_ssize_t nentries;
|
||||
/* Entry info
|
||||
- key_size is the sizeof key type
|
||||
- val_size is the sizeof value type
|
||||
- entry_size is key_size + val_size + alignment
|
||||
*/
|
||||
Py_ssize_t key_size, val_size, entry_size;
|
||||
/* Byte offset from indices to the first entry. */
|
||||
Py_ssize_t entry_offset;
|
||||
|
||||
/* Method table for type-dependent operations. */
|
||||
type_based_methods_table methods;
|
||||
|
||||
/* hash table */
|
||||
char indices[];
|
||||
} NB_DictKeys;
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* num of elements in the hashtable */
|
||||
Py_ssize_t used;
|
||||
NB_DictKeys *keys;
|
||||
} NB_Dict;
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* parent dictionary */
|
||||
NB_Dict *parent;
|
||||
/* parent keys object */
|
||||
NB_DictKeys *parent_keys;
|
||||
/* dict size */
|
||||
Py_ssize_t size;
|
||||
/* iterator position; indicates the next position to read */
|
||||
Py_ssize_t pos;
|
||||
} NB_DictIter;
|
||||
|
||||
|
||||
|
||||
/* A test function for the dict
|
||||
Returns 0 for OK; 1 for failure.
|
||||
*/
|
||||
NUMBA_EXPORT_FUNC(int)
|
||||
numba_test_dict(void);
|
||||
|
||||
/* Allocate a new dict
|
||||
Parameters
|
||||
- NB_Dict **out
|
||||
Output for the new dictionary.
|
||||
- Py_ssize_t size
|
||||
Hashtable size. Must be power of two.
|
||||
- Py_ssize_t key_size
|
||||
Size of a key entry.
|
||||
- Py_ssize_t val_size
|
||||
Size of a value entry.
|
||||
*/
|
||||
NUMBA_EXPORT_FUNC(int)
|
||||
numba_dict_new(NB_Dict **out, Py_ssize_t size, Py_ssize_t key_size, Py_ssize_t val_size);
|
||||
|
||||
/* Allocate a new dict with enough space to hold n_keys without resizing.
|
||||
Parameters
|
||||
- NB_Dict **out
|
||||
Output for the new dictionary.
|
||||
- Py_ssize_t n_keys
|
||||
The number of keys to fit without needing resize.
|
||||
- Py_ssize_t key_size
|
||||
Size of a key entry.
|
||||
- Py_ssize_t val_size
|
||||
Size of a value entry.
|
||||
*/
|
||||
NUMBA_EXPORT_FUNC(int)
|
||||
numba_dict_new_sized(NB_Dict** out, Py_ssize_t n_keys, Py_ssize_t key_size, Py_ssize_t val_size);
|
||||
|
||||
/* Free a dict */
|
||||
NUMBA_EXPORT_FUNC(void)
|
||||
numba_dict_free(NB_Dict *d);
|
||||
|
||||
/* Returns length of a dict */
|
||||
NUMBA_EXPORT_FUNC(Py_ssize_t)
|
||||
numba_dict_length(NB_Dict *d);
|
||||
|
||||
/* Set the method table for type specific operations
|
||||
*/
|
||||
NUMBA_EXPORT_FUNC(void)
|
||||
numba_dict_set_method_table(NB_Dict *d, type_based_methods_table *methods);
|
||||
|
||||
/* Lookup a key
|
||||
|
||||
Parameters
|
||||
- NB_Dict *d
|
||||
The dictionary object.
|
||||
- const char *key_bytes
|
||||
The key as a byte buffer.
|
||||
- Py_hash_t hash
|
||||
The precomputed hash of the key.
|
||||
- char *oldval_bytes
|
||||
An output parameter to store the associated value if the key is found.
|
||||
Must point to memory of sufficient size to store the value.
|
||||
*/
|
||||
NUMBA_EXPORT_FUNC(Py_ssize_t)
|
||||
numba_dict_lookup(NB_Dict *d, const char *key_bytes, Py_hash_t hash, char *oldval_bytes);
|
||||
|
||||
/* Resize the dict to at least *minsize*.
|
||||
*/
|
||||
NUMBA_EXPORT_FUNC(int)
|
||||
numba_dict_resize(NB_Dict *d, Py_ssize_t minsize);
|
||||
|
||||
/* Insert to the dict
|
||||
|
||||
Parameters
|
||||
- NB_Dict *d
|
||||
The dictionary object.
|
||||
- const char *key_bytes
|
||||
The key as a byte buffer.
|
||||
- Py_hash_t hash
|
||||
The precomputed hash of key.
|
||||
- const char *val_bytes
|
||||
The value as a byte buffer.
|
||||
- char *oldval_bytes
|
||||
An output buffer to store the replaced value.
|
||||
Must point to memory of sufficient size to store the value.
|
||||
|
||||
Returns
|
||||
- < 0 for error
|
||||
- 0 for ok
|
||||
- 1 for ok and oldval_bytes has a copy of the replaced value.
|
||||
*/
|
||||
NUMBA_EXPORT_FUNC(int)
|
||||
numba_dict_insert(NB_Dict *d, const char *key_bytes, Py_hash_t hash, const char *val_bytes, char *oldval_bytes);
|
||||
|
||||
/* Same as numba_dict_insert() but oldval_bytes is not needed */
|
||||
NUMBA_EXPORT_FUNC(int)
|
||||
numba_dict_insert_ez(NB_Dict *d, const char *key_bytes, Py_hash_t hash, const char *val_bytes);
|
||||
|
||||
/* Delete an entry from the dict
|
||||
Parameters
|
||||
- NB_Dict *d
|
||||
The dictionary
|
||||
- Py_hash_t hash
|
||||
Precomputed hash of the key to be deleted
|
||||
- Py_ssize_t ix
|
||||
Precomputed entry index of the key to be deleted.
|
||||
Usually results of numba_dict_lookup().
|
||||
*/
|
||||
NUMBA_EXPORT_FUNC(int)
|
||||
numba_dict_delitem(NB_Dict *d, Py_hash_t hash, Py_ssize_t ix);
|
||||
|
||||
/* Remove an item from the dict
|
||||
Parameters
|
||||
- NB_Dict *d
|
||||
The dictionary
|
||||
- char *key_bytes
|
||||
Output. The key as a byte buffer
|
||||
- char *val_bytes
|
||||
Output. The value as a byte buffer
|
||||
*/
|
||||
NUMBA_EXPORT_FUNC(int)
|
||||
numba_dict_popitem(NB_Dict *d, char *key_bytes, char *val_bytes);
|
||||
|
||||
/* Returns the sizeof a dictionary iterator
|
||||
*/
|
||||
NUMBA_EXPORT_FUNC(size_t)
|
||||
numba_dict_iter_sizeof(void);
|
||||
|
||||
/* Fill a NB_DictIter for a dictionary to begin iteration
|
||||
Parameters
|
||||
- NB_DictIter *it
|
||||
Output. Must points to memory of size at least `numba_dict_iter_sizeof()`.
|
||||
- NB_Dict *d
|
||||
The dictionary to be iterated.
|
||||
*/
|
||||
NUMBA_EXPORT_FUNC(void)
|
||||
numba_dict_iter(NB_DictIter *it, NB_Dict *d);
|
||||
|
||||
/* Advance the iterator
|
||||
Parameters
|
||||
- NB_DictIter *it
|
||||
The iterator
|
||||
- const char **key_ptr
|
||||
Output pointer for the key. Points to data in the dictionary.
|
||||
- const char **val_ptr
|
||||
Output pointer for the key. Points to data in the dictionary.
|
||||
|
||||
Returns
|
||||
- 0 for success; valid key_ptr and val_ptr
|
||||
- ERR_ITER_EXHAUSTED for end of iterator.
|
||||
- ERR_DICT_MUTATED for detected dictionary mutation.
|
||||
*/
|
||||
NUMBA_EXPORT_FUNC(int)
|
||||
numba_dict_iter_next(NB_DictIter *it, const char **key_ptr, const char **val_ptr);
|
||||
|
||||
|
||||
NUMBA_EXPORT_FUNC(void)
|
||||
numba_dict_dump(NB_Dict *);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,977 @@
|
||||
#include "listobject.h"
|
||||
|
||||
/* This implements the C component of the Numba typed list. It is loosely
|
||||
* inspired by the list implementation of the cpython list with some parts
|
||||
* taken from the cpython slice implementation. The exact commit-id of the
|
||||
* relevant files are:
|
||||
*
|
||||
* https://github.com/python/cpython/blob/51ddab8dae056867f3595ab3400bffc93f67c8d4/Objects/listobject.c
|
||||
* https://github.com/python/cpython/blob/51ddab8dae056867f3595ab3400bffc93f67c8d4/Objects/sliceobject.c
|
||||
*
|
||||
* Algorithmically, this list is very similar to the cpython implementation so
|
||||
* it should have the same performance (Big-O) characteristics for accessing,
|
||||
* adding and removing elements/items. Specifically, it implements the same
|
||||
* algorithms for list overallocation and growth. However, it never deals with
|
||||
* PyObject types and instead must be typed with a type-size. As a result, the
|
||||
* typed-list is type homogeneous and in contrast to the cpython version can
|
||||
* not store a mixture of arbitrarily typed objects. Reference counting via the
|
||||
* Numba Runtime (NRT) is supported and incrementing and decrementing functions
|
||||
* are store as part of the struct and can be setup from the compiler level.
|
||||
*
|
||||
* Importantly, only a very limited subset of the cpython c functions have been
|
||||
* ported over and the rest have been implemented (in Python) at the compiler
|
||||
* level using the c functions provided. Additionally, initialization of, and
|
||||
* iteration over, a ListIter is provided
|
||||
*
|
||||
* The following functions are implemented for the list:
|
||||
*
|
||||
* - Check valid index valid_index
|
||||
* - Creation numba_list_new
|
||||
* - Deletion numba_list_free
|
||||
* - Accessing the length numba_list_length
|
||||
* - Appending to the list numba_list_append
|
||||
* - Getting an item numba_list_setitem
|
||||
* - Setting an item numba_list_getitem
|
||||
* - Resizing the list numba_list_resize
|
||||
* - Deleting an item numba_list_delitem
|
||||
* - Deleting a slice numba_list_delete_slice
|
||||
*
|
||||
* As you can see, only a single function for slices is implemented. The rest
|
||||
* is all done entirely at the compiler level which then calls the c functions
|
||||
* to mutate the list accordingly. Since slicing allows for replace, insert and
|
||||
* delete operations over multiple items, we can simply implement those using
|
||||
* the basic functions above.
|
||||
*
|
||||
* The following additional functions are implemented for the list, these are
|
||||
* needed to make the list work within Numba.
|
||||
*
|
||||
* - Accessing the allocation numba_list_allocated
|
||||
* - Copying an item copy_item
|
||||
* - Calling incref on item list_incref_item
|
||||
* - Calling decref on item list_decref_item
|
||||
* - Set method table numba_list_set_method_table
|
||||
*
|
||||
* The following functions are implemented for the iterator:
|
||||
*
|
||||
* - Size of the iterator numba_list_iter_size
|
||||
* - Initialization of iter numba_list_iter
|
||||
* - Get next item from iter numba_list_iter_next
|
||||
*
|
||||
* Two methods are provided to query and set the 'is_mutable':
|
||||
*
|
||||
* - Query numba_list_is_mutable
|
||||
* - Set numba_list_set_is_mutable
|
||||
*
|
||||
* Lastly a set of pure C level tests are provided which come in handy when
|
||||
* needing to use valgrind and friends.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
/* Return status for the list functions.
|
||||
*/
|
||||
typedef enum {
|
||||
LIST_OK = 0,
|
||||
LIST_ERR_INDEX = -1,
|
||||
LIST_ERR_NO_MEMORY = -2,
|
||||
LIST_ERR_MUTATED = -3,
|
||||
LIST_ERR_ITER_EXHAUSTED = -4,
|
||||
LIST_ERR_IMMUTABLE = -5,
|
||||
} ListStatus;
|
||||
|
||||
/* Copy an item from a list.
|
||||
*
|
||||
* lp: a list
|
||||
* dst: destination pointer
|
||||
* src: source pointer
|
||||
*/
|
||||
static void
|
||||
copy_item(NB_List *lp, char *dst, const char *src){
|
||||
memcpy(dst, src, lp->item_size);
|
||||
}
|
||||
|
||||
/* Increment a reference to an item in a list.
|
||||
*
|
||||
* lp: a list
|
||||
* item: the item to increment the reference for
|
||||
*/
|
||||
static void
|
||||
list_incref_item(NB_List *lp, const char *item){
|
||||
if (lp->methods.item_incref) {
|
||||
lp->methods.item_incref(item);
|
||||
}
|
||||
}
|
||||
|
||||
/* Decrement a reference to an item in a list.
|
||||
*
|
||||
* lp: a list
|
||||
* item: the item to decrement the reference for
|
||||
*/
|
||||
static void
|
||||
list_decref_item(NB_List *lp, const char *item){
|
||||
if (lp->methods.item_decref) {
|
||||
lp->methods.item_decref(item);
|
||||
}
|
||||
}
|
||||
|
||||
/* Setup the method table for a list.
|
||||
*
|
||||
* This function is used from the compiler level to initialize the internal
|
||||
* method table.
|
||||
*
|
||||
* lp: a list
|
||||
* methods: the methods table to set up
|
||||
*/
|
||||
void
|
||||
numba_list_set_method_table(NB_List *lp, list_type_based_methods_table *methods)
|
||||
{
|
||||
memcpy(&lp->methods, methods, sizeof(list_type_based_methods_table));
|
||||
}
|
||||
|
||||
/* Check if a list index is valid.
|
||||
*
|
||||
* i: the index to check
|
||||
* limit: the size of a list
|
||||
*
|
||||
* Adapted from CPython's valid_index().
|
||||
*
|
||||
* FIXME: need to find a way to inline this, even for Python 2.7 on Windows
|
||||
*/
|
||||
static int
|
||||
valid_index(Py_ssize_t i, Py_ssize_t limit){
|
||||
/* The cast to size_t lets us use just a single comparison
|
||||
to check whether i is in the range: 0 <= i < limit.
|
||||
|
||||
See: Section 14.2 "Bounds Checking" in the Agner Fog
|
||||
optimization manual found at:
|
||||
https://www.agner.org/optimize/optimizing_cpp.pdf
|
||||
*/
|
||||
return (size_t) i < (size_t) limit;
|
||||
}
|
||||
|
||||
/* Initialize a new list.
|
||||
*
|
||||
* out: pointer to hold an initialized list
|
||||
* item_size: the size in bytes of the items in the list
|
||||
* allocated: preallocation of the list in items
|
||||
*
|
||||
* This will allocate sufficient memory to hold the list structure and any
|
||||
* items if requested (allocated != 0). See _listobject.h for more information
|
||||
* on the NB_List struct.
|
||||
*/
|
||||
int
|
||||
numba_list_new(NB_List **out, Py_ssize_t item_size, Py_ssize_t allocated){
|
||||
NB_List *lp;
|
||||
char *items;
|
||||
// allocate memory to hold the struct
|
||||
lp = malloc(aligned_size(sizeof(NB_List)));
|
||||
if (lp == NULL) {
|
||||
return LIST_ERR_NO_MEMORY;
|
||||
}
|
||||
// set up members
|
||||
lp->size = 0;
|
||||
lp->item_size = item_size;
|
||||
lp->allocated = allocated;
|
||||
lp->is_mutable = 1;
|
||||
// set method table to zero */
|
||||
memset(&lp->methods, 0x00, sizeof(list_type_based_methods_table));
|
||||
// allocate memory to hold items, if requested
|
||||
if (allocated != 0) {
|
||||
items = malloc(aligned_size(lp->item_size * allocated));
|
||||
// allocated was definitely not zero, if malloc returns NULL
|
||||
// this is definitely an error
|
||||
if (items == NULL) {
|
||||
// free previously allocated struct to avoid leaking memory
|
||||
free(lp);
|
||||
return LIST_ERR_NO_MEMORY;
|
||||
}
|
||||
lp->items = items;
|
||||
}
|
||||
else {
|
||||
// be explicit
|
||||
lp->items = NULL;
|
||||
}
|
||||
*out = lp;
|
||||
return LIST_OK;
|
||||
}
|
||||
|
||||
/* Free the memory associated with a list.
|
||||
*
|
||||
* lp: a list
|
||||
*/
|
||||
void
|
||||
numba_list_free(NB_List *lp) {
|
||||
// decref all items, if needed
|
||||
Py_ssize_t i;
|
||||
if (lp->methods.item_decref) {
|
||||
for (i = 0; i < lp->size; i++) {
|
||||
char *item = lp->items + lp->item_size * i;
|
||||
list_decref_item(lp, item);
|
||||
}
|
||||
}
|
||||
// free items and list
|
||||
if (lp->items != NULL) {
|
||||
free(lp->items);
|
||||
}
|
||||
free(lp);
|
||||
}
|
||||
|
||||
/* Return the base pointer of the list items.
|
||||
*/
|
||||
char *
|
||||
numba_list_base_ptr(NB_List *lp)
|
||||
{
|
||||
return lp->items;
|
||||
}
|
||||
|
||||
/* Return the address of the list size.
|
||||
*/
|
||||
Py_ssize_t
|
||||
numba_list_size_address(NB_List *lp)
|
||||
{
|
||||
return (Py_ssize_t)&lp->size;
|
||||
}
|
||||
|
||||
|
||||
/* Return the length of a list.
|
||||
*
|
||||
* lp: a list
|
||||
*/
|
||||
Py_ssize_t
|
||||
numba_list_length(NB_List *lp) {
|
||||
return lp->size;
|
||||
}
|
||||
|
||||
/* Return the current allocation of a list.
|
||||
*
|
||||
* lp: a list
|
||||
*/
|
||||
Py_ssize_t
|
||||
numba_list_allocated(NB_List *lp) {
|
||||
return lp->allocated;
|
||||
}
|
||||
|
||||
/* Return the mutability status of the list
|
||||
*
|
||||
* lp: a list
|
||||
*
|
||||
*/
|
||||
int
|
||||
numba_list_is_mutable(NB_List *lp){
|
||||
return lp->is_mutable;
|
||||
}
|
||||
|
||||
/* Set the is_mutable attribute
|
||||
*
|
||||
* lp: a list
|
||||
* is_mutable: an int, 0(False) or 1(True)
|
||||
*
|
||||
*/
|
||||
void
|
||||
numba_list_set_is_mutable(NB_List *lp, int is_mutable){
|
||||
lp->is_mutable = is_mutable;
|
||||
}
|
||||
|
||||
/* Set an item in a list.
|
||||
*
|
||||
* lp: a list
|
||||
* index: the index of the item to set (must be in range 0 <= index < len(list))
|
||||
* item: the item to set
|
||||
*
|
||||
* This assume there is already an element at the given index that will be
|
||||
* overwritten and thereby have its reference decremented. DO NOT use this to
|
||||
* write to an unassigned location.
|
||||
*/
|
||||
int
|
||||
numba_list_setitem(NB_List *lp, Py_ssize_t index, const char *item) {
|
||||
char *loc;
|
||||
// check for mutability
|
||||
if (!lp->is_mutable) {
|
||||
return LIST_ERR_IMMUTABLE;
|
||||
}
|
||||
// check index is valid
|
||||
// FIXME: this can be (and probably is) checked at the compiler level
|
||||
if (!valid_index(index, lp->size)) {
|
||||
return LIST_ERR_INDEX;
|
||||
}
|
||||
// set item at desired location
|
||||
loc = lp->items + lp-> item_size * index;
|
||||
list_decref_item(lp, loc);
|
||||
copy_item(lp, loc, item);
|
||||
list_incref_item(lp, loc);
|
||||
return LIST_OK;
|
||||
}
|
||||
|
||||
/* Get an item from a list.
|
||||
*
|
||||
* lp: a list
|
||||
* index: the index of the item to get (must be in range 0 <= index < len(list))
|
||||
* out: a pointer to hold the item
|
||||
*/
|
||||
int
|
||||
numba_list_getitem(NB_List *lp, Py_ssize_t index, char *out) {
|
||||
char *loc;
|
||||
// check index is valid
|
||||
// FIXME: this can be (and probably is) checked at the compiler level
|
||||
if (!valid_index(index, lp->size)) {
|
||||
return LIST_ERR_INDEX;
|
||||
}
|
||||
// get item at desired location
|
||||
loc = lp->items + lp->item_size * index;
|
||||
copy_item(lp, out, loc);
|
||||
return LIST_OK;
|
||||
}
|
||||
|
||||
/* Append an item to the end of a list.
|
||||
*
|
||||
* lp: a list
|
||||
* item: the item to append.
|
||||
*/
|
||||
int
|
||||
numba_list_append(NB_List *lp, const char *item) {
|
||||
char *loc;
|
||||
// check for mutability
|
||||
if (!lp->is_mutable) {
|
||||
return LIST_ERR_IMMUTABLE;
|
||||
}
|
||||
// resize by one, will change list size
|
||||
int result = numba_list_resize(lp, lp->size + 1);
|
||||
if(result < LIST_OK) {
|
||||
return result;
|
||||
}
|
||||
// insert item at index: original size before resize
|
||||
loc = lp->items + lp->item_size * (lp->size - 1);
|
||||
copy_item(lp, loc, item);
|
||||
list_incref_item(lp, loc);
|
||||
return LIST_OK;
|
||||
}
|
||||
|
||||
/* Resize a list.
|
||||
*
|
||||
* lp: a list
|
||||
* newsize: the desired new size of the list.
|
||||
*
|
||||
* This will increase or decrease the size of the list, including reallocating
|
||||
* the required memory and increasing the total allocation (additional free
|
||||
* space to hold new items).
|
||||
*
|
||||
*
|
||||
* Adapted from CPython's list_resize().
|
||||
*
|
||||
* Ensure lp->items has room for at least newsize elements, and set
|
||||
* lp->size to newsize. If newsize > lp->size on entry, the content
|
||||
* of the new slots at exit is undefined heap trash; it's the caller's
|
||||
* responsibility to overwrite them with sane values.
|
||||
* The number of allocated elements may grow, shrink, or stay the same.
|
||||
* Failure is impossible if newsize <= lp->allocated on entry, although
|
||||
* that partly relies on an assumption that the system realloc() never
|
||||
* fails when passed a number of bytes <= the number of bytes last
|
||||
* allocated (the C standard doesn't guarantee this, but it's hard to
|
||||
* imagine a realloc implementation where it wouldn't be true).
|
||||
* Note that lp->items may change, and even if newsize is less
|
||||
* than lp->size on entry.
|
||||
*/
|
||||
int
|
||||
numba_list_resize(NB_List *lp, Py_ssize_t newsize) {
|
||||
char * items;
|
||||
// check for mutability
|
||||
if (!lp->is_mutable) {
|
||||
return LIST_ERR_IMMUTABLE;
|
||||
}
|
||||
size_t new_allocated, num_allocated_bytes;
|
||||
/* Bypass realloc() when a previous overallocation is large enough
|
||||
to accommodate the newsize. If the newsize falls lower than half
|
||||
the allocated size, then proceed with the realloc() to shrink the list.
|
||||
*/
|
||||
if (lp->allocated >= newsize && newsize >= (lp->allocated >> 1)) {
|
||||
assert(lp->items != NULL || newsize == 0);
|
||||
lp->size = newsize;
|
||||
return LIST_OK;
|
||||
}
|
||||
/* This over-allocates proportional to the list size, making room
|
||||
* for additional growth. The over-allocation is mild, but is
|
||||
* enough to give linear-time amortized behavior over a long
|
||||
* sequence of appends() in the presence of a poorly-performing
|
||||
* system realloc().
|
||||
* The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
|
||||
* Note: new_allocated won't overflow because the largest possible value
|
||||
* is PY_SSIZE_T_MAX * (9 / 8) + 6 which always fits in a size_t.
|
||||
*/
|
||||
new_allocated = (size_t)newsize + (newsize >> 3) + (newsize < 9 ? 3 : 6);
|
||||
if (new_allocated > (size_t)PY_SSIZE_T_MAX / lp->item_size) {
|
||||
return LIST_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
if (newsize == 0)
|
||||
new_allocated = 0;
|
||||
num_allocated_bytes = new_allocated * lp->item_size;
|
||||
items = realloc(lp->items, aligned_size(num_allocated_bytes));
|
||||
// realloc may return NULL if requested size is 0
|
||||
if (num_allocated_bytes != 0 && items == NULL) {
|
||||
return LIST_ERR_NO_MEMORY;
|
||||
}
|
||||
lp->items = items;
|
||||
lp->size = newsize;
|
||||
lp->allocated = (Py_ssize_t)new_allocated;
|
||||
return LIST_OK;
|
||||
}
|
||||
|
||||
/* Delete a single item.
|
||||
*
|
||||
* lp: a list
|
||||
* index: the index of the item to delete
|
||||
* (must be in range 0 <= index < len(list))
|
||||
*
|
||||
* */
|
||||
int
|
||||
numba_list_delitem(NB_List *lp, Py_ssize_t index) {
|
||||
int result;
|
||||
char *loc, *new_loc;
|
||||
Py_ssize_t leftover_bytes;
|
||||
// check for mutability
|
||||
if (!lp->is_mutable) {
|
||||
return LIST_ERR_IMMUTABLE;
|
||||
}
|
||||
// check index is valid
|
||||
// FIXME: this can be (and probably is) checked at the compiler level
|
||||
if (!valid_index(index, lp->size)) {
|
||||
return LIST_ERR_INDEX;
|
||||
}
|
||||
// obtain item and decref if needed
|
||||
loc = lp->items + lp->item_size * index;
|
||||
list_decref_item(lp, loc);
|
||||
if (index != lp->size - 1) {
|
||||
// delitem from somewhere other than the end, incur the memory copy
|
||||
leftover_bytes = (lp->size - 1 - index) * lp->item_size;
|
||||
new_loc = lp->items + (lp->item_size * (index + 1));
|
||||
// use memmove instead of memcpy since we may be dealing with
|
||||
// overlapping regions of memory and the behaviour of memcpy is
|
||||
// undefined in such situation (C99).
|
||||
memmove(loc, new_loc, leftover_bytes);
|
||||
}
|
||||
// finally, shrink list by one
|
||||
result = numba_list_resize(lp, lp->size - 1);
|
||||
if(result < LIST_OK) {
|
||||
// Since we are decreasing the size, this should never happen
|
||||
return result;
|
||||
}
|
||||
return LIST_OK;
|
||||
|
||||
}
|
||||
|
||||
/* Delete a slice
|
||||
*
|
||||
* start: the start index of ths slice
|
||||
* stop: the stop index of the slice (not included)
|
||||
* step: the step to take
|
||||
*
|
||||
* This function assumes that the start and stop were clipped appropriately.
|
||||
* I.e. if step > 0 start >= 0 and stop <= len(l) and
|
||||
* if step < 0 start <= length and stop >= -1
|
||||
* step != 0 and no Python negative indexing allowed.
|
||||
*
|
||||
* This code was copied and edited from the relevant section in
|
||||
* list_ass_subscript from the cpython implementation, see the top of this file
|
||||
* for the exact source
|
||||
*/
|
||||
int
|
||||
numba_list_delete_slice(NB_List *lp,
|
||||
Py_ssize_t start, Py_ssize_t stop, Py_ssize_t step) {
|
||||
int result, i, slicelength, new_length;
|
||||
char *loc, *new_loc;
|
||||
Py_ssize_t leftover_bytes, cur, lim;
|
||||
// check for mutability
|
||||
if (!lp->is_mutable) {
|
||||
return LIST_ERR_IMMUTABLE;
|
||||
}
|
||||
// calculate the slicelength, taken from PySlice_AdjustIndices, see the top
|
||||
// of this file for the exact source
|
||||
if (step > 0) {
|
||||
slicelength = start < stop ? (stop - start - 1) / step + 1 : 0;
|
||||
} else {
|
||||
slicelength = stop < start ? (start - stop - 1) / -step + 1 : 0;
|
||||
}
|
||||
if (slicelength <= 0){
|
||||
return LIST_OK;
|
||||
}
|
||||
new_length = lp->size - slicelength;
|
||||
// reverse step and indices
|
||||
if (step < 0) {
|
||||
stop = start + 1;
|
||||
start = stop + step * (slicelength - 1) - 1;
|
||||
step = -step;
|
||||
}
|
||||
if (step == 1) {
|
||||
// decref if needed
|
||||
if (lp->methods.item_decref) {
|
||||
for (i = start ; i < stop ; i++){
|
||||
loc = lp->items + lp->item_size * i;
|
||||
lp->methods.item_decref(loc);
|
||||
}
|
||||
}
|
||||
// memmove items into place
|
||||
leftover_bytes = (lp->size - stop) * lp->item_size;
|
||||
loc = lp->items + lp->item_size * start;
|
||||
new_loc = lp->items + lp->item_size * stop;
|
||||
memmove(loc, new_loc, leftover_bytes);
|
||||
}
|
||||
else { // step != 1
|
||||
/* drawing pictures might help understand these for
|
||||
* loops. Basically, we memmove the parts of the
|
||||
* list that are *not* part of the slice: step-1
|
||||
* items for each item that is part of the slice,
|
||||
* and then tail end of the list that was not
|
||||
* covered by the slice
|
||||
*
|
||||
* */
|
||||
for (cur = start, // index of item to be deleted
|
||||
i = 0; // counter of total items deleted so far
|
||||
cur < stop;
|
||||
cur += step,
|
||||
i++) {
|
||||
lim = step - 1; // number of leftover items after deletion of item
|
||||
// clip limit, in case we are at the end of the slice, and there
|
||||
// are now less than step-1 items to be moved
|
||||
if (cur + step >= lp->size) {
|
||||
lim = lp->size - cur - 1;
|
||||
}
|
||||
// decref item being removed
|
||||
loc = lp->items + lp->item_size * cur;
|
||||
list_decref_item(lp, loc);
|
||||
/* memmove the aforementioned step-1 (or less) items
|
||||
* dst : index of deleted item minus total deleted sofar
|
||||
* src : index of deleted item plus one (next item)
|
||||
*/
|
||||
memmove(lp->items + lp->item_size * (cur - i),
|
||||
lp->items + lp->item_size * (cur + 1),
|
||||
lim * lp->item_size);
|
||||
}
|
||||
// memmove tail of the list
|
||||
cur = start + slicelength * step;
|
||||
if (cur < lp->size) {
|
||||
memmove(lp->items + lp->item_size * (cur - slicelength),
|
||||
lp->items + lp->item_size * cur,
|
||||
(lp->size - cur) * lp->item_size);
|
||||
}
|
||||
}
|
||||
// resize to correct size
|
||||
result = numba_list_resize(lp, new_length);
|
||||
if(result < LIST_OK) {
|
||||
// Since we are decreasing the size, this should never happen
|
||||
return result;
|
||||
}
|
||||
return LIST_OK;
|
||||
}
|
||||
|
||||
|
||||
/* Return the size of the list iterator (NB_ListIter) struct.
|
||||
*/
|
||||
size_t
|
||||
numba_list_iter_sizeof() {
|
||||
return sizeof(NB_ListIter);
|
||||
}
|
||||
|
||||
/* Initialize a list iterator (NB_ListIter).
|
||||
*
|
||||
* it: an iterator
|
||||
* lp: a list to iterate over
|
||||
*/
|
||||
void
|
||||
numba_list_iter(NB_ListIter *it, NB_List *lp) {
|
||||
// set members of iterator
|
||||
it->parent = lp;
|
||||
it->size = lp->size;
|
||||
it->pos = 0;
|
||||
}
|
||||
|
||||
/* Obtain the next item from a list iterator.
|
||||
*
|
||||
* it: an iterator
|
||||
* item_ptr: pointer to hold the next item
|
||||
*/
|
||||
int
|
||||
numba_list_iter_next(NB_ListIter *it, const char **item_ptr) {
|
||||
NB_List *lp;
|
||||
lp = it->parent;
|
||||
/* FIXME: Detect list mutation during iteration */
|
||||
if (lp->size != it->size) {
|
||||
return LIST_ERR_MUTATED;
|
||||
}
|
||||
// get next element
|
||||
if (it->pos < lp->size) {
|
||||
*item_ptr = lp->items + lp->item_size * it->pos++;
|
||||
return LIST_OK;
|
||||
}else{
|
||||
return LIST_ERR_ITER_EXHAUSTED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#define CHECK(CASE) { \
|
||||
if ( !(CASE) ) { \
|
||||
printf("'%s' failed file %s:%d\n", #CASE, __FILE__, __LINE__); \
|
||||
return -1; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Basic C based tests for the list.
|
||||
*/
|
||||
int
|
||||
numba_test_list(void) {
|
||||
NB_List *lp = NULL;
|
||||
int status, i;
|
||||
Py_ssize_t it_count;
|
||||
const char *it_item = NULL;
|
||||
NB_ListIter iter;
|
||||
char got_item[4] = "\x00\x00\x00\x00";
|
||||
const char *test_items_1 = NULL, *test_items_2 = NULL;
|
||||
char *test_items_3 = NULL;
|
||||
puts("test_list");
|
||||
|
||||
|
||||
status = numba_list_new(&lp, 4, 0);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->item_size == 4);
|
||||
CHECK(lp->size == 0);
|
||||
CHECK(lp->allocated == 0);
|
||||
CHECK(lp->is_mutable == 1);
|
||||
|
||||
// flip and check the is_mutable bit
|
||||
CHECK(numba_list_is_mutable(lp) == 1);
|
||||
numba_list_set_is_mutable(lp, 0);
|
||||
CHECK(numba_list_is_mutable(lp) == 0);
|
||||
numba_list_set_is_mutable(lp, 1);
|
||||
CHECK(numba_list_is_mutable(lp) == 1);
|
||||
|
||||
// append 1st item, this will cause a realloc
|
||||
status = numba_list_append(lp, "abc");
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->size == 1);
|
||||
CHECK(lp->allocated == 4);
|
||||
status = numba_list_getitem(lp, 0, got_item);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(memcmp(got_item, "abc", 4) == 0);
|
||||
|
||||
// append 2nd item
|
||||
status = numba_list_append(lp, "def");
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->size == 2);
|
||||
CHECK(lp->allocated == 4);
|
||||
status = numba_list_getitem(lp, 1, got_item);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(memcmp(got_item, "def", 4) == 0);
|
||||
|
||||
// append 3rd item
|
||||
status = numba_list_append(lp, "ghi");
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->size == 3);
|
||||
CHECK(lp->allocated == 4);
|
||||
status = numba_list_getitem(lp, 2, got_item);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(memcmp(got_item, "ghi", 4) == 0);
|
||||
|
||||
// append 4th item
|
||||
status = numba_list_append(lp, "jkl");
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->size == 4);
|
||||
CHECK(lp->allocated == 4);
|
||||
status = numba_list_getitem(lp, 3, got_item);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(memcmp(got_item, "jkl", 4) == 0);
|
||||
|
||||
// append 5th item, this will cause another realloc
|
||||
status = numba_list_append(lp, "mno");
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->size == 5);
|
||||
CHECK(lp->allocated == 8);
|
||||
status = numba_list_getitem(lp, 4, got_item);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(memcmp(got_item, "mno", 4) == 0);
|
||||
|
||||
// overwrite 1st item
|
||||
status = numba_list_setitem(lp, 0, "pqr");
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->size == 5);
|
||||
CHECK(lp->allocated == 8);
|
||||
status = numba_list_getitem(lp, 0, got_item);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(memcmp(got_item, "pqr", 4) == 0);
|
||||
|
||||
// get and del 1st item, check item shift
|
||||
status = numba_list_getitem(lp, 0, got_item);
|
||||
status = numba_list_delitem(lp, 0);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->size == 4);
|
||||
CHECK(lp->allocated == 8);
|
||||
CHECK(memcmp(got_item, "pqr", 4) == 0);
|
||||
CHECK(memcmp(lp->items, "def\x00ghi\x00jkl\x00mno\x00", 16) == 0);
|
||||
|
||||
// get and del last (4th) item, no shift since only last item affected
|
||||
status = numba_list_getitem(lp, 3, got_item);
|
||||
status = numba_list_delitem(lp, 3);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->size == 3);
|
||||
CHECK(lp->allocated == 6); // this also shrinks the allocation
|
||||
CHECK(memcmp(got_item, "mno", 4) == 0);
|
||||
CHECK(memcmp(lp->items, "def\x00ghi\x00jkl\x00", 12) == 0);
|
||||
|
||||
// flip and check the is_mutable member
|
||||
CHECK(numba_list_is_mutable(lp) == 1);
|
||||
numba_list_set_is_mutable(lp, 0);
|
||||
CHECK(numba_list_is_mutable(lp) == 0);
|
||||
|
||||
// ensure that any attempts to mutate an immutable list fail
|
||||
CHECK(numba_list_setitem(lp, 0, "zzz") == LIST_ERR_IMMUTABLE);
|
||||
CHECK(numba_list_append(lp, "zzz") == LIST_ERR_IMMUTABLE);
|
||||
CHECK(numba_list_delitem(lp, 0) == LIST_ERR_IMMUTABLE);
|
||||
CHECK(numba_list_resize(lp, 23) == LIST_ERR_IMMUTABLE);
|
||||
CHECK(numba_list_delete_slice(lp, 0, 3, 1) == LIST_ERR_IMMUTABLE);
|
||||
|
||||
// ensure that all attempts to query/read from and immutable list succeed
|
||||
CHECK(numba_list_length(lp) == 3);
|
||||
status = numba_list_getitem(lp, 0, got_item);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(memcmp(got_item, "def", 4) == 0);
|
||||
|
||||
// flip the is_mutable member back and check
|
||||
numba_list_set_is_mutable(lp, 1);
|
||||
CHECK(numba_list_is_mutable(lp) == 1);
|
||||
|
||||
// test iterator
|
||||
CHECK(lp->size > 0);
|
||||
numba_list_iter(&iter, lp);
|
||||
it_count = 0;
|
||||
CHECK(iter.parent == lp);
|
||||
CHECK(iter.pos == it_count);
|
||||
|
||||
// current contents of list
|
||||
test_items_1 = "def\x00ghi\x00jkl\x00";
|
||||
while ( (status = numba_list_iter_next(&iter, &it_item)) == LIST_OK) {
|
||||
it_count += 1;
|
||||
CHECK(iter.pos == it_count); // check iterator position
|
||||
CHECK(it_item != NULL); // quick check item is non-null
|
||||
// go fishing in test_items_1
|
||||
CHECK(memcmp((const char *)test_items_1 + ((it_count - 1) * 4), it_item, 4) == 0);
|
||||
}
|
||||
|
||||
CHECK(status == LIST_ERR_ITER_EXHAUSTED);
|
||||
CHECK(lp->size == it_count);
|
||||
|
||||
// free existing list
|
||||
numba_list_free(lp);
|
||||
|
||||
// test growth upon append and shrink during delitem
|
||||
status = numba_list_new(&lp, 1, 0);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->item_size == 1);
|
||||
CHECK(lp->size == 0);
|
||||
CHECK(lp->allocated == 0);
|
||||
|
||||
// first, grow the list
|
||||
// Use exactly 17 elements, should go through the allocation pattern:
|
||||
// 0, 4, 8, 16, 25
|
||||
for (i = 0; i < 17 ; i++) {
|
||||
switch(i) {
|
||||
// Check the allocation before
|
||||
case 0: CHECK(lp->allocated == 0); break;
|
||||
case 4: CHECK(lp->allocated == 4); break;
|
||||
case 8: CHECK(lp->allocated == 8); break;
|
||||
case 16: CHECK(lp->allocated == 16); break;
|
||||
}
|
||||
status = numba_list_append(lp, (const char*)&i);
|
||||
CHECK(status == LIST_OK);
|
||||
switch(i) {
|
||||
// Check that the growth happened accordingly
|
||||
case 0: CHECK(lp->allocated == 4); break;
|
||||
case 4: CHECK(lp->allocated == 8); break;
|
||||
case 8: CHECK(lp->allocated == 16); break;
|
||||
case 16: CHECK(lp->allocated == 25); break;
|
||||
}
|
||||
}
|
||||
CHECK(lp->size == 17);
|
||||
|
||||
// Check current contents of list
|
||||
test_items_2 = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10";
|
||||
CHECK(memcmp(lp->items, test_items_2, 17) == 0);
|
||||
|
||||
// Now, delete them again and check that list shrinks
|
||||
for (i = 17; i > 0 ; i--) {
|
||||
switch(i) {
|
||||
// Check the allocation before delitem
|
||||
case 17: CHECK(lp->allocated == 25); break;
|
||||
case 12: CHECK(lp->allocated == 25); break;
|
||||
case 9: CHECK(lp->allocated == 18); break;
|
||||
case 6: CHECK(lp->allocated == 12); break;
|
||||
case 4: CHECK(lp->allocated == 8); break;
|
||||
case 3: CHECK(lp->allocated == 6); break;
|
||||
case 2: CHECK(lp->allocated == 5); break;
|
||||
case 1: CHECK(lp->allocated == 4); break;
|
||||
}
|
||||
status = numba_list_getitem(lp, i-1, got_item);
|
||||
status = numba_list_delitem(lp, i-1);
|
||||
CHECK(status == LIST_OK);
|
||||
switch(i) {
|
||||
// Check that the shrink happened accordingly
|
||||
case 17: CHECK(lp->allocated == 25); break;
|
||||
case 12: CHECK(lp->allocated == 18); break;
|
||||
case 9: CHECK(lp->allocated == 12); break;
|
||||
case 6: CHECK(lp->allocated == 8); break;
|
||||
case 4: CHECK(lp->allocated == 6); break;
|
||||
case 3: CHECK(lp->allocated == 5); break;
|
||||
case 2: CHECK(lp->allocated == 4); break;
|
||||
case 1: CHECK(lp->allocated == 0); break;
|
||||
}
|
||||
}
|
||||
// free existing list
|
||||
numba_list_free(lp);
|
||||
|
||||
|
||||
// Setup list for testing delete_slice
|
||||
status = numba_list_new(&lp, 1, 0);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->item_size == 1);
|
||||
CHECK(lp->size == 0);
|
||||
CHECK(lp->allocated == 0);
|
||||
for (i = 0; i < 17 ; i++) {
|
||||
status = numba_list_append(lp, (const char*)&i);
|
||||
CHECK(status == LIST_OK);
|
||||
}
|
||||
CHECK(lp->size == 17);
|
||||
test_items_3 = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10";
|
||||
CHECK(memcmp(lp->items, test_items_3, 17) == 0);
|
||||
|
||||
// delete multiple elements from the middle
|
||||
status = numba_list_delete_slice(lp, 2, 5, 1);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->size == 14);
|
||||
test_items_3 = "\x00\x01\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10";
|
||||
CHECK(memcmp(lp->items, test_items_3, 14) == 0);
|
||||
|
||||
// delete single element from start
|
||||
status = numba_list_delete_slice(lp, 0, 1, 1);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->size == 13);
|
||||
test_items_3 = "\x01\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10";
|
||||
CHECK(memcmp(lp->items, test_items_3, 13) == 0);
|
||||
|
||||
// delete single element from end
|
||||
status = numba_list_delete_slice(lp, 12, 13, 1);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->size == 12);
|
||||
test_items_3 = "\x01\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f";
|
||||
CHECK(memcmp(lp->items, test_items_3, 12) == 0);
|
||||
|
||||
// delete single element from middle
|
||||
status = numba_list_delete_slice(lp, 4, 5, 1);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->size == 11);
|
||||
test_items_3 = "\x01\x05\x06\x07\x09\x0a\x0b\x0c\x0d\x0e\x0f";
|
||||
CHECK(memcmp(lp->items, test_items_3, 11) == 0);
|
||||
|
||||
// delete all elements except first and last
|
||||
status = numba_list_delete_slice(lp, 1, 10, 1);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->size == 2);
|
||||
test_items_3 = "\x01\x0f";
|
||||
CHECK(memcmp(lp->items, test_items_3, 2) == 0);
|
||||
|
||||
// delete all remaining elements
|
||||
status = numba_list_delete_slice(lp, 0, lp->size, 1);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->size == 0);
|
||||
test_items_3 = "";
|
||||
CHECK(memcmp(lp->items, test_items_3, 0) == 0);
|
||||
|
||||
// free existing list
|
||||
numba_list_free(lp);
|
||||
|
||||
// Setup list for testing delete_slice with non unary step
|
||||
status = numba_list_new(&lp, 1, 0);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->item_size == 1);
|
||||
CHECK(lp->size == 0);
|
||||
CHECK(lp->allocated == 0);
|
||||
for (i = 0; i < 17 ; i++) {
|
||||
status = numba_list_append(lp, (const char*)&i);
|
||||
CHECK(status == LIST_OK);
|
||||
}
|
||||
CHECK(lp->size == 17);
|
||||
|
||||
// delete all items with odd index
|
||||
status = numba_list_delete_slice(lp, 0, 17, 2);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->size == 8);
|
||||
test_items_3 = "\x01\x03\x05\x07\x09\x0b\x0d\x0f";
|
||||
CHECK(memcmp(lp->items, test_items_3, 8) == 0);
|
||||
|
||||
// delete with a step of 4, starting at index 1
|
||||
status = numba_list_delete_slice(lp, 1, 8, 4);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->size == 6);
|
||||
test_items_3 = "\x01\x05\x07\x09\x0d\x0f";
|
||||
CHECK(memcmp(lp->items, test_items_3, 6) == 0);
|
||||
|
||||
// delete with a step of 2, but finish before end of list
|
||||
status = numba_list_delete_slice(lp, 0, 4, 2);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->size == 4);
|
||||
test_items_3 = "\x05\x09\x0d\x0f";
|
||||
CHECK(memcmp(lp->items, test_items_3, 4) == 0);
|
||||
|
||||
// no-op on empty slice
|
||||
status = numba_list_delete_slice(lp, 0, 0, 1);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->size == 4);
|
||||
test_items_3 = "\x05\x09\x0d\x0f";
|
||||
CHECK(memcmp(lp->items, test_items_3, 4) == 0);
|
||||
|
||||
// no-op on empty slice, non-zero index
|
||||
status = numba_list_delete_slice(lp, 2, 2, 1);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->size == 4);
|
||||
test_items_3 = "\x05\x09\x0d\x0f";
|
||||
CHECK(memcmp(lp->items, test_items_3, 4) == 0);
|
||||
|
||||
// free list and return 0
|
||||
numba_list_free(lp);
|
||||
|
||||
// Setup list for testing delete_slice with negative step
|
||||
status = numba_list_new(&lp, 1, 0);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->item_size == 1);
|
||||
CHECK(lp->size == 0);
|
||||
CHECK(lp->allocated == 0);
|
||||
for (i = 0; i < 17 ; i++) {
|
||||
status = numba_list_append(lp, (const char*)&i);
|
||||
CHECK(status == LIST_OK);
|
||||
}
|
||||
CHECK(lp->size == 17);
|
||||
|
||||
// delete all items using unary negative slice
|
||||
status = numba_list_delete_slice(lp, 16, -1, -1);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->size == 0);
|
||||
|
||||
// refill list
|
||||
for (i = 0; i < 17 ; i++) {
|
||||
status = numba_list_append(lp, (const char*)&i);
|
||||
CHECK(status == LIST_OK);
|
||||
}
|
||||
|
||||
// delete all items using unary negative slice
|
||||
// need to start at index of last item (16) and
|
||||
// go beyond first item, i.e. -1 in Cd
|
||||
status = numba_list_delete_slice(lp, 16, -1, -2);
|
||||
CHECK(status == LIST_OK);
|
||||
CHECK(lp->size == 8);
|
||||
test_items_3 = "\x01\x03\x05\x07\x09\x0b\x0d\x0f";
|
||||
CHECK(memcmp(lp->items, test_items_3, 8) == 0);
|
||||
|
||||
// free list and return 0
|
||||
numba_list_free(lp);
|
||||
return 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
#undef CHECK
|
||||
@@ -0,0 +1,137 @@
|
||||
/* Adapted from CPython3.7 Include/listobject.h
|
||||
*
|
||||
* The exact commit-id of the relevant file is:
|
||||
*
|
||||
* https://github.com/python/cpython/blob/51ddab8dae056867f3595ab3400bffc93f67c8d4/Include/listobject.h
|
||||
*
|
||||
* WARNING:
|
||||
* Most interfaces listed here are exported (global), but they are not
|
||||
* supported, stable, or part of Numba's public API. These interfaces and their
|
||||
* underlying implementations may be changed or removed in future without
|
||||
* notice.
|
||||
* */
|
||||
|
||||
#ifndef NUMBA_LIST_H
|
||||
#define NUMBA_LIST_H
|
||||
|
||||
#include "cext.h"
|
||||
|
||||
typedef void (*list_refcount_op_t)(const void*);
|
||||
|
||||
typedef struct {
|
||||
list_refcount_op_t item_incref;
|
||||
list_refcount_op_t item_decref;
|
||||
} list_type_based_methods_table;
|
||||
|
||||
/* This is the struct for the Numba typed list. It is largely inspired by the
|
||||
* CPython list struct in listobject.h. In essence the list is a homogeneously
|
||||
* typed container that can grow and shrink upon insertion and deletion. This
|
||||
* means that appending an item to, or removing an item from, the end of the
|
||||
* list, this will have a O(1) amortized runtime. This matches the
|
||||
* behaviour of the CPython list type and it will grow with the same
|
||||
* increments.
|
||||
*
|
||||
* 'items' contains space for 'allocated' elements. The number
|
||||
* currently in use is 'size'. The size in bytes of the items stored in the
|
||||
* list is given by 'item_size'.
|
||||
*
|
||||
* Invariants:
|
||||
* 0 <= size <= allocated
|
||||
* len(list) == size
|
||||
* item == NULL implies size == allocated == 0
|
||||
*
|
||||
* FIXME: list.sort() temporarily sets allocated to -1 to detect mutations.
|
||||
*
|
||||
* Items must normally not be NULL, except during construction when
|
||||
* the list is not yet visible outside the function that builds it.
|
||||
*
|
||||
* Additionally, this list has boolean member 'is_mutable' that can be used to
|
||||
* set a list as immutable. Two functions to query and set this member are
|
||||
* provided. Any attempt to mutate an immutable list will result in a status
|
||||
* of LIST_ERR_IMMUTABLE.
|
||||
*
|
||||
*/
|
||||
typedef struct {
|
||||
/* size of the list in items */
|
||||
Py_ssize_t size;
|
||||
/* size of the list items in bytes */
|
||||
Py_ssize_t item_size;
|
||||
/* total allocated slots in items */
|
||||
Py_ssize_t allocated;
|
||||
/* is the list mutable */
|
||||
int is_mutable;
|
||||
/* method table for type-dependent operations */
|
||||
list_type_based_methods_table methods;
|
||||
/* array/pointer for items. Interpretation is governed by item_size */
|
||||
char * items;
|
||||
} NB_List;
|
||||
|
||||
|
||||
typedef struct {
|
||||
/* parent list */
|
||||
NB_List *parent;
|
||||
/* list size */
|
||||
Py_ssize_t size;
|
||||
/* iterator position; indicates the next position to read */
|
||||
Py_ssize_t pos;
|
||||
} NB_ListIter;
|
||||
|
||||
NUMBA_GLOBAL_FUNC(void)
|
||||
numba_list_set_method_table(NB_List *lp, list_type_based_methods_table *methods);
|
||||
|
||||
NUMBA_GLOBAL_FUNC(int)
|
||||
numba_list_new(NB_List **out, Py_ssize_t item_size, Py_ssize_t allocated);
|
||||
|
||||
NUMBA_GLOBAL_FUNC(void)
|
||||
numba_list_free(NB_List *lp);
|
||||
|
||||
NUMBA_GLOBAL_FUNC(char *)
|
||||
numba_list_base_ptr(NB_List *lp);
|
||||
|
||||
NUMBA_GLOBAL_FUNC(Py_ssize_t)
|
||||
numba_list_size_address(NB_List *lp);
|
||||
|
||||
NUMBA_GLOBAL_FUNC(Py_ssize_t)
|
||||
numba_list_length(NB_List *lp);
|
||||
|
||||
NUMBA_GLOBAL_FUNC(Py_ssize_t)
|
||||
numba_list_allocated(NB_List *lp);
|
||||
|
||||
NUMBA_GLOBAL_FUNC(int)
|
||||
numba_list_is_mutable(NB_List *lp);
|
||||
|
||||
NUMBA_GLOBAL_FUNC(void)
|
||||
numba_list_set_is_mutable(NB_List *lp, int is_mutable);
|
||||
|
||||
NUMBA_GLOBAL_FUNC(int)
|
||||
numba_list_setitem(NB_List *lp, Py_ssize_t index, const char *item);
|
||||
|
||||
NUMBA_GLOBAL_FUNC(int)
|
||||
numba_list_getitem(NB_List *lp, Py_ssize_t index, char *out);
|
||||
|
||||
NUMBA_GLOBAL_FUNC(int)
|
||||
numba_list_append(NB_List *lp, const char *item);
|
||||
|
||||
NUMBA_GLOBAL_FUNC(int)
|
||||
numba_list_resize(NB_List *lp, Py_ssize_t newsize);
|
||||
|
||||
NUMBA_GLOBAL_FUNC(int)
|
||||
numba_list_delitem(NB_List *lp, Py_ssize_t index);
|
||||
|
||||
NUMBA_GLOBAL_FUNC(int)
|
||||
numba_list_delete_slice(NB_List *lp,
|
||||
Py_ssize_t start, Py_ssize_t stop, Py_ssize_t step);
|
||||
|
||||
NUMBA_GLOBAL_FUNC(size_t)
|
||||
numba_list_iter_sizeof(void);
|
||||
|
||||
NUMBA_GLOBAL_FUNC(void)
|
||||
numba_list_iter(NB_ListIter *it, NB_List *l);
|
||||
|
||||
NUMBA_GLOBAL_FUNC(int)
|
||||
numba_list_iter_next(NB_ListIter *it, const char **item_ptr);
|
||||
|
||||
NUMBA_EXPORT_FUNC(int)
|
||||
numba_test_list(void);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
#include "cext.h"
|
||||
|
||||
/* Align size *sz* to pointer width */
|
||||
Py_ssize_t
|
||||
aligned_size(Py_ssize_t sz) {
|
||||
Py_ssize_t alignment = sizeof(void*);
|
||||
return sz + (alignment - sz % alignment) % alignment;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
from . import cloudpickle
|
||||
from .cloudpickle import * # noqa
|
||||
|
||||
__doc__ = cloudpickle.__doc__
|
||||
|
||||
__version__ = "3.1.1"
|
||||
|
||||
__all__ = [ # noqa
|
||||
"__version__",
|
||||
"Pickler",
|
||||
"CloudPickler",
|
||||
"dumps",
|
||||
"loads",
|
||||
"dump",
|
||||
"load",
|
||||
"register_pickle_by_value",
|
||||
"unregister_pickle_by_value",
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,14 @@
|
||||
"""Compatibility module.
|
||||
|
||||
It can be necessary to load files generated by previous versions of cloudpickle
|
||||
that rely on symbols being defined under the `cloudpickle.cloudpickle_fast`
|
||||
namespace.
|
||||
|
||||
See: tests/test_backward_compat.py
|
||||
"""
|
||||
|
||||
from . import cloudpickle
|
||||
|
||||
|
||||
def __getattr__(name):
|
||||
return getattr(cloudpickle, name)
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user