[subset] re-write compute distances to use an array lookup for the distance map.

This commit is contained in:
Garret Rieger 2020-11-05 09:21:25 -08:00
parent 5c4e0ffd97
commit 4c8dd41ed9
3 changed files with 27 additions and 34 deletions

View File

@ -43,7 +43,7 @@ struct hb_priority_queue_t
~hb_priority_queue_t () { fini (); } ~hb_priority_queue_t () { fini (); }
private: private:
typedef hb_pair_t<unsigned, unsigned> item_t; typedef hb_pair_t<unsigned, int64_t> item_t;
hb_vector_t<item_t> heap; hb_vector_t<item_t> heap;
public: public:
@ -55,7 +55,7 @@ struct hb_priority_queue_t
bool in_error () const { return heap.in_error (); } bool in_error () const { return heap.in_error (); }
void insert (unsigned value, unsigned priority) void insert (unsigned value, int64_t priority)
{ {
heap.push (item_t (value, priority)); heap.push (item_t (value, priority));
bubble_up (heap.length - 1); bubble_up (heap.length - 1);

View File

@ -161,7 +161,7 @@ struct graph_t
return; return;
} }
hb_hashmap_t<unsigned, int64_t, -1, hb_int_max(int64_t)> distance_to; hb_vector_t<int64_t> distance_to;
compute_distances (&distance_to); compute_distances (&distance_to);
hb_set_t queue; hb_set_t queue;
@ -242,15 +242,16 @@ struct graph_t
private: private:
unsigned closest_object (const hb_set_t& queue, unsigned closest_object (const hb_set_t& queue,
const hb_hashmap_t<unsigned, int64_t, -1, hb_int_max(int64_t)>& distance_to) const hb_vector_t<int64_t> distance_to)
{ {
// TODO(garretrieger): use a priority queue.
int64_t closest_distance = hb_int_max (int64_t); int64_t closest_distance = hb_int_max (int64_t);
unsigned closest_index = -1; unsigned closest_index = -1;
for (unsigned i : queue) for (unsigned i : queue)
{ {
if (distance_to.get (i) < closest_distance) if (distance_to[i] < closest_distance)
{ {
closest_distance = distance_to.get (i); closest_distance = distance_to[i];
closest_index = i; closest_index = i;
} }
} }
@ -262,51 +263,41 @@ struct graph_t
* Finds the distance too each object in the graph * Finds the distance too each object in the graph
* from the initial node. * from the initial node.
*/ */
void compute_distances (hb_hashmap_t<unsigned, int64_t, -1, hb_int_max(int64_t)>* distance_to) void compute_distances (hb_vector_t<int64_t>* distance_to)
{ {
// Uses Dijkstra's algorithm to find all of the shortest distances. // Uses Dijkstra's algorithm to find all of the shortest distances.
// https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm // https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
distance_to->clear (); distance_to->resize (0);
distance_to->resize (objects_.length);
for (unsigned i = 0; i < objects_.length; i++)
(*distance_to)[i] = hb_int_max (int64_t);
(*distance_to)[objects_.length - 1] = 0;
hb_set_t unvisited; hb_set_t unvisited;
unvisited.add_range (0, objects_.length - 1); unvisited.add_range (0, objects_.length - 1);
unsigned current_idx = objects_.length - 1; while (!unvisited.is_empty ())
distance_to->set (current_idx, 0);
while (unvisited.get_population ())
{ {
const auto& current = objects_[current_idx]; unsigned next_idx = closest_object (unvisited, *distance_to);
int current_distance = (*distance_to)[current_idx]; const auto& next = objects_[next_idx];
int next_distance = (*distance_to)[next_idx];
unvisited.del (next_idx);
for (const auto& link : current.links) for (const auto& link : next.links)
{ {
if (!unvisited.has (link.objidx)) continue; if (!unvisited.has (link.objidx)) continue;
const auto& child = objects_[link.objidx]; const auto& child = objects_[link.objidx];
int64_t child_weight = child.tail - child.head + int64_t child_weight = child.tail - child.head +
(!link.is_wide ? (1 << 16) : ((int64_t) 1 << 32)); (!link.is_wide ? (1 << 16) : ((int64_t) 1 << 32));
int64_t child_distance = current_distance + child_weight; int64_t child_distance = next_distance + child_weight;
if (child_distance < distance_to->get (link.objidx)) if (child_distance < (*distance_to)[link.objidx])
distance_to->set (link.objidx, child_distance); (*distance_to)[link.objidx] = child_distance;
}
unvisited.del (current_idx);
// TODO(garretrieger): change this to use a priority queue.
int64_t smallest_distance = hb_int_max(int64_t);
for (hb_codepoint_t idx : unvisited)
{
if (distance_to->get (idx) < smallest_distance)
{
smallest_distance = distance_to->get (idx);
current_idx = idx;
} }
} }
// TODO(garretrieger): Handle this. If anything is left, part of the graph is disconnected.
// TODO(garretrieger): this will trigger if graph is disconnected. Handle this. assert (unvisited.is_empty ());
assert (!unvisited.get_population () || smallest_distance != hb_int_max (int64_t));
}
} }
int64_t compute_offset ( int64_t compute_offset (

View File

@ -271,6 +271,8 @@ static void test_will_overflow_2 ()
assert (graph.will_overflow ()); assert (graph.will_overflow ());
} }
// TODO(garretrieger): add a test(s) using a real font.
int int
main (int argc, char **argv) main (int argc, char **argv)
{ {