stlab.adobe.com Adobe Systems Incorporated
copy_on_write.hpp
Go to the documentation of this file.
1 /*
2  Copyright 2005-2007 Adobe Systems Incorporated
3  Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
4  or a copy at http://stlab.adobe.com/licenses.html)
5 */
6 
7 /**************************************************************************************************/
8 
9 #ifndef ADOBE_COPY_ON_WRITE_HPP
10 #define ADOBE_COPY_ON_WRITE_HPP
11 
12 /**************************************************************************************************/
13 
14 #include <adobe/config.hpp>
15 
16 #include <algorithm>
17 #include <cassert>
18 #include <cstdlib>
19 
20 #include <boost/noncopyable.hpp>
21 #include <boost/operators.hpp>
22 #include <boost/static_assert.hpp>
23 
24 #include <adobe/counter.hpp>
25 #include <adobe/memory.hpp>
26 #include <adobe/move.hpp>
27 #include <adobe/once.hpp>
28 #include <adobe/typeinfo.hpp>
29 
30 /**************************************************************************************************/
31 
32 namespace adobe {
33 
34 /**************************************************************************************************/
35 
36 namespace version_1 {
37 
38 /**************************************************************************************************/
39 
69 template <typename T, // T models Regular
70  typename A = adobe::capture_allocator<T> > // A models Allocator
72 {
73 public:
75  typedef T value_type;
77  typedef A allocator_type;
78 
79 #if !defined(ADOBE_NO_DOCUMENTATION)
80 private:
81  struct implementation_t;
82  typedef typename allocator_type::template rebind<implementation_t>::other implementation_allocator_type;
83 public:
84 #endif
85 
92  {
93  adobe::call_once(init_default, flag_s);
94  object_m = default_s;
95  object_m->header_m.get().count_m.increment();
96  }
97 
101  explicit copy_on_write(const allocator_type& a) :
102  object_m(0)
103  {
104  implementation_allocator_type other_allocator(a);
105 
106  object_m = allocate(other_allocator);
107  }
108 
117  object_m(allocate_move(0, adobe::move(x)))
118  { }
119 
125  object_m(x.object_m)
126  {
127  if (object_m)
128  object_m->header_m.get().count_m.increment();
129  }
130 
132  object_m(x.source.object_m)
133  {
134  x.source.object_m = 0;
135  }
136 
138  {
139  release(object_m);
140  }
141 
148  { swap(*this, x); return *this; }
149 
150 
152  {
153  if (!object_m)
154  object_m = allocate_move(0, adobe::move(x));
155  else if (object_m->header_m.get().count_m.is_one())
156  object_m->value_m = adobe::move(x);
157  else
158  reset(allocate_move(object_m, adobe::move(x)));
159 
160  return *this;
161  }
162 
175  value_type& write()
176  {
177  assert(object_m && "FATAL (sparent) : using a moved copy_on_write object");
178 
179  if (!object_m->header_m.get().count_m.is_one())
180  reset(allocate(object_m, object_m->value_m));
181 
182  return object_m->value_m;
183  }
184 
190  const value_type& read() const
191  {
192  assert(object_m && "FATAL (sparent) : using a moved copy_on_write object");
193  return object_m->value_m;
194  }
195 
201  operator const value_type& () const
202  { return read(); }
203 
214  const value_type& operator*() const
215  { return read(); }
216 
227  const value_type* operator->() const
228  { return &read(); }
229 
237  bool unique_instance() const
238  { return !object_m || object_m->header_m.get().count_m.is_one(); }
239 
247  bool identity(const copy_on_write& x) const
248  { return object_m == x.object_m; }
249 
250  friend inline void swap(copy_on_write& x, copy_on_write& y)
251  { std::swap(x.object_m, y.object_m); }
252 
253  friend inline bool operator<(const copy_on_write& x, const copy_on_write& y)
254  { return y.object_m && (!x.object_m || (!x.identity(y) && *x < *y)); }
255 
256  friend inline bool operator>(const copy_on_write& x, const copy_on_write& y)
257  { return y < x; }
258 
259  friend inline bool operator<=(const copy_on_write& x, const copy_on_write& y)
260  { return !(y < x); }
261 
262  friend inline bool operator>=(const copy_on_write& x, const copy_on_write& y)
263  { return !(x < y); }
264 
265  friend inline bool operator==(const copy_on_write& x, const copy_on_write& y)
266  { return x.identity(y) || (x.object_m && y.object_m && *x == *y); }
267 
268  friend inline bool operator!=(const copy_on_write& x, const copy_on_write& y)
269  { return !(x == y); }
270 
271  allocator_type get_allocator() const
272  { return object_m ? allocator_type(object_m->get_allocator()) : allocator_type(); }
273 
274 private:
275 #if !defined(ADOBE_NO_DOCUMENTATION)
276  static implementation_t* allocate(const implementation_t* alloc_src, const T& x = T())
277  {
278  implementation_allocator_type allocator(alloc_src ?
279  alloc_src->get_allocator() :
280  implementation_allocator_type());
281 
282  return allocate(allocator, x);
283  }
284 
285  static implementation_t* allocate(implementation_allocator_type& allocator, const T& x = T())
286  {
287  implementation_t* tmp(allocator.allocate(1));
288 
289  try {
290  ::new(static_cast<void*>(tmp)) implementation_t(x);
291  } catch (...) {
292  tmp->get_allocator().deallocate(tmp, 1);
293  throw;
294  }
295 
296  return tmp;
297  }
298 
299  static implementation_t* allocate_move(const implementation_t* alloc_src, T x)
300  {
301  implementation_allocator_type allocator(alloc_src ?
302  alloc_src->get_allocator() :
303  implementation_allocator_type());
304  implementation_t* tmp(allocator.allocate(1));
305 
306  try {
307  ::new(static_cast<void*>(tmp)) implementation_t(adobe::move(x));
308  } catch (...) {
309  tmp->get_allocator().deallocate(tmp, 1);
310  throw;
311  }
312 
313  return tmp;
314  }
315 
316  static void release(implementation_t* x)
317  {
318  /*
319  I thought about returning a bool from this routine (denoting whether
320  or not a deallocation took place) but decided not to in the end.
321  Release's semantics are that of giving up ownership of the
322  implementation instance, so you are not allowed to subsequently
323  interact with the implementation instance you've released. Thus,
324  notifying the caller of a deallocation is a moot point.
325  */
326 
327  if (x == 0 || x->header_m.get().count_m.decrement() == false)
328  return;
329 
330  implementation_allocator_type allocator(x->get_allocator());
331 
332  destroy(x);
333 
334  allocator.deallocate(x, 1);
335  }
336 
337  void reset(implementation_t* to)
338  {
339  release(object_m);
340  object_m = to;
341  }
342 
343  implementation_t* object_m;
344 
345  static once_flag flag_s;
346  static implementation_t* default_s;
347 
348  static void release_default();
349  static void init_default();
350 #endif
351 };
352 
353 /**************************************************************************************************/
354 
355 #if !defined(ADOBE_NO_DOCUMENTATION)
356 
357 /**************************************************************************************************/
358 
359 template <typename T, typename A>
361 
362 template <typename T, typename A>
364 
365 template <typename T, typename A>
366 struct copy_on_write<T, A>::implementation_t : private boost::noncopyable
367 {
368  // Assert proper size for counter_t
369  BOOST_STATIC_ASSERT((sizeof(counter_t) == sizeof(std::size_t)));
370  // Assert proper alignment for counter_t
371  BOOST_STATIC_ASSERT((sizeof(counter_t) == sizeof(void*)));
372 
373  struct header_t
374  {
375  counter_t count_m;
376  allocator_type allocator_m;
377  };
378 
379  explicit implementation_t(T x) :
380  value_m(adobe::move(x))
381  { }
382 
383  implementation_allocator_type get_allocator() const
384  { return implementation_allocator_type(header_m.get().allocator_m); }
385 
386  aligned_storage<header_t> header_m;
387  value_type value_m;
388 };
389 
390 template <typename T, typename A>
392 {
393  implementation_allocator_type allocator;
394 
395  default_s = allocate(allocator);
396 
397  std::atexit(release_default); // ignore failure
398 }
399 
400 template <typename T, typename A>
402 {
403  release(default_s);
404 }
405 
406 #endif
407 
408 /**************************************************************************************************/
409 
410 } // namespace version_1
411 
412 /**************************************************************************************************/
413 
415 
416 /**************************************************************************************************/
417 
418 template <typename T, typename A> struct is_movable<copy_on_write<T, A> > : boost::mpl::true_ { };
419 
420 /**************************************************************************************************/
421 
422 } // namespace adobe
423 
424 /**************************************************************************************************/
425 
427 ADOBE_NAME_TYPE_2("copy_on_write:version_1:adobe", adobe::version_1::copy_on_write<T0, T1>)
428 
429 /**************************************************************************************************/
430 
431 #endif
432 
433 /**************************************************************************************************/
bool once_flag
Definition: once.hpp:44
const value_type & operator*() const
Obtain a const reference to the underlying object.
friend void swap(copy_on_write &x, copy_on_write &y)
copy_on_write(const allocator_type &a)
BOOST_STATIC_ASSERT(sizeof(string_t)==sizeof(vector< char >))
copy_on_write & operator=(T x)
A allocator_type
The type of allocator.
move_from is used for move_ctors.
Definition: move.hpp:306
void swap(adobe::lex_stream_t &, adobe::lex_stream_t &)
Definition: lex_stream.hpp:68
T value_type
The type of value stored.
void destroy(T *p)
Definition: memory.hpp:626
bool identity(const copy_on_write &x) const
identity is used to see if two copy_on_write items refer to the same instance.
copy_on_write(const copy_on_write &x)
friend bool operator>=(const copy_on_write &x, const copy_on_write &y)
friend bool operator!=(const copy_on_write &x, const copy_on_write &y)
bool unique_instance() const
unique_instance returns whether or not the reference count to the object instance is one...
friend bool operator>(const copy_on_write &x, const copy_on_write &y)
copy_on_write(move_from< copy_on_write > x)
#define ADOBE_ONCE_INIT
Definition: once.hpp:45
The is_movable trait can be used to identify movable types.
Definition: move.hpp:317
void call_once(void(*func)(), adobe::once_flag &flag)
Definition: once.hpp:47
A thread safe counter.
Definition: counter.hpp:74
copy_on_write & operator=(copy_on_write x)
const value_type & read() const
Obtain a const reference to the underlying object.
const value_type * operator->() const
Obtain a const pointer to the underlying object.
ADOBE_NAME_TYPE_2("closed_hash_map:version_1:adobe", adobe::version_1::closed_hash_map< T0, T1, boost::hash< T0 >, std::equal_to< T0 >, adobe::capture_allocator< adobe::pair< T0, T1 > > >)
copy_on_write(T x)
Constructs a new copy_on_write object with a value x.
A copy-on-write wrapper for any model of Regular.
friend bool operator<(const copy_on_write &x, const copy_on_write &y)
allocator_type get_allocator() const
friend bool operator==(const copy_on_write &x, const copy_on_write &y)
friend bool operator<=(const copy_on_write &x, const copy_on_write &y)

Copyright © 2006-2007 Adobe Systems Incorporated.

Use of this website signifies your agreement to the Terms of Use and Online Privacy Policy.

Search powered by Google