1
0
mirror of https://git.savannah.gnu.org/git/gperf.git synced 2025-12-02 13:09:22 +00:00

Refactor: Use an array-list instead of a linked-list of equiv.-classes.

* src/search.h (Search::compute_partition): Return a 'Partition *', not
a 'EquivalenceClass *'.
(Search::count_possible_collisions, Search::unchanged_partition): Change
parameter from 'EquivalenceClass *' to 'Partition *'.
* src/search.cc (struct EquivalenceClass): Remove field _next.
(struct Partition): New type.
(struct Step): Change type of _partition from 'EquivalenceClass *' to
'Partition *'.
(Search::compute_partition): Return a 'Partition *', not a
'EquivalenceClass *'.
(delete_partition): Update.
(Search::count_possible_collisions, Search::unchanged_partition): Change
parameter from 'EquivalenceClass *' to 'Partition *'.
(Search::find_asso_values): Update.
This commit is contained in:
Bruno Haible
2025-04-19 19:28:54 +02:00
parent b1ff3c70b1
commit 9e29799ac3
3 changed files with 83 additions and 54 deletions

View File

@@ -1,3 +1,21 @@
2025-04-19 Bruno Haible <bruno@clisp.org>
Refactor: Use an array-list instead of a linked-list of equiv.-classes.
* src/search.h (Search::compute_partition): Return a 'Partition *', not
a 'EquivalenceClass *'.
(Search::count_possible_collisions, Search::unchanged_partition): Change
parameter from 'EquivalenceClass *' to 'Partition *'.
* src/search.cc (struct EquivalenceClass): Remove field _next.
(struct Partition): New type.
(struct Step): Change type of _partition from 'EquivalenceClass *' to
'Partition *'.
(Search::compute_partition): Return a 'Partition *', not a
'EquivalenceClass *'.
(delete_partition): Update.
(Search::count_possible_collisions, Search::unchanged_partition): Change
parameter from 'EquivalenceClass *' to 'Partition *'.
(Search::find_asso_values): Update.
2025-04-19 Bruno Haible <bruno@clisp.org> 2025-04-19 Bruno Haible <bruno@clisp.org>
Optimize: Use an array-list instead of a linked-list of keywords. Optimize: Use an array-list instead of a linked-list of keywords.

View File

