resource.monkey2 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. Namespace std.resource
  2. #rem
  3. Ok, the basic rules for resource management are:
  4. * 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).
  5. * If you Retain() a resource, you must eventually Release() it.
  6. * If you open a resource from a resource manager using an OpenBlah method, it will be managed for you.
  7. * Discarding() a resource manager releases any resources it is managing.
  8. Note:
  9. AddDependancy( r1,r2 ) is pretty much the same as:
  10. r2.Retain()
  11. r1.OnDiscarded+=Lambda()
  12. r2.Release()
  13. End
  14. Implemented as a stack for now so I can debug it.
  15. #end
  16. Class Resource
  17. #rem monkeydoc Invoked when the resource is discarded.
  18. #end
  19. Field OnDiscarded:Void()
  20. #rem monkeydoc Creates a new resource.
  21. The reference count for a resource is initially 0.
  22. #end
  23. Method New()
  24. _live.Push( Self )
  25. End
  26. #rem monkeydoc True if resource has been discarded.
  27. #end
  28. Property Discarded:Bool()
  29. Return _refs=-1
  30. End
  31. #rem monkeydoc Retains the resource.
  32. Increments the resource's reference count by 1.
  33. Resources with a reference counter >0 will not be discarded.
  34. #end
  35. Method Retain()
  36. DebugAssert( _refs>=0 )
  37. _refs+=1
  38. End
  39. #rem monkeydoc Releases the resource.
  40. Decrements the resource's reference count by 1.
  41. If the reference count becomes 0, the resource is discarded.
  42. #end
  43. Method Release()
  44. DebugAssert( _refs>0 )
  45. _refs-=1
  46. If Not _refs Discard()
  47. End
  48. #rem monkeydoc Discards the resource.
  49. If the resource's reference count is >0 or the resource has already been discarded, nothing happens.
  50. If the resource's reference count is 0, the resource is discarded. First, OnDiscard() is called, then OnDiscarded() and finally any dependancies are released.
  51. #end
  52. Method Discard()
  53. If _refs Return
  54. _refs=-1
  55. _live.Remove( Self )
  56. OnDiscard()
  57. OnDiscarded()
  58. If Not _depends Return
  59. For Local r:=Eachin _depends
  60. r.Release()
  61. Next
  62. _depends=Null
  63. End
  64. #rem monkeydoc Adds a dependancy to the resource.
  65. Adds `resource` to the list of dependancies for this resource and retains it.
  66. When this resource is eventually discarded, `resource` will be automatically released.
  67. #end
  68. Method AddDependancy( resource:Resource )
  69. DebugAssert( _refs>=0 And resource._refs>=0 )
  70. If Not _depends _depends=New Stack<Resource>
  71. _depends.Add( resource )
  72. resource.Retain()
  73. End
  74. #rem monkeydoc @hidden
  75. #end
  76. Function NumLive:Int()
  77. Return _live.Length
  78. End
  79. Protected
  80. #rem monkeydoc Called when resource is discarded.
  81. #end
  82. Method OnDiscard() Virtual
  83. End
  84. Private
  85. Global _live:=New Stack<Resource>
  86. Field _refs:Int
  87. Field _depends:Stack<Resource>
  88. End
  89. Class ResourceManager Extends Resource
  90. Method New()
  91. If Not _managers
  92. _managers=New Stack<ResourceManager>
  93. Endif
  94. _managers.Push( Self )
  95. End
  96. Function DebugDeps( r:Resource,indent:String )
  97. If Not r._depends Return
  98. indent+=" "
  99. For Local d:=Eachin r._depends
  100. Print indent+String.FromCString( d.typeName() )+", refs="+d._refs
  101. DebugDeps( d,indent )
  102. Next
  103. indent=indent.Slice( 0,-2 )
  104. End
  105. Function DebugAll()
  106. For Local manager:=Eachin _managers
  107. For Local it:=Eachin manager._retained
  108. Print it.Key+", refs="+it.Value._refs
  109. DebugDeps( it.Value,"" )
  110. Next
  111. Next
  112. For Local r:=Eachin _live
  113. 'If Not r._slug Print String.FromCString( r.typeName() )+", ref="+r._refs+", slug="+r._slug
  114. End
  115. End
  116. Method OpenResource:Resource( slug:String )
  117. For Local manager:=Eachin _managers
  118. Local r:=manager._retained[slug]
  119. If Not r Continue
  120. If manager<>Self AddResource( slug,r )
  121. Return r
  122. Next
  123. Return Null
  124. End
  125. Method AddResource( slug:String,r:Resource )
  126. If Not r Return
  127. DebugAssert( Not r.Discarded,"Can't add discarded resource to resource manager" )
  128. If _retained.Contains( slug ) Return
  129. _retained[slug]=r
  130. AddDependancy( r )
  131. End
  132. Protected
  133. Method OnDiscard() Override
  134. _managers.Remove( Self )
  135. _retained=Null
  136. End
  137. Private
  138. Global _managers:Stack<ResourceManager>
  139. Field _retained:=New StringMap<Resource>
  140. End