diff options
Diffstat (limited to 'o3tl/inc/o3tl/cow_wrapper.hxx')
-rw-r--r-- | o3tl/inc/o3tl/cow_wrapper.hxx | 322 |
1 files changed, 0 insertions, 322 deletions
diff --git a/o3tl/inc/o3tl/cow_wrapper.hxx b/o3tl/inc/o3tl/cow_wrapper.hxx deleted file mode 100644 index b54f99d0f190..000000000000 --- a/o3tl/inc/o3tl/cow_wrapper.hxx +++ /dev/null @@ -1,322 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * This file is part of the LibreOffice project. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. - * - * This file incorporates work covered by the following license notice: - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed - * with this work for additional information regarding copyright - * ownership. The ASF licenses this file to you under the Apache - * License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of - * the License at http://www.apache.org/licenses/LICENSE-2.0 . - */ - -#ifndef INCLUDED_O3TL_COW_WRAPPER_HXX -#define INCLUDED_O3TL_COW_WRAPPER_HXX - -#include <osl/interlck.h> - -#include <algorithm> - -#include <boost/utility.hpp> -#include <boost/checked_delete.hpp> - -namespace o3tl -{ - /** Thread-unsafe refcounting - - This is the default locking policy for cow_wrapper. No - locking/guarding against concurrent access is performed - whatsoever. - */ - struct UnsafeRefCountingPolicy - { - typedef sal_uInt32 ref_count_t; - static void incrementCount( ref_count_t& rCount ) { ++rCount; } - static bool decrementCount( ref_count_t& rCount ) { return --rCount != 0; } - }; - - /** Thread-safe refcounting - - Use this to have the cow_wrapper refcounting mechanisms employ - the thread-safe oslInterlockedCount . - */ - struct ThreadSafeRefCountingPolicy - { - typedef oslInterlockedCount ref_count_t; - static void incrementCount( ref_count_t& rCount ) { osl_atomic_increment(&rCount); } - static bool decrementCount( ref_count_t& rCount ) - { - if( rCount == 1 ) // caller is already the only/last reference - return false; - else - return osl_atomic_decrement(&rCount) != 0; - } - }; - - /** Copy-on-write wrapper. - - This template provides copy-on-write semantics for the wrapped - type: when copying, the operation is performed shallow, - i.e. different cow_wrapper objects share the same underlying - instance. Only when accessing the underlying object via - non-const methods, a unique copy is provided. - - The type parameter <code>T</code> must satisfy the following - requirements: it must be default-constructible, copyable (it - need not be assignable), and be of non-reference type. Note - that, despite the fact that this template provides access to - the wrapped type via pointer-like methods - (<code>operator->()</code> and <code>operator*()</code>), it does - <em>not</em> work like e.g. the boost pointer wrappers - (shared_ptr, scoped_ptr, etc.). Internally, the cow_wrapper - holds a by-value instance of the wrapped object. This is to - avoid one additional heap allocation, and providing access via - <code>operator->()</code>/<code>operator*()</code> is because - <code>operator.()</code> cannot be overridden. - - Regarding thread safety: this wrapper is <em>not</em> - thread-safe per se, because cow_wrapper has no way of - syncronizing the potentially many different cow_wrapper - instances, that reference a single shared value_type - instance. That said, when passing - <code>ThreadSafeRefCountingPolicy</code> as the - <code>MTPolicy</code> parameter, accessing a thread-safe - pointee through multiple cow_wrapper instances might be - thread-safe, if the individual pointee methods are - thread-safe, <em>including</em> pointee's copy - constructor. Any wrapped object that needs external - synchronisation (e.g. via an external mutex, which arbitrates - access to object methods, and can be held across multiple - object method calls) cannot easily be dealt with in a - thread-safe way, because, as noted, objects are shared behind - the client's back. - - @attention if one wants to use the pimpl idiom together with - cow_wrapper (i.e. put an opaque type into the cow_wrapper), - then <em>all<em> methods in the surrounding class needs to be - non-inline (<em>including</em> destructor, copy constructor - and assignment operator). - - @example - <pre> -class cow_wrapper_client_impl; - -class cow_wrapper_client -{ -public: - cow_wrapper_client(); - cow_wrapper_client( const cow_wrapper_client& ); - ~cow_wrapper_client(); - - cow_wrapper_client& operator=( const cow_wrapper_client& ); - - void modify( int nVal ); - int queryUnmodified() const; - -private: - otl::cow_wrapper< cow_wrapper_client_impl > maImpl; -}; - </pre> - and the implementation file would look like this: - <pre> -class cow_wrapper_client_impl -{ -public: - void setValue( int nVal ) { mnValue = nVal; } - int getValue() const { return mnValue; } - -private: - int mnValue; -} - -cow_wrapper_client::cow_wrapper_client() : - maImpl() -{ -} -cow_wrapper_client::cow_wrapper_client( const cow_wrapper_client& rSrc ) : - maImpl( rSrc.maImpl ) -{ -} -cow_wrapper_client::~cow_wrapper_client() -{ -} -cow_wrapper_client& cow_wrapper_client::operator=( const cow_wrapper_client& rSrc ) -{ - maImpl = rSrc.maImpl; - return *this; -} -void cow_wrapper_client::modify( int nVal ) -{ - maImpl->setValue( nVal ); -} -int cow_wrapper_client::queryUnmodified() const -{ - return maImpl->getValue(); -} - </pre> - */ - template<typename T, class MTPolicy=UnsafeRefCountingPolicy> class cow_wrapper - { - /** shared value object - gets cloned before cow_wrapper hands - out a non-const reference to it - */ - struct impl_t : private boost::noncopyable - { - impl_t() : - m_value(), - m_ref_count(1) - { - } - - explicit impl_t( const T& v ) : - m_value(v), - m_ref_count(1) - { - } - - T m_value; - typename MTPolicy::ref_count_t m_ref_count; - }; - - void release() - { - if( !MTPolicy::decrementCount(m_pimpl->m_ref_count) ) - boost::checked_delete(m_pimpl), m_pimpl=0; - } - - public: - typedef T value_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef MTPolicy mt_policy; - - /** Default-construct wrapped type instance - */ - cow_wrapper() : - m_pimpl( new impl_t() ) - { - } - - /** Copy-construct wrapped type instance from given object - */ - explicit cow_wrapper( const value_type& r ) : - m_pimpl( new impl_t(r) ) - { - } - - /** Shallow-copy given cow_wrapper - */ - explicit cow_wrapper( const cow_wrapper& rSrc ) : // nothrow - m_pimpl( rSrc.m_pimpl ) - { - MTPolicy::incrementCount( m_pimpl->m_ref_count ); - } - - ~cow_wrapper() // nothrow, if ~T does not throw - { - release(); - } - - /// now sharing rSrc cow_wrapper instance with us - cow_wrapper& operator=( const cow_wrapper& rSrc ) // nothrow - { - // this already guards against self-assignment - MTPolicy::incrementCount( rSrc.m_pimpl->m_ref_count ); - - release(); - m_pimpl = rSrc.m_pimpl; - - return *this; - } - - /// unshare with any other cow_wrapper instance - value_type& make_unique() - { - if( m_pimpl->m_ref_count > 1 ) - { - impl_t* pimpl = new impl_t(m_pimpl->m_value); - release(); - m_pimpl = pimpl; - } - - return m_pimpl->m_value; - } - - /// true, if not shared with any other cow_wrapper instance - bool is_unique() const // nothrow - { - return m_pimpl->m_ref_count == 1; - } - - /// return number of shared instances (1 for unique object) - typename MTPolicy::ref_count_t use_count() const // nothrow - { - return m_pimpl->m_ref_count; - } - - void swap(cow_wrapper& r) // never throws - { - std::swap(m_pimpl, r.m_pimpl); - } - - pointer operator->() { return &make_unique(); } - value_type& operator*() { return make_unique(); } - const_pointer operator->() const { return &m_pimpl->m_value; } - const value_type& operator*() const { return m_pimpl->m_value; } - - pointer get() { return &make_unique(); } - const_pointer get() const { return &m_pimpl->m_value; } - - /// true, if both cow_wrapper internally share the same object - bool same_object( const cow_wrapper& rOther ) const - { - return rOther.m_pimpl == m_pimpl; - } - - private: - impl_t* m_pimpl; - }; - - - template<class T, class P> inline bool operator==( const cow_wrapper<T,P>& a, - const cow_wrapper<T,P>& b ) - { - return a.same_object(b) ? true : *a == *b; - } - - template<class T, class P> inline bool operator!=( const cow_wrapper<T,P>& a, - const cow_wrapper<T,P>& b ) - { - return a.same_object(b) ? false : *a != *b; - } - - template<class A, class B, class P> inline bool operator<( const cow_wrapper<A,P>& a, - const cow_wrapper<B,P>& b ) - { - return *a < *b; - } - - template<class T, class P> inline void swap( cow_wrapper<T,P>& a, - cow_wrapper<T,P>& b ) - { - a.swap(b); - } - - // to enable boost::mem_fn on cow_wrapper - template<class T, class P> inline T * get_pointer( const cow_wrapper<T,P>& r ) - { - return r.get(); - } - -} - -#endif /* INCLUDED_O3TL_COW_WRAPPER_HXX */ - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |