com.oracle.coherence.common.collections.InflatableMap Maven / Gradle / Ivy
Show all versions of coherence Show documentation
/*
* Copyright (c) 2000, 2022, Oracle and/or its affiliates.
*
* Licensed under the Universal Permissive License v 1.0 as shown at
* https://oss.oracle.com/licenses/upl.
*/
package com.oracle.coherence.common.collections;
import java.io.Externalizable;
import java.io.IOException;
import java.io.NotActiveException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
/**
* An implementation of java.util.Map that is optimal (in terms of both size
* and speed) for very small sets of data but still works excellently with
* large sets of data. This implementation is not thread-safe.
*
* The InflatableMap implementation switches at runtime between several different
* sub-implementations for storing the Map of objects, described here:
*
*
* - "empty map" - a map that contains no data;
*
- "single entry" - a reference directly to a single map entry
*
- "Object[]" - a reference to an array of entries; the item limit for
* this implementation is determined by the THRESHOLD constant;
*
- "delegation" - for more than THRESHOLD items, a map is created to
* delegate the map management to; sub-classes can override the default
* delegation class (java.util.HashMap) by overriding the factory method
* instantiateMap.
*
*
* The InflatableMap implementation supports the null key value.
*
* @author cp 06/29/99
*/
public class InflatableMap
extends AbstractMap
implements Cloneable, Externalizable
{
// ----- constructors ---------------------------------------------------
/**
* Construct a InflatableMap.
*/
public InflatableMap()
{
}
/**
* Construct a InflatableMap with the same mappings as the given map.
*
* @param map the map whose mappings are to be placed in this map.
*/
public InflatableMap(Map extends K, ? extends V> map)
{
putAll(map);
}
// ----- Map interface --------------------------------------------------
/**
* Returns true
if this map contains no key-value mappings.
*
* @return true
if this map contains no key-value mappings
*/
public boolean isEmpty()
{
return m_nImpl == I_EMPTY;
}
/**
* Returns the number of key-value mappings in this map.
*
* @return the number of key-value mappings in this map
*/
public int size()
{
switch (m_nImpl)
{
case I_EMPTY:
return 0;
case I_SINGLE:
return 1;
case I_ARRAY_1: case I_ARRAY_2: case I_ARRAY_3: case I_ARRAY_4:
case I_ARRAY_5: case I_ARRAY_6: case I_ARRAY_7: case I_ARRAY_8:
return m_nImpl - I_ARRAY_1 + 1;
case I_OTHER:
return ((Map) m_oContents).size();
default:
throw new IllegalStateException();
}
}
/**
* Returns true
if this map contains a mapping for the specified
* key.
*
* @return true
if this map contains a mapping for the specified
* key, false
otherwise.
*/
public boolean containsKey(Object oKey)
{
switch (m_nImpl)
{
case I_EMPTY:
return false;
case I_SINGLE:
{
Object oKeyEntry = ((Map.Entry) m_oContents).getKey();
return Objects.equals(oKey, oKeyEntry);
}
case I_ARRAY_1: case I_ARRAY_2: case I_ARRAY_3: case I_ARRAY_4:
case I_ARRAY_5: case I_ARRAY_6: case I_ARRAY_7: case I_ARRAY_8:
{
// "Entry[]" implementation
Map.Entry[] aEntry = (Map.Entry[]) m_oContents;
int c = m_nImpl - I_ARRAY_1 + 1;
return indexOf(aEntry, c, oKey) >= 0;
}
case I_OTHER:
return ((Map) m_oContents).containsKey(oKey);
default:
throw new IllegalStateException();
}
}
/**
* Returns the value to which this map maps the specified key.
*
* @param oKey the key object
*
* @return the value to which this map maps the specified key,
* or null if the map contains no mapping for this key
*/
public V get(Object oKey)
{
switch (m_nImpl)
{
case I_EMPTY:
return null;
case I_SINGLE:
{
Map.Entry entry = (Map.Entry) m_oContents;
K entryKey = entry.getKey();
return Objects.equals(oKey, entryKey) ? entry.getValue() : null;
}
case I_ARRAY_1: case I_ARRAY_2: case I_ARRAY_3: case I_ARRAY_4:
case I_ARRAY_5: case I_ARRAY_6: case I_ARRAY_7: case I_ARRAY_8:
{
// "Entry[]" implementation
Map.Entry[] aEntry = (Map.Entry[]) m_oContents;
int c = m_nImpl - I_ARRAY_1 + 1;
int i = indexOf(aEntry, c, oKey);
return i < 0 ? null : aEntry[i].getValue();
}
case I_OTHER:
return ((Map) m_oContents).get(oKey);
default:
throw new IllegalStateException();
}
}
/**
* Associates the specified value with the specified key in this map.
*
* @param key key with which the specified value is to be associated
* @param value value to be associated with the specified key
*
* @return previous value associated with specified key, or null
* if there was no mapping for key
*/
public V put(K key, V value)
{
switch (m_nImpl)
{
case I_EMPTY:
m_oContents = instantiateEntry(key, value);
m_nImpl = I_SINGLE;
return null;
case I_SINGLE:
{
Map.Entry entry = (Map.Entry) m_oContents;
K entryKey = entry.getKey();
V prevValue = null;
if (Objects.equals(key, entryKey))
{
prevValue = entry.getValue();
entry.setValue(value);
}
else
{
// grow to array implementation
Map.Entry[] aEntry = new Map.Entry[THRESHOLD];
aEntry[0] = entry;
aEntry[1] = instantiateEntry(key, value);
m_nImpl = I_ARRAY_2;
m_oContents = aEntry;
}
return prevValue;
}
case I_ARRAY_1: case I_ARRAY_2: case I_ARRAY_3: case I_ARRAY_4:
case I_ARRAY_5: case I_ARRAY_6: case I_ARRAY_7: case I_ARRAY_8:
{
// "Entry[]" implementation
int nImpl = m_nImpl;
Map.Entry[] aEntry = (Map.Entry[]) m_oContents;
int c = nImpl - I_ARRAY_1 + 1;
int i = indexOf(aEntry, c, key);
if (i >= 0)
{
Map.Entry entry = aEntry[i];
V prevValue = entry.getValue();
entry.setValue(value);
return prevValue;
}
// check if adding the object exceeds the "lite" threshold
if (c >= THRESHOLD)
{
// time to switch to a different map implementation
Map map = instantiateMap();
for (i = 0; i < c; ++i)
{
Map.Entry entry = aEntry[i];
map.put(entry.getKey(), entry.getValue());
}
map.put(key, value);
m_nImpl = I_OTHER;
m_oContents = map;
}
else
{
// use the next available element in the array
aEntry[c] = instantiateEntry(key, value);
m_nImpl = (byte) (nImpl + 1);
}
return null;
}
case I_OTHER:
return ((Map) m_oContents).put(key, value);
default:
throw new IllegalStateException();
}
}
/**
* Removes the mapping for this key from this map if present.
* Expensive: updates both the underlying cache and the local cache.
*
* @param oKey key whose mapping is to be removed from the map
*
* @return previous value associated with specified key, or null
* if there was no mapping for key. A null
return can
* also indicate that the map previously associated null
* with the specified key, if the implementation supports
* null
values.
*/
public V remove(Object oKey)
{
switch (m_nImpl)
{
case I_EMPTY:
return null;
case I_SINGLE:
{
Map.Entry entry = (Map.Entry) m_oContents;
K entryKey = entry.getKey();
V prevValue = null;
if (Objects.equals(oKey, entryKey))
{
prevValue = entry.getValue();
m_nImpl = I_EMPTY;
m_oContents = null;
}
return prevValue;
}
case I_ARRAY_1: case I_ARRAY_2: case I_ARRAY_3: case I_ARRAY_4:
case I_ARRAY_5: case I_ARRAY_6: case I_ARRAY_7: case I_ARRAY_8:
{
// "Entry[]" implementation
int nImpl = m_nImpl;
Map.Entry[] aEntry = (Map.Entry[]) m_oContents;
int c = nImpl - I_ARRAY_1 + 1;
int i = indexOf(aEntry, c, oKey);
if (i < 0)
{
return null;
}
V prevValue = aEntry[i].getValue();
if (c == 1)
{
m_nImpl = I_EMPTY;
m_oContents = null;
}
else
{
System.arraycopy(aEntry, i + 1, aEntry, i, c - i - 1);
aEntry[c-1] = null;
m_nImpl = (byte) --nImpl;
}
return prevValue;
}
case I_OTHER:
{
Map map = (Map) m_oContents;
V prevValue = map.remove(oKey);
checkShrinkFromOther();
return prevValue;
}
default:
throw new IllegalStateException();
}
}
/**
* Clear all key/value mappings.
*/
public void clear()
{
m_nImpl = I_EMPTY;
m_oContents = null;
}
// ----- Cloneable interface --------------------------------------------
/**
* Create a clone of the ImmutableArrayList.
*
* @return a clone of this list
*/
public Object clone()
{
InflatableMap that;
try
{
that = (InflatableMap) super.clone();
}
catch (CloneNotSupportedException e)
{
throw ensureRuntimeException(e);
}
switch (this.m_nImpl)
{
case I_EMPTY:
// nothing to do
break;
case I_SINGLE:
{
Map.Entry entry = (Map.Entry) m_oContents;
that.m_oContents = that.instantiateEntry(entry.getKey(), entry.getValue());
}
break;
case I_ARRAY_1: case I_ARRAY_2: case I_ARRAY_3: case I_ARRAY_4:
case I_ARRAY_5: case I_ARRAY_6: case I_ARRAY_7: case I_ARRAY_8:
{
Map.Entry[] aEntryThis = (Map.Entry[]) this.m_oContents;
Map.Entry[] aEntryThat = new Map.Entry[THRESHOLD];
for (int i = 0, c = m_nImpl - I_ARRAY_1 + 1; i < c; ++i)
{
Map.Entry entryThis = aEntryThis[i];
aEntryThat[i] = that.instantiateEntry(
entryThis.getKey(), entryThis.getValue());
}
that.m_oContents = aEntryThat;
}
break;
case I_OTHER:
Map mapThis = (Map) this.m_oContents;
Map mapThat = that.instantiateMap();
mapThat.putAll(mapThis);
that.m_oContents = mapThat;
break;
default:
throw new IllegalStateException();
}
return that;
}
// ----- inner class: EntrySet ------------------------------------------
/**
* Returns a set view of the mappings contained in this map. Each element
* in the returned set is an {@link java.util.Map.Entry Map Entry}. The set is backed by the
* map, so changes to the map are reflected in the set, and vice-versa.
* If the map is modified while an iteration over the set is in progress
* (except by the iterator's own remove
operation, or by the
* setValue
operation on a map entry returned by the iterator)
* the results of the iteration are undefined. The set supports element
* removal, which removes the corresponding mapping from the map, via the
* Iterator.remove
, Set.remove
, removeAll
,
* retainAll
and clear
operations. It is not expected to
* support the add
or addAll
operations.
*
* @return a set view of the mappings contained in this map
*/
public Set> entrySet()
{
return instantiateEntrySet();
}
/**
* A Set of entries backed by this Map.
*/
protected class EntrySet
extends AbstractSet>
implements Serializable
{
/**
* Returns an iterator over the elements contained in this collection.
*
* @return an iterator over the elements contained in this collection
*/
public Iterator> iterator()
{
InflatableMap map = InflatableMap.this;
int c = map.size();
return c == 0
? NULL_ITERATOR
: new EntryIterator<>(map, (Map.Entry[]) toArray(new Map.Entry[c]));
}
/**
* Returns true
if this Set is empty.
*
* @return true
if this Set is empty
*/
public boolean isEmpty()
{
return InflatableMap.this.isEmpty();
}
/**
* Returns the number of elements in this collection.
*
* @return the number of elements in this collection
*/
public int size()
{
return InflatableMap.this.size();
}
/**
* Returns true
if this collection contains the specified
* element. More formally, returns true
if and only if this
* collection contains at least one element e
such that
* (o==null ? e==null : o.equals(e))
.
*
* @param o object to be checked for containment in this collection
*
* @return true
if this collection contains the specified
* element
*/
public boolean contains(Object o)
{
if (o instanceof Map.Entry)
{
Map.Entry entry = (Map.Entry) o;
Object oKey = entry.getKey();
Object oValue = entry.getValue();
InflatableMap map = InflatableMap.this;
Object oActual = map.get(oKey);
return oActual == null
? oValue == null && map.containsKey(oKey)
: Objects.equals(oValue, oActual);
}
return false;
}
/**
* Returns an array containing all of the elements in this collection.
*
* @return an array containing all of the elements in this collection
*/
public Object[] toArray()
{
return toArray((Object[]) null);
}
/**
* Returns an array with a runtime type is that of the specified array
* and that contains all of the elements in this collection. If the
* collection fits in the specified array, it is returned therein.
* Otherwise, a new array is allocated with the runtime type of the
* specified array and the size of this collection.
*
* If the collection fits in the specified array with room to spare
* (i.e. the array has more elements than the collection), the element
* in the array immediately following the end of the collection is set
* to null
. This is useful in determining the length of the
* collection only if the caller knows that the collection does
* not contain any null
elements.)
*
* @param ao the array into which the elements of the collection are
* to be stored, if it is big enough; otherwise, a new
* array of the same runtime type is allocated for this
* purpose
*
* @return an array containing the elements of the collection
*
* @throws ArrayStoreException if the runtime type of the specified
* array is not a supertype of the runtime type of every
* element in this collection
*/
public Object[] toArray(Object ao[])
{
InflatableMap map = InflatableMap.this;
// create the array to store the map contents
int c = map.size();
if (ao == null)
{
ao = c == 0 ? NO_OBJECTS : new Object[c];
}
else if (ao.length < c)
{
// if it is not big enough, a new array of the same runtime
// type is allocated
ao = (Object[]) Array.newInstance(ao.getClass().getComponentType(), c);
}
else if (ao.length > c)
{
// if the collection fits in the specified array with room to
// spare, the element in the array immediately following the
// end of the collection is set to null
ao[c] = null;
}
switch (map.m_nImpl)
{
case I_EMPTY:
break;
case I_SINGLE:
ao[0] = map.m_oContents;
break;
case I_ARRAY_1: case I_ARRAY_2: case I_ARRAY_3: case I_ARRAY_4:
case I_ARRAY_5: case I_ARRAY_6: case I_ARRAY_7: case I_ARRAY_8:
System.arraycopy((Map.Entry[]) m_oContents, 0, ao, 0, c);
break;
case I_OTHER:
ao = ((Map) m_oContents).entrySet().toArray(ao);
break;
default:
throw new IllegalStateException();
}
return ao;
}
}
// ----- Externalizable interface ---------------------------------------
/**
* Initialize this object from the data in the passed ObjectInput stream.
*
* @param in the stream to read data from in order to restore the object
*
* @exception IOException if an I/O exception occurs
*/
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException
{
if (!isEmpty())
{
throw new NotActiveException();
}
int c = in.readInt();
switch (c)
{
case 0:
break;
case 1:
m_nImpl = I_SINGLE;
m_oContents = instantiateEntry((K) in.readObject(), (V) in.readObject());
break;
case 2: case 3: case 4: case 5: case 6: case 7: case 8:
{
Map.Entry[] aEntry = new Map.Entry[THRESHOLD];
for (int i = 0; i < c; ++i)
{
aEntry[i] = instantiateEntry((K) in.readObject(), (V) in.readObject());
}
m_nImpl = (byte) (I_ARRAY_1 + c - 1);
m_oContents = aEntry;
}
break;
default:
{
Map map = instantiateMap();
for (int i = 0; i < c; ++i)
{
map.put((K) in.readObject(), (V) in.readObject());
}
m_nImpl = I_OTHER;
m_oContents = map;
}
break;
}
}
/**
* Write this object's data to the passed ObjectOutput stream.
*
* @param out the stream to write the object to
*
* @exception IOException if an I/O exception occurs
*/
public synchronized void writeExternal(ObjectOutput out)
throws IOException
{
// format is int size followed by that many key/value pairs
int nImpl = m_nImpl;
switch (nImpl)
{
case I_EMPTY:
out.writeInt(0);
break;
case I_SINGLE:
{
Map.Entry entry = (Map.Entry) m_oContents;
out.writeInt(1);
out.writeObject(entry.getKey());
out.writeObject(entry.getValue());
}
break;
case I_ARRAY_1: case I_ARRAY_2: case I_ARRAY_3: case I_ARRAY_4:
case I_ARRAY_5: case I_ARRAY_6: case I_ARRAY_7: case I_ARRAY_8:
{
Map.Entry[] aEntry = (Map.Entry[]) m_oContents;
int c = nImpl - I_ARRAY_1 + 1;
out.writeInt(c);
for (int i = 0; i < c; ++i)
{
Map.Entry entry = aEntry[i];
out.writeObject(entry.getKey());
out.writeObject(entry.getValue());
}
}
break;
case I_OTHER:
{
Map map = ((Map) m_oContents);
int c = map.size();
Map.Entry[] aEntry = (Map.Entry[]) map.entrySet().toArray(new Map.Entry[c]);
out.writeInt(c);
for (int i = 0; i < c; ++i)
{
Map.Entry entry = aEntry[i];
out.writeObject(entry.getKey());
out.writeObject(entry.getValue());
}
}
break;
default:
throw new IllegalStateException();
}
}
// ----- internal methods -----------------------------------------------
/**
* (Factory pattern) Instantiate a Map Entry.
* This method permits inheriting classes to easily override the
* implementation of the Entry object.
*
* @param key the key
* @param value the value
*
* @return an instance of a Map Entry
*/
protected Map.Entry instantiateEntry(K key, V value)
{
return new SimpleEntry(key, value);
}
/**
* (Factory pattern) Instantiate an Entry Set.
* This method permits inheriting classes to easily override the
* implementation of the EntrySet object.
*
* @return an instance of Entry Set
*/
protected Set> instantiateEntrySet()
{
return new EntrySet();
}
/**
* (Factory pattern) Instantiate a Map object to store entries in once
* the "lite" threshold has been exceeded. This method permits inheriting
* classes to easily override the choice of the Map object.
*
* @return an instance of Map
*/
protected Map instantiateMap()
{
return new HashMap<>();
}
/**
* Scan up to the first c
elements of the passed Entry array
* aEntry
looking for the specified key key
. If it is
* found, return its position i
in the array such that
* (0 <= i < c)
. If it is not found, return -1
.
*
* @param aEntry the array of objects to search
* @param c the number of Entry objects in the array to search
* @param oKey the key to look for
*
* @return the index of the object, if found; otherwise -1
*/
private int indexOf(Map.Entry[] aEntry, int c, Object oKey)
{
// first quick-scan by reference
for (int i = 0; i < c; ++i)
{
if (oKey == aEntry[i].getKey())
{
return i;
}
}
// slow scan by equals()
if (oKey != null)
{
for (int i = 0; i < c; ++i)
{
if (oKey.equals(aEntry[i].getKey()))
{
return i;
}
}
}
return -1;
}
/**
* Return the specified exception as a RuntimeException, wrapping it if necessary.
*
* @param t the exception
*
* @return the RuntimeException
*/
protected RuntimeException ensureRuntimeException(Throwable t)
{
return t instanceof RuntimeException
? (RuntimeException) t
: new RuntimeException(t);
}
/**
* After a mutation operation has reduced the size of an underlying Map,
* check if the delegation model should be replaced with a more size-
* efficient storage approach, and switch accordingly.
*/
protected void checkShrinkFromOther()
{
assert m_nImpl == I_OTHER;
// check if the Map is now significantly below the "lite"
// threshold
Map map = (Map) m_oContents;
int c = map.size();
switch (c)
{
case 0:
m_nImpl = I_EMPTY;
m_oContents = null;
break;
case 1:
{
Map.Entry entry = (Map.Entry) map.entrySet().toArray()[0];
m_oContents = instantiateEntry(entry.getKey(), entry.getValue());
m_nImpl = I_SINGLE;
}
break;
case 2: case 3: case 4:
{
// shrink to "Entry[]" implementation
Map.Entry[] aEntry = new Map.Entry[THRESHOLD];
int i = 0;
for (Iterator iter = map.entrySet().iterator(); iter.hasNext(); )
{
Map.Entry entry = (Map.Entry) iter.next();
aEntry[i++] = instantiateEntry(entry.getKey(), entry.getValue());
}
assert i == c;
m_nImpl = (byte) (I_ARRAY_1 + i - 1);
m_oContents = aEntry;
}
break;
}
}
// ----- inner class: EntryIterator -------------------------------------
/**
* A simple Iterator for InflatableMap Entry objects. This class is static in
* order to allow the EntrySet to be quickly garbage-collected.
*/
public static class EntryIterator
implements Iterator>
{
// ----- constructors -------------------------------------------
/**
* Construct an EntryIterator.
*
* @param map the InflatableMap to delegate remove()
calls to
* @param aEntry the array of Map Entry objects to iterate
*/
public EntryIterator(InflatableMap map, Map.Entry[] aEntry)
{
m_map = map;
m_aEntry = aEntry;
}
// ----- Iterator interface -------------------------------------
/**
* Returns true
if the iteration has more elements.
* (In other words, returns true
if next
* would return an element rather than throwing an exception.)
*
* @return true
if the iterator has more elements
*/
public boolean hasNext()
{
return m_iPrev + 1 < m_aEntry.length;
}
/**
* Returns the next element in the iteration.
*
* @return the next element in the iteration
*
* @exception NoSuchElementException iteration has no more
* elements
*/
public Entry next()
{
int iNext = m_iPrev + 1;
if (iNext < m_aEntry.length)
{
m_iPrev = iNext;
m_fCanRemove = true;
return m_aEntry[iNext];
}
else
{
throw new NoSuchElementException();
}
}
/**
* Removes from the underlying set the last element
* returned by the iterator. This method can be called only once
* per call to next
. The behavior of an iterator is
* unspecified if the underlying set is modified while the
* iteration is in progress in any way other than by calling this
* method.
*
* @exception IllegalStateException if the next
method
* has not yet been called, or the remove
* method has already been called after the last call
* to the next
method
*/
public void remove()
{
if (m_fCanRemove)
{
m_fCanRemove = false;
m_map.remove(m_aEntry[m_iPrev].getKey());
}
else
{
throw new IllegalStateException();
}
}
// ----- data members -------------------------------------------
/**
* The InflatableMap. Having this field allows the EntrySet to be
* quickly collected by a GC, because the EntryIterator does not
* have to maintain a reference to it in order to get to the InflatableMap.
*/
Map m_map;
/**
* The entries to iterate.
*/
Map.Entry[] m_aEntry;
/**
* The previous index iterated.
*/
int m_iPrev = -1;
/**
* True if the previously iterated element can be removed.
*/
boolean m_fCanRemove = false;
}
// ----- constants ------------------------------------------------------
/**
* A constant array of zero size. (This saves having to allocate what
* should be a constant.)
*/
private static final Object[] NO_OBJECTS = new Object[0];
/**
* The default point above which the InflatableMap delegates to another Map
* implementation.
*/
protected static final int THRESHOLD = 8;
/**
* Implementation: Empty Map.
*/
private static final int I_EMPTY = 0;
/**
* Implementation: Single-item Map.
*/
private static final int I_SINGLE = 1;
/**
* Implementation: Array Map of 1 item.
*/
private static final int I_ARRAY_1 = 2;
/**
* Implementation: Array Map of 2 items.
*/
private static final int I_ARRAY_2 = 3;
/**
* Implementation: Array Map of 3 items.
*/
private static final int I_ARRAY_3 = 4;
/**
* Implementation: Array Map of 4 items.
*/
private static final int I_ARRAY_4 = 5;
/**
* Implementation: Array Map of 5 items.
*/
private static final int I_ARRAY_5 = 6;
/**
* Implementation: Array Map of 6 items.
*/
private static final int I_ARRAY_6 = 7;
/**
* Implementation: Array Map of 7 items.
*/
private static final int I_ARRAY_7 = 8;
/**
* Implementation: Array Map of 8 items.
*/
private static final int I_ARRAY_8 = 9;
/**
* Implementation: Delegation.
*/
protected static final int I_OTHER = 10;
/**
* An empty iterator.
*/
private static final Iterator NULL_ITERATOR = new Iterator()
{
@Override
public boolean hasNext()
{
return false;
}
@Override
public Object next()
{
throw new NoSuchElementException();
}
};
// ----- data members ---------------------------------------------------
/**
* Implementation, one of I_EMPTY, I_SINGLE, I_ARRAY_* or I_OTHER.
*/
protected byte m_nImpl;
/**
* The Map contents, based on the implementation being used.
*/
protected Object m_oContents;
}