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
29namespace Exiv2
30{
31 namespace Internal
32 {
33 // TODO: remove these custom implementations once we have C++11
34 template <class T>
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
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
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< 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
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
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
ContainerStorage(container &data, size_t, size_t end)
Definition: slice.hpp:360
const value_type & unsafeAt(size_t index) const
Definition: slice.hpp:373
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
slice_type subSlice(size_t begin, size_t end)
Definition: slice.hpp:323
ConstSliceBase< storage_type, const data_type > to_const_base() const
Definition: slice.hpp:307
value_type & at(size_t index)
Definition: slice.hpp:261
Implementation of the storage concept for slices of C arrays.
Definition: slice.hpp:420
value_type & unsafeAt(size_t index)
Definition: slice.hpp:445
PtrSliceStorage(storage_type ptr, size_t, size_t)
Definition: slice.hpp:431
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(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
Slice< const container > subSlice(size_t begin, size_t end) const
Definition: slice.hpp:569