容器是存储检索各类数据的利器,但是STL提供的内容使用起来还是不方便,所以对部分代码做一些封装,而且对于map来说,windows和linux下的用法不一样,曾花了很多时间来编写这个跨平台的map。
正如第一篇所说,由于跨平台代码很难看,只维护了一个Linux的版本,但map是个例外,以后还会有少量例外。
1. 对Queue的封装。这个queue并不是最小粒度的封装,我加了一个semaphore,用来实现生产者和消费者模型。
其实也可以把semaphore移到queue之外,和queue本身分开来实现生产者消费者。我是为了效率,为了方便,呵呵,各位就见仁见智吧。

Code
#include <deque>
#include "Common.h"
#include "Types.h"
namespace GameMate{
template<class V>
class Queue
{
public:
Queue() {}
~Queue() {}
void Push(V value)
{
mutexObject.Lock();
valueQueue.push_back(value);
mutexObject.Unlock();
semaphoreObject.Unlock();
}
V Pop()
{
V tempValue;
semaphoreObject.Lock();
mutexObject.Lock();
tempValue = valueQueue.front();
valueQueue.pop_front();
mutexObject.Unlock();
return tempValue;
}
uint32 Size()
{
uint32 itemCount;
mutexObject.Lock();
itemCount = valueQueue.size();
mutexObject.Unlock();
return itemCount;
}
private:
Mutex mutexObject;
Semaphore semaphoreObject;
std::deque<V> valueQueue;
private:
DISALLOW_COPY_AND_ASSIGN(Queue);
};
Mutex的定义如下,用来实现跨平台:
#ifdef _LINUX_
#include "Sync.h"
typedef ThreadMutex Mutex;
typedef ThreadReadWriteMutex RWMutex;
typedef Semaphore Semaphore;
#elif defined(_WIN32)
#include "CriticalSection.h"
typedef CriticalSection Mutex;
#else
#endif
DISALLOW_COPY_AND_ASSIGN的宏是参考Google C++ Coding Style,用来限制类型复制和拷贝等对class类型变量的误操作,也可以提高性能,减少编译器自作主张为我们生成一些无法预料的代码。
#define DISALLOW_COPY_AND_ASSIGN(TypeName) \
TypeName(const TypeName&); \
void operator=(const TypeName&)
使用时,请在class的声明中加入以下的代码:
class A
{
private:
DISALLOW_COPY_AND_ASSIGN(A);
}
CriticalSection是我对Windows下CRITICAL_SETCION的一个简单封装,只要提供Lock和Unlock接口就好了,Lock就是Enter,Unlock就是Leave,大家可以自己动手封装一下
2. 对map的封装

Code
template <class K, class V>
class HashMap
{
public:
HashMap(void) {}
virtual ~HashMap(void) {}
bool Add(K key, V value)
{
#ifndef _LINUX_
std::pair<std::map<K, V>::iterator, bool> result;
#else
bool result;
#endif
mutexObject.Lock();
#ifndef _LINUX_
result = keyValueMap.insert(std::map<K, V>::value_type(key, value));
#else
result = keyValueMap.insert(std::pair<K, V>(key, value)).second;
#endif
mutexObject.Unlock();
#ifndef _LINUX_
return result.second;
#else
return result;
#endif
}
void RemoveKey(K key)
{
mutexObject.Lock();
keyValueMap.erase(key);
mutexObject.Unlock();
}
/**
* @bug 如果V不是一个指针类型,那么调用该函数会出问题,但都是编译期问题,所以还不要紧
*/
void RemoveAndDestroyKey(K key)
{
mutexObject.Lock();
V value = keyValueMap[key];
if(NULL != value)
{
delete value;
}
keyValueMap.erase(key);
mutexObject.Unlock();
}
void RemoveValue(V value)
{
#ifndef _LINUX_
std::map<K, V>::iterator iter;
#else
typename std::map<K, V>::iterator iter;
#endif
mutexObject.Lock();
for(iter = keyValueMap.begin(); iter != keyValueMap.end(); ++iter)
{
if(iter->second == value)
{
keyValueMap.erase(iter);
break;
}
}
mutexObject.Unlock();
}
/**
* @bug 如果V不是一个指针类型,那么调用该函数会出问题,但都是编译期问题,所以还不要紧
*/
void RemoveAndDestroyValue(V value)
{
#ifndef _LINUX_
std::map<K, V>::iterator iter;
#else
typename std::map<K, V>::iterator iter;
#endif
mutexObject.Lock();
for(iter = keyValueMap.begin(); iter != keyValueMap.end(); iter++)
{
if(iter->second == value)
{
delete iter->second;
keyValueMap.erase(iter);
break;
}
}
mutexObject.Unlock();
}
void RemoveAll()
{
mutexObject.Lock();
keyValueMap.clear();
mutexObject.Unlock();
}
/**
* @bug 如果V不是一个指针类型,那么调用该函数会出问题,但都是编译期问题,所以还不要紧
*/
void RemoveAllAndDestroy()
{
#ifndef _LINUX_
std::map<K, V>::iterator iter;
#else
typename std::map<K, V>::iterator iter;
#endif
mutexObject.Lock();
for(iter = keyValueMap.begin(); iter != keyValueMap.end(); iter++)
{
if(NULL != iter->second)
{
delete iter->second;
iter->second = NULL;
}
}
keyValueMap.clear();
mutexObject.Unlock();
}
bool Empty()
{
bool isEmpty = false;
mutexObject.Lock();
isEmpty = (bool)keyValueMap.empty();
mutexObject.Unlock();
return isEmpty;
}
V GetValueByKey(K key)
{
V value;
mutexObject.Lock();
if(keyValueMap.find(key) != keyValueMap.end())
{
value = keyValueMap[key];
}
else
{
value = 0;
}
mutexObject.Unlock();
return value;
}
std::map<K, V>& GetInnerMap()
{
return keyValueMap;
}
private:
std::map<K, V> keyValueMap;
Mutex mutexObject;
private:
DISALLOW_COPY_AND_ASSIGN(HashMap);
};
RemoveAllAndDestroy函数有潜在的bug。
因为我是为了自己的应用方便,把HashMap<int, void *>这样用的时候,希望在清除map所有项的同时也释放内存,所以就有这个函数。
另外,可以用读写锁ThreadReadWriteMutex替代Mutex,理论上性能高一点,但没有测试过。我封装了一个RWHashMap,采用读写锁的。跟HashMap类似,就不赘述了。
还有,为了应用方便,还定义了一个BiHashMap,用于双向映射。BiHashMap<K, V> myMap; 里面包含了一个<K, V>的map,还有一个<V, K>的map。有兴趣的给我写邮件吧。
3. 对链表的封装(C形式的,借鉴了Codeproject的一个开源系统)

Code
class NodeList;
class Node
{
public:
Node *Next() const;
void Next(Node *pNext);
void AddToList(NodeList *pList);
void RemoveFromList();
protected:
Node();
~Node();
private :
friend class NodeList;
void Unlink();
public:
Node *m_pNext;
Node *m_pPrev;
NodeList *m_pList;
private:
DISALLOW_COPY_AND_ASSIGN(Node);
};
Node::Node(void)
:m_pNext(NULL),
m_pPrev(NULL),
m_pList(NULL)
{
}
Node::~Node(void)
{
try
{
RemoveFromList();
}
catch(
)
{
}
m_pNext = NULL;
m_pPrev = NULL;
m_pList = NULL;
}
Node *Node::Next() const
{
return m_pNext;
}
void Node::Next(Node *pNext)
{
m_pNext = pNext;
if (pNext)
{
pNext->m_pPrev = this;
}
}
void Node::AddToList(NodeList *pList)
{
/*
if(pList == NULL)
{
printf("List is Null!\n");
}
else
{
printf("List is not NULL!\n");
}
*/
m_pList = pList;
}
void Node::RemoveFromList()
{
//printf("In RemoveFromList()! %p\n", m_pList);
if (m_pList)
{
m_pList->RemoveNode(this);
//printf("Remove it!\n");
}
}
void Node::Unlink()
{
if (m_pPrev)
{
m_pPrev->m_pNext = m_pNext;
}
if (m_pNext)
{
m_pNext->m_pPrev = m_pPrev;
}
m_pNext = NULL;
m_pPrev = NULL;
m_pList = NULL;
}
///////////////////////////////NodeList.h////////////////////////////
class NodeList
{
public:
NodeList(void);
virtual ~NodeList(void);
public:
void PushNode(Node *pNode);
Node *PopNode();
Node *Head() const;
uint32 Count() const;
bool Empty() const;
private :
friend void Node::RemoveFromList();
void RemoveNode(Node *pNode);
Node *m_pHead;
uint32 m_numNodes;
private:
DISALLOW_COPY_AND_ASSIGN(NodeList);
};
//////////////////////////////////////////////////////////////////////////
template <class T>
class TemplateNodeList : public NodeList
{
public :
T *PopNode();
T *Head() const;
static T *Next(const T *pNode);
};
template <class T>
T *TemplateNodeList<T>::PopNode()
{
return static_cast<T*>(NodeList::PopNode());
}
template <class T>
T *TemplateNodeList<T>::Head() const
{
return static_cast<T*>(NodeList::Head());
}
template <class T>
T *TemplateNodeList<T>::Next(const T *pNode)
{
return static_cast<T*>(pNode->Next());
}
////////////////////////////////////////NodeList.cpp/////////////////////NodeList::NodeList()
:m_pHead(NULL),
m_numNodes(0)
{
}
NodeList::~NodeList(void)
{
}
void NodeList::PushNode(Node *pNode)
{
pNode->AddToList(this); //仅仅添加到列表
pNode->Next(m_pHead);
m_pHead = pNode;
++m_numNodes;
}
Node *NodeList::PopNode()
{
Node *pNode = m_pHead;
if (pNode)
{
RemoveNode(pNode);
}
return pNode;
}
Node *NodeList::Head() const
{
return m_pHead;
}
uint32 NodeList::Count() const
{
return m_numNodes;
}
bool NodeList::Empty() const
{
return (0 == m_numNodes);
}
void NodeList::RemoveNode(Node *pNode)
{
//printf("%d\n", m_numNodes);
if (pNode == m_pHead)
{
m_pHead = pNode->Next();
}
pNode->Unlink();
--m_numNodes;
//printf("%d\n", m_numNodes);
}
Node的用处在于可对很多资源做缓存处理。比如网络socket。建立一个socket的系统开销是很大的,所以可以预先把socket创建好,然后放到链表里。
如何使用呢?例如我定义了一个缓冲区类Buffer,我想对这个类做缓存处理,因为内存的分配与释放也是开销很大的。就可以:
class Buffer : public Node
{
}
后面会谈到Buffer类,所以这里就不详述了。