#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 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::const_iterator Iend = res.end(); int i = 0; for (std::vector::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); }