tdf#130857 qt weld: Support mail merge "Server Auth" dialog
[LibreOffice.git] / include / o3tl / cow_wrapper.hxx
blob3c5de8eedf3d10944e661944dba4762cdf88595b
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 <atomic>
24 #include <optional>
25 #include <cstddef>
27 namespace o3tl
29 /** Thread-unsafe refcounting
31 This is the default locking policy for cow_wrapper. No
32 locking/guarding against concurrent access is performed
33 whatsoever.
35 struct UnsafeRefCountingPolicy
37 typedef std::size_t ref_count_t;
38 static void incrementCount( ref_count_t& rCount ) { ++rCount; }
39 static bool decrementCount( ref_count_t& rCount ) { return --rCount != 0; }
40 static std::size_t getCount( ref_count_t& rCount) { return rCount; }
43 /** Thread-safe refcounting
45 Use this to have the cow_wrapper refcounting mechanisms employ
46 the thread-safe oslInterlockedCount .
48 struct ThreadSafeRefCountingPolicy
50 typedef std::atomic<int> ref_count_t;
51 static void incrementCount( ref_count_t& rCount ) { rCount++; }
52 static bool decrementCount( ref_count_t& rCount )
54 return (--rCount) != 0;
56 static std::size_t getCount( ref_count_t& rCount) { return rCount; }
59 /** Copy-on-write wrapper.
61 This template provides copy-on-write semantics for the wrapped
62 type: when copying, the operation is performed shallow,
63 i.e. different cow_wrapper objects share the same underlying
64 instance. Only when accessing the underlying object via
65 non-const methods, a unique copy is provided.
67 The type parameter <code>T</code> must satisfy the following
68 requirements: it must be default-constructible, copyable (it
69 need not be assignable), and be of non-reference type. Note
70 that, despite the fact that this template provides access to
71 the wrapped type via pointer-like methods
72 (<code>operator->()</code> and <code>operator*()</code>), it does
73 <em>not</em> work like e.g. the std smart pointer wrappers
74 (shared_ptr, unique_ptr, etc.). Internally, the cow_wrapper
75 holds a by-value instance of the wrapped object. This is to
76 avoid one additional heap allocation, and providing access via
77 <code>operator->()</code>/<code>operator*()</code> is because
78 <code>operator.()</code> cannot be overridden.
80 Regarding thread safety: this wrapper is <em>not</em>
81 thread-safe per se, because cow_wrapper has no way of
82 synchronizing the potentially many different cow_wrapper
83 instances, that reference a single shared value_type
84 instance. That said, when passing
85 <code>ThreadSafeRefCountingPolicy</code> as the
86 <code>MTPolicy</code> parameter, accessing a thread-safe
87 pointee through multiple cow_wrapper instances might be
88 thread-safe, if the individual pointee methods are
89 thread-safe, <em>including</em> pointee's copy
90 constructor. Any wrapped object that needs external
91 synchronisation (e.g. via an external mutex, which arbitrates
92 access to object methods, and can be held across multiple
93 object method calls) cannot easily be dealt with in a
94 thread-safe way, because, as noted, objects are shared behind
95 the client's back.
97 @attention if one wants to use the pimpl idiom together with
98 cow_wrapper (i.e. put an opaque type into the cow_wrapper),
99 then <em>all<em> methods in the surrounding class needs to be
100 non-inline (<em>including</em> destructor, copy constructor
101 and assignment operator).
103 @example
104 <pre>
105 class cow_wrapper_client_impl;
107 class cow_wrapper_client
109 public:
110 cow_wrapper_client();
111 cow_wrapper_client( const cow_wrapper_client& );
112 cow_wrapper_client( cow_wrapper_client&& );
113 ~cow_wrapper_client();
115 cow_wrapper_client& operator=( const cow_wrapper_client& );
116 cow_wrapper_client& operator=( cow_wrapper_client&& );
118 void modify( int nVal );
119 int queryUnmodified() const;
121 private:
122 o3tl::cow_wrapper< cow_wrapper_client_impl > maImpl;
124 </pre>
125 and the implementation file would look like this:
126 <pre>
127 class cow_wrapper_client_impl
129 public:
130 void setValue( int nVal ) { mnValue = nVal; }
131 int getValue() const { return mnValue; }
133 private:
134 int mnValue;
137 cow_wrapper_client::cow_wrapper_client() :
138 maImpl()
141 cow_wrapper_client::cow_wrapper_client( const cow_wrapper_client& rSrc ) :
142 maImpl( rSrc.maImpl )
145 cow_wrapper_client::cow_wrapper_client( cow_wrapper_client& rSrc ) :
146 maImpl( std::move( rSrc.maImpl ) )
149 cow_wrapper_client::~cow_wrapper_client()
152 cow_wrapper_client& cow_wrapper_client::operator=( const cow_wrapper_client& rSrc )
154 maImpl = rSrc.maImpl;
155 return *this;
157 cow_wrapper_client& cow_wrapper_client::operator=( cow_wrapper_client&& rSrc )
159 maImpl = std::move( rSrc.maImpl );
160 return *this;
162 void cow_wrapper_client::modify( int nVal )
164 maImpl->setValue( nVal );
166 int cow_wrapper_client::queryUnmodified() const
168 return maImpl->getValue();
170 </pre>
172 template<typename T, class MTPolicy=UnsafeRefCountingPolicy> class cow_wrapper
174 /** shared value object - gets cloned before cow_wrapper hands
175 out a non-const reference to it
177 struct impl_t
179 impl_t(const impl_t&) = delete;
180 impl_t& operator=(const impl_t&) = delete;
182 impl_t() :
183 m_value(),
184 m_ref_count(1)
188 explicit impl_t( const T& v ) :
189 m_value(v),
190 m_ref_count(1)
194 explicit impl_t( T&& v ) :
195 m_value(std::move(v)),
196 m_ref_count(1)
200 T m_value;
201 typename MTPolicy::ref_count_t m_ref_count;
204 void release()
206 if( m_pimpl && !MTPolicy::decrementCount(m_pimpl->m_ref_count) )
208 delete m_pimpl;
209 m_pimpl = nullptr;
213 public:
214 typedef T value_type;
215 typedef T* pointer;
216 typedef const T* const_pointer;
217 typedef MTPolicy mt_policy;
219 /** Default-construct wrapped type instance
221 cow_wrapper() :
222 m_pimpl( new impl_t() )
226 /** Copy-construct wrapped type instance from given object
228 explicit cow_wrapper( const value_type& r ) :
229 m_pimpl( new impl_t(r) )
233 /** Move-construct wrapped type instance from given object
235 explicit cow_wrapper( value_type&& r ) :
236 m_pimpl( new impl_t(std::move(r)) )
240 /** Shallow-copy given cow_wrapper
242 explicit cow_wrapper( const cow_wrapper& rSrc ) : // nothrow
243 m_pimpl( rSrc.m_pimpl )
245 MTPolicy::incrementCount( m_pimpl->m_ref_count );
248 /** Move-construct and steal rSrc shared resource
250 explicit cow_wrapper( cow_wrapper&& rSrc ) noexcept :
251 m_pimpl( rSrc.m_pimpl )
253 rSrc.m_pimpl = nullptr;
256 // Only intended to be used by std::optional specialisations
257 explicit cow_wrapper( std::nullopt_t ) noexcept :
258 m_pimpl( nullptr )
262 // Only intended to be used by std::optional specialisations
263 explicit cow_wrapper( const cow_wrapper& rSrc, std::nullopt_t ) : // nothrow
264 m_pimpl( rSrc.m_pimpl )
266 if (m_pimpl)
267 MTPolicy::incrementCount( m_pimpl->m_ref_count );
270 ~cow_wrapper() // nothrow, if ~T does not throw
272 release();
275 /// now sharing rSrc cow_wrapper instance with us
276 cow_wrapper& operator=( const cow_wrapper& rSrc ) // nothrow
278 // this already guards against self-assignment
279 MTPolicy::incrementCount( rSrc.m_pimpl->m_ref_count );
281 release();
282 m_pimpl = rSrc.m_pimpl;
284 return *this;
287 /// stealing rSrc's resource
288 cow_wrapper& operator=(cow_wrapper&& rSrc) noexcept
290 // self-movement guts ourself, see also 17.6.4.9
291 release();
292 m_pimpl = rSrc.m_pimpl;
294 rSrc.m_pimpl = nullptr;
296 return *this;
299 /// unshare with any other cow_wrapper instance
300 value_type& make_unique()
302 if( m_pimpl->m_ref_count > 1 )
304 impl_t* pimpl = new impl_t(m_pimpl->m_value);
305 release();
306 m_pimpl = pimpl;
309 return m_pimpl->m_value;
312 /// true, if not shared with any other cow_wrapper instance
313 bool is_unique() const // nothrow
315 return !m_pimpl || m_pimpl->m_ref_count == 1;
318 /// return number of shared instances (1 for unique object)
319 size_t use_count() const // nothrow
321 return m_pimpl ? MTPolicy::getCount(m_pimpl->m_ref_count) : 0;
324 void swap(cow_wrapper& r) // never throws
326 std::swap(m_pimpl, r.m_pimpl);
329 pointer operator->() { return &make_unique(); }
330 value_type& operator*() { return make_unique(); }
331 const_pointer operator->() const { return &m_pimpl->m_value; }
332 const value_type& operator*() const { return m_pimpl->m_value; }
334 pointer get() { return &make_unique(); }
335 const_pointer get() const { return &m_pimpl->m_value; }
337 /// true, if both cow_wrapper internally share the same object
338 bool same_object( const cow_wrapper& rOther ) const
340 return rOther.m_pimpl == m_pimpl;
343 // Only intended to be used by std::optional specialisations
344 bool empty() const { return m_pimpl == nullptr; }
345 // Only intended to be used by std::optional specialisations
346 void set_empty()
348 if (m_pimpl)
350 release();
351 m_pimpl = nullptr;
355 private:
356 impl_t* m_pimpl;
360 template<class T, class P> inline bool operator==( const cow_wrapper<T,P>& a,
361 const cow_wrapper<T,P>& b )
363 return a.same_object(b) || *a == *b;
366 template<class T, class P> inline bool operator!=( const cow_wrapper<T,P>& a,
367 const cow_wrapper<T,P>& b )
369 return !a.same_object(b) && *a != *b;
372 template<class A, class B, class P> inline bool operator<( const cow_wrapper<A,P>& a,
373 const cow_wrapper<B,P>& b )
375 return *a < *b;
378 template<class T, class P> inline void swap( cow_wrapper<T,P>& a,
379 cow_wrapper<T,P>& b )
381 a.swap(b);
386 #endif /* INCLUDED_O3TL_COW_WRAPPER_HXX */
388 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */