Change ArrayRef to use a proper iterator
authorRoland Schulz <roland.schulz@intel.com>
Fri, 26 Jun 2020 16:03:46 +0000 (16:03 +0000)
committerM. Eric Irrgang <mei2n@virginia.edu>
Fri, 26 Jun 2020 16:03:46 +0000 (16:03 +0000)
Fixes #2859

CMakeLists.txt
COPYING
src/external/CMakeLists.txt
src/external/boost/CMakeLists.txt [new file with mode: 0644]
src/external/boost/README [new file with mode: 0644]
src/external/boost/stl_interfaces/fwd.hpp [new file with mode: 0644]
src/external/boost/stl_interfaces/iterator_interface.hpp [new file with mode: 0644]
src/gromacs/gmxpreprocess/ter_db.cpp
src/gromacs/utility/arrayref.h

index 1fd257020c5b351945bb21dac60f09430185ba82..ecca752aea184866cd6a1c42dba7afb27357814f 100644 (file)
@@ -605,6 +605,7 @@ gmx_add_cache_dependency(GMX_BUILD_UNITTESTS BOOL BUILD_TESTING OFF)
 ########################################################################
 
 include_directories(BEFORE ${CMAKE_SOURCE_DIR}/src)
+include_directories(SYSTEM ${CMAKE_SOURCE_DIR}/src/external)
 # Required for config.h, maybe should only be set in src/CMakeLists.txt
 include_directories(BEFORE ${CMAKE_BINARY_DIR}/src)
 
diff --git a/COPYING b/COPYING
index 0ded3b23bd3398330574a6a523c58dc67ade6d53..0088e6ad3ba9391c3f3fffacf4d12bb1c5e8b20f 100644 (file)
--- a/COPYING
+++ b/COPYING
@@ -29,6 +29,7 @@ This file contains the licenses for the following bodies of code:
 18. pybind11
 19. Reference implementation of std::string_view
 20. Reference implementation of std::optional
+21. stl_interfaces
 
 Our chosen method for packaging distributions (CPack) only permits a
 package to have a single license file, so we are unfortunately forced
@@ -1465,3 +1466,33 @@ SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 DEALINGS IN THE SOFTWARE.
+
+21. stl_interfaces
+==================
+
+Used with minor modification from commit 486db0a5543cea2901ed of
+https://github.com/boostorg/stl_interfaces, which is licensed as below.
+
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
index f2c31adfa5456682374851bc1c8c7cff8d48fa54..2188398307e00feccd07abb4efaef3b5e37521c8 100644 (file)
@@ -68,3 +68,4 @@ if(BUILD_TESTING AND GMX_BUILD_UNITTESTS)
 
     set(GTEST_IS_THREADSAFE "${GTEST_IS_THREADSAFE}" PARENT_SCOPE)
 endif()
