瀏覽代碼

enforcing no subclassing of ResourceCounter's subclasses

Josh Wilson 18 年之前
父節點
當前提交
b2422726c5
共有 1 個文件被更改,包括 61 次插入28 次删除
  1. 61 28
      direct/src/showbase/ResourceCounter.py

+ 61 - 28
direct/src/showbase/ResourceCounter.py

@@ -17,22 +17,24 @@ class ResourceCounter(object):
 
 
     Usage:
     Usage:
         Define a subclass of ResourceCounter that defines the
         Define a subclass of ResourceCounter that defines the
-        classmethods acquire() and release().  In these two
+        @classmethods acquire() and release().  In these two
         functions, define your resource allocation and cleanup code.
         functions, define your resource allocation and cleanup code.
 
 
     IMPORTANT:
     IMPORTANT:
         If you define your own __init__ and __del__ methods, you
         If you define your own __init__ and __del__ methods, you
-        MUST be sure to call down to the ones defined in ResourceCounter.
+        MUST be sure to call down to the ones defined in
+        ResourceCounter.
     
     
     Notes:
     Notes:
-        Until we figure out a way to wrangle a bit more functionality out
-        of Python, you MUST NOT define acquire() and release() again in
-        any subclasses of your ResourceCounter subclass in an attempt
-        to manage another resource.  In debug mode, this will raise a
-        runtime assertion. If you have more than one resource, you should
-        subclass ResourceCounter again.  See the example code at the
-        bottom of this file to see how to manage more than one resource
-        with a single instance of an object (Useful for dependent resources).
+        Until we figure out a way to wrangle a bit more functionality
+        out of Python, you MUST NOT inherit from any class that has
+        ResourceCounter as its base class. In debug mode, this will
+        raise a runtime assertion during the invalid class's call to
+        __init__(). If you have more than one resource that you want to
+        manage/access with a single object, you should subclass
+        ResourceCounter again. See the example code at the bottom of
+        this file to see how to accomplish this (This is useful for
+        dependent resources).
     """
     """
     
     
     @classmethod
     @classmethod
@@ -47,25 +49,30 @@ class ResourceCounter(object):
 
 
     @classmethod
     @classmethod
     def decrementCounter(cls):
     def decrementCounter(cls):
-        cls.RESOURCE_COUNTER -= 1
-        if cls.RESOURCE_COUNTER < 1:
-            cls.release()
-
+        try:
+            cls.RESOURCE_COUNTER_INIT
+            del cls.RESOURCE_COUNTER_INIT
+        except AttributeError:
+            cls.RESOURCE_COUNTER -= 1
+            if cls.RESOURCE_COUNTER < 1:
+                cls.release()
+        
     @classmethod
     @classmethod
     def acquire(cls):
     def acquire(cls):
-        cls.RESOURCE_COUNTER -= 1
-        assert cls.__mro__[1] == ResourceCounter, \
-               (lambda: \
-                'acquire() should only be defined in ResourceCounter\'s immediate subclass: %s' \
-                 % cls.__mro__[list(cls.__mro__).index(ResourceCounter) - 1].__name__)()
-
-        cls.RESOURCE_COUNTER += 1
-
+        pass
+    
     @classmethod
     @classmethod
-    def release(cls, *args, **kwargs):
+    def release(cls):
         pass
         pass
     
     
     def __init__(self):
     def __init__(self):
+        cls = type(self)
+        cls.RESOURCE_COUNTER_INIT = True
+        assert cls.__mro__[1] == ResourceCounter, \
+               (lambda: \
+                '%s cannot be subclassed.' \
+                 % cls.__mro__[list(cls.__mro__).index(ResourceCounter) - 1].__name__)()
+        del cls.RESOURCE_COUNTER_INIT
         self.incrementCounter()
         self.incrementCounter()
 
 
     def __del__(self):
     def __del__(self):
