| 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()
|
|
|