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:
18
ChangeLog
18
ChangeLog
@@ -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.
|
||||||
|
|||||||
@@ -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)
|
|
||||||
partition_last->_next = equclass;
|
|
||||||
else
|
|
||||||
partition = equclass;
|
|
||||||
partition_last = equclass;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add the keyword to the equivalence class. */
|
/* Add the keyword to the equivalence class number pindex. */
|
||||||
equclass->_keywords.add_last (keyword);
|
partition->_equclasses.get_at(pindex)._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 ();
|
||||||
|
|
||||||
|
|||||||
10
src/search.h
10
src/search.h
@@ -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 ();
|
||||||
|
|||||||
Reference in New Issue
Block a user