|
// FD.Delegate library
// Copyright (c) 2007 JaeWook Choi
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/test/minimal.hpp>
#include <cassert>
#include <iostream>
#include <boost/thread.hpp>
#include <boost/shared_ptr.hpp>
#include <fd/delegate.hpp>
static std::string test_output;
/**
* Transfer ownership of the lock when the object is being copied.
*/
template<class Lock>
class transfered_lock
{
// lock
Lock & lock_;
// disabled?
mutable bool disabled_;
// no default constructor
transfered_lock();
protected:
// Constructor
explicit transfered_lock(Lock & lk) throw()
: lock_( lk ), disabled_( false )
{
boost::detail::thread::lock_ops<Lock>::lock( lock_ ); // lock.
test_output += "Locked ";
}
// Copy constructor
transfered_lock(transfered_lock const & other) throw()
: lock_( other.lock_ ), disabled_( false )
{
// Transfer the ownership of the lock from other to this
other.disabled_ = true; // disable other's lock
}
// Destructor.
~transfered_lock() throw()
{
if( !disabled_ )
{ // Unlock. if and only if it is not disabled
boost::detail::thread::lock_ops<Lock>::unlock( lock_ );
test_output += "Unlocked ";
}
}
private:
// No assignment operator
transfered_lock & operator =(transfered_lock const & other);
}; // class transfered_lock
/**
*
*/
template<class T, class Lock>
class proxy
: private transfered_lock<Lock>
{
private:
T * pt_; //!< Pointed object.
public:
proxy(Lock & lock, T * pt)
: transfered_lock<Lock>( lock ), pt_( pt )
{
}
T * operator ->() const
{
assert( 0 != pt_ );
return pt_;
}
T & operator *() const
{
assert( 0 != pt_ );
return *pt_;
}
}; // class proxy
template<typename T, typename Lock = boost::mutex>
class guarded_ptr
{
private:
mutable Lock * lock_ptr_;
boost::shared_ptr<T> sptr_;
struct delete_lock
{
Lock * lock_ptr_;
delete_lock(Lock * lock_ptr) : lock_ptr_( lock_ptr ) { }
template<typename U>
void operator ()(U u)
{
boost::checked_delete( u );
delete lock_ptr_;
}
};
public:
typedef T value_type;
typedef Lock lock_type;
typedef proxy<T, Lock> proxy_type;
guarded_ptr() : sptr_(), lock_ptr_( 0 ) { }
template<typename U>
explicit guarded_ptr(U * pt)
: lock_ptr_( new Lock() ), sptr_( pt, delete_lock( lock_ptr_ ) )
{
}
template<typename U>
explicit guarded_ptr(guarded_ptr<U, Lock> const & other)
: lock_ptr_( other.lock_ptr_ ), sptr_( other.sptr_ )
{
}
void swap(guarded_ptr & other)
{
std::swap( lock_ptr_, other.lock_ptr_ );
sptr_.swap( other.sptr_ );
}
template<typename U>
guarded_ptr & operator =(U * pt)
{
guarded_ptr<T, Lock>( pt ).swap( *this );
return *this;
}
template<typename U>
guarded_ptr & operator =(guarded_ptr<U, Lock> const & other)
{
if(this != &other)
{
guarded_ptr( other ).swap( *this );
}
return *this;
}
proxy<T, Lock> operator ->() const
{
return proxy<T, Lock>( *lock_ptr_, sptr_.get() );
}
void reset()
{
guarded_ptr().swap( *this );
}
template<typename U>
void reset(U * pt)
{
guarded_ptr( pt ).swap( *this );
}
template<typename U>
void reset(guarded_ptr<U, Lock> const & other)
{
if( this != &other )
{
guarded_ptr( other ).swap( *this );
}
}
}; // class guarded_ptr
/**
* Library designer can provide get_pointer() to make their smart pointer class
* work with FD.Delegate. However, get_pointer() is not necessarily required
* to return a raw pointer and instead it can return a proxy object as long as
* the returned proxy object supports following two operations of a raw pointer.
*
* 1) member access; operator ->
* 2) dereference; operator *
*/
template<typename T>
typename guarded_ptr<T>::proxy_type get_pointer(guarded_ptr<T> const & gptr)
{
return gptr.operator ->();
}
struct foo
{
void bar()
{
test_output += "foo::bar() ";
}
void foobar()
{
test_output += "foo::foobar() ";
}
};
int
test_main(int, char*[])
{
guarded_ptr<foo> foo_gptr( new foo() );
std::cout << "guarded_ptr #1" << std::endl;
test_output = "";
foo_gptr->bar(); std::cout << std::endl;
BOOST_CHECK(test_output == "Locked foo::bar() Unlocked ");
std::cout << "guarded_ptr #2" << std::endl;
test_output = "";
foo_gptr->foobar(); std::cout << std::endl;
BOOST_CHECK(test_output == "Locked foo::foobar() Unlocked ");
std::cout << "guarded_ptr #3" << std::endl;
test_output = "";
( &( *( foo_gptr.operator ->() ) )->*&foo::bar )(); std::cout<< std::endl;
BOOST_CHECK(test_output == "Locked foo::bar() Unlocked ");
fd::delegate<void ()> dg_foo1, dg_foo2;
dg_foo1.bind( &foo::bar, foo_gptr );
dg_foo2 = dg_foo1;
std::cout << "guarded_ptr in FD.Delegate #1" << std::endl;
test_output = "";
dg_foo1(); std::cout<< std::endl;
BOOST_CHECK(test_output == "Locked foo::bar() Unlocked ");
std::cout << "guarded_ptr in FD.Delegate #2" << std::endl;
test_output = "";
dg_foo2(); std::cout<< std::endl;
BOOST_CHECK(test_output == "Locked foo::bar() Unlocked ");
return 0;
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.
A list of licenses authors might use can be found here
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.