Store functions, with variable function signatures, inside an array

Hello,

I've got an apparently 'simple' question. I have a couple of functions to create animations in my LED cube. Consider the following function prototypes:

 void rain(uint16_t time, LedCube &cubeRef, uint8_t rainVoxels = 2,  uint8_t floorVoxels = 4, uint16_t rainDelay = 75, bool invertDirection = false);
void slantingLines(uint16_t time, LedCube &cubeRef, uint16_t shiftDelay = 75, bool invertDirection = false);
void cornerCube(uint16_t time, LedCube &cubeRef, uint16_t resizeDelay = 75, uint8_t minimumCubeSize = 2);
void sineWave(uint16_t time, LedCube &cubeRef, uint16_t shiftDelay = 75, uint8_t period = 16);

Now normally you would simply call that function and provide the arguments with your own values, for example:

void loop()
{
  /* Rain parameters
  - time: 10000ms
  - cubeRef: cube
  - rainVoxels: 2
  - floorVoxels: 10
  - rainDelay: 55ms
  - invertDirection: false
  */
  rain(10000, cube, 2, 10, 55, false);

  /* Sine wave parameters
  - time: 10000ms
  - cubeRef: cube
  - shiftDelay: 55ms
  - period: 14
  */
  sineWave(10000, cube, 55, 14);

  // ETC....
}

Now I want to do something different. I want to add the function, with the provided argument values, to an array (or another data type). So I know you can use so called function-pointers. The problem with function-pointers is that it only represents a fixed signature of the function. As this function-pointer:void (*functionPtr)(uint16_t, LedCube&, uint8_t, uint8_t, uint16_t, bool); is only valid for the function "rain" as that particular function matches the signature of the function pointer.
Now it isn't possible to create an array based on functions with a different set of arguments. Does anybody know some sort of solution to this problem?

I'm currently stuck with the idea to do this for every single function:

void rainWrapper(void)
{
    /* Rain parameters
  - time: 10000ms
  - cubeRef: cube
  - rainVoxels: 2
  - floorVoxels: 10
  - rainDelay: 55ms
  - invertDirection: false
  */
  rain(10000, cube, 2, 10, 55, false);
}
void sineWaveWrapper(void)
{
 /* Sine wave parameters
  - time: 10000ms
  - cubeRef: cube
  - shiftDelay: 55ms
  - period: 14
  */
  sineWave(10000, cube, 55, 14);
}

With this every function now has the same signature, thus a function-pointer array can be used. This should be one solution, however I think it should be possible to do it easier. I'm looking forward to any feedback :)!

Greetings,

Mike

Google "array of pointers to functions" and see if that helps.

As I mentioned in my first post, this is possible ONLY if all the functions have the same signature as the function pointer array. Which in my case isn't applicable (except the function wrapping I suggested).

Example of the problem:

int multiply(int a, int b);
int divide(int a, int b);
int sum(int a, int b, int c);

int (*functionPointers[3]) (int a, int b);

void setup()
{
  functionPointers[0] = multiply;
  functionPointers[1] = divide;
  functionPointers[2] = sum; // Oops!!! Error, signature does not match!
}

What advantage do you see being able to call the nth function in an array, versus calling function XXX because some counter is n?

@ PaulS

Right now I’m creating a library for LED cubes (ranging from 4x4x4 to 8x8x8). I want to do two things. First off I want to create an random animation generator without the user have to implement it himself/herself. So the user only should add the functions to an array, and then can decide if he/she want them to play in sequence, random order, etc. How to do it exactly, don’t pin me on that as I didn’t figured it out all the way yet :smiley:

Second, the animations are now created with the use of the delay function. I want to remove this delay by building some kind of state machine, where the frame is updated after XXX milliseconds. To do this you can’t simply call the functions like this:

void loop()
{
  /* Rain parameters
  - time: 10000ms
  - cubeRef: cube
  - rainVoxels: 2
  - floorVoxels: 10
  - rainDelay: 55ms
  - invertDirection: false
  */
  rain(10000, cube, 2, 10, 55, false);

  /* Sine wave parameters
  - time: 10000ms
  - cubeRef: cube
  - shiftDelay: 55ms
  - period: 14
  */
  sineWave(10000, cube, 55, 14);

  // ETC....
}

And a function looks like this:

void sineWave(uint16_t time, LedCube &cubeRef, uint16_t shiftDelay /* = 75 */, uint8_t period /* = 16 */)
{
  // Voxel coordinates
  uint8_t z;
  uint8_t x;
  uint8_t y;

  // For loop iterators
  uint16_t i;
  uint8_t j;

  // Other variables
  uint8_t timeCount = 0;
  float sineOffset = (cubeRef.getCubeSize() - 1) / 2.0;
  float omega = (2.0 * PI) / (float)period;

  startTime = millis();
  while(millis() - startTime < time)
  {
    for(i = timeCount; i<(timeCount + cubeRef.getCubeSize()); i++)
    {
      z = round(sineOffset * sin(i * omega) + sineOffset); // Calculate z position
      x = i - timeCount;
      for(j = 0; j<cubeRef.getCubeSize(); j++)
      {
        y = j;
        cubeRef.voxel(z, x, y, 1);
      }
    }
    cubeRef.drawVoxels();
    delay(shiftDelay);
    timeCount++;
    if(timeCount >= period)
      timeCount = 0;
  }
  cubeRef.clearAllVoxels();
}

