List class which stores objects (not pointers) or plain old data.

This commit is contained in:
Stephan Aßmus 2013-07-28 11:55:13 +02:00
parent 8add07a8e1
commit e9e74b7bab

196
src/apps/haiku-depot/List.h Normal file
View File

@ -0,0 +1,196 @@
/*
* Copyright 2009-2012, Stephan Aßmus <superstippi@gmx.de>
* All rights reserved. Distributed under the terms of the MIT License.
*/
#ifndef LIST_H
#define LIST_H
#include <new>
#include <stdlib.h>
#include <SupportDefs.h>
template <typename ItemType, bool PlainOldData, uint32 BlockSize = 8>
class List {
typedef List<ItemType, PlainOldData, BlockSize> SelfType;
public:
List()
:
fItems(NULL),
fCount(0),
fAllocatedCount(0)
{
}
List(const SelfType& other)
:
fItems(NULL),
fCount(0),
fAllocatedCount(0)
{
*this = other;
}
virtual ~List()
{
if (!PlainOldData) {
// Make sure to call destructors of old objects.
_Resize(0);
}
free(fItems);
}
SelfType& operator=(const SelfType& other)
{
if (this == &other)
return *this;
if (PlainOldData) {
if (_Resize(other.fCount))
memcpy(fItems, other.fItems, fCount * sizeof(ItemType));
} else {
// Make sure to call destructors of old objects.
// NOTE: Another option would be to use
// ItemType::operator=(const ItemType& other), but then
// we would need to be carefull which objects are already
// initialized. Also the ItemType requires to implement the
// operator, while doing it this way requires only a copy
// constructor.
_Resize(0);
for (uint32 i = 0; i < other.fCount; i++) {
if (!Add(other.ItemAtFast(i)))
break;
}
}
return *this;
}
bool operator==(const SelfType& other) const
{
if (this == &other)
return true;
if (fCount != other.fCount)
return false;
if (fCount == 0)
return true;
if (PlainOldData) {
return memcmp(fItems, other.fItems,
fCount * sizeof(ItemType)) == 0;
} else {
for (uint32 i = 0; i < other.fCount; i++) {
if (ItemAtFast(i) != other.ItemAtFast(i))
return false;
}
}
return true;
}
bool operator!=(const SelfType& other) const
{
return !(*this == other);
}
inline void Clear()
{
_Resize(0);
}
inline int32 CountItems() const
{
return fCount;
}
inline bool Add(const ItemType& copyFrom)
{
if (_Resize(fCount + 1)) {
ItemType* item = fItems + fCount - 1;
// Initialize the new object from the original.
if (!PlainOldData)
new (item) ItemType(copyFrom);
else
*item = copyFrom;
return true;
}
return false;
}
inline void Remove()
{
if (fCount > 0)
_Resize(fCount - 1);
}
inline void Remove(int32 index)
{
if (index < 0 || index >= (int32)fCount)
return;
if (!PlainOldData) {
ItemType* object = fItems + index;
object->~ItemType();
}
int32 nextIndex = index + 1;
if ((int32)fCount > nextIndex)
memcpy(fItems + index, fItems + nextIndex,
(fCount - nextIndex) * sizeof(ItemType));
fCount--;
}
inline const ItemType& ItemAt(int32 index) const
{
if (index >= (int32)fCount)
return fNullItem;
return ItemAtFast(index);
}
inline const ItemType& ItemAtFast(int32 index) const
{
return *(fItems + index);
}
inline const ItemType& LastItem() const
{
return ItemAt((int32)fCount - 1);
}
private:
inline bool _Resize(uint32 count)
{
if (count > fAllocatedCount) {
uint32 allocationCount = (count + BlockSize - 1)
/ BlockSize * BlockSize;
ItemType* items = reinterpret_cast<ItemType*>(
realloc(fItems, allocationCount * sizeof(ItemType)));
if (items == NULL)
return false;
fItems = items;
fAllocatedCount = allocationCount;
} else if (count < fCount) {
if (!PlainOldData) {
// Uninit old objects so that we can re-use them when
// appending objects without the need to re-allocate.
for (uint32 i = count; i < fCount; i++) {
ItemType* object = fItems + i;
object->~ItemType();
}
}
}
fCount = count;
return true;
}
ItemType* fItems;
ItemType fNullItem;
uint32 fCount;
uint32 fAllocatedCount;
};
#endif // LIST_H