home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2012 January / maximum-cd-2012-01.iso / DiscContents / digsby_setup.exe / lib / peak / events / stm.pyo (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2011-10-05  |  14.3 KB  |  595 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.6)
  3.  
  4. import weakref
  5. import sys
  6. import heapq
  7. import UserList
  8. import UserDict
  9. from peak.util.extremes import Max
  10. from peak.util import decorators
  11.  
  12. try:
  13.     import threading
  14. except ImportError:
  15.     import dummy_threading as threading
  16.  
  17. __all__ = [
  18.     'STMHistory',
  19.     'AbstractSubject',
  20.     'Link',
  21.     'AbstractListener',
  22.     'Controller',
  23.     'CircularityError',
  24.     'LocalController']
  25.  
  26. class CircularityError(Exception):
  27.     pass
  28.  
  29.  
  30. class AbstractSubject(object):
  31.     __slots__ = ()
  32.     manager = None
  33.     layer = 0
  34.     
  35.     def __init__(self):
  36.         self.next_listener = None
  37.  
  38.     
  39.     def iter_listeners(self):
  40.         link = self.next_listener
  41.         while link is not None:
  42.             nxt = link.next_listener
  43.             ob = link()
  44.             if ob is not None:
  45.                 yield ob
  46.             
  47.             link = nxt
  48.  
  49.  
  50.  
  51. class AbstractListener(object):
  52.     __slots__ = ()
  53.     layer = 0
  54.     
  55.     def __init__(self):
  56.         self.next_subject = None
  57.  
  58.     
  59.     def iter_subjects(self):
  60.         link = self.next_subject
  61.         while link is not None:
  62.             nxt = link.next_subject
  63.             if link.subject is not None:
  64.                 yield link.subject
  65.             
  66.             link = nxt
  67.  
  68.     
  69.     def dirty(self):
  70.         return True
  71.  
  72.     
  73.     def run(self):
  74.         raise NotImplementedError
  75.  
  76.  
  77.  
  78. try:
  79.     
  80.     class Link(weakref.ref):
  81.         pass
  82.  
  83. except TypeError:
  84.     
  85.     class link_base(object):
  86.         __slots__ = 'weakref'
  87.         
  88.         def __new__(cls, ob, callback):
  89.             self = object.__new__(cls)
  90.             self.weakref = None((weakref.ref, ob), (lambda r: callback(self)))
  91.             return self
  92.  
  93.         
  94.         def __call__(self):
  95.             return self.weakref()
  96.  
  97.  
  98.  
  99. link_base = weakref.ref
  100.  
  101. try:
  102.     from threading import local
  103. except ImportError:
  104.     from _threading_local import local
  105.     threading.local = local
  106.  
  107.  
  108. try:
  109.     set
  110. except NameError:
  111.     from sets import Set as set
  112.  
  113.  
  114. class Link(link_base):
  115.     __slots__ = [
  116.         'subject',
  117.         'next_subject',
  118.         'prev_subject',
  119.         'next_listener',
  120.         'prev_listener']
  121.     
  122.     def __new__(cls, subject, listener):
  123.         self = link_base.__new__(Link, listener, _unlink_fn)
  124.         self.subject = self.prev_listener = subject
  125.         self.prev_subject = None
  126.         nxt = self.next_subject = listener.next_subject
  127.         if nxt is not None:
  128.             nxt.prev_subject = self
  129.         
  130.         nxt = self.next_listener = subject.next_listener
  131.         if nxt is not None:
  132.             nxt.prev_listener = self
  133.         
  134.         listener.next_subject = self
  135.         subject.next_listener = self
  136.         return self
  137.  
  138.     
  139.     def unlink(self):
  140.         nxt = self.next_listener
  141.         prev = self.prev_listener
  142.         if nxt is not None:
  143.             nxt.prev_listener = prev
  144.         
  145.         if prev is not None and prev.next_listener is self:
  146.             prev.next_listener = nxt
  147.         
  148.         prev = self.prev_subject
  149.         nxt = self.next_subject
  150.         if nxt is not None:
  151.             nxt.prev_subject = prev
  152.         
  153.         if prev is None:
  154.             prev = self()
  155.         
  156.         if prev is not None and prev.next_subject is self:
  157.             prev.next_subject = nxt
  158.         
  159.         self.subject = None
  160.         self.next_subject = None
  161.         self.prev_subject = None
  162.         self.next_listener = None
  163.         self.prev_listener = None
  164.  
  165.  
  166. _unlink_fn = Link.unlink
  167.  
  168. class STMHistory(object):
  169.     active = in_cleanup = undoing = False
  170.     
  171.     def __init__(self):
  172.         self.undo = []
  173.         self.at_commit = []
  174.         self.managers = { }
  175.  
  176.     
  177.     def atomically(self, func = (lambda : pass), *args, **kw):
  178.         if self.active:
  179.             return func(*args, **kw)
  180.         self.active = True
  181.         
  182.         try:
  183.             retval = func(*args, **kw)
  184.             self.cleanup()
  185.             return retval
  186.         except:
  187.             self.active
  188.             self.cleanup(*sys.exc_info())
  189.         finally:
  190.             self.active = False
  191.  
  192.  
  193.     
  194.     def manage(self, mgr):
  195.         if mgr not in self.managers:
  196.             mgr.__enter__()
  197.             self.managers[mgr] = len(self.managers)
  198.         
  199.  
  200.     
  201.     def on_undo(self, func, *args):
  202.         if not self.undoing:
  203.             self.undo.append((func, args))
  204.         
  205.  
  206.     
  207.     def savepoint(self):
  208.         return len(self.undo)
  209.  
  210.     
  211.     def cleanup(self, typ = None, val = None, tb = None):
  212.         self.in_cleanup = True
  213.         if typ is None:
  214.             
  215.             try:
  216.                 self.checkpoint()
  217.             (typ, val, tb) = sys.exc_info()
  218.  
  219.         
  220.         if typ is not None:
  221.             
  222.             try:
  223.                 self.rollback_to(0)
  224.             (typ, val, tb) = sys.exc_info()
  225.  
  226.         
  227.         managers = [ (posn, mgr) for mgr, posn in self.managers.items() ]
  228.         managers.sort()
  229.         self.managers.clear()
  230.         
  231.         try:
  232.             while managers:
  233.                 
  234.                 try:
  235.                     managers.pop()[1].__exit__(typ, val, tb)
  236.                 continue
  237.                 []
  238.                 (typ, val, tb) = sys.exc_info()
  239.                 continue
  240.  
  241.             if typ is not None:
  242.                 raise typ, val, tb
  243.             typ is not None
  244.         finally:
  245.             del self.at_commit[:]
  246.             del self.undo[:]
  247.             self.in_cleanup = False
  248.             typ = None
  249.             val = None
  250.             tb = None
  251.  
  252.  
  253.     
  254.     def change_attr(self, ob, attr, val):
  255.         self.on_undo(setattr, ob, attr, getattr(ob, attr))
  256.         setattr(ob, attr, val)
  257.  
  258.     
  259.     def rollback_to(self, sp = 0):
  260.         undo = self.undo
  261.         self.undoing = True
  262.         rb = self.rollback_to
  263.         
  264.         try:
  265.             while len(undo) > sp:
  266.                 (f, a) = undo.pop()
  267.                 if f == rb and a:
  268.                     sp = min(sp, a[0])
  269.                     continue
  270.                 f(*a)
  271.         finally:
  272.             self.undoing = False
  273.  
  274.  
  275.     
  276.     def on_commit(self, func, *args):
  277.         s = slice(len(self.at_commit), None)
  278.         self.undo.append((self.at_commit.__delitem__, (s,)))
  279.         self.at_commit.append((func, args))
  280.  
  281.     
  282.     def checkpoint(self):
  283.         for f, a in self.at_commit:
  284.             f(*a)
  285.         
  286.         del self.at_commit[:]
  287.  
  288.  
  289.  
  290. class Controller(STMHistory):
  291.     current_listener = None
  292.     destinations = None
  293.     routes = None
  294.     newcells = None
  295.     readonly = False
  296.     
  297.     def __init__(self):
  298.         super(Controller, self).__init__()
  299.         self.reads = { }
  300.         self.writes = { }
  301.         self.has_run = { }
  302.         self.layers = []
  303.         self.queues = { }
  304.         self.to_retry = { }
  305.  
  306.     
  307.     def checkpoint(self):
  308.         self.has_run.clear()
  309.         return super(Controller, self).checkpoint()
  310.  
  311.     
  312.     def _retry(self):
  313.         
  314.         try:
  315.             self.destinations = set(self.to_retry)
  316.             self.routes = { }
  317.             []([]([ self.has_run[r] for r in self.to_retry ]))
  318.             for item in self.to_retry:
  319.                 if item in self.routes:
  320.                     path = check_circularity(item, self.routes)
  321.                     if path:
  322.                         raise CircularityError(self.routes, path)
  323.                     path
  324.                     continue
  325.                 min
  326.         finally:
  327.             self.to_retry.clear()
  328.             self.destinations = None
  329.             self.routes = None
  330.  
  331.  
  332.     
  333.     def __getattr__(self, name):
  334.         if name == 'pulse':
  335.             Value = Value
  336.             import peak.events.trellis
  337.             self.pulse = Value(0)
  338.             return self.pulse
  339.         raise AttributeError(name)
  340.  
  341.     
  342.     def _unrun(self, listener, notified):
  343.         destinations = self.destinations
  344.         if destinations is not None:
  345.             via = destinations.intersection(notified)
  346.             if via:
  347.                 self.routes[listener] = via
  348.                 destinations.add(listener)
  349.             
  350.         
  351.  
  352.     
  353.     def run_rule(self, listener, initialized = True):
  354.         if listener.layer is Max and not (self.readonly):
  355.             return self.with_readonly(self.run_rule, listener, initialized)
  356.         old = self.current_listener
  357.         self.current_listener = listener
  358.         
  359.         try:
  360.             if old is not None:
  361.                 old_reads = self.reads
  362.                 self.reads = { }
  363.                 
  364.                 try:
  365.                     listener.run()
  366.                     self._process_reads(listener)
  367.                 finally:
  368.                     self.reads = old_reads
  369.  
  370.             elif initialized:
  371.                 self.has_run[listener] = self.savepoint()
  372.                 self.on_undo(self.has_run.pop, listener, None)
  373.             
  374.             
  375.             try:
  376.                 listener.run()
  377.                 self._process_writes(listener)
  378.                 self._process_reads(listener)
  379.             except:
  380.                 self.reads.clear()
  381.                 self.writes.clear()
  382.                 raise 
  383.  
  384.         finally:
  385.             self.current_listener = old
  386.  
  387.  
  388.     
  389.     def _process_writes(self, listener):
  390.         notified = { }
  391.         writes = self.writes
  392.         layer = listener.layer
  393.         while writes:
  394.             (subject, writer) = writes.popitem()
  395.             for dependent in subject.iter_listeners():
  396.                 if dependent is not listener:
  397.                     if dependent.dirty():
  398.                         self.schedule(dependent, layer)
  399.                         notified[dependent] = 1
  400.                     
  401.                 dependent.dirty()
  402.             
  403.         if notified:
  404.             self.on_undo(self._unrun, listener, notified)
  405.         
  406.  
  407.     
  408.     def _process_reads(self, listener):
  409.         subjects = self.reads
  410.         link = listener.next_subject
  411.         while link is not None:
  412.             nxt = link.next_subject
  413.             if link.subject in subjects:
  414.                 del subjects[link.subject]
  415.             else:
  416.                 self.undo.append((Link, (link.subject, listener)))
  417.                 link.unlink()
  418.             link = nxt
  419.         while subjects:
  420.             link = Link(subjects.popitem()[0], listener)
  421.             self.undo.append((link.unlink, ()))
  422.  
  423.     
  424.     def schedule(self, listener, source_layer = None):
  425.         new = old = listener.layer
  426.         get = self.queues.get
  427.         if source_layer is not None and source_layer >= listener.layer:
  428.             new = source_layer + 1
  429.         
  430.         if listener in self.has_run:
  431.             self.to_retry[listener] = 1
  432.         
  433.         q = get(old)
  434.         if q and listener in q:
  435.             if new is not old:
  436.                 self.cancel(listener)
  437.             
  438.         elif self.active and not (self.undoing):
  439.             self.on_undo(self.cancel, listener)
  440.         
  441.         if new is not old:
  442.             listener.layer = new
  443.             q = get(new)
  444.         
  445.         if q is None:
  446.             q = self.queues[new] = {
  447.                 listener: 1 }
  448.             heapq.heappush(self.layers, new)
  449.         else:
  450.             q[listener] = 1
  451.  
  452.     
  453.     def cancel(self, listener):
  454.         q = self.queues.get(listener.layer)
  455.         if q and listener in q:
  456.             del q[listener]
  457.             if not q:
  458.                 del self.queues[listener.layer]
  459.                 self.layers.remove(listener.layer)
  460.                 self.layers.sort()
  461.             
  462.         
  463.  
  464.     
  465.     def atomically(self, func = (lambda : pass), *args, **kw):
  466.         if self.active:
  467.             return func(*args, **kw)
  468.         return super(Controller, self).atomically(self._process, func, args, kw)
  469.  
  470.     
  471.     def _process(self, func, args, kw):
  472.         
  473.         try:
  474.             retval = func(*args, **kw)
  475.             layers = self.layers
  476.             queues = self.queues
  477.             while layers or self.at_commit:
  478.                 self.pulse.value += 1
  479.                 while layers:
  480.                     if self.to_retry:
  481.                         self._retry()
  482.                     
  483.                     q = queues[layers[0]]
  484.                     if q:
  485.                         listener = q.popitem()[0]
  486.                         self.on_undo(self.schedule, listener)
  487.                         self.run_rule(listener)
  488.                         continue
  489.                     del queues[layers[0]]
  490.                     heapq.heappop(layers)
  491.                 self.checkpoint()
  492.             return retval
  493.         except:
  494.             del self.layers[:]
  495.             self.queues.clear()
  496.             raise 
  497.  
  498.  
  499.     
  500.     def lock(self, subject):
  501.         manager = subject.manager
  502.         if manager is not None and manager not in self.managers:
  503.             self.manage(manager)
  504.         
  505.  
  506.     
  507.     def used(self, subject):
  508.         self.lock(subject)
  509.         cl = self.current_listener
  510.         if cl is not None and subject not in self.reads:
  511.             self.reads[subject] = 1
  512.             if cl is not subject and subject.layer >= cl.layer:
  513.                 cl.layer = subject.layer + 1
  514.             
  515.         
  516.  
  517.     
  518.     def changed(self, subject):
  519.         self.lock(subject)
  520.         cl = self.current_listener
  521.         if self.readonly and subject is not cl:
  522.             if self.newcells is None or subject not in self.newcells:
  523.                 raise RuntimeError("Can't change objects during @perform or @compute")
  524.         subject not in self.newcells
  525.         if cl is not None:
  526.             self.writes[subject] = cl
  527.         else:
  528.             for listener in subject.iter_listeners():
  529.                 if listener.dirty():
  530.                     self.schedule(listener)
  531.                     continue
  532.             
  533.  
  534.     
  535.     def initialize(self, listener):
  536.         self.run_rule(listener, False)
  537.  
  538.     
  539.     def with_readonly(self, func, *args):
  540.         if self.readonly:
  541.             return func(*args)
  542.         self.readonly = True
  543.         
  544.         try:
  545.             return func(*args)
  546.         finally:
  547.             self.readonly = False
  548.  
  549.  
  550.     
  551.     def new_cell(self, cell):
  552.         if self.newcells is not None:
  553.             self.newcells[cell] = 1
  554.         
  555.  
  556.     
  557.     def with_new(self, func, *args, **kw):
  558.         old = self.newcells
  559.         if old is None:
  560.             self.newcells = { }
  561.         
  562.         
  563.         try:
  564.             return func(*args, **kw)
  565.         finally:
  566.             self.newcells = old
  567.  
  568.  
  569.  
  570.  
  571. def check_circularity(item, routes, start = None, seen = None):
  572.     if seen is None:
  573.         seen = { }
  574.     
  575.     if start is None:
  576.         start = item
  577.     
  578.     for via in routes.get(item, ()):
  579.         if via is start:
  580.             return (via,)
  581.         if via not in seen:
  582.             seen[via] = 1
  583.             path = check_circularity(via, routes, start, seen)
  584.             if path:
  585.                 return (via,) + path
  586.             continue
  587.         path
  588.     
  589.     return ()
  590.  
  591.  
  592. class LocalController(Controller, threading.local):
  593.     pass
  594.  
  595.