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:
parent
1b9e61ad87
commit
0c8bdbafd5
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user