fuzz_ball 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/fuzz_ball/duple_index/DupleIndex.c +276 -0
- data/ext/fuzz_ball/duple_index/DupleIndex.h +60 -0
- data/ext/fuzz_ball/duple_index/extconf.rb +5 -0
- data/ext/fuzz_ball/duple_index/utarray.h +226 -0
- data/ext/fuzz_ball/duple_index/uthash.h +904 -0
- data/ext/fuzz_ball/duple_index/utlist.h +522 -0
- data/ext/fuzz_ball/duple_index/utstring.h +148 -0
- data/ext/fuzz_ball/smith_waterman/SmithWaterman.c +211 -0
- data/ext/fuzz_ball/smith_waterman/SmithWaterman.h +19 -0
- data/ext/fuzz_ball/smith_waterman/extconf.rb +5 -0
- data/lib/fuzz_ball.rb +6 -0
- data/lib/fuzz_ball/searcher.rb +92 -0
- metadata +66 -0
@@ -0,0 +1,276 @@
|
|
1
|
+
// Include the Ruby headers and goodies
|
2
|
+
#include <ruby.h>
|
3
|
+
#include "uthash.h"
|
4
|
+
#include <DupleIndex.h>
|
5
|
+
|
6
|
+
// The initialization method for this module
|
7
|
+
void Init_duple_index() {
|
8
|
+
FuzzBall = rb_define_module("FuzzBall");
|
9
|
+
DupleIndex = rb_define_class_under(FuzzBall, "DupleIndex", rb_cObject);
|
10
|
+
|
11
|
+
rb_define_alloc_func(DupleIndex, method_alloc_index);
|
12
|
+
rb_define_method(DupleIndex, "add", method_add, 2);
|
13
|
+
rb_define_method(DupleIndex, "match", method_match, 1);
|
14
|
+
}
|
15
|
+
|
16
|
+
/* method_alloc_index
|
17
|
+
*
|
18
|
+
* This method is a custom allocation method where we initialize
|
19
|
+
* the hash that will serve as the duple_index and store it in the
|
20
|
+
* duples pointer. We then store it within the instantiated ruby
|
21
|
+
* object for later use.
|
22
|
+
*/
|
23
|
+
VALUE method_alloc_index(VALUE self) {
|
24
|
+
struct duples_hash *duples, *ptr;
|
25
|
+
|
26
|
+
// Initialize the hash with a single, hidden entry so that
|
27
|
+
// the *duples pointer doesn't point to NULL
|
28
|
+
ptr = malloc(sizeof(struct duples_hash));
|
29
|
+
ptr->id = duple_id(-1, -1);
|
30
|
+
ptr->strings = create_duple_pos(-1, -1, NULL, NULL);
|
31
|
+
|
32
|
+
HASH_ADD_INT(duples, id, ptr);
|
33
|
+
|
34
|
+
return Data_Wrap_Struct(self, NULL, method_free_index, duples);
|
35
|
+
}
|
36
|
+
|
37
|
+
/* method_free_index
|
38
|
+
*
|
39
|
+
* called by ruby when it's trying to free the instantiated
|
40
|
+
* DupleIndex class. In this method, we start the deallocation
|
41
|
+
* of memory by iterating over each hash member and calling
|
42
|
+
* free successively.
|
43
|
+
*/
|
44
|
+
static void method_free_index(void *duples) {
|
45
|
+
destroy_index( duples );
|
46
|
+
}
|
47
|
+
|
48
|
+
/* destroy_index
|
49
|
+
*
|
50
|
+
* loops over each key in the duples hash, frees the memory
|
51
|
+
* associated with each hash member by deallocating the linked
|
52
|
+
* list that stores duple positions.
|
53
|
+
*/
|
54
|
+
void destroy_index(struct duples_hash *duples) {
|
55
|
+
struct duples_hash *d, *d_tmp;
|
56
|
+
|
57
|
+
HASH_ITER(hh, duples, d, d_tmp) {
|
58
|
+
destroy_duple_pos(d->strings);
|
59
|
+
|
60
|
+
HASH_DEL(duples, d);
|
61
|
+
free(d);
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
/* destroy_duple_pos
|
66
|
+
*
|
67
|
+
* frees the memory used to store duple_pos structs
|
68
|
+
*/
|
69
|
+
void destroy_duple_pos(struct duple_pos *head) {
|
70
|
+
struct duple_pos *c_pos, *n_pos;
|
71
|
+
|
72
|
+
c_pos = head;
|
73
|
+
|
74
|
+
while (1) {
|
75
|
+
n_pos = c_pos->next;
|
76
|
+
free(c_pos);
|
77
|
+
|
78
|
+
if (n_pos == NULL) {
|
79
|
+
break;
|
80
|
+
} else {
|
81
|
+
c_pos = n_pos;
|
82
|
+
}
|
83
|
+
}
|
84
|
+
}
|
85
|
+
|
86
|
+
/* method_add
|
87
|
+
*
|
88
|
+
* ruby public method that allows one to add strings to the duple index.
|
89
|
+
* strings are represented by a unique index (r_str_id) and by an array
|
90
|
+
* of ints, that represent each character. The add method will then
|
91
|
+
* index where each duple appears, allowing quick recall of what strings
|
92
|
+
* and where in those strings a given duple appears.
|
93
|
+
*/
|
94
|
+
VALUE method_add(VALUE self, VALUE r_str_id, VALUE r_str) {
|
95
|
+
int i, str_id, str_len, c_a, c_b;
|
96
|
+
struct duples_hash *duples;
|
97
|
+
|
98
|
+
Data_Get_Struct(self, struct duples_hash, duples);
|
99
|
+
str_len = (int) RARRAY_LEN(r_str);
|
100
|
+
str_id = NUM2INT( r_str_id );
|
101
|
+
|
102
|
+
for (i=0; i<(str_len-1); i++) {
|
103
|
+
c_a = NUM2INT( RARRAY_PTR(r_str)[i] );
|
104
|
+
c_b = NUM2INT( RARRAY_PTR(r_str)[i+1] );
|
105
|
+
add_duple(duples, c_a, c_b, str_id, i);
|
106
|
+
}
|
107
|
+
|
108
|
+
return Qtrue;
|
109
|
+
}
|
110
|
+
|
111
|
+
/* duple_id
|
112
|
+
*
|
113
|
+
* method that hashes the two intergers that represent a duple into a
|
114
|
+
* unique integer value. Pretty simple algo.
|
115
|
+
*/
|
116
|
+
int duple_id(int c_a, int c_b) {
|
117
|
+
return c_b + (c_a % MAX_CHARS) * MAX_CHARS;
|
118
|
+
}
|
119
|
+
|
120
|
+
/* duple_at
|
121
|
+
*
|
122
|
+
* method that allows one to find which strings (and where in those strings)
|
123
|
+
* a given duple appears (represented by two ints, c_a and c_b)
|
124
|
+
*/
|
125
|
+
struct duples_hash *duple_at(struct duples_hash *duples, int c_a, int c_b) {
|
126
|
+
int d_id;
|
127
|
+
struct duples_hash *d;
|
128
|
+
|
129
|
+
d_id = duple_id(c_a, c_b);
|
130
|
+
HASH_FIND_INT(duples, &d_id, d);
|
131
|
+
|
132
|
+
return d;
|
133
|
+
}
|
134
|
+
|
135
|
+
/* add_duple
|
136
|
+
*
|
137
|
+
* Add a duple (represented by c_a and c_b) to the index, given the string (index)
|
138
|
+
* and position(pos) it appears.
|
139
|
+
*/
|
140
|
+
void add_duple(struct duples_hash *duples, int c_a, int c_b, int index, int pos) {
|
141
|
+
struct duples_hash *ptr;
|
142
|
+
struct duple_pos *d_pos;
|
143
|
+
|
144
|
+
ptr = duple_at(duples, c_a, c_b);
|
145
|
+
if (ptr == NULL) {
|
146
|
+
ptr = malloc(sizeof(struct duples_hash));
|
147
|
+
ptr->id = duple_id(c_a, c_b);
|
148
|
+
ptr->strings = create_duple_pos(index, pos, NULL, NULL);
|
149
|
+
|
150
|
+
HASH_ADD_INT(duples, id, ptr);
|
151
|
+
|
152
|
+
} else {
|
153
|
+
d_pos = create_duple_pos(index, pos, ptr->strings, NULL);
|
154
|
+
ptr->strings->prev = d_pos;
|
155
|
+
ptr->strings = d_pos;
|
156
|
+
}
|
157
|
+
}
|
158
|
+
|
159
|
+
struct duple_pos *create_duple_pos(int index, int pos, struct duple_pos *next, struct duple_pos *prev) {
|
160
|
+
struct duple_pos *ptr;
|
161
|
+
|
162
|
+
ptr = malloc( sizeof(struct duple_pos) );
|
163
|
+
|
164
|
+
ptr->index = index;
|
165
|
+
ptr->pos = pos;
|
166
|
+
ptr->next = next;
|
167
|
+
ptr->prev = prev;
|
168
|
+
|
169
|
+
return ptr;
|
170
|
+
}
|
171
|
+
|
172
|
+
/* method_match
|
173
|
+
*
|
174
|
+
* this is a ruby public method that allows us to query the duple index. For a given
|
175
|
+
* needle string (represented as an array of numbers), we want to return a hash that
|
176
|
+
* lists which strings matched the needle, by how many times a duple in the needle
|
177
|
+
* matched a duple in the hits. To do that, we loop over the duples in the needle
|
178
|
+
* string, find which strings match that duple, then keep track of how many times a
|
179
|
+
* string matched a duple in the needle.
|
180
|
+
* */
|
181
|
+
VALUE method_match(VALUE self, VALUE needle) {
|
182
|
+
|
183
|
+
int i, n_needle, c_a, c_b, match_id;
|
184
|
+
struct match *matches, *match, *match_tmp;
|
185
|
+
struct duples_hash *duples, *duple;
|
186
|
+
struct duple_pos *pos;
|
187
|
+
VALUE matches_by_score = rb_hash_new();
|
188
|
+
VALUE arr;
|
189
|
+
|
190
|
+
Data_Get_Struct(self, struct duples_hash, duples);
|
191
|
+
matches = NULL;
|
192
|
+
|
193
|
+
n_needle = (int) RARRAY_LEN(needle);
|
194
|
+
|
195
|
+
if (n_needle < 2)
|
196
|
+
return matches_by_score; // If the needle has fewer than two chars,
|
197
|
+
// it's not a duple so return immediately
|
198
|
+
|
199
|
+
// Loop over each duple in the needle string
|
200
|
+
for (i=0; i<(n_needle-1); i++) {
|
201
|
+
c_a = NUM2INT( RARRAY_PTR(needle)[i] );
|
202
|
+
c_b = NUM2INT( RARRAY_PTR(needle)[i+1] );
|
203
|
+
|
204
|
+
duple = duple_at(duples, c_a, c_b); // Find the strings and positions
|
205
|
+
// where this duple is found
|
206
|
+
|
207
|
+
if (duple != NULL ) {
|
208
|
+
pos = duple->strings;
|
209
|
+
while (1) { // Loop over the strings where duple is found
|
210
|
+
|
211
|
+
// if String not found in matches hash, create new pointer
|
212
|
+
match_id = pos->index;
|
213
|
+
HASH_FIND_INT(matches, &match_id, match);
|
214
|
+
|
215
|
+
if (match == NULL) {
|
216
|
+
match = create_match(match_id, pos->pos, c_a, c_b);
|
217
|
+
HASH_ADD_INT(matches, id, match);
|
218
|
+
|
219
|
+
} else {
|
220
|
+
/* Only update the match count if the next matching duple appears
|
221
|
+
* *AFTER* the last matched duple. For instance, with a needle string
|
222
|
+
* of 'abc' and a indexed string of 'bcab', we don't want the 'bc'
|
223
|
+
* duple to match since it appears before 'ab' in the indexed string,
|
224
|
+
* whereas it appears after in the needle string.
|
225
|
+
*/
|
226
|
+
if ((match->last_matched_position < pos->pos) && (match->last_matched_ca != c_a) && (match->last_matched_cb != c_b)) {
|
227
|
+
update_match( match, pos->pos, c_a, c_b );
|
228
|
+
}
|
229
|
+
}
|
230
|
+
|
231
|
+
if (pos->next == NULL)
|
232
|
+
break;
|
233
|
+
|
234
|
+
pos = pos->next;
|
235
|
+
}
|
236
|
+
}
|
237
|
+
}
|
238
|
+
|
239
|
+
// Loop over matches and construct the Ruby hash that stores the matching
|
240
|
+
// strings by the number of times they matched. Also free up memory as we go.
|
241
|
+
HASH_ITER(hh, matches, match, match_tmp) {
|
242
|
+
arr = rb_hash_aref(matches_by_score, INT2NUM(match->n_matches));
|
243
|
+
if (arr == Qnil)
|
244
|
+
arr = rb_ary_new();
|
245
|
+
|
246
|
+
rb_ary_push(arr, INT2NUM(match->id));
|
247
|
+
rb_hash_aset(matches_by_score, INT2NUM(match->n_matches), arr);
|
248
|
+
|
249
|
+
HASH_DEL(matches, match);
|
250
|
+
free(match);
|
251
|
+
}
|
252
|
+
|
253
|
+
return matches_by_score;
|
254
|
+
}
|
255
|
+
|
256
|
+
struct match *create_match(int id, int pos, int c_a, int c_b) {
|
257
|
+
struct match *new_match;
|
258
|
+
|
259
|
+
new_match = malloc( sizeof(struct match) );
|
260
|
+
|
261
|
+
new_match->id = id;
|
262
|
+
new_match->n_matches = 1;
|
263
|
+
new_match->last_matched_position = pos;
|
264
|
+
new_match->last_matched_ca = c_a;
|
265
|
+
new_match->last_matched_cb = c_b;
|
266
|
+
|
267
|
+
return new_match;
|
268
|
+
}
|
269
|
+
|
270
|
+
void update_match(struct match* match, int pos, int c_a, int c_b) {
|
271
|
+
match->n_matches++;
|
272
|
+
match->last_matched_position = pos;
|
273
|
+
match->last_matched_ca = c_a;
|
274
|
+
match->last_matched_cb = c_b;
|
275
|
+
}
|
276
|
+
|
@@ -0,0 +1,60 @@
|
|
1
|
+
#define MAX_CHARS 1000
|
2
|
+
|
3
|
+
/* duples_hash is the struct that is the "core" of the duple index.
|
4
|
+
* The id field is a unique integer that represents a unique duple.
|
5
|
+
* the duple_pos pointer is a pointer to a linked list that stores
|
6
|
+
* all of the strings that a given duple appears in.
|
7
|
+
*/
|
8
|
+
struct duples_hash {
|
9
|
+
int id;
|
10
|
+
struct duple_pos *strings;
|
11
|
+
UT_hash_handle hh;
|
12
|
+
};
|
13
|
+
|
14
|
+
/* duple_pos is a node on a doubly-linked list that stores the index
|
15
|
+
* of the string and where inside the string a particular duple appears.
|
16
|
+
* The linked list will store all of the locations where a duple appears.
|
17
|
+
*/
|
18
|
+
struct duple_pos {
|
19
|
+
int index;
|
20
|
+
int pos;
|
21
|
+
|
22
|
+
struct duple_pos *next;
|
23
|
+
struct duple_pos *prev;
|
24
|
+
};
|
25
|
+
|
26
|
+
/* match is a struct that keeps track of how many duples match in a given
|
27
|
+
* string. The id field is the id of the string, n_matches is the number
|
28
|
+
* of duples that have matched, the last_matched_position is the position
|
29
|
+
* of the last matching duple, and last_matched_ca and last_matched_cb
|
30
|
+
* records the first and second character of the last matched duple.
|
31
|
+
*/
|
32
|
+
struct match {
|
33
|
+
int id;
|
34
|
+
int n_matches;
|
35
|
+
int last_matched_position;
|
36
|
+
int last_matched_ca;
|
37
|
+
int last_matched_cb;
|
38
|
+
|
39
|
+
UT_hash_handle hh;
|
40
|
+
};
|
41
|
+
|
42
|
+
// Ruby-related declarations
|
43
|
+
VALUE FuzzBall = Qnil;
|
44
|
+
VALUE DupleIndex = Qnil;
|
45
|
+
|
46
|
+
void Init_duple_index();
|
47
|
+
VALUE method_alloc_index(VALUE self);
|
48
|
+
static void method_free_index(void *duples);
|
49
|
+
VALUE method_add(VALUE self, VALUE r_str_id, VALUE r_str);
|
50
|
+
VALUE method_match(VALUE self, VALUE needle);
|
51
|
+
|
52
|
+
// Internally-used C-declarations (i.e., private methods)
|
53
|
+
void add_duple(struct duples_hash *duples, int c_a, int c_b, int index, int pos);
|
54
|
+
struct duples_hash *duple_at(struct duples_hash *duples, int c_a, int c_b);
|
55
|
+
int duple_id(int c_a, int c_b);
|
56
|
+
struct duple_pos *create_duple_pos(int index, int pos, struct duple_pos *next, struct duple_pos *prev);
|
57
|
+
void destroy_index(struct duples_hash *duples);
|
58
|
+
void destroy_duple_pos(struct duple_pos *head);
|
59
|
+
struct match *create_match(int id, int pos, int c_a, int c_b);
|
60
|
+
void update_match(struct match* match, int pos, int c_a, int c_b);
|
@@ -0,0 +1,226 @@
|
|
1
|
+
/*
|
2
|
+
Copyright (c) 2008-2011, Troy D. Hanson http://uthash.sourceforge.net
|
3
|
+
All rights reserved.
|
4
|
+
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
7
|
+
|
8
|
+
* Redistributions of source code must retain the above copyright
|
9
|
+
notice, this list of conditions and the following disclaimer.
|
10
|
+
|
11
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
12
|
+
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
13
|
+
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
14
|
+
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
15
|
+
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
16
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
17
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
18
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
19
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
20
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
21
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
22
|
+
*/
|
23
|
+
|
24
|
+
/* a dynamic array implementation using macros
|
25
|
+
* see http://uthash.sourceforge.net/utarray
|
26
|
+
*/
|
27
|
+
#ifndef UTARRAY_H
|
28
|
+
#define UTARRAY_H
|
29
|
+
|
30
|
+
#define UTARRAY_VERSION 1.9.4
|
31
|
+
|
32
|
+
#ifdef __GNUC__
|
33
|
+
#define _UNUSED_ __attribute__ ((__unused__))
|
34
|
+
#else
|
35
|
+
#define _UNUSED_
|
36
|
+
#endif
|
37
|
+
|
38
|
+
#include <stddef.h> /* size_t */
|
39
|
+
#include <string.h> /* memset, etc */
|
40
|
+
#include <stdlib.h> /* exit */
|
41
|
+
|
42
|
+
#define oom() exit(-1)
|
43
|
+
|
44
|
+
typedef void (ctor_f)(void *dst, const void *src);
|
45
|
+
typedef void (dtor_f)(void *elt);
|
46
|
+
typedef void (init_f)(void *elt);
|
47
|
+
typedef struct {
|
48
|
+
size_t sz;
|
49
|
+
init_f *init;
|
50
|
+
ctor_f *copy;
|
51
|
+
dtor_f *dtor;
|
52
|
+
} UT_icd;
|
53
|
+
|
54
|
+
typedef struct {
|
55
|
+
unsigned i,n;/* i: index of next available slot, n: num slots */
|
56
|
+
const UT_icd *icd; /* initializer, copy and destructor functions */
|
57
|
+
char *d; /* n slots of size icd->sz*/
|
58
|
+
} UT_array;
|
59
|
+
|
60
|
+
#define utarray_init(a,_icd) do { \
|
61
|
+
memset(a,0,sizeof(UT_array)); \
|
62
|
+
(a)->icd=_icd; \
|
63
|
+
} while(0)
|
64
|
+
|
65
|
+
#define utarray_done(a) do { \
|
66
|
+
if ((a)->n) { \
|
67
|
+
if ((a)->icd->dtor) { \
|
68
|
+
size_t _ut_i; \
|
69
|
+
for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \
|
70
|
+
(a)->icd->dtor(utarray_eltptr(a,_ut_i)); \
|
71
|
+
} \
|
72
|
+
} \
|
73
|
+
free((a)->d); \
|
74
|
+
} \
|
75
|
+
(a)->n=0; \
|
76
|
+
} while(0)
|
77
|
+
|
78
|
+
#define utarray_new(a,_icd) do { \
|
79
|
+
a=(UT_array*)malloc(sizeof(UT_array)); \
|
80
|
+
utarray_init(a,_icd); \
|
81
|
+
} while(0)
|
82
|
+
|
83
|
+
#define utarray_free(a) do { \
|
84
|
+
utarray_done(a); \
|
85
|
+
free(a); \
|
86
|
+
} while(0)
|
87
|
+
|
88
|
+
#define utarray_reserve(a,by) do { \
|
89
|
+
if (((a)->i+by) > ((a)->n)) { \
|
90
|
+
while(((a)->i+by) > ((a)->n)) { (a)->n = ((a)->n ? (2*(a)->n) : 8); } \
|
91
|
+
if ( ((a)->d=(char*)realloc((a)->d, (a)->n*(a)->icd->sz)) == NULL) oom(); \
|
92
|
+
} \
|
93
|
+
} while(0)
|
94
|
+
|
95
|
+
#define utarray_push_back(a,p) do { \
|
96
|
+
utarray_reserve(a,1); \
|
97
|
+
if ((a)->icd->copy) { (a)->icd->copy( _utarray_eltptr(a,(a)->i++), p); } \
|
98
|
+
else { memcpy(_utarray_eltptr(a,(a)->i++), p, (a)->icd->sz); }; \
|
99
|
+
} while(0)
|
100
|
+
|
101
|
+
#define utarray_pop_back(a) do { \
|
102
|
+
if ((a)->icd->dtor) { (a)->icd->dtor( _utarray_eltptr(a,--((a)->i))); } \
|
103
|
+
else { (a)->i--; } \
|
104
|
+
} while(0)
|
105
|
+
|
106
|
+
#define utarray_extend_back(a) do { \
|
107
|
+
utarray_reserve(a,1); \
|
108
|
+
if ((a)->icd->init) { (a)->icd->init(_utarray_eltptr(a,(a)->i)); } \
|
109
|
+
else { memset(_utarray_eltptr(a,(a)->i),0,(a)->icd->sz); } \
|
110
|
+
(a)->i++; \
|
111
|
+
} while(0)
|
112
|
+
|
113
|
+
#define utarray_len(a) ((a)->i)
|
114
|
+
|
115
|
+
#define utarray_eltptr(a,j) (((j) < (a)->i) ? _utarray_eltptr(a,j) : NULL)
|
116
|
+
#define _utarray_eltptr(a,j) ((char*)((a)->d + ((a)->icd->sz*(j) )))
|
117
|
+
|
118
|
+
#define utarray_insert(a,p,j) do { \
|
119
|
+
utarray_reserve(a,1); \
|
120
|
+
if (j > (a)->i) break; \
|
121
|
+
if ((j) < (a)->i) { \
|
122
|
+
memmove( _utarray_eltptr(a,(j)+1), _utarray_eltptr(a,j), \
|
123
|
+
((a)->i - (j))*((a)->icd->sz)); \
|
124
|
+
} \
|
125
|
+
if ((a)->icd->copy) { (a)->icd->copy( _utarray_eltptr(a,j), p); } \
|
126
|
+
else { memcpy(_utarray_eltptr(a,j), p, (a)->icd->sz); }; \
|
127
|
+
(a)->i++; \
|
128
|
+
} while(0)
|
129
|
+
|
130
|
+
#define utarray_inserta(a,w,j) do { \
|
131
|
+
if (utarray_len(w) == 0) break; \
|
132
|
+
if (j > (a)->i) break; \
|
133
|
+
utarray_reserve(a,utarray_len(w)); \
|
134
|
+
if ((j) < (a)->i) { \
|
135
|
+
memmove(_utarray_eltptr(a,(j)+utarray_len(w)), \
|
136
|
+
_utarray_eltptr(a,j), \
|
137
|
+
((a)->i - (j))*((a)->icd->sz)); \
|
138
|
+
} \
|
139
|
+
if ((a)->icd->copy) { \
|
140
|
+
size_t _ut_i; \
|
141
|
+
for(_ut_i=0;_ut_i<(w)->i;_ut_i++) { \
|
142
|
+
(a)->icd->copy(_utarray_eltptr(a,j+_ut_i), _utarray_eltptr(w,_ut_i)); \
|
143
|
+
} \
|
144
|
+
} else { \
|
145
|
+
memcpy(_utarray_eltptr(a,j), _utarray_eltptr(w,0), \
|
146
|
+
utarray_len(w)*((a)->icd->sz)); \
|
147
|
+
} \
|
148
|
+
(a)->i += utarray_len(w); \
|
149
|
+
} while(0)
|
150
|
+
|
151
|
+
#define utarray_resize(dst,num) do { \
|
152
|
+
size_t _ut_i; \
|
153
|
+
if (dst->i > (size_t)(num)) { \
|
154
|
+
if ((dst)->icd->dtor) { \
|
155
|
+
for(_ut_i=num; _ut_i < dst->i; _ut_i++) { \
|
156
|
+
(dst)->icd->dtor(utarray_eltptr(dst,_ut_i)); \
|
157
|
+
} \
|
158
|
+
} \
|
159
|
+
} else if (dst->i < (size_t)(num)) { \
|
160
|
+
utarray_reserve(dst,num-dst->i); \
|
161
|
+
if ((dst)->icd->init) { \
|
162
|
+
for(_ut_i=dst->i; _ut_i < num; _ut_i++) { \
|
163
|
+
(dst)->icd->init(utarray_eltptr(dst,_ut_i)); \
|
164
|
+
} \
|
165
|
+
} else { \
|
166
|
+
memset(_utarray_eltptr(dst,dst->i),0,(dst)->icd->sz*(num-dst->i)); \
|
167
|
+
} \
|
168
|
+
} \
|
169
|
+
dst->i = num; \
|
170
|
+
} while(0)
|
171
|
+
|
172
|
+
#define utarray_concat(dst,src) do { \
|
173
|
+
utarray_inserta((dst),(src),utarray_len(dst)); \
|
174
|
+
} while(0)
|
175
|
+
|
176
|
+
#define utarray_erase(a,pos,len) do { \
|
177
|
+
if ((a)->icd->dtor) { \
|
178
|
+
size_t _ut_i; \
|
179
|
+
for(_ut_i=0; _ut_i < len; _ut_i++) { \
|
180
|
+
(a)->icd->dtor(utarray_eltptr(a,pos+_ut_i)); \
|
181
|
+
} \
|
182
|
+
} \
|
183
|
+
if ((a)->i > (pos+len)) { \
|
184
|
+
memmove( _utarray_eltptr(a,pos), _utarray_eltptr(a,pos+len), \
|
185
|
+
((a->i)-(pos+len))*((a)->icd->sz)); \
|
186
|
+
} \
|
187
|
+
(a)->i -= (len); \
|
188
|
+
} while(0)
|
189
|
+
|
190
|
+
#define utarray_clear(a) do { \
|
191
|
+
if ((a)->i > 0) { \
|
192
|
+
if ((a)->icd->dtor) { \
|
193
|
+
size_t _ut_i; \
|
194
|
+
for(_ut_i=0; _ut_i < (a)->i; _ut_i++) { \
|
195
|
+
(a)->icd->dtor(utarray_eltptr(a,_ut_i)); \
|
196
|
+
} \
|
197
|
+
} \
|
198
|
+
(a)->i = 0; \
|
199
|
+
} \
|
200
|
+
} while(0)
|
201
|
+
|
202
|
+
#define utarray_sort(a,cmp) do { \
|
203
|
+
qsort((a)->d, (a)->i, (a)->icd->sz, cmp); \
|
204
|
+
} while(0)
|
205
|
+
|
206
|
+
#define utarray_find(a,v,cmp) bsearch((v),(a)->d,(a)->i,(a)->icd->sz,cmp)
|
207
|
+
|
208
|
+
#define utarray_front(a) (((a)->i) ? (_utarray_eltptr(a,0)) : NULL)
|
209
|
+
#define utarray_next(a,e) (((e)==NULL) ? utarray_front(a) : ((((a)->i) > (utarray_eltidx(a,e)+1)) ? _utarray_eltptr(a,utarray_eltidx(a,e)+1) : NULL))
|
210
|
+
#define utarray_back(a) (((a)->i) ? (_utarray_eltptr(a,(a)->i-1)) : NULL)
|
211
|
+
#define utarray_eltidx(a,e) (((char*)(e) >= (char*)((a)->d)) ? (((char*)(e) - (char*)((a)->d))/(a)->icd->sz) : -1)
|
212
|
+
|
213
|
+
/* last we pre-define a few icd for common utarrays of ints and strings */
|
214
|
+
static void utarray_str_cpy(void *dst, const void *src) {
|
215
|
+
char **_src = (char**)src, **_dst = (char**)dst;
|
216
|
+
*_dst = (*_src == NULL) ? NULL : strdup(*_src);
|
217
|
+
}
|
218
|
+
static void utarray_str_dtor(void *elt) {
|
219
|
+
char **eltc = (char**)elt;
|
220
|
+
if (*eltc) free(*eltc);
|
221
|
+
}
|
222
|
+
static const UT_icd ut_str_icd _UNUSED_ = {sizeof(char*),NULL,utarray_str_cpy,utarray_str_dtor};
|
223
|
+
static const UT_icd ut_int_icd _UNUSED_ = {sizeof(int),NULL,NULL,NULL};
|
224
|
+
|
225
|
+
|
226
|
+
#endif /* UTARRAY_H */
|