练手的
[定义]
auto_array<typename T, std::size_t dim, typename Allocator = _test_allocator<T> > a;
第一个参数是元素类型,第二个是最高维度,维度标记从0到dim-1,第三个是一个分配器
[重塑数组大小]
reshape(std::size_t dim_index, std::size_t width, long start = 0);
第一个参数是指定第几维,第二个参数是指定该维的宽度,第三个参数是起始下标. 这个函数可以重叠使用,如
a.reshape(0,4);
a.reshape(1,5);
等价于
a.reshape(0,4)(1,5);
[operator[]操作]
和C语言的数组[]操作一样,没有任何不同,只是多了运行时越界检查.
测试代码(编译环境Dev C++(GCC)):
#include <iostream>
#include "auto_array.hpp"
using namespace std;
int main(int argc, char *argv[])
{
auto_array<int,1> a;
a.reshape(0,5);
try {
a[0]=1;
a[0]+=2;
a[1]=3;
a[4]=a[0]*a[1];
}
catch(runtime_error &err)
{
cout<<err.what()<<endl;
system("PAUSE");
return 0;
}
//auto_array<int,2> a;
//a.reshape(0,4)(1,5);
//a[3][0]=1;
if(!a.empty())
cout<<"a is not null"<<endl;
cout<<a[0]<<endl
<<a[1]<<endl
<<a[2]<<endl;
cout<<a.size()<<endl
<<a.max_size()<<endl;
a=0;
if(!a)
cout<<"a is null now"<<endl;
system("PAUSE");
return EXIT_SUCCESS;
}
下一步,设计一个和boost::multi_array类似的'生成器',以下是源码,版权所有:
#ifndef AUTO_ARRAY
#define AUTO_ARRAY
#include <stdexcept>
//test allocator
template<typename T>
class _test_allocator
{
public:
static void* allocate(std::size_t n)
{
return malloc(n*sizeof(T));
}
static void deallocate(void* p, std::size_t /* __n */)
{
free(p);
}
static void* reallocate(void* __p, std::size_t /* old_sz */, std::size_t __new_sz)
{
return realloc(__p, __new_sz*sizeof(T));
}
};
struct range_list
{
long start;
std::size_t width;
std::size_t step;
};
template<typename T, std::size_t dim, typename Allocator = _test_allocator<T> >
class auto_array
{
public:
typedef T value_type;
typedef value_type* pointer;
typedef const value_type* const_pointer;
typedef value_type* iterator;
typedef const value_type* const_iterator;
typedef value_type& reference;
typedef const value_type& const_reference;
typedef size_t size_type;
typedef ptrdiff_t difference_type;
auto_array() : range_changed(false), data(0), length(0), max_sz(0)
{
for(std::size_t i=0;i<dim;++i)
rl[i].width=0;
}
template<std::size_t _dim>
class reshape_functor
{
public:
reshape_functor(range_list *prl) : rl(prl) {}
reshape_functor operator()(std::size_t dim_index, std::size_t width, long start = 0)
{
if(dim_index>=_dim)
throw(std::runtime_error("array reshape error: dimensionality too big"));
rl[dim_index].start=start;
rl[dim_index].width=width;
return *this;
}
private:
range_list *rl;
};
reshape_functor<dim>
reshape(std::size_t dim_index, std::size_t width, long start = 0)
{
range_changed=true;
return reshape_functor<dim>(rl)(dim_index,width,start);
}
template<typename _T, std::size_t _dim>
class index_functor
{
public:
index_functor(_T *pdata, const range_list *prl) : data(pdata), rl(prl) {}
index_functor<_T,_dim-1> operator[](long index)
{
if(index>=rl[0].start && index-rl[0].start<static_cast<long>(rl[0].width))
return index_functor<_T,_dim-1>(data+(index-rl[0].start)*rl[0].step,rl+1);
else
throw(std::runtime_error("array access error: out of bound"));
}
private:
_T *data;
const range_list *rl;
};
template<typename _T>
class index_functor<_T,0>
{
public:
index_functor(_T *pdata, const range_list *prl) : data(pdata) {}
operator _T(){ return data[0]; }
template<typename U>
_T& operator=(const U &other){ return data[0]=other; }
template<typename U>
_T& operator+=(const U &other){ return data[0]+=other; }
template<typename U>
_T& operator-=(const U &other){ return data[0]-=other; }
template<typename U>
_T& operator*=(const U &other){ return data[0]*=other; }
template<typename U>
_T& operator/=(const U &other){ return data[0]/=other; }
template<typename U>
_T& operator%=(const U &other){ return data[0]%=other; }
template<typename U>
_T& operator<<=(const U &other){ return data[0]<<=other; }
template<typename U>
_T& operator>>=(const U &other){ return data[0]>>=other; }
template<typename U>
_T& operator^=(const U &other){ return data[0]^=other; }
template<typename U>
_T& operator&=(const U &other){ return data[0]&=other; }
template<typename U>
_T& operator|=(const U &other){ return data[0]|=other; }
private:
_T *data;
};
index_functor<T,dim-1>
operator[](long index)
{
if(getready())
return index_functor<T,dim>(data,rl)[index];
else
throw(std::runtime_error("array access error: shape uninitialized"));
}
struct dummy{void nonnull(void){}};
typedef void (dummy::*safe_bool)(void);
operator safe_bool() {return data==0?0:&dummy::nonnull;}
bool empty() const {return data==0;}
size_type size() const { return length; }
size_type max_size() const { return max_sz; }
void clear()
{
if(data)
{
deallocate(data,max_sz);
data=0;
max_sz=0;
}
}
void operator=(int zero){ clear(); }
iterator begin() { return data; }
const_iterator begin() const { return data; }
iterator end() { return data+length; }
const_iterator end() const { return data+length; }
private:
pointer allocate(std::size_t n){ return static_cast<pointer>(Allocator::allocate(n)); }
void deallocate(pointer p, std::size_t sz){ Allocator::deallocate(static_cast<void*>(p),sz); }
pointer reallocate(pointer p, std::size_t _old_sz, std::size_t _new_sz){ return static_cast<pointer>(
Allocator::reallocate(static_cast<void*>(p),_old_sz,_new_sz)
); }
bool getready();
private:
range_list rl[dim];
bool range_changed;
T* data;
std::size_t length;
std::size_t max_sz;
};
template<typename T, std::size_t dim, typename Allocator>
bool auto_array<T,dim,Allocator>::getready()
{
if(range_changed)
{
std::size_t _new_length=1;
for(long i=dim-1;i>=0;--i)
{
_new_length*=rl[i].width;
rl[i].step = (i+1==dim?1:rl[i+1].step*rl[i+1].width);
}
if(_new_length>max_sz)
{
do{
max_sz = (max_sz==0?128:(max_sz<<1));
}while(_new_length>max_sz);
if(data)
data=reallocate(data,0,max_sz);
else
data=allocate(max_sz);
}
length=_new_length;
range_changed=false;
}
return length>0;
}
#endif
// by rickone 2008/02/18
评论