1//===- TreeAllocator.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_ADT_TREEALLOCATOR_H
10#define MCLD_ADT_TREEALLOCATOR_H
11#include <set>
12#include <mcld/Support/GCFactory.h>
13
14namespace mcld {
15
16/** \class NodeFactory
17 *  \brief NodeFactory manages the creation and destruction of mcld::Node.
18 *
19 *  NodeFactory guarantees all allocated memory are released finally. When
20 *  the destructor of NodeFactory is called, all allocated memory are freed.
21 *
22 *  NodeFactory provides delegation of memory. Sometimes, we have to merge two
23 *  NodeFactories, and NodeFactory::delegate() can move the memory from one
24 *  NodeFactories to another.
25 *
26 *  @see LinearAllocator
27 */
28template<typename DataType>
29class NodeFactory : public GCFactory<Node<DataType>, 64>
30{
31private:
32  typedef GCFactory<Node<DataType>, 64> Alloc;
33
34public:
35  typedef Node<DataType>                 NodeType;
36  typedef typename Alloc::iterator       iterator;
37  typedef typename Alloc::const_iterator const_iterator;
38
39public:
40  /// produce - produce a node, add it under control
41  NodeType* produce() {
42    NodeType* result = Alloc::allocate();
43    Alloc::construct(result);
44    return result;
45  }
46
47  /// delegate - get the control of chunks owned by the client
48  //  after calling delegate(), client will renouce its control
49  //  of memory space.
50  void delegate(NodeFactory& pClient) {
51    if (this == &pClient)
52      return;
53
54    if (pClient.empty())
55      return;
56
57    if (Alloc::empty()) {
58      replace(pClient);
59      pClient.renounce();
60      return;
61    }
62
63    // neither me nor client is empty
64    concatenate(pClient);
65    pClient.renounce();
66  }
67
68private:
69  /// renounce - give up the control of all chunks
70  void renounce()
71  { Alloc::reset(); }
72
73  /// replace - be the agent of client.
74  void replace(NodeFactory& pClient) {
75    Alloc::m_pRoot = pClient.Alloc::m_pRoot;
76    Alloc::m_pCurrent = pClient.Alloc::m_pCurrent;
77    Alloc::m_AllocatedNum = pClient.Alloc::m_AllocatedNum;
78    Alloc::m_NumAllocData = pClient.Alloc::m_NumAllocData;
79  }
80
81  /// concatenate - conncet two factories
82  void concatenate(NodeFactory& pClient) {
83    Alloc::m_pCurrent->next = pClient.Alloc::m_pRoot;
84    Alloc::m_pCurrent = pClient.Alloc::m_pCurrent;
85    Alloc::m_AllocatedNum += pClient.Alloc::m_AllocatedNum;
86    Alloc::m_NumAllocData += pClient.Alloc::m_NumAllocData;
87  }
88};
89
90} // namespace of mcld
91
92#endif
93
94