forked from sagemath/sage
-
Notifications
You must be signed in to change notification settings - Fork 0
/
memory_allocator.pyx
180 lines (161 loc) · 6.44 KB
/
memory_allocator.pyx
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# sage.doctest: needs sage.misc.cython
from cysignals.memory cimport *
from sage.misc.superseded import deprecation
cdef class MemoryAllocator:
r"""
An object for memory allocation, whose resources are freed upon
``__dealloc__``.
EXAMPLES::
sage: cython(
....: '''
....: from sage.ext.memory_allocator cimport MemoryAllocator
....: cdef MemoryAllocator mem = MemoryAllocator()
....: cdef void* ptr
....: 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)
....: ''')
doctest:...: DeprecationWarning: this class is deprecated; use the class from the python package `memory_allocator`
See https://github.com/sagemath/sage/issues/31591 for details.
"""
def __cinit__(self):
"""
EXAMPLES::
sage: cython(
....: '''
....: from sage.ext.memory_allocator cimport MemoryAllocator
....: def foo():
....: cdef MemoryAllocator mem = MemoryAllocator.__new__(MemoryAllocator)
....: mem.malloc(10000)
....: print(mem.n)
....: print(mem.size)
....: ''')
sage: foo()
doctest:...: DeprecationWarning: this class is deprecated; use the class from the python package `memory_allocator`
See https://github.com/sagemath/sage/issues/31591 for details.
1
16
"""
deprecation(31591, "this class is deprecated; use the class from the python package `memory_allocator`")
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.
TESTS::
sage: cython('''
....: from sage.ext.memory_allocator cimport MemoryAllocator
....: def test_realloc_good():
....: cdef MemoryAllocator mem = MemoryAllocator()
....: ptr = mem.malloc(20)
....: mem.realloc(ptr, 21)
....: def test_realloc_NULL():
....: cdef MemoryAllocator mem = MemoryAllocator()
....: mem.realloc(NULL, 21)
....: def test_realloc_bad():
....: cdef MemoryAllocator mem = MemoryAllocator()
....: cdef MemoryAllocator mem2 = MemoryAllocator()
....: ptr = mem.malloc(20)
....: mem2.realloc(ptr, 21)
....: ''')
sage: test_realloc_good() # random # might raise deprecation warning
sage: test_realloc_good()
sage: test_realloc_NULL()
sage: test_realloc_bad()
Traceback (most recent call last):
...
ValueError: given pointer not found in MemoryAllocator
"""
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::
sage: from sage.ext.memory_allocator import MemoryAllocator
sage: _ = MemoryAllocator()
"""
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)