Index: CHANGES.txt
===================================================================
--- CHANGES.txt	(revision 600585)
+++ CHANGES.txt	(working copy)
@@ -27,7 +27,8 @@
     the field type for sorting automatically, numbers used to be
     interpreted as int, then as float, if parsing the number as an int
     failed. Now the detection checks for int, then for long,
-    then for float. (Daniel Naber)
+    then for float. NOTE: This introduces an incompatible API change to FieldCache.
+    (Daniel Naber, Grant Ingersoll)
 
 API Changes
 
@@ -212,6 +213,9 @@
  6. LUCENE-1015: Added FieldCache extension (ExtendedFieldCache) to
     support doubles and longs.  Added support into SortField for sorting
     on doubles and longs as well.  (Grant Ingersoll)
+    6.a LUCENE-1045: Removed ExtendedFieldCache in favor of modifying the FieldCache proper.
+    NOTE: This causes an incompatible change to the API.
+    Also added support to SortField for Byte and Short.  (Grant Ingersoll)
 
  7. LUCENE-1044: Added optional doSync boolean to
     FSDirectory.getDirectory(...).  If true (the default) then we will
Index: src/test/org/apache/lucene/search/TestSort.java
===================================================================
--- src/test/org/apache/lucene/search/TestSort.java	(revision 600585)
+++ src/test/org/apache/lucene/search/TestSort.java	(working copy)
@@ -98,21 +98,21 @@
 	// the string field to sort by string
     // the i18n field includes accented characters for testing locale-specific sorting
 	private String[][] data = new String[][] {
-	// tracer  contents         int            float           string   custom   i18n               long            double
-	{   "A",   "x a",           "5",           "4f",           "c",     "A-3",   "p\u00EAche",      "10",           "-4.0"},//A
-	{   "B",   "y a",           "5",           "3.4028235E38", "i",     "B-10",  "HAT",             "1000000000", "40.0"},//B
-	{   "C",   "x a b c",       "2147483647",  "1.0",          "j",     "A-2",   "p\u00E9ch\u00E9", "99999999",   "40.00002343"},//C
-	{   "D",   "y a b c",       "-1",          "0.0f",         "a",     "C-0",   "HUT",             String.valueOf(Long.MAX_VALUE),           String.valueOf(Double.MIN_VALUE)},//D
-	{   "E",   "x a b c d",     "5",           "2f",           "h",     "B-8",   "peach",           String.valueOf(Long.MIN_VALUE),           String.valueOf(Double.MAX_VALUE)},//E
-	{   "F",   "y a b c d",     "2",           "3.14159f",     "g",     "B-1",   "H\u00C5T",        "-44",           "343.034435444"},//F
-	{   "G",   "x a b c d",     "3",           "-1.0",         "f",     "C-100", "sin",             "323254543543", "4.043544"},//G
-  {   "H",   "y a b c d",     "0",           "1.4E-45",      "e",     "C-88",  "H\u00D8T",        "1023423423005","4.043545"},//H
-	{   "I",   "x a b c d e f", "-2147483648", "1.0e+0",       "d",     "A-10",  "s\u00EDn",        "332422459999", "4.043546"},//I
-	{   "J",   "y a b c d e f", "4",           ".5",           "b",     "C-7",   "HOT",             "34334543543",  "4.0000220343"},//J
-	{   "W",   "g",             "1",           null,           null,    null,    null,              null,           null},
-	{   "X",   "g",             "1",           "0.1",          null,    null,    null,              null,           null},
-	{   "Y",   "g",             "1",           "0.2",          null,    null,    null,              null,           null},
-	{   "Z",   "f g",           null,          null,           null,    null,    null,              null,           null}
+	// tracer  contents         int            float           string   custom   i18n               long            double, short, byte
+	{   "A",   "x a",           "5",           "4f",           "c",     "A-3",   "p\u00EAche",      "10",           "-4.0", "3", "126"},//A, x
+	{   "B",   "y a",           "5",           "3.4028235E38", "i",     "B-10",  "HAT",             "1000000000", "40.0", "24", "1"},//B, y
+	{   "C",   "x a b c",       "2147483647",  "1.0",          "j",     "A-2",   "p\u00E9ch\u00E9", "99999999",   "40.00002343", "125", "15"},//C, x
+	{   "D",   "y a b c",       "-1",          "0.0f",         "a",     "C-0",   "HUT",             String.valueOf(Long.MAX_VALUE),           String.valueOf(Double.MIN_VALUE), String.valueOf(Short.MIN_VALUE), String.valueOf(Byte.MIN_VALUE)},//D, y
+	{   "E",   "x a b c d",     "5",           "2f",           "h",     "B-8",   "peach",           String.valueOf(Long.MIN_VALUE),           String.valueOf(Double.MAX_VALUE), String.valueOf(Short.MAX_VALUE),           String.valueOf(Byte.MAX_VALUE)},//E,x
+	{   "F",   "y a b c d",     "2",           "3.14159f",     "g",     "B-1",   "H\u00C5T",        "-44",           "343.034435444", "-3", "0"},//F,y
+	{   "G",   "x a b c d",     "3",           "-1.0",         "f",     "C-100", "sin",             "323254543543", "4.043544", "5", "100"},//G,x
+  {   "H",   "y a b c d",     "0",           "1.4E-45",      "e",     "C-88",  "H\u00D8T",        "1023423423005","4.043545", "10", "-50"},//H,y
+	{   "I",   "x a b c d e f", "-2147483648", "1.0e+0",       "d",     "A-10",  "s\u00EDn",        "332422459999", "4.043546", "-340", "51"},//I,x
+	{   "J",   "y a b c d e f", "4",           ".5",           "b",     "C-7",   "HOT",             "34334543543",  "4.0000220343", "300", "2"},//J,y
+	{   "W",   "g",             "1",           null,           null,    null,    null,              null,           null, null, null},
+	{   "X",   "g",             "1",           "0.1",          null,    null,    null,              null,           null, null, null},
+	{   "Y",   "g",             "1",           "0.2",          null,    null,    null,              null,           null, null, null},
+	{   "Z",   "f g",           null,          null,           null,    null,    null,              null,           null, null, null}
 	};
 
 	// create an index of all the documents, or just the x, or just the y documents
@@ -132,6 +132,8 @@
 				if (data[i][6] != null) doc.add (new Field ("i18n",     data[i][6], Field.Store.NO, Field.Index.UN_TOKENIZED));
         if (data[i][7] != null) doc.add (new Field ("long",     data[i][7], Field.Store.NO, Field.Index.UN_TOKENIZED));
         if (data[i][8] != null) doc.add (new Field ("double",     data[i][8], Field.Store.NO, Field.Index.UN_TOKENIZED));
+        if (data[i][8] != null) doc.add (new Field ("short",     data[i][9], Field.Store.NO, Field.Index.UN_TOKENIZED));
+        if (data[i][8] != null) doc.add (new Field ("byte",     data[i][10], Field.Store.NO, Field.Index.UN_TOKENIZED));
         doc.setBoost(2);  // produce some scores above 1.0
 				writer.addDocument (doc);
 			}
@@ -199,6 +201,14 @@
 		assertMatches (full, queryX, sort, "EACGI");
 		assertMatches (full, queryY, sort, "FBJHD");
 
+    sort.setSort (new SortField[] { new SortField ("byte", SortField.BYTE), SortField.FIELD_DOC });
+		assertMatches (full, queryX, sort, "CIGAE");
+		assertMatches (full, queryY, sort, "DHFBJ");
+
+    sort.setSort (new SortField[] { new SortField ("short", SortField.SHORT), SortField.FIELD_DOC });
+		assertMatches (full, queryX, sort, "IAGCE");
+		assertMatches (full, queryY, sort, "DFHBJ");
+
     sort.setSort (new SortField[] { new SortField ("double", SortField.DOUBLE), SortField.FIELD_DOC });
 		assertMatches (full, queryX, sort, "AGICE");
 		assertMatches (full, queryY, sort, "DJHBF");
