//===- InputTree.h --------------------------------------------------------===// // // The MCLinker Project // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef MCLD_INPUT_TREE_H #define MCLD_INPUT_TREE_H #ifdef ENABLE_UNITTEST #include <gtest.h> #endif #include "mcld/ADT/BinTree.h" #include "mcld/ADT/TypeTraits.h" #include "mcld/MC/MCLDInput.h" #include "mcld/MC/InputFactory.h" #include "mcld/Support/FileSystem.h" #include <string> namespace mcld { /** \class template<typename Traits, typename Iterator> PolicyIterator<mcld::Input> * \brief PolicyIterator<mcld::Input> is a partially specific PolicyIterator */ template<typename Traits, typename IteratorType> class PolicyIterator<mcld::Input, Traits, IteratorType> : public PolicyIteratorBase<Input, Traits, IteratorType> { public: typedef PolicyIterator<Input, Traits, IteratorType> Self; typedef PolicyIteratorBase<Input, Traits, IteratorType> Base; typedef PolicyIterator<Input, typename Traits::nonconst_traits, IteratorType> iterator; typedef PolicyIterator<Input, typename Traits::const_traits, IteratorType> const_iterator; public: PolicyIterator() : Base() {} PolicyIterator(const iterator &X) : Base(X.m_pNode) {} explicit PolicyIterator(NodeBase* X) : Base(X) {} virtual ~PolicyIterator() {} bool isGroup() const { return !Base::hasData(); } Self& operator++() { IteratorType::advance(); if (isGroup()) IteratorType::advance(); return *this; } Self operator++(int) { Self tmp(*this); IteratorType::advance(); if (isGroup()) IteratorType::advance(); return tmp; } }; /** \class InputTree * \brief InputTree is the input tree to contains all inputs from the * command line. * * InputTree, of course, is uncopyable. * * @see Input */ class InputTree : public BinaryTree<Input> { private: typedef BinaryTree<Input> BinTreeTy; public: enum Direction { Inclusive = TreeIteratorBase::Leftward, Positional = TreeIteratorBase::Rightward }; typedef BinaryTree<Input>::iterator iterator; typedef BinaryTree<Input>::const_iterator const_iterator; public: /** \class Mover * \brief Mover provides the interface for moving iterator forward. * * Mover is a function object (functor). @ref Mover::move moves * iterator forward in certain direction. @ref Mover::connect * connects two nodes of the given iterators togather. */ struct Mover { virtual ~Mover() {} virtual void connect(TreeIteratorBase& pFrom, const TreeIteratorBase& pTo) const = 0; virtual void move(TreeIteratorBase& pNode) const = 0; }; /** \class Succeeder * \brief class Succeeder moves the iterator afterward. */ struct Succeeder : public Mover { virtual void connect(TreeIteratorBase& pFrom, const TreeIteratorBase& pTo) const { proxy::hook<Positional>(pFrom.m_pNode, pTo.m_pNode); } virtual void move(TreeIteratorBase& pNode) const { pNode.move<Positional>(); } }; /** \class Includer * \brief class Includer moves the iterator downward. */ struct Includer : public Mover { virtual void connect(TreeIteratorBase& pFrom, const TreeIteratorBase& pTo) const { proxy::hook<Inclusive>(pFrom.m_pNode, pTo.m_pNode); } virtual void move(TreeIteratorBase& pNode) const { pNode.move<Inclusive>(); } }; public: static Succeeder Afterward; static Includer Downward; public: using BinTreeTy::merge; InputTree(InputFactory& pInputFactory); ~InputTree(); // ----- modify ----- // /// insert - create a leaf node and merge it in the tree. // This version of join determines the direction at run time. // @param pRoot position the parent node // @param pMover the direction of the connecting edge of the parent node. template<size_t DIRECT> InputTree& insert(TreeIteratorBase pRoot, const std::string& pNamespec, const sys::fs::Path& pPath, unsigned int pType = Input::Unknown); template<size_t DIRECT> InputTree& enterGroup(TreeIteratorBase pRoot); template<size_t DIRECT> InputTree& insert(TreeIteratorBase pRoot, const Input& pInput); InputTree& merge(TreeIteratorBase pRoot, const Mover& pMover, InputTree& pTree); InputTree& insert(TreeIteratorBase pRoot, const Mover& pMover, const std::string& pNamespec, const sys::fs::Path& pPath, unsigned int pType = Input::Unknown); InputTree& insert(TreeIteratorBase pRoot, const Mover& pMover, const Input& pInput); InputTree& enterGroup(TreeIteratorBase pRoot, const Mover& pMover); // ----- observers ----- // unsigned int numOfInputs() const { return m_FileFactory.size(); } bool hasInput() const { return !m_FileFactory.empty(); } private: InputFactory& m_FileFactory; }; bool isGroup(const InputTree::iterator& pos); bool isGroup(const InputTree::const_iterator& pos); bool isGroup(const InputTree::dfs_iterator& pos); bool isGroup(const InputTree::const_dfs_iterator& pos); bool isGroup(const InputTree::bfs_iterator& pos); bool isGroup(const InputTree::const_bfs_iterator& pos); } // namespace of mcld //===----------------------------------------------------------------------===// // template member functions template<size_t DIRECT> mcld::InputTree& mcld::InputTree::insert(mcld::TreeIteratorBase pRoot, const std::string& pNamespec, const mcld::sys::fs::Path& pPath, unsigned int pType) { BinTreeTy::node_type* node = createNode(); node->data = m_FileFactory.produce(pNamespec, pPath, pType); if (pRoot.isRoot()) proxy::hook<TreeIteratorBase::Leftward>(pRoot.m_pNode, const_cast<const node_type*>(node)); else proxy::hook<DIRECT>(pRoot.m_pNode, const_cast<const node_type*>(node)); return *this; } template<size_t DIRECT> mcld::InputTree& mcld::InputTree::enterGroup(mcld::TreeIteratorBase pRoot) { BinTreeTy::node_type* node = createNode(); if (pRoot.isRoot()) proxy::hook<TreeIteratorBase::Leftward>(pRoot.m_pNode, const_cast<const node_type*>(node)); else proxy::hook<DIRECT>(pRoot.m_pNode, const_cast<const node_type*>(node)); return *this; } template<size_t DIRECT> mcld::InputTree& mcld::InputTree::insert(mcld::TreeIteratorBase pRoot, const mcld::Input& pInput) { BinTreeTy::node_type* node = createNode(); node->data = const_cast<mcld::Input*>(&pInput); if (pRoot.isRoot()) proxy::hook<TreeIteratorBase::Leftward>(pRoot.m_pNode, const_cast<const node_type*>(node)); else proxy::hook<DIRECT>(pRoot.m_pNode, const_cast<const node_type*>(node)); return *this; } #endif