Quantcast

Reworked caching

Kevin Lyles [12-14-09 - 09:32]
Reworked caching
Filename
WeightsWatcher.lua
diff --git a/WeightsWatcher.lua b/WeightsWatcher.lua
index 5c1da76..242d327 100644
--- a/WeightsWatcher.lua
+++ b/WeightsWatcher.lua
@@ -4,10 +4,152 @@ end

 currentHooks = {}

-ww_itemCache = {}
-ww_bareItemCache = {}
-ww_weightCache = {}
-ww_weightIdealCache = {}
+ww_bareItemCacheMetatable = {
+	__index = function(tbl, key)
+		tbl[key] = {WeightsWatcher:getItemStats(key)}
+		return tbl[key]
+	end,
+}
+
+ww_itemCacheMetatable = {
+	__index = function(tbl, key)
+		local gemStats, socketBonusActive
+		local bareLink, gems = splitItemLink(key)
+		local normalStats, sockets, socketBonusStat = unpack(ww_bareItemCache[bareLink])
+
+		gemStats = WeightsWatcher:getGemStats(gems)
+
+		-- Removes gems in crafted sockets from consideration
+		for i = #(sockets) + 1, #(gemStats) do
+			table.remove(gemStats)
+		end
+
+		if #(sockets) > 0 then
+			socketBonusActive = true
+			for i = 1, #(sockets) do
+				if not gemStats[i] or not WeightsWatcher:matchesSocket(gemStats[i][1], sockets[i]) then
+					socketBonusActive = false
+					break
+				end
+			end
+		else
+			socketBonusActive = false
+		end
+
+		tbl[key] = {socketBonusActive, gemStats}
+		return tbl[key]
+	end,
+}
+
+ww_weightCacheWeightMetatable = {
+	__index = function(tbl, key)
+		local normalStats, socketBonusActive, socketBonusStat, gemStats
+		local bareLink = splitItemLink(key)
+		normalStats, _, socketBonusStat = unpack(ww_bareItemCache[bareLink])
+		socketBonusActive, gemStats = unpack(ww_itemCache[key])
+
+		tbl[key] = WeightsWatcher:calculateWeight(normalStats, socketBonusActive, socketBonusStat, gemStats, tbl.weight)
+		return tbl[key]
+	end,
+}
+
+ww_weightCacheClassMetatable = {
+	__index = function(tbl, key)
+		tbl[key] = setmetatable({}, ww_weightCacheWeightMetatable)
+		tbl[key].weight = tbl.class[key]
+		return tbl[key]
+	end,
+}
+
+ww_weightCacheMetatable = {
+	__index = function(tbl, key)
+		tbl[key] = setmetatable({}, ww_weightCacheClassMetatable)
+		tbl[key].class = ww_vars.weightsList[key]
+		return tbl[key]
+	end,
+}
+
+ww_weightIdealCacheWeightMetatable = {
+	__index = function(tbl, key)
+		if key == "weight" then
+			return nil
+		elseif key == "bestGems" then
+			local redScore, yellowScore, blueScore, overallScore
+			local bestGems = {}
+
+			bestGems.Red, redScore = WeightsWatcher:bestGemForSocket("Red", tbl.weight, ww_vars.options.gemQualityLimit)
+			bestGems.Yellow, yellowScore = WeightsWatcher:bestGemForSocket("Yellow", tbl.weight, ww_vars.options.gemQualityLimit)
+			bestGems.Blue, blueScore = WeightsWatcher:bestGemForSocket("Blue", tbl.weight, ww_vars.options.gemQualityLimit)
+			bestGems.Meta = WeightsWatcher:bestGemForSocket("Meta", tbl.weight, ww_vars.options.gemQualityLimit)
+			bestGems.overall = bestGems.Red
+			overallScore = redScore
+			if blueScore > overallScore then
+				bestGems.overall = bestGems.Blue
+				overallScore = blueScore
+			end
+			if yellowScore > overallScore then
+				bestGems.overall = bestGems.Yellow
+			end
+			tbl.bestGems = bestGems
+			return bestGems
+		end
+		local gemId, gemIdIgnoreSocket, weightVal, weightValIgnoreSockets, bestGems, bestGemsIgnoreSocket
+		local normalStats, sockets, socketBonusStat = unpack(ww_bareItemCache[key])
+
+		bestGems = {}
+		bestGemsIgnoreSocket = {}
+		for _, color in pairs(sockets) do
+			gemId = tbl.bestGems[color]
+			if gemId ~= 0 then
+				table.insert(bestGems, gemId)
+			end
+			if breakSocketColors then
+				gemIdIgnoreSocket = tbl.bestGems.overall
+				if gemIdIgnoreSocket ~= 0 then
+					table.insert(bestGemsIgnoreSocket, gemIdIgnoreSocket)
+				end
+			end
+		end
+		gemStats = WeightsWatcher:getGemStats(bestGems)
+		weightVal = WeightsWatcher:calculateWeight(normalStats, true, socketBonusStat, gemStats, tbl.weight)
+		if breakSocketColors then
+			gemStatsIgnoreSockets = WeightsWatcher:getGemStats(bestGemsIgnoreSocket)
+			weightValIgnoreSockets = WeightsWatcher:calculateWeight(normalStats, false, socketBonusStat, gemStatsIgnoreSockets, tbl.weight)
+
+			if weightVal < weightValIgnoreSockets then
+				weightVal = weightValIgnoreSockets
+				gemStats = gemStatsIgnoreSockets
+			end
+		end
+
+		tbl[key] = {
+			gemStats = gemStats,
+			score = weightVal,
+		}
+		return tbl[key]
+	end,
+}
+
+ww_weightIdealCacheClassMetatable = {
+	__index = function(tbl, key)
+		tbl[key] = setmetatable({}, ww_weightIdealCacheWeightMetatable)
+		tbl[key].weight = tbl.class[key]
+		return tbl[key]
+	end,
+}
+
+ww_weightIdealCacheMetatable = {
+	__index = function(tbl, key)
+		tbl[key] = setmetatable({}, ww_weightIdealCacheClassMetatable)
+		tbl[key].class = ww_vars.weightsList[key]
+		return tbl[key]
+	end,
+}
+
+ww_bareItemCache = setmetatable({}, ww_bareItemCacheMetatable)
+ww_itemCache = setmetatable({}, ww_itemCacheMetatable)
+ww_weightCache = setmetatable({}, ww_weightCacheMetatable)
+ww_weightIdealCache = setmetatable({}, ww_weightIdealCacheMetatable)

 function WeightsWatcher:OnInitialize()
 	local tempVars
