Blame include/exiv2/slice.hpp

Packit Service 21b5d1
// ********************************************************* -*- C++ -*-
Packit Service 21b5d1
/*
Packit Service 21b5d1
 * Copyright (C) 2004-2018 Exiv2 maintainers
Packit Service 21b5d1
 *
Packit Service 21b5d1
 * This program is part of the Exiv2 distribution.
Packit Service 21b5d1
 *
Packit Service 21b5d1
 * This program is free software; you can redistribute it and/or
Packit Service 21b5d1
 * modify it under the terms of the GNU General Public License
Packit Service 21b5d1
 * as published by the Free Software Foundation; either version 2
Packit Service 21b5d1
 * of the License, or (at your option) any later version.
Packit Service 21b5d1
 *
Packit Service 21b5d1
 * This program is distributed in the hope that it will be useful,
Packit Service 21b5d1
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 21b5d1
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 21b5d1
 * GNU General Public License for more details.
Packit Service 21b5d1
 *
Packit Service 21b5d1
 * You should have received a copy of the GNU General Public License
Packit Service 21b5d1
 * along with this program; if not, write to the Free Software
Packit Service 21b5d1
 * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
Packit Service 21b5d1
 */
Packit Service 21b5d1
/*!
Packit Service 21b5d1
  @file    slice.hpp
Packit Service 21b5d1
  @brief   Simple implementation of slices (=views) for STL containers and C-arrays
Packit Service 21b5d1
  @author  Dan Čermák (D4N)
Packit Service 21b5d1
           dan.cermak@cgc-instruments.com
Packit Service 21b5d1
  @date    30-March-18, D4N: created
Packit Service 21b5d1
 */
