Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Lua: Descending Table Traversal Round 2: Iterator Object (See related posts)

This is some concept code I threw together for Lua to see how feasable it was to make a lua object/table into an iterator that you can manipulate. This iterator descends through all tables and subtables of any queued table. It returns the "path" we're at, as a string, the current table, the key, and the value.

Code:
   1  traverse = {}
   2  function traverse:new(tname)
   3  	local o = {}
   4  	o.names = {}
   5  	o.queue = {}
   6  	o.cur = {
   7  		tbl = nil,
   8  		path = nil,
   9  		state = nil,
  10  	}
  11  
  12  	local mt = {}
  13  	function mt:__call(tn)
  14  		return o:iter(tn)
  15  	end
  16  	mt.__index = self
  17  	setmetatable(o, mt)
  18  
  19  	if tname then
  20  		o:enqueue(tname)
  21  	end
  22  	return o
  23  end
  24  function traverse:next()
  25  	local v
  26  	local names, queue, cur = self.names, self.queue, self.cur
  27  
  28  	local function _poptbl()
  29  		if cur.tbl then
  30  			names[cur.tbl] = nil
  31  		end
  32  		cur.tbl = table.remove(queue, 1)
  33  		cur.path = names[cur.tbl]
  34  		cur.state = nil
  35  	end
  36  
  37  	repeat
  38  		-- Find something to return to the user...
  39  		if not cur.state then
  40  			-- Pop a new table off the stack
  41  			_poptbl()
  42  			if not cur.tbl then
  43  				-- No more tables to process
  44  				return nil
  45  			end
  46  		end
  47  		cur.state,v = next(cur.tbl, cur.state)
  48  	until cur.state
  49  
  50  	if type(v) == "table" then
  51  		local path = cur.path.."."..cur.state
  52  		names[v] = path
  53  		table.insert(queue, v)
  54  	end
  55  	return cur.path,cur.tbl,cur.state,v
  56  end
  57  function traverse:iter(tname)
  58  	if tname then
  59  		self:enqueue(tname)
  60  	end
  61  	return function(...) return self:next(unpack(arg)) end, nil, nil
  62  end
  63  function traverse:enqueue(tname)
  64  	local v = _G[tname]
  65  	table.insert(self.queue, v)
  66  	self.names[v] = tname
  67  end
  68  function traverse:reset()
  69  	self.names = {}
  70  	self.queue = {}
  71  end
  72  local traverse_mt = {
  73      __call = function(self, tname)
  74               	if tname then
  75               		return self:new(tname):iter()
  76               	else
  77               		return self:new()
  78               	end
  79               end
  80  }
  81  setmetatable(traverse, traverse_mt)


Example Usage:
   1  foo = {a={},b={},c={"bar"},d={e={},f={"moo"}},1,2,3,4,5}
   2  bar = {"alpha", "beta", "theta", omega = {}}
   3  
   4  local mytraverser = traverse()
   5  mytraverser:enqueue("bar")
   6  mytraverser:enqueue("foo")
   7  for p,t,k,v in mytraverser() do
   8  --for p,t,k,v in traverse('foo') do
   9  	print(string.format("%s[%s] = %s",tostring(p),tostring(k),tostring(v)))
  10  end


Output from Example Usage:
   1  bar[1] = alpha
   2  bar[2] = beta
   3  bar[3] = theta
   4  bar[omega] = table: 0x510650
   5  foo[1] = 1
   6  foo[2] = 2
   7  foo[3] = 3
   8  foo[4] = 4
   9  foo[5] = 5
  10  foo[a] = table: 0x5102d0
  11  foo[c] = table: 0x510370
  12  foo[b] = table: 0x510320
  13  foo[d] = table: 0x5103c0
  14  foo.c[1] = bar
  15  foo.d[e] = table: 0x5104c0
  16  foo.d[f] = table: 0x510510
  17  foo.d.f[1] = moo

You need to create an account or log in to post comments to this site.


Click here to browse all 5551 code snippets

Related Posts