mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-13 07:57:52 +00:00
- Switched ACS world and global arrays to the TMap class instead of
TAutoGrowArray. A map can handle a wide range of key values better than an array. - Added a templated associative array class, TMap, that uses Lua's "chained scatter table with Brent's variation" algorithm. I had considered using hash_map until I discovered that it's not standard STL, and there are two major but incompatible implementations of it. So I rolled my own, and Lua seemed like a good place to go to for an efficient algorithm, since it makes heavy use of tables. SVN r513 (trunk)
This commit is contained in:
parent
a00bc159a1
commit
f48ad6c4c3
6 changed files with 663 additions and 129 deletions
|
@ -1,3 +1,16 @@
|
||||||
|
April 12, 2007
|
||||||
|
- Switched ACS world and global arrays to the TMap class instead of
|
||||||
|
TAutoGrowArray. A map can handle a wide range of key values better than
|
||||||
|
an array.
|
||||||
|
|
||||||
|
April 10, 2007
|
||||||
|
- Added a templated associative array class, TMap, that uses Lua's "chained
|
||||||
|
scatter table with Brent's variation" algorithm. I had considered using
|
||||||
|
hash_map until I discovered that it's not standard STL, and there are two
|
||||||
|
major but incompatible implementations of it. So I rolled my own, and Lua
|
||||||
|
seemed like a good place to go to for an efficient algorithm, since it
|
||||||
|
makes heavy use of tables.
|
||||||
|
|
||||||
March 28, 2007
|
March 28, 2007
|
||||||
- Fixed some const char * -> char * conversions flagged by GCC 4.2.0 in the
|
- Fixed some const char * -> char * conversions flagged by GCC 4.2.0 in the
|
||||||
Win32-specific code.
|
Win32-specific code.
|
||||||
|
|
139
src/g_game.cpp
139
src/g_game.cpp
|
@ -1553,6 +1553,33 @@ bool G_CheckSaveGameWads (PNGHandle *png, bool printwarn)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void WriteVars (FILE *file, SDWORD *vars, size_t count, DWORD id)
|
||||||
|
{
|
||||||
|
size_t i, j;
|
||||||
|
|
||||||
|
for (i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
if (vars[i] != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i < count)
|
||||||
|
{
|
||||||
|
// Find last non-zero var. Anything beyond the last stored variable
|
||||||
|
// will be zeroed at load time.
|
||||||
|
for (j = count-1; j > i; --j)
|
||||||
|
{
|
||||||
|
if (vars[j] != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
FPNGChunkArchive arc (file, id);
|
||||||
|
for (i = 0; i <= j; ++i)
|
||||||
|
{
|
||||||
|
DWORD var = vars[i];
|
||||||
|
arc << var;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void ReadVars (PNGHandle *png, SDWORD *vars, size_t count, DWORD id)
|
static void ReadVars (PNGHandle *png, SDWORD *vars, size_t count, DWORD id)
|
||||||
{
|
{
|
||||||
size_t len = M_FindPNGChunk (png, id);
|
size_t len = M_FindPNGChunk (png, id);
|
||||||
|
@ -1578,7 +1605,45 @@ static void ReadVars (PNGHandle *png, SDWORD *vars, size_t count, DWORD id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ReadArrayVars (PNGHandle *png, TArray<SDWORD> *vars, size_t count, DWORD id)
|
static void WriteArrayVars (FILE *file, FWorldGlobalArray *vars, unsigned int count, DWORD id)
|
||||||
|
{
|
||||||
|
unsigned int i, j;
|
||||||
|
|
||||||
|
// Find the first non-empty array.
|
||||||
|
for (i = 0; i < count; ++i)
|
||||||
|
{
|
||||||
|
if (vars[i].CountUsed() != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i < count)
|
||||||
|
{
|
||||||
|
// Find last non-empty array. Anything beyond the last stored array
|
||||||
|
// will be emptied at load time.
|
||||||
|
for (j = count-1; j > i; --j)
|
||||||
|
{
|
||||||
|
if (vars[j].CountUsed() != 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
FPNGChunkArchive arc (file, id);
|
||||||
|
arc.WriteCount (i);
|
||||||
|
arc.WriteCount (j);
|
||||||
|
for (; i <= j; ++i)
|
||||||
|
{
|
||||||
|
const SDWORD *key;
|
||||||
|
SDWORD *val;
|
||||||
|
|
||||||
|
arc.WriteCount (vars[i].CountUsed());
|
||||||
|
FWorldGlobalArrayIterator it(vars[i]);
|
||||||
|
while (it.NextPair (key, val))
|
||||||
|
{
|
||||||
|
arc.WriteCount (*key);
|
||||||
|
arc.WriteCount (*val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ReadArrayVars (PNGHandle *png, FWorldGlobalArray *vars, size_t count, DWORD id)
|
||||||
{
|
{
|
||||||
size_t len = M_FindPNGChunk (png, id);
|
size_t len = M_FindPNGChunk (png, id);
|
||||||
unsigned int i, k;
|
unsigned int i, k;
|
||||||
|
@ -1591,7 +1656,6 @@ static void ReadArrayVars (PNGHandle *png, TArray<SDWORD> *vars, size_t count, D
|
||||||
if (len != 0)
|
if (len != 0)
|
||||||
{
|
{
|
||||||
DWORD max, size;
|
DWORD max, size;
|
||||||
DWORD var;
|
|
||||||
FPNGChunkArchive arc (png->File->GetFile(), id, len);
|
FPNGChunkArchive arc (png->File->GetFile(), id, len);
|
||||||
|
|
||||||
i = arc.ReadCount ();
|
i = arc.ReadCount ();
|
||||||
|
@ -1600,14 +1664,12 @@ static void ReadArrayVars (PNGHandle *png, TArray<SDWORD> *vars, size_t count, D
|
||||||
for (; i <= max; ++i)
|
for (; i <= max; ++i)
|
||||||
{
|
{
|
||||||
size = arc.ReadCount ();
|
size = arc.ReadCount ();
|
||||||
if (size > 0)
|
|
||||||
{
|
|
||||||
vars[i].Resize (size);
|
|
||||||
}
|
|
||||||
for (k = 0; k < size; ++k)
|
for (k = 0; k < size; ++k)
|
||||||
{
|
{
|
||||||
arc << var;
|
SDWORD key, val;
|
||||||
vars[i][k] = var;
|
key = arc.ReadCount();
|
||||||
|
val = arc.ReadCount();
|
||||||
|
vars[i].Insert (key, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
png->File->ResetFilePtr();
|
png->File->ResetFilePtr();
|
||||||
|
@ -1916,67 +1978,6 @@ static void PutSavePic (FILE *file, int width, int height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteVars (FILE *file, SDWORD *vars, size_t count, DWORD id)
|
|
||||||
{
|
|
||||||
size_t i, j;
|
|
||||||
|
|
||||||
for (i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
if (vars[i] != 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (i < count)
|
|
||||||
{
|
|
||||||
// Find last non-zero var. Anything beyond the last stored variable
|
|
||||||
// will be zeroed at load time.
|
|
||||||
for (j = count-1; j > i; --j)
|
|
||||||
{
|
|
||||||
if (vars[j] != 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
FPNGChunkArchive arc (file, id);
|
|
||||||
for (i = 0; i <= j; ++i)
|
|
||||||
{
|
|
||||||
DWORD var = vars[i];
|
|
||||||
arc << var;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void WriteArrayVars (FILE *file, TArray<SDWORD> *vars, unsigned int count, DWORD id)
|
|
||||||
{
|
|
||||||
unsigned int i, j, k;
|
|
||||||
SDWORD val;
|
|
||||||
|
|
||||||
for (i = 0; i < count; ++i)
|
|
||||||
{
|
|
||||||
if (vars[i].Size() != 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (i < count)
|
|
||||||
{
|
|
||||||
// Find last non-empty array. Anything beyond the last stored array
|
|
||||||
// will be emptied at load time.
|
|
||||||
for (j = count-1; j > i; --j)
|
|
||||||
{
|
|
||||||
if (vars[j].Size() != 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
FPNGChunkArchive arc (file, id);
|
|
||||||
arc.WriteCount (i);
|
|
||||||
arc.WriteCount (j);
|
|
||||||
for (; i <= j; ++i)
|
|
||||||
{
|
|
||||||
arc.WriteCount (vars[i].Size());
|
|
||||||
for (k = 0; k < vars[i].Size(); ++k)
|
|
||||||
{
|
|
||||||
val = vars[i][k];
|
|
||||||
arc << val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void G_DoSaveGame (bool okForQuicksave)
|
void G_DoSaveGame (bool okForQuicksave)
|
||||||
{
|
{
|
||||||
if (demoplayback)
|
if (demoplayback)
|
||||||
|
|
|
@ -113,11 +113,11 @@ int starttime;
|
||||||
|
|
||||||
// ACS variables with world scope
|
// ACS variables with world scope
|
||||||
SDWORD ACS_WorldVars[NUM_WORLDVARS];
|
SDWORD ACS_WorldVars[NUM_WORLDVARS];
|
||||||
TAutoGrowArray<SDWORD> ACS_WorldArrays[NUM_WORLDVARS];
|
FWorldGlobalArray ACS_WorldArrays[NUM_WORLDVARS];
|
||||||
|
|
||||||
// ACS variables with global scope
|
// ACS variables with global scope
|
||||||
SDWORD ACS_GlobalVars[NUM_GLOBALVARS];
|
SDWORD ACS_GlobalVars[NUM_GLOBALVARS];
|
||||||
TAutoGrowArray<SDWORD> ACS_GlobalArrays[NUM_GLOBALVARS];
|
FWorldGlobalArray ACS_GlobalArrays[NUM_GLOBALVARS];
|
||||||
|
|
||||||
extern bool netdemo;
|
extern bool netdemo;
|
||||||
extern FString BackupSaveName;
|
extern FString BackupSaveName;
|
||||||
|
|
|
@ -286,8 +286,19 @@ extern TArray<level_info_t> wadlevelinfos;
|
||||||
|
|
||||||
extern SDWORD ACS_WorldVars[NUM_WORLDVARS];
|
extern SDWORD ACS_WorldVars[NUM_WORLDVARS];
|
||||||
extern SDWORD ACS_GlobalVars[NUM_GLOBALVARS];
|
extern SDWORD ACS_GlobalVars[NUM_GLOBALVARS];
|
||||||
extern TAutoGrowArray<SDWORD> ACS_WorldArrays[NUM_WORLDVARS];
|
|
||||||
extern TAutoGrowArray<SDWORD> ACS_GlobalArrays[NUM_GLOBALVARS];
|
struct InitIntToZero
|
||||||
|
{
|
||||||
|
void Init(int &v)
|
||||||
|
{
|
||||||
|
v = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
typedef TMap<SDWORD, SDWORD, THashTraits<SDWORD>, InitIntToZero> FWorldGlobalArray;
|
||||||
|
typedef TMapIterator<SDWORD, SDWORD, FWorldGlobalArray> FWorldGlobalArrayIterator;
|
||||||
|
|
||||||
|
extern FWorldGlobalArray ACS_WorldArrays[NUM_WORLDVARS];
|
||||||
|
extern FWorldGlobalArray ACS_GlobalArrays[NUM_GLOBALVARS];
|
||||||
|
|
||||||
extern bool savegamerestore;
|
extern bool savegamerestore;
|
||||||
|
|
||||||
|
|
|
@ -2709,12 +2709,12 @@ int DLevelScript::RunScript ()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PCD_ASSIGNWORLDARRAY:
|
case PCD_ASSIGNWORLDARRAY:
|
||||||
ACS_WorldArrays[NEXTBYTE].SetVal (STACK(2), STACK(1));
|
ACS_WorldArrays[NEXTBYTE][STACK(2)] = STACK(1);
|
||||||
sp -= 2;
|
sp -= 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PCD_ASSIGNGLOBALARRAY:
|
case PCD_ASSIGNGLOBALARRAY:
|
||||||
ACS_GlobalArrays[NEXTBYTE].SetVal (STACK(2), STACK(1));
|
ACS_GlobalArrays[NEXTBYTE][STACK(2)] = STACK(1);
|
||||||
sp -= 2;
|
sp -= 2;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -2739,11 +2739,11 @@ int DLevelScript::RunScript ()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PCD_PUSHWORLDARRAY:
|
case PCD_PUSHWORLDARRAY:
|
||||||
STACK(1) = ACS_WorldArrays[NEXTBYTE].GetVal (STACK(1));
|
STACK(1) = ACS_WorldArrays[NEXTBYTE][STACK(1)];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PCD_PUSHGLOBALARRAY:
|
case PCD_PUSHGLOBALARRAY:
|
||||||
STACK(1) = ACS_GlobalArrays[NEXTBYTE].GetVal (STACK(1));
|
STACK(1) = ACS_GlobalArrays[NEXTBYTE][STACK(1)];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PCD_ADDSCRIPTVAR:
|
case PCD_ADDSCRIPTVAR:
|
||||||
|
@ -2778,8 +2778,7 @@ int DLevelScript::RunScript ()
|
||||||
case PCD_ADDWORLDARRAY:
|
case PCD_ADDWORLDARRAY:
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(2);
|
ACS_WorldArrays[a][STACK(2)] += STACK(1);
|
||||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) + STACK(1));
|
|
||||||
sp -= 2;
|
sp -= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2787,8 +2786,7 @@ int DLevelScript::RunScript ()
|
||||||
case PCD_ADDGLOBALARRAY:
|
case PCD_ADDGLOBALARRAY:
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(2);
|
ACS_GlobalArrays[a][STACK(2)] += STACK(1);
|
||||||
ACS_GlobalArrays[a].SetVal (i, ACS_GlobalArrays[a].GetVal (i) + STACK(1));
|
|
||||||
sp -= 2;
|
sp -= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2825,8 +2823,7 @@ int DLevelScript::RunScript ()
|
||||||
case PCD_SUBWORLDARRAY:
|
case PCD_SUBWORLDARRAY:
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(2);
|
ACS_WorldArrays[a][STACK(2)] -= STACK(1);
|
||||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) - STACK(1));
|
|
||||||
sp -= 2;
|
sp -= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2834,8 +2831,7 @@ int DLevelScript::RunScript ()
|
||||||
case PCD_SUBGLOBALARRAY:
|
case PCD_SUBGLOBALARRAY:
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(2);
|
ACS_GlobalArrays[a][STACK(2)] -= STACK(1);
|
||||||
ACS_GlobalArrays[a].SetVal (i, ACS_GlobalArrays[a].GetVal (i) - STACK(1));
|
|
||||||
sp -= 2;
|
sp -= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2872,8 +2868,7 @@ int DLevelScript::RunScript ()
|
||||||
case PCD_MULWORLDARRAY:
|
case PCD_MULWORLDARRAY:
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(2);
|
ACS_WorldArrays[a][STACK(2)] *= STACK(1);
|
||||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) * STACK(1));
|
|
||||||
sp -= 2;
|
sp -= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2881,8 +2876,7 @@ int DLevelScript::RunScript ()
|
||||||
case PCD_MULGLOBALARRAY:
|
case PCD_MULGLOBALARRAY:
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(2);
|
ACS_GlobalArrays[a][STACK(2)] *= STACK(1);
|
||||||
ACS_GlobalArrays[a].SetVal (i, ACS_GlobalArrays[a].GetVal (i) * STACK(1));
|
|
||||||
sp -= 2;
|
sp -= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2957,8 +2951,7 @@ int DLevelScript::RunScript ()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(2);
|
ACS_WorldArrays[a][STACK(2)] /= STACK(1);
|
||||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) / STACK(1));
|
|
||||||
sp -= 2;
|
sp -= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2971,8 +2964,7 @@ int DLevelScript::RunScript ()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(2);
|
ACS_GlobalArrays[a][STACK(2)] /= STACK(1);
|
||||||
ACS_GlobalArrays[a].SetVal (i, ACS_GlobalArrays[a].GetVal (i) / STACK(1));
|
|
||||||
sp -= 2;
|
sp -= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3047,8 +3039,7 @@ int DLevelScript::RunScript ()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(2);
|
ACS_WorldArrays[a][STACK(2)] %= STACK(1);
|
||||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) % STACK(1));
|
|
||||||
sp -= 2;
|
sp -= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3061,8 +3052,7 @@ int DLevelScript::RunScript ()
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(2);
|
ACS_GlobalArrays[a][STACK(2)] %= STACK(1);
|
||||||
ACS_GlobalArrays[a].SetVal (i, ACS_GlobalArrays[a].GetVal (i) % STACK(1));
|
|
||||||
sp -= 2;
|
sp -= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3100,8 +3090,7 @@ int DLevelScript::RunScript ()
|
||||||
case PCD_ANDWORLDARRAY:
|
case PCD_ANDWORLDARRAY:
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(2);
|
ACS_WorldArrays[a][STACK(2)] &= STACK(1);
|
||||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) & STACK(1));
|
|
||||||
sp -= 2;
|
sp -= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3109,8 +3098,7 @@ int DLevelScript::RunScript ()
|
||||||
case PCD_ANDGLOBALARRAY:
|
case PCD_ANDGLOBALARRAY:
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(2);
|
ACS_GlobalArrays[a][STACK(2)] &= STACK(1);
|
||||||
ACS_GlobalArrays[a].SetVal (i, ACS_GlobalArrays[a].GetVal (i) & STACK(1));
|
|
||||||
sp -= 2;
|
sp -= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3147,8 +3135,7 @@ int DLevelScript::RunScript ()
|
||||||
case PCD_EORWORLDARRAY:
|
case PCD_EORWORLDARRAY:
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(2);
|
ACS_WorldArrays[a][STACK(2)] ^= STACK(1);
|
||||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) ^ STACK(1));
|
|
||||||
sp -= 2;
|
sp -= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3156,8 +3143,7 @@ int DLevelScript::RunScript ()
|
||||||
case PCD_EORGLOBALARRAY:
|
case PCD_EORGLOBALARRAY:
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(2);
|
ACS_GlobalArrays[a][STACK(2)] ^= STACK(1);
|
||||||
ACS_GlobalArrays[a].SetVal (i, ACS_GlobalArrays[a].GetVal (i) ^ STACK(1));
|
|
||||||
sp -= 2;
|
sp -= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3194,8 +3180,7 @@ int DLevelScript::RunScript ()
|
||||||
case PCD_ORWORLDARRAY:
|
case PCD_ORWORLDARRAY:
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(2);
|
ACS_WorldArrays[a][STACK(2)] |= STACK(1);
|
||||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) | STACK(1));
|
|
||||||
sp -= 2;
|
sp -= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3204,7 +3189,7 @@ int DLevelScript::RunScript ()
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(2);
|
int i = STACK(2);
|
||||||
ACS_GlobalArrays[a].SetVal (i, ACS_GlobalArrays[a].GetVal (i) | STACK(1));
|
ACS_GlobalArrays[a][STACK(2)] |= STACK(1);
|
||||||
sp -= 2;
|
sp -= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3241,8 +3226,7 @@ int DLevelScript::RunScript ()
|
||||||
case PCD_LSWORLDARRAY:
|
case PCD_LSWORLDARRAY:
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(2);
|
ACS_WorldArrays[a][STACK(2)] <<= STACK(1);
|
||||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) << STACK(1));
|
|
||||||
sp -= 2;
|
sp -= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3250,8 +3234,7 @@ int DLevelScript::RunScript ()
|
||||||
case PCD_LSGLOBALARRAY:
|
case PCD_LSGLOBALARRAY:
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(2);
|
ACS_GlobalArrays[a][STACK(2)] <<= STACK(1);
|
||||||
ACS_GlobalArrays[a].SetVal (i, ACS_GlobalArrays[a].GetVal (i) << STACK(1));
|
|
||||||
sp -= 2;
|
sp -= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3288,8 +3271,7 @@ int DLevelScript::RunScript ()
|
||||||
case PCD_RSWORLDARRAY:
|
case PCD_RSWORLDARRAY:
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(2);
|
ACS_WorldArrays[a][STACK(2)] >>= STACK(1);
|
||||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) >> STACK(1));
|
|
||||||
sp -= 2;
|
sp -= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3297,8 +3279,7 @@ int DLevelScript::RunScript ()
|
||||||
case PCD_RSGLOBALARRAY:
|
case PCD_RSGLOBALARRAY:
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(2);
|
ACS_GlobalArrays[a][STACK(2)] >>= STACK(1);
|
||||||
ACS_GlobalArrays[a].SetVal (i, ACS_GlobalArrays[a].GetVal (i) >> STACK(1));
|
|
||||||
sp -= 2;
|
sp -= 2;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3332,8 +3313,7 @@ int DLevelScript::RunScript ()
|
||||||
case PCD_INCWORLDARRAY:
|
case PCD_INCWORLDARRAY:
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(1);
|
ACS_WorldArrays[a][STACK(1)] += 1;
|
||||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) + 1);
|
|
||||||
sp--;
|
sp--;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3341,8 +3321,7 @@ int DLevelScript::RunScript ()
|
||||||
case PCD_INCGLOBALARRAY:
|
case PCD_INCGLOBALARRAY:
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(1);
|
ACS_GlobalArrays[a][STACK(1)] += 1;
|
||||||
ACS_GlobalArrays[a].SetVal (i, ACS_GlobalArrays[a].GetVal (i) + 1);
|
|
||||||
sp--;
|
sp--;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3375,8 +3354,7 @@ int DLevelScript::RunScript ()
|
||||||
case PCD_DECWORLDARRAY:
|
case PCD_DECWORLDARRAY:
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(1);
|
ACS_WorldArrays[a][STACK(1)] -= 1;
|
||||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) - 1);
|
|
||||||
sp--;
|
sp--;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3385,7 +3363,7 @@ int DLevelScript::RunScript ()
|
||||||
{
|
{
|
||||||
int a = NEXTBYTE;
|
int a = NEXTBYTE;
|
||||||
int i = STACK(1);
|
int i = STACK(1);
|
||||||
ACS_GlobalArrays[a].SetVal (i, ACS_GlobalArrays[a].GetVal (i) - 1);
|
ACS_GlobalArrays[a][STACK(1)] -= 1;
|
||||||
sp--;
|
sp--;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -3732,7 +3710,7 @@ int DLevelScript::RunScript ()
|
||||||
int a = STACK(1);
|
int a = STACK(1);
|
||||||
int offset = STACK(2);
|
int offset = STACK(2);
|
||||||
int c;
|
int c;
|
||||||
while((c = ACS_WorldArrays[a].GetVal (offset)) != '\0') {
|
while((c = ACS_WorldArrays[a][offset]) != '\0') {
|
||||||
work += (char)c;
|
work += (char)c;
|
||||||
offset++;
|
offset++;
|
||||||
}
|
}
|
||||||
|
@ -3746,7 +3724,7 @@ int DLevelScript::RunScript ()
|
||||||
int a = STACK(1);
|
int a = STACK(1);
|
||||||
int offset = STACK(2);
|
int offset = STACK(2);
|
||||||
int c;
|
int c;
|
||||||
while((c = ACS_GlobalArrays[a].GetVal (offset)) != '\0') {
|
while((c = ACS_GlobalArrays[a][offset]) != '\0') {
|
||||||
work += (char)c;
|
work += (char)c;
|
||||||
offset++;
|
offset++;
|
||||||
}
|
}
|
||||||
|
|
539
src/tarray.h
539
src/tarray.h
|
@ -41,6 +41,8 @@
|
||||||
#include "m_alloc.h"
|
#include "m_alloc.h"
|
||||||
|
|
||||||
|
|
||||||
|
// TArray -------------------------------------------------------------------
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class TArray
|
class TArray
|
||||||
{
|
{
|
||||||
|
@ -251,7 +253,7 @@ private:
|
||||||
Array = (T *)M_Malloc (sizeof(T)*Most);
|
Array = (T *)M_Malloc (sizeof(T)*Most);
|
||||||
for (unsigned int i = 0; i < Count; ++i)
|
for (unsigned int i = 0; i < Count; ++i)
|
||||||
{
|
{
|
||||||
Array[i] = other.Array[i];
|
::new(&Array[i]) T(other.Array[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -276,9 +278,10 @@ private:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// An array with accessors that automatically grow the
|
// TAutoGrowArray -----------------------------------------------------------
|
||||||
// array as needed. But can still be used as a normal
|
// An array with accessors that automatically grow the array as needed.
|
||||||
// TArray if needed. Used by ACS world and global arrays.
|
// It can still be used as a normal TArray if needed. ACS uses this for
|
||||||
|
// world and global arrays.
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class TAutoGrowArray : public TArray<T>
|
class TAutoGrowArray : public TArray<T>
|
||||||
|
@ -304,4 +307,532 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TMap ---------------------------------------------------------------------
|
||||||
|
// An associative array, similar in concept to the STL extension
|
||||||
|
// class hash_map. It is implemented using Lua's table algorithm:
|
||||||
|
/*
|
||||||
|
** Hash uses a mix of chained scatter table with Brent's variation.
|
||||||
|
** A main invariant of these tables is that, if an element is not
|
||||||
|
** in its main position (i.e. the `original' position that its hash gives
|
||||||
|
** to it), then the colliding element is in its own main position.
|
||||||
|
** Hence even when the load factor reaches 100%, performance remains good.
|
||||||
|
*/
|
||||||
|
/******************************************************************************
|
||||||
|
* Copyright (C) 1994-2006 Lua.org, PUC-Rio. All rights reserved.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
typedef unsigned int hash_t;
|
||||||
|
|
||||||
|
template<class KT> struct THashTraits
|
||||||
|
{
|
||||||
|
// Returns the hash value for a key.
|
||||||
|
hash_t Hash(const KT key) { return hash_t(key); }
|
||||||
|
|
||||||
|
// Compares two keys, returning zero if they are the same.
|
||||||
|
int Compare(const KT left, const KT right) { return left != right; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class VT> struct TValueTraits
|
||||||
|
{
|
||||||
|
// Initializes a value for TMap. If a regular consructor isn't
|
||||||
|
// good enough, you can override it.
|
||||||
|
void Init(VT &value)
|
||||||
|
{
|
||||||
|
::new(&value) VT;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class KT, class VT, class HashTraits=THashTraits<KT>, class ValueTraits=TValueTraits<VT> >
|
||||||
|
class TMap
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TMap() { NumUsed = 0; SetNodeVector(1); }
|
||||||
|
TMap(hash_t size) { NumUsed = 0; SetNodeVector(size); }
|
||||||
|
~TMap() { ClearNodeVector(); }
|
||||||
|
|
||||||
|
TMap(const TMap &o)
|
||||||
|
{
|
||||||
|
NumUsed = 0;
|
||||||
|
SetNodeVector(o.CountUsed());
|
||||||
|
CopyNodes(o.Nodes, o.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
TMap &operator= (const TMap &o)
|
||||||
|
{
|
||||||
|
NumUsed = 0;
|
||||||
|
ClearNodeVector();
|
||||||
|
SetNodeVector(o.CountUsed());
|
||||||
|
CopyNodes(o.Nodes, o.Size);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=======================================================================
|
||||||
|
//
|
||||||
|
// Clear
|
||||||
|
//
|
||||||
|
// Empties out the table and resizes it with room for count entries.
|
||||||
|
//
|
||||||
|
//=======================================================================
|
||||||
|
|
||||||
|
void Clear(hash_t count=1)
|
||||||
|
{
|
||||||
|
ClearNodeVector();
|
||||||
|
SetNodeVector(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=======================================================================
|
||||||
|
//
|
||||||
|
// CountUsed
|
||||||
|
//
|
||||||
|
// Returns the number of entries in use in the table.
|
||||||
|
//
|
||||||
|
//=======================================================================
|
||||||
|
|
||||||
|
hash_t CountUsed() const
|
||||||
|
{
|
||||||
|
#ifdef _DEBUG
|
||||||
|
hash_t used = 0;
|
||||||
|
hash_t ct = Size;
|
||||||
|
for (Node *n = Nodes; ct-- > 0; ++n)
|
||||||
|
{
|
||||||
|
if (!n->IsNil())
|
||||||
|
{
|
||||||
|
++used;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert (used == NumUsed);
|
||||||
|
#endif
|
||||||
|
return NumUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=======================================================================
|
||||||
|
//
|
||||||
|
// operator[]
|
||||||
|
//
|
||||||
|
// Returns a reference to the value associated with a particular key,
|
||||||
|
// creating the pair if the key isn't already in the table.
|
||||||
|
//
|
||||||
|
//=======================================================================
|
||||||
|
|
||||||
|
VT &operator[] (const KT key)
|
||||||
|
{
|
||||||
|
return GetNode(key)->Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VT &operator[] (const KT key) const
|
||||||
|
{
|
||||||
|
return GetNode(key)->Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=======================================================================
|
||||||
|
//
|
||||||
|
// CheckKey
|
||||||
|
//
|
||||||
|
// Returns a pointer to the value associated with a particular key, or
|
||||||
|
// NULL if the key isn't in the table.
|
||||||
|
//
|
||||||
|
//=======================================================================
|
||||||
|
|
||||||
|
VT *CheckKey (const KT key)
|
||||||
|
{
|
||||||
|
Node *n = FindKey(key);
|
||||||
|
return n != NULL ? &n->Value : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const VT *CheckKey (const KT key) const
|
||||||
|
{
|
||||||
|
Node *n = FindKey(key);
|
||||||
|
return n != NULL ? &n->Value : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=======================================================================
|
||||||
|
//
|
||||||
|
// Insert
|
||||||
|
//
|
||||||
|
// Adds a key/value pair to the table if key isn't in the table, or
|
||||||
|
// replaces the value for the existing pair if the key is in the table.
|
||||||
|
//
|
||||||
|
// This is functionally equivalent to (*this)[key] = value; but can be
|
||||||
|
// slightly faster if the pair needs to be created because it doesn't run
|
||||||
|
// the constructor on the value part twice.
|
||||||
|
//
|
||||||
|
//=======================================================================
|
||||||
|
|
||||||
|
VT &Insert(const KT key, const VT &value)
|
||||||
|
{
|
||||||
|
Node *n = FindKey(key);
|
||||||
|
if (n != NULL)
|
||||||
|
{
|
||||||
|
n->Value = value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
n = NewKey(key);
|
||||||
|
::new(&n->Value) VT(value);
|
||||||
|
}
|
||||||
|
return n->Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=======================================================================
|
||||||
|
//
|
||||||
|
// Remove
|
||||||
|
//
|
||||||
|
// Removes the key/value pair for a particular key if it is in the table.
|
||||||
|
//
|
||||||
|
//=======================================================================
|
||||||
|
|
||||||
|
void Remove(const KT key)
|
||||||
|
{
|
||||||
|
DelKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
template<class KTa, class VTa, class MTa> friend class TMapIterator;
|
||||||
|
template<class KTb, class VTb, class MTb> friend class TMapConstIterator;
|
||||||
|
|
||||||
|
struct Node
|
||||||
|
{
|
||||||
|
Node *Next;
|
||||||
|
KT Key;
|
||||||
|
VT Value;
|
||||||
|
|
||||||
|
void SetNil()
|
||||||
|
{
|
||||||
|
Next = (Node *)1;
|
||||||
|
}
|
||||||
|
bool IsNil() const
|
||||||
|
{
|
||||||
|
return Next == (Node *)1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* This is used instead of memcpy, because Node is likely to be small,
|
||||||
|
* such that the time spent calling a function would eclipse the time
|
||||||
|
* spent copying. */
|
||||||
|
struct NodeSizedStruct { unsigned char Pads[sizeof(Node)]; };
|
||||||
|
|
||||||
|
Node *Nodes;
|
||||||
|
Node *LastFree; /* any free position is before this position */
|
||||||
|
hash_t Size; /* must be a power of 2 */
|
||||||
|
hash_t NumUsed;
|
||||||
|
|
||||||
|
const Node *MainPosition(const KT k) const
|
||||||
|
{
|
||||||
|
HashTraits Traits;
|
||||||
|
return &Nodes[Traits.Hash(k) & (Size - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
Node *MainPosition(const KT k)
|
||||||
|
{
|
||||||
|
HashTraits Traits;
|
||||||
|
return &Nodes[Traits.Hash(k) & (Size - 1)];
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetNodeVector(hash_t size)
|
||||||
|
{
|
||||||
|
// Round size up to nearest power of 2
|
||||||
|
for (Size = 1; Size < size; Size <<= 1)
|
||||||
|
{ }
|
||||||
|
Nodes = (Node *)M_Malloc(Size * sizeof(Node));
|
||||||
|
LastFree = &Nodes[Size]; /* all positions are free */
|
||||||
|
for (hash_t i = 0; i < Size; ++i)
|
||||||
|
{
|
||||||
|
Nodes[i].SetNil();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClearNodeVector()
|
||||||
|
{
|
||||||
|
for (hash_t i = 0; i < Size; ++i)
|
||||||
|
{
|
||||||
|
if (!Nodes[i].IsNil())
|
||||||
|
{
|
||||||
|
Nodes[i].~Node();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(Nodes);
|
||||||
|
Nodes = NULL;
|
||||||
|
Size = 0;
|
||||||
|
LastFree = NULL;
|
||||||
|
NumUsed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resize(hash_t nhsize)
|
||||||
|
{
|
||||||
|
hash_t i, oldhsize = Size;
|
||||||
|
Node *nold = Nodes;
|
||||||
|
/* create new hash part with appropriate size */
|
||||||
|
SetNodeVector(nhsize);
|
||||||
|
/* re-insert elements from hash part */
|
||||||
|
NumUsed = 0;
|
||||||
|
for (i = 0; i < oldhsize; ++i)
|
||||||
|
{
|
||||||
|
if (!nold[i].IsNil())
|
||||||
|
{
|
||||||
|
Node *n = NewKey(nold[i].Key);
|
||||||
|
::new(&n->Value) VT(nold[i].Value);
|
||||||
|
nold[i].~Node();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(nold);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rehash()
|
||||||
|
{
|
||||||
|
Resize (Size << 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node *GetFreePos()
|
||||||
|
{
|
||||||
|
while (LastFree-- > Nodes)
|
||||||
|
{
|
||||||
|
if (LastFree->IsNil())
|
||||||
|
{
|
||||||
|
return LastFree;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL; /* could not find a free place */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Inserts a new key into a hash table; first, check whether key's main
|
||||||
|
** position is free. If not, check whether colliding node is in its main
|
||||||
|
** position or not: if it is not, move colliding node to an empty place and
|
||||||
|
** put new key in its main position; otherwise (colliding node is in its main
|
||||||
|
** position), new key goes to an empty position.
|
||||||
|
**
|
||||||
|
** The Value field is left unconstructed.
|
||||||
|
*/
|
||||||
|
Node *NewKey(const KT key)
|
||||||
|
{
|
||||||
|
Node *mp = MainPosition(key);
|
||||||
|
if (!mp->IsNil())
|
||||||
|
{
|
||||||
|
Node *othern;
|
||||||
|
Node *n = GetFreePos(); /* get a free place */
|
||||||
|
if (n == NULL) /* cannot find a free place? */
|
||||||
|
{
|
||||||
|
Rehash(); /* grow table */
|
||||||
|
return NewKey(key); /* re-insert key into grown table */
|
||||||
|
}
|
||||||
|
othern = MainPosition(mp->Key);
|
||||||
|
if (othern != mp) /* is colliding node out of its main position? */
|
||||||
|
{ /* yes; move colliding node into free position */
|
||||||
|
while (othern->Next != mp) /* find previous */
|
||||||
|
{
|
||||||
|
othern = othern->Next;
|
||||||
|
}
|
||||||
|
othern->Next = n; /* redo the chain with 'n' in place of 'mp' */
|
||||||
|
CopyNode(n, mp); /* copy colliding node into free pos. (mp->Next also goes) */
|
||||||
|
mp->Next = NULL; /* now 'mp' is free */
|
||||||
|
}
|
||||||
|
else /* colliding node is in its own main position */
|
||||||
|
{ /* new node will go into free position */
|
||||||
|
n->Next = mp->Next; /* chain new position */
|
||||||
|
mp->Next = n;
|
||||||
|
mp = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mp->Next = NULL;
|
||||||
|
}
|
||||||
|
++NumUsed;
|
||||||
|
::new(&mp->Key) KT(key);
|
||||||
|
return mp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DelKey(const KT key)
|
||||||
|
{
|
||||||
|
Node *mp = MainPosition(key), **mpp;
|
||||||
|
HashTraits Traits;
|
||||||
|
|
||||||
|
if (!mp->IsNil() && !Traits.Compare(mp->Key, key)) /* the key is in its main position */
|
||||||
|
{
|
||||||
|
if (mp->Next != NULL) /* move next node to its main position */
|
||||||
|
{
|
||||||
|
Node *n = mp->Next;
|
||||||
|
mp->~Node(); /* deconstruct old node */
|
||||||
|
CopyNode(mp, n); /* copy next node */
|
||||||
|
n->SetNil(); /* next node is now nil */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mp->~Node();
|
||||||
|
mp->SetNil(); /* there is no chain, so main position is nil */
|
||||||
|
}
|
||||||
|
--NumUsed;
|
||||||
|
}
|
||||||
|
else /* the key is either not present or not in its main position */
|
||||||
|
{
|
||||||
|
for (mpp = &mp->Next, mp = *mpp; mp != NULL && Traits.Compare(mp->Key, key); mpp = &mp->Next, mp = *mpp)
|
||||||
|
{ } /* look for the key */
|
||||||
|
if (mp != NULL) /* found it */
|
||||||
|
{
|
||||||
|
*mpp = mp->Next; /* rechain so this node is skipped */
|
||||||
|
mp->~Node();
|
||||||
|
mp->SetNil(); /* because this node is now nil */
|
||||||
|
--NumUsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Node *FindKey(const KT key)
|
||||||
|
{
|
||||||
|
HashTraits Traits;
|
||||||
|
Node *n = MainPosition(key);
|
||||||
|
while (n != NULL && !n->IsNil() && Traits.Compare(n->Key, key))
|
||||||
|
{
|
||||||
|
n = n->Next;
|
||||||
|
}
|
||||||
|
return n == NULL || n->IsNil() ? NULL : n;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node *GetNode(const KT key)
|
||||||
|
{
|
||||||
|
Node *n = FindKey(key);
|
||||||
|
if (n != NULL)
|
||||||
|
{
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
n = NewKey(key);
|
||||||
|
ValueTraits traits;
|
||||||
|
traits.Init(n->Value);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform a bit-wise copy of the node. Used when relocating a node in the table. */
|
||||||
|
void CopyNode(Node *dst, const Node *src)
|
||||||
|
{
|
||||||
|
*(NodeSizedStruct *)dst = *(const NodeSizedStruct *)src;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy all nodes in the node vector to this table. */
|
||||||
|
void CopyNodes(const Node *nodes, hash_t numnodes)
|
||||||
|
{
|
||||||
|
for (; numnodes-- > 0; ++nodes)
|
||||||
|
{
|
||||||
|
if (!nodes->IsNil())
|
||||||
|
{
|
||||||
|
Node *n = NewKey(nodes->Key);
|
||||||
|
::new(&n->Value) VT(nodes->Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// TMapIterator -------------------------------------------------------------
|
||||||
|
// A class to iterate over all the pairs in a TMap.
|
||||||
|
|
||||||
|
template<class KT, class VT, class MapType=TMap<KT,VT> >
|
||||||
|
class TMapIterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TMapIterator(MapType &map)
|
||||||
|
: Map(map), Position(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//=======================================================================
|
||||||
|
//
|
||||||
|
// NextPair
|
||||||
|
//
|
||||||
|
// Returns false if there are no more entries in the table. Otherwise, it
|
||||||
|
// returns true, and key and value are filled with pointers to the
|
||||||
|
// respective parts of the next pair in the table.
|
||||||
|
//
|
||||||
|
//=======================================================================
|
||||||
|
|
||||||
|
bool NextPair(const KT *&key, VT *&value)
|
||||||
|
{
|
||||||
|
if (Position >= Map.Size)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (!Map.Nodes[Position].IsNil())
|
||||||
|
{
|
||||||
|
key = &Map.Nodes[Position].Key;
|
||||||
|
value = &Map.Nodes[Position].Value;
|
||||||
|
Position += 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (++Position < Map.Size);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//=======================================================================
|
||||||
|
//
|
||||||
|
// Reset
|
||||||
|
//
|
||||||
|
// Restarts the iteration so you can do it all over again.
|
||||||
|
//
|
||||||
|
//=======================================================================
|
||||||
|
|
||||||
|
void Reset()
|
||||||
|
{
|
||||||
|
Position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
MapType ⤅
|
||||||
|
hash_t Position;
|
||||||
|
};
|
||||||
|
|
||||||
|
// TMapConstIterator --------------------------------------------------------
|
||||||
|
// Exactly the same as TMapIterator, but it works with a const TMap.
|
||||||
|
|
||||||
|
template<class KT, class VT, class MapType=TMap<KT,VT> >
|
||||||
|
class TMapConstIterator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
TMapConstIterator(const MapType &map)
|
||||||
|
: Map(map), Position(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NextPair(const KT *&key, const VT *&value)
|
||||||
|
{
|
||||||
|
if (Position >= Map.Size)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (!Map.Nodes[Position].IsNil())
|
||||||
|
{
|
||||||
|
key = &Map.Nodes[Position].Key;
|
||||||
|
value = &Map.Nodes[Position].Value;
|
||||||
|
Position += 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} while (++Position < Map.Size);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
const MapType ⤅
|
||||||
|
hash_t Position;
|
||||||
|
};
|
||||||
|
|
||||||
#endif //__TARRAY_H__
|
#endif //__TARRAY_H__
|
||||||
|
|
Loading…
Reference in a new issue