1#------------------------------------------------------------------------------
2
3cdef extern from "Python.h":
4    enum: PY_SSIZE_T_MAX
5    void *PyMem_Malloc(size_t)
6    void *PyMem_Calloc(size_t, size_t)
7    void *PyMem_Realloc(void*, size_t)
8    void  PyMem_Free(void*)
9
10cdef extern from * nogil:
11    """
12    #if PY_VERSION_HEX < 0x03050000
13    #   define PyMPI_RawMalloc(n)    malloc((n)?(n):1)
14    #   define PyMPI_RawCalloc(n,s)  ((n)&&(s))?calloc((n),(s)):calloc(1,1)
15    #   define PyMPI_RawRealloc(p,n) realloc((p),(n)?(n):1))
16    #   define PyMPI_RawFree         free
17    #else
18    #   define PyMPI_RawMalloc  PyMem_RawMalloc
19    #   define PyMPI_RawCalloc  PyMem_RawCalloc
20    #   define PyMPI_RawRealloc PyMem_RawRealloc
21    #   define PyMPI_RawFree    PyMem_RawFree
22    #endif
23    """
24    void *PyMPI_RawMalloc(size_t)
25    void *PyMPI_RawCalloc(size_t, size_t)
26    void *PyMPI_RawRealloc(void*, size_t)
27    void  PyMPI_RawFree(void*)
28
29#------------------------------------------------------------------------------
30
31@cython.final
32@cython.internal
33cdef class _p_mem:
34    cdef void *buf
35    cdef size_t len
36    cdef void (*free)(void*)
37    def __cinit__(self):
38        self.buf = NULL
39        self.len = 0
40        self.free = NULL
41    def __dealloc__(self):
42        if self.free:
43            self.free(self.buf)
44
45
46cdef inline _p_mem allocate(Py_ssize_t m, size_t b, void *buf):
47  if m > PY_SSIZE_T_MAX/<Py_ssize_t>b:
48      raise MemoryError("memory allocation size too large")
49  if m < 0:
50      raise RuntimeError("memory allocation with negative size")
51  cdef _p_mem ob = _p_mem.__new__(_p_mem)
52  ob.len  = <size_t>m * b
53  ob.free = PyMem_Free
54  ob.buf  = PyMem_Malloc(<size_t>m * b)
55  if ob.buf == NULL: raise MemoryError
56  if buf != NULL: (<void**>buf)[0] = ob.buf
57  return ob
58
59
60cdef inline _p_mem rawalloc(Py_ssize_t m, size_t b, bint clear, void *buf):
61  if m > PY_SSIZE_T_MAX/<Py_ssize_t>b:
62      raise MemoryError("memory allocation size too large")
63  if m < 0:
64      raise RuntimeError("memory allocation with negative size")
65  cdef _p_mem ob = _p_mem.__new__(_p_mem)
66  ob.len = <size_t>m * b
67  ob.free = PyMPI_RawFree
68  if clear:
69      ob.buf = PyMPI_RawCalloc(<size_t>m, b)
70  else:
71      ob.buf = PyMPI_RawMalloc(<size_t>m * b)
72  if ob.buf == NULL: raise MemoryError
73  if buf != NULL: (<void**>buf)[0] = ob.buf
74  return ob
75
76#------------------------------------------------------------------------------
77