public static PredictionContext MergeArrays(
ArrayPredictionContext a,
ArrayPredictionContext b,
bool rootIsWildcard,
MergeCache mergeCache)
{
if (mergeCache != null)
{
PredictionContext previous = mergeCache.Get(a, b);
if (previous != null)
{
return(previous);
}
previous = mergeCache.Get(b, a);
if (previous != null)
{
return(previous);
}
}
// merge sorted payloads a + b => M
int i = 0; // walks a
int j = 0; // walks b
int k = 0; // walks target M array
int[] mergedReturnStates =
new int[a.returnStates.Length + b.returnStates.Length];
PredictionContext[] mergedParents =
new PredictionContext[a.returnStates.Length + b.returnStates.Length];
// walk and merge to yield mergedParents, mergedReturnStates
while (i < a.returnStates.Length && j < b.returnStates.Length)
{
PredictionContext a_parent = a.parents[i];
PredictionContext b_parent = b.parents[j];
if (a.returnStates[i] == b.returnStates[j])
{
// same payload (stack tops are equal), must yield merged singleton
int payload = a.returnStates[i];
// $+$ = $
bool both_dollar = payload == EMPTY_RETURN_STATE &&
a_parent == null && b_parent == null;
bool ax_ax = (a_parent != null && b_parent != null) &&
a_parent.Equals(b_parent); // ax+ax -> ax
if (both_dollar || ax_ax)
{
mergedParents[k] = a_parent; // choose left
mergedReturnStates[k] = payload;
}
else // ax+ay -> a'[x,y]
{
PredictionContext mergedParent =
Merge(a_parent, b_parent, rootIsWildcard, mergeCache);
mergedParents[k] = mergedParent;
mergedReturnStates[k] = payload;
}
i++; // hop over left one as usual
j++; // but also skip one in right side since we merge
}
else if (a.returnStates[i] < b.returnStates[j])
{ // copy a[i] to M
mergedParents[k] = a_parent;
mergedReturnStates[k] = a.returnStates[i];
i++;
}
else // b > a, copy b[j] to M
{
mergedParents[k] = b_parent;
mergedReturnStates[k] = b.returnStates[j];
j++;
}
k++;
}
// copy over any payloads remaining in either array
if (i < a.returnStates.Length)
{
for (int p = i; p < a.returnStates.Length; p++)
{
mergedParents[k] = a.parents[p];
mergedReturnStates[k] = a.returnStates[p];
k++;
}
}
else
{
for (int p = j; p < b.returnStates.Length; p++)
{
mergedParents[k] = b.parents[p];
mergedReturnStates[k] = b.returnStates[p];
k++;
}
}
// trim merged if we combined a few that had same stack tops
if (k < mergedParents.Length)
{ // write index < last position; trim
if (k == 1)
{ // for just one merged element, return singleton top
PredictionContext a_ = SingletonPredictionContext.Create(mergedParents[0], mergedReturnStates[0]);
if (mergeCache != null)
{
mergeCache.Put(a, b, a_);
}
return(a_);
}
mergedParents = Arrays.CopyOf(mergedParents, k);
mergedReturnStates = Arrays.CopyOf(mergedReturnStates, k);
}
PredictionContext M = new ArrayPredictionContext(mergedParents, mergedReturnStates);
// if we created same array as a or b, return that instead
// TODO: track whether this is possible above during merge sort for speed
if (M.Equals(a))
{
if (mergeCache != null)
{
mergeCache.Put(a, b, a);
}
return(a);
}
if (M.Equals(b))
{
if (mergeCache != null)
{
mergeCache.Put(a, b, b);
}
return(b);
}
CombineCommonParents(mergedParents);
if (mergeCache != null)
{
mergeCache.Put(a, b, M);
}
return(M);
}