近日,有同事需要设计一个可自由变形的多维数组,苦思数日,不得其解,求助于我。于是我帮他写了一个可自由改变维度及长度的数组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类型的动态数组,不可避免需要建立中间地址缓冲区,如何构造这个缓冲区?通常的算法,是随时构造随时分配,例如一个动态二维数组可以这样构造:
- int i, m = 10, n = 20;
- int **p = ( int** )malloc( m * sizeof( int* ) );
- for( i = 0; i < m; ++i )
- p[i] = ( int* )malloc( n * sizeof( int ) );
这种方法有一个明显的缺点,就是无论元素存储区还是中间地址缓冲区都是不连续的!这会造成如下这些问题:
1. 堆管理函数频繁运行,效率低下,数组越大,效率影响越明显;
2. 如果中间某个步骤内存分配失败,需要对已分配的内存重新释放,算法复杂;
3. 数组使用完后,需要逐个内存块释放,效率低;
4. 若需要动态改变数组,算法复杂。
但实际上,中间地址缓冲区和元素存储区的大小是可以预先计算出来的,在此前提下,两个存储块可以预先整体一次分配,效率有很大提高,更重要的是,这个做法使数组变形的算法大大简化,变形过程变得非常简单,只要改变元素存储区的大小,然后重新产生中间地址就行了。DDLA就是基于这个原理设计的,使用的中间地址缓冲区和元素存储区都是连续的。
以下代码为DDLA功能的简单演示,可将其后的接口头文件和实现源代码编译后运行。
- #include <stdio.h>
- #include "DynamicDLA.h"
- void func( int** );
- int main( void )
- {
- int i, j, k;
- int **p1 = ( int** )new_a( sizeof( int ), 2, 7, 5 );
- int **p2 = ( int** )new_a( sizeof( int ), 2, 15, 25 );
- int ***p3;
- for( i = 0; i < 7; ++i )
- for( j = 0; j < 5; ++j )
- p1[i][j] = j;
- printf( "/np1数组的内容(7x5):/n/n" );
- for( i = 0; i < 7; ++i )
- {
- for( j = 0; j < 5; ++j )
- printf( "%d ", p1[i][j] );
- printf( "/n" );
- }
- p1 = ( int** )resize_a( p1, 2, 5, 7 );
- printf( "/np1数组变形后的内容(5x7):/n/n" );
- for( i = 0; i < 5; ++i )
- {
- for( j = 0; j < 7; ++j )
- printf( "%d ", p1[i][j] );
- printf( "/n" );
- }
- p3 = ( int*** )resize_a( p1, 3, 4, 5, 7 );
- printf( "/np1数组变成3维后的内容(4x5x7) 超出部分可能为乱数:/n/n" );
- for( i = 0; i < 4; ++i )
- {
- for( j = 0; j < 5; ++j )
- {
- for( k = 0; k < 7; ++k )
- printf( "%d ", p3[i][j][k] );
- printf( "/n" );
- }
- printf( "/n" );
- }
- p1 = ( int** )resize_a( p3, 2, 7, 5 );
- printf( "/np1数组变回2维后的内容(7x5):/n/n" );
- for( i = 0; i < 7; ++i )
- {
- for( j = 0; j < 5; ++j )
- printf( "%d ", p1[i][j] );
- printf( "/n" );
- }
- printf( "/n" );
- printf( "p1的长度:%d/n", sizeof_a( p1 ) );
- printf( "p1第一维p1[0]的长度:%d/n", sizeof_a( p1[0] ) );
- printf( "p2的长度:%d/n", sizeof_a( p2 ) );
- printf( "p2第一维p2[0]的长度:%d/n", sizeof_a( p2[0] ) );
- printf( "/n" );
- func( p1 );
- func( p2 );
- delete_a( p1 );
- delete_a( p2 );
- return 0;
- }
- void func( int **p )
- {
- if( sizeof_a( p ) / sizeof_a( p[0] ) == 7 )
- {
- printf( "p1在func内的长度:%d/n", sizeof_a( p ) );
- printf( "p1第一维p1[0]在func内的长度:%d/n", sizeof_a( p[0] ) );
- }
- else
- {
- printf( "p2在func内的长度:%d/n", sizeof_a( p ) );
- printf( "p2第一维p2[0]在func内的长度:%d/n", sizeof_a( p[0] ) );
- }
- printf( "/n" );
- }
下面是ADT接口头文件DynamicDLA.h的内容,各函数的实现源码放在最后一部分。#define cplusplus控制在c还是c++中编译。在c++中使用时,各函数放在命名空间dynamic_dimensionality_length_array中,别名ddla。
- #ifndef DYNAMICDLA_H
- #define DYNAMICDLA_H
- #ifndef __cplusplus
- #include <stddef.h>
- #ifndef BOOl
- #define BOOL
- typedef enum { false, true } bool;
- #endif
- #else
- #include <cstddef>
- namespace dynamic_dimensionality_length_array
- {
- #endif
- void* new_a( size_t, size_t, ... );
- void* new0_a( size_t, size_t, ... );
- void* new_pa( size_t, size_t, size_t* );
- void* resize_a( void*, size_t, ... );
- void* resize_pa( void*, size_t, size_t* );
- bool assign_pa( void*, void*, size_t* );
- bool assign_va( void*, void*, ... );
- bool value_pa( void*, void*, size_t* );
- bool value_va( void*, void*, ... );
- void* address_pa( void*, size_t, size_t* );
- void* address_va( void*, size_t, ... );
- size_t sizeof_a( void* );
- size_t sizeof_pa( void*, size_t, size_t* );
- size_t sizeof_va( void*, size_t, ... );
- 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();
- #ifdef __cplusplus
- }
- namespace ddla = dynamic_dimensionality_length_array;
- #endif
- #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还可以返回元素的大小。
- #include "DynamicDLA.h"
- #ifndef __cplusplus
- #include <stdlib.h>
- #include <string.h>
- #else
- #include <cstdlib>
- #include <cstring>
- namespace dynamic_dimensionality_length_array
- {
- #endif
- struct arrayinfo
- {
- struct arrayinfo *Next;
- char* ElementAddr;
- void** PtrBuffer;
- size_t ElementSize;
- size_t *DimenLength;
- size_t Dimen;
- };
- static struct arrayinfo *Head = NULL;
- static void* newarray( size_t, size_t, size_t*, bool );
- static struct arrayinfo* search( void *PtrBuffer );
- static void** build( void **, char *, size_t, size_t*, size_t, size_t );
- static void process( struct arrayinfo *, size_t, size_t*, void ( * )(void*, size_t* ) );
- static void* address( void*, size_t, size_t* );
- static size_t size( void*, size_t, size_t* );
- void* new_a( size_t ElementSize, size_t Dimen, ... )
- {
- return newarray( ElementSize, Dimen, &Dimen + 1, 1 );
- }
- void* new0_a( size_t ElementSize, size_t Dimen, ... )
- {
- return newarray( ElementSize, Dimen, &Dimen + 1, 0 );
- }
- void* new_pa( size_t ElementSize, size_t Dimen, size_t *DimenLength )
- {
- return newarray( ElementSize, Dimen, DimenLength, 1 );
- }
- void* resize_pa( void *PtrBuffer, size_t Dimen, size_t *DimenLength )
- {
- size_t i, Product = 1, Sum = 0;
- struct arrayinfo *TempArray, *TempSearch, **TempNext = &Head;
- char *TempElement;
- void ** TempBuffer;
- if( !PtrBuffer || !Dimen ) return NULL;
- for( i = 0; i < Dimen; ++i )
- if( !DimenLength[i] ) return NULL;
- for( TempSearch = Head; TempSearch ; TempSearch = TempSearch->Next )
- {
- if( TempSearch->PtrBuffer == PtrBuffer ) break;
- TempNext = &TempSearch->Next;
- }
- if( !TempSearch ) return NULL;
- TempArray = ( struct arrayinfo * )malloc( sizeof( struct arrayinfo ) + Dimen * sizeof( size_t ) );
- if( !TempArray ) return NULL;
- for( i = 0; i < Dimen - 1; ++i )
- Sum += ( Product *= DimenLength[i] );
- Product *= DimenLength[Dimen-1] * TempSearch->ElementSize;
- TempBuffer = ( void** )malloc( Sum * sizeof( void* ) );
- if( !TempBuffer ) return NULL;
- TempElement = ( char* )realloc( TempSearch->ElementAddr, Product * sizeof( char ) );
- if( !TempElement ) return NULL;
- build( TempBuffer, TempElement, TempSearch->ElementSize, DimenLength, 0, Dimen );
- TempArray->ElementAddr = TempElement;
- TempArray->PtrBuffer = TempBuffer;
- TempArray->ElementSize = TempSearch->ElementSize;
- TempArray->DimenLength = &TempArray->Dimen + 1;
- memcpy( TempArray->DimenLength, DimenLength, Dimen * sizeof( size_t ) );
- TempArray->Dimen = Dimen;
- TempArray->Next = TempSearch->Next;
- free( TempSearch->PtrBuffer );
- free( TempSearch );
- *TempNext = TempArray;
- return ( void* )TempBuffer;
- }
- void* resize_a( void *PtrBuffer, size_t Dimen, ... )
- {
- return resize_pa( PtrBuffer, Dimen, &Dimen + 1 );
- }
- bool assign_pa( void *PtrBuffer, void *Padding, size_t *DimenLength )
- {
- size_t i;
- struct arrayinfo *TempArray;
- if( !PtrBuffer || !Padding || !DimenLength || !( TempArray = search( PtrBuffer ) ) )
- return false;
- for( i = 0; i < TempArray->Dimen; ++i )
- if( DimenLength[i] >= TempArray->DimenLength[i] ) return false;
- memcpy( address_pa( PtrBuffer, TempArray->Dimen, DimenLength ), Padding, TempArray->ElementSize );
- return true;
- }
- bool assign_va( void *PtrBuffer, void *Padding, ... )
- {
- return assign_pa( PtrBuffer, Padding, ( size_t* )( &Padding + 1 ) );
- }
- bool value_pa( void *PtrBuffer, void *Padding, size_t *DimenLength )
- {
- size_t i;
- struct arrayinfo *TempArray;
- if( !PtrBuffer || !Padding || !DimenLength || !( TempArray = search( PtrBuffer ) ) )
- return false;
- for( i = 0; i < TempArray->Dimen; ++i )
- if( DimenLength[i] >= TempArray->DimenLength[i] ) return false;
- memcpy( Padding, address_pa( PtrBuffer, TempArray->Dimen, DimenLength ), TempArray->ElementSize );
- return true;
- }
- bool value_va( void *PtrBuffer, void *Padding, ... )
- {
- return value_pa( PtrBuffer, Padding, ( size_t* )( &Padding + 1 ) );
- }
- bool process_a( void *PtrBuffer, void ( *CallBack )(void*, size_t* ) )
- {
- size_t *DimenLength;
- struct arrayinfo *TempArray;
- if( !PtrBuffer || !CallBack || !( TempArray = search( PtrBuffer) ) ) return false;
- DimenLength = ( size_t* )malloc( TempArray->Dimen * sizeof( size_t ) );
- if( !DimenLength ) return false;
- process( TempArray, 0, DimenLength, CallBack );
- free( DimenLength );
- return true;
- }
- void* address_va( void *PtrBuffer, size_t Dimen, ... )
- {
- return address( PtrBuffer, Dimen, &Dimen + 1 );
- }
- void* address_pa( void *PtrBuffer, size_t Dimen, size_t *DimenLength )
- {
- return address( PtrBuffer, Dimen, DimenLength );
- }
- size_t dimen_a( void *PtrBuffer )
- {
- struct arrayinfo *TempArray;
- if( !PtrBuffer || !( TempArray = search( PtrBuffer ) ) ) return 0;
- return TempArray->Dimen;
- }
- size_t sizeof_a( void *PtrBuffer )
- {
- struct arrayinfo *TempArray = Head;
- size_t i;
- if( !PtrBuffer ) return 0;
- for( ; TempArray; TempArray = TempArray->Next )
- {
- size_t Product = 1, Sum = 0;
- for( i = 0; i < TempArray->Dimen - 1; ++i )
- Sum += Product *= TempArray->DimenLength[i];
- Product *= TempArray->DimenLength[i];
- if( TempArray->PtrBuffer == ( void** )PtrBuffer )
- return Product * TempArray->ElementSize;
- for( i = 0; i < Sum; ++i )
- if( TempArray->PtrBuffer[i] == PtrBuffer )
- {
- size_t j;
- size_t TempSum = 0, TempPrdct = 1;
- for( j = 0; j < TempArray->Dimen - 1; ++j )
- {
- TempSum += TempPrdct *= TempArray->DimenLength[j];
- Product /= TempArray->DimenLength[j];
- if( TempSum > i ) return Product * TempArray->ElementSize;
- }
- }
- }
- return 0;
- }
- size_t sizeof_pa( void *PtrBuffer, size_t Dimen, size_t *DimenLength )
- {
- return size( PtrBuffer, Dimen, DimenLength );
- }
- size_t sizeof_va( void *PtrBuffer, size_t Dimen, ... )
- {
- return size( PtrBuffer, Dimen, &Dimen + 1 );
- }
- size_t* dimenlen_a( void *PtrBuffer, size_t *DimenLength )
- {
- struct arrayinfo *TempArray;
- if( !PtrBuffer || !( TempArray = search( PtrBuffer ) ) ) return NULL;
- memcpy( DimenLength, TempArray->DimenLength, TempArray->Dimen );
- return DimenLength;
- }
- size_t elmntsize_a( void *PtrBuffer )
- {
- struct arrayinfo *TempArray;
- if( !PtrBuffer || !( TempArray = search( PtrBuffer ) ) ) return 0;
- return TempArray->ElementSize;
- }
- void delete_a( void *PtrBuffer )
- {
- struct arrayinfo *TempArray, **TempNext = &Head;
- if( !PtrBuffer ) return;
- for( TempArray = Head; TempArray ; TempArray = TempArray->Next )
- {
- if( TempArray->PtrBuffer == PtrBuffer ) break;
- TempNext = &TempArray->Next;
- }
- if( !TempArray ) return;
- free( TempArray->ElementAddr );
- free( TempArray->PtrBuffer );
- *TempNext = TempArray->Next;
- free( TempArray );
- return;
- }
- void delete_all()
- {
- struct arrayinfo *TempArray = Head, *TempNext;
- for( ; TempArray; TempArray = TempNext )
- {
- TempNext = TempArray->Next;
- free( TempArray->ElementAddr );
- free( TempArray->PtrBuffer );
- free( TempArray );
- }
- }
- static void* newarray( size_t ElementSize, size_t Dimen, size_t *DimenLength, bool Flag )
- {
- size_t i, Product = 1, Sum = 0;
- struct arrayinfo *TempArray;
- char *TempElement;
- void ** TempBuffer;
- if( !ElementSize || !Dimen ) return NULL;
- for( i = 0; i < Dimen; ++i )
- if( !DimenLength[i] ) return NULL;
- for( i = 0; i < Dimen - 1; ++i )
- Sum += Product *= DimenLength[i];
- Product *= DimenLength[Dimen-1] * ElementSize;
- if( Flag )
- TempElement = ( char* )malloc( Product * sizeof( char ) );
- else TempElement = ( char* )calloc( Product, sizeof( char ) );
- if( Dimen != 1 )
- TempBuffer = ( void** )malloc( Sum * sizeof( void* ) );
- else TempBuffer = ( void** )TempElement;
- TempArray = ( struct arrayinfo * )malloc( sizeof( struct arrayinfo ) + Dimen * sizeof( size_t ) );
- if( !TempElement || !TempBuffer || !TempArray )
- {
- free( TempElement );
- if( Dimen != 1 ) free( TempBuffer );
- free( TempArray );
- return NULL;
- }
- build( TempBuffer, TempElement, ElementSize, DimenLength, 0, Dimen );
- TempArray->ElementAddr = TempElement;
- TempArray->PtrBuffer = TempBuffer;
- TempArray->ElementSize = ElementSize;
- TempArray->DimenLength = &TempArray->Dimen + 1;
- memcpy( TempArray->DimenLength, DimenLength, Dimen * sizeof( size_t ) );
- TempArray->Dimen = Dimen;
- TempArray->Next = Head;
- Head = TempArray;
- return ( void* )TempBuffer;
- }
- static void** build( void **PtrBuffer, char *ElementAddr, size_t ElementSize,
- size_t *DimenLength, size_t CurDimen, size_t Dimen )
- {
- size_t i;
- if( CurDimen == Dimen - 1 ) return ( void** )ElementAddr;
- for( i = 0; i < DimenLength[CurDimen]; ++i )
- {
- size_t j;
- size_t Product = 1;
- void **NextPtr;
- char *NextData;
- for( j = 0; j <= CurDimen; ++j )
- Product *= DimenLength[j];
- NextPtr = PtrBuffer + Product + i * DimenLength[CurDimen + 1];
- Product = 1;
- for( j = CurDimen + 1; j < Dimen; ++j )
- Product *= DimenLength[j];
- NextData = ElementAddr + i * Product * ElementSize;
- PtrBuffer[i] = ( void* )build( NextPtr, NextData, ElementSize,
- DimenLength, CurDimen + 1, Dimen );
- }
- return PtrBuffer;
- }
- static void process( struct arrayinfo *TempArray, size_t CurDimen,
- size_t *DimenLength, void ( *CallBack )(void*, size_t* ) )
- {
- size_t i;
- for( i = 0; i < TempArray->DimenLength[CurDimen]; ++i )
- {
- DimenLength[CurDimen] = i;
- if( CurDimen == TempArray->Dimen - 1 )
- CallBack( TempArray->PtrBuffer, DimenLength );
- else process( TempArray, CurDimen + 1, DimenLength, CallBack );
- }
- return;
- }
- static struct arrayinfo* search( void *PtrBuffer )
- {
- struct arrayinfo *TempArray = Head;
- for( ; TempArray; TempArray = TempArray->Next )
- if( TempArray->PtrBuffer == PtrBuffer )
- return TempArray;
- return NULL;
- }
- static void* address( void *PtrBuffer, size_t Dimen, size_t *DimenLength )
- {
- size_t i, Sum = 0, Product = 1;
- struct arrayinfo *TempArray;
- if( ( Dimen && !DimenLength )
- || !PtrBuffer
- || !( TempArray = search( PtrBuffer ) )
- || TempArray->Dimen < Dimen
- ) return NULL;
- for( i = 0; i < Dimen; ++i )
- if( DimenLength[i] >= TempArray->DimenLength[i] ) return NULL;
- if( !Dimen ) return ( void* )TempArray->ElementAddr;
- for( i = 0; i < TempArray->Dimen; ++i )
- Product *= TempArray->DimenLength[i];
- for( i = 0; i < Dimen; ++i )
- Sum += DimenLength[i] * ( Product /= TempArray->DimenLength[i] );
- return TempArray->ElementAddr + Sum * TempArray->ElementSize;
- }
- static size_t size( void *PtrBuffer, size_t Dimen, size_t *DimenLength )
- {
- struct arrayinfo *TempArray;
- size_t i, Product = 1;
- if( ( Dimen && !DimenLength )
- || !PtrBuffer
- || !( TempArray = search( PtrBuffer ) )
- || TempArray->Dimen < Dimen
- ) return 0;
- for( i = 0; i < Dimen; ++i )
- if( DimenLength[i] >= TempArray->DimenLength[i] )
- return 0;
- if( !Dimen )
- {
- for( i = 0; i < TempArray->Dimen; ++i )
- Product *= TempArray->DimenLength[i];
- return Product * TempArray->ElementSize;
- }
- for( i = Dimen; i < TempArray->Dimen; ++i )
- Product *= TempArray->DimenLength[i];
- return Product * TempArray->ElementSize;
- }
- #ifdef __cplusplus
- }
- #endif
- #include "DynamicDLA.h"
- #ifndef __cplusplus
- #include <stdlib.h>
- #include <string.h>
- #else
- #include <cstdlib>
- #include <cstring>
- namespace dynamic_dimensionality_length_array
- {
- #endif
- struct arrayinfo
- {
- struct arrayinfo *Next;
- char* ElementAddr;
- void** PtrBuffer;
- size_t ElementSize;
- size_t *DimenLength;
- size_t Dimen;
- };
- static struct arrayinfo *Head = NULL;
- static void* newarray( size_t, size_t, size_t*, bool );
- static struct arrayinfo* search( void *PtrBuffer );
- static void** build( void **, char *, size_t, size_t*, size_t, size_t );
- static void process( struct arrayinfo *, size_t, size_t*, void ( * )(void*, size_t* ) );
- static void* address( void*, size_t, size_t* );
- static size_t size( void*, size_t, size_t* );
- void* new_a( size_t ElementSize, size_t Dimen, ... )
- {
- return newarray( ElementSize, Dimen, &Dimen + 1, 1 );
- }
- void* new0_a( size_t ElementSize, size_t Dimen, ... )
- {
- return newarray( ElementSize, Dimen, &Dimen + 1, 0 );
- }
- void* new_pa( size_t ElementSize, size_t Dimen, size_t *DimenLength )
- {
- return newarray( ElementSize, Dimen, DimenLength, 1 );
- }
- void* resize_pa( void *PtrBuffer, size_t Dimen, size_t *DimenLength )
- {
- size_t i, Product = 1, Sum = 0;
- struct arrayinfo *TempArray, *TempSearch, **TempNext = &Head;
- char *TempElement;
- void ** TempBuffer;
- if( !PtrBuffer || !Dimen ) return NULL;
- for( i = 0; i < Dimen; ++i )
- if( !DimenLength[i] ) return NULL;
- for( TempSearch = Head; TempSearch ; TempSearch = TempSearch->Next )
- {
- if( TempSearch->PtrBuffer == PtrBuffer ) break;
- TempNext = &TempSearch->Next;
- }
- if( !TempSearch ) return NULL;
- TempArray = ( struct arrayinfo * )malloc( sizeof( struct arrayinfo ) + Dimen * sizeof( size_t ) );
- if( !TempArray ) return NULL;
- for( i = 0; i < Dimen - 1; ++i )
- Sum += ( Product *= DimenLength[i] );
- Product *= DimenLength[Dimen-1] * TempSearch->ElementSize;
- TempBuffer = ( void** )malloc( Sum * sizeof( void* ) );
- if( !TempBuffer ) return NULL;
- TempElement = ( char* )realloc( TempSearch->ElementAddr, Product * sizeof( char ) );
- if( !TempElement ) return NULL;
- build( TempBuffer, TempElement, TempSearch->ElementSize, DimenLength, 0, Dimen );
- TempArray->ElementAddr = TempElement;
- TempArray->PtrBuffer = TempBuffer;
- TempArray->ElementSize = TempSearch->ElementSize;
- TempArray->DimenLength = &TempArray->Dimen + 1;
- memcpy( TempArray->DimenLength, DimenLength, Dimen * sizeof( size_t ) );
- TempArray->Dimen = Dimen;
- TempArray->Next = TempSearch->Next;
- free( TempSearch->PtrBuffer );
- free( TempSearch );
- *TempNext = TempArray;
- return ( void* )TempBuffer;
- }
- void* resize_a( void *PtrBuffer, size_t Dimen, ... )
- {
- return resize_pa( PtrBuffer, Dimen, &Dimen + 1 );
- }
- bool assign_pa( void *PtrBuffer, void *Padding, size_t *DimenLength )
- {
- size_t i;
- struct arrayinfo *TempArray;
- if( !PtrBuffer || !Padding || !DimenLength || !( TempArray = search( PtrBuffer ) ) )
- return false;
- for( i = 0; i < TempArray->Dimen; ++i )
- if( DimenLength[i] >= TempArray->DimenLength[i] ) return false;
- memcpy( address_pa( PtrBuffer, TempArray->Dimen, DimenLength ), Padding, TempArray->ElementSize );
- return true;
- }
- bool assign_va( void *PtrBuffer, void *Padding, ... )
- {
- return assign_pa( PtrBuffer, Padding, ( size_t* )( &Padding + 1 ) );
- }
- bool value_pa( void *PtrBuffer, void *Padding, size_t *DimenLength )
- {
- size_t i;
- struct arrayinfo *TempArray;
- if( !PtrBuffer || !Padding || !DimenLength || !( TempArray = search( PtrBuffer ) ) )
- return false;
- for( i = 0; i < TempArray->Dimen; ++i )
- if( DimenLength[i] >= TempArray->DimenLength[i] ) return false;
- memcpy( Padding, address_pa( PtrBuffer, TempArray->Dimen, DimenLength ), TempArray->ElementSize );
- return true;
- }
- bool value_va( void *PtrBuffer, void *Padding, ... )
- {
- return value_pa( PtrBuffer, Padding, ( size_t* )( &Padding + 1 ) );
- }
- bool process_a( void *PtrBuffer, void ( *CallBack )(void*, size_t* ) )
- {
- size_t *DimenLength;
- struct arrayinfo *TempArray;
- if( !PtrBuffer || !CallBack || !( TempArray = search( PtrBuffer) ) ) return false;
- DimenLength = ( size_t* )malloc( TempArray->Dimen * sizeof( size_t ) );
- if( !DimenLength ) return false;
- process( TempArray, 0, DimenLength, CallBack );
- free( DimenLength );
- return true;
- }
- void* address_va( void *PtrBuffer, size_t Dimen, ... )
- {
- return address( PtrBuffer, Dimen, &Dimen + 1 );
- }
- void* address_pa( void *PtrBuffer, size_t Dimen, size_t *DimenLength )
- {
- return address( PtrBuffer, Dimen, DimenLength );
- }
- size_t dimen_a( void *PtrBuffer )
- {
- struct arrayinfo *TempArray;
- if( !PtrBuffer || !( TempArray = search( PtrBuffer ) ) ) return 0;
- return TempArray->Dimen;
- }
- size_t sizeof_a( void *PtrBuffer )
- {
- struct arrayinfo *TempArray = Head;
- size_t i;
- if( !PtrBuffer ) return 0;
- for( ; TempArray; TempArray = TempArray->Next )
- {
- size_t Product = 1, Sum = 0;
- for( i = 0; i < TempArray->Dimen - 1; ++i )
- Sum += Product *= TempArray->DimenLength[i];
- Product *= TempArray->DimenLength[i];
- if( TempArray->PtrBuffer == ( void** )PtrBuffer )
- return Product * TempArray->ElementSize;
- for( i = 0; i < Sum; ++i )
- if( TempArray->PtrBuffer[i] == PtrBuffer )
- {
- size_t j;
- size_t TempSum = 0, TempPrdct = 1;
- for( j = 0; j < TempArray->Dimen - 1; ++j )
- {
- TempSum += TempPrdct *= TempArray->DimenLength[j];
- Product /= TempArray->DimenLength[j];
- if( TempSum > i ) return Product * TempArray->ElementSize;
- }
- }
- }
- return 0;
- }
- size_t sizeof_pa( void *PtrBuffer, size_t Dimen, size_t *DimenLength )
- {
- return size( PtrBuffer, Dimen, DimenLength );
- }
- size_t sizeof_va( void *PtrBuffer, size_t Dimen, ... )
- {
- return size( PtrBuffer, Dimen, &Dimen + 1 );
- }
- size_t* dimenlen_a( void *PtrBuffer, size_t *DimenLength )
- {
- struct arrayinfo *TempArray;
- if( !PtrBuffer || !( TempArray = search( PtrBuffer ) ) ) return NULL;
- memcpy( DimenLength, TempArray->DimenLength, TempArray->Dimen );
- return DimenLength;
- }
- size_t elmntsize_a( void *PtrBuffer )
- {
- struct arrayinfo *TempArray;
- if( !PtrBuffer || !( TempArray = search( PtrBuffer ) ) ) return 0;
- return TempArray->ElementSize;
- }
- void delete_a( void *PtrBuffer )
- {
- struct arrayinfo *TempArray, **TempNext = &Head;
- if( !PtrBuffer ) return;
- for( TempArray = Head; TempArray ; TempArray = TempArray->Next )
- {
- if( TempArray->PtrBuffer == PtrBuffer ) break;
- TempNext = &TempArray->Next;
- }
- if( !TempArray ) return;
- free( TempArray->ElementAddr );
- free( TempArray->PtrBuffer );
- *TempNext = TempArray->Next;
- free( TempArray );
- return;
- }
- void delete_all()
- {
- struct arrayinfo *TempArray = Head, *TempNext;
- for( ; TempArray; TempArray = TempNext )
- {
- TempNext = TempArray->Next;
- free( TempArray->ElementAddr );
- free( TempArray->PtrBuffer );
- free( TempArray );
- }
- }
- static void* newarray( size_t ElementSize, size_t Dimen, size_t *DimenLength, bool Flag )
- {
- size_t i, Product = 1, Sum = 0;
- struct arrayinfo *TempArray;
- char *TempElement;
- void ** TempBuffer;
- if( !ElementSize || !Dimen ) return NULL;
- for( i = 0; i < Dimen; ++i )
- if( !DimenLength[i] ) return NULL;
- for( i = 0; i < Dimen - 1; ++i )
- Sum += Product *= DimenLength[i];
- Product *= DimenLength[Dimen-1] * ElementSize;
- if( Flag )
- TempElement = ( char* )malloc( Product * sizeof( char ) );
- else TempElement = ( char* )calloc( Product, sizeof( char ) );
- if( Dimen != 1 )
- TempBuffer = ( void** )malloc( Sum * sizeof( void* ) );
- else TempBuffer = ( void** )TempElement;
- TempArray = ( struct arrayinfo * )malloc( sizeof( struct arrayinfo ) + Dimen * sizeof( size_t ) );
- if( !TempElement || !TempBuffer || !TempArray )
- {
- free( TempElement );
- if( Dimen != 1 ) free( TempBuffer );
- free( TempArray );
- return NULL;
- }
- build( TempBuffer, TempElement, ElementSize, DimenLength, 0, Dimen );
- TempArray->ElementAddr = TempElement;
- TempArray->PtrBuffer = TempBuffer;
- TempArray->ElementSize = ElementSize;
- TempArray->DimenLength = &TempArray->Dimen + 1;
- memcpy( TempArray->DimenLength, DimenLength, Dimen * sizeof( size_t ) );
- TempArray->Dimen = Dimen;
- TempArray->Next = Head;
- Head = TempArray;
- return ( void* )TempBuffer;
- }
- static void** build( void **PtrBuffer, char *ElementAddr, size_t ElementSize,
- size_t *DimenLength, size_t CurDimen, size_t Dimen )
- {
- size_t i;
- if( CurDimen == Dimen - 1 ) return ( void** )ElementAddr;
- for( i = 0; i < DimenLength[CurDimen]; ++i )
- {
- size_t j;
- size_t Product = 1;
- void **NextPtr;
- char *NextData;
- for( j = 0; j <= CurDimen; ++j )
- Product *= DimenLength[j];
- NextPtr = PtrBuffer + Product + i * DimenLength[CurDimen + 1];
- Product = 1;
- for( j = CurDimen + 1; j < Dimen; ++j )
- Product *= DimenLength[j];
- NextData = ElementAddr + i * Product * ElementSize;
- PtrBuffer[i] = ( void* )build( NextPtr, NextData, ElementSize,
- DimenLength, CurDimen + 1, Dimen );
- }
- return PtrBuffer;
- }
- static void process( struct arrayinfo *TempArray, size_t CurDimen,
- size_t *DimenLength, void ( *CallBack )(void*, size_t* ) )
- {
- size_t i;
- for( i = 0; i < TempArray->DimenLength[CurDimen]; ++i )
- {
- DimenLength[CurDimen] = i;
- if( CurDimen == TempArray->Dimen - 1 )
- CallBack( TempArray->PtrBuffer, DimenLength );
- else process( TempArray, CurDimen + 1, DimenLength, CallBack );
- }
- return;
- }
- static struct arrayinfo* search( void *PtrBuffer )
- {
- struct arrayinfo *TempArray = Head;
- for( ; TempArray; TempArray = TempArray->Next )
- if( TempArray->PtrBuffer == PtrBuffer )
- return TempArray;
- return NULL;
- }
- static void* address( void *PtrBuffer, size_t Dimen, size_t *DimenLength )
- {
- size_t i, Sum = 0, Product = 1;
- struct arrayinfo *TempArray;
- if( ( Dimen && !DimenLength )
- || !PtrBuffer
- || !( TempArray = search( PtrBuffer ) )
- || TempArray->Dimen < Dimen
- ) return NULL;
- for( i = 0; i < Dimen; ++i )
- if( DimenLength[i] >= TempArray->DimenLength[i] ) return NULL;
- if( !Dimen ) return ( void* )TempArray->ElementAddr;
- for( i = 0; i < TempArray->Dimen; ++i )
- Product *= TempArray->DimenLength[i];
- for( i = 0; i < Dimen; ++i )
- Sum += DimenLength[i] * ( Product /= TempArray->DimenLength[i] );
- return TempArray->ElementAddr + Sum * TempArray->ElementSize;
- }
- static size_t size( void *PtrBuffer, size_t Dimen, size_t *DimenLength )
- {
- struct arrayinfo *TempArray;
- size_t i, Product = 1;
- if( ( Dimen && !DimenLength )
- || !PtrBuffer
- || !( TempArray = search( PtrBuffer ) )
- || TempArray->Dimen < Dimen
- ) return 0;
- for( i = 0; i < Dimen; ++i )
- if( DimenLength[i] >= TempArray->DimenLength[i] )
- return 0;
- if( !Dimen )
- {
- for( i = 0; i < TempArray->Dimen; ++i )
- Product *= TempArray->DimenLength[i];
- return Product * TempArray->ElementSize;
- }
- for( i = Dimen; i < TempArray->Dimen; ++i )
- Product *= TempArray->DimenLength[i];
- return Product * TempArray->ElementSize;
- }
- #ifdef __cplusplus
- }
- #endif