New multiprecision integer arithmetic suite.
[u/mdw/catacomb] / mparena.c
CommitLineData
d3409d5e 1/* -*-c-*-
2 *
3 * $Id: mparena.c,v 1.1 1999/11/17 18:02:16 mdw Exp $
4 *
5 * Allocation and freeing of MP buffers
6 *
7 * (c) 1999 Straylight/Edgeware
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of Catacomb.
13 *
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
18 *
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27 * MA 02111-1307, USA.
28 */
29
30/*----- Revision history --------------------------------------------------*
31 *
32 * $Log: mparena.c,v $
33 * Revision 1.1 1999/11/17 18:02:16 mdw
34 * New multiprecision integer arithmetic suite.
35 *
36 */
37
38/*----- Header files ------------------------------------------------------*/
39
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43
44#include <mLib/alloc.h>
45#include <mLib/sub.h>
46
47#include "mparena.h"
48
49/*----- Default allocator -------------------------------------------------*/
50
51static void *defalloc(mparena *a, size_t sz) { return xmalloc(sz); }
52static void deffree(mparena *a, void *p) { free(p); }
53
54mparena_ops mparena_defops = { defalloc, deffree };
55
56/*----- Static variables --------------------------------------------------*/
57
58static mparena arena = { 0, &mparena_defops };
59
60#define MPARENA_RESOLVE(a) do { \
61 if ((a) == MPARENA_GLOBAL) \
62 (a) = &arena; \
63} while (0)
64
65/*----- Main code ---------------------------------------------------------*/
66
67/* --- @tdump@ --- *
68 *
69 * Arguments: @mparena_node *n@ = pointer to tree node to dump
70 *
71 * Returns: ---
72 *
73 * Use: Recursively dumps out the allocation tree.
74 */
75
76static void tdump(mparena_node *n)
77{
78 if (!n)
79 putchar('*');
80 else {
81 putchar('(');
82 tdump(n->left);
83 printf(", %u, ", n->v[0]);
84 tdump(n->right);
85 putchar(')');
86 }
87}
88
89/* --- @mparena_create@ --- *
90 *
91 * Arguments: @mparena *a@ = pointer to arena block
92 *
93 * Returns: ---
94 *
95 * Use: Initializes an MP arena so that blocks can be allocated from
96 * it.
97 */
98
99void mparena_create(mparena *a)
100{
101 a->root = 0;
102 a->ops = &mparena_defops;
103}
104
105/* --- @mparena_setops@ --- *
106 *
107 * Arguments: @mparena *a@ = pointer to arena block
108 * @mparena_ops *ops@ = pointer to operations block or null
109 *
110 * Returns: The previous operations block.
111 *
112 * Use: Sets or queries the operations attached to an arena.
113 */
114
115mparena_ops *mparena_setops(mparena *a, mparena_ops *ops)
116{
117 mparena_ops *o;
118 MPARENA_RESOLVE(a);
119 o = a->ops;
120 if (ops)
121 a->ops = ops;
122 return (0);
123}
124
125/* --- @mparena_destroy@ --- *
126 *
127 * Arguments: @mparena *a@ = pointer to arena block
128 *
129 * Returns: ---
130 *
131 * Use: Frees an MP arena, and all the vectors held within it. The
132 * blocks which are currently allocated can be freed into some
133 * other arena.
134 */
135
136static void tfree(mparena *a, mparena_node *n)
137{
138 a->ops->free(a, n->v);
139 if (n->left)
140 tfree(a, n->left);
141 if (n->right)
142 tfree(a, n->right);
143 DESTROY(n);
144}
145
146void mparena_destroy(mparena *a)
147{
148 tfree(a, a->root);
149 a->root = 0;
150}
151
152/* --- @mpalloc@ --- *
153 *
154 * Arguments: @mparena *a@ = pointer to arena block
155 * @size_t sz@ = number of digits required
156 *
157 * Returns: Pointer to a suitably sized block.
158 *
159 * Use: Allocates a lump of data suitable for use as an array of MP
160 * digits.
161 */
162
163mpw *mpalloc(mparena *a, size_t sz)
164{
165 mparena_node **nn, *n;
166 mpw *v;
167
168 MPARENA_RESOLVE(a);
169 nn = &a->root;
170
171#ifdef notdef
172 printf("*** alloc %u\n", sz);
173 tdump(a->root); putchar('\n');
174#endif
175
176 /* --- First, find a block which is big enough --- */
177
178again:
179 n = *nn;
180 if (!n) {
181 v = a->ops->alloc(a, MPWS(sz + 1));
182 v[0] = sz;
183 return (v + 1);
184 }
185 if (n->v[0] < sz) {
186 nn = &n->right;
187 goto again;
188 }
189
190 /* --- Now try to find a smaller block which is suitable --- */
191
192 while (n->left && n->left->v[0] >= sz) {
193 nn = &n->left;
194 n = *nn;
195 }
196
197 /* --- If the block we've got is still too large, start digging --- */
198
199 if (n->v[0] >= sz * 2) {
200 nn = &n->left;
201 goto again;
202 }
203
204 /* --- I've now found a suitable block --- */
205
206 v = n->v;
207
208 /* --- Remove this node from the tree --- */
209
210 if (!n->left)
211 *nn = n->right;
212 else if (!n->right)
213 *nn = n->left;
214 else {
215 mparena_node *left = n->left;
216 mparena_node *p = *nn = n->right;
217 while (p->left)
218 p = p->left;
219 p->left = left;
220 }
221
222 /* --- Get rid of this node now --- */
223
224 DESTROY(n);
225 return (v + 1);
226}
227
228/* --- @mpfree@ --- *
229 *
230 * Arguments: @mparena *a@ = pointer to arena block
231 * @mpw *v@ = pointer to allocated vector
232 *
233 * Returns: ---
234 *
235 * Use: Returns an MP vector to an arena. It doesn't have to be
236 * returned to the arena from which it was allocated.
237 */
238
239void mpfree(mparena *a, mpw *v)
240{
241 mparena_node **nn, *n;
242 size_t sz = *--v;
243
244 MPARENA_RESOLVE(a);
245 nn = &a->root;
246
247 while (*nn) {
248 n = *nn;
249 if (n->v[0] > sz)
250 nn = &n->left;
251 else
252 nn = &n->right;
253 }
254
255 n = CREATE(mparena_node);
256 n->left = n->right = 0;
257 n->v = v;
258 *nn = n;
259
260#ifdef notdef
261 printf("*** free %u\n", sz);
262 tdump(a->root); putchar('\n');
263#endif
264}
265
266/*----- That's all, folks -------------------------------------------------*/