/* * Copyright (C) 2004-2005 Vadim Berezniker * http://www.kryptolus.com * * This Program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This Program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Make; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * http://www.gnu.org/copyleft/gpl.html * */ #include "stdafx.h" #include "kryList.h" #include "kryListIterator.h" /* * This is a generic doubly-linked list implementation. * Because of the way the data is handled, only pointer types can be stored within the list. */ /* * Creates an empty list. */ template kryList::kryList() : m_head(NULL), m_tail(NULL), m_length(0), m_id(0), m_iterators(NULL) { } /* * Prints a warning if used. * There are currently no reason for this function to be used within sabbu. * (Only time this constructor is invoked is because of a bug in the program) */ template kryList::kryList(kryList & list) { g_warning("Attempt to assign kryLists. Shouldn't happen."); } /* * Destroys the list. */ template kryList::~kryList() { for(GList *ptr = this->m_iterators; ptr; ptr = ptr->next) { kryListIterator *iter = (kryListIterator *) ptr->data; iter->DisconnectFromList(); } this->Clear(); } /* * Assigns another list to this list. * Makes a shallow copy of the given list. */ template void kryList::operator =(kryList &list) { this->Clear(); kryListIterator iter; list.GetIterator(&iter); while(T data = iter.GetNext()) this->Append(data); } /* * Add an item to the end of the list. */ template kryListNode * kryList::Append(T data) { struct kryListNode *node = new kryListNode(); node->data = data; for(GList *ptr = this->m_iterators; ptr; ptr = ptr->next) { kryListIterator *iter = (kryListIterator *) ptr->data; iter->NotifyBeforeAdd(NULL); } if(this->m_head == NULL) { this->m_head = node; this->m_tail = node; node->next = NULL; node->prev = NULL; } else { this->m_tail->next = node; node->prev = this->m_tail; node->next = NULL; this->m_tail = node; } this->m_length++; this->m_id++; return node; } /* * Returns the number of items in the list. */ template int kryList::GetLength() { return this->m_length; } template int kryList::GetCount() { return this->m_length; } /* * Returns the item at the nth position in the list. */ template T kryList::GetNthData(int index) { if(index < 0) { g_warning("List index out of range (less than 0)"); return 0; } kryListIterator ptr; this->GetNthIterator(&ptr, index); return ptr.GetNext(); } /* * Calls a function on every item in the list. */ template void kryList::ForEach(GFunc func, void *userdata) { struct kryListNode *node; if(this->m_head == NULL) return; if(func == NULL) { g_warning("Null function passed to list ForEach."); return; } for(node = this->m_head; node; node = node->next) func((void *) node->data, userdata); } template void kryList::PrintDebug() { struct kryListNode *node; g_warning("PRINT LIST"); for(node = this->m_head; node; node = node->next) g_warning("node: %p data: %p next: %p prev: %p", node, (void *) node->data, node->next, node->prev); g_warning("END"); } /* * Inserts the given item at a specific position in the list. * */ template void kryList::Insert(T data, int position) { int cur_idx = 0; if(position < 0 || position > this->m_length) { g_warning("Insert index out of range. Must be between 0 and %d", this->m_length); return; } kryListIterator iter; GetIterator(&iter); this->RemoveIterator(&iter); while(iter.GetNext()) { if(cur_idx == position) { for(GList *ptr = this->m_iterators; ptr; ptr = ptr->next) { kryListIterator *iter_v = (kryListIterator *) ptr->data; g_warning("notify %p and iter is %p", iter_v, &iter); iter_v->NotifyBeforeAdd(iter.GetNode()); } iter.InsertBefore(data); return; } cur_idx++; } this->Append(data); this->m_id++; } /* * Returns the index of the given data within the list. * * If a function is specified, calls that function to check for data equality. * * Returns -1 if the data is not found. */ template int kryList::IndexOf(T data, GEqualFunc func) { int index = -1; this->Find(data, func, &index); return index; } /* * Deletes the given node from the list. */ template void kryList::Remove(kryListNode *node) { if(node == NULL) { g_warning("Attempt to remove empty node from list."); return; } for(GList *ptr = this->m_iterators; ptr; ptr = ptr->next) { kryListIterator *iter = (kryListIterator *) ptr->data; iter->NotifyBeforeRemove(node); } if(node->prev) node->prev->next = node->next; else this->m_head = node->next; if(node->next) node->next->prev = node->prev; else this->m_tail = node->prev; this->m_length--; delete node; this->m_id++; } /* * Searches the list for the given data and returns the node and index if found. * If cmpFunc is specified, it is used to determine if the given data is equal to the data in the list. * data: The data to look for * cmpFunc; Function to use for comparing data. * index: Location to store index if found. If NULL, found index is not stored. */ template kryListNode *kryList::Find(T data, GEqualFunc cmpFunc, int *index) { int counter = 0; struct kryListNode *node = NULL; for(node = this->m_head; node; node = node->next) { if(cmpFunc == NULL && data == node->data || cmpFunc && cmpFunc((gconstpointer) data, (gconstpointer) node->data)) break; counter++; } if(index && node) *index = counter; return node; } /* * Searches the list for the given data and removes it if it is found in the list. * If cmpFunc is specified, it is used to determine if the given data is equal to the data in the list. */ template void kryList::Remove(T data, GEqualFunc cmpFunc) { this->Remove(this->Find(data, cmpFunc, NULL)); } /* * Removes all data from the list. */ template void kryList::Clear() { struct kryListNode *ptr_node, *next; for(GList *ptr = this->m_iterators; ptr; ptr = ptr->next) { kryListIterator *iter = (kryListIterator *) ptr->data; iter->Invalidate(); } if(this->m_head == NULL) return; for(ptr_node = this->m_head, next = ptr_node->next; ptr_node; ptr_node = next, next = (ptr_node ? ptr_node->next : NULL)) delete ptr_node; this->m_head = NULL; this->m_tail = NULL; this->m_length = 0; this->m_id++; } /* * Initializes the given Iterator to the first piece of data in this list. */ template void kryList::GetIterator(kryListIterator *iter) { if(!iter) { g_warning("NULL iterator passed to GetIterator."); return; } this->AddIterator(iter); iter->SetList(this); } /* * Initializes the given Iterator to the nth item in this list. */ template void kryList::GetNthIterator(kryListIterator *iter, int index) { int idx = 0; if(index < 0 || index >= this->m_length) { g_warning("Attempting to get Iterator beyond the range of the list. "); return; } this->GetIterator(iter); while(idx < index) { iter->GetNext(); idx++; } } template T kryList::operator [] (int index) { kryListIterator iter; this->GetNthIterator(&iter, index); return iter.GetNext(); } /* * Adds an iterator to the list of iterators currently using this list. */ template void kryList::AddIterator(kryListIterator *iter) { this->m_iterators = g_list_append(this->m_iterators, iter); } /* * Removes an iterator from the list of iterators currently using this list. */ template void kryList::RemoveIterator(kryListIterator *iter) { this->m_iterators = g_list_remove(this->m_iterators, iter); } template class kryList; template class kryList; template class kryList; template class kryList; template class kryList; template class kryList; //template class kryList; #include "krySignal.h" template class kryList; template class kryList; template class kryList; template class kryList; template class kryList; template class kryList; template class kryList; template class kryList; template class kryList *>; template class kryList *>;