Exiv2
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>
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> {
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:
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>
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>
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> {
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) {
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> {
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 {
471  const container>::template subSlice<Slice<const container>>(begin, end);
472  }
473 };
474 
483 template <typename 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 {
504  end);
505  }
506 };
507 
511 template <typename 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 */
iterator unsafeGetIteratorAt(size_t index)
Definition: slice.hpp:294
Slice (= view) for STL containers.
Definition: slice.hpp:421
Slice< container > makeSliceUntil(container &cont, size_t end)
Return a new slice spanning until end.
Definition: slice.hpp:566
value_type & unsafeAt(size_t index) noexcept
Definition: slice.hpp:349
PtrSliceStorage(storage_type ptr, size_t, size_t)
Definition: slice.hpp:337
Slice(const T *ptr, size_t begin, size_t end)
Definition: slice.hpp:497
Definition: slice.hpp:484
const_iterator cend() const noexcept
Definition: slice.hpp:120
ConstSliceBase< storage_type, const data_type > to_const_base() const noexcept
Definition: slice.hpp:215
Specialization of slices for constant containers.
Definition: slice.hpp:458
size_t begin_
Definition: slice.hpp:51
Slice< const container > subSlice(size_t begin, size_t end) const
Definition: slice.hpp:449
storage_type< data_type > storage_
Definition: slice.hpp:153
ConstSliceBase(data_type &data, size_t begin, size_t end)
Definition: slice.hpp:92
slice_type subSlice(size_t begin, size_t end) const
Definition: slice.hpp:133
size_t size() const noexcept
Definition: slice.hpp:29
iterator end() noexcept
Definition: slice.hpp:193
iterator begin() noexcept
Definition: slice.hpp:186
Implementation of the storage concept for slices of C arrays.
Definition: slice.hpp:322
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
slice_type subSlice(size_t begin, size_t end)
Definition: slice.hpp:230
Definition: slice.hpp:162
Definition: slice.hpp:254
void rangeCheck(size_t index) const
Definition: slice.hpp:41
This class provides the public-facing const-qualified methods of a slice.
Definition: slice.hpp:82
Slice< T > makeSlice(T &cont, size_t begin, size_t end)
Return a new slice with the given bounds.
Definition: slice.hpp:533
const value_type & at(size_t index) const
Definition: slice.hpp:101
Slice subSlice(size_t begin, size_t end)
Definition: slice.hpp:441
const_iterator cbegin() const noexcept
Definition: slice.hpp:113
Class CrwImage to access Canon CRW images. References: The Canon RAW (CRW) File Format by Phil Harv...
Definition: asfvideo.hpp:15
value_type & at(size_t index)
Definition: slice.hpp:174
iterator unsafeGetIteratorAt(size_t index) noexcept
Definition: slice.hpp:363
Definition: slice.hpp:19
ContainerStorage(container &data, size_t, size_t end)
Definition: slice.hpp:268
const value_type & unsafeAt(size_t index) const
Definition: slice.hpp:280
Definition: slice.hpp:512