mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-23 14:01:37 +00:00
- Introduced a comprehensive rewrite of the matching algorithm, replacing the previous multi-pass approach with a recursive change-count scoring function and greedy assignment strategy. - Updated the `hydrate.lua` and `matching.lua` files to utilize the new algorithm, enhancing the efficiency of instance matching during hydration. - Documented the new algorithm's structure, including fast-paths for Ref pins and (Name, ClassName) grouping, which significantly improve matching accuracy and performance. - Ensured that the new implementation maintains compatibility with existing systems while providing a more robust solution for handling ambiguous instances. These changes enhance the clarity and efficiency of the reconciliation process, paving the way for improved project management and user experience.
117 lines
4.7 KiB
Text
117 lines
4.7 KiB
Text
--!strict
|
|
--!optimize 2
|
|
--!native
|
|
|
|
local function XXH32(Message: buffer, Seed: number?): number
|
|
local PRIME_1, PRIME_1_HIGH, PRIME_1_LOW = 0x9e3779B1, 40503, 31153
|
|
local PRIME_2, PRIME_2_HIGH, PRIME_2_LOW = 0x85ebca77, 34283, 51831
|
|
local PRIME_3_HIGH, PRIME_3_LOW = 49842, 44605
|
|
local PRIME_4_HIGH, PRIME_4_LOW = 10196, 60207
|
|
local PRIME_5, PRIME_5_HIGH, PRIME_5_LOW = 0x165667b1, 5718, 26545
|
|
|
|
local UsedSeed = Seed or 0
|
|
local MessageLength = buffer.len(Message)
|
|
local Digest: number
|
|
local CurrentOffset = 0
|
|
|
|
if MessageLength >= 16 then
|
|
local Accumulator1 = UsedSeed + PRIME_1 + PRIME_2
|
|
local Accumulator2 = UsedSeed + PRIME_2
|
|
local Accumulator3 = UsedSeed
|
|
local Accumulator4 = UsedSeed - PRIME_1
|
|
|
|
while CurrentOffset <= MessageLength - 16 do
|
|
local Word1 = buffer.readu32(Message, CurrentOffset)
|
|
local Word2 = buffer.readu32(Message, CurrentOffset + 4)
|
|
local Word3 = buffer.readu32(Message, CurrentOffset + 8)
|
|
local Word4 = buffer.readu32(Message, CurrentOffset + 12)
|
|
|
|
local AHigh1, ALow1 = bit32.rshift(Word1, 16), bit32.band(Word1, 65535)
|
|
local Mult1 = bit32.lshift((AHigh1 * PRIME_2_LOW) + (ALow1 * PRIME_2_HIGH), 16) + (ALow1 * PRIME_2_LOW)
|
|
|
|
local Temp1 = bit32.lrotate(Accumulator1 + Mult1, 13)
|
|
local AHigh1_2, ALow1_2 = bit32.rshift(Temp1, 16), bit32.band(Temp1, 65535)
|
|
Accumulator1 = bit32.lshift((AHigh1_2 * PRIME_1_LOW) + (ALow1_2 * PRIME_1_HIGH), 16)
|
|
+ (ALow1_2 * PRIME_1_LOW)
|
|
|
|
local AHigh2, ALow2 = bit32.rshift(Word2, 16), bit32.band(Word2, 65535)
|
|
local Mult2 = bit32.lshift((AHigh2 * PRIME_2_LOW) + (ALow2 * PRIME_2_HIGH), 16) + (ALow2 * PRIME_2_LOW)
|
|
|
|
local Temp2 = bit32.lrotate(Accumulator2 + Mult2, 13)
|
|
local AHigh2_2, ALow2_2 = bit32.rshift(Temp2, 16), bit32.band(Temp2, 65535)
|
|
Accumulator2 = bit32.lshift((AHigh2_2 * PRIME_1_LOW) + (ALow2_2 * PRIME_1_HIGH), 16)
|
|
+ (ALow2_2 * PRIME_1_LOW)
|
|
|
|
local AHigh3, ALow3 = bit32.rshift(Word3, 16), bit32.band(Word3, 65535)
|
|
local Mult3 = bit32.lshift((AHigh3 * PRIME_2_LOW) + (ALow3 * PRIME_2_HIGH), 16) + (ALow3 * PRIME_2_LOW)
|
|
|
|
local Temp3 = bit32.lrotate(Accumulator3 + Mult3, 13)
|
|
local AHigh3_2, ALow3_2 = bit32.rshift(Temp3, 16), bit32.band(Temp3, 65535)
|
|
Accumulator3 = bit32.lshift((AHigh3_2 * PRIME_1_LOW) + (ALow3_2 * PRIME_1_HIGH), 16)
|
|
+ (ALow3_2 * PRIME_1_LOW)
|
|
|
|
local AHigh4, ALow4 = bit32.rshift(Word4, 16), bit32.band(Word4, 65535)
|
|
local Mult4 = bit32.lshift((AHigh4 * PRIME_2_LOW) + (ALow4 * PRIME_2_HIGH), 16) + (ALow4 * PRIME_2_LOW)
|
|
|
|
local Temp4 = bit32.lrotate(Accumulator4 + Mult4, 13)
|
|
local AHigh4_2, ALow4_2 = bit32.rshift(Temp4, 16), bit32.band(Temp4, 65535)
|
|
Accumulator4 = bit32.lshift((AHigh4_2 * PRIME_1_LOW) + (ALow4_2 * PRIME_1_HIGH), 16)
|
|
+ (ALow4_2 * PRIME_1_LOW)
|
|
|
|
CurrentOffset += 16
|
|
end
|
|
|
|
Digest = bit32.lrotate(Accumulator1, 1)
|
|
+ bit32.lrotate(Accumulator2, 7)
|
|
+ bit32.lrotate(Accumulator3, 12)
|
|
+ bit32.lrotate(Accumulator4, 18)
|
|
else
|
|
Digest = UsedSeed + PRIME_5
|
|
end
|
|
|
|
Digest += MessageLength
|
|
|
|
while CurrentOffset <= MessageLength - 4 do
|
|
if CurrentOffset + 4 <= buffer.len(Message) then
|
|
local Word = buffer.readu32(Message, CurrentOffset)
|
|
|
|
local AHigh_w, ALow_w = bit32.rshift(Word, 16), bit32.band(Word, 65535)
|
|
local Mult_w = bit32.lshift((AHigh_w * PRIME_3_LOW) + (ALow_w * PRIME_3_HIGH), 16) + (ALow_w * PRIME_3_LOW)
|
|
|
|
Digest += Mult_w
|
|
|
|
local Rotated = bit32.lrotate(Digest, 17)
|
|
local AHigh_r, ALow_r = bit32.rshift(Rotated, 16), bit32.band(Rotated, 65535)
|
|
Digest = bit32.lshift((AHigh_r * PRIME_4_LOW) + (ALow_r * PRIME_4_HIGH), 16) + (ALow_r * PRIME_4_LOW)
|
|
end
|
|
CurrentOffset += 4
|
|
end
|
|
|
|
while CurrentOffset < MessageLength do
|
|
if CurrentOffset < buffer.len(Message) then
|
|
local ByteValue = buffer.readu8(Message, CurrentOffset)
|
|
|
|
local AHigh_b, ALow_b = bit32.rshift(ByteValue, 16), bit32.band(ByteValue, 65535)
|
|
local Mult_b = bit32.lshift((AHigh_b * PRIME_5_LOW) + (ALow_b * PRIME_5_HIGH), 16) + (ALow_b * PRIME_5_LOW)
|
|
|
|
Digest += Mult_b
|
|
|
|
local Rotated_b = bit32.lrotate(Digest, 11)
|
|
local AHigh_rb, ALow_rb = bit32.rshift(Rotated_b, 16), bit32.band(Rotated_b, 65535)
|
|
Digest = bit32.lshift((AHigh_rb * PRIME_1_LOW) + (ALow_rb * PRIME_1_HIGH), 16) + (ALow_rb * PRIME_1_LOW)
|
|
end
|
|
CurrentOffset += 1
|
|
end
|
|
|
|
local XorResult1 = bit32.bxor(Digest, bit32.rshift(Digest, 15))
|
|
local AHigh_f1, ALow_f1 = bit32.rshift(XorResult1, 16), bit32.band(XorResult1, 65535)
|
|
Digest = bit32.lshift((AHigh_f1 * PRIME_2_LOW) + (ALow_f1 * PRIME_2_HIGH), 16) + (ALow_f1 * PRIME_2_LOW)
|
|
|
|
local XorResult2 = bit32.bxor(Digest, bit32.rshift(Digest, 13))
|
|
local AHigh_f2, ALow_f2 = bit32.rshift(XorResult2, 16), bit32.band(XorResult2, 65535)
|
|
Digest = bit32.lshift((AHigh_f2 * PRIME_3_LOW) + (ALow_f2 * PRIME_3_HIGH), 16) + (ALow_f2 * PRIME_3_LOW)
|
|
|
|
return bit32.bxor(Digest, bit32.rshift(Digest, 16))
|
|
end
|
|
|
|
return XXH32
|