Package pyplusplus :: Package utils

# Source Code for Package pyplusplus.utils

      1  # Copyright 2004-2008 Roman Yakovenko.
      2  # Distributed under the Boost Software License, Version 1.0. (See
      3  # accompanying file LICENSE_1_0.txt or copy at
      4  # http://www.boost.org/LICENSE_1_0.txt)
      5
      6  """
      7  This module is a collection of unrelated algorithms, that works on code creators
      8  tree.
      9  """
     10  import os
     11  import math
     12  from pygccxml import declarations
     13  from pyplusplus import code_creators
     14
     15 -class missing_call_policies:
     16      @staticmethod
     17 -    def _selector( creator ):
     18          if not isinstance( creator, code_creators.declaration_based_t ):
     19              return False
     20          if not isinstance( creator.declaration, declarations.calldef_t ):
     21              return False
     22          if isinstance( creator.declaration, declarations.constructor_t ):
     23              return False
     24          return hasattr(creator, 'call_policies') and not creator.call_policies
     25
     26      @staticmethod
     27 -    def print_( extmodule ):
     28          creators = filter( missing_call_policies._selector
     29                             , code_creators.make_flatten_generator( extmodule.creators ) )
     30          for creator in creators:
     31              print creator.declaration.__class__.__name__, ': ', declarations.full_name( creator.declaration )
     32              print '  *** MISSING CALL POLICY', creator.declaration.function_type().decl_string
     33              print
     34
     35      @staticmethod
     36 -    def exclude( extmodule ):
     37          creators = filter( missing_call_policies._selector
     38                             , code_creators.make_flatten_generator( extmodule.creators ) )
     39          for creator in creators:
     40              creator.parent.remove_creator( creator )
     41
     42 -def split_sequence(seq, bucket_size):
     43      #split sequence to buckets, where every will contain maximum bucket_size items
     44      seq_len = len( seq )
     45      if seq_len <= bucket_size:
     46          return [ seq ]
     47      buckets = []
     48      num_of_buckets = int( math.ceil( float( seq_len ) / bucket_size ) )
     49      for i in range(num_of_buckets):
     50          from_ = i * bucket_size
     51          to = min( ( i + 1) * bucket_size, seq_len )
     52          buckets.append( seq[ from_ : to ] )
     53      return buckets
     54
     55
     56 -class exposed_decls_db_t( object ):
     57      DEFAULT_FILE_NAME = 'exposed_decl.pypp.txt'
     58 -    class row_t( declarations.decl_visitor_t ):
     59          FIELD_DELIMITER = '@'
     60          EXPOSED_DECL_SIGN = '+'
     61          UNEXPOSED_DECL_SIGN = '~'
     62          CALLDEF_SIGNATURE_DELIMITER = '#'
     63
     64 -        def __init__( self, decl_or_string ):
     65              self.key = ''
     66              self.signature = ''
     67              self.exposed_sign = ''
     68              self.normalized_name = ''
     69              if isinstance( decl_or_string, declarations.declaration_t ):
     70                  self.__init_from_decl( decl_or_string )
     71              else:
     72                  self.__init_from_str( decl_or_string )
     73
     74 -        def find_out_normalized_name( self, decl ):
     75              if decl.name:
     76                  return decl.partial_name
     77              elif decl.location:#unnamed enums, classes, unions
     78                  return str( decl.location.as_tuple() )
     79              elif isinstance( decl, declarations.namespace_t ):
     80                  return '' #I don't really care about unnamed namespaces
     81              else: #this should nevere happen
     82                  raise RuntimeError( "Unable to create normalized name for declaration: " + str(decl))
     83
     84 -        def __init_from_str( self, row ):
     85              self.exposed_sign, self.key, self.normalized_name, self.signature \
     86                  = row.split( self.FIELD_DELIMITER )
     87
     88 -        def update_key( self, cls ):
     89              self.key = cls.__name__
     90
     91 -        def __init_from_decl( self, decl ):
     92              if decl.ignore:
     93                  self.exposed_sign = self.UNEXPOSED_DECL_SIGN
     94              else:
     95                  self.exposed_sign = self.EXPOSED_DECL_SIGN
     96
     97              self.update_key( decl.__class__ )
     98
     99              self.signature = decl.create_decl_string( with_defaults=False )
    100              if isinstance( decl, declarations.calldef_t ):
    101                  self.signature = self.signature + decl.function_type().decl_string
    102
    103              self.normalized_name = self.find_out_normalized_name( decl )
    104
    105 -        def __str__( self ):
    106              return self.FIELD_DELIMITER.join([ self.exposed_sign
    107                                                 , self.key
    108                                                 , self.normalized_name
    109                                                 , self.signature])
    110
    111 -        def does_refer_same_decl( self, other ):
    112              return self.key == other.key \
    113                     and self.signature == other.signature \
    114                     and self.normalized_name == other.normalized_name
    115
    116 -    def __init__( self ):
    117          self.__registry = {} # key : { name : set(row) }
    118          self.__row_delimiter = os.linesep
    119
    120 -    def save( self, fpath ):
    121          if os.path.isdir( fpath ):
    122              fpath = os.path.join( fpath, self.DEFAULT_FILE_NAME )
    123          f = file( fpath, 'w+b' )
    124          for name2rows in self.__registry.itervalues():
    125              for rows in name2rows.itervalues():
    126                  for row in rows:
    127                      f.write( '%s%s' % ( str(row), self.__row_delimiter ) )
    128          f.close()
    129
    130 -    def load( self, fpath ):
    131          if os.path.isdir( fpath ):
    132              fpath = os.path.join( fpath, self.DEFAULT_FILE_NAME )
    133          f = file( fpath, 'r+b' )
    134          for line in f:
    135              row = self.row_t( line.replace( self.__row_delimiter, '' ) )
    136              self.__update_registry( row )
    137
    138 -    def __update_registry( self, row ):
    139          if not self.__registry.has_key( row.key ):
    140              self.__registry[ row.key ] = { row.normalized_name : [row] }
    141          else:
    142              if not self.__registry[ row.key ].has_key( row.normalized_name ):
    143                  self.__registry[ row.key ][row.normalized_name] = [row]
    144              else:
    145                  self.__registry[ row.key ][row.normalized_name].append(row)
    146
    147 -    def __find_row_in_registry( self, row ):
    148          try:
    149              decls = filter( lambda rrow: rrow.does_refer_same_decl( row )
    150                              , self.__registry[ row.key ][ row.normalized_name ] )
    151              if decls:
    152                  return decls[0]
    153              else:
    154                  return None
    155          except KeyError:
    156              return None
    157
    158 -    def __find_in_registry( self, decl ):
    159          row = self.row_t( decl )
    160          found = self.__find_row_in_registry( row )
    161          if found:
    162              return found
    163          if isinstance( decl, declarations.class_t ):
    164              row.update_key( declarations.class_declaration_t )
    165              found = self.__find_row_in_registry( row )
    166              if found:
    167                  return found
    168          if isinstance( decl, declarations.class_declaration_t ):
    169              row.update_key( declarations.class_t )
    170              found = self.__find_row_in_registry( row )
    171              if found:
    172                  return found
    173          return None
    174
    175 -    def is_exposed( self, decl ):
    176          row = self.__find_in_registry( decl)
    177          return row and self.row_t.EXPOSED_DECL_SIGN == row.exposed_sign
    178
    179 -    def update_decls( self, global_ns ):
    180          for decl in global_ns.decls():
    181              row = self.__find_in_registry( decl )
    182              if not row:
    183                  continue
    184              if self.row_t.EXPOSED_DECL_SIGN == row.exposed_sign:
    185                  decl.ignore = False
    186                  decl.already_exposed = True
    187              else:
    188                  decl.ignore = True
    189                  decl.already_exposed = False
    190
    191 -    def register_decls( self, global_ns, special_decls ):
    192          """register decls in the database
    193
    194          global_ns - reference to the global namespace object
    195          special_decls - set of declarations, which were exposed, even so they
    196          were not ``included``. For example std containers.
    197          """
    198          for decl in global_ns.decls():
    199              row = self.row_t( decl )
    200              if decl in special_decls:
    201                  row.exposed_sign = row.EXPOSED_DECL_SIGN
    202              self.__update_registry( row )
    203