1
0
mirror of https://git.savannah.gnu.org/git/gperf.git synced 2025-12-02 21:19:24 +00:00

Rework the options handling.

This commit is contained in:
Bruno Haible
2002-11-13 18:18:48 +00:00
parent 5e5d12ca2d
commit c8f007fe8b
12 changed files with 739 additions and 439 deletions

View File

@@ -1,3 +1,50 @@
2002-10-14 Bruno Haible <bruno@clisp.org>
* src/options.h (Positions): New class.
(PositionIterator): New class.
(Options::parse_options): Renamed from Options::operator().
(Options::get_asso_max, Options::set_asso_max): Move to class Key_List.
(Options::reset, Options::get): Remove, replaced by class
PositionIterator.
(Options::get_initial_asso_value): Renamed from Options::initial_value.
(Options::key_sort): Remove, replaced by Positions::sort.
(Options): Make all fields and methods non-static.
* src/options.icc (Positions::Positions, Positions::operator[],
Positions::get_size, Positions::pointer, Positions::set_size,
Positions::sort, PositionIterator::PositionIterator,
PositionIterator::next): New methods.
(Options::get_initial_asso_value): Renamed from Options::initial_value.
(Options::get_size_multiple): New method.
(Options::get_key_positions): New method.
(Options::get_max_keysig_size): Implement using _key_positions.
* src/options.cc (Options::long_usage): Split big string into small
pieces.
(PositionStringParser): Prefix field names with _.
(Options::Options): Update.
(Options::~Options): Fix explanation of of _size_multiple. Don't print
_key_positions if it is effectively ignored.
(Options::parse_options): Renamed from Options::operator(). Update.
* src/key-list.h (Key_List): New field _size. New methods get_asso_max,
set_asso_max, get_max_keysig_size.
* src/key-list.cc (Key_List::read_keys): Don't make side effects on
options.
(Key_List::dump): Use Key_List::get_max_keysig_size() instead of
Options::get_max_keysig_size().
(Key_List::get_max_keysig_size): New function.
* src/hash-table.cc (Hash_Table::~Hash_Table): Compute the field
width on the fly if option[ALLCHARS].
* src/gen-perf.cc (Gen_Perf::Gen_Perf): Update,
Use Options::get_size_multiple() instead of Options::get_asso_max().
Use Key_List::get_asso_max() instead of Options::get_asso_max(). Use
Key_List::get_max_keysig_size() instead of
Options::get_max_keysig_size().
(Gen_Perf::affects_prev): Likewise.
(Gen_Perf::change): Likewise.
* src/keyword.cc: Update.
* src/main.cc: Update.
* src/output.cc: Update.
* tests/test-6.exp: Update.
2002-10-13 Bruno Haible <bruno@clisp.org> 2002-10-13 Bruno Haible <bruno@clisp.org>
* src/bool-array.*: Some polishing. * src/bool-array.*: Some polishing.

View File

