diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-20-20-27-20.gh-issue-103092.vVf2IH.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-20-20-27-20.gh-issue-103092.vVf2IH.rst new file mode 100644 index 00000000000000..6eed964bd3c92c --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-20-20-27-20.gh-issue-103092.vVf2IH.rst @@ -0,0 +1,2 @@ +Adapt :mod:`decimal` to :pep:`687`. Patch by Erlend Aasland and Charlie +Zhao. diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index 0e11c879732ab6..069b6d34336865 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -39,6 +39,97 @@ #include "docstrings.h" +#ifdef EXTRA_FUNCTIONALITY + #define _PY_DEC_ROUND_GUARD MPD_ROUND_GUARD +#else + #define _PY_DEC_ROUND_GUARD (MPD_ROUND_GUARD-1) +#endif + +#define SIGNAL_MAP_LEN 9 + +typedef struct { + const char *name; /* condition or signal name */ + const char *fqname; /* fully qualified name */ + uint32_t flag; /* libmpdec flag */ + PyObject *ex; /* corresponding exception */ +} DecCondMap; + +typedef struct { + PyTypeObject *PyDecContextManager_Type; + PyTypeObject *PyDecContext_Type; + PyTypeObject *PyDecSignalDictMixin_Type; + PyTypeObject *PyDec_Type; + PyTypeObject *PyDecSignalDict_Type; + PyTypeObject *DecimalTuple; + + /* Top level Exception; inherits from ArithmeticError */ + PyObject *DecimalException; + +#ifndef WITH_DECIMAL_CONTEXTVAR + /* Key for thread state dictionary */ + PyObject *tls_context_key; + /* Invariant: NULL or the most recently accessed thread local context */ + PyDecContextObject *cached_context; +#else + PyObject *current_context_var; +#endif + + /* Template for creating new thread contexts, calling Context() without + * arguments and initializing the module_context on first access. */ + PyObject *default_context_template; + + /* Basic and extended context templates */ + PyObject *basic_context_template; + PyObject *extended_context_template; + + PyObject *round_map[_PY_DEC_ROUND_GUARD]; + + /* Convert rationals for comparison */ + PyObject *Rational; + + PyObject *SignalTuple; + + DecCondMap signal_map[SIGNAL_MAP_LEN + 1]; + + /* External C-API functions */ + binaryfunc _py_long_multiply; + binaryfunc _py_long_floor_divide; + ternaryfunc _py_long_power; + unaryfunc _py_float_abs; + PyCFunction _py_long_bit_length; + PyCFunction _py_float_as_integer_ratio; +} decimal_state; + +static inline decimal_state * +get_module_state(PyObject *mod) +{ + decimal_state *state = _PyModule_GetState(mod); + assert(state != NULL); + return state; +} + +static struct PyModuleDef _decimal_module; + +static inline decimal_state * +get_module_state_by_def(PyTypeObject *tp) +{ + PyObject *mod = PyType_GetModuleByDef(tp, &_decimal_module); + assert(mod != NULL); + return get_module_state(mod); +} + +static inline decimal_state * +find_state_left_or_right(PyObject *left, PyObject *right) +{ + PyObject *mod = PyType_GetModuleByDef(Py_TYPE(left), &_decimal_module); + if (mod == NULL) { + PyErr_Clear(); + mod = PyType_GetModuleByDef(Py_TYPE(right), &_decimal_module); + } + assert(mod != NULL); + return get_module_state(mod); +} + #if !defined(MPD_VERSION_HEX) || MPD_VERSION_HEX < 0x02050000 #error "libmpdec version >= 2.5.0 required" @@ -99,14 +190,10 @@ typedef struct { #undef MPD #undef CTX -static PyTypeObject PyDec_Type; -static PyTypeObject *PyDecSignalDict_Type; -static PyTypeObject PyDecContext_Type; -static PyTypeObject PyDecContextManager_Type; -#define PyDec_CheckExact(v) Py_IS_TYPE(v, &PyDec_Type) -#define PyDec_Check(v) PyObject_TypeCheck(v, &PyDec_Type) -#define PyDecSignalDict_Check(v) Py_IS_TYPE(v, PyDecSignalDict_Type) -#define PyDecContext_Check(v) PyObject_TypeCheck(v, &PyDecContext_Type) +#define PyDec_CheckExact(st, v) Py_IS_TYPE(v, st->PyDec_Type) +#define PyDec_Check(st, v) PyObject_TypeCheck(v, st->PyDec_Type) +#define PyDecSignalDict_Check(st, v) Py_IS_TYPE(v, st->PyDecSignalDict_Type) +#define PyDecContext_Check(st, v) PyObject_TypeCheck(v, st->PyDecContext_Type) #define MPD(v) (&((PyDecObject *)v)->dec) #define SdFlagAddr(v) (((PyDecSignalDictObject *)v)->flags) #define SdFlags(v) (*((PyDecSignalDictObject *)v)->flags) @@ -127,55 +214,34 @@ incr_false(void) } -#ifndef WITH_DECIMAL_CONTEXTVAR -/* Key for thread state dictionary */ -static PyObject *tls_context_key = NULL; -/* Invariant: NULL or the most recently accessed thread local context */ -static PyDecContextObject *cached_context = NULL; -#else -static PyObject *current_context_var = NULL; -#endif - -/* Template for creating new thread contexts, calling Context() without - * arguments and initializing the module_context on first access. */ -static PyObject *default_context_template = NULL; -/* Basic and extended context templates */ -static PyObject *basic_context_template = NULL; -static PyObject *extended_context_template = NULL; - - /* Error codes for functions that return signals or conditions */ #define DEC_INVALID_SIGNALS (MPD_Max_status+1U) #define DEC_ERR_OCCURRED (DEC_INVALID_SIGNALS<<1) #define DEC_ERRORS (DEC_INVALID_SIGNALS|DEC_ERR_OCCURRED) -typedef struct { - const char *name; /* condition or signal name */ - const char *fqname; /* fully qualified name */ - uint32_t flag; /* libmpdec flag */ - PyObject *ex; /* corresponding exception */ -} DecCondMap; - -/* Top level Exception; inherits from ArithmeticError */ -static PyObject *DecimalException = NULL; - /* Exceptions that correspond to IEEE signals */ #define SUBNORMAL 5 #define INEXACT 6 #define ROUNDED 7 -#define SIGNAL_MAP_LEN 9 -static DecCondMap signal_map[] = { - {"InvalidOperation", "decimal.InvalidOperation", MPD_IEEE_Invalid_operation, NULL}, - {"FloatOperation", "decimal.FloatOperation", MPD_Float_operation, NULL}, - {"DivisionByZero", "decimal.DivisionByZero", MPD_Division_by_zero, NULL}, - {"Overflow", "decimal.Overflow", MPD_Overflow, NULL}, - {"Underflow", "decimal.Underflow", MPD_Underflow, NULL}, - {"Subnormal", "decimal.Subnormal", MPD_Subnormal, NULL}, - {"Inexact", "decimal.Inexact", MPD_Inexact, NULL}, - {"Rounded", "decimal.Rounded", MPD_Rounded, NULL}, - {"Clamped", "decimal.Clamped", MPD_Clamped, NULL}, - {NULL} -}; + +static inline void +signal_map_init(decimal_state *state) +{ + static const DecCondMap signal_map[] = { + {"InvalidOperation", "decimal.InvalidOperation", MPD_IEEE_Invalid_operation, NULL}, + {"FloatOperation", "decimal.FloatOperation", MPD_Float_operation, NULL}, + {"DivisionByZero", "decimal.DivisionByZero", MPD_Division_by_zero, NULL}, + {"Overflow", "decimal.Overflow", MPD_Overflow, NULL}, + {"Underflow", "decimal.Underflow", MPD_Underflow, NULL}, + {"Subnormal", "decimal.Subnormal", MPD_Subnormal, NULL}, + {"Inexact", "decimal.Inexact", MPD_Inexact, NULL}, + {"Rounded", "decimal.Rounded", MPD_Rounded, NULL}, + {"Clamped", "decimal.Clamped", MPD_Clamped, NULL}, + {NULL} + }; + + memcpy(state->signal_map, signal_map, sizeof(signal_map)); +} /* Exceptions that inherit from InvalidOperation */ static DecCondMap cond_map[] = { @@ -208,13 +274,6 @@ static const char *dec_signal_string[MPD_NUM_FLAGS] = { "Underflow", }; -#ifdef EXTRA_FUNCTIONALITY - #define _PY_DEC_ROUND_GUARD MPD_ROUND_GUARD -#else - #define _PY_DEC_ROUND_GUARD (MPD_ROUND_GUARD-1) -#endif -static PyObject *round_map[_PY_DEC_ROUND_GUARD]; - static const char *invalid_rounding_err = "valid values for rounding are:\n\ [ROUND_CEILING, ROUND_FLOOR, ROUND_UP, ROUND_DOWN,\n\ @@ -287,11 +346,11 @@ dec_traphandler(mpd_context_t *ctx UNUSED) /* GCOV_NOT_REACHED */ } static PyObject * -flags_as_exception(uint32_t flags) +flags_as_exception(decimal_state *state, uint32_t flags) { DecCondMap *cm; - for (cm = signal_map; cm->name != NULL; cm++) { + for (cm = state->signal_map; cm->name != NULL; cm++) { if (flags&cm->flag) { return cm->ex; } @@ -301,11 +360,11 @@ flags_as_exception(uint32_t flags) } Py_LOCAL_INLINE(uint32_t) -exception_as_flag(PyObject *ex) +exception_as_flag(decimal_state *state, PyObject *ex) { DecCondMap *cm; - for (cm = signal_map; cm->name != NULL; cm++) { + for (cm = state->signal_map; cm->name != NULL; cm++) { if (cm->ex == ex) { return cm->flag; } @@ -316,7 +375,7 @@ exception_as_flag(PyObject *ex) } static PyObject * -flags_as_list(uint32_t flags) +flags_as_list(decimal_state *state, uint32_t flags) { PyObject *list; DecCondMap *cm; @@ -333,7 +392,7 @@ flags_as_list(uint32_t flags) } } } - for (cm = signal_map+1; cm->name != NULL; cm++) { + for (cm = state->signal_map+1; cm->name != NULL; cm++) { if (flags&cm->flag) { if (PyList_Append(list, cm->ex) < 0) { goto error; @@ -349,7 +408,7 @@ flags_as_list(uint32_t flags) } static PyObject * -signals_as_list(uint32_t flags) +signals_as_list(decimal_state *state, uint32_t flags) { PyObject *list; DecCondMap *cm; @@ -359,7 +418,7 @@ signals_as_list(uint32_t flags) return NULL; } - for (cm = signal_map; cm->name != NULL; cm++) { + for (cm = state->signal_map; cm->name != NULL; cm++) { if (flags&cm->flag) { if (PyList_Append(list, cm->ex) < 0) { Py_DECREF(list); @@ -372,7 +431,7 @@ signals_as_list(uint32_t flags) } static uint32_t -list_as_flags(PyObject *list) +list_as_flags(decimal_state *state, PyObject *list) { PyObject *item; uint32_t flags, x; @@ -384,7 +443,7 @@ list_as_flags(PyObject *list) flags = 0; for (j = 0; j < n; j++) { item = PyList_GetItem(list, j); - x = exception_as_flag(item); + x = exception_as_flag(state, item); if (x & DEC_ERRORS) { return x; } @@ -395,7 +454,7 @@ list_as_flags(PyObject *list) } static PyObject * -flags_as_dict(uint32_t flags) +flags_as_dict(decimal_state *state, uint32_t flags) { DecCondMap *cm; PyObject *dict; @@ -405,7 +464,7 @@ flags_as_dict(uint32_t flags) return NULL; } - for (cm = signal_map; cm->name != NULL; cm++) { + for (cm = state->signal_map; cm->name != NULL; cm++) { PyObject *b = flags&cm->flag ? Py_True : Py_False; if (PyDict_SetItem(dict, cm->ex, b) < 0) { Py_DECREF(dict); @@ -417,7 +476,7 @@ flags_as_dict(uint32_t flags) } static uint32_t -dict_as_flags(PyObject *val) +dict_as_flags(decimal_state *state, PyObject *val) { PyObject *b; DecCondMap *cm; @@ -436,7 +495,7 @@ dict_as_flags(PyObject *val) return DEC_INVALID_SIGNALS; } - for (cm = signal_map; cm->name != NULL; cm++) { + for (cm = state->signal_map; cm->name != NULL; cm++) { b = PyDict_GetItemWithError(val, cm->ex); if (b == NULL) { if (PyErr_Occurred()) { @@ -482,6 +541,7 @@ static int dec_addstatus(PyObject *context, uint32_t status) { mpd_context_t *ctx = CTX(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); ctx->status |= status; if (status & (ctx->traps|MPD_Malloc_error)) { @@ -492,11 +552,11 @@ dec_addstatus(PyObject *context, uint32_t status) return 1; } - ex = flags_as_exception(ctx->traps&status); + ex = flags_as_exception(state, ctx->traps&status); if (ex == NULL) { return 1; /* GCOV_NOT_REACHED */ } - siglist = flags_as_list(ctx->traps&status); + siglist = flags_as_list(state, ctx->traps&status); if (siglist == NULL) { return 1; } @@ -509,18 +569,17 @@ dec_addstatus(PyObject *context, uint32_t status) } static int -getround(PyObject *v) +getround(decimal_state *state, PyObject *v) { int i; - if (PyUnicode_Check(v)) { for (i = 0; i < _PY_DEC_ROUND_GUARD; i++) { - if (v == round_map[i]) { + if (v == state->round_map[i]) { return i; } } for (i = 0; i < _PY_DEC_ROUND_GUARD; i++) { - if (PyUnicode_Compare(v, round_map[i]) == 0) { + if (PyUnicode_Compare(v, state->round_map[i]) == 0) { return i; } } @@ -553,19 +612,20 @@ signaldict_len(PyObject *self UNUSED) return SIGNAL_MAP_LEN; } -static PyObject *SignalTuple; static PyObject * -signaldict_iter(PyObject *self UNUSED) +signaldict_iter(PyObject *self) { - return PyTuple_Type.tp_iter(SignalTuple); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + return PyTuple_Type.tp_iter(state->SignalTuple); } static PyObject * signaldict_getitem(PyObject *self, PyObject *key) { uint32_t flag; + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); - flag = exception_as_flag(key); + flag = exception_as_flag(state, key); if (flag & DEC_ERRORS) { return NULL; } @@ -579,11 +639,12 @@ signaldict_setitem(PyObject *self, PyObject *key, PyObject *value) uint32_t flag; int x; + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); if (value == NULL) { return value_error_int("signal keys cannot be deleted"); } - flag = exception_as_flag(key); + flag = exception_as_flag(state, key); if (flag & DEC_ERRORS) { return -1; } @@ -603,6 +664,22 @@ signaldict_setitem(PyObject *self, PyObject *key, PyObject *value) return 0; } +static int +signaldict_traverse(PyObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + return 0; +} + +static void +signaldict_dealloc(PyObject *self) +{ + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + tp->tp_free(self); + Py_DECREF(tp); +} + static PyObject * signaldict_repr(PyObject *self) { @@ -610,10 +687,10 @@ signaldict_repr(PyObject *self) const char *n[SIGNAL_MAP_LEN]; /* name */ const char *b[SIGNAL_MAP_LEN]; /* bool */ int i; - + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); assert(SIGNAL_MAP_LEN == 9); - for (cm=signal_map, i=0; cm->name != NULL; cm++, i++) { + for (cm=state->signal_map, i=0; cm->name != NULL; cm++, i++) { n[i] = cm->fqname; b[i] = SdFlags(self)&cm->flag ? "True" : "False"; } @@ -631,14 +708,15 @@ signaldict_richcompare(PyObject *v, PyObject *w, int op) { PyObject *res = Py_NotImplemented; - assert(PyDecSignalDict_Check(v)); + decimal_state *state = find_state_left_or_right(v, w); + assert(PyDecSignalDict_Check(state, v)); if (op == Py_EQ || op == Py_NE) { - if (PyDecSignalDict_Check(w)) { + if (PyDecSignalDict_Check(state, w)) { res = (SdFlags(v)==SdFlags(w)) ^ (op==Py_NE) ? Py_True : Py_False; } else if (PyDict_Check(w)) { - uint32_t flags = dict_as_flags(w); + uint32_t flags = dict_as_flags(state, w); if (flags & DEC_ERRORS) { if (flags & DEC_INVALID_SIGNALS) { /* non-comparable: Py_NotImplemented */ @@ -660,62 +738,40 @@ signaldict_richcompare(PyObject *v, PyObject *w, int op) static PyObject * signaldict_copy(PyObject *self, PyObject *args UNUSED) { - return flags_as_dict(SdFlags(self)); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + return flags_as_dict(state, SdFlags(self)); } -static PyMappingMethods signaldict_as_mapping = { - (lenfunc)signaldict_len, /* mp_length */ - (binaryfunc)signaldict_getitem, /* mp_subscript */ - (objobjargproc)signaldict_setitem /* mp_ass_subscript */ -}; - static PyMethodDef signaldict_methods[] = { { "copy", (PyCFunction)signaldict_copy, METH_NOARGS, NULL}, {NULL, NULL} }; -static PyTypeObject PyDecSignalDictMixin_Type = -{ - PyVarObject_HEAD_INIT(0, 0) - "decimal.SignalDictMixin", /* tp_name */ - sizeof(PyDecSignalDictObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - (getattrfunc) 0, /* tp_getattr */ - (setattrfunc) 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc) signaldict_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - &signaldict_as_mapping, /* tp_as_mapping */ - PyObject_HashNotImplemented, /* tp_hash */ - 0, /* tp_call */ - (reprfunc) 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - (setattrofunc) 0, /* tp_setattro */ - (PyBufferProcs *) 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - signaldict_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - (getiterfunc)signaldict_iter, /* tp_iter */ - 0, /* tp_iternext */ - signaldict_methods, /* 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 */ - (initproc)signaldict_init, /* tp_init */ - 0, /* tp_alloc */ - PyType_GenericNew, /* tp_new */ +static PyType_Slot signaldict_slots[] = { + {Py_tp_dealloc, signaldict_dealloc}, + {Py_tp_traverse, signaldict_traverse}, + {Py_tp_repr, signaldict_repr}, + {Py_tp_hash, PyObject_HashNotImplemented}, + {Py_tp_richcompare, signaldict_richcompare}, + {Py_tp_iter, signaldict_iter}, + {Py_tp_methods, signaldict_methods}, + {Py_tp_init, signaldict_init}, + + // Mapping protocol + {Py_mp_length, signaldict_len}, + {Py_mp_subscript, signaldict_getitem}, + {Py_mp_ass_subscript, signaldict_setitem}, + {0, NULL}, +}; + +static PyType_Spec signaldict_spec = { + .name = "decimal.SignalDictMixin", + .basicsize = sizeof(PyDecSignalDictObject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE), + .slots = signaldict_slots, }; @@ -751,8 +807,9 @@ static PyObject * context_getround(PyObject *self, void *closure UNUSED) { int i = mpd_getround(CTX(self)); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); - return Py_NewRef(round_map[i]); + return Py_NewRef(state->round_map[i]); } static PyObject * @@ -909,7 +966,8 @@ context_setround(PyObject *self, PyObject *value, void *closure UNUSED) mpd_context_t *ctx; int x; - x = getround(value); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + x = getround(state, value); if (x == -1) { return -1; } @@ -967,8 +1025,8 @@ context_settraps_list(PyObject *self, PyObject *value) { mpd_context_t *ctx; uint32_t flags; - - flags = list_as_flags(value); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + flags = list_as_flags(state, value); if (flags & DEC_ERRORS) { return -1; } @@ -987,11 +1045,12 @@ context_settraps_dict(PyObject *self, PyObject *value) mpd_context_t *ctx; uint32_t flags; - if (PyDecSignalDict_Check(value)) { + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + if (PyDecSignalDict_Check(state, value)) { flags = SdFlags(value); } else { - flags = dict_as_flags(value); + flags = dict_as_flags(state, value); if (flags & DEC_ERRORS) { return -1; } @@ -1031,8 +1090,9 @@ context_setstatus_list(PyObject *self, PyObject *value) { mpd_context_t *ctx; uint32_t flags; + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); - flags = list_as_flags(value); + flags = list_as_flags(state, value); if (flags & DEC_ERRORS) { return -1; } @@ -1051,11 +1111,12 @@ context_setstatus_dict(PyObject *self, PyObject *value) mpd_context_t *ctx; uint32_t flags; - if (PyDecSignalDict_Check(value)) { + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + if (PyDecSignalDict_Check(state, value)) { flags = SdFlags(value); } else { - flags = dict_as_flags(value); + flags = dict_as_flags(state, value); if (flags & DEC_ERRORS) { return -1; } @@ -1241,8 +1302,9 @@ context_new(PyTypeObject *type, PyObject *args UNUSED, PyObject *kwds UNUSED) PyDecContextObject *self = NULL; mpd_context_t *ctx; - if (type == &PyDecContext_Type) { - self = PyObject_New(PyDecContextObject, &PyDecContext_Type); + decimal_state *state = get_module_state_by_def(type); + if (type == state->PyDecContext_Type) { + self = PyObject_GC_New(PyDecContextObject, state->PyDecContext_Type); } else { self = (PyDecContextObject *)type->tp_alloc(type, 0); @@ -1252,13 +1314,13 @@ context_new(PyTypeObject *type, PyObject *args UNUSED, PyObject *kwds UNUSED) return NULL; } - self->traps = PyObject_CallObject((PyObject *)PyDecSignalDict_Type, NULL); + self->traps = PyObject_CallObject((PyObject *)state->PyDecSignalDict_Type, NULL); if (self->traps == NULL) { self->flags = NULL; Py_DECREF(self); return NULL; } - self->flags = PyObject_CallObject((PyObject *)PyDecSignalDict_Type, NULL); + self->flags = PyObject_CallObject((PyObject *)state->PyDecSignalDict_Type, NULL); if (self->flags == NULL) { Py_DECREF(self); return NULL; @@ -1266,8 +1328,8 @@ context_new(PyTypeObject *type, PyObject *args UNUSED, PyObject *kwds UNUSED) ctx = CTX(self); - if (default_context_template) { - *ctx = *CTX(default_context_template); + if (state->default_context_template) { + *ctx = *CTX(state->default_context_template); } else { *ctx = dflt_ctx; @@ -1279,21 +1341,44 @@ context_new(PyTypeObject *type, PyObject *args UNUSED, PyObject *kwds UNUSED) CtxCaps(self) = 1; self->tstate = NULL; + if (type == state->PyDecContext_Type) { + PyObject_GC_Track(self); + } + return (PyObject *)self; } +static int +context_traverse(PyDecContextObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->traps); + Py_VISIT(self->flags); + return 0; +} + +static int +context_clear(PyDecContextObject *self) +{ + Py_CLEAR(self->traps); + Py_CLEAR(self->flags); + return 0; +} + static void context_dealloc(PyDecContextObject *self) { + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); #ifndef WITH_DECIMAL_CONTEXTVAR - if (self == cached_context) { - cached_context = NULL; + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + if (self == state->cached_context) { + state->cached_context = NULL; } #endif - - Py_XDECREF(self->traps); - Py_XDECREF(self->flags); - Py_TYPE(self)->tp_free(self); + (void)context_clear(self); + tp->tp_free(self); + Py_DECREF(tp); } static int @@ -1337,7 +1422,8 @@ context_repr(PyDecContextObject *self) char traps[MPD_MAX_SIGNAL_LIST]; int n, mem; - assert(PyDecContext_Check(self)); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + assert(PyDecContext_Check(state, self)); ctx = CTX(self); mem = MPD_MAX_SIGNAL_LIST; @@ -1403,7 +1489,8 @@ ieee_context(PyObject *dummy UNUSED, PyObject *v) goto error; } - context = PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL); + decimal_state *state = get_module_state_by_def(Py_TYPE(v)); + context = PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL); if (context == NULL) { return NULL; } @@ -1425,7 +1512,8 @@ context_copy(PyObject *self, PyObject *args UNUSED) { PyObject *copy; - copy = PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + copy = PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL); if (copy == NULL) { return NULL; } @@ -1444,14 +1532,15 @@ context_reduce(PyObject *self, PyObject *args UNUSED) PyObject *traps; PyObject *ret; mpd_context_t *ctx; + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); ctx = CTX(self); - flags = signals_as_list(ctx->status); + flags = signals_as_list(state, ctx->status); if (flags == NULL) { return NULL; } - traps = signals_as_list(ctx->traps); + traps = signals_as_list(state, ctx->traps); if (traps == NULL) { Py_DECREF(flags); return NULL; @@ -1487,18 +1576,18 @@ static PyGetSetDef context_getsets [] = }; -#define CONTEXT_CHECK(obj) \ - if (!PyDecContext_Check(obj)) { \ +#define CONTEXT_CHECK(state, obj) \ + if (!PyDecContext_Check(state, obj)) { \ PyErr_SetString(PyExc_TypeError, \ "argument must be a context"); \ return NULL; \ } -#define CONTEXT_CHECK_VA(obj) \ +#define CONTEXT_CHECK_VA(state, obj) \ if (obj == Py_None) { \ - CURRENT_CONTEXT(obj); \ + CURRENT_CONTEXT(state, obj); \ } \ - else if (!PyDecContext_Check(obj)) { \ + else if (!PyDecContext_Check(state, obj)) { \ PyErr_SetString(PyExc_TypeError, \ "optional argument must be a context"); \ return NULL; \ @@ -1522,6 +1611,7 @@ static PyObject * current_context_from_dict(void) { PyThreadState *tstate = _PyThreadState_GET(); + decimal_state *state = GLOBAL_STATE(); #ifdef Py_DEBUG // The caller must hold the GIL _Py_EnsureTstateNotNULL(tstate); @@ -1534,10 +1624,10 @@ current_context_from_dict(void) return NULL; } - PyObject *tl_context = PyDict_GetItemWithError(dict, tls_context_key); + PyObject *tl_context = PyDict_GetItemWithError(dict, state->tls_context_key); if (tl_context != NULL) { /* We already have a thread local context. */ - CONTEXT_CHECK(tl_context); + CONTEXT_CHECK(state, tl_context); } else { if (PyErr_Occurred()) { @@ -1545,13 +1635,13 @@ current_context_from_dict(void) } /* Set up a new thread local context. */ - tl_context = context_copy(default_context_template, NULL); + tl_context = context_copy(state->default_context_template, NULL); if (tl_context == NULL) { return NULL; } CTX(tl_context)->status = 0; - if (PyDict_SetItem(dict, tls_context_key, tl_context) < 0) { + if (PyDict_SetItem(dict, state->tls_context_key, tl_context) < 0) { Py_DECREF(tl_context); return NULL; } @@ -1560,8 +1650,8 @@ current_context_from_dict(void) /* Cache the context of the current thread, assuming that it * will be accessed several times before a thread switch. */ - cached_context = (PyDecContextObject *)tl_context; - cached_context->tstate = tstate; + state->cached_context = (PyDecContextObject *)tl_context; + state->cached_context->tstate = tstate; /* Borrowed reference with refcount==1 */ return tl_context; @@ -1572,8 +1662,9 @@ static PyObject * current_context(void) { PyThreadState *tstate = _PyThreadState_GET(); - if (cached_context && cached_context->tstate == tstate) { - return (PyObject *)cached_context; + decimal_state *state = GLOBAL_STATE(); + if (state->cached_context && state->cached_context->tstate == tstate) { + return (PyObject *)(state->cached_context); } return current_context_from_dict(); @@ -1606,7 +1697,8 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) { PyObject *dict; - CONTEXT_CHECK(v); + decimal_state *state = GLOBAL_STATE(); + CONTEXT_CHECK(state, v); dict = PyThreadState_GetDict(); if (dict == NULL) { @@ -1617,9 +1709,9 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) /* If the new context is one of the templates, make a copy. * This is the current behavior of decimal.py. */ - if (v == default_context_template || - v == basic_context_template || - v == extended_context_template) { + if (v == state->default_context_template || + v == state->basic_context_template || + v == state->extended_context_template) { v = context_copy(v, NULL); if (v == NULL) { return NULL; @@ -1630,8 +1722,8 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) Py_INCREF(v); } - cached_context = NULL; - if (PyDict_SetItem(dict, tls_context_key, v) < 0) { + state->cached_context = NULL; + if (PyDict_SetItem(dict, state->tls_context_key, v) < 0) { Py_DECREF(v); return NULL; } @@ -1641,15 +1733,15 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) } #else static PyObject * -init_current_context(void) +init_current_context(decimal_state *state) { - PyObject *tl_context = context_copy(default_context_template, NULL); + PyObject *tl_context = context_copy(state->default_context_template, NULL); if (tl_context == NULL) { return NULL; } CTX(tl_context)->status = 0; - PyObject *tok = PyContextVar_Set(current_context_var, tl_context); + PyObject *tok = PyContextVar_Set(state->current_context_var, tl_context); if (tok == NULL) { Py_DECREF(tl_context); return NULL; @@ -1660,10 +1752,10 @@ init_current_context(void) } static inline PyObject * -current_context(void) +current_context(decimal_state *state) { PyObject *tl_context; - if (PyContextVar_Get(current_context_var, NULL, &tl_context) < 0) { + if (PyContextVar_Get(state->current_context_var, NULL, &tl_context) < 0) { return NULL; } @@ -1671,12 +1763,12 @@ current_context(void) return tl_context; } - return init_current_context(); + return init_current_context(state); } /* ctxobj := borrowed reference to the current context */ -#define CURRENT_CONTEXT(ctxobj) \ - ctxobj = current_context(); \ +#define CURRENT_CONTEXT(state, ctxobj) \ + ctxobj = current_context(state); \ if (ctxobj == NULL) { \ return NULL; \ } \ @@ -1686,20 +1778,22 @@ current_context(void) static PyObject * PyDec_GetCurrentContext(PyObject *self UNUSED, PyObject *args UNUSED) { - return current_context(); + decimal_state *state = get_module_state(self); + return current_context(state); } /* Set the thread local context to a new context, decrement old reference */ static PyObject * PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) { - CONTEXT_CHECK(v); + decimal_state *state = get_module_state(self); + CONTEXT_CHECK(state, v); /* If the new context is one of the templates, make a copy. * This is the current behavior of decimal.py. */ - if (v == default_context_template || - v == basic_context_template || - v == extended_context_template) { + if (v == state->default_context_template || + v == state->basic_context_template || + v == state->extended_context_template) { v = context_copy(v, NULL); if (v == NULL) { return NULL; @@ -1710,7 +1804,7 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) Py_INCREF(v); } - PyObject *tok = PyContextVar_Set(current_context_var, v); + PyObject *tok = PyContextVar_Set(state->current_context_var, v); Py_DECREF(v); if (tok == NULL) { return NULL; @@ -1725,7 +1819,7 @@ PyDec_SetCurrentContext(PyObject *self UNUSED, PyObject *v) * owns one reference to the global (outer) context and one * to the local (inner) context. */ static PyObject * -ctxmanager_new(PyTypeObject *type UNUSED, PyObject *args, PyObject *kwds) +ctxmanager_new(PyObject *m UNUSED, PyObject *args, PyObject *kwds) { static char *kwlist[] = { "ctx", "prec", "rounding", @@ -1746,7 +1840,8 @@ ctxmanager_new(PyTypeObject *type UNUSED, PyObject *args, PyObject *kwds) PyObject *flags = Py_None; PyObject *traps = Py_None; - CURRENT_CONTEXT(global); + decimal_state *state = get_module_state(m); + CURRENT_CONTEXT(state, global); if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OOOOOOOOO", kwlist, &local, &prec, &rounding, &Emin, &Emax, &capitals, &clamp, &flags, &traps)) { return NULL; @@ -1754,46 +1849,66 @@ ctxmanager_new(PyTypeObject *type UNUSED, PyObject *args, PyObject *kwds) if (local == Py_None) { local = global; } - else if (!PyDecContext_Check(local)) { + else if (!PyDecContext_Check(state, local)) { PyErr_SetString(PyExc_TypeError, "optional argument must be a context"); return NULL; } - self = PyObject_New(PyDecContextManagerObject, - &PyDecContextManager_Type); - if (self == NULL) { - return NULL; - } - - self->local = context_copy(local, NULL); - if (self->local == NULL) { - self->global = NULL; - Py_DECREF(self); + PyObject *local_copy = context_copy(local, NULL); + if (local_copy == NULL) { return NULL; } - self->global = Py_NewRef(global); int ret = context_setattrs( - self->local, prec, rounding, + local_copy, prec, rounding, Emin, Emax, capitals, clamp, flags, traps ); - if (ret < 0) { - Py_DECREF(self); + Py_DECREF(local_copy); + return NULL; + } + + self = PyObject_GC_New(PyDecContextManagerObject, + state->PyDecContextManager_Type); + if (self == NULL) { + Py_DECREF(local_copy); return NULL; } + self->local = local_copy; + self->global = Py_NewRef(global); + PyObject_GC_Track(self); + return (PyObject *)self; } +static int +ctxmanager_traverse(PyDecContextManagerObject *self, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(self)); + Py_VISIT(self->local); + Py_VISIT(self->global); + return 0; +} + +static int +ctxmanager_clear(PyDecContextManagerObject *self) +{ + Py_CLEAR(self->local); + Py_CLEAR(self->global); + return 0; +} + static void ctxmanager_dealloc(PyDecContextManagerObject *self) { - Py_XDECREF(self->local); - Py_XDECREF(self->global); - PyObject_Free(self); + PyTypeObject *tp = Py_TYPE(self); + PyObject_GC_UnTrack(self); + (void)ctxmanager_clear(self); + tp->tp_free((PyObject *)self); + Py_DECREF(tp); } static PyObject * @@ -1801,7 +1916,7 @@ ctxmanager_set_local(PyDecContextManagerObject *self, PyObject *args UNUSED) { PyObject *ret; - ret = PyDec_SetCurrentContext(NULL, self->local); + ret = PyDec_SetCurrentContext(PyType_GetModule(Py_TYPE(self)), self->local); if (ret == NULL) { return NULL; } @@ -1816,7 +1931,7 @@ ctxmanager_restore_global(PyDecContextManagerObject *self, { PyObject *ret; - ret = PyDec_SetCurrentContext(NULL, self->global); + ret = PyDec_SetCurrentContext(PyType_GetModule(Py_TYPE(self)), self->global); if (ret == NULL) { return NULL; } @@ -1832,36 +1947,20 @@ static PyMethodDef ctxmanager_methods[] = { {NULL, NULL} }; -static PyTypeObject PyDecContextManager_Type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "decimal.ContextManager", /* tp_name */ - sizeof(PyDecContextManagerObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor) ctxmanager_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - (getattrfunc) 0, /* tp_getattr */ - (setattrfunc) 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc) 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - (getattrofunc) PyObject_GenericGetAttr, /* tp_getattro */ - (setattrofunc) 0, /* tp_setattro */ - (PyBufferProcs *) 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - ctxmanager_methods, /* tp_methods */ +static PyType_Slot ctxmanager_slots[] = { + {Py_tp_dealloc, ctxmanager_dealloc}, + {Py_tp_traverse, ctxmanager_traverse}, + {Py_tp_clear, ctxmanager_clear}, + {Py_tp_methods, ctxmanager_methods}, + {0, NULL}, +}; + +static PyType_Spec ctxmanager_spec = { + .name = "decimal.ContextManager", + .basicsize = sizeof(PyDecContextManagerObject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_IMMUTABLETYPE), + .slots = ctxmanager_slots, }; @@ -1874,8 +1973,9 @@ PyDecType_New(PyTypeObject *type) { PyDecObject *dec; - if (type == &PyDec_Type) { - dec = PyObject_New(PyDecObject, &PyDec_Type); + decimal_state *state = get_module_state_by_def(type); + if (type == state->PyDec_Type) { + dec = PyObject_GC_New(PyDecObject, state->PyDec_Type); } else { dec = (PyDecObject *)type->tp_alloc(type, 0); @@ -1895,13 +1995,23 @@ PyDecType_New(PyTypeObject *type) return (PyObject *)dec; } -#define dec_alloc() PyDecType_New(&PyDec_Type) +#define dec_alloc(st) PyDecType_New(st->PyDec_Type) + +static int +dec_traverse(PyObject *dec, visitproc visit, void *arg) +{ + Py_VISIT(Py_TYPE(dec)); + return 0; +} static void dec_dealloc(PyObject *dec) { + PyTypeObject *tp = Py_TYPE(dec); + PyObject_GC_UnTrack(dec); mpd_del(MPD(dec)); - Py_TYPE(dec)->tp_free(dec); + tp->tp_free(dec); + Py_DECREF(tp); } @@ -2240,14 +2350,6 @@ PyDecType_FromLongExact(PyTypeObject *type, PyObject *v, return dec; } -/* External C-API functions */ -static binaryfunc _py_long_multiply; -static binaryfunc _py_long_floor_divide; -static ternaryfunc _py_long_power; -static unaryfunc _py_float_abs; -static PyCFunction _py_long_bit_length; -static PyCFunction _py_float_as_integer_ratio; - /* Return a PyDecObject or a subtype from a PyFloatObject. Conversion is exact. */ static PyObject * @@ -2262,9 +2364,9 @@ PyDecType_FromFloatExact(PyTypeObject *type, PyObject *v, mpd_t *d1, *d2; uint32_t status = 0; mpd_context_t maxctx; + decimal_state *state = get_module_state_by_def(type); - - assert(PyType_IsSubtype(type, &PyDec_Type)); + assert(PyType_IsSubtype(type, state->PyDec_Type)); if (PyLong_Check(v)) { return PyDecType_FromLongExact(type, v, context); @@ -2298,13 +2400,13 @@ PyDecType_FromFloatExact(PyTypeObject *type, PyObject *v, } /* absolute value of the float */ - tmp = _py_float_abs(v); + tmp = state->_py_float_abs(v); if (tmp == NULL) { return NULL; } /* float as integer ratio: numerator/denominator */ - n_d = _py_float_as_integer_ratio(tmp, NULL); + n_d = state->_py_float_as_integer_ratio(tmp, NULL); Py_DECREF(tmp); if (n_d == NULL) { return NULL; @@ -2312,7 +2414,7 @@ PyDecType_FromFloatExact(PyTypeObject *type, PyObject *v, n = PyTuple_GET_ITEM(n_d, 0); d = PyTuple_GET_ITEM(n_d, 1); - tmp = _py_long_bit_length(d, NULL); + tmp = state->_py_long_bit_length(d, NULL); if (tmp == NULL) { Py_DECREF(n_d); return NULL; @@ -2399,7 +2501,8 @@ PyDecType_FromDecimalExact(PyTypeObject *type, PyObject *v, PyObject *context) PyObject *dec; uint32_t status = 0; - if (type == &PyDec_Type && PyDec_CheckExact(v)) { + decimal_state *state = get_module_state_by_def(type); + if (type == state->PyDec_Type && PyDec_CheckExact(state, v)) { return Py_NewRef(v); } @@ -2634,37 +2737,37 @@ PyDecType_FromSequenceExact(PyTypeObject *type, PyObject *v, return dec; } -#define PyDec_FromCString(str, context) \ - PyDecType_FromCString(&PyDec_Type, str, context) -#define PyDec_FromCStringExact(str, context) \ - PyDecType_FromCStringExact(&PyDec_Type, str, context) +#define PyDec_FromCString(st, str, context) \ + PyDecType_FromCString(st->PyDec_Type, str, context) +#define PyDec_FromCStringExact(st, str, context) \ + PyDecType_FromCStringExact(st->PyDec_Type, str, context) -#define PyDec_FromUnicode(unicode, context) \ - PyDecType_FromUnicode(&PyDec_Type, unicode, context) -#define PyDec_FromUnicodeExact(unicode, context) \ - PyDecType_FromUnicodeExact(&PyDec_Type, unicode, context) -#define PyDec_FromUnicodeExactWS(unicode, context) \ - PyDecType_FromUnicodeExactWS(&PyDec_Type, unicode, context) +#define PyDec_FromUnicode(st, unicode, context) \ + PyDecType_FromUnicode(st->PyDec_Type, unicode, context) +#define PyDec_FromUnicodeExact(st, unicode, context) \ + PyDecType_FromUnicodeExact(st->PyDec_Type, unicode, context) +#define PyDec_FromUnicodeExactWS(st, unicode, context) \ + PyDecType_FromUnicodeExactWS(st->PyDec_Type, unicode, context) -#define PyDec_FromSsize(v, context) \ - PyDecType_FromSsize(&PyDec_Type, v, context) -#define PyDec_FromSsizeExact(v, context) \ - PyDecType_FromSsizeExact(&PyDec_Type, v, context) +#define PyDec_FromSsize(st, v, context) \ + PyDecType_FromSsize(st->PyDec_Type, v, context) +#define PyDec_FromSsizeExact(st, v, context) \ + PyDecType_FromSsizeExact(st->PyDec_Type, v, context) -#define PyDec_FromLong(pylong, context) \ - PyDecType_FromLong(&PyDec_Type, pylong, context) -#define PyDec_FromLongExact(pylong, context) \ - PyDecType_FromLongExact(&PyDec_Type, pylong, context) +#define PyDec_FromLong(st, pylong, context) \ + PyDecType_FromLong(st->PyDec_Type, pylong, context) +#define PyDec_FromLongExact(st, pylong, context) \ + PyDecType_FromLongExact(st->PyDec_Type, pylong, context) -#define PyDec_FromFloat(pyfloat, context) \ - PyDecType_FromFloat(&PyDec_Type, pyfloat, context) -#define PyDec_FromFloatExact(pyfloat, context) \ - PyDecType_FromFloatExact(&PyDec_Type, pyfloat, context) +#define PyDec_FromFloat(st, pyfloat, context) \ + PyDecType_FromFloat(st->PyDec_Type, pyfloat, context) +#define PyDec_FromFloatExact(st, pyfloat, context) \ + PyDecType_FromFloatExact(st->PyDec_Type, pyfloat, context) -#define PyDec_FromSequence(sequence, context) \ - PyDecType_FromSequence(&PyDec_Type, sequence, context) -#define PyDec_FromSequenceExact(sequence, context) \ - PyDecType_FromSequenceExact(&PyDec_Type, sequence, context) +#define PyDec_FromSequence(st, sequence, context) \ + PyDecType_FromSequence(st->PyDec_Type, sequence, context) +#define PyDec_FromSequenceExact(st, sequence, context) \ + PyDecType_FromSequenceExact(st->PyDec_Type, sequence, context) /* class method */ static PyObject * @@ -2673,9 +2776,10 @@ dec_from_float(PyObject *type, PyObject *pyfloat) PyObject *context; PyObject *result; - CURRENT_CONTEXT(context); - result = PyDecType_FromFloatExact(&PyDec_Type, pyfloat, context); - if (type != (PyObject *)&PyDec_Type && result != NULL) { + decimal_state *state = get_module_state_by_def((PyTypeObject *)type); + CURRENT_CONTEXT(state, context); + result = PyDecType_FromFloatExact(state->PyDec_Type, pyfloat, context); + if (type != (PyObject *)state->PyDec_Type && result != NULL) { Py_SETREF(result, PyObject_CallFunctionObjArgs(type, result, NULL)); } @@ -2686,7 +2790,8 @@ dec_from_float(PyObject *type, PyObject *pyfloat) static PyObject * ctx_from_float(PyObject *context, PyObject *v) { - return PyDec_FromFloat(v, context); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); + return PyDec_FromFloat(state, v, context); } /* Apply the context to the input operand. Return a new PyDecObject. */ @@ -2696,7 +2801,8 @@ dec_apply(PyObject *v, PyObject *context) PyObject *result; uint32_t status = 0; - result = dec_alloc(); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); + result = dec_alloc(state); if (result == NULL) { return NULL; } @@ -2722,10 +2828,11 @@ dec_apply(PyObject *v, PyObject *context) static PyObject * PyDecType_FromObjectExact(PyTypeObject *type, PyObject *v, PyObject *context) { + decimal_state *state = get_module_state_by_def(type); if (v == NULL) { return PyDecType_FromSsizeExact(type, 0, context); } - else if (PyDec_Check(v)) { + else if (PyDec_Check(state, v)) { return PyDecType_FromDecimalExact(type, v, context); } else if (PyUnicode_Check(v)) { @@ -2756,10 +2863,11 @@ PyDecType_FromObjectExact(PyTypeObject *type, PyObject *v, PyObject *context) static PyObject * PyDec_FromObject(PyObject *v, PyObject *context) { + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); if (v == NULL) { - return PyDec_FromSsize(0, context); + return PyDec_FromSsize(state, 0, context); } - else if (PyDec_Check(v)) { + else if (PyDec_Check(state, v)) { mpd_context_t *ctx = CTX(context); if (mpd_isnan(MPD(v)) && MPD(v)->digits > ctx->prec - ctx->clamp) { @@ -2768,7 +2876,7 @@ PyDec_FromObject(PyObject *v, PyObject *context) if (dec_addstatus(context, MPD_Conversion_syntax)) { return NULL; } - result = dec_alloc(); + result = dec_alloc(state); if (result == NULL) { return NULL; } @@ -2778,19 +2886,19 @@ PyDec_FromObject(PyObject *v, PyObject *context) return dec_apply(v, context); } else if (PyUnicode_Check(v)) { - return PyDec_FromUnicode(v, context); + return PyDec_FromUnicode(state, v, context); } else if (PyLong_Check(v)) { - return PyDec_FromLong(v, context); + return PyDec_FromLong(state, v, context); } else if (PyTuple_Check(v) || PyList_Check(v)) { - return PyDec_FromSequence(v, context); + return PyDec_FromSequence(state, v, context); } else if (PyFloat_Check(v)) { if (dec_addstatus(context, MPD_Float_operation)) { return NULL; } - return PyDec_FromFloat(v, context); + return PyDec_FromFloat(state, v, context); } else { PyErr_Format(PyExc_TypeError, @@ -2811,7 +2919,8 @@ dec_new(PyTypeObject *type, PyObject *args, PyObject *kwds) &v, &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = get_module_state_by_def(type); + CONTEXT_CHECK_VA(state, context); return PyDecType_FromObjectExact(type, v, context); } @@ -2841,13 +2950,13 @@ ctx_create_decimal(PyObject *context, PyObject *args) Py_LOCAL_INLINE(int) convert_op(int type_err, PyObject **conv, PyObject *v, PyObject *context) { - - if (PyDec_Check(v)) { + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); + if (PyDec_Check(state, v)) { *conv = Py_NewRef(v); return 1; } if (PyLong_Check(v)) { - *conv = PyDec_FromLongExact(v, context); + *conv = PyDec_FromLongExact(state, v, context); if (*conv == NULL) { return 0; } @@ -2928,8 +3037,6 @@ convert_op(int type_err, PyObject **conv, PyObject *v, PyObject *context) /* Implicit conversions to Decimal for comparison */ /******************************************************************************/ -/* Convert rationals for comparison */ -static PyObject *Rational = NULL; static PyObject * multiply_by_denominator(PyObject *v, PyObject *r, PyObject *context) { @@ -2946,7 +3053,8 @@ multiply_by_denominator(PyObject *v, PyObject *r, PyObject *context) if (tmp == NULL) { return NULL; } - denom = PyDec_FromLongExact(tmp, context); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); + denom = PyDec_FromLongExact(state, tmp, context); Py_DECREF(tmp); if (denom == NULL) { return NULL; @@ -2958,7 +3066,7 @@ multiply_by_denominator(PyObject *v, PyObject *r, PyObject *context) PyErr_NoMemory(); return NULL; } - result = dec_alloc(); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(denom); mpd_del(vv); @@ -3000,7 +3108,8 @@ numerator_as_decimal(PyObject *r, PyObject *context) return NULL; } - num = PyDec_FromLongExact(tmp, context); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); + num = PyDec_FromLongExact(state, tmp, context); Py_DECREF(tmp); return num; } @@ -3018,11 +3127,12 @@ convert_op_cmp(PyObject **vcmp, PyObject **wcmp, PyObject *v, PyObject *w, *vcmp = v; - if (PyDec_Check(w)) { + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); + if (PyDec_Check(state, w)) { *wcmp = Py_NewRef(w); } else if (PyLong_Check(w)) { - *wcmp = PyDec_FromLongExact(w, context); + *wcmp = PyDec_FromLongExact(state, w, context); } else if (PyFloat_Check(w)) { if (op != Py_EQ && op != Py_NE && @@ -3031,7 +3141,7 @@ convert_op_cmp(PyObject **vcmp, PyObject **wcmp, PyObject *v, PyObject *w, } else { ctx->status |= MPD_Float_operation; - *wcmp = PyDec_FromFloatExact(w, context); + *wcmp = PyDec_FromFloatExact(state, w, context); } } else if (PyComplex_Check(w) && (op == Py_EQ || op == Py_NE)) { @@ -3046,7 +3156,7 @@ convert_op_cmp(PyObject **vcmp, PyObject **wcmp, PyObject *v, PyObject *w, } else { ctx->status |= MPD_Float_operation; - *wcmp = PyDec_FromFloatExact(tmp, context); + *wcmp = PyDec_FromFloatExact(state, tmp, context); Py_DECREF(tmp); } } @@ -3055,7 +3165,7 @@ convert_op_cmp(PyObject **vcmp, PyObject **wcmp, PyObject *v, PyObject *w, } } else { - int is_rational = PyObject_IsInstance(w, Rational); + int is_rational = PyObject_IsInstance(w, state->Rational); if (is_rational < 0) { *wcmp = NULL; } @@ -3115,7 +3225,8 @@ dec_str(PyObject *dec) mpd_ssize_t size; char *cp; - CURRENT_CONTEXT(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); + CURRENT_CONTEXT(state, context); size = mpd_to_sci_size(&cp, MPD(dec), CtxCaps(context)); if (size < 0) { PyErr_NoMemory(); @@ -3133,8 +3244,8 @@ dec_repr(PyObject *dec) { PyObject *res, *context; char *cp; - - CURRENT_CONTEXT(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); + CURRENT_CONTEXT(state, context); cp = mpd_to_sci(MPD(dec), CtxCaps(context)); if (cp == NULL) { PyErr_NoMemory(); @@ -3295,7 +3406,8 @@ dec_format(PyObject *dec, PyObject *args) mpd_t tmp = {MPD_STATIC|MPD_STATIC_DATA,0,0,0,MPD_MINALLOC_MAX,dt}; - CURRENT_CONTEXT(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); + CURRENT_CONTEXT(state, context); if (!PyArg_ParseTuple(args, "O|O", &fmtarg, &override)) { return NULL; } @@ -3558,9 +3670,10 @@ dec_as_integer_ratio(PyObject *self, PyObject *args UNUSED) return NULL; } - CURRENT_CONTEXT(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + CURRENT_CONTEXT(state, context); - tmp = dec_alloc(); + tmp = dec_alloc(state); if (tmp == NULL) { return NULL; } @@ -3591,14 +3704,14 @@ dec_as_integer_ratio(PyObject *self, PyObject *args UNUSED) goto error; } - Py_SETREF(exponent, _py_long_power(tmp, exponent, Py_None)); + Py_SETREF(exponent, state->_py_long_power(tmp, exponent, Py_None)); Py_DECREF(tmp); if (exponent == NULL) { goto error; } if (exp >= 0) { - Py_SETREF(numerator, _py_long_multiply(numerator, exponent)); + Py_SETREF(numerator, state->_py_long_multiply(numerator, exponent)); if (numerator == NULL) { goto error; } @@ -3614,8 +3727,8 @@ dec_as_integer_ratio(PyObject *self, PyObject *args UNUSED) if (tmp == NULL) { goto error; } - Py_SETREF(numerator, _py_long_floor_divide(numerator, tmp)); - Py_SETREF(denominator, _py_long_floor_divide(denominator, tmp)); + Py_SETREF(numerator, state->_py_long_floor_divide(numerator, tmp)); + Py_SETREF(denominator, state->_py_long_floor_divide(denominator, tmp)); Py_DECREF(tmp); if (numerator == NULL || denominator == NULL) { goto error; @@ -3646,11 +3759,12 @@ PyDec_ToIntegralValue(PyObject *dec, PyObject *args, PyObject *kwds) &rounding, &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); + CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); if (rounding != Py_None) { - int round = getround(rounding); + int round = getround(state, rounding); if (round < 0) { return NULL; } @@ -3659,7 +3773,7 @@ PyDec_ToIntegralValue(PyObject *dec, PyObject *args, PyObject *kwds) } } - result = dec_alloc(); + result = dec_alloc(state); if (result == NULL) { return NULL; } @@ -3687,11 +3801,12 @@ PyDec_ToIntegralExact(PyObject *dec, PyObject *args, PyObject *kwds) &rounding, &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); + CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); if (rounding != Py_None) { - int round = getround(rounding); + int round = getround(state, rounding); if (round < 0) { return NULL; } @@ -3700,7 +3815,7 @@ PyDec_ToIntegralExact(PyObject *dec, PyObject *args, PyObject *kwds) } } - result = dec_alloc(); + result = dec_alloc(state); if (result == NULL) { return NULL; } @@ -3754,8 +3869,8 @@ PyDec_Round(PyObject *dec, PyObject *args) uint32_t status = 0; PyObject *context; - - CURRENT_CONTEXT(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); + CURRENT_CONTEXT(state, context); if (!PyArg_ParseTuple(args, "|O", &x)) { return NULL; } @@ -3775,7 +3890,7 @@ PyDec_Round(PyObject *dec, PyObject *args) if (y == -1 && PyErr_Occurred()) { return NULL; } - result = dec_alloc(); + result = dec_alloc(state); if (result == NULL) { return NULL; } @@ -3794,7 +3909,6 @@ PyDec_Round(PyObject *dec, PyObject *args) } } -static PyTypeObject *DecimalTuple = NULL; /* Return the DecimalTuple representation of a PyDecObject. */ static PyObject * PyDec_AsTuple(PyObject *dec, PyObject *dummy UNUSED) @@ -3877,7 +3991,8 @@ PyDec_AsTuple(PyObject *dec, PyObject *dummy UNUSED) } } - result = PyObject_CallFunctionObjArgs((PyObject *)DecimalTuple, + decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); + result = PyObject_CallFunctionObjArgs((PyObject *)state->DecimalTuple, sign, coeff, expt, NULL); out: @@ -3903,8 +4018,9 @@ nm_##MPDFUNC(PyObject *self) \ PyObject *context; \ uint32_t status = 0; \ \ - CURRENT_CONTEXT(context); \ - if ((result = dec_alloc()) == NULL) { \ + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); \ + CURRENT_CONTEXT(state, context); \ + if ((result = dec_alloc(state)) == NULL) { \ return NULL; \ } \ \ @@ -3927,10 +4043,11 @@ nm_##MPDFUNC(PyObject *self, PyObject *other) \ PyObject *context; \ uint32_t status = 0; \ \ - CURRENT_CONTEXT(context) ; \ + decimal_state *state = find_state_left_or_right(self, other); \ + CURRENT_CONTEXT(state, context) ; \ CONVERT_BINOP(&a, &b, self, other, context); \ \ - if ((result = dec_alloc()) == NULL) { \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ return NULL; \ @@ -3967,7 +4084,8 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &context)) { \ return NULL; \ } \ - CONTEXT_CHECK_VA(context); \ + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); \ + CONTEXT_CHECK_VA(state, context); \ \ return MPDFUNC(MPD(self), CTX(context)) ? incr_true() : incr_false(); \ } @@ -3986,9 +4104,11 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &context)) { \ return NULL; \ } \ - CONTEXT_CHECK_VA(context); \ + decimal_state *state = \ + get_module_state_by_def(Py_TYPE(self)); \ + CONTEXT_CHECK_VA(state, context); \ \ - if ((result = dec_alloc()) == NULL) { \ + if ((result = dec_alloc(state)) == NULL) { \ return NULL; \ } \ \ @@ -4017,10 +4137,12 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &other, &context)) { \ return NULL; \ } \ - CONTEXT_CHECK_VA(context); \ + decimal_state *state = \ + get_module_state_by_def(Py_TYPE(self)); \ + CONTEXT_CHECK_VA(state, context); \ CONVERT_BINOP_RAISE(&a, &b, self, other, context); \ \ - if ((result = dec_alloc()) == NULL) { \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ return NULL; \ @@ -4054,10 +4176,12 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &other, &context)) { \ return NULL; \ } \ - CONTEXT_CHECK_VA(context); \ + decimal_state *state = \ + get_module_state_by_def(Py_TYPE(self)); \ + CONTEXT_CHECK_VA(state, context); \ CONVERT_BINOP_RAISE(&a, &b, self, other, context); \ \ - if ((result = dec_alloc()) == NULL) { \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ return NULL; \ @@ -4086,10 +4210,11 @@ dec_##MPDFUNC(PyObject *self, PyObject *args, PyObject *kwds) \ &other, &third, &context)) { \ return NULL; \ } \ - CONTEXT_CHECK_VA(context); \ + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); \ + CONTEXT_CHECK_VA(state, context); \ CONVERT_TERNOP_RAISE(&a, &b, &c, self, other, third, context); \ \ - if ((result = dec_alloc()) == NULL) { \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ Py_DECREF(c); \ @@ -4128,8 +4253,8 @@ static PyObject * nm_dec_as_long(PyObject *dec) { PyObject *context; - - CURRENT_CONTEXT(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(dec)); + CURRENT_CONTEXT(state, context); return dec_as_long(dec, context, MPD_ROUND_DOWN); } @@ -4148,16 +4273,17 @@ nm_mpd_qdivmod(PyObject *v, PyObject *w) uint32_t status = 0; PyObject *ret; - CURRENT_CONTEXT(context); + decimal_state *state = find_state_left_or_right(v, w); + CURRENT_CONTEXT(state, context); CONVERT_BINOP(&a, &b, v, w, context); - q = dec_alloc(); + q = dec_alloc(state); if (q == NULL) { Py_DECREF(a); Py_DECREF(b); return NULL; } - r = dec_alloc(); + r = dec_alloc(state); if (r == NULL) { Py_DECREF(a); Py_DECREF(b); @@ -4188,7 +4314,8 @@ nm_mpd_qpow(PyObject *base, PyObject *exp, PyObject *mod) PyObject *context; uint32_t status = 0; - CURRENT_CONTEXT(context); + decimal_state *state = find_state_left_or_right(base, exp); + CURRENT_CONTEXT(state, context); CONVERT_BINOP(&a, &b, base, exp, context); if (mod != Py_None) { @@ -4199,7 +4326,7 @@ nm_mpd_qpow(PyObject *base, PyObject *exp, PyObject *mod) } } - result = dec_alloc(); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); Py_DECREF(b); @@ -4296,11 +4423,12 @@ dec_conjugate(PyObject *self, PyObject *dummy UNUSED) } static PyObject * -dec_mpd_radix(PyObject *self UNUSED, PyObject *dummy UNUSED) +dec_mpd_radix(PyObject *self, PyObject *dummy UNUSED) { PyObject *result; - result = dec_alloc(); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + result = dec_alloc(state); if (result == NULL) { return NULL; } @@ -4315,7 +4443,8 @@ dec_mpd_qcopy_abs(PyObject *self, PyObject *dummy UNUSED) PyObject *result; uint32_t status = 0; - if ((result = dec_alloc()) == NULL) { + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + if ((result = dec_alloc(state)) == NULL) { return NULL; } @@ -4335,7 +4464,8 @@ dec_mpd_qcopy_negate(PyObject *self, PyObject *dummy UNUSED) PyObject *result; uint32_t status = 0; - if ((result = dec_alloc()) == NULL) { + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + if ((result = dec_alloc(state)) == NULL) { return NULL; } @@ -4364,7 +4494,8 @@ dec_mpd_class(PyObject *self, PyObject *args, PyObject *kwds) &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + CONTEXT_CHECK_VA(state, context); cp = mpd_class(MPD(self), CTX(context)); return PyUnicode_FromString(cp); @@ -4383,7 +4514,8 @@ dec_mpd_to_eng(PyObject *self, PyObject *args, PyObject *kwds) &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + CONTEXT_CHECK_VA(state, context); size = mpd_to_eng_size(&s, MPD(self), CtxCaps(context)); if (size < 0) { @@ -4415,10 +4547,11 @@ dec_mpd_qcopy_sign(PyObject *self, PyObject *args, PyObject *kwds) &other, &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + CONTEXT_CHECK_VA(state, context); CONVERT_BINOP_RAISE(&a, &b, self, other, context); - result = dec_alloc(); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); Py_DECREF(b); @@ -4449,7 +4582,8 @@ dec_mpd_same_quantum(PyObject *self, PyObject *args, PyObject *kwds) &other, &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + CONTEXT_CHECK_VA(state, context); CONVERT_BINOP_RAISE(&a, &b, self, other, context); result = mpd_same_quantum(MPD(a), MPD(b)) ? incr_true() : incr_false(); @@ -4483,11 +4617,12 @@ dec_mpd_qquantize(PyObject *v, PyObject *args, PyObject *kwds) &w, &rounding, &context)) { return NULL; } - CONTEXT_CHECK_VA(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(v)); + CONTEXT_CHECK_VA(state, context); workctx = *CTX(context); if (rounding != Py_None) { - int round = getround(rounding); + int round = getround(state, rounding); if (round < 0) { return NULL; } @@ -4498,7 +4633,7 @@ dec_mpd_qquantize(PyObject *v, PyObject *args, PyObject *kwds) CONVERT_BINOP_RAISE(&a, &b, v, w, context); - result = dec_alloc(); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); Py_DECREF(b); @@ -4526,10 +4661,11 @@ dec_richcompare(PyObject *v, PyObject *w, int op) uint32_t status = 0; int a_issnan, b_issnan; int r; + decimal_state *state = find_state_left_or_right(v, w); - assert(PyDec_Check(v)); + assert(PyDec_Check(state, v)); - CURRENT_CONTEXT(context); + CURRENT_CONTEXT(state, context); CONVERT_BINOP_CMP(&a, &b, v, w, op, context); a_issnan = mpd_issnan(MPD(a)); @@ -4580,7 +4716,8 @@ dec_ceil(PyObject *self, PyObject *dummy UNUSED) { PyObject *context; - CURRENT_CONTEXT(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + CURRENT_CONTEXT(state, context); return dec_as_long(self, context, MPD_ROUND_CEILING); } @@ -4618,7 +4755,8 @@ dec_floor(PyObject *self, PyObject *dummy UNUSED) { PyObject *context; - CURRENT_CONTEXT(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + CURRENT_CONTEXT(state, context); return dec_as_long(self, context, MPD_ROUND_FLOOR); } @@ -4782,7 +4920,8 @@ dec_trunc(PyObject *self, PyObject *dummy UNUSED) { PyObject *context; - CURRENT_CONTEXT(context); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + CURRENT_CONTEXT(state, context); return dec_as_long(self, context, MPD_ROUND_DOWN); } @@ -4798,7 +4937,8 @@ dec_imag(PyObject *self UNUSED, void *closure UNUSED) { PyObject *result; - result = dec_alloc(); + decimal_state *state = get_module_state_by_def(Py_TYPE(self)); + result = dec_alloc(state); if (result == NULL) { return NULL; } @@ -4815,43 +4955,6 @@ static PyGetSetDef dec_getsets [] = {NULL} }; -static PyNumberMethods dec_number_methods = -{ - (binaryfunc) nm_mpd_qadd, - (binaryfunc) nm_mpd_qsub, - (binaryfunc) nm_mpd_qmul, - (binaryfunc) nm_mpd_qrem, - (binaryfunc) nm_mpd_qdivmod, - (ternaryfunc) nm_mpd_qpow, - (unaryfunc) nm_mpd_qminus, - (unaryfunc) nm_mpd_qplus, - (unaryfunc) nm_mpd_qabs, - (inquiry) nm_nonzero, - (unaryfunc) 0, /* no bit-complement */ - (binaryfunc) 0, /* no shiftl */ - (binaryfunc) 0, /* no shiftr */ - (binaryfunc) 0, /* no bit-and */ - (binaryfunc) 0, /* no bit-xor */ - (binaryfunc) 0, /* no bit-ior */ - (unaryfunc) nm_dec_as_long, - 0, /* nb_reserved */ - (unaryfunc) PyDec_AsFloat, - 0, /* binaryfunc nb_inplace_add; */ - 0, /* binaryfunc nb_inplace_subtract; */ - 0, /* binaryfunc nb_inplace_multiply; */ - 0, /* binaryfunc nb_inplace_remainder; */ - 0, /* ternaryfunc nb_inplace_power; */ - 0, /* binaryfunc nb_inplace_lshift; */ - 0, /* binaryfunc nb_inplace_rshift; */ - 0, /* binaryfunc nb_inplace_and; */ - 0, /* binaryfunc nb_inplace_xor; */ - 0, /* binaryfunc nb_inplace_or; */ - (binaryfunc) nm_mpd_qdivint, /* binaryfunc nb_floor_divide; */ - (binaryfunc) nm_mpd_qdiv, /* binaryfunc nb_true_divide; */ - 0, /* binaryfunc nb_inplace_floor_divide; */ - 0, /* binaryfunc nb_inplace_true_divide; */ -}; - static PyMethodDef dec_methods [] = { /* Unary arithmetic functions, optional context arg */ @@ -4944,48 +5047,43 @@ static PyMethodDef dec_methods [] = { NULL, NULL, 1 } }; -static PyTypeObject PyDec_Type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "decimal.Decimal", /* tp_name */ - sizeof(PyDecObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor) dec_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - (getattrfunc) 0, /* tp_getattr */ - (setattrfunc) 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc) dec_repr, /* tp_repr */ - &dec_number_methods, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc) dec_hash, /* tp_hash */ - 0, /* tp_call */ - (reprfunc) dec_str, /* tp_str */ - (getattrofunc) PyObject_GenericGetAttr, /* tp_getattro */ - (setattrofunc) 0, /* tp_setattro */ - (PyBufferProcs *) 0, /* tp_as_buffer */ - (Py_TPFLAGS_DEFAULT| - Py_TPFLAGS_BASETYPE), /* tp_flags */ - doc_decimal, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - dec_richcompare, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - dec_methods, /* tp_methods */ - 0, /* tp_members */ - dec_getsets, /* 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 */ - dec_new, /* tp_new */ - PyObject_Del, /* tp_free */ +static PyType_Slot dec_slots[] = { + {Py_tp_dealloc, dec_dealloc}, + {Py_tp_traverse, dec_traverse}, + {Py_tp_repr, dec_repr}, + {Py_tp_hash, dec_hash}, + {Py_tp_str, dec_str}, + {Py_tp_doc, (void *)doc_decimal}, + {Py_tp_richcompare, dec_richcompare}, + {Py_tp_methods, dec_methods}, + {Py_tp_getset, dec_getsets}, + {Py_tp_new, dec_new}, + + // Number protocol + {Py_nb_add, nm_mpd_qadd}, + {Py_nb_subtract, nm_mpd_qsub}, + {Py_nb_multiply, nm_mpd_qmul}, + {Py_nb_remainder, nm_mpd_qrem}, + {Py_nb_divmod, nm_mpd_qdivmod}, + {Py_nb_power, nm_mpd_qpow}, + {Py_nb_negative, nm_mpd_qminus}, + {Py_nb_positive, nm_mpd_qplus}, + {Py_nb_absolute, nm_mpd_qabs}, + {Py_nb_bool, nm_nonzero}, + {Py_nb_int, nm_dec_as_long}, + {Py_nb_float, PyDec_AsFloat}, + {Py_nb_floor_divide, nm_mpd_qdivint}, + {Py_nb_true_divide, nm_mpd_qdiv}, + {0, NULL}, +}; + + +static PyType_Spec dec_spec = { + .name = "decimal.Decimal", + .basicsize = sizeof(PyDecObject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE), + .slots = dec_slots, }; @@ -5037,8 +5135,9 @@ ctx_##MPDFUNC(PyObject *context, PyObject *v) \ uint32_t status = 0; \ \ CONVERT_OP_RAISE(&a, v, context); \ - \ - if ((result = dec_alloc()) == NULL) { \ + decimal_state *state = \ + get_module_state_by_def(Py_TYPE(context)); \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ return NULL; \ } \ @@ -5068,8 +5167,9 @@ ctx_##MPDFUNC(PyObject *context, PyObject *args) \ } \ \ CONVERT_BINOP_RAISE(&a, &b, v, w, context); \ - \ - if ((result = dec_alloc()) == NULL) { \ + decimal_state *state = \ + get_module_state_by_def(Py_TYPE(context)); \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ return NULL; \ @@ -5103,8 +5203,9 @@ ctx_##MPDFUNC(PyObject *context, PyObject *args) \ } \ \ CONVERT_BINOP_RAISE(&a, &b, v, w, context); \ - \ - if ((result = dec_alloc()) == NULL) { \ + decimal_state *state = \ + get_module_state_by_def(Py_TYPE(context)); \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ return NULL; \ @@ -5132,8 +5233,8 @@ ctx_##MPDFUNC(PyObject *context, PyObject *args) \ } \ \ CONVERT_TERNOP_RAISE(&a, &b, &c, v, w, x, context); \ - \ - if ((result = dec_alloc()) == NULL) { \ + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); \ + if ((result = dec_alloc(state)) == NULL) { \ Py_DECREF(a); \ Py_DECREF(b); \ Py_DECREF(c); \ @@ -5198,14 +5299,14 @@ ctx_mpd_qdivmod(PyObject *context, PyObject *args) } CONVERT_BINOP_RAISE(&a, &b, v, w, context); - - q = dec_alloc(); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); + q = dec_alloc(state); if (q == NULL) { Py_DECREF(a); Py_DECREF(b); return NULL; } - r = dec_alloc(); + r = dec_alloc(state); if (r == NULL) { Py_DECREF(a); Py_DECREF(b); @@ -5253,7 +5354,8 @@ ctx_mpd_qpow(PyObject *context, PyObject *args, PyObject *kwds) } } - result = dec_alloc(); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); Py_DECREF(b); @@ -5304,7 +5406,8 @@ DecCtx_BoolFunc_NO_CTX(mpd_iszero) static PyObject * ctx_iscanonical(PyObject *context UNUSED, PyObject *v) { - if (!PyDec_Check(v)) { + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); + if (!PyDec_Check(state, v)) { PyErr_SetString(PyExc_TypeError, "argument must be a Decimal"); return NULL; @@ -5329,7 +5432,8 @@ PyDecContext_Apply(PyObject *context, PyObject *v) static PyObject * ctx_canonical(PyObject *context UNUSED, PyObject *v) { - if (!PyDec_Check(v)) { + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); + if (!PyDec_Check(state, v)) { PyErr_SetString(PyExc_TypeError, "argument must be a Decimal"); return NULL; @@ -5345,8 +5449,8 @@ ctx_mpd_qcopy_abs(PyObject *context, PyObject *v) uint32_t status = 0; CONVERT_OP_RAISE(&a, v, context); - - result = dec_alloc(); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); return NULL; @@ -5378,8 +5482,8 @@ ctx_mpd_qcopy_negate(PyObject *context, PyObject *v) uint32_t status = 0; CONVERT_OP_RAISE(&a, v, context); - - result = dec_alloc(); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); return NULL; @@ -5475,8 +5579,8 @@ ctx_mpd_qcopy_sign(PyObject *context, PyObject *args) } CONVERT_BINOP_RAISE(&a, &b, v, w, context); - - result = dec_alloc(); + decimal_state *state = get_module_state_by_def(Py_TYPE(context)); + result = dec_alloc(state); if (result == NULL) { Py_DECREF(a); Py_DECREF(b); @@ -5629,47 +5733,27 @@ static PyMethodDef context_methods [] = { NULL, NULL, 1 } }; -static PyTypeObject PyDecContext_Type = -{ - PyVarObject_HEAD_INIT(NULL, 0) - "decimal.Context", /* tp_name */ - sizeof(PyDecContextObject), /* tp_basicsize */ - 0, /* tp_itemsize */ - (destructor) context_dealloc, /* tp_dealloc */ - 0, /* tp_vectorcall_offset */ - (getattrfunc) 0, /* tp_getattr */ - (setattrfunc) 0, /* tp_setattr */ - 0, /* tp_as_async */ - (reprfunc) context_repr, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - (hashfunc) 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - (getattrofunc) context_getattr, /* tp_getattro */ - (setattrofunc) context_setattr, /* tp_setattro */ - (PyBufferProcs *) 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ - doc_context, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - context_methods, /* tp_methods */ - 0, /* tp_members */ - context_getsets, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - context_init, /* tp_init */ - 0, /* tp_alloc */ - context_new, /* tp_new */ - PyObject_Del, /* tp_free */ +static PyType_Slot context_slots[] = { + {Py_tp_dealloc, context_dealloc}, + {Py_tp_traverse, context_traverse}, + {Py_tp_clear, context_clear}, + {Py_tp_repr, context_repr}, + {Py_tp_getattro, context_getattr}, + {Py_tp_setattro, context_setattr}, + {Py_tp_doc, (void *)doc_context}, + {Py_tp_methods, context_methods}, + {Py_tp_getset, context_getsets}, + {Py_tp_init, context_init}, + {Py_tp_new, context_new}, + {0, NULL}, +}; + +static PyType_Spec context_spec = { + .name = "decimal.Context", + .basicsize = sizeof(PyDecContextObject), + .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE), + .slots = context_slots, }; @@ -5684,17 +5768,6 @@ static PyMethodDef _decimal_methods [] = { NULL, NULL, 1, NULL } }; -static struct PyModuleDef _decimal_module = { - PyModuleDef_HEAD_INIT, - "decimal", - doc__decimal, - -1, - _decimal_methods, - NULL, - NULL, - NULL, - NULL -}; struct ssize_constmap { const char *name; mpd_ssize_t val; }; static struct ssize_constmap ssize_constants [] = { @@ -5770,10 +5843,9 @@ cfunc_noargs(PyTypeObject *t, const char *name) } -PyMODINIT_FUNC -PyInit__decimal(void) +static int +_decimal_exec(PyObject *m) { - PyObject *m = NULL; PyObject *numbers = NULL; PyObject *Number = NULL; PyObject *collections = NULL; @@ -5794,31 +5866,34 @@ PyInit__decimal(void) mpd_free = PyMem_Free; mpd_setminalloc(_Py_DEC_MINALLOC); + decimal_state *state = get_module_state(m); /* Init external C-API functions */ - _py_long_multiply = PyLong_Type.tp_as_number->nb_multiply; - _py_long_floor_divide = PyLong_Type.tp_as_number->nb_floor_divide; - _py_long_power = PyLong_Type.tp_as_number->nb_power; - _py_float_abs = PyFloat_Type.tp_as_number->nb_absolute; - ASSIGN_PTR(_py_float_as_integer_ratio, cfunc_noargs(&PyFloat_Type, - "as_integer_ratio")); - ASSIGN_PTR(_py_long_bit_length, cfunc_noargs(&PyLong_Type, "bit_length")); + state->_py_long_multiply = PyLong_Type.tp_as_number->nb_multiply; + state->_py_long_floor_divide = PyLong_Type.tp_as_number->nb_floor_divide; + state->_py_long_power = PyLong_Type.tp_as_number->nb_power; + state->_py_float_abs = PyFloat_Type.tp_as_number->nb_absolute; + ASSIGN_PTR(state->_py_float_as_integer_ratio, cfunc_noargs(&PyFloat_Type, + "as_integer_ratio")); + ASSIGN_PTR(state->_py_long_bit_length, cfunc_noargs(&PyLong_Type, "bit_length")); /* Init types */ - PyDec_Type.tp_base = &PyBaseObject_Type; - PyDecContext_Type.tp_base = &PyBaseObject_Type; - PyDecContextManager_Type.tp_base = &PyBaseObject_Type; - PyDecSignalDictMixin_Type.tp_base = &PyBaseObject_Type; - - CHECK_INT(PyType_Ready(&PyDec_Type)); - CHECK_INT(PyType_Ready(&PyDecContext_Type)); - CHECK_INT(PyType_Ready(&PyDecSignalDictMixin_Type)); - CHECK_INT(PyType_Ready(&PyDecContextManager_Type)); +#define CREATE_TYPE(mod, type, spec) \ + do { \ + type = (PyTypeObject *)PyType_FromMetaclass(NULL, mod, spec, NULL); \ + CHECK_PTR(type); \ + } while (0) + + CREATE_TYPE(m, state->PyDec_Type, &dec_spec); + CREATE_TYPE(m, state->PyDecContext_Type, &context_spec); + CREATE_TYPE(m, state->PyDecSignalDictMixin_Type, &signaldict_spec); + CREATE_TYPE(m, state->PyDecContextManager_Type, &ctxmanager_spec); + #undef CREATE_TYPE ASSIGN_PTR(obj, PyUnicode_FromString("decimal")); - CHECK_INT(PyDict_SetItemString(PyDec_Type.tp_dict, "__module__", obj)); - CHECK_INT(PyDict_SetItemString(PyDecContext_Type.tp_dict, + CHECK_INT(PyDict_SetItemString(state->PyDec_Type->tp_dict, "__module__", obj)); + CHECK_INT(PyDict_SetItemString(state->PyDecContext_Type->tp_dict, "__module__", obj)); Py_CLEAR(obj); @@ -5828,22 +5903,22 @@ PyInit__decimal(void) ASSIGN_PTR(Number, PyObject_GetAttrString(numbers, "Number")); /* Register Decimal with the Number abstract base class */ ASSIGN_PTR(obj, PyObject_CallMethod(Number, "register", "(O)", - (PyObject *)&PyDec_Type)); + (PyObject *)state->PyDec_Type)); Py_CLEAR(obj); /* Rational is a global variable used for fraction comparisons. */ - ASSIGN_PTR(Rational, PyObject_GetAttrString(numbers, "Rational")); + ASSIGN_PTR(state->Rational, PyObject_GetAttrString(numbers, "Rational")); /* Done with numbers, Number */ Py_CLEAR(numbers); Py_CLEAR(Number); /* DecimalTuple */ ASSIGN_PTR(collections, PyImport_ImportModule("collections")); - ASSIGN_PTR(DecimalTuple, (PyTypeObject *)PyObject_CallMethod(collections, + ASSIGN_PTR(state->DecimalTuple, (PyTypeObject *)PyObject_CallMethod(collections, "namedtuple", "(ss)", "DecimalTuple", "sign digits exponent")); ASSIGN_PTR(obj, PyUnicode_FromString("decimal")); - CHECK_INT(PyDict_SetItemString(DecimalTuple->tp_dict, "__module__", obj)); + CHECK_INT(PyDict_SetItemString(state->DecimalTuple->tp_dict, "__module__", obj)); Py_CLEAR(obj); /* MutableMapping */ @@ -5851,10 +5926,10 @@ PyInit__decimal(void) ASSIGN_PTR(MutableMapping, PyObject_GetAttrString(collections_abc, "MutableMapping")); /* Create SignalDict type */ - ASSIGN_PTR(PyDecSignalDict_Type, + ASSIGN_PTR(state->PyDecSignalDict_Type, (PyTypeObject *)PyObject_CallFunction( (PyObject *)&PyType_Type, "s(OO){}", - "SignalDict", &PyDecSignalDictMixin_Type, + "SignalDict", state->PyDecSignalDictMixin_Type, MutableMapping)); /* Done with collections, MutableMapping */ @@ -5862,49 +5937,45 @@ PyInit__decimal(void) Py_CLEAR(collections_abc); Py_CLEAR(MutableMapping); - - /* Create the module */ - ASSIGN_PTR(m, PyModule_Create(&_decimal_module)); - /* Add types to the module */ - CHECK_INT(PyModule_AddObject(m, "Decimal", Py_NewRef(&PyDec_Type))); - CHECK_INT(PyModule_AddObject(m, "Context", - Py_NewRef(&PyDecContext_Type))); - CHECK_INT(PyModule_AddObject(m, "DecimalTuple", Py_NewRef(DecimalTuple))); + CHECK_INT(PyModule_AddType(m, state->PyDec_Type)); + CHECK_INT(PyModule_AddType(m, state->PyDecContext_Type)); + CHECK_INT(PyModule_AddType(m, state->DecimalTuple)); /* Create top level exception */ - ASSIGN_PTR(DecimalException, PyErr_NewException( + ASSIGN_PTR(state->DecimalException, PyErr_NewException( "decimal.DecimalException", PyExc_ArithmeticError, NULL)); - CHECK_INT(PyModule_AddObject(m, "DecimalException", Py_NewRef(DecimalException))); + CHECK_INT(PyModule_AddType(m, (PyTypeObject *)state->DecimalException)); /* Create signal tuple */ - ASSIGN_PTR(SignalTuple, PyTuple_New(SIGNAL_MAP_LEN)); + ASSIGN_PTR(state->SignalTuple, PyTuple_New(SIGNAL_MAP_LEN)); /* Add exceptions that correspond to IEEE signals */ + signal_map_init(state); for (i = SIGNAL_MAP_LEN-1; i >= 0; i--) { PyObject *base; - cm = signal_map + i; + cm = state->signal_map + i; switch (cm->flag) { case MPD_Float_operation: - base = PyTuple_Pack(2, DecimalException, PyExc_TypeError); + base = PyTuple_Pack(2, state->DecimalException, PyExc_TypeError); break; case MPD_Division_by_zero: - base = PyTuple_Pack(2, DecimalException, PyExc_ZeroDivisionError); + base = PyTuple_Pack(2, state->DecimalException, PyExc_ZeroDivisionError); break; case MPD_Overflow: - base = PyTuple_Pack(2, signal_map[INEXACT].ex, - signal_map[ROUNDED].ex); + base = PyTuple_Pack(2, state->signal_map[INEXACT].ex, + state->signal_map[ROUNDED].ex); break; case MPD_Underflow: - base = PyTuple_Pack(3, signal_map[INEXACT].ex, - signal_map[ROUNDED].ex, - signal_map[SUBNORMAL].ex); + base = PyTuple_Pack(3, state->signal_map[INEXACT].ex, + state->signal_map[ROUNDED].ex, + state->signal_map[SUBNORMAL].ex); break; default: - base = PyTuple_Pack(1, DecimalException); + base = PyTuple_Pack(1, state->DecimalException); break; } @@ -5919,7 +5990,7 @@ PyInit__decimal(void) CHECK_INT(PyModule_AddObject(m, cm->name, Py_NewRef(cm->ex))); /* add to signal tuple */ - PyTuple_SET_ITEM(SignalTuple, i, Py_NewRef(cm->ex)); + PyTuple_SET_ITEM(state->SignalTuple, i, Py_NewRef(cm->ex)); } /* @@ -5927,16 +5998,16 @@ PyInit__decimal(void) * several conditions, including InvalidOperation! Naming the * signal IEEEInvalidOperation would prevent the confusion. */ - cond_map[0].ex = signal_map[0].ex; + cond_map[0].ex = state->signal_map[0].ex; /* Add remaining exceptions, inherit from InvalidOperation */ for (cm = cond_map+1; cm->name != NULL; cm++) { PyObject *base; if (cm->flag == MPD_Division_undefined) { - base = PyTuple_Pack(2, signal_map[0].ex, PyExc_ZeroDivisionError); + base = PyTuple_Pack(2, state->signal_map[0].ex, PyExc_ZeroDivisionError); } else { - base = PyTuple_Pack(1, signal_map[0].ex); + base = PyTuple_Pack(1, state->signal_map[0].ex); } if (base == NULL) { goto error; /* GCOV_NOT_REACHED */ @@ -5950,33 +6021,33 @@ PyInit__decimal(void) /* Init default context template first */ - ASSIGN_PTR(default_context_template, - PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL)); + ASSIGN_PTR(state->default_context_template, + PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL)); CHECK_INT(PyModule_AddObject(m, "DefaultContext", - Py_NewRef(default_context_template))); + Py_NewRef(state->default_context_template))); #ifndef WITH_DECIMAL_CONTEXTVAR - ASSIGN_PTR(tls_context_key, PyUnicode_FromString("___DECIMAL_CTX__")); + ASSIGN_PTR(state->tls_context_key, PyUnicode_FromString("___DECIMAL_CTX__")); CHECK_INT(PyModule_AddObject(m, "HAVE_CONTEXTVAR", Py_NewRef(Py_False))); #else - ASSIGN_PTR(current_context_var, PyContextVar_New("decimal_context", NULL)); + ASSIGN_PTR(state->current_context_var, PyContextVar_New("decimal_context", NULL)); CHECK_INT(PyModule_AddObject(m, "HAVE_CONTEXTVAR", Py_NewRef(Py_True))); #endif CHECK_INT(PyModule_AddObject(m, "HAVE_THREADS", Py_NewRef(Py_True))); /* Init basic context template */ - ASSIGN_PTR(basic_context_template, - PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL)); - init_basic_context(basic_context_template); + ASSIGN_PTR(state->basic_context_template, + PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL)); + init_basic_context(state->basic_context_template); CHECK_INT(PyModule_AddObject(m, "BasicContext", - Py_NewRef(basic_context_template))); + Py_NewRef(state->basic_context_template))); /* Init extended context template */ - ASSIGN_PTR(extended_context_template, - PyObject_CallObject((PyObject *)&PyDecContext_Type, NULL)); - init_extended_context(extended_context_template); + ASSIGN_PTR(state->extended_context_template, + PyObject_CallObject((PyObject *)state->PyDecContext_Type, NULL)); + init_extended_context(state->extended_context_template); CHECK_INT(PyModule_AddObject(m, "ExtendedContext", - Py_NewRef(extended_context_template))); + Py_NewRef(state->extended_context_template))); /* Init mpd_ssize_t constants */ @@ -5994,8 +6065,8 @@ PyInit__decimal(void) /* Init string constants */ for (i = 0; i < _PY_DEC_ROUND_GUARD; i++) { - ASSIGN_PTR(round_map[i], PyUnicode_InternFromString(mpd_round_string[i])); - CHECK_INT(PyModule_AddObject(m, mpd_round_string[i], Py_NewRef(round_map[i]))); + ASSIGN_PTR(state->round_map[i], PyUnicode_InternFromString(mpd_round_string[i])); + CHECK_INT(PyModule_AddObject(m, mpd_round_string[i], Py_NewRef(state->round_map[i]))); } /* Add specification version number */ @@ -6003,28 +6074,100 @@ PyInit__decimal(void) CHECK_INT(PyModule_AddStringConstant(m, "__libmpdec_version__", mpd_version())); - return m; + return 0; error: Py_CLEAR(obj); /* GCOV_NOT_REACHED */ Py_CLEAR(numbers); /* GCOV_NOT_REACHED */ Py_CLEAR(Number); /* GCOV_NOT_REACHED */ - Py_CLEAR(Rational); /* GCOV_NOT_REACHED */ Py_CLEAR(collections); /* GCOV_NOT_REACHED */ Py_CLEAR(collections_abc); /* GCOV_NOT_REACHED */ Py_CLEAR(MutableMapping); /* GCOV_NOT_REACHED */ - Py_CLEAR(SignalTuple); /* GCOV_NOT_REACHED */ - Py_CLEAR(DecimalTuple); /* GCOV_NOT_REACHED */ - Py_CLEAR(default_context_template); /* GCOV_NOT_REACHED */ + + return -1; /* GCOV_NOT_REACHED */ +} + +static int +decimal_traverse(PyObject *module, visitproc visit, void *arg) +{ + decimal_state *state = get_module_state(module); + Py_VISIT(state->PyDecContextManager_Type); + Py_VISIT(state->PyDecContext_Type); + Py_VISIT(state->PyDecSignalDictMixin_Type); + Py_VISIT(state->PyDec_Type); + Py_VISIT(state->PyDecSignalDict_Type); + Py_VISIT(state->DecimalTuple); + Py_VISIT(state->DecimalException); + +#ifndef WITH_DECIMAL_CONTEXTVAR + Py_VISIT(state->tls_context_key); + Py_VISIT(state->cached_context); +#else + Py_VISIT(state->current_context_var); +#endif + + Py_VISIT(state->default_context_template); + Py_VISIT(state->basic_context_template); + Py_VISIT(state->extended_context_template); + Py_VISIT(state->Rational); + Py_VISIT(state->SignalTuple); + return 0; +} + +static int +decimal_clear(PyObject *module) +{ + decimal_state *state = get_module_state(module); + Py_CLEAR(state->PyDecContextManager_Type); + Py_CLEAR(state->PyDecContext_Type); + Py_CLEAR(state->PyDecSignalDictMixin_Type); + Py_CLEAR(state->PyDec_Type); + Py_CLEAR(state->PyDecSignalDict_Type); + Py_CLEAR(state->DecimalTuple); + Py_CLEAR(state->DecimalException); + #ifndef WITH_DECIMAL_CONTEXTVAR - Py_CLEAR(tls_context_key); /* GCOV_NOT_REACHED */ + Py_CLEAR(state->tls_context_key); + Py_CLEAR(state->cached_context); #else - Py_CLEAR(current_context_var); /* GCOV_NOT_REACHED */ + Py_CLEAR(state->current_context_var); #endif - Py_CLEAR(basic_context_template); /* GCOV_NOT_REACHED */ - Py_CLEAR(extended_context_template); /* GCOV_NOT_REACHED */ - Py_CLEAR(m); /* GCOV_NOT_REACHED */ - return NULL; /* GCOV_NOT_REACHED */ + Py_CLEAR(state->default_context_template); + Py_CLEAR(state->basic_context_template); + Py_CLEAR(state->extended_context_template); + Py_CLEAR(state->Rational); + Py_CLEAR(state->SignalTuple); + return 0; +} + +static void +decimal_free(void *module) +{ + (void)decimal_clear((PyObject *)module); +} + +static struct PyModuleDef_Slot _decimal_slots[] = { + {Py_mod_exec, _decimal_exec}, + {Py_mod_multiple_interpreters, Py_MOD_PER_INTERPRETER_GIL_SUPPORTED}, + {0, NULL}, +}; + +static struct PyModuleDef _decimal_module = { + PyModuleDef_HEAD_INIT, + .m_name = "decimal", + .m_doc = doc__decimal, + .m_size = sizeof(decimal_state), + .m_methods = _decimal_methods, + .m_slots = _decimal_slots, + .m_traverse = decimal_traverse, + .m_clear = decimal_clear, + .m_free = decimal_free, +}; + +PyMODINIT_FUNC +PyInit__decimal(void) +{ + return PyModuleDef_Init(&_decimal_module); } diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv index 7ca14b91c841d4..1e041257879c3b 100644 --- a/Tools/c-analyzer/cpython/globals-to-fix.tsv +++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv @@ -375,10 +375,6 @@ Modules/_datetimemodule.c - PyDateTime_IsoCalendarDateType - Modules/_datetimemodule.c - PyDateTime_TZInfoType - Modules/_datetimemodule.c - PyDateTime_TimeType - Modules/_datetimemodule.c - PyDateTime_TimeZoneType - -Modules/_decimal/_decimal.c - PyDecContextManager_Type - -Modules/_decimal/_decimal.c - PyDecContext_Type - -Modules/_decimal/_decimal.c - PyDecSignalDictMixin_Type - -Modules/_decimal/_decimal.c - PyDec_Type - Modules/xxmodule.c - Null_Type - Modules/xxmodule.c - Str_Type - Modules/xxmodule.c - Xxo_Type - @@ -389,8 +385,6 @@ Modules/xxsubtype.c - spamlist_type - ## non-static types - initialized once ## heap types -Modules/_decimal/_decimal.c - DecimalTuple - -Modules/_decimal/_decimal.c - PyDecSignalDict_Type - Modules/_tkinter.c - PyTclObject_Type - Modules/_tkinter.c - Tkapp_Type - Modules/_tkinter.c - Tktt_Type - @@ -399,7 +393,6 @@ Modules/xxlimited_35.c - Xxo_Type - ## exception types Modules/_ctypes/_ctypes.c - PyExc_ArgError - Modules/_cursesmodule.c - PyCursesError - -Modules/_decimal/_decimal.c - DecimalException - Modules/_tkinter.c - Tkinter_TclError - Modules/xxlimited_35.c - ErrorObject - Modules/xxmodule.c - ErrorObject - @@ -428,13 +421,6 @@ Modules/_datetimemodule.c - us_per_hour - Modules/_datetimemodule.c - us_per_day - Modules/_datetimemodule.c - us_per_week - Modules/_datetimemodule.c - seconds_per_day - -Modules/_decimal/_decimal.c - basic_context_template - -Modules/_decimal/_decimal.c - current_context_var - -Modules/_decimal/_decimal.c - default_context_template - -Modules/_decimal/_decimal.c - extended_context_template - -Modules/_decimal/_decimal.c - round_map - -Modules/_decimal/_decimal.c - Rational - -Modules/_decimal/_decimal.c - SignalTuple - ## state Modules/_asynciomodule.c - fi_freelist - @@ -462,12 +448,6 @@ Modules/_cursesmodule.c - initialised - Modules/_cursesmodule.c - initialised_setupterm - Modules/_cursesmodule.c - initialisedcolors - Modules/_cursesmodule.c - screen_encoding - -Modules/_decimal/_decimal.c - _py_long_multiply - -Modules/_decimal/_decimal.c - _py_long_floor_divide - -Modules/_decimal/_decimal.c - _py_long_power - -Modules/_decimal/_decimal.c - _py_float_abs - -Modules/_decimal/_decimal.c - _py_long_bit_length - -Modules/_decimal/_decimal.c - _py_float_as_integer_ratio - Modules/_elementtree.c - expat_capi - Modules/readline.c - libedit_append_replace_history_offset - Modules/readline.c - using_libedit_emulation -