| // Protocol Buffers - Google's data interchange format | |
| // Copyright 2023 Google LLC. All rights reserved. | |
| // | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file or at | |
| // https://developers.google.com/open-source/licenses/bsd | |
| #include "python/descriptor_containers.h" | |
| #include "python/descriptor.h" | |
| #include "python/protobuf.h" | |
| #include "upb/reflection/def.h" | |
| // Must be last. | |
| #include "upb/port/def.inc" | |
| // Implements __repr__ as str(dict(self)). | |
| static PyObject* PyUpb_DescriptorMap_Repr(PyObject* _self) { | |
| PyObject* dict = PyDict_New(); | |
| PyObject* ret = NULL; | |
| if (!dict) goto err; | |
| if (PyDict_Merge(dict, _self, 1) != 0) goto err; | |
| ret = PyObject_Str(dict); | |
| err: | |
| Py_XDECREF(dict); | |
| return ret; | |
| } | |
| #define CHECK_TYPE(obj, state_member) \ | |
| assert(PyUpb_ModuleState_MaybeGet() == NULL || /* During shutdown. */ \ | |
| Py_TYPE(obj) == PyUpb_ModuleState_Get()->state_member) | |
| typedef enum { | |
| kPyUpb_CompareEqual, | |
| kPyUpb_CompareNotEqual, | |
| kPyUpb_CompareError, | |
| kPyUpb_CompareNotImplemented, | |
| } PyUpb_CompareResult; | |
| // ----------------------------------------------------------------------------- | |
| // ByNameIterator | |
| // ----------------------------------------------------------------------------- | |
| typedef struct { | |
| // clang-format off | |
| PyObject_HEAD | |
| const PyUpb_ByNameMap_Funcs* funcs; | |
| // clang-format on | |
| const void* parent; // upb_MessageDef*, upb_DefPool*, etc. | |
| PyObject* pool; // DescriptorPool instance, we own a ref. | |
| int index; // Current iterator index. | |
| } PyUpb_ByNameIterator; | |
| static PyUpb_ByNameIterator* PyUpb_ByNameIterator_Self(PyObject* obj) { | |
| CHECK_TYPE(obj, by_name_iterator_type); | |
| return (PyUpb_ByNameIterator*)obj; | |
| } | |
| static void PyUpb_ByNameIterator_Dealloc(PyObject* _self) { | |
| PyUpb_ByNameIterator* self = PyUpb_ByNameIterator_Self(_self); | |
| Py_DECREF(self->pool); | |
| PyUpb_Dealloc(self); | |
| } | |
| static PyObject* PyUpb_ByNameIterator_New(const PyUpb_ByNameMap_Funcs* funcs, | |
| const void* parent, PyObject* pool) { | |
| PyUpb_ModuleState* s = PyUpb_ModuleState_Get(); | |
| PyUpb_ByNameIterator* iter = | |
| (void*)PyType_GenericAlloc(s->by_name_iterator_type, 0); | |
| iter->funcs = funcs; | |
| iter->parent = parent; | |
| iter->pool = pool; | |
| iter->index = 0; | |
| Py_INCREF(iter->pool); | |
| return &iter->ob_base; | |
| } | |
| static PyObject* PyUpb_ByNameIterator_IterNext(PyObject* _self) { | |
| PyUpb_ByNameIterator* self = PyUpb_ByNameIterator_Self(_self); | |
| int size = self->funcs->base.get_elem_count(self->parent); | |
| if (self->index >= size) return NULL; | |
| const void* elem = self->funcs->base.index(self->parent, self->index); | |
| self->index++; | |
| return PyUnicode_FromString(self->funcs->get_elem_name(elem)); | |
| } | |
| static PyType_Slot PyUpb_ByNameIterator_Slots[] = { | |
| {Py_tp_dealloc, PyUpb_ByNameIterator_Dealloc}, | |
| {Py_tp_iter, PyObject_SelfIter}, | |
| {Py_tp_iternext, PyUpb_ByNameIterator_IterNext}, | |
| {0, NULL}}; | |
| static PyType_Spec PyUpb_ByNameIterator_Spec = { | |
| PYUPB_MODULE_NAME "._ByNameIterator", // tp_name | |
| sizeof(PyUpb_ByNameIterator), // tp_basicsize | |
| 0, // tp_itemsize | |
| Py_TPFLAGS_DEFAULT, // tp_flags | |
| PyUpb_ByNameIterator_Slots, | |
| }; | |
| // ----------------------------------------------------------------------------- | |
| // ByNumberIterator | |
| // ----------------------------------------------------------------------------- | |
| typedef struct { | |
| // clang-format off | |
| PyObject_HEAD | |
| const PyUpb_ByNumberMap_Funcs* funcs; | |
| // clang-format on | |
| const void* parent; // upb_MessageDef*, upb_DefPool*, etc. | |
| PyObject* pool; // DescriptorPool instance, we own a ref. | |
| int index; // Current iterator index. | |
| } PyUpb_ByNumberIterator; | |
| static PyUpb_ByNumberIterator* PyUpb_ByNumberIterator_Self(PyObject* obj) { | |
| CHECK_TYPE(obj, by_number_iterator_type); | |
| return (PyUpb_ByNumberIterator*)obj; | |
| } | |
| static void PyUpb_ByNumberIterator_Dealloc(PyObject* _self) { | |
| PyUpb_ByNumberIterator* self = PyUpb_ByNumberIterator_Self(_self); | |
| Py_DECREF(self->pool); | |
| PyUpb_Dealloc(self); | |
| } | |
| static PyObject* PyUpb_ByNumberIterator_New( | |
| const PyUpb_ByNumberMap_Funcs* funcs, const void* parent, PyObject* pool) { | |
| PyUpb_ModuleState* s = PyUpb_ModuleState_Get(); | |
| PyUpb_ByNumberIterator* iter = | |
| (void*)PyType_GenericAlloc(s->by_number_iterator_type, 0); | |
| iter->funcs = funcs; | |
| iter->parent = parent; | |
| iter->pool = pool; | |
| iter->index = 0; | |
| Py_INCREF(iter->pool); | |
| return &iter->ob_base; | |
| } | |
| static PyObject* PyUpb_ByNumberIterator_IterNext(PyObject* _self) { | |
| PyUpb_ByNumberIterator* self = PyUpb_ByNumberIterator_Self(_self); | |
| int size = self->funcs->base.get_elem_count(self->parent); | |
| if (self->index >= size) return NULL; | |
| const void* elem = self->funcs->base.index(self->parent, self->index); | |
| self->index++; | |
| return PyLong_FromLong(self->funcs->get_elem_num(elem)); | |
| } | |
| static PyType_Slot PyUpb_ByNumberIterator_Slots[] = { | |
| {Py_tp_dealloc, PyUpb_ByNumberIterator_Dealloc}, | |
| {Py_tp_iter, PyObject_SelfIter}, | |
| {Py_tp_iternext, PyUpb_ByNumberIterator_IterNext}, | |
| {0, NULL}}; | |
| static PyType_Spec PyUpb_ByNumberIterator_Spec = { | |
| PYUPB_MODULE_NAME "._ByNumberIterator", // tp_name | |
| sizeof(PyUpb_ByNumberIterator), // tp_basicsize | |
| 0, // tp_itemsize | |
| Py_TPFLAGS_DEFAULT, // tp_flags | |
| PyUpb_ByNumberIterator_Slots, | |
| }; | |
| // ----------------------------------------------------------------------------- | |
| // GenericSequence | |
| // ----------------------------------------------------------------------------- | |
| typedef struct { | |
| // clang-format off | |
| PyObject_HEAD | |
| const PyUpb_GenericSequence_Funcs* funcs; | |
| // clang-format on | |
| const void* parent; // upb_MessageDef*, upb_DefPool*, etc. | |
| PyObject* pool; // DescriptorPool instance, we own a ref. | |
| } PyUpb_GenericSequence; | |
| PyUpb_GenericSequence* PyUpb_GenericSequence_Self(PyObject* obj) { | |
| CHECK_TYPE(obj, generic_sequence_type); | |
| return (PyUpb_GenericSequence*)obj; | |
| } | |
| static void PyUpb_GenericSequence_Dealloc(PyObject* _self) { | |
| PyUpb_GenericSequence* self = PyUpb_GenericSequence_Self(_self); | |
| Py_CLEAR(self->pool); | |
| PyUpb_Dealloc(self); | |
| } | |
| PyObject* PyUpb_GenericSequence_New(const PyUpb_GenericSequence_Funcs* funcs, | |
| const void* parent, PyObject* pool) { | |
| PyUpb_ModuleState* s = PyUpb_ModuleState_Get(); | |
| PyUpb_GenericSequence* seq = | |
| (PyUpb_GenericSequence*)PyType_GenericAlloc(s->generic_sequence_type, 0); | |
| seq->funcs = funcs; | |
| seq->parent = parent; | |
| seq->pool = pool; | |
| Py_XINCREF(pool); | |
| return &seq->ob_base; | |
| } | |
| static Py_ssize_t PyUpb_GenericSequence_Length(PyObject* _self) { | |
| PyUpb_GenericSequence* self = PyUpb_GenericSequence_Self(_self); | |
| return self->funcs->get_elem_count(self->parent); | |
| } | |
| static PyObject* PyUpb_GenericSequence_GetItem(PyObject* _self, | |
| Py_ssize_t index) { | |
| PyUpb_GenericSequence* self = PyUpb_GenericSequence_Self(_self); | |
| Py_ssize_t size = self->funcs->get_elem_count(self->parent); | |
| if (index < 0) { | |
| index += size; | |
| } | |
| if (index < 0 || index >= size) { | |
| PyErr_Format(PyExc_IndexError, "list index (%zd) out of range", index); | |
| return NULL; | |
| } | |
| const void* elem = self->funcs->index(self->parent, index); | |
| return self->funcs->get_elem_wrapper(self->pool, elem); | |
| } | |
| // A sequence container can only be equal to another sequence container, or (for | |
| // backward compatibility) to a list containing the same items. | |
| static PyUpb_CompareResult PyUpb_GenericSequence_IsEqual( | |
| PyUpb_GenericSequence* self, PyObject* other) { | |
| // Check the identity of C++ pointers. | |
| if (PyObject_TypeCheck(other, Py_TYPE(self))) { | |
| PyUpb_GenericSequence* other_seq = (void*)other; | |
| if (self->parent == other_seq->parent && self->funcs == other_seq->funcs) { | |
| return kPyUpb_CompareEqual; | |
| } else { | |
| return kPyUpb_CompareNotEqual; | |
| } | |
| } | |
| if (!PyList_Check(other)) { | |
| return kPyUpb_CompareNotImplemented; | |
| } | |
| // return list(self) == other | |
| // We can clamp `i` to int because GenericSequence uses int for size (this | |
| // is useful when we do int iteration below). | |
| int n = PyUpb_GenericSequence_Length((PyObject*)self); | |
| if ((Py_ssize_t)n != PyList_Size(other)) { | |
| return kPyUpb_CompareNotEqual; | |
| } | |
| PyObject* item1; | |
| for (int i = 0; i < n; i++) { | |
| item1 = PyUpb_GenericSequence_GetItem((PyObject*)self, i); | |
| PyObject* item2 = PyList_GetItem(other, i); | |
| if (!item1 || !item2) goto error; | |
| int cmp = PyObject_RichCompareBool(item1, item2, Py_EQ); | |
| Py_DECREF(item1); | |
| if (cmp < 0) return kPyUpb_CompareError; | |
| if (cmp == 0) return kPyUpb_CompareNotEqual; | |
| } | |
| // All items were found and equal | |
| return kPyUpb_CompareEqual; | |
| error: | |
| Py_XDECREF(item1); | |
| return kPyUpb_CompareError; | |
| } | |
| static PyObject* PyUpb_GenericSequence_RichCompare(PyObject* _self, | |
| PyObject* other, int opid) { | |
| PyUpb_GenericSequence* self = PyUpb_GenericSequence_Self(_self); | |
| if (opid != Py_EQ && opid != Py_NE) { | |
| Py_RETURN_NOTIMPLEMENTED; | |
| } | |
| PyUpb_CompareResult eq = PyUpb_GenericSequence_IsEqual(self, other); | |
| switch (eq) { | |
| case kPyUpb_CompareNotImplemented: | |
| Py_RETURN_NOTIMPLEMENTED; | |
| case kPyUpb_CompareError: | |
| return NULL; | |
| case kPyUpb_CompareEqual: | |
| return PyBool_FromLong(opid == Py_EQ); | |
| case kPyUpb_CompareNotEqual: | |
| return PyBool_FromLong(opid == Py_NE); | |
| } | |
| return NULL; | |
| } | |
| static PyObject* PyUpb_GenericSequence_Subscript(PyObject* _self, | |
| PyObject* item) { | |
| PyUpb_GenericSequence* self = PyUpb_GenericSequence_Self(_self); | |
| Py_ssize_t size = self->funcs->get_elem_count(self->parent); | |
| Py_ssize_t idx, count, step; | |
| if (!PyUpb_IndexToRange(item, size, &idx, &count, &step)) return NULL; | |
| if (step == 0) { | |
| return PyUpb_GenericSequence_GetItem(_self, idx); | |
| } else { | |
| PyObject* list = PyList_New(count); | |
| for (Py_ssize_t i = 0; i < count; i++, idx += step) { | |
| const void* elem = self->funcs->index(self->parent, idx); | |
| PyList_SetItem(list, i, self->funcs->get_elem_wrapper(self->pool, elem)); | |
| } | |
| return list; | |
| } | |
| } | |
| // Linear search. Could optimize this in some cases (defs that have index), | |
| // but not all (FileDescriptor.dependencies). | |
| static int PyUpb_GenericSequence_Find(PyObject* _self, PyObject* item) { | |
| PyUpb_GenericSequence* self = PyUpb_GenericSequence_Self(_self); | |
| const void* item_ptr = PyUpb_AnyDescriptor_GetDef(item); | |
| int count = self->funcs->get_elem_count(self->parent); | |
| for (int i = 0; i < count; i++) { | |
| if (self->funcs->index(self->parent, i) == item_ptr) { | |
| return i; | |
| } | |
| } | |
| return -1; | |
| } | |
| static PyObject* PyUpb_GenericSequence_Index(PyObject* self, PyObject* item) { | |
| int position = PyUpb_GenericSequence_Find(self, item); | |
| if (position < 0) { | |
| PyErr_SetNone(PyExc_ValueError); | |
| return NULL; | |
| } else { | |
| return PyLong_FromLong(position); | |
| } | |
| } | |
| static PyObject* PyUpb_GenericSequence_Count(PyObject* _self, PyObject* item) { | |
| PyUpb_GenericSequence* self = PyUpb_GenericSequence_Self(_self); | |
| const void* item_ptr = PyUpb_AnyDescriptor_GetDef(item); | |
| int n = self->funcs->get_elem_count(self->parent); | |
| int count = 0; | |
| for (int i = 0; i < n; i++) { | |
| if (self->funcs->index(self->parent, i) == item_ptr) { | |
| count++; | |
| } | |
| } | |
| return PyLong_FromLong(count); | |
| } | |
| static PyObject* PyUpb_GenericSequence_Append(PyObject* self, PyObject* args) { | |
| PyErr_Format(PyExc_TypeError, "'%R' is not a mutable sequence", self); | |
| return NULL; | |
| } | |
| static PyMethodDef PyUpb_GenericSequence_Methods[] = { | |
| {"index", PyUpb_GenericSequence_Index, METH_O}, | |
| {"count", PyUpb_GenericSequence_Count, METH_O}, | |
| {"append", PyUpb_GenericSequence_Append, METH_O}, | |
| // This was implemented for Python/C++ but so far has not been required. | |
| //{ "__reversed__", (PyCFunction)Reversed, METH_NOARGS, }, | |
| {NULL}}; | |
| static PyType_Slot PyUpb_GenericSequence_Slots[] = { | |
| {Py_tp_dealloc, &PyUpb_GenericSequence_Dealloc}, | |
| {Py_tp_methods, &PyUpb_GenericSequence_Methods}, | |
| {Py_sq_length, PyUpb_GenericSequence_Length}, | |
| {Py_sq_item, PyUpb_GenericSequence_GetItem}, | |
| {Py_tp_richcompare, &PyUpb_GenericSequence_RichCompare}, | |
| {Py_mp_subscript, PyUpb_GenericSequence_Subscript}, | |
| // These were implemented for Python/C++ but so far have not been required. | |
| // {Py_tp_repr, &PyUpb_GenericSequence_Repr}, | |
| // {Py_sq_contains, PyUpb_GenericSequence_Contains}, | |
| // {Py_mp_ass_subscript, PyUpb_GenericSequence_AssignSubscript}, | |
| {0, NULL}, | |
| }; | |
| static PyType_Spec PyUpb_GenericSequence_Spec = { | |
| PYUPB_MODULE_NAME "._GenericSequence", // tp_name | |
| sizeof(PyUpb_GenericSequence), // tp_basicsize | |
| 0, // tp_itemsize | |
| Py_TPFLAGS_DEFAULT, // tp_flags | |
| PyUpb_GenericSequence_Slots, | |
| }; | |
| // ----------------------------------------------------------------------------- | |
| // ByNameMap | |
| // ----------------------------------------------------------------------------- | |
| typedef struct { | |
| // clang-format off | |
| PyObject_HEAD | |
| const PyUpb_ByNameMap_Funcs* funcs; | |
| // clang-format on | |
| const void* parent; // upb_MessageDef*, upb_DefPool*, etc. | |
| PyObject* pool; // DescriptorPool instance, we own a ref. | |
| } PyUpb_ByNameMap; | |
| PyUpb_ByNameMap* PyUpb_ByNameMap_Self(PyObject* obj) { | |
| CHECK_TYPE(obj, by_name_map_type); | |
| return (PyUpb_ByNameMap*)obj; | |
| } | |
| static void PyUpb_ByNameMap_Dealloc(PyObject* _self) { | |
| PyUpb_ByNameMap* self = PyUpb_ByNameMap_Self(_self); | |
| Py_CLEAR(self->pool); | |
| PyUpb_Dealloc(self); | |
| } | |
| PyObject* PyUpb_ByNameMap_New(const PyUpb_ByNameMap_Funcs* funcs, | |
| const void* parent, PyObject* pool) { | |
| PyUpb_ModuleState* s = PyUpb_ModuleState_Get(); | |
| PyUpb_ByNameMap* map = (void*)PyType_GenericAlloc(s->by_name_map_type, 0); | |
| map->funcs = funcs; | |
| map->parent = parent; | |
| map->pool = pool; | |
| Py_XINCREF(pool); | |
| return &map->ob_base; | |
| } | |
| static Py_ssize_t PyUpb_ByNameMap_Length(PyObject* _self) { | |
| PyUpb_ByNameMap* self = PyUpb_ByNameMap_Self(_self); | |
| return self->funcs->base.get_elem_count(self->parent); | |
| } | |
| static PyObject* PyUpb_ByNameMap_Subscript(PyObject* _self, PyObject* key) { | |
| PyUpb_ByNameMap* self = PyUpb_ByNameMap_Self(_self); | |
| const char* name = PyUpb_GetStrData(key); | |
| const void* elem = name ? self->funcs->lookup(self->parent, name) : NULL; | |
| if (!name && PyObject_Hash(key) == -1) return NULL; | |
| if (elem) { | |
| return self->funcs->base.get_elem_wrapper(self->pool, elem); | |
| } else { | |
| PyErr_SetObject(PyExc_KeyError, key); | |
| return NULL; | |
| } | |
| } | |
| static int PyUpb_ByNameMap_AssignSubscript(PyObject* self, PyObject* key, | |
| PyObject* value) { | |
| PyErr_Format(PyExc_TypeError, PYUPB_MODULE_NAME | |
| ".ByNameMap' object does not support item assignment"); | |
| return -1; | |
| } | |
| static int PyUpb_ByNameMap_Contains(PyObject* _self, PyObject* key) { | |
| PyUpb_ByNameMap* self = PyUpb_ByNameMap_Self(_self); | |
| const char* name = PyUpb_GetStrData(key); | |
| const void* elem = name ? self->funcs->lookup(self->parent, name) : NULL; | |
| if (!name && PyObject_Hash(key) == -1) return -1; | |
| return elem ? 1 : 0; | |
| } | |
| static PyObject* PyUpb_ByNameMap_Get(PyObject* _self, PyObject* args) { | |
| PyUpb_ByNameMap* self = PyUpb_ByNameMap_Self(_self); | |
| PyObject* key; | |
| PyObject* default_value = Py_None; | |
| if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &default_value)) { | |
| return NULL; | |
| } | |
| const char* name = PyUpb_GetStrData(key); | |
| const void* elem = name ? self->funcs->lookup(self->parent, name) : NULL; | |
| if (!name && PyObject_Hash(key) == -1) return NULL; | |
| if (elem) { | |
| PyObject* pool = self->pool; | |
| return self->funcs->base.get_elem_wrapper(pool, elem); | |
| } else { | |
| Py_INCREF(default_value); | |
| return default_value; | |
| } | |
| } | |
| static PyObject* PyUpb_ByNameMap_GetIter(PyObject* _self) { | |
| PyUpb_ByNameMap* self = PyUpb_ByNameMap_Self(_self); | |
| return PyUpb_ByNameIterator_New(self->funcs, self->parent, self->pool); | |
| } | |
| static PyObject* PyUpb_ByNameMap_Keys(PyObject* _self, PyObject* args) { | |
| PyUpb_ByNameMap* self = PyUpb_ByNameMap_Self(_self); | |
| int n = self->funcs->base.get_elem_count(self->parent); | |
| PyObject* ret = PyList_New(n); | |
| if (!ret) return NULL; | |
| for (int i = 0; i < n; i++) { | |
| const void* elem = self->funcs->base.index(self->parent, i); | |
| PyObject* key = PyUnicode_FromString(self->funcs->get_elem_name(elem)); | |
| if (!key) goto error; | |
| PyList_SetItem(ret, i, key); | |
| } | |
| return ret; | |
| error: | |
| Py_XDECREF(ret); | |
| return NULL; | |
| } | |
| static PyObject* PyUpb_ByNameMap_Values(PyObject* _self, PyObject* args) { | |
| PyUpb_ByNameMap* self = PyUpb_ByNameMap_Self(_self); | |
| int n = self->funcs->base.get_elem_count(self->parent); | |
| PyObject* ret = PyList_New(n); | |
| if (!ret) return NULL; | |
| PyObject* pool = self->pool; | |
| for (int i = 0; i < n; i++) { | |
| const void* elem = self->funcs->base.index(self->parent, i); | |
| PyObject* py_elem = self->funcs->base.get_elem_wrapper(pool, elem); | |
| if (!py_elem) goto error; | |
| PyList_SetItem(ret, i, py_elem); | |
| } | |
| return ret; | |
| error: | |
| Py_XDECREF(ret); | |
| return NULL; | |
| } | |
| static PyObject* PyUpb_ByNameMap_Items(PyObject* _self, PyObject* args) { | |
| PyUpb_ByNameMap* self = (PyUpb_ByNameMap*)_self; | |
| int n = self->funcs->base.get_elem_count(self->parent); | |
| PyObject* ret = PyList_New(n); | |
| PyObject* item; | |
| PyObject* py_elem; | |
| if (!ret) return NULL; | |
| PyObject* pool = self->pool; | |
| for (int i = 0; i < n; i++) { | |
| const void* elem = self->funcs->base.index(self->parent, i); | |
| item = PyTuple_New(2); | |
| py_elem = self->funcs->base.get_elem_wrapper(pool, elem); | |
| if (!item || !py_elem) goto error; | |
| PyTuple_SetItem(item, 0, | |
| PyUnicode_FromString(self->funcs->get_elem_name(elem))); | |
| PyTuple_SetItem(item, 1, py_elem); | |
| PyList_SetItem(ret, i, item); | |
| } | |
| return ret; | |
| error: | |
| Py_XDECREF(py_elem); | |
| Py_XDECREF(item); | |
| Py_XDECREF(ret); | |
| return NULL; | |
| } | |
| // A mapping container can only be equal to another mapping container, or (for | |
| // backward compatibility) to a dict containing the same items. | |
| static PyUpb_CompareResult PyUpb_ByNameMap_IsEqual(PyUpb_ByNameMap* self, | |
| PyObject* other) { | |
| // Check the identity of C++ pointers. | |
| if (PyObject_TypeCheck(other, Py_TYPE(self))) { | |
| PyUpb_ByNameMap* other_map = (void*)other; | |
| if (self->parent == other_map->parent && self->funcs == other_map->funcs) { | |
| return kPyUpb_CompareEqual; | |
| } else { | |
| return kPyUpb_CompareNotEqual; | |
| } | |
| } | |
| if (!PyDict_Check(other)) { | |
| return kPyUpb_CompareNotImplemented; | |
| } | |
| PyObject* self_dict = PyDict_New(); | |
| if (PyDict_Merge(self_dict, (PyObject*)self, 0) < 0) { | |
| Py_DECREF(self_dict); | |
| return kPyUpb_CompareError; | |
| } | |
| int eq = PyObject_RichCompareBool(self_dict, other, Py_EQ); | |
| Py_DECREF(self_dict); | |
| if (eq < 0) return kPyUpb_CompareError; | |
| if (eq == 0) return kPyUpb_CompareNotEqual; | |
| return kPyUpb_CompareEqual; | |
| } | |
| static PyObject* PyUpb_ByNameMap_RichCompare(PyObject* _self, PyObject* other, | |
| int opid) { | |
| PyUpb_ByNameMap* self = PyUpb_ByNameMap_Self(_self); | |
| if (opid != Py_EQ && opid != Py_NE) { | |
| Py_RETURN_NOTIMPLEMENTED; | |
| } | |
| PyUpb_CompareResult eq = PyUpb_ByNameMap_IsEqual(self, other); | |
| switch (eq) { | |
| case kPyUpb_CompareNotImplemented: | |
| Py_RETURN_NOTIMPLEMENTED; | |
| case kPyUpb_CompareError: | |
| return NULL; | |
| case kPyUpb_CompareEqual: | |
| return PyBool_FromLong(opid == Py_EQ); | |
| case kPyUpb_CompareNotEqual: | |
| return PyBool_FromLong(opid == Py_NE); | |
| } | |
| return NULL; | |
| } | |
| static PyMethodDef PyUpb_ByNameMap_Methods[] = { | |
| {"get", (PyCFunction)&PyUpb_ByNameMap_Get, METH_VARARGS}, | |
| {"keys", PyUpb_ByNameMap_Keys, METH_NOARGS}, | |
| {"values", PyUpb_ByNameMap_Values, METH_NOARGS}, | |
| {"items", PyUpb_ByNameMap_Items, METH_NOARGS}, | |
| {NULL}}; | |
| static PyType_Slot PyUpb_ByNameMap_Slots[] = { | |
| {Py_mp_ass_subscript, PyUpb_ByNameMap_AssignSubscript}, | |
| {Py_mp_length, PyUpb_ByNameMap_Length}, | |
| {Py_mp_subscript, PyUpb_ByNameMap_Subscript}, | |
| {Py_sq_contains, &PyUpb_ByNameMap_Contains}, | |
| {Py_tp_dealloc, &PyUpb_ByNameMap_Dealloc}, | |
| {Py_tp_iter, PyUpb_ByNameMap_GetIter}, | |
| {Py_tp_methods, &PyUpb_ByNameMap_Methods}, | |
| {Py_tp_repr, &PyUpb_DescriptorMap_Repr}, | |
| {Py_tp_richcompare, &PyUpb_ByNameMap_RichCompare}, | |
| {0, NULL}, | |
| }; | |
| static PyType_Spec PyUpb_ByNameMap_Spec = { | |
| PYUPB_MODULE_NAME "._ByNameMap", // tp_name | |
| sizeof(PyUpb_ByNameMap), // tp_basicsize | |
| 0, // tp_itemsize | |
| Py_TPFLAGS_DEFAULT, // tp_flags | |
| PyUpb_ByNameMap_Slots, | |
| }; | |
| // ----------------------------------------------------------------------------- | |
| // ByNumberMap | |
| // ----------------------------------------------------------------------------- | |
| typedef struct { | |
| // clang-format off | |
| PyObject_HEAD | |
| const PyUpb_ByNumberMap_Funcs* funcs; | |
| // clang-format on | |
| const void* parent; // upb_MessageDef*, upb_DefPool*, etc. | |
| PyObject* pool; // DescriptorPool instance, we own a ref. | |
| } PyUpb_ByNumberMap; | |
| PyUpb_ByNumberMap* PyUpb_ByNumberMap_Self(PyObject* obj) { | |
| CHECK_TYPE(obj, by_number_map_type); | |
| return (PyUpb_ByNumberMap*)obj; | |
| } | |
| PyObject* PyUpb_ByNumberMap_New(const PyUpb_ByNumberMap_Funcs* funcs, | |
| const void* parent, PyObject* pool) { | |
| PyUpb_ModuleState* s = PyUpb_ModuleState_Get(); | |
| PyUpb_ByNumberMap* map = (void*)PyType_GenericAlloc(s->by_number_map_type, 0); | |
| map->funcs = funcs; | |
| map->parent = parent; | |
| map->pool = pool; | |
| Py_INCREF(pool); | |
| return &map->ob_base; | |
| } | |
| static void PyUpb_ByNumberMap_Dealloc(PyObject* _self) { | |
| PyUpb_ByNumberMap* self = PyUpb_ByNumberMap_Self(_self); | |
| Py_DECREF(self->pool); | |
| PyUpb_Dealloc(self); | |
| } | |
| static Py_ssize_t PyUpb_ByNumberMap_Length(PyObject* _self) { | |
| PyUpb_ByNumberMap* self = PyUpb_ByNumberMap_Self(_self); | |
| return self->funcs->base.get_elem_count(self->parent); | |
| } | |
| static const void* PyUpb_ByNumberMap_LookupHelper(PyUpb_ByNumberMap* self, | |
| PyObject* key) { | |
| long num = PyLong_AsLong(key); | |
| if (num == -1 && PyErr_Occurred()) { | |
| PyErr_Clear(); | |
| // Ensure that the key is hashable (this will raise an error if not). | |
| PyObject_Hash(key); | |
| return NULL; | |
| } else { | |
| return self->funcs->lookup(self->parent, num); | |
| } | |
| } | |
| static PyObject* PyUpb_ByNumberMap_Subscript(PyObject* _self, PyObject* key) { | |
| PyUpb_ByNumberMap* self = PyUpb_ByNumberMap_Self(_self); | |
| const void* elem = PyUpb_ByNumberMap_LookupHelper(self, key); | |
| if (elem) { | |
| return self->funcs->base.get_elem_wrapper(self->pool, elem); | |
| } else { | |
| if (!PyErr_Occurred()) { | |
| PyErr_SetObject(PyExc_KeyError, key); | |
| } | |
| return NULL; | |
| } | |
| } | |
| static int PyUpb_ByNumberMap_AssignSubscript(PyObject* self, PyObject* key, | |
| PyObject* value) { | |
| PyErr_Format(PyExc_TypeError, PYUPB_MODULE_NAME | |
| ".ByNumberMap' object does not support item assignment"); | |
| return -1; | |
| } | |
| static PyObject* PyUpb_ByNumberMap_Get(PyObject* _self, PyObject* args) { | |
| PyUpb_ByNumberMap* self = PyUpb_ByNumberMap_Self(_self); | |
| PyObject* key; | |
| PyObject* default_value = Py_None; | |
| if (!PyArg_UnpackTuple(args, "get", 1, 2, &key, &default_value)) { | |
| return NULL; | |
| } | |
| const void* elem = PyUpb_ByNumberMap_LookupHelper(self, key); | |
| if (elem) { | |
| return self->funcs->base.get_elem_wrapper(self->pool, elem); | |
| } else if (PyErr_Occurred()) { | |
| return NULL; | |
| } else { | |
| return PyUpb_NewRef(default_value); | |
| } | |
| } | |
| static PyObject* PyUpb_ByNumberMap_GetIter(PyObject* _self) { | |
| PyUpb_ByNumberMap* self = PyUpb_ByNumberMap_Self(_self); | |
| return PyUpb_ByNumberIterator_New(self->funcs, self->parent, self->pool); | |
| } | |
| static PyObject* PyUpb_ByNumberMap_Keys(PyObject* _self, PyObject* args) { | |
| PyUpb_ByNumberMap* self = PyUpb_ByNumberMap_Self(_self); | |
| int n = self->funcs->base.get_elem_count(self->parent); | |
| PyObject* ret = PyList_New(n); | |
| if (!ret) return NULL; | |
| for (int i = 0; i < n; i++) { | |
| const void* elem = self->funcs->base.index(self->parent, i); | |
| PyObject* key = PyLong_FromLong(self->funcs->get_elem_num(elem)); | |
| if (!key) goto error; | |
| PyList_SetItem(ret, i, key); | |
| } | |
| return ret; | |
| error: | |
| Py_XDECREF(ret); | |
| return NULL; | |
| } | |
| static PyObject* PyUpb_ByNumberMap_Values(PyObject* _self, PyObject* args) { | |
| PyUpb_ByNumberMap* self = PyUpb_ByNumberMap_Self(_self); | |
| int n = self->funcs->base.get_elem_count(self->parent); | |
| PyObject* ret = PyList_New(n); | |
| if (!ret) return NULL; | |
| for (int i = 0; i < n; i++) { | |
| const void* elem = self->funcs->base.index(self->parent, i); | |
| PyObject* py_elem = self->funcs->base.get_elem_wrapper(self->pool, elem); | |
| if (!py_elem) goto error; | |
| PyList_SetItem(ret, i, py_elem); | |
| } | |
| return ret; | |
| error: | |
| Py_XDECREF(ret); | |
| return NULL; | |
| } | |
| static PyObject* PyUpb_ByNumberMap_Items(PyObject* _self, PyObject* args) { | |
| PyUpb_ByNumberMap* self = PyUpb_ByNumberMap_Self(_self); | |
| int n = self->funcs->base.get_elem_count(self->parent); | |
| PyObject* ret = PyList_New(n); | |
| PyObject* item; | |
| PyObject* py_elem; | |
| if (!ret) return NULL; | |
| for (int i = 0; i < n; i++) { | |
| const void* elem = self->funcs->base.index(self->parent, i); | |
| int number = self->funcs->get_elem_num(elem); | |
| item = PyTuple_New(2); | |
| py_elem = self->funcs->base.get_elem_wrapper(self->pool, elem); | |
| if (!item || !py_elem) goto error; | |
| PyTuple_SetItem(item, 0, PyLong_FromLong(number)); | |
| PyTuple_SetItem(item, 1, py_elem); | |
| PyList_SetItem(ret, i, item); | |
| } | |
| return ret; | |
| error: | |
| Py_XDECREF(py_elem); | |
| Py_XDECREF(item); | |
| Py_XDECREF(ret); | |
| return NULL; | |
| } | |
| static int PyUpb_ByNumberMap_Contains(PyObject* _self, PyObject* key) { | |
| PyUpb_ByNumberMap* self = PyUpb_ByNumberMap_Self(_self); | |
| const void* elem = PyUpb_ByNumberMap_LookupHelper(self, key); | |
| if (elem) return 1; | |
| if (PyErr_Occurred()) return -1; | |
| return 0; | |
| } | |
| // A mapping container can only be equal to another mapping container, or (for | |
| // backward compatibility) to a dict containing the same items. | |
| static PyUpb_CompareResult PyUpb_ByNumberMap_IsEqual(PyUpb_ByNumberMap* self, | |
| PyObject* other) { | |
| // Check the identity of C++ pointers. | |
| if (PyObject_TypeCheck(other, Py_TYPE(self))) { | |
| PyUpb_ByNumberMap* other_map = (void*)other; | |
| if (self->parent == other_map->parent && self->funcs == other_map->funcs) { | |
| return kPyUpb_CompareEqual; | |
| } else { | |
| return kPyUpb_CompareNotEqual; | |
| } | |
| } | |
| if (!PyDict_Check(other)) { | |
| return kPyUpb_CompareNotImplemented; | |
| } | |
| PyObject* self_dict = PyDict_New(); | |
| if (PyDict_Merge(self_dict, (PyObject*)self, 0) < 0) { | |
| Py_DECREF(self_dict); | |
| return kPyUpb_CompareError; | |
| } | |
| int eq = PyObject_RichCompareBool(self_dict, other, Py_EQ); | |
| Py_DECREF(self_dict); | |
| if (eq < 0) return kPyUpb_CompareError; | |
| if (eq == 0) return kPyUpb_CompareNotEqual; | |
| return kPyUpb_CompareEqual; | |
| } | |
| static PyObject* PyUpb_ByNumberMap_RichCompare(PyObject* _self, PyObject* other, | |
| int opid) { | |
| PyUpb_ByNumberMap* self = PyUpb_ByNumberMap_Self(_self); | |
| if (opid != Py_EQ && opid != Py_NE) { | |
| Py_RETURN_NOTIMPLEMENTED; | |
| } | |
| PyUpb_CompareResult eq = PyUpb_ByNumberMap_IsEqual(self, other); | |
| switch (eq) { | |
| case kPyUpb_CompareNotImplemented: | |
| Py_RETURN_NOTIMPLEMENTED; | |
| case kPyUpb_CompareError: | |
| return NULL; | |
| case kPyUpb_CompareEqual: | |
| return PyBool_FromLong(opid == Py_EQ); | |
| case kPyUpb_CompareNotEqual: | |
| return PyBool_FromLong(opid == Py_NE); | |
| } | |
| return NULL; | |
| } | |
| static PyMethodDef PyUpb_ByNumberMap_Methods[] = { | |
| {"get", (PyCFunction)&PyUpb_ByNumberMap_Get, METH_VARARGS}, | |
| {"keys", PyUpb_ByNumberMap_Keys, METH_NOARGS}, | |
| {"values", PyUpb_ByNumberMap_Values, METH_NOARGS}, | |
| {"items", PyUpb_ByNumberMap_Items, METH_NOARGS}, | |
| {NULL}}; | |
| static PyType_Slot PyUpb_ByNumberMap_Slots[] = { | |
| {Py_mp_ass_subscript, PyUpb_ByNumberMap_AssignSubscript}, | |
| {Py_mp_length, PyUpb_ByNumberMap_Length}, | |
| {Py_mp_subscript, PyUpb_ByNumberMap_Subscript}, | |
| {Py_sq_contains, &PyUpb_ByNumberMap_Contains}, | |
| {Py_tp_dealloc, &PyUpb_ByNumberMap_Dealloc}, | |
| {Py_tp_iter, PyUpb_ByNumberMap_GetIter}, | |
| {Py_tp_methods, &PyUpb_ByNumberMap_Methods}, | |
| {Py_tp_repr, &PyUpb_DescriptorMap_Repr}, | |
| {Py_tp_richcompare, &PyUpb_ByNumberMap_RichCompare}, | |
| {0, NULL}, | |
| }; | |
| static PyType_Spec PyUpb_ByNumberMap_Spec = { | |
| PYUPB_MODULE_NAME "._ByNumberMap", // tp_name | |
| sizeof(PyUpb_ByNumberMap), // tp_basicsize | |
| 0, // tp_itemsize | |
| Py_TPFLAGS_DEFAULT, // tp_flags | |
| PyUpb_ByNumberMap_Slots, | |
| }; | |
| // ----------------------------------------------------------------------------- | |
| // Top Level | |
| // ----------------------------------------------------------------------------- | |
| bool PyUpb_InitDescriptorContainers(PyObject* m) { | |
| PyUpb_ModuleState* s = PyUpb_ModuleState_GetFromModule(m); | |
| s->by_name_map_type = PyUpb_AddClass(m, &PyUpb_ByNameMap_Spec); | |
| s->by_number_map_type = PyUpb_AddClass(m, &PyUpb_ByNumberMap_Spec); | |
| s->by_name_iterator_type = PyUpb_AddClass(m, &PyUpb_ByNameIterator_Spec); | |
| s->by_number_iterator_type = PyUpb_AddClass(m, &PyUpb_ByNumberIterator_Spec); | |
| s->generic_sequence_type = PyUpb_AddClass(m, &PyUpb_GenericSequence_Spec); | |
| return s->by_name_map_type && s->by_number_map_type && | |
| s->by_name_iterator_type && s->by_number_iterator_type && | |
| s->generic_sequence_type; | |
| } | |
| #include "upb/port/undef.inc" |