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
71 changes: 71 additions & 0 deletions src/main/cod/demo/src/main/test/lazyloop/LazyLoop.cod
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,77 @@ out("arrB[600] == 1200 is {d}") // Should be true
out("mixedArr[50] = " + mixedArr[50] + " (should be 'middle')")
out("mixedArr[27] = " + mixedArr[27] + " (should be 'range')")
out("mixedArr[75] = " + mixedArr[75] + " (should be 75)")

out()
out("15. High-branch conditional fast-path stress:")
manyBranches : [int] = [0 to 1Qi]
for i of [0 to 1Qi] {
if i % 53 == 0 { manyBranches[i] = 53 }
elif i % 52 == 0 { manyBranches[i] = 52 }
elif i % 51 == 0 { manyBranches[i] = 51 }
elif i % 50 == 0 { manyBranches[i] = 50 }
elif i % 49 == 0 { manyBranches[i] = 49 }
elif i % 48 == 0 { manyBranches[i] = 48 }
elif i % 47 == 0 { manyBranches[i] = 47 }
elif i % 46 == 0 { manyBranches[i] = 46 }
elif i % 45 == 0 { manyBranches[i] = 45 }
elif i % 44 == 0 { manyBranches[i] = 44 }
elif i % 43 == 0 { manyBranches[i] = 43 }
elif i % 42 == 0 { manyBranches[i] = 42 }
elif i % 41 == 0 { manyBranches[i] = 41 }
elif i % 40 == 0 { manyBranches[i] = 40 }
elif i % 39 == 0 { manyBranches[i] = 39 }
elif i % 38 == 0 { manyBranches[i] = 38 }
elif i % 37 == 0 { manyBranches[i] = 37 }
elif i % 36 == 0 { manyBranches[i] = 36 }
elif i % 35 == 0 { manyBranches[i] = 35 }
elif i % 34 == 0 { manyBranches[i] = 34 }
elif i % 33 == 0 { manyBranches[i] = 33 }
elif i % 32 == 0 { manyBranches[i] = 32 }
elif i % 31 == 0 { manyBranches[i] = 31 }
elif i % 30 == 0 { manyBranches[i] = 30 }
elif i % 29 == 0 { manyBranches[i] = 29 }
elif i % 28 == 0 { manyBranches[i] = 28 }
elif i % 27 == 0 { manyBranches[i] = 27 }
elif i % 26 == 0 { manyBranches[i] = 26 }
elif i % 25 == 0 { manyBranches[i] = 25 }
elif i % 24 == 0 { manyBranches[i] = 24 }
elif i % 23 == 0 { manyBranches[i] = 23 }
elif i % 22 == 0 { manyBranches[i] = 22 }
elif i % 21 == 0 { manyBranches[i] = 21 }
elif i % 20 == 0 { manyBranches[i] = 20 }
elif i % 19 == 0 { manyBranches[i] = 19 }
elif i % 18 == 0 { manyBranches[i] = 18 }
elif i % 17 == 0 { manyBranches[i] = 17 }
elif i % 16 == 0 { manyBranches[i] = 16 }
elif i % 15 == 0 { manyBranches[i] = 15 }
elif i % 14 == 0 { manyBranches[i] = 14 }
elif i % 13 == 0 { manyBranches[i] = 13 }
elif i % 12 == 0 { manyBranches[i] = 12 }
elif i % 11 == 0 { manyBranches[i] = 11 }
elif i % 10 == 0 { manyBranches[i] = 10 }
elif i % 9 == 0 { manyBranches[i] = 9 }
elif i % 8 == 0 { manyBranches[i] = 8 }
elif i % 7 == 0 { manyBranches[i] = 7 }
elif i % 6 == 0 { manyBranches[i] = 6 }
elif i % 5 == 0 { manyBranches[i] = 5 }
elif i % 4 == 0 { manyBranches[i] = 4 }
else { manyBranches[i] = 1 }
}
out("manyBranches[106] = " + manyBranches[106] + " (should be 53)")
out("manyBranches[104] = " + manyBranches[104] + " (should be 52)")
out("manyBranches[97] = " + manyBranches[97] + " (should be 1)")

