/* * Routines for Set Instance Values * by Tom Epperly * 12/4/89 * Version: $Revision: 1.9 $ * Version control file: $RCSfile: setinstval.c,v $ * Date last modified: $Date: 1998/02/05 16:37:50 $ * Last modified by: $Author: ballan $ * * This file is part of the Ascend Language Interpreter. * * Copyright (C) 1990, 1993, 1994 Thomas Guthrie Epperly * * The Ascend Language Interpreter 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. * * The Ascend Language Interpreter is distributed in 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, see . */ #include #include #include #include #include #include #include "symtab.h" #include "instance_enum.h" #include "cmpfunc.h" #include "setinstval.h" #define MYMIN(x,y) (((x)<(y)) ? (x) : (y)) #ifdef ASC_NO_POOL #define SETINST_USES_POOL FALSE #else #define SETINST_USES_POOL TRUE #endif static pool_store_t g_set_pool=NULL; /* * A pool_store for all the sets ever simultaneously in use. */ #define SM_LEN 2 #if (SIZEOF_VOID_P == 8) #define SM_WID 63 #else #define SM_WID 126 #endif /* retune if the size of set stub changes dramatically */ #define SM_ELT_SIZE (sizeof(struct set_t)) #define SM_MORE_ELTS 1 /* Number of slots filled if more elements needed. * So if the pool grows, it grows by SM_MORE_ELTS*SM_WID elements at a time. */ #define SM_MORE_BARS 10 /* This is the number of pool bar slots to add during expansion. * not all the slots will be filled immediately. */ void InitSetManager(void) { #if SETINST_USES_POOL if (g_set_pool != NULL ) { ASC_PANIC("ERROR: InitSetManager called twice.\n"); } g_set_pool = pool_create_store(SM_LEN, SM_WID, SM_ELT_SIZE, SM_MORE_ELTS, SM_MORE_BARS); if (g_set_pool == NULL) { ASC_PANIC("ERROR: InitSetManager unable to allocate pool.\n"); } #endif } void DestroySetManager(void) { #if SETINST_USES_POOL assert(g_set_pool!=NULL); pool_destroy_store(g_set_pool); g_set_pool = NULL; #endif } void ReportSetManager(FILE *f) { #if SETINST_USES_POOL assert(g_set_pool!=NULL); FPRINTF(f,"SetManager "); pool_print_store(f,g_set_pool,0); #else FPRINTF(f,"SetManager pool not used."); #endif } #if SETINST_USES_POOL #define MALLOCSET(x) (x = (struct set_t *)pool_get_element(g_set_pool)) #define FREESET(set) pool_free_element(g_set_pool,(set)) #else #define MALLOCSET(x) x = ASC_NEW(struct set_t) #define FREESET(set) ascfree(set) #endif /* SETINST_USES_POOL */ static int SetIntCmp(long int i1, long int i2) { if (i1==i2) return 0; if (i1kind = empty_set; result->list = NULL; return result; } static void StringViolation(CONST char *name) { Asc_Panic(2, NULL, "Integer set routine %s called with string set argument.\n", name); } static void IntegerViolation(CONST char *name) { Asc_Panic(2, NULL, "String set routine %s called with integer set argument.\n", name); } void InsertInteger(struct set_t *set, asc_intptr_t i){ assert(set&&((set->kind==integer_set)||(set->kind==empty_set))); if(set->kind==empty_set) set->kind = integer_set; else if (set->kind==string_set) StringViolation("InsertInteger"); if(set->list==NULL) { set->list = gl_create(5L); gl_insert_sorted(set->list,(VOIDPTR)i,(CmpFunc)SetIntCmp); }else{ if(gl_search(set->list,(VOIDPTR)i,(CmpFunc)SetIntCmp)==0) gl_insert_sorted(set->list,(VOIDPTR)i,(CmpFunc)SetIntCmp); } } void InsertString(struct set_t *set, symchar *str){ assert(AscFindSymbol(str)!=NULL); assert(set&&((set->kind==string_set)||(set->kind==empty_set))); if(set->kind==empty_set) set->kind = string_set; else if(set->kind==integer_set) IntegerViolation("InsertString"); if(set->list==NULL){ set->list = gl_create(5L); gl_insert_sorted(set->list,(VOIDPTR)str,(CmpFunc)SetStrCmp); }else{ if (gl_search(set->list,str,(CmpFunc)SetStrCmp)==0) gl_insert_sorted(set->list,(VOIDPTR)str,(CmpFunc)SetStrCmp); } } void InsertIntegerRange(struct set_t *set, long int lower, long int upper) { register long i; assert(set&&((set->kind==integer_set)||(set->kind==empty_set))); for(i=lower;i<=upper;InsertInteger(set,i++)); } struct set_t *SetUnion(CONST struct set_t *s1, CONST struct set_t *s2) { struct set_t *result; register unsigned long c1,l1,c2,l2; register int cmp; CmpFunc func; assert(s1&&s2); if (s1->kind==empty_set) return CopySet(s2); if (s2->kind==empty_set) return CopySet(s1); assert(s1->kind==s2->kind); if (s1->list==NULL) { if (s2->list==NULL) { MALLOCSET(result); result->kind = s1->kind; result->list = NULL; return result; } return CopySet(s2); } if (s2->list==NULL) return CopySet(s1); /* prepare for union */ c1=c2=1; l1=gl_length(s1->list); l2=gl_length(s2->list); MALLOCSET(result); result->kind = s1->kind; if ((l1==0)&&(l2==0)) { result->list = NULL; return result; } result->list = gl_create(l1+l2); if (s1->kind == integer_set) func = (CmpFunc)SetIntCmp; else func = (CmpFunc)SetStrCmp; while((c1<=l1)||(c2<=l2)) { if (c1>l1) gl_append_ptr(result->list,gl_fetch(s2->list,c2++)); else if (c2>l2) gl_append_ptr(result->list,gl_fetch(s1->list,c1++)); else { cmp = (*func)(gl_fetch(s1->list,c1),gl_fetch(s2->list,c2)); if (cmp<0) gl_append_ptr(result->list,gl_fetch(s1->list,c1++)); else if (cmp>0) gl_append_ptr(result->list,gl_fetch(s2->list,c2++)); else { /* equal */ gl_append_ptr(result->list,gl_fetch(s1->list,c1++)); c2++; } } } gl_sort(result->list,func); return result; } struct set_t *SetIntersection(CONST struct set_t *s1, CONST struct set_t *s2) { struct set_t *result; register unsigned long c1,l1,c2,l2; register int cmp; CmpFunc func; assert(s1&&s2); if (s1->kind==empty_set) return CreateEmptySet(); if (s2->kind==empty_set) return CreateEmptySet(); assert(s1->kind==s2->kind); if ((s1->list==NULL)||(s2->list==NULL)){ MALLOCSET(result); result->kind = s1->kind; result->list = NULL; return result; } /* prepare for intersection */ c1=c2=1; l1=gl_length(s1->list); l2=gl_length(s2->list); MALLOCSET(result); result->kind = s1->kind; if ((l1==0)&&(l2==0)) { result->list = NULL; return result; } result->list = gl_create(MYMIN(l1,l2)); if (s1->kind == integer_set) func = (CmpFunc)SetIntCmp; else func = (CmpFunc)SetStrCmp; while((c1<=l1)&&(c2<=l2)) { cmp = (*func)(gl_fetch(s1->list,c1),gl_fetch(s2->list,c2)); if (cmp<0) c1++; else if (cmp>0) c2++; else { /* equal */ gl_append_ptr(result->list,gl_fetch(s1->list,c1++)); c2++; } } gl_sort(result->list,func); return result; } struct set_t *SetDifference(CONST struct set_t *s1, CONST struct set_t *s2) { struct set_t *result; register unsigned long c1,l1,c2,l2; register int cmp; CmpFunc func; assert(s1&&s2); if (s1->kind==empty_set) return CreateEmptySet(); if (s2->kind==empty_set) return CopySet(s1); assert(s1->kind==s2->kind); if ((s1->list==NULL)||(s2->list==NULL)||(gl_length(s2->list)==0)|| (gl_length(s1->list)==0)) return CopySet(s1); /* prepare for difference */ c1=c2=1; l1=gl_length(s1->list); l2=gl_length(s2->list); MALLOCSET(result); result->kind = s1->kind; result->list = gl_create(l1); if (s1->kind == integer_set) func = (CmpFunc)SetIntCmp; else func = (CmpFunc)SetStrCmp; while(c1<=l1) { if (c2>l2) gl_append_ptr(result->list,gl_fetch(s1->list,c1++)); else { cmp = (*func)(gl_fetch(s1->list,c1),gl_fetch(s2->list,c2)); if (cmp<0) gl_append_ptr(result->list,gl_fetch(s1->list,c1++)); else if (cmp>0) c2++; else { /* equal */ c1++; c2++; } } } gl_sort(result->list,func); return result; } struct set_t *CopySet(CONST struct set_t *set) { register struct set_t *result; assert(set!=NULL); MALLOCSET(result); result->kind = set->kind; if (set->list!=NULL) result->list = gl_copy(set->list); else result->list = NULL; return result; } int IntMember(asc_intptr_t i, CONST struct set_t *set) { assert(set&&((set->kind==integer_set)||(set->kind==empty_set))); if (set->list==NULL) return 0; return (gl_search(set->list,(VOIDPTR)i,(CmpFunc)SetIntCmp)!=0); } int StrMember(symchar *str, CONST struct set_t *set){ assert(set&&((set->kind==string_set)||(set->kind==empty_set))); if (set->list==NULL) return 0; assert(AscFindSymbol(str)!=NULL); return (gl_search(set->list,str,(CmpFunc)SetStrCmp)!=0); } void DestroySet(struct set_t *set) { if (set!=NULL) { if (set->list!=NULL) gl_destroy(set->list); set->list=NULL; FREESET(set); } } int NullSet(CONST struct set_t *s) { assert(s!=NULL); return (s->list==NULL)||(gl_length(s->list)==0); } unsigned long Cardinality(CONST struct set_t *s) { assert(s!=NULL); if (s->list==NULL) return 0; else return gl_length(s->list); } symchar *FetchStrMember(CONST struct set_t *s, unsigned long int i) { assert(s&&s->list&&(s->kind==string_set)); return gl_fetch(s->list,i); } asc_intptr_t FetchIntMember(CONST struct set_t *s, unsigned long int i){ assert(s&&s->list&&(s->kind==integer_set)); return (asc_intptr_t)gl_fetch(s->list,i); } void SetIterate(struct set_t *s, void (*func) (/* ??? */)) { assert(s!=NULL); if (s->list!=NULL) gl_iterate(s->list,(IterateFunc)func); } enum set_kind SetKind(CONST struct set_t *s) { assert(s!=NULL); return s->kind; } int SetsEqual(CONST struct set_t *s1, CONST struct set_t *s2) { register unsigned long c,length; assert(s1&&s2); if (s1->kind!=s2->kind) return 0; if (s1->list==NULL) { if ((s2->list==NULL)||(gl_length(s2->list)==0)) return 1; else return 0; } if (s2->list==NULL){ if (gl_length(s1->list)==0) return 1; else return 0; } length = gl_length(s1->list); if (length != gl_length(s2->list)) return 0; if (s1->kind == integer_set) { for(c=1;c<=length;c++) { if ((asc_intptr_t)gl_fetch(s1->list,c) != (asc_intptr_t)gl_fetch(s2->list,c)) return 0; } }else{ /* symbol set */ for(c=1;c<=length;c++) { if (gl_fetch(s1->list,c) != gl_fetch(s2->list,c)) return 0; } } return 1; } int Subset(CONST struct set_t *s1, CONST struct set_t *s2) { register asc_intptr_t c1,c2,length1,length2; assert(s1&&s2); if (s1->kind==empty_set) return 1; if (s2->kind==empty_set) return 0; if (s1->kind!=s2->kind) return 0; if ((s1->list==NULL)||(gl_length(s1->list)==0)) return 1; if (s2->list==NULL) return 0; length1=gl_length(s1->list); length2=gl_length(s2->list); if (length1>length2) return 0; c1=c2=1; if (s1->kind == integer_set) { register long i1,i2; while((c1<=length1)&&(c2<=length2)) { i1 = (asc_intptr_t)gl_fetch(s1->list,c1); i2 = (asc_intptr_t)gl_fetch(s2->list,c2); if (i1 == i2) { c1++; c2++; }else if (i1 < i2) return 0; else c2++; } } else { register char *str1,*str2; register int cmp; while((c1<=length1)&&(c2<=length2)) { str1 = gl_fetch(s1->list,c1); str2 = gl_fetch(s2->list,c2); cmp = strcmp(str1,str2); if (cmp==0) { c1++; c2++; }else if (cmp<0) return 0; else c2++; } } if (c1>length1) return 1; else return 0; } int CmpSetInstVal(CONST struct set_t *s1, CONST struct set_t *s2) { unsigned long c,len; symchar *str1, *str2; int cmp; if (s1==s2) { return 0; } if (s1==NULL) { return -1; } if (s2==NULL) { return 1; } if (s1->kind == empty_set) { return -1; } if (s2->kind == empty_set) { return 1; } if (SetKind(s1)!=SetKind(s2)) { return (SetKind(s1)==integer_set) ? 1 : -1; } if (gl_length(s1->list) != gl_length(s2->list)) { return (gl_length(s1->list) < gl_length(s2->list)) ? 1 : -1; } len = gl_length(s1->list); if (s1->kind == integer_set) { for (c = 1; c <= len; c++) { if (gl_fetch(s1->list,c) != gl_fetch(s2->list,c)) { return (gl_fetch(s1->list,c) < gl_fetch(s2->list,c)) ? 1 : -1; } } } else { for (c = 1; c <= len; c++) { str1 = gl_fetch(s1->list,c); str2 = gl_fetch(s2->list,c); cmp = CmpSymchar(str1,str2); if (cmp!=0) { return cmp; } } } return 0; } /*********************************************************************\ Some ordered set processing. The elements of the below sets are not necessarily unique and not necessarily ordered. In this way they behave more like lists. \*********************************************************************/ void AppendIntegerElement(struct set_t *set, asc_intptr_t i){ assert(set&&((set->kind==integer_set)||(set->kind==empty_set))); if(set->kind==empty_set) set->kind = integer_set; else if(set->kind==string_set) StringViolation("InsertInteger"); if(set->list==NULL) { set->list = gl_create(5L); gl_append_ptr(set->list,(VOIDPTR)i); } else { gl_append_ptr(set->list,(VOIDPTR)i); } } void AppendStringElement(struct set_t *set, symchar *str) { assert(set&&((set->kind==string_set)||(set->kind==empty_set))); assert(AscFindSymbol(str)!=NULL); if(set->kind==empty_set) set->kind = string_set; else if(set->kind==integer_set) IntegerViolation("InsertString"); if (set->list==NULL){ set->list = gl_create(5L); gl_append_ptr(set->list,(VOIDPTR)str); } else { gl_append_ptr(set->list,(VOIDPTR)str); } }