# Getting to know Swift and C++ compatibility

Having fun with the experimental features of the swift toolchain.

### Introduction

Swift is a very convenient language, although it has its own quirks and peculiar learning non-linearity. However, with it, you can get production-ready code out pretty quickly. Be that as it may, sometimes you have performance-sensitive sections, and Swift is not very helpful in reducing them. In such cases, C++ becomes a popular choice.

And here the question arises: “how to call a C ++ function through Swift”? To make such a call, you will often need to write an Objective-C wrapper that will act as a public interface to your C++ code. In cases like this, the Swift toolchain can help you import Objective-C code into Swift. The main limitation of this method is that you won’t be able to use C++ classes in Objective-C, only simple POD structures.

We will write sieve of the algorithm of Eratosthenes both in C++ and Swift. Then we’ll learn how to enable C++ compatibility and call C++ code from Swift, and at the same time compare the performance of these implementations. Please note that this compatibility mode is an experimental feature and is subject to change at any time. This article was written on Xcode version 14.2.

### Algorithm

The Sieve of Eratosthenes finds all prime numbers less than or equal to N. A prime number is an integer that is only divisible by itself and 1. The algorithm creates a boolean array to determine if each number is prime. Then he gradually goes through them, marking all multiples as not prime.

Here is the implementation of the algorithm in Swift.

``````// primes.swift

func primes(n: Int) -> [Int] {
var isPrime = [Bool](repeating: true, count: n + 1)

func primes(n: Int) -> [Int] {
var isPrime = [Bool](repeating: true, count: n + 1)

for value in stride(from: 2, to: n + 1, by: 1) where isPrime[value] {
if value * value > n { break }

for multiple in stride(from: value * 2, to: n + 1, by: value) {
isPrime[multiple] = false
}
}

var result = [Int]()

for value in stride(from: 2, to: n + 1, by: 1) where isPrime[value] {
result.append(value)
}

return result
}For a C++ implementation, we need a header and a source file.  Please note that we have entered typedefto have a cleaner name to refer to std::vector.// primes.hpp

#include

typedef std::vector VectorLong;

VectorLong primes(const long &n);
// primes.cpp
#include

#include "primes.hpp"

VectorLong primes(const long &n) {
std::vector isPrime(n + 1); // faster than std::vector
std::fill(isPrime.begin(), isPrime.end(), true);

for (long value = 2; value * value <= n; ++value) {
if (!isPrime[value]) { continue; }

for (long multiple = value * 2; multiple <= n; multiple += value) {
isPrime[multiple] = false;
}
}

VectorLong result;

for (long value = 2; value <= n; ++value) {
if (!isPrime[value]) { continue; }

result.push_back(value);
}

return result;
(adsbygoogle=window.adsbygoogle||[]).push({}) We will create a Swift container/package with two separate targets - to store our Swift and C++ code.  To import C++ code from Swift, we need a module map.// module.modulemap

module CXX {
requires cplusplus
}

// CXX.hpp

#include "primes.hpp"Don't forget to send enable-experimental-cxx-interop in Package.swift in swift targets// swift-tools-version: 5.7

import PackageDescription

let package = Package(
name: "SwiftCXXInteropExample",
platforms: [
.macOS(.v12),
],
products: [
.library(name: "CXX", targets: ["CXX"]),
.executable(name: "CLI", targets: ["CLI"])
],
dependencies: [],
targets: [
.target(name: "CXX"),
.executableTarget(
name: "CLI",
dependencies: ["CXX"],
swiftSettings: [.unsafeFlags(["-enable-experimental-cxx-interop"])]
)
]
)See Apple's documentation if you'd like to learn more about how to enable C++ compatibility.Testing the resultsMuch more convenient and easier to use our VectorLong from swift according to RandomAccessCollection.import CXX

extension VectorLong: RandomAccessCollection {
public var startIndex: Int { 0 }
public var endIndex: Int { size() }
}Now we can call our C++ function from swift and print the result to the console.let cxxVector = primes(100)
let swiftArray = [Int](cxxVector)
print(swiftArray)And now let's check whether our implementation in C ++ will work faster.let signposter = OSSignposter()

let count = 100
let n = 10_000_000

for _ in 0..
let state = signposter.beginInterval("C++")
let _ = primes(n)
signposter.endInterval("C++", state)
}

for _ in 0..
let state = signposter.beginInterval("Swift")
let _ = primes(n: n)
signposter.endInterval("Swift", state)
} We can see that performance in C++ is slightly faster on average, 26 seconds in C++ versus 28 seconds in swift.Final ThoughtsWe were able to directly use std::vector in Swift.  Personally, I have not found a convenient way to switch between Swift Map And std::map, set And std::set.  However, swift c C++ compatibility is developing rapidly, and the future of this compatibility is encouraging.CppInteroperability folder in the Swift repository contains more information about interoperability features, limitations, and future plans.The full code can be found at https://github.com/ksemianov/SwiftCXXInteropExample {
if value * value > n { break }        for multiple in stride(from: value * 2, to: n + 1, by: value) {
isPrime[multiple] = false
}

