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

View File

@ -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

View File

@ -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

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
// 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
// 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;
}

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
// 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;
}