Skip to content

Instantly share code, notes, and snippets.

@nixiz
Last active November 3, 2023 11:06
Show Gist options
  • Save nixiz/61207277e61f7979fcdaa0ca8d9df6da to your computer and use it in GitHub Desktop.
Save nixiz/61207277e61f7979fcdaa0ca8d9df6da to your computer and use it in GitHub Desktop.
C++20 ranges example. Compiler Explorer link: https://godbolt.org/z/nG84M1j7a
#include <iostream>
#include <vector>
#include <string>
#include <string_view>
#include <chrono>
#include <random>
#include <range/v3/all.hpp>
#include <ranges>
using namespace std;
template <typename first_t, typename ...rest_t>
struct first_type {
using value_type = first_t;
};
template <typename ...T>
using first_type_t = typename first_type<T...>::value_type;
template <typename ...type_t>
constexpr auto mean_of(type_t ...vals) noexcept
{
using value_type = first_type_t<type_t...>;
static_assert(conjunction_v<is_same<value_type, type_t>...>,
"all given values must be same type");
const value_type sum = (vals + ...);
const value_type mean = sum / value_type(sizeof... (vals));
return mean;
}
struct student
{
std::string name;
float math{}, physics{}, science{}, history{};
float geometry{}, sports{}, music{};
float average() const noexcept
{
return mean_of(math, physics, science,
history, sports, geometry, music);
}
};
struct student_w_average
{
std::string_view name;
float average_grade{};
};
inline std::vector<student>
create_random_student_list(size_t len, float mean)
{
std::random_device rd{};
std::mt19937 gen{ rd() };
std::normal_distribution<float> d{ mean, 10 };
std::vector<student> lst; lst.resize(len);
for (size_t i = 0; i < len; i++)
{
student ogrn;
float average_grade = std::min(d(gen), 100.f);
uniform_real_distribution dis(fabs(average_grade - 10.f),
std::min(average_grade + 10.f, 100.f));
ogrn.math = dis(gen);
ogrn.physics = dis(gen);
ogrn.science = dis(gen);
ogrn.history = dis(gen);
ogrn.sports = dis(gen);
ogrn.geometry = dis(gen);
ogrn.music = dis(gen);
ogrn.name = "student_" + std::to_string(i);
lst[i] = std::move(ogrn);
}
return lst;
}
class benchmark
{
inline auto time_point() noexcept {
using namespace std::chrono;
return duration_cast<milliseconds>(
system_clock::now().time_since_epoch()
).count();
};
inline void print_duration() const noexcept
{
cout << "function duration in msec : "
<< (stop_time - start_time) << " \n";
}
long long start_time{};
long long stop_time{};
public:
void start() {
start_time = time_point();
}
void done() {
stop_time = time_point();
print_duration();
}
};
void solve_with_stl(const vector<student>& students)
{
benchmark bench; bench.start();
vector<reference_wrapper<const student>> students_above_average;
copy_if(begin(students), end(students),
back_inserter(students_above_average),
[](const auto& s) noexcept
{
return s.average() >= 80.f;
});
vector<student_w_average> result_list;
result_list.resize(students_above_average.size());
transform(begin(students_above_average), end(students_above_average),
begin(result_list),
[](const auto& student_ref) noexcept
{
auto& s = student_ref.get();
auto new_average = mean_of(60.f, s.physics, s.science,
s.history, s.sports, s.geometry,
s.music);
return student_w_average{ s.name, new_average };
});
// for disabling release build optimization!
std::hash<std::string_view> h;
size_t hash_result{};
for (const auto& s : result_list)
{
hash_result += h(s.name) + h(std::to_string(s.average_grade));
}
bench.done();
std::cout << "calculated hash: " << hash_result << std::endl;
}
void solve_with_ranges(const std::vector<student>& students)
{
benchmark bench; bench.start();
auto result_list = students
| std::views::filter([](const auto& s) noexcept
{
return s.average() >= 80.f;
})
| std::views::transform([](const auto& s) noexcept
{
auto new_average = mean_of(60.f, s.physics, s.science,
s.history, s.sports, s.geometry,
s.music);
return student_w_average{ s.name, new_average };
});
// for disabling release build optimization!
std::hash<std::string_view> h;
size_t hash_result{};
for (const auto& s : result_list)
{
hash_result += h(s.name) + h(std::to_string(s.average_grade));
}
bench.done();
std::cout << "calculated hash: " << hash_result << std::endl;
}
int main()
{
constexpr size_t num_of_students = 2000000;
auto students = create_random_student_list(num_of_students, 80);
std::cout << "starting benchmark with " << num_of_students << " ogrenci";
std::cout << "\n ---- \n";
std::cout << "benchmark for solve_with_stl" << std::endl;
solve_with_stl(students);
std::cout << "\n ---- \n";
std::cout << "benchmark for solve_with_ranges" << std::endl;
solve_with_ranges(students);
std::cout << "benchmark is done!\n";
}
/*
Output:
starting benchmark with 2000000 students
----
benchmark for solve_with_stl
function duration in msec : 1775
calculated hash: 4497248063197551443
----
benchmark for solve_with_ranges
function duration in msec : 1107
calculated hash: 4497248063197551443
benchmark is done!
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment