1def str_as_atr(s): 2 if s == '_': 3 return [] 4 atr = [] 5 i = 0 6 while i < len(s): 7 v = s[i] 8 if i + 1 < len(s) and s[i+1].isdigit(): 9 n = 0 10 i = i + 1 11 while i < len(s) and s[i].isdigit(): 12 n = n * 10 + int(s[i]) 13 i += 1 14 else: 15 i += 1 16 n = 1 17 for j in range(n): 18 atr.append(v) 19 return atr 20 21 22def atr_as_str(atr): 23 if not atr: 24 return '_' 25 prefl = [] 26 prestr = ''.join([str(x) for x in atr]) 27 i = 0 28 while i < len(prestr): 29 c = prestr[i] 30 j = i+1 31 while j < len(prestr) and prestr[j] == c: 32 j += 1 33 if j - i > 2: 34 prefl.append(c) 35 prefl.append(str(j-i)) 36 else: 37 while i < j: 38 prefl.append(c) 39 i += 1 40 i = j 41 return ''.join(prefl) 42 43 44def str_as_ixl(s): 45 return [ord(ch)-ord('a') for ch in str_as_atr(s)] 46 47 48def ixl_as_str(ixl): 49 return atr_as_str([chr(ix + ord('a')) for ix in ixl]) 50 51 52class Paths: 53 def __init__(self, mod, rp, key, extended=True, andsets=(), variant=2): 54 self.mod = mod 55 self._hiding_tag_ = mod._hiding_tag_ 56 self.key = key 57 self.rp = rp 58 self.extended = extended 59 self.srcrow = rp.get_row(self.key) 60 self.variant = variant 61 self.andsetbyname = {} 62 row = self.srcrow 63 while row is not None: 64 self.andsetbyname[row.ixlstr] = mod.Use.Anything 65 row = row.parent 66 67 if isinstance(andsets, dict): 68 self.andsetbyname.update(andsets) 69 elif isinstance(andsets, (tuple, list)): 70 row = self.srcrow 71 for i, s in enumerate(andsets): 72 if row is None: 73 raise ValueError('andsets argument is too long') 74 if s is not None: 75 self.andsetbyname[row.ixlstr] = s 76 row = row.parent 77 else: 78 raise TypeError('andsets argument must be dict, tuple, or list') 79 80 mod.OutputHandling.setup_printing( 81 self, 82 stop_only_when_told=variant >= 2) 83 84 def get_str_of_path_component_singleton(self, set): 85 return set.brief.lstrip('<1 ').rstrip('>') 86 87 def source_to_target_info(self): 88 src = 'Source' 89 tgt = 'Target' 90 via = 'Via' 91 92 row = self.srcrow 93 indent = 0 94 while row is not None: 95 if row.parent is None: 96 a = tgt 97 elif row is srcrow: 98 a = src 99 else: 100 a = via 101 a = ' '*indent + a 102 name = row.ixlstr 103 a = a + ' ' + ' '*(8+srcrow.depth*indinc - 104 len(name)-len(a)) + name + ': ' 105 yield a+row.getsummary(mod.line_length-len(a)) 106 row = row.parent 107 indent += indinc 108 109 def _oh_get_label(self): 110 return 'Paths from source %r to target %r.' % (self.srcrow.ixlstr, '_') 111 112 def _oh_get_line_iter(self): 113 return getattr(self, 'get_line_iter_%s' % (self.variant,))() 114 115 def _oh_get_more_state_msg(self, startindex, lastindex): 116 return '' 117 118 def get_line_iter_1(self): 119 # Original variant indenting from left to right 120 121 mod = self.mod 122 123 srcrow = self.srcrow 124 srcset = srcrow.set 125 126 indinc = 2 127 if srcrow.depth >= 10: 128 indinc = 1 129 130 def genlines(row, ks, indent=0): 131 par = row.parent 132 for key, i, set in ks: 133 sidx = '%s[%d]' % (row.ixlstr, i) 134 135 if self.extended: 136 strsing = self.get_str_of_path_component_singleton(set) 137 else: 138 strsing = '' 139 vline = '%s %s %s %s' % ( 140 key, 141 ' '*(40-len(key) - len(sidx)), 142 sidx, 143 strsing 144 ) 145 146 yield vline 147 148 if par is None: 149 continue 150 151 def get_nks(key, set): 152 parset = set.referents & par.set 153 for i, p in enumerate(parset.byid.parts): 154 rels = mod.Path.relations(set.theone, p.theone) 155 for rel in rels: 156 if rel is mod.Path.identity: 157 continue 158 if rel is mod.Path.norelation: 159 k = '??' 160 else: 161 k = str(rel) % '' 162 k = ' '*(indent+indinc)+k 163 yield k, i, p 164 165 for line in genlines(par, get_nks(key, set), indent+indinc): 166 yield line 167 168 def get_ks(): 169 for i, s in enumerate(srcset.byid.parts): 170 k = '[%d] ' % i 171 k = k + (' -'*20)[:36-len(k)-srcrow.depth] 172 yield k, i, s 173 174 for line in genlines(srcrow, get_ks()): 175 yield line 176 return 177 178 def get_line_iter_2(self): 179 # Newer variant 180 181 mod = self.mod 182 183 srcrow = self.srcrow 184 185 indinc = 1 186 if srcrow.depth >= 10: 187 indinc = 1 188 189 lno = [0] 190 191 seen = {} 192 193 indir = 1 194 195 if indir == 1: 196 max_ixlstr_len = 0 197 max_str_len_set = 0 198 row = srcrow 199 while row: 200 if len(row.ixlstr) > max_ixlstr_len: 201 max_ixlstr_len = len(row.ixlstr) 202 if len(str(len(row.set.nodes))) > max_str_len_set: 203 max_str_len_set = len(str(len(row.set.nodes))) 204 row = row.parent 205 206 def genlines(row, part, idx): 207 208 seen[part.nodes, row.depth] = lno[0] 209 sidx = row.ixlstr 210 idxs = '[%d]' % idx 211 if indir < 0: 212 indent = (row.depth)*indinc 213 sidx = '%s%s%s' % ( 214 sidx, ' '*(6+indent-len(sidx)-len(idxs)), idxs) 215 if row.parent is None: 216 sidx += ' == %s' % part.brief 217 218 else: 219 #idxs = ('[%.'+str(max_str_len_set)+'d]')%idx 220 sidx = '%s%s%s' % (sidx, 221 ' '*(3+max_str_len_set + 222 max_ixlstr_len-len(sidx)-len(idxs)), 223 idxs) 224 sidx += ' ' * (srcrow.depth + 1 - row.depth) 225 if row.parent is not None: 226 sidx += '@' 227 else: 228 sidx += '= %s' % part.brief 229 230 if row.parent is None: 231 #vline += ' == %s'%self.get_str_of_path_component_singleton(part) 232 vline = '%2s: %s' % (lno[0], sidx) 233 lno[0] += 1 234 yield ('STOP_AFTER', vline) 235 return 236 237 referents = part.referents & row.parent.set & self.andsetbyname[row.parent.ixlstr] 238 relations = mod.Path.relations 239 iso = mod.Use.iso 240 s = part.theone 241 t = [(relations(s, p.theone), p.by(referents.er), i) 242 for (i, p) in enumerate(referents.byid.parts)] 243 for (rels, p, i) in t: 244 relstrings = [] 245 for rel in rels: 246 if rel is mod.Path.identity: 247 continue 248 if rel is mod.Path.norelation: 249 k = '??' 250 else: 251 k = str(rel) % '' 252 relstrings.append(k) 253 254 relsstr = ' / '.join(relstrings) 255 seenlno = seen.get((p.nodes, row.parent.depth)) 256 vline = '%2s: %s' % (lno[0], sidx) 257 lno[0] += 1 258 if seenlno is not None: 259 relsstr += ' -> #%d' % seenlno 260 yield ('STOP_AFTER', vline + ' ' + relsstr) 261 else: 262 yield vline + ' ' + relsstr 263 for line in genlines(row.parent, p, i): 264 yield line 265 266 for i, p in enumerate((srcrow.set & self.andsetbyname[srcrow.ixlstr]).byid.parts): 267 for line in genlines(srcrow, p, i): 268 yield line 269 270 271class RefPatIter: 272 def __init__(self, rp, start=0): 273 self.rp = rp 274 self._hiding_tag_ = rp._hiding_tag_ 275 self.ix = start 276 277 def __iter__(self): 278 return self 279 280 def __next__(self): 281 try: 282 x = self.rp[self.ix] 283 except IndexError: 284 raise StopIteration 285 self.ix += 1 286 return x 287 288 289class RefPatRow: 290 def __init__(self, rp, kindset, seenline, ixl, parent): 291 self.rp = rp 292 self._hiding_tag_ = rp._hiding_tag_ 293 self.kindset = kindset 294 self.kind, self.set = kindset 295 assert self.set <= self.kind 296 self.seenline = seenline 297 self.ixl = ixl[:] 298 self.parent = parent 299 if parent is not None: 300 self.depth = parent.depth + 1 301 else: 302 self.depth = 0 303 304 self.index = 0 305 self.maxdepth = rp.depth 306 self.max_str_len = rp.mod.line_length 307 self.ixlstr = ixl_as_str(ixl) 308 self.isready = 0 309 self.children = [] 310 311 def __str__(self): 312 prestr = '%2d: %s ' % (self.index, self.ixlstr) 313 314 if self.index & 1: 315 fillpat = ' ' * 100 316 else: 317 fillpat = '-'*100 318 319 lps = len(prestr) 320 fill = fillpat[lps:9+self.depth] 321 322 if self.seenline: 323 ref = '[^ %s]' % self.seenline.index 324 elif self.isroot: 325 ref = '[R]' 326 elif self.depth > 0 and self.set <= self.rp.stopkind: 327 ref = '[S]' 328 elif self.depth < self.maxdepth: 329 ref = '[-]' 330 else: 331 ref = '[+]' 332 333 prefix = '%s%s %s ' % (prestr, fill, ref) 334 return '%s%s' % (prefix, self.getsummary(self.max_str_len-len(prefix))) 335 336 def getchild(self, ix): 337 while ix >= len(self.children) and not self.isready: 338 self.rp.generate(len(self.rp.lines)) 339 return self.children[ix] 340 341 def getsummary(self, max_len): 342 kind, set = self.kind, self.set 343 summary = set.fam.get_str_refpat(set, kind, max_len) 344 return summary 345 346 347class ReferencePattern: 348 __doc__ = '<Help Text' 349 help = """\ 350Methods 351 352 353 354 355""" 356 357 def __init__(self, mod, set, depth, er, relimg, bf, stopkind, nocyc): 358 self.mod = mod 359 self._hiding_tag_ = mod._hiding_tag_ 360 self.View = mod.View 361 self.set = set 362 self.depth = depth 363 self.er = er 364 self.bf = bf 365 self.stopkind = stopkind 366 self.nocyc = nocyc 367 self.is_initialized = 0 368 369 self.totcount = set.count 370 self.totsize = set.indisize 371 self.kind = set.kind 372 self.kindset = (self.kind, self.set) 373 self.relimg = relimg 374 self.top = self 375 376 mod.OutputHandling.setup_printing(self) 377 self.View.referrers_add_target(self) 378 self.reset_nogc() 379 self.is_initialized = 1 380 381 def __getattr__(self, s): 382 if not self.is_initialized: 383 raise AttributeError(s) 384 385 try: 386 return getattr(self.__class__, s) 387 except AttributeError: 388 pass 389 try: 390 row = self.get_row_named(s) 391 except ValueError: 392 raise AttributeError(s) 393 return row.set 394 395 def __getitem__(self, ix): 396 return self.get_row_indexed(ix).set 397 398 def __iter__(self, start=0): 399 return RefPatIter(self, start) 400 401 def __len__(self): 402 self.generate() 403 return len(self.lines) 404 405 def _oh_get_label(self): 406 return 'Reference Pattern by <' + self.er.classifier.get_byname() + '>.' 407 408 def _oh_get_more_state_msg(self, startindex, lastindex): 409 if self.isfullygenerated: 410 msg = '%d more lines. ' % (len(self.lines) - 1-lastindex,) 411 else: 412 msg = '' 413 return msg 414 415 def _oh_get_line_iter(self): 416 it = self.iterlines(0) 417 for el in it: 418 yield str(el) 419 420 def generate(self, ix=None): 421 while ix is None or ix < 0 or ix >= len(self.lines): 422 try: 423 self.lines.append(next(self.lg)) 424 except StopIteration: 425 self.isfullygenerated = 1 426 return 427 self.lines[-1].index = len(self.lines) - 1 428 429 def get_row(self, key): 430 try: 431 [][key] 432 except TypeError: 433 return self.get_row_named(key) 434 except IndexError: 435 return self.get_row_indexed(key) 436 437 def get_row_indexed(self, ix): 438 self.generate(ix) 439 return self.lines[ix] 440 441 def get_row_named(self, name): 442 row = self.get_row_indexed(0) 443 for ix in str_as_ixl(name): 444 try: 445 row = row.getchild(ix) 446 except IndexError: 447 raise ValueError( 448 'Reference pattern has no row named %r' % name) 449 return row 450 451 def iterlines(self, start=None): 452 if start is None: 453 start = 0 454 while 1: 455 try: 456 yield self.get_row_indexed(start) 457 except IndexError: 458 return 459 start += 1 460 461 def linegenerator(self, xxx_todo_changeme, ixl, parent=None): 462 (kind, set) = xxx_todo_changeme 463 seenline = self.seensets.get(set.nodes) 464 ixl = list(ixl) 465 line = RefPatRow(self, (kind, set), seenline=seenline, 466 ixl=ixl, parent=parent) 467 children = self.get_children(line) 468 line.isroot = not children 469 if seenline is None: 470 self.seensets[set.nodes] = line 471 if parent is not None: 472 parent.children.append(line) 473 yield line 474 475 depth = line.depth 476 if (not seenline and depth < self.depth and 477 (depth == 0 or not (set <= self.stopkind))): 478 for i, cs in enumerate(children): 479 ixl.append(i) 480 for rl in self.linegenerator(cs, ixl, line): 481 yield rl 482 ixl.pop() 483 line.isready = 1 484 485 def get_children(self, line): 486 (kind, set) = line.kindset 487 chset = self.relimg(set) 488 if self.nocyc: 489 while line is not None: 490 chset -= line.set 491 line = line.parent 492 return [(row.kind, row.set) 493 for row in self.get_partition(chset, self.er).get_rows()] 494 495 def get_partition(self, set, er): 496 p = self.mod.Part.partition(set, er) 497 return p 498 499 def paths(self, key, **kwds): 500 return Paths(self.mod, self, key, **kwds) 501 502 def reset(self): 503 self.reset_nogc() 504 self.printer.reset() 505 self.mod._root.gc.collect() 506 507 def reset_nogc(self): 508 self.isfullygenerated = 0 509 self.seensets = {} 510 self.lines = [] 511 self.lg = self.linegenerator(self.kindset, []) 512 self.lastindex = None 513 514 515class _GLUECLAMP_: 516 _preload_ = ('_hiding_tag_',) 517 518 depth = 7 519 line_length = 80 520 521 _uniset_exports = ('rp',) 522 _chgable_ = ('er', 523 'depth', 524 'line_length', 525 ) 526 527 # 'module imports' 528 529 _imports_ = ( 530 '_parent:OutputHandling', 531 '_parent:Part', 532 '_parent:Path', 533 '_parent:UniSet', 534 '_parent:Use', 535 '_parent:View', 536 '_parent.View:_hiding_tag_', 537 ) 538 539 # 540 541 def _get_er(self): return self.Use.Clodo 542 543 def _get_stopkind(self): 544 hp = self.Use 545 return ( 546 hp.Type.Module | 547 hp.Type.Type | 548 hp.Type.Module.dictof | 549 hp.Type.Type.dictof | 550 hp.Type.Code | 551 hp.Type.Frame 552 ) 553 554 def rp(self, X, depth=None, er=None, imdom=0, bf=0, src=None, stopkind=None, 555 nocyc=False, ref=None): 556 """rp(X, depth=None, er=None, imdom=0, bf=0, src=None, stopkind=None, nocyc=False, ref=None) 557Reference pattern forming. 558Arguments 559 X Set of objects for which a reference pattern is sought. 560 depth The depth to which the pattern will be generated. The 561 default is taken from depth of this module. 562 er The equivalence relation to partition the referrers. The default 563 is Clodo. 564 imdom If true, the immediate dominators will be used instead 565 of the referrers. This will take longer time to calculate, 566 but may be useful to reduce the complexity of the reference 567 pattern. 568 bf If true, the pattern will be printed in breadth-first 569 order instead of depth-first. (Experimental.) 570 src If specified, an alternative reference source instead 571 of the default root. 572 stopkind 573 nocyc 574 ref 575 576Description 577 Return a reference pattern object based on the objects in the set X. 578 The reference pattern object is of class ReferencePattern. It is 579 described in XXX. 580""" 581 if depth is None: 582 depth = self.depth 583 X = self.UniSet.idset_adapt(X) 584 if src is not None: 585 # Creates an entire new guppy tree 586 # Mostly for testing purposes - 587 # can likely cause type problems generally 588 src = self.UniSet.idset_adapt(src) 589 self = self._root.guppy.Root().guppy.heapy.RefPat 590 self.View.root = tuple(src.nodes) 591 X = self.Use.idset(X.nodes) 592 593 if er is None: 594 er = self.er # NEEDS to be loaded after new Classifier created 595 if imdom: 596 def relimg(X): return X.imdom 597 elif ref is not None: 598 if ref == 'gc': 599 def relimg(X): return X.referrers_gc 600 elif ref == 'gcx': 601 relimg = (lambda x: x.referrers_gc 602 - self._root.guppy.sets.ImmNodeSet 603 - self._parent.heapyc.NodeGraph 604 - self.View.ObservationList) 605 elif ref == 'imdom': 606 def relimg(X): return X.imdom 607 elif callable(ref): 608 relimg = ref 609 else: 610 raise ValueError( 611 "ref should be 'gc', 'gcx', 'imdom', or a callable") 612 else: 613 def relimg(X): return X.referrers 614 if stopkind is None: 615 stopkind = self.stopkind 616 rp = ReferencePattern(self, X, depth, er, relimg, bf, stopkind, nocyc) 617 return rp 618