Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,19 @@ public CobolDataStorage() {
this.data = null;
}

public void setDataRefAndIndex(CobolDataStorage data, int index) {
this.data = data.data;
this.index = index;
}

public int getIndex() {
return this.index;
}

public void setIndex(int index) {
this.index = index;
}

public byte[] getRefOfData() {
return this.data;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import jp.osscons.opensourcecobol.libcobj.common.CobolUtil;
import jp.osscons.opensourcecobol.libcobj.data.AbstractCobolField;
import jp.osscons.opensourcecobol.libcobj.data.CobolDataStorage;
import jp.osscons.opensourcecobol.libcobj.data.CobolFieldAttribute;
import jp.osscons.opensourcecobol.libcobj.data.CobolFieldFactory;
import jp.osscons.opensourcecobol.libcobj.exceptions.CobolStopRunException;

Expand Down Expand Up @@ -903,4 +904,177 @@ public static void performReturn(CobolFile f) {
return;
}
}

/* Table sort */
private static int sortNKeys;
private static CobolFileKey[] sortKeys;
private static CobolDataStorage sortCollate;
private static CobolDataStorage pivotStorage = new CobolDataStorage();
private static CobolDataStorage leftStorage = new CobolDataStorage();
private static CobolDataStorage rightStorage = new CobolDataStorage();
private static CobolDataStorage cmpStorage1 = new CobolDataStorage();
private static CobolDataStorage cmpStorage2 = new CobolDataStorage();
private static CobolDataStorage copyBuffer = null;
private static CobolDataStorage tmpRecord = new CobolDataStorage();
private static int copyBufferSizeMax = 0;
private static int[] sortBuffer = null;
private static AbstractCobolField cmpField1 =
CobolFieldFactory.makeCobolField(
0,
cmpStorage1,
new CobolFieldAttribute(CobolFieldAttribute.COB_TYPE_ALPHANUMERIC, 0, 0, 0, null));
private static AbstractCobolField cmpField2 =
CobolFieldFactory.makeCobolField(
0,
cmpStorage2,
new CobolFieldAttribute(CobolFieldAttribute.COB_TYPE_ALPHANUMERIC, 0, 0, 0, null));

public static void sortTableInit(int nkeys, int collatingSequence) {
sortTableInit(nkeys, null);
}

public static void sortTableInit(int nkeys, CobolDataStorage collatingSequence) {
sortNKeys = 0;
if (sortKeys == null || sortKeys.length < nkeys) {
sortKeys = new CobolFileKey[nkeys];
}
if (collatingSequence != null) {
sortCollate = collatingSequence;
} else {
sortCollate = CobolModule.getCurrentModule().collating_sequence;
}
}

public static void sortTableInitKey(int flag, AbstractCobolField field, int offset) {
if (sortKeys[sortNKeys] == null) {
sortKeys[sortNKeys] = new CobolFileKey();
}
sortKeys[sortNKeys].setFlag(flag);
sortKeys[sortNKeys].setField(
CobolFieldFactory.makeCobolField(
field.getSize(), (CobolDataStorage) null, field.getAttribute()));
sortKeys[sortNKeys].setOffset(offset);
sortNKeys++;
}

public static void sortTable(AbstractCobolField f, int n) {
int recordSize = f.getSize();
if (sortBuffer == null || sortBuffer.length < n) {
sortBuffer = new int[n];
}
for (int i = 0; i < n; ++i) {
sortBuffer[i] = i;
}
CobolDataStorage baseStorage = f.getDataStorage();
int baseStorageBaseIndex = baseStorage.getIndex();
indexQuickSort(f.getDataStorage(), 0, n, recordSize);

int copyBufferSize = n * f.getSize();
if (copyBuffer == null || copyBufferSizeMax < copyBufferSize) {
copyBuffer = new CobolDataStorage(copyBufferSize);
copyBufferSizeMax = copyBufferSize;
}

for (int i = 0; i < n; ++i, copyBuffer.addIndex(recordSize)) {
tmpRecord.setDataRefAndIndex(baseStorage, baseStorageBaseIndex + recordSize * sortBuffer[i]);
copyBuffer.memcpy(tmpRecord, recordSize);
}
copyBuffer.setIndex(0);
baseStorage.memcpy(copyBuffer, copyBufferSize);
}

private static void indexQuickSort(
CobolDataStorage base, int mostLeft, int mostRight, int recordSize) {

if (mostRight - mostLeft <= 1) {
return;
}

int pivot = (mostRight + mostLeft) / 2;
int left = mostLeft, right = mostRight - 1;

while (true) {
pivotStorage.setDataRefAndIndex(base, base.getIndex() + sortBuffer[pivot] * recordSize);
boolean elementBiggerThanPivot = false;
for (; left < pivot; ++left) {
leftStorage.setDataRefAndIndex(base, base.getIndex() + sortBuffer[left] * recordSize);
if (compareStorageForSort(leftStorage, pivotStorage) > 0) {
elementBiggerThanPivot = true;
break;
}
}
boolean elementSmallerThanPivot = false;
for (; right > pivot; --right) {
rightStorage.setDataRefAndIndex(base, base.getIndex() + sortBuffer[right] * recordSize);
if (compareStorageForSort(pivotStorage, rightStorage) > 0) {
elementSmallerThanPivot = true;
break;
}
}
if (elementBiggerThanPivot && elementSmallerThanPivot) {
swap2Indecies(left, right);
++left;
--right;
} else if (elementBiggerThanPivot && !elementSmallerThanPivot) {
if (left + 1 == pivot) {
swap2Indecies(left, pivot);
} else {
rotate3Indecies(pivot, pivot - 1, left);
}
--pivot;
} else if (!elementBiggerThanPivot && elementSmallerThanPivot) {
if (right - 1 == pivot) {
swap2Indecies(pivot, right);
} else {
rotate3Indecies(pivot, pivot + 1, right);
}
++pivot;
} else {
break;
}
}
indexQuickSort(base, mostLeft, pivot, recordSize);
indexQuickSort(base, pivot + 1, mostRight, recordSize);
}