+add_subdirectory(boost)
diff --git a/src/external/boost/CMakeLists.txt b/src/external/boost/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6f0dc69
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# This file is part of the GROMACS molecular simulation package.
+#
+# Copyright (c) 2019, by the GROMACS development team, led by
+# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+# and including many others, as listed in the AUTHORS file in the
+# top-level source directory and at http://www.gromacs.org.
+#
+# GROMACS is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# as published by the Free Software Foundation; either version 2.1
+# of the License, or (at your option) any later version.
+#
+# GROMACS is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with GROMACS; if not, see
+# http://www.gnu.org/licenses, or write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+#
+# If you want to redistribute modifications to GROMACS, please
+# consider that scientific software is very special. Version
+# control is crucial - bugs must be traceable. We will be happy to
+# consider code for inclusion in the official distribution, but
+# derived work must not be called official GROMACS. Details are found
+# in the README & COPYING files - if they are missing, get the
+# official version at http://www.gromacs.org.
+#
+# To help us fund GROMACS development, we humbly ask that you cite
+# the research papers on the package. Check out http://www.gromacs.org.
+
+if(GMX_INSTALL_LEGACY_API)
+  install(FILES
+          stl_interfaces/fwd.hpp  stl_interfaces/iterator_interface.hpp
+          DESTINATION include/gromacs/external/boost/stl_interfaces)
+endif()
diff --git a/src/external/boost/README b/src/external/boost/README
new file mode 100644 (file)
index 0000000..98420c4
--- /dev/null
@@ -0,0 +1,3 @@
+stl_interfaces
+==============
+6486db0a5543cea2901ed380fff010ae9e6acf39 from https://github.com/boostorg/stl_interfaces
diff --git a/src/external/boost/stl_interfaces/fwd.hpp b/src/external/boost/stl_interfaces/fwd.hpp
new file mode 100644 (file)
index 0000000..6c41833
--- /dev/null
@@ -0,0 +1,95 @@
+// Copyright (C) 2019 T. Zachary Laine
+//
+// 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_STL_INTERFACES_FWD_HPP
+#define BOOST_STL_INTERFACES_FWD_HPP
+
+#include <iterator>
+
+#ifndef BOOST_STL_INTERFACES_DOXYGEN
+
+#if defined(_MSC_VER) || defined(__GNUC__) && __GNUC__ < 8
+#define BOOST_STL_INTERFACES_NO_HIDDEN_FRIEND_CONSTEXPR
+#define BOOST_STL_INTERFACES_HIDDEN_FRIEND_CONSTEXPR
+#else
+#define BOOST_STL_INTERFACES_HIDDEN_FRIEND_CONSTEXPR constexpr
+#endif
+
+#if defined(__GNUC__) && __GNUC__ < 9
+#define BOOST_STL_INTERFACES_CONCEPT concept bool
+#else
+#define BOOST_STL_INTERFACES_CONCEPT concept
+#endif
+
+#endif
+
+
+namespace boost { namespace stl_interfaces {
+    inline namespace v1 {
+
+        /** An enumeration used to indicate whether the underlying data have a
+            contiguous or discontiguous layout when instantiating
+            `view_interface` and `sequence_container_interface`. */
+        enum class element_layout : bool {
+            discontiguous = false,
+            contiguous = true
+        };
+
+        namespace v1_dtl {
+            template<typename... T>
+            using void_t = void;
+
+            template<typename Iter>
+            using iter_difference_t =
+                typename std::iterator_traits<Iter>::difference_type;
+
+            template<typename Range, typename = void>
+            struct iterator;
+            template<typename Range>
+            struct iterator<
+                Range,
+                void_t<decltype(std::declval<Range &>().begin())>>
+            {
+                using type = decltype(std::declval<Range &>().begin());
+            };
+            template<typename Range>
+            using iterator_t = typename iterator<Range>::type;
+
+            template<typename Range, typename = void>
+            struct sentinel;
+            template<typename Range>
+            struct sentinel<
+                Range,
+                void_t<decltype(std::declval<Range &>().end())>>
+            {
+                using type = decltype(std::declval<Range &>().end());
+            };
+            template<typename Range>
+            using sentinel_t = typename sentinel<Range>::type;
+
+            template<typename Range>
+            using range_difference_t = iter_difference_t<iterator_t<Range>>;
+
+            template<typename Range>
+            using common_range =
+                std::is_same<iterator_t<Range>, sentinel_t<Range>>;
+
+            template<typename Range, typename = void>
+            struct decrementable_sentinel : std::false_type
+            {
+            };
+            template<typename Range>
+            struct decrementable_sentinel<
+                Range,
+                void_t<decltype(--std::declval<sentinel_t<Range> &>())>>
+                : std::true_type
+            {
+            };
+        }
+
+    }
+}}
+
+#endif
diff --git a/src/external/boost/stl_interfaces/iterator_interface.hpp b/src/external/boost/stl_interfaces/iterator_interface.hpp
new file mode 100644 (file)
index 0000000..5f39619
--- /dev/null
@@ -0,0 +1,623 @@
+// Copyright (C) 2019 T. Zachary Laine
+//
+// 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_STL_INTERFACES_ITERATOR_INTERFACE_HPP
+#define BOOST_STL_INTERFACES_ITERATOR_INTERFACE_HPP
+
+#include "./fwd.hpp"
+
+#include <utility>
+#include <type_traits>
+#if defined(__cpp_lib_three_way_comparison)
+#include <compare>
+#endif
+
+
+namespace boost { namespace stl_interfaces {
+
+    /** A type for granting access to the private members of an iterator
+        derived from `iterator_interface`. */
+    struct access
+    {
+#ifndef BOOST_STL_INTERFACES_DOXYGEN
+
+        template<typename D>
+        static constexpr auto base(D & d) noexcept
+            -> decltype(d.base_reference())
+        {
+            return d.base_reference();
+        }
+        template<typename D>
+        static constexpr auto base(D const & d) noexcept
+            -> decltype(d.base_reference())
+        {
+            return d.base_reference();
+        }
+
+#endif
+    };
+
+    /** The return type of `operator->()` in a proxy iterator.
+
+        This template is used as the default `Pointer` template parameter in
+        the `proxy_iterator_interface` template alias.  Note that the use of
+        this template implies a copy or move of the underlying object of type
+        `T`. */
+    template<typename T>
+    struct proxy_arrow_result
+    {
+        constexpr proxy_arrow_result(T const & value) noexcept(
+            noexcept(T(value))) :
+            value_(value)
+        {}
+        constexpr proxy_arrow_result(T && value) noexcept(
+            noexcept(T(std::move(value)))) :
+            value_(std::move(value))
+        {}
+
+        constexpr T const * operator->() const noexcept { return &value_; }
+        constexpr T * operator->() noexcept { return &value_; }
+
+    private:
+        T value_;
+    };
+
+    namespace detail {
+        template<typename Pointer, typename T>
+        auto make_pointer(
+            T && value,
+            std::enable_if_t<std::is_pointer<Pointer>::value, int> = 0)
+            -> decltype(std::addressof(value))
+        {
+            return std::addressof(value);
+        }
+
+        template<typename Pointer, typename T>
+        auto make_pointer(
+            T && value,
+            std::enable_if_t<!std::is_pointer<Pointer>::value, int> = 0)
+        {
+            return Pointer(std::forward<T>(value));
+        }
+
+        template<typename IteratorConcept>
+        struct concept_category
+        {
+            using type = IteratorConcept;
+        };
+        template<typename IteratorConcept>
+        using concept_category_t =
+            typename concept_category<IteratorConcept>::type;
+
+        template<typename Pointer, typename IteratorConcept>
+        struct pointer
+        {
+            using type = Pointer;
+        };
+        template<typename Pointer>
+        struct pointer<Pointer, std::output_iterator_tag>
+        {
+            using type = void;
+        };
+        template<typename Pointer, typename IteratorConcept>
+        using pointer_t = typename pointer<Pointer, IteratorConcept>::type;
+
+        template<typename T, typename U>
+        using interoperable = std::integral_constant<
+            bool,
+            (std::is_convertible<T, U>::value ||
+             std::is_convertible<U, T>::value)>;
+
+        template<typename T, typename U>
+        using common_t =
+            std::conditional_t<std::is_convertible<T, U>::value, U, T>;
+
+        template<typename T>
+        using use_base = decltype(access::base(std::declval<T &>()));
+
+        template<typename... T>
+        using void_t = void;
+
+        template<
+            typename AlwaysVoid,
+            template<class...> class Template,
+            typename... Args>
+        struct detector : std::false_type
+        {
+        };
+
+        template<template<class...> class Template, typename... Args>
+        struct detector<void_t<Template<Args...>>, Template, Args...>
+            : std::true_type
+        {
+        };
+
+        template<
+            typename T,
+            typename U,
+            bool UseBase = detector<void, use_base, T>::value>
+        struct common_eq
+        {
+            static constexpr auto call(T lhs, U rhs)
+            {
+                return static_cast<common_t<T, U>>(lhs).derived() ==
+                       static_cast<common_t<T, U>>(rhs).derived();
+            }
+        };
+        template<typename T, typename U>
+        struct common_eq<T, U, true>
+        {
+            static constexpr auto call(T lhs, U rhs)
+            {
+                return access::base(lhs) == access::base(rhs);
+            }
+        };
+
+        template<typename T, typename U>
+        constexpr auto common_diff(T lhs, U rhs) noexcept(noexcept(
+            static_cast<common_t<T, U>>(lhs) -
+            static_cast<common_t<T, U>>(rhs)))
+            -> decltype(
+                static_cast<common_t<T, U>>(lhs) -
+                static_cast<common_t<T, U>>(rhs))
+        {
+            return static_cast<common_t<T, U>>(lhs) -
+                   static_cast<common_t<T, U>>(rhs);
+        }
+    }
+
+}}
+
+namespace boost { namespace stl_interfaces { inline namespace v1 {
+
+    /** A CRTP template that one may derive from to make defining iterators
+        easier.
+
+        The template parameter `D` for `iterator_interface` may be an
+        incomplete type.  Before any member of the resulting specialization of
+        `iterator_interface` other than special member functions is
+        referenced, `D` shall be complete, and model
+        `std::derived_from<iterator_interface<D>>`. */
+    template<
+        typename Derived,
+        typename IteratorConcept,
+        typename ValueType,
+        typename Reference = ValueType &,
+        typename Pointer = ValueType *,
+        typename DifferenceType = std::ptrdiff_t
+#ifndef BOOST_STL_INTERFACES_DOXYGEN
+        ,
+        typename E = std::enable_if_t<
+            std::is_class<Derived>::value &&
+            std::is_same<Derived, std::remove_cv_t<Derived>>::value>
+#endif
+        >
+    struct iterator_interface;
+
+    namespace v1_dtl {
+        template<typename Iterator, typename = void>
+        struct ra_iter : std::false_type
+        {
+        };
+        template<typename Iterator>
+        struct ra_iter<Iterator, void_t<typename Iterator::iterator_concept>>
+            : std::integral_constant<
+                  bool,
+                  std::is_base_of<
+                      std::random_access_iterator_tag,
+                      typename Iterator::iterator_concept>::value>
+        {
+        };
+
+        template<typename Iterator, typename DifferenceType, typename = void>
+        struct plus_eq : std::false_type
+        {
+        };
+        template<typename Iterator, typename DifferenceType>
+        struct plus_eq<
+            Iterator,
+            DifferenceType,
+            void_t<decltype(
+                std::declval<Iterator &>() += std::declval<DifferenceType>())>>
+            : std::true_type
+        {
+        };
+
+        template<
+            typename D,
+            typename IteratorConcept,
+            typename ValueType,
+            typename Reference,
+            typename Pointer,
+            typename DifferenceType>
+        void derived_iterator(iterator_interface<
+                              D,
+                              IteratorConcept,
+                              ValueType,
+                              Reference,
+                              Pointer,
+                              DifferenceType> const &);
+    }
+
+    template<
+        typename Derived,
+        typename IteratorConcept,
+        typename ValueType,
+        typename Reference,
+        typename Pointer,
+        typename DifferenceType
+#ifndef BOOST_STL_INTERFACES_DOXYGEN
+        ,
+        typename E
+#endif
+        >
+    struct iterator_interface
+    {
+#ifndef BOOST_STL_INTERFACES_DOXYGEN
+    private:
+        constexpr Derived & derived() noexcept
+        {
+            return static_cast<Derived &>(*this);
+        }
+        constexpr Derived const & derived() const noexcept
+        {
+            return static_cast<Derived const &>(*this);
+        }
+
+        template<typename T, typename U, bool UseBase>
+        friend struct detail::common_eq;
+#endif
+
+    public:
+        using iterator_concept = IteratorConcept;
+        using iterator_category = detail::concept_category_t<iterator_concept>;
+        using value_type = std::remove_const_t<ValueType>;
+        using reference = Reference;
+        using pointer = detail::pointer_t<Pointer, iterator_concept>;
+        using difference_type = DifferenceType;
+
+        template<typename D = Derived>
+        constexpr auto operator*() const
+            noexcept(noexcept(*access::base(std::declval<D const &>())))
+                -> decltype(*access::base(std::declval<D const &>()))
+        {
+            return *access::base(derived());
+        }
+
+        template<typename D = Derived>
+        constexpr auto operator-> () const noexcept(
+            noexcept(detail::make_pointer<pointer>(*std::declval<D const &>())))
+            -> decltype(
+                detail::make_pointer<pointer>(*std::declval<D const &>()))
+        {
+            return detail::make_pointer<pointer>(*derived());
+        }
+
+        template<typename D = Derived>
+        constexpr auto operator[](difference_type i) const noexcept(noexcept(
+            D(std::declval<D const &>()),
+            std::declval<D &>() += i,
+            *std::declval<D &>()))
+            -> decltype(std::declval<D &>() += i, *std::declval<D &>())
+        {
+            D retval = derived();
+            retval += i;
+            return *retval;
+        }
+
+        template<
+            typename D = Derived,
+            typename Enable =
+                std::enable_if_t<!v1_dtl::plus_eq<D, difference_type>::value>>
+        constexpr auto
+        operator++() noexcept(noexcept(++access::base(std::declval<D &>())))
+            -> decltype(++access::base(std::declval<D &>()))
+        {
+            return ++access::base(derived());
+        }
+
+        template<typename D = Derived>
+        constexpr auto operator++() noexcept(
+            noexcept(std::declval<D &>() += difference_type(1)))
+            -> decltype(
+                std::declval<D &>() += difference_type(1), std::declval<D &>())
+        {
+            derived() += difference_type(1);
+            return derived();
+        }
+        template<typename D = Derived>
+        constexpr auto operator++(int)noexcept(
+            noexcept(D(std::declval<D &>()), ++std::declval<D &>()))
+            -> std::remove_reference_t<decltype(
+                D(std::declval<D &>()),
+                ++std::declval<D &>(),
+                std::declval<D &>())>
+        {
+            D retval = derived();
+            ++derived();
+            return retval;
+        }
+
+        template<typename D = Derived>
+        constexpr auto operator+=(difference_type n) noexcept(
+            noexcept(access::base(std::declval<D &>()) += n))
+            -> decltype(access::base(std::declval<D &>()) += n)
+        {
+            return access::base(derived()) += n;
+        }
+
+        template<typename D = Derived>
+        constexpr auto operator+(difference_type i) const
+            noexcept(noexcept(D(std::declval<D &>()), std::declval<D &>() += i))
+                -> std::remove_reference_t<decltype(
+                    D(std::declval<D &>()),
+                    std::declval<D &>() += i,
+                    std::declval<D &>())>
+        {
+            D retval = derived();
+            retval += i;
+            return retval;
+        }
+        friend BOOST_STL_INTERFACES_HIDDEN_FRIEND_CONSTEXPR Derived
+        operator+(difference_type i, Derived it) noexcept
+        {
+            return it + i;
+        }
+
+        template<
+            typename D = Derived,
+            typename Enable =
+                std::enable_if_t<!v1_dtl::plus_eq<D, difference_type>::value>>
+        constexpr auto
+        operator--() noexcept(noexcept(--access::base(std::declval<D &>())))
+            -> decltype(--access::base(std::declval<D &>()))
+        {
+            return --access::base(derived());
+        }
+
+        template<typename D = Derived>
+        constexpr auto operator--() noexcept(noexcept(
+            D(std::declval<D &>()), std::declval<D &>() += -difference_type(1)))
+            -> decltype(
+                std::declval<D &>() += -difference_type(1), std::declval<D &>())
+        {
+            derived() += -difference_type(1);
+            return derived();
+        }
+        template<typename D = Derived>
+        constexpr auto operator--(int)noexcept(
+            noexcept(D(std::declval<D &>()), --std::declval<D &>()))
+            -> std::remove_reference_t<decltype(
+                D(std::declval<D &>()),
+                --std::declval<D &>(),
+                std::declval<D &>())>
+        {
+            D retval = derived();
+            --derived();
+            return retval;
+        }
+
+        template<typename D = Derived>
+        constexpr D & operator-=(difference_type i) noexcept
+        {
+            derived() += -i;
+            return derived();
+        }
+
+        template<typename D = Derived>
+        constexpr auto operator-(D other) const noexcept(noexcept(
+            access::base(std::declval<D const &>()) - access::base(other)))
+            -> decltype(
+                access::base(std::declval<D const &>()) - access::base(other))
+        {
+            return access::base(derived()) - access::base(other);
+        }
+
+        friend BOOST_STL_INTERFACES_HIDDEN_FRIEND_CONSTEXPR Derived
+        operator-(Derived it, difference_type i) noexcept
+        {
+            Derived retval = it;
+            retval += -i;
+            return retval;
+        }
+    };
+
+    /** Implementation of `operator==()`, implemented in terms of the iterator
+        underlying IteratorInterface, for all iterators derived from
+        `iterator_interface`, except those with an iterator category derived
+        from `std::random_access_iterator_tag`.  */
+    template<
+        typename IteratorInterface1,
+        typename IteratorInterface2,
+        typename Enable =
+            std::enable_if_t<!v1_dtl::ra_iter<IteratorInterface1>::value>>
+    constexpr auto
+    operator==(IteratorInterface1 lhs, IteratorInterface2 rhs) noexcept
+        -> decltype(
+            access::base(std::declval<IteratorInterface1 &>()) ==
+            access::base(std::declval<IteratorInterface2 &>()))
+    {
+        return access::base(lhs) == access::base(rhs);
+    }
+
+    /** Implementation of `operator==()` for all iterators derived from
+        `iterator_interface` that have an iterator category derived from
+        `std::random_access_iterator_tag`.  */
+    template<
+        typename IteratorInterface1,
+        typename IteratorInterface2,
+        typename Enable =
+            std::enable_if_t<v1_dtl::ra_iter<IteratorInterface1>::value>>
+    constexpr auto
+    operator==(IteratorInterface1 lhs, IteratorInterface2 rhs) noexcept(
+        noexcept(detail::common_diff(lhs, rhs)))
+        -> decltype(
+            v1_dtl::derived_iterator(lhs), detail::common_diff(lhs, rhs) == 0)
+    {
+        return detail::common_diff(lhs, rhs) == 0;
+    }
+
+    /** Implementation of `operator!=()` for all iterators derived from
+        `iterator_interface`.  */
+    template<typename IteratorInterface1, typename IteratorInterface2>
+    constexpr auto operator!=(
+        IteratorInterface1 lhs,
+        IteratorInterface2 rhs) noexcept(noexcept(!(lhs == rhs)))
+        -> decltype(v1_dtl::derived_iterator(lhs), !(lhs == rhs))
+    {
+        return !(lhs == rhs);
+    }
+
+    /** Implementation of `operator<()` for all iterators derived from
+        `iterator_interface` that have an iterator category derived from
+        `std::random_access_iterator_tag`.  */
+    template<typename IteratorInterface1, typename IteratorInterface2>
+    constexpr auto
+    operator<(IteratorInterface1 lhs, IteratorInterface2 rhs) noexcept(
+        noexcept(detail::common_diff(lhs, rhs)))
+        -> decltype(
+            v1_dtl::derived_iterator(lhs), detail::common_diff(lhs, rhs) < 0)
+    {
+        return detail::common_diff(lhs, rhs) < 0;
+    }
+
+    /** Implementation of `operator<=()` for all iterators derived from
+        `iterator_interface` that have an iterator category derived from
+        `std::random_access_iterator_tag`.  */
+    template<typename IteratorInterface1, typename IteratorInterface2>
+    constexpr auto
+    operator<=(IteratorInterface1 lhs, IteratorInterface2 rhs) noexcept(
+        noexcept(detail::common_diff(lhs, rhs)))
+        -> decltype(
+            v1_dtl::derived_iterator(lhs), detail::common_diff(lhs, rhs) <= 0)
+    {
+        return detail::common_diff(lhs, rhs) <= 0;
+    }
+
+    /** Implementation of `operator>()` for all iterators derived from
+        `iterator_interface` that have an iterator category derived from
+        `std::random_access_iterator_tag`.  */
+    template<typename IteratorInterface1, typename IteratorInterface2>
+    constexpr auto
+    operator>(IteratorInterface1 lhs, IteratorInterface2 rhs) noexcept(
+        noexcept(detail::common_diff(lhs, rhs)))
+        -> decltype(
+            v1_dtl::derived_iterator(lhs), detail::common_diff(lhs, rhs) > 0)
+    {
+        return detail::common_diff(lhs, rhs) > 0;
+    }
+
+    /** Implementation of `operator>=()` for all iterators derived from
+        `iterator_interface` that have an iterator category derived from
+        `std::random_access_iterator_tag`.  */
+    template<typename IteratorInterface1, typename IteratorInterface2>
+    constexpr auto
+    operator>=(IteratorInterface1 lhs, IteratorInterface2 rhs) noexcept(
+        noexcept(detail::common_diff(lhs, rhs)))
+        -> decltype(
+            v1_dtl::derived_iterator(lhs), detail::common_diff(lhs, rhs) >= 0)
+    {
+        return detail::common_diff(lhs, rhs) >= 0;
+    }
+
+
+    /** A template alias useful for defining proxy iterators.  \see
+        `iterator_interface`. */
+    template<
+        typename Derived,
+        typename IteratorConcept,
+        typename ValueType,
+        typename Reference = ValueType,
+        typename DifferenceType = std::ptrdiff_t>
+    using proxy_iterator_interface = iterator_interface<
+        Derived,
+        IteratorConcept,
+        ValueType,
+        Reference,
+        proxy_arrow_result<Reference>,
+        DifferenceType>;
+
+}}}
+
+#ifdef BOOST_STL_INTERFACES_DOXYGEN
+
+/** `static_asserts` that type `type` models concept `concept_name`.  This is
+    useful for checking that an iterator, view, etc. that you write using one
+    of the *`_interface` templates models the right C++ concept.
+
+    For example: `BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(my_iter,
+    std::input_iterator)`.
+
+    \note This macro expands to nothing when `__cpp_lib_concepts` is not
+    defined. */
+#define BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(type, concept_name)
+
+/** `static_asserts` that the types of all typedefs in
+    `std::iterator_traits<iter>` match the remaining macro parameters.  This
+    is useful for checking that an iterator you write using
+    `iterator_interface` has the correct iterator traits.
+
+    For example: `BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS(my_iter,
+    std::input_iterator_tag, std::input_iterator_tag, int, int &, int *, std::ptrdiff_t)`.
+
+    \note This macro ignores the `concept` parameter when `__cpp_lib_concepts`
+    is not defined. */
+#define BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS(                    \
+    iter, category, concept, value_type, reference, pointer, difference_type)
+
+#else
+
+#define BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_CONCEPT_IMPL(              \
+    type, concept_name)                                                        \
+    static_assert(concept_name<type>, "");
+
+#define BOOST_STL_INTERFACES_STATIC_ASSERT_CONCEPT(iter, concept_name)
+
+#define BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS_IMPL(               \
+    iter, category, value_t, ref, ptr, diff_t)                                 \
+    static_assert(                                                             \
+        std::is_same<                                                          \
+            typename std::iterator_traits<iter>::iterator_category,            \
+            category>::value,                                                  \
+        "");                                                                   \
+    static_assert(                                                             \
+        std::is_same<                                                          \
+            typename std::iterator_traits<iter>::value_type,                   \
+            value_t>::value,                                                   \
+        "");                                                                   \
+    static_assert(                                                             \
+        std::is_same<typename std::iterator_traits<iter>::reference, ref>::    \
+            value,                                                             \
+        "");                                                                   \
+    static_assert(                                                             \
+        std::is_same<typename std::iterator_traits<iter>::pointer, ptr>::      \
+            value,                                                             \
+        "");                                                                   \
+    static_assert(                                                             \
+        std::is_same<                                                          \
+            typename std::iterator_traits<iter>::difference_type,              \
+            diff_t>::value,                                                    \
+        "");
+
+#if 201703L < __cplusplus && defined(__cpp_lib_ranges)
+#define BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS(                    \
+    iter, category, concept, value_type, reference, pointer, difference_type)  \
+    static_assert(                                                             \
+        std::is_same<                                                          \
+            typename std::iterator_traits<iter>::iterator_concept,             \
+            concept>::value,                                                   \
+        "");                                                                   \
+    BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS_IMPL(                   \
+        iter, category, value_type, reference, pointer, difference_type)
+#else
+#define BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS(                    \
+    iter, category, concept, value_type, reference, pointer, difference_type)  \
+    BOOST_STL_INTERFACES_STATIC_ASSERT_ITERATOR_TRAITS_IMPL(                   \
+        iter, category, value_type, reference, pointer, difference_type)
+#endif
+
+#endif
+
+#endif
index 55ba2e241feef8be35ef4b80bb4691f4f551d131..bdf1f3db8e57f7fc20713895356e9faa4eb896a9 100644 (file)
@@ -425,7 +425,7 @@ std::vector<MoleculePatchDatabase*> filter_ter(gmx::ArrayRef<MoleculePatchDataba
             if (gmx::equalCaseInsensitive(resname, s, 3))
             {
                 found = true;
-                list.push_back(it);
+                list.push_back(&*it);
             }
             else
             {
@@ -478,14 +478,14 @@ std::vector<MoleculePatchDatabase*> filter_ter(gmx::ArrayRef<MoleculePatchDataba
                 });
                 if (found == list.end())
                 {
-                    list.push_back(it);
+                    list.push_back(&*it);
                 }
             }
         }
     }
     if (none_idx != tb.end())
     {
-        list.push_back(none_idx);
+        list.push_back(&*none_idx);
     }
 
     return list;
