fuzz_ball 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,5 @@
1
+ require 'mkmf'
2
+
3
+ dir_config("fuzz_ball/duple_index")
4
+ create_makefile("fuzz_ball/duple_index")
5
+
@@ -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 */