Last active
June 28, 2016 08:59
-
-
Save agalera/918901457618b92316c0 to your computer and use it in GitHub Desktop.
Product.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Python.h> | |
#include <stdio.h> | |
#include <string.h> | |
typedef struct { | |
PyObject_HEAD | |
char* trans; | |
int len_letters; | |
char* letters; | |
int repeat; | |
int iters; | |
int init; | |
int* values; | |
} product_struct; | |
PyObject* product_iter(PyObject *self) | |
{ | |
Py_INCREF(self); | |
return self; | |
} | |
PyObject* product_iternext(PyObject *self) | |
{ | |
product_struct *p = (product_struct *)self; | |
if (p->init < p->iters) { | |
int i; | |
for (i=p->repeat-1; i>=0; i--){ | |
if (p->values[i] == p->len_letters-1){ | |
p->values[i] = 0; | |
p->trans[i] = p->letters[0]; | |
}else{ | |
p->values[i]++; | |
p->trans[i] = p->letters[p->values[i]]; | |
break; | |
} | |
} | |
PyObject *tmp = Py_BuildValue("s", p->trans); | |
p->init++; | |
return tmp; | |
} else { | |
/* Raising of standard StopIteration exception with empty value. */ | |
PyErr_SetNone(PyExc_StopIteration); | |
return NULL; | |
} | |
} | |
static PyTypeObject productType = { | |
PyObject_HEAD_INIT(NULL) | |
0, /*ob_size*/ | |
"product", /*tp_name*/ | |
sizeof(product_struct), /*tp_basicsize*/ | |
0, /*tp_itemsize*/ | |
0, /*tp_dealloc*/ | |
0, /*tp_print*/ | |
0, /*tp_getattr*/ | |
0, /*tp_setattr*/ | |
0, /*tp_compare*/ | |
0, /*tp_repr*/ | |
0, /*tp_as_number*/ | |
0, /*tp_as_sequence*/ | |
0, /*tp_as_mapping*/ | |
0, /*tp_hash */ | |
0, /*tp_call*/ | |
0, /*tp_str*/ | |
0, /*tp_getattro*/ | |
0, /*tp_setattro*/ | |
0, /*tp_as_buffer*/ | |
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, | |
/* tp_flags: Py_TPFLAGS_HAVE_ITER tells python to | |
use tp_iter and tp_iternext fields. */ | |
"Internal product iterator object.", /* tp_doc */ | |
0, /* tp_traverse */ | |
0, /* tp_clear */ | |
0, /* tp_richcompare */ | |
0, /* tp_weaklistoffset */ | |
product_iter, /* tp_iter: __iter__() method */ | |
product_iternext /* tp_iternext: next() method */ | |
}; | |
long pow(int a, int b) | |
{ | |
if (b<=0) | |
return 1; | |
else | |
return a*pow(a,b-1); | |
} | |
void calculate(int *values, int number, int repeat, int len_letters) | |
{ | |
int i = 0; | |
int accumulated = 0; | |
for(i=repeat-1; i>=0; i--){ | |
values[i] = (number - accumulated) / pow(len_letters, i); | |
accumulated = accumulated + values[i]*pow(len_letters, i); | |
} | |
values[repeat-1]--; | |
} | |
static PyObject* product(PyObject* self, PyObject *args) | |
{ | |
int repeat; | |
int init; | |
int iters; | |
char* letters; | |
product_struct *p; | |
if (!PyArg_ParseTuple(args, "siii", &letters, &repeat, &init, &iters)) { | |
return NULL; | |
} | |
//printf("%s %d %d %d", letters, repeat, init, iters); | |
/* I don't need python callable __init__() method for this iterator, | |
so I'll simply allocate it as PyObject and initialize it by hand. */ | |
p = PyObject_New(product_struct, &productType); | |
if (!p) return NULL; | |
int values[repeat]; | |
int len_letters = strlen(letters); | |
calculate(values, init, repeat, len_letters); | |
int i; | |
p->values = malloc(repeat * sizeof(int)); | |
p->trans = malloc(repeat * sizeof(char)); | |
p->letters = malloc(repeat * sizeof(char)); | |
for (i=0; i < len_letters; i++){ | |
p->letters[i] = letters[i]; | |
} | |
for (i=0; i < repeat; i++){ | |
p->values[i] = values[i]; | |
p->trans[i] = letters[values[i]]; | |
} | |
p->len_letters = len_letters; | |
p->repeat = repeat; | |
p->iters = iters; | |
p->init = init; | |
return (PyObject *)p; | |
} | |
static PyMethodDef SpamMethods[] = { | |
{"product", product, METH_VARARGS, "the best help."}, | |
{NULL, NULL, 0, NULL} /* Sentinel */ | |
}; | |
PyMODINIT_FUNC | |
initproduct(void) | |
{ | |
PyObject* m; | |
productType.tp_new = PyType_GenericNew; | |
if (PyType_Ready(&productType) < 0) return; | |
m = Py_InitModule("product", SpamMethods); | |
Py_INCREF(&productType); | |
PyModule_AddObject(m, "_product", (PyObject *)&productType); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment