LibreOffice Module o3tl (master) 1
cow_wrapper.hxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#ifndef INCLUDED_O3TL_COW_WRAPPER_HXX
21#define INCLUDED_O3TL_COW_WRAPPER_HXX
22
23#include <osl/interlck.h>
24
25#include <optional>
26#include <cstddef>
27
28namespace o3tl
29{
37 {
38 typedef std::size_t ref_count_t;
39 static void incrementCount( ref_count_t& rCount ) { ++rCount; }
40 static bool decrementCount( ref_count_t& rCount ) { return --rCount != 0; }
41 };
42
49 {
50 typedef oslInterlockedCount ref_count_t;
51 static void incrementCount( ref_count_t& rCount ) { osl_atomic_increment(&rCount); }
52 static bool decrementCount( ref_count_t& rCount )
53 {
54 return osl_atomic_decrement(&rCount) != 0;
55 }
56 };
57
171 template<typename T, class MTPolicy=UnsafeRefCountingPolicy> class cow_wrapper
172 {
176 struct impl_t
177 {
178 impl_t(const impl_t&) = delete;
179 impl_t& operator=(const impl_t&) = delete;
180
182 m_value(),
183 m_ref_count(1)
184 {
185 }
186
187 explicit impl_t( const T& v ) :
188 m_value(v),
189 m_ref_count(1)
190 {
191 }
192
193 explicit impl_t( T&& v ) :
194 m_value(std::move(v)),
195 m_ref_count(1)
196 {
197 }
198
200 typename MTPolicy::ref_count_t m_ref_count;
201 };
202
203 void release()
204 {
205 if( m_pimpl && !MTPolicy::decrementCount(m_pimpl->m_ref_count) )
206 {
207 delete m_pimpl;
208 m_pimpl = nullptr;
209 }
210 }
211
212 public:
213 typedef T value_type;
214 typedef T* pointer;
215 typedef const T* const_pointer;
216 typedef MTPolicy mt_policy;
217
221 m_pimpl( new impl_t() )
222 {
223 }
224
227 explicit cow_wrapper( const value_type& r ) :
228 m_pimpl( new impl_t(r) )
229 {
230 }
231
234 explicit cow_wrapper( value_type&& r ) :
235 m_pimpl( new impl_t(std::move(r)) )
236 {
237 }
238
241 explicit cow_wrapper( const cow_wrapper& rSrc ) : // nothrow
242 m_pimpl( rSrc.m_pimpl )
243 {
244 MTPolicy::incrementCount( m_pimpl->m_ref_count );
245 }
246
249 explicit cow_wrapper( cow_wrapper&& rSrc ) noexcept :
250 m_pimpl( rSrc.m_pimpl )
251 {
252 rSrc.m_pimpl = nullptr;
253 }
254
255 // Only intended to be used by std::optional specialisations
256 explicit cow_wrapper( std::nullopt_t ) noexcept :
257 m_pimpl( nullptr )
258 {
259 }
260
261 // Only intended to be used by std::optional specialisations
262 explicit cow_wrapper( const cow_wrapper& rSrc, std::nullopt_t ) : // nothrow
263 m_pimpl( rSrc.m_pimpl )
264 {
265 if (m_pimpl)
266 MTPolicy::incrementCount( m_pimpl->m_ref_count );
267 }
268
269 ~cow_wrapper() // nothrow, if ~T does not throw
270 {
271 release();
272 }
273
275 cow_wrapper& operator=( const cow_wrapper& rSrc ) // nothrow
276 {
277 // this already guards against self-assignment
278 MTPolicy::incrementCount( rSrc.m_pimpl->m_ref_count );
279
280 release();
281 m_pimpl = rSrc.m_pimpl;
282
283 return *this;
284 }
285
288 {
289 // self-movement guts ourself, see also 17.6.4.9
290 release();
291 m_pimpl = rSrc.m_pimpl;
292
293 rSrc.m_pimpl = nullptr;
294
295 return *this;
296 }
297
300 {
301 if( m_pimpl->m_ref_count > 1 )
302 {
303 impl_t* pimpl = new impl_t(m_pimpl->m_value);
304 release();
305 m_pimpl = pimpl;
306 }
307
308 return m_pimpl->m_value;
309 }
310
312 bool is_unique() const // nothrow
313 {
314 return !m_pimpl || m_pimpl->m_ref_count == 1;
315 }
316
318 typename MTPolicy::ref_count_t use_count() const // nothrow
319 {
320 return m_pimpl ? m_pimpl->m_ref_count : 0;
321 }
322
323 void swap(cow_wrapper& r) // never throws
324 {
326 }
327
331 const value_type& operator*() const { return m_pimpl->m_value; }
332
333 pointer get() { return &make_unique(); }
334 const_pointer get() const { return &m_pimpl->m_value; }
335
337 bool same_object( const cow_wrapper& rOther ) const
338 {
339 return rOther.m_pimpl == m_pimpl;
340 }
341
342 // Only intended to be used by std::optional specialisations
343 bool empty() const { return m_pimpl == nullptr; }
344 // Only intended to be used by std::optional specialisations
346 {
347 if (m_pimpl)
348 {
349 release();
350 m_pimpl = nullptr;
351 }
352 }
353
354 private:
356 };
357
358
359 template<class T, class P> inline bool operator==( const cow_wrapper<T,P>& a,
360 const cow_wrapper<T,P>& b )
361 {
362 return a.same_object(b) || *a == *b;
363 }
364
365 template<class T, class P> inline bool operator!=( const cow_wrapper<T,P>& a,
366 const cow_wrapper<T,P>& b )
367 {
368 return !a.same_object(b) && *a != *b;
369 }
370
371 template<class A, class B, class P> inline bool operator<( const cow_wrapper<A,P>& a,
372 const cow_wrapper<B,P>& b )
373 {
374 return *a < *b;
375 }
376
377 template<class T, class P> inline void swap( cow_wrapper<T,P>& a,
379 {
380 a.swap(b);
381 }
382
383}
384
385#endif /* INCLUDED_O3TL_COW_WRAPPER_HXX */
386
387/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool same_object(const cow_wrapper &rOther) const
true, if both cow_wrapper internally share the same object
MTPolicy::ref_count_t use_count() const
return number of shared instances (1 for unique object)
cow_wrapper()
Default-construct wrapped type instance.
cow_wrapper(const cow_wrapper &rSrc, std::nullopt_t)
value_type & make_unique()
unshare with any other cow_wrapper instance
cow_wrapper(std::nullopt_t) noexcept
cow_wrapper & operator=(const cow_wrapper &rSrc)
now sharing rSrc cow_wrapper instance with us
cow_wrapper & operator=(cow_wrapper &&rSrc) noexcept
stealing rSrc's resource
value_type & operator*()
const value_type & operator*() const
cow_wrapper(value_type &&r)
Move-construct wrapped type instance from given object.
const T * const_pointer
bool empty() const
cow_wrapper(const value_type &r)
Copy-construct wrapped type instance from given object.
const_pointer operator->() const
const_pointer get() const
cow_wrapper(cow_wrapper &&rSrc) noexcept
Move-construct and steal rSrc shared resource.
cow_wrapper(const cow_wrapper &rSrc)
Shallow-copy given cow_wrapper.
pointer operator->()
bool is_unique() const
true, if not shared with any other cow_wrapper instance
void swap(cow_wrapper &r)
float v
uno_Any a
void swap(cow_wrapper< T, P > &a, cow_wrapper< T, P > &b)
bool operator==(const cow_wrapper< T, P > &a, const cow_wrapper< T, P > &b)
bool operator<(const cow_wrapper< A, P > &a, const cow_wrapper< B, P > &b)
bool operator!=(const cow_wrapper< T, P > &a, const cow_wrapper< T, P > &b)
Thread-safe refcounting.
Definition: cow_wrapper.hxx:49
static bool decrementCount(ref_count_t &rCount)
Definition: cow_wrapper.hxx:52
oslInterlockedCount ref_count_t
Definition: cow_wrapper.hxx:50
static void incrementCount(ref_count_t &rCount)
Definition: cow_wrapper.hxx:51
Thread-unsafe refcounting.
Definition: cow_wrapper.hxx:37
static bool decrementCount(ref_count_t &rCount)
Definition: cow_wrapper.hxx:40
static void incrementCount(ref_count_t &rCount)
Definition: cow_wrapper.hxx:39
shared value object - gets cloned before cow_wrapper hands out a non-const reference to it
impl_t & operator=(const impl_t &)=delete
MTPolicy::ref_count_t m_ref_count
impl_t(const impl_t &)=delete