Exiv2
slice.hpp
1 // ***************************************************************** -*- C++ -*-
2 /*
3  * Copyright (C) 2004-2021 Exiv2 authors
4  * This program is part of the Exiv2 distribution.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program 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
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
19  */
20 
21 #ifndef EXIV2_INCLUDE_SLICE_HPP
22 #define EXIV2_INCLUDE_SLICE_HPP
23 
24 #include <cassert>
25 #include <cstddef>
26 #include <iterator>
27 #include <stdexcept>
28 
29 namespace Exiv2
30 {
31  namespace Internal
32  {
33  // TODO: remove these custom implementations once we have C++11
34  template <class T>
35  struct remove_const
36  {
37  typedef T type;
38  };
39 
40  template <class T>
41  struct remove_const<const T>
42  {
43  typedef T type;
44  };
45 
46  template <class T>
48  {
49  typedef T type;
50  };
51  template <class T>
52  struct remove_volatile<volatile T>
53  {
54  typedef T type;
55  };
56  template <class T>
57  struct remove_cv
58  {
59  typedef typename remove_const<typename remove_volatile<T>::type>::type type;
60  };
61 
62  template <class T>
64  {
65  typedef T type;
66  };
67 
68  template <class T>
69  struct remove_pointer<T*>
70  {
71  typedef T type;
72  };
73 
74  template <class T>
75  struct remove_pointer<T* const>
76  {
77  typedef T type;
78  };
79 
86  struct SliceBase
87  {
88  inline SliceBase(size_t begin, size_t end) : begin_(begin), end_(end)
89  {
90  if (begin >= end) {
91  throw std::out_of_range("Begin must be smaller than end");
92  }
93  }
94 
98  inline size_t size() const throw()
99  {
100  // cannot underflow, as we know that begin < end
101  return end_ - begin_;
102  }
103 
104  protected:
111  inline void rangeCheck(size_t index) const
112  {
113  if (index >= size()) {
114  throw std::out_of_range("Index outside of the slice");
115  }
116  }
117 
122  const size_t begin_, end_;
123  };
124 
151  template <template <typename data_type> class storage_type, typename data_type>
153  {
154  typedef typename storage_type<data_type>::iterator iterator;
155  typedef typename storage_type<data_type>::const_iterator const_iterator;
156  typedef typename storage_type<data_type>::value_type value_type;
157 
163  ConstSliceBase(data_type& data, size_t begin, size_t end)
164  : SliceBase(begin, end), storage_(data, begin, end)
165  {
166  }
167 
174  const value_type& at(size_t index) const
175  {
176  rangeCheck(index);
177  // we know: begin_ < end <= size() <= SIZE_T_MAX
178  // and: index < end - begin
179  // thus: index + begin < end <= SIZE_T_MAX
180  // => no overflow is possible
181  return storage_.unsafeAt(begin_ + index);
182  }
183 
187  const_iterator cbegin() const throw()
188  {
189  return storage_.unsafeGetIteratorAt(begin_);
190  }
191 
195  const_iterator cend() const throw()
196  {
197  return storage_.unsafeGetIteratorAt(end_);
198  }
199 
208  template <typename slice_type>
209  slice_type subSlice(size_t begin, size_t end) const
210  {
211  this->rangeCheck(begin);
212  // end == size() is a legal value, since end is the first
213  // element beyond the slice
214  // end == 0 is not a legal value (subtraction will underflow and
215  // throw an exception)
216  this->rangeCheck(end - 1);
217  // additions are safe, begin and end are smaller than size()
218  const size_t new_begin = begin + this->begin_;
219  const size_t new_end = this->begin_ + end;
220  if (new_end > this->end_) {
221  throw std::out_of_range("Invalid input parameters to slice");
222  }
223  return slice_type(storage_.data_, new_begin, new_end);
224  }
225 
226  protected:
230  storage_type<data_type> storage_;
231  };
232 
238  template <template <typename> class storage_type, typename data_type>
239  struct MutableSliceBase : public ConstSliceBase<storage_type, data_type>
240  {
241  typedef typename ConstSliceBase<storage_type, data_type>::iterator iterator;
242  typedef typename ConstSliceBase<storage_type, data_type>::const_iterator const_iterator;
243  typedef typename ConstSliceBase<storage_type, data_type>::value_type value_type;
244 
250  MutableSliceBase(data_type& data, size_t begin, size_t end)
251  : ConstSliceBase<storage_type, data_type>(data, begin, end)
252  {
253  }
254 
261  value_type& at(size_t index)
262  {
263  this->rangeCheck(index);
264  return this->storage_.unsafeAt(this->begin_ + index);
265  }
266 
267  const value_type& at(size_t index) const
268  {
269  // TODO: use using base_type::at once we have C++11
270  return base_type::at(index);
271  }
272 
276  iterator begin() throw()
277  {
278  return this->storage_.unsafeGetIteratorAt(this->begin_);
279  }
280 
284  iterator end() throw()
285  {
286  return this->storage_.unsafeGetIteratorAt(this->end_);
287  }
288 
289  protected:
308  {
309  return ConstSliceBase<storage_type, const data_type>(this->storage_.data_, this->begin_, this->end_);
310  }
311 
312  typedef ConstSliceBase<storage_type, data_type> base_type;
313 
322  template <typename slice_type>
323  slice_type subSlice(size_t begin, size_t end)
324  {
325  this->rangeCheck(begin);
326  // end == size() is a legal value, since end is the first
327  // element beyond the slice
328  // end == 0 is not a legal value (subtraction will underflow and
329  // throw an exception)
330  this->rangeCheck(end - 1);
331 
332  // additions are safe, begin & end are smaller than size()
333  const size_t new_begin = begin + this->begin_;
334  const size_t new_end = this->begin_ + end;
335  if (new_end > this->end_) {
336  throw std::out_of_range("Invalid input parameters to slice");
337  }
338  return slice_type(this->storage_.data_, new_begin, new_end);
339  }
340  };
341 
347  template <typename container>
349  {
350  typedef typename container::iterator iterator;
351 
352  typedef typename container::const_iterator const_iterator;
353 
354  typedef typename Internal::remove_cv<typename container::value_type>::type value_type;
355 
360  ContainerStorage(container& data, size_t /* begin*/, size_t end) : data_(data)
361  {
362  if (end > data.size()) {
363  throw std::out_of_range("Invalid input parameters to slice");
364  }
365  }
366 
373  const value_type& unsafeAt(size_t index) const
374  {
375  return data_.at(index);
376  }
377 
378  value_type& unsafeAt(size_t index)
379  {
380  return data_.at(index);
381  }
382 
389  iterator unsafeGetIteratorAt(size_t index)
390  {
391  // we are screwed if the container got changed => try to catch it
392  assert(index <= data_.size());
393 
394  iterator it = data_.begin();
395  std::advance(it, index);
396  return it;
397  }
398 
399  const_iterator unsafeGetIteratorAt(size_t index) const
400  {
401  assert(index <= data_.size());
402 
403  const_iterator it = data_.begin();
404  std::advance(it, index);
405  return it;
406  }
407 
408  container& data_;
409  };
410 
418  template <typename storage_type>
420  {
421  typedef typename remove_cv<typename remove_pointer<storage_type>::type>::type value_type;
422  typedef value_type* iterator;
423  typedef const value_type* const_iterator;
424 
431  PtrSliceStorage(storage_type ptr, size_t /*begin*/, size_t /*end*/) : data_(ptr)
432  {
433  // TODO: change this to nullptr once we use C++11
434  if (ptr == NULL) {
435  throw std::invalid_argument("Null pointer passed to slice constructor");
436  }
437  }
438 
445  value_type& unsafeAt(size_t index) throw()
446  {
447  return data_[index];
448  }
449 
450  const value_type& unsafeAt(size_t index) const throw()
451  {
452  return data_[index];
453  }
454 
461  iterator unsafeGetIteratorAt(size_t index) throw()
462  {
463  return data_ + index;
464  }
465 
466  const_iterator unsafeGetIteratorAt(size_t index) const throw()
467  {
468  return data_ + index;
469  }
470 
471  storage_type data_;
472  };
473 
474  } // namespace Internal
475 
520  template <typename container>
521  struct Slice : public Internal::MutableSliceBase<Internal::ContainerStorage, container>
522  {
523  typedef typename container::iterator iterator;
524 
525  typedef typename container::const_iterator const_iterator;
526 
527  typedef typename Internal::remove_cv<typename container::value_type>::type value_type;
528 
545  Slice(container& cont, size_t begin, size_t end)
546  : Internal::MutableSliceBase<Internal::ContainerStorage, container>(cont, begin, end)
547  {
548  }
549 
559  Slice subSlice(size_t begin, size_t end)
560  {
562  end);
563  }
564 
569  Slice<const container> subSlice(size_t begin, size_t end) const
570  {
571  return this->to_const_base().template subSlice<Slice<const container> >(begin, end);
572  }
573  };
574 
578  template <typename container>
579  struct Slice<const container> : public Internal::ConstSliceBase<Internal::ContainerStorage, const container>
580  {
581  typedef typename container::iterator iterator;
582 
583  typedef typename container::const_iterator const_iterator;
584 
585  typedef typename Internal::remove_cv<typename container::value_type>::type value_type;
586 
587  Slice(const container& cont, size_t begin, size_t end)
589  {
590  }
591 
592  Slice subSlice(size_t begin, size_t end) const
593  {
595  const container>::template subSlice<Slice<const container> >(begin, end);
596  }
597  };
598 
607  template <typename T>
609  {
622  Slice(const T* ptr, size_t begin, size_t end)
623  : Internal::ConstSliceBase<Internal::PtrSliceStorage, const T*>(ptr, begin, end)
624  {
625  // TODO: use using in C++11
626  }
627 
628  Slice<const T*> subSlice(size_t begin, size_t end) const
629  {
631  begin, end);
632  }
633  };
634 
638  template <typename T>
640  {
641  Slice(T* ptr, size_t begin, size_t end)
643  {
644  // TODO: use using in C++11
645  }
646 
647  Slice<T*> subSlice(size_t begin, size_t end)
648  {
649  return Internal::MutableSliceBase<Internal::PtrSliceStorage, T*>::template subSlice<Slice<T*> >(begin, end);
650  }
651 
652  Slice<const T*> subSlice(size_t begin, size_t end) const
653  {
654  return this->to_const_base().template subSlice<Slice<const T*> >(begin, end);
655  }
656  };
657 
664  template <typename T>
665  inline Slice<T> makeSlice(T& cont, size_t begin, size_t end)
666  {
667  return Slice<T>(cont, begin, end);
668  }
669 
673  template <typename T>
674  inline Slice<T*> makeSlice(T* ptr, size_t begin, size_t end)
675  {
676  return Slice<T*>(ptr, begin, end);
677  }
678 
682  template <typename container>
683  inline Slice<container> makeSlice(container& cont)
684  {
685  return Slice<container>(cont, 0, cont.size());
686  }
687 
692  template <typename container>
693  inline Slice<container> makeSliceFrom(container& cont, size_t begin)
694  {
695  return Slice<container>(cont, begin, cont.size());
696  }
697 
701  template <typename container>
702  inline Slice<container> makeSliceUntil(container& cont, size_t end)
703  {
704  return Slice<container>(cont, 0, end);
705  }
706 
710  template <typename T>
711  inline Slice<T*> makeSliceUntil(T* ptr, size_t end)
712  {
713  return Slice<T*>(ptr, 0, end);
714  }
715 
716 } // namespace Exiv2
717 
718 #endif /* EXIV2_INCLUDE_SLICE_HPP */
Provides classes and functions to encode and decode Exif and Iptc data. The libexiv2 API consists of ...
Definition: asfvideo.hpp:36
Slice< container > makeSliceFrom(container &cont, size_t begin)
Return a new slice spanning from begin until the end of the container.
Definition: slice.hpp:693
Slice< T > makeSlice(T &cont, size_t begin, size_t end)
Return a new slice with the given bounds.
Definition: slice.hpp:665
Slice< container > makeSliceUntil(container &cont, size_t end)
Return a new slice spanning until end.
Definition: slice.hpp:702
This class provides the public-facing const-qualified methods of a slice.
Definition: slice.hpp:153
slice_type subSlice(size_t begin, size_t end) const
Definition: slice.hpp:209
const_iterator cend() const
Definition: slice.hpp:195
storage_type< data_type > storage_
Definition: slice.hpp:230
const value_type & at(size_t index) const
Definition: slice.hpp:174
const_iterator cbegin() const
Definition: slice.hpp:187
ConstSliceBase(data_type &data, size_t begin, size_t end)
Definition: slice.hpp:163
Definition: slice.hpp:349
iterator unsafeGetIteratorAt(size_t index)
Definition: slice.hpp:389
const value_type & unsafeAt(size_t index) const
Definition: slice.hpp:373
ContainerStorage(container &data, size_t, size_t end)
Definition: slice.hpp:360
Definition: slice.hpp:240
iterator begin()
Definition: slice.hpp:276
iterator end()
Definition: slice.hpp:284
MutableSliceBase(data_type &data, size_t begin, size_t end)
Definition: slice.hpp:250
ConstSliceBase< storage_type, const data_type > to_const_base() const
Definition: slice.hpp:307
value_type & at(size_t index)
Definition: slice.hpp:261
slice_type subSlice(size_t begin, size_t end)
Definition: slice.hpp:323
Implementation of the storage concept for slices of C arrays.
Definition: slice.hpp:420
PtrSliceStorage(storage_type ptr, size_t, size_t)
Definition: slice.hpp:431
value_type & unsafeAt(size_t index)
Definition: slice.hpp:445
iterator unsafeGetIteratorAt(size_t index)
Definition: slice.hpp:461
Definition: slice.hpp:87
size_t size() const
Definition: slice.hpp:98
const size_t begin_
Definition: slice.hpp:122
void rangeCheck(size_t index) const
Definition: slice.hpp:111
Definition: slice.hpp:36
Definition: slice.hpp:58
Definition: slice.hpp:64
Definition: slice.hpp:48
Definition: slice.hpp:640
Definition: slice.hpp:609
Slice(const T *ptr, size_t begin, size_t end)
Definition: slice.hpp:622
Specialization of slices for constant containers.
Definition: slice.hpp:580
Slice (= view) for STL containers.
Definition: slice.hpp:522
Slice subSlice(size_t begin, size_t end)
Definition: slice.hpp:559
Slice< const container > subSlice(size_t begin, size_t end) const
Definition: slice.hpp:569
Slice(container &cont, size_t begin, size_t end)
Construct a slice of the container cont starting at begin (including) and ending before end.
Definition: slice.hpp:545