1 /* vim: set noexpandtab tabstop=4 shiftwidth=4 wrap:
2 *----------------------------------------------------------------------------
4 *----------------------------------------------------------------------------
5 * This file is part of emufs.
7 * emufs is free software; you can redistribute it and/or modify it under the
8 * terms of the GNU General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option) any later
12 * emufs is distributed in the hope that it will be useful, but WITHOUT ANY
13 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along
18 * with emufs; if not, write to the Free Software Foundation, Inc., 59 Temple
19 * Place, Suite 330, Boston, MA 02111-1307 USA
20 *----------------------------------------------------------------------------
21 * Creado: mié may 26 19:46:31 ART 2004
22 * Autores: Leandro Lucarella <llucare@fi.uba.ar>
23 *----------------------------------------------------------------------------
33 * Implementación de un buffer ordenado. Al obtener un dato del buffer, se
34 * obtiene de forma ordenada.
43 /** Prueba si \c x es menor que \c y usando la función de comparación. */
44 #define LT(b, x, y) (b->cmp(x, y) < 0)
45 /** Prueba si \c x es mayor que \c y usando la función de comparación. */
46 #define GT(b, x, y) (b->cmp(x, y) > 0)
47 /** Prueba si \c x es igual a \c y usando la función de comparación. */
48 #define EQ(b, x, y) (b->cmp(x, y) == 0)
49 /** Prueba si \c x es distinto a \c y usando la función de comparación. */
50 #define NE(b, x, y) (b->cmp(x, y) != 0)
51 /** Prueba si \c x es menor o igual a \c y usando la función de comparación. */
52 #define LE(b, x, y) (b->cmp(x, y) <= 0)
53 /** Prueba si \c x es mayor o igual a \c y usando la función de comparación. */
54 #define GE(b, x, y) (b->cmp(x, y) >= 0)
56 /** Crea un nuevo nodo, se guarda una copia del dato en el nodo. */
57 static BUFFORD_NODE* bufford_node_new(void* data, size_t reg_size);
59 /** Borra un nodo, liberando la memoria propia pero no la del dato. */
60 static void bufford_node_delete(BUFFORD_NODE* node);
62 /** Borra un nodo del buffer recursivamente, borrando sus hijos también. */
63 static void bufford_clear_node_recursive(BUFFORD_NODE* node);
65 /** Inserta un nodo en el buffer sin modificar el tamaño. */
66 static void bufford_insert_node(BUFFORD* buff, BUFFORD_NODE* new_node);
68 BUFFORD_NODE* bufford_node_new(void* data, size_t reg_size)
70 BUFFORD_NODE* n = malloc(sizeof(BUFFORD_NODE));
73 /* hago una copia del dato */
74 n->data = malloc(reg_size);
76 memcpy(n->data, data, reg_size);
86 void bufford_node_delete(BUFFORD_NODE* node)
92 void bufford_clear_node_recursive(BUFFORD_NODE* node)
96 if (node->left) bufford_clear_node_recursive(node->left);
97 if (node->right) bufford_clear_node_recursive(node->right);
99 bufford_node_delete(node);
102 void bufford_insert_node(BUFFORD* buff, BUFFORD_NODE* new_node)
106 if (buff->root) { /* no está vacío */
107 BUFFORD_NODE* curr = buff->root;
110 if (LT(buff, new_node->data, curr->data)) {
111 if (curr->left) { /* hay más, paso al próximo */
115 /* no hay más, lo inserto */
116 curr->left = new_node;
119 if (GT(buff, new_node->data, curr->data)) {
120 if (curr->right) { /* hay más, paso al próximo */
124 /* no hay más, lo inserto */
125 curr->right = new_node;
128 /* es igual! => error */
129 assert(NE(buff, new_node->data, curr->data));
134 buff->root = new_node;
137 BUFFORD* bufford_new(size_t size, size_t reg_size, CMP_FUNC cmp)
139 BUFFORD* b = malloc(sizeof(BUFFORD));
143 assert(reg_size > 0);
148 b->reg_size = reg_size;
152 BUFFORD* bufford_new_bytes_size(size_t size, size_t reg_size, CMP_FUNC cmp)
154 BUFFORD* b = malloc(sizeof(BUFFORD));
157 assert(reg_size > 0);
158 assert(size > (reg_size + sizeof(BUFFORD_NODE)));
162 b->max_size = size / (reg_size + sizeof(BUFFORD_NODE));
163 b->reg_size = reg_size;
167 void bufford_delete(BUFFORD* buff)
174 void bufford_clear(BUFFORD* buff)
177 if (buff->root) bufford_clear_node_recursive(buff->root);
181 int bufford_full(BUFFORD* buff)
184 return buff->size == buff->max_size;
187 int bufford_empty(BUFFORD* buff)
190 return buff->size == 0;
193 int bufford_push(BUFFORD* buff, void* data)
195 BUFFORD_NODE* new_node;
198 if (buff->size == buff->max_size) return 0; /* ERROR, está lleno */
199 new_node = bufford_node_new(data, buff->reg_size);
200 if (!new_node) return 0; /* ERROR, no hay memoria */
201 if (buff->root) { /* no está vacío */
202 BUFFORD_NODE* curr = buff->root;
205 if (LT(buff, data, curr->data)) {
206 if (curr->left) { /* hay más, paso al próximo */
210 /* no hay más, lo inserto */
211 curr->left = new_node;
215 if (GT(buff, data, curr->data)) {
216 if (curr->right) { /* hay más, paso al próximo */
220 /* no hay más, lo inserto */
221 curr->right = new_node;
225 /* es igual! => error */
227 assert(NE(buff, data, curr->data));
228 return 0; /* ERROR, dato duplicado */
232 buff->root = new_node;
237 void* bufford_pop_min(BUFFORD* buff)
240 BUFFORD_NODE* curr = buff->root;
241 /* nodo previo al iterador */
242 BUFFORD_NODE* prev = 0;
243 /* valor mínimo encontrado, si se encontró */
246 if (!curr) return 0; /* si no hay nodos, no hay nada que hacer */
247 /* buscamos el mínimo nodo */
252 /* lo sacamos del árbol */
253 if (prev) { /* si tiene padre (no es el raíz) */
254 /* le cuelgo de la izquierda el hijo de la derecha, sabemos que a
255 * izquierda no tiene nada.*/
256 prev->left = curr->right;
257 } else { /* si es el raíz */
258 buff->root = curr->right; /* ponemos el nuevo raíz */
260 min_found = curr->data;
261 bufford_node_delete(curr);
266 void* bufford_pop_next(BUFFORD* buff, void* min)
269 BUFFORD_NODE* curr = buff->root;
270 /* nodo previo al iterador */
271 BUFFORD_NODE* prev = 0;
272 /* nodo con el dato más pequeño encontrado hasta ahora */
273 BUFFORD_NODE* curr_min = 0;
274 /* padre del nodo con el dato más pequeño encontrado hasta ahora */
275 BUFFORD_NODE* padre = 0;
276 /* valor mínimo encontrado, si se encontró */
280 /* buscamos el mínimo nodo mayor que 'min' */
282 if (GT(buff, curr->data, min)) { /* actual mayor que buscado */
283 /* guardo y paso al de la izquierda */
288 } else { /* actual no es mayor que buscado, paso a derecha */
293 /* si encontramos uno, lo sacamos del árbol */
295 BUFFORD_NODE* link; /* nodo al cual enganchar con el padre */
296 BUFFORD_NODE* orphan = 0; /* nodo huerfano */
297 if (curr_min->left) {
298 link = curr_min->left;
299 orphan = curr_min->right;
301 link = curr_min->right;
303 if (padre) { /* si tiene padre (no es el raíz) */
304 if (padre->left == curr_min) { /* si es el de la izq */
305 padre->left = link; /* enganchamos */
306 } else { /* si no, es el de la derecha */
307 padre->right = link; /* enganchamos */
309 } else { /* si es el raíz */
310 buff->root = link; /* ponemos el nuevo raíz */
312 if (orphan) { /* si quedó un huerfano, lo insertamos */
313 bufford_insert_node(buff, orphan);
315 min_found = curr_min->data;
316 bufford_node_delete(curr_min);
322 void* bufford_get_min(BUFFORD* buff)
325 BUFFORD_NODE* curr = buff->root;
327 if (!curr) return 0; /* si no hay nodos, no hay nada que hacer */
328 /* buscamos el mínimo nodo */
329 while (curr->left) curr = curr->left;
333 void* bufford_get_next(BUFFORD* buff, void* min)
336 BUFFORD_NODE* curr = buff->root;
337 /* nodo con el dato más pequeño encontrado hasta ahora */
338 BUFFORD_NODE* curr_min = 0;
341 /* buscamos el mínimo nodo mayor que 'min' */
343 if (GT(buff, curr->data, min)) { /* actual mayor que buscado */
344 /* guardo y paso al de la izquierda */
347 } else curr = curr->right; /* paso a la derecha */
349 if (curr_min) return curr_min->data;