瀏覽代碼

assert when subclassing rules are not followed

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

+ 54 - 27
direct/src/showbase/ResourceCounter.py

@@ -3,13 +3,14 @@ class ResourceCounter(object):
     """
     This class is an attempt to combine the RAIA idiom with reference
     counting semantics in order to model shared resources. RAIA stands
-    for "Resource Allocation Is Acquisiton" (see 'Effective C++' for a
-    more detailed explanation)
+    for "Resource Allocation Is Acquisition" (see 'Effective C++' for a
+    more in-depth explanation)
     
     When a resource is needed, create an appropriate ResourceCounter
     object.  If the resource is already available (meaning another
     ResourceCounter object of the same type already exists), no action
-    is taken.  The resource will remain valid until all matching
+    is taken.  Otherwise, acquire() is invoked, and the resource is
+    allocated. The resource will remain valid until all matching
     ResourceCounter objects have been deleted.  When no objects of
     a particular ResourceCounter type exist, the release() function for
     that type is invoked and the managed resource is cleaned up.
@@ -27,10 +28,11 @@ class ResourceCounter(object):
         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.  If you have more than one resource,
+        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).
+        bottom of this file to see how to manage more than one resource
+        with a single instance of an object (Useful for dependent resources).
     """
     
     @classmethod
@@ -46,18 +48,22 @@ class ResourceCounter(object):
     @classmethod
     def decrementCounter(cls):
         cls.RESOURCE_COUNTER -= 1
-
-        if cls.RESOURCE_COUNTER == 0:
+        if cls.RESOURCE_COUNTER < 1:
             cls.release()
 
     @classmethod
     def acquire(cls):
-        pass
+        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
 
     @classmethod
     def release(cls, *args, **kwargs):
         pass
-
     
     def __init__(self):
         self.incrementCounter()
@@ -73,19 +79,20 @@ if __debug__ and __name__ == '__main__':
         """
         @classmethod
         def acquire(cls):
-            ResourceCounter.acquire()
-            print '-- Acquiring Mouse'
+            super(MouseResource, cls).acquire()
+            print '-- Acquire Mouse'
         
         @classmethod
         def release(cls):
-            ResourceCounter.release()
-            print '-- Releasing Mouse'
+            print '-- Release Mouse'
+            super(MouseResource, cls).release()
+
     
         def __init__(self):
-            ResourceCounter.__init__(self)
-        
+            super(MouseResource, self).__init__()            
+
         def __del__(self):
-            ResourceCounter.__del__(self)
+            super(MouseResource, self).__del__()
 
     class CursorResource(ResourceCounter):
         """
@@ -93,26 +100,38 @@ if __debug__ and __name__ == '__main__':
         resource.  Notice how this class also inherits from
         ResourceCounter.  Instead of subclassing MouseCounter,
         we will just acquire it in our __init__() and release
-        it in our 
+        it in our __del__().
         """
         @classmethod
         def acquire(cls):
-            print '-- Acquiring Cursor'
-            ResourceCounter.acquire()
+            super(CursorResource, cls).acquire()
+            print '-- Acquire Cursor'
             
         @classmethod
         def release(cls):
-            print '-- Releasing Cursor'            
-            ResourceCounter.release()
+            print '-- Release Cursor'
+            super(CursorResource, cls).release()
 
         def __init__(self):
             self.__mouseResource = MouseResource()
-            ResourceCounter.__init__(self)
+            super(CursorResource, self).__init__()            
         
         def __del__(self):
-            ResourceCounter.__del__(self)
+            super(CursorResource, self).__del__()
             del self.__mouseResource
 
+    class InvalidResource(MouseResource):
+        @classmethod
+        def acquire(cls):
+            super(InvalidResource, cls).acquire()
+            print '-- Acquire Invalid'
+            
+        @classmethod
+        def release(cls):
+            print '-- Release Invalid'
+            super(InvalidResource, cls).release()
+            
+            
     print '\nAllocate Mouse'
     m = MouseResource()
     print 'Free up Mouse'
@@ -154,13 +173,21 @@ if __debug__ and __name__ == '__main__':
     del m
     print 'Free up Cursor'
     del c
-        
+
+    # example of an invalid subclass
+    try:
+        print '\nAllocate Invalid'
+        i = InvalidResource()
+        print 'Free up Invalid'
+    except AssertionError,e:
+        print e
 
     def demoFunc():
         print '\nAllocate Cursor within function'
         c = CursorResource()
-        
+
         print 'Cursor will be freed on function exit'
         
-
     demoFunc()
+
+