PageRenderTime 45ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/src/main/java/com/github/jsonj/SimpleStringKeyMap.java

http://github.com/jillesvangurp/jsonj
Java | 345 lines | 287 code | 53 blank | 5 comment | 33 complexity | 04045442bbe13d6ba53980005a6b67b1 MD5 | raw file
  1. package com.github.jsonj;
  2. import org.apache.commons.lang3.Validate;
  3. import java.io.Serializable;
  4. import java.util.ArrayList;
  5. import java.util.Arrays;
  6. import java.util.Collection;
  7. import java.util.Collections;
  8. import java.util.ConcurrentModificationException;
  9. import java.util.HashSet;
  10. import java.util.Iterator;
  11. import java.util.Map;
  12. import java.util.NoSuchElementException;
  13. import java.util.Objects;
  14. import java.util.Set;
  15. /**
  16. * Performant array list based map for small number of entries. Get performs linearly for number of entries however, it
  17. * uses vastly less memory and it is actually fast enough for small numbers of entries.
  18. */
  19. public class SimpleStringKeyMap<V> implements Map<String, V>, Serializable {
  20. private static final long serialVersionUID = 7650009698202273725L;
  21. private boolean immutable=false;
  22. String[] keysArr=new String[3];
  23. private final ArrayList<V> values = new ArrayList<>();
  24. public void makeImmutable() {
  25. immutable=true;
  26. }
  27. public boolean isMutable() {
  28. return !immutable;
  29. }
  30. @Override
  31. public int size() {
  32. return values.size();
  33. }
  34. @Override
  35. public boolean isEmpty() {
  36. return values.size() == 0;
  37. }
  38. @Override
  39. public boolean containsKey(Object key) {
  40. return containsKey((String)key);
  41. }
  42. public boolean containsKey(String key) {
  43. for(int i=0; i<values.size();i++) {
  44. String k = keysArr[i];
  45. if(key.equals(k)) {
  46. return true;
  47. }
  48. }
  49. return false;
  50. }
  51. @Override
  52. public boolean containsValue(Object value) {
  53. for(V e: values) {
  54. if(e.equals(value)) {
  55. return true;
  56. }
  57. }
  58. return false;
  59. }
  60. @Override
  61. public V get(Object key) {
  62. return getWithKey((String)key);
  63. }
  64. public V getWithKey(String key) {
  65. int index = getIndex(key);
  66. if(index>=0) {
  67. return values.get(index);
  68. } else {
  69. return null;
  70. }
  71. }
  72. private int getIndex(String key) {
  73. int j=0;
  74. for(int i=0; i<values.size();i++) {
  75. String k = keysArr[i];
  76. if(key.equals(k)) {
  77. return j;
  78. }
  79. j++;
  80. }
  81. return -1;
  82. }
  83. @Override
  84. public V put(String key, V value) {
  85. if(immutable) {
  86. throw new IllegalStateException("object is immutable");
  87. }
  88. Validate.notNull(key);
  89. int index = getIndex(key);
  90. if(index >=0) {
  91. values.set(index, value);
  92. } else {
  93. if(values.size()+1<keysArr.length) {
  94. // dynamically grow array
  95. keysArr = Arrays.copyOf(keysArr, keysArr.length + 3);
  96. }
  97. keysArr[values.size()] = key;
  98. values.add(value);
  99. }
  100. return value;
  101. }
  102. @Override
  103. public V remove(Object key) {
  104. if(immutable) {
  105. throw new IllegalStateException("object is immutable");
  106. }
  107. int index = getIndex((String)key);
  108. if(index >=0) {
  109. System.arraycopy(keysArr,index+1,keysArr,index,keysArr.length-1-index);
  110. return values.remove(index);
  111. } else {
  112. return null;
  113. }
  114. }
  115. @Override
  116. public void putAll(java.util.Map<? extends String, ? extends V> m) {
  117. if(immutable) {
  118. throw new IllegalStateException("object is immutable");
  119. }
  120. for (Entry<? extends String, ? extends V> e : m.entrySet()) {
  121. put(e.getKey(), e.getValue());
  122. }
  123. };
  124. @Override
  125. public void clear() {
  126. keysArr = new String[5];
  127. values.clear();
  128. }
  129. @Override
  130. public Set<String> keySet() {
  131. Set<String> result = new HashSet<>();
  132. for(int i=0; i<values.size();i++) {
  133. result.add(keysArr[i]);
  134. }
  135. return result;
  136. }
  137. @Override
  138. public Collection<V> values() {
  139. return Collections.unmodifiableList(values);
  140. }
  141. @Override
  142. public Set<Entry<String, V>> entrySet() {
  143. return new EntrySet(this);
  144. }
  145. private class EntrySet implements Set<Entry<String, V>> {
  146. private final SimpleStringKeyMap<V> owner;
  147. public EntrySet(SimpleStringKeyMap<V> simpleMap) {
  148. this.owner = simpleMap;
  149. }
  150. @Override
  151. public int size() {
  152. return owner.size();
  153. }
  154. @Override
  155. public boolean isEmpty() {
  156. return owner.isEmpty();
  157. }
  158. @Override
  159. public boolean contains(Object o) {
  160. @SuppressWarnings("unchecked")
  161. Entry<String, JsonElement> e = (Entry<String, JsonElement>) o;
  162. int index = owner.getIndex(e.getKey());
  163. if(index >= 0) {
  164. return values.get(index).equals(e.getValue());
  165. } else {
  166. return false;
  167. }
  168. }
  169. @Override
  170. public Iterator<Entry<String, V>> iterator() {
  171. return new Iterator<Map.Entry<String,V>>() {
  172. int startSize=size();
  173. int index=0;
  174. @Override
  175. public boolean hasNext() {
  176. if(size() != startSize) {
  177. throw new ConcurrentModificationException();
  178. }
  179. return index < values.size();
  180. }
  181. @Override
  182. public Entry<String, V> next() {
  183. if(hasNext()) {
  184. EntryImpl next = new EntryImpl(keysArr[index], values.get(index));
  185. index++;
  186. return next;
  187. } else {
  188. throw new NoSuchElementException();
  189. }
  190. }
  191. @Override
  192. public void remove() {
  193. if(immutable) {
  194. throw new IllegalStateException("object is immutable");
  195. }
  196. if(owner.size() == 0) {
  197. throw new NoSuchElementException("The entry set is empty");
  198. }
  199. if(index == 0) {
  200. throw new IllegalStateException("next has not been called yet");
  201. }
  202. int removeIndex = index-1;
  203. System.arraycopy(keysArr,removeIndex+1,keysArr,removeIndex,keysArr.length-1-removeIndex);
  204. values.remove(removeIndex);
  205. index--;
  206. startSize--;
  207. }
  208. };
  209. }
  210. @Override
  211. public Object[] toArray() {
  212. @SuppressWarnings("unchecked")
  213. Entry<String,V>[] result = new Entry[owner.size()];
  214. int i=0;
  215. for(Entry<String,V> e: this) {
  216. result[i] = e;
  217. i++;
  218. }
  219. return result;
  220. }
  221. @SuppressWarnings("unchecked")
  222. @Override
  223. public <T> T[] toArray(T[] a) {
  224. return (T[]) toArray();
  225. }
  226. @Override
  227. public boolean add(Entry<String, V> e) {
  228. throw new UnsupportedOperationException();
  229. }
  230. @Override
  231. public boolean remove(Object o) {
  232. throw new UnsupportedOperationException();
  233. }
  234. @Override
  235. public boolean containsAll(Collection<?> c) {
  236. for(Object o: c) {
  237. if(!contains(o)) {
  238. return false;
  239. }
  240. }
  241. return true;
  242. }
  243. @Override
  244. public boolean addAll(Collection<? extends java.util.Map.Entry<String, V>> c) {
  245. throw new UnsupportedOperationException();
  246. }
  247. @Override
  248. public boolean retainAll(Collection<?> c) {
  249. throw new UnsupportedOperationException();
  250. }
  251. @Override
  252. public boolean removeAll(Collection<?> c) {
  253. throw new UnsupportedOperationException();
  254. }
  255. @Override
  256. public void clear() {
  257. throw new UnsupportedOperationException();
  258. }
  259. }
  260. private class EntryImpl implements Entry<String, V> {
  261. private final String key;
  262. private final V value;
  263. public EntryImpl(String key, V value) {
  264. this.key = key;
  265. this.value = value;
  266. }
  267. @Override
  268. public String getKey() {
  269. return key;
  270. }
  271. @Override
  272. public V getValue() {
  273. return value;
  274. }
  275. @Override
  276. public V setValue(V value) {
  277. throw new UnsupportedOperationException("Entries are immutable");
  278. }
  279. @Override
  280. public boolean equals(Object obj) {
  281. return Objects.deepEquals(this, obj);
  282. }
  283. @Override
  284. public int hashCode() {
  285. return Objects.hash(key,value);
  286. }
  287. @Override
  288. public String toString() {
  289. return key +":"+value;
  290. }
  291. }
  292. }