65 template <
typename renormedSymbolTable_T>
68 const size_t symbolTablePrecission =
mSymbolTable.getPrecision();
69 const size_t encoderLowerBound = coder_type::getStreamingLowerBound();
70 if (symbolTablePrecission > encoderLowerBound) {
72 "Renorming precision of symbol table ({} Bits) exceeds renorming lower bound of encoder ({} Bits).\
73 This can cause overflows during encoding.",
74 symbolTablePrecission, encoderLowerBound));
82 template <
typename stream_IT,
typename source_IT,
typename literals_IT = std::
nullptr_t, std::enable_if_t<utils::isCompatibleIter_v<
typename symbolTable_T::source_type, source_IT>,
bool> = true>
83 decltype(
auto)
process(source_IT inputBegin, source_IT inputEnd, stream_IT outputBegin, literals_IT literalsBegin =
nullptr)
const;
85 template <
typename literals_IT = std::
nullptr_t>
86 inline decltype(
auto)
process(gsl::span<const source_type> inputStream, gsl::span<stream_type> outputStream, literals_IT literalsBegin =
nullptr)
const
88 return process(inputStream.data(), inputStream.data() + inputStream.size(), outputStream.data(), literalsBegin);
98 static_assert(
internal::isPow2(nStreams_V),
"the number of streams must be a power of 2");
99 static_assert(coder_type::getNstreams() <=
Encoder::getNStreams(),
"The specified coder type has more streams than your encoder");
100 static_assert(
NCoders % 2 == 0,
"At least 2 encoders must run in parallel");
104template <
typename stream_IT,
typename source_IT,
typename literals_IT, std::enable_if_t<utils::isCompatibleIter_v<
typename symbolTable_T::source_type, source_IT>,
bool>>
108 using namespace internal;
109 using namespace utils;
110 using namespace encoderImpl;
112 if (inputBegin == inputEnd) {
113 LOG(warning) <<
"passed empty message to encoder, skip encoding";
114 return makeReturn(outputBegin, literalsBegin);
117 if (std::is_null_pointer_v<literals_IT> && mSymbolTable.hasEscapeSymbol()) {
118 throw HistogramError(
"The Symbol table used requires you to pass a literals iterator");
121 std::array<coder_type, NCoders> coders;
123 for (
auto& coder : coders) {
124 coder =
coder_type{mSymbolTable.getPrecision()};
128 const auto inputBufferSize = std::distance(inputBegin, inputEnd);
129 const size_t nRemainderSymbols = inputBufferSize % NStreams;
130 const size_t nPartialCoderIterations = nRemainderSymbols / NCoderStreams;
131 const size_t nFractionalEncodes = nRemainderSymbols % NCoderStreams;
139 stream_IT outputIter = outputBegin;
140 source_IT inputIter = advanceIter(inputEnd, -1);
141 source_IT inputREnd = advanceIter(inputBegin, -1);
143 EncoderSymbolMapper<symbolTable_type, coder_type, literals_IT> symbolMapper{this->mSymbolTable, literalsBegin};
144 typename coder_type::symbol_type encoderSymbols[2]{};
147#pragma GCC diagnostic push
148#pragma GCC diagnostic ignored "-Warray-bounds"
149 coder_type* codersREnd = advanceIter(coders.data(), -1);
150#pragma GCC diagnostic pop
151 coder_type* activeCoder = codersREnd + nPartialCoderIterations;
154 if (nFractionalEncodes) {
158 inputIter = symbolMapper.unpackSymbols(inputIter, encoderSymbols[0], nFractionalEncodes);
159 outputIter = activeCoder->putSymbols(outputIter, encoderSymbols[0], nFractionalEncodes);
164 while (activeCoder != codersREnd) {
165 if (inputIter != inputREnd) {
166 inputIter = symbolMapper.unpackSymbols(inputIter, encoderSymbols[0]);
167 outputIter = (activeCoder--)->putSymbols(outputIter, encoderSymbols[0]);
171 constexpr size_t lastCoderIdx = NCoders - 1;
172 while (inputIter != inputREnd) {
174 for (
size_t i = 0;
i < coders.size();
i += 2) {
175 inputIter = symbolMapper.unpackSymbols(inputIter, encoderSymbols[0]);
176 outputIter = coders[lastCoderIdx -
i].putSymbols(outputIter, encoderSymbols[0]);
177 inputIter = symbolMapper.unpackSymbols(inputIter, encoderSymbols[1]);
178 outputIter = coders[lastCoderIdx - (
i + 1)].putSymbols(outputIter, encoderSymbols[1]);
182 for (
size_t i = coders.size();
i-- > 0;) {
183 outputIter = coders[
i].flush(outputIter);
186 return makeReturn(outputIter, symbolMapper.getIncompressibleIterator());