#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 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 class controlled_access : 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 const obj_type &operator()(Func func) const { func(m_obj); return m_obj; } template 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 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 class invalidable : 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 const obj_type &operator()(Func func) const { if (m_invalid) func(m_obj), m_invalid = false; return m_obj; } template obj_type &operator()(Func func) { if (m_invalid) func(m_obj), m_invalid = false; return m_obj; } }; } // namespace tcg #endif // TCG_CONTROLLED_ACCESS_H