mirror of
https://github.com/oxen-io/session-android.git
synced 2025-04-17 04:21:25 +00:00
Added OrderEnforcer class to schedule ordered tasks.
This commit is contained in:
parent
bcebf58b76
commit
e63773e5c8
74
src/org/thoughtcrime/securesms/camera/OrderEnforcer.java
Normal file
74
src/org/thoughtcrime/securesms/camera/OrderEnforcer.java
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
package org.thoughtcrime.securesms.camera;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
|
public class OrderEnforcer<E> {
|
||||||
|
|
||||||
|
private final E[] stages;
|
||||||
|
private final Map<E, Integer> stageIndices;
|
||||||
|
private final Map<E, List<Runnable>> actions;
|
||||||
|
private final boolean[] completion;
|
||||||
|
|
||||||
|
public OrderEnforcer(@NonNull E... stages) {
|
||||||
|
this.stages = stages;
|
||||||
|
this.stageIndices = new HashMap<>();
|
||||||
|
this.actions = new HashMap<>();
|
||||||
|
this.completion = new boolean[stages.length];
|
||||||
|
|
||||||
|
for (int i = 0; i < stages.length; i++) {
|
||||||
|
stageIndices.put(stages[i], i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void run(@NonNull E stage, Runnable r) {
|
||||||
|
if (isCompletedThrough(stage)) {
|
||||||
|
r.run();
|
||||||
|
} else {
|
||||||
|
List<Runnable> stageActions = actions.containsKey(stage) ? actions.get(stage) : new CopyOnWriteArrayList<>();
|
||||||
|
stageActions.add(r);
|
||||||
|
|
||||||
|
actions.put(stage, stageActions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void markCompleted(@NonNull E stage) {
|
||||||
|
completion[stageIndices.get(stage)] = true;
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while (i < completion.length && completion[i]) {
|
||||||
|
List<Runnable> stageActions = actions.get(stages[i]);
|
||||||
|
if (stageActions != null) {
|
||||||
|
for (Runnable r : stageActions) {
|
||||||
|
r.run();
|
||||||
|
}
|
||||||
|
stageActions.clear();
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void reset() {
|
||||||
|
for (int i = 0; i < completion.length; i++) {
|
||||||
|
completion[i] = false;
|
||||||
|
}
|
||||||
|
actions.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isCompletedThrough(@NonNull E stage) {
|
||||||
|
int index = stageIndices.get(stage);
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
while (i <= index && i < completion.length) {
|
||||||
|
if (!completion[i]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,104 @@
|
|||||||
|
package org.thoughtcrime.securesms.camera;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import static junit.framework.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class OrderEnforcerTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void markCompleted_singleEntry() {
|
||||||
|
AtomicInteger counter = new AtomicInteger(0);
|
||||||
|
|
||||||
|
OrderEnforcer<Stage> enforcer = new OrderEnforcer<>(Stage.A, Stage.B, Stage.C, Stage.D);
|
||||||
|
enforcer.run(Stage.A, new CountRunnable(counter));
|
||||||
|
assertEquals(0, counter.get());
|
||||||
|
|
||||||
|
enforcer.markCompleted(Stage.A);
|
||||||
|
assertEquals(1, counter.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void markCompleted_singleEntry_waterfall() {
|
||||||
|
AtomicInteger counter = new AtomicInteger(0);
|
||||||
|
|
||||||
|
OrderEnforcer<Stage> enforcer = new OrderEnforcer<>(Stage.A, Stage.B, Stage.C, Stage.D);
|
||||||
|
enforcer.run(Stage.C, new CountRunnable(counter));
|
||||||
|
assertEquals(0, counter.get());
|
||||||
|
|
||||||
|
enforcer.markCompleted(Stage.A);
|
||||||
|
assertEquals(0, counter.get());
|
||||||
|
|
||||||
|
enforcer.markCompleted(Stage.C);
|
||||||
|
assertEquals(0, counter.get());
|
||||||
|
|
||||||
|
enforcer.markCompleted(Stage.B);
|
||||||
|
assertEquals(1, counter.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void markCompleted_multipleEntriesPerStage_waterfall() {
|
||||||
|
AtomicInteger counter = new AtomicInteger(0);
|
||||||
|
|
||||||
|
OrderEnforcer<Stage> enforcer = new OrderEnforcer<>(Stage.A, Stage.B, Stage.C, Stage.D);
|
||||||
|
|
||||||
|
enforcer.run(Stage.A, new CountRunnable(counter));
|
||||||
|
enforcer.run(Stage.A, new CountRunnable(counter));
|
||||||
|
assertEquals(0, counter.get());
|
||||||
|
|
||||||
|
enforcer.run(Stage.B, new CountRunnable(counter));
|
||||||
|
enforcer.run(Stage.B, new CountRunnable(counter));
|
||||||
|
assertEquals(0, counter.get());
|
||||||
|
|
||||||
|
enforcer.run(Stage.C, new CountRunnable(counter));
|
||||||
|
enforcer.run(Stage.C, new CountRunnable(counter));
|
||||||
|
assertEquals(0, counter.get());
|
||||||
|
|
||||||
|
enforcer.run(Stage.D, new CountRunnable(counter));
|
||||||
|
enforcer.run(Stage.D, new CountRunnable(counter));
|
||||||
|
assertEquals(0, counter.get());
|
||||||
|
|
||||||
|
enforcer.markCompleted(Stage.A);
|
||||||
|
assertEquals(counter.get(), 2);
|
||||||
|
|
||||||
|
enforcer.markCompleted(Stage.D);
|
||||||
|
assertEquals(counter.get(), 2);
|
||||||
|
|
||||||
|
enforcer.markCompleted(Stage.B);
|
||||||
|
assertEquals(counter.get(), 4);
|
||||||
|
|
||||||
|
enforcer.markCompleted(Stage.C);
|
||||||
|
assertEquals(counter.get(), 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void run_alreadyCompleted() {
|
||||||
|
AtomicInteger counter = new AtomicInteger(0);
|
||||||
|
|
||||||
|
OrderEnforcer<Stage> enforcer = new OrderEnforcer<>(Stage.A, Stage.B, Stage.C, Stage.D);
|
||||||
|
enforcer.markCompleted(Stage.A);
|
||||||
|
enforcer.markCompleted(Stage.B);
|
||||||
|
|
||||||
|
enforcer.run(Stage.B, new CountRunnable(counter));
|
||||||
|
assertEquals(1, counter.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class CountRunnable implements Runnable {
|
||||||
|
private final AtomicInteger counter;
|
||||||
|
|
||||||
|
public CountRunnable(AtomicInteger counter) {
|
||||||
|
this.counter = counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
counter.incrementAndGet();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum Stage {
|
||||||
|
A, B, C, D
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user