Browse Source

WIP resource manager support;Renamed virtual Stream.Close to Strean.OnClose (sorry).

Mark Sibly 9 years ago
parent
commit
db32905ccf

+ 42 - 33
modules/std/graphics/pixmap.monkey2

@@ -1,12 +1,14 @@
 
 
 Namespace std.graphics
 Namespace std.graphics
 
 
+Using std.resource
+
 #rem monkeydoc Pixmaps allow you to store and manipulate rectangular blocks of pixel data.
 #rem monkeydoc Pixmaps allow you to store and manipulate rectangular blocks of pixel data.
 
 
 A pixmap contains a block of memory used to store a rectangular array of pixels.
 A pixmap contains a block of memory used to store a rectangular array of pixels.
 
 
 #end
 #end
-Class Pixmap Extends std.resource.Resource
+Class Pixmap Extends Resource
 
 
 	#rem monkeydoc Creates a new pixmap.
 	#rem monkeydoc Creates a new pixmap.
 	
 	
@@ -24,6 +26,8 @@ Class Pixmap Extends std.resource.Resource
 	
 	
 	#end
 	#end
 	Method New( width:Int,height:Int,format:PixelFormat=PixelFormat.RGBA32 )
 	Method New( width:Int,height:Int,format:PixelFormat=PixelFormat.RGBA32 )
+	
+'		Print "New pixmap1, width="+width+", height="+height
 
 
 		Local depth:=PixelFormatDepth( format )
 		Local depth:=PixelFormatDepth( format )
 		Local pitch:=width*depth
 		Local pitch:=width*depth
@@ -36,7 +40,7 @@ Class Pixmap Extends std.resource.Resource
 		_data=data
 		_data=data
 		_pitch=pitch
 		_pitch=pitch
 		
 		
-		OnDiscarded=Lambda()
+		OnDiscarded+=Lambda()
 			libc.free( _data )
 			libc.free( _data )
 			_data=Null
 			_data=Null
 		End
 		End
@@ -44,6 +48,8 @@ Class Pixmap Extends std.resource.Resource
 	
 	
 	Method New( width:Int,height:Int,format:PixelFormat,data:UByte Ptr,pitch:Int )
 	Method New( width:Int,height:Int,format:PixelFormat,data:UByte Ptr,pitch:Int )
 	
 	
+'		Print "New pixmap2, width="+width+", height="+height
+
 		Local depth:=PixelFormatDepth( format )
 		Local depth:=PixelFormatDepth( format )
 		
 		
 		_width=width
 		_width=width
@@ -299,6 +305,22 @@ Class Pixmap Extends std.resource.Resource
 			Next
 			Next
 		next
 		next
 	End
 	End
+
+	#rem monkeydoc Creates a copy of the pixmap.
+
+	@return A new pixmap.
+	
+	#end
+	Method Copy:Pixmap()
+	
+		Local pitch:=Width * Depth
+		Local data:=Cast<UByte Ptr>( libc.malloc( pitch * Height ) )
+		For Local y:=0 Until Height
+			memcpy( data+y*pitch,PixelPtr( 0,y ),pitch )
+		Next
+		
+		Return New Pixmap( Width,Height,Format,data,pitch )
+	End
 	
 	
 	#rem monkeydoc Paste a pixmap to the pixmap.
 	#rem monkeydoc Paste a pixmap to the pixmap.
 	
 	
@@ -323,17 +345,6 @@ Class Pixmap Extends std.resource.Resource
 		Next
 		Next
 	End
 	End
 
 
-	'Optimize!
-	'
-	#rem monkeydoc Creates a copy of the pixmap.
-	
-	@return A new pixmap.
-	
-	#end
-	Method Copy:Pixmap()
-		Return Convert( _format )
-	End
-
 	'Optimize!
 	'Optimize!
 	'
 	'
 	#rem monkeydoc Converts the pixmap to a different format.
 	#rem monkeydoc Converts the pixmap to a different format.
@@ -404,9 +415,7 @@ Class Pixmap Extends std.resource.Resource
 		
 		
 		Local pixmap:=New Pixmap( width,height,_format,PixelPtr( x,y ),_pitch )
 		Local pixmap:=New Pixmap( width,height,_format,PixelPtr( x,y ),_pitch )
 		
 		
-		OnDiscarded+=Lambda()
-			pixmap.Discard()
-		End
+		AddDependancy( pixmap )
 		
 		
 		Return pixmap
 		Return pixmap
 	End
 	End
@@ -440,23 +449,6 @@ Class Pixmap Extends std.resource.Resource
 		Return pixmap
 		Return pixmap
 	End
 	End
 
 
-	#rem monkeydoc @hidden experimental!
-	#end	
-	Function Open:Pixmap( path:String,format:PixelFormat=Null,pmAlpha:Bool=False )
-
-		path=RealPath( path )
-		
-		Local slug:="Pixmap:path="+path+"&format="+Int( format )+"&pmAlpha="+Int( pmAlpha )
-		
-		Local pixmap:=Cast<Pixmap>( OpenResource( slug ) )
-		If pixmap Return pixmap
-		
-		pixmap=Load( path,format,pmAlpha )
-		
-		AddResource( slug,pixmap )
-		Return pixmap
-	End
-	
 	Private
 	Private
 	
 	
 	Field _width:Int
 	Field _width:Int
@@ -467,3 +459,20 @@ Class Pixmap Extends std.resource.Resource
 	Field _pitch:Int
 	Field _pitch:Int
 
 
 End
 End
+
+Class ResourceManager Extension
+
+	Method OpenPixmap:Pixmap( path:String,format:PixelFormat=Null,pmAlpha:Bool=False )
+	
+		Local slug:="Pixmap:name="+StripDir( StripExt( path ) )+"&format="+Int( format )+"&pmAlpha="+Int( pmAlpha )
+
+		Local pixmap:=Cast<Pixmap>( OpenResource( slug ) )
+		If pixmap Return pixmap
+		
+		pixmap=Pixmap.Load( path,format,pmAlpha )
+		
+		AddResource( slug,pixmap )
+		Return pixmap
+	End
+	
+End

+ 1 - 1
modules/std/memory/datastream.monkey2

@@ -53,7 +53,7 @@ Class DataStream Extends std.stream.Stream
 	#rem monkeydoc Closes the datastream.
 	#rem monkeydoc Closes the datastream.
 	
 	
 	#end
 	#end
-	Method Close() Override
+	Method OnClose() Override
 		If Not _buf Return
 		If Not _buf Return
 		_buf=Null
 		_buf=Null
 		_off=0
 		_off=0

+ 10 - 0
modules/std/misc/chartype.monkey2

@@ -3,6 +3,8 @@ Namespace std.stringio
 
 
 #rem monkeydoc Checks if a character is whitespace.
 #rem monkeydoc Checks if a character is whitespace.
 
 
+Returns true if `char` is 32 or less.
+
 @param chr The character to check.
 @param chr The character to check.
 
 
 @return True if `char` is 32 or less.
 @return True if `char` is 32 or less.
@@ -14,6 +16,8 @@ End
 
 
 #rem monkeydoc checks if a character is a decimal digit.
 #rem monkeydoc checks if a character is a decimal digit.
 
 
+Returns true if `ch` is '0'-'9'.
+
 @param chr The character to check.
 @param chr The character to check.
 
 
 @return True if `ch` is '0'-'9'.
 @return True if `ch` is '0'-'9'.
@@ -25,6 +29,8 @@ End
 
 
 #rem monkeydoc Checks if a character is alphabetic.
 #rem monkeydoc Checks if a character is alphabetic.
 
 
+Returns true if `ch` is 'a'-'z' or 'A'-'Z'.
+
 @param chr The character to check.
 @param chr The character to check.
 
 
 @return True if `ch` is 'a'-'z' or 'A'-'Z'.
 @return True if `ch` is 'a'-'z' or 'A'-'Z'.
@@ -36,6 +42,8 @@ End
 
 
 #rem monkeydoc Checks if a character is an identifier.
 #rem monkeydoc Checks if a character is an identifier.
 
 
+Returns true if `ch` is '0'-'9', 'a'-'z', 'A'-'Z' or '_'.
+
 @param chr The character to check.
 @param chr The character to check.
 
 
 @return True if `ch` is '0'-'9', 'a'-'z', 'A'-'Z' or '_'.
 @return True if `ch` is '0'-'9', 'a'-'z', 'A'-'Z' or '_'.
@@ -47,6 +55,8 @@ End
 
 
 #rem monkeydoc Checks if a character is a hexadecimal digit.
 #rem monkeydoc Checks if a character is a hexadecimal digit.
 
 
+Returns true if `ch` is '0'-'9', 'a'-'f', or 'A'-'F'.
+
 @param chr The character to check.
 @param chr The character to check.
 
 
 @return True if `ch` is '0'-'9', 'a'-'f', or 'A'-'F'.
 @return True if `ch` is '0'-'9', 'a'-'f', or 'A'-'F'.

