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

407 lines, 216 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 <sys/stat.h>
7#include <unistd.h>
8
9#include "mycpp/gc_alloc.h" // gHeap
10#include "mycpp/gc_dict.h" // for dict_erase()
11#include "mycpp/gc_mops.h"
12#include "mycpp/gc_tuple.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#define BUF_SIZE 131072
157
158// Wrap a FILE* for read and write
159class CFile : public File {
160 public:
161 explicit CFile(int fd) : File(), fd_(fd) {
162 }
163 // Writer
164 void write(BigStr* s) override;
165 void flush() override;
166
167 // Reader
168 BigStr* readline() override;
169
170 // Both
171 bool isatty() override;
172 void close() override;
173
174 static constexpr ObjHeader obj_header() {
175 return ObjHeader::ClassFixed(field_mask(), sizeof(CFile));
176 }
177
178 static constexpr uint32_t field_mask() {
179 // not mutating field_mask because FILE* isn't a GC object
180 return File::field_mask();
181 }
182
183 private:
184 void read_into_buffer();
185
186 int fd_;
187 char buffer_[BUF_SIZE];
188 size_t pos_ = 0;
189 size_t end_ = 0;
190 bool eof_ = false;
191
192 DISALLOW_COPY_AND_ASSIGN(CFile)
193};
194
195// Abstract File we can only read from.
196// TODO: can we get rid of DCHECK() and reinterpret_cast?
197class LineReader : public File {
198 public:
199 LineReader() : File() {
200 }
201 void write(BigStr* s) override {
202 CHECK(false); // should not happen
203 }
204 void flush() override {
205 CHECK(false); // should not happen
206 }
207
208 static constexpr ObjHeader obj_header() {
209 return ObjHeader::ClassFixed(field_mask(), sizeof(LineReader));
210 }
211
212 static constexpr uint32_t field_mask() {
213 return kZeroMask;
214 }
215};
216
217class BufLineReader : public LineReader {
218 public:
219 explicit BufLineReader(BigStr* s) : LineReader(), s_(s), pos_(0) {
220 }
221 virtual BigStr* readline();
222 virtual bool isatty() {
223 return false;
224 }
225 virtual void close() {
226 }
227
228 BigStr* s_;
229 int pos_;
230
231 static constexpr ObjHeader obj_header() {
232 return ObjHeader::ClassFixed(field_mask(), sizeof(LineReader));
233 }
234
235 static constexpr uint32_t field_mask() {
236 return LineReader::field_mask() | maskbit(offsetof(BufLineReader, s_));
237 }
238
239 DISALLOW_COPY_AND_ASSIGN(BufLineReader)
240};
241
242extern LineReader* gStdin;
243
244inline LineReader* Stdin() {
245 if (gStdin == nullptr) {
246 gStdin = reinterpret_cast<LineReader*>(Alloc<CFile>(STDIN_FILENO));
247 }
248 return gStdin;
249}
250
251LineReader* open(BigStr* path);
252
253// Abstract File we can only write to.
254// TODO: can we get rid of DCHECK() and reinterpret_cast?
255class Writer : public File {
256 public:
257 Writer() : File() {
258 }
259 BigStr* readline() override {
260 CHECK(false); // should not happen
261 }
262
263 static constexpr ObjHeader obj_header() {
264 return ObjHeader::ClassFixed(field_mask(), sizeof(Writer));
265 }
266
267 static constexpr uint32_t field_mask() {
268 return kZeroMask;
269 }
270};
271
272class MutableStr;
273
274class BufWriter : public Writer {
275 public:
276 BufWriter() : Writer(), str_(nullptr), len_(0) {
277 }
278 void write(BigStr* s) override;
279 void write_spaces(int n);
280 void clear() { // Reuse this instance
281 str_ = nullptr;
282 len_ = 0;
283 is_valid_ = true;
284 }
285 void close() override {
286 }
287 void flush() override {
288 }
289 bool isatty() override {
290 return false;
291 }
292 BigStr* getvalue(); // part of cStringIO API
293
294 //
295 // Low Level API for C++ usage only
296 //
297
298 // Convenient API that avoids BigStr*
299 void WriteConst(const char* c_string);
300
301 // Potentially resizes the buffer.
302 void EnsureMoreSpace(int n);
303 // After EnsureMoreSpace(42), you can write 42 more bytes safely.
304 //
305 // Note that if you call EnsureMoreSpace(42), write 5 byte, and then
306 // EnsureMoreSpace(42) again, the amount of additional space reserved is 47.
307
308 // (Similar to vector::reserve(n), but it takes an integer to ADD to the
309 // capacity.)
310
311 uint8_t* LengthPointer(); // start + length
312 uint8_t* CapacityPointer(); // start + capacity
313 void SetLengthFrom(uint8_t* length_ptr);
314
315 int Length() {
316 return len_;
317 }
318
319 // Rewind to earlier position, future writes start there
320 void Truncate(int length);
321
322 static constexpr ObjHeader obj_header() {
323 return ObjHeader::ClassFixed(field_mask(), sizeof(BufWriter));
324 }
325
326 static constexpr unsigned field_mask() {
327 // maskvit_v() because BufWriter has virtual methods
328 return Writer::field_mask() | maskbit(offsetof(BufWriter, str_));
329 }
330
331 private:
332 void WriteRaw(char* s, int n);
333
334 MutableStr* str_; // getvalue() turns this directly into Str*, no copying
335 int len_; // how many bytes have been written so far
336 bool is_valid_ = true; // It becomes invalid after getvalue() is called
337};
338
339extern Writer* gStdout;
340
341inline Writer* Stdout() {
342 if (gStdout == nullptr) {
343 gStdout = reinterpret_cast<Writer*>(Alloc<CFile>(STDOUT_FILENO));
344 gHeap.RootGlobalVar(gStdout);
345 }
346 return gStdout;
347}
348
349extern Writer* gStderr;
350
351inline Writer* Stderr() {
352 if (gStderr == nullptr) {
353 gStderr = reinterpret_cast<Writer*>(Alloc<CFile>(STDERR_FILENO));
354 gHeap.RootGlobalVar(gStderr);
355 }
356 return gStderr;
357}
358
359class UniqueObjects {
360 // Can't be expressed in typed Python because we don't have uint64_t for
361 // addresses
362
363 public:
364 UniqueObjects() {
365 }
366 void Add(void* obj) {
367 }
368 int Get(void* obj) {
369 return -1;
370 }
371
372 static constexpr ObjHeader obj_header() {
373 return ObjHeader::ClassFixed(field_mask(), sizeof(UniqueObjects));
374 }
375
376 // SPECIAL CASE? We should never have a unique reference to an object? So
377 // don't bother tracing
378 static constexpr uint32_t field_mask() {
379 return kZeroMask;
380 }
381
382 private:
383 // address -> small integer ID
384 Dict<void*, int> addresses_;
385};
386
387
388class StatResult {
389public:
390 bool isreg();
391
392 static constexpr ObjHeader obj_header() {
393 return ObjHeader::ClassFixed(field_mask(), sizeof(StatResult));
394 }
395
396 static constexpr uint32_t field_mask() {
397 return kZeroMask;
398 }
399
400 struct stat stat_result_;
401};
402
403StatResult* stat(BigStr* filename);
404
405} // namespace mylib
406
407#endif // MYCPP_GC_MYLIB_H