维度及长度均可任意变形的动态数组

  近日,有同事需要设计一个可自由变形的多维数组,苦思数日,不得其解,求助于我。于是我帮他写了一个可自由改变维度及长度的数组ADT。后来想,网上应该也有人需要这种东西吧,何不放到博客上来,让有此需要的朋友也一同来参考参考。于是就将开始的3个函数扩展为20个函数。鉴于时间仓促,源码一定有很多不完善的地方,如果遇到哪些牛人有兴趣对其进行改进,更求之不得了。

    我将此ADT称为Dynamic Dimensionality and Length Array,动态维度及长度数组,简称DDLA。它的主要特性如下:

1. 超越C99的VLA可变长数组。VLA虽然每维的长度可为变量,但仍有两个限制,一是维度不可变;二是一旦定义,长度不能再改变,即非动态的。DDLA则无论维度、长度皆动态,不但每维长度可为变量,维度也可为变量。

2. DDLA即使定义之后,仍可以根据需要在任何时候任意改变维度及长度,做到真正的完全动态,堪称数组中的变形金刚。而且,变形之后,原有数据仍可保留。变形方式简单快捷。

3. 超越c/c++数组作为形参会隐式转换为指针的特性。c/c++这项特性在提高效率的同时,也造成了在被调函数内部无法通过sizeof运算直接取得传入数组大小的问题。DDLA继续保持这个效率的同时,仍然可以在被调函数内部直接计算出传入数组的大小。

    设计DDLA类型的动态数组,不可避免需要建立中间地址缓冲区,如何构造这个缓冲区?通常的算法,是随时构造随时分配,例如一个动态二维数组可以这样构造:

 

  1. int i, m = 10, n = 20;  
  2. int **p = ( int** )malloc( m * sizeofint* ) );  
  3. for( i = 0; i < m; ++i )  
  4.     p[i] = ( int* )malloc( n * sizeofint ) );  

 

    这种方法有一个明显的缺点,就是无论元素存储区还是中间地址缓冲区都是不连续的!这会造成如下这些问题:

 

1. 堆管理函数频繁运行,效率低下,数组越大,效率影响越明显;

2. 如果中间某个步骤内存分配失败,需要对已分配的内存重新释放,算法复杂;

3. 数组使用完后,需要逐个内存块释放,效率低;

4. 若需要动态改变数组,算法复杂。

 

    但实际上,中间地址缓冲区和元素存储区的大小是可以预先计算出来的,在此前提下,两个存储块可以预先整体一次分配,效率有很大提高,更重要的是,这个做法使数组变形的算法大大简化,变形过程变得非常简单,只要改变元素存储区的大小,然后重新产生中间地址就行了。DDLA就是基于这个原理设计的,使用的中间地址缓冲区和元素存储区都是连续的。

以下代码为DDLA功能的简单演示,可将其后的接口头文件和实现源代码编译后运行。

  1. #include <stdio.h>  
  2. #include "DynamicDLA.h"  
  3.   
  4. void func( int** );  
  5.   
  6. int main( void )  
  7. {  
  8.     int i, j, k;  
  9.     int **p1 = ( int** )new_a( sizeofint ), 2, 7, 5 );  
  10.     int **p2 = ( int** )new_a( sizeofint ), 2, 15, 25 );  
  11.     int ***p3;  
  12.     for( i = 0; i < 7; ++i )  
  13.         for( j = 0; j < 5; ++j )  
  14.             p1[i][j] = j;  
  15.     printf( "/np1数组的内容(7x5):/n/n" );  
  16.     for( i = 0; i < 7; ++i )  
  17.     {  
  18.         for( j = 0; j < 5; ++j )  
  19.             printf( "%d ", p1[i][j] );  
  20.         printf( "/n" );  
  21.     }  
  22.     p1 = ( int** )resize_a( p1, 2, 5, 7 );  
  23.     printf( "/np1数组变形后的内容(5x7):/n/n" );  
  24.     for( i = 0; i < 5; ++i )  
  25.     {  
  26.         for( j = 0; j < 7; ++j )  
  27.             printf( "%d ", p1[i][j] );  
  28.         printf( "/n" );  
  29.     }  
  30.     p3 = ( int*** )resize_a( p1, 3, 4, 5, 7 );  
  31.     printf( "/np1数组变成3维后的内容(4x5x7) 超出部分可能为乱数:/n/n" );  
  32.     for( i = 0; i < 4; ++i )  
  33.     {  
  34.         for( j = 0; j < 5; ++j )  
  35.         {  
  36.             for( k = 0; k < 7; ++k )  
  37.                 printf( "%d ", p3[i][j][k] );  
  38.             printf( "/n" );  
  39.         }  
  40.         printf( "/n" );  
  41.     }  
  42.     p1 = ( int** )resize_a( p3, 2, 7, 5 );  
  43.     printf( "/np1数组变回2维后的内容(7x5):/n/n" );  
  44.     for( i = 0; i < 7; ++i )  
  45.     {  
  46.         for( j = 0; j < 5; ++j )  
  47.             printf( "%d ", p1[i][j] );  
  48.         printf( "/n" );  
  49.     }  
  50.     printf( "/n" );  
  51.     printf( "p1的长度:%d/n", sizeof_a( p1 ) );  
  52.     printf( "p1第一维p1[0]的长度:%d/n", sizeof_a( p1[0] ) );  
  53.     printf( "p2的长度:%d/n", sizeof_a( p2 ) );  
  54.     printf( "p2第一维p2[0]的长度:%d/n", sizeof_a( p2[0] ) );  
  55.     printf( "/n" );  
  56.     func( p1 );  
  57.     func( p2 );  
  58.     delete_a( p1 );  
  59.     delete_a( p2 );  
  60.     return 0;  
  61. }  
  62.   
  63. void func( int **p )  
  64. {  
  65.     if( sizeof_a( p ) / sizeof_a( p[0] ) == 7 )  
  66.     {  
  67.         printf( "p1在func内的长度:%d/n", sizeof_a( p ) );  
  68.         printf( "p1第一维p1[0]在func内的长度:%d/n", sizeof_a( p[0] ) );  
  69.     }  
  70.     else  
  71.     {  
  72.         printf( "p2在func内的长度:%d/n", sizeof_a( p ) );  
  73.         printf( "p2第一维p2[0]在func内的长度:%d/n", sizeof_a( p[0] ) );  
  74.     }  
  75.     printf( "/n" );  
  76. }  

 下面是ADT接口头文件DynamicDLA.h的内容,各函数的实现源码放在最后一部分。#define cplusplus控制在c还是c++中编译。在c++中使用时,各函数放在命名空间dynamic_dimensionality_length_array中,别名ddla。

 

  1. #ifndef DYNAMICDLA_H  
  2. #define DYNAMICDLA_H  
  3.   
  4. #ifndef __cplusplus  
  5.   
  6. #include <stddef.h>  
  7.   
  8. #ifndef BOOl  
  9. #define BOOL  
  10. typedef enum { falsetrue } bool;  
  11. #endif  
  12.   
  13. #else  
  14.   
  15. #include <cstddef>  
  16.   
  17. namespace dynamic_dimensionality_length_array  
  18. {  
  19.   
  20. #endif  
  21.   
  22. void* new_a( size_tsize_t, ... );  
  23. void* new0_a( size_tsize_t, ... );  
  24. void* new_pa( size_tsize_tsize_t* );  
  25. void* resize_a( void*, size_t, ... );  
  26. void* resize_pa( void*, size_tsize_t* );  
  27. bool assign_pa( void*, void*, size_t* );  
  28. bool assign_va( void*, void*, ... );  
  29. bool value_pa( void*, void*, size_t* );  
  30. bool value_va( void*, void*, ... );  
  31. void* address_pa( void*, size_tsize_t* );  
  32. void* address_va( void*, size_t, ... );  
  33. size_t sizeof_a( void* );  
  34. size_t sizeof_pa( void*, size_tsize_t* );  
  35. size_t sizeof_va( void*, size_t, ... );  
  36. size_t dimen_a( void* );  
  37. size_t* dimenlen_a( void*, size_t* );  
  38. size_t elmntsize_a( void* );  
  39. bool process_a( void*, void (*)(void*, size_t* ) );  
  40. void delete_a( void* );  
  41. void delete_all();  
  42.   
  43.   
  44. #ifdef __cplusplus  
  45.   
  46. }  
  47.   
  48. namespace ddla = dynamic_dimensionality_length_array;  
  49.   
  50. #endif  
  51.   
  52. #endif  

  下面一组函数是DDLA的基本函数:

 

