Skip to content

Commit

Permalink
major improvements to numeric python object conversion to tcl
Browse files Browse the repository at this point in the history
When creating a new Tcl object from a Python object,  and the Python object was numeric, tohil always converted it to a string, which thereby supported both Tcl and Python's arbitrary precision arithmetic, but would be slower than using access functions that worked on machine-native numeric types.

Tohil, now, if the python object is a number, tries PyLong_AsLongAndOverflow to convert to long and if it works without overflow, returns a Tcl_NewLongObj.

If it overflowed, tohil tries PyLong_AsLongLongAndOverflow, and if that doesn't overflow, tohil returns a new wide integer through Tcl_NewWideIntObj.

Likewise if the number is floating point, it is converted through PyFLoat_AsDouble and Tcl_NewDoubleObj.

Now, only if the number is wider than a long long, or complex, is it converted to a string for Tcl.
  • Loading branch information
lehenbauer committed Nov 19, 2021
1 parent 37db38e commit 5904070
Showing 1 changed file with 30 additions and 2 deletions.
32 changes: 30 additions & 2 deletions generic/tohil.c
Original file line number Diff line number Diff line change
Expand Up @@ -529,13 +529,41 @@ _pyObjToTcl(Tcl_Interp *interp, PyObject *pObj)
ckfree(utf8string);
Py_DECREF(pBytesObj);
} else if (PyNumber_Check(pObj)) {
/* We go via string to support arbitrary length numbers */
// we go via string to support arbitrary length numbers
if (PyLong_Check(pObj)) {
int overflow = 0;
// try long conversion
long longValue = PyLong_AsLongAndOverflow(pObj, &overflow);
if (!overflow)
return Tcl_NewLongObj(longValue);

// not big enough try long long conversion
overflow = 0;
Tcl_WideInt wideValue = PyLong_AsLongLongAndOverflow(pObj, &overflow);
if (!overflow) {
return Tcl_NewWideIntObj(wideValue);
}
// still not big enough just use strings
// (both python and tcl have bignum support)
pStrObj = PyNumber_ToBase(pObj, 10);
} else {
assert(PyComplex_Check(pObj) || PyFloat_Check(pObj));
// it's not int, it better be float or complex
if (PyFloat_Check(pObj)) {
// it's float, effeciently get it from python
// to tcl
double doubleValue = PyFloat_AsDouble(pObj);
if (doubleValue == 1.0 && PyErr_Occurred()) {
return NULL;
}
return Tcl_NewDoubleObj(doubleValue);
}
// it has to be complex type at this point, punt to string
assert(PyComplex_Check(pObj));
pStrObj = PyObject_Str(pObj);
}

// still here? it's either wider than a long long, or
// complex, send it to tcl as a string
if (pStrObj == NULL)
return NULL;
pBytesObj = PyUnicode_AsUTF8String(pStrObj);
Expand Down

0 comments on commit 5904070

Please sign in to comment.