make dict_makeIndex work for depth > 1.

This commit is contained in:
Eric House 2011-10-26 22:20:21 -07:00
parent f2c4e39cd4
commit 412a58f6b9
3 changed files with 219 additions and 134 deletions

View file

@ -682,27 +682,33 @@ dict_getLangName( const DictionaryCtxt* ctxt )
}
#ifdef XWFEATURE_WALKDICT
typedef struct _EdgeArray {
array_edge* edges[MAX_COLS];
XP_U16 nEdges;
} EdgeArray;
static void
edgesToIndices( const DictionaryCtxt* dict, XP_U16 nEdges,
array_edge** edges, DictWord* word )
edgesToIndices( const DictionaryCtxt* dict, const EdgeArray* edges,
DictWord* word )
{
XP_U16 ii;
word->nTiles = nEdges;
for ( ii = 0; ii < nEdges; ++ii ) {
word->indices[ii] = edges[ii] - dict->base;
word->nTiles = edges->nEdges;
for ( ii = 0; ii < edges->nEdges; ++ii ) {
word->indices[ii] = edges->edges[ii] - dict->base;
}
}
static void
indicesToEdges( const DictionaryCtxt* dict,
const DictWord* word, array_edge** edges )
const DictWord* word, EdgeArray* edges )
{
XP_U16 nEdges = word->nTiles;
XP_U16 ii;
for ( ii = 0; ii < nEdges; ++ii ) {
edges[ii] = &dict->base[word->indices[ii]];
edges->edges[ii] = &dict->base[word->indices[ii]];
}
edges->nEdges = nEdges;
}
/* On entry and exit, edge at end of array should be ACCEPTING. The job of
@ -713,28 +719,28 @@ indicesToEdges( const DictionaryCtxt* dict,
* LAST_EDGE, try with its next-letter neighbor.
*/
static XP_Bool
nextWord( const DictionaryCtxt* dict, array_edge** edges, XP_U16* nTilesP )
nextWord( const DictionaryCtxt* dict, EdgeArray* edges )
{
XP_U16 nTiles = *nTilesP;
XP_U16 nTiles = edges->nEdges;
XP_Bool success = XP_FALSE;
while ( 0 < nTiles && ! success ) {
array_edge* next = dict_follow( dict, edges[nTiles-1] );
array_edge* next = dict_follow( dict, edges->edges[nTiles-1] );
if ( !!next ) {
edges[nTiles++] = next;
edges->edges[nTiles++] = next;
success = ISACCEPTING( dict, next );
continue; /* try with longer word */
}
while ( IS_LAST_EDGE( dict, edges[nTiles-1] ) && 0 < --nTiles ) {
while ( IS_LAST_EDGE( dict, edges->edges[nTiles-1] ) && 0 < --nTiles ) {
}
if ( 0 < nTiles ) {
edges[nTiles-1] += dict->nodeSize;
success = ISACCEPTING( dict, edges[nTiles-1] );
edges->edges[nTiles-1] += dict->nodeSize;
success = ISACCEPTING( dict, edges->edges[nTiles-1] );
}
}
*nTilesP = nTiles;
edges->nEdges = nTiles;
return success;
}
@ -749,74 +755,66 @@ isFirstEdge( const DictionaryCtxt* dict, array_edge* edge )
}
static XP_Bool
lastEdges( const DictionaryCtxt* dict, array_edge** edges, XP_U16* nEdgesP )
lastEdges( const DictionaryCtxt* dict, EdgeArray* edges )
{
XP_U16 nEdges = *nEdgesP;
array_edge* edge = edges[nEdges-1];
array_edge* edge = edges->edges[edges->nEdges-1];
for ( ; ; ) {
while ( !IS_LAST_EDGE( dict, edge ) ) {
edge += dict->nodeSize;
}
edges[nEdges-1] = edge;
edges->edges[edges->nEdges-1] = edge;
edge = dict_follow( dict, edge );
if ( NULL == edge ) {
break;
}
++nEdges;
++edges->nEdges;
}
*nEdgesP = nEdges;
return ISACCEPTING( dict, edges[nEdges-1] );
return ISACCEPTING( dict, edges->edges[edges->nEdges-1] );
}
static XP_Bool
prevWord( const DictionaryCtxt* dict, array_edge** edges, XP_U16* nEdgesP )
prevWord( const DictionaryCtxt* dict, EdgeArray* edges )
{
XP_U16 nEdges = *nEdgesP;
XP_Bool success = XP_FALSE;
while ( 0 < nEdges && ! success ) {
if ( isFirstEdge( dict, edges[nEdges-1] ) ) {
--nEdges;
success = 0 < nEdges && ISACCEPTING( dict, edges[nEdges-1] );
while ( 0 < edges->nEdges && ! success ) {
if ( isFirstEdge( dict, edges->edges[edges->nEdges-1] ) ) {
--edges->nEdges;
success = 0 < edges->nEdges && ISACCEPTING( dict, edges->edges[edges->nEdges-1] );
continue;
}
edges[nEdges-1] -= dict->nodeSize;
array_edge* next = dict_follow( dict, edges[nEdges-1] );
edges->edges[edges->nEdges-1] -= dict->nodeSize;
array_edge* next = dict_follow( dict, edges->edges[edges->nEdges-1] );
if ( NULL != next ) {
edges[nEdges++] = next;
success = lastEdges( dict, edges, &nEdges );
edges->edges[edges->nEdges++] = next;
success = lastEdges( dict, edges );
if ( success ) {
continue;
}
}
success = ISACCEPTING( dict, edges[nEdges-1] );
success = ISACCEPTING( dict, edges->edges[edges->nEdges-1] );
}
*nEdgesP = nEdges;
return success;
}
typedef XP_Bool (*WordFinder)(const DictionaryCtxt* dict, array_edge** edges,
XP_U16* nTilesP );
typedef XP_Bool (*WordFinder)(const DictionaryCtxt* dict, EdgeArray* edges );
static XP_Bool
dict_getWord( const DictionaryCtxt* dict, DictWord* word, WordFinder finder )
{
XP_U16 nTiles = word->nTiles;
array_edge* edges[MAX_COLS];
indicesToEdges( dict, word, edges );
XP_Bool success = (*finder)( dict, edges, &nTiles );
EdgeArray edges;
indicesToEdges( dict, word, &edges );
XP_Bool success = (*finder)( dict, &edges );
if ( success ) {
edgesToIndices( dict, nTiles, edges, word );
edgesToIndices( dict, &edges, word );
}
return success;
}
static XP_Bool
findStartsWith( const DictionaryCtxt* dict, Tile* tiles, XP_U16 nTiles,
array_edge** edges, XP_U16* nEdgesP )
findStartsWith( const DictionaryCtxt* dict, Tile* tiles, XP_U16 nTiles, EdgeArray* edges )
{
XP_Bool success = XP_TRUE;
XP_U16 nEdges = 0;
array_edge* edge = dict_getTopEdge( dict );
while ( nTiles-- > 0 ) {
@ -826,49 +824,102 @@ findStartsWith( const DictionaryCtxt* dict, Tile* tiles, XP_U16 nTiles,
success = XP_FALSE;
break;
}
edges[nEdges++] = edge;
edges->edges[edges->nEdges++] = edge;
edge = dict_follow( dict, edge );
}
*nEdgesP = nEdges;
return success;
}
static XP_Bool
wordsEqual( array_edge** edges1, XP_U16 nEdges1,
array_edge** edges2, XP_U16 nEdges2 )
wordsEqual( EdgeArray* word1, EdgeArray* word2 )
{
XP_Bool success = nEdges1 == nEdges2;
XP_Bool success = word1->nEdges == word2->nEdges;
if ( success ) {
success = 0 == memcmp( edges1, edges2, nEdges1 * sizeof(edges1[0]) );
success = 0 == memcmp( word1->edges, word2->edges,
word1->nEdges * sizeof(word1->edges[0]) );
}
return success;
}
XP_U32
dict_countWords( const DictionaryCtxt* dict )
{
array_edge* edges[MAX_COLS];
XP_U16 nEdges = 0;
EdgeArray edges = { .nEdges = 0 };
XP_U32 count = 0;
edges[nEdges++] = dict_getTopEdge( dict );
if ( ISACCEPTING( dict, edges[0] ) ) {
edges.edges[edges.nEdges++] = dict_getTopEdge( dict );
if ( ISACCEPTING( dict, edges.edges[0] ) ) {
++count;
}
while ( nextWord( dict, edges, &nEdges ) ) {
while ( nextWord( dict, &edges ) ) {
++count;
}
return count;
}
void
dict_makeIndex( const DictionaryCtxt* dict, XP_U16 depth,
DictIndex* indices, XP_U16 count )
static void
indexOne( const DictionaryCtxt* dict, XP_U16 depth, Tile* tiles,
DictIndex* indices, XP_U16* nextIndex,
XWStreamCtxt* stream, EdgeArray* prevEdges, DictIndex* prevIndex )
{
XP_USE( indices );
XP_ASSERT( depth == 1 ); /* so far */
XP_U16 ii, needCount;
XP_U16 nextIndex = 0;
EdgeArray curEdges = { .nEdges = 0 };
if ( !findStartsWith( dict, tiles, depth, &curEdges ) ) {
indices[(*nextIndex)++] = NO_INDEX;
} else {
XP_ASSERT( curEdges.nEdges == depth );
if ( ! ISACCEPTING( dict, curEdges.edges[curEdges.nEdges-1] ) ) {
if ( !nextWord( dict, &curEdges ) ) {
XP_ASSERT( 0 );
}
}
if ( wordsEqual( &curEdges, prevEdges ) ) {
XP_ASSERT( *prevIndex == 0 );
} else {
/* Walk the prev word forward until they're the same */
while ( nextWord( dict, prevEdges ) ) {
++*prevIndex;
if ( wordsEqual( &curEdges, prevEdges ) ) {
break;
}
}
}
indices[(*nextIndex)++] = *prevIndex;
if ( NULL != stream ) {
XP_UCHAR prefix[8];
(void)dict_tilesToString( dict, tiles, depth, prefix, VSIZE(prefix) );
stream_catString( stream, prefix );
}
}
if ( NULL != stream ) {
stream_catString( stream, "\n" );
}
}
static void
doOneDepth( const DictionaryCtxt* dict,
const Tile* allTiles, XP_U16 nTiles, Tile* prefix,
XP_U16 curDepth, XP_U16 maxDepth,
DictIndex* indices, XP_U16* nextEntry,
XWStreamCtxt* stream, EdgeArray* prevEdges, DictIndex* prevIndex )
{
XP_U16 ii;
for ( ii = 0; ii < nTiles; ++ii ) {
prefix[curDepth] = allTiles[ii];
if ( curDepth + 1 == maxDepth ) {
indexOne( dict, maxDepth, prefix, indices, nextEntry,
stream, prevEdges, prevIndex);
} else {
doOneDepth( dict, allTiles, nTiles, prefix, curDepth+1, maxDepth,
indices, nextEntry, stream, prevEdges, prevIndex );
}
}
}
XP_U16
dict_makeIndex( const DictionaryCtxt* dict, XP_U16 depth,
DictIndex* indices, XP_U16 count, XWStreamCtxt* stream )
{
XP_ASSERT( depth < MAX_COLS );
XP_U16 ii, needCount, nTiles;
XP_U16 nFaces = dict_numTileFaces( dict );
XP_Bool hasBlank = dict_hasBlankTile( dict );
if ( hasBlank ) {
@ -879,66 +930,46 @@ dict_makeIndex( const DictionaryCtxt* dict, XP_U16 depth,
}
XP_ASSERT( needCount <= count );
Tile allTiles[nFaces];
nTiles = 0;
for ( ii = 0; ii < nFaces; ++ii ) {
if ( hasBlank && ii == dict_getBlankTile( dict ) ) {
continue;
}
allTiles[nTiles++] = (Tile)ii;
}
/* For each tile string implied by depth (A if depth == 1, AAA if == 3 ),
* find the first word starting with that IF EXISTS. If it does, find its
* index. As an optimization, find index starting with the previous word.
*/
XP_U16 nextIndex = 0;
DictWord firstWord;
if ( dict_firstWord( dict, &firstWord ) ) {
array_edge* prevEdges[MAX_COLS];
indicesToEdges( dict, &firstWord, prevEdges );
XP_U16 prevNEdges = firstWord.nTiles;
DictIndex index = 0;
EdgeArray prevEdges;
DictIndex prevIndex = 0;
Tile prefix[depth];
indicesToEdges( dict, &firstWord, &prevEdges );
Tile tiles[1];
nFaces = dict_numTileFaces( dict );
for ( tiles[0] = 0; tiles[0] < nFaces; ++tiles[0] ) {
if ( hasBlank && tiles[0] == dict_getBlankTile( dict ) ) {
continue;
}
doOneDepth( dict, allTiles, nFaces, prefix, 0, depth,
indices, &nextIndex, stream, &prevEdges, &prevIndex );
array_edge* curEdges[MAX_COLS];
XP_U16 curNEdges;
if ( !findStartsWith( dict, tiles, 1, curEdges, &curNEdges ) ) {
indices[nextIndex++] = NO_INDEX;
} else {
XP_ASSERT( curNEdges == depth );
if ( ! ISACCEPTING( dict, curEdges[curNEdges-1] ) ) {
if ( !nextWord( dict, curEdges, &curNEdges ) ) {
XP_ASSERT( 0 );
}
}
if ( wordsEqual( curEdges, curNEdges, prevEdges, prevNEdges ) ) {
XP_ASSERT( index == 0 );
} else {
/* Walk the prev word forward until they're the same */
while ( nextWord( dict, prevEdges, &prevNEdges ) ) {
++index;
if ( wordsEqual( curEdges, curNEdges, prevEdges, prevNEdges ) ) {
break;
}
}
}
indices[nextIndex++] = index;
}
}
}
return nextIndex;
}
XP_Bool
dict_firstWord( const DictionaryCtxt* dict, DictWord* word )
{
array_edge* edges[MAX_COLS];
XP_U16 nEdges = 0;
edges[nEdges++] = dict_getTopEdge( dict );
EdgeArray edges = { .nEdges = 0 };
edges.edges[edges.nEdges++] = dict_getTopEdge( dict );
XP_Bool success = ISACCEPTING( dict, edges[0] )
|| nextWord( dict, edges, &nEdges );
XP_Bool success = ISACCEPTING( dict, edges.edges[0] )
|| nextWord( dict, &edges );
if ( success ) {
word->wordCount = dict_getWordCount( dict );
edgesToIndices( dict, nEdges, edges, word );
edgesToIndices( dict, &edges, word );
word->index = 0;
}
@ -958,15 +989,14 @@ dict_getNextWord( const DictionaryCtxt* dict, DictWord* word )
XP_Bool
dict_lastWord( const DictionaryCtxt* dict, DictWord* word )
{
array_edge* edges[MAX_COLS];
XP_U16 nEdges = 0;
edges[nEdges++] = dict_getTopEdge( dict );
EdgeArray edges = { .nEdges = 0 };
edges.edges[edges.nEdges++] = dict_getTopEdge( dict );
XP_Bool success = lastEdges( dict, edges, &nEdges );
XP_Bool success = lastEdges( dict, &edges );
if ( success ) {
word->wordCount = dict_getWordCount( dict );
edgesToIndices( dict, nEdges, edges, word );
edgesToIndices( dict, &edges, word );
word->index = word->wordCount - 1;
}
@ -1017,23 +1047,22 @@ dict_getNthWord( const DictionaryCtxt* dict, DictWord* word, XP_U32 nn )
}
}
array_edge* edges[MAX_COLS];
XP_U16 nEdges = word->nTiles;
indicesToEdges( dict, word, edges );
EdgeArray edges;
indicesToEdges( dict, word, &edges );
if ( word->index < nn ) {
for ( ii = nn - word->index; ii > 0; --ii ) {
if ( !nextWord( dict, edges, &nEdges ) ) {
if ( !nextWord( dict, &edges ) ) {
XP_ASSERT( 0 );
}
}
} else if ( word->index > nn ) {
for ( ii = word->index - nn; ii > 0; --ii ) {
if ( !prevWord( dict, edges, &nEdges ) ) {
if ( !prevWord( dict, &edges ) ) {
XP_ASSERT( 0 );
}
}
}
edgesToIndices( dict, nEdges, edges, word );
edgesToIndices( dict, &edges, word );
word->index = nn;
}
return success;
@ -1044,15 +1073,16 @@ dict_wordToString( const DictionaryCtxt* dict, const DictWord* word,
XP_UCHAR* buf, XP_U16 buflen )
{
XP_U16 ii;
array_edge* edges[MAX_COLS];
const XP_U16 nTiles = word->nTiles;
Tile tiles[MAX_COLS];
EdgeArray edges;
indicesToEdges( dict, word, edges );
indicesToEdges( dict, word, &edges );
for ( ii = 0; ii < word->nTiles; ++ii ) {
tiles[ii] = EDGETILE( dict, edges[ii] );
for ( ii = 0; ii < nTiles; ++ii ) {
tiles[ii] = EDGETILE( dict, edges.edges[ii] );
}
(void)dict_tilesToString( dict, tiles, word->nTiles, buf, buflen );
(void)dict_tilesToString( dict, tiles, nTiles, buf, buflen );
}
#endif /* XWFEATURE_WALKDICT */

View file

@ -219,8 +219,9 @@ typedef struct _DictWord {
} DictWord;
XP_U32 dict_countWords( const DictionaryCtxt* dict );
void dict_makeIndex( const DictionaryCtxt* dict, XP_U16 depth,
DictIndex* indices, XP_U16 count );
XP_U16 dict_makeIndex( const DictionaryCtxt* dict, XP_U16 depth,
DictIndex* indices, XP_U16 count,
XWStreamCtxt* stream );
XP_Bool dict_firstWord( const DictionaryCtxt* dict, DictWord* word );
XP_Bool dict_lastWord( const DictionaryCtxt* dict, DictWord* word );
XP_Bool dict_getNextWord( const DictionaryCtxt* dict, DictWord* word );

View file

@ -893,9 +893,39 @@ tmp_noop_sigintterm( int XP_UNUSED(sig) )
}
#ifdef XWFEATURE_WALKDICT
static void
walk_dict_test( const DictionaryCtxt* dict )
#if 0
static char*
mkPrefix( const DictionaryCtxt* dict, int index, int depth, char* buf, int len )
{
Tile tiles[depth];
Tile blank;
XP_U16 nTiles = dict_numTileFaces( dict );
if ( dict_hasBlankTile( dict ) ) {
blank = dict_getBlankTile( dict );
--nTiles;
} else {
blank = -1;
}
int ii;
for ( ii = depth-1; ii >= 0; --ii ) {
Tile tile = index % nTiles;
if ( -1 != blank && blank <= tile ) {
++tile;
}
tiles[ii] = tile;
index /= nTiles;
}
dict_tilesToString( dict, tiles, depth, buf, len );
return buf;
}
#endif
static void
walk_dict_test( const LaunchParams* params )
{
const DictionaryCtxt* dict = params->dict;
/* This is just to test that the dict-iterating code works. The words are
meant to be printed e.g. in a scrolling dialog on Android. */
DictWord word;
@ -967,13 +997,20 @@ walk_dict_test( const DictionaryCtxt* dict )
}
}
DictIndex indices[26];
dict_makeIndex( dict, 1, indices, VSIZE(indices) );
for ( ii = 0; ii < VSIZE(indices); ++ii ) {
DictIndex index = indices[ii];
if ( NO_INDEX == index ) {
continue;
} else if ( dict_getNthWord( dict, &word, indices[ii] ) ) {
XP_U16 depth = 2;
DictIndex indices[26*26]; /* pow(26,depth) */
XWStreamCtxt* stream = mem_stream_make( MPPARM(params->util->mpool)
params->vtMgr,
NULL, CHANNEL_NONE, NULL );
XP_U16 nIndices = dict_makeIndex( dict, depth, indices, VSIZE(indices), stream );
const char* ptr = (char*)stream_getPtr( stream );
for ( ii = 0; ii < nIndices; ++ii ) {
char* next = strstr( (char*)ptr, "\n" );
XP_ASSERT( !!next );
if ( next > ptr && indices[ii] != NO_INDEX ) {
if ( !dict_getNthWord( dict, &word, indices[ii] ) ) {
XP_ASSERT( 0 );
}
XP_ASSERT( word.index == indices[ii] );
XP_UCHAR buf1[64];
dict_wordToString( dict, &word, buf1, VSIZE(buf1) );
@ -981,10 +1018,27 @@ walk_dict_test( const DictionaryCtxt* dict )
if ( ii > 0 && dict_getNthWord( dict, &word, indices[ii]-1 ) ) {
dict_wordToString( dict, &word, buf2, VSIZE(buf2) );
}
fprintf( stderr, "%d: index: %ld; word: %s (prev: %s)\n", ii, indices[ii], buf1, buf2 );
char prfx[8];
snprintf( prfx, depth+1, "%s", ptr );
prfx[depth] = '\0';
fprintf( stderr,
"%d: index: %ld; prefix: %s; word: %s (prev: %s)\n",
ii, indices[ii], prfx, buf1, buf2 );
} else if ( next == ptr && indices[ii] == NO_INDEX ) {
} else {
XP_ASSERT( 0 );
}
ptr = next + 1;
}
/* for ( ii = 0; ii < VSIZE(indices); ++ii ) { */
/* DictIndex index = indices[ii]; */
/* if ( NO_INDEX == index ) { */
/* continue; */
/* } */
/* catOnClose( stream, NULL ); */
stream_destroy( stream );
exit( 0 );
}
#else
@ -1380,7 +1434,7 @@ main( int argc, char** argv )
/* } */
/* } */
walk_dict_test( mainParams.dict );
walk_dict_test( &mainParams );
if ( 0 ) {
#ifdef XWFEATURE_RELAY