void* new_a( size_t, size_t, ... );

void* new0_a( size_t, size_t, ... );

void* resize_a( void*, size_t, ... );

size_t sizeof_a( void* );

size_t dimen_a( void* );

size_t* dimenlen_a( void*, size_t* );

size_t elmntsize_a( void* );

bool process_a( void*, void (*)(void*, size_t* ) );

void delete_a( void* );

void delete_all();

    new_a和new0_a用于创建数组,new0_a同时将数组各元素初始化为0。返回值为中间地址缓冲区的首地址,第一个参数为元素大小,单位字节,第二个参数为维度,可变参数为各维的长度,例如:

 

int **p = ( int** )new_a( sizeof( int ), 2, 7, 8 );

创建一个二维、各维长度分别为7和8的动态数组,接受返回值的指针的*声明符的个数必须与数组的维度相等。

    当元素大小、维度或各维长度小于1、动态内存分配失败时,函数返回NULL。

    resize_a用于动态改变数组的维度和长度,变形的过程中元素大小不变,当新数组比原数组大时,多出的部分内容不确定;新数组比原数组小时,多出的部分被截断,共有的部分内容不变。resize_a第一个参数为DDLA, 第二个参数为新数组的维度,可变参数为各维的长度。

    当元素大小、维度或各维长度小于1、动态内存分配失败时,函数返回NULL。

    当一个动态数组创建后,各维的首地址就是中间数组的地址,例如对于:

int **p = ( int** )new_a( sizeof( int ), 2, 7, 8 );

p[0]这个数组的地址就是p[0]的值,与传统的动态数组一样,不可以用&p[0]代替p[0],因为&p[0]的值是保存p[0]的值的那个内存单元的地址,而不是象c/c++的传统数组定义那样地址值与p[0]相同,在这里&p[0]与p[0]是不一样的,这是所有动态数组的共性。

   只能对数组元素取地址,例如&p[0][0]。

    elmntsize_a、dimen_a、dimenlen_a分别返回DDLA的元素大小、维度和各维长度,其中需要为dimenlen_a准备一个size_t类型的缓冲区,dimenlen_a将各维长度保存在这里,dimenlen_a第二个参数传递缓冲区的首地址,函数返回值也返回这个首地址。

    如果三个函数的第一个实参不是DDLA,则返回0,dimenlen_a返回NULL。

   sizeof_a是专为实现类似sizeof运算符的功能设计的,它可以计算出各维中间数组的长度,单位为字节,但不能用它计算元素的大小,获得元素大小可用elmntsize_a函数。示例如下:

    对于上述定义的p动态二维数组,则sizeof_a( p )为7 x 8 x sizeof( int ),sizeof_a( p[0] )为8 x sizeof( int ),但不能使用sizeof_a( p[0][0] )。当p不是DDLA时,sizeof_a返回0。

    无论DDLA处于什么地方,即使在被调函数内部,仍可以通过sizeof_a得出DDLA的大小。

    process_a函数可以使用回调函数对整个或部分数组的元素进行操作,回调函数类型为 void (void*, size_t* ),两个参数的内容由process_a传递,第一个参数的实参为DDLA, 第二个参数为保存当前元素各维下标的size_t类型数组的首地址,从这里可以获知当前处理元素为哪一个元素,数组长度与维度相同。在回调函数内部可以使用DDLA各函数,但process_a本身除外,否则会出现无限调用嵌套的情况。

    delete_a和delete_all用于释放不再使用的DDLA,以获得更多的剩余内存空间,delete_a释放单个DDLA,delete_all一次释放所有DDLA,如果参数不是DDLA或者为空,两函数将啥也不做。

    前面介绍过的new_a等函数,都使用可变参数,但是有时候,输入的维度为变量,由于维度未知,就不能使用可变参数了,同时也不能使用确定类型的指针接受new_a返回的地址,也无法使用下标访问数组的元素,这时候可以使用new_pa函数创建这样的数组,new_pa第三个参数定义为一个指向由用户提供的size_t类型一维数组的指针,该数组保存各维长度,new_pa从此处读取各维长度,第一个元素为第一维长度,其余类推,该数组长度与维度相等。

    接受new_pa数组的指针可定义为void*类型

    与之对应,resize_pa与new_pa一样,用于处理维度为变量的情况,用一个size_t类型数组指示各维长度。

    创建这种数组的示例如下:

