ATLAS Offline Software
CachedPointer.icc
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration
3 */
4 // $Id$
5 /**
6  * @file CxxUtils/CachedPointer.icc
7  * @author scott snyder <snyder@bnl.gov>
8  * @date Nov, 2017, from earlier code in AthLinks.
9  * @brief Cached pointer with atomic update.
10  */
11 
12 
13 namespace CxxUtils {
14 
15 template <class T>
16 inline
17 void CachedPointerStaticAsserts()
18 {
19 }
20 
21 
22 /**
23  * @brief Default constructor. Sets the element to null.
24  */
25 template <class T>
26 inline
27 CachedPointer<T>::CachedPointer()
28  : m_a (nullptr)
29 {
30  static_assert(std::is_nothrow_copy_assignable_v<CachedPointer<T>> &&
31  std::is_nothrow_move_assignable_v<CachedPointer<T>> &&
32  std::is_nothrow_copy_constructible_v<CachedPointer<T>> &&
33  std::is_nothrow_move_constructible_v<CachedPointer<T>>);
34 }
35 
36 /**
37  * @brief Constructor from an element.
38  */
39 template <class T>
40 inline
41 CachedPointer<T>::CachedPointer (pointer_t elt)
42  : m_a (elt)
43 {
44  static_assert(std::is_nothrow_copy_assignable_v<CachedPointer<T>> &&
45  std::is_nothrow_move_assignable_v<CachedPointer<T>> &&
46  std::is_nothrow_copy_constructible_v<CachedPointer<T>> &&
47  std::is_nothrow_move_constructible_v<CachedPointer<T>>);
48 }
49 
50 
51 /**
52  * @brief Copy constructor.
53  */
54 template <class T>
55 inline
56 CachedPointer<T>::CachedPointer (const CachedPointer& other) noexcept
57  : m_a (other.get())
58 {
59 }
60 
61 /**
62  * @brief Assignment.
63  */
64 template <class T>
65 inline
66 CachedPointer<T>&
67 CachedPointer<T>::operator= (const CachedPointer& other) noexcept
68 {
69  if (this != &other) {
70  store (other.get());
71  }
72  return *this;
73 }
74 
75 
76 /**
77  * @brief Set the element, assuming it is currently null.
78  * @param elt The new value for the element.
79  *
80  * The current value of the element must either be null, in which case,
81  * it is set to ELT, or else it must already be equal to ELT, in which
82  * case no write occurs. Anything else is considered an error.
83  *
84  * The reason for doing things this way is that we (have to) allow
85  * a pointer to the underlying element to escape to user code, and we
86  * don't want a write to conflict with a non-atomic read. (Such a read
87  * can only happen after the element has been set for the first time.)
88  */
89 template <class T>
90 inline
91 void CachedPointer<T>::set (pointer_t elt) const
92 {
93  // Set the element to ELT if it is currently null.
94  pointer_t null = nullptr;
95  m_a.compare_exchange_strong (null, elt, std::memory_order_relaxed);
96  // If the element was originally null, then NULL will still be null.
97  // If the element was originally ELT, then no write will have been performed,
98  // and NULL will be ELT. If the element was originally something else,
99  // then NULL will be set to that value.
100  assert (null == nullptr || null == elt);
101 }
102 
103 
104 /**
105  * @brief Store a new value to the element.
106  */
107 template <class T>
108 inline
109 void CachedPointer<T>::store (pointer_t elt)
110 {
111  m_a.store (elt, std::memory_order_relaxed);
112 }
113 
114 
115 /**
116  * @brief Return the current value of the element.
117  */
118 template <class T>
119 inline
120 typename CachedPointer<T>::pointer_t
121 CachedPointer<T>::get() const
122 {
123  return m_a.load (std::memory_order_relaxed);
124 }
125 
126 
127 /**
128  * @brief Return a pointer to the cached element.
129  */
130 template <class T>
131 inline
132 const typename CachedPointer<T>::pointer_t*
133 CachedPointer<T>::ptr() const
134 {
135  return &m_e;
136 }
137 
138 } // namespace CxxUtils