index b095b823dca5913afd9689984da40259005913b7..d7efde7145a3558afe06b4933ea31cd869f115e6 100644 (file)
 #include <utility>
 #include <vector>
 
+#if __has_include(<boost/stl_interfaces/iterator_interface.hpp>)
+#    include <boost/stl_interfaces/iterator_interface.hpp>
+#else // fallback for installed headers
+#    include <gromacs/external/boost/stl_interfaces/iterator_interface.hpp>
+#endif
+
 #include "gromacs/utility/gmxassert.h"
 
 namespace gmx
 {
 
+template<class T>
+struct ArrayRefIter :
+    boost::stl_interfaces::iterator_interface<ArrayRefIter<T>, std::random_access_iterator_tag, T>
+{
+    // This default constructor does not initialize it_
+    constexpr ArrayRefIter() noexcept {}
+    constexpr explicit ArrayRefIter(T* it) noexcept : it_(it) {}
+    template<class T2 = T, class = std::enable_if_t<std::is_const<T2>::value>>
+    constexpr ArrayRefIter(ArrayRefIter<std::remove_const_t<T2>> it) noexcept : it_(&*it)
+    {
+    }
+
+    constexpr T&            operator*() const noexcept { return *it_; }
+    constexpr ArrayRefIter& operator+=(std::ptrdiff_t i) noexcept
+    {
+        it_ += i;
+        return *this;
+    }
+    constexpr auto operator-(ArrayRefIter other) const noexcept { return it_ - other.it_; }
+
+private:
+    T* it_;
+};
+
 /*! \brief STL-like interface to a C array of T (or part
  * of a std container of T).
  *
@@ -115,13 +145,13 @@ public:
     //! Const pointer to an element.
     typedef const T* const_pointer;
     //! Const iterator type to an element.
-    typedef const T* const_iterator;
+    typedef ArrayRefIter<const T> const_iterator;
     //! Reference to an element.
     typedef T& reference;
     //! Pointer to an element.
     typedef T* pointer;
     //! Iterator type to an element.
-    typedef T* iterator;
+    typedef ArrayRefIter<T> iterator;
     //! Standard reverse iterator.
     typedef std::reverse_iterator<iterator> reverse_iterator;
     //! Standard reverse iterator.
@@ -162,6 +192,18 @@ public:
     {
         GMX_ASSERT(end >= begin, "Invalid range");
     }
+    /*! \brief
+     * Constructs a reference to a particular range.
+     *
+     * \param[in] begin  Iterator to the beginning of a range.
+     * \param[in] end    iterator to the end of a range.
+     *
+     * Passed iterators must remain valid for the lifetime of this object.
+     */
+    ArrayRef(iterator begin, iterator end) : begin_(begin), end_(end)
+    {
+        GMX_ASSERT(end >= begin, "Invalid range");
+    }
     //! \cond
     // Doxygen 1.8.5 doesn't parse the declaration correctly...
     /*! \brief
@@ -192,9 +234,9 @@ public:
         return { begin_ + start, begin_ + start + count };
     }
     //! Returns an iterator to the beginning of the reference.
-    iterator begin() const { return begin_; }
+    iterator begin() const { return iterator(begin_); }
     //! Returns an iterator to the end of the reference.
-    iterator end() const { return end_; }
+    iterator end() const { return iterator(end_); }
     //! Returns an iterator to the reverse beginning of the reference.
     reverse_iterator rbegin() const { return reverse_iterator(end()); }
     //! Returns an iterator to the reverse end of the reference.
@@ -230,7 +272,7 @@ public:
     reference back() const { return *(end_ - 1); }
 
     //! Returns a raw pointer to the contents of the array.
-    pointer data() const { return begin_; }
+    pointer data() const { return &*begin_; }
 
     /*! \brief
      * Swaps referenced memory with the other object.
@@ -245,8 +287,8 @@ public:
     }
 
 private:
-    pointer begin_;
-    pointer end_;
+    iterator begin_;
+    iterator end_;
 };
 
 //! \copydoc ArrayRef::fromArray()