diff --git a/src/dobject.cpp b/src/dobject.cpp index 1b35d09c2..90e2cfffa 100644 --- a/src/dobject.cpp +++ b/src/dobject.cpp @@ -464,7 +464,7 @@ DObject::DObject () : ObjectFlags(0), Class(0) { if (FreeIndices.Pop (Index)) - Objects[Index] = this; + Objects[(unsigned int)Index] = this; else Index = Objects.Push (this); } @@ -473,7 +473,7 @@ DObject::DObject (TypeInfo *inClass) : ObjectFlags(0), Class(inClass) { if (FreeIndices.Pop (Index)) - Objects[Index] = this; + Objects[(unsigned int)Index] = this; else Index = Objects.Push (this); } @@ -559,7 +559,7 @@ void DObject::RemoveFromArray () } else if (Objects.Size() > Index) { - Objects[Index] = NULL; + Objects[(unsigned int)Index] = NULL; FreeIndices.Push (Index); } } diff --git a/src/farchive.cpp b/src/farchive.cpp index 6fd76aa4c..757248481 100644 --- a/src/farchive.cpp +++ b/src/farchive.cpp @@ -551,7 +551,7 @@ FPNGChunkFile::FPNGChunkFile (FILE *file, DWORD id, size_t chunklen) : FCompressedFile (file, EReading, true, false), m_ChunkID (id) { m_Buffer = (byte *)M_Malloc (chunklen); - m_BufferSize = chunklen; + m_BufferSize = (unsigned int)chunklen; fread (m_Buffer, chunklen, 1, m_File); // Skip the CRC for now. Maybe later it will be used. fseek (m_File, 4, SEEK_CUR); diff --git a/src/name.cpp b/src/name.cpp index 7245a5db0..0ef2737a2 100644 --- a/src/name.cpp +++ b/src/name.cpp @@ -1,6 +1,71 @@ +/* +** name.cpp +** Implements int-as-string mapping. +** +**--------------------------------------------------------------------------- +** Copyright 2005-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + #include #include "name.h" #include "c_dispatch.h" +#include "m_alloc.h" + +// MACROS ------------------------------------------------------------------ + +// The number of bytes to allocate to each NameBlock unless somebody is evil +// and wants a really long name. In that case, it gets its own NameBlock +// that is just large enough to hold it. +#define BLOCK_SIZE 1024 + +// How many entries to grow the NameArray by when it needs to grow. +#define NAME_GROW_AMOUNT 48 + +// TYPES ------------------------------------------------------------------- + +// Name text is stored in a linked list of NameBlock structures. This +// is really the header for the block, with the remainder of the block +// being populated by text for names. + +struct FName::NameManager::NameBlock +{ + size_t NextAlloc; + NameBlock *NextBlock; +}; + +// PRIVATE FUNCTION PROTOTYPES --------------------------------------------- + +// PUBLIC DATA DEFINITIONS ------------------------------------------------- + +// PRIVATE DATA DEFINITIONS ------------------------------------------------ + +FName::NameManager FName::NameData; // Define the predefined names. static const char *PredefinedNames[] = @@ -10,31 +75,38 @@ static const char *PredefinedNames[] = #undef xx }; -int FName::Buckets[FName::HASH_SIZE]; -TArray FName::NameArray; -bool FName::Inited; +// CODE -------------------------------------------------------------------- -FName::MainName::MainName (int next) -: NextHash(next) -{ -} +//========================================================================== +// +// FName :: NameManager :: FindName +// +// Returns the index of a name. If the name does not exist and noCreate is +// true, then it returns false. If the name does not exist and noCreate is +// false, then the name is added to the table and its new index is returned. +// +//========================================================================== -int FName::FindName (const char *text, bool noCreate) +int FName::NameManager::FindName (const char *text, bool noCreate) { - if (!Inited) InitBuckets (); + if (!Inited) + { + InitBuckets (); + } if (text == NULL) { return 0; } - int hash = MakeKey (text) % HASH_SIZE; - int scanner = Buckets[hash]; + DWORD hash = MakeKey (text); + DWORD bucket = hash % HASH_SIZE; + int scanner = Buckets[bucket]; // See if the name already exists. while (scanner >= 0) { - if (stricmp (NameArray[scanner].Text.GetChars(), text) == 0) + if (NameArray[scanner].Hash == hash && stricmp (NameArray[scanner].Text, text) == 0) { return scanner; } @@ -47,28 +119,122 @@ int FName::FindName (const char *text, bool noCreate) return 0; } - // Assigning the string to the name after pushing it avoids needless - // manipulation of the string pool. - MainName entry (Buckets[hash]); - unsigned int index = NameArray.Push (entry); - NameArray[index].Text = text; - Buckets[hash] = index; - return index; + return AddName (text, hash, bucket); } -void FName::InitBuckets () -{ - size_t i; +//========================================================================== +// +// FName :: NameManager :: InitBuckets +// +// Sets up the hash table and inserts all the default names into the table. +// +//========================================================================== +void FName::NameManager::InitBuckets () +{ Inited = true; - for (i = 0; i < HASH_SIZE; ++i) - { - Buckets[i] = -1; - } + memset (Buckets, -1, sizeof(Buckets)); // Register built-in names. 'None' must be name 0. - for (i = 0; i < countof(PredefinedNames); ++i) + for (size_t i = 0; i < countof(PredefinedNames); ++i) { FindName (PredefinedNames[i], false); } } + +//========================================================================== +// +// FName :: NameManager :: AddName +// +// Adds a new name to the name table. +// +//========================================================================== + +int FName::NameManager::AddName (const char *text, DWORD hash, DWORD bucket) +{ + char *textstore; + NameBlock *block = Blocks; + size_t len = strlen (text) + 1; + + // Get a block large enough for the name. Only the first block in the + // list is ever considered for name storage. + if (block == NULL || block->NextAlloc + len >= BLOCK_SIZE) + { + block = AddBlock (len); + } + + // Copy the string into the block. + textstore = (char *)block + block->NextAlloc; + strcpy (textstore, text); + block->NextAlloc += len; + + // Add an entry for the name to the NameArray + if (NumNames >= MaxNames) + { + // If no names have been defined yet, make the first allocation + // large enough to hold all the predefined names. + MaxNames += MaxNames == 0 ? countof(PredefinedNames) + NAME_GROW_AMOUNT : NAME_GROW_AMOUNT; + + NameArray = (NameEntry *)M_Realloc (NameArray, MaxNames * sizeof(NameEntry)); + } + + NameArray[NumNames].Text = textstore; + NameArray[NumNames].Hash = hash; + NameArray[NumNames].NextHash = Buckets[bucket]; + Buckets[bucket] = NumNames; + + return NumNames++; +} + +//========================================================================== +// +// FName :: NameManager :: AddBlock +// +// Creates a new NameBlock at least large enough to hold the required +// number of chars. +// +//========================================================================== + +FName::NameManager::NameBlock *FName::NameManager::AddBlock (size_t len) +{ + NameBlock *block; + + len += sizeof(NameBlock); + if (len < BLOCK_SIZE) + { + len = BLOCK_SIZE; + } + block = (NameBlock *)M_Malloc (len); + block->NextAlloc = sizeof(NameBlock); + block->NextBlock = Blocks; + Blocks = block; + return block; +} + +//========================================================================== +// +// FName :: NameManager :: ~NameManager +// +// Release all the memory used for name bookkeeping. +// +//========================================================================== + +FName::NameManager::~NameManager() +{ + NameBlock *block, *next; + + for (block = Blocks; block != NULL; block = next) + { + next = block->NextBlock; + free (block); + } + Blocks = NULL; + + if (NameArray != NULL) + { + free (NameArray); + NameArray = NULL; + } + NumNames = MaxNames = 0; + memset (Buckets, -1, sizeof(Buckets)); +} diff --git a/src/name.h b/src/name.h index ed6c90fb8..d892ca18f 100644 --- a/src/name.h +++ b/src/name.h @@ -1,8 +1,40 @@ +/* +** name.h +** +**--------------------------------------------------------------------------- +** Copyright 2005-2006 Randy Heit +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + #ifndef NAME_H #define NAME_H -#include "zstring.h" -#include "tarray.h" +#include "doomtype.h" enum ENamedName { @@ -15,28 +47,24 @@ class FName { public: FName () : Index(0) {} - FName (const char *text) { Index = FindName (text, false); } - FName (const FString &text) { Index = FindName (text.GetChars(), false); } - FName (const char *text, bool noCreate) { Index = FindName (text, noCreate); } - FName (const FString &text, bool noCreate) { Index = FindName (text.GetChars(), noCreate); } + FName (const char *text) { Index = NameData.FindName (text, false); } + FName (const char *text, bool noCreate) { Index = NameData.FindName (text, noCreate); } FName (const FName &other) { Index = other.Index; } FName (ENamedName index) { Index = index; } // ~FName () {} // Names can be added but never removed. int GetIndex() const { return Index; } operator int() const { return Index; } - const FString &GetText() const { return NameArray[Index].Text; } - const char *GetChars() const { return NameArray[Index].Text.GetChars(); } + const char *GetChars() const { return NameData.NameArray[Index].Text; } + operator const char *() const { return NameData.NameArray[Index].Text; } - FName &operator = (const char *text) { Index = FindName (text, false); return *this; } - FName &operator = (const FString &text) { Index = FindName (text.GetChars(), false); return *this; } + FName &operator = (const char *text) { Index = NameData.FindName (text, false); return *this; } FName &operator = (const FName &other) { Index = other.Index; return *this; } FName &operator = (ENamedName index) { Index = index; return *this; } - int SetName (const char *text, bool noCreate) { return Index = FindName (text, false); } - int SetName (const FString &text, bool noCreate) { return Index = FindName (text.GetChars(), false); } + int SetName (const char *text, bool noCreate=false) { return Index = NameData.FindName (text, noCreate); } - bool IsValidName() const { return (unsigned int)Index < NameArray.Size(); } + bool IsValidName() const { return (unsigned)Index < (unsigned)NameData.NumNames; } // Note that the comparison operators compare the names' indices, not // their text, so they cannot be used to do a lexicographical sort. @@ -57,47 +85,36 @@ public: private: int Index; - enum { HASH_SIZE = 256 }; - - struct MainName + struct NameEntry { - MainName (int next); - MainName (const MainName &other) : Text(other.Text), NextHash(other.NextHash) {} - MainName () {} - FString Text; + char *Text; + DWORD Hash; int NextHash; - - void *operator new (size_t size, MainName *addr) - { - return addr; - } - void operator delete (void *, MainName *) - { - } }; - static TArray NameArray; - static int Buckets[HASH_SIZE]; - static int FindName (const char *text, bool noCreate); - static void InitBuckets (); - static bool Inited; -#ifndef __GNUC__ - template<> friend void CopyForTArray (MainName &dst, MainName &src) + struct NameManager { - dst.NextHash = src.NextHash; - CopyForTArray (dst.Text, src.Text); - } -#else - template friend inline void CopyForTArray (MainName &dst, MainName &src); -#endif + // No constructor because we can't ensure that it actually gets + // called before any FNames are constructed during startup. This + // means this struct must only exist in the program's BSS section. + ~NameManager(); + + enum { HASH_SIZE = 256 }; + struct NameBlock; + + NameBlock *Blocks; + NameEntry *NameArray; + int NumNames, MaxNames; + int Buckets[HASH_SIZE]; + + int FindName (const char *text, bool noCreate); + int AddName (const char *text, DWORD hash, DWORD bucket); + NameBlock *AddBlock (size_t len); + void InitBuckets (); + bool Inited; + }; + + static NameManager NameData; }; -#ifdef __GNUC__ -template<> inline void CopyForTArray (FName::MainName &dst, FName::MainName &src) -{ - dst.NextHash = src.NextHash; - CopyForTArray (dst.Text, src.Text); -} -#endif - #endif diff --git a/src/v_font.cpp b/src/v_font.cpp index eb887aafb..b025bed18 100644 --- a/src/v_font.cpp +++ b/src/v_font.cpp @@ -1082,7 +1082,7 @@ void FFontChar2::MakeTexture () I_FatalError ("The font %s is corrupt", name); } - if (Spans!=NULL) Spans = CreateSpans (Pixels); + Spans = CreateSpans (Pixels); } //===========================================================================