| // 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 | |
| #ifndef PYUPB_FREE_THREADING_WEAK_MAP_H_ | |
| #define PYUPB_FREE_THREADING_WEAK_MAP_H_ | |
| // clang-format off | |
| #include "Python.h" | |
| // clang-format on | |
| #include <stdbool.h> | |
| #include <stdint.h> | |
| #include "python/free_threading/mutex.h" | |
| #include "upb/hash/int_table.h" | |
| // A WeakMap maps C pointers to the corresponding Python wrapper object. We | |
| // want a consistent Python wrapper object for each C object, both to save | |
| // memory and to provide object stability (ie. x is x). | |
| // | |
| // Each wrapped object should add itself to the map when it is constructed and | |
| // remove itself from the map when it is destroyed. The map is weak so it does | |
| // not take references to the cached objects. | |
| struct PyUpb_WeakMap; | |
| typedef struct PyUpb_WeakMap PyUpb_WeakMap; | |
| PyUpb_WeakMap* PyUpb_WeakMap_New(void); | |
| void PyUpb_WeakMap_Free(PyUpb_WeakMap* map); | |
| // Returns the number of entries in the map. | |
| size_t PyUpb_WeakMap_Count(PyUpb_WeakMap* map); | |
| // Adds the given object to the map, indexed by the given key. | |
| // If key is already present in the map, py_obj is DECREF'd and replaced with | |
| // the existing object. | |
| // | |
| // If memory allocation fails, returns false and does not modify the map. | |
| bool PyUpb_WeakMap_Add(PyUpb_WeakMap* map, const void* key, PyObject** obj); | |
| // Adds the given object to the map, indexed by the given key. | |
| // The key must not already be present in the map. | |
| // | |
| // If memory allocation fails, returns false and does not modify the map. | |
| bool PyUpb_WeakMap_UniqueAdd(PyUpb_WeakMap* map, const void* key, | |
| PyObject* obj); | |
| // Removes the given key from the cache. It must exist in the cache currently. | |
| void PyUpb_WeakMap_Erase(PyUpb_WeakMap* map, const void* key, PyObject* obj); | |
| // Removes the entry from the cache, but only if it matches the given value. | |
| // Returns true if the entry was found and removed. | |
| bool PyUpb_WeakMap_EraseIfEqual(PyUpb_WeakMap* map, const void* key, | |
| PyObject* obj); | |
| // Returns a new reference to an object if it exists, otherwise returns NULL. | |
| PyObject* PyUpb_WeakMap_Get(PyUpb_WeakMap* map, const void* key); | |
| typedef struct { | |
| PyUpb_WeakMap* map; | |
| intptr_t iter; | |
| #ifdef Py_GIL_DISABLED | |
| PyObject** deferred_decrefs; | |
| size_t count; | |
| size_t cap; | |
| #endif | |
| } PyUpb_WeakMapIter; | |
| // Iteration lifecycle: Begin locks map->mutex; End releases map->mutex and | |
| // decrefs any objects visited during iteration. Returns false and sets | |
| // MemoryError on allocation failure (leaving map->mutex unlocked). | |
| bool PyUpb_WeakMapIter_Begin(PyUpb_WeakMapIter* iter, PyUpb_WeakMap* map); | |
| bool PyUpb_WeakMapIter_Next(PyUpb_WeakMapIter* iter, const void** key, | |
| PyObject** obj); | |
| void PyUpb_WeakMapIter_Delete(PyUpb_WeakMapIter* iter); | |
| void PyUpb_WeakMapIter_End(PyUpb_WeakMapIter* iter); | |
| #endif // PYUPB_FREE_THREADING_WEAK_MAP_H_ |