func primes(n: Int) -> [Int] {
var isPrime = [Bool](repeating: true, count: n + 1)

for value in stride(from: 2, to: n + 1, by: 1) where isPrime[value] {
if value * value > n { break }

for multiple in stride(from: value * 2, to: n + 1, by: value) {
isPrime[multiple] = false
}
}

var result = [Int]()

for value in stride(from: 2, to: n + 1, by: 1) where isPrime[value] {
result.append(value)
}

return result
}For a C++ implementation, we need a header and a source file.  Please note that we have entered typedefto have a cleaner name to refer to std::vector.// primes.hpp

#include

typedef std::vector VectorLong;

VectorLong primes(const long &n);
// primes.cpp
#include

#include "primes.hpp"

VectorLong primes(const long &n) {
std::vector isPrime(n + 1); // faster than std::vector
std::fill(isPrime.begin(), isPrime.end(), true);

for (long value = 2; value * value <= n; ++value) {
if (!isPrime[value]) { continue; }

for (long multiple = value * 2; multiple <= n; multiple += value) {
isPrime[multiple] = false;
}
}

VectorLong result;

for (long value = 2; value <= n; ++value) {
if (!isPrime[value]) { continue; }

result.push_back(value);
}

return result;
}Project structure We will create a Swift container/package with two separate targets - to store our Swift and C++ code.  To import C++ code from Swift, we need a module map.// module.modulemap

module CXX {
requires cplusplus
}

// CXX.hpp

#include "primes.hpp"Don't forget to send enable-experimental-cxx-interop in Package.swift in swift targets// swift-tools-version: 5.7

import PackageDescription

let package = Package(
name: "SwiftCXXInteropExample",
platforms: [
.macOS(.v12),
],
products: [
.library(name: "CXX", targets: ["CXX"]),
.executable(name: "CLI", targets: ["CLI"])
],
dependencies: [],
targets: [
.target(name: "CXX"),
.executableTarget(
name: "CLI",
dependencies: ["CXX"],
swiftSettings: [.unsafeFlags(["-enable-experimental-cxx-interop"])]
)
]
)See Apple's documentation if you'd like to learn more about how to enable C++ compatibility.Testing the resultsMuch more convenient and easier to use our VectorLong from swift according to RandomAccessCollection.import CXX

extension VectorLong: RandomAccessCollection {
public var startIndex: Int { 0 }
public var endIndex: Int { size() }
}Now we can call our C++ function from swift and print the result to the console.let cxxVector = primes(100)
let swiftArray = [Int](cxxVector)
print(swiftArray)And now let's check whether our implementation in C ++ will work faster.let signposter = OSSignposter()

let count = 100
let n = 10_000_000

for _ in 0..
let state = signposter.beginInterval("C++")
let _ = primes(n)
signposter.endInterval("C++", state)
}

for _ in 0..
let state = signposter.beginInterval("Swift")
let _ = primes(n: n)
signposter.endInterval("Swift", state)
} We can see that performance in C++ is slightly faster on average, 26 seconds in C++ versus 28 seconds in swift.Final ThoughtsWe were able to directly use std::vector in Swift.  Personally, I have not found a convenient way to switch between Swift Map And std::map, set And std::set.  However, swift c C++ compatibility is developing rapidly, and the future of this compatibility is encouraging.CppInteroperability folder in the Swift repository contains more information about interoperability features, limitations, and future plans.The full code can be found at https://github.com/ksemianov/SwiftCXXInteropExample {
result.append(value)
}``````    return result
}```For a C++ implementation, we need a header and a source file.  Please note that we have entered typedefto have a cleaner name to refer to std::vector.```// primes.hpp

#include

typedef std::vector VectorLong;

VectorLong primes(const long &n);
// primes.cpp
#include

#include "primes.hpp"

