123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118open!Core_kernel(* Invariants:
- [Append (x, y)] must have both [x] and [y] non-empty (complexity analysis
of [to_string] relies on it).
- Overall length is less than [String.max_length] (so [to_string] can work, at least in
principle). *)moduleTree=structtypet=|Baseofstring|Appendoft*tletrecunrolltaux=matchtwith|Basex->x,aux|Append(x,y)->unrollx(y::aux);;letto_char_sequencet=letf(((x,xs)asxxs),xpos):_Sequence.Step.t=ifxpos<String.lengthxthenYield(x.[xpos],(xxs,xpos+1))else(matchxswith|[]->Done|y::ys->Skip(unrollyys,0))inSequence.unfold_step~init:(unrollt[],0)~f;;leteither_is_prefix_of_othert1t2=Sequence.for_all(Sequence.zip(to_char_sequencet1)(to_char_sequencet2))~f:(fun(x,y)->Char.equalxy);;endtypet={len:int;tree:Tree.t}letof_strings={len=String.lengths;tree=Bases}letempty=of_string""letlengtht=t.lenletis_emptyt=lengtht=0letto_string{len;tree}=matchtreewith|Bases->s|Append(s1,s2)->letbuf=Bytes.createlenin(* [todo] avoids stack overflow (some usage patterns result in highly unbalanced
trees, so the naive recursive approach doesn't work) *)letrecgotodostart:Tree.t->_=function|Bases->Bytes.From_string.blit~src:s~src_pos:0~dst:buf~dst_pos:start~len:(String.lengths);letstart=start+String.lengthsin(matchtodowith|[]->assert(start=len)|x::xs->goxsstartx)|Append(s1,s2)->go(s2::todo)starts1ingo[s2]0s1;Bytes.unsafe_to_string~no_mutation_while_string_reachable:buf;;letto_char_sequencet=Tree.to_char_sequencet.tree(* We could loosen the [String.max_length] length restriction, since people can still read
an arbitrary-length sequence out of [to_char_sequence]. I choose not to do this because
I think [to_string] will be the more popular choice, and I'd prefer for it not to be
able to raise. If someone else chooses differently, we'll likely still want to check
against [Int.max_value]. *)let(^)ab=ifis_emptyathenbelseifis_emptybthenaelseifString.max_length-a.len<b.lenthenError.raise_s[%message"Rope.(a ^ b) would be longer than String.max_length"(lengtha:int)(lengthb:int)(String.max_length:int)]else{len=a.len+b.len;tree=Append(a.tree,b.tree)};;letconcat?(sep=empty)ts=List.reducets~f:(funxy->x^sep^y)|>Option.value~default:empty;;letconcat_array?(sep=empty)ts=Array.reducets~f:(funxy->x^sep^y)|>Option.value~default:empty;;letrecadd_to_buffer_internalbuffertodo:Tree.t->_=function|Append(s1,s2)->add_to_buffer_internalbuffer(s2::todo)s1|Bases->Buffer.add_stringbuffers;(matchtodowith|[]->()|x::xs->add_to_buffer_internalbufferxsx);;letadd_to_buffer{len=_;tree}buffer=add_to_buffer_internalbuffer[]treeletis_prefixt~prefix=prefix.len<=t.len&&Tree.either_is_prefix_of_othert.treeprefix.tree;;