1 /* The MIT License
2 
3    Copyright (C) 2016 Genome Research Ltd.
4 
5    Author: Petr Danecek <pd3@sanger.ac.uk>
6 
7    Permission is hereby granted, free of charge, to any person obtaining a copy
8    of this software and associated documentation files (the "Software"), to deal
9    in the Software without restriction, including without limitation the rights
10    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11    copies of the Software, and to permit persons to whom the Software is
12    furnished to do so, subject to the following conditions:
13 
14    The above copyright notice and this permission notice shall be included in
15    all copies or substantial portions of the Software.
16 
17    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23    THE SOFTWARE.
24 
25  */
26 /*
27     Usage example:
28 
29         #include "kheap.h"
30 
31         // First we prepare the user data to store, in this example it is a
32         // struct with a single element "key", and a comparator function
33         // "is_smaller".  In this example the comparator defines a min heap (as
34         // opposed to a max heap).
35         typedef struct
36         {
37             uint32_t key;
38         }
39         data_t;
40         static inline int is_smaller(data_t *a, data_t *b)
41         {
42             return a->key < b->key ? 1 : 0;
43         }
44         data_t data[3] = { {3}, {2}, {1} };
45 
46 
47         // Heap declaration, "mh" is an arbitrary string.  The typedef is not
48         // required, it is just a convenience shortcut so that we can use
49         // "heap_t" instead of the generic "khp_mh_t" automatically created by
50         // the KHEAP_INIT macro.
51         KHEAP_INIT(mh, data_t, is_smaller)
52         typedef khp_mh_t heap_t;
53 
54         // Initialize the heap, insert the test data, then retrieve them back,
55         // sorted. Multiple heaps with the same name "mh" can be created and
56         // used simultaneously, as long as they all use the same data type
57         // "data_t".
58         heap_t *heap = khp_init(mh);
59 
60         // When inserting a new element, the heap stores a copy of the memory
61         // area pointed to by the third argument.
62         for (int i=0; i<3; i++)
63             khp_insert(mh, heap, &data[i]);
64 
65         while (heap->ndat)
66         {
67             printf("%d\n", heap->dat[0].pos);
68             khp_delete(mh, heap);
69         }
70 
71         // Clean up
72         khp_destroy(mh, heap);
73 
74 */
75 
76 #ifndef __KHEAP_H__
77 #define __KHEAP_H__
78 
79 #include <stdlib.h>
80 
81 #ifndef kroundup32
82 #define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
83 #endif
84 
85 #ifndef kh_inline
86 #ifdef _MSC_VER
87 #define kh_inline __inline
88 #else
89 #define kh_inline inline
90 #endif
91 #endif /* kh_inline */
92 
93 #ifndef klib_unused
94 #if (defined __clang__ && __clang_major__ >= 3) || (defined __GNUC__ && __GNUC__ >= 3)
95 #define klib_unused __attribute__ ((__unused__))
96 #else
97 #define klib_unused
98 #endif
99 #endif /* klib_unused */
100 
101 
102 #define __KHEAP_TYPE(name, kheap_t) \
103     typedef struct {                \
104         int ndat, mdat;             \
105         kheap_t *dat;               \
106         kheap_t tmp;                \
107     } khp_##name##_t;
108 
109 #define khp_parent(i) (((i)-1)/2)
110 #define khp_lchild(i) (2*(i)+1)
111 #define khp_rchild(i) (2*(i)+2)
112 #define khp_swap(hp,i,j) {               \
113         ((hp)->tmp)    = ((hp)->dat[i]); \
114         ((hp)->dat[i]) = ((hp)->dat[j]); \
115         ((hp)->dat[j]) = ((hp)->tmp);    \
116     }
117 
118 #define __KHEAP_IMPL(name, SCOPE, kheap_t, __cmp)                       \
119     SCOPE khp_##name##_t *khp_init_##name(void)                         \
120     {                                                                   \
121         return (khp_##name##_t*)calloc(1, sizeof(khp_##name##_t));      \
122     }                                                                   \
123     SCOPE void khp_destroy_##name(khp_##name##_t *heap)                 \
124     {                                                                   \
125         if (heap) free(heap->dat);                                      \
126         free(heap);                                                     \
127     }                                                                   \
128     SCOPE int khp_insert_##name(khp_##name##_t *heap, kheap_t *dat)     \
129     {                                                                   \
130         heap->ndat++;                                                   \
131         if ( heap->ndat > heap->mdat )                                  \
132         {                                                               \
133             heap->mdat = heap->ndat;                                    \
134             kroundup32(heap->mdat);                                     \
135             heap->dat = (kheap_t*)realloc(heap->dat, heap->mdat*sizeof(kheap_t));         \
136             memset(heap->dat + heap->ndat, 0, (heap->mdat - heap->ndat)*sizeof(kheap_t)); \
137         }                                                               \
138         int i = heap->ndat - 1;                                         \
139         while ( i && __cmp(dat,&heap->dat[khp_parent(i)]) )             \
140         {                                                               \
141             heap->dat[i] = heap->dat[khp_parent(i)];                    \
142             i = khp_parent(i);                                          \
143         }                                                               \
144         heap->dat[i] = *dat;                                            \
145         return i;                                                       \
146     }                                                                   \
147     SCOPE void khp_heapify_##name(khp_##name##_t *heap, int i)          \
148     {                                                                   \
149 /*todo: loop instead of a recursive function? */ \
150         int extreme = khp_lchild(i) < heap->ndat && __cmp(&heap->dat[khp_lchild(i)],&heap->dat[i]) ? khp_lchild(i) : i;     \
151         if ( khp_rchild(i) < heap->ndat && __cmp(&heap->dat[khp_rchild(i)],&heap->dat[extreme]) ) extreme = khp_rchild(i);  \
152         if ( extreme != i )                                             \
153         {                                                               \
154             khp_swap(heap,i,extreme);                                   \
155             khp_heapify_##name(heap,extreme);                           \
156         }                                                               \
157     }                                                                   \
158     SCOPE void khp_delete_##name(khp_##name##_t *heap)                  \
159     {                                                                   \
160         if ( !heap || !heap->ndat ) return;                             \
161         heap->dat[0] = heap->dat[--heap->ndat];                         \
162         khp_heapify_##name(heap, 0);                                    \
163     }                                                                   \
164 
165 #define KHEAP_INIT(name, kheap_t, __cmp)            \
166     __KHEAP_TYPE(name, kheap_t)                     \
167     __KHEAP_IMPL(name, static kh_inline klib_unused, kheap_t, __cmp)
168 
169 #define khp_init(name) khp_init_##name()
170 #define khp_destroy(name, heap) khp_destroy_##name(heap)
171 #define khp_insert(name, heap, dat) khp_insert_##name(heap, dat)
172 #define khp_delete(name, heap) khp_delete_##name(heap)
173 
174 #endif
175