/*****************************************************************
|
| AP4 - Lists
|
| Copyright 2002 Gilles Boccon-Gibod
|
|
| This file is part of Bento4/AP4 (MP4 Atom Processing Library).
|
| Unless you have obtained Bento4 under a difference license,
| this version of Bento4 is Bento4|GPL.
| Bento4|GPL is free software; you can redistribute it and/or modify
| it under the terms of the GNU General Public License as published by
| the Free Software Foundation; either version 2, or (at your option)
| any later version.
|
| Bento4|GPL is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
| GNU General Public License for more details.
|
| You should have received a copy of the GNU General Public License
| along with Bento4|GPL; see the file COPYING. If not, write to the
| Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
| 02111-1307, USA.
|
****************************************************************/
#ifndef _AP4_LIST_H_
#define _AP4_LIST_H_
/*----------------------------------------------------------------------
| includes
+---------------------------------------------------------------------*/
#include "Ap4.h"
#include "Ap4Results.h"
/*----------------------------------------------------------------------
| forward references
+---------------------------------------------------------------------*/
template <typename T> class AP4_List;
/*----------------------------------------------------------------------
| AP4_List
+---------------------------------------------------------------------*/
template <typename T>
class AP4_List
{
public:
// types
class Item
{
public:
// types
class Operator
{
public:
// methods
virtual ~Operator() {}
virtual AP4_Result Action(T* data) const = 0;
};
class Finder
{
public:
// methods
virtual ~Finder() {}
virtual AP4_Result Test(T* data) const = 0;
};
// methods
Item(T* data) : m_Data(data), m_Next(0), m_Prev(0) {}
~Item() {}
Item* GetNext() { return m_Next; }
Item* GetPrev() { return m_Prev; }
T* GetData() { return m_Data; }
private:
// members
T* m_Data;
Item* m_Next;
Item* m_Prev;
// friends
friend class AP4_List;
};
// methods
AP4_List<T>(): m_ItemCount(0), m_Head(0), m_Tail(0) {}
virtual ~AP4_List<T>();
AP4_Result Add(T* data);
AP4_Result Add(Item* item);
AP4_Result Remove(T* data);
AP4_Result Insert(Item* where, T* data);
AP4_Result Get(AP4_Ordinal idx, T*& data);
AP4_Result PopHead(T*& data);
AP4_Result Apply(const typename Item::Operator& op);
AP4_Result ApplyUntilFailure(const typename Item::Operator& op);
AP4_Result ApplyUntilSuccess(const typename Item::Operator& op);
AP4_Result ReverseApply(const typename Item::Operator& op);
AP4_Result Find(const typename Item::Finder& finder, T*& data);
AP4_Result ReverseFind(const typename Item::Finder& finder, T*& data);
AP4_Result DeleteReferences();
AP4_Cardinal ItemCount() { return m_ItemCount; }
Item* FirstItem() { return m_Head; }
Item* LastItem() { return m_Tail; }
protected:
// members
AP4_Cardinal m_ItemCount;
Item* m_Head;
Item* m_Tail;
private:
// these cannot be used
AP4_List<T>(const AP4_List<T>&);
AP4_List<T>& operator=(const AP4_List<T>&);
};
/*----------------------------------------------------------------------
| AP4_List<T>::~AP4_List<T>
+---------------------------------------------------------------------*/
template <typename T>
AP4_List<T>::~AP4_List()
{
Item* item = m_Head;
while (item) {
Item* next = item->m_Next;
delete item;
item = next;
}
}
/*----------------------------------------------------------------------
| AP4_List<T>::Add
+---------------------------------------------------------------------*/
template <typename T>
inline
AP4_Result
AP4_List<T>::Add(T* data)
{
return Add(new Item(data));
}
/*----------------------------------------------------------------------
| AP4_List<T>::Add
+---------------------------------------------------------------------*/
template <typename T>
AP4_Result
AP4_List<T>::Add(Item* item)
{
// add element at the tail
if (m_Tail) {
item->m_Prev = m_Tail;
item->m_Next = NULL;
m_Tail->m_Next = item;
m_Tail = item;
} else {
m_Head = item;
m_Tail = item;
item->m_Next = NULL;
item->m_Prev = NULL;
}
// one more item in the list now
m_ItemCount++;
return AP4_SUCCESS;
}
/*----------------------------------------------------------------------
| AP4_List<T>::Remove
+---------------------------------------------------------------------*/
template <typename T>
AP4_Result
AP4_List<T>::Remove(T* data)
{
Item* item = m_Head;
while (item) {
if (item->m_Data == data) {
// delete item
if (item->m_Prev) {
// item is not the head
if (item->m_Next) {
// item is not the tail
item->m_Next->m_Prev = item->m_Prev;
item->m_Prev->m_Next = item->m_Next;
} else {
// item is the tail
m_Tail = item->m_Prev;
m_Tail->m_Next = NULL;
}
} else {
// item is the head
m_Head = item->m_Next;
if (m_Head) {
// item is not the tail
m_Head->m_Prev = NULL;
} else {
// item is also the tail
m_Tail = NULL;
}
}
// delete the item
delete item;
// one less item in the list now
m_ItemCount--;
return AP4_SUCCESS;
}
item = item->m_Next;
}
return AP4_ERROR_NO_SUCH_ITEM;
}
/*----------------------------------------------------------------------
| AP4_List<T>::Insert
+---------------------------------------------------------------------*/
template <typename T>
AP4_Result
AP4_List<T>::Insert(Item* where, T* data)
{
Item* item = new Item(data);
if (where == NULL) {
// insert as the head
if (m_Head) {
// replace the current head
item->m_Prev = NULL;
item->m_Next = m_Head;
m_Head->m_Prev = item;
m_Head = item;
} else {
// this item becomes the head and tail
m_Head = item;
m_Tail = item;
item->m_Next = NULL;
item->m_Prev = NULL;
}
} else {
// insert after the 'where' item
if (where == m_Tail) {
// add the item at the end
return Add(item);
} else {
// update the links
item->m_Prev = where;
item->m_Next = where->m_Next;
where->m_Next->m_Prev = item;
where->m_Next = item;
}
}
// one more item in the list now
++m_ItemCount;
return AP4_SUCCESS;
}
/*----------------------------------------------------------------------
| AP4_List<T>::Get
+---------------------------------------------------------------------*/
template <typename T>
AP4_Result
AP4_List<T>::Get(AP4_Ordinal idx, T*& data)
{
Item* item = m_Head;
if (idx < m_ItemCount) {
while (idx--) item = item->m_Next;
data = item->m_Data;
return AP4_SUCCESS;
} else {
data = NULL;
return AP4_ERROR_NO_SUCH_ITEM;
}
}
/*----------------------------------------------------------------------
| AP4_List<T>::PopHead
+---------------------------------------------------------------------*/
template <typename T>
AP4_Result
AP4_List<T>::PopHead(T*& data)
{
// check that we have at least one item
if (m_Head == NULL) {
return AP4_ERROR_LIST_EMPTY;
}
// remove the item and return it
data = m_Head->m_Data;
Item* head = m_Head;
m_Head = m_Head->m_Next;
if (m_Head) {
m_Head->m_Prev = NULL;
} else {
m_Tail = NULL;
}
// delete item
delete head;
// one less item in the list now
m_ItemCount--;
return AP4_SUCCESS;
}
/*----------------------------------------------------------------------
| AP4_List<T>::Apply
+---------------------------------------------------------------------*/
template <typename T>
inline
AP4_Result
AP4_List<T>::Apply(const typename Item::Operator& op)
{
Item* item = m_Head;
while (item) {
op.Action(item->m_Data);
item = item->m_Next;
}
return AP4_SUCCESS;
}
/*----------------------------------------------------------------------
| AP4_List<T>::ApplyUntilFailure
+---------------------------------------------------------------------*/
template <typename T>
inline
AP4_Result
AP4_List<T>::ApplyUntilFailure(const typename Item::Operator& op)
{
Item* item = m_Head;
while (item) {
AP4_Result result;
result = op.Action(item->m_Data);
if (result != AP4_SUCCESS) return result;
item = item->m_Next;
}
return AP4_SUCCESS;
}
/*----------------------------------------------------------------------
| AP4_List<T>::ApplyUntilSuccess
+---------------------------------------------------------------------*/
template <typename T>
inline
AP4_Result
AP4_List<T>::ApplyUntilSuccess(const typename Item::Operator& op)
{
Item* item = m_Head;
while (item) {
AP4_Result result;
result = op.Action(item->m_Data);
if (result == AP4_SUCCESS) return AP4_SUCCESS;
item = item->m_Next;
}
return AP4_FAILURE;
}
/*----------------------------------------------------------------------
| AP4_List<T>::ReverseApply
+---------------------------------------------------------------------*/
template <typename T>
inline
AP4_Result
AP4_List<T>::ReverseApply(const typename Item::Operator& op)
{
Item* item = m_Tail;
while (item) {
if (op.Action(item->m_Data) != AP4_SUCCESS) {
return AP4_ERROR_LIST_OPERATION_ABORTED;
}
item = item->m_Prev;
}
return AP4_SUCCESS;
}
/*----------------------------------------------------------------------
| AP4_List<T>::Find
+---------------------------------------------------------------------*/
template <typename T>
inline
AP4_Result
AP4_List<T>::Find(const typename Item::Finder& finder, T*& data)
{
Item* item = m_Head;
while (item) {
if (finder.Test(item->m_Data) == AP4_SUCCESS) {
data = item->m_Data;
return AP4_SUCCESS;
}
item = item->m_Next;
}
data = NULL;
return AP4_ERROR_NO_SUCH_ITEM;
}
/*----------------------------------------------------------------------
| AP4_List<T>::ReverseFind
+---------------------------------------------------------------------*/
template <typename T>
inline
AP4_Result
AP4_List<T>::ReverseFind(const typename Item::Finder& finder, T*& data)
{
Item* item = m_Tail;
while (item) {
if (finder.Test(item->m_Data) == AP4_SUCCESS) {
data = item->m_Data;
return AP4_SUCCESS;
}
item = item->m_Prev;
}
data = NULL;
return AP4_ERROR_NO_SUCH_ITEM;
}
/*----------------------------------------------------------------------
| AP4_List<T>::DeleteReferences
+---------------------------------------------------------------------*/
template <typename T>
inline
AP4_Result
AP4_List<T>::DeleteReferences()
{
Item* item = m_Head;
while (item) {
Item* next = item->m_Next;
delete item->m_Data;
delete item;
item = next;
}
// no more items
m_Head = m_Tail = NULL;
m_ItemCount = 0;
return AP4_SUCCESS;
}
#endif // _AP4_LIST_H_
↑ V832 It's better to use '= default;' syntax instead of empty destructor body.