| // Copyright 2017-2020 The Verible Authors. |
| // |
| // 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 VERIBLE_COMMON_UTIL_VECTOR_TREE_H_ |
| #define VERIBLE_COMMON_UTIL_VECTOR_TREE_H_ |
| |
| #include <algorithm> |
| #include <cstddef> |
| #include <functional> |
| #include <iosfwd> // IWYU pragma: keep |
| #include <iterator> |
| #include <numeric> |
| #include <set> |
| #include <utility> |
| #include <vector> |
| |
| #include "common/util/container_proxy.h" |
| #include "common/util/iterator_range.h" |
| #include "common/util/logging.h" |
| #include "common/util/type_traits.h" |
| |
| namespace verible { |
| |
| // VectorTree is a hierarchical representation of information. |
| // While it may be useful to maintain some invariant relationship between |
| // parents and children nodes, it is not required for this class. |
| // The traversal methods ApplyPreOrder/ApplyPostOrder could be used to |
| // maintain or verify parent-child invariants. |
| // The VectorTree class is itself also the same as the vector_tree_internally |
| // used node class; i.e. there is no separate node class. |
| // |
| // Example applications (with some parent-child invariant relationship): |
| // |
| // * Range interval tree -- A numeric range from [0:N] could be sub-divided |
| // into smaller ranges [0:k], [k:N] for some 0 < k < N, or multiple |
| // monotonically increasing k's. This class is a generalization of an |
| // interval tree concept. |
| // |
| // * Lexical tokens output -- some tokens could be further tokenized or |
| // expanded, but the choice of view depends on consumer and application. |
| // This can be useful for embedding snippets of one language within another; |
| // further lexing/parsing of an unexpanded substring can be deferred. |
| // |
| // * Lexical token range partitions -- token sub-range partitioning is a |
| // critical step in a formatting strategy; the decision to partition |
| // a particular range may be difficult to determine statically, so it |
| // is best left undecided until a later heuristic pass. |
| // |
| // Construction: |
| // This implementation gives the user the liberty to construct the tree |
| // nodes in any order and any manner. A top-down construction may guarantee |
| // that a parent is well-formed before creating its children, whereas a |
| // bottom-up construction completes creation of children before the enveloping |
| // parent. |
| template <typename T> |
| class VectorTree { |
| typedef VectorTree<T> this_type; |
| |
| // Forward declaration |
| class ChildrenList; |
| |
| public: |
| // Self-recursive type that represents children in an expanded view. |
| typedef std::vector<this_type> subnodes_type; |
| typedef T value_type; |
| |
| VectorTree() : children_(*this) {} |
| |
| // Deep copy-constructor. |
| VectorTree(const this_type& other) |
| : node_value_(other.node_value_), |
| parent_(other.parent_), |
| children_(*this, other.children_) {} |
| |
| VectorTree(this_type&& other) noexcept |
| : node_value_(std::move(other.node_value_)), |
| parent_(other.parent_), |
| children_(*this, std::move(other.children_)) {} |
| |
| // This constructor can be used to recursively build trees. |
| // e.g. |
| // // looks like function-call, but just invokes constructor: |
| // typedef VectorTree<Foo> FooNode; |
| // auto foo_tree = FooNode({value-initializer}, |
| // FooNode({value-initializer}, /* children nodes... */ ), |
| // FooNode({value-initializer}, /* children nodes... */ ) |
| // ); |
| template <typename... Args> |
| explicit VectorTree(const value_type& v, Args&&... args) |
| : node_value_(v), children_(*this) { |
| children_.reserve(sizeof...(args)); |
| (children_.emplace_back(std::forward<Args>(args)), ...); |
| } |
| |
| template <typename... Args> |
| explicit VectorTree(value_type&& v, Args&&... args) |
| : node_value_(std::move(v)), children_(*this) { |
| children_.reserve(sizeof...(args)); |
| (children_.emplace_back(std::forward<Args>(args)), ...); |
| } |
| |
| ~VectorTree() { CHECK(CheckIntegrity()); } |
| |
| // Swaps values and subtrees of two nodes. |
| // This operation is safe for unrelated trees (no common ancestor). |
| // This operation is safe when the two nodes share a common ancestor, |
| // excluding the case where one node is a direct ancestor of the other. |
| // TODO(fangism): Add a proper check for this property, and test. |
| void swap(this_type& other) { |
| std::swap(node_value_, other.node_value_); |
| children_.swap(other.children_); // efficient O(1) vector::swap |
| // + O(|children|) linking to parent |
| } |
| |
| // Copy value and children, but relink new children to this node. |
| VectorTree& operator=(const this_type& source) { |
| if (this == &source) return *this; |
| node_value_ = source.node_value_; |
| children_ = source.children_; |
| return *this; |
| } |
| |
| // Explicit move-assignability needed for vector::erase() |
| // No need to change parent links when children keep same parent. |
| VectorTree& operator=(this_type&& source) noexcept { |
| node_value_ = std::move(source.node_value_); |
| children_ = std::move(source.children_); |
| return *this; |
| } |
| |
| // Accessors |
| |
| T& Value() { return node_value_; } |
| |
| const T& Value() const { return node_value_; } |
| |
| this_type* Parent() { return parent_; } |
| |
| const this_type* Parent() const { return parent_; } |
| |
| ChildrenList& Children() { return children_; } |
| |
| const ChildrenList& Children() const { return children_; } |
| |
| private: |
| // Returns true if parent-child links are valid in entire tree. |
| bool CheckIntegrity() const { |
| for (const auto& child : children_) { |
| CHECK_EQ(child.Parent(), this) |
| << "Inconsistency: child's parent does not point back to this node!"; |
| if (!child.CheckIntegrity()) return false; |
| } |
| return true; |
| } |
| |
| // A wrapper of a sequence container for storing VectorTree nodes that sets |
| // correct parent pointer in each inserted node. The reference to the |
| // "correct" parent is passed to a constructor. |
| // |
| // The sole purpose of this class is to function as a children list in |
| // VectorTree, both as a storage and as a public interface for tree |
| // manipulation (through reference). |
| // |
| // This class handles parent pointer assignment for all cases where the |
| // children list itself is modified. However, it does not clear or otherwise |
| // change parent pointer in removed nodes. |
| class ChildrenList : ContainerProxyBase<ChildrenList, subnodes_type> { |
| using Base = ContainerProxyBase<ChildrenList, subnodes_type>; |
| friend Base; |
| |
| public: |
| using typename Base::container_type; |
| |
| // Import (via `using`) ContainerProxy members supported by std::vector. |
| USING_CONTAINER_PROXY_STD_VECTOR_MEMBERS(Base) |
| |
| // Move-cast to wrapped container's type. Moves out the container. |
| explicit operator container_type() && { return std::move(container_); } |
| |
| protected: |
| // ContainerProxy interface |
| |
| container_type& underlying_container() { return container_; } |
| const container_type& underlying_container() const { return container_; } |
| |
| void ElementsInserted(iterator first, iterator last) { |
| LinkChildrenToParent(iterator_range(first, last)); |
| } |
| |
| // Unused: |
| // void ElementsBeingRemoved(iterator first, iterator last) |
| |
| // Unused: |
| // void ElementsBeingReplaced() |
| |
| void ElementsWereReplaced() { LinkChildrenToParent(container_); } |
| |
| private: |
| // Sets parent pointer of nodes from `children` range to address of `node_`. |
| template <class Range> |
| void LinkChildrenToParent(Range&& children) { |
| for (auto& child : children) { |
| child.parent_ = &node_; |
| } |
| } |
| |
| // Allow construction, assignment and direct access to `container_` inside |
| // VectorTree. |
| friend VectorTree; |
| |
| // Hide constructors and assignments from the world. This object is created |
| // and assigned-to only in VectorTree. |
| |
| explicit ChildrenList(VectorTree& node) : node_(node) {} |
| |
| // Construction requires parent node reference. |
| ChildrenList(const ChildrenList&) = delete; |
| |
| ChildrenList(VectorTree& node, const ChildrenList& other) |
| : node_(node), container_(other.container_) { |
| LinkChildrenToParent(container_); |
| } |
| |
| ChildrenList& operator=(const ChildrenList& other) { |
| container_ = other.container_; |
| LinkChildrenToParent(container_); |
| return *this; |
| } |
| |
| // Construction requires parent node reference. |
| ChildrenList(ChildrenList&&) = delete; |
| |
| ChildrenList(VectorTree& node, ChildrenList&& other) noexcept |
| : node_(node), container_(std::move(other.container_)) { |
| // Note: `other` is not notified about the change because it ends up in |
| // undefined state as a result of the move. |
| LinkChildrenToParent(container_); |
| } |
| |
| ChildrenList& operator=(ChildrenList&& other) noexcept { |
| // Note: `other` is not notified about the change because it ends up in |
| // undefined state as a result of the move. |
| container_ = std::move(other.container_); |
| LinkChildrenToParent(container_); |
| return *this; |
| } |
| |
| // Reference to a VectorTree node in which this object represents a list of |
| // children. |
| // TODO(mglb): try to get rid of this reference. See: |
| // https://github.com/chipsalliance/verible/pull/1252#discussion_r825196108 |
| // Also look at MapTree::KeyValuePair() - `offsetof` is already used there |
| // so it could be user here too. |
| VectorTree& node_; |
| |
| // Actual data container where the nodes are stored. |
| subnodes_type container_; |
| }; |
| |
| // Singular value stored at this node. |
| value_type node_value_; |
| |
| // Pointer up to parent node. |
| // Only the root node of a tree has a nullptr parent_. |
| // This value is managed by ChildrenList, constructors, and |
| // operator=(). There should be no need to set it manually in other places. |
| this_type* parent_ = nullptr; |
| |
| // Array of nodes/subtrees. |
| ChildrenList children_; |
| }; |
| |
| // Provide ADL-enabled overload for use by swap implementations. |
| template <class T> |
| void swap(VectorTree<T>& left, VectorTree<T>& right) { |
| left.swap(right); |
| } |
| |
| } // namespace verible |
| |
| #endif // VERIBLE_COMMON_UTIL_VECTOR_TREE_H_ |