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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/generate_callback_templates.py
diff --git a/base/generate_callback_templates.py b/base/generate_callback_templates.py
new file mode 100755
index 0000000000000000000000000000000000000000..17f87185ce69bf467cb06414dd42df19e614f7bb
--- /dev/null
+++ b/base/generate_callback_templates.py
@@ -0,0 +1,562 @@
+#!/usr/bin/python
+
+# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Geneartes the types and factory methods needed for Callbacks.
+
+See base/callback.h for details on the callback system.
+"""
+
+import datetime
+from optparse import OptionParser
+
+# Supporting functions and methods up to 5 arguments seems to be good enough
+# for most use cases. The historical callback mechanisms in Chrome only
+# only supported 5 arguments, and did not have issues. Increase this value if
+# necessary. The cost is for each argument, you get N more sets of factory
+# methods, and one more set of callbck classes.
+MAX_ARGS=5
+
+# Enum type for specifying the return type of a callback.
+class ReturnType:
+ VOID = 0
+ RESULT = 1
+
+
+# Enum type for specifying if we need to generate a template for a
+# callback that Refcounts the object it wraps.
+class WillRef:
+ YES = 0
+ NO = 1
+
+class SpecializationType:
+ METHOD = 0
+ CONST_METHOD = 1
+ FUNCTION = 2
+
+
+HEADER = """\
+// Copyright (c) %(year)d The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is automatically generated by base/generate_callback_templates.py.
+// DO NOT EDIT!
+
+#ifndef BASE_CALLBACK_%(filesuffix)s_H_
+
+%(includes)s
+
+namespace base {
+"""
+
+FOOTER = """\
+} // namespace base
+
+#endif // BASE_CALLBACK_%(filesuffix)s_H_
+"""
+
+
+CALLBACK_CLASS_BODY = """\
+class %(name)s%(inherit)s {
+ public:
+ virtual ~%(name)s() { }%(methods)s
+ %(run_declaration)s
+};
+"""
+
+
+TEMPLATE_DECLARATION = """template <%s>"""
+
+
+RUN_DECLARATION = "virtual %(return_type)s Run(%(params)s) = 0;"
+
+
+STANDARD_METHODS = """
+ virtual bool IsRepeatable() const { return false; }"""
+
+PREBIND_DECLARATION = """\
+%(template_line)s
+class %(classname)s : public %(interface_name)s"""
+
+PREBIND_TYPEDEFS = """\
+ typedef %(interface_name)s base;
+ typedef %(return_type)s (T::*Signature)()%(spacer)s%(const)s;
+"""
+
+METHOD_CONSTRUCTOR_BODY = """
+ ::base::internal::RefUtil<%s, T>::TakeRef(object_);
+ \
+"""
+
+METHOD_DESTRUCTOR_BODY = """
+ ::base::internal::RefUtil<%s, T>::ReleaseRef(object_);
+ \
+"""
+
+CONSTRUCTOR_TEMPLATE = """\
+inline %(classname)s(%(arglist)s)
+ : %(initializers)s {%(body)s}
+"""
+
+DESTRUCTOR_TEMPLATE = """\
+virtual ~%(classname)s() {%(body)s}
+"""
+
+PREBIND_CLASS = """
+%(class_decl)s {
+ public:
+ %(typedefs)s
+
+ private:
+ %(storage)s
+
+ public:
+ %(constructor)s
+ %(destructor)s
+ virtual bool IsRepeatable() const {
+ return !del;
+ }
+
+ %(run_func)s
+};
+"""
+
+
+SPECIALIZATION_HELPERS = """\
+namespace internal {
+template <bool ref, typename T>
+class RefUtil {
+ public:
+ static inline void TakeRef(T* object) {
+ static_cast<typename ::base::RefCountedThreadSafe<T>*>(object)->AddRef();
+ }
+
+ static inline void ReleaseRef(T* object) {
+ static_cast<typename ::base::RefCountedThreadSafe<T>*>(object)->Release();
+ }
+};
+
+template <typename T>
+class RefUtil<false, T> {
+ public:
+ static inline void TakeRef(T* object) {
+ }
+
+ static inline void ReleaseRef(T* object) {
+ }
+};
+
+// Identity<T>::type is a typedef of T. Useful for preventing the
+// compiler from inferring the type of an argument in templates.
+template <typename T>
+struct Identity {
+ typedef T type;
+};
+} // namespace internal
+"""
+
+RUN_DEFINITON = """\
+virtual void Run(%(run_args)s) {
+ if (!del) {
+ (%(deref_prefix)s*function_)(%(invocation_args)s);
+ } else {
+ Signature function = function_;
+ // Null-out pointer now to force sefault if called again.
+ function_ = NULL;
+ (%(deref_prefix)s*function)(%(invocation_args)s);
+ delete this;
+ }
+ }\
+"""
+
+RESULT_RUN_DEFINITON = """\
+virtual R Run(%(run_args)s) {
+ if (!del) {
+ R result = (%(deref_prefix)s*function_)(%(invocation_args)s);
+ return result;
+ } else {
+ Signature function = function_;
+ // Null-out pointer now to force a segfault if called again.
+ function_ = NULL;
+ R result = (%(deref_prefix)s*function)(%(invocation_args)s);
+ delete this;
+ return result;
+ }
+ }\
+"""
+
+
+FACTORY_METHOD = """\
+%(template_line)s
+%(typename_prefix)s%(qualified_classname)s::base*
+New%(variant)sCallback(%(factory_args)s) {
+ return new %(qualified_classname)s(%(constructor_args)s);
+}
+"""
+
+def GenerateRunDeclaration(return_type, args):
+ if return_type == ReturnType.VOID:
+ return_type = 'void'
+ elif return_type == ReturnType.RESULT:
+ return_type = 'R'
+ params = ', '.join(Expand('A%(n)d', args))
+ return RUN_DECLARATION % { 'return_type' : return_type, 'params' : params }
+
+
+def GenerateSignatureTypeList(return_type, prebind, args):
+ template_params = []
+ if return_type == ReturnType.RESULT:
+ template_params.append('typename R')
+ template_params.extend(
+ ['typename P%d' % (x+1) for x in xrange(0, prebind)])
+ template_params.extend(
+ ['typename A%d' % (x+1) for x in xrange(0, args)])
+ return template_params
+
+
+def GenerateTemplateLine(template_params):
+ return TEMPLATE_DECLARATION % ', '.join(template_params)
+
+
+def PrintClosure(will_ref):
+ if will_ref == WillRef.NO:
+ name = 'Closure'
+ inherit = ''
+ if will_ref == WillRef.YES:
+ name = 'RefClosure'
+ inherit = ' : public Closure'
+ run_declaration = GenerateRunDeclaration(ReturnType.VOID, 0)
+ print CALLBACK_CLASS_BODY % { 'name' : name,
+ 'methods' : STANDARD_METHODS,
+ 'inherit' : inherit,
+ 'run_declaration': run_declaration }
+
+
+def PrintOneClass(return_type, args):
+ if return_type == ReturnType.VOID:
+ barename = 'Callback'
+ if return_type == ReturnType.RESULT:
+ barename = 'ResultCallback'
+
+ if args == 0:
+ name = barename
+ else:
+ name = '%s%d' % (barename, args)
+
+ run_declaration = GenerateRunDeclaration(return_type, args)
+ print GenerateTemplateLine(GenerateSignatureTypeList(return_type, 0, args))
+ print CALLBACK_CLASS_BODY % { 'name' : name,
+ 'methods' : STANDARD_METHODS,
+ 'inherit' : '',
+ 'run_declaration': run_declaration }
+
+
+def PrintCallbackClass(return_type, args):
+ if args == 0 and return_type == ReturnType.VOID:
+ # This is the pure Closure case. Generate the two closure classes.
+ PrintClosure(WillRef.NO);
+ PrintClosure(WillRef.YES);
+ else:
+ PrintOneClass(return_type, args)
+
+
+def PrintTypes(year):
+ print HEADER % { 'year' : year, 'filesuffix' : 'TYPE', 'includes': '' }
+ for args in xrange(0, MAX_ARGS + 1):
+ PrintCallbackClass(ReturnType.VOID, args)
+ PrintCallbackClass(ReturnType.RESULT, args)
+ print FOOTER % { 'year' : year, 'filesuffix' : 'TYPE' }
+
+
+def GenerateInterfaceName(return_type, args, will_ref):
+ if args == 0:
+ if will_ref == WillRef.YES:
+ return 'RefClosure'
+ elif will_ref == WillRef.NO:
+ return 'Closure'
+ arg_types = Expand('A%(n)d', args)
+ if return_type == ReturnType.VOID:
+ return 'Callback%d<%s>' % (args, ', '.join(arg_types))
+ elif return_type == ReturnType.RESULT:
+ result_args = ['R']
+ result_args.extend(arg_types)
+ return 'ResultCallback%d<%s>' % (args, ', '.join(result_args))
+
+
+#TODO(ajwong): will_Ref is unused. remove.
+def GenerateClassName(specialization_type, return_type, prebind, args, will_ref):
+ base_name = "CB_"
+ if specialization_type == SpecializationType.CONST_METHOD:
+ base_name += 'ConstMethod'
+ elif specialization_type == SpecializationType.METHOD:
+ base_name += 'Method'
+ elif specialization_type == SpecializationType.FUNCTION:
+ base_name += 'Function'
+
+ if return_type == ReturnType.RESULT:
+ base_name += 'Result'
+
+ return "%sCallback_%d_%d" % (base_name, prebind, args)
+
+
+def Expand(pattern, num):
+ return [pattern % {'n' : (x+1)} for x in xrange(0, num)]
+
+def GeneratePrebindDeclaration(object_type, return_type, prebind, args, classname, interface_name, will_ref):
+ type_list = GenerateSignatureTypeList(return_type, prebind, args)
+
+ # Special case the 0-argument specialization for refcounted callbacks to
+ # derive from RefClosure instead of Closure so that interfaces can
+ # rely on the static type to ensure only refcounted closures are allowed.
+ if args == 0 and will_ref == WillRef.YES:
+ prebind_template_typelist = ['bool del']
+ specialization_list = ['del', 'true']
+ if object_type != '':
+ prebind_template_typelist.append('typename T')
+ specialization_list.append('T')
+ specialization_list.extend([x.split(' ')[1] for x in type_list])
+ specialization = '<%s>' % ', '.join(specialization_list)
+ else:
+ prebind_template_typelist = ['bool del', 'bool ref']
+ if object_type != '':
+ prebind_template_typelist.append('typename T')
+ specialization = ''
+
+ prebind_template_typelist.extend(type_list)
+ template_line = GenerateTemplateLine(prebind_template_typelist)
+
+ return PREBIND_DECLARATION % {'template_line': template_line,
+ 'classname': classname + specialization,
+ 'interface_name': interface_name}
+
+def GenerateSignatureTemplate(specialization_type):
+ if specialization_type == SpecializationType.METHOD:
+ return '%s (T::*%s)(%s)'
+ elif specialization_type == SpecializationType.CONST_METHOD:
+ return '%s (T::*%s)(%s) const'
+ elif specialization_type == SpecializationType.FUNCTION:
+ return '%s (*%s)(%s)'
+
+
+def GenerateTypedefs(specialization_type, return_type, prebind, args, interface_name):
+ base_typedef = 'typedef %s base;' % interface_name
+ if return_type == ReturnType.RESULT:
+ return_string = 'R'
+ elif return_type == ReturnType.VOID:
+ return_string = 'void'
+
+ all_args = Expand('P%(n)d', prebind)
+ all_args.extend(Expand('A%(n)d', args))
+ arg_list = ', '.join(all_args)
+
+ signature_type = GenerateSignatureTemplate(specialization_type) % (return_string, 'Signature', arg_list)
+ signature = 'typedef %s;' % signature_type
+ return '\n '.join([base_typedef, signature])
+
+
+def GenerateObjectType(specialization_type):
+ if specialization_type == SpecializationType.METHOD:
+ return 'T*';
+ elif specialization_type == SpecializationType.CONST_METHOD:
+ return 'const T*'
+ elif specialization_type == SpecializationType.FUNCTION:
+ return ''
+
+
+def GenerateStorage(object_type, prebind):
+ if object_type:
+ storage_decls = ['%s object_;' % object_type]
+ else:
+ storage_decls = []
+
+ storage_decls.append('Signature function_;')
+ storage_decls.extend(Expand('typename ::std::tr1::remove_reference<P%(n)d>::type p%(n)d_;', prebind))
+ return '\n '.join(storage_decls)
+
+
+def GenerateConstructor(object_type, prebind, classname, will_ref):
+ if will_ref == WillRef.YES:
+ ref = 'true'
+ elif will_ref == WillRef.NO:
+ ref = 'false'
+
+ if object_type:
+ constructor_arglist = ['%s object' % object_type]
+ body = METHOD_CONSTRUCTOR_BODY % ref
+ initializers = ['object_(object)', 'function_(function)']
+ else:
+ constructor_arglist = []
+ body = ' '
+ initializers = ['function_(function)']
+ constructor_arglist.append('Signature function')
+ constructor_arglist.extend(Expand('P%(n)d p%(n)d', prebind))
+ initializers.extend(Expand('p%(n)d_(p%(n)d)', prebind))
+ return CONSTRUCTOR_TEMPLATE % {'classname': classname,
+ 'arglist': ', '.join(constructor_arglist),
+ 'initializers': ',\n '.join(initializers),
+ 'body': body }
+
+
+def GenerateDestructor(object_type, classname, will_ref):
+ if will_ref == WillRef.YES:
+ ref = 'true'
+ elif will_ref == WillRef.NO:
+ ref = 'ref'
+
+ if object_type:
+ body = METHOD_DESTRUCTOR_BODY % ref
+ else:
+ body = ' '
+ return DESTRUCTOR_TEMPLATE % {'classname': classname, 'body': body}
+
+
+def GenerateRunDefinition(object_type, return_type, prebind, args):
+ arg_list = Expand('A%(n)d a%(n)d', args)
+ invocation_list = Expand('p%(n)d_', prebind)
+ invocation_list.extend(Expand('a%(n)d', args))
+ params = {'run_args': ', '.join(arg_list),
+ 'invocation_args': ', '.join(invocation_list)}
+ if object_type != '':
+ params['deref_prefix'] = 'object_->'
+ else:
+ params['deref_prefix'] = ''
+ if return_type == ReturnType.VOID:
+ return RUN_DEFINITON % params
+ elif return_type == ReturnType.RESULT:
+ return RESULT_RUN_DEFINITON % params
+
+
+def PrintCallbackFactory(specialization_type, return_type, prebind, args, will_ref, permanent):
+ if permanent:
+ specialization_list = ['false']
+ variant = 'Permanent'
+ else:
+ specialization_list = ['true']
+ variant = ''
+
+ if will_ref == WillRef.YES:
+ specialization_list.append('true')
+ variant += 'Ref'
+ else:
+ specialization_list.append('false')
+
+ if specialization_type == SpecializationType.METHOD:
+ factory_arglist = ['T* object']
+ constructor_arglist = ['object']
+ type_list = ['typename T']
+ elif specialization_type == SpecializationType.CONST_METHOD:
+ factory_arglist = ['const T* object']
+ constructor_arglist = ['object']
+ type_list = ['typename T']
+ elif specialization_type == SpecializationType.FUNCTION:
+ factory_arglist = []
+ constructor_arglist = []
+ type_list = []
+
+ type_list.extend(GenerateSignatureTypeList(return_type, prebind, args))
+ specialization_list.extend([x.split(' ')[1] for x in type_list])
+ if len(type_list) == 0:
+ typename_prefix = ''
+ else:
+ typename_prefix = 'typename '
+
+ classname = GenerateClassName(specialization_type, return_type, prebind, args, will_ref)
+ qualified_classname = '%s<%s>' % (classname, ', '.join(specialization_list))
+
+ arg_list = Expand('P%(n)d', prebind)
+ arg_list.extend(Expand('A%(n)d', args))
+ template = GenerateSignatureTemplate(specialization_type)
+ if return_type == ReturnType.VOID:
+ return_string = 'void'
+ elif return_type == ReturnType.RESULT:
+ return_string = 'R'
+ signature_arg = template % (return_string, 'function', ','.join(arg_list))
+ factory_arglist.append(signature_arg)
+ factory_arglist.extend(Expand('typename ::base::internal::Identity<P%(n)d>::type p%(n)d', prebind))
+
+ constructor_arglist.append('function')
+ constructor_arglist.extend(Expand('p%(n)d', prebind))
+
+ params = {}
+ params['qualified_classname'] = qualified_classname
+ params['factory_args'] = ', '.join(factory_arglist)
+ params['constructor_args'] = ', '.join(constructor_arglist)
+ params['variant'] = variant
+ params['typename_prefix'] = typename_prefix
+
+ # In this base case, there are no templates.
+ if (specialization_type == SpecializationType.FUNCTION and
+ return_type == ReturnType.VOID and
+ args == 0 and prebind == 0):
+ params['template_line'] = ''
+ else:
+ params['template_line'] = 'template <%s>' % ', '.join(type_list)
+
+ print FACTORY_METHOD % params
+
+
+#TODO(ajwong): We don't need all of these for function factories. Fix.
+def PrintSpecializationClass(specialization_type, return_type, prebind, args):
+ PrintSpecializationClassHelper(specialization_type, return_type, WillRef.NO, prebind, args)
+ PrintCallbackFactory(specialization_type, return_type, prebind, args, WillRef.NO, False)
+ PrintCallbackFactory(specialization_type, return_type, prebind, args, WillRef.NO, True)
+ if specialization_type != SpecializationType.FUNCTION:
+ if args == 0:
+ PrintSpecializationClassHelper(specialization_type, return_type, WillRef.YES, prebind, args)
+ PrintCallbackFactory(specialization_type, return_type, prebind, args, WillRef.YES, False)
+ PrintCallbackFactory(specialization_type, return_type, prebind, args, WillRef.YES, True)
+
+
+def PrintSpecializationClassHelper(specialization_type, return_type, will_ref, prebind, args):
+ classname = GenerateClassName(specialization_type, return_type, prebind, args, will_ref)
+ interface_name = GenerateInterfaceName(return_type, args, will_ref)
+ object_type = GenerateObjectType(specialization_type)
+
+ params = {}
+ params['class_decl'] = GeneratePrebindDeclaration(object_type, return_type, prebind, args, classname, interface_name, will_ref)
+ params['typedefs'] = GenerateTypedefs(specialization_type, return_type, prebind, args, interface_name)
+ params['storage'] = GenerateStorage(object_type, prebind)
+ params['constructor'] = GenerateConstructor(object_type, prebind, classname, will_ref)
+ params['destructor'] = GenerateDestructor(object_type, classname, will_ref)
+ params['run_func'] = GenerateRunDefinition(object_type, return_type, prebind, args)
+
+ print PREBIND_CLASS % params
+
+
+def PrintSpecializations(year):
+ includes = ['#include <tr1/type_traits>', '#include "base/ref_counted.h"']
+ print HEADER % {'year': year,
+ 'filesuffix': 'SPECIALIZATIONS',
+ 'includes': '\n'.join(includes)}
+ print SPECIALIZATION_HELPERS
+ for args in xrange(0, MAX_ARGS + 1):
+ for prebind in xrange(0, MAX_ARGS + 1):
+ PrintSpecializationClass(SpecializationType.METHOD, ReturnType.VOID, prebind, args)
+ PrintSpecializationClass(SpecializationType.METHOD, ReturnType.RESULT, prebind, args)
+ PrintSpecializationClass(SpecializationType.CONST_METHOD, ReturnType.VOID, prebind, args)
+ PrintSpecializationClass(SpecializationType.CONST_METHOD, ReturnType.RESULT, prebind, args)
+ PrintSpecializationClass(SpecializationType.FUNCTION, ReturnType.VOID, prebind, args)
+ PrintSpecializationClass(SpecializationType.FUNCTION, ReturnType.RESULT, prebind, args)
+ print FOOTER % { 'year' : year, 'filesuffix' : 'SPECIALIZATIONS' }
+
+
+def main():
+ parser = OptionParser()
+ parser.add_option("-m", "--mode", dest="mode",
+ help="Either 'types' or 'specializations' to generate "
+ "either the types for all the callbacks, or the factory "
+ "methods and the corresponding specializations.")
+ (options, args) = parser.parse_args()
+
+ year = datetime.datetime.now().year
+ if options.mode == 'types':
+ PrintTypes(year)
+ elif options.mode == 'specializations':
+ PrintSpecializations(year)
+
+
+if __name__ == '__main__':
+ main()
« 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