@@ -138,145 +280,18 @@ function WeightsWatcher:OnDisable()
 	currentHooks = {}
 end

-function WeightsWatcher:cacheItemStats(link)
-	-- Stats: normal stats, sockets, socket bonus, gem-given stats, whether the socket bonus is active, ideal gems, ideal gems ignoring socket bonuses
-	local normalStats, sockets, socketBonusStat, socketBonusActive, gemStats
-
-	_, itemId, _, gemId1, gemId2, gemId3, gemId4, suffixId, uniqueId, linkLevel = strsplit(":", link)
+function splitItemLink(link)
+	local _, itemId, _, gemId1, gemId2, gemId3, gemId4, suffixId, uniqueId, linkLevel = strsplit(":", link)
 	-- Strip color codes
 	linkLevel = strsplit("|", linkLevel)
 	bareLink = strjoin(":", "item", itemId, "0:0:0:0:0", suffixId, uniqueId, linkLevel)

-	if ww_bareItemCache[bareLink] then
-		normalStats, sockets, socketBonusStat = unpack(ww_bareItemCache[bareLink])
-	else
-		normalStats, sockets, socketBonusStat = WeightsWatcher:getItemStats(bareLink)
-		ww_bareItemCache[bareLink] = {normalStats, sockets, socketBonusStat}
-	end
-
-	if ww_itemCache[link] then
-		socketBonusActive, gemStats = unpack(ww_itemCache[link])
-	else
-		gemStats = WeightsWatcher:getGemStats({gemId1, gemId2, gemId3, gemId4})
-
-		-- Removes gems in crafted sockets from consideration
-		for i = #(sockets) + 1, #(gemStats) do
-			table.remove(gemStats)
-		end
-
-		if #(sockets) > 0 then
-			socketBonusActive = true
-			for i = 1, #(sockets) do
-				if not gemStats[i] or not WeightsWatcher:matchesSocket(gemStats[i][1], sockets[i]) then
-					socketBonusActive = false
-					break
-				end
-			end
-		else
-			socketBonusActive = false
-		end
-
-		ww_itemCache[link] = {socketBonusActive, gemStats}
-	end
-
-	for _, class in ipairs(ww_charVars.activeWeights) do
-		if ww_vars.weightsList[class] then
-			if not ww_weightCache[class] then
-				ww_weightCache[class] = {}
-			end
-			for _, weight in pairs(ww_charVars.activeWeights[class]) do
-				if ww_vars.weightsList[class][weight] then
-					if not ww_weightCache[class][weight] then
-						ww_weightCache[class][weight] = {}
-					end
-					if not ww_weightCache[class][weight][link] then
-						ww_weightCache[class][weight][link] = WeightsWatcher:calculateWeight(normalStats, socketBonusActive, socketBonusStat, gemStats, ww_vars.weightsList[class][weight])
-					end
-				end
-			end
-		end
-	end
-
-	if #(sockets) > 0 then
-		for _, class in ipairs(ww_charVars.activeWeights) do
-			if ww_vars.weightsList[class] then
-				if not ww_weightIdealCache[class] then
-					ww_weightIdealCache[class] = {}
-				end
-				for _, weight in pairs(ww_charVars.activeWeights[class]) do
-					if ww_vars.weightsList[class][weight] then
-						local socketBonusWeight = ww_vars.weightsList[class][weight][string.lower(socketBonusStat[1])]
-						local breakSocketColors = ww_vars.options.breakSocketColors or (not ww_vars.options.neverBreakSocketColors and (not socketBonusWeight or socketBonusWeight <= 0))
-
-						if not ww_weightIdealCache[class][weight] then
-							ww_weightIdealCache[class][weight] = {}
-						end
-
-						if not ww_weightIdealCache[class][weight].bestGems then
-							local redScore, yellowScore, blueScore, overallScore
-							local bestGems = {}
-
-							bestGems.Red, redScore = WeightsWatcher:bestGemForSocket("Red", ww_vars.weightsList[class][weight], ww_vars.options.gemQualityLimit)
-							bestGems.Yellow, yellowScore = WeightsWatcher:bestGemForSocket("Yellow", ww_vars.weightsList[class][weight], ww_vars.options.gemQualityLimit)
-							bestGems.Blue, blueScore = WeightsWatcher:bestGemForSocket("Blue", ww_vars.weightsList[class][weight], ww_vars.options.gemQualityLimit)
-							bestGems.Meta = WeightsWatcher:bestGemForSocket("Meta", ww_vars.weightsList[class][weight], ww_vars.options.gemQualityLimit)
-							bestGems.overall = bestGems.Red
-							overallScore = redScore
-							if blueScore > overallScore then
-								bestGems.overall = bestGems.Blue
-								overallScore = blueScore
-							end
-							if yellowScore > overallScore then
-								bestGems.overall = bestGems.Yellow
-							end
-							ww_weightIdealCache[class][weight].bestGems = bestGems
-						end
-
-						if not ww_weightIdealCache[class][weight][bareLink] then
-							local gemId, gemIdIgnoreSocket, weightVal, weightValIgnoreSockets, bestGems, bestGemsIgnoreSocket
-
-							ww_weightIdealCache[class][weight][bareLink] = {}
-
-							bestGems = {}
-							bestGemsIgnoreSocket = {}
-							for _, color in pairs(sockets) do
-								gemId = ww_weightIdealCache[class][weight].bestGems[color]
-								if gemId ~= 0 then
-									table.insert(bestGems, gemId)
-								end
-								if breakSocketColors then
-									gemIdIgnoreSocket = ww_weightIdealCache[class][weight].bestGems.overall
-									if gemIdIgnoreSocket ~= 0 then
-										table.insert(bestGemsIgnoreSocket, gemIdIgnoreSocket)
-									end
-								end
-							end
-							gemStats = WeightsWatcher:getGemStats(bestGems)
-							weightVal = WeightsWatcher:calculateWeight(normalStats, true, socketBonusStat, gemStats, ww_vars.weightsList[class][weight])
-							if breakSocketColors then
-								gemStatsIgnoreSockets = WeightsWatcher:getGemStats(bestGemsIgnoreSocket)
-								weightValIgnoreSockets = WeightsWatcher:calculateWeight(normalStats, false, socketBonusStat, gemStatsIgnoreSockets, ww_vars.weightsList[class][weight])
-
-								if weightVal < weightValIgnoreSockets then
-									weightVal = weightValIgnoreSockets
-									gemStats = gemStatsIgnoreSockets
-								end
-							end
-							ww_weightIdealCache[class][weight][bareLink].gemStats = gemStats
-							ww_weightIdealCache[class][weight][bareLink].score = weightVal
-						end
-					end
-				end
-			end
-		end
-	end
-
-	return bareLink
+	return bareLink, {gemId1, gemId2, gemId3, gemId4}
 end

 function WeightsWatcher:displayItemStats(tooltip, ttname)
 	local link, bareLink, itemType, stackSize, sockets, gemStats
-	local stat, value, string
+	local stat, value, str
 	local _, playerClass = UnitClass("player")

 	_, link = tooltip:GetItem()
@@ -286,7 +301,7 @@ function WeightsWatcher:displayItemStats(tooltip, ttname)

 	_, _, _, _, _, itemType, _, stackSize = GetItemInfo(link)
 	if (IsEquippableItem(link) and itemType ~= "Container" and itemType ~= "Quiver") or (itemType == "Gem" and stackSize == 1) or (itemType == "Consumable") or (itemType == "Recipe") then
-		bareLink = WeightsWatcher:cacheItemStats(link)
+		bareLink = splitItemLink(link)

 		if keyDetectors[ww_vars.options.tooltip.showWeights]() then
 			tooltip:AddLine("Current Weights:")
@@ -294,11 +309,11 @@ function WeightsWatcher:displayItemStats(tooltip, ttname)
 				if ww_vars.weightsList[class] then
 					for _, weight in pairs(ww_charVars.activeWeights[class]) do
 						if ww_vars.weightsList[class][weight] then
-							string = "  " .. weight
+							str = "  " .. weight
 							if ww_vars.options.tooltip.showClassNames == "Always" or (ww_vars.options.tooltip.showClassNames == "Others" and class ~= playerClass) then
-								string = string .. " - " .. classNames[class]
+								str = str .. " - " .. classNames[class]
 							end
-							tooltip:AddDoubleLine(string, string.format("%.3f", ww_weightCache[class][weight][link]))
+							tooltip:AddDoubleLine(str, string.format("%.3f", ww_weightCache[class][weight][link]))
 						end
 					end
 				end
@@ -313,11 +328,11 @@ function WeightsWatcher:displayItemStats(tooltip, ttname)
 						if ww_vars.weightsList[class] then
 							for _, weight in pairs(ww_charVars.activeWeights[class]) do
 								if ww_vars.weightsList[class][weight] then
-									string = "  " .. weight
+									str = "  " .. weight
 									if ww_vars.options.tooltip.showClassNames == "Always" or (ww_vars.options.tooltip.showClassNames == "Others" and class ~= playerClass) then
-										string = string .. " - " .. classNames[class]
+										str = str .. " - " .. classNames[class]
 									end
-									tooltip:AddDoubleLine(string, string.format("%.3f", ww_weightIdealCache[class][weight][bareLink].score))
+									tooltip:AddDoubleLine(str, string.format("%.3f", ww_weightIdealCache[class][weight][bareLink].score))
 									if keyDetectors[ww_vars.options.tooltip.showIdealGems]() then
 										gemStats = ww_weightIdealCache[class][weight][bareLink].gemStats
 										for _, gem in ipairs(gemStats) do