| Index: src/IceStringPool.h
|
| diff --git a/src/IceStringPool.h b/src/IceStringPool.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..bd1c76b6da69da6a3a2a19294aa359b54c0faaca
|
| --- /dev/null
|
| +++ b/src/IceStringPool.h
|
| @@ -0,0 +1,164 @@
|
| +//===- subzero/src/IceStringPool.h - String pooling -------------*- C++ -*-===//
|
| +//
|
| +// The Subzero Code Generator
|
| +//
|
| +// This file is distributed under the University of Illinois Open Source
|
| +// License. See LICENSE.TXT for details.
|
| +//
|
| +//===----------------------------------------------------------------------===//
|
| +///
|
| +/// \file
|
| +/// \brief Defines unique pooled strings with short unique IDs. This makes
|
| +/// hashing, equality testing, and ordered comparison faster, and avoids a lot
|
| +/// of memory allocation compared to directly using std::string.
|
| +///
|
| +//===----------------------------------------------------------------------===//
|
| +
|
| +#ifndef SUBZERO_SRC_ICESTRINGPOOL_H
|
| +#define SUBZERO_SRC_ICESTRINGPOOL_H
|
| +
|
| +#include <cstdint> // uintptr_t
|
| +#include <string>
|
| +
|
| +namespace Ice {
|
| +
|
| +class StringPool {
|
| + StringPool(const StringPool &) = delete;
|
| + StringPool &operator=(const StringPool &) = delete;
|
| +
|
| +public:
|
| + using IDType = uintptr_t;
|
| +
|
| + StringPool() = default;
|
| + ~StringPool() = default;
|
| + IDType getNewID() {
|
| + // TODO(stichnot): Make it so that the GlobalString ctor doesn't have to
|
| + // grab the lock, and instead does an atomic increment of NextID.
|
| + auto NewID = NextID;
|
| + NextID += IDIncrement;
|
| + return NewID;
|
| + }
|
| + IDType getOrAddString(const std::string &Value) {
|
| + auto Iter = StringToId.find(Value);
|
| + if (Iter == StringToId.end()) {
|
| + auto *NewStr = new std::string(Value);
|
| + auto ID = reinterpret_cast<IDType>(NewStr);
|
| + assert(StringToId.find(Value) == StringToId.end());
|
| + StringToId[Value].reset(NewStr);
|
| + return ID;
|
| + }
|
| + return reinterpret_cast<IDType>(Iter->second.get());
|
| + }
|
| + void dump(Ostream &Str) {
|
| + if (StringToId.empty())
|
| + return;
|
| + Str << "String pool (NumStrings=" << StringToId.size()
|
| + << " NumIDs=" << ((NextID - FirstID) / IDIncrement) << "):";
|
| + for (auto &Tuple : StringToId) {
|
| + Str << " " << Tuple.first;
|
| + }
|
| + Str << "\n";
|
| + }
|
| +
|
| +private:
|
| + static constexpr IDType FirstID = 1;
|
| + static constexpr IDType IDIncrement = 2;
|
| + IDType NextID = FirstID;
|
| + std::unordered_map<std::string, std::unique_ptr<std::string>> StringToId;
|
| +};
|
| +
|
| +template <typename Traits> class StringID {
|
| +public:
|
| + using IDType = StringPool::IDType;
|
| +
|
| + StringID(const StringID &) = default;
|
| + StringID &operator=(const StringID &) = default;
|
| + // Create a default, invalid StringID.
|
| + StringID() = default;
|
| + /// Create a unique StringID without an actual string, by grabbing the next
|
| + /// unique integral ID from the Owner.
|
| + explicit StringID(const typename Traits::OwnerType *Owner)
|
| + : ID(Traits::getStrings(Owner)->getNewID()) {}
|
| + /// Create a unique StringID that holds an actual string, by fetching or
|
| + /// adding the string from the Owner's pool.
|
| + StringID(const typename Traits::OwnerType *Owner, const std::string &Value)
|
| + : ID(Traits::getStrings(Owner)->getOrAddString(Value)) {
|
| + assert(hasString());
|
| + }
|
| +
|
| + static bool hasString(IDType ID) { return isValid(ID) && ((ID & 0x1) == 0); }
|
| + bool hasString() const { return hasString(ID); }
|
| +
|
| + IDType getID() const {
|
| + assert(isValid());
|
| + return ID;
|
| + }
|
| + const std::string &toString() const {
|
| + assert(hasString());
|
| + return *reinterpret_cast<std::string *>(ID);
|
| + }
|
| + std::string toStringOrEmpty() const {
|
| + if (hasString())
|
| + return toString();
|
| + return "";
|
| + }
|
| +
|
| + bool operator==(const StringID &Other) const { return ID == Other.ID; }
|
| + bool operator!=(const StringID &Other) const { return !(*this == Other); }
|
| + bool operator<(const StringID &Other) const {
|
| + const bool ThisHasString = hasString();
|
| + const bool OtherHasString = Other.hasString();
|
| + // Do a normal string comparison if both have strings.
|
| + if (ThisHasString && OtherHasString)
|
| + return this->toString() < Other.toString();
|
| + // Use the ID as a tiebreaker if neither has a string.
|
| + if (!ThisHasString && !OtherHasString)
|
| + return ID < Other.ID;
|
| + // If exactly one has a string, then that one comes first.
|
| + assert(!OtherHasString);
|
| + return ThisHasString;
|
| + }
|
| +
|
| +private:
|
| + static constexpr IDType InvalidID = 0;
|
| + IDType ID = InvalidID;
|
| +
|
| + static bool isValid(IDType ID) { return ID != InvalidID; }
|
| + bool isValid() const { return isValid(ID); }
|
| +};
|
| +
|
| +struct GlobalStringPoolTraits {
|
| + using OwnerType = GlobalContext;
|
| + static LockedPtr<StringPool> getStrings(const OwnerType *Owner);
|
| +};
|
| +
|
| +using GlobalString = StringID<struct GlobalStringPoolTraits>;
|
| +
|
| +template <typename T>
|
| +Ostream &operator<<(Ostream &Str, const StringID<T> &Name) {
|
| + return Str << Name.toString();
|
| +}
|
| +
|
| +template <typename T>
|
| +std::string operator+(const std::string &A, const StringID<T> &B) {
|
| + return A + B.toString();
|
| +}
|
| +
|
| +template <typename T>
|
| +std::string operator+(const StringID<T> &A, const std::string &B) {
|
| + return A.toString() + B;
|
| +}
|
| +
|
| +} // end of namespace Ice
|
| +
|
| +namespace std {
|
| +template <typename T> struct hash<Ice::StringID<T>> {
|
| + size_t operator()(const Ice::StringID<T> &Key) const {
|
| + if (Key.hasString())
|
| + return hash<std::string>()(Key.toString());
|
| + return hash<Ice::StringPool::IDType>()(Key.getID());
|
| + }
|
| +};
|
| +} // end of namespace std
|
| +
|
| +#endif // SUBZERO_SRC_ICESTRINGPOOL_H
|
|
|