Index: src/test/org/apache/lucene/search/TestExtendedFieldCache.java
===================================================================
--- src/test/org/apache/lucene/search/TestExtendedFieldCache.java	(revision 600585)
+++ src/test/org/apache/lucene/search/TestExtendedFieldCache.java	(working copy)
@@ -54,7 +54,7 @@
 
 
   public void test() throws IOException {
-    ExtendedFieldCache cache = new ExtendedFieldCacheImpl();
+    FieldCache cache = new FieldCache();
     double [] doubles = cache.getDoubles(reader, "theDouble");
     assertTrue("doubles Size: " + doubles.length + " is not: " + NUM_DOCS, doubles.length == NUM_DOCS);
     for (int i = 0; i < doubles.length; i++) {
Index: src/java/org/apache/lucene/search/FieldDocSortedHitQueue.java
===================================================================
--- src/java/org/apache/lucene/search/FieldDocSortedHitQueue.java	(revision 600585)
+++ src/java/org/apache/lucene/search/FieldDocSortedHitQueue.java	(working copy)
@@ -124,6 +124,20 @@
 					if (i1 > i2) c = 1;
 					break;
         }
+        case SortField.BYTE:{
+					int i1 = ((Byte)docA.fields[i]).byteValue();
+					int i2 = ((Byte)docB.fields[i]).byteValue();
+					if (i1 < i2) c = -1;
+					if (i1 > i2) c = 1;
+					break;
+        }
+        case SortField.SHORT:{
+					int i1 = ((Short)docA.fields[i]).shortValue();
+					int i2 = ((Short)docB.fields[i]).shortValue();
+					if (i1 < i2) c = -1;
+					if (i1 > i2) c = 1;
+					break;
+        }
         case SortField.LONG:{
 					long l1 = ((Long)docA.fields[i]).longValue();
 					long l2 = ((Long)docB.fields[i]).longValue();
Index: src/java/org/apache/lucene/search/FieldCache.java
===================================================================
--- src/java/org/apache/lucene/search/FieldCache.java	(revision 600585)
+++ src/java/org/apache/lucene/search/FieldCache.java	(working copy)
@@ -18,7 +18,15 @@
  */
 
 import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.TermDocs;
+import org.apache.lucene.index.TermEnum;
+import org.apache.lucene.index.Term;
+
 import java.io.IOException;
+import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.HashMap;
+import java.util.Locale;
 
 /**
  * Expert: Maintains caches of term values.
@@ -29,7 +37,7 @@
  * @since   lucene 1.4
  * @version $Id$
  */
-public interface FieldCache {
+public class FieldCache {
 
   /** Indicator for StringIndex values in the cache. */
   // NOTE: the value assigned to this constant must not be
@@ -85,10 +93,171 @@
     public float parseFloat(String string);
   }
 
+  /** Interface to parse longs from document fields.
+   * @see FieldCache#getFloats(IndexReader, String, FieldCache.FloatParser)
+   */
+  public interface LongParser {
+    /**
+     * Return an long representation of this field's value.
+     */
+    public long parseLong(String string);
+  }
+
+  /** Interface to parse doubles from document fields.
+   * @see FieldCache#getFloats(IndexReader, String, FieldCache.FloatParser)
+   */
+  public interface DoubleParser {
+    /**
+     * Return an long representation of this field's value.
+     */
+    public double parseDouble(String string);
+  }
+
+
+
   /** Expert: The cache used internally by sorting and range query classes. */
-  public static FieldCache DEFAULT = new FieldCacheImpl();
+  public static FieldCache DEFAULT = new FieldCache();
 
-  /** Checks the internal cache for an appropriate entry, and if none is
+  /**
+   * Expert: Internal cache.
+   */
+  abstract static class Cache {
+    private final Map readerCache = new WeakHashMap();
+
+    protected abstract Object createValue(IndexReader reader, Object key)
+            throws IOException;
+
+    public Object get(IndexReader reader, Object key) throws IOException {
+      Map innerCache;
+      Object value;
+      synchronized (readerCache) {
+        innerCache = (Map) readerCache.get(reader);
+        if (innerCache == null) {
+          innerCache = new HashMap();
+          readerCache.put(reader, innerCache);
+          value = null;
+        } else {
+          value = innerCache.get(key);
+        }
+        if (value == null) {
+          value = new CreationPlaceholder();
+          innerCache.put(key, value);
+        }
+      }
+      if (value instanceof CreationPlaceholder) {
+        synchronized (value) {
+          CreationPlaceholder progress = (CreationPlaceholder) value;
+          if (progress.value == null) {
+            progress.value = createValue(reader, key);
+            synchronized (readerCache) {
+              innerCache.put(key, progress.value);
+            }
+          }
+          return progress.value;
+        }
+      }
+      return value;
+    }
+  }
+
+  static final class CreationPlaceholder {
+    Object value;
+  }
+
+  /**
+   * Expert: Every composite-key in the internal cache is of this type.
+   */
+  static class Entry {
+    final String field;        // which Fieldable
+    final int type;            // which SortField type
+    final Object custom;       // which custom comparator
+    final Locale locale;       // the locale we're sorting (if string)
+
+    /**
+     * Creates one of these objects.
+     */
+    Entry(String field, int type, Locale locale) {
+      this.field = field.intern();
+      this.type = type;
+      this.custom = null;
+      this.locale = locale;
+    }
+
+    /**
+     * Creates one of these objects for a custom comparator.
+     */
+    Entry(String field, Object custom) {
+      this.field = field.intern();
+      this.type = SortField.CUSTOM;
+      this.custom = custom;
+      this.locale = null;
+    }
+
+    /**
+     * Two of these are equal iff they reference the same field and type.
+     */
+    public boolean equals(Object o) {
+      if (o instanceof Entry) {
+        Entry other = (Entry) o;
+        if (other.field == field && other.type == type) {
+          if (other.locale == null ? locale == null : other.locale.equals(locale)) {
+            if (other.custom == null) {
+              if (custom == null) return true;
+            } else if (other.custom.equals(custom)) {
+              return true;
+            }
+          }
+        }
+      }
+      return false;
+    }
+
+    /**
+     * Composes a hashcode based on the field and type.
+     */
+    public int hashCode() {
+      return field.hashCode() ^ type ^ (custom == null ? 0 : custom.hashCode()) ^ (locale == null ? 0 : locale.hashCode());
+    }
+  }
+
+  private static final ByteParser BYTE_PARSER = new ByteParser() {
+    public byte parseByte(String value) {
+      return Byte.parseByte(value);
+    }
+  };
+
+  private static final ShortParser SHORT_PARSER = new ShortParser() {
+    public short parseShort(String value) {
+      return Short.parseShort(value);
+    }
+  };
+
+  private static final IntParser INT_PARSER = new IntParser() {
+    public int parseInt(String value) {
+      return Integer.parseInt(value);
+    }
+  };
+
+
+  private static final FloatParser FLOAT_PARSER = new FloatParser() {
+    public float parseFloat(String value) {
+      return Float.parseFloat(value);
+    }
+  };
+
+  private static final FieldCache.LongParser LONG_PARSER = new FieldCache.LongParser() {
+    public long parseLong(String value) {
+      return Long.parseLong(value);
+    }
+  };
+
+  private static final FieldCache.DoubleParser DOUBLE_PARSER = new FieldCache.DoubleParser() {
+    public double parseDouble(String value) {
+      return Double.parseDouble(value);
+    }
+  };
+
+    /** Checks the internal cache for an appropriate entry, and if none is
    * found, reads the terms in <code>field</code> as a single byte and returns an array
    * of size <code>reader.maxDoc()</code> of the value each document
    * has in the given field.
@@ -97,9 +266,15 @@
    * @return The values in the given field for each document.
    * @throws IOException  If any error occurs.
    */
-  public byte[] getBytes (IndexReader reader, String field)
-  throws IOException;
 
+  public byte[] getBytes(IndexReader reader, String field) throws IOException {
+    return getBytes(reader, field, BYTE_PARSER);
+  }
+
+
+
+
+
   /** Checks the internal cache for an appropriate entry, and if none is found,
    * reads the terms in <code>field</code> as bytes and returns an array of
    * size <code>reader.maxDoc()</code> of the value each document has in the
@@ -110,9 +285,39 @@
    * @return The values in the given field for each document.
    * @throws IOException  If any error occurs.
    */
-  public byte[] getBytes (IndexReader reader, String field, ByteParser parser)
-  throws IOException;
+  public byte[] getBytes(IndexReader reader, String field, ByteParser parser)
+          throws IOException {
+    return (byte[]) bytesCache.get(reader, new Entry(field, parser));
+  }
 
+  Cache bytesCache = new Cache() {
+
+    protected Object createValue(IndexReader reader, Object entryKey)
+            throws IOException {
+      Entry entry = (Entry) entryKey;
+      String field = entry.field;
+      ByteParser parser = (ByteParser) entry.custom;
+      final byte[] retArray = new byte[reader.maxDoc()];
+      TermDocs termDocs = reader.termDocs();
+      TermEnum termEnum = reader.terms(new Term(field, ""));
+      try {
+        do {
+          Term term = termEnum.term();
+          if (term == null || term.field() != field) break;
+          byte termval = parser.parseByte(term.text());
+          termDocs.seek(termEnum);
+          while (termDocs.next()) {
+            retArray[termDocs.doc()] = termval;
+          }
+        } while (termEnum.next());
+      } finally {
+        termDocs.close();
+        termEnum.close();
+      }
+      return retArray;
+    }
+  };
+
   /** Checks the internal cache for an appropriate entry, and if none is
    * found, reads the terms in <code>field</code> as shorts and returns an array
    * of size <code>reader.maxDoc()</code> of the value each document
@@ -122,8 +327,9 @@
    * @return The values in the given field for each document.
    * @throws IOException  If any error occurs.
    */
-  public short[] getShorts (IndexReader reader, String field)
-  throws IOException;
+  public short[] getShorts(IndexReader reader, String field) throws IOException {
+    return getShorts(reader, field, SHORT_PARSER);
+  }
 
   /** Checks the internal cache for an appropriate entry, and if none is found,
    * reads the terms in <code>field</code> as shorts and returns an array of
@@ -135,9 +341,39 @@
    * @return The values in the given field for each document.
    * @throws IOException  If any error occurs.
    */
-  public short[] getShorts (IndexReader reader, String field, ShortParser parser)
-  throws IOException;
+  public short[] getShorts(IndexReader reader, String field, ShortParser parser)
+          throws IOException {
+    return (short[]) shortsCache.get(reader, new Entry(field, parser));
+  }
 
+  Cache shortsCache = new Cache() {
+
+    protected Object createValue(IndexReader reader, Object entryKey)
+            throws IOException {
+      Entry entry = (Entry) entryKey;
+      String field = entry.field;
+      ShortParser parser = (ShortParser) entry.custom;
+      final short[] retArray = new short[reader.maxDoc()];
+      TermDocs termDocs = reader.termDocs();
+      TermEnum termEnum = reader.terms(new Term(field, ""));
+      try {
+        do {
+          Term term = termEnum.term();
+          if (term == null || term.field() != field) break;
+          short termval = parser.parseShort(term.text());
+          termDocs.seek(termEnum);
+          while (termDocs.next()) {
+            retArray[termDocs.doc()] = termval;
+          }
+        } while (termEnum.next());
+      } finally {
+        termDocs.close();
+        termEnum.close();
+      }
+      return retArray;
+    }
+  };
+
   /** Checks the internal cache for an appropriate entry, and if none is
    * found, reads the terms in <code>field</code> as integers and returns an array
    * of size <code>reader.maxDoc()</code> of the value each document
@@ -147,8 +383,9 @@
    * @return The values in the given field for each document.
    * @throws IOException  If any error occurs.
    */
-  public int[] getInts (IndexReader reader, String field)
-  throws IOException;
+  public int[] getInts(IndexReader reader, String field) throws IOException {
+    return getInts(reader, field, INT_PARSER);
+  }
 
   /** Checks the internal cache for an appropriate entry, and if none is found,
    * reads the terms in <code>field</code> as integers and returns an array of
@@ -160,9 +397,40 @@
    * @return The values in the given field for each document.
    * @throws IOException  If any error occurs.
    */
-  public int[] getInts (IndexReader reader, String field, IntParser parser)
-  throws IOException;
+  public int[] getInts(IndexReader reader, String field, IntParser parser)
+          throws IOException {
+    return (int[]) intsCache.get(reader, new Entry(field, parser));
+  }
 
+  Cache intsCache = new Cache() {
+
+    protected Object createValue(IndexReader reader, Object entryKey)
+            throws IOException {
+      Entry entry = (Entry) entryKey;
+      String field = entry.field;
+      IntParser parser = (IntParser) entry.custom;
+      final int[] retArray = new int[reader.maxDoc()];
+      TermDocs termDocs = reader.termDocs();
+      TermEnum termEnum = reader.terms(new Term(field, ""));
+      try {
+        do {
+          Term term = termEnum.term();
+          if (term == null || term.field() != field) break;
+          int termval = parser.parseInt(term.text());
+          termDocs.seek(termEnum);
+          while (termDocs.next()) {
+            retArray[termDocs.doc()] = termval;
+          }
+        } while (termEnum.next());
+      } finally {
+        termDocs.close();
+        termEnum.close();
+      }
+      return retArray;
+    }
+  };
+
+
   /** Checks the internal cache for an appropriate entry, and if
    * none is found, reads the terms in <code>field</code> as floats and returns an array
    * of size <code>reader.maxDoc()</code> of the value each document
@@ -172,8 +440,10 @@
    * @return The values in the given field for each document.
    * @throws IOException  If any error occurs.
    */
-  public float[] getFloats (IndexReader reader, String field)
-  throws IOException;
+  public float[] getFloats(IndexReader reader, String field)
+          throws IOException {
+    return getFloats(reader, field, FLOAT_PARSER);
+  }
 
   /** Checks the internal cache for an appropriate entry, and if
    * none is found, reads the terms in <code>field</code> as floats and returns an array
@@ -185,9 +455,39 @@
    * @return The values in the given field for each document.
    * @throws IOException  If any error occurs.
    */
-  public float[] getFloats (IndexReader reader, String field,
-                            FloatParser parser) throws IOException;
+  public float[] getFloats(IndexReader reader, String field, FloatParser parser)
+          throws IOException {
+    return (float[]) floatsCache.get(reader, new Entry(field, parser));
+  }
 
+  Cache floatsCache = new Cache() {
+
+    protected Object createValue(IndexReader reader, Object entryKey)
+            throws IOException {
+      Entry entry = (Entry) entryKey;
+      String field = entry.field;
+      FloatParser parser = (FloatParser) entry.custom;
+      final float[] retArray = new float[reader.maxDoc()];
+      TermDocs termDocs = reader.termDocs();
+      TermEnum termEnum = reader.terms(new Term(field, ""));
+      try {
+        do {
+          Term term = termEnum.term();
+          if (term == null || term.field() != field) break;
+          float termval = parser.parseFloat(term.text());
+          termDocs.seek(termEnum);
+          while (termDocs.next()) {
+            retArray[termDocs.doc()] = termval;
+          }
+        } while (termEnum.next());
+      } finally {
+        termDocs.close();
+        termEnum.close();
+      }
+      return retArray;
+    }
+  };
+
   /** Checks the internal cache for an appropriate entry, and if none
    * is found, reads the term values in <code>field</code> and returns an array
    * of size <code>reader.maxDoc()</code> containing the value each document
@@ -197,9 +497,37 @@
    * @return The values in the given field for each document.
    * @throws IOException  If any error occurs.
    */
-  public String[] getStrings (IndexReader reader, String field)
-  throws IOException;
+  public String[] getStrings(IndexReader reader, String field)
+          throws IOException {
+    return (String[]) stringsCache.get(reader, field);
+  }
 
+  Cache stringsCache = new Cache() {
+
+    protected Object createValue(IndexReader reader, Object fieldKey)
+            throws IOException {
+      String field = ((String) fieldKey).intern();
+      final String[] retArray = new String[reader.maxDoc()];
+      TermDocs termDocs = reader.termDocs();
+      TermEnum termEnum = reader.terms(new Term(field, ""));
+      try {
+        do {
+          Term term = termEnum.term();
+          if (term == null || term.field() != field) break;
+          String termval = term.text();
+          termDocs.seek(termEnum);
+          while (termDocs.next()) {
+            retArray[termDocs.doc()] = termval;
+          }
+        } while (termEnum.next());
+      } finally {
+        termDocs.close();
+        termEnum.close();
+      }
+      return retArray;
+    }
+  };
+
   /** Checks the internal cache for an appropriate entry, and if none
    * is found reads the term values in <code>field</code> and returns
    * an array of them in natural order, along with an array telling
@@ -209,9 +537,80 @@
    * @return Array of terms and index into the array for each document.
    * @throws IOException  If any error occurs.
    */
-  public StringIndex getStringIndex (IndexReader reader, String field)
-  throws IOException;
+  public StringIndex getStringIndex(IndexReader reader, String field)
+          throws IOException {
+    return (StringIndex) stringsIndexCache.get(reader, field);
+  }
 
+  Cache stringsIndexCache = new Cache() {
+
+    protected Object createValue(IndexReader reader, Object fieldKey)
+            throws IOException {
+      String field = ((String) fieldKey).intern();
+      final int[] retArray = new int[reader.maxDoc()];
+      String[] mterms = new String[reader.maxDoc() + 1];
+      TermDocs termDocs = reader.termDocs();
+      TermEnum termEnum = reader.terms(new Term(field, ""));
+      int t = 0;  // current term number
+
+      // an entry for documents that have no terms in this field
+      // should a document with no terms be at top or bottom?
+      // this puts them at the top - if it is changed, FieldDocSortedHitQueue
+      // needs to change as well.
+      mterms[t++] = null;
+
+      try {
+        do {
+          Term term = termEnum.term();
+          if (term == null || term.field() != field) break;
+
+          // store term text
+          // we expect that there is at most one term per document
+          if (t >= mterms.length) throw new RuntimeException("there are more terms than " +
+                  "documents in field \"" + field + "\", but it's impossible to sort on " +
+                  "tokenized fields");
+          mterms[t] = term.text();
+
+          termDocs.seek(termEnum);
+          while (termDocs.next()) {
+            retArray[termDocs.doc()] = t;
+          }
+
+          t++;
+        } while (termEnum.next());
+      } finally {
+        termDocs.close();
+        termEnum.close();
+      }
+
+      if (t == 0) {
+        // if there are no terms, make the term array
+        // have a single null entry
+        mterms = new String[1];
+      } else if (t < mterms.length) {
+        // if there are less terms than documents,
+        // trim off the dead array space
+        String[] terms = new String[t];
+        System.arraycopy(mterms, 0, terms, 0, t);
+        mterms = terms;
+      }
+
+      StringIndex value = new StringIndex(retArray, mterms);
+      return value;
+    }
+  };
+
+  /** The pattern used to detect integer values in a field */
+  /** removed for java 1.3 compatibility
+   protected static final Pattern pIntegers = Pattern.compile ("[0-9\\-]+");
+   **/
+
+  /** The pattern used to detect float values in a field */
+  /**
+   * removed for java 1.3 compatibility
+   * protected static final Object pFloats = Pattern.compile ("[0-9+\\-\\.eEfFdD]+");
+   */
+
   /** Checks the internal cache for an appropriate entry, and if
    * none is found reads <code>field</code> to see if it contains integers, floats
    * or strings, and then calls one of the other methods in this class to get the
@@ -223,9 +622,63 @@
    * @return int[], float[] or StringIndex.
    * @throws IOException  If any error occurs.
    */
-  public Object getAuto (IndexReader reader, String field)
-  throws IOException;
 
+  public Object getAuto(IndexReader reader, String field) throws IOException {
+    return autoCache.get(reader, field);
+  }
+
+  Cache autoCache = new Cache() {
+
+    protected Object createValue(IndexReader reader, Object fieldKey)
+        throws IOException {
+      String field = ((String)fieldKey).intern();
+      TermEnum enumerator = reader.terms (new Term (field, ""));
+      try {
+        Term term = enumerator.term();
+        if (term == null) {
+          throw new RuntimeException ("no terms in field " + field + " - cannot determine sort type");
+        }
+        Object ret = null;
+        if (term.field() == field) {
+          String termtext = term.text().trim();
+
+          /**
+           * Java 1.4 level code:
+
+           if (pIntegers.matcher(termtext).matches())
+           return IntegerSortedHitQueue.comparator (reader, enumerator, field);
+
+           else if (pFloats.matcher(termtext).matches())
+           return FloatSortedHitQueue.comparator (reader, enumerator, field);
+           */
+
+          // Java 1.3 level code:
+          try {
+            Integer.parseInt (termtext);
+            ret = getInts (reader, field);
+          } catch (NumberFormatException nfe1) {
+            try {
+              Long.parseLong(termtext);
+              ret = getLongs (reader, field);
+            } catch (NumberFormatException nfe2) {
+              try {
+                Float.parseFloat (termtext);
+                ret = getFloats (reader, field);
+              } catch (NumberFormatException nfe3) {
+                ret = getStringIndex (reader, field);
+              }
+            }
+          }
+        } else {
+          throw new RuntimeException ("field \"" + field + "\" does not appear to be indexed");
+        }
+        return ret;
+      } finally {
+        enumerator.close();
+      }
+    }
+  };
+
   /** Checks the internal cache for an appropriate entry, and if none
    * is found reads the terms out of <code>field</code> and calls the given SortComparator
    * to get the sort values.  A hit in the cache will happen if <code>reader</code>,
@@ -237,7 +690,159 @@
    * @return Array of sort objects, one for each document.
    * @throws IOException  If any error occurs.
    */
-  public Comparable[] getCustom (IndexReader reader, String field, SortComparator comparator)
-  throws IOException;
+  public Comparable[] getCustom(IndexReader reader, String field,
+                                SortComparator comparator) throws IOException {
+    return (Comparable[]) customCache.get(reader, new Entry(field, comparator));
+  }
+
+  Cache customCache = new Cache() {
+
+    protected Object createValue(IndexReader reader, Object entryKey)
+            throws IOException {
+      Entry entry = (Entry) entryKey;
+      String field = entry.field;
+      SortComparator comparator = (SortComparator) entry.custom;
+      final Comparable[] retArray = new Comparable[reader.maxDoc()];
+      TermDocs termDocs = reader.termDocs();
+      TermEnum termEnum = reader.terms(new Term(field, ""));
+      try {
+        do {
+          Term term = termEnum.term();
+          if (term == null || term.field() != field) break;
+          Comparable termval = comparator.getComparable(term.text());
+          termDocs.seek(termEnum);
+          while (termDocs.next()) {
+            retArray[termDocs.doc()] = termval;
+          }
+        } while (termEnum.next());
+      } finally {
+        termDocs.close();
+        termEnum.close();
+      }
+      return retArray;
+    }
+  };
+
+  /**
+   * Checks the internal cache for an appropriate entry, and if none is
+   * found, reads the terms in <code>field</code> as longs and returns an array
+   * of size <code>reader.maxDoc()</code> of the value each document
+   * has in the given field.
+   *
+   * @param reader Used to get field values.
+   * @param field  Which field contains the longs.
+   * @return The values in the given field for each document.
+   * @throws java.io.IOException If any error occurs.
+   */
+  public long[] getLongs(IndexReader reader, String field) throws IOException {
+    return getLongs(reader, field, LONG_PARSER);
+  }
+
+  /**
+   * Checks the internal cache for an appropriate entry, and if none is found,
+   * reads the terms in <code>field</code> as longs and returns an array of
+   * size <code>reader.maxDoc()</code> of the value each document has in the
+   * given field.
+   *
+   * @param reader Used to get field values.
+   * @param field  Which field contains the longs.
+   * @param parser Computes integer for string values.
+   * @return The values in the given field for each document.
+   * @throws IOException If any error occurs.
+   */
+  public long[] getLongs(IndexReader reader, String field, FieldCache.LongParser parser)
+          throws IOException {
+    return (long[]) longsCache.get(reader, new Entry(field, parser));
+  }
+
+  Cache longsCache = new Cache() {
+
+    protected Object createValue(IndexReader reader, Object entryKey)
+            throws IOException {
+      Entry entry = (Entry) entryKey;
+      String field = entry.field;
+      FieldCache.LongParser parser = (FieldCache.LongParser) entry.custom;
+      final long[] retArray = new long[reader.maxDoc()];
+      TermDocs termDocs = reader.termDocs();
+      TermEnum termEnum = reader.terms(new Term(field, ""));
+      try {
+        do {
+          Term term = termEnum.term();
+          if (term == null || term.field() != field) break;
+          long termval = parser.parseLong(term.text());
+          termDocs.seek(termEnum);
+          while (termDocs.next()) {
+            retArray[termDocs.doc()] = termval;
+          }
+        } while (termEnum.next());
+      } finally {
+        termDocs.close();
+        termEnum.close();
+      }
+      return retArray;
+    }
+  };
+
+  /**
+   * Checks the internal cache for an appropriate entry, and if none is
+   * found, reads the terms in <code>field</code> as integers and returns an array
+   * of size <code>reader.maxDoc()</code> of the value each document
+   * has in the given field.
+   *
+   * @param reader Used to get field values.
+   * @param field  Which field contains the doubles.
+   * @return The values in the given field for each document.
+   * @throws IOException If any error occurs.
+   */
+  public double[] getDoubles(IndexReader reader, String field)
+          throws IOException {
+    return getDoubles(reader, field, DOUBLE_PARSER);
+  }
+
+  /**
+   * Checks the internal cache for an appropriate entry, and if none is found,
+   * reads the terms in <code>field</code> as doubles and returns an array of
+   * size <code>reader.maxDoc()</code> of the value each document has in the
+   * given field.
+   *
+   * @param reader Used to get field values.
+   * @param field  Which field contains the doubles.
+   * @param parser Computes integer for string values.
+   * @return The values in the given field for each document.
+   * @throws IOException If any error occurs.
+   */
+  public double[] getDoubles(IndexReader reader, String field, FieldCache.DoubleParser parser)
+          throws IOException {
+    return (double[]) doublesCache.get(reader, new Entry(field, parser));
+  }
+
+  Cache doublesCache = new Cache() {
+
+    protected Object createValue(IndexReader reader, Object entryKey)
+            throws IOException {
+      Entry entry = (Entry) entryKey;
+      String field = entry.field;
+      FieldCache.DoubleParser parser = (FieldCache.DoubleParser) entry.custom;
+      final double[] retArray = new double[reader.maxDoc()];
+      TermDocs termDocs = reader.termDocs();
+      TermEnum termEnum = reader.terms(new Term(field, ""));
+      try {
+        do {
+          Term term = termEnum.term();
+          if (term == null || term.field() != field) break;
+          double termval = parser.parseDouble(term.text());
+          termDocs.seek(termEnum);
+          while (termDocs.next()) {
+            retArray[termDocs.doc()] = termval;
+          }
+        } while (termEnum.next());
+      } finally {
+        termDocs.close();
+        termEnum.close();
+      }
+      return retArray;
+    }
+  };
+
   
 }
Index: src/java/org/apache/lucene/search/ExtendedFieldCacheImpl.java
===================================================================
--- src/java/org/apache/lucene/search/ExtendedFieldCacheImpl.java	(revision 600585)
+++ src/java/org/apache/lucene/search/ExtendedFieldCacheImpl.java	(working copy)
@@ -1,117 +0,0 @@
-package org.apache.lucene.search;
-
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.Term;
-import org.apache.lucene.index.TermDocs;
-import org.apache.lucene.index.TermEnum;
-
-import java.io.IOException;
-
-
-/**
- *
- *
- **/
-class ExtendedFieldCacheImpl extends FieldCacheImpl implements ExtendedFieldCache {
-  private static final LongParser LONG_PARSER = new LongParser() {
-      public long parseLong(String value) {
-        return Long.parseLong(value);
-      }
-  };
-
-  private static final DoubleParser DOUBLE_PARSER = new DoubleParser() {
-      public double parseDouble(String value) {
-        return Double.parseDouble(value);
-      }
-  };
-
-  private static final ByteParser BYTE_PARSER = new ByteParser() {
-    public byte parseByte(String string) {
-      return Byte.parseByte(string);
-    }
-  };
-
-  private static final ShortParser SHORT_PARSER = new ShortParser() {
-    public short parseShort(String string) {
-      return Short.parseShort(string);
-    }
-  };
-
-  public long[] getLongs(IndexReader reader, String field) throws IOException {
-    return getLongs(reader, field, LONG_PARSER);
-  }
-
-  // inherit javadocs
-  public long[] getLongs(IndexReader reader, String field, LongParser parser)
-      throws IOException {
-    return (long[]) longsCache.get(reader, new Entry(field, parser));
-  }
-
-  Cache longsCache = new Cache() {
-
-    protected Object createValue(IndexReader reader, Object entryKey)
-        throws IOException {
-      Entry entry = (Entry) entryKey;
-      String field = entry.field;
-      LongParser parser = (LongParser) entry.custom;
-      final long[] retArray = new long[reader.maxDoc()];
-      TermDocs termDocs = reader.termDocs();
-      TermEnum termEnum = reader.terms (new Term(field, ""));
-      try {
-        do {
-          Term term = termEnum.term();
-          if (term==null || term.field() != field) break;
-          long termval = parser.parseLong(term.text());
-          termDocs.seek (termEnum);
-          while (termDocs.next()) {
-            retArray[termDocs.doc()] = termval;
-          }
-        } while (termEnum.next());
-      } finally {
-        termDocs.close();
-        termEnum.close();
-      }
-      return retArray;
-    }
-  };
-
-  // inherit javadocs
-  public double[] getDoubles(IndexReader reader, String field)
-    throws IOException {
-    return getDoubles(reader, field, DOUBLE_PARSER);
-  }
-
-  // inherit javadocs
-  public double[] getDoubles(IndexReader reader, String field, DoubleParser parser)
-      throws IOException {
-    return (double[]) doublesCache.get(reader, new Entry(field, parser));
-  }
-
-  Cache doublesCache = new Cache() {
-
-    protected Object createValue(IndexReader reader, Object entryKey)
-        throws IOException {
-      Entry entry = (Entry) entryKey;
-      String field = entry.field;
-      DoubleParser parser = (DoubleParser) entry.custom;
-      final double[] retArray = new double[reader.maxDoc()];
-      TermDocs termDocs = reader.termDocs();
-      TermEnum termEnum = reader.terms (new Term (field, ""));
-      try {
-        do {
-          Term term = termEnum.term();
-          if (term==null || term.field() != field) break;
-          double termval = parser.parseDouble(term.text());
-          termDocs.seek (termEnum);
-          while (termDocs.next()) {
-            retArray[termDocs.doc()] = termval;
-          }
-        } while (termEnum.next());
-      } finally {
-        termDocs.close();
-        termEnum.close();
-      }
-      return retArray;
-    }
-  };
-}
Index: src/java/org/apache/lucene/search/FieldSortedHitQueue.java
===================================================================
--- src/java/org/apache/lucene/search/FieldSortedHitQueue.java	(revision 600585)
+++ src/java/org/apache/lucene/search/FieldSortedHitQueue.java	(working copy)
@@ -149,19 +149,19 @@
   throws IOException {
     if (type == SortField.DOC) return ScoreDocComparator.INDEXORDER;
     if (type == SortField.SCORE) return ScoreDocComparator.RELEVANCE;
-    FieldCacheImpl.Entry entry = (factory != null)
-      ? new FieldCacheImpl.Entry (field, factory)
-      : new FieldCacheImpl.Entry (field, type, locale);
+    FieldCache.Entry entry = (factory != null)
+      ? new FieldCache.Entry (field, factory)
+      : new FieldCache.Entry (field, type, locale);
     return (ScoreDocComparator)Comparators.get(reader, entry);
   }
 
   /** Internal cache of comparators. Similar to FieldCache, only
    *  caches comparators instead of term values. */
-  static final FieldCacheImpl.Cache Comparators = new FieldCacheImpl.Cache() {
+  static final FieldCache.Cache Comparators = new FieldCache.Cache() {
 
     protected Object createValue(IndexReader reader, Object entryKey)
         throws IOException {
-      FieldCacheImpl.Entry entry = (FieldCacheImpl.Entry) entryKey;
+      FieldCache.Entry entry = (FieldCache.Entry) entryKey;
       String fieldname = entry.field;
       int type = entry.type;
       Locale locale = entry.locale;
@@ -174,6 +174,12 @@
         case SortField.INT:
           comparator = comparatorInt (reader, fieldname);
           break;
+        case SortField.SHORT:
+          comparator = comparatorShort(reader, fieldname);
+          break;
+        case SortField.BYTE:
+          comparator = comparatorByte(reader, fieldname);
+          break;
         case SortField.FLOAT:
           comparator = comparatorFloat (reader, fieldname);
           break;
@@ -198,6 +204,68 @@
   };
 
   /**
+   * Returns a comparator for sorting hits according to a field containing bytes.
+   * @param reader  Index to use.
+   * @param fieldname  Fieldable containg integer values.
+   * @return  Comparator for sorting hits.
+   * @throws IOException If an error occurs reading the index.
+   */
+  static ScoreDocComparator comparatorByte(final IndexReader reader, final String fieldname)
+  throws IOException {
+    final String field = fieldname.intern();
+    final byte[] fieldOrder = FieldCache.DEFAULT.getBytes(reader, field);
+    return new ScoreDocComparator() {
+
+      public final int compare (final ScoreDoc i, final ScoreDoc j) {
+        final int fi = fieldOrder[i.doc];
+        final int fj = fieldOrder[j.doc];
+        if (fi < fj) return -1;
+        if (fi > fj) return 1;
+        return 0;
+      }
+
+      public Comparable sortValue (final ScoreDoc i) {
+        return new Byte(fieldOrder[i.doc]);
+      }
+
+      public int sortType() {
+        return SortField.INT;
+      }
+    };
+  }
+
+  /**
+   * Returns a comparator for sorting hits according to a field containing shorts.
+   * @param reader  Index to use.
+   * @param fieldname  Fieldable containg integer values.
+   * @return  Comparator for sorting hits.
+   * @throws IOException If an error occurs reading the index.
+   */
+  static ScoreDocComparator comparatorShort(final IndexReader reader, final String fieldname)
+  throws IOException {
+    final String field = fieldname.intern();
+    final short[] fieldOrder = FieldCache.DEFAULT.getShorts(reader, field);
+    return new ScoreDocComparator() {
+
+      public final int compare (final ScoreDoc i, final ScoreDoc j) {
+        final int fi = fieldOrder[i.doc];
+        final int fj = fieldOrder[j.doc];
+        if (fi < fj) return -1;
+        if (fi > fj) return 1;
+        return 0;
+      }
+
+      public Comparable sortValue (final ScoreDoc i) {
+        return new Short(fieldOrder[i.doc]);
+      }
+
+      public int sortType() {
+        return SortField.SHORT;
+      }
+    };
+  }
+
+  /**
    * Returns a comparator for sorting hits according to a field containing integers.
    * @param reader  Index to use.
    * @param fieldname  Fieldable containg integer values.
@@ -238,7 +306,7 @@
   static ScoreDocComparator comparatorLong (final IndexReader reader, final String fieldname)
   throws IOException {
     final String field = fieldname.intern();
-    final long[] fieldOrder = ExtendedFieldCache.EXT_DEFAULT.getLongs (reader, field);
+    final long[] fieldOrder = FieldCache.DEFAULT.getLongs (reader, field);
     return new ScoreDocComparator() {
 
       public final int compare (final ScoreDoc i, final ScoreDoc j) {
@@ -301,7 +369,7 @@
   static ScoreDocComparator comparatorDouble(final IndexReader reader, final String fieldname)
   throws IOException {
     final String field = fieldname.intern();
-    final double[] fieldOrder = ExtendedFieldCache.EXT_DEFAULT.getDoubles (reader, field);
+    final double[] fieldOrder = FieldCache.DEFAULT.getDoubles (reader, field);
     return new ScoreDocComparator () {
 
       public final int compare (final ScoreDoc i, final ScoreDoc j) {
Index: src/java/org/apache/lucene/search/ExtendedFieldCache.java
===================================================================
--- src/java/org/apache/lucene/search/ExtendedFieldCache.java	(revision 600585)
+++ src/java/org/apache/lucene/search/ExtendedFieldCache.java	(working copy)
@@ -1,87 +0,0 @@
-package org.apache.lucene.search;
-
-import org.apache.lucene.index.IndexReader;
-
-import java.io.IOException;
-
-
-/**
- *
- *
- **/
-public interface ExtendedFieldCache extends FieldCache {
-  public interface LongParser {
-    /**
-     * Return an long representation of this field's value.
-     */
-    public long parseLong(String string);
-  }
-
-  public interface DoubleParser {
-    /**
-     * Return an long representation of this field's value.
-     */
-    public double parseDouble(String string);
-  }
-
-  public static ExtendedFieldCache EXT_DEFAULT = new ExtendedFieldCacheImpl();
-
-  /**
-   * Checks the internal cache for an appropriate entry, and if none is
-   * found, reads the terms in <code>field</code> as longs and returns an array
-   * of size <code>reader.maxDoc()</code> of the value each document
-   * has in the given field.
-   *
-   * @param reader Used to get field values.
-   * @param field  Which field contains the longs.
-   * @return The values in the given field for each document.
-   * @throws java.io.IOException If any error occurs.
-   */
-  public long[] getLongs(IndexReader reader, String field)
-          throws IOException;
-
-  /**
-   * Checks the internal cache for an appropriate entry, and if none is found,
-   * reads the terms in <code>field</code> as longs and returns an array of
-   * size <code>reader.maxDoc()</code> of the value each document has in the
-   * given field.
-   *
-   * @param reader Used to get field values.
-   * @param field  Which field contains the longs.
-   * @param parser Computes integer for string values.
-   * @return The values in the given field for each document.
-   * @throws IOException If any error occurs.
-   */
-  public long[] getLongs(IndexReader reader, String field, LongParser parser)
-          throws IOException;
-
-
-  /**
-   * Checks the internal cache for an appropriate entry, and if none is
-   * found, reads the terms in <code>field</code> as integers and returns an array
-   * of size <code>reader.maxDoc()</code> of the value each document
-   * has in the given field.
-   *
-   * @param reader Used to get field values.
-   * @param field  Which field contains the doubles.
-   * @return The values in the given field for each document.
-   * @throws IOException If any error occurs.
-   */
-  public double[] getDoubles(IndexReader reader, String field)
-          throws IOException;
-
-  /**
-   * Checks the internal cache for an appropriate entry, and if none is found,
-   * reads the terms in <code>field</code> as doubles and returns an array of
-   * size <code>reader.maxDoc()</code> of the value each document has in the
-   * given field.
-   *
-   * @param reader Used to get field values.
-   * @param field  Which field contains the doubles.
-   * @param parser Computes integer for string values.
-   * @return The values in the given field for each document.
-   * @throws IOException If any error occurs.
-   */
-  public double[] getDoubles(IndexReader reader, String field, DoubleParser parser)
-          throws IOException;
-}
Index: src/java/org/apache/lucene/search/SortField.java
===================================================================
--- src/java/org/apache/lucene/search/SortField.java	(revision 600585)
+++ src/java/org/apache/lucene/search/SortField.java	(working copy)
@@ -68,10 +68,20 @@
    * lower values are at the front. */
   public static final int DOUBLE = 7;
 
+  /**
+   * Sort using term values as encoded Shorts.  Sort values are shorts and lower values are at the front
+   */
+  public static final int SHORT = 8;
+
   /** Sort using a custom Comparator.  Sort values are any Comparable and
    * sorting is done according to natural order. */
   public static final int CUSTOM = 9;
 
+  /**
+   * Sort using term values as encoded bytes.  Sort values are bytes and lower values are at the front
+   */
+  public static final int BYTE = 10;
+
   // IMPLEMENTATION NOTE: the FieldCache.STRING_INDEX is in the same "namespace"
   // as the above static int values.  Any new values must not have the same value
   // as FieldCache.STRING_INDEX.
Index: src/java/org/apache/lucene/search/FieldCacheImpl.java
===================================================================
--- src/java/org/apache/lucene/search/FieldCacheImpl.java	(revision 600585)
+++ src/java/org/apache/lucene/search/FieldCacheImpl.java	(working copy)
@@ -1,560 +0,0 @@
-package org.apache.lucene.search;
-
-/**
- * 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.
- */
-
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.Term;
-import org.apache.lucene.index.TermDocs;
-import org.apache.lucene.index.TermEnum;
-import org.apache.lucene.search.ExtendedFieldCache.LongParser;
-
-import java.io.IOException;
-import java.util.Locale;
-import java.util.Map;
-import java.util.WeakHashMap;
-import java.util.HashMap;
-
-/**
- * Expert: The default cache implementation, storing all values in memory.
- * A WeakHashMap is used for storage.
- *
- * <p>Created: May 19, 2004 4:40:36 PM
- *
- * @author  Tim Jones (Nacimiento Software)
- * @since   lucene 1.4
- * @version $Id$
- */
-class FieldCacheImpl
-implements FieldCache {
-	
-  /** Expert: Internal cache. */
-  abstract static class Cache {
-    private final Map readerCache = new WeakHashMap();
-    
-    protected abstract Object createValue(IndexReader reader, Object key)
-        throws IOException;
-
-    public Object get(IndexReader reader, Object key) throws IOException {
-      Map innerCache;
-      Object value;
-      synchronized (readerCache) {
-        innerCache = (Map) readerCache.get(reader);
-        if (innerCache == null) {
-          innerCache = new HashMap();
-          readerCache.put(reader, innerCache);
-          value = null;
-        } else {
-          value = innerCache.get(key);
-        }
-        if (value == null) {
-          value = new CreationPlaceholder();
-          innerCache.put(key, value);
-        }
-      }
-      if (value instanceof CreationPlaceholder) {
-        synchronized (value) {
-          CreationPlaceholder progress = (CreationPlaceholder) value;
-          if (progress.value == null) {
-            progress.value = createValue(reader, key);
-            synchronized (readerCache) {
-              innerCache.put(key, progress.value);
-            }
-          }
-          return progress.value;
-        }
-      }
-      return value;
-    }
-  }
-
-  static final class CreationPlaceholder {
-    Object value;
-  }
-
-  /** Expert: Every composite-key in the internal cache is of this type. */
-  static class Entry {
-    final String field;        // which Fieldable
-    final int type;            // which SortField type
-    final Object custom;       // which custom comparator
-    final Locale locale;       // the locale we're sorting (if string)
-
-    /** Creates one of these objects. */
-    Entry (String field, int type, Locale locale) {
-      this.field = field.intern();
-      this.type = type;
-      this.custom = null;
-      this.locale = locale;
-    }
-
-    /** Creates one of these objects for a custom comparator. */
-    Entry (String field, Object custom) {
-      this.field = field.intern();
-      this.type = SortField.CUSTOM;
-      this.custom = custom;
-      this.locale = null;
-    }
-
-    /** Two of these are equal iff they reference the same field and type. */
-    public boolean equals (Object o) {
-      if (o instanceof Entry) {
-        Entry other = (Entry) o;
-        if (other.field == field && other.type == type) {
-          if (other.locale == null ? locale == null : other.locale.equals(locale)) {
-            if (other.custom == null) {
-              if (custom == null) return true;
-            } else if (other.custom.equals (custom)) {
-              return true;
-            }
-          }
-        }
-      }
-      return false;
-    }
-
-    /** Composes a hashcode based on the field and type. */
-    public int hashCode() {
-      return field.hashCode() ^ type ^ (custom==null ? 0 : custom.hashCode()) ^ (locale==null ? 0 : locale.hashCode());
-    }
-  }
-
-  private static final ByteParser BYTE_PARSER = new ByteParser() {
-    public byte parseByte(String value) {
-      return Byte.parseByte(value);
-    }
-  };
-
-  private static final ShortParser SHORT_PARSER = new ShortParser() {
-    public short parseShort(String value) {
-      return Short.parseShort(value);
-    }
-  };
-
-  private static final IntParser INT_PARSER = new IntParser() {
-      public int parseInt(String value) {
-        return Integer.parseInt(value);
-      }
-  };
-
-  private static final LongParser LONG_PARSER = new LongParser() {
-    public long parseLong(String value) {
-      return Long.parseLong(value);
-    }
-  };
-
-  private static final FloatParser FLOAT_PARSER = new FloatParser() {
-      public float parseFloat(String value) {
-        return Float.parseFloat(value);
-      }
-  };
-
-  // inherit javadocs
-  public byte[] getBytes (IndexReader reader, String field) throws IOException {
-    return getBytes(reader, field, BYTE_PARSER);
-  }
-
-  // inherit javadocs
-  public byte[] getBytes(IndexReader reader, String field, ByteParser parser)
-      throws IOException {
-    return (byte[]) bytesCache.get(reader, new Entry(field, parser));
-  }
-
-  Cache bytesCache = new Cache() {
-
-    protected Object createValue(IndexReader reader, Object entryKey)
-        throws IOException {
-      Entry entry = (Entry) entryKey;
-      String field = entry.field;
-      ByteParser parser = (ByteParser) entry.custom;
-      final byte[] retArray = new byte[reader.maxDoc()];
-      TermDocs termDocs = reader.termDocs();
-      TermEnum termEnum = reader.terms (new Term (field, ""));
-      try {
-        do {
-          Term term = termEnum.term();
-          if (term==null || term.field() != field) break;
-          byte termval = parser.parseByte(term.text());
-          termDocs.seek (termEnum);
-          while (termDocs.next()) {
-            retArray[termDocs.doc()] = termval;
-          }
-        } while (termEnum.next());
-      } finally {
-        termDocs.close();
-        termEnum.close();
-      }
-      return retArray;
-    }
-  };
-  
-  // inherit javadocs
-  public short[] getShorts (IndexReader reader, String field) throws IOException {
-    return getShorts(reader, field, SHORT_PARSER);
-  }
-
-  // inherit javadocs
-  public short[] getShorts(IndexReader reader, String field, ShortParser parser)
-      throws IOException {
-    return (short[]) shortsCache.get(reader, new Entry(field, parser));
-  }
-
-  Cache shortsCache = new Cache() {
-
-    protected Object createValue(IndexReader reader, Object entryKey)
-        throws IOException {
-      Entry entry = (Entry) entryKey;
-      String field = entry.field;
-      ShortParser parser = (ShortParser) entry.custom;
-      final short[] retArray = new short[reader.maxDoc()];
-      TermDocs termDocs = reader.termDocs();
-      TermEnum termEnum = reader.terms (new Term (field, ""));
-      try {
-        do {
-          Term term = termEnum.term();
-          if (term==null || term.field() != field) break;
-          short termval = parser.parseShort(term.text());
-          termDocs.seek (termEnum);
-          while (termDocs.next()) {
-            retArray[termDocs.doc()] = termval;
-          }
-        } while (termEnum.next());
-      } finally {
-        termDocs.close();
-        termEnum.close();
-      }
-      return retArray;
-    }
-  };
-  
-  // inherit javadocs
-  public int[] getInts (IndexReader reader, String field) throws IOException {
-    return getInts(reader, field, INT_PARSER);
-  }
-
-  // inherit javadocs
-  public int[] getInts(IndexReader reader, String field, IntParser parser)
-      throws IOException {
-    return (int[]) intsCache.get(reader, new Entry(field, parser));
-  }
-
-  Cache intsCache = new Cache() {
-
-    protected Object createValue(IndexReader reader, Object entryKey)
-        throws IOException {
-      Entry entry = (Entry) entryKey;
-      String field = entry.field;
-      IntParser parser = (IntParser) entry.custom;
-      final int[] retArray = new int[reader.maxDoc()];
-      TermDocs termDocs = reader.termDocs();
-      TermEnum termEnum = reader.terms (new Term (field, ""));
-      try {
-        do {
-          Term term = termEnum.term();
-          if (term==null || term.field() != field) break;
-          int termval = parser.parseInt(term.text());
-          termDocs.seek (termEnum);
-          while (termDocs.next()) {
-            retArray[termDocs.doc()] = termval;
-          }
-        } while (termEnum.next());
-      } finally {
-        termDocs.close();
-        termEnum.close();
-      }
-      return retArray;
-    }
-  };
-
-  // inherit javadocs
-  public long[] getLongs (IndexReader reader, String field) throws IOException {
-    return getLongs(reader, field, LONG_PARSER);
-  }
-
-  // inherit javadocs
-  public long[] getLongs(IndexReader reader, String field, LongParser parser)
-      throws IOException {
-    return (long[]) longsCache.get(reader, new Entry(field, parser));
-  }
-
-  Cache longsCache = new Cache() {
-
-    protected Object createValue(IndexReader reader, Object entryKey)
-        throws IOException {
-      Entry entry = (Entry) entryKey;
-      String field = entry.field;
-      LongParser parser = (LongParser) entry.custom;
-      final long[] retArray = new long[reader.maxDoc()];
-      TermDocs termDocs = reader.termDocs();
-      TermEnum termEnum = reader.terms (new Term (field, ""));
-      try {
-        do {
-          Term term = termEnum.term();
-          if (term==null || term.field() != field) break;
-          long termval = parser.parseLong(term.text());
-          termDocs.seek (termEnum);
-          while (termDocs.next()) {
-            retArray[termDocs.doc()] = termval;
-          }
-        } while (termEnum.next());
-      } finally {
-        termDocs.close();
-        termEnum.close();
-      }
-      return retArray;
-    }
-  };
-
-  // inherit javadocs
-  public float[] getFloats (IndexReader reader, String field)
-    throws IOException {
-    return getFloats(reader, field, FLOAT_PARSER);
-  }
-
-  // inherit javadocs
-  public float[] getFloats(IndexReader reader, String field, FloatParser parser)
-      throws IOException {
-    return (float[]) floatsCache.get(reader, new Entry(field, parser));
-  }
-
-  Cache floatsCache = new Cache() {
-
-    protected Object createValue(IndexReader reader, Object entryKey)
-        throws IOException {
-      Entry entry = (Entry) entryKey;
-      String field = entry.field;
-      FloatParser parser = (FloatParser) entry.custom;
-      final float[] retArray = new float[reader.maxDoc()];
-      TermDocs termDocs = reader.termDocs();
-      TermEnum termEnum = reader.terms (new Term (field, ""));
-      try {
-        do {
-          Term term = termEnum.term();
-          if (term==null || term.field() != field) break;
-          float termval = parser.parseFloat(term.text());
-          termDocs.seek (termEnum);
-          while (termDocs.next()) {
-            retArray[termDocs.doc()] = termval;
-          }
-        } while (termEnum.next());
-      } finally {
-        termDocs.close();
-        termEnum.close();
-      }
-      return retArray;
-    }
-  };
-
-  // inherit javadocs
-  public String[] getStrings(IndexReader reader, String field)
-      throws IOException {
-    return (String[]) stringsCache.get(reader, field);
-  }
-
-  Cache stringsCache = new Cache() {
-
-    protected Object createValue(IndexReader reader, Object fieldKey)
-        throws IOException {
-      String field = ((String) fieldKey).intern();
-      final String[] retArray = new String[reader.maxDoc()];
-      TermDocs termDocs = reader.termDocs();
-      TermEnum termEnum = reader.terms (new Term (field, ""));
-      try {
-        do {
-          Term term = termEnum.term();
-          if (term==null || term.field() != field) break;
-          String termval = term.text();
-          termDocs.seek (termEnum);
-          while (termDocs.next()) {
-            retArray[termDocs.doc()] = termval;
-          }
-        } while (termEnum.next());
-      } finally {
-        termDocs.close();
-        termEnum.close();
-      }
-      return retArray;
-    }
-  };
-
-  // inherit javadocs
-  public StringIndex getStringIndex(IndexReader reader, String field)
-      throws IOException {
-    return (StringIndex) stringsIndexCache.get(reader, field);
-  }
-
-  Cache stringsIndexCache = new Cache() {
-
-    protected Object createValue(IndexReader reader, Object fieldKey)
-        throws IOException {
-      String field = ((String) fieldKey).intern();
-      final int[] retArray = new int[reader.maxDoc()];
-      String[] mterms = new String[reader.maxDoc()+1];
-      TermDocs termDocs = reader.termDocs();
-      TermEnum termEnum = reader.terms (new Term (field, ""));
-      int t = 0;  // current term number
-
-      // an entry for documents that have no terms in this field
-      // should a document with no terms be at top or bottom?
-      // this puts them at the top - if it is changed, FieldDocSortedHitQueue
-      // needs to change as well.
-      mterms[t++] = null;
-
-      try {
-        do {
-          Term term = termEnum.term();
-          if (term==null || term.field() != field) break;
-
-          // store term text
-          // we expect that there is at most one term per document
-          if (t >= mterms.length) throw new RuntimeException ("there are more terms than " +
-                  "documents in field \"" + field + "\", but it's impossible to sort on " +
-                  "tokenized fields");
-          mterms[t] = term.text();
-
-          termDocs.seek (termEnum);
-          while (termDocs.next()) {
-            retArray[termDocs.doc()] = t;
-          }
-
-          t++;
-        } while (termEnum.next());
-      } finally {
-        termDocs.close();
-        termEnum.close();
-      }
-
-      if (t == 0) {
-        // if there are no terms, make the term array
-        // have a single null entry
-        mterms = new String[1];
-      } else if (t < mterms.length) {
-        // if there are less terms than documents,
-        // trim off the dead array space
-        String[] terms = new String[t];
-        System.arraycopy (mterms, 0, terms, 0, t);
-        mterms = terms;
-      }
-
-      StringIndex value = new StringIndex (retArray, mterms);
-      return value;
-    }
-  };
-
-  /** The pattern used to detect integer values in a field */
-  /** removed for java 1.3 compatibility
-   protected static final Pattern pIntegers = Pattern.compile ("[0-9\\-]+");
-   **/
-
-  /** The pattern used to detect float values in a field */
-  /**
-   * removed for java 1.3 compatibility
-   * protected static final Object pFloats = Pattern.compile ("[0-9+\\-\\.eEfFdD]+");
-   */
-
-	// inherit javadocs
-  public Object getAuto(IndexReader reader, String field) throws IOException {
-    return autoCache.get(reader, field);
-  }
-
-  Cache autoCache = new Cache() {
-
-    protected Object createValue(IndexReader reader, Object fieldKey)
-        throws IOException {
-      String field = ((String)fieldKey).intern();
-      TermEnum enumerator = reader.terms (new Term (field, ""));
-      try {
-        Term term = enumerator.term();
-        if (term == null) {
-          throw new RuntimeException ("no terms in field " + field + " - cannot determine sort type");
-        }
-        Object ret = null;
-        if (term.field() == field) {
-          String termtext = term.text().trim();
-
-          /**
-           * Java 1.4 level code:
-
-           if (pIntegers.matcher(termtext).matches())
-           return IntegerSortedHitQueue.comparator (reader, enumerator, field);
-
-           else if (pFloats.matcher(termtext).matches())
-           return FloatSortedHitQueue.comparator (reader, enumerator, field);
-           */
-
-          // Java 1.3 level code:
-          try {
-            Integer.parseInt (termtext);
-            ret = getInts (reader, field);
-          } catch (NumberFormatException nfe1) {
-            try {
-              Long.parseLong(termtext);
-              ret = getLongs (reader, field);
-            } catch (NumberFormatException nfe2) {
-              try {
-                Float.parseFloat (termtext);
-                ret = getFloats (reader, field);
-              } catch (NumberFormatException nfe3) {
-                ret = getStringIndex (reader, field);
-              }
-            }
-          }          
-        } else {
-          throw new RuntimeException ("field \"" + field + "\" does not appear to be indexed");
-        }
-        return ret;
-      } finally {
-        enumerator.close();
-      }
-    }
-  };
-
-  // inherit javadocs
-  public Comparable[] getCustom(IndexReader reader, String field,
-      SortComparator comparator) throws IOException {
-    return (Comparable[]) customCache.get(reader, new Entry(field, comparator));
-  }
-
-  Cache customCache = new Cache() {
-
-    protected Object createValue(IndexReader reader, Object entryKey)
-        throws IOException {
-      Entry entry = (Entry) entryKey;
-      String field = entry.field;
-      SortComparator comparator = (SortComparator) entry.custom;
-      final Comparable[] retArray = new Comparable[reader.maxDoc()];
-      TermDocs termDocs = reader.termDocs();
-      TermEnum termEnum = reader.terms (new Term (field, ""));
-      try {
-        do {
-          Term term = termEnum.term();
-          if (term==null || term.field() != field) break;
-          Comparable termval = comparator.getComparable (term.text());
-          termDocs.seek (termEnum);
-          while (termDocs.next()) {
-            retArray[termDocs.doc()] = termval;
-          }
-        } while (termEnum.next());
-      } finally {
-        termDocs.close();
-        termEnum.close();
-      }
-      return retArray;
-    }
-  };
-  
-}
-
