#ifndef __RECYCLE_STACK_H__ #define __RECYCLE_STACK_H__ #if _MSC_VER >= 1000 #pragma once #endif // _MSC_VER >= 1000 /* Yet another conversation with friends that turned into a coding exercise Knowing that allocs/reallocs are expensive, we need a high performance stack structure for ints that is extreemly memory efficient The first draft solution was a collection of some straight C functions and a transparent stack struct that over realloced in 16 node blocks This is a little bit different, 1) we make two simple singly linked lists, one is the active stack and the other is the recycle stack 2) every time we "pop" from the active stack, we move the node object onto the recycle stack 3) when adding a node to the active stack, we check if we can take one from the recycle stack before allocating more memory 4) It's templatized so we're no longer limited to ints -Jason De Arte, September 20, 2005 */ // For my own debugging static long sSingleLinkListStackAllocCount = 0; template class CSingleLinkListStack { public: struct Node { Node * next; T data; }; protected: Node * m_root; // starting point for the linked list int m_depth; // keep track of how many elements there are static long s_allocs; // Shared copy function void Copy(const CSingleLinkListStack & aCopy) { ATLASSERT(!"NOT FULLY IMPLEMENTED NOR TESTED - This code Should be unreachable. Why are you using it? -Jason"); return; // When copying a list over we will need to clear out our existing // list, but let's be smart about it // if both lists are the same length // straight copy of Node.data from one to the other // if our list is shorter than their list // copy over the nodes that we can & then create new nodes // if our list is longer than their list // copy over the Node.data and delete the rest // TODO: Implement the above logic } void init() { m_root = NULL; m_depth = 0; } static Node * createNode(const T & data) { Node * node = new Node; node->next = NULL; node->data = data; sSingleLinkListStackAllocCount++; return node; } static void destroyNode(Node * node) { if(node) sSingleLinkListStackAllocCount--; delete node; } public: CSingleLinkListStack() { init(); } protected: CSingleLinkListStack( const CSingleLinkListStack & aCopy ) { ATLASSERT(!"NOT FULLY IMPLEMENTED NOR TESTED - This code Should be unreachable. Why are you using it? -Jason"); init(); Copy(aCopy); } protected: CSingleLinkListStack operator=(const CSingleLinkListStack& aCopy) { ATLASSERT(!"NOT FULLY IMPLEMENTED NOR TESTED - This code Should be unreachable. Why are you using it? -Jason"); Copy(aCopy); return this; } public: ~CSingleLinkListStack() { DeleteStack(); } void DeleteStack() { while( m_root ) { destroyNode( PopNode() ); } } // Place a pre-allocated node on the stack void PushNode(Node * node) { if(!node) { ATLASSERT(!"PushNode, can't push a null node on the stack"); return; } // set node as the new root if( !m_root ) { m_root = node; m_root->next = NULL; } else { node->next = m_root; m_root = node; } m_depth++; } // Push data on the stack void PushData(const T & data) { PushNode(createNode(data)); } // Non-distructivly pop a node off the stack Node * PopNode() { if( !m_root ) return NULL; Node * node = m_root; m_root = m_root->next; node->next = NULL; m_depth--; return node; } // Pop data off the stack, node* will be deleted bool PopData(T * data) { Node * node = PopNode(); if(!node) return false; if(data) data = node->data; destroyNode(node); return true; } // just in case you were wondering how many elements were in the stack int count() { return m_depth; } }; template class CRecycleStack { protected: CSingleLinkListStack m_workingStack; CSingleLinkListStack m_recycleStack; typedef CSingleLinkListStack::Node* NodePtr; CRecycleStack( const CRecycleStack & aCopy ) { ATLASSERT(!"NOT FULLY IMPLEMENTED NOR TESTED - This code Should be unreachable. Why are you using it? -Jason"); } CRecycleStack operator=(const CRecycleStack& aCopy) { ATLASSERT(!"NOT FULLY IMPLEMENTED NOR TESTED - This code Should be unreachable. Why are you using it? -Jason"); } public: CRecycleStack(int preAlloc = 0) { growFreeSpace(preAlloc); } ~CRecycleStack() {} void Push(const T & data) { // // Try to take a node from the recycle list and repurpose it in the // working stack before creating a new element // NodePtr node = m_recycleStack.PopNode(); if(!node) { m_workingStack.PushData(data); } else { node->data = data; m_workingStack.PushNode(node); } } bool Pop(T & data) { // // Instead of just getting the data, get the node and move it to the // recycler so we may use it again // NodePtr node = m_workingStack.PopNode(); if( !node ) return false; data = node->data; node->data = NULL; m_recycleStack.PushNode(node); return true; } // Sort of a Pre-Alloc void growFreeSpace(unsigned int nodes) { for( unsigned int idx = 0; idx < nodes; idx++ ) { m_recycleStack.PushData(0); } } // Keep that free space in check void compactFreeSpace(unsigned int minimumFreeNodes = 0) { while( m_recycleStack.count() > minimumFreeNodes ) { m_recycleStack.PopNode(NULL); } } // Number of elements in the working stack int count() { return m_workingStack.count(); } // Number of elements in the recycle stack int recycleCount() { return m_recycleStack.count(); } }; #endif //__RECYCLE_STACK_H__