224 lines
6 KiB
C
224 lines
6 KiB
C
|
|
||
|
|
||
|
#ifndef TCG_CONTROLLED_ACCESS_H
|
||
|
#define TCG_CONTROLLED_ACCESS_H
|
||
|
|
||
|
// tcg includes
|
||
|
#include "base.h"
|
||
|
|
||
|
/*!
|
||
|
\file controlled_access.h
|
||
|
|
||
|
\brief This file contains the description of a C++ idiom that can be used
|
||
|
to perform controlled access on an object.
|
||
|
|
||
|
\details Controlled access forces users to invoke a function every time an
|
||
|
object is accessed, at compile-time.
|
||
|
|
||
|
Some notable cases for this idiom include the "frequent notifier / lazy update"
|
||
|
scenario, where an object is frequently notified for status updates, but
|
||
|
many updates can be spared until the data is finally accessed.
|
||
|
*/
|
||
|
|
||
|
namespace tcg
|
||
|
{
|
||
|
|
||
|
enum DirectAccess { direct_access }; //!< Enum used to access variables with
|
||
|
//! controlled output directly.
|
||
|
|
||
|
//*************************************************************************
|
||
|
// tcg::controlled_access definition
|
||
|
//*************************************************************************
|
||
|
|
||
|
/*!
|
||
|
\brief The controlled_access template class encapsulate an object that
|
||
|
can be accessed \b only after a functor has been invoked, enforcing
|
||
|
access tracking at compile time.
|
||
|
|
||
|
\details The accessor functor can be specified by explicit template argument
|
||
|
or supplying it during access. In case the accessor type is specified,
|
||
|
an instance of the functor will be stored together with the accessed
|
||
|
variable.
|
||
|
|
||
|
\todo Move functor to base class to enable empty class optimization for
|
||
|
stateless functors.
|
||
|
*/
|
||
|
|
||
|
template <typename Obj, typename Func = tcg::empty_type>
|
||
|
class controlled_access : tcg::noncopyable<>
|
||
|
{
|
||
|
Obj m_obj; //!< Stored object.
|
||
|
Func m_func; //!< Functor to be invoked upon access.
|
||
|
|
||
|
public:
|
||
|
typedef Obj obj_type;
|
||
|
typedef Func func_type;
|
||
|
|
||
|
public:
|
||
|
controlled_access(const func_type &func) : m_obj(), m_func(func) {}
|
||
|
controlled_access(const obj_type &obj, const func_type &func)
|
||
|
: m_obj(obj), m_func(func) {}
|
||
|
|
||
|
const obj_type &operator()(DirectAccess) const { return m_obj; }
|
||
|
obj_type &operator()(DirectAccess) { return m_obj; }
|
||
|
|
||
|
const obj_type &operator()() const
|
||
|
{
|
||
|
m_func(m_obj);
|
||
|
return m_obj;
|
||
|
}
|
||
|
obj_type &operator()()
|
||
|
{
|
||
|
m_func(m_obj);
|
||
|
return m_obj;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
/*!
|
||
|
\brief Explicit specialization advocating no explicit accessor functor - the
|
||
|
accessor must be supplied upon access.
|
||
|
*/
|
||
|
|
||
|
template <typename Obj>
|
||
|
class controlled_access<Obj, tcg::empty_type> : tcg::noncopyable<>
|
||
|
{
|
||
|
Obj m_obj; //!< Stored object.
|
||
|
|
||
|
public:
|
||
|
typedef Obj obj_type;
|
||
|
|
||
|
public:
|
||
|
controlled_access() : m_obj() {}
|
||
|
controlled_access(const obj_type &obj) : m_obj(obj) {}
|
||
|
|
||
|
const obj_type &operator()(DirectAccess) const { return m_obj; }
|
||
|
obj_type &operator()(DirectAccess) { return m_obj; }
|
||
|
|
||
|
template <typename Func>
|
||
|
const obj_type &operator()(Func func) const
|
||
|
{
|
||
|
func(m_obj);
|
||
|
return m_obj;
|
||
|
}
|
||
|
|
||
|
template <typename Func>
|
||
|
obj_type &operator()(Func func)
|
||
|
{
|
||
|
func(m_obj);
|
||
|
return m_obj;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//==============================================================================
|
||
|
|
||
|
/*!
|
||
|
\brief The invalidable template class is a common case of controlled variable
|
||
|
access for objects which can be \a invalidated, and thus require a validator
|
||
|
procedure to be invoked strictly before a user access to the object can be
|
||
|
allowed.
|
||
|
|
||
|
\details An invalidable instance wraps a \a mutable object and adds a boolean to
|
||
|
signal its current validity state.
|
||
|
|
||
|
The initial validity of the object can be specified at construction, and
|
||
|
explicitly set to the invalid state through the invalidate() method.
|
||
|
|
||
|
Access to the wrapped object requires either the invocation a validator
|
||
|
functor through the various operator() overloads, or that the access is
|
||
|
explicitly marked as \a direct by supplying the \p tcg::direct_access tag.
|
||
|
*/
|
||
|
|
||
|
template <typename Obj, typename Func = tcg::empty_type>
|
||
|
class invalidable : tcg::noncopyable<>
|
||
|
{
|
||
|
mutable Obj m_obj; //!< Stored object.
|
||
|
mutable bool m_invalid; //!< Data validity status.
|
||
|
|
||
|
Func m_func; //!< Functor to be invoked upon access.
|
||
|
|
||
|
public:
|
||
|
typedef Obj obj_type;
|
||
|
typedef Func func_type;
|
||
|
|
||
|
public:
|
||
|
invalidable(const func_type &func, bool invalid = false)
|
||
|
: m_obj(), m_func(func), m_invalid(invalid) {}
|
||
|
invalidable(const obj_type &obj, const func_type &func, bool invalid = false)
|
||
|
: m_obj(obj), m_func(func), m_invalid(invalid) {}
|
||
|
|
||
|
void invalidate() { m_invalid = true; }
|
||
|
bool isInvalid() const { return m_invalid; }
|
||
|
|
||
|
const obj_type &operator()(DirectAccess) const { return m_obj; }
|
||
|
obj_type &operator()(DirectAccess) { return m_obj; }
|
||
|
|
||
|
const obj_type &operator()() const
|
||
|
{
|
||
|
if (m_invalid)
|
||
|
m_func(m_obj), m_invalid = false;
|
||
|
|
||
|
return m_obj;
|
||
|
}
|
||
|
|
||
|
obj_type &operator()()
|
||
|
{
|
||
|
if (m_invalid)
|
||
|
m_func(m_obj), m_invalid = false;
|
||
|
|
||
|
return m_obj;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
/*!
|
||
|
\brief Explicit specialization advocating no explicit validator functor - the
|
||
|
accessor must be supplied upon access.
|
||
|
*/
|
||
|
|
||
|
template <typename Obj>
|
||
|
class invalidable<Obj, tcg::empty_type> : tcg::noncopyable<>
|
||
|
{
|
||
|
mutable Obj m_obj; //!< Stored object
|
||
|
mutable bool m_invalid; //!< Data validity status
|
||
|
|
||
|
public:
|
||
|
typedef Obj obj_type;
|
||
|
|
||
|
public:
|
||
|
invalidable(bool invalid = false)
|
||
|
: m_obj(), m_invalid(invalid) {}
|
||
|
invalidable(const obj_type &obj, bool invalid = false)
|
||
|
: m_obj(obj), m_invalid(invalid) {}
|
||
|
|
||
|
void invalidate() { m_invalid = true; }
|
||
|
bool isInvalid() const { return m_invalid; }
|
||
|
|
||
|
const obj_type &operator()(DirectAccess) const { return m_obj; }
|
||
|
obj_type &operator()(DirectAccess) { return m_obj; }
|
||
|
|
||
|
template <typename Func>
|
||
|
const obj_type &operator()(Func func) const
|
||
|
{
|
||
|
if (m_invalid)
|
||
|
func(m_obj), m_invalid = false;
|
||
|
|
||
|
return m_obj;
|
||
|
}
|
||
|
|
||
|
template <typename Func>
|
||
|
obj_type &operator()(Func func)
|
||
|
{
|
||
|
if (m_invalid)
|
||
|
func(m_obj), m_invalid = false;
|
||
|
|
||
|
return m_obj;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
} // namespace tcg
|
||
|
|
||
|
#endif // TCG_CONTROLLED_ACCESS_H
|