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.zstdunsafe;
35  
36  import static org.waarp.compress.zstdunsafe.Constants.*;
37  import static org.waarp.compress.zstdunsafe.UnsafeUtil.*;
38  import static sun.misc.Unsafe.*;
39  
40  class SequenceStore {
41    public final byte[] literalsBuffer;
42    public int literalsLength;
43  
44    public final int[] offsets;
45    public final int[] literalLengths;
46    public final int[] matchLengths;
47    public int sequenceCount;
48  
49    public final byte[] literalLengthCodes;
50    public final byte[] matchLengthCodes;
51    public final byte[] offsetCodes;
52  
53    public LongField longLengthField;
54    public int longLengthPosition;
55  
56    public enum LongField {
57      LITERAL, MATCH
58    }
59  
60    private static final byte[] LITERAL_LENGTH_CODE = {
61        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16, 17, 17, 18,
62        18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22,
63        22, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24,
64        24, 24, 24, 24, 24, 24, 24
65    };
66  
67    private static final byte[] MATCH_LENGTH_CODE = {
68        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
69        21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 32, 33, 33, 34, 34, 35,
70        35, 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 38, 38, 38, 38, 39,
71        39, 39, 39, 39, 39, 39, 39, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
72        40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41,
73        41, 41, 41, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42,
74        42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42
75    };
76  
77    public SequenceStore(final int blockSize, final int maxSequences) {
78      offsets = new int[maxSequences];
79      literalLengths = new int[maxSequences];
80      matchLengths = new int[maxSequences];
81  
82      literalLengthCodes = new byte[maxSequences];
83      matchLengthCodes = new byte[maxSequences];
84      offsetCodes = new byte[maxSequences];
85  
86      literalsBuffer = new byte[blockSize];
87  
88      reset();
89    }
90  
91    public void appendLiterals(final Object inputBase, final long inputAddress,
92                               final int inputSize) {
93      UNSAFE.copyMemory(inputBase, inputAddress, literalsBuffer,
94                        ARRAY_BYTE_BASE_OFFSET + literalsLength, inputSize);
95      literalsLength += inputSize;
96    }
97  
98    public void storeSequence(final Object literalBase, final long literalAddress,
99                              final int literalLength, final int offsetCode,
100                             final int matchLengthBase) {
101     long input = literalAddress;
102     long output = ARRAY_BYTE_BASE_OFFSET + literalsLength;
103     int copied = 0;
104     do {
105       UNSAFE.putLong(literalsBuffer, output,
106                      UNSAFE.getLong(literalBase, input));
107       input += SIZE_OF_LONG;
108       output += SIZE_OF_LONG;
109       copied += SIZE_OF_LONG;
110     } while (copied < literalLength);
111 
112     literalsLength += literalLength;
113 
114     if (literalLength > 65535) {
115       longLengthField = LongField.LITERAL;
116       longLengthPosition = sequenceCount;
117     }
118     literalLengths[sequenceCount] = literalLength;
119 
120     offsets[sequenceCount] = offsetCode + 1;
121 
122     if (matchLengthBase > 65535) {
123       longLengthField = LongField.MATCH;
124       longLengthPosition = sequenceCount;
125     }
126 
127     matchLengths[sequenceCount] = matchLengthBase;
128 
129     sequenceCount++;
130   }
131 
132   public void reset() {
133     literalsLength = 0;
134     sequenceCount = 0;
135     longLengthField = null;
136   }
137 
138   public void generateCodes() {
139     for (int i = 0; i < sequenceCount; ++i) {
140       literalLengthCodes[i] = (byte) literalLengthToCode(literalLengths[i]);
141       offsetCodes[i] = (byte) Util.highestBit(offsets[i]);
142       matchLengthCodes[i] = (byte) matchLengthToCode(matchLengths[i]);
143     }
144 
145     if (longLengthField == LongField.LITERAL) {
146       literalLengthCodes[longLengthPosition] =
147           Constants.MAX_LITERALS_LENGTH_SYMBOL;
148     }
149     if (longLengthField == LongField.MATCH) {
150       matchLengthCodes[longLengthPosition] = Constants.MAX_MATCH_LENGTH_SYMBOL;
151     }
152   }
153 
154   private static int literalLengthToCode(final int literalLength) {
155     if (literalLength >= 64) {
156       return Util.highestBit(literalLength) + 19;
157     } else {
158       return LITERAL_LENGTH_CODE[literalLength];
159     }
160   }
161 
162   /*
163    * matchLengthBase = matchLength - MINMATCH
164    * (that's how it's stored in SequenceStore)
165    */
166   private static int matchLengthToCode(final int matchLengthBase) {
167     if (matchLengthBase >= 128) {
168       return Util.highestBit(matchLengthBase) + 36;
169     } else {
170       return MATCH_LENGTH_CODE[matchLengthBase];
171     }
172   }
173 }