2 * "$Id: array.c 4970 2006-01-24 14:05:45Z mike $"
4 * Sorted array routines for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2006 by Easy Software Products.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
24 * This file is subject to the Apple OS-Developed Software exception.
28 * cupsArrayAdd() - Add an element to the array.
29 * cupsArrayClear() - Clear the array.
30 * cupsArrayCount() - Get the number of elements in the array.
31 * cupsArrayCurrent() - Return the current element in the array.
32 * cupsArrayDelete() - Free all memory used by the array.
33 * cupsArrayDup() - Duplicate the array.
34 * cupsArrayFind() - Find an element in the array.
35 * cupsArrayFirst() - Get the first element in the array.
36 * cupsArrayIndex() - Get the N-th element in the array.
37 * cupsArrayInsert() - Insert an element in the array.
38 * cupsArrayLast() - Get the last element in the array.
39 * cupsArrayNew() - Create a new array.
40 * cupsArrayNext() - Get the next element in the array.
41 * cupsArrayPrev() - Get the previous element in the array.
42 * cupsArrayRemove() - Remove an element from the array.
43 * cupsArrayRestore() - Reset the current element to the last cupsArraySave.
44 * cupsArraySave() - Mark the current element for a later cupsArrayRestore.
45 * cups_find() - Find an element in the array...
49 * Include necessary headers...
61 #define _CUPS_MAXSAVE 32 /**** Maximum number of saves ****/
65 * Types and structures...
68 struct _cups_array_s
/**** CUPS array structure ****/
71 * The current implementation uses an insertion sort into an array of
72 * sorted pointers. We leave the array type private/opaque so that we
73 * can change the underlying implementation without affecting the users
77 int num_elements
, /* Number of array elements */
78 alloc_elements
, /* Allocated array elements */
79 current
, /* Current element */
80 insert
, /* Last inserted element */
81 num_saved
, /* Number of saved elements */
84 void **elements
; /* Array elements */
85 cups_array_func_t compare
; /* Element comparison function */
86 void *data
; /* User data passed to compare */
94 static int cups_find(cups_array_t
*a
, void *e
, int prev
, int *rdiff
);
98 * 'cupsArrayAdd()' - Add an element to the array.
101 int /* O - 1 on success, 0 on failure */
102 cupsArrayAdd(cups_array_t
*a
, /* I - Array */
103 void *e
) /* I - Element */
105 int i
, /* Looping var */
106 current
, /* Current element */
107 diff
; /* Comparison with current element */
110 DEBUG_printf(("cupsArrayAdd(a=%p, e=%p)\n", a
, e
));
113 * Range check input...
118 DEBUG_puts("cupsArrayAdd: returning 0");
123 * Verify we have room for the new element...
126 if (a
->num_elements
>= a
->alloc_elements
)
129 * Allocate additional elements; start with 16 elements, then
130 * double the size until 1024 elements, then add 1024 elements
134 void **temp
; /* New array elements */
135 int count
; /* New allocation count */
138 if (a
->alloc_elements
== 0)
141 temp
= malloc(count
* sizeof(void *));
145 if (a
->alloc_elements
< 1024)
146 count
= a
->alloc_elements
* 2;
148 count
= a
->alloc_elements
+ 1024;
150 temp
= realloc(a
->elements
, count
* sizeof(void *));
153 DEBUG_printf(("cupsArrayAdd: count=%d\n", count
));
157 DEBUG_puts("cupsAddAdd: allocation failed, returning 0");
161 a
->alloc_elements
= count
;
166 * Find the insertion point for the new element; if there is no
167 * compare function or elements, just add it to the end...
170 if (!a
->num_elements
|| !a
->compare
)
173 * Append to the end...
176 current
= a
->num_elements
;
181 * Do a binary search for the insertion point...
184 current
= cups_find(a
, e
, a
->insert
, &diff
);
191 * Insert or append the element...
194 if (current
< a
->num_elements
)
197 * Shift other elements to the right...
200 memmove(a
->elements
+ current
+ 1, a
->elements
+ current
,
201 (a
->num_elements
- current
) * sizeof(void *));
203 if (a
->current
>= current
)
206 for (i
= 0; i
< a
->num_saved
; i
++)
207 if (a
->saved
[i
] >= current
)
210 DEBUG_printf(("cupsArrayAdd: insert element at index %d...\n", current
));
214 printf("cupsArrayAdd: append element at %d...\n", current
);
217 a
->elements
[current
] = e
;
222 for (current
= 0; current
< a
->num_elements
; current
++)
223 printf("cupsArrayAdd: a->elements[%d]=%p\n", current
, a
->elements
[current
]);
226 DEBUG_puts("cupsArrayAdd: returning 1");
233 * 'cupsArrayClear()' - Clear the array.
237 cupsArrayClear(cups_array_t
*a
) /* I - Array */
240 * Range check input...
247 * Set the number of elements to 0; we don't actually free the memory
248 * here - that is done in cupsArrayDelete()...
259 * 'cupsArrayCount()' - Get the number of elements in the array.
262 int /* O - Number of elements */
263 cupsArrayCount(cups_array_t
*a
) /* I - Array */
266 * Range check input...
273 * Return the number of elements...
276 return (a
->num_elements
);
281 * 'cupsArrayCurrent()' - Return the current element in the array.
284 void * /* O - Element */
285 cupsArrayCurrent(cups_array_t
*a
) /* I - Array */
288 * Range check input...
295 * Return the current element...
298 if (a
->current
>= 0 && a
->current
< a
->num_elements
)
299 return (a
->elements
[a
->current
]);
306 * 'cupsArrayDelete()' - Free all memory used by the array.
310 cupsArrayDelete(cups_array_t
*a
) /* I - Array */
313 * Range check input...
320 * Free the array of element pointers - the caller is responsible
321 * for freeing the elements themselves...
324 if (a
->alloc_elements
)
332 * 'cupsArrayDup()' - Duplicate the array.
335 cups_array_t
* /* O - Duplicate array */
336 cupsArrayDup(cups_array_t
*a
) /* I - Array */
338 cups_array_t
*da
; /* Duplicate array */
342 * Range check input...
349 * Allocate memory for the array...
352 da
= calloc(1, sizeof(cups_array_t
));
356 da
->compare
= a
->compare
;
358 da
->current
= a
->current
;
359 da
->insert
= a
->insert
;
360 da
->num_saved
= a
->num_saved
;
362 memcpy(da
->saved
, a
->saved
, sizeof(a
->saved
));
367 * Allocate memory for the elements...
370 da
->elements
= malloc(a
->num_elements
* sizeof(void *));
378 * Copy the element pointers...
381 memcpy(da
->elements
, a
->elements
, a
->num_elements
* sizeof(void *));
382 da
->num_elements
= a
->num_elements
;
383 da
->alloc_elements
= a
->num_elements
;
387 * Return the new array...
395 * 'cupsArrayFind()' - Find an element in the array.
398 void * /* O - Element found or NULL */
399 cupsArrayFind(cups_array_t
*a
, /* I - Array */
400 void *e
) /* I - Element */
402 int current
, /* Current element */
403 diff
; /* Difference */
407 * Range check input...
414 * See if we have any elements...
417 if (!a
->num_elements
)
421 * Yes, look for a match...
424 current
= cups_find(a
, e
, a
->current
, &diff
);
431 a
->current
= current
;
433 return (a
->elements
[current
]);
449 * 'cupsArrayFirst()' - Get the first element in the array.
452 void * /* O - First element or NULL */
453 cupsArrayFirst(cups_array_t
*a
) /* I - Array */
456 * Range check input...
463 * Return the first element...
468 return (cupsArrayCurrent(a
));
473 * 'cupsArrayIndex()' - Get the N-th element in the array.
476 void * /* O - N-th element or NULL */
477 cupsArrayIndex(cups_array_t
*a
, /* I - Array */
478 int n
) /* I - Index into array, starting at 0 */
485 return (cupsArrayCurrent(a
));
490 * 'cupsArrayInsert()' - Insert an element in the array.
492 * When inserting an element in a sorted array, this function works
493 * just like cupsArrayAdd(). For unsorted arrays, the element is
494 * inserted at the beginning of the array.
497 int /* O - 0 on failure, 1 on success */
498 cupsArrayInsert(cups_array_t
*a
, /* I - Array */
499 void *e
) /* I - Element */
501 int i
; /* Looping var */
504 DEBUG_printf(("cupsArrayInsert(a=%p, e=%p)\n", a
, e
));
507 * Range check input...
512 DEBUG_puts("cupsArrayInsert: returning 0");
517 * Inserting into a sorted array is the same as adding...
521 return (cupsArrayAdd(a
, e
));
524 * Verify we have room for the new element...
527 if (a
->num_elements
>= a
->alloc_elements
)
530 * Allocate additional elements; start with 16 elements, then
531 * double the size until 1024 elements, then add 1024 elements
535 void **temp
; /* New array elements */
536 int count
; /* New allocation count */
539 if (a
->alloc_elements
== 0)
542 temp
= malloc(count
* sizeof(void *));
546 if (a
->alloc_elements
< 1024)
547 count
= a
->alloc_elements
* 2;
549 count
= a
->alloc_elements
+ 1024;
551 temp
= realloc(a
->elements
, count
* sizeof(void *));
554 DEBUG_printf(("cupsArrayInsert: count=%d\n", count
));
558 DEBUG_puts("cupsAddInsert: allocation failed, returning 0");
562 a
->alloc_elements
= count
;
567 * Insert the element...
570 memmove(a
->elements
+ 1, a
->elements
, a
->num_elements
* sizeof(void *));
575 for (i
= 0; i
< a
->num_saved
; i
++)
576 if (a
->saved
[i
] >= 0)
584 for (i
= 0; i
< a
->num_elements
; i
++)
585 printf("cupsArrayInsert: a->elements[%d]=%p\n", i
, a
->elements
[i
]);
588 DEBUG_puts("cupsArrayInsert: returning 1");
595 * 'cupsArrayLast()' - Get the last element in the array.
598 void * /* O - Last element or NULL */
599 cupsArrayLast(cups_array_t
*a
) /* I - Array */
602 * Range check input...
609 * Return the last element...
612 a
->current
= a
->num_elements
- 1;
614 return (cupsArrayCurrent(a
));
619 * 'cupsArrayNew()' - Create a new array.
622 cups_array_t
* /* O - Array */
623 cupsArrayNew(cups_array_func_t f
, /* I - Comparison function */
624 void *d
) /* I - User data */
626 cups_array_t
*a
; /* Array */
630 * Allocate memory for the array...
633 a
= calloc(1, sizeof(cups_array_t
));
648 * 'cupsArrayNext()' - Get the next element in the array.
651 void * /* O - Next element or NULL */
652 cupsArrayNext(cups_array_t
*a
) /* I - Array */
655 * Range check input...
662 * Return the next element...
665 if (a
->current
< a
->num_elements
)
668 return (cupsArrayCurrent(a
));
673 * 'cupsArrayPrev()' - Get the previous element in the array.
676 void * /* O - Previous element or NULL */
677 cupsArrayPrev(cups_array_t
*a
) /* I - Array */
680 * Range check input...
687 * Return the previous element...
693 return (cupsArrayCurrent(a
));
698 * 'cupsArrayRemove()' - Remove an element from the array.
701 int /* O - 1 on success, 0 on failure */
702 cupsArrayRemove(cups_array_t
*a
, /* I - Array */
703 void *e
) /* I - Element */
705 int i
, /* Looping var */
706 current
, /* Current element */
707 diff
; /* Difference */
711 * Range check input...
718 * See if the element is in the array...
721 if (!a
->num_elements
)
724 current
= cups_find(a
, e
, a
->current
, &diff
);
729 * Yes, now remove it...
734 if (current
< a
->num_elements
)
735 memmove(a
->elements
+ current
, a
->elements
+ current
+ 1,
736 (a
->num_elements
- current
) * sizeof(void *));
738 if (current
<= a
->current
)
741 if (current
<= a
->insert
)
744 for (i
= 0; i
< a
->num_saved
; i
++)
745 if (current
<= a
->saved
[i
])
753 * 'cupsArrayRestore()' - Reset the current element to the last cupsArraySave.
756 void * /* O - New current element */
757 cupsArrayRestore(cups_array_t
*a
) /* I - Array */
762 if (a
->num_saved
<= 0)
766 a
->current
= a
->saved
[a
->num_saved
];
768 if (a
->current
>= 0 && a
->current
< a
->num_elements
)
769 return (a
->elements
[a
->current
]);
776 * 'cupsArraySave()' - Mark the current element for a later cupsArrayRestore.
778 * The save/restore stack is guaranteed to be at least 32 elements deep.
781 int /* O - 1 on success, 0 on failure */
782 cupsArraySave(cups_array_t
*a
) /* I - Array */
787 if (a
->num_saved
>= _CUPS_MAXSAVE
)
790 a
->saved
[a
->num_saved
] = a
->current
;
798 * 'cups_find()' - Find an element in the array...
801 static int /* O - Index of match */
802 cups_find(cups_array_t
*a
, /* I - Array */
803 void *e
, /* I - Element */
804 int prev
, /* I - Previous index */
805 int *rdiff
) /* O - Difference of match */
807 int left
, /* Left side of search */
808 right
, /* Right side of search */
809 current
, /* Current element */
810 diff
; /* Comparison with current element */
813 DEBUG_printf(("cups_find(a=%p, e=%p, prev=%d, rdiff=%p)\n", a
, e
, prev
,
819 * Do a binary search for the element...
822 DEBUG_puts("cups_find: binary search");
824 if (prev
>= 0 && prev
< a
->num_elements
)
827 * Start search on either side of previous...
830 if ((diff
= (*(a
->compare
))(e
, a
->elements
[prev
], a
->data
)) == 0 ||
831 (diff
< 0 && prev
== 0) ||
832 (diff
> 0 && prev
== (a
->num_elements
- 1)))
835 * Exact or edge match, return it!
838 DEBUG_printf(("cups_find: Returning %d, diff=%d\n", prev
, diff
));
847 * Start with previous on right side...
856 * Start wih previous on left side...
860 right
= a
->num_elements
- 1;
866 * Start search in the middle...
870 right
= a
->num_elements
- 1;
875 current
= (left
+ right
) / 2;
876 diff
= (*(a
->compare
))(e
, a
->elements
[current
], a
->data
);
878 DEBUG_printf(("cups_find: left=%d, right=%d, current=%d, diff=%d\n",
879 left
, right
, current
, diff
));
888 while ((right
- left
) > 1);
893 * Check the last 1 or 2 elements...
896 if ((diff
= (*(a
->compare
))(e
, a
->elements
[left
], a
->data
)) <= 0)
900 diff
= (*(a
->compare
))(e
, a
->elements
[right
], a
->data
);
908 * Do a linear pointer search...
911 DEBUG_puts("cups_find: linear search");
915 for (current
= 0; current
< a
->num_elements
; current
++)
916 if (a
->elements
[current
] == e
)
921 * Return the closest element and the difference...
924 DEBUG_printf(("cups_find: Returning %d, diff=%d\n", current
, diff
));
933 * End of "$Id: array.c 4970 2006-01-24 14:05:45Z mike $".