From 0c8bdbafd535f10661ddf55470150da758c08454 Mon Sep 17 00:00:00 2001 From: Rene Gollent Date: Thu, 12 Jun 2008 21:30:28 +0000 Subject: [PATCH] Revamp BList somewhat to further optimize the resizing behavior. We now keep track of a lower bound as to when the list should scale itself back down. When increasing the list size, we double the current, with the lower bound set to 1/4 of the current size, not allowing it to go any smaller than the block size. These combined allow us to do very cheap tests to see if an operation requires a resize at all, and minimize how often the list actually needs to be resized, since the difference in upper and lower bounds prevents bouncing back and forth between a size in the case of adding/removing an item while close to a boundary. All in all this should make BList noticably more scalable when doing large numbers of add/remove operations. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25946 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/build/os/support/List.h | 12 ++--- headers/os/support/List.h | 8 +-- src/build/libbe/support/List.cpp | 84 +++++++++++++++++++++----------- src/kits/support/List.cpp | 80 ++++++++++++++++++++---------- 4 files changed, 120 insertions(+), 64 deletions(-) diff --git a/headers/build/os/support/List.h b/headers/build/os/support/List.h index 52affec9e5..31e7eacdee 100644 --- a/headers/build/os/support/List.h +++ b/headers/build/os/support/List.h @@ -43,8 +43,8 @@ public: /* Adding and removing items. */ bool AddItem(void *item, int32 index); bool AddItem(void *item); - bool AddList(BList *list, int32 index); - bool AddList(BList *list); + bool AddList(const BList *list, int32 index); + bool AddList(const BList *list); bool RemoveItem(void *item); void *RemoveItem(int32 index); bool RemoveItems(int32 index, int32 count); @@ -85,14 +85,14 @@ private: virtual void _ReservedList2(); // return type differs from BeOS version - bool Resize(int32 count); - + bool _ResizeArray(int32 count); private: void** fObjectList; - size_t fPhysicalSize; + int32 fPhysicalSize; int32 fItemCount; int32 fBlockSize; - uint32 _reserved[2]; + int32 fResizeThreshold; + uint32 _reserved[1]; }; #endif // _BE_LIST_H diff --git a/headers/os/support/List.h b/headers/os/support/List.h index 1ca7232c8f..2d5594cd07 100644 --- a/headers/os/support/List.h +++ b/headers/os/support/List.h @@ -56,14 +56,14 @@ class BList { virtual void _ReservedList1(); virtual void _ReservedList2(); - bool Resize(int32 count); - + bool _ResizeArray(int32 count); private: void** fObjectList; - size_t fPhysicalSize; + int32 fPhysicalSize; int32 fItemCount; int32 fBlockSize; - uint32 _reserved[2]; + int32 fResizeThreshold; + uint32 _reserved[1]; }; #endif // _BE_LIST_H diff --git a/src/build/libbe/support/List.cpp b/src/build/libbe/support/List.cpp index a6b069b493..f03cbc7548 100644 --- a/src/build/libbe/support/List.cpp +++ b/src/build/libbe/support/List.cpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// Copyright (c) 2001-2002, OpenBeOS +// Copyright (c) 2001-2008, Haiku, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), @@ -22,6 +22,7 @@ // File Name: List.cpp // Author(s): The Storage kit Team // Isaac Yonemoto +// Rene Gollent // Description: BList class provides storage for pointers. // Not thread safe. //------------------------------------------------------------------------------ @@ -34,7 +35,7 @@ #include #include #include - +#include // helper function static inline @@ -51,11 +52,12 @@ BList::BList(int32 count) : fObjectList(NULL), fPhysicalSize(0), fItemCount(0), - fBlockSize(count) + fBlockSize(count), + fResizeThreshold(0) { if (fBlockSize <= 0) fBlockSize = 1; - Resize(fItemCount); + _ResizeArray(fItemCount); } @@ -82,7 +84,8 @@ BList& BList::operator =(const BList &list) { fBlockSize = list.fBlockSize; - Resize(list.fItemCount); + _ResizeArray(list.fItemCount); + fItemCount = list.fItemCount; memcpy(fObjectList, list.fObjectList, fItemCount * sizeof(void*)); return *this; } @@ -92,9 +95,15 @@ BList::operator =(const BList &list) bool BList::AddItem(void *item, int32 index) { - bool result = (index >= 0 && index <= fItemCount - && Resize(fItemCount + 1)); + 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; } @@ -107,12 +116,14 @@ bool BList::AddItem(void *item) { bool result = true; - if ((int32)fPhysicalSize > fItemCount) { + if (fPhysicalSize > fItemCount) { fObjectList[fItemCount] = item; - fItemCount++; + ++fItemCount; } else { - if ((result = Resize(fItemCount + 1))) - fObjectList[fItemCount - 1] = item; + if ((result = _ResizeArray(fItemCount + 1))) { + fObjectList[fItemCount] = item; + ++fItemCount; + } } return result; } @@ -120,13 +131,15 @@ BList::AddItem(void *item) // AddList bool -BList::AddList(BList *list, int32 index) +BList::AddList(const BList *list, int32 index) { bool result = (list && index >= 0 && index <= fItemCount); if (result && list->fItemCount > 0) { int32 count = list->fItemCount; - result = Resize(fItemCount + count); + 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 *)); @@ -138,14 +151,16 @@ BList::AddList(BList *list, int32 index) // AddList bool -BList::AddList(BList *list) +BList::AddList(const BList *list) { bool result = (list != NULL); if (result && list->fItemCount > 0) { int32 index = fItemCount; int32 count = list->fItemCount; - result = Resize(fItemCount + count); + if (fItemCount + count > fPhysicalSize) + result = _ResizeArray(fItemCount + count); if (result) { + fItemCount += count; memcpy(fObjectList + index, list->fObjectList, list->fItemCount * sizeof(void *)); } @@ -174,7 +189,9 @@ BList::RemoveItem(int32 index) if (index >= 0 && index < fItemCount) { item = fObjectList[index]; move_items(fObjectList + index + 1, -1, fItemCount - index - 1); - Resize(fItemCount - 1); + --fItemCount; + if (fItemCount <= fResizeThreshold) + _ResizeArray(fItemCount); } return item; } @@ -191,7 +208,9 @@ BList::RemoveItems(int32 index, int32 count) if (count > 0) { move_items(fObjectList + index + count, -count, fItemCount - index - count); - Resize(fItemCount - count); + fItemCount -= count; + if (fItemCount <= fResizeThreshold) + _ResizeArray(fItemCount); } else result = false; } @@ -217,7 +236,8 @@ BList::ReplaceItem(int32 index, void *newItem) void BList::MakeEmpty() { - Resize(0); + fItemCount = 0; + _ResizeArray(0); } @@ -401,37 +421,45 @@ BList::DoForEach(bool (*func)(void *, void*), void * arg) } } - // FBC void BList::_ReservedList1() {} void BList::_ReservedList2() {} - // Resize // // Resizes fObjectList to be large enough to contain count items. // fItemCount is adjusted accordingly. bool -BList::Resize(int32 count) +BList::_ResizeArray(int32 count) { bool result = true; // calculate the new physical size - int32 newSize = count; - if (newSize <= 0) - newSize = 1; - newSize = ((newSize - 1) / fBlockSize + 1) * fBlockSize; + // 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 ((size_t)newSize != fPhysicalSize) { + 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; } - if (result) - fItemCount = count; return result; } diff --git a/src/kits/support/List.cpp b/src/kits/support/List.cpp index 72e73831ef..b2b70f7ec9 100644 --- a/src/kits/support/List.cpp +++ b/src/kits/support/List.cpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// Copyright (c) 2001-2002, OpenBeOS +// Copyright (c) 2001-2008, Haiku, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), @@ -22,6 +22,7 @@ // File Name: List.cpp // Author(s): The Storage kit Team // Isaac Yonemoto +// Rene Gollent // Description: BList class provides storage for pointers. // Not thread safe. //------------------------------------------------------------------------------ @@ -51,11 +52,12 @@ BList::BList(int32 count) : fObjectList(NULL), fPhysicalSize(0), fItemCount(0), - fBlockSize(count) + fBlockSize(count), + fResizeThreshold(0) { if (fBlockSize <= 0) fBlockSize = 1; - Resize(fItemCount); + _ResizeArray(fItemCount); } @@ -82,7 +84,8 @@ BList& BList::operator =(const BList &list) { fBlockSize = list.fBlockSize; - Resize(list.fItemCount); + _ResizeArray(list.fItemCount); + fItemCount = list.fItemCount; memcpy(fObjectList, list.fObjectList, fItemCount * sizeof(void*)); return *this; } @@ -92,9 +95,15 @@ BList::operator =(const BList &list) bool BList::AddItem(void *item, int32 index) { - bool result = (index >= 0 && index <= fItemCount - && Resize(fItemCount + 1)); + 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; } @@ -107,12 +116,14 @@ bool BList::AddItem(void *item) { bool result = true; - if ((int32)fPhysicalSize > fItemCount) { + if (fPhysicalSize > fItemCount) { fObjectList[fItemCount] = item; - fItemCount++; + ++fItemCount; } else { - if ((result = Resize(fItemCount + 1))) - fObjectList[fItemCount - 1] = item; + if ((result = _ResizeArray(fItemCount + 1))) { + fObjectList[fItemCount] = item; + ++fItemCount; + } } return result; } @@ -125,8 +136,10 @@ BList::AddList(const BList *list, int32 index) bool result = (list && index >= 0 && index <= fItemCount); if (result && list->fItemCount > 0) { int32 count = list->fItemCount; - result = Resize(fItemCount + count); + 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 *)); @@ -144,8 +157,10 @@ BList::AddList(const BList *list) if (result && list->fItemCount > 0) { int32 index = fItemCount; int32 count = list->fItemCount; - result = Resize(fItemCount + count); + if (fItemCount + count > fPhysicalSize) + result = _ResizeArray(fItemCount + count); if (result) { + fItemCount += count; memcpy(fObjectList + index, list->fObjectList, list->fItemCount * sizeof(void *)); } @@ -174,7 +189,9 @@ BList::RemoveItem(int32 index) if (index >= 0 && index < fItemCount) { item = fObjectList[index]; move_items(fObjectList + index + 1, -1, fItemCount - index - 1); - Resize(fItemCount - 1); + --fItemCount; + if (fItemCount <= fResizeThreshold) + _ResizeArray(fItemCount); } return item; } @@ -191,7 +208,9 @@ BList::RemoveItems(int32 index, int32 count) if (count > 0) { move_items(fObjectList + index + count, -count, fItemCount - index - count); - Resize(fItemCount - count); + fItemCount -= count; + if (fItemCount <= fResizeThreshold) + _ResizeArray(fItemCount); } else result = false; } @@ -217,7 +236,8 @@ BList::ReplaceItem(int32 index, void *newItem) void BList::MakeEmpty() { - Resize(0); + fItemCount = 0; + _ResizeArray(0); } @@ -401,9 +421,15 @@ BList::DoForEach(bool (*func)(void *, void*), void * arg) } } +#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) @@ -411,52 +437,54 @@ 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); + return self->AddList((const BList *)list); } - +#endif // FBC void BList::_ReservedList1() {} void BList::_ReservedList2() {} - // Resize // // Resizes fObjectList to be large enough to contain count items. // fItemCount is adjusted accordingly. bool -BList::Resize(int32 count) +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 = fBlockSize; + int32 newSize = fPhysicalSize > 0 ? fPhysicalSize : fBlockSize; int32 targetSize = count; if (targetSize <= 0) targetSize = fBlockSize; - if ((size_t)targetSize != fPhysicalSize) { + if (targetSize > fPhysicalSize) { while (newSize < targetSize) newSize <<= 1; + } else if (targetSize <= fResizeThreshold) { + newSize = fResizeThreshold; } // resize if necessary - if ((size_t)newSize != fPhysicalSize) { + 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; } - if (result) - fItemCount = count; return result; }