This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Symmetryc's profile picture

[Function] Variable or Infinite Depth Table

Started by Symmetryc, 05 December 2013 - 07:28 PM
Symmetryc #1
Posted 05 December 2013 - 08:28 PM
Hello, I've made a function that allows you to create variable or infinite depth tables: http://pastebin.com/mZJhuTq5

Explanation:

local index = dofile("index") -- assuming you named the file "index"
local t = setmetatable({}, {__index = index(5)}) -- Depth of 5 indices
t[1][2][3][4][5] = 7 -- No attempt to index nil
print(t[1][2][3][4][5]) --> 7
t.thing.hello[{}][function() end][true] = 18 -- can use _any_ key
local t = setmetatable({}, {__index = index(-1)}) -- Depth of -1 makes it infinitely long
t[1][2][3][4][5][6][7][8][9][0] = 6 -- could've kept making it longer if I wanted =P
t.helloworld.lua.cc.foo.bar = "=)" -- can have values with different depths
print(t[1][2][3][4][5][6][7][8][9][0]) --> 6
print(t.helloworld.lua.cc.foo.bar) --> =)
Edited on 05 December 2013 - 07:28 PM
oeed #2
Posted 05 December 2013 - 09:30 PM
Wait, so what does this do?
What's the advantage of doing this over normal tables?
Symmetryc #3
Posted 05 December 2013 - 09:53 PM
Wait, so what does this do?
What's the advantage of doing this over normal tables?
You can change the depth of the table, ex:

-- normal table (depth 1)
local t = {}
t[1][2][3] = 5 -- error
-- depth 3 table
local t = setmetatable({}, {__index = index(3)})
t[1][2][3] = 5 -- no error

It is most useful in situations where you are mapping something. For instance, let's say you're creating a buffer, you could do this:

local buffer = {
	new = function()
		return setmetatable(
			{
				local pos = {0, 0}
				set_pixel = function(self, x, y, back, color, text)
					-- no need to check to see if self[x] is a table, self[x][y] is a table, etc.
					-- thus, gaining not only efficiency but convenience when you are using it
					-- over and over in a variety of functions.
					-- also, if you want to have a buffer for something larger than the screen
					-- size, i. e. a map that is larger than the screen, but only part of it will
					-- be shown on the screen at any given time, like the pos implementation in this
					-- example buffer.
					self[x + self.pos[1]][y + self.pos[1]] = {back, color, text}
				end;
				get_pixel = function(self, x, y)
					-- No need to check for tables again, gaining efficiency
					return unpack(self[x + self.pos[1]][y + self.pos[2]])
				end;
				draw = function(self) -- uses get_pixel
					local max_x, max_y = term.getSize()
					for x = 1, max_x do
						for y = 1, max_y do
							term.setCursorPos(x, y)
							local pixel = {self:get_pixel(x, y)}
							term.setBackgroundColor(pixel[1] or colors.black)
							term.setTextColor(pixel[2] or colors.white)
							term.write(pixel[3] or "")
						end
					end
				end;
				write = function(self, x, y, text, back, color) -- uses set_pixel
					for i = x, #text do
						self:set_pixel(i, y, back, color, text:sub(i - x + 1, i - x + 1))
					end
				end;
				shift = function(self, x_shift, y_shift)
					self.pos = {self.pos[1] + x_shift, self.pos[2] + y_shift}
				end;
			},
			{
				__index = index(3);
			}
		)
	end;
}

Edit: Whew, that took sometime lol, hope it helped :)/>.
Edited on 05 December 2013 - 08:54 PM
oeed #4
Posted 06 December 2013 - 05:15 AM
Wait, so what does this do?
What's the advantage of doing this over normal tables?
You can change the depth of the table, ex:

-- normal table (depth 1)
local t = {}
t[1][2][3] = 5 -- error
-- depth 3 table
local t = setmetatable({}, {__index = index(3)})
t[1][2][3] = 5 -- no error

It is most useful in situations where you are mapping something. For instance, let's say you're creating a buffer, you could do this:

local buffer = {
	new = function()
		return setmetatable(
			{
				local pos = {0, 0}
				set_pixel = function(self, x, y, back, color, text)
					-- no need to check to see if self[x] is a table, self[x][y] is a table, etc.
					-- thus, gaining not only efficiency but convenience when you are using it
					-- over and over in a variety of functions.
					-- also, if you want to have a buffer for something larger than the screen
					-- size, i. e. a map that is larger than the screen, but only part of it will
					-- be shown on the screen at any given time, like the pos implementation in this
					-- example buffer.
					self[x + self.pos[1]][y + self.pos[1]] = {back, color, text}
				end;
				get_pixel = function(self, x, y)
					-- No need to check for tables again, gaining efficiency
					return unpack(self[x + self.pos[1]][y + self.pos[2]])
				end;
				draw = function(self) -- uses get_pixel
					local max_x, max_y = term.getSize()
					for x = 1, max_x do
						for y = 1, max_y do
							term.setCursorPos(x, y)
							local pixel = {self:get_pixel(x, y)}
							term.setBackgroundColor(pixel[1] or colors.black)
							term.setTextColor(pixel[2] or colors.white)
							term.write(pixel[3] or "")
						end
					end
				end;
				write = function(self, x, y, text, back, color) -- uses set_pixel
					for i = x, #text do
						self:set_pixel(i, y, back, color, text:sub(i - x + 1, i - x + 1))
					end
				end;
				shift = function(self, x_shift, y_shift)
					self.pos = {self.pos[1] + x_shift, self.pos[2] + y_shift}
				end;
			},
			{
				__index = index(3);
			}
		)
	end;
}

Edit: Whew, that took sometime lol, hope it helped :)/>.

Oh I see. Seems rather useful, I shall take a further look.