add --shared
[pylucene.git] / lucene-java-3.4.0 / lucene / contrib / analyzers / common / src / java / org / tartarus / snowball / SnowballProgram.java
1 /*
2
3 Copyright (c) 2001, Dr Martin Porter
4 Copyright (c) 2002, Richard Boulton
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9
10     * Redistributions of source code must retain the above copyright notice,
11     * this list of conditions and the following disclaimer.
12     * Redistributions in binary form must reproduce the above copyright
13     * notice, this list of conditions and the following disclaimer in the
14     * documentation and/or other materials provided with the distribution.
15     * Neither the name of the copyright holders nor the names of its contributors
16     * may be used to endorse or promote products derived from this software
17     * without specific prior written permission.
18
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
23 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30  */
31
32
33 package org.tartarus.snowball;
34
35 import java.lang.reflect.InvocationTargetException;
36
37 import org.apache.lucene.util.ArrayUtil;
38 import org.apache.lucene.util.RamUsageEstimator;
39
40 /**
41  * This is the rev 502 of the Snowball SVN trunk,
42  * but modified:
43  * made abstract and introduced abstract method stem to avoid expensive reflection in filter class.
44  * refactored StringBuffers to StringBuilder
45  * uses char[] as buffer instead of StringBuffer/StringBuilder
46  * eq_s,eq_s_b,insert,replace_s take CharSequence like eq_v and eq_v_b
47  * reflection calls (Lovins, etc) use EMPTY_ARGS/EMPTY_PARAMS
48  */
49 public abstract class SnowballProgram {
50     private static final Object[] EMPTY_ARGS = new Object[0];
51
52     protected SnowballProgram()
53     {
54         current = new char[8];
55         setCurrent("");
56     }
57
58     public abstract boolean stem();
59
60     /**
61      * Set the current string.
62      */
63     public void setCurrent(String value)
64     {
65         current = value.toCharArray();
66         cursor = 0;
67         limit = value.length();
68         limit_backward = 0;
69         bra = cursor;
70         ket = limit;
71     }
72
73     /**
74      * Get the current string.
75      */
76     public String getCurrent()
77     {
78       return new String(current, 0, limit);
79     }
80     
81     /**
82      * Set the current string.
83      * @param text character array containing input
84      * @param length valid length of text.
85      */
86     public void setCurrent(char text[], int length) {
87       current = text;
88       cursor = 0;
89       limit = length;
90       limit_backward = 0;
91       bra = cursor;
92       ket = limit;
93     }
94
95     /**
96      * Get the current buffer containing the stem.
97      * <p>
98      * NOTE: this may be a reference to a different character array than the
99      * one originally provided with setCurrent, in the exceptional case that 
100      * stemming produced a longer intermediate or result string. 
101      * </p>
102      * <p>
103      * It is necessary to use {@link #getCurrentBufferLength()} to determine
104      * the valid length of the returned buffer. For example, many words are
105      * stemmed simply by subtracting from the length to remove suffixes.
106      * </p>
107      * @see #getCurrentBufferLength()
108      */
109     public char[] getCurrentBuffer() {
110       return current;
111     }
112     
113     /**
114      * Get the valid length of the character array in 
115      * {@link #getCurrentBuffer()}. 
116      * @return valid length of the array.
117      */
118     public int getCurrentBufferLength() {
119       return limit;
120     }
121
122     // current string
123     private char current[];
124
125     protected int cursor;
126     protected int limit;
127     protected int limit_backward;
128     protected int bra;
129     protected int ket;
130
131     protected void copy_from(SnowballProgram other)
132     {
133         current          = other.current;
134         cursor           = other.cursor;
135         limit            = other.limit;
136         limit_backward   = other.limit_backward;
137         bra              = other.bra;
138         ket              = other.ket;
139     }
140
141     protected boolean in_grouping(char [] s, int min, int max)
142     {
143         if (cursor >= limit) return false;
144         char ch = current[cursor];
145         if (ch > max || ch < min) return false;
146         ch -= min;
147         if ((s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return false;
148         cursor++;
149         return true;
150     }
151
152     protected boolean in_grouping_b(char [] s, int min, int max)
153     {
154         if (cursor <= limit_backward) return false;
155         char ch = current[cursor - 1];
156         if (ch > max || ch < min) return false;
157         ch -= min;
158         if ((s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return false;
159         cursor--;
160         return true;
161     }
162
163     protected boolean out_grouping(char [] s, int min, int max)
164     {
165         if (cursor >= limit) return false;
166         char ch = current[cursor];
167         if (ch > max || ch < min) {
168             cursor++;
169             return true;
170         }
171         ch -= min;
172         if ((s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) {
173             cursor ++;
174             return true;
175         }
176         return false;
177     }
178
179     protected boolean out_grouping_b(char [] s, int min, int max)
180     {
181         if (cursor <= limit_backward) return false;
182         char ch = current[cursor - 1];
183         if (ch > max || ch < min) {
184             cursor--;
185             return true;
186         }
187         ch -= min;
188         if ((s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) {
189             cursor--;
190             return true;
191         }
192         return false;
193     }
194
195     protected boolean in_range(int min, int max)
196     {
197         if (cursor >= limit) return false;
198         char ch = current[cursor];
199         if (ch > max || ch < min) return false;
200         cursor++;
201         return true;
202     }
203
204     protected boolean in_range_b(int min, int max)
205     {
206         if (cursor <= limit_backward) return false;
207         char ch = current[cursor - 1];
208         if (ch > max || ch < min) return false;
209         cursor--;
210         return true;
211     }
212
213     protected boolean out_range(int min, int max)
214     {
215         if (cursor >= limit) return false;
216         char ch = current[cursor];
217         if (!(ch > max || ch < min)) return false;
218         cursor++;
219         return true;
220     }
221
222     protected boolean out_range_b(int min, int max)
223     {
224         if (cursor <= limit_backward) return false;
225         char ch = current[cursor - 1];
226         if(!(ch > max || ch < min)) return false;
227         cursor--;
228         return true;
229     }
230
231     protected boolean eq_s(int s_size, CharSequence s)
232     {
233         if (limit - cursor < s_size) return false;
234         int i;
235         for (i = 0; i != s_size; i++) {
236             if (current[cursor + i] != s.charAt(i)) return false;
237         }
238         cursor += s_size;
239         return true;
240     }
241
242     /** @deprecated for binary back compat. Will be removed in Lucene 4.0 */
243     @Deprecated
244     protected boolean eq_s(int s_size, String s)
245     {
246         return eq_s(s_size, (CharSequence)s);
247     }
248
249     protected boolean eq_s_b(int s_size, CharSequence s)
250     {
251         if (cursor - limit_backward < s_size) return false;
252         int i;
253         for (i = 0; i != s_size; i++) {
254             if (current[cursor - s_size + i] != s.charAt(i)) return false;
255         }
256         cursor -= s_size;
257         return true;
258     }
259
260     /** @deprecated for binary back compat. Will be removed in Lucene 4.0 */
261     @Deprecated
262     protected boolean eq_s_b(int s_size, String s)
263     {
264         return eq_s_b(s_size, (CharSequence)s);
265     }
266
267     protected boolean eq_v(CharSequence s)
268     {
269         return eq_s(s.length(), s);
270     }
271
272     /** @deprecated for binary back compat. Will be removed in Lucene 4.0 */
273     @Deprecated
274     protected boolean eq_v(StringBuilder s)
275     {
276         return eq_s(s.length(), (CharSequence)s);
277     }
278
279     protected boolean eq_v_b(CharSequence s)
280     {   return eq_s_b(s.length(), s);
281     }
282
283     /** @deprecated for binary back compat. Will be removed in Lucene 4.0 */
284     @Deprecated
285     protected boolean eq_v_b(StringBuilder s)
286     {   return eq_s_b(s.length(), (CharSequence)s);
287     }
288
289     protected int find_among(Among v[], int v_size)
290     {
291         int i = 0;
292         int j = v_size;
293
294         int c = cursor;
295         int l = limit;
296
297         int common_i = 0;
298         int common_j = 0;
299
300         boolean first_key_inspected = false;
301
302         while(true) {
303             int k = i + ((j - i) >> 1);
304             int diff = 0;
305             int common = common_i < common_j ? common_i : common_j; // smaller
306             Among w = v[k];
307             int i2;
308             for (i2 = common; i2 < w.s_size; i2++) {
309                 if (c + common == l) {
310                     diff = -1;
311                     break;
312                 }
313                 diff = current[c + common] - w.s[i2];
314                 if (diff != 0) break;
315                 common++;
316             }
317             if (diff < 0) {
318                 j = k;
319                 common_j = common;
320             } else {
321                 i = k;
322                 common_i = common;
323             }
324             if (j - i <= 1) {
325                 if (i > 0) break; // v->s has been inspected
326                 if (j == i) break; // only one item in v
327
328                 // - but now we need to go round once more to get
329                 // v->s inspected. This looks messy, but is actually
330                 // the optimal approach.
331
332                 if (first_key_inspected) break;
333                 first_key_inspected = true;
334             }
335         }
336         while(true) {
337             Among w = v[i];
338             if (common_i >= w.s_size) {
339                 cursor = c + w.s_size;
340                 if (w.method == null) return w.result;
341                 boolean res;
342                 try {
343                     Object resobj = w.method.invoke(w.methodobject, EMPTY_ARGS);
344                     res = resobj.toString().equals("true");
345                 } catch (InvocationTargetException e) {
346                     res = false;
347                     // FIXME - debug message
348                 } catch (IllegalAccessException e) {
349                     res = false;
350                     // FIXME - debug message
351                 }
352                 cursor = c + w.s_size;
353                 if (res) return w.result;
354             }
355             i = w.substring_i;
356             if (i < 0) return 0;
357         }
358     }
359
360     // find_among_b is for backwards processing. Same comments apply
361     protected int find_among_b(Among v[], int v_size)
362     {
363         int i = 0;
364         int j = v_size;
365
366         int c = cursor;
367         int lb = limit_backward;
368
369         int common_i = 0;
370         int common_j = 0;
371
372         boolean first_key_inspected = false;
373
374         while(true) {
375             int k = i + ((j - i) >> 1);
376             int diff = 0;
377             int common = common_i < common_j ? common_i : common_j;
378             Among w = v[k];
379             int i2;
380             for (i2 = w.s_size - 1 - common; i2 >= 0; i2--) {
381                 if (c - common == lb) {
382                     diff = -1;
383                     break;
384                 }
385                 diff = current[c - 1 - common] - w.s[i2];
386                 if (diff != 0) break;
387                 common++;
388             }
389             if (diff < 0) {
390                 j = k;
391                 common_j = common;
392             } else {
393                 i = k;
394                 common_i = common;
395             }
396             if (j - i <= 1) {
397                 if (i > 0) break;
398                 if (j == i) break;
399                 if (first_key_inspected) break;
400                 first_key_inspected = true;
401             }
402         }
403         while(true) {
404             Among w = v[i];
405             if (common_i >= w.s_size) {
406                 cursor = c - w.s_size;
407                 if (w.method == null) return w.result;
408
409                 boolean res;
410                 try {
411                     Object resobj = w.method.invoke(w.methodobject, EMPTY_ARGS);
412                     res = resobj.toString().equals("true");
413                 } catch (InvocationTargetException e) {
414                     res = false;
415                     // FIXME - debug message
416                 } catch (IllegalAccessException e) {
417                     res = false;
418                     // FIXME - debug message
419                 }
420                 cursor = c - w.s_size;
421                 if (res) return w.result;
422             }
423             i = w.substring_i;
424             if (i < 0) return 0;
425         }
426     }
427
428     /* to replace chars between c_bra and c_ket in current by the
429      * chars in s.
430      */
431     protected int replace_s(int c_bra, int c_ket, CharSequence s)
432     {
433         final int adjustment = s.length() - (c_ket - c_bra);
434         final int newLength = limit + adjustment;
435         //resize if necessary
436         if (newLength > current.length) {
437           char newBuffer[] = new char[ArrayUtil.oversize(newLength, RamUsageEstimator.NUM_BYTES_CHAR)];
438           System.arraycopy(current, 0, newBuffer, 0, limit);
439           current = newBuffer;
440         }
441         // if the substring being replaced is longer or shorter than the
442         // replacement, need to shift things around
443         if (adjustment != 0 && c_ket < limit) {
444           System.arraycopy(current, c_ket, current, c_bra + s.length(), 
445               limit - c_ket);
446         }
447         // insert the replacement text
448         // Note, faster is s.getChars(0, s.length(), current, c_bra);
449         // but would have to duplicate this method for both String and StringBuilder
450         for (int i = 0; i < s.length(); i++)
451           current[c_bra + i] = s.charAt(i);
452         
453         limit += adjustment;
454         if (cursor >= c_ket) cursor += adjustment;
455         else if (cursor > c_bra) cursor = c_bra;
456         return adjustment;
457     }
458
459     /** @deprecated for binary back compat. Will be removed in Lucene 4.0 */
460     @Deprecated
461     protected int replace_s(int c_bra, int c_ket, String s) {
462         return replace_s(c_bra, c_ket, (CharSequence)s);
463     }
464
465     protected void slice_check()
466     {
467         if (bra < 0 ||
468             bra > ket ||
469             ket > limit)
470         {
471             System.err.println("faulty slice operation");
472         // FIXME: report error somehow.
473         /*
474             fprintf(stderr, "faulty slice operation:\n");
475             debug(z, -1, 0);
476             exit(1);
477             */
478         }
479     }
480
481     protected void slice_from(CharSequence s)
482     {
483         slice_check();
484         replace_s(bra, ket, s);
485     }
486  
487     /** @deprecated for binary back compat. Will be removed in Lucene 4.0 */
488     @Deprecated
489     protected void slice_from(String s)
490     {
491         slice_from((CharSequence)s);
492     }
493
494     /** @deprecated for binary back compat. Will be removed in Lucene 4.0 */
495     @Deprecated
496     protected void slice_from(StringBuilder s)
497     {
498         slice_from((CharSequence)s);
499     }
500
501     protected void slice_del()
502     {
503         slice_from((CharSequence)"");
504     }
505
506     protected void insert(int c_bra, int c_ket, CharSequence s)
507     {
508         int adjustment = replace_s(c_bra, c_ket, s);
509         if (c_bra <= bra) bra += adjustment;
510         if (c_bra <= ket) ket += adjustment;
511     }
512
513     /** @deprecated for binary back compat. Will be removed in Lucene 4.0 */
514     @Deprecated
515     protected void insert(int c_bra, int c_ket, String s)
516     {
517         insert(c_bra, c_ket, (CharSequence)s);
518     }
519
520     /** @deprecated for binary back compat. Will be removed in Lucene 4.0 */
521     @Deprecated
522     protected void insert(int c_bra, int c_ket, StringBuilder s)
523     {
524         insert(c_bra, c_ket, (CharSequence)s);
525     }
526
527     /* Copy the slice into the supplied StringBuffer */
528     protected StringBuilder slice_to(StringBuilder s)
529     {
530         slice_check();
531         int len = ket - bra;
532         s.setLength(0);
533         s.append(current, bra, len);
534         return s;
535     }
536
537     protected StringBuilder assign_to(StringBuilder s)
538     {
539         s.setLength(0);
540         s.append(current, 0, limit);
541         return s;
542     }
543
544 /*
545 extern void debug(struct SN_env * z, int number, int line_count)
546 {   int i;
547     int limit = SIZE(z->p);
548     //if (number >= 0) printf("%3d (line %4d): '", number, line_count);
549     if (number >= 0) printf("%3d (line %4d): [%d]'", number, line_count,limit);
550     for (i = 0; i <= limit; i++)
551     {   if (z->lb == i) printf("{");
552         if (z->bra == i) printf("[");
553         if (z->c == i) printf("|");
554         if (z->ket == i) printf("]");
555         if (z->l == i) printf("}");
556         if (i < limit)
557         {   int ch = z->p[i];
558             if (ch == 0) ch = '#';
559             printf("%c", ch);
560         }
561     }
562     printf("'\n");
563 }
564 */
565
566 };
567