fuzz_ball 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 */
|