Optimize longestMatch delimiter algorithm

The longestMatch function is called everytime after delimiters are found. On
some file types, this function was a noticable hotspot.

Although not very likely, in the worst case, the current longestMatch algorithm
could go over the entire matches list 3 times: Once for finding the location of
earliest match, once for remove any matches that start later than that
location, and once for finding longest length of those that remain. In addition,
the use of various scala functions will cause new lists to be allocated,
causing slower performance.

This modifies the algorithm to only go over the matches list once, while
keeping track of the first longest match that it has seen. Additionally, all
functional code is replace with iterative code to be more performant. Lastly,
replace the Seq with an ArrayBuffer so that we are guaranteed constant append
and constant random access on the matches sequence.

This also adds an early return in the case where there is only one match, which
is probably the most likely case.

DFDL-992
3 files changed