/* File: lexalpha.c * Author: Jean Thierry-Mieg (mieg@kaa.crbm.cnrs-mop.fr) * Copyright (C) J Thierry-Mieg and R Durbin, 1994 * ------------------------------------------------------------------- * Acedb 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. * or see the on-line version at http://www.gnu.org/copyleft/gpl.txt * ------------------------------------------------------------------- * This file is part of the ACEDB genome database package, written by * Richard Durbin (MRC LMB, UK) rd@mrc-lmba.cam.ac.uk, and * Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr * * Description: * Exported functions: * HISTORY: * Last edited: Jul 9 11:28 2003 (rnc) * * Sep 1 23:24 1998 (rd): restructure keySetAlphaHeap() a bit * remove keySetCopy if keySetmax == 1 - not correct if key not visible * follow aliases if keySetMax() < LIMIT ; this always happened if > LIMIT * because lexSetStatus() follows aliases. Also it is desirable. * for > LIMIT, transfer responsibility for lexIsVisibleKey() check to * alphaMake(), and change key names to avoid errors on old caches. * This is cleaner, and more efficient. * alphaMake() always makes a keyset - safer, free, and perhaps needed now * added lexMaxVisible() for command.c * Created: Tue Nov 22 11:34:29 1994 (mieg) *------------------------------------------------------------------- */ /* $Id: lexalpha.c,v 1.45 2003/07/09 13:20:59 rnc Exp $ */ #define LIMIT 300 #define MAXCLASS 256 #include "acedb.h" #include "lex.h" #include "a.h" #include "whooks/sysclass.h" #include "pick.h" #include "utils.h" static KEYSET alphaSet[MAXCLASS] ; static void alphaGet(int c) ; static int classAlphaOrder (void *a, void *b) { int c1 = *(int*)a , c2 = *(int*) b ; return lexstrcmp (className(KEYMAKE(c1, 0)), className(KEYMAKE(c2,0))) ; } /* return the alphabetic first nn keys of ks */ KEYSET lexAlphaClassList (BOOL redo) { static KEYSET ks = 0 ; int i ; if (redo) keySetDestroy (ks) ; if (!ks) { ks = keySetCreate () ; i = MAXCLASS ; while (i--) keySet(ks, i) = i ; arraySort (ks, classAlphaOrder) ; } return ks ; } KEYSET keySetAlphaHeap (KEYSET ks, int nn) { char ff[MAXCLASS] ; /* flags the class present in ks */ int i, c , c1, j ; KEYSET ksa ; KEY *kp, *kpa, k ; KEYSET alphaClassList ; if (!keySetExists(ks)) return 0 ; /* may be messcrash ? */ if (keySetMax(ks) == 0 || nn == 0) /* nothing to sort */ return keySetCreate(); /* return empty keyset */ memset(ff, 0, MAXCLASS) ; if (keySetMax(ks) < LIMIT) /* do directly */ { ksa = arrayCreate (keySetMax(ks), KEY) ; keySet (ksa, keySetMax(ks)) = 0 ; /* make room, is that needed after arrayCreate ? */ /* follow aliases and remove invisible keys */ kp = arrp (ks, 0, KEY) - 1 ; i = keySetMax (ks) ; j = 0 ; while (kp++, i--) { k = lexAliasOf(*kp) ; /* follow aliases */ if (lexIsKeyVisible(k)) arr (ksa, j++,KEY) = k ; /* use a macro, space is guaranteed */ } keySetMax(ksa) = j ; /* then sort and return */ arraySort(ksa,keySetAlphaOrder) ; arrayCompress (ksa) ; /* avoid duplicates */ return ksa ; } /* keySetMax > LIMIT set flags and then loop through presorted keysets = alphaSet[c] */ kp = arrp (ks, 0, KEY) ; for (i = keySetMax(ks) ; i-- ; ++kp) { c = class(*kp) ; if (!ff[c]) { ff[c] = 1 ; lexClearClassStatus(c, ALPHASTATUS) ; } if (*kp) /* michel, dec 98 avoid *kp = 0 */ lexSetStatus (*kp, ALPHASTATUS) ; /* does follow aliases */ else /* messcrash ("bad key 0") */ ; /* RD 990107: should messcrash really */ } if (nn > keySetMax(ks)) nn = keySetMax(ks) ; ksa = arrayCreate (nn, KEY) ; keySet(ksa, nn - 1) = 0 ; /* make room */ kpa = arrp(ksa, 0, KEY) ; j = 0 ; alphaClassList = lexAlphaClassList (FALSE) ; for (c1 = 0 ; c1 < MAXCLASS ; c1++) { c = keySet(alphaClassList, c1) ; if (ff[c]) { alphaGet(c) ; /* creates alphaSet */ kp = arrp(alphaSet[c], 0, KEY) ; for (i = keySetMax (alphaSet[c]) ; i-- ; ++kp) if ((lexGetStatus(*kp) & ALPHASTATUS)) { *kpa++ = *kp ; if (++j == nn) goto ok ; /* break all loops */ } } } ok: keySetMax(ksa) = j ; return ksa ; } /******************************************/ /******************************************/ static BOOL firstPass = TRUE ; static char isMarked[MAXCLASS] ; /* class changed - rebuild needed */ static char isTouched[MAXCLASS] ; /* lexalpha changed - needs saving */ static void alphaMake (int c) { int i, max = lexMax(c) ; KEYSET ks ; KEY kk, *kp ; if (max) { /* make a keySet of visible keys in the class */ ks = arrayCreate (max, KEY) ; keySet(ks, max - 1) = 0 ; /* make space */ for (i = max, kp = arrp(ks, 0, KEY), kk = KEYMAKE(c,0) ; i-- ; kk++) if (lexIsKeyVisible (kk)) *kp++ = kk ; keySetMax(ks) = kp - arrp(ks,0,KEY) ; /* sort it */ arraySort (ks, keySetAlphaOrder) ; } else ks = keySetCreate() ; /* make an empty keyset */ keySetDestroy (alphaSet[c]) ; alphaSet[c] = ks ; isTouched[c] = 1 ; isMarked[c] = 0; } /***********************/ static void alphaRead (int c) { KEY key ; lexaddkey(messprintf("_lexalpha%d",c), &key, _VVoc) ; alphaSet [c] = arrayGet (key, KEY, "k") ; isTouched [c] = 0 ; } /***********************/ static void alphaGet (int c) { int i ; if (firstPass) { firstPass = FALSE ; i = MAXCLASS ; while (i--) { isTouched[i] = 0 ; isMarked [i] = 0 ; alphaSet[i] = 0 ; } } if (isMarked[c]) /* obsolete on disk */ alphaMake (c) ; else { if (!alphaSet[c]) alphaRead (c) ; if (!alphaSet[c]) alphaMake (c) ; } } /***********************/ /***********************/ void lexAlphaMakeAll (void) { int c = MAXCLASS ; while (c--) if (lexMax(c)) alphaMake (c) ; } /***********************/ void lexAlphaSaveAll (void) { int c = MAXCLASS ; KEY key ; KEYSET ks ; while (c--) { lexaddkey(messprintf("_lexalpha%d",c), &key, _VVoc) ; /* rd - must call lexaddkey() before isMarked[], else on c == _VVoc it can change the value !!!! */ if (isMarked[c]) alphaMake (c) ; ks = alphaSet [c] ; if (ks && isTouched [c]) { arrayStore (key, ks, "k") ; isTouched[c] = 0 ; } } } /***********************/ void lexAlphaMark (int c) { if (firstPass) { int i = MAXCLASS ; firstPass = FALSE ; while (i--) { isTouched[i] = 0 ; isMarked [i] = 0 ; alphaSet[i] = 0 ; } } if (c >= 0 && c < MAXCLASS) isMarked [c] = 1 ; /* RD 980901 - no need to destroy here and potentially bad for lexAlphaIterator*() */ } /***********************/ void lexAlphaClear (void) { int i = MAXCLASS ; while (i--) { isTouched[i] = 0 ; isMarked [i] = 0 ; if (keySetExists(alphaSet[i])) keySetDestroy (alphaSet[i]) ; } } /***********************/ int lexMaxVisible (int c) { alphaGet(c) ; return keySetMax(alphaSet[c]) ; } /***********************/ /***********************/ #ifdef LEX_ALPHA_ITERATOR /* needs more work */ struct LexAlphaIteratorStruct { int c ; int i ; unsigned char mask ; } ; LexAlphaIterator *lexAlphaIteratorCreate (KEY classe, STORE_HANDLE h) { LexAlphaIterator lat ; unsigned char mask ; if (!pickIsA (&classe, &mask)) return 0 ; lat = (LexAlphaIterator) halloc (sizeof(LexAlphaIteratorStruct), h) ; lat->c = classe ; lat->i = -1 ; lat->mask = mask ; alphaGet(lat->c) ; return lat ; } KEY lexAlphaIteratorNext (LexAlphaIterator lat) { KEY k ; if (!alphaSet[lat->c]) messcrash ("lost alphaSet[%s] in lexAlphaIteratorNext()", pickClass2Word(lat->c)) ; while (TRUE) { ++lat->i ; if (lat->i >= arrayMax(alphaSet[lat->c])) return 0 ; k = arr(alphaSet[lat->c],i,KEY) ; if (!mask || mask == (mask & q->isMask)) /* q is private to lexsubs4! */ return k ; } return 0 ; /* for compiler happiness */ } #endif /***********************/ int keySetCountVisible (KEYSET kset) { int max=0, i ; if (kset && keySetMax(kset)) { KEY *kp = arrp (kset, 0, KEY) - 1 ; i = keySetMax(kset) ; while (kp++, i--) if (lexIsKeyVisible(*kp)) max++ ; } return max; } /***********************/ /***********************/ int keyNamesAverage (KEYSET kSet, int *goodEntries) { int length = 0; char *cp ; int i; *goodEntries = 0; /* count the number of usable items in this list and determine the average length for names in the list */ if (kSet) { KEY *kp = arrp (kSet, 0, KEY) ; i = keySetMax(kSet) ; while (kp && i--) { if (lexIsKeyVisible(*kp)) { *goodEntries += 1 ; cp = 0 ; if (nextName (*kp, &cp) && *cp != '\177') length += strlen (cp); } kp++; } if (*goodEntries) length = length / *goodEntries; } return length; } /*********************** end of file *********************/