Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / gil / image_view.hpp
index 353e402..d1e50a7 100644 (file)
@@ -11,6 +11,8 @@
 #include <boost/gil/dynamic_step.hpp>
 #include <boost/gil/iterator_from_2d.hpp>
 
+#include <boost/assert.hpp>
+
 #include <cstddef>
 #include <iterator>
 
@@ -48,10 +50,10 @@ namespace boost { namespace gil {
 ///
 ////////////////////////////////////////////////////////////////////////////////////////
 template <typename Loc>     // Models 2D Pixel Locator
-class image_view {
+class image_view
+{
 public:
-
-// aliases required by ConstRandomAccessNDImageViewConcept
+    // aliases required by ConstRandomAccessNDImageViewConcept
     static const std::size_t num_dimensions=2;
     using value_type = typename Loc::value_type;
     using reference = typename Loc::reference;       // result of dereferencing
@@ -72,35 +74,69 @@ public:
     using reverse_iterator = std::reverse_iterator<iterator>;
     using size_type = std::size_t;
 
-// aliases required by ConstRandomAccess2DImageViewConcept
+    // aliases required by ConstRandomAccess2DImageViewConcept
     using xy_locator = locator;
     using x_iterator = typename xy_locator::x_iterator;     // pixel iterator along a row
     using y_iterator = typename xy_locator::y_iterator;     // pixel iterator along a column
     using x_coord_t = typename xy_locator::x_coord_t;
     using y_coord_t = typename xy_locator::y_coord_t;
 
-    template <typename Deref> struct add_deref
+    template <typename Deref>
+    struct add_deref
     {
         using type = image_view<typename Loc::template add_deref<Deref>::type>;
-        static type make(const image_view<Loc>& iv, const Deref& d)
+        static type make(image_view<Loc> const& view, Deref const& d)
         {
-            return type(iv.dimensions(), Loc::template add_deref<Deref>::make(iv.pixels(),d));
+            return type(view.dimensions(), Loc::template add_deref<Deref>::make(view.pixels(), d));
         }
     };
 
     image_view() : _dimensions(0,0) {}
-    template <typename View> image_view(const View& iv)                                    : _dimensions(iv.dimensions()), _pixels(iv.pixels()) {}
+    image_view(image_view const& img_view)
+        : _dimensions(img_view.dimensions()), _pixels(img_view.pixels())
+    {}
 
-    template <typename L2> image_view(const point_t& sz            , const L2& loc)        : _dimensions(sz),          _pixels(loc) {}
-    template <typename L2> image_view(coord_t width, coord_t height, const L2& loc)        : _dimensions(x_coord_t(width),y_coord_t(height)), _pixels(loc) {}
+    template <typename View>
+    image_view(View const& view) : _dimensions(view.dimensions()), _pixels(view.pixels()) {}
 
-    template <typename View> image_view& operator=(const View& iv)  { _pixels=iv.pixels(); _dimensions=iv.dimensions(); return *this; }
-    image_view& operator=(const image_view& iv)                     { _pixels=iv.pixels(); _dimensions=iv.dimensions(); return *this; }
+    template <typename L2>
+    image_view(point_t const& dims, L2 const& loc) : _dimensions(dims), _pixels(loc) {}
 
-    template <typename View> bool operator==(const View& v) const   { return pixels()==v.pixels() && dimensions()==v.dimensions(); }
-    template <typename View> bool operator!=(const View& v) const   { return !(*this==v); }
+    template <typename L2>
+    image_view(coord_t width, coord_t height, L2 const& loc)
+        : _dimensions(x_coord_t(width), y_coord_t(height)), _pixels(loc)
+    {}
 
-    template <typename L2> friend void swap(image_view<L2>& x, image_view<L2>& y);
+    template <typename View>
+    image_view& operator=(View const& view)
+    {
+        _pixels = view.pixels();
+        _dimensions = view.dimensions();
+        return *this;
+    }
+
+    image_view& operator=(image_view const& view)
+    {
+        // TODO: Self-assignment protection?
+        _pixels = view.pixels();
+        _dimensions = view.dimensions();
+        return *this;
+    }
+
+    template <typename View>
+    bool operator==(View const &view) const
+    {
+        return pixels() == view.pixels() && dimensions() == view.dimensions();
+    }
+
+    template <typename View>
+    bool operator!=(View const& view) const
+    {
+        return !(*this == view);
+    }
+
+    template <typename L2>
+    friend void swap(image_view<L2> &lhs, image_view<L2> &rhs);
 
     /// \brief Exchanges the elements of the current view with those of \a other
     ///       in constant time.
@@ -113,72 +149,223 @@ public:
         swap(*this, other);
     }
 
+    auto dimensions() const -> point_t const&
+    {
+        return _dimensions;
+    }
+
+    auto pixels() const -> locator const&
+    {
+        return _pixels;
+    }
+
+    auto width() const -> x_coord_t
+    {
+        return dimensions().x;
+    }
+
+    auto height() const -> y_coord_t
+    {
+        return dimensions().y;
+    }
+
+    auto num_channels() const -> std::size_t
+    {
+        return gil::num_channels<value_type>::value;
+    }
+
+    bool is_1d_traversable() const
+    {
+        return _pixels.is_1d_traversable(width());
+    }
+
     /// \brief Returns true if the view has no elements, false otherwise.
     ///
     /// \note Required by the Collection concept
     /// \see  https://www.boost.org/libs/utility/Collection.html
-    bool empty() const { return !(width() > 0 && height() > 0); }
+    bool empty() const
+    {
+        return !(width() > 0 && height() > 0);
+    }
 
     /// \brief Returns a reference to the first element in raster order.
     ///
     /// \note Required by the ForwardCollection, since view model the concept.
     /// \see  https://www.boost.org/libs/utility/Collection.html
-    reference front() const { return *begin(); }
+    auto front() const -> reference
+    {
+        BOOST_ASSERT(!empty());
+        return *begin();
+    }
 
     /// \brief Returns a reference to the last element in raster order.
     ///
     /// \note Required by the ForwardCollection, since view model the concept.
     /// \see  https://www.boost.org/libs/utility/Collection.html
-    reference back() const { return *rbegin(); }
-
-    const point_t&   dimensions()            const { return _dimensions; }
-    const locator&   pixels()                const { return _pixels; }
-    x_coord_t        width()                 const { return dimensions().x; }
-    y_coord_t        height()                const { return dimensions().y; }
-    std::size_t      num_channels()          const { return gil::num_channels<value_type>::value; }
-    bool             is_1d_traversable()     const { return _pixels.is_1d_traversable(width()); }
+    auto back() const -> reference
+    {
+        BOOST_ASSERT(!empty());
+        return *rbegin();
+    }
 
     //\{@
     /// \name 1D navigation
-    size_type           size()               const { return width()*height(); }
-    iterator            begin()              const { return iterator(_pixels,_dimensions.x); }
-    iterator            end()                const { return begin()+(difference_type)size(); }    // potential performance problem!
-    reverse_iterator    rbegin()             const { return reverse_iterator(end()); }
-    reverse_iterator    rend()               const { return reverse_iterator(begin()); }
-    reference operator[](difference_type i)  const { return begin()[i]; }        // potential performance problem!
-    iterator            at(difference_type i)const { return begin()+i; }
-    iterator            at(const point_t& p) const { return begin()+p.y*width()+p.x; }
-    iterator            at(x_coord_t x, y_coord_t y)const { return begin()+y*width()+x; }
+    auto size() const -> size_type
+    {
+        return width() * height();
+    }
+
+    auto begin() const -> iterator
+    {
+        return iterator(_pixels, _dimensions.x);
+    }
+
+    auto end() const -> iterator
+    {
+        // potential performance problem!
+        return begin() + static_cast<difference_type>(size());
+    }
+
+    auto rbegin() const -> reverse_iterator
+    {
+        return reverse_iterator(end());
+    }
 
+    auto rend() const -> reverse_iterator
+    {
+        return reverse_iterator(begin());
+    }
+
+    auto operator[](difference_type i) const -> reference
+    {
+        BOOST_ASSERT(i < static_cast<difference_type>(size()));
+        return begin()[i]; // potential performance problem!
+    }
+
+    auto at(difference_type i) const ->iterator
+    {
+        BOOST_ASSERT(i < size());
+        return begin() + i;
+    }
+
+    auto at(point_t const& p) const -> iterator
+    {
+        BOOST_ASSERT(0 <= p.x && p.x < width());
+        BOOST_ASSERT(0 <= p.y && p.y < height());
+        return begin() + p.y * width() + p.x;
+    }
+
+    auto at(x_coord_t x, y_coord_t y) const -> iterator
+    {
+        BOOST_ASSERT(0 <= x && x < width());
+        BOOST_ASSERT(0 <= y && y < height());
+        return begin() + y * width() + x;
+    }
     //\}@
 
     //\{@
     /// \name 2-D navigation
-    reference operator()(const point_t& p)        const { return _pixels(p.x,p.y); }
-    reference operator()(x_coord_t x, y_coord_t y)const { return _pixels(x,y); }
-    template <std::size_t D> typename axis<D>::iterator axis_iterator(const point_t& p) const { return _pixels.template axis_iterator<D>(p); }
-    xy_locator xy_at(x_coord_t x, y_coord_t y)    const { return _pixels+point_t(x_coord_t(x),y_coord_t(y)); }
-    locator    xy_at(const point_t& p)            const { return _pixels+p; }
+    auto operator()(point_t const& p) const -> reference
+    {
+        BOOST_ASSERT(0 <= p.x && p.x < width());
+        BOOST_ASSERT(0 <= p.y && p.y < height());
+        return _pixels(p.x, p.y);
+    }
+
+    auto operator()(x_coord_t x, y_coord_t y) const -> reference
+    {
+        BOOST_ASSERT(0 <= x && x < width());
+        BOOST_ASSERT(0 <= y && y < height());
+        return _pixels(x, y);
+    }
+
+    template <std::size_t D>
+    auto axis_iterator(point_t const& p) const -> typename axis<D>::iterator
+    {
+        // allow request for iterators from inclusive range of [begin, end]
+        BOOST_ASSERT(0 <= p.x && p.x <= width());
+        BOOST_ASSERT(0 <= p.y && p.y <= height());
+        return _pixels.template axis_iterator<D>(p);
+    }
+
+    auto xy_at(x_coord_t x, y_coord_t y) const -> xy_locator
+    {
+        // TODO: Are relative locations of neighbors with negative offsets valid? Sampling?
+        BOOST_ASSERT(x < width());
+        BOOST_ASSERT(y < height());
+        return _pixels + point_t(x, y);
+    }
+
+    auto xy_at(point_t const& p) const -> locator
+    {
+        // TODO: Are relative locations of neighbors with negative offsets valid? Sampling?
+        BOOST_ASSERT(p.x < width());
+        BOOST_ASSERT(p.y < height());
+        return _pixels + p;
+    }
     //\}@
 
     //\{@
     /// \name X navigation
-    x_iterator x_at(x_coord_t x, y_coord_t y)     const { return _pixels.x_at(x,y); }
-    x_iterator x_at(const point_t& p)             const { return _pixels.x_at(p); }
-    x_iterator row_begin(y_coord_t y)             const { return x_at(0,y); }
-    x_iterator row_end(y_coord_t y)               const { return x_at(width(),y); }
+    auto x_at(x_coord_t x, y_coord_t y) const -> x_iterator
+    {
+        BOOST_ASSERT(0 <= x && x <= width()); // allow request for [begin, end] inclusive
+        BOOST_ASSERT(0 <= y && y < height());
+        return _pixels.x_at(x, y);
+    }
+
+    auto x_at(point_t const& p) const -> x_iterator
+    {
+        BOOST_ASSERT(0 <= p.x && p.x <= width()); // allow request for [begin, end] inclusive
+        BOOST_ASSERT(0 <= p.y && p.y < height());
+        return _pixels.x_at(p);
+    }
+
+    auto row_begin(y_coord_t y) const -> x_iterator
+    {
+        BOOST_ASSERT(0 <= y && y < height());
+        return x_at(0, y);
+    }
+
+    auto row_end(y_coord_t y) const -> x_iterator
+    {
+        BOOST_ASSERT(0 <= y && y < height());
+        return x_at(width(), y);
+    }
     //\}@
 
     //\{@
     /// \name Y navigation
-    y_iterator y_at(x_coord_t x, y_coord_t y)     const { return xy_at(x,y).y(); }
-    y_iterator y_at(const point_t& p)             const { return xy_at(p).y(); }
-    y_iterator col_begin(x_coord_t x)             const { return y_at(x,0); }
-    y_iterator col_end(x_coord_t x)               const { return y_at(x,height()); }
+    auto y_at(x_coord_t x, y_coord_t y) const -> y_iterator
+    {
+        BOOST_ASSERT(0 <= x && x < width());
+        BOOST_ASSERT(0 <= y && y <= height()); // allow request for [begin, end] inclusive
+        return xy_at(x, y).y();
+    }
+
+    auto y_at(point_t const& p) const -> y_iterator
+    {
+        BOOST_ASSERT(0 <= p.x && p.x < width());
+        BOOST_ASSERT(0 <= p.y && p.y <= height()); // allow request for [begin, end] inclusive
+        return xy_at(p).y();
+    }
+
+    auto col_begin(x_coord_t x) const -> y_iterator
+    {
+        BOOST_ASSERT(0 <= x && x < width());
+        return y_at(x, 0);
+    }
+
+    auto col_end(x_coord_t x) const -> y_iterator
+    {
+        BOOST_ASSERT(0 <= x && x < width());
+        return y_at(x, height());
+    }
     //\}@
 
 private:
-    template <typename L2> friend class image_view;
+    template <typename L2>
+    friend class image_view;
 
     point_t    _dimensions;
     xy_locator _pixels;
@@ -212,8 +399,9 @@ struct is_planar<image_view<L> > : public is_planar<L> {};
 /////////////////////////////
 
 template <typename L>
-struct dynamic_x_step_type<image_view<L> > {
-    using type = image_view<typename dynamic_x_step_type<L>::type>;
+struct dynamic_x_step_type<image_view<L>>
+{
+    using type = image_view<typename gil::dynamic_x_step_type<L>::type>;
 };
 
 /////////////////////////////
@@ -221,8 +409,9 @@ struct dynamic_x_step_type<image_view<L> > {
 /////////////////////////////
 
 template <typename L>
-struct dynamic_y_step_type<image_view<L> > {
-    using type = image_view<typename dynamic_y_step_type<L>::type>;
+struct dynamic_y_step_type<image_view<L>>
+{
+    using type = image_view<typename gil::dynamic_y_step_type<L>::type>;
 };
 
 /////////////////////////////
@@ -230,7 +419,8 @@ struct dynamic_y_step_type<image_view<L> > {
 /////////////////////////////
 
 template <typename L>
-struct transposed_type<image_view<L> > {
+struct transposed_type<image_view<L>>
+{
     using type = image_view<typename transposed_type<L>::type>;
 };