Packit Service 21b5d1
Packit Service 21b5d1
#ifndef EXIV2_INCLUDE_SLICE_HPP
Packit Service 21b5d1
#define EXIV2_INCLUDE_SLICE_HPP
Packit Service 21b5d1
Packit Service 21b5d1
#include <cassert>
Packit Service 21b5d1
#include <cstddef>
Packit Service 21b5d1
#include <iterator>
Packit Service 21b5d1
#include <stdexcept>
Packit Service 21b5d1
Packit Service 21b5d1
namespace Exiv2
Packit Service 21b5d1
{
Packit Service 21b5d1
    namespace Internal
Packit Service 21b5d1
    {
Packit Service 21b5d1
        // TODO: remove these custom implementations once we have C++11
Packit Service 21b5d1
        template <class T>
Packit Service 21b5d1
        struct remove_const
Packit Service 21b5d1
        {
Packit Service 21b5d1
            typedef T type;
Packit Service 21b5d1
        };
Packit Service 21b5d1
Packit Service 21b5d1
        template <class T>
Packit Service 21b5d1
        struct remove_const<const T>
Packit Service 21b5d1
        {
Packit Service 21b5d1
            typedef T type;
Packit Service 21b5d1
        };
Packit Service 21b5d1
Packit Service 21b5d1
        template <class T>
Packit Service 21b5d1
        struct remove_volatile
Packit Service 21b5d1
        {
Packit Service 21b5d1
            typedef T type;
Packit Service 21b5d1
        };
Packit Service 21b5d1
        template <class T>
Packit Service 21b5d1
        struct remove_volatile<volatile T>
Packit Service 21b5d1
        {
Packit Service 21b5d1
            typedef T type;
Packit Service 21b5d1
        };
Packit Service 21b5d1
        template <class T>
Packit Service 21b5d1
        struct remove_cv
Packit Service 21b5d1
        {
Packit Service 21b5d1
            typedef typename remove_const<typename remove_volatile<T>::type>::type type;
Packit Service 21b5d1
        };
Packit Service 21b5d1
Packit Service 21b5d1
        template <class T>
Packit Service 21b5d1
        struct remove_pointer
Packit Service 21b5d1
        {
Packit Service 21b5d1
            typedef T type;
Packit Service 21b5d1
        };
Packit Service 21b5d1
Packit Service 21b5d1
        template <class T>
Packit Service 21b5d1
        struct remove_pointer<T*>
Packit Service 21b5d1
        {
Packit Service 21b5d1
            typedef T type;
Packit Service 21b5d1
        };
Packit Service 21b5d1
Packit Service 21b5d1
        template <class T>
Packit Service 21b5d1
        struct remove_pointer<T* const>
Packit Service 21b5d1
        {
Packit Service 21b5d1
            typedef T type;
Packit Service 21b5d1
        };
Packit Service 21b5d1
Packit Service 21b5d1
        /*!
Packit Service 21b5d1
         * Common base class of all slice implementations.
Packit Service 21b5d1
         *
Packit Service 21b5d1
         * Implements only the most basic functions, which do not require any
Packit Service 21b5d1
         * knowledge about the stored data.
Packit Service 21b5d1
         */
Packit Service 21b5d1
        struct SliceBase
Packit Service 21b5d1
        {
Packit Service 21b5d1
            inline SliceBase(size_t begin, size_t end) : begin_(begin), end_(end)
Packit Service 21b5d1
            {
Packit Service 21b5d1
                if (begin >= end) {
Packit Service 21b5d1
                    throw std::out_of_range("Begin must be smaller than end");
Packit Service 21b5d1
                }
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
            /*!
Packit Service 21b5d1
             * Return the number of elements in the slice.
Packit Service 21b5d1
             */
Packit Service 21b5d1
            inline size_t size() const throw()
Packit Service 21b5d1
            {
Packit Service 21b5d1
                // cannot underflow, as we know that begin < end
Packit Service 21b5d1
                return end_ - begin_;
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
        protected:
Packit Service 21b5d1
            /*!
Packit Service 21b5d1
             * Throw an exception when index is too large.
Packit Service 21b5d1
             *
Packit Service 21b5d1
             * @throw std::out_of_range when `index` will access an element
Packit Service 21b5d1
             * outside of the slice
Packit Service 21b5d1
             */
Packit Service 21b5d1
            inline void rangeCheck(size_t index) const
Packit Service 21b5d1
            {
Packit Service 21b5d1
                if (index >= size()) {
Packit Service 21b5d1
                    throw std::out_of_range("Index outside of the slice");
Packit Service 21b5d1
                }
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
            /*!
Packit Service 21b5d1
             * lower and upper bounds of the slice with respect to the
Packit Service 21b5d1
             * container/array stored in storage_
Packit Service 21b5d1
             */
Packit Service 21b5d1
            const size_t begin_, end_;
Packit Service 21b5d1
        };
Packit Service 21b5d1
Packit Service 21b5d1
        /*!
Packit Service 21b5d1
         * @brief This class provides the public-facing const-qualified methods
Packit Service 21b5d1
         * of a slice.
Packit Service 21b5d1
         *
Packit Service 21b5d1
         * The public methods are implemented in a generic fashion using a
Packit Service 21b5d1
         * storage_type. This type contains the actual reference to the data to
Packit Service 21b5d1
         * which the slice points and provides the following methods:
Packit Service 21b5d1
         *
Packit Service 21b5d1
         * - (const) value_type& unsafeAt(size_t index) (const)
Packit Service 21b5d1
         *   Return the value at the given index of the underlying container,
Packit Service 21b5d1
         *   without promising to perform a range check and without any
Packit Service 21b5d1
         *   knowledge of the slices' size
Packit Service 21b5d1
         *
Packit Service 21b5d1
         * - const_iterator/iterator unsafeGetIteratorAt(size_t index) (const)
Packit Service 21b5d1
         *   Return a (constant) iterator at the given index of the underlying
Packit Service 21b5d1
         *   container. Again, no range checks are promised.
Packit Service 21b5d1
         *
Packit Service 21b5d1
         * - Constructor(data_type& data, size_t begin, size_t end)
Packit Service 21b5d1
         *   Can use `begin` & `end` to perform range checks on `data`, but
Packit Service 21b5d1
         *   should not store both values. Must not take ownership of `data`!
Packit Service 21b5d1
         *
Packit Service 21b5d1
         * - Must save data as a public member named `data_`.
Packit Service 21b5d1
         *
Packit Service 21b5d1
         * - Must provide appropriate typedefs for iterator, const_iterator and
Packit Service 21b5d1
         *   value_type
Packit Service 21b5d1
         */
Packit Service 21b5d1
        template <template <typename data_type> class storage_type, typename data_type>
Packit Service 21b5d1
        struct ConstSliceBase : SliceBase
Packit Service 21b5d1
        {
Packit Service 21b5d1
            typedef typename storage_type<data_type>::iterator iterator;
Packit Service 21b5d1
            typedef typename storage_type<data_type>::const_iterator const_iterator;
Packit Service 21b5d1
            typedef typename storage_type<data_type>::value_type value_type;
Packit Service 21b5d1
Packit Service 21b5d1
            /*!
Packit Service 21b5d1
             * Default contructor, requires begin to be smaller than end,
Packit Service 21b5d1
             * otherwise an exception is thrown. Also forwards all parameters to
Packit Service 21b5d1
             * the constructor of storage_
Packit Service 21b5d1
             */
Packit Service 21b5d1
            ConstSliceBase(data_type& data, size_t begin, size_t end)
Packit Service 21b5d1
                : SliceBase(begin, end), storage_(data, begin, end)
Packit Service 21b5d1
            {
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
            /*!
Packit Service 21b5d1
             * Obtain a constant reference to the element with the specified
Packit Service 21b5d1
             * index in the slice.
Packit Service 21b5d1
             *
Packit Service 21b5d1
             * @throw std::out_of_range when index is out of bounds of the slice
Packit Service 21b5d1
             */
Packit Service 21b5d1
            const value_type& at(size_t index) const
Packit Service 21b5d1
            {
Packit Service 21b5d1
                rangeCheck(index);
Packit Service 21b5d1
                // we know: begin_ < end <= size() <= SIZE_T_MAX
Packit Service 21b5d1
                // and: index < end - begin
Packit Service 21b5d1
                // thus: index + begin < end <= SIZE_T_MAX
Packit Service 21b5d1
                // => no overflow is possible
Packit Service 21b5d1
                return storage_.unsafeAt(begin_ + index);
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
            /*!
Packit Service 21b5d1
             * Obtain a constant iterator to the first element in the slice.
Packit Service 21b5d1
             */
Packit Service 21b5d1
            const_iterator cbegin() const throw()
Packit Service 21b5d1
            {
Packit Service 21b5d1
                return storage_.unsafeGetIteratorAt(begin_);
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
            /*!
Packit Service 21b5d1
             * Obtain a constant iterator to the first beyond the slice.
Packit Service 21b5d1
             */
Packit Service 21b5d1
            const_iterator cend() const throw()
Packit Service 21b5d1
            {
Packit Service 21b5d1
                return storage_.unsafeGetIteratorAt(end_);
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
            /*!
Packit Service 21b5d1
             * Create a constant sub-slice with the given bounds (with respect
Packit Service 21b5d1
             * to the current slice).
Packit Service 21b5d1
             *
Packit Service 21b5d1
             * @tparam slice_type  Type of the slice that this function shall
Packit Service 21b5d1
             * return. Provide it with the type of the class that derives from
Packit Service 21b5d1
             * mutable_slice_base.
Packit Service 21b5d1
             */
Packit Service 21b5d1
            template <typename slice_type>
Packit Service 21b5d1
            slice_type subSlice(size_t begin, size_t end) const
Packit Service 21b5d1
            {
Packit Service 21b5d1
                this->rangeCheck(begin);
Packit Service 21b5d1
                // end == size() is a legal value, since end is the first
Packit Service 21b5d1
                // element beyond the slice
Packit Service 21b5d1
                // end == 0 is not a legal value (subtraction will underflow and
Packit Service 21b5d1
                // throw an exception)
Packit Service 21b5d1
                this->rangeCheck(end - 1);
Packit Service 21b5d1
                // additions are safe, begin and end are smaller than size()
Packit Service 21b5d1
                const size_t new_begin = begin + this->begin_;
Packit Service 21b5d1
                const size_t new_end = this->begin_ + end;
Packit Service 21b5d1
                if (new_end > this->end_) {
Packit Service 21b5d1
                    throw std::out_of_range("Invalid input parameters to slice");
Packit Service 21b5d1
                }
Packit Service 21b5d1
                return slice_type(storage_.data_, new_begin, new_end);
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
        protected:
Packit Service 21b5d1
            /*!
Packit Service 21b5d1
             * Stores a reference to the actual data.
Packit Service 21b5d1
             */
Packit Service 21b5d1
            storage_type<data_type> storage_;
Packit Service 21b5d1
        };
Packit Service 21b5d1
Packit Service 21b5d1
        /*!
Packit Service 21b5d1
         * This class provides all public-facing non-const-qualified methods of
Packit Service 21b5d1
         * slices. It only re-implements the const-qualified versions as
Packit Service 21b5d1
         * non-const.
Packit Service 21b5d1
         */
Packit Service 21b5d1
        template <template <typename> class storage_type, typename data_type>
Packit Service 21b5d1
        struct MutableSliceBase : public ConstSliceBase<storage_type, data_type>
Packit Service 21b5d1
        {
Packit Service 21b5d1
            typedef typename ConstSliceBase<storage_type, data_type>::iterator iterator;
Packit Service 21b5d1
            typedef typename ConstSliceBase<storage_type, data_type>::const_iterator const_iterator;
Packit Service 21b5d1
            typedef typename ConstSliceBase<storage_type, data_type>::value_type value_type;
Packit Service 21b5d1
Packit Service 21b5d1
            /*!
Packit Service 21b5d1
             * Forwards everything to the constructor of const_slice_base
Packit Service 21b5d1
             *
Packit Service 21b5d1
             * @todo use using once we have C++11
Packit Service 21b5d1
             */
Packit Service 21b5d1
            MutableSliceBase(data_type& data, size_t begin, size_t end)
Packit Service 21b5d1
                : ConstSliceBase<storage_type, data_type>(data, begin, end)
Packit Service 21b5d1
            {
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
            /*!
Packit Service 21b5d1
             * Obtain a reference to the element with the specified index in the
Packit Service 21b5d1
             * slice.
Packit Service 21b5d1
             *
Packit Service 21b5d1
             * @throw std::out_of_range when index is out of bounds of the slice
Packit Service 21b5d1
             */
Packit Service 21b5d1
            value_type& at(size_t index)
Packit Service 21b5d1
            {
Packit Service 21b5d1
                this->rangeCheck(index);
Packit Service 21b5d1
                return this->storage_.unsafeAt(this->begin_ + index);
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
            const value_type& at(size_t index) const
Packit Service 21b5d1
            {
Packit Service 21b5d1
                // TODO: use using base_type::at once we have C++11
Packit Service 21b5d1
                return base_type::at(index);
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
            /*!
Packit Service 21b5d1
             * Obtain an iterator to the first element in the slice.
Packit Service 21b5d1
             */
Packit Service 21b5d1
            iterator begin() throw()
Packit Service 21b5d1
            {
Packit Service 21b5d1
                return this->storage_.unsafeGetIteratorAt(this->begin_);
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
            /*!
Packit Service 21b5d1
             * Obtain an iterator to the first element beyond the slice.
Packit Service 21b5d1
             */
Packit Service 21b5d1
            iterator end() throw()
Packit Service 21b5d1
            {
Packit Service 21b5d1
                return this->storage_.unsafeGetIteratorAt(this->end_);
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
        protected:
Packit Service 21b5d1
            /*!
Packit Service 21b5d1
             * Explicitly convert this instance into a base-class of the
Packit Service 21b5d1
             * appropriate constant version of this slice.
Packit Service 21b5d1
             *
Packit Service 21b5d1
             * This function is required to properly implement the `subSlice()
Packit Service 21b5d1
             * const` function for mutable slices. The problem here is, that a
Packit Service 21b5d1
             * slice<T> and a slice<const T> actually don't share the same base
Packit Service 21b5d1
             * class `ConstSliceBase<storage_type, T>`. Instead `slice<T>`
Packit Service 21b5d1
             * inherits from `ConstSliceBase<storage_type, T>` and `slice
Packit Service 21b5d1
             * T>` inherits from `ConstSliceBase<storage_type, const T>`.
Packit Service 21b5d1
             *
Packit Service 21b5d1
             * Now, `slice<T>` can call the `subSlice() const` method from its
Packit Service 21b5d1
             * base class, but that will return a mutable `slice<T>`! Instead we
Packit Service 21b5d1
             * use this function to convert the ``slice<T>` into the parent of
Packit Service 21b5d1
             * the appropriate `slice<const T>` and call its `subSlice() const`,
Packit Service 21b5d1
             * which returns the correct type.
Packit Service 21b5d1
             */
Packit Service 21b5d1
            ConstSliceBase<storage_type, const data_type> to_const_base() const throw()
Packit Service 21b5d1
            {
Packit Service 21b5d1
                return ConstSliceBase<storage_type, const data_type>(this->storage_.data_, this->begin_, this->end_);
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
            typedef ConstSliceBase<storage_type, data_type> base_type;
Packit Service 21b5d1
Packit Service 21b5d1
            /*!
Packit Service 21b5d1
             * Create a mutable sub-slice with the given bounds (with respect to
Packit Service 21b5d1
             * the current slice).
Packit Service 21b5d1
             *
Packit Service 21b5d1
             * @tparam slice_type  Type of the slice that this function shall
Packit Service 21b5d1
             * return. Provide it with the type of the class that derives from
Packit Service 21b5d1
             * mutable_slice_base.
Packit Service 21b5d1
             */
Packit Service 21b5d1
            template <typename slice_type>
Packit Service 21b5d1
            slice_type subSlice(size_t begin, size_t end)
Packit Service 21b5d1
            {
Packit Service 21b5d1
                this->rangeCheck(begin);
Packit Service 21b5d1
                // end == size() is a legal value, since end is the first
Packit Service 21b5d1
                // element beyond the slice
Packit Service 21b5d1
                // end == 0 is not a legal value (subtraction will underflow and
Packit Service 21b5d1
                // throw an exception)
Packit Service 21b5d1
                this->rangeCheck(end - 1);
Packit Service 21b5d1
Packit Service 21b5d1
                // additions are safe, begin & end are smaller than size()
Packit Service 21b5d1
                const size_t new_begin = begin + this->begin_;
Packit Service 21b5d1
                const size_t new_end = this->begin_ + end;
Packit Service 21b5d1
                if (new_end > this->end_) {
Packit Service 21b5d1
                    throw std::out_of_range("Invalid input parameters to slice");
Packit Service 21b5d1
                }
Packit Service 21b5d1
                return slice_type(this->storage_.data_, new_begin, new_end);
Packit Service 21b5d1
            }
Packit Service 21b5d1
        };
Packit Service 21b5d1
Packit Service 21b5d1
        /*!
Packit Service 21b5d1
         * Implementation of the storage concept for STL-containers.
Packit Service 21b5d1
         *
Packit Service 21b5d1
         * @tparam container  Type of the STL-container.
Packit Service 21b5d1
         */
Packit Service 21b5d1
        template <typename container>
Packit Service 21b5d1
        struct ContainerStorage
Packit Service 21b5d1
        {
Packit Service 21b5d1
            typedef typename container::iterator iterator;
Packit Service 21b5d1
Packit Service 21b5d1
            typedef typename container::const_iterator const_iterator;
Packit Service 21b5d1
Packit Service 21b5d1
            typedef typename Internal::remove_cv<typename container::value_type>::type value_type;
Packit Service 21b5d1
Packit Service 21b5d1
            /*!
Packit Service 21b5d1
             * @throw std::out_of_range when end is larger than the container's
Packit Service 21b5d1
             * size.
Packit Service 21b5d1
             */
Packit Service 21b5d1
            ContainerStorage(container& data, size_t /* begin*/, size_t end) : data_(data)
Packit Service 21b5d1
            {
Packit Service 21b5d1
                if (end > data.size()) {
Packit Service 21b5d1
                    throw std::out_of_range("Invalid input parameters to slice");
Packit Service 21b5d1
                }
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
            /*!
Packit Service 21b5d1
             * Obtain a constant reference to the element with the given `index`
Packit Service 21b5d1
             * in the container.
Packit Service 21b5d1
             *
Packit Service 21b5d1
             * @throw whatever container::at() throws
Packit Service 21b5d1
             */
Packit Service 21b5d1
            const value_type& unsafeAt(size_t index) const
Packit Service 21b5d1
            {
Packit Service 21b5d1
                return data_.at(index);
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
            value_type& unsafeAt(size_t index)
Packit Service 21b5d1
            {
Packit Service 21b5d1
                return data_.at(index);
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
            /*!
Packit Service 21b5d1
             * Obtain an iterator at the position of the element with the given
Packit Service 21b5d1
             * index in the container.
Packit Service 21b5d1
             *
Packit Service 21b5d1
             * @throw whatever container::begin() and std::advance() throw
Packit Service 21b5d1
             */
Packit Service 21b5d1
            iterator unsafeGetIteratorAt(size_t index)
Packit Service 21b5d1
            {
Packit Service 21b5d1
                // we are screwed if the container got changed => try to catch it
Packit Service 21b5d1
                assert(index <= data_.size());
Packit Service 21b5d1
Packit Service 21b5d1
                iterator it = data_.begin();
Packit Service 21b5d1
                std::advance(it, index);
Packit Service 21b5d1
                return it;
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
            const_iterator unsafeGetIteratorAt(size_t index) const
Packit Service 21b5d1
            {
Packit Service 21b5d1
                assert(index <= data_.size());
Packit Service 21b5d1
Packit Service 21b5d1
                const_iterator it = data_.begin();
Packit Service 21b5d1
                std::advance(it, index);
Packit Service 21b5d1
                return it;
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
            container& data_;
Packit Service 21b5d1
        };
Packit Service 21b5d1
Packit Service 21b5d1
        /*!
Packit Service 21b5d1
         * @brief Implementation of the storage concept for slices of C arrays.
Packit Service 21b5d1
         *
Packit Service 21b5d1
         * @tparam storage_type  Type as which the C-array should be stored. Use
Packit Service 21b5d1
         * this parameter to save constant arrays as `const` and mutable ones as
Packit Service 21b5d1
         * non-`const`.
Packit Service 21b5d1
         */
Packit Service 21b5d1
        template <typename storage_type>
Packit Service 21b5d1
        struct PtrSliceStorage
Packit Service 21b5d1
        {
Packit Service 21b5d1
            typedef typename remove_cv<typename remove_pointer<storage_type>::type>::type value_type;
Packit Service 21b5d1
            typedef value_type* iterator;
Packit Service 21b5d1
            typedef const value_type* const_iterator;
Packit Service 21b5d1
Packit Service 21b5d1
            /*!
Packit Service 21b5d1
             * Stores ptr and checks that it is not `NULL`. The slice's bounds
Packit Service 21b5d1
             * are ignored, as we do not know the array's length.
Packit Service 21b5d1
             *
Packit Service 21b5d1
             * @throw std::invalid_argument when ptr is `NULL`
Packit Service 21b5d1
             */
Packit Service 21b5d1
            PtrSliceStorage(storage_type ptr, size_t /*begin*/, size_t /*end*/) : data_(ptr)
Packit Service 21b5d1
            {
Packit Service 21b5d1
                // TODO: change this to nullptr once we use C++11
Packit Service 21b5d1
                if (ptr == NULL) {
Packit Service 21b5d1
                    throw std::invalid_argument("Null pointer passed to slice constructor");
Packit Service 21b5d1
                }
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
            /*!
Packit Service 21b5d1
             * Obtain a reference to the element with the given `index` in the
Packit Service 21b5d1
             * array.
Packit Service 21b5d1
             *
Packit Service 21b5d1
             * @throw nothing
Packit Service 21b5d1
             */
Packit Service 21b5d1
            value_type& unsafeAt(size_t index) throw()
Packit Service 21b5d1
            {
Packit Service 21b5d1
                return data_[index];
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
            const value_type& unsafeAt(size_t index) const throw()
Packit Service 21b5d1
            {
Packit Service 21b5d1
                return data_[index];
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
            /*!
Packit Service 21b5d1
             * Obtain an iterator (=pointer) at the position of the element with
Packit Service 21b5d1
             * the given index in the container.
Packit Service 21b5d1
             *
Packit Service 21b5d1
             * @throw nothing
Packit Service 21b5d1
             */
Packit Service 21b5d1
            iterator unsafeGetIteratorAt(size_t index) throw()
Packit Service 21b5d1
            {
Packit Service 21b5d1
                return data_ + index;
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
            const_iterator unsafeGetIteratorAt(size_t index) const throw()
Packit Service 21b5d1
            {
Packit Service 21b5d1
                return data_ + index;
Packit Service 21b5d1
            }
Packit Service 21b5d1
Packit Service 21b5d1
            storage_type data_;
Packit Service 21b5d1
        };
Packit Service 21b5d1
Packit Service 21b5d1
    }  // namespace Internal
Packit Service 21b5d1
Packit Service 21b5d1
    /*!
Packit Service 21b5d1
     * @brief Slice (= view) for STL containers.
Packit Service 21b5d1
     *
Packit Service 21b5d1
     * This is a very simple implementation of slices (i.e. views of sub-arrays)
Packit Service 21b5d1
     * for STL containers that support O(1) element access and random access
Packit Service 21b5d1
     * iterators (like std::vector, std::array and std::string).
Packit Service 21b5d1
     *
Packit Service 21b5d1
     * A slice represents the semi-open interval [begin, end) and provides a
Packit Service 21b5d1
     * (mutable) view, it does however not own the data! It can be used to
Packit Service 21b5d1
     * conveniently pass parts of containers into functions without having to use
Packit Service 21b5d1
     * iterators or offsets.
Packit Service 21b5d1
     *
Packit Service 21b5d1
     * In contrast to C++20's std::span<T> it is impossible to read beyond the
Packit Service 21b5d1
     * container's bounds and unchecked access is not-possible (by design).
Packit Service 21b5d1
     *
Packit Service 21b5d1
     * Example usage:
Packit Service 21b5d1
     * ~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
Packit Service 21b5d1
     * std::vector<int> vec = {0, 1, 2, 3, 4};
Packit Service 21b5d1
     * slice<std::vector<int> > one_two(vec, 1, 3);
Packit Service 21b5d1
     * assert(one_two.size() == 2);
Packit Service 21b5d1
     * assert(one_two.at(0) == 1 && one_two.at(1) == 2);
Packit Service 21b5d1
     * // mutate the contents:
Packit Service 21b5d1
     * one_two.at(0) *= 2;
Packit Service 21b5d1
     * one_two.at(1) *= 3;
Packit Service 21b5d1
     * assert(one_two.at(0) == 2 && one_two.at(1) == 6);
Packit Service 21b5d1
     * ~~~~~~~~~~~~~~~~~~~~~~~~~
Packit Service 21b5d1
     *
Packit Service 21b5d1
     * Slices also offer access via iterators of the same type as the underlying
Packit Service 21b5d1
     * container, so that they can be used in a comparable fashion:
Packit Service 21b5d1
     * ~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
Packit Service 21b5d1
     * std::vector<int> vec = {0, 1, 2, 3, 4};
Packit Service 21b5d1
     * slice<std::vector<int>> three_four(vec, 3, 5);
Packit Service 21b5d1
     * assert(*three_four.begin() == 3 && *three_four.end() == 4);
Packit Service 21b5d1
     * // this prints:
Packit Service 21b5d1
     * // 3
Packit Service 21b5d1
     * // 4
Packit Service 21b5d1
     * for (const auto & elem : three_four) {
Packit Service 21b5d1
     *     std::cout << elem << std::endl;
Packit Service 21b5d1
     * }
Packit Service 21b5d1
     * ~~~~~~~~~~~~~~~~~~~~~~~~~
Packit Service 21b5d1
     *
Packit Service 21b5d1
     * @tparam container A STL container type, like vector or array. Must support
Packit Service 21b5d1
     * array-like access via the `at()` method.
Packit Service 21b5d1
     */
Packit Service 21b5d1
    template <typename container>
Packit Service 21b5d1
    struct Slice : public Internal::MutableSliceBase<Internal::ContainerStorage, container>
Packit Service 21b5d1
    {
Packit Service 21b5d1
        typedef typename container::iterator iterator;
Packit Service 21b5d1
Packit Service 21b5d1
        typedef typename container::const_iterator const_iterator;
Packit Service 21b5d1
Packit Service 21b5d1
        typedef typename Internal::remove_cv<typename container::value_type>::type value_type;
Packit Service 21b5d1
Packit Service 21b5d1
        /*!
Packit Service 21b5d1
         * @brief Construct a slice of the container `cont` starting at `begin`
Packit Service 21b5d1
         * (including) and ending before `end`.
Packit Service 21b5d1
         *
Packit Service 21b5d1
         * @param[in] cont Reference to the container
Packit Service 21b5d1
         * @param[in] begin First element of the slice.
Packit Service 21b5d1
         * @param[in] end First element beyond the slice.
Packit Service 21b5d1
         *
Packit Service 21b5d1
         * @throws std::out_of_range For invalid slice bounds: when end is not
Packit Service 21b5d1
         * larger than begin or when the slice's bounds are larger than the
Packit Service 21b5d1
         * container's size.
Packit Service 21b5d1
         *
Packit Service 21b5d1
         * Please note that due to the requirement that `end` must be larger
Packit Service 21b5d1
         * than `begin` (they cannot be equal) it is impossible to construct a
Packit Service 21b5d1
         * slice with zero length.
Packit Service 21b5d1
         */
Packit Service 21b5d1
        Slice(container& cont, size_t begin, size_t end)
Packit Service 21b5d1
            : Internal::MutableSliceBase<Internal::ContainerStorage, container>(cont, begin, end)
Packit Service 21b5d1
        {
Packit Service 21b5d1
        }
Packit Service 21b5d1
Packit Service 21b5d1
        /*!
Packit Service 21b5d1
         * Construct a sub-slice of this slice with the given bounds. The bounds
Packit Service 21b5d1
         * are evaluated with respect to the current slice.
Packit Service 21b5d1
         *
Packit Service 21b5d1
         * @param[in] begin  First element in the new slice.
Packit Service 21b5d1
         * @param[in] end  First element beyond the new slice.
Packit Service 21b5d1
         *
Packit Service 21b5d1
         * @throw std::out_of_range when begin or end are invalid
Packit Service 21b5d1
         */
Packit Service 21b5d1
        Slice subSlice(size_t begin, size_t end)
Packit Service 21b5d1
        {
Packit Service 21b5d1
            return Internal::MutableSliceBase<Internal::ContainerStorage, container>::template subSlice<Slice>(begin,
Packit Service 21b5d1
                                                                                                               end);
Packit Service 21b5d1
        }
Packit Service 21b5d1
Packit Service 21b5d1
        /*!
Packit Service 21b5d1
         * Constructs a new constant subSlice. Behaves otherwise exactly like
Packit Service 21b5d1
         * the non-const version.
Packit Service 21b5d1
         */
Packit Service 21b5d1
        Slice<const container> subSlice(size_t begin, size_t end) const
Packit Service 21b5d1
        {
Packit Service 21b5d1
            return this->to_const_base().template subSlice<Slice<const container> >(begin, end);
Packit Service 21b5d1
        }
Packit Service 21b5d1
    };
Packit Service 21b5d1
Packit Service 21b5d1
    /*!
Packit Service 21b5d1
     * @brief Specialization of slices for constant containers.
Packit Service 21b5d1
     */
Packit Service 21b5d1
    template <typename container>
Packit Service 21b5d1
    struct Slice<const container> : public Internal::ConstSliceBase<Internal::ContainerStorage, const container>
Packit Service 21b5d1
    {
Packit Service 21b5d1
        typedef typename container::iterator iterator;
Packit Service 21b5d1
Packit Service 21b5d1
        typedef typename container::const_iterator const_iterator;
Packit Service 21b5d1
Packit Service 21b5d1
        typedef typename Internal::remove_cv<typename container::value_type>::type value_type;
Packit Service 21b5d1
Packit Service 21b5d1
        Slice(const container& cont, size_t begin, size_t end)
Packit Service 21b5d1
            : Internal::ConstSliceBase<Internal::ContainerStorage, const container>(cont, begin, end)
Packit Service 21b5d1
        {
Packit Service 21b5d1
        }
Packit Service 21b5d1
Packit Service 21b5d1
        Slice subSlice(size_t begin, size_t end) const
Packit Service 21b5d1
        {
Packit Service 21b5d1
            return Internal::ConstSliceBase
Packit Service 21b5d1
                                            const container>::template subSlice<Slice<const container> >(begin, end);
Packit Service 21b5d1
        }
Packit Service 21b5d1
    };
Packit Service 21b5d1
Packit Service 21b5d1
    /*!
Packit Service 21b5d1
     * Specialization of slices for constant C-arrays.
Packit Service 21b5d1
     *
Packit Service 21b5d1
     * These have exactly the same interface as the slices for STL-containers,
Packit Service 21b5d1
     * with the *crucial* exception, that the slice's constructor *cannot* make
Packit Service 21b5d1
     * a proper bounds check! It can only verify that you didn't accidentally
Packit Service 21b5d1
     * swap begin and end!
Packit Service 21b5d1
     */
Packit Service 21b5d1
    template <typename T>
Packit Service 21b5d1
    struct Slice<const T*> : public Internal::ConstSliceBase<Internal::PtrSliceStorage, const T*>
Packit Service 21b5d1
    {
Packit Service 21b5d1
        /*!
Packit Service 21b5d1
         * Constructor.
Packit Service 21b5d1
         *
Packit Service 21b5d1
         * @param[in] ptr  C-array of which a slice should be constructed. Must
Packit Service 21b5d1
         *     not be a null pointer.
Packit Service 21b5d1
         * @param[in] begin  Index of the first element in the slice.
Packit Service 21b5d1
         * @param[in] end  Index of the first element that is no longer in the
Packit Service 21b5d1
         *     slice.
Packit Service 21b5d1
         *
Packit Service 21b5d1
         * Please note that the constructor has no way how to verify that
Packit Service 21b5d1
         * `begin` and `end` are not out of bounds of the provided array!
Packit Service 21b5d1
         */
Packit Service 21b5d1
        Slice(const T* ptr, size_t begin, size_t end)
Packit Service 21b5d1
            : Internal::ConstSliceBase<Internal::PtrSliceStorage, const T*>(ptr, begin, end)
Packit Service 21b5d1
        {
Packit Service 21b5d1
            // TODO: use using in C++11
Packit Service 21b5d1
        }
Packit Service 21b5d1
Packit Service 21b5d1
        Slice<const T*> subSlice(size_t begin, size_t end) const
Packit Service 21b5d1
        {
Packit Service 21b5d1
            return Internal::ConstSliceBase<Internal::PtrSliceStorage, const T*>::template subSlice<Slice<const T*> >(
Packit Service 21b5d1
                begin, end);
Packit Service 21b5d1
        }
Packit Service 21b5d1
    };
Packit Service 21b5d1
Packit Service 21b5d1
    /*!
Packit Service 21b5d1
     * Specialization of slices for (mutable) C-arrays.
Packit Service 21b5d1
     */
Packit Service 21b5d1
    template <typename T>
Packit Service 21b5d1
    struct Slice<T*> : public Internal::MutableSliceBase<Internal::PtrSliceStorage, T*>
Packit Service 21b5d1
    {
Packit Service 21b5d1
        Slice(T* ptr, size_t begin, size_t end)
Packit Service 21b5d1
            : Internal::MutableSliceBase<Internal::PtrSliceStorage, T*>(ptr, begin, end)
Packit Service 21b5d1
        {
Packit Service 21b5d1
            // TODO: use using in C++11
Packit Service 21b5d1
        }
Packit Service 21b5d1
Packit Service 21b5d1
        Slice<T*> subSlice(size_t begin, size_t end)
Packit Service 21b5d1
        {
Packit Service 21b5d1
            return Internal::MutableSliceBase<Internal::PtrSliceStorage, T*>::template subSlice<Slice<T*> >(begin, end);
Packit Service 21b5d1
        }
Packit Service 21b5d1
Packit Service 21b5d1
        Slice<const T*> subSlice(size_t begin, size_t end) const
Packit Service 21b5d1
        {
Packit Service 21b5d1
            return this->to_const_base().template subSlice<Slice<const T*> >(begin, end);
Packit Service 21b5d1
        }
Packit Service 21b5d1
    };
Packit Service 21b5d1
Packit Service 21b5d1
    /*!
Packit Service 21b5d1
     * @brief Return a new slice with the given bounds.
Packit Service 21b5d1
     *
Packit Service 21b5d1
     * Convenience wrapper around the slice's constructor for automatic template
Packit Service 21b5d1
     * parameter deduction.
Packit Service 21b5d1
     */
Packit Service 21b5d1
    template <typename T>
Packit Service 21b5d1
    inline Slice<T> makeSlice(T& cont, size_t begin, size_t end)
Packit Service 21b5d1
    {
Packit Service 21b5d1
        return Slice<T>(cont, begin, end);
Packit Service 21b5d1
    }
Packit Service 21b5d1
Packit Service 21b5d1
    /*!
Packit Service 21b5d1
     * Overload of makeSlice for slices of C-arrays.
Packit Service 21b5d1
     */
Packit Service 21b5d1
    template <typename T>
Packit Service 21b5d1
    inline Slice<T*> makeSlice(T* ptr, size_t begin, size_t end)
Packit Service 21b5d1
    {
Packit Service 21b5d1
        return Slice<T*>(ptr, begin, end);
Packit Service 21b5d1
    }
Packit Service 21b5d1
Packit Service 21b5d1
    /*!
Packit Service 21b5d1
     * @brief Return a new slice spanning the whole container.
Packit Service 21b5d1
     */
Packit Service 21b5d1
    template <typename container>
Packit Service 21b5d1
    inline Slice<container> makeSlice(container& cont)
Packit Service 21b5d1
    {
Packit Service 21b5d1
        return Slice<container>(cont, 0, cont.size());
Packit Service 21b5d1
    }
Packit Service 21b5d1
Packit Service 21b5d1
    /*!
Packit Service 21b5d1
     * @brief Return a new slice spanning from begin until the end of the
Packit Service 21b5d1
     * container.
Packit Service 21b5d1
     */
Packit Service 21b5d1
    template <typename container>
Packit Service 21b5d1
    inline Slice<container> makeSliceFrom(container& cont, size_t begin)
Packit Service 21b5d1
    {
Packit Service 21b5d1
        return Slice<container>(cont, begin, cont.size());
Packit Service 21b5d1
    }
Packit Service 21b5d1
Packit Service 21b5d1
    /*!
Packit Service 21b5d1
     * @brief Return a new slice spanning until `end`.
Packit Service 21b5d1
     */
Packit Service 21b5d1
    template <typename container>
Packit Service 21b5d1
    inline Slice<container> makeSliceUntil(container& cont, size_t end)
Packit Service 21b5d1
    {
Packit Service 21b5d1
        return Slice<container>(cont, 0, end);
Packit Service 21b5d1
    }
Packit Service 21b5d1
Packit Service 21b5d1
    /*!
Packit Service 21b5d1
     * Overload of makeSliceUntil for pointer based slices.
Packit Service 21b5d1
     */
Packit Service 21b5d1
    template <typename T>
Packit Service 21b5d1
    inline Slice<T*> makeSliceUntil(T* ptr, size_t end)
Packit Service 21b5d1
    {
Packit Service 21b5d1
        return Slice<T*>(ptr, 0, end);
Packit Service 21b5d1
    }
Packit Service 21b5d1
Packit Service 21b5d1
}  // namespace Exiv2
Packit Service 21b5d1
Packit Service 21b5d1
#endif /* EXIV2_INCLUDE_SLICE_HPP */