├── .appveyor.yml ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── BoostBook.pro ├── Chapter01 ├── 01_A_program_options_base │ ├── 01_A_program_options_base.pro │ └── main.cpp ├── 01_B_program_options_short │ ├── 01_B_program_options_short.pro │ ├── apples_oranges.cfg │ └── main.cpp ├── 02_any │ ├── 02_any.pro │ └── main.cpp ├── 03_variant │ ├── 03_variant.pro │ └── main.cpp ├── 04_A_any_db_example │ ├── 04_A_any_db_example.pro │ └── main.cpp ├── 04_B_variant_db_example │ ├── 04_B_variant_db_example.pro │ └── main.cpp ├── 05_optional │ ├── 05_optional.pro │ └── main.cpp ├── 06_array │ ├── 06_array.pro │ └── main.cpp ├── 07_A_tuple │ ├── 07_A_tuple.pro │ └── main.cpp ├── 07_B_tuple_construction_order │ ├── 07_B_tuple_construction_order.pro │ └── main.cpp ├── 08_bind │ ├── 08_bind.pro │ └── main.cpp ├── 09_type_index │ ├── 09_type_index.pro │ └── main.cpp ├── 10_A_move │ ├── 10_A_move.pro │ └── main.cpp ├── 10_B_move_c++11 │ └── 10_B_move_c++11.pro ├── 11_noncopyable │ ├── 11_noncopyable.pro │ └── main.cpp ├── 12_A_noncopyable_movable │ ├── 12_A_noncopyable_movable.pro │ └── main.cpp ├── 12_B_noncopyable_movable_c++11 │ └── 12_B_noncopyable_movable_c++11.pro ├── 13_algorithm │ ├── 13_algorithm.pro │ └── main.cpp └── Chapter01.pro ├── Chapter02 ├── 01_scoped_ptr │ ├── 01_scoped_ptr.pro │ └── main.cpp ├── 02_shared_ptr │ ├── 02_shared_ptr.pro │ └── main.cpp ├── 03_scoped_array │ ├── 03_scoped_array.pro │ └── main.cpp ├── 04_shared_array │ ├── 04_shared_array.pro │ └── main.cpp ├── 05_function_fobject │ ├── 05_function_fobject.pro │ └── main.cpp ├── 06_function_fpointer │ ├── 06_function_fpointer.pro │ └── main.cpp ├── 07_function_lambda_c++11 │ ├── 07_function_lambda_c++11.pro │ └── main.cpp ├── 08_ptr_container_c++11 │ ├── 08_ptr_container_c++11.pro │ └── main.cpp ├── 09_scope_exit │ ├── 09_scope_exit.pro │ └── main.cpp ├── 10_base_from_member │ ├── 10_base_from_member.pro │ └── main.cpp └── Chapter02.pro ├── Chapter03 ├── 01_lexical_to_number │ ├── 01_lexical_to_number.pro │ └── main.cpp ├── 02_lexical_to_string │ ├── 02_lexical_to_string.pro │ └── main.cpp ├── 03_numeric_cast │ ├── 03_numeric_cast.pro │ └── main.cpp ├── 04_lexical_user_defined │ ├── 04_lexical_user_defined.pro │ └── main.cpp ├── 05_pointer_cast │ ├── 05_pointer_cast.pro │ └── main.cpp ├── 06_polymorphic_cast │ ├── 06_polymorphic_cast.pro │ └── main.cpp ├── 07_spirit │ ├── 07_spirit.pro │ └── main.cpp ├── 08_spirit_rules │ ├── 08_spirit_rules.pro │ └── main.cpp └── Chapter03.pro ├── Chapter04 ├── 01_static_assert │ ├── 01_static_assert.pro │ └── main.cpp ├── 02_enable_if_c │ ├── 02_enable_if_c.pro │ └── main.cpp ├── 03_disable_if_c │ ├── 03_disable_if_c.pro │ └── main.cpp ├── 04_mpl_int_ │ ├── 04_mpl_int_.pro │ └── main.cpp ├── 05_is_stdvector │ ├── 05_is_stdvector.pro │ └── main.cpp ├── 06_conditional │ ├── 06_conditional.pro │ └── main.cpp ├── 07_typeof │ ├── 07_typeof.pro │ └── main.cpp └── Chapter04.pro ├── Chapter05 ├── 01_thread │ ├── 01_thread.pro │ └── main.cpp ├── 02_mutex │ ├── 02_mutex.pro │ └── main.cpp ├── 03_atomics │ ├── 03_atomics.pro │ └── main.cpp ├── 04_work_queue │ ├── 04_work_queue.pro │ └── main.cpp ├── 05_shared_lock │ ├── 05_shared_lock.pro │ └── main.cpp ├── 06_thread_specific_ptr │ ├── 06_thread_specific_ptr.pro │ └── main.cpp ├── 07_interruptions │ ├── 07_interruptions.pro │ └── main.cpp ├── 08_thread_group │ ├── 08_thread_group.pro │ └── main.cpp ├── 09_once │ ├── 09_once.pro │ └── main.cpp ├── 10_locks │ ├── 10_locks.pro │ └── main.cpp └── Chapter05.pro ├── Chapter06 ├── 01_tasks_processor_base │ ├── 01_tasks_processor_base.pro │ ├── main.cpp │ └── tasks_processor_base.hpp ├── 02_tasks_processor_timers │ ├── 02_tasks_processor_timers.pro │ ├── main.cpp │ └── tasks_processor_timers.hpp ├── 03_tasks_processor_network_client │ ├── 03_tasks_processor_network_client.pro │ ├── client.cpp │ ├── client.hpp │ └── tasks_processor_network_client.hpp ├── 04_tasks_processor_network_accept │ ├── 04_tasks_processor_network_accept.pro │ ├── main.cpp │ └── tasks_processor_network_accept.hpp ├── 05_tasks_processor_multithread │ ├── 05_tasks_processor_multithread.pro │ ├── main.cpp │ └── tasks_processor_multithread.hpp ├── 06_conveyor │ ├── 06_conveyor.pro │ └── main.cpp ├── 07_nonblocking_barrier │ ├── 07_nonblocking_barrier.pro │ └── main.cpp ├── 08_exception_ptr │ ├── 08_exception_ptr.pro │ └── main.cpp ├── 09_tasks_processor_signals │ ├── 09_tasks_processor_signals.pro │ ├── main.cpp │ └── tasks_processor_signals.hpp ├── Chapter06.pro └── flat │ ├── 01_tasks_processor_base │ ├── 01_tasks_processor_base.pro │ └── main.cpp │ ├── 02_tasks_processor_timers │ ├── 02_tasks_processor_timers.pro │ └── main.cpp │ ├── 04_tasks_processor_network_accept │ ├── 04_tasks_processor_network_accept.pro │ └── main.cpp │ ├── 05_tasks_processor_multithread │ ├── 05_tasks_processor_multithread.pro │ └── main.cpp │ ├── 07_nonblocking_barrier │ ├── 07_nonblocking_barrier.pro │ └── main.cpp │ ├── 08_exception_ptr │ ├── 08_exception_ptr.pro │ └── main.cpp │ ├── 09_tasks_processor_signals │ ├── 09_tasks_processor_signals.pro │ └── main.cpp │ ├── Readme.md │ ├── flat.pro │ └── flatten.py ├── Chapter07 ├── 01_case_conv │ ├── 01_case_conv.pro │ └── main.cpp ├── 02_regex_match │ ├── 02_regex_match.pro │ └── main.cpp ├── 03_regex_replace │ ├── 03_regex_replace.pro │ └── main.cpp ├── 04_format │ ├── 04_format.pro │ └── main.cpp ├── 05_string_algo │ ├── 05_string_algo.pro │ └── main.cpp ├── 06_iterator_range │ ├── 06_iterator_range.pro │ └── main.cpp ├── 07_string_view │ ├── 07_string_view.pro │ └── main.cpp └── Chapter07.pro ├── Chapter08 ├── 01_vector_of_types │ ├── 01_vector_of_types.pro │ └── main.cpp ├── 02_manipulating_vector_of_types │ ├── 02_manipulating_vector_of_types.pro │ └── main.cpp ├── 03_result_of_c++11 │ ├── 03_result_of_c++11.pro │ └── main.cpp ├── 04_higher_order_metafunctions │ ├── 04_higher_order_metafunctions.pro │ └── main.cpp ├── 05_lazy │ ├── 05_lazy.pro │ └── main.cpp ├── 06_tuple_to_string │ ├── 06_tuple_to_string.pro │ └── main.cpp ├── 07_splitting_tuple │ ├── 07_splitting_tuple.pro │ └── main.cpp ├── 08_splitting_tuple_hana │ ├── 08_splitting_tuple_hana.pro │ └── main.cpp └── Chapter08.pro ├── Chapter09 ├── 01_small_vector │ ├── 01_small_vector.pro │ └── main.cpp ├── 02_static_vector │ ├── 02_static_vector.pro │ └── main.cpp ├── 03_hash │ ├── 03_hash.pro │ └── main.cpp ├── 04_unordered │ ├── 04_unordered.pro │ └── main.cpp ├── 05_bimap │ ├── 05_bimap.pro │ └── main.cpp ├── 06_multiindex │ ├── 06_multiindex.pro │ └── main.cpp ├── 07_slist_and_pool │ ├── 07_slist_and_pool.pro │ └── main.cpp ├── 08_flat │ ├── 08_flat.pro │ └── main.cpp └── Chapter09.pro ├── Chapter10 ├── 01_predef │ ├── 01_predef.pro │ └── main.cpp ├── 02_int128 │ ├── 02_int128.pro │ └── main.cpp ├── 03_no_rtti │ ├── 03_no_rtti.pro │ └── main.cpp ├── 04_constexpr_c++11 │ ├── 04_constexpr_c++11.pro │ └── main.cpp ├── 05_noexcept_c++11 │ ├── 05_noexcept_c++11.pro │ └── main.cpp ├── 06_A_my_library │ ├── 06_A_my_library.pro │ ├── my_library.cpp │ └── my_library.hpp ├── 06_B_export_import │ ├── 06_B_export_import.pro │ └── main.cpp ├── 07_version │ ├── 07_version.pro │ └── main.cpp └── Chapter10.pro ├── Chapter11 ├── 01_listing_files │ ├── 01_listing_files.pro │ └── main.cpp ├── 02_erasing_files │ ├── 02_erasing_files.pro │ └── main.cpp ├── 03_A_plugin_hello │ ├── 03_A_plugin_hello.pro │ └── plugin_hello.cpp ├── 03_B_plugin_do_not │ ├── 03_B_plugin_do_not.pro │ └── plugin_do_not.cpp ├── 03_C_dll_usage │ ├── 03_C_dll_usage.pro │ └── main.cpp ├── 04_stacktrace │ ├── 04_stacktrace.pro │ └── main.cpp ├── 05_interprocess_basics │ ├── 05_interprocess_basics.pro │ └── main.cpp ├── 06_interprocess_queue │ ├── 06_interprocess_queue.pro │ └── main.cpp ├── 07_interprocess_pointers │ ├── 07_interprocess_pointers.pro │ └── main.cpp ├── 08_reading_files │ ├── 08_reading_files.pro │ └── main.cpp ├── 09_coroutines │ ├── 09_coroutines.pro │ └── main.cpp └── Chapter11.pro ├── Chapter12 ├── 01_graph │ ├── 01_graph.pro │ └── main.cpp ├── 02_graph_vis │ ├── 02_graph_vis.pro │ └── main.cpp ├── 03_random │ ├── 03_random.pro │ └── main.cpp ├── 04_math │ ├── 04_math.pro │ └── main.cpp ├── 05_testing │ ├── 05_testing.pro │ └── main.cpp ├── 06_testing_advanced │ ├── 06_testing_advanced.pro │ ├── developer1.cpp │ ├── developer2.cpp │ ├── foo.cpp │ ├── foo.hpp │ └── main.cpp ├── 07_gil │ ├── 07_gil.pro │ └── main.cpp └── Chapter12.pro ├── LICENSE_1_0.txt ├── Readme.md ├── config.txt └── test.py /.appveyor.yml: -------------------------------------------------------------------------------- 1 | # Use, modification, and distribution are 2 | # subject to the Boost Software License, Version 1.0. (See accompanying 3 | # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 4 | # 5 | # Copyright Antony Polukhin 2016-2019. 6 | 7 | # 8 | # See https://svn.boost.org/trac/boost/wiki/TravisCoverals for description of this file 9 | # and how it can be used with Boost libraries. 10 | # 11 | # File revision #5 + modifications 12 | 13 | init: 14 | - set BRANCH_TO_TEST=master # Change to Boost branch you wish to test with. Use %APPVEYOR_REPO_BRANCH% for current branch. 15 | 16 | ############################################################################################################### 17 | # From this point and below code is same for all the Boost libs 18 | ############################################################################################################### 19 | 20 | version: 1.87.{build}-{branch} 21 | 22 | # branches to build 23 | branches: 24 | except: 25 | - gh-pages 26 | 27 | environment: 28 | matrix: 29 | - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 30 | TOOLSET_PATH: C:\Qt\6.8\msvc2022_64\bin 31 | BOOST_FLAGS: toolset=msvc address-model=64 32 | BUILD_COMMAND: nmake /NOLOGO 33 | 34 | #- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 35 | # TOOLSET_PATH: C:\Qt\6.8\mingw_64\bin 36 | # BOOST_FLAGS: toolset=gcc --layout=system variant=release address-model=64 37 | # BUILD_COMMAND: mingw32-make -j2 38 | 39 | skip_tags: true 40 | 41 | before_build: 42 | - set PATH=%PATH%;%TOOLSET_PATH% 43 | - echo "Testing %APPVEYOR_PROJECT_NAME%" 44 | 45 | # Cloning Boost libraries (fast nondeep cloning) 46 | - set BOOST=C:/boost-local 47 | - git init %BOOST% 48 | - cd %BOOST% 49 | - git remote add --no-tags -t %BRANCH_TO_TEST% origin https://github.com/boostorg/boost.git 50 | - git fetch --depth=1 51 | - git checkout %BRANCH_TO_TEST% 52 | - git submodule update --init --merge --jobs 16 53 | - git remote set-branches --add origin %BRANCH_TO_TEST% 54 | #- git pull --recurse-submodules # Updaes submodules to most recent version. Not required 55 | 56 | - call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat" 57 | # Packages from nuget. 58 | - nuget install libpng-v142 -ExcludeVersion -NonInteractive 59 | - nuget install zlib_static -ExcludeVersion -NonInteractive 60 | 61 | build_script: 62 | # Building Boost. 63 | - bootstrap.bat 64 | - b2.exe headers 65 | - b2.exe -j4 %BOOST_FLAGS% architecture=x86 link=static --with-program_options --with-filesystem --with-system --with-test --with-atomic --with-thread --with-timer --with-date_time --with-chrono --with-regex --with-random --with-context stage 66 | - cd %APPVEYOR_BUILD_FOLDER% 67 | 68 | after_build: 69 | before_test: 70 | test_script: 71 | # Building examples. 72 | - qmake "BOOST_PATH=%BOOST%" "CONFIG+=debug" BoostBook.pro 73 | - "%BUILD_COMMAND%" 74 | - python ./test.py -v 75 | 76 | after_test: 77 | on_success: 78 | on_failure: 79 | on_finish: 80 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | 'on': 4 | schedule: 5 | - cron: '30 6 * * 1' # Every Monday at 6:30 6 | pull_request: 7 | push: 8 | branches: 9 | - second_edition 10 | 11 | env: 12 | UBSAN_OPTIONS: print_stacktrace=1 13 | ASAN_OPTIONS: detect_odr_violation=2 14 | 15 | jobs: 16 | posix: 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | include: 21 | - CXX_FLAGS: --coverage -fsanitize=address,leak,undefined 22 | LINK_FLAGS: --coverage 23 | QLIBS: -lasan -lubsan 24 | TOOLSET: gcc-12 25 | CXXTOOLSET: g++-12 26 | GCOV: --gcov-tool gcov-6 27 | os: ubuntu-24.04 28 | info: gcc-12 29 | 30 | 31 | name: '${{matrix.os}}: ${{matrix.info}}' 32 | runs-on: ${{matrix.os}} 33 | 34 | steps: 35 | - uses: actions/checkout@v4 36 | 37 | - name: Install deps 38 | run: | 39 | sudo apt update 40 | sudo apt install --allow-downgrades -y git python3-yaml gcc-12 g++-12 qt5-qmake language-pack-ru gdb libc++-dev libpng-dev 41 | 42 | - name: Install Boost 43 | run: | 44 | PROJECT_DIR=`pwd` 45 | git init $HOME/boost-local 46 | cd $HOME/boost-local 47 | git remote add --no-tags -t master origin https://github.com/boostorg/boost.git 48 | git fetch --depth=10 49 | git checkout master 50 | git submodule update --init --merge >/dev/null 51 | git status 52 | ./bootstrap.sh 53 | ./b2 headers 54 | ./b2 -j4 toolset=${{ matrix.TOOLSET }} address-model=64 architecture=x86 link=shared --with-program_options --with-filesystem --with-system --with-test --with-atomic --with-thread --with-timer --with-chrono --with-regex --with-random --with-context stage 55 | cd $PROJECT_DIR 56 | 57 | - name: Run qmake 58 | run: | 59 | QT_SELECT=qt5 qmake "QMAKE_CXX=${{ matrix.CXXTOOLSET }}" "QMAKE_LINK=${{ matrix.CXXTOOLSET }}" "QMAKE_CXXFLAGS+=${{ matrix.CXX_FLAGS }}" "QMAKE_LFLAGS+=${{ matrix.LINK_FLAGS }}" "LIBS+=${{ matrix.QLIBS }}" "BOOST_PATH=$HOME/boost-local" "CONFIG+=debug" BoostBook.pro 60 | 61 | - name: Build 62 | run: | 63 | make -j4 64 | 65 | - name: Test 66 | run: | 67 | python ./test.py -v 68 | 69 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.pro.user 2 | build-* 3 | BoostBook.pro.user.2.6pre1 4 | example_file.txt 5 | save_file.txt 6 | symlink 7 | test_file.txt 8 | dir/ 9 | -------------------------------------------------------------------------------- /BoostBook.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | RESOURCES += Readme.md LICENSE_1_0.txt 4 | 5 | SUBDIRS += \ 6 | Chapter01 \ 7 | Chapter02 \ 8 | Chapter03 \ 9 | Chapter04 \ 10 | Chapter05 \ 11 | Chapter06 \ 12 | Chapter06/flat \ 13 | Chapter07 \ 14 | Chapter08 \ 15 | Chapter09 \ 16 | Chapter10 \ 17 | Chapter11 \ 18 | Chapter12 19 | -------------------------------------------------------------------------------- /Chapter01/01_A_program_options_base/01_A_program_options_base.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | !msvc:LIBS += -lboost_program_options 6 | 7 | SOURCES += main.cpp 8 | 9 | -------------------------------------------------------------------------------- /Chapter01/01_A_program_options_base/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace opt = boost::program_options; 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | // Constructing an options describing variable and giving it a 9 | // textual description "All options". 10 | opt::options_description desc("All options"); 11 | 12 | // When we are adding options, first parameter is a name 13 | // to be used in command line. Second parameter is a type 14 | // of that option, wrapped in value<> class. Third parameter 15 | // must be a short description of that option. 16 | desc.add_options() 17 | ("apples", opt::value(), "how many apples do you have") 18 | ("oranges", opt::value(), "how many oranges do you have") 19 | ("help", "produce help message") 20 | ; 21 | 22 | // Variable to store our command line arguments. 23 | opt::variables_map vm; 24 | 25 | // Parsing and storing arguments. 26 | opt::store(opt::parse_command_line(argc, argv, desc), vm); 27 | 28 | // Must be called after all the parsing and storing. 29 | opt::notify(vm); 30 | 31 | if (vm.count("help")) { 32 | std::cout << desc << "\n"; 33 | return 1; 34 | } 35 | 36 | std::cout << "Fruits count: " 37 | << vm["apples"].as() + vm["oranges"].as() 38 | << std::endl; 39 | 40 | } // end of `main` 41 | 42 | -------------------------------------------------------------------------------- /Chapter01/01_B_program_options_short/01_B_program_options_short.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | !msvc:LIBS += -lboost_program_options 6 | 7 | SOURCES += main.cpp 8 | 9 | include(apples_oranges.cfg) 10 | 11 | -------------------------------------------------------------------------------- /Chapter01/01_B_program_options_short/apples_oranges.cfg: -------------------------------------------------------------------------------- 1 | # This is a comment in config file example 2 | 3 | oranges=20 4 | #apples=10 5 | #name=Reader 6 | -------------------------------------------------------------------------------- /Chapter01/01_B_program_options_short/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | namespace opt = boost::program_options; 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | opt::options_description desc("All options"); 9 | 10 | int oranges_var = 0; 11 | desc.add_options() 12 | // ProgramOptions stores the option value into 13 | // the variable that is passed by pointer. Here value of 14 | // "--oranges" option will be stored into 'oranges_var'. 15 | ("oranges,o", opt::value(&oranges_var)->required(), 16 | "oranges that you have") 17 | 18 | // 'name' option is not marked with 'required()', 19 | // so user may not provide it. 20 | ("name", opt::value(), "your name") 21 | ("help", "produce help message") 22 | 23 | // 'a' is a short option name for apples. Use as '-a 10'. 24 | // If no value provided, then the default value is used. 25 | ("apples,a", opt::value()->default_value(10), 26 | "apples that you have") 27 | ; 28 | 29 | opt::variables_map vm; 30 | 31 | // Parsing command line options and storing values to 'vm' 32 | opt::store(opt::parse_command_line(argc, argv, desc), vm); 33 | 34 | // We can also parse environment variables. Just use 35 | // 'opt::store with' 'opt::parse_environment' function. 36 | 37 | if (vm.count("help")) { 38 | std::cout << desc << "\n"; 39 | return 1; 40 | } 41 | 42 | // Adding missing options from "apples_oranges.cfg" config file. 43 | try { 44 | opt::store( 45 | opt::parse_config_file("apples_oranges.cfg", desc), 46 | vm 47 | ); 48 | } catch (const opt::reading_file& e) { 49 | std::cout << "Error: " << e.what() << std::endl; 50 | } 51 | 52 | try { 53 | // `opt::required_option` exception is thrown if 54 | // one of the required options was not set. 55 | opt::notify(vm); 56 | 57 | } catch (const opt::required_option& e) { 58 | std::cout << "Error: " << e.what() << std::endl; 59 | return 2; 60 | } 61 | 62 | if (vm.count("name")) { 63 | std::cout << "Hi," << vm["name"].as() << "!\n"; 64 | } 65 | std::cout << "Fruits count: " 66 | << vm["apples"].as() + vm["oranges"].as() 67 | << std::endl; 68 | } 69 | -------------------------------------------------------------------------------- /Chapter01/02_any/02_any.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter01/02_any/main.cpp: -------------------------------------------------------------------------------- 1 | //#include 2 | //#include 3 | //#include 4 | //#include 5 | 6 | //int main() 7 | //{ 8 | 9 | // typedef std::auto_ptr object_ptr; 10 | // std::vector some_values; 11 | // some_values.push_back(new Object(10)); 12 | // some_values.push_back(new Object("Hello there")); 13 | // some_values.push_back(new Object(std::string("Wow!"))); 14 | 15 | // std::string* p = dynamic_cast(some_values.back().get()); 16 | // assert(p); 17 | // (*p) += " That is great!\n"; 18 | // std::cout << *p; 19 | 20 | // return 0; 21 | //} 22 | 23 | void example(); 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | int main() { 31 | std::vector some_values; 32 | some_values.push_back(10); 33 | const char* c_str = "Hello there!"; 34 | some_values.push_back(c_str); 35 | some_values.push_back(std::string("Wow!")); 36 | 37 | std::string& s = boost::any_cast(some_values.back()); 38 | s += " That is great!\n"; 39 | std::cout << s; 40 | 41 | example(); 42 | } 43 | 44 | void example() { 45 | boost::any variable(std::string("Hello world!")); 46 | 47 | // Following method may throw a boost::bad_any_cast exception 48 | // if actual value in variable is not a std::string. 49 | std::string s1 = boost::any_cast(variable); 50 | 51 | // Never throws. If actual value in variable is not a std::string 52 | // will return an NULL pointer. 53 | std::string* s2 = boost::any_cast(&variable); 54 | 55 | 56 | (void)s2; // Supressing warnings about unused variable 57 | (void)s1; 58 | } 59 | -------------------------------------------------------------------------------- /Chapter01/03_variant/03_variant.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter01/03_variant/main.cpp: -------------------------------------------------------------------------------- 1 | void example1(); 2 | void example2(); 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | typedef boost::variant my_var_t; 11 | std::vector some_values; 12 | some_values.push_back(10); 13 | some_values.push_back("Hello there!"); 14 | some_values.push_back(std::string("Wow!")); 15 | 16 | std::string& s = boost::get(some_values.back()); 17 | s += " That is great!\n"; 18 | std::cout << s; 19 | 20 | example1(); 21 | example2(); 22 | } 23 | 24 | 25 | 26 | void example1() { 27 | // Default constructor constructs an instance of boost::blank. 28 | boost::variant< 29 | boost::blank, int, const char*, std::string 30 | > var; 31 | 32 | // 'which()' method returns an index of a type 33 | // currently held by variant. 34 | assert(var.which() == 0); // boost::blank 35 | 36 | var = "Hello, dear reader"; 37 | assert(var.which() != 0); 38 | } 39 | 40 | 41 | 42 | void example2() { 43 | boost::variant variable(0); 44 | 45 | // Following method may throw a boost::bad_get 46 | // exception if actual value in variable is not an int. 47 | int s1 = boost::get(variable); 48 | 49 | // If actual value in variable is not an int will return NULL. 50 | int* s2 = boost::get(&variable); 51 | 52 | 53 | assert(s1 == 0); 54 | assert(s2); 55 | assert(*s2 == 0); 56 | } 57 | -------------------------------------------------------------------------------- /Chapter01/04_A_any_db_example/04_A_any_db_example.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter01/04_A_any_db_example/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | // This typedefs and methods will be in our header, 9 | // that wraps around native SQL interface. 10 | typedef boost::any cell_t; 11 | typedef std::vector db_row_t; 12 | 13 | // This is just an example, no actual work with database. 14 | db_row_t get_row(const char* /*query*/) { 15 | // In real application 'query' parameter shall have a 'const 16 | // char*' or 'const std::string&' type? See recipe "Type 17 | // 'reference to string'" for an answer. 18 | db_row_t row; 19 | row.push_back(10); 20 | row.push_back(10.1f); 21 | row.push_back(std::string("hello again")); 22 | return row; 23 | } 24 | 25 | // This is how a user will use your classes. 26 | struct db_sum { 27 | private: 28 | double& sum_; 29 | 30 | public: 31 | explicit db_sum(double& sum) 32 | : sum_(sum) 33 | {} 34 | 35 | void operator()(const cell_t& value) { 36 | const std::type_info& ti = value.type(); 37 | if (ti == typeid(int)) { 38 | sum_ += boost::any_cast(value); 39 | } else if (ti == typeid(float)) { 40 | sum_ += boost::any_cast(value); 41 | } 42 | } 43 | }; 44 | 45 | int main() { 46 | db_row_t row = get_row("Query: Give me some row, please."); 47 | double res = 0.0; 48 | std::for_each(row.begin(), row.end(), db_sum(res)); 49 | std::cout << "Sum of arithmetic types in database row is: " << res << std::endl; 50 | } 51 | -------------------------------------------------------------------------------- /Chapter01/04_B_variant_db_example/04_B_variant_db_example.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter01/04_B_variant_db_example/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // This typedefs and methods will be in header, 7 | // that wraps around native SQL interface. 8 | typedef boost::variant cell_t; 9 | typedef std::vector db_row_t; 10 | 11 | // This is just an example, no actual work with database. 12 | db_row_t get_row(const char* /*query*/) { 13 | // See recipe "Type 'reference to string'" 14 | // for a better type for 'query' parameter. 15 | db_row_t row; 16 | row.push_back(10); 17 | row.push_back(10.1f); 18 | row.push_back("hello again"); 19 | return row; 20 | } 21 | 22 | // This is how code required to sum values 23 | // We can provide no template parameter 24 | // to boost::static_visitor<> if our visitor returns nothing. 25 | struct db_sum_visitor: public boost::static_visitor { 26 | double operator()(int value) const { 27 | return value; 28 | } 29 | double operator()(float value) const { 30 | return value; 31 | } 32 | double operator()(const std::string& /*value*/) const { 33 | return 0.0; 34 | } 35 | }; 36 | 37 | int main() { 38 | db_row_t row = get_row("Query: Give me some row, please."); 39 | double res = 0.0; 40 | for (db_row_t::const_iterator it = row.begin(), end = row.end(); it != end; ++it) { 41 | res += boost::apply_visitor(db_sum_visitor(), *it); 42 | } 43 | 44 | std::cout << "Sum of arithmetic types in database row is: " 45 | << res << std::endl; 46 | } 47 | -------------------------------------------------------------------------------- /Chapter01/05_optional/05_optional.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter01/05_optional/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class locked_device { 5 | explicit locked_device(const char* /*param*/) { 6 | // We have unique access to device. 7 | std::cout << "Device is locked\n"; 8 | } 9 | 10 | static bool try_lock_device_impl(); 11 | public: 12 | void use() { 13 | std::cout << "Success!\n"; 14 | } 15 | 16 | static boost::optional try_lock_device() { 17 | if (!try_lock_device_impl()) { 18 | // Failed to lock device. 19 | return boost::none; 20 | } 21 | 22 | // Success! 23 | return locked_device("device name"); 24 | } 25 | 26 | ~locked_device(); // Releases device lock. 27 | }; 28 | 29 | int main() { 30 | for (unsigned i = 0; i < 10; ++i) { 31 | boost::optional t 32 | = locked_device::try_lock_device(); 33 | // optional is convertible to bool 34 | if (t) { 35 | t->use(); 36 | return 0; 37 | } else { 38 | std::cout << "...trying again\n"; 39 | } 40 | } 41 | 42 | std::cout << "Failure!\n"; 43 | return -1; 44 | } 45 | 46 | // details: 47 | 48 | locked_device::~locked_device(){} 49 | 50 | bool locked_device::try_lock_device_impl() { 51 | static int i = 0; 52 | ++i; 53 | return i == 3; 54 | } 55 | -------------------------------------------------------------------------------- /Chapter01/06_array/06_array.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | 8 | -------------------------------------------------------------------------------- /Chapter01/06_array/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef boost::array array4_t; 5 | 6 | array4_t& vector_advance(array4_t& val) { 7 | // C++11 lambda function 8 | const auto inc = [](char& c){ ++c; }; 9 | 10 | // boost::array has begin(), cbegin(), end(), cend(), 11 | // rbegin(), size(), empty() and other functions that are 12 | // common for STL containers. 13 | std::for_each(val.begin(), val.end(), inc); 14 | return val; 15 | } 16 | 17 | int main() { 18 | // We can initialize boost::array just like an array in C++11: 19 | // array4_t val = {0, 1, 2, 3}; 20 | // but in C++03 additional pair of curly brackets is required. 21 | array4_t val = {{0, 1, 2, 3}}; 22 | 23 | array4_t val_res; // it is default constructible 24 | val_res = vector_advance(val); // it is assignable 25 | 26 | assert(val.size() == 4); 27 | assert(val[0] == 1); 28 | /*val[4];*/ // Will trigger an assert because max index is 3 29 | 30 | // We can make this assert work at compile-time. 31 | // Interested? See recipe 'Check sizes at compile-time' 32 | assert(sizeof(val) == sizeof(char) * array4_t::static_size); 33 | } 34 | -------------------------------------------------------------------------------- /Chapter01/07_A_tuple/07_A_tuple.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter01/07_A_tuple/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | boost::tuple almost_a_pair(10, "Hello"); 5 | boost::tuple quad(10, 1.0f, 10.0, 1); 6 | 7 | 8 | 9 | #include 10 | 11 | void sample1() { 12 | const int i = boost::get<0>(almost_a_pair); 13 | const std::string& str = boost::get<1>(almost_a_pair); 14 | const double d = boost::get<2>(quad); 15 | 16 | (void) i; 17 | (void) str; 18 | (void) d; 19 | } 20 | 21 | 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | void sample2() { 29 | // Tuple comparison operators are 30 | // defined in header "boost/tuple/tuple_comparison.hpp" 31 | // Don't forget to include it! 32 | std::set > s; 33 | s.insert(boost::make_tuple(1, 1.0, 2)); 34 | s.insert(boost::make_tuple(2, 10.0, 2)); 35 | s.insert(boost::make_tuple(3, 100.0, 2)); 36 | 37 | #ifndef BOOST_NO_CXX11_AUTO_DECLARATIONS 38 | // Requires C++11 39 | const auto t = boost::make_tuple(0, -1.0, 2); 40 | assert(2 == boost::get<2>(t)); 41 | // We can make a compile time assert for type 42 | // of t. Interested? See chapter 'Compile time tricks' 43 | #endif 44 | } 45 | 46 | 47 | #include 48 | #include 49 | 50 | void sample3() { 51 | boost::tuple quad(10, 1.0f, 10.0, 1); 52 | int i; 53 | float f; 54 | double d; 55 | int i2; 56 | 57 | // Passing values from 'quad' variables 58 | // to variables 'i', 'f', 'd', 'i2'. 59 | boost::tie(i, f, d, i2) = quad; 60 | 61 | assert(i == 10); 62 | assert(i2 == 1); 63 | } 64 | 65 | struct id_name_pair { 66 | int id; 67 | std::string name; 68 | }; 69 | 70 | int main () { 71 | sample1(); 72 | sample2(); 73 | sample3(); 74 | } 75 | -------------------------------------------------------------------------------- /Chapter01/07_B_tuple_construction_order/07_B_tuple_construction_order.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter01/07_B_tuple_construction_order/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | struct printer { 6 | printer() { std::cout << I; } 7 | }; 8 | 9 | int main() { 10 | // Outputs 012 11 | boost::tuple, printer<1>, printer<2> > t; 12 | (void)t; 13 | } 14 | -------------------------------------------------------------------------------- /Chapter01/08_bind/08_bind.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | 8 | -------------------------------------------------------------------------------- /Chapter01/09_type_index/09_type_index.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | 8 | -------------------------------------------------------------------------------- /Chapter01/09_type_index/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | void do_something(const T& x) { 6 | std::cout << "T is " << typeid(T).name() << std::endl; 7 | 8 | (void)x; 9 | } 10 | 11 | 12 | void sample1() { 13 | auto&& x = 42; 14 | std::cout << "x is " 15 | << typeid(decltype(x)).name() 16 | << std::endl; 17 | 18 | (void)x; 19 | } 20 | 21 | #include 22 | #include 23 | 24 | template 25 | void do_something_again(const T& x) { 26 | std::cout << "T is " << boost::typeindex::type_id() << std::endl; 27 | 28 | (void)x; 29 | } 30 | 31 | 32 | 33 | #include 34 | 35 | void sample2() { 36 | auto&& x = 42; 37 | std::cout << "x is " 38 | << boost::typeindex::type_id_with_cvr() 39 | << std::endl; 40 | 41 | (void)x; 42 | } 43 | 44 | 45 | int main () { 46 | do_something(1.0); 47 | sample1(); 48 | do_something_again(1.0); 49 | sample2(); 50 | } 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Chapter01/10_A_move/10_A_move.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter01/10_A_move/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | 9 | namespace other { 10 | class characteristics{}; 11 | } 12 | 13 | struct person_info { 14 | std::string name_; 15 | std::string second_name_; 16 | other::characteristics characteristic_; 17 | 18 | // Fields declared here 19 | // ... 20 | private: 21 | BOOST_COPYABLE_AND_MOVABLE(person_info) 22 | public: 23 | // For the simplicity of example we will assume that 24 | // person_info default constructor and swap are very 25 | // fast/cheap to call. 26 | person_info(); 27 | 28 | person_info(const person_info& p) 29 | : name_(p.name_) 30 | , second_name_(p.second_name_) 31 | , characteristic_(p.characteristic_) 32 | {} 33 | 34 | person_info(BOOST_RV_REF(person_info) person) { 35 | swap(person); 36 | } 37 | 38 | person_info& operator=(BOOST_COPY_ASSIGN_REF(person_info) person) { 39 | person_info tmp(person); 40 | swap(tmp); 41 | return *this; 42 | } 43 | 44 | person_info& operator=(BOOST_RV_REF(person_info) person) { 45 | person_info tmp(boost::move(person)); 46 | swap(tmp); 47 | return *this; 48 | } 49 | 50 | void swap(person_info& rhs); 51 | }; 52 | 53 | 54 | #include 55 | 56 | void person_info::swap(person_info& rhs) { 57 | name_.swap(rhs.name_); 58 | second_name_.swap(rhs.second_name_); 59 | boost::swap(characteristic_, rhs.characteristic_); 60 | } 61 | 62 | 63 | 64 | int main() { 65 | person_info vasya; 66 | vasya.name_ = "Vasya"; 67 | vasya.second_name_ = "Snow"; 68 | 69 | person_info new_vasya(boost::move(vasya)); 70 | assert(new_vasya.name_ == "Vasya"); 71 | assert(new_vasya.second_name_ == "Snow"); 72 | assert(vasya.name_.empty()); 73 | assert(vasya.second_name_.empty()); 74 | 75 | vasya = boost::move(new_vasya); 76 | assert(vasya.name_ == "Vasya"); 77 | assert(vasya.second_name_ == "Snow"); 78 | assert(new_vasya.name_.empty()); 79 | assert(new_vasya.second_name_.empty()); 80 | 81 | new_vasya = vasya; 82 | assert(vasya.name_ == "Vasya"); 83 | assert(vasya.second_name_ == "Snow"); 84 | assert(new_vasya.name_ == "Vasya"); 85 | assert(new_vasya.second_name_ == "Snow"); 86 | } 87 | 88 | 89 | // details: 90 | 91 | BOOST_DEFAULTED_FUNCTION(person_info::person_info(), {}) 92 | 93 | -------------------------------------------------------------------------------- /Chapter01/10_B_move_c++11/10_B_move_c++11.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += ../10_A_move/main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | 8 | -------------------------------------------------------------------------------- /Chapter01/11_noncopyable/11_noncopyable.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter01/11_noncopyable/main.cpp: -------------------------------------------------------------------------------- 1 | class descriptor_owner { 2 | void* descriptor_; 3 | 4 | public: 5 | explicit descriptor_owner(const char* params); 6 | 7 | ~descriptor_owner() { 8 | // system_api_free_descriptor(descriptor_); 9 | } 10 | }; 11 | 12 | descriptor_owner::descriptor_owner(const char* ){} 13 | 14 | 15 | void i_am_bad() { 16 | descriptor_owner d1("O_o"); 17 | descriptor_owner d2("^_^"); 18 | 19 | // Descriptor of d2 was not correctly freed 20 | d2 = d1; 21 | 22 | // destructor of d2 will free the descriptor 23 | // destructor of d1 will try to free already freed descriptor 24 | } 25 | 26 | #include 27 | 28 | class descriptor_owner_fixed : private boost::noncopyable { 29 | // ... 30 | public: 31 | descriptor_owner_fixed(const char* params){ (void)params; } 32 | }; 33 | 34 | void i_am_good() { 35 | descriptor_owner_fixed d1("O_o"); 36 | descriptor_owner_fixed d2("^_^"); 37 | 38 | // Won't compile 39 | //d2 = d1; 40 | //descriptor_owner_fixed d3(d1); 41 | } 42 | 43 | 44 | int main() { 45 | i_am_bad(); 46 | i_am_good(); 47 | } 48 | 49 | -------------------------------------------------------------------------------- /Chapter01/12_A_noncopyable_movable/12_A_noncopyable_movable.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP03FLAG 7 | -------------------------------------------------------------------------------- /Chapter01/12_B_noncopyable_movable_c++11/12_B_noncopyable_movable_c++11.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += ../12_A_noncopyable_movable/main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | 8 | -------------------------------------------------------------------------------- /Chapter01/13_algorithm/13_algorithm.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter01/13_algorithm/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | boost::array chars_65_125_pre11() { 4 | boost::array res; 5 | 6 | const unsigned char offset = 65; 7 | for (std::size_t i = 0; i < res.size(); ++i) { 8 | res[i] = i + offset; 9 | } 10 | 11 | return res; 12 | } 13 | 14 | 15 | #include 16 | #include 17 | 18 | boost::array chars_65_125() { 19 | boost::array res; 20 | boost::algorithm::iota(res.begin(), res.end(), 65); 21 | return res; 22 | } 23 | 24 | #include 25 | #include 26 | #include 27 | 28 | void to_hex_test1() { 29 | const std::string data = "Hello word"; 30 | boost::algorithm::hex( 31 | data.begin(), data.end(), 32 | std::ostream_iterator(std::cout) 33 | ); 34 | 35 | std::cout << '\n'; 36 | } 37 | 38 | void to_hex_test2() { 39 | const std::string data = "Hello word"; 40 | boost::algorithm::hex( 41 | data, 42 | std::ostream_iterator(std::cout) 43 | ); 44 | 45 | std::cout << '\n'; 46 | } 47 | 48 | #include 49 | int main() { 50 | assert(chars_65_125_pre11() == chars_65_125()); 51 | to_hex_test1(); 52 | to_hex_test2(); 53 | } 54 | -------------------------------------------------------------------------------- /Chapter01/Chapter01.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | 01_A_program_options_base \ 5 | 01_B_program_options_short \ 6 | 02_any \ 7 | 03_variant \ 8 | 04_A_any_db_example \ 9 | 04_B_variant_db_example \ 10 | 05_optional \ 11 | 06_array \ 12 | 07_A_tuple \ 13 | 07_B_tuple_construction_order \ 14 | 08_bind \ 15 | 09_type_index \ 16 | 10_A_move \ 17 | 10_B_move_c++11 \ 18 | 11_noncopyable \ 19 | 12_A_noncopyable_movable \ 20 | 12_B_noncopyable_movable_c++11 \ 21 | 13_algorithm 22 | 23 | -------------------------------------------------------------------------------- /Chapter02/01_scoped_ptr/01_scoped_ptr.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter02/02_shared_ptr/02_shared_ptr.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | !msvc:LIBS += -lboost_thread -lboost_system -lboost_chrono 7 | -------------------------------------------------------------------------------- /Chapter02/03_scoped_array/03_scoped_array.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter02/03_scoped_array/main.cpp: -------------------------------------------------------------------------------- 1 | void may_throw1(char ch); 2 | void may_throw2(const char* buffer); 3 | 4 | void foo() { 5 | // we cannot allocate 10MB of memory on stack, 6 | // so we allocate it on heap 7 | char* buffer = new char[1024 * 1024 * 10]; 8 | 9 | // Oops. Here comes some code, that may throw. 10 | // It was a bad idea to use raw pointer as the memory may leak!! 11 | may_throw1(buffer[0]); 12 | may_throw2(buffer); 13 | 14 | delete[] buffer; 15 | } 16 | 17 | 18 | #include 19 | 20 | void foo_fixed() { 21 | // We allocate array on heap 22 | boost::scoped_array buffer(new char[1024 * 1024 * 10]); 23 | 24 | // Here comes some code, that may throw, 25 | // but now exception won't cause a memory leak 26 | may_throw1(buffer[0]); 27 | may_throw2(buffer.get()); 28 | 29 | // destructor of 'buffer' variable will call delete[] 30 | } 31 | 32 | #include 33 | 34 | void foo_fixed2() { 35 | // We allocate array on heap 36 | const boost::movelib::unique_ptr buffer 37 | = boost::movelib::make_unique(1024 * 1024 * 10); 38 | 39 | // Here comes some code, that may throw, 40 | // but now exception won't cause a memory leak 41 | may_throw1(buffer[0]); 42 | may_throw2(buffer.get()); 43 | 44 | // destructor of 'buffer' variable will call delete[] 45 | } 46 | 47 | #include 48 | #include 49 | 50 | int main() { 51 | // foo(); // Leaks memory 52 | try { foo_fixed(); assert(false); } catch (...) {} 53 | try { foo_fixed2(); assert(false); } catch (...) {} 54 | } 55 | 56 | 57 | void may_throw1(char /*ch*/) { 58 | // Do nothing 59 | } 60 | 61 | void may_throw2(const char* /*buffer*/) { 62 | throw std::exception(); 63 | } 64 | -------------------------------------------------------------------------------- /Chapter02/04_shared_array/04_shared_array.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | !msvc:LIBS += -lboost_thread -lboost_system -lboost_chrono 7 | -------------------------------------------------------------------------------- /Chapter02/05_function_fobject/05_function_fobject.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter02/05_function_fobject/main.cpp: -------------------------------------------------------------------------------- 1 | // making a typedef for function pointer accepting int 2 | // and returning nothing 3 | typedef void (*func_t)(int); 4 | 5 | // Function that accepts pointer to function and 6 | // calls accepted function for each integer that it has. 7 | // It cannot work with functional objects :( 8 | void process_integers(func_t f); 9 | 10 | // Functional object 11 | class int_processor { 12 | const int min_; 13 | const int max_; 14 | bool& triggered_; 15 | 16 | public: 17 | int_processor(int min, int max, bool& triggered) 18 | : min_(min) 19 | , max_(max) 20 | , triggered_(triggered) 21 | {} 22 | 23 | void operator()(int i) const { 24 | if (i < min_ || i > max_) { 25 | triggered_ = true; 26 | } 27 | } 28 | }; 29 | 30 | #include 31 | typedef boost::function fobject_t; 32 | 33 | // Now this function may accept functional objects 34 | void process_integers(const fobject_t& f); 35 | 36 | int main() { 37 | bool is_triggered = false; 38 | int_processor fo(0, 200, is_triggered); 39 | process_integers(fo); 40 | assert(is_triggered); 41 | } 42 | 43 | bool g_is_triggered = false; 44 | void set_functional_object(fobject_t& f) { 45 | // Local variable 46 | int_processor fo( 100, 200, g_is_triggered); 47 | 48 | f = fo; 49 | // now 'f' holds a copy of 'fo' 50 | 51 | // 'fo' leavs scope and will be destroyed, 52 | // but it's OK to use 'f' in outer scope. 53 | } 54 | 55 | 56 | void foo(const fobject_t& f) { 57 | // boost::function is convertible to bool 58 | if (f) { 59 | // we have value in 'f' 60 | // ... 61 | } else { 62 | // 'f' is empty 63 | // ... 64 | } 65 | } 66 | 67 | void process_integers(const fobject_t& f) { 68 | static const int data[] = {1, 2, 3, 4, 5, 250}; 69 | std::for_each(data, data + sizeof(data) / sizeof(int), f); 70 | } 71 | 72 | 73 | // Making sure that `set_functional_object` works as expected 74 | struct more_tests_runner { 75 | more_tests_runner() { 76 | fobject_t out; 77 | assert(!out); 78 | set_functional_object(out); 79 | assert(out); 80 | 81 | foo(out); 82 | } 83 | }; 84 | more_tests_runner more_tests; 85 | -------------------------------------------------------------------------------- /Chapter02/06_function_fpointer/06_function_fpointer.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter02/06_function_fpointer/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | typedef boost::function fobject_t; 3 | 4 | // Now this function may accept functional objects 5 | void process_integers(const fobject_t& f); 6 | 7 | 8 | void my_ints_function(int i); 9 | 10 | int main() { 11 | process_integers(&my_ints_function); 12 | } 13 | 14 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES 15 | #include 16 | int something(std::string&&){ return 0; } 17 | #endif 18 | 19 | 20 | #include 21 | void my_ints_function(int i) { assert(i == 10); } 22 | void process_integers(const fobject_t& fun) { 23 | fun(10); 24 | 25 | #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES 26 | boost::function f = &something; 27 | f(std::string("Hello")); // Works 28 | #endif 29 | } 30 | -------------------------------------------------------------------------------- /Chapter02/07_function_lambda_c++11/07_function_lambda_c++11.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter02/07_function_lambda_c++11/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | typedef boost::function fobject_t; 3 | 4 | // Now this function may accept functional objects 5 | void process_integers(const fobject_t& f); 6 | 7 | 8 | 9 | #include 10 | #include 11 | //#include 12 | 13 | void sample() { 14 | // lambda function with no parameters that does nothing 15 | process_integers([](int /*i*/){}); 16 | 17 | // lambda function that stores a reference 18 | std::deque ints; 19 | process_integers([&ints](int i){ 20 | ints.push_back(i); 21 | }); 22 | 23 | // lambda function that modifies its content 24 | std::size_t match_count = 0; 25 | process_integers([ints, &match_count](int i) mutable { 26 | if (ints.front() == i) { 27 | ++ match_count; 28 | } 29 | ints.pop_front(); 30 | }); 31 | 32 | assert(match_count == 6); 33 | } 34 | 35 | 36 | 37 | int main() { 38 | sample(); 39 | 40 | std::deque v = {10, 20, 30, 40, 50}; 41 | 42 | std::for_each(v.begin(), v.end(), [](int& v) { v += 10; }); 43 | 44 | const boost::function f0( 45 | [](int& v) { v += 10; } 46 | ); 47 | std::for_each(v.begin(), v.end(), f0); 48 | 49 | const auto f1 = [](int& v) { v += 10; }; 50 | std::for_each(v.begin(), v.end(), f1); 51 | } 52 | 53 | void process_integers(const fobject_t& f) { 54 | static const int data[] = {1, 2, 3, 4, 5, 200}; 55 | // We'll be using only 6 elements in this example 56 | std::for_each(data, data + 6, f); 57 | } 58 | -------------------------------------------------------------------------------- /Chapter02/08_ptr_container_c++11/08_ptr_container_c++11.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter02/08_ptr_container_c++11/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | template 6 | struct ptr_cmp { 7 | template 8 | bool operator()(const T1& v1, const T1& v2) const { 9 | return operator ()(*v1, *v2); 10 | } 11 | 12 | bool operator()(const T& v1, const T& v2) const { 13 | return std::less()(v1, v2); 14 | } 15 | }; 16 | 17 | void example1() { 18 | std::set > s; 19 | s.insert(new int(1)); 20 | s.insert(new int(0)); 21 | 22 | // ... 23 | assert(**s.begin() == 0); 24 | // ... 25 | 26 | // Oops! Any exception in the above code leads to 27 | // memory leak. 28 | 29 | // Deallocating resources. 30 | std::for_each(s.begin(), s.end(), [](int* p) { delete p; }); 31 | } 32 | 33 | 34 | 35 | #include 36 | #include 37 | 38 | void example2_cpp11() { 39 | typedef std::unique_ptr int_uptr_t; 40 | std::set > s; 41 | s.insert(int_uptr_t(new int(1))); 42 | s.insert(int_uptr_t(new int(0))); 43 | 44 | // ... 45 | assert(**s.begin() == 0); 46 | // ... 47 | 48 | // Resources will be deallocated by unique_ptr<>. 49 | } 50 | 51 | 52 | 53 | #include 54 | #include 55 | 56 | void example3() { 57 | typedef boost::shared_ptr int_sptr_t; 58 | std::set > s; 59 | s.insert(boost::make_shared(1)); 60 | s.insert(boost::make_shared(0)); 61 | 62 | // ... 63 | assert(**s.begin() == 0); 64 | // ... 65 | 66 | // Resources will be deallocated by shared_ptr<>. 67 | } 68 | 69 | 70 | 71 | #include 72 | 73 | void correct_impl() { 74 | boost::ptr_set s; 75 | s.insert(new int(1)); 76 | s.insert(new int(0)); 77 | 78 | // ... 79 | assert(*s.begin() == 0); 80 | // ... 81 | 82 | // Resources will be deallocated by container itself. 83 | } 84 | 85 | 86 | 87 | #include 88 | #include 89 | #include 90 | 91 | void theres_more_example() { 92 | // Creating vector of 10 elements with values 100 93 | boost::ptr_vector v; 94 | int value = 100; 95 | v.resize(10, &value); // Beware! No ownership of pointer! 96 | 97 | assert(v.size() == 10); 98 | assert(v.back() == 100); 99 | } 100 | 101 | 102 | 103 | #include 104 | #include 105 | #include 106 | 107 | void example2_cpp03() { 108 | typedef boost::movelib::unique_ptr int_uptr_t; 109 | boost::container::set > s; 110 | s.insert(boost::movelib::make_unique(1)); 111 | s.insert(boost::movelib::make_unique(0)); 112 | // ... 113 | assert(**s.begin() == 0); 114 | } 115 | 116 | 117 | 118 | int main() { 119 | example1(); 120 | example2_cpp11(); 121 | example3(); 122 | correct_impl(); 123 | theres_more_example(); 124 | example2_cpp03(); 125 | } 126 | -------------------------------------------------------------------------------- /Chapter02/09_scope_exit/09_scope_exit.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter02/09_scope_exit/main.cpp: -------------------------------------------------------------------------------- 1 | void unique_ptr_example(); 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | std::FILE* f = std::fopen("example_file.txt", "w"); 10 | assert(f); 11 | 12 | BOOST_SCOPE_EXIT(f) { 13 | // Whatever happened in outer scope, this code will be executed 14 | // and file will be correctly closed. 15 | std::fclose(f); 16 | } BOOST_SCOPE_EXIT_END 17 | 18 | // Some code that may throw or return. 19 | // ... 20 | 21 | unique_ptr_example(); 22 | } 23 | 24 | class theres_more_example { 25 | public: 26 | void close(std::FILE*); 27 | 28 | void func() { 29 | std::FILE* f = 0; 30 | BOOST_SCOPE_EXIT(f, this_) { // Capturing `this` as 'this_' 31 | this_->close(f); 32 | } BOOST_SCOPE_EXIT_END 33 | } 34 | }; 35 | 36 | 37 | #include 38 | #include 39 | 40 | void unique_ptr_example() { 41 | boost::movelib::unique_ptr f( 42 | std::fopen("example_file.txt", "w"), // open file 43 | &std::fclose // specific deleter 44 | ); 45 | // ... 46 | 47 | 48 | 49 | theres_more_example tme; 50 | tme.func(); 51 | } 52 | 53 | #include 54 | void theres_more_example::close(std::FILE* f) { assert(!f); } 55 | 56 | -------------------------------------------------------------------------------- /Chapter02/10_base_from_member/10_base_from_member.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter02/10_base_from_member/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class tasks_processor: boost::noncopyable { 5 | std::ostream& log_; 6 | 7 | protected: 8 | virtual void do_process() = 0; 9 | 10 | public: 11 | explicit tasks_processor(std::ostream& log) 12 | : log_(log) 13 | {} 14 | 15 | void process() { 16 | log_ << "Starting data processing"; 17 | do_process(); 18 | } 19 | }; 20 | 21 | class fake_tasks_processor: public tasks_processor { 22 | std::ostringstream logger_; 23 | 24 | virtual void do_process() { 25 | logger_ << "Fake processor processed!"; 26 | } 27 | 28 | public: 29 | fake_tasks_processor() 30 | : tasks_processor(logger_) // Oops! logger_ does not exist here 31 | , logger_() 32 | {} 33 | 34 | #ifdef NEWER_DEFINED1 35 | fake_tasks_processor() 36 | : logger_() // Oops! It is still constructed AFTER tasks_processor. 37 | , tasks_processor(logger_) 38 | {} 39 | #endif 40 | 41 | }; 42 | 43 | #include 44 | 45 | class fake_tasks_processor_fixed 46 | : boost::base_from_member 47 | , public tasks_processor 48 | { 49 | typedef boost::base_from_member logger_t; 50 | 51 | virtual void do_process() { 52 | logger_t::member << "Fake processor processed!"; 53 | } 54 | 55 | public: 56 | fake_tasks_processor_fixed() 57 | : logger_t() 58 | , tasks_processor(logger_t::member) 59 | {} 60 | }; 61 | 62 | class fake_tasks_processor2 63 | : boost::base_from_member 64 | , boost::base_from_member 65 | , public tasks_processor 66 | { 67 | 68 | typedef boost::base_from_member logger0_t; 69 | typedef boost::base_from_member logger1_t; 70 | 71 | virtual void do_process() { 72 | logger0_t::member << "0: Fake processor2 processed!"; 73 | logger1_t::member << "1: Fake processor2 processed!"; 74 | } 75 | 76 | public: 77 | fake_tasks_processor2() 78 | : logger0_t() 79 | , logger1_t() 80 | , tasks_processor(logger0_t::member) 81 | {} 82 | }; 83 | 84 | 85 | int main() { 86 | fake_tasks_processor_fixed tp; 87 | tp.process(); 88 | 89 | fake_tasks_processor2 tp2; 90 | tp2.process(); 91 | } 92 | -------------------------------------------------------------------------------- /Chapter02/Chapter02.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | 01_scoped_ptr \ 5 | 02_shared_ptr \ 6 | 03_scoped_array \ 7 | 04_shared_array \ 8 | 05_function_fobject \ 9 | 06_function_fpointer \ 10 | 07_function_lambda_c++11 \ 11 | 08_ptr_container_c++11 \ 12 | 09_scope_exit \ 13 | 10_base_from_member 14 | -------------------------------------------------------------------------------- /Chapter03/01_lexical_to_number/01_lexical_to_number.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter03/01_lexical_to_number/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void sample1() { 4 | std::istringstream iss("100"); 5 | int i; 6 | iss >> i; 7 | 8 | // ... 9 | } 10 | 11 | 12 | 13 | #include 14 | 15 | void sample2() { 16 | char * end; 17 | const int i = std::strtol ("100", &end, 10); 18 | 19 | // ... 20 | (void)i; // Supressing warning about unused variable. 21 | } 22 | 23 | 24 | 25 | #include 26 | 27 | void sample3() { 28 | const int i = boost::lexical_cast("100"); 29 | // ... 30 | (void)i; // Supressing warning about unused variable. 31 | } 32 | 33 | 34 | 35 | #include 36 | #include 37 | 38 | void sample4() { 39 | char chars[] = {'x', '1', '0', '0', 'y' }; 40 | const int i = boost::lexical_cast(chars + 1, 3); 41 | assert(i == 100); 42 | } 43 | 44 | 45 | 46 | #include 47 | #include 48 | #include 49 | 50 | void sample5() { 51 | try { 52 | // short usually may not store values greater than 32767 53 | const short s = boost::lexical_cast("1000000"); 54 | assert(false); // Must not reach this line. 55 | (void)s; // Supressing warning about unused variable. 56 | } catch (const boost::bad_lexical_cast& e) { 57 | std::cout << e.what() << '\n'; 58 | } 59 | } 60 | 61 | 62 | 63 | #include 64 | #include 65 | #include 66 | 67 | void sample6() { 68 | try { 69 | const int i = boost::lexical_cast("This is not a number!"); 70 | assert(false); // Must not reach this line. 71 | (void)i; // Supressing warning about unused variable. 72 | } catch (const boost::bad_lexical_cast& /*e*/) {} 73 | } 74 | 75 | 76 | 77 | #include 78 | #include 79 | 80 | void sample7() { 81 | int i = 0; 82 | const bool ok = boost::conversion::try_lexical_convert("Bad stuff", i); 83 | assert(!ok); 84 | } 85 | 86 | 87 | 88 | #include 89 | #include 90 | 91 | void sample8() { 92 | try { 93 | std::locale::global(std::locale("ru_RU.UTF8")); 94 | // In Russia coma sign is used as a decimal separator. 95 | float f = boost::lexical_cast("1,0"); 96 | assert(f < 1.01 && f > 0.99); 97 | std::locale::global(std::locale::classic()); // Restoring C locale 98 | } catch (const std::runtime_error&) { /* locale is not supported */ } 99 | } 100 | 101 | 102 | int main() { 103 | sample1(); 104 | sample2(); 105 | sample3(); 106 | sample4(); 107 | sample5(); 108 | sample6(); 109 | sample7(); 110 | sample8(); 111 | } 112 | -------------------------------------------------------------------------------- /Chapter03/02_lexical_to_string/02_lexical_to_string.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter03/02_lexical_to_string/main.cpp: -------------------------------------------------------------------------------- 1 | // Boost.LexicalCast way of converting to strings: 2 | #include 3 | #include 4 | 5 | void lexical_cast_example() { 6 | const std::string s = boost::lexical_cast(100); 7 | assert(s == "100"); 8 | } 9 | 10 | 11 | 12 | // C++ way of converting to strings: 13 | #include 14 | #include 15 | 16 | void cpp_convert_example() { 17 | std::stringstream ss; // Slow/heavy default constructor. 18 | ss << 100; 19 | std::string s; 20 | ss >> s; 21 | 22 | // Variable 'ss' will dangle all the way, till the end 23 | // of scope. Multiple virtual methods and heavy 24 | // operations were called during the conversion. 25 | assert(s == "100"); 26 | } 27 | 28 | 29 | // C way of converting to strings: 30 | #include 31 | #include 32 | 33 | void c_convert_example() { 34 | char buffer[100]; 35 | std::sprintf(buffer, "%i", 100); 36 | 37 | // You will need an unsigned long long int type to 38 | // count how many times errors were made in 'printf' 39 | // like functions all around the world. 'printf' 40 | // functions are a constant security threat! 41 | 42 | // But wait, we still need to construct a std::string. 43 | const std::string s = buffer; 44 | // Now we have a 'buffer' variable that is not used. 45 | 46 | assert(s == "100"); 47 | } 48 | 49 | 50 | 51 | int main() { 52 | lexical_cast_example(); 53 | cpp_convert_example(); 54 | c_convert_example(); 55 | } 56 | -------------------------------------------------------------------------------- /Chapter03/03_numeric_cast/03_numeric_cast.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter03/04_lexical_user_defined/04_lexical_user_defined.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter03/04_lexical_user_defined/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Negative number that does not store minus sign. 5 | class negative_number { 6 | unsigned short number_; 7 | 8 | public: 9 | explicit negative_number(unsigned short number = 0) 10 | : number_(number) 11 | {} 12 | 13 | // ... 14 | unsigned short value_without_sign() const { 15 | return number_; 16 | } 17 | }; 18 | 19 | inline std::ostream& 20 | operator<<(std::ostream& os, const negative_number& num) 21 | { 22 | os << '-' << num.value_without_sign(); 23 | return os; 24 | } 25 | 26 | inline std::istream& operator>>(std::istream& is, negative_number& num) 27 | { 28 | char ch; 29 | is >> ch; 30 | if (ch != '-') { 31 | throw std::logic_error( 32 | "negative_number class stores ONLY negative values" 33 | ); 34 | } 35 | 36 | unsigned short s; 37 | is >> s; 38 | num = negative_number(s); 39 | return is; 40 | } 41 | 42 | 43 | #include 44 | #include 45 | #include 46 | 47 | void example1() { 48 | const negative_number n 49 | = boost::lexical_cast("-100"); 50 | assert(n.value_without_sign() == 100); 51 | 52 | const int i = boost::lexical_cast(n); 53 | assert(i == -100); 54 | 55 | typedef boost::array arr_t; 56 | const arr_t arr = boost::lexical_cast(n); 57 | assert(arr[0] == '-'); 58 | assert(arr[1] == '1'); 59 | assert(arr[2] == '0'); 60 | assert(arr[3] == '0'); 61 | assert(arr[4] == 0); 62 | } 63 | 64 | 65 | template 66 | std::basic_ostream& 67 | operator<<(std::basic_ostream& os, const negative_number& num) 68 | { 69 | os << static_cast('-') << num.value_without_sign(); 70 | return os; 71 | } 72 | 73 | template 74 | std::basic_istream& 75 | operator>>(std::basic_istream& is, negative_number& num) 76 | { 77 | CharT ch; 78 | is >> ch; 79 | if (ch != static_cast('-')) { 80 | throw std::logic_error( 81 | "negative_number class stores ONLY negative values" 82 | ); 83 | } 84 | unsigned short s; 85 | is >> s; 86 | num = negative_number(s); 87 | return is; 88 | } 89 | 90 | void example2() { 91 | const negative_number n = boost::lexical_cast(L"-1"); 92 | assert(n.value_without_sign() == 1); 93 | 94 | typedef boost::array warr_t; 95 | const warr_t arr = boost::lexical_cast(n); 96 | assert(arr[0] == L'-'); 97 | assert(arr[1] == L'1'); 98 | assert(arr[2] == 0); 99 | } 100 | 101 | 102 | int main() { 103 | example1(); 104 | example2(); 105 | } 106 | -------------------------------------------------------------------------------- /Chapter03/05_pointer_cast/05_pointer_cast.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter03/05_pointer_cast/main.cpp: -------------------------------------------------------------------------------- 1 | struct base { 2 | virtual void some_methods() = 0; 3 | virtual ~base(); 4 | }; 5 | 6 | struct derived: public base { 7 | void some_methods() /*override*/; 8 | virtual void derived_method() const; 9 | 10 | ~derived() /*override*/; 11 | }; 12 | 13 | 14 | #include 15 | boost::shared_ptr construct_derived(); 16 | void im_accepting_derived(boost::shared_ptr p); 17 | 18 | /* 19 | 20 | void trying_hard_to_pass_derived() { 21 | boost::shared_ptr d = construct_derived(); 22 | 23 | // Oops! Compile time error: 24 | // ‘const struct base’ has no member named ‘derived_method’. 25 | d->derived_method(); 26 | 27 | // Oops! Compile time error: 28 | // could not convert ‘d’ to ‘boost::shared_ptr’. 29 | im_accepting_derived(d); 30 | } 31 | 32 | */ 33 | 34 | #include 35 | 36 | void trying_hard_to_pass_derived2() { 37 | boost::shared_ptr d 38 | = boost::dynamic_pointer_cast( 39 | construct_derived() 40 | ); 41 | 42 | if (!d) { 43 | throw std::runtime_error( 44 | "Failed to dynamic cast" 45 | ); 46 | } 47 | 48 | d->derived_method(); 49 | im_accepting_derived(d); 50 | } 51 | 52 | int main() { 53 | trying_hard_to_pass_derived2(); 54 | } 55 | 56 | 57 | 58 | // Implementation details: 59 | 60 | #include 61 | #include 62 | 63 | bool g_derived_was_called = false; 64 | base::~base() { 65 | assert(g_derived_was_called); 66 | } 67 | 68 | void derived::derived_method() const { 69 | g_derived_was_called = true; 70 | } 71 | 72 | void derived::some_methods() {} 73 | 74 | derived::~derived() {} 75 | 76 | boost::shared_ptr construct_derived() { 77 | return boost::make_shared(); 78 | } 79 | 80 | void im_accepting_derived(boost::shared_ptr p) { 81 | assert(p); 82 | } 83 | -------------------------------------------------------------------------------- /Chapter03/06_polymorphic_cast/06_polymorphic_cast.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter03/06_polymorphic_cast/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct object { 4 | virtual ~object() {} 5 | }; 6 | 7 | struct banana: public object { 8 | void eat() const {} 9 | virtual ~banana(){} 10 | }; 11 | 12 | struct penguin: public object { 13 | bool try_to_fly() const { 14 | return false; // penguins do not fly 15 | } 16 | virtual ~penguin(){} 17 | }; 18 | 19 | object* try_produce_banana(); 20 | 21 | void try_eat_banana_impl1() { 22 | const object* obj = try_produce_banana(); 23 | if (!obj) { 24 | throw std::bad_cast(); 25 | } 26 | 27 | dynamic_cast(*obj).eat(); 28 | } 29 | 30 | #include 31 | void try_eat_banana_impl2() { 32 | const object* obj = try_produce_banana(); 33 | boost::polymorphic_cast(obj)->eat(); 34 | } 35 | 36 | 37 | 38 | object* try_produce_banana() { 39 | static penguin peng; 40 | static banana banan; 41 | static int i = 0; 42 | ++ i; 43 | if (i == 3 || i == 6) { 44 | return 0; 45 | } else if (i == 2 || i == 5) { 46 | return &peng; 47 | } 48 | return &banan; 49 | } 50 | 51 | #include 52 | using namespace std; 53 | 54 | int main() { 55 | try_eat_banana_impl1(); 56 | try { try_eat_banana_impl1(); assert(false); } catch(...){} 57 | try { try_eat_banana_impl1(); assert(false); } catch(...){} 58 | 59 | try_eat_banana_impl2(); 60 | try { try_eat_banana_impl2(); assert(false); } catch(...){} 61 | try { try_eat_banana_impl2(); assert(false); } catch(...){} 62 | } 63 | 64 | -------------------------------------------------------------------------------- /Chapter03/07_spirit/07_spirit.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter03/08_spirit_rules/08_spirit_rules.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter03/Chapter03.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | 01_lexical_to_number \ 5 | 02_lexical_to_string \ 6 | 03_numeric_cast \ 7 | 04_lexical_user_defined \ 8 | 05_pointer_cast \ 9 | 06_polymorphic_cast \ 10 | 07_spirit \ 11 | 08_spirit_rules 12 | -------------------------------------------------------------------------------- /Chapter04/01_static_assert/01_static_assert.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | #QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter04/02_enable_if_c/02_enable_if_c.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter04/02_enable_if_c/main.cpp: -------------------------------------------------------------------------------- 1 | namespace intro { 2 | 3 | // Generic implementation. 4 | template 5 | class data_processor { 6 | double process(const T& v1, const T& v2, const T& v3); 7 | }; 8 | 9 | 10 | // Integral types optimized version. 11 | template 12 | class data_processor_integral { 13 | typedef int fast_int_t; 14 | double process(fast_int_t v1, fast_int_t v2, fast_int_t v3); 15 | }; 16 | 17 | // SSE optimized version for float types. 18 | template 19 | class data_processor_sse { 20 | double process(double v1, double v2, double v3); 21 | }; 22 | 23 | } // namespace intro 24 | 25 | #include 26 | #include 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | // Generic implementation. 33 | template 34 | class data_processor { 35 | // ... 36 | public: 37 | double process(const T& /*v1*/, const T& /*v2*/, const T& /*v3*/) { 38 | BOOST_STATIC_ASSERT((boost::is_same::value)); 39 | return 0.0; 40 | } 41 | }; 42 | 43 | 44 | // Integral types optimized version. 45 | template 46 | class data_processor< 47 | T, 48 | typename boost::enable_if_c::value >::type 49 | > 50 | { 51 | // ... 52 | public: 53 | typedef int fast_int_t; 54 | double process(fast_int_t /*v1*/, fast_int_t /*v2*/, fast_int_t /*v3*/){ 55 | BOOST_STATIC_ASSERT((boost::is_same::value || boost::is_same::value)); 56 | return 0.0; 57 | } 58 | }; 59 | 60 | // SSE optimized version for float types. 61 | template 62 | class data_processor< 63 | T, 64 | typename boost::enable_if_c::value >::type 65 | > 66 | { 67 | // ... 68 | public: 69 | double process(double /*v1*/, double /*v2*/, double /*v3*/){ 70 | BOOST_STATIC_ASSERT((boost::is_same::value || boost::is_same::value)); 71 | return 0.0; 72 | } 73 | }; 74 | 75 | template 76 | double example_func(T v1, T v2, T v3) { 77 | data_processor proc; 78 | return proc.process(v1, v2, v3); 79 | } 80 | 81 | int main () { 82 | // Integral types optimized version 83 | // will be called. 84 | example_func(1, 2, 3); 85 | short s = 0; 86 | example_func(s, s, s); 87 | 88 | // Real types version will be called. 89 | example_func(1.0, 2.0, 3.0); 90 | example_func(1.0f, 2.0f, 3.0f); 91 | 92 | // Generic version will be called. 93 | example_func("Hello", "word", "processing"); 94 | } 95 | 96 | -------------------------------------------------------------------------------- /Chapter04/03_disable_if_c/03_disable_if_c.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter04/03_disable_if_c/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | //template 5 | //T process_data(const T& v1, const T& v2, const T& v3); 6 | 7 | template 8 | T process_data_plus_assign(const T& v1, const T& v2, const T& v3){ 9 | BOOST_STATIC_ASSERT((boost::is_same::value)); 10 | (void)v2; 11 | (void)v3; 12 | return v1; 13 | } 14 | 15 | #include 16 | #include 17 | 18 | // Modified generic version of process_data 19 | template 20 | typename boost::disable_if_c::value,T>::type 21 | process_data(const T& v1, const T& v2, const T& v3) 22 | { 23 | BOOST_STATIC_ASSERT((boost::is_same::value)); 24 | (void)v2; 25 | (void)v3; 26 | return v1; 27 | } 28 | 29 | // This process_data will call a process_data_plus_assign 30 | template 31 | typename boost::enable_if_c::value, T>::type 32 | process_data(const T& v1, const T& v2, const T& v3) 33 | { 34 | return process_data_plus_assign(v1, v2, v3); 35 | } 36 | 37 | // First version 38 | template 39 | typename boost::disable_if, T>::type 40 | process_data2(const T& v1, const T& v2, const T& v3); 41 | 42 | // process_data_plus_assign 43 | template 44 | typename boost::enable_if, T>::type 45 | process_data2(const T& v1, const T& v2, const T& v3); 46 | 47 | 48 | int main() { 49 | int i = 1; 50 | // Optimized version. 51 | process_data(i, i, i); 52 | 53 | // Default version. 54 | // Explicitly specifing template parameter. 55 | process_data("Testing", "example", "function"); 56 | } 57 | -------------------------------------------------------------------------------- /Chapter04/04_mpl_int_/04_mpl_int_.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | #QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter04/04_mpl_int_/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | namespace detail { 7 | // Generic implementation. 8 | template 9 | T process_impl(const T& val, Tag /*ignore*/) { 10 | // ... 11 | BOOST_STATIC_ASSERT(sizeof(val) != 1 12 | && sizeof(val) != 4 13 | && sizeof(val) != 8 14 | ); 15 | return val; 16 | } 17 | 18 | // 1 byte optimized implementation. 19 | template 20 | T process_impl(const T& val, boost::mpl::int_<1> /*ignore*/) { 21 | // ... 22 | BOOST_STATIC_ASSERT(sizeof(val) == 1); 23 | return val; 24 | } 25 | 26 | 27 | // 4 bytes optimized implementation. 28 | template 29 | T process_impl(const T& val, boost::mpl::int_<4> /*ignore*/) { 30 | // ... 31 | BOOST_STATIC_ASSERT(sizeof(val) == 4); 32 | return val; 33 | } 34 | 35 | // 8 bytes optimized implementation. 36 | template 37 | T process_impl(const T& val, boost::mpl::int_<8> /*ignore*/) { 38 | // ... 39 | BOOST_STATIC_ASSERT(sizeof(val) == 8); 40 | return val; 41 | } 42 | } // namespace detail 43 | 44 | 45 | // Dispatching calls: 46 | template 47 | T process(const T& val) { 48 | BOOST_STATIC_ASSERT((boost::is_pod::value)); 49 | return detail::process_impl(val, boost::mpl::int_()); 50 | } 51 | 52 | template 53 | struct int_ { 54 | static const int value = Value; 55 | typedef int_ type; 56 | typedef int value_type; 57 | }; 58 | 59 | #include 60 | int main() { 61 | std::cout 62 | << ' ' << process(int(0)) 63 | << ' ' << process(double(1)) 64 | << ' ' << process(float(2)) 65 | << ' ' << process(char(3)) 66 | << ' ' << process(unsigned(4)) 67 | << ' ' << process(short(5)) 68 | << std::endl; 69 | } 70 | -------------------------------------------------------------------------------- /Chapter04/05_is_stdvector/05_is_stdvector.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | #QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter04/05_is_stdvector/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | struct is_stdvector: boost::false_type {}; 6 | 7 | template 8 | struct is_stdvector >: boost::true_type {}; 9 | 10 | 11 | #include 12 | int main () { 13 | BOOST_STATIC_ASSERT(is_stdvector >::value); 14 | BOOST_STATIC_ASSERT(!is_stdvector::value); 15 | BOOST_STATIC_ASSERT(!is_stdvector::value); 16 | } 17 | -------------------------------------------------------------------------------- /Chapter04/06_conditional/06_conditional.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | #QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter04/07_typeof/07_typeof.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | #QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter04/07_typeof/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | BOOST_AUTO(var, boost::bind(std::plus(), _1, _1)); 6 | 7 | typedef BOOST_TYPEOF(0.5 + 0.5f) type; 8 | 9 | // Long and portable way: 10 | template 11 | struct result_of { 12 | typedef BOOST_TYPEOF_TPL(T1() + T2()) type; 13 | }; 14 | 15 | template 16 | typename result_of::type add(const T1& t1, const T2& t2) { 17 | return t1 + t2; 18 | }; 19 | 20 | // ... or ... 21 | 22 | // Shorter version that may crush some compilers. 23 | template 24 | BOOST_TYPEOF_TPL(T1() + T2()) add2(const T1& t1, const T2& t2) { 25 | return t1 + t2; 26 | }; 27 | 28 | 29 | #include 30 | #include 31 | BOOST_STATIC_ASSERT((boost::is_same::value)); 32 | 33 | 34 | namespace readers_project { 35 | template 36 | struct readers_template_class{}; 37 | } 38 | 39 | #include 40 | 41 | typedef 42 | readers_project::readers_template_class 43 | readers_template_class_1; 44 | 45 | typedef BOOST_TYPEOF(boost::get<0>( 46 | boost::make_tuple(readers_template_class_1(), 1) 47 | )) readers_template_class_deduced; 48 | 49 | BOOST_STATIC_ASSERT(( 50 | boost::is_same< 51 | readers_template_class_1, 52 | readers_template_class_deduced 53 | >::value 54 | )); 55 | 56 | BOOST_TYPEOF_REGISTER_TEMPLATE( 57 | readers_project::readers_template_class /*class name*/, 58 | 3 /*number of template classes*/ 59 | ) 60 | 61 | 62 | 63 | #if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) 64 | namespace modern_cpp { 65 | typedef decltype(0.5 + 0.5f) type; 66 | 67 | template 68 | auto add(const T1& t1, const T2& t2) ->decltype(t1 + t2) { 69 | return t1 + t2; 70 | }; 71 | } 72 | 73 | #endif 74 | 75 | #include 76 | int main () { 77 | assert(add(1, 2) == 3); 78 | 79 | #if !defined(BOOST_NO_CXX11_DECLTYPE) && !defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) 80 | BOOST_STATIC_ASSERT(( 81 | boost::is_same< 82 | type, 83 | modern_cpp::type 84 | >::value 85 | )); 86 | 87 | 88 | BOOST_STATIC_ASSERT(( 89 | boost::is_same< 90 | decltype(add(1,2)), 91 | decltype(modern_cpp::add(1,2)) 92 | >::value 93 | )); 94 | #endif 95 | } 96 | -------------------------------------------------------------------------------- /Chapter04/Chapter04.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | 01_static_assert \ 5 | 02_enable_if_c \ 6 | 03_disable_if_c \ 7 | 04_mpl_int_ \ 8 | 05_is_stdvector \ 9 | 06_conditional \ 10 | 07_typeof 11 | 12 | -------------------------------------------------------------------------------- /Chapter05/01_thread/01_thread.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | !msvc:LIBS += -lboost_thread -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter05/01_thread/main.cpp: -------------------------------------------------------------------------------- 1 | #include // for std::size_t 2 | 3 | bool is_first_run(); 4 | 5 | // Function that executes for a long time. 6 | void fill_file(char fill_char, std::size_t size, const char* filename); 7 | 8 | // Called in thread that draws a user interface: 9 | void example_without_threads() { 10 | if (is_first_run()) { 11 | // This will be executing for a long time during which 12 | // users interface freezes... 13 | fill_file(0, 8 * 1024 * 1024, "save_file.txt"); 14 | } 15 | } 16 | 17 | 18 | 19 | 20 | #include 21 | 22 | // Called in thread that draws a user interface: 23 | void example_with_threads() { 24 | if (is_first_run()) { 25 | boost::thread(boost::bind( 26 | &fill_file, 27 | 0, 28 | 8 * 1024 * 1024, 29 | "save_file.txt" 30 | )).detach(); 31 | } 32 | } 33 | 34 | 35 | 36 | void example_with_joining_threads() { 37 | if (is_first_run()) { 38 | boost::thread t(boost::bind( 39 | &fill_file, 40 | 0, 41 | 8 * 1024 * 1024, 42 | "save_file.txt" 43 | )); 44 | 45 | // Do some work. 46 | // ... 47 | 48 | // Waiting for thread to finish. 49 | t.join(); 50 | } 51 | } 52 | 53 | 54 | 55 | #include 56 | 57 | void some_func(); 58 | 59 | void example_with_raii() { 60 | boost::scoped_thread t( 61 | boost::thread(&some_func) 62 | ); 63 | 64 | // 't' will be joined at scope exit. 65 | } 66 | 67 | 68 | 69 | void set_not_first_run(); 70 | 71 | int main() { 72 | example_with_threads(); 73 | example_with_joining_threads(); 74 | example_with_raii(); 75 | 76 | example_without_threads(); 77 | } 78 | 79 | // details: 80 | 81 | #include 82 | #include 83 | #include 84 | void fill_file(char fill_char, std::size_t size, const char* filename) { 85 | std::ofstream ofs(filename); 86 | std::fill_n(std::ostreambuf_iterator(ofs), size, fill_char); 87 | } 88 | 89 | bool is_first_run() { 90 | return true; 91 | } 92 | 93 | void some_func(){} 94 | -------------------------------------------------------------------------------- /Chapter05/02_mutex/02_mutex.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | !msvc:LIBS += -lboost_thread -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter05/02_mutex/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | // In previous recipe we included 6 | // , which includes all 7 | // the classes of Boost.Thread. 8 | // Following header includes only boost::thread. 9 | #include 10 | 11 | namespace without_sync { 12 | 13 | int shared_i = 0; 14 | 15 | void do_inc() { 16 | for (std::size_t i = 0; i < 30000; ++i) { 17 | const int i_snapshot = ++shared_i; 18 | // Do some work with i_snapshot. 19 | // ... 20 | (void) i_snapshot; 21 | } 22 | } 23 | 24 | void do_dec() { 25 | for (std::size_t i = 0; i < 30000; ++i) { 26 | const int i_snapshot = --shared_i; 27 | // Do some work with i_snapshot. 28 | // ... 29 | (void) i_snapshot; 30 | } 31 | } 32 | 33 | void run() { 34 | boost::thread t1(&do_inc); 35 | boost::thread t2(&do_dec); 36 | 37 | t1.join(); 38 | t2.join(); 39 | 40 | // assert(shared_i == 0); // Oops! 41 | std::cout << "shared_i == " << shared_i; 42 | } 43 | 44 | } // namespace without_sync 45 | 46 | #include 47 | #include 48 | 49 | namespace with_sync { 50 | 51 | int shared_i = 0; 52 | boost::mutex i_mutex; 53 | 54 | void do_inc() { 55 | for (std::size_t i = 0; i < 30000; ++i) { 56 | int i_snapshot; 57 | { // Critical section begin. 58 | boost::lock_guard lock(i_mutex); 59 | i_snapshot = ++shared_i; 60 | } // Critical section end. 61 | 62 | // Do some work with i_snapshot. 63 | // ... 64 | (void)i_snapshot; 65 | } 66 | } 67 | 68 | void do_dec() { 69 | for (std::size_t i = 0; i < 30000; ++i) { 70 | int i_snapshot; 71 | { // Critical section begin. 72 | boost::lock_guard lock(i_mutex); 73 | i_snapshot = -- shared_i; 74 | } // Critical section end. 75 | 76 | // Do some work with i_snapshot. 77 | // ... 78 | (void) i_snapshot; 79 | } 80 | } 81 | 82 | void run() { 83 | boost::thread t1(&do_inc); 84 | boost::thread t2(&do_dec); 85 | 86 | t1.join(); 87 | t2.join(); 88 | 89 | assert(shared_i == 0); 90 | std::cout << "shared_i == " << shared_i; 91 | } 92 | 93 | } // namespace without_sync 94 | 95 | #include 96 | 97 | int main() { 98 | without_sync::run(); 99 | std::cout << '\n'; 100 | with_sync::run(); 101 | std::cout << '\n'; 102 | } 103 | -------------------------------------------------------------------------------- /Chapter05/03_atomics/03_atomics.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | !msvc:LIBS += -lboost_thread -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter05/03_atomics/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | boost::atomic shared_i(0); 9 | 10 | void do_inc() { 11 | for (std::size_t i = 0; i < 30000; ++i) { 12 | const int i_snapshot = ++ shared_i; 13 | 14 | // Do some work with i_snapshot. 15 | // ... 16 | (void) i_snapshot; 17 | } 18 | } 19 | 20 | void do_dec() { 21 | for (std::size_t i = 0; i < 30000; ++i) { 22 | const int i_snapshot = -- shared_i; 23 | 24 | // Do some work with i_snapshot. 25 | // ... 26 | (void) i_snapshot; 27 | } 28 | } 29 | 30 | 31 | int main() { 32 | boost::thread t1(&do_inc); 33 | boost::thread t2(&do_dec); 34 | 35 | t1.join(); 36 | t2.join(); 37 | 38 | assert(shared_i == 0); 39 | std::cout << "shared_i == " << shared_i << std::endl; 40 | 41 | assert(shared_i.is_lock_free()); 42 | } 43 | 44 | #include 45 | BOOST_STATIC_ASSERT(BOOST_ATOMIC_INT_LOCK_FREE == 2); 46 | -------------------------------------------------------------------------------- /Chapter05/04_work_queue/04_work_queue.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | !msvc:LIBS += -lboost_thread -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter05/05_shared_lock/05_shared_lock.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | QMAKE_CXXFLAGS += $$CPP11FLAG 6 | SOURCES += main.cpp 7 | !msvc:LIBS += -lboost_thread -lboost_system 8 | -------------------------------------------------------------------------------- /Chapter05/06_thread_specific_ptr/06_thread_specific_ptr.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | !msvc:LIBS += -lboost_thread -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter05/06_thread_specific_ptr/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class connection: boost::noncopyable { 4 | public: 5 | // Opening a connection is a slow operation 6 | void open(); 7 | 8 | void send_result(int result); 9 | 10 | // Other methods 11 | // ... 12 | int open_count_; 13 | connection(): open_count_(0) {} 14 | }; 15 | 16 | // In header file: 17 | connection& get_connection(); 18 | 19 | // In source file: 20 | #include 21 | #include 22 | #include 23 | 24 | boost::thread_specific_ptr connection_ptr; 25 | 26 | connection& get_connection() { 27 | connection* p = connection_ptr.get(); 28 | if (!p) { 29 | connection_ptr.reset(new connection); 30 | p = connection_ptr.get(); 31 | p->open(); 32 | } 33 | 34 | return *p; 35 | } 36 | 37 | 38 | void task() { 39 | int result = 2; 40 | // Some computations go there. 41 | // ... 42 | 43 | // Sending the result: 44 | get_connection().send_result(result); 45 | } 46 | 47 | void connection::open() { 48 | assert(!open_count_); 49 | open_count_ = 1; 50 | } 51 | 52 | void connection::send_result(int /*result*/) {} 53 | 54 | void run_tasks() { 55 | for (std::size_t i = 0; i < 1000 /*0000*/; ++i) { 56 | task(); 57 | } 58 | } 59 | 60 | #include 61 | 62 | int main() { 63 | boost::thread t1(&run_tasks); 64 | boost::thread t2(&run_tasks); 65 | boost::thread t3(&run_tasks); 66 | boost::thread t4(&run_tasks); 67 | 68 | // Waiting for all the tasks to stop. 69 | t1.join(); 70 | t2.join(); 71 | t3.join(); 72 | t4.join(); 73 | } 74 | -------------------------------------------------------------------------------- /Chapter05/07_interruptions/07_interruptions.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | !msvc:LIBS += -lboost_thread -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter05/07_interruptions/main.cpp: -------------------------------------------------------------------------------- 1 | bool stop_parsing = true; 2 | bool not_end_of_parsing = true; 3 | 4 | #include 5 | 6 | void do_parse(); 7 | 8 | int main() { 9 | boost::thread parser_thread(&do_parse); 10 | 11 | // ... 12 | 13 | if (stop_parsing) { 14 | // No more parsing required. 15 | // TODO: Stop the parser! 16 | } 17 | 18 | if (stop_parsing) { 19 | // No more parsing required. 20 | parser_thread.interrupt(); 21 | } 22 | 23 | parser_thread.join(); 24 | } 25 | 26 | void do_parse() { 27 | while (not_end_of_parsing) { 28 | // If current thread was interrupted, the following 29 | // line will throw an boost::thread_interrupted. 30 | boost::this_thread::interruption_point(); 31 | 32 | // Some parsing goes here. 33 | // ... 34 | } 35 | 36 | // Newer shall reach this code 37 | assert(false); 38 | } 39 | 40 | -------------------------------------------------------------------------------- /Chapter05/08_thread_group/08_thread_group.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | !msvc:LIBS += -lboost_thread -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter05/08_thread_group/main.cpp: -------------------------------------------------------------------------------- 1 | void do_assert(int threads_joined); 2 | 3 | 4 | 5 | #include 6 | 7 | void some_function(); 8 | 9 | void sample() { 10 | boost::thread t1(&some_function); 11 | boost::thread t2(&some_function); 12 | boost::thread t3(&some_function); 13 | // ... 14 | 15 | t1.join(); 16 | t2.join(); 17 | t3.join(); 18 | } 19 | 20 | 21 | 22 | #include 23 | 24 | int main() { 25 | boost::thread_group threads; 26 | 27 | // Launching 10 threads. 28 | for (unsigned i = 0; i < 10; ++i) { 29 | threads.create_thread(&some_function); 30 | } 31 | 32 | // Joining all threads. 33 | threads.join_all(); 34 | 35 | // We can also interrupt all of them 36 | // by calling threads.interrupt_all(); 37 | 38 | do_assert(10); 39 | sample(); 40 | do_assert(13); 41 | } 42 | 43 | 44 | // details: 45 | 46 | #include 47 | boost::atomic_int g_counter(0); 48 | 49 | void do_assert(int threads_joined) { 50 | assert(g_counter == threads_joined); 51 | } 52 | 53 | void some_function() { 54 | ++g_counter; 55 | } 56 | -------------------------------------------------------------------------------- /Chapter05/09_once/09_once.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | QMAKE_CXXFLAGS += $$CPP11FLAG 6 | SOURCES += main.cpp 7 | !msvc:LIBS += -lboost_thread -lboost_system 8 | -------------------------------------------------------------------------------- /Chapter05/09_once/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Executes for a long time. 5 | std::vector read_defaults(); 6 | 7 | namespace first_attempt { 8 | 9 | struct postprocessor { 10 | typedef std::vector answer_t; 11 | 12 | // Concurrent calls on the same variable are safe. 13 | answer_t act(const std::string& in) const { 14 | if (in.empty()) { 15 | // Extremely rare condition. 16 | return read_defaults(); 17 | } 18 | 19 | // ... 20 | answer_t ret; 21 | return ret; 22 | } 23 | }; 24 | 25 | } // namespace first_attempt 26 | 27 | namespace second_attempt { 28 | 29 | struct postprocessor { 30 | typedef std::vector answer_t; 31 | 32 | private: 33 | answer_t default_; 34 | 35 | public: 36 | postprocessor() 37 | : default_(read_defaults()) 38 | {} 39 | 40 | // Concurrent calls on the same variable are safe. 41 | answer_t act(const std::string& in) const { 42 | if (in.empty()) { 43 | // Extremely rare condition. 44 | return default_; 45 | } 46 | 47 | // ... 48 | answer_t ret; 49 | return ret; 50 | } 51 | }; 52 | 53 | } // namespace second_attempt 54 | 55 | 56 | 57 | 58 | #include 59 | 60 | namespace right_solution { 61 | 62 | struct postprocessor { 63 | typedef std::vector answer_t; 64 | 65 | private: 66 | mutable boost::once_flag default_flag_; 67 | mutable answer_t default_; 68 | 69 | public: 70 | postprocessor() 71 | : default_flag_(BOOST_ONCE_INIT) 72 | , default_() 73 | {} 74 | 75 | // Concurrent calls on the same variable are safe. 76 | answer_t act(const std::string& in) const { 77 | answer_t ret; 78 | if (in.empty()) { 79 | // Extremely rare condition. 80 | boost::call_once(default_flag_, [this]() { 81 | this->default_ = read_defaults(); 82 | }); 83 | return default_; 84 | } 85 | 86 | // ... 87 | return ret; 88 | } 89 | }; 90 | 91 | } // namespace right_solution 92 | 93 | #include 94 | void once_printer(int i) { 95 | static boost::once_flag flag = BOOST_ONCE_INIT; 96 | boost::call_once( 97 | flag, 98 | [](int v) { std::cout << "Print once " << v << '\n'; }, 99 | i // <=== Passed to lambda from above. 100 | ); 101 | 102 | // ... 103 | } 104 | 105 | 106 | #include 107 | int main() { 108 | right_solution::postprocessor pp; 109 | assert(pp.act(std::string()).size() == 5); 110 | assert(pp.act("Hello").size() == 0); 111 | 112 | for (unsigned i = 0; i < 10; ++i) { 113 | once_printer(i); 114 | } 115 | } 116 | 117 | // Details: 118 | 119 | std::vector read_defaults() { 120 | std::vector ret { 121 | "Do", "not", "look", "at", "me" 122 | }; 123 | return ret; 124 | } 125 | -------------------------------------------------------------------------------- /Chapter05/10_locks/10_locks.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | !msvc:LIBS += -lboost_thread -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter05/10_locks/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef int item_t; 5 | 6 | namespace first_attempt { 7 | 8 | class user { 9 | boost::mutex loot_mutex_; 10 | std::vector loot_; 11 | public: 12 | // ... 13 | 14 | void exchange_loot(user& u); 15 | }; 16 | 17 | } // namespace first_attempt 18 | 19 | #include 20 | #include 21 | 22 | void first_attempt::user::exchange_loot(user& u) { 23 | // Terribly wrong!!! ABBA deadlocks. 24 | boost::lock_guard l0(loot_mutex_); 25 | boost::lock_guard l1(u.loot_mutex_); 26 | loot_.swap(u.loot_); 27 | } 28 | 29 | 30 | 31 | namespace second_attempt { 32 | 33 | class user { 34 | boost::mutex loot_mutex_; 35 | std::vector loot_; 36 | public: 37 | // ... 38 | 39 | void exchange_loot(user& u); 40 | }; 41 | 42 | } // namespace second_attempt 43 | 44 | #ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES 45 | 46 | #include 47 | void second_attempt::user::exchange_loot(user& u) { 48 | typedef boost::unique_lock lock_t; 49 | 50 | std::tuple l = boost::make_unique_locks( 51 | loot_mutex_, u.loot_mutex_ 52 | ); 53 | 54 | loot_.swap(u.loot_); 55 | } 56 | 57 | 58 | #endif // #ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES 59 | 60 | 61 | 62 | #ifdef __cpp_lib_scoped_lock 63 | #include 64 | namespace cpp17_attempt { 65 | 66 | class user { 67 | std::mutex loot_mutex_; 68 | std::vector loot_; 69 | public: 70 | // ... 71 | 72 | void exchange_loot(user& u); 73 | }; 74 | 75 | } // namespace cpp17_attempt 76 | 77 | void cpp17_attempt::user::exchange_loot(user& u) { 78 | std::scoped_lock l(loot_mutex_, u.loot_mutex_); 79 | loot_.swap(u.loot_); 80 | } 81 | 82 | #endif // __cpp_lib_scoped_lock 83 | 84 | 85 | 86 | namespace portable_attempt { 87 | 88 | class user { 89 | boost::mutex loot_mutex_; 90 | std::vector loot_; 91 | public: 92 | // ... 93 | 94 | void exchange_loot(user& u); 95 | }; 96 | 97 | #include 98 | 99 | void user::exchange_loot(user& u) { 100 | typedef boost::unique_lock lock_t; 101 | 102 | lock_t l0(loot_mutex_, boost::defer_lock); 103 | lock_t l1(u.loot_mutex_, boost::defer_lock); 104 | boost::lock(l0, l1); 105 | 106 | loot_.swap(u.loot_); 107 | } 108 | 109 | } // namespace last_attempt 110 | 111 | 112 | 113 | template 114 | void do_test() { 115 | UserType u1; 116 | UserType u2; 117 | 118 | u1.exchange_loot(u2); 119 | } 120 | 121 | 122 | int main() { 123 | do_test(); // Intentionally has ABBA deadlock! 124 | 125 | #ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES 126 | do_test(); 127 | #endif 128 | #ifdef __cpp_lib_scoped_lock 129 | do_test(); 130 | #endif 131 | do_test(); 132 | } 133 | -------------------------------------------------------------------------------- /Chapter05/Chapter05.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | 01_thread \ 5 | 02_mutex \ 6 | 03_atomics \ 7 | 04_work_queue \ 8 | 05_shared_lock \ 9 | 06_thread_specific_ptr \ 10 | 07_interruptions \ 11 | 08_thread_group \ 12 | 09_once \ 13 | 10_locks 14 | 15 | 16 | -------------------------------------------------------------------------------- /Chapter06/01_tasks_processor_base/01_tasks_processor_base.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | HEADERS += tasks_processor_base.hpp 6 | SOURCES += main.cpp 7 | !msvc { 8 | LIBS += -lboost_system -lboost_thread 9 | win32:LIBS += -lws2_32 10 | } 11 | -------------------------------------------------------------------------------- /Chapter06/01_tasks_processor_base/main.cpp: -------------------------------------------------------------------------------- 1 | // Amost all the code for this example is in this header 2 | #include "tasks_processor_base.hpp" 3 | using namespace tp_base; 4 | 5 | int func_test() { 6 | static int counter = 0; 7 | ++ counter; 8 | boost::this_thread::interruption_point(); 9 | 10 | switch (counter) { 11 | case 3: 12 | throw std::logic_error("Just checking"); 13 | 14 | case 10: 15 | // Emulation of thread interruption. 16 | // Caught inside task_wrapped and does not stop execution. 17 | throw boost::thread_interrupted(); 18 | 19 | case 30: 20 | // Throwing exception not derived from std::exception. 21 | throw 1; 22 | 23 | case 90: 24 | // Stopping the tasks_processor. 25 | tasks_processor::stop(); 26 | } 27 | 28 | return counter; 29 | } 30 | 31 | int main () { 32 | for (std::size_t i = 0; i < 100; ++i) { 33 | tasks_processor::push_task(&func_test); 34 | } 35 | 36 | // Processing was not started. 37 | assert(func_test() == 1); 38 | 39 | // We can also use lambda as a task. 40 | #ifndef BOOST_NO_CXX11_LAMBDAS 41 | // Counting 2 + 2 asynchronously. 42 | int sum = 0; 43 | tasks_processor::push_task( 44 | [&sum]() { sum = 2 + 2; } 45 | ); 46 | // Processing was not started. 47 | assert(sum == 0); 48 | #endif 49 | 50 | // Does not throw, but blocks till 51 | // one of the tasks it is owning 52 | // calls tasks_processor::stop(). 53 | tasks_processor::start(); 54 | assert(func_test() >= 91); 55 | } 56 | -------------------------------------------------------------------------------- /Chapter06/02_tasks_processor_timers/02_tasks_processor_timers.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | 6 | HEADERS += \ 7 | ../01_tasks_processor_base/tasks_processor_base.hpp \ 8 | tasks_processor_timers.hpp 9 | 10 | SOURCES += main.cpp 11 | QMAKE_CXXFLAGS += $$CPP11FLAG 12 | !msvc { 13 | LIBS += -lboost_system -lboost_thread 14 | win32:LIBS += -lws2_32 15 | } 16 | -------------------------------------------------------------------------------- /Chapter06/02_tasks_processor_timers/main.cpp: -------------------------------------------------------------------------------- 1 | // Almost all the code for this recipe 2 | // is in this header file. 3 | #include "tasks_processor_timers.hpp" 4 | using namespace tp_timers; 5 | 6 | struct test_functor { 7 | int& i_; 8 | 9 | explicit test_functor(int& i); 10 | 11 | void operator()() const { 12 | i_ = 1; 13 | tasks_processor::stop(); 14 | } 15 | }; 16 | 17 | void test_func1(); 18 | 19 | #include 20 | 21 | int main () { 22 | const int seconds_to_wait = 3; 23 | int i = 0; 24 | 25 | tasks_processor::run_delayed( 26 | boost::posix_time::seconds(seconds_to_wait), 27 | test_functor(i) 28 | ); 29 | 30 | tasks_processor::run_delayed( 31 | boost::posix_time::from_time_t(time(NULL) + 1), 32 | &test_func1 33 | ); 34 | 35 | int t1 = static_cast(time(NULL)); 36 | assert(i == 0); 37 | 38 | // Blocks till one of the tasks 39 | // calls tasks_processor::stop(). 40 | tasks_processor::start(); 41 | 42 | assert(i == 1); 43 | int t2 = static_cast(time(NULL)); 44 | assert(t2 - t1 >= seconds_to_wait); 45 | } 46 | 47 | 48 | test_functor::test_functor(int& i) 49 | : i_(i) 50 | {} 51 | 52 | void test_func1() { 53 | throw std::logic_error("It works!"); 54 | } 55 | -------------------------------------------------------------------------------- /Chapter06/02_tasks_processor_timers/tasks_processor_timers.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOK_CHAPTER6_TASK_PROCESSOR_TIMERS_HPP 2 | #define BOOK_CHAPTER6_TASK_PROCESSOR_TIMERS_HPP 3 | 4 | #include "../01_tasks_processor_base/tasks_processor_base.hpp" 5 | 6 | #include 7 | #include 8 | #include // std::unique_ptr 9 | #include 10 | 11 | namespace detail { 12 | 13 | template 14 | struct timer_task { 15 | private: 16 | std::unique_ptr timer_; 17 | task_wrapped task_; 18 | 19 | public: 20 | explicit timer_task( 21 | std::unique_ptr timer, 22 | const Functor& task_unwrapped) 23 | : timer_(std::move(timer)) 24 | , task_(task_unwrapped) 25 | {} 26 | 27 | void operator()(const boost::system::error_code& error) const { 28 | if (!error) { 29 | task_(); 30 | } else { 31 | std::cerr << error << '\n'; 32 | } 33 | } 34 | }; 35 | 36 | } // namespace detail 37 | 38 | namespace tp_timers { 39 | 40 | class tasks_processor: public tp_base::tasks_processor { 41 | // ... 42 | public: 43 | template 44 | static void run_delayed(Time duration_or_time, const Func& f) { 45 | std::unique_ptr timer( 46 | new boost::asio::deadline_timer( 47 | get_ios(), duration_or_time 48 | ) 49 | ); 50 | 51 | boost::asio::deadline_timer& timer_ref = *timer; 52 | 53 | timer_ref.async_wait( 54 | detail::timer_task( 55 | std::move(timer), 56 | f 57 | ) 58 | ); 59 | } 60 | }; 61 | 62 | } // namespace tp_timers 63 | 64 | #endif // BOOK_CHAPTER6_TASK_PROCESSOR_TIMERS_HPP 65 | -------------------------------------------------------------------------------- /Chapter06/03_tasks_processor_network_client/03_tasks_processor_network_client.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | # We are NOT building an executable 6 | TEMPLATE -= app 7 | 8 | # ... we are building a library. 9 | TEMPLATE = lib 10 | 11 | HEADERS += \ 12 | ../01_tasks_processor_base/tasks_processor_base.hpp \ 13 | ../02_tasks_processor_timers/tasks_processor_timers.hpp \ 14 | tasks_processor_network_client.hpp 15 | 16 | SOURCES += client.cpp 17 | QMAKE_CXXFLAGS += $$CPP11FLAG 18 | !msvc { 19 | LIBS += -lboost_system -lboost_thread 20 | win32:LIBS += -lws2_32 -lwsock32 21 | } 22 | -------------------------------------------------------------------------------- /Chapter06/03_tasks_processor_network_client/client.cpp: -------------------------------------------------------------------------------- 1 | // Big part of code for this recipe 2 | // in in this header: 3 | #include "tasks_processor_network_client.hpp" 4 | #include "client.hpp" 5 | using namespace tp_network_client; 6 | 7 | bool g_authed = false; 8 | 9 | void process_server_response( 10 | connection_ptr&& soc, 11 | const boost::system::error_code& err) 12 | { 13 | if (err && err != boost::asio::error::eof) { 14 | std::cerr << "Client error on receive: " << err.message() << '\n'; 15 | assert(false); 16 | } 17 | 18 | if (soc->data.size() != 2) { 19 | std::cerr << "Wrong bytes count\n"; 20 | assert(false); 21 | } 22 | 23 | if (soc->data != "OK") { 24 | std::cerr << "Wrong response: " << soc->data << '\n'; 25 | assert(false); 26 | } 27 | 28 | g_authed = true; 29 | soc->shutdown(); 30 | tasks_processor::stop(); 31 | } 32 | 33 | void receive_auth_response( 34 | connection_ptr&& soc, 35 | const boost::system::error_code& err) 36 | { 37 | if (err) { 38 | std::cerr << "Error on sending data: " << err.message() << '\n'; 39 | assert(false); 40 | } 41 | 42 | async_read_data( 43 | std::move(soc), 44 | &process_server_response, 45 | 2 46 | ); 47 | } 48 | 49 | void send_auth() { 50 | connection_ptr soc = tasks_processor::create_connection( 51 | "127.0.0.1", g_port_num 52 | ); 53 | soc->data = "auth_name"; 54 | 55 | async_write_data( 56 | std::move(soc), 57 | &receive_auth_response 58 | ); 59 | } 60 | -------------------------------------------------------------------------------- /Chapter06/03_tasks_processor_network_client/client.hpp: -------------------------------------------------------------------------------- 1 | // Helper heade file 2 | extern bool g_authed; 3 | const unsigned short g_port_num = 65001; 4 | 5 | void send_auth(); 6 | -------------------------------------------------------------------------------- /Chapter06/04_tasks_processor_network_accept/04_tasks_processor_network_accept.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | HEADERS += \ 6 | ../01_tasks_processor_base/tasks_processor_base.hpp \ 7 | ../02_tasks_processor_timers/tasks_processor_timers.hpp \ 8 | ../03_tasks_processor_network_client/tasks_processor_network_client.hpp \ 9 | ../03_tasks_processor_network_client/client.hpp \ 10 | 04_tasks_processor_network_accept.hpp 11 | 12 | SOURCES += \ 13 | ../03_tasks_processor_network_client/client.cpp \ 14 | main.cpp 15 | 16 | QMAKE_CXXFLAGS += $$CPP11FLAG 17 | !msvc { 18 | LIBS += -lboost_system -lboost_thread 19 | win32:LIBS += -lws2_32 -lwsock32 20 | } 21 | -------------------------------------------------------------------------------- /Chapter06/04_tasks_processor_network_accept/main.cpp: -------------------------------------------------------------------------------- 1 | // Big part of code for this recipe 2 | // in in this header: 3 | #include "tasks_processor_network_accept.hpp" 4 | #include "../03_tasks_processor_network_client/client.hpp" 5 | using namespace tp_network; 6 | 7 | class authorizer { 8 | public: 9 | static void on_connection_accpet( 10 | connection_ptr&& connection, 11 | const boost::system::error_code& error) 12 | { 13 | if (error) return; 14 | async_read_data_at_least(std::move(connection), &authorizer::on_datarecieve, 1, 1024); 15 | } 16 | 17 | static void on_datarecieve(connection_ptr&& connection, const boost::system::error_code& error) { 18 | if (error) { 19 | std::cerr << "authorizer.on_datarecieve: error during recieving response: " << error << '\n'; 20 | assert(false); 21 | } 22 | 23 | if (connection->data.size() == 0) { 24 | std::cerr << "authorizer.on_datarecieve: zero bytes recieved\n"; 25 | assert(false); 26 | } 27 | 28 | assert(connection->data == "auth_name"); 29 | 30 | // We have data and now we can 31 | // do some authorization. 32 | // ... 33 | connection->data = "OK"; 34 | // ... 35 | 36 | // Now we have response in `connection->data` and it's time to send it. 37 | async_write_data(std::move(connection), &authorizer::on_datasend); 38 | } 39 | 40 | static void on_datasend(connection_ptr&& connection, const boost::system::error_code& error) { 41 | if (error) { 42 | std::cerr << "authorizer.on_datasend: error during sending response: " << error << '\n'; 43 | assert(false); 44 | } 45 | 46 | connection->shutdown(); 47 | } 48 | }; 49 | 50 | 51 | int main() { 52 | tasks_processor::run_delayed(boost::posix_time::seconds(1), &send_auth); 53 | tasks_processor::add_listener(g_port_num, &authorizer::on_connection_accpet); 54 | assert(!g_authed); 55 | 56 | tasks_processor::start(); 57 | assert(g_authed); 58 | } 59 | -------------------------------------------------------------------------------- /Chapter06/05_tasks_processor_multithread/05_tasks_processor_multithread.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | HEADERS += \ 6 | ../01_tasks_processor_base/tasks_processor_base.hpp \ 7 | ../02_tasks_processor_timers/tasks_processor_timers.hpp \ 8 | ../03_tasks_processor_network_client/tasks_processor_network_client.hpp \ 9 | ../04_tasks_processor_network_accept/tasks_processor_network_accept.hpp \ 10 | tasks_processor_multithread.hpp 11 | 12 | 13 | SOURCES += main.cpp 14 | QMAKE_CXXFLAGS += $$CPP11FLAG 15 | !msvc { 16 | LIBS += -lboost_system -lboost_thread 17 | win32:LIBS += -lws2_32 -lwsock32 18 | } 19 | -------------------------------------------------------------------------------- /Chapter06/05_tasks_processor_multithread/main.cpp: -------------------------------------------------------------------------------- 1 | // See this header some code of this recipe 2 | #include "tasks_processor_multithread.hpp" 3 | using namespace tp_multithread; 4 | 5 | const std::size_t threads_count = 5; 6 | #include 7 | boost::barrier g_barrier(threads_count); 8 | 9 | void multythread_test() { 10 | g_barrier.wait(); 11 | tasks_processor::stop(); 12 | } 13 | 14 | int main() { 15 | for (std::size_t i = 0; i < threads_count; ++i) { 16 | tasks_processor::push_task(&multythread_test); 17 | } 18 | tasks_processor::start_multiple(threads_count); 19 | 20 | tasks_processor::start_multiple(); 21 | tasks_processor::stop(); 22 | } 23 | -------------------------------------------------------------------------------- /Chapter06/05_tasks_processor_multithread/tasks_processor_multithread.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOK_CHAPTER6_TASK_PROCESSOR_MULTITHREAD_HPP 2 | #define BOOK_CHAPTER6_TASK_PROCESSOR_MULTITHREAD_HPP 3 | 4 | #include "../04_tasks_processor_network_accept/tasks_processor_network_accept.hpp" 5 | 6 | #include 7 | 8 | namespace tp_multithread { 9 | 10 | class tasks_processor: public tp_network::tasks_processor { 11 | public: 12 | // Default value will attempt to guess optimal count of threads. 13 | static void start_multiple(std::size_t threads_count = 0) { 14 | if (!threads_count) { 15 | threads_count = (std::max)(static_cast( 16 | boost::thread::hardware_concurrency()), 1 17 | ); 18 | } 19 | 20 | // First thread is the current thread. 21 | -- threads_count; 22 | 23 | boost::thread_group tg; 24 | for (std::size_t i = 0; i < threads_count; ++i) { 25 | tg.create_thread([]() { get_ios().run(); }); 26 | } 27 | 28 | get_ios().run(); 29 | tg.join_all(); 30 | } 31 | }; 32 | 33 | } // namespace tp_multithread 34 | 35 | #endif // BOOK_CHAPTER6_TASK_PROCESSOR_MULTITHREAD_HPP 36 | -------------------------------------------------------------------------------- /Chapter06/06_conveyor/06_conveyor.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | !msvc { 8 | LIBS += -lboost_system -lboost_thread 9 | win32:LIBS += -lws2_32 10 | } 11 | -------------------------------------------------------------------------------- /Chapter06/07_nonblocking_barrier/07_nonblocking_barrier.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | !msvc { 8 | LIBS += -lboost_system -lboost_thread 9 | win32:LIBS += -lws2_32 10 | } 11 | -------------------------------------------------------------------------------- /Chapter06/08_exception_ptr/08_exception_ptr.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | HEADERS += ../01_tasks_processor_base/tasks_processor_base.hpp 6 | SOURCES += main.cpp 7 | !msvc { 8 | LIBS += -lboost_system -lboost_thread 9 | win32:LIBS += -lws2_32 10 | } 11 | -------------------------------------------------------------------------------- /Chapter06/08_exception_ptr/main.cpp: -------------------------------------------------------------------------------- 1 | #include "../01_tasks_processor_base/tasks_processor_base.hpp" 2 | using namespace tp_base; 3 | 4 | #include 5 | 6 | struct process_exception { 7 | boost::exception_ptr exc_; 8 | 9 | explicit process_exception(const boost::exception_ptr& exc) 10 | : exc_(exc) 11 | {} 12 | 13 | void operator()() const; 14 | }; 15 | 16 | #include 17 | void func_test2(); // Forward declaration. 18 | 19 | void process_exception::operator()() const { 20 | try { 21 | boost::rethrow_exception(exc_); 22 | } catch (const boost::bad_lexical_cast& /*e*/) { 23 | std::cout << "Lexical cast exception detected.\n" << std::endl; 24 | 25 | // Pushing another task to execute. 26 | tasks_processor::push_task(&func_test2); 27 | } catch (...) { 28 | std::cout << "Can not handle such exceptions:\n" 29 | << boost::current_exception_diagnostic_information() 30 | << std::endl; 31 | 32 | // Stopping. 33 | tasks_processor::stop(); 34 | } 35 | } 36 | 37 | #include 38 | void func_test1() { 39 | try { 40 | boost::lexical_cast("oops!"); 41 | } catch (...) { 42 | tasks_processor::push_task( 43 | process_exception(boost::current_exception()) 44 | ); 45 | } 46 | } 47 | 48 | void func_test2() { 49 | try { 50 | // ... 51 | BOOST_THROW_EXCEPTION(std::logic_error("Some fatal logic error")); 52 | // ... 53 | } catch (...) { 54 | tasks_processor::push_task( 55 | process_exception(boost::current_exception()) 56 | ); 57 | } 58 | } 59 | 60 | void run_throw(boost::exception_ptr& ptr) { 61 | try { 62 | // A lot of code goes here. 63 | } catch (...) { 64 | ptr = boost::current_exception(); 65 | } 66 | } 67 | 68 | int main () { 69 | tasks_processor::push_task(&func_test1); 70 | tasks_processor::start(); 71 | 72 | 73 | boost::exception_ptr ptr; 74 | 75 | // Do some work in parallel. 76 | boost::thread t( 77 | &run_throw, 78 | boost::ref(ptr) 79 | ); 80 | 81 | // Some code goes here. 82 | // ... 83 | 84 | t.join(); 85 | 86 | // Checking for exception. 87 | if (ptr) { 88 | // Exception occurred in thread. 89 | boost::rethrow_exception(ptr); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Chapter06/09_tasks_processor_signals/09_tasks_processor_signals.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | HEADERS += \ 6 | ../01_tasks_processor_base/tasks_processor_base.hpp \ 7 | ../02_tasks_processor_timers/tasks_processor_timers.hpp \ 8 | ../03_tasks_processor_network/tasks_processor_network.hpp \ 9 | ../05_tasks_processor_multithread/tasks_processor_multithread.hpp \ 10 | tasks_processor_signals.hpp 11 | 12 | SOURCES += main.cpp 13 | QMAKE_CXXFLAGS += $$CPP11FLAG 14 | !msvc { 15 | LIBS += -lboost_system -lboost_thread 16 | win32:LIBS += -lws2_32 -lwsock32 17 | } 18 | -------------------------------------------------------------------------------- /Chapter06/09_tasks_processor_signals/main.cpp: -------------------------------------------------------------------------------- 1 | // Almost all the code for this recipe 2 | // is in this header file 3 | #include "tasks_processor_signals.hpp" 4 | using namespace tp_full; 5 | 6 | void accept_3_signals_and_stop(int signal) { 7 | static int signals_count = 0; 8 | assert(signal == SIGINT); 9 | 10 | ++ signals_count; 11 | std::cout << "Captured " << signals_count << " SIGINT\n"; 12 | if (signals_count == 3) { 13 | tasks_processor::stop(); 14 | } 15 | } 16 | 17 | 18 | int main () { 19 | tasks_processor::register_signals_handler( 20 | &accept_3_signals_and_stop, 21 | { SIGINT, SIGSEGV } 22 | ); 23 | 24 | tasks_processor::start(); 25 | } 26 | -------------------------------------------------------------------------------- /Chapter06/09_tasks_processor_signals/tasks_processor_signals.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOK_CHAPTER6_TASK_PROCESSOR_SIGNALS_HPP 2 | #define BOOK_CHAPTER6_TASK_PROCESSOR_SIGNALS_HPP 3 | 4 | #include "../05_tasks_processor_multithread/tasks_processor_multithread.hpp" 5 | 6 | 7 | #include 8 | #include 9 | 10 | namespace tp_full { 11 | 12 | class tasks_processor: public tp_multithread::tasks_processor { 13 | protected: 14 | static boost::asio::signal_set& signals() { 15 | static boost::asio::signal_set signals_(get_ios()); 16 | return signals_; 17 | } 18 | 19 | static boost::function& signal_handler() { 20 | static boost::function users_signal_handler_; 21 | return users_signal_handler_; 22 | } 23 | 24 | private: 25 | static void handle_signals( 26 | const boost::system::error_code& error, 27 | int signal_number) 28 | { 29 | signals().async_wait(&tasks_processor::handle_signals); 30 | 31 | if (error) { 32 | std::cerr << "Error in signal handling: " << error << '\n'; 33 | } else { 34 | boost::function h = signal_handler(); 35 | 36 | detail::make_task_wrapped([h, signal_number]() { 37 | h(signal_number); 38 | })(); // make and run task_wrapped 39 | } 40 | 41 | } 42 | 43 | public: 44 | // This function is not thread safe! 45 | // Must be called before all the `start()` calls. 46 | // Function can be called only once. 47 | template 48 | static void register_signals_handler( 49 | const Func& f, 50 | std::initializer_list signals_to_wait) 51 | { 52 | // Making shure that this is the first call. 53 | assert(!signal_handler()); 54 | 55 | signal_handler() = f; 56 | boost::asio::signal_set& sigs = signals(); 57 | 58 | std::for_each( 59 | signals_to_wait.begin(), 60 | signals_to_wait.end(), 61 | [&sigs](int signal) { sigs.add(signal); } 62 | ); 63 | 64 | sigs.async_wait(&tasks_processor::handle_signals); 65 | } 66 | }; 67 | 68 | } // namespace tp_full 69 | 70 | #endif // BOOK_CHAPTER6_TASK_PROCESSOR_SIGNALS_HPP 71 | 72 | -------------------------------------------------------------------------------- /Chapter06/Chapter06.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | 01_tasks_processor_base \ 5 | 02_tasks_processor_timers \ 6 | 03_tasks_processor_network_client \ 7 | 04_tasks_processor_network_accept \ 8 | 05_tasks_processor_multithread \ 9 | 06_conveyor \ 10 | 07_nonblocking_barrier \ 11 | 08_exception_ptr \ 12 | 09_tasks_processor_signals 13 | 14 | 15 | -------------------------------------------------------------------------------- /Chapter06/flat/01_tasks_processor_base/01_tasks_processor_base.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | !msvc { 7 | LIBS += -lboost_system -lboost_thread 8 | win32:LIBS += -lws2_32 9 | } 10 | -------------------------------------------------------------------------------- /Chapter06/flat/02_tasks_processor_timers/02_tasks_processor_timers.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | !msvc { 8 | LIBS += -lboost_system -lboost_thread 9 | win32:LIBS += -lws2_32 10 | } 11 | -------------------------------------------------------------------------------- /Chapter06/flat/04_tasks_processor_network_accept/04_tasks_processor_network_accept.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | QMAKE_CXXFLAGS += $$CPP11FLAG 8 | !msvc { 9 | LIBS += -lboost_system -lboost_thread 10 | win32:LIBS += -lws2_32 -lwsock32 11 | } 12 | -------------------------------------------------------------------------------- /Chapter06/flat/05_tasks_processor_multithread/05_tasks_processor_multithread.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | !msvc { 8 | LIBS += -lboost_system -lboost_thread 9 | win32:LIBS += -lws2_32 -lwsock32 10 | } 11 | -------------------------------------------------------------------------------- /Chapter06/flat/07_nonblocking_barrier/07_nonblocking_barrier.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | !msvc { 8 | LIBS += -lboost_system -lboost_thread 9 | win32:LIBS += -lws2_32 10 | } 11 | -------------------------------------------------------------------------------- /Chapter06/flat/08_exception_ptr/08_exception_ptr.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | !msvc { 7 | LIBS += -lboost_system -lboost_thread 8 | win32:LIBS += -lws2_32 9 | } 10 | -------------------------------------------------------------------------------- /Chapter06/flat/09_tasks_processor_signals/09_tasks_processor_signals.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | !msvc { 8 | LIBS += -lboost_system -lboost_thread 9 | win32:LIBS += -lws2_32 -lwsock32 10 | } 11 | -------------------------------------------------------------------------------- /Chapter06/flat/Readme.md: -------------------------------------------------------------------------------- 1 | This directory contains preprocessed code from the ../Chapter06 folder: 2 | * All the headers were copyied into the main.cpp 3 | * Include guards were removed 4 | * Project files updated accordingly 5 | 6 | Files in this folder are used by online compiler (it can not deal with foreign includes). 7 | -------------------------------------------------------------------------------- /Chapter06/flat/flat.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | 01_tasks_processor_base \ 5 | 02_tasks_processor_timers \ 6 | 04_tasks_processor_network_accept \ 7 | 05_tasks_processor_multithread \ 8 | 07_nonblocking_barrier \ 9 | 08_exception_ptr \ 10 | 09_tasks_processor_signals 11 | 12 | 13 | -------------------------------------------------------------------------------- /Chapter06/flat/flatten.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import signal 4 | import subprocess 5 | import re 6 | import shutil 7 | 8 | class flattener: 9 | ''' ****************************************** Private functions ********************************************** ''' 10 | @staticmethod 11 | def _process_source(out, path): 12 | with open(path, 'r') as f: 13 | for line in f: 14 | m = re.findall(r'#include.*"(.*?)"', line) 15 | if m: 16 | d = os.path.dirname(path) 17 | flattener._process_source(out, os.path.join(d, m[0])) 18 | elif 'BOOK_' not in line: 19 | out.write(line) 20 | 21 | @staticmethod 22 | def _flat_source(path): 23 | flat_name = os.path.join( 24 | os.path.dirname(path).replace('../', ''), 25 | "main.cpp" 26 | ) 27 | try: 28 | with open(flat_name, 'w+') as out: 29 | flattener._process_source(out, path) 30 | if 'tasks_processor_network_accept' in flat_name: 31 | with open('../03_tasks_processor_network_client/client.cpp', 'r') as f: 32 | for line in f: 33 | m = re.findall(r'#include.*"(.*?)"', line) 34 | if not m and 'using namespace' not in line: 35 | out.write(line) 36 | except: 37 | pass 38 | 39 | @staticmethod 40 | def _is_source(path): 41 | return os.path.isfile(path) and '.cpp' in path and 'flat' not in path 42 | 43 | ''' ****************************************** Public functions *********************************************** ''' 44 | @staticmethod 45 | def make_flat(): 46 | print "\nStarting flattening..." 47 | 48 | for folder, _, files in os.walk('..'): 49 | if 'flat' in folder: 50 | continue 51 | 52 | for f in files: 53 | path = os.path.join(folder, f) 54 | if flattener._is_source(path): 55 | flattener._flat_source(path) 56 | 57 | print "\n*** SUCESS ***" 58 | 59 | 60 | if __name__ == "__main__": 61 | flattener.make_flat() 62 | 63 | 64 | -------------------------------------------------------------------------------- /Chapter07/01_case_conv/01_case_conv.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter07/01_case_conv/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | std::string str1 = "Thanks for reading me!"; 3 | std::string str2 = "Thanks for reading ME!"; 4 | 5 | #include 6 | 7 | const bool solution_1 = ( 8 | boost::iequals(str1, str2) 9 | ); 10 | 11 | 12 | #include 13 | #include 14 | 15 | const bool solution_2 = ( 16 | str1.size() == str2.size() && std::equal( 17 | str1.begin(), 18 | str1.end(), 19 | str2.begin(), 20 | boost::is_iequal() 21 | ) 22 | ); 23 | 24 | #include 25 | 26 | void solution_3() { 27 | std::string str1_low = boost::to_lower_copy(str1); 28 | std::string str2_low = boost::to_lower_copy(str2); 29 | assert(str1_low == str2_low); 30 | } 31 | 32 | #include 33 | 34 | void solution_4() { 35 | std::string str1_up = boost::to_upper_copy(str1); 36 | std::string str2_up = boost::to_upper_copy(str2); 37 | assert(str1_up == str2_up); 38 | } 39 | 40 | #include 41 | 42 | void solution_5() { 43 | boost::to_lower(str1); 44 | boost::to_lower(str2); 45 | assert(str1 == str2); 46 | } 47 | 48 | int main() { 49 | assert(solution_1); 50 | assert(solution_2); 51 | solution_3(); 52 | solution_4(); 53 | solution_5(); 54 | 55 | // On some platforms std::locale::classic() works 56 | // faster than std::locale(). 57 | boost::iequals(str1, str2, std::locale::classic()); 58 | } 59 | -------------------------------------------------------------------------------- /Chapter07/02_regex_match/02_regex_match.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | !msvc:LIBS += -lboost_regex 7 | -------------------------------------------------------------------------------- /Chapter07/02_regex_match/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | std::cout 6 | << "Available regex syntaxes:\n" 7 | << "\t[0] Perl\n" 8 | << "\t[1] Perl case insensitive\n" 9 | << "\t[2] POSIX extended\n" 10 | << "\t[3] POSIX extended case insensitive\n" 11 | << "\t[4] POSIX basic\n" 12 | << "\t[5] POSIX basic case insensitive\n\n" 13 | << "Choose regex syntax: "; 14 | 15 | boost::regex::flag_type flag; 16 | switch (std::cin.get()) { 17 | case '0': flag = boost::regex::perl; 18 | break; 19 | 20 | case '1': flag = boost::regex::perl|boost::regex::icase; 21 | break; 22 | 23 | case '2': flag = boost::regex::extended; 24 | break; 25 | 26 | case '3': flag = boost::regex::extended|boost::regex::icase; 27 | break; 28 | 29 | case '4': flag = boost::regex::basic; 30 | break; 31 | 32 | case '5': flag = boost::regex::basic|boost::regex::icase; 33 | break; 34 | default: 35 | std::cout << "Incorrect number of regex syntax. Exiting... \n"; 36 | return 1; 37 | } 38 | // Disabling exceptions. 39 | flag |= boost::regex::no_except; 40 | 41 | // Restoring std::cin. 42 | std::cin.ignore(); 43 | std::cin.clear(); 44 | 45 | std::string regex, str; 46 | do { 47 | std::cout << "Input regex: "; 48 | if (!std::getline(std::cin, regex) || regex.empty()) { 49 | return 0; 50 | } 51 | 52 | // Without `boost::regex::no_except`flag this 53 | // constructor may throw. 54 | const boost::regex e(regex, flag); 55 | if (e.status()) { 56 | std::cout << "Incorrect regex pattern!\n"; 57 | continue; 58 | } 59 | 60 | std::cout << "String to match: "; 61 | while (std::getline(std::cin, str) && !str.empty()) { 62 | const bool matched = boost::regex_match(str, e); 63 | std::cout << (matched ? "MATCH\n" : "DOES NOT MATCH\n"); 64 | std::cout << "String to match: "; 65 | } // end of `while (std::getline(std::cin, str))` 66 | 67 | std::cout << '\n'; 68 | 69 | // Restoring std::cin. 70 | std::cin.ignore(); 71 | std::cin.clear(); 72 | } while (1); 73 | } // int main() 74 | 75 | -------------------------------------------------------------------------------- /Chapter07/03_regex_replace/03_regex_replace.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | !msvc:LIBS += -lboost_regex 7 | -------------------------------------------------------------------------------- /Chapter07/04_format/04_format.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter07/04_format/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | class i_hold_some_internals { 5 | int i; 6 | std::string s; 7 | char c; 8 | // ... 9 | public: 10 | i_hold_some_internals() 11 | : i(100) 12 | , s("Reader") 13 | , c('!') 14 | {} 15 | 16 | // `fmt` parameter may contain the following: 17 | // $1$ for outputting integer 'i'. 18 | // $2$ for outputting string 's'. 19 | // $3$ for outputting character 'c'. 20 | std::string to_string(const std::string& fmt) const { 21 | boost::format f(fmt); 22 | unsigned char flags = boost::io::all_error_bits; 23 | flags ^= boost::io::too_many_args_bit; 24 | f.exceptions(flags); 25 | return (f % i % s % c).str(); 26 | } 27 | }; 28 | 29 | int main() { 30 | i_hold_some_internals class_instance; 31 | 32 | std::cout << class_instance.to_string( 33 | "Hello, dear %2%! " 34 | "Did you read the book for %1% %% %3%\n" 35 | ); 36 | 37 | std::cout << class_instance.to_string( 38 | "%1% == %1% && %1%%% != %1%\n\n" 39 | ); 40 | 41 | // Outputs 'Reader'. 42 | std::cout << class_instance.to_string("%2%\n\n"); 43 | 44 | try { 45 | class_instance.to_string("%1% %2% %3% %4% %5%\n"); 46 | assert(false); 47 | } catch (const std::exception& e) { 48 | // boost::io::too_few_args exception is catched. 49 | std::cout << e.what() << '\n'; 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /Chapter07/05_string_algo/05_string_algo.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter07/05_string_algo/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | const std::string str = "Hello, hello, dear Reader."; 4 | 5 | #include 6 | void erasing_examples() { 7 | namespace ba = boost::algorithm; 8 | using std::cout; 9 | 10 | cout<<"\n erase_all_copy :" << ba::erase_all_copy(str, ","); 11 | cout<<"\n erase_first_copy:" << ba::erase_first_copy(str, ","); 12 | cout<<"\n erase_last_copy :" << ba::erase_last_copy(str, ","); 13 | cout<<"\n ierase_all_copy :" << ba::ierase_all_copy(str, "hello"); 14 | cout<<"\n ierase_nth_copy :" << ba::ierase_nth_copy(str, ",", 1); 15 | } 16 | 17 | #include 18 | void replacing_examples() { 19 | namespace ba = boost::algorithm; 20 | using std::cout; 21 | 22 | cout << "\n replace_all_copy :" 23 | << ba::replace_all_copy(str, ",", "!"); 24 | 25 | cout << "\n replace_first_copy :" 26 | << ba::replace_first_copy(str, ",", "!"); 27 | 28 | cout << "\n replace_head_copy :" 29 | << ba::replace_head_copy(str, 6, "Whaaaaaaa!"); 30 | } 31 | 32 | #include 33 | void erasing_examples_locale() { 34 | namespace ba = boost::algorithm; 35 | 36 | const std::locale loc = std::locale::classic(); 37 | 38 | const std::string r1 39 | = ba::ierase_all_copy(str, "hello", loc); 40 | 41 | const std::string r2 42 | = ba::ierase_nth_copy(str, ",", 1, loc); 43 | // ... 44 | assert(r1 == ba::ierase_all_copy(str, "hello")); 45 | assert(r2 == ba::ierase_nth_copy(str, ",", 1)); 46 | } 47 | 48 | int main() { 49 | erasing_examples(); 50 | replacing_examples(); 51 | erasing_examples_locale(); 52 | } 53 | 54 | -------------------------------------------------------------------------------- /Chapter07/06_iterator_range/06_iterator_range.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter07/06_iterator_range/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | const char str[] = 8 | "This is a long long character array." 9 | "Please split this character array to sentences!" 10 | "Do you know, that sentences are separated using period, " 11 | "exclamation mark and question mark? :-)" 12 | ; 13 | 14 | typedef boost::split_iterator split_iter_t; 15 | split_iter_t sentences = boost::make_split_iterator(str, 16 | boost::algorithm::token_finder(boost::is_any_of("?!.")) 17 | ); 18 | 19 | for (unsigned int i = 1; !sentences.eof(); ++sentences, ++i) { 20 | boost::iterator_range range = *sentences; 21 | std::cout << "Sentence #" << i << " : \t" << range << '\n'; 22 | std::cout << range.size() << " characters.\n"; 23 | std::cout 24 | << "Sentence has " 25 | << std::count(range.begin(), range.end(), ' ') 26 | << " whitespaces.\n\n"; 27 | } // end of for(...) loop 28 | } // end of main() 29 | -------------------------------------------------------------------------------- /Chapter07/07_string_view/07_string_view.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter07/07_string_view/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | std::string between_str(const std::string& input, char starts, char ends) { 5 | std::string::const_iterator pos_beg 6 | = std::find(input.begin(), input.end(), starts); 7 | if (pos_beg == input.end()) { 8 | return std::string(); 9 | } 10 | ++ pos_beg; 11 | 12 | std::string::const_iterator pos_end 13 | = std::find(pos_beg, input.end(), ends); 14 | 15 | return std::string(pos_beg, pos_end); 16 | } 17 | 18 | #include 19 | boost::string_view between( 20 | boost::string_view input, 21 | char starts, 22 | char ends) 23 | { 24 | boost::string_view::const_iterator pos_beg 25 | = std::find(input.cbegin(), input.cend(), starts); 26 | if (pos_beg == input.cend()) { 27 | return boost::string_view(); 28 | } 29 | ++ pos_beg; 30 | 31 | boost::string_view::const_iterator pos_end 32 | = std::find(pos_beg, input.cend(), ends); 33 | // ... 34 | if (pos_end == input.cend()) { 35 | return boost::string_view(pos_beg, input.end() - pos_beg); 36 | } 37 | 38 | return boost::string_view(pos_beg, pos_end - pos_beg); 39 | } 40 | 41 | #include 42 | void string_view_init_examples() { 43 | boost::string_view r0("^_^"); 44 | 45 | std::string O_O("O__O"); 46 | boost::string_view r1 = O_O; 47 | 48 | std::vector chars_vec(10, '#'); 49 | boost::string_view r2(&chars_vec.front(), chars_vec.size()); 50 | 51 | (void)r0; 52 | (void)r1; 53 | (void)r2; 54 | } 55 | 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | 63 | void string_view_algorithms_examples() { 64 | boost::string_view r("O_O"); 65 | // Finding single symbol. 66 | std::find(r.cbegin(), r.cend(), '_'); 67 | 68 | // Will print 'o_o'. 69 | boost::to_lower_copy(std::ostream_iterator(std::cout), r); 70 | std::cout << '\n'; 71 | 72 | // Will print 'O_O'. 73 | std::cout << r << '\n'; 74 | 75 | // Will print '^_^'. 76 | boost::replace_all_copy( 77 | std::ostream_iterator(std::cout), r, "O", "^" 78 | ); 79 | std::cout << '\n'; 80 | 81 | r = "100"; 82 | assert(boost::lexical_cast(r) == 100); 83 | } 84 | 85 | int main() { 86 | std::cout << between("Getting expression (between brackets)", '(', ')') << '\n'; 87 | 88 | std::string s("(expression)"); 89 | std::cout << between(s, '(', ')') << '\n'; 90 | 91 | string_view_init_examples(); 92 | string_view_algorithms_examples(); 93 | 94 | assert(between_str(s, '(', ')') == between(s, '(', ')')); 95 | assert(between_str("(expr", '(', ')') == between("(expr", '(', ')')); 96 | assert(between_str("expr)", '(', ')') == between("expr)", '(', ')')); 97 | } 98 | -------------------------------------------------------------------------------- /Chapter07/Chapter07.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | 01_case_conv \ 5 | 02_regex_match \ 6 | 03_regex_replace \ 7 | 04_format \ 8 | 05_string_algo \ 9 | 06_iterator_range \ 10 | 07_string_view 11 | -------------------------------------------------------------------------------- /Chapter08/01_vector_of_types/01_vector_of_types.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter08/02_manipulating_vector_of_types/02_manipulating_vector_of_types.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter08/03_result_of_c++11/03_result_of_c++11.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | 8 | -------------------------------------------------------------------------------- /Chapter08/03_result_of_c++11/main.cpp: -------------------------------------------------------------------------------- 1 | template 2 | auto my_function_cpp11(const T1& v1, const T2& v2) 3 | -> decltype(v1 + v2) 4 | { 5 | return v1 + v2; 6 | } 7 | 8 | #include 9 | 10 | struct s1 {}; 11 | struct s2 {}; 12 | struct s3 {}; 13 | 14 | inline s3 operator + (const s1& /*v1*/, const s2& /*v2*/) { 15 | return s3(); 16 | } 17 | 18 | inline s3 operator + (const s2& /*v1*/, const s1& /*v2*/) { 19 | return s3(); 20 | } 21 | 22 | #include 23 | namespace result_of { 24 | 25 | template 26 | struct my_function_cpp03 { 27 | typedef typename boost::common_type::type type; 28 | }; 29 | 30 | template <> 31 | struct my_function_cpp03 { 32 | typedef s3 type; 33 | }; 34 | 35 | template <> 36 | struct my_function_cpp03 { 37 | typedef s3 type; 38 | }; 39 | } // namespace result_of 40 | 41 | template 42 | typename result_of::my_function_cpp03::type 43 | my_function_cpp03(const T1& v1, const T2& v2) 44 | { 45 | return v1 + v2; 46 | } 47 | 48 | int main() { 49 | s1 v1; 50 | s2 v2; 51 | 52 | s3 res0 = my_function_cpp11(v1, v2); 53 | assert(my_function_cpp11('\0', 1) == 1); 54 | 55 | s3 res1 = my_function_cpp03(v1, v2); 56 | assert(my_function_cpp03('\0', 1) == 1); 57 | 58 | (void)res0; 59 | (void)res1; 60 | } 61 | -------------------------------------------------------------------------------- /Chapter08/04_higher_order_metafunctions/04_higher_order_metafunctions.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | 8 | -------------------------------------------------------------------------------- /Chapter08/04_higher_order_metafunctions/main.cpp: -------------------------------------------------------------------------------- 1 | typedef void(*function_t)(int); 2 | 3 | function_t higher_order_function1(); 4 | void higher_order_function2(function_t f); 5 | function_t higher_order_function3(function_t f); 6 | 7 | template 8 | struct coalesce; 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | template 15 | struct coalesce { 16 | typedef typename boost::mpl::apply::type type1; 17 | typedef typename boost::mpl::apply::type type2; 18 | 19 | typedef typename boost::mpl::if_< 20 | boost::is_same< boost::mpl::false_, type1>, 21 | type2, 22 | type1 23 | >::type type; 24 | }; 25 | 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | using boost::mpl::_1; 32 | using boost::mpl::_2; 33 | 34 | typedef coalesce< 35 | boost::mpl::true_, 36 | boost::mpl::int_<5>, 37 | boost::mpl::not_<_1>, 38 | boost::mpl::next<_1> 39 | >::type res1_t; 40 | BOOST_STATIC_ASSERT((res1_t::value == 6)); 41 | 42 | typedef coalesce< 43 | boost::mpl::false_, 44 | boost::mpl::int_<5>, 45 | boost::mpl::not_<_1>, 46 | boost::mpl::next<_1> 47 | >::type res2_t; 48 | BOOST_STATIC_ASSERT((res2_t::value)); 49 | 50 | typedef coalesce< 51 | boost::mpl::false_, 52 | boost::mpl::false_, 53 | boost::mpl::not_<_1>, 54 | boost::mpl::not_ > 55 | >::type res3_t; 56 | BOOST_STATIC_ASSERT((res3_t::value)); 57 | 58 | typedef coalesce< 59 | boost::mpl::false_, 60 | boost::mpl::true_, 61 | boost::mpl::not_<_1>, 62 | boost::mpl::not_ > 63 | >::type res4_t; 64 | BOOST_STATIC_ASSERT((res4_t::value)); 65 | 66 | 67 | 68 | #include 69 | #include 70 | int main() { 71 | // std::cerr << typeid(res2_t).name() << '\n'; 72 | } 73 | -------------------------------------------------------------------------------- /Chapter08/05_lazy/05_lazy.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter08/05_lazy/main.cpp: -------------------------------------------------------------------------------- 1 | struct fallback; 2 | 3 | template < 4 | class Func, 5 | class Param, 6 | class Cond, 7 | class Fallback = fallback> 8 | struct apply_if; 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | //#define USE_INCORRECT_APPLY_IF 15 | #ifndef USE_INCORRECT_APPLY_IF 16 | 17 | template 18 | struct apply_if { 19 | typedef typename boost::mpl::apply< 20 | Cond, Param 21 | >::type condition_t; 22 | 23 | typedef boost::mpl::apply applied_type; 24 | 25 | typedef typename boost::mpl::eval_if_c< 26 | condition_t::value, 27 | applied_type, 28 | boost::mpl::identity 29 | >::type type; 30 | }; 31 | 32 | #else // USE_INCORRECT_APPLY_IF 33 | 34 | template 35 | struct apply_if { 36 | typedef typename boost::mpl::apply< 37 | Cond, Param 38 | >::type condition_t; 39 | 40 | // Incorrect: metafunction is evaluated when `::type` called. 41 | typedef typename boost::mpl::apply::type applied_type; 42 | 43 | typedef typename boost::mpl::if_c< 44 | condition_t::value, 45 | applied_type, 46 | boost::mpl::identity 47 | >::type type; 48 | }; 49 | 50 | #endif // USE_INCORRECT_APPLY_IF 51 | 52 | #include 53 | #include 54 | #include 55 | #include 56 | 57 | using boost::mpl::_1; 58 | using boost::mpl::_2; 59 | 60 | typedef apply_if< 61 | boost::make_unsigned<_1>, 62 | int, 63 | boost::is_integral<_1> 64 | >::type res1_t; 65 | 66 | BOOST_STATIC_ASSERT(( 67 | boost::is_same::value 68 | )); 69 | 70 | 71 | // Will fail with static assertion somewhere deeply in the implementation 72 | // of boost::make_unsigned<_1> if we do not evaluate the function lazily. 73 | typedef apply_if< 74 | boost::make_unsigned<_1>, 75 | float, 76 | boost::is_integral<_1> 77 | >::type res2_t; 78 | 79 | BOOST_STATIC_ASSERT(( 80 | boost::is_same::value 81 | )); 82 | 83 | /* 84 | // eval_if_c implementation example 85 | 86 | template 87 | struct eval_if_c { 88 | typedef typename if_c::type f_; 89 | typedef typename f_::type type; // call `::type` only for one parameter 90 | }; 91 | 92 | */ 93 | 94 | int main() {} 95 | -------------------------------------------------------------------------------- /Chapter08/06_tuple_to_string/06_tuple_to_string.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter08/07_splitting_tuple/07_splitting_tuple.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter08/07_splitting_tuple/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | typename boost::fusion::result_of::remove_if< 6 | const Sequence, 7 | boost::is_arithmetic 8 | >::type get_nonarithmetics(const Sequence& seq) 9 | { 10 | return boost::fusion::remove_if< 11 | boost::is_arithmetic 12 | >(seq); 13 | } 14 | 15 | template 16 | typename boost::fusion::result_of::remove_if< 17 | const Sequence, 18 | boost::mpl::not_< boost::is_arithmetic > 19 | >::type get_arithmetics(const Sequence& seq) 20 | { 21 | return boost::fusion::remove_if< 22 | boost::mpl::not_< boost::is_arithmetic > 23 | >(seq); 24 | } 25 | 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | int main() { 32 | typedef boost::fusion::vector< 33 | int, boost::blank, boost::blank, float 34 | > tup1_t; 35 | tup1_t tup1(8, boost::blank(), boost::blank(), 0.0); 36 | 37 | boost::fusion::vector res_na 38 | = get_nonarithmetics(tup1); 39 | boost::fusion::vector res_a = get_arithmetics(tup1); 40 | assert(boost::fusion::at_c<0>(res_a) == 8); 41 | 42 | (void)res_na; 43 | } 44 | 45 | #include 46 | #include 47 | #include 48 | 49 | template 50 | struct make_nonconst: boost::mpl::transform< 51 | Sequence, 52 | boost::remove_const 53 | > {}; 54 | 55 | typedef boost::fusion::vector< 56 | const int, const boost::blank, boost::blank 57 | > type1; 58 | typedef make_nonconst::type nc_type; 59 | 60 | BOOST_STATIC_ASSERT((boost::is_same< 61 | boost::fusion::result_of::value_at_c::type, 62 | int 63 | >::value)); 64 | 65 | BOOST_STATIC_ASSERT((boost::is_same< 66 | boost::fusion::result_of::value_at_c::type, 67 | boost::blank 68 | >::value)); 69 | 70 | BOOST_STATIC_ASSERT((boost::is_same< 71 | boost::fusion::result_of::value_at_c::type, 72 | boost::blank 73 | >::value)); 74 | -------------------------------------------------------------------------------- /Chapter08/08_splitting_tuple_hana/08_splitting_tuple_hana.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter08/08_splitting_tuple_hana/main.cpp: -------------------------------------------------------------------------------- 1 | #if __cplusplus >= 201600 2 | 3 | #include 4 | 5 | #include 6 | 7 | constexpr auto is_arithmetic_ = [](const auto& v) { 8 | assert(false); 9 | auto type = boost::hana::typeid_(v); 10 | return boost::hana::traits::is_arithmetic(type); 11 | }; // is_arithmetic_ 12 | 13 | 14 | #include 15 | 16 | template 17 | auto get_nonarithmetics(const Sequence& seq) { 18 | return boost::hana::remove_if(seq, [](const auto& v) { 19 | return is_arithmetic_(v); 20 | }); 21 | } 22 | 23 | #include 24 | 25 | constexpr auto get_arithmetics = [](const auto& seq) { 26 | return boost::hana::filter(seq, is_arithmetic_); 27 | }; 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | struct foo { 35 | bool operator==(const foo&) const { return true; } 36 | bool operator!=(const foo&) const { return false; } 37 | }; 38 | 39 | int main() { 40 | const auto tup1 41 | = boost::hana::make_tuple(8, foo{}, foo{}, 0.0); 42 | 43 | const auto res_na = get_nonarithmetics(tup1); 44 | const auto res_a = get_arithmetics(tup1); 45 | 46 | using boost::hana::literals::operator ""_c; 47 | assert(res_a[0_c] == 8); 48 | 49 | const auto res_na_expected = boost::hana::make_tuple(foo(), foo()); 50 | assert(res_na == res_na_expected); 51 | } 52 | 53 | #else // #if __cplusplus >= 201600 54 | int main() {} 55 | #endif // #if __cplusplus >= 201600 56 | -------------------------------------------------------------------------------- /Chapter08/Chapter08.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | 01_vector_of_types \ 5 | 02_manipulating_vector_of_types \ 6 | 03_result_of_c++11 \ 7 | 04_higher_order_metafunctions \ 8 | 05_lazy \ 9 | 06_tuple_to_string \ 10 | 07_splitting_tuple \ 11 | 08_splitting_tuple_hana 12 | -------------------------------------------------------------------------------- /Chapter09/01_small_vector/01_small_vector.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter09/01_small_vector/main.cpp: -------------------------------------------------------------------------------- 1 | class operation {}; 2 | 3 | #include 4 | 5 | class operation; 6 | 7 | template 8 | void execute_operations(const T&); 9 | 10 | bool has_operation(); 11 | operation get_operation(); 12 | 13 | void process_transaction_1() { 14 | std::vector ops; 15 | ops.reserve(8); // TODO: Memory allocation. Not good! 16 | 17 | while (has_operation()) { 18 | ops.push_back(get_operation()); 19 | } 20 | 21 | execute_operations(ops); 22 | // ... 23 | } 24 | 25 | #include 26 | 27 | void process_transaction_2() { 28 | boost::container::small_vector ops; 29 | 30 | while (has_operation()) { 31 | ops.push_back(get_operation()); 32 | } 33 | 34 | execute_operations(ops); 35 | // ... 36 | } 37 | 38 | namespace optimal { 39 | 40 | 41 | void execute_operations( 42 | const boost::container::small_vector_base& ops 43 | ); 44 | 45 | } // namespace optimal 46 | 47 | void process_transaction_3() { 48 | boost::container::small_vector ops; 49 | 50 | while (has_operation()) { 51 | ops.push_back(get_operation()); 52 | } 53 | 54 | optimal::execute_operations(ops); 55 | // ... 56 | } 57 | 58 | 59 | int main() { 60 | process_transaction_1(); 61 | process_transaction_2(); 62 | process_transaction_3(); 63 | } 64 | 65 | 66 | template 67 | void execute_operations(const T& v) { 68 | assert(v.size() == 8); 69 | } 70 | 71 | void optimal::execute_operations(const boost::container::small_vector_base& ops) { 72 | assert(ops.size() == 8); 73 | } 74 | 75 | bool has_operation() { 76 | static int i = 0; 77 | return ++i % 9 != 0; 78 | } 79 | 80 | operation get_operation() { 81 | return operation(); 82 | } 83 | 84 | void execute_operations( 85 | const boost::container::small_vector&); 86 | 87 | void execute_operations( 88 | const boost::container::small_vector&); 89 | 90 | void execute_operations( 91 | const boost::container::small_vector&); 92 | 93 | -------------------------------------------------------------------------------- /Chapter09/02_static_vector/02_static_vector.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter09/02_static_vector/main.cpp: -------------------------------------------------------------------------------- 1 | class event {}; 2 | 3 | #include 4 | boost::container::static_vector get_events(); 5 | 6 | #include 7 | 8 | int main () { 9 | boost::container::static_vector ev = get_events(); 10 | assert(ev.size() == 5); 11 | 12 | boost::container::static_vector ints; 13 | ints.push_back(1); 14 | ints.push_back(2); 15 | try { 16 | // The following line always throws: 17 | ints.push_back(3); 18 | } catch (const std::exception& ) { 19 | // ... 20 | } 21 | } 22 | 23 | 24 | boost::container::static_vector get_events() { 25 | boost::container::static_vector ev; 26 | for (unsigned i = 0; i < 5; ++i) { 27 | ev.emplace_back(); 28 | } 29 | return ev; 30 | } 31 | 32 | /* 33 | 34 | #include 35 | std::vector get_events(); 36 | 37 | #include 38 | boost::array get_events(); 39 | 40 | #include 41 | boost::container::small_vector get_events(); 42 | 43 | */ 44 | -------------------------------------------------------------------------------- /Chapter09/03_hash/03_hash.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter09/03_hash/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | template 4 | std::size_t test_default() { 5 | // Constants 6 | const std::size_t ii_max = 200000; 7 | const std::string s( 8 | "Long long long string that " 9 | "will be used in tests to compare " 10 | "speed of equality comparisons." 11 | ); 12 | 13 | // Making some data, that will be 14 | // used in comparisons. 15 | const T data1[] = { 16 | T(s), 17 | T(s + s), 18 | T(s + ". Whooohooo"), 19 | T(std::string("")) 20 | }; 21 | 22 | const T data2[] = { 23 | T(s), 24 | T(s + s), 25 | T(s + ". Whooohooo"), 26 | T(std::string("")) 27 | }; 28 | 29 | const std::size_t data_dimensions = sizeof(data1) / sizeof(data1[0]); 30 | 31 | std::size_t matches = 0u; 32 | for (std::size_t ii = 0; ii < ii_max; ++ii) { 33 | for (std::size_t i = 0; i < data_dimensions; ++i) { 34 | for (std::size_t j = 0; j < data_dimensions; ++j) { 35 | if (data1[i] == data2[j]) { 36 | ++ matches; 37 | } 38 | } 39 | } 40 | } 41 | 42 | return matches; 43 | } 44 | 45 | 46 | 47 | 48 | #include 49 | 50 | struct string_hash_fast { 51 | typedef std::size_t comp_type; 52 | 53 | const comp_type comparison_; 54 | const std::string str_; 55 | 56 | explicit string_hash_fast(const std::string& s) 57 | : comparison_( 58 | boost::hash()(s) 59 | ) 60 | , str_(s) 61 | {} 62 | }; 63 | 64 | inline bool operator == ( 65 | const string_hash_fast& s1, const string_hash_fast& s2) 66 | { 67 | return s1.comparison_ == s2.comparison_ && s1.str_ == s2.str_; 68 | } 69 | 70 | inline bool operator != ( 71 | const string_hash_fast& s1, const string_hash_fast& s2) 72 | { 73 | return !(s1 == s2); 74 | } 75 | 76 | // Must be in the namespace of string_hash_fast class. 77 | inline std::size_t hash_value(const string_hash_fast& v) { 78 | return v.comparison_; 79 | } 80 | 81 | #include 82 | #include 83 | 84 | int main(int argc, char* argv[]) { 85 | if (argc < 2) { 86 | assert( 87 | test_default() 88 | == 89 | test_default() 90 | ); 91 | return 0; 92 | } 93 | 94 | switch (argv[1][0]) { 95 | case 'h': 96 | std::cout << "HASH matched: " 97 | << test_default(); 98 | break; 99 | 100 | case 's': 101 | std::cout << "STD matched: " 102 | << test_default(); 103 | break; 104 | 105 | default: 106 | return 2; 107 | } 108 | 109 | std::cout << '\n'; 110 | assert( 111 | boost::hash()(string_hash_fast("test")) 112 | == 113 | boost::hash()("test") 114 | ); 115 | } 116 | 117 | -------------------------------------------------------------------------------- /Chapter09/04_unordered/04_unordered.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | !msvc:LIBS += -lboost_timer -lboost_chrono -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter09/05_bimap/05_bimap.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter09/05_bimap/main.cpp: -------------------------------------------------------------------------------- 1 | void example1(); 2 | void example2(); 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | int main() { 9 | typedef boost::bimap< 10 | std::string, 11 | boost::bimaps::multiset_of 12 | > name_id_type; 13 | 14 | name_id_type name_id; 15 | 16 | // Inserting keys <-> values 17 | name_id.insert(name_id_type::value_type( 18 | "John Snow", 1 19 | )); 20 | 21 | name_id.insert(name_id_type::value_type( 22 | "Vasya Pupkin", 2 23 | )); 24 | 25 | name_id.insert(name_id_type::value_type( 26 | "Antony Polukhin", 3 27 | )); 28 | 29 | // Same person as "Antony Polukhin" 30 | name_id.insert(name_id_type::value_type( 31 | "Anton Polukhin", 3 32 | )); 33 | 34 | 35 | std::cout << "Left:\n"; 36 | 37 | typedef name_id_type::left_const_iterator left_const_iterator; 38 | const left_const_iterator lend = name_id.left.end(); 39 | 40 | for (left_const_iterator it = name_id.left.begin(); 41 | it!= lend; 42 | ++it) 43 | { 44 | std::cout << it->first << " <=> " << it->second << '\n'; 45 | } 46 | 47 | std::cout << "\nRight:\n"; 48 | 49 | typedef name_id_type::right_const_iterator right_const_iterator; 50 | const right_const_iterator rend = name_id.right.end(); 51 | 52 | for (right_const_iterator it = name_id.right.begin(); 53 | it!= rend; 54 | ++it) 55 | { 56 | std::cout << it->first << " <=> " << it->second << '\n'; 57 | } 58 | 59 | assert(name_id.left.find("John Snow")->second == 1); 60 | assert(name_id.right.find(2)->second == "Vasya Pupkin"); 61 | assert( 62 | name_id.find(name_id_type::value_type( 63 | "Anton Polukhin", 3 64 | )) != name_id.end() 65 | ); 66 | 67 | example1(); 68 | example2(); 69 | } /* end of main() */ 70 | 71 | #include 72 | typedef boost::bimap< 73 | boost::bimaps::set_of, 74 | boost::bimaps::multiset_of 75 | > name_id_type; 76 | 77 | #include 78 | void example1() { 79 | name_id_type name_id; 80 | 81 | std::map key1; // == name_id.left 82 | std::multimap key2; // == name_id.right 83 | } 84 | 85 | #include 86 | #include 87 | 88 | typedef boost::bimap< 89 | boost::bimaps::unordered_set_of, 90 | boost::bimaps::unordered_multiset_of 91 | > hash_name_id_type; 92 | 93 | void example2() { 94 | hash_name_id_type name_id; 95 | } 96 | -------------------------------------------------------------------------------- /Chapter09/06_multiindex/06_multiindex.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter09/07_slist_and_pool/07_slist_and_pool.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | !msvc:LIBS += -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter09/07_slist_and_pool/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef boost::fast_pool_allocator allocator_t; 6 | typedef boost::container::slist slist_t; 7 | 8 | void list_specific(slist_t& list, slist_t::iterator it) { 9 | typedef slist_t::iterator iterator; 10 | 11 | // Erasing element 776 12 | assert( *(++iterator(it)) == 776); 13 | assert(*it == 777); 14 | 15 | list.erase_after(it); 16 | 17 | assert(*it == 777); 18 | assert( *(++iterator(it)) == 775); 19 | 20 | list.clear(); 21 | assert(list.empty()); 22 | 23 | // Freeing memory: slist rebinds allocator_t and allocates 24 | // nodes of the slist, not just ints. 25 | 26 | boost::singleton_pool< 27 | boost::fast_pool_allocator_tag, 28 | sizeof(slist_t::stored_allocator_type::value_type) 29 | >::release_memory(); 30 | } // end of list_specific function 31 | 32 | #include 33 | typedef std::list stdlist_t; 34 | void list_specific(stdlist_t& list, stdlist_t::iterator it) { 35 | // Erasing element 776 36 | ++it; 37 | assert( *it == 776); 38 | it = list.erase(it); 39 | assert(*it == 775); 40 | } 41 | 42 | template 43 | void test_lists() { 44 | typedef ListT list_t; 45 | 46 | // Inserting 1000000 zeros. 47 | list_t list(1000000, 0); 48 | 49 | for (int i = 0; i < 1000; ++i) { 50 | list.insert(list.begin(), i); 51 | } 52 | 53 | // Searching for some value. 54 | typedef typename list_t::iterator iterator; 55 | iterator it = std::find(list.begin(), list.end(), 777); 56 | assert(it != list.end()); 57 | 58 | // Erasing some values. 59 | for (int i = 0; i < 100; ++i) { 60 | list.pop_front(); 61 | } 62 | 63 | // Iterator is still valid and points to the same value. 64 | assert(it != list.end()); 65 | assert(*it == 777); 66 | 67 | // Inserting more values 68 | for (int i = -100; i < 10; ++i) { 69 | list.insert(list.begin(), i); 70 | } 71 | 72 | // Iterator is still valid and points to the same value 73 | assert(it != list.end()); 74 | assert(*it == 777); 75 | 76 | list_specific(list, it); 77 | } 78 | 79 | void test_slist() { 80 | test_lists(); 81 | } 82 | 83 | void test_list() { 84 | test_lists >(); 85 | } 86 | 87 | #include 88 | int main(int argc, char* argv[]) { 89 | if (argc < 2) { 90 | test_slist(); 91 | test_list(); 92 | return 0; 93 | } 94 | 95 | switch(argv[1][0]) { 96 | case 's': std::cout << "slist_t: "; test_slist(); break; 97 | case 'l': std::cout << "std::list: "; test_list(); break; 98 | default: 99 | std::cout << "Use 's' for testsing slist performance " 100 | "and 'l' for testsing std::list performance."; 101 | } 102 | 103 | return 0; 104 | } 105 | -------------------------------------------------------------------------------- /Chapter09/08_flat/08_flat.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter09/08_flat/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() { 6 | boost::container::flat_set set; 7 | set.reserve(4096); 8 | 9 | for (int i = 0; i < 4000; ++i) { 10 | set.insert(i); 11 | } 12 | 13 | // 5.1 14 | assert(set.lower_bound(500) - set.lower_bound(100) == 400); 15 | 16 | // 5.2 17 | set.erase(0); 18 | 19 | // 5.3 20 | set.erase(5000); 21 | 22 | // 5.4 23 | assert(std::lower_bound(set.cbegin(), set.cend(), 900000) == set.cend()); 24 | 25 | // 5.5 26 | assert( 27 | set.lower_bound(100) + 400 28 | == 29 | set.find(500) 30 | ); 31 | } // end of main() function 32 | 33 | -------------------------------------------------------------------------------- /Chapter09/Chapter09.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | 01_small_vector \ 5 | 02_static_vector \ 6 | 03_hash \ 7 | 04_unordered \ 8 | 05_bimap \ 9 | 06_multiindex \ 10 | 07_slist_and_pool \ 11 | 08_flat 12 | 13 | -------------------------------------------------------------------------------- /Chapter10/01_predef/01_predef.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter10/01_predef/main.cpp: -------------------------------------------------------------------------------- 1 | //#include 2 | 3 | #if !defined(__clang__) \ 4 | && !defined(__ICC) \ 5 | && !defined(__INTEL_COMPILER) \ 6 | && (defined(__GNUC__) || defined(__GNUG__)) 7 | 8 | // GCC specific 9 | 10 | #endif 11 | 12 | #include 13 | 14 | #if BOOST_COMP_GNUC 15 | 16 | // GCC specific 17 | 18 | #endif 19 | 20 | 21 | #include 22 | #include 23 | 24 | #if BOOST_COMP_GNUC && BOOST_OS_LINUX && !BOOST_OS_ANDROID 25 | 26 | // Do something for non Android Linux. 27 | 28 | #endif 29 | 30 | int main() {} 31 | -------------------------------------------------------------------------------- /Chapter10/02_int128/02_int128.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter10/02_int128/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace project { 4 | 5 | #ifdef BOOST_HAS_INT128 6 | typedef boost::int128_type int_t; 7 | typedef boost::uint128_type uint_t; 8 | 9 | inline int_t mul(int_t v1, int_t v2, int_t v3) { 10 | return v1 * v2 * v3; 11 | } 12 | 13 | #else // #ifdef BOOST_HAS_INT128 14 | 15 | #ifdef BOOST_NO_LONG_LONG 16 | #error "This code requires at least int64_t support" 17 | #endif 18 | 19 | struct int_t { boost::long_long_type hi, lo; }; 20 | struct uint_t { boost::ulong_long_type hi, lo; }; 21 | 22 | inline int_t mul(int_t v1, int_t v2, int_t v3) { 23 | // Some hand written math. 24 | // ... 25 | return int_t(); 26 | } 27 | 28 | #endif // #ifdef BOOST_HAS_INT128 29 | 30 | } // namespace project 31 | 32 | int main() { 33 | using namespace project; 34 | 35 | mul(int_t(), int_t(), int_t()); 36 | return 0; 37 | } 38 | 39 | -------------------------------------------------------------------------------- /Chapter10/03_no_rtti/03_no_rtti.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | #QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter10/03_no_rtti/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | #if !defined(BOOST_NO_RTTI) \ 5 | && !defined(BOOST_NO_CXX11_HDR_TYPEINDEX) 6 | 7 | #include 8 | using std::type_index; 9 | 10 | template 11 | type_index type_id() { 12 | return typeid(T); 13 | } 14 | 15 | #else 16 | 17 | #include 18 | #include // std::basic_ostream 19 | #include 20 | 21 | struct type_index { 22 | const char* name_; 23 | 24 | explicit type_index(const char* name) 25 | : name_(name) 26 | {} 27 | 28 | const char* name() const { return name_; } 29 | }; 30 | 31 | inline bool operator == (type_index v1, type_index v2) { 32 | return !std::strcmp(v1.name_, v2.name_); 33 | } 34 | 35 | inline bool operator != (type_index v1, type_index v2) { 36 | return !(v1 == v2); 37 | } 38 | 39 | template 40 | inline std::basic_ostream& operator << (std::basic_ostream& os, const type_index& t) { 41 | return os << t.name_; 42 | } 43 | 44 | template 45 | inline type_index type_id() { 46 | return type_index(BOOST_CURRENT_FUNCTION); 47 | } 48 | 49 | #endif 50 | 51 | void test(); 52 | 53 | #include 54 | #include 55 | 56 | int main() { 57 | assert(type_id() == type_id()); 58 | assert(type_id() != type_id()); 59 | 60 | std::cout << type_id().name(); 61 | 62 | test(); 63 | } 64 | 65 | #include 66 | 67 | void test() { 68 | using boost::typeindex::type_id; 69 | 70 | assert(type_id() == type_id()); 71 | assert(type_id() != type_id()); 72 | } 73 | 74 | -------------------------------------------------------------------------------- /Chapter10/04_constexpr_c++11/04_constexpr_c++11.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter10/04_constexpr_c++11/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if !defined(BOOST_NO_CXX11_CONSTEXPR) \ 4 | && !defined(BOOST_NO_CXX11_HDR_ARRAY) 5 | 6 | template 7 | constexpr int get_size(const T& val) { 8 | return val.size() * sizeof(typename T::value_type); 9 | } 10 | 11 | template 12 | struct integral_constant { 13 | BOOST_STATIC_CONSTEXPR T value = Value; 14 | BOOST_CONSTEXPR operator T() const { 15 | return this->value; 16 | } 17 | }; 18 | 19 | char array[integral_constant()]; 20 | 21 | #else 22 | #error "This code requires C++11 constexpr and std::array" 23 | #endif 24 | 25 | 26 | #include 27 | 28 | int main() { 29 | std::array arr; 30 | static_assert(get_size(arr) == 5 * sizeof(short), ""); 31 | 32 | unsigned char data[get_size(arr)]; 33 | (void)data; 34 | } 35 | 36 | 37 | -------------------------------------------------------------------------------- /Chapter10/05_noexcept_c++11/05_noexcept_c++11.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | -------------------------------------------------------------------------------- /Chapter10/05_noexcept_c++11/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | class move_nothrow { 4 | // Some class class members go here. 5 | // ... 6 | 7 | public: 8 | move_nothrow() BOOST_NOEXCEPT; 9 | move_nothrow(move_nothrow&&) BOOST_NOEXCEPT 10 | // Members initialization goes here. 11 | // ... 12 | {} 13 | 14 | move_nothrow& operator=(move_nothrow&&) BOOST_NOEXCEPT { 15 | // Implementation goes here. 16 | // ... 17 | return *this; 18 | } 19 | 20 | move_nothrow(const move_nothrow&); 21 | move_nothrow& operator=(const move_nothrow&); 22 | }; 23 | 24 | // In header file. 25 | int foo() BOOST_NOEXCEPT; 26 | 27 | 28 | // In source file. 29 | int foo() BOOST_NOEXCEPT { 30 | return 0; 31 | } 32 | 33 | #include 34 | 35 | int main() { 36 | std::vector v(10); 37 | v.push_back(move_nothrow()); 38 | 39 | foo(); 40 | } 41 | 42 | 43 | // details: 44 | move_nothrow::move_nothrow() BOOST_NOEXCEPT {} 45 | -------------------------------------------------------------------------------- /Chapter10/06_A_my_library/06_A_my_library.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | # We are NOT building an executable 6 | TEMPLATE -= app 7 | 8 | # ... we are building a library. 9 | TEMPLATE = lib 10 | 11 | # Sources and headers of the library. 12 | SOURCES += my_library.cpp 13 | HEADERS += my_library.hpp 14 | 15 | # Making a dynamic library. 16 | DEFINES += MY_LIBRARY_LINK_DYNAMIC=1 17 | 18 | -------------------------------------------------------------------------------- /Chapter10/06_A_my_library/my_library.cpp: -------------------------------------------------------------------------------- 1 | #define MY_LIBRARY_COMPILATION 2 | #include "my_library.hpp" 3 | 4 | int MY_LIBRARY_API foo() { 5 | // Implementation goes here. 6 | // ... 7 | return 0; 8 | } 9 | 10 | int bar::meow() const { 11 | throw bar_exception(); 12 | } 13 | -------------------------------------------------------------------------------- /Chapter10/06_A_my_library/my_library.hpp: -------------------------------------------------------------------------------- 1 | #ifndef MY_LIBRARY_HPP 2 | #define MY_LIBRARY_HPP 3 | 4 | #include 5 | 6 | #if defined(MY_LIBRARY_LINK_DYNAMIC) 7 | # if defined(MY_LIBRARY_COMPILATION) 8 | # define MY_LIBRARY_API BOOST_SYMBOL_EXPORT 9 | # else 10 | # define MY_LIBRARY_API BOOST_SYMBOL_IMPORT 11 | # endif 12 | #else 13 | # define MY_LIBRARY_API 14 | #endif 15 | 16 | int MY_LIBRARY_API foo(); 17 | 18 | class MY_LIBRARY_API bar { 19 | public: 20 | /* ... */ 21 | int meow() const; 22 | }; 23 | 24 | #include 25 | 26 | struct BOOST_SYMBOL_VISIBLE bar_exception 27 | : public std::exception 28 | {}; 29 | 30 | #endif // MY_LIBRARY_HPP 31 | -------------------------------------------------------------------------------- /Chapter10/06_B_export_import/06_B_export_import.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | # There is a line in parent project: 6 | # 06_B_export_import.depends = 06_A_my_library 7 | # that forces `06_A_my_library` project 8 | # build before building this project. 9 | 10 | SOURCES += main.cpp 11 | HEADERS += ../06_A_my_library/my_library.hpp 12 | DEFINES += MY_LIBRARY_LINK_DYNAMIC 13 | 14 | msvc { 15 | QMAKE_LFLAGS += /LIBPATH:../06_A_my_library/release 16 | QMAKE_LFLAGS += /LIBPATH:../06_A_my_library/debug 17 | QMAKE_LFLAGS += /LIBPATH:release 18 | QMAKE_LFLAGS += /LIBPATH:debug 19 | QMAKE_LFLAGS += /LIBPATH:../../Chapter10/06_A_my_library/release 20 | QMAKE_LFLAGS += /LIBPATH:../../Chapter10/06_A_my_library/debug 21 | QMAKE_LFLAGS += /LIBPATH:Chapter10/06_A_my_library/release 22 | QMAKE_LFLAGS += /LIBPATH:Chapter10/06_A_my_library/debug 23 | } else { 24 | LIBS += -L../06_A_my_library 25 | LIBS += -L../06_A_my_library/release 26 | LIBS += -L../06_A_my_library/debug 27 | } 28 | 29 | LIBS += -l06_A_my_library 30 | 31 | # We compile-in the path to the library. 32 | unix|macos { 33 | QMAKE_LFLAGS+=-Wl,-rpath=../06_A_my_library/ 34 | QMAKE_LFLAGS+=-Wl,-rpath=Chapter10/06_A_my_library/ 35 | } 36 | -------------------------------------------------------------------------------- /Chapter10/06_B_export_import/main.cpp: -------------------------------------------------------------------------------- 1 | #include "../06_A_my_library/my_library.hpp" 2 | #include 3 | 4 | int main() { 5 | assert(foo() == 0); 6 | bar b; 7 | try { 8 | b.meow(); 9 | assert(false); 10 | } catch (const bar_exception&) {} 11 | } 12 | -------------------------------------------------------------------------------- /Chapter10/07_version/07_version.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter10/07_version/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | int to_int(const char* str, std::size_t length); 3 | 4 | #include 5 | #include 6 | 7 | #if (BOOST_VERSION >= 105200) 8 | 9 | int to_int(const char* str, std::size_t length) { 10 | return boost::lexical_cast(str, length); 11 | } 12 | 13 | #else 14 | 15 | int to_int(const char* str, std::size_t length) { 16 | return boost::lexical_cast( 17 | std::string(str, length) 18 | ); 19 | } 20 | 21 | #endif 22 | 23 | 24 | 25 | #include 26 | 27 | int main() { 28 | assert(to_int("10000000", 3) == 100); 29 | } 30 | -------------------------------------------------------------------------------- /Chapter10/Chapter10.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | 01_predef \ 5 | 02_int128 \ 6 | 03_no_rtti \ 7 | 04_constexpr_c++11 \ 8 | 05_noexcept_c++11 \ 9 | 06_A_my_library \ 10 | 06_B_export_import \ 11 | 07_version 12 | 13 | 06_B_export_import.depends = 06_A_my_library 14 | -------------------------------------------------------------------------------- /Chapter11/01_listing_files/01_listing_files.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | !msvc:LIBS += -lboost_system -lboost_filesystem 7 | -------------------------------------------------------------------------------- /Chapter11/01_listing_files/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | boost::filesystem::directory_iterator begin("./"); 6 | boost::filesystem::directory_iterator end; 7 | 8 | for (; begin != end; ++ begin) { 9 | /* 10 | boost::filesystem::file_status fs = 11 | boost::filesystem::status(*begin); 12 | */ 13 | 14 | boost::filesystem::file_status fs = 15 | begin->status(); 16 | 17 | switch (fs.type()) { 18 | case boost::filesystem::regular_file: 19 | std::cout << "FILE "; 20 | break; 21 | case boost::filesystem::symlink_file: 22 | std::cout << "SYMLINK "; 23 | break; 24 | case boost::filesystem::directory_file: 25 | std::cout << "DIRECTORY "; 26 | break; 27 | default: 28 | std::cout << "OTHER "; 29 | break; 30 | } 31 | 32 | if (fs.permissions() & boost::filesystem::owner_write) { 33 | std::cout << "W "; 34 | } else { 35 | std::cout << " "; 36 | } 37 | 38 | std::cout << begin->path() << '\n'; 39 | //std::cout << *begin << '\n'; 40 | } /*for*/ 41 | } /*main*/ 42 | -------------------------------------------------------------------------------- /Chapter11/02_erasing_files/02_erasing_files.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | !msvc:LIBS += -lboost_system -lboost_filesystem 7 | -------------------------------------------------------------------------------- /Chapter11/02_erasing_files/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #if defined(BOOST_MSVC) || defined(__MINGW32__) 4 | // Workarounds for https://svn.boost.org/trac10/ticket/13135 5 | // and https://github.com/boostorg/filesystem/issues/168 6 | # define NDEBUG 1 7 | #endif 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | int main() { 15 | boost::system::error_code error; 16 | 17 | boost::filesystem::create_directories("dir/subdir", error); 18 | assert(!error); 19 | 20 | std::ofstream ofs("dir/subdir/file.txt"); 21 | ofs << "Boost.Filesystem is fun!"; 22 | assert(ofs); 23 | ofs.close(); 24 | 25 | boost::filesystem::create_symlink( 26 | "dir/subdir/file.txt", "symlink", error); 27 | 28 | if (!error) { 29 | std::cerr << "Symlink created\n"; 30 | assert(boost::filesystem::exists("symlink")); 31 | } else { 32 | std::cerr << "Failed to create a symlink\n"; 33 | 34 | boost::filesystem::remove_all("dir", error); 35 | assert(!error); 36 | 37 | boost::filesystem::remove("symlink", error); 38 | assert(!error); 39 | } /*if (!error)*/ 40 | } /*main*/ 41 | -------------------------------------------------------------------------------- /Chapter11/03_A_plugin_hello/03_A_plugin_hello.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | # We are NOT building an executable 6 | TEMPLATE -= app 7 | 8 | # ... we are building a library. 9 | TEMPLATE = lib 10 | 11 | # Sources and headers of the library. 12 | SOURCES += plugin_hello.cpp 13 | -------------------------------------------------------------------------------- /Chapter11/03_A_plugin_hello/plugin_hello.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define API extern "C" BOOST_SYMBOL_EXPORT 5 | 6 | API std::string greeter(const std::string& name) { 7 | return "Good to meet you, " + name + "."; 8 | } 9 | 10 | -------------------------------------------------------------------------------- /Chapter11/03_B_plugin_do_not/03_B_plugin_do_not.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | # We are NOT building an executable 6 | TEMPLATE -= app 7 | 8 | # ... we are building a library. 9 | TEMPLATE = lib 10 | 11 | # Sources and headers of the library. 12 | SOURCES += plugin_do_not.cpp 13 | -------------------------------------------------------------------------------- /Chapter11/03_B_plugin_do_not/plugin_do_not.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define API extern "C" BOOST_SYMBOL_EXPORT 5 | 6 | API std::string greeter(const std::string& name) { 7 | return "They are fast. Faster than you can believe. " 8 | "Don't turn your back, don't look away, " 9 | "and don't blink. Good luck, " + name + "."; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /Chapter11/03_C_dll_usage/03_C_dll_usage.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | !msvc:LIBS += -lboost_system -lboost_filesystem 8 | unix:LIBS += -ldl 9 | -------------------------------------------------------------------------------- /Chapter11/03_C_dll_usage/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | int main(int argc, char* argv[]) { 7 | assert(argc == 2); 8 | boost::filesystem::path plugin_path = argv[1]; 9 | 10 | boost::dll::shared_library plugin( 11 | plugin_path, 12 | boost::dll::load_mode::append_decorations 13 | ); 14 | 15 | auto greeter = plugin.get("greeter"); 16 | std::cout << greeter("Sally Sparrow"); 17 | } 18 | -------------------------------------------------------------------------------- /Chapter11/04_stacktrace/04_stacktrace.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | #DEFINES += BOOST_STACKTRACE_USE_BACKTRACE=1 8 | 9 | unix { 10 | !msvc:LIBS += -ldl -lbacktrace 11 | } 12 | -------------------------------------------------------------------------------- /Chapter11/04_stacktrace/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void report_bankruptcy() { 5 | std::cout << "Sorry, you're bankrupt!\n"; 6 | std::cout << "Here's how it happened:\n" << boost::stacktrace::stacktrace(); 7 | std::exit(0); 8 | } 9 | 10 | BOOST_NOINLINE void start_trading(int money); 11 | 12 | int main() { 13 | int money = 1000; 14 | start_trading(money); 15 | } 16 | 17 | // details: 18 | 19 | // Note: BOOST_NOINLINE and BOOST_FORCEINLINE are used for a more nice output. 20 | // Do not use them in production code without super extremely high need. 21 | 22 | // 99% precise HFT simulator: 23 | 24 | BOOST_NOINLINE void make_a_bet(int money); 25 | BOOST_FORCEINLINE int party(int money); 26 | BOOST_NOINLINE void win(int money); 27 | 28 | 29 | 30 | BOOST_NOINLINE void loose(int money) { 31 | if (money < 10) { 32 | report_bankruptcy(); 33 | } 34 | make_a_bet(money); 35 | } 36 | 37 | BOOST_NOINLINE int go_to_casino(int money) { 38 | static bool i = true; 39 | if (i) { 40 | // First time in casin0 :) 41 | i = false; 42 | win(money * 2); 43 | } 44 | money *= 0.00000003; // Lucky day in a casino! Not all the money are lost. 45 | loose(money); 46 | return party(money); 47 | } 48 | 49 | BOOST_NOINLINE int go_to_bar(int money) { 50 | money -= 11; // 1 beer please ... 51 | money -= 11 * 20; // ... and 1 beer to everyone in the room! 52 | return party(money); 53 | } 54 | 55 | BOOST_FORCEINLINE int party(int money) { 56 | if (money > 0) { 57 | return money & 1 ? go_to_casino(money) : go_to_bar(money); 58 | } 59 | 60 | report_bankruptcy(); 61 | return 0; 62 | } 63 | 64 | BOOST_NOINLINE void win(int money) { 65 | money = party(money); 66 | make_a_bet(money); 67 | } 68 | 69 | BOOST_NOINLINE void make_a_bet(int money) { 70 | static int i = 3; 71 | -- i; 72 | if (!i) { 73 | i = 3; 74 | win(money * 100500); 75 | } else { 76 | loose(money * 0.9); 77 | } 78 | } 79 | 80 | BOOST_NOINLINE void start_trading(int money) { 81 | make_a_bet(money); 82 | } 83 | -------------------------------------------------------------------------------- /Chapter11/05_interprocess_basics/05_interprocess_basics.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | # If unix like OS => link with 'rt' library 8 | unix { 9 | !msvc:LIBS += -lrt 10 | } 11 | -------------------------------------------------------------------------------- /Chapter11/05_interprocess_basics/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | typedef boost::atomic atomic_t; 6 | #if (BOOST_ATOMIC_INT_LOCK_FREE != 2) 7 | #error "This code requires lock-free boost::atomic" 8 | #endif 9 | 10 | //#include 11 | //typedef std::atomic atomic_t; 12 | 13 | 14 | 15 | int main() { 16 | boost::interprocess::managed_shared_memory 17 | segment(boost::interprocess::open_or_create, "shm1-cache", 1024); 18 | 19 | atomic_t& atomic 20 | = *segment.find_or_construct // 1 21 | ("shm1-counter") // 2 22 | (0) // 3 23 | ; 24 | 25 | std::cout << "I have index " << ++ atomic 26 | << ". Press any key...\n"; 27 | std::cin.get(); 28 | 29 | const int snapshot = --atomic; 30 | if (!snapshot) { 31 | segment.destroy("shm1-counter"); 32 | boost::interprocess::shared_memory_object 33 | ::remove("shm1-cache"); 34 | } 35 | } /*main*/ 36 | -------------------------------------------------------------------------------- /Chapter11/06_interprocess_queue/06_interprocess_queue.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | # If unix like OS => link with 'rt' library 8 | unix { 9 | !msvc:LIBS += -lrt 10 | } 11 | -------------------------------------------------------------------------------- /Chapter11/07_interprocess_pointers/07_interprocess_pointers.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | # If unix like OS => link with 'rt' library 8 | unix { 9 | !msvc:LIBS += -lrt 10 | } 11 | -------------------------------------------------------------------------------- /Chapter11/07_interprocess_pointers/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct with_pointer { 4 | int* pointer_; 5 | // ... 6 | int value_holder_; 7 | }; 8 | 9 | 10 | #include 11 | 12 | struct correct_struct { 13 | boost::interprocess::offset_ptr pointer_; 14 | // ... 15 | int value_holder_; 16 | }; 17 | 18 | 19 | #include 20 | 21 | template 22 | void test() { 23 | typedef T correct_struct; 24 | static const int ethalon_value = 777; 25 | 26 | boost::interprocess::managed_shared_memory 27 | segment(boost::interprocess::open_or_create, "segment", 4096); 28 | 29 | correct_struct* ptr = 30 | segment.find("structure").first; 31 | 32 | if (ptr) { 33 | std::cout << "Structure found\n"; 34 | assert(*ptr->pointer_ == ethalon_value); 35 | segment.destroy("structure"); 36 | } else { 37 | std::cout << "Creating structure\n"; 38 | correct_struct& ref = *segment.construct("structure")(); 39 | ref.pointer_ = &ref.value_holder_; 40 | assert(ref.pointer_ == &ref.value_holder_); 41 | assert(*ref.pointer_ == ref.value_holder_); 42 | ref.value_holder_ = ethalon_value; 43 | assert(*ref.pointer_ == ethalon_value); 44 | } 45 | } 46 | 47 | 48 | #include 49 | 50 | int main() { 51 | test(); // Shall be OK 52 | //test(); // Shall fail 53 | } 54 | -------------------------------------------------------------------------------- /Chapter11/08_reading_files/08_reading_files.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter11/08_reading_files/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int main(int argc, char* argv[]) { 11 | static const std::size_t filesize = 1024 * 1024 /** 128*/; 12 | const char filename[] = "test_file.txt"; 13 | 14 | assert(argc >= 2); // Run with c,m,r or a parameter: ./this_program c 15 | switch (argv[1][0]) { 16 | case 'c': { 17 | // Not effective, but this is not a place that we measure 18 | std::ofstream f(filename, std::ofstream::binary); 19 | std::fill_n( 20 | std::ostream_iterator(f), 21 | filesize - 1, 22 | '\3' 23 | ); 24 | 25 | f << '\1'; 26 | } 27 | break; 28 | 29 | case 'm': { 30 | std::cout << "mapped_region:"; 31 | const boost::interprocess::mode_t mode = boost::interprocess::read_only; 32 | boost::interprocess::file_mapping fm(filename, mode); 33 | boost::interprocess::mapped_region region(fm, mode, 0, 0); 34 | //region.advise(boost::interprocess::mapped_region::advice_sequential); 35 | 36 | const char* begin = static_cast( 37 | region.get_address() 38 | ); 39 | const char* pos = std::find( 40 | begin, begin + region.get_size(), '\1' 41 | ); 42 | assert(pos == begin + filesize - 1); 43 | assert(region.get_size() == filesize); 44 | } 45 | break; 46 | 47 | case 'r': { 48 | std::cout << "ifstream:"; 49 | static const std::size_t kilobyte = 1024; 50 | std::ifstream f(filename, std::ifstream::binary); 51 | char c[kilobyte]; 52 | char* begin = c; 53 | char* end = c + sizeof(c); 54 | char* pos; 55 | 56 | size_t i = 0; 57 | for (; i < filesize / kilobyte; ++i) { 58 | f.read(c, kilobyte); 59 | pos = std::find(begin, end, '\1'); 60 | if (pos != end) { 61 | break; 62 | } 63 | } 64 | 65 | assert(pos - begin == kilobyte - 1); 66 | assert(i == filesize / kilobyte - 1); 67 | } 68 | break; 69 | 70 | case 'a': { 71 | std::cout << "C:"; 72 | static const std::size_t kilobyte = 1024; 73 | FILE* f = fopen(filename, "rb"); 74 | char c[kilobyte]; 75 | char* begin = c; 76 | char* end = c + sizeof(c); 77 | char* pos; 78 | 79 | size_t i = 0; 80 | for (; i < filesize / kilobyte; ++i) { 81 | std::size_t res = fread(c, 1, kilobyte, f); 82 | pos = std::find(begin, end, '\1'); 83 | if (pos != end) { 84 | break; 85 | } 86 | (void)res; 87 | } 88 | 89 | assert(pos - begin == kilobyte - 1); 90 | assert(i == filesize / kilobyte - 1); 91 | fclose (f); 92 | } 93 | break; 94 | 95 | default: 96 | return 42; 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Chapter11/09_coroutines/09_coroutines.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP11FLAG 7 | 8 | !msvc:LIBS += -lboost_thread -lboost_system -lboost_context 9 | -------------------------------------------------------------------------------- /Chapter11/09_coroutines/main.cpp: -------------------------------------------------------------------------------- 1 | struct spinlock_t { 2 | bool try_lock(); 3 | }; 4 | 5 | struct port_t { 6 | bool block_ready(); 7 | }; 8 | 9 | template bool copy_to_buffer(T& /*value*/); 10 | template void process(T& /*value*/); 11 | 12 | #include 13 | 14 | #include 15 | typedef boost::coroutines2::asymmetric_coroutine corout_t; 16 | 17 | struct coroutine_task { 18 | std::string& result; 19 | 20 | coroutine_task(std::string& r) 21 | : result(r) 22 | {} 23 | 24 | void operator()(corout_t::pull_type& yield); 25 | 26 | private: 27 | std::size_t ticks_to_work; 28 | void tick(corout_t::pull_type& yield); 29 | }; 30 | 31 | 32 | void coroutine_task::operator()(corout_t::pull_type& yield) { 33 | ticks_to_work = yield.get(); 34 | 35 | // Prepare buffers. 36 | std::string buffer0; 37 | 38 | while (1) { 39 | const bool requiers_1_more_copy = copy_to_buffer(buffer0); 40 | tick(yield); 41 | 42 | if (requiers_1_more_copy) { 43 | std::string buffer1; 44 | 45 | copy_to_buffer(buffer1); 46 | tick(yield); 47 | 48 | process(buffer1); 49 | tick(yield); 50 | } 51 | 52 | process(buffer0); 53 | tick(yield); 54 | } 55 | } 56 | 57 | void coroutine_task::tick(corout_t::pull_type& yield) { 58 | result += 'o'; 59 | 60 | if (ticks_to_work != 0) { 61 | --ticks_to_work; 62 | } 63 | 64 | if (ticks_to_work == 0) { 65 | // Switching back to main. 66 | yield(); 67 | 68 | ticks_to_work = yield.get(); 69 | } 70 | } 71 | 72 | int main() { 73 | std::string result; 74 | coroutine_task task(result); 75 | corout_t::push_type coroutine(task); 76 | 77 | // Doing some work. 78 | // ... 79 | spinlock_t spinlock; 80 | port_t port; 81 | 82 | while (!spinlock.try_lock()) { 83 | // We may do some useful work, before 84 | // attempting to lock a spinlock once more. 85 | coroutine(10); // 10 is the ticks count to run. 86 | } 87 | // Spinlock is locked. 88 | // ... 89 | assert(result.size() == 10 * 100); 90 | result.clear(); 91 | 92 | while (!port.block_ready()) { 93 | // We may do some useful work, before 94 | // attempting to get block of data once more. 95 | coroutine(300); // 300 is the ticks count to run. 96 | 97 | // Do something with `result` variable. 98 | } 99 | 100 | assert(result.size() == 10 * 300); 101 | std::cout << "OK\n"; 102 | } 103 | 104 | // details: 105 | 106 | template bool copy_to_buffer(T& /*value*/) { 107 | static std::size_t i = 0; 108 | ++ i; 109 | return i & 1; 110 | } 111 | 112 | template void process(T& /*value*/) {} 113 | 114 | bool spinlock_t::try_lock() { 115 | static int i = 0; 116 | return i++ >= 100; 117 | } 118 | 119 | bool port_t::block_ready() { 120 | static int i = 0; 121 | return i++ >= 10; 122 | } 123 | 124 | -------------------------------------------------------------------------------- /Chapter11/Chapter11.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | 01_listing_files \ 5 | 02_erasing_files \ 6 | 03_A_plugin_hello \ 7 | 03_B_plugin_do_not \ 8 | 03_C_dll_usage \ 9 | 04_stacktrace \ 10 | 05_interprocess_basics \ 11 | 06_interprocess_queue \ 12 | 07_interprocess_pointers \ 13 | 08_reading_files 14 | 15 | # Some strange link errors on come MinGW implementations: 16 | # 17 | # Cannot export _jump_fcontext: symbol not found 18 | # Cannot export _make_fcontext: symbol not found 19 | # Cannot export _ontop_fcontext: symbol not found 20 | # collect2.exe: error: ld returned 1 exit status 21 | !win32-g++ { 22 | SUBDIRS += 09_coroutines 23 | } 24 | 25 | 26 | 03_C_dll_usage.depends = \ 27 | 03_A_plugin_hello \ 28 | 03_B_plugin_do_not 29 | 30 | -------------------------------------------------------------------------------- /Chapter12/01_graph/01_graph.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter12/01_graph/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | typedef std::string vertex_t; 4 | 5 | typedef boost::adjacency_list< 6 | boost::vecS 7 | , boost::vecS 8 | , boost::bidirectionalS 9 | , vertex_t 10 | > graph_type; 11 | 12 | #include 13 | #include 14 | 15 | inline void find_and_print( 16 | const graph_type& graph, boost::string_ref name) 17 | { 18 | typedef typename boost::graph_traits< 19 | graph_type 20 | >::vertex_iterator vert_it_t; 21 | 22 | vert_it_t it, end; 23 | boost::tie(it, end) = boost::vertices(graph); 24 | 25 | typedef typename boost::graph_traits< 26 | graph_type 27 | >::vertex_descriptor desc_t; 28 | 29 | for (; it != end; ++ it) { 30 | const desc_t desc = *it; 31 | const vertex_t& vertex = boost::get( 32 | boost::vertex_bundle, graph 33 | )[desc]; 34 | 35 | if (vertex == name.data()) { 36 | break; 37 | } 38 | } 39 | 40 | assert(it != end); 41 | std::cout << name << '\n'; 42 | } /* find_and_print */ 43 | 44 | int main() { 45 | graph_type graph; 46 | 47 | static const std::size_t vertex_count = 5; 48 | graph.m_vertices.reserve(vertex_count); 49 | /* 50 | C++ -> STL -> Boost -> C++ guru <- C 51 | */ 52 | 53 | typedef boost::graph_traits< 54 | graph_type 55 | >::vertex_descriptor descriptor_t; 56 | 57 | descriptor_t cpp 58 | = boost::add_vertex(vertex_t("C++"), graph); 59 | descriptor_t stl 60 | = boost::add_vertex(vertex_t("STL"), graph); 61 | descriptor_t boost 62 | = boost::add_vertex(vertex_t("Boost"), graph); 63 | descriptor_t guru 64 | = boost::add_vertex(vertex_t("C++ guru"), graph); 65 | descriptor_t ansic 66 | = boost::add_vertex(vertex_t("C"), graph); 67 | 68 | BOOST_STATIC_ASSERT((boost::is_same::value)); 69 | 70 | boost::add_edge(cpp, stl, graph); 71 | boost::add_edge(stl, boost, graph); 72 | boost::add_edge(boost, guru, graph); 73 | boost::add_edge(ansic, guru, graph); 74 | 75 | 76 | find_and_print(graph, "Boost"); 77 | find_and_print(graph, "C++ guru"); 78 | } // end of main 79 | 80 | -------------------------------------------------------------------------------- /Chapter12/02_graph_vis/02_graph_vis.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | 7 | -------------------------------------------------------------------------------- /Chapter12/02_graph_vis/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | typedef std::string vertex_t; 4 | 5 | typedef boost::adjacency_list< 6 | boost::vecS 7 | , boost::vecS 8 | , boost::bidirectionalS 9 | , vertex_t 10 | > graph_type; 11 | 12 | #include 13 | 14 | namespace detail { 15 | template 16 | class vertex_writer { 17 | const GraphT& g_; 18 | 19 | public: 20 | explicit vertex_writer(const GraphT& g) 21 | : g_(g) 22 | {} 23 | 24 | template 25 | void operator()( 26 | std::ostream& out, 27 | const VertexDescriptorT& d) const 28 | { 29 | out << " [label=\"" 30 | << boost::get(boost::vertex_bundle, g_)[d] 31 | << "\"]"; 32 | } 33 | }; // vertex_writer 34 | } // namespace detail 35 | 36 | #include 37 | 38 | std::ostream& operator<<(std::ostream& out, const graph_type& g) { 39 | detail::vertex_writer vw(g); 40 | boost::write_graphviz(out, g, vw); 41 | 42 | return out; 43 | } 44 | 45 | 46 | 47 | int main() { 48 | graph_type graph; 49 | 50 | static const std::size_t vertex_count = 5; 51 | graph.m_vertices.reserve(vertex_count); 52 | /* 53 | C++ -> STL -> Boost -> C++ guru <- C 54 | */ 55 | 56 | typedef boost::graph_traits::vertex_descriptor descriptor_t; 57 | descriptor_t cpp 58 | = boost::add_vertex(vertex_t("C++"), graph); 59 | descriptor_t stl 60 | = boost::add_vertex(vertex_t("STL"), graph); 61 | descriptor_t boost 62 | = boost::add_vertex(vertex_t("Boost"), graph); 63 | descriptor_t guru 64 | = boost::add_vertex(vertex_t("C++ guru"), graph); 65 | descriptor_t ansic 66 | = boost::add_vertex(vertex_t("C"), graph); 67 | 68 | BOOST_STATIC_ASSERT((boost::is_same::value)); 69 | 70 | boost::add_edge(cpp, stl, graph); 71 | boost::add_edge(stl, boost, graph); 72 | boost::add_edge(boost, guru, graph); 73 | boost::add_edge(ansic, guru, graph); 74 | 75 | std::cout << graph; 76 | } 77 | -------------------------------------------------------------------------------- /Chapter12/03_random/03_random.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | !msvc:LIBS += -lboost_random -lboost_system 7 | -------------------------------------------------------------------------------- /Chapter12/03_random/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() { 7 | static const std::string provider = 8 | #ifdef BOOST_WINDOWS 9 | "Microsoft Strong Cryptographic Provider" 10 | #else 11 | "/dev/urandom" 12 | #endif 13 | ; 14 | 15 | boost::random_device device(provider); 16 | boost::random::uniform_int_distribution random(1000); 17 | 18 | for (unsigned int i = 0; i < 100; ++i) { 19 | std::cerr << random(device) << '\t'; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Chapter12/04_math/04_math.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | -------------------------------------------------------------------------------- /Chapter12/04_math/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | void check_float_inputs(T value) { 6 | assert(!boost::math::isinf(value)); 7 | assert(!boost::math::isnan(value)); 8 | 9 | if (boost::math::signbit(value)) { 10 | value = boost::math::changesign(value); 11 | } 12 | 13 | // ... 14 | assert(value + (std::numeric_limits::epsilon)() >= static_cast(0)); 15 | } // check_float_inputs 16 | 17 | int main() { 18 | check_float_inputs(0.0); 19 | check_float_inputs(-110.0f); 20 | check_float_inputs(-11.0l); 21 | 22 | // Shall fail the `!boost::math::isinf(value)` assertion 23 | //check_float_inputs((std::numeric_limits::max)() * 2.0); 24 | 25 | 26 | // Shall fail the `!boost::math::isnan(value)` assertion 27 | //check_float_inputs(std::sqrt(-1.0)); 28 | } 29 | -------------------------------------------------------------------------------- /Chapter12/05_testing/05_testing.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | unix:DEFINES += BOOST_TEST_DYN_LINK=1 6 | SOURCES += main.cpp 7 | 8 | !msvc:LIBS += -lboost_unit_test_framework -lboost_system 9 | -------------------------------------------------------------------------------- /Chapter12/05_testing/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | struct foo { 3 | int val_; 4 | 5 | operator int() const; 6 | bool is_not_null() const; 7 | void throws() const; // throws(std::logic_error) 8 | }; 9 | 10 | 11 | 12 | #define BOOST_TEST_MODULE test_module_name 13 | #include 14 | 15 | BOOST_AUTO_TEST_CASE(test_no_1) { 16 | foo f1 = {1}, f2 = {2}; 17 | BOOST_CHECK(f1.is_not_null()); 18 | 19 | BOOST_CHECK_NE(f1, f2); 20 | 21 | BOOST_CHECK_THROW(f1.throws(), std::logic_error); 22 | } // BOOST_AUTO_TEST_CASE(test_no_1) 23 | 24 | BOOST_AUTO_TEST_CASE(test_no_2) { 25 | foo f1 = {1}, f2 = {2}; 26 | BOOST_REQUIRE_NE(f1, f2); 27 | // ... 28 | } // BOOST_AUTO_TEST_CASE(test_no_2) 29 | 30 | #define DO_NOT_FAIL 31 | #ifdef DO_NOT_FAIL 32 | foo::operator int() const { 33 | return val_; 34 | } 35 | 36 | bool foo::is_not_null() const { 37 | return !!val_; 38 | } 39 | 40 | void foo::throws() const { 41 | throw std::logic_error("Expected exception"); 42 | } 43 | 44 | #else 45 | 46 | foo::operator int() const { 47 | return 0; 48 | } 49 | 50 | bool foo::is_not_null() const { 51 | return !val_; 52 | } 53 | 54 | void foo::throws() const {} 55 | 56 | #endif // DO_NOT_FAIL 57 | -------------------------------------------------------------------------------- /Chapter12/06_testing_advanced/06_testing_advanced.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | unix:DEFINES += BOOST_TEST_DYN_LINK=1 6 | 7 | SOURCES += main.cpp foo.cpp developer1.cpp developer2.cpp 8 | HEADERS += foo.hpp 9 | 10 | !msvc:LIBS += -lboost_unit_test_framework -lboost_system 11 | -------------------------------------------------------------------------------- /Chapter12/06_testing_advanced/developer1.cpp: -------------------------------------------------------------------------------- 1 | // developer1.cpp 2 | #include 3 | #include "foo.hpp" 4 | 5 | BOOST_AUTO_TEST_CASE(test_no_1) { 6 | // ... 7 | foo f1 = {1}, f2 = {2}; 8 | BOOST_CHECK(f1.is_not_null()); 9 | 10 | BOOST_CHECK_NE(f1, f2); 11 | 12 | BOOST_CHECK_THROW(f1.throws(), std::logic_error); 13 | } // BOOST_AUTO_TEST_CASE(test_no_1) 14 | -------------------------------------------------------------------------------- /Chapter12/06_testing_advanced/developer2.cpp: -------------------------------------------------------------------------------- 1 | // developer2.cpp 2 | #include 3 | #include "foo.hpp" 4 | 5 | BOOST_AUTO_TEST_CASE(test_no_2) { 6 | // ... 7 | foo f1 = {1}, f2 = {2}; 8 | BOOST_REQUIRE_NE(f1, f2); 9 | // ... 10 | } // BOOST_AUTO_TEST_CASE(test_no_2) 11 | -------------------------------------------------------------------------------- /Chapter12/06_testing_advanced/foo.cpp: -------------------------------------------------------------------------------- 1 | #include "foo.hpp" 2 | 3 | #define DO_NOT_FAIL 4 | #ifdef DO_NOT_FAIL 5 | foo::operator int() const { 6 | return val_; 7 | } 8 | 9 | bool foo::is_not_null() const { 10 | return !!val_; 11 | } 12 | 13 | void foo::throws() const { 14 | throw std::logic_error("Expected exception"); 15 | } 16 | 17 | #else 18 | 19 | foo::operator int() const { 20 | return 0; 21 | } 22 | 23 | bool foo::is_not_null() const { 24 | return !val_; 25 | } 26 | 27 | void foo::throws() const {} 28 | 29 | #endif // DO_NOT_FAIL 30 | 31 | -------------------------------------------------------------------------------- /Chapter12/06_testing_advanced/foo.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BOOST_BOOK_CHAPTER12_FOO_HPP 2 | #define BOOST_BOOK_CHAPTER12_FOO_HPP 3 | 4 | #include 5 | struct foo { 6 | int val_; 7 | 8 | operator int() const; 9 | bool is_not_null() const; 10 | void throws() const; // throws(std::logic_error) 11 | }; 12 | 13 | #endif // BOOST_BOOK_CHAPTER12_FOO_HPP 14 | -------------------------------------------------------------------------------- /Chapter12/06_testing_advanced/main.cpp: -------------------------------------------------------------------------------- 1 | #define BOOST_TEST_MODULE test_module_name 2 | #include 3 | -------------------------------------------------------------------------------- /Chapter12/07_gil/07_gil.pro: -------------------------------------------------------------------------------- 1 | if (!include(../../config.txt)) { 2 | error("Failed to open config.txt") 3 | } 4 | 5 | SOURCES += main.cpp 6 | QMAKE_CXXFLAGS += $$CPP14FLAG 7 | 8 | 9 | # Those paths are used by CI scripts of the book. You may not find those libraries by that path in default Boost archive. 10 | # Just install libpng into your system and add correct include paths to the build script. 11 | INCLUDEPATH += $$BOOST_PATH/libpng/build/native/include 12 | INCLUDEPATH += $$BOOST_PATH/libpng-v142/build/native/include 13 | INCLUDEPATH += $$BOOST_PATH/zlib/build/native/include 14 | INCLUDEPATH += $$BOOST_PATH/zlib.v140.windesktop.msvcstl.dyn.rt-dyn/build/native/include 15 | INCLUDEPATH += $$BOOST_PATH/zlib_static/build/native/include 16 | msvc { 17 | QMAKE_LFLAGS += /LIBPATH:$$BOOST_PATH/libpng/build/native/lib/x64/v140/dynamic/Release/ 18 | QMAKE_LFLAGS += /LIBPATH:$$BOOST_PATH/libpng-v142/build/native/lib/x64/v142/Release/ 19 | QMAKE_LFLAGS += /LIBPATH:$$BOOST_PATH/zlib_static/build/native/lib/Win32/v142/Release/MultiThreaded 20 | LIBS += -llibpng16 21 | } else { 22 | unix { 23 | LIBS += -lpng 24 | } else { 25 | LIBS += -llibpng16 26 | QMAKE_LFLAGS += -L$$BOOST_PATH/libpng/build/native/lib/Win32/v140/dynamic/Release/ 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Chapter12/07_gil/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // MinGW workarounds for https://svn.boost.org/trac10/ticket/3908 : 4 | #ifndef png_infopp_NULL 5 | # define png_infopp_NULL NULL 6 | #endif 7 | #ifndef int_p_NULL 8 | # define int_p_NULL NULL 9 | #endif 10 | 11 | #include 12 | #if (BOOST_VERSION < 106800) 13 | # include 14 | # include 15 | #else 16 | # include 17 | # include 18 | #endif 19 | #include 20 | 21 | #include 22 | 23 | #include 24 | 25 | struct negate { 26 | typedef void result_type; // required 27 | 28 | template 29 | void operator()(const View& source) const { 30 | 31 | // Code formatting is shifted left to fit page width 32 | boost::gil::gil_function_requires< 33 | boost::gil::ImageViewConcept 34 | >(); 35 | 36 | typedef typename View::value_type value_type; 37 | typedef typename boost::gil::channel_type::type channel_t; 38 | 39 | const std::size_t channels = boost::gil::num_channels::value; 40 | const channel_t max_val = (std::numeric_limits::max)(); 41 | 42 | for (unsigned int y = 0; y < source.height(); ++y) { 43 | for (unsigned int x = 0; x < source.width(); ++x) { 44 | for (unsigned int c = 0; c < channels; ++c) { 45 | source(x, y)[c] = max_val - source(x, y)[c]; 46 | } 47 | } 48 | } 49 | 50 | 51 | } 52 | }; // negate 53 | 54 | int main(int argc, char *argv[]) { 55 | assert(argc == 2); 56 | 57 | #if (BOOST_VERSION < 107400) 58 | typedef boost::mpl::vector3< 59 | boost::gil::gray8_image_t, 60 | boost::gil::gray16_image_t, 61 | boost::gil::rgb8_image_t 62 | > img_types; 63 | boost::gil::any_image source; 64 | #else 65 | // Boost.GIL now uses variadic templates 66 | boost::gil::any_image< 67 | boost::gil::gray8_image_t, 68 | boost::gil::gray16_image_t, 69 | boost::gil::rgb8_image_t 70 | > source; 71 | #endif 72 | 73 | std::string file_name(argv[1]); 74 | boost::gil::png_read_image(file_name, source); 75 | 76 | boost::gil::apply_operation( 77 | view(source), 78 | negate() 79 | ); 80 | 81 | boost::gil::png_write_view("negate_" + file_name, const_view(source)); 82 | } 83 | -------------------------------------------------------------------------------- /Chapter12/Chapter12.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS += \ 4 | 01_graph \ 5 | 02_graph_vis \ 6 | 03_random \ 7 | 04_math \ 8 | 05_testing \ 9 | 06_testing_advanced \ 10 | 07_gil 11 | 12 | -------------------------------------------------------------------------------- /LICENSE_1_0.txt: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /config.txt: -------------------------------------------------------------------------------- 1 | # This file is used by ALL recipes and it contains ... 2 | 3 | # ... QMake specific settings that shall not be modified 4 | TEMPLATE = app 5 | CONFIG += console 6 | CONFIG -= qt 7 | CONFIG += thread 8 | 9 | # ... and a big portion of settings that reader may modify: 10 | 11 | isEmpty(BOOST_PATH) { 12 | # Path to the Boost. 13 | #BOOST_PATH = /data/boost_1_63_0/ 14 | BOOST_PATH = /data/boost/ 15 | #BOOST_PATH = /home/antoshkka/experiments/boost_1_63_0/ 16 | } 17 | 18 | # Compiler to use (comment out to use default one). 19 | #QMAKE_CXX = clang++ 20 | 21 | # Paths to boost headers and libraries 22 | # (if you are using Linux and installed Boost from repository you may comment out those lines). 23 | INCLUDEPATH += $$BOOST_PATH 24 | QMAKE_RPATHDIR += $$BOOST_PATH/stage/lib 25 | 26 | # Boost specific defines. 27 | DEFINES += BOOST_THREAD_VERSION=4 28 | DEFINES += BOOST_ASIO_DISABLE_STD_ATOMIC=1 # Workaround for GCC-4.6 issues with atomics 29 | DEFINES += BOOST_ASIO_DISABLE_HANDLER_TYPE_REQUIREMENTS=1 # Workaround for move-only functors support for ASIO 30 | 31 | # Flags to set your compiler into C++03/C++11/C++14 mode. 32 | msvc { 33 | # MSVC compilers 34 | CPP03FLAG = 35 | CPP11FLAG = 36 | CPP14FLAG = 37 | } else { 38 | # all other compilers 39 | CPP03FLAG = -std=c++03 40 | CPP11FLAG = -std=c++0x 41 | CPP14FLAG = -std=c++14 42 | } 43 | 44 | # Disabling some annoing warnings and adding paths to the Boost libraries. 45 | msvc { 46 | QMAKE_LFLAGS += /LIBPATH:$$BOOST_PATH/stage/lib 47 | DEFINES += _CRT_SECURE_NO_WARNINGS 48 | } else { 49 | LIBS += -L$$BOOST_PATH/stage/lib 50 | QMAKE_CXXFLAGS += -Wno-deprecated-declarations -Wno-unused-variable 51 | } 52 | --------------------------------------------------------------------------------