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
37namespace Exiv2
38{
39 namespace Internal
40 {
41 // TODO: remove these custom implementations once we have C++11
42 template <class T>
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
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
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 */
Provides classes and functions to encode and decode Exif and Iptc data. The libexiv2 API consists of ...
Definition: asfvideo.hpp:36
Slice< T > makeSlice(T &cont, size_t begin, size_t end)
Return a new slice with the given bounds.
Definition: slice.hpp:673
Slice< container > makeSliceUntil(container &cont, size_t end)
Return a new slice spanning until end.
Definition: slice.hpp:710
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
This class provides the public-facing const-qualified methods of a slice.
Definition: slice.hpp:161
slice_type subSlice(size_t begin, size_t end) const
Definition: slice.hpp:217
const_iterator cend() const
Definition: slice.hpp:203
storage_type< data_type > storage_
Definition: slice.hpp:238
const value_type & at(size_t index) const
Definition: slice.hpp:182
const_iterator cbegin() const
Definition: slice.hpp:195
ConstSliceBase(data_type &data, size_t begin, size_t end)
Definition: slice.hpp:171
Definition: slice.hpp:357
iterator unsafeGetIteratorAt(size_t index)
Definition: slice.hpp:397
ContainerStorage(container &data, size_t, size_t end)
Definition: slice.hpp:368
const value_type & unsafeAt(size_t index) const
Definition: slice.hpp:381
Definition: slice.hpp:248
iterator begin()
Definition: slice.hpp:284
iterator end()
Definition: slice.hpp:292
MutableSliceBase(data_type &data, size_t begin, size_t end)
Definition: slice.hpp:258
slice_type subSlice(size_t begin, size_t end)
Definition: slice.hpp:331
ConstSliceBase< storage_type, const data_type > to_const_base() const
Definition: slice.hpp:315
value_type & at(size_t index)
Definition: slice.hpp:269
Implementation of the storage concept for slices of C arrays.
Definition: slice.hpp:428
value_type & unsafeAt(size_t index)
Definition: slice.hpp:453
PtrSliceStorage(storage_type ptr, size_t, size_t)
Definition: slice.hpp:439
iterator unsafeGetIteratorAt(size_t index)
Definition: slice.hpp:469
Definition: slice.hpp:95
size_t size() const
Definition: slice.hpp:106
const size_t begin_
Definition: slice.hpp:130
void rangeCheck(size_t index) const
Definition: slice.hpp:119
Definition: slice.hpp:44
Definition: slice.hpp:66
Definition: slice.hpp:72
Definition: slice.hpp:56
Definition: slice.hpp:648
Definition: slice.hpp:617
Slice(const T *ptr, size_t begin, size_t end)
Definition: slice.hpp:630
Specialization of slices for constant containers.
Definition: slice.hpp:588
Slice (= view) for STL containers.
Definition: slice.hpp:530
Slice subSlice(size_t begin, size_t end)
Definition: slice.hpp:567
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
Slice< const container > subSlice(size_t begin, size_t end) const
Definition: slice.hpp:577