blob: 850543786c4743055dc457defd3fee4bfb5132fe [file] [log] [blame]
// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#ifndef _FX_UTILS
#define _FX_UTILS
class CFX_ThreadLock;
class CFX_BaseArray;
template<class baseType> class CFX_BaseArrayTemplate;
template<class baseType> class CFX_ObjectBaseArrayTemplate;
class CFX_BaseMassArray;
class CFX_BaseMassArrayImp;
template<class baseType> class CFX_MassArrayTemplate;
template<class baseType> class CFX_ObjectMassArrayTemplate;
class CFX_BaseDiscreteArray;
template<class baseType> class CFX_DiscreteArrayTemplate;
class CFX_BaseStack;
template<class baseType> class CFX_StackTemplate;
template<class baseType> class CFX_ObjectStackTemplate;
template<class baseType> class CFX_CPLTreeNode;
template<class baseType> class CFX_CPLTree;
class CFX_ThreadLock
{
public:
CFX_ThreadLock();
virtual ~CFX_ThreadLock();
void Lock();
void Unlock();
private:
FX_LPVOID m_pData;
};
class CFX_BaseArray : public CFX_Target
{
protected:
CFX_BaseArray(FX_INT32 iGrowSize, FX_INT32 iBlockSize);
~CFX_BaseArray();
FX_INT32 GetSize() const;
FX_INT32 GetBlockSize() const;
FX_LPBYTE AddSpaceTo(FX_INT32 index);
FX_LPBYTE GetAt(FX_INT32 index) const;
FX_LPBYTE GetBuffer() const;
FX_INT32 Append(const CFX_BaseArray &src, FX_INT32 iStart = 0, FX_INT32 iCount = -1);
FX_INT32 Copy(const CFX_BaseArray &src, FX_INT32 iStart = 0, FX_INT32 iCount = -1);
FX_INT32 RemoveLast(FX_INT32 iCount = -1);
void RemoveAll(FX_BOOL bLeaveMemory = FALSE);
FX_LPVOID m_pData;
};
template<class baseType>
class CFX_BaseArrayTemplate : public CFX_BaseArray
{
public:
CFX_BaseArrayTemplate(FX_INT32 iGrowSize = 100) : CFX_BaseArray(iGrowSize, sizeof(baseType)) {}
CFX_BaseArrayTemplate(FX_INT32 iGrowSize, FX_INT32 iBlockSize) : CFX_BaseArray(iGrowSize, iBlockSize) {}
FX_INT32 GetSize() const
{
return CFX_BaseArray::GetSize();
}
FX_INT32 GetBlockSize() const
{
return CFX_BaseArray::GetBlockSize();
}
baseType* AddSpace()
{
return (baseType*)CFX_BaseArray::AddSpaceTo(CFX_BaseArray::GetSize());
}
FX_INT32 Add(const baseType &element)
{
FX_INT32 index = CFX_BaseArray::GetSize();
*(baseType*)CFX_BaseArray::AddSpaceTo(index) = element;
return index;
}
baseType* GetBuffer() const
{
return (baseType*)CFX_BaseArray::GetBuffer();
}
baseType& GetAt(FX_INT32 index) const
{
return *(baseType*)CFX_BaseArray::GetAt(index);
}
baseType* GetPtrAt(FX_INT32 index) const
{
return (baseType*)CFX_BaseArray::GetAt(index);
}
void SetAt(FX_INT32 index, const baseType &element)
{
*(baseType*)CFX_BaseArray::GetAt(index) = element;
}
void SetAtGrow(FX_INT32 index, const baseType &element)
{
*(baseType*)CFX_BaseArray::AddSpaceTo(index) = element;
}
FX_INT32 Append(const CFX_BaseArrayTemplate &src, FX_INT32 iStart = 0, FX_INT32 iCount = -1)
{
return CFX_BaseArray::Append(src, iStart, iCount);
}
FX_INT32 Copy(const CFX_BaseArrayTemplate &src, FX_INT32 iStart = 0, FX_INT32 iCount = -1)
{
return CFX_BaseArray::Copy(src, iStart, iCount);
}
FX_INT32 RemoveLast(FX_INT32 iCount = -1)
{
return CFX_BaseArray::RemoveLast(iCount);
}
void RemoveAll(FX_BOOL bLeaveMemory = FALSE)
{
CFX_BaseArray::RemoveAll(bLeaveMemory);
}
};
typedef CFX_BaseArrayTemplate<FX_LPVOID> CFDE_PtrArray;
typedef CFX_BaseArrayTemplate<FX_DWORD> CFDE_DWordArray;
typedef CFX_BaseArrayTemplate<FX_WORD> CFDE_WordArray;
template<class baseType>
class CFX_ObjectBaseArrayTemplate : public CFX_BaseArray
{
public:
CFX_ObjectBaseArrayTemplate(FX_INT32 iGrowSize = 100) : CFX_BaseArray(iGrowSize, sizeof(baseType)) {}
~CFX_ObjectBaseArrayTemplate()
{
RemoveAll(FALSE);
}
FX_INT32 GetSize() const
{
return CFX_BaseArray::GetSize();
}
FX_INT32 GetBlockSize() const
{
return CFX_BaseArray::GetBlockSize();
}
FX_INT32 Add(const baseType &element)
{
FX_INT32 index = CFX_BaseArray::GetSize();
baseType *p = (baseType*)CFX_BaseArray::AddSpaceTo(index);
FXTARGET_New ((void*)p)baseType(element);
return index;
}
baseType& GetAt(FX_INT32 index) const
{
return *(baseType*)CFX_BaseArray::GetAt(index);
}
baseType* GetPtrAt(FX_INT32 index) const
{
return (baseType*)CFX_BaseArray::GetAt(index);
}
FX_INT32 Append(const CFX_ObjectBaseArrayTemplate &src, FX_INT32 iStart = 0, FX_INT32 iCount = -1)
{
FXSYS_assert(GetBlockSize() == src.GetBlockSize());
if (iCount == 0) {
return 0;
}
FX_INT32 iSize = src.GetSize();
FXSYS_assert(iStart > -1 && iStart < iSize);
if (iCount < 0) {
iCount = iSize;
}
if (iStart + iCount > iSize) {
iCount = iSize - iStart;
}
if (iCount < 1) {
return 0;
}
iSize = CFX_BaseArray::GetSize();
CFX_BaseArray::AddSpaceTo(iSize + iCount - 1);
FX_LPBYTE *pStart = CFX_BaseArray::GetAt(iSize);
FX_INT32 iBlockSize = CFX_BaseArray::GetBlockSize();
iSize = iStart + iCount;
for (FX_INT32 i = iStart; i < iSize; i ++) {
FXTARGET_NewWith ((void*)pStart)baseType(src.GetAt(i));
pStart += iBlockSize;
}
return iCount;
}
FX_INT32 Copy(const CFX_ObjectBaseArrayTemplate &src, FX_INT32 iStart = 0, FX_INT32 iCount = -1)
{
FXSYS_assert(GetBlockSize() == src.GetBlockSize());
if (iCount == 0) {
return 0;
}
FX_INT32 iSize = src.GetSize();
FXSYS_assert(iStart > -1 && iStart < iSize);
if (iCount < 0) {
iCount = iSize;
}
if (iStart + iCount > iSize) {
iCount = iSize - iStart;
}
if (iCount < 1) {
return 0;
}
RemoveAll(TRUE);
CFX_BaseArray::AddSpaceTo(iCount - 1);
FX_LPBYTE *pStart = CFX_BaseArray::GetAt(0);
FX_INT32 iBlockSize = CFX_BaseArray::GetBlockSize();
iSize = iStart + iCount;
for (FX_INT32 i = iStart; i < iSize; i ++) {
FXTARGET_New ((void*)pStart)baseType(src.GetAt(i));
pStart += iBlockSize;
}
return iCount;
}
FX_INT32 RemoveLast(FX_INT32 iCount = -1)
{
FX_INT32 iSize = CFX_BaseArray::GetSize();
if (iCount < 0 || iCount > iSize) {
iCount = iSize;
}
if (iCount == 0) {
return iSize;
}
for (FX_INT32 i = iSize - iCount; i < iSize; i ++) {
((baseType*)GetPtrAt(i))->~baseType();
}
return CFX_BaseArray::RemoveLast(iCount);
}
void RemoveAll(FX_BOOL bLeaveMemory = FALSE)
{
FX_INT32 iSize = CFX_BaseArray::GetSize();
for (FX_INT32 i = 0; i < iSize; i ++) {
((baseType*)GetPtrAt(i))->~baseType();
}
CFX_BaseArray::RemoveAll(bLeaveMemory);
}
};
class CFX_BaseMassArray : public CFX_Target
{
protected:
CFX_BaseMassArray(FX_INT32 iChunkSize, FX_INT32 iBlockSize);
~CFX_BaseMassArray();
FX_INT32 GetSize() const;
FX_LPBYTE AddSpaceTo(FX_INT32 index);
FX_LPBYTE GetAt(FX_INT32 index) const;
FX_INT32 Append(const CFX_BaseMassArray &src, FX_INT32 iStart = 0, FX_INT32 iCount = -1);
FX_INT32 Copy(const CFX_BaseMassArray &src, FX_INT32 iStart = 0, FX_INT32 iCount = -1);
FX_INT32 RemoveLast(FX_INT32 iCount = -1);
void RemoveAll(FX_BOOL bLeaveMemory = FALSE);
CFX_BaseMassArrayImp* m_pData;
};
template<class baseType>
class CFX_MassArrayTemplate : public CFX_BaseMassArray
{
public:
CFX_MassArrayTemplate(FX_INT32 iChunkSize = 100) : CFX_BaseMassArray(iChunkSize, sizeof(baseType)) {}
CFX_MassArrayTemplate(FX_INT32 iChunkSize, FX_INT32 iBlockSize) : CFX_BaseMassArray(iChunkSize, iBlockSize) {}
FX_INT32 GetSize() const
{
return CFX_BaseMassArray::GetSize();
}
baseType* AddSpace()
{
return (baseType*)CFX_BaseMassArray::AddSpaceTo(CFX_BaseMassArray::GetSize());
}
FX_INT32 Add(const baseType &element)
{
FX_INT32 index = CFX_BaseMassArray::GetSize();
*(baseType*)CFX_BaseMassArray::AddSpaceTo(index) = element;
return index;
}
baseType& GetAt(FX_INT32 index) const
{
return *(baseType*)CFX_BaseMassArray::GetAt(index);
}
baseType* GetPtrAt(FX_INT32 index) const
{
return (baseType*)CFX_BaseMassArray::GetAt(index);
}
void SetAt(FX_INT32 index, const baseType &element)
{
*(baseType*)CFX_BaseMassArray::GetAt(index) = element;
}
void SetAtGrow(FX_INT32 index, const baseType &element)
{
*(baseType*)CFX_BaseMassArray::AddSpaceTo(index) = element;
}
FX_INT32 Append(const CFX_MassArrayTemplate &src, FX_INT32 iStart = 0, FX_INT32 iCount = -1)
{
return CFX_BaseMassArray::Append(src, iStart, iCount);
}
FX_INT32 Copy(const CFX_MassArrayTemplate &src, FX_INT32 iStart = 0, FX_INT32 iCount = -1)
{
return CFX_BaseMassArray::Copy(src, iStart, iCount);
}
FX_INT32 RemoveLast(FX_INT32 iCount = -1)
{
return CFX_BaseMassArray::RemoveLast(iCount);
}
void RemoveAll(FX_BOOL bLeaveMemory = FALSE)
{
CFX_BaseMassArray::RemoveAll(bLeaveMemory);
}
};
typedef CFX_MassArrayTemplate<FX_LPVOID> CFX_PtrMassArray;
typedef CFX_MassArrayTemplate<FX_INT32> CFX_Int32MassArray;
typedef CFX_MassArrayTemplate<FX_DWORD> CFX_DWordMassArray;
typedef CFX_MassArrayTemplate<FX_WORD> CFX_WordMassArray;
typedef CFX_MassArrayTemplate<CFX_Rect> CFX_RectMassArray;
typedef CFX_MassArrayTemplate<CFX_RectF> CFX_RectFMassArray;
template<class baseType>
class CFX_ObjectMassArrayTemplate : public CFX_BaseMassArray
{
public:
CFX_ObjectMassArrayTemplate(FX_INT32 iChunkSize = 100) : CFX_BaseMassArray(iChunkSize, sizeof(baseType)) {}
~CFX_ObjectMassArrayTemplate()
{
RemoveAll(FALSE);
}
FX_INT32 GetSize() const
{
return CFX_BaseMassArray::GetSize();
}
FX_INT32 Add(const baseType &element)
{
FX_INT32 index = CFX_BaseMassArray::GetSize();
baseType *p = (baseType*)CFX_BaseMassArray::AddSpaceTo(index);
FXTARGET_New ((void*)p)baseType(element);
return index;
}
baseType& GetAt(FX_INT32 index) const
{
return *(baseType*)CFX_BaseMassArray::GetAt(index);
}
baseType* GetPtrAt(FX_INT32 index) const
{
return (baseType*)CFX_BaseMassArray::GetAt(index);
}
FX_INT32 Append(const CFX_ObjectMassArrayTemplate &src, FX_INT32 iStart = 0, FX_INT32 iCount = -1)
{
if (iCount == 0) {
return CFX_BaseMassArray::GetSize();
}
FX_INT32 iSize = src.GetSize();
FXSYS_assert(iStart > -1 && iStart < iSize);
if (iCount < 0) {
iCount = iSize;
}
FX_INT32 iEnd = iStart + iCount;
if (iEnd > iSize) {
iEnd = iSize;
}
for (FX_INT32 i = iStart; i < iEnd; i ++) {
Add(src.GetAt(i));
}
return CFX_BaseMassArray::GetSize();
}
FX_INT32 Copy(const CFX_ObjectMassArrayTemplate &src, FX_INT32 iStart = 0, FX_INT32 iCount = -1)
{
if (iCount == 0) {
return CFX_BaseMassArray::GetSize();
}
FX_INT32 iSize = src.GetSize();
FXSYS_assert(iStart > -1 && iStart < iSize);
if (iCount < 0) {
iCount = iSize;
}
FX_INT32 iEnd = iStart + iCount;
if (iEnd > iSize) {
iEnd = iSize;
}
RemoveAll(TRUE);
for (FX_INT32 i = iStart; i < iEnd; i ++) {
Add(src.GetAt(i));
}
return CFX_BaseMassArray::GetSize();
}
FX_INT32 RemoveLast(FX_INT32 iCount = -1)
{
FX_INT32 iSize = CFX_BaseMassArray::GetSize();
if (iCount < 0 || iCount > iSize) {
iCount = iSize;
}
if (iCount == 0) {
return iSize;
}
for (FX_INT32 i = iSize - iCount; i < iSize; i ++) {
((baseType*)GetPtrAt(i))->~baseType();
}
return CFX_BaseMassArray::RemoveLast(iCount);
}
void RemoveAll(FX_BOOL bLeaveMemory = FALSE)
{
FX_INT32 iSize = CFX_BaseMassArray::GetSize();
for (FX_INT32 i = 0; i < iSize; i ++) {
((baseType*)GetPtrAt(i))->~baseType();
}
CFX_BaseMassArray::RemoveAll(bLeaveMemory);
}
};
class CFX_BaseDiscreteArray : public CFX_Target
{
protected:
CFX_BaseDiscreteArray(FX_INT32 iChunkSize, FX_INT32 iBlockSize);
~CFX_BaseDiscreteArray();
FX_LPBYTE AddSpaceTo(FX_INT32 index);
FX_LPBYTE GetAt(FX_INT32 index) const;
void RemoveAll();
FX_LPVOID m_pData;
};
template<class baseType>
class CFX_DiscreteArrayTemplate : public CFX_BaseDiscreteArray
{
public:
CFX_DiscreteArrayTemplate(FX_INT32 iChunkSize = 100) : CFX_BaseDiscreteArray(iChunkSize, sizeof(baseType)) {}
baseType& GetAt(FX_INT32 index, const baseType &defValue) const
{
baseType *p = (baseType*)CFX_BaseDiscreteArray::GetAt(index);
return p == NULL ? (baseType&)defValue : *p;
}
baseType* GetPtrAt(FX_INT32 index) const
{
return (baseType*)CFX_BaseDiscreteArray::GetAt(index);
}
void SetAtGrow(FX_INT32 index, const baseType &element)
{
*(baseType*)CFX_BaseDiscreteArray::AddSpaceTo(index) = element;
}
void RemoveAll()
{
CFX_BaseDiscreteArray::RemoveAll();
}
};
typedef CFX_DiscreteArrayTemplate<FX_LPVOID> CFX_PtrDiscreteArray;
typedef CFX_DiscreteArrayTemplate<FX_DWORD> CFX_DWordDiscreteArray;
typedef CFX_DiscreteArrayTemplate<FX_WORD> CFX_WordDiscreteArray;
class CFX_BaseStack : public CFX_Target
{
protected:
CFX_BaseStack(FX_INT32 iChunkSize, FX_INT32 iBlockSize);
~CFX_BaseStack();
FX_LPBYTE Push();
void Pop();
FX_LPBYTE GetTopElement() const;
FX_INT32 GetSize() const;
FX_LPBYTE GetAt(FX_INT32 index) const;
void RemoveAll(FX_BOOL bLeaveMemory = FALSE);
CFX_BaseMassArrayImp* m_pData;
};
template<class baseType>
class CFX_StackTemplate : public CFX_BaseStack
{
public:
CFX_StackTemplate(FX_INT32 iChunkSize = 100) : CFX_BaseStack(iChunkSize, sizeof(baseType)) {}
FX_INT32 Push(const baseType &element)
{
FX_INT32 index = CFX_BaseStack::GetSize();
*(baseType*)CFX_BaseStack::Push() = element;
return index;
}
void Pop()
{
CFX_BaseStack::Pop();
}
baseType* GetTopElement() const
{
return (baseType*)CFX_BaseStack::GetTopElement();
}
FX_INT32 GetSize() const
{
return CFX_BaseStack::GetSize();
}
baseType* GetAt(FX_INT32 index) const
{
return (baseType*)CFX_BaseStack::GetAt(index);
}
void RemoveAll(FX_BOOL bLeaveMemory = FALSE)
{
CFX_BaseStack::RemoveAll(bLeaveMemory);
}
};
typedef CFX_StackTemplate<FX_LPVOID> CFX_PtrStack;
typedef CFX_StackTemplate<FX_DWORD> CFX_DWordStack;
typedef CFX_StackTemplate<FX_WORD> CFX_WordStack;
typedef CFX_StackTemplate<FX_INT32> CFX_Int32Stack;
template<class baseType>
class CFX_ObjectStackTemplate : public CFX_BaseStack
{
public:
CFX_ObjectStackTemplate(FX_INT32 iChunkSize = 100) : CFX_BaseStack(iChunkSize, sizeof(baseType)) {}
~CFX_ObjectStackTemplate()
{
RemoveAll();
}
FX_INT32 Push(const baseType &element)
{
FX_INT32 index = CFX_BaseStack::GetSize();
baseType *p = (baseType*)CFX_BaseStack::Push();
FXTARGET_New ((void*)p)baseType(element);
return index;
}
void Pop()
{
baseType *p = (baseType*)CFX_BaseStack::GetTopElement();
if (p != NULL) {
p->~baseType();
}
CFX_BaseStack::Pop();
}
baseType* GetTopElement() const
{
return (baseType*)CFX_BaseStack::GetTopElement();
}
FX_INT32 GetSize() const
{
return CFX_BaseStack::GetSize();
}
baseType* GetAt(FX_INT32 index) const
{
return (baseType*)CFX_BaseStack::GetAt(index);
}
void RemoveAll(FX_BOOL bLeaveMemory = FALSE)
{
FX_INT32 iSize = CFX_BaseStack::GetSize();
for (FX_INT32 i = 0; i < iSize; i ++) {
((baseType*)CFX_BaseStack::GetAt(i))->~baseType();
}
CFX_BaseStack::RemoveAll(bLeaveMemory);
}
FX_INT32 Copy(const CFX_ObjectStackTemplate &src, FX_INT32 iStart = 0, FX_INT32 iCount = -1)
{
if (iCount == 0) {
return CFX_BaseStack::GetSize();
}
FX_INT32 iSize = src.GetSize();
FXSYS_assert(iStart > -1 && iStart < iSize);
if (iCount < 0) {
iCount = iSize;
}
FX_INT32 iEnd = iStart + iCount;
if (iEnd > iSize) {
iEnd = iSize;
}
RemoveAll(TRUE);
for (FX_INT32 i = iStart; i < iEnd; i ++) {
Push(*src.GetAt(i));
}
return CFX_BaseStack::GetSize();
}
};
template<class baseType>
class CFX_CPLTreeNode : public CFX_Target
{
public:
typedef CFX_CPLTreeNode<baseType> CPLTreeNode;
CFX_CPLTreeNode() : m_pParentNode(NULL)
, m_pChildNode(NULL)
, m_pPrevNode(NULL)
, m_pNextNode(NULL)
, m_Data()
{
}
enum TreeNode {Root = 0, Parent, FirstSibling, PreviousSibling, NextSibling, LastSibling, FirstNeighbor, PreviousNeighbor, NextNeighbor, LastNeighbor, FirstChild, LastChild};
CPLTreeNode* GetNode(TreeNode eNode) const
{
switch (eNode) {
case Root: {
CPLTreeNode *pParent = (CPLTreeNode*)this;
CPLTreeNode *pTemp;
while ((pTemp = pParent->m_pParentNode) != NULL) {
pParent = pTemp;
}
return pParent;
}
case Parent:
return m_pParentNode;
case FirstSibling: {
CPLTreeNode *pNode = (CPLTreeNode*)this;
CPLTreeNode *pTemp;
while ((pTemp = pNode->m_pPrevNode) != NULL) {
pNode = pTemp;
}
return pNode == (CPLTreeNode*)this ? NULL : pNode;
}
case PreviousSibling:
return m_pPrevNode;
case NextSibling:
return m_pNextNode;
case LastSibling: {
CPLTreeNode *pNode = (CPLTreeNode*)this;
CPLTreeNode *pTemp;
while ((pTemp = pNode->m_pNextNode) != NULL) {
pNode = pTemp;
}
return pNode == (CPLTreeNode*)this ? NULL : pNode;
}
case FirstNeighbor: {
CPLTreeNode *pParent = (CPLTreeNode*)this;
CPLTreeNode *pTemp;
while ((pTemp = pParent->m_pParentNode) != NULL) {
pParent = pTemp;
}
return pParent == (CPLTreeNode*)this ? NULL : pParent;
}
case PreviousNeighbor: {
if (m_pPrevNode == NULL) {
return m_pParentNode;
}
CPLTreeNode *pNode = m_pPrevNode;
CPLTreeNode *pTemp;
while ((pTemp = pNode->m_pChildNode) != NULL) {
pNode = pTemp;
while ((pTemp = pNode->m_pNextNode) != NULL) {
pNode = pTemp;
}
}
return pNode;
}
case NextNeighbor: {
if (m_pChildNode != NULL) {
return m_pChildNode;
}
if (m_pNextNode != NULL) {
return m_pNextNode;
}
CPLTreeNode *pNode = m_pParentNode;
while (pNode != NULL) {
if (pNode->m_pNextNode != NULL) {
return pNode->m_pNextNode;
}
pNode = pNode->m_pParentNode;
}
return NULL;
}
case LastNeighbor: {
CPLTreeNode *pNode = (CPLTreeNode*)this;
CPLTreeNode *pTemp;
while ((pTemp = pNode->m_pParentNode) != NULL) {
pNode = pTemp;
}
while (TRUE) {
CPLTreeNode *pTemp;
while ((pTemp = pNode->m_pNextNode) != NULL) {
pNode = pTemp;
}
if (pNode->m_pChildNode == NULL) {
break;
}
pNode = pNode->m_pChildNode;
}
return pNode == (CPLTreeNode*)this ? NULL : pNode;
}
case FirstChild:
return m_pChildNode;
case LastChild: {
if (m_pChildNode == NULL) {
return NULL;
}
CPLTreeNode *pChild = m_pChildNode;
CPLTreeNode *pTemp;
while ((pTemp = pChild->m_pNextNode) != NULL) {
pChild = pTemp;
}
return pChild;
}
default:
break;
}
return NULL;
}
void SetParentNode(CPLTreeNode *pNode)
{
m_pParentNode = pNode;
}
FX_INT32 CountChildNodes() const
{
FX_INT32 iCount = 0;
CPLTreeNode *pNode = m_pChildNode;
while (pNode) {
iCount ++;
pNode = pNode->m_pNextNode;
}
return iCount;
}
CPLTreeNode* GetChildNode(FX_INT32 iIndex) const
{
FX_INT32 iCount = 0;
CPLTreeNode *pNode = m_pChildNode;
while (pNode) {
if (iIndex == iCount) {
return pNode;
}
iCount ++;
pNode = pNode->m_pNextNode;
}
return NULL;
}
FX_INT32 GetNodeIndex() const
{
FX_INT32 index = 0;
CPLTreeNode *pNode = m_pPrevNode;
while (pNode != NULL) {
index ++;
pNode = pNode->m_pPrevNode;
}
return index;
}
FX_BOOL IsParentNode(const CPLTreeNode *pNode) const
{
CPLTreeNode *pParent = m_pParentNode;
while (pParent != NULL) {
if (pParent == pNode) {
return TRUE;
}
pParent = pParent->GetTreeNode(Parent);
}
return FALSE;
}
FX_BOOL IsChildNode(const CPLTreeNode *pNode) const
{
if (pNode == NULL) {
return FALSE;
}
return pNode->IsParentNode((const CPLTreeNode*)this);
}
void SetChildNode(CPLTreeNode *pNode)
{
m_pChildNode = pNode;
}
void SetPrevNode(CPLTreeNode *pNode)
{
m_pPrevNode = pNode;
}
void SetNextNode(CPLTreeNode *pNode)
{
m_pNextNode = pNode;
}
FX_INT32 GetNodeLevel() const
{
FX_INT32 iLevel = 0;
CPLTreeNode *pNode = (CPLTreeNode*)this;
while ((pNode = pNode->m_pParentNode) != NULL) {
iLevel ++;
}
return iLevel;
}
FX_BOOL IsRootNode() const
{
return m_pParentNode == NULL;
}
baseType GetData() const
{
return m_Data;
}
void SetData(baseType data)
{
m_Data = data;
}
protected:
CPLTreeNode *m_pParentNode;
CPLTreeNode *m_pChildNode;
CPLTreeNode *m_pPrevNode;
CPLTreeNode *m_pNextNode;
baseType m_Data;
friend class CFX_CPLTree<baseType>;
};
template<class baseType>
class CFX_CPLTree
{
public:
typedef CFX_CPLTreeNode<baseType> CPLTreeNode;
CFX_CPLTree() : m_Root()
{
}
~CFX_CPLTree()
{
CPLTreeNode *pNode = m_Root.GetNode(CPLTreeNode::LastNeighbor);
while (pNode != NULL) {
if (pNode->IsRootNode()) {
break;
}
CPLTreeNode *pTemp = pNode->GetNode(CPLTreeNode::PreviousNeighbor);
delete pNode;
pNode = pTemp;
}
}
CPLTreeNode* GetRoot()
{
return &m_Root;
}
CPLTreeNode* AddChild(baseType data, CPLTreeNode *pParent = NULL)
{
if (pParent == NULL) {
pParent = &m_Root;
}
CPLTreeNode *pChild = FXTARGET_New CPLTreeNode;
pChild->SetParentNode(pParent);
pChild->SetData(data);
if (pParent->m_pChildNode == NULL) {
pParent->m_pChildNode = pChild;
} else {
CPLTreeNode *pLast = pParent->GetNode(CPLTreeNode::LastChild);
pChild->SetPrevNode(pLast);
pLast->SetNextNode(pChild);
}
return pChild;
}
protected:
CPLTreeNode m_Root;
};
#endif