nss: upgrade to release 3.73
[LibreOffice.git] / include / o3tl / cow_wrapper.hxx
blobb9c463b852e46e961f918c51a5a93c5d06ce4c0f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #ifndef INCLUDED_O3TL_COW_WRAPPER_HXX
21 #define INCLUDED_O3TL_COW_WRAPPER_HXX
23 #include <memory>
24 #include <osl/interlck.h>
26 #include <utility>
27 #include <cstddef>
29 namespace o3tl
31 /** Thread-unsafe refcounting
33 This is the default locking policy for cow_wrapper. No
34 locking/guarding against concurrent access is performed
35 whatsoever.
37 struct UnsafeRefCountingPolicy
39 typedef std::size_t ref_count_t;
40 static void incrementCount( ref_count_t& rCount ) { ++rCount; }
41 static bool decrementCount( ref_count_t& rCount ) { return --rCount != 0; }
44 /** Thread-safe refcounting
46 Use this to have the cow_wrapper refcounting mechanisms employ
47 the thread-safe oslInterlockedCount .
49 struct ThreadSafeRefCountingPolicy
51 typedef oslInterlockedCount ref_count_t;
52 static void incrementCount( ref_count_t& rCount ) { osl_atomic_increment(&rCount); }
53 static bool decrementCount( ref_count_t& rCount )
55 if( rCount == 1 ) // caller is already the only/last reference
56 return false;
57 else
58 return osl_atomic_decrement(&rCount) != 0;
62 /** Copy-on-write wrapper.
64 This template provides copy-on-write semantics for the wrapped
65 type: when copying, the operation is performed shallow,
66 i.e. different cow_wrapper objects share the same underlying
67 instance. Only when accessing the underlying object via
68 non-const methods, a unique copy is provided.
70 The type parameter <code>T</code> must satisfy the following
71 requirements: it must be default-constructible, copyable (it
72 need not be assignable), and be of non-reference type. Note
73 that, despite the fact that this template provides access to
74 the wrapped type via pointer-like methods
75 (<code>operator->()</code> and <code>operator*()</code>), it does
76 <em>not</em> work like e.g. the std smart pointer wrappers
77 (shared_ptr, unique_ptr, etc.). Internally, the cow_wrapper
78 holds a by-value instance of the wrapped object. This is to
79 avoid one additional heap allocation, and providing access via
80 <code>operator->()</code>/<code>operator*()</code> is because
81 <code>operator.()</code> cannot be overridden.
83 Regarding thread safety: this wrapper is <em>not</em>
84 thread-safe per se, because cow_wrapper has no way of
85 synchronizing the potentially many different cow_wrapper
86 instances, that reference a single shared value_type
87 instance. That said, when passing
88 <code>ThreadSafeRefCountingPolicy</code> as the
89 <code>MTPolicy</code> parameter, accessing a thread-safe
90 pointee through multiple cow_wrapper instances might be
91 thread-safe, if the individual pointee methods are
92 thread-safe, <em>including</em> pointee's copy
93 constructor. Any wrapped object that needs external
94 synchronisation (e.g. via an external mutex, which arbitrates
95 access to object methods, and can be held across multiple
96 object method calls) cannot easily be dealt with in a
97 thread-safe way, because, as noted, objects are shared behind
98 the client's back.
100 @attention if one wants to use the pimpl idiom together with
101 cow_wrapper (i.e. put an opaque type into the cow_wrapper),
102 then <em>all<em> methods in the surrounding class needs to be
103 non-inline (<em>including</em> destructor, copy constructor
104 and assignment operator).
106 @example
107 <pre>
108 class cow_wrapper_client_impl;
110 class cow_wrapper_client
112 public:
113 cow_wrapper_client();
114 cow_wrapper_client( const cow_wrapper_client& );
115 cow_wrapper_client( cow_wrapper_client&& );
116 ~cow_wrapper_client();
118 cow_wrapper_client& operator=( const cow_wrapper_client& );
119 cow_wrapper_client& operator=( cow_wrapper_client&& );
121 void modify( int nVal );
122 int queryUnmodified() const;
124 private:
125 o3tl::cow_wrapper< cow_wrapper_client_impl > maImpl;
127 </pre>
128 and the implementation file would look like this:
129 <pre>
130 class cow_wrapper_client_impl
132 public:
133 void setValue( int nVal ) { mnValue = nVal; }
134 int getValue() const { return mnValue; }
136 private:
137 int mnValue;
140 cow_wrapper_client::cow_wrapper_client() :
141 maImpl()
144 cow_wrapper_client::cow_wrapper_client( const cow_wrapper_client& rSrc ) :
145 maImpl( rSrc.maImpl )
148 cow_wrapper_client::cow_wrapper_client( cow_wrapper_client& rSrc ) :
149 maImpl( std::move( rSrc.maImpl ) )
152 cow_wrapper_client::~cow_wrapper_client()
155 cow_wrapper_client& cow_wrapper_client::operator=( const cow_wrapper_client& rSrc )
157 maImpl = rSrc.maImpl;
158 return *this;
160 cow_wrapper_client& cow_wrapper_client::operator=( cow_wrapper_client&& rSrc )
162 maImpl = std::move( rSrc.maImpl );
163 return *this;
165 void cow_wrapper_client::modify( int nVal )
167 maImpl->setValue( nVal );
169 int cow_wrapper_client::queryUnmodified() const
171 return maImpl->getValue();
173 </pre>
175 template<typename T, class MTPolicy=UnsafeRefCountingPolicy> class cow_wrapper
177 /** shared value object - gets cloned before cow_wrapper hands
178 out a non-const reference to it
180 struct impl_t
182 impl_t(const impl_t&) = delete;
183 impl_t& operator=(const impl_t&) = delete;
185 impl_t() :
186 m_value(),
187 m_ref_count(1)
191 explicit impl_t( const T& v ) :
192 m_value(v),
193 m_ref_count(1)
197 explicit impl_t( T&& v ) :
198 m_value(std::move(v)),
199 m_ref_count(1)
203 T m_value;
204 typename MTPolicy::ref_count_t m_ref_count;
207 void release()
209 if( m_pimpl && !MTPolicy::decrementCount(m_pimpl->m_ref_count) )
211 delete m_pimpl;
212 m_pimpl = nullptr;
216 public:
217 typedef T value_type;
218 typedef T* pointer;
219 typedef const T* const_pointer;
220 typedef MTPolicy mt_policy;
222 /** Default-construct wrapped type instance
224 cow_wrapper() :
225 m_pimpl( new impl_t() )
229 /** Copy-construct wrapped type instance from given object
231 explicit cow_wrapper( const value_type& r ) :
232 m_pimpl( new impl_t(r) )
236 /** Move-construct wrapped type instance from given object
238 explicit cow_wrapper( value_type&& r ) :
239 m_pimpl( new impl_t(std::move(r)) )
243 /** Shallow-copy given cow_wrapper
245 explicit cow_wrapper( const cow_wrapper& rSrc ) : // nothrow
246 m_pimpl( rSrc.m_pimpl )
248 MTPolicy::incrementCount( m_pimpl->m_ref_count );
251 /** Move-construct and steal rSrc shared resource
253 explicit cow_wrapper( cow_wrapper&& rSrc ) noexcept :
254 m_pimpl( rSrc.m_pimpl )
256 rSrc.m_pimpl = nullptr;
259 ~cow_wrapper() // nothrow, if ~T does not throw
261 release();
264 /// now sharing rSrc cow_wrapper instance with us
265 cow_wrapper& operator=( const cow_wrapper& rSrc ) // nothrow
267 // this already guards against self-assignment
268 MTPolicy::incrementCount( rSrc.m_pimpl->m_ref_count );
270 release();
271 m_pimpl = rSrc.m_pimpl;
273 return *this;
276 /// stealing rSrc's resource
277 cow_wrapper& operator=(cow_wrapper&& rSrc) noexcept
279 // self-movement guts ourself, see also 17.6.4.9
280 release();
281 m_pimpl = rSrc.m_pimpl;
283 rSrc.m_pimpl = nullptr;
285 return *this;
288 /// unshare with any other cow_wrapper instance
289 value_type& make_unique()
291 if( m_pimpl->m_ref_count > 1 )
293 impl_t* pimpl = new impl_t(m_pimpl->m_value);
294 release();
295 m_pimpl = pimpl;
298 return m_pimpl->m_value;
301 /// true, if not shared with any other cow_wrapper instance
302 bool is_unique() const // nothrow
304 return !m_pimpl || m_pimpl->m_ref_count == 1;
307 /// return number of shared instances (1 for unique object)
308 typename MTPolicy::ref_count_t use_count() const // nothrow
310 return m_pimpl ? m_pimpl->m_ref_count : 0;
313 void swap(cow_wrapper& r) // never throws
315 std::swap(m_pimpl, r.m_pimpl);
318 pointer operator->() { return &make_unique(); }
319 value_type& operator*() { return make_unique(); }
320 const_pointer operator->() const { return &m_pimpl->m_value; }
321 const value_type& operator*() const { return m_pimpl->m_value; }
323 pointer get() { return &make_unique(); }
324 const_pointer get() const { return &m_pimpl->m_value; }
326 /// true, if both cow_wrapper internally share the same object
327 bool same_object( const cow_wrapper& rOther ) const
329 return rOther.m_pimpl == m_pimpl;
332 private:
333 impl_t* m_pimpl;
337 template<class T, class P> inline bool operator==( const cow_wrapper<T,P>& a,
338 const cow_wrapper<T,P>& b )
340 return a.same_object(b) || *a == *b;
343 template<class T, class P> inline bool operator!=( const cow_wrapper<T,P>& a,
344 const cow_wrapper<T,P>& b )
346 return !a.same_object(b) && *a != *b;
349 template<class A, class B, class P> inline bool operator<( const cow_wrapper<A,P>& a,
350 const cow_wrapper<B,P>& b )
352 return *a < *b;
355 template<class T, class P> inline void swap( cow_wrapper<T,P>& a,
356 cow_wrapper<T,P>& b )
358 a.swap(b);
363 #endif /* INCLUDED_O3TL_COW_WRAPPER_HXX */
365 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */