VCC PRIORITY QUEUE NATIVE IMPL
Courageous
jkraska1 at san.rr.com
Mon May 29 15:23:18 EDT 2000
This is a visual c++ implementation of a heap-priority queue.
It is 5-6 times faster than the equivalent python, as tested
doing heapsort. This priority queue implements "lowest is best"
priority, so all pops always retrieve the lowest item in the
queue.
This is my second implementation of a python C extension, and
I believe it is correct, however there exists some small chance
I've messed up something with references, as I'm fairly new at
this.
Hope someone finds this useful,
C/
//////////////////////////////////////////////////////////////////////
// Pqueue.c -- pque and pque cursor object types for python
//////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <Python.h>
//////////////////////////////////////////////////////////////////////
// FORWARD DECLARES AND THE LIKE:
//////////////////////////////////////////////////////////////////////
static char msg[256];
staticforward PyTypeObject PqueueObjectType;
//////////////////////////////////////////////////////////////////////
// INTERNAL DATA TYPES:
//////////////////////////////////////////////////////////////////////
typedef struct __PqueueNode PqueueNode;
typedef struct __PqueueNode
{
double priority;
PyObject* object;
}
PqueueNode;
//////////////////////////////////////////////////////////////////////
// EXTERNAL DATA TYPES / PYTHON OBJECTS:
//////////////////////////////////////////////////////////////////////
typedef struct __Pqueue
{
PyObject_HEAD
PqueueNode** heap; // the heap array
long len; // current length
long alloclen; // allocated length
}
Pqueue;
//////////////////////////////////////////////////////////////////////
static void PqueueObjectDestroy (Pqueue* self);
static PyObject* PqueueObjectGetattr (Pqueue* self, char* name);
static int PqueueSeqLen (Pqueue* self);
//####################################################################
// PQUEUE METHODS
//####################################################################
static PyObject* PqueuePush ( Pqueue* pque, PyObject* args )
{
PqueueNode* newnode;
PqueueNode* temp;
PyObject* object;
double pri;
PqueueNode** heap;
long pos;
if (!PyArg_ParseTuple(args,"dO", &pri, &object))
{
PyErr_SetString(PyExc_ValueError, "attempt to push onto pque without an object to push");
return NULL;
}
Py_INCREF ( object );
newnode = (PqueueNode*) malloc ( sizeof(PqueueNode) );
newnode->object = object;
newnode->priority = pri;
pos = pque->len+1;
heap = pque->heap;
heap[pos] = newnode;
pque->len++;
//sprintf(msg,"print \"pushing node pos= %d pri= %f\"", pos, pri);
//PyRun_SimpleString(msg);
while (heap[pos/2]->priority > heap[pos]->priority)
{
temp = heap[pos/2];
heap[pos/2] = heap[pos];
heap[pos] = temp;
pos /= 2;
}
Py_INCREF(Py_None);
return Py_None;
}
static PyObject* PqueuePop ( Pqueue* pque, PyObject* args )
{
PqueueNode** heap;
PqueueNode* popnode;
PqueueNode* temp;
PyObject* retval;
long pos;
long len;
double pri;
long j;
if (pque->len == 0)
{
Py_INCREF(Py_None);
return Py_None;
}
heap = pque->heap;
popnode = heap[1];
retval = popnode->object;
len = pque->len;
pri = popnode->priority;
pos = 1;
j = 2;
if (len>1)
{
heap[1]=heap[len];
len--;
while ( pos <= len/2 )
{
if ( j<len && heap[j]->priority > heap[j+1]->priority) j++;
if ( heap[pos]->priority <= heap[j]->priority) break;
temp = heap[pos];
heap[pos] = heap[j];
heap[j] = temp;
pos = j;
j = pos*2;
}
}
pque->len--;
free((char*)popnode);
//Py_INCREF(retval);
return retval;
}
//// PqueuePeek() -- return the value of the tail item, but don't pop
static PyObject* PqueuePeek ( Pqueue* pque, PyObject* args )
{
if (pque->len == 0)
{
Py_INCREF(Py_None);
return Py_None;
}
Py_INCREF(pque->heap[1]->object);
return pque->heap[1]->object;
}
static PyObject* PqueueDump ( Pqueue* pque, PyObject* args )
{
int i;
for (i=0;i<pque->len+1;i++)
{
sprintf(msg,"print \"node %f\"", pque->heap[i]->priority);
PyRun_SimpleString(msg);
}
Py_INCREF(Py_None);
return Py_None;
}
//####################################################################
// MODULE HOOKUPS
//####################################################################
//// Primary instance object CONSTRUCTOR
static PyObject* PqueueCreate ( PyObject* module, PyObject* args )
{
Pqueue* pque = PyObject_NEW (Pqueue,&PqueueObjectType);
PqueueNode* sentinel = (PqueueNode*) malloc ( sizeof(PqueueNode));
long initialsize = 1000;
PyArg_ParseTuple(args,"i", &initialsize); // failure okay
sprintf(msg,"print \"new pque size is %d\"", initialsize);
PyRun_SimpleString(msg);
// we always make room for a sentinel
pque->heap = (PqueueNode**) malloc ( (initialsize+2) * sizeof(PqueueNode*) );
sentinel->priority = -1;
pque->heap[0] = sentinel;
pque->len = 0;
pque->alloclen = initialsize;
return pque;
}
//// Pqueue object method hookup
static char PqueuePushDoc[]=
"p.push(priority,object) -- pushes an object onto the queue with the designated priority; always
returns None";
static char PqueuePopDoc[]=
"p.pop() -- pops the highest priority object off the priority queue; returns None if no object
is present.";
static char PqueuePeekDoc[]=
"p.peek() -- returns the object at the head of the pque, leaving it in the pque; returns None if
no object is present.";
static struct PyMethodDef PqueueObjectMethods[]=
{
{ "push", (PyCFunction)PqueuePush, 1, PqueuePushDoc },
{ "pop", (PyCFunction)PqueuePop, 0, PqueuePopDoc },
{ "peek", (PyCFunction)PqueuePeek, 0, PqueuePeekDoc },
{ "dump", (PyCFunction)PqueueDump, 0, PqueuePeekDoc },
{ NULL, NULL }
};
static PySequenceMethods PqueueSequenceMethods=
{
(inquiry) PqueueSeqLen, // len(p)
(binaryfunc) 0, // concat
(intargfunc) 0, // ?
(intargfunc) 0, // p[i]
(intintargfunc) 0, // p[i:j]
(intobjargproc) 0, // p[i]=v
(intintobjargproc) 0, // p[i:j]=v
};
//// Pqueue object python type
static PyTypeObject PqueueObjectType =
{
PyObject_HEAD_INIT(0) // mandatory init
0, // ?
"pqueue", // object name
sizeof(Pqueue), // record size
0, // ?
(destructor) PqueueObjectDestroy,
0, // print
(getattrfunc) PqueueObjectGetattr,
0, //PqueueObjectSetattr,
0, // compare
0, //PqueueObjectRepr,
0, // number
&PqueueSequenceMethods,
0, // mapping
0, // hash
0, // call
0 // str
};
//// Our module-level methods; there's just one:
static char PqueueCreateDoc[] =
"create() -- creates a priority queue object";
static PyMethodDef PqueueModuleMethods[]=
{
{"create", PqueueCreate, 1, PqueueCreateDoc},
{NULL, NULL }
};
//####################################################################
// PQUEUE PRIMARY METHODS
//####################################################################
static void PqueueObjectDestroy (Pqueue* self)
{
int i;
free((char*)self->heap[0]); // free the sentinel
for (i=1;i<self->len+1;i++) // from sentinel to end
{
Py_DECREF ( self->heap[i]->object );
free((char*)self->heap[i]);
}
PyMem_DEL (self);
}
static PyObject* PqueueObjectGetattr ( Pqueue* self, char* name)
{
return Py_FindMethod(PqueueObjectMethods,(PyObject*)self, name);
}
static int PqueueSeqLen (Pqueue* self)
{
return self->len;
}
//####################################################################
// GLUE
//####################################################################
void _declspec(dllexport) initpqueue()
{
Py_InitModule("pqueue", PqueueModuleMethods);
}
//////////////////////////////////////////////////////////////////////
// END
//////////////////////////////////////////////////////////////////////
More information about the Python-list
mailing list