package com.fasterxml.jackson.jr.ob.impl;

import java.util.*;

A specialized Map implementation that will collect entries during building, but only materialize full lookup structure when needed; that is, actual building of hash lookup is deferred.

Inspired by lazily initialized Map used by Boon library.

/** * A specialized {@link java.util.Map} implementation that will collect * entries during building, but only materialize full lookup structure * when needed; that is, actual building of hash lookup is deferred. *<p> * Inspired by lazily initialized Map used by Boon library. */
public class DeferredMap extends AbstractMap<String, Object> { private Map<String, Object> _map; private Object[] _entries; private int _end; private final boolean _ordered; public DeferredMap(boolean ordered) { this(ordered, 4); } public DeferredMap(boolean ordered, int initialSize) { _ordered = ordered; } @Override public Object put(String key, Object value) { if (_map == null) { if (_entries == null) { _entries = new Object[8]; } else if (_end == _entries.length) { final int newSize = _newSize(_end); _entries = Arrays.copyOf(_entries, newSize); } _entries[_end] = key; _entries[++_end] = value; ++_end; // here's assuming no dups are added return null; } return _map.put(key, value); } @Override public Set<Entry<String, Object>> entrySet() { buildIfNeeded(); return _map.entrySet(); } @Override public int size() { // assuming no dups; otherwise could overestimate return (_map == null) ? (_end >> 1) : _map.size(); } @Override public boolean isEmpty() { return (_map == null) ? (_end == 0) : _map.isEmpty(); } @Override public boolean containsValue(Object value) { buildIfNeeded(); return _map.containsValue(value); } @Override public boolean containsKey(Object key) { buildIfNeeded(); return _map.containsKey(key); } @Override public Object get(Object key) { buildIfNeeded(); return _map.get( key ); } @Override public Object remove(Object key) { buildIfNeeded(); return _map.remove( key ); } @Override public void clear() { if (_map != null ) { _map.clear(); } else { _end = 0; } } @Override public Set<String> keySet() { buildIfNeeded(); return _map.keySet(); } @Override public Collection<Object> values() { buildIfNeeded(); return _map.values(); } @Override public boolean equals(Object other) { buildIfNeeded(); return _map.equals(other); } @Override public int hashCode() { buildIfNeeded(); return _map.hashCode(); } @Override public String toString() { buildIfNeeded(); return _map.toString(); } @Override protected Object clone() throws CloneNotSupportedException { buildIfNeeded(); if (_map instanceof HashMap) { return ((HashMap<?,?>)_map).clone(); } return new HashMap<String, Object>(_map); } protected void buildIfNeeded() { if (_map == null) { // translate from entry count (which is 2 * size) bit down; trying to avoid // having to resize... i.e. use 3/4 of entry count _map = _buildMap(_end >> 2); for (int i = 0; i < _end; i += 2) { _map.put((String) _entries[i], _entries[i+1]); } _entries = null; } } private final int _newSize(int size) { if (size < 200) { return size+size; } // note: MUST ensure it's divisible by two (that is, last bit is 0), because // always adding values in pairs, but checking size before add if (size < 2000) { return size + ((size>>1) & ~1); } return size + ((size>>2) & ~1); } protected Map<String, Object> _buildMap(int expSize) { int size; if (expSize < 4) { size = 4; } else { // should add ~1/3 as size is rounded up to power of 3 size = expSize + (3 * (expSize >> 3)); } if (_ordered) { return new LinkedHashMap<String, Object>(size); } return new HashMap<String, Object>(size); } }