1

I state that I am a C programmer more than a C++ programmer (with C++ I'm a beginner: p)

I've written a C++ class to manage multidimensional arrays (n-dimensional matrices). This class has methods to create the matrix and to set and to get value in/from the matrix (also to set the position inside it).

I've two issues:

  • With the idea that I want a syntax similar to m(x,y,z, ..., n) to set/get values some methods use the ellipsis E.G.: getValue(int dim0,...); But I think it's dangerous; although in the functions I've written I assume that the passed arguments are the same number of the matrix dimensions, the user might pass less values than necessary, then he will have no compiler errors or warnings.

  • I want to be able to manage the data type that the matrix cells contain during runtime at matrix creation time (without the use of union and somehow declaring the type). In the class code I've inserted a typedef (for development purposes) which indicates the points where such a modifications would/might impact.

For the first issue I've no ideas better than those implemented. Do you have suggestions?

To solve the second issue, I might think to create overloads for the methods getValue(), setValue() and createMatrix(), but this idea requires some workarounds and probably to rewrite completely each single method and then to have more copies of the "same" code (I want avoid that with the intent to have a better maintenance capability) , moreover this solution doesn't grant to manage all possible types. I'm thinking about the use of templates, but I don't understand if such a way is the better way. Do you have suggestions?

These are the main methods to be modified to solve both the issues:

methods in the CPP module:

int Matrix::createMatrix(Matrix::value_t *values)
{
    int retval=1;

    if ( (m_values!=NULL || !numOfDim()) && valAreIntAlloc()==true ) {
        return 0;
    }

    if (values!=NULL) {
        m_values=values;
        setValAreIntAlloc(false);
    } else {
        setValAreIntAlloc(true);
        // Compute the number of elements for
        // the whole matrix
        for(int i=0;i<numOfDim();i++) {
            retval*=numOfElemInDim(i);
            if (!retval) {
                //Indicate that a dimension has a 0 value
                //as numOfElemInDim! The caller will be allowed
                //to know the such a dimension using: -retval-1;
                retval=-(i+1);
                break;
            }
        }
        if (retval>0) {
            m_values=new value_t[retval];
            if (m_values!=NULL)
                retval=0;
        }
    }

    //Returns:
    //1 if values is an external allocated memory,
    //0 if nothing has been allocated or the
    //m_values is already set as internal!
    //elsewhere the number of allocated elements.
    return retval;
}

void Matrix::setPositions(int dim0, ...)
{
    va_list vl;
    va_start(vl,dim0);

    setPosition(0,dim0);
    for (int i=1;i<numOfDim();i++)
        setPosition(i,va_arg(vl,int));

    va_end(vl);
}

Matrix::value_t Matrix::getValue(int dim0, ...)
{
    va_list vl;
    va_start(vl,dim0);

    setPosition(0,dim0);
    for (int i=1;i<numOfDim();i++)
        setPosition(i,va_arg(vl,int));

    va_end(vl);
    return getValue();
}

void Matrix::setValue(Matrix::value_t value, int dim0, ...)
{
    va_list vl;
    va_start(vl,dim0);

    setPosition(0,dim0);
    for (int i=1;i<numOfDim();i++)
        setPosition(i,va_arg(vl,int));

    va_end(vl);
    setValue(value);
}

methods inline in the Header file:

inline value_t getValue() { return m_values[posInValueVector()]; }

inline void setValue(value_t value) { m_values[posInValueVector()]=value; }

The methods setPosition(), setPositions() are used to set the coordinates of the matrix cell to be managed; the method posInValueVector() computes the index inside the vector (created by the method createMatrix) of the matrix cell using the coordinates.

Here al the code:

main.cpp

#include <iostream>
#include <cstdio>

#include "matrix.h"

using namespace std;

int main()
{
    Matrix m(3);
    m.setNumOfElemInDims(4,5,6);
    m.createMatrix();

    for(int i=0;i<m.numOfElemInDim(0);i++)
        for(int j=0;j<m.numOfElemInDim(1);j++)
            for(int k=0;k<m.numOfElemInDim(2);k++)
                m.setValue(i*100+j*10+k,i,j,k); // matrix(i,j,k)=i*100+j*10+k

    //printout the values of all matrix(i,j,k) cells
    //I've used the printf because I find it very simple!
    for(int i=0;i<m.numOfElemInDim(0);i++)
        for(int j=0;j<m.numOfElemInDim(1);j++)
            for(int k=0;k<m.numOfElemInDim(2);k++)
                printf("(%d,%d,%d)=%03.0f\n",i,j,k,m.getValue(i,j,k));
}

matrix.h

#ifndef MATRIX_H
#define MATRIX_H

class Matrix
{
public:
    typedef double value_t;

    Matrix();
    Matrix(int numOfDim, int *nelem=NULL);
    ~Matrix();

    inline unsigned int numOfDim() const {return m_numOfDim;}

    int setNumOfDim(int numOfDim, int *nelem=NULL);

    inline  int numOfElemInDim(int dim) const
        {return (dim<numOfDim())?m_numOfElemInDim[dim]:-1; }

    int setNumOfElemInDim(int dim, int nelem);
    int setNumOfElemInDims(int el0, ...);

    int createMatrix(value_t *values);
    inline int createMatrix() { return createMatrix(NULL); }

    inline bool valAreIntAlloc() const {return m_valAreIntAlloc;}
    inline void setValAreIntAlloc(bool valAreIntAlloc)
        {m_valAreIntAlloc = valAreIntAlloc;}

    inline int position(int dim) const {return m_positions[dim];}
    inline void setPosition(int dim,int value)
        {m_positions[dim] = value;}

    inline void setPositions(int *positions)
        {for(int i=0;i<numOfDim();i++) setPosition(i,positions[i]);}

    void setPositions(int dim0, ...);

    inline value_t getValue() { return m_values[posInValueVector()]; }

    value_t getValue(int dim0, ...);

    inline void setValue(value_t value) { m_values[posInValueVector()]=value; }
    void setValue(value_t value, int dim0, ...);

private:
    int m_numOfDim;
    int * m_numOfElemInDim;
    int * m_positions;

    value_t * m_values;
    bool m_valAreIntAlloc;

    int posInValueVector();
};

#endif // MATRIX_H

matrix.cpp

#include <iostream>
#include <cstdarg>

#include "matrix.h"

#define __INIT__(v)\
m_numOfDim(v),\
m_numOfElemInDim(NULL),\
m_positions(NULL),\
m_values(NULL),\
m_valAreIntAlloc(false)

Matrix::Matrix():
    __INIT__(0)
{
}

Matrix::~Matrix()
{
    if (m_numOfElemInDim!=NULL)
        delete m_numOfElemInDim;

    if (m_positions!=NULL)
        delete m_positions;

    if (valAreIntAlloc() && m_values!=NULL)
        delete m_values;
}

Matrix::Matrix(int numOfDim, int *nelem):
    __INIT__(numOfDim)
{
    setNumOfDim(numOfDim,nelem);
}

int Matrix::setNumOfDim(int numOfDim, int *nelem)
{
    int retval=0;

    m_numOfDim = numOfDim;

    m_numOfElemInDim = new int[numOfDim];
    if (m_numOfElemInDim==NULL)
        return 1;

    m_positions = new int[numOfDim];
    if (m_positions==NULL)
        return 2;

    for(int i=0;i<m_numOfDim;i++) {
        if (setNumOfElemInDim(i,(nelem==NULL)?0:nelem[i])) {
            retval=-1;
            break;
        }
        setPosition(i,0);
    }

    return retval; //All ok!
}

int Matrix::setNumOfElemInDim(int dim,int nelem)
{
    int retval=-1;

    if (dim<numOfDim()) {
        m_numOfElemInDim[dim] = nelem;
        retval=0;
    }

    return retval;
}

int Matrix::setNumOfElemInDims(int el0, ...)
{
    va_list vl;
    va_start(vl,el0);

    setNumOfElemInDim(0,el0);
    for (int i=1;i<numOfDim();i++)
        setNumOfElemInDim(i,va_arg(vl,int));

    va_end(vl);
    return 0;
}

int Matrix::createMatrix(Matrix::value_t *values)
{
    int retval=1;

    if ( (m_values!=NULL || !numOfDim()) && valAreIntAlloc()==true ) {
        return 0;
    }

    if (values!=NULL) {
        m_values=values;
        setValAreIntAlloc(false);
    } else {
        setValAreIntAlloc(true);
        // Compute the number of elements for
        // the whole matrix
        for(int i=0;i<numOfDim();i++) {
            retval*=numOfElemInDim(i);
            if (!retval) {
                //Indicate that a dimension has a 0 value
                //as numOfElemInDim! The caller will be allowed
                //to know the such a dimension using: -retval-1;
                retval=-(i+1);
                break;
            }
        }
        if (retval>0) {
            m_values=new value_t[retval];
            if (m_values!=NULL)
                retval=0;
        }
    }

    //Returns:
    //1 if values is an external allocated memory,
    //0 if nothing has been allocated or the
    //m_values is already set as internal!
    //elsewhere the number of allocated elements.
    return retval;
}

void Matrix::setPositions(int dim0, ...)
{
    va_list vl;
    va_start(vl,dim0);

    setPosition(0,dim0);
    for (int i=1;i<numOfDim();i++)
        setPosition(i,va_arg(vl,int));

    va_end(vl);
}

Matrix::value_t Matrix::getValue(int dim0, ...)
{
    va_list vl;
    va_start(vl,dim0);

    setPosition(0,dim0);
    for (int i=1;i<numOfDim();i++)
        setPosition(i,va_arg(vl,int));

    va_end(vl);
    return getValue();
}

void Matrix::setValue(Matrix::value_t value, int dim0, ...)
{
    va_list vl;
    va_start(vl,dim0);

    setPosition(0,dim0);
    for (int i=1;i<numOfDim();i++)
        setPosition(i,va_arg(vl,int));

    va_end(vl);
    setValue(value);
}

int Matrix::posInValueVector()
{
    int pos=position(0);

    for(int i=1;i<numOfDim();i++)
        pos=pos*numOfElemInDim(i)+position(i);

    return pos;
}
Sir Jo Black
  • 2,024
  • 2
  • 15
  • 22
  • Maybe by using, one way or another, [Boost variant](http://www.boost.org/doc/libs/1_58_0/doc/html/variant.html) or [Boost any](http://www.boost.org/doc/libs/1_58_0/doc/html/any.html)? – Some programmer dude May 02 '15 at 23:37
  • In this code I don't use boost! I don't have a good knowledge of boost. Do you think I may use it to solve the issues I indicate? – Sir Jo Black May 02 '15 at 23:41
  • You can use non type template parameters to set the number of required arguments, or at least assert they are correct at runtime if that's too complex. – OMGtechy May 02 '15 at 23:42
  • Another argument not too clear for me! I've to study the templates!!! @OMGtechy, Do you means that using such a templates I can obtain that the user cannot use a wrong number of parameter? – Sir Jo Black May 02 '15 at 23:49
  • @SergioFormiggini yes – OMGtechy May 02 '15 at 23:49
  • @OMGtechy. Can you show me a simple example? I think that is also possible to verify the number of argument passed by ellipsis at runtime, but It's not so simple as it seems! – Sir Jo Black May 02 '15 at 23:53
  • I suspect most of your goals are bad ideas. Why would you eant to specify the data stored at runtime? Why not via template parameter? How often do you need to make the number of dimensions runtime dynamic? These are all possible, but each of them throws out type safety to a greater or lesser degree, and seemingly needlessly. Second, as a general rule in C++, calling `new` or `malloc` in "client" code usually means you are doing something wrong: use `unique_ptr` and `vector` to manage dynamic buffer lifetime. – Yakk - Adam Nevraumont May 03 '15 at 00:39
  • @Yakk. My goal is not to modify the behaviour of a created matrix at runtime. I want to have the capability to choise what type of element to manage at runtime. Now I'm following the idea to use a memory area and to cast it when I read/write the cells. I'm adding a property which represents the cell dimension and then I use it. – Sir Jo Black May 03 '15 at 00:57
  • It's probably a bad idea to have any sort of `setPositions` thing in your class. It is also probably a bad idea to manage the data type at run time *at the level of an individual cell*. You actually want to templatize your matrix class over your data type, and then probably templatize the entire matrix handling component. You then instantiate your templates with all the data types you will need, and select the right instance at run time. – n. m. could be an AI May 03 '15 at 06:18
  • @n.m. Yes I begin to understand. See the the reply of the user 6502 in this question: http://stackoverflow.com/questions/30010444/how-to-convert-a-define-in-a-template-variadic – Sir Jo Black May 03 '15 at 06:25
  • @n.m. The type is not managed at single cell level! ...It's managed for all the cells when the method createMatrix is called! The setPositions is a method to point the cell I want read or write. – Sir Jo Black May 03 '15 at 06:28
  • @n.m. An issue I've is to run this code on an MCU, then I need it uses memory without using new (although the code here use it) and uses a contiguous memory area without padding or other stuff. (But this is not matter in this question) – Sir Jo Black May 03 '15 at 06:32
  • "setPositions is a method to point the cell I want read or write". Why a two-step process? Read/write the cell with one function that gets all the cell coordinates at once, don't store them in the matrix. – n. m. could be an AI May 03 '15 at 07:57
  • setPosition is an inline function, is only the computation of the index ... The compiler should compile it inside the functions that read or get. If you look at the two macros (orrible) that I've indicated in my reply below you see that all the function involved are inline! – Sir Jo Black May 03 '15 at 08:02
  • "It's managed for all the cells when the method createMatrix is called". If your cell is a union (or any comparable thing such as boost::variant or booost::any), then you do manage it on the cell level, and then hide that fact behind an interface such as `createMatrix`. While it's OK to hide complexity behind an interface, in your case it's not needed in the first place. You want to have bigger things (a matrix as a whole, or the entire matrix handling component) packed in a union-like thing. – n. m. could be an AI May 03 '15 at 08:03
  • It doesn't matter if it's inline or not, the bad thing is having the coordinate *data* in the matrix class. A matrix is a collection of cells. It doesn't have any built-in notion of distinguished "current cell" and you are better off not imposing one artificially. – n. m. could be an AI May 03 '15 at 08:13
  • The method createMatrix doesn't calls the method setPosition nor the method setPositions! ... But the code has a lot of problems, this is true! – Sir Jo Black May 03 '15 at 08:14
  • Ok, the properties m_position may be avoided, but basically setPosition is used to compute the pointer to read or write a cell! I used it before to use the variadic methods to have a function to set the index to read or write. I might use it to compute an handle and then use it to read or write if I don't use the variadic ... – Sir Jo Black May 03 '15 at 08:21
  • @n.m. How do you think to access the cells whereas you don't know the number of dimensions the matrix may manage and you don't think to use variadic methods? – Sir Jo Black May 03 '15 at 08:25
  • @n.m. The idea was to have something similar at the seek function for the files! – Sir Jo Black May 03 '15 at 08:28
  • @n.m. However I understand your point of view! For sure to store that data in the object has no mean for the matrix object. But my idea was that (not using variadic) I need a memory where the position data is stored before to read or write, this memory (obviously) may be outside the object and following what you say it would be better it be in an another "place"!!! ... I go to sleep that is all the night that I'm near the PC! – Sir Jo Black May 03 '15 at 08:39

2 Answers2

1

I think the solution below, that is an answer at another my question, is a beautiful solution and implements all what I wanted, but I used a lot of code ... It's based on C++11 variadic templates.

A dubt I've about this code is the way in whose it manages the memory. My will would be the memory is a single block, I'm almost sure this code don't do that. However is a good and fast code!

template<typename T, int ...rest>
struct matrix;

template<typename T, int n>
struct matrix<T, n> {
    T data[n];
    matrix() {
        for (int i=0; i<n; i++) {
            data[i] = T(0);
        }
    }
    T& operator[](int index) { return data[index]; }
};

template<typename T, int n, int ...rest>
struct matrix<T, n, rest...> {
    matrix<T, rest...> data[n];
    matrix<T, rest...>& operator[](int index) { return data[index]; }
};

that can be used with:

matrix<double, 10, 9, 4> m;
for (int i=0; i<10; i++) {
    for (int j=0; j<9; j++) {
        for (int k=0; k<4; k++) {
            m[i][j][k] = i + j*2.718 + k*3.1416;
        }
    }
}
Community
  • 1
  • 1
Sir Jo Black
  • 2,024
  • 2
  • 15
  • 22
  • It would be much better with template typedef.Just change your `matrix` to `matrix_impl` - and do not define any operation within. Only types: `template struct matrix_impl { using type = T[n]; };` and `template struct matrix_impl { using type = typename T::type[n]; };` The typedef: `template using matrix=typename matrix_impl::type;` – PiotrNycz May 04 '15 at 14:27
  • I'm new at these kind of objects (templates)! I'm a C programmer more than a C++ programmer, I'm able to code using C++, but I've a lot to study to understand the templates! Then I don't understand the advantage of your proposal, probably because for me is still not very clear the template I proposed (that isn't a code written by me) – Sir Jo Black May 04 '15 at 17:52
  • I was thinking about this: "My will would be the memory is a single block", In this way you can be sure - since `Matrix` would identical to `T[1][2][3]`... – PiotrNycz May 04 '15 at 18:42
0

I've found a solution, but I don't fully enjoy it!

I've modified the createMatrix(), getValue() and setValue() methods and inserted two defines the accomplish the function with the ellipsis. The idea was to use a template. Below are the defines that I would like they be templates:

#define __MATRIX_GETVALUE(C,T,val,dim0...) \
    va_list vl; \
    va_start(vl,dim0); \
    C->setPositions(vl,dim0); va_end(vl);\
    val = *((T *)(m_values)+posInValueVector())

#define __MATRIX_SETVALUE(C,T,val,dim0...) \
    va_list vl; \
    va_start(vl,dim0); \
    C->setPositions(vl,dim0); va_end(vl);\
    *((T *)(m_values)+posInValueVector())=val

In the following the modified code:

main.cpp

#include <iostream>
#include <cstdio>

#include "matrix.h"

using namespace std;

int main()
{
    Matrix m(3);
    m.setNumOfCellForDims(4,5,6);

    puts("-----------------> DBL m(i,j,k)=i*100+j*10+k+111 -------------------");
    m.createMatrix(sizeof(double));
    for(int i=0;i<m.numOfCellInDim(0);i++)
        for(int j=0;j<m.numOfCellInDim(1);j++)
            for(int k=0;k<m.numOfCellInDim(2);k++)
                m.setValue((double)i*100+j*10+k+111,i,j,k); // matrix(i,j,k)=i*100+j*10+k

    //printout the values of all matrix(i,j,k) cells
    double valdbl;
    for(int i=0;i<m.numOfCellInDim(0);i++)
        for(int j=0;j<m.numOfCellInDim(1);j++)
            for(int k=0;k<m.numOfCellInDim(2);k++)
                printf("(%d,%d,%d)=%03.0f\n",i,j,k,m.getValue(valdbl,i,j,k));

    puts("-----------------> INT m(i,j,k)=i*100+j*10+k+222 -------------------");
    m.clearMatrix();
    m.setNumOfDim(3);
    m.setNumOfCellForDims(4,5,6);
    m.createMatrix(sizeof(int));

    for(int i=0;i<m.numOfCellInDim(0);i++)
        for(int j=0;j<m.numOfCellInDim(1);j++)
            for(int k=0;k<m.numOfCellInDim(2);k++)
                m.setValue((int)(i*100+j*10+k+222),i,j,k); // matrix(i,j,k)=i*100+j*10+k

    //printout the values of all matrix(i,j,k) cells
    int valint;
    for(int i=0;i<m.numOfCellInDim(0);i++)
        for(int j=0;j<m.numOfCellInDim(1);j++)
            for(int k=0;k<m.numOfCellInDim(2);k++)
                printf("(%d,%d,%d)=%03d\n",i,j,k,m.getValue(valint,i,j,k));
}

matrix.h

#ifndef MATRIX_H
#define MATRIX_H
#include <cstdarg>
#include <cstring>

#define __MATRIX_GETVALUE(C,T,val,dim0...) \
    va_list vl; \
    va_start(vl,dim0); \
    C->setPositions(vl,dim0); va_end(vl);\
    val = *((T *)(m_values)+posInValueVector())

#define __MATRIX_SETVALUE(C,T,val,dim0...) \
    va_list vl; \
    va_start(vl,dim0); \
    C->setPositions(vl,dim0); va_end(vl);\
    *((T *)(m_values)+posInValueVector())=val

class Matrix
{
public:
    Matrix();
    Matrix(int numOfDim, int *ncell=NULL);
    ~Matrix();

    void clearMatrix();

    inline unsigned int numOfDim() const {return m_numOfDim;}

    int setNumOfDim(int numOfDim, int *ncell=NULL);

    inline  int numOfCellInDim(int dim) const
        {return (dim<numOfDim())?m_numOfCellInDim[dim]:-1; }

    int setNumOfCellForDim(int dim, int ncell);
    int setNumOfCellForDims(int el0, ...);

    int createMatrix(int size, void *values);
    inline int createMatrix(int size) { return createMatrix(size,NULL); }

    inline bool valAreIntAlloc() const {return m_valAreIntAlloc;}
    inline void setValAreIntAlloc(bool valAreIntAlloc)
        {m_valAreIntAlloc = valAreIntAlloc;}

    inline int position(int dim) const {return m_positions[dim];}
    inline void setPosition(int dim,int value)
        {m_positions[dim] = value;}

    inline void setPositions(int *positions)
        {for(int i=0;i<numOfDim();i++) setPosition(i,positions[i]);}

    void setPositions(int dim0, ...);

    inline void * getValue() { return (char *)m_values+posInValueVector(); }

    inline double getValue(double &value)
    { return value=*(double *)(m_values)+posInValueVector(); }

    inline int getValue(int &value)
    { return value=*(int *)(m_values)+posInValueVector(); }

    //void * getValue(int dim0, ...);
    inline double getValue(double &value, int dim0, ...) {
        __MATRIX_GETVALUE(this,double,value,dim0);
        return value;
    }

    inline int getValue(int &value, int dim0, ...) {
        __MATRIX_GETVALUE(this,int,value,dim0);
        return value;
    }

    inline void setValue(double value)
        { *((double *)(m_values)+posInValueVector())=value; }
    inline void setValue(int value)
        { *((int *)(m_values)+posInValueVector())=value; }
    inline void setValue(void *value, int size)
        { memcpy((char *)m_values+posInValueVector(),(char *)value,size); }

    //void setValue(double value, int dim0, ...);
    inline void setValue(double value, int dim0, ...) {
        __MATRIX_SETVALUE(this,double,value,dim0);
    }
    inline void setValue(int value, int dim0, ...) {
        __MATRIX_SETVALUE(this,int,value,dim0);
    }

    inline int cellSize() const {return m_cellSize;}
    inline void setCellSize(int cellSize) {m_cellSize = cellSize;}

private:
    int m_numOfDim;
    int m_cellSize;

    int * m_numOfCellInDim;
    int * m_positions;

    void * m_values;
    bool m_valAreIntAlloc;

    int posInValueVector();

#ifdef MATRIX_CPP
    inline
#endif
    int setPositions(va_list &vl, const int &dim0);
};

#endif // MATRIX_H

matrix.cpp

#define MATRIX_CPP
#include <iostream>

#include "matrix.h"

#define __INIT__(v)\
m_numOfDim(v),\
m_cellSize(0), \
m_numOfCellInDim(NULL),\
m_positions(NULL),\
m_values(NULL),\
m_valAreIntAlloc(false)

Matrix::Matrix():
    __INIT__(0)
{
}

Matrix::~Matrix()
{
    clearMatrix();
}

void Matrix::clearMatrix()
{
    if (m_numOfCellInDim!=NULL)
        delete m_numOfCellInDim;
    m_numOfCellInDim=NULL;

    if (m_positions!=NULL)
        delete m_positions;
    m_positions=NULL;

    if (valAreIntAlloc() && m_values!=NULL)
        delete (char *)m_values;
    m_values=NULL;
}

Matrix::Matrix(int numOfDim, int *ncell):
    __INIT__(numOfDim)
{
    setNumOfDim(numOfDim,ncell);
}

int Matrix::setNumOfDim(int numOfDim, int *ncell)
{
    int retval=0;

    m_numOfDim = numOfDim;

    m_numOfCellInDim = new int[numOfDim];
    if (m_numOfCellInDim==NULL)
        return 1;

    m_positions = new int[numOfDim];
    if (m_positions==NULL)
        return 2;

    for(int i=0;i<m_numOfDim;i++) {
        if (setNumOfCellForDim(i,(ncell==NULL)?0:ncell[i])) {
            retval=-1;
            break;
        }
        setPosition(i,0);
    }

    return retval; //All ok!
}

int Matrix::setNumOfCellForDim(int dim,int ncell)
{
    int retval=-1;

    if (dim<numOfDim()) {
        m_numOfCellInDim[dim] = ncell;
        retval=0;
    }

    return retval;
}

int Matrix::setNumOfCellForDims(int el0, ...)
{
    va_list vl;
    va_start(vl,el0);

    setNumOfCellForDim(0,el0);
    for (int i=1;i<numOfDim();i++)
        setNumOfCellForDim(i,va_arg(vl,int));

    va_end(vl);
    return 0;
}

int Matrix::createMatrix(int size, void *values)
{
    int retval=1;

    setCellSize(size);

    if ( (m_values!=NULL || !numOfDim()) && valAreIntAlloc()==true ) {
        return 0;
    }

    if (values!=NULL) {
        m_values=values;
        setValAreIntAlloc(false);
    } else {
        setValAreIntAlloc(true);
        // Compute the number of cellents for
        // the whole matrix
        for(int i=0;i<numOfDim();i++) {
            retval*=numOfCellInDim(i);
            if (!retval) {
                //Indicate that a dimension has a 0 value
                //as numOfCellInDim! The caller will be allowed
                //to know the such a dimension using: -retval-1;
                retval=-(i+1);
                break;
            }
        }
        if (retval>0) {
            m_values=new char[retval*cellSize()];
            if (m_values!=NULL)
                retval=0;
        }
    }

    //Returns:
    //1 if values is an external allocated memory,
    //0 if nothing has been allocated or the
    //m_values is already set as internal!
    //elsewhere the number of allocated cellents.
    return retval;
}

void Matrix::setPositions(int dim0, ...)
{
    va_list vl;
    va_start(vl,dim0);

    setPositions(vl,dim0);
    va_end(vl);
}

int Matrix::setPositions(va_list &vl,const int &dim0)
{
    setPosition(0,dim0);
    for (int i=1;i<numOfDim();i++)
        setPosition(i,va_arg(vl,int));
}

int Matrix::posInValueVector()
{
    int pos=position(0);

    for(int i=1;i<numOfDim();i++)
        pos=pos*numOfCellInDim(i)+position(i);

    return pos;
}
Sir Jo Black
  • 2,024
  • 2
  • 15
  • 22