PageRenderTime 114ms CodeModel.GetById 25ms app.highlight 75ms RepoModel.GetById 1ms app.codeStats 1ms

/src/gmpy_context.c

http://gmpy.googlecode.com/
C | 1210 lines | 1056 code | 105 blank | 49 comment | 192 complexity | b6d49f7521d13f2626efc8d864dc6753 MD5 | raw file
   1/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
   2 * gmpy_context.c                                                          *
   3 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
   4 * Python interface to the GMP or MPIR, MPFR, and MPC multiple precision   *
   5 * libraries.                                                              *
   6 *                                                                         *
   7 * Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,               *
   8 *           2008, 2009 Alex Martelli                                      *
   9 *                                                                         *
  10 * Copyright 2008, 2009, 2010, 2011, 2012, 2013 Case Van Horsen            *
  11 *                                                                         *
  12 * This file is part of GMPY2.                                             *
  13 *                                                                         *
  14 * GMPY2 is free software: you can redistribute it and/or modify it under  *
  15 * the terms of the GNU Lesser General Public License as published by the  *
  16 * Free Software Foundation, either version 3 of the License, or (at your  *
  17 * option) any later version.                                              *
  18 *                                                                         *
  19 * GMPY2 is distributed in the hope that it will be useful, but WITHOUT    *
  20 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or   *
  21 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public    *
  22 * License for more details.                                               *
  23 *                                                                         *
  24 * You should have received a copy of the GNU Lesser General Public        *
  25 * License along with GMPY2; if not, see <http://www.gnu.org/licenses/>    *
  26 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  27
  28/* A GMPyContextObject contains an instance of the C struct gmpy_context
  29 * and a PyObject* used to reference the enclosing instance when used as a
  30 * context manager in Python.
  31 *
  32 * gmpy2 uses a global pointer "context" to refer to the active
  33 * GMPyContextObject.
  34 *
  35 * WARNING: The context manager is not thread-safe. This may be fixed in a
  36 *          future version.
  37 */
  38
  39/* Create and delete Context objects. */
  40
  41static PyObject *
  42GMPyContext_new(void)
  43{
  44    GMPyContextObject *result;
  45
  46    if ((result = PyObject_New(GMPyContextObject, &GMPyContext_Type))) {
  47        result->ctx.mpfr_prec = DBL_MANT_DIG;
  48        result->ctx.mpfr_round = MPFR_RNDN;
  49        result->ctx.emax = MPFR_EMAX_DEFAULT;
  50        result->ctx.emin = MPFR_EMIN_DEFAULT;
  51        result->ctx.subnormalize = 0;
  52        result->ctx.underflow = 0;
  53        result->ctx.overflow = 0;
  54        result->ctx.inexact = 0;
  55        result->ctx.invalid = 0;
  56        result->ctx.erange = 0;
  57        result->ctx.divzero = 0;
  58        result->ctx.trap_underflow = 0;
  59        result->ctx.trap_overflow = 0;
  60        result->ctx.trap_inexact = 0;
  61        result->ctx.trap_invalid = 0;
  62        result->ctx.trap_erange = 0;
  63        result->ctx.trap_divzero = 0;
  64        result->ctx.trap_expbound = 0;
  65
  66#ifdef WITHMPC
  67        result->ctx.real_prec = -1;
  68        result->ctx.imag_prec = -1;
  69        result->ctx.real_round = -1;
  70        result->ctx.imag_round = -1;
  71        result->ctx.allow_complex = 0;
  72#endif
  73    }
  74    return (PyObject*)result;
  75};
  76
  77static void
  78GMPyContext_dealloc(GMPyContextObject *self)
  79{
  80    PyObject_Del(self);
  81};
  82
  83PyDoc_STRVAR(doc_context_ieee,
  84"ieee(bitwidth) -> context\n\n"
  85"Return a new context corresponding to a standard IEEE floating point\n"
  86"format. The currently supported precisions are 32, 64, and 128 bits.");
  87
  88static PyObject *
  89GMPyContext_ieee(PyObject *self, PyObject *other)
  90{
  91    long bitwidth;
  92    GMPyContextObject *result;
  93
  94    bitwidth = PyIntOrLong_AsLong(other);
  95    if (bitwidth == -1 && PyErr_Occurred()) {
  96        TYPE_ERROR("ieee() requires 'int' argument");
  97        return NULL;
  98    }
  99
 100    if (bitwidth == 32) {
 101        result = (GMPyContextObject*)GMPyContext_new();
 102        if (result) {
 103            result->ctx.subnormalize = 1;
 104            result->ctx.mpfr_prec = 24;
 105            result->ctx.emax = 128;
 106            result->ctx.emin = -148;
 107        }
 108        return (PyObject*)result;
 109    }
 110    else if (bitwidth == 64) {
 111        result = (GMPyContextObject*)GMPyContext_new();
 112        if (result) {
 113            result->ctx.subnormalize = 1;
 114            result->ctx.mpfr_prec = 53;
 115            result->ctx.emax = 1024;
 116            result->ctx.emin = -1073;
 117        }
 118        return (PyObject*)result;
 119    }
 120    else if (bitwidth == 128) {
 121        result = (GMPyContextObject*)GMPyContext_new();
 122        if (result) {
 123            result->ctx.subnormalize = 1;
 124            result->ctx.mpfr_prec = 113;
 125            result->ctx.emax = 16384;
 126            result->ctx.emin = -16493;
 127        }
 128        return (PyObject*)result;
 129    }
 130    else {
 131        VALUE_ERROR("bitwidth must be 32, 64, or 128");
 132        return NULL;
 133    }
 134}
 135
 136/* Create and delete ContextManager objects. */
 137
 138static PyObject *
 139GMPyContextManager_new(void)
 140{
 141    return (PyObject*)PyObject_New(GMPyContextManagerObject,
 142                                   &GMPyContextManager_Type);
 143};
 144
 145static void
 146GMPyContextManager_dealloc(GMPyContextManagerObject *self)
 147{
 148    PyObject_Del(self);
 149};
 150
 151/* Helper function to convert to convert a rounding mode to a string. */
 152
 153static PyObject *
 154_round_to_name(int val)
 155{
 156    if (val == MPFR_RNDN) return Py2or3String_FromString("RoundToNearest");
 157    if (val == MPFR_RNDZ) return Py2or3String_FromString("RoundToZero");
 158    if (val == MPFR_RNDU) return Py2or3String_FromString("RoundUp");
 159    if (val == MPFR_RNDD) return Py2or3String_FromString("RoundDown");
 160    if (val == MPFR_RNDA) return Py2or3String_FromString("RoundAwayZero");
 161    if (val == GMPY_DEFAULT) return Py2or3String_FromString("Default");
 162    return NULL;
 163};
 164
 165static PyObject *
 166GMPyContext_repr(GMPyContextObject *self)
 167{
 168    PyObject *format;
 169    PyObject *tuple;
 170    PyObject *result = NULL;
 171    int i = 0;
 172
 173#ifdef WITHMPC
 174    tuple = PyTuple_New(23);
 175#else
 176    tuple = PyTuple_New(18);
 177#endif
 178    if (!tuple) return NULL;
 179
 180#ifdef WITHMPC
 181    format = Py2or3String_FromString(
 182            "context(precision=%s, real_prec=%s, imag_prec=%s,\n"
 183            "        round=%s, real_round=%s, imag_round=%s,\n"
 184            "        emax=%s, emin=%s,\n"
 185            "        subnormalize=%s,\n"
 186            "        trap_underflow=%s, underflow=%s,\n"
 187            "        trap_overflow=%s, overflow=%s,\n"
 188            "        trap_inexact=%s, inexact=%s,\n"
 189            "        trap_invalid=%s, invalid=%s,\n"
 190            "        trap_erange=%s, erange=%s,\n"
 191            "        trap_divzero=%s, divzero=%s,\n"
 192            "        trap_expbound=%s,\n"
 193            "        allow_complex=%s)"
 194            );
 195#else
 196    format = Py2or3String_FromString(
 197            "context(precision=%s,\n"
 198            "        round=%s,\n"
 199            "        emax=%s, emin=%s,\n"
 200            "        subnormalize=%s,\n"
 201            "        trap_underflow=%s, underflow=%s,\n"
 202            "        trap_overflow=%s, overflow=%s,\n"
 203            "        trap_inexact=%s, inexact=%s,\n"
 204            "        trap_invalid=%s, invalid=%s,\n"
 205            "        trap_erange=%s, erange=%s,\n"
 206            "        trap_divzero=%s, divzero=%s,\n"
 207            "        trap_expbound=%s)"
 208            );
 209#endif
 210    if (!format) {
 211        Py_DECREF(tuple);
 212        return NULL;
 213    }
 214
 215    PyTuple_SET_ITEM(tuple, i++, PyIntOrLong_FromLong(self->ctx.mpfr_prec));
 216#ifdef WITHMPC
 217    if (self->ctx.real_prec == GMPY_DEFAULT)
 218        PyTuple_SET_ITEM(tuple, i++, Py2or3String_FromString("Default"));
 219    else
 220        PyTuple_SET_ITEM(tuple, i++, PyIntOrLong_FromLong(self->ctx.real_prec));
 221    if (self->ctx.imag_prec == GMPY_DEFAULT)
 222        PyTuple_SET_ITEM(tuple, i++, Py2or3String_FromString("Default"));
 223    else
 224        PyTuple_SET_ITEM(tuple, i++, PyIntOrLong_FromLong(self->ctx.imag_prec));
 225#endif
 226    PyTuple_SET_ITEM(tuple, i++, _round_to_name(self->ctx.mpfr_round));
 227#ifdef WITHMPC
 228    PyTuple_SET_ITEM(tuple, i++, _round_to_name(self->ctx.real_round));
 229    PyTuple_SET_ITEM(tuple, i++, _round_to_name(self->ctx.imag_round));
 230#endif
 231    PyTuple_SET_ITEM(tuple, i++, PyIntOrLong_FromLong(self->ctx.emax));
 232    PyTuple_SET_ITEM(tuple, i++, PyIntOrLong_FromLong(self->ctx.emin));
 233    PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.subnormalize));
 234    PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.trap_underflow));
 235    PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.underflow));
 236    PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.trap_overflow));
 237    PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.overflow));
 238    PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.trap_inexact));
 239    PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.inexact));
 240    PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.trap_invalid));
 241    PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.invalid));
 242    PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.trap_erange));
 243    PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.erange));
 244    PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.trap_divzero));
 245    PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.divzero));
 246    PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.trap_expbound));
 247#ifdef WITHMPC
 248    PyTuple_SET_ITEM(tuple, i++, PyBool_FromLong(self->ctx.allow_complex));
 249#endif
 250
 251    if (!PyErr_Occurred())
 252        result = Py2or3String_Format(format, tuple);
 253    else
 254        SYSTEM_ERROR("internal error in GMPyContext_repr");
 255
 256    Py_DECREF(format);
 257    Py_DECREF(tuple);
 258    return result;
 259};
 260
 261static PyObject *
 262GMPyContextManager_repr(GMPyContextManagerObject *self)
 263{
 264    return Py_BuildValue("s", "<gmpy2.ContextManagerObject>");
 265}
 266
 267PyDoc_STRVAR(doc_get_context,
 268"get_context() -> gmpy2 context\n\n"
 269"Return a reference to the current context.");
 270
 271static PyObject *
 272GMPyContext_get_context(PyObject *self, PyObject *args)
 273{
 274    Py_INCREF((PyObject*)context);
 275    return (PyObject*)context;
 276}
 277
 278PyDoc_STRVAR(doc_context_copy,
 279"context.copy() -> gmpy2 context\n\n"
 280"Return a copy of a context.");
 281
 282static PyObject *
 283GMPyContext_context_copy(PyObject *self, PyObject *other)
 284{
 285    GMPyContextObject *result;
 286
 287    result = (GMPyContextObject*)GMPyContext_new();
 288    result->ctx = ((GMPyContextObject*)self)->ctx;
 289    return (PyObject*)result;
 290}
 291
 292PyDoc_STRVAR(doc_local_context,
 293"local_context([context[,keywords]]) -> context manager\n\n"
 294"Create a context manager object that will restore the current context\n"
 295"when the 'with ...' block terminates. The temporary context for the\n"
 296"'with ...' block is based on the current context if no context is\n"
 297"specified. Keyword arguments are supported and will modify the\n"
 298"temporary new context.");
 299
 300static PyObject *
 301GMPyContext_local_context(PyObject *self, PyObject *args, PyObject *kwargs)
 302{
 303    GMPyContextManagerObject *result;
 304    PyObject *local_args = args;
 305    int arg_context = 0;
 306
 307#ifdef WITHMPC
 308    static char *kwlist[] = {
 309        "precision", "real_prec", "imag_prec", "round",
 310        "real_round", "imag_round", "emax", "emin", "subnormalize",
 311        "trap_underflow", "trap_overflow", "trap_inexact",
 312        "trap_invalid", "trap_erange", "trap_divzero",
 313        "trap_expbound", "allow_complex", NULL };
 314#else
 315    static char *kwlist[] = {
 316        "precision", "round", "emax", "emin", "subnormalize",
 317        "trap_underflow", "trap_overflow", "trap_inexact",
 318        "trap_invalid", "trap_erange", "trap_divzero", "trap_expbound",
 319        NULL };
 320#endif
 321
 322    if (PyTuple_GET_SIZE(args) == 1 && GMPyContext_Check(PyTuple_GET_ITEM(args, 0))) {
 323        arg_context = 1;
 324        if (!(local_args = PyTuple_New(0)))
 325            return NULL;
 326    }
 327    else if (PyTuple_GET_SIZE(args)) {
 328        VALUE_ERROR("local_context() only supports [context[,keyword]] arguments");
 329        return NULL;
 330    }
 331
 332    if (!(result = (GMPyContextManagerObject*)GMPyContextManager_new()))
 333        return NULL;
 334
 335    if (arg_context) {
 336        result->new_ctx = ((GMPyContextObject*)PyTuple_GET_ITEM(args, 0))->ctx;
 337    }
 338    else {
 339        result->new_ctx = context->ctx;
 340    }
 341    result->old_ctx = context->ctx;
 342
 343#ifdef WITHMPC
 344    if (!(PyArg_ParseTupleAndKeywords(local_args, kwargs,
 345            "|llliiilliiiiiiiii", kwlist,
 346            &result->new_ctx.mpfr_prec,
 347            &result->new_ctx.real_prec,
 348            &result->new_ctx.imag_prec,
 349            &result->new_ctx.mpfr_round,
 350            &result->new_ctx.real_round,
 351            &result->new_ctx.imag_round,
 352            &result->new_ctx.emax,
 353            &result->new_ctx.emin,
 354            &result->new_ctx.subnormalize,
 355            &result->new_ctx.trap_underflow,
 356            &result->new_ctx.trap_overflow,
 357            &result->new_ctx.trap_inexact,
 358            &result->new_ctx.trap_invalid,
 359            &result->new_ctx.trap_erange,
 360            &result->new_ctx.trap_divzero,
 361            &result->new_ctx.trap_expbound,
 362            &result->new_ctx.allow_complex))) {
 363#else
 364    if (!(PyArg_ParseTupleAndKeywords(local_args, kwargs,
 365            "|lilliiiiiiii", kwlist,
 366            &result->new_ctx.mpfr_prec,
 367            &result->new_ctx.mpfr_round,
 368            &result->new_ctx.emax,
 369            &result->new_ctx.emin,
 370            &result->new_ctx.subnormalize,
 371            &result->new_ctx.trap_underflow,
 372            &result->new_ctx.trap_overflow,
 373            &result->new_ctx.trap_inexact,
 374            &result->new_ctx.trap_invalid,
 375            &result->new_ctx.trap_erange,
 376            &result->new_ctx.trap_divzero,
 377            &result->new_ctx.trap_expbound))) {
 378#endif
 379        VALUE_ERROR("invalid keyword arguments in local_context()");
 380        goto error;
 381    }
 382
 383    /* Sanity check for values. */
 384    if (result->new_ctx.mpfr_prec < MPFR_PREC_MIN ||
 385        result->new_ctx.mpfr_prec > MPFR_PREC_MAX) {
 386        VALUE_ERROR("invalid value for precision");
 387        goto error;
 388    }
 389
 390#ifdef WITHMPC
 391    if (!(result->new_ctx.real_prec == GMPY_DEFAULT ||
 392        (result->new_ctx.real_prec >= MPFR_PREC_MIN &&
 393        result->new_ctx.real_prec <= MPFR_PREC_MAX))) {
 394        VALUE_ERROR("invalid value for real_prec");
 395        goto error;
 396    }
 397    if (!(result->new_ctx.imag_prec == GMPY_DEFAULT ||
 398        (result->new_ctx.imag_prec >= MPFR_PREC_MIN &&
 399        result->new_ctx.imag_prec <= MPFR_PREC_MAX))) {
 400        VALUE_ERROR("invalid value for imag_prec");
 401        goto error;
 402    }
 403#endif
 404
 405    if (!(result->new_ctx.mpfr_round == MPFR_RNDN ||
 406        result->new_ctx.mpfr_round == MPFR_RNDZ ||
 407        result->new_ctx.mpfr_round == MPFR_RNDU ||
 408        result->new_ctx.mpfr_round == MPFR_RNDD ||
 409        result->new_ctx.mpfr_round == MPFR_RNDA)) {
 410        VALUE_ERROR("invalid value for round");
 411        goto error;
 412    }
 413
 414#ifdef WITHMPC
 415    if (result->new_ctx.mpfr_round == MPFR_RNDA) {
 416        /* Since RNDA is not supported for MPC, set the MPC rounding modes
 417         * to MPFR_RNDN.
 418         */
 419        result->new_ctx.real_round = MPFR_RNDN;
 420        result->new_ctx.imag_round = MPFR_RNDN;
 421    }
 422    if (!(result->new_ctx.real_round == MPFR_RNDN ||
 423        result->new_ctx.real_round == MPFR_RNDZ ||
 424        result->new_ctx.real_round == MPFR_RNDU ||
 425        result->new_ctx.real_round == MPFR_RNDD ||
 426        result->new_ctx.real_round == GMPY_DEFAULT)) {
 427        VALUE_ERROR("invalid value for real_round");
 428        goto error;
 429    }
 430    if (!(result->new_ctx.imag_round == MPFR_RNDN ||
 431        result->new_ctx.imag_round == MPFR_RNDZ ||
 432        result->new_ctx.imag_round == MPFR_RNDU ||
 433        result->new_ctx.imag_round == MPFR_RNDD ||
 434        result->new_ctx.imag_round == GMPY_DEFAULT)) {
 435        VALUE_ERROR("invalid value for imag_round");
 436        goto error;
 437    }
 438#endif
 439
 440    if (!(result->new_ctx.emin < 0 && result->new_ctx.emax > 0)) {
 441        VALUE_ERROR("invalid values for emin and/or emax");
 442        goto error;
 443    }
 444
 445    if (mpfr_set_emin(result->new_ctx.emin)) {
 446        VALUE_ERROR("invalid value for emin");
 447        goto error;
 448    }
 449    if (mpfr_set_emax(result->new_ctx.emax)) {
 450        VALUE_ERROR("invalid value for emax");
 451        goto error;
 452    }
 453
 454    if (arg_context) {
 455        Py_DECREF(local_args);
 456    }
 457    return (PyObject*)result;
 458
 459  error:
 460    if (arg_context) {
 461        Py_DECREF(local_args);
 462    }
 463    Py_DECREF((PyObject*)result);
 464    return NULL;
 465}
 466
 467#ifdef WITHMPC
 468
 469PyDoc_STRVAR(doc_context,
 470"context() -> context manager\n\n"
 471"Return a new context for controlling MPFR and MPC arithmetic. To load\n"
 472"the new context, use set_context(). Options can only be specified as\n"
 473"keyword arguments. \n\n"
 474"    precision:      precision, in bits, of an MPFR result\n"
 475"    real_prec:      precision, in bits, of Re(MPC)\n"
 476"                      -1 implies use mpfr_prec\n"
 477"    imag_prec:      precision, in bits, of Im(MPC)\n"
 478"                      -1 implies use real_prec\n"
 479"    round:          rounding mode for MPFR\n"
 480"    real_round:     rounding mode for Re(MPC)\n"
 481"                      -1 implies use mpfr_round\n"
 482"    imag_round:     rounding mode for Im(MPC)\n"
 483"                      -1 implies use real_round\n"
 484"    e_max:          maximum allowed exponent\n"
 485"    e_min:          minimum allowed exponent\n"
 486"    subnormalize:   if True, subnormalized results can be returned\n"
 487"    trap_underflow: if True, raise exception for underflow\n"
 488"                    if False, set underflow flag\n"
 489"    trap_overflow:  if True, raise exception for overflow\n"
 490"                    if False, set overflow flag and return Inf or -Inf\n"
 491"    trap_inexact:   if True, raise exception for inexact result\n"
 492"                    if False, set inexact flag\n"
 493"    trap_invalid:   if True, raise exception for invalid operation\n"
 494"                    if False, set invalid flag and return NaN\n"
 495"    trap_erange:    if True, raise exception for range error\n"
 496"                    if False, set erange flag\n"
 497"    trap_divzero:   if True, raise exception for division by zero\n"
 498"                    if False, set divzero flag and return Inf or -Inf\n"
 499"    trap_expbound:  if True, raise exception when mpfr/mpc exponent\n"
 500"                        no longer valid in current context\n"
 501"                    if False, mpfr/mpc with exponent out-of-bounds\n"
 502"                        will be coerced to either 0 or Infinity\n"
 503"    allow_complex:  if True, allow mpfr functions to return mpc\n"
 504"                    if False, mpfr functions cannot return an mpc\n");
 505
 506#else
 507
 508PyDoc_STRVAR(doc_context,
 509"context() -> context\n\n"
 510"Return a new context for controlling MPFR arithmetic. To load the\n"
 511"new context, use set_context(). Options can only be specified as\n"
 512"keyword arguments. \n\n"
 513"    precision:      precision, in bits, of an MPFR result\n"
 514"    round:          rounding mode for MPFR\n"
 515"    e_max:          maximum allowed exponent\n"
 516"    e_min:          minimum allowed exponent\n"
 517"    subnormalize:   if True, subnormalized results can be returned\n"
 518"    trap_underflow: if True, raise exception for underflow\n"
 519"                    if False, set underflow flag\n"
 520"    trap_overflow:  if True, raise exception for overflow\n"
 521"                    if False, set overflow flag and return Inf or -Inf\n"
 522"    trap_inexact:   if True, raise exception for inexact result\n"
 523"                    if False, set inexact flag\n"
 524"    trap_invalid:   if True, raise exception for invalid operation\n"
 525"                    if False, set invalid flag and return NaN\n"
 526"    trap_erange:    if True, raise exception for range error\n"
 527"                    if False, set erange flag\n"
 528"    trap_divzero:   if True, raise exception for division by zero\n"
 529"                    if False, set divzero flag and return Inf or -Inf\n"
 530"    trap_expbound:  if True, raise exception when mpfr/mpc exponent\n"
 531"                        no longer valid in current context\n"
 532"                    if False, mpfr/mpc with exponent out-of-bounds will\n"
 533"                        coerced to either 0 or Infinity\n");
 534
 535#endif
 536
 537static PyObject *
 538GMPyContext_context(PyObject *self, PyObject *args, PyObject *kwargs)
 539{
 540    GMPyContextObject *result;
 541
 542#ifdef WITHMPC
 543    static char *kwlist[] = {
 544        "precision", "real_prec", "imag_prec", "round",
 545        "real_round", "imag_round", "emax", "emin", "subnormalize",
 546        "trap_underflow", "trap_overflow", "trap_inexact",
 547        "trap_invalid", "trap_erange", "trap_divzero", "trap_expbound",
 548        "allow_complex", NULL };
 549#else
 550    static char *kwlist[] = {
 551        "precision", "round", "emax", "emin", "subnormalize",
 552        "trap_underflow", "trap_overflow", "trap_inexact",
 553        "trap_invalid", "trap_erange", "trap_divzero",
 554        "trap_expbound", NULL };
 555#endif
 556
 557    if (PyTuple_GET_SIZE(args)) {
 558        VALUE_ERROR("context() only supports keyword arguments");
 559        return NULL;
 560    }
 561
 562    if (!(result = (GMPyContextObject*)GMPyContext_new()))
 563        return NULL;
 564
 565#ifdef WITHMPC
 566    if (!(PyArg_ParseTupleAndKeywords(args, kwargs,
 567            "|llliiilliiiiiiiii", kwlist,
 568            &result->ctx.mpfr_prec,
 569            &result->ctx.real_prec,
 570            &result->ctx.imag_prec,
 571            &result->ctx.mpfr_round,
 572            &result->ctx.real_round,
 573            &result->ctx.imag_round,
 574            &result->ctx.emax,
 575            &result->ctx.emin,
 576            &result->ctx.subnormalize,
 577            &result->ctx.trap_underflow,
 578            &result->ctx.trap_overflow,
 579            &result->ctx.trap_inexact,
 580            &result->ctx.trap_invalid,
 581            &result->ctx.trap_erange,
 582            &result->ctx.trap_divzero,
 583            &result->ctx.trap_expbound,
 584            &result->ctx.allow_complex))) {
 585#else
 586    if (!(PyArg_ParseTupleAndKeywords(args, kwargs,
 587            "|lilliiiiiiii", kwlist,
 588            &result->ctx.mpfr_prec,
 589            &result->ctx.mpfr_round,
 590            &result->ctx.emax,
 591            &result->ctx.emin,
 592            &result->ctx.subnormalize,
 593            &result->ctx.trap_underflow,
 594            &result->ctx.trap_overflow,
 595            &result->ctx.trap_inexact,
 596            &result->ctx.trap_invalid,
 597            &result->ctx.trap_erange,
 598            &result->ctx.trap_divzero,
 599            &result->ctx.trap_expbound))) {
 600#endif
 601        VALUE_ERROR("invalid keyword arguments in context()");
 602        return NULL;
 603    }
 604
 605    /* Sanity check for values. */
 606    if (result->ctx.mpfr_prec < MPFR_PREC_MIN ||
 607        result->ctx.mpfr_prec > MPFR_PREC_MAX) {
 608        Py_DECREF((PyObject*)result);
 609        VALUE_ERROR("invalid value for precision");
 610        return NULL;
 611    }
 612
 613#ifdef WITHMPC
 614    if (!(result->ctx.real_prec == GMPY_DEFAULT ||
 615        (result->ctx.real_prec >= MPFR_PREC_MIN &&
 616        result->ctx.real_prec <= MPFR_PREC_MAX))) {
 617        Py_DECREF((PyObject*)result);
 618        VALUE_ERROR("invalid value for real_prec");
 619        return NULL;
 620    }
 621    if (!(result->ctx.imag_prec == GMPY_DEFAULT ||
 622        (result->ctx.imag_prec >= MPFR_PREC_MIN &&
 623        result->ctx.imag_prec <= MPFR_PREC_MAX))) {
 624        Py_DECREF((PyObject*)result);
 625        VALUE_ERROR("invalid value for imag_prec");
 626        return NULL;
 627    }
 628#endif
 629
 630    if (!(result->ctx.mpfr_round == MPFR_RNDN ||
 631        result->ctx.mpfr_round == MPFR_RNDZ ||
 632        result->ctx.mpfr_round == MPFR_RNDU ||
 633        result->ctx.mpfr_round == MPFR_RNDD ||
 634        result->ctx.mpfr_round == MPFR_RNDA)) {
 635        Py_DECREF((PyObject*)result);
 636        VALUE_ERROR("invalid value for round");
 637        return NULL;
 638    }
 639
 640#ifdef WITHMPC
 641    if (result->ctx.mpfr_round == MPFR_RNDA) {
 642        /* Since RNDA is not supported for MPC, set the MPC rounding modes
 643           to MPFR_RNDN. */
 644        result->ctx.real_round = MPFR_RNDN;
 645        result->ctx.imag_round = MPFR_RNDN;
 646    }
 647    if (!(result->ctx.real_round == MPFR_RNDN ||
 648        result->ctx.real_round == MPFR_RNDZ ||
 649        result->ctx.real_round == MPFR_RNDU ||
 650        result->ctx.real_round == MPFR_RNDD ||
 651        result->ctx.real_round == GMPY_DEFAULT)) {
 652        Py_DECREF((PyObject*)result);
 653        VALUE_ERROR("invalid value for real_round");
 654        return NULL;
 655    }
 656    if (!(result->ctx.imag_round == MPFR_RNDN ||
 657        result->ctx.imag_round == MPFR_RNDZ ||
 658        result->ctx.imag_round == MPFR_RNDU ||
 659        result->ctx.imag_round == MPFR_RNDD ||
 660        result->ctx.imag_round == GMPY_DEFAULT)) {
 661        Py_DECREF((PyObject*)result);
 662        VALUE_ERROR("invalid value for imag_round");
 663        return NULL;
 664    }
 665#endif
 666
 667    if (!(result->ctx.emin < 0 && result->ctx.emax > 0)) {
 668        VALUE_ERROR("invalid values for emin and/or emax");
 669        Py_DECREF((PyObject*)result);
 670        return NULL;
 671    }
 672
 673    if (mpfr_set_emin(result->ctx.emin)) {
 674        VALUE_ERROR("invalid value for emin");
 675        Py_DECREF((PyObject*)result);
 676        return NULL;
 677    }
 678    if (mpfr_set_emax(result->ctx.emax)) {
 679        VALUE_ERROR("invalid value for emax");
 680        Py_DECREF((PyObject*)result);
 681        return NULL;
 682    }
 683
 684    result->ctx.underflow = 0;
 685    result->ctx.overflow = 0;
 686    result->ctx.inexact = 0;
 687    result->ctx.invalid = 0;
 688    result->ctx.erange = 0;
 689    result->ctx.divzero = 0;
 690    return (PyObject*)result;
 691}
 692
 693PyDoc_STRVAR(doc_set_context,
 694"set_context(context)\n\n"
 695"Activate a context object controlling MPFR and MPC arithmetic.\n");
 696
 697static PyObject *
 698GMPyContext_set_context(PyObject *self, PyObject *other)
 699{
 700    if (GMPyContext_Check(other)) {
 701        Py_INCREF((PyObject*)other);
 702        Py_DECREF((PyObject*)context);
 703        context = (GMPyContextObject*)other;
 704        mpfr_set_emin(context->ctx.emin);
 705        mpfr_set_emax(context->ctx.emax);
 706        Py_RETURN_NONE;
 707    }
 708    else {
 709        VALUE_ERROR("set_context() requires a context argument");
 710        return NULL;
 711    }
 712}
 713
 714static PyObject *
 715GMPyContextManager_enter(PyObject *self, PyObject *args)
 716{
 717    GMPyContextObject *result;
 718
 719    if (!(result = (GMPyContextObject*)GMPyContext_new()))
 720        return NULL;
 721
 722    result->ctx = ((GMPyContextManagerObject*)self)->new_ctx;
 723    Py_DECREF((PyObject*)context);
 724    context = (GMPyContextObject*)result;
 725    Py_INCREF((PyObject*)context);
 726    mpfr_set_emin(context->ctx.emin);
 727    mpfr_set_emax(context->ctx.emax);
 728    return (PyObject*)result;
 729}
 730
 731static PyObject *
 732GMPyContextManager_exit(PyObject *self, PyObject *args)
 733{
 734    GMPyContextObject *result;
 735
 736    if (!(result = (GMPyContextObject*)GMPyContext_new()))
 737        return NULL;
 738
 739    result->ctx = ((GMPyContextManagerObject*)self)->old_ctx;
 740    Py_DECREF((PyObject*)context);
 741    context = (GMPyContextObject*)result;
 742    mpfr_set_emin(context->ctx.emin);
 743    mpfr_set_emax(context->ctx.emax);
 744    Py_RETURN_NONE;
 745}
 746
 747static PyObject *
 748GMPyContext_enter(PyObject *self, PyObject *args)
 749{
 750    GMPyContextObject *result;
 751
 752    if (!(result = (GMPyContextObject*)GMPyContext_new()))
 753        return NULL;
 754
 755    result->ctx = ((GMPyContextObject*)self)->ctx;
 756    Py_DECREF((PyObject*)context);
 757    context = (GMPyContextObject*)result;
 758    Py_INCREF((PyObject*)context);
 759    mpfr_set_emin(context->ctx.emin);
 760    mpfr_set_emax(context->ctx.emax);
 761    return (PyObject*)result;
 762}
 763
 764static PyObject *
 765GMPyContext_exit(PyObject *self, PyObject *args)
 766{
 767    Py_DECREF((PyObject*)context);
 768    context = (GMPyContextObject*)self;
 769    Py_INCREF((PyObject*)context);
 770    mpfr_set_emin(context->ctx.emin);
 771    mpfr_set_emax(context->ctx.emax);
 772    Py_RETURN_NONE;
 773}
 774
 775PyDoc_STRVAR(doc_context_clear_flags,
 776"clear_flags()\n\n"
 777"Clear all MPFR exception flags.");
 778static PyObject *
 779GMPyContext_clear_flags(PyObject *self, PyObject *args)
 780{
 781    ((GMPyContextObject*)self)->ctx.underflow = 0;
 782    ((GMPyContextObject*)self)->ctx.overflow = 0;
 783    ((GMPyContextObject*)self)->ctx.inexact = 0;
 784    ((GMPyContextObject*)self)->ctx.invalid = 0;
 785    ((GMPyContextObject*)self)->ctx.erange = 0;
 786    ((GMPyContextObject*)self)->ctx.divzero = 0;
 787    Py_RETURN_NONE;
 788}
 789
 790/* Define the get/set functions. */
 791
 792#define GETSET_BOOLEAN(NAME) \
 793static PyObject * \
 794GMPyContext_get_##NAME(GMPyContextObject *self, void *closure) \
 795{ \
 796    return PyBool_FromLong(self->ctx.NAME); \
 797}; \
 798static int \
 799GMPyContext_set_##NAME(GMPyContextObject *self, PyObject *value, void *closure) \
 800{ \
 801    if (!(PyBool_Check(value))) { \
 802        TYPE_ERROR(#NAME " must be True or False"); \
 803        return -1; \
 804    } \
 805    self->ctx.NAME = (value == Py_True) ? 1 : 0; \
 806    return 0; \
 807}
 808
 809GETSET_BOOLEAN(subnormalize);
 810GETSET_BOOLEAN(underflow);
 811GETSET_BOOLEAN(overflow);
 812GETSET_BOOLEAN(inexact);
 813GETSET_BOOLEAN(invalid);
 814GETSET_BOOLEAN(erange);
 815GETSET_BOOLEAN(divzero);
 816GETSET_BOOLEAN(trap_underflow);
 817GETSET_BOOLEAN(trap_overflow);
 818GETSET_BOOLEAN(trap_inexact);
 819GETSET_BOOLEAN(trap_invalid);
 820GETSET_BOOLEAN(trap_erange);
 821GETSET_BOOLEAN(trap_divzero);
 822GETSET_BOOLEAN(trap_expbound);
 823#ifdef WITHMPC
 824GETSET_BOOLEAN(allow_complex)
 825#endif
 826
 827static PyObject *
 828GMPyContext_get_precision(GMPyContextObject *self, void *closure)
 829{
 830    return PyIntOrLong_FromSsize_t((Py_ssize_t)(self->ctx.mpfr_prec));
 831}
 832
 833static int
 834GMPyContext_set_precision(GMPyContextObject *self, PyObject *value, void *closure)
 835{
 836    Py_ssize_t temp;
 837
 838    if (!(PyIntOrLong_Check(value))) {
 839        TYPE_ERROR("precision must be Python integer");
 840        return -1;
 841    }
 842    temp = PyIntOrLong_AsSsize_t(value);
 843    if (temp < MPFR_PREC_MIN || temp > MPFR_PREC_MAX || PyErr_Occurred()) {
 844        VALUE_ERROR("invalid value for precision");
 845        return -1;
 846    }
 847    self->ctx.mpfr_prec = (mpfr_prec_t)temp;
 848    return 0;
 849}
 850
 851#ifdef WITHMPC
 852static PyObject *
 853GMPyContext_get_real_prec(GMPyContextObject *self, void *closure)
 854{
 855    return PyIntOrLong_FromSsize_t((Py_ssize_t)(GET_REAL_PREC(self)));
 856}
 857
 858static int
 859GMPyContext_set_real_prec(GMPyContextObject *self, PyObject *value, void *closure)
 860{
 861    Py_ssize_t temp;
 862
 863    if (!(PyIntOrLong_Check(value))) {
 864        TYPE_ERROR("real_prec must be Python integer");
 865        return -1;
 866    }
 867    temp = PyIntOrLong_AsSsize_t(value);
 868    if (temp == -1) {
 869        if (PyErr_Occurred()) {
 870            VALUE_ERROR("invalid value for real_prec");
 871            return -1;
 872        }
 873    }
 874    else if (temp < MPFR_PREC_MIN || temp > MPFR_PREC_MAX) {
 875        VALUE_ERROR("invalid value for real_prec");
 876        return -1;
 877    }
 878    self->ctx.real_prec = (mpfr_prec_t)temp;
 879    return 0;
 880}
 881
 882static PyObject *
 883GMPyContext_get_imag_prec(GMPyContextObject *self, void *closure)
 884{
 885    return PyIntOrLong_FromSsize_t((Py_ssize_t)(GET_IMAG_PREC(self)));
 886}
 887
 888static int
 889GMPyContext_set_imag_prec(GMPyContextObject *self, PyObject *value, void *closure)
 890{
 891    Py_ssize_t temp;
 892
 893    if (!(PyIntOrLong_Check(value))) {
 894        TYPE_ERROR("imag_prec must be Python integer");
 895        return -1;
 896    }
 897    temp = PyIntOrLong_AsSsize_t(value);
 898    if (temp == -1) {
 899        if (PyErr_Occurred()) {
 900            VALUE_ERROR("invalid value for imag_prec");
 901            return -1;
 902        }
 903    }
 904    else if (temp < MPFR_PREC_MIN || temp > MPFR_PREC_MAX) {
 905        VALUE_ERROR("invalid value for imag_prec");
 906        return -1;
 907    }
 908    self->ctx.imag_prec = (mpfr_prec_t)temp;
 909    return 0;
 910}
 911#endif
 912
 913static PyObject *
 914GMPyContext_get_round(GMPyContextObject *self, void *closure)
 915{
 916    return PyIntOrLong_FromLong((long)(self->ctx.mpfr_round));
 917}
 918
 919static int
 920GMPyContext_set_round(GMPyContextObject *self, PyObject *value, void *closure)
 921{
 922    long temp;
 923
 924    if (!(PyIntOrLong_Check(value))) {
 925        TYPE_ERROR("round mode must be Python integer");
 926        return -1;
 927    }
 928    temp = PyIntOrLong_AsLong(value);
 929    if (temp == -1 && PyErr_Occurred()) {
 930        VALUE_ERROR("invalid value for round mode");
 931        return -1;
 932    }
 933    if (temp == MPFR_RNDN)
 934        self->ctx.mpfr_round = MPFR_RNDN;
 935    else if (temp == MPFR_RNDZ)
 936        self->ctx.mpfr_round = MPFR_RNDZ;
 937    else if (temp == MPFR_RNDU)
 938        self->ctx.mpfr_round = MPFR_RNDU;
 939    else if (temp == MPFR_RNDD)
 940        self->ctx.mpfr_round = MPFR_RNDD;
 941    else if (temp == MPFR_RNDA) {
 942        self->ctx.mpfr_round = MPFR_RNDA;
 943#ifdef WITHMPC
 944        /* Since RNDA is not supported for MPC, set the MPC rounding modes
 945           to MPFR_RNDN. */
 946        self->ctx.real_round = MPFR_RNDN;
 947        self->ctx.imag_round = MPFR_RNDN;
 948#endif
 949    }
 950    else {
 951        VALUE_ERROR("invalid value for round mode");
 952        return -1;
 953    }
 954    return 0;
 955}
 956
 957#ifdef WITHMPC
 958static PyObject *
 959GMPyContext_get_real_round(GMPyContextObject *self, void *closure)
 960{
 961    return PyIntOrLong_FromLong((long)GET_REAL_ROUND(self));
 962}
 963
 964static int
 965GMPyContext_set_real_round(GMPyContextObject *self, PyObject *value, void *closure)
 966{
 967    long temp;
 968
 969    if (!(PyIntOrLong_Check(value))) {
 970        TYPE_ERROR("round mode must be Python integer");
 971        return -1;
 972    }
 973    temp = PyIntOrLong_AsLong(value);
 974    if (temp == -1 && PyErr_Occurred()) {
 975        VALUE_ERROR("invalid value for round mode");
 976        return -1;
 977    }
 978    if (temp == GMPY_DEFAULT || temp == MPFR_RNDN || temp == MPFR_RNDZ ||
 979        temp == MPFR_RNDU || temp == MPFR_RNDD) {
 980        self->ctx.real_round = (int)temp;
 981    }
 982    else {
 983        VALUE_ERROR("invalid value for round mode");
 984        return -1;
 985    }
 986    return 0;
 987}
 988
 989static PyObject *
 990GMPyContext_get_imag_round(GMPyContextObject *self, void *closure)
 991{
 992    return PyIntOrLong_FromLong((long)GET_IMAG_ROUND(self));
 993}
 994
 995static int
 996GMPyContext_set_imag_round(GMPyContextObject *self, PyObject *value, void *closure)
 997{
 998    long temp;
 999
1000    if (!(PyIntOrLong_Check(value))) {
1001        TYPE_ERROR("round mode must be Python integer");
1002        return -1;
1003    }
1004    temp = PyIntOrLong_AsLong(value);
1005    if (temp == -1 && PyErr_Occurred()) {
1006        VALUE_ERROR("invalid value for round mode");
1007        return -1;
1008    }
1009    if (temp == GMPY_DEFAULT || temp == MPFR_RNDN || temp == MPFR_RNDZ ||
1010        temp == MPFR_RNDU || temp == MPFR_RNDD) {
1011        self->ctx.imag_round = (int)temp;
1012    }
1013    else {
1014        VALUE_ERROR("invalid value for round mode");
1015        return -1;
1016    }
1017    return 0;
1018}
1019#endif
1020
1021static PyObject *
1022GMPyContext_get_emin(GMPyContextObject *self, void *closure)
1023{
1024    return PyIntOrLong_FromLong(self->ctx.emin);
1025}
1026
1027static int
1028GMPyContext_set_emin(GMPyContextObject *self, PyObject *value, void *closure)
1029{
1030    long exp;
1031
1032    if (!(PyIntOrLong_Check(value))) {
1033        TYPE_ERROR("emin must be Python integer");
1034        return -1;
1035    }
1036    exp = PyIntOrLong_AsLong(value);
1037    if (exp == -1 && PyErr_Occurred()) {
1038        VALUE_ERROR("requested minimum exponent is invalid");
1039        return -1;
1040    }
1041    if (mpfr_set_emin((mpfr_prec_t)exp)) {
1042        VALUE_ERROR("requested minimum exponent is invalid");
1043        return -1;
1044    }
1045    self->ctx.emin = exp;
1046    mpfr_set_emin(exp);
1047    return 0;
1048}
1049
1050static PyObject *
1051GMPyContext_get_emax(GMPyContextObject *self, void *closure)
1052{
1053    return PyIntOrLong_FromLong(self->ctx.emax);
1054}
1055
1056static int
1057GMPyContext_set_emax(GMPyContextObject *self, PyObject *value, void *closure)
1058{
1059    long exp;
1060
1061    if (!(PyIntOrLong_Check(value))) {
1062        TYPE_ERROR("emax must be Python integer");
1063        return -1;
1064    }
1065    exp = PyIntOrLong_AsLong(value);
1066    if (exp == -1 && PyErr_Occurred()) {
1067        VALUE_ERROR("requested maximum exponent is invalid");
1068        return -1;
1069    }
1070    if (mpfr_set_emax((mpfr_prec_t)exp)) {
1071        VALUE_ERROR("requested maximum exponent is invalid");
1072        return -1;
1073    }
1074    self->ctx.emax = exp;
1075    mpfr_set_emax(exp);
1076    return 0;
1077}
1078
1079#define ADD_GETSET(NAME) \
1080    {#NAME, \
1081        (getter)GMPyContext_get_##NAME, \
1082        (setter)GMPyContext_set_##NAME, NULL, NULL}
1083
1084static PyGetSetDef GMPyContext_getseters[] = {
1085    ADD_GETSET(precision),
1086#ifdef WITHMPC
1087    ADD_GETSET(real_prec),
1088    ADD_GETSET(imag_prec),
1089#endif
1090    ADD_GETSET(round),
1091#ifdef WITHMPC
1092    ADD_GETSET(real_round),
1093    ADD_GETSET(imag_round),
1094#endif
1095    ADD_GETSET(emax),
1096    ADD_GETSET(emin),
1097    ADD_GETSET(subnormalize),
1098    ADD_GETSET(underflow),
1099    ADD_GETSET(overflow),
1100    ADD_GETSET(inexact),
1101    ADD_GETSET(invalid),
1102    ADD_GETSET(erange),
1103    ADD_GETSET(divzero),
1104    ADD_GETSET(trap_underflow),
1105    ADD_GETSET(trap_overflow),
1106    ADD_GETSET(trap_inexact),
1107    ADD_GETSET(trap_invalid),
1108    ADD_GETSET(trap_erange),
1109    ADD_GETSET(trap_divzero),
1110    ADD_GETSET(trap_expbound),
1111#ifdef WITHMPC
1112    ADD_GETSET(allow_complex),
1113#endif
1114    {NULL}
1115};
1116
1117static PyMethodDef GMPyContext_methods[] =
1118{
1119    { "clear_flags", GMPyContext_clear_flags, METH_NOARGS,
1120            doc_context_clear_flags },
1121    { "copy", GMPyContext_context_copy, METH_NOARGS, doc_context_copy },
1122    { "__enter__", GMPyContext_enter, METH_NOARGS, NULL },
1123    { "__exit__", GMPyContext_exit, METH_VARARGS, NULL },
1124    { NULL, NULL, 1 }
1125};
1126
1127static PyTypeObject GMPyContext_Type =
1128{
1129#ifdef PY3
1130    PyVarObject_HEAD_INIT(0, 0)
1131#else
1132    PyObject_HEAD_INIT(0)
1133        0,                                  /* ob_size          */
1134#endif
1135    "gmpy2 context",                        /* tp_name          */
1136    sizeof(GMPyContextObject),              /* tp_basicsize     */
1137        0,                                  /* tp_itemsize      */
1138    (destructor) GMPyContext_dealloc,       /* tp_dealloc       */
1139        0,                                  /* tp_print         */
1140        0,                                  /* tp_getattr       */
1141        0,                                  /* tp_setattr       */
1142        0,                                  /* tp_reserved      */
1143    (reprfunc) GMPyContext_repr,            /* tp_repr          */
1144        0,                                  /* tp_as_number     */
1145        0,                                  /* tp_as_sequence   */
1146        0,                                  /* tp_as_mapping    */
1147        0,                                  /* tp_hash          */
1148        0,                                  /* tp_call          */
1149        0,                                  /* tp_str           */
1150        0,                                  /* tp_getattro      */
1151        0,                                  /* tp_setattro      */
1152        0,                                  /* tp_as_buffer     */
1153    Py_TPFLAGS_DEFAULT,                     /* tp_flags         */
1154    "GMPY2 Context Object",                 /* tp_doc           */
1155        0,                                  /* tp_traverse      */
1156        0,                                  /* tp_clear         */
1157        0,                                  /* tp_richcompare   */
1158        0,                                  /* tp_weaklistoffset*/
1159        0,                                  /* tp_iter          */
1160        0,                                  /* tp_iternext      */
1161    GMPyContext_methods,                    /* tp_methods       */
1162        0,                                  /* tp_members       */
1163    GMPyContext_getseters,                  /* tp_getset        */
1164};
1165
1166static PyMethodDef GMPyContextManager_methods[] =
1167{
1168    { "__enter__", GMPyContextManager_enter, METH_NOARGS, NULL },
1169    { "__exit__", GMPyContextManager_exit, METH_VARARGS, NULL },
1170    { NULL, NULL, 1 }
1171};
1172
1173static PyTypeObject GMPyContextManager_Type =
1174{
1175#ifdef PY3
1176    PyVarObject_HEAD_INIT(0, 0)
1177#else
1178    PyObject_HEAD_INIT(0)
1179        0,                                   /* ob_size          */
1180#endif
1181    "gmpy2 context",                         /* tp_name          */
1182    sizeof(GMPyContextManagerObject),        /* tp_basicsize     */
1183        0,                                   /* tp_itemsize      */
1184    (destructor) GMPyContextManager_dealloc, /* tp_dealloc       */
1185        0,                                   /* tp_print         */
1186        0,                                   /* tp_getattr       */
1187        0,                                   /* tp_setattr       */
1188        0,                                   /* tp_reserved      */
1189    (reprfunc) GMPyContextManager_repr,      /* tp_repr          */
1190        0,                                   /* tp_as_number     */
1191        0,                                   /* tp_as_sequence   */
1192        0,                                   /* tp_as_mapping    */
1193        0,                                   /* tp_hash          */
1194        0,                                   /* tp_call          */
1195        0,                                   /* tp_str           */
1196        0,                                   /* tp_getattro      */
1197        0,                                   /* tp_setattro      */
1198        0,                                   /* tp_as_buffer     */
1199    Py_TPFLAGS_DEFAULT,                      /* tp_flags         */
1200    "GMPY2 Context manager",                 /* tp_doc           */
1201        0,                                   /* tp_traverse      */
1202        0,                                   /* tp_clear         */
1203        0,                                   /* tp_richcompare   */
1204        0,                                   /* tp_weaklistoffset*/
1205        0,                                   /* tp_iter          */
1206        0,                                   /* tp_iternext      */
1207    GMPyContextManager_methods,              /* tp_methods       */
1208        0,                                   /* tp_members       */
1209        0,                                   /* tp_getset        */
1210};