mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	 214562ed4d
			
		
	
	
		214562ed4d
		
			
		
	
	
	
	
		
			
			Move some `#include <stdbool.h>` after `#include "Python.h"` when `pyconfig.h` is not included first and when we are in a platform-agnostic context. This is to avoid having features defined by `stdbool.h` before those decided by `Python.h`.
		
			
				
	
	
		
			193 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			193 lines
		
	
	
	
		
			4.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "Python.h"
 | |
| 
 | |
| #include "pycore_index_pool.h"
 | |
| #include "pycore_lock.h"
 | |
| 
 | |
| #include <stdbool.h>
 | |
| 
 | |
| #ifdef Py_GIL_DISABLED
 | |
| 
 | |
| static inline void
 | |
| swap(int32_t *values, Py_ssize_t i, Py_ssize_t j)
 | |
| {
 | |
|     int32_t tmp = values[i];
 | |
|     values[i] = values[j];
 | |
|     values[j] = tmp;
 | |
| }
 | |
| 
 | |
| static bool
 | |
| heap_try_swap(_PyIndexHeap *heap, Py_ssize_t i, Py_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 Py_ssize_t
 | |
| parent(Py_ssize_t i)
 | |
| {
 | |
|     return (i - 1) / 2;
 | |
| }
 | |
| 
 | |
| static inline Py_ssize_t
 | |
| left_child(Py_ssize_t i)
 | |
| {
 | |
|     return 2 * i + 1;
 | |
| }
 | |
| 
 | |
| static inline Py_ssize_t
 | |
| right_child(Py_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 (Py_ssize_t cur = heap->size - 1; cur > 0; cur = parent(cur)) {
 | |
|         if (!heap_try_swap(heap, cur, parent(cur))) {
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| static Py_ssize_t
 | |
| heap_min_child(_PyIndexHeap *heap, Py_ssize_t i)
 | |
| {
 | |
|     if (left_child(i) < heap->size) {
 | |
|         if (right_child(i) < heap->size) {
 | |
|             Py_ssize_t lval = heap->values[left_child(i)];
 | |
|             Py_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 (Py_ssize_t cur = 0; cur < heap->size;) {
 | |
|         Py_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, Py_ssize_t limit)
 | |
| {
 | |
|     assert(limit > 0);
 | |
|     if (heap->capacity > limit) {
 | |
|         return 0;
 | |
|     }
 | |
|     Py_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 = PyMem_RawCalloc(new_capacity, sizeof(int32_t));
 | |
|     if (new_values == NULL) {
 | |
|         return -1;
 | |
|     }
 | |
|     if (heap->values != NULL) {
 | |
|         memcpy(new_values, heap->values, heap->capacity);
 | |
|         PyMem_RawFree(heap->values);
 | |
|     }
 | |
|     heap->values = new_values;
 | |
|     heap->capacity = new_capacity;
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| static void
 | |
| heap_fini(_PyIndexHeap *heap)
 | |
| {
 | |
|     if (heap->values != NULL) {
 | |
|         PyMem_RawFree(heap->values);
 | |
|         heap->values = NULL;
 | |
|     }
 | |
|     heap->size = -1;
 | |
|     heap->capacity = -1;
 | |
| }
 | |
| 
 | |
| #define LOCK_POOL(pool) PyMutex_LockFlags(&pool->mutex, _Py_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);
 | |
|             PyErr_NoMemory();
 | |
|             return -1;
 | |
|         }
 | |
|         index = pool->next_index++;
 | |
|     }
 | |
|     else {
 | |
|         index = heap_pop(free_indices);
 | |
|     }
 | |
|     UNLOCK_POOL(pool);
 | |
|     return index;
 | |
| }
 | |
| 
 | |
| void
 | |
| _PyIndexPool_FreeIndex(_PyIndexPool *pool, int32_t index)
 | |
| {
 | |
|     LOCK_POOL(pool);
 | |
|     heap_add(&pool->free_indices, index);
 | |
|     UNLOCK_POOL(pool);
 | |
| }
 | |
| 
 | |
| void
 | |
| _PyIndexPool_Fini(_PyIndexPool *pool)
 | |
| {
 | |
|     heap_fini(&pool->free_indices);
 | |
| }
 | |
| 
 | |
| #endif  // Py_GIL_DISABLED
 |