/src/leptonica/src/stack.c
Line | Count | Source (jump to first uncovered line) |
1 | | /*====================================================================* |
2 | | - Copyright (C) 2001 Leptonica. All rights reserved. |
3 | | - |
4 | | - Redistribution and use in source and binary forms, with or without |
5 | | - modification, are permitted provided that the following conditions |
6 | | - are met: |
7 | | - 1. Redistributions of source code must retain the above copyright |
8 | | - notice, this list of conditions and the following disclaimer. |
9 | | - 2. Redistributions in binary form must reproduce the above |
10 | | - copyright notice, this list of conditions and the following |
11 | | - disclaimer in the documentation and/or other materials |
12 | | - provided with the distribution. |
13 | | - |
14 | | - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
15 | | - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
16 | | - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
17 | | - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY |
18 | | - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
19 | | - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
20 | | - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
21 | | - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
22 | | - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
23 | | - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
24 | | - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
25 | | *====================================================================*/ |
26 | | |
27 | | /*! |
28 | | * \file stack.c |
29 | | * <pre> |
30 | | * |
31 | | * Generic stack |
32 | | * |
33 | | * The lstack is an array of void * ptrs, onto which |
34 | | * objects can be stored. At any time, the number of |
35 | | * stored objects is lstack->n. The object at the bottom |
36 | | * of the lstack is at array[0]; the object at the top of |
37 | | * the lstack is at array[n-1]. New objects are added |
38 | | * to the top of the lstack; i.e., the first available |
39 | | * location, which is at array[n]. The lstack is expanded |
40 | | * by doubling, when needed. Objects are removed |
41 | | * from the top of the lstack. When an attempt is made |
42 | | * to remove an object from an empty lstack, the result is null. |
43 | | * |
44 | | * Create/Destroy |
45 | | * L_STACK *lstackCreate() |
46 | | * void lstackDestroy() |
47 | | * |
48 | | * Accessors |
49 | | * l_int32 lstackAdd() |
50 | | * void *lstackRemove() |
51 | | * static l_int32 lstackExtendArray() |
52 | | * l_int32 lstackGetCount() |
53 | | * |
54 | | * Text description |
55 | | * l_int32 lstackPrint() |
56 | | * </pre> |
57 | | */ |
58 | | |
59 | | #ifdef HAVE_CONFIG_H |
60 | | #include <config_auto.h> |
61 | | #endif /* HAVE_CONFIG_H */ |
62 | | |
63 | | #include "allheaders.h" |
64 | | |
65 | | /* Bounds on initial array size */ |
66 | | static const l_uint32 MaxPtrArraySize = 100000; |
67 | | static const l_int32 InitialPtrArraySize = 20; /*!< n'importe quoi */ |
68 | | |
69 | | /* Static function */ |
70 | | static l_int32 lstackExtendArray(L_STACK *lstack); |
71 | | |
72 | | /*---------------------------------------------------------------------* |
73 | | * Create/Destroy * |
74 | | *---------------------------------------------------------------------*/ |
75 | | /*! |
76 | | * \brief lstackCreate() |
77 | | * |
78 | | * \param[in] n initial ptr array size; use 0 for default |
79 | | * \return lstack, or NULL on error |
80 | | */ |
81 | | L_STACK * |
82 | | lstackCreate(l_int32 n) |
83 | 0 | { |
84 | 0 | L_STACK *lstack; |
85 | |
|
86 | 0 | if (n <= 0 || n > (l_int32)MaxPtrArraySize) |
87 | 0 | n = InitialPtrArraySize; |
88 | |
|
89 | 0 | lstack = (L_STACK *)LEPT_CALLOC(1, sizeof(L_STACK)); |
90 | 0 | lstack->array = (void **)LEPT_CALLOC(n, sizeof(void *)); |
91 | 0 | if (!lstack->array) { |
92 | 0 | lstackDestroy(&lstack, FALSE); |
93 | 0 | return (L_STACK *)ERROR_PTR("lstack array not made", __func__, NULL); |
94 | 0 | } |
95 | | |
96 | 0 | lstack->nalloc = n; |
97 | 0 | lstack->n = 0; |
98 | 0 | return lstack; |
99 | 0 | } |
100 | | |
101 | | |
102 | | /*! |
103 | | * \brief lstackDestroy() |
104 | | * |
105 | | * \param[in,out] plstack will be set to null before returning |
106 | | * \param[in] freeflag TRUE to free each remaining struct in the array |
107 | | * \return void |
108 | | * |
109 | | * <pre> |
110 | | * Notes: |
111 | | * (1) If %freeflag is TRUE, frees each struct in the array. |
112 | | * (2) If %freeflag is FALSE but there are elements on the array, |
113 | | * gives a warning and destroys the array. This will |
114 | | * cause a memory leak of all the items that were on the lstack. |
115 | | * So if the items require their own destroy function, they |
116 | | * must be destroyed before the lstack. |
117 | | * (3) To destroy the lstack, we destroy the ptr array, then |
118 | | * the lstack, and then null the contents of the input ptr. |
119 | | * </pre> |
120 | | */ |
121 | | void |
122 | | lstackDestroy(L_STACK **plstack, |
123 | | l_int32 freeflag) |
124 | 0 | { |
125 | 0 | void *item; |
126 | 0 | L_STACK *lstack; |
127 | |
|
128 | 0 | if (plstack == NULL) { |
129 | 0 | L_WARNING("ptr address is NULL\n", __func__); |
130 | 0 | return; |
131 | 0 | } |
132 | 0 | if ((lstack = *plstack) == NULL) |
133 | 0 | return; |
134 | | |
135 | 0 | if (freeflag) { |
136 | 0 | while(lstack->n > 0) { |
137 | 0 | item = lstackRemove(lstack); |
138 | 0 | LEPT_FREE(item); |
139 | 0 | } |
140 | 0 | } else if (lstack->n > 0) { |
141 | 0 | L_WARNING("memory leak of %d items in lstack\n", __func__, lstack->n); |
142 | 0 | } |
143 | |
|
144 | 0 | if (lstack->auxstack) |
145 | 0 | lstackDestroy(&lstack->auxstack, freeflag); |
146 | |
|
147 | 0 | if (lstack->array) |
148 | 0 | LEPT_FREE(lstack->array); |
149 | 0 | LEPT_FREE(lstack); |
150 | 0 | *plstack = NULL; |
151 | 0 | } |
152 | | |
153 | | |
154 | | |
155 | | /*---------------------------------------------------------------------* |
156 | | * Accessors * |
157 | | *---------------------------------------------------------------------*/ |
158 | | /*! |
159 | | * \brief lstackAdd() |
160 | | * |
161 | | * \param[in] lstack |
162 | | * \param[in] item to be added to the lstack |
163 | | * \return 0 if OK; 1 on error. |
164 | | */ |
165 | | l_ok |
166 | | lstackAdd(L_STACK *lstack, |
167 | | void *item) |
168 | 0 | { |
169 | 0 | if (!lstack) |
170 | 0 | return ERROR_INT("lstack not defined", __func__, 1); |
171 | 0 | if (!item) |
172 | 0 | return ERROR_INT("item not defined", __func__, 1); |
173 | | |
174 | | /* Do we need to extend the array? */ |
175 | 0 | if (lstack->n >= lstack->nalloc) { |
176 | 0 | if (lstackExtendArray(lstack)) |
177 | 0 | return ERROR_INT("extension failed", __func__, 1); |
178 | 0 | } |
179 | | |
180 | | /* Store the new pointer */ |
181 | 0 | lstack->array[lstack->n] = (void *)item; |
182 | 0 | lstack->n++; |
183 | |
|
184 | 0 | return 0; |
185 | 0 | } |
186 | | |
187 | | |
188 | | /*! |
189 | | * \brief lstackRemove() |
190 | | * |
191 | | * \param[in] lstack |
192 | | * \return ptr to item popped from the top of the lstack, |
193 | | * or NULL if the lstack is empty or on error |
194 | | */ |
195 | | void * |
196 | | lstackRemove(L_STACK *lstack) |
197 | 0 | { |
198 | 0 | void *item; |
199 | |
|
200 | 0 | if (!lstack) |
201 | 0 | return ERROR_PTR("lstack not defined", __func__, NULL); |
202 | | |
203 | 0 | if (lstack->n == 0) |
204 | 0 | return NULL; |
205 | | |
206 | 0 | lstack->n--; |
207 | 0 | item = lstack->array[lstack->n]; |
208 | |
|
209 | 0 | return item; |
210 | 0 | } |
211 | | |
212 | | |
213 | | /*! |
214 | | * \brief lstackExtendArray() |
215 | | * |
216 | | * \param[in] lstack |
217 | | * \return 0 if OK; 1 on error |
218 | | */ |
219 | | static l_int32 |
220 | | lstackExtendArray(L_STACK *lstack) |
221 | 0 | { |
222 | 0 | if (!lstack) |
223 | 0 | return ERROR_INT("lstack not defined", __func__, 1); |
224 | | |
225 | 0 | if ((lstack->array = (void **)reallocNew((void **)&lstack->array, |
226 | 0 | sizeof(void *) * lstack->nalloc, |
227 | 0 | 2 * sizeof(void *) * lstack->nalloc)) == NULL) |
228 | 0 | return ERROR_INT("new lstack array not defined", __func__, 1); |
229 | | |
230 | 0 | lstack->nalloc = 2 * lstack->nalloc; |
231 | 0 | return 0; |
232 | 0 | } |
233 | | |
234 | | |
235 | | /*! |
236 | | * \brief lstackGetCount() |
237 | | * |
238 | | * \param[in] lstack |
239 | | * \return count, or 0 on error |
240 | | */ |
241 | | l_int32 |
242 | | lstackGetCount(L_STACK *lstack) |
243 | 0 | { |
244 | 0 | if (!lstack) |
245 | 0 | return ERROR_INT("lstack not defined", __func__, 1); |
246 | | |
247 | 0 | return lstack->n; |
248 | 0 | } |
249 | | |
250 | | |
251 | | |
252 | | /*---------------------------------------------------------------------* |
253 | | * Debug output * |
254 | | *---------------------------------------------------------------------*/ |
255 | | /*! |
256 | | * \brief lstackPrint() |
257 | | * |
258 | | * \param[in] fp file stream |
259 | | * \param[in] lstack |
260 | | * \return 0 if OK; 1 on error |
261 | | */ |
262 | | l_ok |
263 | | lstackPrint(FILE *fp, |
264 | | L_STACK *lstack) |
265 | 0 | { |
266 | 0 | l_int32 i; |
267 | |
|
268 | 0 | if (!fp) |
269 | 0 | return ERROR_INT("stream not defined", __func__, 1); |
270 | 0 | if (!lstack) |
271 | 0 | return ERROR_INT("lstack not defined", __func__, 1); |
272 | | |
273 | 0 | fprintf(fp, "\n Stack: nalloc = %d, n = %d, array = %p\n", |
274 | 0 | lstack->nalloc, lstack->n, lstack->array); |
275 | 0 | for (i = 0; i < lstack->n; i++) |
276 | 0 | fprintf(fp, "array[%d] = %p\n", i, lstack->array[i]); |
277 | |
|
278 | 0 | return 0; |
279 | 0 | } |