1 /* -*- Mode: c; c-basic-offset: 2 -*-
2 *
3 * raptor_sequence.c - Raptor sequence support
4 *
5 * Copyright (C) 2003-2008, David Beckett http://www.dajobe.org/
6 * Copyright (C) 2003-2004, University of Bristol, UK http://www.bristol.ac.uk/
7 *
8 * This package is Free Software and part of Redland http://librdf.org/
9 *
10 * It is licensed under the following three licenses as alternatives:
11 * 1. GNU Lesser General Public License (LGPL) V2.1 or any newer version
12 * 2. GNU General Public License (GPL) V2 or any newer version
13 * 3. Apache License, V2.0 or any newer version
14 *
15 * You may not use this file except in compliance with at least one of
16 * the above three licenses.
17 *
18 * See LICENSE.html or LICENSE.txt at the top of this package for the
19 * complete terms and further detail along with the license texts for
20 * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively.
21 *
22 *
23 *
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #include <raptor_config.h>
28 #endif
29
30 #ifdef WIN32
31 #include <win32_raptor_config.h>
32 #endif
33
34 #include <stdio.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <stdarg.h>
38 #ifdef HAVE_ERRNO_H
39 #include <errno.h>
40 #endif
41 #ifdef HAVE_STDLIB_H
42 #include <stdlib.h>
43 #endif
44
45
46 #include "raptor.h"
47 #include "raptor_internal.h"
48
49
50 #ifndef STANDALONE
51
52 /*
53 * Sequence of maximum capacity C containing N data items
54 *
55 * array:
56 * 0 <-- N consecutive items --> C - 1
57 * -----------------------------------------------------------
58 * | | | data1 | ..... data N | ... | |
59 * -----------------------------------------------------------
60 * ------ O -----> offset of first data item
61 *
62 * start = O
63 * size = N
64 * capacity = C
65 *
66 */
67 struct raptor_sequence_s {
68 /* how many items are in the sequence 0..capacity */
69 int size;
70
71 /* length of the 'sequence' array below */
72 int capacity;
73
74 /* offset of the first data item in the sequence: 0..capacity-1 */
75 int start;
76
77 /* array of size 'capacity' pointing to the data */
78 void **sequence;
79
80 /* handler to call to free a data item (or NULL) */
81 raptor_sequence_free_handler *free_handler;
82 raptor_sequence_free_handler_v2 *free_handler_v2;
83
84 /* handler to call to print a data item (or NULL) */
85 raptor_sequence_print_handler *print_handler;
86 raptor_sequence_print_handler_v2 *print_handler_v2;
87
88 /* free/print handler context data */
89 void *handler_context;
90 };
91
92
93 static int raptor_sequence_ensure(raptor_sequence *seq, int capacity, int grow_at_front);
94
95 /**
96 * raptor_new_sequence:
97 * @free_handler: handler to free a sequence item
98 * @print_handler: handler to print a sequence item to a FILE*
99 *
100 * Constructor - create a new sequence with the given handlers.
101 *
102 * Return value: a new #raptor_sequence or NULL on failure
103 **/
104 raptor_sequence*
raptor_new_sequence(raptor_sequence_free_handler * free_handler,raptor_sequence_print_handler * print_handler)105 raptor_new_sequence(raptor_sequence_free_handler *free_handler,
106 raptor_sequence_print_handler *print_handler)
107 {
108 raptor_sequence* seq=(raptor_sequence*)RAPTOR_CALLOC(raptor_sequence, 1, sizeof(raptor_sequence));
109 if(!seq)
110 return NULL;
111 seq->free_handler=free_handler;
112 seq->print_handler=print_handler;
113
114 return seq;
115 }
116
117
118 /**
119 * raptor_new_sequence_v2:
120 * @free_handler: handler to free a sequence item
121 * @print_handler: handler to print a sequence item to a FILE*
122 * @handler_context: context information to pass to free/print handlers
123 *
124 * Constructor - create a new sequence with the given handlers and handler context.
125 *
126 * Return value: a new #raptor_sequence or NULL on failure
127 **/
128 raptor_sequence*
raptor_new_sequence_v2(raptor_sequence_free_handler_v2 * free_handler,raptor_sequence_print_handler_v2 * print_handler,void * handler_context)129 raptor_new_sequence_v2(raptor_sequence_free_handler_v2 *free_handler,
130 raptor_sequence_print_handler_v2 *print_handler,
131 void *handler_context)
132 {
133 raptor_sequence* seq=(raptor_sequence*)RAPTOR_CALLOC(raptor_sequence, 1, sizeof(raptor_sequence));
134 if(!seq)
135 return NULL;
136 seq->free_handler_v2=free_handler;
137 seq->print_handler_v2=print_handler;
138 seq->handler_context=handler_context;
139
140 return seq;
141 }
142
143
144 /**
145 * raptor_free_sequence:
146 * @seq: sequence to destroy
147 *
148 * Destructor - free a #raptor_sequence
149 **/
150 void
raptor_free_sequence(raptor_sequence * seq)151 raptor_free_sequence(raptor_sequence* seq)
152 {
153 int i;
154 int j;
155
156 RAPTOR_ASSERT_OBJECT_POINTER_RETURN(seq, raptor_sequence);
157
158 if(seq->free_handler) {
159 for(i=seq->start, j=seq->start+seq->size; i<j; i++)
160 if(seq->sequence[i])
161 seq->free_handler(seq->sequence[i]);
162 } else if(seq->free_handler_v2) {
163 for(i=seq->start, j=seq->start+seq->size; i<j; i++)
164 if(seq->sequence[i])
165 seq->free_handler_v2(seq->handler_context, seq->sequence[i]);
166 }
167
168 if(seq->sequence)
169 RAPTOR_FREE(ptrarray, seq->sequence);
170
171 RAPTOR_FREE(raptor_sequence, seq);
172 }
173
174
175 static int
raptor_sequence_ensure(raptor_sequence * seq,int capacity,int grow_at_front)176 raptor_sequence_ensure(raptor_sequence *seq, int capacity, int grow_at_front)
177 {
178 void **new_sequence;
179 int offset;
180
181 RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(seq, raptor_sequence, 1);
182
183 if(capacity && seq->capacity >= capacity)
184 return 0;
185
186 /* POLICY - minimum size */
187 if(capacity < 8)
188 capacity=8;
189
190 new_sequence=(void**)RAPTOR_CALLOC(ptrarray, capacity, sizeof(void*));
191 if(!new_sequence)
192 return 1;
193
194 offset=(grow_at_front ? (capacity-seq->capacity) : 0)+seq->start;
195 if(seq->size) {
196 memcpy(&new_sequence[offset], &seq->sequence[seq->start], sizeof(void*)*seq->size);
197 RAPTOR_FREE(ptrarray, seq->sequence);
198 }
199 seq->start=offset;
200
201 seq->sequence=new_sequence;
202 seq->capacity=capacity;
203 return 0;
204 }
205
206
207 /**
208 * raptor_sequence_size:
209 * @seq: sequence object
210 *
211 * Get the number of items in a sequence.
212 *
213 * Return value: the sequence size (>=0)
214 **/
215 int
raptor_sequence_size(raptor_sequence * seq)216 raptor_sequence_size(raptor_sequence* seq)
217 {
218 RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(seq, raptor_sequence, -1);
219
220 return seq->size;
221 }
222
223
224 /* Store methods */
225
226 /**
227 * raptor_sequence_set_at:
228 * @seq: sequence object
229 * @idx: index into sequence to operate at
230 * @data: new data item.
231 *
232 * Replace/set an item in a sequence.
233 *
234 * The item at the offset @idx in the sequence is replaced with the
235 * new item @data (which may be NULL). Any existing item is freed
236 * with the sequence's free_handler. If necessary the sequence
237 * is extended (with NULLs) to handle a larger offset.
238 *
239 * The sequence takes ownership of the new data item. On failure, the
240 * item is freed immediately.
241 *
242 * Return value: non-0 on failure
243 **/
244 int
raptor_sequence_set_at(raptor_sequence * seq,int idx,void * data)245 raptor_sequence_set_at(raptor_sequence* seq, int idx, void *data)
246 {
247 int need_capacity;
248
249 RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(seq, raptor_sequence, 1);
250
251 /* Cannot provide a negative index */
252 if(idx < 0) {
253 if(data) {
254 if(seq->free_handler)
255 seq->free_handler(data);
256 else if(seq->free_handler_v2)
257 seq->free_handler_v2(seq->handler_context, data);
258 }
259 return 1;
260 }
261
262 need_capacity=seq->start+idx+1;
263 if(need_capacity > seq->capacity) {
264 if(seq->capacity*2 > need_capacity)
265 need_capacity = seq->capacity*2;
266 if(raptor_sequence_ensure(seq, need_capacity, 0)) {
267 if(data) {
268 if(seq->free_handler)
269 seq->free_handler(data);
270 else if(seq->free_handler_v2)
271 seq->free_handler_v2(seq->handler_context, data);
272 }
273 return 1;
274 }
275 }
276
277 if(idx < seq->size) {
278 /* if there is old data, delete it if there is a free handler */
279 if(seq->sequence[seq->start+idx]) {
280 if(seq->free_handler)
281 seq->free_handler(seq->sequence[seq->start+idx]);
282 else if(seq->free_handler_v2)
283 seq->free_handler_v2(seq->handler_context, seq->sequence[seq->start+idx]);
284 }
285 /* size remains the same */
286 } else {
287 /* if there is no old data, size is increasing */
288 /* make sure there are seq->size items starting from seq->start */
289 seq->size=idx+1;
290 }
291
292 seq->sequence[seq->start+idx]=data;
293 return 0;
294 }
295
296
297
298 /**
299 * raptor_sequence_push:
300 * @seq: sequence to add to
301 * @data: item to add
302 *
303 * Add an item to the end of the sequence.
304 *
305 * The sequence takes ownership of the pushed item and frees it with the
306 * free_handler. On failure, the item is freed immediately.
307 *
308 * Return value: non-0 on failure
309 **/
310 int
raptor_sequence_push(raptor_sequence * seq,void * data)311 raptor_sequence_push(raptor_sequence* seq, void *data)
312 {
313 RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(seq, raptor_sequence, 1);
314
315 if(seq->start+seq->size == seq->capacity) {
316 if(raptor_sequence_ensure(seq, seq->capacity*2, 0)) {
317 if(data) {
318 if(seq->free_handler)
319 seq->free_handler(data);
320 else if(seq->free_handler_v2)
321 seq->free_handler_v2(seq->handler_context, data);
322 }
323 return 1;
324 }
325 }
326
327 seq->sequence[seq->start+seq->size]=data;
328 seq->size++;
329 return 0;
330 }
331
332
333 /**
334 * raptor_sequence_shift:
335 * @seq: sequence to add to
336 * @data: item to add
337 *
338 * Add an item to the start of the sequence.
339 *
340 * The sequence takes ownership of the shifted item and frees it with the
341 * free_handler. On failure, the item is freed immediately.
342 *
343 * Return value: non-0 on failure
344 **/
345 int
raptor_sequence_shift(raptor_sequence * seq,void * data)346 raptor_sequence_shift(raptor_sequence* seq, void *data)
347 {
348 RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(seq, raptor_sequence, 1);
349
350 if(!seq->start) {
351 if(raptor_sequence_ensure(seq, seq->capacity*2, 1)) {
352 if(data) {
353 if(seq->free_handler)
354 seq->free_handler(data);
355 else if(seq->free_handler_v2)
356 seq->free_handler_v2(seq->handler_context, data);
357 }
358 return 1;
359 }
360 }
361
362 seq->sequence[--seq->start]=data;
363 seq->size++;
364 return 0;
365 }
366
367
368 /**
369 * raptor_sequence_get_at:
370 * @seq: sequence to use
371 * @idx: index of item to get
372 *
373 * Retrieve an item at offset @index in the sequence.
374 *
375 * This is efficient to perform. #raptor_sequence is optimised
376 * to append/remove from the end of the sequence.
377 *
378 * After this call the item is still owned by the sequence.
379 *
380 * Return value: the object or NULL if @index is out of range (0... sequence size-1)
381 **/
382 void*
raptor_sequence_get_at(raptor_sequence * seq,int idx)383 raptor_sequence_get_at(raptor_sequence* seq, int idx)
384 {
385 RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(seq, raptor_sequence, NULL);
386
387 if(idx < 0 || idx > seq->size-1)
388 return NULL;
389 return seq->sequence[seq->start+idx];
390 }
391
392
393 /**
394 * raptor_sequence_delete_at:
395 * @seq: sequence object
396 * @idx: index into sequence to operate at
397 *
398 * Remove an item from a position a sequence, returning it
399 *
400 * The item at the offset @idx in the sequence is replaced with a
401 * NULL pointer and any existing item is returned. The caller
402 * owns the resulting item.
403 *
404 * Return value: NULL on failure
405 **/
406 void*
raptor_sequence_delete_at(raptor_sequence * seq,int idx)407 raptor_sequence_delete_at(raptor_sequence* seq, int idx)
408 {
409 void* data;
410
411 RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(seq, raptor_sequence, NULL);
412
413 if(idx < 0 || idx > seq->size-1)
414 return NULL;
415
416 data=seq->sequence[seq->start+idx];
417 seq->sequence[seq->start+idx]=NULL;
418
419 return data;
420 }
421
422
423
424 /**
425 * raptor_sequence_pop:
426 * @seq: sequence to use
427 *
428 * Retrieve the item at the end of the sequence.
429 *
430 * Ownership of the item is transferred to the caller,
431 * i.e. caller is responsible of freeing the item.
432 *
433 * Return value: the object or NULL if the sequence is empty
434 **/
435 void*
raptor_sequence_pop(raptor_sequence * seq)436 raptor_sequence_pop(raptor_sequence* seq)
437 {
438 void *data;
439 int i;
440
441 RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(seq, raptor_sequence, NULL);
442
443 if(!seq->size)
444 return NULL;
445
446 seq->size--;
447 i=seq->start+seq->size;
448 data=seq->sequence[i];
449 seq->sequence[i]=NULL;
450
451 return data;
452 }
453
454
455 /**
456 * raptor_sequence_unshift:
457 * @seq: sequence to use
458 *
459 * Retrieve the item at the start of the sequence.
460 *
461 * Ownership of the item is transferred to the caller,
462 * i.e. caller is responsible of freeing the item.
463 *
464 * Return value: the object or NULL if the sequence is empty
465 **/
466 void*
raptor_sequence_unshift(raptor_sequence * seq)467 raptor_sequence_unshift(raptor_sequence* seq)
468 {
469 void *data;
470 int i;
471
472 RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(seq, raptor_sequence, NULL);
473
474 if(!seq->size)
475 return NULL;
476
477 i=seq->start++;
478 data=seq->sequence[i];
479 seq->size--;
480 seq->sequence[i]=NULL;
481
482 return data;
483 }
484
485
486 /**
487 * raptor_compare_strings:
488 * @a: pointer first string
489 * @b: pointer to second string
490 *
491 * Utility function for raptor_sequence_sort() to compare a sequence of strings.
492 *
493 * Return value: comparison of @a to @b as strings
494 **/
495 int
raptor_compare_strings(const void * a,const void * b)496 raptor_compare_strings(const void *a, const void *b)
497 {
498 return strcmp(*(char**)a, *(char**)b);
499 }
500
501
502
503 /**
504 * raptor_sequence_sort:
505 * @seq: sequence to sort
506 * @compare: comparison function
507 *
508 * The comparison function is compatible with that used for qsort()
509 * and provides the addresses of pointers to the data that
510 * must be dereferenced to get to the stored sequence data.
511 *
512 **/
513 RAPTOR_EXTERN_C
514 void
raptor_sequence_sort(raptor_sequence * seq,int (* compare)(const void *,const void *))515 raptor_sequence_sort(raptor_sequence* seq,
516 int(*compare)(const void *, const void *))
517 {
518 RAPTOR_ASSERT_OBJECT_POINTER_RETURN(seq, raptor_sequence);
519
520 if(seq->size > 1)
521 qsort(&seq->sequence[seq->start], seq->size, sizeof(void*), compare);
522 }
523
524
525
526 /**
527 * raptor_sequence_print_string:
528 * @data: data item (a char*)
529 * @fh: file handle to print to
530 *
531 * Helper function for printing a sequence of strings.
532 *
533 * Intended for use as a #raptor_sequence_print_handler passed into
534 * raptor_new_sequence().
535 */
536 void
raptor_sequence_print_string(char * data,FILE * fh)537 raptor_sequence_print_string(char *data, FILE *fh)
538 {
539 fputs(data, fh);
540 }
541
542
543 #if !defined(RAPTOR_DISABLE_DEPRECATED) && !defined(RAPTOR_DISABLE_V1)
544 /**
545 * raptor_sequence_print_uri:
546 * @data: data item (a #raptor_uri)
547 * @fh: file handle to print to
548 *
549 * Helper function for printing a sequence of URIs.
550 *
551 * Intended for use as a #raptor_sequence_print_handler passed into
552 * raptor_new_sequence().
553 *
554 * raptor_init() MUST have been called before calling this function.
555 *
556 * @deprecated: Use raptor_uri_print() instead.
557 */
558 void
raptor_sequence_print_uri(char * data,FILE * fh)559 raptor_sequence_print_uri(char *data, FILE *fh)
560 {
561 raptor_uri* uri=(raptor_uri*)data;
562 fputs((const char*)raptor_uri_as_string_v2(raptor_world_instance(), uri), fh);
563 }
564 #endif
565
566
567 /**
568 * raptor_sequence_set_print_handler:
569 * @seq: sequence
570 * @print_handler: print handler
571 *
572 * Set the print handler for the sequence.
573 *
574 * This is set in the raptor_new_sequence() constructor and can be
575 * overridden here.
576 */
577 void
raptor_sequence_set_print_handler(raptor_sequence * seq,raptor_sequence_print_handler * print_handler)578 raptor_sequence_set_print_handler(raptor_sequence *seq,
579 raptor_sequence_print_handler *print_handler) {
580 if(!seq)
581 return;
582 seq->print_handler=print_handler;
583 }
584
585
586 /**
587 * raptor_sequence_set_print_handler_v2:
588 * @seq: sequence
589 * @print_handler: print handler
590 *
591 * Set the print handler for the sequence.
592 *
593 * This is set in the raptor_new_sequence_v2() constructor and can be
594 * overridden here.
595 */
596 void
raptor_sequence_set_print_handler_v2(raptor_sequence * seq,raptor_sequence_print_handler_v2 * print_handler)597 raptor_sequence_set_print_handler_v2(raptor_sequence *seq,
598 raptor_sequence_print_handler_v2 *print_handler) {
599 if(!seq)
600 return;
601 seq->print_handler_v2=print_handler;
602 }
603
604
605 /**
606 * raptor_sequence_print:
607 * @seq: sequence to sort
608 * @fh: file handle
609 *
610 * Print the sequence contents using the print_handler to print the data items.
611 */
612 void
raptor_sequence_print(raptor_sequence * seq,FILE * fh)613 raptor_sequence_print(raptor_sequence* seq, FILE* fh)
614 {
615 int i;
616
617 RAPTOR_ASSERT_OBJECT_POINTER_RETURN(seq, raptor_sequence);
618
619 fputc('[', fh);
620 for(i=0; i<seq->size; i++) {
621 if(i)
622 fputs(", ", fh);
623 if(seq->sequence[seq->start+i]) {
624 if(seq->print_handler)
625 seq->print_handler(seq->sequence[seq->start+i], fh);
626 else if(seq->print_handler_v2)
627 seq->print_handler_v2(seq->handler_context, seq->sequence[seq->start+i], fh);
628 } else
629 fputs("(empty)", fh);
630 }
631 fputc(']', fh);
632 }
633
634
635 /**
636 * raptor_sequence_join:
637 * @dest: #raptor_sequence destination sequence
638 * @src: #raptor_sequence source sequence
639 *
640 * Join two sequences moving all items from one sequence to the end of another.
641 *
642 * After this operation, sequence src will be empty (zero size) but
643 * will have the same item capacity as before.
644 *
645 * Return value: non-0 on failure
646 */
647 int
raptor_sequence_join(raptor_sequence * dest,raptor_sequence * src)648 raptor_sequence_join(raptor_sequence* dest, raptor_sequence *src)
649 {
650 RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(dest, raptor_sequence, 1);
651 RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(src, raptor_sequence, 1);
652
653 if(raptor_sequence_ensure(dest, dest->size + src->size, 0))
654 return 1;
655 memcpy(&dest->sequence[dest->start+dest->size], &src->sequence[src->start], sizeof(void*)*src->size);
656 dest->size += src->size;
657
658 src->size=0;
659
660 return 0;
661 }
662
663
664 #endif
665
666
667
668 #ifdef STANDALONE
669 #include <stdio.h>
670
671 int main(int argc, char *argv[]);
672
673
674 #define assert_match_string(function, expr, string) do { char *result=expr; if(strcmp(result, string)) { fprintf(stderr, "%s:" #function " failed - returned %s, expected %s\n", program, result, string); exit(1); } } while(0)
675 #define assert_match_int(function, expr, value) do { int result=expr; if(result != value) { fprintf(stderr, "%s:" #function " failed - returned %d, expected %d\n", program, result, value); exit(1); } } while(0)
676
677 int
main(int argc,char * argv[])678 main(int argc, char *argv[])
679 {
680 const char *program=raptor_basename(argv[0]);
681 raptor_sequence* seq1=raptor_new_sequence(NULL, (raptor_sequence_print_handler*)raptor_sequence_print_string);
682 raptor_sequence* seq2=raptor_new_sequence(NULL, (raptor_sequence_print_handler*)raptor_sequence_print_string);
683 char *s;
684 int i;
685
686 if(raptor_sequence_pop(seq1) || raptor_sequence_unshift(seq1)) {
687 fprintf(stderr, "%s: should not be able to pop/unshift from an empty sequence\n", program);
688 exit(1);
689 }
690
691 raptor_sequence_set_at(seq1, 0, (void*)"first");
692
693 raptor_sequence_push(seq1, (void*)"third");
694
695 raptor_sequence_shift(seq1, (void*)"second");
696
697 s=(char*)raptor_sequence_get_at(seq1, 0);
698 assert_match_string(raptor_sequence_get_at, s, "second");
699
700 s=(char*)raptor_sequence_get_at(seq1, 1);
701 assert_match_string(raptor_sequence_get_at, s, "first");
702
703 s=(char*)raptor_sequence_get_at(seq1, 2);
704 assert_match_string(raptor_sequence_get_at, s, "third");
705
706 assert_match_int(raptor_sequence_size, raptor_sequence_size(seq1), 3);
707
708 fprintf(stderr, "%s: sequence after additions: ", program);
709 raptor_sequence_print(seq1, stderr);
710 fputc('\n', stderr);
711
712 /* now made alphabetical i.e. first, second, third */
713 raptor_sequence_sort(seq1, raptor_compare_strings);
714
715 fprintf(stderr, "%s: sequence after sort: ", program);
716 raptor_sequence_print(seq1, stderr);
717 fputc('\n', stderr);
718
719 s=(char*)raptor_sequence_pop(seq1);
720 assert_match_string(raptor_sequence_get_at, s, "third");
721
722 assert_match_int(raptor_sequence_size, raptor_sequence_size(seq1), 2);
723
724 fprintf(stderr, "%s: sequence after pop: ", program);
725 raptor_sequence_print(seq1, stderr);
726 fputc('\n', stderr);
727
728 s=(char*)raptor_sequence_unshift(seq1);
729 assert_match_string(raptor_sequence_get_at, s, "first");
730
731 assert_match_int(raptor_sequence_size, raptor_sequence_size(seq1), 1);
732
733 fprintf(stderr, "%s: sequence after unshift: ", program);
734 raptor_sequence_print(seq1, stderr);
735 fputc('\n', stderr);
736
737 s=(char*)raptor_sequence_get_at(seq1, 0);
738 assert_match_string(raptor_sequence_get_at, s, "second");
739
740 raptor_sequence_push(seq2, (void*)"first.2");
741 if(raptor_sequence_join(seq2, seq1)) {
742 fprintf(stderr, "%s: raptor_sequence_join failed\n", program);
743 exit(1);
744 }
745
746 assert_match_int(raptor_sequence_size, raptor_sequence_size(seq1), 0);
747 assert_match_int(raptor_sequence_size, raptor_sequence_size(seq2), 2);
748
749 raptor_free_sequence(seq1);
750 raptor_free_sequence(seq2);
751
752 /* test sequence growing */
753
754 seq1=raptor_new_sequence(NULL, (raptor_sequence_print_handler*)raptor_sequence_print_string);
755 for(i=0; i<100; i++)
756 if(raptor_sequence_shift(seq1, (void*)"foo")) {
757 fprintf(stderr, "%s: raptor_sequence_shift failed\n", program);
758 exit(1);
759 }
760 assert_match_int(raptor_sequence_size, raptor_sequence_size(seq1), 100);
761 for(i=0; i<100; i++)
762 raptor_sequence_unshift(seq1);
763 assert_match_int(raptor_sequence_size, raptor_sequence_size(seq1), 0);
764 raptor_free_sequence(seq1);
765
766 seq1=raptor_new_sequence(NULL, (raptor_sequence_print_handler*)raptor_sequence_print_string);
767 for(i=0; i<100; i++)
768 if(raptor_sequence_push(seq1, (void*)"foo")) {
769 fprintf(stderr, "%s: raptor_sequence_push failed\n", program);
770 exit(1);
771 }
772 assert_match_int(raptor_sequence_size, raptor_sequence_size(seq1), 100);
773 for(i=0; i<100; i++)
774 raptor_sequence_pop(seq1);
775 assert_match_int(raptor_sequence_size, raptor_sequence_size(seq1), 0);
776 raptor_free_sequence(seq1);
777
778 return (0);
779 }
780 #endif
781