Merge pull request #409 from Alkarex/patch-1
[mono.git] / mcs / tools / monkeydoc / Lucene.Net / Lucene.Net / Search / NumericRangeQuery.cs
1 /* 
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  * 
9  * http://www.apache.org/licenses/LICENSE-2.0
10  * 
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 using System;
19
20 using NumericTokenStream = Mono.Lucene.Net.Analysis.NumericTokenStream;
21 using NumericField = Mono.Lucene.Net.Documents.NumericField;
22 using IndexReader = Mono.Lucene.Net.Index.IndexReader;
23 using Term = Mono.Lucene.Net.Index.Term;
24 using NumericUtils = Mono.Lucene.Net.Util.NumericUtils;
25 using StringHelper = Mono.Lucene.Net.Util.StringHelper;
26 using ToStringUtils = Mono.Lucene.Net.Util.ToStringUtils;
27
28 namespace Mono.Lucene.Net.Search
29 {
30         
31         /// <summary> <p/>A {@link Query} that matches numeric values within a
32         /// specified range.  To use this, you must first index the
33         /// numeric values using {@link NumericField} (expert: {@link
34         /// NumericTokenStream}).  If your terms are instead textual,
35         /// you should use {@link TermRangeQuery}.  {@link
36         /// NumericRangeFilter} is the filter equivalent of this
37         /// query.<p/>
38         /// 
39         /// <p/>You create a new NumericRangeQuery with the static
40         /// factory methods, eg:
41         /// 
42         /// <pre>
43         /// Query q = NumericRangeQuery.newFloatRange("weight",
44         /// new Float(0.3f), new Float(0.10f),
45         /// true, true);
46         /// </pre>
47         /// 
48         /// matches all documents whose float valued "weight" field
49         /// ranges from 0.3 to 0.10, inclusive.
50         /// 
51         /// <p/>The performance of NumericRangeQuery is much better
52         /// than the corresponding {@link TermRangeQuery} because the
53         /// number of terms that must be searched is usually far
54         /// fewer, thanks to trie indexing, described below.<p/>
55         /// 
56         /// <p/>You can optionally specify a <a
57         /// href="#precisionStepDesc"><code>precisionStep</code></a>
58         /// when creating this query.  This is necessary if you've
59         /// changed this configuration from its default (4) during
60         /// indexing.  Lower values consume more disk space but speed
61         /// up searching.  Suitable values are between <b>1</b> and
62         /// <b>8</b>. A good starting point to test is <b>4</b>,
63         /// which is the default value for all <code>Numeric*</code>
64         /// classes.  See <a href="#precisionStepDesc">below</a> for
65         /// details.
66         /// 
67         /// <p/>This query defaults to {@linkplain
68         /// MultiTermQuery#CONSTANT_SCORE_AUTO_REWRITE_DEFAULT} for
69         /// 32 bit (int/float) ranges with precisionStep &lt;8 and 64
70         /// bit (long/double) ranges with precisionStep &lt;6.
71         /// Otherwise it uses {@linkplain
72         /// MultiTermQuery#CONSTANT_SCORE_FILTER_REWRITE} as the
73         /// number of terms is likely to be high.  With precision
74         /// steps of &lt;4, this query can be run with one of the
75         /// BooleanQuery rewrite methods without changing
76         /// BooleanQuery's default max clause count.
77         /// 
78         /// <p/><font color="red"><b>NOTE:</b> This API is experimental and
79         /// might change in incompatible ways in the next release.</font>
80         /// 
81         /// <br/><h3>How it works</h3>
82         /// 
83         /// <p/>See the publication about <a target="_blank" href="http://www.panfmp.org">panFMP</a>,
84         /// where this algorithm was described (referred to as <code>TrieRangeQuery</code>):
85         /// 
86         /// <blockquote><strong>Schindler, U, Diepenbroek, M</strong>, 2008.
87         /// <em>Generic XML-based Framework for Metadata Portals.</em>
88         /// Computers &amp; Geosciences 34 (12), 1947-1955.
89         /// <a href="http://dx.doi.org/10.1016/j.cageo.2008.02.023"
90         /// target="_blank">doi:10.1016/j.cageo.2008.02.023</a></blockquote>
91         /// 
92         /// <p/><em>A quote from this paper:</em> Because Apache Lucene is a full-text
93         /// search engine and not a conventional database, it cannot handle numerical ranges
94         /// (e.g., field value is inside user defined bounds, even dates are numerical values).
95         /// We have developed an extension to Apache Lucene that stores
96         /// the numerical values in a special string-encoded format with variable precision
97         /// (all numerical values like doubles, longs, floats, and ints are converted to
98         /// lexicographic sortable string representations and stored with different precisions
99         /// (for a more detailed description of how the values are stored,
100         /// see {@link NumericUtils}). A range is then divided recursively into multiple intervals for searching:
101         /// The center of the range is searched only with the lowest possible precision in the <em>trie</em>,
102         /// while the boundaries are matched more exactly. This reduces the number of terms dramatically.<p/>
103         /// 
104         /// <p/>For the variant that stores long values in 8 different precisions (each reduced by 8 bits) that
105         /// uses a lowest precision of 1 byte, the index contains only a maximum of 256 distinct values in the
106         /// lowest precision. Overall, a range could consist of a theoretical maximum of
107         /// <code>7*255*2 + 255 = 3825</code> distinct terms (when there is a term for every distinct value of an
108         /// 8-byte-number in the index and the range covers almost all of them; a maximum of 255 distinct values is used
109         /// because it would always be possible to reduce the full 256 values to one term with degraded precision).
110         /// In practice, we have seen up to 300 terms in most cases (index with 500,000 metadata records
111         /// and a uniform value distribution).<p/>
112         /// 
113         /// <a name="precisionStepDesc"/><h3>Precision Step</h3>
114         /// <p/>You can choose any <code>precisionStep</code> when encoding values.
115         /// Lower step values mean more precisions and so more terms in index (and index gets larger).
116         /// On the other hand, the maximum number of terms to match reduces, which optimized query speed.
117         /// The formula to calculate the maximum term count is:
118         /// <pre>
119         /// n = [ (bitsPerValue/precisionStep - 1) * (2^precisionStep - 1 ) * 2 ] + (2^precisionStep - 1 )
120         /// </pre>
121         /// <p/><em>(this formula is only correct, when <code>bitsPerValue/precisionStep</code> is an integer;
122         /// in other cases, the value must be rounded up and the last summand must contain the modulo of the division as
123         /// precision step)</em>.
124         /// For longs stored using a precision step of 4, <code>n = 15*15*2 + 15 = 465</code>, and for a precision
125         /// step of 2, <code>n = 31*3*2 + 3 = 189</code>. But the faster search speed is reduced by more seeking
126         /// in the term enum of the index. Because of this, the ideal <code>precisionStep</code> value can only
127         /// be found out by testing. <b>Important:</b> You can index with a lower precision step value and test search speed
128         /// using a multiple of the original step value.<p/>
129         /// 
130         /// <p/>Good values for <code>precisionStep</code> are depending on usage and data type:
131         /// <ul>
132         /// <li>The default for all data types is <b>4</b>, which is used, when no <code>precisionStep</code> is given.</li>
133         /// <li>Ideal value in most cases for <em>64 bit</em> data types <em>(long, double)</em> is <b>6</b> or <b>8</b>.</li>
134         /// <li>Ideal value in most cases for <em>32 bit</em> data types <em>(int, float)</em> is <b>4</b>.</li>
135         /// <li>Steps <b>&gt;64</b> for <em>long/double</em> and <b>&gt;32</b> for <em>int/float</em> produces one token
136         /// per value in the index and querying is as slow as a conventional {@link TermRangeQuery}. But it can be used
137         /// to produce fields, that are solely used for sorting (in this case simply use {@link Integer#MAX_VALUE} as
138         /// <code>precisionStep</code>). Using {@link NumericField NumericFields} for sorting
139         /// is ideal, because building the field cache is much faster than with text-only numbers.
140         /// Sorting is also possible with range query optimized fields using one of the above <code>precisionSteps</code>.</li>
141         /// </ul>
142         /// 
143         /// <p/>Comparisons of the different types of RangeQueries on an index with about 500,000 docs showed
144         /// that {@link TermRangeQuery} in boolean rewrite mode (with raised {@link BooleanQuery} clause count)
145         /// took about 30-40 secs to complete, {@link TermRangeQuery} in constant score filter rewrite mode took 5 secs
146         /// and executing this class took &lt;100ms to complete (on an Opteron64 machine, Java 1.5, 8 bit
147         /// precision step). This query type was developed for a geographic portal, where the performance for
148         /// e.g. bounding boxes or exact date/time stamps is important.<p/>
149         /// 
150         /// </summary>
151         /// <since> 2.9
152         /// 
153         /// </since>
154         [Serializable]
155         public sealed class NumericRangeQuery:MultiTermQuery
156         {
157                 
158                 private NumericRangeQuery(System.String field, int precisionStep, int valSize, System.ValueType min, System.ValueType max, bool minInclusive, bool maxInclusive)
159                 {
160                         System.Diagnostics.Debug.Assert((valSize == 32 || valSize == 64));
161                         if (precisionStep < 1)
162                                 throw new System.ArgumentException("precisionStep must be >=1");
163                         this.field = StringHelper.Intern(field);
164                         this.precisionStep = precisionStep;
165                         this.valSize = valSize;
166                         this.min = min;
167                         this.max = max;
168                         this.minInclusive = minInclusive;
169                         this.maxInclusive = maxInclusive;
170                         
171                         // For bigger precisionSteps this query likely
172                         // hits too many terms, so set to CONSTANT_SCORE_FILTER right off
173                         // (especially as the FilteredTermEnum is costly if wasted only for AUTO tests because it
174                         // creates new enums from IndexReader for each sub-range)
175                         switch (valSize)
176                         {
177                                 
178                                 case 64: 
179                                         SetRewriteMethod((precisionStep > 6)?CONSTANT_SCORE_FILTER_REWRITE:CONSTANT_SCORE_AUTO_REWRITE_DEFAULT);
180                                         break;
181                                 
182                                 case 32: 
183                                         SetRewriteMethod((precisionStep > 8)?CONSTANT_SCORE_FILTER_REWRITE:CONSTANT_SCORE_AUTO_REWRITE_DEFAULT);
184                                         break;
185                                 
186                                 default: 
187                                         // should never happen
188                                         throw new System.ArgumentException("valSize must be 32 or 64");
189                                 
190                         }
191                         
192                         // shortcut if upper bound == lower bound
193                         if (min != null && min.Equals(max))
194                         {
195                                 SetRewriteMethod(CONSTANT_SCORE_BOOLEAN_QUERY_REWRITE);
196                         }
197                 }
198                 
199                 /// <summary> Factory that creates a <code>NumericRangeQuery</code>, that queries a <code>long</code>
200                 /// range using the given <a href="#precisionStepDesc"><code>precisionStep</code></a>.
201         /// You can have half-open ranges (which are in fact &lt;/&#8804; or &gt;/&#8805; queries)
202                 /// by setting the min or max value to <code>null</code>. By setting inclusive to false, it will
203                 /// match all documents excluding the bounds, with inclusive on, the boundaries are hits, too.
204                 /// </summary>
205                 public static NumericRangeQuery NewLongRange(System.String field, int precisionStep, System.ValueType min, System.ValueType max, bool minInclusive, bool maxInclusive)
206                 {
207                         return new NumericRangeQuery(field, precisionStep, 64, min, max, minInclusive, maxInclusive);
208                 }
209                 
210                 /// <summary> Factory that creates a <code>NumericRangeQuery</code>, that queries a <code>long</code>
211                 /// range using the default <code>precisionStep</code> {@link NumericUtils#PRECISION_STEP_DEFAULT} (4).
212         /// You can have half-open ranges (which are in fact &lt;/&#8804; or &gt;/&#8805; queries)
213                 /// by setting the min or max value to <code>null</code>. By setting inclusive to false, it will
214                 /// match all documents excluding the bounds, with inclusive on, the boundaries are hits, too.
215                 /// </summary>
216                 public static NumericRangeQuery NewLongRange(System.String field, System.ValueType min, System.ValueType max, bool minInclusive, bool maxInclusive)
217                 {
218                         return new NumericRangeQuery(field, NumericUtils.PRECISION_STEP_DEFAULT, 64, min, max, minInclusive, maxInclusive);
219                 }
220                 
221                 /// <summary> Factory that creates a <code>NumericRangeQuery</code>, that queries a <code>int</code>
222                 /// range using the given <a href="#precisionStepDesc"><code>precisionStep</code></a>.
223         /// You can have half-open ranges (which are in fact &lt;/&#8804; or &gt;/&#8805; queries)
224                 /// by setting the min or max value to <code>null</code>. By setting inclusive to false, it will
225                 /// match all documents excluding the bounds, with inclusive on, the boundaries are hits, too.
226                 /// </summary>
227                 public static NumericRangeQuery NewIntRange(System.String field, int precisionStep, System.ValueType min, System.ValueType max, bool minInclusive, bool maxInclusive)
228                 {
229                         return new NumericRangeQuery(field, precisionStep, 32, min, max, minInclusive, maxInclusive);
230                 }
231                 
232                 /// <summary> Factory that creates a <code>NumericRangeQuery</code>, that queries a <code>int</code>
233                 /// range using the default <code>precisionStep</code> {@link NumericUtils#PRECISION_STEP_DEFAULT} (4).
234         /// You can have half-open ranges (which are in fact &lt;/&#8804; or &gt;/&#8805; queries)
235                 /// by setting the min or max value to <code>null</code>. By setting inclusive to false, it will
236                 /// match all documents excluding the bounds, with inclusive on, the boundaries are hits, too.
237                 /// </summary>
238                 public static NumericRangeQuery NewIntRange(System.String field, System.ValueType min, System.ValueType max, bool minInclusive, bool maxInclusive)
239                 {
240                         return new NumericRangeQuery(field, NumericUtils.PRECISION_STEP_DEFAULT, 32, min, max, minInclusive, maxInclusive);
241                 }
242                 
243                 /// <summary> Factory that creates a <code>NumericRangeQuery</code>, that queries a <code>double</code>
244                 /// range using the given <a href="#precisionStepDesc"><code>precisionStep</code></a>.
245         /// You can have half-open ranges (which are in fact &lt;/&#8804; or &gt;/&#8805; queries)
246                 /// by setting the min or max value to <code>null</code>. By setting inclusive to false, it will
247                 /// match all documents excluding the bounds, with inclusive on, the boundaries are hits, too.
248                 /// </summary>
249                 public static NumericRangeQuery NewDoubleRange(System.String field, int precisionStep, System.Double min, System.Double max, bool minInclusive, bool maxInclusive)
250                 {
251                         return new NumericRangeQuery(field, precisionStep, 64, min, max, minInclusive, maxInclusive);
252                 }
253                 
254                 /// <summary> Factory that creates a <code>NumericRangeQuery</code>, that queries a <code>double</code>
255                 /// range using the default <code>precisionStep</code> {@link NumericUtils#PRECISION_STEP_DEFAULT} (4).
256         /// You can have half-open ranges (which are in fact &lt;/&#8804; or &gt;/&#8805; queries)
257                 /// by setting the min or max value to <code>null</code>. By setting inclusive to false, it will
258                 /// match all documents excluding the bounds, with inclusive on, the boundaries are hits, too.
259                 /// </summary>
260                 public static NumericRangeQuery NewDoubleRange(System.String field, System.Double min, System.Double max, bool minInclusive, bool maxInclusive)
261                 {
262                         return new NumericRangeQuery(field, NumericUtils.PRECISION_STEP_DEFAULT, 64, min, max, minInclusive, maxInclusive);
263                 }
264                 
265                 /// <summary> Factory that creates a <code>NumericRangeQuery</code>, that queries a <code>float</code>
266                 /// range using the given <a href="#precisionStepDesc"><code>precisionStep</code></a>.
267         /// You can have half-open ranges (which are in fact &lt;/&#8804; or &gt;/&#8805; queries)
268                 /// by setting the min or max value to <code>null</code>. By setting inclusive to false, it will
269                 /// match all documents excluding the bounds, with inclusive on, the boundaries are hits, too.
270                 /// </summary>
271                 public static NumericRangeQuery NewFloatRange(System.String field, int precisionStep, System.Single min, System.Single max, bool minInclusive, bool maxInclusive)
272                 {
273                         return new NumericRangeQuery(field, precisionStep, 32, min, max, minInclusive, maxInclusive);
274                 }
275                 
276                 /// <summary> Factory that creates a <code>NumericRangeQuery</code>, that queries a <code>float</code>
277                 /// range using the default <code>precisionStep</code> {@link NumericUtils#PRECISION_STEP_DEFAULT} (4).
278         /// You can have half-open ranges (which are in fact &lt;/&#8804; or &gt;/&#8805; queries)
279                 /// by setting the min or max value to <code>null</code>. By setting inclusive to false, it will
280                 /// match all documents excluding the bounds, with inclusive on, the boundaries are hits, too.
281                 /// </summary>
282                 public static NumericRangeQuery NewFloatRange(System.String field, System.Single min, System.Single max, bool minInclusive, bool maxInclusive)
283                 {
284                         return new NumericRangeQuery(field, NumericUtils.PRECISION_STEP_DEFAULT, 32, min, max, minInclusive, maxInclusive);
285                 }
286                 
287                 //@Override
288                 public /*protected internal*/ override FilteredTermEnum GetEnum(IndexReader reader)
289                 {
290                         return new NumericRangeTermEnum(this, reader);
291                 }
292                 
293                 /// <summary>Returns the field name for this query </summary>
294                 public System.String GetField()
295                 {
296                         return field;
297                 }
298                 
299                 /// <summary>Returns <code>true</code> if the lower endpoint is inclusive </summary>
300                 public bool IncludesMin()
301                 {
302                         return minInclusive;
303                 }
304                 
305                 /// <summary>Returns <code>true</code> if the upper endpoint is inclusive </summary>
306                 public bool IncludesMax()
307                 {
308                         return maxInclusive;
309                 }
310                 
311                 /// <summary>Returns the lower value of this range query </summary>
312                 public System.ValueType GetMin()
313                 {
314                         return min;
315                 }
316                 
317                 /// <summary>Returns the upper value of this range query </summary>
318                 public System.ValueType GetMax()
319                 {
320                         return max;
321                 }
322                 
323                 //@Override
324                 public override System.String ToString(System.String field)
325                 {
326                         System.Text.StringBuilder sb = new System.Text.StringBuilder();
327                         if (!this.field.Equals(field))
328                                 sb.Append(this.field).Append(':');
329                         return sb.Append(minInclusive?'[':'{').Append((min == null)?"*":min.ToString()).Append(" TO ").Append((max == null)?"*":max.ToString()).Append(maxInclusive?']':'}').Append(ToStringUtils.Boost(GetBoost())).ToString();
330                 }
331                 
332                 //@Override
333                 public  override bool Equals(System.Object o)
334                 {
335                         if (o == this)
336                                 return true;
337                         if (!base.Equals(o))
338                                 return false;
339                         if (o is NumericRangeQuery)
340                         {
341                                 NumericRangeQuery q = (NumericRangeQuery) o;
342                                 return ((System.Object) field == (System.Object) q.field && (q.min == null?min == null:q.min.Equals(min)) && (q.max == null?max == null:q.max.Equals(max)) && minInclusive == q.minInclusive && maxInclusive == q.maxInclusive && precisionStep == q.precisionStep);
343                         }
344                         return false;
345                 }
346                 
347                 //@Override
348                 public override int GetHashCode()
349                 {
350                         int hash = base.GetHashCode();
351                         hash += (field.GetHashCode() ^ 0x4565fd66 + precisionStep ^ 0x64365465);
352                         if (min != null)
353                                 hash += (min.GetHashCode() ^ 0x14fa55fb);
354                         if (max != null)
355                                 hash += (max.GetHashCode() ^ 0x733fa5fe);
356                         return hash + (minInclusive.GetHashCode() ^ 0x14fa55fb) + (maxInclusive.GetHashCode() ^ 0x733fa5fe);
357                 }
358
359          // field must be interned after reading from stream
360         //private void ReadObject(java.io.ObjectInputStream in) 
361         //{
362         //    in.defaultReadObject();
363         //    field = StringHelper.intern(field);
364         //}
365
366
367         [System.Runtime.Serialization.OnDeserialized]
368         internal void OnDeserialized(System.Runtime.Serialization.StreamingContext context)
369         {
370             field = StringHelper.Intern(field);
371         }
372                 
373                 // members (package private, to be also fast accessible by NumericRangeTermEnum)
374                 internal System.String field;
375                 internal int precisionStep;
376                 internal int valSize;
377                 internal System.ValueType min;
378                 internal System.ValueType max;
379                 internal bool minInclusive;
380                 internal bool maxInclusive;
381                 
382                 /// <summary> Subclass of FilteredTermEnum for enumerating all terms that match the
383                 /// sub-ranges for trie range queries.
384                 /// <p/>
385                 /// WARNING: This term enumeration is not guaranteed to be always ordered by
386                 /// {@link Term#compareTo}.
387                 /// The ordering depends on how {@link NumericUtils#splitLongRange} and
388                 /// {@link NumericUtils#splitIntRange} generates the sub-ranges. For
389                 /// {@link MultiTermQuery} ordering is not relevant.
390                 /// </summary>
391                 private sealed class NumericRangeTermEnum:FilteredTermEnum
392                 {
393                         private class AnonymousClassLongRangeBuilder:NumericUtils.LongRangeBuilder
394                         {
395                                 public AnonymousClassLongRangeBuilder(NumericRangeTermEnum enclosingInstance)
396                                 {
397                                         InitBlock(enclosingInstance);
398                                 }
399                                 private void  InitBlock(NumericRangeTermEnum enclosingInstance)
400                                 {
401                                         this.enclosingInstance = enclosingInstance;
402                                 }
403                                 private NumericRangeTermEnum enclosingInstance;
404                                 public NumericRangeTermEnum Enclosing_Instance
405                                 {
406                                         get
407                                         {
408                                                 return enclosingInstance;
409                                         }
410                                         
411                                 }
412                                 //@Override
413                                 public override void  AddRange(System.String minPrefixCoded, System.String maxPrefixCoded)
414                                 {
415                                         Enclosing_Instance.rangeBounds.Add(minPrefixCoded);
416                                         Enclosing_Instance.rangeBounds.Add(maxPrefixCoded);
417                                 }
418                         }
419                         private class AnonymousClassIntRangeBuilder:NumericUtils.IntRangeBuilder
420                         {
421                                 public AnonymousClassIntRangeBuilder(NumericRangeTermEnum enclosingInstance)
422                                 {
423                                         InitBlock(enclosingInstance);
424                                 }
425                                 private void  InitBlock(NumericRangeTermEnum enclosingInstance)
426                                 {
427                                         this.enclosingInstance = enclosingInstance;
428                                 }
429                                 private NumericRangeTermEnum enclosingInstance;
430                                 public NumericRangeTermEnum Enclosing_Instance
431                                 {
432                                         get
433                                         {
434                                                 return enclosingInstance;
435                                         }
436                                         
437                                 }
438                                 //@Override
439                                 public override void  AddRange(System.String minPrefixCoded, System.String maxPrefixCoded)
440                                 {
441                                         Enclosing_Instance.rangeBounds.Add(minPrefixCoded);
442                                         Enclosing_Instance.rangeBounds.Add(maxPrefixCoded);
443                                 }
444                         }
445                         private void  InitBlock(NumericRangeQuery enclosingInstance)
446                         {
447                                 this.enclosingInstance = enclosingInstance;
448                         }
449                         private NumericRangeQuery enclosingInstance;
450                         public NumericRangeQuery Enclosing_Instance
451                         {
452                                 get
453                                 {
454                                         return enclosingInstance;
455                                 }
456                                 
457                         }
458                         
459                         private IndexReader reader;
460                         private System.Collections.ArrayList rangeBounds = new System.Collections.ArrayList();
461                         private System.String currentUpperBound = null;
462                         
463                         internal NumericRangeTermEnum(NumericRangeQuery enclosingInstance, IndexReader reader)
464                         {
465                                 InitBlock(enclosingInstance);
466                                 this.reader = reader;
467                                 
468                                 switch (Enclosing_Instance.valSize)
469                                 {
470                                         
471                                         case 64:  {
472                                                         // lower
473                                                         long minBound = System.Int64.MinValue;
474                                                         if (Enclosing_Instance.min is System.Int64)
475                                                         {
476                                                                 minBound = System.Convert.ToInt64(Enclosing_Instance.min);
477                                                         }
478                                                         else if (Enclosing_Instance.min is System.Double)
479                                                         {
480                                                                 minBound = NumericUtils.DoubleToSortableLong(System.Convert.ToDouble(Enclosing_Instance.min));
481                                                         }
482                                                         if (!Enclosing_Instance.minInclusive && Enclosing_Instance.min != null)
483                                                         {
484                                                                 if (minBound == System.Int64.MaxValue)
485                                                                         break;
486                                                                 minBound++;
487                                                         }
488                                                         
489                                                         // upper
490                                                         long maxBound = System.Int64.MaxValue;
491                                                         if (Enclosing_Instance.max is System.Int64)
492                                                         {
493                                                                 maxBound = System.Convert.ToInt64(Enclosing_Instance.max);
494                                                         }
495                                                         else if (Enclosing_Instance.max is System.Double)
496                                                         {
497                                                                 maxBound = NumericUtils.DoubleToSortableLong(System.Convert.ToDouble(Enclosing_Instance.max));
498                                                         }
499                                                         if (!Enclosing_Instance.maxInclusive && Enclosing_Instance.max != null)
500                                                         {
501                                                                 if (maxBound == System.Int64.MinValue)
502                                                                         break;
503                                                                 maxBound--;
504                                                         }
505                                                         
506                                                         NumericUtils.SplitLongRange(new AnonymousClassLongRangeBuilder(this), Enclosing_Instance.precisionStep, minBound, maxBound);
507                                                         break;
508                                                 }
509                                         
510                                         
511                                         case 32:  {
512                                                         // lower
513                                                         int minBound = System.Int32.MinValue;
514                                                         if (Enclosing_Instance.min is System.Int32)
515                                                         {
516                                                                 minBound = System.Convert.ToInt32(Enclosing_Instance.min);
517                                                         }
518                                                         else if (Enclosing_Instance.min is System.Single)
519                                                         {
520                                                                 minBound = NumericUtils.FloatToSortableInt(System.Convert.ToSingle(Enclosing_Instance.min));
521                                                         }
522                                                         if (!Enclosing_Instance.minInclusive && Enclosing_Instance.min != null)
523                                                         {
524                                                                 if (minBound == System.Int32.MaxValue)
525                                                                         break;
526                                                                 minBound++;
527                                                         }
528                                                         
529                                                         // upper
530                                                         int maxBound = System.Int32.MaxValue;
531                                                         if (Enclosing_Instance.max is System.Int32)
532                                                         {
533                                                                 maxBound = System.Convert.ToInt32(Enclosing_Instance.max);
534                                                         }
535                                                         else if (Enclosing_Instance.max is System.Single)
536                                                         {
537                                                                 maxBound = NumericUtils.FloatToSortableInt(System.Convert.ToSingle(Enclosing_Instance.max));
538                                                         }
539                                                         if (!Enclosing_Instance.maxInclusive && Enclosing_Instance.max != null)
540                                                         {
541                                                                 if (maxBound == System.Int32.MinValue)
542                                                                         break;
543                                                                 maxBound--;
544                                                         }
545                                                         
546                                                         NumericUtils.SplitIntRange(new AnonymousClassIntRangeBuilder(this), Enclosing_Instance.precisionStep, minBound, maxBound);
547                                                         break;
548                                                 }
549                                         
550                                         
551                                         default: 
552                                                 // should never happen
553                                                 throw new System.ArgumentException("valSize must be 32 or 64");
554                                         
555                                 }
556                                 
557                                 // seek to first term
558                                 Next();
559                         }
560                         
561                         //@Override
562                         public override float Difference()
563                         {
564                                 return 1.0f;
565                         }
566                         
567                         /// <summary>this is a dummy, it is not used by this class. </summary>
568                         //@Override
569                         public override bool EndEnum()
570                         {
571                                 System.Diagnostics.Debug.Assert(false); // should never be called
572                                 return (currentTerm != null);
573                         }
574                         
575                         /// <summary> Compares if current upper bound is reached,
576                         /// this also updates the term count for statistics.
577                         /// In contrast to {@link FilteredTermEnum}, a return value
578                         /// of <code>false</code> ends iterating the current enum
579                         /// and forwards to the next sub-range.
580                         /// </summary>
581                         //@Override
582                         public /*protected internal*/ override bool TermCompare(Term term)
583                         {
584                                 return ((System.Object) term.Field() == (System.Object) Enclosing_Instance.field && String.CompareOrdinal(term.Text(), currentUpperBound) <= 0);
585                         }
586                         
587                         /// <summary>Increments the enumeration to the next element.  True if one exists. </summary>
588                         //@Override
589                         public override bool Next()
590                         {
591                                 // if a current term exists, the actual enum is initialized:
592                                 // try change to next term, if no such term exists, fall-through
593                                 if (currentTerm != null)
594                                 {
595                                         System.Diagnostics.Debug.Assert(actualEnum != null);
596                                         if (actualEnum.Next())
597                                         {
598                                                 currentTerm = actualEnum.Term();
599                                                 if (TermCompare(currentTerm))
600                                                         return true;
601                                         }
602                                 }
603                                 // if all above fails, we go forward to the next enum,
604                                 // if one is available
605                                 currentTerm = null;
606                                 if (rangeBounds.Count < 2)
607                                         return false;
608                                 // close the current enum and read next bounds
609                                 if (actualEnum != null)
610                                 {
611                                         actualEnum.Close();
612                                         actualEnum = null;
613                                 }
614                                 System.Object tempObject;
615                                 tempObject = rangeBounds[0];
616                                 rangeBounds.RemoveAt(0);
617                                 System.String lowerBound = (System.String) tempObject;
618                                 System.Object tempObject2;
619                                 tempObject2 = rangeBounds[0];
620                                 rangeBounds.RemoveAt(0);
621                                 this.currentUpperBound = ((System.String) tempObject2);
622                                 // this call recursively uses next(), if no valid term in
623                                 // next enum found.
624                                 // if this behavior is changed/modified in the superclass,
625                                 // this enum will not work anymore!
626                                 SetEnum(reader.Terms(new Term(Enclosing_Instance.field, lowerBound)));
627                                 return (currentTerm != null);
628                         }
629                         
630                         /// <summary>Closes the enumeration to further activity, freeing resources.  </summary>
631                         //@Override
632                         public override void  Close()
633                         {
634                                 rangeBounds.Clear();
635                                 currentUpperBound = null;
636                                 base.Close();
637                         }
638                 }
639         }
640 }