Skip to content

Commit 89f2f76

Browse files
authored
Merge pull request #473 from LebedevRI/tree
`PrefixCodeLUTDecoder<???, PrefixCodeTreeDecoder<???>>` support
2 parents 7312dd5 + 4a81fb4 commit 89f2f76

7 files changed

Lines changed: 127 additions & 29 deletions

File tree

fuzz/all-fuzzers.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,23 @@ PanasonicV6DecompressorFuzzer
2222
PanasonicV7DecompressorFuzzer
2323
PentaxDecompressorFuzzer
2424
PhaseOneDecompressorFuzzer
25+
PrefixCodeDecoderFuzzer-LUTWithLookupVsLUTWithTree
2526
PrefixCodeDecoderFuzzer-LUTWithLookupVsLUTWithVector
2627
PrefixCodeDecoderFuzzer-LUTWithLookupVsLookup
2728
PrefixCodeDecoderFuzzer-LUTWithLookupVsTree
2829
PrefixCodeDecoderFuzzer-LUTWithLookupVsVector
30+
PrefixCodeDecoderFuzzer-LUTWithTreeVsLUTWithVector
31+
PrefixCodeDecoderFuzzer-LUTWithTreeVsLookup
32+
PrefixCodeDecoderFuzzer-LUTWithTreeVsTree
33+
PrefixCodeDecoderFuzzer-LUTWithTreeVsVector
2934
PrefixCodeDecoderFuzzer-LUTWithVectorVsLookup
3035
PrefixCodeDecoderFuzzer-LUTWithVectorVsTree
3136
PrefixCodeDecoderFuzzer-LUTWithVectorVsVector
3237
PrefixCodeDecoderFuzzer-LookupVsTree
3338
PrefixCodeDecoderFuzzer-LookupVsVector
3439
PrefixCodeDecoderFuzzer-TreeVsVector
3540
PrefixCodeLUTWithLookupDecoderFuzzer
41+
PrefixCodeLUTWithTreeDecoderFuzzer
3642
PrefixCodeLUTWithVectorDecoderFuzzer
3743
PrefixCodeLookupDecoderFuzzer
3844
PrefixCodeTreeDecoderFuzzer

fuzz/librawspeed/codes/PrefixCodeDecoder/CMakeLists.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,8 @@ function(add_ht_dual_fuzzer impl0 impl1)
6767
add_dependencies(PrefixCodeDecoderFuzzers ${fuzzer})
6868
endfunction()
6969

70-
set(IMPL "Tree")
7170
set(FRONTEND "LUT")
72-
set(BACKEND "Lookup" "Vector")
71+
set(BACKEND "Tree" "Vector" "Lookup")
7372

7473
foreach(backend ${BACKEND})
7574
list(APPEND IMPL "${backend}")

src/librawspeed/adt/BitIterator.h

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
RawSpeed - RAW file decoder.
3+
4+
Copyright (C) 2023 Roman Lebedev
5+
6+
This library is free software; you can redistribute it and/or
7+
modify it under the terms of the GNU Lesser General Public
8+
License as published by the Free Software Foundation; either
9+
version 2 of the License, or (at your option) any later version.
10+
11+
This library is distributed in the hope that it will be useful,
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14+
Lesser General Public License for more details.
15+
16+
You should have received a copy of the GNU Lesser General Public
17+
License along with this library; if not, write to the Free Software
18+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19+
*/
20+
21+
#pragma once
22+
23+
#include "adt/Invariant.h" // for invariant
24+
#include "common/Common.h" // for bitwidth
25+
#include <iterator> // for input_iterator_tag
26+
#include <utility> // for enable_if_t, is_unsigned_v
27+
28+
namespace rawspeed {
29+
30+
template <typename T, typename = std::enable_if_t<std::is_unsigned_v<T>>>
31+
struct BitMSBIterator {
32+
T bitsPat;
33+
int bitIdx;
34+
35+
using iterator_category = std::input_iterator_tag;
36+
using difference_type = std::ptrdiff_t;
37+
using value_type = bool;
38+
using pointer = const value_type*; // Unusable, but must be here.
39+
using reference = const value_type&; // Unusable, but must be here.
40+
41+
BitMSBIterator(T bitsPat_, int bitIdx_) : bitsPat(bitsPat_), bitIdx(bitIdx_) {
42+
invariant(bitIdx < static_cast<int>(bitwidth<T>()) && bitIdx >= -1);
43+
}
44+
45+
value_type operator*() const {
46+
invariant(static_cast<unsigned>(bitIdx) < bitwidth<T>() &&
47+
"Iterator overflow");
48+
return (bitsPat >> bitIdx) & 0b1;
49+
}
50+
BitMSBIterator& operator++() {
51+
--bitIdx; // We go from MSB to LSB.
52+
invariant(bitIdx >= -1);
53+
return *this;
54+
}
55+
friend inline bool operator==(const BitMSBIterator& a,
56+
const BitMSBIterator& b) {
57+
invariant(a.bitsPat == b.bitsPat && "Comparing unrelated iterators.");
58+
return a.bitIdx == b.bitIdx;
59+
}
60+
friend bool operator!=(const BitMSBIterator& a, const BitMSBIterator& b) {
61+
return !(a == b);
62+
}
63+
};
64+
65+
} // namespace rawspeed

