Пример #1
0
    def __init__(self, yamlfile, install_dir, package_name, io_handlers,
                 verbose, dryrun):
        self.install_dir = install_dir
        self.package_name = package_name
        self.io_handlers = io_handlers
        self.verbose = verbose
        self.dryrun = dryrun
        self.yamlfile = yamlfile

        self.reader = PodioConfigReader(yamlfile)
        self.reader.read()
        self.include_subfolder = self.reader.options["includeSubfolder"]

        self.env = jinja2.Environment(
            loader=jinja2.FileSystemLoader(TEMPLATE_DIR),
            keep_trailing_newline=True,
            lstrip_blocks=True,
            trim_blocks=True)

        self.get_syntax = self.reader.options["getSyntax"]
        self.incfolder = self.package_name + "/" if self.reader.options[
            "includeSubfolder"] else ""
        self.expose_pod_members = self.reader.options["exposePODMembers"]

        self.clang_format = []
Пример #2
0
    def __init__(self, yamlfile, install_dir, package_name,
                 verbose=True, getSyntax=False):

        self.yamlfile = yamlfile
        self.install_dir = install_dir
        self.package_name = package_name
        self.template_dir = os.path.join(thisdir, "../templates")
        self.verbose = verbose
        self.getSyntax = getSyntax
        self.buildin_types = ClassDefinitionValidator.buildin_types
        self.created_classes = []
        self.requested_classes = []
        self.reader = PodioConfigReader(yamlfile)
        self.warnings = []
Пример #3
0
 def __init__(self,yamlfile, install_dir, package_name, verbose = True):
   self.yamlfile = yamlfile
   self.install_dir = install_dir
   self.package_name =package_name
   self.template_dir = os.path.join(thisdir,"../templates")
   self.verbose=verbose
   self.buildin_types = ["int","float","double","unsigned int","unsigned","short","bool","longlong","ulonglong"]
   self.created_classes = []
   self.requested_classes = []
   self.reader = PodioConfigReader(yamlfile)
   self.warnings = []
Пример #4
0
class ClassGenerator(object):
    def __init__(self, yamlfile, install_dir, package_name, io_handlers,
                 verbose, dryrun):
        self.install_dir = install_dir
        self.package_name = package_name
        self.io_handlers = io_handlers
        self.verbose = verbose
        self.dryrun = dryrun
        self.yamlfile = yamlfile

        self.reader = PodioConfigReader(yamlfile)
        self.reader.read()
        self.include_subfolder = self.reader.options["includeSubfolder"]

        self.env = jinja2.Environment(
            loader=jinja2.FileSystemLoader(TEMPLATE_DIR),
            keep_trailing_newline=True,
            lstrip_blocks=True,
            trim_blocks=True)

        self.get_syntax = self.reader.options["getSyntax"]
        self.incfolder = self.package_name + "/" if self.reader.options[
            "includeSubfolder"] else ""
        self.expose_pod_members = self.reader.options["exposePODMembers"]

        self.clang_format = []

    def process(self):
        for name, component in self.reader.components.items():
            self._process_component(name, component)

        for name, datatype in self.reader.datatypes.items():
            self._process_datatype(name, datatype)

        if 'ROOT' in self.io_handlers:
            self._create_selection_xml()
        self.print_report()

    def print_report(self):
        if not self.verbose:
            return

        with open(os.path.join(THIS_DIR, "figure.txt"), 'rb') as pkl:
            figure = pickle.load(pkl)

        nclasses = 5 * len(self.reader.datatypes) + len(self.reader.components)
        text = REPORT_TEXT.format(yamlfile=self.yamlfile,
                                  nclasses=nclasses,
                                  installdir=self.install_dir)

        print()
        for figline, summaryline in zip_longest(figure,
                                                text.splitlines(),
                                                fillvalue=''):
            print(figline + summaryline)
        print("     'Homage to the Square' - Josef Albers")
        print()

    def _eval_template(self, template, data):
        """Fill the specified template"""
        return self.env.get_template(template).render(data)

    def _write_file(self, name, content):
        """Write the content to file. Dispatch to the correct directory depending on
    whether it is a header or a .cc file."""
        if name.endswith("h"):
            fullname = os.path.join(self.install_dir, self.package_name, name)
        else:
            fullname = os.path.join(self.install_dir, "src", name)
        if not self.dryrun:
            if self.clang_format:
                cfproc = subprocess.Popen(self.clang_format,
                                          stdin=subprocess.PIPE,
                                          stdout=subprocess.PIPE)
                content = cfproc.communicate(
                    input=content.encode())[0].decode()

            try:
                with open(fullname, 'r') as f:
                    existing_content = f.read()
                    changed = existing_content != content

            except EnvironmentError as e:
                # If we deprecate python2 support, FileNotFoundError becomes available
                # and this can be using it. For now we keep it compatible with both
                # versions
                if e.errno != errno.ENOENT:
                    raise
                changed = True

            if changed:
                with open(fullname, 'w') as f:
                    f.write(content)

    @staticmethod
    def _get_filenames_templates(template_base, name):
        """Get the list of output filenames and corresponding template names"""
        # depending on which category is passed different naming conventions apply
        # for the generated files. Additionally not all categories need source files.
        # Listing the special cases here
        fn_base = {
            'Data': 'Data',
            'Obj': 'Obj',
            'ConstObject': 'Const',
            'PrintInfo': 'PrintInfo',
            'Object': '',
            'Component': '',
            'SIOBlock': 'SIOBlock',
        }.get(template_base, template_base)

        endings = {
            'Data': ('h', ),
            'Component': ('h', ),
            'PrintInfo': ('h', )
        }.get(template_base, ('h', 'cc'))

        fn_templates = []
        for ending in endings:
            template_name = '{fn}.{end}.jinja2'.format(fn=template_base,
                                                       end=ending)
            filename = '{name}{fn}.{end}'.format(fn=fn_base,
                                                 name=name,
                                                 end=ending)
            fn_templates.append((filename, template_name))

        return fn_templates

    def _fill_templates(self, template_base, data):
        """Fill the template and write the results to file"""
        # Update the passed data with some global things that are the same for all
        # files
        data['package_name'] = self.package_name
        data['use_get_syntax'] = self.get_syntax
        data['incfolder'] = self.incfolder

        for filename, template in self._get_filenames_templates(
                template_base, data['class'].bare_type):
            self._write_file(filename, self._eval_template(template, data))

    def _process_component(self, name, component):
        """Process one component"""
        includes = set()
        if any(m.is_array for m in component['Members']):
            includes.add('#include <array>')

        for member in component['Members']:
            if member.full_type in self.reader.components or member.array_type in self.reader.components:
                includes.add(self._build_include(member.bare_type))

        includes.update(
            component.get("ExtraCode", {}).get("includes", "").split('\n'))

        component['includes'] = self._sort_includes(includes)
        component['class'] = DataType(name)

        self._fill_templates('Component', component)

    def _process_datatype(self, name, definition):
        """Process one datatype"""
        datatype = self._preprocess_datatype(name, definition)
        self._fill_templates('Data', datatype)
        self._fill_templates('Object', datatype)
        self._fill_templates('ConstObject', datatype)
        self._fill_templates('Obj', datatype)
        self._fill_templates('Collection', datatype)

        if 'SIO' in self.io_handlers:
            self._fill_templates('SIOBlock', datatype)

    def _preprocess_for_obj(self, datatype):
        """Do the preprocessing that is necessary for the Obj classes"""
        fwd_declarations = {}
        includes, includes_cc = set(), set()

        for relation in datatype['OneToOneRelations']:
            if not relation.is_builtin:
                relation.relation_type = relation.as_qualified_const()

            if relation.full_type != datatype['class'].full_type:
                if relation.namespace not in fwd_declarations:
                    fwd_declarations[relation.namespace] = []
                fwd_declarations[relation.namespace].append('Const' +
                                                            relation.bare_type)
                includes_cc.add(
                    self._build_include(relation.bare_type + 'Const'))

        if datatype['VectorMembers'] or datatype['OneToManyRelations']:
            includes.add('#include <vector>')
            includes.add('#include "podio/RelationRange.h"')

        for relation in datatype['VectorMembers'] + datatype[
                'OneToManyRelations']:
            if not relation.is_builtin:
                if relation.full_type not in self.reader.components:
                    relation.relation_type = relation.as_qualified_const()

                if relation.full_type == datatype['class'].full_type:
                    includes_cc.add(
                        self._build_include(datatype['class'].bare_type))
                else:
                    includes.add(self._build_include(relation.bare_type))

        datatype['forward_declarations_obj'] = fwd_declarations
        datatype['includes_obj'] = self._sort_includes(includes)
        datatype['includes_cc_obj'] = self._sort_includes(includes_cc)

    def _preprocess_for_class(self, datatype):
        """Do the preprocessing that is necessary for the classes and Const classes"""
        includes = set(datatype['includes_data'])
        fwd_declarations = {}
        includes_cc = set()

        for member in datatype["Members"]:
            if self.expose_pod_members and not member.is_builtin and not member.is_array:
                member.sub_members = self.reader.components[
                    member.full_type]['Members']

        for relation in datatype['OneToOneRelations']:
            if self._needs_include(relation):
                if relation.namespace not in fwd_declarations:
                    fwd_declarations[relation.namespace] = []
                fwd_declarations[relation.namespace].append(relation.bare_type)
                fwd_declarations[relation.namespace].append('Const' +
                                                            relation.bare_type)
                includes_cc.add(self._build_include(relation.bare_type))

        if datatype['VectorMembers'] or datatype['OneToManyRelations']:
            includes.add('#include <vector>')

        for relation in datatype['OneToManyRelations']:
            if self._needs_include(relation):
                includes.add(self._build_include(relation.bare_type))
            elif relation.is_array:
                includes.add('#include <array>')
                if not relation.is_builtin_array:
                    includes.add(self._build_include(relation.array_bare_type))

        for vectormember in datatype['VectorMembers']:
            if vectormember.full_type in self.reader.components:
                includes.add(self._build_include(vectormember.bare_type))

        includes.update(
            datatype.get('ExtraCode', {}).get('includes', '').split('\n'))
        includes.update(
            datatype.get('ConstExtraCode', {}).get('includes', '').split('\n'))

        # When we have a relation to the same type we have the header that we are
        # just generating in the includes. This would lead to a circular include, so
        # remove "ourselves" again from the necessary includes
        try:
            includes.remove(self._build_include(datatype['class'].bare_type))
        except KeyError:
            pass

        datatype['includes'] = self._sort_includes(includes)
        datatype['includes_cc'] = self._sort_includes(includes_cc)
        datatype['forward_declarations'] = fwd_declarations

    def _preprocess_for_collection(self, datatype):
        """Do the necessary preprocessing for the collection"""
        includes_cc = set()
        for relation in datatype['OneToManyRelations'] + datatype[
                'OneToOneRelations']:
            includes_cc.add(
                self._build_include(relation.bare_type + 'Collection'))

        if datatype['VectorMembers']:
            includes_cc.add('#include <numeric>')

        datatype['includes_coll_cc'] = self._sort_includes(includes_cc)

        # the ostream operator needs a bit of help from the python side in the form
        # of some pre processing but also in the form of formatting, both are done
        # here.
        # TODO: also handle array members properly. These are currently simply
        # ignored
        header_contents = []
        for member in datatype['Members']:
            header = {'name': member.name}
            if member.full_type in self.reader.components:
                comps = [
                    c.name for c in self.reader.components[member.full_type]
                    ['Members']
                ]
                header['components'] = comps
            header_contents.append(header)

        def ostream_collection_header(member_header, col_width=12):
            """Custom filter for the jinja2 templates to handle the ostream header that is
      printed for the collections. Need this custom filter because it is easier
      to implement the content dependent width in python than in jinja2.
      """
            if not isinstance(member_header, Mapping):
                # Assume that we have a string and format it according to the width
                return '{{:>{width}}}'.format(
                    width=col_width).format(member_header)

            components = member_header.get('components', None)
            name = member_header['name']
            if components is None:
                return '{{:>{width}}}'.format(width=col_width).format(name)

            n_comps = len(components)
            comp_str = '[ {}]'.format(', '.join(components))
            return '{{:>{width}}}'.format(
                width=col_width * n_comps).format(name + ' ' + comp_str)

        datatype['ostream_collection_settings'] = {
            'header_contents': header_contents
        }
        # Register the custom filter for it to become available in the templates
        self.env.filters[
            'ostream_collection_header'] = ostream_collection_header

    def _preprocess_datatype(self, name, definition):
        """Preprocess the datatype (building includes, etc.)"""
        # Make a copy here and add the preprocessing steps to that such that the
        # original definition can be left untouched
        data = deepcopy(definition)
        data['class'] = DataType(name)
        data['includes_data'] = self._get_member_includes(
            definition["Members"])
        data['is_pod'] = self._is_pod_type(definition["Members"])
        self._preprocess_for_class(data)
        self._preprocess_for_obj(data)
        self._preprocess_for_collection(data)

        return data

    def _get_member_includes(self, members):
        """Process all members and gather the necessary includes"""
        includes = set()
        for member in members:
            if member.is_array:
                includes.add("#include <array>")
                if not member.is_builtin_array:
                    includes.add(self._build_include(member.array_bare_type))

            for stl_type in ClassDefinitionValidator.allowed_stl_types:
                if member.full_type == 'std::' + stl_type:
                    includes.add("#include <{}>".format(stl_type))

            if self._needs_include(member):
                includes.add(self._build_include(member.bare_type))

        return self._sort_includes(includes)

    @staticmethod
    def _is_pod_type(members):
        """Check if the members of the class define a POD type"""
        for stl_type in ClassDefinitionValidator.allowed_stl_types:
            full_stl_type = 'std::' + stl_type
            if any(m.full_type.startswith(full_stl_type) for m in members):
                return False

        return True

    def _needs_include(self, member):
        """Check whether the member needs an include from within the datamodel"""
        return member.full_type in self.reader.components or member.full_type in self.reader.datatypes

    def _create_selection_xml(self):
        """Create the selection xml that is necessary for ROOT I/O"""
        data = {
            'components': [DataType(c) for c in self.reader.components.keys()],
            'datatypes': [DataType(d) for d in self.reader.datatypes.keys()]
        }
        self._write_file('selection.xml',
                         self._eval_template('selection.xml.jinja2', data))

    def _build_include(self, classname):
        """Return the include statement."""
        if self.include_subfolder:
            classname = os.path.join(self.package_name, classname)
        return '#include "%s.h"' % classname

    def _sort_includes(self, includes):
        """Sort the includes in order to try to have the std includes at the bottom"""
        package_includes = sorted(i for i in includes
                                  if self.package_name in i)
        podio_includes = sorted(i for i in includes if 'podio' in i)
        stl_includes = sorted(i for i in includes if '<' in i and '>' in i)
        # TODO: check whether there are includes that fulfill more than one of the
        # above conditions?

        return package_includes + podio_includes + stl_includes
