2 * "$Id: array.c 5119 2006-02-16 15:52:06Z 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_array_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 unique
, /* Are all elements unique? */
82 num_saved
, /* Number of saved elements */
85 void **elements
; /* Array elements */
86 cups_array_func_t compare
; /* Element comparison function */
87 void *data
; /* User data passed to compare */
95 static int cups_array_add(cups_array_t
*a
, void *e
, int insert
);
96 static int cups_array_find(cups_array_t
*a
, void *e
, int prev
, int *rdiff
);
100 * 'cupsArrayAdd()' - Add an element to the array.
102 * When adding an element to a sorted array, non-unique elements are
103 * appended at the end of the run. For unsorted arrays, the element
104 * is inserted at the end of the array.
107 int /* O - 1 on success, 0 on failure */
108 cupsArrayAdd(cups_array_t
*a
, /* I - Array */
109 void *e
) /* I - Element */
111 DEBUG_printf(("cupsArrayAdd(a=%p, e=%p)\n", a
, e
));
114 * Range check input...
119 DEBUG_puts("cupsArrayAdd: returning 0");
124 * Append the element...
127 return (cups_array_add(a
, e
, 0));
132 * 'cupsArrayClear()' - Clear the array.
136 cupsArrayClear(cups_array_t
*a
) /* I - Array */
139 * Range check input...
146 * Set the number of elements to 0; we don't actually free the memory
147 * here - that is done in cupsArrayDelete()...
159 * 'cupsArrayCount()' - Get the number of elements in the array.
162 int /* O - Number of elements */
163 cupsArrayCount(cups_array_t
*a
) /* I - Array */
166 * Range check input...
173 * Return the number of elements...
176 return (a
->num_elements
);
181 * 'cupsArrayCurrent()' - Return the current element in the array.
184 void * /* O - Element */
185 cupsArrayCurrent(cups_array_t
*a
) /* I - Array */
188 * Range check input...
195 * Return the current element...
198 if (a
->current
>= 0 && a
->current
< a
->num_elements
)
199 return (a
->elements
[a
->current
]);
206 * 'cupsArrayDelete()' - Free all memory used by the array.
210 cupsArrayDelete(cups_array_t
*a
) /* I - Array */
213 * Range check input...
220 * Free the array of element pointers - the caller is responsible
221 * for freeing the elements themselves...
224 if (a
->alloc_elements
)
232 * 'cupsArrayDup()' - Duplicate the array.
235 cups_array_t
* /* O - Duplicate array */
236 cupsArrayDup(cups_array_t
*a
) /* I - Array */
238 cups_array_t
*da
; /* Duplicate array */
242 * Range check input...
249 * Allocate memory for the array...
252 da
= calloc(1, sizeof(cups_array_t
));
256 da
->compare
= a
->compare
;
258 da
->current
= a
->current
;
259 da
->insert
= a
->insert
;
260 da
->unique
= a
->unique
;
261 da
->num_saved
= a
->num_saved
;
263 memcpy(da
->saved
, a
->saved
, sizeof(a
->saved
));
268 * Allocate memory for the elements...
271 da
->elements
= malloc(a
->num_elements
* sizeof(void *));
279 * Copy the element pointers...
282 memcpy(da
->elements
, a
->elements
, a
->num_elements
* sizeof(void *));
283 da
->num_elements
= a
->num_elements
;
284 da
->alloc_elements
= a
->num_elements
;
288 * Return the new array...
296 * 'cupsArrayFind()' - Find an element in the array.
299 void * /* O - Element found or NULL */
300 cupsArrayFind(cups_array_t
*a
, /* I - Array */
301 void *e
) /* I - Element */
303 int current
, /* Current element */
304 diff
; /* Difference */
308 * Range check input...
315 * See if we have any elements...
318 if (!a
->num_elements
)
322 * Yes, look for a match...
325 current
= cups_array_find(a
, e
, a
->current
, &diff
);
329 * Found a match! If the array does not contain unique values, find
330 * the first element that is the same...
333 if (!a
->unique
&& a
->compare
)
336 * The array is not unique, find the first match...
339 while (current
> 0 && !(*(a
->compare
))(e
, a
->elements
[current
- 1],
344 a
->current
= current
;
346 return (a
->elements
[current
]);
362 * 'cupsArrayFirst()' - Get the first element in the array.
365 void * /* O - First element or NULL */
366 cupsArrayFirst(cups_array_t
*a
) /* I - Array */
369 * Range check input...
376 * Return the first element...
381 return (cupsArrayCurrent(a
));
386 * 'cupsArrayIndex()' - Get the N-th element in the array.
389 void * /* O - N-th element or NULL */
390 cupsArrayIndex(cups_array_t
*a
, /* I - Array */
391 int n
) /* I - Index into array, starting at 0 */
398 return (cupsArrayCurrent(a
));
403 * 'cupsArrayInsert()' - Insert an element in the array.
405 * When inserting an element in a sorted array, non-unique elements are
406 * inserted at the beginning of the run. For unsorted arrays, the element
407 * is inserted at the beginning of the array.
410 int /* O - 0 on failure, 1 on success */
411 cupsArrayInsert(cups_array_t
*a
, /* I - Array */
412 void *e
) /* I - Element */
414 DEBUG_printf(("cupsArrayInsert(a=%p, e=%p)\n", a
, e
));
417 * Range check input...
422 DEBUG_puts("cupsArrayInsert: returning 0");
427 * Insert the element...
430 return (cups_array_add(a
, e
, 1));
435 * 'cupsArrayLast()' - Get the last element in the array.
438 void * /* O - Last element or NULL */
439 cupsArrayLast(cups_array_t
*a
) /* I - Array */
442 * Range check input...
449 * Return the last element...
452 a
->current
= a
->num_elements
- 1;
454 return (cupsArrayCurrent(a
));
459 * 'cupsArrayNew()' - Create a new array.
462 cups_array_t
* /* O - Array */
463 cupsArrayNew(cups_array_func_t f
, /* I - Comparison function */
464 void *d
) /* I - User data */
466 cups_array_t
*a
; /* Array */
470 * Allocate memory for the array...
473 a
= calloc(1, sizeof(cups_array_t
));
489 * 'cupsArrayNext()' - Get the next element in the array.
492 void * /* O - Next element or NULL */
493 cupsArrayNext(cups_array_t
*a
) /* I - Array */
496 * Range check input...
503 * Return the next element...
506 if (a
->current
< a
->num_elements
)
509 return (cupsArrayCurrent(a
));
514 * 'cupsArrayPrev()' - Get the previous element in the array.
517 void * /* O - Previous element or NULL */
518 cupsArrayPrev(cups_array_t
*a
) /* I - Array */
521 * Range check input...
528 * Return the previous element...
534 return (cupsArrayCurrent(a
));
539 * 'cupsArrayRemove()' - Remove an element from the array.
542 int /* O - 1 on success, 0 on failure */
543 cupsArrayRemove(cups_array_t
*a
, /* I - Array */
544 void *e
) /* I - Element */
546 int i
, /* Looping var */
547 current
, /* Current element */
548 diff
; /* Difference */
552 * Range check input...
559 * See if the element is in the array...
562 if (!a
->num_elements
)
565 current
= cups_array_find(a
, e
, a
->current
, &diff
);
570 * Yes, now remove it...
575 if (current
< a
->num_elements
)
576 memmove(a
->elements
+ current
, a
->elements
+ current
+ 1,
577 (a
->num_elements
- current
) * sizeof(void *));
579 if (current
<= a
->current
)
582 if (current
<= a
->insert
)
585 for (i
= 0; i
< a
->num_saved
; i
++)
586 if (current
<= a
->saved
[i
])
589 if (a
->num_elements
<= 1)
597 * 'cupsArrayRestore()' - Reset the current element to the last cupsArraySave.
600 void * /* O - New current element */
601 cupsArrayRestore(cups_array_t
*a
) /* I - Array */
606 if (a
->num_saved
<= 0)
610 a
->current
= a
->saved
[a
->num_saved
];
612 if (a
->current
>= 0 && a
->current
< a
->num_elements
)
613 return (a
->elements
[a
->current
]);
620 * 'cupsArraySave()' - Mark the current element for a later cupsArrayRestore.
622 * The save/restore stack is guaranteed to be at least 32 elements deep.
625 int /* O - 1 on success, 0 on failure */
626 cupsArraySave(cups_array_t
*a
) /* I - Array */
631 if (a
->num_saved
>= _CUPS_MAXSAVE
)
634 a
->saved
[a
->num_saved
] = a
->current
;
642 * 'cups_array_add()' - Insert or append an element to the array...
645 static int /* O - 1 on success, 0 on failure */
646 cups_array_add(cups_array_t
*a
, /* I - Array */
647 void *e
, /* I - Element to add */
648 int insert
) /* I - 1 = insert, 0 = append */
650 int i
, /* Looping var */
651 current
, /* Current element */
652 diff
; /* Comparison with current element */
655 DEBUG_printf(("cups_array_add(a=%p, e=%p, insert=%d)\n", a
, e
, insert
));
658 * Verify we have room for the new element...
661 if (a
->num_elements
>= a
->alloc_elements
)
664 * Allocate additional elements; start with 16 elements, then
665 * double the size until 1024 elements, then add 1024 elements
669 void **temp
; /* New array elements */
670 int count
; /* New allocation count */
673 if (a
->alloc_elements
== 0)
676 temp
= malloc(count
* sizeof(void *));
680 if (a
->alloc_elements
< 1024)
681 count
= a
->alloc_elements
* 2;
683 count
= a
->alloc_elements
+ 1024;
685 temp
= realloc(a
->elements
, count
* sizeof(void *));
688 DEBUG_printf(("cups_array_add: count=%d\n", count
));
692 DEBUG_puts("cupsAddAdd: allocation failed, returning 0");
696 a
->alloc_elements
= count
;
701 * Find the insertion point for the new element; if there is no
702 * compare function or elements, just add it to the beginning or end...
705 if (!a
->num_elements
|| !a
->compare
)
708 * No elements or comparison function, insert/append as needed...
712 current
= 0; /* Insert at beginning */
714 current
= a
->num_elements
; /* Append to the end */
719 * Do a binary search for the insertion point...
722 current
= cups_array_find(a
, e
, a
->insert
, &diff
);
727 * Insert after the current element...
735 * Compared equal, make sure we add to the begining or end of
736 * the current run of equal elements...
744 * Insert at beginning of run...
747 while (current
> 0 && !(*(a
->compare
))(e
, a
->elements
[current
- 1],
754 * Append at end of run...
761 while (current
< a
->num_elements
&&
762 !(*(a
->compare
))(e
, a
->elements
[current
], a
->data
));
768 * Insert or append the element...
771 if (current
< a
->num_elements
)
774 * Shift other elements to the right...
777 memmove(a
->elements
+ current
+ 1, a
->elements
+ current
,
778 (a
->num_elements
- current
) * sizeof(void *));
780 if (a
->current
>= current
)
783 for (i
= 0; i
< a
->num_saved
; i
++)
784 if (a
->saved
[i
] >= current
)
787 DEBUG_printf(("cups_array_add: insert element at index %d...\n", current
));
791 printf("cups_array_add: append element at %d...\n", current
);
794 a
->elements
[current
] = e
;
799 for (current
= 0; current
< a
->num_elements
; current
++)
800 printf("cups_array_add: a->elements[%d]=%p\n", current
, a
->elements
[current
]);
803 DEBUG_puts("cups_array_add: returning 1");
810 * 'cups_array_find()' - Find an element in the array...
813 static int /* O - Index of match */
814 cups_array_find(cups_array_t
*a
, /* I - Array */
815 void *e
, /* I - Element */
816 int prev
, /* I - Previous index */
817 int *rdiff
) /* O - Difference of match */
819 int left
, /* Left side of search */
820 right
, /* Right side of search */
821 current
, /* Current element */
822 diff
; /* Comparison with current element */
825 DEBUG_printf(("cups_array_find(a=%p, e=%p, prev=%d, rdiff=%p)\n", a
, e
, prev
,
831 * Do a binary search for the element...
834 DEBUG_puts("cups_array_find: binary search");
836 if (prev
>= 0 && prev
< a
->num_elements
)
839 * Start search on either side of previous...
842 if ((diff
= (*(a
->compare
))(e
, a
->elements
[prev
], a
->data
)) == 0 ||
843 (diff
< 0 && prev
== 0) ||
844 (diff
> 0 && prev
== (a
->num_elements
- 1)))
847 * Exact or edge match, return it!
850 DEBUG_printf(("cups_array_find: Returning %d, diff=%d\n", prev
, diff
));
859 * Start with previous on right side...
868 * Start wih previous on left side...
872 right
= a
->num_elements
- 1;
878 * Start search in the middle...
882 right
= a
->num_elements
- 1;
887 current
= (left
+ right
) / 2;
888 diff
= (*(a
->compare
))(e
, a
->elements
[current
], a
->data
);
890 DEBUG_printf(("cups_array_find: left=%d, right=%d, current=%d, diff=%d\n",
891 left
, right
, current
, diff
));
900 while ((right
- left
) > 1);
905 * Check the last 1 or 2 elements...
908 if ((diff
= (*(a
->compare
))(e
, a
->elements
[left
], a
->data
)) <= 0)
912 diff
= (*(a
->compare
))(e
, a
->elements
[right
], a
->data
);
920 * Do a linear pointer search...
923 DEBUG_puts("cups_array_find: linear search");
927 for (current
= 0; current
< a
->num_elements
; current
++)
928 if (a
->elements
[current
] == e
)
933 * Return the closest element and the difference...
936 DEBUG_printf(("cups_array_find: Returning %d, diff=%d\n", current
, diff
));
945 * End of "$Id: array.c 5119 2006-02-16 15:52:06Z mike $".