/home/uke/oil/mycpp/mylib2.h
Line | Count | Source (jump to first uncovered line) |
1 | | // mylib2.h |
2 | | // |
3 | | // Rewrites of mylib.py in C++. |
4 | | // TODO: Remove mylib.{h,cc}, and make this the main copy. |
5 | | |
6 | | #ifndef MYLIB2_H |
7 | | #define MYLIB2_H |
8 | | |
9 | | #include "gc_heap.h" |
10 | | #include "my_runtime.h" // Tuple2 |
11 | | |
12 | | using gc_heap::Alloc; |
13 | | using gc_heap::kZeroMask; |
14 | | using gc_heap::maskbit; |
15 | | using gc_heap::maskbit_v; |
16 | | using gc_heap::StackRoots; |
17 | | |
18 | | namespace mylib { |
19 | | |
20 | | Tuple2<Str*, Str*> split_once(Str* s, Str* delim); |
21 | | |
22 | | template <typename V> |
23 | | void dict_remove(Dict<Str*, V>* haystack, Str* needle) { |
24 | | int pos = haystack->position_of_key(needle); |
25 | | if (pos == -1) { |
26 | | return; |
27 | | } |
28 | | haystack->entry_->items_[pos] = gc_heap::kDeletedEntry; |
29 | | // Zero out for GC. These could be nullptr or 0 |
30 | | haystack->keys_->items_[pos] = 0; |
31 | | haystack->values_->items_[pos] = 0; |
32 | | haystack->len_--; |
33 | | } |
34 | | |
35 | | // These 3 functions use a static buffer first because we don't know what n is |
36 | | // until we call snprintf(). |
37 | | |
38 | 0 | inline Str* hex_lower(int i) { |
39 | 0 | char buf[kIntBufSize]; |
40 | 0 | int length = snprintf(buf, kIntBufSize, "%x", i); |
41 | 0 | return CopyStr(buf, length); |
42 | 0 | } |
43 | | |
44 | 0 | inline Str* hex_upper(int i) { |
45 | 0 | char buf[kIntBufSize]; |
46 | 0 | int length = snprintf(buf, kIntBufSize, "%X", i); |
47 | 0 | return CopyStr(buf, length); |
48 | 0 | } |
49 | | |
50 | 0 | inline Str* octal(int i) { |
51 | 0 | char buf[kIntBufSize]; |
52 | 0 | int length = snprintf(buf, kIntBufSize, "%o", i); |
53 | 0 | return CopyStr(buf, length); |
54 | 0 | } |
55 | | |
56 | | class LineReader : gc_heap::Obj { |
57 | | public: |
58 | | // Abstract type with no fields: unknown size |
59 | | LineReader(uint16_t field_mask, int obj_len) |
60 | 0 | : gc_heap::Obj(Tag::FixedSize, field_mask, obj_len) { |
61 | 0 | } |
62 | | virtual Str* readline() = 0; |
63 | 0 | virtual bool isatty() { |
64 | 0 | return false; |
65 | 0 | } |
66 | 0 | virtual int fileno() { |
67 | 0 | NotImplemented(); // Uncalled |
68 | 0 | } |
69 | | }; |
70 | | |
71 | | class BufLineReader : public LineReader { |
72 | | public: |
73 | | explicit BufLineReader(Str* s); |
74 | | virtual Str* readline(); |
75 | | |
76 | | Str* s_; |
77 | | int pos_; |
78 | | |
79 | | DISALLOW_COPY_AND_ASSIGN(BufLineReader) |
80 | | }; |
81 | | |
82 | 0 | constexpr uint16_t maskof_BufLineReader() { |
83 | 0 | return maskbit_v(offsetof(BufLineReader, s_)); |
84 | 0 | } |
85 | | |
86 | | inline BufLineReader::BufLineReader(Str* s) |
87 | | : LineReader(maskof_BufLineReader(), sizeof(BufLineReader)), |
88 | | s_(s), |
89 | | pos_(0) { |
90 | | } |
91 | | |
92 | | // Wrap a FILE* |
93 | | class CFileLineReader : public LineReader { |
94 | | public: |
95 | | explicit CFileLineReader(FILE* f); |
96 | | virtual Str* readline(); |
97 | 0 | virtual int fileno() { |
98 | 0 | return ::fileno(f_); |
99 | 0 | } |
100 | | |
101 | | private: |
102 | | FILE* f_; |
103 | | |
104 | | DISALLOW_COPY_AND_ASSIGN(CFileLineReader) |
105 | | }; |
106 | | |
107 | | inline CFileLineReader::CFileLineReader(FILE* f) |
108 | | : LineReader(kZeroMask, sizeof(CFileLineReader)), f_(f) { |
109 | | } |
110 | | |
111 | | extern LineReader* gStdin; |
112 | | |
113 | 0 | inline LineReader* Stdin() { |
114 | 0 | if (gStdin == nullptr) { |
115 | 0 | gStdin = new CFileLineReader(stdin); |
116 | 0 | } |
117 | 0 | return gStdin; |
118 | 0 | } |
119 | | |
120 | 0 | inline LineReader* open(Str* path) { |
121 | 0 | StackRoots _roots({&path}); |
122 | 0 |
|
123 | 0 | FILE* f = fopen(path->data_, "r"); |
124 | 0 |
|
125 | 0 | // TODO: Better error checking. IOError? |
126 | 0 | if (!f) { |
127 | 0 | throw new AssertionError("file not found"); |
128 | 0 | } |
129 | 0 | return Alloc<CFileLineReader>(f); |
130 | 0 | } |
131 | | |
132 | | class Writer : public gc_heap::Obj { |
133 | | public: |
134 | | Writer(uint8_t heap_tag, uint16_t field_mask, int obj_len) |
135 | 58 | : gc_heap::Obj(heap_tag, field_mask, obj_len) { |
136 | 58 | } |
137 | | virtual void write(Str* s) = 0; |
138 | | virtual void flush() = 0; |
139 | | virtual bool isatty() = 0; |
140 | | }; |
141 | | |
142 | | class BufWriter : public Writer { |
143 | | public: |
144 | | BufWriter() |
145 | | : Writer(Tag::FixedSize, gc_heap::kZeroMask, sizeof(BufWriter)), |
146 | | data_(nullptr), |
147 | 55 | len_(0) { |
148 | 55 | } |
149 | | virtual void write(Str* s) override; |
150 | 0 | virtual void flush() override { |
151 | 0 | } |
152 | 0 | virtual bool isatty() override { |
153 | 0 | return false; |
154 | 0 | } |
155 | | // For cStringIO API |
156 | 317 | Str* getvalue() { |
157 | 317 | if (data_) { |
158 | 317 | Str* ret = gc_heap::CopyStr(data_, len_); |
159 | 317 | reset(); // Invalidate this instance |
160 | 317 | return ret; |
161 | 317 | } else { |
162 | | // log('') translates to this |
163 | | // Strings are immutable so we can do this. |
164 | 0 | return gc_heap::kEmptyString; |
165 | 0 | } |
166 | 317 | } |
167 | | |
168 | | // Methods to compile printf format strings to |
169 | | |
170 | | // To reuse the global gBuf instance |
171 | | // problem: '%r' % obj will recursively call asdl/format.py, which has its |
172 | | // own % operations |
173 | 610 | void reset() { |
174 | 610 | data_ = nullptr; // make sure we get a new buffer next time |
175 | 610 | len_ = 0; |
176 | 610 | } |
177 | | |
178 | | // Note: we do NOT need to instantiate a Str() to append |
179 | | void write_const(const char* s, int len); |
180 | | |
181 | | // strategy: snprintf() based on sizeof(int) |
182 | | void format_d(int i); |
183 | | void format_s(Str* s); |
184 | | void format_r(Str* s); // formats with quotes |
185 | | |
186 | | // looks at arbitrary type tags? Is this possible |
187 | | // Passes "this" to functions generated by ASDL? |
188 | | void format_r(void* s); |
189 | | |
190 | | private: |
191 | | // Just like a string, except it's mutable |
192 | | char* data_; |
193 | | int len_; |
194 | | }; |
195 | | |
196 | | // Wrap a FILE* |
197 | | class CFileWriter : public Writer { |
198 | | public: |
199 | | explicit CFileWriter(FILE* f) |
200 | 3 | : Writer(Tag::FixedSize, gc_heap::kZeroMask, sizeof(BufWriter)), f_(f) { |
201 | 3 | } |
202 | | virtual void write(Str* s) override; |
203 | | virtual void flush() override; |
204 | | virtual bool isatty() override; |
205 | | |
206 | | private: |
207 | | FILE* f_; |
208 | | |
209 | | DISALLOW_COPY_AND_ASSIGN(CFileWriter) |
210 | | }; |
211 | | |
212 | | extern Writer* gStdout; |
213 | | |
214 | 10 | inline Writer* Stdout() { |
215 | 10 | if (gStdout == nullptr) { |
216 | 3 | gStdout = new CFileWriter(stdout); |
217 | 3 | } |
218 | 10 | return gStdout; |
219 | 10 | } |
220 | | |
221 | | extern Writer* gStderr; |
222 | | |
223 | 0 | inline Writer* Stderr() { |
224 | 0 | if (gStderr == nullptr) { |
225 | 0 | gStderr = new CFileWriter(stderr); |
226 | 0 | } |
227 | 0 | return gStderr; |
228 | 0 | } |
229 | | |
230 | | } // namespace mylib |
231 | | |
232 | | // Global formatter |
233 | | extern mylib::BufWriter gBuf; |
234 | | |
235 | | #endif // MYLIB2_H |