/* * Copyright 2001-2014 Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * The Storage Kit Team * Stephan Aßmus * Rene Gollent * John Scipione, jscipione@gmail.com * Isaac Yonemoto */ //! BList class provides storage for pointers. Not thread safe. #include #include #include #include // helper function static inline void move_items(void** items, int32 offset, int32 count) { if (count > 0 && offset != 0) memmove(items + offset, items, count * sizeof(void*)); } BList::BList(int32 count) : fObjectList(NULL), fPhysicalSize(0), fItemCount(0), fBlockSize(count), fResizeThreshold(0) { if (fBlockSize <= 0) fBlockSize = 1; _ResizeArray(fItemCount); } BList::BList(const BList& other) : fObjectList(NULL), fPhysicalSize(0), fItemCount(0), fBlockSize(other.fBlockSize) { *this = other; } BList::~BList() { free(fObjectList); } BList& BList::operator=(const BList& other) { if (&other != this) { fBlockSize = other.fBlockSize; if (_ResizeArray(other.fItemCount)) { fItemCount = other.fItemCount; memcpy(fObjectList, other.fObjectList, fItemCount * sizeof(void*)); } } return *this; } bool BList::operator==(const BList& other) const { if (&other == this) return true; if (other.fItemCount != fItemCount) return false; if (fItemCount > 0) { return memcmp(fObjectList, other.fObjectList, fItemCount * sizeof(void*)) == 0; } return true; } bool BList::operator!=(const BList& other) const { return !(*this == other); } bool BList::AddItem(void* item, int32 index) { if (index < 0 || index > fItemCount) return false; bool result = true; if (fItemCount + 1 > fPhysicalSize) result = _ResizeArray(fItemCount + 1); if (result) { ++fItemCount; move_items(fObjectList + index, 1, fItemCount - index - 1); fObjectList[index] = item; } return result; } bool BList::AddItem(void* item) { bool result = true; if (fPhysicalSize > fItemCount) { fObjectList[fItemCount] = item; ++fItemCount; } else { if ((result = _ResizeArray(fItemCount + 1))) { fObjectList[fItemCount] = item; ++fItemCount; } } return result; } bool BList::AddList(const BList* list, int32 index) { bool result = (list && index >= 0 && index <= fItemCount); if (result && list->fItemCount > 0) { int32 count = list->fItemCount; if (fItemCount + count > fPhysicalSize) result = _ResizeArray(fItemCount + count); if (result) { fItemCount += count; move_items(fObjectList + index, count, fItemCount - index - count); memcpy(fObjectList + index, list->fObjectList, list->fItemCount * sizeof(void*)); } } return result; } bool BList::AddList(const BList* list) { bool result = (list != NULL); if (result && list->fItemCount > 0) { int32 index = fItemCount; int32 count = list->fItemCount; if (fItemCount + count > fPhysicalSize) result = _ResizeArray(fItemCount + count); if (result) { fItemCount += count; memcpy(fObjectList + index, list->fObjectList, list->fItemCount * sizeof(void*)); } } return result; } bool BList::RemoveItem(void* item) { int32 index = IndexOf(item); bool result = (index >= 0); if (result) RemoveItem(index); return result; } void* BList::RemoveItem(int32 index) { void* item = NULL; if (index >= 0 && index < fItemCount) { item = fObjectList[index]; move_items(fObjectList + index + 1, -1, fItemCount - index - 1); --fItemCount; if (fItemCount <= fResizeThreshold) _ResizeArray(fItemCount); } return item; } bool BList::RemoveItems(int32 index, int32 count) { bool result = (index >= 0 && index <= fItemCount); if (result) { if (index + count > fItemCount) count = fItemCount - index; if (count > 0) { move_items(fObjectList + index + count, -count, fItemCount - index - count); fItemCount -= count; if (fItemCount <= fResizeThreshold) _ResizeArray(fItemCount); } else result = false; } return result; } bool BList::ReplaceItem(int32 index, void* item) { bool result = false; if (index >= 0 && index < fItemCount) { fObjectList[index] = item; result = true; } return result; } void BList::MakeEmpty() { fItemCount = 0; _ResizeArray(0); } // #pragma mark - Reordering items. void BList::SortItems(int (*compareFunc)(const void*, const void*)) { if (compareFunc) qsort(fObjectList, fItemCount, sizeof(void*), compareFunc); } bool BList::SwapItems(int32 indexA, int32 indexB) { bool result = false; if (indexA >= 0 && indexA < fItemCount && indexB >= 0 && indexB < fItemCount) { void* tmpItem = fObjectList[indexA]; fObjectList[indexA] = fObjectList[indexB]; fObjectList[indexB] = tmpItem; result = true; } return result; } /*! This moves a list item from posititon a to position b, moving the appropriate block of list elements to make up for the move. For example, in the array: A B C D E F G H I J Moveing 1(B)->6(G) would result in this: A C D E F G B H I J */ bool BList::MoveItem(int32 from, int32 to) { if ((from >= fItemCount) || (to >= fItemCount) || (from < 0) || (to < 0)) return false; void* tmpMover = fObjectList[from]; if (from < to) { memmove(fObjectList + from, fObjectList + from + 1, (to - from) * sizeof(void*)); } else if (from > to) { memmove(fObjectList + to + 1, fObjectList + to, (from - to) * sizeof(void*)); } fObjectList[to] = tmpMover; return true; } // #pragma mark - Retrieving items. void* BList::ItemAt(int32 index) const { void* item = NULL; if (index >= 0 && index < fItemCount) item = fObjectList[index]; return item; } void* BList::FirstItem() const { void* item = NULL; if (fItemCount > 0) item = fObjectList[0]; return item; } void* BList::ItemAtFast(int32 index) const { return fObjectList[index]; } void* BList::Items() const { return fObjectList; } void* BList::LastItem() const { void* item = NULL; if (fItemCount > 0) item = fObjectList[fItemCount - 1]; return item; } // #pragma mark - Querying the list. bool BList::HasItem(void* item) const { return (IndexOf(item) >= 0); } bool BList::HasItem(const void* item) const { return (IndexOf(item) >= 0); } int32 BList::IndexOf(void* item) const { for (int32 i = 0; i < fItemCount; i++) { if (fObjectList[i] == item) return i; } return -1; } int32 BList::IndexOf(const void* item) const { for (int32 i = 0; i < fItemCount; i++) { if (fObjectList[i] == item) return i; } return -1; } int32 BList::CountItems() const { return fItemCount; } bool BList::IsEmpty() const { return fItemCount == 0; } // #pragma mark - Iterating over the list. /*! Iterate a function over the whole list. If the function outputs a true value, then the process is terminated. */ void BList::DoForEach(bool (*func)(void*)) { if (func == NULL) return; bool terminate = false; int32 index = 0; while ((!terminate) && (index < fItemCount)) { terminate = func(fObjectList[index]); index++; } } /*! Iterate a function over the whole list. If the function outputs a true value, then the process is terminated. This version takes an additional argument which is passed to the function. */ void BList::DoForEach(bool (*func)(void*, void*), void* arg) { if (func == NULL) return; bool terminate = false; int32 index = 0; while ((!terminate) && (index < fItemCount)) { terminate = func(fObjectList[index], arg); index++; } } #if (__GNUC__ == 2) // This is somewhat of a hack for backwards compatibility - // the reason these functions are defined this way rather than simply // being made private members is that if they are included, then whenever // gcc encounters someone calling AddList() with a non-const BList pointer, // it will try to use the private version and fail with a compiler error. // obsolete AddList(BList* list, int32 index) and AddList(BList* list) // AddList extern "C" bool AddList__5BListP5BListl(BList* self, BList* list, int32 index) { return self->AddList((const BList*)list, index); } // AddList extern "C" bool AddList__5BListP5BList(BList* self, BList* list) { return self->AddList((const BList*)list); } #endif // FBC void BList::_ReservedList1() {} void BList::_ReservedList2() {} //! Resizes fObjectList to be large enough to contain count items. bool BList::_ResizeArray(int32 count) { bool result = true; // calculate the new physical size // by doubling the existing size // until we can hold at least count items int32 newSize = fPhysicalSize > 0 ? fPhysicalSize : fBlockSize; int32 targetSize = count; if (targetSize <= 0) targetSize = fBlockSize; if (targetSize > fPhysicalSize) { while (newSize < targetSize) newSize <<= 1; } else if (targetSize <= fResizeThreshold) newSize = fResizeThreshold; // resize if necessary if (newSize != fPhysicalSize) { void** newObjectList = (void**)realloc(fObjectList, newSize * sizeof(void*)); if (newObjectList) { fObjectList = newObjectList; fPhysicalSize = newSize; // set our lower bound to either 1/4 //of the current physical size, or 0 fResizeThreshold = fPhysicalSize >> 2 >= fBlockSize ? fPhysicalSize >> 2 : 0; } else result = false; } return result; }