Пример #5
0
class ClassGenerator(object):

  def __init__(self,yamlfile, install_dir, package_name, verbose = True):
    self.yamlfile = yamlfile
    self.install_dir = install_dir
    self.package_name =package_name
    self.template_dir = os.path.join(thisdir,"../templates")
    self.verbose=verbose
    self.buildin_types = ["int","float","double","unsigned int","unsigned","short","bool","longlong","ulonglong"]
    self.created_classes = []
    self.requested_classes = []
    self.reader = PodioConfigReader(yamlfile)
    self.warnings = []

  def load_data_definitions(self):
    self.datatypes = self.reader.read()

  def process(self):
    stream = open(self.yamlfile, "r")
    content = yaml.load(stream)
    if content.has_key("components"):
      self.components = content["components"]
      self.process_components(content["components"])
    self.load_data_definitions()
    self.process_datatypes(self.datatypes)
    self.create_selection_xml()
    self.print_report()

  def process_components(self,content):
    for name in content.iterkeys():
      self.requested_classes.append(name)
    for name, components in content.iteritems():
      self.create_component(name, components)

  def process_datatypes(self,content):
    for name in content.iterkeys():
      self.requested_classes.append(name)
      self.requested_classes.append("%sData" %name)
    for name, components in content.iteritems():
      self.create_data(name, components)
      self.create_class(name, components)
      self.create_collection(name, components)
      self.create_obj(name, components)

  def print_report(self):
    if self.verbose:
      pkl = open(os.path.join(thisdir,"figure.txt"))
      figure = pickle.load(pkl)
      text = _text_ % (self.yamlfile,
                       len(self.created_classes),
                       self.install_dir
                      )
      for i, line in enumerate(figure):
        print
        print line+text.splitlines()[i],
      print "     'Homage to the Square' - Josef Albers"
      print

  def get_template(self,filename):
      templatefile = os.path.join(self.template_dir,filename)
      return open(templatefile,"r").read()

  def create_selection_xml(self):
      content = ""
      for klass in self.created_classes:
        #if not klass.endswith("Collection") or klass.endswith("Data"):
          content += '          <class name="std::vector<%s>" />\n' %klass
          content += """
          <class name="%s">
            <field name="m_registry" transient="true"/>
            <field name="m_container" transient="true"/>
          </class>\n""" %klass

      templatefile = os.path.join(self.template_dir,"selection.xml.template")
      template = open(templatefile,"r").read()
      content = string.Template(template).substitute({"classes" : content})
      self.write_file("selection.xml",content)

  def create_data(self, classname, definition):
    # check whether all member types are known
    # and prepare include directives
    namespace_open = ""
    namespace_close = ""
    if "::" in classname:
      namespace, rawclassname = classname.split("::")
      namespace_open = "namespace %s {" % namespace
      namespace_close = "} // namespace %s" % namespace
    else:
      rawclassname = classname

    includes = ""
    description = definition["Description"]
    author      = definition["Author"]
    members = definition["Members"]
    for member in members:
      klass = member["type"]
      name  = member["type"]
      if klass in self.buildin_types:
        pass
      elif klass in self.requested_classes:
        #    includes += '#include "%s/%s.h"\n' %(self.package_name,klass)
        if "::" in klass:
          namespace, klassname = klass.split("::")
          includes += '#include "%s.h"\n' % klassname
        else:
          includes += '#include "%s.h"\n' %(klass)
      elif "std::array" in klass:
          includes += "#include <array>\n"
          self.created_classes.append(klass)
      elif "vector" in klass:
          includes += "#include <vector>\n"
          self.warnings.append("%s defines a vector member %s, that spoils the PODness" %(classname, klass))
      elif "[" in klass:
          raise Exception("'%s' defines an array type. Array types are not supported yet." %(classname, klass))
      else:
        raise Exception("'%s' defines a member of a type '%s' that is not (yet) declared!" %(classname, klass))
    membersCode = ""
    for member in members:
      name = member["name"]
      klass = member["type"]
      description = member["description"]
      membersCode+= "  %s %s; ///%s \n" %(klass, name, description)

    # now handle the vector-members
    vectormembers = definition["VectorMembers"]
    for vectormember in vectormembers:
      name = vectormember["name"]
      membersCode+= "  unsigned int %s_begin; \n" %(name)
      membersCode+= "  unsigned int %s_end; \n" %(name)

    # now handle the one-to-many relations
    refvectors = definition["OneToManyRelations"]
    for refvector in refvectors:
      name = refvector["name"]
      membersCode+= "  unsigned int %s_begin; \n" %(name)
      membersCode+= "  unsigned int %s_end; \n" %(name)

    substitutions = {"includes" : includes,
                     "members"  : membersCode,
                     "name"     : rawclassname,
                     "description" : description,
                     "author"   : author,
                     "package_name" : self.package_name,
                     "namespace_open" : namespace_open,
                     "namespace_close" : namespace_close
    }
    self.fill_templates("Data",substitutions)
    self.created_classes.append(classname+"Data")

  def create_class(self, classname, definition):
    namespace_open = ""
    namespace_close = ""
    if "::" in classname:
      namespace, rawclassname = classname.split("::")
      namespace_open = "namespace %s {" % namespace
      namespace_close = "} // namespace %s" % namespace
    else:
      rawclassname = classname
    includes = ""
    includes_cc = ""
    forward_declarations = ""
    forward_declarations_namespace = {"":[]}
    getter_implementations = ""
    setter_implementations = ""
    getter_declarations = ""
    setter_declarations = ""
    constructor_signature = ""
    constructor_body = ""
    ConstGetter_implementations = ""

    # check whether all member types are known
    # and prepare include directives
    includes += '#include "%s.h"\n' %(rawclassname+"Data")
    #includes += '#include "%s/%s.h"\n' %(self.package_name,classname+"Data")
    description = definition["Description"]
    author      = definition["Author"]
    members = definition["Members"]
    for member in members:
      klass = member["type"]
      if klass in self.buildin_types:
        pass
      elif klass in self.requested_classes:
        #includes += '#include "%s/%s.h"\n' %(self.package_name,klass)
        if "::" in klass:
          namespace, klassname = klass.split("::")
          includes += '#include "%s.h"\n' %klassname
        else:
          includes += '#include "%s.h"\n' %klass

      elif "std::array" in klass:
        includes += "#include <array>\n"
      elif "vector" in klass:
        includes += "#include <vector>\n"
      else:
        raise Exception("'%s' defines a member of a type '%s' that is not declared!" %(classname, klass))

    # check on-to-one relations and prepare include directives
    oneToOneRelations = definition["OneToOneRelations"]
    for member in oneToOneRelations:
      klass = member["type"]
      if klass in self.requested_classes:
        mnamespace = ""
        klassname = klass
        if "::" in klass:
          mnamespace, klassname = klass.split("::")
          if mnamespace not in forward_declarations_namespace.keys():
            forward_declarations_namespace[mnamespace] = []

        forward_declarations_namespace[mnamespace] += ["class %s;\n" %(klassname)]
        forward_declarations_namespace[mnamespace] += ["class Const%s;\n" %(klassname)]
        includes_cc += '#include "%s.h"\n' %(klassname)

    for nsp in forward_declarations_namespace.iterkeys():
      if nsp != "":
        forward_declarations += "namespace %s {\n" % nsp
      forward_declarations += "".join(forward_declarations_namespace[nsp])
      if nsp != "":
        forward_declarations += "}\n"

    # check one-to-many relations for consistency
    # and prepare include directives
    refvectors = definition["OneToManyRelations"]
    if len(refvectors) != 0:
      includes += "#include <vector>\n"
    for item in refvectors:
      klass = item["type"]
      if klass in self.requested_classes:
        if "::" in klass:
          mnamespace, klassname = klass.split("::")
          includes += '#include "%s.h"\n' %klassname
        else:
          includes += '#include "%s.h"\n' %klass
      elif "std::array" in klass:
        includes += "#include <array>\n"
      else:
        raise Exception("'%s' declares a non-allowed many-relation to '%s'!" %(classname, klass))

    # handle standard members
    for member in members:
      name = member["name"]
      klass = member["type"]
      description = member["description"]
      getter_declarations+= "  const %s& %s() const;\n" %(klass, name)
      getter_implementations+= "  const %s& %s::%s() const { return m_obj->data.%s; }\n" %(klass,rawclassname,name, name)
#      getter_declarations+= "  %s& %s() { return m_obj->data.%s; };\n" %(klass, name, name)
      if klass in self.buildin_types:
        setter_declarations += "  void %s(%s value);\n" %(name, klass)
        setter_implementations += "void %s::%s(%s value){ m_obj->data.%s = value;}\n" %(rawclassname, name, klass, name)
      else:
        setter_declarations += "  %s& %s();\n" %(klass, name)  # getting non-const reference is conceptually a setter
        setter_implementations += "  %s& %s::%s() { return m_obj->data.%s; }\n" %(klass, rawclassname,name, name)
        setter_declarations += "  void %s(class %s value);\n" %(name, klass)
        setter_implementations += "void %s::%s(class %s value){ m_obj->data.%s = value;}\n" %(rawclassname, name, klass, name)
      # set up signature
      constructor_signature += "%s %s," %(klass, name)
      # constructor
      constructor_body += "  m_obj->data.%s = %s;" %(name, name)
      ConstGetter_implementations += "  const %s& Const%s::%s() const { return m_obj->data.%s; }\n" %(klass, rawclassname, name, name)

    # one-to-one relations
    for member in oneToOneRelations:
        name = member["name"]
        klass = member["type"]
        mnamespace = ""
        klassname = klass
        if "::" in klass:
          mnamespace, klassname = klass.split("::")
          setter_declarations += "  void %s(%s::Const%s value);\n" %(name, mnamespace, klassname)
          setter_implementations += "void %s::%s(%s::Const%s value) { if (m_obj->m_%s != nullptr) delete m_obj->m_%s; m_obj->m_%s = new Const%s(value); }\n" %(rawclassname, name, mnamespace, klassname, name, name, name, klassname)
          getter_declarations += "  const %s::Const%s %s() const;\n" %(mnamespace, klassname, name)
          getter_implementations += "  const %s::Const%s %s::%s() const { if (m_obj->m_%s == nullptr) {\n return %s::Const%s(nullptr);}\n return %s::Const%s(*(m_obj->m_%s));}\n" \
                                    %(mnamespace, klassname, rawclassname, name, name, mnamespace, klassname, mnamespace, klassname, name)
          ConstGetter_implementations += "  const %s::Const%s Const%s::%s() const { if (m_obj->m_%s == nullptr) {\n return %s::Const%s(nullptr);}\n return %s::Const%s(*(m_obj->m_%s));}\n" \
                                    %(mnamespace, klassname, rawclassname, name, name, mnamespace, klassname, mnamespace, klassname, name)
        else:
          setter_declarations += "  void %s(Const%s value);\n" %(name, klassname)
          setter_implementations += "void %s::%s(Const%s value) { if (m_obj->m_%s != nullptr) delete m_obj->m_%s; m_obj->m_%s = new Const%s(value); }\n" %(rawclassname,name, klassname, name, name, name,klassname)
          getter_declarations += "  const Const%s %s() const;\n" %(klassname, name)
          getter_implementations += "  const Const%s %s::%s() const { if (m_obj->m_%s == nullptr) {\n return Const%s(nullptr);}\n return Const%s(*(m_obj->m_%s));}\n" \
                                    %(klassname, rawclassname, name, name, klassname, klassname, name)
          ConstGetter_implementations += "  const Const%s Const%s::%s() const { if (m_obj->m_%s == nullptr) {\n return Const%s(nullptr);}\n return Const%s(*(m_obj->m_%s));}\n" \
                                    %(klassname, rawclassname, name, name, klassname, klassname, name)

    # handle vector members
    vectormembers = definition["VectorMembers"]
    if len(vectormembers) != 0:
      includes += "#include <vector>\n"
    for item in vectormembers:
      klass = item["type"]
      if klass not in self.buildin_types and klass not in self.components:
        raise Exception("'%s' declares a non-allowed vector member of type '%s'!" %(classname, klass))
      if klass in self.components:
        if "::" in klass:
          namespace, klassname = klass.split("::")
          includes += '#include "%s.h"\n' %klassname
        else:
          includes += '#include "%s.h"\n' %klass

    # handle constructor from values
    constructor_signature = constructor_signature.rstrip(",")
    if constructor_signature == "":
       constructor_implementation = ""
       constructor_declaration = ""
       ConstConstructor_declaration = ""
       ConstConstructor_implementation = ""
    else:
      substitutions = { "name" : rawclassname,
                        "constructor" : constructor_body,
                        "signature" : constructor_signature
      }
      constructor_implementation = self.evaluate_template("Object.constructor.cc.template",substitutions)
      constructor_declaration = "  %s(%s);\n" %(rawclassname, constructor_signature)
      ConstConstructor_implementation = self.evaluate_template("ConstObject.constructor.cc.template",substitutions)
      ConstConstructor_declaration = "Const%s(%s);\n" %(rawclassname, constructor_signature)

    # handle one-to-many relations
    references_members = ""
    references_declarations = ""
    references = ""
    ConstReferences_declarations = ""
    ConstReferences = ""
    references_template = self.get_template("RefVector.cc.template")
    references_declarations_template = self.get_template("RefVector.h.template")
    ConstReferences_declarations_template = self.get_template("ConstRefVector.h.template")
    ConstReferences_template = self.get_template("ConstRefVector.cc.template")

    for refvector in refvectors+definition["VectorMembers"]:
      relationtype = refvector["type"]
      if relationtype not in self.buildin_types and relationtype not in self.components:
          relationtype = "Const"+relationtype

      substitutions = {"relation" : refvector["name"],
                       "relationtype" : relationtype,
                       "classname" : rawclassname,
                       "package_name" : self.package_name
                      }
      references_declarations += string.Template(references_declarations_template).substitute(substitutions)
      references += string.Template(references_template).substitute(substitutions)
      references_members += "std::vector<%s>* m_%s; //! transient \n" %(refvector["type"], refvector["name"])
      ConstReferences_declarations += string.Template(ConstReferences_declarations_template).substitute(substitutions)
      ConstReferences += string.Template(ConstReferences_template).substitute(substitutions)


    substitutions = {"includes" : includes,
                     "includes_cc" : includes_cc,
                     "forward_declarations" : forward_declarations,
                     "getters"  : getter_implementations,
                     "getter_declarations": getter_declarations,
                     "setters"  : setter_implementations,
                     "setter_declarations": setter_declarations,
                     "constructor_declaration" : constructor_declaration,
                     "constructor_implementation" : constructor_implementation,
                     "name"     : rawclassname,
                     "description" : description,
                     "author"   : author,
                     "relations" : references,
                     "relation_declarations" : references_declarations,
                     "relation_members" : references_members,
                     ""
                     "package_name" : self.package_name,
                     "namespace_open" : namespace_open,
                     "namespace_close" : namespace_close
                    }
    self.fill_templates("Object",substitutions)
    self.created_classes.append(classname)


    substitutions["constructor_declaration"] = ConstConstructor_declaration
    substitutions["constructor_implementation"] = ConstConstructor_implementation
    substitutions["relation_declarations"] = ConstReferences_declarations
    substitutions["relations"] = ConstReferences
    substitutions["getters"]   = ConstGetter_implementations
    self.fill_templates("ConstObject", substitutions)
    if "::" in classname:
      self.created_classes.append("%s::Const%s" %(namespace, rawclassname))
    else:
      self.created_classes.append("Const%s" %classname)

  def create_collection(self, classname, definition):
    namespace_open = ""
    namespace_close = ""
    if "::" in classname:
      namespace, rawclassname = classname.split("::")
      namespace_open = "namespace %s {" % namespace
      namespace_close = "} // namespace %s" % namespace
    else:
      rawclassname = classname
    members = definition["Members"]
    constructorbody = ""
    prepareforwritinghead = ""
    prepareforwritingbody = ""
    vectorized_access_decl, vectorized_access_impl = self.prepare_vectorized_access(rawclassname,members)
    setreferences = ""
    prepareafterread = ""
    includes = ""
    initializers = ""
    relations = ""
    create_relations = ""
    clear_relations  = ""
    push_back_relations = ""
    prepareafterread_refmembers = ""
    prepareforwriting_refmembers = ""

    refmembers = definition["OneToOneRelations"]
    refvectors = definition["OneToManyRelations"]
    nOfRefVectors = len(refvectors)
    nOfRefMembers = len(refmembers)
    if nOfRefVectors + nOfRefMembers > 0:
      # member initialization
      constructorbody += "  m_refCollections = new podio::CollRefCollection();\n"
      clear_relations += "  for (auto& pointer : (*m_refCollections)) {pointer->clear(); }\n"
      for counter, item in enumerate(refvectors):
        name  = item["name"]
        klass = item["type"]
        substitutions = { "counter" : counter,
                          "class" : klass,
                          "name"  : name }
        mnamespace = ""
        klassname = klass
        if "::" in klass:
          mnamespace, klassname = klass.split("::")
        # includes
        includes += '#include "%sCollection.h" \n' %(klassname)

        if mnamespace != "":
          # members
          relations += "  std::vector<::%s::Const%s>* m_rel_%s; //relation buffer for r/w\n" %(mnamespace, klassname, name)
          relations += "  std::vector<std::vector<::%s::Const%s>*> m_rel_%s_tmp;\n " %(mnamespace, klassname, name)
          # constructor calls
          initializers += ",m_rel_%s(new std::vector<::%s::Const%s>())" %(name, mnamespace, klassname)
        else:
          # members
          relations += "  std::vector<Const%s>* m_rel_%s; //relation buffer for r/w\n" %(klass, name)
          relations += "  std::vector<std::vector<Const%s>*> m_rel_%s_tmp;\n " %(klass, name)
          # constructor calls
          initializers += ",m_rel_%s(new std::vector<Const%s>())" %(name, klass)
        constructorbody += "  m_refCollections->push_back(new std::vector<podio::ObjectID>());\n"
        # relation handling in ::create
        create_relations += "  m_rel_%s_tmp.push_back(obj->m_%s);\n" %(name,name)
        # relation handling in ::clear
        clear_relations += "  // clear relations to %s. Make sure to unlink() the reference data as they may be gone already\n" %(name)
        clear_relations += "  for (auto& pointer : m_rel_%s_tmp) {for(auto& item : (*pointer)) {item.unlink();}; delete pointer;}\n" %(name)
        clear_relations += "  m_rel_%s_tmp.clear();\n" %(name)
        clear_relations += "  for (auto& item : (*m_rel_%s)) {item.unlink(); }\n" %(name)
        clear_relations += "  m_rel_%s->clear();\n" %(name)
        # relation handling in push_back
        push_back_relations += "  m_rel_%s_tmp.push_back(obj->m_%s);\n" %(name,name)
        # relation handling in ::prepareForWrite
        prepareforwritingbody += self.evaluate_template("CollectionPrepareForWriting.cc.template",substitutions)
        # relation handling in ::settingReferences
        setreferences += self.evaluate_template("CollectionSetReferences.cc.template",substitutions)
        prepareafterread += "    obj->m_%s = m_rel_%s;" %(name, name)
      for counter, item in enumerate(refmembers):
        name  = item["name"]
        klass = item["type"]
        mnamespace = ""
        klassname = klass
        if "::" in klass:
          mnamespace, klassname = klass.split("::")
        substitutions = { "counter" : counter+nOfRefVectors,
                          "class" : klass,
                          "rawclass" : klassname,
                          "name"  : name }


        # includes
        includes += '#include "%sCollection.h" \n' %(klassname)

        if mnamespace != "":
          # constructor calls
          initializers += ",m_rel_%s(new std::vector<::%s::Const%s>())" %(name, mnamespace, klassname)
          # members
          relations += "  std::vector<::%s::Const%s>* m_rel_%s; //relation buffer for r/w\n" %(mnamespace,  klassname, name)
        else:
          # constructor calls
          initializers += ",m_rel_%s(new std::vector<Const%s>())" %(name, klass)
          # members
          relations += "  std::vector<Const%s>* m_rel_%s; //relation buffer for r/w\n" %(klass, name)
        constructorbody += "  m_refCollections->push_back(new std::vector<podio::ObjectID>());\n"
        # relation handling in ::clear
        clear_relations += "  for (auto& item : (*m_rel_%s)) {item.unlink(); }\n" %(name)
        clear_relations += "  m_rel_%s->clear();\n" %(name)
        # relation handling in ::prepareForWrite
        prepareforwriting_refmembers +=  "  for (auto& obj : m_entries) {\nif (obj->m_%s != nullptr){\n(*m_refCollections)[%s]->emplace_back(obj->m_%s->getObjectID());} else {(*m_refCollections)[%s]->push_back({-2,-2}); } }\n" %(name,counter+nOfRefVectors,name,counter+nOfRefVectors)
        # relation handling in ::settingReferences
        prepareafterread_refmembers += self.evaluate_template("CollectionSetSingleReference.cc.template",substitutions)
    substitutions = { "name" : rawclassname,
                      "constructorbody" : constructorbody,
                      "prepareforwritinghead" : prepareforwritinghead,
                      "prepareforwritingbody" : prepareforwritingbody,
                      "prepareforwriting_refmembers" : prepareforwriting_refmembers,
                      "setreferences" : setreferences,
                      "prepareafterread" : prepareafterread,
                      "prepareafterread_refmembers" : prepareafterread_refmembers,
                      "includes" : includes,
                      "initializers" : initializers,
                      "relations"           : relations,
                      "create_relations" : create_relations,
                      "clear_relations"  : clear_relations,
                      "push_back_relations" : push_back_relations,
                      "package_name" : self.package_name,
                      "vectorized_access_declaration" : vectorized_access_decl,
                      "vectorized_access_implementation" : vectorized_access_impl,
                      "namespace_open" : namespace_open,
                      "namespace_close" : namespace_close
    }
    self.fill_templates("Collection",substitutions)
    self.created_classes.append("%sCollection"%classname)

  def create_component(self, classname, components):
    """ Create a component class to be used within the data types
        Components can only contain simple data types and no user
        defined ones
    """
    namespace_open = ""
    namespace_close = ""
    if "::" in classname:
      namespace, rawclassname = classname.split("::")
      namespace_open = "namespace %s {" % namespace
      namespace_close = "} // namespace %s" % namespace
    else:
      rawclassname = classname
    for klass in components.itervalues():
      if klass in self.buildin_types or self.components.has_key(klass):
        pass
      else:
        raise Exception("'%s' defines a member of a type '%s' which is not allowed in a component!" %(classname, klass))
    includes = ""
    members = ""
    for name, klass in components.iteritems():
      klassname = klass
      mnamespace = ""
      if "::" in klass:
        mnamespace, klassname = klass.split("::")
      if mnamespace == "":
        members+= "  %s %s;\n" %(klassname, name)
      else:
        members += " ::%s::%s %s;\n" %(mnamespace, klassname, name)
      if self.components.has_key(klass):
          includes+= '#include "%s.h"\n' %(klassname)
    substitutions = { "includes" : includes,
                      "members"  : members,
                      "name"     : rawclassname,
                      "package_name" : self.package_name,
                      "namespace_open" : namespace_open,
                      "namespace_close" : namespace_close
    }
    self.fill_templates("Component",substitutions)
    self.created_classes.append(classname)

  def create_obj(self, classname, definition):
    """ Create an obj class containing all information
        relevant for a given object.
    """
    namespace_open = ""
    namespace_close = ""
    if "::" in classname:
      namespace, rawclassname = classname.split("::")
      namespace_open = "namespace %s {" % namespace
      namespace_close = "} // namespace %s" % namespace
    else:
      rawclassname = classname

    relations = ""
    includes = ""
    includes_cc = ""
    forward_declarations = ""
    forward_declarations_namespace = {"":[]}
    initialize_relations = ""
    deepcopy_relations = ""
    delete_relations = ""
    refvectors = definition["OneToManyRelations"]
    singleRelations = definition["OneToOneRelations"]
    # do includes and forward declarations for
    # oneToOneRelations and do proper cleanups
    for item in singleRelations:
      name  = item["name"]
      klass = item["type"]
      klassname = klass
      mnamespace = ""
      if "::" in klass:
        mnamespace, klassname = klass.split("::")
        if mnamespace not in forward_declarations_namespace.keys():
          forward_declarations_namespace[mnamespace] = []

      if mnamespace != "":
        relations+= "  ::%s::Const%s* m_%s;\n" %(mnamespace, klassname, name)
      else:
        relations+= "  Const%s* m_%s;\n" %(klassname, name)

      if klass not in self.buildin_types:
        if klass != classname:
          forward_declarations_namespace[mnamespace] += ['class Const%s;\n' %(klassname)]
          includes_cc += '#include "%sConst.h"\n' %(klassname)
          initialize_relations += ",m_%s(nullptr)\n" %(name)
        delete_relations+="delete m_%s;\n" %name

    for nsp in forward_declarations_namespace.iterkeys():
      if nsp != "":
        forward_declarations += "namespace %s {" % nsp
      forward_declarations += "".join(forward_declarations_namespace[nsp])
      if nsp != "":
        forward_declarations += "}\n"

    if len(refvectors+definition["VectorMembers"]) !=0:
      includes += "#include <vector>\n"

    for item in refvectors+definition["VectorMembers"]:
      name  = item["name"]
      klass = item["type"]
      if klass not in self.buildin_types:
        if klass not in self.components:
          if "::" in klass:
            mnamespace, klassname = klass.split("::")
            klassWithQualifier = "::"+mnamespace+"::Const"+klassname
          else:
            klassWithQualifier = "Const"+klass
        else:
            klassWithQualifier = klass
        relations += "  std::vector<%s>* m_%s;\n" %(klassWithQualifier, name)
        initialize_relations += ",m_%s(new std::vector<%s>())" %(name,klassWithQualifier)
        deepcopy_relations += ",m_%s(new std::vector<%s>(*(other.m_%s)))" %(name,klassWithQualifier,name)
        if klass == classname:
          includes_cc += '#include "%s.h"\n' %(rawclassname)
        else:
          if "::" in klass:
            mnamespace, klassname = klass.split("::")
            includes += '#include "%s.h"\n' %klassname
          else:
            includes += '#include "%s.h"\n' %klass
      else:
          relations += "  std::vector<%s>* m_%s;\n" %(klass, name)
          initialize_relations += ",m_%s(new std::vector<%s>())" %(name,klass)
          deepcopy_relations += ",m_%s(new std::vector<%s>(*(other.m_%s)))" %(name,klass,name)

      delete_relations += "delete m_%s;\n" %(name)
    substitutions = { "name" : rawclassname,
                      "includes" : includes,
                      "includes_cc" : includes_cc,
                      "forward_declarations" : forward_declarations,
                      "relations" : relations,
                      "initialize_relations" : initialize_relations,
                      "deepcopy_relations" : deepcopy_relations,
                      "delete_relations" : delete_relations,
                      "namespace_open" : namespace_open,
                      "namespace_close" : namespace_close
    }
    self.fill_templates("Obj",substitutions)
    self.created_classes.append(classname+"Obj")

  def prepare_vectorized_access(self, classname,members ):
    implementation = ""
    declaration = ""
    for member in members:
      name = member["name"]
      klass = member["type"]
      substitutions = { "classname" : classname,
                       "member"    : name,
                       "type"      : klass
                       }
      if klass not in self.buildin_types:
        substitutions["type"] = "class %s" % klass
      implementation += self.evaluate_template("CollectionReturnArray.cc.template", substitutions)
      declaration += "  template<size_t arraysize>  \n  const std::array<%s,arraysize> %s() const;\n" %(klass, name)
    return declaration, implementation

  def write_file(self, name,content):
    #dispatch headers to header dir, the rest to /src
    # fullname = os.path.join(self.install_dir,self.package_name,name)
    if name.endswith("h"):
     fullname = os.path.join(self.install_dir,self.package_name,name)
    else:
     fullname = os.path.join(self.install_dir,"src",name)
    open(fullname, "w").write(content)

  def evaluate_template(self, filename, substitutions):
      """ reads in a given template, evaluates it
          and returns result
      """
      templatefile = os.path.join(self.template_dir,filename)
      template = open(templatefile,"r").read()
      return string.Template(template).substitute(substitutions)

  def fill_templates(self, category, substitutions):
    # "Data" denotes the real class;
    # only headers and the FN should not contain Data
    if category == "Data":
      FN = "Data"
      endings = ("h")
    elif category == "Obj":
      FN = "Obj"
      endings = ("h","cc")
    elif category == "Component":
      FN = ""
      endings = ("h")
    elif category == "Object":
      FN = ""
      endings = ("h","cc")
    elif category == "ConstObject":
      FN = "Const"
      endings = ("h","cc")
    else:
      FN = category
      endings = ("h","cc")
    for ending in endings:
      templatefile = "%s.%s.template" %(category,ending)
      templatefile = os.path.join(self.template_dir,templatefile)
      template = open(templatefile,"r").read()
      content = string.Template(template).substitute(substitutions)
      filename = "%s%s.%s" %(substitutions["name"],FN,ending)
      self.write_file(filename, content)
