/* * The Python Imaging Library * $Id$ * * heap data type used by the image quantizer * * history: * 98-09-10 tjs Contributed * 98-12-29 fl Added to PIL 1.0b1 * * Written by Toby J Sargeant . * * Copyright (c) 1998 by Toby J Sargeant * Copyright (c) 1998 by Secret Labs AB * * See the README file for information on usage and redistribution. */ #include #include #include #include #include #include "QuantHeap.h" struct _Heap { void **heap; unsigned int heapsize; unsigned int heapcount; HeapCmpFunc cf; }; #define INITIAL_SIZE 256 // #define DEBUG #ifdef DEBUG static int _heap_test(Heap *); #endif void ImagingQuantHeapFree(Heap *h) { free(h->heap); free(h); } static int _heap_grow(Heap *h, unsigned int newsize) { void *newheap; if (!newsize) { newsize = h->heapsize << 1; } if (newsize < h->heapsize) { return 0; } if (newsize > INT_MAX / sizeof(void *)) { return 0; } /* malloc check ok, using calloc for overflow, also checking above due to memcpy below*/ newheap = calloc(newsize, sizeof(void *)); if (!newheap) { return 0; } memcpy(newheap, h->heap, sizeof(void *) * h->heapsize); free(h->heap); h->heap = newheap; h->heapsize = newsize; return 1; } #ifdef DEBUG static int _heap_test(Heap *h) { unsigned int k; for (k = 1; k * 2 <= h->heapcount; k++) { if (h->cf(h, h->heap[k], h->heap[k * 2]) < 0) { printf("heap is bad\n"); return 0; } if (k * 2 + 1 <= h->heapcount && h->cf(h, h->heap[k], h->heap[k * 2 + 1]) < 0) { printf("heap is bad\n"); return 0; } } return 1; } #endif int ImagingQuantHeapRemove(Heap *h, void **r) { unsigned int k, l; void *v; if (!h->heapcount) { return 0; } *r = h->heap[1]; v = h->heap[h->heapcount--]; for (k = 1; k * 2 <= h->heapcount; k = l) { l = k * 2; if (l < h->heapcount) { if (h->cf(h, h->heap[l], h->heap[l + 1]) < 0) { l++; } } if (h->cf(h, v, h->heap[l]) > 0) { break; } h->heap[k] = h->heap[l]; } h->heap[k] = v; #ifdef DEBUG if (!_heap_test(h)) { printf("oops - heap_remove messed up the heap\n"); exit(1); } #endif return 1; } int ImagingQuantHeapAdd(Heap *h, void *val) { int k; if (h->heapcount == h->heapsize - 1) { _heap_grow(h, 0); } k = ++h->heapcount; while (k != 1) { if (h->cf(h, val, h->heap[k / 2]) <= 0) { break; } h->heap[k] = h->heap[k / 2]; k >>= 1; } h->heap[k] = val; #ifdef DEBUG if (!_heap_test(h)) { printf("oops - heap_add messed up the heap\n"); exit(1); } #endif return 1; } int ImagingQuantHeapTop(Heap *h, void **r) { if (!h->heapcount) { return 0; } *r = h->heap[1]; return 1; } Heap * ImagingQuantHeapNew(HeapCmpFunc cf) { Heap *h; /* malloc check ok, small constant allocation */ h = malloc(sizeof(Heap)); if (!h) { return NULL; } h->heapsize = INITIAL_SIZE; /* malloc check ok, using calloc for overflow */ h->heap = calloc(h->heapsize, sizeof(void *)); if (!h->heap) { free(h); return NULL; } h->heapcount = 0; h->cf = cf; return h; }