VectorLong primes(const long &n) {
std::vector isPrime(n + 1); // faster than std::vector
std::fill(isPrime.begin(), isPrime.end(), true);

for (long value = 2; value * value <= n; ++value) {

func primes(n: Int) -> [Int] {
var isPrime = [Bool](repeating: true, count: n + 1)

for value in stride(from: 2, to: n + 1, by: 1) where isPrime[value] {
if value * value > n { break }

for multiple in stride(from: value * 2, to: n + 1, by: value) {
isPrime[multiple] = false
}
}

var result = [Int]()

for value in stride(from: 2, to: n + 1, by: 1) where isPrime[value] {
result.append(value)
}

return result
}For a C++ implementation, we need a header and a source file.  Please note that we have entered typedefto have a cleaner name to refer to std::vector.// primes.hpp

#include

typedef std::vector VectorLong;

VectorLong primes(const long &n);
// primes.cpp
#include

#include "primes.hpp"

VectorLong primes(const long &n) {
std::vector isPrime(n + 1); // faster than std::vector
std::fill(isPrime.begin(), isPrime.end(), true);

for (long value = 2; value * value <= n; ++value) {
if (!isPrime[value]) { continue; }

for (long multiple = value * 2; multiple <= n; multiple += value) {
isPrime[multiple] = false;
}
}

VectorLong result;

for (long value = 2; value <= n; ++value) {
if (!isPrime[value]) { continue; }

result.push_back(value);
}

return result;
}Project structure We will create a Swift container/package with two separate targets - to store our Swift and C++ code.  To import C++ code from Swift, we need a module map.// module.modulemap

module CXX {
requires cplusplus
}

// CXX.hpp

#include "primes.hpp"Don't forget to send enable-experimental-cxx-interop in Package.swift in swift targets// swift-tools-version: 5.7

import PackageDescription

let package = Package(
name: "SwiftCXXInteropExample",
platforms: [
.macOS(.v12),
],
products: [
.library(name: "CXX", targets: ["CXX"]),
.executable(name: "CLI", targets: ["CLI"])
],
dependencies: [],
targets: [
.target(name: "CXX"),
.executableTarget(
name: "CLI",
dependencies: ["CXX"],
swiftSettings: [.unsafeFlags(["-enable-experimental-cxx-interop"])]
)
]
)See Apple's documentation if you'd like to learn more about how to enable C++ compatibility.Testing the resultsMuch more convenient and easier to use our VectorLong from swift according to RandomAccessCollection.import CXX

extension VectorLong: RandomAccessCollection {
public var startIndex: Int { 0 }
public var endIndex: Int { size() }
}Now we can call our C++ function from swift and print the result to the console.let cxxVector = primes(100)
let swiftArray = [Int](cxxVector)
print(swiftArray)And now let's check whether our implementation in C ++ will work faster.let signposter = OSSignposter()

let count = 100
let n = 10_000_000

for _ in 0..
let state = signposter.beginInterval("C++")
let _ = primes(n)
signposter.endInterval("C++", state)
}

for _ in 0..
let state = signposter.beginInterval("Swift")
let _ = primes(n: n)
signposter.endInterval("Swift", state)
} We can see that performance in C++ is slightly faster on average, 26 seconds in C++ versus 28 seconds in swift.Final ThoughtsWe were able to directly use std::vector in Swift.  Personally, I have not found a convenient way to switch between Swift Map And std::map, set And std::set.  However, swift c C++ compatibility is developing rapidly, and the future of this compatibility is encouraging.CppInteroperability folder in the Swift repository contains more information about interoperability features, limitations, and future plans.The full code can be found at https://github.com/ksemianov/SwiftCXXInteropExample) { continue; }        for (long multiple = value * 2; multiple <= n; multiple += value) {
isPrime[multiple] = false;
}
}    VectorLong result;    for (long value = 2; value <= n; ++value) {

func primes(n: Int) -> [Int] {
var isPrime = [Bool](repeating: true, count: n + 1)

for value in stride(from: 2, to: n + 1, by: 1) where isPrime[value] {
if value * value > n { break }

for multiple in stride(from: value * 2, to: n + 1, by: value) {
isPrime[multiple] = false
}
}

var result = [Int]()

for value in stride(from: 2, to: n + 1, by: 1) where isPrime[value] {
result.append(value)
}

return result
}For a C++ implementation, we need a header and a source file.  Please note that we have entered typedefto have a cleaner name to refer to std::vector.// primes.hpp

#include

typedef std::vector VectorLong;

VectorLong primes(const long &n);
// primes.cpp
#include

#include "primes.hpp"

VectorLong primes(const long &n) {
std::vector isPrime(n + 1); // faster than std::vector
std::fill(isPrime.begin(), isPrime.end(), true);

for (long value = 2; value * value <= n; ++value) {
if (!isPrime[value]) { continue; }

for (long multiple = value * 2; multiple <= n; multiple += value) {
isPrime[multiple] = false;
}
}

VectorLong result;

for (long value = 2; value <= n; ++value) {
if (!isPrime[value]) { continue; }

result.push_back(value);
}

return result;
}Project structure We will create a Swift container/package with two separate targets - to store our Swift and C++ code.  To import C++ code from Swift, we need a module map.// module.modulemap

module CXX {
requires cplusplus
}

// CXX.hpp

#include "primes.hpp"Don't forget to send enable-experimental-cxx-interop in Package.swift in swift targets// swift-tools-version: 5.7

import PackageDescription

let package = Package(
name: "SwiftCXXInteropExample",
platforms: [
.macOS(.v12),
],
products: [
.library(name: "CXX", targets: ["CXX"]),
.executable(name: "CLI", targets: ["CLI"])
],
dependencies: [],
targets: [
.target(name: "CXX"),
.executableTarget(
name: "CLI",
dependencies: ["CXX"],
swiftSettings: [.unsafeFlags(["-enable-experimental-cxx-interop"])]
)
]
)See Apple's documentation if you'd like to learn more about how to enable C++ compatibility.Testing the resultsMuch more convenient and easier to use our VectorLong from swift according to RandomAccessCollection.import CXX

extension VectorLong: RandomAccessCollection {
public var startIndex: Int { 0 }
public var endIndex: Int { size() }
}Now we can call our C++ function from swift and print the result to the console.let cxxVector = primes(100)
let swiftArray = [Int](cxxVector)
print(swiftArray)And now let's check whether our implementation in C ++ will work faster.let signposter = OSSignposter()

let count = 100
let n = 10_000_000

for _ in 0..
let state = signposter.beginInterval("C++")
let _ = primes(n)
signposter.endInterval("C++", state)
}

