aboutsummaryrefslogtreecommitdiffstats
path: root/java/src/com/android/inputmethod/latin/makedict/SparseTableContentUpdater.java
blob: 4518f21b96df59f82ac0888ef9167401a50f8b0a (about) (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.inputmethod.latin.makedict;

import com.android.inputmethod.latin.makedict.DictDecoder.DictionaryBufferFactory;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 * An auxiliary class for updating data associated with SparseTable.
 */
public class SparseTableContentUpdater extends SparseTableContentReader {
    protected OutputStream mLookupTableOutStream;
    protected OutputStream[] mAddressTableOutStreams;
    protected OutputStream[] mContentOutStreams;

    public SparseTableContentUpdater(final String name, final int blockSize,
            final File baseDir, final String[] contentFilenames, final String[] contentIds,
            final DictionaryBufferFactory factory) {
        super(name, blockSize, baseDir, contentFilenames, contentIds, factory);
        mAddressTableOutStreams = new OutputStream[mContentCount];
        mContentOutStreams = new OutputStream[mContentCount];
    }

    protected void openStreamsAndBuffers() throws IOException {
        openBuffers();
        mLookupTableOutStream = new FileOutputStream(mLookupTableFile, true /* append */);
        for (int i = 0; i < mContentCount; ++i) {
            mAddressTableOutStreams[i] = new FileOutputStream(mAddressTableFiles[i],
                    true /* append */);
            mContentOutStreams[i] = new FileOutputStream(mContentFiles[i], true /* append */);
        }
    }

    /**
     * Set the contentIndex-th elements of contentId-th table.
     *
     * @param contentId the id of the content table.
     * @param contentIndex the index where to set the valie.
     * @param value the value to set.
     */
    protected void setContentValue(final int contentId, final int contentIndex, final int value)
            throws IOException {
        if ((contentIndex / mBlockSize) * SparseTable.SIZE_OF_INT_IN_BYTES
                >= mLookupTableBuffer.limit()) {
            // Need to extend the lookup table
            final int currentSize = mLookupTableBuffer.limit()
                    / SparseTable.SIZE_OF_INT_IN_BYTES;
            final int target = contentIndex / mBlockSize + 1;
            for (int i = currentSize; i < target; ++i) {
                BinaryDictEncoderUtils.writeUIntToStream(mLookupTableOutStream,
                        SparseTable.NOT_EXIST, SparseTable.SIZE_OF_INT_IN_BYTES);
            }
            // We need to reopen the byte buffer of the lookup table because a MappedByteBuffer in
            // Java isn't expanded automatically when the underlying file is expanded.
            reopenLookupTable();
        }

        mLookupTableBuffer.position((contentIndex / mBlockSize) * SparseTable.SIZE_OF_INT_IN_BYTES);
        int posInAddressTable = mLookupTableBuffer.readInt();
        if (posInAddressTable == SparseTable.NOT_EXIST) {
            // Need to extend the address table
            mLookupTableBuffer.position(mLookupTableBuffer.position()
                    - SparseTable.SIZE_OF_INT_IN_BYTES);
            posInAddressTable = mAddressTableBuffers[0].limit() / mBlockSize;
            BinaryDictEncoderUtils.writeUIntToDictBuffer(mLookupTableBuffer,
                    posInAddressTable, SparseTable.SIZE_OF_INT_IN_BYTES);
            for (int i = 0; i < mContentCount; ++i) {
                for (int j = 0; j < mBlockSize; ++j) {
                    BinaryDictEncoderUtils.writeUIntToStream(mAddressTableOutStreams[i],
                            SparseTable.NOT_EXIST, SparseTable.SIZE_OF_INT_IN_BYTES);
                }
            }
            // We need to reopen the byte buffers of the address tables because a MappedByteBuffer
            // in Java isn't expanded automatically when the underlying file is expanded.
            reopenAddressTables();
        }
        posInAddressTable += (contentIndex % mBlockSize) * SparseTable.SIZE_OF_INT_IN_BYTES;

        mAddressTableBuffers[contentId].position(posInAddressTable);
        BinaryDictEncoderUtils.writeUIntToDictBuffer(mAddressTableBuffers[contentId],
                value, SparseTable.SIZE_OF_INT_IN_BYTES);
    }

    private void reopenLookupTable() throws IOException {
        mLookupTableOutStream.flush();
        mLookupTableBuffer = mFactory.getDictionaryBuffer(mLookupTableFile);
    }

    private void reopenAddressTables() throws IOException {
        for (int i = 0; i < mContentCount; ++i) {
            mAddressTableOutStreams[i].flush();
            mAddressTableBuffers[i] = mFactory.getDictionaryBuffer(mAddressTableFiles[i]);
        }
    }

    protected void close() throws IOException {
        mLookupTableOutStream.close();
        for (final OutputStream stream : mAddressTableOutStreams) {
            stream.close();
        }
        for (final OutputStream stream : mContentOutStreams) {
            stream.close();
        }
    }
}