comparison src/dynarr.c @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children 3d6bfa290dbd
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 /* Simple 'n' stupid dynamic-array module.
2 Copyright (C) 1993 Sun Microsystems, Inc.
3
4 This file is part of XEmacs.
5
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 /* Synched up with: Not in FSF. */
22
23 /* Written by Ben Wing, December 1993. */
24
25 /*
26
27 A "dynamic array" is a contiguous array of fixed-size elements where there
28 is no upper limit (except available memory) on the number of elements in the
29 array. Because the elements are maintained contiguously, space is used
30 efficiently (no per-element pointers necessary) and random access to a
31 particular element is in constant time. At any one point, the block of memory
32 that holds the array has an upper limit; if this limit is exceeded, the
33 memory is realloc()ed into a new array that is twice as big. Assuming that
34 the time to grow the array is on the order of the new size of the array
35 block, this scheme has a provably constant amortized time (i.e. average
36 time over all additions).
37
38 When you add elements or retrieve elements, pointers are used. Note that
39 the element itself (of whatever size it is), and not the pointer to it,
40 is stored in the array; thus you do not have to allocate any heap memory
41 on your own. Also, returned pointers are only guaranteed to be valid
42 until the next operation that changes the length of the array.
43
44 This is a container object. Declare a dynamic array of a specific type
45 as follows:
46
47 struct mytype_dynarr
48 {
49 Dynarr_declare (mytype);
50 };
51
52 Use the following functions/macros:
53
54 void *Dynarr_new(type)
55 [MACRO] Create a new dynamic-array object, with each element of the
56 specified type. The return value is a void * and must be cast to the
57 proper dynamic array type.
58
59 Dynarr_add(d, el)
60 [MACRO] Add an element to the end of a dynamic array. EL is a pointer
61 to the element; the element itself is stored in the array, however.
62 No function call is performed unless the array needs to be resized.
63
64 Dynarr_add_many(d, base, len)
65 [MACRO] Add LEN elements to the end of the dynamic array. The elements
66 should be contiguous in memory, starting at BASE.
67
68 Dynarr_insert_many_at_start(d, base, len)
69 [MACRO] Append LEN elements to the beginning of the dynamic array.
70 The elements should be contiguous in memory, starting at BASE.
71
72 Dynarr_insert_many(d, base, len, start)
73 Insert LEN elements to the dynamic arrary starting at position
74 START. The elements should be contiguous in memory, starting at BASE.
75
76 int Dynarr_length(d)
77 [MACRO] Return the number of elements currently in a dynamic array.
78
79 type Dynarr_at(d, i)
80 [MACRO] Return the element at the specified index (no bounds checking
81 done on the index). The element itself is returned, not a pointer
82 to it.
83
84 type *Dynarr_atp(d, i)
85 [MACRO] Return a pointer to the element at the specified index (no
86 bounds checking done on the index). The pointer may not be valid
87 after an element is added to or removed from the array.
88
89 Dynarr_reset(d)
90 [MACRO] Reset the length of a dynamic array to 0.
91
92 Dynarr_free(d)
93 Destroy a dynamic array and the memory allocated to it.
94
95 Use the following global variable:
96
97 Dynarr_min_size
98 Minimum allowable size for a dynamic array when it is resized. The
99 default is 32 and does not normally need to be changed.
100
101 */
102
103 #include <config.h>
104 #include "lisp.h"
105
106 int Dynarr_min_size = 1;
107
108 void *
109 Dynarr_newf (int elsize)
110 {
111 Dynarr *d = (Dynarr *) xmalloc (sizeof (Dynarr));
112
113 memset (d, 0, sizeof (*d));
114 d->elsize = elsize;
115
116 return d;
117 }
118
119 void
120 Dynarr_resize (void *d, int size)
121 {
122 int newsize;
123 double multiplier;
124 Dynarr *dy = (Dynarr *) d;
125
126 if (dy->max <= 8)
127 multiplier = 2;
128 else
129 multiplier = 1.5;
130
131 for (newsize = dy->max; newsize < size;)
132 newsize = max (Dynarr_min_size, multiplier * newsize);
133
134 /* Don't do anything if the array is already big enough. */
135 if (newsize > dy->max)
136 {
137 dy->base = xrealloc (dy->base, newsize*dy->elsize);
138 dy->max = newsize;
139 }
140 }
141
142 /* Add a number of contiguous elements to the array starting at START. */
143 void
144 Dynarr_insert_many (void *d, CONST void *el, int len, int start)
145 {
146 Dynarr *dy = (Dynarr *) d;
147
148 Dynarr_resize (dy, dy->cur+len);
149 /* Silently adjust start to be valid. */
150 if (start > dy->cur)
151 start = dy->cur;
152 else if (start < 0)
153 start = 0;
154
155 if (start != dy->cur)
156 {
157 memmove ((char *) dy->base + (start + len)*dy->elsize,
158 (char *) dy->base + start*dy->elsize,
159 (dy->cur - start)*dy->elsize);
160 }
161 memcpy ((char *) dy->base + start*dy->elsize, el, len*dy->elsize);
162 dy->cur += len;
163
164 if (dy->cur > dy->largest)
165 dy->largest = dy->cur;
166 }
167
168 void
169 Dynarr_delete_many (void *d, int start, int len)
170 {
171 Dynarr *dy = (Dynarr *) d;
172
173 assert (start >= 0 && len >= 0 && start + len <= dy->cur);
174 memmove ((char *) dy->base + start*dy->elsize,
175 (char *) dy->base + (start + len)*dy->elsize,
176 (dy->cur - start - len)*dy->elsize);
177 dy->cur -= len;
178 }
179
180 void
181 Dynarr_free (void *d)
182 {
183 Dynarr *dy = (Dynarr *) d;
184
185 if (dy->base)
186 xfree (dy->base);
187 xfree (dy);
188 }
189
190 #ifdef MEMORY_USAGE_STATS
191
192 /* Return memory usage for Dynarr D. The returned value is the total
193 amount of bytes actually being used for the Dynarr, including all
194 overhead. The extra amount of space in the Dynarr that is
195 allocated beyond what was requested is returned in DYNARR_OVERHEAD
196 in STATS. The extra amount of space that malloc() allocates beyond
197 what was requested of it is returned in MALLOC_OVERHEAD in STATS.
198 See the comment above the definition of this structure. */
199
200 int
201 Dynarr_memory_usage (void *d, struct overhead_stats *stats)
202 {
203 int total = 0;
204 Dynarr *dy = (Dynarr *) d;
205
206 /* We have to be a bit tricky here because not all of the
207 memory that malloc() will claim as "requested" was actually
208 requested. */
209
210 if (dy->base)
211 {
212 int malloc_used = malloced_storage_size (dy->base,
213 dy->elsize * dy->max, 0);
214 /* #### This may or may not be correct. Some Dynarrs would
215 prefer that we use dy->cur instead of dy->largest here. */
216 int was_requested = dy->elsize * dy->largest;
217 int dynarr_overhead = dy->elsize * (dy->max - dy->largest);
218
219 total += malloc_used;
220 stats->was_requested += was_requested;
221 stats->dynarr_overhead += dynarr_overhead;
222 /* And the remainder must be malloc overhead. */
223 stats->malloc_overhead +=
224 malloc_used - was_requested - dynarr_overhead;
225 }
226
227 total += malloced_storage_size (d, sizeof (*dy), stats);
228
229 return total;
230 }
231
232 #endif