| /* | |
| * Copyright 2024 WebAssembly Community Group participants | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #ifndef wasm_support_disjoint_sets_h | |
| #define wasm_support_disjoint_sets_h | |
| #include <cassert> | |
| #include <cstddef> | |
| #include <vector> | |
| namespace wasm { | |
| // A disjoint set forest (a.k.a. union-find) implementation. See | |
| // https://en.wikipedia.org/wiki/Disjoint-set_data_structure. | |
| struct DisjointSets { | |
| struct ElemInfo { | |
| // The index of the parent element, or the index of the element itself if it | |
| // has no parent. | |
| size_t parent; | |
| // An upper bound on the height of the tree rooted at this element. | |
| size_t rank; | |
| }; | |
| mutable std::vector<ElemInfo> info; | |
| // Add an element and return its index. | |
| size_t addSet() { | |
| size_t ret = info.size(); | |
| info.push_back({ret, 0}); | |
| return ret; | |
| } | |
| // Get the representative element of the set to which `elem` belongs. | |
| size_t getRoot(size_t elem) const { | |
| assert(elem < info.size()); | |
| size_t root = elem; | |
| // Follow parent pointers up to the root. | |
| for (; info[root].parent != root; root = info[root].parent) { | |
| } | |
| // Compress the path to make subsequent getRoots of this set faster. | |
| while (elem != root) { | |
| size_t parent = info[elem].parent; | |
| info[elem].parent = root; | |
| elem = parent; | |
| } | |
| return root; | |
| } | |
| // Join the sets to which the elements belong and return the representative | |
| // element of the union. | |
| size_t getUnion(size_t elem1, size_t elem2) { | |
| assert(elem1 < info.size() && elem2 < info.size()); | |
| size_t root1 = getRoot(elem1); | |
| size_t root2 = getRoot(elem2); | |
| if (root1 == root2) { | |
| // Already in the same set. | |
| return root1; | |
| } | |
| // Canonicalize so that root1 has the greater rank. | |
| if (info[root1].rank < info[root2].rank) { | |
| std::swap(root1, root2); | |
| } | |
| // Merge the trees, smaller into larger. | |
| info[root2].parent = root1; | |
| // If the ranks were equal, the new root has a larger rank. | |
| if (info[root1].rank == info[root2].rank) { | |
| ++info[root1].rank; | |
| } | |
| return root1; | |
| } | |
| // Reserve space for `size` disjoint sets. | |
| void reserve(size_t size) { info.reserve(size); } | |
| }; | |
| } // namespace wasm | |
| #endif // wasm_support_disjoint_sets_h |