Skip to content

Commit 6dd2977

Browse files
committed
Add error handling of invalid inputs
1 parent 9d0c76e commit 6dd2977

File tree

1 file changed

+119
-58
lines changed

1 file changed

+119
-58
lines changed

leetcode/parser.hpp

Lines changed: 119 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -122,27 +122,39 @@ void print_impl(ostream &os, const T &val, bool write_newline) {
122122
#define DBG_8(x, ...) DBG_VAL(x), DBG_7(__VA_ARGS__)
123123
#define DBG_9(x, ...) DBG_VAL(x), DBG_8(__VA_ARGS__)
124124
#define DBG_10(x, ...) DBG_VAL(x), DBG_9(__VA_ARGS__)
125-
#define dbg(...) CONCAT(DBG_, NUM_ARGS(__VA_ARGS__))(__VA_ARGS__), cerr << '\n';
125+
126126
// supports up to 10 arguments debugging at one time
127+
#define dbg(...) CONCAT(DBG_, NUM_ARGS(__VA_ARGS__))(__VA_ARGS__), cerr << '\n';
127128

128129
template <typename T> T parse(istream &is = cin) {
129130
T ans;
130131
char ch;
132+
is >> ws;
131133
if constexpr (same_as<T, char>) {
132-
is >> ch; // skip '"'
133-
is >> ans;
134-
is >> ch; // skip '"'
134+
if (!(is >> ch) || ch != '"')
135+
throw runtime_error("Expected '\"' before char");
136+
if (!(is >> ans))
137+
throw runtime_error("Failed to parse char");
138+
if (!(is >> ch) || ch != '"')
139+
throw runtime_error("Expected '\"' after char");
135140
} else if constexpr (same_as<T, bool>) {
136141
string s;
137-
is >> s;
142+
if (!(is >> s))
143+
throw runtime_error("Failed to parse bool");
144+
if (s != "true" && s != "false")
145+
throw runtime_error("Expected 'true' or 'false' for bool, got: " + s);
138146
ans = (s == "true");
139147
} else if constexpr (same_as<T, string>) {
140-
is >> ch; // skip '"'
141-
getline(is, ans, '"');
148+
if (!(is >> ch) || ch != '"')
149+
throw runtime_error("Expected '\"' before string");
150+
if (!getline(is, ans, '"'))
151+
throw runtime_error("Failed to parse string or missing closing '\"'");
142152
} else if constexpr (is_arithmetic_v<T>) {
143-
is >> ans;
153+
if (!(is >> ans))
154+
throw runtime_error("Failed to parse numeric value");
144155
} else if constexpr (same_as<T, TreeNode *>) {
145-
is >> ch; // skip '['
156+
if (!(is >> ch) || ch != '[')
157+
throw runtime_error("Expected '[' at start of TreeNode array");
146158
is >> ws;
147159
if (is.peek() == ']') {
148160
is >> ch;
@@ -153,66 +165,98 @@ template <typename T> T parse(istream &is = cin) {
153165
queue<TreeNode *> q;
154166
q.push(dummy);
155167

156-
while (is && is.peek() != ']') {
157-
is >> ws;
158-
string token;
159-
char c;
160-
while (is && (c = is.peek()) != ',' && c != ']') {
161-
token += c;
162-
is.get();
163-
}
164-
if (token != "null") {
165-
auto new_node = new TreeNode{stoi(token)};
168+
try {
169+
while (is && is.peek() != ']') {
170+
is >> ws;
171+
string token;
172+
char c;
173+
while (is && (c = is.peek()) != ',' && c != ']') {
174+
token += c;
175+
is.get();
176+
}
177+
if (token.empty())
178+
throw runtime_error("Empty token in TreeNode array");
179+
180+
if (token != "null") {
181+
int val;
182+
try {
183+
val = stoi(token);
184+
} catch (...) {
185+
throw runtime_error("Invalid integer in TreeNode array: " +
186+
token);
187+
}
188+
auto new_node = new TreeNode{val};
189+
if (right)
190+
q.front()->right = new_node;
191+
else
192+
q.front()->left = new_node;
193+
q.push(new_node);
194+
}
166195
if (right)
167-
q.front()->right = new_node;
168-
else
169-
q.front()->left = new_node;
170-
q.push(new_node);
171-
}
172-
if (right)
173-
q.pop();
174-
right = !right;
196+
q.pop();
197+
right = !right;
175198

176-
if (is.peek() == ',')
177-
is >> ch;
199+
if (is.peek() == ',')
200+
is >> ch;
201+
}
202+
if (!is || is.peek() != ']')
203+
throw runtime_error("Expected ']' at end of TreeNode array");
204+
is >> ch; // skip ']'
205+
ans = dummy->right;
206+
dummy->right = nullptr;
207+
delete dummy;
208+
} catch (...) {
209+
dummy->right = nullptr;
210+
delete dummy;
211+
throw;
178212
}
179-
is >> ch; // skip ']'
180-
ans = dummy->right;
181-
dummy->right = nullptr;
182-
delete dummy;
183213
}
184214
} else if constexpr (same_as<T, ListNode *>) {
185215
auto dummy = new ListNode{};
186216
auto cur = dummy;
187-
is >> ch; // skip '['
217+
if (!(is >> ch) || ch != '[')
218+
throw runtime_error("Expected '[' at start of ListNode array");
188219
is >> ws;
189220
if (is.peek() != ']') {
190-
while (true) {
191-
cur->next = new ListNode{parse<int>(is)};
192-
cur = cur->next;
193-
is >> ws;
194-
if (is.peek() == ']')
195-
break;
196-
is >> ch; // skip ','
221+
try {
222+
while (true) {
223+
cur->next = new ListNode{parse<int>(is)};
224+
cur = cur->next;
225+
is >> ws;
226+
if (is.peek() == ']')
227+
break;
228+
if (!(is >> ch) || ch != ',')
229+
throw runtime_error("Expected ',' between ListNode elements");
230+
}
231+
} catch (...) {
232+
dummy->next = nullptr;
233+
delete dummy;
234+
throw;
197235
}
198236
}
199-
is >> ch; // skip ']'
237+
if (!(is >> ch) || ch != ']')
238+
throw runtime_error("Expected ']' at end of ListNode array");
200239
ans = dummy->next;
201240
dummy->next = nullptr;
202241
delete dummy;
203242
} else if constexpr (ranges::range<T>) {
204-
is >> ch; // skip '['
243+
if (!(is >> ch) || ch != '[')
244+
throw runtime_error("Expected '[' at start of array");
205245
is >> ws;
206246
if (is.peek() != ']') {
207247
while (true) {
208248
ans.emplace_back(parse<typename T::value_type>(is));
209249
is >> ws;
250+
if (!is)
251+
throw runtime_error("Stream error while parsing array");
210252
if (is.peek() == ']')
211253
break;
212-
is >> ch; // skip ','
254+
if (!(is >> ch) || ch != ',')
255+
throw runtime_error("Expected ',' between array elements");
213256
}
214257
}
215-
is >> ch; // skip ']'
258+
if (!(is >> ch) || ch != ']')
259+
throw runtime_error("Expected ']' at end of array");
216260
} else
217261
static_assert(false, "parsing for type not supported");
218262
return ans;
@@ -221,18 +265,35 @@ template <typename T> T parse(istream &is = cin) {
221265
template <typename Solution, typename R, typename... Ts>
222266
void run(R (Solution::*fn)(Ts...)) {
223267
tuple<Solution, decay_t<Ts>...> args;
224-
[&]<size_t... Idx>(index_sequence<Idx...>) {
225-
(((get<Idx + 1>(args) = parse<decay_t<Ts>>())), ...);
226-
}(index_sequence_for<Ts...>{});
227-
if constexpr (same_as<R, void>) {
228-
apply(fn, args);
229-
[]<size_t... Idx>(auto &&args, index_sequence<Idx...>) {
230-
((cout << "#" << (Idx + 1) << ": ",
231-
print_impl(cout, get<Idx + 1>(args), true)),
232-
...);
233-
}(args, index_sequence_for<Ts...>{});
234-
} else {
235-
auto res = apply(fn, args);
236-
print_impl(cout, res, true);
268+
get<0>(args) = Solution{};
269+
try {
270+
[&]<size_t... Idx>(index_sequence<Idx...>) {
271+
size_t arg_num = 0;
272+
(
273+
[&]() {
274+
arg_num = Idx + 1;
275+
get<Idx + 1>(args) = parse<decay_t<Ts>>();
276+
}(),
277+
...);
278+
}(index_sequence_for<Ts...>{});
279+
} catch (const exception &e) {
280+
cerr << "Error: " << e.what() << endl;
281+
return;
282+
}
283+
284+
try {
285+
if constexpr (same_as<R, void>) {
286+
apply(fn, args);
287+
[]<size_t... Idx>(auto &&args, index_sequence<Idx...>) {
288+
((cout << "#" << (Idx + 1) << ": ",
289+
print_impl(cout, get<Idx + 1>(args), true)),
290+
...);
291+
}(args, index_sequence_for<Ts...>{});
292+
} else {
293+
auto res = apply(fn, args);
294+
print_impl(cout, res, true);
295+
}
296+
} catch (const exception &e) {
297+
cerr << "Runtime error: " << e.what() << endl;
237298
}
238299
}

0 commit comments

Comments
 (0)