Line | Branch | Exec | Source |
---|---|---|---|
1 | #ifndef LYTHON_SRC_AST_HEADER | ||
2 | #define LYTHON_SRC_AST_HEADER | ||
3 | |||
4 | #include <iostream> | ||
5 | #include <memory> | ||
6 | #include <mutex> | ||
7 | #include <string> | ||
8 | #include <string_view> | ||
9 | #include <unordered_map> | ||
10 | |||
11 | #include "dtypes.h" | ||
12 | #include "logging/exceptions.h" | ||
13 | #include "logging/logging.h" | ||
14 | #include "utilities/stopwatch.h" | ||
15 | |||
16 | namespace lython { | ||
17 | // /!\ string a allocated twice | ||
18 | |||
19 | NEW_EXCEPTION(NameTaken); | ||
20 | |||
21 | #define ASSERT(pred, msg) \ | ||
22 | { \ | ||
23 | if (!(pred)) { \ | ||
24 | throw NameTaken(msg); \ | ||
25 | } \ | ||
26 | } | ||
27 | |||
28 | class StringRef; | ||
29 | |||
30 | // Should be careful to only use this for name-like strings | ||
31 | // Since we keep the strings forever | ||
32 | // At the moment this is global but we should maybe tie this to a Module | ||
33 | // so the strings can expire | ||
34 | class StringDatabase { | ||
35 | public: | ||
36 | bool print_stats = false; | ||
37 | |||
38 | static StringDatabase& instance(); | ||
39 | |||
40 | StringView operator[](std::size_t i) const; | ||
41 | |||
42 | StringRef string(String const& name); | ||
43 | |||
44 | StringDatabase(); | ||
45 | |||
46 | ~StringDatabase() { | ||
47 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 1 times.
|
15 | if (print_stats) { |
48 | 14 | report(std::cout); | |
49 | } | ||
50 | 15 | } | |
51 | |||
52 | std::ostream& report(std::ostream& out) const; | ||
53 | |||
54 | struct StringEntry { | ||
55 | String data; | ||
56 | int count = 1; | ||
57 | int copy = 0; | ||
58 | int in_use = 0; | ||
59 | }; | ||
60 | |||
61 | private: | ||
62 | StringRef lookup_or_insert_string(String const& name); | ||
63 | StringRef insert_string(String const& name); | ||
64 | |||
65 | std::size_t inc(std::size_t i); | ||
66 | |||
67 | std::size_t dec(std::size_t n); | ||
68 | |||
69 | std::size_t count() const { return size; } | ||
70 | |||
71 | Array<StringEntry>& newblock(); | ||
72 | Array<StringEntry>& current_block(); | ||
73 | |||
74 | StringEntry& get(std::size_t i) { | ||
75 | 103502 | size_t block = i / block_size; | |
76 | 103502 | size_t entry = i % block_size; | |
77 | 103502 | return (*reverse[block])[entry]; | |
78 | } | ||
79 | |||
80 | StringEntry const& get(std::size_t i) const { | ||
81 | 64232 | size_t block = i / block_size; | |
82 | 64232 | size_t entry = i % block_size; | |
83 | 64232 | return (*reverse[block])[entry]; | |
84 | } | ||
85 | |||
86 | // Array<StringEntry> strings; // String storage | ||
87 | #if !BUILD_WEBASSEMBLY | ||
88 | mutable std::recursive_mutex mu; | ||
89 | #endif | ||
90 | mutable double wait_time; | ||
91 | |||
92 | friend class StringRef; | ||
93 | friend bool _metadata_init_names(); | ||
94 | |||
95 | // Used to check if the string is already stored | ||
96 | Dict<StringView, std::size_t> defined; | ||
97 | |||
98 | // Allocates strings in block to avoid reallocation | ||
99 | int block_size = 1024; | ||
100 | std::size_t size = 0; | ||
101 | |||
102 | List<Array<StringEntry>> memory_blocks; | ||
103 | Array<Array<StringEntry>*> reverse; | ||
104 | |||
105 | friend bool _metadata_init_names(); | ||
106 | }; | ||
107 | |||
108 | #define STRING_VIEW(X) X | ||
109 | |||
110 | // Very Cheap string reference | ||
111 | class StringRef { | ||
112 | public: | ||
113 | StringRef(std::size_t r = 0): ref(StringDatabase::instance().inc(r)) { | ||
114 | assert(ref < StringDatabase::instance().count(), "StringRef is valid"); | ||
115 | 18378 | STRING_VIEW(debug_view = StringDatabase::instance()[ref]); | |
116 | 18378 | } | |
117 | |||
118 | StringRef(String const& name): ref(StringDatabase::instance().string(name).ref) { | ||
119 | assert(ref < StringDatabase::instance().count(), "StringRef is valid"); | ||
120 | 3207 | STRING_VIEW(debug_view = StringDatabase::instance()[ref]); | |
121 | 3207 | } | |
122 | |||
123 | StringRef(StringRef const& name): ref(StringDatabase::instance().inc(name.ref)) { | ||
124 | assert(ref < StringDatabase::instance().count(), "StringRef is valid"); | ||
125 | 2196 | STRING_VIEW(debug_view = StringDatabase::instance()[ref]); | |
126 | 2196 | } | |
127 | |||
128 | StringRef(StringRef const&& name): ref(StringDatabase::instance().inc(name.ref)) { | ||
129 | assert(ref < StringDatabase::instance().count(), "StringRef is valid"); | ||
130 | 2024 | STRING_VIEW(debug_view = StringDatabase::instance()[ref]); | |
131 | 2024 | } | |
132 | |||
133 | bool operator==(StringRef const& b) const { return ref == b.ref; } | ||
134 | |||
135 | bool operator!=(StringRef const& b) const { return ref != b.ref; } | ||
136 | |||
137 | StringRef& operator=(String const& name) { | ||
138 | 4497 | StringDatabase::instance().dec(ref); | |
139 |
2/4✓ Branch 1 taken 4497 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4497 times.
✗ Branch 5 not taken.
|
4497 | ref = StringDatabase::instance().string(name).ref; |
140 | 4497 | STRING_VIEW(debug_view = StringDatabase::instance()[ref]); | |
141 | 4497 | return *this; | |
142 | } | ||
143 | |||
144 | StringRef operator=(StringRef const& name) { | ||
145 | 337 | StringDatabase::instance().dec(ref); | |
146 | 337 | ref = StringDatabase::instance().inc(name.ref); | |
147 | 337 | STRING_VIEW(debug_view = StringDatabase::instance()[ref]); | |
148 | 337 | return *this; | |
149 | } | ||
150 | |||
151 | ~StringRef(); | ||
152 | |||
153 | void print(std::ostream& out) const; | ||
154 | |||
155 | operator StringView() const; | ||
156 | |||
157 | operator bool() const { return ref != 0; } | ||
158 | |||
159 | std::size_t __id__() const { return ref; } | ||
160 | |||
161 | private: | ||
162 | std::size_t ref = 0; | ||
163 | StringView debug_view; | ||
164 | }; | ||
165 | |||
166 | std::ostream& operator<<(std::ostream& out, StringRef ref); | ||
167 | |||
168 | String join(String const& sep, Array<StringRef> const& strs); | ||
169 | |||
170 | // hash the reference instead of the string itself | ||
171 | // This could cause issues if we have multiple string databases | ||
172 | struct string_ref_hash { | ||
173 | std::size_t operator()(StringRef const& v) const noexcept { return _h(v.__id__()); } | ||
174 | std::hash<std::size_t> _h; | ||
175 | }; | ||
176 | |||
177 | inline void show_string_stats_on_destroy(bool enabled) { | ||
178 | 1 | StringDatabase::instance().print_stats = enabled; | |
179 | 1 | } | |
180 | |||
181 | } // namespace lython | ||
182 | |||
183 | template <> | ||
184 | struct std::hash<lython::StringRef> { | ||
185 | std::size_t operator()(lython::StringRef const& s) const noexcept { | ||
186 | 8476 | return std::hash<std::size_t>{}(s.__id__()); | |
187 | } | ||
188 | }; | ||
189 | |||
190 | #endif | ||
191 |