以前在做一个编译器的时候,碰到这样一个问题:编译器把所有的标识符(identifier)字符串存储在一个String Table中,其实就是一个std::vector<std::string>,便于用数字来引用,但是在查找时却要根据字符串来匹配,速度显然不行。于是我不得不自己编一个Dictionary,存储的是<__int64,Entry>值对,Entry是这个标识符的入口,而__int64则是该标识符在String Table中的索引,查找时也是根据string来比较的。这样既能保证查找的效率,又能保留标识符的索引。
现在趁还记得,写下来再说。
为简化情形,先假设已经定义的如下的类:
class Entry;
其内容不重要,意义就是标识符的入口。
自定义的类里面,最重要的就是一个Comparator类,这个类的作用是告诉我们的Dictionary,该如何比较传给它的参数:__int64和std::string。我把String Table作为模板参数__StrTbl,而__StrTbl::U8就是__int64。仿照标准库的代码,具体实现如下:
#include <map>
template<class __StrTbl>class Comparator
:public std::binary_function<std::string,typename __StrTbl::U8,bool>
{
public:
typedef typename __StrTbl::U8 U8;
typedef std::binary_function<std::string,U8,bool> __MyBase;
typedef typename __MyBase::first_argument_type first_argument_type;
public:
~Comparator(){}
explicit Comparator(const __StrTbl & st):StrTbl_(st){}
template<typename T1,typename T2>
bool operator ()(const T1 & left,const T2 & right) const{
return DataTrans(left) < DataTrans(right);
}
const __StrTbl & StrTable() const{
return StrTbl_;
}
private:
const std::string & DataTrans(const std::string & val) const{return val;}
const std::string & DataTrans(U8 index) const{return StrTbl_[index];}
private:
const __StrTbl & StrTbl_;
};
注意到Comparator的构造函数必须要传const __StrTbl &,原因是很显然的。
然后就是operator ()()的传入参数类型,我都用模板参数,但是用DataTrans()来转化成__StrTbl里对应的字符串。其余的几个typedef和const函数就没什么的好说的了。
现在可以定义Dictionary类了,和Comparator类一样,它也需要一个模板参数__StrTbl,而。仿照标准库的map,实现如下:
#include "Comparator.h"
#include "Entry.h"
template<class __StrTbl>class Dictionary:
public std::_Tree<
std::_Tmap_traits<
typename __StrTbl::U8,
Entry,
Comparator<__StrTbl>,
std::allocator<std::pair<
const typename __StrTbl::U8,
Entry> >
,false
>
>
{
public:
typedef typename __StrTbl::U1 U1;
typedef typename __StrTbl::U4 U4;
typedef typename __StrTbl::U8 U8;
typedef Dictionary _Myt;
typedef U8 key_type;
typedef Entry mapped_type;
typedef Entry referent_type; // retained
typedef Comparator<__StrTbl> key_compare;
typedef std::_Tree<std::_Tmap_traits<key_type,mapped_type,key_compare,std::allocator<std::pair<const key_type,mapped_type> >,false> > _Mybase;
typedef typename _Mybase::value_compare value_compare;
typedef typename _Mybase::allocator_type allocator_type;
typedef typename _Mybase::size_type size_type;
typedef typename _Mybase::difference_type difference_type;
typedef typename _Mybase::pointer pointer;
typedef typename _Mybase::const_pointer const_pointer;
typedef typename _Mybase::reference reference;
typedef typename _Mybase::const_reference const_reference;
typedef typename _Mybase::iterator iterator;
typedef typename _Mybase::const_iterator const_iterator;
typedef typename _Mybase::reverse_iterator reverse_iterator;
typedef typename _Mybase::const_reverse_iterator const_reverse_iterator;
typedef typename _Mybase::value_type value_type;
//my declarations
typedef typename key_compare::first_argument_type first_argument_type;
private:
iterator Lower_bound(const first_argument_type & val)
{ // find leftmost node not less than _Keyval in mutable tree
return (_TREE_ITERATOR(_LBound(val)));
}
_Nodeptr _LBound(const first_argument_type & val) const
{ // find leftmost node not less than _Keyval
_Nodeptr _Pnode = _Root();
_Nodeptr _Wherenode = _Myhead; // end() if search fails
while (!_Isnil(_Pnode))
if (this->comp(_Key(_Pnode), val))
_Pnode = _Right(_Pnode); // descend right subtree
else{ // _Pnode not less than _Keyval, remember it
_Wherenode = _Pnode;
_Pnode = _Left(_Pnode); // descend left subtree
}
return (_Wherenode); // return best remembered candidate
}
public:
~Dictionary(){}
explicit Dictionary(const __StrTbl & strtbl):_Mybase(key_compare(strtbl), allocator_type()),strTbl_(strtbl){}
iterator Query(const first_argument_type & val){ // find an element in mutable sequence that matches val
iterator _Where = Lower_bound(val);
return (_Where == end() || this->comp(val, _Key(_Where._Mynode())) ? end() : _Where);
}
bool Has(const first_argument_type & val){
return Query(val) != end();
}
template<class __Symbol>
void AddEntry(const __Symbol & sym,U4 index,U4 subIndex){
insert(value_type(sym.Text(),mapped_type(U1(__Symbol::SymType),index,subIndex)));
}
private:
const __StrTbl & strTbl_;
};
在AddEntry()里出现了几个新的类名,__Symbol是符号表类,U4和U1分别为unsigned long和unsigned __int8。
insert需要一个std::pair(U8,Entry),前者是sym.Text()的返回值,后者是mapped_type(U1(__Symbol::SymType),index,subIndex),其实就是Entry的构造函数,具体传的参数就与实际情况有关了。
时间紧,现在吃饭去了!