thomasfn

Classes

Mar 30th, 2012
139
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 7.80 KB | None | 0 0
  1. /*
  2.     *********************************************
  3.     * Basic Class System for GMod - by thomasfn *
  4.     *********************************************
  5.     sh_class.lua - Loads the core class system
  6. */
  7.  
  8. local CLASS_VERSION = 1.00
  9.  
  10. local PULL_DATA = {}
  11.  
  12. if (class_sys) then
  13.     if (class_sys.Version >= CLASS_VERSION) then return MsgN( "Not loading class system, already loaded. Version:(Me=" .. CLASS_VERSION .. ",Other=" .. class_sys.Version .. ")" ) end
  14.     PULL_DATA = { class_sys.PullFactories(), class_sys.PullInstances(), class_sys.PullFlags() }
  15.     MsgN( "Reloading class system. Version:(Me=" .. CLASS_VERSION .. ",Other=" .. class_sys.Version .. ")" )
  16. end
  17.    
  18. class_sys = {}
  19. class_sys.Version = CLASS_VERSION
  20.  
  21. local Factories = PULL_DATA[1] or {}
  22. local Instances = PULL_DATA[2] or {}
  23. local Flags = PULL_DATA[3] or {}
  24.  
  25. for i=1, #Instances do
  26.     Instances[i]._instancepulled = true
  27. end
  28. for i=1, #Factories do
  29.     Factories[i]._factorypulled = true
  30. end
  31.  
  32. function class_sys.PullFactories()
  33.     return Factories
  34. end
  35. function class_sys.PullInstances()
  36.     return Instances
  37. end
  38. function class_sys.PullFlags()
  39.     return Flags
  40. end
  41.  
  42. local function IterateBaseClasses( class, iterator, includehost, ... )
  43.     local base = (includehost and class) or Factories[ class._baseclass ]
  44.     while (base) do
  45.         local result = iterator( class, base, ... )
  46.         if (result) then return result end
  47.         base = Factories[ base._baseclass ]
  48.     end
  49. end
  50.  
  51. local BaseClass = {}
  52. local function LocateBase_It( class, base, func )
  53.     //print( "LocateBase_It: " .. class._name .. ":" .. base._name .. " {" .. tostring( func ) .. "}" )
  54.     if (base._registry[ func ]) then return base end
  55. end
  56. function BaseClass:CallBase( name, ... )
  57.     local origin = debug.getinfo( 2, "f" ).func
  58.     local base = IterateBaseClasses( self, LocateBase_It, true, origin )
  59.     if (base) then base = Factories[ base._baseclass ] end
  60.     if (base) then return base[ name ]( self, ... ) end
  61. end
  62. local function GetBaseChain_It( class, base, tbl )
  63.     table.insert( tbl, base )
  64. end
  65. function BaseClass:GetBaseChain( includehost )
  66.     local tmp = {}
  67.     IterateBaseClasses( self, GetBaseChain_It, includehost, tmp )
  68.     return tmp
  69. end
  70. function BaseClass:CallConstructor( ... )
  71.     local basechain = self:GetBaseChain( true )
  72.     for i=#basechain, 1, -1 do
  73.         local base = basechain[i]
  74.         local constructor = base[ base._subname ]
  75.         if (constructor) then constructor( self, ... ) end
  76.     end
  77. end
  78. local function Is_It( class, base, name )
  79.     if (base._name == name) then return true end
  80. end
  81. function BaseClass:Is( name )
  82.     return IterateBaseClasses( self, Is_It, true, name ) or false
  83. end
  84. function BaseClass:Equals( other )
  85.     return rawequal( self, other )
  86. end
  87. function BaseClass:Type()
  88.     return self._name
  89. end
  90.  
  91. local FactoryMeta = {}
  92. function FactoryMeta.__index( tbl, key )
  93.     local base = Factories[ rawget( tbl, "_baseclass" ) ]
  94.     if (base) then
  95.         return base[ key ]
  96.     else
  97.         return BaseClass[ key ]
  98.     end
  99. end
  100. function FactoryMeta.__newindex( tbl, key, val )
  101.     if (type( val ) == "function") then
  102.         local registry = rawget( tbl, "_registry" )
  103.         registry[ val ] = true
  104.     end
  105.     rawset( tbl, key, val )
  106. end
  107.  
  108. local metaGlobal = { __index = _G }
  109.  
  110. function class( name, _lvl )
  111.     if (Factories[ name ]) then return error( "Class '" .. name .. "' already exists", 3 ) end
  112.     Instances[ name ] = 0
  113.     local factory = setmetatable( {}, FactoryMeta )
  114.     factory._registry = {}
  115.     factory._name = name
  116.     factory._abstract = false
  117.     factory._static = false
  118.     factory._baseclass = ""
  119.     factory._implements = {}
  120.     factory._class = true
  121.     factory._meta = {}
  122.     function factory._meta.__index( tbl, key )
  123.         if (type( key ) == "number") then
  124.             local idxfunc = factory.Index
  125.             if (idxfunc) then return idxfunc( tbl, key ) end
  126.         end
  127.         return factory[ key ]
  128.     end
  129.     function factory._meta.__eq( tbl, other )
  130.         return tbl:Equals( other )
  131.     end
  132.     function factory._meta.__gc( tbl )
  133.         if (Instances[ name ]) then Instances[ name ] = Instances[ name ] - 1 end
  134.     end
  135.     local subparts = string.Explode( ".", name )
  136.     local subname = subparts[ #subparts ]
  137.     local caller = debug.getinfo( _lvl or 2, "f" ).func
  138.     local env = setmetatable( {}, metaGlobal )
  139.     env[ subname ] = factory
  140.     setfenv( caller, env )
  141.     Factories[ name ] = factory
  142.     factory._subname = subname
  143.     return function( base )
  144.         factory._baseclass = base
  145.     end
  146. end
  147.  
  148. function abstract_class( name, _lvl )
  149.     local func = class( name, _lvl or 3 )
  150.     Factories[ name ]._abstract = true
  151.     Instances[ name ] = nil
  152.     return func
  153. end
  154.  
  155. function wrapper_class( name, base, metatable, validator )
  156.     if (base) then
  157.         class( name )( base )
  158.     else
  159.         class( name )
  160.     end
  161.     local env = getfenv( wrapper_class )
  162.     local c = env[ name ]
  163.     c[ name ] = function( self, obj )
  164.         if (not validator( obj )) then return error( "Object is not valid", 4 ) end
  165.         self.Object = obj
  166.     end
  167.     for key, val in pairs( metatable ) do
  168.         local val = val
  169.         if (type( val ) == "function") then
  170.             c[ key ] = function( self, ... )
  171.                 if (not validator( self.Object )) then return error( "Object is not valid", 4 ) end
  172.                 return val( self.Object, ... )
  173.             end
  174.         end
  175.     end
  176. end
  177.  
  178. function static_class( name )
  179.     local func = class( name, 3 )
  180.     Factories[ name ]._static = true
  181.     local caller = debug.getinfo( 2, "f" ).func
  182.     local env = getfenv( caller )
  183.     function env.static_finalise()
  184.         Factories[ name ]._static = false
  185.         _G[ name ] = new( name )
  186.         Factories[ name ]._static = true
  187.         Instances[ name ] = nil
  188.         env.static_finalise = nil
  189.     end
  190.     return func
  191. end
  192.  
  193. function new( name, ... )
  194.     local factory = Factories[ name ]
  195.     if (not factory) then return error( "Failed to create instance of class '" .. name .. "' (class not found)", 3 ) end
  196.     if (factory._abstract) then return error( "Failed to create instance of class '" .. name .. "' (class is abstract)", 2 ) end
  197.     if (factory._static) then return error( "Failed to create instance of class '" .. name .. "' (class is static)", 2 ) end
  198.     if (factory._factorypulled) then ErrorNoHalt( "Warning: Class '" .. name .. "' was pulled from a previous version of class_sys.\n" ) end
  199.     local meta = factory._meta
  200.     if ((not meta.inited) and factory.InitMeta) then
  201.         factory.InitMeta( meta )
  202.         meta.inited = true
  203.     end
  204.     local o = setmetatable( {}, meta )
  205.     o:CallConstructor( ... )
  206.     if (o.PostConstructor) then o:PostConstructor() end
  207.     Instances[ name ] = Instances[ name ] + 1
  208.     return o
  209. end
  210.  
  211. function class_flag( name )
  212.     if (Flags[ name ]) then return true end
  213.     Flags[ name ] = true
  214.     return false
  215. end
  216.  
  217. function factory_exists( name )
  218.     return Factories[ name ] ~= nil
  219. end
  220.  
  221. function factory_wipe( name )
  222.     Factories[ name ] = nil
  223. end
  224.  
  225. function ClassMemoryStats()
  226.     return Instances
  227. end
  228.  
  229. if (CLIENT) then
  230.     concommand.Add( "cl_class_stats", function( ply, com, args )
  231.         print( "INSTANCE COUNT" )
  232.         for key, val in pairs( Instances ) do
  233.             print( key .. ": " .. val )
  234.         end
  235.     end )
  236. end
  237. if (SERVER) then
  238.     concommand.Add( "sv_class_stats", function( ply, com, args )
  239.         print( "INSTANCE COUNT" )
  240.         for key, val in pairs( Instances ) do
  241.             print( key .. ": " .. val )
  242.         end
  243.     end )
  244. end
  245.  
  246. function ValidClass( obj, name )
  247.     if (type( obj ) ~= "table") then return false end
  248.     if (name) then
  249.         return obj._class and obj:Is( name )
  250.     else
  251.         return obj._class
  252.     end
  253. end
  254.  
  255. /* DEFAULT CLASSES */
  256.  
  257. abstract_class "ICallable"
  258. function ICallable.InitMeta( meta )
  259.     meta.__call = function( self, ... )
  260.         return self:Call( ... )
  261.     end
  262. end
  263. function ICallable:Call() end
  264. function ICallable:Proxy()
  265.     return function( ... ) return self( ... ) end
  266. end
  267.  
  268. abstract_class "IDetour" ("ICallable")
  269. function IDetour:IDetour( old, override )
  270.     self.OldFunc = old
  271.     if (override and ValidClass( old, "IDetour" )) then self.OldFunc = old.OldFunc end
  272. end
  273. function IDetour:Call( ... )
  274.     local result = self:Func( ... )
  275.     if (result) then
  276.         return result
  277.     else
  278.         return self.OldFunc( ... )
  279.     end
  280. end
  281. function IDetour:Func( ... ) end
Advertisement
Add Comment
Please, Sign In to add comment