From 6c196ec8a41d6ed506c133c8b33dba9684f9a7a6 Mon Sep 17 00:00:00 2001 From: xleroy Date: Wed, 3 Mar 2010 12:34:43 +0000 Subject: Updated raytracer test. Added SPASS test. git-svn-id: https://yquem.inria.fr/compcert/svn/compcert/trunk@1271 fca1b0fc-160b-0410-b1d3-a4f43f01ea2e --- test/spass/list.c | 1660 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1660 insertions(+) create mode 100644 test/spass/list.c (limited to 'test/spass/list.c') diff --git a/test/spass/list.c b/test/spass/list.c new file mode 100644 index 00000000..c956e1e1 --- /dev/null +++ b/test/spass/list.c @@ -0,0 +1,1660 @@ +/**************************************************************/ +/* ********************************************************** */ +/* * * */ +/* * LISTS * */ +/* * * */ +/* * $Module: LIST * */ +/* * * */ +/* * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 * */ +/* * MPI fuer Informatik * */ +/* * * */ +/* * This program is free software; you can redistribute * */ +/* * it and/or modify it under the terms of the GNU * */ +/* * General Public License as published by the Free * */ +/* * Software Foundation; either version 2 of the License, * */ +/* * or (at your option) any later version. * */ +/* * * */ +/* * This program is distributed in the hope that it will * */ +/* * be useful, but WITHOUT ANY WARRANTY; without even * */ +/* * the implied warranty of MERCHANTABILITY or FITNESS * */ +/* * FOR A PARTICULAR PURPOSE. See the GNU General Public * */ +/* * License for more details. * */ +/* * * */ +/* * You should have received a copy of the GNU General * */ +/* * Public License along with this program; if not, write * */ +/* * to the Free Software Foundation, Inc., 59 Temple * */ +/* * Place, Suite 330, Boston, MA 02111-1307 USA * */ +/* * * */ +/* * * */ +/* $Revision: 21527 $ * */ +/* $State$ * */ +/* $Date: 2005-04-24 21:10:28 -0700 (Sun, 24 Apr 2005) $ * */ +/* $Author: duraid $ * */ +/* * * */ +/* * Contact: * */ +/* * Christoph Weidenbach * */ +/* * MPI fuer Informatik * */ +/* * Stuhlsatzenhausweg 85 * */ +/* * 66123 Saarbruecken * */ +/* * Email: weidenb@mpi-sb.mpg.de * */ +/* * Germany * */ +/* * * */ +/* ********************************************************** */ +/**************************************************************/ + + +/* $RCSfile$ */ + +#include "list.h" + +/**************************************************************/ +/* ********************************************************** */ +/* * * */ +/* * MEMORY MANAGEMENT * */ +/* * * */ +/* ********************************************************** */ +/**************************************************************/ + +LIST list_Copy(const LIST List) +/************************************************************** + INPUT: A List. + RETURNS: The copy of the list. + CAUTION: The entries of the list are NOT copied ! + the function needs time O(n), where is the length + of the list. +***************************************************************/ +{ + LIST Copy; + LIST Scan1,Scan2; + + + if (list_Empty(List)) + return list_Nil(); + + Copy = list_List(list_Car(List)); + Scan1 = Copy; + Scan2 = list_Cdr(List); + + while (!list_Empty(Scan2)) { + list_Rplacd(Scan1, list_List(list_Car(Scan2))); + Scan1 = list_Cdr(Scan1); + Scan2 = list_Cdr(Scan2); + } + return Copy; +} + + +LIST list_CopyWithElement(const LIST List, POINTER (*CopyElement)(POINTER)) +/************************************************************** + INPUT: A List and a copy function for the elements. + RETURNS: The copy of the list. + CAUTION: The entries of the list are NOT copied ! + The function needs time O(n*c), where is the length + of the list and is the time for a call of the + element copy function. +***************************************************************/ +{ + LIST Copy; + LIST Scan1,Scan2; + + if (list_Empty(List)) + return list_Nil(); + + Copy = list_List(CopyElement(list_Car(List))); + Scan1 = Copy; + Scan2 = list_Cdr(List); + + while (!list_Empty(Scan2)) { + list_Rplacd(Scan1, list_List(CopyElement(list_Car(Scan2)))); + Scan1 = list_Cdr(Scan1); + Scan2 = list_Cdr(Scan2); + } + return Copy; +} + + +void list_InsertNext(LIST List, POINTER Pointer) +/************************************************************** + INPUT: A list and a pointer to anything. + RETURNS: A list with Pointer being added at the position that + follows List. + SUMMARY: We enqueue the element at position list_Cdr(List); + The function needs time O(1). +***************************************************************/ +{ +#ifdef CHECK + if (Pointer == NULL) { + misc_StartErrorReport(); + misc_ErrorReport("\n In list_InsertNext: NULL Pointer. "); + misc_FinishErrorReport(); + } +#endif + + list_Rplacd(List, list_Cons(Pointer, list_Cdr(List))); +} + + +void list_NMapCar(LIST List, POINTER (*ElementFunc)(POINTER)) +/************************************************************** + INPUT: A List and a function for the elements. + RETURNS: The List where all elements are replaced by the result of + the function calls of to the elements + CAUTION: The List is not copied ! + The function needs time O(n*f), where is the length + of the list and is the time for a call of the + element function. +***************************************************************/ +{ + LIST Scan; + + for (Scan = List; !list_Empty(Scan); Scan = list_Cdr(Scan)) + list_Rplaca(Scan, ElementFunc(list_Car(Scan))); +} + + +void list_Apply(void (*Function)(POINTER), LIST List) +/************************************************************** + INPUT: A non-resulting function and a list. + SUMMARY: Apply the function to all members of the list. + The function needs time O(n*f), where is the length + of the list and is the time for a call of the + element function. +***************************************************************/ +{ + while (!list_Empty(List)) { + Function(list_Car(List)); + List = list_Cdr(List); + } +} + + +LIST list_Reverse(const LIST List) +/************************************************************** + INPUT: A list. + RETURNS: A new list where the order of the elements is reversed. + EFFECT: The function needs time O(n), where is the length + of the list. +***************************************************************/ +{ + LIST ReverseList; + LIST Scan; + + ReverseList = list_Nil(); + + for (Scan=List;!list_Empty(Scan);Scan=list_Cdr(Scan)) + ReverseList = list_Cons(list_Car(Scan), ReverseList); + + return ReverseList; +} + + +LIST list_NReverse(LIST List) +/************************************************************** + INPUT: A list + RETURNS: The same list with reversed order of items. + CAUTION: Destructive. + The function needs time O(n), where is the length + of the list. +***************************************************************/ +{ + LIST ReverseList; + LIST Scan1; + LIST Scan2; + + ReverseList = list_Nil(); + + for (Scan1=List; !list_Empty(Scan1); Scan1=list_Cdr(Scan1)) + ReverseList = list_Cons(list_Car(Scan1),ReverseList); + + for (Scan1=List, Scan2=ReverseList; + !list_Empty(Scan1); + Scan1=list_Cdr(Scan1), Scan2=list_Cdr(Scan2)) + list_Rplaca(Scan1, list_Car(Scan2)); + + list_Delete(ReverseList); + return List; +} + + +static __inline__ BOOL list_PointerLower (POINTER A, POINTER B) +{ + return (NAT) A < (NAT) B; +} + +LIST list_PointerSort(LIST List) +/************************************************************** + INPUT: A list + RETURNS: The same list where the elements are sorted as pointers. + EFFECT: The function needs time O(n log n), where is the length + of the list. + CAUTION: Destructive. +***************************************************************/ +{ + return list_Sort(List, list_PointerLower); +} + + +BOOL list_SortedInOrder(LIST L, BOOL (*Test)(POINTER, POINTER)) +/************************************************************** + INPUT: A list, and an ordering function. + RETURNS: TRUE, if the list is ordered with respect to the + ordering function, FALSE otherwise. + EFFECT: The function needs time O(n), where is the + length of the list. +***************************************************************/ +{ + LIST Scan1, Scan2; + + if (!(list_Empty(L) || list_Empty(list_Cdr(L)))) { + Scan1 = L; + Scan2 = list_Cdr(Scan1); + + /* Scan the list. */ + do { + /* If all elements are ordered, then every element */ + /* is <= its successor with respect to the ordering */ + /* function. */ + /* We might have a strictly ordering Test function, */ + /* which implements < instead of <=, so let's test */ + /* for equality first. */ + if (!Test(list_Car(Scan1), list_Car(Scan2)) && + Test(list_Car(Scan2), list_Car(Scan1))) + /* It is really strictly greater, so return FALSE. */ + return FALSE; + + Scan1 = list_Cdr(Scan1); + Scan2 = list_Cdr(Scan1); + } while (!list_Empty(Scan2)); + } + + return TRUE; +} + + +LIST list_Merge(LIST List1, LIST List2, BOOL (*Test)(POINTER, POINTER)) +/************************************************************** + INPUT: Two sorted lists List1 and List2, and an ordering function. + RETURNS: The merged list ordered with respect to the ordering function. + EFFECT: The function needs time O(n), where is the length of the list. +***************************************************************/ +{ + + LIST Scan1, Scan2, Result, ResultStart; + +#ifdef CHECK + if (!list_SortedInOrder(List1, Test)) { + /* print an error message and exit */ + misc_StartErrorReport(); + misc_ErrorReport("\n In list_Merge: First argument is not sorted."); + misc_FinishErrorReport(); + } + else if (!list_SortedInOrder (List2, Test)) { + /* print an error message and exit */ + misc_StartErrorReport(); + misc_ErrorReport("\n In list_Merge: Second argument is not sorted."); + misc_FinishErrorReport(); + } +#endif + + if (list_Empty(List1)) + return List2; + + if (list_Empty(List2)) + return List1; + + /* This version is derived from list_NNumberMerge, but it doesn't need */ + /* to allocate and deallocate memory, so it should be more efficient. */ + + /* Use the list with the least element as result list. */ + if (Test(list_Car(List1), list_Car(List2))) { + ResultStart = List1; + Scan1 = list_Cdr(List1); + Scan2 = List2; + } + else { + ResultStart = List2; + Scan1 = List1; + Scan2 = list_Cdr(List2); + } + + /* Result is the last element of the merged list. */ + + Result = ResultStart; + + while (!list_Empty(Scan1) && !list_Empty(Scan2)) { + /* This function doesn't implement stable merging. */ + /* Add another test if you need it. */ + + if (Test(list_Car(Scan1), list_Car(Scan2))) { + list_Rplacd(Result,Scan1); + Scan1 = list_Cdr(Scan1); + } + else { + list_Rplacd(Result,Scan2); + Scan2 = list_Cdr(Scan2); + } + Result = list_Cdr(Result); + } + + if (list_Empty(Scan1)) + list_Rplacd(Result, Scan2); + else + list_Rplacd(Result, Scan1); + + return ResultStart; +} + + +void list_Split(LIST L, LIST *Half1, LIST *Half2) +/************************************************************** + INPUT: A list, and two pointers to lists. + RETURNS: Nothing. + EFFECT: The input list is split in two. and + point to the resulting halves. + The input list is destructively changed! + If the list length is odd, is assigned the + bigger part. + The function needs time O(n), where is the + length of the input list. +***************************************************************/ +{ + /* Adapted code from proofcheck ... MergeSort. */ + + LIST SingleStep, DoubleStep, Prev; + + if (list_Empty(L) || list_Empty(list_Cdr(L))) { + *Half1 = list_Nil(); + *Half2 = L; + } + else { + /* divide list in two halves */ + Prev = L; + SingleStep = list_Cdr(L); + DoubleStep = list_Cdr(SingleStep); + + while (!list_Empty(DoubleStep) && !list_Empty(list_Cdr(DoubleStep))) { + Prev = SingleStep; + SingleStep = list_Cdr(SingleStep); + DoubleStep = list_Cdr(list_Cdr(DoubleStep)); + } + + *Half1 = L; + *Half2 = SingleStep; + list_Rplacd(Prev, list_Nil()); + } +} + + +LIST list_MergeSort (LIST L, BOOL (*Test) (POINTER, POINTER)) +/************************************************************** + INPUT: A list, and an ordering function. + RETURNS: The list sorted with respect to the ordering function. + EFFECT: The function needs time O((n log n) * t), where + is the length of the input list and is the + execution time of the ordering function. +***************************************************************/ +{ + LIST Result; +#ifdef CHECK + NAT originallength; + + originallength = list_Length(L); +#endif + + /* Only sort if list has more than one element */ + if (!list_Empty(L) && !list_Empty(list_Cdr(L))) { + LIST lowerhalf; + LIST greaterhalf; + + LIST *lowerhalfptr; + LIST *greaterhalfptr; + + lowerhalfptr = &lowerhalf; + greaterhalfptr = &greaterhalf; + + list_Split(L, lowerhalfptr, greaterhalfptr); + +#ifdef CHECK + if((list_Length(lowerhalf) + list_Length(greaterhalf)) + != originallength) { + /* output an error message and exit */ + misc_StartErrorReport(); + misc_ErrorReport("\n In list_MergeSort: Split lists' total sizes"); + misc_ErrorReport("\n don't match original list's size."); + misc_FinishErrorReport(); + } +#endif + + lowerhalf = list_MergeSort(lowerhalf, Test); + + greaterhalf = list_MergeSort(greaterhalf, Test); + +#ifdef CHECK + if((list_Length(lowerhalf) + list_Length(greaterhalf)) + != originallength) { + /* output an error message and exit */ + misc_StartErrorReport(); + misc_ErrorReport("\n In list_MergeSort: Mergesorted lists' total sizes"); + misc_ErrorReport("\n don't match original list's size."); + misc_FinishErrorReport(); + } +#endif + + Result = list_Merge(lowerhalf, greaterhalf, Test); + +#ifdef CHECK + if(list_Length(Result) != originallength) { + /* output an error message and exit */ + misc_StartErrorReport(); + misc_ErrorReport("\n In list_MergeSort: Merged list's size doesn't match "); + misc_ErrorReport("\n original list's size."); + misc_FinishErrorReport(); + } +#endif + + } + else { + Result = L; + } + + return Result; +} + + +LIST list_InsertionSort(LIST List, BOOL (*Test)(POINTER, POINTER)) +/************************************************************** + INPUT: A list and a 'less' function on the elements. + RETURNS: The same list where the elements are sorted with + respect to Test. + EFFECT: The function needs time O(n^2*t), where is the + length of the list and is the time for the test + function. + CAUTION: Destructive. +***************************************************************/ +{ + LIST Scan1,Scan2,Min; + POINTER Exchange; + + for (Scan1=List; !list_Empty(Scan1); Scan1=list_Cdr(Scan1)) { + Min = Scan1; + for (Scan2 = list_Cdr(Scan1); !list_Empty(Scan2); Scan2 = list_Cdr(Scan2)) + if (Test(list_Car(Scan2), list_Car(Min))) { + Exchange = list_Car(Min); + list_Rplaca(Min, list_Car(Scan2)); + list_Rplaca(Scan2, Exchange); + } + } + + return List; +} + + +LIST list_Sort(LIST List, BOOL (*Test)(POINTER, POINTER)) +/************************************************************** + INPUT: A list and a 'less' function on the elements. + RETURNS: The same list where the elements are sorted with + respect to Test. + EFFECT: The function needs time O((n log n) *t), where + is the length of the list and is the time for + the test function. + CAUTION: Destructive. +***************************************************************/ +{ + LIST Result; + +#ifdef CHECK + NAT originallength; + + originallength = list_Length(List); +#endif + + Result = list_MergeSort(List, Test); + +#ifdef CHECK + if (!list_SortedInOrder(Result, Test)) { + misc_StartErrorReport(); + misc_ErrorReport("\n In list_Sort: list_MergeSort did not sort properly."); + misc_FinishErrorReport(); + } + if (list_Length(Result) != originallength) { + misc_StartErrorReport(); + misc_ErrorReport("\n In list_Sort: list_MergeSort lost elements. "); + misc_FinishErrorReport(); + } +#endif + + return Result; +} + + +/* Help Variable used to store a pointer to the numbering function to use + in element comparisons. +*/ +static NAT (*NumberFunction)(POINTER) = NULL; + +static __inline__ BOOL list_PointerNumberedLower(POINTER A, POINTER B) +{ + return (BOOL) (NumberFunction(A) < NumberFunction(B)); +} + +static __inline__ BOOL list_PointerNumberedLowerOrEqual(POINTER A, POINTER B) +{ + return (BOOL) (NumberFunction(A) <= NumberFunction(B)); +} + +static __inline__ BOOL list_PointerNumberedGreater(POINTER A, POINTER B) +{ + return (BOOL) (NumberFunction(A) > NumberFunction(B)); +} + +LIST list_NumberSort(LIST List, NAT (*Number)(POINTER)) +/************************************************************** + INPUT: A list and function mapping elements to numbers. + RETURNS: The same list where the elements are sorted with + respect to < and the Number function. + EFFECT: The function needs time O((n log n) * f), where + is the length of the list and is the time for a + call of the function. + CAUTION: Destructive. +***************************************************************/ +{ + /* Use number function as temporary variable. It is used as + an implicit parameter in list_PointerLower. + We can't make it an explicit parameter, because of the + prototype of list_Sort. + */ + + NumberFunction = Number; + + return list_Sort(List, list_PointerNumberedLower); + +} + + +LIST list_GreaterNumberSort(LIST List, NAT (*Number)(POINTER)) +/************************************************************** + INPUT: A list and function mapping elements to numbers. + RETURNS: The same list where the elements are sorted with + respect to > and the Number function. + EFFECT: The function needs time O((n log n) * f), where + is the length of the list and is the time for a + call of the function. + CAUTION: Destructive. +***************************************************************/ +{ + /* Use number function as temporary variable. It is used as + an implicit parameter in list_PointerLower. + We can't make it an explicit parameter, because of the + prototype of list_Sort. + */ + + NumberFunction = Number; + + return list_Sort(List, list_PointerNumberedGreater); +} + + +LIST list_NNumberMerge(LIST List1, LIST List2, NAT (*Number)(POINTER)) +/************************************************************** + INPUT: Two sorted lists and function mapping elements to + numbers. + RETURNS: The merge of the lists where the elements are sorted + with respect to < and the Number function. + CAUTION: Destructive on both lists. +***************************************************************/ +{ + NumberFunction = Number; + + return list_Merge(List1, List2, list_PointerNumberedLowerOrEqual); +} + + +POINTER list_DequeueNext(LIST List) +/************************************************************** + INPUT: A list + RETURNS: A pointer to a dequeued element. + SUMMARY: We dequeue the element pointed to by list_Cdr(List). + The function needs time O(1). +***************************************************************/ +{ + POINTER Pointer; + LIST Memo; + + if (list_Empty(List)) + return NULL; + + Memo = list_Cdr(List); + if (list_Empty(Memo)) + return NULL; + + Pointer = list_Car(Memo); + list_Rplacd(List, Memo->cdr); + list_Free(Memo); + return Pointer; +} + + +POINTER list_NthElement(LIST List, NAT Number) +/************************************************************** + INPUT: A List and a natural number. + RETURNS: The th element of the list, NULL otherwise. + EFFECT: The function needs time O(Number). +***************************************************************/ +{ + while (!list_Empty(List) && --Number > 0) + List = list_Cdr(List); + + if (list_Empty(List)) + return NULL; + else + return list_Car(List); +} + + +void list_DeleteWithElement(LIST List, void (*ElementDelete)(POINTER)) +/************************************************************** + INPUT: A list and a delete function for the elements. + RETURNS: Nothing. + EFFECT: The list and all its elements are deleted. + The function needs time O(n*d), where is the length + of the list and is the time for the delete function. +***************************************************************/ +{ + LIST Scan; + + while (!list_Empty(List)) { + Scan = list_Cdr(List); + ElementDelete(list_Car(List)); + list_Free(List); + List = Scan; + } +} + + +NAT list_DeleteWithElementCount(LIST List, void (*ElementDelete)(POINTER)) +/************************************************************** + INPUT: A List and a delete function for the elements. + RETURNS: The number of deleted elements. + EFFECT: The List and all its elements are deleted. + The function needs time O(n*d), where is the length + of the list and is the time for the delete function. +***************************************************************/ +{ + int Result; + LIST Scan; + + Result = 0; + + while (!list_Empty(List)) { + Scan = list_Cdr(List); + ElementDelete(list_Car(List)); + list_Free(List); + List = Scan; + Result++; + } + + return Result; +} + + +LIST list_DeleteElement(LIST List, POINTER Element, BOOL (*Test)(POINTER, POINTER)) +/************************************************************** + INPUT: A list, an element pointer, an equality test for + elements + RETURNS: The list where Element is deleted from List with + respect to Test. + EFFECTS: If List contains Element with respect to EqualityTest, + Element is deleted from List + CAUTION: Destructive. Be careful, the first element of a + list cannot be changed destructively by call by + reference. +***************************************************************/ +{ + LIST Scan1,Scan2; + + while (!list_Empty(List) && Test(Element, list_Car(List))) { + Scan1 = list_Cdr(List); + list_Free(List); + List = Scan1; + } + + if (list_Empty(List)) + return list_Nil(); + + Scan2 = List; + Scan1 = list_Cdr(List); + + while (!list_Empty(Scan1)) { + if (Test(Element, list_Car(Scan1))) { + list_Rplacd(Scan2, list_Cdr(Scan1)); + list_Free(Scan1); + Scan1 = list_Cdr(Scan2); + } + else { + Scan2 = Scan1; + Scan1 = list_Cdr(Scan1); + } + } + return List; +} + + +LIST list_DeleteElementIf(LIST List, BOOL (*Test)(POINTER)) +/************************************************************** + INPUT: A list and a test for elements. + RETURNS: The list where an element is deleted if on it + succeeds. + CAUTION: Destructive. Be careful, the first element of a list + cannot be changed destructively by call by + reference. +***************************************************************/ +{ + LIST Scan1,Scan2; + + while (!list_Empty(List) && Test(list_Car(List))) { + Scan1 = list_Cdr(List); + list_Free(List); + List = Scan1; + } + + if (list_Empty(List)) + return list_Nil(); + + Scan2 = List; + Scan1 = list_Cdr(List); + + while (!list_Empty(Scan1)) { + if (Test(list_Car(Scan1))) { + list_Rplacd(Scan2, list_Cdr(Scan1)); + list_Free(Scan1); + Scan1 = list_Cdr(Scan2); + } + else { + Scan2 = Scan1; + Scan1 = list_Cdr(Scan1); + } + } + return List; +} + + +LIST list_DeleteElementIfFree(LIST List, BOOL (*Test)(POINTER), + void (*Delete)(POINTER)) +/************************************************************** + INPUT: A list, a test for elements and a delete function + for elements. + RETURNS: The list where an element is deleted if on it + succeeds. + The element is deleted with . + CAUTION: Destructive. Be careful, the first element of a list + cannot be changed destructively by call by reference. +***************************************************************/ +{ + LIST Scan1,Scan2; + + while (!list_Empty(List) && Test(list_Car(List))) { + Scan1 = list_Cdr(List); + Delete(list_Car(List)); + list_Free(List); + List = Scan1; + } + + if (list_Empty(List)) + return list_Nil(); + + Scan2 = List; + Scan1 = list_Cdr(List); + + while (!list_Empty(Scan1)) { + if (Test(list_Car(Scan1))) { + Delete(list_Car(Scan1)); + list_Rplacd(Scan2, list_Cdr(Scan1)); + list_Free(Scan1); + Scan1 = list_Cdr(Scan2); + } + else { + Scan2 = Scan1; + Scan1 = list_Cdr(Scan1); + } + } + return List; +} + + + +LIST list_DeleteElementFree(LIST List, POINTER Element, + BOOL (*Test)(POINTER, POINTER), + void (*Free)(POINTER)) +/************************************************************** + INPUT: A list, an element pointer, an equality test for + elements and a free function for elements. + RETURNS: The list where Element is deleted from List with + respect to Test. + EFFECTS: If the list contains with respect to , + is deleted from the list and freed. + CAUTION: Destructive. Be careful, the first element of a list + cannot be changed destructively by call by reference. +***************************************************************/ +{ + LIST Scan1,Scan2; + + while (!list_Empty(List) && Test(Element, list_Car(List))) { + Scan1 = list_Cdr(List); + Free(list_Car(List)); + list_Free(List); + List = Scan1; + } + + if (list_Empty(List)) + return list_Nil(); + + Scan2 = List; + Scan1 = list_Cdr(List); + + while (!list_Empty(Scan1)) { + if (Test(Element, list_Car(Scan1))) { + list_Rplacd(Scan2, list_Cdr(Scan1)); + Free(list_Car(Scan1)); + list_Free(Scan1); + Scan1 = list_Cdr(Scan2); + } + else { + Scan2 = Scan1; + Scan1 = list_Cdr(Scan1); + } + } + return List; +} + + +LIST list_DeleteOneElement(LIST List, POINTER Element, BOOL (*Test)(POINTER, POINTER)) +/************************************************************** + INPUT: A list, an element pointer and an equality test for + elements. + RETURNS: The list where at most one element was deleted from + if the Test between and the element + succeeds. + EFFECT: The function needs time O(n*t) in the worst case, and + time O(t) in the best case, where is the length of + the list and t is the time for a call of the test function. + CAUTION: Destructive. Be careful, the first element of a list + cannot be changed destructively by call by + reference. + The memory of the deleted element is not freed. +***************************************************************/ +{ + LIST scan1, scan2; + + if (list_Empty(List)) + return List; + else { + if (Test(Element, list_Car(List))) + return list_Pop(List); + } + + for (scan2 = List, scan1 = list_Cdr(List); !list_Empty(scan1); + scan2 = scan1, scan1 = list_Cdr(scan1)) { + if (Test(Element, list_Car(scan1))) { + list_Rplacd(scan2, list_Cdr(scan1)); + list_Free(scan1); + scan1 = list_Cdr(scan2); + return List; + } + } + return List; +} + + +LIST list_PointerDeleteElement(LIST List, POINTER Element) +/************************************************************** + INPUT: A list and an element pointer + RETURNS: The list where Element is deleted from List with respect to + pointer equality. + EFFECTS: If contains with respect to pointer equality, + is deleted from . + This function needs time O(n), where is the length of the list. + CAUTION: Destructive. Be careful, the first element of a list cannot + be changed destructively by call by reference. +***************************************************************/ +{ + LIST Scan1,Scan2; + + while (!list_Empty(List) && Element == list_Car(List)) { + Scan1 = list_Cdr(List); + list_Free(List); + List = Scan1; + } + + if (list_Empty(List)) + return list_Nil(); + + Scan2 = List; + Scan1 = list_Cdr(List); + + while (!list_Empty(Scan1)) { + if (Element == list_Car(Scan1)) { + list_Rplacd(Scan2, list_Cdr(Scan1)); + list_Free(Scan1); + Scan1 = list_Cdr(Scan2); + } + else { + Scan2 = Scan1; + Scan1 = list_Cdr(Scan1); + } + } + return List; +} + +LIST list_PointerDeleteElementFree(LIST List, POINTER Element, + void (*Free)(POINTER)) +/************************************************************** + INPUT: A list, an element pointer and a free function for + elements. + RETURNS: The list where Element is deleted from List with + respect to pointer equality and freed. + EFFECTS: If List contains Element with respect to pointer + equality, Element is deleted from List + CAUTION: Destructive. Be careful, the first element of a list + cannot be changed destructively by call by + reference. +***************************************************************/ +{ + LIST Scan1,Scan2; + + while (!list_Empty(List) && Element == list_Car(List)) { + Scan1 = list_Cdr(List); + Free(list_Car(List)); + list_Free(List); + List = Scan1; + } + + if (list_Empty(List)) + return list_Nil(); + + Scan2 = List; + Scan1 = list_Cdr(List); + + while (!list_Empty(Scan1)) { + if (Element == list_Car(Scan1)) { + list_Rplacd(Scan2, list_Cdr(Scan1)); + Free(list_Car(Scan1)); + list_Free(Scan1); + Scan1 = list_Cdr(Scan2); + } + else { + Scan2 = Scan1; + Scan1 = list_Cdr(Scan1); + } + } + return List; +} + + +LIST list_PointerDeleteOneElement(LIST List, POINTER Element) +/************************************************************** + INPUT: A list and an element pointer. + RETURNS: The list where one occurrence of Element is deleted from List + with respect to pointer equality. + EFFECTS: If List contains Element with respect to pointer equality, + Element is deleted from List. + CAUTION: Destructive. Be careful, the first element of a list cannot + be changed destructively by call by reference. +***************************************************************/ +{ + LIST Scan1,Scan2; + + if (list_Empty(List)) + return List; + else { + if (Element == list_Car(List)) + return list_Pop(List); + } + + Scan2 = List; + Scan1 = list_Cdr(List); + + while (!list_Empty(Scan1)) { + if (Element == list_Car(Scan1)) { + list_Rplacd(Scan2, list_Cdr(Scan1)); + list_Free(Scan1); + Scan1 = list_Cdr(Scan2); + return List; + } + else { + Scan2 = Scan1; + Scan1 = list_Cdr(Scan1); + } + } + return List; +} + + +BOOL list_DeleteFromList(LIST* List, POINTER Element) +/************************************************************** + INPUT: A list and an element pointer + RETURNS: TRUE, if Element was deleted; FALSE, otherwise. + EFFECTS: If List contains Element with respect to pointer equality, + all occurrences of Element are deleted from List. + CAUTION: Destructive. Be careful, the first element of a list cannot + be changed destructively by call by reference. +***************************************************************/ +{ + BOOL Found; + LIST Scan1; + + Found = FALSE; + + while (list_Exist(*List) && Element == list_Car(*List)) { + Scan1 = list_Cdr(*List); + list_Free(*List); + *List = Scan1; + Found = TRUE; + } + + if (list_Exist(*List)) { + LIST Scan2; + + Scan2 = *List; + Scan1 = list_Cdr(*List); + + while (list_Exist(Scan1)) { + if (Element == list_Car(Scan1)) { + list_Rplacd(Scan2, list_Cdr(Scan1)); + list_Free(Scan1); + Scan1 = list_Cdr(Scan2); + Found = TRUE; + } else { + Scan2 = Scan1; + Scan1 = list_Cdr(Scan1); + } + } + } + + return Found; +} + + +BOOL list_DeleteOneFromList(LIST* List, POINTER Element) +/************************************************************** + INPUT: A list and an element pointer + RETURNS: TRUE, if was deleted; FALSE, otherwise. + EFFECTS: If contains with respect to pointer equality, + the first occurrence of is deleted from . + CAUTION: Destructive. +***************************************************************/ +{ + if (list_Exist(*List)) { + LIST Scan1; + + /* special treatment for the first element */ + if (Element == list_Car(*List)) { + Scan1 = list_Cdr(*List); + list_Free(*List); + *List = Scan1; + return TRUE; + } else { + LIST Scan2; + + for (Scan2 = *List, Scan1 = list_Cdr(*List); list_Exist(Scan1); ) { + if (Element == list_Car(Scan1)) { + list_Rplacd(Scan2, list_Cdr(Scan1)); + list_Free(Scan1); + Scan1 = list_Cdr(Scan2); + return TRUE; + } else { + Scan2 = Scan1; + Scan1 = list_Cdr(Scan1); + } + } + } + } + return FALSE; +} + + +BOOL list_IsSetOfPointers(LIST L) +/************************************************************** + INPUT: A list. + RETURNS: TRUE, if is a set of pointers (without duplicates), + FALSE, otherwise. + EFFECT: The function needs n(n-1)/2 comparisons in the worst case, + where n is the length of the list. So its time complexity + is O(n^2). +***************************************************************/ +{ + for ( ; !list_Empty(L); L = list_Cdr(L)) { + if (list_PointerMember(list_Cdr(L), list_Car(L))) + return FALSE; + } + return TRUE; +} + + +LIST list_DeleteDuplicates(LIST List, BOOL (*Test)(POINTER, POINTER)) +/************************************************************** + INPUT: A list, an equality test for elements + RETURNS: The list where multiple occurrences are deleted. + CAUTION: Destructive. +***************************************************************/ +{ + LIST Scan; + + Scan = List; + + while (!list_Empty(Scan)) { + list_Rplacd(Scan, + list_DeleteElement(list_Cdr(Scan), list_Car(Scan), Test)); + Scan = list_Cdr(Scan); + } + return List; +} + + +LIST list_DeleteDuplicatesFree(LIST List, BOOL (*Test)(POINTER, POINTER), + void (*Free)(POINTER)) +/************************************************************** + INPUT: A list, an equality test for elements, and a free + function for elements. + RETURNS: The list where multiple occurrences are deleted. + CAUTION: Destructive and frees all duplicates. +***************************************************************/ +{ + LIST Scan; + + Scan = List; + + while (!list_Empty(Scan)) { + list_Rplacd(Scan, list_DeleteElementFree(list_Cdr(Scan), list_Car(Scan), Test, Free)); + Scan = list_Cdr(Scan); + } + return List; +} + + +LIST list_PointerDeleteDuplicates(LIST List) +/************************************************************** + INPUT: A list + RETURNS: The list where multiple occurrences are deleted. + CAUTION: Destructive. + EFFECT: The function needs +***************************************************************/ +{ + LIST Scan; + + Scan = List; + + while (!list_Empty(Scan)) { + list_Rplacd(Scan, list_PointerDeleteElement(list_Cdr(Scan), + list_Car(Scan))); + Scan = list_Cdr(Scan); + } + return List; +} + + +LIST list_NPointerUnion(LIST List1, LIST List2) +/************************************************************** + INPUT: Two lists. + RETURNS: Regarding both lists as sets, the union of the sets. + CAUTION: Destructive. +***************************************************************/ +{ + return list_PointerDeleteDuplicates(list_Nconc(List1,List2)); +} + + +LIST list_NUnion(LIST List1, LIST List2, BOOL (*Test)(POINTER, POINTER)) +/************************************************************** + INPUT: Two lists and an equality test for the elements. + RETURNS: Regarding both lists as sets, the union of the sets. + CAUTION: Destructive. +***************************************************************/ +{ + return list_DeleteDuplicates(list_Nconc(List1,List2), Test); +} + + +LIST list_NListTimes(LIST List1, LIST List2) +/************************************************************** + INPUT: Two lists of lists. + RETURNS: The list of combinations of element lists. + CAUTION: Destroys List1 and List2. +***************************************************************/ +{ + LIST Result, Scan1, Scan2; + + Result = list_Nil(); + + if (!list_Empty(List2)) { + for (Scan1=List1; !list_Empty(Scan1); Scan1=list_Cdr(Scan1)) + for (Scan2=List2; !list_Empty(Scan2); Scan2=list_Cdr(Scan2)) + Result = list_Cons(list_Append(((LIST)list_Car(Scan1)), + list_Copy((LIST)list_Car(Scan2))), + Result); + } + list_DeleteWithElement(List1, (void (*)(POINTER))list_Delete); + list_DeleteWithElement(List2, (void (*)(POINTER))list_Delete); + + return Result; +} + + +LIST list_NIntersect(LIST List1, LIST List2, BOOL (*Test)(POINTER, POINTER)) +/************************************************************** + INPUT: Two lists and an equality test for the elements. + RETURNS: Regarding both lists as sets, the intersection of the sets. + CAUTION: Destructive on List1 +***************************************************************/ +{ + LIST Scan1, Scan2; + + while (!list_Empty(List1) && !list_Member(List2, list_Car(List1), Test)) { + Scan1 = list_Cdr(List1); + list_Free(List1); + List1 = Scan1; + } + + if (list_Empty(List1)) + return List1; + + Scan1 = List1; + Scan2 = list_Cdr(List1); + + while (!list_Empty(Scan2)) { + if (list_Member(List2, list_Car(Scan2), Test)) { + Scan2 = list_Cdr(Scan2); + Scan1 = list_Cdr(Scan1); + } + else { + list_Rplacd(Scan1, list_Cdr(Scan2)); + list_Free(Scan2); + Scan2 = list_Cdr(Scan1); + } + } + return List1; +} + + +LIST list_NPointerIntersect(LIST List1, LIST List2) +/************************************************************** + INPUT: Two lists. + RETURNS: Regarding both lists as sets, the intersection of the sets. + CAUTION: Destructive on List1 +***************************************************************/ +{ + LIST Scan1, Scan2; + + while (!list_Empty(List1) && !list_PointerMember(List2, list_Car(List1))) { + Scan1 = list_Cdr(List1); + list_Free(List1); + List1 = Scan1; + } + + if (list_Empty(List1)) + return List1; + + Scan1 = List1; + Scan2 = list_Cdr(List1); + + while (!list_Empty(Scan2)) { + if (list_PointerMember(List2, list_Car(Scan2))) { + Scan2 = list_Cdr(Scan2); + Scan1 = list_Cdr(Scan1); + } + else { + list_Rplacd(Scan1, list_Cdr(Scan2)); + list_Free(Scan2); + Scan2 = list_Cdr(Scan1); + } + } + return List1; +} + + +void list_NInsert(LIST List1, LIST List2) +/************************************************************** + INPUT: Two lists where must not be empty. + EFFECT: is destructively concatenated after + the first element of . + RETURNS: void. + CAUTION: Destructive on List1 and List2. +***************************************************************/ +{ + LIST Help; + +#ifdef CHECK + if (list_Empty(List1)) { + misc_StartErrorReport(); + misc_ErrorReport("\n In list_NInsert: Empty list argument."); + misc_FinishErrorReport(); + } +#endif + + Help = list_Cdr(List1); + list_Rplacd(List1,List2); + List2 = List1; + + while (!list_Empty(list_Cdr(List2))) + List2 = list_Cdr(List2); + + list_Rplacd(List2,Help); +} + + +BOOL list_HasIntersection(LIST List1, LIST List2) +/************************************************************** + INPUT: Two lists . + RETURNS: TRUE iff List1 and List2 have a common element. + EFFECT: The function needs time O(n*m), where n and m are the + lengths of the lists. +***************************************************************/ +{ + LIST Scan; + + if (!list_Empty(List2)) { + for (Scan=List1; !list_Empty(Scan); Scan=list_Cdr(Scan)) + if (list_PointerMember(List2, list_Car(Scan))) + return TRUE; + } + return FALSE; +} + + +LIST list_NPointerDifference(LIST List1, LIST List2) +/************************************************************** + INPUT: Two lists. + RETURNS: The list List1-List2. + CAUTION: Destructive on List1. +***************************************************************/ +{ + LIST Scan; + + if (!list_Empty(List1)) { + for (Scan=List2; !list_Empty(Scan); Scan=list_Cdr(Scan)) + List1 = list_PointerDeleteElement(List1, list_Car(Scan)); + } + return List1; +} + + +LIST list_NDifference(LIST List1, LIST List2, BOOL (*Test)(POINTER, POINTER)) +/************************************************************** + INPUT: Two lists and an equality test for elements. + RETURNS: The list List1-List2 wrt. . + CAUTION: Destructive on List1. +***************************************************************/ +{ + LIST Scan; + + if (!list_Empty(List1)) { + for (Scan=List2; !list_Empty(Scan); Scan=list_Cdr(Scan)) + List1 = list_DeleteElement(List1, list_Car(Scan), Test); + } + return List1; +} + + +LIST list_NMultisetDifference(LIST List1, LIST List2, BOOL (*Test)(POINTER, POINTER)) +/************************************************************** + INPUT: Two lists representing multisets and an equality + test for elements. + RETURNS: The multiset difference List1-List2 wrt. . + CAUTION: Destructive on List1. The memory of deleted + elements is not freed. +***************************************************************/ +{ + LIST scan; + /* Delete equal arguments */ + if (!list_Empty(List1)) { + for (scan = List2; !list_Empty(scan); scan = list_Cdr(scan)) + /* Delete at most one element from List1 equal to */ + /* the actual element of List2. */ + List1 = list_DeleteOneElement(List1, list_Car(scan), Test); + } + return List1; +} + + +BOOL list_PointerReplaceMember(LIST List, POINTER Old, POINTER New) +/************************************************************** + INPUT: A list, a pointer to an old element, a pointer to a new element + RETURNS: TRUE iff was replaced. + EFFECT: The first occurrence of in the list is replaced by . +***************************************************************/ +{ + while (!list_Empty(List)) { + if (Old == list_Car(List)) { + list_Rplaca(List, New); + return TRUE; + } + List = list_Cdr(List); + } + return FALSE; +} + + +void list_DeleteAssocListWithValues(LIST List, void (*ValueDelete)(POINTER)) +/************************************************************** + INPUT: An association list and a delete function for the values. + RETURNS: void. + EFFECT: The assoc list and its values are deleted. +***************************************************************/ +{ + LIST Scan; + + for (Scan=List;!list_Empty(Scan);Scan = list_Cdr(Scan)) { + ValueDelete(list_PairSecond(list_Car(Scan))); + list_PairFree(list_Car(Scan)); + } + + list_Delete(List); +} + + +POINTER list_AssocListValue(LIST List, POINTER Key) +/************************************************************** + INPUT: An association list and a key. + RETURNS: The value for in the list. If is not + contained, NULL. +***************************************************************/ +{ + LIST Scan; + + for (Scan=List;!list_Empty(Scan);Scan = list_Cdr(Scan)) + if (Key == list_PairFirst(list_Car(Scan))) + return list_PairSecond(list_Car(Scan)); + + return NULL; +} + + +LIST list_AssocListPair(LIST List, POINTER Key) +/************************************************************** + INPUT: An association list and a key. + RETURNS: The (. is not + contained, the NULL pair. +***************************************************************/ +{ + LIST Scan; + + for (Scan=List;!list_Empty(Scan);Scan = list_Cdr(Scan)) + if (Key == list_PairFirst(list_Car(Scan))) + return list_Car(Scan); + + return list_PairNull(); +} + + +LIST list_MultisetDistribution(LIST Multiset) +/************************************************************** + INPUT: A list representing a multiset. + RETURNS: The associative list of pairs (.) + representing the distribution of elements in the list. + If the input multiset is empty, the NULL pair. +***************************************************************/ +{ + LIST Distribution; + LIST Scan; + + Distribution = list_PairNull(); + + for (Scan = Multiset; !list_Empty(Scan); Scan = list_Cdr(Scan)) { + LIST Count; + POINTER Element; + int Occurences; + + Element = list_Car(Scan); + Count = list_AssocListPair(Distribution, Element); + + if (Count != list_PairNull()) { + Occurences = (int) list_PairSecond(Count); + list_PairRplacSecond(Count, (POINTER) (Occurences + 1)); + } + else { + Distribution = list_AssocCons(Distribution, Element, (POINTER) 1); + } + } + + return Distribution; +} + + +int list_CompareElementDistribution(LIST LeftPair, LIST RightPair) +/************************************************************** + INPUT: Two lists, representing single element frequency + counts. + RETURNS: 1 if left > right, -1 if left < right, 0 otherwise. + EFFECT: Compares two element frequencies. +***************************************************************/ +{ + if ((int) list_PairSecond(LeftPair) < (int) list_PairSecond(RightPair)) { + return -1; + } + else if ((int) list_PairSecond(LeftPair) > (int) list_PairSecond(RightPair)) { + return 1; + } + + return 0; +} + + +BOOL list_CompareElementDistributionLEQ(LIST LeftPair, LIST RightPair) { +/************************************************************** + INPUT: Two lists, representing single element frequency + counts. + RETURNS: TRUE if left <= right, FALSE otherwise. + EFFECT: Compares two element frequencies. +***************************************************************/ + return (list_CompareElementDistribution(LeftPair, RightPair) <= 0); +} + + +static int list_CompareDistributions(LIST Left, LIST Right) +/************************************************************** + INPUT: Two lists, representing element distributions. + RETURNS: 1 if left > right, -1 if left < right, 0 otherwise. + EFFECT: Compares the two distributions by comparing the + element frequencies from left to right. + CAUTION: Expects the distributions to be sorted. +***************************************************************/ +{ + LIST scan, scan2; + int result; + + result = 0; + + scan = Left; + scan2 = Right; + + /* Compare distributions. */ + + while ( !(list_Empty(scan) || list_Empty(scan2))) { + result = list_CompareElementDistribution(list_Car(scan), list_Car(scan2)); + if (result != 0) { + break; + } + + scan = list_Cdr(scan); + scan2 = list_Cdr(scan2); + } + + /* If the result is 0, and a distribution still + has elements left, it is declared to be greater. + */ + if (result == 0) { + if (list_Empty(scan) && !list_Empty(scan2)) + result = -1; + else if (!list_Empty(scan) && list_Empty(scan2)) + result = 1; + } + + return result; +} + + +int list_CompareMultisetsByElementDistribution(LIST Left, LIST Right) +/************************************************************** + INPUT: Two lists, representing multisets. + RETURNS: 1 if left > right, -1 if left < right, 0 otherwise. + EFFECT: Compares two multisets by counting their element + frequencies, sorting them, and comparing the + resulting multisets over natural numbers. +***************************************************************/ +{ + LIST lmsd, rmsd; /* multiset distributions. */ + int result; + + /* Convert multiset of elements into a + multiset of pairs (element, occurrences). + */ + + lmsd = list_MultisetDistribution(Left); + rmsd = list_MultisetDistribution(Right); + + /* Sort multiset distributions in order + to make them comparable. + */ + + lmsd = list_Sort(lmsd, (BOOL (*) (POINTER, POINTER)) list_CompareElementDistributionLEQ); + rmsd = list_Sort(rmsd, (BOOL (*) (POINTER, POINTER)) list_CompareElementDistributionLEQ); + + result = list_CompareDistributions(lmsd, rmsd); + + list_DeleteDistribution(lmsd); + list_DeleteDistribution(rmsd); + + return result; +} + + +NAT list_Length(LIST List) +/************************************************************** + INPUT: A List. + RETURNS: The number of elements.. + EFFECT: The function needs time O(n), where is the length + of the list. +***************************************************************/ +{ + NAT Result; + + Result = 0; + + while (!list_Empty(List)) { + Result++; + List = list_Cdr(List); + } + + return Result; +} + + +NAT list_Bytes(LIST List) +/************************************************************** + INPUT: A List. + RETURNS: The number of Bytes occupied by the list structure of + EFFECT: the function needs time O(n), where is the length + of the list. +***************************************************************/ +{ + return (list_Length(List)*sizeof(LIST_NODE)); +} -- cgit