OILS / mycpp / gc_mylib.h View on Github | oils.pub

400 lines, 211 significant
1// gc_mylib.h - corresponds to mycpp/mylib.py
2
3#ifndef MYCPP_GC_MYLIB_H
4#define MYCPP_GC_MYLIB_H
5
6#include "mycpp/gc_alloc.h" // gHeap
7#include "mycpp/gc_dict.h" // for dict_erase()
8#include "mycpp/gc_mops.h"
9#include "mycpp/gc_tuple.h"
10
11#include <sys/stat.h>
12#include <unistd.h>
13
14template <class K, class V>
15class Dict;
16
17namespace mylib {
18
19bool isinf_(double f);
20bool isnan_(double f);
21
22void InitCppOnly();
23
24// Wrappers around our C++ APIs
25
26inline void MaybeCollect() {
27 gHeap.MaybeCollect();
28}
29
30inline void PrintGcStats() {
31 gHeap.PrintShortStats(); // print to stderr
32}
33
34void print_stderr(BigStr* s);
35
36inline int ByteAt(BigStr* s, int i) {
37 DCHECK(0 <= i);
38 DCHECK(i <= len(s));
39
40 return static_cast<unsigned char>(s->data_[i]);
41}
42
43inline int ByteEquals(int byte, BigStr* ch) {
44 DCHECK(0 <= byte);
45 DCHECK(byte < 256);
46
47 DCHECK(len(ch) == 1);
48
49 return byte == static_cast<unsigned char>(ch->data_[0]);
50}
51
52inline int ByteInSet(int byte, BigStr* byte_set) {
53 DCHECK(0 <= byte);
54 DCHECK(byte < 256);
55
56 int n = len(byte_set);
57 for (int i = 0; i < n; ++i) {
58 int b = static_cast<unsigned char>(byte_set->data_[i]);
59 if (byte == b) {
60 return true;
61 }
62 }
63 return false;
64}
65
66BigStr* JoinBytes(List<int>* byte_list);
67
68void BigIntSort(List<mops::BigInt>* keys);
69
70// const int kStdout = 1;
71// const int kStderr = 2;
72
73// void writeln(BigStr* s, int fd = kStdout);
74
75Tuple2<BigStr*, BigStr*> split_once(BigStr* s, BigStr* delim);
76
77template <typename K, typename V>
78void dict_erase(Dict<K, V>* haystack, K needle) {
79 DCHECK(haystack->obj_header().heap_tag != HeapTag::Global);
80
81 int pos = haystack->hash_and_probe(needle);
82 if (pos == kTooSmall) {
83 return;
84 }
85 DCHECK(pos >= 0);
86 int kv_index = haystack->index_->items_[pos];
87 if (kv_index < 0) {
88 return;
89 }
90
91 int last_kv_index = haystack->len_ - 1;
92 DCHECK(kv_index <= last_kv_index);
93
94 // Swap the target entry with the most recently inserted one before removing
95 // it. This has two benefits.
96 // (1) It keeps the entry arrays compact. All valid entries occupy a
97 // contiguous region in memory.
98 // (2) It prevents holes in the entry arrays. This makes iterating over
99 // entries (e.g. in keys() or DictIter()) trivial and doesn't require
100 // any extra validity state (like a bitset of unusable slots). This is
101 // important because keys and values wont't always be pointers, so we
102 // can't rely on NULL checks for validity. We also can't wrap the slab
103 // entry types in some other type without modifying the garbage
104 // collector to trace through unmanaged types (or paying the extra
105 // allocations for the outer type).
106 if (kv_index != last_kv_index) {
107 K last_key = haystack->keys_->items_[last_kv_index];
108 V last_val = haystack->values_->items_[last_kv_index];
109 int last_pos = haystack->hash_and_probe(last_key);
110 DCHECK(last_pos != kNotFound);
111 haystack->keys_->items_[kv_index] = last_key;
112 haystack->values_->items_[kv_index] = last_val;
113 haystack->index_->items_[last_pos] = kv_index;
114 }
115
116 // Zero out for GC. These could be nullptr or 0
117 haystack->keys_->items_[last_kv_index] = 0;
118 haystack->values_->items_[last_kv_index] = 0;
119 haystack->index_->items_[pos] = kDeletedEntry;
120 haystack->len_--;
121 DCHECK(haystack->len_ < haystack->capacity_);
122}
123
124inline BigStr* hex_lower(int i) {
125 // Note: Could also use OverAllocatedStr, but most strings are small?
126 char buf[kIntBufSize];
127 int len = snprintf(buf, kIntBufSize, "%x", i);
128 return ::StrFromC(buf, len);
129}
130
131// Abstract type: Union of LineReader and Writer
132class File {
133 public:
134 File() {
135 }
136 // Writer
137 virtual void write(BigStr* s) = 0;
138 virtual void flush() = 0;
139
140 // Reader
141 virtual BigStr* readline() = 0;
142
143 // Both
144 virtual bool isatty() = 0;
145 virtual void close() = 0;
146
147 static constexpr ObjHeader obj_header() {
148 return ObjHeader::ClassFixed(field_mask(), sizeof(File));
149 }
150
151 static constexpr uint32_t field_mask() {
152 return kZeroMask;
153 }
154};
155
156// Wrap a FILE* for read and write
157class CFile : public File {
158 public:
159 explicit CFile(int fd) : File(), fd_(fd) {
160 }
161 // Writer
162 void write(BigStr* s) override;
163 void flush() override;
164
165 // Reader
166 BigStr* readline() override;
167
168 // Both
169 bool isatty() override;
170 void close() override;
171
172 static constexpr ObjHeader obj_header() {
173 return ObjHeader::ClassFixed(field_mask(), sizeof(CFile));
174 }
175
176 static constexpr uint32_t field_mask() {
177 // not mutating field_mask because FILE* isn't a GC object
178 return File::field_mask();
179 }
180
181 private:
182 int fd_;
183 char line_[131072];
184
185 DISALLOW_COPY_AND_ASSIGN(CFile)
186};
187
188// Abstract File we can only read from.
189// TODO: can we get rid of DCHECK() and reinterpret_cast?
190class LineReader : public File {
191 public:
192 LineReader() : File() {
193 }
194 void write(BigStr* s) override {
195 CHECK(false); // should not happen
196 }
197 void flush() override {
198 CHECK(false); // should not happen
199 }
200
201 static constexpr ObjHeader obj_header() {
202 return ObjHeader::ClassFixed(field_mask(), sizeof(LineReader));
203 }
204
205 static constexpr uint32_t field_mask() {
206 return kZeroMask;
207 }
208};
209
210class BufLineReader : public LineReader {
211 public:
212 explicit BufLineReader(BigStr* s) : LineReader(), s_(s), pos_(0) {
213 }
214 virtual BigStr* readline();
215 virtual bool isatty() {
216 return false;
217 }
218 virtual void close() {
219 }
220
221 BigStr* s_;
222 int pos_;
223
224 static constexpr ObjHeader obj_header() {
225 return ObjHeader::ClassFixed(field_mask(), sizeof(LineReader));
226 }
227
228 static constexpr uint32_t field_mask() {
229 return LineReader::field_mask() | maskbit(offsetof(BufLineReader, s_));
230 }
231
232 DISALLOW_COPY_AND_ASSIGN(BufLineReader)
233};
234
235extern LineReader* gStdin;
236
237inline LineReader* Stdin() {
238 if (gStdin == nullptr) {
239 gStdin = reinterpret_cast<LineReader*>(Alloc<CFile>(STDIN_FILENO));
240 }
241 return gStdin;
242}
243
244LineReader* open(BigStr* path);
245
246// Abstract File we can only write to.
247// TODO: can we get rid of DCHECK() and reinterpret_cast?
248class Writer : public File {
249 public:
250 Writer() : File() {
251 }
252 BigStr* readline() override {
253 CHECK(false); // should not happen
254 }
255
256 static constexpr ObjHeader obj_header() {
257 return ObjHeader::ClassFixed(field_mask(), sizeof(Writer));
258 }
259
260 static constexpr uint32_t field_mask() {
261 return kZeroMask;
262 }
263};
264
265class MutableStr;
266
267class BufWriter : public Writer {
268 public:
269 BufWriter() : Writer(), str_(nullptr), len_(0) {
270 }
271 void write(BigStr* s) override;
272 void write_spaces(int n);
273 void clear() { // Reuse this instance
274 str_ = nullptr;
275 len_ = 0;
276 is_valid_ = true;
277 }
278 void close() override {
279 }
280 void flush() override {
281 }
282 bool isatty() override {
283 return false;
284 }
285 BigStr* getvalue(); // part of cStringIO API
286
287 //
288 // Low Level API for C++ usage only
289 //
290
291 // Convenient API that avoids BigStr*
292 void WriteConst(const char* c_string);
293
294 // Potentially resizes the buffer.
295 void EnsureMoreSpace(int n);
296 // After EnsureMoreSpace(42), you can write 42 more bytes safely.
297 //
298 // Note that if you call EnsureMoreSpace(42), write 5 byte, and then
299 // EnsureMoreSpace(42) again, the amount of additional space reserved is 47.
300
301 // (Similar to vector::reserve(n), but it takes an integer to ADD to the
302 // capacity.)
303
304 uint8_t* LengthPointer(); // start + length
305 uint8_t* CapacityPointer(); // start + capacity
306 void SetLengthFrom(uint8_t* length_ptr);
307
308 int Length() {
309 return len_;
310 }
311
312 // Rewind to earlier position, future writes start there
313 void Truncate(int length);
314
315 static constexpr ObjHeader obj_header() {
316 return ObjHeader::ClassFixed(field_mask(), sizeof(BufWriter));
317 }
318
319 static constexpr unsigned field_mask() {
320 // maskvit_v() because BufWriter has virtual methods
321 return Writer::field_mask() | maskbit(offsetof(BufWriter, str_));
322 }
323
324 private:
325 void WriteRaw(char* s, int n);
326
327 MutableStr* str_; // getvalue() turns this directly into Str*, no copying
328 int len_; // how many bytes have been written so far
329 bool is_valid_ = true; // It becomes invalid after getvalue() is called
330};
331
332extern Writer* gStdout;
333
334inline Writer* Stdout() {
335 if (gStdout == nullptr) {
336 gStdout = reinterpret_cast<Writer*>(Alloc<CFile>(STDOUT_FILENO));
337 gHeap.RootGlobalVar(gStdout);
338 }
339 return gStdout;
340}
341
342extern Writer* gStderr;
343
344inline Writer* Stderr() {
345 if (gStderr == nullptr) {
346 gStderr = reinterpret_cast<Writer*>(Alloc<CFile>(STDERR_FILENO));
347 gHeap.RootGlobalVar(gStderr);
348 }
349 return gStderr;
350}
351
352class UniqueObjects {
353 // Can't be expressed in typed Python because we don't have uint64_t for
354 // addresses
355
356 public:
357 UniqueObjects() {
358 }
359 void Add(void* obj) {
360 }
361 int Get(void* obj) {
362 return -1;
363 }
364
365 static constexpr ObjHeader obj_header() {
366 return ObjHeader::ClassFixed(field_mask(), sizeof(UniqueObjects));
367 }
368
369 // SPECIAL CASE? We should never have a unique reference to an object? So
370 // don't bother tracing
371 static constexpr uint32_t field_mask() {
372 return kZeroMask;
373 }
374
375 private:
376 // address -> small integer ID
377 Dict<void*, int> addresses_;
378};
379
380
381class StatResult {
382public:
383 bool isreg();
384
385 static constexpr ObjHeader obj_header() {
386 return ObjHeader::ClassFixed(field_mask(), sizeof(StatResult));
387 }
388
389 static constexpr uint32_t field_mask() {
390 return kZeroMask;
391 }
392
393 struct stat stat_result_;
394};
395
396StatResult* stat(BigStr* filename);
397
398} // namespace mylib
399
400#endif // MYCPP_GC_MYLIB_H