Grid code quality improvements
* Grid [x, y] subscript - convenience for `.at()` * Extract UIEntityCollection - cleanup of UIGrid.cpp * Thread-safe type cache - PyTypeCache * Exception-safe extend() - validate before modify
This commit is contained in:
parent
a77ac6c501
commit
d6ef29f3cd
7 changed files with 1492 additions and 1097 deletions
114
src/UIGrid.h
114
src/UIGrid.h
|
|
@ -23,6 +23,7 @@
|
|||
#include "GridLayers.h"
|
||||
#include "GridChunk.h"
|
||||
#include "SpatialHash.h"
|
||||
#include "UIEntityCollection.h" // EntityCollection types (extracted from UIGrid)
|
||||
|
||||
class UIGrid: public UIDrawable
|
||||
{
|
||||
|
|
@ -180,6 +181,8 @@ public:
|
|||
|
||||
static PyMethodDef methods[];
|
||||
static PyGetSetDef getsetters[];
|
||||
static PyMappingMethods mpmethods; // For grid[x, y] subscript access
|
||||
static PyObject* subscript(PyUIGridObject* self, PyObject* key); // __getitem__
|
||||
static PyObject* get_entities(PyUIGridObject* self, void* closure);
|
||||
static PyObject* get_children(PyUIGridObject* self, void* closure);
|
||||
static PyObject* repr(PyUIGridObject* self);
|
||||
|
|
@ -200,54 +203,7 @@ public:
|
|||
static PyObject* py_layer(PyUIGridObject* self, PyObject* args);
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
std::shared_ptr<std::list<std::shared_ptr<UIEntity>>> data;
|
||||
std::shared_ptr<UIGrid> grid;
|
||||
} PyUIEntityCollectionObject;
|
||||
|
||||
class UIEntityCollection {
|
||||
public:
|
||||
static PySequenceMethods sqmethods;
|
||||
static PyMappingMethods mpmethods;
|
||||
static PyObject* append(PyUIEntityCollectionObject* self, PyObject* o);
|
||||
static PyObject* extend(PyUIEntityCollectionObject* self, PyObject* o);
|
||||
static PyObject* remove(PyUIEntityCollectionObject* self, PyObject* o);
|
||||
static PyObject* pop(PyUIEntityCollectionObject* self, PyObject* args);
|
||||
static PyObject* insert(PyUIEntityCollectionObject* self, PyObject* args);
|
||||
static PyObject* index_method(PyUIEntityCollectionObject* self, PyObject* value);
|
||||
static PyObject* count(PyUIEntityCollectionObject* self, PyObject* value);
|
||||
static PyObject* find(PyUIEntityCollectionObject* self, PyObject* args, PyObject* kwds);
|
||||
static PyMethodDef methods[];
|
||||
static PyObject* repr(PyUIEntityCollectionObject* self);
|
||||
static int init(PyUIEntityCollectionObject* self, PyObject* args, PyObject* kwds);
|
||||
static PyObject* iter(PyUIEntityCollectionObject* self);
|
||||
static Py_ssize_t len(PyUIEntityCollectionObject* self);
|
||||
static PyObject* getitem(PyUIEntityCollectionObject* self, Py_ssize_t index);
|
||||
static int setitem(PyUIEntityCollectionObject* self, Py_ssize_t index, PyObject* value);
|
||||
static int contains(PyUIEntityCollectionObject* self, PyObject* value);
|
||||
static PyObject* concat(PyUIEntityCollectionObject* self, PyObject* other);
|
||||
static PyObject* inplace_concat(PyUIEntityCollectionObject* self, PyObject* other);
|
||||
static PyObject* subscript(PyUIEntityCollectionObject* self, PyObject* key);
|
||||
static int ass_subscript(PyUIEntityCollectionObject* self, PyObject* key, PyObject* value);
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
std::shared_ptr<std::list<std::shared_ptr<UIEntity>>> data;
|
||||
std::list<std::shared_ptr<UIEntity>>::iterator current; // Actual list iterator - O(1) increment
|
||||
std::list<std::shared_ptr<UIEntity>>::iterator end; // End iterator for bounds check
|
||||
int start_size; // For detecting modification during iteration
|
||||
} PyUIEntityCollectionIterObject;
|
||||
|
||||
class UIEntityCollectionIter {
|
||||
public:
|
||||
static int init(PyUIEntityCollectionIterObject* self, PyObject* args, PyObject* kwds);
|
||||
static PyObject* next(PyUIEntityCollectionIterObject* self);
|
||||
static PyObject* repr(PyUIEntityCollectionIterObject* self);
|
||||
static PyObject* getitem(PyUIEntityCollectionObject* self, Py_ssize_t index);
|
||||
|
||||
};
|
||||
// UIEntityCollection types are now in UIEntityCollection.h
|
||||
|
||||
// Forward declaration of methods array
|
||||
extern PyMethodDef UIGrid_all_methods[];
|
||||
|
|
@ -268,11 +224,8 @@ namespace mcrfpydef {
|
|||
obj->data.reset();
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
},
|
||||
//TODO - PyUIGrid REPR def:
|
||||
.tp_repr = (reprfunc)UIGrid::repr,
|
||||
//.tp_hash = NULL,
|
||||
//.tp_iter
|
||||
//.tp_iternext
|
||||
.tp_as_mapping = &UIGrid::mpmethods, // Enable grid[x, y] subscript access
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
|
||||
.tp_doc = PyDoc_STR("Grid(pos=None, size=None, grid_size=None, texture=None, **kwargs)\n\n"
|
||||
"A grid-based UI element for tile-based rendering and entity management.\n\n"
|
||||
|
|
@ -330,61 +283,6 @@ namespace mcrfpydef {
|
|||
}
|
||||
};
|
||||
|
||||
// #189 - Use inline instead of static to ensure single instance across translation units
|
||||
inline PyTypeObject PyUIEntityCollectionIterType = {
|
||||
.ob_base = {.ob_base = {.ob_refcnt = 1, .ob_type = NULL}, .ob_size = 0},
|
||||
.tp_name = "mcrfpy.UIEntityCollectionIter",
|
||||
.tp_basicsize = sizeof(PyUIEntityCollectionIterObject),
|
||||
.tp_itemsize = 0,
|
||||
.tp_dealloc = (destructor)[](PyObject* self)
|
||||
{
|
||||
PyUIEntityCollectionIterObject* obj = (PyUIEntityCollectionIterObject*)self;
|
||||
obj->data.reset();
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
},
|
||||
.tp_repr = (reprfunc)UIEntityCollectionIter::repr,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_doc = PyDoc_STR("Iterator for a collection of UI objects"),
|
||||
.tp_iter = PyObject_SelfIter,
|
||||
.tp_iternext = (iternextfunc)UIEntityCollectionIter::next,
|
||||
//.tp_getset = UIEntityCollection::getset,
|
||||
.tp_init = (initproc)UIEntityCollectionIter::init, // just raise an exception
|
||||
.tp_alloc = PyType_GenericAlloc,
|
||||
.tp_new = [](PyTypeObject* type, PyObject* args, PyObject* kwds) -> PyObject*
|
||||
{
|
||||
PyErr_SetString(PyExc_TypeError, "UICollection cannot be instantiated: a C++ data source is required.");
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
// #189 - Use inline instead of static to ensure single instance across translation units
|
||||
inline PyTypeObject PyUIEntityCollectionType = {
|
||||
.ob_base = {.ob_base = {.ob_refcnt = 1, .ob_type = NULL}, .ob_size = 0},
|
||||
.tp_name = "mcrfpy.EntityCollection",
|
||||
.tp_basicsize = sizeof(PyUIEntityCollectionObject),
|
||||
.tp_itemsize = 0,
|
||||
.tp_dealloc = (destructor)[](PyObject* self)
|
||||
{
|
||||
PyUIEntityCollectionObject* obj = (PyUIEntityCollectionObject*)self;
|
||||
obj->data.reset();
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
},
|
||||
.tp_repr = (reprfunc)UIEntityCollection::repr,
|
||||
.tp_as_sequence = &UIEntityCollection::sqmethods,
|
||||
.tp_as_mapping = &UIEntityCollection::mpmethods,
|
||||
.tp_flags = Py_TPFLAGS_DEFAULT,
|
||||
.tp_doc = PyDoc_STR("Iterable, indexable collection of Entities"),
|
||||
.tp_iter = (getiterfunc)UIEntityCollection::iter,
|
||||
.tp_methods = UIEntityCollection::methods, // append, remove
|
||||
//.tp_getset = UIEntityCollection::getset,
|
||||
.tp_init = (initproc)UIEntityCollection::init, // just raise an exception
|
||||
.tp_new = [](PyTypeObject* type, PyObject* args, PyObject* kwds) -> PyObject*
|
||||
{
|
||||
// Does PyUIEntityCollectionType need __new__ if it's not supposed to be instantiable by the user?
|
||||
// Should I just raise an exception? Or is the uninitialized shared_ptr enough of a blocker?
|
||||
PyErr_SetString(PyExc_TypeError, "EntityCollection cannot be instantiated: a C++ data source is required.");
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
// EntityCollection types moved to UIEntityCollection.h
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue