Reaktoro  v2.9.2
A unified framework for modeling chemically reactive systems
Memoization.hpp
1 // Reaktoro is a unified framework for modeling chemically reactive systems.
2 //
3 // Copyright © 2014-2022 Allan Leal
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with this library. If not, see <http://www.gnu.org/licenses/>.
17 
18 #pragma once
19 
20 // Reaktoro includes
21 #include <Reaktoro/Common/Meta.hpp>
22 #include <Reaktoro/Common/TraitsUtils.hpp>
23 #include <Reaktoro/Common/Types.hpp>
24 
25 namespace Reaktoro {
26 
28 template<typename T>
30 {
32  using Type = Decay<T>;
33 
56  using CacheType = Type;
57 
65  static auto equal(const CacheType& a, const Type& b)
66  {
67  return a == b;
68  }
69 
73  static auto assign(CacheType& a, const Type& b)
74  {
75  a = b;
76  }
77 };
78 
79 namespace detail {
80 
82 template<typename CacheType, typename T>
83 constexpr auto sameValue(const CacheType& a, const T& b)
84 {
85  return MemoizationTraits<Decay<T>>::equal(a, b);
86 };
87 
89 template<typename CacheType, typename T>
90 constexpr auto assignValue(CacheType& a, const T& b)
91 {
92  return MemoizationTraits<Decay<T>>::assign(a, b);
93 };
94 
96 template<typename Tuple1, typename Tuple2>
97 auto sameValues(const Tuple1& tuple1, const Tuple2& tuple2)
98 {
99  using std::tuple_size_v;
100  using std::get;
101  constexpr auto N1 = tuple_size_v<Tuple1>;
102  constexpr auto N2 = tuple_size_v<Tuple2>;
103  static_assert(N1 == N2);
104  bool res = true;
105  For<N1>([&](auto i) constexpr {
106  res = res && sameValue(get<i>(tuple1), get<i>(tuple2));
107  });
108  return res;
109 }
110 
112 template<typename Tuple1, typename Tuple2>
113 auto assignValues(Tuple1& tuple1, const Tuple2& tuple2)
114 {
115  using std::tuple_size_v;
116  using std::get;
117  constexpr auto N1 = tuple_size_v<Tuple1>;
118  constexpr auto N2 = tuple_size_v<Tuple2>;
119  static_assert(N1 == N2);
120  For<N1>([&](auto i) constexpr {
121  assignValue(get<i>(tuple1), get<i>(tuple2));
122  });
123 }
124 
126 template<typename T>
127 using CacheType = typename MemoizationTraits<Decay<T>>::CacheType;
128 
129 } // namespace detail
130 
133 {
134 public:
136  static auto isEnabled() -> bool;
137 
139  static auto isDisabled() -> bool;
140 
142  static auto enable() -> void;
143 
145  static auto disable() -> void;
146 
148  Memoization() = delete;
149 };
150 
152 template<typename Ret, typename... Args>
153 auto memoize(Fn<Ret(Args...)> f) -> Fn<Ret(Args...)>
154 {
155  auto cache = std::make_shared<Map<Tuple<Args...>, Ret>>();
156  return [=](Args... args) mutable -> Ret
157  {
159  return f(args...);
160  Tuple<Args...> t(args...);
161  if(cache->find(t) == cache->end())
162  (*cache)[t] = f(args...);
163  return (*cache)[t];
164  };
165 }
166 
168 template<typename Fun, Requires<!isFunction<Fun>> = true>
169 auto memoize(Fun f)
170 {
171  return memoize(asFunction(f));
172 }
173 
175 template<typename Ret, typename... Args>
176 auto memoizeLast(Fn<Ret(Args...)> f) -> Fn<Ret(Args...)>
177 {
179  Ret result = Ret();
180  auto firsttime = true;
181  return [=](Args... args) mutable -> Ret
182  {
184  return f(args...);
185  if(detail::sameValues(cache, std::tie(args...)) && !firsttime)
186  return Ret(result);
187  detail::assignValues(cache, std::tie(args...));
188  firsttime = false;
189  return result = f(args...);
190  };
191 }
192 
194 template<typename Fun, Requires<!isFunction<Fun>> = true>
195 auto memoizeLast(Fun f)
196 {
197  return memoizeLast(asFunction(f));
198 }
199 
201 template<typename Ret, typename RetRef, typename... Args>
202 auto memoizeLastUsingRef(Fn<void(RetRef, Args...)> f) -> Fn<void(RetRef, Args...)>
203 {
205  Ret result = Ret();
206  auto firsttime = true;
207  return [=](RetRef res, Args... args) mutable -> void
208  {
210  f(res, args...);
211  else if(detail::sameValues(cache, std::tie(args...)) && !firsttime)
212  res = result;
213  else
214  {
215  f(res, args...);
216  result = res;
217  detail::assignValues(cache, std::tie(args...));
218  }
219  firsttime = false;
220  };
221 }
222 
226 template<typename Ret, typename Fun, Requires<!isFunction<Fun>> = true>
228 {
229  return memoizeLastUsingRef<Ret>(asFunction(f));
230 }
231 
234 template<typename Ret, typename... Args>
235 auto memoizeLastUsingRef(Fn<void(Ret&, Args...)> f) -> Fn<void(Ret&, Args...)>
236 {
237  return memoizeLastUsingRef<Ret, Ret&>(f);
238 }
239 
243 template<typename Fun, Requires<!isFunction<Fun>> = true>
245 {
246  return memoizeLastUsingRef(asFunction(f));
247 }
248 
249 } // namespace Reaktoro
The class used to control memoization in the application.
Definition: Memoization.hpp:133
Memoization()=delete
Deleted default constructor.
static auto isDisabled() -> bool
Return true if memoization is currently disabled.
static auto isEnabled() -> bool
Return true if memoization is currently enabled.
static auto enable() -> void
Enable memoization optimization.
static auto disable() -> void
Disable memoization optimization.
The namespace containing all components of the Reaktoro library.
Definition: Algorithms.hpp:28
auto memoize(Fn< Ret(Args...)> f) -> Fn< Ret(Args...)>
Return a memoized version of given function f.
Definition: Memoization.hpp:153
auto memoizeLastUsingRef(Fn< void(RetRef, Args...)> f) -> Fn< void(RetRef, Args...)>
Return a memoized version of given function f that caches only the arguments used in the last call.
Definition: Memoization.hpp:202
auto memoizeLast(Fn< Ret(Args...)> f) -> Fn< Ret(Args...)>
Return a memoized version of given function f that caches only the arguments used in the last call.
Definition: Memoization.hpp:176
constexpr auto asFunction(const Fun &f)
Convert lambda/function pointers/member functions to std::function.
Definition: TraitsUtils.hpp:92
std::tuple< Args... > Tuple
Convenient alias for std::tuple<Args...>.
Definition: Types.hpp:94
std::function< F > Fn
Convenient alias for std::function<R(Args...)>.
Definition: Types.hpp:110
std::unordered_map< Key, T > Map
Convenient alias for std::unordered_map<Key, T>.
Definition: Types.hpp:74
Used to enable function arguments of a type T to be cached in a memoized version of the function.
Definition: Memoization.hpp:30
static auto assign(CacheType &a, const Type &b)
Assign the value of b, of type T, into a, of type CacheType.
Definition: Memoization.hpp:73
Decay< T > Type
The type T without const, reference, and pointer specifiers.
Definition: Memoization.hpp:32
static auto equal(const CacheType &a, const Type &b)
Check if a, of type CacheType, is equal to b, of type T.
Definition: Memoization.hpp:65
Type CacheType
The type of the object constructed with a given object of type T.
Definition: Memoization.hpp:56