michael@0: // Copyright (c) 2013 Google Inc. michael@0: // All rights reserved. michael@0: // michael@0: // Redistribution and use in source and binary forms, with or without michael@0: // modification, are permitted provided that the following conditions are michael@0: // met: michael@0: // michael@0: // * Redistributions of source code must retain the above copyright michael@0: // notice, this list of conditions and the following disclaimer. michael@0: // * Redistributions in binary form must reproduce the above michael@0: // copyright notice, this list of conditions and the following disclaimer michael@0: // in the documentation and/or other materials provided with the michael@0: // distribution. michael@0: // * Neither the name of Google Inc. nor the names of its michael@0: // contributors may be used to endorse or promote products derived from michael@0: // this software without specific prior written permission. michael@0: // michael@0: // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: michael@0: #ifndef COMMON_UNIQUE_STRING_H_ michael@0: #define COMMON_UNIQUE_STRING_H_ michael@0: michael@0: #include michael@0: #include michael@0: #include "common/using_std_string.h" michael@0: michael@0: namespace google_breakpad { michael@0: michael@0: // Abstract type michael@0: class UniqueString; michael@0: michael@0: // Unique-ify a string. |ToUniqueString| can never return NULL. michael@0: const UniqueString* ToUniqueString(string); michael@0: michael@0: // ditto, starting instead from the first n characters of a C string michael@0: const UniqueString* ToUniqueString_n(const char* str, size_t n); michael@0: michael@0: // Pull chars out of the string. No range checking. michael@0: const char Index(const UniqueString*, int); michael@0: michael@0: // Get the contained C string (debugging only) michael@0: const char* const FromUniqueString(const UniqueString*); michael@0: michael@0: // Do a strcmp-style comparison on the contained C string michael@0: int StrcmpUniqueString(const UniqueString*, const UniqueString*); michael@0: michael@0: // Less-than comparison of two UniqueStrings, usable for std::sort. michael@0: bool LessThan_UniqueString(const UniqueString*, const UniqueString*); michael@0: michael@0: // Some handy pre-uniqified strings. Z is an escape character: michael@0: // ZS '$' michael@0: // ZD '.' michael@0: // Zeq '=' michael@0: // Zplus '+' michael@0: // Zstar '*' michael@0: // Zslash '/' michael@0: // Zpercent '%' michael@0: // Zat '@' michael@0: // Zcaret '^' michael@0: michael@0: // Note that ustr__empty and (UniqueString*)NULL are considered michael@0: // to be different. michael@0: // michael@0: // Unfortunately these have to be written as functions so as to michael@0: // make them safe to use in static initialisers. michael@0: michael@0: // "" michael@0: inline static const UniqueString* ustr__empty() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString(""); michael@0: return us; michael@0: } michael@0: michael@0: // "$eip" michael@0: inline static const UniqueString* ustr__ZSeip() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString("$eip"); michael@0: return us; michael@0: } michael@0: michael@0: // "$ebp" michael@0: inline static const UniqueString* ustr__ZSebp() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString("$ebp"); michael@0: return us; michael@0: } michael@0: michael@0: // "$esp" michael@0: inline static const UniqueString* ustr__ZSesp() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString("$esp"); michael@0: return us; michael@0: } michael@0: michael@0: // "$ebx" michael@0: inline static const UniqueString* ustr__ZSebx() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString("$ebx"); michael@0: return us; michael@0: } michael@0: michael@0: // "$esi" michael@0: inline static const UniqueString* ustr__ZSesi() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString("$esi"); michael@0: return us; michael@0: } michael@0: michael@0: // "$edi" michael@0: inline static const UniqueString* ustr__ZSedi() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString("$edi"); michael@0: return us; michael@0: } michael@0: michael@0: // ".cbCalleeParams" michael@0: inline static const UniqueString* ustr__ZDcbCalleeParams() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString(".cbCalleeParams"); michael@0: return us; michael@0: } michael@0: michael@0: // ".cbSavedRegs" michael@0: inline static const UniqueString* ustr__ZDcbSavedRegs() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString(".cbSavedRegs"); michael@0: return us; michael@0: } michael@0: michael@0: // ".cbLocals" michael@0: inline static const UniqueString* ustr__ZDcbLocals() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString(".cbLocals"); michael@0: return us; michael@0: } michael@0: michael@0: // ".raSearchStart" michael@0: inline static const UniqueString* ustr__ZDraSearchStart() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString(".raSearchStart"); michael@0: return us; michael@0: } michael@0: michael@0: // ".raSearch" michael@0: inline static const UniqueString* ustr__ZDraSearch() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString(".raSearch"); michael@0: return us; michael@0: } michael@0: michael@0: // ".cbParams" michael@0: inline static const UniqueString* ustr__ZDcbParams() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString(".cbParams"); michael@0: return us; michael@0: } michael@0: michael@0: // "+" michael@0: inline static const UniqueString* ustr__Zplus() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString("+"); michael@0: return us; michael@0: } michael@0: michael@0: // "-" michael@0: inline static const UniqueString* ustr__Zminus() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString("-"); michael@0: return us; michael@0: } michael@0: michael@0: // "*" michael@0: inline static const UniqueString* ustr__Zstar() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString("*"); michael@0: return us; michael@0: } michael@0: michael@0: // "/" michael@0: inline static const UniqueString* ustr__Zslash() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString("/"); michael@0: return us; michael@0: } michael@0: michael@0: // "%" michael@0: inline static const UniqueString* ustr__Zpercent() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString("%"); michael@0: return us; michael@0: } michael@0: michael@0: // "@" michael@0: inline static const UniqueString* ustr__Zat() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString("@"); michael@0: return us; michael@0: } michael@0: michael@0: // "^" michael@0: inline static const UniqueString* ustr__Zcaret() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString("^"); michael@0: return us; michael@0: } michael@0: michael@0: // "=" michael@0: inline static const UniqueString* ustr__Zeq() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString("="); michael@0: return us; michael@0: } michael@0: michael@0: // ".cfa" michael@0: inline static const UniqueString* ustr__ZDcfa() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString(".cfa"); michael@0: return us; michael@0: } michael@0: michael@0: // ".ra" michael@0: inline static const UniqueString* ustr__ZDra() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString(".ra"); michael@0: return us; michael@0: } michael@0: michael@0: // "pc" michael@0: inline static const UniqueString* ustr__pc() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString("pc"); michael@0: return us; michael@0: } michael@0: michael@0: // "lr" michael@0: inline static const UniqueString* ustr__lr() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString("lr"); michael@0: return us; michael@0: } michael@0: michael@0: // "sp" michael@0: inline static const UniqueString* ustr__sp() { michael@0: static const UniqueString* us = NULL; michael@0: if (!us) us = ToUniqueString("sp"); michael@0: return us; michael@0: } michael@0: michael@0: template michael@0: class UniqueStringMap michael@0: { michael@0: private: michael@0: static const int N_FIXED = 10; michael@0: michael@0: public: michael@0: UniqueStringMap() : n_fixed_(0), n_sets_(0), n_gets_(0), n_clears_(0) {}; michael@0: ~UniqueStringMap() {}; michael@0: michael@0: // Empty out the map. michael@0: void clear() { michael@0: ++n_clears_; michael@0: map_.clear(); michael@0: n_fixed_ = 0; michael@0: } michael@0: michael@0: // Do "map[ix] = v". michael@0: void set(const UniqueString* ix, ValueType v) { michael@0: ++n_sets_; michael@0: int i; michael@0: for (i = 0; i < n_fixed_; ++i) { michael@0: if (fixed_keys_[i] == ix) { michael@0: fixed_vals_[i] = v; michael@0: return; michael@0: } michael@0: } michael@0: if (n_fixed_ < N_FIXED) { michael@0: i = n_fixed_; michael@0: fixed_keys_[i] = ix; michael@0: fixed_vals_[i] = v; michael@0: ++n_fixed_; michael@0: } else { michael@0: map_[ix] = v; michael@0: } michael@0: } michael@0: michael@0: // Lookup 'ix' in the map, and also return a success/fail boolean. michael@0: ValueType get(/*OUT*/bool* have, const UniqueString* ix) const { michael@0: ++n_gets_; michael@0: int i; michael@0: for (i = 0; i < n_fixed_; ++i) { michael@0: if (fixed_keys_[i] == ix) { michael@0: *have = true; michael@0: return fixed_vals_[i]; michael@0: } michael@0: } michael@0: typename std::map::const_iterator it michael@0: = map_.find(ix); michael@0: if (it == map_.end()) { michael@0: *have = false; michael@0: return ValueType(); michael@0: } else { michael@0: *have = true; michael@0: return it->second; michael@0: } michael@0: }; michael@0: michael@0: // Lookup 'ix' in the map, and return zero if it is not present. michael@0: ValueType get(const UniqueString* ix) const { michael@0: ++n_gets_; michael@0: bool found; michael@0: ValueType v = get(&found, ix); michael@0: return found ? v : ValueType(); michael@0: } michael@0: michael@0: // Find out whether 'ix' is in the map. michael@0: bool have(const UniqueString* ix) const { michael@0: ++n_gets_; michael@0: bool found; michael@0: (void)get(&found, ix); michael@0: return found; michael@0: } michael@0: michael@0: // Copy the contents to a std::map, generally for testing. michael@0: void copy_to_map(std::map* m) const { michael@0: m->clear(); michael@0: int i; michael@0: for (i = 0; i < n_fixed_; ++i) { michael@0: (*m)[fixed_keys_[i]] = fixed_vals_[i]; michael@0: } michael@0: m->insert(map_.begin(), map_.end()); michael@0: } michael@0: michael@0: // Note that users of this class rely on having also a sane michael@0: // assignment operator. The default one is OK, though. michael@0: // AFAICT there are no uses of the copy constructor, but if michael@0: // there were, the default one would also suffice. michael@0: michael@0: private: michael@0: // Quick (hopefully) cache michael@0: const UniqueString* fixed_keys_[N_FIXED]; michael@0: ValueType fixed_vals_[N_FIXED]; michael@0: int n_fixed_; // 0 .. N_FIXED inclusive michael@0: // Fallback storage when the cache is filled michael@0: std::map map_; michael@0: michael@0: // For tracking usage stats. michael@0: mutable int n_sets_, n_gets_, n_clears_; michael@0: }; michael@0: michael@0: } // namespace google_breakpad michael@0: michael@0: #endif // COMMON_UNIQUE_STRING_H_