Last active
November 3, 2023 11:06
-
-
Save nixiz/61207277e61f7979fcdaa0ca8d9df6da to your computer and use it in GitHub Desktop.
C++20 ranges example. Compiler Explorer link: https://godbolt.org/z/nG84M1j7a
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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