mirror of
https://github.com/johndoe6345789/typthon.git
synced 2026-04-24 13:45:05 +00:00
Massive automated renaming of all Py_/PyObject/etc. prefixes to Ty_/TyObject/etc. This includes: - All public API types (TyObject, TyTypeObject, etc.) - All public API functions (Ty_Initialize, Ty_BuildValue, etc.) - All internal API (_Ty_ prefixes) - Reference counting macros (Ty_INCREF, Ty_DECREF, etc.) - Type flags (Ty_TPFLAGS_*) - Debug flags (Ty_DEBUG, Ty_TRACE_REFS, etc.) - All object type APIs (TyList_, TyDict_, TyUnicode_, etc.) This changes over 60,000 occurrences across 1000+ files. Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
198 lines
4.6 KiB
C
198 lines
4.6 KiB
C
#include "Python.h"
|
|
|
|
#include "pycore_index_pool.h"
|
|
#include "pycore_lock.h"
|
|
|
|
#include <stdbool.h>
|
|
|
|
#ifdef Ty_GIL_DISABLED
|
|
|
|
static inline void
|
|
swap(int32_t *values, Ty_ssize_t i, Ty_ssize_t j)
|
|
{
|
|
int32_t tmp = values[i];
|
|
values[i] = values[j];
|
|
values[j] = tmp;
|
|
}
|
|
|
|
static bool
|
|
heap_try_swap(_PyIndexHeap *heap, Ty_ssize_t i, Ty_ssize_t j)
|
|
{
|
|
if (i < 0 || i >= heap->size) {
|
|
return 0;
|
|
}
|
|
if (j < 0 || j >= heap->size) {
|
|
return 0;
|
|
}
|
|
if (i <= j) {
|
|
if (heap->values[i] <= heap->values[j]) {
|
|
return 0;
|
|
}
|
|
}
|
|
else if (heap->values[j] <= heap->values[i]) {
|
|
return 0;
|
|
}
|
|
swap(heap->values, i, j);
|
|
return 1;
|
|
}
|
|
|
|
static inline Ty_ssize_t
|
|
parent(Ty_ssize_t i)
|
|
{
|
|
return (i - 1) / 2;
|
|
}
|
|
|
|
static inline Ty_ssize_t
|
|
left_child(Ty_ssize_t i)
|
|
{
|
|
return 2 * i + 1;
|
|
}
|
|
|
|
static inline Ty_ssize_t
|
|
right_child(Ty_ssize_t i)
|
|
{
|
|
return 2 * i + 2;
|
|
}
|
|
|
|
static void
|
|
heap_add(_PyIndexHeap *heap, int32_t val)
|
|
{
|
|
assert(heap->size < heap->capacity);
|
|
// Add val to end
|
|
heap->values[heap->size] = val;
|
|
heap->size++;
|
|
// Sift up
|
|
for (Ty_ssize_t cur = heap->size - 1; cur > 0; cur = parent(cur)) {
|
|
if (!heap_try_swap(heap, cur, parent(cur))) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static Ty_ssize_t
|
|
heap_min_child(_PyIndexHeap *heap, Ty_ssize_t i)
|
|
{
|
|
if (left_child(i) < heap->size) {
|
|
if (right_child(i) < heap->size) {
|
|
Ty_ssize_t lval = heap->values[left_child(i)];
|
|
Ty_ssize_t rval = heap->values[right_child(i)];
|
|
return lval < rval ? left_child(i) : right_child(i);
|
|
}
|
|
return left_child(i);
|
|
}
|
|
else if (right_child(i) < heap->size) {
|
|
return right_child(i);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int32_t
|
|
heap_pop(_PyIndexHeap *heap)
|
|
{
|
|
assert(heap->size > 0);
|
|
// Pop smallest and replace with the last element
|
|
int32_t result = heap->values[0];
|
|
heap->values[0] = heap->values[heap->size - 1];
|
|
heap->size--;
|
|
// Sift down
|
|
for (Ty_ssize_t cur = 0; cur < heap->size;) {
|
|
Ty_ssize_t min_child = heap_min_child(heap, cur);
|
|
if (min_child > -1 && heap_try_swap(heap, cur, min_child)) {
|
|
cur = min_child;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static int
|
|
heap_ensure_capacity(_PyIndexHeap *heap, Ty_ssize_t limit)
|
|
{
|
|
assert(limit > 0);
|
|
if (heap->capacity > limit) {
|
|
return 0;
|
|
}
|
|
Ty_ssize_t new_capacity = heap->capacity ? heap->capacity : 1024;
|
|
while (new_capacity && new_capacity < limit) {
|
|
new_capacity <<= 1;
|
|
}
|
|
if (!new_capacity) {
|
|
return -1;
|
|
}
|
|
int32_t *new_values = TyMem_RawCalloc(new_capacity, sizeof(int32_t));
|
|
if (new_values == NULL) {
|
|
return -1;
|
|
}
|
|
if (heap->values != NULL) {
|
|
memcpy(new_values, heap->values, heap->capacity);
|
|
TyMem_RawFree(heap->values);
|
|
}
|
|
heap->values = new_values;
|
|
heap->capacity = new_capacity;
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
heap_fini(_PyIndexHeap *heap)
|
|
{
|
|
if (heap->values != NULL) {
|
|
TyMem_RawFree(heap->values);
|
|
heap->values = NULL;
|
|
}
|
|
heap->size = -1;
|
|
heap->capacity = -1;
|
|
}
|
|
|
|
#define LOCK_POOL(pool) PyMutex_LockFlags(&pool->mutex, _Ty_LOCK_DONT_DETACH)
|
|
#define UNLOCK_POOL(pool) PyMutex_Unlock(&pool->mutex)
|
|
|
|
int32_t
|
|
_PyIndexPool_AllocIndex(_PyIndexPool *pool)
|
|
{
|
|
LOCK_POOL(pool);
|
|
int32_t index;
|
|
_PyIndexHeap *free_indices = &pool->free_indices;
|
|
if (free_indices->size == 0) {
|
|
// No free indices. Make sure the heap can always store all of the
|
|
// indices that have been allocated to avoid having to allocate memory
|
|
// (which can fail) when freeing an index. Freeing indices happens when
|
|
// threads are being destroyed, which makes error handling awkward /
|
|
// impossible. This arrangement shifts handling of allocation failures
|
|
// to when indices are allocated, which happens at thread creation,
|
|
// where we are better equipped to deal with failure.
|
|
if (heap_ensure_capacity(free_indices, pool->next_index + 1) < 0) {
|
|
UNLOCK_POOL(pool);
|
|
TyErr_NoMemory();
|
|
return -1;
|
|
}
|
|
index = pool->next_index++;
|
|
}
|
|
else {
|
|
index = heap_pop(free_indices);
|
|
}
|
|
|
|
pool->tlbc_generation++;
|
|
|
|
UNLOCK_POOL(pool);
|
|
return index;
|
|
}
|
|
|
|
void
|
|
_PyIndexPool_FreeIndex(_PyIndexPool *pool, int32_t index)
|
|
{
|
|
LOCK_POOL(pool);
|
|
pool->tlbc_generation++;
|
|
heap_add(&pool->free_indices, index);
|
|
UNLOCK_POOL(pool);
|
|
}
|
|
|
|
void
|
|
_PyIndexPool_Fini(_PyIndexPool *pool)
|
|
{
|
|
heap_fini(&pool->free_indices);
|
|
}
|
|
|
|
#endif // Ty_GIL_DISABLED
|