+ 192 - 14
modules/std/resource/resource.monkey2

@@ -1,51 +1,229 @@
 
 
 Namespace std.resource
 Namespace std.resource
 
 
+#rem
+
+Ok, the basic rules for resource management are:
+
+* If you create a resource using 'New' or 'Load', you must either Retain() it, Discard() it or add it as a dependancy of another resource (same as retaining it really).
+
+* If you Retain() a resource, you must eventually Release() it.
+
+* If you open a resource from a resource manager using an OpenBlah method, it will be managed for you.
+
+* Discarding() a resource manager releases any resources it is managing.
+
+Note:
+
+AddDependancy( r1,r2 ) is pretty much the same as:
+
+r2.Retain()
+r1.OnDiscarded+=Lambda()
+	r2.Release()
+End
+
+Implemented as a stack for now so I can debug it.
+
+#end
+
 Class Resource
 Class Resource
 
 
+	#rem monkeydoc Invoked when the resource is discarded.
+	#end
 	Field OnDiscarded:Void()
 	Field OnDiscarded:Void()
 	
 	
+	#rem monkeydoc Creates a new resource.
+	
+	The reference count for a resource is initially 0.
+	
+	#end
+	Method New()
+
+		_live.Push( Self )
+	End
+	
+	#rem monkeydoc True if resource has been discarded.
+	#end
 	Property Discarded:Bool()
 	Property Discarded:Bool()
 	
 	
-		Return _discarded
+		Return _refs=-1
 	End
 	End
+
+	#rem monkeydoc Retains the resource.
 	
 	
-	Method Discard()
+	Increments the resource's reference count by 1.
 	
 	
-		If _discarded Or _refs Return
+	Resources with a reference counter >0 will not be discarded.
+	
+	#end
+	Method Retain()
+		DebugAssert( _refs>=0 )
 		
 		
-		_discarded=True
+		_refs+=1
+	End
+	
+	#rem monkeydoc Releases the resource.
+	
+	Decrements the resource's reference count by 1.
+	
+	If the reference count becomes 0, the resource is discarded.
+	
+	#end
+	Method Release()
+
+		DebugAssert( _refs>0 )
+		
+		_refs-=1
+		
+		If Not _refs Discard()
+	End
+	
+	#rem monkeydoc Discards the resource.
+	
+	If the resource's reference count is >0 or the resource has already been discarded, nothing happens.
+	
+	If the resource's reference count is 0, the resource is discarded. First, OnDiscard() is called, then OnDiscarded() and finally any dependancies are released.
+	
+	#end
+	Method Discard()
+		If _refs Return
+		
+		_refs=-1
+		
+		_live.Remove( Self )
 	
 	
 		OnDiscard()
 		OnDiscard()
 		
 		
 		OnDiscarded()
 		OnDiscarded()
+		
+		If Not _depends Return
+		
+		For Local r:=Eachin _depends
+			r.Release()
+		Next
+		
+		_depends=Null
+	End
+	
+	#rem monkeydoc Adds a dependancy to the resource.
+	
+	Adds `resource` to the list of dependancies for this resource and retains it.
+	
+	When this resource is eventually discarded, `resource` will be automatically released.
+	
+	#end
+	Method AddDependancy( resource:Resource )
+		DebugAssert( _refs>=0 And resource._refs>=0 )
+		
+		If Not _depends _depends=New Stack<Resource>
+		
+		_depends.Add( resource )
+		
+		resource.Retain()
+	End
+
+	#rem monkeydoc @hidden
+	#end	
+	Function NumLive:Int()
+	
+		Return _live.Length
 	End
 	End
 	
 	
 	Protected
 	Protected
 	
 	
+	#rem monkeydoc Called when resource is discarded.
+	#end
 	Method OnDiscard() Virtual
 	Method OnDiscard() Virtual
 	End
 	End
 	
 	
-	Function OpenResource:Resource( slug:String )
+	Private
+	
+	Global _live:=New Stack<Resource>
 	
 	
-		Return _open[slug]
+	Field _refs:Int
+	
+	Field _depends:Stack<Resource>
+End
+
+Class ResourceManager Extends Resource
+
+	Method New()
+		If Not _managers
+			_managers=New Stack<ResourceManager>
+		Endif
+		_managers.Push( Self )
 	End
 	End
 	
 	
