]> git.sur5r.net Git - cc65/blobdiff - src/common/strpool.c
Merge branch 'master' of https://github.com/jedeoric/cc65
[cc65] / src / common / strpool.c
index b6411865ff2648f679065ae7acedb2fddc0757e7..244681afdbe93277ee996d67c5ed51a5b9f2e225 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 2003      Ullrich von Bassewitz                                       */
-/*               Römerstrasse 52                                             */
-/*               D-70794 Filderstadt                                         */
-/* EMail:        uz@cc65.org                                                 */
+/* (C) 2003-2011, Ullrich von Bassewitz                                      */
+/*                Roemerstrasse 52                                           */
+/*                D-70794 Filderstadt                                        */
+/* EMail:         uz@cc65.org                                                */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
 
 
 /* A string pool is used to store identifiers and other strings. Each string
- * stored in the pool has a unique id, which may be used to access the string
- * in the pool. Identical strings are only stored once in the pool and have
- * identical ids. This means that instead of comparing strings, just the
- * string pool ids must be compared.
- */
+** stored in the pool has a unique id, which may be used to access the string
+** in the pool. Identical strings are stored only once in the pool and have
+** identical ids. This means that instead of comparing strings, just the
+** string pool ids must be compared.
+*/
 
 
 
 
 /* common */
 #include "coll.h"
-#include "hashstr.h"
+#include "hashfunc.h"
+#include "hashtab.h"
 #include "strbuf.h"
 #include "strpool.h"
 #include "xmalloc.h"
 
 
 
+/*****************************************************************************/
+/*                                 Forwards                                  */
+/*****************************************************************************/
+
+
+
+static unsigned HT_GenHash (const void* Key);
+/* Generate the hash over a key. */
+
+static const void* HT_GetKey (const void* Entry);
+/* Given a pointer to the user entry data, return a pointer to the key */
+
+static int HT_Compare (const void* Key1, const void* Key2);
+/* Compare two keys. The function must return a value less than zero if
+** Key1 is smaller than Key2, zero if both are equal, and a value greater
+** than zero if Key1 is greater then Key2.
+*/
+
+
+
 /*****************************************************************************/
 /*                                     Data                                  */
 /*****************************************************************************/
 
 
 /* A string pool entry */
