Loading [MathJax]/extensions/tex2jax.js
The Gaudi Framework  v38r1p1 (ae26267b)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
SynchronizedValue.h
Go to the documentation of this file.
1 /***********************************************************************************\
2 * (c) Copyright 1998-2023 CERN for the benefit of the LHCb and ATLAS collaborations *
3 * *
4 * This software is distributed under the terms of the Apache version 2 licence, *
5 * copied verbatim in the file "LICENSE". *
6 * *
7 * In applying this licence, CERN does not waive the privileges and immunities *
8 * granted to it by virtue of its status as an Intergovernmental Organization *
9 * or submit itself to any jurisdiction. *
10 \***********************************************************************************/
11 #pragma once
12 #include <functional>
13 #include <mutex>
14 #include <shared_mutex>
15 #include <tuple>
16 #include <type_traits>
17 #include <utility>
18 
19 namespace Gaudi::cxx {
20 
21  namespace details {
22 
23  template <typename Value, typename... Args>
24  using require_constructible_t = std::enable_if_t<std::is_constructible_v<Value, Args...>>;
25 
26  } // namespace details
27 
28  // C++20: replace with http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0290r2.html
29  // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4033.html
30 
31  template <typename Value, typename Mutex = std::mutex,
32  typename ReadLock = std::conditional_t<std::is_same_v<std::shared_mutex, Mutex>, std::shared_lock<Mutex>,
34  typename WriteLock = std::lock_guard<Mutex>>
36  static_assert( !std::is_reference_v<Value>, "Value must not be a reference" );
38  mutable Mutex m_mtx;
39 
40  public:
41  template <typename... Args, typename = details::require_constructible_t<Value, Args...>>
42  SynchronizedValue( Args&&... args ) : m_obj{ std::forward<Args>( args )... } {}
43 
45  static_assert( std::is_default_constructible_v<Value> ); // bound to hold, as otherwise we wouldn't get this
46  // far... so for 'documnentation purpose' really (C++20:
47  // turn into a `requires` clause )...
48  static_assert( std::is_copy_assignable_v<Value> );
49  auto lock = std::scoped_lock{ rhs.m_mtx, m_mtx };
50  m_obj = rhs.m_obj;
51  }
52 
54  static_assert( std::is_copy_assignable_v<Value> );
55  if ( this != &rhs ) {
56  auto lock = std::scoped_lock{ rhs.m_mtx, m_mtx };
57  m_obj = rhs.m_obj;
58  }
59  return *this;
60  }
61 
63  static_assert( std::is_default_constructible_v<Value> ); // bound to hold, as otherwise we wouldn't get this
64  // far... so for 'documnentation purpose' really (C++20:
65  // turn into a `requires` clause )...
66  static_assert( std::is_move_assignable_v<Value> );
67  auto lock = std::scoped_lock{ rhs.m_mtx, m_mtx };
68  m_obj = std::move( rhs.m_obj );
69  }
70 
72  static_assert( std::is_move_assignable_v<Value> );
73  if ( this != &rhs ) {
74  auto lock = std::scoped_lock{ rhs.m_mtx, m_mtx };
75  m_obj = std::move( rhs.m_obj );
76  }
77  return *this;
78  }
79 
80  template <typename F, typename... Args,
81  typename = std::enable_if_t<std::is_invocable_v<F, Value&, Args...> &&
82  !std::is_invocable_v<F, const Value&, Args...>>>
83  decltype( auto ) with_lock( F&& f, Args&&... args ) {
84  WriteLock _{ m_mtx };
85  return std::invoke( std::forward<F>( f ), m_obj, std::forward<Args>( args )... );
86  }
87 
88  template <typename F, typename... Args, typename = std::enable_if_t<std::is_invocable_v<F, const Value&, Args...>>>
89  decltype( auto ) with_lock( F&& f, Args&&... args ) const {
90  ReadLock _{ m_mtx };
91  return std::invoke( std::forward<F>( f ), m_obj, std::forward<Args>( args )... );
92  }
93  };
94 
95  // transform an f(T,...) into an f(SynchronizedValue<T>,...)
96  template <typename Fun>
97  auto with_lock( Fun&& f ) {
98  return [f = std::forward<Fun>( f )]( auto& p, auto&&... args ) -> decltype( auto ) {
99  return p.with_lock( f, std::forward<decltype( args )>( args )... );
100  };
101  }
102  // call f(T) for each element in a container of Synced<T>
103  template <typename ContainerOfSynced, typename Fun>
104  void for_each( ContainerOfSynced& c, Fun&& f ) {
105  std::for_each( begin( c ), end( c ), with_lock( std::forward<Fun>( f ) ) );
106  }
107 
108 } // namespace Gaudi::cxx
std::for_each
T for_each(T... args)
Gaudi::cxx::SynchronizedValue::SynchronizedValue
SynchronizedValue(Args &&... args)
Definition: SynchronizedValue.h:42
Gaudi::cxx::SynchronizedValue::SynchronizedValue
SynchronizedValue(SynchronizedValue &&rhs)
Definition: SynchronizedValue.h:62
std::move
T move(T... args)
std::lock_guard
STL class.
gaudirun.c
c
Definition: gaudirun.py:525
MultiMergers.Value
Value
Definition: MultiMergers.py:15
Gaudi::cxx::SynchronizedValue::SynchronizedValue
SynchronizedValue(const SynchronizedValue &rhs)
Definition: SynchronizedValue.h:44
Gaudi::cxx::SynchronizedValue::operator=
SynchronizedValue & operator=(const SynchronizedValue &rhs)
Definition: SynchronizedValue.h:53
Gaudi::cxx::SynchronizedValue::m_mtx
Mutex m_mtx
Definition: SynchronizedValue.h:38
Gaudi::cxx::for_each
void for_each(ContainerOfSynced &c, Fun &&f)
Definition: SynchronizedValue.h:104
details
Definition: AnyDataWrapper.h:18
Gaudi::cxx::details::require_constructible_t
std::enable_if_t< std::is_constructible_v< Value, Args... > > require_constructible_t
Definition: SynchronizedValue.h:24
std::forward
T forward(T... args)
CLHEP::begin
double * begin(CLHEP::HepVector &v)
Definition: TupleAlg.cpp:45
Gaudi::cxx::SynchronizedValue::m_obj
Value m_obj
Definition: SynchronizedValue.h:36
gaudirun.args
args
Definition: gaudirun.py:336
Gaudi::cxx
Definition: SynchronizedValue.h:19
Gaudi::cxx::SynchronizedValue
Definition: SynchronizedValue.h:35
std::mutex
STL class.
IOTest.end
end
Definition: IOTest.py:123
Gaudi::cxx::SynchronizedValue::operator=
SynchronizedValue & operator=(SynchronizedValue &&rhs)
Definition: SynchronizedValue.h:71
Gaudi::cxx::with_lock
auto with_lock(Fun &&f)
Definition: SynchronizedValue.h:97
std::shared_lock
STL class.