diff options
Diffstat (limited to 'gold/stringpool.cc')
-rw-r--r-- | gold/stringpool.cc | 222 |
1 files changed, 157 insertions, 65 deletions
diff --git a/gold/stringpool.cc b/gold/stringpool.cc index d53cf77..34c11b4 100644 --- a/gold/stringpool.cc +++ b/gold/stringpool.cc @@ -12,42 +12,103 @@ namespace gold { -Stringpool::Stringpool() - : string_set_(), strings_(), strtab_size_(0), next_index_(1) +template<typename Stringpool_char> +Stringpool_template<Stringpool_char>::Stringpool_template(bool zero_null) + : string_set_(), strings_(), strtab_size_(0), next_index_(1), + zero_null_(zero_null) { } -Stringpool::~Stringpool() +template<typename Stringpool_char> +Stringpool_template<Stringpool_char>::~Stringpool_template() { - for (std::list<Stringdata*>::iterator p = this->strings_.begin(); + for (typename std::list<Stringdata*>::iterator p = this->strings_.begin(); p != this->strings_.end(); ++p) delete[] reinterpret_cast<char*>(*p); } +// Return the length of a string of arbitrary character type. + +template<typename Stringpool_char> +size_t +Stringpool_template<Stringpool_char>::string_length(const Stringpool_char* p) +{ + size_t len = 0; + for (; *p != 0; ++p) + ++len; + return len; +} + +// Specialize string_length for char. Maybe we could just use +// std::char_traits<>::length? + +template<> +inline size_t +Stringpool_template<char>::string_length(const char* p) +{ + return strlen(p); +} + +// Equality comparison function. + +template<typename Stringpool_char> +bool +Stringpool_template<Stringpool_char>::Stringpool_eq::operator()( + const Stringpool_char* s1, + const Stringpool_char* s2) const +{ + while (*s1 != 0) + if (*s1++ != *s2++) + return false; + return *s2 == 0; +} + +// Specialize equality comparison for char. + +template<> +bool +Stringpool_template<char>::Stringpool_eq::operator()(const char* s1, + const char* s2) const +{ + return strcmp(s1, s2) == 0; +} + // Hash function. +template<typename Stringpool_char> size_t -Stringpool::Stringpool_hash::operator()(const char* s) const +Stringpool_template<Stringpool_char>::Stringpool_hash::operator()( + const Stringpool_char* s) const { // Fowler/Noll/Vo (FNV) hash (type FNV-1a). if (sizeof(size_t) == 8) { size_t result = static_cast<size_t>(14695981039346656037ULL); - while (*s != '\0') + while (*s != 0) { - result &= (size_t) *s++; - result *= 1099511628211ULL; + const char* p = reinterpret_cast<const char*>(s); + for (size_t i = 0; i < sizeof(Stringpool_char); ++i) + { + result &= (size_t) *p++; + result *= 1099511628211ULL; + } + ++s; } return result; } else { size_t result = 2166136261UL; - while (*s != '\0') + while (*s != 0) { - result ^= (size_t) *s++; - result *= 16777619UL; + const char* p = reinterpret_cast<const char*>(s); + for (size_t i = 0; i < sizeof(Stringpool_char); ++i) + { + result ^= (size_t) *p++; + result *= 16777619UL; + } + ++s; } return result; } @@ -56,8 +117,10 @@ Stringpool::Stringpool_hash::operator()(const char* s) const // Add a string to the list of canonical strings. Return a pointer to // the canonical string. If PKEY is not NULL, set *PKEY to the key. -const char* -Stringpool::add_string(const char* s, Key* pkey) +template<typename Stringpool_char> +const Stringpool_char* +Stringpool_template<Stringpool_char>::add_string(const Stringpool_char* s, + Key* pkey) { // We are in trouble if we've already computed the string offsets. gold_assert(this->strtab_size_ == 0); @@ -69,11 +132,11 @@ Stringpool::add_string(const char* s, Key* pkey) const size_t key_mult = 1024; gold_assert(key_mult >= buffer_size); - size_t len = strlen(s); + size_t len = (string_length(s) + 1) * sizeof(Stringpool_char); size_t alc; bool front = true; - if (len >= buffer_size) + if (len > buffer_size) { alc = sizeof(Stringdata) + len; front = false; @@ -83,26 +146,26 @@ Stringpool::add_string(const char* s, Key* pkey) else { Stringdata *psd = this->strings_.front(); - if (len >= psd->alc - psd->len) + if (len > psd->alc - psd->len) alc = sizeof(Stringdata) + buffer_size; else { char* ret = psd->data + psd->len; - memcpy(ret, s, len + 1); + memcpy(ret, s, len); if (pkey != NULL) *pkey = psd->index * key_mult + psd->len; - psd->len += len + 1; + psd->len += len; - return ret; + return reinterpret_cast<const Stringpool_char*>(ret); } } Stringdata *psd = reinterpret_cast<Stringdata*>(new char[alc]); psd->alc = alc - sizeof(Stringdata); - memcpy(psd->data, s, len + 1); - psd->len = len + 1; + memcpy(psd->data, s, len); + psd->len = len; psd->index = this->next_index_; ++this->next_index_; @@ -114,13 +177,14 @@ Stringpool::add_string(const char* s, Key* pkey) else this->strings_.push_back(psd); - return psd->data; + return reinterpret_cast<const Stringpool_char*>(psd->data); } // Add a string to a string pool. -const char* -Stringpool::add(const char* s, Key* pkey) +template<typename Stringpool_char> +const Stringpool_char* +Stringpool_template<Stringpool_char>::add(const Stringpool_char* s, Key* pkey) { // 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 @@ -128,7 +192,7 @@ Stringpool::add(const char* s, Key* pkey) // unordered_map, 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); + typename String_set_type::const_iterator p = this->string_set_.find(s); if (p != this->string_set_.end()) { if (pkey != NULL) @@ -137,11 +201,12 @@ Stringpool::add(const char* s, Key* pkey) } Key k; - const char* ret = this->add_string(s, &k); + const Stringpool_char* ret = this->add_string(s, &k); const off_t ozero = 0; - std::pair<const char*, Val> element(ret, std::make_pair(k, ozero)); - std::pair<String_set_type::iterator, bool> ins = + std::pair<const Stringpool_char*, Val> element(ret, + std::make_pair(k, ozero)); + std::pair<typename String_set_type::iterator, bool> ins = this->string_set_.insert(element); gold_assert(ins.second); @@ -153,19 +218,23 @@ Stringpool::add(const char* s, Key* pkey) // Add a prefix of a string to a string pool. -const char* -Stringpool::add(const char* s, size_t len, Key* pkey) +template<typename Stringpool_char> +const Stringpool_char* +Stringpool_template<Stringpool_char>::add(const Stringpool_char* s, size_t len, + Key* pkey) { // FIXME: This implementation should be rewritten when we rewrite // the hash table to avoid copying. - std::string st(s, len); + std::basic_string<Stringpool_char> st(s, len); return this->add(st, pkey); } -const char* -Stringpool::find(const char* s, Key* pkey) const +template<typename Stringpool_char> +const Stringpool_char* +Stringpool_template<Stringpool_char>::find(const Stringpool_char* s, + Key* pkey) const { - String_set_type::const_iterator p = this->string_set_.find(s); + typename String_set_type::const_iterator p = this->string_set_.find(s); if (p == this->string_set_.end()) return NULL; @@ -186,19 +255,20 @@ Stringpool::find(const char* s, Key* pkey) const // in, but we need to ensure that suffixes wind up next to each other. // So we do a reversed lexicographic sort on the reversed string. +template<typename Stringpool_char> bool -Stringpool::Stringpool_sort_comparison::operator()( - String_set_type::iterator it1, - String_set_type::iterator it2) const +Stringpool_template<Stringpool_char>::Stringpool_sort_comparison::operator()( + typename String_set_type::iterator it1, + typename String_set_type::iterator it2) const { - const char* s1 = it1->first; - const char* s2 = it2->first; - int len1 = strlen(s1); - int len2 = strlen(s2); - int minlen = len1 < len2 ? len1 : len2; - const char* p1 = s1 + len1 - 1; - const char* p2 = s2 + len2 - 1; - for (int i = minlen - 1; i >= 0; --i, --p1, --p2) + const Stringpool_char* s1 = it1->first; + const Stringpool_char* s2 = it2->first; + size_t len1 = string_length(s1); + size_t len2 = string_length(s2); + size_t minlen = len1 < len2 ? len1 : len2; + const Stringpool_char* p1 = s1 + len1 - 1; + const Stringpool_char* p2 = s2 + len2 - 1; + for (size_t i = minlen; i > 0; --i, --p1, --p2) { if (*p1 != *p2) return *p1 > *p2; @@ -208,21 +278,24 @@ Stringpool::Stringpool_sort_comparison::operator()( // Return whether s1 is a suffix of s2. +template<typename Stringpool_char> bool -Stringpool::is_suffix(const char* s1, const char* s2) +Stringpool_template<Stringpool_char>::is_suffix(const Stringpool_char* s1, + const Stringpool_char* s2) { - size_t len1 = strlen(s1); - size_t len2 = strlen(s2); + size_t len1 = string_length(s1); + size_t len2 = string_length(s2); if (len1 > len2) return false; - return strcmp(s1, s2 + len2 - len1) == 0; + return memcmp(s1, s2 + len2 - len1, len1 * sizeof(Stringpool_char)) == 0; } // Turn the stringpool into an ELF strtab: determine the offsets of // each string in the table. +template<typename Stringpool_char> void -Stringpool::set_string_offsets() +Stringpool_template<Stringpool_char>::set_string_offsets() { if (this->strtab_size_ != 0) { @@ -232,30 +305,33 @@ Stringpool::set_string_offsets() size_t count = this->string_set_.size(); - std::vector<String_set_type::iterator> v; + std::vector<typename String_set_type::iterator> v; v.reserve(count); - for (String_set_type::iterator p = this->string_set_.begin(); + for (typename String_set_type::iterator p = this->string_set_.begin(); p != this->string_set_.end(); ++p) v.push_back(p); std::sort(v.begin(), v.end(), Stringpool_sort_comparison()); - // Offset 0 is reserved for the empty string. - off_t offset = 1; + const size_t charsize = sizeof(Stringpool_char); + + // Offset 0 may be reserved for the empty string. + off_t offset = this->zero_null_ ? charsize : 0; for (size_t i = 0; i < count; ++i) { - if (v[i]->first[0] == '\0') + if (this->zero_null_ && v[i]->first[0] == 0) v[i]->second.second = 0; - else if (i > 0 && Stringpool::is_suffix(v[i]->first, v[i - 1]->first)) + else if (i > 0 && is_suffix(v[i]->first, v[i - 1]->first)) v[i]->second.second = (v[i - 1]->second.second - + strlen(v[i - 1]->first) - - strlen(v[i]->first)); + + ((string_length(v[i - 1]->first) + - string_length(v[i]->first)) + * charsize)); else { v[i]->second.second = offset; - offset += strlen(v[i]->first) + 1; + offset += (string_length(v[i]->first) + 1) * charsize; } } @@ -265,11 +341,13 @@ Stringpool::set_string_offsets() // Get the offset of a string in the ELF strtab. The string must // exist. +template<typename Stringpool_char> off_t -Stringpool::get_offset(const char* s) const +Stringpool_template<Stringpool_char>::get_offset(const Stringpool_char* s) + const { gold_assert(this->strtab_size_ != 0); - String_set_type::const_iterator p = this->string_set_.find(s); + typename String_set_type::const_iterator p = this->string_set_.find(s); if (p != this->string_set_.end()) return p->second.second; gold_unreachable(); @@ -277,18 +355,32 @@ Stringpool::get_offset(const char* s) const // Write the ELF strtab into the output file at the specified offset. +template<typename Stringpool_char> void -Stringpool::write(Output_file* of, off_t offset) +Stringpool_template<Stringpool_char>::write(Output_file* of, off_t offset) { gold_assert(this->strtab_size_ != 0); unsigned char* viewu = of->get_output_view(offset, this->strtab_size_); char* view = reinterpret_cast<char*>(viewu); - view[0] = '\0'; - for (String_set_type::const_iterator p = this->string_set_.begin(); + if (this->zero_null_) + view[0] = '\0'; + for (typename String_set_type::const_iterator p = this->string_set_.begin(); p != this->string_set_.end(); ++p) - strcpy(view + p->second.second, p->first); + memcpy(view + p->second.second, p->first, + (string_length(p->first) + 1) * sizeof(Stringpool_char)); of->write_output_view(offset, this->strtab_size_, viewu); } +// Instantiate the templates we need. + +template +class Stringpool_template<char>; + +template +class Stringpool_template<uint16_t>; + +template +class Stringpool_template<uint32_t>; + } // End namespace gold. |