mirror of
https://github.com/ZDoom/gzdoom.git
synced 2025-02-22 03:51:11 +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 \
|
vectors.cpp \
|
||||||
name.cpp \
|
name.cpp \
|
||||||
zstring.cpp \
|
zstring.cpp \
|
||||||
zstringpool.cpp \
|
|
||||||
zstrformat.cpp \
|
zstrformat.cpp \
|
||||||
w_wad.cpp \
|
w_wad.cpp \
|
||||||
wi_stuff.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)
|
May 14, 2006 (Changes by Graf Zahl)
|
||||||
- Added a show_obituaries option to disable obituaries without disabling
|
- Added a show_obituaries option to disable obituaries without disabling
|
||||||
other more important message types which have lower priority for some
|
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->inuse = false;
|
||||||
bot->lastteam = keepTeam ? players[i].userinfo.team : TEAM_None;
|
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;
|
playeringame[i] = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -509,7 +509,7 @@ void C_SetDefaultBindings ()
|
||||||
|
|
||||||
BOOL C_DoKey (event_t *ev)
|
BOOL C_DoKey (event_t *ev)
|
||||||
{
|
{
|
||||||
char *binding = NULL;
|
FString binding;
|
||||||
bool dclick;
|
bool dclick;
|
||||||
int dclickspot;
|
int dclickspot;
|
||||||
byte dclickmask;
|
byte dclickmask;
|
||||||
|
@ -553,33 +553,27 @@ BOOL C_DoKey (event_t *ev)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (binding == NULL || *binding==0)
|
if (binding.IsEmpty())
|
||||||
{
|
{
|
||||||
binding = Bindings[ev->data1];
|
binding = Bindings[ev->data1];
|
||||||
dclick = false;
|
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;
|
||||||
{
|
}
|
||||||
return false;
|
|
||||||
}
|
char *copy = binding.LockBuffer();
|
||||||
binding[0] = '-';
|
|
||||||
|
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);
|
AddCommandString (copy, dclick ? ev->data1 | KEY_DBLCLICKED : ev->data1);
|
||||||
|
|
||||||
if (ev->type == EV_KeyUp)
|
|
||||||
{
|
|
||||||
binding[0] = '+';
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
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;
|
return (unsigned int)key < NUM_KEYS ? Bindings[key].GetChars() : NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,6 @@ void C_SetDefaultBindings ();
|
||||||
void C_UnbindAll ();
|
void C_UnbindAll ();
|
||||||
|
|
||||||
// Returns string bound to given key (NULL if none)
|
// Returns string bound to given key (NULL if none)
|
||||||
char *C_GetBinding (int key);
|
const char *C_GetBinding (int key);
|
||||||
|
|
||||||
#endif //__C_BINDINGS_H__
|
#endif //__C_BINDINGS_H__
|
||||||
|
|
|
@ -146,7 +146,7 @@ void DefaultExtension (char *path, const char *extension)
|
||||||
|
|
||||||
void DefaultExtension (FString &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))
|
while (src != &path[0] && !IsSeperator(*src))
|
||||||
{
|
{
|
||||||
|
|
|
@ -83,6 +83,7 @@
|
||||||
#include "gameconfigfile.h"
|
#include "gameconfigfile.h"
|
||||||
#include "sbar.h"
|
#include "sbar.h"
|
||||||
#include "decallib.h"
|
#include "decallib.h"
|
||||||
|
#include "version.h"
|
||||||
#include "r_polymost.h"
|
#include "r_polymost.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "v_text.h"
|
#include "v_text.h"
|
||||||
|
@ -1409,7 +1410,6 @@ static EIWADType ScanIWAD (const char *iwad)
|
||||||
static int CheckIWAD (const char *doomwaddir, WadStuff *wads)
|
static int CheckIWAD (const char *doomwaddir, WadStuff *wads)
|
||||||
{
|
{
|
||||||
const char *slash;
|
const char *slash;
|
||||||
char iwad[512];
|
|
||||||
int i;
|
int i;
|
||||||
int numfound;
|
int numfound;
|
||||||
|
|
||||||
|
@ -1422,8 +1422,10 @@ static int CheckIWAD (const char *doomwaddir, WadStuff *wads)
|
||||||
{
|
{
|
||||||
if (wads[i].Path.IsEmpty())
|
if (wads[i].Path.IsEmpty())
|
||||||
{
|
{
|
||||||
sprintf (iwad, "%s%s%s", doomwaddir, slash, IWADNames[i]);
|
FString iwad;
|
||||||
FixPathSeperator (iwad);
|
|
||||||
|
iwad.Format ("%s%s%s", doomwaddir, slash, IWADNames[i]);
|
||||||
|
FixPathSeperator (iwad.LockBuffer());
|
||||||
if (FileExists (iwad))
|
if (FileExists (iwad))
|
||||||
{
|
{
|
||||||
wads[i].Type = ScanIWAD (iwad);
|
wads[i].Type = ScanIWAD (iwad);
|
||||||
|
@ -1495,12 +1497,10 @@ static EIWADType IdentifyVersion (const char *zdoom_wad)
|
||||||
bool iwadparmfound = false;
|
bool iwadparmfound = false;
|
||||||
FString custwad;
|
FString custwad;
|
||||||
|
|
||||||
memset (wads, 0, sizeof(wads));
|
|
||||||
|
|
||||||
if (iwadparm)
|
if (iwadparm)
|
||||||
{
|
{
|
||||||
custwad = iwadparm;
|
custwad = iwadparm;
|
||||||
FixPathSeperator (custwad.GetChars());
|
FixPathSeperator (custwad.LockBuffer());
|
||||||
if (CheckIWAD (custwad, wads))
|
if (CheckIWAD (custwad, wads))
|
||||||
{ // -iwad parameter was a directory
|
{ // -iwad parameter was a directory
|
||||||
iwadparm = NULL;
|
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"))
|
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;
|
iwadparmfound = true;
|
||||||
}
|
}
|
||||||
|
@ -1612,17 +1612,19 @@ static EIWADType IdentifyVersion (const char *zdoom_wad)
|
||||||
|
|
||||||
if (wads[pickwad].Type == IWAD_Strife)
|
if (wads[pickwad].Type == IWAD_Strife)
|
||||||
{ // Try to load voices.wad along with strife1.wad
|
{ // Try to load voices.wad along with strife1.wad
|
||||||
char *filepart = strrchr (wads[pickwad].Path, '/');
|
long lastslash = wads[pickwad].Path.LastIndexOf ('/');
|
||||||
if (filepart == NULL)
|
FString path;
|
||||||
|
|
||||||
|
if (lastslash == -1)
|
||||||
{
|
{
|
||||||
filepart = wads[pickwad].Path;
|
path = wads[pickwad].Path;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
++filepart;
|
path = FString (wads[pickwad].Path, lastslash + 1);
|
||||||
}
|
}
|
||||||
strcpy (filepart, "voices.wad");
|
path += "voices.wad";
|
||||||
D_AddFile (wads[pickwad].Path);
|
D_AddFile (path);
|
||||||
}
|
}
|
||||||
|
|
||||||
return wads[pickwad].Type;
|
return wads[pickwad].Type;
|
||||||
|
|
|
@ -77,6 +77,8 @@ enum EIWADType
|
||||||
|
|
||||||
struct WadStuff
|
struct WadStuff
|
||||||
{
|
{
|
||||||
|
WadStuff() : Type(IWAD_Doom2TNT) {}
|
||||||
|
|
||||||
FString Path;
|
FString Path;
|
||||||
EIWADType Type;
|
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
|
// 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.
|
// 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, '\\');
|
char *slash = strrchr (fileonly, '\\');
|
||||||
if (slash != NULL)
|
if (slash != NULL)
|
||||||
{
|
{
|
||||||
|
|
|
@ -155,6 +155,8 @@ enum
|
||||||
class player_s
|
class player_s
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
player_s();
|
||||||
|
|
||||||
void Serialize (FArchive &arc);
|
void Serialize (FArchive &arc);
|
||||||
void FixPointers (const DObject *obj, DObject *replacement);
|
void FixPointers (const DObject *obj, DObject *replacement);
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include "tarray.h"
|
#include "tarray.h"
|
||||||
#include "doomtype.h"
|
#include "doomtype.h"
|
||||||
|
#include "m_alloc.h"
|
||||||
|
|
||||||
struct PClass;
|
struct PClass;
|
||||||
|
|
||||||
|
|
|
@ -738,7 +738,7 @@ BOOL G_Responder (event_t *ev)
|
||||||
if (gameaction == ga_nothing &&
|
if (gameaction == ga_nothing &&
|
||||||
(demoplayback || gamestate == GS_DEMOSCREEN || gamestate == GS_TITLELEVEL))
|
(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)
|
if (ev->type == EV_KeyDown)
|
||||||
{
|
{
|
||||||
|
@ -1118,7 +1118,7 @@ void G_PlayerReborn (int player)
|
||||||
botskill_t b_skill;//Added by MC:
|
botskill_t b_skill;//Added by MC:
|
||||||
APlayerPawn *actor;
|
APlayerPawn *actor;
|
||||||
const PClass *cls;
|
const PClass *cls;
|
||||||
char *log;
|
FString log;
|
||||||
|
|
||||||
p = &players[player];
|
p = &players[player];
|
||||||
|
|
||||||
|
@ -1134,7 +1134,9 @@ void G_PlayerReborn (int player)
|
||||||
cls = p->cls;
|
cls = p->cls;
|
||||||
log = p->LogText;
|
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));
|
memcpy (p->frags, frags, sizeof(p->frags));
|
||||||
p->fragcount = fragcount;
|
p->fragcount = fragcount;
|
||||||
|
@ -1483,7 +1485,7 @@ void G_ScreenShot (char *filename)
|
||||||
// G_InitFromSavegame
|
// G_InitFromSavegame
|
||||||
// Can be called by the startup code or the menu task.
|
// 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)
|
if (name != NULL)
|
||||||
{
|
{
|
||||||
|
|
|
@ -37,7 +37,7 @@ void G_DeferedPlayDemo (char* demo);
|
||||||
|
|
||||||
// Can be called by the startup code or M_Responder,
|
// Can be called by the startup code or M_Responder,
|
||||||
// calls P_SetupLevel or W_EnterWorld.
|
// calls P_SetupLevel or W_EnterWorld.
|
||||||
void G_LoadGame (char* name);
|
void G_LoadGame (const char* name);
|
||||||
|
|
||||||
void G_DoLoadGame (void);
|
void G_DoLoadGame (void);
|
||||||
|
|
||||||
|
|
|
@ -148,8 +148,6 @@ static void ReadMultiplePlayers (FArchive &arc, int numPlayers, int numPlayersNo
|
||||||
BYTE *tempPlayerUsed = new BYTE[numPlayers];
|
BYTE *tempPlayerUsed = new BYTE[numPlayers];
|
||||||
BYTE *playerUsed = new BYTE[MAXPLAYERS];
|
BYTE *playerUsed = new BYTE[MAXPLAYERS];
|
||||||
|
|
||||||
memset (playertemp, 0, numPlayers*sizeof(player_t));
|
|
||||||
|
|
||||||
for (i = 0; i < numPlayers; ++i)
|
for (i = 0; i < numPlayers; ++i)
|
||||||
{
|
{
|
||||||
nametemp[i] = NULL;
|
nametemp[i] = NULL;
|
||||||
|
|
|
@ -67,6 +67,102 @@ static TArray<sector_t *> PredictionTouchingSectorsBackup;
|
||||||
|
|
||||||
BOOL onground;
|
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
|
// This function supplements the pointer cleanup in dobject.cpp, because
|
||||||
// player_s is not derived from DObject. (I tried it, and DestroyScan was
|
// player_s is not derived from DObject. (I tried it, and DestroyScan was
|
||||||
|
|
|
@ -93,7 +93,7 @@ byte** warpedflats;
|
||||||
int* flatwarpedwhen;
|
int* flatwarpedwhen;
|
||||||
|
|
||||||
|
|
||||||
|
static TArray<BYTE *> BuildTileFiles;
|
||||||
FTextureManager TexMan;
|
FTextureManager TexMan;
|
||||||
|
|
||||||
FTextureManager::FTextureManager ()
|
FTextureManager::FTextureManager ()
|
||||||
|
@ -2771,7 +2771,7 @@ void R_InitBuildTiles ()
|
||||||
int slashat = rffpath.LastIndexOf ('/');
|
int slashat = rffpath.LastIndexOf ('/');
|
||||||
if (slashat >= 0)
|
if (slashat >= 0)
|
||||||
{
|
{
|
||||||
rffpath.Resize (slashat + 1);
|
rffpath.Truncate (slashat + 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2793,8 +2793,6 @@ void R_InitBuildTiles ()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// BADBAD: This memory is never explicitly deleted except when the
|
|
||||||
// version number is wrong.
|
|
||||||
int len = Q_filelength (f);
|
int len = Q_filelength (f);
|
||||||
BYTE *art = new BYTE[len];
|
BYTE *art = new BYTE[len];
|
||||||
if (fread (art, 1, len, f) != len || LittleLong(*(DWORD *)art) != 1)
|
if (fread (art, 1, len, f) != len || LittleLong(*(DWORD *)art) != 1)
|
||||||
|
@ -2803,6 +2801,7 @@ void R_InitBuildTiles ()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
BuildTileFiles.Push (art);
|
||||||
TexMan.AddTiles (art);
|
TexMan.AddTiles (art);
|
||||||
}
|
}
|
||||||
fclose (f);
|
fclose (f);
|
||||||
|
@ -2820,8 +2819,6 @@ void R_InitBuildTiles ()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// BADBAD: This memory is never explicitly deleted except when the
|
|
||||||
// version number is wrong.
|
|
||||||
BYTE *art = new BYTE[Wads.LumpLength (lumpnum)];
|
BYTE *art = new BYTE[Wads.LumpLength (lumpnum)];
|
||||||
Wads.ReadLump (lumpnum, art);
|
Wads.ReadLump (lumpnum, art);
|
||||||
|
|
||||||
|
@ -2831,11 +2828,20 @@ void R_InitBuildTiles ()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
BuildTileFiles.Push (art);
|
||||||
TexMan.AddTiles (art);
|
TexMan.AddTiles (art);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void R_DeinitBuildTiles ()
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < BuildTileFiles.Size(); ++i)
|
||||||
|
{
|
||||||
|
delete[] BuildTileFiles[i];
|
||||||
|
}
|
||||||
|
BuildTileFiles.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
static struct FakeCmap {
|
static struct FakeCmap {
|
||||||
char name[8];
|
char name[8];
|
||||||
|
@ -3030,6 +3036,7 @@ void R_InitData ()
|
||||||
void R_DeinitData ()
|
void R_DeinitData ()
|
||||||
{
|
{
|
||||||
R_DeinitColormaps ();
|
R_DeinitColormaps ();
|
||||||
|
R_DeinitBuildTiles();
|
||||||
|
|
||||||
// Free openings
|
// Free openings
|
||||||
if (openings != NULL)
|
if (openings != NULL)
|
||||||
|
|
|
@ -81,13 +81,6 @@ struct FRandomSoundList
|
||||||
WORD NumSounds;
|
WORD NumSounds;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
|
||||||
void CopyForTArray<FRandomSoundList> (FRandomSoundList &dst, FRandomSoundList &src)
|
|
||||||
{
|
|
||||||
dst = src;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct FPlayerClassLookup
|
struct FPlayerClassLookup
|
||||||
{
|
{
|
||||||
char Name[MAX_SNDNAME+1];
|
char Name[MAX_SNDNAME+1];
|
||||||
|
|
|
@ -417,14 +417,15 @@ bool TimiditySong::ValidateTimidity ()
|
||||||
|
|
||||||
bool TimiditySong::LaunchTimidity ()
|
bool TimiditySong::LaunchTimidity ()
|
||||||
{
|
{
|
||||||
if (CommandLine.Len() == 0)
|
if (CommandLine.IsEmpty())
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tell Timidity whether it should loop or not
|
// Tell Timidity whether it should loop or not
|
||||||
CommandLine[LoopPos] = m_Looping ? 'l' : ' ';
|
char *cmdline = CommandLine.LockBuffer();
|
||||||
DPrintf ("cmd: \x1cG%s\n", CommandLine.GetChars());
|
cmdline[LoopPos] = m_Looping ? 'l' : ' ';
|
||||||
|
DPrintf ("cmd: \x1cG%s\n", cmdline);
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
STARTUPINFO startup = { sizeof(startup), };
|
STARTUPINFO startup = { sizeof(startup), };
|
||||||
|
@ -440,14 +441,16 @@ bool TimiditySong::LaunchTimidity ()
|
||||||
startup.lpTitle = "TiMidity (ZDoom Launched)";
|
startup.lpTitle = "TiMidity (ZDoom Launched)";
|
||||||
startup.wShowWindow = SW_SHOWMINNOACTIVE;
|
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))
|
/*HIGH_PRIORITY_CLASS|*/DETACHED_PROCESS, NULL, NULL, &startup, &procInfo))
|
||||||
{
|
{
|
||||||
ChildProcess = procInfo.hProcess;
|
ChildProcess = procInfo.hProcess;
|
||||||
//SetThreadPriority (procInfo.hThread, THREAD_PRIORITY_HIGHEST);
|
//SetThreadPriority (procInfo.hThread, THREAD_PRIORITY_HIGHEST);
|
||||||
CloseHandle (procInfo.hThread); // Don't care about the created thread
|
CloseHandle (procInfo.hThread); // Don't care about the created thread
|
||||||
|
CommandLine.UnlockBuffer();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
CommandLine.UnlockBuffer();
|
||||||
|
|
||||||
char hres[9];
|
char hres[9];
|
||||||
LPTSTR msgBuf;
|
LPTSTR msgBuf;
|
||||||
|
|
68
src/tarray.h
68
src/tarray.h
|
@ -38,37 +38,9 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
#include "m_alloc.h"
|
#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>
|
template <class T>
|
||||||
class TArray
|
class TArray
|
||||||
{
|
{
|
||||||
|
@ -140,7 +112,7 @@ public:
|
||||||
unsigned int Push (const T &item)
|
unsigned int Push (const T &item)
|
||||||
{
|
{
|
||||||
Grow (1);
|
Grow (1);
|
||||||
ConstructInTArray (&Array[Count], item);
|
::new((void*)&Array[Count]) T(item);
|
||||||
return Count++;
|
return Count++;
|
||||||
}
|
}
|
||||||
bool Pop (T &item)
|
bool Pop (T &item)
|
||||||
|
@ -148,7 +120,7 @@ public:
|
||||||
if (Count > 0)
|
if (Count > 0)
|
||||||
{
|
{
|
||||||
item = Array[--Count];
|
item = Array[--Count];
|
||||||
DoDelete (Count, Count);
|
Array[Count].~T();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -157,12 +129,9 @@ public:
|
||||||
{
|
{
|
||||||
if (index < Count)
|
if (index < Count)
|
||||||
{
|
{
|
||||||
for (unsigned int i = index; i < Count - 1; ++i)
|
Array[index].~T();
|
||||||
{
|
memmove (&Array[index], &Array[index+1], Count - index - 1);
|
||||||
Array[i] = Array[i+1];
|
|
||||||
}
|
|
||||||
Count--;
|
Count--;
|
||||||
DoDelete (Count, Count);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Inserts an item into the array, shifting elements as needed
|
// 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
|
// Inserting somewhere past the end of the array, so we can
|
||||||
// just add it without moving things.
|
// just add it without moving things.
|
||||||
Resize (index + 1);
|
Resize (index + 1);
|
||||||
ConstructInTArray (&Array[index], item);
|
::new ((void *)&Array[index]) T(item);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Inserting somewhere in the middle of the array, so make
|
// Inserting somewhere in the middle of the array,
|
||||||
// room for it and shift old entries out of the way.
|
// so make room for it
|
||||||
|
|
||||||
Resize (Count + 1);
|
Resize (Count + 1);
|
||||||
|
|
||||||
// Now copy items from the index and onward
|
// Now move items from the index and onward out of the way
|
||||||
for (unsigned int i = Count - 1; i-- > index; )
|
memmove (&Array[index+1], &Array[index], sizeof(T)*(Count - index - 1));
|
||||||
{
|
|
||||||
Array[i+1] = Array[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now put the new element in
|
// And put the new element in
|
||||||
DoDelete (index, index);
|
::new ((void *)&Array[index]) T(item);
|
||||||
ConstructInTArray (&Array[index], item);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void ShrinkToFit ()
|
void ShrinkToFit ()
|
||||||
|
@ -233,7 +197,7 @@ public:
|
||||||
Grow (amount - Count);
|
Grow (amount - Count);
|
||||||
for (unsigned int i = Count; i < amount; ++i)
|
for (unsigned int i = Count; i < amount; ++i)
|
||||||
{
|
{
|
||||||
ConstructEmptyInTArray (&Array[i]);
|
::new((void *)&Array[i]) T;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Count != amount)
|
else if (Count != amount)
|
||||||
|
@ -293,13 +257,7 @@ private:
|
||||||
void DoResize ()
|
void DoResize ()
|
||||||
{
|
{
|
||||||
size_t allocsize = sizeof(T)*Most;
|
size_t allocsize = sizeof(T)*Most;
|
||||||
T *newarray = (T *)M_Malloc (allocsize);
|
Array = (T *)M_Realloc (Array, allocsize);
|
||||||
for (unsigned int i = 0; i < Count; ++i)
|
|
||||||
{
|
|
||||||
CopyForTArray (newarray[i], Array[i]);
|
|
||||||
}
|
|
||||||
free (Array);
|
|
||||||
Array = newarray;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DoDelete (unsigned int first, unsigned int last)
|
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
|
// Reverse the palette because BUILD used entry 255 as
|
||||||
// transparent, but we use 0 as transparent.
|
// 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)
|
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] = (ipal[765-c] << 2) | (ipal[765-c] >> 4);
|
||||||
opal[c+1] = (ipal[766-c] << 2) | (ipal[766-c] >> 4);
|
opal[c+1] = (ipal[766-c] << 2) | (ipal[766-c] >> 4);
|
||||||
opal[c+2] = (ipal[767-c] << 2) | (ipal[767-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] = ipal[765-c];
|
||||||
opal[c+1] = ipal[766-c];
|
opal[c+1] = ipal[766-c];
|
||||||
opal[c+2] = ipal[767-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;
|
return true;
|
||||||
|
|
|
@ -634,7 +634,7 @@ BOOL CALLBACK IWADBoxCallback (HWND hDlg, UINT message, WPARAM wParam, LPARAM lP
|
||||||
for (i = 0; i < NumWads; i++)
|
for (i = 0; i < NumWads; i++)
|
||||||
{
|
{
|
||||||
char work[256];
|
char work[256];
|
||||||
char *filepart = strrchr (WadList[i].Path, '/');
|
const char *filepart = strrchr (WadList[i].Path, '/');
|
||||||
if (filepart == NULL)
|
if (filepart == NULL)
|
||||||
filepart = WadList[i].Path;
|
filepart = WadList[i].Path;
|
||||||
else
|
else
|
||||||
|
|
430
src/zstring.cpp
430
src/zstring.cpp
|
@ -1,39 +1,74 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <new> // for bad_alloc
|
||||||
|
|
||||||
#include "zstring.h"
|
#include "zstring.h"
|
||||||
|
|
||||||
|
FNullStringData FString::NullString =
|
||||||
FString::FString (size_t len)
|
|
||||||
{
|
{
|
||||||
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)
|
FString::FString (const char *copyStr)
|
||||||
{
|
{
|
||||||
size_t len = strlen (copyStr);
|
if (copyStr == NULL || *copyStr == '\0')
|
||||||
Chars = Pond.Alloc (this, len);
|
{
|
||||||
StrCopy (Chars, copyStr, len);
|
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)
|
FString::FString (const char *copyStr, size_t len)
|
||||||
{
|
{
|
||||||
Chars = Pond.Alloc (this, len);
|
AllocBuffer (len);
|
||||||
StrCopy (Chars, copyStr, len);
|
StrCopy (Chars, copyStr, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
FString::FString (char oneChar)
|
FString::FString (char oneChar)
|
||||||
{
|
{
|
||||||
Chars = Pond.Alloc (this, 1);
|
if (oneChar == '\0')
|
||||||
Chars[0] = oneChar;
|
{
|
||||||
Chars[1] = '\0';
|
NullString.RefCount++;
|
||||||
|
Chars = &NullString.Nothing[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AllocBuffer (1);
|
||||||
|
Chars[0] = oneChar;
|
||||||
|
Chars[1] = '\0';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FString::FString (const FString &head, const FString &tail)
|
FString::FString (const FString &head, const FString &tail)
|
||||||
{
|
{
|
||||||
size_t len1 = head.Len();
|
size_t len1 = head.Len();
|
||||||
size_t len2 = tail.Len();
|
size_t len2 = tail.Len();
|
||||||
Chars = Pond.Alloc (this, len1 + len2);
|
AllocBuffer (len1 + len2);
|
||||||
StrCopy (Chars, head);
|
StrCopy (Chars, head);
|
||||||
StrCopy (Chars + len1, tail);
|
StrCopy (Chars + len1, tail);
|
||||||
}
|
}
|
||||||
|
@ -42,7 +77,7 @@ FString::FString (const FString &head, const char *tail)
|
||||||
{
|
{
|
||||||
size_t len1 = head.Len();
|
size_t len1 = head.Len();
|
||||||
size_t len2 = strlen (tail);
|
size_t len2 = strlen (tail);
|
||||||
Chars = Pond.Alloc (this, len1 + len2);
|
AllocBuffer (len1 + len2);
|
||||||
StrCopy (Chars, head);
|
StrCopy (Chars, head);
|
||||||
StrCopy (Chars + len1, tail, len2);
|
StrCopy (Chars + len1, tail, len2);
|
||||||
}
|
}
|
||||||
|
@ -50,7 +85,7 @@ FString::FString (const FString &head, const char *tail)
|
||||||
FString::FString (const FString &head, char tail)
|
FString::FString (const FString &head, char tail)
|
||||||
{
|
{
|
||||||
size_t len1 = head.Len();
|
size_t len1 = head.Len();
|
||||||
Chars = Pond.Alloc (this, len1 + 1);
|
AllocBuffer (len1 + 1);
|
||||||
StrCopy (Chars, head);
|
StrCopy (Chars, head);
|
||||||
Chars[len1] = tail;
|
Chars[len1] = tail;
|
||||||
Chars[len1+1] = '\0';
|
Chars[len1+1] = '\0';
|
||||||
|
@ -60,7 +95,7 @@ FString::FString (const char *head, const FString &tail)
|
||||||
{
|
{
|
||||||
size_t len1 = strlen (head);
|
size_t len1 = strlen (head);
|
||||||
size_t len2 = tail.Len();
|
size_t len2 = tail.Len();
|
||||||
Chars = Pond.Alloc (this, len1 + len2);
|
AllocBuffer (len1 + len2);
|
||||||
StrCopy (Chars, head, len1);
|
StrCopy (Chars, head, len1);
|
||||||
StrCopy (Chars + len1, tail);
|
StrCopy (Chars + len1, tail);
|
||||||
}
|
}
|
||||||
|
@ -69,7 +104,7 @@ FString::FString (const char *head, const char *tail)
|
||||||
{
|
{
|
||||||
size_t len1 = strlen (head);
|
size_t len1 = strlen (head);
|
||||||
size_t len2 = strlen (tail);
|
size_t len2 = strlen (tail);
|
||||||
Chars = Pond.Alloc (this, len1 + len2);
|
AllocBuffer (len1 + len2);
|
||||||
StrCopy (Chars, head, len1);
|
StrCopy (Chars, head, len1);
|
||||||
StrCopy (Chars + len1, tail, len2);
|
StrCopy (Chars + len1, tail, len2);
|
||||||
}
|
}
|
||||||
|
@ -77,62 +112,76 @@ FString::FString (const char *head, const char *tail)
|
||||||
FString::FString (char head, const FString &tail)
|
FString::FString (char head, const FString &tail)
|
||||||
{
|
{
|
||||||
size_t len2 = tail.Len();
|
size_t len2 = tail.Len();
|
||||||
Chars = Pond.Alloc (this, 1 + len2);
|
AllocBuffer (1 + len2);
|
||||||
Chars[0] = head;
|
Chars[0] = head;
|
||||||
StrCopy (Chars + 1, tail);
|
StrCopy (Chars + 1, tail);
|
||||||
}
|
}
|
||||||
|
|
||||||
FString::~FString ()
|
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);
|
Data()->RefCount = 1;
|
||||||
Chars = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FString &FString::operator = (const FString &other)
|
FString &FString::operator = (const FString &other)
|
||||||
{
|
{
|
||||||
if (Chars != NULL)
|
assert (Chars != NULL);
|
||||||
|
|
||||||
|
if (&other != this)
|
||||||
{
|
{
|
||||||
Pond.Free (Chars);
|
int oldrefcount = Data()->RefCount < 0;
|
||||||
}
|
Data()->Release();
|
||||||
if (other.Chars == NULL)
|
AttachToOther(other);
|
||||||
{
|
if (oldrefcount < 0)
|
||||||
Chars = NULL;
|
{
|
||||||
}
|
LockBuffer();
|
||||||
else
|
Data()->RefCount = oldrefcount;
|
||||||
{
|
}
|
||||||
Chars = Pond.Alloc (this, other.GetHeader()->Len);
|
|
||||||
StrCopy (Chars, other);
|
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
FString &FString::operator = (const char *copyStr)
|
FString &FString::operator = (const char *copyStr)
|
||||||
{
|
{
|
||||||
if (Chars != NULL)
|
Data()->Release();
|
||||||
|
if (copyStr == NULL || *copyStr == '\0')
|
||||||
{
|
{
|
||||||
Pond.Free (Chars);
|
NullString.RefCount++;
|
||||||
}
|
Chars = &NullString.Nothing[0];
|
||||||
if (copyStr == NULL)
|
|
||||||
{
|
|
||||||
Chars = NULL;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
size_t len = strlen (copyStr);
|
size_t len = strlen (copyStr);
|
||||||
/*
|
AllocBuffer (len);
|
||||||
if (len == 0)
|
StrCopy (Chars, copyStr, len);
|
||||||
{
|
|
||||||
Chars = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
Chars = Pond.Alloc (this, len);
|
|
||||||
StrCopy (Chars, copyStr, len);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -147,11 +196,8 @@ void FString::Format (const char *fmt, ...)
|
||||||
|
|
||||||
void FString::VFormat (const char *fmt, va_list arglist)
|
void FString::VFormat (const char *fmt, va_list arglist)
|
||||||
{
|
{
|
||||||
if (Chars != NULL)
|
Data()->Release();
|
||||||
{
|
Chars = (char *)(FStringData::Alloc(128) + 1);
|
||||||
Pond.Free (Chars);
|
|
||||||
}
|
|
||||||
Chars = NULL;
|
|
||||||
StringFormat::VWorker (FormatHelper, this, fmt, arglist);
|
StringFormat::VWorker (FormatHelper, this, fmt, arglist);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,8 +205,12 @@ int FString::FormatHelper (void *data, const char *cstr, int len)
|
||||||
{
|
{
|
||||||
FString *str = (FString *)data;
|
FString *str = (FString *)data;
|
||||||
size_t len1 = str->Len();
|
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);
|
StrCopy (str->Chars + len1, cstr, len);
|
||||||
|
str->Data()->Len = (unsigned int)(len1 + len);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +243,7 @@ FString &FString::operator += (const FString &tail)
|
||||||
{
|
{
|
||||||
size_t len1 = Len();
|
size_t len1 = Len();
|
||||||
size_t len2 = tail.Len();
|
size_t len2 = tail.Len();
|
||||||
Chars = Pond.Realloc (this, Chars, len1 + len2);
|
ReallocBuffer (len1 + len2);
|
||||||
StrCopy (Chars + len1, tail);
|
StrCopy (Chars + len1, tail);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -202,7 +252,7 @@ FString &FString::operator += (const char *tail)
|
||||||
{
|
{
|
||||||
size_t len1 = Len();
|
size_t len1 = Len();
|
||||||
size_t len2 = strlen(tail);
|
size_t len2 = strlen(tail);
|
||||||
Chars = Pond.Realloc (this, Chars, len1 + len2);
|
ReallocBuffer (len1 + len2);
|
||||||
StrCopy (Chars + len1, tail, len2);
|
StrCopy (Chars + len1, tail, len2);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@ -210,17 +260,17 @@ FString &FString::operator += (const char *tail)
|
||||||
FString &FString::operator += (char tail)
|
FString &FString::operator += (char tail)
|
||||||
{
|
{
|
||||||
size_t len1 = Len();
|
size_t len1 = Len();
|
||||||
Chars = Pond.Realloc (this, Chars, len1 + 1);
|
ReallocBuffer (len1 + 1);
|
||||||
Chars[len1] = tail;
|
Chars[len1] = tail;
|
||||||
Chars[len1+1] = '\0';
|
Chars[len1+1] = '\0';
|
||||||
return *this;
|
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';
|
Chars[newlen] = '\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,7 +300,7 @@ FString FString::Mid (size_t pos, size_t numChars) const
|
||||||
size_t len = Len();
|
size_t len = Len();
|
||||||
if (pos >= len)
|
if (pos >= len)
|
||||||
{
|
{
|
||||||
return FString("");
|
return FString();
|
||||||
}
|
}
|
||||||
if (pos + numChars > len)
|
if (pos + numChars > len)
|
||||||
{
|
{
|
||||||
|
@ -402,24 +452,29 @@ long FString::LastIndexOfAny (const char *charset, long endIndex) const
|
||||||
|
|
||||||
void FString::ToUpper ()
|
void FString::ToUpper ()
|
||||||
{
|
{
|
||||||
|
LockBuffer();
|
||||||
size_t max = Len();
|
size_t max = Len();
|
||||||
for (size_t i = 0; i < max; ++i)
|
for (size_t i = 0; i < max; ++i)
|
||||||
{
|
{
|
||||||
Chars[i] = toupper(Chars[i]);
|
Chars[i] = toupper(Chars[i]);
|
||||||
}
|
}
|
||||||
|
UnlockBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FString::ToLower ()
|
void FString::ToLower ()
|
||||||
{
|
{
|
||||||
|
LockBuffer();
|
||||||
size_t max = Len();
|
size_t max = Len();
|
||||||
for (size_t i = 0; i < max; ++i)
|
for (size_t i = 0; i < max; ++i)
|
||||||
{
|
{
|
||||||
Chars[i] = tolower(Chars[i]);
|
Chars[i] = tolower(Chars[i]);
|
||||||
}
|
}
|
||||||
|
UnlockBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FString::SwapCase ()
|
void FString::SwapCase ()
|
||||||
{
|
{
|
||||||
|
LockBuffer();
|
||||||
size_t max = Len();
|
size_t max = Len();
|
||||||
for (size_t i = 0; i < max; ++i)
|
for (size_t i = 0; i < max; ++i)
|
||||||
{
|
{
|
||||||
|
@ -432,6 +487,7 @@ void FString::SwapCase ()
|
||||||
Chars[i] = toupper(Chars[i]);
|
Chars[i] = toupper(Chars[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
UnlockBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FString::StripLeft ()
|
void FString::StripLeft ()
|
||||||
|
@ -442,11 +498,21 @@ void FString::StripLeft ()
|
||||||
if (!isspace(Chars[i]))
|
if (!isspace(Chars[i]))
|
||||||
break;
|
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)
|
void FString::StripLeft (const FString &charset)
|
||||||
|
@ -462,11 +528,21 @@ void FString::StripLeft (const char *charset)
|
||||||
if (!strchr (charset, Chars[i]))
|
if (!strchr (charset, Chars[i]))
|
||||||
break;
|
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 ()
|
void FString::StripRight ()
|
||||||
|
@ -477,8 +553,18 @@ void FString::StripRight ()
|
||||||
if (!isspace(Chars[i]))
|
if (!isspace(Chars[i]))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Chars[i+1] = '\0';
|
if (Data()->RefCount <= 1)
|
||||||
Pond.Realloc (this, Chars, i+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)
|
void FString::StripRight (const FString &charset)
|
||||||
|
@ -494,8 +580,18 @@ void FString::StripRight (const char *charset)
|
||||||
if (!strchr (charset, Chars[i]))
|
if (!strchr (charset, Chars[i]))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Chars[i+1] = '\0';
|
if (Data()->RefCount <= 1)
|
||||||
Pond.Realloc (this, Chars, i+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 ()
|
void FString::StripLeftRight ()
|
||||||
|
@ -511,17 +607,27 @@ void FString::StripLeftRight ()
|
||||||
if (!isspace(Chars[j]))
|
if (!isspace(Chars[j]))
|
||||||
break;
|
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)
|
void FString::StripLeftRight (const FString &charset)
|
||||||
{
|
{
|
||||||
return StripLeft (charset.Chars);
|
return StripLeftRight (charset.Chars);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FString::StripLeftRight (const char *charset)
|
void FString::StripLeftRight (const char *charset)
|
||||||
|
@ -537,12 +643,22 @@ void FString::StripLeftRight (const char *charset)
|
||||||
if (!strchr (charset, Chars[j]))
|
if (!strchr (charset, Chars[j]))
|
||||||
break;
|
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)
|
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;
|
index = mylen;
|
||||||
}
|
}
|
||||||
Pond.Realloc (this, Chars, mylen + instrlen);
|
if (Data()->RefCount <= 1)
|
||||||
if (index < mylen)
|
|
||||||
{
|
{
|
||||||
|
ReallocBuffer (mylen + instrlen);
|
||||||
memmove (Chars + index + instrlen, Chars + index, (mylen - index + 1)*sizeof(char));
|
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));
|
else
|
||||||
if (index == mylen)
|
|
||||||
{
|
{
|
||||||
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)
|
void FString::ReplaceChars (char oldchar, char newchar)
|
||||||
{
|
{
|
||||||
size_t i, j;
|
size_t i, j;
|
||||||
|
|
||||||
|
LockBuffer();
|
||||||
for (i = 0, j = Len(); i < j; ++i)
|
for (i = 0, j = Len(); i < j; ++i)
|
||||||
{
|
{
|
||||||
if (Chars[i] == oldchar)
|
if (Chars[i] == oldchar)
|
||||||
|
@ -584,11 +707,14 @@ void FString::ReplaceChars (char oldchar, char newchar)
|
||||||
Chars[i] = newchar;
|
Chars[i] = newchar;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
UnlockBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FString::ReplaceChars (const char *oldcharset, char newchar)
|
void FString::ReplaceChars (const char *oldcharset, char newchar)
|
||||||
{
|
{
|
||||||
size_t i, j;
|
size_t i, j;
|
||||||
|
|
||||||
|
LockBuffer();
|
||||||
for (i = 0, j = Len(); i < j; ++i)
|
for (i = 0, j = Len(); i < j; ++i)
|
||||||
{
|
{
|
||||||
if (strchr (oldcharset, Chars[i]) != NULL)
|
if (strchr (oldcharset, Chars[i]) != NULL)
|
||||||
|
@ -596,11 +722,14 @@ void FString::ReplaceChars (const char *oldcharset, char newchar)
|
||||||
Chars[i] = newchar;
|
Chars[i] = newchar;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
UnlockBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FString::StripChars (char killchar)
|
void FString::StripChars (char killchar)
|
||||||
{
|
{
|
||||||
size_t read, write, mylen;
|
size_t read, write, mylen;
|
||||||
|
|
||||||
|
LockBuffer();
|
||||||
for (read = write = 0, mylen = Len(); read < mylen; ++read)
|
for (read = write = 0, mylen = Len(); read < mylen; ++read)
|
||||||
{
|
{
|
||||||
if (Chars[read] != killchar)
|
if (Chars[read] != killchar)
|
||||||
|
@ -609,12 +738,15 @@ void FString::StripChars (char killchar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Chars[write] = '\0';
|
Chars[write] = '\0';
|
||||||
Pond.Realloc (this, Chars, write);
|
ReallocBuffer (write);
|
||||||
|
UnlockBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FString::StripChars (const char *killchars)
|
void FString::StripChars (const char *killchars)
|
||||||
{
|
{
|
||||||
size_t read, write, mylen;
|
size_t read, write, mylen;
|
||||||
|
|
||||||
|
LockBuffer();
|
||||||
for (read = write = 0, mylen = Len(); read < mylen; ++read)
|
for (read = write = 0, mylen = Len(); read < mylen; ++read)
|
||||||
{
|
{
|
||||||
if (strchr (killchars, Chars[read]) == NULL)
|
if (strchr (killchars, Chars[read]) == NULL)
|
||||||
|
@ -623,7 +755,8 @@ void FString::StripChars (const char *killchars)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Chars[write] = '\0';
|
Chars[write] = '\0';
|
||||||
Pond.Realloc (this, Chars, write);
|
ReallocBuffer (write);
|
||||||
|
UnlockBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FString::MergeChars (char merger)
|
void FString::MergeChars (char merger)
|
||||||
|
@ -634,6 +767,8 @@ void FString::MergeChars (char merger)
|
||||||
void FString::MergeChars (char merger, char newchar)
|
void FString::MergeChars (char merger, char newchar)
|
||||||
{
|
{
|
||||||
size_t read, write, mylen;
|
size_t read, write, mylen;
|
||||||
|
|
||||||
|
LockBuffer();
|
||||||
for (read = write = 0, mylen = Len(); read < mylen; )
|
for (read = write = 0, mylen = Len(); read < mylen; )
|
||||||
{
|
{
|
||||||
if (Chars[read] == merger)
|
if (Chars[read] == merger)
|
||||||
|
@ -649,12 +784,15 @@ void FString::MergeChars (char merger, char newchar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Chars[write] = '\0';
|
Chars[write] = '\0';
|
||||||
Pond.Realloc (this, Chars, write);
|
ReallocBuffer (write);
|
||||||
|
UnlockBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FString::MergeChars (const char *charset, char newchar)
|
void FString::MergeChars (const char *charset, char newchar)
|
||||||
{
|
{
|
||||||
size_t read, write, mylen;
|
size_t read, write, mylen;
|
||||||
|
|
||||||
|
LockBuffer();
|
||||||
for (read = write = 0, mylen = Len(); read < mylen; )
|
for (read = write = 0, mylen = Len(); read < mylen; )
|
||||||
{
|
{
|
||||||
if (strchr (charset, Chars[read]) != NULL)
|
if (strchr (charset, Chars[read]) != NULL)
|
||||||
|
@ -670,7 +808,8 @@ void FString::MergeChars (const char *charset, char newchar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Chars[write] = '\0';
|
Chars[write] = '\0';
|
||||||
Pond.Realloc (this, Chars, write);
|
ReallocBuffer (write);
|
||||||
|
UnlockBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FString::Substitute (const FString &oldstr, const FString &newstr)
|
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)
|
void FString::Substitute (const char *oldstr, const char *newstr, size_t oldstrlen, size_t newstrlen)
|
||||||
{
|
{
|
||||||
|
LockBuffer();
|
||||||
for (size_t checkpt = 0; checkpt < Len(); )
|
for (size_t checkpt = 0; checkpt < Len(); )
|
||||||
{
|
{
|
||||||
char *match = strstr (Chars + checkpt, oldstr);
|
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;
|
size_t matchpt = match - Chars;
|
||||||
if (oldstrlen != newstrlen)
|
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));
|
memmove (Chars + matchpt + newstrlen, Chars + matchpt + oldstrlen, (len + 1 - matchpt - oldstrlen)*sizeof(char));
|
||||||
}
|
}
|
||||||
memcpy (Chars + matchpt, newstr, newstrlen);
|
memcpy (Chars + matchpt, newstr, newstrlen);
|
||||||
|
@ -715,6 +855,7 @@ void FString::Substitute (const char *oldstr, const char *newstr, size_t oldstrl
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
UnlockBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FString::IsInt () const
|
bool FString::IsInt () const
|
||||||
|
@ -842,12 +983,6 @@ double FString::ToDouble () const
|
||||||
return strtod (Chars, NULL);
|
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)
|
void FString::StrCopy (char *to, const char *from, size_t len)
|
||||||
{
|
{
|
||||||
memcpy (to, from, len*sizeof(char));
|
memcpy (to, from, len*sizeof(char));
|
||||||
|
@ -858,3 +993,106 @@ void FString::StrCopy (char *to, const FString &from)
|
||||||
{
|
{
|
||||||
StrCopy (to, from.Chars, from.Len());
|
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 <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include "tarray.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
|
class FString
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FString () : Chars(NULL) {}
|
FString () : Chars(&NullString.Nothing[0]) { NullString.RefCount++; }
|
||||||
|
|
||||||
// Copy constructors
|
// Copy constructors
|
||||||
FString (const FString &other) { Chars = NULL; *this = other; }
|
FString (const FString &other) { AttachToOther (other); }
|
||||||
FString (const char *copyStr);
|
FString (const char *copyStr);
|
||||||
FString (const char *copyStr, size_t copyLen);
|
FString (const char *copyStr, size_t copyLen);
|
||||||
FString (char oneChar);
|
FString (char oneChar);
|
||||||
|
@ -28,12 +83,14 @@ public:
|
||||||
|
|
||||||
~FString ();
|
~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; }
|
operator const char *() const { return Chars; }
|
||||||
|
|
||||||
char *GetChars() const { return Chars; }
|
const char *GetChars() const { return Chars; }
|
||||||
char &operator[] (int index) { return Chars[index]; }
|
const char &operator[] (int index) const { return Chars[index]; }
|
||||||
char &operator[] (size_t index) { return Chars[index]; }
|
const char &operator[] (size_t index) const { return Chars[index]; }
|
||||||
|
|
||||||
FString &operator = (const FString &other);
|
FString &operator = (const FString &other);
|
||||||
FString &operator = (const char *copyStr);
|
FString &operator = (const char *copyStr);
|
||||||
|
@ -117,10 +174,10 @@ public:
|
||||||
unsigned long ToULong (int base=0) const;
|
unsigned long ToULong (int base=0) const;
|
||||||
double ToDouble () 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; }
|
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 FString &other) const { return strcmp (Chars, other.Chars); }
|
||||||
int Compare (const char *other) const { return strcmp (Chars, other); }
|
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); }
|
int CompareNoCase (const char *other) const { return stricmp (Chars, other); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct StringHeader
|
const FStringData *Data() const { return (FStringData *)Chars - 1; }
|
||||||
{
|
FStringData *Data() { return (FStringData *)Chars - 1; }
|
||||||
#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);
|
|
||||||
};
|
|
||||||
|
|
||||||
FString (size_t len);
|
void AttachToOther (const FString &other);
|
||||||
StringHeader *GetHeader () const;
|
void AllocBuffer (size_t len);
|
||||||
|
void ReallocBuffer (size_t newlen);
|
||||||
|
|
||||||
static int FormatHelper (void *data, const char *str, int len);
|
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 char *from, size_t len);
|
||||||
static void StrCopy (char *to, const FString &from);
|
static void StrCopy (char *to, const FString &from);
|
||||||
static PoolGroup Pond;
|
|
||||||
|
|
||||||
char *Chars;
|
char *Chars;
|
||||||
|
|
||||||
#ifndef __GNUC__
|
static FNullStringData NullString;
|
||||||
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
|
|
||||||
|
|
||||||
private:
|
friend struct FStringData;
|
||||||
void *operator new (size_t size, FString *addr)
|
|
||||||
{
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
void operator delete (void *, FString *)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#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
|
namespace StringFormat
|
||||||
{
|
{
|
||||||
enum
|
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
|
<File
|
||||||
RelativePath=".\src\zstring.cpp">
|
RelativePath=".\src\zstring.cpp">
|
||||||
</File>
|
</File>
|
||||||
<File
|
|
||||||
RelativePath=".\src\zstringpool.cpp">
|
|
||||||
</File>
|
|
||||||
<Filter
|
<Filter
|
||||||
Name="Decorate++"
|
Name="Decorate++"
|
||||||
Filter="">
|
Filter="">
|
||||||
|
|
Loading…
Reference in a new issue