| //===- 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 |
| |