summaryrefslogtreecommitdiff
path: root/Modules/_decimal/_decimal.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_decimal/_decimal.c')
-rw-r--r--Modules/_decimal/_decimal.c185
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;