Solve exercise 13
This commit is contained in:
parent
a410e816f4
commit
c99b0817c0
6 changed files with 511 additions and 0 deletions
29
app/src/main/java/ch/nuth/zhaw/exbox/CObject.java
Normal file
29
app/src/main/java/ch/nuth/zhaw/exbox/CObject.java
Normal file
|
@ -0,0 +1,29 @@
|
|||
package ch.nuth.zhaw.exbox;
|
||||
|
||||
/** base class of collectable objects */
|
||||
public class CObject implements Collectable {
|
||||
private boolean mark; // to mark object
|
||||
public CObject next, down;
|
||||
public String value;
|
||||
|
||||
public CObject (String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public void setMark(boolean mark) {
|
||||
this.mark = mark;
|
||||
}
|
||||
|
||||
public boolean isMarked() {
|
||||
return mark;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return this.getClass() == o.getClass() && this.value.equals(((CObject)o).value);
|
||||
}
|
||||
}
|
6
app/src/main/java/ch/nuth/zhaw/exbox/Collectable.java
Normal file
6
app/src/main/java/ch/nuth/zhaw/exbox/Collectable.java
Normal file
|
@ -0,0 +1,6 @@
|
|||
package ch.nuth.zhaw.exbox;
|
||||
|
||||
public interface Collectable {
|
||||
void setMark(boolean b);
|
||||
boolean isMarked();
|
||||
}
|
188
app/src/main/java/ch/nuth/zhaw/exbox/Storage.java
Normal file
188
app/src/main/java/ch/nuth/zhaw/exbox/Storage.java
Normal file
|
@ -0,0 +1,188 @@
|
|||
package ch.nuth.zhaw.exbox;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class Storage {
|
||||
public static boolean generationalGCActive = true; // in Aufgabe 2 verwendet
|
||||
public static StringBuffer log = new StringBuffer();
|
||||
private static List<Collectable> root;
|
||||
private static List<Collectable> youngHeap;
|
||||
private static List<Collectable> oldHeap;
|
||||
public static boolean youngGenerationOnly = true;
|
||||
|
||||
static {
|
||||
clear();
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
root = new LinkedList<>();
|
||||
youngHeap = new LinkedList<>();
|
||||
// oldHeap erst in Aufgabe 2 verwenden!
|
||||
oldHeap = new LinkedList<>();
|
||||
}
|
||||
|
||||
/* add root object */
|
||||
public static void addRoot(Collectable obj) {
|
||||
root.add(obj);
|
||||
}
|
||||
|
||||
// create a collectable object of class cls
|
||||
public static Collectable _new(String cls, Object arg) {
|
||||
Collectable obj = null;
|
||||
try {
|
||||
// create an object and call constructor
|
||||
Constructor<?> cst = Class.forName(getPackage() + cls).getConstructor(arg.getClass());
|
||||
obj = (Collectable) cst.newInstance(new Object[] { arg });
|
||||
// add object to heap
|
||||
youngHeap.add(obj);
|
||||
log.append("New: ").append(obj).append("\n");
|
||||
} catch (Exception ex) {
|
||||
log.append("error creating object ").append(cls).append("\n");
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static String getPackage() {
|
||||
Package pack = Storage.class.getPackage();
|
||||
if (pack != null && !pack.getName().equals("")) {
|
||||
return pack.getName() + ".";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/* remove object from heap */
|
||||
public static void delete(Collectable obj) {
|
||||
if (youngHeap.remove(obj)) {
|
||||
if (generationalGCActive) {
|
||||
log.append("Delete young heap: ").append(obj).append("\n");
|
||||
} else {
|
||||
log.append("Delete heap: ").append(obj).append("\n");
|
||||
}
|
||||
} else if (oldHeap.remove(obj)) {
|
||||
log.append("Delete old heap: ").append(obj).append("\n");
|
||||
} else {
|
||||
log.append("error trying to delete not existing object ").append(obj).append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* get all root objects */
|
||||
public static Iterable<Collectable> getRoot() {
|
||||
return new LinkedList<>(root);
|
||||
}
|
||||
|
||||
/* get young heap */
|
||||
public static Iterable<Collectable> getYoungHeap() {
|
||||
return new LinkedList<>(youngHeap);
|
||||
}
|
||||
|
||||
/* get old heap */
|
||||
public static Iterable<Collectable> getOldHeap() {
|
||||
return new LinkedList<>(oldHeap);
|
||||
}
|
||||
|
||||
/* get heap */
|
||||
public static Iterable<Collectable> getHeap() {
|
||||
return new LinkedList<>(youngHeap);
|
||||
}
|
||||
|
||||
/* get references to collectables of an object */
|
||||
public static Iterable<Collectable> getRefs(Collectable obj) {
|
||||
// get all fields of an object
|
||||
List<Collectable> fieldList = new LinkedList<>();
|
||||
for (Field field : obj.getClass().getFields()) {
|
||||
try {
|
||||
Object o = field.get(obj);
|
||||
if (o instanceof Collectable) {
|
||||
fieldList.add((Collectable) o);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
return fieldList;
|
||||
}
|
||||
|
||||
/* dump an iterator */
|
||||
public static void dump(String s, Iterable<Collectable> itr) {
|
||||
log.append(s);
|
||||
for (Collectable o : itr) {
|
||||
log.append(" ").append(o);
|
||||
}
|
||||
log.append("\n");
|
||||
}
|
||||
|
||||
public static String getLog() {
|
||||
return log.toString();
|
||||
}
|
||||
|
||||
private static void mark(Collectable cObject) {
|
||||
// TODO Aufgabe 13.1
|
||||
if (!cObject.isMarked()) {
|
||||
cObject.setMark(true);
|
||||
|
||||
for (Collectable item : getRefs(cObject)) {
|
||||
mark(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void sweep() {
|
||||
// TODO Aufgabe 13.1 und Aufgabe 13.2
|
||||
Map<Iterable<Collectable>, Consumer<Collectable>> heaps = new HashMap<>();
|
||||
Consumer<Collectable> noOp = (item) -> {};
|
||||
|
||||
Consumer<Collectable> copy = (item) -> {
|
||||
youngHeap.remove(item);
|
||||
oldHeap.add(item);
|
||||
};
|
||||
|
||||
heaps.put(getYoungHeap(), generationalGCActive ? copy : noOp);
|
||||
|
||||
if (!youngGenerationOnly) {
|
||||
heaps.put(getOldHeap(), noOp);
|
||||
}
|
||||
|
||||
for (Map.Entry<Iterable<Collectable>, Consumer<Collectable>> entry : heaps.entrySet()) {
|
||||
for (Collectable item : entry.getKey()) {
|
||||
if (!item.isMarked()) {
|
||||
delete(item);
|
||||
} else {
|
||||
item.setMark(false);
|
||||
entry.getValue().accept(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void gc() {
|
||||
if (generationalGCActive) {
|
||||
if (youngGenerationOnly) {
|
||||
log.append("\nCollector start young generation only\n");
|
||||
} else {
|
||||
log.append("\nCollector start young and old generation\n");
|
||||
}
|
||||
} else {
|
||||
log.append("\nCollector start\n");
|
||||
}
|
||||
|
||||
// TODO Aufgabe 13.1 und Aufgabe 13.2
|
||||
for (Collectable item : getRoot()) {
|
||||
mark(item);
|
||||
}
|
||||
|
||||
sweep();
|
||||
|
||||
if (generationalGCActive) {
|
||||
youngGenerationOnly = !youngGenerationOnly;
|
||||
}
|
||||
|
||||
log.append("Collector end\n");
|
||||
}
|
||||
}
|
66
app/src/main/java/ch/nuth/zhaw/exbox/TestCObjectServer.java
Normal file
66
app/src/main/java/ch/nuth/zhaw/exbox/TestCObjectServer.java
Normal file
|
@ -0,0 +1,66 @@
|
|||
package ch.nuth.zhaw.exbox;
|
||||
|
||||
public class TestCObjectServer implements CommandExecutor {
|
||||
private static CObject new_CObject(Object s) {
|
||||
return (CObject) Storage._new("CObject", s);
|
||||
}
|
||||
|
||||
static CObject a;
|
||||
static CObject e;
|
||||
|
||||
public String execute (String input) {
|
||||
run();
|
||||
return Storage.getLog();
|
||||
}
|
||||
|
||||
private void run() {
|
||||
a = new_CObject("A");
|
||||
CObject b = new_CObject("B");
|
||||
CObject c = new_CObject("C");
|
||||
CObject d = new_CObject("D");
|
||||
e = new_CObject("E");
|
||||
CObject f = new_CObject("F");
|
||||
CObject g = new_CObject("G");
|
||||
Storage.addRoot(a);
|
||||
Storage.addRoot(e);
|
||||
a.next = b; b.next = c; b.down = a; c.down = d;
|
||||
e.next = f; f.next = g; g.next = e;
|
||||
Storage.dump("\nRoots:", Storage.getRoot());
|
||||
if (Storage.generationalGCActive) {
|
||||
Storage.dump("\nYoung heap 1:", Storage.getYoungHeap());
|
||||
Storage.dump("Old heap 1:", Storage.getOldHeap());
|
||||
} else {
|
||||
Storage.dump("Heap 1:", Storage.getYoungHeap());
|
||||
}
|
||||
Storage.gc();
|
||||
if (Storage.generationalGCActive) {
|
||||
Storage.dump("Young heap 2:", Storage.getYoungHeap());
|
||||
Storage.dump("Old heap 2:", Storage.getOldHeap());
|
||||
} else {
|
||||
Storage.dump("Heap 2:", Storage.getYoungHeap());
|
||||
}
|
||||
b.next = f;
|
||||
Storage.gc();
|
||||
if (Storage.generationalGCActive) {
|
||||
Storage.dump("Young heap 3:", Storage.getYoungHeap());
|
||||
Storage.dump("Old heap 3:", Storage.getOldHeap());
|
||||
} else {
|
||||
Storage.dump("Heap 3:", Storage.getYoungHeap());
|
||||
}
|
||||
f.next = null;
|
||||
Storage.gc();
|
||||
if (Storage.generationalGCActive) {
|
||||
Storage.dump("Young heap 4:", Storage.getYoungHeap());
|
||||
Storage.dump("Old heap 4:", Storage.getOldHeap());
|
||||
} else {
|
||||
Storage.dump("Heap 4:", Storage.getYoungHeap());
|
||||
}
|
||||
Storage.gc();
|
||||
if (Storage.generationalGCActive) {
|
||||
Storage.dump("Young heap 5:", Storage.getYoungHeap());
|
||||
Storage.dump("Old heap 5:", Storage.getOldHeap());
|
||||
} else {
|
||||
Storage.dump("Heap 5:", Storage.getYoungHeap());
|
||||
}
|
||||
}
|
||||
}
|
92
app/src/test/java/ch/nuth/zhaw/exbox/ADS13_1_test.java
Normal file
92
app/src/test/java/ch/nuth/zhaw/exbox/ADS13_1_test.java
Normal file
|
@ -0,0 +1,92 @@
|
|||
package ch.nuth.zhaw.exbox;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class ADS13_1_test {
|
||||
private CObject new_CObject(Object s) {
|
||||
return (CObject) Storage._new("CObject", s);
|
||||
}
|
||||
|
||||
static CObject a, d;
|
||||
CObject b, c, e, f, g;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
Storage.generationalGCActive = false;
|
||||
Storage.clear();
|
||||
newObjects();
|
||||
}
|
||||
|
||||
private void testContent(String message, Iterable<Collectable> content, String expected) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
content.forEach(b::append);
|
||||
assertEquals(expected, b.toString(), message);
|
||||
}
|
||||
|
||||
private void newObjects() {
|
||||
a = new_CObject("A");
|
||||
b = new_CObject("B");
|
||||
c = new_CObject("C");
|
||||
d = new_CObject("D");
|
||||
e = new_CObject("E");
|
||||
f = new_CObject("F");
|
||||
g = new_CObject("G");
|
||||
Storage.addRoot(a);
|
||||
Storage.addRoot(d);
|
||||
a.next = b;
|
||||
b.next = c;
|
||||
b.down = a;
|
||||
c.down = d;
|
||||
d.next = e;
|
||||
e.next = f;
|
||||
f.next = g;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoot() {
|
||||
testContent("ROOT", Storage.getRoot(), "AD");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitialHeap() {
|
||||
testContent("HEAP1", Storage.getHeap(), "ABCDEFG");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAfterFirstGC() {
|
||||
Storage.gc();
|
||||
testContent("HEAP2", Storage.getHeap(), "ABCDEFG");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAfterFirstChangeGC() {
|
||||
Storage.gc();
|
||||
e.next = d;
|
||||
Storage.gc();
|
||||
testContent("HEAP3", Storage.getHeap(), "ABCDE");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAfterSecondChangeGC() {
|
||||
Storage.gc();
|
||||
e.next = d;
|
||||
Storage.gc();
|
||||
a.next = null;
|
||||
Storage.gc();
|
||||
testContent("HEAP4", Storage.getHeap(), "ADE");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFinalHeap() {
|
||||
Storage.gc();
|
||||
e.next = d;
|
||||
Storage.gc();
|
||||
a.next = null;
|
||||
Storage.gc();
|
||||
Storage.gc();
|
||||
testContent("HEAP5", Storage.getHeap(), "ADE");
|
||||
}
|
||||
}
|
130
app/src/test/java/ch/nuth/zhaw/exbox/ADS13_3_test.java
Normal file
130
app/src/test/java/ch/nuth/zhaw/exbox/ADS13_3_test.java
Normal file
|
@ -0,0 +1,130 @@
|
|||
package ch.nuth.zhaw.exbox;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
public class ADS13_3_test {
|
||||
private CObject new_CObject(Object s) {
|
||||
return (CObject) Storage._new("CObject", s);
|
||||
}
|
||||
|
||||
static CObject a, d;
|
||||
CObject b, c, e, f, g, h;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
Storage.generationalGCActive = true;
|
||||
Storage.youngGenerationOnly = true;
|
||||
Storage.clear();
|
||||
newObjects();
|
||||
}
|
||||
|
||||
private void testContent(String message, Iterable<Collectable> content, String expected) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
content.forEach(b::append);
|
||||
assertEquals(expected, b.toString(), message);
|
||||
}
|
||||
|
||||
private void newObjects() {
|
||||
a = new_CObject("A");
|
||||
b = new_CObject("B");
|
||||
c = new_CObject("C");
|
||||
d = new_CObject("D");
|
||||
e = new_CObject("E");
|
||||
f = new_CObject("F");
|
||||
g = new_CObject("G");
|
||||
Storage.addRoot(a);
|
||||
Storage.addRoot(d);
|
||||
a.next = b;
|
||||
b.next = c;
|
||||
b.down = a;
|
||||
c.down = d;
|
||||
d.next = e;
|
||||
e.next = f;
|
||||
f.next = g;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoot() {
|
||||
testContent("ROOT", Storage.getRoot(), "AD");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInitialHeap() {
|
||||
testContent("YOUNG HEAP1", Storage.getYoungHeap(), "ABCDEFG");
|
||||
testContent("OLD HEAP1", Storage.getOldHeap(), ""); }
|
||||
|
||||
@Test
|
||||
public void testAfterFirstGC() {
|
||||
Storage.gc();
|
||||
Storage.getYoungHeap();
|
||||
Storage.getOldHeap();
|
||||
testContent("YOUNG HEAP2", Storage.getYoungHeap(), "");
|
||||
testContent("OLD HEAP2", Storage.getOldHeap(), "ABCDEFG");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAfterFirstChangeGC() {
|
||||
Storage.gc();
|
||||
e.next = d;
|
||||
Storage.gc();
|
||||
testContent("YOUNG HEAP3", Storage.getYoungHeap(), "");
|
||||
testContent("OLD HEAP3", Storage.getOldHeap(), "ABCDE");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAfterSecondChangeGC() {
|
||||
Storage.gc();
|
||||
e.next = d;
|
||||
Storage.gc();
|
||||
a.next = null;
|
||||
Storage.gc();
|
||||
testContent("YOUNG HEAP4", Storage.getYoungHeap(), "");
|
||||
testContent("OLD HEAP4", Storage.getOldHeap(), "ABCDE");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAfterSecondCallGC() {
|
||||
Storage.gc();
|
||||
e.next = d;
|
||||
Storage.gc();
|
||||
a.next = null;
|
||||
Storage.gc();
|
||||
Storage.gc();
|
||||
testContent("YOUNG HEAP5", Storage.getYoungHeap(), "");
|
||||
testContent("OLD HEAP5", Storage.getOldHeap(), "ADE");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAfterAddObjecthGC() {
|
||||
Storage.gc();
|
||||
e.next = d;
|
||||
Storage.gc();
|
||||
a.next = null;
|
||||
Storage.gc();
|
||||
Storage.gc();
|
||||
h = new_CObject("H");
|
||||
a.next = h;
|
||||
testContent("YOUNG HEAP5", Storage.getYoungHeap(), "H");
|
||||
testContent("OLD HEAP5", Storage.getOldHeap(), "ADE");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFinalHeap() {
|
||||
Storage.gc();
|
||||
e.next = d;
|
||||
Storage.gc();
|
||||
a.next = null;
|
||||
Storage.gc();
|
||||
Storage.gc();
|
||||
h = new_CObject("H");
|
||||
a.next = h;
|
||||
testContent("YOUNG HEAP5", Storage.getYoungHeap(), "H");
|
||||
testContent("OLD HEAP5", Storage.getOldHeap(), "ADE");
|
||||
Storage.gc();
|
||||
testContent("YOUNG HEAP5", Storage.getYoungHeap(), "");
|
||||
testContent("OLD HEAP5", Storage.getOldHeap(), "ADEH");
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue