/* * File: list.h * Author: John R. Douceur * Date: 19 November 1997 * Copyright (c) 1997-1999 Microsoft Corporation */ #ifndef _INC_LIST #define _INC_LIST #include template class LinkedList; template class NodePool; template class ListNode { public: bool before_head() const {return previous_node == 0;} bool beyond_tail() const {return next_node == 0;} Class &value() {return node_value;} ListNode *next() const {return next_node;} ListNode *previous() const {return previous_node;} ListNode *insert_before(); ListNode *insert_after(); ListNode *insert_before(Class object); ListNode *insert_after(Class object); ListNode *insert_before(ListNode *node); ListNode *insert_after(ListNode *node); ListNode *insert_before(LinkedList *list); ListNode *insert_after(LinkedList *list); void remove(); ListNode *remove_forward(); ListNode *remove_backward(); friend class LinkedList; friend class NodePool; ~ListNode() {} private: ListNode() {} Class node_value; ListNode *next_node; ListNode *previous_node; }; template class LinkedList { public: LinkedList(); ~LinkedList(); ListNode *head() const {return list_head.next_node;} ListNode *tail() const {return list_tail.previous_node;} bool is_empty() const {return list_head.next_node->next_node == 0;} void flush(); friend class ListNode; friend class NodePool; private: ListNode list_head; ListNode list_tail; }; template struct NodeGroup { NodeGroup *next_group; ListNode nodes[1]; }; template class NodePool { public: friend class ListNode; friend class LinkedList; static void initialize(void); static void uninitialize(void); private: static ListNode *allocate(); static void deallocate(ListNode *node); static void deallocate(LinkedList *list); static CRITICAL_SECTION critical_section; static int group_size; static const int max_group_size; static NodeGroup *group_list; static ListNode *node_list; }; template const int NodePool::max_group_size = 1024; template ListNode * ListNode::insert_before() { ListNode *node = NodePool::allocate(); if (node == 0) { return 0; } node->previous_node = previous_node; node->next_node = this; previous_node->next_node = node; previous_node = node; return node; } template ListNode * ListNode::insert_after() { ListNode *node = NodePool::allocate(); if (node == 0) { return 0; } node->next_node = next_node; node->previous_node = this; next_node->previous_node = node; next_node = node; return node; } template ListNode * ListNode::insert_before( Class object) { ListNode *node = NodePool::allocate(); if (node == 0) { return 0; } node->previous_node = previous_node; node->next_node = this; node->node_value = object; previous_node->next_node = node; previous_node = node; return node; } template ListNode * ListNode::insert_after( Class object) { ListNode *node = NodePool::allocate(); if (node == 0) { return 0; } node->next_node = next_node; node->previous_node = this; node->node_value = object; next_node->previous_node = node; next_node = node; return node; } template ListNode * ListNode::insert_before( ListNode *node) { node->previous_node->next_node = node->next_node; node->next_node->previous_node = node->previous_node; node->previous_node = previous_node; node->next_node = this; previous_node->next_node = node; previous_node = node; return node; } template ListNode * ListNode::insert_after( ListNode *node) { node->previous_node->next_node = node->next_node; node->next_node->previous_node = node->previous_node; node->next_node = next_node; node->previous_node = this; next_node->previous_node = node; next_node = node; return node; } template ListNode * ListNode::insert_before( LinkedList *list) { if (!list->is_empty()) { ListNode *old_head = list->list_head.next_node; previous_node->next_node = old_head; old_head->previous_node = previous_node; previous_node = list->list_tail.previous_node; previous_node->next_node = this; list->list_head.next_node = &list->list_tail; list->list_tail.previous_node = &list->list_head; return old_head; } else { return this; } } template ListNode * ListNode::insert_after( LinkedList *list) { if (!list->is_empty()) { ListNode *old_tail = list->list_tail.previous_node; next_node->previous_node = old_tail; old_tail->next_node = next_node; next_node = list->list_head.next_node; next_node->previous_node = this; list->list_tail.previous_node = &list->list_head; list->list_head.next_node = &list->list_tail; return old_tail; } else { return this; } } template void ListNode::remove() { previous_node->next_node = next_node; next_node->previous_node = previous_node; NodePool::deallocate(this); } template ListNode * ListNode::remove_forward() { ListNode *node = next_node; previous_node->next_node = next_node; next_node->previous_node = previous_node; NodePool::deallocate(this); return node; } template ListNode * ListNode::remove_backward() { ListNode *node = previous_node; previous_node->next_node = next_node; next_node->previous_node = previous_node; NodePool::deallocate(this); return node; } template LinkedList::LinkedList() { list_head.next_node = &list_tail; list_head.previous_node = 0; list_tail.next_node = 0; list_tail.previous_node = &list_head; } template LinkedList::~LinkedList() { NodePool::deallocate(this); } template void LinkedList::flush() { NodePool::deallocate(this); } template int NodePool::group_size = 1; template NodeGroup * NodePool::group_list = 0; template ListNode * NodePool::node_list = 0; template CRITICAL_SECTION NodePool::critical_section = {0}; template void NodePool::initialize() { InitializeCriticalSection(&critical_section); } template void NodePool::uninitialize() { DeleteCriticalSection(&critical_section); } template ListNode * NodePool::allocate() { EnterCriticalSection(&critical_section); if (node_list == 0) { NodeGroup *node_group = (NodeGroup *)malloc(sizeof(NodeGroup) + (group_size - 1) * sizeof(ListNode)); while (node_group == 0 && group_size > 1) { group_size /= 2; node_group = (NodeGroup *)malloc(sizeof(NodeGroup) + (group_size - 1) * sizeof(ListNode)); } if (node_group == 0) { LeaveCriticalSection(&critical_section); return 0; } node_group->next_group = group_list; group_list = node_group; for (int index = 0; index < group_size; index++) { node_group->nodes[index].next_node = node_list; node_list = &node_group->nodes[index]; } group_size *= 2; if (group_size > max_group_size) { group_size = max_group_size; } } ListNode *node = node_list; node_list = node->next_node; LeaveCriticalSection(&critical_section); return node; } template void NodePool::deallocate( ListNode *node) { EnterCriticalSection(&critical_section); node->next_node = node_list; node_list = node; LeaveCriticalSection(&critical_section); } template void NodePool::deallocate( LinkedList *list) { EnterCriticalSection(&critical_section); if (!list->is_empty()) { list->list_tail.previous_node->next_node = node_list; node_list = list->list_head.next_node; list->list_tail.previous_node = &list->list_head; list->list_head.next_node = &list->list_tail; } LeaveCriticalSection(&critical_section); } #endif /* _INC_LIST */