forked from Sneeds-Feed-and-Seed/sneedacity
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathClientDataHelpers.h
153 lines (137 loc) · 5.19 KB
/
ClientDataHelpers.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/*!********************************************************************
Sneedacity: A Digital Audio Editor
@file ClientDataHelpers.h
@brief Some implementation details for ClientData
Paul Licameli
**********************************************************************/
#ifndef __SNEEDACITY_CLIENT_DATA_HELPERS__
#define __SNEEDACITY_CLIENT_DATA_HELPERS__
#include <memory>
#include <mutex>
#include <type_traits>
namespace ClientData {
// Helpers to define ClientData::Site class template
//! Statically specify whether there is mutual exclusion (separately for the table of factories, and for the per-host container of client objects).
/*! Used as non-type template parameter of ClientData::Site */
enum LockingPolicy {
NoLocking,
NonrecursiveLocking, //!< using std::mutex
RecursiveLocking, //!< using std::recursive_mutex
};
//! Statically specify how the ClientData::Site implements its copy constructor and assignment.
/*! (Move construction and assignment always work.)
Used as non-type template parameter of ClientData::Site */
enum CopyingPolicy {
SkipCopying, //!< ignore the source and leave empty
ShallowCopying, //!< copy pointers only; won't compile for std::unique_ptr
DeepCopying, //!< point to new sub-objects; these must define a Clone() member; won't compile for std::weak_ptr
};
// forward declarations
struct Base;
template<
template<typename> class Owner
> struct Cloneable;
//! Conversion allowing operator * on any @b Pointer parameter of ClientData::Site
/*! Return value should be bound to a const reference */
template< typename Ptr > static inline
const Ptr &Dereferenceable( Ptr &p )
{ return p; }
//! Overload of ClientData::Dereferenceable returns an rvalue
template< typename Obj > static inline
std::shared_ptr<Obj> Dereferenceable( std::weak_ptr<Obj> &p )
{ return p.lock(); }
//! Decorator template injects type Lock and method lock() into interface of @b Object
/*!
@tparam Object decorated class
@tparam LockingPolicy one of ClientData::LockingPolicy
*/
template< typename Object, LockingPolicy > struct Lockable{};
//! Specialization for trivial, non-locking policy
template< typename Object > struct Lockable< Object, NoLocking >
: Object {
//! Empty class
struct Lock{};
Lock lock() const { return {}; }
};
//! Specialization for real locking with std::mutex
template< typename Object > struct Lockable< Object, NonrecursiveLocking >
: Object, std::mutex {
using Lock = std::unique_lock< std::mutex >;
Lock lock() const { return Lock{ *this }; }
};
//! Specialization for real locking with std::recursive_mutex
template< typename Object > struct Lockable< Object, RecursiveLocking >
: Object, std::recursive_mutex {
using Lock = std::unique_lock< std::recursive_mutex >;
Lock lock() const { return Lock{ *this }; }
};
//! Decorated reference to a ClientData::Lockable, with a current lock on it
/*! Uses inheritance to benefit from the empty base class optimization if possible */
template< typename Lockable > struct Locked
: private Lockable::Lock
{
explicit Locked( Lockable &object )
: Lockable::Lock( object.lock() )
, mObject( object )
{}
Lockable &mObject;
};
//! Decorator template injects copy and move operators for container of pointers
template< typename Container, CopyingPolicy > struct Copyable{};
//! Specialization that ignores contents of the source when copying (not when moving).
template< typename Container > struct Copyable< Container, SkipCopying >
: Container {
Copyable() = default;
Copyable( const Copyable & ) {}
Copyable &operator=( const Copyable & ) { return *this; }
Copyable( Copyable && ) = default;
Copyable &operator=( Copyable&& ) = default;
};
//! Specialization that copies pointers, not sub-objects; [strong guarantee](@ref Strong-guarantee) for assignment
template< typename Container > struct Copyable< Container, ShallowCopying >
: Container {
Copyable() = default;
//! Call through to operator =
Copyable( const Copyable &other )
{ *this = other; }
//! @excsafety{Strong}
Copyable &operator=( const Copyable &other )
{
if (this != &other) {
// Build then swap for strong exception guarantee
Copyable temp;
for ( auto &&ptr : other )
temp.push_back( ptr );
this->swap( temp );
}
return *this;
}
Copyable( Copyable && ) = default;
Copyable &operator=( Copyable&& ) = default;
};
//! Specialization that clones sub-objects when copying; [strong guarantee](@ref Strong-guarantee) for assignment
template< typename Container > struct Copyable< Container, DeepCopying >
: Container {
Copyable() = default;
//! Call through to operator =
Copyable( const Copyable &other )
{ *this = other; }
//! @excsafety{Strong}
Copyable &operator=( const Copyable &other )
{
if (this != &other) {
// Build then swap for strong exception guarantee
Copyable temp;
for ( auto &&p : other ) {
using Ptr = decltype( p->Clone() );
temp.push_back( p ? p->Clone() : Ptr{} );
}
this->swap( temp );
}
return *this;
}
Copyable( Copyable && ) = default;
Copyable &operator=( Copyable&& ) = default;
};
}
#endif