GCC Code Coverage Report


Directory: ./
File: src/utilities/names.h
Date: 2023-04-27 00:55:30
Exec Total Coverage
Lines: 28 28 100.0%
Functions: 19 19 100.0%
Branches: 4 6 66.7%

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