diff options
Diffstat (limited to 'src/emscripten-optimizer/istring.h')
-rw-r--r-- | src/emscripten-optimizer/istring.h | 161 |
1 files changed, 161 insertions, 0 deletions
diff --git a/src/emscripten-optimizer/istring.h b/src/emscripten-optimizer/istring.h new file mode 100644 index 000000000..b77fec4e5 --- /dev/null +++ b/src/emscripten-optimizer/istring.h @@ -0,0 +1,161 @@ +// Interned String type, 100% interned on creation. Comparisons are always just a pointer comparison + +#ifndef __istring_h__ +#define __istring_h__ + +#include <unordered_set> +#include <unordered_map> +#include <set> + +#include <string.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> + +namespace cashew { + +struct IString { + const char *str; + + static size_t hash_c(const char *str) { // see http://www.cse.yorku.ca/~oz/hash.html + unsigned int hash = 5381; + int c; + while ((c = *str++)) { + hash = ((hash << 5) + hash) ^ c; + } + return (size_t)hash; + } + + class CStringHash : public std::hash<const char *> { + public: + size_t operator()(const char *str) const { + return IString::hash_c(str); + } + }; + class CStringEqual : public std::equal_to<const char *> { + public: + bool operator()(const char *x, const char *y) const { + return strcmp(x, y) == 0; + } + }; + + IString() : str(nullptr) {} + IString(const char *s, bool reuse=true) { // if reuse=true, then input is assumed to remain alive; not copied + assert(s); + set(s, reuse); + } + + void set(const char *s, bool reuse=true) { + typedef std::unordered_set<const char *, CStringHash, CStringEqual> StringSet; + static StringSet* strings = new StringSet(); + + if (reuse) { + auto result = strings->insert(s); // if already present, does nothing + str = *(result.first); + } else { + auto existing = strings->find(s); + if (existing == strings->end()) { + char *copy = (char*)malloc(strlen(s)+1); // XXX leaked + strcpy(copy, s); + s = copy; + } else { + s = *existing; + } + strings->insert(s); + str = s; + } + } + + void set(const IString &s) { + str = s.str; + } + + void clear() { + str = nullptr; + } + + bool operator==(const IString& other) const { + //assert((str == other.str) == !strcmp(str, other.str)); + return str == other.str; // fast! + } + bool operator!=(const IString& other) const { + //assert((str == other.str) == !strcmp(str, other.str)); + return str != other.str; // fast! + } + bool operator<(const IString& other) const { + return strcmp(str ? str : "", other.str ? other.str : "") < 0; + } + + char operator[](int x) const { + return str[x]; + } + + bool operator!() const { // no string, or empty string + return !str || str[0] == 0; + } + + const char *c_str() const { return str; } + bool equals(const char *other) const { return !strcmp(str, other); } + + bool is() { return str != nullptr; } + bool isNull() { return str == nullptr; } +}; + +} // namespace cashew + +// Utilities for creating hashmaps/sets over IStrings + +namespace std { + +template <> struct hash<cashew::IString> : public unary_function<cashew::IString, size_t> { + size_t operator()(const cashew::IString& str) const { + size_t hash = size_t(str.str); + return hash = ((hash << 5) + hash) ^ 5381; /* (hash * 33) ^ c */ + } +}; + +template <> struct equal_to<cashew::IString> : public binary_function<cashew::IString, cashew::IString, bool> { + bool operator()(const cashew::IString& x, const cashew::IString& y) const { + return x == y; + } +}; + +} // namespace std + +namespace cashew { + +// IStringSet + +class IStringSet : public std::unordered_set<IString> { +public: + IStringSet() {} + IStringSet(const char *init) { // comma-delimited list + int size = strlen(init); + char *curr = new char[size+1]; // leaked! + strcpy(curr, init); + while (1) { + char *end = strchr(curr, ' '); + if (end) *end = 0; + insert(curr); + if (!end) break; + curr = end + 1; + } + } + + bool has(const IString& str) { + return count(str) > 0; + } +}; + +class IOrderedStringSet : public std::set<IString> { +public: + bool has(const IString& str) { + return count(str) > 0; + } +}; + +} // namespace cashew + +#endif // __istring_h__ + |