C++ ranges/views vs. Rust iterator

71 points Bijan777 68 comments

it seems there is a quite a bit of gap between the performance of Rust iterator and C++ ranges/views unless I am missing something.

https://godbolt.org/z/v76rcEb9n

https://godbolt.org/z/YG1dv4qYh

Rust:

use std::time::Instant;

fn expand_iota_views(input: &[i32]) -> impl Iterator<Item = i32> + '_ {

input

.iter()

.flat_map(|&n| 1..=n)

.flat_map(|n| 1..=n)

.flat_map(|n| 1..=n)

}

fn main() {

let input: Vec<i32> = (0..=50).collect();

let sample_result: Vec<i32> = expand_iota_views(&input).collect();

println!("Rust Result count: {}", sample_result.len());

let start = Instant::now();

let mut total_count = 0;

for _ in 0..1000 {

let result = expand_iota_views(&input);

total_count += result.count();

}

let duration = start.elapsed();

println!("Rust Total count (1000 iterations): {}", total_count);

println!("Rust Total time: {} microseconds", duration.as_micros());

println!(

"Rust Average per iteration: {:.2} microseconds",

duration.as_micros() as f64 / 1000.0

);

}

Output:

Rust Result count: 292825

Rust Total count (1000 iterations): 292825000

Rust Total time: 1025 microseconds

Rust Average per iteration: 1.02 microseconds

C++:

#include <chrono>

#include <iostream>

#include <numeric>

#include <ranges>

#include <vector>

inline auto expandIotaViews(const std::vector<int>& input) {

auto iota_transform = [](const int number) {

return std::views::iota(1, number + 1);

};

return input

| std::views::transform(iota_transform)

| std::views::join

| std::views::transform(iota_transform)

| std::views::join

| std::views::transform(iota_transform)

| std::views::join;

}

int main() {

std::vector<int> input(51);

std::iota(input.begin(), input.end(), 0);

auto sample_result = expandIotaViews(input);

std::vector<int> result_vec;

for (auto val : sample_result) {

result_vec.push_back(val);

}

std::cout << "C++ Result count: " << result_vec.size() << std::endl;

auto start = std::chrono::high_resolution_clock::now();

size_t total_count = 0;

for (int i = 0; i < 1000; ++i) {

auto result = expandIotaViews(input);

total_count += std::ranges::distance(result);

}

auto end = std::chrono::high_resolution_clock::now();

auto duration =

std::chrono::duration_cast<std::chrono::microseconds>(end - start);

std::cout << "C++ Total count (1000 iterations): " << total_count

<< std::endl;

std::cout << "C++ Total time: " << duration.count() << " microseconds"

<< std::endl;

std::cout << "C++ Average per iteration: " << duration.count() / 1000.0

<< " microseconds" << std::endl;

return 0;

}

Output:

C++ Result count: 292825

C++ Total count (1000 iterations): 292825000

C++ Total time: 174455 microseconds

C++ Average per iteration: 174.455 microseconds