Exiv2
slice.hpp
Go to the documentation of this file.
1 // ********************************************************* -*- C++ -*-
2 /*
3  * Copyright (C) 2004-2018 Exiv2 maintainers
4  *
5  * This program is part of the Exiv2 distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
20  */
29 #ifndef EXIV2_INCLUDE_SLICE_HPP
30 #define EXIV2_INCLUDE_SLICE_HPP
31 
32 #include <cassert>
33 #include <cstddef>
34 #include <iterator>
35 #include <stdexcept>
36 
37 namespace Exiv2
38 {
39  namespace Internal
40  {
41  // TODO: remove these custom implementations once we have C++11
42  template <class T>
43  struct remove_const
44  {
45  typedef T type;
46  };
47 
48  template <class T>
49  struct remove_const<const T>
50  {
51  typedef T type;
52  };
53 
54  template <class T>
56  {
57  typedef T type;
58  };
59  template <class T>
60  struct remove_volatile<volatile T>
61  {
62  typedef T type;
63  };
64  template <class T>
65  struct remove_cv
66  {
67  typedef typename remove_const<typename remove_volatile<T>::type>::type type;
68  };
69 
70  template <class T>
72  {
73  typedef T type;
74  };
75 
76  template <class T>
77  struct remove_pointer<T*>
78  {
79  typedef T type;
80  };
81 
82  template <class T>
83  struct remove_pointer<T* const>
84  {
85  typedef T type;
86  };
87 
94  struct SliceBase
95  {
96  inline SliceBase(size_t begin, size_t end) : begin_(begin), end_(end)
97  {
98  if (begin >= end) {
99  throw std::out_of_range("Begin must be smaller than end");
100  }
101  }
102 
106  inline size_t size() const throw()
107  {
108  // cannot underflow, as we know that begin < end
109  return end_ - begin_;
110  }
111 
112  protected:
119  inline void rangeCheck(size_t index) const
120  {
121  if (index >= size()) {
122  throw std::out_of_range("Index outside of the slice");
123  }
124  }
125 
130  const size_t begin_, end_;
131  };
132 
159  template <template <typename data_type> class storage_type, typename data_type>
161  {
162  typedef typename storage_type<data_type>::iterator iterator;
163  typedef typename storage_type<data_type>::const_iterator const_iterator;
164  typedef typename storage_type<data_type>::value_type value_type;
165 
171  ConstSliceBase(data_type& data, size_t begin, size_t end)
172  : SliceBase(begin, end), storage_(data, begin, end)
173  {
174  }
175 
182  const value_type& at(size_t index) const
183  {
184  rangeCheck(index);
185  // we know: begin_ < end <= size() <= SIZE_T_MAX
186  // and: index < end - begin
187  // thus: index + begin < end <= SIZE_T_MAX
188  // => no overflow is possible
189  return storage_.unsafeAt(begin_ + index);
190  }
191 
195  const_iterator cbegin() const throw()
196  {
197  return storage_.unsafeGetIteratorAt(begin_);
198  }
199 
203  const_iterator cend() const throw()
204  {
205  return storage_.unsafeGetIteratorAt(end_);
206  }
207 
216  template <typename slice_type>
217  slice_type subSlice(size_t begin, size_t end) const
218  {
219  this->rangeCheck(begin);
220  // end == size() is a legal value, since end is the first
221  // element beyond the slice
222  // end == 0 is not a legal value (subtraction will underflow and
223  // throw an exception)
224  this->rangeCheck(end - 1);
225  // additions are safe, begin and end are smaller than size()
226  const size_t new_begin = begin + this->begin_;
227  const size_t new_end = this->begin_ + end;
228  if (new_end > this->end_) {
229  throw std::out_of_range("Invalid input parameters to slice");
230  }
231  return slice_type(storage_.data_, new_begin, new_end);
232  }
233 
234  protected:
238  storage_type<data_type> storage_;
239  };
240 
246  template <template <typename> class storage_type, typename data_type>
247  struct MutableSliceBase : public ConstSliceBase<storage_type, data_type>
248  {
249  typedef typename ConstSliceBase<storage_type, data_type>::iterator iterator;
250  typedef typename ConstSliceBase<storage_type, data_type>::const_iterator const_iterator;
251  typedef typename ConstSliceBase<storage_type, data_type>::value_type value_type;
252 
258  MutableSliceBase(data_type& data, size_t begin, size_t end)
259  : ConstSliceBase<storage_type, data_type>(data, begin, end)
260  {
261  }
262 
269  value_type& at(size_t index)
270  {
271  this->rangeCheck(index);
272  return this->storage_.unsafeAt(this->begin_ + index);
273  }
274 
275  const value_type& at(size_t index) const
276  {
277  // TODO: use using base_type::at once we have C++11
278  return base_type::at(index);
279  }
280 
284  iterator begin() throw()
285  {
286  return this->storage_.unsafeGetIteratorAt(this->begin_);
287  }
288 
292  iterator end() throw()
293  {
294  return this->storage_.unsafeGetIteratorAt(this->end_);
295  }
296 
297  protected:
316  {
317  return ConstSliceBase<storage_type, const data_type>(this->storage_.data_, this->begin_, this->end_);
318  }
319 
320  typedef ConstSliceBase<storage_type, data_type> base_type;
321 
330  template <typename slice_type>
331  slice_type subSlice(size_t begin, size_t end)
332  {
333  this->rangeCheck(begin);
334  // end == size() is a legal value, since end is the first
335  // element beyond the slice
336  // end == 0 is not a legal value (subtraction will underflow and
337  // throw an exception)
338  this->rangeCheck(end - 1);
339 
340  // additions are safe, begin & end are smaller than size()
341  const size_t new_begin = begin + this->begin_;
342  const size_t new_end = this->begin_ + end;
343  if (new_end > this->end_) {
344  throw std::out_of_range("Invalid input parameters to slice");
345  }
346  return slice_type(this->storage_.data_, new_begin, new_end);
347  }
348  };
349 
355  template <typename container>
357  {
358  typedef typename container::iterator iterator;
359 
360  typedef typename container::const_iterator const_iterator;
361 
362  typedef typename Internal::remove_cv<typename container::value_type>::type value_type;
363 
368  ContainerStorage(container& data, size_t /* begin*/, size_t end) : data_(data)
369  {
370  if (end > data.size()) {
371  throw std::out_of_range("Invalid input parameters to slice");
372  }
373  }
374 
381  const value_type& unsafeAt(size_t index) const
382  {
383  return data_.at(index);
384  }
385 
386  value_type& unsafeAt(size_t index)
387  {
388  return data_.at(index);
389  }
390 
397  iterator unsafeGetIteratorAt(size_t index)
398  {
399  // we are screwed if the container got changed => try to catch it
400  assert(index <= data_.size());
401 
402  iterator it = data_.begin();
403  std::advance(it, index);
404  return it;
405  }
406 
407  const_iterator unsafeGetIteratorAt(size_t index) const
408  {
409  assert(index <= data_.size());
410 
411  const_iterator it = data_.begin();
412  std::advance(it, index);
413  return it;
414  }
415 
416  container& data_;
417  };
418 
426  template <typename storage_type>
428  {
429  typedef typename remove_cv<typename remove_pointer<storage_type>::type>::type value_type;
430  typedef value_type* iterator;
431  typedef const value_type* const_iterator;
432 
439  PtrSliceStorage(storage_type ptr, size_t /*begin*/, size_t /*end*/) : data_(ptr)
440  {
441  // TODO: change this to nullptr once we use C++11
442  if (ptr == NULL) {
443  throw std::invalid_argument("Null pointer passed to slice constructor");
444  }
445  }
446 
453  value_type& unsafeAt(size_t index) throw()
454  {
455  return data_[index];
456  }
457 
458  const value_type& unsafeAt(size_t index) const throw()
459  {
460  return data_[index];
461  }
462 
469  iterator unsafeGetIteratorAt(size_t index) throw()
470  {
471  return data_ + index;
472  }
473 
474  const_iterator unsafeGetIteratorAt(size_t index) const throw()
475  {
476  return data_ + index;
477  }
478 
479  storage_type data_;
480  };
481 
482  } // namespace Internal
483 
528  template <typename container>
529  struct Slice : public Internal::MutableSliceBase<Internal::ContainerStorage, container>
530  {
531  typedef typename container::iterator iterator;
532 
533  typedef typename container::const_iterator const_iterator;
534 
535  typedef typename Internal::remove_cv<typename container::value_type>::type value_type;
536 
553  Slice(container& cont, size_t begin, size_t end)
554  : Internal::MutableSliceBase<Internal::ContainerStorage, container>(cont, begin, end)
555  {
556  }
557 
567  Slice subSlice(size_t begin, size_t end)
568  {
570  end);
571  }
572 
577  Slice<const container> subSlice(size_t begin, size_t end) const
578  {
579  return this->to_const_base().template subSlice<Slice<const container> >(begin, end);
580  }
581  };
582 
586  template <typename container>
587  struct Slice<const container> : public Internal::ConstSliceBase<Internal::ContainerStorage, const container>
588  {
589  typedef typename container::iterator iterator;
590 
591  typedef typename container::const_iterator const_iterator;
592 
593  typedef typename Internal::remove_cv<typename container::value_type>::type value_type;
594 
595  Slice(const container& cont, size_t begin, size_t end)
597  {
598  }
599 
600  Slice subSlice(size_t begin, size_t end) const
601  {
603  const container>::template subSlice<Slice<const container> >(begin, end);
604  }
605  };
606 
615  template <typename T>
617  {
630  Slice(const T* ptr, size_t begin, size_t end)
631  : Internal::ConstSliceBase<Internal::PtrSliceStorage, const T*>(ptr, begin, end)
632  {
633  // TODO: use using in C++11
634  }
635 
636  Slice<const T*> subSlice(size_t begin, size_t end) const
637  {
639  begin, end);
640  }
641  };
642 
646  template <typename T>
648  {
649  Slice(T* ptr, size_t begin, size_t end)
651  {
652  // TODO: use using in C++11
653  }
654 
655  Slice<T*> subSlice(size_t begin, size_t end)
656  {
657  return Internal::MutableSliceBase<Internal::PtrSliceStorage, T*>::template subSlice<Slice<T*> >(begin, end);
658  }
659 
660  Slice<const T*> subSlice(size_t begin, size_t end) const
661  {
662  return this->to_const_base().template subSlice<Slice<const T*> >(begin, end);
663  }
664  };
665 
672  template <typename T>
673  inline Slice<T> makeSlice(T& cont, size_t begin, size_t end)
674  {
675  return Slice<T>(cont, begin, end);
676  }
677 
681  template <typename T>
682  inline Slice<T*> makeSlice(T* ptr, size_t begin, size_t end)
683  {
684  return Slice<T*>(ptr, begin, end);
685  }
686 
690  template <typename container>
691  inline Slice<container> makeSlice(container& cont)
692  {
693  return Slice<container>(cont, 0, cont.size());
694  }
695 
700  template <typename container>
701  inline Slice<container> makeSliceFrom(container& cont, size_t begin)
702  {
703  return Slice<container>(cont, begin, cont.size());
704  }
705 
709  template <typename container>
710  inline Slice<container> makeSliceUntil(container& cont, size_t end)
711  {
712  return Slice<container>(cont, 0, end);
713  }
714 
718  template <typename T>
719  inline Slice<T*> makeSliceUntil(T* ptr, size_t end)
720  {
721  return Slice<T*>(ptr, 0, end);
722  }
723 
724 } // namespace Exiv2
725 
726 #endif /* EXIV2_INCLUDE_SLICE_HPP */
iterator unsafeGetIteratorAt(size_t index)
Definition: slice.hpp:397
value_type & unsafeAt(size_t index)
Definition: slice.hpp:453
Slice (= view) for STL containers.
Definition: slice.hpp:529
Slice< container > makeSliceUntil(container &cont, size_t end)
Return a new slice spanning until end.
Definition: slice.hpp:710
PtrSliceStorage(storage_type ptr, size_t, size_t)
Definition: slice.hpp:439
Slice(const T *ptr, size_t begin, size_t end)
Definition: slice.hpp:630
Definition: slice.hpp:616
Specialization of slices for constant containers.
Definition: slice.hpp:587
Definition: slice.hpp:55
Definition: slice.hpp:71
storage_type< data_type > storage_
Definition: slice.hpp:238
ConstSliceBase(data_type &data, size_t begin, size_t end)
Definition: slice.hpp:171
const value_type & at(size_t index) const
Definition: slice.hpp:182
iterator unsafeGetIteratorAt(size_t index)
Definition: slice.hpp:469
Implementation of the storage concept for slices of C arrays.
Definition: slice.hpp:427
ConstSliceBase< storage_type, const data_type > to_const_base() const
Definition: slice.hpp:315
iterator begin()
Definition: slice.hpp:284
Slice< container > makeSliceFrom(container &cont, size_t begin)
Return a new slice spanning from begin until the end of the container.
Definition: slice.hpp:701
slice_type subSlice(size_t begin, size_t end)
Definition: slice.hpp:331
Definition: slice.hpp:247
Slice< const container > subSlice(size_t begin, size_t end) const
Definition: slice.hpp:577
Definition: slice.hpp:356
size_t size() const
Definition: slice.hpp:106
const_iterator cbegin() const
Definition: slice.hpp:195
void rangeCheck(size_t index) const
Definition: slice.hpp:119
const value_type & unsafeAt(size_t index) const
Definition: slice.hpp:381
This class provides the public-facing const-qualified methods of a slice.
Definition: slice.hpp:160
Slice< T > makeSlice(T &cont, size_t begin, size_t end)
Return a new slice with the given bounds.
Definition: slice.hpp:673
const size_t begin_
Definition: slice.hpp:130
slice_type subSlice(size_t begin, size_t end) const
Definition: slice.hpp:217
Slice subSlice(size_t begin, size_t end)
Definition: slice.hpp:567
Definition: slice.hpp:43
Provides classes and functions to encode and decode Exif and Iptc data. The libexiv2 API consists of ...
Definition: asfvideo.hpp:36
value_type & at(size_t index)
Definition: slice.hpp:269
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:553
iterator end()
Definition: slice.hpp:292
Definition: slice.hpp:94
ContainerStorage(container &data, size_t, size_t end)
Definition: slice.hpp:368
const_iterator cend() const
Definition: slice.hpp:203
Definition: slice.hpp:647
MutableSliceBase(data_type &data, size_t begin, size_t end)
Definition: slice.hpp:258
Definition: slice.hpp:65