Search code examples
c++swiftbridging

wrapping std::vector<double> from C++ to C for use in Swift


I want to use a program which is written in C++ in Swift 4. I already read and understood the description how to do the briding and wrapping as described in http://www.swiftprogrammer.info/swift_call_cpp.html.

However, real life is more complicated and I have no experience in C++. I have the following piece of code in the C++ header file.

namespace Fft {
   void transform(std::vector<double> &real, std::vector<double> &imag);
}

I have two questions:

  1. How to write the function declaration in C? I have no idea what the equivalent of vector is in C.
  2. What is the meaning of namespace in C?

Solution

  • You can write some bridging functions that use C compatible types to call C++ functions. This is very untested code just to give you an idea what you could do:

    namespace Fft {
       void transform(std::vector<double> &real, std::vector<double> &imag);
    }
    
    extern "C" {
    
    struct complex_vector
    {
        void* real;
        void* imag;
    };
    
    complex_vector create_complex_vector(size_t size)
    {
        complex_vector cv;
        cv.real = new std::vector<double>(size);
        cv.imag = new std::vector<double>(size);
        return cv;
    }
    
    void complex_vector_push_back(complex_vector cv, double real, double imag)
    {
        reinterpret_cast<std::vector<double>*>(cv.real)->push_back(real);
        reinterpret_cast<std::vector<double>*>(cv.imag)->push_back(imag);
    }
    
    void complex_vector_reserve(complex_vector cv, size_t size)
    {
        reinterpret_cast<std::vector<double>*>(cv.real)->reserve(size);
        reinterpret_cast<std::vector<double>*>(cv.imag)->reserve(size);
    }
    
    void complex_vector_resize(complex_vector cv, size_t size)
    {
        reinterpret_cast<std::vector<double>*>(cv.real)->resize(size);
        reinterpret_cast<std::vector<double>*>(cv.imag)->resize(size);
    }
    
    void fill_complex_vector(complex_vector cv, double* real, double* imag)
    {
        auto v_real = reinterpret_cast<std::vector<double>*>(cv.real)->data();
        auto v_imag = reinterpret_cast<std::vector<double>*>(cv.imag)->data();
        auto v_size = reinterpret_cast<std::vector<double>*>(cv.real)->size();
    
        std::copy(real, real + v_size, v_real);
        std::copy(imag, imag + v_size, v_imag);
    }
    
    void fft_transform(complex_vector cv)
    {
        Fft::transform(*reinterpret_cast<std::vector<double>*>(cv.real), *reinterpret_cast<std::vector<double>*>(cv.imag));
    }
    
    double* complex_vector_real_array(complex_vector cv)
    {
        return reinterpret_cast<std::vector<double>*>(cv.real)->data();
    }
    
    double* complex_vector_imag_array(complex_vector cv)
    {
        return reinterpret_cast<std::vector<double>*>(cv.imag)->data();
    }
    
    size_t complex_vector_size(complex_vector cv)
    {
        return reinterpret_cast<std::vector<double>*>(cv.imag)->size();
    }
    
    void destroy_complex_vector(complex_vector cv)
    {
        delete reinterpret_cast<std::vector<double>*>(cv.real);
        delete reinterpret_cast<std::vector<double>*>(cv.imag);
    }
    
    } // extern "C"
    

    If you compile that as C++ the extern "C" {} block will make it so you can call those functions from C.

    You could write a C program a bit like this for example:

    complex_vector cv = create_complex_vector(1024);
    
    // fill the vector
    for(int i = 0; i < complex_vector_size(cv); ++i)
        complex_vector_push_back(cv, 0.2 * i, 0.4 * i);
    
    // call the transform
    fft_transform(cv);
    
    double* real = complex_vector_real_array(cv);
    double* imag = complex_vector_imag_array(cv);
    size_t size = complex_vector_size(cv);
    
    // use your transformed data here ...
    
    destroy_complex_vector(cv);
    

    Note: Completely untested code.