Index: tests/collections/.expect/string-api-coverage-noshare.txt
===================================================================
--- tests/collections/.expect/string-api-coverage-noshare.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
+++ tests/collections/.expect/string-api-coverage-noshare.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -0,0 +1,1 @@
+string-api-coverage.txt
Index: tests/collections/.expect/string-api-coverage.txt
===================================================================
--- tests/collections/.expect/string-api-coverage.txt	(revision 0fc447c38ee7b02d6cdb7bd08aef617ade5852c7)
+++ tests/collections/.expect/string-api-coverage.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -1,3 +1,5 @@
 hello hello hello
+
+hello
 true false
 true false
Index: tests/collections/.expect/string-ctx-manage.txt
===================================================================
--- tests/collections/.expect/string-ctx-manage.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
+++ tests/collections/.expect/string-ctx-manage.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -0,0 +1,7 @@
+hi
+bye
+hi
+bye
+hi
+bye
+done
Index: tests/collections/.expect/string-gc.txt
===================================================================
--- tests/collections/.expect/string-gc.txt	(revision 0fc447c38ee7b02d6cdb7bd08aef617ade5852c7)
+++ tests/collections/.expect/string-gc.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -38,2 +38,13 @@
 x from 5 to 15
 y from 5 to 15
+======================== fillNoCompact
+about to expand, a = aaa
+expanded, a = aaa
+about to expand, a = aaa
+expanded, a = aaa
+about to expand, a = aaa
+expanded, a = aaa
+about to expand, a = aaa
+expanded, a = aaa
+about to expand, a = aaa
+expanded, a = aaa
Index: tests/collections/.expect/string-overwrite-noshare.txt
===================================================================
--- tests/collections/.expect/string-overwrite-noshare.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
+++ tests/collections/.expect/string-overwrite-noshare.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -0,0 +1,1 @@
+string-overwrite.txt
Index: tests/collections/string-api-coverage-noshare.cfa
===================================================================
--- tests/collections/string-api-coverage-noshare.cfa	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
+++ tests/collections/string-api-coverage-noshare.cfa	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -0,0 +1,2 @@
+#define STRING_SHARING_OFF
+#include "string-api-coverage.cfa"
Index: tests/collections/string-api-coverage.cfa
===================================================================
--- tests/collections/string-api-coverage.cfa	(revision 0fc447c38ee7b02d6cdb7bd08aef617ade5852c7)
+++ tests/collections/string-api-coverage.cfa	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -1,3 +1,4 @@
 #include <containers/string.hfa>
