• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
14
15
16def generate_files(injection_graph, generate_runtime_bench_code, use_normalized_component=False):
17    if use_normalized_component:
18        assert not generate_runtime_bench_code
19
20    file_content_by_name = dict()
21
22    for node_id in injection_graph.nodes_iter():
23        file_content_by_name['component%s.h' % node_id] = _generate_component_header(node_id)
24        file_content_by_name['component%s.cpp' % node_id] = _generate_component_source(node_id, injection_graph.successors(node_id))
25
26    [toplevel_node] = [node_id
27                       for node_id in injection_graph.nodes_iter()
28                       if not injection_graph.predecessors(node_id)]
29    file_content_by_name['main.cpp'] = _generate_main(toplevel_node, generate_runtime_bench_code)
30
31    return file_content_by_name
32
33def _get_component_type(component_index):
34    return 'fruit::Component<Interface{component_index}>'.format(**locals())
35
36def _generate_component_header(component_index):
37    component_type = _get_component_type(component_index)
38    template = """
39#ifndef COMPONENT{component_index}_H
40#define COMPONENT{component_index}_H
41
42#include <fruit/fruit.h>
43
44// Example include that the code might use
45#include <vector>
46
47struct Interface{component_index} {{
48  virtual ~Interface{component_index}() = default;
49}};
50
51{component_type} getComponent{component_index}();
52
53#endif // COMPONENT{component_index}_H
54"""
55    return template.format(**locals())
56
57def _generate_component_source(component_index, deps):
58    include_directives = ''.join(['#include "component%s.h"\n' % index for index in deps + [component_index]])
59
60    fields = ''.join(['Interface%s& x%s;\n' % (dep, dep)
61                      for dep in deps])
62
63    component_deps = ', '.join(['Interface%s& x%s' % (dep, dep)
64                                for dep in deps])
65    param_initializers = ', '.join('x%s(x%s)' % (dep, dep)
66                                   for dep in deps)
67    if param_initializers:
68        param_initializers = ': ' + param_initializers
69
70    install_expressions = ''.join(['        .install(getComponent%s)\n' % dep for dep in deps])
71
72    component_type = _get_component_type(component_index)
73
74    template = """
75{include_directives}
76
77namespace {{
78struct X{component_index} : public Interface{component_index} {{
79  {fields}
80
81  INJECT(X{component_index}({component_deps})) {param_initializers} {{}}
82
83  virtual ~X{component_index}() = default;
84}};
85}}
86
87"""
88
89    template += """
90{component_type} getComponent{component_index}() {{
91    return fruit::createComponent(){install_expressions}
92        .bind<Interface{component_index}, X{component_index}>();
93}}
94"""
95
96    return template.format(**locals())
97
98def _generate_main(toplevel_component, generate_runtime_bench_code):
99    if generate_runtime_bench_code:
100        template = """
101#include "component{toplevel_component}.h"
102
103#include <ctime>
104#include <iostream>
105#include <cstdlib>
106#include <iomanip>
107#include <chrono>
108
109using namespace std;
110
111fruit::Component<> getEmptyComponent() {{
112  return fruit::createComponent();
113}}
114
115int main(int argc, char* argv[]) {{
116  if (argc != 2) {{
117    std::cout << "Need to specify num_loops as argument." << std::endl;
118    exit(1);
119  }}
120  size_t num_loops = std::atoi(argv[1]);
121
122  fruit::NormalizedComponent<Interface{toplevel_component}> normalizedComponent(getComponent{toplevel_component});
123
124  std::chrono::high_resolution_clock::time_point start_time = std::chrono::high_resolution_clock::now();
125  for (size_t i = 0; i < num_loops; i++) {{
126    fruit::Injector<Interface{toplevel_component}> injector(normalizedComponent, getEmptyComponent);
127    injector.get<std::shared_ptr<Interface{toplevel_component}>>();
128  }}
129  double perRequestTime = std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::high_resolution_clock::now() - start_time).count();
130
131  std::cout << std::fixed;
132  std::cout << std::setprecision(15);
133  std::cout << "Total per request          = " << perRequestTime / num_loops << std::endl;
134  return 0;
135}}
136    """
137    else:
138        template = """
139#include "component{toplevel_component}.h"
140
141#include <iostream>
142
143fruit::Component<> getEmptyComponent() {{
144  return fruit::createComponent();
145}}
146
147int main(void) {{
148  fruit::NormalizedComponent<Interface{toplevel_component}> normalizedComponent(getComponent{toplevel_component});
149  fruit::Injector<Interface{toplevel_component}> injector(normalizedComponent, getEmptyComponent);
150  injector.get<std::shared_ptr<Interface{toplevel_component}>>();
151  std::cout << "Hello, world" << std::endl;
152  return 0;
153}}
154    """
155
156    return template.format(**locals())
157