2
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
4
This program is free software; you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation; version 2 of the License.
8
This program is distributed in the hope that it will be useful,
9
but WITHOUT ANY WARRANTY; without even the implied warranty of
10
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License
14
along with this program; if not, write to the Free Software
15
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
22
The idea of presented algorithm see in
23
"The Art of Computer Programming" by Donald E. Knuth
24
Volume 3 "Sorting and searching"
25
(chapter 6.3 "Digital searching" - name and number of chapter
26
is back translation from Russian edition :))
28
as illustration of data structures, imagine next table:
30
static SYMBOL symbols[] = {
31
{ "ADD", SYM(ADD),0,0},
32
{ "AND", SYM(AND),0,0},
33
{ "DAY", SYM(DAY_SYM),0,0},
36
for this structure, presented program generate next searching-structure:
54
| symbols[2] ( "DAY" )
56
+----------+--+-+-+-+-+-+-+-+-+-+--+
57
| 2 char|d |e|f|j|h|i|j|k|l|m|n |
58
+----------+--+-+-+-+-+-+-+-+-+-+--+
59
|first_char|0 |0|0|0|0|0|0|0|0|0|0 |
60
|last_char |-1|0|0|0|0|0|0|0|0|0|-1|
61
|link |+ |0|0|0|0|0|0|0|0|0|+ |
64
symbols[0] ( "ADD" ) symbols[1] ( "AND" )
66
for optimization, link is the 16-bit index in 'symbols' or 'sql_functions'
69
So, we can read full search-structure as 32-bit word
73
use instead to_upper_lex, special array
74
(substitute chars) without skip codes..
76
try use reverse order of comparing..
80
#define NO_YACC_SYMBOLS
81
#include <my_global.h>
82
#include "mysql_version.h"
88
#include <welcome_copyright_notice.h> /* ORACLE_WELCOME_COPYRIGHT_NOTICE */
90
struct hash_lex_struct
95
hash_lex_struct *char_tails;
101
hash_lex_struct *get_hash_struct_by_len(hash_lex_struct **root_by_len,
102
int len, int *max_len)
105
*root_by_len= (hash_lex_struct *)realloc((char*)*root_by_len,
106
sizeof(hash_lex_struct)*len);
107
hash_lex_struct *cur, *end= *root_by_len + len;
108
for (cur= *root_by_len + *max_len; cur<end; cur++)
112
return (*root_by_len)+(len-1);
115
void insert_into_hash(hash_lex_struct *root, const char *name,
116
int len_from_begin, int index, int function)
118
hash_lex_struct *end, *cur, *tails;
120
if (!root->first_char)
122
root->first_char= -1;
123
root->iresult= index;
127
if (root->first_char == -1)
129
int index2= root->iresult;
130
const char *name2= (index2 < 0 ? sql_functions[-index2-1] :
131
symbols[index2]).name + len_from_begin;
132
root->first_char= (int) (uchar) name2[0];
133
root->last_char= (char) root->first_char;
134
tails= (hash_lex_struct*)malloc(sizeof(hash_lex_struct));
135
root->char_tails= tails;
136
tails->first_char= -1;
137
tails->iresult= index2;
140
size_t real_size= (root->last_char-root->first_char+1);
142
if (root->first_char>(*name))
144
size_t new_size= root->last_char-(*name)+1;
145
if (new_size<real_size) printf("error!!!!\n");
146
tails= root->char_tails;
147
tails= (hash_lex_struct*)realloc((char*)tails,
148
sizeof(hash_lex_struct)*new_size);
149
root->char_tails= tails;
150
memmove(tails+(new_size-real_size),tails,real_size*sizeof(hash_lex_struct));
151
end= tails + new_size - real_size;
152
for (cur= tails; cur<end; cur++)
154
root->first_char= (int) (uchar) *name;
157
if (root->last_char<(*name))
159
size_t new_size= (*name)-root->first_char+1;
160
if (new_size<real_size) printf("error!!!!\n");
161
tails= root->char_tails;
162
tails= (hash_lex_struct*)realloc((char*)tails,
163
sizeof(hash_lex_struct)*new_size);
164
root->char_tails= tails;
165
end= tails + new_size;
166
for (cur= tails+real_size; cur<end; cur++)
168
root->last_char= (*name);
171
insert_into_hash(root->char_tails+(*name)-root->first_char,
172
name+1,len_from_begin+1,index,function);
176
hash_lex_struct *root_by_len= 0;
179
hash_lex_struct *root_by_len2= 0;
182
void insert_symbols()
186
for (cur= symbols; i<array_elements(symbols); cur++, i++){
187
hash_lex_struct *root=
188
get_hash_struct_by_len(&root_by_len,cur->length,&max_len);
189
insert_into_hash(root,cur->name,0,(uint) i,0);
193
void insert_sql_functions()
197
for (cur= sql_functions; i < (int) array_elements(sql_functions); cur++, i++)
199
hash_lex_struct *root=
200
get_hash_struct_by_len(&root_by_len,cur->length,&max_len);
201
insert_into_hash(root,cur->name,0,-i-1,1);
207
SYMBOL *cur, *end= symbols + array_elements(symbols);
208
for (cur= symbols; cur < end; cur++)
209
cur->length=(uchar) strlen(cur->name);
210
end= sql_functions + array_elements(sql_functions);
211
for (cur= sql_functions; cur<end; cur++)
212
cur->length=(uchar) strlen(cur->name);
215
void generate_find_structs()
222
root_by_len2= root_by_len;
229
insert_sql_functions();
233
int size_hash_map= 0;
235
void add_struct_to_map(hash_lex_struct *st)
237
st->ithis= size_hash_map/4;
239
hash_map= (char*)realloc((char*)hash_map,size_hash_map);
240
hash_map[size_hash_map-4]= (char) (st->first_char == -1 ? 0 :
242
hash_map[size_hash_map-3]= (char) (st->first_char == -1 ||
243
st->first_char == 0 ? 0 : st->last_char);
244
if (st->first_char == -1)
246
hash_map[size_hash_map-2]= ((unsigned int)(int16)st->iresult)&255;
247
hash_map[size_hash_map-1]= ((unsigned int)(int16)st->iresult)>>8;
249
else if (st->first_char == 0)
251
hash_map[size_hash_map-2]= ((unsigned int)(int16)array_elements(symbols))&255;
252
hash_map[size_hash_map-1]= ((unsigned int)(int16)array_elements(symbols))>>8;
257
void add_structs_to_map(hash_lex_struct *st, int len)
259
hash_lex_struct *cur, *end= st+len;
260
for (cur= st; cur<end; cur++)
261
add_struct_to_map(cur);
262
for (cur= st; cur<end; cur++)
264
if (cur->first_char && cur->first_char != -1)
265
add_structs_to_map(cur->char_tails,cur->last_char-cur->first_char+1);
269
void set_links(hash_lex_struct *st, int len)
271
hash_lex_struct *cur, *end= st+len;
272
for (cur= st; cur<end; cur++)
274
if (cur->first_char != 0 && cur->first_char != -1)
276
int ilink= cur->char_tails->ithis;
277
hash_map[cur->ithis*4+2]= ilink%256;
278
hash_map[cur->ithis*4+3]= ilink/256;
279
set_links(cur->char_tails,cur->last_char-cur->first_char+1);
285
void print_hash_map(const char *name)
290
printf("static uchar %s[%d]= {\n",name,size_hash_map);
291
for (i=0, cur= hash_map; i<size_hash_map; i++, cur++)
298
printf("\'%c\', ",*cur);
300
case 2: printf("%u, ",(uint)(uchar)*cur); break;
301
case 3: printf("%u,\n",(uint)(uchar)*cur); break;
308
void print_find_structs()
310
add_structs_to_map(root_by_len,max_len);
311
set_links(root_by_len,max_len);
312
print_hash_map("sql_functions_map");
319
add_structs_to_map(root_by_len2,max_len2);
320
set_links(root_by_len2,max_len2);
321
print_hash_map("symbols_map");
325
int check_dup_symbols(SYMBOL *s1, SYMBOL *s2)
327
if (s1->length!=s2->length || strncmp(s1->name,s2->name,s1->length))
330
const char *err_tmpl= "\ngen_lex_hash fatal error : \
331
Unfortunately gen_lex_hash can not generate a hash,\n since \
332
your lex.h has duplicate definition for a symbol \"%s\"\n\n";
333
printf (err_tmpl,s1->name);
334
fprintf (stderr,err_tmpl,s1->name);
340
int check_duplicates()
342
SYMBOL *cur1, *cur2, *s_end, *f_end;
344
s_end= symbols + array_elements(symbols);
345
f_end= sql_functions + array_elements(sql_functions);
347
for (cur1= symbols; cur1<s_end; cur1++)
349
for (cur2= cur1+1; cur2<s_end; cur2++)
351
if (check_dup_symbols(cur1,cur2))
354
for (cur2= sql_functions; cur2<f_end; cur2++)
356
if (check_dup_symbols(cur1,cur2))
361
for (cur1= sql_functions; cur1<f_end; cur1++)
363
for (cur2= cur1+1; cur2< f_end; cur2++)
365
if (check_dup_symbols(cur1,cur2))
373
int main(int argc,char **argv)
377
/* Broken up to indicate that it's not advice to you, gentle reader. */
378
printf("/*\n\n Do " "not " "edit " "this " "file " "directly!\n\n*/\n");
381
puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2000, 2011"));
384
/* Broken up to indicate that it's not advice to you, gentle reader. */
385
printf("/* Do " "not " "edit " "this " "file! This is generated by "
386
"gen_lex_hash.cc\nthat seeks for a perfect hash function */\n\n");
387
printf("#include \"lex.h\"\n\n");
391
if (check_duplicates())
394
generate_find_structs();
395
print_find_structs();
397
printf("\nstatic unsigned int sql_functions_max_len=%d;\n", max_len);
398
printf("\nstatic unsigned int symbols_max_len=%d;\n\n", max_len2);
401
static SYMBOL *get_hash_symbol(const char *s,\n\
402
unsigned int len,bool function)\n\
404
register uchar *hash_map;\n\
405
register const char *cur_str= s;\n\
408
DBUG_PRINT(\"warning\", (\"get_hash_symbol() received a request for a zero-length symbol, which is probably a mistake.\"));\
415
if (len>sql_functions_max_len) return 0;\n\
416
hash_map= sql_functions_map;\n\
417
register uint32 cur_struct= uint4korr(hash_map+((len-1)*4));\n\
420
register uchar first_char= (uchar)cur_struct;\n\
422
if (first_char == 0)\n\
424
register int16 ires= (int16)(cur_struct>>16);\n\
425
if (ires==array_elements(symbols)) return 0;\n\
426
register SYMBOL *res;\n\
428
res= symbols+ires;\n\
430
res= sql_functions-ires-1;\n\
431
register uint count= (uint) (cur_str - s);\n\
432
return lex_casecmp(cur_str,res->name+count,len-count) ? 0 : res;\n\
435
register uchar cur_char= (uchar)to_upper_lex[(uchar)*cur_str];\n\
436
if (cur_char<first_char) return 0;\n\
438
if (cur_char>(uchar)cur_struct) return 0;\n\
441
cur_struct= uint4korr(hash_map+\n\
442
(((uint16)cur_struct + cur_char - first_char)*4));\n\
449
if (len>symbols_max_len) return 0;\n\
450
hash_map= symbols_map;\n\
451
register uint32 cur_struct= uint4korr(hash_map+((len-1)*4));\n\
454
register uchar first_char= (uchar)cur_struct;\n\
456
if (first_char==0){\n\
457
register int16 ires= (int16)(cur_struct>>16);\n\
458
if (ires==array_elements(symbols)) return 0;\n\
459
register SYMBOL *res= symbols+ires;\n\
460
register uint count= (uint) (cur_str - s);\n\
461
return lex_casecmp(cur_str,res->name+count,len-count)!=0 ? 0 : res;\n\
464
register uchar cur_char= (uchar)to_upper_lex[(uchar)*cur_str];\n\
465
if (cur_char<first_char) return 0;\n\
467
if (cur_char>(uchar)cur_struct) return 0;\n\
470
cur_struct= uint4korr(hash_map+\n\
471
(((uint16)cur_struct + cur_char - first_char)*4));\n\