diff --git a/libmaxsi/Makefile b/libmaxsi/Makefile index df6f59d5..143ea4cc 100644 --- a/libmaxsi/Makefile +++ b/libmaxsi/Makefile @@ -67,6 +67,7 @@ process.h \ types.h \ format.h \ keyboard.h \ +sortedlist.h \ sortix-vga.h \ sortix-keyboard.h \ sortix-sound.h \ diff --git a/libmaxsi/hsrc/sortedlist.h b/libmaxsi/hsrc/sortedlist.h new file mode 100644 index 00000000..68191f53 --- /dev/null +++ b/libmaxsi/hsrc/sortedlist.h @@ -0,0 +1,318 @@ +/****************************************************************************** + + COPYRIGHT(C) JONAS 'SORTIE' TERMANSEN 2011. + + This file is part of LibMaxsi. + + LibMaxsi is free software: you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the Free + Software Foundation, either version 3 of the License, or (at your option) + any later version. + + LibMaxsi 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 Lesser General Public License for + more details. + + You should have received a copy of the GNU Lesser General Public License + along with LibMaxsi. If not, see . + + sortedlist.h + A container that ensures its elements are always sorted when they are + accessed. It also provides binary search. + +******************************************************************************/ + +#ifndef LIBMAXSI_SORTEDLIST_H +#define LIBMAXSI_SORTEDLIST_H + +#ifndef SIZE_MAX +#error Define __STDC_LIMIT_MACROS before including +#endif + +namespace Maxsi +{ + template class SortedList + { + public: + // GCC appears to be broken as the const in the function pointer typedef + // below is ignored for some reason. Is it a compiler bug? + typedef int (*compare_t)(const T, const T); + + private: + static const int FLAG_SORTED = (1<<0); + + private: + T* list; + size_t listused; + size_t listlength; + compare_t comparator; + unsigned flags; + + public: + SortedList(compare_t thecomparator = NULL) : + list(NULL), + listused(0), + listlength(0), + comparator(thecomparator), + flags(0) + { + + } + + ~SortedList() + { + Clear(); + } + + public: + void SetComparator(compare_t thecomparator) + { + comparator = thecomparator; + flags &= ~FLAG_SORTED; + } + + void Clear() + { + for ( size_t i = 0; i < listused; i++ ) + { + list[i].~T(); + } + + listused = 0; + flags |= FLAG_SORTED; + delete[] list; + list = NULL; + } + + size_t Length() + { + return listused; + } + + bool Empty() + { + return !listused; + } + + bool IsSorted() + { + return (flags & FLAG_SORTED); + } + + void Sort(compare_t thecomparator) + { + comparator = thecomparator; + Sort(); + } + + void Sort() + { + if ( !listused || (flags & FLAG_SORTED) ) { return; } + + MergeSort(0, listused-1); + + flags |= FLAG_SORTED; + } + + void Invalidate() + { + flags &= ~FLAG_SORTED; + } + + bool Add(T t) + { + if ( listused == listlength && !Expand() ) { return false; } + + list[listused++] = t; + + flags &= ~FLAG_SORTED; + + return true; + } + + T Get(size_t index) + { + if ( !(flags & FLAG_SORTED) ) { Sort(); } + + return list[index]; + } + + // Accesses the elements, but the order might not be sorted. + T GetUnsorted(size_t index) + { + return list[index]; + } + + T Remove(size_t index) + { + if ( !(flags & FLAG_SORTED) ) { Sort(); } + + T result = list[listused-1]; + + if ( index == listused-1 ) + { + list[--listused].~T(); + } + else + { + list[index].~T(); + list[index] = list[--listused]; + list[listused].~T(); + flags &= ~FLAG_SORTED; + } + + return result; + } + + size_t Search(T searchee) + { + return Search(comparator, searchee); + } + + // Returns the index of the element being searched for using the given + // comparator, or returns SIZE_MAX if not found. + template size_t Search(int (*searcher)(const T t, const Searchee searchee), const Searchee searchee) + { + if ( !listused ) { return SIZE_MAX; } + if ( flags & FLAG_SORTED ) { Sort(); } + + size_t minindex = 0; + size_t maxindex = listused-1; + + do + { + size_t tryindex = (minindex + maxindex) / 2; + const T& t = list[tryindex]; + int relation = searcher(t, searchee); + if ( relation == 0 ) { return tryindex; } + if ( relation < 0 ) { minindex = tryindex+1; } + if ( relation > 0 ) { maxindex = tryindex-1; } + } while ( maxindex + 1 != minindex ); + + return SIZE_MAX; + } + + private: + bool Expand() + { + size_t newsize = (listused == 0 ) ? 4 : listlength*2; + + T* newlist = new T[newsize*2]; + if ( !newlist ) { return false; } + + for ( size_t i = 0; i < listused; i++ ) + { + newlist[i] = list[i]; + list[i].~T(); + } + + delete[] list; + list = newlist; + listlength = newsize; + + return true; + } + + T* GetDestList() + { + return list + listlength; + } + + void MergeSort(size_t minindex, size_t maxindex) + { + FixupMergeSort(minindex, maxindex); + } + + void FixupMergeSort(size_t minindex, size_t maxindex) + { + MergeSortInternal(minindex, maxindex); + + T* destlist = GetDestList(); + + do + { + list[minindex] = destlist[minindex]; + } while ( minindex++ != maxindex ); + } + + void MergeSortInternal(size_t minindex, size_t maxindex) + { + T* destlist = GetDestList(); + + if ( maxindex - minindex == 1 ) + { + if ( 0 < comparator(list[minindex], list[maxindex]) ) + { + destlist[minindex] = list[maxindex]; + destlist[maxindex] = list[minindex]; + list[minindex].~T(); + list[maxindex].~T(); + } + else + { + destlist[minindex] = list[minindex]; + destlist[maxindex] = list[maxindex]; + list[minindex].~T(); + list[maxindex].~T(); + } + + return; + } + + if ( minindex == maxindex ) + { + destlist[minindex] = list[minindex]; + list[minindex].~T(); + + return; + } + + const size_t asize = (maxindex - minindex + 1) / 2 + 1; + const size_t bsize = (maxindex - minindex) / 2; + const size_t astart = minindex; + const size_t bstart = minindex + asize; + const size_t aend = minindex + asize - 1; + const size_t bend = minindex + asize + bsize - 1; + + FixupMergeSort(astart, aend); + FixupMergeSort(bstart, bend); + + destlist += minindex; + + size_t aindex = astart; + size_t bindex = bstart; + + while ( aindex <= aend && bindex <= bend ) + { + int relation = comparator(list[aindex], list[bindex]); + if ( relation <= 0 ) + { + *destlist++ = list[aindex]; + list[aindex++].~T(); + } + else + { + *destlist++ = list[bindex]; + list[bindex++].~T(); + } + } + + while ( aindex <= aend ) + { + *destlist++ = list[aindex]; + list[aindex++].~T(); + } + + while ( bindex <= bend ) + { + *destlist++ = list[bindex]; + list[bindex++].~T(); + } + } + + }; +} + +#endif +