spiped 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/ext/spiped/extconf.rb +3 -0
- data/ext/spiped/spiped-source/BUILDING +46 -0
- data/ext/spiped/spiped-source/CHANGELOG +44 -0
- data/ext/spiped/spiped-source/COPYRIGHT +33 -0
- data/ext/spiped/spiped-source/Makefile +47 -0
- data/ext/spiped/spiped-source/Makefile.POSIX +27 -0
- data/ext/spiped/spiped-source/Makefile.inc +20 -0
- data/ext/spiped/spiped-source/Makefile.prog +23 -0
- data/ext/spiped/spiped-source/POSIX/README +10 -0
- data/ext/spiped/spiped-source/POSIX/posix-cflags.sh +10 -0
- data/ext/spiped/spiped-source/POSIX/posix-clock_realtime.c +3 -0
- data/ext/spiped/spiped-source/POSIX/posix-l.c +1 -0
- data/ext/spiped/spiped-source/POSIX/posix-l.sh +14 -0
- data/ext/spiped/spiped-source/POSIX/posix-msg_nosignal.c +3 -0
- data/ext/spiped/spiped-source/README +198 -0
- data/ext/spiped/spiped-source/STYLE +151 -0
- data/ext/spiped/spiped-source/lib/dnsthread/dnsthread.c +464 -0
- data/ext/spiped/spiped-source/lib/dnsthread/dnsthread.h +45 -0
- data/ext/spiped/spiped-source/libcperciva/alg/sha256.c +442 -0
- data/ext/spiped/spiped-source/libcperciva/alg/sha256.h +95 -0
- data/ext/spiped/spiped-source/libcperciva/cpusupport/Build/cpusupport-X86-AESNI.c +13 -0
- data/ext/spiped/spiped-source/libcperciva/cpusupport/Build/cpusupport-X86-CPUID.c +8 -0
- data/ext/spiped/spiped-source/libcperciva/cpusupport/Build/cpusupport.sh +37 -0
- data/ext/spiped/spiped-source/libcperciva/cpusupport/cpusupport.h +63 -0
- data/ext/spiped/spiped-source/libcperciva/cpusupport/cpusupport_x86_aesni.c +30 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aes.c +166 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aes.h +31 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aes_aesni.c +229 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aes_aesni.h +31 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aesctr.c +124 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_aesctr.h +41 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_dh.c +293 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_dh.h +43 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_dh_group14.c +46 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_dh_group14.h +9 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_entropy.c +215 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_entropy.h +14 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_verify_bytes.c +21 -0
- data/ext/spiped/spiped-source/libcperciva/crypto/crypto_verify_bytes.h +14 -0
- data/ext/spiped/spiped-source/libcperciva/datastruct/elasticarray.c +276 -0
- data/ext/spiped/spiped-source/libcperciva/datastruct/elasticarray.h +167 -0
- data/ext/spiped/spiped-source/libcperciva/datastruct/mpool.h +85 -0
- data/ext/spiped/spiped-source/libcperciva/datastruct/ptrheap.c +334 -0
- data/ext/spiped/spiped-source/libcperciva/datastruct/ptrheap.h +89 -0
- data/ext/spiped/spiped-source/libcperciva/datastruct/timerqueue.c +241 -0
- data/ext/spiped/spiped-source/libcperciva/datastruct/timerqueue.h +60 -0
- data/ext/spiped/spiped-source/libcperciva/events/events.c +203 -0
- data/ext/spiped/spiped-source/libcperciva/events/events.h +106 -0
- data/ext/spiped/spiped-source/libcperciva/events/events_immediate.c +149 -0
- data/ext/spiped/spiped-source/libcperciva/events/events_internal.h +95 -0
- data/ext/spiped/spiped-source/libcperciva/events/events_network.c +347 -0
- data/ext/spiped/spiped-source/libcperciva/events/events_network_selectstats.c +106 -0
- data/ext/spiped/spiped-source/libcperciva/events/events_timer.c +273 -0
- data/ext/spiped/spiped-source/libcperciva/network/network.h +95 -0
- data/ext/spiped/spiped-source/libcperciva/network/network_accept.c +103 -0
- data/ext/spiped/spiped-source/libcperciva/network/network_connect.c +258 -0
- data/ext/spiped/spiped-source/libcperciva/network/network_read.c +155 -0
- data/ext/spiped/spiped-source/libcperciva/network/network_write.c +188 -0
- data/ext/spiped/spiped-source/libcperciva/util/asprintf.c +49 -0
- data/ext/spiped/spiped-source/libcperciva/util/asprintf.h +16 -0
- data/ext/spiped/spiped-source/libcperciva/util/daemonize.c +134 -0
- data/ext/spiped/spiped-source/libcperciva/util/daemonize.h +10 -0
- data/ext/spiped/spiped-source/libcperciva/util/entropy.c +76 -0
- data/ext/spiped/spiped-source/libcperciva/util/entropy.h +13 -0
- data/ext/spiped/spiped-source/libcperciva/util/imalloc.h +33 -0
- data/ext/spiped/spiped-source/libcperciva/util/insecure_memzero.c +19 -0
- data/ext/spiped/spiped-source/libcperciva/util/insecure_memzero.h +33 -0
- data/ext/spiped/spiped-source/libcperciva/util/monoclock.c +52 -0
- data/ext/spiped/spiped-source/libcperciva/util/monoclock.h +14 -0
- data/ext/spiped/spiped-source/libcperciva/util/noeintr.c +54 -0
- data/ext/spiped/spiped-source/libcperciva/util/noeintr.h +14 -0
- data/ext/spiped/spiped-source/libcperciva/util/sock.c +472 -0
- data/ext/spiped/spiped-source/libcperciva/util/sock.h +56 -0
- data/ext/spiped/spiped-source/libcperciva/util/sock_internal.h +14 -0
- data/ext/spiped/spiped-source/libcperciva/util/sock_util.c +271 -0
- data/ext/spiped/spiped-source/libcperciva/util/sock_util.h +51 -0
- data/ext/spiped/spiped-source/libcperciva/util/sysendian.h +146 -0
- data/ext/spiped/spiped-source/libcperciva/util/warnp.c +76 -0
- data/ext/spiped/spiped-source/libcperciva/util/warnp.h +59 -0
- data/ext/spiped/spiped-source/proto/proto_conn.c +362 -0
- data/ext/spiped/spiped-source/proto/proto_conn.h +25 -0
- data/ext/spiped/spiped-source/proto/proto_crypt.c +396 -0
- data/ext/spiped/spiped-source/proto/proto_crypt.h +102 -0
- data/ext/spiped/spiped-source/proto/proto_handshake.c +330 -0
- data/ext/spiped/spiped-source/proto/proto_handshake.h +30 -0
- data/ext/spiped/spiped-source/proto/proto_pipe.c +202 -0
- data/ext/spiped/spiped-source/proto/proto_pipe.h +23 -0
- data/ext/spiped/spiped-source/spipe/Makefile +90 -0
- data/ext/spiped/spiped-source/spipe/README +24 -0
- data/ext/spiped/spiped-source/spipe/main.c +178 -0
- data/ext/spiped/spiped-source/spipe/pushbits.c +101 -0
- data/ext/spiped/spiped-source/spipe/pushbits.h +10 -0
- data/ext/spiped/spiped-source/spipe/spipe.1 +60 -0
- data/ext/spiped/spiped-source/spiped/Makefile +98 -0
- data/ext/spiped/spiped-source/spiped/README +62 -0
- data/ext/spiped/spiped-source/spiped/dispatch.c +214 -0
- data/ext/spiped/spiped-source/spiped/dispatch.h +27 -0
- data/ext/spiped/spiped-source/spiped/main.c +267 -0
- data/ext/spiped/spiped-source/spiped/spiped.1 +112 -0
- data/lib/spiped.rb +3 -0
- metadata +143 -0
@@ -0,0 +1,167 @@
|
|
1
|
+
#ifndef _ELASTICARRAY_H_
|
2
|
+
#define _ELASTICARRAY_H_
|
3
|
+
|
4
|
+
#include <stddef.h>
|
5
|
+
|
6
|
+
/**
|
7
|
+
* Elastic Arrays are dynamically resizing arrays which remain within a
|
8
|
+
* factor of 4 of the optimal size for the data they contain and have (within
|
9
|
+
* a constant factor) amortized optimal running time providing that all of
|
10
|
+
* the allocated space is accessed at some point. Functions return NULL or
|
11
|
+
* (int)(-1) on error and set errno; other return types indicate that failure
|
12
|
+
* is not possible. On error, the array will be unmodified.
|
13
|
+
*
|
14
|
+
* The ELASTICARRAY_DECL(type, prefix, rectype) macro can be used to create a
|
15
|
+
* more friendly interface, at the expense of restricting the array to only
|
16
|
+
* holding a single data type.
|
17
|
+
*/
|
18
|
+
|
19
|
+
/* Opaque elastic array type. */
|
20
|
+
struct elasticarray;
|
21
|
+
|
22
|
+
/**
|
23
|
+
* elasticarray_init(nrec, reclen):
|
24
|
+
* Create and return an elastic array holding ${nrec} (uninitialized) records
|
25
|
+
* of length ${reclen}. Takes O(nrec * reclen) time.
|
26
|
+
*/
|
27
|
+
struct elasticarray * elasticarray_init(size_t, size_t);
|
28
|
+
|
29
|
+
/**
|
30
|
+
* elasticarray_resize(EA, nrec, reclen):
|
31
|
+
* Resize the elastic array pointed to by ${EA} to hold ${nrec} records of
|
32
|
+
* length ${reclen}. If ${nrec} exceeds the number of records previously
|
33
|
+
* held by the array, the additional records will be uninitialized. Takes
|
34
|
+
* O(nrec * reclen) time.
|
35
|
+
*/
|
36
|
+
int elasticarray_resize(struct elasticarray *, size_t, size_t);
|
37
|
+
|
38
|
+
/**
|
39
|
+
* elasticarray_getsize(EA, reclen):
|
40
|
+
* Return the number of length-${reclen} records in the array, rounding down
|
41
|
+
* if there is a partial record (which can only occur if elasticarray_*
|
42
|
+
* functions have been called with different values of reclen). The value
|
43
|
+
* ${reclen} must be positive.
|
44
|
+
*/
|
45
|
+
size_t elasticarray_getsize(struct elasticarray *, size_t);
|
46
|
+
|
47
|
+
/**
|
48
|
+
* elasticarray_append(EA, buf, nrec, reclen):
|
49
|
+
* Append to the elastic array ${EA} the ${nrec} records of length ${reclen}
|
50
|
+
* stored in ${buf}. Takes O(nrec * reclen) amortized time.
|
51
|
+
*/
|
52
|
+
int elasticarray_append(struct elasticarray *, const void *, size_t, size_t);
|
53
|
+
|
54
|
+
/**
|
55
|
+
* elasticarray_shrink(EA, nrec, reclen):
|
56
|
+
* Delete the final ${nrec} records of length ${reclen} from the elastic
|
57
|
+
* array ${EA}. If there are fewer than ${nrec} records, all records
|
58
|
+
* present will be deleted.
|
59
|
+
*
|
60
|
+
* As an exception to the normal rule, an elastic array may occupy more than
|
61
|
+
* 4 times the optimal storage immediately following an elasticarray_shrink
|
62
|
+
* call; but only if realloc(3) failed to shrink a memory allocation.
|
63
|
+
*/
|
64
|
+
void elasticarray_shrink(struct elasticarray *, size_t, size_t);
|
65
|
+
|
66
|
+
/**
|
67
|
+
* elasticarray_truncate(EA):
|
68
|
+
* Release any spare space in the elastic array ${EA}.
|
69
|
+
*/
|
70
|
+
int elasticarray_truncate(struct elasticarray *);
|
71
|
+
|
72
|
+
/**
|
73
|
+
* elasticarray_get(EA, pos, reclen):
|
74
|
+
* Return a pointer to record number ${pos} of length ${reclen} in the
|
75
|
+
* elastic array ${EA}. Takes O(1) time.
|
76
|
+
*/
|
77
|
+
void * elasticarray_get(struct elasticarray *, size_t, size_t);
|
78
|
+
|
79
|
+
/**
|
80
|
+
* elasticarray_free(EA):
|
81
|
+
* Free the elastic array ${EA}. Takes O(1) time.
|
82
|
+
*/
|
83
|
+
void elasticarray_free(struct elasticarray *);
|
84
|
+
|
85
|
+
/**
|
86
|
+
* elasticarray_export(EA, buf, nrec, reclen):
|
87
|
+
* Return the data in the elastic array ${EA} as a buffer ${buf} containing
|
88
|
+
* ${nrec} records of length ${reclen}. Free the elastic array ${EA}.
|
89
|
+
*/
|
90
|
+
int elasticarray_export(struct elasticarray *, void **, size_t *, size_t);
|
91
|
+
|
92
|
+
/**
|
93
|
+
* ELASTICARRAY_DECL(type, prefix, rectype):
|
94
|
+
* Declare the type ${type} and the following functions:
|
95
|
+
* ${type} ${prefix}_init(size_t nrec);
|
96
|
+
* int ${prefix}_resize(${type} EA, size_t nrec);
|
97
|
+
* size_t ${prefix}_getsize(${type} EA);
|
98
|
+
* int ${prefix}_append(${type} EA, const void * buf, size_t nrec);
|
99
|
+
* void ${prefix}_shrink(${type} EA, size_t nrec);
|
100
|
+
* int ${prefix}_truncate(${type} EA);
|
101
|
+
* ${rectype} * ${prefix}_get(${type} EA, size_t pos);
|
102
|
+
* void ${prefix}_free(${type} EA);
|
103
|
+
*/
|
104
|
+
#define ELASTICARRAY_DECL(type, prefix, rectype) \
|
105
|
+
static inline struct prefix##_struct * \
|
106
|
+
prefix##_init(size_t nrec) \
|
107
|
+
{ \
|
108
|
+
struct elasticarray * EA; \
|
109
|
+
\
|
110
|
+
EA = elasticarray_init(nrec, sizeof(rectype)); \
|
111
|
+
return ((struct prefix##_struct *)EA); \
|
112
|
+
} \
|
113
|
+
static inline int \
|
114
|
+
prefix##_resize(struct prefix##_struct * EA, size_t nrec) \
|
115
|
+
{ \
|
116
|
+
return (elasticarray_resize((struct elasticarray *)EA, \
|
117
|
+
nrec, sizeof(rectype))); \
|
118
|
+
} \
|
119
|
+
static inline size_t \
|
120
|
+
prefix##_getsize(struct prefix##_struct * EA) \
|
121
|
+
{ \
|
122
|
+
return (elasticarray_getsize((struct elasticarray *)EA, \
|
123
|
+
sizeof(rectype))); \
|
124
|
+
} \
|
125
|
+
static inline int \
|
126
|
+
prefix##_append(struct prefix##_struct * EA, \
|
127
|
+
rectype const * buf, size_t nrec) \
|
128
|
+
{ \
|
129
|
+
return (elasticarray_append((struct elasticarray *)EA, \
|
130
|
+
buf, nrec, sizeof(rectype))); \
|
131
|
+
} \
|
132
|
+
static inline void \
|
133
|
+
prefix##_shrink(struct prefix##_struct * EA, size_t nrec) \
|
134
|
+
{ \
|
135
|
+
elasticarray_shrink((struct elasticarray *)EA, \
|
136
|
+
nrec, sizeof(rectype)); \
|
137
|
+
} \
|
138
|
+
static inline int \
|
139
|
+
prefix##_truncate(struct prefix##_struct * EA) \
|
140
|
+
{ \
|
141
|
+
return (elasticarray_truncate( \
|
142
|
+
(struct elasticarray *)EA)); \
|
143
|
+
} \
|
144
|
+
static inline rectype * \
|
145
|
+
prefix##_get(struct prefix##_struct * EA, size_t pos) \
|
146
|
+
{ \
|
147
|
+
rectype * rec; \
|
148
|
+
\
|
149
|
+
rec = elasticarray_get((struct elasticarray *)EA, \
|
150
|
+
pos, sizeof(rectype)); \
|
151
|
+
return (rec); \
|
152
|
+
} \
|
153
|
+
static inline void \
|
154
|
+
prefix##_free(struct prefix##_struct * EA) \
|
155
|
+
{ \
|
156
|
+
elasticarray_free((struct elasticarray *)EA); \
|
157
|
+
} \
|
158
|
+
static inline int \
|
159
|
+
prefix##_export(struct prefix##_struct * EA, rectype ** buf, \
|
160
|
+
size_t * nrec) \
|
161
|
+
{ \
|
162
|
+
return (elasticarray_export((struct elasticarray *)EA, \
|
163
|
+
(void **)buf, nrec, sizeof(rectype))); \
|
164
|
+
} \
|
165
|
+
typedef struct prefix##_struct * type
|
166
|
+
|
167
|
+
#endif /* !_ELASTICARRAY_H_ */
|
@@ -0,0 +1,85 @@
|
|
1
|
+
#ifndef _MPOOL_H_
|
2
|
+
#define _MPOOL_H_
|
3
|
+
|
4
|
+
#include <stdlib.h>
|
5
|
+
|
6
|
+
/**
|
7
|
+
* Memory allocator cache. Memory allocations can be returned to the pool
|
8
|
+
* and reused by a subsequent allocation without returning all the way to
|
9
|
+
* free/malloc. In effect, this is an optimization for the case where we
|
10
|
+
* know we will want another allocation of the same size soon, at the expense
|
11
|
+
* of allowing the memory to be reused by some other code.
|
12
|
+
*/
|
13
|
+
|
14
|
+
/**
|
15
|
+
* MPOOL(name, type, size):
|
16
|
+
* Define the functions
|
17
|
+
*
|
18
|
+
* ${type} * mpool_${name}_malloc(void);
|
19
|
+
* void mpool_${name}_free(${type} *);
|
20
|
+
*
|
21
|
+
* which allocate and free structures of type ${type}. Up to ${size}
|
22
|
+
* such structures are kept cached after _free is called in order to
|
23
|
+
* allow future _malloc calls to be rapidly serviced.
|
24
|
+
*
|
25
|
+
* Cached structures will be freed at program exit time in order to aid
|
26
|
+
* in the detection of memory leaks.
|
27
|
+
*/
|
28
|
+
#define MPOOL(name, type, size) \
|
29
|
+
static struct mpool_##name##_struct { \
|
30
|
+
size_t stacklen; \
|
31
|
+
void * top; \
|
32
|
+
int atexit_set; \
|
33
|
+
} mpool_##name##_rec = {0, NULL, 0}; \
|
34
|
+
\
|
35
|
+
static void \
|
36
|
+
mpool_##name##_atexit(void) \
|
37
|
+
{ \
|
38
|
+
void * top; \
|
39
|
+
\
|
40
|
+
while ((top = mpool_##name##_rec.top) != NULL) { \
|
41
|
+
mpool_##name##_rec.top = *(void **)top; \
|
42
|
+
free(top); \
|
43
|
+
} \
|
44
|
+
} \
|
45
|
+
\
|
46
|
+
static inline type * \
|
47
|
+
mpool_##name##_malloc(void) \
|
48
|
+
{ \
|
49
|
+
type * p; \
|
50
|
+
\
|
51
|
+
if (mpool_##name##_rec.stacklen) { \
|
52
|
+
p = mpool_##name##_rec.top; \
|
53
|
+
mpool_##name##_rec.top = *(void **)p; \
|
54
|
+
mpool_##name##_rec.stacklen -= 1; \
|
55
|
+
} else { \
|
56
|
+
if (mpool_##name##_rec.atexit_set == 0) { \
|
57
|
+
atexit(mpool_##name##_atexit); \
|
58
|
+
mpool_##name##_rec.atexit_set = 1; \
|
59
|
+
} \
|
60
|
+
p = malloc((sizeof(type) > sizeof(void *)) ? \
|
61
|
+
sizeof(type) : sizeof(void *)); \
|
62
|
+
} \
|
63
|
+
\
|
64
|
+
return (p); \
|
65
|
+
} \
|
66
|
+
\
|
67
|
+
static inline void \
|
68
|
+
mpool_##name##_free(type * p) \
|
69
|
+
{ \
|
70
|
+
\
|
71
|
+
if (p == NULL) \
|
72
|
+
return; \
|
73
|
+
\
|
74
|
+
if (mpool_##name##_rec.stacklen < size) { \
|
75
|
+
*(void **)p = mpool_##name##_rec.top; \
|
76
|
+
mpool_##name##_rec.top = p; \
|
77
|
+
mpool_##name##_rec.stacklen += 1; \
|
78
|
+
} else { \
|
79
|
+
free(p); \
|
80
|
+
} \
|
81
|
+
} \
|
82
|
+
\
|
83
|
+
struct mpool_##name##_dummy
|
84
|
+
|
85
|
+
#endif /* !_MPOOL_H_ */
|
@@ -0,0 +1,334 @@
|
|
1
|
+
#include <stdlib.h>
|
2
|
+
|
3
|
+
#include "elasticarray.h"
|
4
|
+
|
5
|
+
#include "ptrheap.h"
|
6
|
+
|
7
|
+
ELASTICARRAY_DECL(PTRLIST, ptrlist, void *);
|
8
|
+
|
9
|
+
struct ptrheap {
|
10
|
+
int (* compar)(void *, const void *, const void *);
|
11
|
+
void (* setreccookie)(void *, void *, size_t);
|
12
|
+
void * cookie;
|
13
|
+
PTRLIST elems;
|
14
|
+
size_t nelems;
|
15
|
+
};
|
16
|
+
|
17
|
+
/**
|
18
|
+
* swap(elems, i, j, setreccookie, cookie):
|
19
|
+
* Swap elements ${i} and ${j} in ${elems}. If ${setreccookie} is non-NULL,
|
20
|
+
* invoke ${setreccookie}(${cookie}, elem, pos) for each of the elements and
|
21
|
+
* their new positions in the tree.
|
22
|
+
*/
|
23
|
+
static void
|
24
|
+
swap(PTRLIST elems, size_t i, size_t j,
|
25
|
+
void (* setreccookie)(void *, void *, size_t), void * cookie)
|
26
|
+
{
|
27
|
+
void * tmp;
|
28
|
+
|
29
|
+
/* Swap the elements. */
|
30
|
+
tmp = *ptrlist_get(elems, i);
|
31
|
+
*ptrlist_get(elems, i) = *ptrlist_get(elems, j);
|
32
|
+
*ptrlist_get(elems, j) = tmp;
|
33
|
+
|
34
|
+
/* Notify about the moved elements. */
|
35
|
+
if (setreccookie != NULL) {
|
36
|
+
setreccookie(cookie, *ptrlist_get(elems, i), i);
|
37
|
+
setreccookie(cookie, *ptrlist_get(elems, j), j);
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
/**
|
42
|
+
* heapifyup(elems, i, compar, setreccookie, cookie):
|
43
|
+
* Sift up element ${i} of the elements ${elems}, using the comparison
|
44
|
+
* function ${compar} and the cookie ${cookie}. If elements move and
|
45
|
+
* ${setreccookie} is non-NULL, use it to notify about the updated position
|
46
|
+
* of elements in the heap.
|
47
|
+
*/
|
48
|
+
static void
|
49
|
+
heapifyup(PTRLIST elems, size_t i,
|
50
|
+
int (* compar)(void *, const void *, const void *),
|
51
|
+
void (* setreccookie)(void *, void *, size_t), void * cookie)
|
52
|
+
{
|
53
|
+
|
54
|
+
/* Iterate up the tree. */
|
55
|
+
do {
|
56
|
+
/* If we're at the root, we have nothing to do. */
|
57
|
+
if (i == 0)
|
58
|
+
break;
|
59
|
+
|
60
|
+
/* If this is >= its parent, we're done. */
|
61
|
+
if (compar(cookie, *ptrlist_get(elems, i),
|
62
|
+
*ptrlist_get(elems, (i - 1) / 2)) >= 0)
|
63
|
+
break;
|
64
|
+
|
65
|
+
/* Swap with the parent. */
|
66
|
+
swap(elems, i, (i - 1) / 2, setreccookie, cookie);
|
67
|
+
|
68
|
+
/* Move up the tree. */
|
69
|
+
i = (i - 1) / 2;
|
70
|
+
} while (1);
|
71
|
+
}
|
72
|
+
|
73
|
+
/**
|
74
|
+
* heapify(elems, i, N, compar, setreccookie, cookie):
|
75
|
+
* Sift down element number ${i} out of ${N} of the elements ${elems}, using
|
76
|
+
* the comparison function ${compar} and the cookie ${cookie}. If elements
|
77
|
+
* move and ${setreccookie} is non-NULL, use it to notify about the updated
|
78
|
+
* position of elements in the heap.
|
79
|
+
*/
|
80
|
+
static void
|
81
|
+
heapify(PTRLIST elems, size_t i, size_t N,
|
82
|
+
int (* compar)(void *, const void *, const void *),
|
83
|
+
void (* setreccookie)(void *, void *, size_t), void * cookie)
|
84
|
+
{
|
85
|
+
size_t min;
|
86
|
+
|
87
|
+
/* Iterate down the tree. */
|
88
|
+
do {
|
89
|
+
/* Look for the minimum element out of {i, 2i+1, 2i+2}. */
|
90
|
+
min = i;
|
91
|
+
|
92
|
+
/* Is this bigger than element 2i+1? */
|
93
|
+
if ((2 * i + 1 < N) &&
|
94
|
+
(compar(cookie, *ptrlist_get(elems, min),
|
95
|
+
*ptrlist_get(elems, 2 * i + 1)) > 0))
|
96
|
+
min = 2 * i + 1;
|
97
|
+
|
98
|
+
/* Is this bigger than element 2i+2? */
|
99
|
+
if ((2 * i + 2 < N) &&
|
100
|
+
(compar(cookie, *ptrlist_get(elems, min),
|
101
|
+
*ptrlist_get(elems, 2 * i + 2)) > 0))
|
102
|
+
min = 2 * i + 2;
|
103
|
+
|
104
|
+
/* If the minimum is i, we have heap-property. */
|
105
|
+
if (min == i)
|
106
|
+
break;
|
107
|
+
|
108
|
+
/* Move the minimum into position i. */
|
109
|
+
swap(elems, min, i, setreccookie, cookie);
|
110
|
+
|
111
|
+
/* Move down the tree. */
|
112
|
+
i = min;
|
113
|
+
} while (1);
|
114
|
+
}
|
115
|
+
|
116
|
+
/**
|
117
|
+
* ptrheap_init(compar, setreccookie, cookie):
|
118
|
+
* Create and return an empty heap. The function ${compar}(${cookie}, x, y)
|
119
|
+
* should return less than, equal to, or greater than 0 depending on whether
|
120
|
+
* x is less than, equal to, or greater than y; and if ${setreccookie} is
|
121
|
+
* non-zero it will be called as ${setreccookie}(${cookie}, ${ptr}, ${rc}) to
|
122
|
+
* indicate that the value ${rc} is the current record cookie for the pointer
|
123
|
+
* ${ptr}. The function ${setreccookie} may not make any ptrheap_* calls.
|
124
|
+
*/
|
125
|
+
struct ptrheap *
|
126
|
+
ptrheap_init(int (* compar)(void *, const void *, const void *),
|
127
|
+
void (* setreccookie)(void *, void *, size_t), void * cookie)
|
128
|
+
{
|
129
|
+
|
130
|
+
/* Let ptrheap_create handle this. */
|
131
|
+
return (ptrheap_create(compar, setreccookie, cookie, 0, NULL));
|
132
|
+
}
|
133
|
+
|
134
|
+
/**
|
135
|
+
* ptrheap_create(compar, setreccookie, cookie, N, ptrs):
|
136
|
+
* Create and return a heap, as in ptrheap_init, but with the ${N} pointers
|
137
|
+
* in ${ptrs} as heap elements. This is faster than creating an empty heap
|
138
|
+
* and adding the elements individually.
|
139
|
+
*/
|
140
|
+
struct ptrheap *
|
141
|
+
ptrheap_create(int (* compar)(void *, const void *, const void *),
|
142
|
+
void (* setreccookie)(void *, void *, size_t), void * cookie,
|
143
|
+
size_t N, void ** ptrs)
|
144
|
+
{
|
145
|
+
struct ptrheap * H;
|
146
|
+
size_t i;
|
147
|
+
|
148
|
+
/* Allocate structure. */
|
149
|
+
if ((H = malloc(sizeof(struct ptrheap))) == NULL)
|
150
|
+
goto err0;
|
151
|
+
|
152
|
+
/* Store parameters. */
|
153
|
+
H->compar = compar;
|
154
|
+
H->setreccookie = setreccookie;
|
155
|
+
H->cookie = cookie;
|
156
|
+
|
157
|
+
/* We will have N elements. */
|
158
|
+
H->nelems = N;
|
159
|
+
|
160
|
+
/* Allocate space for N heap elements. */
|
161
|
+
if ((H->elems = ptrlist_init(N)) == NULL)
|
162
|
+
goto err1;
|
163
|
+
|
164
|
+
/* Copy the heap elements in. */
|
165
|
+
for (i = 0; i < N; i++)
|
166
|
+
*ptrlist_get(H->elems, i) = ptrs[i];
|
167
|
+
|
168
|
+
/* Turn this into a heap. */
|
169
|
+
for (i = N - 1; i < N; i--)
|
170
|
+
heapify(H->elems, i, N, H->compar, NULL, H->cookie);
|
171
|
+
|
172
|
+
/* Advise the caller about the record cookies. */
|
173
|
+
if (H->setreccookie != NULL)
|
174
|
+
for (i = 0; i < N; i++)
|
175
|
+
(H->setreccookie)(H->cookie,
|
176
|
+
*ptrlist_get(H->elems, i), i);
|
177
|
+
|
178
|
+
/* Success! */
|
179
|
+
return (H);
|
180
|
+
|
181
|
+
err1:
|
182
|
+
free(H);
|
183
|
+
err0:
|
184
|
+
/* Failure! */
|
185
|
+
return (NULL);
|
186
|
+
}
|
187
|
+
|
188
|
+
/**
|
189
|
+
* ptrheap_add(H, ptr):
|
190
|
+
* Add the pointer ${ptr} to the heap ${H}.
|
191
|
+
*/
|
192
|
+
int
|
193
|
+
ptrheap_add(struct ptrheap * H, void * ptr)
|
194
|
+
{
|
195
|
+
|
196
|
+
/* Add the element to the end of the heap. */
|
197
|
+
if (ptrlist_append(H->elems, &ptr, 1))
|
198
|
+
goto err0;
|
199
|
+
H->nelems += 1;
|
200
|
+
|
201
|
+
/* Advise the caller about the current location of this record. */
|
202
|
+
if (H->setreccookie != NULL)
|
203
|
+
(H->setreccookie)(H->cookie, ptr, H->nelems - 1);
|
204
|
+
|
205
|
+
/* Move the new element up in the tree if necessary. */
|
206
|
+
heapifyup(H->elems, H->nelems - 1,
|
207
|
+
H->compar, H->setreccookie, H->cookie);
|
208
|
+
|
209
|
+
/* Success! */
|
210
|
+
return (0);
|
211
|
+
|
212
|
+
err0:
|
213
|
+
/* Failure! */
|
214
|
+
return (-1);
|
215
|
+
}
|
216
|
+
|
217
|
+
/**
|
218
|
+
* ptrheap_getmin(H):
|
219
|
+
* Return the minimum pointer in the heap ${H}. If the heap is empty, NULL
|
220
|
+
* is returned.
|
221
|
+
*/
|
222
|
+
void *
|
223
|
+
ptrheap_getmin(struct ptrheap * H)
|
224
|
+
{
|
225
|
+
|
226
|
+
/* If we have any elements, the minimum is in position 0. */
|
227
|
+
if (H->nelems)
|
228
|
+
return (*ptrlist_get(H->elems, 0));
|
229
|
+
else
|
230
|
+
return (NULL);
|
231
|
+
}
|
232
|
+
|
233
|
+
/**
|
234
|
+
* ptrheap_delete(H, rc):
|
235
|
+
* Delete from the heap ${H} the element ptr for which the function call
|
236
|
+
* setreccookie(cookie, ptr, ${rc}) was most recently made.
|
237
|
+
*/
|
238
|
+
void
|
239
|
+
ptrheap_delete(struct ptrheap * H, size_t rc)
|
240
|
+
{
|
241
|
+
|
242
|
+
/*
|
243
|
+
* If the element we're deleting is not at the end of the heap,
|
244
|
+
* replace it with the element which is currently at the end.
|
245
|
+
*/
|
246
|
+
if (rc != H->nelems - 1) {
|
247
|
+
/* Move ptr from position H->nelems - 1 into position rc. */
|
248
|
+
*ptrlist_get(H->elems, rc) =
|
249
|
+
*ptrlist_get(H->elems, H->nelems - 1);
|
250
|
+
if (H->setreccookie != NULL)
|
251
|
+
(H->setreccookie)(H->cookie,
|
252
|
+
*ptrlist_get(H->elems, rc), rc);
|
253
|
+
|
254
|
+
/* Is this too small to be in position ${rc}? */
|
255
|
+
if ((rc > 0) &&
|
256
|
+
(H->compar(H->cookie, *ptrlist_get(H->elems, rc),
|
257
|
+
*ptrlist_get(H->elems, (rc - 1) / 2)) < 0)) {
|
258
|
+
/* Swap with the parent, and keep moving up. */
|
259
|
+
swap(H->elems, rc, (rc - 1) / 2,
|
260
|
+
H->setreccookie, H->cookie);
|
261
|
+
heapifyup(H->elems, (rc - 1) / 2,
|
262
|
+
H->compar, H->setreccookie, H->cookie);
|
263
|
+
} else {
|
264
|
+
/* Maybe we need to move it down instead? */
|
265
|
+
heapify(H->elems, rc, H->nelems,
|
266
|
+
H->compar, H->setreccookie, H->cookie);
|
267
|
+
}
|
268
|
+
}
|
269
|
+
|
270
|
+
/*
|
271
|
+
* We've got everything we want to keep in positions 0 .. nelems - 2,
|
272
|
+
* and we have heap-nature, so all we need to do is strip off the
|
273
|
+
* final pointer.
|
274
|
+
*/
|
275
|
+
ptrlist_shrink(H->elems, 1);
|
276
|
+
H->nelems--;
|
277
|
+
}
|
278
|
+
|
279
|
+
/**
|
280
|
+
* ptrheap_deletemin(H):
|
281
|
+
* Delete the minimum element in the heap ${H}.
|
282
|
+
*/
|
283
|
+
void
|
284
|
+
ptrheap_deletemin(struct ptrheap * H)
|
285
|
+
{
|
286
|
+
|
287
|
+
/* Let ptrheap_delete handle this. */
|
288
|
+
ptrheap_delete(H, 0);
|
289
|
+
}
|
290
|
+
|
291
|
+
/**
|
292
|
+
* ptrheap_increase(H, rc):
|
293
|
+
* Adjust the heap ${H} to account for the fact that the element ptr for
|
294
|
+
* which the function call setreccookie(cookie, ptr, ${rc}) was most recently
|
295
|
+
* made has incrased.
|
296
|
+
*/
|
297
|
+
void
|
298
|
+
ptrheap_increase(struct ptrheap * H, size_t rc)
|
299
|
+
{
|
300
|
+
|
301
|
+
/* Move the element down if necessary. */
|
302
|
+
heapify(H->elems, rc, H->nelems,
|
303
|
+
H->compar, H->setreccookie, H->cookie);
|
304
|
+
}
|
305
|
+
|
306
|
+
/**
|
307
|
+
* ptrheap_increasemin(H):
|
308
|
+
* Adjust the heap ${H} to account for the fact that the (formerly) minimum
|
309
|
+
* element has increased.
|
310
|
+
*/
|
311
|
+
void
|
312
|
+
ptrheap_increasemin(struct ptrheap * H)
|
313
|
+
{
|
314
|
+
|
315
|
+
/* Move the element down if necessary. */
|
316
|
+
heapify(H->elems, 0, H->nelems,
|
317
|
+
H->compar, H->setreccookie, H->cookie);
|
318
|
+
}
|
319
|
+
|
320
|
+
/**
|
321
|
+
* ptrheap_free(H):
|
322
|
+
* Free the pointer heap ${H}.
|
323
|
+
*/
|
324
|
+
void
|
325
|
+
ptrheap_free(struct ptrheap * H)
|
326
|
+
{
|
327
|
+
|
328
|
+
/* Be compatible with free(NULL). */
|
329
|
+
if (H == NULL)
|
330
|
+
return;
|
331
|
+
|
332
|
+
ptrlist_free(H->elems);
|
333
|
+
free(H);
|
334
|
+
}
|