// //======================================================================= // Copyright 2012 // Author: Alex Hagen-Zanker // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) //======================================================================= // // Comparing three strategies for creating algorithm objects // - using fragmented functions // - using the proposed boost coroutine library [1] // - using the boost asio stackless coroutine example [2] // // [1] http://lists.boost.org/boost-announce/2012/09/0366.php // [2] http://blog.think-async.com/2010/03/potted-guide-to-stackless-coroutines.html // //======================================================================= // #pragma warning(disable: 4355)// using 'this' in constructor #include // Part of proposed coroutine library #include #include #include #include static const bool compile_switch_1 = true; // should the algorithm check the sum upon initialization static const bool compile_switch_2 = true; // should the algorithm check the sum upon updating // This file is demonstrating the general principal followed for creating algorithm objects in coroutine_dijkstra and object_dijkstra int sum_function(const std::vector& v) { int sum =0; if(compile_switch_1 && sum < 0) std::cout << "this should not happen" << std::endl; std::vector::const_iterator i(v.begin()), i_end(v.end()); for(; i!=i_end; ++i) { sum += *i; if(compile_switch_2 && sum < 0) std::cout << "this should not happen" << std::endl; } return sum; } // Applying the fragmented functions method namespace s1 { struct sum_function_class { enum result { finish, report, continue_ }; typedef result (sum_function_class::*resume_function_type)(); // pointer to next resume function public: sum_function_class(const std::vector& v) : resume(&sum_function_class::start), v(v) {} void init() { resume = &sum_function_class::start; } bool next() { while(true) { switch( (this->*resume)() ) { case finish: return false; case report: return true; //case intermediate:do nothing } } } int get_sum() { return sum; } private: result start() { i = v.begin(); i_end = v.end(); sum = 0; if(compile_switch_1) { resume = &sum_function_class::check; return report; } else { return check(); } } result check() { if(i!=i_end) { resume = &sum_function_class::body; return continue_; // to prevent the resume function from becoming recursive } return finish; } result body() { sum += *i; if(compile_switch_2) { resume = &sum_function_class::increment; return report; } else { return increment(); } } result increment() { ++i; return check(); } resume_function_type resume; int sum; std::vector::const_iterator i, i_end; const std::vector& v; }; }//s1 // Using the boost coroutine library that is under review namespace s2 { struct sum_function_class { typedef boost::coro::coroutine coroutine_type; public: sum_function_class(const std::vector& v) : coroutine_sum(boost::bind(&sum_function_class::func, this, _1) ), v(v) {} bool next() { coroutine_sum(); return !coroutine_sum.is_complete(); } int get_sum() { return sum; } private: void func(coroutine_type::self_t& self) { sum =0; i = v.begin(); i_end = v.end(); if(compile_switch_1) self.yield(); for(; i!=i_end; ++i) { sum += *i; if(compile_switch_2) self.yield(); } } coroutine_type coroutine_sum; int sum; std::vector::const_iterator i, i_end; const std::vector& v; }; } //s2 // Using the lightweight Boost.Asio coroutine; namespace s3 { struct sum_function_class { public: sum_function_class(const std::vector& v) : v(v) {} bool next() { func(); return !coroutine_sum.is_complete(); } int get_sum() { return sum; } private: void func() { CORO_REENTER(coroutine_sum) { sum = 0; i = v.begin(); i_end = v.end(); if(compile_switch_1) CORO_YIELD; for(; i!=i_end; ++i) { sum += *i; if(compile_switch_2) CORO_YIELD; } } } coroutine coroutine_sum; int sum; std::vector::const_iterator i, i_end; const std::vector& v; }; } //s3 int demo_algorithm_objects() { std::vector small; small.push_back(1); small.push_back(3); small.push_back(4); small.push_back(2); small.push_back(8); s1::sum_function_class s1_small(small); while(s1_small.next()) { std::cout << "Fragmented_sum intermediate: " << s1_small.get_sum() << std::endl; } std::cout << "Fragmented_sum final: " << s1_small.get_sum() << std::endl; std::cout << std::endl; s2::sum_function_class s2_small(small); while(s2_small.next()) { std::cout << "Boost.Coroutine intermediate: " << s2_small.get_sum() << std::endl; } std::cout << "Boost.Coroutine final: " << s2_small.get_sum() << std::endl; std::cout << std::endl; s3::sum_function_class s3_small(small); while(s3_small.next()) { std::cout << "Boost.Asio.Coroutine intermediate: " << s3_small.get_sum() << std::endl; } std::cout << "Boost.Asio.Coroutine final: " << s3_small.get_sum() << std::endl; std::cout << std::endl; std::vector large(10000000, 2); clock_t t1 = clock(); std::cout << "sum plain : " << sum_function(large); clock_t t2 = clock(); std::cout << " time: " << (t2 - t1) / (double)(CLOCKS_PER_SEC) << std::endl;; s1::sum_function_class s1_large(large); while(s1_large.next()) { if(s1_large.get_sum() < 0) std::cout <<"this should not happen"<< std::endl; } std::cout << "sum fragmented : " << s1_large.get_sum(); clock_t t3 = clock(); std::cout << " time: " << (t3 - t2) / (double)(CLOCKS_PER_SEC) << std::endl;; s2::sum_function_class s2_large(large); while(s2_large.next()){ if(s2_large.get_sum() < 0) std::cout <<"this should not happen"<< std::endl; } std::cout << "sum boost coro : "<< s2_large.get_sum(); clock_t t4 = clock(); std::cout << " time: " << (t4 - t3) / (double)(CLOCKS_PER_SEC) << std::endl; s3::sum_function_class s3_large(large); while(s3_large.next()){ if(s3_large.get_sum() < 0) std::cout <<"this should not happen"<< std::endl; } std::cout << "sum asio coro : "<< s3_large.get_sum(); clock_t t5 = clock(); std::cout << " time: " << (t5 - t4) / (double)(CLOCKS_PER_SEC) << std::endl; std::cout << std::endl; return 0; } int main() { demo_algorithm_objects(); }