Dash Core Source Documentation (0.16.0.1)

Find detailed information regarding the Dash Core source code.

atom.hpp
Go to the documentation of this file.
1 //
2 // immer: immutable data structures for C++
3 // Copyright (C) 2016, 2017, 2018 Juan Pedro Bolivar Puente
4 //
5 // This software is distributed under the Boost Software License, Version 1.0.
6 // See accompanying file LICENSE or copy at http://boost.org/LICENSE_1_0.txt
7 //
8 
9 #pragma once
10 
11 #include <immer/box.hpp>
13 
14 #include <atomic>
15 #include <type_traits>
16 
17 namespace immer {
18 
19 namespace detail {
20 
21 template <typename T, typename MemoryPolicy>
23 {
25  using value_type = T;
26  using memory_policy = MemoryPolicy;
27  using spinlock_t = typename MemoryPolicy::refcount::spinlock_type;
28  using scoped_lock_t = typename spinlock_t::scoped_lock;
29 
30  refcount_atom_impl(const refcount_atom_impl&) = delete;
34 
36  : impl_{std::move(b)}
37  {}
38 
39  box_type load() const
40  {
41  scoped_lock_t lock{lock_};
42  return impl_;
43  }
44 
45  void store(box_type b)
46  {
47  scoped_lock_t lock{lock_};
48  impl_ = std::move(b);
49  }
50 
52  {
53  {
54  scoped_lock_t lock{lock_};
55  swap(b, impl_);
56  }
57  return std::move(b);
58  }
59 
60  template <typename Fn>
61  box_type update(Fn&& fn)
62  {
63  while (true) {
64  auto oldv = load();
65  auto newv = oldv.update(fn);
66  {
67  scoped_lock_t lock{lock_};
68  if (oldv.impl_ == impl_.impl_) {
69  impl_ = newv;
70  return { newv };
71  }
72  }
73  }
74  }
75 
76 private:
77  mutable spinlock_t lock_;
79 };
80 
81 template <typename T, typename MemoryPolicy>
83 {
85  using value_type = T;
86  using memory_policy = MemoryPolicy;
87 
88  static_assert(
89  std::is_same<typename MemoryPolicy::refcount,
90  no_refcount_policy>::value,
91  "gc_atom_impl can only be used when there is no refcount!");
92 
93  gc_atom_impl(const gc_atom_impl&) = delete;
94  gc_atom_impl(gc_atom_impl&&) = delete;
95  gc_atom_impl& operator=(const gc_atom_impl&) = delete;
96  gc_atom_impl& operator=(gc_atom_impl&&) = delete;
97 
99  : impl_{b.impl_}
100  {}
101 
102  box_type load() const
103  { return {impl_.load()}; }
104 
105  void store(box_type b)
106  { impl_.store(b.impl_); }
107 
109  { return {impl_.exchange(b.impl_)}; }
110 
111  template <typename Fn>
112  box_type update(Fn&& fn)
113  {
114  while (true) {
115  auto oldv = box_type{impl_.load()};
116  auto newv = oldv.update(fn);
117  if (impl_.compare_exchange_weak(oldv.impl_, newv.impl_))
118  return { newv };
119  }
120  }
121 
122 private:
123  std::atomic<typename box_type::holder*> impl_;
124 };
125 
126 } // namespace detail
127 
152 template <typename T,
153  typename MemoryPolicy = default_memory_policy>
154 class atom
155 {
156 public:
158  using value_type = T;
159  using memory_policy = MemoryPolicy;
160 
161  atom(const atom&) = delete;
162  atom(atom&&) = delete;
163  void operator=(const atom&) = delete;
164  void operator=(atom&&) = delete;
165 
170  : impl_{std::move(v)}
171  {}
172 
177  {
178  impl_.store(std::move(b));
179  return *this;
180  }
181 
185  operator box_type() const
186  { return impl_.load(); }
187 
191  operator value_type() const
192  { return *impl_.load(); }
193 
197  box_type load() const
198  { return impl_.load(); }
199 
203  void store(box_type b)
204  { impl_.store(std::move(b)); }
205 
210  { return impl_.exchange(std::move(b)); }
211 
224  template <typename Fn>
225  box_type update(Fn&& fn)
226  { return impl_.update(std::forward<Fn>(fn)); }
227 
228 private:
230  {
231  template <typename U, typename MP>
232  struct apply
233  {
235  };
236  };
237 
239  {
240  template <typename U, typename MP>
241  struct apply
242  {
244  };
245  };
246 
247  // If we are using "real" garbage collection (we assume this when we use
248  // `no_refcount_policy`), we just store the pointer in an atomic. If we use
249  // reference counting, we rely on the reference counting spinlock.
250  using impl_t = typename std::conditional_t<
251  std::is_same<typename MemoryPolicy::refcount, no_refcount_policy>::value,
254  >::template apply<T, MemoryPolicy>::type;
255 
257 };
258 
259 }
box_type load() const
Definition: atom.hpp:197
gc_atom_impl(const gc_atom_impl &)=delete
refcount_atom_impl & operator=(const refcount_atom_impl &)=delete
box_type exchange(box_type b)
Definition: atom.hpp:51
box_type exchange(box_type b)
Definition: atom.hpp:209
void store(box_type b)
Definition: atom.hpp:45
void store(box_type b)
Definition: atom.hpp:105
atom(const atom &)=delete
std::atomic< typename box_type::holder * > impl_
Definition: atom.hpp:123
atom & operator=(box_type b)
Definition: atom.hpp:176
holder * impl_
Definition: box.hpp:50
typename spinlock_t::scoped_lock scoped_lock_t
Definition: atom.hpp:28
typename std::conditional_t< std::is_same< typename MemoryPolicy::refcount, no_refcount_policy >::value, get_gc_atom_impl, get_refcount_atom_impl >::template apply< T, MemoryPolicy >::type impl_t
Definition: atom.hpp:254
box_type update(Fn &&fn)
Definition: atom.hpp:225
void store(box_type b)
Definition: atom.hpp:203
typename MemoryPolicy::refcount::spinlock_type spinlock_t
Definition: atom.hpp:27
box_type exchange(box_type b)
Definition: atom.hpp:108
gc_atom_impl(box_type b)
Definition: atom.hpp:98
box_type update(Fn &&fn)
Definition: atom.hpp:112
atom(box_type v={})
Definition: atom.hpp:169
box_type update(Fn &&fn)
Definition: atom.hpp:61
MemoryPolicy memory_policy
Definition: atom.hpp:159
void operator=(const atom &)=delete
MemoryPolicy memory_policy
Definition: atom.hpp:86
box< T, MemoryPolicy > box_type
Definition: atom.hpp:157
refcount_atom_impl(const refcount_atom_impl &)=delete
gc_atom_impl & operator=(const gc_atom_impl &)=delete
box_type load() const
Definition: atom.hpp:102
impl_t impl_
Definition: atom.hpp:256
T value_type
Definition: atom.hpp:158
Released under the MIT license