Apply clang-format to source tree
[alexxy/gromacs.git] / src / gromacs / compat / pointers.h
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2018,2019, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35
36 /*! \libinternal \file
37  * \brief Provides ported functions/classes from gsl/pointers
38  *
39  * Adapted from the Guidelines Support Library v2.0.0. at
40  * https://github.com/Microsoft/GSL
41  *
42  * \author Mark Abraham <mark.j.abraham@gmail.com>
43  * \ingroup module_compat
44  * \inlibraryapi
45  */
46 #ifndef GMX_COMPAT_POINTERS_H
47 #define GMX_COMPAT_POINTERS_H
48
49 #include <type_traits>
50 #include <utility>
51
52 #include "gromacs/utility/gmxassert.h"
53
54 namespace gmx
55 {
56 namespace compat
57 {
58
59 //! Contract-assurance macros that work like a simple version of the GSL ones
60 //! \{
61 #if !defined(__INTEL_COMPILER) || !(__INTEL_COMPILER == 1800 && __INTEL_COMPILER_UPDATE == 0)
62 #    define Expects(cond) GMX_ASSERT((cond), "Precondition violation")
63 #    define Ensures(cond) GMX_ASSERT((cond), "Postcondition violation")
64 #else
65 // icc 18.0.0 in a RelWithAssert build has an ICE, even if we directly
66 // embed the contents of GMX_ASSERT, so it seems the lambda in
67 // GMX_ASSERT is too complex for it in this use case.
68 #    define Expects(cond)
69 #    define Ensures(cond)
70 #endif
71 //! \}
72
73 /*! \libinternal
74  * \brief Restricts a pointer or smart pointer to only hold non-null values.
75  *
76  * Has zero size overhead over T.
77  *
78  * If T is a pointer (i.e. T == U*) then
79  * - allow construction from U*
80  * - disallow construction from nullptr_t
81  * - disallow default construction
82  * - ensure construction from null U* fails (only in debug builds)
83  * - allow implicit conversion to U*
84  *
85  * \todo Eliminate this when we require a version of C++ that supports
86  * std::not_null.
87  */
88 template<class T>
89 class not_null
90 {
91 public:
92     static_assert(std::is_assignable<T&, std::nullptr_t>::value, "T cannot be assigned nullptr.");
93
94     //! Move constructor. Asserts in debug mode if \c is nullptr.
95     template<typename U, typename = typename std::enable_if<std::is_convertible<U, T>::value>::type>
96     constexpr explicit not_null(U&& u) : ptr_(std::forward<U>(u))
97     {
98         Expects(ptr_ != nullptr);
99     }
100
101     //! Simple constructor. Asserts in debug mode if \c u is nullptr.
102     template<typename = typename std::enable_if<!std::is_same<std::nullptr_t, T>::value>::type>
103     constexpr explicit not_null(T u) : ptr_(u)
104     {
105         Expects(ptr_ != nullptr);
106     }
107
108     //! Copy constructor.
109     template<typename U, typename = typename std::enable_if<std::is_convertible<U, T>::value>::type>
110     constexpr not_null(const not_null<U>& other) : not_null(other.get())
111     {
112     }
113
114     //! Default constructors and assignment.
115     //! \{
116     not_null(not_null&& other) noexcept = default;
117     not_null(const not_null& other)     = default;
118     not_null& operator=(const not_null& other) = default;
119     //! \}
120
121     //! Getters
122     //! \{
123     constexpr T get() const
124     {
125         Ensures(ptr_ != nullptr);
126         return ptr_;
127     }
128
129     constexpr   operator T() const { return get(); }
130     constexpr T operator->() const { return get(); }
131     //! \}
132
133     //! Deleted to prevent compilation when someone attempts to assign a null pointer constant.
134     //! \{
135     not_null(std::nullptr_t) = delete;
136     not_null& operator=(std::nullptr_t) = delete;
137     //! \}
138
139     //! Deleted unwanted operators because pointers only point to single objects.
140     //! \{
141     not_null& operator++()                     = delete;
142     not_null& operator--()                     = delete;
143     not_null  operator++(int)                  = delete;
144     not_null  operator--(int)                  = delete;
145     not_null& operator+=(std::ptrdiff_t)       = delete;
146     not_null& operator-=(std::ptrdiff_t)       = delete;
147     void      operator[](std::ptrdiff_t) const = delete;
148     //! \}
149
150 private:
151     T ptr_;
152 };
153
154 //! Convenience function for making not_null pointers from plain pointers.
155 template<class T>
156 not_null<T> make_not_null(T&& t)
157 {
158     return not_null<typename std::remove_cv<typename std::remove_reference<T>::type>::type>{
159         std::forward<T>(t)
160     };
161 }
162
163 //! Convenience function for making not_null pointers from smart pointers.
164 template<class T>
165 not_null<typename T::pointer> make_not_null(T& t)
166 {
167     return not_null<typename std::remove_reference<T>::type::pointer>{ t.get() };
168 }
169
170 //! Operators to compare not_null pointers.
171 //! \{
172 template<class T, class U>
173 auto operator==(const not_null<T>& lhs, const not_null<U>& rhs) -> decltype(lhs.get() == rhs.get())
174 {
175     return lhs.get() == rhs.get();
176 }
177
178 template<class T, class U>
179 auto operator!=(const not_null<T>& lhs, const not_null<U>& rhs) -> decltype(lhs.get() != rhs.get())
180 {
181     return lhs.get() != rhs.get();
182 }
183
184 template<class T, class U>
185 auto operator<(const not_null<T>& lhs, const not_null<U>& rhs) -> decltype(lhs.get() < rhs.get())
186 {
187     return lhs.get() < rhs.get();
188 }
189
190 template<class T, class U>
191 auto operator<=(const not_null<T>& lhs, const not_null<U>& rhs) -> decltype(lhs.get() <= rhs.get())
192 {
193     return lhs.get() <= rhs.get();
194 }
195
196 template<class T, class U>
197 auto operator>(const not_null<T>& lhs, const not_null<U>& rhs) -> decltype(lhs.get() > rhs.get())
198 {
199     return lhs.get() > rhs.get();
200 }
201
202 template<class T, class U>
203 auto operator>=(const not_null<T>& lhs, const not_null<U>& rhs) -> decltype(lhs.get() >= rhs.get())
204 {
205     return lhs.get() >= rhs.get();
206 }
207 //! \}
208
209 //! Deleted unwanted arithmetic operators.
210 //! \{
211 template<class T, class U>
212 std::ptrdiff_t operator-(const not_null<T>&, const not_null<U>&) = delete;
213 template<class T>
214 not_null<T> operator-(const not_null<T>&, std::ptrdiff_t) = delete;
215 template<class T>
216 not_null<T> operator+(const not_null<T>&, std::ptrdiff_t) = delete;
217 template<class T>
218 not_null<T> operator+(std::ptrdiff_t, const not_null<T>&) = delete;
219 //! \}
220
221 } // namespace compat
222 } // namespace gmx
223
224 #endif