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)
for value in stride(from: 2, to: n + 1, by: 1) where isPrime
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)
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.
Much 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 Thoughts
We 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.
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
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)
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.
Much 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 Thoughts
We 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.
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
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)
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.
Much 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 Thoughts
We 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.
for (long multiple = value * 2; multiple <= n; multiple += value) {
isPrime[multiple] = false;
}
}
VectorLong result;
for (long value = 2; value <= n; ++value) {
if (!isPrime
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)
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.
Much 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 Thoughts
We 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.
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.
Much 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 Thoughts
We 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.