]> gitweb.fperrin.net Git - Dictionary.git/blob - src/com/hughes/android/dictionary/engine/RowBase.java
0f1c31770323aac2b14ac5f44b23313ce1403a38
[Dictionary.git] / src / com / hughes / android / dictionary / engine / RowBase.java
1 // Copyright 2011 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package com.hughes.android.dictionary.engine;
16
17 import com.hughes.util.IndexedObject;
18 import com.hughes.util.raf.RAFListSerializer;
19 import com.ibm.icu.text.Transliterator;
20
21 import java.io.DataInput;
22 import java.io.DataOutput;
23 import java.io.IOException;
24 import java.io.PrintStream;
25 import java.util.Comparator;
26 import java.util.List;
27 import java.util.regex.Pattern;
28
29 public abstract class RowBase extends IndexedObject {
30     /**
31      * the Index owning this RowBase.
32      */
33     public final Index index;
34
35     /**
36      * Where this RowBase points to.
37      */
38     public final int referenceIndex;
39
40     /**
41      * the TokenRow above this RowBase, populated on demand.
42      */
43     private TokenRow tokenRow = null;
44
45     RowBase(final DataInput raf, final int thisRowIndex, final Index index, final int extra)
46     throws IOException {
47         super(thisRowIndex);
48         this.index = index;
49         this.referenceIndex = extra == -1 ? raf.readInt() : ((extra << 16) + raf.readUnsignedShort()); // what this points to.
50     }
51
52     public RowBase(final int referenceIndex, final int thisRowIndex, final Index index) {
53         super(thisRowIndex);
54         this.index = index;
55         this.referenceIndex = referenceIndex;
56     }
57
58     static final class RowKey {
59         final Class<? extends RowBase> rowClass;
60         final int referenceIndex;
61
62         private RowKey(Class<? extends RowBase> rowClass, int referenceIndex) {
63             this.rowClass = rowClass;
64             this.referenceIndex = referenceIndex;
65         }
66
67         @Override
68         public boolean equals(Object o) {
69             if (!(o instanceof RowKey)) {
70                 return false;
71             }
72             final RowKey that = (RowKey) o;
73             return this.referenceIndex == that.referenceIndex
74                    && this.rowClass.equals(that.rowClass);
75         }
76
77         @Override
78         public int hashCode() {
79             return rowClass.hashCode() + referenceIndex;
80         }
81     }
82
83     public RowKey getRowKey() {
84         return new RowKey(this.getClass(), referenceIndex);
85     }
86
87     /**
88      * @return the TokenRow that this row is "filed under".
89      */
90     public TokenRow getTokenRow(final boolean search) {
91         if (tokenRow == null && search) {
92             int r = index() - 1;
93             int rUp = index() + 1;
94             while (r >= 0) {
95                 final RowBase row = index.rows.get(r);
96                 final TokenRow candidate = row.getTokenRow(false);
97                 if (candidate != null) {
98                     for (++r; r <= index(); ++r) {
99                         index.rows.get(r).setTokenRow(candidate);
100                     }
101                     break;
102                 }
103                 if (rUp < index.rows.size()) {
104                     final RowBase rowUp = index.rows.get(rUp);
105                     TokenRow candidateUp = rowUp.getTokenRow(false);
106                     if (candidateUp != null) {
107                         // Did we hit the next set of TokenRows?
108                         if (candidateUp.index() > this.index()) {
109                             final int tokenIndex = index.sortedIndexEntries
110                                                    .get(candidateUp.referenceIndex - 1).startRow;
111                             candidateUp = (TokenRow) index.rows.get(tokenIndex);
112                         }
113                         for (--rUp; rUp >= index(); --rUp) {
114                             index.rows.get(rUp).setTokenRow(candidateUp);
115                         }
116                         break;
117                     }
118                     rUp++;
119                 }
120                 --r;
121             }
122             assert tokenRow != null;
123         }
124         return tokenRow;
125     }
126
127     public void setTokenRow(TokenRow tokenRow) {
128         assert this.tokenRow == null;
129         assert tokenRow != null;
130         this.tokenRow = tokenRow;
131     }
132
133     public abstract void print(PrintStream out);
134
135     public abstract String getRawText(final boolean compact);
136
137     public abstract RowMatchType matches(final List<String> searchTokens,
138                                          final Pattern orderedMatch, final Transliterator normalizer, boolean swapPairEntries);
139
140     // RowBase must manage "disk-based" polymorphism. All other polymorphism is
141     // dealt with in the normal manner.
142     static class Serializer implements RAFListSerializer<RowBase> {
143
144         final Index index;
145
146         Serializer(final Index index) {
147             this.index = index;
148         }
149
150         @Override
151         public RowBase read(DataInput raf, final int listIndex) throws IOException {
152             int rowType = raf.readUnsignedByte();
153             int extra = -1;
154             if (rowType >= 0x20) {
155                 extra = rowType & 0x1f;
156                 rowType = (rowType >> 5) - 1;
157             }
158             if (rowType == 0) {
159                 return new PairEntry.Row(raf, listIndex, index, extra);
160             } else if (rowType == 1 || rowType == 3) {
161                 return new TokenRow(raf, listIndex, index, /* hasMainEntry */rowType == 1, extra);
162             } else if (rowType == 2) {
163                 return new TextEntry.Row(raf, listIndex, index, extra);
164             } else if (rowType == 4) {
165                 return new HtmlEntry.Row(raf, listIndex, index, extra);
166             }
167             throw new RuntimeException("Invalid rowType:" + rowType);
168         }
169
170         @Override
171         public void write(DataOutput raf, RowBase t) throws IOException {
172             int type = 0;
173             if (t instanceof PairEntry.Row) {
174                 type = 0;
175             } else if (t instanceof TokenRow) {
176                 final TokenRow tokenRow = (TokenRow) t;
177                 type = tokenRow.hasMainEntry ? 1 : 3;
178             } else if (t instanceof TextEntry.Row) {
179                 type = 2;
180             } else if (t instanceof HtmlEntry.Row) {
181                 type = 4;
182             }
183             assert t.referenceIndex < (1 << 21);
184             if ((t.referenceIndex >> 16) >= (1 << 5))
185                 throw new RuntimeException("referenceIndex larger than supported max");
186             raf.writeByte(((type + 1) << 5) + (t.referenceIndex >> 16));
187             raf.writeShort(t.referenceIndex);
188         }
189     }
190
191     public static final class LengthComparator implements Comparator<RowBase> {
192
193         final boolean swapPairEntries;
194
195         public LengthComparator(boolean swapPairEntries) {
196             this.swapPairEntries = swapPairEntries;
197         }
198
199         @Override
200         public int compare(RowBase row1, RowBase row2) {
201             final int l1 = row1.getSideLength(swapPairEntries);
202             final int l2 = row2.getSideLength(swapPairEntries);
203             return l1 < l2 ? -1 : l1 == l2 ? 0 : 1;
204         }
205     }
206
207     public int getSideLength(boolean swapPairEntries) {
208         return getRawText(false).length();
209     }
210
211 }