1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-07 23:32:53 +02:00
audacity/src/ClientDataHelpers.h

141 lines
4.3 KiB
C++

/**********************************************************************
Audacity: A Digital Audio Editor
ClientDataHelpers.h
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
// To specify (separately for the table of factories, and for the per-Site
// container of client data objects) whether to ensure mutual exclusion.
enum LockingPolicy {
NoLocking,
NonrecursiveLocking, // using std::mutex
RecursiveLocking, // using std::recursive_mutex
};
// To specify how the Site implements its copy constructor and assignment.
// (Move construction and assignment always work.)
enum CopyingPolicy {
SkipCopying, // copy ignores the argument and constructs empty
ShallowCopying, // just copy smart pointers; won't compile for unique_ptr
DeepCopying, // requires ClientData to define a Clone() member;
// won't compile for weak_ptr (and wouldn't work)
};
// forward declarations
struct Base;
template<
template<typename> class Owner
> struct Cloneable;
// A conversion so we can use operator * in all the likely cases for the
// template parameter Pointer. (Return value should be bound only to const
// lvalue references)
template< typename Ptr > static inline
const Ptr &Dereferenceable( Ptr &p )
{ return p; } // returns an lvalue
template< typename Obj > static inline
std::shared_ptr<Obj> Dereferenceable( std::weak_ptr<Obj> &p )
{ return p.lock(); } // overload returns a prvalue
// Decorator template to implement locking policies
template< typename Object, LockingPolicy > struct Lockable;
template< typename Object > struct Lockable< Object, NoLocking >
: Object {
// implement trivial non-locking policy
struct Lock{};
Lock lock() const { return {}; }
};
template< typename Object > struct Lockable< Object, NonrecursiveLocking >
: Object, std::mutex {
// implement real locking
using Lock = std::unique_lock< std::mutex >;
Lock lock() const { return Lock{ *this }; }
};
template< typename Object > struct Lockable< Object, RecursiveLocking >
: Object, std::recursive_mutex {
// implement real locking
using Lock = std::unique_lock< std::recursive_mutex >;
Lock lock() const { return Lock{ *this }; }
};
// Pairing of a reference to a Lockable and a lock on it
template< typename Lockable > struct Locked
// inherit, maybe empty base class optimization applies:
: private Lockable::Lock
{
explicit Locked( Lockable &object )
: Lockable::Lock( object.lock() )
, mObject( object )
{}
Lockable &mObject;
};
// Decorator template implements the copying policy
template< typename Container, CopyingPolicy > struct Copyable;
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;
};
template< typename Container > struct Copyable< Container, ShallowCopying >
: Container {
Copyable() = default;
Copyable( const Copyable &other )
{ *this = other; }
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;
};
template< typename Container > struct Copyable< Container, DeepCopying >
: Container {
Copyable() = default;
Copyable( const Copyable &other )
{ *this = other; }
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