-	Function AddResource( slug:String,r:Resource )
+	Function DebugDeps( r:Resource,indent:String )
 	
 	
-		If _open.Contains( slug ) Return
+		If Not r._depends Return
 	
 	
-		_open[slug]=r
+		indent+="  "
+		For Local d:=Eachin r._depends
+			Print indent+String.FromCString( d.typeName() )+", refs="+d._refs
+			DebugDeps( d,indent )
+		Next
+		indent=indent.Slice( 0,-2 )
 		
 		
-		If r r._refs+=1
 	End
 	End
 	
 	
-	Private
+	Function DebugAll()
 	
 	
-	Field _refs:Int
+		For Local manager:=Eachin _managers
+		
+			For Local it:=Eachin manager._retained
+			
+				Print it.Key+", refs="+it.Value._refs
+				DebugDeps( it.Value,"" )
+
+			Next
+		Next
+		
+		For Local r:=Eachin _live
+			'If Not r._slug Print String.FromCString( r.typeName() )+", ref="+r._refs+", slug="+r._slug
+		End
+	End
+	
+	Method OpenResource:Resource( slug:String )
+	
+		For Local manager:=Eachin _managers
+		
+			Local r:=manager._retained[slug]
+			If Not r Continue
+			
+			If manager<>Self AddResource( slug,r )
+			
+			Return r
+		Next
+
+		Return Null
+	End
+	
+	Method AddResource( slug:String,r:Resource )
+		If Not r Return
+		
+		DebugAssert( Not r.Discarded,"Can't add discarded resource to resource manager" )
+
+		If _retained.Contains( slug ) Return
+		
+		_retained[slug]=r
+		
+		AddDependancy( r )
+	End
+	
+	Protected
+	
+	Method OnDiscard() Override
 	
 	
-	Field _discarded:=False
+		_managers.Remove( Self )
 	
 	
-	Global _open:=New StringMap<Resource>
+		_retained=Null
+	End
+	
+	Private
 	
 	
+	Global _managers:Stack<ResourceManager>
+	
+	Field _retained:=New StringMap<Resource>
+
 End
 End

+ 1 - 1
modules/std/socket/socket.monkey2

@@ -69,7 +69,7 @@ Class Socket Extends std.stream.Stream
 
 
 	#rem monkeydoc Closes the socket.
 	#rem monkeydoc Closes the socket.
 	#end
 	#end
-	Method Close:Void() Override
+	Method OnClose() Override
 		If _socket<0 Return
 		If _socket<0 Return
 	
 	
 		socket_close( _socket )
 		socket_close( _socket )

+ 1 - 1
modules/std/stream/filestream.monkey2

@@ -41,7 +41,7 @@ Class FileStream Extends Stream
 	Closing the filestream also sets its position and length to 0.
 	Closing the filestream also sets its position and length to 0.
 	
 	
 	#end
 	#end
-	Method Close() Override
+	Method OnClose() Override
 		If Not _file Return	
 		If Not _file Return	
 		fclose( _file )
 		fclose( _file )
 		_file=Null
 		_file=Null

+ 10 - 3
modules/std/stream/stream.monkey2

@@ -29,7 +29,10 @@ Class Stream
 	
 	
 	#rem monkeydoc Closes the stream.
 	#rem monkeydoc Closes the stream.
 	#end
 	#end
-	Method Close:Void() Abstract
+	Method Close:Void()
+		OnClose()
+		_tmpbuf.Discard()
+	End
 
 
 	#rem monkeydoc Seeks to a position in the stream.
 	#rem monkeydoc Seeks to a position in the stream.
 	
 	
@@ -132,8 +135,10 @@ Class Stream
 	
 	
 		Local data:=New DataBuffer( count )
 		Local data:=New DataBuffer( count )
 		Local n:=ReadAll( data,0,count )
 		Local n:=ReadAll( data,0,count )
-		If n<count Return data.Slice( 0,n )
-		Return data
+		If n>=count Return data
+		Local tmp:=data.Slice( 0,n )
+		data.Discard()
+		Return tmp
 	End
 	End
 	
 	
 	Method ReadAll:DataBuffer()
 	Method ReadAll:DataBuffer()
@@ -468,6 +473,8 @@ Class Stream
 		_tmpbuf=New DataBuffer( 8,ByteOrder.LittleEndian )
 		_tmpbuf=New DataBuffer( 8,ByteOrder.LittleEndian )
 	End
 	End
 	
 	
+	Method OnClose() Abstract
+	
 	Private
 	Private
 	
 	
 	Field _tmpbuf:DataBuffer
 	Field _tmpbuf:DataBuffer