mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-11-15 08:41:59 +00:00
SVN r116 (trunk)
This commit is contained in:
parent
afd6a1258f
commit
ac53ed6ecd
25 changed files with 600 additions and 745 deletions
|
@ -270,7 +270,6 @@ ${COMPILER} "autostart.cpp \
|
|||
vectors.cpp \
|
||||
name.cpp \
|
||||
zstring.cpp \
|
||||
zstringpool.cpp \
|
||||
zstrformat.cpp \
|
||||
w_wad.cpp \
|
||||
wi_stuff.cpp \
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
May 15, 2006
|
||||
- Changed the memory management for FString. Instead of using a garbage
|
||||
collected heap, it now uses normal heap calls and reference counting to
|
||||
implement lazy copying. You may now use bitwise operators to move
|
||||
(but not copy!) FStrings around in memory. This means that the
|
||||
CopyForTArray template function is gone, since TArrays can now freely
|
||||
move their contents around without bothering with their specifics.
|
||||
|
||||
There is one important caveat, however. It is not acceptable to blindly 0
|
||||
an FString's contents. This necessitated the creation of a proper
|
||||
constructor for player_s so that it can be reset without using memset. I
|
||||
did a quick scan of all memsets in the source and didn't see anything else
|
||||
with a similar problem, but it's possible I missed something.
|
||||
- Fixed: Build tiles were never deallocated.
|
||||
- Fixed: Using Build's palette.dat only got half the palette right.
|
||||
|
||||
May 14, 2006 (Changes by Graf Zahl)
|
||||
- Added a show_obituaries option to disable obituaries without disabling
|
||||
other more important message types which have lower priority for some
|
||||
|
|
|
@ -64,7 +64,8 @@ void DCajunMaster::ClearPlayer (int i, bool keepTeam)
|
|||
bot->inuse = false;
|
||||
bot->lastteam = keepTeam ? players[i].userinfo.team : TEAM_None;
|
||||
}
|
||||
memset (&players[i], 0, sizeof(player_t));
|
||||
players[i].~player_t();
|
||||
::new(&players[i]) player_t;
|
||||
playeringame[i] = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -509,7 +509,7 @@ void C_SetDefaultBindings ()
|
|||
|
||||
BOOL C_DoKey (event_t *ev)
|
||||
{
|
||||
char *binding = NULL;
|
||||
FString binding;
|
||||
bool dclick;
|
||||
int dclickspot;
|
||||
byte dclickmask;
|
||||
|
@ -553,33 +553,27 @@ BOOL C_DoKey (event_t *ev)
|
|||
}
|
||||
|
||||
|
||||
if (binding == NULL || *binding==0)
|
||||
if (binding.IsEmpty())
|
||||
{
|
||||
binding = Bindings[ev->data1];
|
||||
dclick = false;
|
||||
}
|
||||
|
||||
if (binding != NULL && *binding!=0 && (chatmodeon == 0 || ev->data1 < 256))
|
||||
if (!binding.IsEmpty() && (chatmodeon == 0 || ev->data1 < 256))
|
||||
{
|
||||
if (ev->type == EV_KeyUp)
|
||||
if (ev->type == EV_KeyUp && binding[0] != '+')
|
||||
{
|
||||
if (binding[0] != '+')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
binding[0] = '-';
|
||||
return false;
|
||||
}
|
||||
|
||||
char *copy = binding.LockBuffer();
|
||||
|
||||
if (ev->type == EV_KeyUp)
|
||||
{
|
||||
copy[0] = '-';
|
||||
}
|
||||
|
||||
// Copy the command in case it rebinds the key
|
||||
char copy[1024];
|
||||
strncpy (copy, binding, 1023);
|
||||
copy[1023] = 0;
|
||||
AddCommandString (copy, dclick ? ev->data1 | KEY_DBLCLICKED : ev->data1);
|
||||
|
||||
if (ev->type == EV_KeyUp)
|
||||
{
|
||||
binding[0] = '+';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -711,7 +705,7 @@ void C_ChangeBinding (const char *str, int newone)
|
|||
}
|
||||
}
|
||||
|
||||
char *C_GetBinding (int key)
|
||||
const char *C_GetBinding (int key)
|
||||
{
|
||||
return (unsigned int)key < NUM_KEYS ? Bindings[key].GetChars() : NULL;
|
||||
}
|
||||
|
|
|
@ -53,6 +53,6 @@ void C_SetDefaultBindings ();
|
|||
void C_UnbindAll ();
|
||||
|
||||
// Returns string bound to given key (NULL if none)
|
||||
char *C_GetBinding (int key);
|
||||
const char *C_GetBinding (int key);
|
||||
|
||||
#endif //__C_BINDINGS_H__
|
||||
|
|
|
@ -146,7 +146,7 @@ void DefaultExtension (char *path, const char *extension)
|
|||
|
||||
void DefaultExtension (FString &path, const char *extension)
|
||||
{
|
||||
char *src = &path[int(path.Len())-1];
|
||||
const char *src = &path[int(path.Len())-1];
|
||||
|
||||
while (src != &path[0] && !IsSeperator(*src))
|
||||
{
|
||||
|
|
|
@ -83,6 +83,7 @@
|
|||
#include "gameconfigfile.h"
|
||||
#include "sbar.h"
|
||||
#include "decallib.h"
|
||||
#include "version.h"
|
||||
#include "r_polymost.h"
|
||||
#include "version.h"
|
||||
#include "v_text.h"
|
||||
|
@ -1409,7 +1410,6 @@ static EIWADType ScanIWAD (const char *iwad)
|
|||
static int CheckIWAD (const char *doomwaddir, WadStuff *wads)
|
||||
{
|
||||
const char *slash;
|
||||
char iwad[512];
|
||||
int i;
|
||||
int numfound;
|
||||
|
||||
|
@ -1422,8 +1422,10 @@ static int CheckIWAD (const char *doomwaddir, WadStuff *wads)
|
|||
{
|
||||
if (wads[i].Path.IsEmpty())
|
||||
{
|
||||
sprintf (iwad, "%s%s%s", doomwaddir, slash, IWADNames[i]);
|
||||
FixPathSeperator (iwad);
|
||||
FString iwad;
|
||||
|
||||
iwad.Format ("%s%s%s", doomwaddir, slash, IWADNames[i]);
|
||||
FixPathSeperator (iwad.LockBuffer());
|
||||
if (FileExists (iwad))
|
||||
{
|
||||
wads[i].Type = ScanIWAD (iwad);
|
||||
|
@ -1495,12 +1497,10 @@ static EIWADType IdentifyVersion (const char *zdoom_wad)
|
|||
bool iwadparmfound = false;
|
||||
FString custwad;
|
||||
|
||||
memset (wads, 0, sizeof(wads));
|
||||
|
||||
if (iwadparm)
|
||||
{
|
||||
custwad = iwadparm;
|
||||
FixPathSeperator (custwad.GetChars());
|
||||
FixPathSeperator (custwad.LockBuffer());
|
||||
if (CheckIWAD (custwad, wads))
|
||||
{ // -iwad parameter was a directory
|
||||
iwadparm = NULL;
|
||||
|
@ -1514,7 +1514,7 @@ static EIWADType IdentifyVersion (const char *zdoom_wad)
|
|||
}
|
||||
}
|
||||
|
||||
if (iwadparm == NULL || wads[0].Path == NULL)
|
||||
if (iwadparm == NULL || wads[0].Path.IsEmpty())
|
||||
{
|
||||
if (GameConfig->SetSection ("IWADSearch.Directories"))
|
||||
{
|
||||
|
@ -1552,7 +1552,7 @@ static EIWADType IdentifyVersion (const char *zdoom_wad)
|
|||
}
|
||||
}
|
||||
|
||||
if (iwadparm != NULL && wads[0].Path != NULL)
|
||||
if (iwadparm != NULL && !wads[0].Path.IsEmpty())
|
||||
{
|
||||
iwadparmfound = true;
|
||||
}
|
||||
|
@ -1612,17 +1612,19 @@ static EIWADType IdentifyVersion (const char *zdoom_wad)
|
|||
|
||||
if (wads[pickwad].Type == IWAD_Strife)
|
||||
{ // Try to load voices.wad along with strife1.wad
|
||||
char *filepart = strrchr (wads[pickwad].Path, '/');
|
||||
if (filepart == NULL)
|
||||
long lastslash = wads[pickwad].Path.LastIndexOf ('/');
|
||||
FString path;
|
||||
|
||||
if (lastslash == -1)
|
||||
{
|
||||
filepart = wads[pickwad].Path;
|
||||
path = wads[pickwad].Path;
|
||||
}
|
||||
else
|
||||
{
|
||||
++filepart;
|
||||
path = FString (wads[pickwad].Path, lastslash + 1);
|
||||
}
|
||||
strcpy (filepart, "voices.wad");
|
||||
D_AddFile (wads[pickwad].Path);
|
||||
path += "voices.wad";
|
||||
D_AddFile (path);
|
||||
}
|
||||
|
||||
return wads[pickwad].Type;
|
||||
|
|
|
@ -77,6 +77,8 @@ enum EIWADType
|
|||
|
||||
struct WadStuff
|
||||
{
|
||||
WadStuff() : Type(IWAD_Doom2TNT) {}
|
||||
|
||||
FString Path;
|
||||
EIWADType Type;
|
||||
};
|
||||
|
|
|
@ -2194,7 +2194,7 @@ void Net_DoCommand (int type, byte **stream, int player)
|
|||
{
|
||||
// Paths sent over the network will be valid for the system that sent
|
||||
// the save command. For other systems, the path needs to be changed.
|
||||
char *fileonly = savegamefile.GetChars();
|
||||
const char *fileonly = savegamefile.GetChars();
|
||||
char *slash = strrchr (fileonly, '\\');
|
||||
if (slash != NULL)
|
||||
{
|
||||
|
|
|
@ -155,6 +155,8 @@ enum
|
|||
class player_s
|
||||
{
|
||||
public:
|
||||
player_s();
|
||||
|
||||
void Serialize (FArchive &arc);
|
||||
void FixPointers (const DObject *obj, DObject *replacement);
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#include <stdlib.h>
|
||||
#include "tarray.h"
|
||||
#include "doomtype.h"
|
||||
#include "m_alloc.h"
|
||||
|
||||
struct PClass;
|
||||
|
||||
|
|
|
@ -738,7 +738,7 @@ BOOL G_Responder (event_t *ev)
|
|||
if (gameaction == ga_nothing &&
|
||||
(demoplayback || gamestate == GS_DEMOSCREEN || gamestate == GS_TITLELEVEL))
|
||||
{
|
||||
char *cmd = C_GetBinding (ev->data1);
|
||||
const char *cmd = C_GetBinding (ev->data1);
|
||||
|
||||
if (ev->type == EV_KeyDown)
|
||||
{
|
||||
|
@ -1118,7 +1118,7 @@ void G_PlayerReborn (int player)
|
|||
botskill_t b_skill;//Added by MC:
|
||||
APlayerPawn *actor;
|
||||
const PClass *cls;
|
||||
char *log;
|
||||
FString log;
|
||||
|
||||
p = &players[player];
|
||||
|
||||
|
@ -1134,7 +1134,9 @@ void G_PlayerReborn (int player)
|
|||
cls = p->cls;
|
||||
log = p->LogText;
|
||||
|
||||
memset (p, 0, sizeof(*p));
|
||||
// Reset player structure to its defaults
|
||||
p->~player_t();
|
||||
::new(p) player_t;
|
||||
|
||||
memcpy (p->frags, frags, sizeof(p->frags));
|
||||
p->fragcount = fragcount;
|
||||
|
@ -1483,7 +1485,7 @@ void G_ScreenShot (char *filename)
|
|||
// G_InitFromSavegame
|
||||
// Can be called by the startup code or the menu task.
|
||||
//
|
||||
void G_LoadGame (char* name)
|
||||
void G_LoadGame (const char* name)
|
||||
{
|
||||
if (name != NULL)
|
||||
{
|
||||
|
|
|
@ -37,7 +37,7 @@ void G_DeferedPlayDemo (char* demo);
|
|||
|
||||
// Can be called by the startup code or M_Responder,
|
||||
// calls P_SetupLevel or W_EnterWorld.
|
||||
void G_LoadGame (char* name);
|
||||
void G_LoadGame (const char* name);
|
||||
|
||||
void G_DoLoadGame (void);
|
||||
|
||||
|
|
|
@ -148,8 +148,6 @@ static void ReadMultiplePlayers (FArchive &arc, int numPlayers, int numPlayersNo
|
|||
BYTE *tempPlayerUsed = new BYTE[numPlayers];
|
||||
BYTE *playerUsed = new BYTE[MAXPLAYERS];
|
||||
|
||||
memset (playertemp, 0, numPlayers*sizeof(player_t));
|
||||
|
||||
for (i = 0; i < numPlayers; ++i)
|
||||
{
|
||||
nametemp[i] = NULL;
|
||||
|
|
|
@ -67,6 +67,102 @@ static TArray<sector_t *> PredictionTouchingSectorsBackup;
|
|||
|
||||
BOOL onground;
|
||||
|
||||
// The player_s constructor. Since LogText is not a POD, we cannot just
|
||||
// memset it all to 0.
|
||||
player_s::player_s()
|
||||
: mo(0),
|
||||
playerstate(0),
|
||||
cls(0),
|
||||
DesiredFOV(0),
|
||||
FOV(0),
|
||||
viewz(0),
|
||||
viewheight(0),
|
||||
defaultviewheight(0),
|
||||
deltaviewheight(0),
|
||||
bob(0),
|
||||
momx(0),
|
||||
momy(0),
|
||||
centering(0),
|
||||
turnticks(0),
|
||||
oldbuttons(0),
|
||||
attackdown(0),
|
||||
health(0),
|
||||
InvFirst(0),
|
||||
InvSel(0),
|
||||
inventorytics(0),
|
||||
CurrentPlayerClass(0),
|
||||
pieces(0),
|
||||
backpack(0),
|
||||
fragcount(0),
|
||||
lastkilltime(0),
|
||||
multicount(0),
|
||||
spreecount(0),
|
||||
ReadyWeapon(0),
|
||||
PendingWeapon(0),
|
||||
cheats(0),
|
||||
Powers(0),
|
||||
refire(0),
|
||||
inconsistant(0),
|
||||
killcount(0),
|
||||
itemcount(0),
|
||||
secretcount(0),
|
||||
damagecount(0),
|
||||
bonuscount(0),
|
||||
hazardcount(0),
|
||||
poisoncount(0),
|
||||
poisoner(0),
|
||||
attacker(0),
|
||||
extralight(0),
|
||||
xviewshift(0),
|
||||
morphTics(0),
|
||||
PremorphWeapon(0),
|
||||
chickenPeck(0),
|
||||
jumpTics(0),
|
||||
respawn_time(0),
|
||||
camera(0),
|
||||
air_finished(0),
|
||||
accuracy(0),
|
||||
stamina(0),
|
||||
savedyaw(0),
|
||||
savedpitch(0),
|
||||
angle(0),
|
||||
dest(0),
|
||||
prev(0),
|
||||
enemy(0),
|
||||
missile(0),
|
||||
mate(0),
|
||||
last_mate(0),
|
||||
t_active(0),
|
||||
t_respawn(0),
|
||||
t_strafe(0),
|
||||
t_react(0),
|
||||
t_fight(0),
|
||||
t_roam(0),
|
||||
t_rocket(0),
|
||||
isbot(0),
|
||||
first_shot(0),
|
||||
sleft(0),
|
||||
allround(0),
|
||||
oldx(0),
|
||||
oldy(0),
|
||||
skin(0),
|
||||
BlendR(0),
|
||||
BlendG(0),
|
||||
BlendB(0),
|
||||
BlendA(0),
|
||||
LogText(),
|
||||
crouching(0),
|
||||
crouchdir(0),
|
||||
crouchfactor(0),
|
||||
crouchoffset(0),
|
||||
crouchviewdelta(0)
|
||||
{
|
||||
memset (&cmd, 0, sizeof(cmd));
|
||||
memset (&userinfo, 0, sizeof(userinfo));
|
||||
memset (frags, 0, sizeof(frags));
|
||||
memset (psprites, 0, sizeof(psprites));
|
||||
memset (&skill, 0, sizeof(skill));
|
||||
}
|
||||
|
||||
// This function supplements the pointer cleanup in dobject.cpp, because
|
||||
// player_s is not derived from DObject. (I tried it, and DestroyScan was
|
||||
|
|
|
@ -93,7 +93,7 @@ byte** warpedflats;
|
|||
int* flatwarpedwhen;
|
||||
|
||||
|
||||
|
||||
static TArray<BYTE *> BuildTileFiles;
|
||||
FTextureManager TexMan;
|
||||
|
||||
FTextureManager::FTextureManager ()
|
||||
|
@ -2771,7 +2771,7 @@ void R_InitBuildTiles ()
|
|||
int slashat = rffpath.LastIndexOf ('/');
|
||||
if (slashat >= 0)
|
||||
{
|
||||
rffpath.Resize (slashat + 1);
|
||||
rffpath.Truncate (slashat + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -2793,8 +2793,6 @@ void R_InitBuildTiles ()
|
|||
break;
|
||||
}
|
||||
|
||||
// BADBAD: This memory is never explicitly deleted except when the
|
||||
// version number is wrong.
|
||||
int len = Q_filelength (f);
|
||||
BYTE *art = new BYTE[len];
|
||||
if (fread (art, 1, len, f) != len || LittleLong(*(DWORD *)art) != 1)
|
||||
|
@ -2803,6 +2801,7 @@ void R_InitBuildTiles ()
|
|||
}
|
||||
else
|
||||
{
|
||||
BuildTileFiles.Push (art);
|
||||
TexMan.AddTiles (art);
|
||||
}
|
||||
fclose (f);
|
||||
|
@ -2820,8 +2819,6 @@ void R_InitBuildTiles ()
|
|||
break;
|
||||
}
|
||||
|
||||
// BADBAD: This memory is never explicitly deleted except when the
|
||||
// version number is wrong.
|
||||
BYTE *art = new BYTE[Wads.LumpLength (lumpnum)];
|
||||
Wads.ReadLump (lumpnum, art);
|
||||
|
||||
|
@ -2831,11 +2828,20 @@ void R_InitBuildTiles ()
|
|||
}
|
||||
else
|
||||
{
|
||||
BuildTileFiles.Push (art);
|
||||
TexMan.AddTiles (art);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void R_DeinitBuildTiles ()
|
||||
{
|
||||
for (unsigned int i = 0; i < BuildTileFiles.Size(); ++i)
|
||||
{
|
||||
delete[] BuildTileFiles[i];
|
||||
}
|
||||
BuildTileFiles.Clear();
|
||||
}
|
||||
|
||||
static struct FakeCmap {
|
||||
char name[8];
|
||||
|
@ -3030,6 +3036,7 @@ void R_InitData ()
|
|||
void R_DeinitData ()
|
||||
{
|
||||
R_DeinitColormaps ();
|
||||
R_DeinitBuildTiles();
|
||||
|
||||
// Free openings
|
||||
if (openings != NULL)
|
||||
|
|
|
@ -81,13 +81,6 @@ struct FRandomSoundList
|
|||
WORD NumSounds;
|
||||
};
|
||||
|
||||
template<>
|
||||
void CopyForTArray<FRandomSoundList> (FRandomSoundList &dst, FRandomSoundList &src)
|
||||
{
|
||||
dst = src;
|
||||
}
|
||||
|
||||
|
||||
struct FPlayerClassLookup
|
||||
{
|
||||
char Name[MAX_SNDNAME+1];
|
||||
|
|
|
@ -417,14 +417,15 @@ bool TimiditySong::ValidateTimidity ()
|
|||
|
||||
bool TimiditySong::LaunchTimidity ()
|
||||
{
|
||||
if (CommandLine.Len() == 0)
|
||||
if (CommandLine.IsEmpty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Tell Timidity whether it should loop or not
|
||||
CommandLine[LoopPos] = m_Looping ? 'l' : ' ';
|
||||
DPrintf ("cmd: \x1cG%s\n", CommandLine.GetChars());
|
||||
char *cmdline = CommandLine.LockBuffer();
|
||||
cmdline[LoopPos] = m_Looping ? 'l' : ' ';
|
||||
DPrintf ("cmd: \x1cG%s\n", cmdline);
|
||||
|
||||
#ifdef _WIN32
|
||||
STARTUPINFO startup = { sizeof(startup), };
|
||||
|
@ -440,14 +441,16 @@ bool TimiditySong::LaunchTimidity ()
|
|||
startup.lpTitle = "TiMidity (ZDoom Launched)";
|
||||
startup.wShowWindow = SW_SHOWMINNOACTIVE;
|
||||
|
||||
if (CreateProcess (NULL, CommandLine.GetChars(), NULL, NULL, TRUE,
|
||||
if (CreateProcess (NULL, cmdline, NULL, NULL, TRUE,
|
||||
/*HIGH_PRIORITY_CLASS|*/DETACHED_PROCESS, NULL, NULL, &startup, &procInfo))
|
||||
{
|
||||
ChildProcess = procInfo.hProcess;
|
||||
//SetThreadPriority (procInfo.hThread, THREAD_PRIORITY_HIGHEST);
|
||||
CloseHandle (procInfo.hThread); // Don't care about the created thread
|
||||
CommandLine.UnlockBuffer();
|
||||
return true;
|
||||
}
|
||||
CommandLine.UnlockBuffer();
|
||||
|
||||
char hres[9];
|
||||
LPTSTR msgBuf;
|
||||
|
|
68
src/tarray.h
68
src/tarray.h
|
@ -38,37 +38,9 @@
|
|||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <new>
|
||||
|
||||
#include "m_alloc.h"
|
||||
|
||||
|
||||
// This function is called once for each entry in the TArray after it grows.
|
||||
// The old entries will be immediately freed afterwards, so if they need to
|
||||
// be destroyed, it needs to happen in this function.
|
||||
template<class T>
|
||||
void CopyForTArray (T &dst, T &src)
|
||||
{
|
||||
::new((void*)&dst) T(src);
|
||||
src.~T();
|
||||
}
|
||||
|
||||
// This function is called by Push to copy the the element to an unconstructed
|
||||
// area of memory. Basically, if NeedsDestructor is overloaded to return true,
|
||||
// then this should be overloaded to use placement new.
|
||||
template<class T>
|
||||
void ConstructInTArray (T *dst, const T &src)
|
||||
{
|
||||
::new((void*)dst) T(src);
|
||||
}
|
||||
|
||||
// This function is much like the above function, except it is called when
|
||||
// the array is explicitly enlarged without using Push.
|
||||
template<class T>
|
||||
void ConstructEmptyInTArray (T *dst)
|
||||
{
|
||||
::new((void*)dst) T;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class TArray
|
||||
{
|
||||
|
@ -140,7 +112,7 @@ public:
|
|||
unsigned int Push (const T &item)
|
||||
{
|
||||
Grow (1);
|
||||
ConstructInTArray (&Array[Count], item);
|
||||
::new((void*)&Array[Count]) T(item);
|
||||
return Count++;
|
||||
}
|
||||
bool Pop (T &item)
|
||||
|
@ -148,7 +120,7 @@ public:
|
|||
if (Count > 0)
|
||||
{
|
||||
item = Array[--Count];
|
||||
DoDelete (Count, Count);
|
||||
Array[Count].~T();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -157,12 +129,9 @@ public:
|
|||
{
|
||||
if (index < Count)
|
||||
{
|
||||
for (unsigned int i = index; i < Count - 1; ++i)
|
||||
{
|
||||
Array[i] = Array[i+1];
|
||||
}
|
||||
Array[index].~T();
|
||||
memmove (&Array[index], &Array[index+1], Count - index - 1);
|
||||
Count--;
|
||||
DoDelete (Count, Count);
|
||||
}
|
||||
}
|
||||
// Inserts an item into the array, shifting elements as needed
|
||||
|
@ -173,24 +142,19 @@ public:
|
|||
// Inserting somewhere past the end of the array, so we can
|
||||
// just add it without moving things.
|
||||
Resize (index + 1);
|
||||
ConstructInTArray (&Array[index], item);
|
||||
::new ((void *)&Array[index]) T(item);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Inserting somewhere in the middle of the array, so make
|
||||
// room for it and shift old entries out of the way.
|
||||
|
||||
// Inserting somewhere in the middle of the array,
|
||||
// so make room for it
|
||||
Resize (Count + 1);
|
||||
|
||||
// Now copy items from the index and onward
|
||||
for (unsigned int i = Count - 1; i-- > index; )
|
||||
{
|
||||
Array[i+1] = Array[i];
|
||||
}
|
||||
// Now move items from the index and onward out of the way
|
||||
memmove (&Array[index+1], &Array[index], sizeof(T)*(Count - index - 1));
|
||||
|
||||
// Now put the new element in
|
||||
DoDelete (index, index);
|
||||
ConstructInTArray (&Array[index], item);
|
||||
// And put the new element in
|
||||
::new ((void *)&Array[index]) T(item);
|
||||
}
|
||||
}
|
||||
void ShrinkToFit ()
|
||||
|
@ -233,7 +197,7 @@ public:
|
|||
Grow (amount - Count);
|
||||
for (unsigned int i = Count; i < amount; ++i)
|
||||
{
|
||||
ConstructEmptyInTArray (&Array[i]);
|
||||
::new((void *)&Array[i]) T;
|
||||
}
|
||||
}
|
||||
else if (Count != amount)
|
||||
|
@ -293,13 +257,7 @@ private:
|
|||
void DoResize ()
|
||||
{
|
||||
size_t allocsize = sizeof(T)*Most;
|
||||
T *newarray = (T *)M_Malloc (allocsize);
|
||||
for (unsigned int i = 0; i < Count; ++i)
|
||||
{
|
||||
CopyForTArray (newarray[i], Array[i]);
|
||||
}
|
||||
free (Array);
|
||||
Array = newarray;
|
||||
Array = (T *)M_Realloc (Array, allocsize);
|
||||
}
|
||||
|
||||
void DoDelete (unsigned int first, unsigned int last)
|
||||
|
|
|
@ -311,13 +311,10 @@ static bool FixBuildPalette (BYTE *opal, int lump, bool blood)
|
|||
// Reverse the palette because BUILD used entry 255 as
|
||||
// transparent, but we use 0 as transparent.
|
||||
|
||||
for (int c = 0; c < 768/2; c += 3)
|
||||
for (int c = 0; c < 768; c += 3)
|
||||
{
|
||||
if (!blood)
|
||||
{
|
||||
opal[765-c] = (ipal[0] << 2) | (ipal[0] >> 4);
|
||||
opal[766-c] = (ipal[1] << 2) | (ipal[1] >> 4);
|
||||
opal[767-c] = (ipal[2] << 2) | (ipal[2] >> 4);
|
||||
opal[c] = (ipal[765-c] << 2) | (ipal[765-c] >> 4);
|
||||
opal[c+1] = (ipal[766-c] << 2) | (ipal[766-c] >> 4);
|
||||
opal[c+2] = (ipal[767-c] << 2) | (ipal[767-c] >> 4);
|
||||
|
@ -327,9 +324,6 @@ static bool FixBuildPalette (BYTE *opal, int lump, bool blood)
|
|||
opal[c] = ipal[765-c];
|
||||
opal[c+1] = ipal[766-c];
|
||||
opal[c+2] = ipal[767-c];
|
||||
opal[765-c] = ipal[c];
|
||||
opal[766-c] = ipal[c+1];
|
||||
opal[767-c] = ipal[c+2];
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -634,7 +634,7 @@ BOOL CALLBACK IWADBoxCallback (HWND hDlg, UINT message, WPARAM wParam, LPARAM lP
|
|||
for (i = 0; i < NumWads; i++)
|
||||
{
|
||||
char work[256];
|
||||
char *filepart = strrchr (WadList[i].Path, '/');
|
||||
const char *filepart = strrchr (WadList[i].Path, '/');
|
||||
if (filepart == NULL)
|
||||
filepart = WadList[i].Path;
|
||||
else
|
||||
|
|
430
src/zstring.cpp
430
src/zstring.cpp
|
@ -1,39 +1,74 @@
|
|||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <new> // for bad_alloc
|
||||
|
||||
#include "zstring.h"
|
||||
|
||||
|
||||
FString::FString (size_t len)
|
||||
FNullStringData FString::NullString =
|
||||
{
|
||||
Chars = Pond.Alloc (this, len);
|
||||
0, // Length of string
|
||||
2, // Size of character buffer
|
||||
2, // RefCount; it must never be modified, so keep it above 1 user at all times
|
||||
"\0"
|
||||
};
|
||||
|
||||
void FString::AttachToOther (const FString &other)
|
||||
{
|
||||
assert (other.Chars != NULL);
|
||||
|
||||
if (other.Data()->RefCount < 0)
|
||||
{
|
||||
AllocBuffer (other.Data()->Len);
|
||||
StrCopy (Chars, other.Chars, other.Data()->Len);
|
||||
}
|
||||
else
|
||||
{
|
||||
Chars = const_cast<FString &>(other).Data()->AddRef();
|
||||
}
|
||||
}
|
||||
|
||||
FString::FString (const char *copyStr)
|
||||
{
|
||||
size_t len = strlen (copyStr);
|
||||
Chars = Pond.Alloc (this, len);
|
||||
StrCopy (Chars, copyStr, len);
|
||||
if (copyStr == NULL || *copyStr == '\0')
|
||||
{
|
||||
NullString.RefCount++;
|
||||
Chars = &NullString.Nothing[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t len = strlen (copyStr);
|
||||
AllocBuffer (len);
|
||||
StrCopy (Chars, copyStr, len);
|
||||
}
|
||||
}
|
||||
|
||||
FString::FString (const char *copyStr, size_t len)
|
||||
{
|
||||
Chars = Pond.Alloc (this, len);
|
||||
AllocBuffer (len);
|
||||
StrCopy (Chars, copyStr, len);
|
||||
}
|
||||
|
||||
FString::FString (char oneChar)
|
||||
{
|
||||
Chars = Pond.Alloc (this, 1);
|
||||
Chars[0] = oneChar;
|
||||
Chars[1] = '\0';
|
||||
if (oneChar == '\0')
|
||||
{
|
||||
NullString.RefCount++;
|
||||
Chars = &NullString.Nothing[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
AllocBuffer (1);
|
||||
Chars[0] = oneChar;
|
||||
Chars[1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
FString::FString (const FString &head, const FString &tail)
|
||||
{
|
||||
size_t len1 = head.Len();
|
||||
size_t len2 = tail.Len();
|
||||
Chars = Pond.Alloc (this, len1 + len2);
|
||||
AllocBuffer (len1 + len2);
|
||||
StrCopy (Chars, head);
|
||||
StrCopy (Chars + len1, tail);
|
||||
}
|
||||
|
@ -42,7 +77,7 @@ FString::FString (const FString &head, const char *tail)
|
|||
{
|
||||
size_t len1 = head.Len();
|
||||
size_t len2 = strlen (tail);
|
||||
Chars = Pond.Alloc (this, len1 + len2);
|
||||
AllocBuffer (len1 + len2);
|
||||
StrCopy (Chars, head);
|
||||
StrCopy (Chars + len1, tail, len2);
|
||||
}
|
||||
|
@ -50,7 +85,7 @@ FString::FString (const FString &head, const char *tail)
|
|||
FString::FString (const FString &head, char tail)
|
||||
{
|
||||
size_t len1 = head.Len();
|
||||
Chars = Pond.Alloc (this, len1 + 1);
|
||||
AllocBuffer (len1 + 1);
|
||||
StrCopy (Chars, head);
|
||||
Chars[len1] = tail;
|
||||
Chars[len1+1] = '\0';
|
||||
|
@ -60,7 +95,7 @@ FString::FString (const char *head, const FString &tail)
|
|||
{
|
||||
size_t len1 = strlen (head);
|
||||
size_t len2 = tail.Len();
|
||||
Chars = Pond.Alloc (this, len1 + len2);
|
||||
AllocBuffer (len1 + len2);
|
||||
StrCopy (Chars, head, len1);
|
||||
StrCopy (Chars + len1, tail);
|
||||
}
|
||||
|
@ -69,7 +104,7 @@ FString::FString (const char *head, const char *tail)
|
|||
{
|
||||
size_t len1 = strlen (head);
|
||||
size_t len2 = strlen (tail);
|
||||
Chars = Pond.Alloc (this, len1 + len2);
|
||||
AllocBuffer (len1 + len2);
|
||||
StrCopy (Chars, head, len1);
|
||||
StrCopy (Chars + len1, tail, len2);
|
||||
}
|
||||
|
@ -77,62 +112,76 @@ FString::FString (const char *head, const char *tail)
|
|||
FString::FString (char head, const FString &tail)
|
||||
{
|
||||
size_t len2 = tail.Len();
|
||||
Chars = Pond.Alloc (this, 1 + len2);
|
||||
AllocBuffer (1 + len2);
|
||||
Chars[0] = head;
|
||||
StrCopy (Chars + 1, tail);
|
||||
}
|
||||
|
||||
FString::~FString ()
|
||||
{
|
||||
if (Chars != NULL)
|
||||
Data()->Release();
|
||||
}
|
||||
|
||||
char *FString::LockBuffer()
|
||||
{
|
||||
if (Data()->RefCount == 1)
|
||||
{ // We're the only user, so we can lock it straight away
|
||||
Data()->RefCount = -1;
|
||||
}
|
||||
else if (Data()->RefCount < -1)
|
||||
{ // Already locked; just add to the lock count
|
||||
Data()->RefCount--;
|
||||
}
|
||||
else
|
||||
{ // Somebody else is also using this character buffer, so create a copy
|
||||
FStringData *old = Data();
|
||||
AllocBuffer (old->Len);
|
||||
StrCopy (Chars, old->Chars(), old->Len);
|
||||
old->Release();
|
||||
}
|
||||
return Chars;
|
||||
}
|
||||
|
||||
void FString::UnlockBuffer()
|
||||
{
|
||||
assert (Data()->RefCount < 0);
|
||||
|
||||
if (++Data()->RefCount == 0)
|
||||
{
|
||||
Pond.Free (Chars);
|
||||
Chars = NULL;
|
||||
Data()->RefCount = 1;
|
||||
}
|
||||
}
|
||||
|
||||
FString &FString::operator = (const FString &other)
|
||||
{
|
||||
if (Chars != NULL)
|
||||
assert (Chars != NULL);
|
||||
|
||||
if (&other != this)
|
||||
{
|
||||
Pond.Free (Chars);
|
||||
}
|
||||
if (other.Chars == NULL)
|
||||
{
|
||||
Chars = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
Chars = Pond.Alloc (this, other.GetHeader()->Len);
|
||||
StrCopy (Chars, other);
|
||||
int oldrefcount = Data()->RefCount < 0;
|
||||
Data()->Release();
|
||||
AttachToOther(other);
|
||||
if (oldrefcount < 0)
|
||||
{
|
||||
LockBuffer();
|
||||
Data()->RefCount = oldrefcount;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
FString &FString::operator = (const char *copyStr)
|
||||
{
|
||||
if (Chars != NULL)
|
||||
Data()->Release();
|
||||
if (copyStr == NULL || *copyStr == '\0')
|
||||
{
|
||||
Pond.Free (Chars);
|
||||
}
|
||||
if (copyStr == NULL)
|
||||
{
|
||||
Chars = NULL;
|
||||
NullString.RefCount++;
|
||||
Chars = &NullString.Nothing[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t len = strlen (copyStr);
|
||||
/*
|
||||
if (len == 0)
|
||||
{
|
||||
Chars = NULL;
|
||||
}
|
||||
else
|
||||
*/
|
||||
{
|
||||
Chars = Pond.Alloc (this, len);
|
||||
StrCopy (Chars, copyStr, len);
|
||||
}
|
||||
AllocBuffer (len);
|
||||
StrCopy (Chars, copyStr, len);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
@ -147,11 +196,8 @@ void FString::Format (const char *fmt, ...)
|
|||
|
||||
void FString::VFormat (const char *fmt, va_list arglist)
|
||||
{
|
||||
if (Chars != NULL)
|
||||
{
|
||||
Pond.Free (Chars);
|
||||
}
|
||||
Chars = NULL;
|
||||
Data()->Release();
|
||||
Chars = (char *)(FStringData::Alloc(128) + 1);
|
||||
StringFormat::VWorker (FormatHelper, this, fmt, arglist);
|
||||
}
|
||||
|
||||
|
@ -159,8 +205,12 @@ int FString::FormatHelper (void *data, const char *cstr, int len)
|
|||
{
|
||||
FString *str = (FString *)data;
|
||||
size_t len1 = str->Len();
|
||||
str->Chars = Pond.Realloc (str, str->Chars, len1 + len);
|
||||
if (len1 + len > str->Data()->AllocLen)
|
||||
{
|
||||
str->Chars = (char *)(str->Data()->Realloc((len1 + len + 127) & ~127) + 1);
|
||||
}
|
||||
StrCopy (str->Chars + len1, cstr, len);
|
||||
str->Data()->Len = (unsigned int)(len1 + len);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
@ -193,7 +243,7 @@ FString &FString::operator += (const FString &tail)
|
|||
{
|
||||
size_t len1 = Len();
|
||||
size_t len2 = tail.Len();
|
||||
Chars = Pond.Realloc (this, Chars, len1 + len2);
|
||||
ReallocBuffer (len1 + len2);
|
||||
StrCopy (Chars + len1, tail);
|
||||
return *this;
|
||||
}
|
||||
|
@ -202,7 +252,7 @@ FString &FString::operator += (const char *tail)
|
|||
{
|
||||
size_t len1 = Len();
|
||||
size_t len2 = strlen(tail);
|
||||
Chars = Pond.Realloc (this, Chars, len1 + len2);
|
||||
ReallocBuffer (len1 + len2);
|
||||
StrCopy (Chars + len1, tail, len2);
|
||||
return *this;
|
||||
}
|
||||
|
@ -210,17 +260,17 @@ FString &FString::operator += (const char *tail)
|
|||
FString &FString::operator += (char tail)
|
||||
{
|
||||
size_t len1 = Len();
|
||||
Chars = Pond.Realloc (this, Chars, len1 + 1);
|
||||
ReallocBuffer (len1 + 1);
|
||||
Chars[len1] = tail;
|
||||
Chars[len1+1] = '\0';
|
||||
return *this;
|
||||
}
|
||||
|
||||
void FString::Resize (long newlen)
|
||||
void FString::Truncate (long newlen)
|
||||
{
|
||||
if (newlen >= 0)
|
||||
if (newlen >= 0 && newlen < (long)Len())
|
||||
{
|
||||
Chars = Pond.Realloc (this, Chars, newlen);
|
||||
ReallocBuffer (newlen);
|
||||
Chars[newlen] = '\0';
|
||||
}
|
||||
}
|
||||
|
@ -250,7 +300,7 @@ FString FString::Mid (size_t pos, size_t numChars) const
|
|||
size_t len = Len();
|
||||
if (pos >= len)
|
||||
{
|
||||
return FString("");
|
||||
return FString();
|
||||
}
|
||||
if (pos + numChars > len)
|
||||
{
|
||||
|
@ -402,24 +452,29 @@ long FString::LastIndexOfAny (const char *charset, long endIndex) const
|
|||
|
||||
void FString::ToUpper ()
|
||||
{
|
||||
LockBuffer();
|
||||
size_t max = Len();
|
||||
for (size_t i = 0; i < max; ++i)
|
||||
{
|
||||
Chars[i] = toupper(Chars[i]);
|
||||
}
|
||||
UnlockBuffer();
|
||||
}
|
||||
|
||||
void FString::ToLower ()
|
||||
{
|
||||
LockBuffer();
|
||||
size_t max = Len();
|
||||
for (size_t i = 0; i < max; ++i)
|
||||
{
|
||||
Chars[i] = tolower(Chars[i]);
|
||||
}
|
||||
UnlockBuffer();
|
||||
}
|
||||
|
||||
void FString::SwapCase ()
|
||||
{
|
||||
LockBuffer();
|
||||
size_t max = Len();
|
||||
for (size_t i = 0; i < max; ++i)
|
||||
{
|
||||
|
@ -432,6 +487,7 @@ void FString::SwapCase ()
|
|||
Chars[i] = toupper(Chars[i]);
|
||||
}
|
||||
}
|
||||
UnlockBuffer();
|
||||
}
|
||||
|
||||
void FString::StripLeft ()
|
||||
|
@ -442,11 +498,21 @@ void FString::StripLeft ()
|
|||
if (!isspace(Chars[i]))
|
||||
break;
|
||||
}
|
||||
for (j = 0; i <= max; ++j, ++i)
|
||||
if (Data()->RefCount <= 1)
|
||||
{
|
||||
Chars[j] = Chars[i];
|
||||
for (j = 0; i <= max; ++j, ++i)
|
||||
{
|
||||
Chars[j] = Chars[i];
|
||||
}
|
||||
ReallocBuffer (j-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
FStringData *old = Data();
|
||||
AllocBuffer (max - i);
|
||||
StrCopy (Chars, old->Chars() + i, max - i);
|
||||
old->Release();
|
||||
}
|
||||
Pond.Realloc (this, Chars, j-1);
|
||||
}
|
||||
|
||||
void FString::StripLeft (const FString &charset)
|
||||
|
@ -462,11 +528,21 @@ void FString::StripLeft (const char *charset)
|
|||
if (!strchr (charset, Chars[i]))
|
||||
break;
|
||||
}
|
||||
for (j = 0; i <= max; ++j, ++i)
|
||||
if (Data()->RefCount <= 1)
|
||||
{
|
||||
Chars[j] = Chars[i];
|
||||
for (j = 0; i <= max; ++j, ++i)
|
||||
{
|
||||
Chars[j] = Chars[i];
|
||||
}
|
||||
ReallocBuffer (j-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
FStringData *old = Data();
|
||||
AllocBuffer (max - i);
|
||||
StrCopy (Chars, old->Chars() + i, max - i);
|
||||
old->Release();
|
||||
}
|
||||
Pond.Realloc (this, Chars, j-1);
|
||||
}
|
||||
|
||||
void FString::StripRight ()
|
||||
|
@ -477,8 +553,18 @@ void FString::StripRight ()
|
|||
if (!isspace(Chars[i]))
|
||||
break;
|
||||
}
|
||||
Chars[i+1] = '\0';
|
||||
Pond.Realloc (this, Chars, i+1);
|
||||
if (Data()->RefCount <= 1)
|
||||
{
|
||||
Chars[i+1] = '\0';
|
||||
ReallocBuffer (i+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
FStringData *old = Data();
|
||||
AllocBuffer (i+1);
|
||||
StrCopy (Chars, old->Chars(), i+1);
|
||||
old->Release();
|
||||
}
|
||||
}
|
||||
|
||||
void FString::StripRight (const FString &charset)
|
||||
|
@ -494,8 +580,18 @@ void FString::StripRight (const char *charset)
|
|||
if (!strchr (charset, Chars[i]))
|
||||
break;
|
||||
}
|
||||
Chars[i+1] = '\0';
|
||||
Pond.Realloc (this, Chars, i+1);
|
||||
if (Data()->RefCount <= 1)
|
||||
{
|
||||
Chars[i+1] = '\0';
|
||||
ReallocBuffer (i+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
FStringData *old = Data();
|
||||
AllocBuffer (i+1);
|
||||
StrCopy (Chars, old->Chars(), i+1);
|
||||
old->Release();
|
||||
}
|
||||
}
|
||||
|
||||
void FString::StripLeftRight ()
|
||||
|
@ -511,17 +607,27 @@ void FString::StripLeftRight ()
|
|||
if (!isspace(Chars[j]))
|
||||
break;
|
||||
}
|
||||
for (k = 0; i <= j; ++i, ++k)
|
||||
if (Data()->RefCount <= 1)
|
||||
{
|
||||
Chars[k] = Chars[i];
|
||||
for (k = 0; i <= j; ++i, ++k)
|
||||
{
|
||||
Chars[k] = Chars[i];
|
||||
}
|
||||
Chars[k] = '\0';
|
||||
ReallocBuffer (k);
|
||||
}
|
||||
else
|
||||
{
|
||||
FStringData *old = Data();
|
||||
AllocBuffer (j - i);
|
||||
StrCopy (Chars, old->Chars(), j - i);
|
||||
old->Release();
|
||||
}
|
||||
Chars[k] = '\0';
|
||||
Pond.Realloc (this, Chars, k);
|
||||
}
|
||||
|
||||
void FString::StripLeftRight (const FString &charset)
|
||||
{
|
||||
return StripLeft (charset.Chars);
|
||||
return StripLeftRight (charset.Chars);
|
||||
}
|
||||
|
||||
void FString::StripLeftRight (const char *charset)
|
||||
|
@ -537,12 +643,22 @@ void FString::StripLeftRight (const char *charset)
|
|||
if (!strchr (charset, Chars[j]))
|
||||
break;
|
||||
}
|
||||
for (k = 0; i <= j; ++i, ++k)
|
||||
if (Data()->RefCount <= 1)
|
||||
{
|
||||
Chars[k] = Chars[i];
|
||||
for (k = 0; i <= j; ++i, ++k)
|
||||
{
|
||||
Chars[k] = Chars[i];
|
||||
}
|
||||
Chars[k] = '\0';
|
||||
ReallocBuffer (k);
|
||||
}
|
||||
else
|
||||
{
|
||||
FStringData *old = Data();
|
||||
AllocBuffer (j - i);
|
||||
StrCopy (Chars, old->Chars(), j - i);
|
||||
old->Release();
|
||||
}
|
||||
Chars[k] = '\0';
|
||||
Pond.Realloc (this, Chars, k);
|
||||
}
|
||||
|
||||
void FString::Insert (size_t index, const FString &instr)
|
||||
|
@ -562,21 +678,28 @@ void FString::Insert (size_t index, const char *instr, size_t instrlen)
|
|||
{
|
||||
index = mylen;
|
||||
}
|
||||
Pond.Realloc (this, Chars, mylen + instrlen);
|
||||
if (index < mylen)
|
||||
if (Data()->RefCount <= 1)
|
||||
{
|
||||
ReallocBuffer (mylen + instrlen);
|
||||
memmove (Chars + index + instrlen, Chars + index, (mylen - index + 1)*sizeof(char));
|
||||
memcpy (Chars + index, instr, instrlen*sizeof(char));
|
||||
}
|
||||
memcpy (Chars + index, instr, instrlen*sizeof(char));
|
||||
if (index == mylen)
|
||||
else
|
||||
{
|
||||
Chars[mylen + instrlen] = '\0';
|
||||
FStringData *old = Data();
|
||||
AllocBuffer (mylen + instrlen);
|
||||
StrCopy (Chars, old->Chars(), index);
|
||||
StrCopy (Chars + index, instr, instrlen);
|
||||
StrCopy (Chars + index + instrlen, Chars + index, mylen - index + 1);
|
||||
old->Release();
|
||||
}
|
||||
}
|
||||
|
||||
void FString::ReplaceChars (char oldchar, char newchar)
|
||||
{
|
||||
size_t i, j;
|
||||
|
||||
LockBuffer();
|
||||
for (i = 0, j = Len(); i < j; ++i)
|
||||
{
|
||||
if (Chars[i] == oldchar)
|
||||
|
@ -584,11 +707,14 @@ void FString::ReplaceChars (char oldchar, char newchar)
|
|||
Chars[i] = newchar;
|
||||
}
|
||||
}
|
||||
UnlockBuffer();
|
||||
}
|
||||
|
||||
void FString::ReplaceChars (const char *oldcharset, char newchar)
|
||||
{
|
||||
size_t i, j;
|
||||
|
||||
LockBuffer();
|
||||
for (i = 0, j = Len(); i < j; ++i)
|
||||
{
|
||||
if (strchr (oldcharset, Chars[i]) != NULL)
|
||||
|
@ -596,11 +722,14 @@ void FString::ReplaceChars (const char *oldcharset, char newchar)
|
|||
Chars[i] = newchar;
|
||||
}
|
||||
}
|
||||
UnlockBuffer();
|
||||
}
|
||||
|
||||
void FString::StripChars (char killchar)
|
||||
{
|
||||
size_t read, write, mylen;
|
||||
|
||||
LockBuffer();
|
||||
for (read = write = 0, mylen = Len(); read < mylen; ++read)
|
||||
{
|
||||
if (Chars[read] != killchar)
|
||||
|
@ -609,12 +738,15 @@ void FString::StripChars (char killchar)
|
|||
}
|
||||
}
|
||||
Chars[write] = '\0';
|
||||
Pond.Realloc (this, Chars, write);
|
||||
ReallocBuffer (write);
|
||||
UnlockBuffer();
|
||||
}
|
||||
|
||||
void FString::StripChars (const char *killchars)
|
||||
{
|
||||
size_t read, write, mylen;
|
||||
|
||||
LockBuffer();
|
||||
for (read = write = 0, mylen = Len(); read < mylen; ++read)
|
||||
{
|
||||
if (strchr (killchars, Chars[read]) == NULL)
|
||||
|
@ -623,7 +755,8 @@ void FString::StripChars (const char *killchars)
|
|||
}
|
||||
}
|
||||
Chars[write] = '\0';
|
||||
Pond.Realloc (this, Chars, write);
|
||||
ReallocBuffer (write);
|
||||
UnlockBuffer();
|
||||
}
|
||||
|
||||
void FString::MergeChars (char merger)
|
||||
|
@ -634,6 +767,8 @@ void FString::MergeChars (char merger)
|
|||
void FString::MergeChars (char merger, char newchar)
|
||||
{
|
||||
size_t read, write, mylen;
|
||||
|
||||
LockBuffer();
|
||||
for (read = write = 0, mylen = Len(); read < mylen; )
|
||||
{
|
||||
if (Chars[read] == merger)
|
||||
|
@ -649,12 +784,15 @@ void FString::MergeChars (char merger, char newchar)
|
|||
}
|
||||
}
|
||||
Chars[write] = '\0';
|
||||
Pond.Realloc (this, Chars, write);
|
||||
ReallocBuffer (write);
|
||||
UnlockBuffer();
|
||||
}
|
||||
|
||||
void FString::MergeChars (const char *charset, char newchar)
|
||||
{
|
||||
size_t read, write, mylen;
|
||||
|
||||
LockBuffer();
|
||||
for (read = write = 0, mylen = Len(); read < mylen; )
|
||||
{
|
||||
if (strchr (charset, Chars[read]) != NULL)
|
||||
|
@ -670,7 +808,8 @@ void FString::MergeChars (const char *charset, char newchar)
|
|||
}
|
||||
}
|
||||
Chars[write] = '\0';
|
||||
Pond.Realloc (this, Chars, write);
|
||||
ReallocBuffer (write);
|
||||
UnlockBuffer();
|
||||
}
|
||||
|
||||
void FString::Substitute (const FString &oldstr, const FString &newstr)
|
||||
|
@ -695,6 +834,7 @@ void FString::Substitute (const char *oldstr, const char *newstr)
|
|||
|
||||
void FString::Substitute (const char *oldstr, const char *newstr, size_t oldstrlen, size_t newstrlen)
|
||||
{
|
||||
LockBuffer();
|
||||
for (size_t checkpt = 0; checkpt < Len(); )
|
||||
{
|
||||
char *match = strstr (Chars + checkpt, oldstr);
|
||||
|
@ -704,7 +844,7 @@ void FString::Substitute (const char *oldstr, const char *newstr, size_t oldstrl
|
|||
size_t matchpt = match - Chars;
|
||||
if (oldstrlen != newstrlen)
|
||||
{
|
||||
Pond.Realloc (this, Chars, len + newstrlen - oldstrlen);
|
||||
ReallocBuffer (len + newstrlen - oldstrlen);
|
||||
memmove (Chars + matchpt + newstrlen, Chars + matchpt + oldstrlen, (len + 1 - matchpt - oldstrlen)*sizeof(char));
|
||||
}
|
||||
memcpy (Chars + matchpt, newstr, newstrlen);
|
||||
|
@ -715,6 +855,7 @@ void FString::Substitute (const char *oldstr, const char *newstr, size_t oldstrl
|
|||
break;
|
||||
}
|
||||
}
|
||||
UnlockBuffer();
|
||||
}
|
||||
|
||||
bool FString::IsInt () const
|
||||
|
@ -842,12 +983,6 @@ double FString::ToDouble () const
|
|||
return strtod (Chars, NULL);
|
||||
}
|
||||
|
||||
FString::StringHeader *FString::GetHeader () const
|
||||
{
|
||||
if (Chars == NULL) return NULL;
|
||||
return (StringHeader *)(Chars - sizeof(StringHeader));
|
||||
}
|
||||
|
||||
void FString::StrCopy (char *to, const char *from, size_t len)
|
||||
{
|
||||
memcpy (to, from, len*sizeof(char));
|
||||
|
@ -858,3 +993,106 @@ void FString::StrCopy (char *to, const FString &from)
|
|||
{
|
||||
StrCopy (to, from.Chars, from.Len());
|
||||
}
|
||||
|
||||
void FString::AllocBuffer (size_t len)
|
||||
{
|
||||
Chars = (char *)(FStringData::Alloc(len) + 1);
|
||||
Data()->Len = (unsigned int)len;
|
||||
}
|
||||
|
||||
void FString::ReallocBuffer (size_t newlen)
|
||||
{
|
||||
if (Data()->RefCount > 1)
|
||||
{ // If more than one reference, we must use a new copy
|
||||
FStringData *old = Data();
|
||||
AllocBuffer (newlen);
|
||||
StrCopy (Chars, old->Chars(), old->Len);
|
||||
old->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (newlen > Data()->AllocLen)
|
||||
{
|
||||
Chars = (char *)(Data()->Realloc(newlen) + 1);
|
||||
}
|
||||
Data()->Len = (unsigned int)newlen;
|
||||
}
|
||||
}
|
||||
|
||||
// Under Windows, use the system heap functions for managing string memory.
|
||||
// Under other OSs, use ordinary memory management instead.
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
static HANDLE StringHeap;
|
||||
#endif
|
||||
|
||||
FStringData *FStringData::Alloc (size_t strlen)
|
||||
{
|
||||
strlen += 1 + sizeof(FStringData); // Add space for header and terminating null
|
||||
strlen = (strlen + 7) & ~7; // Pad length up
|
||||
|
||||
#ifdef _WIN32
|
||||
if (StringHeap == NULL)
|
||||
{
|
||||
StringHeap = HeapCreate (0, 64*1024, 0);
|
||||
if (StringHeap == NULL)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
}
|
||||
|
||||
FStringData *block = (FStringData *)HeapAlloc (StringHeap, 0, strlen);
|
||||
#else
|
||||
FStringData *block = (FStringData *)malloc (strlen);
|
||||
#endif
|
||||
if (block == NULL)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
block->Len = 0;
|
||||
block->AllocLen = (unsigned int)strlen - sizeof(FStringData) - 1;
|
||||
block->RefCount = 1;
|
||||
return block;
|
||||
}
|
||||
|
||||
FStringData *FStringData::Realloc (size_t newstrlen)
|
||||
{
|
||||
assert (RefCount <= 1);
|
||||
|
||||
newstrlen += 1 + sizeof(FStringData); // Add space for header and terminating null
|
||||
newstrlen = (newstrlen + 7) & ~7; // Pad length up
|
||||
|
||||
#ifdef _WIN32
|
||||
FStringData *block = (FStringData *)HeapReAlloc (StringHeap, 0, this, newstrlen);
|
||||
#else
|
||||
FStringData *block = (FStringData *)realloc (this, newstrlen);
|
||||
#endif
|
||||
if (block == NULL)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
block->AllocLen = (unsigned int)newstrlen - sizeof(FStringData) - 1;
|
||||
return block;
|
||||
}
|
||||
|
||||
void FStringData::Dealloc ()
|
||||
{
|
||||
assert (RefCount <= 0);
|
||||
|
||||
#ifdef _WIN32
|
||||
HeapFree (StringHeap, 0, this);
|
||||
#else
|
||||
free (this);
|
||||
#endif
|
||||
}
|
||||
|
||||
FStringData *FStringData::MakeCopy ()
|
||||
{
|
||||
FStringData *copy = Alloc (Len);
|
||||
copy->Len = Len;
|
||||
FString::StrCopy (copy->Chars(), Chars(), Len);
|
||||
return copy;
|
||||
}
|
||||
|
|
146
src/zstring.h
146
src/zstring.h
|
@ -4,16 +4,71 @@
|
|||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include "tarray.h"
|
||||
|
||||
//#define NOPOOLS
|
||||
struct FStringData
|
||||
{
|
||||
unsigned int Len; // Length of string, excluding terminating null
|
||||
unsigned int AllocLen; // Amount of memory allocated for string
|
||||
int RefCount; // < 0 means it's locked
|
||||
// char StrData[xxx];
|
||||
|
||||
char *Chars()
|
||||
{
|
||||
return (char *)(this + 1);
|
||||
}
|
||||
|
||||
const char *Chars() const
|
||||
{
|
||||
return (const char *)(this + 1);
|
||||
}
|
||||
|
||||
char *AddRef()
|
||||
{
|
||||
if (RefCount < 0)
|
||||
{
|
||||
return (char *)(MakeCopy() + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
RefCount++;
|
||||
return (char *)(this + 1);
|
||||
}
|
||||
}
|
||||
|
||||
void Release()
|
||||
{
|
||||
assert (RefCount != 0);
|
||||
|
||||
if (--RefCount <= 0)
|
||||
{
|
||||
Dealloc();
|
||||
}
|
||||
}
|
||||
|
||||
FStringData *MakeCopy();
|
||||
|
||||
static FStringData *Alloc (size_t strlen);
|
||||
FStringData *Realloc (size_t newstrlen);
|
||||
void Dealloc ();
|
||||
};
|
||||
|
||||
struct FNullStringData
|
||||
{
|
||||
unsigned int Len;
|
||||
unsigned int AllocLen;
|
||||
int RefCount;
|
||||
char Nothing[2];
|
||||
};
|
||||
|
||||
class FString
|
||||
{
|
||||
public:
|
||||
FString () : Chars(NULL) {}
|
||||
FString () : Chars(&NullString.Nothing[0]) { NullString.RefCount++; }
|
||||
|
||||
// Copy constructors
|
||||
FString (const FString &other) { Chars = NULL; *this = other; }
|
||||
FString (const FString &other) { AttachToOther (other); }
|
||||
FString (const char *copyStr);
|
||||
FString (const char *copyStr, size_t copyLen);
|
||||
FString (char oneChar);
|
||||
|
@ -28,12 +83,14 @@ public:
|
|||
|
||||
~FString ();
|
||||
|
||||
operator char *() { return Chars; }
|
||||
char *LockBuffer(); // Obtain write access to the character buffer
|
||||
void UnlockBuffer(); // Allow shared access to the character buffer
|
||||
|
||||
operator const char *() const { return Chars; }
|
||||
|
||||
char *GetChars() const { return Chars; }
|
||||
char &operator[] (int index) { return Chars[index]; }
|
||||
char &operator[] (size_t index) { return Chars[index]; }
|
||||
const char *GetChars() const { return Chars; }
|
||||
const char &operator[] (int index) const { return Chars[index]; }
|
||||
const char &operator[] (size_t index) const { return Chars[index]; }
|
||||
|
||||
FString &operator = (const FString &other);
|
||||
FString &operator = (const char *copyStr);
|
||||
|
@ -117,10 +174,10 @@ public:
|
|||
unsigned long ToULong (int base=0) const;
|
||||
double ToDouble () const;
|
||||
|
||||
size_t Len() const { return Chars == NULL ? 0 : ((StringHeader *)(Chars - sizeof(StringHeader)))->Len; }
|
||||
size_t Len() const { return Data()->Len; }
|
||||
bool IsEmpty() const { return Len() == 0; }
|
||||
|
||||
void Resize (long newlen);
|
||||
void Truncate (long newlen);
|
||||
|
||||
int Compare (const FString &other) const { return strcmp (Chars, other.Chars); }
|
||||
int Compare (const char *other) const { return strcmp (Chars, other); }
|
||||
|
@ -129,81 +186,24 @@ public:
|
|||
int CompareNoCase (const char *other) const { return stricmp (Chars, other); }
|
||||
|
||||
protected:
|
||||
struct StringHeader
|
||||
{
|
||||
#ifndef NOPOOLS
|
||||
FString *Owner; // FString this char array belongs to
|
||||
#endif
|
||||
size_t Len; // Length of FString, excluding terminating null
|
||||
};
|
||||
struct Pool;
|
||||
struct PoolGroup
|
||||
{
|
||||
#ifndef NOPOOLS
|
||||
~PoolGroup ();
|
||||
Pool *Pools;
|
||||
Pool *FindPool (char *chars) const;
|
||||
static StringHeader *GetHeader (char *chars);
|
||||
#endif
|
||||
char *Alloc (FString *owner, size_t len);
|
||||
char *Realloc (FString *owner, char *chars, size_t newlen);
|
||||
void Free (char *chars);
|
||||
};
|
||||
const FStringData *Data() const { return (FStringData *)Chars - 1; }
|
||||
FStringData *Data() { return (FStringData *)Chars - 1; }
|
||||
|
||||
FString (size_t len);
|
||||
StringHeader *GetHeader () const;
|
||||
void AttachToOther (const FString &other);
|
||||
void AllocBuffer (size_t len);
|
||||
void ReallocBuffer (size_t newlen);
|
||||
|
||||
static int FormatHelper (void *data, const char *str, int len);
|
||||
static void StrCopy (char *to, const char *from, size_t len);
|
||||
static void StrCopy (char *to, const FString &from);
|
||||
static PoolGroup Pond;
|
||||
|
||||
char *Chars;
|
||||
|
||||
#ifndef __GNUC__
|
||||
template<> friend void CopyForTArray<FString> (FString &dst, FString &src)
|
||||
{
|
||||
// When a TArray is resized, we just need to update the Owner, because
|
||||
// the old copy is going to go away very soon. No need to call the
|
||||
// destructor, either, because full ownership is transferred to the
|
||||
// new FString.
|
||||
char *chars = src.Chars;
|
||||
dst.Chars = chars;
|
||||
if (chars != NULL)
|
||||
{
|
||||
((FString::StringHeader *)(chars - sizeof(FString::StringHeader)))->Owner = &dst;
|
||||
}
|
||||
}
|
||||
#else
|
||||
template<class FString> friend inline void CopyForTArray (FString &dst, FString &src);
|
||||
#endif
|
||||
static FNullStringData NullString;
|
||||
|
||||
private:
|
||||
void *operator new (size_t size, FString *addr)
|
||||
{
|
||||
return addr;
|
||||
}
|
||||
void operator delete (void *, FString *)
|
||||
{
|
||||
}
|
||||
friend struct FStringData;
|
||||
};
|
||||
|
||||
#ifdef __GNUC__
|
||||
template<> inline void CopyForTArray<FString> (FString &dst, FString &src)
|
||||
{
|
||||
// When a TArray is resized, we just need to update the Owner, because
|
||||
// the old copy is going to go away very soon. No need to call the
|
||||
// destructor, either, because full ownership is transferred to the
|
||||
// new FString.
|
||||
char *chars = src.Chars;
|
||||
dst.Chars = chars;
|
||||
if (chars != NULL)
|
||||
{
|
||||
((FString::StringHeader *)(chars - sizeof(FString::StringHeader)))->Owner = &dst;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace StringFormat
|
||||
{
|
||||
enum
|
||||
|
|
|
@ -1,448 +0,0 @@
|
|||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "zstring.h"
|
||||
|
||||
FString::PoolGroup FString::Pond;
|
||||
|
||||
#ifndef NOPOOLS
|
||||
struct FString::Pool
|
||||
{
|
||||
// The pool's performance (and thus the FString class's performance) is
|
||||
// controlled via these two constants. A small pool size will result
|
||||
// in more frequent garbage collection, while a large pool size will
|
||||
// result in longer garbage collection. A large pool can also end up
|
||||
// wasting memory. Something that's not too small and not too large
|
||||
// is ideal. Similarly, making the granularity too big will also result
|
||||
// in more frequent garbage collection. But if you do a lot of
|
||||
// concatenation with the += operator, then a large granularity is good
|
||||
// because it gives the FString more room to grow without needing to
|
||||
// be reallocated.
|
||||
//
|
||||
// Note that the granularity must be a power of 2. The pool size need
|
||||
// not be, although it's best to make it a multiple of the granularity.
|
||||
enum { POOL_SIZE = 64*1024 };
|
||||
enum { BLOCK_GRANULARITY = 16 };
|
||||
|
||||
Pool (size_t minSize);
|
||||
~Pool ();
|
||||
char *Alloc (FString *owner, size_t len);
|
||||
char *Realloc (char *chars, size_t newlen);
|
||||
void Free (char *chars);
|
||||
void MergeFreeBlocks (StringHeader *block);
|
||||
void CollectGarbage ();
|
||||
bool BigEnough (size_t len) const;
|
||||
size_t RoundLen (size_t len) const;
|
||||
|
||||
Pool *Next;
|
||||
size_t FreeSpace;
|
||||
char *PoolData;
|
||||
char *MaxAlloc;
|
||||
StringHeader *NextAlloc;
|
||||
};
|
||||
|
||||
// The PoolGroup does not get a constructor, because there is no way to
|
||||
// guarantee it will be constructed before any strings that need it.
|
||||
// Instead, we rely on the loader to initialize Pools to NULL for us.
|
||||
|
||||
FString::PoolGroup::~PoolGroup ()
|
||||
{
|
||||
int count = 0;
|
||||
Pool *pool = Pools, *next;
|
||||
while (pool != NULL)
|
||||
{
|
||||
count++;
|
||||
next = pool->Next;
|
||||
delete pool;
|
||||
pool = next;
|
||||
}
|
||||
Pools = NULL;
|
||||
}
|
||||
|
||||
char *FString::PoolGroup::Alloc (FString *owner, size_t len)
|
||||
{
|
||||
char *mem;
|
||||
Pool *pool, *best, **prev, **bestprev;
|
||||
|
||||
// If no pools, create one
|
||||
if (Pools == NULL)
|
||||
{
|
||||
Pools = new FString::Pool (len);
|
||||
}
|
||||
|
||||
// Try to allocate space from an existing pool
|
||||
for (pool = Pools; pool != NULL; pool = pool->Next)
|
||||
{
|
||||
mem = pool->Alloc (owner, len);
|
||||
if (mem != NULL)
|
||||
{
|
||||
return mem;
|
||||
}
|
||||
}
|
||||
|
||||
// Compact the pool with the most free space and try again
|
||||
best = Pools;
|
||||
bestprev = &Pools;
|
||||
pool = best->Next;
|
||||
prev = &best->Next;
|
||||
while (pool != NULL)
|
||||
{
|
||||
if (pool->FreeSpace > best->FreeSpace)
|
||||
{
|
||||
bestprev = prev;
|
||||
best = pool;
|
||||
}
|
||||
prev = &pool->Next;
|
||||
pool = pool->Next;
|
||||
}
|
||||
if (best->BigEnough (len))
|
||||
{
|
||||
best->CollectGarbage ();
|
||||
mem = best->Alloc (owner, len);
|
||||
// Move the pool to the front of the list
|
||||
*bestprev = best->Next;
|
||||
best->Next = Pools;
|
||||
Pools = best;
|
||||
}
|
||||
else
|
||||
{
|
||||
// No pools were large enough to hold the FString, so create a new one
|
||||
pool = new FString::Pool (len);
|
||||
pool->Next = Pools;
|
||||
Pools = pool;
|
||||
mem = pool->Alloc (owner, len);
|
||||
}
|
||||
return mem;
|
||||
}
|
||||
|
||||
char *FString::PoolGroup::Realloc (FString *owner, char *chars, size_t newlen)
|
||||
{
|
||||
if (chars == NULL)
|
||||
{
|
||||
chars = Alloc (owner, newlen);
|
||||
if (chars != NULL)
|
||||
{
|
||||
chars[0] = '\0';
|
||||
}
|
||||
return chars;
|
||||
}
|
||||
Pool *pool = FindPool (chars);
|
||||
char *newchars = pool->Realloc (chars, newlen);
|
||||
if (newchars == NULL)
|
||||
{
|
||||
newchars = Alloc (owner, newlen);
|
||||
if (newchars != NULL)
|
||||
{
|
||||
StrCopy (newchars, chars, GetHeader (chars)->Len);
|
||||
pool->Free (chars);
|
||||
}
|
||||
}
|
||||
return newchars;
|
||||
}
|
||||
|
||||
void FString::PoolGroup::Free (char *chars)
|
||||
{
|
||||
Pool *pool = FindPool (chars);
|
||||
if (pool != NULL)
|
||||
{
|
||||
pool->Free (chars);
|
||||
}
|
||||
}
|
||||
|
||||
FString::Pool *FString::PoolGroup::FindPool (char *chars) const
|
||||
{
|
||||
Pool *pool = Pools;
|
||||
while (pool != NULL)
|
||||
{
|
||||
if (pool->PoolData <= chars && pool->MaxAlloc > chars)
|
||||
{
|
||||
break;
|
||||
}
|
||||
pool = pool->Next;
|
||||
}
|
||||
return pool;
|
||||
}
|
||||
|
||||
FString::StringHeader *FString::PoolGroup::GetHeader (char *chars)
|
||||
{
|
||||
return (StringHeader *)(chars - sizeof(StringHeader));
|
||||
}
|
||||
|
||||
FString::Pool::Pool (size_t minSize)
|
||||
{
|
||||
if (minSize < POOL_SIZE)
|
||||
{
|
||||
minSize = POOL_SIZE;
|
||||
}
|
||||
minSize = RoundLen (minSize-1);
|
||||
PoolData = new char[minSize];
|
||||
FreeSpace = minSize;
|
||||
MaxAlloc = PoolData + minSize;
|
||||
Next = NULL;
|
||||
NextAlloc = (StringHeader *)PoolData;
|
||||
NextAlloc->Owner = NULL;
|
||||
NextAlloc->Len = minSize;
|
||||
}
|
||||
|
||||
FString::Pool::~Pool ()
|
||||
{
|
||||
if (PoolData != NULL)
|
||||
{
|
||||
// Watch out! During program exit, the pool may be deleted before
|
||||
// all the strings stored in it. So we need to walk through the pool
|
||||
// and make any owned strings un-owned.
|
||||
StringHeader *str;
|
||||
StringHeader *laststr;
|
||||
|
||||
for (str = (StringHeader *)PoolData; str < NextAlloc; )
|
||||
{
|
||||
if (str->Owner != NULL)
|
||||
{
|
||||
FString *owner = str->Owner;
|
||||
// assert (owner->Chars == (char *)str + sizeof(StringHeader));
|
||||
Free ((char *)str + sizeof(StringHeader));
|
||||
owner->Chars = "";
|
||||
}
|
||||
laststr = str;
|
||||
str = (StringHeader *)((char *)str + str->Len);
|
||||
}
|
||||
|
||||
delete[] PoolData;
|
||||
PoolData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
char *FString::Pool::Alloc (FString *owner, size_t len)
|
||||
{
|
||||
if (NextAlloc == (StringHeader *)MaxAlloc)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
size_t needlen = RoundLen (len);
|
||||
if (NextAlloc->Len >= needlen)
|
||||
{
|
||||
char *chars = (char *)NextAlloc + sizeof(StringHeader);
|
||||
chars[0] = '\0';
|
||||
NextAlloc->Owner = owner;
|
||||
NextAlloc->Len = len;
|
||||
NextAlloc = (StringHeader *)((char *)NextAlloc + needlen);
|
||||
if (NextAlloc != (StringHeader *)MaxAlloc)
|
||||
{
|
||||
NextAlloc->Owner = NULL;
|
||||
NextAlloc->Len = MaxAlloc - (char *)NextAlloc;
|
||||
}
|
||||
FreeSpace -= needlen;
|
||||
return chars;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *FString::Pool::Realloc (char *chars, size_t newlen)
|
||||
{
|
||||
size_t needlen = RoundLen (newlen);
|
||||
StringHeader *oldhead = (StringHeader *)(chars - sizeof(StringHeader));
|
||||
size_t oldtruelen = RoundLen (oldhead->Len);
|
||||
|
||||
if (oldtruelen > needlen)
|
||||
{ // Shrinking, so make a new free block after this one.
|
||||
StringHeader *nextblock = (StringHeader *)((char *)oldhead + needlen);
|
||||
nextblock->Owner = NULL;
|
||||
nextblock->Len = oldtruelen - needlen;
|
||||
MergeFreeBlocks (nextblock);
|
||||
oldhead->Len = newlen;
|
||||
return chars;
|
||||
}
|
||||
|
||||
if (oldtruelen == needlen)
|
||||
{ // There is already enough space allocated for the needed growth
|
||||
oldhead->Len = newlen;
|
||||
return chars;
|
||||
}
|
||||
|
||||
// If there is free space after this FString, try to grow into it.
|
||||
StringHeader *nexthead = (StringHeader *)((char *)oldhead + oldtruelen);
|
||||
if (nexthead < (StringHeader *)MaxAlloc && nexthead->Owner == NULL)
|
||||
{
|
||||
// Make sure there's only one free block past this FString
|
||||
MergeFreeBlocks (nexthead);
|
||||
// Is there enough room to grow?
|
||||
if (oldtruelen + nexthead->Len >= needlen)
|
||||
{
|
||||
oldhead->Len = newlen;
|
||||
size_t newfreelen = oldtruelen + nexthead->Len - needlen;
|
||||
if (newfreelen > 0)
|
||||
{
|
||||
StringHeader *nextnewhead = (StringHeader *)((char *)oldhead + needlen);
|
||||
nextnewhead->Owner = NULL;
|
||||
nextnewhead->Len = newfreelen;
|
||||
// If this is the last FString in the pool, then the NextAlloc marker also needs to move
|
||||
if (nexthead == NextAlloc)
|
||||
{
|
||||
NextAlloc = nextnewhead;
|
||||
}
|
||||
}
|
||||
FreeSpace -= needlen - oldtruelen;
|
||||
return chars;
|
||||
}
|
||||
}
|
||||
|
||||
// There was insufficient room for growth, so try to allocate space at the end of the pool
|
||||
char *newchars = Alloc (oldhead->Owner, newlen);
|
||||
if (newchars != NULL)
|
||||
{
|
||||
FString::StrCopy (newchars, chars, oldhead->Len);
|
||||
Free (chars);
|
||||
return newchars;
|
||||
}
|
||||
|
||||
// There was not enough space
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void FString::Pool::Free (char *chars)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
for (StringHeader *str = (StringHeader *)PoolData; str < NextAlloc; )
|
||||
{
|
||||
if (str->Owner != NULL)
|
||||
{
|
||||
// assert (str->Owner->Chars == (char *)str + sizeof(StringHeader));
|
||||
str = (StringHeader *)((char *)str + RoundLen(str->Len));
|
||||
}
|
||||
else
|
||||
{
|
||||
str = (StringHeader *)((char *)str + str->Len);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
StringHeader *head = (StringHeader *)(chars - sizeof(StringHeader));
|
||||
size_t truelen = RoundLen (head->Len);
|
||||
|
||||
FreeSpace += truelen;
|
||||
|
||||
head->Owner = NULL;
|
||||
head->Len = truelen;
|
||||
MergeFreeBlocks (head);
|
||||
|
||||
#ifdef _DEBUG
|
||||
memset (head + 1, 0xCE, head->Len - sizeof(StringHeader));
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
for (StringHeader *str = (StringHeader *)PoolData; str < NextAlloc; )
|
||||
{
|
||||
if (str->Owner != NULL)
|
||||
{
|
||||
// assert (str->Owner->Chars == (char *)str + sizeof(StringHeader));
|
||||
str = (StringHeader *)((char *)str + RoundLen(str->Len));
|
||||
}
|
||||
else
|
||||
{
|
||||
str = (StringHeader *)((char *)str + str->Len);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void FString::Pool::MergeFreeBlocks (StringHeader *head)
|
||||
{
|
||||
StringHeader *block;
|
||||
|
||||
for (block = head;
|
||||
block->Owner == NULL && block != NextAlloc;
|
||||
block = (StringHeader *)((char *)block + block->Len))
|
||||
{
|
||||
}
|
||||
|
||||
// If this chain of blocks meets up with the free space, then they can join up with it.
|
||||
if (block == NextAlloc)
|
||||
{
|
||||
NextAlloc = head;
|
||||
head->Len = MaxAlloc - (char *)head;
|
||||
}
|
||||
else
|
||||
{
|
||||
head->Len = (char *)block - (char *)head;
|
||||
}
|
||||
}
|
||||
|
||||
bool FString::Pool::BigEnough (size_t len) const
|
||||
{
|
||||
return FreeSpace >= RoundLen (len);
|
||||
}
|
||||
|
||||
size_t FString::Pool::RoundLen (size_t len) const
|
||||
{
|
||||
return (len + 1 + sizeof(StringHeader) + BLOCK_GRANULARITY - 1) & ~(BLOCK_GRANULARITY - 1);
|
||||
}
|
||||
|
||||
void FString::Pool::CollectGarbage ()
|
||||
{
|
||||
// This is a generational garbage collector. The space occupied by strings from
|
||||
// the first two generations will not be collected unless noGenerations is set true.
|
||||
|
||||
StringHeader *moveto, *movefrom;
|
||||
moveto = movefrom = (StringHeader *)PoolData;
|
||||
|
||||
while (movefrom < NextAlloc)
|
||||
{
|
||||
if (movefrom->Owner != NULL)
|
||||
{
|
||||
size_t truelen = RoundLen (movefrom->Len);
|
||||
if (moveto != movefrom)
|
||||
{
|
||||
memmove (moveto, movefrom, truelen);
|
||||
moveto->Owner->Chars = (char *)moveto + sizeof(StringHeader);
|
||||
}
|
||||
moveto = (StringHeader *)((char *)moveto + truelen);
|
||||
movefrom = (StringHeader *)((char *)movefrom + truelen);
|
||||
}
|
||||
else
|
||||
{
|
||||
movefrom = (StringHeader *)((char *)movefrom + movefrom->Len);
|
||||
}
|
||||
}
|
||||
|
||||
NextAlloc = moveto;
|
||||
if (NextAlloc != (StringHeader *)MaxAlloc)
|
||||
{
|
||||
NextAlloc->Len = MaxAlloc - (char *)moveto;
|
||||
NextAlloc->Owner = NULL;
|
||||
if (NextAlloc->Len != FreeSpace)
|
||||
FreeSpace = FreeSpace;
|
||||
}
|
||||
else if (FreeSpace != 0)
|
||||
FreeSpace = FreeSpace;
|
||||
}
|
||||
#else
|
||||
char *FString::PoolGroup::Alloc (FString *owner, size_t len)
|
||||
{
|
||||
char *mem = (char *)malloc (len + 1 + sizeof(StringHeader));
|
||||
StringHeader *head = (StringHeader *)mem;
|
||||
mem += sizeof(StringHeader);
|
||||
head->Len = len;
|
||||
return mem;
|
||||
}
|
||||
|
||||
char *FString::PoolGroup::Realloc (FString *owner, char *chars, size_t newlen)
|
||||
{
|
||||
if (chars == NULL)
|
||||
{
|
||||
chars = Alloc (owner, newlen);
|
||||
chars[0] = '\0';
|
||||
return chars;
|
||||
}
|
||||
StringHeader *head = (StringHeader *)(chars - sizeof(StringHeader));
|
||||
head = (StringHeader *)realloc (head, newlen+1+sizeof(StringHeader));
|
||||
head->Len = newlen;
|
||||
return (char *)head + sizeof(StringHeader);
|
||||
}
|
||||
|
||||
void FString::PoolGroup::Free (char *chars)
|
||||
{
|
||||
free (chars - sizeof(StringHeader));
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1766,9 +1766,6 @@
|
|||
<File
|
||||
RelativePath=".\src\zstring.cpp">
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\src\zstringpool.cpp">
|
||||
</File>
|
||||
<Filter
|
||||
Name="Decorate++"
|
||||
Filter="">
|
||||
|
|
Loading…
Reference in a new issue