Updated Spanish translation
[anjuta-git-plugin.git] / plugins / debug-manager / sparse_buffer.c
blobea4209617d12a682dd6131e8174aeba85627a69d
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 sparse_buffer.c
4 Copyright (C) 2006 Sebastien Granjoux
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 #include "sparse_buffer.h"
23 #include "anjuta-marshal.h"
25 #include <string.h>
27 /*#define DEBUG*/
28 #include <libanjuta/anjuta-debug.h>
31 * This object works with the DmaSparseView which is a text view window allowing
32 * to display very big amount of data. Only the part of the data currently
33 * displayed is kept in memory.
35 * This object doesn't replace the GtkTextBuffer in the corresponding
36 * DmaSparseView. The GtkTextBuffer of each DmaSparseView contains only the data
37 * displayed by the view. So several view displaying the same DmaSparseBuffer
38 * will probably have GtkTextBuffer containing different data.
40 * The DmaSparseBuffer object contains the data necessary for each view and
41 * try to maintain a cache of recently used data. The data should be split in
42 * blocks having a address and a size. The buffer does not care about the
43 * exact content of each block.
45 * The DmaSparseBuffer does not have any graphical knowledge, like which data
46 * correspond to one line in the GtkTextBuffer.
47 *---------------------------------------------------------------------------*/
49 enum
51 DMA_SPARSE_BUFFER_NODE_SIZE = 512,
52 DMA_SPARSE_BUFFER_MAX_PAGE = 60,
55 static GObjectClass *parent_class = NULL;
57 enum
59 CHANGED,
60 LAST_SIGNAL
63 static guint signals[LAST_SIGNAL] = {0};
65 /* Helper functions
66 *---------------------------------------------------------------------------*/
68 /* DmaBufferNode functions
69 *---------------------------------------------------------------------------*/
71 /* Transport functions
72 *---------------------------------------------------------------------------*/
74 DmaSparseBufferTransport*
75 dma_sparse_buffer_alloc_transport (DmaSparseBuffer *buffer, guint lines, guint chars)
77 DmaSparseBufferTransport *trans;
79 trans = g_slice_new0 (DmaSparseBufferTransport);
81 trans->buffer = buffer;
82 trans->lines = lines;
83 trans->chars = chars;
84 trans->next = buffer->pending;
85 buffer->pending = trans;
87 return trans;
90 void
91 dma_sparse_buffer_free_transport (DmaSparseBufferTransport *trans)
93 DmaSparseBufferTransport **prev;
95 g_return_if_fail (trans != NULL);
97 for (prev = &trans->buffer->pending; *prev != trans; prev = &(*prev)->next)
99 if (*prev == NULL)
101 g_warning ("transport structure is missing");
102 return;
106 /* Remove transport structure and free it */
107 *prev = trans->next;
109 g_slice_free (DmaSparseBufferTransport, trans);
112 /* Private functions
113 *---------------------------------------------------------------------------*/
115 static DmaSparseBufferNode*
116 dma_sparse_buffer_find (DmaSparseBuffer *buffer, guint address)
118 DmaSparseBufferNode *node = NULL;
119 DmaSparseBufferNode *next;
121 /* Look in last node */
122 if (buffer->cache.head != NULL)
124 gint gap = buffer->cache.head->lower - address + DMA_SPARSE_BUFFER_NODE_SIZE * 4;
126 if (gap < DMA_SPARSE_BUFFER_NODE_SIZE * 9)
128 /* node should be quite near */
129 node = buffer->cache.head;
131 else
133 node = buffer->head;
136 else
138 node = buffer->head;
141 for (;;)
143 if (node == NULL) break;
145 if (node->lower > address)
147 /* Search backward */
148 node = node->prev;
150 else if (node->upper < address)
152 /* Search forward */
153 next = node->next;
155 if ((next == NULL) || (next->lower > address))
157 /* Corresponding node doesn't exist */
158 break;
160 node = next;
162 else
164 /* Find current node */
165 break;
169 return node;
172 static void
173 on_dma_sparse_buffer_changed (const DmaSparseBuffer *buffer)
177 /* Public functions
178 *---------------------------------------------------------------------------*/
180 DmaSparseBufferNode*
181 dma_sparse_buffer_lookup (DmaSparseBuffer *buffer, guint address)
183 return dma_sparse_buffer_find (buffer, address);
186 DmaSparseBufferNode*
187 dma_sparse_buffer_first (DmaSparseBuffer *buffer)
189 return buffer->head;
192 void
193 dma_sparse_buffer_insert (DmaSparseBuffer *buffer, DmaSparseBufferNode *node)
195 /* New node should have been allocated by caller with g_new */
196 DmaSparseBufferNode *prev;
198 DEBUG_PRINT ("insert block %p %x %x", node, node->lower, node->upper);
199 /* Look for previous node */
200 prev = dma_sparse_buffer_find (buffer, node->lower);
201 while ((prev != NULL) && (node->lower <= prev->upper))
203 DmaSparseBufferNode *tmp;
205 DEBUG_PRINT ("remove previous block %x %x", prev->lower, prev->upper);
206 /* node overlap, remove it */
207 tmp = prev->prev;
208 dma_sparse_buffer_remove (buffer, prev);
209 prev = tmp;
212 /* Insert node just after prev */
213 if (prev == NULL)
215 /* Insert at the beginning */
216 node->prev = NULL;
217 node->next = buffer->head;
218 buffer->head = node;
220 else
222 node->prev = prev;
223 node->next = prev->next;
224 prev->next = node;
226 if (node->next != NULL)
228 node->next->prev = node;
231 /* Check if new node overlap next one */
232 while ((node->next != NULL) && (node->upper >= node->next->lower))
234 DEBUG_PRINT ("remove next block %p %x %x", node->next, node->next->lower, node->next->upper);
235 /* node overlap, remove it */
236 dma_sparse_buffer_remove (buffer, node->next);
239 /* Insert node at the beginning of cache list */
240 node->cache.prev = NULL;
241 node->cache.next = buffer->cache.head;
242 if (buffer->cache.head != NULL)
244 buffer->cache.head->prev = node;
246 buffer->stamp++;
249 void
250 dma_sparse_buffer_remove (DmaSparseBuffer *buffer, DmaSparseBufferNode *node)
252 /* Remove node from node list */
253 if (node->next != NULL)
255 node->next->prev = node->prev;
257 if (node->prev != NULL)
259 node->prev->next = node->next;
261 if (buffer->head == node)
263 buffer->head = node->next;
266 /* Remove node from cache list */
267 if (node->cache.next != NULL)
269 node->cache.next->prev = node->cache.prev;
271 if (node->cache.prev != NULL)
273 node->cache.prev->next = node->cache.next;
275 if (buffer->cache.head == node)
277 buffer->cache.head = node->cache.next;
279 if (buffer->cache.tail == node)
281 buffer->cache.tail = node->cache.prev;
284 g_free (node);
286 buffer->stamp++;
289 void
290 dma_sparse_buffer_remove_all (DmaSparseBuffer *buffer)
292 DmaSparseBufferNode *node;
293 DmaSparseBufferNode *next;
295 for (node = buffer->head; node != NULL; node = next)
297 next = node->next;
298 g_free (node);
300 buffer->cache.head = NULL;
301 buffer->cache.tail = NULL;
302 buffer->head = NULL;
303 buffer->stamp++;
306 guint
307 dma_sparse_buffer_get_lower (const DmaSparseBuffer *buffer)
309 return buffer->lower;
312 guint
313 dma_sparse_buffer_get_upper (const DmaSparseBuffer *buffer)
315 return buffer->upper;
318 void
319 dma_sparse_buffer_changed (const DmaSparseBuffer *buffer)
321 g_signal_emit (G_OBJECT (buffer), signals[CHANGED], 0);
324 void
325 dma_sparse_buffer_add_mark (DmaSparseBuffer *buffer, guint address, gint mark)
327 gint markers;
329 if (buffer->mark == NULL)
331 /* Create new hash table */
332 buffer->mark = g_hash_table_new (g_direct_hash, g_direct_equal);
335 /* Add mark */
336 markers = GPOINTER_TO_INT (g_hash_table_lookup (buffer->mark, GINT_TO_POINTER (address)));
337 markers |= 1 << mark;
338 g_hash_table_replace (buffer->mark, GINT_TO_POINTER (address), GINT_TO_POINTER (markers));
341 void
342 dma_sparse_buffer_remove_mark (DmaSparseBuffer *buffer, guint address, gint mark)
344 gint markers;
346 if (buffer->mark == NULL) return; /* No mark */
348 /* Remove one mark */
349 markers = GPOINTER_TO_INT (g_hash_table_lookup (buffer->mark, GINT_TO_POINTER (address)));
350 markers &= ~ (1 << mark);
352 if (markers == 0)
354 g_hash_table_remove (buffer->mark, GINT_TO_POINTER (address));
356 else
358 g_hash_table_replace (buffer->mark, GINT_TO_POINTER (address), GINT_TO_POINTER (markers));
362 struct RemoveMarkPacket
364 GHashTable *hash;
365 gint mark;
368 static void
369 on_remove_mark (gpointer key, gpointer value, gpointer user_data)
371 struct RemoveMarkPacket* pack = (struct RemoveMarkPacket *)user_data;
373 value = GINT_TO_POINTER (GPOINTER_TO_INT (value) & ~(1<< pack->mark));
374 g_hash_table_replace (pack->hash, key, value);
377 static gboolean
378 on_remove_empty_mark (gpointer key, gpointer value, gpointer user_data)
380 return (value == NULL);
383 void
384 dma_sparse_buffer_remove_all_mark (DmaSparseBuffer *buffer, gint mark)
386 /* marker hash table could be null, is no marks have been set */
387 if (buffer->mark != NULL)
389 struct RemoveMarkPacket pack;
391 pack.hash = buffer->mark;
392 pack.mark = mark;
394 g_hash_table_foreach (buffer->mark, on_remove_mark, &pack);
395 g_hash_table_foreach_remove (buffer->mark, on_remove_empty_mark, NULL);
399 gint
400 dma_sparse_buffer_get_marks (DmaSparseBuffer *buffer, guint address)
402 if (buffer->mark == NULL) return 0;
404 return GPOINTER_TO_INT (g_hash_table_lookup (buffer->mark, GINT_TO_POINTER (address)));
407 /* Iterator private functions
408 *---------------------------------------------------------------------------*/
410 static gboolean
411 dma_sparse_iter_forward_line (DmaSparseIter *iter)
413 return DMA_GET_SPARSE_BUFFER_CLASS (iter->buffer)->forward_line (iter);
416 static gboolean
417 dma_sparse_iter_backward_line (DmaSparseIter *iter)
419 return DMA_GET_SPARSE_BUFFER_CLASS (iter->buffer)->backward_line (iter);
422 static void
423 dma_sparse_iter_insert_line (DmaSparseIter *iter, GtkTextIter *dst)
425 DMA_GET_SPARSE_BUFFER_CLASS (iter->buffer)->insert_line (iter, dst);
428 /* Iterator public functions
429 *---------------------------------------------------------------------------*/
431 void
432 dma_sparse_buffer_get_iterator_at_address (DmaSparseBuffer *buffer, DmaSparseIter *iter, guint address)
434 g_return_if_fail (iter != NULL);
435 g_return_if_fail (DMA_IS_SPARSE_BUFFER (buffer));
437 iter->buffer = buffer;
438 iter->node = dma_sparse_buffer_find (buffer, address);
439 iter->base = address;
440 iter->offset = 0;
441 iter->stamp = buffer->stamp;
442 iter->line = 0;
444 DMA_GET_SPARSE_BUFFER_CLASS (iter->buffer)->refresh_iter (iter);
447 void
448 dma_sparse_buffer_get_iterator_near_address (DmaSparseBuffer *buffer, DmaSparseIter *iter, guint address)
450 g_return_if_fail (iter != NULL);
451 g_return_if_fail (DMA_IS_SPARSE_BUFFER (buffer));
453 iter->buffer = buffer;
454 iter->node = dma_sparse_buffer_find (buffer, address);
455 iter->base = address;
456 iter->offset = 1;
457 iter->line = 0;
458 iter->stamp = buffer->stamp;
460 DMA_GET_SPARSE_BUFFER_CLASS (iter->buffer)->refresh_iter (iter);
463 void
464 dma_sparse_iter_copy (DmaSparseIter *dst, const DmaSparseIter *src)
466 memcpy(dst, src, sizeof (DmaSparseIter));
469 void
470 dma_sparse_iter_move_at (DmaSparseIter *iter, guint address)
472 dma_sparse_buffer_get_iterator_at_address (iter->buffer, iter, address);
475 void
476 dma_sparse_iter_move_near (DmaSparseIter *iter, guint address)
478 dma_sparse_buffer_get_iterator_near_address (iter->buffer, iter, address);
481 void
482 dma_sparse_iter_refresh (DmaSparseIter *iter)
484 if (iter->buffer->stamp != iter->stamp)
486 iter->node = dma_sparse_buffer_find (iter->buffer, iter->base);
487 iter->stamp = iter->buffer->stamp;
488 DMA_GET_SPARSE_BUFFER_CLASS (iter->buffer)->refresh_iter (iter);
492 void
493 dma_sparse_iter_round (DmaSparseIter *iter, gboolean round_up)
495 if (iter->buffer->stamp != iter->stamp)
497 iter->node = dma_sparse_buffer_find (iter->buffer, iter->base);
498 iter->stamp = iter->buffer->stamp;
500 DMA_GET_SPARSE_BUFFER_CLASS (iter->buffer)->round_iter (iter, round_up);
503 gulong
504 dma_sparse_iter_get_address (DmaSparseIter *iter)
506 return DMA_GET_SPARSE_BUFFER_CLASS (iter->buffer)->get_address (iter);
509 gboolean
510 dma_sparse_iter_forward_lines (DmaSparseIter *iter, gint count)
512 gint i;
514 dma_sparse_iter_refresh (iter);
516 if (count < 0)
518 for (i = 0; i > count; --i)
520 if (!dma_sparse_iter_backward_line (iter)) return FALSE;
523 else if (count > 0)
525 for (i = 0; i < count; i++)
527 if (!dma_sparse_iter_forward_line (iter)) return FALSE;
531 return TRUE;
534 void
535 dma_sparse_iter_insert_lines (DmaSparseIter *src, GtkTextIter *dst, guint count)
537 DmaSparseIter iter;
538 guint line = 0;
539 GtkTextBuffer *buffer;
541 buffer = gtk_text_iter_get_buffer (dst);
543 /* It is possible to get an iterator that doesn't point to any node
544 * if it has been move to a fixed address without rounding it to
545 * the nearest line */
547 dma_sparse_iter_copy (&iter, src);
548 dma_sparse_iter_refresh (&iter);
550 /* Fill with data */
551 for (; line < count; line++)
553 dma_sparse_iter_insert_line (&iter, dst);
554 if (!dma_sparse_iter_forward_line (&iter))
556 /* no more data */
557 break;
559 if (line != count - 1) gtk_text_buffer_insert (buffer, dst, "\n", 1);
563 /* GObject functions
564 *---------------------------------------------------------------------------*/
566 /* Used in dispose and finalize */
568 /* dispose is the first destruction step. It is used to unref object created
569 * with instance_init in order to break reference counting cycles. This
570 * function could be called several times. All function should still work
571 * after this call. It has to called its parents.*/
573 static void
574 dma_sparse_buffer_dispose (GObject *object)
576 /*DmaSparseBuffer *self = DMA_DATA_BUFFER (object);*/
578 G_OBJECT_CLASS (parent_class)->dispose (object);
581 /* finalize is the last destruction step. It must free all memory allocated
582 * with instance_init. It is called only one time just before releasing all
583 * memory */
585 static void
586 dma_sparse_buffer_finalize (GObject *object)
588 DmaSparseBuffer *buffer = DMA_SPARSE_BUFFER (object);
589 DmaSparseBufferTransport *trans;
591 dma_sparse_buffer_remove_all (buffer);
593 /* Free all remaining transport structure */
594 for (trans = buffer->pending; trans != NULL;)
596 DmaSparseBufferTransport *next = trans->next;
598 g_slice_free (DmaSparseBufferTransport, trans);
599 trans = next;
602 /* Free marker hash table */
603 if (buffer->mark != NULL)
605 g_hash_table_destroy (buffer->mark);
606 buffer->mark = NULL;
609 G_OBJECT_CLASS (parent_class)->finalize (object);
612 /* instance_init is the constructor. All functions should work after this
613 * call. */
615 static void
616 dma_sparse_buffer_instance_init (DmaSparseBuffer *buffer)
618 buffer->lower = 0;
619 buffer->upper = 0;
621 buffer->cache.head = NULL;
622 buffer->cache.tail = NULL;
623 buffer->head = NULL;
624 buffer->stamp = 0;
625 buffer->pending = NULL;
626 buffer->mark = NULL;
629 /* class_init intialize the class itself not the instance */
631 static void
632 dma_sparse_buffer_class_init (DmaSparseBufferClass * klass)
634 GObjectClass *object_class;
636 g_return_if_fail (klass != NULL);
638 parent_class = g_type_class_peek_parent (klass);
640 object_class = G_OBJECT_CLASS (klass);
642 object_class->dispose = dma_sparse_buffer_dispose;
643 object_class->finalize = dma_sparse_buffer_finalize;
645 klass->changed = on_dma_sparse_buffer_changed;
647 signals[CHANGED] = g_signal_new ("changed",
648 G_OBJECT_CLASS_TYPE (object_class),
649 G_SIGNAL_RUN_LAST,
650 G_STRUCT_OFFSET (DmaSparseBufferClass, changed),
651 NULL, NULL,
652 anjuta_marshal_VOID__VOID,
653 G_TYPE_NONE,
657 GType
658 dma_sparse_buffer_get_type (void)
660 static GType type = 0;
662 if (!type)
664 static const GTypeInfo type_info =
666 sizeof (DmaSparseBufferClass),
667 (GBaseInitFunc) NULL,
668 (GBaseFinalizeFunc) NULL,
669 (GClassInitFunc) dma_sparse_buffer_class_init,
670 (GClassFinalizeFunc) NULL,
671 NULL, /* class_data */
672 sizeof (DmaSparseBuffer),
673 0, /* n_preallocs */
674 (GInstanceInitFunc) dma_sparse_buffer_instance_init,
675 NULL /* value_table */
678 type = g_type_register_static (G_TYPE_OBJECT,
679 "DmaSparseBuffer", &type_info, 0);
682 return type;
685 /* Creation and Destruction
686 *---------------------------------------------------------------------------*/
688 DmaSparseBuffer*
689 dma_sparse_buffer_new (guint lower, guint upper)
691 DmaSparseBuffer *buffer;
693 buffer = g_object_new (DMA_SPARSE_BUFFER_TYPE, NULL);
694 g_assert (buffer != NULL);
696 buffer->lower = lower;
697 buffer->upper = upper;
699 return buffer;
702 void
703 dma_sparse_buffer_free (DmaSparseBuffer *buffer)
705 g_object_unref (buffer);