RawSpeed
fast raw decoding library
Loading...
Searching...
No Matches
BitStream.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 "adt/Bit.h"
26#include "adt/Casts.h"
27#include "adt/Invariant.h"
29#include <cstdint>
30
31namespace rawspeed {
32
33template <BitOrder bo> struct BitStreamTraits;
34
35// simple 64-bit wide cache implementation that acts like a FiFo.
36// There are two variants:
37// * L->R: new bits are pushed in on the left and pulled out on the right
38// * L<-R: new bits are pushed in on the right and pulled out on the left
39// Each BitStream specialization uses one of the two.
40
42 uint64_t cache = 0; // the actual bits stored in the cache
43 int fillLevel = 0; // bits left in cache
44
45 static constexpr int Size = bitwidth<decltype(cache)>();
46
47 // how many bits could be requested to be filled
48 static constexpr int MaxGetBits = bitwidth<uint32_t>();
49
50 void establishClassInvariants() const noexcept;
51};
52
53__attribute__((always_inline)) inline void
55 invariant(fillLevel >= 0);
57}
58
59struct BitStreamCacheLeftInRightOut final : BitStreamCacheBase {
60 void push(uint64_t bits, int count) noexcept {
61 establishClassInvariants();
62 invariant(count >= 0);
63 // NOTE: count may be zero!
64 invariant(count <= Size);
65 invariant(count + fillLevel <= Size);
66 cache |= bits << fillLevel;
67 fillLevel += count;
68 }
69
70 [[nodiscard]] uint32_t peek(int count) const noexcept {
71 establishClassInvariants();
72 invariant(count >= 0);
73 invariant(count <= MaxGetBits);
74 invariant(count != 0);
75 invariant(count <= Size);
76 invariant(count <= fillLevel);
77 return extractLowBits(static_cast<uint32_t>(cache), count);
78 }
79
80 void skip(int count) noexcept {
81 establishClassInvariants();
82 invariant(count >= 0);
83 // `count` *could* be larger than `MaxGetBits`.
84 // `count` could be zero.
85 invariant(count <= Size);
86 invariant(count <= fillLevel);
87 cache >>= count;
88 fillLevel -= count;
89 }
90};
91
93 void push(uint64_t bits, int count) noexcept {
95 invariant(count >= 0);
96 // NOTE: count may be zero!
97 invariant(count <= Size);
98 invariant(count + fillLevel <= Size);
99 // If the maximal size of the cache is BitStreamCacheBase::Size, and we
100 // have fillLevel [high] bits set, how many empty [low] bits do we have?
101 const int vacantBits = BitStreamCacheBase::Size - fillLevel;
102 invariant(vacantBits >= 0);
103 invariant(vacantBits <= Size);
104 invariant(vacantBits != 0);
105 invariant(vacantBits >= count);
106 // If we just directly 'or' these low bits into the cache right now,
107 // how many unfilled bits of a gap will there be in the middle of a cache?
108 const int emptyBitsGap = vacantBits - count;
109 invariant(emptyBitsGap >= 0);
110 invariant(emptyBitsGap <= Size);
111 if (count != 0) {
112 invariant(emptyBitsGap < Size);
113 // So just shift the new bits so that there is no gap in the middle.
114 cache |= bits << emptyBitsGap;
115 }
116 fillLevel += count;
117 }
118
119 [[nodiscard]] auto peek(int count) const noexcept {
121 invariant(count >= 0);
122 invariant(count <= Size);
123 invariant(count <= MaxGetBits);
124 invariant(count != 0);
125 invariant(count <= fillLevel);
127 extractHighBits(cache, count,
128 /*effectiveBitwidth=*/BitStreamCacheBase::Size));
129 }
130
131 void skip(int count) noexcept {
133 invariant(count >= 0);
134 // `count` *could* be larger than `MaxGetBits`.
135 // `count` could be zero.
136 invariant(count <= Size);
137 invariant(count <= fillLevel);
138 fillLevel -= count;
139 cache <<= count;
140 }
141};
142
143} // namespace rawspeed
#define invariant(expr)
Definition Invariant.h:27
__attribute__((noinline)) __attribute__((visibility("default"))) JPEGStuffedByteStreamGenerator
constexpr unsigned RAWSPEED_READNONE bitwidth(T unused={})
Definition Bit.h:43
constexpr RAWSPEED_READNONE T extractHighBits(T value, unsigned nBits, unsigned effectiveBitwidth=bitwidth< T >())
Definition Bit.h:120
constexpr RAWSPEED_READNONE Ttgt implicit_cast(Tsrc value)
Definition Casts.h:32
void establishClassInvariants() const noexcept
static constexpr int MaxGetBits
Definition BitStream.h:48
static constexpr int Size
Definition BitStream.h:45
void push(uint64_t bits, int count) noexcept
Definition BitStream.h:93
void skip(int count) noexcept
Definition BitStream.h:131
auto peek(int count) const noexcept
Definition BitStream.h:119