| Exiv2

Loading...
Searching...
No Matches
slice.hpp
1// SPDX-License-Identifier: GPL-2.0-or-later
2
3#ifndef EXIV2_INCLUDE_SLICE_HPP
4#define EXIV2_INCLUDE_SLICE_HPP
5
6#include <cassert>
7#include <cstddef>
8#include <iterator>
9#include <stdexcept>
10
11 namespace Exiv2 {
12 namespace Internal {
19 struct SliceBase {
20 inline SliceBase(size_t begin, size_t end) : begin_(begin), end_(end) {
21 if (begin >= end) {
22 throw std::out_of_range("Begin must be smaller than end");
23 }
24 }
25
29 [[nodiscard]] inline size_t size() const noexcept {
30 // cannot underflow, as we know that begin < end
31 return end_ - begin_;
32 }
33
34 protected:
41 inline void rangeCheck(size_t index) const {
42 if (index >= size()) {
43 throw std::out_of_range("Index outside of the slice");
44 }
45 }
46
51 size_t begin_;
52 size_t end_;
53};
54
81 template <template <typename data_type> class storage_type, typename data_type>
82 struct ConstSliceBase : SliceBase {
83 using iterator = typename storage_type<data_type>::iterator;
84 using const_iterator = typename storage_type<data_type>::const_iterator;
85 using value_type = typename storage_type<data_type>::value_type;
86
92 ConstSliceBase(data_type& data, size_t begin, size_t end) : SliceBase(begin, end), storage_(data, begin, end) {
93 }
94
101 const value_type& at(size_t index) const {
102 rangeCheck(index);
103 // we know: begin_ < end <= size() <= SIZE_T_MAX
104 // and: index < end - begin
105 // thus: index + begin < end <= SIZE_T_MAX
106 // => no overflow is possible
107 return storage_.unsafeAt(begin_ + index);
108 }
109
113 [[nodiscard]] const_iterator cbegin() const noexcept {
114 return storage_.unsafeGetIteratorAt(begin_);
115 }
116
120 [[nodiscard]] const_iterator cend() const noexcept {
121 return storage_.unsafeGetIteratorAt(end_);
122 }
123
132 template <typename slice_type>
133 [[nodiscard]] slice_type subSlice(size_t begin, size_t end) const {
134 this->rangeCheck(begin);
135 // end == size() is a legal value, since end is the first
136 // element beyond the slice
137 // end == 0 is not a legal value (subtraction will underflow and
138 // throw an exception)
139 this->rangeCheck(end - 1);
140 // additions are safe, begin and end are smaller than size()
141 const size_t new_begin = begin + this->begin_;
142 const size_t new_end = this->begin_ + end;
143 if (new_end > this->end_) {
144 throw std::out_of_range("Invalid input parameters to slice");
145 }
146 return slice_type(storage_.data_, new_begin, new_end);
147 }
148
149 protected:
153 storage_type<data_type> storage_;
154};
155
161 template <template <typename> class storage_type, typename data_type>
162 struct MutableSliceBase : public ConstSliceBase<storage_type, data_type> {
163 using ConstSliceBase<storage_type, data_type>::ConstSliceBase;
164 using iterator = typename ConstSliceBase<storage_type, data_type>::iterator;
165 using const_iterator = typename ConstSliceBase<storage_type, data_type>::const_iterator;
166 using value_type = typename ConstSliceBase<storage_type, data_type>::value_type;
167
174 value_type& at(size_t index) {
175 this->rangeCheck(index);
176 return this->storage_.unsafeAt(this->begin_ + index);
177 }
178
179 const value_type& at(size_t index) const {
180 return base_type::at(index);
181 }
182
186 iterator begin() noexcept {
187 return this->storage_.unsafeGetIteratorAt(this->begin_);
188 }
189
193 iterator end() noexcept {
194 return this->storage_.unsafeGetIteratorAt(this->end_);
195 }
196
197 protected:
215 [[nodiscard]] ConstSliceBase<storage_type, const data_type> to_const_base() const noexcept {
216 return {this->storage_.data_, this->begin_, this->end_};
217 }
218
219 using base_type = ConstSliceBase<storage_type, data_type>;
220
229 template <typename slice_type>
230 slice_type subSlice(size_t begin, size_t end) {
231 this->rangeCheck(begin);
232 // end == size() is a legal value, since end is the first
233 // element beyond the slice
234 // end == 0 is not a legal value (subtraction will underflow and
235 // throw an exception)
236 this->rangeCheck(end - 1);
237
238 // additions are safe, begin & end are smaller than size()
239 const size_t new_begin = begin + this->begin_;
240 const size_t new_end = this->begin_ + end;
241 if (new_end > this->end_) {
242 throw std::out_of_range("Invalid input parameters to slice");
243 }
244 return slice_type(this->storage_.data_, new_begin, new_end);
245 }
246};
247
253 template <typename container>
254 struct ContainerStorage {
255 using iterator = typename container::iterator;
256 using const_iterator = typename container::const_iterator;
257
258#if __cplusplus >= 201402L || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201402L))
259 using value_type = std::remove_cv_t<typename container::value_type>;
260#else
261 using value_type = typename std::remove_cv<typename container::value_type>::type;
262#endif
263
268 ContainerStorage(container& data, size_t /* begin*/, size_t end) : data_(data) {
269 if (end > data.size()) {
270 throw std::out_of_range("Invalid input parameters to slice");
271 }
272 }
273
280 [[nodiscard]] const value_type& unsafeAt(size_t index) const {
281 return data_.at(index);
282 }
283
284 [[nodiscard]] value_type& unsafeAt(size_t index) {
285 return data_.at(index);
286 }
287
294 [[nodiscard]] iterator unsafeGetIteratorAt(size_t index) {
295 // we are screwed if the container got changed => try to catch it
296 assert(index <= data_.size());
297
298 auto it = data_.begin();
299 std::advance(it, index);
300 return it;
301 }
302
303 [[nodiscard]] const_iterator unsafeGetIteratorAt(size_t index) const {
304 assert(index <= data_.size());
305
306 auto it = data_.begin();
307 std::advance(it, index);
308 return it;
309 }
310
311 container& data_;
312};
313
321 template <typename storage_type>
322 struct PtrSliceStorage {
323#if __cplusplus >= 201402L || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201402L))
324 using value_type = std::remove_cv_t<std::remove_pointer_t<storage_type>>;
325#else
326 using value_type = typename std::remove_cv<typename std::remove_pointer<storage_type>::type>::type;
327#endif
328 using iterator = value_type*;
329 using const_iterator = const value_type*;
330
337 PtrSliceStorage(storage_type ptr, size_t /*begin*/, size_t /*end*/) : data_(ptr) {
338 if (!ptr) {
339 throw std::invalid_argument("Null pointer passed to slice constructor");
340 }
341 }
342
349 [[nodiscard]] value_type& unsafeAt(size_t index) noexcept {
350 return data_[index];
351 }
352
353 [[nodiscard]] const value_type& unsafeAt(size_t index) const noexcept {
354 return data_[index];
355 }
356
363 [[nodiscard]] iterator unsafeGetIteratorAt(size_t index) noexcept {
364 return data_ + index;
365 }
366
367 [[nodiscard]] const_iterator unsafeGetIteratorAt(size_t index) const noexcept {
368 return data_ + index;
369 }
370
371 storage_type data_;
372};
373
374} // namespace Internal
375
420 template <typename container>
421 struct Slice : public Internal::MutableSliceBase<Internal::ContainerStorage, container> {
422 using Internal::MutableSliceBase<Internal::ContainerStorage, container>::MutableSliceBase;
423 using iterator = typename container::iterator;
424 using const_iterator = typename container::const_iterator;
425
426#if __cplusplus >= 201402L || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201402L))
427 using value_type = std::remove_cv_t<typename container::value_type>;
428#else
429 using value_type = typename std::remove_cv<typename container::value_type>::type;
430#endif
431
441 Slice subSlice(size_t begin, size_t end) {
442 return Internal::MutableSliceBase<Internal::ContainerStorage, container>::template subSlice<Slice>(begin, end);
443 }
444
449 [[nodiscard]] Slice<const container> subSlice(size_t begin, size_t end) const {
450 return this->to_const_base().template subSlice<Slice<const container>>(begin, end);
451 }
452};
453
457 template <typename container>
458 struct Slice<const container> : public Internal::ConstSliceBase<Internal::ContainerStorage, const container> {
459 using Internal::ConstSliceBase<Internal::ContainerStorage, const container>::ConstSliceBase;
460 using iterator = typename container::iterator;
461 using const_iterator = typename container::const_iterator;
462
463#if __cplusplus >= 201402L || (defined(_MSVC_LANG) && (_MSVC_LANG >= 201402L))
464 using value_type = std::remove_cv_t<typename container::value_type>;
465#else
466 using value_type = typename std::remove_cv<typename container::value_type>::type;
467#endif
468
469 Slice subSlice(size_t begin, size_t end) const {
470 return Internal::ConstSliceBase<Internal::ContainerStorage,
471 const container>::template subSlice<Slice<const container>>(begin, end);
472 }
473};
474
483 template <typename T>
484 struct Slice<const T*> : public Internal::ConstSliceBase<Internal::PtrSliceStorage, const T*> {
497 Slice(const T* ptr, size_t begin, size_t end) :
498 Internal::ConstSliceBase<Internal::PtrSliceStorage, const T*>(ptr, begin, end) {
499 // TODO: use using in C++11
500 }
501
502 Slice<const T*> subSlice(size_t begin, size_t end) const {
503 return Internal::ConstSliceBase<Internal::PtrSliceStorage, const T*>::template subSlice<Slice<const T*>>(begin,
504 end);
505 }
506};
507
511 template <typename T>
512 struct Slice<T*> : public Internal::MutableSliceBase<Internal::PtrSliceStorage, T*> {
513 Slice(T* ptr, size_t begin, size_t end) : Internal::MutableSliceBase<Internal::PtrSliceStorage, T*>(ptr, begin, end) {
514 // TODO: use using in C++11
515 }
516
517 Slice<T*> subSlice(size_t begin, size_t end) {
518 return Internal::MutableSliceBase<Internal::PtrSliceStorage, T*>::template subSlice<Slice<T*>>(begin, end);
519 }
520
521 [[nodiscard]] Slice<const T*> subSlice(size_t begin, size_t end) const {
522 return this->to_const_base().template subSlice<Slice<const T*>>(begin, end);
523 }
524};
525
532 template <typename T>
533 inline Slice<T> makeSlice(T& cont, size_t begin, size_t end) {
534 return Slice<T>(cont, begin, end);
535}
536
540 template <typename T>
541 inline Slice<T*> makeSlice(T* ptr, size_t begin, size_t end) {
542 return Slice<T*>(ptr, begin, end);
543}
544
548 template <typename container>
549 inline Slice<container> makeSlice(container& cont) {
550 return Slice<container>(cont, 0, cont.size());
551}
552
557 template <typename container>
558 inline Slice<container> makeSliceFrom(container& cont, size_t begin) {
559 return Slice<container>(cont, begin, cont.size());
560}
561
565 template <typename container>
566 inline Slice<container> makeSliceUntil(container& cont, size_t end) {
567 return Slice<container>(cont, 0, end);
568}
569
573 template <typename T>
574 inline Slice<T*> makeSliceUntil(T* ptr, size_t end) {
575 return Slice<T*>(ptr, 0, end);
576}
577
578} // namespace Exiv2
579
580#endif /* EXIV2_INCLUDE_SLICE_HPP */
Exiv2::Internal
Helper structure for the Matroska tags lookup table.
Definition matroskavideo.hpp:39
Exiv2
Class CrwImage to access Canon CRW images. References: The Canon RAW (CRW) File Format by Phil Harv...
Definition asfvideo.hpp:15
Exiv2::makeSlice
Slice< T > makeSlice(T &cont, size_t begin, size_t end)
Return a new slice with the given bounds.
Definition slice.hpp:533
Exiv2::makeSliceUntil
Slice< container > makeSliceUntil(container &cont, size_t end)
Return a new slice spanning until end.
Definition slice.hpp:566
Exiv2::makeSliceFrom
Slice< container > makeSliceFrom(container &cont, size_t begin)
Return a new slice spanning from begin until the end of the container.
Definition slice.hpp:558
Exiv2::Internal::ConstSliceBase
This class provides the public-facing const-qualified methods of a slice.
Definition slice.hpp:82
Exiv2::Internal::ConstSliceBase::subSlice
slice_type subSlice(size_t begin, size_t end) const
Definition slice.hpp:133
Exiv2::Internal::ConstSliceBase::cend
const_iterator cend() const noexcept
Definition slice.hpp:120
Exiv2::Internal::ConstSliceBase::storage_
storage_type< data_type > storage_
Definition slice.hpp:153
Exiv2::Internal::ConstSliceBase::cbegin
const_iterator cbegin() const noexcept
Definition slice.hpp:113
Exiv2::Internal::ConstSliceBase::at
const value_type & at(size_t index) const
Definition slice.hpp:101
Exiv2::Internal::ConstSliceBase::ConstSliceBase
ConstSliceBase(data_type &data, size_t begin, size_t end)
Definition slice.hpp:92
Exiv2::Internal::ContainerStorage
Definition slice.hpp:254
Exiv2::Internal::ContainerStorage::unsafeGetIteratorAt
iterator unsafeGetIteratorAt(size_t index)
Definition slice.hpp:294
Exiv2::Internal::ContainerStorage::ContainerStorage
ContainerStorage(container &data, size_t, size_t end)
Definition slice.hpp:268
Exiv2::Internal::ContainerStorage::unsafeAt
const value_type & unsafeAt(size_t index) const
Definition slice.hpp:280
Exiv2::Internal::MutableSliceBase
Definition slice.hpp:162
Exiv2::Internal::MutableSliceBase::end
iterator end() noexcept
Definition slice.hpp:193
Exiv2::Internal::MutableSliceBase::begin
iterator begin() noexcept
Definition slice.hpp:186
Exiv2::Internal::MutableSliceBase::subSlice
slice_type subSlice(size_t begin, size_t end)
Definition slice.hpp:230
Exiv2::Internal::MutableSliceBase::at
value_type & at(size_t index)
Definition slice.hpp:174
Exiv2::Internal::PtrSliceStorage
Implementation of the storage concept for slices of C arrays.
Definition slice.hpp:322
Exiv2::Internal::PtrSliceStorage::PtrSliceStorage
PtrSliceStorage(storage_type ptr, size_t, size_t)
Definition slice.hpp:337
Exiv2::Internal::PtrSliceStorage::unsafeAt
value_type & unsafeAt(size_t index) noexcept
Definition slice.hpp:349
Exiv2::Internal::PtrSliceStorage::unsafeGetIteratorAt
iterator unsafeGetIteratorAt(size_t index) noexcept
Definition slice.hpp:363
Exiv2::Internal::SliceBase::size
size_t size() const noexcept
Definition slice.hpp:29
Exiv2::Internal::SliceBase::begin_
size_t begin_
Definition slice.hpp:51
Exiv2::Internal::SliceBase::rangeCheck
void rangeCheck(size_t index) const
Definition slice.hpp:41
Exiv2::Slice< const T * >::Slice
Slice(const T *ptr, size_t begin, size_t end)
Definition slice.hpp:497
Exiv2::Slice
Slice (= view) for STL containers.
Definition slice.hpp:421
Exiv2::Slice::subSlice
Slice subSlice(size_t begin, size_t end)
Definition slice.hpp:441
Exiv2::Slice::subSlice
Slice< const container > subSlice(size_t begin, size_t end) const
Definition slice.hpp:449