├── .gitignore ├── .travis.yml ├── 01.cc ├── 02.cc ├── 03.cc ├── 04.cc ├── 05.cc ├── 06.cc ├── 07.cc ├── 08.cc ├── CMakeLists.txt ├── LICENSE ├── README.md ├── Slides-Pulling-Visitors-Daniel-J-H.pdf ├── shell.nix └── use-boost-coroutine2.patch /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: generic 2 | sudo: required 3 | dist: trusty 4 | 5 | install: 6 | - bash <(curl -sS https://nixos.org/nix/install) 7 | - source $HOME/.nix-profile/etc/profile.d/nix.sh 8 | 9 | before_script: 10 | - cd ${TRAVIS_BUILD_DIR} 11 | 12 | script: 13 | - nix-shell --pure --run 'env CXXFLAGS="-Wall -Wextra -pedantic" mkdir -p build && cd build && cmake ..' 14 | - nix-shell --pure --run 'cmake --build build' 15 | -------------------------------------------------------------------------------- /01.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | using namespace boost; 5 | 6 | 7 | // The following constructs a simple graph we can dynamically add edges and vertices to. 8 | // Using vecS for the adjacency list containers selects std::vector for inner and outer container. 9 | // Using directedS makes all edges directed by default. We can still manually add reverse edges. 10 | 11 | using graph_t = adjacency_list; 12 | 13 | int main() { 14 | auto n_vertices = 3u; 15 | graph_t graph(n_vertices); 16 | 17 | add_edge(0, 1, graph); 18 | add_edge(1, 2, graph); 19 | add_edge(2, 0, graph); 20 | 21 | print_graph(graph); 22 | } 23 | -------------------------------------------------------------------------------- /02.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace boost; 10 | using namespace boost::adaptors; 11 | 12 | 13 | // Here we show Bundled Properties by attaching edge_data_t to each edge in the adjacency list. 14 | // We use boost::no_property for vertex properties since we do not want properties on them. 15 | // Algorithms such as vertices(graph) and edges(graph) return ranges (pairs with first, last). 16 | // We prefer using Boost.Range's algorithms such as boost::accumulate to iterate on the pair's range. 17 | // In addition, we find Boost.Range's adaptors and their pipe syntax a perfect fit for these use-cases. 18 | 19 | struct edge_data_t { int duration = 0; }; 20 | 21 | using graph_t = adjacency_list; 22 | 23 | int main() { 24 | auto n_vertices = 3u; 25 | graph_t graph(n_vertices); 26 | 27 | add_edge(0, 1, edge_data_t{100}, graph); 28 | add_edge(1, 2, edge_data_t{200}, graph); 29 | add_edge(2, 0, edge_data_t{-10}, graph); 30 | 31 | auto duration = [&graph](auto edge) { return graph[edge].duration; }; 32 | auto positive = [](auto duration) { return duration > 0; }; 33 | 34 | auto total = accumulate(edges(graph) | transformed(duration) | filtered(positive), 0); 35 | 36 | std::cout << total << std::endl; 37 | } 38 | -------------------------------------------------------------------------------- /03.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace boost; 14 | using namespace boost::adaptors; 15 | 16 | 17 | // The following uses a static graph (compressed sparse row graph) we can no longer modify once constructed. 18 | // Due to this restriction it is highly compact and efficient, and the only option for large sparse graphs. 19 | // We do not use Bundled Properties but instead only temporarily use external properties through a property map. 20 | 21 | struct vertex_data_t { int priority = 0; }; 22 | 23 | using graph_t = compressed_sparse_row_graph; 24 | using vertex_t = graph_traits::vertex_descriptor; 25 | 26 | int main() { 27 | auto n_vertices = 3u; 28 | std::vector sources{0, 1, 2}; 29 | std::vector targets{1, 2, 0}; 30 | 31 | auto tag = construct_inplace_from_sources_and_targets; 32 | graph_t graph{tag, sources, targets, n_vertices}; 33 | 34 | std::vector vertex_data{{15}, {-5}, {10}}; 35 | auto vertex_data_map = make_iterator_property_map(vertex_data.begin(), get(vertex_index, graph)); 36 | 37 | auto priority = [&vertex_data_map](auto vertex) { return get(vertex_data_map, vertex).priority; }; 38 | 39 | auto avg = accumulate(vertices(graph) | transformed(priority), 0.) / size(vertex_data); 40 | 41 | std::cout << avg << std::endl; 42 | } 43 | -------------------------------------------------------------------------------- /04.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace boost; 9 | 10 | 11 | // Here we provide a custom breadth-first search visitor, printing vertices in the order we discover them. 12 | // Note how the breadth_first_search call at the end runs through before the final "*" is printed. 13 | 14 | using graph_t = compressed_sparse_row_graph; 15 | using vertex_t = graph_traits::vertex_descriptor; 16 | 17 | struct discover_visitor : default_bfs_visitor { 18 | void discover_vertex(const vertex_t vertex, const graph_t&) { 19 | std::cout << vertex << std::endl; 20 | } 21 | }; 22 | 23 | int main() { 24 | /* 25 | * 0 -> 1 -> 2 26 | * ^ | | 27 | * | v v 28 | * 5 <- 4 <- 3 29 | */ 30 | auto n_vertices = 6u; 31 | std::vector sources{0, 1, 1, 2, 3, 4, 5}; 32 | std::vector targets{1, 2, 4, 3, 4, 5, 0}; 33 | 34 | auto tag = construct_inplace_from_sources_and_targets; 35 | graph_t graph{tag, sources, targets, n_vertices}; 36 | 37 | vertex_t source{0}; 38 | breadth_first_search(graph, source, visitor(discover_visitor{})); 39 | std::cout << "*" << std::endl; 40 | } 41 | -------------------------------------------------------------------------------- /05.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | 12 | using namespace boost; 13 | 14 | 15 | // In the following we introduce coroutines and the overall pattern presented here. 16 | // We provide a breadth-first search visitor that pushes vertices into a push_type coroutine. 17 | // Using the coroutine's pull_type lets us transform the visitor into a lazy generator we can step through. 18 | // The generator provides the usual begin(), end() interface and is suitable for range-based for loops. 19 | // Looping through the generator does the following: 20 | // - run the visitor for one vertex 21 | // - stop the visitor handing over the vertex to the call site 22 | // - resume the visitor for one vertex, repeat this stepwise process 23 | // This provides us with a lazy range of vertices in breadth-first order we can loop over, inverting the control flow. 24 | // Note how we can use stdlib algorithms on this range, e.g. std::find_if to search for vertices in breadth-first order. 25 | 26 | using graph_t = compressed_sparse_row_graph; 27 | using vertex_t = graph_traits::vertex_descriptor; 28 | using coro_t = coroutines::asymmetric_coroutine; 29 | 30 | struct discover_visitor : default_bfs_visitor { 31 | discover_visitor(coro_t::push_type& sink_) : sink(sink_) { } 32 | 33 | void discover_vertex(const vertex_t vertex, const graph_t&) { 34 | sink(vertex); 35 | } 36 | 37 | coro_t::push_type& sink; 38 | }; 39 | 40 | int main() { 41 | /* 42 | * 0 -> 1 -> 2 43 | * ^ | | 44 | * | v v 45 | * 5 <- 4 <- 3 46 | */ 47 | auto n_vertices = 6u; 48 | std::vector sources{0, 1, 1, 2, 3, 4, 5}; 49 | std::vector targets{1, 2, 4, 3, 4, 5, 0}; 50 | 51 | auto tag = construct_inplace_from_sources_and_targets; 52 | graph_t graph{tag, sources, targets, n_vertices}; 53 | 54 | vertex_t source{0}; 55 | 56 | coro_t::pull_type lazy_bfs_vertices{[&](auto& sink) { 57 | breadth_first_search(graph, source, visitor(discover_visitor{sink})); 58 | }}; 59 | 60 | for (auto vertex : lazy_bfs_vertices) { 61 | std::cout << vertex << std::endl; 62 | std::cout << "*" << std::endl; 63 | } 64 | 65 | // The following shows how we're able to plug in the full stdlib algorithms. 66 | // It also shows what happens if you step through an exhausted generator. 67 | // Give it a try and then comment out the range-based for loop above. 68 | 69 | // auto splits = [&graph](auto vertex) { return out_degree(vertex, graph) > 1; }; 70 | // auto it = find_if(lazy_bfs_vertices, splits); 71 | // 72 | // if (it != end(lazy_bfs_vertices)) 73 | // std::cout << *it << std::endl; 74 | } 75 | -------------------------------------------------------------------------------- /06.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace boost; 10 | 11 | 12 | // Use-case: bidirectional Dijkstra st-shortest path. 13 | // In the following we construct a graph and run a Dijkstra search starting at the source on it. 14 | // We also construct a reverse graph and run a Dijkstra search starting at the target on it. 15 | // The question is how to stop in the "middle" where both searches meet (assuming there exists a path). 16 | // Follow the execution and have a look where the "*" is getting printed. 17 | // One approach is to use threads, synchronization and throwing exceptions from the visitors. 18 | 19 | struct edge_data_t { int distance = 0; }; 20 | 21 | using graph_t = compressed_sparse_row_graph; 22 | using vertex_t = graph_traits::vertex_descriptor; 23 | 24 | struct dijkstra_stepwise : default_dijkstra_visitor { 25 | dijkstra_stepwise(vertex_t middle_) : middle(middle_) {} 26 | 27 | template 28 | void examine_vertex(const vertex_t vertex, const graph_t&) const { 29 | std::cout << vertex << std::endl; 30 | } 31 | 32 | vertex_t middle; 33 | }; 34 | 35 | int main() { 36 | /* 37 | * 0 <-> 1 <-> 2 38 | * ^ ^ ^ 39 | * | | | 40 | * v v v 41 | * 5 <-> 4 <-> 3 42 | */ 43 | auto n_vertices = 6u; 44 | 45 | std::vector> edges{{0, 1}, {1, 2}, {1, 4}, {2, 3}, {3, 4}, {4, 5}, {5, 0}}; 46 | std::vector distances{{1}, {1}, {2}, {1}, {1}, {2}, {2}}; 47 | 48 | auto tag = edges_are_unsorted_multi_pass; 49 | graph_t graph{tag, edges.begin(), edges.end(), distances.begin(), n_vertices}; 50 | 51 | vertex_t source{0}; 52 | vertex_t target{3}; 53 | 54 | auto reversed_graph = make_reverse_graph(graph); 55 | 56 | std::vector forward_prev(num_vertices(graph)); 57 | std::vector backward_prev(num_vertices(graph)); 58 | 59 | auto forward_prev_map = make_iterator_property_map(forward_prev.begin(), get(vertex_index, graph)); 60 | auto backward_prev_map = make_iterator_property_map(backward_prev.begin(), get(vertex_index, reversed_graph)); 61 | 62 | vertex_t middle{target}; 63 | 64 | dijkstra_shortest_paths_no_color_map(graph, source, 65 | weight_map(get(&edge_data_t::distance, graph)) 66 | .predecessor_map(forward_prev_map) 67 | .visitor(dijkstra_stepwise{middle})); 68 | 69 | std::cout << "*" << std::endl; 70 | 71 | dijkstra_shortest_paths_no_color_map(reversed_graph, target, 72 | weight_map(get(&edge_data_t::distance, reversed_graph)) 73 | .predecessor_map(backward_prev_map) 74 | .visitor(dijkstra_stepwise{middle})); 75 | } 76 | -------------------------------------------------------------------------------- /07.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | using namespace boost; 12 | 13 | 14 | // Use-case: bidirectional Dijkstra st-shortest path. 15 | // In the following we construct a graph and run a Dijkstra search starting at the source on it. 16 | // We also construct a reverse graph and run a Dijkstra search starting at the target on it. 17 | // This time we use the coroutine pattern to construct lazy shortest path ranges. 18 | // We then can step through both ranges in a ping-pong fashion, alternating between forward and reverse search. 19 | 20 | struct edge_data_t { int distance = 0; }; 21 | 22 | using graph_t = compressed_sparse_row_graph; 23 | using vertex_t = graph_traits::vertex_descriptor; 24 | using coro_t = coroutines::asymmetric_coroutine; 25 | 26 | struct dijkstra_stepwise : default_dijkstra_visitor { 27 | dijkstra_stepwise(coro_t::push_type& sink_) : sink(sink_) {} 28 | 29 | template 30 | void examine_vertex(const vertex_t vertex, const graph_t&) const { 31 | sink(vertex); 32 | } 33 | 34 | coro_t::push_type& sink; 35 | }; 36 | 37 | int main() { 38 | /* 39 | * 0 <-> 1 <-> 2 40 | * ^ ^ ^ 41 | * | | | 42 | * v v v 43 | * 5 <-> 4 <-> 3 44 | */ 45 | auto n_vertices = 6u; 46 | 47 | std::vector> edges{{0, 1}, {1, 2}, {1, 4}, {2, 3}, {3, 4}, {4, 5}, {5, 0}}; 48 | std::vector distances{{1}, {1}, {2}, {1}, {1}, {2}, {2}}; 49 | 50 | auto tag = edges_are_unsorted_multi_pass; 51 | graph_t graph{tag, edges.begin(), edges.end(), distances.begin(), n_vertices}; 52 | 53 | vertex_t source{0}; 54 | vertex_t target{3}; 55 | 56 | auto reversed_graph = make_reverse_graph(graph); 57 | 58 | std::vector forward_prev(num_vertices(graph)); 59 | std::vector backward_prev(num_vertices(graph)); 60 | 61 | auto forward_prev_map = make_iterator_property_map(forward_prev.begin(), get(vertex_index, graph)); 62 | auto backward_prev_map = make_iterator_property_map(backward_prev.begin(), get(vertex_index, reversed_graph)); 63 | 64 | coro_t::pull_type lazy_forward_vertices{[&](auto& sink) { 65 | dijkstra_shortest_paths_no_color_map(graph, source, 66 | weight_map(get(&edge_data_t::distance, graph)) 67 | .predecessor_map(forward_prev_map) 68 | .visitor(dijkstra_stepwise{sink})); 69 | }}; 70 | 71 | coro_t::pull_type lazy_backward_vertices{[&](auto& sink) { 72 | dijkstra_shortest_paths_no_color_map(reversed_graph, target, 73 | weight_map(get(&edge_data_t::distance, reversed_graph)) 74 | .predecessor_map(backward_prev_map) 75 | .visitor(dijkstra_stepwise{sink})); 76 | }}; 77 | 78 | // Manually stepping through the generators (as in: not using range-based for loop) requires us to 79 | // - extract the vertex with .get() the visitors are handing over to us 80 | // - single stepping the stopped coroutines with operator() to resume them 81 | while (lazy_forward_vertices && lazy_backward_vertices) { 82 | std::cout << "forward " << lazy_forward_vertices.get() << std::endl; 83 | std::cout << "backward " << lazy_backward_vertices.get() << std::endl; 84 | 85 | lazy_forward_vertices(); 86 | lazy_backward_vertices(); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /08.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | using namespace boost; 17 | using namespace boost::adaptors; 18 | 19 | 20 | // The following shows how to produce GeoJSON from your graph with location-tagged vertices. 21 | // Use Mapbox Studio geojson.io or Github / Gist to visualize the GeoJSON result on top of a map. 22 | // You can format the output for quick manual inspection with: ./08 | python3 -m json.tool 23 | // For larger graphs you want to use tippecanoe for zoom-level based simplification. 24 | // The following could be made more generic requiring only a location property map. 25 | 26 | struct location_t { float longitude = 0., latitude = 0.; }; 27 | 28 | using graph_t = compressed_sparse_row_graph; 29 | using vertex_t = graph_traits::vertex_descriptor; 30 | 31 | 32 | std::ostream& operator<<(std::ostream& out, const location_t location) { 33 | boost::format fmt{"{\"type\":\"Feature\"," 34 | "\"properties\":{}," 35 | "\"geometry\":{" 36 | "\"type\":\"Point\"," 37 | "\"coordinates\":[%1$.5f,%2$.5f]}}"}; 38 | 39 | return out << (fmt % location.longitude % location.latitude); 40 | } 41 | 42 | std::ostream& operator<<(std::ostream& out, const graph_t graph) { 43 | boost::format fmt{"{\"type\":\"FeatureCollection\"," 44 | "\"features\":[%1%]}"}; 45 | 46 | auto location = [&graph](auto vertex) { 47 | std::ostringstream fmt; 48 | fmt << graph[vertex]; 49 | return fmt.str(); 50 | }; 51 | 52 | auto coordinates = vertices(graph) | transformed(location); 53 | return out << (fmt % algorithm::join(coordinates, ",")); 54 | } 55 | 56 | 57 | int main() { 58 | auto n_vertices = 3u; 59 | std::vector sources{0, 1, 2}; 60 | std::vector targets{1, 2, 0}; 61 | 62 | auto tag = construct_inplace_from_sources_and_targets; 63 | graph_t graph{tag, sources, targets, n_vertices}; 64 | 65 | graph[0] = {13.42252, 52.49603}; 66 | graph[1] = {13.40229, 52.52363}; 67 | graph[2] = {13.41816, 52.49933}; 68 | 69 | std::cout << graph << std::endl; 70 | } 71 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1 FATAL_ERROR) 2 | project(pulling-visitors VERSION 0.0.1 LANGUAGES CXX) 3 | 4 | set(CMAKE_CXX_STANDARD 14) 5 | 6 | find_package(Boost 1.59 REQUIRED coroutine thread system context) 7 | include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) 8 | 9 | 10 | add_executable(01 01.cc) 11 | add_executable(02 02.cc) 12 | add_executable(03 03.cc) 13 | add_executable(04 04.cc) 14 | 15 | add_executable(05 05.cc) 16 | target_link_libraries(05 ${Boost_COROUTINE_LIBRARY} ${Boost_CONTEXT_LIBRARY} ${Boost_SYSTEM_LIBRARY}) 17 | 18 | add_executable(06 06.cc) 19 | 20 | add_executable(07 07.cc) 21 | target_link_libraries(07 ${Boost_COROUTINE_LIBRARY} ${Boost_CONTEXT_LIBRARY} ${Boost_SYSTEM_LIBRARY}) 22 | 23 | add_executable(08 08.cc) 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Daniel J. Hofmann 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Pulling Visitors: Boost.Graph + Boost.Coroutine 2 | 3 | [![Continuous Integration](https://travis-ci.org/daniel-j-h/cppnow2016.svg?branch=master)](https://travis-ci.org/daniel-j-h/cppnow2016) 4 | 5 | 6 | ## Overview 7 | 8 | I recommend going through the examples in order. 9 | 10 | | Example | Introduces | 11 | | -------------- | ---------------------------------------------------------------------------------------------------- | 12 | | [01.cc](01.cc) | Dynamic graph, `adjacency_list` | 13 | | [02.cc](02.cc) | Bundled Properties, working with vertex / edge ranges | 14 | | [03.cc](03.cc) | Static graph, `compressed_sparse_row_graph`, temporary graph-external properties | 15 | | [04.cc](04.cc) | Breadth-first search, customization through visitor | 16 | | [05.cc](05.cc) | Breadth-first search, inverting control flow with coroutines, stepwise iteration, stdlib integration | 17 | | [06.cc](06.cc) | Bidirectional dijkstra, customization through visitor, problem with stepping visitors | 18 | | [07.cc](07.cc) | Bidirectional dijkstra, inverted control flow with coroutines, stepwise iteration | 19 | | [08.cc](08.cc) | GeoJSON from graph for visualization | 20 | 21 | 22 | ## Building the Examples 23 | 24 | 25 | mkdir build && cd build 26 | export CC='clang' CXX='clang++' CXXFLAGS='-Wall -Wextra -pedantic' 27 | cmake .. -DCMAKE_BUILD_TYPE=Release 28 | 29 | With [Nix](https://nixos.org/nix/): 30 | 31 | nix-shell --pure --run 'env CXXFLAGS="-Wall -Wextra -pedantic" mkdir build && cd build && cmake ..' 32 | nix-shell --pure --run 'cmake --build build' 33 | 34 | Note: apply `use-boost-coroutine2.patch` if you want to use the newer Boost.Coroutine2 instead of the Boost.Coroutine library. 35 | This requires your Boost >=1.59 distribution to be build with `CXXFLAGS=-std=c++14`, which is probably not the case by default or using Boost >=1.61 where Boost.Coroutine2 was relaxed to C++11. 36 | 37 | ## Resources 38 | 39 | - [Boost.Graph](http://www.boost.org/doc/libs/1_60_0/libs/graph/doc/table_of_contents.html) 40 | - [Boost.Graph Concepts](http://www.boost.org/doc/libs/1_60_0/libs/graph/doc/graph_concepts.html) 41 | - [Boost.Coroutine](http://www.boost.org/doc/libs/1_60_0/libs/coroutine/doc/html/index.html) 42 | - [tippecanoe](https://github.com/mapbox/tippecanoe) for zoom-based GeoJSON simplification 43 | - [Mapbox Studio](https://www.mapbox.com/studio) or [geojson.io](http://geojson.io) for visualizing GeoJSON 44 | - [Richel Bilderbeek's recent take on writing a C++11 Boost.Graph tutorial](https://github.com/richelbilderbeek/BoostGraphTutorial) 45 | - [libosmium](https://github.com/osmcode/libosmium) and [Boost.Geometry](http://www.boost.org/doc/libs/1_60_0/libs/geometry/doc/html/index.html) for your OpenStreetMap based project 46 | - [How it all started](http://lists.boost.org/boost-users/2015/11/85302.php) 47 | 48 | 49 | ## License 50 | 51 | Copyright © 2016 Daniel J. Hofmann 52 | 53 | Distributed under the MIT License (MIT). 54 | -------------------------------------------------------------------------------- /Slides-Pulling-Visitors-Daniel-J-H.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/daniel-j-h/cppnow2016/69deb829e000e385f52070f2cb4956bd54a99eca/Slides-Pulling-Visitors-Daniel-J-H.pdf -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | # Nix development environment for reproducible builds. 2 | # Enter development environment via `nix-shell`. 3 | # 4 | # Resources: 5 | # - https://nixos.org/nix/ 6 | # - https://nixos.org/nix/manual/#chap-quick-start 7 | # - https://nixos.org/nixpkgs/manual/ 8 | 9 | with import {}; { 10 | devEnv = stdenv.mkDerivation { 11 | name = "pulling-visitors"; 12 | buildInputs = [ cmake boost ]; 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /use-boost-coroutine2.patch: -------------------------------------------------------------------------------- 1 | diff --git a/05.cc b/05.cc 2 | index 7fcf4ff..d324e50 100644 3 | --- a/05.cc 4 | +++ b/05.cc 5 | @@ -7,7 +7,7 @@ 6 | 7 | #include 8 | 9 | -#include 10 | +#include 11 | 12 | using namespace boost; 13 | 14 | @@ -25,7 +25,7 @@ using namespace boost; 15 | 16 | using graph_t = compressed_sparse_row_graph; 17 | using vertex_t = graph_traits::vertex_descriptor; 18 | -using coro_t = coroutines::asymmetric_coroutine; 19 | +using coro_t = coroutines2::coroutine; 20 | 21 | struct discover_visitor : default_bfs_visitor { 22 | discover_visitor(coro_t::push_type& sink_) : sink(sink_) { } 23 | diff --git a/07.cc b/07.cc 24 | index d690108..99b1053 100644 25 | --- a/07.cc 26 | +++ b/07.cc 27 | @@ -6,7 +6,7 @@ 28 | #include 29 | #include 30 | 31 | -#include 32 | +#include 33 | 34 | using namespace boost; 35 | 36 | @@ -21,7 +21,7 @@ struct edge_data_t { int distance = 0; }; 37 | 38 | using graph_t = compressed_sparse_row_graph; 39 | using vertex_t = graph_traits::vertex_descriptor; 40 | -using coro_t = coroutines::asymmetric_coroutine; 41 | +using coro_t = coroutines2::coroutine; 42 | 43 | struct dijkstra_stepwise : default_dijkstra_visitor { 44 | dijkstra_stepwise(coro_t::push_type& sink_) : sink(sink_) {} 45 | diff --git a/CMakeLists.txt b/CMakeLists.txt 46 | index 4efc452..f0058e5 100644 47 | --- a/CMakeLists.txt 48 | +++ b/CMakeLists.txt 49 | @@ -3,7 +3,7 @@ project(pulling-visitors VERSION 0.0.1 LANGUAGES CXX) 50 | 51 | set(CMAKE_CXX_STANDARD 14) 52 | 53 | -find_package(Boost 1.59 REQUIRED coroutine thread system context) 54 | +find_package(Boost 1.59 REQUIRED thread system context) 55 | include_directories(SYSTEM ${Boost_INCLUDE_DIRS}) 56 | 57 | 58 | @@ -13,11 +13,11 @@ add_executable(03 03.cc) 59 | add_executable(04 04.cc) 60 | 61 | add_executable(05 05.cc) 62 | -target_link_libraries(05 ${Boost_COROUTINE_LIBRARY} ${Boost_CONTEXT_LIBRARY} ${Boost_SYSTEM_LIBRARY}) 63 | +target_link_libraries(05 ${Boost_CONTEXT_LIBRARY} ${Boost_SYSTEM_LIBRARY}) 64 | 65 | add_executable(06 06.cc) 66 | 67 | add_executable(07 07.cc) 68 | -target_link_libraries(07 ${Boost_COROUTINE_LIBRARY} ${Boost_CONTEXT_LIBRARY} ${Boost_SYSTEM_LIBRARY}) 69 | +target_link_libraries(07 ${Boost_CONTEXT_LIBRARY} ${Boost_SYSTEM_LIBRARY}) 70 | 71 | add_executable(08 08.cc) 72 | --------------------------------------------------------------------------------