for _ in 0..
let state = signposter.beginInterval("Swift")
let _ = primes(n: n)
signposter.endInterval("Swift", state)
} We can see that performance in C++ is slightly faster on average, 26 seconds in C++ versus 28 seconds in swift.Final ThoughtsWe were able to directly use std::vector in Swift.  Personally, I have not found a convenient way to switch between Swift Map And std::map, set And std::set.  However, swift c C++ compatibility is developing rapidly, and the future of this compatibility is encouraging.CppInteroperability folder in the Swift repository contains more information about interoperability features, limitations, and future plans.The full code can be found at https://github.com/ksemianov/SwiftCXXInteropExample) { continue; }        result.push_back(value);
}``````    return result;
}```Project structure We will create a Swift container/package with two separate targets – to store our Swift and C++ code.  To import C++ code from Swift, we need a module map.```// module.modulemap

module CXX {
requires cplusplus
}

// CXX.hpp

#include "primes.hpp"```Don’t forget to send enable-experimental-cxx-interop in Package.swift in swift targets```// swift-tools-version: 5.7

import PackageDescription

let package = Package(
name: "SwiftCXXInteropExample",
platforms: [
.macOS(.v12),
],
products: [
.library(name: "CXX", targets: ["CXX"]),
.executable(name: "CLI", targets: ["CLI"])
],
dependencies: [],
targets: [
.target(name: "CXX"),
.executableTarget(
name: "CLI",
dependencies: ["CXX"],
swiftSettings: [.unsafeFlags(["-enable-experimental-cxx-interop"])]
)
]
)```See Apple’s documentation if you’d like to learn more about how to enable C++ compatibility.Testing the resultsMuch more convenient and easier to use our VectorLong from swift according to RandomAccessCollection.```import CXX

extension VectorLong: RandomAccessCollection {
public var startIndex: Int { 0 }
public var endIndex: Int { size() }
}```Now we can call our C++ function from swift and print the result to the console.```let cxxVector = primes(100)
let swiftArray = [Int](cxxVector)
print(swiftArray)```And now let’s check whether our implementation in C ++ will work faster.```let signposter = OSSignposter()

let count = 100
let n = 10_000_000

for _ in 0..
let state = signposter.beginInterval("C++")
let _ = primes(n)
signposter.endInterval("C++", state)
}

for _ in 0..
let state = signposter.beginInterval("Swift")
let _ = primes(n: n)
signposter.endInterval("Swift", state)