Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(85)

Side by Side Diff: base/generate_callback_templates.py

Issue 3555014: Script to generated a grand-unified callback system. (Closed)
Patch Set: Created 10 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/python
2
3 # Copyright (c) 2009 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
6
7 """Geneartes the types and factory methods needed for Callbacks.
8
9 See base/callback.h for details on the callback system.
10 """
11
12 import datetime
13 from optparse import OptionParser
14
15 # Supporting functions and methods up to 5 arguments seems to be good enough
16 # for most use cases. The historical callback mechanisms in Chrome only
17 # only supported 5 arguments, and did not have issues. Increase this value if
18 # necessary. The cost is for each argument, you get N more sets of factory
19 # methods, and one more set of callbck classes.
20 MAX_ARGS=5
21
22 # Enum type for specifying the return type of a callback.
23 class ReturnType:
24 VOID = 0
25 RESULT = 1
26
27
28 # Enum type for specifying if we need to generate a template for a
29 # callback that Refcounts the object it wraps.
30 class WillRef:
31 YES = 0
32 NO = 1
33
34 class SpecializationType:
35 METHOD = 0
36 CONST_METHOD = 1
37 FUNCTION = 2
38
39
40 HEADER = """\
41 // Copyright (c) %(year)d The Chromium Authors. All rights reserved.
42 // Use of this source code is governed by a BSD-style license that can be
43 // found in the LICENSE file.
44
45 // This file is automatically generated by base/generate_callback_templates.py.
46 // DO NOT EDIT!
47
48 #ifndef BASE_CALLBACK_%(filesuffix)s_H_
49
50 %(includes)s
51
52 namespace base {
53 """
54
55 FOOTER = """\
56 } // namespace base
57
58 #endif // BASE_CALLBACK_%(filesuffix)s_H_
59 """
60
61
62 CALLBACK_CLASS_BODY = """\
63 class %(name)s%(inherit)s {
64 public:
65 virtual ~%(name)s() { }%(methods)s
66 %(run_declaration)s
67 };
68 """
69
70
71 TEMPLATE_DECLARATION = """template <%s>"""
72
73
74 RUN_DECLARATION = "virtual %(return_type)s Run(%(params)s) = 0;"
75
76
77 STANDARD_METHODS = """
78 virtual bool IsRepeatable() const { return false; }"""
79
80 PREBIND_DECLARATION = """\
81 %(template_line)s
82 class %(classname)s : public %(interface_name)s"""
83
84 PREBIND_TYPEDEFS = """\
85 typedef %(interface_name)s base;
86 typedef %(return_type)s (T::*Signature)()%(spacer)s%(const)s;
87 """
88
89 METHOD_CONSTRUCTOR_BODY = """
90 ::base::internal::RefUtil<%s, T>::TakeRef(object_);
91 \
92 """
93
94 METHOD_DESTRUCTOR_BODY = """
95 ::base::internal::RefUtil<%s, T>::ReleaseRef(object_);
96 \
97 """
98
99 CONSTRUCTOR_TEMPLATE = """\
100 inline %(classname)s(%(arglist)s)
101 : %(initializers)s {%(body)s}
102 """
103
104 DESTRUCTOR_TEMPLATE = """\
105 virtual ~%(classname)s() {%(body)s}
106 """
107
108 PREBIND_CLASS = """
109 %(class_decl)s {
110 public:
111 %(typedefs)s
112
113 private:
114 %(storage)s
115
116 public:
117 %(constructor)s
118 %(destructor)s
119 virtual bool IsRepeatable() const {
120 return !del;
121 }
122
123 %(run_func)s
124 };
125 """
126
127
128 SPECIALIZATION_HELPERS = """\
129 namespace internal {
130 template <bool ref, typename T>
131 class RefUtil {
132 public:
133 static inline void TakeRef(T* object) {
134 static_cast<typename ::base::RefCountedThreadSafe<T>*>(object)->AddRef();
135 }
136
137 static inline void ReleaseRef(T* object) {
138 static_cast<typename ::base::RefCountedThreadSafe<T>*>(object)->Release();
139 }
140 };
141
142 template <typename T>
143 class RefUtil<false, T> {
144 public:
145 static inline void TakeRef(T* object) {
146 }
147
148 static inline void ReleaseRef(T* object) {
149 }
150 };
151
152 // Identity<T>::type is a typedef of T. Useful for preventing the
153 // compiler from inferring the type of an argument in templates.
154 template <typename T>
155 struct Identity {
156 typedef T type;
157 };
158 } // namespace internal
159 """
160
161 RUN_DEFINITON = """\
162 virtual void Run(%(run_args)s) {
163 if (!del) {
164 (%(deref_prefix)s*function_)(%(invocation_args)s);
165 } else {
166 Signature function = function_;
167 // Null-out pointer now to force sefault if called again.
168 function_ = NULL;
169 (%(deref_prefix)s*function)(%(invocation_args)s);
170 delete this;
171 }
172 }\
173 """
174
175 RESULT_RUN_DEFINITON = """\
176 virtual R Run(%(run_args)s) {
177 if (!del) {
178 R result = (%(deref_prefix)s*function_)(%(invocation_args)s);
179 return result;
180 } else {
181 Signature function = function_;
182 // Null-out pointer now to force a segfault if called again.
183 function_ = NULL;
184 R result = (%(deref_prefix)s*function)(%(invocation_args)s);
185 delete this;
186 return result;
187 }
188 }\
189 """
190
191
192 FACTORY_METHOD = """\
193 %(template_line)s
194 %(typename_prefix)s%(qualified_classname)s::base*
195 New%(variant)sCallback(%(factory_args)s) {
196 return new %(qualified_classname)s(%(constructor_args)s);
197 }
198 """
199
200 def GenerateRunDeclaration(return_type, args):
201 if return_type == ReturnType.VOID:
202 return_type = 'void'
203 elif return_type == ReturnType.RESULT:
204 return_type = 'R'
205 params = ', '.join(Expand('A%(n)d', args))
206 return RUN_DECLARATION % { 'return_type' : return_type, 'params' : params }
207
208
209 def GenerateSignatureTypeList(return_type, prebind, args):
210 template_params = []
211 if return_type == ReturnType.RESULT:
212 template_params.append('typename R')
213 template_params.extend(
214 ['typename P%d' % (x+1) for x in xrange(0, prebind)])
215 template_params.extend(
216 ['typename A%d' % (x+1) for x in xrange(0, args)])
217 return template_params
218
219
220 def GenerateTemplateLine(template_params):
221 return TEMPLATE_DECLARATION % ', '.join(template_params)
222
223
224 def PrintClosure(will_ref):
225 if will_ref == WillRef.NO:
226 name = 'Closure'
227 inherit = ''
228 if will_ref == WillRef.YES:
229 name = 'RefClosure'
230 inherit = ' : public Closure'
231 run_declaration = GenerateRunDeclaration(ReturnType.VOID, 0)
232 print CALLBACK_CLASS_BODY % { 'name' : name,
233 'methods' : STANDARD_METHODS,
234 'inherit' : inherit,
235 'run_declaration': run_declaration }
236
237
238 def PrintOneClass(return_type, args):
239 if return_type == ReturnType.VOID:
240 barename = 'Callback'
241 if return_type == ReturnType.RESULT:
242 barename = 'ResultCallback'
243
244 if args == 0:
245 name = barename
246 else:
247 name = '%s%d' % (barename, args)
248
249 run_declaration = GenerateRunDeclaration(return_type, args)
250 print GenerateTemplateLine(GenerateSignatureTypeList(return_type, 0, args))
251 print CALLBACK_CLASS_BODY % { 'name' : name,
252 'methods' : STANDARD_METHODS,
253 'inherit' : '',
254 'run_declaration': run_declaration }
255
256
257 def PrintCallbackClass(return_type, args):
258 if args == 0 and return_type == ReturnType.VOID:
259 # This is the pure Closure case. Generate the two closure classes.
260 PrintClosure(WillRef.NO);
261 PrintClosure(WillRef.YES);
262 else:
263 PrintOneClass(return_type, args)
264
265
266 def PrintTypes(year):
267 print HEADER % { 'year' : year, 'filesuffix' : 'TYPE', 'includes': '' }
268 for args in xrange(0, MAX_ARGS + 1):
269 PrintCallbackClass(ReturnType.VOID, args)
270 PrintCallbackClass(ReturnType.RESULT, args)
271 print FOOTER % { 'year' : year, 'filesuffix' : 'TYPE' }
272
273
274 def GenerateInterfaceName(return_type, args, will_ref):
275 if args == 0:
276 if will_ref == WillRef.YES:
277 return 'RefClosure'
278 elif will_ref == WillRef.NO:
279 return 'Closure'
280 arg_types = Expand('A%(n)d', args)
281 if return_type == ReturnType.VOID:
282 return 'Callback%d<%s>' % (args, ', '.join(arg_types))
283 elif return_type == ReturnType.RESULT:
284 result_args = ['R']
285 result_args.extend(arg_types)
286 return 'ResultCallback%d<%s>' % (args, ', '.join(result_args))
287
288
289 #TODO(ajwong): will_Ref is unused. remove.
290 def GenerateClassName(specialization_type, return_type, prebind, args, will_ref) :
291 base_name = "CB_"
292 if specialization_type == SpecializationType.CONST_METHOD:
293 base_name += 'ConstMethod'
294 elif specialization_type == SpecializationType.METHOD:
295 base_name += 'Method'
296 elif specialization_type == SpecializationType.FUNCTION:
297 base_name += 'Function'
298
299 if return_type == ReturnType.RESULT:
300 base_name += 'Result'
301
302 return "%sCallback_%d_%d" % (base_name, prebind, args)
303
304
305 def Expand(pattern, num):
306 return [pattern % {'n' : (x+1)} for x in xrange(0, num)]
307
308 def GeneratePrebindDeclaration(object_type, return_type, prebind, args, classnam e, interface_name, will_ref):
309 type_list = GenerateSignatureTypeList(return_type, prebind, args)
310
311 # Special case the 0-argument specialization for refcounted callbacks to
312 # derive from RefClosure instead of Closure so that interfaces can
313 # rely on the static type to ensure only refcounted closures are allowed.
314 if args == 0 and will_ref == WillRef.YES:
315 prebind_template_typelist = ['bool del']
316 specialization_list = ['del', 'true']
317 if object_type != '':
318 prebind_template_typelist.append('typename T')
319 specialization_list.append('T')
320 specialization_list.extend([x.split(' ')[1] for x in type_list])
321 specialization = '<%s>' % ', '.join(specialization_list)
322 else:
323 prebind_template_typelist = ['bool del', 'bool ref']
324 if object_type != '':
325 prebind_template_typelist.append('typename T')
326 specialization = ''
327
328 prebind_template_typelist.extend(type_list)
329 template_line = GenerateTemplateLine(prebind_template_typelist)
330
331 return PREBIND_DECLARATION % {'template_line': template_line,
332 'classname': classname + specialization,
333 'interface_name': interface_name}
334
335 def GenerateSignatureTemplate(specialization_type):
336 if specialization_type == SpecializationType.METHOD:
337 return '%s (T::*%s)(%s)'
338 elif specialization_type == SpecializationType.CONST_METHOD:
339 return '%s (T::*%s)(%s) const'
340 elif specialization_type == SpecializationType.FUNCTION:
341 return '%s (*%s)(%s)'
342
343
344 def GenerateTypedefs(specialization_type, return_type, prebind, args, interface_ name):
345 base_typedef = 'typedef %s base;' % interface_name
346 if return_type == ReturnType.RESULT:
347 return_string = 'R'
348 elif return_type == ReturnType.VOID:
349 return_string = 'void'
350
351 all_args = Expand('P%(n)d', prebind)
352 all_args.extend(Expand('A%(n)d', args))
353 arg_list = ', '.join(all_args)
354
355 signature_type = GenerateSignatureTemplate(specialization_type) % (return_stri ng, 'Signature', arg_list)
356 signature = 'typedef %s;' % signature_type
357 return '\n '.join([base_typedef, signature])
358
359
360 def GenerateObjectType(specialization_type):
361 if specialization_type == SpecializationType.METHOD:
362 return 'T*';
363 elif specialization_type == SpecializationType.CONST_METHOD:
364 return 'const T*'
365 elif specialization_type == SpecializationType.FUNCTION:
366 return ''
367
368
369 def GenerateStorage(object_type, prebind):
370 if object_type:
371 storage_decls = ['%s object_;' % object_type]
372 else:
373 storage_decls = []
374
375 storage_decls.append('Signature function_;')
376 storage_decls.extend(Expand('typename ::std::tr1::remove_reference<P%(n)d>::ty pe p%(n)d_;', prebind))
377 return '\n '.join(storage_decls)
378
379
380 def GenerateConstructor(object_type, prebind, classname, will_ref):
381 if will_ref == WillRef.YES:
382 ref = 'true'
383 elif will_ref == WillRef.NO:
384 ref = 'false'
385
386 if object_type:
387 constructor_arglist = ['%s object' % object_type]
388 body = METHOD_CONSTRUCTOR_BODY % ref
389 initializers = ['object_(object)', 'function_(function)']
390 else:
391 constructor_arglist = []
392 body = ' '
393 initializers = ['function_(function)']
394 constructor_arglist.append('Signature function')
395 constructor_arglist.extend(Expand('P%(n)d p%(n)d', prebind))
396 initializers.extend(Expand('p%(n)d_(p%(n)d)', prebind))
397 return CONSTRUCTOR_TEMPLATE % {'classname': classname,
398 'arglist': ', '.join(constructor_arglist),
399 'initializers': ',\n '.join(initializers),
400 'body': body }
401
402
403 def GenerateDestructor(object_type, classname, will_ref):
404 if will_ref == WillRef.YES:
405 ref = 'true'
406 elif will_ref == WillRef.NO:
407 ref = 'ref'
408
409 if object_type:
410 body = METHOD_DESTRUCTOR_BODY % ref
411 else:
412 body = ' '
413 return DESTRUCTOR_TEMPLATE % {'classname': classname, 'body': body}
414
415
416 def GenerateRunDefinition(object_type, return_type, prebind, args):
417 arg_list = Expand('A%(n)d a%(n)d', args)
418 invocation_list = Expand('p%(n)d_', prebind)
419 invocation_list.extend(Expand('a%(n)d', args))
420 params = {'run_args': ', '.join(arg_list),
421 'invocation_args': ', '.join(invocation_list)}
422 if object_type != '':
423 params['deref_prefix'] = 'object_->'
424 else:
425 params['deref_prefix'] = ''
426 if return_type == ReturnType.VOID:
427 return RUN_DEFINITON % params
428 elif return_type == ReturnType.RESULT:
429 return RESULT_RUN_DEFINITON % params
430
431
432 def PrintCallbackFactory(specialization_type, return_type, prebind, args, will_r ef, permanent):
433 if permanent:
434 specialization_list = ['false']
435 variant = 'Permanent'
436 else:
437 specialization_list = ['true']
438 variant = ''
439
440 if will_ref == WillRef.YES:
441 specialization_list.append('true')
442 variant += 'Ref'
443 else:
444 specialization_list.append('false')
445
446 if specialization_type == SpecializationType.METHOD:
447 factory_arglist = ['T* object']
448 constructor_arglist = ['object']
449 type_list = ['typename T']
450 elif specialization_type == SpecializationType.CONST_METHOD:
451 factory_arglist = ['const T* object']
452 constructor_arglist = ['object']
453 type_list = ['typename T']
454 elif specialization_type == SpecializationType.FUNCTION:
455 factory_arglist = []
456 constructor_arglist = []
457 type_list = []
458
459 type_list.extend(GenerateSignatureTypeList(return_type, prebind, args))
460 specialization_list.extend([x.split(' ')[1] for x in type_list])
461 if len(type_list) == 0:
462 typename_prefix = ''
463 else:
464 typename_prefix = 'typename '
465
466 classname = GenerateClassName(specialization_type, return_type, prebind, args, will_ref)
467 qualified_classname = '%s<%s>' % (classname, ', '.join(specialization_list))
468
469 arg_list = Expand('P%(n)d', prebind)
470 arg_list.extend(Expand('A%(n)d', args))
471 template = GenerateSignatureTemplate(specialization_type)
472 if return_type == ReturnType.VOID:
473 return_string = 'void'
474 elif return_type == ReturnType.RESULT:
475 return_string = 'R'
476 signature_arg = template % (return_string, 'function', ','.join(arg_list))
477 factory_arglist.append(signature_arg)
478 factory_arglist.extend(Expand('typename ::base::internal::Identity<P%(n)d>::ty pe p%(n)d', prebind))
479
480 constructor_arglist.append('function')
481 constructor_arglist.extend(Expand('p%(n)d', prebind))
482
483 params = {}
484 params['qualified_classname'] = qualified_classname
485 params['factory_args'] = ', '.join(factory_arglist)
486 params['constructor_args'] = ', '.join(constructor_arglist)
487 params['variant'] = variant
488 params['typename_prefix'] = typename_prefix
489
490 # In this base case, there are no templates.
491 if (specialization_type == SpecializationType.FUNCTION and
492 return_type == ReturnType.VOID and
493 args == 0 and prebind == 0):
494 params['template_line'] = ''
495 else:
496 params['template_line'] = 'template <%s>' % ', '.join(type_list)
497
498 print FACTORY_METHOD % params
499
500
501 #TODO(ajwong): We don't need all of these for function factories. Fix.
502 def PrintSpecializationClass(specialization_type, return_type, prebind, args):
503 PrintSpecializationClassHelper(specialization_type, return_type, WillRef.NO, p rebind, args)
504 PrintCallbackFactory(specialization_type, return_type, prebind, args, WillRef. NO, False)
505 PrintCallbackFactory(specialization_type, return_type, prebind, args, WillRef. NO, True)
506 if specialization_type != SpecializationType.FUNCTION:
507 if args == 0:
508 PrintSpecializationClassHelper(specialization_type, return_type, WillRef.Y ES, prebind, args)
509 PrintCallbackFactory(specialization_type, return_type, prebind, args, WillRe f.YES, False)
510 PrintCallbackFactory(specialization_type, return_type, prebind, args, WillRe f.YES, True)
511
512
513 def PrintSpecializationClassHelper(specialization_type, return_type, will_ref, p rebind, args):
514 classname = GenerateClassName(specialization_type, return_type, prebind, args, will_ref)
515 interface_name = GenerateInterfaceName(return_type, args, will_ref)
516 object_type = GenerateObjectType(specialization_type)
517
518 params = {}
519 params['class_decl'] = GeneratePrebindDeclaration(object_type, return_type, pr ebind, args, classname, interface_name, will_ref)
520 params['typedefs'] = GenerateTypedefs(specialization_type, return_type, prebin d, args, interface_name)
521 params['storage'] = GenerateStorage(object_type, prebind)
522 params['constructor'] = GenerateConstructor(object_type, prebind, classname, w ill_ref)
523 params['destructor'] = GenerateDestructor(object_type, classname, will_ref)
524 params['run_func'] = GenerateRunDefinition(object_type, return_type, prebind, args)
525
526 print PREBIND_CLASS % params
527
528
529 def PrintSpecializations(year):
530 includes = ['#include <tr1/type_traits>', '#include "base/ref_counted.h"']
531 print HEADER % {'year': year,
532 'filesuffix': 'SPECIALIZATIONS',
533 'includes': '\n'.join(includes)}
534 print SPECIALIZATION_HELPERS
535 for args in xrange(0, MAX_ARGS + 1):
536 for prebind in xrange(0, MAX_ARGS + 1):
537 PrintSpecializationClass(SpecializationType.METHOD, ReturnType.VOID, prebi nd, args)
538 PrintSpecializationClass(SpecializationType.METHOD, ReturnType.RESULT, pre bind, args)
539 PrintSpecializationClass(SpecializationType.CONST_METHOD, ReturnType.VOID, prebind, args)
540 PrintSpecializationClass(SpecializationType.CONST_METHOD, ReturnType.RESUL T, prebind, args)
541 PrintSpecializationClass(SpecializationType.FUNCTION, ReturnType.VOID, pre bind, args)
542 PrintSpecializationClass(SpecializationType.FUNCTION, ReturnType.RESULT, p rebind, args)
543 print FOOTER % { 'year' : year, 'filesuffix' : 'SPECIALIZATIONS' }
544
545
546 def main():
547 parser = OptionParser()
548 parser.add_option("-m", "--mode", dest="mode",
549 help="Either 'types' or 'specializations' to generate "
550 "either the types for all the callbacks, or the factory "
551 "methods and the corresponding specializations.")
552 (options, args) = parser.parse_args()
553
554 year = datetime.datetime.now().year
555 if options.mode == 'types':
556 PrintTypes(year)
557 elif options.mode == 'specializations':
558 PrintSpecializations(year)
559
560
561 if __name__ == '__main__':
562 main()
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698