1 // Copyright 2011 Google Inc. All Rights Reserved.
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
15 package com.hughes.android.dictionary.engine;
17 import com.hughes.util.IndexedObject;
18 import com.hughes.util.raf.RAFListSerializer;
19 import com.ibm.icu.text.Transliterator;
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;
29 public abstract class RowBase extends IndexedObject {
31 * the Index owning this RowBase.
33 public final Index index;
36 * Where this RowBase points to.
38 public final int referenceIndex;
41 * the TokenRow above this RowBase, populated on demand.
43 private TokenRow tokenRow = null;
45 RowBase(final DataInput raf, final int thisRowIndex, final Index index, final int extra)
49 this.referenceIndex = extra == -1 ? raf.readInt() : ((extra << 16) + raf.readUnsignedShort()); // what this points to.
52 public RowBase(final int referenceIndex, final int thisRowIndex, final Index index) {
55 this.referenceIndex = referenceIndex;
58 static final class RowKey {
59 final Class<? extends RowBase> rowClass;
60 final int referenceIndex;
62 private RowKey(Class<? extends RowBase> rowClass, int referenceIndex) {
63 this.rowClass = rowClass;
64 this.referenceIndex = referenceIndex;
68 public boolean equals(Object o) {
69 if (!(o instanceof RowKey)) {
72 final RowKey that = (RowKey) o;
73 return this.referenceIndex == that.referenceIndex
74 && this.rowClass.equals(that.rowClass);
78 public int hashCode() {
79 return rowClass.hashCode() + referenceIndex;
83 public RowKey getRowKey() {
84 return new RowKey(this.getClass(), referenceIndex);
88 * @return the TokenRow that this row is "filed under".
90 public TokenRow getTokenRow(final boolean search) {
91 if (tokenRow == null && search) {
93 int rUp = index() + 1;
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);
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);
113 for (--rUp; rUp >= index(); --rUp) {
114 index.rows.get(rUp).setTokenRow(candidateUp);
122 assert tokenRow != null;
127 public void setTokenRow(TokenRow tokenRow) {
128 assert this.tokenRow == null;
129 assert tokenRow != null;
130 this.tokenRow = tokenRow;
133 public abstract void print(PrintStream out);
135 public abstract String getRawText(final boolean compact);
137 public abstract RowMatchType matches(final List<String> searchTokens,
138 final Pattern orderedMatch, final Transliterator normalizer, boolean swapPairEntries);
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> {
146 Serializer(final Index index) {
151 public RowBase read(DataInput raf, final int listIndex) throws IOException {
152 int rowType = raf.readUnsignedByte();
154 if (rowType >= 0x20) {
155 extra = rowType & 0x1f;
156 rowType = (rowType >> 5) - 1;
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);
167 throw new RuntimeException("Invalid rowType:" + rowType);
171 public void write(DataOutput raf, RowBase t) throws IOException {
173 if (t instanceof PairEntry.Row) {
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) {
180 } else if (t instanceof HtmlEntry.Row) {
183 assert t.referenceIndex < (1 << 21);
184 raf.writeByte(((type + 1) << 5) + (t.referenceIndex >> 16));
185 raf.writeShort(t.referenceIndex);
189 public static final class LengthComparator implements Comparator<RowBase> {
191 final boolean swapPairEntries;
193 public LengthComparator(boolean swapPairEntries) {
194 this.swapPairEntries = swapPairEntries;
198 public int compare(RowBase row1, RowBase row2) {
199 final int l1 = row1.getSideLength(swapPairEntries);
200 final int l2 = row2.getSideLength(swapPairEntries);
201 return l1 < l2 ? -1 : l1 == l2 ? 0 : 1;
205 public int getSideLength(boolean swapPairEntries) {
206 return getRawText(false).length();