-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathSmartTables.lua
191 lines (154 loc) · 4.33 KB
/
SmartTables.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
-- Copyright (c) 2020 Jurian Vierbergen, Some Rights Reserved
-- subjected to the MPL-2.0 License
local module = table.create(3,0)
local Initialization = table.create(2,0)
local Storage = table.create(0,0)
local Calls = table.create(0,0)
local HttpService = game:GetService("HttpService")
-- [[ internal functions ]]
-- functionalitites related to instance based keys
function Generate(Variable)
Storage[Variable] = HttpService:GenerateGUID(false)
return Storage[Variable]
end
function GetDebugId(Variable)
if Storage[Variable] then
return Storage[Variable]
end
end
-- metatable creation from template
function CreateMetaTable(self, _Call, _Value, TableName, Store, NotInit)
local meta = setmetatable({
__META__Internal_Value = _Value,
__META__TableName = rawget(self, "__META__TableName")
}, Initialization)
if NotInit then
self = DisposeMetaTable(self)
end
return meta
end
-- first occuring index finding
function LoopTablesForIndex(Table, Index)
local Value
Index = tostring(Index)
local function Loop(Table, Index)
if Value then return end
for i,v in pairs(Table) do
local index = tostring(i)
if typeof(i) == "Instance" then
local InstanceDebugId = GetDebugId(i)
if not InstanceDebugId then
index = Generate(i)
else
index = InstanceDebugId
end
end
if index:sub(1,8) == "__META__" then index = index:sub(9, #i) end
if index == Index then
Value = v
return
elseif index ~= Index and typeof(v) == "table" then
Loop(v, Index)
end
end
end
Loop(Table, Index)
return Value
end
-- new indexation from the outside
function ExternalLoopAndSet(Table, Index, Value)
for i,v in pairs(Table) do
if i == Index then
rawset(Table, i, Value)
return
elseif i ~= Index and typeof(v) == "table" then
ExternalLoopAndSet(Table[i], Index, Value)
end
end
end
function MetaMethodCheck(self, Name)
local Meta = getmetatable(self)
if Meta[Name] then
return function()
return Meta[Name](self)
end
end
end
function DisposeMetaTable(self)
for i,v in pairs(self) do
self[i] = nil
end
setmetatable(self, nil)
self = nil
end
-- Methods of the first occuring metatable (retrieved from .new(), they require some specific structured indexation)
function Initialization.__index(self, index, NotInit)
local M_ReturnValue = MetaMethodCheck(self, index)
if M_ReturnValue then
return M_ReturnValue
end
if typeof(index) == "Instance" then
local InstanceDebugId = GetDebugId(index)
index = (InstanceDebugId == nil) and Generate(index) or InstanceDebugId
end
local Value = LoopTablesForIndex(rawget(self, "__META__Internal_Value") or self, index)
if Value then
local LoadedTable = (rawget(self, "__META__Shared")) and rawget(Calls[rawget(self, "__META__TableName")], index) or nil
if LoadedTable then return LoadedTable end
if typeof(Value) == "table" then
return CreateMetaTable(self, index, Value, rawget(self, "__META__TableName"), false, NotInit)
else
return Value
end
end
end
function Initialization.getn(self)
local n = 0
for i,v in pairs(self.__META__Internal_Value) do
n += 1
end
return n
end
function Initialization.__newindex(self, index, value)
return ExternalLoopAndSet(self, index, value)
end
function Initialization.GetRaw(self)
return self["__META__Internal_Value"]
end
function Initialization.Dispose(self)
if Calls[self.__META__TableName] then
Calls[self.__META__TableName] = nil
end
DisposeMetaTable(self)
return nil
end
-- public functionalities from require
function module.new(Target, Shared, TargetName)
Shared = (Shared == nil or Shared == false) and false or (Shared == true) and true
TargetName = (TargetName == nil) and HttpService:GenerateGUID(false) or TargetName
local PsuedoTable = table.create(0, 0)
PsuedoTable["__META__Internal_Value"] = Target
for i,v in pairs(Target) do
local index = i
if typeof(i) == "Instance" then
index = Generate(i)
end
PsuedoTable["__META__" .. index] = v
end
PsuedoTable.__META__TableName = TargetName
PsuedoTable.__META__Shared = Shared
local Meta = setmetatable(PsuedoTable, Initialization)
if Shared then
Calls[TargetName] = table.create(0,0)
Calls[TargetName]["__METAINIT__"] = Meta
end
return Meta
end
function module.GetTable(Name)
if Name and Calls[Name] then
return Calls[Name].__METAINIT__
elseif not Name then
return Calls
end
end
return module