mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-28 10:56:18 +03:00
177 lines
3.5 KiB
C
177 lines
3.5 KiB
C
/*
|
|
* 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 <tjs@longford.cs.monash.edu.au>.
|
|
*
|
|
* 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 <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <limits.h>
|
|
|
|
#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;
|
|
}
|