1 /* Copyright 2009-2016 Francesco Biscani (bluescarni@gmail.com) 2 3 This file is part of the Piranha library. 4 5 The Piranha library is free software; you can redistribute it and/or modify 6 it under the terms of either: 7 8 * the GNU Lesser General Public License as published by the Free 9 Software Foundation; either version 3 of the License, or (at your 10 option) any later version. 11 12 or 13 14 * the GNU General Public License as published by the Free Software 15 Foundation; either version 3 of the License, or (at your option) any 16 later version. 17 18 or both in parallel, as here. 19 20 The Piranha library is distributed in the hope that it will be useful, but 21 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 22 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 23 for more details. 24 25 You should have received copies of the GNU General Public License and the 26 GNU Lesser General Public License along with the Piranha library. If not, 27 see https://www.gnu.org/licenses/. */ 28 29 #ifndef PIRANHA_TERM_HPP 30 #define PIRANHA_TERM_HPP 31 32 #include <cstddef> 33 #include <functional> 34 #include <type_traits> 35 #include <utility> 36 37 #include "is_cf.hpp" 38 #include "is_key.hpp" 39 #include "math.hpp" 40 #include "symbol_set.hpp" 41 #include "type_traits.hpp" 42 43 namespace piranha 44 { 45 46 namespace detail 47 { 48 49 // Tag for piranha::term. 50 struct term_tag { 51 }; 52 } 53 54 /// Term class. 55 /** 56 * This class represents series terms, which are parametrised over a coefficient type \p Cf and a key type 57 * \p Key. One mutable coefficient instance and one key instance are the only data members and they can be accessed 58 * directly. 59 * 60 * ## Type requirements ## 61 * 62 * - \p Cf must satisfy piranha::is_cf. 63 * - \p Key must satisfy piranha::is_key. 64 * 65 * ## Exception safety guarantee ## 66 * 67 * This class provides the strong exception safety guarantee for all operations. 68 * 69 * ## Move semantics ## 70 * 71 * Move semantics is equivalent to its data members' move semantics. 72 */ 73 template <typename Cf, typename Key> 74 class term : detail::term_tag 75 { 76 PIRANHA_TT_CHECK(is_cf, Cf); 77 PIRANHA_TT_CHECK(is_key, Key); 78 // Enabler for the generic binary ctor. 79 template <typename T, typename U> 80 using binary_ctor_enabler = 81 typename std::enable_if<std::is_constructible<Cf, T &&>::value && std::is_constructible<Key, U &&>::value, 82 int>::type; 83 84 public: 85 /// Alias for coefficient type. 86 typedef Cf cf_type; 87 /// Alias for key type. 88 typedef Key key_type; 89 /// Default constructor. 90 /** 91 * Will explicitly call the default constructors of <tt>Cf</tt> and <tt>Key</tt>. 92 * 93 * @throws unspecified any exception thrown by the default constructors of \p Cf and \p Key. 94 */ term()95 term() : m_cf(), m_key() 96 { 97 } 98 /// Default copy constructor. 99 /** 100 * @throws unspecified any exception thrown by the copy constructors of \p Cf and \p Key. 101 */ 102 term(const term &) = default; 103 /// Defaulted move constructor. 104 term(term &&) = default; 105 /// Constructor from generic coefficient and key. 106 /** 107 * \note 108 * This constructor is activated only if coefficient and key are constructible from \p T and \p U. 109 * 110 * This constructor will forward perfectly \p cf and \p key to construct coefficient and key. 111 * 112 * @param cf argument used for the construction of the coefficient. 113 * @param key argument used for the construction of the key. 114 * 115 * @throws unspecified any exception thrown by the constructors of \p Cf and \p Key. 116 */ 117 template <typename T, typename U, binary_ctor_enabler<T, U> = 0> term(T && cf,U && key)118 explicit term(T &&cf, U &&key) : m_cf(std::forward<T>(cf)), m_key(std::forward<U>(key)) 119 { 120 } 121 /// Trivial destructor. ~term()122 ~term() 123 { 124 PIRANHA_TT_CHECK(is_container_element, term); 125 } 126 /// Copy assignment operator. 127 /** 128 * @param other assignment argument. 129 * 130 * @return reference to \p this. 131 * 132 * @throws unspecified any exception thrown by the copy constructors of \p Cf and \p Key. 133 */ operator =(const term & other)134 term &operator=(const term &other) 135 { 136 if (likely(this != &other)) { 137 term tmp(other); 138 *this = std::move(tmp); 139 } 140 return *this; 141 } 142 /// Trivial move-assignment operator. 143 /** 144 * @param other assignment argument. 145 * 146 * @return reference to \p this. 147 */ operator =(term && other)148 term &operator=(term &&other) noexcept 149 { 150 if (likely(this != &other)) { 151 m_cf = std::move(other.m_cf); 152 m_key = std::move(other.m_key); 153 } 154 return *this; 155 } 156 /// Equality operator. 157 /** 158 * Equivalence of terms is defined by the equivalence of their keys. 159 * 160 * @param other comparison argument. 161 * 162 * @return <tt>m_key == other.m_key</tt>. 163 * 164 * @throws unspecified any exception thrown by the equality operators of \p Key. 165 */ operator ==(const term & other) const166 bool operator==(const term &other) const 167 { 168 return m_key == other.m_key; 169 } 170 /// Hash value. 171 /** 172 * The term's hash value is given by its key's hash value. 173 * 174 * @return hash value of \p m_key as calculated via a default-constructed instance of \p std::hash. 175 * 176 * @throws unspecified any exception thrown by the hash functor of \p Key. 177 */ hash() const178 std::size_t hash() const 179 { 180 return std::hash<key_type>()(m_key); 181 } 182 /// Compatibility test. 183 /** 184 * @param args reference arguments set. 185 * 186 * @return the key's <tt>is_compatible()</tt> method's return value. 187 */ is_compatible(const symbol_set & args) const188 bool is_compatible(const symbol_set &args) const noexcept 189 { 190 // NOTE: if this (and is_ignorable) are made re-implementable at a certain point in derived term classes, 191 // we must take care of asserting noexcept on the corresponding methods in the derived class. 192 return m_key.is_compatible(args); 193 } 194 /// Ignorability test. 195 /** 196 * Note that this method is not allowed to throw, so any exception thrown by calling piranha::math::is_zero() on the 197 * coefficient 198 * will result in the termination of the program. 199 * 200 * @param args reference arguments set. 201 * 202 * @return \p true if either the key's <tt>is_ignorable()</tt> method or piranha::math::is_zero() on the coefficient 203 * return \p true, 204 * \p false otherwise. 205 */ is_ignorable(const symbol_set & args) const206 bool is_ignorable(const symbol_set &args) const noexcept 207 { 208 return (math::is_zero(m_cf) || m_key.is_ignorable(args)); 209 } 210 /// Coefficient member. 211 mutable Cf m_cf; 212 /// Key member. 213 Key m_key; 214 }; 215 216 namespace detail 217 { 218 219 // Enabler for the enable_noexcept_checks specialisation for terms. 220 template <typename T> 221 using term_enc_enabler = typename std::enable_if<std::is_base_of<detail::term_tag, T>::value>::type; 222 } 223 224 /// Specialisation of piranha::enable_noexcept_checks for piranha::term. 225 /** 226 * This specialisation is activated when \p T is an instance of piranha::term. The value of the type trait 227 * is set to \p true if both the coefficient and key types satisfy piranha::enable_noexcept_checks. Otherwise, 228 * the value of the type trait is set to \p false. 229 */ 230 template <typename T> 231 struct enable_noexcept_checks<T, detail::term_enc_enabler<T>> { 232 private: 233 static const bool implementation_defined 234 = enable_noexcept_checks<typename T::cf_type>::value && enable_noexcept_checks<typename T::key_type>::value; 235 236 public: 237 /// Value of the type trait. 238 static const bool value = implementation_defined; 239 }; 240 241 template <typename T> 242 const bool enable_noexcept_checks<T, typename std::enable_if<std::is_base_of<detail::term_tag, T>::value>::type>::value; 243 } 244 245 #endif 246