out()
out("16. Pending updates scaling + precedence:")
pendingScale := [0 to 10K]
for i of [0 to 199] {
pendingScale[i to 10K by 100] = i
}
out("pendingScale[500] = " + pendingScale[500] + " (should be 100)")
out("pendingScale[150] = " + pendingScale[150] + " (should be 150)")
out("pendingScale[250] = " + pendingScale[250] + " (should be 150)")
out("pendingScale[199] = " + pendingScale[199] + " (should be 199)")
out()
out("=== All tests completed ===")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ share main() {
out("fib[10]=" + fib[10] + " expected=55")
out("fib[20]=" + fib[20] + " expected=6765")
out("fib[30]=" + fib[30] + " expected=832040")
out("fib[100]=" + fib[100] + " expected=354224848179261915075")
out("fib[500]=" + fib[500])
out("fib[1000]=" + fib[1000])
out("fib[1500]=" + fib[1500])
out("fib[1999]=" + fib[1999])
out("fib[2000]=" + fib[2000])

jac := [0 to 2000]
jac[0] = 0
Expand All @@ -33,5 +39,14 @@ share main() {
out("shift[2]=" + shift[2] + " expected=6")
out("shift[3]=" + shift[3] + " expected=12")
out("shift[10]=" + shift[10] + " expected=495")

ramp := [0 to 2000]
ramp[0] = 1
for i of [1 to 2000] {
ramp[i] = ramp[i-1] + 7
}
out("ramp[10]=" + ramp[10] + " expected=71")
out("ramp[1000]=" + ramp[1000] + " expected=7001")
out("ramp[2000]=" + ramp[2000] + " expected=14001")
out("elapsed_ms=" + (timer() - start))
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ share main() {
out("pair1-b[10]=" + b[10] + " expected=16")
out("pair1-a[20]=" + a[20] + " expected=1536")
out("pair1-b[20]=" + b[20] + " expected=512")
out("pair1-a[100]=" + a[100])
out("pair1-b[100]=" + b[100])
out("pair1-a[150]=" + a[150])
out("pair1-b[150]=" + b[150])
out("pair1-a[200]=" + a[200])
out("pair1-b[200]=" + b[200])

c := [0 to 200]
d := [0 to 200]
Expand All @@ -39,5 +45,11 @@ share main() {
out("pair2-d[10]=" + d[10] + " expected=41")
out("pair2-c[20]=" + c[20] + " expected=3070")
out("pair2-d[20]=" + d[20] + " expected=1367")
out("pair2-c[100]=" + c[100])
out("pair2-d[100]=" + d[100])
out("pair2-c[150]=" + c[150])
out("pair2-d[150]=" + d[150])
out("pair2-c[200]=" + c[200])
out("pair2-d[200]=" + d[200])
out("elapsed_ms=" + (timer() - start))
}
139 changes: 126 additions & 13 deletions src/main/java/cod/range/NaturalArray.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,12 @@ public class NaturalArray {
private Map<Long, Object> computedCache = new HashMap<Long, Object>();

// Pending updates for lazy assignment
private static final int PENDING_UPDATES_TREE_THRESHOLD = 100;
private List<PendingRangeUpdate> pendingUpdates = new ArrayList<PendingRangeUpdate>();
private NavigableMap<Long, List<PendingRangeUpdate>> pendingUpdatesByStart = null;
private NavigableMap<Long, Long> pendingUpdateOrderPrefixByStart = null;
private boolean pendingUpdateOrderPrefixDirty = false;
private long nextPendingUpdateOrder = 0L;
private boolean hasPendingUpdates = false;

// Output cache
Expand Down Expand Up @@ -214,15 +219,18 @@ public ProcessedRange merge(ProcessedRange other) {
private static class PendingRangeUpdate implements Comparable<PendingRangeUpdate> {
final ProcessedRange range;
final Object value;
final long order;

PendingRangeUpdate(Object spec, Object value) {
PendingRangeUpdate(Object spec, Object value, long order) {
this.range = new ProcessedRange(spec); // Process ONCE
this.value = value;
this.order = order;
}

PendingRangeUpdate(ProcessedRange range, Object value) {
PendingRangeUpdate(ProcessedRange range, Object value, long order) {
this.range = range;
this.value = value;
this.order = order;
}

boolean contains(long index) {
Expand Down Expand Up @@ -1028,8 +1036,7 @@ public void setRange(Object range, Object value) {
}

try {
pendingUpdates.add(new PendingRangeUpdate(range, value));
hasPendingUpdates = true;
registerPendingUpdate(new PendingRangeUpdate(range, value, nextPendingUpdateOrder++));

if (!isMutable) {
becomeMutable();
Expand Down Expand Up @@ -1098,9 +1105,8 @@ public void setMultiRange(Object multiRange, Object value) {
if (range == null) {
throw new InternalError("Null range in MultiRangeSpec");
}
pendingUpdates.add(new PendingRangeUpdate(range, value));
registerPendingUpdate(new PendingRangeUpdate(range, value, nextPendingUpdateOrder++));
}
hasPendingUpdates = true;

if (!isMutable) {
becomeMutable();
Expand All @@ -1127,16 +1133,117 @@ private void applyPendingUpdatesForIndex(long index) {
if (!hasPendingUpdates || pendingUpdates.isEmpty()) {
return;
}


PendingRangeUpdate resolvedUpdate = resolvePendingUpdateForIndex(index);
if (resolvedUpdate == null) {
return;
}

if (cache == null) {
cache = new HashMap<Long, Object>();
}
cache.put(index, resolvedUpdate.value);
invalidateRecentCache(index);
}

private void registerPendingUpdate(PendingRangeUpdate update) {
pendingUpdates.add(update);
hasPendingUpdates = true;

if (pendingUpdatesByStart != null) {
addPendingUpdateToTree(update);
return;
}

if (pendingUpdates.size() >= PENDING_UPDATES_TREE_THRESHOLD) {
convertPendingUpdatesToTreeIndex();
}
}

private void addPendingUpdateToTree(PendingRangeUpdate update) {
if (pendingUpdatesByStart == null) {
pendingUpdatesByStart = new TreeMap<Long, List<PendingRangeUpdate>>();
}
List<PendingRangeUpdate> updatesAtStart = pendingUpdatesByStart.get(update.range.start);
if (updatesAtStart == null) {
updatesAtStart = new ArrayList<PendingRangeUpdate>();
pendingUpdatesByStart.put(update.range.start, updatesAtStart);
}
updatesAtStart.add(update);
pendingUpdateOrderPrefixDirty = true;
}

private void convertPendingUpdatesToTreeIndex() {
pendingUpdatesByStart = new TreeMap<Long, List<PendingRangeUpdate>>();
for (PendingRangeUpdate update : pendingUpdates) {
if (update.contains(index)) {
if (cache == null) {
cache = new HashMap<Long, Object>();
addPendingUpdateToTree(update);
}
}

private void rebuildPendingUpdateOrderPrefix() {
if (pendingUpdatesByStart == null) {
pendingUpdateOrderPrefixByStart = null;
pendingUpdateOrderPrefixDirty = false;
return;
}

pendingUpdateOrderPrefixByStart = new TreeMap<Long, Long>();
long runningMax = Long.MIN_VALUE;
for (Map.Entry<Long, List<PendingRangeUpdate>> entry : pendingUpdatesByStart.entrySet()) {
long bucketMax = Long.MIN_VALUE;
for (PendingRangeUpdate update : entry.getValue()) {
if (update.order > bucketMax) {
bucketMax = update.order;
}
}
if (bucketMax > runningMax) {
runningMax = bucketMax;
}
pendingUpdateOrderPrefixByStart.put(entry.getKey(), runningMax);
}
pendingUpdateOrderPrefixDirty = false;
}

private PendingRangeUpdate resolvePendingUpdateForIndex(long index) {
if (pendingUpdatesByStart == null) {
for (int i = pendingUpdates.size() - 1; i >= 0; i--) {
PendingRangeUpdate update = pendingUpdates.get(i);
if (update.contains(index)) {
return update;
}
}
return null;
}

if (pendingUpdateOrderPrefixDirty || pendingUpdateOrderPrefixByStart == null) {
rebuildPendingUpdateOrderPrefix();
}

PendingRangeUpdate winner = null;
NavigableMap<Long, List<PendingRangeUpdate>> candidatesByStart = pendingUpdatesByStart.headMap(index, true);
for (Map.Entry<Long, List<PendingRangeUpdate>> entry : candidatesByStart.descendingMap().entrySet()) {
List<PendingRangeUpdate> updatesAtStart = entry.getValue();
for (int i = updatesAtStart.size() - 1; i >= 0; i--) {
PendingRangeUpdate candidate = updatesAtStart.get(i);
if (winner != null && candidate.order <= winner.order) {
break;
}
if (!candidate.contains(index)) {
continue;
}
if (winner == null || candidate.order > winner.order) {
winner = candidate;
}
}

if (winner != null && pendingUpdateOrderPrefixByStart != null) {
Long remainingMaxOrder = pendingUpdateOrderPrefixByStart.get(entry.getKey());
if (remainingMaxOrder != null && winner.order >= remainingMaxOrder) {
break;
}
cache.put(index, update.value);
invalidateRecentCache(index);
}
}
return winner;
}

public void commitUpdates() {
Expand Down Expand Up @@ -1166,7 +1273,7 @@ public int compare(PendingRangeUpdate a, PendingRangeUpdate b) {
} else if (canMerge(current, update)) {
// Extend current range
ProcessedRange mergedRange = current.range.merge(update.range);
current = new PendingRangeUpdate(mergedRange, current.value);
current = new PendingRangeUpdate(mergedRange, current.value, current.order);
} else {
merged.add(current);
current = update;
Expand All @@ -1180,6 +1287,9 @@ public int compare(PendingRangeUpdate a, PendingRangeUpdate b) {
}

pendingUpdates.clear();
pendingUpdatesByStart = null;
pendingUpdateOrderPrefixByStart = null;
pendingUpdateOrderPrefixDirty = false;
hasPendingUpdates = false;
}

Expand Down Expand Up @@ -1688,6 +1798,9 @@ public int getPendingUpdateCount() {

public void discardUpdates() {
pendingUpdates.clear();
pendingUpdatesByStart = null;
pendingUpdateOrderPrefixByStart = null;
pendingUpdateOrderPrefixDirty = false;
hasPendingUpdates = false;
}

Expand Down
Loading