diff options
Diffstat (limited to 'gold/stringpool.cc')
-rw-r--r-- | gold/stringpool.cc | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/gold/stringpool.cc b/gold/stringpool.cc new file mode 100644 index 0000000..0368014 --- /dev/null +++ b/gold/stringpool.cc @@ -0,0 +1,130 @@ +// stringpool.cc -- a string pool for gold + +#include "gold.h" + +#include <cassert> +#include <cstring> + +#include "stringpool.h" + +namespace gold +{ + +Stringpool::Stringpool() + : string_set_(), strings_() +{ +} + +Stringpool::~Stringpool() +{ + for (std::list<stringdata*>::iterator p = this->strings_.begin(); + p != this->strings_.end(); + ++p) + delete[] reinterpret_cast<char*>(*p); +} + +// Hash function. + +size_t +Stringpool::Stringpool_hash::operator()(const char* s) const +{ + // Fowler/Noll/Vo (FNV) hash (type FNV-1a). + if (sizeof(size_t) == 8) + { + size_t result = 14695981039346656037ULL; + while (*s != '\0') + { + result &= (size_t) *s++; + result *= 1099511628211ULL; + } + return result; + } + else + { + size_t result = 2166136261UL; + while (*s != '\0') + { + result ^= (size_t) *s++; + result *= 16777619UL; + } + return result; + } +} + +// Add a string to the list of canonical strings. Return a pointer to +// the canonical string. + +const char* +Stringpool::add_string(const char* s) +{ + const size_t buffer_size = 1000; + size_t len = strlen(s); + + size_t alc; + bool front = true; + if (len >= buffer_size) + { + alc = sizeof(stringdata) + len; + front = false; + } + else if (this->strings_.empty()) + alc = sizeof(stringdata) + buffer_size; + else + { + stringdata *psd = this->strings_.front(); + if (len >= psd->alc - psd->len) + alc = sizeof(stringdata) + buffer_size; + else + { + char* ret = psd->data + psd->len; + memcpy(ret, s, len + 1); + psd->len += len + 1; + return ret; + } + } + + stringdata *psd = reinterpret_cast<stringdata*>(new char[alc]); + psd->alc = alc; + memcpy(psd->data, s, len + 1); + psd->len = len + 1; + if (front) + this->strings_.push_front(psd); + else + this->strings_.push_back(psd); + return psd->data; +} + +// Add a string to a string pool. + +const char* +Stringpool::add(const char* s) +{ + // FIXME: This will look up the entry twice in the hash table. The + // problem is that we can't insert S before we canonicalize it. I + // don't think there is a way to handle this correct with + // unordered_set, so this should be replaced with custom code to do + // what we need, which is to return the empty slot. + + String_set_type::const_iterator p = this->string_set_.find(s); + if (p != this->string_set_.end()) + return *p; + + const char* ret = this->add_string(s); + std::pair<String_set_type::iterator, bool> ins = + this->string_set_.insert(ret); + assert(ins.second); + return ret; +} + +// Add a prefix of a string to a string pool. + +const char* +Stringpool::add(const char* s, size_t len) +{ + // FIXME: This implementation should be rewritten when we rewrite + // the hash table to avoid copying. + std::string st(s, len); + return this->add(st); +} + +} // End namespace gold. |