2

I have a struct as follows:

struct power_model {
    int64_t (*estimate_energy)(statistics *stats, statistics *scaled_stats, parameters *from, parameters *to, energy_container *energy_container);
    int64_t (*estimate_performance)(statistics *stats, parameters *params);
    uint32_t (*freq_to_volt)(uint32_t freq);
};

There are multiple power models that my code contains. I would like to wrap these models with SWIG and expose them to Python so that I can run my unit tests.

While the SWIG documentation talks about exposing function pointers, it does not talk about function pointers contained within structs. I tried to encapsulate the calls in my interface file

%{
#include "models.h"
%}

%include "models.h"

%extend power_model {
  %pythoncallback;
  int64_t (*estimate_energy)(statistics *stats, statistics *scaled_stats, parameters *from, parameters *to, energy_container *energy_container);
  int64_t (*estimate_performance)(statistics *stats, parameters *params);
  uint32_t (*freq_to_volt)(uint32_t freq);
  %nopythoncallback;
}

I also tried prefixing the field names with %constant.

With these approaches, I always end up with the same error:

In [3]: model.estimate_energy()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-b2e3ace2fc9b> in <module>()
----> 1 model.estimate_energy()

TypeError: 'SwigPyObject' object is not callable

How can I call the underlying functions referenced by the function pointers contained within struct power_model?

Edit: To elaborate on my setup, I am also sources of two additional files to better explain the setup I'm trying to achieve with the power_model interface.

nexus5.c

static int64_t estimate_energy(statistics *stats, statistics *scaled_stats, parameters *from, parameters *to, energy_container *energy) {
    ...
}
static int64_t estimate_performance(statistics *stats, parameters *params) {
    ...
}
static uint32_t freq_to_volt(uint32_t freq) {
    ...
}

struct power_model nexus5_power_model = {
     .estimate_energy = estimate_energy,
     .estimate_performance = estimate_performance,
     .freq_to_volt = freq_to_volt,
};

galaxy_s.c

static int64_t estimate_energy(statistics *stats, statistics *scaled_stats, parameters *from, parameters *to, energy_container *energy) {
    ...
}
static int64_t estimate_performance(statistics *stats, parameters *params) {
    ...
}
static uint32_t freq_to_volt(uint32_t freq) {
    ...
}

struct power_model galaxy_s_power_model = {
     .estimate_energy = estimate_energy,
     .estimate_performance = estimate_performance,
     .freq_to_volt = freq_to_volt,
};
7
  • The example here stackoverflow.com/questions/22923696/… demonstrates many aspects of function pointers, for all solutions 1-5, you add a struct, e.g. typedef struct A { fptr_t f;} A; and store and execute functions. No problem Commented Sep 28, 2015 at 18:39
  • This does not work in my case. I cannot create the struct in my interface file. The struct is present in a header file and I just include it in my interface file. Also, I have 5 files with static int64_t estimate_energy(...). How would I include these functions in my interface file and wrap them around %pythoncallback;. For me, the whole point of using struct with function pointers is to provide an interface that different models can implement in differing ways. Commented Sep 29, 2015 at 0:03
  • As long as the prototype for the functions are known, it works for me. Try working up an example from scratch to get familiar with the ordering of the header files included, SWIG does not recurse header files for definitions. The error is most likely due to this rather than function pointers. Commented Sep 29, 2015 at 6:57
  • I'm not relying on recursive header file definitions. I am including models.h that contains the struct power_model. The actual implementation of all of these function pointers are all static functions which I cannot prototype in header files or in the interface file. Even if I could prototype them in the interface file, they all have the same name - something I can easily change..but that makes me question whether this is the right approach Commented Sep 29, 2015 at 14:25
  • You don't need to prototype static functions, just their prototype like shown below. You do need to expose the many static function to be able to use their address for assigning pointers. Commented Sep 29, 2015 at 14:29

1 Answer 1

1

This works for me. The solution 5 is the preferred one.

test.i

%module test

%{
#include "test.h"
%}

// Solution 5 (right one)
%pythoncallback;
double f5(double);
%nopythoncallback;
%ignore f5;

%include "test.h"    

test.h

typedef double (*fptr_t)(double);

// Solution 5
double f5(double x) {
  return x*x;
}

typedef struct bla {
  fptr_t f;
} bla;

From within Python

import test
s = test.bla
# Assign function pointer
s.f = test.f5
# Execute
s.f(2)

f is a function taking a function pointer as argument

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.