用于EagleEye3.0 规则集漏报和误报测试的示例项目,项目收集于github和gitee
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

690 lines
21 KiB

/**
* Copyright (C) 2014-2050 SOUI团队
* All rights reserved.
*
* @file stree.hpp
* @brief 树模板--提供对一般的数据类型实现树结构
* @version v1.0
* @author soui
* @date 2014-07-13
*
* Describe 此类是下拉窗口的父类 只需要派生该类即可
*
* version: 1.0 2003-10-24 实现基本功能
* 2.0 2004-12-29 增加两个遍历接口,修改内存释放部分可能存在的bug
* 2.1 2006-10-17 为节点增加一个hChildLast数据,以加快在数据插入时的速度
* 2.2 2008-10-16 修改一个遍历接口的问题
* 2.3 2011-10-17 将数据释放的接口从回调函数改成虚函数
*/
#if !defined(AFX_STREE_H__D2332B4E_2C7E_4357_BE22_EC55BF496C1C__INCLUDED_)
#define AFX_STREE_H__D2332B4E_2C7E_4357_BE22_EC55BF496C1C__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#ifndef SASSERT
#define SASSERT(x)
#endif
//typedef ULONG_PTR HSTREEITEM;
#define STVI_ROOT ((HSTREEITEM)0xFFFF0000)//=TVI_ROOT
#define STVI_FIRST ((HSTREEITEM)0xFFFF0001)//=TVI_FIRST
#define STVI_LAST ((HSTREEITEM)0xFFFF0002)//=TVI_LAST
#define STVN_ROOT ((HSTREENODE)(ULONG_PTR)0xFFFF0000)//=STVN_ROOT
#define STVN_FIRST ((HSTREENODE)(ULONG_PTR)0xFFFF0001)//=STVN_FIRST
#define STVN_LAST ((HSTREENODE)(ULONG_PTR)0xFFFF0002)//=STVN_LAST
#define STVL_ROOT ((PSTREELINK)(ULONG_PTR)0xFFFF0000)
/**
* @class CSTree 模板类
* @brief CSTree 模板类
*
* Describe CSTree 模板类
*/
template<class T>
class CSTree
{
/**
* @class _STREENODE
* @brief 节点结构体
*
* Describe 节点结构体
*/
typedef struct _STREENODE{
struct _STREENODE *hParent; /**< 父节点 */
struct _STREENODE *hChildFirst; /**< 第一个子节点 */
struct _STREENODE *hChildLast; /**< 最后一个子节点 */
struct _STREENODE *hPrevSibling; /**< 兄节点 */
struct _STREENODE *hNextSibling; /**< 弟节点 */
T data; /**< 数据 */
}STREENODE,*HSTREENODE;
/**
* @class _STREELINK
* @brief 树结点的链接
*
* Describe 此结构体用于连接树节点
*/
typedef struct _STREELINK{
HSTREENODE hParent; /**< 父节点 */
HSTREENODE hChildFirst; /**< 第一个子节点 */
HSTREENODE hChildLast; /**< 最后一个子节点 */
HSTREENODE hPrevSibling; /**< 兄节点 */
HSTREENODE hNextSibling; /**< 弟节点 */
}STREELINK,*PSTREELINK;
/**
* 回调函数
* @brief 下拉窗口鼠标左键按下事件
* @param T *:当前遍历到的结点的数据
* @param LPARAM:回调时使用的参数
* @return FALSE-继续,TRUE-中断遍历
*
* Describe 遍历一个树结点的回调函数原型,
*/
typedef BOOL (*CBTRAVERSING)(T*,LPARAM);
public:
/**
* CSTree::CSTree
* @brief 构造函数
*
* Describe 构造函数
*/
CSTree()
{
m_hRootFirst=NULL;
m_hRootLast=NULL;
}
/**
* CSTree::~CSTree
* @brief 析构函数
*
* Describe 析构函数
*/
virtual ~CSTree(){DeleteAllItems();}
/**
* CSTree::DeleteAllItems
* @brief 删除所有节点
*
* Describe 删除所有节点
*/
void DeleteAllItems(){
if(m_hRootFirst)
{
FreeNode(STVN_ROOT);
m_hRootFirst=NULL;
m_hRootLast=NULL;
}
}
/**
* CSTree::GetNextSiblingItem
* @brief 获取下一个兄弟
* @param HSTREEITEM hItem -- 节点
* @return 返回HSTREEITEM
*
* Describe 获取下一个兄弟
*/
static HSTREEITEM GetNextSiblingItem(HSTREEITEM hItem){
PSTREELINK pLink= (PSTREELINK)hItem;
SASSERT(pLink&&pLink!=STVL_ROOT);
return (HSTREEITEM)pLink->hNextSibling;
}
/**
* CSTree::GetPrevSiblingItem
* @brief 获取上一个兄弟
* @param HSTREEITEM hItem -- 节点
* @return 返回HSTREEITEM
*
* Describe 获取上一个兄弟
*/
static HSTREEITEM GetPrevSiblingItem(HSTREEITEM hItem)
{
PSTREELINK pLink= (PSTREELINK)hItem;
SASSERT(pLink&&pLink!=STVL_ROOT);
return (HSTREEITEM)pLink->hPrevSibling;
}
/**
* CSTree::GetParentItem
* @brief 获取父结点
* @param HSTREEITEM hItem -- 节点
* @return 返回HSTREEITEM
*
* Describe 获取父结点
*/
static HSTREEITEM GetParentItem(HSTREEITEM hItem)
{
PSTREELINK pLink= (PSTREELINK)hItem;
SASSERT(pLink&&pLink!=STVL_ROOT);
return (HSTREEITEM)pLink->hParent;
}
/**
* CSTree::GetItemLevel
* @brief 获取结点层数
* @param HSTREEITEM hItem -- 节点
* @return 返回int
*
* Describe 获取结点层数
*/
static int GetItemLevel(HSTREEITEM hItem)
{
int nRet=-1;
if(hItem==STVI_ROOT) hItem=NULL;
while(hItem)
{
nRet++;
hItem=GetParentItem(hItem);
}
return nRet;
}
/**
* GetRootItem
* @brief 获取指定节点的根节点
* @param HSTREEITEM hItem -- 当前节点
* @return HSTREEITEM 根节点
*
* Describe
*/
static HSTREEITEM GetRootItem(HSTREEITEM hItem)
{
HSTREEITEM hParent=hItem;
while(GetParentItem(hParent))
{
hParent = GetParentItem(hParent);
}
return hParent;
}
/**
* CSTree::GetChildItem
* @brief 获取第一个子结点
* @param HSTREEITEM hItem -- 节点
* @param BOOL bFirst -- 是否第一个节点
* @return 返回HSTREEITEM
*
* Describe 获取第一个子结点
*/
HSTREEITEM GetChildItem(HSTREEITEM hItem,BOOL bFirst=TRUE) const
{
HSTREENODE hsNode= (HSTREENODE)hItem;
SASSERT(hsNode);
if(hsNode==STVN_ROOT)
{
if(bFirst)
return (HSTREEITEM)m_hRootFirst;
else
return (HSTREEITEM)m_hRootLast;
}
else
{
if(bFirst)
return (HSTREEITEM)hsNode->hChildFirst;
else
return (HSTREEITEM)hsNode->hChildLast;
}
}
/**
* CSTree::GetChildrenCount
* @brief 获取子结点数量
* @param HSTREEITEM hItem -- 节点
* @return 返回int
*
* Describe 获取子结点数量
*/
int GetChildrenCount(HSTREEITEM hItem) const
{
int nRet=0;
HSTREEITEM hChild=GetChildItem(hItem);
while(hChild)
{
nRet++;
hChild=GetNextSiblingItem(hChild);
}
return nRet;
}
/**
* CSTree::DeleteItem
* @brief 删除一个节点,可以被派生类重载
* @param HSTREEITEM hItem -- 节点
*
* Describe 删除一个节点,可以被派生类重载
*/
virtual void DeleteItem(HSTREEITEM hItem)
{
HSTREENODE hsNode= (HSTREENODE)hItem;
SASSERT(hsNode);
if(hsNode==STVN_ROOT)
{
FreeNode(STVN_ROOT);
m_hRootFirst=NULL;
m_hRootLast=NULL;
return;
}
STREENODE nodeCopy=*hsNode;
BOOL bRootFirst=hsNode==m_hRootFirst;
BOOL bRootLast=hsNode==m_hRootLast;
FreeNode(hsNode);
if(nodeCopy.hPrevSibling)//has prevsibling
nodeCopy.hPrevSibling->hNextSibling=nodeCopy.hNextSibling;
else if(nodeCopy.hParent)//parent's first child
nodeCopy.hParent->hChildFirst=nodeCopy.hNextSibling;
if(nodeCopy.hNextSibling)// update next sibling's previous sibling
nodeCopy.hNextSibling->hPrevSibling=nodeCopy.hPrevSibling;
else if(nodeCopy.hParent)//parent's last child
nodeCopy.hParent->hChildLast=nodeCopy.hPrevSibling;
//update root item
if(bRootFirst) m_hRootFirst=nodeCopy.hNextSibling;
if(bRootLast) m_hRootLast=nodeCopy.hPrevSibling;
}
/**
* CSTree::DeleteItemEx
* @brief 删除一个结点分枝,如果该结点的父结点没有其它子节点则一起删除
* @param HSTREEITEM hItem -- 节点
* @return 返回BOOL
*
* Describe 删除一个结点分枝,如果该结点的父结点没有其它子节点则一起删除
*/
BOOL DeleteItemEx(HSTREEITEM hItem)
{
if(GetChildItem(hItem)) return FALSE;
while(hItem && !GetChildItem(hItem))
{
HSTREEITEM hParent=GetParentItem(hItem);
DeleteItem(hItem);
hItem=hParent;
}
return TRUE;
}
/**
* CSTree::GetItem
* @brief 获取结点中保存的数据
* @param HSTREEITEM hItem -- 节点
* @return 返回T
*
* Describe 获取结点中保存的数据
*/
static T GetItem(HSTREEITEM hItem){
SASSERT(hItem!=STVI_ROOT);
HSTREENODE hsNode= (HSTREENODE)hItem;
SASSERT(hsNode);
return hsNode->data;
}
/**
* CSTree::GetItem
* @brief 获取结点中保存的数据
* @param HSTREEITEM hItem -- 节点
* @return 返回T
*
* Describe 获取结点中保存的数据
*/
static T& GetItemRef(HSTREEITEM hItem){
SASSERT(hItem!=STVI_ROOT);
HSTREENODE hsNode= (HSTREENODE)hItem;
SASSERT(hsNode);
return hsNode->data;
}
/**
* CSTree::GetItemPt
* @brief 获取结点中保存的数据
* @param HSTREEITEM hItem -- 节点
* @return 返回T*
*
* Describe 获取结点中保存的数据
*/
static T *GetItemPt(HSTREEITEM hItem){
SASSERT(hItem!=STVI_ROOT);
HSTREENODE hsNode= (HSTREENODE)hItem;
SASSERT(hsNode);
return &hsNode->data;
}
/**
* CSTree::InsertItem
* @brief 插入一个新结点
* @param const T &data -- 结点数据
* @param HSTREEITEM hParent -- 新结点的父结点
* @param HSTREEITEM hInsertAfter -- 新结点的前一个兄弟结点
* @return 返回HSTREEITEM 新结点的指针
*
* Describe 获取结点中保存的数据
*/
HSTREEITEM InsertItem(const T &data,HSTREEITEM hParent=STVI_ROOT,HSTREEITEM hInsertAfter=STVI_LAST){
HSTREENODE hParentNode=(HSTREENODE) hParent;
HSTREENODE hInsertAfterNode=(HSTREENODE) hInsertAfter;
if(hParentNode==STVN_ROOT)
hParentNode=NULL;
SASSERT(hInsertAfter);
if(hInsertAfterNode!=STVN_FIRST && hInsertAfterNode!=STVN_LAST)
{
if(hInsertAfterNode->hParent!=hParentNode) return NULL;
if(hInsertAfterNode->hNextSibling==NULL) hInsertAfterNode=STVN_LAST;
}
HSTREENODE hInserted=new STREENODE;
hInserted->data=data;
hInserted->hParent=hParentNode;
hInserted->hChildFirst=NULL;
hInserted->hChildLast=NULL;
if(hInsertAfterNode==STVN_FIRST)
{
hInserted->hPrevSibling=NULL;
if(hParentNode==NULL)//root
{
hInserted->hNextSibling=m_hRootFirst;
if(m_hRootFirst) m_hRootFirst->hPrevSibling=hInserted;
m_hRootFirst=hInserted;
if(m_hRootLast==NULL) m_hRootLast=hInserted;
}else //has parent
{
hInserted->hNextSibling=hParentNode->hChildFirst;
if(hInserted->hNextSibling)
{
hInserted->hNextSibling->hPrevSibling=hInserted;
hParentNode->hChildFirst=hInserted;
}else
{
hParentNode->hChildLast=hParentNode->hChildFirst=hInserted;
}
}
}else if(hInsertAfterNode==STVN_LAST)
{
hInserted->hNextSibling=NULL;
if(hParentNode==NULL)//root
{
hInserted->hPrevSibling=m_hRootLast;
if(m_hRootLast) m_hRootLast->hNextSibling=hInserted;
m_hRootLast=hInserted;
if(!m_hRootFirst) m_hRootFirst=hInserted;
}else
{
hInserted->hPrevSibling=hParentNode->hChildLast;
if(hParentNode->hChildLast)
{
hInserted->hPrevSibling->hNextSibling=hInserted;
hParentNode->hChildLast=hInserted;
}else
{
hParentNode->hChildLast=hParentNode->hChildFirst=hInserted;
}
}
}else
{
HSTREENODE hNextSibling=hInsertAfterNode->hNextSibling;
hInserted->hPrevSibling=hInsertAfterNode;
hInserted->hNextSibling=hNextSibling;
hNextSibling->hPrevSibling = hInsertAfterNode->hNextSibling = hInserted;
}
return (HSTREEITEM)hInserted;
}
/**
* CSTree::TraversingRecursion
* @brief 采用递归方式遍历一个树结点
* @param HSTREEITEM hItem -- 起始结点
* @param CBTRAVERSING funTraversing -- 执行实际操作的回调函数
* @param LPARAM lParam -- 回调时使用的参数
* @return 返回HSTREEITEM
*
* Describe 采用递归方式遍历一个树结点
*/
HSTREEITEM TraversingRecursion(HSTREEITEM hItem,CBTRAVERSING funTraversing,LPARAM lParam)
{
SASSERT(hItem);
if(hItem!=STVI_ROOT)
{
if(funTraversing(GetItemPt(hItem),lParam)) return hItem;
}
HSTREEITEM hChild=GetChildItem(hItem);
while(hChild)
{
HSTREEITEM hTmp=GetChildItem(hChild);
if(hTmp)
{
HSTREEITEM hRet=TraversingRecursion(hTmp,funTraversing,lParam);
if(hRet) return hRet;
}else
{
if(funTraversing(GetItemPt(hChild),lParam)) return hChild;
}
hChild=GetNextSiblingItem(hChild);
}
return NULL;
}
/**
* CSTree::TraversingSequence
* @brief 按顺序方式从指定结点开始查找后面的结点,包括自己的子节点及自己向下的兄弟结点
* @param HSTREEITEM hItem -- 起始结点
* @param CBTRAVERSING funTraversing -- 执行实际操作的回调函数
* @param LPARAM lParam -- 回调时使用的参数
* @return 返回HSTREEITEM
*
* Describe 按顺序方式从指定结点开始查找后面的结点,包括自己的子节点及自己向下的兄弟结点
*/
HSTREEITEM TraversingSequence(HSTREEITEM hItem,CBTRAVERSING funTraversing,LPARAM lParam)
{
if(!m_hRootFirst) return NULL;
if(hItem!=STVI_ROOT)
{
if(funTraversing(GetItemPt(hItem),lParam)) return hItem;
}
HSTREEITEM hNext=GetNextItem(hItem);
while(hNext)
{
if(funTraversing(GetItemPt(hNext),lParam)) return hNext;
hNext=GetNextItem(hNext);
}
return NULL;
}
/**
* CSTree::GetRootItem
* @brief 获取根节点
* @param BOOL bFirst -- 是否从根节点
* @return 返回HSTREEITEM
*
* Describe 获取根节点
*/
HSTREEITEM GetRootItem(BOOL bFirst=TRUE){
return (HSTREEITEM)(bFirst?m_hRootFirst:m_hRootLast);
}
/**
* CSTree::GetDesendants
* @brief 获取结点的子孙结点数
* @param HSTREEITEM hItem -- 起始结点
* @return 返回int
*
* Describe 获取结点的子孙结点数
*/
int GetDesendants(HSTREEITEM hItem)
{
int nRet=0;
HSTREEITEM hChild=GetChildItem(hItem);
while(hChild)
{
nRet += 1+GetDesendants(hChild);
hChild=GetNextSiblingItem(hChild);
}
return nRet;
}
/**
* CSTree::GetNextItem
* @brief 获取当前结点的下一个结点
* @param HSTREEITEM hItem -- 当前结点
* @return 返回HSTREEITEM 当前结点的下一个结点
*
* Describe 获取当前结点的下一个结点
* 如果当前结点有子结点,则返回自己的第一个子结点,
* 否则如果有向下的兄弟结点,则返回自己向下兄弟结点、
* 否则搜索自己的父结点的向下兄弟结点
*/
HSTREEITEM GetNextItem(HSTREEITEM hItem) const
{
if(hItem==STVI_ROOT) return (HSTREEITEM)m_hRootFirst;
HSTREEITEM hRet=GetChildItem(hItem);
if(hRet) return hRet;
HSTREEITEM hParent=hItem;
while(hParent)
{
hRet=GetNextSiblingItem(hParent);
if(hRet) return hRet;
hParent=GetParentItem(hParent);
}
return NULL;
}
/**
* CSTree::GetNextItem
* @brief 获取当前结点的下一个结点
* @param HSTREEITEM hItem -- 当前结点
* @param int &nLevel -- 当前结点(hItem)与目标结点(return)的层次关系,
* 1-父子关系,0-兄弟关系,-n-子->父的兄弟
* @return 返回HSTREEITEM 当前结点的下一个结点
*
* Describe 获取当前结点的下一个结点
* 如果当前结点有子结点,则返回自己的第一个子结点,
* 否则如果有向下的兄弟结点,则返回自己向下兄弟结点、
* 否则搜索自己的父结点的向下兄弟结点
*/
HSTREEITEM GetNextItem(HSTREEITEM hItem,int &nLevel) const
{
if(hItem==STVI_ROOT)
{
nLevel=1;
return (HSTREEITEM)m_hRootFirst;
}
HSTREEITEM hRet=GetChildItem(hItem);
if(hRet)
{
nLevel=1;
return hRet;
}
HSTREEITEM hParent=hItem;
nLevel=0;
while(hParent)
{
hRet=GetNextSiblingItem(hParent);
if(hRet) return hRet;
nLevel--;
hParent=GetParentItem(hParent);
}
return NULL;
}
void SortChildren(HSTREEITEM hItem,int (__cdecl *funSort)(void *,const void *,const void *), void * pCtx)
{
int nChilds = GetChildrenCount(hItem);
if(nChilds>1)
{
HSTREEITEM *pChilds = new HSTREEITEM[nChilds];
HSTREEITEM hChild = GetChildItem(hItem);
pChilds[0] = hChild;
for(int i=1;i<nChilds;i++)
{
hChild = GetNextSiblingItem(hChild);
pChilds[i]= hChild;
}
//调用qsort排序
qsort_s(pChilds,nChilds,sizeof(HSTREEITEM),funSort,pCtx);
//重新整理链表
for(int i=0;i<nChilds-1;i++)
{
HSTREENODE node = (HSTREENODE)pChilds[i];
node->hNextSibling = (HSTREENODE)pChilds[i+1];
}
for(int i=1;i<nChilds;i++)
{
HSTREENODE node = (HSTREENODE)pChilds[i];
node->hPrevSibling = (HSTREENODE)pChilds[i-1];
}
HSTREENODE node = (HSTREENODE)pChilds[0];
node->hPrevSibling = NULL;
node = (HSTREENODE)pChilds[nChilds-1];
node->hNextSibling = NULL;
if(hItem!=STVI_ROOT)
{
HSTREENODE parent = (HSTREENODE)hItem;
parent->hChildFirst = (HSTREENODE)pChilds[0];
parent->hChildLast = (HSTREENODE)pChilds[nChilds-1];
}else
{
m_hRootFirst = (HSTREENODE)pChilds[0];
m_hRootLast = (HSTREENODE)pChilds[nChilds-1];
}
delete []pChilds;
}
//子节点排序
HSTREEITEM hChild = GetChildItem(hItem);
while(hChild)
{
HSTREENODE node = (HSTREENODE)hChild;
if(node->hChildFirst && node->hChildLast && node->hChildFirst != node->hChildLast)
{
SortChildren(hChild,funSort,pCtx);
}
hChild = GetNextSiblingItem(hChild);
}
}
private:
/**
* CSTree::FreeNode
* @brief 采用后序遍历的方式释放结点占用的空间
* @param HSTREENODE hsNode -- 当前结点
*
* Describe 采用后序遍历的方式释放结点占用的空间
*/
void FreeNode(HSTREENODE hsNode)
{
SASSERT(hsNode);
HSTREENODE hSibling=(HSTREENODE)GetChildItem((HSTREEITEM)hsNode);
while(hSibling)
{
HSTREENODE hNextSibling=hSibling->hNextSibling;
FreeNode(hSibling);
hSibling=hNextSibling;
}
if(hsNode!=STVN_ROOT)
{
OnNodeFree(hsNode->data);
delete hsNode;
}
}
protected:
/**
* CSTree::OnNodeFree
* @brief 在派生类中实现数据的释放操作
* @param T & data -- 数据
*
* Describe 在派生类中实现数据的释放操作
*/
virtual void OnNodeFree(T & data){}
HSTREENODE m_hRootFirst; /**< 第一个根节点 */
HSTREENODE m_hRootLast; /**< 最后一个根节点 */
};
#endif // !defined(AFX_STREE_H__D2332B4E_2C7E_4357_BE22_EC55BF496C1C__INCLUDED_)