ga6 almost done
This commit is contained in:
parent
2b94c67c9a
commit
53ac4a1cbd
3 changed files with 504 additions and 0 deletions
139
SQ-2023-H6/pom.xml
Normal file
139
SQ-2023-H6/pom.xml
Normal file
|
@ -0,0 +1,139 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.usi.sq</groupId>
|
||||
<artifactId>SQ-2023-H6</artifactId>
|
||||
<version>1.0</version>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<junit.platform.version>1.7.0-M1</junit.platform.version>
|
||||
<junit.jupiter.version>5.6.2</junit.jupiter.version>
|
||||
<junit.vintage.version>5.6.2</junit.vintage.version>
|
||||
<junit.version>4.13</junit.version>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>central</id>
|
||||
<url>https://repo.maven.apache.org/maven2</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0-M5</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<source>8</source>
|
||||
<target>8</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.5</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<!-- attached to Maven test phase -->
|
||||
<execution>
|
||||
<id>report</id>
|
||||
<phase>test</phase>
|
||||
<goals>
|
||||
<goal>report</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.pitest</groupId>
|
||||
<artifactId>pitest-maven</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<configuration>
|
||||
<targetClasses>
|
||||
<param>org.usi.sq.util*</param>
|
||||
</targetClasses>
|
||||
<targetTests>
|
||||
<param>org.usi.sq.util*</param>
|
||||
<param>*</param>
|
||||
</targetTests>
|
||||
|
||||
</configuration>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.pitest</groupId>
|
||||
<artifactId>pitest-junit5-plugin</artifactId>
|
||||
<version>0.12</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>${junit.jupiter.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>${junit.jupiter.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>${junit.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.vintage</groupId>
|
||||
<artifactId>junit-vintage-engine</artifactId>
|
||||
<version>${junit.vintage.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<version>0.8.5</version>
|
||||
<reportSets>
|
||||
<reportSet>
|
||||
<reports>
|
||||
<!-- select non-aggregate reports -->
|
||||
<report>report</report>
|
||||
</reports>
|
||||
</reportSet>
|
||||
</reportSets>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-report-plugin</artifactId>
|
||||
<version>3.0.0-M5</version>
|
||||
<configuration>
|
||||
<!-- place configuration here if required-->
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jxr-plugin</artifactId>
|
||||
<version>3.3.0</version>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
</project>
|
276
SQ-2023-H6/src/main/java/org/usi/sq/util/CircularFifoQueue.java
Normal file
276
SQ-2023-H6/src/main/java/org/usi/sq/util/CircularFifoQueue.java
Normal file
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.usi.sq.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* CircularFifoQueue is a first-in first-out queue with a fixed size that
|
||||
* replaces its oldest element if full.
|
||||
* <p>
|
||||
* The removal order of a {@link CircularFifoQueue} is based on the
|
||||
* insertion order; elements are removed in the same order in which they
|
||||
* were added. The iteration order is the same as the removal order.
|
||||
* </p>
|
||||
* <p>
|
||||
* This queue prevents null objects from being added.
|
||||
* </p>
|
||||
*
|
||||
* @param <E> the type of elements in this collection
|
||||
* @since 4.0
|
||||
*/
|
||||
public class CircularFifoQueue<E> {
|
||||
|
||||
/** Serialization version. */
|
||||
private static final long serialVersionUID = -8423413834657610406L;
|
||||
|
||||
/** Underlying storage array. */
|
||||
private transient E[] elements;
|
||||
|
||||
/** Array index of first (oldest) queue element. */
|
||||
private transient int start = 0;
|
||||
|
||||
/**
|
||||
* Index mod maxElements of the array position following the last queue
|
||||
* element. Queue elements start at elements[start] and "wrap around"
|
||||
* elements[maxElements-1], ending at elements[decrement(end)].
|
||||
* For example, elements = {c,a,b}, start=1, end=1 corresponds to
|
||||
* the queue [a,b,c].
|
||||
*/
|
||||
private transient int end = 0;
|
||||
|
||||
/** Flag to indicate if the queue is currently full. */
|
||||
private transient boolean full = false;
|
||||
|
||||
/** Capacity of the queue. */
|
||||
private final int maxElements;
|
||||
|
||||
/**
|
||||
* Constructor that creates a queue with the default size of 32.
|
||||
*/
|
||||
public CircularFifoQueue() {
|
||||
this(32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that creates a queue with the specified size.
|
||||
*
|
||||
* @param size the size of the queue (cannot be changed)
|
||||
* @throws IllegalArgumentException if the size is < 1
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public CircularFifoQueue(final int size) {
|
||||
if (size <= 0) {
|
||||
throw new IllegalArgumentException("The size must be greater than 0");
|
||||
}
|
||||
elements = (E[]) new Object[size];
|
||||
maxElements = elements.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the capacity limit of this queue has been reached,
|
||||
* i.e. the number of elements stored in the queue equals its maximum size.
|
||||
*
|
||||
* @return {@code true} if the capacity limit has been reached, {@code false} otherwise
|
||||
* @since 4.1
|
||||
*/
|
||||
public boolean isAtFullCapacity() {
|
||||
return size() == maxElements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given element to this queue. If the queue is full, the least recently added
|
||||
* element is discarded so that a new element can be inserted.
|
||||
*
|
||||
* @param element the element to add
|
||||
* @return true, always
|
||||
* @throws NullPointerException if the given element is null
|
||||
*/
|
||||
public boolean add(final E element) {
|
||||
if (null == element) {
|
||||
throw new NullPointerException("Attempted to add null object to queue");
|
||||
}
|
||||
|
||||
if (isAtFullCapacity()) {
|
||||
remove();
|
||||
}
|
||||
|
||||
elements[end++] = element;
|
||||
|
||||
if (end >= maxElements) {
|
||||
end = 0;
|
||||
}
|
||||
|
||||
if (end == start) {
|
||||
full = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given element to this queue. If the queue is full, the least recently added
|
||||
* element is discarded so that a new element can be inserted.
|
||||
*
|
||||
* @param element the element to add
|
||||
* @return true, always
|
||||
* @throws NullPointerException if the given element is null
|
||||
*/
|
||||
public boolean offer(final E element) {
|
||||
return add(element);
|
||||
}
|
||||
|
||||
/**
|
||||
* Increments the internal index.
|
||||
*
|
||||
* @param index the index to increment
|
||||
* @return the updated index
|
||||
*/
|
||||
private int increment(int index) {
|
||||
index++;
|
||||
if (index >= maxElements) {
|
||||
index = 0;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrements the internal index.
|
||||
*
|
||||
* @param index the index to decrement
|
||||
* @return the updated index
|
||||
*/
|
||||
private int decrement(int index) {
|
||||
index--;
|
||||
if (index < 0) {
|
||||
index = maxElements - 1;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this queue is empty; false otherwise.
|
||||
*
|
||||
* @return true if this queue is empty
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
public E remove() {
|
||||
if (isEmpty()) {
|
||||
throw new NoSuchElementException("queue is empty");
|
||||
}
|
||||
|
||||
final E element = elements[start];
|
||||
if (null != element) {
|
||||
elements[start++] = null;
|
||||
|
||||
if (start >= maxElements) {
|
||||
start = 0;
|
||||
}
|
||||
full = false;
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of elements stored in the queue.
|
||||
*
|
||||
* @return this queue's size
|
||||
*/
|
||||
public int size() {
|
||||
int size = 0;
|
||||
|
||||
if (end < start) {
|
||||
size = maxElements - start + end;
|
||||
} else if (end == start) {
|
||||
size = full ? maxElements : 0;
|
||||
} else {
|
||||
size = end - start;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns an iterator over this queue's elements.
|
||||
*
|
||||
* @return an iterator over this queue's elements
|
||||
*/
|
||||
public Iterator<E> iterator() {
|
||||
return new Iterator<E>() {
|
||||
|
||||
private int index = start;
|
||||
private int lastReturnedIndex = -1;
|
||||
private boolean isFirst = full;
|
||||
|
||||
public boolean hasNext() {
|
||||
return isFirst || index != end;
|
||||
}
|
||||
|
||||
public E next() {
|
||||
if (!hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
isFirst = false;
|
||||
lastReturnedIndex = index;
|
||||
index = increment(index);
|
||||
return elements[lastReturnedIndex];
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
if (lastReturnedIndex == -1) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
// First element can be removed quickly
|
||||
if (lastReturnedIndex == start) {
|
||||
CircularFifoQueue.this.remove();
|
||||
lastReturnedIndex = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
int pos = lastReturnedIndex + 1;
|
||||
if (start < lastReturnedIndex && pos < end) {
|
||||
// shift in one part
|
||||
System.arraycopy(elements, pos, elements, lastReturnedIndex, end - pos);
|
||||
} else {
|
||||
// Other elements require us to shift the subsequent elements
|
||||
while (pos != end) {
|
||||
if (pos >= maxElements) {
|
||||
elements[pos - 1] = elements[0];
|
||||
pos = 0;
|
||||
} else {
|
||||
elements[decrement(pos)] = elements[pos];
|
||||
pos = increment(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lastReturnedIndex = -1;
|
||||
end = decrement(end);
|
||||
elements[end] = null;
|
||||
full = false;
|
||||
index = decrement(index);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package org.usi.sq.util;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class CircularFifoQueueTest {
|
||||
|
||||
private void testIteratorEmpty(Iterator<?> it) {
|
||||
assertFalse(it.hasNext());
|
||||
assertThrows(NoSuchElementException.class, it::next);
|
||||
}
|
||||
|
||||
private <T> void testIteratorNext(Iterator<T> it, T e) {
|
||||
assertTrue(it.hasNext());
|
||||
assertEquals(e, it.next());
|
||||
}
|
||||
|
||||
private <T> void testQueueAll(int initQueueSize, List<T> values, long removeQueueCount, List<Integer> itrRemoveIndexes) {
|
||||
final Set<Integer> removeIndexesSet = new HashSet<>(itrRemoveIndexes);
|
||||
|
||||
final CircularFifoQueue<T> queue = new CircularFifoQueue<>(initQueueSize);
|
||||
for (T e : values) assertTrue(queue.offer(e));
|
||||
|
||||
int queueSizeAfterOffers = Math.min(initQueueSize, values.size());
|
||||
for (int i = 0; i < removeQueueCount; i++) {
|
||||
assertEquals(values.get(values.size() - queueSizeAfterOffers + i), queue.remove());
|
||||
}
|
||||
|
||||
assertEquals(queueSizeAfterOffers - removeQueueCount, queue.size());
|
||||
assertEquals(queue.size() == initQueueSize, queue.isAtFullCapacity());
|
||||
|
||||
final Iterator<T> it = queue.iterator();
|
||||
final List<T> notRemovedValues = new ArrayList<>(values.size());
|
||||
|
||||
final List<T> expected = values.subList(Math.max(0, values.size() - queue.size()), values.size());
|
||||
|
||||
// Test Iteration
|
||||
for (int i = 0; i < expected.size(); i++) {
|
||||
T e = expected.get(i);
|
||||
testIteratorNext(it, e);
|
||||
|
||||
if (removeIndexesSet.contains(i)) {
|
||||
it.remove();
|
||||
assertThrows(IllegalStateException.class, it::remove); // removing again causes explosion
|
||||
} else {
|
||||
notRemovedValues.add(e);
|
||||
}
|
||||
}
|
||||
testIteratorEmpty(it);
|
||||
|
||||
// Test removal
|
||||
assertEquals(notRemovedValues.size(), queue.size());
|
||||
final Iterator<T> itNew = queue.iterator();
|
||||
for (T e : notRemovedValues) testIteratorNext(itNew, e);
|
||||
testIteratorEmpty(itNew);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testIterator() {
|
||||
assertThrows(IllegalArgumentException.class, () -> new CircularFifoQueue<Void>(0));
|
||||
assertThrows(NoSuchElementException.class, () -> new CircularFifoQueue<Void>().remove());
|
||||
assertThrows(NullPointerException.class, () -> new CircularFifoQueue<Void>().offer(null));
|
||||
|
||||
testQueueIteratorRemove(10, Arrays.asList(1, 2, 3), 0, 2);
|
||||
testQueueIteratorRemove(3, Arrays.asList(1, 2, 3), 0, 2);
|
||||
testQueueIteratorRemove(3, Arrays.asList(1, 2, 3), 0, 2);
|
||||
testQueueIteratorRemove(2, Arrays.asList(1, 2, 3));
|
||||
testQueueIteratorRemove(4, Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9), 1, 3);
|
||||
testQueueAll(7, Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13), 4, Arrays.asList(1, 3));
|
||||
|
||||
testQueueIteratorRemove(4, Arrays.asList(1, 2, 3, 4, 5), 1, 3);
|
||||
testQueueIteratorRemove(10, Collections.emptyList());
|
||||
testQueueQueueRemove(4, Arrays.asList(1, 2, 3, 4, 5), 1);
|
||||
}
|
||||
|
||||
private void testQueueQueueRemove(int i, List<Integer> asList, int i1) {
|
||||
testQueueAll(i, asList, i1, Collections.emptyList());
|
||||
}
|
||||
|
||||
private void testQueueIteratorRemove(int i, List<Integer> asList, Integer... asList1) {
|
||||
testQueueAll(i, asList, 0, Arrays.asList(asList1));
|
||||
}
|
||||
}
|
Reference in a new issue