/src/exiv2/include/exiv2/slice.hpp
Line | Count | Source |
1 | | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | | |
3 | | #ifndef EXIV2_SLICE_HPP |
4 | | #define EXIV2_SLICE_HPP |
5 | | |
6 | | #include <cassert> |
7 | | #include <cstddef> |
8 | | #include <iterator> |
9 | | #include <stdexcept> |
10 | | |
11 | | namespace Exiv2 { |
12 | | namespace Internal { |
13 | | /*! |
14 | | * Common base class of all slice implementations. |
15 | | * |
16 | | * Implements only the most basic functions, which do not require any |
17 | | * knowledge about the stored data. |
18 | | */ |
19 | | struct SliceBase { |
20 | 76.6M | SliceBase(size_t begin, size_t end) : begin_(begin), end_(end) { |
21 | 76.6M | if (begin >= end) { |
22 | 57 | throw std::out_of_range("Begin must be smaller than end"); |
23 | 57 | } |
24 | 76.6M | } |
25 | | |
26 | | /*! |
27 | | * Return the number of elements in the slice. |
28 | | */ |
29 | 158M | [[nodiscard]] size_t size() const noexcept { |
30 | | // cannot underflow, as we know that begin < end |
31 | 158M | return end_ - begin_; |
32 | 158M | } |
33 | | |
34 | | protected: |
35 | | /*! |
36 | | * Throw an exception when index is too large. |
37 | | * |
38 | | * @throw std::out_of_range when `index` will access an element |
39 | | * outside of the slice |
40 | | */ |
41 | 155M | void rangeCheck(size_t index) const { |
42 | 155M | if (index >= size()) { |
43 | 0 | throw std::out_of_range("Index outside of the slice"); |
44 | 0 | } |
45 | 155M | } |
46 | | |
47 | | /*! |
48 | | * lower and upper bounds of the slice with respect to the |
49 | | * container/array stored in storage_ |
50 | | */ |
51 | | size_t begin_; |
52 | | size_t end_; |
53 | | }; |
54 | | |
55 | | /*! |
56 | | * @brief This class provides the public-facing const-qualified methods |
57 | | * of a slice. |
58 | | * |
59 | | * The public methods are implemented in a generic fashion using a |
60 | | * storage_type. This type contains the actual reference to the data to |
61 | | * which the slice points and provides the following methods: |
62 | | * |
63 | | * - (const) value_type& unsafeAt(size_t index) (const) |
64 | | * Return the value at the given index of the underlying container, |
65 | | * without promising to perform a range check and without any |
66 | | * knowledge of the slices' size |
67 | | * |
68 | | * - const_iterator/iterator unsafeGetIteratorAt(size_t index) (const) |
69 | | * Return a (constant) iterator at the given index of the underlying |
70 | | * container. Again, no range checks are promised. |
71 | | * |
72 | | * - Constructor(data_type& data, size_t begin, size_t end) |
73 | | * Can use `begin` & `end` to perform range checks on `data`, but |
74 | | * should not store both values. Must not take ownership of `data`! |
75 | | * |
76 | | * - Must save data as a public member named `data_`. |
77 | | * |
78 | | * - Must provide appropriate typedefs for iterator, const_iterator and |
79 | | * value_type |
80 | | */ |
81 | | template <template <typename data_type> class storage_type, typename data_type> |
82 | | struct ConstSliceBase : SliceBase { |
83 | | using value_type = typename storage_type<data_type>::value_type; |
84 | | |
85 | | /*! |
86 | | * Default constructor, requires begin to be smaller than end, |
87 | | * otherwise an exception is thrown. Also forwards all parameters to |
88 | | * the constructor of storage_ |
89 | | */ |
90 | 76.6M | ConstSliceBase(data_type& data, size_t begin, size_t end) : SliceBase(begin, end), storage_(data, begin, end) { |
91 | 76.6M | } Exiv2::Internal::ConstSliceBase<Exiv2::Internal::PtrSliceStorage, unsigned char*>::ConstSliceBase(unsigned char*&, unsigned long, unsigned long) Line | Count | Source | 90 | 120k | ConstSliceBase(data_type& data, size_t begin, size_t end) : SliceBase(begin, end), storage_(data, begin, end) { | 91 | 120k | } |
Exiv2::Internal::ConstSliceBase<Exiv2::Internal::PtrSliceStorage, unsigned char* const>::ConstSliceBase(unsigned char* const&, unsigned long, unsigned long) Line | Count | Source | 90 | 1.24k | ConstSliceBase(data_type& data, size_t begin, size_t end) : SliceBase(begin, end), storage_(data, begin, end) { | 91 | 1.24k | } |
Exiv2::Internal::ConstSliceBase<Exiv2::Internal::PtrSliceStorage, unsigned char const*>::ConstSliceBase(unsigned char const*&, unsigned long, unsigned long) Line | Count | Source | 90 | 76.5M | ConstSliceBase(data_type& data, size_t begin, size_t end) : SliceBase(begin, end), storage_(data, begin, end) { | 91 | 76.5M | } |
Exiv2::Internal::ConstSliceBase<Exiv2::Internal::ContainerStorage, Exiv2::Slice<unsigned char*> const>::ConstSliceBase(Exiv2::Slice<unsigned char*> const&, unsigned long, unsigned long) Line | Count | Source | 90 | 1.22k | ConstSliceBase(data_type& data, size_t begin, size_t end) : SliceBase(begin, end), storage_(data, begin, end) { | 91 | 1.22k | } |
|
92 | | |
93 | | /*! |
94 | | * Obtain a constant reference to the element with the specified |
95 | | * index in the slice. |
96 | | * |
97 | | * @throw std::out_of_range when index is out of bounds of the slice |
98 | | */ |
99 | 155M | [[nodiscard]] const auto& at(size_t index) const { |
100 | 155M | rangeCheck(index); |
101 | | // we know: begin_ < end <= size() <= SIZE_T_MAX |
102 | | // and: index < end - begin |
103 | | // thus: index + begin < end <= SIZE_T_MAX |
104 | | // => no overflow is possible |
105 | 155M | return storage_.unsafeAt(begin_ + index); |
106 | 155M | } Exiv2::Internal::ConstSliceBase<Exiv2::Internal::PtrSliceStorage, unsigned char*>::at(unsigned long) const Line | Count | Source | 99 | 2.43M | [[nodiscard]] const auto& at(size_t index) const { | 100 | 2.43M | rangeCheck(index); | 101 | | // we know: begin_ < end <= size() <= SIZE_T_MAX | 102 | | // and: index < end - begin | 103 | | // thus: index + begin < end <= SIZE_T_MAX | 104 | | // => no overflow is possible | 105 | 2.43M | return storage_.unsafeAt(begin_ + index); | 106 | 2.43M | } |
Exiv2::Internal::ConstSliceBase<Exiv2::Internal::PtrSliceStorage, unsigned char const*>::at(unsigned long) const Line | Count | Source | 99 | 153M | [[nodiscard]] const auto& at(size_t index) const { | 100 | 153M | rangeCheck(index); | 101 | | // we know: begin_ < end <= size() <= SIZE_T_MAX | 102 | | // and: index < end - begin | 103 | | // thus: index + begin < end <= SIZE_T_MAX | 104 | | // => no overflow is possible | 105 | 153M | return storage_.unsafeAt(begin_ + index); | 106 | 153M | } |
Exiv2::Internal::ConstSliceBase<Exiv2::Internal::ContainerStorage, Exiv2::Slice<unsigned char*> const>::at(unsigned long) const Line | Count | Source | 99 | 7.81k | [[nodiscard]] const auto& at(size_t index) const { | 100 | 7.81k | rangeCheck(index); | 101 | | // we know: begin_ < end <= size() <= SIZE_T_MAX | 102 | | // and: index < end - begin | 103 | | // thus: index + begin < end <= SIZE_T_MAX | 104 | | // => no overflow is possible | 105 | 7.81k | return storage_.unsafeAt(begin_ + index); | 106 | 7.81k | } |
|
107 | | |
108 | | /*! |
109 | | * Obtain a constant iterator to the first element in the slice. |
110 | | */ |
111 | | [[nodiscard]] auto cbegin() const noexcept { |
112 | | return storage_.unsafeGetIteratorAt(begin_); |
113 | | } |
114 | | |
115 | | /*! |
116 | | * Obtain a constant iterator to the first beyond the slice. |
117 | | */ |
118 | | [[nodiscard]] auto cend() const noexcept { |
119 | | return storage_.unsafeGetIteratorAt(end_); |
120 | | } |
121 | | |
122 | | /*! |
123 | | * Create a constant sub-slice with the given bounds (with respect |
124 | | * to the current slice). |
125 | | * |
126 | | * @tparam slice_type Type of the slice that this function shall |
127 | | * return. Provide it with the type of the class that derives from |
128 | | * mutable_slice_base. |
129 | | */ |
130 | | template <typename slice_type> |
131 | 1.24k | [[nodiscard]] slice_type subSlice(size_t begin, size_t end) const { |
132 | 1.24k | this->rangeCheck(begin); |
133 | | // end == size() is a legal value, since end is the first |
134 | | // element beyond the slice |
135 | | // end == 0 is not a legal value (subtraction will underflow and |
136 | | // throw an exception) |
137 | 1.24k | this->rangeCheck(end - 1); |
138 | | // additions are safe, begin and end are smaller than size() |
139 | 1.24k | const size_t new_begin = begin + this->begin_; |
140 | 1.24k | const size_t new_end = this->begin_ + end; |
141 | 1.24k | if (new_end > this->end_) { |
142 | 0 | throw std::out_of_range("Invalid input parameters to slice"); |
143 | 0 | } |
144 | 1.24k | return {storage_.data_, new_begin, new_end}; |
145 | 1.24k | } |
146 | | |
147 | | protected: |
148 | | /*! |
149 | | * Stores a reference to the actual data. |
150 | | */ |
151 | | storage_type<data_type> storage_; |
152 | | }; |
153 | | |
154 | | /*! |
155 | | * This class provides all public-facing non-const-qualified methods of |
156 | | * slices. It only re-implements the const-qualified versions as |
157 | | * non-const. |
158 | | */ |
159 | | template <template <typename> class storage_type, typename data_type> |
160 | | struct MutableSliceBase : public ConstSliceBase<storage_type, data_type> { |
161 | | using ConstSliceBase<storage_type, data_type>::ConstSliceBase; |
162 | | |
163 | | /*! |
164 | | * Obtain a reference to the element with the specified index in the |
165 | | * slice. |
166 | | * |
167 | | * @throw std::out_of_range when index is out of bounds of the slice |
168 | | */ |
169 | | auto& at(size_t index) { |
170 | | this->rangeCheck(index); |
171 | | return this->storage_.unsafeAt(this->begin_ + index); |
172 | | } |
173 | | |
174 | 2.43M | [[nodiscard]] const auto& at(size_t index) const { |
175 | 2.43M | return base_type::at(index); |
176 | 2.43M | } |
177 | | |
178 | | /*! |
179 | | * Obtain an iterator to the first element in the slice. |
180 | | */ |
181 | | [[nodiscard]] auto begin() noexcept { |
182 | | return this->storage_.unsafeGetIteratorAt(this->begin_); |
183 | | } |
184 | | |
185 | | /*! |
186 | | * Obtain an iterator to the first element beyond the slice. |
187 | | */ |
188 | | [[nodiscard]] auto end() noexcept { |
189 | | return this->storage_.unsafeGetIteratorAt(this->end_); |
190 | | } |
191 | | |
192 | | protected: |
193 | | /*! |
194 | | * Explicitly convert this instance into a base-class of the |
195 | | * appropriate constant version of this slice. |
196 | | * |
197 | | * This function is required to properly implement the `subSlice() |
198 | | * const` function for mutable slices. The problem here is, that a |
199 | | * slice<T> and a slice<const T> actually don't share the same base |
200 | | * class `ConstSliceBase<storage_type, T>`. Instead `slice<T>` |
201 | | * inherits from `ConstSliceBase<storage_type, T>` and `slice<const |
202 | | * T>` inherits from `ConstSliceBase<storage_type, const T>`. |
203 | | * |
204 | | * Now, `slice<T>` can call the `subSlice() const` method from its |
205 | | * base class, but that will return a mutable `slice<T>`! Instead we |
206 | | * use this function to convert the `slice<T>` into the parent of |
207 | | * the appropriate `slice<const T>` and call its `subSlice() const`, |
208 | | * which returns the correct type. |
209 | | */ |
210 | 1.24k | [[nodiscard]] ConstSliceBase<storage_type, const data_type> to_const_base() const noexcept { |
211 | 1.24k | return {this->storage_.data_, this->begin_, this->end_}; |
212 | 1.24k | } |
213 | | |
214 | | using base_type = ConstSliceBase<storage_type, data_type>; |
215 | | |
216 | | /*! |
217 | | * Create a mutable sub-slice with the given bounds (with respect to |
218 | | * the current slice). |
219 | | * |
220 | | * @tparam slice_type Type of the slice that this function shall |
221 | | * return. Provide it with the type of the class that derives from |
222 | | * mutable_slice_base. |
223 | | */ |
224 | | template <typename slice_type> |
225 | | [[nodiscard]] slice_type subSlice(size_t begin, size_t end) { |
226 | | this->rangeCheck(begin); |
227 | | // end == size() is a legal value, since end is the first |
228 | | // element beyond the slice |
229 | | // end == 0 is not a legal value (subtraction will underflow and |
230 | | // throw an exception) |
231 | | this->rangeCheck(end - 1); |
232 | | |
233 | | // additions are safe, begin & end are smaller than size() |
234 | | const size_t new_begin = begin + this->begin_; |
235 | | const size_t new_end = this->begin_ + end; |
236 | | if (new_end > this->end_) { |
237 | | throw std::out_of_range("Invalid input parameters to slice"); |
238 | | } |
239 | | return {this->storage_.data_, new_begin, new_end}; |
240 | | } |
241 | | }; |
242 | | |
243 | | /*! |
244 | | * Implementation of the storage concept for STL-containers. |
245 | | * |
246 | | * @tparam container Type of the STL-container. |
247 | | */ |
248 | | template <typename container> |
249 | | struct ContainerStorage { |
250 | | using value_type = std::remove_cv_t<typename container::value_type>; |
251 | | |
252 | | /*! |
253 | | * @throw std::out_of_range when end is larger than the container's |
254 | | * size. |
255 | | */ |
256 | 1.20k | ContainerStorage(container& data, size_t /* begin*/, size_t end) : data_(data) { |
257 | 1.20k | if (end > data.size()) { |
258 | 0 | throw std::out_of_range("Invalid input parameters to slice"); |
259 | 0 | } |
260 | 1.20k | } |
261 | | |
262 | | /*! |
263 | | * Obtain a constant reference to the element with the given `index` |
264 | | * in the container. |
265 | | * |
266 | | * @throw whatever container::at() throws |
267 | | */ |
268 | 7.81k | [[nodiscard]] const auto& unsafeAt(size_t index) const { |
269 | 7.81k | return data_.at(index); |
270 | 7.81k | } |
271 | | |
272 | | [[nodiscard]] auto& unsafeAt(size_t index) { |
273 | | return data_.at(index); |
274 | | } |
275 | | |
276 | | /*! |
277 | | * Obtain an iterator at the position of the element with the given |
278 | | * index in the container. |
279 | | * |
280 | | * @throw whatever container::begin() and std::advance() throw |
281 | | */ |
282 | | [[nodiscard]] auto unsafeGetIteratorAt(size_t index) { |
283 | | // we are screwed if the container got changed => try to catch it |
284 | | assert(index <= data_.size()); |
285 | | |
286 | | auto it = data_.begin(); |
287 | | std::advance(it, index); |
288 | | return it; |
289 | | } |
290 | | |
291 | | [[nodiscard]] auto unsafeGetIteratorAt(size_t index) const { |
292 | | assert(index <= data_.size()); |
293 | | |
294 | | auto it = data_.begin(); |
295 | | std::advance(it, index); |
296 | | return it; |
297 | | } |
298 | | |
299 | | container& data_; |
300 | | }; |
301 | | |
302 | | /*! |
303 | | * @brief Implementation of the storage concept for slices of C arrays. |
304 | | * |
305 | | * @tparam storage_type Type as which the C-array should be stored. Use |
306 | | * this parameter to save constant arrays as `const` and mutable ones as |
307 | | * non-`const`. |
308 | | */ |
309 | | template <typename storage_type> |
310 | | struct PtrSliceStorage { |
311 | | using value_type = std::remove_cv_t<std::remove_pointer_t<storage_type>>; |
312 | | |
313 | | /*! |
314 | | * Stores ptr and checks that it is not `NULL`. The slice's bounds |
315 | | * are ignored, as we do not know the array's length. |
316 | | * |
317 | | * @throw std::invalid_argument when ptr is `NULL` |
318 | | */ |
319 | 76.6M | PtrSliceStorage(storage_type ptr, size_t /*begin*/, size_t /*end*/) : data_(ptr) { |
320 | 76.6M | if (!ptr) { |
321 | 0 | throw std::invalid_argument("Null pointer passed to slice constructor"); |
322 | 0 | } |
323 | 76.6M | } Exiv2::Internal::PtrSliceStorage<unsigned char*>::PtrSliceStorage(unsigned char*, unsigned long, unsigned long) Line | Count | Source | 319 | 120k | PtrSliceStorage(storage_type ptr, size_t /*begin*/, size_t /*end*/) : data_(ptr) { | 320 | 120k | if (!ptr) { | 321 | 0 | throw std::invalid_argument("Null pointer passed to slice constructor"); | 322 | 0 | } | 323 | 120k | } |
Exiv2::Internal::PtrSliceStorage<unsigned char* const>::PtrSliceStorage(unsigned char*, unsigned long, unsigned long) Line | Count | Source | 319 | 1.24k | PtrSliceStorage(storage_type ptr, size_t /*begin*/, size_t /*end*/) : data_(ptr) { | 320 | 1.24k | if (!ptr) { | 321 | 0 | throw std::invalid_argument("Null pointer passed to slice constructor"); | 322 | 0 | } | 323 | 1.24k | } |
Exiv2::Internal::PtrSliceStorage<unsigned char const*>::PtrSliceStorage(unsigned char const*, unsigned long, unsigned long) Line | Count | Source | 319 | 76.5M | PtrSliceStorage(storage_type ptr, size_t /*begin*/, size_t /*end*/) : data_(ptr) { | 320 | 76.5M | if (!ptr) { | 321 | 0 | throw std::invalid_argument("Null pointer passed to slice constructor"); | 322 | 0 | } | 323 | 76.5M | } |
|
324 | | |
325 | | /*! |
326 | | * Obtain a reference to the element with the given `index` in the |
327 | | * array. |
328 | | * |
329 | | * @note Does not throw |
330 | | */ |
331 | | [[nodiscard]] auto& unsafeAt(size_t index) noexcept { |
332 | | return data_[index]; |
333 | | } |
334 | | |
335 | 155M | [[nodiscard]] const auto& unsafeAt(size_t index) const noexcept { |
336 | 155M | return data_[index]; |
337 | 155M | } Exiv2::Internal::PtrSliceStorage<unsigned char*>::unsafeAt(unsigned long) const Line | Count | Source | 335 | 2.43M | [[nodiscard]] const auto& unsafeAt(size_t index) const noexcept { | 336 | 2.43M | return data_[index]; | 337 | 2.43M | } |
Exiv2::Internal::PtrSliceStorage<unsigned char const*>::unsafeAt(unsigned long) const Line | Count | Source | 335 | 153M | [[nodiscard]] const auto& unsafeAt(size_t index) const noexcept { | 336 | 153M | return data_[index]; | 337 | 153M | } |
|
338 | | |
339 | | /*! |
340 | | * Obtain an iterator (=pointer) at the position of the element with |
341 | | * the given index in the container. |
342 | | * |
343 | | * @note Does not throw |
344 | | */ |
345 | | [[nodiscard]] auto unsafeGetIteratorAt(size_t index) noexcept { |
346 | | return data_ + index; |
347 | | } |
348 | | |
349 | | [[nodiscard]] auto unsafeGetIteratorAt(size_t index) const noexcept { |
350 | | return data_ + index; |
351 | | } |
352 | | |
353 | | storage_type data_; |
354 | | }; |
355 | | |
356 | | } // namespace Internal |
357 | | |
358 | | /*! |
359 | | * @brief Slice (= view) for STL containers. |
360 | | * |
361 | | * This is a very simple implementation of slices (i.e. views of sub-arrays) |
362 | | * for STL containers that support O(1) element access and random access |
363 | | * iterators (like std::vector, std::array and std::string). |
364 | | * |
365 | | * A slice represents the semi-open interval [begin, end) and provides a |
366 | | * (mutable) view, it does however not own the data! It can be used to |
367 | | * conveniently pass parts of containers into functions without having to use |
368 | | * iterators or offsets. |
369 | | * |
370 | | * In contrast to C++20's std::span<T> it is impossible to read beyond the |
371 | | * container's bounds and unchecked access is not-possible (by design). |
372 | | * |
373 | | * Example usage: |
374 | | * ~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} |
375 | | * std::vector<int> vec = {0, 1, 2, 3, 4}; |
376 | | * slice<std::vector<int> > one_two(vec, 1, 3); |
377 | | * assert(one_two.size() == 2); |
378 | | * assert(one_two.at(0) == 1 && one_two.at(1) == 2); |
379 | | * // mutate the contents: |
380 | | * one_two.at(0) *= 2; |
381 | | * one_two.at(1) *= 3; |
382 | | * assert(one_two.at(0) == 2 && one_two.at(1) == 6); |
383 | | * ~~~~~~~~~~~~~~~~~~~~~~~~~ |
384 | | * |
385 | | * Slices also offer access via iterators of the same type as the underlying |
386 | | * container, so that they can be used in a comparable fashion: |
387 | | * ~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} |
388 | | * std::vector<int> vec = {0, 1, 2, 3, 4}; |
389 | | * slice<std::vector<int>> three_four(vec, 3, 5); |
390 | | * assert(*three_four.begin() == 3 && *three_four.end() == 4); |
391 | | * // this prints: |
392 | | * // 3 |
393 | | * // 4 |
394 | | * for (const auto & elem : three_four) { |
395 | | * std::cout << elem << '\n'; |
396 | | * } |
397 | | * ~~~~~~~~~~~~~~~~~~~~~~~~~ |
398 | | * |
399 | | * @tparam container A STL container type, like vector or array. Must support |
400 | | * array-like access via the `at()` method. |
401 | | */ |
402 | | template <typename container> |
403 | | struct Slice : public Internal::MutableSliceBase<Internal::ContainerStorage, container> { |
404 | | using Internal::MutableSliceBase<Internal::ContainerStorage, container>::MutableSliceBase; |
405 | | |
406 | | /*! |
407 | | * Constructs a new constant subSlice. Behaves otherwise exactly like |
408 | | * the non-const version. |
409 | | */ |
410 | | [[nodiscard]] Slice<const container> subSlice(size_t begin, size_t end) const { |
411 | | return this->to_const_base().template subSlice<Slice<const container>>(begin, end); |
412 | | } |
413 | | }; |
414 | | |
415 | | /*! |
416 | | * @brief Specialization of slices for constant containers. |
417 | | */ |
418 | | template <typename container> |
419 | | struct Slice<const container> : public Internal::ConstSliceBase<Internal::ContainerStorage, const container> { |
420 | | using Internal::ConstSliceBase<Internal::ContainerStorage, const container>::ConstSliceBase; |
421 | | |
422 | | [[nodiscard]] Slice subSlice(size_t begin, size_t end) const { |
423 | | return Internal::ConstSliceBase<Internal::ContainerStorage, |
424 | | const container>::template subSlice<Slice<const container>>(begin, end); |
425 | | } |
426 | | }; |
427 | | |
428 | | /*! |
429 | | * Specialization of slices for constant C-arrays. |
430 | | * |
431 | | * These have exactly the same interface as the slices for STL-containers, |
432 | | * with the *crucial* exception, that the slice's constructor *cannot* make |
433 | | * a proper bounds check! It can only verify that you didn't accidentally |
434 | | * swap begin and end! |
435 | | */ |
436 | | template <typename T> |
437 | | struct Slice<const T*> : public Internal::ConstSliceBase<Internal::PtrSliceStorage, const T*> { |
438 | | /*! |
439 | | * Constructor. |
440 | | * |
441 | | * @param[in] ptr C-array of which a slice should be constructed. Must |
442 | | * not be a null pointer. |
443 | | * @param[in] begin Index of the first element in the slice. |
444 | | * @param[in] end Index of the first element that is no longer in the |
445 | | * slice. |
446 | | * |
447 | | * Please note that the constructor has no way how to verify that |
448 | | * `begin` and `end` are not out of bounds of the provided array! |
449 | | */ |
450 | | Slice(const T* ptr, size_t begin, size_t end) : |
451 | 76.5M | Internal::ConstSliceBase<Internal::PtrSliceStorage, const T*>(ptr, begin, end) { |
452 | | // TODO: use using in C++11 |
453 | 76.5M | } |
454 | | |
455 | | [[nodiscard]] Slice<const T*> subSlice(size_t begin, size_t end) const { |
456 | | return Internal::ConstSliceBase<Internal::PtrSliceStorage, const T*>::template subSlice<Slice<const T*>>(begin, |
457 | | end); |
458 | | } |
459 | | }; |
460 | | |
461 | | /*! |
462 | | * Specialization of slices for (mutable) C-arrays. |
463 | | */ |
464 | | template <typename T> |
465 | | struct Slice<T*> : public Internal::MutableSliceBase<Internal::PtrSliceStorage, T*> { |
466 | 120k | Slice(T* ptr, size_t begin, size_t end) : Internal::MutableSliceBase<Internal::PtrSliceStorage, T*>(ptr, begin, end) { |
467 | | // TODO: use using in C++11 |
468 | 120k | } |
469 | | |
470 | | [[nodiscard]] Slice<T*> subSlice(size_t begin, size_t end) { |
471 | | return Internal::MutableSliceBase<Internal::PtrSliceStorage, T*>::template subSlice<Slice<T*>>(begin, end); |
472 | | } |
473 | | |
474 | 1.24k | [[nodiscard]] Slice<const T*> subSlice(size_t begin, size_t end) const { |
475 | 1.24k | return this->to_const_base().template subSlice<Slice<const T*>>(begin, end); |
476 | 1.24k | } |
477 | | }; |
478 | | |
479 | | /*! |
480 | | * @brief Return a new slice with the given bounds. |
481 | | * |
482 | | * Convenience wrapper around the slice's constructor for automatic template |
483 | | * parameter deduction. |
484 | | */ |
485 | | template <typename T> |
486 | 1.22k | [[nodiscard]] Slice<T> makeSlice(T& cont, size_t begin, size_t end) { |
487 | 1.22k | return {cont, begin, end}; |
488 | 1.22k | } |
489 | | |
490 | | /*! |
491 | | * Overload of makeSlice for slices of C-arrays. |
492 | | */ |
493 | | template <typename T> |
494 | | [[nodiscard]] Slice<T*> makeSlice(T* ptr, size_t begin, size_t end) { |
495 | | return {ptr, begin, end}; |
496 | | } |
497 | | |
498 | | /*! |
499 | | * @brief Return a new slice spanning the whole container. |
500 | | */ |
501 | | template <typename container> |
502 | | [[nodiscard]] Slice<container> makeSlice(container& cont) { |
503 | | return {cont, 0, cont.size()}; |
504 | | } |
505 | | |
506 | | /*! |
507 | | * @brief Return a new slice spanning from begin until the end of the |
508 | | * container. |
509 | | */ |
510 | | template <typename container> |
511 | | [[nodiscard]] Slice<container> makeSliceFrom(container& cont, size_t begin) { |
512 | | return {cont, begin, cont.size()}; |
513 | | } |
514 | | |
515 | | /*! |
516 | | * @brief Return a new slice spanning until `end`. |
517 | | */ |
518 | | template <typename container> |
519 | | [[nodiscard]] Slice<container> makeSliceUntil(container& cont, size_t end) { |
520 | | return {cont, 0, end}; |
521 | | } |
522 | | |
523 | | /*! |
524 | | * Overload of makeSliceUntil for pointer based slices. |
525 | | */ |
526 | | template <typename T> |
527 | 76.5M | [[nodiscard]] Slice<T*> makeSliceUntil(T* ptr, size_t end) { |
528 | 76.5M | return {ptr, 0, end}; |
529 | 76.5M | } Exiv2::Slice<unsigned char*> Exiv2::makeSliceUntil<unsigned char>(unsigned char*, unsigned long) Line | Count | Source | 527 | 2.49k | [[nodiscard]] Slice<T*> makeSliceUntil(T* ptr, size_t end) { | 528 | 2.49k | return {ptr, 0, end}; | 529 | 2.49k | } |
Exiv2::Slice<unsigned char const*> Exiv2::makeSliceUntil<unsigned char const>(unsigned char const*, unsigned long) Line | Count | Source | 527 | 76.5M | [[nodiscard]] Slice<T*> makeSliceUntil(T* ptr, size_t end) { | 528 | 76.5M | return {ptr, 0, end}; | 529 | 76.5M | } |
|
530 | | |
531 | | } // namespace Exiv2 |
532 | | |
533 | | #endif // EXIV2_SLICE_HPP |