Пример #6
0
class ClassGenerator(object):

    def __init__(self, yamlfile, install_dir, package_name,
                 verbose=True, getSyntax=False):

        self.yamlfile = yamlfile
        self.install_dir = install_dir
        self.package_name = package_name
        self.template_dir = os.path.join(thisdir, "../templates")
        self.verbose = verbose
        self.getSyntax = getSyntax
        self.buildin_types = ClassDefinitionValidator.buildin_types
        self.created_classes = []
        self.requested_classes = []
        self.reader = PodioConfigReader(yamlfile)
        self.warnings = []

    def process(self):
        self.reader.read()
        self.process_components(self.reader.components)
        self.process_datatypes(self.reader.datatypes)
        self.create_selection_xml()
        self.print_report()

    def process_components(self, content):
        self.requested_classes += content.keys()
        for name, components in content.iteritems():
            self.create_component(name, components["Members"])

    def process_datatypes(self, content):
        for name in content.iterkeys():
            self.requested_classes.append(name)
            self.requested_classes.append("%sData" % name)
        for name, components in content.iteritems():
            self.create_data(name, components)
            self.create_class(name, components)
            self.create_collection(name, components)
            self.create_obj(name, components)

    def print_report(self):
        if self.verbose:
            pkl = open(os.path.join(thisdir, "figure.txt"))
            figure = pickle.load(pkl)
            text = _text_ % (self.yamlfile,
                             len(self.created_classes),
                             self.install_dir
                             )
        for i, line in enumerate(figure):
            print
            print line + text.splitlines()[i],
        print "     'Homage to the Square' - Josef Albers"
        print

    def get_template(self, filename):
        templatefile = os.path.join(self.template_dir, filename)
        return open(templatefile, "r").read()

    def create_selection_xml(self):
        content = ""
        for klass in self.created_classes:
            # if not klass.endswith("Collection") or klass.endswith("Data"):
            content += '          <class name="std::vector<%s>" />\n' % klass
            content += """
            <class name="%s">
              <field name="m_registry" transient="true"/>
              <field name="m_container" transient="true"/>
            </class>\n""" % klass

        templatefile = os.path.join(self.template_dir,
                                    "selection.xml.template")
        template = open(templatefile, "r").read()
        content = string.Template(template).substitute({"classes": content})
        self.write_file("selection.xml", content)

    def process_datatype(self, classname, definition, is_data=False):
        datatype_dict = {}
        datatype_dict["description"] = definition["Description"]
        datatype_dict["author"] = definition["Author"]
        datatype_dict["includes"] = []
        datatype_dict["members"] = []
        members = definition["Members"]
        for member in members:
            klass = member["type"]
            name = member["name"]
            description = member["description"]
            datatype_dict["members"].append("  %s %s;  ///<%s"
                                            % (klass, name, description))
            if "std::string" == klass:
                datatype_dict["includes"].append("#include <string>")
                self.warnings.append("%s defines a string member %s, that spoils the PODness"
                                     % (classname, klass))
            elif klass in self.buildin_types:
                pass
            elif klass in self.requested_classes:
                if "::" in klass:
                    namespace, klassname = klass.split("::")
                    datatype_dict["includes"].append('#include "%s.h"'
                                                     % klassname)
                else:
                    datatype_dict["includes"].append('#include "%s.h"'
                                                     % klass)
            elif "std::array" in klass:
                datatype_dict["includes"].append("#include <array>")
                self.created_classes.append(klass)
            elif "vector" in klass:
                datatype_dict["includes"].append("#include <vector>")
                if is_data:  # avoid having warnings twice
                    self.warnings.append("%s defines a vector member %s, that spoils the PODness" % (classname, klass))
            elif "[" in klass and is_data:  # FIXME: is this only true ofr PODs?
                raise Exception("'%s' defines an array type. Array types are not supported yet." % (classname, klass))
            else:
                raise Exception("'%s' defines a member of a type '%s' that is not (yet) declared!" % (classname, klass))
        return datatype_dict


    def demangle_classname(self, classname):
      namespace_open = ""
      namespace_close = ""
      namespace = ""
      rawclassname = ""
      if "::" in classname:
        cnameparts = classname.split("::")
        if len(cnameparts) > 2:
          raise Exception("'%s' defines a type with nested namespaces. Not supported, yet." % classname)
        namespace, rawclassname = cnameparts
        namespace_open = "namespace %s {" % namespace
        namespace_close = "} // namespace %s" % namespace
      else:
        rawclassname = classname
      return namespace, rawclassname, namespace_open, namespace_close


    def create_data(self, classname, definition):
      # check whether all member types are known
      # and prepare include directives
      namespace, rawclassname, namespace_open, namespace_close = self.demangle_classname(classname)

      data = self.process_datatype(classname, definition)

      # now handle the vector-members
      vectormembers = definition["VectorMembers"]
      for vectormember in vectormembers:
        name = vectormember["name"]
        data["members"].append("  unsigned int %s_begin;" % name)
        data["members"].append("  unsigned int %s_end;" %(name))

      # now handle the one-to-many relations
      refvectors = definition["OneToManyRelations"]
      for refvector in refvectors:
        name = refvector["name"]
        data["members"].append("  unsigned int %s_begin;" %(name))
        data["members"].append("  unsigned int %s_end;" %(name))

      substitutions = {"includes" : "\n".join(data["includes"]),
                      "members"  : "\n".join(data["members"]),
                      "name"     : rawclassname,
                      "description" : data["description"],
                      "author"   :  data["author"],
                      "package_name" : self.package_name,
                      "namespace_open" : namespace_open,
                      "namespace_close" : namespace_close
      }
      self.fill_templates("Data", substitutions)
      self.created_classes.append(classname+"Data")

    def create_class(self, classname, definition):
      namespace, rawclassname, namespace_open, namespace_close = self.demangle_classname(classname)

      includes_cc = ""
      forward_declarations = ""
      forward_declarations_namespace = {"":[]}
      getter_implementations = ""
      setter_implementations = ""
      getter_declarations = ""
      setter_declarations = ""
      constructor_signature = ""
      constructor_body = ""
      ConstGetter_implementations = ""

      # check whether all member types are known
      # and prepare include directives
      datatype = self.process_datatype(classname, definition, False)

      datatype["includes"].append('#include "%s.h"' % (rawclassname+"Data"))

      # check on-to-one relations and prepare include directives
      oneToOneRelations = definition["OneToOneRelations"]
      for member in oneToOneRelations:
        klass = member["type"]
        if klass in self.requested_classes:
          mnamespace = ""
          klassname = klass
          if "::" in klass:
            mnamespace, klassname = klass.split("::")
            if mnamespace not in forward_declarations_namespace.keys():
              forward_declarations_namespace[mnamespace] = []

          forward_declarations_namespace[mnamespace] += ["class %s;\n" %(klassname)]
          forward_declarations_namespace[mnamespace] += ["class Const%s;\n" %(klassname)]
          includes_cc += '#include "%s.h"\n' %(klassname)

      for nsp in forward_declarations_namespace.iterkeys():
        if nsp != "":
          forward_declarations += "namespace %s {\n" % nsp
        forward_declarations += "".join(forward_declarations_namespace[nsp])
        if nsp != "":
          forward_declarations += "}\n"

      # check one-to-many relations for consistency
      # and prepare include directives
      refvectors = definition["OneToManyRelations"]
      if len(refvectors) != 0:
        datatype["includes"].append("#include <vector>")
      for item in refvectors:
        klass = item["type"]
        if klass in self.requested_classes:
          if "::" in klass:
            mnamespace, klassname = klass.split("::")
            datatype["includes"].append('#include "%s.h"' %klassname)
          else:
            datatype["includes"].append('#include "%s.h"' %klass)
        elif "std::array" in klass:
          datatype["includes"].append("#include <array>")
        else:
          raise Exception("'%s' declares a non-allowed many-relation to '%s'!" %(classname, klass))

      # handle standard members
      for member in definition["Members"]:
        name = member["name"]
        klass = member["type"]
        gname,sname = name,name
        if( self.getSyntax ):
          gname = "get" + name[:1].upper() + name[1:]
          sname = "set" + name[:1].upper() + name[1:]
        getter_declarations += declarations["member_getter"].format(type=klass, name=name,fname=gname)
        getter_implementations += implementations["member_getter"].format(type=klass, classname=rawclassname, name=name, fname=gname)
        if klass in self.buildin_types:
          setter_declarations += declarations["member_builtin_setter"].format(type=klass, name=name, fname=sname)
          setter_implementations += implementations["member_builtin_setter"].format(type=klass, classname=rawclassname, name=name, fname=sname)
        else:
          setter_declarations += declarations["member_class_refsetter"].format(type=klass, name=name)
          setter_implementations += implementations["member_class_refsetter"].format(type=klass, classname=rawclassname, name=name, fname=sname)
          setter_declarations += declarations["member_class_setter"].format(type=klass, name=name, fname=sname)
          setter_implementations += implementations["member_class_setter"].format(type=klass, classname=rawclassname, name=name, fname=sname)
        # Getter for the Const variety of this datatype
        ConstGetter_implementations += implementations["const_member_getter"].format(type=klass, classname=rawclassname, name=name, fname=gname)


        # set up signature
        constructor_signature += "%s %s," %(klass, name)
        # constructor
        constructor_body += "  m_obj->data.%s = %s;" %(name, name)

      # one-to-one relations
      for member in oneToOneRelations:
          name = member["name"]
          klass = member["type"]
          mnamespace = ""
          klassname = klass
          mnamespace, klassname, _, __ = self.demangle_classname(klass)

          setter_declarations += declarations["one_rel_setter"].format(name=name, namespace=mnamespace, type=klassname)
          setter_implementations += implementations["one_rel_setter"].format(name=name, namespace=mnamespace, type=klassname, classname=rawclassname)
          getter_declarations += declarations["one_rel_getter"].format(name=name, namespace=mnamespace, type=klassname)
          getter_implementations += implementations["one_rel_getter"].format(name=name, namespace=mnamespace, type=klassname, classname=rawclassname)
          ConstGetter_implementations += implementations["const_one_rel_getter"].format(name=name, namespace=mnamespace, type=klassname, classname=rawclassname)


      # handle vector members
      vectormembers = definition["VectorMembers"]
      if len(vectormembers) != 0:
        datatype["includes"].append("#include <vector>")
      for item in vectormembers:
        klass = item["type"]
        if klass not in self.buildin_types and klass not in self.reader.components:
          raise Exception("'%s' declares a non-allowed vector member of type '%s'!" %(classname, klass))
        if klass in self.reader.components:
          if "::" in klass:
            namespace, klassname = klass.split("::")
            datatype["includes"].append('#include "%s.h"' %klassname)
          else:
            datatype["includes"].append('#include "%s.h"' %klass)

      # handle constructor from values
      constructor_signature = constructor_signature.rstrip(",")
      if constructor_signature == "":
        constructor_implementation = ""
        constructor_declaration = ""
        ConstConstructor_declaration = ""
        ConstConstructor_implementation = ""
      else:
        substitutions = { "name" : rawclassname,
                          "constructor" : constructor_body,
                          "signature" : constructor_signature
        }
        constructor_implementation = self.evaluate_template("Object.constructor.cc.template",substitutions)
        constructor_declaration = "  %s(%s);\n" %(rawclassname, constructor_signature)
        ConstConstructor_implementation = self.evaluate_template("ConstObject.constructor.cc.template",substitutions)
        ConstConstructor_declaration = "Const%s(%s);\n" %(rawclassname, constructor_signature)

      # handle one-to-many relations
      references_members = ""
      references_declarations = ""
      references = ""
      ConstReferences_declarations = ""
      ConstReferences = ""
      references_template = self.get_template("RefVector.cc.template")
      references_declarations_template = self.get_template("RefVector.h.template")
      ConstReferences_declarations_template = self.get_template("ConstRefVector.h.template")
      ConstReferences_template = self.get_template("ConstRefVector.cc.template")

      for refvector in refvectors+definition["VectorMembers"]:
        relationtype = refvector["type"]
        if relationtype not in self.buildin_types and relationtype not in self.reader.components:
            relationtype = "Const"+relationtype

        relationName = refvector["name"]
        get_relation = relationName
        add_relation = "add"+relationName

        if( self.getSyntax ):
          get_relation = "get" + relationName[:1].upper() + relationName[1:]
          add_relation = "add" + relationName[:1].upper() + relationName[1:len(relationName)-1]  # drop the 's' at the end !??

        substitutions = {"relation" : relationName,
                        "get_relation" : get_relation,
                        "add_relation" : add_relation,
                        "relationtype" : relationtype,
                        "classname"  : rawclassname,
                        "package_name" : self.package_name
                        }
        references_declarations += string.Template(references_declarations_template).substitute(substitutions)
        references += string.Template(references_template).substitute(substitutions)
        references_members += "std::vector<%s>* m_%s; ///< transient \n" %(refvector["type"], refvector["name"])
        ConstReferences_declarations += string.Template(ConstReferences_declarations_template).substitute(substitutions)
        ConstReferences += string.Template(ConstReferences_template).substitute(substitutions)

      # handle user provided extra code
      extracode_declarations = ""
      extracode = ""
      constextracode_declarations = ""
      constextracode = ""
      if definition.has_key("ExtraCode"):
        extra = definition["ExtraCode"]
        if( extra.has_key("declaration")):
            extracode_declarations = extra["declaration"].replace("{name}",rawclassname)
        if( extra.has_key("implementation")):
            extracode = extra["implementation"].replace("{name}",rawclassname)
        if( extra.has_key("const_declaration")):
            constextracode_declarations = extra["const_declaration"].replace("{name}","Const"+rawclassname)
            extracode_declarations += "\n"
            extracode_declarations += extra["const_declaration"]
        if( extra.has_key("const_implementation")):
            constextracode = extra["const_implementation"].replace("{name}","Const"+rawclassname)
            extracode += "\n"
            extracode += extra["const_implementation"].replace("{name}",rawclassname)
        # TODO: add loading of code from external files
        if( extra.has_key("includes")):
            datatype["includes"].append( extra["includes"] )
            print " ***** adding includes : " ,  extra["includes"] , "to" ,  datatype["includes"]

      substitutions = {"includes" : "\n".join(datatype["includes"]),
                      "includes_cc" : includes_cc,
                      "forward_declarations" : forward_declarations,
                      "getters"  : getter_implementations,
                      "getter_declarations": getter_declarations,
                      "setters"  : setter_implementations,
                      "setter_declarations": setter_declarations,
                      "constructor_declaration" : constructor_declaration,
                      "constructor_implementation" : constructor_implementation,
                      "extracode" : extracode,
                      "extracode_declarations" : extracode_declarations,
                      "name"     : rawclassname,
                      "description" : datatype["description"],
                      "author"   : datatype["author"],
                      "relations" : references,
                      "relation_declarations" : references_declarations,
                      "relation_members" : references_members,
                      "package_name" : self.package_name,
                      "namespace_open" : namespace_open,
                      "namespace_close" : namespace_close
                      }
      self.fill_templates("Object",substitutions)
      self.created_classes.append(classname)


      substitutions["constructor_declaration"] = ConstConstructor_declaration
      substitutions["constructor_implementation"] = ConstConstructor_implementation
      substitutions["relation_declarations"] = ConstReferences_declarations
      substitutions["relations"] = ConstReferences
      substitutions["getters"]   = ConstGetter_implementations
      substitutions["constextracode"] = constextracode
      substitutions["constextracode_declarations"] = constextracode_declarations
      self.fill_templates("ConstObject", substitutions)
      if "::" in classname:
        self.created_classes.append("%s::Const%s" %(namespace, rawclassname))
      else:
        self.created_classes.append("Const%s" %classname)

    def create_collection(self, classname, definition):
      namespace, rawclassname, namespace_open, namespace_close = self.demangle_classname(classname)

      members = definition["Members"]
      constructorbody = ""
      destructorbody  = ""
      prepareforwritinghead = ""
      prepareforwritingbody = ""
      vectorized_access_decl, vectorized_access_impl = self.prepare_vectorized_access(rawclassname,members)
      setreferences = ""
      prepareafterread = ""
      includes = ""
      initializers = ""
      relations = ""
      create_relations = ""
      clear_relations  = ""
      push_back_relations = ""
      prepareafterread_refmembers = ""
      prepareforwriting_refmembers = ""

      refmembers = definition["OneToOneRelations"]
      refvectors = definition["OneToManyRelations"]
      nOfRefVectors = len(refvectors)
      nOfRefMembers = len(refmembers)
      if nOfRefVectors + nOfRefMembers > 0:
        # member initialization
        #constructorbody += "\tm_refCollections = new podio::CollRefCollection();\n"
        destructorbody  += "\tfor (auto& pointer : m_refCollections) { if (pointer != nullptr) delete pointer; }\n"
        clear_relations += "\tfor (auto& pointer : m_refCollections) { pointer->clear(); }\n"
        for counter, item in enumerate(refvectors):
          name  = item["name"]
          klass = item["type"]
          substitutions = { "counter" : counter,
                            "class" : klass,
                            "name"  : name }

          mnamespace, klassname, _, __ = self.demangle_classname(klass)

          # includes
          includes += '#include "%sCollection.h" \n' %(klassname)

          # FIXME check if it compiles with :: for both... then delete this.
          relations += declarations["relation"].format(namespace=mnamespace, type=klassname, name=name)
          relations += declarations["relation_collection"].format(namespace=mnamespace, type=klassname, name=name)
          initializers += implementations["ctor_list_relation"].format(namespace=mnamespace, type=klassname, name=name)

          constructorbody += "\tm_refCollections.push_back(new std::vector<podio::ObjectID>());\n"
          # relation handling in ::create
          create_relations += "\tm_rel_{name}_tmp.push_back(obj->m_{name});\n".format(name=name)
          # relation handling in ::clear
          clear_relations += implementations["clear_relations_vec"].format(name=name)
          clear_relations += implementations["clear_relations"].format(name=name)
          # relation handling in dtor:
          destructorbody += implementations["destroy_relations"].format(name=name)
          # relation handling in push_back
          push_back_relations += "\tm_rel_{name}_tmp.push_back(obj->m_{name});\n".format(name=name)
          # relation handling in ::prepareForWrite
          prepareforwritinghead += "\tint {name}_index =0;\n".format(name=name)
          prepareforwritingbody += self.evaluate_template("CollectionPrepareForWriting.cc.template",substitutions)
          # relation handling in ::settingReferences
          setreferences += self.evaluate_template("CollectionSetReferences.cc.template",substitutions)
          prepareafterread += "\t\tobj->m_%s = m_rel_%s;" %(name, name)
        for counter, item in enumerate(refmembers):
          name  = item["name"]
          klass = item["type"]
          mnamespace = ""
          klassname = klass
          if "::" in klass:
            mnamespace, klassname = klass.split("::")
          substitutions = { "counter" : counter+nOfRefVectors,
                            "class" : klass,
                            "rawclass" : klassname,
                            "name"  : name }


          # includes
          includes += '#include "%sCollection.h"\n' %(klassname)
          # constructor call
          initializers += implementations["ctor_list_relation"].format(namespace=mnamespace, type=klassname, name=name)
          # member
          relations += declarations["relation"].format(namespace=mnamespace, type=klassname, name=name)
          constructorbody += "\tm_refCollections.push_back(new std::vector<podio::ObjectID>());\n"
          # relation handling in ::clear
          clear_relations += implementations["clear_relations"].format(name=name)
          # relation handling in dtor:
          destructorbody += implementations["destroy_relations"].format(name=name)
          # relation handling in ::prepareForWrite
          prepareforwriting_refmembers += implementations["prep_writing_relations"].format(name=name, i=(counter+nOfRefVectors))
          # relation handling in ::settingReferences
          prepareafterread_refmembers += self.evaluate_template("CollectionSetSingleReference.cc.template",substitutions)
      substitutions = { "name" : rawclassname,
                        "constructorbody" : constructorbody,
                        "destructorbody"  : destructorbody,
                        "prepareforwritinghead" : prepareforwritinghead,
                        "prepareforwritingbody" : prepareforwritingbody,
                        "prepareforwriting_refmembers" : prepareforwriting_refmembers,
                        "setreferences" : setreferences,
                        "prepareafterread" : prepareafterread,
                        "prepareafterread_refmembers" : prepareafterread_refmembers,
                        "includes" : includes,
                        "initializers" : initializers,
                        "relations"           : relations,
                        "create_relations" : create_relations,
                        "clear_relations"  : clear_relations,
                        "push_back_relations" : push_back_relations,
                        "package_name" : self.package_name,
                        "vectorized_access_declaration" : vectorized_access_decl,
                        "vectorized_access_implementation" : vectorized_access_impl,
                        "namespace_open" : namespace_open,
                        "namespace_close" : namespace_close
      }
      self.fill_templates("Collection",substitutions)
      self.created_classes.append("%sCollection"%classname)

    def create_component(self, classname, components):
      """ Create a component class to be used within the data types
          Components can only contain simple data types and no user
          defined ones
      """
      namespace, rawclassname, namespace_open, namespace_close = self.demangle_classname(classname)

      includes = ""
      members = ""
      extracode_declarations = ""

      #fg: sort the dictionary, so at least we get a predictable order (alphabetical) of the members
      keys = sorted( components.keys() )
      for name in keys:
        klass = components[ name ]
  #    for name, klass in components.iteritems():

        if( name != "ExtraCode"):
          klassname = klass
          mnamespace = ""
          if "::" in klass:
            mnamespace, klassname = klass.split("::")
          if mnamespace == "":
            members+= "  %s %s;\n" %(klassname, name)
          else:
            members += " ::%s::%s %s;\n" %(mnamespace, klassname, name)
          if self.reader.components.has_key(klass):
              includes+= '#include "%s.h"\n' %(klassname)
        else:
          # handle user provided extra code
          if klass.has_key("declaration"):
            extracode_declarations = klass["declaration"]


      substitutions = { "includes" : includes,
                        "members"  : members,
                        "extracode_declarations" : extracode_declarations,
                        "name"     : rawclassname,
                        "package_name" : self.package_name,
                        "namespace_open" : namespace_open,
                        "namespace_close" : namespace_close
      }
      self.fill_templates("Component",substitutions)
      self.created_classes.append(classname)

    def create_obj(self, classname, definition):
      """ Create an obj class containing all information
          relevant for a given object.
      """
      namespace, rawclassname, namespace_open, namespace_close = self.demangle_classname(classname)

      relations = ""
      includes = ""
      includes_cc = ""
      forward_declarations = ""
      forward_declarations_namespace = {"":[]}
      initialize_relations = ""
      deepcopy_relations = ""
      delete_relations = ""
      delete_singlerelations = ""
      refvectors = definition["OneToManyRelations"]
      singleRelations = definition["OneToOneRelations"]
      # do includes and forward declarations for
      # oneToOneRelations and do proper cleanups
      for item in singleRelations:
        name  = item["name"]
        klass = item["type"]
        klassname = klass
        mnamespace = ""
        if "::" in klass:
          mnamespace, klassname = klass.split("::")
          if mnamespace not in forward_declarations_namespace.keys():
            forward_declarations_namespace[mnamespace] = []

        if mnamespace != "":
          relations+= "  ::%s::Const%s* m_%s;\n" %(mnamespace, klassname, name)
        else:
          relations+= "  Const%s* m_%s;\n" %(klassname, name)

        if klass not in self.buildin_types:
          if klass != classname:
            forward_declarations_namespace[mnamespace] += ['class Const%s;\n' %(klassname)]
            includes_cc += '#include "%sConst.h"\n' %(klassname)
            initialize_relations += ",m_%s(nullptr)\n" %(name)
          delete_singlerelations+="\t\tif (m_%s != nullptr) delete m_%s;\n" % (name, name)

      for nsp in forward_declarations_namespace.iterkeys():
        if nsp != "":
          forward_declarations += "namespace %s {" % nsp
        forward_declarations += "".join(forward_declarations_namespace[nsp])
        if nsp != "":
          forward_declarations += "}\n"

      if len(refvectors+definition["VectorMembers"]) !=0:
        includes += "#include <vector>\n"

      for item in refvectors+definition["VectorMembers"]:
        name  = item["name"]
        klass = item["type"]
        if klass not in self.buildin_types:
          if klass not in self.reader.components:
            if "::" in klass:
              mnamespace, klassname = klass.split("::")
              klassWithQualifier = "::"+mnamespace+"::Const"+klassname
            else:
              klassWithQualifier = "Const"+klass
          else:
              klassWithQualifier = klass
          relations += "\tstd::vector<%s>* m_%s;\n" %(klassWithQualifier, name)
          initialize_relations += ", m_%s(new std::vector<%s>())" %(name,klassWithQualifier)
          deepcopy_relations += ", m_%s(new std::vector<%s>(*(other.m_%s)))" %(name,klassWithQualifier,name)
          if klass == classname:
            includes_cc += '#include "%s.h"\n' %(rawclassname)
          else:
            if "::" in klass:
              mnamespace, klassname = klass.split("::")
              includes += '#include "%s.h"\n' %klassname
            else:
              includes += '#include "%s.h"\n' %klass
        else:
            relations += "\tstd::vector<%s>* m_%s;\n" %(klass, name)
            initialize_relations += ", m_%s(new std::vector<%s>())" %(name,klass)
            deepcopy_relations += ", m_%s(new std::vector<%s>(*(other.m_%s)))" %(name,klass,name)

        delete_relations += "\t\tdelete m_%s;\n" %(name)
      substitutions = { "name" : rawclassname,
                        "includes" : includes,
                        "includes_cc" : includes_cc,
                        "forward_declarations" : forward_declarations,
                        "relations" : relations,
                        "initialize_relations" : initialize_relations,
                        "deepcopy_relations" : deepcopy_relations,
                        "delete_relations" : delete_relations,
                        "delete_singlerelations" : delete_singlerelations,
                        "namespace_open" : namespace_open,
                        "namespace_close" : namespace_close
      }
      self.fill_templates("Obj",substitutions)
      self.created_classes.append(classname+"Obj")

    def prepare_vectorized_access(self, classname,members ):
      implementation = ""
      declaration = ""
      for member in members:
        name = member["name"]
        klass = member["type"]
        substitutions = { "classname" : classname,
                        "member"    : name,
                        "type"      : klass
                        }
        if klass not in self.buildin_types:
          substitutions["type"] = "class %s" % klass
        implementation += self.evaluate_template("CollectionReturnArray.cc.template", substitutions)
        declaration += "\ttemplate<size_t arraysize>\n\tconst std::array<%s,arraysize> %s() const;\n" %(klass, name)
      return declaration, implementation

    def write_file(self, name,content):
      #dispatch headers to header dir, the rest to /src
      # fullname = os.path.join(self.install_dir,self.package_name,name)
      if name.endswith("h"):
        fullname = os.path.join(self.install_dir,self.package_name,name)
      else:
        fullname = os.path.join(self.install_dir,"src",name)
      open(fullname, "w").write(content)

    def evaluate_template(self, filename, substitutions):
        """ reads in a given template, evaluates it
            and returns result
        """
        templatefile = os.path.join(self.template_dir,filename)
        template = open(templatefile,"r").read()
        return string.Template(template).substitute(substitutions)

    def fill_templates(self, category, substitutions):
      # "Data" denotes the real class;
      # only headers and the FN should not contain Data
      if category == "Data":
        FN = "Data"
        endings = ("h")
      elif category == "Obj":
        FN = "Obj"
        endings = ("h","cc")
      elif category == "Component":
        FN = ""
        endings = ("h")
      elif category == "Object":
        FN = ""
        endings = ("h","cc")
      elif category == "ConstObject":
        FN = "Const"
        endings = ("h","cc")
      else:
        FN = category
        endings = ("h","cc")
      for ending in endings:
        templatefile = "%s.%s.template" %(category,ending)
        templatefile = os.path.join(self.template_dir,templatefile)
        template = open(templatefile,"r").read()
        content = string.Template(template).substitute(substitutions).expandtabs(2)
        filename = "%s%s.%s" %(substitutions["name"],FN,ending)
        self.write_file(filename, content)
