blob: 94cc4a7b845791379f469bef8545e441eac6a237 [file] [log] [blame]
Stefan Krah39042e02020-08-10 16:32:21 +02001.. sectionauthor:: Stefan Krah
2
3.. highlight:: c
4
5
6Decimal capsule API
7===================
8
9Capsule API functions can be used in the same manner as regular library
10functions, provided that the API has been initialized.
11
12
13Initialize
14----------
15
16Typically, a C extension module that uses the decimal API will do these
17steps in its init function:
18
Anthony Sottiled5752aa2020-10-11 11:26:50 -070019.. code-block:: c
Stefan Krah39042e02020-08-10 16:32:21 +020020
21 #include "pydecimal.h"
22
23 static int decimal_initialized = 0;
24 if (!decimal_initialized) {
25 if (import_decimal() < 0) {
26 return NULL;
27 }
28
29 decimal_initialized = 1;
30 }
31
32
33Type checking, predicates, accessors
34------------------------------------
35
36.. c:function:: int PyDec_TypeCheck(const PyObject *dec)
37
38 Return 1 if ``dec`` is a Decimal, 0 otherwise. This function does not set
39 any exceptions.
40
41
42.. c:function:: int PyDec_IsSpecial(const PyObject *dec)
43
44 Return 1 if ``dec`` is ``NaN``, ``sNaN`` or ``Infinity``, 0 otherwise.
45
46 Set TypeError and return -1 if ``dec`` is not a Decimal. It is guaranteed that
47 this is the only failure mode, so if ``dec`` has already been type-checked, no
48 errors can occur and the function can be treated as a simple predicate.
49
50
51.. c:function:: int PyDec_IsNaN(const PyObject *dec)
52
53 Return 1 if ``dec`` is ``NaN`` or ``sNaN``, 0 otherwise.
54
55 Set TypeError and return -1 if ``dec`` is not a Decimal. It is guaranteed that
56 this is the only failure mode, so if ``dec`` has already been type-checked, no
57 errors can occur and the function can be treated as a simple predicate.
58
59
60.. c:function:: int PyDec_IsInfinite(const PyObject *dec)
61
62 Return 1 if ``dec`` is ``Infinity``, 0 otherwise.
63
64 Set TypeError and return -1 if ``dec`` is not a Decimal. It is guaranteed that
65 this is the only failure mode, so if ``dec`` has already been type-checked, no
66 errors can occur and the function can be treated as a simple predicate.
67
68
69.. c:function:: int64_t PyDec_GetDigits(const PyObject *dec)
70
71 Return the number of digits in the coefficient. For ``Infinity``, the
72 number of digits is always zero. Typically, the same applies to ``NaN``
73 and ``sNaN``, but both of these can have a payload that is equivalent to
74 a coefficient. Therefore, ``NaNs`` can have a nonzero return value.
75
76 Set TypeError and return -1 if ``dec`` is not a Decimal. It is guaranteed that
77 this is the only failure mode, so if ``dec`` has already been type-checked, no
78 errors can occur and the function can be treated as a simple accessor.
79
80
81Exact conversions between decimals and primitive C types
82--------------------------------------------------------
83
84This API supports conversions for decimals with a coefficient up to 38 digits.
85
86Data structures
87~~~~~~~~~~~~~~~
88
89The conversion functions use the following status codes and data structures:
90
Anthony Sottiled5752aa2020-10-11 11:26:50 -070091.. code-block:: c
Stefan Krah39042e02020-08-10 16:32:21 +020092
93 /* status cases for getting a triple */
94 enum mpd_triple_class {
95 MPD_TRIPLE_NORMAL,
96 MPD_TRIPLE_INF,
97 MPD_TRIPLE_QNAN,
98 MPD_TRIPLE_SNAN,
99 MPD_TRIPLE_ERROR,
100 };
101
102 typedef struct {
103 enum mpd_triple_class tag;
104 uint8_t sign;
105 uint64_t hi;
106 uint64_t lo;
107 int64_t exp;
108 } mpd_uint128_triple_t;
109
110The status cases are explained below. ``sign`` is 0 for positive and 1 for negative.
111``((uint128_t)hi << 64) + lo`` is the coefficient, ``exp`` is the exponent.
112
113The data structure is called "triple" because the decimal triple (sign, coeff, exp)
114is an established term and (``hi``, ``lo``) represents a single ``uint128_t`` coefficient.
115
116
117Functions
118~~~~~~~~~
119
120.. c:function:: mpd_uint128_triple_t PyDec_AsUint128Triple(const PyObject *dec)
121
122 Convert a decimal to a triple. As above, it is guaranteed that the only
123 Python failure mode is a TypeError, checks can be omitted if the type is
124 known.
125
126 For simplicity, the usage of the function and all special cases are
127 explained in code form and comments:
128
Anthony Sottiled5752aa2020-10-11 11:26:50 -0700129.. code-block:: c
Stefan Krah39042e02020-08-10 16:32:21 +0200130
131 triple = PyDec_AsUint128Triple(dec);
132 switch (triple.tag) {
133 case MPD_TRIPLE_QNAN:
134 /*
135 * Success: handle a quiet NaN.
136 * 1) triple.sign is 0 or 1.
137 * 2) triple.exp is always 0.
138 * 3) If triple.hi or triple.lo are nonzero, the NaN has a payload.
139 */
140 break;
141
142 case MPD_TRIPLE_SNAN:
143 /*
144 * Success: handle a signaling NaN.
145 * 1) triple.sign is 0 or 1.
146 * 2) triple.exp is always 0.
147 * 3) If triple.hi or triple.lo are nonzero, the sNaN has a payload.
148 */
149 break;
150
151 case MPD_TRIPLE_INF:
152 /*
153 * Success: handle Infinity.
154 * 1) triple.sign is 0 or 1.
155 * 2) triple.exp is always 0.
156 * 3) triple.hi and triple.lo are always zero.
157 */
158 break;
159
160 case MPD_TRIPLE_NORMAL:
161 /* Success: handle a finite value. */
162 break;
163
164 case MPD_TRIPLE_ERROR:
165 /* TypeError check: can be omitted if the type of dec is known. */
166 if (PyErr_Occurred()) {
167 return NULL;
168 }
169
170 /* Too large for conversion. PyDec_AsUint128Triple() does not set an
171 exception so applications can choose themselves. Typically this
172 would be a ValueError. */
173 PyErr_SetString(PyExc_ValueError,
174 "value out of bounds for a uint128 triple");
175 return NULL;
176 }
177
178.. c:function:: PyObject *PyDec_FromUint128Triple(const mpd_uint128_triple_t *triple)
179
180 Create a decimal from a triple. The following rules must be observed for
181 initializing the triple:
182
183 1) ``triple.sign`` must always be 0 (for positive) or 1 (for negative).
184
185 2) ``MPD_TRIPLE_QNAN``: ``triple.exp`` must be 0. If ``triple.hi`` or ``triple.lo``
186 are nonzero, create a ``NaN`` with a payload.
187
188 3) ``MPD_TRIPLE_SNAN``: ``triple.exp`` must be 0. If ``triple.hi`` or ``triple.lo``
189 are nonzero, create an ``sNaN`` with a payload.
190
191 4) ``MPD_TRIPLE_INF``: ``triple.exp``, ``triple.hi`` and ``triple.lo`` must be zero.
192
193 5) ``MPD_TRIPLE_NORMAL``: ``MPD_MIN_ETINY + 38 < triple.exp < MPD_MAX_EMAX - 38``.
194 ``triple.hi`` and ``triple.lo`` can be chosen freely.
195
196 6) ``MPD_TRIPLE_ERROR``: It is always an error to set this tag.
197
198
199 If one of the above conditions is not met, the function returns ``NaN`` if
200 the ``InvalidOperation`` trap is not set in the thread local context. Otherwise,
201 it sets the ``InvalidOperation`` exception and returns NULL.
202
203 Additionally, though extremely unlikely give the small allocation sizes,
204 the function can set ``MemoryError`` and return ``NULL``.
205
206
207Advanced API
208------------
209
210This API enables the use of ``libmpdec`` functions. Since Python is compiled with
211hidden symbols, the API requires an external libmpdec and the ``mpdecimal.h``
212header.
213
214
215Functions
216~~~~~~~~~
217
218.. c:function:: PyObject *PyDec_Alloc(void)
219
220 Return a new decimal that can be used in the ``result`` position of ``libmpdec``
221 functions.
222
223.. c:function:: mpd_t *PyDec_Get(PyObject *v)
224
225 Get a pointer to the internal ``mpd_t`` of the decimal. Decimals are immutable,
226 so this function must only be used on a new Decimal that has been created by
227 PyDec_Alloc().
228
229.. c:function:: const mpd_t *PyDec_GetConst(const PyObject *v)
230
231 Get a pointer to the constant internal ``mpd_t`` of the decimal.