Skip to content

Instantly share code, notes, and snippets.

@agalera
Last active June 28, 2016 08:59
Show Gist options
  • Save agalera/918901457618b92316c0 to your computer and use it in GitHub Desktop.
Save agalera/918901457618b92316c0 to your computer and use it in GitHub Desktop.
Product.c
#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