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 <utility>
26 #include <cstddef>
27 
28 namespace 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  if( rCount == 1 ) // caller is already the only/last reference
55  return false;
56  else
57  return osl_atomic_decrement(&rCount) != 0;
58  }
59  };
60 
174  template<typename T, class MTPolicy=UnsafeRefCountingPolicy> class cow_wrapper
175  {
179  struct impl_t
180  {
181  impl_t(const impl_t&) = delete;
182  impl_t& operator=(const impl_t&) = delete;
183 
184  impl_t() :
185  m_value(),
186  m_ref_count(1)
187  {
188  }
189 
190  explicit impl_t( const T& v ) :
191  m_value(v),
192  m_ref_count(1)
193  {
194  }
195 
196  explicit impl_t( T&& v ) :
197  m_value(std::move(v)),
198  m_ref_count(1)
199  {
200  }
201 
203  typename MTPolicy::ref_count_t m_ref_count;
204  };
205 
206  void release()
207  {
208  if( m_pimpl && !MTPolicy::decrementCount(m_pimpl->m_ref_count) )
209  {
210  delete m_pimpl;
211  m_pimpl = nullptr;
212  }
213  }
214 
215  public:
216  typedef T value_type;
217  typedef T* pointer;
218  typedef const T* const_pointer;
219  typedef MTPolicy mt_policy;
220 
224  m_pimpl( new impl_t() )
225  {
226  }
227 
230  explicit cow_wrapper( const value_type& r ) :
231  m_pimpl( new impl_t(r) )
232  {
233  }
234 
237  explicit cow_wrapper( value_type&& r ) :
238  m_pimpl( new impl_t(std::move(r)) )
239  {
240  }
241 
244  explicit cow_wrapper( const cow_wrapper& rSrc ) : // nothrow
245  m_pimpl( rSrc.m_pimpl )
246  {
247  MTPolicy::incrementCount( m_pimpl->m_ref_count );
248  }
249 
252  explicit cow_wrapper( cow_wrapper&& rSrc ) noexcept :
253  m_pimpl( rSrc.m_pimpl )
254  {
255  rSrc.m_pimpl = nullptr;
256  }
257 
258  ~cow_wrapper() // nothrow, if ~T does not throw
259  {
260  release();
261  }
262 
264  cow_wrapper& operator=( const cow_wrapper& rSrc ) // nothrow
265  {
266  // this already guards against self-assignment
267  MTPolicy::incrementCount( rSrc.m_pimpl->m_ref_count );
268 
269  release();
270  m_pimpl = rSrc.m_pimpl;
271 
272  return *this;
273  }
274 
277  {
278  // self-movement guts ourself, see also 17.6.4.9
279  release();
280  m_pimpl = rSrc.m_pimpl;
281 
282  rSrc.m_pimpl = nullptr;
283 
284  return *this;
285  }
286 
288  value_type& make_unique()
289  {
290  if( m_pimpl->m_ref_count > 1 )
291  {
292  impl_t* pimpl = new impl_t(m_pimpl->m_value);
293  release();
294  m_pimpl = pimpl;
295  }
296 
297  return m_pimpl->m_value;
298  }
299 
301  bool is_unique() const // nothrow
302  {
303  return !m_pimpl || m_pimpl->m_ref_count == 1;
304  }
305 
307  typename MTPolicy::ref_count_t use_count() const // nothrow
308  {
309  return m_pimpl ? m_pimpl->m_ref_count : 0;
310  }
311 
312  void swap(cow_wrapper& r) // never throws
313  {
315  }
316 
317  pointer operator->() { return &make_unique(); }
318  value_type& operator*() { return make_unique(); }
319  const_pointer operator->() const { return &m_pimpl->m_value; }
320  const value_type& operator*() const { return m_pimpl->m_value; }
321 
322  pointer get() { return &make_unique(); }
323  const_pointer get() const { return &m_pimpl->m_value; }
324 
326  bool same_object( const cow_wrapper& rOther ) const
327  {
328  return rOther.m_pimpl == m_pimpl;
329  }
330 
331  private:
332  impl_t* m_pimpl;
333  };
334 
335 
336  template<class T, class P> inline bool operator==( const cow_wrapper<T,P>& a,
337  const cow_wrapper<T,P>& b )
338  {
339  return a.same_object(b) || *a == *b;
340  }
341 
342  template<class T, class P> inline bool operator!=( const cow_wrapper<T,P>& a,
343  const cow_wrapper<T,P>& b )
344  {
345  return !a.same_object(b) && *a != *b;
346  }
347 
348  template<class A, class B, class P> inline bool operator<( const cow_wrapper<A,P>& a,
349  const cow_wrapper<B,P>& b )
350  {
351  return *a < *b;
352  }
353 
354  template<class T, class P> inline void swap( cow_wrapper<T,P>& a,
355  cow_wrapper<T,P>& b )
356  {
357  a.swap(b);
358  }
359 
360 }
361 
362 #endif /* INCLUDED_O3TL_COW_WRAPPER_HXX */
363 
364 /* 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:48
oslInterlockedCount ref_count_t
Definition: cow_wrapper.hxx:50
static void incrementCount(ref_count_t &rCount)
Definition: cow_wrapper.hxx:51
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:39
void swap(cow_wrapper< T, P > &a, cow_wrapper< T, P > &b)
uno_Any a
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:36
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:52
const value_type & operator*() const
static bool decrementCount(ref_count_t &rCount)
Definition: cow_wrapper.hxx:40