private HashNgramMap(final ValueContainer<T> values, final ConfigOptions opts, final LongArray[] numNgramsForEachWord, final boolean reversed) {
super(values, opts);
this.reversed = reversed;
this.maxLoadFactor = opts.hashTableLoadFactor;
this.storeSuffixOffsets = values.storeSuffixoffsets();
final int maxNgramOrder = numNgramsForEachWord.length;
explicitMaps = null;
isExplicit = false;
implicitMaps = new ImplicitWordHashMap[maxNgramOrder - 1];
final long numWords = numNgramsForEachWord[0].size();
implicitUnigramMap = new UnigramHashMap(numWords, this);
initCapacities = null;
final long maxSize = getMaximumSize(numNgramsForEachWord);
final boolean fitsInInt = maxSize < Integer.MAX_VALUE;
final int logicalNumRangeEntries = (maxNgramOrder - 1) * (int) numWords;
final long[] wordRanges = new long[fitsInInt ? (logicalNumRangeEntries / 2 + logicalNumRangeEntries % 2) : logicalNumRangeEntries];
values.setMap(this);
values.setSizeAtLeast(numWords, 0);
for (int ngramOrder = 1; ngramOrder < maxNgramOrder; ++ngramOrder) {
final long numNgramsForPreviousOrder = ngramOrder == 1 ? numWords : implicitMaps[ngramOrder - 2].getCapacity();
implicitMaps[ngramOrder - 1] = new ImplicitWordHashMap(numNgramsForEachWord[ngramOrder], wordRanges, ngramOrder, maxNgramOrder - 1,
numNgramsForPreviousOrder, (int) numWords, this, fitsInInt, !opts.storeRankedProbBackoffs);
values.setSizeAtLeast(implicitMaps[ngramOrder - 1].getCapacity(), ngramOrder);
}
}