summaryrefslogtreecommitdiffstats
path: root/src/raptor_sequence.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/raptor_sequence.c895
1 files changed, 895 insertions, 0 deletions
diff --git a/src/raptor_sequence.c b/src/raptor_sequence.c
new file mode 100644
index 0000000..c64ad1d
--- /dev/null
+++ b/src/raptor_sequence.c
@@ -0,0 +1,895 @@
+/* -*- Mode: c; c-basic-offset: 2 -*-
+ *
+ * raptor_sequence.c - Raptor sequence support
+ *
+ * Copyright (C) 2003-2010, David Beckett http://www.dajobe.org/
+ * Copyright (C) 2003-2004, University of Bristol, UK http://www.bristol.ac.uk/
+ *
+ * This package is Free Software and part of Redland http://librdf.org/
+ *
+ * It is licensed under the following three licenses as alternatives:
+ * 1. GNU Lesser General Public License (LGPL) V2.1 or any newer version
+ * 2. GNU General Public License (GPL) V2 or any newer version
+ * 3. Apache License, V2.0 or any newer version
+ *
+ * You may not use this file except in compliance with at least one of
+ * the above three licenses.
+ *
+ * See LICENSE.html or LICENSE.txt at the top of this package for the
+ * complete terms and further detail along with the license texts for
+ * the licenses in COPYING.LIB, COPYING and LICENSE-2.0.txt respectively.
+ *
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <raptor_config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+
+#include "raptor2.h"
+#include "raptor_internal.h"
+
+
+/* POLICY - minimum size */
+#define RAPTOR_SEQUENCE_MIN_CAPACITY 8
+
+
+#ifndef STANDALONE
+
+/*
+ * Sequence of maximum capacity C containing N data items
+ *
+ * array:
+ * 0 <-- N consecutive items --> C - 1
+ * -----------------------------------------------------------
+ * | | | data1 | ..... data N | ... | |
+ * -----------------------------------------------------------
+ * ------ O -----> offset of first data item
+ *
+ * start = O
+ * size = N
+ * capacity = C
+ *
+ */
+struct raptor_sequence_s {
+ /* how many items are in the sequence 0..capacity */
+ int size;
+
+ /* length of the 'sequence' array below */
+ int capacity;
+
+ /* offset of the first data item in the sequence: 0..capacity-1 */
+ int start;
+
+ /* array of size 'capacity' pointing to the data */
+ void **sequence;
+
+
+ /* handler to call to free a data item (or NULL) */
+ raptor_data_free_handler free_handler;
+
+ /* handler to call to print a data item (or NULL) */
+ raptor_data_print_handler print_handler;
+
+
+ /* context pointer for @context_free_handler and @context_print_handler */
+ void *handler_context;
+
+ /* handler to call to free a data item (or NULL) also passing in
+ * as first arg the @handler_context */
+ raptor_data_context_free_handler context_free_handler;
+
+ /* handler to call to print a data item (or NULL) also passing in
+ * as first arg the @handler_context
+ */
+ raptor_data_context_print_handler context_print_handler;
+};
+
+
+static int raptor_sequence_ensure(raptor_sequence *seq, int capacity, int grow_at_front);
+
+
+/**
+ * raptor_new_sequence:
+ * @free_handler: handler to free a sequence item
+ * @print_handler: handler to print a sequence item to a FILE*
+ *
+ * Constructor - create a new sequence with the given handlers.
+ *
+ * This creates a sequence over objects that need only the item data
+ * pointers in order to print or free the objects.
+ *
+ * For example sequences of strings could use handlers (free, NULL)
+ * and sequences of #raptor_uri could use (raptor_free_uri,
+ * raptor_print_uri)
+ *
+ * Return value: a new #raptor_sequence or NULL on failure
+ **/
+raptor_sequence*
+raptor_new_sequence(raptor_data_free_handler free_handler,
+ raptor_data_print_handler print_handler)
+{
+ raptor_sequence* seq = RAPTOR_CALLOC(raptor_sequence*, 1, sizeof(*seq));
+ if(!seq)
+ return NULL;
+
+ seq->free_handler = free_handler;
+ seq->print_handler = print_handler;
+
+ return seq;
+}
+
+
+/**
+ * raptor_new_sequence_with_context:
+ * @free_handler: handler to free a sequence item
+ * @print_handler: handler to print a sequence item to a FILE*
+ * @handler_context: context information to pass to free/print handlers
+ *
+ * Constructor - create a new sequence with the given handlers and handler context.
+ *
+ * This creates a sequence over objects that need context + item data
+ * pointers in order to print or free the objects.
+ *
+ * Return value: a new #raptor_sequence or NULL on failure
+ **/
+raptor_sequence*
+raptor_new_sequence_with_context(raptor_data_context_free_handler free_handler,
+ raptor_data_context_print_handler print_handler,
+ void *handler_context)
+{
+ raptor_sequence* seq = RAPTOR_CALLOC(raptor_sequence*, 1, sizeof(*seq));
+ if(!seq)
+ return NULL;
+
+ seq->context_free_handler = free_handler;
+ seq->context_print_handler = print_handler;
+ seq->handler_context = handler_context;
+
+ return seq;
+}
+
+
+/**
+ * raptor_free_sequence:
+ * @seq: sequence to destroy
+ *
+ * Destructor - free a #raptor_sequence
+ **/
+void
+raptor_free_sequence(raptor_sequence* seq)
+{
+ int i;
+ int j;
+
+ if(!seq)
+ return;
+
+ if(seq->free_handler) {
+ for(i = seq->start, j = seq->start + seq->size; i < j; i++)
+ if(seq->sequence[i])
+ seq->free_handler(seq->sequence[i]);
+ } else if(seq->context_free_handler) {
+ for(i = seq->start, j = seq->start + seq->size; i < j; i++)
+ if(seq->sequence[i])
+ seq->context_free_handler(seq->handler_context, seq->sequence[i]);
+ }
+
+ if(seq->sequence)
+ RAPTOR_FREE(ptrarray, seq->sequence);
+
+ RAPTOR_FREE(raptor_sequence, seq);
+}
+
+
+static int
+raptor_sequence_ensure(raptor_sequence *seq, int capacity, int grow_at_front)
+{
+ void **new_sequence;
+ int offset;
+
+ RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(seq, raptor_sequence, 1);
+
+ if(capacity && seq->capacity >= capacity)
+ return 0;
+
+ /* POLICY - minimum size */
+ if(capacity < RAPTOR_SEQUENCE_MIN_CAPACITY)
+ capacity = RAPTOR_SEQUENCE_MIN_CAPACITY;
+
+ new_sequence = RAPTOR_CALLOC(void**, capacity, sizeof(void*));
+ if(!new_sequence)
+ return 1;
+
+ offset = (grow_at_front ? (capacity - seq->capacity) : 0) + seq->start;
+ if(seq->size) {
+ memcpy(&new_sequence[offset], &seq->sequence[seq->start],
+ sizeof(void*) * seq->size);
+ RAPTOR_FREE(ptrarray, seq->sequence);
+ }
+ seq->start = offset;
+
+ seq->sequence = new_sequence;
+ seq->capacity = capacity;
+
+ return 0;
+}
+
+
+/**
+ * raptor_sequence_size:
+ * @seq: sequence object
+ *
+ * Get the number of items in a sequence.
+ *
+ * Return value: the sequence size (>=0)
+ **/
+int
+raptor_sequence_size(raptor_sequence* seq)
+{
+ RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(seq, raptor_sequence, -1);
+
+ return seq->size;
+}
+
+
+/* Store methods */
+
+/**
+ * raptor_sequence_set_at:
+ * @seq: sequence object
+ * @idx: index into sequence to operate at
+ * @data: new data item.
+ *
+ * Replace/set an item in a sequence.
+ *
+ * The item at the offset @idx in the sequence is replaced with the
+ * new item @data (which may be NULL). Any existing item is freed
+ * with the sequence's free_handler. If necessary the sequence
+ * is extended (with NULLs) to handle a larger offset.
+ *
+ * The sequence takes ownership of the new data item. On failure, the
+ * item is freed immediately.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+raptor_sequence_set_at(raptor_sequence* seq, int idx, void *data)
+{
+ int need_capacity;
+
+ RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(seq, raptor_sequence, 1);
+
+ /* Cannot provide a negative index */
+ if(idx < 0) {
+ if(data) {
+ if(seq->free_handler)
+ seq->free_handler(data);
+ else if(seq->context_free_handler)
+ seq->context_free_handler(seq->handler_context, data);
+ }
+ return 1;
+ }
+
+ need_capacity = seq->start + idx + 1;
+ if(need_capacity > seq->capacity) {
+ if(seq->capacity * 2 > need_capacity)
+ need_capacity = seq->capacity * 2;
+
+ if(raptor_sequence_ensure(seq, need_capacity, 0)) {
+ if(data) {
+ if(seq->free_handler)
+ seq->free_handler(data);
+ else if(seq->context_free_handler)
+ seq->context_free_handler(seq->handler_context, data);
+ }
+ return 1;
+ }
+ }
+
+ if(idx < seq->size) {
+ /* if there is old data, delete it if there is a free handler */
+ if(seq->sequence[seq->start + idx]) {
+ if(seq->free_handler)
+ seq->free_handler(seq->sequence[seq->start + idx]);
+ else if(seq->context_free_handler)
+ seq->context_free_handler(seq->handler_context,
+ seq->sequence[seq->start + idx]);
+ }
+ /* size remains the same */
+ } else {
+ /* if there is no old data, size is increasing */
+ /* make sure there are seq->size items starting from seq->start */
+ seq->size = idx + 1;
+ }
+
+ seq->sequence[seq->start + idx] = data;
+
+ return 0;
+}
+
+
+
+/**
+ * raptor_sequence_push:
+ * @seq: sequence to add to
+ * @data: item to add
+ *
+ * Add an item to the end of the sequence.
+ *
+ * The sequence takes ownership of the pushed item and frees it with the
+ * free_handler. On failure, the item is freed immediately.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+raptor_sequence_push(raptor_sequence* seq, void *data)
+{
+ RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(seq, raptor_sequence, 1);
+
+ if(seq->start + seq->size == seq->capacity) {
+ if(raptor_sequence_ensure(seq, seq->capacity * 2, 0)) {
+ if(data) {
+ if(seq->free_handler)
+ seq->free_handler(data);
+ else if(seq->context_free_handler)
+ seq->context_free_handler(seq->handler_context, data);
+ }
+ return 1;
+ }
+ }
+
+ seq->sequence[seq->start + seq->size] = data;
+ seq->size++;
+
+ return 0;
+}
+
+
+/**
+ * raptor_sequence_shift:
+ * @seq: sequence to add to
+ * @data: item to add
+ *
+ * Add an item to the start of the sequence.
+ *
+ * The sequence takes ownership of the shifted item and frees it with the
+ * free_handler. On failure, the item is freed immediately.
+ *
+ * Return value: non-0 on failure
+ **/
+int
+raptor_sequence_shift(raptor_sequence* seq, void *data)
+{
+ RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(seq, raptor_sequence, 1);
+
+ if(!seq->start) {
+ if(raptor_sequence_ensure(seq, seq->capacity * 2, 1)) {
+ if(data) {
+ if(seq->free_handler)
+ seq->free_handler(data);
+ else if(seq->context_free_handler)
+ seq->context_free_handler(seq->handler_context, data);
+ }
+ return 1;
+ }
+ }
+
+ seq->sequence[--seq->start] = data;
+ seq->size++;
+
+ return 0;
+}
+
+
+/**
+ * raptor_sequence_get_at:
+ * @seq: sequence to use
+ * @idx: index of item to get
+ *
+ * Retrieve an item at offset @index in the sequence.
+ *
+ * This is efficient to perform. #raptor_sequence is optimised
+ * to append/remove from the end of the sequence.
+ *
+ * After this call the item is still owned by the sequence.
+ *
+ * Return value: the object or NULL if @index is out of range (0... sequence size - 1)
+ **/
+void*
+raptor_sequence_get_at(raptor_sequence* seq, int idx)
+{
+ RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(seq, raptor_sequence, NULL);
+
+ if(idx < 0 || idx > seq->size - 1)
+ return NULL;
+
+ return seq->sequence[seq->start + idx];
+}
+
+
+/**
+ * raptor_sequence_delete_at:
+ * @seq: sequence object
+ * @idx: index into sequence to operate at
+ *
+ * Remove an item from a position a sequence, returning it
+ *
+ * The item at the offset @idx in the sequence is replaced with a
+ * NULL pointer and any existing item is returned. The caller
+ * owns the resulting item.
+ *
+ * Return value: NULL on failure
+ **/
+void*
+raptor_sequence_delete_at(raptor_sequence* seq, int idx)
+{
+ void* data;
+
+ RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(seq, raptor_sequence, NULL);
+
+ if(idx < 0 || idx > seq->size - 1)
+ return NULL;
+
+ data = seq->sequence[seq->start + idx];
+ seq->sequence[seq->start + idx] = NULL;
+
+ return data;
+}
+
+
+
+/**
+ * raptor_sequence_pop:
+ * @seq: sequence to use
+ *
+ * Retrieve the item at the end of the sequence.
+ *
+ * Ownership of the item is transferred to the caller,
+ * i.e. caller is responsible of freeing the item.
+ *
+ * Return value: the object or NULL if the sequence is empty
+ **/
+void*
+raptor_sequence_pop(raptor_sequence* seq)
+{
+ void *data;
+ int i;
+
+ RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(seq, raptor_sequence, NULL);
+
+ if(!seq->size)
+ return NULL;
+
+ seq->size--;
+ i = seq->start + seq->size;
+ data = seq->sequence[i];
+ seq->sequence[i] = NULL;
+
+ return data;
+}
+
+
+/**
+ * raptor_sequence_unshift:
+ * @seq: sequence to use
+ *
+ * Retrieve the item at the start of the sequence.
+ *
+ * Ownership of the item is transferred to the caller,
+ * i.e. caller is responsible of freeing the item.
+ *
+ * Return value: the object or NULL if the sequence is empty
+ **/
+void*
+raptor_sequence_unshift(raptor_sequence* seq)
+{
+ void *data;
+ int i;
+
+ RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(seq, raptor_sequence, NULL);
+
+ if(!seq->size)
+ return NULL;
+
+ i = seq->start++;
+ data = seq->sequence[i];
+ seq->size--;
+ seq->sequence[i] = NULL;
+
+ return data;
+}
+
+
+/**
+ * raptor_sequence_sort:
+ * @seq: sequence to sort
+ * @compare: comparison function with args (a, b)
+ *
+ * Sort a sequence inline
+ *
+ * The comparison function @compare is compatible with that used for
+ * qsort() and provides the addresses of pointers to the data that
+ * must be dereferenced to get to the stored sequence data.
+ *
+ **/
+RAPTOR_EXTERN_C
+void
+raptor_sequence_sort(raptor_sequence* seq, raptor_data_compare_handler compare)
+{
+ RAPTOR_ASSERT_OBJECT_POINTER_RETURN(seq, raptor_sequence);
+
+ if(seq->size > 1)
+ qsort(&seq->sequence[seq->start], seq->size, sizeof(void*), compare);
+}
+
+
+/**
+ * raptor_sequence_sort_r:
+ * @seq: sequence to sort
+ * @compare: comparison function with args (a, b, user data)
+ * @user_data: User data argument for @compare
+ *
+ * Sort a sequence inline with user data
+ *
+ * The comparison function @compare_r is compatible with that used
+ * for raptor_sort_r() and provides the addresses of pointers to the
+ * data that must be dereferenced to get to the stored sequence data.
+ *
+ **/
+RAPTOR_EXTERN_C
+void
+raptor_sequence_sort_r(raptor_sequence* seq,
+ raptor_data_compare_arg_handler compare,
+ void* user_data)
+{
+ RAPTOR_ASSERT_OBJECT_POINTER_RETURN(seq, raptor_sequence);
+
+ if(seq->size > 1)
+ raptor_sort_r(&seq->sequence[seq->start], seq->size, sizeof(void*),
+ compare, user_data);
+}
+
+
+/**
+ * raptor_sequence_print:
+ * @seq: sequence to sort
+ * @fh: file handle
+ *
+ * Print the sequence contents using the print_handler to print the data items.
+ *
+ * Return value: non-0 on failure
+ */
+int
+raptor_sequence_print(raptor_sequence* seq, FILE* fh)
+{
+ int rc = 0;
+ int i;
+
+ RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(seq, raptor_sequence, 1);
+
+ fputc('[', fh);
+ for(i = 0; i < seq->size; i++) {
+ if(i)
+ fputs(", ", fh);
+ if(seq->sequence[seq->start + i]) {
+ if(seq->print_handler)
+ seq->print_handler(seq->sequence[seq->start + i], fh);
+ else if(seq->context_print_handler)
+ seq->context_print_handler(seq->handler_context,
+ seq->sequence[seq->start + i], fh);
+ } else
+ fputs("(empty)", fh);
+ }
+ fputc(']', fh);
+
+ return rc;
+}
+
+
+/**
+ * raptor_sequence_join:
+ * @dest: #raptor_sequence destination sequence
+ * @src: #raptor_sequence source sequence
+ *
+ * Join two sequences moving all items from one sequence to the end of another.
+ *
+ * After this operation, sequence src will be empty (zero size) but
+ * will have the same item capacity as before.
+ *
+ * Return value: non-0 on failure
+ */
+int
+raptor_sequence_join(raptor_sequence* dest, raptor_sequence *src)
+{
+ RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(dest, raptor_sequence, 1);
+ RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(src, raptor_sequence, 1);
+
+ if(raptor_sequence_ensure(dest, dest->size + src->size, 0))
+ return 1;
+
+ memcpy(&dest->sequence[dest->start + dest->size], &src->sequence[src->start],
+ sizeof(void*) * src->size);
+ dest->size += src->size;
+
+ src->size = 0;
+
+ return 0;
+}
+
+
+/**
+ * raptor_sequence_swap:
+ * @seq: sequence
+ * @i: first data index
+ * @j: second data index
+ *
+ * Swap a pair of elements in a sequence
+ *
+ * Return value: non-0 if arguments are out of range
+ */
+int
+raptor_sequence_swap(raptor_sequence* seq, int i, int j)
+{
+ if(i < 0 || i >= seq->size || j < 0 || j >= seq->size)
+ return 1;
+
+ if(i != j) {
+ void* tmp = seq->sequence[i];
+ seq->sequence[i] = seq->sequence[j];
+ seq->sequence[j] = tmp;
+ }
+
+ return 0;
+}
+
+
+/**
+ * raptor_sequence_reverse:
+ * @seq: sequence
+ * @start_index: starting index
+ * @length: number of elements to reverse
+ *
+ * Reverse a range of elements
+ *
+ * Return value: non-0 if arguments are out of range
+ */
+int
+raptor_sequence_reverse(raptor_sequence* seq, int start_index, int length)
+{
+ int end_index = start_index + length - 1;
+
+ RAPTOR_ASSERT_OBJECT_POINTER_RETURN_VALUE(seq, raptor_sequence, 1);
+
+ if(end_index >= seq->size || start_index < 1 || length <= 1)
+ return 1;
+
+ while( (start_index != end_index) && (start_index != end_index + 1) ) {
+ raptor_sequence_swap(seq, start_index, end_index);
+ start_index++; end_index--;
+ }
+
+ return 0;
+}
+
+
+/**
+ * raptor_sequence_next_permutation:
+ * @seq: int seq
+ * @compare: comparison function
+ *
+ * Get the next permutation of a sequence in lexicographic order
+ *
+ * Assumes the initial order of the items is lexicographically
+ * increasing. This function alters the order of the items until the
+ * last permuatation is done at which point the contents is reset to
+ * the intial order.
+ *
+ * Algorithm used is described in http://en.wikipedia.org/wiki/Permutation
+ *
+ * The comparison function @compare is compatible with that used for
+ * qsort() and provides the addresses of pointers to the data that
+ * must be dereferenced to get to the stored sequence data.
+ *
+ * Return value: non-0 at the last permutation
+ */
+RAPTOR_EXTERN_C
+int
+raptor_sequence_next_permutation(raptor_sequence *seq,
+ raptor_data_compare_handler compare)
+{
+ int k;
+ int l;
+ void* temp;
+
+ if(seq->size < 2)
+ return 1;
+
+ /* 1. Find the largest index k such that a[k] < a[k + 1]. If no such
+ * index exists, the permutation is the last permutation.
+ */
+ k = seq->size - 2;
+ while(k >= 0 && compare(seq->sequence[k], seq->sequence[k + 1]) >= 0)
+ k--;
+
+ if(k == -1) {
+ /* done - reset to starting order */
+ raptor_sequence_reverse(seq, 0, seq->size);
+ return 1;
+ }
+
+ /* 2. Find the largest index l such that a[k] < a[l]. Since k + 1
+ * is such an index, l is well defined and satisfies k < l.
+ */
+ l = seq->size - 1;
+ while( compare(seq->sequence[k], seq->sequence[l]) >= 0)
+ l--;
+
+ /* 3. Swap a[k] with a[l]. */
+#if 1
+ temp = seq->sequence[k];
+ seq->sequence[k] = seq->sequence[l];
+ seq->sequence[l] = temp;
+#else
+ raptor_sequence_swap(seq, k, l);
+#endif
+
+ /* 4. Reverse the sequence from a[k + 1] up to and including the
+ * final element a[n].
+ */
+ raptor_sequence_reverse(seq, k + 1, seq->size - (k + 1));
+
+ return 0;
+}
+
+
+#endif
+
+
+
+#ifdef STANDALONE
+#include <stdio.h>
+
+int main(int argc, char *argv[]);
+
+static int
+raptor_compare_strings(const void *a, const void *b)
+{
+ return strcmp(*(char**)a, *(char**)b);
+}
+
+static int
+raptor_sequence_print_string(void *data, FILE *fh)
+{
+ fputs((char*)data, fh);
+ return 0;
+}
+
+#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)
+#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)
+
+int
+main(int argc, char *argv[])
+{
+ const char *program = raptor_basename(argv[0]);
+ raptor_sequence* seq1 = raptor_new_sequence(NULL, raptor_sequence_print_string);
+ raptor_sequence* seq2 = raptor_new_sequence(NULL, raptor_sequence_print_string);
+ char *s;
+ int i;
+
+ if(raptor_sequence_pop(seq1) || raptor_sequence_unshift(seq1)) {
+ fprintf(stderr, "%s: should not be able to pop/unshift from an empty sequence\n", program);
+ exit(1);
+ }
+
+ raptor_sequence_set_at(seq1, 0, (void*)"first");
+
+ raptor_sequence_push(seq1, (void*)"third");
+
+ raptor_sequence_shift(seq1, (void*)"second");
+
+ s = (char*)raptor_sequence_get_at(seq1, 0);
+ assert_match_string(raptor_sequence_get_at, s, "second");
+
+ s = (char*)raptor_sequence_get_at(seq1, 1);
+ assert_match_string(raptor_sequence_get_at, s, "first");
+
+ s = (char*)raptor_sequence_get_at(seq1, 2);
+ assert_match_string(raptor_sequence_get_at, s, "third");
+
+ assert_match_int(raptor_sequence_size, raptor_sequence_size(seq1), 3);
+
+#if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
+ fprintf(stderr, "%s: sequence after additions: ", program);
+ raptor_sequence_print(seq1, stderr);
+ fputc('\n', stderr);
+#endif
+
+ /* now made alphabetical i.e. first, second, third */
+ raptor_sequence_sort(seq1, raptor_compare_strings);
+
+#if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
+ fprintf(stderr, "%s: sequence after sort: ", program);
+ raptor_sequence_print(seq1, stderr);
+ fputc('\n', stderr);
+#endif
+
+ s = (char*)raptor_sequence_pop(seq1);
+ assert_match_string(raptor_sequence_get_at, s, "third");
+
+ assert_match_int(raptor_sequence_size, raptor_sequence_size(seq1), 2);
+
+#if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
+ fprintf(stderr, "%s: sequence after pop: ", program);
+ raptor_sequence_print(seq1, stderr);
+ fputc('\n', stderr);
+#endif
+
+ s = (char*)raptor_sequence_unshift(seq1);
+ assert_match_string(raptor_sequence_get_at, s, "first");
+
+ assert_match_int(raptor_sequence_size, raptor_sequence_size(seq1), 1);
+
+#if defined(RAPTOR_DEBUG) && RAPTOR_DEBUG > 1
+ fprintf(stderr, "%s: sequence after unshift: ", program);
+ raptor_sequence_print(seq1, stderr);
+ fputc('\n', stderr);
+#endif
+
+ s = (char*)raptor_sequence_get_at(seq1, 0);
+ assert_match_string(raptor_sequence_get_at, s, "second");
+
+ raptor_sequence_push(seq2, (void*)"first.2");
+ if(raptor_sequence_join(seq2, seq1)) {
+ fprintf(stderr, "%s: raptor_sequence_join failed\n", program);
+ exit(1);
+ }
+
+ assert_match_int(raptor_sequence_size, raptor_sequence_size(seq1), 0);
+ assert_match_int(raptor_sequence_size, raptor_sequence_size(seq2), 2);
+
+ raptor_free_sequence(seq1);
+ raptor_free_sequence(seq2);
+
+ /* test sequence growing */
+
+ seq1 = raptor_new_sequence(NULL, raptor_sequence_print_string);
+ for(i = 0; i < 100; i++)
+ if(raptor_sequence_shift(seq1, (void*)"foo")) {
+ fprintf(stderr, "%s: raptor_sequence_shift failed\n", program);
+ exit(1);
+ }
+ assert_match_int(raptor_sequence_size, raptor_sequence_size(seq1), 100);
+ for(i = 0; i < 100; i++)
+ raptor_sequence_unshift(seq1);
+ assert_match_int(raptor_sequence_size, raptor_sequence_size(seq1), 0);
+ raptor_free_sequence(seq1);
+
+ seq1 = raptor_new_sequence(NULL, raptor_sequence_print_string);
+ for(i = 0; i < 100; i++)
+ if(raptor_sequence_push(seq1, (void*)"foo")) {
+ fprintf(stderr, "%s: raptor_sequence_push failed\n", program);
+ exit(1);
+ }
+ assert_match_int(raptor_sequence_size, raptor_sequence_size(seq1), 100);
+ for(i = 0; i < 100; i++)
+ raptor_sequence_pop(seq1);
+ assert_match_int(raptor_sequence_size, raptor_sequence_size(seq1), 0);
+ raptor_free_sequence(seq1);
+
+ return (0);
+}
+#endif