diff --git a/xtoskrnl/CMakeLists.txt b/xtoskrnl/CMakeLists.txt index 66dad3b..1080ff6 100644 --- a/xtoskrnl/CMakeLists.txt +++ b/xtoskrnl/CMakeLists.txt @@ -72,6 +72,7 @@ list(APPEND XTOSKRNL_SOURCE ${XTOSKRNL_SOURCE_DIR}/rtl/math.cc ${XTOSKRNL_SOURCE_DIR}/rtl/memory.cc ${XTOSKRNL_SOURCE_DIR}/rtl/sha1.cc + ${XTOSKRNL_SOURCE_DIR}/rtl/slist.cc ${XTOSKRNL_SOURCE_DIR}/rtl/string.cc ${XTOSKRNL_SOURCE_DIR}/rtl/widestr.cc) diff --git a/xtoskrnl/includes/rtl.hh b/xtoskrnl/includes/rtl.hh index a667024..8b28b89 100644 --- a/xtoskrnl/includes/rtl.hh +++ b/xtoskrnl/includes/rtl.hh @@ -20,6 +20,7 @@ #include #include #include +#include #include #include diff --git a/xtoskrnl/includes/rtl/slist.hh b/xtoskrnl/includes/rtl/slist.hh new file mode 100644 index 0000000..1ac5cbd --- /dev/null +++ b/xtoskrnl/includes/rtl/slist.hh @@ -0,0 +1,38 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/includes/rtl/slist.hh + * DESCRIPTION: Singly linked list manipulation routines + * DEVELOPERS: Rafal Kupiec + */ + +#ifndef __XTOSKRNL_RTL_SLIST_HH +#define __XTOSKRNL_RTL_SLIST_HH + +#include + + +/* Runtime Library */ +namespace RTL +{ + class SinglyList + { + public: + STATIC XTCDECL PSINGLE_LIST_ENTRY GetFirstEntry(IN PSINGLE_LIST_HEADER ListHead); + STATIC XTCDECL VOID InitializeListHead(IN PSINGLE_LIST_HEADER ListHead); + STATIC XTCDECL VOID InsertHeadList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN PSINGLE_LIST_ENTRY Entry); + STATIC XTCDECL VOID InsertTailList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN PSINGLE_LIST_ENTRY Entry); + STATIC XTCDECL BOOLEAN ListEmpty(IN PSINGLE_LIST_HEADER ListHead); + STATIC XTAPI USHORT QueryListDepth(IN PSINGLE_LIST_HEADER ListHead); + STATIC XTCDECL VOID RemoveEntryList(IN PSINGLE_LIST_HEADER ListHead, + IN PSINGLE_LIST_ENTRY Entry); + STATIC XTCDECL VOID SpliceHeadList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN OUT PSINGLE_LIST_HEADER SpliceList); + STATIC XTCDECL VOID SpliceTailList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN OUT PSINGLE_LIST_HEADER SpliceList); + }; +} + +#endif /* __XTOSKRNL_RTL_SLIST_HH */ diff --git a/xtoskrnl/rtl/slist.cc b/xtoskrnl/rtl/slist.cc new file mode 100644 index 0000000..1cedebe --- /dev/null +++ b/xtoskrnl/rtl/slist.cc @@ -0,0 +1,327 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtoskrnl/rtl/slist.cc + * DESCRIPTION: Singly linked list manipulation routines + * DEVELOPERS: Rafal Kupiec + */ + +#include + + +/** + * Retrieves the first entry from a singly linked list without removing it from the list. + * + * @param ListHead + * Supplies a pointer to a structure that serves as the list header. + * + * @return This routine returns a pointer to the first entry in the list, or NULLPTR if the list is empty. + * + * @since XT 1.0 + */ +XTCDECL +PSINGLE_LIST_ENTRY +RTL::SinglyList::GetFirstEntry(IN PSINGLE_LIST_HEADER ListHead) +{ + /* Check if the list is empty */ + if(ListEmpty(ListHead)) + { + /* Empty list, return NULLPTR */ + return NULLPTR; + } + + /* Return first entry in the list */ + return ListHead->Next.Next; +} + +/** + * Initializes a structure representing the head of a singly linked list. + * + * @param ListHead + * Supplies a pointer to a structure that serves as the list header. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +RTL::SinglyList::InitializeListHead(IN PSINGLE_LIST_HEADER ListHead) +{ + /* Initialize the list head */ + ListHead->Alignment = 0; +} + +/** + * Inserts an entry at the head of a singly linked list. + * + * @param ListHead + * Supplies a pointer to the head of the list. + * + * @param Entry + * Supplies a pointer to the entry that will be inserted in the list. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +RTL::SinglyList::InsertHeadList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN PSINGLE_LIST_ENTRY Entry) +{ + /* Insert entry at the head of the list and increment depth */ + Entry->Next = ListHead->Next.Next; + ListHead->Next.Next = Entry; + ListHead->Depth++; +} + +/** + * Inserts an entry at the tail of a singly linked list. + * + * @param ListHead + * Supplies a pointer to the head of the list. + * + * @param Entry + * Supplies a pointer to the entry that will be inserted in the list. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +RTL::SinglyList::InsertTailList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN PSINGLE_LIST_ENTRY Entry) +{ + PSINGLE_LIST_ENTRY CurrentEntry; + + /* Set Next pointer of the new entry to NULLPTR */ + Entry->Next = NULLPTR; + + /* Check if the list is empty */ + if(ListEmpty(ListHead)) + { + /* Insert entry at the head */ + ListHead->Next.Next = Entry; + } + else + { + /* Traverse the list to find the last entry */ + CurrentEntry = ListHead->Next.Next; + while(CurrentEntry->Next != NULLPTR) + { + /* Move to the next entry */ + CurrentEntry = CurrentEntry->Next; + } + + /* Insert entry at the tail */ + CurrentEntry->Next = Entry; + } + + /* Increment list depth */ + ListHead->Depth++; +} + +/** + * Indicates whether a singly linked list structure is empty, or not initialized at all. + * + * @param ListHead + * Supplies a pointer to a structure that represents the head of the list. + * + * @return This routine returns TRUE if there are currently no entries in the list or FALSE otherwise. + * + * @since XT 1.0 + */ +XTCDECL +BOOLEAN +RTL::SinglyList::ListEmpty(IN PSINGLE_LIST_HEADER ListHead) +{ + /* Check if the list is empty */ + return (ListHead == NULLPTR || ListHead->Next.Next == NULLPTR); +} + +/** + * Queries the current depth (number of entries) of a singly linked list. + * + * @param ListHead + * Supplies a pointer to a structure that represents the head of the singly linked list. + * + * @return This routine returns the number of entries currently in the list, or zero if the list head is NULLPTR. + * + * @since XT 1.0 + */ +XTAPI +USHORT +RTL::SinglyList::QueryListDepth(IN PSINGLE_LIST_HEADER ListHead) +{ + /* Check if the list head is initialized and valid */ + if(ListHead == NULLPTR) + { + /* Return zero */ + return 0; + } + + /* Return the list depth */ + return ListHead->Depth; +} + +/** + * Removes an entry from a singly linked list. + * + * @param ListHead + * Supplies a pointer to the head of the list. + * + * @param Entry + * Supplies a pointer to the entry that will be removed from the list. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +RTL::SinglyList::RemoveEntryList(IN PSINGLE_LIST_HEADER ListHead, + IN PSINGLE_LIST_ENTRY Entry) +{ + PSINGLE_LIST_ENTRY PreviousEntry; + + /* Check if the list is empty */ + if(ListEmpty(ListHead)) + { + /* List is empty, nothing to remove */ + return; + } + + /* Check if the entry is the first one */ + if(ListHead->Next.Next == Entry) + { + /* Remove the first entry and decrement depth */ + ListHead->Next.Next = Entry->Next; + ListHead->Depth--; + + /* Nothing else to do */ + return; + } + + /* Find the previous entry */ + PreviousEntry = ListHead->Next.Next; + while(PreviousEntry->Next != Entry) + { + /* Move to the next entry */ + PreviousEntry = PreviousEntry->Next; + + /* Check if we reached the end of the list */ + if(PreviousEntry == NULLPTR) + { + /* Entry not found */ + return; + } + } + + /* Remove the entry and decrement depth */ + PreviousEntry->Next = Entry->Next; + ListHead->Depth--; +} + +/** + * Splices a singly linked list at the head of another list. The source list is reinitialized to empty. + * + * @param ListHead + * Supplies a pointer to a structure that represents the head of the list. + * + * @param SpliceList + * Supplies a pointer to a structure that represents the head of the list that will be spliced. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +RTL::SinglyList::SpliceHeadList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN OUT PSINGLE_LIST_HEADER SpliceList) +{ + PSINGLE_LIST_ENTRY LastEntry; + + /* Check if the list to splice is empty */ + if(ListEmpty(SpliceList)) + { + /* Nothing to splice, return */ + return; + } + + /* Find the last entry of the list to splice */ + LastEntry = SpliceList->Next.Next; + while(LastEntry->Next != NULLPTR) + { + /* Move to the next entry */ + LastEntry = LastEntry->Next; + } + + /* Splice the list at the head of destination */ + LastEntry->Next = ListHead->Next.Next; + ListHead->Next.Next = SpliceList->Next.Next; + + /* Update depth of the destination list */ + ListHead->Depth += SpliceList->Depth; + + /* Reinitialize the source list to empty */ + SpliceList->Next.Next = NULLPTR; + SpliceList->Depth = 0; +} + +/** + * Splices a singly linked list at the tail of another list. The source list is reinitialized to empty. + * + * @param ListHead + * Supplies a pointer to the head of the destination list. + * + * @param SpliceList + * Supplies a pointer to the head of the list that will be spliced. + * + * @return This routine does not return any value. + * + * @since XT 1.0 + */ +XTCDECL +VOID +RTL::SinglyList::SpliceTailList(IN OUT PSINGLE_LIST_HEADER ListHead, + IN OUT PSINGLE_LIST_HEADER SpliceList) +{ + PSINGLE_LIST_ENTRY LastEntry; + + /* Check if the list to splice is empty */ + if(ListEmpty(SpliceList)) + { + /* Nothing to splice, return */ + return; + } + + /* Check if the destination list is empty */ + if(ListHead->Next.Next == NULLPTR) + { + /* Simply move the splice list to the destination head */ + ListHead->Next.Next = SpliceList->Next.Next; + } + else + { + /* Find the last entry of the destination list */ + LastEntry = ListHead->Next.Next; + while(LastEntry->Next != NULLPTR) + { + /* Move to the next entry */ + LastEntry = LastEntry->Next; + } + + /* Splice the list at the tail of destination */ + LastEntry->Next = SpliceList->Next.Next; + } + + /* Update depth of the destination list */ + ListHead->Depth += SpliceList->Depth; + + /* Reinitialize the source list to empty */ + SpliceList->Next.Next = NULLPTR; + SpliceList->Depth = 0; +}