mirror of
https://github.com/worldforge/cyphesis
synced 2026-08-13 12:26:04 -04:00
166 lines
6.1 KiB
C++
166 lines
6.1 KiB
C++
#include "Py_Filter.h"
|
|
#include "Py_Thing.h"
|
|
|
|
///\brief Create a new Filter object for a given query
|
|
PyObject * get_filter(PyObject * self, PyObject* query){
|
|
if (!PyUnicode_CheckExact(query)){
|
|
PyErr_SetString(PyExc_TypeError, "Map_get_filter what must be string");
|
|
return nullptr;
|
|
}
|
|
char * query_str = PyUnicode_AsUTF8(query);
|
|
PyFilter* f = newPyFilter();
|
|
try {
|
|
//FIXME: creating and accessing an instance of a factory should be done in a better way
|
|
EntityFilter::MindProviderFactory factory;
|
|
f->m_filter = new EntityFilter::Filter(query_str, &factory);
|
|
}
|
|
catch (std::invalid_argument& e){
|
|
PyErr_SetString(PyExc_TypeError, String::compose("Invalid query for Entity Filter: %1", e.what()).c_str());
|
|
return nullptr;
|
|
}
|
|
return (PyObject*)f;
|
|
}
|
|
|
|
///\brief Match a single entity using a filter that called this method.
|
|
static PyObject * match_entity(PyFilter * self, PyObject * py_entity)
|
|
{
|
|
if (!PyLocatedEntity_Check(py_entity)) {
|
|
PyErr_SetString(PyExc_AssertionError, "Argument must be Entity in match_entity");
|
|
return nullptr;
|
|
}
|
|
|
|
if(self->m_filter == nullptr){
|
|
PyErr_SetString(PyExc_AssertionError, "nullptr Filter in Filter.match_entity");
|
|
return nullptr;
|
|
}
|
|
|
|
//Not sure if this is safest or the most correct way to get an entity pointer
|
|
LocatedEntity* entity = ((PyEntity*)py_entity)->m_entity.l;
|
|
|
|
EntityFilter::Filter* filter = self->m_filter;
|
|
|
|
if (entity && filter->match(*entity)) {
|
|
Py_INCREF(Py_True);
|
|
return Py_True;
|
|
} else {
|
|
Py_INCREF(Py_False);
|
|
return Py_False;
|
|
}
|
|
}
|
|
|
|
///\This method is used to search the "contains" property of an entity,
|
|
///returning a list of entities that match a given filter
|
|
///
|
|
///This is useful when the client code knows that the query always requires
|
|
///to search within a contains property (i.e. inventory of a given entity)
|
|
///
|
|
///@param self - filter used to match entities
|
|
///@param py_entity - an entity whose "contains" property to search
|
|
PyObject* search_contains(PyFilter* self, PyEntity* py_entity){
|
|
#ifndef NDEBUG
|
|
if (self->m_filter == nullptr) {
|
|
PyErr_SetString(PyExc_AssertionError,
|
|
"nullptr Filter in Entity_filter.search_contains");
|
|
return nullptr;
|
|
}
|
|
#endif // NDEBUG
|
|
|
|
//This function is often used on mind's own entity, in which case, the type is PyMind
|
|
if (!PyMind_Check(py_entity) && !PyEntity_Check(py_entity)){
|
|
return nullptr;
|
|
}
|
|
LocatedEntity* ent = py_entity->m_entity.l;
|
|
|
|
if(!ent->m_contains){
|
|
return PyList_New(0);
|
|
}
|
|
//Perform actual search
|
|
auto iter = ent->m_contains->begin();
|
|
auto iter_end = ent->m_contains->end();
|
|
|
|
std::vector<LocatedEntity*> res;
|
|
|
|
for (;iter != iter_end; ++iter){
|
|
if((**iter).isVisible() && self->m_filter->match(**iter)){
|
|
res.push_back(*iter);
|
|
}
|
|
}
|
|
|
|
//Create a python list an fill it with the entities we got
|
|
//FIXME: the code below is reused in multiple places
|
|
PyObject * list = PyList_New(res.size());
|
|
if (list == nullptr) {
|
|
return nullptr;
|
|
}
|
|
std::vector<LocatedEntity*>::const_iterator Iend = res.end();
|
|
int i = 0;
|
|
for (std::vector<LocatedEntity*>::const_iterator I = res.begin(); I != Iend; ++I, ++i) {
|
|
PyObject * thing = wrapEntity(*I);
|
|
if (thing == nullptr) {
|
|
Py_DECREF(list);
|
|
return nullptr;
|
|
}
|
|
PyList_SetItem(list, i, thing);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
static void Filter_dealloc(PyFilter *self)
|
|
{
|
|
if (self->m_filter != nullptr) {
|
|
delete self->m_filter;
|
|
}
|
|
Py_TYPE(self)->tp_free((PyObject*)self);
|
|
}
|
|
|
|
static PyMethodDef Filter_methods[] = {
|
|
{"match_entity", (PyCFunction)match_entity, METH_O},
|
|
{"search_contains", (PyCFunction)search_contains, METH_O},
|
|
{nullptr, nullptr} // sentinel
|
|
};
|
|
|
|
PyTypeObject PyFilter_Type = {
|
|
PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
|
"Filter", // tp_name
|
|
sizeof(PyFilter), // tp_basicsize
|
|
0, // tp_itemsize
|
|
// methods
|
|
(destructor)Filter_dealloc, // 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, // tp_flags
|
|
"Filter object", // tp_doc
|
|
0, // tp_travers
|
|
0, // tp_clear
|
|
0, // tp_richcompare
|
|
0, // tp_weaklistoffset
|
|
0, // tp_iter
|
|
0, // tp_iternext
|
|
Filter_methods, // tp_methods
|
|
0, // tp_members
|
|
0, // tp_getset
|
|
0, // tp_base
|
|
0, // tp_dict
|
|
0, // tp_descr_get
|
|
0, // tp_descr_set
|
|
0, // tp_dictoffset
|
|
0, // tp_init
|
|
0, // tp_alloc
|
|
0, // tp_new
|
|
};
|
|
|
|
PyFilter* newPyFilter(){
|
|
return (PyFilter*)PyFilter_Type.tp_new(&PyFilter_Type, 0, 0);
|
|
}
|