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