瀏覽代碼

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
     This class is an attempt to combine the RAIA idiom with reference
     counting semantics in order to model shared resources. RAIA stands
     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
     When a resource is needed, create an appropriate ResourceCounter
     object.  If the resource is already available (meaning another
     object.  If the resource is already available (meaning another
     ResourceCounter object of the same type already exists), no action
     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
     ResourceCounter objects have been deleted.  When no objects of
     a particular ResourceCounter type exist, the release() function for
     a particular ResourceCounter type exist, the release() function for
     that type is invoked and the managed resource is cleaned up.
     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
         Until we figure out a way to wrangle a bit more functionality out
         of Python, you MUST NOT define acquire() and release() again in
         of Python, you MUST NOT define acquire() and release() again in
         any subclasses of your ResourceCounter subclass in an attempt
         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
         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
     @classmethod
@@ -46,18 +48,22 @@ class ResourceCounter(object):
     @classmethod
     @classmethod
     def decrementCounter(cls):
     def decrementCounter(cls):
         cls.RESOURCE_COUNTER -= 1
         cls.RESOURCE_COUNTER -= 1
-
-        if cls.RESOURCE_COUNTER == 0:
+        if cls.RESOURCE_COUNTER < 1:
             cls.release()
             cls.release()
 
 
     @classmethod
     @classmethod
     def acquire(cls):
     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
     @classmethod
     def release(cls, *args, **kwargs):
     def release(cls, *args, **kwargs):
         pass
         pass
-
     
     
     def __init__(self):
     def __init__(self):
         self.incrementCounter()
         self.incrementCounter()
@@ -73,19 +79,20 @@ if __debug__ and __name__ == '__main__':
         """
         """
         @classmethod
         @classmethod
         def acquire(cls):
         def acquire(cls):
-            ResourceCounter.acquire()
-            print '-- Acquiring Mouse'
+            super(MouseResource, cls).acquire()
+            print '-- Acquire Mouse'
         
         
         @classmethod
         @classmethod
         def release(cls):
         def release(cls):
-            ResourceCounter.release()
-            print '-- Releasing Mouse'
+            print '-- Release Mouse'
+            super(MouseResource, cls).release()
+
     
     
         def __init__(self):
         def __init__(self):
-            ResourceCounter.__init__(self)
-        
+            super(MouseResource, self).__init__()            
+
         def __del__(self):
         def __del__(self):
-            ResourceCounter.__del__(self)
+            super(MouseResource, self).__del__()
 
 
     class CursorResource(ResourceCounter):
     class CursorResource(ResourceCounter):
         """
         """
@@ -93,26 +100,38 @@ if __debug__ and __name__ == '__main__':
         resource.  Notice how this class also inherits from
         resource.  Notice how this class also inherits from
         ResourceCounter.  Instead of subclassing MouseCounter,
         ResourceCounter.  Instead of subclassing MouseCounter,
         we will just acquire it in our __init__() and release
         we will just acquire it in our __init__() and release
-        it in our 
+        it in our __del__().
         """
         """
         @classmethod
         @classmethod
         def acquire(cls):
         def acquire(cls):
-            print '-- Acquiring Cursor'
-            ResourceCounter.acquire()
+            super(CursorResource, cls).acquire()
+            print '-- Acquire Cursor'
             
             
         @classmethod
         @classmethod
         def release(cls):
         def release(cls):
-            print '-- Releasing Cursor'            
-            ResourceCounter.release()
+            print '-- Release Cursor'
+            super(CursorResource, cls).release()
 
 
         def __init__(self):
         def __init__(self):
             self.__mouseResource = MouseResource()
             self.__mouseResource = MouseResource()
-            ResourceCounter.__init__(self)
+            super(CursorResource, self).__init__()            
         
         
         def __del__(self):
         def __del__(self):
-            ResourceCounter.__del__(self)
+            super(CursorResource, self).__del__()
             del self.__mouseResource
             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'
     print '\nAllocate Mouse'
     m = MouseResource()
     m = MouseResource()
     print 'Free up Mouse'
     print 'Free up Mouse'
@@ -154,13 +173,21 @@ if __debug__ and __name__ == '__main__':
     del m
     del m
     print 'Free up Cursor'
     print 'Free up Cursor'
     del c
     del c
-        
+
+    # example of an invalid subclass
+    try:
+        print '\nAllocate Invalid'
+        i = InvalidResource()
+        print 'Free up Invalid'
+    except AssertionError,e:
+        print e
 
 
     def demoFunc():
     def demoFunc():
         print '\nAllocate Cursor within function'
         print '\nAllocate Cursor within function'
         c = CursorResource()
         c = CursorResource()
-        
+
         print 'Cursor will be freed on function exit'
         print 'Cursor will be freed on function exit'
         
         
-
     demoFunc()
     demoFunc()
+
+