View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  
21  /*
22   * Licensed under the Apache License, Version 2.0 (the "License");
23   * you may not use this file except in compliance with the License.
24   * You may obtain a copy of the License at
25   *
26   *     http://www.apache.org/licenses/LICENSE-2.0
27   *
28   * Unless required by applicable law or agreed to in writing, software
29   * distributed under the License is distributed on an "AS IS" BASIS,
30   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31   * See the License for the specific language governing permissions and
32   * limitations under the License.
33   */
34  package org.waarp.compress.zstdsafe;
35  
36  import static org.waarp.compress.zstdsafe.Constants.*;
37  import static org.waarp.compress.zstdsafe.UnsafeUtil.*;
38  
39  class SequenceStore {
40    public final byte[] literalsBuffer;
41    public int literalsLength;
42  
43    public final int[] offsets;
44    public final int[] literalLengths;
45    public final int[] matchLengths;
46    public int sequenceCount;
47  
48    public final byte[] literalLengthCodes;
49    public final byte[] matchLengthCodes;
50    public final byte[] offsetCodes;
51  
52    public LongField longLengthField;
53    public int longLengthPosition;
54  
55    public enum LongField {
56      LITERAL, MATCH
57    }
58  
59    private static final byte[] LITERAL_LENGTH_CODE = {
60        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 17, 17, 18,
61        18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22,
62        22, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24,
63        24, 24, 24, 24, 24, 24, 24
64    };
65  
66    private static final byte[] MATCH_LENGTH_CODE = {
67        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
68        21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 32, 33, 33, 34, 34, 35,
69        35, 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 39,
70        39, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
71        40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
72        41, 41, 41, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
73        42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42
74    };
75  
76    public SequenceStore(final int blockSize, final int maxSequences) {
77      offsets = new int[maxSequences];
78      literalLengths = new int[maxSequences];
79      matchLengths = new int[maxSequences];
80  
81      literalLengthCodes = new byte[maxSequences];
82      matchLengthCodes = new byte[maxSequences];
83      offsetCodes = new byte[maxSequences];
84  
85      literalsBuffer = new byte[blockSize];
86  
87      reset();
88    }
89  
90    public void appendLiterals(final byte[] inputBase, final int inputAddress,
91                               final int inputSize) {
92      copyMemory(inputBase, inputAddress, literalsBuffer, literalsLength,
93                 inputSize);
94      literalsLength += inputSize;
95    }
96  
97    public void storeSequence(final byte[] literalBase, final int literalAddress,
98                              final int literalLength, final int offsetCode,
99                              final int matchLengthBase) {
100     int input = literalAddress;
101     int output = literalsLength;
102     int copied = 0;
103     do {
104       putLong(literalsBuffer, output, getLong(literalBase, input));
105       input += SIZE_OF_LONG;
106       output += SIZE_OF_LONG;
107       copied += SIZE_OF_LONG;
108     } while (copied < literalLength);
109 
110     literalsLength += literalLength;
111 
112     if (literalLength > 65535) {
113       longLengthField = LongField.LITERAL;
114       longLengthPosition = sequenceCount;
115     }
116     literalLengths[sequenceCount] = literalLength;
117 
118     offsets[sequenceCount] = offsetCode + 1;
119 
120     if (matchLengthBase > 65535) {
121       longLengthField = LongField.MATCH;
122       longLengthPosition = sequenceCount;
123     }
124 
125     matchLengths[sequenceCount] = matchLengthBase;
126 
127     sequenceCount++;
128   }
129 
130   public void reset() {
131     literalsLength = 0;
132     sequenceCount = 0;
133     longLengthField = null;
134   }
135 
136   public void generateCodes() {
137     for (int i = 0; i < sequenceCount; ++i) {
138       literalLengthCodes[i] = (byte) literalLengthToCode(literalLengths[i]);
139       offsetCodes[i] = (byte) Util.highestBit(offsets[i]);
140       matchLengthCodes[i] = (byte) matchLengthToCode(matchLengths[i]);
141     }
142 
143     if (longLengthField == LongField.LITERAL) {
144       literalLengthCodes[longLengthPosition] =
145           Constants.MAX_LITERALS_LENGTH_SYMBOL;
146     }
147     if (longLengthField == LongField.MATCH) {
148       matchLengthCodes[longLengthPosition] = Constants.MAX_MATCH_LENGTH_SYMBOL;
149     }
150   }
151 
152   private static int literalLengthToCode(final int literalLength) {
153     if (literalLength >= 64) {
154       return Util.highestBit(literalLength) + 19;
155     } else {
156       return LITERAL_LENGTH_CODE[literalLength];
157     }
158   }
159 
160   /*
161    * matchLengthBase = matchLength - MINMATCH
162    * (that's how it's stored in SequenceStore)
163    */
164   private static int matchLengthToCode(final int matchLengthBase) {
165     if (matchLengthBase >= 128) {
166       return Util.highestBit(matchLengthBase) + 36;
167     } else {
168       return MATCH_LENGTH_CODE[matchLengthBase];
169     }
170   }
171 }