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
This commit is contained in:
Rene Gollent
2008-06-12 21:30:28 +00:00
parent 1b9e61ad87
commit 0c8bdbafd5
4 changed files with 120 additions and 64 deletions
+6 -6
View File
@@ -43,8 +43,8 @@ public:
/* Adding and removing items. */ /* Adding and removing items. */
bool AddItem(void *item, int32 index); bool AddItem(void *item, int32 index);
bool AddItem(void *item); bool AddItem(void *item);
bool AddList(BList *list, int32 index); bool AddList(const BList *list, int32 index);
bool AddList(BList *list); bool AddList(const BList *list);
bool RemoveItem(void *item); bool RemoveItem(void *item);
void *RemoveItem(int32 index); void *RemoveItem(int32 index);
bool RemoveItems(int32 index, int32 count); bool RemoveItems(int32 index, int32 count);
@@ -85,14 +85,14 @@ private:
virtual void _ReservedList2(); virtual void _ReservedList2();
// return type differs from BeOS version // return type differs from BeOS version
bool Resize(int32 count); bool _ResizeArray(int32 count);
private: private:
void** fObjectList; void** fObjectList;
size_t fPhysicalSize; int32 fPhysicalSize;
int32 fItemCount; int32 fItemCount;
int32 fBlockSize; int32 fBlockSize;
uint32 _reserved[2]; int32 fResizeThreshold;
uint32 _reserved[1];
}; };
#endif // _BE_LIST_H #endif // _BE_LIST_H
+4 -4
View File
@@ -56,14 +56,14 @@ class BList {
virtual void _ReservedList1(); virtual void _ReservedList1();
virtual void _ReservedList2(); virtual void _ReservedList2();
bool Resize(int32 count); bool _ResizeArray(int32 count);
private: private:
void** fObjectList; void** fObjectList;
size_t fPhysicalSize; int32 fPhysicalSize;
int32 fItemCount; int32 fItemCount;
int32 fBlockSize; int32 fBlockSize;
uint32 _reserved[2]; int32 fResizeThreshold;
uint32 _reserved[1];
}; };
#endif // _BE_LIST_H #endif // _BE_LIST_H
+56 -28
View File
@@ -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 // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
@@ -22,6 +22,7 @@
// File Name: List.cpp // File Name: List.cpp
// Author(s): The Storage kit Team // Author(s): The Storage kit Team
// Isaac Yonemoto // Isaac Yonemoto
// Rene Gollent
// Description: BList class provides storage for pointers. // Description: BList class provides storage for pointers.
// Not thread safe. // Not thread safe.
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -34,7 +35,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <syslog.h>
// helper function // helper function
static inline static inline
@@ -51,11 +52,12 @@ BList::BList(int32 count)
: fObjectList(NULL), : fObjectList(NULL),
fPhysicalSize(0), fPhysicalSize(0),
fItemCount(0), fItemCount(0),
fBlockSize(count) fBlockSize(count),
fResizeThreshold(0)
{ {
if (fBlockSize <= 0) if (fBlockSize <= 0)
fBlockSize = 1; fBlockSize = 1;
Resize(fItemCount); _ResizeArray(fItemCount);
} }
@@ -82,7 +84,8 @@ BList&
BList::operator =(const BList &list) BList::operator =(const BList &list)
{ {
fBlockSize = list.fBlockSize; fBlockSize = list.fBlockSize;
Resize(list.fItemCount); _ResizeArray(list.fItemCount);
fItemCount = list.fItemCount;
memcpy(fObjectList, list.fObjectList, fItemCount * sizeof(void*)); memcpy(fObjectList, list.fObjectList, fItemCount * sizeof(void*));
return *this; return *this;
} }
@@ -92,9 +95,15 @@ BList::operator =(const BList &list)
bool bool
BList::AddItem(void *item, int32 index) BList::AddItem(void *item, int32 index)
{ {
bool result = (index >= 0 && index <= fItemCount if (index < 0 || index > fItemCount)
&& Resize(fItemCount + 1)); return false;
bool result = true;
if (fItemCount + 1 > fPhysicalSize)
result = _ResizeArray(fItemCount + 1);
if (result) { if (result) {
++fItemCount;
move_items(fObjectList + index, 1, fItemCount - index - 1); move_items(fObjectList + index, 1, fItemCount - index - 1);
fObjectList[index] = item; fObjectList[index] = item;
} }
@@ -107,12 +116,14 @@ bool
BList::AddItem(void *item) BList::AddItem(void *item)
{ {
bool result = true; bool result = true;
if ((int32)fPhysicalSize > fItemCount) { if (fPhysicalSize > fItemCount) {
fObjectList[fItemCount] = item; fObjectList[fItemCount] = item;
fItemCount++; ++fItemCount;
} else { } else {
if ((result = Resize(fItemCount + 1))) if ((result = _ResizeArray(fItemCount + 1))) {
fObjectList[fItemCount - 1] = item; fObjectList[fItemCount] = item;
++fItemCount;
}
} }
return result; return result;
} }
@@ -120,13 +131,15 @@ BList::AddItem(void *item)
// AddList // AddList
bool bool
BList::AddList(BList *list, int32 index) BList::AddList(const BList *list, int32 index)
{ {
bool result = (list && index >= 0 && index <= fItemCount); bool result = (list && index >= 0 && index <= fItemCount);
if (result && list->fItemCount > 0) { if (result && list->fItemCount > 0) {
int32 count = list->fItemCount; int32 count = list->fItemCount;
result = Resize(fItemCount + count); if (fItemCount + count > fPhysicalSize)
result = _ResizeArray(fItemCount + count);
if (result) { if (result) {
fItemCount += count;
move_items(fObjectList + index, count, fItemCount - index - count); move_items(fObjectList + index, count, fItemCount - index - count);
memcpy(fObjectList + index, list->fObjectList, memcpy(fObjectList + index, list->fObjectList,
list->fItemCount * sizeof(void *)); list->fItemCount * sizeof(void *));
@@ -138,14 +151,16 @@ BList::AddList(BList *list, int32 index)
// AddList // AddList
bool bool
BList::AddList(BList *list) BList::AddList(const BList *list)
{ {
bool result = (list != NULL); bool result = (list != NULL);
if (result && list->fItemCount > 0) { if (result && list->fItemCount > 0) {
int32 index = fItemCount; int32 index = fItemCount;
int32 count = list->fItemCount; int32 count = list->fItemCount;
result = Resize(fItemCount + count); if (fItemCount + count > fPhysicalSize)
result = _ResizeArray(fItemCount + count);
if (result) { if (result) {
fItemCount += count;
memcpy(fObjectList + index, list->fObjectList, memcpy(fObjectList + index, list->fObjectList,
list->fItemCount * sizeof(void *)); list->fItemCount * sizeof(void *));
} }
@@ -174,7 +189,9 @@ BList::RemoveItem(int32 index)
if (index >= 0 && index < fItemCount) { if (index >= 0 && index < fItemCount) {
item = fObjectList[index]; item = fObjectList[index];
move_items(fObjectList + index + 1, -1, fItemCount - index - 1); move_items(fObjectList + index + 1, -1, fItemCount - index - 1);
Resize(fItemCount - 1); --fItemCount;
if (fItemCount <= fResizeThreshold)
_ResizeArray(fItemCount);
} }
return item; return item;
} }
@@ -191,7 +208,9 @@ BList::RemoveItems(int32 index, int32 count)
if (count > 0) { if (count > 0) {
move_items(fObjectList + index + count, -count, move_items(fObjectList + index + count, -count,
fItemCount - index - count); fItemCount - index - count);
Resize(fItemCount - count); fItemCount -= count;
if (fItemCount <= fResizeThreshold)
_ResizeArray(fItemCount);
} else } else
result = false; result = false;
} }
@@ -217,7 +236,8 @@ BList::ReplaceItem(int32 index, void *newItem)
void void
BList::MakeEmpty() BList::MakeEmpty()
{ {
Resize(0); fItemCount = 0;
_ResizeArray(0);
} }
@@ -401,37 +421,45 @@ BList::DoForEach(bool (*func)(void *, void*), void * arg)
} }
} }
// FBC // FBC
void BList::_ReservedList1() {} void BList::_ReservedList1() {}
void BList::_ReservedList2() {} void BList::_ReservedList2() {}
// Resize // Resize
// //
// Resizes fObjectList to be large enough to contain count items. // Resizes fObjectList to be large enough to contain count items.
// fItemCount is adjusted accordingly. // fItemCount is adjusted accordingly.
bool bool
BList::Resize(int32 count) BList::_ResizeArray(int32 count)
{ {
bool result = true; bool result = true;
// calculate the new physical size // calculate the new physical size
int32 newSize = count; // by doubling the existing size
if (newSize <= 0) // until we can hold at least count items
newSize = 1; int32 newSize = fPhysicalSize > 0 ? fPhysicalSize : fBlockSize;
newSize = ((newSize - 1) / fBlockSize + 1) * 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 // resize if necessary
if ((size_t)newSize != fPhysicalSize) { if (newSize != fPhysicalSize) {
void** newObjectList void** newObjectList
= (void**)realloc(fObjectList, newSize * sizeof(void*)); = (void**)realloc(fObjectList, newSize * sizeof(void*));
if (newObjectList) { if (newObjectList) {
fObjectList = newObjectList; fObjectList = newObjectList;
fPhysicalSize = newSize; 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 } else
result = false; result = false;
} }
if (result)
fItemCount = count;
return result; return result;
} }
+54 -26
View File
@@ -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 // Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"), // copy of this software and associated documentation files (the "Software"),
@@ -22,6 +22,7 @@
// File Name: List.cpp // File Name: List.cpp
// Author(s): The Storage kit Team // Author(s): The Storage kit Team
// Isaac Yonemoto // Isaac Yonemoto
// Rene Gollent
// Description: BList class provides storage for pointers. // Description: BList class provides storage for pointers.
// Not thread safe. // Not thread safe.
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -51,11 +52,12 @@ BList::BList(int32 count)
: fObjectList(NULL), : fObjectList(NULL),
fPhysicalSize(0), fPhysicalSize(0),
fItemCount(0), fItemCount(0),
fBlockSize(count) fBlockSize(count),
fResizeThreshold(0)
{ {
if (fBlockSize <= 0) if (fBlockSize <= 0)
fBlockSize = 1; fBlockSize = 1;
Resize(fItemCount); _ResizeArray(fItemCount);
} }
@@ -82,7 +84,8 @@ BList&
BList::operator =(const BList &list) BList::operator =(const BList &list)
{ {
fBlockSize = list.fBlockSize; fBlockSize = list.fBlockSize;
Resize(list.fItemCount); _ResizeArray(list.fItemCount);
fItemCount = list.fItemCount;
memcpy(fObjectList, list.fObjectList, fItemCount * sizeof(void*)); memcpy(fObjectList, list.fObjectList, fItemCount * sizeof(void*));
return *this; return *this;
} }
@@ -92,9 +95,15 @@ BList::operator =(const BList &list)
bool bool
BList::AddItem(void *item, int32 index) BList::AddItem(void *item, int32 index)
{ {
bool result = (index >= 0 && index <= fItemCount if (index < 0 || index > fItemCount)
&& Resize(fItemCount + 1)); return false;
bool result = true;
if (fItemCount + 1 > fPhysicalSize)
result = _ResizeArray(fItemCount + 1);
if (result) { if (result) {
++fItemCount;
move_items(fObjectList + index, 1, fItemCount - index - 1); move_items(fObjectList + index, 1, fItemCount - index - 1);
fObjectList[index] = item; fObjectList[index] = item;
} }
@@ -107,12 +116,14 @@ bool
BList::AddItem(void *item) BList::AddItem(void *item)
{ {
bool result = true; bool result = true;
if ((int32)fPhysicalSize > fItemCount) { if (fPhysicalSize > fItemCount) {
fObjectList[fItemCount] = item; fObjectList[fItemCount] = item;
fItemCount++; ++fItemCount;
} else { } else {
if ((result = Resize(fItemCount + 1))) if ((result = _ResizeArray(fItemCount + 1))) {
fObjectList[fItemCount - 1] = item; fObjectList[fItemCount] = item;
++fItemCount;
}
} }
return result; return result;
} }
@@ -125,8 +136,10 @@ BList::AddList(const BList *list, int32 index)
bool result = (list && index >= 0 && index <= fItemCount); bool result = (list && index >= 0 && index <= fItemCount);
if (result && list->fItemCount > 0) { if (result && list->fItemCount > 0) {
int32 count = list->fItemCount; int32 count = list->fItemCount;
result = Resize(fItemCount + count); if (fItemCount + count > fPhysicalSize)
result = _ResizeArray(fItemCount + count);
if (result) { if (result) {
fItemCount += count;
move_items(fObjectList + index, count, fItemCount - index - count); move_items(fObjectList + index, count, fItemCount - index - count);
memcpy(fObjectList + index, list->fObjectList, memcpy(fObjectList + index, list->fObjectList,
list->fItemCount * sizeof(void *)); list->fItemCount * sizeof(void *));
@@ -144,8 +157,10 @@ BList::AddList(const BList *list)
if (result && list->fItemCount > 0) { if (result && list->fItemCount > 0) {
int32 index = fItemCount; int32 index = fItemCount;
int32 count = list->fItemCount; int32 count = list->fItemCount;
result = Resize(fItemCount + count); if (fItemCount + count > fPhysicalSize)
result = _ResizeArray(fItemCount + count);
if (result) { if (result) {
fItemCount += count;
memcpy(fObjectList + index, list->fObjectList, memcpy(fObjectList + index, list->fObjectList,
list->fItemCount * sizeof(void *)); list->fItemCount * sizeof(void *));
} }
@@ -174,7 +189,9 @@ BList::RemoveItem(int32 index)
if (index >= 0 && index < fItemCount) { if (index >= 0 && index < fItemCount) {
item = fObjectList[index]; item = fObjectList[index];
move_items(fObjectList + index + 1, -1, fItemCount - index - 1); move_items(fObjectList + index + 1, -1, fItemCount - index - 1);
Resize(fItemCount - 1); --fItemCount;
if (fItemCount <= fResizeThreshold)
_ResizeArray(fItemCount);
} }
return item; return item;
} }
@@ -191,7 +208,9 @@ BList::RemoveItems(int32 index, int32 count)
if (count > 0) { if (count > 0) {
move_items(fObjectList + index + count, -count, move_items(fObjectList + index + count, -count,
fItemCount - index - count); fItemCount - index - count);
Resize(fItemCount - count); fItemCount -= count;
if (fItemCount <= fResizeThreshold)
_ResizeArray(fItemCount);
} else } else
result = false; result = false;
} }
@@ -217,7 +236,8 @@ BList::ReplaceItem(int32 index, void *newItem)
void void
BList::MakeEmpty() 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) // obsolete AddList(BList* list, int32 index) and AddList(BList* list)
// AddList // AddList
extern "C" bool extern "C" bool
AddList__5BListP5BListl(BList* self, BList* list, int32 index) 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); return self->AddList((const BList*)list, index);
} }
// AddList // AddList
extern "C" bool extern "C" bool
AddList__5BListP5BList(BList* self, BList* list) AddList__5BListP5BList(BList* self, BList* list)
{ {
return self->AddList((const BList*)list); return self->AddList((const BList *)list);
} }
#endif
// FBC // FBC
void BList::_ReservedList1() {} void BList::_ReservedList1() {}
void BList::_ReservedList2() {} void BList::_ReservedList2() {}
// Resize // Resize
// //
// Resizes fObjectList to be large enough to contain count items. // Resizes fObjectList to be large enough to contain count items.
// fItemCount is adjusted accordingly. // fItemCount is adjusted accordingly.
bool bool
BList::Resize(int32 count) BList::_ResizeArray(int32 count)
{ {
bool result = true; bool result = true;
// calculate the new physical size // calculate the new physical size
// by doubling the existing size // by doubling the existing size
// until we can hold at least count items // until we can hold at least count items
int32 newSize = fBlockSize; int32 newSize = fPhysicalSize > 0 ? fPhysicalSize : fBlockSize;
int32 targetSize = count; int32 targetSize = count;
if (targetSize <= 0) if (targetSize <= 0)
targetSize = fBlockSize; targetSize = fBlockSize;
if ((size_t)targetSize != fPhysicalSize) { if (targetSize > fPhysicalSize) {
while (newSize < targetSize) while (newSize < targetSize)
newSize <<= 1; newSize <<= 1;
} else if (targetSize <= fResizeThreshold) {
newSize = fResizeThreshold;
} }
// resize if necessary // resize if necessary
if ((size_t)newSize != fPhysicalSize) { if (newSize != fPhysicalSize) {
void** newObjectList void** newObjectList
= (void**)realloc(fObjectList, newSize * sizeof(void*)); = (void**)realloc(fObjectList, newSize * sizeof(void*));
if (newObjectList) { if (newObjectList) {
fObjectList = newObjectList; fObjectList = newObjectList;
fPhysicalSize = newSize; 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 } else
result = false; result = false;
} }
if (result)
fItemCount = count;
return result; return result;
} }