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 154
|
/*!********************************************************************
Audacity: A Digital Audio Editor
@file ClientDataHelpers.h
@brief Some implementation details for ClientData
Paul Licameli
**********************************************************************/
#ifndef __AUDACITY_CLIENT_DATA_HELPERS__
#define __AUDACITY_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<
typename Covariant,
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
|