* 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
*/
#include <List.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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);
}
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;
}
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;
}
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;
}
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;
}
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++;
}
}
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)
extern "C" bool
AddList__5BListP5BListl(BList* self, BList* list, int32 index)
{
return self->AddList((const BList*)list, index);
}
extern "C" bool
AddList__5BListP5BList(BList* self, BList* list)
{
return self->AddList((const BList*)list);
}
#endif
void BList::_ReservedList1() {}
void BList::_ReservedList2() {}
bool
BList::_ResizeArray(int32 count)
{
bool result = true;
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;
if (newSize != fPhysicalSize) {
void** newObjectList
= (void**)realloc(fObjectList, newSize * sizeof(void*));
if (newObjectList) {
fObjectList = newObjectList;
fPhysicalSize = newSize;
fResizeThreshold = fPhysicalSize >> 2 >= fBlockSize
? fPhysicalSize >> 2 : 0;
} else
result = false;
}
return result;
}