From 52daf0722f7f4ad9d3f29e3cbbbaddde066f49f3 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Mon, 20 May 2019 01:44:06 -0700 Subject: 5211 Update syntax-highlighted renderings after a _long_ time. --- html/subx/003trace.cc.html | 730 +++++++++++++++++++++++---------------------- 1 file changed, 373 insertions(+), 357 deletions(-) (limited to 'html/subx/003trace.cc.html') diff --git a/html/subx/003trace.cc.html b/html/subx/003trace.cc.html index 4fd9723f..03d36a46 100644 --- a/html/subx/003trace.cc.html +++ b/html/subx/003trace.cc.html @@ -190,370 +190,386 @@ if ('onhashchange' in window) { 129 } 130 }; 131 -132 //: Starting a new trace line. -133 :(before "End trace_stream Methods") -134 ostream& stream(string label) { -135 return stream(Max_depth, label); -136 } -137 -138 ostream& stream(int depth, string label) { -139 if (depth > collect_depth) return null_stream; -140 curr_stream = new ostringstream; -141 curr_label = label; -142 curr_depth = depth; -143 (*curr_stream) << std::hex; // printing addresses is the common case -144 return *curr_stream; +132 string unescape_newline(string& s) { +133 std::stringstream ss; +134 for (int i = 0; i < SIZE(s); ++i) { +135 if (s.at(i) == '\n') +136 ss << "\\n"; +137 else +138 ss << s.at(i); +139 } +140 return ss.str(); +141 } +142 +143 void dump_trace_line(ostream& s, trace_line& t) { +144 s << std::setw(4) << t.depth << ' ' << t.label << ": " << unescape_newline(t.contents) << '\n'; 145 } 146 -147 //: End of a trace line; append it to the trace. -148 :(before "End Types") -149 struct end {}; -150 :(code) -151 ostream& operator<<(ostream& os, end /*unused*/) { -152 if (Trace_stream) Trace_stream->newline(); -153 return os; -154 } -155 -156 :(before "End trace_stream Methods") -157 void newline(); -158 :(code) -159 void trace_stream::newline() { -160 if (!curr_stream) return; -161 string curr_contents = curr_stream->str(); -162 if (!curr_contents.empty()) { -163 past_lines.push_back(trace_line(curr_contents, trim(curr_label), curr_depth)); // preserve indent in contents -164 // maybe incrementally dump trace -165 trace_line& t = past_lines.back(); -166 if (should_incrementally_print_trace()) { -167 cerr << std::setw(4) << t.depth << ' ' << t.label << ": " << t.contents << '\n'; -168 } -169 // End trace Commit -170 } -171 -172 // clean up -173 delete curr_stream; -174 curr_stream = NULL; -175 curr_label.clear(); -176 curr_depth = Max_depth; -177 } -178 -179 //:: == Initializing the trace in tests -180 -181 :(before "End Includes") -182 #define START_TRACING_UNTIL_END_OF_SCOPE lease_tracer leased_tracer; -183 :(before "End Test Setup") -184 START_TRACING_UNTIL_END_OF_SCOPE -185 -186 //: Trace_stream is a resource, lease_tracer uses RAII to manage it. -187 :(before "End Types") -188 struct lease_tracer { -189 lease_tracer(); -190 ~lease_tracer(); -191 }; -192 :(code) -193 lease_tracer::lease_tracer() { Trace_stream = new trace_stream; } -194 lease_tracer::~lease_tracer() { -195 delete Trace_stream; -196 Trace_stream = NULL; -197 } -198 -199 //:: == Errors and warnings using traces +147 //: Starting a new trace line. +148 :(before "End trace_stream Methods") +149 ostream& stream(string label) { +150 return stream(Max_depth, label); +151 } +152 +153 ostream& stream(int depth, string label) { +154 if (depth > collect_depth) return null_stream; +155 curr_stream = new ostringstream; +156 curr_label = label; +157 curr_depth = depth; +158 (*curr_stream) << std::hex; // printing addresses is the common case +159 return *curr_stream; +160 } +161 +162 //: End of a trace line; append it to the trace. +163 :(before "End Types") +164 struct end {}; +165 :(code) +166 ostream& operator<<(ostream& os, end /*unused*/) { +167 if (Trace_stream) Trace_stream->newline(); +168 return os; +169 } +170 +171 :(before "End trace_stream Methods") +172 void newline(); +173 :(code) +174 void trace_stream::newline() { +175 if (!curr_stream) return; +176 string curr_contents = curr_stream->str(); +177 if (!curr_contents.empty()) { +178 past_lines.push_back(trace_line(curr_contents, trim(curr_label), curr_depth)); // preserve indent in contents +179 // maybe incrementally dump trace +180 trace_line& t = past_lines.back(); +181 if (should_incrementally_print_trace()) { +182 dump_trace_line(cerr, t); +183 } +184 // End trace Commit +185 } +186 +187 // clean up +188 delete curr_stream; +189 curr_stream = NULL; +190 curr_label.clear(); +191 curr_depth = Max_depth; +192 } +193 +194 //:: == Initializing the trace in tests +195 +196 :(before "End Includes") +197 #define START_TRACING_UNTIL_END_OF_SCOPE lease_tracer leased_tracer; +198 :(before "End Test Setup") +199 START_TRACING_UNTIL_END_OF_SCOPE 200 -201 :(before "End Includes") -202 #define raise (!Trace_stream ? (++Trace_errors,cerr) /*do print*/ : Trace_stream->stream(Error_depth, "error")) -203 #define warn (!Trace_stream ? (++Trace_errors,cerr) /*do print*/ : Trace_stream->stream(Warn_depth, "warn")) -204 -205 //: Print errors and warnings to the screen by default. -206 :(before "struct trace_stream") // include constants in all cleaved compilation units -207 const int Error_depth = 0; -208 const int Warn_depth = 1; -209 :(before "End Globals") -210 int Hide_errors = false; // if set, don't print errors or warnings to screen -211 int Hide_warnings = false; // if set, don't print warnings to screen -212 :(before "End Reset") -213 Hide_errors = false; -214 Hide_warnings = false; -215 //: Never dump warnings in tests -216 :(before "End Test Setup") -217 Hide_warnings = true; -218 :(code) -219 bool trace_stream::should_incrementally_print_trace() { -220 if (!Hide_errors && curr_depth == Error_depth) return true; -221 if (!Hide_warnings && !Hide_errors && curr_depth == Warn_depth) return true; -222 // End Incremental Trace Print Conditions -223 return false; -224 } -225 :(before "End trace_stream Methods") -226 bool should_incrementally_print_trace(); -227 -228 :(before "End Globals") -229 int Trace_errors = 0; // used only when Trace_stream is NULL -230 -231 // Fail tests that displayed (unexpected) errors. -232 // Expected errors should always be hidden and silently checked for. -233 :(before "End Test Teardown") -234 if (Passed && !Hide_errors && trace_contains_errors()) { -235 Passed = false; -236 } -237 :(code) -238 bool trace_contains_errors() { -239 return Trace_errors > 0 || trace_count("error") > 0; -240 } -241 -242 :(before "End Includes") -243 // If we aren't yet sure how to deal with some corner case, use assert_for_now -244 // to indicate that it isn't an inviolable invariant. -245 #define assert_for_now assert -246 #define raise_for_now raise -247 -248 //:: == Other assertions on traces -249 //: Primitives: -250 //: - CHECK_TRACE_CONTENTS(lines) -251 //: Assert that the trace contains the given lines (separated by newlines) -252 //: in order. There can be other intervening lines between them. -253 //: - CHECK_TRACE_DOESNT_CONTAIN(line) -254 //: - CHECK_TRACE_DOESNT_CONTAIN(label, contents) -255 //: Assert that the trace doesn't contain the given (single) line. -256 //: - CHECK_TRACE_COUNT(label, count) -257 //: Assert that the trace contains exactly 'count' lines with the given -258 //: 'label'. -259 //: - CHECK_TRACE_CONTAINS_ERRORS() -260 //: - CHECK_TRACE_DOESNT_CONTAIN_ERRORS() -261 //: - trace_count_prefix(label, prefix) -262 //: Count the number of trace lines with the given 'label' that start with -263 //: the given 'prefix'. -264 -265 :(before "End Includes") -266 #define CHECK_TRACE_CONTENTS(...) check_trace_contents(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__) -267 -268 #define CHECK_TRACE_DOESNT_CONTAIN(...) CHECK(trace_doesnt_contain(__VA_ARGS__)) -269 -270 #define CHECK_TRACE_COUNT(label, count) \ -271 if (Passed && trace_count(label) != (count)) { \ -272 cerr << "\nF - " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ << "): trace_count of " << label << " should be " << count << '\n'; \ -273 cerr << " got " << trace_count(label) << '\n'; /* multiple eval */ \ -274 DUMP(label); \ -275 Passed = false; \ -276 return; /* Currently we stop at the very first failure. */ \ -277 } -278 -279 #define CHECK_TRACE_CONTAINS_ERRORS() CHECK(trace_contains_errors()) -280 #define CHECK_TRACE_DOESNT_CONTAIN_ERRORS() \ -281 if (Passed && trace_contains_errors()) { \ -282 cerr << "\nF - " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ << "): unexpected errors\n"; \ -283 DUMP("error"); \ -284 Passed = false; \ -285 return; \ -286 } -287 -288 // Allow tests to ignore trace lines generated during setup. -289 #define CLEAR_TRACE delete Trace_stream, Trace_stream = new trace_stream -290 -291 :(code) -292 bool check_trace_contents(string FUNCTION, string FILE, int LINE, string expected) { -293 if (!Passed) return false; -294 if (!Trace_stream) return false; -295 vector<string> expected_lines = split(expected, "\n"); -296 int curr_expected_line = 0; -297 while (curr_expected_line < SIZE(expected_lines) && expected_lines.at(curr_expected_line).empty()) -298 ++curr_expected_line; -299 if (curr_expected_line == SIZE(expected_lines)) return true; -300 string label, contents; -301 split_label_contents(expected_lines.at(curr_expected_line), &label, &contents); -302 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { -303 if (label != p->label) continue; -304 if (contents != trim(p->contents)) continue; -305 ++curr_expected_line; -306 while (curr_expected_line < SIZE(expected_lines) && expected_lines.at(curr_expected_line).empty()) -307 ++curr_expected_line; -308 if (curr_expected_line == SIZE(expected_lines)) return true; -309 split_label_contents(expected_lines.at(curr_expected_line), &label, &contents); -310 } -311 -312 if (line_exists_anywhere(label, contents)) { -313 cerr << "\nF - " << FUNCTION << "(" << FILE << ":" << LINE << "): line [" << label << ": " << contents << "] out of order in trace:\n"; -314 DUMP(""); -315 } -316 else { -317 cerr << "\nF - " << FUNCTION << "(" << FILE << ":" << LINE << "): missing [" << contents << "] in trace:\n"; -318 DUMP(label); -319 } -320 Passed = false; -321 return false; -322 } -323 -324 bool trace_doesnt_contain(string expected) { -325 vector<string> tmp = split_first(expected, ": "); -326 if (SIZE(tmp) == 1) { -327 raise << expected << ": missing label or contents in trace line\n" << end(); -328 assert(false); -329 } -330 return trace_count(tmp.at(0), tmp.at(1)) == 0; -331 } -332 -333 int trace_count(string label) { -334 return trace_count(label, ""); -335 } -336 -337 int trace_count(string label, string line) { -338 if (!Trace_stream) return 0; -339 long result = 0; -340 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { -341 if (label == p->label) { -342 if (line == "" || trim(line) == trim(p->contents)) -343 ++result; -344 } +201 //: Trace_stream is a resource, lease_tracer uses RAII to manage it. +202 :(before "End Types") +203 struct lease_tracer { +204 lease_tracer(); +205 ~lease_tracer(); +206 }; +207 :(code) +208 lease_tracer::lease_tracer() { Trace_stream = new trace_stream; } +209 lease_tracer::~lease_tracer() { +210 delete Trace_stream; +211 Trace_stream = NULL; +212 } +213 +214 //:: == Errors and warnings using traces +215 +216 :(before "End Includes") +217 #define raise (!Trace_stream ? (++Trace_errors,cerr) /*do print*/ : Trace_stream->stream(Error_depth, "error")) +218 #define warn (!Trace_stream ? (++Trace_errors,cerr) /*do print*/ : Trace_stream->stream(Warn_depth, "warn")) +219 +220 //: Print errors and warnings to the screen by default. +221 :(before "struct trace_stream") // include constants in all cleaved compilation units +222 const int Error_depth = 0; +223 const int Warn_depth = 1; +224 :(before "End Globals") +225 int Hide_errors = false; // if set, don't print errors or warnings to screen +226 int Hide_warnings = false; // if set, don't print warnings to screen +227 :(before "End Reset") +228 Hide_errors = false; +229 Hide_warnings = false; +230 //: Never dump warnings in tests +231 :(before "End Test Setup") +232 Hide_warnings = true; +233 :(code) +234 bool trace_stream::should_incrementally_print_trace() { +235 if (!Hide_errors && curr_depth == Error_depth) return true; +236 if (!Hide_warnings && !Hide_errors && curr_depth == Warn_depth) return true; +237 // End Incremental Trace Print Conditions +238 return false; +239 } +240 :(before "End trace_stream Methods") +241 bool should_incrementally_print_trace(); +242 +243 :(before "End Globals") +244 int Trace_errors = 0; // used only when Trace_stream is NULL +245 +246 // Fail tests that displayed (unexpected) errors. +247 // Expected errors should always be hidden and silently checked for. +248 :(before "End Test Teardown") +249 if (Passed && !Hide_errors && trace_contains_errors()) { +250 Passed = false; +251 } +252 :(code) +253 bool trace_contains_errors() { +254 return Trace_errors > 0 || trace_count("error") > 0; +255 } +256 +257 :(before "End Includes") +258 // If we aren't yet sure how to deal with some corner case, use assert_for_now +259 // to indicate that it isn't an inviolable invariant. +260 #define assert_for_now assert +261 #define raise_for_now raise +262 +263 //:: == Other assertions on traces +264 //: Primitives: +265 //: - CHECK_TRACE_CONTENTS(lines) +266 //: Assert that the trace contains the given lines (separated by newlines) +267 //: in order. There can be other intervening lines between them. +268 //: - CHECK_TRACE_DOESNT_CONTAIN(line) +269 //: - CHECK_TRACE_DOESNT_CONTAIN(label, contents) +270 //: Assert that the trace doesn't contain the given (single) line. +271 //: - CHECK_TRACE_COUNT(label, count) +272 //: Assert that the trace contains exactly 'count' lines with the given +273 //: 'label'. +274 //: - CHECK_TRACE_CONTAINS_ERRORS() +275 //: - CHECK_TRACE_DOESNT_CONTAIN_ERRORS() +276 //: - trace_count_prefix(label, prefix) +277 //: Count the number of trace lines with the given 'label' that start with +278 //: the given 'prefix'. +279 +280 :(before "End Includes") +281 #define CHECK_TRACE_CONTENTS(...) check_trace_contents(__FUNCTION__, __FILE__, __LINE__, __VA_ARGS__) +282 +283 #define CHECK_TRACE_DOESNT_CONTAIN(...) CHECK(trace_doesnt_contain(__VA_ARGS__)) +284 +285 #define CHECK_TRACE_COUNT(label, count) \ +286 if (Passed && trace_count(label) != (count)) { \ +287 cerr << "\nF - " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ << "): trace_count of " << label << " should be " << count << '\n'; \ +288 cerr << " got " << trace_count(label) << '\n'; /* multiple eval */ \ +289 DUMP(label); \ +290 Passed = false; \ +291 return; /* Currently we stop at the very first failure. */ \ +292 } +293 +294 #define CHECK_TRACE_CONTAINS_ERRORS() CHECK(trace_contains_errors()) +295 #define CHECK_TRACE_DOESNT_CONTAIN_ERRORS() \ +296 if (Passed && trace_contains_errors()) { \ +297 cerr << "\nF - " << __FUNCTION__ << "(" << __FILE__ << ":" << __LINE__ << "): unexpected errors\n"; \ +298 DUMP("error"); \ +299 Passed = false; \ +300 return; \ +301 } +302 +303 // Allow tests to ignore trace lines generated during setup. +304 #define CLEAR_TRACE delete Trace_stream, Trace_stream = new trace_stream +305 +306 :(code) +307 bool check_trace_contents(string FUNCTION, string FILE, int LINE, string expected) { +308 if (!Passed) return false; +309 if (!Trace_stream) return false; +310 vector<string> expected_lines = split(expected, "\n"); +311 int curr_expected_line = 0; +312 while (curr_expected_line < SIZE(expected_lines) && expected_lines.at(curr_expected_line).empty()) +313 ++curr_expected_line; +314 if (curr_expected_line == SIZE(expected_lines)) return true; +315 string label, contents; +316 split_label_contents(expected_lines.at(curr_expected_line), &label, &contents); +317 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { +318 if (label != p->label) continue; +319 string t = trim(p->contents); +320 if (contents != unescape_newline(t)) continue; +321 ++curr_expected_line; +322 while (curr_expected_line < SIZE(expected_lines) && expected_lines.at(curr_expected_line).empty()) +323 ++curr_expected_line; +324 if (curr_expected_line == SIZE(expected_lines)) return true; +325 split_label_contents(expected_lines.at(curr_expected_line), &label, &contents); +326 } +327 +328 if (line_exists_anywhere(label, contents)) { +329 cerr << "\nF - " << FUNCTION << "(" << FILE << ":" << LINE << "): line [" << label << ": " << contents << "] out of order in trace:\n"; +330 DUMP(""); +331 } +332 else { +333 cerr << "\nF - " << FUNCTION << "(" << FILE << ":" << LINE << "): missing [" << contents << "] in trace:\n"; +334 DUMP(label); +335 } +336 Passed = false; +337 return false; +338 } +339 +340 bool trace_doesnt_contain(string expected) { +341 vector<string> tmp = split_first(expected, ": "); +342 if (SIZE(tmp) == 1) { +343 raise << expected << ": missing label or contents in trace line\n" << end(); +344 assert(false); 345 } -346 return result; +346 return trace_count(tmp.at(0), tmp.at(1)) == 0; 347 } 348 -349 int trace_count_prefix(string label, string prefix) { -350 if (!Trace_stream) return 0; -351 long result = 0; -352 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { -353 if (label == p->label) { -354 if (starts_with(trim(p->contents), trim(prefix))) -355 ++result; -356 } -357 } -358 return result; -359 } -360 -361 void split_label_contents(const string& s, string* label, string* contents) { -362 static const string delim(": "); -363 size_t pos = s.find(delim); -364 if (pos == string::npos) { -365 *label = ""; -366 *contents = trim(s); -367 } -368 else { -369 *label = trim(s.substr(0, pos)); -370 *contents = trim(s.substr(pos+SIZE(delim))); -371 } -372 } -373 -374 bool line_exists_anywhere(const string& label, const string& contents) { -375 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { -376 if (label != p->label) continue; -377 if (contents == trim(p->contents)) return true; -378 } -379 return false; -380 } -381 -382 vector<string> split(string s, string delim) { -383 vector<string> result; -384 size_t begin=0, end=s.find(delim); -385 while (true) { -386 if (end == string::npos) { -387 result.push_back(string(s, begin, string::npos)); -388 break; -389 } -390 result.push_back(string(s, begin, end-begin)); -391 begin = end+SIZE(delim); -392 end = s.find(delim, begin); -393 } -394 return result; -395 } -396 -397 vector<string> split_first(string s, string delim) { -398 vector<string> result; -399 size_t end=s.find(delim); -400 result.push_back(string(s, 0, end)); -401 if (end != string::npos) -402 result.push_back(string(s, end+SIZE(delim), string::npos)); -403 return result; -404 } -405 -406 //:: == Helpers for debugging using traces -407 -408 :(before "End Includes") -409 // To debug why a test is failing, dump its trace using '?'. -410 #define DUMP(label) if (Trace_stream) cerr << Trace_stream->readable_contents(label); -411 -412 // To add temporary prints to the trace, use 'dbg'. -413 // `git log` should never show any calls to 'dbg'. -414 #define dbg trace(0, "a") -415 -416 //: Dump the entire trace to file where it can be browsed offline. -417 //: Dump the trace as it happens; that way you get something even if the -418 //: program crashes. -419 -420 :(before "End Globals") -421 ofstream Trace_file; -422 :(before "End Commandline Options(*arg)") -423 else if (is_equal(*arg, "--trace")) { -424 cerr << "saving trace to 'last_run'\n"; -425 Trace_file.open("last_run"); -426 // Add a dummy line up top; otherwise the `browse_trace` tool currently has -427 // no way to expand any lines above an error. -428 Trace_file << " 0 dummy: start\n"; -429 } -430 :(before "End trace Commit") -431 if (Trace_file) { -432 Trace_file << std::setw(4) << t.depth << ' ' << t.label << ": " << t.contents << '\n'; -433 } -434 :(before "End One-time Setup") -435 atexit(cleanup_main); -436 :(code) -437 void cleanup_main() { -438 if (Trace_file) Trace_file.close(); -439 // End cleanup_main -440 } -441 -442 :(before "End trace_stream Methods") -443 string readable_contents(string label) { -444 string trim(const string& s); // prototype -445 ostringstream output; -446 label = trim(label); -447 for (vector<trace_line>::iterator p = past_lines.begin(); p != past_lines.end(); ++p) -448 if (label.empty() || label == p->label) -449 output << std::setw(4) << p->depth << ' ' << p->label << ": " << p->contents << '\n'; -450 return output.str(); -451 } -452 -453 //: Print traces to the screen as they happen. -454 //: Particularly useful when juggling multiple trace streams, like when -455 //: debugging sandboxes. -456 :(before "End Globals") -457 bool Dump_trace = false; -458 :(before "End Commandline Options(*arg)") -459 else if (is_equal(*arg, "--dump")) { -460 Dump_trace = true; -461 } -462 :(before "End Incremental Trace Print Conditions") -463 if (Dump_trace) return true; -464 -465 //: Miscellaneous helpers. -466 -467 :(code) -468 string trim(const string& s) { -469 string::const_iterator first = s.begin(); -470 while (first != s.end() && isspace(*first)) -471 ++first; -472 if (first == s.end()) return ""; -473 -474 string::const_iterator last = --s.end(); -475 while (last != s.begin() && isspace(*last)) -476 --last; -477 ++last; -478 return string(first, last); -479 } +349 int trace_count(string label) { +350 return trace_count(label, ""); +351 } +352 +353 int trace_count(string label, string line) { +354 if (!Trace_stream) return 0; +355 long result = 0; +356 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { +357 if (label == p->label) { +358 if (line == "" || trim(line) == trim(p->contents)) +359 ++result; +360 } +361 } +362 return result; +363 } +364 +365 int trace_count_prefix(string label, string prefix) { +366 if (!Trace_stream) return 0; +367 long result = 0; +368 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { +369 if (label == p->label) { +370 if (starts_with(trim(p->contents), trim(prefix))) +371 ++result; +372 } +373 } +374 return result; +375 } +376 +377 void split_label_contents(const string& s, string* label, string* contents) { +378 static const string delim(": "); +379 size_t pos = s.find(delim); +380 if (pos == string::npos) { +381 *label = ""; +382 *contents = trim(s); +383 } +384 else { +385 *label = trim(s.substr(0, pos)); +386 *contents = trim(s.substr(pos+SIZE(delim))); +387 } +388 } +389 +390 bool line_exists_anywhere(const string& label, const string& contents) { +391 for (vector<trace_line>::iterator p = Trace_stream->past_lines.begin(); p != Trace_stream->past_lines.end(); ++p) { +392 if (label != p->label) continue; +393 if (contents == trim(p->contents)) return true; +394 } +395 return false; +396 } +397 +398 vector<string> split(string s, string delim) { +399 vector<string> result; +400 size_t begin=0, end=s.find(delim); +401 while (true) { +402 if (end == string::npos) { +403 result.push_back(string(s, begin, string::npos)); +404 break; +405 } +406 result.push_back(string(s, begin, end-begin)); +407 begin = end+SIZE(delim); +408 end = s.find(delim, begin); +409 } +410 return result; +411 } +412 +413 vector<string> split_first(string s, string delim) { +414 vector<string> result; +415 size_t end=s.find(delim); +416 result.push_back(string(s, 0, end)); +417 if (end != string::npos) +418 result.push_back(string(s, end+SIZE(delim), string::npos)); +419 return result; +420 } +421 +422 //:: == Helpers for debugging using traces +423 +424 :(before "End Includes") +425 // To debug why a test is failing, dump its trace using '?'. +426 #define DUMP(label) if (Trace_stream) cerr << Trace_stream->readable_contents(label); +427 +428 // To add temporary prints to the trace, use 'dbg'. +429 // `git log` should never show any calls to 'dbg'. +430 #define dbg trace(0, "a") +431 +432 //: Dump the entire trace to file where it can be browsed offline. +433 //: Dump the trace as it happens; that way you get something even if the +434 //: program crashes. +435 +436 :(before "End Globals") +437 ofstream Trace_file; +438 :(before "End Commandline Options(*arg)") +439 else if (is_equal(*arg, "--trace")) { +440 cerr << "saving trace to 'last_run'\n"; +441 Trace_file.open("last_run"); +442 // Add a dummy line up top; otherwise the `browse_trace` tool currently has +443 // no way to expand any lines above an error. +444 Trace_file << " 0 dummy: start\n"; +445 } +446 :(before "End trace Commit") +447 if (Trace_file) { +448 dump_trace_line(Trace_file, t); +449 } +450 :(before "End One-time Setup") +451 atexit(cleanup_main); +452 :(code) +453 void cleanup_main() { +454 if (Trace_file) Trace_file.close(); +455 // End cleanup_main +456 } +457 +458 :(before "End trace_stream Methods") +459 string readable_contents(string label) { +460 string trim(const string& s); // prototype +461 ostringstream output; +462 label = trim(label); +463 for (vector<trace_line>::iterator p = past_lines.begin(); p != past_lines.end(); ++p) +464 if (label.empty() || label == p->label) +465 dump_trace_line(output, *p); +466 return output.str(); +467 } +468 +469 //: Print traces to the screen as they happen. +470 //: Particularly useful when juggling multiple trace streams, like when +471 //: debugging sandboxes. +472 :(before "End Globals") +473 bool Dump_trace = false; +474 :(before "End Commandline Options(*arg)") +475 else if (is_equal(*arg, "--dump")) { +476 Dump_trace = true; +477 } +478 :(before "End Incremental Trace Print Conditions") +479 if (Dump_trace) return true; 480 -481 :(before "End Includes") -482 #include <vector> -483 using std::vector; -484 #include <list> -485 using std::list; -486 #include <set> -487 using std::set; -488 -489 #include <sstream> -490 using std::istringstream; -491 using std::ostringstream; -492 -493 #include <fstream> -494 using std::ifstream; -495 using std::ofstream; +481 //: Miscellaneous helpers. +482 +483 :(code) +484 string trim(const string& s) { +485 string::const_iterator first = s.begin(); +486 while (first != s.end() && isspace(*first)) +487 ++first; +488 if (first == s.end()) return ""; +489 +490 string::const_iterator last = --s.end(); +491 while (last != s.begin() && isspace(*last)) +492 --last; +493 ++last; +494 return string(first, last); +495 } +496 +497 :(before "End Includes") +498 #include <vector> +499 using std::vector; +500 #include <list> +501 using std::list; +502 #include <set> +503 using std::set; +504 +505 #include <sstream> +506 using std::istringstream; +507 using std::ostringstream; +508 +509 #include <fstream> +510 using std::ifstream; +511 using std::ofstream; -- cgit 1.4.1-2-gfad0