xref: /haiku/src/apps/glteapot/util.h (revision a381c8a06378de22ff08adf4282b4e3f7e50d250)
1 /*
2 	Copyright 1999, Be Incorporated.   All Rights Reserved.
3 	This file may be used under the terms of the Be Sample Code License.
4 */
5 
6 #ifndef UTIL_H
7 #define UTIL_H
8 
9 #include <memory.h>
10 #include "error.h"
11 
12 template <class contents>
13 struct LispNode {
14 	contents* car;
15 	LispNode* cdr;
16 
17 	/* Create a node with no next */
18 	inline LispNode(contents* value)
19 		: car(value), cdr(0) { }
20 
21 	/* Create a node with specified next */
22 	inline LispNode(contents* value, LispNode* next)
23  		: car (value), cdr(next) { }
24 
25 	/* Create a node and insert it in a list right after `prev' */
26 	inline LispNode(LispNode* prev, contents* value)
27 		: car(value), cdr(prev->cdr) { prev->cdr = this; }
28 };
29 
30 
31 template <class contents>
32 struct LispList {
33 	LispNode<contents> *first;
34 
35 	/* -------- List creation --------------- */
36 	/* Create an empty list */
37 	inline LispList()
38 	{
39 		first = 0;
40 	}
41 
42 
43 	/* Create a list pointing to the specified node */
44 	inline LispList(LispNode<contents>* _first)
45 	{
46 		first = _first;
47 	}
48 
49 
50 	/* ?? */
51 	inline LispList(LispList &init)
52 	{
53 		first = init.first;
54 	}
55 
56 
57 	/* ---------- List queries ------------- */
58 	inline int is_empty()
59 	{
60 		return first == 0;
61 	}
62 
63 
64 	/* Determines if a thing is on the list */
65 	inline int is_present(contents* element)
66 	{
67 		for (LispNode<contents>* node = first; node; node = node->cdr)
68 			if (node->car == element)
69 				return 1;
70 		return 0;
71 	}
72 
73 
74 	/* Returns the length of the list */
75 	inline int count()
76 	{
77 		int n = 0;
78 		for (LispNode<contents>* node = first; node; node = node->cdr)
79 			n++;
80 	    return n;
81 	}
82 
83 
84 	/* ----------- Adding "nodes" to the list ------------ */
85 	/* Add a specified node to the head of the list.  */
86 	inline void add_head(LispNode<contents>* new_element)
87 	{
88 		new_element->cdr = first;
89 		first = new_element;
90 	}
91 
92 
93 	/* Add a specified node anywhere on the list */
94 	inline void add(LispNode<contents>* new_element)
95 	{
96 		add_head (new_element);
97 	}
98 
99 
100 	inline void add_tail(LispNode<contents>* new_element)
101 	{
102 		LispNode<contents>** pred = &first;
103 		while(*pred)
104 			pred = &(*pred)->cdr;
105 		*pred = new_element;
106 		new_element->cdr = 0;
107 	}
108 
109 
110 	/* ----------- Adding "contents" to the list ------------ */
111 	/* -----  (Which in my opinion is far more useful) ------ */
112 
113 	/* Create new node pointing to thing, & add to head of list. */
114 	inline void add_head_new(contents* new_element)
115 	{
116 		first = new LispNode<contents>(new_element, first);
117 	}
118 
119 
120 	inline void add_head(contents* new_element)
121 	{
122 		add_head_new(new_element);
123 	}
124 
125 
126 	/* Create new node pointing to thing, & add to end of list. */
127 	inline void add_tail_new(contents* new_element)
128 	{
129 		LispNode< contents >** pred = &first;
130 		while (*pred)
131 			pred = &(*pred)->cdr;
132 
133 		*pred = new LispNode< contents >(new_element);
134 	}
135 
136 
137 	inline void add_tail(contents* new_element)
138 	{
139 		add_tail_new(new_element);
140 	}
141 
142 
143 	/* Create new node pointing to thing, & add anywhere on list */
144 	inline void add_new(contents* new_element)
145 	{
146 		add_head_new(new_element);
147 	}
148 
149 
150 	inline void add(contents* new_element)
151 	{
152 		add_new(new_element);
153 	}
154 
155 
156 	/* Create and add a new node for a specified element,
157 		but only if it's not already on the list.  */
158 	inline void add_new_once(contents* new_element)
159 	{
160 		if (!is_present(new_element))
161 			add_head_new(new_element);
162 	}
163 
164 
165 	inline void add_tail_once(contents *new_element)
166 	{
167 		if (!is_present(new_element))
168 			add_tail_new(new_element);
169 	}
170 
171 
172 	/* ------- Removing things from the list ------------ */
173 
174 	/* Remove and return the first node on the list j.h. */
175 	inline LispNode<contents>* rem_head ()
176 	{
177 		LispNode<contents>* n = first;
178 
179 		if (n) {
180 			first = first->cdr;
181 		}
182 
183 		return n;
184 	}
185 
186 
187 	/* Remove and return any node on the list.  */
188 	inline LispNode<contents>* remove ()
189 	{
190 		return( rem_head() );
191 	}
192 
193 
194 	/* Remove a specified node from the list.  */
195 	inline void remove (LispNode<contents>* node)
196 	{
197 		for (LispNode<contents> **pp = &first; *pp; pp = &(*pp)->cdr)
198 			if (*pp == node) {
199 				*pp = (*pp)->cdr;
200 		  		return;
201 			}
202 	}
203 
204 
205 	/* Remove & delete all nodes pointing to a particular element. */
206 	inline void rem_del (contents* element)
207 	{
208 		LispNode<contents>** pp = &first;
209 		while (*pp) {
210 			if ((*pp)->car == element) {
211 				LispNode<contents> *o = *pp;
212 				*pp = o->cdr;
213 				delete o;
214 			} else
215 				pp = &(*pp)->cdr;
216 		}
217 	}
218 
219 
220 	/* Remove and delete all nodes on the list.  */
221 	inline void rem_del_all()
222 	{
223 		while (first) {
224 			LispNode<contents>* old = first;
225 			first = first->cdr;
226 			delete old;
227 		}
228 	}
229 
230 
231 	/* -------- Simple list storage (by j.h.) ------------ */
232 
233 	/* When you just want to hold a bunch of stuff on a list and then pull them
234 		off later.  Note that these calls do NOT check for to see if a thing is
235 		already on the list.  Use is_present() before adding.
236 	*/
237 	/* Put something anywhere on the list */
238 	inline void put( contents* c )
239 	{
240 		add_tail( c );
241 	}
242 
243 
244 	/* Put something at beginning of list */
245 	inline void put_head( contents* c )
246 	{
247 		add_head( c );
248 	}
249 
250 
251 	/* Put something at end of the list */
252 	inline void put_tail( contents* c )
253 	{
254 		add_tail( c );
255 	}
256 
257 #if 0 /* leaks memory */
258 	  /* Take a specific thing off the list */
259 	  inline contents *get(contents *element)
260 	    {
261 	      contents *c = 0;
262 	      for (LispNode<contents> *node = first; node; node = node->cdr)
263 	      {
264 		if (node->car == element)
265 		{
266 		  c = node->car;
267 		  remove(node);
268 		  break;
269 		}
270 	      }
271 	      return c;
272 	    }
273 #endif
274 
275 	/* Take the first thing off the list */
276 	inline contents* get_head()
277 	{
278 		contents *c = 0;
279 		if(first) {
280 			c = first->car;
281 			delete rem_head();
282 		}
283 		return c;
284 	}
285 
286 
287 	/* Take something off the list */
288 	inline contents* get()
289 	{
290 		return(get_head());
291 	}
292 
293 
294 	/* XXX inline contents *get_tail() { } */
295 
296 /* -------- Stack simulation (by j.h.) ------------ */
297 	/* Put a thing onto the head of the list */
298 	inline void push(contents* c)
299 	{
300 		put_head(c);
301 	}
302 
303 
304 	/* Remove a thing from the head of the list */
305 	inline contents* pop()
306 	{
307 		return(get_head());
308 	}
309 
310 	/* Pop everything off the stack.  Empty the stack/list. */
311 	inline void pop_all()
312 	{
313 		rem_del_all();
314 	}
315 
316 
317 	/* ----------- list/list manipulations ------------ */
318 
319 	/* Add all elements present on another list to this list also. */
320 	inline void add_new(LispList other)
321 	{
322 		for (LispNode<contents>* n = other.first; n; n = n->cdr)
323 			add_new(n->car);
324 	}
325 
326 
327 	inline void add_new_once(LispList other)
328 	{
329 		for (LispNode<contents>* n = other.first; n; n = n->cdr)
330 			add_new_once(n->car);
331 	}
332 
333 
334 	/* Remove and delete all nodes whose contents are also present
335 	   in a different list (set disjunction). */
336 	inline void rem_del(LispList other)
337 	{
338 		for (LispNode<contents>* n = other.first; n; n = n->cdr)
339 			rem_del(n->car);
340 	}
341 };
342 
343 template <class thetype>
344 struct DoubleLinkedNode
345 {
346 	thetype* next;
347 	thetype* prev;
348 
349 	DoubleLinkedNode()
350 	{
351 		next = prev = NULL;
352 	}
353 
354 
355 	void insert_after(thetype* n)
356 	{
357 		if (next != NULL)
358 			next->prev = n;
359 
360 		n->next = next;
361 		n->prev = (thetype*)this;
362 		next = n;
363 	}
364 
365 
366 	void insert_before(thetype* n)
367 	{
368 		prev->next = n;
369 		n->next = (thetype*)this;
370 		n->prev = prev;
371 		prev = n;
372 	}
373 
374 
375 	void remove()
376 	{
377 		assert(prev != NULL);
378 		prev->next = next;
379 
380 		if (next != NULL)
381 			next->prev = prev;
382 	}
383 };
384 
385 
386 template <class thetype>
387 struct DoubleLinkedList : public DoubleLinkedNode<thetype>
388 {
389 	DoubleLinkedList() : DoubleLinkedNode<thetype>() {};
390 
391 	void insert(thetype* n)
392 	{
393 		insert_after(n);
394 	}
395 
396 
397 	void add(thetype* n)
398 	{
399 		insert_after(n);
400 	}
401 };
402 
403 
404 template <class T>
405 struct BufferArray {
406 	T * items;
407 	int num_items;
408 	int num_slots;
409 	int slot_inc;
410 
411 	void resize(int i)
412 	{
413 		items = (T*)realloc(items,sizeof(T)*i);
414 		num_slots = i;
415 	}
416 
417 
418 	T & operator [](int index)
419 	{
420 		assert(index < num_items);
421 		return items[index];
422 	}
423 
424 
425 	T & get(int index)
426 	{
427 		assert(index < num_items);
428 		return items[index];
429 	}
430 
431 
432 	void add(T &item)
433 	{
434 		if (num_items == num_slots)
435 			resize(num_slots+slot_inc);
436 
437 		memcpy(items+num_items,&item,sizeof(item));
438 		num_items++;
439 	}
440 
441 
442 	BufferArray(int start_slots, int _slot_inc)
443 	{
444 		num_slots = start_slots;
445 		slot_inc = _slot_inc;
446 		assert(slot_inc > 0);
447 		num_items = 0;
448 		items = (T*)malloc(sizeof(T)*num_slots);
449 	}
450 
451 
452 	~BufferArray()
453 	{
454 		free(items);
455 	}
456 };
457 
458 #endif // UTIL_H
459