diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 new file mode 100644 index 0000000..86842d4 --- /dev/null +++ b/example/Jamfile.v2 @@ -0,0 +1,74 @@ + +# Copyright (C) 2009-2012 Lorenzo Caminiti +# Distributed under the Boost Software License, Version 1.0 +# (see accompanying file LICENSE_1_0.txt or a copy at +# http://www.boost.org/LICENSE_1_0.txt) +# Home at http://www.boost.org/libs/local_function + +import testing ; + +project : requirements /boost//unit_test_framework ; + +run add_global_functor.cpp ; +run add_local_functor.cpp ; +# I'm not sure why this does not compile... I've asked Booster. +#run add_phoenix.cpp ; + +run const_block.cpp ; +# Compilation fails for debug but not for release builds so commented out. +#compile-fail const_block_err.cpp ; + +run expensive_copy_lambda.cpp ; +run expensive_copy_local_function.cpp ; + +run gcc_access.cpp ; +run gcc_lambda.cpp ; +run gcc_lambda_cpp11.cpp ; +run gcc_square.cpp ; +run gcc_store.cpp ; + +run impl_pp_keyword.cpp ; +run impl_tparam_tricks.cpp ; + +run n2529_this.cpp ; +run n2550_find_if.cpp ; + +compile-fail noncopyable_lambda_err.cpp ; +run noncopyable_local_function.cpp ; + +run phoenix_factorial.cpp ; +run phoenix_factorial_local.cpp ; + +exe profile_global_functor : profile_global_functor.cpp + : /boost/chrono//boost_chrono + /boost/system//boost_system + static + ; +exe profile_lambda : profile_lambda.cpp + : /boost/chrono//boost_chrono + /boost/system//boost_system + static + ; +exe profile_local_function : profile_local_function.cpp + : /boost/chrono//boost_chrono + /boost/system//boost_system + static + ; +exe profile_local_function_inline : profile_local_function_inline.cpp + : /boost/chrono//boost_chrono + /boost/system//boost_system + static + ; +exe profile_local_functor : profile_local_functor.cpp + : /boost/chrono//boost_chrono + /boost/system//boost_system + static + ; +exe profile_phoenix : profile_phoenix.cpp + : /boost/chrono//boost_chrono + /boost/system//boost_system + static + ; + +run scope_exit.cpp ; + diff --git a/example/add_global_functor.cpp b/example/add_global_functor.cpp new file mode 100644 index 0000000..479c1d3 --- /dev/null +++ b/example/add_global_functor.cpp @@ -0,0 +1,37 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#define BOOST_TEST_MODULE TestAddGlobalFunctor +#include +#include + +//[add_global_functor +// Unfortunately, cannot be defined locally (so not a real alternative). +struct global_add { // Unfortunately, boilerplate code to program the class. + global_add(int& _sum, int _factor): sum(_sum), factor(_factor) {} + + inline void operator()(int num) { // Body uses C++ statement syntax. + sum += factor * num; + } +private: // Unfortunately, cannot bind so repeat variable types. + int& sum; // Access `sum` by reference. + const int factor; // Make `factor` constant. +}; + +BOOST_AUTO_TEST_CASE( test_add_global_functor ) { + int sum = 0, factor = 10; + + global_add add(sum, factor); + + add(1); + int nums[] = {2, 3}; + std::for_each(nums, nums + 2, add); // Passed as template parameter. + + BOOST_CHECK( sum == 60 ); +} +//] + diff --git a/example/add_local_functor.cpp b/example/add_local_functor.cpp new file mode 100644 index 0000000..f856d94 --- /dev/null +++ b/example/add_local_functor.cpp @@ -0,0 +1,35 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#define BOOST_TEST_MODULE TestAddLocalFunctor +#include + +BOOST_AUTO_TEST_CASE( test_add_local_functor ) +//[add_local_functor +{ + int sum = 0, factor = 10; + + struct local_add { // Unfortunately, boilerplate code to program the class. + local_add(int& _sum, int _factor): sum(_sum), factor(_factor) {} + + inline void operator()(int num) { // Body uses C++ statement syntax. + sum += factor * num; + } + private: // Unfortunately, cannot bind so repeat variable types. + int& sum; // Access `sum` by reference. + const int factor; // Make `factor` constant. + } add(sum, factor); + + add(1); + int nums[] = {2, 3}; + // Unfortunately, cannot pass as template parameter to `std::for_each`. + for(size_t i = 0; i < 2; ++i) add(nums[i]); + + BOOST_CHECK( sum == 60 ); +} +//] + diff --git a/example/add_phoenix.cpp b/example/add_phoenix.cpp new file mode 100644 index 0000000..b971c8a --- /dev/null +++ b/example/add_phoenix.cpp @@ -0,0 +1,35 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include +#define BOOST_TEST_MODULE TestAddPhoenix +#include +#include +#include + +BOOST_AUTO_TEST_CASE( test_add_phoenix ) +//[add_phoenix +{ + using boost::phoenix::let; + using boost::phoenix::local_names::_f; + using boost::phoenix::cref; + using boost::phoenix::ref; + using boost::phoenix::arg_names::_1; + + int sum = 0, factor = 10; + int nums[] = {1, 2, 3}; + + // Passed to template, `factor` by constant, and defined in expression. + std::for_each(nums, nums + 3, let(_f = cref(factor))[ + // Unfortunately, body cannot use C++ statement syntax. + ref(sum) += _f * _1 // Access `sum` by reference. + ]); + + BOOST_CHECK( sum == 60 ); +} +//] + diff --git a/example/chrono.py b/example/chrono.py new file mode 100755 index 0000000..0766821 --- /dev/null +++ b/example/chrono.py @@ -0,0 +1,22 @@ + +# Copyright (C) 2009-2012 Lorenzo Caminiti +# Distributed under the Boost Software License, Version 1.0 +# (see accompanying file LICENSE_1_0.txt or a copy at +# http://www.boost.org/LICENSE_1_0.txt) +# Home at http://www.boost.org/libs/local_function + +import sys +import time +import os + +# Usage: python crono.py COMMAND [COMMAND_OPTIONS] + +cmd = "" +for arg in sys.argv[1:]: cmd += str(arg) + " " + +start = time.time() +ret = os.system(cmd) +sec = time.time() - start + +if (ret == 0): print "\n" + str(sec) + "s" + diff --git a/example/const_block.cpp b/example/const_block.cpp new file mode 100644 index 0000000..55fb5ec --- /dev/null +++ b/example/const_block.cpp @@ -0,0 +1,18 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include "const_block.hpp" +#include + +int main(void) { + int x = 0, y = 0; + CONST_BLOCK(x, y) { + assert(x == y); + } CONST_BLOCK_END + return 0; +} + diff --git a/example/const_block.hpp b/example/const_block.hpp new file mode 100644 index 0000000..824fb01 --- /dev/null +++ b/example/const_block.hpp @@ -0,0 +1,55 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#ifndef CONST_BLOCK_HPP_ +#define CONST_BLOCK_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// PRIVATE // + +#define CONST_BLOCK_BIND_(r, unused, i, var) \ + BOOST_PP_COMMA_IF(i) const bind& var + +#define CONST_BLOCK_(list) \ + void BOOST_LOCAL_FUNCTION( \ + BOOST_PP_IIF(BOOST_PP_LIST_IS_NIL(list), \ + void BOOST_PP_TUPLE_EAT(3) \ + , \ + BOOST_PP_LIST_FOR_EACH_I \ + )(CONST_BLOCK_BIND_, ~, list) \ + ) + +#define CONST_BLOCK_END_(id) \ + BOOST_LOCAL_FUNCTION_NAME(BOOST_PP_CAT(const_assert_, id)) \ + BOOST_PP_CAT(const_assert_, id)(); /* call local function immediately */ + +// PUBLIC // + +// Arguments `void | var1, var2, ... | (var1) (var2) ...`. +#ifdef BOOST_NO_VARIADIC_MACROS +# define CONST_BLOCK(void_or_seq) \ + CONST_BLOCK_(BOOST_LOCAL_FUNCTION_DETAIL_PP_VOID_LIST(void_or_seq)) +#else +# define CONST_BLOCK(...) \ + CONST_BLOCK_(BOOST_LOCAL_FUNCTION_DETAIL_PP_VOID_LIST(__VA_ARGS__)) +#endif + +#define CONST_BLOCK_END \ + CONST_BLOCK_END_(BOOST_LOCAL_FUNCTION_DETAIL_PP_LINE_COUNTER) + +#endif // #include guard + diff --git a/example/const_block_err.cpp b/example/const_block_err.cpp new file mode 100644 index 0000000..3e70c50 --- /dev/null +++ b/example/const_block_err.cpp @@ -0,0 +1,20 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include "const_block.hpp" +#include + +int main(void) { + //[const_block + int x = 1, y = 2; + CONST_BLOCK(x, y) { // Constant block. + assert(x = y); // Compiler error. + } CONST_BLOCK_END + //] + return 0; +} + diff --git a/example/expensive_copy_lambda.cpp b/example/expensive_copy_lambda.cpp new file mode 100644 index 0000000..d87cff5 --- /dev/null +++ b/example/expensive_copy_lambda.cpp @@ -0,0 +1,40 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include +#ifndef BOOST_NO_LAMBDAS + +#include +#include + +//[expensive_copy_lambda +struct n { + int i; + n(int _i): i(_i) {} + n(n const& x): i(x.i) { // Some time consuming copy. + for (unsigned i = 0; i < 10000; ++i) std::cout << '.'; + } +}; + +int main(void) { + n x(-1); + + auto f = [x]() { // Problem: Expensive copy, but if bind + assert( x.i == -1); // by `&x` then `x` is not constant. + }; + f(); + + return 0; +} +//] + +#else // NO_LAMBDAS + +int main(void) { return 0; } // Trivial program. + +#endif // NO_LAMBDAS + diff --git a/example/expensive_copy_local_function.cpp b/example/expensive_copy_local_function.cpp new file mode 100644 index 0000000..d732533 --- /dev/null +++ b/example/expensive_copy_local_function.cpp @@ -0,0 +1,32 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include +#include +#include + +//[expensive_copy_local_function +struct n { + int i; + n(int _i): i(_i) {} + n(n const& x): i(x.i) { // Some time consuming copy. + for (unsigned i = 0; i < 10000; ++i) std::cout << '.'; + } +}; + +int main(void) { + n x(-1); + + void BOOST_LOCAL_FUNCTION(const bind& x) { // OK: No copy + assert( x.i == -1 ); // and constant. + } BOOST_LOCAL_FUNCTION_NAME(f) + f(); + + return 0; +} +//] + diff --git a/example/gcc_access.cpp b/example/gcc_access.cpp new file mode 100644 index 0000000..bd7872b --- /dev/null +++ b/example/gcc_access.cpp @@ -0,0 +1,23 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include +#define BOOST_TEST_MODULE TestGccAccess +#include + +BOOST_AUTO_TEST_CASE( test_gcc_access ) { + int nums[] = {1, 2, 3}; + int offset = -1; + int BOOST_LOCAL_FUNCTION(const bind offset, int* array, int index) { + return array[index + offset]; + } BOOST_LOCAL_FUNCTION_NAME(access) + + BOOST_CHECK( access(nums, 1) == 1 ); + BOOST_CHECK( access(nums, 2) == 2 ); + BOOST_CHECK( access(nums, 3) == 3 ); +} + diff --git a/example/gcc_lambda.cpp b/example/gcc_lambda.cpp new file mode 100644 index 0000000..196c5e4 --- /dev/null +++ b/example/gcc_lambda.cpp @@ -0,0 +1,38 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include +#if defined(__GCC__) || !defined(BOOST_NO_LAMBDAS) + +#include "gcc_lambda.hpp" +#define BOOST_TEST_MODULE TestGccLambda +#include +#include + +BOOST_AUTO_TEST_CASE( test_gcc_lambda ) { + //[gcc_lambda + int val = 2; + int nums[] = {1, 2, 3}; + int* end = nums + 3; + + int* iter = std::find_if(nums, end, + GCC_LAMBDA(const bind val, int num, return bool) { + return num == val; + } GCC_LAMBDA_END + ); + //] + + BOOST_CHECK( iter != end ); + BOOST_CHECK( *iter == val ); +} + +#else // GCC || !NO_LAMBDAS + +int main(void) { return 0; } + +#endif // GCC || !NO_LAMBDAS + diff --git a/example/gcc_lambda.hpp b/example/gcc_lambda.hpp new file mode 100644 index 0000000..561e3df --- /dev/null +++ b/example/gcc_lambda.hpp @@ -0,0 +1,125 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#ifndef GCC_LAMBDA_HPP_ +#define GCC_LAMBDA_HPP_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// PRIVATE // + +#define GCC_LAMBDA_SPLIT_BIND_(elem, binds, params, results) \ + (BOOST_PP_LIST_APPEND(binds, (elem, BOOST_PP_NIL)), params, results) + +#define GCC_LAMBDA_SPLIT_PARAM_(elem, binds, params, results) \ + (binds, BOOST_PP_LIST_APPEND(params, (elem, BOOST_PP_NIL)), results) + +#define GCC_LAMBDA_SPLIT_RESULT_(elem, binds, params, results) \ + (binds, params, BOOST_PP_LIST_APPEND(results, (elem, BOOT_PP_NIL))) + +#define GCC_LAMBDA_SPLIT_DISPATCH_(d, binds_params_results, elem) \ + BOOST_PP_IIF(BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_IS_RETURN_FRONT(elem), \ + GCC_LAMBDA_SPLIT_RESULT_ \ + , BOOST_PP_IIF(BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_IS_BIND_FRONT(elem), \ + GCC_LAMBDA_SPLIT_BIND_ \ + , BOOST_PP_IIF(BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_IS_CONST_BIND_FRONT( \ + elem), \ + GCC_LAMBDA_SPLIT_BIND_ \ + , /* no result, no bind, and no const bind so it's param */ \ + GCC_LAMBDA_SPLIT_PARAM_ \ + )))(elem, BOOST_PP_TUPLE_ELEM(3, 0, binds_params_results), \ + BOOST_PP_TUPLE_ELEM(3, 1, binds_params_results), \ + BOOST_PP_TUPLE_ELEM(3, 2, binds_params_results)) + +#define GCC_LAMBDA_SPLIT_(list) \ + BOOST_PP_LIST_FOLD_LEFT(GCC_LAMBDA_SPLIT_DISPATCH_, \ + (BOOST_PP_NIL, BOOST_PP_NIL, BOOST_PP_NIL), list) + +#define GCC_LAMBDA_REMOVE_CONST_BIND_(r, unused, i, elem) \ + BOOST_PP_COMMA_IF(i) \ + BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_CONST_BIND_REMOVE_FRONT(elem) + +#define GCC_LAMBDA_RESULT_TYPE_(results) \ + BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_RETURN_REMOVE_FRONT( \ + BOOST_PP_LIST_FIRST(results)) + +#ifdef BOOST_NO_LAMBDAS +# define GCC_LAMBDA_(binds, params, results) \ + ({ /* open statement expression (GCC extension only) */ \ + BOOST_LOCAL_FUNCTION( \ + BOOST_PP_LIST_ENUM(BOOST_PP_LIST_APPEND(binds, \ + BOOST_PP_LIST_APPEND(params, \ + BOOST_PP_IIF(BOOST_PP_LIST_IS_NIL(results), \ + (return void, BOOST_PP_NIL) /* default for lambdas */ \ + , \ + results \ + )\ + ) \ + )) \ + ) +#else +# define GCC_LAMBDA_(binds, params, results) \ + /* ignore const binding because not supported by C++11 lambdas */ \ + [ BOOST_PP_LIST_FOR_EACH_I(GCC_LAMBDA_REMOVE_CONST_BIND_, ~, binds) ] \ + ( BOOST_PP_LIST_ENUM(params) ) \ + BOOST_PP_IIF(BOOST_PP_LIST_IS_NIL(results), \ + BOOST_PP_TUPLE_EAT(1) /* void result type (default) */ \ + , \ + -> GCC_LAMBDA_RESULT_TYPE_ \ + )(results) +#endif + +#define GCC_LAMBDA_TUPLE_(binds_params_results) \ + GCC_LAMBDA_(BOOST_PP_TUPLE_ELEM(3, 0, binds_params_results), \ + BOOST_PP_TUPLE_ELEM(3, 1, binds_params_results), \ + BOOST_PP_TUPLE_ELEM(3, 2, binds_params_results)) + +#define GCC_LAMBDA_END_(id) \ + BOOST_LOCAL_FUNCTION_NAME(BOOST_PP_CAT(gcc_lambda_, id)) \ + BOOST_PP_CAT(gcc_lambda_, id); \ + }) /* close statement expression (GCC extension only) */ + +// PUBLIC // + +// Same arguments as for local functions but respect to C++11 lambdas: +// const bind v is =v, bind& v is &v, void if no return specified, no = or &. +#ifdef BOOST_NO_VARIADIC_MACROS +# define GCC_LAMBDA(void_or_seq) \ + GCC_LAMBDA_TUPLE_(GCC_LAMBDA_SPLIT_( \ + BOOST_LOCAL_FUNCTION_DETAIL_PP_VOID_LIST(void_or_seq))) +#else +# define GCC_LAMBDA(...) \ + GCC_LAMBDA_TUPLE_(GCC_LAMBDA_SPLIT_( \ + BOOST_LOCAL_FUNCTION_DETAIL_PP_VOID_LIST(__VA_ARGS__))) +#endif + +#ifdef BOOST_NO_LAMBDAS +# define GCC_LAMBDA_END \ + GCC_LAMBDA_END_(BOOST_LOCAL_FUNCTION_DETAIL_PP_LINE_COUNTER) +#else +# define GCC_LAMBDA_END /* nothing */ +#endif + +#endif // #include guard + diff --git a/example/gcc_lambda_cpp11.cpp b/example/gcc_lambda_cpp11.cpp new file mode 100644 index 0000000..904bfa9 --- /dev/null +++ b/example/gcc_lambda_cpp11.cpp @@ -0,0 +1,37 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include +#ifndef BOOST_NO_LAMBDAS + +#define BOOST_TEST_MODULE TestGccLambdaCpp11 +#include +#include + +BOOST_AUTO_TEST_CASE( test_gcc_lambda_cpp11 ) { + //[gcc_lambda_cpp11 + int val = 2; + int nums[] = {1, 2, 3}; + int* end = nums + 3; + + int* iter = std::find_if(nums, end, + [val](int num) -> bool { + return num == val; + } + ); + //] + + BOOST_CHECK( iter != end ); + BOOST_CHECK( *iter == val ); +} + +#else // NO_LAMBDAS + +int main(void) { return 0; } // Trivial test. + +#endif // NO_LAMBDAS + diff --git a/example/gcc_square.cpp b/example/gcc_square.cpp new file mode 100644 index 0000000..9f7bbd7 --- /dev/null +++ b/example/gcc_square.cpp @@ -0,0 +1,23 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include +#define BOOST_TEST_MODULE TestGccSquare +#include + +double add_square(double a, double b) { + double BOOST_LOCAL_FUNCTION(double z) { + return z * z; + } BOOST_LOCAL_FUNCTION_NAME(square) + + return square(a) + square(b); +} + +BOOST_AUTO_TEST_CASE( test_gcc_square ) { + BOOST_CHECK( add_square(2.0, 4.0) == 20.0 ); +} + diff --git a/example/gcc_store.cpp b/example/gcc_store.cpp new file mode 100644 index 0000000..aca8dd9 --- /dev/null +++ b/example/gcc_store.cpp @@ -0,0 +1,33 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include +#include +#define BOOST_TEST_MODULE TestGccStore +#include + +void intermediate(boost::function store_func, int size) { + store_func(size - 1, -1); +} + +void hack(int* array, int size) { + void BOOST_LOCAL_FUNCTION(bind array, int index, int value) { + array[index] = value; + } BOOST_LOCAL_FUNCTION_NAME(store) + + intermediate(store, size); +} + +BOOST_AUTO_TEST_CASE( test_gcc_store ) { + int nums[] = {1, 2, 3}; + hack(nums, 3); + + BOOST_CHECK( nums[0] == 1 ); + BOOST_CHECK( nums[1] == 2 ); + BOOST_CHECK( nums[2] == -1 ); +} + diff --git a/example/impl_pp_keyword.cpp b/example/impl_pp_keyword.cpp new file mode 100644 index 0000000..2598705 --- /dev/null +++ b/example/impl_pp_keyword.cpp @@ -0,0 +1,28 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +//[impl_pp_keyword +#include +#include +#include +#define BOOST_TEST_MODULE TestImplPpKeyword +#include + +// Expand to 1 if space-separated tokens end with `this_`, 0 otherwise. +#define IS_THIS_BACK(tokens) \ + BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_IS_THISUNDERSCORE_BACK( \ + BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_BIND_REMOVE_FRONT( \ + BOOST_LOCAL_FUNCTION_DETAIL_PP_KEYWORD_CONST_REMOVE_FRONT( \ + tokens \ + ))) + +BOOST_AUTO_TEST_CASE( test_impl_pp_keyword ) { + BOOST_CHECK( IS_THIS_BACK(const bind this_) == 1 ); + BOOST_CHECK( IS_THIS_BACK(const bind& x) == 0 ); +} +//] + diff --git a/example/impl_tparam_tricks.cpp b/example/impl_tparam_tricks.cpp new file mode 100644 index 0000000..924471a --- /dev/null +++ b/example/impl_tparam_tricks.cpp @@ -0,0 +1,72 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +//[impl_tparam_tricks +#define BOOST_TEST_MODULE TestImplTparamTricks +#include +#include +#include + +// Casting functor trick. +struct casting_func { + explicit casting_func(void* obj, void (*call)(void*, const int&)): + obj_(obj), call_(call) {} + // Unfortunately, function pointer call is not inlined. + inline void operator()(const int& num) { call_(obj_, num); } +private: + void* obj_; + void (*call_)(void*, const int&); +}; + +// Virtual functor trick. +struct virtual_func { + struct interface { + // Unfortunately, virtual function call is not inlined. + inline virtual void operator()(const int&) {} + }; + explicit virtual_func(interface& func): func_(&func) {} + inline void operator()(const int& num) { (*func_)(num); } +private: + interface* func_; +}; + +BOOST_AUTO_TEST_CASE( test_impl_tparam_tricks ) { + int sum = 0, factor = 10; + + // Local class for local function. + struct local_add: virtual_func::interface { + explicit local_add(int& _sum, const int& _factor): + sum_(_sum), factor_(_factor) {} + inline void operator()(const int& num) { + body(sum_, factor_, num); + } + inline static void call( + void* obj, const int& num) { + local_add* self = static_cast(obj); + self->body(self->sum_, self->factor_, num); + } + private: + int& sum_; + const int& factor_; + inline void body(int& sum, const int& factor, const int& num) { + sum += factor * num; + } + } add_local(sum, factor); + casting_func add_casting(&add_local, &local_add::call); + virtual_func add_virtual(add_local); + + std::vector v(10); + std::fill(v.begin(), v.end(), 1); + +// std::for_each(v.begin(), v.end(), add_local); // Error but OK on C++11. + std::for_each(v.begin(), v.end(), add_casting); // OK. + std::for_each(v.begin(), v.end(), add_virtual); // OK. + + BOOST_CHECK( sum == 200 ); +} +//] + diff --git a/example/n2529_this.cpp b/example/n2529_this.cpp new file mode 100644 index 0000000..2388588 --- /dev/null +++ b/example/n2529_this.cpp @@ -0,0 +1,42 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include +#define BOOST_TEST_MODULE TestN2529This +#include +#include +#include + +struct v { + std::vector nums; + + v(const std::vector& numbers): nums(numbers) {} + + void change_sign_all(const std::vector& indices) { + void BOOST_LOCAL_FUNCTION(bind this_, int i) { // Bind object `this`. + this_->nums.at(i) = -this_->nums.at(i); + } BOOST_LOCAL_FUNCTION_NAME(complement) + + std::for_each(indices.begin(), indices.end(), complement); + } +}; + +BOOST_AUTO_TEST_CASE( test_n2529_this ) { + std::vector n(3); + n[0] = 1; n[1] = 2; n[2] = 3; + + std::vector i(2); + i[0] = 0; i[1] = 2; // Will change n[0] and n[2] but not n[1]. + + v vn(n); + vn.change_sign_all(i); + + BOOST_CHECK( vn.nums.at(0) == -1 ); + BOOST_CHECK( vn.nums.at(1) == 2 ); + BOOST_CHECK( vn.nums.at(2) == -3 ); +} + diff --git a/example/n2550_find_if.cpp b/example/n2550_find_if.cpp new file mode 100644 index 0000000..46e3596 --- /dev/null +++ b/example/n2550_find_if.cpp @@ -0,0 +1,41 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include +#define BOOST_TEST_MODULE TestN2550FindIf +#include +#include +#include + +struct employee { + int salary; + explicit employee(const int& a_salary): salary(a_salary) {} +}; + +BOOST_AUTO_TEST_CASE( test_n2550_find_if ) { + std::vector employees; + employees.push_back(employee( 85000)); + employees.push_back(employee(100000)); + employees.push_back(employee(120000)); + + int min_salary = 100000; + int u_limit = min_salary + 1; + + bool BOOST_LOCAL_FUNCTION(const bind& min_salary, const bind& u_limit, + const employee& e) { + return e.salary >= min_salary && e.salary < u_limit; + } BOOST_LOCAL_FUNCTION_NAME(between) + + // Pass local function to an STL algorithm as a template paramter (this + // cannot be done with plain member functions of local classes). + std::vector::iterator i = std::find_if( + employees.begin(), employees.end(), between); + + BOOST_CHECK( i != employees.end() ); + BOOST_CHECK( i->salary >= min_salary && i->salary < u_limit ); +} + diff --git a/example/noncopyable_lambda_err.cpp b/example/noncopyable_lambda_err.cpp new file mode 100644 index 0000000..6e92d12 --- /dev/null +++ b/example/noncopyable_lambda_err.cpp @@ -0,0 +1,37 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include +#ifndef BOOST_NO_LAMBDAS + +#include +#include + +//[noncopyable_lambda_err +struct n: boost::noncopyable { + int i; + n(int _i): i(_i) {} +}; + +int main(void) { + n x(-1); + + auto f = [x](void) { // Error: x is non-copyable, but if + assert( x.i == -1 ); // bind `&x` then `x` is not constant. + }; + f(); + + return 0; +} +//] + +#else // NO_LAMBDAS + +#error "Trivial failure." + +#endif // NO_LAMBDAS + diff --git a/example/noncopyable_local_function.cpp b/example/noncopyable_local_function.cpp new file mode 100644 index 0000000..9f76afb --- /dev/null +++ b/example/noncopyable_local_function.cpp @@ -0,0 +1,29 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include +#include +#include + +//[noncopyable_local_function +struct n: boost::noncopyable { + int i; + n(int _i): i(_i) {} +}; + +int main() { + n x(-1); + + void BOOST_LOCAL_FUNCTION(const bind& x) { // OK: No copy + assert( x.i == -1 ); // and constant. + } BOOST_LOCAL_FUNCTION_NAME(f) + f(); + + return 0; +} +//] + diff --git a/example/phoenix_factorial.cpp b/example/phoenix_factorial.cpp new file mode 100644 index 0000000..e3cb92b --- /dev/null +++ b/example/phoenix_factorial.cpp @@ -0,0 +1,40 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include +#include +#define BOOST_TEST_MODULE TestPhoenixFactorial +#include + +//[phoenix_factorial +struct factorial_impl { // Phoenix function from global functor. + template + struct result; + + template + struct result : result {}; + + template + struct result { typedef Arg type; }; + + template // Polymorphic. + Arg operator()(Arg n) const { + return (n <= 0) ? 1 : n * (*this)(n - 1); + } +}; + +BOOST_AUTO_TEST_CASE( test_phoenix_factorial ) { + using boost::phoenix::arg_names::arg1; + + boost::phoenix::function factorial; + + int i = 4; + BOOST_CHECK( factorial(i)() == 24 ); // Call. + BOOST_CHECK( factorial(arg1)(i) == 24 ); // Lazy call. +} +//] + diff --git a/example/phoenix_factorial_local.cpp b/example/phoenix_factorial_local.cpp new file mode 100644 index 0000000..94f358f --- /dev/null +++ b/example/phoenix_factorial_local.cpp @@ -0,0 +1,31 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include +#include +#include +#include +#define BOOST_TEST_MODULE TestPhoenixFactorialLocal +#include + +//[phoenix_factorial_local +BOOST_AUTO_TEST_CASE( test_phoenix_factorial_local ) { + using boost::phoenix::arg_names::arg1; + + int BOOST_LOCAL_FUNCTION(int n) { // Unfortunately, monomorphic. + return (n <= 0) ? 1 : n * factorial_impl(n - 1); + } BOOST_LOCAL_FUNCTION_NAME(recursive factorial_impl) + + boost::phoenix::function< boost::function > + factorial(factorial_impl); // Phoenix function from local function. + + int i = 4; + BOOST_CHECK( factorial(i)() == 24 ); // Call. + BOOST_CHECK( factorial(arg1)(i) == 24 ); // Lazy call. +} +//] + diff --git a/example/profile.xls b/example/profile.xls new file mode 100644 index 0000000..9087ed1 Binary files /dev/null and b/example/profile.xls differ diff --git a/example/profile_gcc_cpp11_debug.png b/example/profile_gcc_cpp11_debug.png new file mode 100644 index 0000000..2bc7b6b Binary files /dev/null and b/example/profile_gcc_cpp11_debug.png differ diff --git a/example/profile_gcc_cpp11_release.png b/example/profile_gcc_cpp11_release.png new file mode 100644 index 0000000..ea7d880 Binary files /dev/null and b/example/profile_gcc_cpp11_release.png differ diff --git a/example/profile_gcc_debug.png b/example/profile_gcc_debug.png new file mode 100644 index 0000000..84e88a2 Binary files /dev/null and b/example/profile_gcc_debug.png differ diff --git a/example/profile_gcc_release.png b/example/profile_gcc_release.png new file mode 100644 index 0000000..c10f287 Binary files /dev/null and b/example/profile_gcc_release.png differ diff --git a/example/profile_global_functor.cpp b/example/profile_global_functor.cpp new file mode 100644 index 0000000..6e104e4 --- /dev/null +++ b/example/profile_global_functor.cpp @@ -0,0 +1,51 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include +#include +#include +#include +#include "profile_helpers.hpp" + +struct global_add { + global_add(double& _sum, const int& _factor): sum(_sum), factor(_factor) {} + inline void operator()(const double& num) { + sum += factor * num; + } +private: + double& sum; + const int& factor; +}; + +int main(int argc, char* argv[]) { + unsigned long size = 0, trials =0; + profile::args(argc, argv, size, trials); + + double sum = 0.0; + int factor = 1; + + boost::chrono::system_clock::time_point start = + boost::chrono::system_clock::now(); + global_add add(sum, factor); + boost::chrono::duration decl_sec = + boost::chrono::system_clock::now() - start; + + std::vector v(size); + std::fill(v.begin(), v.end(), 1.0); + + boost::chrono::duration trials_sec; + for(unsigned long i = 0; i < trials; ++i) { + boost::chrono::system_clock::time_point start = + boost::chrono::system_clock::now(); + std::for_each(v.begin(), v.end(), add); + trials_sec += boost::chrono::system_clock::now() - start; + } + + profile::display(size, trials, sum, trials_sec.count(), decl_sec.count()); + return 0; +} + diff --git a/example/profile_helpers.hpp b/example/profile_helpers.hpp new file mode 100644 index 0000000..fe7969d --- /dev/null +++ b/example/profile_helpers.hpp @@ -0,0 +1,54 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#ifndef PROFILE_HELPERS_HPP_ +#define PROFILE_HELPERS_HPP_ + +#include +#include + +namespace profile { + +void args(int argc, char* argv[], unsigned long& size, unsigned long& trials) { + size = 100000000; // Defaults. + trials = 10; // Default. + if (argc != 1 && argc != 2 && argc != 3) { + std::cerr << "ERROR: Incorrect argument(s)" << std::endl; + std::cerr << "Usage: " << argv[0] << " [SIZE] [TRIALS]" << + std::endl; + std::cerr << "Defaults: SIZE = " << double(size) << ", TRIALS = " << + double(trials) << std::endl; + exit(1); + } + if (argc >= 2) size = atol(argv[1]); + if (argc >= 3) trials = atol(argv[2]); + + std::clog << "vector size = " << double(size) << std::endl; + std::clog << "number of trials = " << double(trials) << std::endl; + std::clog << "number of calls = " << double(size) * double(trials) << + std::endl; +} + +void display(const unsigned long& size, const unsigned long& trials, + const double& sum, const double& trials_sec, + const double& decl_sec = 0.0) { + std::clog << "sum = " << sum << std::endl; + std::clog << "declaration run-time [s] = " << decl_sec << std::endl; + std::clog << "trials run-time [s] = " << trials_sec << std::endl; + + double avg_sec = decl_sec + trials_sec / trials; + std::clog << "average run-time [s] = declaration run-time + trials " << + "run-time / number of trials = " << std::endl; + std::cout << avg_sec << std::endl; // To cout so it can be parsed easily. + + assert(sum == double(size) * double(trials)); +} + +} // namespace + +#endif // #include guard + diff --git a/example/profile_lambda.cpp b/example/profile_lambda.cpp new file mode 100644 index 0000000..a30ef8c --- /dev/null +++ b/example/profile_lambda.cpp @@ -0,0 +1,46 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include +#ifndef BOOST_NO_LAMBDAS + +#include +#include +#include +#include +#include "profile_helpers.hpp" + +int main(int argc, char* argv[]) { + unsigned long size = 0, trials = 0; + profile::args(argc, argv, size, trials); + + double sum = 0.0; + int factor = 1; + + std::vector v(size); + std::fill(v.begin(), v.end(), 1.0); + + boost::chrono::duration trials_sec; + for(unsigned long i = 0; i < trials; ++i) { + boost::chrono::system_clock::time_point start = + boost::chrono::system_clock::now(); + std::for_each(v.begin(), v.end(), [&sum, factor](const double& num) { + sum += factor * num; + }); + trials_sec += boost::chrono::system_clock::now() - start; + } + + profile::display(size, trials, sum, trials_sec.count()); + return 0; +} + +#else // NO_LAMBDAS + +int main(void) { return 0; } // Trivial program. + +#endif // NO_LAMBDAS + diff --git a/example/profile_legend_global_functor.png b/example/profile_legend_global_functor.png new file mode 100644 index 0000000..d7f5b70 Binary files /dev/null and b/example/profile_legend_global_functor.png differ diff --git a/example/profile_legend_lambda.png b/example/profile_legend_lambda.png new file mode 100644 index 0000000..58770b1 Binary files /dev/null and b/example/profile_legend_lambda.png differ diff --git a/example/profile_legend_local_function.png b/example/profile_legend_local_function.png new file mode 100644 index 0000000..5b9b517 Binary files /dev/null and b/example/profile_legend_local_function.png differ diff --git a/example/profile_legend_local_function_inline.png b/example/profile_legend_local_function_inline.png new file mode 100644 index 0000000..809de56 Binary files /dev/null and b/example/profile_legend_local_function_inline.png differ diff --git a/example/profile_legend_local_functor.png b/example/profile_legend_local_functor.png new file mode 100644 index 0000000..6038c57 Binary files /dev/null and b/example/profile_legend_local_functor.png differ diff --git a/example/profile_legend_phoenix.png b/example/profile_legend_phoenix.png new file mode 100644 index 0000000..2499625 Binary files /dev/null and b/example/profile_legend_phoenix.png differ diff --git a/example/profile_local_function.cpp b/example/profile_local_function.cpp new file mode 100644 index 0000000..1e2029a --- /dev/null +++ b/example/profile_local_function.cpp @@ -0,0 +1,45 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include +#include +#include +#include +#include +#include "profile_helpers.hpp" + +int main(int argc, char* argv[]) { + unsigned long size = 0, trials = 0; + profile::args(argc, argv, size, trials); + + double sum = 0.0; + int factor = 1; + + boost::chrono::system_clock::time_point start = + boost::chrono::system_clock::now(); + void BOOST_LOCAL_FUNCTION( + const double& num, bind& sum, const bind& factor) { + sum += factor * num; + } BOOST_LOCAL_FUNCTION_NAME(add) + boost::chrono::duration decl_sec = + boost::chrono::system_clock::now() - start; + + std::vector v(size); + std::fill(v.begin(), v.end(), 1.0); + + boost::chrono::duration trials_sec; + for(unsigned long i = 0; i < trials; ++i) { + boost::chrono::system_clock::time_point start = + boost::chrono::system_clock::now(); + std::for_each(v.begin(), v.end(), add); + trials_sec += boost::chrono::system_clock::now() - start; + } + + profile::display(size, trials, sum, trials_sec.count(), decl_sec.count()); + return 0; +} + diff --git a/example/profile_local_function_inline.cpp b/example/profile_local_function_inline.cpp new file mode 100644 index 0000000..8b113ac --- /dev/null +++ b/example/profile_local_function_inline.cpp @@ -0,0 +1,45 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include +#include +#include +#include +#include +#include "profile_helpers.hpp" + +int main(int argc, char* argv[]) { + unsigned long size = 0, trials = 0; + profile::args(argc, argv, size, trials); + + double sum = 0.0; + int factor = 1; + + boost::chrono::system_clock::time_point start = + boost::chrono::system_clock::now(); + void BOOST_LOCAL_FUNCTION( + const double& num, bind& sum, const bind& factor) { + sum += factor * num; + } BOOST_LOCAL_FUNCTION_NAME(inline add) // Inlined. + boost::chrono::duration decl_sec = + boost::chrono::system_clock::now() - start; + + std::vector v(size); + std::fill(v.begin(), v.end(), 1.0); + + boost::chrono::duration trials_sec; + for(unsigned long i = 0; i < trials; ++i) { + boost::chrono::system_clock::time_point start = + boost::chrono::system_clock::now(); + for(unsigned long j = 0; j < v.size(); ++j) add(v[j]); // No for_each. + trials_sec += boost::chrono::system_clock::now() - start; + } + + profile::display(size, trials, sum, trials_sec.count(), decl_sec.count()); + return 0; +} + diff --git a/example/profile_local_functor.cpp b/example/profile_local_functor.cpp new file mode 100644 index 0000000..abdef0b --- /dev/null +++ b/example/profile_local_functor.cpp @@ -0,0 +1,50 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include +#include +#include +#include +#include "profile_helpers.hpp" + +int main(int argc, char* argv[]) { + unsigned long size = 0, trials = 0; + profile::args(argc, argv, size, trials); + + double sum = 0.0; + int factor = 1; + + boost::chrono::system_clock::time_point start = + boost::chrono::system_clock::now(); + struct local_add { + local_add(double& _sum, const int& _factor): + sum(_sum), factor(_factor) {} + inline void operator()(const double& num) { + sum += factor * num; + } + private: + double& sum; + const int& factor; + } add(sum, factor); + boost::chrono::duration decl_sec = + boost::chrono::system_clock::now() - start; + + std::vector v(size); + std::fill(v.begin(), v.end(), 1.0); + + boost::chrono::duration trials_sec; + for(unsigned long i = 0; i < trials; ++i) { + boost::chrono::system_clock::time_point start = + boost::chrono::system_clock::now(); + for(unsigned long j = 0; j < v.size(); ++j) add(v[j]); // No for_each. + trials_sec += boost::chrono::system_clock::now() - start; + } + + profile::display(size, trials, sum, trials_sec.count(), decl_sec.count()); + return 0; +} + diff --git a/example/profile_msvc_debug.png b/example/profile_msvc_debug.png new file mode 100644 index 0000000..225f122 Binary files /dev/null and b/example/profile_msvc_debug.png differ diff --git a/example/profile_msvc_release.png b/example/profile_msvc_release.png new file mode 100644 index 0000000..b447211 Binary files /dev/null and b/example/profile_msvc_release.png differ diff --git a/example/profile_phoenix.cpp b/example/profile_phoenix.cpp new file mode 100644 index 0000000..7bd2088 --- /dev/null +++ b/example/profile_phoenix.cpp @@ -0,0 +1,45 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include +#include +#include +#include +#include +#include +#include +#include +#include "profile_helpers.hpp" + +int main(int argc, char* argv[]) { + unsigned long size = 0, trials = 0; + profile::args(argc, argv, size, trials); + + double sum = 0.0; + int factor = 1; + + std::vector v(size); + std::fill(v.begin(), v.end(), 1.0); + + boost::chrono::duration trials_sec; + for(unsigned long i = 0; i < trials; ++i) { + boost::chrono::system_clock::time_point start = + boost::chrono::system_clock::now(); + + using boost::phoenix::ref; + using boost::phoenix::arg_names::_1; + std::for_each(v.begin(), v.end(), ( + ref(sum) += factor * _1 + )); + + trials_sec += boost::chrono::system_clock::now() - start; + } + + profile::display(size, trials, sum, trials_sec.count()); + return 0; +} + diff --git a/example/scope_exit.cpp b/example/scope_exit.cpp new file mode 100644 index 0000000..438f8ca --- /dev/null +++ b/example/scope_exit.cpp @@ -0,0 +1,110 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#include "scope_exit.hpp" +#include +#include +#include +#include BOOST_TYPEOF_INCREMENT_REGISTRATION_GROUP() +#define BOOST_TEST_MODULE TestScopeExit +#include +#include +#include +#include + +class person; BOOST_TYPEOF_REGISTER_TYPE(person) +class person { + friend class world; +public: + typedef unsigned int id_t; + typedef unsigned int evolution_t; + + person(void): id_(0), evolution_(0) {} + + friend std::ostream& operator<<(std::ostream& o, person const& p) { + return o << "person(" << p.id_ << ", " << p.evolution_ << ")"; + } +private: + id_t id_; + evolution_t evolution_; +}; + +class world; BOOST_TYPEOF_REGISTER_TYPE(world) +class world { +public: + typedef unsigned int id_t; + + world(void): next_id_(1) {} + + void add_person(person const& a_person); + + friend std::ostream& operator<<(std::ostream& o, world const& w) { + o << "world(" << w.next_id_ << ", {"; + BOOST_FOREACH(person const& p, w.persons_) { + o << " " << p << ", "; + } + return o << "})"; + } +private: + id_t next_id_; + std::vector persons_; +}; + +void world::add_person(person const& a_person) { + persons_.push_back(a_person); + + // This block must be no-throw. + //[scope_exit + person& p = persons_.back(); + person::evolution_t checkpoint = p.evolution_; + + SCOPE_EXIT(const bind checkpoint, const bind& p, bind this_) { + if (checkpoint == p.evolution_) this_->persons_.pop_back(); + } SCOPE_EXIT_END + //] + + // ... + + checkpoint = ++p.evolution_; + + // Assign new id to the person. + world::id_t const prev_id = p.id_; + p.id_ = next_id_++; + SCOPE_EXIT(const bind checkpoint, const bind prev_id, bind& p, + bind& next_id_) { + if (checkpoint == p.evolution_) { + next_id_ = p.id_; + p.id_ = prev_id; + } + } SCOPE_EXIT_END + + // ... + + checkpoint = ++p.evolution_; +} + +BOOST_AUTO_TEST_CASE( test_scope_exit ) { + person adam, eva; + std::ostringstream oss; + oss << adam; + std::cout << oss.str() << std::endl; + BOOST_CHECK( oss.str() == "person(0, 0)" ); + + oss.str(""); + oss << eva; + std::cout << oss.str() << std::endl; + BOOST_CHECK( oss.str() == "person(0, 0)" ); + + world w; + w.add_person(adam); + w.add_person(eva); + oss.str(""); + oss << w; + std::cout << oss.str() << std::endl; + BOOST_CHECK( oss.str() == "world(3, { person(1, 2), person(2, 2), })" ); +} + diff --git a/example/scope_exit.hpp b/example/scope_exit.hpp new file mode 100644 index 0000000..2b1b387 --- /dev/null +++ b/example/scope_exit.hpp @@ -0,0 +1,47 @@ + +// Copyright (C) 2009-2012 Lorenzo Caminiti +// Distributed under the Boost Software License, Version 1.0 +// (see accompanying file LICENSE_1_0.txt or a copy at +// http://www.boost.org/LICENSE_1_0.txt) +// Home at http://www.boost.org/libs/local_function + +#ifndef SCOPE_EXIT_HPP_ +#define SCOPE_EXIT_HPP_ + +#include +#include +#include +#include +#include + +//[scope_exit_class +struct scope_exit { + scope_exit(boost::function f): f_(f) {} + ~scope_exit(void) { f_(); } +private: + boost::function f_; +}; +//] + +// PRIVATE // + +#define SCOPE_EXIT_END_(id) \ + BOOST_LOCAL_FUNCTION_NAME(BOOST_PP_CAT(scope_exit_func_, id)) \ + scope_exit BOOST_PP_CAT(scope_exit_, id)( \ + BOOST_PP_CAT(scope_exit_func_, id)); + +// PUBLIC // + +#ifdef BOOST_NO_VARIADIC_MACROS +# define SCOPE_EXIT(void_or_seq) \ + void BOOST_LOCAL_FUNCTION(void_or_seq) +#else +# define SCOPE_EXIT(...) \ + void BOOST_LOCAL_FUNCTION(__VA_ARGS__) +#endif + +#define SCOPE_EXIT_END \ + SCOPE_EXIT_END_(BOOST_LOCAL_FUNCTION_DETAIL_PP_LINE_COUNTER) + +#endif // #include guard +