mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-10 23:01:50 +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
|
||||
- Fixed some const char * -> char * conversions flagged by GCC 4.2.0 in the
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
unsigned int i, k;
|
||||
|
@ -1591,7 +1656,6 @@ static void ReadArrayVars (PNGHandle *png, TArray<SDWORD> *vars, size_t count, D
|
|||
if (len != 0)
|
||||
{
|
||||
DWORD max, size;
|
||||
DWORD var;
|
||||
FPNGChunkArchive arc (png->File->GetFile(), id, len);
|
||||
|
||||
i = arc.ReadCount ();
|
||||
|
@ -1600,14 +1664,12 @@ static void ReadArrayVars (PNGHandle *png, TArray<SDWORD> *vars, size_t count, D
|
|||
for (; i <= max; ++i)
|
||||
{
|
||||
size = arc.ReadCount ();
|
||||
if (size > 0)
|
||||
{
|
||||
vars[i].Resize (size);
|
||||
}
|
||||
for (k = 0; k < size; ++k)
|
||||
{
|
||||
arc << var;
|
||||
vars[i][k] = var;
|
||||
SDWORD key, val;
|
||||
key = arc.ReadCount();
|
||||
val = arc.ReadCount();
|
||||
vars[i].Insert (key, val);
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
if (demoplayback)
|
||||
|
|
|
@ -113,11 +113,11 @@ int starttime;
|
|||
|
||||
// ACS variables with world scope
|
||||
SDWORD ACS_WorldVars[NUM_WORLDVARS];
|
||||
TAutoGrowArray<SDWORD> ACS_WorldArrays[NUM_WORLDVARS];
|
||||
FWorldGlobalArray ACS_WorldArrays[NUM_WORLDVARS];
|
||||
|
||||
// ACS variables with global scope
|
||||
SDWORD ACS_GlobalVars[NUM_GLOBALVARS];
|
||||
TAutoGrowArray<SDWORD> ACS_GlobalArrays[NUM_GLOBALVARS];
|
||||
FWorldGlobalArray ACS_GlobalArrays[NUM_GLOBALVARS];
|
||||
|
||||
extern bool netdemo;
|
||||
extern FString BackupSaveName;
|
||||
|
|
|
@ -286,8 +286,19 @@ extern TArray<level_info_t> wadlevelinfos;
|
|||
|
||||
extern SDWORD ACS_WorldVars[NUM_WORLDVARS];
|
||||
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;
|
||||
|
||||
|
|
|
@ -2709,12 +2709,12 @@ int DLevelScript::RunScript ()
|
|||
break;
|
||||
|
||||
case PCD_ASSIGNWORLDARRAY:
|
||||
ACS_WorldArrays[NEXTBYTE].SetVal (STACK(2), STACK(1));
|
||||
ACS_WorldArrays[NEXTBYTE][STACK(2)] = STACK(1);
|
||||
sp -= 2;
|
||||
break;
|
||||
|
||||
case PCD_ASSIGNGLOBALARRAY:
|
||||
ACS_GlobalArrays[NEXTBYTE].SetVal (STACK(2), STACK(1));
|
||||
ACS_GlobalArrays[NEXTBYTE][STACK(2)] = STACK(1);
|
||||
sp -= 2;
|
||||
break;
|
||||
|
||||
|
@ -2739,11 +2739,11 @@ int DLevelScript::RunScript ()
|
|||
break;
|
||||
|
||||
case PCD_PUSHWORLDARRAY:
|
||||
STACK(1) = ACS_WorldArrays[NEXTBYTE].GetVal (STACK(1));
|
||||
STACK(1) = ACS_WorldArrays[NEXTBYTE][STACK(1)];
|
||||
break;
|
||||
|
||||
case PCD_PUSHGLOBALARRAY:
|
||||
STACK(1) = ACS_GlobalArrays[NEXTBYTE].GetVal (STACK(1));
|
||||
STACK(1) = ACS_GlobalArrays[NEXTBYTE][STACK(1)];
|
||||
break;
|
||||
|
||||
case PCD_ADDSCRIPTVAR:
|
||||
|
@ -2778,8 +2778,7 @@ int DLevelScript::RunScript ()
|
|||
case PCD_ADDWORLDARRAY:
|
||||
{
|
||||
int a = NEXTBYTE;
|
||||
int i = STACK(2);
|
||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) + STACK(1));
|
||||
ACS_WorldArrays[a][STACK(2)] += STACK(1);
|
||||
sp -= 2;
|
||||
}
|
||||
break;
|
||||
|
@ -2787,8 +2786,7 @@ int DLevelScript::RunScript ()
|
|||
case PCD_ADDGLOBALARRAY:
|
||||
{
|
||||
int a = NEXTBYTE;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
@ -2825,8 +2823,7 @@ int DLevelScript::RunScript ()
|
|||
case PCD_SUBWORLDARRAY:
|
||||
{
|
||||
int a = NEXTBYTE;
|
||||
int i = STACK(2);
|
||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) - STACK(1));
|
||||
ACS_WorldArrays[a][STACK(2)] -= STACK(1);
|
||||
sp -= 2;
|
||||
}
|
||||
break;
|
||||
|
@ -2834,8 +2831,7 @@ int DLevelScript::RunScript ()
|
|||
case PCD_SUBGLOBALARRAY:
|
||||
{
|
||||
int a = NEXTBYTE;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
@ -2872,8 +2868,7 @@ int DLevelScript::RunScript ()
|
|||
case PCD_MULWORLDARRAY:
|
||||
{
|
||||
int a = NEXTBYTE;
|
||||
int i = STACK(2);
|
||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) * STACK(1));
|
||||
ACS_WorldArrays[a][STACK(2)] *= STACK(1);
|
||||
sp -= 2;
|
||||
}
|
||||
break;
|
||||
|
@ -2881,8 +2876,7 @@ int DLevelScript::RunScript ()
|
|||
case PCD_MULGLOBALARRAY:
|
||||
{
|
||||
int a = NEXTBYTE;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
@ -2957,8 +2951,7 @@ int DLevelScript::RunScript ()
|
|||
else
|
||||
{
|
||||
int a = NEXTBYTE;
|
||||
int i = STACK(2);
|
||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) / STACK(1));
|
||||
ACS_WorldArrays[a][STACK(2)] /= STACK(1);
|
||||
sp -= 2;
|
||||
}
|
||||
break;
|
||||
|
@ -2971,8 +2964,7 @@ int DLevelScript::RunScript ()
|
|||
else
|
||||
{
|
||||
int a = NEXTBYTE;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
@ -3047,8 +3039,7 @@ int DLevelScript::RunScript ()
|
|||
else
|
||||
{
|
||||
int a = NEXTBYTE;
|
||||
int i = STACK(2);
|
||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) % STACK(1));
|
||||
ACS_WorldArrays[a][STACK(2)] %= STACK(1);
|
||||
sp -= 2;
|
||||
}
|
||||
break;
|
||||
|
@ -3061,8 +3052,7 @@ int DLevelScript::RunScript ()
|
|||
else
|
||||
{
|
||||
int a = NEXTBYTE;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
@ -3100,8 +3090,7 @@ int DLevelScript::RunScript ()
|
|||
case PCD_ANDWORLDARRAY:
|
||||
{
|
||||
int a = NEXTBYTE;
|
||||
int i = STACK(2);
|
||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) & STACK(1));
|
||||
ACS_WorldArrays[a][STACK(2)] &= STACK(1);
|
||||
sp -= 2;
|
||||
}
|
||||
break;
|
||||
|
@ -3109,8 +3098,7 @@ int DLevelScript::RunScript ()
|
|||
case PCD_ANDGLOBALARRAY:
|
||||
{
|
||||
int a = NEXTBYTE;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
@ -3147,8 +3135,7 @@ int DLevelScript::RunScript ()
|
|||
case PCD_EORWORLDARRAY:
|
||||
{
|
||||
int a = NEXTBYTE;
|
||||
int i = STACK(2);
|
||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) ^ STACK(1));
|
||||
ACS_WorldArrays[a][STACK(2)] ^= STACK(1);
|
||||
sp -= 2;
|
||||
}
|
||||
break;
|
||||
|
@ -3156,8 +3143,7 @@ int DLevelScript::RunScript ()
|
|||
case PCD_EORGLOBALARRAY:
|
||||
{
|
||||
int a = NEXTBYTE;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
@ -3194,8 +3180,7 @@ int DLevelScript::RunScript ()
|
|||
case PCD_ORWORLDARRAY:
|
||||
{
|
||||
int a = NEXTBYTE;
|
||||
int i = STACK(2);
|
||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) | STACK(1));
|
||||
ACS_WorldArrays[a][STACK(2)] |= STACK(1);
|
||||
sp -= 2;
|
||||
}
|
||||
break;
|
||||
|
@ -3204,7 +3189,7 @@ int DLevelScript::RunScript ()
|
|||
{
|
||||
int a = NEXTBYTE;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
@ -3241,8 +3226,7 @@ int DLevelScript::RunScript ()
|
|||
case PCD_LSWORLDARRAY:
|
||||
{
|
||||
int a = NEXTBYTE;
|
||||
int i = STACK(2);
|
||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) << STACK(1));
|
||||
ACS_WorldArrays[a][STACK(2)] <<= STACK(1);
|
||||
sp -= 2;
|
||||
}
|
||||
break;
|
||||
|
@ -3250,8 +3234,7 @@ int DLevelScript::RunScript ()
|
|||
case PCD_LSGLOBALARRAY:
|
||||
{
|
||||
int a = NEXTBYTE;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
@ -3288,8 +3271,7 @@ int DLevelScript::RunScript ()
|
|||
case PCD_RSWORLDARRAY:
|
||||
{
|
||||
int a = NEXTBYTE;
|
||||
int i = STACK(2);
|
||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) >> STACK(1));
|
||||
ACS_WorldArrays[a][STACK(2)] >>= STACK(1);
|
||||
sp -= 2;
|
||||
}
|
||||
break;
|
||||
|
@ -3297,8 +3279,7 @@ int DLevelScript::RunScript ()
|
|||
case PCD_RSGLOBALARRAY:
|
||||
{
|
||||
int a = NEXTBYTE;
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
@ -3332,8 +3313,7 @@ int DLevelScript::RunScript ()
|
|||
case PCD_INCWORLDARRAY:
|
||||
{
|
||||
int a = NEXTBYTE;
|
||||
int i = STACK(1);
|
||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) + 1);
|
||||
ACS_WorldArrays[a][STACK(1)] += 1;
|
||||
sp--;
|
||||
}
|
||||
break;
|
||||
|
@ -3341,8 +3321,7 @@ int DLevelScript::RunScript ()
|
|||
case PCD_INCGLOBALARRAY:
|
||||
{
|
||||
int a = NEXTBYTE;
|
||||
int i = STACK(1);
|
||||
ACS_GlobalArrays[a].SetVal (i, ACS_GlobalArrays[a].GetVal (i) + 1);
|
||||
ACS_GlobalArrays[a][STACK(1)] += 1;
|
||||
sp--;
|
||||
}
|
||||
break;
|
||||
|
@ -3375,8 +3354,7 @@ int DLevelScript::RunScript ()
|
|||
case PCD_DECWORLDARRAY:
|
||||
{
|
||||
int a = NEXTBYTE;
|
||||
int i = STACK(1);
|
||||
ACS_WorldArrays[a].SetVal (i, ACS_WorldArrays[a].GetVal (i) - 1);
|
||||
ACS_WorldArrays[a][STACK(1)] -= 1;
|
||||
sp--;
|
||||
}
|
||||
break;
|
||||
|
@ -3385,7 +3363,7 @@ int DLevelScript::RunScript ()
|
|||
{
|
||||
int a = NEXTBYTE;
|
||||
int i = STACK(1);
|
||||
ACS_GlobalArrays[a].SetVal (i, ACS_GlobalArrays[a].GetVal (i) - 1);
|
||||
ACS_GlobalArrays[a][STACK(1)] -= 1;
|
||||
sp--;
|
||||
}
|
||||
break;
|
||||
|
@ -3732,7 +3710,7 @@ int DLevelScript::RunScript ()
|
|||
int a = STACK(1);
|
||||
int offset = STACK(2);
|
||||
int c;
|
||||
while((c = ACS_WorldArrays[a].GetVal (offset)) != '\0') {
|
||||
while((c = ACS_WorldArrays[a][offset]) != '\0') {
|
||||
work += (char)c;
|
||||
offset++;
|
||||
}
|
||||
|
@ -3746,7 +3724,7 @@ int DLevelScript::RunScript ()
|
|||
int a = STACK(1);
|
||||
int offset = STACK(2);
|
||||
int c;
|
||||
while((c = ACS_GlobalArrays[a].GetVal (offset)) != '\0') {
|
||||
while((c = ACS_GlobalArrays[a][offset]) != '\0') {
|
||||
work += (char)c;
|
||||
offset++;
|
||||
}
|
||||
|
|
539
src/tarray.h
539
src/tarray.h
|
@ -41,6 +41,8 @@
|
|||
#include "m_alloc.h"
|
||||
|
||||
|
||||
// TArray -------------------------------------------------------------------
|
||||
|
||||
template <class T>
|
||||
class TArray
|
||||
{
|
||||
|
@ -251,7 +253,7 @@ private:
|
|||
Array = (T *)M_Malloc (sizeof(T)*Most);
|
||||
for (unsigned int i = 0; i < Count; ++i)
|
||||
{
|
||||
Array[i] = other.Array[i];
|
||||
::new(&Array[i]) T(other.Array[i]);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -276,9 +278,10 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
// An array with accessors that automatically grow the
|
||||
// array as needed. But can still be used as a normal
|
||||
// TArray if needed. Used by ACS world and global arrays.
|
||||
// TAutoGrowArray -----------------------------------------------------------
|
||||
// An array with accessors that automatically grow the array as needed.
|
||||
// It can still be used as a normal TArray if needed. ACS uses this for
|
||||
// world and global arrays.
|
||||
|
||||
template <class 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__
|
||||
|
|
Loading…
Reference in a new issue