/*
* Copyright 2015 Liu Huanting.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package fm.liu.timo.merger;
import java.util.ArrayDeque;
import java.util.Collections;
import fm.liu.timo.mysql.packet.RowDataPacket;
/**
* @author Liu Huanting 2015年6月4日
*/
public class Sorter {
private final MergeInfo[] mergeInfo;
private ArrayDeque<RowDataPacket> rows;
private RowDataPacket[] result;
private RowDataPacket[] temp;
private int p;
private int pL;
private int pR;
public Sorter(MergeInfo[] mergeInfo) {
this.mergeInfo = mergeInfo;
}
public MergeInfo[] getMergeInfo() {
return mergeInfo;
}
public void offer(ArrayDeque<RowDataPacket> rows) {
this.rows = rows;
}
public ArrayDeque<RowDataPacket> getResult() {
sort(rows.toArray(new RowDataPacket[rows.size()]));
if (result != null) {
Collections.addAll(rows, result);
}
return rows;
}
private RowDataPacket[] sort(RowDataPacket[] rows) {
this.rows.clear();
result = rows;
if (rows == null || rows.length < 2 || this.mergeInfo == null
|| this.mergeInfo.length < 1) {
return rows;
}
merge(0, rows.length - 1);
return result;
}
private void merge(int l, int r) {
if (l < r) {
int mid = (l + r) / 2;
merge(l, mid);
merge(mid + 1, r);
merge(l, mid, r);
}
}
private void merge(int l, int mid, int r) {
temp = new RowDataPacket[(r - l) + 1];
p = 0;
pL = l;
pR = mid + 1;
while (pL <= mid || pR <= r) {
if (pL == mid + 1) {
while (pR <= r) {
temp[p++] = result[pR++];
}
} else if (pR == r + 1) {
while (pL <= mid) {
temp[p++] = result[pL++];
}
} else {
compare(0);
}
}
for (pL = l, pR = 0; pL <= r; pL++, pR++) {
result[pL] = temp[pR];
}
}
private void compare(int index) {
if (index == this.mergeInfo.length) {
if (this.mergeInfo[index - 1].type == MergeType.ASC) {
temp[p++] = result[pL++];
} else {
temp[p++] = result[pR++];
}
return;
}
ColumnInfo info = this.mergeInfo[index].columnInfo;
byte[] left = result[pL].fieldValues.get(info.index);
byte[] right = result[pR].fieldValues.get(info.index);
int r = Comparer.compareColumn(left, right, info.type);
if (r <= 0) {
if (r < 0) {
if (this.mergeInfo[index].type == MergeType.ASC) {
temp[p++] = result[pL++];
} else {
temp[p++] = result[pR++];
}
} else {
compare(index + 1);
}
} else {
if (this.mergeInfo[index].type == MergeType.ASC) {
temp[p++] = result[pR++];
} else {
temp[p++] = result[pL++];
}
}
}
}