TEST_F(SegmentTermEnumTest, testPrevTermAtEnd) {
    DirectoryPtr dir = newLucene<MockRAMDirectory>();
    IndexWriterPtr writer  = newLucene<IndexWriter>(dir, newLucene<WhitespaceAnalyzer>(), true, IndexWriter::MaxFieldLengthLIMITED);
    addDoc(writer, L"aaa bbb");
    writer->close();
    SegmentReaderPtr reader = SegmentReader::getOnlySegmentReader(dir);
    SegmentTermEnumPtr termEnum = boost::dynamic_pointer_cast<SegmentTermEnum>(reader->terms());
    EXPECT_TRUE(termEnum->next());
    EXPECT_EQ(L"aaa", termEnum->term()->text());
    EXPECT_TRUE(termEnum->next());
    EXPECT_EQ(L"aaa", termEnum->prev()->text());
    EXPECT_EQ(L"bbb", termEnum->term()->text());
    EXPECT_TRUE(!termEnum->next());
    EXPECT_EQ(L"bbb", termEnum->prev()->text());
}
 TermInfoPtr TermInfosReader::get(TermPtr term, bool useCache)
 {
     if (_size == 0)
         return TermInfoPtr();
     
     ensureIndexIsRead();
     
     TermInfoPtr ti;
     TermInfosReaderThreadResourcesPtr resources(getThreadResources());
     TermInfoCachePtr cache;
     
     if (useCache)
     {
         cache = resources->termInfoCache;
         // check the cache first if the term was recently looked up
         ti = cache->get(term);
         if (ti)
             return ti;
     }
     
     // optimize sequential access: first try scanning cached enum without seeking
     SegmentTermEnumPtr enumerator = resources->termEnum;
     
     if (enumerator->term() && // term is at or past current
         ((enumerator->prev() && term->compareTo(enumerator->prev()) > 0) ||
         term->compareTo(enumerator->term()) >= 0))
     {
         int32_t enumOffset = (int32_t)(enumerator->position / totalIndexInterval ) + 1;
         if (indexTerms.size() == enumOffset || // but before end of block
             term->compareTo(indexTerms[enumOffset]) < 0)
         {
             // no need to seek
             int32_t numScans = enumerator->scanTo(term);
             if (enumerator->term() && term->compareTo(enumerator->term()) == 0)
             {
                 ti = enumerator->termInfo();
                 if (cache && numScans > 1)
                 {
                     // we only want to put this TermInfo into the cache if scanEnum skipped more 
                     // than one dictionary entry. This prevents RangeQueries or WildcardQueries to 
                     // wipe out the cache when they iterate over a large numbers of terms in order.
                     cache->put(term, ti);
                 }
             }
             else
                 ti.reset();
             return ti;
         }
     }
     
     // random-access: must seek
     seekEnum(enumerator, getIndexOffset(term));
     enumerator->scanTo(term);
     if (enumerator->term() && term->compareTo(enumerator->term()) == 0)
     {
         ti = enumerator->termInfo();
         if (cache)
             cache->put(term, ti);
     }
     else
         ti.reset();
     return ti;
 }
 void TermInfosReader::seekEnum(SegmentTermEnumPtr enumerator, int32_t indexOffset)
 {
     enumerator->seek(indexPointers[indexOffset], ((int64_t)indexOffset * (int64_t)totalIndexInterval) - 1, indexTerms[indexOffset], indexInfos[indexOffset]);
 }