Commit 12a001cb authored by Morten Welinder's avatar Morten Welinder Committed by Morten Welinder

Avoid listifying. (cb_dependent_queue_recalc, cell_queue_recalc): Recast

2001-08-29  Morten Welinder  <terra@diku.dk>

	* src/eval.c (workbook_queue_all_recalc): Avoid listifying.
	(cb_dependent_queue_recalc, cell_queue_recalc): Recast in terms of
 	dependent_queue_recalc_list.
	(dependent_queue_recalc_list): Eliminate recursion which used to
 	be unbounded deep.

	* src/eval.h (struct _Dependent): Name next to next_dep and prev
 	to prev_dep.  (Because we might need a similar list for evaluation
 	at some point.)

	(DEPENDENT_TYPE): New macro type hide most uses of the ugly
 	DEPENDENT_TYPE_MASK.  All such uses fixed.
parent 52fb8834
2001-08-29 Morten Welinder <terra@diku.dk>
* src/eval.c (workbook_queue_all_recalc): Avoid listifying.
(cb_dependent_queue_recalc, cell_queue_recalc): Recast in terms of
dependent_queue_recalc_list.
(dependent_queue_recalc_list): Eliminate recursion which used to
be unbounded deep.
* src/eval.h (struct _Dependent): Name next to next_dep and prev
to prev_dep. (Because we might need a similar list for evaluation
at some point.)
(DEPENDENT_TYPE): New macro type hide most uses of the ugly
DEPENDENT_TYPE_MASK. All such uses fixed.
2001-08-29 Jody Goldberg <jgoldberg@home.com>
* src/eval.c (dependent_queue_recalc_list) : fix my breakage and don't
......
2001-08-29 Morten Welinder <terra@diku.dk>
* src/eval.c (workbook_queue_all_recalc): Avoid listifying.
(cb_dependent_queue_recalc, cell_queue_recalc): Recast in terms of
dependent_queue_recalc_list.
(dependent_queue_recalc_list): Eliminate recursion which used to
be unbounded deep.
* src/eval.h (struct _Dependent): Name next to next_dep and prev
to prev_dep. (Because we might need a similar list for evaluation
at some point.)
(DEPENDENT_TYPE): New macro type hide most uses of the ugly
DEPENDENT_TYPE_MASK. All such uses fixed.
2001-08-29 Jody Goldberg <jgoldberg@home.com>
* src/eval.c (dependent_queue_recalc_list) : fix my breakage and don't
......
2001-08-29 Morten Welinder <terra@diku.dk>
* src/eval.c (workbook_queue_all_recalc): Avoid listifying.
(cb_dependent_queue_recalc, cell_queue_recalc): Recast in terms of
dependent_queue_recalc_list.
(dependent_queue_recalc_list): Eliminate recursion which used to
be unbounded deep.
* src/eval.h (struct _Dependent): Name next to next_dep and prev
to prev_dep. (Because we might need a similar list for evaluation
at some point.)
(DEPENDENT_TYPE): New macro type hide most uses of the ugly
DEPENDENT_TYPE_MASK. All such uses fixed.
2001-08-29 Jody Goldberg <jgoldberg@home.com>
* src/eval.c (dependent_queue_recalc_list) : fix my breakage and don't
......
2001-08-29 Morten Welinder <terra@diku.dk>
* src/eval.c (workbook_queue_all_recalc): Avoid listifying.
(cb_dependent_queue_recalc, cell_queue_recalc): Recast in terms of
dependent_queue_recalc_list.
(dependent_queue_recalc_list): Eliminate recursion which used to
be unbounded deep.
* src/eval.h (struct _Dependent): Name next to next_dep and prev
to prev_dep. (Because we might need a similar list for evaluation
at some point.)
(DEPENDENT_TYPE): New macro type hide most uses of the ugly
DEPENDENT_TYPE_MASK. All such uses fixed.
2001-08-29 Jody Goldberg <jgoldberg@home.com>
* src/eval.c (dependent_queue_recalc_list) : fix my breakage and don't
......
......@@ -149,7 +149,7 @@ cb_compare_deps (gconstpointer a, gconstpointer b)
static void
cb_collect_deps (Dependent *dep, gpointer user)
{
if ((dep->flags & DEPENDENT_TYPE_MASK) == DEPENDENT_CELL) {
if (DEPENDENT_TYPE (dep) == DEPENDENT_CELL) {
GList **list = (GList **)user;
*list = g_list_prepend (*list, dep);
}
......
......@@ -35,15 +35,15 @@
#include "cell.h"
#include "sheet.h"
#define UNLINK_DEP(wb,dep) \
do { \
if (wb->dependents == dep) \
wb->dependents = dep->next; \
if (dep->next) \
dep->next->prev = dep->prev; \
if (dep->prev) \
dep->prev->next = dep->next; \
/* Note, that ->prev and ->next are still valid. */ \
#define UNLINK_DEP(wb,dep) \
do { \
if (wb->dependents == dep) \
wb->dependents = dep->next_dep; \
if (dep->next_dep) \
dep->next_dep->prev_dep = dep->prev_dep; \
if (dep->prev_dep) \
dep->prev_dep->next_dep = dep->next_dep; \
/* Note, that ->prev_dep and ->next_dep are still valid. */ \
} while (0)
......@@ -101,7 +101,7 @@ dependent_type_register (DependentClass const *klass)
void
dependent_set_expr (Dependent *dep, ExprTree *expr)
{
int const t = (dep->flags & DEPENDENT_TYPE_MASK);
int const t = DEPENDENT_TYPE (dep);
if (t == DEPENDENT_CELL) {
/*
......@@ -124,19 +124,22 @@ dependent_set_expr (Dependent *dep, ExprTree *expr)
* Marks @dep as needing recalculation
* NOTE : it does NOT recursively dirty dependencies.
*/
#define dependent_queue_recalc(dep) dep->flags |= DEPENDENT_NEEDS_RECALC
#define dependent_queue_recalc(dep) \
do { (dep)->flags |= DEPENDENT_NEEDS_RECALC; } while (0)
void
cb_dependent_queue_recalc (Dependent *dep, gpointer ignore)
static void
cb_cell_list_deps (Dependent *dep, gpointer user)
{
g_return_if_fail (dep != NULL);
GSList **list = (GSList **)user;
*list = g_slist_prepend (*list, dep);
}
if (!(dep->flags & DEPENDENT_NEEDS_RECALC)) {
dependent_queue_recalc (dep);
if ((dep->flags & DEPENDENT_TYPE_MASK) == DEPENDENT_CELL)
cell_foreach_dep (DEP_TO_CELL (dep),
cb_dependent_queue_recalc, NULL);
}
static GSList *
cell_list_deps (const Cell *cell)
{
GSList *deps = NULL;
cell_foreach_dep (cell, cb_cell_list_deps, &deps);
return deps;
}
......@@ -146,30 +149,81 @@ cb_dependent_queue_recalc (Dependent *dep, gpointer ignore)
* @recurse : optionally recursively dirty things
*
* Queues any elements of @list for recalc that are not already queued,
* and marks all elements as needing a recalc. Yes this code is the same as
* above, but this is a high volume operation.
* and marks all elements as needing a recalc.
*/
static void
dependent_queue_recalc_list (GSList const *list, gboolean recurse)
dependent_queue_recalc_list (GSList *list, gboolean recurse)
{
GSList *work = NULL;
for (; list != NULL ; list = list->next) {
Dependent *dep = list->data;
if (!(dep->flags & DEPENDENT_NEEDS_RECALC)) {
dependent_queue_recalc (dep);
if (recurse)
work = g_slist_prepend (work, dep);
}
}
/* FIXME : it would be better if we queued the entire list then
* recursed. That would save time, but we need to keep track
* of deps that are already queued
*/
if (recurse &&
(dep->flags & DEPENDENT_TYPE_MASK) == DEPENDENT_CELL)
cell_foreach_dep (DEP_TO_CELL (dep),
cb_dependent_queue_recalc, NULL);
/*
* Work is now a list of marked cells whose dependencies need
* to be marked. Marking early guarentees that we will not
* get duplicates. (And it thus limits the length of the list.)
* We treat work as a stack.
*/
while (work) {
Dependent *dep = work->data;
/* Pop the top element. */
list = work;
work = work->next;
g_slist_free_1 (list);
if ((DEPENDENT_TYPE (dep)) == DEPENDENT_CELL) {
GSList *deps = cell_list_deps (DEP_TO_CELL (dep));
for (list = deps; list != NULL ; list = list->next) {
Dependent *dep = list->data;
if (!(dep->flags & DEPENDENT_NEEDS_RECALC)) {
dependent_queue_recalc (dep);
work = g_slist_prepend (work, dep);
}
}
g_slist_free (deps);
}
}
}
void
cb_dependent_queue_recalc (Dependent *dep, gpointer ignore)
{
g_return_if_fail (dep != NULL);
if (!(dep->flags & DEPENDENT_NEEDS_RECALC)) {
GSList *list = g_slist_prepend (NULL, dep);
dependent_queue_recalc_list (list, TRUE);
g_slist_free (list);
}
}
/*
* dependent_unqueue:
* @dep: the dependent to remove from the recomputation queue
*
* Removes a dependent that has been previously added to the recalc
* queue. Used internally when a dependent that was queued is changed or
* removed.
*/
void
dependent_unqueue (Dependent *dep)
{
g_return_if_fail (dep != NULL);
dep->flags &= ~(DEPENDENT_NEEDS_RECALC);
}
/**************************************************************************
* Data structures for managing dependencies between objects.
*
......@@ -513,10 +567,10 @@ dependent_link (Dependent *dep, CellPos const *pos)
wb = dep->sheet->workbook;
/* Make this the new head of the dependent list. */
dep->prev = NULL;
dep->next = wb->dependents;
if (dep->next)
dep->next->prev = dep;
dep->prev_dep = NULL;
dep->next_dep = wb->dependents;
if (dep->next_dep)
dep->next_dep->prev_dep = dep;
wb->dependents = dep;
dep->flags |= DEPENDENT_IN_EXPR_LIST;
......@@ -662,9 +716,14 @@ cell_queue_recalc (Cell const *cell)
g_return_if_fail (cell != NULL);
if (!cell_needs_recalc (cell)) {
GSList *deps;
if (cell_has_expr (cell))
dependent_queue_recalc (CELL_TO_DEP (cell));
cell_foreach_dep (cell, cb_dependent_queue_recalc, NULL);
deps = cell_list_deps (cell);
dependent_queue_recalc_list (deps, TRUE);
g_slist_free (deps);
}
}
......@@ -814,7 +873,7 @@ sheet_region_queue_recalc (Sheet const *sheet, Range const *r)
WORKBOOK_FOREACH_DEPENDENT (sheet->workbook, dep, {
Cell *cell = DEP_TO_CELL (dep);
if (dep->sheet == sheet &&
((dep->flags & DEPENDENT_TYPE_MASK) == DEPENDENT_CELL) &&
(DEPENDENT_TYPE (dep) == DEPENDENT_CELL) &&
range_contains (r, cell->pos.col, cell->pos.row))
dependent_queue_recalc (dep);
});
......@@ -1000,8 +1059,9 @@ void
workbook_queue_all_recalc (Workbook *wb)
{
/* FIXME : warning what about dependents in other workbooks */
WORKBOOK_FOREACH_DEPENDENT (wb, dep,
dependent_queue_recalc (dep););
WORKBOOK_FOREACH_DEPENDENT
(wb, dep, { dependent_queue_recalc (dep); });
}
/*
......@@ -1015,7 +1075,7 @@ workbook_recalc (Workbook *wb)
WORKBOOK_FOREACH_DEPENDENT (wb, dep,
if (dep->flags & DEPENDENT_NEEDS_RECALC) {
int const t = (dep->flags & DEPENDENT_TYPE_MASK);
int const t = DEPENDENT_TYPE (dep);
if (t != DEPENDENT_CELL) {
DependentClass *klass = g_ptr_array_index (dep_classes, t);
......@@ -1204,7 +1264,7 @@ dependent_debug_name (Dependent const *dep, FILE *out)
else
g_warning ("Invalid dep, missing sheet");
t = (dep->flags & DEPENDENT_TYPE_MASK);
t = DEPENDENT_TYPE (dep);
if (t != DEPENDENT_CELL) {
DependentClass *klass = g_ptr_array_index (dep_classes, t);
......
......@@ -11,7 +11,7 @@ struct _Dependent
ExprTree *expression;
/* Double-linked list. */
struct _Dependent *next, *prev;
struct _Dependent *next_dep, *prev_dep;
};
typedef struct {
......@@ -31,6 +31,8 @@ typedef enum {
DEPENDENT_TYPE_MASK = 0x00000fff,
} DependentFlags;
#define DEPENDENT_TYPE(dep) ((dep)->flags & DEPENDENT_TYPE_MASK)
typedef void (*DepFunc) (Dependent *dep, gpointer user);
guint32 dependent_type_register (DependentClass const *klass);
......
......@@ -35,15 +35,15 @@
#include "cell.h"
#include "sheet.h"
#define UNLINK_DEP(wb,dep) \
do { \
if (wb->dependents == dep) \
wb->dependents = dep->next; \
if (dep->next) \
dep->next->prev = dep->prev; \
if (dep->prev) \
dep->prev->next = dep->next; \
/* Note, that ->prev and ->next are still valid. */ \
#define UNLINK_DEP(wb,dep) \
do { \
if (wb->dependents == dep) \
wb->dependents = dep->next_dep; \
if (dep->next_dep) \
dep->next_dep->prev_dep = dep->prev_dep; \
if (dep->prev_dep) \
dep->prev_dep->next_dep = dep->next_dep; \
/* Note, that ->prev_dep and ->next_dep are still valid. */ \
} while (0)
......@@ -101,7 +101,7 @@ dependent_type_register (DependentClass const *klass)
void
dependent_set_expr (Dependent *dep, ExprTree *expr)
{
int const t = (dep->flags & DEPENDENT_TYPE_MASK);
int const t = DEPENDENT_TYPE (dep);
if (t == DEPENDENT_CELL) {
/*
......@@ -124,19 +124,22 @@ dependent_set_expr (Dependent *dep, ExprTree *expr)
* Marks @dep as needing recalculation
* NOTE : it does NOT recursively dirty dependencies.
*/
#define dependent_queue_recalc(dep) dep->flags |= DEPENDENT_NEEDS_RECALC
#define dependent_queue_recalc(dep) \
do { (dep)->flags |= DEPENDENT_NEEDS_RECALC; } while (0)
void
cb_dependent_queue_recalc (Dependent *dep, gpointer ignore)
static void
cb_cell_list_deps (Dependent *dep, gpointer user)
{
g_return_if_fail (dep != NULL);
GSList **list = (GSList **)user;
*list = g_slist_prepend (*list, dep);
}
if (!(dep->flags & DEPENDENT_NEEDS_RECALC)) {
dependent_queue_recalc (dep);
if ((dep->flags & DEPENDENT_TYPE_MASK) == DEPENDENT_CELL)
cell_foreach_dep (DEP_TO_CELL (dep),
cb_dependent_queue_recalc, NULL);
}
static GSList *
cell_list_deps (const Cell *cell)
{
GSList *deps = NULL;
cell_foreach_dep (cell, cb_cell_list_deps, &deps);
return deps;
}
......@@ -146,30 +149,81 @@ cb_dependent_queue_recalc (Dependent *dep, gpointer ignore)
* @recurse : optionally recursively dirty things
*
* Queues any elements of @list for recalc that are not already queued,
* and marks all elements as needing a recalc. Yes this code is the same as
* above, but this is a high volume operation.
* and marks all elements as needing a recalc.
*/
static void
dependent_queue_recalc_list (GSList const *list, gboolean recurse)
dependent_queue_recalc_list (GSList *list, gboolean recurse)
{
GSList *work = NULL;
for (; list != NULL ; list = list->next) {
Dependent *dep = list->data;
if (!(dep->flags & DEPENDENT_NEEDS_RECALC)) {
dependent_queue_recalc (dep);
if (recurse)
work = g_slist_prepend (work, dep);
}
}
/* FIXME : it would be better if we queued the entire list then
* recursed. That would save time, but we need to keep track
* of deps that are already queued
*/
if (recurse &&
(dep->flags & DEPENDENT_TYPE_MASK) == DEPENDENT_CELL)
cell_foreach_dep (DEP_TO_CELL (dep),
cb_dependent_queue_recalc, NULL);
/*
* Work is now a list of marked cells whose dependencies need
* to be marked. Marking early guarentees that we will not
* get duplicates. (And it thus limits the length of the list.)
* We treat work as a stack.
*/
while (work) {
Dependent *dep = work->data;
/* Pop the top element. */
list = work;
work = work->next;
g_slist_free_1 (list);
if ((DEPENDENT_TYPE (dep)) == DEPENDENT_CELL) {
GSList *deps = cell_list_deps (DEP_TO_CELL (dep));
for (list = deps; list != NULL ; list = list->next) {
Dependent *dep = list->data;
if (!(dep->flags & DEPENDENT_NEEDS_RECALC)) {
dependent_queue_recalc (dep);
work = g_slist_prepend (work, dep);
}
}
g_slist_free (deps);
}
}
}
void
cb_dependent_queue_recalc (Dependent *dep, gpointer ignore)
{
g_return_if_fail (dep != NULL);
if (!(dep->flags & DEPENDENT_NEEDS_RECALC)) {
GSList *list = g_slist_prepend (NULL, dep);
dependent_queue_recalc_list (list, TRUE);
g_slist_free (list);
}
}
/*
* dependent_unqueue:
* @dep: the dependent to remove from the recomputation queue
*
* Removes a dependent that has been previously added to the recalc
* queue. Used internally when a dependent that was queued is changed or
* removed.
*/
void
dependent_unqueue (Dependent *dep)
{
g_return_if_fail (dep != NULL);
dep->flags &= ~(DEPENDENT_NEEDS_RECALC);
}
/**************************************************************************
* Data structures for managing dependencies between objects.
*
......@@ -513,10 +567,10 @@ dependent_link (Dependent *dep, CellPos const *pos)
wb = dep->sheet->workbook;
/* Make this the new head of the dependent list. */
dep->prev = NULL;
dep->next = wb->dependents;
if (dep->next)
dep->next->prev = dep;
dep->prev_dep = NULL;
dep->next_dep = wb->dependents;
if (dep->next_dep)
dep->next_dep->prev_dep = dep;
wb->dependents = dep;
dep->flags |= DEPENDENT_IN_EXPR_LIST;
......@@ -662,9 +716,14 @@ cell_queue_recalc (Cell const *cell)
g_return_if_fail (cell != NULL);
if (!cell_needs_recalc (cell)) {
GSList *deps;
if (cell_has_expr (cell))
dependent_queue_recalc (CELL_TO_DEP (cell));
cell_foreach_dep (cell, cb_dependent_queue_recalc, NULL);
deps = cell_list_deps (cell);
dependent_queue_recalc_list (deps, TRUE);
g_slist_free (deps);
}
}
......@@ -814,7 +873,7 @@ sheet_region_queue_recalc (Sheet const *sheet, Range const *r)
WORKBOOK_FOREACH_DEPENDENT (sheet->workbook, dep, {
Cell *cell = DEP_TO_CELL (dep);
if (dep->sheet == sheet &&
((dep->flags & DEPENDENT_TYPE_MASK) == DEPENDENT_CELL) &&
(DEPENDENT_TYPE (dep) == DEPENDENT_CELL) &&
range_contains (r, cell->pos.col, cell->pos.row))
dependent_queue_recalc (dep);
});
......@@ -1000,8 +1059,9 @@ void
workbook_queue_all_recalc (Workbook *wb)
{
/* FIXME : warning what about dependents in other workbooks */
WORKBOOK_FOREACH_DEPENDENT (wb, dep,
dependent_queue_recalc (dep););
WORKBOOK_FOREACH_DEPENDENT
(wb, dep, { dependent_queue_recalc (dep); });
}
/*
......@@ -1015,7 +1075,7 @@ workbook_recalc (Workbook *wb)
WORKBOOK_FOREACH_DEPENDENT (wb, dep,
if (dep->flags & DEPENDENT_NEEDS_RECALC) {
int const t = (dep->flags & DEPENDENT_TYPE_MASK);
int const t = DEPENDENT_TYPE (dep);
if (t != DEPENDENT_CELL) {
DependentClass *klass = g_ptr_array_index (dep_classes, t);
......@@ -1204,7 +1264,7 @@ dependent_debug_name (Dependent const *dep, FILE *out)
else
g_warning ("Invalid dep, missing sheet");
t = (dep->flags & DEPENDENT_TYPE_MASK);
t = DEPENDENT_TYPE (dep);
if (t != DEPENDENT_CELL) {
DependentClass *klass = g_ptr_array_index (dep_classes, t);
......
......@@ -11,7 +11,7 @@ struct _Dependent
ExprTree *expression;
/* Double-linked list. */
struct _Dependent *next, *prev;
struct _Dependent *next_dep, *prev_dep;
};
typedef struct {
......@@ -31,6 +31,8 @@ typedef enum {
DEPENDENT_TYPE_MASK = 0x00000fff,
} DependentFlags;
#define DEPENDENT_TYPE(dep) ((dep)->flags & DEPENDENT_TYPE_MASK)
typedef void (*DepFunc) (Dependent *dep, gpointer user);
guint32 dependent_type_register (DependentClass const *klass);
......
......@@ -45,7 +45,7 @@ eval_pos_init_dep (EvalPos *eval_pos, Dependent const *dep)
{
g_return_val_if_fail (dep != NULL, NULL);
if (DEPENDENT_CELL == (dep->flags & DEPENDENT_TYPE_MASK)) {
if (DEPENDENT_TYPE (dep) == DEPENDENT_CELL) {
Cell const *cell = DEP_TO_CELL (dep);
return eval_pos_init (eval_pos, dep->sheet, &cell->pos);
} else {
......
......@@ -1947,8 +1947,7 @@ TOGGLE_HANDLER (display_formulas,{
Workbook *wb = wb_control_workbook (WORKBOOK_CONTROL (wbcg));
WORKBOOK_FOREACH_DEPENDENT
(wb, dep, {
int const t = (dep->flags & DEPENDENT_TYPE_MASK);
if (t == DEPENDENT_CELL)
if (DEPENDENT_TYPE (dep) == DEPENDENT_CELL)
sheet_cell_calc_span (DEP_TO_CELL (dep), SPANCALC_RE_RENDER);
});
sheet_adjust_preferences (sheet, TRUE, FALSE);
......
......@@ -158,7 +158,7 @@ do { \
do { \
Dependent *dep = (wb)->dependents; \
while (dep) { \
Dependent *_next = dep->next; \
Dependent *_next = dep->next_dep; \
code; \
dep = _next; \
} \
......
......@@ -694,7 +694,7 @@ workbook_expr_relocate (Workbook *wb, ExprRelocateInfo const *info)
newtree = expr_rewrite (dep->expression, &rwinfo);
if (newtree) {
int const t = (dep->flags & DEPENDENT_TYPE_MASK);
int const t = DEPENDENT_TYPE (dep);
/* Don't store relocations if they were inside the region
* being moved. That is handled elsewhere */
......
......@@ -158,7 +158,7 @@ do { \
do { \
Dependent *dep = (wb)->dependents; \
while (dep) { \
Dependent *_next = dep->next; \
Dependent *_next = dep->next_dep; \
code; \
dep = _next; \
} \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment