Commit 9602342b authored by Kirinn's avatar Kirinn

Lift serialisation buffer size from the saved buffer

parent 667e02e0
......@@ -51,8 +51,8 @@ interface
uses mccommon, sysutils;
procedure LoadVarState(poku : pointer);
procedure SaveVarState(var poku : pointer);
procedure LoadVarState(inbuf : pointer; bufbytes : dword);
function SaveVarState(var outbuf : pointer) : dword;
function GetVarType(const varnamu : string) : byte;
procedure SetNumVar(const varnamu : string; num : longint; sudo : boolean = FALSE);
function GetNumVar(const varnamu : string) : longint;
......@@ -186,6 +186,7 @@ end;
procedure DelStrVar(num : dword);
var poku : pointer;
i : dword;
begin
setlength(strvar[num].txt, 0);
if num = strvarcount - 1 then begin
......@@ -199,8 +200,8 @@ begin
// This only happens if a script keeps switching same named variables between number and string types, which you
// shouldn't be doing anyway.
poku := NIL;
SaveVarState(poku);
LoadVarState(poku); // loadstate sets danglies to 0
i := SaveVarState(poku);
LoadVarState(poku, i); // loadstate sets danglies to 0
freemem(poku); poku := NIL;
end;
end;
......@@ -210,6 +211,7 @@ function AddVar(const varnamu : string; typenum : byte; sudo : boolean) : dword;
// write-protected and sudo is not set.
// Returns the bucket number where the variable can be found topmost.
var poku : pointer;
i : dword;
function NewStrVar : dword;
// Adds a new slot to the string var array, returns the slot number.
......@@ -252,9 +254,9 @@ begin
// a slight delay as all existing variables are redistributed.
if (addbucketsautomatically) and (length(bucket[AddVar].content) >= 80) then begin
poku := NIL;
SaveVarState(poku);
inc(dword((poku + 4)^), 4); // poke a bigger bucket count directly in
LoadVarState(poku);
i := SaveVarState(poku);
inc(dword(poku^), 4); // poke a bigger bucket count directly in
LoadVarState(poku, i);
freemem(poku); poku := NIL;
// Find the new bucket this variable will go in.
AddVar := FindVar(varnamu) and $7FFFFFFF;
......@@ -280,7 +282,7 @@ begin
end;
end;
procedure LoadVarState(poku : pointer);
procedure LoadVarState(inbuf : pointer; bufbytes : dword);
// The input variable must be a pointer to a packed snapshot created by the above SaveState procedure. The snapshot is
// extracted over existing variable data, including overwriting the bucket count.
// If the current number of languages is fewer than the languages in the snapshot, the extra language string variables are
......@@ -292,12 +294,11 @@ var readp, endp : pointer;
savedbuckets, numstrings, savedlanguages : dword;
begin
// Safeties, read the header.
if poku = NIL then raise Exception.create('LoadVarState: tried to load null');
i := dword(poku^);
if i < 16 then raise Exception.create('LoadVarState: state too small, corrupted?');
if inbuf = NIL then raise Exception.create('LoadVarState: tried to load null');
if bufbytes < 12 then raise Exception.create('LoadVarState: state too small, corrupted?');
readp := poku + 4;
endp := poku + i;
readp := inbuf;
endp := inbuf + bufbytes;
savedbuckets := dword(readp^); inc(readp, 4);
addbucketsautomatically := (savedbuckets and $80000000) <> 0;
savedbuckets := savedbuckets and $7FFFFFFF;
......@@ -371,12 +372,12 @@ begin
end;
end;
procedure SaveVarState(var poku : pointer);
function SaveVarState(var outbuf : pointer) : dword;
// The input variable must be a null pointer. A packed snapshot of the current variable state is placed there.
// Returns the number of bytes used for the snapshot.
// The caller is responsible for freeing the buffer, and may want to compress the buffer if saving in a file.
//
// Snapshot content:
// dword : byte size of used memory excluding this dword
// dwords : bucketcount, numstrings, numlanguages (except bucketcount's top bit is addbucketsautomatically)
// array of...
// byte : variable type
......@@ -386,13 +387,13 @@ procedure SaveVarState(var poku : pointer);
// if string then array[numlanguages] of...
// dword : UTF-8 string byte length
// array[length] of bytes : UTF-8 string content
var i, j, k, l, numstrings, memused : dword;
var i, j, k, l, numstrings : dword;
writep : pointer;
begin
Assert(poku = NIL);
Assert(outbuf = NIL);
// Calculate the memory needed.
numstrings := 0;
memused := 16; // header: 4 dwords
result := 12; // header: 3 dwords
i := bucketcount;
while i <> 0 do begin
dec(i);
......@@ -402,24 +403,23 @@ begin
k := bucket[i].content[j].varnum;
if bucket[i].content[j].vartype = VARMON_VARTYPEINT then begin
// numeric variable!
inc(memused, 7 + dword(length(bucket[i].content[j].namu)));
inc(result, 7 + dword(length(bucket[i].content[j].namu)));
end
else begin
// string variable!
inc(memused, 3 + dword(length(bucket[i].content[j].namu)) + 4 * numlanguages);
inc(result, 3 + dword(length(bucket[i].content[j].namu)) + 4 * numlanguages);
for l := numlanguages - 1 downto 0 do
inc(memused, dword(length(strvar[k].txt[l])));
inc(result, dword(length(strvar[k].txt[l])));
inc(numstrings);
end;
end;
end;
// Reserve the memory... caller is responsible for freeing it.
getmem(poku, memused);
writep := poku;
getmem(outbuf, result);
writep := outbuf;
// Write the header.
dword(writep^) := memused; inc(writep, 4);
i := bucketcount;
if addbucketsautomatically then i := i or $80000000;
dword(writep^) := i; inc(writep, 4);
......@@ -543,7 +543,7 @@ procedure GetStrVar(const varnamu : string; language : byte);
// stash is not changed. Use this if you only need one language specifically.
// If the given variable doesn't exist, places an empty string. If the language is out of bounds, substitutes with language 0.
// If the requested variable is a number, converts it to a string.
var i, j, l : dword;
var i, j : dword;
begin
i := FindVar(upcase(varnamu));
if i >= $80000000 then begin
......@@ -588,14 +588,15 @@ procedure SetNumBuckets(const newbuckets : dword);
// a larger number of buckets will be faster. If a script uses few variables, a small number of buckets keeps the memory
// overhead low.
var poku : pointer;
i : dword;
begin
if newbuckets = bucketcount then exit;
if (newbuckets = 0) or (newbuckets > VARMON_MAXBUCKETS) then
raise Exception.create('Bad new bucketcount, must be 1..' + strdec(VARMON_MAXBUCKETS));
poku := NIL;
SaveVarState(poku);
dword((poku + 4)^) := newbuckets; // poke bucketcount in saved structure
LoadVarState(poku);
i := SaveVarState(poku);
dword(poku^) := newbuckets; // poke bucketcount in saved structure
LoadVarState(poku, i);
freemem(poku); poku := NIL;
// Manually setting the number of buckets disables automatic bucket adding.
addbucketsautomatically := FALSE;
......
......@@ -9,7 +9,7 @@ uses mcvarmon, mccommon;
var strutsi : UTF8string;
poku, poku2 : pointer;
i : dword;
i, size1, size2 : dword;
begin
poku := NIL;
......@@ -42,7 +42,7 @@ begin
// Save current and wipe. Should be duly wiped.
writeln(':: save1 ::');
SaveVarState(poku);
size1 := SaveVarState(poku);
writeln(':: init1 ::');
VarmonInit(0, 0);
Assert(CountStrVars = 0);
......@@ -58,11 +58,11 @@ begin
SetNumVar('k', 99, TRUE);
Assert(CountStrVars = 2);
writeln(':: save2 ::');
SaveVarState(poku2);
size2 := SaveVarState(poku2);
// Load state. The new variables should be gone, and the previous present.
writeln(':: load1 ::');
LoadVarState(poku);
LoadVarState(poku, size1);
Assert(GetVarType('b') = VARMON_VARTYPENULL);
Assert(GetVarType('c') = VARMON_VARTYPENULL);
Assert(GetVarType('j') = VARMON_VARTYPENULL);
......@@ -77,7 +77,7 @@ begin
// Load state again. New variables should be present.
writeln(':: load2 ::');
LoadVarState(poku2);
LoadVarState(poku2, size2);
Assert(GetVarType('b') = VARMON_VARTYPESTR);
Assert(GetVarType('c') = VARMON_VARTYPESTR);
Assert(GetVarType('j') = VARMON_VARTYPEINT);
......@@ -132,21 +132,21 @@ begin
for i := 0 to 2 do stringstash[i] := strdec(i);
SetStrVar('a');
freemem(poku); poku := NIL;
SaveVarState(poku);
size1 := SaveVarState(poku);
VarmonInit(3, 1);
LoadVarState(poku);
LoadVarState(poku, size1);
GetStrVar('a');
for i := 0 to 2 do Assert(stringstash[i] = strdec(i));
// Loading with a different current language count should work.
VarmonInit(2, 1);
LoadVarState(poku);
LoadVarState(poku, size1);
GetStrVar('a');
Assert(length(stringstash) = 2);
for i := 0 to 1 do Assert(stringstash[i] = strdec(i));
VarmonInit(4, 1);
LoadVarState(poku);
LoadVarState(poku, size1);
GetStrVar('a');
Assert(length(stringstash) = 4);
for i := 0 to 2 do Assert(stringstash[i] = strdec(i));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment