Skip to content

Instantly share code, notes, and snippets.

@marcoonroad
Created October 22, 2016 16:52
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 marcoonroad/aabc5f0c05ed9690615af76a36e44588 to your computer and use it in GitHub Desktop.
Save marcoonroad/aabc5f0c05ed9690615af76a36e44588 to your computer and use it in GitHub Desktop.
Cloning optimized with clone families.
local export = { }
local weakkey = { __mode = 'k' }
local updated = setmetatable ({ }, weakkey)
local clones = setmetatable ({ }, weakkey)
local prototype = setmetatable ({ }, weakkey)
local proxy = setmetatable ({ }, weakkey)
local metatable = { }
-- we use the `prototype` relation for indexing --
-- propagation while the `clones` relation --
-- is used for propagation by mutation/writes --
function metatable: __index (selector)
local value = proxy[ self ][ selector ]
if not rawequal (value, nil) then
return value
elseif rawequal (prototype[ self ], nil) then
return nil
elseif updated[ self ][ selector ] then
-- when it already have passed by here, --
-- nil is the result value despite --
-- non-nil mutations on prototype-side... --
return nil
else
-- transitive propagation by access. --
-- result value can be nil, though --
local value = prototype[ self ][ selector ]
-- intransitive propagation by mutation --
updated[ self ][ selector ] = true
proxy[ self ][ selector ] = value
-- we have chosen to not propagate down with --
-- mutation, 'cause it will generate too much --
-- overhead as an expensive computation. also, --
-- transitive propagation by mutation is --
-- useless here, 'cause we already have --
-- transivity by indexing on prototype-side... --
return value
end
end
function metatable: __newindex (selector, value)
-- transitive propagation by indexing --
local previous = self[ selector ]
for child in pairs (clones[ self ]) do
if not updated[ child ][ selector ] then
-- intransitive propagation by mutation --
updated[ child ][ selector ] = true
proxy[ child ][ selector ] = previous
end
end
updated[ self ][ selector ] = true
proxy[ self ][ selector ] = value
return
end
function export.create (structure)
local alias = { }
proxy[ alias ] = structure
updated[ alias ] = { }
clones[ alias ] = setmetatable ({ }, weakkey)
setmetatable (alias, metatable)
return alias
end
function export.copy (structure)
local copy = export.create { }
prototype[ copy ] = structure
clones[ structure ][ copy ] = true
return copy
end
return export
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment