#ifndef wasm_istring_h
#define wasm_istring_h
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "support/threads.h"
#include "support/utilities.h"
namespace cashew {
struct IString {
const char* str = nullptr;
static size_t
hash_c(const char* str) { 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() = default;
IString(const char* s, bool reuse = true) {
assert(s);
set(s, reuse);
}
void set(const char* s, bool reuse = true) {
typedef std::unordered_set<const char*, CStringHash, CStringEqual>
StringSet;
thread_local static StringSet strings;
auto existing = strings.find(s);
if (existing == strings.end()) {
static std::mutex mutex;
std::unique_lock<std::mutex> lock(mutex);
static StringSet globalStrings;
auto globalExisting = globalStrings.find(s);
if (globalExisting == globalStrings.end()) {
if (!reuse) {
static std::vector<std::unique_ptr<std::string>> allocated;
allocated.emplace_back(wasm::make_unique<std::string>(s));
s = allocated.back()->c_str(); }
globalStrings.insert(s);
} else {
s = *globalExisting;
}
strings.insert(s);
} else {
s = *existing;
}
str = s;
}
void set(const IString& s) { str = s.str; }
void clear() { str = nullptr; }
bool operator==(const IString& other) const {
return str == other.str; }
bool operator!=(const IString& other) const {
return str != other.str; }
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 { return !str || str[0] == 0;
}
const char* c_str() const { return str; }
bool equals(const char* other) const { return !strcmp(str, other); }
bool is() const { return str != nullptr; }
bool isNull() const { return str == nullptr; }
const char* stripPrefix(const char* prefix) const {
const char* ptr = str;
while (true) {
if (*prefix == 0) {
return ptr;
}
if (*ptr == 0) {
return nullptr;
}
if (*ptr++ != *prefix++) {
return nullptr;
}
}
}
bool startsWith(const char* prefix) const {
return stripPrefix(prefix) != nullptr;
}
bool startsWith(const IString& prefix) const {
return startsWith(prefix.str);
}
size_t size() const { return str ? strlen(str) : 0; }
};
}
namespace std {
template<> struct hash<cashew::IString> {
size_t operator()(const cashew::IString& str) const {
return std::hash<size_t>{}(size_t(str.str));
}
};
template<> struct equal_to<cashew::IString> {
bool operator()(const cashew::IString& x, const cashew::IString& y) const {
return x == y;
}
};
}
namespace cashew {
class IStringSet : public std::unordered_set<IString> {
std::vector<char> data;
public:
IStringSet() = default;
IStringSet(const char* init) { int size = strlen(init) + 1;
data.resize(size);
char* curr = &data[0];
strncpy(curr, init, size);
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; }
};
}
#endif