1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
|
from .memory cimport *
cdef class MemoryAllocator:
r"""
An object for memory allocation, whose resources are freed upon
``__dealloc__``.
EXAMPLES::
>>> from memory_allocator.test import TestMemoryAllocator
>>> mem = TestMemoryAllocator()
>>> for n in range(100):
... ptr = mem.malloc(n)
... _ = mem.realloc(ptr, 2*n)
... _ = mem.calloc(n, n)
... ptr = mem.allocarray(n, n)
... _ = mem.reallocarray(ptr, n + 1, n)
... _ = mem.aligned_malloc(32, (n//32 + 1)*32)
... _ = mem.aligned_calloc(16, n, 16)
... _ = mem.aligned_allocarray(8, n, 8)
"""
def __cinit__(self):
"""
EXAMPLES::
>>> from memory_allocator.test import TestMemoryAllocator
>>> _ = TestMemoryAllocator()
>>> _ = malloc(10000)
>>> mem.n()
1
>>> mem.size()
16
"""
self.n = 0
self.size = 16
self.pointers = self.static_pointers
cdef int resize(self, size_t new_size) except -1:
r"""
Resize the list of pointers to contain ``new_size`` elements.
It is required that ``new_size`` is at least ``self.n``, but
this condition is not checked.
"""
cdef size_t i
if self.pointers == self.static_pointers:
# Case 1: allocate pointers for the first time
self.pointers = <void**>check_allocarray(new_size, sizeof(void*))
for i in range(self.n):
self.pointers[i] = self.static_pointers[i]
else:
# Case 2: resize pointers
self.pointers = <void**>check_reallocarray(self.pointers, new_size, sizeof(void*))
self.size = new_size
cdef void** find_pointer(self, void* ptr) except NULL:
r"""
Return the address in the list of stored pointers where ``ptr``
is stored. If ``ptr`` is not found in the existing pointers and
``ptr`` is not ``NULL``, then an exception is raised. If ``ptr``
is ``NULL``, then we simply add ``NULL`` as an additional
pointer and return the address of that.
"""
cdef size_t i = 0
for i in range(self.n):
if self.pointers[i] == ptr:
return &self.pointers[i]
if ptr != NULL:
raise ValueError("given pointer not found in MemoryAllocator")
self.enlarge_if_needed()
addr = &self.pointers[self.n]
self.n += 1
return addr
cdef void* malloc(self, size_t size) except? NULL:
r"""
Returns a new pointer and stores it to be automatically freed later.
"""
self.enlarge_if_needed()
cdef void* val = check_malloc(size)
self.pointers[self.n] = val
self.n += 1
return val
cdef void* calloc(self, size_t nmemb, size_t size) except? NULL:
r"""
Returns a new pointer and stores it to be automatically freed later.
"""
self.enlarge_if_needed()
cdef void* val = check_calloc(nmemb, size)
self.pointers[self.n] = val
self.n += 1
return val
cdef void* allocarray(self, size_t nmemb, size_t size) except? NULL:
r"""
Returns a new pointer and stores it to be automatically freed later.
"""
self.enlarge_if_needed()
cdef void* val = check_allocarray(nmemb, size)
self.pointers[self.n] = val
self.n += 1
return val
cdef void* realloc(self, void* ptr, size_t size) except? NULL:
r"""
Re-allocates `ptr` and automatically frees it later.
"""
cdef void** addr = self.find_pointer(ptr)
cdef void* val = check_realloc(ptr, size)
addr[0] = val
return val
cdef void* reallocarray(self, void* ptr, size_t nmemb,
size_t size) except? NULL:
r"""
Re-allocates `ptr` and automatically frees it later.
"""
cdef void** addr = self.find_pointer(ptr)
cdef void* val = check_reallocarray(ptr, nmemb, size)
addr[0] = val
return val
def __dealloc__(self):
r"""
Free the allocated resources
EXAMPLES::
>>> from memory_allocator.test import TestMemoryAllocator
>>> _ = TestMemoryAllocator()
"""
cdef size_t i
for i in range(self.n):
sig_free(self.pointers[i])
if self.pointers != self.static_pointers:
sig_free(self.pointers)
|