local core = require "skynet.sharedata.core" local type = type local rawset = rawset local conf = {} conf.host = { new = core.new, delete = core.delete, getref = core.getref, markdirty = core.markdirty, incref = core.incref, decref = core.decref, } local meta = {} local isdirty = core.isdirty local index = core.index local needupdate = core.needupdate local len = core.len local core_nextkey = core.nextkey local function findroot(self) while self.__parent do self = self.__parent end return self end local function update(root, cobj, gcobj) root.__obj = cobj root.__gcobj = gcobj local children = root.__cache if children then for k,v in pairs(children) do local pointer = index(cobj, k) if type(pointer) == "userdata" then update(v, pointer, gcobj) else children[k] = nil end end end end local function genkey(self) local key = tostring(self.__key) while self.__parent do self = self.__parent key = self.__key .. "." .. key end return key end local function getcobj(self) local obj = self.__obj if isdirty(obj) then local newobj, newtbl = needupdate(self.__gcobj) if newobj then local newgcobj = newtbl.__gcobj local root = findroot(self) update(root, newobj, newgcobj) if obj == self.__obj then error ("The key [" .. genkey(self) .. "] doesn't exist after update") end obj = self.__obj end end return obj end function meta:__newindex(key, value) error ("Error newindex, the key [" .. genkey(self) .. "]") end function meta:__index(key) local obj = getcobj(self) local v = index(obj, key) if type(v) == "userdata" then local children = self.__cache if children == nil then children = {} rawset(self, "__cache", children) end local r = children[key] if r then return r end r = setmetatable({ __obj = v, __gcobj = self.__gcobj, __parent = self, __key = key, }, meta) children[key] = r return r else return v end end function meta:__len() return len(getcobj(self)) end function meta:__pairs() return conf.next, self, nil end function conf.next(obj, key) local cobj = getcobj(obj) local nextkey = core_nextkey(cobj, key) if nextkey then return nextkey, obj[nextkey] end end function conf.box(obj) local gcobj = core.box(obj) return setmetatable({ __parent = false, __obj = obj, __gcobj = gcobj, __key = "", } , meta) end function conf.update(self, pointer) local cobj = self.__obj assert(isdirty(cobj), "Only dirty object can be update") core.update(self.__gcobj, pointer, { __gcobj = core.box(pointer) }) end function conf.flush(obj) getcobj(obj) end local function clone_table(cobj) local obj = {} local key while true do key = core_nextkey(cobj, key) if key == nil then break end local v = index(cobj, key) if type(v) == "userdata" then v = clone_table(v) end obj[key] = v end return obj end local function find_node(cobj, key, ...) if key == nil then return cobj end local cobj = index(cobj, key) if cobj == nil then return nil end if type(cobj) == "userdata" then return find_node(cobj, ...) end return cobj end function conf.copy(cobj, ...) cobj = find_node(cobj, ...) if cobj then if type(cobj) == "userdata" then return clone_table(cobj) else return cobj end end end return conf