scuffed-code/icu4c/source/common/ucmp8.c
Helena Chapman aedb933f7e ICU-163 Fixed warnings on MSVC 6.0.
X-SVN-Rev: 476
1999-12-29 22:33:47 +00:00

435 lines
12 KiB
C

/*
********************************************************************
* COPYRIGHT:
* Copyright (c) 1997-1999, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************
*/
#ifndef _STDLIB_H
#include <stdlib.h>
#endif
#ifndef _STDIO_H
#include <stdio.h>
#endif
#include "ucmp8.h"
#include "cmemory.h"
static int32_t findOverlappingPosition(CompactByteArray* this_obj,
uint32_t start,
const UChar *tempIndex,
int32_t tempIndexCount,
uint32_t cycle);
/* internal constants*/
int32_t ucmp8_getkUnicodeCount() { return UCMP8_kUnicodeCount;}
int32_t ucmp8_getkBlockCount() { return UCMP8_kBlockCount;}
/* debug flags*/
/*=======================================================*/
CompactByteArray* ucmp8_open(int8_t defaultValue)
{
/* set up the index array and the data array.
* the index array always points into particular parts of the data array
* it is initially set up to point at regular block boundaries
* The following example uses blocks of 4 for simplicity
* Example: Expanded
* INDEX# 0 1 2 3 4
* INDEX 0 4 8 12 16 ...
* ARRAY abcdeababcedzyabcdea...
* | | | | | |...
* whenever you set an element in the array, it unpacks to this state
* After compression, the index will point to various places in the data array
* wherever there is a runs of the same elements as in the original
* Example: Compressed
* INDEX# 0 1 2 3 4
* INDEX 0 4 1 8 2 ...
* ARRAY abcdeabazyabc...
* If you look at the example, index# 2 in the expanded version points
* to data position number 8, which has elements "bced". In the compressed
* version, index# 2 points to data position 1, which also has "bced"
*/
CompactByteArray* this_obj = (CompactByteArray*) uprv_malloc(sizeof(CompactByteArray));
int32_t i;
if (this_obj == NULL) return NULL;
this_obj->fStructSize = sizeof(CompactByteArray);
this_obj->fArray = NULL;
this_obj->fIndex = NULL;
this_obj->fCount = UCMP8_kUnicodeCount;
this_obj->fCompact = FALSE;
this_obj->fBogus = FALSE;
this_obj->fAlias = FALSE;
this_obj->fArray = (int8_t*) uprv_malloc(sizeof(int8_t) * UCMP8_kUnicodeCount);
if (!this_obj->fArray)
{
this_obj->fBogus = TRUE;
return NULL;
}
this_obj->fIndex = (uint16_t*) uprv_malloc(sizeof(uint16_t) * UCMP8_kIndexCount);
if (!this_obj->fIndex)
{
uprv_free(this_obj->fArray);
this_obj->fArray = NULL;
this_obj->fBogus = TRUE;
return NULL;
}
for (i = 0; i < UCMP8_kUnicodeCount; ++i)
{
this_obj->fArray[i] = defaultValue;
}
for (i = 0; i < UCMP8_kIndexCount; ++i)
{
this_obj->fIndex[i] = (uint16_t)(i << UCMP8_kBlockShift);
}
return this_obj;
}
CompactByteArray* ucmp8_openAdopt(uint16_t *indexArray,
int8_t *newValues,
int32_t count)
{
CompactByteArray* this_obj = (CompactByteArray*) uprv_malloc(sizeof(CompactByteArray));
if (!this_obj) return NULL;
this_obj->fArray = NULL;
this_obj->fIndex = NULL;
this_obj->fCount = count;
this_obj->fBogus = FALSE;
this_obj->fStructSize = sizeof(CompactByteArray);
this_obj->fArray = newValues;
this_obj->fIndex = indexArray;
this_obj->fCompact = (count < UCMP8_kUnicodeCount) ? TRUE : FALSE;
this_obj->fAlias = FALSE;
return this_obj;
}
CompactByteArray* ucmp8_openAlias(uint16_t *indexArray,
int8_t *newValues,
int32_t count)
{
CompactByteArray* this_obj = (CompactByteArray*) uprv_malloc(sizeof(CompactByteArray));
if (!this_obj) return NULL;
this_obj->fArray = NULL;
this_obj->fIndex = NULL;
this_obj->fCount = count;
this_obj->fBogus = FALSE;
this_obj->fStructSize = sizeof(CompactByteArray);
this_obj->fArray = newValues;
this_obj->fIndex = indexArray;
this_obj->fCompact = (count < UCMP8_kUnicodeCount) ? TRUE : FALSE;
this_obj->fAlias = TRUE;
return this_obj;
}
/*=======================================================*/
void ucmp8_close(CompactByteArray* this_obj)
{
if(this_obj != NULL) {
if(!this_obj->fAlias) {
if(this_obj->fArray != NULL) {
uprv_free(this_obj->fArray);
}
if(this_obj->fIndex != NULL) {
uprv_free(this_obj->fIndex);
}
}
uprv_free(this_obj);
}
}
/*=======================================================*/
void ucmp8_expand(CompactByteArray* this_obj)
{
/* can optimize later.
* if we have to expand, then walk through the blocks instead of using Get
* this code unpacks the array by copying the blocks to the normalized position.
* Example: Compressed
* INDEX# 0 1 2 3 4
* INDEX 0 4 1 8 2 ...
* ARRAY abcdeabazyabc...
* turns into
* Example: Expanded
* INDEX# 0 1 2 3 4
* INDEX 0 4 8 12 16 ...
* ARRAY abcdeababcedzyabcdea...
*/
int32_t i;
if (this_obj->fCompact)
{
int8_t* tempArray;
tempArray = (int8_t*) uprv_malloc(sizeof(int8_t) * UCMP8_kUnicodeCount);
if (!tempArray)
{
this_obj->fBogus = TRUE;
return;
}
for (i = 0; i < UCMP8_kUnicodeCount; ++i)
{
tempArray[i] = ucmp8_get(this_obj,(UChar)i); /* HSYS : How expand?*/
}
for (i = 0; i < UCMP8_kIndexCount; ++i)
{
this_obj->fIndex[i] = (uint16_t)(i<< UCMP8_kBlockShift);
}
uprv_free(this_obj->fArray);
this_obj->fArray = tempArray;
this_obj->fCompact = FALSE;
this_obj->fAlias = FALSE;
}
}
/*=======================================================*/
/* this_obj->fArray: an array to be overlapped
* start and count: specify the block to be overlapped
* tempIndex: the overlapped array (actually indices back into inputContents)
* inputHash: an index of hashes for tempIndex, where
* inputHash[i] = XOR of values from i-count+1 to i
*/
int32_t
findOverlappingPosition(CompactByteArray* this_obj,
uint32_t start,
const UChar* tempIndex,
int32_t tempIndexCount,
uint32_t cycle)
{
/* this_obj is a utility routine for finding blocks that overlap.
* IMPORTANT: the cycle number is very important. Small cycles take a lot
* longer to work. In some cases, they may be able to get better compaction.
*/
int32_t i;
int32_t j;
int32_t currentCount;
for (i = 0; i < tempIndexCount; i += cycle)
{
currentCount = UCMP8_kBlockCount;
if (i + UCMP8_kBlockCount > tempIndexCount)
{
currentCount = tempIndexCount - i;
}
for (j = 0; j < currentCount; ++j)
{
if (this_obj->fArray[start + j] != this_obj->fArray[tempIndex[i + j]]) break;
}
if (j == currentCount) break;
}
return i;
}
bool_t
ucmp8_isBogus(const CompactByteArray* this_obj)
{
return this_obj == NULL || this_obj->fBogus;
}
const int8_t*
ucmp8_getArray(const CompactByteArray* this_obj)
{
return this_obj->fArray;
}
const uint16_t*
ucmp8_getIndex(const CompactByteArray* this_obj)
{
return this_obj->fIndex;
}
int32_t
ucmp8_getCount(const CompactByteArray* this_obj)
{
return this_obj->fCount;
}
void
ucmp8_set(CompactByteArray* this_obj,
UChar c,
int8_t value)
{
if (this_obj->fCompact == TRUE)
{
ucmp8_expand(this_obj);
if (this_obj->fBogus) return;
}
this_obj->fArray[(int32_t)c] = value;
}
void
ucmp8_setRange(CompactByteArray* this_obj,
UChar start,
UChar end,
int8_t value)
{
int32_t i;
if (this_obj->fCompact == TRUE)
{
ucmp8_expand(this_obj);
if (this_obj->fBogus) return;
}
for (i = start; i <= end; ++i)
{
this_obj->fArray[i] = value;
}
}
/*=======================================================*/
void
ucmp8_compact(CompactByteArray* this_obj,
uint32_t cycle)
{
if (!this_obj->fCompact)
{
/* this_obj actually does the compaction.
* it walks throught the contents of the expanded array, finding the
* first block in the data that matches the contents of the current index.
* As it works, it keeps an updated pointer to the last position,
* so that it knows how big to make the final array
* If the matching succeeds, then the index will point into the data
* at some earlier position.
* If the matching fails, then last position pointer will be bumped,
* and the index will point to that last block of data.
*/
UChar* tempIndex;
int32_t tempIndexCount;
int8_t* tempArray;
int32_t iBlock, iIndex;
/* fix cycle, must be 0 < cycle <= blockcount*/
if (cycle < 0) cycle = 1;
else if (cycle > (uint32_t)UCMP8_kBlockCount) cycle = UCMP8_kBlockCount;
/* make temp storage, larger than we need*/
tempIndex = (UChar*) uprv_malloc(sizeof(UChar)* UCMP8_kUnicodeCount);
if (!tempIndex)
{
this_obj->fBogus = TRUE;
return;
}
/* set up first block.*/
tempIndexCount = UCMP8_kBlockCount;
for (iIndex = 0; iIndex < UCMP8_kBlockCount; ++iIndex)
{
tempIndex[iIndex] = (uint16_t)iIndex;
}; /* endfor (iIndex = 0; .....)*/
this_obj->fIndex[0] = 0;
/* for each successive block, find out its first position in the compacted array*/
for (iBlock = 1; iBlock < UCMP8_kIndexCount; ++iBlock)
{
int32_t newCount, firstPosition, block;
block = iBlock << UCMP8_kBlockShift;
/* if (debugSmall) if (block > debugSmallLimit) break;*/
firstPosition = findOverlappingPosition(this_obj,
block,
tempIndex,
tempIndexCount,
cycle);
/* if not contained in the current list, copy the remainder
* invariant; cumulativeHash[iBlock] = XOR of values from iBlock-kBlockCount+1 to iBlock
* we do this_obj by XORing out cumulativeHash[iBlock-kBlockCount]
*/
newCount = firstPosition + UCMP8_kBlockCount;
if (newCount > tempIndexCount)
{
for (iIndex = tempIndexCount; iIndex < newCount; ++iIndex)
{
tempIndex[iIndex] = (uint16_t)(iIndex - firstPosition + block);
} /* endfor (iIndex = tempIndexCount....)*/
tempIndexCount = newCount;
} /* endif (newCount > tempIndexCount)*/
this_obj->fIndex[iBlock] = (uint16_t)firstPosition;
} /* endfor (iBlock = 1.....)*/
/* now allocate and copy the items into the array*/
tempArray = (int8_t*) uprv_malloc(tempIndexCount * sizeof(int8_t));
if (!tempArray)
{
this_obj->fBogus = TRUE;
uprv_free(tempIndex);
return;
}
for (iIndex = 0; iIndex < tempIndexCount; ++iIndex)
{
tempArray[iIndex] = this_obj->fArray[tempIndex[iIndex]];
}
uprv_free(this_obj->fArray);
this_obj->fArray = tempArray;
this_obj->fCount = tempIndexCount;
/* free up temp storage*/
uprv_free(tempIndex);
this_obj->fCompact = TRUE;
} /* endif (!this_obj->fCompact)*/
}
/* We use sizeof(*array), etc so that this code can be as portable as
possible between the ucmpX_ family.
*/
U_CAPI CompactByteArray * U_EXPORT2 ucmp8_cloneFromData(const uint8_t **source, UErrorCode *status)
{
CompactByteArray *array;
const CompactByteArray *oldArray;
if(U_FAILURE(*status))
return NULL;
oldArray= (const CompactByteArray*)*source;
if(oldArray->fStructSize != sizeof(*oldArray))
{
*status = U_INVALID_TABLE_FORMAT; /* ? */
return NULL;
}
array = (CompactByteArray*)malloc(sizeof(*array));
uprv_memcpy(array,*source, sizeof(*array));
array->fAlias = TRUE;
*source += array->fStructSize;
array->fArray = (int8_t*)*source;
*source += (sizeof(int8_t)*array->fCount);
if(((*source)-((const uint8_t*)oldArray)) & 1 )
{
(*source)++;
}
array->fIndex = (uint16_t*)*source;
*source += (sizeof(uint16_t)*UCMP8_kIndexCount);
/* eat up padding */
while((*source-((uint8_t*)oldArray))%4)
(*source)++;
return array;
}