#include #include /* Modify a subrange of a string, while a witness is watching another subrange of the same string. Cases are the relative positions and overlaps of the modifier vs the witness. MS = modifier start ME = modifier end WS = witness start WE = witness end The test does: starts with the entire string being, initially, the alphabet; prints this entire alphabet sets up modifier and witness as ranges within it, and prints a visualization of those ranges does the main modification prints the result of the main modification, which is always an unsurprising consequence of the modifier range, but shows little about what happened to the witness, particularly if the witness is/became empty modifies the witness to be "?" prints the result of this second modification, which implies what the witness included after the main modification Deriving the concrete list of cases.... By definition of a string, MS <= ME and WS <= WE. This API's convention has Start positions being inclusive and end positions being exclusive. v Case number in output With 1 equivalence class: MS = ME = WS = WE 1 With 2 equivalence classes: < = = MS rest 2 WS rest 3 = < = MS ME WS WE 4 WS WE MS ME 5 MS WS ME WE 6 = = < rest ME 7 rest WE 8 With 3 equivalence classes < < = MS ME WS WE 9 WS ME WE 10 +2 11, 12 < = < MS WS ME WE 13 WE ME 14 +2 15, 16 = < < MS WS WE ME 17 ME WS WE 18 +2 19, 20 With 4 equivalence classes < < < MS ME WS WE 21 WS ME WE 22 WE ME 23 +3 24, 25, 26 */ void showOneReplacement(string & s, int ms, int me, int ws, int we, const char* replaceWith) { assert( ms >= 0 && ms <= me && me <= size(s) ); assert( ws >= 0 && ws <= we && we <= size(s) ); string mod = s(ms, me)`shareEdits; string wit = s(ws, we)`shareEdits; string modOld = mod; string witOld = wit; // s, before the mode sout | s; // visualize the pair of ranges sout | nlOff; for ( i; size(s) ) { if( i < ms || i > me ) { sout | ' '; } else if ( i < me ) { sout | '-'; } else { assert ( i == me ); sout | '!'; } } sout | nl; for ( i; size(s) ) { if( i < ws || i > we ) { sout | ' '; } else if ( i < we ) { sout | '-'; } else { assert ( i == we ); sout | '?'; } } sout | nl; sout | nlOn; mod = replaceWith; // main replacement sout | s | "( wit = " | wit | "witlen = " | size(wit) | " )"; wit = "?"; // witness-revelaing replacement sout | s; } void runReplaceCases() { char * alphabetTemplate = "abcdefghijklmnopqrstuvwxyz"; struct { int ms; int me; int ws; int we; char *replaceWith; char *label; } cases[] = { { 12, 14, 10, 20, "xxxxx", "warmup" }, { 10, 10, 10, 10, "=====", "1" }, { 10, 10, 10, 10, "==" , "" }, { 10, 10, 10, 10, "=" , "" }, { 10, 10, 10, 10, "" , "" }, { 10, 12, 12, 12, "=====", "2" }, { 10, 12, 12, 12, "==" , "" }, { 10, 12, 12, 12, "=" , "" }, { 10, 12, 12, 12, "" , "" }, { 12, 12, 10, 12, "=====", "3" }, { 12, 12, 10, 12, "==" , "" }, { 12, 12, 10, 12, "=" , "" }, { 12, 12, 10, 12, "" , "" }, { 10, 10, 12, 12, "=====", "4" }, { 10, 10, 12, 12, "==" , "" }, { 10, 10, 12, 12, "=" , "" }, { 10, 10, 12, 12, "" , "" }, { 12, 12, 10, 10, "=====", "5" }, { 12, 12, 10, 10, "==" , "" }, { 12, 12, 10, 10, "=" , "" }, { 12, 12, 10, 10, "" , "" }, { 10, 12, 10, 12, "=====", "6" }, { 10, 12, 10, 12, "==" , "" }, { 10, 12, 10, 12, "=" , "" }, { 10, 12, 10, 12, "" , "" }, { 10, 12, 10, 10, "=====", "7" }, { 10, 12, 10, 10, "==" , "" }, { 10, 12, 10, 10, "=" , "" }, { 10, 12, 10, 10, "" , "" }, { 10, 10, 10, 12, "=====", "8" }, { 10, 10, 10, 12, "==" , "" }, { 10, 10, 10, 12, "=" , "" }, { 10, 10, 10, 12, "" , "" }, { 10, 12, 14, 14, "=====", "9" }, { 10, 12, 14, 14, "==" , "" }, { 10, 12, 14, 14, "=" , "" }, { 10, 12, 14, 14, "" , "" }, { 10, 14, 12, 14, "=====", "10" }, { 10, 14, 12, 14, "==" , "" }, { 10, 14, 12, 14, "=" , "" }, // FORMERLY unrunnable bug: tries to print seemingly infinite string { 10, 14, 12, 14, "" , "" }, // ditto { 14, 14, 10, 12, "=====", "11" }, { 14, 14, 10, 12, "==" , "" }, { 14, 14, 10, 12, "=" , "" }, { 14, 14, 10, 12, "" , "" }, { 12, 14, 10, 14, "=====", "12" }, // correctness observation: watching klmn while mn |-> xxx gives klxxx because the mn is inside what I'm watching { 12, 14, 10, 14, "==" , "" }, { 12, 14, 10, 14, "=" , "" }, { 12, 14, 10, 14, "" , "" }, { 10, 12, 12, 14, "=====", "13" }, { 10, 12, 12, 14, "==" , "" }, { 10, 12, 12, 14, "=" , "" }, { 10, 12, 12, 14, "" , "" }, { 10, 14, 12, 12, "=====", "14" }, { 10, 14, 12, 12, "==" , "" }, { 10, 14, 12, 12, "=" , "" }, { 10, 14, 12, 12, "" , "" }, { 12, 14, 10, 12, "=====", "15" }, { 12, 14, 10, 12, "==" , "" }, { 12, 14, 10, 12, "=" , "" }, { 12, 14, 10, 12, "" , "" }, { 12, 12, 10, 14, "=====", "16" }, { 12, 12, 10, 14, "==" , "" }, { 12, 12, 10, 14, "=" , "" }, { 12, 12, 10, 14, "" , "" }, { 10, 14, 10, 12, "=====", "17" }, { 10, 14, 10, 12, "==" , "" }, { 10, 14, 10, 12, "=" , "" }, { 10, 14, 10, 12, "" , "" }, { 10, 10, 12, 14, "=====", "18" }, { 10, 10, 12, 14, "==" , "" }, { 10, 10, 12, 14, "=" , "" }, { 10, 10, 12, 14, "" , "" }, { 10, 12, 10, 14, "=====", "19" }, { 10, 12, 10, 14, "==" , "" }, { 10, 12, 10, 14, "=" , "" }, { 10, 12, 10, 14, "" , "" }, { 12, 14, 10, 10, "=====", "20" }, { 12, 14, 10, 10, "==" , "" }, { 12, 14, 10, 10, "=" , "" }, { 12, 14, 10, 10, "" , "" }, { 10, 12, 14, 16, "=====", "21" }, { 10, 12, 14, 16, "==" , "" }, { 10, 12, 14, 16, "=" , "" }, { 10, 12, 14, 16, "" , "" }, { 10, 14, 12, 16, "=====", "22" }, { 10, 14, 12, 16, "==" , "" }, { 10, 14, 12, 16, "=" , "" }, { 10, 14, 12, 16, "" , "" }, { 10, 16, 12, 14, "=====", "23" }, { 10, 16, 12, 14, "==" , "" }, { 10, 16, 12, 14, "=" , "" }, { 10, 16, 12, 14, "" , "" }, { 14, 16, 10, 12, "=====", "24" }, { 14, 16, 10, 12, "==" , "" }, { 14, 16, 10, 12, "=" , "" }, { 14, 16, 10, 12, "" , "" }, { 12, 16, 10, 14, "=====", "25" }, { 12, 16, 10, 14, "==" , "" }, { 12, 16, 10, 14, "=" , "" }, { 12, 16, 10, 14, "" , "" }, { 12, 14, 10, 16, "=====", "26" }, { 12, 14, 10, 16, "==" , "" }, { 12, 14, 10, 16, "=" , "" }, { 12, 14, 10, 16, "" , "" }, }; for ( i; sizeof(cases)/sizeof(cases[0]) ) { sout | "------------------------------------------------------------------------" | cases[i].label; string replaceIn = alphabetTemplate; showOneReplacement( replaceIn, cases[i].ms, cases[i].me, cases[i].ws, cases[i].we, cases[i].replaceWith ); } } int main() { #ifdef STRING_SHARING_OFF string_sharectx c = { NO_SHARING }; #endif // 0 1 2 // 01234567890123456789012345 string s = "abcdefghijklmnopqrstuvwxyz"; s(5,10) = "qqqqq"; // start=5, end=10, len=5 sout | s; s(5,5) = "-----"; // start=5, end=5, len=0 sout | s; runReplaceCases(); }