Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 //===- subzero/src/IceStringPool.h - String pooling -------------*- C++ -*-===// | |
| 2 // | |
| 3 // The Subzero Code Generator | |
| 4 // | |
| 5 // This file is distributed under the University of Illinois Open Source | |
| 6 // License. See LICENSE.TXT for details. | |
| 7 // | |
| 8 //===----------------------------------------------------------------------===// | |
| 9 /// | |
| 10 /// \file | |
| 11 /// \brief Defines unique pooled strings with short unique IDs. This makes | |
| 12 /// hashing, equality testing, and ordered comparison faster, and avoids a lot | |
| 13 /// of memory allocation compared to directly using std::string. | |
| 14 /// | |
| 15 //===----------------------------------------------------------------------===// | |
| 16 | |
| 17 #ifndef SUBZERO_SRC_ICESTRINGPOOL_H | |
| 18 #define SUBZERO_SRC_ICESTRINGPOOL_H | |
| 19 | |
| 20 #include <cstdint> // uintptr_t | |
| 21 #include <string> | |
| 22 | |
| 23 namespace Ice { | |
| 24 | |
| 25 class StringPool { | |
| 26 StringPool(const StringPool &) = delete; | |
| 27 StringPool &operator=(const StringPool &) = delete; | |
| 28 | |
| 29 public: | |
| 30 using IDType = uintptr_t; | |
| 31 | |
| 32 StringPool() = default; | |
| 33 ~StringPool() = default; | |
| 34 IDType getNewID() { | |
| 35 // TODO(stichnot): Make it so that the GlobalString ctor doesn't have to | |
| 36 // grab the lock, and instead does an atomic increment of NextID. | |
| 37 auto NewID = NextID; | |
| 38 NextID += IDIncrement; | |
| 39 return NewID; | |
| 40 } | |
| 41 IDType getOrAddString(const std::string &Value) { | |
| 42 auto Iter = StringToId.find(Value); | |
| 43 if (Iter == StringToId.end()) { | |
| 44 auto *NewStr = new std::string(Value); | |
| 45 auto ID = reinterpret_cast<IDType>(NewStr); | |
| 46 assert(StringToId.find(Value) == StringToId.end()); | |
|
John
2016/03/29 14:23:16
why the assert?
Jim Stichnoth
2016/03/29 21:40:50
I think this was left over from an earlier impleme
| |
| 47 StringToId[Value].reset(NewStr); | |
| 48 return ID; | |
| 49 } | |
| 50 return reinterpret_cast<IDType>(Iter->second.get()); | |
| 51 } | |
| 52 void dump(Ostream &Str) { | |
|
John
2016/03/29 14:23:16
const
Jim Stichnoth
2016/03/29 21:40:50
Done.
| |
| 53 if (StringToId.empty()) | |
| 54 return; | |
| 55 Str << "String pool (NumStrings=" << StringToId.size() | |
| 56 << " NumIDs=" << ((NextID - FirstID) / IDIncrement) << "):"; | |
| 57 for (auto &Tuple : StringToId) { | |
|
John
2016/03/29 14:23:16
const auto &
Jim Stichnoth
2016/03/29 21:40:50
Done.
| |
| 58 Str << " " << Tuple.first; | |
| 59 } | |
| 60 Str << "\n"; | |
| 61 } | |
| 62 | |
| 63 private: | |
| 64 static constexpr IDType FirstID = 1; | |
| 65 static constexpr IDType IDIncrement = 2; | |
| 66 IDType NextID = FirstID; | |
| 67 std::unordered_map<std::string, std::unique_ptr<std::string>> StringToId; | |
| 68 }; | |
| 69 | |
| 70 template <typename Traits> class StringID { | |
| 71 public: | |
| 72 using IDType = StringPool::IDType; | |
| 73 | |
| 74 StringID(const StringID &) = default; | |
| 75 StringID &operator=(const StringID &) = default; | |
| 76 // Create a default, invalid StringID. | |
| 77 StringID() = default; | |
|
John
2016/03/29 14:23:16
I would declare ctors/assignment opers in the foll
Jim Stichnoth
2016/03/29 21:40:50
Done.
| |
| 78 /// Create a unique StringID without an actual string, by grabbing the next | |
| 79 /// unique integral ID from the Owner. | |
|
John
2016/03/29 14:23:16
The comment you added explain what the ctor does,
Jim Stichnoth
2016/03/29 21:40:50
Nice, done.
| |
| 80 explicit StringID(const typename Traits::OwnerType *Owner) | |
| 81 : ID(Traits::getStrings(Owner)->getNewID()) {} | |
| 82 /// Create a unique StringID that holds an actual string, by fetching or | |
| 83 /// adding the string from the Owner's pool. | |
| 84 StringID(const typename Traits::OwnerType *Owner, const std::string &Value) | |
| 85 : ID(Traits::getStrings(Owner)->getOrAddString(Value)) { | |
| 86 assert(hasString()); | |
| 87 } | |
| 88 | |
| 89 static bool hasString(IDType ID) { return isValid(ID) && ((ID & 0x1) == 0); } | |
|
John
2016/03/29 14:23:16
I am suspicious of static methods as they are ofte
Jim Stichnoth
2016/03/29 21:40:50
Done - using hasStdString().
| |
| 90 bool hasString() const { return hasString(ID); } | |
| 91 | |
| 92 IDType getID() const { | |
| 93 assert(isValid()); | |
| 94 return ID; | |
| 95 } | |
| 96 const std::string &toString() const { | |
| 97 assert(hasString()); | |
|
John
2016/03/29 14:23:16
an assert here looks wrong -- if somehow toString(
Jim Stichnoth
2016/03/29 21:40:50
Done.
| |
| 98 return *reinterpret_cast<std::string *>(ID); | |
| 99 } | |
| 100 std::string toStringOrEmpty() const { | |
| 101 if (hasString()) | |
| 102 return toString(); | |
| 103 return ""; | |
| 104 } | |
| 105 | |
| 106 bool operator==(const StringID &Other) const { return ID == Other.ID; } | |
| 107 bool operator!=(const StringID &Other) const { return !(*this == Other); } | |
| 108 bool operator<(const StringID &Other) const { | |
| 109 const bool ThisHasString = hasString(); | |
| 110 const bool OtherHasString = Other.hasString(); | |
| 111 // Do a normal string comparison if both have strings. | |
| 112 if (ThisHasString && OtherHasString) | |
| 113 return this->toString() < Other.toString(); | |
| 114 // Use the ID as a tiebreaker if neither has a string. | |
| 115 if (!ThisHasString && !OtherHasString) | |
| 116 return ID < Other.ID; | |
| 117 // If exactly one has a string, then that one comes first. | |
| 118 assert(!OtherHasString); | |
| 119 return ThisHasString; | |
| 120 } | |
| 121 | |
| 122 private: | |
| 123 static constexpr IDType InvalidID = 0; | |
| 124 IDType ID = InvalidID; | |
| 125 | |
| 126 static bool isValid(IDType ID) { return ID != InvalidID; } | |
|
John
2016/03/29 14:23:16
same thing for the static method here.
Jim Stichnoth
2016/03/29 21:40:50
Done.
| |
| 127 bool isValid() const { return isValid(ID); } | |
| 128 }; | |
| 129 | |
| 130 struct GlobalStringPoolTraits { | |
|
John
2016/03/29 14:23:16
I got to move this to IceDefs.h, but not to IceGlo
Jim Stichnoth
2016/03/29 21:40:49
Left this alone, but added a TODO.
| |
| 131 using OwnerType = GlobalContext; | |
| 132 static LockedPtr<StringPool> getStrings(const OwnerType *Owner); | |
| 133 }; | |
| 134 | |
| 135 using GlobalString = StringID<struct GlobalStringPoolTraits>; | |
| 136 | |
| 137 template <typename T> | |
| 138 Ostream &operator<<(Ostream &Str, const StringID<T> &Name) { | |
| 139 return Str << Name.toString(); | |
| 140 } | |
| 141 | |
| 142 template <typename T> | |
| 143 std::string operator+(const std::string &A, const StringID<T> &B) { | |
| 144 return A + B.toString(); | |
| 145 } | |
| 146 | |
| 147 template <typename T> | |
| 148 std::string operator+(const StringID<T> &A, const std::string &B) { | |
| 149 return A.toString() + B; | |
| 150 } | |
| 151 | |
| 152 } // end of namespace Ice | |
| 153 | |
| 154 namespace std { | |
| 155 template <typename T> struct hash<Ice::StringID<T>> { | |
| 156 size_t operator()(const Ice::StringID<T> &Key) const { | |
| 157 if (Key.hasString()) | |
| 158 return hash<std::string>()(Key.toString()); | |
| 159 return hash<Ice::StringPool::IDType>()(Key.getID()); | |
| 160 } | |
| 161 }; | |
| 162 } // end of namespace std | |
| 163 | |
| 164 #endif // SUBZERO_SRC_ICESTRINGPOOL_H | |
| OLD | NEW |