/* ******************************************************************************* * * Copyright (C) 2002, International Business Machines * Corporation and others. All Rights Reserved. * ******************************************************************************* * file name: propsvec.c * encoding: US-ASCII * tab size: 8 (not used) * indentation:4 * * created on: 2002feb22 * created by: Markus W. Scherer * * Store additional Unicode character properties in bit set vectors. */ #include #include "unicode/utypes.h" #include "cmemory.h" #include "utrie.h" #include "uprops.h" #include "propsvec.h" static uint32_t * _findRow(uint32_t *pv, uint32_t rangeStart) { uint32_t *row; int32_t columns, i, start, limit; columns=(int32_t)pv[UPVEC_COLUMNS]; limit=(int32_t)pv[UPVEC_ROWS]; pv+=UPVEC_HEADER_LENGTH; /* do a binary search for the start of the range */ start=0; while(start0); } return pv; } U_CFUNC void upvec_close(uint32_t *pv) { if(pv==NULL) { uprv_free(pv); } } U_CFUNC UBool upvec_setValue(uint32_t *pv, uint32_t start, uint32_t limit, int32_t column, uint32_t value, uint32_t mask, UErrorCode *pErrorCode) { uint32_t *firstRow, *lastRow; int32_t columns; UBool splitFirstRow, splitLastRow; /* argument checking */ if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { return FALSE; } if( pv==NULL || start>limit || limit>0x110000 || column<0 || (uint32_t)(column+1)>=pv[UPVEC_COLUMNS] ) { *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; return FALSE; } if(start==limit) { /* empty range, nothing to do */ return TRUE; } /* initialize */ columns=pv[UPVEC_COLUMNS]; column+=2; /* skip range start and limit columns */ value&=mask; /* find the rows whose ranges overlap with the input range */ /* find the first row, always successful */ firstRow=_findRow(pv, start); /* find the last row, always successful */ lastRow=firstRow; while(limit>lastRow[1]) { lastRow+=columns; } /* * Rows need to be split if they partially overlap with the * input range (only possible for the first and last rows) * and if their value differs from the input value. */ splitFirstRow= (UBool)(start!=firstRow[0] && value!=(firstRow[column]&mask)); splitLastRow= (UBool)(limit!=lastRow[1] && value!=(lastRow[column]&mask)); /* split first/last rows if necessary */ if(splitFirstRow || splitLastRow) { int32_t count, rows; rows=(int32_t)pv[UPVEC_ROWS]; if((rows+splitFirstRow+splitLastRow)>(int32_t)pv[UPVEC_MAXROWS]) { *pErrorCode=U_INDEX_OUTOFBOUNDS_ERROR; return FALSE; } /* count the number of row cells to move after the last row, and move them */ count = (int32_t)((pv+UPVEC_HEADER_LENGTH+rows*columns)-(lastRow+columns)); if(count>0) { uprv_memmove( lastRow+(1+splitFirstRow+splitLastRow)*columns, lastRow+columns, count*4); } pv[UPVEC_ROWS]=rows+splitFirstRow+splitLastRow; /* split the first row, and move the firstRow pointer to the second part */ if(splitFirstRow) { /* copy all affected rows up one and move the lastRow pointer */ count = (int32_t)((lastRow-firstRow)+columns); uprv_memmove(firstRow+columns, firstRow, count*4); lastRow+=columns; /* split the range and move the firstRow pointer */ firstRow[1]=firstRow[columns]=start; firstRow+=columns; } /* split the last row */ if(splitLastRow) { /* copy the last row data */ uprv_memcpy(lastRow+columns, lastRow, columns*4); /* split the range and move the firstRow pointer */ lastRow[1]=lastRow[columns]=limit; } } /* set the input value in all remaining rows */ firstRow+=column; lastRow+=column; mask=~mask; for(;;) { *firstRow=(*firstRow&mask)|value; if(firstRow==lastRow) { break; } firstRow+=columns; } return TRUE; } U_CFUNC uint32_t * upvec_getRow(uint32_t *pv, int32_t rowIndex, uint32_t *pRangeStart, uint32_t *pRangeLimit) { uint32_t *row; int32_t columns; if(pv==NULL || rowIndex<0 || rowIndex>=(int32_t)pv[UPVEC_ROWS]) { return NULL; } columns=pv[UPVEC_COLUMNS]; row=pv+UPVEC_HEADER_LENGTH+rowIndex*columns; if(pRangeStart!=NULL) { *pRangeStart=row[0]; } if(pRangeLimit!=NULL) { *pRangeLimit=row[1]; } return row+2; } static int upvec_compareRows(const void *l, const void *r) { const uint32_t *left=(const uint32_t *)l, *right=(const uint32_t *)r; int32_t i, count, columns; count=columns=2+UPROPS_VECTOR_WORDS; /* start comparing after start/limit but wrap around to them */ i=2; do { if(left[i]!=right[i]) { return left[i]0); return 0; } U_CFUNC int32_t upvec_toTrie(uint32_t *pv, UNewTrie *trie, UErrorCode *pErrorCode) { uint32_t *row; int32_t columns, valueColumns, rows, count; /* argument checking */ if(pErrorCode==NULL || U_FAILURE(*pErrorCode)) { return 0; } if(pv==NULL || trie==NULL) { *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR; return 0; } row=pv+UPVEC_HEADER_LENGTH; columns=(int32_t)pv[UPVEC_COLUMNS]; rows=(int32_t)pv[UPVEC_ROWS]; /* sort the properties vectors to find unique vector values */ if(rows>1) { qsort(pv+UPVEC_HEADER_LENGTH, rows, columns*4, upvec_compareRows); } /* * Move vector contents up to a contiguous array with only unique * vector values, and set indexes to those values into the trie. * * This destroys the Properties Vector structure and replaces it * with an array of just vector values. */ valueColumns=columns-2; /* not counting start & limit */ count=-valueColumns; do { /* add a new values vector if it is different from the current one */ if(count<0 || 0!=uprv_memcmp(row+2, pv+count, valueColumns*4)) { count+=valueColumns; uprv_memmove(pv+count, row+2, valueColumns*4); } if(count>0 && !utrie_setRange32(trie, (UChar32)row[0], (UChar32)row[1], (uint32_t)count, FALSE)) { *pErrorCode=U_BUFFER_OVERFLOW_ERROR; return 0; } row+=columns; } while(--rows>0); return count+valueColumns; }