RawSpeed
fast raw decoding library
Loading...
Searching...
No Matches
VariableLengthLoad.h
Go to the documentation of this file.
1/*
2 RawSpeed - RAW file decoder.
3
4 Copyright (C) 2024 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/Array1DRef.h"
24#include "adt/Bit.h"
25#include "adt/Casts.h"
27#include "adt/Invariant.h"
28#include "io/Endianness.h"
29#include <algorithm>
30#include <climits>
31#include <cstddef>
32#include <cstdint>
33#include <cstring>
34#include <type_traits>
35
36namespace rawspeed {
37
38namespace impl {
39
40template <typename T> struct zext {};
41
42template <> struct zext<uint8_t> {
43 using type = uint16_t;
44};
45template <> struct zext<uint16_t> {
46 using type = uint32_t;
47};
48template <> struct zext<uint32_t> {
49 using type = uint64_t;
50};
51
52template <typename T>
53concept CanZExt = requires { typename zext<T>::type; };
54
55template <typename T>
56 requires std::is_unsigned_v<T> && CanZExt<T>
57inline T logicalRightShiftSafe(T val, int shAmt) {
58 invariant(shAmt >= 0);
59 shAmt = std::min(shAmt, implicit_cast<int>(bitwidth<T>()));
60 using WideT = typename zext<T>::type;
61 auto valWide = static_cast<WideT>(val);
62 valWide >>= shAmt;
63 return implicit_cast<T>(valWide);
64}
65
66template <typename T>
67 requires std::is_unsigned_v<T> && (!CanZExt<T>)
68inline T logicalRightShiftSafe(T val, int shAmt) {
69 invariant(shAmt >= 0);
70 if (shAmt >= implicit_cast<int>(bitwidth<T>()))
71 return 0;
72 val >>= shAmt;
73 return val;
74}
75
76template <typename T>
77 requires std::is_unsigned_v<T>
79 Array1DRef<const std::byte> in, int inPos) {
80 invariant(out.size() == sizeof(T));
81
82 int inPosFixup = 0;
83 if (int inPosEnd = inPos + out.size(); in.size() < inPosEnd)
84 inPosFixup = in.size() - inPosEnd;
85 invariant(inPosFixup <= 0);
86
87 inPos += inPosFixup;
88
89 in = in.getCrop(inPos, out.size()).getAsArray1DRef();
90 invariant(in.size() == out.size());
91
92 auto tmp = getLE<T>(in.begin());
93
94 int posMismatchBits = CHAR_BIT * (-inPosFixup);
95 tmp = logicalRightShiftSafe(tmp, posMismatchBits);
96
97 tmp = getLE<T>(&tmp);
98 memcpy(out.begin(), &tmp, sizeof(T));
99}
100
101} // namespace impl
102
104 Array1DRef<const std::byte> in, int inPos) {
105
106 invariant(out.size() != 0);
108 invariant(out.size() <= 8);
109 invariant(in.size() != 0);
110 invariant(out.size() <= in.size());
111 invariant(inPos >= 0);
112
113 switch (out.size()) {
114 case 1:
115 impl::variableLengthLoad<uint8_t>(out, in, inPos);
116 return;
117 case 2:
119 return;
120 case 4:
122 return;
123 case 8:
125 return;
126 default:
127 __builtin_unreachable();
128 }
129}
130
133 invariant(out.size() != 0);
134 invariant(in.size() != 0);
135 invariant(out.size() <= in.size());
136 invariant(inPos >= 0);
137
138 std::fill(out.begin(), out.end(), std::byte{0x00});
139
140 for (int outIndex = 0; outIndex != out.size(); ++outIndex) {
141 const int inIndex = inPos + outIndex;
142 if (inIndex >= in.size())
143 return;
144 out(outIndex) = in(inIndex); // masked load
145 }
146}
147
150 int inPos) {
151 invariant(out.size() != 0);
152 invariant(in.size() != 0);
153 invariant(out.size() <= in.size());
154 invariant(inPos >= 0);
155
156 std::fill(out.begin(), out.end(), std::byte{0x00});
157
158 inPos = std::min(inPos, in.size());
159
160 int inPosEnd = inPos + out.size();
161 inPosEnd = std::min(inPosEnd, in.size());
162 invariant(inPos <= inPosEnd);
163
164 const int copySize = inPosEnd - inPos;
165 invariant(copySize >= 0);
166 invariant(copySize <= out.size());
167
168 out = out.getCrop(/*offset=*/0, copySize).getAsArray1DRef();
169 in = in.getCrop(/*offset=*/inPos, copySize).getAsArray1DRef();
170 invariant(in.size() == out.size());
171
172 memcpy(out.begin(), in.begin(), copySize);
173}
174
175} // namespace rawspeed
#define invariant(expr)
Definition Invariant.h:27
CroppedArray1DRef< T > getCrop(int offset, int numElts) const
Definition Array1DRef.h:110
int RAWSPEED_READONLY size() const
void variableLengthLoad(Array1DRef< std::byte > out, Array1DRef< const std::byte > in, int inPos)
T logicalRightShiftSafe(T val, int shAmt)
constexpr RAWSPEED_READNONE Ttgt implicit_cast(Tsrc value)
Definition Casts.h:32
throw T(buf.data())
void variableLengthLoadNaiveViaConditionalLoad(Array1DRef< std::byte > out, Array1DRef< const std::byte > in, int inPos)
constexpr bool RAWSPEED_READNONE isPowerOfTwo(T val)
Definition Bit.h:38
void variableLengthLoad(const Array1DRef< std::byte > out, Array1DRef< const std::byte > in, int inPos)
constexpr unsigned RAWSPEED_READNONE bitwidth(T unused={})
Definition Bit.h:43
void variableLengthLoadNaiveViaMemcpy(Array1DRef< std::byte > out, Array1DRef< const std::byte > in, int inPos)
T getLE(const void *data)
Definition Endianness.h:120