bpo-41324 Add a minimal decimal capsule API (#21519)

This commit is contained in:
Stefan Krah 2020-08-10 16:32:21 +02:00 committed by GitHub
parent 416f0b71ba
commit 39042e00ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 1096 additions and 7 deletions

View file

@ -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;