diff --git a/charpool.cc b/charpool.cc index e0963100a..313db169a 100644 --- a/charpool.cc +++ b/charpool.cc @@ -72,8 +72,8 @@ static char *charpool[16]; static int currentcharpool; -static int currentcharpoolsz; -static char *nextchar; +static size_t currentcharpoolsz; +static size_t nexti; /* Allocated blocks are allocated to multiples of ALIGN_ON. This is the definition used by the malloc in Glibc 2.7, which says that it "suffices for @@ -87,7 +87,8 @@ static int cp_init(void) { /* Create our char pool */ currentcharpool = 0; currentcharpoolsz = 16384; - nextchar = charpool[0] = (char *) safe_malloc(currentcharpoolsz); + nexti = 0; + charpool[0] = (char *) safe_malloc(currentcharpoolsz); charpool_initialized = 1; return 0; } @@ -109,8 +110,8 @@ static inline void cp_grow(void) { } currentcharpoolsz <<= 1; - nextchar = charpool[currentcharpool] = (char *) - safe_malloc(currentcharpoolsz); + nexti = 0; + charpool[currentcharpool] = (char *) safe_malloc(currentcharpoolsz); } void *cp_alloc(int sz) { @@ -122,9 +123,9 @@ void *cp_alloc(int sz) { if ((modulus = sz % ALIGN_ON)) sz += ALIGN_ON - modulus; - if ((nextchar - charpool[currentcharpool]) + sz <= currentcharpoolsz) { - p = nextchar; - nextchar += sz; + if (nexti + sz <= currentcharpoolsz) { + p = charpool[currentcharpool] + nexti; + nexti += sz; return p; } /* Doh! We've got to make room */ @@ -134,32 +135,12 @@ void *cp_alloc(int sz) { } -char *cp_strdup(const char *src) { -const char *p; -char *q; -/* end points to the first illegal char */ -char *end; -int modulus; - - cp_init(); - - end = charpool[currentcharpool] + currentcharpoolsz; - q = nextchar; - p = src; - while((nextchar < end) && *p) { - *nextchar++ = *p++; - } - - if (nextchar < end) { - /* Goody, we have space */ - *nextchar++ = '\0'; - if ((modulus = (nextchar - q) % ALIGN_ON)) - nextchar += ALIGN_ON - modulus; - return q; - } - - /* Doh! We ran out -- need to allocate more */ - cp_grow(); - - return cp_strdup(src); +const char *cp_strndup(const char *src, int len) { + char *dst = (char *) cp_alloc(len + 1); // Additional byte for null terminator + dst[len] = '\0'; + return (const char *) memcpy(dst, src, len); +} + +const char *cp_strdup(const char *src) { + return cp_strndup(src, strlen(src)); } diff --git a/charpool.h b/charpool.h index 3fc3f564d..e9bc26fb1 100644 --- a/charpool.h +++ b/charpool.h @@ -66,7 +66,9 @@ #define CHARPOOL_H void *cp_alloc(int sz); -char *cp_strdup(const char *src); +/* len does not include null terminator */ +const char *cp_strndup(const char *src, int len); +const char *cp_strdup(const char *src); void cp_free(void); diff --git a/string_pool.cc b/string_pool.cc index 12d689bff..44452fb40 100644 --- a/string_pool.cc +++ b/string_pool.cc @@ -58,9 +58,11 @@ ***************************************************************************/ #include "string_pool.h" #include +#include "charpool.h" #include #include +#include #include #include #include @@ -69,19 +71,52 @@ #undef NDEBUG #include +class StringPoolItem { + public: + const char *str; + int len; + bool in_cp; + + StringPoolItem(const char *i_str, int i_len) : str(i_str), len(i_len), in_cp(false) {} + ~StringPoolItem() {} // charpool allocations are permanent and can't be freed. + StringPoolItem(const StringPoolItem& other) { + // If the string is already in the charpool, there's no reason we should + // be copy-constructed, since that only happens on a successful insert + // (new unique item) + assert(!other.in_cp); + this->len = other.len; + this->str = cp_strndup(other.str, other.len); + this->in_cp = true; + } + +// asdfq <> asdf + bool operator< (const StringPoolItem& other) const { + return this->len < other.len || memcmp(this->str, other.str, other.len) < 0; + } +}; + +typedef std::set StringPool; + +const char *string_pool_insert_len(const char *s, int len) +{ + static StringPool pool; + StringPoolItem spi (s, len); + + StringPool::iterator it = pool.insert(spi).first; + assert(it->in_cp); // We should only be storing charpool-allocated strings + + return it->str; +} + const char *string_pool_insert(const char *s) { - static std::set pool; - static std::pair::iterator, bool> pair; - - pair = pool.insert(s); - - return pair.first->c_str(); + return string_pool_insert_len(s, strlen(s)); } const char *string_pool_substr(const char *s, const char *t) { - return string_pool_insert(std::string(s, t).c_str()); + assert(t >= s); + return string_pool_insert_len(s, t - s); } const char *string_pool_substr_strip(const char *s, const char *t) { @@ -133,7 +168,7 @@ const char *string_pool_sprintf(const char *fmt, ...) break; } - s = string_pool_insert(buf); + s = string_pool_insert_len(buf, n); free(buf); return s;