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