Package pygccxml :: Package declarations :: Module container_traits

Source Code for Module pygccxml.declarations.container_traits

  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  defines few algorithms, that deals with different properties of std containers 
  8  """ 
  9   
 10  import types 
 11  import string 
 12  import calldef 
 13  import cpptypes 
 14  import namespace 
 15  import templates 
 16  import type_traits 
 17  import class_declaration 
 18   
 19  std_namespaces = ( 'std', 'stdext', '__gnu_cxx' ) 
20 21 -class defaults_eraser:
22 @staticmethod
23 - def normalize( type_str ):
24 return type_str.replace( ' ', '' )
25 26 @staticmethod
27 - def replace_basic_string( cls_name ):
28 strings = { 29 'std::string' : ( 'std::basic_string<char,std::char_traits<char>,std::allocator<char> >' 30 , 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >' ) 31 , 'std::wstring' : ( 'std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >' 32 , 'std::basic_string<wchar_t, std::char_traits<wchar_t>, std::allocator<wchar_t> >' ) } 33 34 new_name = cls_name 35 for short_name, long_names in strings.iteritems(): 36 for lname in long_names: 37 new_name = new_name.replace( lname, short_name ) 38 return new_name
39
40 - class recursive_impl:
41 @staticmethod
42 - def decorated_call_prefix( cls_name, text, doit ):
43 has_text = cls_name.startswith( text ) 44 if has_text: 45 cls_name = cls_name[ len( text ): ] 46 answer = doit( cls_name ) 47 if has_text: 48 answer = text + answer 49 return answer
50 51 @staticmethod
52 - def decorated_call_suffix( cls_name, text, doit ):
53 has_text = cls_name.endswith( text ) 54 if has_text: 55 cls_name = cls_name[: len( text )] 56 answer = doit( cls_name ) 57 if has_text: 58 answer = answer + text 59 return answer
60 61 @staticmethod
62 - def erase_call( cls_name ):
63 global find_container_traits 64 c_traits = find_container_traits( cls_name ) 65 if not c_traits: 66 return cls_name 67 return c_traits.remove_defaults( cls_name )
68 69 @staticmethod
70 - def erase_recursive( cls_name ):
71 ri = defaults_eraser.recursive_impl 72 no_std = lambda cls_name: ri.decorated_call_prefix( cls_name, 'std::', ri.erase_call ) 73 no_stdext = lambda cls_name: ri.decorated_call_prefix( cls_name, 'stdext::', no_std ) 74 no_gnustd = lambda cls_name: ri.decorated_call_prefix( cls_name, '__gnu_cxx::', no_stdext ) 75 no_const = lambda cls_name: ri.decorated_call_prefix( cls_name, 'const ', no_gnustd ) 76 no_end_const = lambda cls_name: ri.decorated_call_suffix( cls_name, ' const', no_const ) 77 return no_end_const( cls_name )
78 79 @staticmethod
80 - def erase_recursive( cls_name ):
82 83 @staticmethod
84 - def erase_allocator( cls_name, default_allocator='std::allocator' ):
85 cls_name = defaults_eraser.replace_basic_string( cls_name ) 86 c_name, c_args = templates.split( cls_name ) 87 if 2 != len( c_args ): 88 return 89 value_type = c_args[0] 90 tmpl = string.Template( "$container< $value_type, $allocator<$value_type> >" ) 91 tmpl = tmpl.substitute( container=c_name, value_type=value_type, allocator=default_allocator ) 92 if defaults_eraser.normalize( cls_name ) == defaults_eraser.normalize( tmpl ): 93 return templates.join( c_name, [defaults_eraser.erase_recursive( value_type )] )
94 95 @staticmethod
96 - def erase_container( cls_name, default_container_name='std::deque' ):
97 cls_name = defaults_eraser.replace_basic_string( cls_name ) 98 c_name, c_args = templates.split( cls_name ) 99 if 2 != len( c_args ): 100 return 101 value_type = c_args[0] 102 dc_no_defaults = defaults_eraser.erase_recursive( c_args[1] ) 103 if defaults_eraser.normalize( dc_no_defaults ) \ 104 != defaults_eraser.normalize( templates.join( default_container_name, [value_type] ) ): 105 return 106 return templates.join( c_name, [defaults_eraser.erase_recursive( value_type )] )
107 108 @staticmethod
109 - def erase_container_compare( cls_name, default_container_name='std::vector', default_compare='std::less' ):
110 cls_name = defaults_eraser.replace_basic_string( cls_name ) 111 c_name, c_args = templates.split( cls_name ) 112 if 3 != len( c_args ): 113 return 114 dc_no_defaults = defaults_eraser.erase_recursive( c_args[1] ) 115 if defaults_eraser.normalize( dc_no_defaults ) \ 116 != defaults_eraser.normalize( templates.join( default_container_name, [c_args[0]] ) ): 117 return 118 dcomp_no_defaults = defaults_eraser.erase_recursive( c_args[2] ) 119 if defaults_eraser.normalize( dcomp_no_defaults ) \ 120 != defaults_eraser.normalize( templates.join( default_compare, [c_args[0]] ) ): 121 return 122 value_type = defaults_eraser.erase_recursive( c_args[0] ) 123 return templates.join( c_name, [value_type] )
124 125 @staticmethod
126 - def erase_compare_allocator( cls_name, default_compare='std::less', default_allocator='std::allocator' ):
127 cls_name = defaults_eraser.replace_basic_string( cls_name ) 128 c_name, c_args = templates.split( cls_name ) 129 if 3 != len( c_args ): 130 return 131 value_type = c_args[0] 132 tmpl = string.Template( "$container< $value_type, $compare<$value_type>, $allocator<$value_type> >" ) 133 tmpl = tmpl.substitute( container=c_name 134 , value_type=value_type 135 , compare=default_compare 136 , allocator=default_allocator ) 137 if defaults_eraser.normalize( cls_name ) == defaults_eraser.normalize( tmpl ): 138 return templates.join( c_name, [defaults_eraser.erase_recursive( value_type )] )
139 140 @staticmethod
141 - def erase_map_compare_allocator( cls_name, default_compare='std::less', default_allocator='std::allocator' ):
142 cls_name = defaults_eraser.replace_basic_string( cls_name ) 143 c_name, c_args = templates.split( cls_name ) 144 if 4 != len( c_args ): 145 return 146 key_type = c_args[0] 147 mapped_type = c_args[1] 148 tmpls = [ 149 string.Template( "$container< $key_type, $mapped_type, $compare<$key_type>, $allocator< std::pair< const $key_type, $mapped_type> > >" ) 150 , string.Template( "$container< $key_type, $mapped_type, $compare<$key_type>, $allocator< std::pair< $key_type const, $mapped_type> > >" ) 151 , string.Template( "$container< $key_type, $mapped_type, $compare<$key_type>, $allocator< std::pair< $key_type, $mapped_type> > >" )] 152 for tmpl in tmpls: 153 tmpl = tmpl.substitute( container=c_name 154 , key_type=key_type 155 , mapped_type=mapped_type 156 , compare=default_compare 157 , allocator=default_allocator ) 158 if defaults_eraser.normalize( cls_name ) == defaults_eraser.normalize( tmpl ): 159 return templates.join( c_name 160 , [ defaults_eraser.erase_recursive( key_type ) 161 , defaults_eraser.erase_recursive( mapped_type )] )
162 163 164 @staticmethod
165 - def erase_hash_allocator( cls_name ):
166 cls_name = defaults_eraser.replace_basic_string( cls_name ) 167 c_name, c_args = templates.split( cls_name ) 168 if len( c_args ) < 3: 169 return 170 171 default_hash=None 172 default_less='std::less' 173 default_equal_to='std::equal_to' 174 default_allocator='std::allocator' 175 176 tmpl = None 177 if 3 == len( c_args ): 178 default_hash='hash_compare' 179 tmpl = "$container< $value_type, $hash<$value_type, $less<$value_type> >, $allocator<$value_type> >" 180 elif 4 == len( c_args ): 181 default_hash='hash' 182 tmpl = "$container< $value_type, $hash<$value_type >, $equal_to<$value_type >, $allocator<$value_type> >" 183 else: 184 return 185 186 value_type = c_args[0] 187 tmpl = string.Template( tmpl ) 188 for ns in std_namespaces: 189 inst = tmpl.substitute( container=c_name 190 , value_type=value_type 191 , hash= ns + '::' + default_hash 192 , less=default_less 193 , equal_to=default_equal_to 194 , allocator=default_allocator ) 195 if defaults_eraser.normalize( cls_name ) == defaults_eraser.normalize( inst ): 196 return templates.join( c_name, [defaults_eraser.erase_recursive( value_type )] )
197 198 199 @staticmethod
200 - def erase_hashmap_compare_allocator( cls_name ):
201 cls_name = defaults_eraser.replace_basic_string( cls_name ) 202 c_name, c_args = templates.split( cls_name ) 203 204 default_hash=None 205 default_less='std::less' 206 default_allocator='std::allocator' 207 default_equal_to = 'std::equal_to' 208 209 tmpl = None 210 key_type = None 211 mapped_type = None 212 if 2 < len( c_args ): 213 key_type = c_args[0] 214 mapped_type = c_args[1] 215 else: 216 return 217 218 if 4 == len( c_args ): 219 default_hash = 'hash_compare' 220 tmpl = string.Template( "$container< $key_type, $mapped_type, $hash<$key_type, $less<$key_type> >, $allocator< std::pair< const $key_type, $mapped_type> > >" ) 221 if key_type.startswith( 'const ' ) or key_type.endswith( ' const' ): 222 tmpl = string.Template( "$container< $key_type, $mapped_type, $hash<$key_type, $less<$key_type> >, $allocator< std::pair< $key_type, $mapped_type> > >" ) 223 elif 5 == len( c_args ): 224 default_hash = 'hash' 225 tmpl = string.Template( "$container< $key_type, $mapped_type, $hash<$key_type >, $equal_to<$key_type>, $allocator< $mapped_type> >" ) 226 if key_type.startswith( 'const ' ) or key_type.endswith( ' const' ): 227 tmpl = string.Template( "$container< $key_type, $mapped_type, $hash<$key_type >, $equal_to<$key_type>, $allocator< $mapped_type > >" ) 228 else: 229 return 230 231 for ns in std_namespaces: 232 inst = tmpl.substitute( container=c_name 233 , key_type=key_type 234 , mapped_type=mapped_type 235 , hash=ns + '::' + default_hash 236 , less=default_less 237 , equal_to = default_equal_to 238 , allocator=default_allocator ) 239 if defaults_eraser.normalize( cls_name ) == defaults_eraser.normalize( inst ): 240 return templates.join( c_name 241 , [ defaults_eraser.erase_recursive( key_type ) 242 , defaults_eraser.erase_recursive( mapped_type )] )
243
244 245 -class container_traits_impl_t:
246 """this class implements the functionality needed for convinient work with 247 STD container classes. 248 249 Implemented functionality: 250 - find out whether a declaration is STD container or not 251 - find out container value( mapped ) type 252 253 This class tries to be useful as much, as possible. For example, for class 254 declaration( and not definition ) it parsers the class name in order to 255 extract all the information. 256 """
257 - def __init__( self 258 , container_name 259 , element_type_index 260 , element_type_typedef 261 , defaults_remover 262 , key_type_index=None 263 , key_type_typedef=None ):
264 """ 265 container_name - std container name 266 element_type_index - position of value\\mapped type within template 267 arguments list 268 element_type_typedef - class typedef to the value\\mapped type 269 key_type_index - position of key type within template arguments list 270 key_type_typedef - class typedef to the key type 271 """ 272 self._name = container_name 273 self.remove_defaults_impl = defaults_remover 274 self.element_type_index = element_type_index 275 self.element_type_typedef = element_type_typedef 276 self.key_type_index = key_type_index 277 self.key_type_typedef = key_type_typedef
278
279 - def name(self):
280 return self._name
281
282 - def get_container_or_none( self, type ):
283 """returns reference to the class declaration or None""" 284 type = type_traits.remove_alias( type ) 285 type = type_traits.remove_cv( type ) 286 287 cls = None 288 if isinstance( type, cpptypes.declarated_t ): 289 cls = type_traits.remove_alias( type.declaration ) 290 elif isinstance( type, class_declaration.class_t ): 291 cls = type 292 elif isinstance( type, class_declaration.class_declaration_t ): 293 cls = type 294 else: 295 return 296 297 if not cls.name.startswith( self.name() + '<' ): 298 return 299 300 for ns in std_namespaces: 301 if type_traits.impl_details.is_defined_in_xxx( ns, cls ): 302 return cls
303
304 - def is_my_case( self, type ):
305 """checks, whether type is STD container or not""" 306 return bool( self.get_container_or_none( type ) )
307
308 - def class_declaration( self, type ):
309 """returns reference to the class declaration""" 310 cls = self.get_container_or_none( type ) 311 if not cls: 312 raise TypeError( 'Type "%s" is not instantiation of std::%s' % ( type.decl_string, self.name() ) ) 313 return cls
314
315 - def is_sequence( self, type ):
316 #raise exception if type is not container 317 unused = self.class_declaration( type ) 318 return self.key_type_index is None
319
320 - def is_mapping( self, type ):
321 return not self.is_sequence( type )
322
323 - def __find_xxx_type( self, type, xxx_index, xxx_typedef, cache_property_name ):
324 cls = self.class_declaration( type ) 325 result = getattr( cls.cache, cache_property_name ) 326 if not result: 327 if isinstance( cls, class_declaration.class_t ): 328 xxx_type = cls.typedef( xxx_typedef, recursive=False ).type 329 result = type_traits.remove_declarated( xxx_type ) 330 else: 331 xxx_type_str = templates.args( cls.name )[xxx_index] 332 result = type_traits.impl_details.find_value_type( cls.top_parent, xxx_type_str ) 333 if None is result: 334 raise RuntimeError( "Unable to find out %s '%s' key\\value type." 335 % ( self.name(), cls.decl_string ) ) 336 setattr( cls.cache, cache_property_name, result ) 337 return result
338
339 - def element_type( self, type ):
340 """returns reference to the class value\\mapped type declaration""" 341 return self.__find_xxx_type( type 342 , self.element_type_index 343 , self.element_type_typedef 344 , 'container_element_type')
345
346 - def key_type( self, type ):
347 """returns reference to the class key type declaration""" 348 if not self.is_mapping( type ): 349 raise TypeError( 'Type "%s" is not "mapping" container' % str( type ) ) 350 return self.__find_xxx_type( type 351 , self.key_type_index 352 , self.key_type_typedef 353 , 'container_key_type' )
354
355 - def remove_defaults( self, type_or_string ):
356 """remove template defaults from a template class instantiation 357 358 For example: 359 std::vector< int, std::allocator< int > > 360 will become 361 std::vector< int > 362 """ 363 name = type_or_string 364 if not isinstance( type_or_string, types.StringTypes ): 365 name = self.class_declaration( type_or_string ).name 366 if not self.remove_defaults_impl: 367 return name 368 no_defaults = self.remove_defaults_impl( name ) 369 if not no_defaults: 370 return name 371 else: 372 return no_defaults
373 374 create_traits = container_traits_impl_t 375 list_traits = create_traits( 'list' 376 , 0 377 , 'value_type' 378 , defaults_eraser.erase_allocator ) 379 380 deque_traits = create_traits( 'deque' 381 , 0 382 , 'value_type' 383 , defaults_eraser.erase_allocator ) 384 385 queue_traits = create_traits( 'queue' 386 , 0 387 , 'value_type' 388 , defaults_eraser.erase_container ) 389 390 priority_queue_traits = create_traits( 'priority_queue' 391 , 0 392 , 'value_type' 393 , defaults_eraser.erase_container_compare ) 394 395 vector_traits = create_traits( 'vector' 396 , 0 397 , 'value_type' 398 , defaults_eraser.erase_allocator ) 399 400 stack_traits = create_traits( 'stack' 401 , 0 402 , 'value_type' 403 , defaults_eraser.erase_container ) 404 405 map_traits = create_traits( 'map' 406 , 1 407 , 'mapped_type' 408 , defaults_eraser.erase_map_compare_allocator 409 , key_type_index=0 410 , key_type_typedef='key_type') 411 412 multimap_traits = create_traits( 'multimap' 413 , 1 414 , 'mapped_type' 415 , defaults_eraser.erase_map_compare_allocator 416 , key_type_index=0 417 , key_type_typedef='key_type') 418 419 420 hash_map_traits = create_traits( 'hash_map' 421 , 1 422 , 'mapped_type' 423 , defaults_eraser.erase_hashmap_compare_allocator 424 , key_type_index=0 425 , key_type_typedef='key_type') 426 427 428 hash_multimap_traits = create_traits( 'hash_multimap' 429 , 1 430 , 'mapped_type' 431 , defaults_eraser.erase_hashmap_compare_allocator 432 , key_type_index=0 433 , key_type_typedef='key_type') 434 435 set_traits = create_traits( 'set' 436 , 0 437 , 'value_type' 438 , defaults_eraser.erase_compare_allocator) 439 440 multiset_traits = create_traits( 'multiset' 441 , 0 442 , 'value_type' 443 , defaults_eraser.erase_compare_allocator ) 444 445 hash_set_traits = create_traits( 'hash_set' 446 , 0 447 , 'value_type' 448 , defaults_eraser.erase_hash_allocator ) 449 450 hash_multiset_traits = create_traits( 'hash_multiset' 451 , 0 452 , 'value_type' 453 , defaults_eraser.erase_hash_allocator ) 454 455 container_traits = ( 456 list_traits 457 , deque_traits 458 , queue_traits 459 , priority_queue_traits 460 , vector_traits 461 , stack_traits 462 , map_traits 463 , multimap_traits 464 , hash_map_traits 465 , hash_multimap_traits 466 , set_traits 467 , hash_set_traits 468 , multiset_traits 469 , hash_multiset_traits ) 470 """tuple of all STD container traits classes"""
471 472 -def find_container_traits( cls_or_string ):
473 if isinstance( cls_or_string, types.StringTypes ): 474 if not templates.is_instantiation( cls_or_string ): 475 return None 476 name = templates.name( cls_or_string ) 477 if name.startswith( 'std::' ): 478 name = name[ len( 'std::' ): ] 479 for cls_traits in container_traits: 480 if cls_traits.name() == name: 481 return cls_traits 482 else: 483 for cls_traits in container_traits: 484 if cls_traits.is_my_case( cls_or_string ): 485 return cls_traits
486