void *p;

size_t *buffer;

int m;

scanf( “%d”, &m );

buffer = ( size_t* )malloc( m * sizeof( size_t ) );

.................            /*填充buffer缓冲,产生各维长度*/

p = new_pa( sizeof( int ), m, buffer );

这种方法创建的p无法直接通过下标运算符访问其元素,这时候可以通过另一组函数操作p,它们是:

assign_pa        assign_va

value_pa         value_va

address_pa       address_va

sizeof_pa        sizeof_va

pa版本的函数象new_pa一样,使用一个缓冲区存放各维长度,va是这些函数的可变参数版本。

 

    assign_pa对某元素赋值,value_pa则相反,是取值,address_pa返回某元素或中间数组的地址,当第二个参数为0时,address_pa还可以返回元素存储区的首地址,这个地址才是真正的保存元素内容的区域的首地址,p的值是中间地址缓冲区的首地址,如果觉得这些函数使用比较麻烦,可以通过address获得的元素存储区首地址直接操作元素的值,这也是连续存储区带来的好处。sizeof_pa返回数组及各中间数组的大小,sizeof_pa还可以返回元素的大小。



  1. #include "DynamicDLA.h"  
  2.   
  3. #ifndef __cplusplus  
  4.   
  5. #include <stdlib.h>  
  6. #include <string.h>  
  7.   
  8. #else  
  9.   
  10. #include <cstdlib>  
  11. #include <cstring>  
  12.   
  13. namespace dynamic_dimensionality_length_array  
  14. {  
  15.   
  16.   
  17. #endif  
  18.   
  19. struct arrayinfo  
  20. {  
  21.     struct arrayinfo *Next;  
  22.     char* ElementAddr;  
  23.     void** PtrBuffer;  
  24.     size_t ElementSize;  
  25.     size_t *DimenLength;  
  26.     size_t Dimen;  
  27. };  
  28.   
  29. static struct arrayinfo *Head = NULL;  
  30.   
  31. static void* newarray( size_tsize_tsize_t*, bool );  
  32. static struct arrayinfo* search( void *PtrBuffer );  
  33. static void** build( void **, char *, size_tsize_t*, size_tsize_t );  
  34. static void process( struct arrayinfo *, size_tsize_t*, void ( * )(void*, size_t* ) );  
  35. static void* address( void*, size_tsize_t* );  
  36. static size_t size( void*, size_tsize_t* );  
  37.   
  38. void* new_a( size_t ElementSize, size_t Dimen, ... )  
  39. {  
  40.     return newarray( ElementSize, Dimen, &Dimen + 1, 1 );  
  41. }  
  42.   
  43. void* new0_a( size_t ElementSize, size_t Dimen, ... )  
  44. {  
  45.     return newarray( ElementSize, Dimen, &Dimen + 1, 0 );  
  46. }  
  47.   
  48.  void* new_pa( size_t ElementSize, size_t Dimen, size_t *DimenLength )  
  49. {  
  50.     return newarray( ElementSize, Dimen, DimenLength, 1 );  
  51. }  
  52.   
  53. void* resize_pa( void *PtrBuffer, size_t Dimen, size_t *DimenLength )  
  54. {  
  55.     size_t i, Product = 1, Sum = 0;  
  56.     struct arrayinfo *TempArray, *TempSearch, **TempNext = &Head;  
  57.     char *TempElement;  
  58.     void ** TempBuffer;  
  59.     if( !PtrBuffer || !Dimen ) return NULL;  
  60.     for( i = 0; i < Dimen; ++i )  
  61.         if( !DimenLength[i] ) return NULL;  
  62.     for( TempSearch = Head; TempSearch ; TempSearch = TempSearch->Next )  
  63.     {  
  64.         if( TempSearch->PtrBuffer == PtrBuffer ) break;  
  65.         TempNext = &TempSearch->Next;  
  66.     }  
  67.     if( !TempSearch ) return NULL;  
  68.     TempArray = ( struct arrayinfo * )malloc( sizeofstruct arrayinfo ) + Dimen * sizeofsize_t ) );  
  69.     if( !TempArray ) return NULL;  
  70.     for( i = 0; i < Dimen - 1; ++i )  
  71.         Sum += ( Product *= DimenLength[i] );  
  72.     Product *= DimenLength[Dimen-1] * TempSearch->ElementSize;  
  73.     TempBuffer = ( void** )malloc( Sum * sizeofvoid* ) );  
  74.     if( !TempBuffer ) return NULL;  
  75.     TempElement = ( char* )realloc( TempSearch->ElementAddr, Product * sizeofchar ) );  
  76.     if( !TempElement ) return NULL;  
  77.     build( TempBuffer, TempElement, TempSearch->ElementSize, DimenLength, 0, Dimen );  
  78.     TempArray->ElementAddr = TempElement;  
  79.     TempArray->PtrBuffer = TempBuffer;  
  80.     TempArray->ElementSize = TempSearch->ElementSize;  
  81.     TempArray->DimenLength = &TempArray->Dimen + 1;  
  82.     memcpy( TempArray->DimenLength, DimenLength, Dimen * sizeofsize_t ) );  
  83.     TempArray->Dimen = Dimen;  
  84.     TempArray->Next = TempSearch->Next;  
  85.     free( TempSearch->PtrBuffer );  
  86.     free( TempSearch );  
  87.     *TempNext = TempArray;  
  88.     return ( void* )TempBuffer;  
  89. }  
  90.   
  91.   
  92. void* resize_a( void *PtrBuffer, size_t Dimen, ... )  
  93. {  
  94.     return resize_pa( PtrBuffer, Dimen, &Dimen + 1 );  
  95. }  
  96.   
  97.   
  98.   
  99. bool assign_pa( void *PtrBuffer, void *Padding, size_t *DimenLength )  
  100. {  
  101.     size_t i;  
  102.     struct arrayinfo *TempArray;  
  103.     if( !PtrBuffer || !Padding || !DimenLength || !( TempArray = search( PtrBuffer ) ) )  
  104.         return false;  
  105.     for( i = 0; i < TempArray->Dimen; ++i )  
  106.         if( DimenLength[i] >= TempArray->DimenLength[i] ) return false;  
  107.     memcpy( address_pa( PtrBuffer, TempArray->Dimen, DimenLength ), Padding, TempArray->ElementSize );  
  108.     return true;  
  109. }  
  110.   
  111. bool assign_va( void *PtrBuffer, void *Padding, ... )  
  112. {  
  113.     return assign_pa( PtrBuffer, Padding, ( size_t* )( &Padding + 1 ) );  
  114. }  
  115.   
  116. bool value_pa( void *PtrBuffer, void *Padding, size_t *DimenLength )  
  117. {  
  118.     size_t i;  
  119.     struct arrayinfo *TempArray;  
  120.     if( !PtrBuffer || !Padding || !DimenLength || !( TempArray = search( PtrBuffer ) ) )  
  121.         return false;  
  122.     for( i = 0; i < TempArray->Dimen; ++i )  
  123.         if( DimenLength[i] >= TempArray->DimenLength[i] ) return false;  
  124.     memcpy( Padding, address_pa( PtrBuffer, TempArray->Dimen, DimenLength ), TempArray->ElementSize );  
  125.     return true;  
  126. }  
  127.   
  128. bool value_va( void *PtrBuffer, void *Padding, ... )  
  129. {  
  130.     return value_pa( PtrBuffer, Padding, ( size_t* )( &Padding + 1 ) );  
  131. }  
  132.   
  133. bool process_a( void *PtrBuffer, void ( *CallBack )(void*, size_t* ) )  
  134. {  
  135.     size_t *DimenLength;  
  136.     struct arrayinfo *TempArray;  
  137.     if( !PtrBuffer || !CallBack || !( TempArray = search( PtrBuffer) ) ) return false;  
  138.     DimenLength = ( size_t* )malloc( TempArray->Dimen * sizeofsize_t ) );  
  139.     if( !DimenLength ) return false;  
  140.     process( TempArray, 0, DimenLength, CallBack );  
  141.     free( DimenLength );  
  142.     return true;  
  143. }  
  144.   
  145. void* address_va( void *PtrBuffer, size_t Dimen, ... )  
  146. {  
  147.     return address( PtrBuffer, Dimen, &Dimen + 1 );  
  148. }  
  149.   
  150. void* address_pa( void *PtrBuffer, size_t Dimen, size_t *DimenLength )  
  151. {  
  152.     return address( PtrBuffer, Dimen, DimenLength );  
  153. }  
  154.   
  155. size_t dimen_a( void *PtrBuffer )  
  156. {  
  157.     struct arrayinfo *TempArray;  
  158.     if( !PtrBuffer || !( TempArray = search( PtrBuffer ) ) ) return 0;  
  159.     return TempArray->Dimen;  
  160. }  
  161.   
  162. size_t sizeof_a( void *PtrBuffer )  
  163. {  
  164.     struct arrayinfo *TempArray = Head;  
  165.     size_t i;  
  166.     if( !PtrBuffer ) return 0;  
  167.     for( ; TempArray; TempArray = TempArray->Next )  
  168.     {  
  169.         size_t Product = 1, Sum = 0;  
  170.         for( i = 0; i < TempArray->Dimen - 1; ++i )  
  171.                 Sum += Product *= TempArray->DimenLength[i];  
  172.         Product *= TempArray->DimenLength[i];  
  173.         if( TempArray->PtrBuffer == ( void** )PtrBuffer )  
  174.             return Product * TempArray->ElementSize;  
  175.         for( i = 0; i < Sum; ++i )  
  176.             if( TempArray->PtrBuffer[i] == PtrBuffer )  
  177.             {  
  178.                 size_t j;  
  179.                 size_t TempSum = 0, TempPrdct = 1;  
  180.                 for( j = 0; j < TempArray->Dimen - 1; ++j )  
  181.                 {  
  182.                     TempSum += TempPrdct *= TempArray->DimenLength[j];  
  183.                     Product /= TempArray->DimenLength[j];  
  184.                     if( TempSum > i ) return Product * TempArray->ElementSize;  
  185.                 }  
  186.             }  
  187.     }  
  188.     return 0;  
  189. }  
  190.   
  191. size_t sizeof_pa( void *PtrBuffer, size_t Dimen, size_t *DimenLength )  
  192. {  
  193.     return size( PtrBuffer, Dimen, DimenLength );  
  194. }  
  195.   
  196. size_t sizeof_va( void *PtrBuffer, size_t Dimen, ... )  
  197. {  
  198.     return size( PtrBuffer, Dimen, &Dimen + 1 );  
  199. }  
  200.   
  201.   
  202. size_t* dimenlen_a( void *PtrBuffer, size_t *DimenLength )  
  203. {  
  204.     struct arrayinfo *TempArray;  
  205.     if( !PtrBuffer || !( TempArray = search( PtrBuffer ) ) ) return NULL;  
  206.     memcpy( DimenLength, TempArray->DimenLength, TempArray->Dimen );  
  207.     return DimenLength;  
  208. }  
  209.   
  210. size_t elmntsize_a( void *PtrBuffer )  
  211. {  
  212.     struct arrayinfo *TempArray;  
  213.     if( !PtrBuffer || !( TempArray = search( PtrBuffer ) ) ) return 0;  
  214.     return TempArray->ElementSize;  
  215. }  
  216.   
  217. void delete_a( void *PtrBuffer )  
  218. {  
  219.     struct arrayinfo *TempArray, **TempNext = &Head;  
  220.     if( !PtrBuffer ) return;  
  221.     for( TempArray = Head; TempArray ; TempArray = TempArray->Next )  
  222.     {  
  223.         if( TempArray->PtrBuffer == PtrBuffer ) break;  
  224.         TempNext = &TempArray->Next;  
  225.     }  
  226.     if( !TempArray ) return;  
  227.     free( TempArray->ElementAddr );  
  228.     free( TempArray->PtrBuffer );  
  229.     *TempNext = TempArray->Next;  
  230.     free( TempArray );  
  231.     return;  
  232. }  
  233.   
  234. void delete_all()  
  235. {  
  236.     struct arrayinfo *TempArray = Head, *TempNext;  
  237.     for( ; TempArray; TempArray = TempNext )  
  238.     {  
  239.         TempNext = TempArray->Next;  
  240.         free( TempArray->ElementAddr );  
  241.         free( TempArray->PtrBuffer );  
  242.         free( TempArray );  
  243.     }  
  244. }  
  245.   
  246.   
  247. static void* newarray( size_t ElementSize, size_t Dimen, size_t *DimenLength, bool Flag )  
  248. {  
  249.     size_t i, Product = 1, Sum = 0;  
  250.     struct arrayinfo *TempArray;  
  251.     char *TempElement;  
  252.     void ** TempBuffer;  
  253.     if( !ElementSize || !Dimen ) return NULL;  
  254.     for( i = 0; i < Dimen; ++i )  
  255.         if( !DimenLength[i] ) return NULL;  
  256.     for( i = 0; i < Dimen - 1; ++i )  
  257.         Sum += Product *= DimenLength[i];  
  258.     Product *= DimenLength[Dimen-1] * ElementSize;  
  259.     if( Flag )  
  260.         TempElement = ( char* )malloc( Product * sizeofchar ) );  
  261.     else TempElement = ( char* )calloc( Product, sizeofchar ) );  
  262.     if( Dimen != 1 )  
  263.         TempBuffer = ( void** )malloc( Sum * sizeofvoid* ) );  
  264.     else TempBuffer = ( void** )TempElement;  
  265.     TempArray = ( struct arrayinfo * )malloc( sizeofstruct arrayinfo ) + Dimen * sizeofsize_t ) );  
  266.     if( !TempElement || !TempBuffer || !TempArray )  
  267.     {  
  268.         free( TempElement );  
  269.         if( Dimen != 1 ) free( TempBuffer );  
  270.         free( TempArray );  
  271.         return NULL;  
  272.     }  
  273.     build( TempBuffer, TempElement, ElementSize, DimenLength, 0, Dimen );  
  274.     TempArray->ElementAddr = TempElement;  
  275.     TempArray->PtrBuffer = TempBuffer;  
  276.     TempArray->ElementSize = ElementSize;  
  277.     TempArray->DimenLength = &TempArray->Dimen + 1;  
  278.     memcpy( TempArray->DimenLength, DimenLength, Dimen * sizeofsize_t ) );  
  279.     TempArray->Dimen = Dimen;  
  280.     TempArray->Next = Head;  
  281.     Head = TempArray;  
  282.     return ( void* )TempBuffer;  
  283. }  
  284.   
  285. static void** build( void **PtrBuffer, char *ElementAddr, size_t ElementSize,  
  286.                     size_t *DimenLength, size_t CurDimen, size_t Dimen )  
  287. {  
  288.     size_t i;  
  289.     if( CurDimen == Dimen - 1 ) return ( void** )ElementAddr;  
  290.     for( i = 0; i < DimenLength[CurDimen]; ++i )  
  291.     {  
  292.         size_t j;  
  293.         size_t Product = 1;  
  294.         void **NextPtr;  
  295.         char *NextData;  
  296.         for( j = 0; j <= CurDimen; ++j )  
  297.             Product *= DimenLength[j];  
  298.         NextPtr = PtrBuffer + Product + i * DimenLength[CurDimen + 1];  
  299.         Product = 1;  
  300.         for( j = CurDimen + 1; j < Dimen; ++j )  
  301.             Product *= DimenLength[j];  
  302.         NextData = ElementAddr + i * Product * ElementSize;  
  303.         PtrBuffer[i] = ( void* )build( NextPtr, NextData, ElementSize,  
  304.                                         DimenLength, CurDimen + 1, Dimen );  
  305.     }  
  306.     return PtrBuffer;  
  307. }  
  308.   
  309. static void process( struct arrayinfo *TempArray, size_t CurDimen,  
  310.                     size_t *DimenLength, void ( *CallBack )(void*, size_t* ) )  
  311. {  
  312.     size_t i;  
  313.     for( i = 0; i < TempArray->DimenLength[CurDimen]; ++i )  
  314.     {  
  315.             DimenLength[CurDimen] = i;  
  316.             if( CurDimen == TempArray->Dimen - 1 )  
  317.                 CallBack( TempArray->PtrBuffer, DimenLength );  
  318.             else process( TempArray, CurDimen + 1, DimenLength, CallBack );  
  319.     }  
  320.     return;  
  321. }  
  322.   
  323. static struct arrayinfo* search( void *PtrBuffer )  
  324. {  
  325.     struct arrayinfo *TempArray = Head;  
  326.     for( ; TempArray; TempArray = TempArray->Next )  
  327.         if( TempArray->PtrBuffer == PtrBuffer )  
  328.             return TempArray;  
  329.     return NULL;  
  330. }  
  331.   
  332. static void* address( void *PtrBuffer, size_t Dimen, size_t *DimenLength )  
  333. {  
  334.     size_t i, Sum = 0, Product = 1;  
  335.     struct arrayinfo *TempArray;  
  336.     if( ( Dimen && !DimenLength )  
  337.         || !PtrBuffer  
  338.         || !( TempArray = search( PtrBuffer ) )  
  339.         || TempArray->Dimen < Dimen  
  340.       ) return NULL;  
  341.     for( i = 0; i < Dimen; ++i )  
  342.         if( DimenLength[i] >= TempArray->DimenLength[i] ) return NULL;  
  343.     if( !Dimen ) return ( void* )TempArray->ElementAddr;  
  344.     for( i = 0; i < TempArray->Dimen; ++i )  
  345.         Product *= TempArray->DimenLength[i];  
  346.     for( i = 0; i < Dimen; ++i )  
  347.         Sum += DimenLength[i] * ( Product /= TempArray->DimenLength[i] );  
  348.     return TempArray->ElementAddr + Sum * TempArray->ElementSize;  
  349. }  
  350.   
  351. static size_t size( void *PtrBuffer, size_t Dimen, size_t *DimenLength )  
  352. {  
  353.     struct arrayinfo *TempArray;  
  354.     size_t i, Product = 1;  
  355.     if( ( Dimen && !DimenLength )  
  356.         || !PtrBuffer  
  357.         || !( TempArray = search( PtrBuffer ) )  
  358.         || TempArray->Dimen < Dimen  
  359.       ) return 0;  
  360.     for( i = 0; i < Dimen; ++i )  
  361.         if( DimenLength[i] >= TempArray->DimenLength[i] )  
  362.             return 0;  
  363.     if( !Dimen )  
  364.     {  
  365.         for( i = 0; i < TempArray->Dimen; ++i )  
  366.             Product *= TempArray->DimenLength[i];  
  367.         return Product * TempArray->ElementSize;  
  368.     }  
  369.     for( i = Dimen; i < TempArray->Dimen; ++i )  
  370.         Product *= TempArray->DimenLength[i];  
  371.     return Product * TempArray->ElementSize;  
  372. }  
  373.   
  374.   
  375. #ifdef __cplusplus  
  376.   
  377. }  
  378.   
  379. #endif  


  1. #include "DynamicDLA.h"  
  2.   
  3. #ifndef __cplusplus  
  4.   
  5. #include <stdlib.h>  
  6. #include <string.h>  
  7.   
  8. #else  
  9.   
  10. #include <cstdlib>  
  11. #include <cstring>  
  12.   
  13. namespace dynamic_dimensionality_length_array  
  14. {  
  15.   
  16.   
  17. #endif  
  18.   
  19. struct arrayinfo  
  20. {  
  21.     struct arrayinfo *Next;  
  22.     char* ElementAddr;  
  23.     void** PtrBuffer;  
  24.     size_t ElementSize;  
  25.     size_t *DimenLength;  
  26.     size_t Dimen;  
  27. };  
  28.   
  29. static struct arrayinfo *Head = NULL;  
  30.   
  31. static void* newarray( size_tsize_tsize_t*, bool );  
  32. static struct arrayinfo* search( void *PtrBuffer );  
  33. static void** build( void **, char *, size_tsize_t*, size_tsize_t );  
  34. static void process( struct arrayinfo *, size_tsize_t*, void ( * )(void*, size_t* ) );  
  35. static void* address( void*, size_tsize_t* );  
  36. static size_t size( void*, size_tsize_t* );  
  37.   
  38. void* new_a( size_t ElementSize, size_t Dimen, ... )  
  39. {  
  40.     return newarray( ElementSize, Dimen, &Dimen + 1, 1 );  
  41. }  
  42.   
  43. void* new0_a( size_t ElementSize, size_t Dimen, ... )  
  44. {  
  45.     return newarray( ElementSize, Dimen, &Dimen + 1, 0 );  
  46. }  
  47.   
  48.  void* new_pa( size_t ElementSize, size_t Dimen, size_t *DimenLength )  
  49. {  
  50.     return newarray( ElementSize, Dimen, DimenLength, 1 );  
  51. }  
  52.   
  53. void* resize_pa( void *PtrBuffer, size_t Dimen, size_t *DimenLength )  
  54. {  
  55.     size_t i, Product = 1, Sum = 0;  
  56.     struct arrayinfo *TempArray, *TempSearch, **TempNext = &Head;  
  57.     char *TempElement;  
  58.     void ** TempBuffer;  
  59.     if( !PtrBuffer || !Dimen ) return NULL;  
  60.     for( i = 0; i < Dimen; ++i )  
  61.         if( !DimenLength[i] ) return NULL;  
  62.     for( TempSearch = Head; TempSearch ; TempSearch = TempSearch->Next )  
  63.     {  
  64.         if( TempSearch->PtrBuffer == PtrBuffer ) break;  
  65.         TempNext = &TempSearch->Next;  
  66.     }  
  67.     if( !TempSearch ) return NULL;  
  68.     TempArray = ( struct arrayinfo * )malloc( sizeofstruct arrayinfo ) + Dimen * sizeofsize_t ) );  
  69.     if( !TempArray ) return NULL;  
  70.     for( i = 0; i < Dimen - 1; ++i )  
  71.         Sum += ( Product *= DimenLength[i] );  
  72.     Product *= DimenLength[Dimen-1] * TempSearch->ElementSize;  
  73.     TempBuffer = ( void** )malloc( Sum * sizeofvoid* ) );  
  74.     if( !TempBuffer ) return NULL;  
  75.     TempElement = ( char* )realloc( TempSearch->ElementAddr, Product * sizeofchar ) );  
  76.     if( !TempElement ) return NULL;  
  77.     build( TempBuffer, TempElement, TempSearch->ElementSize, DimenLength, 0, Dimen );  
  78.     TempArray->ElementAddr = TempElement;  
  79.     TempArray->PtrBuffer = TempBuffer;  
  80.     TempArray->ElementSize = TempSearch->ElementSize;  
  81.     TempArray->DimenLength = &TempArray->Dimen + 1;  
  82.     memcpy( TempArray->DimenLength, DimenLength, Dimen * sizeofsize_t ) );  
  83.     TempArray->Dimen = Dimen;  
  84.     TempArray->Next = TempSearch->Next;  
  85.     free( TempSearch->PtrBuffer );  
  86.     free( TempSearch );  
  87.     *TempNext = TempArray;  
  88.     return ( void* )TempBuffer;  
  89. }  
  90.   
  91.   
  92. void* resize_a( void *PtrBuffer, size_t Dimen, ... )  
  93. {  
  94.     return resize_pa( PtrBuffer, Dimen, &Dimen + 1 );  
  95. }  
  96.   
  97.   
  98.   
  99. bool assign_pa( void *PtrBuffer, void *Padding, size_t *DimenLength )  
  100. {  
  101.     size_t i;  
  102.     struct arrayinfo *TempArray;  
  103.     if( !PtrBuffer || !Padding || !DimenLength || !( TempArray = search( PtrBuffer ) ) )  
  104.         return false;  
  105.     for( i = 0; i < TempArray->Dimen; ++i )  
  106.         if( DimenLength[i] >= TempArray->DimenLength[i] ) return false;  
  107.     memcpy( address_pa( PtrBuffer, TempArray->Dimen, DimenLength ), Padding, TempArray->ElementSize );  
  108.     return true;  
  109. }  
  110.   
  111. bool assign_va( void *PtrBuffer, void *Padding, ... )  
  112. {  
  113.     return assign_pa( PtrBuffer, Padding, ( size_t* )( &Padding + 1 ) );  
  114. }  
  115.   
  116. bool value_pa( void *PtrBuffer, void *Padding, size_t *DimenLength )  
  117. {  
  118.     size_t i;  
  119.     struct arrayinfo *TempArray;  
  120.     if( !PtrBuffer || !Padding || !DimenLength || !( TempArray = search( PtrBuffer ) ) )  
  121.         return false;  
  122.     for( i = 0; i < TempArray->Dimen; ++i )  
  123.         if( DimenLength[i] >= TempArray->DimenLength[i] ) return false;  
  124.     memcpy( Padding, address_pa( PtrBuffer, TempArray->Dimen, DimenLength ), TempArray->ElementSize );  
  125.     return true;  
  126. }  
  127.   
  128. bool value_va( void *PtrBuffer, void *Padding, ... )  
  129. {  
  130.     return value_pa( PtrBuffer, Padding, ( size_t* )( &Padding + 1 ) );  
  131. }  
  132.   
  133. bool process_a( void *PtrBuffer, void ( *CallBack )(void*, size_t* ) )  
  134. {  
  135.     size_t *DimenLength;  
  136.     struct arrayinfo *TempArray;  
  137.     if( !PtrBuffer || !CallBack || !( TempArray = search( PtrBuffer) ) ) return false;  
  138.     DimenLength = ( size_t* )malloc( TempArray->Dimen * sizeofsize_t ) );  
  139.     if( !DimenLength ) return false;  
  140.     process( TempArray, 0, DimenLength, CallBack );  
  141.     free( DimenLength );  
  142.     return true;  
  143. }  
  144.   
  145. void* address_va( void *PtrBuffer, size_t Dimen, ... )  
  146. {  
  147.     return address( PtrBuffer, Dimen, &Dimen + 1 );  
  148. }  
  149.   
  150. void* address_pa( void *PtrBuffer, size_t Dimen, size_t *DimenLength )  
  151. {  
  152.     return address( PtrBuffer, Dimen, DimenLength );  
  153. }  
  154.   
  155. size_t dimen_a( void *PtrBuffer )  
  156. {  
  157.     struct arrayinfo *TempArray;  
  158.     if( !PtrBuffer || !( TempArray = search( PtrBuffer ) ) ) return 0;  
  159.     return TempArray->Dimen;  
  160. }  
  161.   
  162. size_t sizeof_a( void *PtrBuffer )  
  163. {  
  164.     struct arrayinfo *TempArray = Head;  
  165.     size_t i;  
  166.     if( !PtrBuffer ) return 0;  
  167.     for( ; TempArray; TempArray = TempArray->Next )  
  168.     {  
  169.         size_t Product = 1, Sum = 0;  
  170.         for( i = 0; i < TempArray->Dimen - 1; ++i )  
  171.                 Sum += Product *= TempArray->DimenLength[i];  
  172.         Product *= TempArray->DimenLength[i];  
  173.         if( TempArray->PtrBuffer == ( void** )PtrBuffer )  
  174.             return Product * TempArray->ElementSize;  
  175.         for( i = 0; i < Sum; ++i )  
  176.             if( TempArray->PtrBuffer[i] == PtrBuffer )  
  177.             {  
  178.                 size_t j;  
  179.                 size_t TempSum = 0, TempPrdct = 1;  
  180.                 for( j = 0; j < TempArray->Dimen - 1; ++j )  
  181.                 {  
  182.                     TempSum += TempPrdct *= TempArray->DimenLength[j];  
  183.                     Product /= TempArray->DimenLength[j];  
  184.                     if( TempSum > i ) return Product * TempArray->ElementSize;  
  185.                 }  
  186.             }  
  187.     }  
  188.     return 0;  
  189. }  
  190.   
  191. size_t sizeof_pa( void *PtrBuffer, size_t Dimen, size_t *DimenLength )  
  192. {  
  193.     return size( PtrBuffer, Dimen, DimenLength );  
  194. }  
  195.   
  196. size_t sizeof_va( void *PtrBuffer, size_t Dimen, ... )  
  197. {  
  198.     return size( PtrBuffer, Dimen, &Dimen + 1 );  
  199. }  
  200.   
  201.   
  202. size_t* dimenlen_a( void *PtrBuffer, size_t *DimenLength )  
  203. {  
  204.     struct arrayinfo *TempArray;  
  205.     if( !PtrBuffer || !( TempArray = search( PtrBuffer ) ) ) return NULL;  
  206.     memcpy( DimenLength, TempArray->DimenLength, TempArray->Dimen );  
  207.     return DimenLength;  
  208. }  
  209.   
  210. size_t elmntsize_a( void *PtrBuffer )  
  211. {  
  212.     struct arrayinfo *TempArray;  
  213.     if( !PtrBuffer || !( TempArray = search( PtrBuffer ) ) ) return 0;  
  214.     return TempArray->ElementSize;  
  215. }  
  216.   
  217. void delete_a( void *PtrBuffer )  
  218. {  
  219.     struct arrayinfo *TempArray, **TempNext = &Head;  
  220.     if( !PtrBuffer ) return;  
  221.     for( TempArray = Head; TempArray ; TempArray = TempArray->Next )  
  222.     {  
  223.         if( TempArray->PtrBuffer == PtrBuffer ) break;  
  224.         TempNext = &TempArray->Next;  
  225.     }  
  226.     if( !TempArray ) return;  
  227.     free( TempArray->ElementAddr );  
  228.     free( TempArray->PtrBuffer );  
  229.     *TempNext = TempArray->Next;  
  230.     free( TempArray );  
  231.     return;  
  232. }  
  233.   
  234. void delete_all()  
  235. {  
  236.     struct arrayinfo *TempArray = Head, *TempNext;  
  237.     for( ; TempArray; TempArray = TempNext )  
  238.     {  
  239.         TempNext = TempArray->Next;  
  240.         free( TempArray->ElementAddr );  
  241.         free( TempArray->PtrBuffer );  
  242.         free( TempArray );  
  243.     }  
  244. }  
  245.   
  246.   
  247. static void* newarray( size_t ElementSize, size_t Dimen, size_t *DimenLength, bool Flag )  
  248. {  
  249.     size_t i, Product = 1, Sum = 0;  
  250.     struct arrayinfo *TempArray;  
  251.     char *TempElement;  
  252.     void ** TempBuffer;  
  253.     if( !ElementSize || !Dimen ) return NULL;  
  254.     for( i = 0; i < Dimen; ++i )  
  255.         if( !DimenLength[i] ) return NULL;  
  256.     for( i = 0; i < Dimen - 1; ++i )  
  257.         Sum += Product *= DimenLength[i];  
  258.     Product *= DimenLength[Dimen-1] * ElementSize;  
  259.     if( Flag )  
  260.         TempElement = ( char* )malloc( Product * sizeofchar ) );  
  261.     else TempElement = ( char* )calloc( Product, sizeofchar ) );  
  262.     if( Dimen != 1 )  
  263.         TempBuffer = ( void** )malloc( Sum * sizeofvoid* ) );  
  264.     else TempBuffer = ( void** )TempElement;  
  265.     TempArray = ( struct arrayinfo * )malloc( sizeofstruct arrayinfo ) + Dimen * sizeofsize_t ) );  
  266.     if( !TempElement || !TempBuffer || !TempArray )  
  267.     {  
  268.         free( TempElement );  
  269.         if( Dimen != 1 ) free( TempBuffer );  
  270.         free( TempArray );  
  271.         return NULL;  
  272.     }  
  273.     build( TempBuffer, TempElement, ElementSize, DimenLength, 0, Dimen );  
  274.     TempArray->ElementAddr = TempElement;  
  275.     TempArray->PtrBuffer = TempBuffer;  
  276.     TempArray->ElementSize = ElementSize;  
  277.     TempArray->DimenLength = &TempArray->Dimen + 1;  
  278.     memcpy( TempArray->DimenLength, DimenLength, Dimen * sizeofsize_t ) );  
  279.     TempArray->Dimen = Dimen;  
  280.     TempArray->Next = Head;  
  281.     Head = TempArray;  
  282.     return ( void* )TempBuffer;  
  283. }  
  284.   
  285. static void** build( void **PtrBuffer, char *ElementAddr, size_t ElementSize,  
  286.                     size_t *DimenLength, size_t CurDimen, size_t Dimen )  
  287. {  
  288.     size_t i;  
  289.     if( CurDimen == Dimen - 1 ) return ( void** )ElementAddr;  
  290.     for( i = 0; i < DimenLength[CurDimen]; ++i )  
  291.     {  
  292.         size_t j;  
  293.         size_t Product = 1;  
  294.         void **NextPtr;  
  295.         char *NextData;  
  296.         for( j = 0; j <= CurDimen; ++j )  
  297.             Product *= DimenLength[j];  
  298.         NextPtr = PtrBuffer + Product + i * DimenLength[CurDimen + 1];  
  299.         Product = 1;  
  300.         for( j = CurDimen + 1; j < Dimen; ++j )  
  301.             Product *= DimenLength[j];  
  302.         NextData = ElementAddr + i * Product * ElementSize;  
  303.         PtrBuffer[i] = ( void* )build( NextPtr, NextData, ElementSize,  
  304.                                         DimenLength, CurDimen + 1, Dimen );  
  305.     }  
  306.     return PtrBuffer;  
  307. }  
  308.   
  309. static void process( struct arrayinfo *TempArray, size_t CurDimen,  
  310.                     size_t *DimenLength, void ( *CallBack )(void*, size_t* ) )  
  311. {  
  312.     size_t i;  
  313.     for( i = 0; i < TempArray->DimenLength[CurDimen]; ++i )  
  314.     {  
  315.             DimenLength[CurDimen] = i;  
  316.             if( CurDimen == TempArray->Dimen - 1 )  
  317.                 CallBack( TempArray->PtrBuffer, DimenLength );  
  318.             else process( TempArray, CurDimen + 1, DimenLength, CallBack );  
  319.     }  
  320.     return;  
  321. }  
  322.   
  323. static struct arrayinfo* search( void *PtrBuffer )  
  324. {  
  325.     struct arrayinfo *TempArray = Head;  
  326.     for( ; TempArray; TempArray = TempArray->Next )  
  327.         if( TempArray->PtrBuffer == PtrBuffer )  
  328.             return TempArray;  
  329.     return NULL;  
  330. }  
  331.   
  332. static void* address( void *PtrBuffer, size_t Dimen, size_t *DimenLength )  
  333. {  
  334.     size_t i, Sum = 0, Product = 1;  
  335.     struct arrayinfo *TempArray;  
  336.     if( ( Dimen && !DimenLength )  
  337.         || !PtrBuffer  
  338.         || !( TempArray = search( PtrBuffer ) )  
  339.         || TempArray->Dimen < Dimen  
  340.       ) return NULL;  
  341.     for( i = 0; i < Dimen; ++i )  
  342.         if( DimenLength[i] >= TempArray->DimenLength[i] ) return NULL;  
  343.     if( !Dimen ) return ( void* )TempArray->ElementAddr;  
  344.     for( i = 0; i < TempArray->Dimen; ++i )  
  345.         Product *= TempArray->DimenLength[i];  
  346.     for( i = 0; i < Dimen; ++i )  
  347.         Sum += DimenLength[i] * ( Product /= TempArray->DimenLength[i] );  
  348.     return TempArray->ElementAddr + Sum * TempArray->ElementSize;  
  349. }  
  350.   
  351. static size_t size( void *PtrBuffer, size_t Dimen, size_t *DimenLength )  
  352. {  
  353.     struct arrayinfo *TempArray;  
  354.     size_t i, Product = 1;  
  355.     if( ( Dimen && !DimenLength )  
  356.         || !PtrBuffer  
  357.         || !( TempArray = search( PtrBuffer ) )  
  358.         || TempArray->Dimen < Dimen  
  359.       ) return 0;  
  360.     for( i = 0; i < Dimen; ++i )  
  361.         if( DimenLength[i] >= TempArray->DimenLength[i] )  
  362.             return 0;  
  363.     if( !Dimen )  
  364.     {  
  365.         for( i = 0; i < TempArray->Dimen; ++i )  
  366.             Product *= TempArray->DimenLength[i];  
  367.         return Product * TempArray->ElementSize;  
  368.     }  
  369.     for( i = Dimen; i < TempArray->Dimen; ++i )  
  370.         Product *= TempArray->DimenLength[i];  
  371.     return Product * TempArray->ElementSize;  
  372. }  
  373.   
  374.   
  375. #ifdef __cplusplus  
  376.   
  377. }  
  378.   
  379. #endif  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值