Swift Cpp Wrapper Example Save Abandoned

Example of C / C++ / Objective-C / Swift interoperability

Project README

How to call C/C++ from Swift and Swift from C++

How to call C from Swift

In ViewController.swift:

hello_c("World".cString(using: String.Encoding.utf8))

In C.h:

#ifndef C_h
#define C_h
#ifdef __cplusplus
extern "C" {
#endif
    void hello_c(const char * name);
#ifdef __cplusplus
}
#endif
#endif /* C_h */

In C.c:

#include "C.h"
#include <stdio.h>
void hello_c(const char * name) {
    printf("Hello %s in C\n", name);
}

In Example-Bridging-Header.h:

#import "C.h"

How to call C++ from Swift (option 1)

In ViewController.swift:

CPP_Wrapper().hello_cpp_wrapped("World")

In CPP.hpp:

#pragma once
#include <string>
class CPP {
public:
    void hello_cpp(const std::string& name);
};

In CPP.cpp:

#include "CPP.hpp"
#include <iostream>
using namespace std;
void CPP::hello_cpp(const std::string& name) {
    cout << "Hello " << name << " in C++" << endl;
}

In CPP-Wrapper.h:

#import <Foundation/Foundation.h>
@interface CPP_Wrapper : NSObject
- (void)hello_cpp_wrapped:(NSString *)name;
@end

In CPP-Wrapper.mm:

#import "CPP-Wrapper.h"
#include "CPP.hpp"
@implementation CPP_Wrapper
- (void)hello_cpp_wrapped:(NSString *)name {
    CPP cpp;
    cpp.hello_cpp([name cStringUsingEncoding:NSUTF8StringEncoding]);
}
@end

In Example-Bridging-Header.h:

#import "CPP-Wrapper.h"

How to call C++ from Swift (option 2)

In ViewController.swift:

let queue = LockFreeQueue()
queue.push("1" as NSObject)
queue.push("2" as NSObject)
let first = queue.pop();
print(first as! NSString)

In lock_free_objc_wrapper.h:

#import <Foundation/Foundation.h>
#ifndef lock_free_objc_wrapper_h
#define lock_free_objc_wrapper_h
@interface LockFreeQueue : NSObject
- (void)push:(NSObject *)data;
- (NSObject *)pop;
@end
#endif

In lock_free_objc_wrapper.mm:

#import "lock_free_objc_wrapper.h"
#include "lock_free_queue.hpp"
@interface LockFreeQueue() {
    lock_free_queue<void*>* queue;
}
@end

@implementation LockFreeQueue
- (instancetype)init {
    if (self = [super init]) {
        queue = new lock_free_queue<void*>();
    }
    return self;
}

- (void)dealloc {
    delete queue;
}

- (void)push:(NSObject *)data {
    queue->push((void*)CFBridgingRetain(data));
}

- (NSObject*)pop{
    std::unique_ptr<void*> res = queue->pop();
    if(res == nullptr) return nil;
    return CFBridgingRelease(*res);
}
@end

In lock_free_queue.hpp:

#ifndef lock_free_queue_hpp
#define lock_free_queue_hpp
#ifdef __cplusplus
template<typename T>
class lock_free_queue {
...
public:
    lock_free_queue() {
    ...
    }
    ~lock_free_queue() {
    ...
    }
    std::unique_ptr<T> pop() {
    ...
    }
    void push(T new_value) {
    ...
    }
#endif
#endif

In Example-Bridging-Header.h:

#import "lock_free_objc_wrapper.h"

How to call Swift from C++ (plain closure without context)

In ViewController.swift:

let checker = PrimeChecker()
checker.simpleCall {
    print("And back to Swift")
}

In prime_feature_objc_wrapper.h:

#import <Foundation/Foundation.h>
#ifndef prime_feature_objc_wrapper_h
#define prime_feature_objc_wrapper_h
@interface PrimeChecker : NSObject
- (void) simpleCall: (void(*)())function;
@end
#endif

In prime_feature_objc_wrapper.mm:

#import "prime_feature_objc_wrapper.h"
#include "prime_feature.hpp"
@interface PrimeChecker() {
    prime_checker* checker;
}
@end

@implementation PrimeChecker
- (instancetype)init {
    if (self = [super init]) {
        checker = new prime_checker();
    }
    return self;
}

- (void)dealloc {
    delete checker;
}

- (void)simpleCall: (void(*)())function  {
    checker->simpleCall(function);
}
@end

In prime_checker.hpp:

#ifndef prime_feature_h
#define prime_feature_h
#ifdef __cplusplus
#include <iostream>
#include <string>
class prime_checker {
public:
    void simpleCall(void(*function)()){
      function();
    }
};
#endif
#endif

How to call Swift from C++ (closure WITH context)

You have to pass pointer to object to closure right to C++ method and then back to Swift:

In prime_checker.hpp (void* target - raw pointer to 'self' in Swift, pass it to void(resultCallback)(bool result, void target))):

void checkIsPrime(std::string value, 
void(*progressCallback)(void*), 
void(*resultCallback)(bool result, void* target), 
void* target) {
       ...
        progressCallback(target);
        bool x = true;
        resultCallback(x, target);
        ...
    }

In prime_feature_objc_wrapper.h:

- (void) checkIsPrime: (NSString *)value with: (void(*)(void*)) progressCallback andWith: (void(*)(bool result, void* target)) resultCallback withTarget: (void*) target ;

In prime_feature_objc_wrapper.mm:

- (void) checkIsPrime: (NSString *)value with: (void(*)(void*)) progressCallback andWith: (void(*)(bool result, void* target)) resultCallback withTarget: (void*) target{
    checker->checkIsPrime([value UTF8String], progressCallback, resultCallback, target);
}

In ViewController.swift:

// raw pointer to self
let observer = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
// pass pointer to c++ method
checker.checkIsPrime(self.input?.stringValue, with: { observer in
                // from raw pointer to 'self'
                let mySelf = Unmanaged<ViewController>.fromOpaque(observer!).takeUnretainedValue()
                // update UI from main thread using mySelf
                DispatchQueue.main.async{
                    mySelf.progress.stringValue...
                }
            }, andWith: { (result : Bool, observer) in
                ...
            }, withTarget: observer)
Open Source Agenda is not affiliated with "Swift Cpp Wrapper Example" Project. README Source: dredwardhyde/swift-cpp-wrapper-example
Stars
63
Open Issues
0
Last Commit
5 years ago

Open Source Agenda Badge

Open Source Agenda Rating