JustSomeGuy said:
I have a need to make an applicaiton that uses a variable number of nested
for loops.
for now I'm using a fixed number:
for (z=0; z < Z; ++z)
for (y=0; y < Y; ++y)
for (x=0; x < X; ++x)
The thing is there could be less or more nested loops necessary.
How can I write this such that the number of for loops is a variable?
How about creating an n dimensional iterator.
Below is somthing I just wrote it's far from a complete system but it
gives you an idea of what you can do. (no range checks etc etc). I'm
not even sure I would model it this way, it's the first thing that came
to mind.
There are all kinds of optimizations you can make if the sizes of the
dimensions are constant.
The code below is very generic and hence not optimal. If your app is a
heavy numerical application, you'll need some hooks to do things more
optimally.
#include <vector>
#include <iostream>
#include <iterator>
#include <algorithm>
//
// nDimensional describes the sizes for each dimension
//
class nDimensional
{
public:
// this contains the dimensions
const int * m_dim_siz;
int m_dim_n;
// constructor
nDimensional( const int * dim_siz, int dim_n )
: m_dim_siz( dim_siz ),
m_dim_n( dim_n )
{
}
// number of elements in a system
int NumEntries()
{
if ( m_dim_n == 0 )
{
return 1;
}
int val = * m_dim_siz;
int count = m_dim_n - 1;
for (
const int * ptr = m_dim_siz + 1;
count > 0;
count --, ptr ++
) {
val *= * ptr;
}
return val;
}
};
//
// nDimensionalIterator allows you to iterate over
// all dimensions
//
class nDimensionalIterator
: public std::vector<int>,
public nDimensional
{
public:
bool m_finished;
nDimensionalIterator( const std::vector<int> & sizes )
: nDimensional( & sizes[0], sizes.size() ),
std::vector<int>( sizes.size(), 0 ),
m_finished( false )
{
}
nDimensionalIterator( const int * sizes, int dimensions )
: nDimensional( sizes, dimensions ),
std::vector<int>( dimensions, 0 ),
m_finished( false )
{
}
nDimensionalIterator( const nDimensional & dims )
: nDimensional( dims ),
std::vector<int>( dims.m_dim_n, 0 ),
m_finished( false )
{
}
//
// post increment iterator
//
inline nDimensionalIterator & operator ++()
{
std::vector<int>::iterator val_iter = begin();
std::vector<int>::iterator val_iter_end = end();
const int * size_iter = m_dim_siz;
while ( val_iter != val_iter_end )
{
int value = ++( * val_iter );
if ( value < * size_iter )
{
m_finished = false;
return * this;
}
* val_iter = 0;
size_iter ++;
val_iter ++;
}
m_finished = true;
return * this;
}
//
// a linear index
//
int Index() const
{
if ( m_dim_n == 0 )
{
return 0;
}
std::vector<int>::const_iterator val_iter = begin();
int index = * ( val_iter ++ );
int val = * m_dim_siz;
int count = m_dim_n - 1;
for (
const int * ptr = m_dim_siz + 1;
count > 0;
count --, ptr ++, val_iter ++
) {
index += ( * val_iter ) * val;
val *= * ptr;
}
return index;
}
};
//
// This defines an n dimensional matrix.
//
template <typename T>
class nDimensionalMatrix
: public std::vector<T>,
public nDimensional
{
public:
nDimensionalMatrix( const int * sizes, int dimensions )
: nDimensional( sizes, dimensions ),
std::vector<T>(
nDimensional( sizes, dimensions ).NumEntries(),
T()
)
{
}
T & operator []( const nDimensionalIterator & iter )
{
return (* static_cast< std::vector<T> *>(this))[ iter.Index() ];
}
};
//
// a 4 dimensional system 4x3x2x4
//
int dim_siz[] = { 4, 3, 2, 4 };
//
// some example code
//
void foo()
{
// create a 4x3x2x4 (4 dimensional) float matrix
//
nDimensionalMatrix< float > f( dim_siz, sizeof( dim_siz )/
sizeof(* dim_siz ) );
float val = 0;
// initialize the matrix
for (
nDimensionalIterator iter( dim_siz, sizeof( dim_siz )/
sizeof(* dim_siz ) );
! iter.m_finished;
++ iter
) {
f[ iter ] = val;
val += 1.1f;
std::copy(iter.begin(), iter.end(),
std:
stream_iterator<int>(std::cout, " "));
std::cout << " index = " << iter.Index();
std::cout << " set to " << f[ iter ];
std::cout << "\n";
}
for (
nDimensionalIterator iter( f );
! iter.m_finished;
++ iter
) {
std::copy(iter.begin(), iter.end(),
std:
stream_iterator<int>(std::cout, " "));
std::cout << " index = " << iter.Index();
std::cout << " f[ iter ] is " << f[ iter ];
std::cout << "\n";
}
}
// test
int main()
{
foo();
}