[subset] Improve sharing of Ligature subtables.
Ligature subtables use virtual links to enforce an ordering constraint between the subtables and the coverage table. Unfortunately this has the sideeffect of prevent the subtables from being shared by another Ligature with a different coverage table since object equality compares all links real and virtual. This change makes virtual links stored separately from real links and updates the equality check to only check real links. If an object is de-duped any virtual links it has are merged into the object that replaces it.
This commit is contained in:
parent
ca22741110
commit
9121ed0cec
|
@ -100,7 +100,7 @@ struct graph_t
|
||||||
|
|
||||||
bool is_leaf () const
|
bool is_leaf () const
|
||||||
{
|
{
|
||||||
return !obj.links.length;
|
return !obj.real_links.length && !obj.virtual_links.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
void raise_priority ()
|
void raise_priority ()
|
||||||
|
@ -164,9 +164,11 @@ struct graph_t
|
||||||
if (check_success (!vertices_.in_error ()))
|
if (check_success (!vertices_.in_error ()))
|
||||||
v->obj = *objects[i];
|
v->obj = *objects[i];
|
||||||
if (!removed_nil) continue;
|
if (!removed_nil) continue;
|
||||||
for (unsigned i = 0; i < v->obj.links.length; i++)
|
// Fix indices to account for removed nil object.
|
||||||
// Fix indices to account for removed nil object.
|
for (auto& l : hb_concat (v->obj.real_links.writer (),
|
||||||
v->obj.links[i].objidx--;
|
v->obj.virtual_links.writer ())) {
|
||||||
|
l.objidx--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,7 +217,8 @@ struct graph_t
|
||||||
|
|
||||||
memcpy (start, vertices_[i].obj.head, size);
|
memcpy (start, vertices_[i].obj.head, size);
|
||||||
|
|
||||||
for (const auto& link : vertices_[i].obj.links)
|
// Only real links needs to be serialized.
|
||||||
|
for (const auto& link : vertices_[i].obj.real_links)
|
||||||
serialize_link (link, start, c);
|
serialize_link (link, start, c);
|
||||||
|
|
||||||
// All duplications are already encoded in the graph, so don't
|
// All duplications are already encoded in the graph, so don't
|
||||||
|
@ -260,7 +263,7 @@ struct graph_t
|
||||||
sorted_graph[new_id] = next;
|
sorted_graph[new_id] = next;
|
||||||
id_map[next_id] = new_id--;
|
id_map[next_id] = new_id--;
|
||||||
|
|
||||||
for (const auto& link : next.obj.links) {
|
for (const auto& link : hb_concat (next.obj.real_links, next.obj.virtual_links)) {
|
||||||
removed_edges[link.objidx]++;
|
removed_edges[link.objidx]++;
|
||||||
if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx]))
|
if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx]))
|
||||||
queue.push (link.objidx);
|
queue.push (link.objidx);
|
||||||
|
@ -314,7 +317,7 @@ struct graph_t
|
||||||
sorted_graph[new_id] = next;
|
sorted_graph[new_id] = next;
|
||||||
id_map[next_id] = new_id--;
|
id_map[next_id] = new_id--;
|
||||||
|
|
||||||
for (const auto& link : next.obj.links) {
|
for (const auto& link : hb_concat (next.obj.real_links, next.obj.virtual_links)) {
|
||||||
removed_edges[link.objidx]++;
|
removed_edges[link.objidx]++;
|
||||||
if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx]))
|
if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx]))
|
||||||
// Add the order that the links were encountered to the priority.
|
// Add the order that the links were encountered to the priority.
|
||||||
|
@ -348,7 +351,8 @@ struct graph_t
|
||||||
hb_set_t roots;
|
hb_set_t roots;
|
||||||
for (unsigned i = 0; i <= root_index; i++)
|
for (unsigned i = 0; i <= root_index; i++)
|
||||||
{
|
{
|
||||||
for (auto& l : vertices_[i].obj.links)
|
// Only real links can form 32 bit spaces
|
||||||
|
for (auto& l : vertices_[i].obj.real_links)
|
||||||
{
|
{
|
||||||
if (l.width == 4 && !l.is_signed)
|
if (l.width == 4 && !l.is_signed)
|
||||||
{
|
{
|
||||||
|
@ -466,7 +470,8 @@ struct graph_t
|
||||||
|
|
||||||
void find_subgraph (unsigned node_idx, hb_hashmap_t<unsigned, unsigned>& subgraph)
|
void find_subgraph (unsigned node_idx, hb_hashmap_t<unsigned, unsigned>& subgraph)
|
||||||
{
|
{
|
||||||
for (const auto& link : vertices_[node_idx].obj.links)
|
for (const auto& link : hb_concat (vertices_[node_idx].obj.real_links,
|
||||||
|
vertices_[node_idx].obj.virtual_links))
|
||||||
{
|
{
|
||||||
if (subgraph.has (link.objidx))
|
if (subgraph.has (link.objidx))
|
||||||
{
|
{
|
||||||
|
@ -482,7 +487,8 @@ struct graph_t
|
||||||
{
|
{
|
||||||
if (subgraph.has (node_idx)) return;
|
if (subgraph.has (node_idx)) return;
|
||||||
subgraph.add (node_idx);
|
subgraph.add (node_idx);
|
||||||
for (const auto& link : vertices_[node_idx].obj.links)
|
for (const auto& link : hb_concat (vertices_[node_idx].obj.real_links,
|
||||||
|
vertices_[node_idx].obj.virtual_links))
|
||||||
find_subgraph (link.objidx, subgraph);
|
find_subgraph (link.objidx, subgraph);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,7 +503,8 @@ struct graph_t
|
||||||
return;
|
return;
|
||||||
|
|
||||||
index_map.set (node_idx, duplicate (node_idx));
|
index_map.set (node_idx, duplicate (node_idx));
|
||||||
for (const auto& l : object (node_idx).links) {
|
for (const auto& l : hb_concat (object (node_idx).real_links,
|
||||||
|
object (node_idx).virtual_links)) {
|
||||||
duplicate_subgraph (l.objidx, index_map);
|
duplicate_subgraph (l.objidx, index_map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -523,13 +530,19 @@ struct graph_t
|
||||||
clone->parents.reset ();
|
clone->parents.reset ();
|
||||||
|
|
||||||
unsigned clone_idx = vertices_.length - 2;
|
unsigned clone_idx = vertices_.length - 2;
|
||||||
for (const auto& l : child.obj.links)
|
for (const auto& l : child.obj.real_links)
|
||||||
{
|
{
|
||||||
clone->obj.links.push (l);
|
clone->obj.real_links.push (l);
|
||||||
|
vertices_[l.objidx].parents.push (clone_idx);
|
||||||
|
}
|
||||||
|
for (const auto& l : child.obj.virtual_links)
|
||||||
|
{
|
||||||
|
clone->obj.virtual_links.push (l);
|
||||||
vertices_[l.objidx].parents.push (clone_idx);
|
vertices_[l.objidx].parents.push (clone_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
check_success (!clone->obj.links.in_error ());
|
check_success (!clone->obj.real_links.in_error ());
|
||||||
|
check_success (!clone->obj.virtual_links.in_error ());
|
||||||
|
|
||||||
// The last object is the root of the graph, so swap back the root to the end.
|
// The last object is the root of the graph, so swap back the root to the end.
|
||||||
// The root's obj idx does change, however since it's root nothing else refers to it.
|
// The root's obj idx does change, however since it's root nothing else refers to it.
|
||||||
|
@ -539,7 +552,8 @@ struct graph_t
|
||||||
vertices_[vertices_.length - 1] = root;
|
vertices_[vertices_.length - 1] = root;
|
||||||
|
|
||||||
// Since the root moved, update the parents arrays of all children on the root.
|
// Since the root moved, update the parents arrays of all children on the root.
|
||||||
for (const auto& l : root.obj.links)
|
for (const auto& l : hb_concat (root.obj.real_links,
|
||||||
|
root.obj.virtual_links))
|
||||||
vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ());
|
vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ());
|
||||||
|
|
||||||
return clone_idx;
|
return clone_idx;
|
||||||
|
@ -555,7 +569,8 @@ struct graph_t
|
||||||
update_parents ();
|
update_parents ();
|
||||||
|
|
||||||
unsigned links_to_child = 0;
|
unsigned links_to_child = 0;
|
||||||
for (const auto& l : vertices_[parent_idx].obj.links)
|
for (const auto& l : hb_concat (vertices_[parent_idx].obj.real_links,
|
||||||
|
vertices_[parent_idx].obj.virtual_links))
|
||||||
{
|
{
|
||||||
if (l.objidx == child_idx) links_to_child++;
|
if (l.objidx == child_idx) links_to_child++;
|
||||||
}
|
}
|
||||||
|
@ -578,9 +593,9 @@ struct graph_t
|
||||||
if (parent_idx == clone_idx) parent_idx++;
|
if (parent_idx == clone_idx) parent_idx++;
|
||||||
|
|
||||||
auto& parent = vertices_[parent_idx];
|
auto& parent = vertices_[parent_idx];
|
||||||
for (unsigned i = 0; i < parent.obj.links.length; i++)
|
for (auto& l : hb_concat (parent.obj.real_links.writer (),
|
||||||
|
parent.obj.virtual_links.writer ()))
|
||||||
{
|
{
|
||||||
auto& l = parent.obj.links[i];
|
|
||||||
if (l.objidx != child_idx)
|
if (l.objidx != child_idx)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -601,8 +616,9 @@ struct graph_t
|
||||||
// to invalidate positions. It does not change graph structure so no need
|
// to invalidate positions. It does not change graph structure so no need
|
||||||
// to update distances or edge counts.
|
// to update distances or edge counts.
|
||||||
auto& parent = vertices_[parent_idx].obj;
|
auto& parent = vertices_[parent_idx].obj;
|
||||||
for (unsigned i = 0; i < parent.links.length; i++)
|
for (auto& l : hb_concat (parent.real_links.writer (),
|
||||||
vertices_[parent.links[i].objidx].raise_priority ();
|
parent.virtual_links.writer ()))
|
||||||
|
vertices_[l.objidx].raise_priority ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -615,7 +631,8 @@ struct graph_t
|
||||||
|
|
||||||
for (int parent_idx = vertices_.length - 1; parent_idx >= 0; parent_idx--)
|
for (int parent_idx = vertices_.length - 1; parent_idx >= 0; parent_idx--)
|
||||||
{
|
{
|
||||||
for (const auto& link : vertices_[parent_idx].obj.links)
|
// Don't need to check virtual links for overflow
|
||||||
|
for (const auto& link : vertices_[parent_idx].obj.real_links)
|
||||||
{
|
{
|
||||||
int64_t offset = compute_offset (parent_idx, link);
|
int64_t offset = compute_offset (parent_idx, link);
|
||||||
if (is_valid_offset (offset, link))
|
if (is_valid_offset (offset, link))
|
||||||
|
@ -665,11 +682,11 @@ struct graph_t
|
||||||
"%4d (%4d in, %4d out, space %2d)",
|
"%4d (%4d in, %4d out, space %2d)",
|
||||||
o.parent,
|
o.parent,
|
||||||
parent.incoming_edges (),
|
parent.incoming_edges (),
|
||||||
parent.obj.links.length,
|
parent.obj.real_links.length + parent.obj.virtual_links.length,
|
||||||
space_for (o.parent),
|
space_for (o.parent),
|
||||||
o.child,
|
o.child,
|
||||||
child.incoming_edges (),
|
child.incoming_edges (),
|
||||||
child.obj.links.length,
|
child.obj.real_links.length + child.obj.virtual_links.length,
|
||||||
space_for (o.child));
|
space_for (o.child));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -728,7 +745,8 @@ struct graph_t
|
||||||
if (visited.has (p)) continue;
|
if (visited.has (p)) continue;
|
||||||
visited.add (p);
|
visited.add (p);
|
||||||
|
|
||||||
for (const auto& l : vertices_[p].obj.links)
|
// Only real links can be wide
|
||||||
|
for (const auto& l : vertices_[p].obj.real_links)
|
||||||
{
|
{
|
||||||
if (l.objidx == node_idx && l.width == 4 && !l.is_signed)
|
if (l.objidx == node_idx && l.width == 4 && !l.is_signed)
|
||||||
{
|
{
|
||||||
|
@ -755,7 +773,8 @@ struct graph_t
|
||||||
|
|
||||||
for (unsigned p = 0; p < vertices_.length; p++)
|
for (unsigned p = 0; p < vertices_.length; p++)
|
||||||
{
|
{
|
||||||
for (auto& l : vertices_[p].obj.links)
|
for (auto& l : hb_concat (vertices_[p].obj.real_links,
|
||||||
|
vertices_[p].obj.virtual_links))
|
||||||
{
|
{
|
||||||
vertices_[l.objidx].parents.push (p);
|
vertices_[l.objidx].parents.push (p);
|
||||||
}
|
}
|
||||||
|
@ -823,7 +842,8 @@ struct graph_t
|
||||||
int64_t next_distance = vertices_[next_idx].distance;
|
int64_t next_distance = vertices_[next_idx].distance;
|
||||||
visited[next_idx] = true;
|
visited[next_idx] = true;
|
||||||
|
|
||||||
for (const auto& link : next.obj.links)
|
for (const auto& link : hb_concat (next.obj.real_links,
|
||||||
|
next.obj.virtual_links))
|
||||||
{
|
{
|
||||||
if (visited[link.objidx]) continue;
|
if (visited[link.objidx]) continue;
|
||||||
|
|
||||||
|
@ -922,9 +942,9 @@ struct graph_t
|
||||||
if (!id_map) return;
|
if (!id_map) return;
|
||||||
for (unsigned i : subgraph)
|
for (unsigned i : subgraph)
|
||||||
{
|
{
|
||||||
for (unsigned j = 0; j < vertices_[i].obj.links.length; j++)
|
for (auto& link : hb_concat (vertices_[i].obj.real_links.writer (),
|
||||||
|
vertices_[i].obj.virtual_links.writer ()))
|
||||||
{
|
{
|
||||||
auto& link = vertices_[i].obj.links[j];
|
|
||||||
if (!id_map.has (link.objidx)) continue;
|
if (!id_map.has (link.objidx)) continue;
|
||||||
if (only_wide && !(link.width == 4 && !link.is_signed)) continue;
|
if (only_wide && !(link.width == 4 && !link.is_signed)) continue;
|
||||||
|
|
||||||
|
@ -942,9 +962,10 @@ struct graph_t
|
||||||
for (unsigned i = 0; i < sorted_graph->length; i++)
|
for (unsigned i = 0; i < sorted_graph->length; i++)
|
||||||
{
|
{
|
||||||
(*sorted_graph)[i].remap_parents (id_map);
|
(*sorted_graph)[i].remap_parents (id_map);
|
||||||
for (unsigned j = 0; j < (*sorted_graph)[i].obj.links.length; j++)
|
for (auto& link : hb_concat ((*sorted_graph)[i].obj.real_links.writer (),
|
||||||
|
(*sorted_graph)[i].obj.virtual_links.writer ()))
|
||||||
|
|
||||||
{
|
{
|
||||||
auto& link = (*sorted_graph)[i].obj.links[j];
|
|
||||||
link.objidx = id_map[link.objidx];
|
link.objidx = id_map[link.objidx];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1023,7 +1044,8 @@ struct graph_t
|
||||||
const auto& v = vertices_[start_idx];
|
const auto& v = vertices_[start_idx];
|
||||||
|
|
||||||
// Graph is treated as undirected so search children and parents of start_idx
|
// Graph is treated as undirected so search children and parents of start_idx
|
||||||
for (const auto& l : v.obj.links)
|
for (const auto& l : hb_concat (v.obj.real_links,
|
||||||
|
v.obj.virtual_links))
|
||||||
find_connected_nodes (l.objidx, targets, visited, connected);
|
find_connected_nodes (l.objidx, targets, visited, connected);
|
||||||
|
|
||||||
for (unsigned p : v.parents)
|
for (unsigned p : v.parents)
|
||||||
|
|
|
@ -65,19 +65,26 @@ struct hb_serialize_context_t
|
||||||
|
|
||||||
struct object_t
|
struct object_t
|
||||||
{
|
{
|
||||||
void fini () { links.fini (); }
|
void fini () {
|
||||||
|
real_links.fini ();
|
||||||
|
virtual_links.fini ();
|
||||||
|
}
|
||||||
|
|
||||||
bool operator == (const object_t &o) const
|
bool operator == (const object_t &o) const
|
||||||
{
|
{
|
||||||
|
// Virtual links aren't considered for equality since they don't affect the functionality
|
||||||
|
// of the object.
|
||||||
return (tail - head == o.tail - o.head)
|
return (tail - head == o.tail - o.head)
|
||||||
&& (links.length == o.links.length)
|
&& (real_links.length == o.real_links.length)
|
||||||
&& 0 == hb_memcmp (head, o.head, tail - head)
|
&& 0 == hb_memcmp (head, o.head, tail - head)
|
||||||
&& links.as_bytes () == o.links.as_bytes ();
|
&& real_links.as_bytes () == o.real_links.as_bytes ();
|
||||||
}
|
}
|
||||||
uint32_t hash () const
|
uint32_t hash () const
|
||||||
{
|
{
|
||||||
|
// Virtual links aren't considered for equality since they don't affect the functionality
|
||||||
|
// of the object.
|
||||||
return hb_bytes_t (head, tail - head).hash () ^
|
return hb_bytes_t (head, tail - head).hash () ^
|
||||||
links.as_bytes ().hash ();
|
real_links.as_bytes ().hash ();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct link_t
|
struct link_t
|
||||||
|
@ -92,7 +99,8 @@ struct hb_serialize_context_t
|
||||||
|
|
||||||
char *head;
|
char *head;
|
||||||
char *tail;
|
char *tail;
|
||||||
hb_vector_t<link_t> links;
|
hb_vector_t<link_t> real_links;
|
||||||
|
hb_vector_t<link_t> virtual_links;
|
||||||
object_t *next;
|
object_t *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -101,12 +109,14 @@ struct hb_serialize_context_t
|
||||||
char *head;
|
char *head;
|
||||||
char *tail;
|
char *tail;
|
||||||
object_t *current; // Just for sanity check
|
object_t *current; // Just for sanity check
|
||||||
unsigned num_links;
|
unsigned num_real_links;
|
||||||
|
unsigned num_virtual_links;
|
||||||
hb_serialize_error_t errors;
|
hb_serialize_error_t errors;
|
||||||
};
|
};
|
||||||
|
|
||||||
snapshot_t snapshot ()
|
snapshot_t snapshot ()
|
||||||
{ return snapshot_t { head, tail, current, current->links.length, errors }; }
|
{ return snapshot_t {
|
||||||
|
head, tail, current, current->real_links.length, current->virtual_links.length, errors }; }
|
||||||
|
|
||||||
hb_serialize_context_t (void *start_, unsigned int size) :
|
hb_serialize_context_t (void *start_, unsigned int size) :
|
||||||
start ((char *) start_),
|
start ((char *) start_),
|
||||||
|
@ -282,7 +292,8 @@ struct hb_serialize_context_t
|
||||||
|
|
||||||
if (!len)
|
if (!len)
|
||||||
{
|
{
|
||||||
assert (!obj->links.length);
|
assert (!obj->real_links.length);
|
||||||
|
assert (!obj->virtual_links.length);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,6 +303,7 @@ struct hb_serialize_context_t
|
||||||
objidx = packed_map.get (obj);
|
objidx = packed_map.get (obj);
|
||||||
if (objidx)
|
if (objidx)
|
||||||
{
|
{
|
||||||
|
merge_virtual_links (obj, objidx);
|
||||||
obj->fini ();
|
obj->fini ();
|
||||||
return objidx;
|
return objidx;
|
||||||
}
|
}
|
||||||
|
@ -327,7 +339,8 @@ struct hb_serialize_context_t
|
||||||
// Overflows that happened after the snapshot will be erased by the revert.
|
// Overflows that happened after the snapshot will be erased by the revert.
|
||||||
if (unlikely (in_error () && !only_overflow ())) return;
|
if (unlikely (in_error () && !only_overflow ())) return;
|
||||||
assert (snap.current == current);
|
assert (snap.current == current);
|
||||||
current->links.shrink (snap.num_links);
|
current->real_links.shrink (snap.num_real_links);
|
||||||
|
current->virtual_links.shrink (snap.num_virtual_links);
|
||||||
errors = snap.errors;
|
errors = snap.errors;
|
||||||
revert (snap.head, snap.tail);
|
revert (snap.head, snap.tail);
|
||||||
}
|
}
|
||||||
|
@ -375,8 +388,8 @@ struct hb_serialize_context_t
|
||||||
|
|
||||||
assert (current);
|
assert (current);
|
||||||
|
|
||||||
auto& link = *current->links.push ();
|
auto& link = *current->virtual_links.push ();
|
||||||
if (current->links.in_error ())
|
if (current->virtual_links.in_error ())
|
||||||
err (HB_SERIALIZE_ERROR_OTHER);
|
err (HB_SERIALIZE_ERROR_OTHER);
|
||||||
|
|
||||||
link.width = 0;
|
link.width = 0;
|
||||||
|
@ -400,8 +413,8 @@ struct hb_serialize_context_t
|
||||||
assert (current);
|
assert (current);
|
||||||
assert (current->head <= (const char *) &ofs);
|
assert (current->head <= (const char *) &ofs);
|
||||||
|
|
||||||
auto& link = *current->links.push ();
|
auto& link = *current->real_links.push ();
|
||||||
if (current->links.in_error ())
|
if (current->real_links.in_error ())
|
||||||
err (HB_SERIALIZE_ERROR_OTHER);
|
err (HB_SERIALIZE_ERROR_OTHER);
|
||||||
|
|
||||||
link.width = sizeof (T);
|
link.width = sizeof (T);
|
||||||
|
@ -440,10 +453,8 @@ struct hb_serialize_context_t
|
||||||
assert (packed.length > 1);
|
assert (packed.length > 1);
|
||||||
|
|
||||||
for (const object_t* parent : ++hb_iter (packed))
|
for (const object_t* parent : ++hb_iter (packed))
|
||||||
for (const object_t::link_t &link : parent->links)
|
for (const object_t::link_t &link : parent->real_links)
|
||||||
{
|
{
|
||||||
if (unlikely (!link.width)) continue; // Don't need to resolve virtual offsets
|
|
||||||
|
|
||||||
const object_t* child = packed[link.objidx];
|
const object_t* child = packed[link.objidx];
|
||||||
if (unlikely (!child)) { err (HB_SERIALIZE_ERROR_OTHER); return; }
|
if (unlikely (!child)) { err (HB_SERIALIZE_ERROR_OTHER); return; }
|
||||||
unsigned offset = 0;
|
unsigned offset = 0;
|
||||||
|
@ -642,6 +653,13 @@ struct hb_serialize_context_t
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
void merge_virtual_links (const object_t* from, objidx_t to_idx) {
|
||||||
|
object_t* to = packed[to_idx];
|
||||||
|
for (const auto& l : from->virtual_links) {
|
||||||
|
to->virtual_links.push (l);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Object memory pool. */
|
/* Object memory pool. */
|
||||||
hb_pool_t<object_t> object_pool;
|
hb_pool_t<object_t> object_pool;
|
||||||
|
|
||||||
|
|
|
@ -763,20 +763,20 @@ populate_serializer_virtual_link (hb_serialize_context_t* c)
|
||||||
|
|
||||||
start_object ("b", 1, c);
|
start_object ("b", 1, c);
|
||||||
add_offset (obj_d, c);
|
add_offset (obj_d, c);
|
||||||
unsigned obj_b = c->pop_pack ();
|
unsigned obj_b = c->pop_pack (false);
|
||||||
|
|
||||||
start_object ("e", 1, c);
|
start_object ("e", 1, c);
|
||||||
add_virtual_offset (obj_b, c);
|
add_virtual_offset (obj_b, c);
|
||||||
unsigned obj_e = c->pop_pack();
|
unsigned obj_e = c->pop_pack (false);
|
||||||
|
|
||||||
start_object ("c", 1, c);
|
start_object ("c", 1, c);
|
||||||
add_offset (obj_e, c);
|
add_offset (obj_e, c);
|
||||||
unsigned obj_c = c->pop_pack ();
|
unsigned obj_c = c->pop_pack (false);
|
||||||
|
|
||||||
start_object ("a", 1, c);
|
start_object ("a", 1, c);
|
||||||
add_offset (obj_b, c);
|
add_offset (obj_b, c);
|
||||||
add_offset (obj_c, c);
|
add_offset (obj_c, c);
|
||||||
c->pop_pack ();
|
c->pop_pack (false);
|
||||||
|
|
||||||
c->end_serialize();
|
c->end_serialize();
|
||||||
}
|
}
|
||||||
|
@ -792,19 +792,19 @@ static void test_sort_kahn_1 ()
|
||||||
graph.sort_kahn ();
|
graph.sort_kahn ();
|
||||||
|
|
||||||
assert(strncmp (graph.object (3).head, "abc", 3) == 0);
|
assert(strncmp (graph.object (3).head, "abc", 3) == 0);
|
||||||
assert(graph.object (3).links.length == 2);
|
assert(graph.object (3).real_links.length == 2);
|
||||||
assert(graph.object (3).links[0].objidx == 2);
|
assert(graph.object (3).real_links[0].objidx == 2);
|
||||||
assert(graph.object (3).links[1].objidx == 1);
|
assert(graph.object (3).real_links[1].objidx == 1);
|
||||||
|
|
||||||
assert(strncmp (graph.object (2).head, "def", 3) == 0);
|
assert(strncmp (graph.object (2).head, "def", 3) == 0);
|
||||||
assert(graph.object (2).links.length == 1);
|
assert(graph.object (2).real_links.length == 1);
|
||||||
assert(graph.object (2).links[0].objidx == 0);
|
assert(graph.object (2).real_links[0].objidx == 0);
|
||||||
|
|
||||||
assert(strncmp (graph.object (1).head, "jkl", 3) == 0);
|
assert(strncmp (graph.object (1).head, "jkl", 3) == 0);
|
||||||
assert(graph.object (1).links.length == 0);
|
assert(graph.object (1).real_links.length == 0);
|
||||||
|
|
||||||
assert(strncmp (graph.object (0).head, "ghi", 3) == 0);
|
assert(strncmp (graph.object (0).head, "ghi", 3) == 0);
|
||||||
assert(graph.object (0).links.length == 0);
|
assert(graph.object (0).real_links.length == 0);
|
||||||
|
|
||||||
free (buffer);
|
free (buffer);
|
||||||
}
|
}
|
||||||
|
@ -821,24 +821,24 @@ static void test_sort_kahn_2 ()
|
||||||
|
|
||||||
|
|
||||||
assert(strncmp (graph.object (4).head, "abc", 3) == 0);
|
assert(strncmp (graph.object (4).head, "abc", 3) == 0);
|
||||||
assert(graph.object (4).links.length == 3);
|
assert(graph.object (4).real_links.length == 3);
|
||||||
assert(graph.object (4).links[0].objidx == 3);
|
assert(graph.object (4).real_links[0].objidx == 3);
|
||||||
assert(graph.object (4).links[1].objidx == 0);
|
assert(graph.object (4).real_links[1].objidx == 0);
|
||||||
assert(graph.object (4).links[2].objidx == 2);
|
assert(graph.object (4).real_links[2].objidx == 2);
|
||||||
|
|
||||||
assert(strncmp (graph.object (3).head, "def", 3) == 0);
|
assert(strncmp (graph.object (3).head, "def", 3) == 0);
|
||||||
assert(graph.object (3).links.length == 1);
|
assert(graph.object (3).real_links.length == 1);
|
||||||
assert(graph.object (3).links[0].objidx == 1);
|
assert(graph.object (3).real_links[0].objidx == 1);
|
||||||
|
|
||||||
assert(strncmp (graph.object (2).head, "mn", 2) == 0);
|
assert(strncmp (graph.object (2).head, "mn", 2) == 0);
|
||||||
assert(graph.object (2).links.length == 0);
|
assert(graph.object (2).real_links.length == 0);
|
||||||
|
|
||||||
assert(strncmp (graph.object (1).head, "ghi", 3) == 0);
|
assert(strncmp (graph.object (1).head, "ghi", 3) == 0);
|
||||||
assert(graph.object (1).links.length == 1);
|
assert(graph.object (1).real_links.length == 1);
|
||||||
assert(graph.object (1).links[0].objidx == 0);
|
assert(graph.object (1).real_links[0].objidx == 0);
|
||||||
|
|
||||||
assert(strncmp (graph.object (0).head, "jkl", 3) == 0);
|
assert(strncmp (graph.object (0).head, "jkl", 3) == 0);
|
||||||
assert(graph.object (0).links.length == 0);
|
assert(graph.object (0).real_links.length == 0);
|
||||||
|
|
||||||
free (buffer);
|
free (buffer);
|
||||||
}
|
}
|
||||||
|
@ -854,24 +854,24 @@ static void test_sort_shortest ()
|
||||||
graph.sort_shortest_distance ();
|
graph.sort_shortest_distance ();
|
||||||
|
|
||||||
assert(strncmp (graph.object (4).head, "abc", 3) == 0);
|
assert(strncmp (graph.object (4).head, "abc", 3) == 0);
|
||||||
assert(graph.object (4).links.length == 3);
|
assert(graph.object (4).real_links.length == 3);
|
||||||
assert(graph.object (4).links[0].objidx == 2);
|
assert(graph.object (4).real_links[0].objidx == 2);
|
||||||
assert(graph.object (4).links[1].objidx == 0);
|
assert(graph.object (4).real_links[1].objidx == 0);
|
||||||
assert(graph.object (4).links[2].objidx == 3);
|
assert(graph.object (4).real_links[2].objidx == 3);
|
||||||
|
|
||||||
assert(strncmp (graph.object (3).head, "mn", 2) == 0);
|
assert(strncmp (graph.object (3).head, "mn", 2) == 0);
|
||||||
assert(graph.object (3).links.length == 0);
|
assert(graph.object (3).real_links.length == 0);
|
||||||
|
|
||||||
assert(strncmp (graph.object (2).head, "def", 3) == 0);
|
assert(strncmp (graph.object (2).head, "def", 3) == 0);
|
||||||
assert(graph.object (2).links.length == 1);
|
assert(graph.object (2).real_links.length == 1);
|
||||||
assert(graph.object (2).links[0].objidx == 1);
|
assert(graph.object (2).real_links[0].objidx == 1);
|
||||||
|
|
||||||
assert(strncmp (graph.object (1).head, "ghi", 3) == 0);
|
assert(strncmp (graph.object (1).head, "ghi", 3) == 0);
|
||||||
assert(graph.object (1).links.length == 1);
|
assert(graph.object (1).real_links.length == 1);
|
||||||
assert(graph.object (1).links[0].objidx == 0);
|
assert(graph.object (1).real_links[0].objidx == 0);
|
||||||
|
|
||||||
assert(strncmp (graph.object (0).head, "jkl", 3) == 0);
|
assert(strncmp (graph.object (0).head, "jkl", 3) == 0);
|
||||||
assert(graph.object (0).links.length == 0);
|
assert(graph.object (0).real_links.length == 0);
|
||||||
|
|
||||||
free (buffer);
|
free (buffer);
|
||||||
}
|
}
|
||||||
|
@ -887,27 +887,27 @@ static void test_duplicate_leaf ()
|
||||||
graph.duplicate (4, 1);
|
graph.duplicate (4, 1);
|
||||||
|
|
||||||
assert(strncmp (graph.object (5).head, "abc", 3) == 0);
|
assert(strncmp (graph.object (5).head, "abc", 3) == 0);
|
||||||
assert(graph.object (5).links.length == 3);
|
assert(graph.object (5).real_links.length == 3);
|
||||||
assert(graph.object (5).links[0].objidx == 3);
|
assert(graph.object (5).real_links[0].objidx == 3);
|
||||||
assert(graph.object (5).links[1].objidx == 4);
|
assert(graph.object (5).real_links[1].objidx == 4);
|
||||||
assert(graph.object (5).links[2].objidx == 0);
|
assert(graph.object (5).real_links[2].objidx == 0);
|
||||||
|
|
||||||
assert(strncmp (graph.object (4).head, "jkl", 3) == 0);
|
assert(strncmp (graph.object (4).head, "jkl", 3) == 0);
|
||||||
assert(graph.object (4).links.length == 0);
|
assert(graph.object (4).real_links.length == 0);
|
||||||
|
|
||||||
assert(strncmp (graph.object (3).head, "def", 3) == 0);
|
assert(strncmp (graph.object (3).head, "def", 3) == 0);
|
||||||
assert(graph.object (3).links.length == 1);
|
assert(graph.object (3).real_links.length == 1);
|
||||||
assert(graph.object (3).links[0].objidx == 2);
|
assert(graph.object (3).real_links[0].objidx == 2);
|
||||||
|
|
||||||
assert(strncmp (graph.object (2).head, "ghi", 3) == 0);
|
assert(strncmp (graph.object (2).head, "ghi", 3) == 0);
|
||||||
assert(graph.object (2).links.length == 1);
|
assert(graph.object (2).real_links.length == 1);
|
||||||
assert(graph.object (2).links[0].objidx == 1);
|
assert(graph.object (2).real_links[0].objidx == 1);
|
||||||
|
|
||||||
assert(strncmp (graph.object (1).head, "jkl", 3) == 0);
|
assert(strncmp (graph.object (1).head, "jkl", 3) == 0);
|
||||||
assert(graph.object (1).links.length == 0);
|
assert(graph.object (1).real_links.length == 0);
|
||||||
|
|
||||||
assert(strncmp (graph.object (0).head, "mn", 2) == 0);
|
assert(strncmp (graph.object (0).head, "mn", 2) == 0);
|
||||||
assert(graph.object (0).links.length == 0);
|
assert(graph.object (0).real_links.length == 0);
|
||||||
|
|
||||||
free (buffer);
|
free (buffer);
|
||||||
}
|
}
|
||||||
|
@ -923,32 +923,32 @@ static void test_duplicate_interior ()
|
||||||
graph.duplicate (3, 2);
|
graph.duplicate (3, 2);
|
||||||
|
|
||||||
assert(strncmp (graph.object (6).head, "abc", 3) == 0);
|
assert(strncmp (graph.object (6).head, "abc", 3) == 0);
|
||||||
assert(graph.object (6).links.length == 3);
|
assert(graph.object (6).real_links.length == 3);
|
||||||
assert(graph.object (6).links[0].objidx == 4);
|
assert(graph.object (6).real_links[0].objidx == 4);
|
||||||
assert(graph.object (6).links[1].objidx == 2);
|
assert(graph.object (6).real_links[1].objidx == 2);
|
||||||
assert(graph.object (6).links[2].objidx == 1);
|
assert(graph.object (6).real_links[2].objidx == 1);
|
||||||
|
|
||||||
assert(strncmp (graph.object (5).head, "jkl", 3) == 0);
|
assert(strncmp (graph.object (5).head, "jkl", 3) == 0);
|
||||||
assert(graph.object (5).links.length == 1);
|
assert(graph.object (5).real_links.length == 1);
|
||||||
assert(graph.object (5).links[0].objidx == 0);
|
assert(graph.object (5).real_links[0].objidx == 0);
|
||||||
|
|
||||||
assert(strncmp (graph.object (4).head, "def", 3) == 0);
|
assert(strncmp (graph.object (4).head, "def", 3) == 0);
|
||||||
assert(graph.object (4).links.length == 1);
|
assert(graph.object (4).real_links.length == 1);
|
||||||
assert(graph.object (4).links[0].objidx == 3);
|
assert(graph.object (4).real_links[0].objidx == 3);
|
||||||
|
|
||||||
assert(strncmp (graph.object (3).head, "ghi", 3) == 0);
|
assert(strncmp (graph.object (3).head, "ghi", 3) == 0);
|
||||||
assert(graph.object (3).links.length == 1);
|
assert(graph.object (3).real_links.length == 1);
|
||||||
assert(graph.object (3).links[0].objidx == 5);
|
assert(graph.object (3).real_links[0].objidx == 5);
|
||||||
|
|
||||||
assert(strncmp (graph.object (2).head, "jkl", 3) == 0);
|
assert(strncmp (graph.object (2).head, "jkl", 3) == 0);
|
||||||
assert(graph.object (2).links.length == 1);
|
assert(graph.object (2).real_links.length == 1);
|
||||||
assert(graph.object (2).links[0].objidx == 0);
|
assert(graph.object (2).real_links[0].objidx == 0);
|
||||||
|
|
||||||
assert(strncmp (graph.object (1).head, "mn", 2) == 0);
|
assert(strncmp (graph.object (1).head, "mn", 2) == 0);
|
||||||
assert(graph.object (1).links.length == 0);
|
assert(graph.object (1).real_links.length == 0);
|
||||||
|
|
||||||
assert(strncmp (graph.object (0).head, "opqrst", 6) == 0);
|
assert(strncmp (graph.object (0).head, "opqrst", 6) == 0);
|
||||||
assert(graph.object (0).links.length == 0);
|
assert(graph.object (0).real_links.length == 0);
|
||||||
|
|
||||||
free (buffer);
|
free (buffer);
|
||||||
}
|
}
|
||||||
|
@ -1247,6 +1247,43 @@ static void test_virtual_link ()
|
||||||
free (out_buffer);
|
free (out_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_shared_node_with_virtual_links ()
|
||||||
|
{
|
||||||
|
size_t buffer_size = 100;
|
||||||
|
void* buffer = malloc (buffer_size);
|
||||||
|
hb_serialize_context_t c (buffer, buffer_size);
|
||||||
|
|
||||||
|
c.start_serialize<char> ();
|
||||||
|
|
||||||
|
unsigned obj_b = add_object ("b", 1, &c);
|
||||||
|
unsigned obj_c = add_object ("c", 1, &c);
|
||||||
|
|
||||||
|
start_object ("d", 1, &c);
|
||||||
|
add_virtual_offset (obj_b, &c);
|
||||||
|
unsigned obj_d_1 = c.pop_pack ();
|
||||||
|
|
||||||
|
start_object ("d", 1, &c);
|
||||||
|
add_virtual_offset (obj_c, &c);
|
||||||
|
unsigned obj_d_2 = c.pop_pack ();
|
||||||
|
|
||||||
|
assert (obj_d_1 == obj_d_2);
|
||||||
|
|
||||||
|
start_object ("a", 1, &c);
|
||||||
|
add_offset (obj_b, &c);
|
||||||
|
add_offset (obj_c, &c);
|
||||||
|
add_offset (obj_d_1, &c);
|
||||||
|
add_offset (obj_d_2, &c);
|
||||||
|
c.pop_pack ();
|
||||||
|
c.end_serialize ();
|
||||||
|
|
||||||
|
assert(c.object_graph() [obj_d_1]->virtual_links.length == 2);
|
||||||
|
assert(c.object_graph() [obj_d_1]->virtual_links[0].objidx == obj_b);
|
||||||
|
assert(c.object_graph() [obj_d_1]->virtual_links[1].objidx == obj_c);
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// TODO(garretrieger): update will_overflow tests to check the overflows array.
|
// TODO(garretrieger): update will_overflow tests to check the overflows array.
|
||||||
// TODO(garretrieger): add tests for priority raising.
|
// TODO(garretrieger): add tests for priority raising.
|
||||||
|
|
||||||
|
@ -1273,4 +1310,5 @@ main (int argc, char **argv)
|
||||||
test_duplicate_leaf ();
|
test_duplicate_leaf ();
|
||||||
test_duplicate_interior ();
|
test_duplicate_interior ();
|
||||||
test_virtual_link ();
|
test_virtual_link ();
|
||||||
|
test_shared_node_with_virtual_links ();
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue