diff options
Diffstat (limited to 'Modules/_decimal/_decimal.c')
-rw-r--r-- | Modules/_decimal/_decimal.c | 185 |
1 files changed, 178 insertions, 7 deletions
diff --git a/Modules/_decimal/_decimal.c b/Modules/_decimal/_decimal.c index fb4e020f12..e7c44acba0 100644 --- a/Modules/_decimal/_decimal.c +++ b/Modules/_decimal/_decimal.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2012 Stefan Krah. All rights reserved. + * Copyright (c) 2008-2020 Stefan Krah. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,6 +33,8 @@ #include <stdlib.h> +#define CPYTHON_DECIMAL_MODULE +#include "pydecimal.h" #include "docstrings.h" @@ -5555,6 +5557,160 @@ static PyTypeObject PyDecContext_Type = }; +/****************************************************************************/ +/* C-API */ +/****************************************************************************/ + +static void *_decimal_api[CPYTHON_DECIMAL_MAX_API]; + +/* Simple API */ +static int +PyDec_TypeCheck(const PyObject *v) +{ + return PyDec_Check(v); +} + +static int +PyDec_IsSpecial(const PyObject *v) +{ + if (!PyDec_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "PyDec_IsSpecial: argument must be a Decimal"); + return -1; + } + + return mpd_isspecial(MPD(v)); +} + +static int +PyDec_IsNaN(const PyObject *v) +{ + if (!PyDec_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "PyDec_IsNaN: argument must be a Decimal"); + return -1; + } + + return mpd_isnan(MPD(v)); +} + +static int +PyDec_IsInfinite(const PyObject *v) +{ + if (!PyDec_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "PyDec_IsInfinite: argument must be a Decimal"); + return -1; + } + + return mpd_isinfinite(MPD(v)); +} + +static int64_t +PyDec_GetDigits(const PyObject *v) +{ + if (!PyDec_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "PyDec_GetDigits: argument must be a Decimal"); + return -1; + } + + return MPD(v)->digits; +} + +static mpd_uint128_triple_t +PyDec_AsUint128Triple(const PyObject *v) +{ + if (!PyDec_Check(v)) { + mpd_uint128_triple_t triple = { MPD_TRIPLE_ERROR, 0, 0, 0, 0 }; + PyErr_SetString(PyExc_TypeError, + "PyDec_AsUint128Triple: argument must be a Decimal"); + return triple; + } + + return mpd_as_uint128_triple(MPD(v)); +} + +static PyObject * +PyDec_FromUint128Triple(const mpd_uint128_triple_t *triple) +{ + PyObject *context; + PyObject *result; + uint32_t status = 0; + + CURRENT_CONTEXT(context); + + result = dec_alloc(); + if (result == NULL) { + return NULL; + } + + if (mpd_from_uint128_triple(MPD(result), triple, &status) < 0) { + if (dec_addstatus(context, status)) { + Py_DECREF(result); + return NULL; + } + } + + return result; +} + +/* Advanced API */ +static PyObject * +PyDec_Alloc(void) +{ + return dec_alloc(); +} + +static mpd_t * +PyDec_Get(PyObject *v) +{ + if (!PyDec_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "PyDec_Get: argument must be a Decimal"); + return NULL; + } + + return MPD(v); +} + +static const mpd_t * +PyDec_GetConst(const PyObject *v) +{ + if (!PyDec_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "PyDec_GetConst: argument must be a Decimal"); + return NULL; + } + + return MPD(v); +} + +static PyObject * +init_api(void) +{ + /* Simple API */ + _decimal_api[PyDec_TypeCheck_INDEX] = (void *)PyDec_TypeCheck; + _decimal_api[PyDec_IsSpecial_INDEX] = (void *)PyDec_IsSpecial; + _decimal_api[PyDec_IsNaN_INDEX] = (void *)PyDec_IsNaN; + _decimal_api[PyDec_IsInfinite_INDEX] = (void *)PyDec_IsInfinite; + _decimal_api[PyDec_GetDigits_INDEX] = (void *)PyDec_GetDigits; + _decimal_api[PyDec_AsUint128Triple_INDEX] = (void *)PyDec_AsUint128Triple; + _decimal_api[PyDec_FromUint128Triple_INDEX] = (void *)PyDec_FromUint128Triple; + + /* Advanced API */ + _decimal_api[PyDec_Alloc_INDEX] = (void *)PyDec_Alloc; + _decimal_api[PyDec_Get_INDEX] = (void *)PyDec_Get; + _decimal_api[PyDec_GetConst_INDEX] = (void *)PyDec_GetConst; + + return PyCapsule_New(_decimal_api, "_decimal._API", NULL); +} + + +/****************************************************************************/ +/* Module */ +/****************************************************************************/ + static PyMethodDef _decimal_methods [] = { { "getcontext", (PyCFunction)PyDec_GetCurrentContext, METH_NOARGS, doc_getcontext}, @@ -5665,17 +5821,27 @@ PyInit__decimal(void) DecCondMap *cm; struct ssize_constmap *ssize_cm; struct int_constmap *int_cm; + static PyObject *capsule = NULL; + static int initialized = 0; int i; /* Init libmpdec */ - mpd_traphandler = dec_traphandler; - mpd_mallocfunc = PyMem_Malloc; - mpd_reallocfunc = PyMem_Realloc; - mpd_callocfunc = mpd_callocfunc_em; - mpd_free = PyMem_Free; - mpd_setminalloc(_Py_DEC_MINALLOC); + if (!initialized) { + mpd_traphandler = dec_traphandler; + mpd_mallocfunc = PyMem_Malloc; + mpd_reallocfunc = PyMem_Realloc; + mpd_callocfunc = mpd_callocfunc_em; + mpd_free = PyMem_Free; + mpd_setminalloc(_Py_DEC_MINALLOC); + + capsule = init_api(); + if (capsule == NULL) { + return NULL; + } + initialized = 1; + } /* Init external C-API functions */ _py_long_multiply = PyLong_Type.tp_as_number->nb_multiply; @@ -5900,6 +6066,11 @@ PyInit__decimal(void) CHECK_INT(PyModule_AddStringConstant(m, "__version__", "1.70")); CHECK_INT(PyModule_AddStringConstant(m, "__libmpdec_version__", mpd_version())); + /* Add capsule API */ + Py_INCREF(capsule); + if (PyModule_AddObject(m, "_API", capsule) < 0) { + goto error; + } return m; |