Skip to content

Instantly share code, notes, and snippets.

@XanDDemoX
Created February 19, 2017 14:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save XanDDemoX/37729817cf274f70ae9a593360b84312 to your computer and use it in GitHub Desktop.
Save XanDDemoX/37729817cf274f70ae9a593360b84312 to your computer and use it in GitHub Desktop.
Codea class performance tests
--//// 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