Search code examples
coperatorssemanticscode-reuse

How to reuse the same C code but with different operators


I am building a library in C and one of the functions that is part of the library is something like:

void myFunction(double *inPtr, double start, double step, double *outPtr, int N, t_shape shape)
{
    int i;

    switch (shape) {

        default:
        case ShapeLinear:
            /* more stuff going on */
            for (i = 0; i < N; i++) {
                *(outPtr++) = *(inPtr++) * start;
                start += step;
            }
            /* more stuff going on */
            break;

        case ShapeExponential:
            /* more stuff going on */
            for (i = 0; i < N; i++) {
                *(outPtr++) = *(inPtr++) * start;
                start *= step;
            }
            /* more stuff going on */
            break;

        case ShapeSquared:
            /* more stuff going on */
            for (i = 0; i < N; i++) {
                *(outPtr++) = *(inPtr++) * start * start;
                start += step;
            }
            /* more stuff going on */
            break;

        case ShapeCubed:
            /* more stuff going on */
            for (i = 0; i < N; i++) {
                *(outPtr++) = *(inPtr++) * start * start * start;
                start += step;
            }
            /* more stuff going on */
            break;
    }
}

This is a simplified version just for the purpose of demonstration.
The actual function in the library has more cases and each case is longer and more complex.

Now I would like to create another version of exactly the same function with the only difference that instead of just assigning a value to outPtr, I would like to add and assign it.

void myFunctionAdd(double *inPtr, double start, double step, double *outPtr, int N, t_shape shape)
{
    int i;

    switch (shape) {

        default:
        case ShapeLinear:
            /* more stuff going on */
            for (i = 0; i < N; i++) {
                *(outPtr++) += *(inPtr++) * start;
                start += step;
            }
            /* more stuff going on */
            break;

        case ShapeExponential:
            /* more stuff going on */
            for (i = 0; i < N; i++) {
                *(outPtr++) += *(inPtr++) * start;
                start *= step;
            }
            /* more stuff going on */
            break;

        case ShapeSquared:
            /* more stuff going on */
            for (i = 0; i < N; i++) {
                *(outPtr++) += *(inPtr++) * start * start;
                start += step;
            }
            /* more stuff going on */
            break;

        case ShapeCubed:
            /* more stuff going on */
            for (i = 0; i < N; i++) {
                *(outPtr++) += *(inPtr++) * start * start * start;
                start += step;
            }
            /* more stuff going on */
            break;
    }
}

As I said, the real function I am working on is longer and more complex so having to rewrite the same code twice is really something I wouldn’t want to do.
It would be bad programming practice and more difficult to maintain.

Is there a C programming technique to deal with this issue?
Could blocks (closures) be useful in this situation?
Do I need to refactor the code somehow?
How would you tackle the problem?


Solution

  • the classic c solution is to pass in a function that gets called to do what you want to vary. This depends however on the basic shape of the operation being the same

    ie

    typedef int (*func_ptr)(int,int); 
    myFunction(....... func_ptr do_what)
    {
    int i;
    
    switch (shape) {
    
        default:
        case ShapeLinear:
            /* more stuff going on */
            for (i = 0; i < N; i++) {
                *(outPtr++) = func_ptr(*(inptr++), outPtr);
                start += step;
            }
            /* more stuff going on */
            break;
    }
    
    int assign(int a, int b)
    {
    return a;
    }
    
    int add_assign(int a, int b)
    {
    return a + b;
    }
    

    then call

     myFunction(......assign);
    

    or

    myfunction(......add_assign);
    

    this feels a bit forced in your case tho since we have to pass in the old value of outPtr