private static int compareStorageForSort(CobolDataStorage s1, CobolDataStorage s2) {
for (int i = 0; i < sortNKeys; ++i) {
int keySize = sortKeys[i].getField().getSize();
cmpField1.setSize(keySize);
cmpField2.setSize(keySize);

CobolFieldAttribute attr = sortKeys[i].getField().getAttribute();
cmpField1.setAttribute(attr);
cmpField2.setAttribute(attr);

cmpStorage1.setDataRefAndIndex(s1, s1.getIndex() + sortKeys[i].getOffset());
cmpStorage2.setDataRefAndIndex(s2, s2.getIndex() + sortKeys[i].getOffset());

int cmp;
if (attr.isTypeNumeric()) {
cmp = cmpField1.numericCompareTo(cmpField2);
} else if (attr.isTypeNational()) {
cmp = CobolUtil.nationalCmps(s1, s2, keySize, sortCollate);
} else {
cmp = cmpField1.cmpAlnum(cmpField2);
}
if (cmp != 0) {
return (sortKeys[i].getFlag() == COB_ASCENDING) ? cmp : -cmp;
}
}
return 0;
}

private static void swap2Indecies(int a, int b) {
int tmp = sortBuffer[a];
sortBuffer[a] = sortBuffer[b];
sortBuffer[b] = tmp;
}

private static void rotate3Indecies(int a, int b, int c) {
int tmp = sortBuffer[c];
sortBuffer[c] = sortBuffer[b];
sortBuffer[b] = sortBuffer[a];
sortBuffer[a] = tmp;
}
}
59 changes: 44 additions & 15 deletions tests/run.src/miscellaneous.at
Original file line number Diff line number Diff line change
Expand Up @@ -1366,30 +1366,50 @@ AT_CLEANUP


AT_SETUP([SORT: table sort])
AT_CHECK([${SKIP_TEST}])

AT_DATA([prog.cob], [
IDENTIFICATION DIVISION.
PROGRAM-ID. prog.
DATA DIVISION.
WORKING-STORAGE SECTION.
01 G VALUE "d4b2e1a3c5".
02 TBL OCCURS 5.
02 TBL-G OCCURS 5.
03 X PIC X.
03 Y PIC 9.
PROCEDURE DIVISION.
SORT TBL ASCENDING KEY X.
DISPLAY G
END-DISPLAY.
SORT TBL DESCENDING KEY Y.
DISPLAY G
END-DISPLAY.
SORT TBL ASCENDING KEY TBL.
DISPLAY G
END-DISPLAY.
SORT TBL DESCENDING KEY.
DISPLAY G
END-DISPLAY.
01 H VALUE "d4Db2Be3Ea5Ac6Cf1F".
02 TBL-H OCCURS 6.
03 A PIC X.
03 B PIC 9.
03 C PIC X.
PROCEDURE DIVISION.
SORT TBL-G ASCENDING KEY X.
DISPLAY G.
SORT TBL-G DESCENDING KEY Y.
DISPLAY G.
SORT TBL-G ASCENDING KEY TBL-G.
DISPLAY G.
SORT TBL-G DESCENDING KEY.
DISPLAY G.

SORT TBL-H ASCENDING KEY A.
DISPLAY H.
SORT TBL-H DESCENDING KEY B.
DISPLAY H.
SORT TBL-H DESCENDING KEY C.
DISPLAY H.
SORT TBL-H ASCENDING KEY TBL-H.
DISPLAY H.
SORT TBL-H DESCENDING KEY.
DISPLAY H.

SORT TBL-G ASCENDING KEY X.
DISPLAY G.
SORT TBL-G DESCENDING KEY Y.
DISPLAY G.
SORT TBL-G ASCENDING KEY TBL-G.
DISPLAY G.
SORT TBL-G DESCENDING KEY.
DISPLAY G.
STOP RUN.
])

Expand All @@ -1399,6 +1419,15 @@ AT_CHECK([java prog], [0],
c5d4a3b2e1
a3b2c5d4e1
e1d4c5b2a3
a5Ab2Bc6Cd4De3Ef1F
c6Ca5Ad4De3Eb2Bf1F
f1Fe3Ed4Dc6Cb2Ba5A
a5Ab2Bc6Cd4De3Ef1F
f1Fe3Ed4Dc6Cb2Ba5A
a3b2c5d4e1
c5d4a3b2e1
a3b2c5d4e1
e1d4c5b2a3
])

AT_CLEANUP
Expand Down