Project
Loading...
Searching...
No Matches
Encoder.h
Go to the documentation of this file.
1// Copyright 2019-2023 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
15
16#ifndef RANS_INTERNAL_ENCODE_ENCODER_H_
17#define RANS_INTERNAL_ENCODE_ENCODER_H_
18
19#include <algorithm>
20#include <iomanip>
21#include <memory>
22
23#include <fairlogger/Logger.h>
24#include <stdexcept>
25
26#include <gsl/span>
27
30
31namespace o2::rans
32{
33
34namespace encoderImpl
35{
36
37template <typename stream_IT, typename literals_IT = std::nullptr_t>
38[[nodiscard]] inline constexpr decltype(auto) makeReturn(stream_IT streamEnd, literals_IT literalsEnd = nullptr) noexcept
39{
40 if constexpr (std::is_null_pointer_v<literals_IT>) {
41 return streamEnd;
42 } else {
43 return std::make_pair(streamEnd, literalsEnd);
44 }
45};
46
47} // namespace encoderImpl
48
49template <class encoder_T, class symbolTable_T, std::size_t nStreams_V>
51{
52 public:
53 using symbolTable_type = symbolTable_T;
54 using symbol_type = typename symbolTable_T::value_type;
55 using coder_type = encoder_T;
56 using source_type = typename symbolTable_type::source_type;
57 using stream_type = typename coder_type::stream_type;
58 using size_type = std::size_t;
59 using difference_type = std::ptrdiff_t;
60
61 static constexpr size_type NStreams = nStreams_V;
62
63 Encoder() = default;
64
65 template <typename renormedSymbolTable_T>
66 Encoder(const renormedSymbolTable_T& renormedFrequencyTable) : mSymbolTable{renormedFrequencyTable}
67 {
68 const size_t symbolTablePrecission = mSymbolTable.getPrecision();
69 const size_t encoderLowerBound = coder_type::getStreamingLowerBound();
70 if (symbolTablePrecission > encoderLowerBound) {
71 throw EncodingError(fmt::format(
72 "Renorming precision of symbol table ({} Bits) exceeds renorming lower bound of encoder ({} Bits).\
73 This can cause overflows during encoding.",
74 symbolTablePrecission, encoderLowerBound));
75 }
76 };
77
78 [[nodiscard]] inline const symbolTable_type& getSymbolTable() const noexcept { return mSymbolTable; };
79
80 [[nodiscard]] inline static constexpr size_type getNStreams() noexcept { return NStreams; };
81
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;
84
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
87 {
88 return process(inputStream.data(), inputStream.data() + inputStream.size(), outputStream.data(), literalsBegin);
89 };
90
91 protected:
93
94 static constexpr size_type NCoderStreams = coder_type::getNstreams();
96
97 // compile time preconditions:
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");
101};
102
103template <class encoder_T, class symbolTable_T, std::size_t nStreams_V>
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>>
105decltype(auto) Encoder<encoder_T, symbolTable_T, nStreams_V>::process(source_IT inputBegin, source_IT inputEnd, stream_IT outputBegin, literals_IT literalsBegin) const
106{
107
108 using namespace internal;
109 using namespace utils;
110 using namespace encoderImpl;
111
112 if (inputBegin == inputEnd) {
113 LOG(warning) << "passed empty message to encoder, skip encoding";
114 return makeReturn(outputBegin, literalsBegin);
115 }
116
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");
119 }
120
121 std::array<coder_type, NCoders> coders;
122
123 for (auto& coder : coders) {
124 coder = coder_type{mSymbolTable.getPrecision()};
125 }
126
127 // calculate sizes and numbers of iterations:
128 const auto inputBufferSize = std::distance(inputBegin, inputEnd); // size of the input buffer
129 const size_t nRemainderSymbols = inputBufferSize % NStreams;
130 const size_t nPartialCoderIterations = nRemainderSymbols / NCoderStreams;
131 const size_t nFractionalEncodes = nRemainderSymbols % NCoderStreams;
132
133 // from here on, everything runs backwards!
134 // We are encoding symbols from the end of the message to the beginning of the message.
135 // Since rANS works like a stack, this allows the decoder to work in forward direction.
136 // To guarante consistency betweenn different coder implementations, all interleaved
137 // streams have to run backwards as well, i.e. stream m of coder n+1 runs before stream p of coder n.
138
139 stream_IT outputIter = outputBegin;
140 source_IT inputIter = advanceIter(inputEnd, -1);
141 source_IT inputREnd = advanceIter(inputBegin, -1);
142
143 EncoderSymbolMapper<symbolTable_type, coder_type, literals_IT> symbolMapper{this->mSymbolTable, literalsBegin};
144 typename coder_type::symbol_type encoderSymbols[2]{};
145
146 // one past the end. Will not be dereferenced, thus safe.
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;
152
153 // we are encoding backwards!
154 if (nFractionalEncodes) {
155 // one more encoding step than nPartialCoderIterations for masked encoding
156 // will not cause out of range for coders
157 ++activeCoder;
158 inputIter = symbolMapper.unpackSymbols(inputIter, encoderSymbols[0], nFractionalEncodes);
159 outputIter = activeCoder->putSymbols(outputIter, encoderSymbols[0], nFractionalEncodes);
160 --activeCoder;
161 }
162
163 // align encoders
164 while (activeCoder != codersREnd) {
165 if (inputIter != inputREnd) {
166 inputIter = symbolMapper.unpackSymbols(inputIter, encoderSymbols[0]);
167 outputIter = (activeCoder--)->putSymbols(outputIter, encoderSymbols[0]);
168 }
169 }
170
171 constexpr size_t lastCoderIdx = NCoders - 1;
172 while (inputIter != inputREnd) {
173 // iterate over coders
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]);
179 }
180 }
181
182 for (size_t i = coders.size(); i-- > 0;) {
183 outputIter = coders[i].flush(outputIter);
184 }
185
186 return makeReturn(outputIter, symbolMapper.getIncompressibleIterator());
187}
188
189}; // namespace o2::rans
190
191#endif /* RANS_INTERNAL_ENCODE_ENCODER_H_ */
Looks up statistical properties in symbol table for each source symbol. Specialed for each coder type...
int32_t i
common helper classes and functions
typename coder_type::stream_type stream_type
Definition Encoder.h:57
Encoder(const renormedSymbolTable_T &renormedFrequencyTable)
Definition Encoder.h:66
typename symbolTable_T::value_type symbol_type
Definition Encoder.h:54
const symbolTable_type & getSymbolTable() const noexcept
Definition Encoder.h:78
std::ptrdiff_t difference_type
Definition Encoder.h:59
static constexpr size_type NCoders
Definition Encoder.h:95
decltype(auto) process(gsl::span< const source_type > inputStream, gsl::span< stream_type > outputStream, literals_IT literalsBegin=nullptr) const
Definition Encoder.h:86
static constexpr size_type NStreams
Definition Encoder.h:61
symbolTable_type mSymbolTable
Definition Encoder.h:92
std::size_t size_type
Definition Encoder.h:58
static constexpr size_type getNStreams() noexcept
Definition Encoder.h:80
typename symbolTable_type::source_type source_type
Definition Encoder.h:56
static constexpr size_type NCoderStreams
Definition Encoder.h:94
encoder_T coder_type
Definition Encoder.h:55
symbolTable_T symbolTable_type
Definition Encoder.h:53
constexpr decltype(auto) makeReturn(stream_IT streamEnd, literals_IT literalsEnd=nullptr) noexcept
Definition Encoder.h:38
constexpr bool isPow2(T x) noexcept
Definition utils.h:104
Common utility functions.
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"