-
-
Save XanDDemoX/37729817cf274f70ae9a593360b84312 to your computer and use it in GitHub Desktop.
Codea class performance tests
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--//// Replacement for existing Codea class() functionality (@drtimhill) | |
function codeaClass(base) | |
local c = {} -- a new class instance | |
if type(base) == 'table' then | |
-- our new class is a shallow copy of the base class! | |
for i,v in pairs(base) do | |
c[i] = v | |
end | |
c._base = base | |
end | |
-- the class will be the metatable for all its objects, | |
-- and they will look up their methods in it. | |
c.__index = c | |
-- expose a constructor which can be called by <classname>(<args>) | |
local mt = {} | |
mt.__call = function(class_tbl, ...) | |
local obj = {} | |
setmetatable(obj,c) | |
if class_tbl.init then | |
class_tbl.init(obj,...) | |
else | |
-- make sure that any stuff from the base class is initialized! | |
if base and base.init then | |
base.init(obj, ...) | |
end | |
end | |
return obj | |
end | |
c.is_a = function(self, klass) | |
local m = getmetatable(self) | |
while m do | |
if m == klass then return true end | |
m = m._base | |
end | |
return false | |
end | |
setmetatable(c, mt) | |
return c | |
end | |
--do -- Hide locals private to implementation | |
--//// factory(): Construct new object of specified class | |
-- (Called indirectly using class constructor e.g. "Foo(...)") | |
-- (As a convenience, we set obj:_class to the class) | |
-- cls Class of object to create | |
-- ... Arguments to forward to class:init() initializer | |
-- returns Newly constructed object | |
local function factory(cls, ...) | |
local obj = setmetatable({}, cls) | |
obj._class = cls | |
obj:init(...) | |
return obj | |
end | |
--//// _Root: The root class for the class hierarchy | |
-- Implements basic class functions, but has no __call, so | |
-- that it is not possible to create instances of _Root | |
local _Root = {} | |
_Root.__index = _Root | |
_Root.__call = factory | |
--//// obj:init(): Initialize a new object (class instance) | |
-- self Object to initialize | |
-- ... Arguments forwarded from constructor (e.g. Ball(...)) | |
function _Root:init(...) | |
-- Dummy init for _Root | |
print("root") | |
end | |
--//// obj:is_a(): Check to see if object is instance of class | |
-- self Object to check | |
-- cls The class to check (this class and all its superclasses) | |
-- returns true if the object is an instance of the class/superclass | |
function _Root:is_a(cls) | |
local m = getmetatable(self) | |
while m do | |
if m == cls then return true end | |
m = getmetatable(m) | |
end | |
return false | |
end | |
--//// class(): Create a new class, with optional base class | |
-- (As a convenience, we set cls:_base to the base class of the class) | |
-- base Base class, default is _Root class if none specified | |
-- returns New class (create objects using class constructor e.g. "Foo()") | |
function class(base) | |
base = base or _Root | |
local cls = setmetatable({}, base) | |
cls.__index = cls | |
cls.__call = factory | |
cls._base = base | |
return cls | |
end | |
--end | |
-- Some simple examples | |
MyClass = class() | |
MyDerivedClass = class(MyClass) | |
MyThirdClass = class(MyDerivedClass) | |
-- Note that we can create base class methods after setting inheritance above | |
function MyClass:init(x, y) | |
print("MyClass:init(): x=" .. tostring(x) .. ", y=" .. tostring(y)) | |
MyClass._base.init(self) -- Not strictly needed for class derived from _Root | |
self.x, self.y = x, y | |
end | |
function MyDerivedClass:init(x, y, r) | |
print("MyDerivedClass:init(): x=" .. tostring(x) .. ", y=" .. tostring(y)) | |
MyDerivedClass._base.init(self, x, y) | |
self.r = r | |
end | |
function MyDerivedClass:draw() | |
print("MyDerivedClass:draw(): x=" .. tostring(self.x) .. ", y=" .. tostring(self.y)) | |
MyDerivedClass._base.draw(self) | |
end | |
function MyClass:draw() | |
print("MyClass:draw(): x=" .. tostring(self.x) .. ", y=" .. tostring(self.y)) | |
end | |
o1 = MyClass(10, 100) | |
o2 = MyDerivedClass(20, 200, 1.0) | |
o3 = MyThirdClass(30, 300, 2.0) -- Will use MyDerivedClass:init() | |
print("o3:is_a(MyDerivedClass)=" .. tostring(o3:is_a(MyDerivedClass))) | |
print("o2:is_a(MyThirdClass)=" .. tostring(o2:is_a(MyThirdClass))) | |
o1:draw() -- Calls MyClass:draw() | |
o2:draw() -- Calls MyDerivedClass:draw() | |
o3:draw() -- Calls MyDerivedClass:draw() | |
function noUpValuesClass(base) | |
local c = {} -- a new class instance | |
if type(base) == 'table' then | |
-- our new class is a shallow copy of the base class! | |
for i,v in pairs(base) do | |
c[i] = v | |
end | |
c.base = base | |
end | |
-- the class will be the metatable for all its objects, | |
-- and they will look up their methods in it. | |
c.__index = c | |
c.is_a = function(self, klass) | |
local m = getmetatable(self) | |
while m do | |
if m == klass then return true end | |
m = m.base | |
end | |
return false | |
end | |
-- expose a constructor which can be called by <classname>(<args>) | |
local mt = {} | |
mt.__call = function(class_tbl, ...) | |
local obj = setmetatable({},class_tbl) | |
-- make sure that any stuff from the base class is initialized! | |
-- no need to check for a base init because if class_tbl has a base it is already a shallow copy of base. | |
if class_tbl.init then | |
class_tbl.init(obj,...) | |
end | |
return obj | |
end | |
return setmetatable(c, mt) | |
end | |
IndexClass1 = class() | |
function IndexClass1:init() | |
end | |
function IndexClass1:veryBase() | |
end | |
IndexClass2 = class(IndexClass1) | |
function IndexClass2:init() | |
IndexClass2._base.init(self) | |
end | |
IndexClass3 = class(IndexClass2) | |
function IndexClass3:init() | |
IndexClass3._base.init(self) | |
end | |
ShallowCopyClass1 = codeaClass() | |
function ShallowCopyClass1:init() | |
end | |
function ShallowCopyClass1:veryBase() | |
end | |
ShallowCopyClass2 = codeaClass(ShallowCopyClass1) | |
function ShallowCopyClass2:init() | |
ShallowCopyClass2._base.init(self) | |
end | |
ShallowCopyClass3 = codeaClass(ShallowCopyClass2) | |
function ShallowCopyClass3:init() | |
ShallowCopyClass3._base.init(self) | |
end | |
CodeaClass1 = codeaClass() | |
function CodeaClass1:init() | |
end | |
CodeaClass2 = codeaClass(CodeaClass1) | |
function CodeaClass2:init() | |
CodeaClass1.init(self) | |
end | |
CodeaClass3 = codeaClass(CodeaClass2) | |
function CodeaClass3:init() | |
CodeaClass2.init(self) | |
end | |
NoUpValuesClass1 = noUpValuesClass() | |
function NoUpValuesClass1:init() | |
end | |
NoUpValuesClass2 = noUpValuesClass(NoUpValuesClass1) | |
function NoUpValuesClass2:init() | |
NoUpValuesClass2.base.init(self) | |
end | |
NoUpValuesClass3 = noUpValuesClass(NoUpValuesClass2) | |
function NoUpValuesClass3:init() | |
NoUpValuesClass3.base.init(self) | |
end | |
function runTests() | |
local shallow3 = ShallowCopyClass3() | |
local index3 = IndexClass3() | |
local tests = { | |
{ | |
label = "Ignore", | |
func = function() | |
--[[ | |
CodeaClass3() | |
IndexClass3() | |
ShallowCopyClass3() | |
NoUpValuesClass3() | |
]]-- | |
end | |
}, | |
{ | |
label = "CodeaClass3 init", | |
func = function() | |
CodeaClass3() | |
end | |
}, | |
{ | |
label="NoUpValuesClass3 init", | |
func= function() | |
NoUpValuesClass3() | |
end | |
}, | |
{ | |
label="IndexClass3 init", | |
func = function() | |
IndexClass3() | |
end | |
}, | |
{ | |
label="ShallowCopyClass3 init", | |
func = function() | |
ShallowCopyClass3() | |
end | |
}, | |
{ | |
label="IndexClass3 veryBase lookup", | |
func = function() | |
local value = index3.veryBase | |
end | |
}, | |
{ | |
label="ShallowCopyClass3 veryBase lookup", | |
func = function() | |
local value = shallow3.veryBase | |
end | |
}, | |
{ | |
label="IndexClass3 veryBase call", | |
func = function() | |
index3:veryBase() | |
end | |
}, | |
{ | |
label="ShallowCopyClass3 veryBase call", | |
func = function() | |
shallow3:veryBase() | |
end | |
}, | |
{ | |
label="IndexClass3 is_a", | |
func= function() | |
index3:is_a(IndexClass1) | |
end | |
}, | |
{ | |
label="ShallowCopyClass3 is_a", | |
func = function() | |
shallow3:is_a(ShallowCopyClass1) | |
end | |
} | |
} | |
local iterations = 1000000 | |
local baseline = getExecTime(function() end,iterations) | |
print(string.format("Baseline = %.15f",baseline)) | |
for i,item in pairs(tests) do | |
local func = item.func | |
local time = getExecTime(func,iterations) | |
print(string.format("%s: %.15f", item.label, time)) | |
collectgarbage() | |
end | |
end | |
function getExecTime(func, count) | |
local starttime = os.clock() | |
for i=1, count do | |
func() | |
end | |
local endtime = os.clock() | |
return endtime-starttime | |
end | |
function setup() | |
-- for i=1,10 do | |
runTests() | |
-- end | |
end | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment