1//===- InputTree.h --------------------------------------------------------===//
2//
3//                     The MCLinker Project
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9#ifndef MCLD_INPUT_TREE_H
10#define MCLD_INPUT_TREE_H
11#ifdef ENABLE_UNITTEST
12#include <gtest.h>
13#endif
14
15#include "mcld/ADT/BinTree.h"
16#include "mcld/ADT/TypeTraits.h"
17#include "mcld/MC/MCLDInput.h"
18#include "mcld/MC/InputFactory.h"
19#include "mcld/Support/FileSystem.h"
20
21#include <string>
22
23
24namespace mcld
25{
26
27/** \class template<typename Traits, typename Iterator> PolicyIterator<mcld::Input>
28 *  \brief PolicyIterator<mcld::Input> is a partially specific PolicyIterator
29 */
30template<typename Traits, typename IteratorType>
31class PolicyIterator<mcld::Input, Traits, IteratorType> : public PolicyIteratorBase<Input, Traits, IteratorType>
32{
33public:
34  typedef PolicyIterator<Input, Traits, IteratorType> Self;
35  typedef PolicyIteratorBase<Input, Traits, IteratorType> Base;
36  typedef PolicyIterator<Input, typename Traits::nonconst_traits, IteratorType> iterator;
37  typedef PolicyIterator<Input, typename Traits::const_traits, IteratorType>    const_iterator;
38
39public:
40  PolicyIterator()
41    : Base() {}
42
43  PolicyIterator(const iterator &X)
44    : Base(X.m_pNode) {}
45
46  explicit PolicyIterator(NodeBase* X)
47    : Base(X) {}
48
49  virtual ~PolicyIterator() {}
50
51  bool isGroup() const
52  { return !Base::hasData(); }
53
54  Self& operator++() {
55    IteratorType::advance();
56    if (isGroup())
57      IteratorType::advance();
58    return *this;
59  }
60
61  Self operator++(int) {
62    Self tmp(*this);
63    IteratorType::advance();
64    if (isGroup())
65      IteratorType::advance();
66    return tmp;
67  }
68};
69
70/** \class InputTree
71 *  \brief InputTree is the input tree to contains all inputs from the
72 *  command line.
73 *
74 *  InputTree, of course, is uncopyable.
75 *
76 *  @see Input
77 */
78class InputTree : public BinaryTree<Input>
79{
80private:
81  typedef BinaryTree<Input> BinTreeTy;
82
83public:
84  enum Direction {
85    Inclusive  = TreeIteratorBase::Leftward,
86    Positional = TreeIteratorBase::Rightward
87  };
88
89  typedef BinaryTree<Input>::iterator       iterator;
90  typedef BinaryTree<Input>::const_iterator const_iterator;
91
92public:
93  /** \class Mover
94   *  \brief Mover provides the interface for moving iterator forward.
95   *
96   *  Mover is a function object (functor). @ref Mover::move moves
97   *  iterator forward in certain direction. @ref Mover::connect
98   *  connects two nodes of the given iterators togather.
99   */
100  struct Mover {
101    virtual ~Mover() {}
102    virtual void connect(TreeIteratorBase& pFrom, const TreeIteratorBase& pTo) const = 0;
103    virtual void move(TreeIteratorBase& pNode) const = 0;
104  };
105
106  /** \class Succeeder
107   *  \brief class Succeeder moves the iterator afterward.
108   */
109  struct Succeeder : public Mover {
110    virtual void connect(TreeIteratorBase& pFrom, const TreeIteratorBase& pTo) const {
111      proxy::hook<Positional>(pFrom.m_pNode, pTo.m_pNode);
112    }
113
114    virtual void move(TreeIteratorBase& pNode) const {
115      pNode.move<Positional>();
116    }
117  };
118
119  /** \class Includer
120   *  \brief class Includer moves the iterator downward.
121   */
122  struct Includer : public Mover {
123    virtual void connect(TreeIteratorBase& pFrom, const TreeIteratorBase& pTo) const {
124      proxy::hook<Inclusive>(pFrom.m_pNode, pTo.m_pNode);
125    }
126
127    virtual void move(TreeIteratorBase& pNode) const {
128      pNode.move<Inclusive>();
129    }
130  };
131
132public:
133  static Succeeder Afterward;
134  static Includer  Downward;
135
136public:
137
138  using BinTreeTy::merge;
139
140  InputTree(InputFactory& pInputFactory);
141  ~InputTree();
142
143  // -----  modify  ----- //
144  /// insert - create a leaf node and merge it in the tree.
145  //  This version of join determines the direction at run time.
146  //  @param pRoot  position the parent node
147  //  @param pMover the direction of the connecting edge of the parent node.
148  template<size_t DIRECT>
149  InputTree& insert(TreeIteratorBase pRoot,
150                    const std::string& pNamespec,
151                    const sys::fs::Path& pPath,
152                    unsigned int pType = Input::Unknown);
153
154  template<size_t DIRECT>
155  InputTree& enterGroup(TreeIteratorBase pRoot);
156
157  template<size_t DIRECT>
158  InputTree& insert(TreeIteratorBase pRoot,
159                    const Input& pInput);
160
161  InputTree& merge(TreeIteratorBase pRoot,
162                   const Mover& pMover,
163                   InputTree& pTree);
164
165  InputTree& insert(TreeIteratorBase pRoot,
166                    const Mover& pMover,
167                    const std::string& pNamespec,
168                    const sys::fs::Path& pPath,
169                    unsigned int pType = Input::Unknown);
170
171  InputTree& insert(TreeIteratorBase pRoot,
172                    const Mover& pMover,
173                    const Input& pInput);
174
175  InputTree& enterGroup(TreeIteratorBase pRoot,
176                        const Mover& pMover);
177
178  // -----  observers  ----- //
179  unsigned int numOfInputs() const
180  { return m_FileFactory.size(); }
181
182  bool hasInput() const
183  { return !m_FileFactory.empty(); }
184
185private:
186  InputFactory& m_FileFactory;
187
188};
189
190bool isGroup(const InputTree::iterator& pos);
191bool isGroup(const InputTree::const_iterator& pos);
192bool isGroup(const InputTree::dfs_iterator& pos);
193bool isGroup(const InputTree::const_dfs_iterator& pos);
194bool isGroup(const InputTree::bfs_iterator& pos);
195bool isGroup(const InputTree::const_bfs_iterator& pos);
196
197} // namespace of mcld
198
199//===----------------------------------------------------------------------===//
200// template member functions
201template<size_t DIRECT>
202mcld::InputTree&
203mcld::InputTree::insert(mcld::TreeIteratorBase pRoot,
204                        const std::string& pNamespec,
205                        const mcld::sys::fs::Path& pPath,
206                        unsigned int pType)
207{
208  BinTreeTy::node_type* node = createNode();
209  node->data = m_FileFactory.produce(pNamespec, pPath, pType);
210  if (pRoot.isRoot())
211    proxy::hook<TreeIteratorBase::Leftward>(pRoot.m_pNode,
212        const_cast<const node_type*>(node));
213  else
214    proxy::hook<DIRECT>(pRoot.m_pNode,
215        const_cast<const node_type*>(node));
216  return *this;
217}
218
219template<size_t DIRECT>
220mcld::InputTree&
221mcld::InputTree::enterGroup(mcld::TreeIteratorBase pRoot)
222{
223  BinTreeTy::node_type* node = createNode();
224  if (pRoot.isRoot())
225    proxy::hook<TreeIteratorBase::Leftward>(pRoot.m_pNode,
226        const_cast<const node_type*>(node));
227  else
228    proxy::hook<DIRECT>(pRoot.m_pNode,
229        const_cast<const node_type*>(node));
230  return *this;
231}
232
233template<size_t DIRECT>
234mcld::InputTree& mcld::InputTree::insert(mcld::TreeIteratorBase pRoot,
235	                                 const mcld::Input& pInput)
236{
237  BinTreeTy::node_type* node = createNode();
238  node->data = const_cast<mcld::Input*>(&pInput);
239  if (pRoot.isRoot())
240    proxy::hook<TreeIteratorBase::Leftward>(pRoot.m_pNode,
241                                         const_cast<const node_type*>(node));
242  else
243    proxy::hook<DIRECT>(pRoot.m_pNode,
244                        const_cast<const node_type*>(node));
245  return *this;
246}
247
248#endif
249
250