GC gc_cache_lookup (struct gc_cache *cache, XGCValues *gcv, unsigned long mask) { struct gc_cache_cell *cell, *next, *prev; struct gcv_and_mask gcvm; if ((!!cache->head) != (!!cache->tail)) abort (); if (cache->head && (cache->head->prev || cache->tail->next)) abort (); gcvm.mask = mask; gcvm.gcv = *gcv; /* this copies... */ #ifdef GCCACHE_HASH if (gethash (&gcvm, cache->table, (void *) &cell)) #else /* !GCCACHE_HASH */ cell = cache->tail; /* start at the end (most recently used) */ while (cell) { if (gc_cache_eql (&gcvm, &cell->gcvm)) break; else cell = cell->prev; } if (cell) #endif /* !GCCACHE_HASH */ { /* Found a cell. Move this cell to the end of the list, so that it will be less likely to be collected than a cell that was accessed less recently. */ if (cell == cache->tail) return cell->gc; next = cell->next; prev = cell->prev; if (prev) prev->next = next; if (next) next->prev = prev; if (cache->head == cell) cache->head = next; cell->next = 0; cell->prev = cache->tail; cache->tail->next = cell; cache->tail = cell; if (cache->head == cell) abort (); if (cell->next) abort (); if (cache->head->prev) abort (); if (cache->tail->next) abort (); return cell->gc; } /* else, cache miss. */ if (cache->size == GC_CACHE_SIZE) /* Reuse the first cell on the list (least-recently-used.) Remove it from the list, and unhash it from the table. */ { cell = cache->head; cache->head = cell->next; cache->head->prev = 0; if (cache->tail == cell) cache->tail = 0; /* only one */ BLOCK_INPUT; XFreeGC (cache->dpy, cell->gc); cache->delete_count++; UNBLOCK_INPUT; #ifdef GCCACHE_HASH remhash (&cell->gcvm, cache->table); #endif } else if (cache->size > GC_CACHE_SIZE) abort (); else { /* Allocate a new cell (don't put it in the list or table yet.) */ cell = (struct gc_cache_cell *) xmalloc (sizeof (struct gc_cache_cell)); cache->size++; } /* Now we've got a cell (new or reused). Fill it in. */ memcpy (&cell->gcvm.gcv, gcv, sizeof (XGCValues)); cell->gcvm.mask = mask; /* Put the cell on the end of the list. */ cell->next = 0; cell->prev = cache->tail; if (cache->tail) cache->tail->next = cell; cache->tail = cell; if (! cache->head) cache->head = cell; cache->create_count++; #ifdef GCCACHE_HASH /* Hash it in the table */ puthash (&cell->gcvm, cell, cache->table); #endif /* Now make and return the GC. */ BLOCK_INPUT; cell->gc = XCreateGC (cache->dpy, cache->window, mask, gcv); UNBLOCK_INPUT; /* debug */ if (cell->gc != gc_cache_lookup (cache, gcv, mask)) abort (); return cell->gc; }
GC gc_cache_lookup(struct gc_cache *cache, XGCValues * gcv, unsigned long mask) { struct gc_cache_cell *cell = NULL, *next = NULL, *prev = NULL; struct gcv_and_mask gcvm; if (cache == NULL) abort(); else if ((!!cache->head) != (!!cache->tail)) abort(); else if (cache->head && cache->tail && (cache->head->prev || cache->tail->next)) abort(); else { gcvm.mask = mask; gcvm.gcv = *gcv; /* this copies... */ #ifdef GCCACHE_HASH if (gethash(&gcvm, cache->table, (const void **)((void*)&cell))) #else /* !GCCACHE_HASH */ /* start at the end (most recently used) */ cell = cache->tail; while (cell) { if (gc_cache_eql(&gcvm, &cell->gcvm)) break; else cell = cell->prev; } /* #### This whole file needs some serious overhauling. */ if (!(mask | GCTile) && cell->gc->values.tile) cell = NULL; else if (!(mask | GCStipple) && cell->gc->values.stipple) cell = NULL; #endif /* !GCCACHE_HASH */ { /* Found a cell. Move this cell to the end of the list, so that it will be less likely to be collected than a cell that was accessed less recently. */ if (!cell) { abort(); return NULL; } else { if (cell == cache->tail) return cell->gc; next = cell->next; prev = cell->prev; if (prev) prev->next = next; if (next) next->prev = prev; if (cache->head == cell) cache->head = next; cell->next = NULL; cell->prev = cache->tail; if (cache->tail) cache->tail->next = cell; else abort(); cache->tail = cell; if (cache->head == cell) abort(); else if (cell->next) abort(); else if (cache->head != NULL && cache->head->prev) abort(); else if (cache->tail != NULL && cache->tail->next) abort(); return cell->gc; } } /* else, cache miss. */ if (cache == NULL) abort(); else if (cache->size == GC_CACHE_SIZE) /* Reuse the first cell on the list (least-recently-used). Remove it from the list, and unhash it from the table. */ { cell = cache->head; if (cache->head != NULL) { cache->head = cell->next; cache->head->prev = 0; } if (cache->tail == cell) cache->tail = 0; /* only one */ XFreeGC(cache->dpy, cell->gc); cache->delete_count++; #ifdef GCCACHE_HASH remhash(&cell->gcvm, cache->table); #endif } else if (cache->size > GC_CACHE_SIZE) abort(); else { /* Allocate a new cell (don't put it in the list or table yet). */ cell = xnew(struct gc_cache_cell); cache->size++; } if (cell != NULL) { /* Now we've got a cell (new or reused). Fill it in. */ memcpy(&cell->gcvm.gcv, gcv, sizeof(XGCValues)); cell->gcvm.mask = mask; /* Put the cell on the end of the list. */ cell->next = 0; cell->prev = cache->tail; if (cache->tail) cache->tail->next = cell; cache->tail = cell; if (!cache->head) cache->head = cell; cache->create_count++; #ifdef GCCACHE_HASH /* Hash it in the table */ puthash(&cell->gcvm, cell, cache->table); #endif /* Now make and return the GC. */ cell->gc = XCreateGC(cache->dpy, cache->window, mask, gcv); /* debug */ assert(cell->gc == gc_cache_lookup(cache, gcv, mask)); return cell->gc; } } return NULL; /* No cell determined */ }