summaryrefslogtreecommitdiff
path: root/include/mcld/ADT/TreeAllocator.h
blob: fc95bf7fb267ae27e1d5c5048d17f973fee5ff7e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
//===- TreeAllocator.h ----------------------------------------------------===//
//
//                     The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef MCLD_TREE_ALLOCATOR_H
#define MCLD_TREE_ALLOCATOR_H
#ifdef ENABLE_UNITTEST
#include <gtest.h>
#endif
#include <set>
#include "mcld/Support/GCFactory.h"
#include "mcld/ADT/TreeBase.h"

namespace mcld
{

/** \class NodeFactory
 *  \brief NodeFactory manages the creation and destruction of mcld::Node.
 *
 *  NodeFactory guarantees all allocated memory are released finally. When
 *  the destructor of NodeFactory is called, all allocated memory are freed.
 *
 *  NodeFactory provides delegation of memory. Sometimes, we have to merge two
 *  NodeFactories, and NodeFactory::delegate() can move the memory from one
 *  NodeFactories to another.
 *
 *  @see LinearAllocator
 */
template<typename DataType>
class NodeFactory : public GCFactory<Node<DataType>, 64>
{
private:
  typedef GCFactory<Node<DataType>, 64> Alloc;

public:
  typedef Node<DataType>                 NodeType;
  typedef typename Alloc::iterator       iterator;
  typedef typename Alloc::const_iterator const_iterator;

public:
  /// produce - produce a node, add it under control
  NodeType* produce() {
    NodeType* result = Alloc::allocate();
    Alloc::construct(result);
    return result;
  }

  /// delegate - get the control of chunks owned by the client
  //  after calling delegate(), client will renouce its control
  //  of memory space.
  void delegate(NodeFactory& pClient) {
    if (this == &pClient)
      return;

    if (pClient.empty())
      return;

    if (Alloc::empty()) {
      replace(pClient);
      pClient.renounce();
      return;
    }

    // neither me nor client is empty
    concatenate(pClient);
    pClient.renounce();
  }

private:
  /// renounce - give up the control of all chunks
  void renounce()
  { Alloc::reset(); }

  /// replace - be the agent of client.
  void replace(NodeFactory& pClient) {
    Alloc::m_pRoot = pClient.Alloc::m_pRoot;
    Alloc::m_pCurrent = pClient.Alloc::m_pCurrent;
    Alloc::m_AllocatedNum = pClient.Alloc::m_AllocatedNum;
    Alloc::m_NumAllocData = pClient.Alloc::m_NumAllocData;
  }

  /// concatenate - conncet two factories
  void concatenate(NodeFactory& pClient) {
    Alloc::m_pCurrent->next = pClient.Alloc::m_pRoot;
    Alloc::m_pCurrent = pClient.Alloc::m_pCurrent;
    Alloc::m_AllocatedNum += pClient.Alloc::m_AllocatedNum;
    Alloc::m_NumAllocData += pClient.Alloc::m_NumAllocData;
  }
};

} // namespace of mcld

#endif