因为HugeNumberBase的实现是需要详细解说的,可能要花上不久的时间和不少的篇幅,我觉得可能先等我把所有其他“外围”代码都解决完了,再来专心对付这个“核心”会比较好,所以我这里介绍DataAllocation.h和Helper.h的实现。
4.DataAllocation.h
——————————————————————————————————
/*
* Copyright (c) 2005 by DoZerg. ALL RIGHTS RESERVED.
* Consult your license regarding permissions and restrictions.
*/
#pragma once
namespace DoZerg{
//class DataInStack
template<long N,typename __DataType>
class DataInStack
{
public:
typedef __DataType * ptr;
typedef const __DataType * const_ptr;
operator ptr(){
return data_;
}
operator const_ptr() const{
return data_;
}
private:
__DataType data_[N];
};
//class DataInHeap
template<long N,typename __DataType>
class DataInHeap
{
public:
typedef __DataType * ptr;
typedef const __DataType * const_ptr;
DataInHeap():data_(new __DataType[N]){
}
DataInHeap(const DataInHeap & v):data_(new __DataType[N]){
FromSelf(v);
}
~DataInHeap(){
delete [] data_;
}
DataInHeap & operator =(const DataInHeap & v){
FromSelf(v);
return *this;
}
operator ptr(){
return data_;
}
operator const_ptr() const{
return data_;
}
private:
ptr data_;
void FromSelf(const DataInHeap & v){
memcpy(data_,v.data_,N * sizeof(__DataType));
}
};
//class DataAutoSelect : with a allocation selection strategy(if N<100 then DataInStack,else DataInHeap)
template<long N,typename __DataType>
class DataAutoSelect
{
public:
typedef __DataType * ptr;
typedef const __DataType * const_ptr;
operator ptr(){
return data_;
}
operator const_ptr() const{
return data_;
}
private:
template<bool,class T1,class T2>struct IfType{ typedef T1 RType; };
template<class T1,class T2>struct IfType<false,T1,T2>{ typedef T2 RType; };
typedef typename IfType< (N<100),DataInStack<N,__DataType>,DataInHeap<N,__DataType> >::RType RType;
RType data_;
};
}//namespace DoZerg
——————————————————————————————————
这里有3个类模版,DataInStack,DataInHeap和DataAutoSelect。
1)DataInStack
这个类模版从栈空间里“申请”数据data_,其实就是这句:
__DataType data_[N];
如果大整数本来是在栈空间里生成的,那么data_自然也在栈空间里了;如果大整数在堆空间里生成,那么data_也会存在于堆空间。
它有2个模版参数:
long N,
typename __DataType
第一个N是数据数组data_的长度,第二个__DataType是数据的类型。
这里用__DataType来抽象内部的数据类型,那么一个128bits的整数,可以用2个long long来表示,也可以用4个long来表示,甚至用16个char来表示。
DataInStack需要提供的接口,或者说“合格”的Alloc应该提供的接口包括:
默认构造函数
拷贝构造函数
拷贝赋值函数
typedef __DataType * ptr;
typedef const __DataType * const_ptr;
operator ptr();
operator const_ptr() const;
后面几个直接写成代码形式,希望能更清晰。
对于DataInStack,前3个接口使用编译器自动的生成就行了,所以实际上它只提供了后4个接口。
2)DataInHeap
它与DataInStack的本质区别就是只存储data_指针,数据空间是在构造的时候new出来的,所以它的数据永远在堆空间里。考虑到大整数可能占用比较大的内存,把数据空间移到堆里也许能减轻线程栈空间的压力。
由于DataInHeap只存储数据的指针,那么编译器生成的浅拷贝函数就不够用了,所以它实现了一个Alloc应该具有的全部接口。
3)DataAutoSelect
这个类模版是我展示小小“技巧”的一个东西,本来是不需要的。
它的主要作用就是根据数据数组长度N的大小,来选择采用DataInStack还是DataInHeap,这里我的界限是100。如果N<100,将采用DataInStack;否则采用DataInHeap。
它首先实现了作为Alloc接口必须的东西,即public下的所有东西,然后把内部数据的表示进行了“技术处理”(当然还利用了DataInStack和DataInHeap拷贝函数)。
注意到这二行:
template<bool,class T1,class T2>struct IfType{ typedef T1 RType; };
template<class T1,class T2>struct IfType<false,T1,T2>{ typedef T2 RType; };
定义了一个类模版IfType,接受3个模版参数,并把T1定义成RType;
下面对IfType进行了特化,在第一个模版参数为false的情况下,把T2定义成RType;那么前面定义R1为RType的情况只能是第一个模版参数为true了。
于是这样IfType就成了一个类型选择器,根据第一个模版参数进行T1或T2的类型选择。
所以接下来的这行:
typedef typename IfType< (N<100),DataInStack<N,__DataType>,DataInHeap<N,__DataType> >::RType RType;
也就不再“神秘”。
IfType<
(N<100),
DataInStack<N,__DataType>,
DataInHeap<N,__DataType>
>
IfType的第一个模版参数是(N<100),由它决定,最终是DataInStack<N,__DataType>定义成RType,还是DataInHeap<N,__DataType>定义成RType。
然后把这个RType定义成DataAutoSelect的RType。
于是根据N值来选择DataInStack或DataInHeap的目的就达到了。