diff --git a/.gitignore b/.gitignore
index a870eaf..4f94b89 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
-.idea/
-long-map.iml
\ No newline at end of file
+.idea/*
+*.iml
+target/*
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 36c092b..88d2c48 100644
--- a/pom.xml
+++ b/pom.xml
@@ -18,8 +18,8 @@
3.3
UTF-8
- 1.8
- 1.8
+ 9
+ 9
@@ -27,10 +27,16 @@
- junit
- junit
- 4.12
+ org.junit.jupiter
+ junit-jupiter-engine
+ 5.4.0
test
+
+ org.junit.jupiter
+ junit-jupiter-api
+ 5.4.0
+ compile
+
diff --git a/src/main/java/de/comparus/opensource/longmap/LongMap.java b/src/main/java/de/comparus/opensource/longmap/LongMap.java
index adbf242..4612631 100644
--- a/src/main/java/de/comparus/opensource/longmap/LongMap.java
+++ b/src/main/java/de/comparus/opensource/longmap/LongMap.java
@@ -2,16 +2,22 @@
public interface LongMap {
V put(long key, V value);
+
V get(long key);
+
V remove(long key);
boolean isEmpty();
+
boolean containsKey(long key);
+
boolean containsValue(V value);
long[] keys();
+
V[] values();
long size();
+
void clear();
}
diff --git a/src/main/java/de/comparus/opensource/longmap/LongMapImpl.java b/src/main/java/de/comparus/opensource/longmap/LongMapImpl.java
index 2f0b54b..1de694a 100644
--- a/src/main/java/de/comparus/opensource/longmap/LongMapImpl.java
+++ b/src/main/java/de/comparus/opensource/longmap/LongMapImpl.java
@@ -1,43 +1,180 @@
package de.comparus.opensource.longmap;
+import java.util.Objects;
+
public class LongMapImpl implements LongMap {
+
+ private static final int DEFAULT_INITIAL_CAPACITY = 16;
+ private static final int DEFAULT_INCREASE_CAPACITY = 2;
+ private static final float DEFAULT_LOAD_FACTOR = 0.75F;
+ private int size;
+ private float threshold;
+ private Node[] table;
+
+ public LongMapImpl() {
+ threshold = (int) (DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
+ table = new Node[DEFAULT_INITIAL_CAPACITY];
+ }
+
+ private static class Node {
+ private V value;
+ private long key;
+ private Node next;
+
+ public Node(V value, long key, Node next) {
+ this.value = value;
+ this.key = key;
+ this.next = next;
+ }
+ }
+
public V put(long key, V value) {
- return null;
+ if (threshold < size) {
+ resize();
+ }
+ Node[] currentTable = table;
+ int index = getIndex(key);
+ if (currentTable[index] == null) {
+ currentTable[index] = new Node<>(value, key, null);
+ size++;
+ return value;
+ }
+
+ Node currentNode = currentTable[index];
+ while (currentNode.next != null || key == currentNode.key) {
+ if (key == currentNode.key) {
+ currentNode.value = value;
+ return value;
+ }
+ currentNode = currentNode.next;
+ }
+
+ currentNode.next = new Node<>(value, key, null);
+ size++;
+
+ return value;
}
public V get(long key) {
+ Node currentNode = table[getIndex(key)];
+ while (currentNode != null) {
+ if (key == currentNode.key) {
+ return currentNode.value;
+ }
+ currentNode = currentNode.next;
+ }
return null;
}
public V remove(long key) {
+ int index = getIndex(key);
+ if (isEmpty() || table[index] == null) {
+ return null;
+ }
+ Node currentNode = table[index];
+ if (currentNode.key == key) {
+ table[index] = currentNode.next;
+ size--;
+ return currentNode.value;
+ }
+ while (currentNode.next != null) {
+ if (currentNode.next.key == key) {
+ V value = currentNode.next.value;
+ currentNode.next = currentNode.next.next;
+ size--;
+ return value;
+ }
+ currentNode = currentNode.next;
+ }
return null;
}
public boolean isEmpty() {
- return false;
+ return size == 0;
}
public boolean containsKey(long key) {
+ Node currentNode = table[getIndex(key)];
+ while (currentNode != null) {
+ if (key == currentNode.key) {
+ return true;
+ }
+ currentNode = currentNode.next;
+ }
return false;
}
public boolean containsValue(V value) {
+ Node[] currentTable = table;
+ for (Node vNode : currentTable) {
+ Node currentNode = vNode;
+ while (currentNode != null) {
+ if (Objects.equals(value, currentNode.value)) {
+ return true;
+ }
+ currentNode = currentNode.next;
+ }
+ }
return false;
}
public long[] keys() {
- return null;
+ Node[] currentTable = table;
+ long[] keysArray = new long[size];
+ int k = 0;
+ for (Node vNode : currentTable) {
+ Node currentNode = vNode;
+ while (currentNode != null) {
+ keysArray[k++] = currentNode.key;
+ currentNode = currentNode.next;
+ }
+ }
+ return keysArray;
}
public V[] values() {
- return null;
+ Node[] currentTable = table;
+ V[] valuesArray = (V[]) new Object[size];
+ int k = 0;
+ for (Node vNode : currentTable) {
+ Node currentNode = vNode;
+ while (currentNode != null) {
+ valuesArray[k++] = currentNode.value;
+ currentNode = currentNode.next;
+ }
+ }
+ return valuesArray;
}
public long size() {
- return 0;
+ return size;
}
public void clear() {
+ Node[] currentTable = table;
+ if (currentTable != null && size > 0) {
+ size = 0;
+ for (int i = 0; i < currentTable.length; i++) {
+ currentTable[i] = null;
+ }
+ }
+ }
+
+ private int getIndex(long key) {
+ return (int) Math.abs(key % table.length);
+ }
+ private void resize() {
+ Node[] oldTable = table;
+ size = 0;
+ table = new Node[oldTable.length * DEFAULT_INCREASE_CAPACITY];
+ threshold = table.length * DEFAULT_LOAD_FACTOR;
+ for (int i = 0; i < oldTable.length; i++) {
+ Node nodeOld = oldTable[i];
+ while (nodeOld != null) {
+ put(nodeOld.key, nodeOld.value);
+ nodeOld = nodeOld.next;
+ }
+ }
}
}
diff --git a/src/main/java/de/comparus/opensource/longmap/LongMapImplTest.java b/src/main/java/de/comparus/opensource/longmap/LongMapImplTest.java
new file mode 100644
index 0000000..62c038a
--- /dev/null
+++ b/src/main/java/de/comparus/opensource/longmap/LongMapImplTest.java
@@ -0,0 +1,139 @@
+package de.comparus.opensource.longmap;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class LongMapImplTest {
+
+ @Test
+ public void testMethodSize_Ok() {
+ LongMap map = new LongMapImpl<>();
+ map.put(1L, "First");
+ assertEquals(1, map.size());
+ map.put(2L, "Second");
+ assertEquals(2, map.size());
+ map.put(17L, "Third");
+ assertEquals(3, map.size());
+ map.put(-100L, "Forth");
+ assertEquals(4, map.size());
+ }
+
+ @Test
+ public void testMethodPut_Ok() {
+ LongMap map = new LongMapImpl<>();
+ assertEquals("first", map.put(20L, "first"));
+ assertEquals("second", map.put(120L, "second"));
+ assertEquals("third", map.put(-120L, "third"));
+ assertEquals("forth", map.put(0L, "forth"));
+ assertEquals("fifth", map.put(1L, "fifth"));
+ assertEquals("One hundred", map.put(8L, "One hundred"));
+ }
+
+ @Test
+ public void testMethodPutForCorrectWorkSameKey_Ok() {
+ LongMap map = new LongMapImpl<>();
+ assertEquals(10, map.put(100L, 10));
+ assertEquals(20, map.put(100L, 20));
+ assertEquals(-10020, map.put(100L, -10020));
+ assertNull(map.put(100L, null));
+ }
+
+ @Test
+ public void testMethodGet_Ok() {
+ LongMap map = new LongMapImpl<>();
+ assertEquals(map.put(20L, "first"), map.get(20L));
+ assertEquals(map.put(-20L, "second"), map.get(-20L));
+ assertEquals(map.put(120L, "third"), map.get(120L));
+ assertEquals(map.put(220L, null), map.get(220L));
+ assertNull(map.get(-123L));
+ }
+
+ @Test
+ public void testMethodRemove_Ok() {
+ LongMap map = new LongMapImpl<>();
+ assertEquals(map.put(20L, "first"), map.remove(20L));
+ assertEquals(map.put(-20L, "second"), map.remove(-20L));
+ assertEquals(map.put(120L, "third"), map.remove(120L));
+ assertNull(map.remove(120L));
+ assertEquals(map.put(220L, null), map.remove(220L));
+ assertNull(map.remove(-11220L));
+ map.put(20L, "first");
+ map.put(52L, "second");
+ assertEquals(map.put(36L, "third"), map.remove(36L));
+ }
+
+ @Test
+ public void testMethodIsEmpty_Ok() {
+ LongMap map = new LongMapImpl<>();
+ assertTrue(map.isEmpty());
+ map.put(10L, "value");
+ assertFalse(map.isEmpty());
+ }
+
+ @Test
+ public void testMethodClear_Ok() {
+ LongMap map = new LongMapImpl<>();
+ map.clear();
+ assertEquals(0, map.size());
+ map.put(10L, 1);
+ map.put(1L, 10);
+ assertNotEquals(0, map.size());
+ map.clear();
+ assertEquals(0, map.size());
+ }
+
+ @Test
+ public void testMethodContainKey_Ok() {
+ LongMap map = new LongMapImpl<>();
+ map.put(0L, 0);
+ assertTrue(map.containsKey(0));
+ assertFalse(map.containsKey(1000L));
+ }
+
+ @Test
+ public void testMethodContainValue_Ok() {
+ LongMap map = new LongMapImpl<>();
+ map.put(100L, "One");
+ assertTrue(map.containsValue("One"));
+ assertFalse(map.containsValue("Three"));
+ }
+
+ @Test
+ public void testMethodKeys_Ok() {
+ LongMap map = new LongMapImpl<>();
+ map.put(20L, "first");
+ map.put(36L, "first");
+ map.put(19L, "first");
+ map.put(-20L, "second");
+ map.put(120L, "third");
+ map.put(220L, null);
+ long[] expected = new long[]{19L, 20L, 36L, -20L, 120L, 220L};
+ long[] actual = map.keys();
+ Assertions.assertArrayEquals(expected, actual);
+ }
+
+ @Test
+ public void testMethodValues_Ok() {
+ LongMap map = new LongMapImpl<>();
+ Integer[] expected = new Integer[10];
+ for (int i = 0; i < 10; i++) {
+ map.put(i, i);
+ expected[i] = i;
+ }
+ Assertions.assertArrayEquals(expected, map.values());
+ }
+
+ @Test
+ public void testForResize_Ok() {
+ LongMap map = new LongMapImpl<>();
+ for (int i = 0; i < 10000; i++) {
+ map.put(i, i);
+ }
+ assertEquals(10000, map.size());
+ }
+}