@@ -79,17 +86,29 @@ if __debug__ and __name__ == '__main__':
         """
         """
         @classmethod
         @classmethod
         def acquire(cls):
         def acquire(cls):
+            # The call to the super-class's acquire() is
+            # not necessary at the moment, but may be in
+            # the future, so do it now for good measure.
             super(MouseResource, cls).acquire()
             super(MouseResource, cls).acquire()
+
+            # Now acquire the resource this class is
+            # managing.
             print '-- Acquire Mouse'
             print '-- Acquire Mouse'
         
         
         @classmethod
         @classmethod
         def release(cls):
         def release(cls):
+            # First, release the resource this class is
+            # managing.
             print '-- Release Mouse'
             print '-- Release Mouse'
+
+            # The call to the super-class's release() is
+            # not necessary at the moment, but may be in
+            # the future, so do it now for good measure.
             super(MouseResource, cls).release()
             super(MouseResource, cls).release()
 
 
     
     
         def __init__(self):
         def __init__(self):
-            super(MouseResource, self).__init__()            
+            super(MouseResource, self).__init__()
 
 
         def __del__(self):
         def __del__(self):
             super(MouseResource, self).__del__()
             super(MouseResource, self).__del__()
@@ -110,14 +129,26 @@ if __debug__ and __name__ == '__main__':
         @classmethod
         @classmethod
         def release(cls):
         def release(cls):
             print '-- Release Cursor'
             print '-- Release Cursor'
+
             super(CursorResource, cls).release()
             super(CursorResource, cls).release()
 
 
         def __init__(self):
         def __init__(self):
+            # The required resource references should
+            # be stored on 'self' since we want to
+            # release it when the object is deleted.
             self.__mouseResource = MouseResource()
             self.__mouseResource = MouseResource()
+
+            # Call the super-classes __init__()
+            # after all required resources are
+            # referenced.
             super(CursorResource, self).__init__()            
             super(CursorResource, self).__init__()            
         
         
         def __del__(self):
         def __del__(self):
+            # Free up the most dependent resource
+            # first, the one this class is managing.
             super(CursorResource, self).__del__()
             super(CursorResource, self).__del__()
+            
+            # Now unlink any required resources.
             del self.__mouseResource
             del self.__mouseResource
 
 
     class InvalidResource(MouseResource):
     class InvalidResource(MouseResource):
@@ -131,7 +162,6 @@ if __debug__ and __name__ == '__main__':
             print '-- Release Invalid'
             print '-- Release Invalid'
             super(InvalidResource, cls).release()
             super(InvalidResource, cls).release()
             
             
-            
     print '\nAllocate Mouse'
     print '\nAllocate Mouse'
     m = MouseResource()
     m = MouseResource()
     print 'Free up Mouse'
     print 'Free up Mouse'
@@ -169,11 +199,9 @@ if __debug__ and __name__ == '__main__':
     print '\nAllocate Cursor then Mouse'
     print '\nAllocate Cursor then Mouse'
     c = CursorResource()
     c = CursorResource()
     m = MouseResource()
     m = MouseResource()
-    print 'Free up Mouse'
-    del m
     print 'Free up Cursor'
     print 'Free up Cursor'
     del c
     del c
-
+    
     # example of an invalid subclass
     # example of an invalid subclass
     try:
     try:
         print '\nAllocate Invalid'
         print '\nAllocate Invalid'
@@ -181,6 +209,10 @@ if __debug__ and __name__ == '__main__':
         print 'Free up Invalid'
         print 'Free up Invalid'
     except AssertionError,e:
     except AssertionError,e:
         print e
         print e
+    print
+
+    print 'Free up Mouse'
+    del m
 
 
     def demoFunc():
     def demoFunc():
         print '\nAllocate Cursor within function'
         print '\nAllocate Cursor within function'
@@ -191,3 +223,4 @@ if __debug__ and __name__ == '__main__':
     demoFunc()
     demoFunc()
 
 
 
 
+