Skip to content

Commit

Permalink
Optimize: O(1) index lookup of map elements in a list
Browse files Browse the repository at this point in the history
There was a big performance bottleneck with MapElementList, where
indexOf() was being used to look up indices in O(n) time.
  • Loading branch information
skyjake committed Mar 22, 2013
1 parent eab7868 commit 196b53b
Showing 1 changed file with 52 additions and 11 deletions.
63 changes: 52 additions & 11 deletions doomsday/client/include/map/mapelement.h
Expand Up @@ -44,7 +44,11 @@ namespace de {
class MapElement
{
public:
MapElement(int t = DMU_NONE) : _type(t) {}
enum { NoIndex = -1 };

public:
MapElement(int t = DMU_NONE)
: _type(t), _indexInList(NoIndex) {}

virtual ~MapElement() {}

Expand All @@ -53,6 +57,16 @@ class MapElement
return _type;
}

int indexInList() const
{
return _indexInList;
}

void setIndexInList(int idx = NoIndex)
{
_indexInList = idx;
}

template <typename Type>
inline Type *castTo()
{
Expand All @@ -69,17 +83,30 @@ class MapElement
return t;
}

MapElement &operator = (MapElement const &other)
{
_type = other._type;
// We retain our current index in the list.
return *this;
}

private:
int _type;
int _indexInList;
};

/**
* Collection of owned map elements with type @a Type.
* Collection of owned map elements with type @a Type. The template argument
* @a Type must be a class derived from MapElement.
*
* The base class is protected because MapElement instances remember their
* indices: all access to the list must occur through this class's public
* interface so that the indices can be maintained appropriately.
*/
template <typename Type>
class MapElementList : public QList<MapElement *>
class MapElementList : protected QList<MapElement *>
{
typedef QList<MapElement *> Super;
typedef QList<MapElement *> Base;

public:
MapElementList() {}
Expand All @@ -92,41 +119,55 @@ class MapElementList : public QList<MapElement *>
clear();
}

int size() const
{
return Base::size();
}

void clear()
{
// Delete all the objects.
for(iterator i = begin(); i != end(); ++i)
{
delete *i;
}
Super::clear();
Base::clear();
}

void clearAndResize(int count)
{
clear();
while(count-- > 0)
{
append(new Type);
Type *t = new Type;
t->setIndexInList(size());
append(t);
}
}

int indexOf(Type const *t, int from = 0) const
/**
* Looks up the index of an element in the list. Complexity: O(1).
*
* @param t Element. Must be in the list.
*
* @return Index of the element @a t.
*/
int indexOf(Type const *t) const
{
// Note: Bad performance!
return Super::indexOf(const_cast<Type *>(t), from);
//DENG2_ASSERT(Base::indexOf(const_cast<Type *>(t)) == t->indexInList());
return t->indexInList();
}

Type &operator [] (int index)
{
DENG_ASSERT(dynamic_cast<Type *>(at(index)) != 0);
return *static_cast<Type *>(Super::at(index));
return *static_cast<Type *>(Base::at(index));
}

Type const &operator [] (int index) const
{
DENG_ASSERT(dynamic_cast<Type const *>(at(index)) != 0);
return *static_cast<Type const *>(Super::at(index));
return *static_cast<Type const *>(Base::at(index));
}
};

Expand Down

0 comments on commit 196b53b

Please sign in to comment.