Adding SequentialAllocator; hopefully usefor for GameDOS, NakedOS, Apple Pascal, and likely RDOS as well.

This commit is contained in:
a2geek committed 2026-10-06 18:51:38 -05:00
1 parent bf517ee583
commit 19720bd5f3
3 files changed
+79

No files matched your search

@@ -19,6 +19,7 @@
*/
package org.applecommander.device;
import org.applecommander.device.Coordinate.TrackAndSectorCoordinate;
import org.applecommander.util.DataBuffer;
import org.applecommander.util.InformationGroup;
import org.applecommander.util.InformationProvider;
@@ -102,6 +103,12 @@ public interface TrackSectorDevice extends Device {
public int deviceSize() {
return sectorsPerDisk() * SECTOR_SIZE;
}
public int calculateSectorOffset(int track, int sector) {
return track * sectorsPerTrack + sector;
}
public TrackAndSectorCoordinate sectorOffsetToCoordinate(int sectorOffset) {
return new TrackAndSectorCoordinate(sectorOffset / sectorsPerTrack, sectorOffset % sectorsPerTrack);
}
@Override
public List<InformationGroup> information() {
@@ -0,0 +1,51 @@
package org.applecommander.os;
import org.applecommander.util.Range;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
/// The SequentialAllocator is intended to handle what is, essentially, a
/// single dimension allocation. That is, if the disk is allocated by sequential
/// chunks, this allocator should support it. For images that use T/S geometry
/// instead of block geometry, the T/S will need to be transformed.
///
/// For instance, GameDOS allocates by T/S but allocates all in a chunk. So once
/// there is a starting place, the rest of the file follows in a very specific
/// order.
public class SequentialAllocator {
private final int totalSize;
private final List<Range> used = new ArrayList<>();
public SequentialAllocator(int totalSize) {
this.totalSize = totalSize;
}
public void addUsed(int first, int last) {
assert first <= last;
assert first < totalSize && last <= totalSize;
used.add(new Range(first, last));
}
public void addUsedByLength(int first, int length) {
addUsed(first, first+length-1);
}
/// Look for `requestSize` spaces between the used ranges.
/// Returns either the first placement that the request will fit
/// or a `-1` if there is no fit.
public int find(int requestSize) {
used.sort(Comparator.comparingInt(Range::first));
int start = 0;
for (Range range : used) {
if (range.first() - start >= requestSize) {
return start;
}
start = range.last() + 1;
}
if (totalSize - start >= requestSize) {
return start;
}
return -1;
}
}
@@ -0,0 +1,21 @@
package org.applecommander.os;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class SequentialAllocatorTest {
@Test
public void test() {
SequentialAllocator allocator = new SequentialAllocator(10);
allocator.addUsed(2,4);
allocator.addUsed(5,6);
// Allocation:
// 0123456789
// FFUUUUUFFF
assertEquals(0, allocator.find(2));
assertEquals(7, allocator.find(3));
assertEquals(-1, allocator.find(4));
}
}