diff --git a/src/common/utilities.hh b/src/common/utilities.hh index 3fe50a4..f918ed1 100644 --- a/src/common/utilities.hh +++ b/src/common/utilities.hh @@ -1,308 +1,306 @@ /** * @file utilities.hh * * @author Till Junge * * @date 17 Nov 2017 * * @brief additions to the standard name space to anticipate C++17 features * * Copyright © 2017 Till Junge * * µSpectre 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 3, or (at * your option) any later version. * * µSpectre 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 * General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with µSpectre; see the file COPYING. If not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * * Boston, MA 02111-1307, USA. * * Additional permission under GNU GPL version 3 section 7 * * If you modify this Program, or any covered work, by linking or combining it * with proprietary FFT implementations or numerical libraries, containing parts * covered by the terms of those libraries' licenses, the licensors of this * Program grant you additional permission to convey the resulting work. */ #ifndef UTILITIES_H #define UTILITIES_H -#include - #include #ifdef NO_EXPERIMENTAL # include #else # include #endif namespace std_replacement { namespace detail { template struct is_reference_wrapper : std::false_type {}; template struct is_reference_wrapper> : std::true_type {}; //! from cppreference template auto INVOKE(T Base::*pmf, Derived&& ref, Args&&... args) noexcept(noexcept((std::forward(ref).*pmf)(std::forward(args)...))) -> std::enable_if_t::value && std::is_base_of>::value, decltype((std::forward(ref).*pmf)(std::forward(args)...))> { return (std::forward(ref).*pmf)(std::forward(args)...); } //! from cppreference template auto INVOKE(T Base::*pmf, RefWrap&& ref, Args&&... args) noexcept(noexcept((ref.get().*pmf)(std::forward(args)...))) -> std::enable_if_t::value && is_reference_wrapper>::value, decltype((ref.get().*pmf)(std::forward(args)...))> { return (ref.get().*pmf)(std::forward(args)...); } //! from cppreference template auto INVOKE(T Base::*pmf, Pointer&& ptr, Args&&... args) noexcept(noexcept(((*std::forward(ptr)).*pmf)(std::forward(args)...))) -> std::enable_if_t::value && !is_reference_wrapper>::value && !std::is_base_of>::value, decltype(((*std::forward(ptr)).*pmf)(std::forward(args)...))> { return ((*std::forward(ptr)).*pmf)(std::forward(args)...); } //! from cppreference template auto INVOKE(T Base::*pmd, Derived&& ref) noexcept(noexcept(std::forward(ref).*pmd)) -> std::enable_if_t::value && std::is_base_of>::value, decltype(std::forward(ref).*pmd)> { return std::forward(ref).*pmd; } //! from cppreference template auto INVOKE(T Base::*pmd, RefWrap&& ref) noexcept(noexcept(ref.get().*pmd)) -> std::enable_if_t::value && is_reference_wrapper>::value, decltype(ref.get().*pmd)> { return ref.get().*pmd; } //! from cppreference template auto INVOKE(T Base::*pmd, Pointer&& ptr) noexcept(noexcept((*std::forward(ptr)).*pmd)) -> std::enable_if_t::value && !is_reference_wrapper>::value && !std::is_base_of>::value, decltype((*std::forward(ptr)).*pmd)> { return (*std::forward(ptr)).*pmd; } //! from cppreference template auto INVOKE(F&& f, Args&&... args) noexcept(noexcept(std::forward(f)(std::forward(args)...))) -> std::enable_if_t>::value, decltype(std::forward(f)(std::forward(args)...))> { return std::forward(f)(std::forward(args)...); } } // namespace detail //! from cppreference template< class F, class... ArgTypes > auto invoke(F&& f, ArgTypes&&... args) // exception specification for QoI noexcept(noexcept(detail::INVOKE(std::forward(f), std::forward(args)...))) -> decltype(detail::INVOKE(std::forward(f), std::forward(args)...)) { return detail::INVOKE(std::forward(f), std::forward(args)...); } namespace detail { //! from cppreference template constexpr decltype(auto) apply_impl(F &&f, Tuple &&t, std::index_sequence) { return std_replacement::invoke(std::forward(f), std::get(std::forward(t))...); } } // namespace detail //! from cppreference template constexpr decltype(auto) apply(F &&f, Tuple &&t) { return detail::apply_impl (std::forward(f), std::forward(t), std::make_index_sequence>::value>{}); } } //namespace std_replacement namespace muSpectre { namespace internal { /** * helper struct template to compute the type of a tuple with a * given number of entries of the same type */ template struct tuple_array_helper { //! underlying tuple using type = typename tuple_array_helper::type; }; /** * helper struct template to compute the type of a tuple with a * given number of entries of the same type */ template< typename T, typename... tail> struct tuple_array_helper<0, T, tail...> { //! underlying tuple using type = std::tuple; }; /** * helper struct for runtime index access to * tuples. RecursionLevel indicates how much more we can recurse * down */ template struct Accessor { using Stored_t = typename TupArr::Stored_t; inline static Stored_t get(const size_t & index, TupArr & container) { if (index == Index) { return std::get(container); } else { return Accessor::get(index, container); } } inline static const Stored_t get(const size_t & index, const TupArr & container) { if (index == Index) { return std::get(container); } else { return Accessor::get(index, container); } } }; /** * specialisation for recursion end */ template struct Accessor { using Stored_t = typename TupArr::Stored_t; inline static Stored_t get(const size_t & index, TupArr & container) { if (index == Index) { return std::get(container); } else { std::stringstream err{}; err << "Index " << index << "is out of range."; throw std::runtime_error(err.str()); } } inline static const Stored_t get(const size_t & index, const TupArr & container) { if (index == Index) { return std::get(container); } else { std::stringstream err{}; err << "Index " << index << "is out of range."; throw std::runtime_error(err.str()); } } }; /** * helper struct that provides the tuple_array. */ template struct tuple_array_provider { //! tuple type that can be used (almost) like an `std::array` class type: public tuple_array_helper::type { public: //! short-hand using Parent = typename tuple_array_helper::type; using Stored_t = T; constexpr static size_t Size{size}; //! constructor inline type(Parent && parent):Parent{parent}{}; //! element access T operator[] (const size_t & index) { return Accessor::get(index, *this); } //! element access const T operator[](const size_t & index) const { return Accessor::get(index, *this); } protected: }; }; } // internal /** * This is a convenience structure to create a tuple of `nb_elem` * entries of type `T`. It is named tuple_array, because it is * somewhat similar to an `std::array`. The reason for * this structure is that the `std::array` is not allowed by the * standard to store references (8.3.2 References, paragraph 5: * "There shall be no references to references, no arrays of * references, and no pointers to references.") use this, if you * want to have a statically known number of references to store, * and you wish to do so efficiently. */ template using tuple_array = typename internal::tuple_array_provider::type; using std_replacement::apply; /** * emulation `std::optional` (a C++17 feature) */ template #ifdef NO_EXPERIMENTAL using optional = typename boost::optional; #else using optional = typename std::experimental::optional; #endif } // muSpectre #endif /* UTILITIES_H */