mirror of
https://github.com/isledecomp/isle.git
synced 2024-11-29 19:16:05 -05:00
0bb3ea6a03
* MxList refactor * Reorder LegoPathControllerList::Destroy * MxPtrList custom destructor and more offsets Co-authored-by: Christian Semmler <mail@csemmler.com> * Fix member offset comments in collection classes * Fix template annotations --------- Co-authored-by: Christian Semmler <mail@csemmler.com>
251 lines
4.7 KiB
C++
251 lines
4.7 KiB
C++
#ifndef MXLIST_H
|
|
#define MXLIST_H
|
|
|
|
#include "mxcollection.h"
|
|
#include "mxcore.h"
|
|
#include "mxtypes.h"
|
|
|
|
template <class T>
|
|
class MxList;
|
|
template <class T>
|
|
class MxListCursor;
|
|
|
|
template <class T>
|
|
class MxPtrList : public MxList<T*> {
|
|
public:
|
|
MxPtrList(void (*p_destroy)(T*) = Destroy) { m_customDestructor = p_destroy; }
|
|
};
|
|
|
|
template <class T>
|
|
class MxListEntry {
|
|
public:
|
|
MxListEntry() {}
|
|
MxListEntry(T p_obj, MxListEntry* p_prev)
|
|
{
|
|
m_obj = p_obj;
|
|
m_prev = p_prev;
|
|
m_next = NULL;
|
|
}
|
|
MxListEntry(T p_obj, MxListEntry* p_prev, MxListEntry* p_next)
|
|
{
|
|
m_obj = p_obj;
|
|
m_prev = p_prev;
|
|
m_next = p_next;
|
|
}
|
|
|
|
T GetValue() { return this->m_obj; }
|
|
MxListEntry* GetNext() { return m_next; }
|
|
MxListEntry* GetPrev() { return m_prev; }
|
|
|
|
void SetValue(T p_obj) { m_obj = p_obj; }
|
|
void SetNext(MxListEntry* p_next) { m_next = p_next; }
|
|
void SetPrev(MxListEntry* p_prev) { m_prev = p_prev; }
|
|
|
|
private:
|
|
T m_obj;
|
|
MxListEntry* m_prev;
|
|
MxListEntry* m_next;
|
|
};
|
|
|
|
// SIZE 0x18
|
|
template <class T>
|
|
class MxList : protected MxCollection<T> {
|
|
public:
|
|
MxList()
|
|
{
|
|
m_last = NULL;
|
|
m_first = NULL;
|
|
}
|
|
|
|
virtual ~MxList() override;
|
|
|
|
void Append(T p_obj) { _InsertEntry(p_obj, this->m_last, NULL); };
|
|
void DeleteAll();
|
|
MxU32 GetCount() { return this->m_count; }
|
|
void SetDestroy(void (*p_customDestructor)(T)) { this->m_customDestructor = p_customDestructor; }
|
|
|
|
friend class MxListCursor<T>;
|
|
|
|
protected:
|
|
MxListEntry<T>* m_first; // 0x10
|
|
MxListEntry<T>* m_last; // 0x14
|
|
|
|
void _DeleteEntry(MxListEntry<T>* match);
|
|
MxListEntry<T>* _InsertEntry(T, MxListEntry<T>*, MxListEntry<T>*);
|
|
};
|
|
|
|
template <class T>
|
|
class MxListCursor : public MxCore {
|
|
public:
|
|
MxListCursor(MxList<T>* p_list)
|
|
{
|
|
m_list = p_list;
|
|
m_match = NULL;
|
|
}
|
|
|
|
MxBool Find(T p_obj);
|
|
void Detach();
|
|
void Destroy();
|
|
MxBool Next(T& p_obj);
|
|
MxBool Current(T& p_obj);
|
|
MxBool Advance();
|
|
MxBool HasMatch() { return m_match != NULL; }
|
|
void SetValue(T p_obj);
|
|
void Head() { m_match = m_list->m_first; }
|
|
void Reset() { m_match = NULL; }
|
|
void Prepend(T p_newobj);
|
|
|
|
private:
|
|
MxList<T>* m_list;
|
|
MxListEntry<T>* m_match;
|
|
};
|
|
|
|
// Unclear purpose
|
|
template <class T>
|
|
class MxListCursorChild : public MxListCursor<T> {
|
|
public:
|
|
MxListCursorChild(MxList<T>* p_list) : MxListCursor<T>(p_list) {}
|
|
};
|
|
|
|
// Unclear purpose
|
|
template <class T>
|
|
class MxListCursorChildChild : public MxListCursorChild<T> {
|
|
public:
|
|
MxListCursorChildChild(MxList<T>* p_list) : MxListCursorChild<T>(p_list) {}
|
|
};
|
|
|
|
template <class T>
|
|
MxList<T>::~MxList()
|
|
{
|
|
DeleteAll();
|
|
}
|
|
|
|
template <class T>
|
|
inline void MxList<T>::DeleteAll()
|
|
{
|
|
for (MxListEntry<T>* t = m_first;;) {
|
|
if (!t)
|
|
break;
|
|
|
|
MxListEntry<T>* next = t->GetNext();
|
|
this->m_customDestructor(t->GetValue());
|
|
delete t;
|
|
t = next;
|
|
}
|
|
|
|
this->m_count = 0;
|
|
m_last = NULL;
|
|
m_first = NULL;
|
|
}
|
|
|
|
template <class T>
|
|
inline MxListEntry<T>* MxList<T>::_InsertEntry(T p_newobj, MxListEntry<T>* p_prev, MxListEntry<T>* p_next)
|
|
{
|
|
MxListEntry<T>* newEntry = new MxListEntry<T>(p_newobj, p_prev, p_next);
|
|
|
|
if (p_prev)
|
|
p_prev->SetNext(newEntry);
|
|
else
|
|
this->m_first = newEntry;
|
|
|
|
if (p_next)
|
|
p_next->SetPrev(newEntry);
|
|
else
|
|
this->m_last = newEntry;
|
|
|
|
this->m_count++;
|
|
return newEntry;
|
|
}
|
|
|
|
template <class T>
|
|
inline void MxList<T>::_DeleteEntry(MxListEntry<T>* match)
|
|
{
|
|
if (match->GetPrev())
|
|
match->GetPrev()->SetNext(match->GetNext());
|
|
else
|
|
m_first = match->GetNext();
|
|
|
|
if (match->GetNext())
|
|
match->GetNext()->SetPrev(match->GetPrev());
|
|
else
|
|
m_last = match->GetPrev();
|
|
|
|
delete match;
|
|
this->m_count--;
|
|
}
|
|
|
|
template <class T>
|
|
inline MxBool MxListCursor<T>::Find(T p_obj)
|
|
{
|
|
for (m_match = m_list->m_first; m_match && m_list->Compare(m_match->GetValue(), p_obj);
|
|
m_match = m_match->GetNext())
|
|
;
|
|
|
|
return m_match != NULL;
|
|
}
|
|
|
|
template <class T>
|
|
inline void MxListCursor<T>::Detach()
|
|
{
|
|
m_list->_DeleteEntry(m_match);
|
|
m_match = NULL;
|
|
}
|
|
|
|
template <class T>
|
|
inline void MxListCursor<T>::Destroy()
|
|
{
|
|
if (m_match) {
|
|
m_list->m_customDestructor(m_match->GetValue());
|
|
Detach();
|
|
}
|
|
}
|
|
|
|
template <class T>
|
|
inline MxBool MxListCursor<T>::Next(T& p_obj)
|
|
{
|
|
if (!m_match)
|
|
m_match = m_list->m_first;
|
|
else
|
|
m_match = m_match->GetNext();
|
|
|
|
if (m_match)
|
|
p_obj = m_match->GetValue();
|
|
|
|
return m_match != NULL;
|
|
}
|
|
|
|
template <class T>
|
|
inline MxBool MxListCursor<T>::Current(T& p_obj)
|
|
{
|
|
if (m_match)
|
|
p_obj = m_match->GetValue();
|
|
|
|
return m_match != NULL;
|
|
}
|
|
|
|
template <class T>
|
|
inline MxBool MxListCursor<T>::Advance()
|
|
{
|
|
if (!m_match)
|
|
m_match = m_list->m_first;
|
|
else
|
|
m_match = m_match->GetNext();
|
|
|
|
return m_match != NULL;
|
|
}
|
|
|
|
template <class T>
|
|
inline void MxListCursor<T>::SetValue(T p_obj)
|
|
{
|
|
if (m_match)
|
|
m_match->SetValue(p_obj);
|
|
}
|
|
|
|
template <class T>
|
|
inline void MxListCursor<T>::Prepend(T p_newobj)
|
|
{
|
|
if (m_match)
|
|
m_list->_InsertEntry(p_newobj, m_match->GetPrev(), m_match);
|
|
}
|
|
|
|
#endif // MXLIST_H
|