Reaktoro  v2.11.0
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-2024 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 
47  using CacheType = Type;
48 
56  static auto equal(const CacheType& a, const Type& b)
57  {
58  return a == b;
59  }
60 
64  static auto assign(CacheType& a, const Type& b)
65  {
66  a = b;
67  }
68 };
69 
70 namespace detail {
71 
73 template<typename CacheType, typename T>
74 constexpr auto sameValue(const CacheType& a, const T& b)
75 {
76  return MemoizationTraits<Decay<T>>::equal(a, b);
77 };
78 
80 template<typename CacheType, typename T>
81 constexpr auto assignValue(CacheType& a, const T& b)
82 {
83  return MemoizationTraits<Decay<T>>::assign(a, b);
84 };
85 
87 template<typename Tuple1, typename Tuple2>
88 auto sameValues(const Tuple1& tuple1, const Tuple2& tuple2)
89 {
90  using std::tuple_size_v;
91  using std::get;
92  constexpr auto N1 = tuple_size_v<Tuple1>;
93  constexpr auto N2 = tuple_size_v<Tuple2>;
94  static_assert(N1 == N2);
95  bool res = true;
96  For<N1>([&](auto i) constexpr {
97  res = res && sameValue(get<i>(tuple1), get<i>(tuple2));
98  });
99  return res;
100 }
101 
103 template<typename Tuple1, typename Tuple2>
104 auto assignValues(Tuple1& tuple1, const Tuple2& tuple2)
105 {
106  using std::tuple_size_v;
107  using std::get;
108  constexpr auto N1 = tuple_size_v<Tuple1>;
109  constexpr auto N2 = tuple_size_v<Tuple2>;
110  static_assert(N1 == N2);
111  For<N1>([&](auto i) constexpr {
112  assignValue(get<i>(tuple1), get<i>(tuple2));
113  });
114 }
115 
117 template<typename T>
118 using CacheType = typename MemoizationTraits<Decay<T>>::CacheType;
119 
120 } // namespace detail
121 
124 {
125 public:
127  static auto isEnabled() -> bool;
128 
130  static auto isDisabled() -> bool;
131 
133  static auto enable() -> void;
134 
136  static auto disable() -> void;
137 
139  Memoization() = delete;
140 };
141 
143 template<typename Ret, typename... Args>
144 auto memoize(Fn<Ret(Args...)> f) -> Fn<Ret(Args...)>
145 {
146  auto cache = std::make_shared<Map<Tuple<Args...>, Ret>>();
147  return [=](Args... args) mutable -> Ret
148  {
150  return f(args...);
151  Tuple<Args...> t(args...);
152  if(cache->find(t) == cache->end())
153  (*cache)[t] = f(args...);
154  return (*cache)[t];
155  };
156 }
157 
159 template<typename Fun, Requires<!isFunction<Fun>> = true>
160 auto memoize(Fun f)
161 {
162  return memoize(asFunction(f));
163 }
164 
166 template<typename Ret, typename... Args>
167 auto memoizeLast(Fn<Ret(Args...)> f) -> Fn<Ret(Args...)>
168 {
170  Ret result = Ret();
171  auto firsttime = true;
172  return [=](Args... args) mutable -> Ret
173  {
175  return f(args...);
176  if(detail::sameValues(cache, std::tie(args...)) && !firsttime)
177  return Ret(result);
178  detail::assignValues(cache, std::tie(args...));
179  firsttime = false;
180  return result = f(args...);
181  };
182 }
183 
185 template<typename Fun, Requires<!isFunction<Fun>> = true>
186 auto memoizeLast(Fun f)
187 {
188  return memoizeLast(asFunction(f));
189 }
190 
192 template<typename Ret, typename RetRef, typename... Args>
193 auto memoizeLastUsingRef(Fn<void(RetRef, Args...)> f) -> Fn<void(RetRef, Args...)>
194 {
196  Ret result = Ret();
197  auto firsttime = true;
198  return [=](RetRef res, Args... args) mutable -> void
199  {
201  f(res, args...);
202  else if(detail::sameValues(cache, std::tie(args...)) && !firsttime)
203  res = result;
204  else
205  {
206  f(res, args...);
207  result = res;
208  detail::assignValues(cache, std::tie(args...));
209  }
210  firsttime = false;
211  };
212 }
213 
217 template<typename Ret, typename Fun, Requires<!isFunction<Fun>> = true>
219 {
220  return memoizeLastUsingRef<Ret>(asFunction(f));
221 }
222 
225 template<typename Ret, typename... Args>
226 auto memoizeLastUsingRef(Fn<void(Ret&, Args...)> f) -> Fn<void(Ret&, Args...)>
227 {
228  return memoizeLastUsingRef<Ret, Ret&>(f);
229 }
230 
234 template<typename Fun, Requires<!isFunction<Fun>> = true>
236 {
237  return memoizeLastUsingRef(asFunction(f));
238 }
239 
240 } // namespace Reaktoro
The class used to control memoization in the application.
Definition: Memoization.hpp:124
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:29
auto memoize(Fn< Ret(Args...)> f) -> Fn< Ret(Args...)>
Return a memoized version of given function f.
Definition: Memoization.hpp:144
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:193
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:167
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:64
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:56
Type CacheType
The type of the object constructed with a given object of type T.
Definition: Memoization.hpp:47