@@ -43,17 +43,17 @@ Gen_Perf::Gen_Perf ()
Key_List::read_keys (); Key_List::read_keys ();
if (option[ORDER]) if (option[ORDER])
reorder (); reorder ();
asso_value_max = option.get_asso_max ();
non_linked_length = Key_List::keyword_list_length ();
_num_done = 1; _num_done = 1;
_fewest_collisions = 0; _fewest_collisions = 0;
asso_value_max = option.get_size_multiple ();
non_linked_length = Key_List::keyword_list_length ();
if (asso_value_max == 0) if (asso_value_max == 0)
asso_value_max = non_linked_length; asso_value_max = non_linked_length;
else if (asso_value_max > 0) else if (asso_value_max > 0)
asso_value_max *= non_linked_length; asso_value_max *= non_linked_length;
else /* if (asso_value_max < 0) */ else /* if (asso_value_max < 0) */
asso_value_max = non_linked_length / -asso_value_max; asso_value_max = non_linked_length / -asso_value_max;
option.set_asso_max (POW (asso_value_max)); set_asso_max (POW (asso_value_max));
if (option[RANDOM]) if (option[RANDOM])
{ {
@@ -64,14 +64,14 @@ Gen_Perf::Gen_Perf ()
} }
else else
{ {
int asso_value = option.initial_value (); int asso_value = option.get_initial_asso_value ();
if (asso_value) /* Initialize array if user requests non-zero default. */ if (asso_value) /* Initialize array if user requests non-zero default. */
for (int i = ALPHA_SIZE - 1; i >= 0; i--) for (int i = ALPHA_SIZE - 1; i >= 0; i--)
_asso_values[i] = asso_value & option.get_asso_max () - 1; _asso_values[i] = asso_value & get_asso_max () - 1;
} }
_max_hash_value = Key_List::max_key_length () + option.get_asso_max () * _max_hash_value = Key_List::max_key_length () + get_asso_max () *
option.get_max_keysig_size (); get_max_keysig_size ();
_collision_detector = new Bool_Array (_max_hash_value + 1); _collision_detector = new Bool_Array (_max_hash_value + 1);
if (option[DEBUG]) if (option[DEBUG])
@@ -172,7 +172,7 @@ Gen_Perf::affects_prev (char c, KeywordExt *curr)
{ {
int original_char = _asso_values[(unsigned char)c]; int original_char = _asso_values[(unsigned char)c];
int total_iterations = !option[FAST] int total_iterations = !option[FAST]
? option.get_asso_max () : option.get_iterations () ? option.get_iterations () : keyword_list_length (); ? get_asso_max () : option.get_iterations () ? option.get_iterations () : keyword_list_length ();
/* Try all legal associated values. */ /* Try all legal associated values. */
@@ -182,7 +182,7 @@ Gen_Perf::affects_prev (char c, KeywordExt *curr)
_asso_values[(unsigned char)c] = _asso_values[(unsigned char)c] =
(_asso_values[(unsigned char)c] + (option.get_jump () ? option.get_jump () : rand ())) (_asso_values[(unsigned char)c] + (option.get_jump () ? option.get_jump () : rand ()))
& (option.get_asso_max () - 1); & (get_asso_max () - 1);
/* Iteration Number array is a win, O(1) intialization time! */ /* Iteration Number array is a win, O(1) intialization time! */
_collision_detector->clear (); _collision_detector->clear ();
@@ -221,7 +221,7 @@ Gen_Perf::change (KeywordExt *prior, KeywordExt *curr)
int union_set_length; int union_set_length;
if (!union_set) if (!union_set)
union_set = new char [2 * option.get_max_keysig_size ()]; union_set = new char [2 * get_max_keysig_size ()];
if (option[DEBUG]) if (option[DEBUG])
{ {
@@ -265,7 +265,7 @@ Gen_Perf::change (KeywordExt *prior, KeywordExt *curr)
if (option[DEBUG]) if (option[DEBUG])
{ {
fprintf (stderr, "** collision not resolved after %d iterations, %d duplicates remain, continuing...\n", fprintf (stderr, "** collision not resolved after %d iterations, %d duplicates remain, continuing...\n",
!option[FAST] ? option.get_asso_max () : option.get_iterations () ? option.get_iterations () : keyword_list_length (), !option[FAST] ? get_asso_max () : option.get_iterations () ? option.get_iterations () : keyword_list_length (),
_fewest_collisions + _total_duplicates); _fewest_collisions + _total_duplicates);
fflush (stderr); fflush (stderr);
} }

View File

@@ -44,7 +44,18 @@ Hash_Table::~Hash_Table ()
{ {
if (option[DEBUG]) if (option[DEBUG])
{ {
int field_width = option.get_max_keysig_size (); int field_width;
if (option[ALLCHARS])
{
field_width = 0;
for (int i = _size - 1; i >= 0; i--)
if (_table[i])
if (field_width < _table[i]->_selchars_length)
field_width = _table[i]->_selchars_length;
}
else
field_width = option.get_max_keysig_size ();
fprintf (stderr, fprintf (stderr,
"\ndumping the hash table\n" "\ndumping the hash table\n"

View File

@@ -449,8 +449,6 @@ Key_List::read_keys ()
fprintf (stderr, "Empty input key is not allowed.\nTo recognize an empty input key, your code should check for\nlen == 0 before calling the gperf generated lookup function.\n"); fprintf (stderr, "Empty input key is not allowed.\nTo recognize an empty input key, your code should check for\nlen == 0 before calling the gperf generated lookup function.\n");
exit (1); exit (1);
} }
if (option[ALLCHARS])
option.set_keysig_size (_max_key_len);
} }
} }
@@ -624,7 +622,7 @@ Key_List::sort ()
void void
Key_List::dump () Key_List::dump ()
{ {
int field_width = option.get_max_keysig_size (); int field_width = get_max_keysig_size ();
fprintf (stderr, "\nList contents are:\n(hash value, key length, index, %*s, keyword):\n", fprintf (stderr, "\nList contents are:\n(hash value, key length, index, %*s, keyword):\n",
field_width, "selchars"); field_width, "selchars");
@@ -667,3 +665,10 @@ Key_List::max_key_length ()
return _max_key_len; return _max_key_len;
} }
/* Returns number of key positions. */
int
Key_List::get_max_keysig_size ()
{
return option[ALLCHARS] ? _max_key_len : option.get_max_keysig_size ();
}

View File

@@ -51,6 +51,7 @@ private:
int _list_len; /* Length of head's Key_List, not counting duplicates. */ int _list_len; /* Length of head's Key_List, not counting duplicates. */
protected: protected:
int _total_keys; /* Total number of keys, counting duplicates. */ int _total_keys; /* Total number of keys, counting duplicates. */
int _size; /* Range of the hash table. */
private: private:
static int _determined[MAX_ALPHA_SIZE]; /* Used in function reorder, below. */ static int _determined[MAX_ALPHA_SIZE]; /* Used in function reorder, below. */
static int get_occurrence (KeywordExt *ptr); static int get_occurrence (KeywordExt *ptr);
@@ -79,6 +80,9 @@ public:
void reorder (); void reorder ();
void sort (); void sort ();
void read_keys (); void read_keys ();
int get_max_keysig_size ();
void set_asso_max (int r) { _size = r; }
int get_asso_max () { return _size; }
}; };
#endif #endif

View File

@@ -65,21 +65,21 @@ void KeywordExt::init_selchars (Vectors *v)
char *key_set = char *key_set =
new char[(option[ALLCHARS] ? _allchars_length : option.get_max_keysig_size ())]; new char[(option[ALLCHARS] ? _allchars_length : option.get_max_keysig_size ())];
char *ptr = key_set; char *ptr = key_set;
int i;
if (option[ALLCHARS]) if (option[ALLCHARS])
/* Use all the character positions in the KEY. */ /* Use all the character positions in the KEY. */
for (i = _allchars_length; i > 0; k++, ptr++, i--) for (int i = _allchars_length; i > 0; k++, ptr++, i--)
v->_occurrences[(unsigned char)(*ptr = *k)]++; v->_occurrences[(unsigned char)(*ptr = *k)]++;
else else
/* Only use those character positions specified by the user. */ /* Only use those character positions specified by the user. */
{ {
/* Iterate through the list of key_positions, initializing occurrences /* Iterate through the list of key_positions, initializing occurrences
table and selchars (via char * pointer ptr). */ table and selchars (via char * pointer ptr). */
PositionIterator iter (option.get_key_positions ());
for (option.reset (); (i = option.get ()) != EOS; ) for (int i; (i = iter.next ()) != PositionIterator::EOS; )
{ {
if (i == WORD_END) if (i == Positions::LASTCHAR)
/* Special notation for last KEY position, i.e. '$'. */ /* Special notation for last KEY position, i.e. '$'. */
*ptr = _allchars[_allchars_length - 1]; *ptr = _allchars[_allchars_length - 1];
else if (i <= _allchars_length) else if (i <= _allchars_length)

View File

@@ -29,7 +29,7 @@ int
main (int argc, char *argv[]) main (int argc, char *argv[])
{ {
/* Sets the Options. */ /* Sets the Options. */
option (argc, argv); option.parse_options (argc, argv);
/* Initializes the key word list. */ /* Initializes the key word list. */
Gen_Perf generate_table; Gen_Perf generate_table;

View File

@@ -57,92 +57,95 @@ static const char *const DEFAULT_WORDLIST_NAME = "wordlist";
/* Default delimiters that separate keywords from their attributes. */ /* Default delimiters that separate keywords from their attributes. */
static const char *const DEFAULT_DELIMITERS = ",\n"; static const char *const DEFAULT_DELIMITERS = ",\n";
int Options::_option_word;
int Options::_total_switches;
int Options::_total_keysig_size;
int Options::_size;
int Options::_key_pos;
int Options::_jump;
int Options::_initial_asso_value;
int Options::_argument_count;
int Options::_iterations;
char **Options::_argument_vector;
const char *Options::_function_name;
const char *Options::_key_name;
const char *Options::_initializer_suffix;
const char *Options::_class_name;
const char *Options::_hash_name;
const char *Options::_wordlist_name;
const char *Options::_delimiters;
char Options::_key_positions[MAX_KEY_POS];
/* Prints program usage to given stream. */ /* Prints program usage to given stream. */
void void
Options::short_usage (FILE * strm) Options::short_usage (FILE * stream) const
{ {
fprintf (strm, "Usage: %s [-cCdDef[num]F<initializers>GhH<hashname>i<init>Ijk<keys>K<keyname>lL<language>nN<function name>ors<size>S<switches>tTvW<wordlistname>Z<class name>7] [input-file]\n" fprintf (stream, "Usage: %s [-cCdDef[num]F<initializers>GhH<hashname>i<init>Ijk<keys>K<keyname>lL<language>nN<function name>ors<size>S<switches>tTvW<wordlistname>Z<class name>7] [input-file]\n"
"Try `%s --help' for more information.\n", "Try '%s --help' for more information.\n",
program_name, program_name); program_name, program_name);
} }
void void
Options::long_usage (FILE * strm) Options::long_usage (FILE * stream) const
{ {
fprintf (strm, fprintf (stream,
"GNU `gperf' generates perfect hash functions.\n" "GNU 'gperf' generates perfect hash functions.\n");
"\n" fprintf (stream, "\n");
"Usage: %s [OPTION]... [INPUT-FILE]\n" fprintf (stream,
"\n" "Usage: %s [OPTION]... [INPUT-FILE]\n",
program_name);
fprintf (stream, "\n");
fprintf (stream,
"If a long option shows an argument as mandatory, then it is mandatory\n" "If a long option shows an argument as mandatory, then it is mandatory\n"
"for the equivalent short option also.\n" "for the equivalent short option also.\n");
"\n" fprintf (stream, "\n");
"Input file interpretation:\n" fprintf (stream,
"Input file interpretation:\n");
fprintf (stream,
" -e, --delimiters=DELIMITER-LIST\n" " -e, --delimiters=DELIMITER-LIST\n"
" Allow user to provide a string containing delimiters\n" " Allow user to provide a string containing delimiters\n"
" used to separate keywords from their attributes.\n" " used to separate keywords from their attributes.\n"
" Default is \",\\n\".\n" " Default is \",\\n\".\n");
fprintf (stream,
" -t, --struct-type Allows the user to include a structured type\n" " -t, --struct-type Allows the user to include a structured type\n"
" declaration for generated code. Any text before %%%%\n" " declaration for generated code. Any text before %%%%\n"
" is considered part of the type declaration. Key\n" " is considered part of the type declaration. Key\n"
" words and additional fields may follow this, one\n" " words and additional fields may follow this, one\n"
" group of fields per line.\n" " group of fields per line.\n");
"\n" fprintf (stream, "\n");
"Language for the output code:\n" fprintf (stream,
"Language for the output code:\n");
fprintf (stream,
" -L, --language=LANGUAGE-NAME\n" " -L, --language=LANGUAGE-NAME\n"
" Generates code in the specified language. Languages\n" " Generates code in the specified language. Languages\n"
" handled are currently C++, ANSI-C, C, and KR-C. The\n" " handled are currently C++, ANSI-C, C, and KR-C. The\n"
" default is C.\n" " default is C.\n");
"\n" fprintf (stream, "\n");
"Details in the output code:\n" fprintf (stream,
"Details in the output code:\n");
fprintf (stream,
" -K, --slot-name=NAME Select name of the keyword component in the keyword\n" " -K, --slot-name=NAME Select name of the keyword component in the keyword\n"
" structure.\n" " structure.\n");
fprintf (stream,
" -F, --initializer-suffix=INITIALIZERS\n" " -F, --initializer-suffix=INITIALIZERS\n"
" Initializers for additional components in the keyword\n" " Initializers for additional components in the keyword\n"
" structure.\n" " structure.\n");
fprintf (stream,
" -H, --hash-fn-name=NAME\n" " -H, --hash-fn-name=NAME\n"
" Specify name of generated hash function. Default is\n" " Specify name of generated hash function. Default is\n"
" `hash'.\n" " 'hash'.\n");
fprintf (stream,
" -N, --lookup-fn-name=NAME\n" " -N, --lookup-fn-name=NAME\n"
" Specify name of generated lookup function. Default\n" " Specify name of generated lookup function. Default\n"
" name is `in_word_set'.\n" " name is 'in_word_set'.\n");
fprintf (stream,
" -Z, --class-name=NAME Specify name of generated C++ class. Default name is\n" " -Z, --class-name=NAME Specify name of generated C++ class. Default name is\n"
" `Perfect_Hash'.\n" " 'Perfect_Hash'.\n");
" -7, --seven-bit Assume 7-bit characters.\n" fprintf (stream,
" -7, --seven-bit Assume 7-bit characters.\n");
fprintf (stream,
" -c, --compare-strncmp Generate comparison code using strncmp rather than\n" " -c, --compare-strncmp Generate comparison code using strncmp rather than\n"
" strcmp.\n" " strcmp.\n");
fprintf (stream,
" -C, --readonly-tables Make the contents of generated lookup tables\n" " -C, --readonly-tables Make the contents of generated lookup tables\n"
" constant, i.e., readonly.\n" " constant, i.e., readonly.\n");
fprintf (stream,
" -E, --enum Define constant values using an enum local to the\n" " -E, --enum Define constant values using an enum local to the\n"
" lookup function rather than with defines.\n" " lookup function rather than with defines.\n");
fprintf (stream,
" -I, --includes Include the necessary system include file <string.h>\n" " -I, --includes Include the necessary system include file <string.h>\n"
" at the beginning of the code.\n" " at the beginning of the code.\n");
fprintf (stream,
" -G, --global Generate the static table of keywords as a static\n" " -G, --global Generate the static table of keywords as a static\n"
" global variable, rather than hiding it inside of the\n" " global variable, rather than hiding it inside of the\n"
" lookup function (which is the default behavior).\n" " lookup function (which is the default behavior).\n");
fprintf (stream,
" -W, --word-array-name=NAME\n" " -W, --word-array-name=NAME\n"
" Specify name of word list array. Default name is\n" " Specify name of word list array. Default name is\n"
" `wordlist'.\n" " 'wordlist'.\n");
fprintf (stream,
" -S, --switch=COUNT Causes the generated C code to use a switch\n" " -S, --switch=COUNT Causes the generated C code to use a switch\n"
" statement scheme, rather than an array lookup table.\n" " statement scheme, rather than an array lookup table.\n"
" This can lead to a reduction in both time and space\n" " This can lead to a reduction in both time and space\n"
@@ -152,13 +155,16 @@ Options::long_usage (FILE * strm)
" elements, a value of 2 generates 2 tables with 1/2\n" " elements, a value of 2 generates 2 tables with 1/2\n"
" the elements in each table, etc. If COUNT is very\n" " the elements in each table, etc. If COUNT is very\n"
" large, say 1000000, the generated C code does a\n" " large, say 1000000, the generated C code does a\n"
" binary search.\n" " binary search.\n");
fprintf (stream,
" -T, --omit-struct-type\n" " -T, --omit-struct-type\n"
" Prevents the transfer of the type declaration to the\n" " Prevents the transfer of the type declaration to the\n"
" output file. Use this option if the type is already\n" " output file. Use this option if the type is already\n"
" defined elsewhere.\n" " defined elsewhere.\n");
"\n" fprintf (stream, "\n");
"Algorithm employed by gperf:\n" fprintf (stream,
"Algorithm employed by gperf:\n");
fprintf (stream,
" -k, --key-positions=KEYS\n" " -k, --key-positions=KEYS\n"
" Select the key positions used in the hash function.\n" " Select the key positions used in the hash function.\n"
" The allowable choices range between 1-%d, inclusive.\n" " The allowable choices range between 1-%d, inclusive.\n"
@@ -166,59 +172,71 @@ Options::long_usage (FILE * strm)
" used, and key positions may occur in any order.\n" " used, and key positions may occur in any order.\n"
" Also, the meta-character '*' causes the generated\n" " Also, the meta-character '*' causes the generated\n"
" hash function to consider ALL key positions, and $\n" " hash function to consider ALL key positions, and $\n"
" indicates the ``final character'' of a key, e.g.,\n" " indicates the \"final character\" of a key, e.g.,\n"
" $,1,2,4,6-10.\n" " $,1,2,4,6-10.\n",
Positions::MAX_KEY_POS - 1);
fprintf (stream,
" -l, --compare-strlen Compare key lengths before trying a string\n" " -l, --compare-strlen Compare key lengths before trying a string\n"
" comparison. This helps cut down on the number of\n" " comparison. This helps cut down on the number of\n"
" string comparisons made during the lookup.\n" " string comparisons made during the lookup.\n");
fprintf (stream,
" -D, --duplicates Handle keywords that hash to duplicate values. This\n" " -D, --duplicates Handle keywords that hash to duplicate values. This\n"
" is useful for certain highly redundant keyword sets.\n" " is useful for certain highly redundant keyword sets.\n");
" -f, --fast=ITERATIONS Generate the gen-perf.hash function ``fast''. This\n" fprintf (stream,
" -f, --fast=ITERATIONS Generate the gen-perf.hash function \"fast\". This\n"
" decreases gperf's running time at the cost of\n" " decreases gperf's running time at the cost of\n"
" minimizing generated table size. The numeric\n" " minimizing generated table size. The numeric\n"
" argument represents the number of times to iterate\n" " argument represents the number of times to iterate\n"
" when resolving a collision. `0' means ``iterate by\n" " when resolving a collision. '0' means \"iterate by\n"
" the number of keywords''.\n" " the number of keywords\".\n");
fprintf (stream,
" -i, --initial-asso=N Provide an initial value for the associate values\n" " -i, --initial-asso=N Provide an initial value for the associate values\n"
" array. Default is 0. Setting this value larger helps\n" " array. Default is 0. Setting this value larger helps\n"
" inflate the size of the final table.\n" " inflate the size of the final table.\n");
" -j, --jump=JUMP-VALUE Affects the ``jump value'', i.e., how far to advance\n" fprintf (stream,
" -j, --jump=JUMP-VALUE Affects the \"jump value\", i.e., how far to advance\n"
" the associated character value upon collisions. Must\n" " the associated character value upon collisions. Must\n"
" be an odd number, default is %d.\n" " be an odd number, default is %d.\n",
DEFAULT_JUMP_VALUE);
fprintf (stream,
" -n, --no-strlen Do not include the length of the keyword when\n" " -n, --no-strlen Do not include the length of the keyword when\n"
" computing the hash function.\n" " computing the hash function.\n");
fprintf (stream,
" -o, --occurrence-sort Reorders input keys by frequency of occurrence of\n" " -o, --occurrence-sort Reorders input keys by frequency of occurrence of\n"
" the key sets. This should decrease the search time\n" " the key sets. This should decrease the search time\n"
" dramatically.\n" " dramatically.\n");
fprintf (stream,
" -r, --random Utilizes randomness to initialize the associated\n" " -r, --random Utilizes randomness to initialize the associated\n"
" values table.\n" " values table.\n");
fprintf (stream,
" -s, --size-multiple=N Affects the size of the generated hash table. The\n" " -s, --size-multiple=N Affects the size of the generated hash table. The\n"
" numeric argument N indicates ``how many times larger\n" " numeric argument N indicates \"how many times larger\n"
" or smaller'' the associated value range should be,\n" " or smaller\" the associated value range should be,\n"
" in relationship to the number of keys, e.g. a value\n" " in relationship to the number of keys, e.g. a value\n"
" of 3 means ``allow the maximum associated value to\n" " of 3 means \"allow the maximum associated value to\n"
" be about 3 times larger than the number of input\n" " be about 3 times larger than the number of input\n"
" keys.'' Conversely, a value of -3 means ``make the\n" " keys\". Conversely, a value of -3 means \"make the\n"
" maximum associated value about 3 times smaller than\n" " maximum associated value about 3 times smaller than\n"
" the number of input keys. A larger table should\n" " the number of input keys\". A larger table should\n"
" decrease the time required for an unsuccessful\n" " decrease the time required for an unsuccessful\n"
" search, at the expense of extra table space. Default\n" " search, at the expense of extra table space. Default\n"
" value is 1.\n" " value is 1.\n");
"\n" fprintf (stream, "\n");
fprintf (stream,
"Informative output:\n" "Informative output:\n"
" -h, --help Print this message.\n" " -h, --help Print this message.\n"
" -v, --version Print the gperf version number.\n" " -v, --version Print the gperf version number.\n"
" -d, --debug Enables the debugging option (produces verbose\n" " -d, --debug Enables the debugging option (produces verbose\n"
" output to the standard error).\n" " output to the standard error).\n");
"\n" fprintf (stream, "\n");
"Report bugs to <bug-gnu-utils@gnu.org>.\n" fprintf (stream,
, program_name, MAX_KEY_POS - 1, DEFAULT_JUMP_VALUE); "Report bugs to <bug-gnu-utils@gnu.org>.\n");
} }
/* Output command-line Options. */ /* Prints the given options. */
void void
Options::print_options () Options::print_options () const
{ {
int i; int i;
@@ -278,110 +296,96 @@ Options::print_options ()
class PositionStringParser class PositionStringParser
{ {
public: public:
PositionStringParser (const char *s, int lo, int hi, int word_end, int bad_val, int key_end); PositionStringParser (const char *str, int low_bound, int high_bound, int end_word_marker, int error_value, int end_marker);
int nextPosition (); int nextPosition ();
private: private:
const char *str; /* A pointer to the string provided by the user. */ /* A pointer to the string provided by the user. */
int end; /* Value returned after last key is processed. */ const char * _str;
int end_word; /* A value marking the abstract ``end of word'' ( usually '$'). */ /* Smallest possible value, inclusive. */
int error_value; /* Error value returned when input is syntactically erroneous. */ int const _low_bound;
int hi_bound; /* Greatest possible value, inclusive. */ /* Greatest possible value, inclusive. */
int lo_bound; /* Smallest possible value, inclusive. */ int const _high_bound;
int size; /* A value marking the abstract "end of word" ( usually '$'). */
int curr_value; int const _end_word_marker;
int upper_bound; /* Error value returned when input is syntactically erroneous. */
int const _error_value;
/* Value returned after last key is processed. */
int const _end_marker;
int _size;
int _curr_value;
int _upper_bound;
}; };
PositionStringParser::PositionStringParser (const char *s, int lo, int hi, int word_end, int bad_val, int key_end) PositionStringParser::PositionStringParser (const char *str, int low_bound, int high_bound, int end_word_marker, int error_value, int end_marker)
: str (s), end (key_end), end_word (word_end), error_value (bad_val), hi_bound (hi), lo_bound (lo), : _str (str),
size (0), curr_value (0), upper_bound (0) _low_bound (low_bound),
_high_bound (high_bound),
_end_word_marker (end_word_marker),
_error_value (error_value),
_end_marker (end_marker),
_size (0),
_curr_value (0),
_upper_bound (0)
{ {
} }
int PositionStringParser::nextPosition () int PositionStringParser::nextPosition ()
{ {
if (size) if (_size)
{ {
if (++curr_value >= upper_bound) if (++_curr_value >= _upper_bound)
size = 0; _size = 0;
return curr_value; return _curr_value;
} }
else else
{ {
while (*str) while (*_str)
switch (*str) switch (*_str)
{ {
default: return error_value; default: return _error_value;
case ',': str++; break; case ',': _str++; break;
case '$': str++; return end_word; case '$': _str++; return _end_word_marker;
case '0': case '1': case '2': case '3': case '4': case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': case '5': case '6': case '7': case '8': case '9':
for (curr_value = 0; isdigit ((unsigned char)(*str)); str++) for (_curr_value = 0; isdigit ((unsigned char)(*_str)); _str++)
curr_value = curr_value * 10 + (*str - '0'); _curr_value = _curr_value * 10 + (*_str - '0');
if (*str == '-') if (*_str == '-')
{ {
for (size = 1, upper_bound = 0; for (_size = 1, _upper_bound = 0;
isdigit ((unsigned char)(*++str)); isdigit ((unsigned char)(*++_str));
upper_bound = upper_bound * 10 + (*str - '0')); _upper_bound = _upper_bound * 10 + (*_str - '0'));
if (upper_bound <= curr_value || upper_bound > hi_bound) if (_upper_bound <= _curr_value || _upper_bound > _high_bound)
return error_value; return _error_value;
} }
return curr_value >= lo_bound && curr_value <= hi_bound return _curr_value >= _low_bound && _curr_value <= _high_bound
? curr_value : error_value; ? _curr_value : _error_value;
} }
return end; return _end_marker;
} }
} }
/* Sorts the key positions *IN REVERSE ORDER!!*
This makes further routines more efficient. Especially when generating code.
Uses a simple Insertion Sort since the set is probably ordered.
Returns 1 if there are no duplicates, 0 otherwise. */
inline int
Options::key_sort (char *base, int len)
{
/* Bubble sort. */
for (int i = 1; i < len; i++)
{
int j;
int tmp;
for (j = i, tmp = base[j]; j > 0 && tmp >= base[j - 1]; j--)
if ((base[j] = base[j - 1]) == tmp) /* oh no, a duplicate!!! */
return 0;
base[j] = tmp;
}
return 1;
}
/* Sets the default Options. */ /* Sets the default Options. */
Options::Options () Options::Options ()
: _option_word (DEFAULTCHARS | C),
_iterations (0),
_jump (DEFAULT_JUMP_VALUE),
_initial_asso_value (0),
_total_switches (1),
_size_multiple (1),
_function_name (DEFAULT_NAME),
_key_name (DEFAULT_KEY),
_initializer_suffix (DEFAULT_INITIALIZER_SUFFIX),
_class_name (DEFAULT_CLASS_NAME),
_hash_name (DEFAULT_HASH_NAME),
_wordlist_name (DEFAULT_WORDLIST_NAME),
_delimiters (DEFAULT_DELIMITERS),
_key_positions (1, Positions::LASTCHAR)
{ {
_key_positions[0] = WORD_START;
_key_positions[1] = WORD_END;
_key_positions[2] = EOS;
_total_keysig_size = 2;
_delimiters = DEFAULT_DELIMITERS;
_jump = DEFAULT_JUMP_VALUE;
_option_word = DEFAULTCHARS | C;
_function_name = DEFAULT_NAME;
_key_name = DEFAULT_KEY;
_initializer_suffix = DEFAULT_INITIALIZER_SUFFIX;
_hash_name = DEFAULT_HASH_NAME;
_wordlist_name = DEFAULT_WORDLIST_NAME;
_class_name = DEFAULT_CLASS_NAME;
_size = 1;
_total_switches = 1;
_iterations = 0;
_initial_asso_value = 0;
} }
/* Dumps option status when debug is set. */ /* Dumps option status when debug is set. */
@@ -390,8 +394,6 @@ Options::~Options ()
{ {
if (_option_word & DEBUG) if (_option_word & DEBUG)
{ {
char *ptr;
fprintf (stderr, "\ndumping Options:" fprintf (stderr, "\ndumping Options:"
"\nDEBUG is.......: %s" "\nDEBUG is.......: %s"
"\nORDER is.......: %s" "\nORDER is.......: %s"
@@ -421,7 +423,7 @@ Options::~Options ()
"\nkey name = %s" "\nkey name = %s"
"\ninitializer suffix = %s" "\ninitializer suffix = %s"
"\njump value = %d" "\njump value = %d"
"\nmax associated value = %d" "\nhash table size multiplier = %d"
"\ninitial associated value = %d" "\ninitial associated value = %d"
"\ndelimiters = %s" "\ndelimiters = %s"
"\nnumber of switch statements = %d\n", "\nnumber of switch statements = %d\n",
@@ -448,19 +450,22 @@ Options::~Options ()
_option_word & SEVENBIT ? "enabled" : "disabled", _option_word & SEVENBIT ? "enabled" : "disabled",
_iterations, _iterations,
_function_name, _hash_name, _wordlist_name, _key_name, _function_name, _hash_name, _wordlist_name, _key_name,
_initializer_suffix, _jump, _size - 1, _initial_asso_value, _initializer_suffix, _jump, _size_multiple, _initial_asso_value,
_delimiters, _total_switches); _delimiters, _total_switches);
if (_option_word & ALLCHARS) if (_option_word & ALLCHARS)
fprintf (stderr, "all characters are used in the hash function\n"); fprintf (stderr, "all characters are used in the hash function\n");
else
{
fprintf (stderr, "maximum keysig size = %d\nkey positions are: \n", fprintf (stderr, "maximum keysig size = %d\nkey positions are: \n",
_total_keysig_size); _key_positions.get_size());
for (ptr = _key_positions; *ptr != EOS; ptr++) PositionIterator iter (_key_positions);
if (*ptr == WORD_END) for (int pos; (pos = iter.next()) != PositionIterator::EOS; )
if (pos == Positions::LASTCHAR)
fprintf (stderr, "$\n"); fprintf (stderr, "$\n");
else else
fprintf (stderr, "%d\n", *ptr); fprintf (stderr, "%d\n", pos);
}
fprintf (stderr, "finished dumping Options\n"); fprintf (stderr, "finished dumping Options\n");
} }
@@ -505,7 +510,7 @@ static const struct option long_options[] =
}; };
void void
Options::operator() (int argc, char *argv[]) Options::parse_options (int argc, char *argv[])
{ {
int option_char; int option_char;
@@ -615,43 +620,52 @@ Options::operator() (int argc, char *argv[])
case 'k': /* Sets key positions used for hash function. */ case 'k': /* Sets key positions used for hash function. */
{ {
const int BAD_VALUE = -1; const int BAD_VALUE = -1;
const int EOS = PositionIterator::EOS;
int value; int value;
PositionStringParser sparser (/*getopt*/optarg, 1, MAX_KEY_POS - 1, WORD_END, BAD_VALUE, EOS); PositionStringParser sparser (/*getopt*/optarg, 1, Positions::MAX_KEY_POS - 1, Positions::LASTCHAR, BAD_VALUE, EOS);
if (/*getopt*/optarg [0] == '*') /* Use all the characters for hashing!!!! */ if (/*getopt*/optarg [0] == '*') /* Use all the characters for hashing!!!! */
_option_word = (_option_word & ~DEFAULTCHARS) | ALLCHARS; _option_word = (_option_word & ~DEFAULTCHARS) | ALLCHARS;
else else
{ {
char *key_pos; unsigned char *key_positions = _key_positions.pointer();
unsigned char *key_pos;
for (key_pos = _key_positions; (value = sparser.nextPosition()) != EOS; key_pos++) for (key_pos = key_positions; (value = sparser.nextPosition()) != EOS; key_pos++)
if (value == BAD_VALUE) if (value == BAD_VALUE)
{ {
fprintf (stderr, "Illegal key value or range, use 1,2,3-%d,'$' or '*'.\n", fprintf (stderr, "Illegal key value or range, use 1,2,3-%d,'$' or '*'.\n",
MAX_KEY_POS - 1); Positions::MAX_KEY_POS - 1);
short_usage (stderr); short_usage (stderr);
exit (1); exit (1);
} }
else else
*key_pos = value;; *key_pos = value;
*key_pos = EOS; *key_pos = EOS;
if (! (_total_keysig_size = (key_pos - _key_positions))) unsigned int total_keysig_size = key_pos - key_positions;
if (total_keysig_size == 0)
{ {
fprintf (stderr, "No keys selected.\n"); fprintf (stderr, "No keys selected.\n");
short_usage (stderr); short_usage (stderr);
exit (1); exit (1);
} }
else if (! key_sort (_key_positions, _total_keysig_size)) _key_positions.set_size (total_keysig_size);
/* Sorts the key positions *IN REVERSE ORDER!!*
This makes further routines more efficient. Especially
when generating code. */
if (! _key_positions.sort())
{ {
fprintf (stderr, "Duplicate keys selected\n"); fprintf (stderr, "Duplicate keys selected\n");
short_usage (stderr); short_usage (stderr);
exit (1); exit (1);
} }
if (_total_keysig_size != 2 if (!(_key_positions.get_size() == 2
|| (_key_positions[0] != 1 || _key_positions[1] != WORD_END)) && _key_positions[0] == 1
&& _key_positions[1] == Positions::LASTCHAR))
_option_word &= ~DEFAULTCHARS; _option_word &= ~DEFAULTCHARS;
} }
break; break;
@@ -710,8 +724,8 @@ Options::operator() (int argc, char *argv[])
} }
case 's': /* Range of associated values, determines size of final table. */ case 's': /* Range of associated values, determines size of final table. */
{ {
if (abs (_size = atoi (/*getopt*/optarg)) > 50) if (abs (_size_multiple = atoi (/*getopt*/optarg)) > 50)
fprintf (stderr, "%d is excessive, did you really mean this?! (try `%s --help' for help)\n", _size, program_name); fprintf (stderr, "%d is excessive, did you really mean this?! (try `%s --help' for help)\n", _size_multiple, program_name);
break; break;
} }
case 'S': /* Generate switch statement output, rather than lookup table. */ case 'S': /* Generate switch statement output, rather than lookup table. */

View File

@@ -22,56 +22,139 @@ along with GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
/* This module provides a uniform interface to the various options available /* This module provides a uniform interface to the various options available
to a user of the gperf hash function generator. In addition to the to a user of the gperf hash function generator. */
run-time options, found in the Option_Type below, there is also the
hash table Size and the Keys to be used in the hashing.
The overall design of this module was an experiment in using C++
classes as a mechanism to enhance centralization of option and
and error handling, which tend to get out of hand in a C program. */
#ifndef options_h #ifndef options_h
#define options_h 1 #define options_h 1
#include <stdio.h> #include <stdio.h>
/* Enumerate the potential debugging Options. */ /* Enumeration of the possible boolean options. */
enum Option_Type enum Option_Type
{ {
DEBUG = 01, /* Enable debugging (prints diagnostics to stderr). */ /* Enable debugging (prints diagnostics to stderr). */
ORDER = 02, /* Apply ordering heuristic to speed-up search time. */ DEBUG = 1 << 0,
ALLCHARS = 04, /* Use all characters in hash function. */
TYPE = 010, /* Handle user-defined type structured keyword input. */ /* Apply ordering heuristic to speed-up search time. */
RANDOM = 020, /* Randomly initialize the associated values table. */ ORDER = 1 << 1,
DEFAULTCHARS = 040, /* Make default char positions be 1,$ (end of keyword). */
SWITCH = 0100, /* Generate switch output to save space. */ /* Use all characters in hash function. */
NOLENGTH = 0200, /* Don't include keyword length in hash computations. */ ALLCHARS = 1 << 2,
LENTABLE = 0400, /* Generate a length table for string comparison. */
DUP = 01000, /* Handle duplicate hash values for keywords. */ /* Handle user-defined type structured keyword input. */
FAST = 02000, /* Generate the hash function ``fast.'' */ TYPE = 1 << 3,
NOTYPE = 04000, /* Don't include user-defined type definition in output -- it's already defined elsewhere. */
COMP = 010000, /* Generate strncmp rather than strcmp. */ /* Randomly initialize the associated values table. */
GLOBAL = 020000, /* Make the keyword table a global variable. */ RANDOM = 1 << 4,
CONST = 040000, /* Make the generated tables readonly (const). */
KRC = 0100000, /* Generate K&R C code: no prototypes, no const. */ /* Make default char positions be 1,$ (end of keyword). */
C = 0200000, /* Generate C code: no prototypes, but const (user can #define it away). */ DEFAULTCHARS = 1 << 5,
ANSIC = 0400000, /* Generate ISO/ANSI C code: prototypes and const, but no class. */
CPLUSPLUS = 01000000, /* Generate C++ code: prototypes, const, class, inline, enum. */ /* Generate switch output to save space. */
ENUM = 02000000, /* Use enum for constants. */ SWITCH = 1 << 6,
INCLUDE = 04000000, /* Generate #include statements. */
SEVENBIT = 010000000 /* Assume 7-bit, not 8-bit, characters. */ /* Don't include keyword length in hash computations. */
NOLENGTH = 1 << 7,
/* Generate a length table for string comparison. */
LENTABLE = 1 << 8,
/* Handle duplicate hash values for keywords. */
DUP = 1 << 9,
/* Generate the hash function "fast". */
FAST = 1 << 10,
/* Don't include user-defined type definition in output -- it's already
defined elsewhere. */
NOTYPE = 1 << 11,
/* Generate strncmp rather than strcmp. */
COMP = 1 << 12,
/* Make the keyword table a global variable. */
GLOBAL = 1 << 13,
/* Make the generated tables readonly (const). */
CONST = 1 << 14,
/* Generate K&R C code: no prototypes, no const. */
KRC = 1 << 15,
/* Generate C code: no prototypes, but const (user can #define it away). */
C = 1 << 16,
/* Generate ISO/ANSI C code: prototypes and const, but no class. */
ANSIC = 1 << 17,
/* Generate C++ code: prototypes, const, class, inline, enum. */
CPLUSPLUS = 1 << 18,
/* Use enum for constants. */
ENUM = 1 << 19,
/* Generate #include statements. */
INCLUDE = 1 << 20,
/* Assume 7-bit, not 8-bit, characters. */
SEVENBIT = 1 << 21
}; };
/* Define some useful constants (these don't really belong here, but I'm /* This class denotes a set of key positions. */
not sure where else to put them!). These should be consts, but g++
doesn't seem to do the right thing with them at the moment... ;-( */
enum class Positions
{ {
MAX_KEY_POS = 128 - 1, /* Max size of each word's key set. */ friend class PositionIterator;
WORD_START = 1, /* Signals the start of a word. */ public:
WORD_END = 0, /* Signals the end of a word. */ /* Denotes the last char of a keyword, depending on the keyword's length. */
EOS = MAX_KEY_POS /* Signals end of the key list. */ static const int LASTCHAR = 0;
/* Maximum size of the set. */
static const int MAX_KEY_POS = 127;
/* Constructors. */
Positions ();
Positions (int key1);
Positions (int key1, int key2);
/* Accessors. */
int operator[] (unsigned int index) const;
unsigned int get_size () const;
/* Write access. */
unsigned char * pointer ();
void set_size (unsigned int size);
/* Sorts the array in reverse order.
Returns 1 if there are no duplicates, 0 otherwise. */
int sort ();
private:
/* Number of positions, excluding the terminating PositionIterator::EOS. */
unsigned int _size;
/* Array of positions. 1 for the first char, 2 for the second char etc.,
LASTCHAR for the last char. PositionIterator::EOS past the end. */
unsigned char _positions[MAX_KEY_POS];
};
/* This class denotes an iterator through a set of key positions. */
class PositionIterator
{
public:
/* Initializes an iterator through POSITIONS. */
PositionIterator (Positions const& positions);
/* End of iteration marker. */
static const int EOS = Positions::MAX_KEY_POS;
/* Retrieves the next position, or EOS past the end. */
int next ();
private:
const Positions& _set;
int _index;
}; };
/* Class manager for gperf program Options. */ /* Class manager for gperf program Options. */
@@ -79,51 +162,119 @@ enum
class Options class Options
{ {
public: public:
/* Constructor. */
Options (); Options ();
/* Destructor. */
~Options (); ~Options ();
int operator[] (Option_Type option);
void operator() (int argc, char *argv[]); /* Parses the options given in the command-line arguments. */
static void print_options (); void parse_options (int argc, char *argv[]);
static void set_asso_max (int r);
static int get_asso_max (); /* Prints the given options. */
static void reset (); void print_options () const;
static int get ();
static int get_iterations (); /* Accessors. */
static int get_max_keysig_size ();
static void set_keysig_size (int); /* Tests a given boolean option. Returns 1 if set, 0 otherwise. */
static int get_jump (); int operator[] (Option_Type option) const;
static int initial_value ();
static int get_total_switches (); /* Returns the iterations value. */
static const char *get_function_name (); int get_iterations () const;
static const char *get_key_name ();
static const char *get_initializer_suffix (); /* Returns the jump value. */
static const char *get_class_name (); int get_jump () const;
static const char *get_hash_name ();
static const char *get_wordlist_name (); /* Returns the initial associated character value. */
static const char *get_delimiter (); int get_initial_asso_value () const;
/* Returns the total number of switch statements to generate. */
int get_total_switches () const;
/* Returns the factor by which to multiply the generated table's size. */
int get_size_multiple () const;
/* Returns the generated function name. */
const char * get_function_name () const;
/* Returns the keyword key name. */
const char * get_key_name () const;
/* Returns the struct initializer suffix. */
const char * get_initializer_suffix () const;
/* Returns the generated class name. */
const char * get_class_name () const;
/* Returns the hash function name. */
const char * get_hash_name () const;
/* Returns the hash table array name. */
const char * get_wordlist_name () const;
/* Returns the string used to delimit keywords from other attributes. */
const char * get_delimiter () const;
/* Returns key positions. */
const Positions& get_key_positions () const;
/* Returns total distinct key positions. */
int get_max_keysig_size () const;
private: private:
static int _option_word; /* Holds the user-specified Options. */ /* Prints program usage to given stream. */
static int _total_switches; /* Number of switch statements to generate. */ void short_usage (FILE * stream) const;
static int _total_keysig_size; /* Total number of distinct key_positions. */
static int _size; /* Range of the hash table. */ /* Prints program usage to given stream. */
static int _key_pos; /* Tracks current key position for Iterator. */ void long_usage (FILE * stream) const;
static int _jump; /* Jump length when trying alternative values. */
static int _initial_asso_value; /* Initial value for asso_values table. */ /* Records count of command-line arguments. */
static int _argument_count; /* Records count of command-line arguments. */ int _argument_count;
static int _iterations; /* Amount to iterate when a collision occurs. */
static char **_argument_vector; /* Stores a pointer to command-line vector. */ /* Stores a pointer to command-line argument vector. */
static const char *_function_name; /* Names used for generated lookup function. */ char **_argument_vector;
static const char *_key_name; /* Name used for keyword key. */
static const char *_initializer_suffix; /* Suffix for empty struct initializers. */ /* Holds the boolean options. */
static const char *_class_name; /* Name used for generated C++ class. */ int _option_word;
static const char *_hash_name; /* Name used for generated hash function. */
static const char *_wordlist_name; /* Name used for hash table array. */ /* Amount to iterate when a collision occurs. */
static const char *_delimiters; /* Separates keywords from other attributes. */ int _iterations;
static char _key_positions[MAX_KEY_POS]; /* Contains user-specified key choices. */
static int key_sort (char *base, int len); /* Sorts key positions in REVERSE order. */ /* Jump length when trying alternative values. */
static void short_usage (FILE * strm); /* Prints proper program usage. */ int _jump;
static void long_usage (FILE * strm); /* Prints proper program usage. */
/* Initial value for asso_values table. */
int _initial_asso_value;
/* Number of switch statements to generate. */
int _total_switches;
/* Factor by which to multiply the generated table's size. */
int _size_multiple;
/* Names used for generated lookup function. */
const char *_function_name;
/* Name used for keyword key. */
const char *_key_name;
/* Suffix for empty struct initializers. */
const char *_initializer_suffix;
/* Name used for generated C++ class. */
const char *_class_name;
/* Name used for generated hash function. */
const char *_hash_name;
/* Name used for hash table array. */
const char *_wordlist_name;
/* Separates keywords from other attributes. */
const char *_delimiters;
/* Contains user-specified key choices. */
Positions _key_positions;
}; };
/* Global option coordinator for the entire program. */ /* Global option coordinator for the entire program. */

View File

@@ -19,128 +19,193 @@ You should have received a copy of the GNU General Public License
along with GNU GPERF; see the file COPYING. If not, write to the Free along with GNU GPERF; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
/* TRUE if option enable, else FALSE. */ INLINE
Positions::Positions ()
: _size (0)
{
_positions[0] = PositionIterator::EOS;
}
INLINE
Positions::Positions (int key1)
: _size (1)
{
_positions[0] = key1;
_positions[1] = PositionIterator::EOS;
}
INLINE
Positions::Positions (int key1, int key2)
: _size (2)
{
_positions[0] = key1;
_positions[1] = key2;
_positions[2] = PositionIterator::EOS;
}
INLINE int INLINE int
Options::operator[] (Option_Type option) Positions::operator[] (unsigned int index) const
{ {
return _option_word & option; return _positions[index];
} }
/* Initializes the key Iterator. */ INLINE unsigned int
INLINE void Positions::get_size () const
Options::reset ()
{
_key_pos = 0;
}
/* Returns current key_position and advance index. */
INLINE int
Options::get ()
{
return _key_positions[_key_pos++];
}
/* Sets the size of the table size. */
INLINE void
Options::set_asso_max (int r)
{
_size = r;
}
/* Returns the size of the table size. */
INLINE int
Options::get_asso_max ()
{ {
return _size; return _size;
} }
/* Returns total distinct key positions. */ INLINE unsigned char *
INLINE int Positions::pointer ()
Options::get_max_keysig_size ()
{ {
return _total_keysig_size; return _positions;
} }
/* Sets total distinct key positions. */
INLINE void INLINE void
Options::set_keysig_size (int size) Positions::set_size (unsigned int size)
{ {
_total_keysig_size = size; _size = size;
}
/* Sorts the array in reverse order.
Returns 1 if there are no duplicates, 0 otherwise. */
INLINE int
Positions::sort ()
{
/* Bubble sort. */
int duplicate_free = 1;
unsigned char *base = _positions;
unsigned int len = _size;
for (unsigned int i = 1; i < len; i++)
{
unsigned int j;
int tmp;
for (j = i, tmp = base[j]; j > 0 && tmp >= base[j - 1]; j--)
if ((base[j] = base[j - 1]) == tmp) /* oh no, a duplicate!!! */
duplicate_free = 0;
base[j] = tmp;
}
return duplicate_free;
}
INLINE
PositionIterator::PositionIterator (Positions const& positions)
: _set (positions),
_index (0)
{
}
INLINE int
PositionIterator::next ()
{
return _set._positions[_index++];
}
/* Tests a given boolean option. Returns 1 if set, 0 otherwise. */
INLINE int
Options::operator[] (Option_Type option) const
{
return _option_word & option;
}
/* Returns the iterations value. */
INLINE int
Options::get_iterations () const
{
return _iterations;
} }
/* Returns the jump value. */ /* Returns the jump value. */
INLINE int INLINE int
Options::get_jump () Options::get_jump () const
{ {
return _jump; return _jump;
} }
/* Returns the initial associated character value. */
INLINE int
Options::get_initial_asso_value () const
{
return _initial_asso_value;
}
/* Returns the total number of switch statements to generate. */
INLINE int
Options::get_total_switches () const
{
return _total_switches;
}
/* Returns the factor by which to multiply the generated table's size. */
INLINE int
Options::get_size_multiple () const
{
return _size_multiple;
}
/* Returns the generated function name. */ /* Returns the generated function name. */
INLINE const char * INLINE const char *
Options::get_function_name () Options::get_function_name () const
{ {
return _function_name; return _function_name;
} }
/* Returns the keyword key name. */ /* Returns the keyword key name. */
INLINE const char * INLINE const char *
Options::get_key_name () Options::get_key_name () const
{ {
return _key_name; return _key_name;
} }
/* Returns the struct initializer suffix. */ /* Returns the struct initializer suffix. */
INLINE const char * INLINE const char *
Options::get_initializer_suffix () Options::get_initializer_suffix () const
{ {
return _initializer_suffix; return _initializer_suffix;
} }
/* Returns the generated class name. */
INLINE const char *
Options::get_class_name () const
{
return _class_name;
}
/* Returns the hash function name. */ /* Returns the hash function name. */
INLINE const char * INLINE const char *
Options::get_hash_name () Options::get_hash_name () const
{ {
return _hash_name; return _hash_name;
} }
/* Returns the hash table array name. */ /* Returns the hash table array name. */
INLINE const char * INLINE const char *
Options::get_wordlist_name () Options::get_wordlist_name () const
{ {
return _wordlist_name; return _wordlist_name;
} }
/* Returns the generated class name. */
INLINE const char *
Options::get_class_name ()
{
return _class_name;
}
/* Returns the initial associated character value. */
INLINE int
Options::initial_value ()
{
return _initial_asso_value;
}
/* Returns the iterations value. */
INLINE int
Options::get_iterations ()
{
return _iterations;
}
/* Returns the string used to delimit keywords from other attributes. */ /* Returns the string used to delimit keywords from other attributes. */
INLINE const char * INLINE const char *
Options::get_delimiter () Options::get_delimiter () const
{ {
return _delimiters; return _delimiters;
} }
/* Gets the total number of switch statements to generate. */ /* Returns key positions. */
INLINE int INLINE const Positions&
Options::get_total_switches () Options::get_key_positions () const
{ {
return _total_switches; return _key_positions;
}
/* Returns total distinct key positions. */
INLINE int
Options::get_max_keysig_size () const
{
return _key_positions.get_size();
} }

View File

@@ -470,16 +470,34 @@ Output::output_hash_function ()
printf (" return %sasso_values[%sstr[len - 1]] + asso_values[%sstr[0]];\n", printf (" return %sasso_values[%sstr[len - 1]] + asso_values[%sstr[0]];\n",
option[NOLENGTH] ? "" : "len + ", option[NOLENGTH] ? "" : "len + ",
char_to_index, char_to_index); char_to_index, char_to_index);
else if (option[ALLCHARS])
{
/* User wants *all* characters considered in hash. */
printf (" register int hval = %s;\n\n"
" switch (%s)\n"
" {\n"
" default:\n",
option[NOLENGTH] ? "0" : "len",
option[NOLENGTH] ? "len" : "hval");
for (int i = _max_key_len; i > 0; i--)
printf (" case %d:\n"
" hval += asso_values[%sstr[%d]];\n",
i, char_to_index, i - 1);
printf (" break;\n"
" }\n"
" return hval;\n");
}
else else
{ {
PositionIterator iter (option.get_key_positions());
int key_pos; int key_pos;
option.reset ();
/* Get first (also highest) key position. */ /* Get first (also highest) key position. */
key_pos = option.get (); key_pos = iter.next ();
if (!option[ALLCHARS] && (key_pos == WORD_END || key_pos <= _min_key_len)) if (key_pos == Positions::LASTCHAR || key_pos <= _min_key_len)
{ {
/* We can perform additional optimizations here: /* We can perform additional optimizations here:
Write it out as a single expression. Note that the values Write it out as a single expression. Note that the values
@@ -489,16 +507,16 @@ Output::output_hash_function ()
printf (" return %s", printf (" return %s",
option[NOLENGTH] ? "" : "len + "); option[NOLENGTH] ? "" : "len + ");
for (; key_pos != WORD_END; ) for (; key_pos != Positions::LASTCHAR; )
{ {
printf ("asso_values[%sstr[%d]]", char_to_index, key_pos - 1); printf ("asso_values[%sstr[%d]]", char_to_index, key_pos - 1);
if ((key_pos = option.get ()) != EOS) if ((key_pos = iter.next ()) != PositionIterator::EOS)
printf (" + "); printf (" + ");
else else
break; break;
} }
if (key_pos == WORD_END) if (key_pos == Positions::LASTCHAR)
printf ("asso_values[%sstr[len - 1]]", char_to_index); printf ("asso_values[%sstr[len - 1]]", char_to_index);
printf (";\n"); printf (";\n");
@@ -513,25 +531,11 @@ Output::output_hash_function ()
option[NOLENGTH] ? "0" : "len", option[NOLENGTH] ? "0" : "len",
option[NOLENGTH] ? "len" : "hval"); option[NOLENGTH] ? "len" : "hval");
/* User wants *all* characters considered in hash. */ while (key_pos != Positions::LASTCHAR && key_pos > _max_key_len)
if (option[ALLCHARS]) if ((key_pos = iter.next ()) == PositionIterator::EOS)
{
for (int i = _max_key_len; i > 0; i--)
printf (" case %d:\n"
" hval += asso_values[%sstr[%d]];\n",
i, char_to_index, i - 1);
printf (" break;\n"
" }\n"
" return hval;\n");
}
else /* do the hard part... */
{
while (key_pos != WORD_END && key_pos > _max_key_len)
if ((key_pos = option.get ()) == EOS)
break; break;
if (key_pos != EOS && key_pos != WORD_END) if (key_pos != PositionIterator::EOS && key_pos != Positions::LASTCHAR)
{ {
int i = key_pos; int i = key_pos;
do do
@@ -542,9 +546,9 @@ Output::output_hash_function ()
printf (" hval += asso_values[%sstr[%d]];\n", printf (" hval += asso_values[%sstr[%d]];\n",
char_to_index, key_pos - 1); char_to_index, key_pos - 1);
key_pos = option.get (); key_pos = iter.next ();
} }
while (key_pos != EOS && key_pos != WORD_END); while (key_pos != PositionIterator::EOS && key_pos != Positions::LASTCHAR);
for ( ; i >= _min_key_len; i--) for ( ; i >= _min_key_len; i--)
printf (" case %d:\n", i); printf (" case %d:\n", i);
@@ -553,12 +557,11 @@ Output::output_hash_function ()
printf (" break;\n" printf (" break;\n"
" }\n" " }\n"
" return hval"); " return hval");
if (key_pos == WORD_END) if (key_pos == Positions::LASTCHAR)
printf (" + asso_values[%sstr[len - 1]]", char_to_index); printf (" + asso_values[%sstr[len - 1]]", char_to_index);
printf (";\n"); printf (";\n");
} }
} }
}
printf ("}\n\n"); printf ("}\n\n");
} }
@@ -1432,7 +1435,7 @@ Output::output ()
else if (option[CPLUSPLUS]) else if (option[CPLUSPLUS])
printf ("C++"); printf ("C++");
printf (" code produced by gperf version %s */\n", version_string); printf (" code produced by gperf version %s */\n", version_string);
Options::print_options (); option.print_options ();
printf ("%s\n", _include_src); printf ("%s\n", _include_src);

View File

@@ -1,4 +1,4 @@
GNU `gperf' generates perfect hash functions. GNU 'gperf' generates perfect hash functions.
Usage: ../src/gperf [OPTION]... [INPUT-FILE] Usage: ../src/gperf [OPTION]... [INPUT-FILE]
@@ -30,12 +30,12 @@ Details in the output code:
structure. structure.
-H, --hash-fn-name=NAME -H, --hash-fn-name=NAME
Specify name of generated hash function. Default is Specify name of generated hash function. Default is
`hash'. 'hash'.
-N, --lookup-fn-name=NAME -N, --lookup-fn-name=NAME
Specify name of generated lookup function. Default Specify name of generated lookup function. Default
name is `in_word_set'. name is 'in_word_set'.
-Z, --class-name=NAME Specify name of generated C++ class. Default name is -Z, --class-name=NAME Specify name of generated C++ class. Default name is
`Perfect_Hash'. 'Perfect_Hash'.
-7, --seven-bit Assume 7-bit characters. -7, --seven-bit Assume 7-bit characters.
-c, --compare-strncmp Generate comparison code using strncmp rather than -c, --compare-strncmp Generate comparison code using strncmp rather than
strcmp. strcmp.
@@ -50,7 +50,7 @@ Details in the output code:
lookup function (which is the default behavior). lookup function (which is the default behavior).
-W, --word-array-name=NAME -W, --word-array-name=NAME
Specify name of word list array. Default name is Specify name of word list array. Default name is
`wordlist'. 'wordlist'.
-S, --switch=COUNT Causes the generated C code to use a switch -S, --switch=COUNT Causes the generated C code to use a switch
statement scheme, rather than an array lookup table. statement scheme, rather than an array lookup table.
This can lead to a reduction in both time and space This can lead to a reduction in both time and space
@@ -74,23 +74,23 @@ Algorithm employed by gperf:
used, and key positions may occur in any order. used, and key positions may occur in any order.
Also, the meta-character '*' causes the generated Also, the meta-character '*' causes the generated
hash function to consider ALL key positions, and $ hash function to consider ALL key positions, and $
indicates the ``final character'' of a key, e.g., indicates the "final character" of a key, e.g.,
$,1,2,4,6-10. $,1,2,4,6-10.
-l, --compare-strlen Compare key lengths before trying a string -l, --compare-strlen Compare key lengths before trying a string
comparison. This helps cut down on the number of comparison. This helps cut down on the number of
string comparisons made during the lookup. string comparisons made during the lookup.
-D, --duplicates Handle keywords that hash to duplicate values. This -D, --duplicates Handle keywords that hash to duplicate values. This
is useful for certain highly redundant keyword sets. is useful for certain highly redundant keyword sets.
-f, --fast=ITERATIONS Generate the gen-perf.hash function ``fast''. This -f, --fast=ITERATIONS Generate the gen-perf.hash function "fast". This
decreases gperf's running time at the cost of decreases gperf's running time at the cost of
minimizing generated table size. The numeric minimizing generated table size. The numeric
argument represents the number of times to iterate argument represents the number of times to iterate
when resolving a collision. `0' means ``iterate by when resolving a collision. '0' means "iterate by
the number of keywords''. the number of keywords".
-i, --initial-asso=N Provide an initial value for the associate values -i, --initial-asso=N Provide an initial value for the associate values
array. Default is 0. Setting this value larger helps array. Default is 0. Setting this value larger helps
inflate the size of the final table. inflate the size of the final table.
-j, --jump=JUMP-VALUE Affects the ``jump value'', i.e., how far to advance -j, --jump=JUMP-VALUE Affects the "jump value", i.e., how far to advance
the associated character value upon collisions. Must the associated character value upon collisions. Must
be an odd number, default is 5. be an odd number, default is 5.
-n, --no-strlen Do not include the length of the keyword when -n, --no-strlen Do not include the length of the keyword when
@@ -101,14 +101,14 @@ Algorithm employed by gperf:
-r, --random Utilizes randomness to initialize the associated -r, --random Utilizes randomness to initialize the associated
values table. values table.
-s, --size-multiple=N Affects the size of the generated hash table. The -s, --size-multiple=N Affects the size of the generated hash table. The
numeric argument N indicates ``how many times larger numeric argument N indicates "how many times larger
or smaller'' the associated value range should be, or smaller" the associated value range should be,
in relationship to the number of keys, e.g. a value in relationship to the number of keys, e.g. a value
of 3 means ``allow the maximum associated value to of 3 means "allow the maximum associated value to
be about 3 times larger than the number of input be about 3 times larger than the number of input
keys.'' Conversely, a value of -3 means ``make the keys". Conversely, a value of -3 means "make the
maximum associated value about 3 times smaller than maximum associated value about 3 times smaller than
the number of input keys. A larger table should the number of input keys". A larger table should
decrease the time required for an unsuccessful decrease the time required for an unsuccessful
search, at the expense of extra table space. Default search, at the expense of extra table space. Default
value is 1. value is 1.