#include <chrono>
#include <iostream>
#include <numeric>
#include <vector>
constexpr int square( int x )
{
return x * x;
}
constexpr int times_two( int x )
{
return 2 * x;
}
// map ((^2) . (^2)) $ [1,2,3]
int manual_fusion( const std::vector<int>& xs )
{
std::vector<int> zs;
zs.reserve( xs.size() );
for ( int x : xs )
{
zs.push_back( square( times_two( x ) ) );
}
return zs[0];
}
// map (^2) . map (^2) $ [1,2,3]
int two_loops( const std::vector<int>& xs )
{
std::vector<int> ys;
ys.reserve( xs.size() );
for ( int x : xs )
{
ys.push_back( times_two( x ) );
}
std::vector<int> zs;
zs.reserve( ys.size() );
for ( int y : ys )
{
zs.push_back( square( y ) );
}
return zs[0];
}
template <typename F>
void test( F f )
{
const std::vector<int> xs( 100000000, 42 );
const auto start_time = std::chrono::high_resolution_clock::now();
const auto result = f( xs );
const auto end_time = std::chrono::high_resolution_clock::now();
const auto elapsed = end_time - start_time;
const auto elapsed_us = std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count();
std::cout << elapsed_us / 1000 << " ms - " << result << std::endl;
}
int main()
{
test( manual_fusion );
test( two_loops );
}
I2luY2x1ZGUgPGNocm9ubz4KI2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8bnVtZXJpYz4KI2luY2x1ZGUgPHZlY3Rvcj4KCmNvbnN0ZXhwciBpbnQgc3F1YXJlKCBpbnQgeCApCnsKCXJldHVybiB4ICogeDsKfQoKY29uc3RleHByIGludCB0aW1lc190d28oIGludCB4ICkKewoJcmV0dXJuIDIgKiB4Owp9CgovLyBtYXAgKCheMikgLiAoXjIpKSAkIFsxLDIsM10KaW50IG1hbnVhbF9mdXNpb24oIGNvbnN0IHN0ZDo6dmVjdG9yPGludD4mIHhzICkKewoJc3RkOjp2ZWN0b3I8aW50PiB6czsKCXpzLnJlc2VydmUoIHhzLnNpemUoKSApOwoJZm9yICggaW50IHggOiB4cyApCgl7CgkJenMucHVzaF9iYWNrKCBzcXVhcmUoIHRpbWVzX3R3byggeCApICkgKTsKCX0KCXJldHVybiB6c1swXTsKfQoKLy8gbWFwICheMikgLiBtYXAgKF4yKSAkIFsxLDIsM10KaW50IHR3b19sb29wcyggY29uc3Qgc3RkOjp2ZWN0b3I8aW50PiYgeHMgKQp7CglzdGQ6OnZlY3RvcjxpbnQ+IHlzOwoJeXMucmVzZXJ2ZSggeHMuc2l6ZSgpICk7Cglmb3IgKCBpbnQgeCA6IHhzICkKCXsKCQl5cy5wdXNoX2JhY2soIHRpbWVzX3R3byggeCApICk7Cgl9CgoJc3RkOjp2ZWN0b3I8aW50PiB6czsKCXpzLnJlc2VydmUoIHlzLnNpemUoKSApOwoJZm9yICggaW50IHkgOiB5cyApCgl7CgkJenMucHVzaF9iYWNrKCBzcXVhcmUoIHkgKSApOwoJfQoJcmV0dXJuIHpzWzBdOwp9Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgRj4Kdm9pZCB0ZXN0KCBGIGYgKQp7Cgljb25zdCBzdGQ6OnZlY3RvcjxpbnQ+IHhzKCAxMDAwMDAwMDAsIDQyICk7CgoJY29uc3QgYXV0byBzdGFydF90aW1lID0gc3RkOjpjaHJvbm86OmhpZ2hfcmVzb2x1dGlvbl9jbG9jazo6bm93KCk7Cgljb25zdCBhdXRvIHJlc3VsdCA9IGYoIHhzICk7Cgljb25zdCBhdXRvIGVuZF90aW1lID0gc3RkOjpjaHJvbm86OmhpZ2hfcmVzb2x1dGlvbl9jbG9jazo6bm93KCk7CgoJY29uc3QgYXV0byBlbGFwc2VkID0gZW5kX3RpbWUgLSBzdGFydF90aW1lOwoJY29uc3QgYXV0byBlbGFwc2VkX3VzID0gc3RkOjpjaHJvbm86OmR1cmF0aW9uX2Nhc3Q8c3RkOjpjaHJvbm86Om1pY3Jvc2Vjb25kcz4oZWxhcHNlZCkuY291bnQoKTsKCXN0ZDo6Y291dCA8PCBlbGFwc2VkX3VzIC8gMTAwMCA8PCAiIG1zIC0gIiA8PCByZXN1bHQgPDwgc3RkOjplbmRsOwp9CgppbnQgbWFpbigpCnsKCXRlc3QoIG1hbnVhbF9mdXNpb24gKTsKCXRlc3QoIHR3b19sb29wcyApOwp9