src/librawspeed/adt/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ FILE(GLOB SOURCES
22
"AlignedAllocator.h"
33
"Array1DRef.h"
44
"Array2DRef.h"
5+
"BitIterator.h"
56
"CroppedArray1DRef.h"
67
"CroppedArray2DRef.h"
78
"DefaultInitAllocatorAdaptor.h"

src/librawspeed/codes/AbstractPrefixCode.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020

2121
#pragma once
2222

23+
#include "adt/BitIterator.h" // for BitMSBIterator
24+
#include "adt/iterator_range.h" // for iterator_range
2325
#include "common/Common.h" // for bitwidth
2426
#include "decoders/RawDecoderException.h" // for ThrowException, ThrowRDE
2527
#include <cstdint> // for uint16_t
@@ -150,6 +152,11 @@ template <typename CodeTag> class AbstractPrefixCode {
150152
assert(code <= ((1U << code_len) - 1U));
151153
}
152154

155+
[[nodiscard]] iterator_range<BitMSBIterator<typename Traits::CodeTy>>
156+
getBitsMSB() const {
157+
return {{code, code_len - 1}, {code, -1}};
158+
}
159+
153160
static bool HaveCommonPrefix(const CodeSymbol& symbol,
154161
const CodeSymbol& partial) {
155162
assert(partial.code_len <= symbol.code_len);

src/librawspeed/codes/BinaryPrefixTree.h

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -87,20 +87,12 @@ void BinaryPrefixTree<CodeTag>::add(const CodeSymbol symbol, CodeTy value) {
8787
invariant(symbol.code_len > 0);
8888
invariant(symbol.code_len <= Traits::MaxCodeLenghtBits);
8989

90-
auto getSymbolsNthMSB = [&symbol](int msbBitIdx) {
91-
invariant(msbBitIdx >= 0 && msbBitIdx < symbol.code_len);
92-
unsigned MSBs = extractHighBits(symbol.code, 1 + msbBitIdx,
93-
/*effectiveBitwidth=*/symbol.code_len);
94-
return MSBs & 0b1;
95-
};
96-
9790
CodeSymbol partial;
9891
partial.code = 0;
9992
partial.code_len = 0;
10093

10194
std::reference_wrapper<std::unique_ptr<Node>> newBud = root;
102-
for (int depth = 0; depth < symbol.code_len; ++depth) {
103-
unsigned bit = getSymbolsNthMSB(depth);
95+
for (unsigned bit : symbol.getBitsMSB()) {
10496
++partial.code_len;
10597
partial.code = (partial.code << 1) | bit;
10698
std::unique_ptr<Node>& bud = newBud;

src/librawspeed/codes/PrefixCodeTreeDecoder.h

Lines changed: 46 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,15 @@
3030
#include <initializer_list> // for initializer_list
3131
#include <iterator> // for advance, next
3232
#include <memory> // for unique_ptr, make_unique
33+
#include <optional> // for optional
3334
#include <tuple> // for tie
3435
#include <utility> // for pair
3536
#include <vector> // for vector, vector<>::co...
3637

3738
namespace rawspeed {
3839

3940
template <typename CodeTag>
40-
class PrefixCodeTreeDecoder final : public AbstractPrefixCodeDecoder<CodeTag> {
41+
class PrefixCodeTreeDecoder : public AbstractPrefixCodeDecoder<CodeTag> {
4142
public:
4243
using Tag = CodeTag;
4344
using Base = AbstractPrefixCodeDecoder<CodeTag>;
@@ -48,29 +49,23 @@ class PrefixCodeTreeDecoder final : public AbstractPrefixCodeDecoder<CodeTag> {
4849
private:
4950
BinaryPrefixTree<CodeTag> tree;
5051

52+
protected:
5153
template <typename BIT_STREAM>
52-
inline std::pair<typename Base::CodeSymbol,
53-
typename Traits::CodeValueTy /*codeValue*/>
54-
readSymbol(BIT_STREAM& bs) const {
55-
static_assert(
56-
BitStreamTraits<typename BIT_STREAM::tag>::canUseWithPrefixCodeDecoder,
57-
"This BitStream specialization is not marked as usable here");
54+
inline std::pair<typename Base::CodeSymbol, int /*codeValue*/>
55+
finishReadingPartialSymbol(BIT_STREAM& bs,
56+
typename Base::CodeSymbol initialPartial) const {
5857
typename Base::CodeSymbol partial;
58+
partial.code = 0;
59+
partial.code_len = 0;
5960

6061
const auto* top = &(tree.root->getAsBranch());
6162

62-
// Read bits until either find the code or detect the incorrect code
63-
for (partial.code = 0, partial.code_len = 1;; ++partial.code_len) {
64-
invariant(partial.code_len <= Traits::MaxCodeLenghtBits);
65-
66-
// Read one more bit
67-
const bool bit = bs.getBitsNoFill(1);
68-
69-
// codechecker_false_positive [core.uninitialized.Assign]
63+
auto walkBinaryTree = [&partial, &top](bool bit)
64+
-> std::optional<
65+
std::pair<typename Base::CodeSymbol, int /*codeValue*/>> {
7066
partial.code <<= 1;
7167
partial.code |= bit;
72-
73-
// What is the last bit, which we have just read?
68+
partial.code_len++;
7469

7570
// NOTE: The order *IS* important! Left to right, zero to one!
7671
const auto& newNode = top->buds[bit];
@@ -84,17 +79,50 @@ class PrefixCodeTreeDecoder final : public AbstractPrefixCodeDecoder<CodeTag> {
8479
if (static_cast<typename decltype(tree)::Node::Type>(*newNode) ==
8580
decltype(tree)::Node::Type::Leaf) {
8681
// Ok, great, hit a Leaf. This is it.
87-
return {partial, newNode->getAsLeaf().value};
82+
return {{partial, newNode->getAsLeaf().value}};
8883
}
8984

9085
// Else, this is a branch, continue looking.
9186
top = &(newNode->getAsBranch());
87+
return std::nullopt;
88+
};
89+
90+
// First, translate pre-existing code bits.
91+
for (unsigned bit : initialPartial.getBitsMSB()) {
92+
if (auto sym = walkBinaryTree(bit))
93+
return *sym;
94+
}
95+
96+
// Read bits until either find the code or detect the incorrect code
97+
while (true) {
98+
invariant(partial.code_len <= Traits::MaxCodeLenghtBits);
99+
100+
// Read one more bit
101+
const bool bit = bs.getBitsNoFill(1);
102+
103+
if (auto sym = walkBinaryTree(bit))
104+
return *sym;
92105
}
93106

94107
// We have either returned the found symbol, or thrown on incorrect symbol.
95108
__builtin_unreachable();
96109
}
97110

111+
template <typename BIT_STREAM>
112+
inline std::pair<typename Base::CodeSymbol, int /*codeValue*/>
113+
readSymbol(BIT_STREAM& bs) const {
114+
static_assert(
115+
BitStreamTraits<typename BIT_STREAM::tag>::canUseWithPrefixCodeDecoder,
116+
"This BitStream specialization is not marked as usable here");
117+
118+
// Start from completely unknown symbol.
119+
typename Base::CodeSymbol partial;
120+
partial.code_len = 0;
121+
partial.code = 0;
122+
123+
return finishReadingPartialSymbol(bs, partial);
124+
}
125+
98126
public:
99127
void setup(bool fullDecode_, bool fixDNGBug16_) {
100128
AbstractPrefixCodeDecoder<CodeTag>::setup(fullDecode_, fixDNGBug16_);

0 commit comments

Comments
 (0)