import string, sys, re, os headers = ''' #include #include #include #include #include #include ''' form = string.Template(''' /* * Type-erased interface for: * * struct ${struct_name} * { ${comment_members} * }; * */ struct ${struct_name} { // Constructors ${struct_name} () = default; template ${struct_name} (PrivateDetailTypeErasedT value) : private_detail_te_handle_mem_var ( std::make_shared< private_detail_te_handle_type::type> >(std::forward(value)) ) {} // Assignment template ${struct_name} & operator= (PrivateDetailTypeErasedT value) { if (private_detail_te_handle_mem_var.unique()) *private_detail_te_handle_mem_var = std::forward(value); else if (!private_detail_te_handle_mem_var) private_detail_te_handle_mem_var = std::make_shared(std::forward(value)); return *this; } // Cast template PrivateDetailTypeErasedT * any_cast() { return private_detail_te_get_handle().type() == typeid(PrivateDetailTypeErasedT) ? std::addressof(static_cast::type> &>(private_detail_te_get_handle()).private_detail_te_value) : nullptr; } template const typename std::remove_cv::type * any_cast() const { return private_detail_te_get_handle().type() == typeid(PrivateDetailTypeErasedT) ? std::addressof(static_cast::type> &>(private_detail_te_get_handle()).private_detail_te_value) : nullptr; } const std::type_info& type_id() const { if(private_detail_te_handle_empty()) return typeid(std::nullptr_t); else return private_detail_te_get_handle().type(); } ${nonvirtual_members} private: struct private_detail_te_handle_base_type { virtual ~private_detail_te_handle_base_type () {} virtual std::shared_ptr clone () const = 0; virtual const std::type_info& type() const = 0; ${pure_virtual_members} }; template struct private_detail_te_handle_type : private_detail_te_handle_base_type { template private_detail_te_handle_type (PrivateDetailTypeErasedT value, typename std::enable_if< std::is_reference::value >::type * = nullptr) : private_detail_te_value (value) {} template private_detail_te_handle_type (PrivateDetailTypeErasedT value, typename std::enable_if< !std::is_reference::value, int >::type * = nullptr) noexcept : private_detail_te_value (std::move(value)) {} std::shared_ptr clone () const override { return std::make_shared(private_detail_te_value); } const std::type_info& type() const override { return typeid(private_detail_te_value); } ${virtual_members} PrivateDetailTypeErasedT private_detail_te_value; }; template struct private_detail_te_handle_type> : private_detail_te_handle_type { private_detail_te_handle_type (std::reference_wrapper ref) : private_detail_te_handle_type (ref.get()) {} }; bool private_detail_te_handle_empty() const { return private_detail_te_handle_mem_var == nullptr; } const private_detail_te_handle_base_type & private_detail_te_get_handle () const { assert(private_detail_te_handle_mem_var != nullptr); return *private_detail_te_handle_mem_var; } private_detail_te_handle_base_type & private_detail_te_get_handle () { assert(private_detail_te_handle_mem_var != nullptr); if (!private_detail_te_handle_mem_var.unique()) private_detail_te_handle_mem_var = private_detail_te_handle_mem_var->clone(); return *private_detail_te_handle_mem_var; } std::shared_ptr private_detail_te_handle_mem_var; }; template inline const ValueType * any_cast(const ${struct_name} * x) { return x->any_cast(); } template inline ValueType * any_cast(${struct_name} * x) { return x->any_cast(); } template inline ValueType & any_cast(${struct_name} & x) { auto * y = x.any_cast::type>(); if (y == nullptr) throw std::bad_cast(); return *y; } template inline const ValueType & any_cast(const ${struct_name} & x) { const auto * y = x.any_cast::type>(); if (y == nullptr) throw std::bad_cast(); return *y; } ''') nonvirtual_member = string.Template(''' ${friend} ${return_type} ${name}(${params}) ${const} { assert(${this}.private_detail_te_handle_mem_var); return ${this}.private_detail_te_get_handle().${internal_name}(${member_args}); } ''') pure_virtual_member = string.Template("virtual ${return_type} ${internal_name}(${member_params}) ${member_const} = 0;\n") virtual_member = string.Template(''' ${return_type} ${internal_name}(${member_params}) ${member_const} override { ${using} return ${call}; } ''') comment_member = string.Template('''* ${friend} ${return_type} ${name}(${params}) ${const};''') def trim_type_name(name): n = name.strip() if n.startswith('const'): return trim_type_name(n[5:]) if n.endswith(('&', '*')): return trim_type_name(n[0:-1]) return n def internal_name(name): internal_names = { 'operator<<': 'operator_shift_left', 'operator>>': 'operator_shift_right', } if name in internal_names: return internal_names[name] else: return name def generate_call(m, friend, indirect): if m['name'].startswith('operator'): op = m['name'][8:] args = m['args'] if ',' in args: return args.replace(',', op) else: return string.Template('${op}${args}').substitute(op=op, args=args) if friend: return string.Template('${name}(${args})').substitute(m) if indirect: if m['args']: return string.Template('${default}(private_detail_te_value, ${args})').substitute(m) else: return string.Template('${default}(private_detail_te_value)').substitute(m) return string.Template('private_detail_te_value.${name}(${args})').substitute(m) def convert_member(d, struct_name): for name in d: member = { 'name': name, 'internal_name': internal_name(name), 'const': '', 'member_const': '', 'friend': '', 'this': '(*this)', 'using': '' } args = [] params = [] member_args = [] member_params = [] skip = False friend = False indirect = False if 'friend' in d[name]: friend = True skip = True if 'default' in d[name]: indirect = True for x in d[name]: t = d[name][x] if x == 'return': member['return_type'] = t elif x == 'const': member['const'] = 'const' member['member_const'] = 'const' elif x == 'friend': member['friend'] = 'friend' elif x == 'default': member['default'] = t elif x == 'using': member['using'] = 'using {};'.format(d[name]['using']) elif x.startswith('__') and x.endswith('__'): continue else: use_member = not(skip and struct_name == trim_type_name(t)) arg_name = x if not use_member: arg_name = 'private_detail_te_value' member['this'] = x if 'const' in t: member['member_const'] = 'const' if t.endswith(('&', '*')): if use_member: member_args.append(x) args.append(arg_name) else: if use_member: member_args.append('std::move({})'.format(x)) args.append('std::move({})'.format(arg_name)) params.append(t+' '+x) if use_member: member_params.append(t+' '+x) else: skip = False member['args'] = ','.join(args) member['member_args'] = ','.join(member_args) member['params'] = ','.join(params) member['params'] = ','.join(params) member['member_params'] = ','.join(member_params) member['call'] = generate_call(member, friend, indirect) return member return None def generate_form(name, members): nonvirtual_members = [] pure_virtual_members = [] virtual_members = [] comment_members = [] for member in members: m = convert_member(member, name) nonvirtual_members.append(nonvirtual_member.substitute(m)) pure_virtual_members.append(pure_virtual_member.substitute(m)) virtual_members.append(virtual_member.substitute(m)) comment_members.append(comment_member.substitute(m)) return form.substitute( nonvirtual_members=''.join(nonvirtual_members), pure_virtual_members=''.join(pure_virtual_members), virtual_members=''.join(virtual_members), comment_members='\n'.join(comment_members), struct_name=name ) def virtual(name, returns=None, **kwargs): args = kwargs args['return'] = returns return { name: args } def friend(name, returns=None, **kwargs): args = kwargs args['return'] = returns args['friend'] = 'friend' return { name: args } def interface(name, *members): return generate_form(name, members) def template_eval(template,**kwargs): start = '<%' end = '%>' escaped = (re.escape(start), re.escape(end)) mark = re.compile('%s(.*?)%s' % escaped, re.DOTALL) for key in kwargs: exec('%s = %s' % (key, kwargs[key])) for item in mark.findall(template): template = template.replace(start+item+end, str(eval(item.strip()))) return template f = open(sys.argv[1]).read() r = template_eval(f) sys.stdout.write(r)