Skip to content

Commit

Permalink
support for fraction objects
Browse files Browse the repository at this point in the history
  • Loading branch information
teepark committed Feb 11, 2014
1 parent 95a3deb commit 1990bfd
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 7 deletions.
3 changes: 3 additions & 0 deletions include/mummy.h
Expand Up @@ -79,6 +79,7 @@
#define MUMMY_TYPE_TIMEDELTA 0x1D
#define MUMMY_TYPE_DECIMAL 0x1E
#define MUMMY_TYPE_SPECIALNUM 0x1F
#define MUMMY_TYPE_FRACTION 0x20

#define MUMMY_SPECIAL_INFINITY 0x10
#define MUMMY_SPECIAL_NAN 0x20
Expand Down Expand Up @@ -113,6 +114,7 @@ int mummy_read_utf8(mummy_string *, int, char **, int *);
int mummy_point_to_utf8(mummy_string *, char **, int *);
int mummy_read_decimal(mummy_string *, char *, int16_t *, uint16_t *, char **);
int mummy_read_specialnum(mummy_string *, char *);
int mummy_read_fraction(mummy_string *, int64_t *, int64_t *);
int mummy_read_date(mummy_string *, short *, char *, char *);
int mummy_read_time(mummy_string *, char *, char *, char *, int *);
int mummy_read_datetime(mummy_string *, short *, char *, char *,
Expand Down Expand Up @@ -144,6 +146,7 @@ int mummy_feed_decimal(mummy_string *, char, int16_t, uint16_t, char *);
/*int mummy_feed_va_decimal(mummy_string *, char, uint16_t, uint16_t, ...);*/
int mummy_feed_infinity(mummy_string *, char);
int mummy_feed_nan(mummy_string *, char);
int mummy_feed_fraction(mummy_string *, int64_t, int64_t);
int mummy_feed_date(mummy_string *, unsigned short, char, char);
int mummy_feed_time(mummy_string *, char, char, char, int);
int mummy_feed_datetime(
Expand Down
11 changes: 11 additions & 0 deletions lib/dump.c
Expand Up @@ -197,6 +197,17 @@ mummy_feed_nan(mummy_string *str, char is_snan) {
return 0;
}

inline int
mummy_feed_fraction(mummy_string *str, int64_t numerator, int64_t denominator) {
mummy_string_makespace(str, 17);
str->data[str->offset++] = MUMMY_TYPE_FRACTION;
*((int64_t *)(str->data + str->offset)) = htonll(numerator);
str->offset += 8;
*((int64_t *)(str->data + str->offset)) = htonll(denominator);
str->offset += 8;
return 0;
}

inline int
mummy_feed_date(mummy_string *str, unsigned short year, char month, char day) {
mummy_string_makespace(str, 5);
Expand Down
11 changes: 11 additions & 0 deletions lib/load.c
Expand Up @@ -273,6 +273,17 @@ mummy_read_specialnum(mummy_string *str, char *flags) {
return 0;
}

inline int
mummy_read_fraction(mummy_string *str,
int64_t *numerator, int64_t *denominator) {
if (mummy_string_space(str) < 17) return -1;
*numerator = ntohll(*(int64_t *)(str->data + str->offset + 1));
str->offset += 9;
*denominator = ntohll(*(int64_t *)(str->data + str->offset));
str->offset += 8;
return 0;
}

inline int
mummy_read_date(mummy_string *str, short *year, char *month, char *day) {
if (mummy_string_space(str) < 5) return -1;
Expand Down
27 changes: 24 additions & 3 deletions python/dump.c
@@ -1,8 +1,9 @@
#include "mummypy.h"


/* import decimal and datetime at mummy import time */
/* import decimal, fraction and datetime at mummy import time */
extern PyObject *PyDecimalType;
extern PyObject *PyFractionType;
extern PyDateTime_CAPI *PyDateTimeCAPI;


Expand All @@ -12,7 +13,7 @@ dump_one(PyObject *obj, mummy_string *str, PyObject *default_handler,
int i, rc = 0;
size_t size;
long l;
long long ll;
long long ll, ll2;
char c, *buf;
PyObject *key, *value, *iterator, *args;
Py_ssize_t pst;
Expand Down Expand Up @@ -57,6 +58,7 @@ dump_one(PyObject *obj, mummy_string *str, PyObject *default_handler,
size = _PyLong_NumBits(obj) + 1;
size = (size >> 3) + (size & 0x7 ? 1 : 0);

/* TODO: this extra copy shouldn't be necessary */
if (!(buf = malloc(size))) {
PyErr_SetString(PyExc_MemoryError, "out of memory");
return -1;
Expand Down Expand Up @@ -326,12 +328,31 @@ dump_one(PyObject *obj, mummy_string *str, PyObject *default_handler,
if (EINVAL == rc) {
PyErr_SetString(PyExc_SystemError,
"mummy dump internal failure");
return -1;
goto fail;
}
}
goto done;
}

if (Py_TYPE(obj) == (PyTypeObject *)PyFractionType) {
if (NULL == (value = PyObject_GetAttrString(obj, "numerator")))
goto fail;
ll = PyInt_AsLongLong(value);
Py_DECREF(value);
if (-1 == ll && PyErr_Occurred())
goto fail;

if (NULL == (value = PyObject_GetAttrString(obj, "denominator")))
goto fail;
ll2 = PyInt_AsLongLong(value);
Py_DECREF(value);
if (-1 == ll2 && PyErr_Occurred())
goto fail;

rc = mummy_feed_fraction(str, (int64_t)ll, (int64_t)ll2);
goto done;
}

/* didn't find the object type */
if (default_handler != Py_None) {
Py_INCREF(obj);
Expand Down
36 changes: 34 additions & 2 deletions python/load.c
@@ -1,6 +1,7 @@
#include "mummypy.h"

extern PyDateTime_CAPI *PyDateTimeCAPI;
extern PyObject *PyFractionType;
extern PyObject *PyDecimalType;

#define INVALID do {\
Expand All @@ -10,9 +11,18 @@ extern PyObject *PyDecimalType;
} while(0)


static PyObject *
python_num(int64_t num) {
if (-2147483648LL <= num && num < 2147483648LL) {
return PyInt_FromLong((long)num);
}
return PyLong_FromLongLong(num);
}


static PyObject *
load_one(mummy_string *str) {
int64_t int_result = 0;
int64_t int_result = 0, int_result2;
int i, microsecond;
int days, seconds, microseconds;
short year, expo;
Expand Down Expand Up @@ -131,7 +141,8 @@ load_one(mummy_string *str) {
}
goto done;

case MUMMY_TYPE_DATE: if (mummy_read_date(str, &year, &month, &day)) INVALID;
case MUMMY_TYPE_DATE:
if (mummy_read_date(str, &year, &month, &day)) INVALID;
result = PyDateTimeCAPI->Date_FromDate(
year, month, day, PyDateTimeCAPI->DateType);
goto done;
Expand Down Expand Up @@ -250,6 +261,26 @@ load_one(mummy_string *str) {
return NULL;
}

case MUMMY_TYPE_FRACTION:
if (mummy_read_fraction(str, &int_result, &int_result2)) INVALID;
if (NULL == (triple = PyTuple_New(2))) return NULL;

if (NULL == (value = python_num(int_result))) {
Py_DECREF(triple);
return NULL;
}
PyTuple_SET_ITEM(triple, 0, value);

if (NULL == (value = python_num(int_result2))) {
Py_DECREF(triple);
return NULL;
}
PyTuple_SET_ITEM(triple, 1, value);

result = PyObject_Call(PyFractionType, triple, NULL);
Py_DECREF(triple);
return result;

default:
PyErr_SetString(PyExc_ValueError, "invalid mummy (unrecognized type)");
return NULL;
Expand All @@ -275,6 +306,7 @@ load_one(mummy_string *str) {
return NULL;
}


PyObject *
python_loads(PyObject *self, PyObject *data) {
PyObject *result;
Expand Down
14 changes: 14 additions & 0 deletions python/mummy/serialization.py
@@ -1,5 +1,6 @@
import datetime
import decimal
import fractions
import itertools
import struct
import sys
Expand Down Expand Up @@ -88,6 +89,8 @@ def __iter__(self):
MUMMY_TYPE_DECIMAL = 0x1E
MUMMY_TYPE_SPECIALNUM = 0x1F

MUMMY_TYPE_FRACTION = 0x20

MUMMY_SPECIAL_INFINITY = 0x10
MUMMY_SPECIAL_NAN = 0x20

Expand Down Expand Up @@ -176,6 +179,9 @@ def _get_type_code(x):
return MUMMY_TYPE_SPECIALNUM
return MUMMY_TYPE_DECIMAL

if type(x) is fractions.Fraction:
return MUMMY_TYPE_FRACTION

raise ValueError("%r cannot be serialized" % type(x))


Expand Down Expand Up @@ -336,6 +342,9 @@ def _dump_specialnum(x, depth=0, default=None):
if x.is_infinite():
return _dump_uchar(MUMMY_SPECIAL_INFINITY | int(x < 0))

def _dump_fraction(x, depth=0, default=None):
return struct.pack("!qq", x.numerator, x.denominator)


_dumpers = {
MUMMY_TYPE_NULL: _dump_none,
Expand Down Expand Up @@ -370,6 +379,7 @@ def _dump_specialnum(x, depth=0, default=None):
MUMMY_TYPE_TIMEDELTA: _dump_timedelta,
MUMMY_TYPE_DECIMAL: _dump_decimal,
MUMMY_TYPE_SPECIALNUM: _dump_specialnum,
MUMMY_TYPE_FRACTION: _dump_fraction,
}

def pure_python_dumps(item, default=None, depth=0, compress=True):
Expand Down Expand Up @@ -620,6 +630,9 @@ def _load_specialnum(x):
return decimal.Decimal("sNaN"), 1
return decimal.Decimal("NaN"), 1

def _load_fraction(x):
return fractions.Fraction(*struct.unpack("!qq", x[:16])), 16


_loaders = {
MUMMY_TYPE_NULL: _load_none,
Expand Down Expand Up @@ -654,6 +667,7 @@ def _load_specialnum(x):
MUMMY_TYPE_TIMEDELTA: _load_timedelta,
MUMMY_TYPE_DECIMAL: _load_decimal,
MUMMY_TYPE_SPECIALNUM: _load_specialnum,
MUMMY_TYPE_FRACTION: _load_fraction,
}

def _loads(data):
Expand Down
16 changes: 14 additions & 2 deletions python/mummymodule.c
Expand Up @@ -5,6 +5,7 @@

/* import decimal and datetime at mummy import time */
PyObject *PyDecimalType;
PyObject *PyFractionType;
PyDateTime_CAPI *PyDateTimeCAPI;


Expand Down Expand Up @@ -49,7 +50,7 @@ static struct PyModuleDef _mummymodule = {

PyMODINIT_FUNC
PyInit__mummy(void) {
PyObject *mummy_module, *decimal_module;
PyObject *mummy_module, *decimal_module, *fractions_module;

mummy_module = PyModule_Create(&_mummymodule);

Expand All @@ -59,13 +60,19 @@ PyInit__mummy(void) {
decimal_module = PyImport_ImportModule("decimal");
PyDecimalType = PyObject_GetAttrString(decimal_module, "Decimal");
Py_INCREF(PyDecimalType);
Py_DECREF(decimal_module);

fractions_module = PyImport_ImportModule("fractions");
PyFractionType = PyObject_GetAttrString(fractions_module, "Fraction");
Py_INCREF(PyFractionType);
Py_DECREF(fractions_module);

return module;
}
#else
PyMODINIT_FUNC
init_mummy(void) {
PyObject *decimal_module;
PyObject *decimal_module, *fractions_module;

Py_InitModule("_mummy", methods);

Expand All @@ -76,5 +83,10 @@ init_mummy(void) {
PyDecimalType = PyObject_GetAttrString(decimal_module, "Decimal");
Py_INCREF(PyDecimalType);
Py_DECREF(decimal_module);

fractions_module = PyImport_ImportModule("fractions");
PyFractionType = PyObject_GetAttrString(fractions_module, "Fraction");
Py_INCREF(PyFractionType);
Py_DECREF(fractions_module);
}
#endif

0 comments on commit 1990bfd

Please sign in to comment.