Пример #7
0
class ClassGenerator(object):

    def __init__(self, yamlfile, install_dir, package_name,
                 verbose=True, dryrun=False):

        self.yamlfile = yamlfile
        self.install_dir = install_dir
        self.package_name = package_name
        self.template_dir = os.path.join(thisdir, "../templates")
        self.verbose = verbose
        self.buildin_types = ClassDefinitionValidator.buildin_types
        self.created_classes = []
        self.requested_classes = []
        self.reader = PodioConfigReader(yamlfile)
        self.warnings = []
        self.component_members = {}
        self.dryrun = dryrun

    def process(self):
        self.reader.read()
        self.getSyntax = self.reader.options["getSyntax"]
        self.expose_pod_members = self.reader.options["exposePODMembers"]
        self.process_components(self.reader.components)
        self.process_datatypes(self.reader.datatypes)
        self.create_selection_xml()
        self.print_report()

    def process_components(self, content):
        self.requested_classes += content.keys()
        for name, components in content.iteritems():
            self.create_component(name, components["Members"])

    def process_datatypes(self, content):
        for name in content.iterkeys():
            self.requested_classes.append(name)
            self.requested_classes.append("%sData" % name)
        for name, components in content.iteritems():
            self.create_data(name, components)
            self.create_class(name, components)
            self.create_collection(name, components)
            self.create_obj(name, components)
            # self.create_PrintInfo(name, components)

    def print_report(self):
        if self.verbose:
            pkl = open(os.path.join(thisdir, "figure.txt"))
            figure = pickle.load(pkl)
            text = _text_ % (self.yamlfile,
                             len(self.created_classes),
                             self.install_dir
                             )
        cntr = 0
        print
        for figline, summaryline in zip(figure, text.splitlines()):
            cntr += 1
            print figline + summaryline
        for i in xrange(cntr, len(figure)):
            print figure[i]
        print "     'Homage to the Square' - Josef Albers"
        print

    def get_template(self, filename):
        templatefile = os.path.join(self.template_dir, filename)
        return open(templatefile, "r").read()

    def create_selection_xml(self):
        content = ""
        for klass in self.created_classes:
            # if not klass.endswith("Collection") or klass.endswith("Data"):
            content += '          <class name="std::vector<%s>" />\n' % klass
            content += """
            <class name="%s">
              <field name="m_registry" transient="true"/>
              <field name="m_container" transient="true"/>
            </class>\n""" % klass

        templatefile = os.path.join(self.template_dir,
                                    "selection.xml.template")
        template = open(templatefile, "r").read()
        content = string.Template(template).substitute({"classes": content})
        self.write_file("selection.xml", content)

    def process_datatype(self, classname, definition, is_data=False):
        datatype_dict = {}
        datatype_dict["description"] = definition["Description"]
        datatype_dict["author"] = definition["Author"]
        datatype_dict["includes"] = []
        datatype_dict["members"] = []
        members = definition["Members"]
        for member in members:
            klass = member["type"]
            name = member["name"]
            description = member["description"]
            datatype_dict["members"].append("  %s %s;  ///<%s"
                                            % (klass, name, description))
            if "std::string" == klass:
                datatype_dict["includes"].append("#include <string>")
                self.warnings.append("%s defines a string member %s, that spoils the PODness"
                                     % (classname, klass))
            elif klass in self.buildin_types:
                pass
            elif klass in self.requested_classes:
                if "::" in klass:
                    namespace, klassname = klass.split("::")
                    datatype_dict["includes"].append('#include "%s.h"'
                                                     % klassname)
                else:
                    datatype_dict["includes"].append('#include "%s.h"'
                                                     % klass)
            elif "std::array" in klass:
                datatype_dict["includes"].append("#include <array>")
                self.created_classes.append(klass)
            elif "vector" in klass:
                datatype_dict["includes"].append("#include <vector>")
                if is_data:  # avoid having warnings twice
                    self.warnings.append("%s defines a vector member %s, that spoils the PODness" % (classname, klass))
            elif "[" in klass and is_data:  # FIXME: is this only true ofr PODs?
                raise Exception("'%s' defines an array type. Array types are not supported yet." % (classname, klass))
            else:
                raise Exception("'%s' defines a member of a type '%s' that is not (yet) declared!" % (classname, klass))
        return datatype_dict


    def demangle_classname(self, classname):
      namespace_open = ""
      namespace_close = ""
      namespace = ""
      rawclassname = ""
      if "::" in classname:
        cnameparts = classname.split("::")
        if len(cnameparts) > 2:
          raise Exception("'%s' defines a type with nested namespaces. Not supported, yet." % classname)
        namespace, rawclassname = cnameparts
        namespace_open = "namespace %s {" % namespace
        namespace_close = "} // namespace %s" % namespace
      else:
        rawclassname = classname
      return namespace, rawclassname, namespace_open, namespace_close


    def create_data(self, classname, definition):
      # check whether all member types are known
      # and prepare include directives
      namespace, rawclassname, namespace_open, namespace_close = self.demangle_classname(classname)

      data = self.process_datatype(classname, definition)

      # now handle the vector-members
      vectormembers = definition["VectorMembers"]
      for vectormember in vectormembers:
        name = vectormember["name"]
        data["members"].append("  unsigned int %s_begin;" % name)
        data["members"].append("  unsigned int %s_end;" %(name))

      # now handle the one-to-many relations
      refvectors = definition["OneToManyRelations"]
      for refvector in refvectors:
        name = refvector["name"]
        data["members"].append("  unsigned int %s_begin;" %(name))
        data["members"].append("  unsigned int %s_end;" %(name))

      substitutions = {"includes" : "\n".join(data["includes"]),
                      "members"  : "\n".join(data["members"]),
                      "name"     : rawclassname,
                      "description" : data["description"],
                      "author"   :  data["author"],
                      "package_name" : self.package_name,
                      "namespace_open" : namespace_open,
                      "namespace_close" : namespace_close
      }
      self.fill_templates("Data", substitutions)
      self.created_classes.append(classname+"Data")

    def create_class(self, classname, definition):
      namespace, rawclassname, namespace_open, namespace_close = self.demangle_classname(classname)

      includes_cc = ""
      forward_declarations = ""
      forward_declarations_namespace = {"":[]}
      getter_implementations = ""
      setter_implementations = ""
      getter_declarations = ""
      setter_declarations = ""
      constructor_signature = ""
      constructor_body = ""
      ConstGetter_implementations = ""

      # check whether all member types are known
      # and prepare include directives
      datatype = self.process_datatype(classname, definition, False)

      datatype["includes"].append('#include "%s.h"' % (rawclassname+"Data"))

      # check on-to-one relations and prepare include directives
      oneToOneRelations = definition["OneToOneRelations"]
      for member in oneToOneRelations:
        klass = member["type"]
        if klass in self.requested_classes:
          mnamespace = ""
          klassname = klass
          if "::" in klass:
            mnamespace, klassname = klass.split("::")
            if mnamespace not in forward_declarations_namespace.keys():
              forward_declarations_namespace[mnamespace] = []

          forward_declarations_namespace[mnamespace] += ["class %s;\n" %(klassname)]
          forward_declarations_namespace[mnamespace] += ["class Const%s;\n" %(klassname)]
          includes_cc += '#include "%s.h"\n' %(klassname)

      for nsp in forward_declarations_namespace.iterkeys():
        if nsp != "":
          forward_declarations += "namespace %s {\n" % nsp
        forward_declarations += "".join(forward_declarations_namespace[nsp])
        if nsp != "":
          forward_declarations += "}\n"

      # check one-to-many relations for consistency
      # and prepare include directives
      refvectors = definition["OneToManyRelations"]
      if len(refvectors) != 0:
        datatype["includes"].append("#include <vector>")
      for item in refvectors:
        klass = item["type"]
        if klass in self.requested_classes:
          if "::" in klass:
            mnamespace, klassname = klass.split("::")
            datatype["includes"].append('#include "%s.h"' %klassname)
          else:
            datatype["includes"].append('#include "%s.h"' %klass)
        elif "std::array" in klass:
          datatype["includes"].append("#include <array>")
        else:
          raise Exception("'%s' declares a non-allowed many-relation to '%s'!" %(classname, klass))

      # handle standard members
      all_members = {}
      for member in definition["Members"]:
        name = member["name"]
        klass = member["type"]
        desc = member["description"]
        gname,sname = name,name
        if( self.getSyntax ):
          gname = "get" + name[:1].upper() + name[1:]
          sname = "set" + name[:1].upper() + name[1:]
        if name in all_members.keys():
          raise Exception("'%s' clashes with another member name in class '%s', previously defined in %s" % (name, classname, all_members[name]))
        all_members[name] = classname
        getter_declarations += declarations["member_getter"].format(type=klass, name=name,fname=gname, description=desc)
        getter_implementations += implementations["member_getter"].format(type=klass, classname=rawclassname, name=name, fname=gname)
        if klass in self.buildin_types:
          setter_declarations += declarations["member_builtin_setter"].format(type=klass, name=name, fname=sname, description=desc)
          setter_implementations += implementations["member_builtin_setter"].format(type=klass, classname=rawclassname, name=name, fname=sname)
        else:
          setter_declarations += declarations["member_class_refsetter"].format(type=klass, name=name, description=desc)
          setter_implementations += implementations["member_class_refsetter"].format(type=klass, classname=rawclassname, name=name, fname=sname)
          setter_declarations += declarations["member_class_setter"].format(type=klass, name=name, fname=sname, description=desc)
          setter_implementations += implementations["member_class_setter"].format(type=klass, classname=rawclassname, name=name, fname=sname)
          if self.expose_pod_members:
            sub_members = self.component_members[klass]
            for sub_member in sub_members:
              comp_member_class, comp_member_name = sub_member
              if comp_member_name in all_members.keys():
                raise Exception("'%s' clashes with another member name in class '%s' (defined in the component '%s' and '%s')" % (comp_member_name, classname, name, all_members[comp_member_name]))
              all_members[comp_member_name] = " member '" + name + "'"
              # use mystructMember with camel case as name to avoid clashes
              comp_gname, comp_sname = comp_member_name, comp_member_name
              if self.getSyntax:
                comp_gname = "get" + comp_member_name[:1].upper() + comp_member_name[1:]
                comp_sname = "set" + comp_member_name[:1].upper() + comp_member_name[1:]

              getter_declarations += declarations["pod_member_getter"].format(type=comp_member_class, name=comp_member_name, fname=comp_gname, compname=name, description=desc)
              getter_implementations += implementations["pod_member_getter"].format(type=comp_member_class, classname=rawclassname, name=comp_member_name, fname=comp_gname, compname=name, description=desc)
              if comp_member_class in self.buildin_types:
                setter_declarations += declarations["pod_member_builtin_setter"].format(type=comp_member_class, name=comp_member_name, fname=comp_sname, compname=name, description=desc)
                setter_implementations += implementations["pod_member_builtin_setter"].format(type=comp_member_class, classname=rawclassname, name=comp_member_name, fname=comp_sname, compname=name, description=desc)
              else:
                setter_declarations += declarations["pod_member_class_refsetter"].format(type=comp_member_class, name=comp_member_name, compname=name, description=desc)
                setter_implementations += implementations["pod_member_class_refsetter"].format(type=comp_member_class, classname=rawclassname, name=comp_member_name, fname=comp_sname, compname=name, description=desc)
                setter_declarations += declarations["pod_member_class_setter"].format(type=comp_member_class, name=comp_member_name, fname=comp_sname, compname=name, description=desc)
                setter_implementations += implementations["pod_member_class_setter"].format(type=comp_member_class, classname=rawclassname, fname=comp_sname, name=comp_member_name, compname=name, description=desc)
              ConstGetter_implementations += implementations["const_pod_member_getter"].format(type=comp_member_class, classname=rawclassname, name=comp_member_name, fname=comp_gname, compname=name, description=desc)

        # Getter for the Const variety of this datatype
        ConstGetter_implementations += implementations["const_member_getter"].format(type=klass, classname=rawclassname, name=name, fname=gname, description=desc)


        # set up signature
        constructor_signature += "%s %s," %(klass, name)
        # constructor
        constructor_body += "  m_obj->data.%s = %s;" %(name, name)

      # one-to-one relations
      for member in oneToOneRelations:
          name = member["name"]
          klass = member["type"]
          desc = member["description"]
          mnamespace = ""
          klassname = klass
          mnamespace, klassname, _, __ = self.demangle_classname(klass)

          setter_declarations += declarations["one_rel_setter"].format(name=name, namespace=mnamespace, type=klassname, description=desc)
          setter_implementations += implementations["one_rel_setter"].format(name=name, namespace=mnamespace, type=klassname, classname=rawclassname)
          getter_declarations += declarations["one_rel_getter"].format(name=name, namespace=mnamespace, type=klassname, description=desc)
          getter_implementations += implementations["one_rel_getter"].format(name=name, namespace=mnamespace, type=klassname, classname=rawclassname)
          ConstGetter_implementations += implementations["const_one_rel_getter"].format(name=name, namespace=mnamespace, type=klassname, classname=rawclassname, description=desc)


      # handle vector members
      vectormembers = definition["VectorMembers"]
      if len(vectormembers) != 0:
        datatype["includes"].append("#include <vector>")
      for item in vectormembers:
        klass = item["type"]
        if klass not in self.buildin_types and klass not in self.reader.components:
          raise Exception("'%s' declares a non-allowed vector member of type '%s'!" %(classname, klass))
        if klass in self.reader.components:
          if "::" in klass:
            namespace, klassname = klass.split("::")
            datatype["includes"].append('#include "%s.h"' %klassname)
          else:
            datatype["includes"].append('#include "%s.h"' %klass)

      # handle constructor from values
      constructor_signature = constructor_signature.rstrip(",")
      if constructor_signature == "":
        constructor_implementation = ""
        constructor_declaration = ""
        ConstConstructor_declaration = ""
        ConstConstructor_implementation = ""
      else:
        substitutions = { "name" : rawclassname,
                          "constructor" : constructor_body,
                          "signature" : constructor_signature
        }
        constructor_implementation = self.evaluate_template("Object.constructor.cc.template",substitutions)
        constructor_declaration = "  %s(%s);\n" %(rawclassname, constructor_signature)
        ConstConstructor_implementation = self.evaluate_template("ConstObject.constructor.cc.template",substitutions)
        ConstConstructor_declaration = "Const%s(%s);\n" %(rawclassname, constructor_signature)

      # handle one-to-many relations
      references_members = ""
      references_declarations = ""
      references = ""
      ConstReferences_declarations = ""
      ConstReferences = ""
      references_template = self.get_template("RefVector.cc.template")
      references_declarations_template = self.get_template("RefVector.h.template")
      ConstReferences_declarations_template = self.get_template("ConstRefVector.h.template")
      ConstReferences_template = self.get_template("ConstRefVector.cc.template")

      for refvector in refvectors+definition["VectorMembers"]:
        relnamespace, reltype, _, __ = self.demangle_classname(refvector["type"])
        relationtype = refvector["type"]
        if relationtype not in self.buildin_types and relationtype not in self.reader.components:
            relationtype = relnamespace+"::Const"+reltype

        relationName = refvector["name"]
        get_relation = relationName
        add_relation = "add"+relationName

        if( self.getSyntax ):
          get_relation = "get" + relationName[:1].upper() + relationName[1:]
          add_relation = "add" + relationName[:1].upper() + relationName[1:len(relationName)-1]  # drop the 's' at the end !??

        substitutions = {"relation" : relationName,
                        "get_relation" : get_relation,
                        "add_relation" : add_relation,
                        "relationtype" : relationtype,
                        "classname"  : rawclassname,
                        "package_name" : self.package_name
                        }
        references_declarations += string.Template(references_declarations_template).substitute(substitutions)
        references += string.Template(references_template).substitute(substitutions)
        references_members += "std::vector<%s>* m_%s; ///< transient \n" %(refvector["type"], refvector["name"])
        ConstReferences_declarations += string.Template(ConstReferences_declarations_template).substitute(substitutions)
        ConstReferences += string.Template(ConstReferences_template).substitute(substitutions)

      # handle user provided extra code
      extracode_declarations = ""
      extracode = ""
      constextracode_declarations = ""
      constextracode = ""
      if definition.has_key("ExtraCode"):
        extra = definition["ExtraCode"]
        if( extra.has_key("declaration")):
            extracode_declarations = extra["declaration"].replace("{name}",rawclassname)
        if( extra.has_key("implementation")):
            extracode = extra["implementation"].replace("{name}",rawclassname)
        if( extra.has_key("const_declaration")):
            constextracode_declarations = extra["const_declaration"].replace("{name}","Const"+rawclassname)
            extracode_declarations += "\n"
            extracode_declarations += extra["const_declaration"]
        if( extra.has_key("const_implementation")):
            constextracode = extra["const_implementation"].replace("{name}","Const"+rawclassname)
            extracode += "\n"
            extracode += extra["const_implementation"].replace("{name}",rawclassname)
        # TODO: add loading of code from external files
        if( extra.has_key("includes")):
            datatype["includes"].append( extra["includes"] )
            print " ***** adding includes : " ,  extra["includes"] , "to" ,  datatype["includes"]

      substitutions = {"includes" : "\n".join(datatype["includes"]),
                      "includes_cc" : includes_cc,
                      "forward_declarations" : forward_declarations,
                      "getters"  : getter_implementations,
                      "getter_declarations": getter_declarations,
                      "setters"  : setter_implementations,
                      "setter_declarations": setter_declarations,
                      "constructor_declaration" : constructor_declaration,
                      "constructor_implementation" : constructor_implementation,
                      "extracode" : extracode,
                      "extracode_declarations" : extracode_declarations,
                      "name"     : rawclassname,
                      "description" : datatype["description"],
                      "author"   : datatype["author"],
                      "relations" : references,
                      "relation_declarations" : references_declarations,
                      "relation_members" : references_members,
                      "package_name" : self.package_name,
                      "namespace_open" : namespace_open,
                      "namespace_close" : namespace_close, 
                     }
      self.fill_templates("Object",substitutions)
      self.created_classes.append(classname)


      substitutions["constructor_declaration"] = ConstConstructor_declaration
      substitutions["constructor_implementation"] = ConstConstructor_implementation
      substitutions["relation_declarations"] = ConstReferences_declarations
      substitutions["relations"] = ConstReferences
      substitutions["getters"]   = ConstGetter_implementations
      substitutions["constextracode"] = constextracode
      substitutions["constextracode_declarations"] = constextracode_declarations
      self.fill_templates("ConstObject", substitutions)
      if "::" in classname:
        self.created_classes.append("%s::Const%s" %(namespace, rawclassname))
      else:
        self.created_classes.append("Const%s" %classname)

    def create_collection(self, classname, definition):
      namespace, rawclassname, namespace_open, namespace_close = self.demangle_classname(classname)

      members = definition["Members"]
      constructorbody = ""
      destructorbody  = ""
      prepareforwritinghead = ""
      prepareforwritingbody = ""
      vectorized_access_decl, vectorized_access_impl = self.prepare_vectorized_access(rawclassname,members)
      setreferences = ""
      prepareafterread = ""
      includes = ""
      initializers = ""
      relations = ""
      create_relations = ""
      clear_relations  = ""
      push_back_relations = ""
      prepareafterread_refmembers = ""
      prepareforwriting_refmembers = ""

      refmembers = definition["OneToOneRelations"]
      refvectors = definition["OneToManyRelations"]
      nOfRefVectors = len(refvectors)
      nOfRefMembers = len(refmembers)
      if nOfRefVectors + nOfRefMembers > 0:
        # member initialization
        #constructorbody += "\tm_refCollections = new podio::CollRefCollection();\n"
        destructorbody  += "\tfor (auto& pointer : m_refCollections) { if (pointer != nullptr) delete pointer; }\n"
        clear_relations += "\tfor (auto& pointer : m_refCollections) { pointer->clear(); }\n"
        for counter, item in enumerate(refvectors):
          name  = item["name"]
          klass = item["type"]
          substitutions = { "counter" : counter,
                            "class" : klass,
                            "name"  : name }

          mnamespace, klassname, _, __ = self.demangle_classname(klass)

          # includes
          includes += '#include "%sCollection.h" \n' %(klassname)

          # FIXME check if it compiles with :: for both... then delete this.
          relations += declarations["relation"].format(namespace=mnamespace, type=klassname, name=name)
          relations += declarations["relation_collection"].format(namespace=mnamespace, type=klassname, name=name)
          initializers += implementations["ctor_list_relation"].format(namespace=mnamespace, type=klassname, name=name)

          constructorbody += "\tm_refCollections.push_back(new std::vector<podio::ObjectID>());\n"
          # relation handling in ::create
          create_relations += "\tm_rel_{name}_tmp.push_back(obj->m_{name});\n".format(name=name)
          # relation handling in ::clear
          clear_relations += implementations["clear_relations_vec"].format(name=name)
          clear_relations += implementations["clear_relations"].format(name=name)
          # relation handling in dtor:
          destructorbody += implementations["destroy_relations"].format(name=name)
          # relation handling in push_back
          push_back_relations += "\tm_rel_{name}_tmp.push_back(obj->m_{name});\n".format(name=name)
          # relation handling in ::prepareForWrite
          prepareforwritinghead += "\tint {name}_index =0;\n".format(name=name)
          prepareforwritingbody += self.evaluate_template("CollectionPrepareForWriting.cc.template",substitutions)
          # relation handling in ::settingReferences
          setreferences += self.evaluate_template("CollectionSetReferences.cc.template",substitutions)
          prepareafterread += "\t\tobj->m_%s = m_rel_%s;" %(name, name)
        for counter, item in enumerate(refmembers):
          name  = item["name"]
          klass = item["type"]
          mnamespace = ""
          klassname = klass
          if "::" in klass:
            mnamespace, klassname = klass.split("::")
          substitutions = { "counter" : counter+nOfRefVectors,
                            "class" : klass,
                            "rawclass" : klassname,
                            "name"  : name }


          # includes
          includes += '#include "%sCollection.h"\n' %(klassname)
          # constructor call
          initializers += implementations["ctor_list_relation"].format(namespace=mnamespace, type=klassname, name=name)
          # member
          relations += declarations["relation"].format(namespace=mnamespace, type=klassname, name=name)
          constructorbody += "\tm_refCollections.push_back(new std::vector<podio::ObjectID>());\n"
          # relation handling in ::clear
          clear_relations += implementations["clear_relations"].format(name=name)
          # relation handling in dtor:
          destructorbody += implementations["destroy_relations"].format(name=name)
          # relation handling in ::prepareForWrite
          prepareforwriting_refmembers += implementations["prep_writing_relations"].format(name=name, i=(counter+nOfRefVectors))
          # relation handling in ::settingReferences
          prepareafterread_refmembers += self.evaluate_template("CollectionSetSingleReference.cc.template",substitutions)
      substitutions = { "name" : rawclassname,
                        "constructorbody" : constructorbody,
                        "destructorbody"  : destructorbody,
                        "prepareforwritinghead" : prepareforwritinghead,
                        "prepareforwritingbody" : prepareforwritingbody,
                        "prepareforwriting_refmembers" : prepareforwriting_refmembers,
                        "setreferences" : setreferences,
                        "prepareafterread" : prepareafterread,
                        "prepareafterread_refmembers" : prepareafterread_refmembers,
                        "includes" : includes,
                        "initializers" : initializers,
                        "relations"           : relations,
                        "create_relations" : create_relations,
                        "clear_relations"  : clear_relations,
                        "push_back_relations" : push_back_relations,
                        "package_name" : self.package_name,
                        "vectorized_access_declaration" : vectorized_access_decl,
                        "vectorized_access_implementation" : vectorized_access_impl,
                        "namespace_open" : namespace_open,
                        "namespace_close" : namespace_close
      }
      self.fill_templates("Collection",substitutions)
      self.created_classes.append("%sCollection"%classname)

    def create_PrintInfo(self, classname, definition):
        namespace, rawclassname, namespace_open, namespace_close = self.demangle_classname(classname)

        toFormattingStrings = {"char" : "3" , "unsigned char" : "3", "long":"11", "longlong":"22", "bool":"1", "int":""}
        formats = {"char" : 3 , "unsigned char" : 3, "long": 11, "longlong": 22 , "bool": 1,}

        outputSingleObject = 'o << "' + classname + ':" << std::endl; \n     o << '
        WidthIntegers = ""
        widthOthers = ""
        findMaximum = ""
        setFormats = ""
        formattedOutput = ""
        tableHeader = ""
        for member in definition["Members"]:
            name = member["name"]
            lengthName = len(name)
            klass = member["type"]
            if(klass in toFormattingStrings  and not klass == "int"):
                if(formats[klass] > lengthName):
                    widthOthers = widthOthers + "  int"+ " " + name + "Width = " + toFormattingStrings[klass] + " ; \n"
                else:
                    widthOthers = widthOthers + "  int" + " " + name + "Width = " + str(lengthName) + " ; \n"
            elif klass == "int":
                findMaximum += "\n    int " + name + "Max ; \n"  
                findMaximum += "    " + name + "Width = 1 ; \n "
                findMaximum += "     for(int i = 0 ; i < value.size(); i++){ \n"
                findMaximum += "         if( value[i].get" + name[:1].upper() + name[1:] + "() > 0 ){ \n" 
                findMaximum += "            if(" + name + "Max <  value[i].get" + name[:1].upper() + name[1:] + "()){ \n"
                findMaximum += "               " + name + "Max = value[i].get" + name[:1].upper() + name[1:] + "();"
                findMaximum += "\n            } \n" 
                findMaximum += "\n         } \n" 
                findMaximum += "         else if( -" + name + "Max / 10 > value[i].get" + name[:1].upper() + name[1:] + "()){ \n"
                findMaximum += "             " + name + "Max = - value[i].get" +  name[:1].upper() + name[1:] + "() * 10; "
                findMaximum += "\n         } \n"
                findMaximum += "     } \n"
                setFormats  += "\n    while(" + name + "Max != 0){ \n"
                setFormats  += "       " + name + "Width++; \n       " + name + "Max = " + name + "Max / 10; \n    } \n"
                setFormats  += "   if(" + name + "Width < " + str(lengthName) + "){ " + name + "Width = " + str(lengthName) + ";} \n"
                WidthIntegers = WidthIntegers + "  " + klass + " " + name + "Width = 1 ; \n"
            elif(klass == "double" or klass == "float"):
                if(lengthName > 12):
                    widthOthers = widthOthers + "  int" + " " + name + "Width = " + str(lengthName) + " ; \n"
                else:
                    widthOthers = widthOthers + "  int" + " " + name + "Width = 12 ; \n"
            elif(klass == "DoubleThree" or klass == "FloatThree"):
                if(lengthName > 38):
                    widthOthers = widthOthers + "  int" + " " + name + "Width = " + str(lengthName) + " ; \n"
                else:
                    widthOthers += "  int" + " " + name + "Width = 38 ; \n"
            elif(klass == "IntTwo"):
                if(lengthName > 24):
                    widthOthers = widthOthers + "  int" + " " + name + "Width = " + str(lengthName) + " ; \n"
                else:
                    widthOthers += "  int" + " " + name + "Width = 24 ; \n"
            else:
                widthOthers = widthOthers + "  int" + " " + name + "Width = 38 ; \n"
            if(klass != "StingVec"):
                tableHeader += 'std::setw(' + classname + "PrintInfo::instance()." + name + 'Width) << "' + name + '" << "|" << '
                if(klass == "DoubleThree" or klass == "FloatThree" or klass == "StringVec"):
                    formattedOutput += " value[i].get" + name[:1].upper() + name[1:] + '() << " "' + " << "
                else:
                    formattedOutput += " std::setw(" + classname + "PrintInfo::instance()." + name + "Width)"
                    formattedOutput += " << value[i].get" + name[:1].upper() + name[1:] + '() << " "' + " << "
                    outputSingleObject += '"' + klass + '" << " " << "' + name + '" << " "' + " << value.get" + name[:1].upper() + name[1:] + '() << " "' + " << "


        substitutions = { "name" : rawclassname,
                      "widthIntegers" : WidthIntegers,
                      "widthOthers"   : widthOthers,
                      "findMaximum"   : findMaximum,
                      "setFormats"    : setFormats,
                      "formattedOutput" : formattedOutput,
                      "tableHeader"   : tableHeader,
                      "outputSingleObject" : outputSingleObject
                      }
 
      # TODO: add loading of code from external files

        self.fill_templates("PrintInfo",substitutions)
        self.created_classes.append(classname)


    def create_component(self, classname, components):
      """ Create a component class to be used within the data types
          Components can only contain simple data types and no user
          defined ones
      """
      namespace, rawclassname, namespace_open, namespace_close = self.demangle_classname(classname)

      includes = ""
      members = ""
      extracode_declarations = ""
      ostreamComponents = ""
      printed = [""]
      self.component_members[classname] = []
      #fg: sort the dictionary, so at least we get a predictable order (alphabetical) of the members
      keys = sorted( components.keys() )
      for name in keys:
        klass = components[ name ]
  #    for name, klass in components.iteritems():
        if( name != "ExtraCode"):
          klassname = klass
          mnamespace = ""
          if "::" in klass:
            mnamespace, klassname = klass.split("::")
          if mnamespace == "":
              if((classname == "DoubleThree" or classname == "FloatThree") and not classname in printed):
                    ostreamComponents +=  "   inline std::ostream& operator<<( std::ostream& o,const " + classname + "& value ){ \n"
                    ostreamComponents +=  "       for(unsigned int i = 0; i < 3; i++){ \n"
                    ostreamComponents +=  '          o << value[i] << " " ; } \n'
                    ostreamComponents +=  "       return o ; \n"
                    ostreamComponents +=  "   } \n \n"
                    printed += [classname]
              elif(classname == "IntTwo" and not classname in printed):
                    ostreamComponents +=  "   inline std::ostream& operator<<( std::ostream& o,const " + classname + "& value ){ \n"
                    ostreamComponents +=  "       for(unsigned int i = 0; i < 2; i++){ \n"
                    ostreamComponents +=  '          o << value[i] << " " ; } \n'
                    ostreamComponents +=  "       return o ; \n"
                    ostreamComponents +=  "   } \n \n"
                    printed += [classname]
              elif(classname == "StringVec" and not classname in printed):
                    ostreamComponents +=  "   inline std::ostream& operator<<( std::ostream& o,const " + classname + "& value ){ \n"
                    ostreamComponents +=  "       for(unsigned int i = 0; i < value.size(); i++){"
                    ostreamComponents +=  '          o << value[i] << " " ; } \n'
                    ostreamComponents +=  "       return o ; \n"
                    ostreamComponents +=  "   } \n \n"
                    printed += [classname] 
              members+= "  %s %s;\n" %(klassname, name)
              self.component_members[classname].append([klassname, name])
          else:
            members += " ::%s::%s %s;\n" %(mnamespace, klassname, name)
            self.component_members[classname].append(["::%s::%s" % (mnamespace, klassname), name])
          if self.reader.components.has_key(klass):
              includes+= '#include "%s.h"\n' %(klassname)
        else:
          # handle user provided extra code
          if klass.has_key("declaration"):
            extracode_declarations = klass["declaration"]


      substitutions = { "ostreamComponents" : ostreamComponents,
                        "includes" : includes,
                        "members"  : members,
                        "extracode_declarations" : extracode_declarations,
                        "name"     : rawclassname,
                        "package_name" : self.package_name,
                        "namespace_open" : namespace_open,
                        "namespace_close" : namespace_close
      }
      self.fill_templates("Component",substitutions)
      self.created_classes.append(classname)

    def create_obj(self, classname, definition):
      """ Create an obj class containing all information
          relevant for a given object.
      """
      namespace, rawclassname, namespace_open, namespace_close = self.demangle_classname(classname)

      relations = ""
      includes = ""
      includes_cc = ""
      forward_declarations = ""
      forward_declarations_namespace = {"":[]}
      initialize_relations = ""
      set_relations = ""
      deepcopy_relations = ""
      delete_relations = ""
      delete_singlerelations = ""
      refvectors = definition["OneToManyRelations"]
      singleRelations = definition["OneToOneRelations"]
      # do includes and forward declarations for
      # oneToOneRelations and do proper cleanups
      for item in singleRelations:
        name  = item["name"]
        klass = item["type"]
        klassname = klass
        mnamespace = ""
        if klass not in self.buildin_types:
          if "::" in klass:
            mnamespace, klassname = klass.split("::")
            klassWithQualifier = "::"+mnamespace+"::Const"+klassname
            if mnamespace not in forward_declarations_namespace.keys():
              forward_declarations_namespace[mnamespace] = []
          else:
            klassWithQualifier = "Const"+klass
        else:
          klassWithQualifier = klass

        if mnamespace != "":
          relations+= "  ::%s::Const%s* m_%s;\n" %(mnamespace, klassname, name)
        else:
          relations+= "  Const%s* m_%s;\n" %(klassname, name)

        if klass not in self.buildin_types:
          if klass != classname:
            forward_declarations_namespace[mnamespace] += ['class Const%s;\n' %(klassname)]
            includes_cc += '#include "%sConst.h"\n' %(klassname)
            initialize_relations += ", m_%s(nullptr)\n" %(name)
            # for deep copy initialise as nullptr and set in copy ctor body if copied object has non-trivial relation
            deepcopy_relations += ", m_%s(nullptr)" % (name)
            set_relations += implementations["set_relations"].format(name=name, klass=klassWithQualifier)
          delete_singlerelations+="\t\tif (m_%s != nullptr) delete m_%s;\n" % (name, name)

      for nsp in forward_declarations_namespace.iterkeys():
        if nsp != "":
          forward_declarations += "namespace %s {" % nsp
        forward_declarations += "".join(forward_declarations_namespace[nsp])
        if nsp != "":
          forward_declarations += "}\n"

      if len(refvectors+definition["VectorMembers"]) !=0:
        includes += "#include <vector>\n"

      for item in refvectors+definition["VectorMembers"]:
        name  = item["name"]
        klass = item["type"]
        if klass not in self.buildin_types:
          if klass not in self.reader.components:
            if "::" in klass:
              mnamespace, klassname = klass.split("::")
              klassWithQualifier = "::"+mnamespace+"::Const"+klassname
            else:
              klassWithQualifier = "Const"+klass
          else:
              klassWithQualifier = klass
          relations += "\tstd::vector<%s>* m_%s;\n" %(klassWithQualifier, name)
          initialize_relations += ", m_%s(new std::vector<%s>())" %(name,klassWithQualifier)
          deepcopy_relations += ", m_%s(new std::vector<%s>(*(other.m_%s)))" %(name,klassWithQualifier,name)
          if klass == classname:
            includes_cc += '#include "%s.h"\n' %(rawclassname)
          else:
            if "::" in klass:
              mnamespace, klassname = klass.split("::")
              includes += '#include "%s.h"\n' %klassname
            else:
              includes += '#include "%s.h"\n' %klass
        else:
            relations += "\tstd::vector<%s>* m_%s;\n" %(klass, name)
            initialize_relations += ", m_%s(new std::vector<%s>())" %(name,klass)
            deepcopy_relations += ", m_%s(new std::vector<%s>(*(other.m_%s)))" %(name,klass,name)

        delete_relations += "\t\tdelete m_%s;\n" %(name)
      substitutions = { "name" : rawclassname,
                        "includes" : includes,
                        "includes_cc" : includes_cc,
                        "forward_declarations" : forward_declarations,
                        "relations" : relations,
                        "initialize_relations" : initialize_relations,
                        "deepcopy_relations" : deepcopy_relations,
                        "delete_relations" : delete_relations,
                        "delete_singlerelations" : delete_singlerelations,
                        "namespace_open" : namespace_open,
                        "namespace_close" : namespace_close,
                        "set_deepcopy_relations": set_relations
      }
      self.fill_templates("Obj",substitutions)
      self.created_classes.append(classname+"Obj")

    def prepare_vectorized_access(self, classname,members ):
      implementation = ""
      declaration = ""
      for member in members:
        name = member["name"]
        klass = member["type"]
        substitutions = { "classname" : classname,
                        "member"    : name,
                        "type"      : klass
                        }
        if klass not in self.buildin_types:
          substitutions["type"] = "class %s" % klass
        implementation += self.evaluate_template("CollectionReturnArray.cc.template", substitutions)
        declaration += "\ttemplate<size_t arraysize>\n\tconst std::array<%s,arraysize> %s() const;\n" %(klass, name)
      return declaration, implementation

    def write_file(self, name,content):
      #dispatch headers to header dir, the rest to /src
      # fullname = os.path.join(self.install_dir,self.package_name,name)
      if name.endswith("h"):
        fullname = os.path.join(self.install_dir,self.package_name,name)
      else:
        fullname = os.path.join(self.install_dir,"src",name)
      if not self.dryrun:
        open(fullname, "w").write(content)

    def evaluate_template(self, filename, substitutions):
        """ reads in a given template, evaluates it
            and returns result
        """
        templatefile = os.path.join(self.template_dir,filename)
        template = open(templatefile,"r").read()
        return string.Template(template).substitute(substitutions)

    def fill_templates(self, category, substitutions):
      # "Data" denotes the real class;
      # only headers and the FN should not contain Data
      if category == "Data":
        FN = "Data"
        endings = ("h")
      elif category == "Obj":
        FN = "Obj"
        endings = ("h","cc")
      elif category == "Component":
        FN = ""
        endings = ("h")
      elif category == "Object":
        FN = ""
        endings = ("h","cc")
      elif category == "ConstObject":
        FN = "Const"
        endings = ("h","cc")
      elif category == "PrintInfo":
        FN = "PrintInfo"
        endings = ("h")
      else:
        FN = category
        endings = ("h","cc")
      for ending in endings:
        templatefile = "%s.%s.template" %(category,ending)
        templatefile = os.path.join(self.template_dir,templatefile)
        template = open(templatefile,"r").read()
        content = string.Template(template).substitute(substitutions).expandtabs(2)
        filename = "%s%s.%s" %(substitutions["name"],FN,ending)
        self.write_file(filename, content)