Skip to content

gh-106078: Prepare to isolate decimal module #106880

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 53 additions & 21 deletions Modules/_decimal/_decimal.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#endif

struct PyDecContextObject;
struct DecCondMap;

typedef struct {
PyTypeObject *PyDecContextManager_Type;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 */
Expand All @@ -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},
Expand All @@ -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},
Expand All @@ -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",
Expand Down Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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,
Expand All @@ -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()) {
Expand Down Expand Up @@ -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";
}
Expand Down Expand Up @@ -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:
Expand All @@ -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);
Expand All @@ -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 */
Expand Down Expand Up @@ -6057,6 +6087,8 @@ PyInit__decimal(void)
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
Expand Down
4 changes: 2 additions & 2 deletions Tools/c-analyzer/cpython/ignored.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -205,13 +205,13 @@ Modules/_datetimemodule.c - max_fold_seconds -
Modules/_datetimemodule.c datetime_isoformat specs -
Modules/_datetimemodule.c parse_hh_mm_ss_ff correction -
Modules/_datetimemodule.c time_isoformat specs -
Modules/_decimal/_decimal.c - cond_map -
Modules/_decimal/_decimal.c - cond_map_template -
Modules/_decimal/_decimal.c - dec_signal_string -
Modules/_decimal/_decimal.c - dflt_ctx -
Modules/_decimal/_decimal.c - int_constants -
Modules/_decimal/_decimal.c - invalid_rounding_err -
Modules/_decimal/_decimal.c - invalid_signals_err -
Modules/_decimal/_decimal.c - signal_map -
Modules/_decimal/_decimal.c - signal_map_template -
Modules/_decimal/_decimal.c - ssize_constants -
Modules/_elementtree.c - ExpatMemoryHandler -
Modules/_hashopenssl.c - py_hashes -
Expand Down