Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / gil / extension / numeric / kernel.hpp
index da75176..3186180 100644 (file)
@@ -1,14 +1,17 @@
 //
 // Copyright 2005-2007 Adobe Systems Incorporated
+// Copyright 2019 Miral Shah <miralshah2211@gmail.com>
 //
 // Distributed under the Boost Software License, Version 1.0
 // See accompanying file LICENSE_1_0.txt or copy at
 // http://www.boost.org/LICENSE_1_0.txt
 //
+
 #ifndef BOOST_GIL_EXTENSION_NUMERIC_KERNEL_HPP
 #define BOOST_GIL_EXTENSION_NUMERIC_KERNEL_HPP
 
 #include <boost/gil/utilities.hpp>
+#include <boost/gil/point.hpp>
 
 #include <boost/assert.hpp>
 
@@ -17,6 +20,7 @@
 #include <cstddef>
 #include <memory>
 #include <vector>
+#include <cmath>
 
 namespace boost { namespace gil {
 
@@ -26,93 +30,316 @@ namespace detail {
 
 /// \brief kernel adaptor for one-dimensional cores
 /// Core needs to provide size(),begin(),end(),operator[],
-///                       value_type,iterator,const_iterator,reference,const_reference
+/// value_type,iterator,const_iterator,reference,const_reference
 template <typename Core>
-class kernel_1d_adaptor : public Core {
-private:
-    std::size_t _center;
+class kernel_1d_adaptor : public Core
+{
 public:
-    kernel_1d_adaptor() : _center(0) {}
+    kernel_1d_adaptor() = default;
 
-    explicit kernel_1d_adaptor(std::size_t center_in)
-        : _center(center_in)
+    explicit kernel_1d_adaptor(std::size_t center)
+        : center_(center)
     {
-        BOOST_ASSERT(_center < this->size());
+        BOOST_ASSERT(center_ < this->size());
     }
 
-    kernel_1d_adaptor(std::size_t size_in, std::size_t center_in)
-        : Core(size_in)
-        , _center(center_in)
+    kernel_1d_adaptor(std::size_t size, std::size_t center)
+        : Core(size) , center_(center)
     {
-        BOOST_ASSERT(_center < this->size());
+        BOOST_ASSERT(this->size() > 0);
+        BOOST_ASSERT(center_ < this->size()); // also implies `size() > 0`
     }
 
-    kernel_1d_adaptor(kernel_1d_adaptor const& k_in) : Core(k_in), _center(k_in._center) {}
+    kernel_1d_adaptor(kernel_1d_adaptor const& other)
+        : Core(other), center_(other.center_)
+    {
+        BOOST_ASSERT(this->size() > 0);
+        BOOST_ASSERT(center_ < this->size()); // also implies `size() > 0`
+    }
 
-    kernel_1d_adaptor& operator=(const kernel_1d_adaptor& k_in) {
-        Core::operator=(k_in);
-        _center=k_in._center;
+    kernel_1d_adaptor& operator=(kernel_1d_adaptor const& other)
+    {
+        Core::operator=(other);
+        center_ = other.center_;
         return *this;
     }
 
     std::size_t left_size() const
     {
-        BOOST_ASSERT(_center < this->size());
-        return _center;
+        BOOST_ASSERT(center_ < this->size());
+        return center_;
     }
 
     std::size_t right_size() const
     {
-        BOOST_ASSERT(_center < this->size());
-        return this->size() - _center - 1;
+        BOOST_ASSERT(center_ < this->size());
+        return this->size() - center_ - 1;
+    }
+
+    auto center() -> std::size_t&
+    {
+        BOOST_ASSERT(center_ < this->size());
+        return center_;
     }
 
-    std::size_t& center()       {return _center;}
-    const std::size_t& center() const {return _center;}
+    auto center() const -> std::size_t const&
+    {
+        BOOST_ASSERT(center_ < this->size());
+        return center_;
+    }
+
+private:
+    std::size_t center_{0};
 };
 
 } // namespace detail
 
 /// \brief variable-size kernel
-template <typename T, typename Alloc = std::allocator<T> >
-class kernel_1d : public detail::kernel_1d_adaptor<std::vector<T,Alloc>>
+template <typename T, typename Allocator = std::allocator<T> >
+class kernel_1d : public detail::kernel_1d_adaptor<std::vector<T, Allocator>>
 {
-    using parent_t = detail::kernel_1d_adaptor<std::vector<T,Alloc>>;
+    using parent_t = detail::kernel_1d_adaptor<std::vector<T, Allocator>>;
 public:
-    kernel_1d() {}
-    kernel_1d(std::size_t size_in,std::size_t center_in) : parent_t(size_in,center_in) {}
+
+    kernel_1d() = default;
+    kernel_1d(std::size_t size, std::size_t center) : parent_t(size, center) {}
+
     template <typename FwdIterator>
-    kernel_1d(FwdIterator elements, std::size_t size_in, std::size_t center_in) : parent_t(size_in,center_in) {
-        detail::copy_n(elements,size_in,this->begin());
+    kernel_1d(FwdIterator elements, std::size_t size, std::size_t center)
+        : parent_t(size, center)
+    {
+        detail::copy_n(elements, size, this->begin());
     }
-    kernel_1d(const kernel_1d& k_in)                     : parent_t(k_in) {}
+
+    kernel_1d(kernel_1d const& other) : parent_t(other) {}
+    kernel_1d& operator=(kernel_1d const& other) = default;
 };
 
 /// \brief static-size kernel
 template <typename T,std::size_t Size>
-class kernel_1d_fixed : public detail::kernel_1d_adaptor<std::array<T,Size>>
+class kernel_1d_fixed : public detail::kernel_1d_adaptor<std::array<T, Size>>
 {
-    using parent_t = detail::kernel_1d_adaptor<std::array<T,Size>>;
+    using parent_t = detail::kernel_1d_adaptor<std::array<T, Size>>;
 public:
-    kernel_1d_fixed() {}
-    explicit kernel_1d_fixed(std::size_t center_in) : parent_t(center_in) {}
+    static constexpr std::size_t static_size = Size;
+    static_assert(static_size > 0, "kernel must have size greater than 0");
+    static_assert(static_size % 2 == 1, "kernel size must be odd to ensure validity at the center");
+
+    kernel_1d_fixed() = default;
+    explicit kernel_1d_fixed(std::size_t center) : parent_t(center) {}
 
     template <typename FwdIterator>
-    explicit kernel_1d_fixed(FwdIterator elements, std::size_t center_in) : parent_t(center_in) {
-        detail::copy_n(elements,Size,this->begin());
+    explicit kernel_1d_fixed(FwdIterator elements, std::size_t center)
+        : parent_t(center)
+    {
+        detail::copy_n(elements, Size, this->begin());
     }
-    kernel_1d_fixed(const kernel_1d_fixed& k_in)    : parent_t(k_in) {}
+
+    kernel_1d_fixed(kernel_1d_fixed const& other) : parent_t(other) {}
+    kernel_1d_fixed& operator=(kernel_1d_fixed const& other) = default;
 };
 
+// TODO: This data member is odr-used and definition at namespace scope
+// is required by C++11. Redundant and deprecated in C++17.
+template <typename T,std::size_t Size>
+constexpr std::size_t kernel_1d_fixed<T, Size>::static_size;
+
 /// \brief reverse a kernel
 template <typename Kernel>
-inline Kernel reverse_kernel(const Kernel& kernel) {
+inline Kernel reverse_kernel(Kernel const& kernel)
+{
     Kernel result(kernel);
-    result.center()=kernel.right_size();
+    result.center() = kernel.right_size();
     std::reverse(result.begin(), result.end());
     return result;
 }
 
+
+namespace detail {
+
+template <typename Core>
+class kernel_2d_adaptor : public Core
+{
+public:
+    kernel_2d_adaptor() = default;
+
+    explicit kernel_2d_adaptor(std::size_t center_y, std::size_t center_x)
+        : center_(center_x, center_y)
+    {
+        BOOST_ASSERT(center_.y < this->size() && center_.x < this->size());
+    }
+
+    kernel_2d_adaptor(std::size_t size, std::size_t center_y, std::size_t center_x)
+        : Core(size * size), square_size(size), center_(center_x, center_y)
+    {
+        BOOST_ASSERT(this->size() > 0);
+        BOOST_ASSERT(center_.y < this->size() && center_.x < this->size()); // implies `size() > 0`
+    }
+
+    kernel_2d_adaptor(kernel_2d_adaptor const& other)
+        : Core(other), square_size(other.square_size), center_(other.center_.x, other.center_.y)
+    {
+        BOOST_ASSERT(this->size() > 0);
+        BOOST_ASSERT(center_.y < this->size() && center_.x < this->size()); // implies `size() > 0`
+    }
+
+    kernel_2d_adaptor& operator=(kernel_2d_adaptor const& other)
+    {
+        Core::operator=(other);
+        center_.y = other.center_.y;
+        center_.x = other.center_.x;
+        square_size = other.square_size;
+        return *this;
+    }
+
+    std::size_t upper_size() const
+    {
+        BOOST_ASSERT(center_.y < this->size());
+        return center_.y;
+    }
+
+    std::size_t lower_size() const
+    {
+        BOOST_ASSERT(center_.y < this->size());
+        return this->size() - center_.y - 1;
+    }
+
+    std::size_t left_size() const
+    {
+        BOOST_ASSERT(center_.x < this->size());
+        return center_.x;
+    }
+
+    std::size_t right_size() const
+    {
+        BOOST_ASSERT(center_.x < this->size());
+        return this->size() - center_.x - 1;
+    }
+
+    auto center_y() -> std::size_t&
+    {
+        BOOST_ASSERT(center_.y < this->size());
+        return center_.y;
+    }
+
+    auto center_y() const -> std::size_t const&
+    {
+        BOOST_ASSERT(center_.y < this->size());
+        return center_.y;
+    }
+
+    auto center_x() -> std::size_t&
+    {
+        BOOST_ASSERT(center_.x < this->size());
+        return center_.x;
+    }
+
+    auto center_x() const -> std::size_t const&
+    {
+        BOOST_ASSERT(center_.x < this->size());
+        return center_.x;
+    }
+
+    std::size_t size() const
+    {
+        return square_size;
+    }
+
+    typename Core::value_type at(std::size_t x, std::size_t y) const
+    {
+        if (x >= this->size() || y >= this->size())
+        {
+            throw std::out_of_range("Index out of range");
+        }
+        return this->begin()[y * this->size() + x];
+    }
+
+protected:
+    std::size_t square_size{0};
+
+private:
+    point<std::size_t> center_{0, 0};
+};
+
+/// \brief variable-size kernel
+template
+<
+    typename T,
+    typename Allocator = std::allocator<T>
+>
+class kernel_2d : public detail::kernel_2d_adaptor<std::vector<T, Allocator>>
+{
+    using parent_t = detail::kernel_2d_adaptor<std::vector<T, Allocator>>;
+
+public:
+
+    kernel_2d() = default;
+    kernel_2d(std::size_t size,std::size_t center_y, std::size_t center_x)
+        : parent_t(size, center_y, center_x)
+    {}
+
+    template <typename FwdIterator>
+    kernel_2d(FwdIterator elements, std::size_t size, std::size_t center_y, std::size_t center_x)
+        : parent_t(static_cast<int>(std::sqrt(size)), center_y, center_x)
+    {
+        detail::copy_n(elements, size, this->begin());
+    }
+
+    kernel_2d(kernel_2d const& other) : parent_t(other) {}
+    kernel_2d& operator=(kernel_2d const& other) = default;
+};
+
+/// \brief static-size kernel
+template <typename T, std::size_t Size>
+class kernel_2d_fixed :
+    public detail::kernel_2d_adaptor<std::array<T, Size * Size>>
+{
+    using parent_t = detail::kernel_2d_adaptor<std::array<T, Size * Size>>;
+public:
+    static constexpr std::size_t static_size = Size;
+    static_assert(static_size > 0, "kernel must have size greater than 0");
+    static_assert(static_size % 2 == 1, "kernel size must be odd to ensure validity at the center");
+
+    kernel_2d_fixed()
+    {
+        this->square_size = Size;
+    }
+
+    explicit kernel_2d_fixed(std::size_t center_y, std::size_t center_x) :
+        parent_t(center_y, center_x)
+    {
+        this->square_size = Size;
+    }
+
+    template <typename FwdIterator>
+    explicit kernel_2d_fixed(FwdIterator elements, std::size_t center_y, std::size_t center_x)
+        : parent_t(center_y, center_x)
+    {
+        this->square_size = Size;
+        detail::copy_n(elements, Size * Size, this->begin());
+    }
+
+    kernel_2d_fixed(kernel_2d_fixed const& other) : parent_t(other) {}
+    kernel_2d_fixed& operator=(kernel_2d_fixed const& other) = default;
+};
+
+// TODO: This data member is odr-used and definition at namespace scope
+// is required by C++11. Redundant and deprecated in C++17.
+template <typename T, std::size_t Size>
+constexpr std::size_t kernel_2d_fixed<T, Size>::static_size;
+
+} //namespace detail
+
+/// \brief reverse a kernel
+//template <typename Kernel>
+//inline Kernel reverse_kernel(Kernel const& kernel)
+//{
+//    Kernel result(kernel);
+//    result.center() = kernel.right_size();
+//    std::reverse(result.begin(), result.end());
+//    return result;
+//}
+
 }} // namespace boost::gil
 
 #endif