-struct StrPoolEntry {
-    StrPoolEntry*       Next;   /* Pointer to next entry in hash chain */
-    unsigned            Hash;   /* Full hash value */
+struct StringPoolEntry {
+    HashNode            Node;   /* Node for the hash table */
     unsigned            Id;     /* The numeric string id */
-    unsigned            Len;    /* Length of the string (excluding terminator) */
-    char                S[1];   /* The string itself */
+    StrBuf              Buf;    /* The string itself */
+};
+
+/* A string pool */
+struct StringPool {
+    Collection          Entries;        /* Entries sorted by number */
+    unsigned            TotalSize;      /* Total size of all string data */
+    HashTable           Tab;            /* Hash table */
+};
+
+/* Hash table functions */
+static const HashFunctions HashFunc = {
+    HT_GenHash,
+    HT_GetKey,
+    HT_Compare
 };
 
 
 
 /*****************************************************************************/
-/*                            struct StrPoolEntry                            */
+/*                          struct StringPoolEntry                           */
 /*****************************************************************************/
 
 
 
-static StrPoolEntry* NewStrPoolEntry (const char* S, unsigned Hash, unsigned Id)
+static StringPoolEntry* NewStringPoolEntry (const StrBuf* S, unsigned Id)
 /* Create a new string pool entry and return it. */
 {
-    /* Get the length of the string */
-    unsigned Len = strlen (S);
-
     /* Allocate memory */
-    StrPoolEntry* E = xmalloc (sizeof (StrPoolEntry) + Len);
+    StringPoolEntry* E = xmalloc (sizeof (StringPoolEntry));
 
     /* Initialize the fields */
-    E->Next = 0;
-    E->Hash = Hash;
+    InitHashNode (&E->Node);
     E->Id   = Id;
-    E->Len  = Len;
-    memcpy (E->S, S, Len+1);
+    SB_Init (&E->Buf);
+    SB_Copy (&E->Buf, S);
+
+    /* Always zero terminate the string */
+    SB_Terminate (&E->Buf);
 
     /* Return the new entry */
     return E;
@@ -99,65 +131,82 @@ static StrPoolEntry* NewStrPoolEntry (const char* S, unsigned Hash, unsigned Id)
 
 
 /*****************************************************************************/
-/*                                     Code                                  */
+/*                           Hash table functions                            */
 /*****************************************************************************/
 
 
 
-StrPool* InitStrPool (StrPool* P)
-/* Initialize a string pool */
+static unsigned HT_GenHash (const void* Key)
+/* Generate the hash over a key. */
 {
-    unsigned I;
+    return HashBuf (Key);
+}
 
-    /* Initialize the fields */
-    for (I = 0; I < sizeof (P->Tab) / sizeof (P->Tab[0]); ++I) {
-        P->Tab[I] = 0;
-    }
-    P->Entries = EmptyCollection;
-    P->TotalSize = 0;
 
-    /* Return a pointer to the initialized pool */
-    return P;
+
+static const void* HT_GetKey (const void* Entry)
+/* Given a pointer to the user entry data, return a pointer to the index */
+{
+    return &((const StringPoolEntry*) Entry)->Buf;
 }
 
 
 
-void DoneStrPool (StrPool* P)
-/* Free the data of a string pool (but not the data itself) */
+static int HT_Compare (const void* Key1, const void* Key2)
+/* Compare two keys. The function must return a value less than zero if
+** Key1 is smaller than Key2, zero if both are equal, and a value greater
+** than zero if Key1 is greater then Key2.
+*/
 {
-    unsigned I;
+    return SB_Compare (Key1, Key2);
+}
 
-    /* Free all entries and clear the entry collection */
-    for (I = 0; I < CollCount (&P->Entries); ++I) {
-        xfree (CollAtUnchecked (&P->Entries, I));
-    }
-    CollDeleteAll (&P->Entries);
 
-    /* Clear the hash table */
-    for (I = 0; I < sizeof (P->Tab) / sizeof (P->Tab[0]); ++I) {
-        P->Tab[I] = 0;
-    }
 
-    /* Reset the size */
-    P->TotalSize = 0;
-}
+/*****************************************************************************/
+/*                                     Code                                  */
+/*****************************************************************************/
 
 
 
-StrPool* NewStrPool (void)
+StringPool* NewStringPool (unsigned HashSlots)
 /* Allocate, initialize and return a new string pool */
 {
-    /* Allocate memory, initialize and return it */
-    return InitStrPool (xmalloc (sizeof (StrPool)));
+    /* Allocate memory */
+    StringPool* P = xmalloc (sizeof (*P));
+
+    /* Initialize the fields */
+    P->Entries   = EmptyCollection;
+    P->TotalSize = 0;
+    InitHashTable (&P->Tab, HashSlots, &HashFunc);
+
+    /* Return a pointer to the new pool */
+    return P;
 }
 
 
 
-void FreeStrPool (StrPool* P)
+void FreeStringPool (StringPool* P)
 /* Free a string pool */
 {
-    /* Free all entries */
-    DoneStrPool (P);
+    unsigned I;
+
+    /* Free all entries and clear the entry collection */
+    for (I = 0; I < CollCount (&P->Entries); ++I) {
+
+        /* Get a pointer to the entry */
+        StringPoolEntry* E = CollAtUnchecked (&P->Entries, I);
+
+        /* Free string buffer memory */
+        SB_Done (&E->Buf);
+
+        /* Free the memory for the entry itself */
+        xfree (E);
+    }
+    CollDeleteAll (&P->Entries);
+
+    /* Free the hash table */
+    DoneHashTable (&P->Tab);
 
     /* Free the string pool itself */
     xfree (P);
@@ -165,51 +214,42 @@ void FreeStrPool (StrPool* P)
 
 
 
-const char* SP_Get (const StrPool* P, unsigned Index)
+const StrBuf* SP_Get (const StringPool* P, unsigned Index)
 /* Return a string from the pool. Index must exist, otherwise FAIL is called. */
 {
     /* Get the collection entry */
-    const StrPoolEntry* E = CollConstAt (&P->Entries, Index);
+    const StringPoolEntry* E = CollConstAt (&P->Entries, Index);
 
     /* Return the string from the entry */
-    return E->S;
+    return &E->Buf;
 }
 
 
 
-unsigned SP_Add (StrPool* P, const char* S)
-/* Add a string to the buffer and return the index. If the string does already
- * exist in the pool, SP_Add will just return the index of the existing string.
- */
+unsigned SP_Add (StringPool* P, const StrBuf* S)
+/* Add a string buffer to the buffer and return the index. If the string does
+** already exist in the pool, SP_AddBuf will just return the index of the
+** existing string.
+*/
 {
-    /* Calculate the string hash */
-    unsigned Hash = HashStr (S);
-
-    /* Calculate the reduced string hash */
-    unsigned RHash = Hash % (sizeof (P->Tab)/sizeof (P->Tab[0]));
-
-    /* Search for an existing entry */
-    StrPoolEntry* E = P->Tab[RHash];
-    while (E) {
-        if (E->Hash == Hash && strcmp (E->S, S) == 0) {
-            /* Found, return the id of the existing string */
-            return E->Id;
-        }
-        E = E->Next;
-    }
+    /* Search for a matching entry in the hash table */
+    StringPoolEntry* E = HT_Find (&P->Tab, S);
 
-    /* We didn't find the entry, so create a new one */
-    E = NewStrPoolEntry (S, Hash, CollCount (&P->Entries));
+    /* Did we find it? */
+    if (E == 0) {
 
-    /* Insert the new entry into the entry collection */
-    CollAppend (&P->Entries, E);
+        /* We didn't find the entry, so create a new one */
+        E = NewStringPoolEntry (S, CollCount (&P->Entries));
 
-    /* Insert the new entry into the hash table */
-    E->Next = P->Tab[RHash];
-    P->Tab[RHash] = E;
+        /* Insert the new entry into the entries collection */
+        CollAppend (&P->Entries, E);
 
-    /* Add up the string size (plus terminator) */
-    P->TotalSize += E->Len + 1;
+        /* Insert the new entry into the hash table */
+        HT_Insert (&P->Tab, E);
+
+        /* Add up the string size */
+        P->TotalSize += SB_GetLen (&E->Buf);
+    }
 
     /* Return the id of the entry */
     return E->Id;
@@ -217,50 +257,27 @@ unsigned SP_Add (StrPool* P, const char* S)
 
 
 
-unsigned SP_AddBuf (StrPool* P, const void* Buffer, unsigned Size)
-/* Add strings from a string buffer. Buffer must contain a list of zero
- * terminated strings. These strings are added to the pool, starting with
- * the current index. The number of strings added is returned.
- * Beware: The function will do only loose range checking for the buffer
- * limits, so a SEGV may occur if the last string in the buffer is not
- * correctly terminated.
- */
+unsigned SP_AddStr (StringPool* P, const char* S)
+/* Add a string to the buffer and return the index. If the string does already
+** exist in the pool, SP_Add will just return the index of the existing string.
+*/
 {
-    /* Cast the buffer pointer to something useful */
-    const char* Buf = Buffer;
-
-    /* Remember the current number of strings in the buffer. */
-    unsigned OldCount = SB_GetCount (P);
+    unsigned Id;
 
-    /* Add all strings from the buffer */
-    while (Size) {
+    /* First make a string buffer, then add it. This is some overhead, but the
+    ** routine will probably go.
+    */
+    StrBuf Buf;
+    Id = SP_Add (P, SB_InitFromString (&Buf, S));
 
-        /* Add the next entry */
-        unsigned Id = SP_Add (P, Buf);
-
-        /* Get the entry from the id */
-        const StrPoolEntry* E = CollConstAt (&P->Entries, Id);
-
-        /* Skip this string */
-        Buf  += E->Len + 1;
-        Size -= E->Len + 1;
-    }
-
-    /* Return the number of strings added */
-    return SB_GetCount (P) - OldCount;
+    /* Return the id of the new entry */
+    return Id;
 }
 
 
 
-void SP_Build (StrPool* P, const void* Buffer, unsigned Size)
-/* Delete existing data and use the data from Buffer instead. */
+unsigned SP_GetCount (const StringPool* P)
+/* Return the number of strings in the pool */
 {
-    /* Delete old data */
-    DoneStrPool (P);
-
-    /* Add the buffer data */
-    SP_AddBuf (P, Buffer, Size);
+    return CollCount (&P->Entries);
 }
-
-
-