RawSpeed
fast raw decoding library
Loading...
Searching...
No Matches
BitStreamer.h
Go to the documentation of this file.
1/*
2 RawSpeed - RAW file decoder.
3
4 Copyright (C) 2009-2014 Klaus Post
5 Copyright (C) 2017 Axel Waggershauser
6 Copyright (C) 2017-2021 Roman Lebedev
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21*/
22
23#pragma once
24
25#include "rawspeedconfig.h"
26#include "adt/Array1DRef.h"
27#include "adt/Casts.h"
28#include "adt/Invariant.h"
32#include "io/Endianness.h"
33#include "io/IOException.h"
34#include <array>
35#include <climits>
36#include <cstddef>
37#include <cstdint>
38
39namespace rawspeed {
40
41template <typename BIT_STREAM> struct BitStreamerTraits;
42
43template <typename Tag> struct BitStreamerReplenisherBase {
45
48
50 int pos = 0;
51
52 void establishClassInvariants() const noexcept;
53
55
56 explicit BitStreamerReplenisherBase(Array1DRef<const std::byte> input_)
57 : input(input_) {
59 ThrowIOE("Bit stream size is smaller than MaxProcessBytes");
60 }
61};
62
63template <typename Tag>
64__attribute__((always_inline)) inline void
66 input.establishClassInvariants();
67 invariant(input.size() >= BitStreamerTraits<Tag>::MaxProcessBytes);
68 invariant(pos >= 0);
69 invariant(pos % StreamTraits::MinLoadStepByteMultiple == 0);
70 // `pos` *could* be out-of-bounds of `input`.
71}
72
73template <typename Tag>
74struct BitStreamerForwardSequentialReplenisher
75 : public BitStreamerReplenisherBase<Tag> {
76 using Base = BitStreamerReplenisherBase<Tag>;
77 using Traits = BitStreamerTraits<Tag>;
78 using StreamTraits = BitStreamTraits<Traits::Tag>;
79
80 using Base::BitStreamerReplenisherBase;
81
82 BitStreamerForwardSequentialReplenisher() = delete;
83
84 [[nodiscard]] typename Base::size_type getPos() const {
85 Base::establishClassInvariants();
86 return Base::pos;
87 }
88 [[nodiscard]] typename Base::size_type getRemainingSize() const {
89 Base::establishClassInvariants();
90 return Base::input.size() - getPos();
91 }
92 void markNumBytesAsConsumed(typename Base::size_type numBytes) {
93 Base::establishClassInvariants();
94 invariant(numBytes >= 0);
95 invariant(numBytes != 0);
96 invariant(numBytes % StreamTraits::MinLoadStepByteMultiple == 0);
97 Base::pos += numBytes;
98 }
99
100 std::array<std::byte, BitStreamerTraits<Tag>::MaxProcessBytes> getInput() {
101 Base::establishClassInvariants();
102
103 std::array<std::byte, BitStreamerTraits<Tag>::MaxProcessBytes> tmpStorage;
104 auto tmp = Array1DRef<std::byte>(tmpStorage.data(),
105 implicit_cast<int>(tmpStorage.size()));
106
107 // Do we have BitStreamerTraits<Tag>::MaxProcessBytes or more bytes left in
108 // the input buffer? If so, then we can just read from said buffer.
109 if (getPos() + BitStreamerTraits<Tag>::MaxProcessBytes <=
110 Base::input.size()) [[likely]] {
111 auto currInput =
112 Base::input.getCrop(getPos(), BitStreamerTraits<Tag>::MaxProcessBytes)
113 .getAsArray1DRef();
114 invariant(currInput.size() == tmp.size());
115 memcpy(tmp.begin(), currInput.begin(),
116 BitStreamerTraits<Tag>::MaxProcessBytes);
117 return tmpStorage;
118 }
119
120 // We have to use intermediate buffer, either because the input is running
121 // out of bytes, or because we want to enforce bounds checking.
122
123 // Note that in order to keep all fill-level invariants we must allow to
124 // over-read past-the-end a bit.
125 if (getPos() > Base::input.size() +
126 2 * BitStreamerTraits<Tag>::MaxProcessBytes) [[unlikely]]
127 ThrowIOE("Buffer overflow read in BitStreamer");
128
129 variableLengthLoadNaiveViaMemcpy(tmp, Base::input, getPos());
130
131 return tmpStorage;
132 }
133};
134
135template <typename Derived,
136 typename Replenisher =
137 BitStreamerForwardSequentialReplenisher<Derived>>
139public:
143
144 using Cache = typename StreamTraits::StreamFlow;
145
146protected:
148
149private:
150 Replenisher replenisher;
151
152 // this method can be re-implemented in the concrete BitStreamer template
153 // specializations. It will return the number of bytes processed. It needs
154 // to process up to BitStreamerTraits<Tag>::MaxProcessBytes bytes of input.
157 inputStorage) {
158 static_assert(BitStreamCacheBase::MaxGetBits >= 32, "check implementation");
160 auto input = Array1DRef<std::byte>(inputStorage.data(),
161 implicit_cast<int>(inputStorage.size()));
162 invariant(input.size() == Traits::MaxProcessBytes);
163
164 constexpr int StreamChunkBitwidth =
166 static_assert(CHAR_BIT * Traits::MaxProcessBytes >= StreamChunkBitwidth);
167 static_assert(CHAR_BIT * Traits::MaxProcessBytes % StreamChunkBitwidth ==
168 0);
169 constexpr int NumChunksNeeded =
170 (CHAR_BIT * Traits::MaxProcessBytes) / StreamChunkBitwidth;
171 static_assert(NumChunksNeeded >= 1);
172
173 for (int i = 0; i != NumChunksNeeded; ++i) {
174 auto chunkInput =
175 input.getBlock(sizeof(typename StreamTraits::ChunkType), i);
177 chunkInput.begin(),
178 StreamTraits::ChunkEndianness != getHostEndianness());
179 cache.push(chunk, StreamChunkBitwidth);
180 }
181 return Traits::MaxProcessBytes;
182 }
183
184public:
185 void establishClassInvariants() const noexcept {
186 cache.establishClassInvariants();
187 replenisher.establishClassInvariants();
188 }
189
190 BitStreamer() = delete;
191
195
196 void reload() {
198
200 state.pos = getInputPosition();
201 state.fillLevel = getFillLevel();
202 const auto bsPos = getAsByteStreamPosition(state);
203
204 auto replacement = BitStreamer(replenisher.input);
205 if (bsPos.bytePos != 0)
206 replacement.replenisher.markNumBytesAsConsumed(bsPos.bytePos);
207 replacement.fill(Cache::MaxGetBits);
208 replacement.skipBitsNoFill(bsPos.numBitsToSkip);
209 invariant(
210 replacement.getFillLevel() >
211 (Cache::MaxGetBits -
213 *this = std::move(replacement);
214 }
215
216 void fill(int nbits = Cache::MaxGetBits) {
218 invariant(nbits >= 0);
219 invariant(nbits != 0);
220 invariant(nbits <= Cache::MaxGetBits);
221
222 if (cache.fillLevel >= nbits)
223 return;
224
225 const auto input = replenisher.getInput();
226 const auto numBytes = static_cast<Derived*>(this)->fillCache(input);
227 replenisher.markNumBytesAsConsumed(numBytes);
228 invariant(cache.fillLevel >= nbits);
229 }
230
231 // these methods might be specialized by implementations that support it
232 [[nodiscard]] size_type RAWSPEED_READONLY getInputPosition() const {
234 return replenisher.getPos();
235 }
236
237 // these methods might be specialized by implementations that support it
238 [[nodiscard]] size_type getStreamPosition() const {
240 return getInputPosition() - (cache.fillLevel >> 3);
241 }
242
243 [[nodiscard]] size_type getRemainingSize() const {
245 return replenisher.getRemainingSize();
246 }
247
248 [[nodiscard]] size_type RAWSPEED_READONLY getFillLevel() const {
250 return cache.fillLevel;
251 }
252
253 uint32_t RAWSPEED_READONLY peekBitsNoFill(int nbits) {
255 invariant(nbits >= 0);
256 invariant(nbits != 0);
257 invariant(nbits <= Cache::MaxGetBits);
258 return cache.peek(nbits);
259 }
260
261 void skipBitsNoFill(int nbits) {
263 invariant(nbits >= 0);
264 // `nbits` could be zero.
265 invariant(nbits <= Cache::MaxGetBits);
266 cache.skip(nbits);
267 }
268
271 invariant(nbits >= 0);
272 invariant(nbits != 0);
273 invariant(nbits <= Cache::MaxGetBits);
274 uint32_t ret = peekBitsNoFill(nbits);
275 skipBitsNoFill(nbits);
276 return ret;
277 }
278
279 uint32_t peekBits(int nbits) {
281 invariant(nbits >= 0);
282 invariant(nbits != 0);
283 invariant(nbits <= Cache::MaxGetBits);
284 fill(nbits);
285 return peekBitsNoFill(nbits);
286 }
287
288 void skipBits(int nbits) {
290 fill(nbits);
291 skipBitsNoFill(nbits);
292 }
293
294 uint32_t getBits(int nbits) {
296 invariant(nbits >= 0);
297 invariant(nbits != 0);
298 invariant(nbits <= Cache::MaxGetBits);
299 fill(nbits);
300 return getBitsNoFill(nbits);
301 }
302
303 // This may be used to skip arbitrarily large number of *bits*,
304 // not limited by the fill level.
305 void skipManyBits(int nbits) {
307 int remainingBitsToSkip = nbits;
308 for (; remainingBitsToSkip >= Cache::MaxGetBits;
309 remainingBitsToSkip -= Cache::MaxGetBits) {
310 fill(Cache::MaxGetBits);
311 skipBitsNoFill(Cache::MaxGetBits);
312 }
313 if (remainingBitsToSkip > 0) {
314 fill(remainingBitsToSkip);
315 skipBitsNoFill(remainingBitsToSkip);
316 }
317 }
318
319 // This may be used to skip arbitrarily large number of *bytes*,
320 // not limited by the fill level.
321 void skipBytes(int nbytes) {
323 int nbits = 8 * nbytes;
324 skipManyBits(nbits);
325 }
326};
327
328} // namespace rawspeed
Declaration of the bitstream data structure.
#define ThrowIOE(...)
Definition IOException.h:37
#define invariant(expr)
Definition Invariant.h:27
size_type fillCache(std::array< std::byte, BitStreamerTraits< Derived >::MaxProcessBytes > inputStorage)
void establishClassInvariants() const noexcept
size_type RAWSPEED_READONLY getInputPosition() const
BitStreamerTraits< Derived > Traits
size_type getRemainingSize() const
typename StreamTraits::StreamFlow Cache
BitStreamTraits< Traits::Tag > StreamTraits
void skipBits(int nbits)
size_type getStreamPosition() const
size_type RAWSPEED_READONLY getFillLevel() const
uint32_t peekBits(int nbits)
uint32_t getBitsNoFill(int nbits)
void skipBitsNoFill(int nbits)
BitStreamer(Array1DRef< const std::byte > input)
void skipManyBits(int nbits)
uint32_t getBits(int nbits)
uint32_t RAWSPEED_READONLY peekBitsNoFill(int nbits)
void fill(int nbits=Cache::MaxGetBits)
void skipBytes(int nbytes)
constexpr RAWSPEED_READNONE Ttgt implicit_cast(Tsrc value)
Definition Casts.h:32
int8_t getByteSwapped(int8_t v)
Definition Endianness.h:75
ByteStreamPosition< bo > getAsByteStreamPosition(BitStreamPosition< bo > state)
Endianness getHostEndianness()
Definition Endianness.h:51
__attribute__((noinline)) __attribute__((visibility("default"))) JPEGStuffedByteStreamGenerator
constexpr unsigned RAWSPEED_READNONE bitwidth(T unused={})
Definition Bit.h:43
void variableLengthLoadNaiveViaMemcpy(Array1DRef< std::byte > out, Array1DRef< const std::byte > in, int inPos)
constexpr RAWSPEED_READNONE Ttgt implicit_cast(Tsrc value)
Definition Casts.h:32
static constexpr int MaxGetBits
Definition BitStream.h:48
BitStreamTraits< Traits::Tag > StreamTraits
Definition BitStreamer.h:47
void establishClassInvariants() const noexcept
BitStreamerTraits< Tag > Traits
Definition BitStreamer.h:46
Array1DRef< const std::byte > input
Definition BitStreamer.h:49