Why do I want to remove the delay? Simply because, I’ll need interaction with the serial port to support bluetooth/usb communication to a laptop/Android device.

If you really want different signatures, you will need a switch-case structure.

If you can get all the functions the same - you might be able to use a union or something - you can use an array. You might also be able to use a void func (void) pointer and cast it to your declaration.

Have you investigated va_list and the ellipsis operator?

have you tried to make a array of unions to function pointers?

a union is a sort of struct with every member in the same memory location instead of side by side.
http://www.cplusplus.com/doc/tutorial/other_data_types

that said a switch case would probably easier to maintain.
instead of the function the user has to select a number..

I'm baffled as to what that buys you.... But, you can define functions, each of which takes no arguments, and makes the necessary function call with arguments. Put pointers to those functions in an array, or use a switch statement to call them.

Regards,
Ray L.

@KeithRB

If you really want different signatures, you will need a switch-case structure.

@robtillaart

that said a switch case would probably easier to maintain. instead of the function the user has to select a number

@RayLivingston

Put pointers to those functions in an array, or use a switch statement to call them.

Ok a switch case structure would be possible to call different functions. However then I’m still dealing with the problem that every function needs different argument values. The user that uses my library still has to somehow provide those argument values before the functions are called. One way would be to use the ellipsis operator what @econjack suggested. However that can become messy if you provide a wrong number of arguments etc…

@KeithRB

If you can get all the functions the same - you might be able to use a union or something - you can use an array.

@robtillaart

have you tried to make a array of unions to function pointers?

a union is a sort of struct with every member in the same memory location instead of side by side.
http://www.cplusplus.com/doc/tutorial/other_data_types

An union array is possible to store functions with a different number of arguments. But also here the user of my library first have to specify the argument values. So that means besides I store the functions inside an array of unions, I still have to store the user specified argument values, which ultimately differ in numbers because the functions (and their arguments) are different between each other.

Sorry if I completely misunderstood you guys, but I’m really afraid this won’t be the solution.

However then I'm still dealing with the problem that every function needs different argument values.

Two pointers - one to a function, the other to a structure containing the parameters.
Now, each function has an identical prototype - a void function accepting a pointer to struct.

For this XML like structures are invented, (Yes you need a parser)

<functions>
  <function A 1 2 3 />
  <function B 4 5 6 7 8 9 />
  <function C "Hello world" 42>
  <etc>
</functions>

or just

A 1 2 3
B 4 5 6.789
C "Hello world" 42

the parser read a line until “\n” (optionally from Serial or EEPROM or SD card)
the first field (space, comma, TAB whatever separator) indicates the functions
the rest are the parameters

If you provide the params as string to the function and let the function convert them to integers floats or whatever you have quite a generic system.

alternative a smarter parser could read

A i1 i2 i3                    
B i4 i5 f6.789
C s"Hello world" L42

function A has three ints
function B has three ints and a float
and C has a string and a Long

just some ideas

@AWOL, thanks! That could be a solution. I will first try something like robtillaart suggested. If that isn't working I will look into what you suggested.

@robtillaart, That ain't actually a bad idea, I will see if I can make a simple parser to do something like you suggested. I will let you know, thanks!

AWOL:
Two pointers - one to a function, the other to a structure containing the parameters.

Or one pointer to a struct containing the parameters and the function - wait, that's an object!

Abstract base class for animator classes:

class LedCubeAnimator {
public:
  virtual void update(uint16_t time, LedCube &cubeRef) = 0;
};

Now the actual animator classes

class SlantingLineAnimator : public LedCubeAnimator {
  // function-specific parameters here
  uint16_t _shiftDelay;
  bool _invertDirection;

public:
  // constructor: just store the parameters
  SlantingLineAnimator(uint16_t shiftDelay = 75, bool invertDirection = false) :
    _shiftDelay(shiftDelay),
    _invertDirection(invertDirection)
  { }
  
  virtual void update(uint16_t time, LedCube &cubeRef) {
    slantingLines(time, cubeRef, _shiftDelay, _invertDirection);
  }
};

// these are similar

class RainAnimator : public LedCubeAnimator {···};
class CornerCubeAnimator : public LedCubeAnimator {···};
class SineWaveAnimator : public LedCubeAnimator {···};

The list of different animators with different parameters becomes really nice:

LedCubeAnimator *animators[] = {
  new RainAnimator,
  new RainAnimator(3, 5, 60, true),
  new SlantingLineAnimator,
  new CornerCubeAnimator,
  new CornerCubeAnimator(90, 3),
  new SineWaveAnimator,
  new SineWaveAnimator(60, 32)
};

Updating the animation:

animators[animIndex]->update(time, cube);

After a couple hours I just finished a simple parser like robtillaart suggested... and then see your comment @oqibidipo :blush: Never thought of this, I was too focused to solve it the hard way hahaha. Thanks man for opening up my eyes, really helped me!

@everybody else, thanks for your time. Very much appreciated!! :slight_smile: :slight_smile: