12#ifndef __AUDACITY_CLIENT_DATA__
13#define __AUDACITY_CLIENT_DATA__
35template<
typename Object >
using UniquePtr = std::unique_ptr< Object >;
38template<
typename Object >
using BarePtr = Object*;
47 typename Covariant = void,
48 template<
typename>
class Owner =
UniquePtr
51 using Base = std::conditional_t<
52 std::is_void_v<Covariant>,
Cloneable, Covariant
223 template<
typename>
class Pointer =
UniquePtr,
233 static_assert( std::has_virtual_destructor<ClientData>::value,
234 "ClientData::Site requires a data class with a virtual destructor" );
245 auto size = factories.mObject.size();
257 {
mData = std::move(other.mData);
return *
this; }
282 mIndex = factories.mObject.size();
283 factories.mObject.emplace_back( std::move(
factory ) );
289 other.mOwner =
false;
296 if (
mIndex < factories.mObject.size() )
297 factories.mObject[
mIndex] =
nullptr;
317 template<
typename Sub
class = ClientData >
321 return DoGet< Subclass >( data,
key );
326 template<
typename Sub
class = const ClientData >
328 std::enable_if_t< std::is_const< Subclass >::value, Subclass & >
331 return DoGet< Subclass >( data,
key );
341 template<
typename Sub
class = ClientData >
345 return DoFind< Subclass >( data,
key );
350 template<
typename Sub
class = const ClientData >
352 std::enable_if_t< std::is_const< Subclass >::value, Subclass * >
355 return DoFind< Subclass >( data,
key );
363 template<
typename ReplacementPo
inter >
366 ReplacementPointer &&replacement
374 *iter = std::forward< ReplacementPointer >( replacement );
388 template<
typename Function >
392 for(
auto &pObject : data.mObject ) {
401 template<
typename Function >
402 void ForEach(
const Function &function )
const
405 for(
auto &pObject : data.mObject ) {
408 const auto &c_ref = *ptr;
427 template<
typename Function>
434 size = factories.mObject.size();
441 std::optional<
decltype(
GetData())> oOtherData;
442 if (std::addressof(other) < std::addressof(*
this))
443 oOtherData.emplace(other.
GetData());
446 oOtherData.emplace(other.
GetData());
447 auto &otherData = *oOtherData;
456 for (
size_t ii = 0; ii <
size; ++ii, ++iter, ++otherIter) {
457 auto &pObject = *iter;
458 auto &pOtherObject = *otherIter;
463 if (!*deref && !*otherDeref)
465 else if (!*deref && create) {
468 auto &
factory = factories.mObject[ii];
474 else if (!*otherDeref && create) {
477 auto &
factory = factories.mObject[ii];
485 (*deref ? &**deref :
nullptr),
486 (*otherDeref ? &**otherDeref :
nullptr));
496 template<
typename Function >
500 for(
auto &pObject : data.mObject ) {
502 if ( ptr && function ( *ptr ) )
510 template<
typename Function >
514 for(
auto &pObject : data.mObject ) {
517 const auto &c_ref = *ptr;
518 if ( function( c_ref ) )
531 template<
typename Function>
535 for (
auto &pObject : data.mObject) {
555 size = factories.mObject.size();
562 for (
size_t ii = 0; ii <
size; ++ii, ++iter )
563 static_cast< void >(
Build( data, iter, ii ) );
583 auto &pointer = create ?
Build( data, iter, index ) : *iter;
587 template<
typename Sub
class >
590 const auto &d =
Slot( data,
key,
true );
595 return static_cast< Subclass&
>( *d );
598 template<
typename Sub
class >
601 const auto &d =
Slot( data,
key,
false );
605 return static_cast< Subclass*
>( &*d );
631 if (data.
mObject.size() <= index)
632 data.
mObject.resize(index + 1);
635 static typename DataContainer::iterator
inline
643 auto result = data.
mObject.begin();
644 std::advance( result, index );
649 typename DataContainer::iterator iter,
size_t index )
654 auto &result = *iter;
658 auto &
factory = factories.mObject[index];
Some implementation details for ClientData.
MessageBoxException for violation of preconditions or assertions.
#define THROW_INCONSISTENCY_EXCEPTION
Throw InconsistencyException, using C++ preprocessor to identify the source code location.
Client code makes static instance from a factory of attachments; passes it to Get or Find as a retrie...
RegisteredFactory(RegisteredFactory &&other)
RegisteredFactory(DataFactory factory)
Utility to register hooks into a host class that attach client data.
size_t size() const
How many attachment pointers are in the Site.
Site & operator=(const Site &other)
ClientData * FindIf(const Function &function)
Return pointer to first attachment in this that is not null and satisfies a predicate,...
Pointer< ClientData > DataPointer
static Locked< DataFactories > GetFactories()
Locked< DataContainer > GetData()
void EraseIf(const Function &function)
Erase attached objects satisfying a predicate.
DataContainer mData
Container of pointers returned by factories, per instance of Host class.
Subclass * DoFind(Locked< DataContainer > &data, const RegisteredFactory &key)
static size_t numFactories()
How many static factories have been registered with this specialization of Site.
static DataContainer::iterator GetIterator(Locked< DataContainer > &data, size_t index)
Subclass * Find(const RegisteredFactory &key)
Get a (bare) pointer to an attachment, or null, down-cast it to Subclass *; will not create on demand...
static void EnsureIndex(Locked< DataContainer > &data, size_t index)
Locked< const DataContainer > GetData() const
void ForCorresponding(Site &other, const Function &function, bool create=true)
void ForEach(const Function &function)
Invoke function on each ClientData object that has been created in this.
void ForEach(const Function &function) const
Invoke function on each ClientData object that has been created in this.
DataPointer & Build(Locked< DataContainer > &, typename DataContainer::iterator iter, size_t index)
void BuildAll()
For each RegisteredFactory, if the corresponding attachment is absent in this, build and store it.
Subclass & DoGet(Locked< DataContainer > &data, const RegisteredFactory &key)
std::function< DataPointer(Host &) > DataFactory
Type of function from which RegisteredFactory is constructed; it builds attachments.
auto Find(const RegisteredFactory &key) const -> std::enable_if_t< std::is_const< Subclass >::value, Subclass * >
Get a (bare) pointer to an attachment, or null, down-cast it to Subclass *; will not create on demand...
const ClientData * FindIf(const Function &function) const
Return pointer to first attachment in this that is not null and satisfies a predicate,...
auto Get(const RegisteredFactory &key) const -> std::enable_if_t< std::is_const< Subclass >::value, Subclass & >
Get reference to an attachment, creating on demand if not present, down-cast it to Subclass.
Subclass & Get(const RegisteredFactory &key)
Get reference to an attachment, creating on demand if not present, down-cast it to Subclass.
void Assign(const RegisteredFactory &key, ReplacementPointer &&replacement)
Reassign Site's pointer to ClientData.
decltype(Dereferenceable(std::declval< DataPointer & >())) Slot(Locked< DataContainer > &data, const RegisteredFactory &key, bool create)
Utility ClientData::Site to register hooks into a host class that attach client data.
static const Ptr & Dereferenceable(Ptr &p)
Conversion allowing operator * on any Pointer parameter of ClientData::Site.
Object * BarePtr
This template-template parameter for ClientData::Site risks dangling pointers, so be careful.
CopyingPolicy
Statically specify how the ClientData::Site implements its copy constructor and assignment.
@ SkipCopying
ignore the source and leave empty
LockingPolicy
Statically specify whether there is mutual exclusion (separately for the table of factories,...
std::unique_ptr< Object > UniquePtr
A one-argument alias template for the default template-template parameter of ClientData::Site.
A convenient default parameter for class template Site.
A convenient base class defining abstract virtual Clone() for a given kind of pointer.
virtual PointerType Clone() const =0
Cloneable(const Cloneable &)=default
std::conditional_t< std::is_void_v< Covariant >, Cloneable, Covariant > Base
Owner< Base > PointerType
virtual ~Cloneable()=default
Cloneable & operator=(const Cloneable &)=default
Decorator template injects copy and move operators for container of pointers.
Decorator template injects type Lock and method lock() into interface of Object.
Decorated reference to a ClientData::Lockable, with a current lock on it.