@@ -951,12 +951,19 @@ struct EquivalenceClass
/* The keywords in this equivalence class. */ /* The keywords in this equivalence class. */
ArrayList<KeywordExt*> _keywords; ArrayList<KeywordExt*> _keywords;
EquivalenceClass * _next;
/* Constructor. */ /* Constructor. */
EquivalenceClass () : _keywords () {} EquivalenceClass () : _keywords () {}
}; };
struct Partition
{
/* The equivalence classes in this partition. */
ArrayList<EquivalenceClass> _equclasses;
/* Constructor. */
Partition () : _equclasses () {}
};
struct Step struct Step
{ {
/* The characters whose values are being determined in this step. */ /* The characters whose values are being determined in this step. */
@@ -968,7 +975,7 @@ struct Step
/* The characters whose values will be determined after this step. */ /* The characters whose values will be determined after this step. */
bool * _undetermined; bool * _undetermined;
/* The keyword set partition after this step. */ /* The keyword set partition after this step. */
EquivalenceClass * _partition; Partition * _partition;
/* The expected number of iterations in this step. */ /* The expected number of iterations in this step. */
double _expected_lower; double _expected_lower;
double _expected_upper; double _expected_upper;
@@ -1004,7 +1011,7 @@ undetermined_hashcode (KeywordExt *key)
return key->_undetermined_chars_hashcode; return key->_undetermined_chars_hashcode;
} }
EquivalenceClass * Partition *
Search::compute_partition (bool *undetermined) const Search::compute_partition (bool *undetermined) const
{ {
/* Prepare the use of the hash-map: For each keyword, /* Prepare the use of the hash-map: For each keyword,
@@ -1032,56 +1039,47 @@ Search::compute_partition (bool *undetermined) const
} }
} }
EquivalenceClass *partition = NULL; Partition *partition = new Partition ();
EquivalenceClass *partition_last = NULL; {
/* A hash-map that maps each keyword to the EquivalenceClass that contains /* A hash-map that maps each keyword to the EquivalenceClass that contains
it. */ it. */
gl_Map<KeywordExt *, EquivalenceClass const *> gl_Map<KeywordExt *, void const *>
map (GL_HASH_MAP, undetermined_equals, undetermined_hashcode, NULL, NULL); map (GL_HASH_MAP, undetermined_equals, undetermined_hashcode, NULL, NULL);
for (KeywordExt_List *temp = _head; temp; temp = temp->rest()) for (KeywordExt_List *temp = _head; temp; temp = temp->rest())
{ {
KeywordExt *keyword = temp->first(); KeywordExt *keyword = temp->first();
/* Look up the equivalence class to which this keyword belongs. */ /* Look up the equivalence class to which this keyword belongs. */
EquivalenceClass *equclass = const_cast<EquivalenceClass *>(map.get(keyword)); size_t pindex = reinterpret_cast<size_t>(map.get(keyword)) - 1;
if (equclass == NULL) if (pindex == (size_t)-1)
{ {
equclass = new EquivalenceClass(); /* Allocate a new EquivalenceClass and add it as the last element to
equclass->_next = NULL; the partition. */
pindex = partition->_equclasses.add_last (* new EquivalenceClass());
/* Map this keyword (and all equivalent ones that will be seen later) /* Map this keyword (and all equivalent ones that will be seen later)
to equclass. */ to the equivalence class number pindex. */
map.put(keyword, equclass); map.put(keyword, reinterpret_cast<void *>(pindex + 1));
}
if (partition) /* Add the keyword to the equivalence class number pindex. */
partition_last->_next = equclass; partition->_equclasses.get_at(pindex)._keywords.add_last (keyword);
else }
partition = equclass; }
partition_last = equclass;
}
/* Add the keyword to the equivalence class. */
equclass->_keywords.add_last (keyword);
}
return partition; return partition;
} }
static void static void
delete_partition (EquivalenceClass *partition) delete_partition (Partition *partition)
{ {
while (partition != NULL) delete partition;
{
EquivalenceClass *equclass = partition;
partition = equclass->_next;
delete equclass;
}
} }
/* Compute the possible number of collisions when _asso_values[c] is /* Compute the possible number of collisions when _asso_values[c] is
chosen, leading to the given partition. */ chosen, leading to the given partition. */
unsigned int unsigned int
Search::count_possible_collisions (EquivalenceClass *partition, unsigned int c) const Search::count_possible_collisions (Partition *partition, unsigned int c) const
{ {
/* Every equivalence class p is split according to the frequency of /* Every equivalence class p is split according to the frequency of
occurrence of c, leading to equivalence classes p1, p2, ... occurrence of c, leading to equivalence classes p1, p2, ...
@@ -1090,8 +1088,11 @@ Search::count_possible_collisions (EquivalenceClass *partition, unsigned int c)
unsigned int sum = 0; unsigned int sum = 0;
unsigned int m = _max_selchars_length; unsigned int m = _max_selchars_length;
DYNAMIC_ARRAY (split_cardinalities, unsigned int, m + 1); DYNAMIC_ARRAY (split_cardinalities, unsigned int, m + 1);
for (EquivalenceClass *cls = partition; cls; cls = cls->_next) size_t partition_size = partition->_equclasses.size();
for (size_t pindex = 0; pindex < partition_size; pindex++)
{ {
EquivalenceClass *cls = & partition->_equclasses.get_at(pindex);
for (unsigned int i = 0; i <= m; i++) for (unsigned int i = 0; i <= m; i++)
split_cardinalities[i] = 0; split_cardinalities[i] = 0;
@@ -1119,10 +1120,13 @@ Search::count_possible_collisions (EquivalenceClass *partition, unsigned int c)
/* Test whether adding c to the undetermined characters changes the given /* Test whether adding c to the undetermined characters changes the given
partition. */ partition. */
bool bool
Search::unchanged_partition (EquivalenceClass *partition, unsigned int c) const Search::unchanged_partition (Partition *partition, unsigned int c) const
{ {
for (EquivalenceClass *cls = partition; cls; cls = cls->_next) size_t partition_size = partition->_equclasses.size();
for (size_t pindex = 0; pindex < partition_size; pindex++)
{ {
EquivalenceClass *cls = & partition->_equclasses.get_at(pindex);
unsigned int first_count = UINT_MAX; unsigned int first_count = UINT_MAX;
size_t cls_size = cls->_keywords.size(); size_t cls_size = cls->_keywords.size();
@@ -1168,7 +1172,7 @@ Search::find_asso_values ()
for (;;) for (;;)
{ {
/* Compute the partition that needs to be refined. */ /* Compute the partition that needs to be refined. */
EquivalenceClass *partition = compute_partition (undetermined); Partition *partition = compute_partition (undetermined);
/* Determine the main character to be chosen in this step. /* Determine the main character to be chosen in this step.
Choosing such a character c has the effect of splitting every Choosing such a character c has the effect of splitting every
@@ -1214,7 +1218,7 @@ Search::find_asso_values ()
/* Now determine how the equivalence classes will be before this /* Now determine how the equivalence classes will be before this
step. */ step. */
undetermined[chosen_c] = true; undetermined[chosen_c] = true;
partition = compute_partition (undetermined); Partition *partition_before = compute_partition (undetermined);
/* Now determine which other characters should be determined in this /* Now determine which other characters should be determined in this
step, because they will not change the equivalence classes at step, because they will not change the equivalence classes at
@@ -1223,7 +1227,7 @@ Search::find_asso_values ()
of the equivalence class. */ of the equivalence class. */
for (unsigned int c = 0; c < _alpha_size; c++) for (unsigned int c = 0; c < _alpha_size; c++)
if (_occurrences[c] > 0 && determined[c] if (_occurrences[c] > 0 && determined[c]
&& unchanged_partition (partition, c)) && unchanged_partition (partition_before, c))
{ {
undetermined[c] = true; undetermined[c] = true;
determined[c] = false; determined[c] = false;
@@ -1259,7 +1263,7 @@ Search::find_asso_values ()
exp (static_cast<double>(chosen_possible_collisions) exp (static_cast<double>(chosen_possible_collisions)
/ static_cast<double>(_asso_value_max)); / static_cast<double>(_asso_value_max));
delete_partition (partition); delete_partition (partition_before);
step->_next = steps; step->_next = steps;
steps = step; steps = step;
@@ -1285,8 +1289,11 @@ Search::find_asso_values ()
fprintf (stderr, "], expected number of iterations between %g and %g.\n", fprintf (stderr, "], expected number of iterations between %g and %g.\n",
step->_expected_lower, step->_expected_upper); step->_expected_lower, step->_expected_upper);
fprintf (stderr, "Keyword equivalence classes:\n"); fprintf (stderr, "Keyword equivalence classes:\n");
for (EquivalenceClass *cls = step->_partition; cls; cls = cls->_next) Partition *partition = step->_partition;
size_t partition_size = partition->_equclasses.size();
for (size_t pindex = 0; pindex < partition_size; pindex++)
{ {
EquivalenceClass *cls = & partition->_equclasses.get_at(pindex);
fprintf (stderr, "\n"); fprintf (stderr, "\n");
size_t cls_size = cls->_keywords.size(); size_t cls_size = cls->_keywords.size();
for (size_t index = 0; index < cls_size; index++) for (size_t index = 0; index < cls_size; index++)
@@ -1336,8 +1343,12 @@ Search::find_asso_values ()
/* Test whether these asso_values[] lead to collisions among /* Test whether these asso_values[] lead to collisions among
the equivalence classes that should be collision-free. */ the equivalence classes that should be collision-free. */
bool has_collision = false; bool has_collision = false;
for (EquivalenceClass *cls = step->_partition; cls; cls = cls->_next) Partition *partition = step->_partition;
size_t partition_size = partition->_equclasses.size();
for (size_t pindex = 0; pindex < partition_size; pindex++)
{ {
EquivalenceClass *cls = & partition->_equclasses.get_at(pindex);
/* Iteration Number array is a win, O(1) initialization time! */ /* Iteration Number array is a win, O(1) initialization time! */
_collision_detector->clear (); _collision_detector->clear ();

View File

@@ -2,7 +2,7 @@
/* Search algorithm. /* Search algorithm.
Copyright (C) 1989-1998, 2000, 2002-2003, 2009 Free Software Foundation, Inc. Copyright (C) 1989-1998, 2000, 2002-2003, 2009, 2025 Free Software Foundation, Inc.
Written by Douglas C. Schmidt <schmidt@ics.uci.edu> Written by Douglas C. Schmidt <schmidt@ics.uci.edu>
and Bruno Haible <bruno@clisp.org>. and Bruno Haible <bruno@clisp.org>.
@@ -28,7 +28,7 @@
#include "positions.h" #include "positions.h"
#include "bool-array.h" #include "bool-array.h"
struct EquivalenceClass; struct Partition;
class Search class Search
{ {
@@ -80,11 +80,11 @@ private:
/* Initializes the asso_values[] related parameters. */ /* Initializes the asso_values[] related parameters. */
void prepare_asso_values (); void prepare_asso_values ();
EquivalenceClass * compute_partition (bool *undetermined) const; Partition * compute_partition (bool *undetermined) const;
unsigned int count_possible_collisions (EquivalenceClass *partition, unsigned int c) const; unsigned int count_possible_collisions (Partition *partition, unsigned int c) const;
bool unchanged_partition (EquivalenceClass *partition, unsigned int c) const; bool unchanged_partition (Partition *partition, unsigned int c) const;
/* Finds some _asso_values[] that fit. */ /* Finds some _asso_values[] that fit. */
void find_asso_values (); void find_asso_values ();