diff options
Diffstat (limited to 'Modules/_decimal')
-rw-r--r-- | Modules/_decimal/_decimal.c | 74 |
1 files changed, 53 insertions, 21 deletions
diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index f9dc6e8..f531def 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -46,6 +46,7 @@ #endif struct PyDecContextObject; +struct DecCondMap; typedef struct { PyTypeObject *PyDecContextManager_Type; @@ -82,6 +83,9 @@ typedef struct { PyObject *SignalTuple; + struct DecCondMap *signal_map; + struct DecCondMap *cond_map; + /* External C-API functions */ binaryfunc _py_long_multiply; binaryfunc _py_long_floor_divide; @@ -181,7 +185,7 @@ incr_false(void) #define DEC_ERR_OCCURRED (DEC_INVALID_SIGNALS<<1) #define DEC_ERRORS (DEC_INVALID_SIGNALS|DEC_ERR_OCCURRED) -typedef struct { +typedef struct DecCondMap { const char *name; /* condition or signal name */ const char *fqname; /* fully qualified name */ uint32_t flag; /* libmpdec flag */ @@ -193,7 +197,7 @@ typedef struct { #define INEXACT 6 #define ROUNDED 7 #define SIGNAL_MAP_LEN 9 -static DecCondMap signal_map[] = { +static DecCondMap signal_map_template[] = { {"InvalidOperation", "decimal.InvalidOperation", MPD_IEEE_Invalid_operation, NULL}, {"FloatOperation", "decimal.FloatOperation", MPD_Float_operation, NULL}, {"DivisionByZero", "decimal.DivisionByZero", MPD_Division_by_zero, NULL}, @@ -207,7 +211,7 @@ static DecCondMap signal_map[] = { }; /* Exceptions that inherit from InvalidOperation */ -static DecCondMap cond_map[] = { +static DecCondMap cond_map_template[] = { {"InvalidOperation", "decimal.InvalidOperation", MPD_Invalid_operation, NULL}, {"ConversionSyntax", "decimal.ConversionSyntax", MPD_Conversion_syntax, NULL}, {"DivisionImpossible", "decimal.DivisionImpossible", MPD_Division_impossible, NULL}, @@ -219,6 +223,21 @@ static DecCondMap cond_map[] = { {NULL} }; +/* Return a duplicate of DecCondMap template */ +static inline DecCondMap * +dec_cond_map_init(DecCondMap *template, Py_ssize_t size) +{ + DecCondMap *cm; + cm = PyMem_Malloc(size); + if (cm == NULL) { + PyErr_NoMemory(); + return NULL; + } + + memcpy(cm, template, size); + return cm; +} + static const char *dec_signal_string[MPD_NUM_FLAGS] = { "Clamped", "InvalidOperation", @@ -312,8 +331,9 @@ static PyObject * flags_as_exception(uint32_t flags) { DecCondMap *cm; + decimal_state *state = GLOBAL_STATE(); - for (cm = signal_map; cm->name != NULL; cm++) { + for (cm = state->signal_map; cm->name != NULL; cm++) { if (flags&cm->flag) { return cm->ex; } @@ -326,8 +346,9 @@ Py_LOCAL_INLINE(uint32_t) exception_as_flag(PyObject *ex) { DecCondMap *cm; + decimal_state *state = GLOBAL_STATE(); - for (cm = signal_map; cm->name != NULL; cm++) { + for (cm = state->signal_map; cm->name != NULL; cm++) { if (cm->ex == ex) { return cm->flag; } @@ -342,20 +363,21 @@ flags_as_list(uint32_t flags) { PyObject *list; DecCondMap *cm; + decimal_state *state = GLOBAL_STATE(); list = PyList_New(0); if (list == NULL) { return NULL; } - for (cm = cond_map; cm->name != NULL; cm++) { + for (cm = state->cond_map; cm->name != NULL; cm++) { if (flags&cm->flag) { if (PyList_Append(list, cm->ex) < 0) { goto error; } } } - 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; @@ -375,13 +397,14 @@ signals_as_list(uint32_t flags) { PyObject *list; DecCondMap *cm; + decimal_state *state = GLOBAL_STATE(); list = PyList_New(0); if (list == NULL) { 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); @@ -421,13 +444,14 @@ flags_as_dict(uint32_t flags) { DecCondMap *cm; PyObject *dict; + decimal_state *state = GLOBAL_STATE(); dict = PyDict_New(); if (dict == NULL) { 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); @@ -445,6 +469,7 @@ dict_as_flags(PyObject *val) DecCondMap *cm; uint32_t flags = 0; int x; + decimal_state *state = GLOBAL_STATE(); if (!PyDict_Check(val)) { PyErr_SetString(PyExc_TypeError, @@ -458,7 +483,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()) { @@ -652,7 +677,8 @@ signaldict_repr(PyObject *self) assert(SIGNAL_MAP_LEN == 9); - for (cm=signal_map, i=0; cm->name != NULL; cm++, i++) { + decimal_state *state = GLOBAL_STATE(); + for (cm=state->signal_map, i=0; cm->name != NULL; cm++, i++) { n[i] = cm->fqname; b[i] = SdFlags(self)&cm->flag ? "True" : "False"; } @@ -5922,10 +5948,12 @@ PyInit__decimal(void) ASSIGN_PTR(state->SignalTuple, PyTuple_New(SIGNAL_MAP_LEN)); /* Add exceptions that correspond to IEEE signals */ + ASSIGN_PTR(state->signal_map, dec_cond_map_init(signal_map_template, + sizeof(signal_map_template))); 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: @@ -5936,13 +5964,13 @@ PyInit__decimal(void) 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, state->DecimalException); @@ -5968,16 +5996,18 @@ PyInit__decimal(void) * several conditions, including InvalidOperation! Naming the * signal IEEEInvalidOperation would prevent the confusion. */ - cond_map[0].ex = signal_map[0].ex; + ASSIGN_PTR(state->cond_map, dec_cond_map_init(cond_map_template, + sizeof(cond_map_template))); + state->cond_map[0].ex = state->signal_map[0].ex; /* Add remaining exceptions, inherit from InvalidOperation */ - for (cm = cond_map+1; cm->name != NULL; cm++) { + for (cm = state->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 */ @@ -6057,6 +6087,8 @@ error: Py_CLEAR(collections_abc); /* GCOV_NOT_REACHED */ Py_CLEAR(MutableMapping); /* GCOV_NOT_REACHED */ Py_CLEAR(state->SignalTuple); /* GCOV_NOT_REACHED */ + PyMem_Free(state->signal_map); /* GCOV_NOT_REACHED */ + PyMem_Free(state->cond_map); /* GCOV_NOT_REACHED */ Py_CLEAR(state->DecimalTuple); /* GCOV_NOT_REACHED */ Py_CLEAR(state->default_context_template); /* GCOV_NOT_REACHED */ #ifndef WITH_DECIMAL_CONTEXTVAR |