// This file is part of the Essence operating system. // It is released under the terms of the MIT license -- see LICENSE.md. // Written by: nakst. template struct LinkedList; template struct LinkedItem { void RemoveFromList(); LinkedItem *previousItem; LinkedItem *nextItem; // TODO Separate these out? struct LinkedList *list; T *thisItem; }; template struct LinkedList { void InsertStart(LinkedItem *item); void InsertEnd(LinkedItem *item); void InsertBefore(LinkedItem *newItem, LinkedItem *beforeItem); void Remove(LinkedItem *item); void Validate(int from); LinkedItem *firstItem; LinkedItem *lastItem; size_t count; #ifdef DEBUG_BUILD bool modCheck; #endif }; struct SimpleList { void Insert(SimpleList *link, bool start); void Remove(); union { SimpleList *previous, *last; }; union { SimpleList *next, *first; }; }; #ifndef SHARED_DEFINITIONS_ONLY template void LinkedItem::RemoveFromList() { if (!list) { EsPanic("LinkedItem::RemoveFromList - Item not in list.\n"); } list->Remove(this); } template void LinkedList::InsertStart(LinkedItem *item) { #ifdef DEBUG_BUILD if (modCheck) EsPanic("LinkedList::InsertStart - Concurrent modification\n"); modCheck = true; EsDefer({modCheck = false;}); #endif if (item->list == this) EsPanic("LinkedList::InsertStart - Inserting an item that is already in this list\n"); if (item->list) EsPanic("LinkedList::InsertStart - Inserting an item that is already in a list\n"); if (firstItem) { item->nextItem = firstItem; item->previousItem = nullptr; firstItem->previousItem = item; firstItem = item; } else { firstItem = lastItem = item; item->previousItem = item->nextItem = nullptr; } count++; item->list = this; Validate(0); } template void LinkedList::InsertEnd(LinkedItem *item) { #ifdef DEBUG_BUILD if (modCheck) EsPanic("LinkedList::InsertEnd - Concurrent modification\n"); modCheck = true; EsDefer({modCheck = false;}); #endif if (item->list == this) EsPanic("LinkedList::InsertEnd - Inserting a item that is already in this list\n"); if (item->list) EsPanic("LinkedList::InsertEnd - Inserting a item that is already in a list\n"); if (lastItem) { item->previousItem = lastItem; item->nextItem = nullptr; lastItem->nextItem = item; lastItem = item; } else { firstItem = lastItem = item; item->previousItem = item->nextItem = nullptr; } count++; item->list = this; Validate(1); } template void LinkedList::InsertBefore(LinkedItem *item, LinkedItem *before) { #ifdef DEBUG_BUILD if (modCheck) EsPanic("LinkedList::InsertBefore - Concurrent modification\n"); modCheck = true; EsDefer({modCheck = false;}); #endif if (item->list == this) EsPanic("LinkedList::InsertBefore - Inserting a item that is already in this list\n"); if (item->list) EsPanic("LinkedList::InsertBefore - Inserting a item that is already in a list\n"); if (before != firstItem) { item->previousItem = before->previousItem; item->previousItem->nextItem = item; } else { firstItem = item; item->previousItem = nullptr; } item->nextItem = before; before->previousItem = item; count++; item->list = this; Validate(3); } template void LinkedList::Remove(LinkedItem *item) { #ifdef DEBUG_BUILD if (modCheck) EsPanic("LinkedList::Remove - Concurrent modification\n"); modCheck = true; EsDefer({modCheck = false;}); #endif if (!item->list) EsPanic("LinkedList::Remove - Removing an item that has already been removed\n"); if (item->list != this) EsPanic("LinkedList::Remove - Removing an item from a different list (list = %x, this = %x)\n", item->list, this); if (item->previousItem) { item->previousItem->nextItem = item->nextItem; } else { firstItem = item->nextItem; } if (item->nextItem) { item->nextItem->previousItem = item->previousItem; } else { lastItem = item->previousItem; } item->previousItem = item->nextItem = nullptr; item->list = nullptr; count--; Validate(2); } template void LinkedList::Validate(int from) { #ifdef DEBUG_BUILD if (count == 0) { if (firstItem || lastItem) { EsPanic("LinkedList::Validate (%d) - Invalid list (1)\n", from); } } else if (count == 1) { if (firstItem != lastItem || firstItem->previousItem || firstItem->nextItem || firstItem->list != this || !firstItem->thisItem) { EsPanic("LinkedList::Validate (%d) - Invalid list (2)\n", from); } } else { if (firstItem == lastItem || firstItem->previousItem || lastItem->nextItem) { EsPanic("LinkedList::Validate (%d) - Invalid list (3) %x %x %x %x\n", from, firstItem, lastItem, firstItem->previousItem, lastItem->nextItem); } { LinkedItem *item = firstItem; size_t index = count; while (--index) { if (item->nextItem == item || item->list != this || !item->thisItem) { EsPanic("LinkedList::Validate (%d) - Invalid list (4)\n", from); } item = item->nextItem; } if (item != lastItem) { EsPanic("LinkedList::Validate (%d) - Invalid list (5)\n", from); } } { LinkedItem *item = lastItem; size_t index = count; while (--index) { if (item->previousItem == item) { EsPanic("LinkedList::Validate (%d) - Invalid list (6)\n", from); } item = item->previousItem; } if (item != firstItem) { EsPanic("LinkedList::Validate (%d) - Invalid list (7)\n", from); } } } #else (void) from; #endif } void SimpleList::Insert(SimpleList *item, bool start) { if (item->previous || item->next) { EsPanic("SimpleList::Insert - Bad links in %x.\n", this); } if (!first && !last) { item->previous = this; item->next = this; first = item; last = item; } else if (start) { item->previous = this; item->next = first; first->previous = item; first = item; } else { item->previous = last; item->next = this; last->next = item; last = item; } } void SimpleList::Remove() { if (previous->next != this || next->previous != this) { EsPanic("SimpleList::Remove - Bad links in %x.\n", this); } if (previous == next) { next->first = nullptr; next->last = nullptr; } else { previous->next = next; next->previous = previous; } previous = next = nullptr; } #endif