| 272 | } |
| 273 | |
| 274 | void Signature::FindUniqueHashes(size_t* next_node_id_p) { |
| 275 | // Start by sorting by the hash value. |
| 276 | std::sort(nodes.begin() + *next_node_id_p, nodes.end(), |
| 277 | SigNode::NodeOrderLess()); |
| 278 | |
| 279 | // At each call, if no nodes have unique hashes, one node that has a |
| 280 | // non-unique (shared) hash can be made unique by assigning a unique id. |
| 281 | // This node gets picked predictably by taking the last node. |
| 282 | // TODO(babkin): Technically, more than one node can be unshared, |
| 283 | // as long as their last_hashed_nodes_ overlap only by the nodes that |
| 284 | // already had the assigned ids before the current round. But it's not clear |
| 285 | // yet, how often would this beneficial, because it looks like for many |
| 286 | // subgraphs unsharing one node should be enough to untangle them. This |
| 287 | // would need more measurement before implementing. |
| 288 | bool found_unique = false; |
| 289 | for (size_t n = *next_node_id_p; n < nodes.size(); ++n) { |
| 290 | size_t cur_hash = nodes[n]->GetHighTopoHash(); |
| 291 | if (n + 1 < nodes.size() && nodes[n + 1]->GetHighTopoHash() == cur_hash) { |
| 292 | // A sequence of nodes sharing the same hash. Skip over it. |
| 293 | // TODO(babkin): check here for the arbitrary hash conflicts and resolve |
| 294 | // them. |
| 295 | for (++n; |
| 296 | n + 1 < nodes.size() && nodes[n + 1]->GetHighTopoHash() == cur_hash; |
| 297 | ++n) { |
| 298 | } |
| 299 | if (found_unique || n != nodes.size() - 1) { |
| 300 | // Either some unique nodes have already been found, or this is |
| 301 | // not the last chance, keep trying to find the unique nodes. |
| 302 | continue; |
| 303 | } |
| 304 | // Here we're at the last node and haven't found any unique ones. |
| 305 | // So fall through and make this last node unique. |
| 306 | } |
| 307 | |
| 308 | found_unique = true; |
| 309 | size_t id = (*next_node_id_p)++; |
| 310 | nodes[n]->unique_rank_ = id; |
| 311 | |
| 312 | size_t last_hash = nodes[n]->GetHighTopoHash(); |
| 313 | CombineHash(last_hash, &sig_short); |
| 314 | sig_full.push_back(last_hash); |
| 315 | |
| 316 | // Take the hash at 0 and mix the unique rank into it. After that it will |
| 317 | // stay fixed. |
| 318 | nodes[n]->topo_hash_.resize(1); |
| 319 | nodes[n]->topo_hash_[0] = id + 1; // Avoid the value of 0. |
| 320 | |
| 321 | nodes[n]->hash_is_final_ = true; |
| 322 | nodes[n]->last_hashed_nodes_ = nodes[n]->node_mask_; |
| 323 | if (n != id) { |
| 324 | std::swap(nodes[id], nodes[n]); |
| 325 | } |
| 326 | } |
| 327 | } |
| 328 | |
| 329 | void Signature::ComputeOneRound(size_t next_node_id) { |
| 330 | // Reset the state of the nodes. |
nothing calls this directly
no test coverage detected