1# Copyright 2016 Google Inc. All Rights Reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS-IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14import itertools 15import networkx as nx 16 17def generate_files(injection_graph, use_new_delete, use_interfaces, generate_runtime_bench_code): 18 file_content_by_name = dict() 19 20 for node_id in injection_graph.nodes_iter(): 21 deps = injection_graph.successors(node_id) 22 if use_interfaces: 23 file_content_by_name['class%s_interface.h' % node_id] = _generate_class_interface_header(node_id) 24 file_content_by_name['class%s.h' % node_id] = _generate_class_header_with_interfaces(node_id, deps) 25 file_content_by_name['class%s.cpp' % node_id] = _generate_class_cpp_file_with_interfaces(node_id, deps) 26 else: 27 file_content_by_name['class%s.h' % node_id] = _generate_class_header_without_interfaces(node_id, deps) 28 file_content_by_name['class%s.cpp' % node_id] = _generate_class_cpp_file_without_interfaces(node_id, deps) 29 30 file_content_by_name['main.cpp'] = _generate_main(injection_graph, use_interfaces, use_new_delete, generate_runtime_bench_code) 31 32 return file_content_by_name 33 34def _generate_class_interface_header(class_index): 35 template = """ 36#ifndef CLASS{class_index}_INTERFACE_H 37#define CLASS{class_index}_INTERFACE_H 38 39// Example include that the code might use 40#include <vector> 41 42struct Interface{class_index} {{ 43 virtual void foo() = 0; 44 virtual ~Interface{class_index}(); 45}}; 46 47#endif // CLASS{class_index}_INTERFACE_H 48""" 49 return template.format(**locals()) 50 51def _generate_class_header_with_interfaces(class_index, deps): 52 include_directives = ''.join('#include "class%s_interface.h"\n' % index 53 for index in itertools.chain(deps, (class_index,))) 54 fields = ''.join('Interface%s& x%s;\n' % (index, index) 55 for index in deps) 56 constructor_params = ', '.join('Interface%s& x%s' % (index, index) 57 for index in deps) 58 59 template = """ 60#ifndef CLASS{class_index}_H 61#define CLASS{class_index}_H 62 63{include_directives} 64 65struct Class{class_index} : public Interface{class_index} {{ 66 {fields} 67 Class{class_index}({constructor_params}); 68 69 virtual void foo() override; 70 71 virtual ~Class{class_index}(); 72}}; 73 74#endif // CLASS{class_index}_H 75""" 76 return template.format(**locals()) 77 78def _generate_class_header_without_interfaces(class_index, deps): 79 include_directives = ''.join('#include "class%s.h"\n' % index 80 for index in deps) 81 fields = ''.join('Class%s& x%s;\n' % (index, index) 82 for index in deps) 83 constructor_params = ', '.join('Class%s& x%s' % (index, index) 84 for index in deps) 85 86 template = """ 87#ifndef CLASS{class_index}_H 88#define CLASS{class_index}_H 89 90// Example include that the code might use 91#include <vector> 92 93{include_directives} 94 95struct Class{class_index} {{ 96 {fields} 97 Class{class_index}({constructor_params}); 98}}; 99 100#endif // CLASS{class_index}_H 101""" 102 return template.format(**locals()) 103 104def _generate_class_cpp_file_with_interfaces(class_index, deps): 105 constructor_params = ', '.join('Interface%s& x%s' % (index, index) 106 for index in deps) 107 field_initializers = ', '.join('x%s(x%s)' % (index, index) 108 for index in deps) 109 if field_initializers: 110 field_initializers = ': ' + field_initializers 111 112 template = """ 113#include "class{class_index}.h" 114 115Interface{class_index}::~Interface{class_index}() {{ 116}} 117 118Class{class_index}::Class{class_index}({constructor_params}) 119 {field_initializers} {{ 120}} 121 122void Class{class_index}::foo() {{ 123}} 124 125Class{class_index}::~Class{class_index}() {{ 126}} 127""" 128 return template.format(**locals()) 129 130def _generate_class_cpp_file_without_interfaces(class_index, deps): 131 constructor_params = ', '.join('Class%s& x%s' % (index, index) 132 for index in deps) 133 field_initializers = ', '.join('x%s(x%s)' % (index, index) 134 for index in deps) 135 if field_initializers: 136 field_initializers = ': ' + field_initializers 137 138 template = """ 139#include "class{class_index}.h" 140 141Class{class_index}::Class{class_index}({constructor_params}) 142 {field_initializers} {{ 143}} 144""" 145 return template.format(**locals()) 146 147 148def _generate_main(injection_graph, use_interfaces, use_new_delete, generate_runtime_bench_code): 149 [toplevel_class_index] = [node_id 150 for node_id in injection_graph.nodes_iter() 151 if not injection_graph.predecessors(node_id)] 152 153 if use_interfaces: 154 include_directives = ''.join('#include "class%s.h"\n' % index 155 for index in injection_graph.nodes_iter()) 156 else: 157 include_directives = '#include "class%s.h"\n' % toplevel_class_index 158 159 if use_new_delete: 160 instance_creations = ''.join('std::unique_ptr<Class%s> x%s(new Class%s(%s));\n' % (class_index, 161 class_index, 162 class_index, 163 ', '.join('*x%s' % dep_index 164 for dep_index in injection_graph.successors(class_index))) 165 for class_index in reversed(list(nx.topological_sort(injection_graph)))) 166 else: 167 instance_creations = ''.join('Class%s x%s{%s};\n' % (class_index, 168 class_index, 169 ', '.join('x%s' % dep_index 170 for dep_index in injection_graph.successors(class_index))) 171 for class_index in reversed(list(nx.topological_sort(injection_graph)))) 172 173 void_casts = ''.join('(void) x%s;\n' % index 174 for index in injection_graph.nodes_iter()) 175 176 if generate_runtime_bench_code: 177 template = """ 178{include_directives} 179 180#include <ctime> 181#include <iostream> 182#include <cstdlib> 183#include <iomanip> 184#include <chrono> 185 186using namespace std; 187 188void do_injection() {{ 189 {instance_creations} 190 {void_casts} 191}} 192 193int main(int argc, char* argv[]) {{ 194 if (argc != 2) {{ 195 std::cout << "Need to specify num_loops as argument." << std::endl; 196 exit(1); 197 }} 198 size_t num_loops = std::atoi(argv[1]); 199 std::chrono::high_resolution_clock::time_point start_time; 200 201 start_time = std::chrono::high_resolution_clock::now(); 202 for (size_t i = 0; i < 1 + num_loops/100; i++) {{ 203 do_injection(); 204 }} 205 double fullInjectionTime = std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::high_resolution_clock::now() - start_time).count(); 206 207 std::cout << std::fixed; 208 std::cout << std::setprecision(15); 209 std::cout << "Total per request = " << fullInjectionTime * 100 / num_loops << std::endl; 210 return 0; 211}} 212""" 213 else: 214 template = """ 215{include_directives} 216 217#include <memory> 218#include <iostream> 219 220int main() {{ 221 {instance_creations} 222 {void_casts} 223 std::cout << "Hello, world" << std::endl; 224 return 0; 225}} 226""" 227 return template.format(**locals()) 228