generic_shared_internal.hpp
1 /*
2  * This file is part of CasADi.
3  *
4  * CasADi -- A symbolic framework for dynamic optimization.
5  * Copyright (C) 2010-2023 Joel Andersson, Joris Gillis, Moritz Diehl,
6  * KU Leuven. All rights reserved.
7  * Copyright (C) 2011-2014 Greg Horn
8  *
9  * CasADi is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 3 of the License, or (at your option) any later version.
13  *
14  * CasADi 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 CasADi; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  *
23  */
24 
25 
26 #ifndef CASADI_GENERIC_SHARED_INTERNAL_HPP
27 #define CASADI_GENERIC_SHARED_INTERNAL_HPP
28 
29 #include "generic_shared.hpp"
30 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
31 #include <memory>
32 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
33 
34 #ifdef CASADI_WITH_THREAD
35 #include <atomic>
36 #endif // CASADI_WITH_THREAD
37 
38 namespace casadi {
39 
42  template<typename Shared, typename Internal>
43  class GenericSharedInternal {
44  friend class GenericShared<Shared, Internal>;
45  public:
46 
48  GenericSharedInternal();
49 
51  GenericSharedInternal(const GenericSharedInternal& node);
52 
54  GenericSharedInternal& operator=(const GenericSharedInternal& node);
55 
57  virtual ~GenericSharedInternal() = 0;
58 
60  casadi_int getCount() const;
61 
62  std::string debug_repr(const Internal*) const;
63 
67  GenericWeakRef<Shared, Internal>* weak();
68 
69  protected:
71  void initSingleton() {
72  casadi_assert_dev(static_cast<Internal*>(this)->count==0);
73  static_cast<Internal*>(this)->count++;
74  }
75 
77  void destroySingleton() {
78  static_cast<Internal*>(this)->count--;
79  }
80 
82  template<class B>
83  B shared_from_this() {
84  casadi_assert_dev(B::test_cast(static_cast<Internal*>(this)));
85  B ret;
86  ret.own(static_cast<Internal*>(this));
87  return ret;
88  }
89 
91  template<class B>
92  const B shared_from_this() const {
93  casadi_assert_dev(B::test_cast(static_cast<const Internal*>(this)));
94  B ret;
95  ret.own(const_cast<Internal*>(static_cast<const Internal*>(this)));
96  return ret;
97  }
98 
99  private:
101 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
102  // Atomic so lazy publication in weak() races count_down()/teardown safely
103  std::atomic<GenericWeakRef<Shared, Internal>*> weak_ref_;
104 #else
105  GenericWeakRef<Shared, Internal>* weak_ref_;
106 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
107  };
108 
109  template<typename Shared, typename Internal>
110  class GenericWeakRefInternal : public Internal {
111  public:
112  // Constructor
113  GenericWeakRefInternal(Internal* raw);
114 
115  // Destructor
116  ~GenericWeakRefInternal() override;
117 
118  // Raw pointer to the cached object
119  Internal* raw_;
120 
121 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
122  mutable std::shared_ptr<std::mutex> mutex_;
123 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
124  };
125 
126 
127  template<class A>
128  A getcopy(const A& a,
129  std::map<typename A::base_type*,
130  typename A::internal_base_type> & already_copied) {
131  A ret;
132  if (!a.is_null()) {
133  auto it =
134  already_copied.find(const_cast<typename A::base_type*>(a.get()));
135  if (it!=already_copied.end()) {
136  ret.own(it->second.get());
137  }
138  }
139  return ret;
140  }
141 
143 
144 
145  template<typename Shared, typename Internal>
146  GenericSharedInternal<Shared, Internal>::
147  GenericSharedInternal(const GenericSharedInternal& node) {
148  static_cast<Internal*>(this)->count = 0; // reference counter is _not_ copied
149 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
150  weak_ref_.store(nullptr, std::memory_order_relaxed); // nor same weak references
151 #else
152  weak_ref_ = nullptr; // nor will they have the same weak references
153 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
154  }
155 
156  template<typename Shared, typename Internal>
157  GenericSharedInternal<Shared, Internal>&
158  GenericSharedInternal<Shared, Internal>::
159  operator=(const GenericSharedInternal<Shared, Internal>& node) {
160  // do _not_ copy the reference counter
161  return *this;
162  }
163 
164  template<typename Shared, typename Internal>
165  GenericSharedInternal<Shared, Internal>::GenericSharedInternal() {
166  static_cast<Internal*>(this)->count = 0;
167 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
168  weak_ref_.store(nullptr, std::memory_order_relaxed);
169 #else
170  weak_ref_ = nullptr;
171 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
172  }
173 
174  template<typename Shared, typename Internal>
175  std::string GenericSharedInternal<Shared, Internal>::debug_repr(const Internal* i) const {
176  // Note: i != this because of something something multiple inheritance
177  return str( (casadi_int)(i)) + "/" + static_cast<const Internal*>(this)->class_name();
178  }
179 
180  template<typename Shared, typename Internal>
181  GenericSharedInternal<Shared, Internal>::~GenericSharedInternal() {
182  #ifdef WITH_REFCOUNT_WARNINGS
183  if (static_cast<Internal*>(this)->count!=0) {
184  // Note that casadi_assert_warning cannot be used in destructors
185  std::cerr << "Reference counting failure." <<
186  "Possible cause: Circular dependency in user code." << std::endl;
187  }
188  #endif // WITH_REFCOUNT_WARNINGS
189 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
190  GenericWeakRef<Shared, Internal>* weak_ref =
191  weak_ref_.exchange(nullptr, std::memory_order_acq_rel);
192 #else
193  GenericWeakRef<Shared, Internal>* weak_ref = weak_ref_;
194  weak_ref_ = nullptr;
195 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
196  if (weak_ref != nullptr) {
197  // Assumption: no other GenericSharedInternal instances
198  // point to the same WeakRefInternal through weak_ref
199  weak_ref->kill();
200  delete weak_ref;
201  }
202  }
203 
204  template<typename Shared, typename Internal>
205  casadi_int GenericSharedInternal<Shared, Internal>::getCount() const {
206  return static_cast<const Internal*>(this)->count;
207  }
208 
209  template<typename Shared, typename Internal>
210  GenericWeakRef<Shared, Internal>* GenericSharedInternal<Shared, Internal>::weak() {
211 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
212  auto* w = weak_ref_.load(std::memory_order_acquire);
213  if (!w) {
214  auto* nw = new GenericWeakRef<Shared, Internal>(static_cast<Internal*>(this));
215  GenericWeakRef<Shared, Internal>* expected = nullptr;
216  if (weak_ref_.compare_exchange_strong(
217  expected, nw, std::memory_order_release, std::memory_order_acquire)) {
218  w = nw;
219  } else {
220  delete nw; // lost the race; another thread published first
221  w = expected;
222  }
223  }
224  return w;
225 #else
226  if (weak_ref_==nullptr) {
227  weak_ref_ = new GenericWeakRef<Shared, Internal>(static_cast<Internal*>(this));
228  }
229  return weak_ref_;
230 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
231  }
232 
233  template<typename Shared, typename Internal>
234  GenericWeakRefInternal<Shared, Internal>::GenericWeakRefInternal(Internal* raw) :
235  raw_(raw)
236 #ifdef CASADI_WITH_THREADSAFE_SYMBOLICS
237  , mutex_(std::make_shared<std::mutex>())
238 #endif // CASADI_WITH_THREADSAFE_SYMBOLICS
239  {
240  }
241 
242  template<typename Shared, typename Internal>
243  GenericWeakRefInternal<Shared, Internal>::~GenericWeakRefInternal() {
244  }
245 
246 
247 } // namespace casadi
248 
249 
250 #endif // CASADI_GENERIC_SHARED_INTERNAL_HPP
The casadi namespace.
Definition: archiver.hpp:32