code: func (d *dataEncoder) optimiseDataModes() error {
  	for i := 0; i < len(d.actual); {
  		mode := d.actual[i].dataMode
  		numChars := len(d.actual[i].data)
  
  		j := i + 1
  		for j < len(d.actual) {
  			nextNumChars := len(d.actual[j].data)
  			nextMode := d.actual[j].dataMode
  
  			if nextMode > mode {
  				break
  			}
  
  			coalescedLength, err := d.encodedLength(mode, numChars+nextNumChars)
  
  			if err != nil {
  				return err
  			}
  
  			seperateLength1, err := d.encodedLength(mode, numChars)
  
  			if err != nil {
  				return err
  			}
  
  			seperateLength2, err := d.encodedLength(nextMode, nextNumChars)
  
  			if err != nil {
  				return err
  			}
  
  			if coalescedLength < seperateLength1+seperateLength2 {
  				j++
  				numChars += nextNumChars
  			} else {
  				break
  			}
  		}
  
  		optimised := segment{dataMode: mode,
  			data: make([]byte, 0, numChars)}
  
  		for k := i; k < j; k++ {
  			optimised.data = append(optimised.data, d.actual[k].data...)
  		}
  
  		d.optimised = append(d.optimised, optimised)
  
  		i = j
  	}
  
  	return nil
  }
docs: // optimiseDataModes optimises the list of segments to reduce the overall output
  // encoded data length.
  //
  // The algorithm coalesces adjacent segments. segments are only coalesced when
  // the Data Modes are compatible, and when the coalesced segment has a shorter
  // encoded length than separate segments.
  //
  // Multiple segments may be coalesced. For example a string of alternating
  // alphanumeric/numeric segments ANANANANA can be optimised to just A.