2 * listfunc - list handling routines
4 * Copyright (C) 1999-2007 David I. Bell
6 * Calc is open software; you can redistribute it and/or modify it under
7 * the terms of the version 2.1 of the GNU Lesser General Public License
8 * as published by the Free Software Foundation.
10 * Calc is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
13 * Public License for more details.
15 * A copy of version 2.1 of the GNU Lesser General Public License is
16 * distributed with calc under the filename COPYING-LGPL. You should have
17 * received a copy with calc; if not, write to Free Software Foundation, Inc.
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * @(#) $Revision: 30.1 $
21 * @(#) $Id: listfunc.c,v 30.1 2007/03/16 11:09:46 chongo Exp $
22 * @(#) $Source: /usr/local/src/bin/calc/RCS/listfunc.c,v $
24 * Under source code control: 1990/02/15 01:48:18
25 * File existed as early as: before 1990
27 * Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
31 * List handling routines.
32 * Lists can be composed of any types of values, mixed if desired.
33 * Lists are doubly linked so that elements can be inserted or
34 * deleted efficiently at any point in the list. A pointer is
35 * kept to the most recently indexed element so that sequential
43 E_FUNC
long irand(long s
);
45 S_FUNC LISTELEM
*elemalloc(void);
46 S_FUNC
void elemfree(LISTELEM
*ep
);
47 S_FUNC
void removelistelement(LIST
*lp
, LISTELEM
*ep
);
51 * Insert an element before the first element of a list.
54 * lp list to put element onto
55 * vp value to be inserted
58 insertlistfirst(LIST
*lp
, VALUE
*vp
)
60 LISTELEM
*ep
; /* list element */
63 copyvalue(vp
, &ep
->e_value
);
64 if (lp
->l_count
== 0) {
68 lp
->l_first
->e_prev
= ep
;
69 ep
->e_next
= lp
->l_first
;
77 * Insert an element after the last element of a list.
80 * lp list to put element onto
81 * vp value to be inserted
84 insertlistlast(LIST
*lp
, VALUE
*vp
)
86 LISTELEM
*ep
; /* list element */
89 copyvalue(vp
, &ep
->e_value
);
90 if (lp
->l_count
== 0) {
93 lp
->l_last
->e_next
= ep
;
94 ep
->e_prev
= lp
->l_last
;
102 * Insert an element into the middle of list at the given index (zero based).
103 * The specified index will select the new element, so existing elements
104 * at or beyond the index will be shifted down one position. It is legal
105 * to specify an index which is right at the end of the list, in which
106 * case the element is appended to the list.
109 * lp list to put element onto
110 * index element number to insert in front of
111 * vp value to be inserted
114 insertlistmiddle(LIST
*lp
, long index
, VALUE
*vp
)
116 LISTELEM
*ep
; /* list element */
117 LISTELEM
*oldep
; /* old list element at desired index */
120 insertlistfirst(lp
, vp
);
123 if (index
== lp
->l_count
) {
124 insertlistlast(lp
, vp
);
128 if ((index
>= 0) && (index
< lp
->l_count
))
129 oldep
= listelement(lp
, index
);
131 math_error("Index out of bounds for list insertion");
135 copyvalue(vp
, &ep
->e_value
);
137 ep
->e_prev
= oldep
->e_prev
;
138 ep
->e_prev
->e_next
= ep
;
141 lp
->l_cacheindex
= index
;
147 * Remove the first element from a list, returning its value.
148 * Returns the null value if no more elements exist.
151 * lp list to have element removed
152 * vp location of the value
155 removelistfirst(LIST
*lp
, VALUE
*vp
)
157 if (lp
->l_count
== 0) {
159 vp
->v_subtype
= V_NOSUBTYPE
;
162 *vp
= lp
->l_first
->e_value
;
163 lp
->l_first
->e_value
.v_type
= V_NULL
;
164 lp
->l_first
->e_value
.v_type
= V_NOSUBTYPE
;
165 removelistelement(lp
, lp
->l_first
);
170 * Remove the last element from a list, returning its value.
171 * Returns the null value if no more elements exist.
174 * lp list to have element removed
175 * vp location of the value
178 removelistlast(LIST
*lp
, VALUE
*vp
)
180 if (lp
->l_count
== 0) {
182 vp
->v_subtype
= V_NOSUBTYPE
;
185 *vp
= lp
->l_last
->e_value
;
186 lp
->l_last
->e_value
.v_type
= V_NULL
;
187 lp
->l_last
->e_value
.v_subtype
= V_NOSUBTYPE
;
188 removelistelement(lp
, lp
->l_last
);
193 * Remove the element with the given index from a list, returning its value.
196 * lp list to have element removed
197 * index list element to be removed
198 * vp location of the value
201 removelistmiddle(LIST
*lp
, long index
, VALUE
*vp
)
203 LISTELEM
*ep
; /* element being removed */
206 if ((index
>= 0) && (index
< lp
->l_count
))
207 ep
= listelement(lp
, index
);
209 math_error("Index out of bounds for list deletion");
213 ep
->e_value
.v_type
= V_NULL
;
214 ep
->e_value
.v_subtype
= V_NOSUBTYPE
;
215 removelistelement(lp
, ep
);
220 * Remove an arbitrary element from a list.
221 * The value contained in the element is freed.
225 * ep list element to remove
228 removelistelement(LIST
*lp
, LISTELEM
*ep
)
230 if ((ep
== lp
->l_cache
) || ((ep
!= lp
->l_first
) && (ep
!= lp
->l_last
)))
233 ep
->e_next
->e_prev
= ep
->e_prev
;
235 ep
->e_prev
->e_next
= ep
->e_next
;
236 if (ep
== lp
->l_first
) {
237 lp
->l_first
= ep
->e_next
;
240 if (ep
== lp
->l_last
)
241 lp
->l_last
= ep
->e_prev
;
248 listsegment(LIST
*lp
, long n1
, long n2
)
255 if ((n1
>= lp
->l_count
&& n2
>= lp
->l_count
) || (n1
< 0 && n2
< 0))
257 if (n1
>= lp
->l_count
)
258 n1
= lp
->l_count
- 1;
259 if (n2
>= lp
->l_count
)
260 n2
= lp
->l_count
- 1;
269 while(n1
-- > 0 && ep
)
271 while(i
-- > 0 && ep
) {
272 insertlistlast(newlp
, &ep
->e_value
);
277 while(n2
-- > 0 && ep
)
279 while(i
-- > 0 && ep
) {
280 insertlistfirst(newlp
, &ep
->e_value
);
289 * Search a list for the specified value starting at the specified index.
290 * Returns 0 and stores the element number (zero based) if the value is
291 * found, otherwise returns 1.
294 listsearch(LIST
*lp
, VALUE
*vp
, long i
, long j
, ZVALUE
*index
)
296 register LISTELEM
*ep
;
298 if (i
< 0 || j
> lp
->l_count
) {
299 math_error("This should not happen in call to listsearch");
303 ep
= listelement(lp
, i
);
306 math_error("This should not happen in listsearch");
309 if (acceptvalue(&ep
->e_value
, vp
)) {
311 lp
->l_cacheindex
= i
;
323 * Search a list backwards for the specified value starting at the
324 * specified index. Returns 0 and stores i if the value is found at
325 * index i; otherwise returns 1.
328 listrsearch(LIST
*lp
, VALUE
*vp
, long i
, long j
, ZVALUE
*index
)
330 register LISTELEM
*ep
;
332 if (i
< 0 || j
> lp
->l_count
) {
333 math_error("This should not happen in call to listrsearch");
337 ep
= listelement(lp
, --j
);
340 math_error("This should not happen in listsearch");
343 if (acceptvalue(&ep
->e_value
, vp
)) {
345 lp
->l_cacheindex
= j
;
357 * Index into a list and return the address for the value corresponding
358 * to that index. Returns NULL if the element does not exist.
361 * lp list to index into
362 * index index of desired element
365 listfindex(LIST
*lp
, long index
)
369 ep
= listelement(lp
, index
);
377 * Return the element at a specified index number of a list.
378 * The list is indexed starting at zero, and negative indices
379 * indicate to index from the end of the list. This routine finds
380 * the element by chaining through the list from the closest one
381 * of the first, last, and cached elements. Returns NULL if the
382 * element does not exist.
385 * lp list to index into
386 * index index of desired element
389 listelement(LIST
*lp
, long index
)
391 register LISTELEM
*ep
; /* current list element */
392 long dist
; /* distance to element */
393 long temp
; /* temporary distance */
394 BOOL forward
; /* TRUE if need to walk forwards */
397 index
+= lp
->l_count
;
398 if ((index
< 0) || (index
>= lp
->l_count
))
401 * Check quick special cases first.
406 return lp
->l_first
->e_next
;
407 if (index
== lp
->l_count
- 1)
409 if ((index
== lp
->l_cacheindex
) && lp
->l_cache
)
412 * Calculate whether it is better to go forwards from
413 * the first element or backwards from the last element.
415 forward
= ((index
* 2) <= lp
->l_count
);
420 dist
= (lp
->l_count
- 1) - index
;
424 * Now see if we have a cached element and if so, whether or
425 * not the distance from it is better than the above distance.
428 temp
= index
- lp
->l_cacheindex
;
429 if ((temp
>= 0) && (temp
< dist
)) {
434 if ((temp
< 0) && (-temp
< dist
)) {
441 * Now walk forwards or backwards from the selected element
442 * until we reach the correct element. Cache the location of
443 * the found element for future use.
453 lp
->l_cacheindex
= index
;
459 * Compare two lists to see if they are identical.
460 * Returns TRUE if they are different.
463 listcmp(LIST
*lp1
, LIST
*lp2
)
470 if (lp1
->l_count
!= lp2
->l_count
)
474 count
= lp1
->l_count
;
475 while (count
-- > 0) {
476 if (comparevalue(&e1
->e_value
, &e2
->e_value
))
489 listcopy(LIST
*oldlp
)
495 oldep
= oldlp
->l_first
;
497 insertlistlast(lp
, &oldep
->e_value
);
498 oldep
= oldep
->e_next
;
505 * Round elements of a list to a specified number of decimal digits
508 listround(LIST
*oldlp
, VALUE
*v2
, VALUE
*v3
)
511 LISTELEM
*oldep
, *ep
, *eq
;
514 oldep
= oldlp
->l_first
;
515 lp
->l_count
= oldlp
->l_count
;
520 roundvalue(&oldep
->e_value
, v2
, v3
, &ep
->e_value
);
521 oldep
= oldep
->e_next
;
536 * Round elements of a list to a specified number of binary digits
539 listbround(LIST
*oldlp
, VALUE
*v2
, VALUE
*v3
)
542 LISTELEM
*oldep
, *ep
, *eq
;
545 oldep
= oldlp
->l_first
;
546 lp
->l_count
= oldlp
->l_count
;
551 broundvalue(&oldep
->e_value
, v2
, v3
, &ep
->e_value
);
552 oldep
= oldep
->e_next
;
567 * Approximate a list by approximating elements by multiples of v2,
568 * type of rounding determined by v3.
571 listappr(LIST
*oldlp
, VALUE
*v2
, VALUE
*v3
)
574 LISTELEM
*oldep
, *ep
, *eq
;
577 oldep
= oldlp
->l_first
;
578 lp
->l_count
= oldlp
->l_count
;
583 apprvalue(&oldep
->e_value
, v2
, v3
, &ep
->e_value
);
584 oldep
= oldep
->e_next
;
599 * Construct a list whose elements are integer quotients of the elements
600 * of a specified list by a specified number.
603 listquo(LIST
*oldlp
, VALUE
*v2
, VALUE
*v3
)
606 LISTELEM
*oldep
, *ep
, *eq
;
609 oldep
= oldlp
->l_first
;
610 lp
->l_count
= oldlp
->l_count
;
615 quovalue(&oldep
->e_value
, v2
, v3
, &ep
->e_value
);
616 oldep
= oldep
->e_next
;
631 * Construct a list whose elements are the remainders after integral
632 * division of the elements of a specified list by a specified number.
635 listmod(LIST
*oldlp
, VALUE
*v2
, VALUE
*v3
)
638 LISTELEM
*oldep
, *ep
, *eq
;
641 oldep
= oldlp
->l_first
;
642 lp
->l_count
= oldlp
->l_count
;
647 modvalue(&oldep
->e_value
, v2
, v3
, &ep
->e_value
);
648 oldep
= oldep
->e_next
;
663 listreverse(LIST
*lp
)
675 e1
->e_value
= e2
->e_value
;
687 LISTELEM
*last
, *a
, *a1
, *b
, *next
;
688 LISTELEM
*S
[LONG_BITS
+1];
689 long len
[LONG_BITS
+1];
698 start
->e_next
= next
;
699 for (k
= 0; next
&& k
< LONG_BITS
; k
++) {
705 while (k
> 0 && (!next
|| len
[k
] >= len
[k
- 1])) {/* merging */
712 if (precvalue(&b
->e_value
, &a
->e_value
)) {
714 a
->e_prev
->e_next
= b
;
715 b
->e_prev
= a
->e_prev
;
719 if (!precvalue(&b
->e_value
,
730 b
->e_prev
->e_next
= a
;
731 a
->e_prev
= b
->e_prev
;
738 if (precvalue(&b
->e_value
,
745 a
->e_prev
->e_next
= b
;
746 b
->e_prev
= a
->e_prev
;
750 if (!precvalue(&b
->e_value
,
756 b
->e_prev
->e_next
= a
;
757 a
->e_prev
= b
->e_prev
;
771 if (k
>= LONG_BITS
) {
772 /* this should never happen */
773 math_error("impossible k overflow in listsort!");
776 lp
->l_first
= start
->e_next
;
777 lp
->l_first
->e_prev
= NULL
;
779 lp
->l_last
->e_next
= NULL
;
784 listrandperm(LIST
*lp
)
791 for (ep
= lp
->l_last
; s
> 1; ep
= ep
->e_prev
) {
794 eq
= listelement(lp
, i
);
796 eq
->e_value
= ep
->e_value
;
805 * Allocate an element for a list.
812 ep
= (LISTELEM
*) malloc(sizeof(LISTELEM
));
814 math_error("Cannot allocate list element");
819 ep
->e_value
.v_type
= V_NULL
;
820 ep
->e_value
.v_subtype
= V_NOSUBTYPE
;
826 * Free a list element, along with any contained value.
829 elemfree(LISTELEM
*ep
)
831 if (ep
->e_value
.v_type
!= V_NULL
)
832 freevalue(&ep
->e_value
);
838 * Allocate a new list header.
845 lp
= (LIST
*) malloc(sizeof(LIST
));
847 math_error("Cannot allocate list header");
853 lp
->l_cacheindex
= 0;
860 * Free a list header, along with all of its list elements.
865 register LISTELEM
*ep
;
867 while (lp
->l_count
-- > 0) {
869 lp
->l_first
= ep
->e_next
;
877 * Print out a list along with the specified number of its elements.
878 * The elements are printed out in shortened form.
881 listprint(LIST
*lp
, long max_print
)
887 if (max_print
> lp
->l_count
)
888 max_print
= lp
->l_count
;
892 while (index
-- > 0) {
893 if ((ep
->e_value
.v_type
!= V_NUM
) ||
894 (!qiszero(ep
->e_value
.v_num
)))
900 math_fmt("list (%ld element%s, %ld nonzero)", lp
->l_count
,
901 ((lp
->l_count
== 1) ? "" : "s"), count
);
906 * Walk through the first few list elements, printing their
907 * value in short and unambiguous format.
911 for (index
= 0; index
< max_print
; index
++) {
912 math_fmt("\t[[%ld]] = ", index
);
913 printvalue(&ep
->e_value
, PRINT_SHORT
| PRINT_UNAMBIG
);
917 if (max_print
< lp
->l_count
)