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 <memory>
24 #include <osl/interlck.h>
25 
26 #include <utility>
27 #include <cstddef>
28 
29 namespace o3tl
30 {
38  {
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; }
42  };
43 
50  {
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 )
54  {
55  if( rCount == 1 ) // caller is already the only/last reference
56  return false;
57  else
58  return osl_atomic_decrement(&rCount) != 0;
59  }
60  };
61 
175  template<typename T, class MTPolicy=UnsafeRefCountingPolicy> class cow_wrapper
176  {
180  struct impl_t
181  {
182  impl_t(const impl_t&) = delete;
183  impl_t& operator=(const impl_t&) = delete;
184 
185  impl_t() :
186  m_value(),
187  m_ref_count(1)
188  {
189  }
190 
191  explicit impl_t( const T& v ) :
192  m_value(v),
193  m_ref_count(1)
194  {
195  }
196 
197  explicit impl_t( T&& v ) :
198  m_value(std::move(v)),
199  m_ref_count(1)
200  {
201  }
202 
204  typename MTPolicy::ref_count_t m_ref_count;
205  };
206 
207  void release()
208  {
209  if( m_pimpl && !MTPolicy::decrementCount(m_pimpl->m_ref_count) )
210  {
211  delete m_pimpl;
212  m_pimpl = nullptr;
213  }
214  }
215 
216  public:
217  typedef T value_type;
218  typedef T* pointer;
219  typedef const T* const_pointer;
220  typedef MTPolicy mt_policy;
221 
225  m_pimpl( new impl_t() )
226  {
227  }
228 
231  explicit cow_wrapper( const value_type& r ) :
232  m_pimpl( new impl_t(r) )
233  {
234  }
235 
238  explicit cow_wrapper( value_type&& r ) :
239  m_pimpl( new impl_t(std::move(r)) )
240  {
241  }
242 
245  explicit cow_wrapper( const cow_wrapper& rSrc ) : // nothrow
246  m_pimpl( rSrc.m_pimpl )
247  {
248  MTPolicy::incrementCount( m_pimpl->m_ref_count );
249  }
250 
253  explicit cow_wrapper( cow_wrapper&& rSrc ) noexcept :
254  m_pimpl( rSrc.m_pimpl )
255  {
256  rSrc.m_pimpl = nullptr;
257  }
258 
259  ~cow_wrapper() // nothrow, if ~T does not throw
260  {
261  release();
262  }
263 
265  cow_wrapper& operator=( const cow_wrapper& rSrc ) // nothrow
266  {
267  // this already guards against self-assignment
268  MTPolicy::incrementCount( rSrc.m_pimpl->m_ref_count );
269 
270  release();
271  m_pimpl = rSrc.m_pimpl;
272 
273  return *this;
274  }
275 
278  {
279  // self-movement guts ourself, see also 17.6.4.9
280  release();
281  m_pimpl = rSrc.m_pimpl;
282 
283  rSrc.m_pimpl = nullptr;
284 
285  return *this;
286  }
287 
289  value_type& make_unique()
290  {
291  if( m_pimpl->m_ref_count > 1 )
292  {
293  impl_t* pimpl = new impl_t(m_pimpl->m_value);
294  release();
295  m_pimpl = pimpl;
296  }
297 
298  return m_pimpl->m_value;
299  }
300 
302  bool is_unique() const // nothrow
303  {
304  return !m_pimpl || m_pimpl->m_ref_count == 1;
305  }
306 
308  typename MTPolicy::ref_count_t use_count() const // nothrow
309  {
310  return m_pimpl ? m_pimpl->m_ref_count : 0;
311  }
312 
313  void swap(cow_wrapper& r) // never throws
314  {
316  }
317 
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; }
322 
323  pointer get() { return &make_unique(); }
324  const_pointer get() const { return &m_pimpl->m_value; }
325 
327  bool same_object( const cow_wrapper& rOther ) const
328  {
329  return rOther.m_pimpl == m_pimpl;
330  }
331 
332  private:
333  impl_t* m_pimpl;
334  };
335 
336 
337  template<class T, class P> inline bool operator==( const cow_wrapper<T,P>& a,
338  const cow_wrapper<T,P>& b )
339  {
340  return a.same_object(b) || *a == *b;
341  }
342 
343  template<class T, class P> inline bool operator!=( const cow_wrapper<T,P>& a,
344  const cow_wrapper<T,P>& b )
345  {
346  return !a.same_object(b) && *a != *b;
347  }
348 
349  template<class A, class B, class P> inline bool operator<( const cow_wrapper<A,P>& a,
350  const cow_wrapper<B,P>& b )
351  {
352  return *a < *b;
353  }
354 
355  template<class T, class P> inline void swap( cow_wrapper<T,P>& a,
356  cow_wrapper<T,P>& b )
357  {
358  a.swap(b);
359  }
360 
361 }
362 
363 #endif /* INCLUDED_O3TL_COW_WRAPPER_HXX */
364 
365 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
MTPolicy::ref_count_t use_count() const
return number of shared instances (1 for unique object)
Thread-safe refcounting.
Definition: cow_wrapper.hxx:49
oslInterlockedCount ref_count_t
Definition: cow_wrapper.hxx:51
static void incrementCount(ref_count_t &rCount)
Definition: cow_wrapper.hxx:52
cow_wrapper(const value_type &r)
Copy-construct wrapped type instance from given object.
bool operator!=(const cow_wrapper< T, P > &a, const cow_wrapper< T, P > &b)
shared value object - gets cloned before cow_wrapper hands out a non-const reference to it ...
void swap(cow_wrapper &r)
cow_wrapper()
Default-construct wrapped type instance.
static void incrementCount(ref_count_t &rCount)
Definition: cow_wrapper.hxx:40
void swap(cow_wrapper< T, P > &a, cow_wrapper< T, P > &b)
MTPolicy::ref_count_t m_ref_count
cow_wrapper(value_type &&r)
Move-construct wrapped type instance from given object.
bool same_object(const cow_wrapper &rOther) const
true, if both cow_wrapper internally share the same object
cow_wrapper & operator=(const cow_wrapper &rSrc)
now sharing rSrc cow_wrapper instance with us
bool operator==(const cow_wrapper< T, P > &a, const cow_wrapper< T, P > &b)
value_type & make_unique()
unshare with any other cow_wrapper instance
pointer operator->()
value_type & operator*()
cow_wrapper & operator=(cow_wrapper &&rSrc) noexcept
stealing rSrc's resource
float v
Thread-unsafe refcounting.
Definition: cow_wrapper.hxx:37
bool is_unique() const
true, if not shared with any other cow_wrapper instance
const_pointer operator->() const
impl_t & operator=(const impl_t &)=delete
cow_wrapper(cow_wrapper &&rSrc) noexcept
Move-construct and steal rSrc shared resource.
cow_wrapper(const cow_wrapper &rSrc)
Shallow-copy given cow_wrapper.
const T * const_pointer
static bool decrementCount(ref_count_t &rCount)
Definition: cow_wrapper.hxx:53
const value_type & operator*() const
static bool decrementCount(ref_count_t &rCount)
Definition: cow_wrapper.hxx:41