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 15from typing import List 16 17import networkx as nx 18 19def generate_files(injection_graph: nx.DiGraph, use_new_delete: bool, use_interfaces: bool, generate_runtime_bench_code: bool): 20 file_content_by_name = dict() 21 22 for node_id in injection_graph.nodes: 23 deps = list(injection_graph.successors(node_id)) 24 if use_interfaces: 25 file_content_by_name['class%s_interface.h' % node_id] = _generate_class_interface_header(node_id) 26 file_content_by_name['class%s.h' % node_id] = _generate_class_header_with_interfaces(node_id, deps) 27 file_content_by_name['class%s.cpp' % node_id] = _generate_class_cpp_file_with_interfaces(node_id, deps) 28 else: 29 file_content_by_name['class%s.h' % node_id] = _generate_class_header_without_interfaces(node_id, deps) 30 file_content_by_name['class%s.cpp' % node_id] = _generate_class_cpp_file_without_interfaces(node_id, deps) 31 32 file_content_by_name['main.cpp'] = _generate_main(injection_graph, use_interfaces, use_new_delete, generate_runtime_bench_code) 33 34 return file_content_by_name 35 36def _generate_class_interface_header(class_index: int): 37 template = """ 38#ifndef CLASS{class_index}_INTERFACE_H 39#define CLASS{class_index}_INTERFACE_H 40 41// Example include that the code might use 42#include <vector> 43 44struct Interface{class_index} {{ 45 virtual void foo() = 0; 46 virtual ~Interface{class_index}(); 47}}; 48 49#endif // CLASS{class_index}_INTERFACE_H 50""" 51 return template.format(**locals()) 52 53def _generate_class_header_with_interfaces(class_index: int, deps: List[int]): 54 include_directives = ''.join('#include "class%s_interface.h"\n' % index 55 for index in itertools.chain(deps, (class_index,))) 56 fields = ''.join('Interface%s& x%s;\n' % (index, index) 57 for index in deps) 58 constructor_params = ', '.join('Interface%s& x%s' % (index, index) 59 for index in deps) 60 61 template = """ 62#ifndef CLASS{class_index}_H 63#define CLASS{class_index}_H 64 65{include_directives} 66 67struct Class{class_index} : public Interface{class_index} {{ 68 {fields} 69 Class{class_index}({constructor_params}); 70 71 virtual void foo() override; 72 73 virtual ~Class{class_index}(); 74}}; 75 76#endif // CLASS{class_index}_H 77""" 78 return template.format(**locals()) 79 80def _generate_class_header_without_interfaces(class_index: int, deps: List[int]): 81 include_directives = ''.join('#include "class%s.h"\n' % index 82 for index in deps) 83 fields = ''.join('Class%s& x%s;\n' % (index, index) 84 for index in deps) 85 constructor_params = ', '.join('Class%s& x%s' % (index, index) 86 for index in deps) 87 88 template = """ 89#ifndef CLASS{class_index}_H 90#define CLASS{class_index}_H 91 92// Example include that the code might use 93#include <vector> 94 95{include_directives} 96 97struct Class{class_index} {{ 98 {fields} 99 Class{class_index}({constructor_params}); 100}}; 101 102#endif // CLASS{class_index}_H 103""" 104 return template.format(**locals()) 105 106def _generate_class_cpp_file_with_interfaces(class_index: int, deps: List[int]): 107 constructor_params = ', '.join('Interface%s& x%s' % (index, index) 108 for index in deps) 109 field_initializers = ', '.join('x%s(x%s)' % (index, index) 110 for index in deps) 111 if field_initializers: 112 field_initializers = ': ' + field_initializers 113 114 template = """ 115#include "class{class_index}.h" 116 117Interface{class_index}::~Interface{class_index}() {{ 118}} 119 120Class{class_index}::Class{class_index}({constructor_params}) 121 {field_initializers} {{ 122}} 123 124void Class{class_index}::foo() {{ 125}} 126 127Class{class_index}::~Class{class_index}() {{ 128}} 129""" 130 return template.format(**locals()) 131 132def _generate_class_cpp_file_without_interfaces(class_index: int, deps: List[int]): 133 constructor_params = ', '.join('Class%s& x%s' % (index, index) 134 for index in deps) 135 field_initializers = ', '.join('x%s(x%s)' % (index, index) 136 for index in deps) 137 if field_initializers: 138 field_initializers = ': ' + field_initializers 139 140 template = """ 141#include "class{class_index}.h" 142 143Class{class_index}::Class{class_index}({constructor_params}) 144 {field_initializers} {{ 145}} 146""" 147 return template.format(**locals()) 148 149 150def _generate_main(injection_graph: nx.DiGraph, use_interfaces: bool, use_new_delete: bool, generate_runtime_bench_code: bool): 151 [toplevel_class_index] = [node_id 152 for node_id in injection_graph.nodes 153 if not any(True for p in injection_graph.predecessors(node_id))] 154 155 if use_interfaces: 156 include_directives = ''.join('#include "class%s.h"\n' % index 157 for index in injection_graph.nodes) 158 else: 159 include_directives = '#include "class%s.h"\n' % toplevel_class_index 160 161 if use_new_delete: 162 instance_creations = ''.join('std::unique_ptr<Class%s> x%s(new Class%s(%s));\n' % (class_index, 163 class_index, 164 class_index, 165 ', '.join('*x%s' % dep_index 166 for dep_index in injection_graph.successors(class_index))) 167 for class_index in reversed(list(nx.topological_sort(injection_graph)))) 168 else: 169 instance_creations = ''.join('Class%s x%s{%s};\n' % (class_index, 170 class_index, 171 ', '.join('x%s' % dep_index 172 for dep_index in injection_graph.successors(class_index))) 173 for class_index in reversed(list(nx.topological_sort(injection_graph)))) 174 175 void_casts = ''.join('(void) x%s;\n' % index 176 for index in injection_graph.nodes) 177 178 if generate_runtime_bench_code: 179 template = """ 180{include_directives} 181 182#include <ctime> 183#include <iostream> 184#include <cstdlib> 185#include <iomanip> 186#include <chrono> 187 188using namespace std; 189 190void do_injection() {{ 191 {instance_creations} 192 {void_casts} 193}} 194 195int main(int argc, char* argv[]) {{ 196 if (argc != 2) {{ 197 std::cout << "Need to specify num_loops as argument." << std::endl; 198 exit(1); 199 }} 200 size_t num_loops = std::atoi(argv[1]); 201 std::chrono::high_resolution_clock::time_point start_time; 202 203 start_time = std::chrono::high_resolution_clock::now(); 204 for (size_t i = 0; i < 1 + num_loops/100; i++) {{ 205 do_injection(); 206 }} 207 double fullInjectionTime = std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::high_resolution_clock::now() - start_time).count(); 208 209 std::cout << std::fixed; 210 std::cout << std::setprecision(15); 211 std::cout << "Total per request = " << fullInjectionTime * 100 / num_loops << std::endl; 212 return 0; 213}} 214""" 215 else: 216 template = """ 217{include_directives} 218 219#include <memory> 220#include <iostream> 221 222int main() {{ 223 {instance_creations} 224 {void_casts} 225 std::cout << "Hello, world" << std::endl; 226 return 0; 227}} 228""" 229 return template.format(**locals()) 230