about summary refs log tree commit diff
path: root/lib/util/mallocvar.h
blob: 73498357cd94b825fbc0d0949a4ff106e9e32a5c (plain) (blame)
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
/* These are some dynamic memory allocation facilities.  They are essentially
   an extension to C, as they do allocations with a cognizance of C
   variables.  You can use them to make C read more like a high level
   language.

   Before including this, you must define an __inline__ macro if your
   compiler doesn't recognize it as a keyword.
*/

#ifndef MALLOCVAR_INCLUDED
#define MALLOCVAR_INCLUDED

#include "pm_config.h"

#include <limits.h>
#include <stdlib.h>

#ifdef __cplusplus
extern "C" {
#endif
#if 0
} /* to fake out automatic code indenters */
#endif

static __inline__ void
mallocProduct(void **      const resultP,
              size_t       const factor1,
              unsigned int const factor2) {
/*----------------------------------------------------------------------------
   malloc a space whose size in bytes is the product of 'factor1' and
   'factor2'.  But if the malloc fails, or that size is too large even to
   request from malloc, return NULL without allocating anything.

   If either factor is zero, malloc a single byte.
-----------------------------------------------------------------------------*/
    /* C99 introduces SIZE_MAX, the maximum size_t value.

       Pre-C99, we do the best we can, assuming conventional encoding of
       numbers and that size_t is unsigned.
    */
    size_t const sizeMax =
#if defined(SIZE_MAX)
        SIZE_MAX
#else
        ~((size_t)0)
#endif
        ;

    if (factor1 == 0 || factor2 == 0)
        *resultP = malloc(1);
    else {
        /* N.B. The type of malloc's argument is size_t */
        if ((size_t)factor2 != factor2)
            *resultP = NULL;
        else {
            if (sizeMax / factor2 < factor1)
                *resultP = NULL;
            else
                *resultP = malloc(factor1 * factor2);
        }
    }
}



static __inline__ void
reallocProduct(void **      const blockP,
               size_t       const factor1,
               unsigned int const factor2) {
/*----------------------------------------------------------------------------
   Reallocate the block at *blockPP to size 'factor1' * 'factor2'.
   (Reallocate means make *blockPP point to a block of that size that
   contains the same data as the block to which *blockP points now, with
   additional space as needed at the end).

   If *blockPP is null, make *blockPP point to a new block of memory of
   the desired size with no contents.

   If the reallocation fails, release any memory pointed by *blockP and
   make *blockP null.
-----------------------------------------------------------------------------*/
    size_t const sizeMax =
#if defined(SIZE_MAX)
        SIZE_MAX
#else
        ~((size_t)0)
#endif
        ;

    void * const oldBlockP = *blockP;

    void * newBlockP;

    /* N.B. The type of realloc's argument is size_t */
    if ((size_t)factor2 != factor2)
        newBlockP = NULL;
    else {
        if (sizeMax / factor2 < factor1)
            newBlockP = NULL;
        else
            newBlockP = realloc(oldBlockP, factor1 * factor2);
    }
    if (newBlockP)
        *blockP = newBlockP;
    else {
        free(oldBlockP);
        *blockP = NULL;
    }
}



#define MALLOCARRAY(arrayName, nElements) do { \
    void * array; \
    mallocProduct(&array, nElements, sizeof(arrayName[0])); \
    arrayName = array; \
} while (0)

#define REALLOCARRAY(arrayName, nElements) do { \
    void * array; \
    array = arrayName; \
    reallocProduct(&array, nElements, sizeof(arrayName[0])); \
    arrayName = array; \
} while (0)


#define MALLOCARRAY_NOFAIL(arrayName, nElements) \
do { \
    MALLOCARRAY(arrayName, nElements); \
    if ((arrayName) == NULL) \
        abort(); \
} while(0)

#define REALLOCARRAY_NOFAIL(arrayName, nElements) \
do { \
    REALLOCARRAY(arrayName, nElements); \
    if ((arrayName) == NULL) \
        abort(); \
} while(0)

#define MALLOCARRAY2(arrayName, nRows, nCols) do { \
    void * array; \
    pm_mallocarray2(&array, nRows, nCols, sizeof(arrayName[0][0]));  \
    arrayName = array; \
} while (0)

#define MALLOCARRAY2_NOFAIL(arrayName, nRows, nCols) do { \
    MALLOCARRAY2(arrayName, nRows, nCols);       \
    if ((arrayName) == NULL) \
        abort(); \
} while (0)

void
pm_freearray2(void ** const rowIndex);


#define MALLOCVAR(varName) \
    varName = malloc(sizeof(*varName))

#define MALLOCVAR_NOFAIL(varName) \
    do {if ((varName = malloc(sizeof(*varName))) == NULL) abort();} while(0)

void
pm_mallocarray2(void **      const resultP,
                unsigned int const cols,
                unsigned int const rows,
                unsigned int const elementSize);

#ifdef __cplusplus
}
#endif
#endif