1 | /* |
2 | * Copyright 2022 WebAssembly Community Group participants |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | // Interned String type, 100% interned on creation. Comparisons are always just |
18 | // a pointer comparison |
19 | |
20 | #ifndef wasm_support_istring_h |
21 | #define wasm_support_istring_h |
22 | |
23 | #include <set> |
24 | #include <string_view> |
25 | #include <unordered_set> |
26 | |
27 | #include <assert.h> |
28 | |
29 | #include "threads.h" |
30 | #include "utilities.h" |
31 | |
32 | namespace wasm { |
33 | |
34 | struct IString { |
35 | private: |
36 | static std::string_view interned(std::string_view s, bool reuse = true); |
37 | |
38 | public: |
39 | const std::string_view str; |
40 | |
41 | IString() = default; |
42 | |
43 | // TODO: This is a wildly unsafe default inherited from the previous |
44 | // implementation. Change it? |
45 | IString(std::string_view str, bool reuse = true) |
46 | : str(interned(str, reuse)) {} |
47 | |
48 | // But other C strings generally do need to be copied. |
49 | IString(const char* str) : str(interned(str, false)) {} |
50 | IString(const std::string& str) : str(interned(str, false)) {} |
51 | |
52 | IString(const IString& other) = default; |
53 | |
54 | IString& operator=(const IString& other) { |
55 | return *(new (this) IString(other)); |
56 | } |
57 | |
58 | bool operator==(const IString& other) const { |
59 | // Fast! No need to compare contents due to interning |
60 | return str.data() == other.str.data(); |
61 | } |
62 | bool operator!=(const IString& other) const { return !(*this == other); } |
63 | bool operator<(const IString& other) const { return str < other.str; } |
64 | bool operator<=(const IString& other) const { return str <= other.str; } |
65 | bool operator>(const IString& other) const { return str > other.str; } |
66 | bool operator>=(const IString& other) const { return str >= other.str; } |
67 | |
68 | char operator[](int x) const { return str[x]; } |
69 | |
70 | explicit operator bool() const { return str.data() != nullptr; } |
71 | |
72 | // TODO: deprecate? |
73 | bool is() const { return bool(*this); } |
74 | bool isNull() const { return !bool(*this); } |
75 | |
76 | std::string toString() const { return {str.data(), str.size()}; } |
77 | |
78 | bool equals(std::string_view other) const { return str == other; } |
79 | |
80 | bool startsWith(std::string_view prefix) const { |
81 | // TODO: Use C++20 `starts_with`. |
82 | return str.substr(0, prefix.size()) == prefix; |
83 | } |
84 | bool startsWith(IString str) const { return startsWith(str.str); } |
85 | |
86 | // Disambiguate for string literals. |
87 | template<int N> bool startsWith(const char (&str)[N]) { |
88 | return startsWith(std::string_view(str)); |
89 | } |
90 | |
91 | size_t size() const { return str.size(); } |
92 | }; |
93 | |
94 | } // namespace wasm |
95 | |
96 | namespace std { |
97 | |
98 | template<> struct hash<wasm::IString> { |
99 | size_t operator()(const wasm::IString& str) const { |
100 | return std::hash<size_t>{}(uintptr_t(str.str.data())); |
101 | } |
102 | }; |
103 | |
104 | inline std::ostream& operator<<(std::ostream& os, const wasm::IString& str) { |
105 | return os << str.str; |
106 | } |
107 | |
108 | } // namespace std |
109 | |
110 | #endif // wasm_support_istring_h |
111 | |