+#include <string_sharectx.hfa>
 
 void assertWellFormedHandleList( int maxLen ) { // with(HeapArea)
@@ -25,4 +26,9 @@
 
 int main () {
+
+    #ifdef STRING_SHARING_OFF
+    string_sharectx c = { NO_SHARING };
+    #endif
+
     string s = "hello";
     string s2 = "hello";
@@ -31,5 +37,11 @@
 
     // IO operator, x2
-    sout | s | s | s;
+    sout | s | s | s;  // hello hello hello
+
+    // empty ctor then assign
+    string sxx;
+    sout | sxx;  // (blank line)
+    sxx = s;
+    sout | sxx;  // hello
 
     // Comparisons
Index: tests/collections/string-ctx-manage.cfa
===================================================================
--- tests/collections/string-ctx-manage.cfa	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
+++ tests/collections/string-ctx-manage.cfa	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -0,0 +1,79 @@
+#include <string.hfa>
+#include <string_sharectx.hfa>
+#include <string_res.hfa>
+
+// In these tests, shared heaps are never remotely full and string sizes are tiny.
+// So here, the SUT should put a yes-sharing string in a heap with lots of spare room.
+// The SUT should always keep a no-sharing string's buffer 1x--2x the string's size.
+// This check uses 3x as a heuristic split between those cases.
+void assertSpareRoomInHeap( string & s, bool expectOversized ) {
+    double bytesInHeap = DEBUG_string_bytes_in_heap(s.inner->Handle.ulink);
+    double bytesUsed =  s.inner->Handle.lnth;
+    double overhead = bytesInHeap / bytesUsed;
+    assert (overhead >= 1);
+    if ( expectOversized )
+        assert( overhead >= 3.0 );
+    else 
+        assert( overhead < 3.0 );
+}
+
+void baseline() {
+    string x = "hi";
+    assertSpareRoomInHeap( x, true );
+
+    string y = x; // construct y in same context, no write yet => no copy yet
+    assertSpareRoomInHeap( y, true );
+    assert( y.inner->Handle.s == x.inner->Handle.s);
+    sout | y; // hi
+
+    x = "bye";
+    assertSpareRoomInHeap( x, true );
+    y = x; // y in same context, no write yet => no copy yet
+    assertSpareRoomInHeap( y, true );
+    assert( y.inner->Handle.s == x.inner->Handle.s);
+    sout | y; // bye
+}
+
+void eagerCopy() {
+    string x = "hi";
+    assertSpareRoomInHeap( x, true );
+    string_sharectx c = { NEW_SHARING };
+
+    string y = x; // construct y in different context => eager copy
+    assertSpareRoomInHeap( y, true );
+    assert( y.inner->Handle.s != x.inner->Handle.s);
+    sout | y; // hi
+
+    x = "bye";
+    assertSpareRoomInHeap( x, true );
+    y = x; // y was already in different context => eager copy
+    assertSpareRoomInHeap( y, true );
+    assert( y.inner->Handle.s != x.inner->Handle.s);
+    sout | y; // bye
+}
+
+void soloAlloc() {
+    string x = "hi";
+    assertSpareRoomInHeap( x, true );
+    string_sharectx c = { NO_SHARING };
+    
+    string y = x; // y allocates into private pad, implying eager copy
+    assertSpareRoomInHeap( y, false );
+    assert( y.inner->Handle.s != x.inner->Handle.s);
+    sout | y; // hi
+
+    x = "bye";
+    assertSpareRoomInHeap( x, true );
+    y = x; // into private y => eager copy
+    assertSpareRoomInHeap( y, false );
+    assert( y.inner->Handle.s != x.inner->Handle.s);
+    sout | y; // bye
+}
+
+
+int main() {
+    baseline();
+    eagerCopy();
+    soloAlloc();
+    printf("done\n");
+}
Index: tests/collections/string-gc.cfa
===================================================================
--- tests/collections/string-gc.cfa	(revision 0fc447c38ee7b02d6cdb7bd08aef617ade5852c7)
+++ tests/collections/string-gc.cfa	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -2,9 +2,9 @@
 
 size_t bytesRemaining() {
-    return DEBUG_string_bytes_avail_until_gc( DEBUG_string_heap );
+    return DEBUG_string_bytes_avail_until_gc( DEBUG_string_heap() );
 }
 
 size_t heapOffsetStart( string_res & s ) {
-    const char * startByte = DEBUG_string_heap_start( DEBUG_string_heap );
+    const char * startByte = DEBUG_string_heap_start( DEBUG_string_heap() );
     assert( s.Handle.s >= startByte );
     return s.Handle.s - startByte;
@@ -120,6 +120,34 @@
 }
 
+void fillNoCompact() {
+    // show that allocating in a heap filled with mostly live strings (no collectable garbage) causes heap growth
+
+    sout | "======================== fillNoCompact";
+
+    size_t lastTimeBytesAvail = bytesRemaining();
+    assert( lastTimeBytesAvail >= 200 ); // starting this test with nontrivial room
+
+    // mostly fill the pad
+    string_res a = "aaa";  // will have to be moved
+    string_res z = "zzz";
+    for (i; 5) {
+        while ( bytesRemaining() > 10 ) {
+            z += ".";
+        }
+        sout | "about to expand, a = " | a;
+        while ( bytesRemaining() <= 10 ) {
+            z += ".";
+        }
+        sout | "expanded, a = " | a;
+
+        // each growth gives more usable space than the last
+        assert( bytesRemaining() > lastTimeBytesAvail );
+        lastTimeBytesAvail = bytesRemaining();
+    }
+}
+
 int main() {
     basicFillCompact();
     fillCompact_withSharedEdits();
+    fillNoCompact();
 }
Index: tests/collections/string-overwrite-noshare.cfa
===================================================================
--- tests/collections/string-overwrite-noshare.cfa	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
+++ tests/collections/string-overwrite-noshare.cfa	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -0,0 +1,2 @@
+#define STRING_SHARING_OFF
+#include "string-overwrite.cfa"
Index: tests/collections/string-overwrite.cfa
===================================================================
--- tests/collections/string-overwrite.cfa	(revision 0fc447c38ee7b02d6cdb7bd08aef617ade5852c7)
+++ tests/collections/string-overwrite.cfa	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -1,3 +1,4 @@
 #include <containers/string.hfa>
+#include <string_sharectx.hfa>
 
 /*
@@ -11,5 +12,5 @@
 WE = witness end
 
-The dest does:
+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
@@ -24,4 +25,5 @@
 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
@@ -118,5 +120,4 @@
     struct { int ms; int me; int ws; int we; char *replaceWith; char *label; } cases[] = {
         { 12, 14, 10, 20, "xxxxx", "warmup" },
-//        { 12, 14, 12, 14, "xxxxx", ""       },  // the bug that got me into this test (should be a dup with case 6)
         { 10, 10, 10, 10, "=====", "1"      },
         { 10, 10, 10, 10, "=="   , ""       },
@@ -223,10 +224,4 @@
         { 12, 14, 10, 16, "="    , ""       },
         { 12, 14, 10, 16, ""     , ""       },
-/*
-        { , , , , "=====", "NN"     },
-        {  "=="   , ""       },
-        {  "="    , ""       },
-        {  ""     , ""       },
-*/
     };
     for ( i; sizeof(cases)/sizeof(cases[0]) ) {
@@ -238,13 +233,11 @@
 
 
-// void f( string & s, string & toEdit ) {
-
-//     sout | s | "|" | toEdit | "|";
-
-//     s(14, 16) = "-";
-//     sout | s | "|" | toEdit | "|";
-// }
-
 int main() {
+
+    #ifdef STRING_SHARING_OFF
+    string_sharectx c = { NO_SHARING };
+    #endif
+
+
     //          0         1         2
     //          01234567890123456789012345
Index: tests/zombies/string-perf/.gitignore
===================================================================
--- tests/zombies/string-perf/.gitignore	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
+++ tests/zombies/string-perf/.gitignore	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -0,0 +1,2 @@
+!Makefile
+perfexp-*
Index: tests/zombies/string-perf/Makefile
===================================================================
--- tests/zombies/string-perf/Makefile	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
+++ tests/zombies/string-perf/Makefile	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -0,0 +1,105 @@
+
+CFABUILD = ~/cfa2/build-perf
+LIBCFA = $(CFABUILD)/libcfa/*/src/.libs/libcfa.so
+
+CFA = $(CFABUILD)/driver/cfa
+PERFFLAGS_CFA = -nodebug -O2
+PERFFLAGS_CXX = -DNDEBUG -O2
+
+
+# function: convert to upper case
+define uc
+$(shell echo $(1) | tr  '[:lower:]' '[:upper:]')
+endef
+
+# function: project numbered element of filename named by hyphen-delimited tuple
+# (call hyphProj,q-w-e-r.txt,1) is Q
+define ucHyphProj
+$(call uc,$(word $(2),$(subst -, ,$(basename $(1)))))
+endef
+
+# function: cross two lists, adding hyphen delimiters
+# (call hyphCross,a b c,1 2) is a-1 a-2 b-1 b-2 c-1 c-2
+define hyphCross
+$(foreach x,$(1),$(foreach xs,$(2),$(x)-$(xs)))
+endef
+
+define hyphCross3
+$(call hyphCross,$(1),$(call hyphCross,$(2),$(3)))
+endef
+
+define hyphCross4
+$(call hyphCross,$(1),$(call hyphCross3,$(2),$(3),$(4)))
+endef
+
+define hyphCross5
+$(call hyphCross,$(1),$(call hyphCross4,$(2),$(3),$(4),$(5)))
+endef
+
+OPERATIONS=pta peq
+ALLOCS=reuse fresh
+CFA_APILEVELS=hl ll
+CFA_SHARINGS=share noshare
+PLATFORMS=cfa stl buhr94
+
+ifneq ($(filter cfa,$(PLATFORMS)),)
+	CFA_PERFPROGS=$(call hyphCross5,perfexp-cfa,$(CFA_APILEVELS),$(OPERATIONS),$(CFA_SHARINGS),$(ALLOCS))
+endif
+
+ifneq ($(filter stl,$(PLATFORMS)),)
+	STL_PERFPROGS=$(call hyphCross3,perfexp-stl,$(OPERATIONS),$(ALLOCS))
+endif
+
+ifneq ($(filter buhr94,$(PLATFORMS)),)
+	BUHR94_PERFPROGS=$(call hyphCross3,perfexp-buhr94,$(OPERATIONS),$(ALLOCS))
+endif
+
+PERFPROGS = $(CFA_PERFPROGS) $(STL_PERFPROGS) $(BUHR94_PERFPROGS)
+
+all : $(PERFPROGS)
+
+
+
+perfexp-cfa-%: CFA_APILEVEL=$(call ucHyphProj,$@,3)
+perfexp-cfa-%: OPERATION=$(call ucHyphProj,$@,4)
+perfexp-cfa-%: CFA_SHARING=$(call ucHyphProj,$@,5)
+perfexp-cfa-%: ALLOC=$(call ucHyphProj,$@,6)
+perfexp-cfa-%: prog.cfa $(LIBCFA)
+	$(CFA) $(PERFFLAGS_CFA) $< -o $@ -DIMPL_CFA_$(CFA_APILEVEL)_$(CFA_SHARING) -DOP_$(OPERATION) -DALLOC_$(ALLOC)
+
+perfexp-stl-%: OPERATION=$(call ucHyphProj,$@,3)
+perfexp-stl-%: ALLOC=$(call ucHyphProj,$@,4)
+perfexp-stl-%: prog.cfa
+	$(CXX) -xc++ $(PERFFLAGS_CXX) $< -o $@ -DIMPL_STL -DOP_$(OPERATION) -DALLOC_$(ALLOC)
+
+perfexp-buhr94-%.o: OPERATION=$(call ucHyphProj,$@,3)
+perfexp-buhr94-%.o: ALLOC=$(call ucHyphProj,$@,4)
+perfexp-buhr94-%.o: prog.cfa
+	$(CXX) -xc++ -c $(PERFFLAGS_CXX) $< -o $@ -DIMPL_BUHR94 -DOP_$(OPERATION) -DALLOC_$(ALLOC)
+
+buhr94-string.o:
+	$(CXX) -xc++ -c $(PERFFLAGS_CXX) ~/usys1/sm/string/StringSharing/src/string.cc -o $@
+
+buhr94-VbyteSM.o:
+	$(CXX) -xc++ -c $(PERFFLAGS_CXX) ~/usys1/sm/string/StringSharing/src/VbyteSM.cc -o $@
+
+perfexp-buhr94-% : perfexp-buhr94-%.o buhr94-string.o buhr94-VbyteSM.o
+	$(CXX) $(PERFFLAGS_CXX) $^ -o $@
+
+clean:
+	rm -f *.o perfexp*
+
+MEASURE = $(PERFPROGS)
+CORPORI = corpus-100-*-1.txt
+
+measurement: $(MEASURE)
+	tofile=measurement-`date '+%F--%H-%M-%S'`.csv ; \
+	echo $$tofile ; \
+	for prog in $(MEASURE) ; do \
+	    for corpus in $(CORPORI) ; do \
+			corpusbody=`cat $$corpus` ; \
+			printed=`./$$prog 100 10 $$corpusbody` ; \
+			echo $$prog,$$corpus,$$printed  >>  $$tofile ; \
+			echo $$prog,$$corpus,$$printed  ; \
+		done ; \
+	done
Index: tests/zombies/string-perf/corpus-100-1-1.txt
===================================================================
--- tests/zombies/string-perf/corpus-100-1-1.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
+++ tests/zombies/string-perf/corpus-100-1-1.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -0,0 +1,100 @@
+t
+w
+m
+k
+b
+n
+x
+n
+a
+s
+g
+f
+a
+g
+p
+l
+b
+l
+g
+f
+f
+i
+n
+q
+l
+t
+k
+p
+g
+p
+o
+j
+p
+e
+t
+i
+f
+h
+r
+k
+l
+w
+f
+j
+m
+o
+g
+s
+w
+t
+j
+u
+v
+n
+g
+s
+h
+r
+g
+g
+g
+t
+v
+k
+o
+m
+j
+r
+m
+x
+j
+o
+m
+i
+n
+n
+k
+i
+x
+c
+b
+o
+v
+v
+q
+g
+r
+t
+d
+y
+t
+m
+v
+o
+t
+i
+h
+i
+h
+r
Index: tests/zombies/string-perf/corpus-100-10-1.txt
===================================================================
--- tests/zombies/string-perf/corpus-100-10-1.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
+++ tests/zombies/string-perf/corpus-100-10-1.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -0,0 +1,100 @@
+arffxh
+qx
+fbfnvxvw
+ktcfgonnoklj
+eqqe
+ywvjewor
+pqrqdnuj
+kyjbjvmwcdpibqfyam
+rgshymadcvmxilijw
+vvkb
+secaddobw
+veuk
+ama
+k
+autadrvnukiymlerahoxduvnava
+ln
+ni
+nme
+cywlbjwfe
+nsxqqthqrj
+dwk
+iwhw
+t
+cskdfjljlyej
+ufynwlldivusu
+pxbpdtcgy
+tkasrjlmqmdnxosjmpckusivilr
+utboebivmv
+diotjfms
+dueapnvabpnvjo
+osv
+ftal
+ofnvtgqyewytkwwmnkkwbxnvtdcndpsuwisqrj
+vhrrtpoifbtefruboafeduwargtjxfcvovplnhtu
+pankwp
+wufcsfdklyvlga
+vwyjmgfirxkfihwl
+uqinvnajmwutygrxgbloivgggmqplcvitevps
+chvydugutmxhbjdipjwhyk
+utdbrvtq
+e
+whmdfgrfpv
+sgfedmfpxaje
+ecawaemylyfqhy
+wunr
+svgh
+widimg
+o
+mqk
+ryxyphyo
+vdxaxtggwfoaobidrrpieqcdqctxbkeyncymxg
+unlweogi
+xaqctsgku
+lx
+pxduwrufoqtanxo
+iutllyfghrcld
+avxfsx
+nfngynu
+es
+bpxo
+fv
+xxldxl
+ytryu
+ejogyligfuhutw
+bsjyqwdqier
+ysahx
+vgmkq
+pldm
+axjsjk
+gpequwv
+pxdplbxxnot
+dwpm
+px
+yjffy
+wviutbsyqgd
+eqixunwm
+vdyneis
+kfjin
+doyci
+halykmv
+jkagnbvu
+rfywojm
+mctrmbyo
+ayyvxlh
+rwe
+rqhyrgpbtkqx
+ikhjyw
+axkbjrbbrhtlx
+lpkbtgokgwushetestceumxy
+pg
+chppyassihdqfxjmfdsxy
+cujbvcscnwjfmlhiepr
+gygrn
+ugmueqrprptnrkkepap
+ivp
+eycnqpboypjdhdub
+rqm
+cst
+ktohkqnjsd
+lhqkwcpgfmkaebpifi
Index: tests/zombies/string-perf/corpus-100-2-1.txt
===================================================================
--- tests/zombies/string-perf/corpus-100-2-1.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
+++ tests/zombies/string-perf/corpus-100-2-1.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -0,0 +1,100 @@
+q
+yc
+by
+e
+wt
+od
+ev
+v
+c
+gjhk
+xla
+t
+u
+e
+q
+v
+e
+c
+h
+e
+dt
+icsppbpddi
+ge
+lbrv
+hbil
+ssq
+y
+g
+p
+yf
+p
+j
+i
+ejb
+baciblv
+g
+d
+qpo
+f
+b
+vqvfr
+v
+n
+cq
+e
+cr
+qx
+ve
+luht
+j
+hcc
+vil
+xmw
+m
+r
+x
+f
+g
+c
+pwv
+k
+p
+mu
+k
+x
+eke
+winogdv
+l
+ja
+i
+btgs
+u
+b
+t
+l
+l
+s
+biajn
+paxy
+piy
+e
+kud
+vl
+w
+t
+q
+tt
+vd
+us
+u
+mldo
+h
+oc
+paol
+oihhxe
+x
+gkwby
+v
+g
+b
Index: tests/zombies/string-perf/corpus-100-20-1.txt
===================================================================
--- tests/zombies/string-perf/corpus-100-20-1.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
+++ tests/zombies/string-perf/corpus-100-20-1.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -0,0 +1,100 @@
+wlgfygaqsdfmqvcygkiyaasjonymuarrnaamiadd
+krvjuwrhgqjgmvwaujuudplgpxo
+euwomuajssryjd
+v
+ey
+nvtslfydfquj
+tbxpbiitchgfoehs
+fiaydngdrmv
+xhjyhbbrjwtsdcjilensmnupebuvpqkoavniwqaiowbt
+mcmqqffgcxkeuivmvkoryypr
+xgycbaofoixvphyntfjdbxyomspmihojqpnrreyimxgdhhsbmcgqcffpyuejc
+ssmgmel
+oamuftdywrdekgjpxkmewrbpmnyatmoiodduyitvdyanhmefwsltkmmxcnavaoeotklsuhqxhrmoeswdlixwxmuaa
+wcndshpfclmsltkalqsiuhqueohbrjxollreukjwvyr
+sfkevdoskgnqwwtoitfthabekmbilvrhbc
+yib
+ujgoigiaofhlmhorrbuap
+uwtw
+thnmdyurkdckuhtg
+cuovxj
+pdtmyqasynhenfvxkxkfigldiitfjdgyia
+isodtclxrsvrdwejflwktiebrjhqsjfddvgyytxs
+v
+sspcxd
+ixjobbylutwcwayfaacauqvgjrynpcpbcy
+gdqtxmqcjtbrvdtvykthwlikenchpeyxhs
+hfljrfnldsfbrruaqjiepxgyokaotujbbwnuebghtniohfqyqbfialh
+ykfufqyinmdtplblylcj
+skkwpvwdfpepuavobeepkyhvc
+v
+xhksrup
+sokyerocrmq
+twkevraymxpkfagwwvgqltrplirfvkari
+vg
+vhqwwecykcygirtejmprgup
+whcjdi
+cqhbpl
+rxhqgsidwrpplvmcpklrvrdktvtwnhcffkvnfgqexgtmfhou
+cpptscnoxmcfpkm
+gbhnrlnyiagpqbltqdnlgeceqfmgryixarnugevogcgxdrtwujidnlkhswpkvbkysbtyfpnlr
+lwnfvlphofsyonvfaugmtbppdufsjypwxdduoucgcwfrmew
+yfbuirklorfaquxqadnrxpxc
+ftdjsriav
+jpnuefahxwf
+xifrixpkouhshakpdivmx
+j
+rmmrjtljcrbmrsygqgyxjmpmulbtx
+yrwnjhhxslpwxjpwpiepgpeycykduintaljmuqkpccmalfadng
+w
+yvayiftrsqtgaidt
+tvyiymnyqeh
+ddlbdkjigddwamairtgnpfwqsk
+l
+wwtciuhufpckvbkkbvcucqnjneeawp
+vpnb
+jivqbadwdohfmlcocrarwhuvwmroc
+p
+e
+efpicsylalwdccuevtlqrlfm
+ihpvlfdqunuomi
+aite
+rkgnwagi
+sknadmmipfedburjlrrixe
+inphnvrso
+jriv
+qllwomtgygasoaxqilgsbdkttpfnxbtrogqdullttnnknnbybj
+cmexjuew
+frowagcutorneh
+sudtvmlxcrxlmckkkeyhehjc
+atqfbqxxttvhft
+wrwmwjyhoxougayjbsbgvtgtqapahllggkufttmku
+ibdhmgdnoy
+wvbwndgcopkykpuheich
+fmarvfikhuifvhsyqwpghqsylcdvgmoncri
+wqkgns
+jdhkteccoswpgavfgitumnd
+nvxtjsguvphrtjtketbmtwrchoyucehpchmnbuiykrrgdnrjhuw
+toibdhxgoixq
+mfs
+psrkmbnasxkpwn
+lxmpglxwvxnnl
+hsncnxoon
+jnbbkrkwpwoxkmuiklwxigtvihvyxkpjarkllwkbvychnyramq
+vwsthcqi
+dyldsxoeuyhqajanjsqvjrtjkosofcqibclvadauejnftoufj
+dufaepoagvcwgfbtbbwdxemolidgpmuvjavoskqyisyoaakde
+geousaexitmdpwgnnbxeciwbwyeicisimjfijjgrgtxxqgoehmilxhpugtfkeausjabumipucnuutjbdyjqwsgtbcalgcgaoiblulbppolkkulntwfqpnlsqnewrm
+ivbuqmvjdnupxreoobvftlsmcitcdgbleeixr
+h
+ueouxsl
+uhuqtndxyyacgenmiwkce
+ybaqvyjiler
+unwbmxaoaispvcmigsfgtfysgidsnubklalxxooawiqumfgsylbusapa
+ssyqvlcy
+cyoqcnbslpxrjydmwvnmvyiqxypldqlfpaxrq
+mcrntdoyqlwgbvflo
+kgqpwfwpf
+jxywatkvwbwnpuvqsbchioocgnhddoannakptwmsxjjngfgyhkjrbathnbkrsnhgprvjqkequnf
+tnfdyoucqrkeuwxnkftayslpdqhxgoeacjdd
+biossun
Index: tests/zombies/string-perf/corpus-100-5-1.txt
===================================================================
--- tests/zombies/string-perf/corpus-100-5-1.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
+++ tests/zombies/string-perf/corpus-100-5-1.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -0,0 +1,100 @@
+hsiq
+erkpoqlew
+tpgsfigwyn
+tbpuf
+nns
+ukakbqxhnob
+wvlhckh
+wdvoyc
+orjemthy
+xweonftkbh
+gs
+yrfujgy
+xr
+e
+fl
+c
+d
+drnwcqhwwc
+xv
+tfp
+hnmsutaiaew
+maw
+aa
+h
+qlbphi
+nx
+wo
+qlpqtpv
+uitslvsf
+tvqunydboe
+lugegvvcntvic
+bpo
+uuqtnl
+mrldxvrs
+v
+atfn
+cxswa
+nxg
+oaydjnu
+rusjnwh
+ycvo
+an
+wptlnaxdcwilldl
+aeqpe
+gfaeu
+fidc
+y
+ny
+qb
+ypbebgg
+w
+nxctx
+o
+oywsyvj
+xa
+bnh
+povxugvtt
+v
+tfgnvfm
+gkbtib
+mqlf
+achxi
+reb
+uwxbmtjyj
+mklwn
+jf
+p
+ctwacerif
+d
+gfrcqtmggysd
+i
+u
+fknbkpfo
+nw
+rcb
+vd
+pr
+vtqahcpemwqax
+qfsbsrvmvwlrcdiw
+gq
+iawxg
+w
+mwbf
+vivpeil
+wficp
+gwvc
+xbgelfbbdeif
+rd
+vofcnlkpdpwcnb
+ncs
+qxur
+acjctousdau
+nfjr
+gvmj
+al
+reamxdobo
+ue
+njoibdpkw
+ssbccbpduufkslyvasr
+hfq
Index: tests/zombies/string-perf/corpus-5-20-1.txt
===================================================================
--- tests/zombies/string-perf/corpus-5-20-1.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
+++ tests/zombies/string-perf/corpus-5-20-1.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -0,0 +1,5 @@
+xtprjlkvxoha
+fwjvjxlhetotwuvrrkplahwm
+tmjdpckmmgwmtgqpwnpsjhktwyvhvkbpakuppfccoboijhbhu
+agxkcwlyeilialuvbkbgopjfbtpcbmsbtsnxpaywklhk
+cibpmhges
Index: tests/zombies/string-perf/corpus-5-20-2.txt
===================================================================
--- tests/zombies/string-perf/corpus-5-20-2.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
+++ tests/zombies/string-perf/corpus-5-20-2.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -0,0 +1,5 @@
+cyvgqodbfmnkefjurrjmfloimkldtmcxlafcqkfwxuhe
+sbulkjsvydklonfb
+dotktl
+ykvwtaymbvalgsjfwwqnkxrfdgb
+amma
Index: tests/zombies/string-perf/corpus-5-20-3.txt
===================================================================
--- tests/zombies/string-perf/corpus-5-20-3.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
+++ tests/zombies/string-perf/corpus-5-20-3.txt	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -0,0 +1,5 @@
+otado
+drymnkbfofeqkjbythdtprmnjbikhwfmre
+fpdmgiqw
+a
+twhxqwrenbhvnqusgma
Index: tests/zombies/string-perf/make-corpus.cfa
===================================================================
--- tests/zombies/string-perf/make-corpus.cfa	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
+++ tests/zombies/string-perf/make-corpus.cfa	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -0,0 +1,47 @@
+#include <stdlib.hfa>
+#include <math.h>
+#include <limits.h>
+#include <unistd.h>
+
+// generate random draws from a geometric distribution of the given mean
+// https://math.stackexchange.com/questions/485448/prove-the-way-to-generate-geometrically-distributed-random-numbers
+static double denom;
+static void initialize(int mean) {
+    srand(getpid());
+    double p = 1.0 / (double) mean;
+    denom = log(1-p);
+}
+static int nextGeoRand() {
+    // ret = ⌊ln(U)/ln(1−p)⌋ where U ~ U(0, 1)
+    double U = (double)rand() / (double)INT_MAX;
+    return 1 + (int) (log(U) / denom);
+}
+
+// write a randomly generated alphabetic string whose length is drawn from above distribution
+static void emit1() {
+    int lim = nextGeoRand();
+    // printf("==%d\n", lim);
+    for (i; lim) {
+        char emit = 'a' + (rand() % ('z'-'a'));
+        printf("%c", emit);
+    }
+    printf("\n");
+}
+
+// usage: ./make-corpus toGen mean
+int main(int argc, char ** argv) {
+    assert(argc == 3);
+
+    int toGen = atoi(argv[1]);
+    assert(toGen > 0);
+    assert(toGen < 1000000);
+
+    int mean = atoi(argv[2]);
+    assert(mean > 0);
+    assert(mean < 1000);
+
+    initialize(mean);
+    for( i; toGen ) {
+        emit1();
+    }
+}
Index: tests/zombies/string-perf/prog.cfa
===================================================================
--- tests/zombies/string-perf/prog.cfa	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
+++ tests/zombies/string-perf/prog.cfa	(revision 12c1eeff7e4358f66eb036d8fd54ae6257c2472c)
@@ -0,0 +1,160 @@
+
+#if defined IMPL_STL
+  #include <string>
+  #include <iostream>
+  #include <cstdio>
+  using namespace std;
+  #define IMPL_CXX
+
+#elif defined IMPL_CFA_HL_SHARE
+  #define IMPL_CFA_HL
+  #define IMPL_CFA
+
+#elif defined IMPL_CFA_LL_SHARE
+  #define IMPL_CFA_LL
+  #define IMPL_CFA
+
+#elif defined IMPL_CFA_HL_NOSHARE
+  #define IMPL_CFA_HL
+  #define CFA_NOSHARE
+  #define IMPL_CFA
+
+#elif defined IMPL_CFA_LL_NOSHARE
+  #define IMPL_CFA_LL
+  #define CFA_NOSHARE
+  #define IMPL_CFA
+
+#elif defined IMPL_BUHR94
+  #include <iostream>
+  #include <cstdio>
+  #include "/u0/mlbrooks/usys1/sm/string/StringSharing/src/string.h"
+  #define IMPL_CXX
+
+#else
+  #error Bad IMPL_
+#endif
+
+
+#if defined IMPL_CFA_HL
+  #include <string.hfa>
+#elif defined IMPL_CFA_LL
+  #include <string_res.hfa>
+#endif
+
+#if defined CFA_NOSHARE
+  #include <string_sharectx.hfa>
+  #define STRING_SHARING_CONTROL \
+    string_sharectx c = { NO_SHARING };
+#else 
+  #define STRING_SHARING_CONTROL
+#endif
+
+#if defined IMPL_CFA
+  #include <math.hfa>
+#elif defined IMPL_CXX
+  #include <algorithm>
+  using std::min;
+#endif
+
+#include <time.h>
+#include <stdlib.h> // atoi
+#include <string.h> // strlen, only during setup
+
+#if defined IMPL_STL || defined IMPL_BUHR94
+    #define PRINT(s) std::cout << s << std::endl
+#elif defined IMPL_CFA_HL || defined IMPL_CFA_LL
+    #define PRINT(s) sout | s;
+#else
+    #error Unhandled print case
+#endif
+
+double meanLen(int N, char ** strings) {
+    int totalLen = 0;
+    for (int i = 0 ; i < N; i ++) {
+        totalLen += strlen(strings[i]);
+    }
+    return (double)totalLen / (double)N;
+}
+
+volatile int checkthis = 0;
+#define MAYBE( op ) if (checkthis) { op; }
+
+int main( int argc, char ** argv ) {
+
+    STRING_SHARING_CONTROL
+
+
+    const char * usage_args = "ConcatsPerReset ExecTimeSecs Corpus...";
+    const int static_arg_posns = 3;
+
+    int concatsPerReset = -1, execTimeSecs = -1;
+
+    switch (min(argc, static_arg_posns)) {
+      case 3: execTimeSecs = atoi(argv[2]);
+      case 2: concatsPerReset = atoi(argv[1]);
+    }
+
+    int corpuslen = argc - static_arg_posns;
+    char ** corpus = argv + static_arg_posns;
+
+    if (execTimeSecs < 1 || concatsPerReset < 1 || corpuslen < 1) {
+      printf("usage: %s %s\n", argv[0], usage_args);
+      printf("output:\nconcatsPerReset,corpusItemCount,corpusMeanLenChars,concatDoneActualCount,execTimeActualSec\n");
+      exit(1);
+    }
+
+    double meanCorpusLen = meanLen(corpuslen, corpus);
+
+    clock_t start, end_target, end_actual;
+
+    #if defined IMPL_CFA_LL && defined OP_PTA
+        string_res pta_ll_temp;
+    #endif
+
+    #if defined IMPL_CFA_LL
+      #define DECLS \
+        string_res initval = "starter"; \
+        string_res accum = { initval, COPY_VALUE };
+    #else
+      #define DECLS \
+        string initval = "starter"; \
+        string accum = initval;
+    #endif
+
+    #if defined ALLOC_REUSE
+      DECLS
+      #define RESET \
+        accum = initval;
+    #elif defined ALLOC_FRESH
+      #define RESET \
+        DECLS
+    #else
+      #error bad alloc
+    #endif
+
+    start = clock();
+    end_target = start + CLOCKS_PER_SEC * execTimeSecs;
+    volatile unsigned int t = 0;
+    for ( ; t % 100 != 0 || clock() < end_target ; t += 1 ) {
+            RESET
+            for ( volatile unsigned int i = 0; i < concatsPerReset; i += 1 ) {
+              MAYBE( PRINT(accum) )
+              char *toAppend = corpus[i % corpuslen]; // ? corpus[rand() % corpuslen]
+              #if defined OP_PTA && defined IMPL_CFA_LL
+                 pta_ll_temp = accum;
+                 pta_ll_temp += toAppend;
+                 accum = pta_ll_temp;
+              #elif defined OP_PTA
+                 accum = accum + toAppend;
+              #elif defined OP_PEQ
+                 accum += toAppend;
+              #endif
+            }
+    }
+    end_actual = clock();
+    unsigned int concatsDone = t * concatsPerReset;
+    double elapsed = ((double) (end_actual - start)) / CLOCKS_PER_SEC;
+    printf("%d,%d,%f,%d,%f\n", concatsPerReset, corpuslen, meanCorpusLen, concatsDone, elapsed);
+
+    return 0;
+}
