memory.hpp
Go to the documentation of this file.
00001 /* 00002 Copyright 2005-2007 Adobe Systems Incorporated 00003 Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt 00004 or a copy at http://stlab.adobe.com/licenses.html) 00005 */ 00006 00007 /*************************************************************************************************/ 00008 00009 #ifndef ADOBE_MEMORY_HPP 00010 #define ADOBE_MEMORY_HPP 00011 00012 #include <adobe/config.hpp> 00013 00014 #include <cassert> 00015 #include <functional> 00016 #include <memory> 00017 00018 #include <boost/utility/enable_if.hpp> 00019 #include <boost/type_traits/is_const.hpp> 00020 00021 #include <adobe/conversion.hpp> 00022 #include <adobe/functional.hpp> 00023 #include <adobe/memory_fwd.hpp> 00024 #include <adobe/move.hpp> 00025 00026 /*************************************************************************************************/ 00027 00028 namespace adobe { 00029 00030 /*************************************************************************************************/ 00031 00041 template <typename T> 00042 struct empty_ptr; 00043 00044 template <typename T> 00045 struct empty_ptr<T*> : std::unary_function<T*, bool> 00046 { 00047 bool operator () (const T* x) const throw() 00048 { return x == NULL; } 00049 }; 00050 00051 00052 template <typename T> 00053 struct empty_ptr<T(*)[]> : std::unary_function<T*, bool> 00054 { 00055 bool operator () (const T* x) const throw() 00056 { return x == NULL; } 00057 }; 00058 00059 /* 00060 REVISIT (sparent) : This is a hack - the new delete_ptr is not a template 00061 auto_ptr/auto_resource are too complicated with the traits classes - 00062 provide a delete op as a tempalte argument? 00063 */ 00064 00065 template <typename T> 00066 struct delete_ptr_trait; 00067 00068 template <typename T> 00069 struct delete_ptr_trait<T*> : std::unary_function<T*, void> 00070 { void operator()(const T* x) const { delete x; } }; 00071 00072 template <typename T> 00073 struct delete_ptr_trait<T(*)[]> : std::unary_function<T*, void> 00074 { void operator()(const T* x) const { delete [] x; } }; 00075 00077 00078 /*************************************************************************************************/ 00079 00080 template<typename X, class Traits> class auto_ptr; 00081 template<typename X, class Traits> class auto_resource; 00082 00083 template <typename ptrT> 00084 struct ptr_traits; 00085 00087 template <typename T> 00088 struct ptr_traits<T(*)[]> 00089 { 00090 typedef T element_type; 00091 typedef T* pointer_type; 00092 typedef const T* const_pointer_type; 00093 00094 template <class U> struct rebind { typedef adobe::ptr_traits<U> other; }; 00095 enum { is_array = true }; 00096 00097 static void delete_ptr(pointer_type x) throw() { delete_ptr_trait<T(*)[]>()(x); } 00098 static bool empty_ptr(const_pointer_type x) throw() { return adobe::empty_ptr<T(*)[]>()(x); } 00099 }; 00100 00162 template <typename T> 00163 struct ptr_traits<T*> 00164 { 00165 typedef T element_type; 00166 typedef T* pointer_type; 00167 typedef const pointer_type const_pointer_type; 00168 00169 template <class U> struct rebind { typedef adobe::ptr_traits<U> other; }; 00170 enum { is_array = false }; 00171 00172 static void delete_ptr(pointer_type x) throw() { adobe::delete_ptr_trait<T*>()(x); } 00173 static bool empty_ptr(const_pointer_type x) throw() { return adobe::empty_ptr<T*>()(x); } 00174 }; 00175 00177 template <typename T> 00178 struct ptr_traits<std::auto_ptr<T> > 00179 { 00180 typedef typename std::auto_ptr<T>::element_type element_type; 00181 typedef std::auto_ptr<T> pointer_type; 00182 typedef std::auto_ptr<const T> const_pointer_type; 00183 00184 template <class U> struct rebind { typedef adobe::ptr_traits<U> other; }; 00185 enum { is_array = false }; 00186 }; 00187 00189 template <typename R, typename T> 00190 struct runtime_cast_t<R, std::auto_ptr<T> > { 00191 R operator()(std::auto_ptr<T>& x) const 00192 { 00193 typedef typename R::element_type* dest_type; 00194 dest_type result = dynamic_cast<dest_type>(x.get()); 00195 if (result) x.release(); 00196 return R(result); 00197 } 00198 }; 00199 00201 template <typename T, class Traits> 00202 struct ptr_traits<auto_ptr<T, Traits> > 00203 { 00204 typedef typename auto_ptr<T, Traits>::element_type element_type; 00205 typedef auto_ptr<T, Traits> pointer_type; 00206 typedef auto_ptr<const T, Traits> const_pointer_type; 00207 00208 enum { is_array = Traits::is_array }; 00209 }; 00210 00212 template <typename R, typename T, typename Traits> 00213 struct runtime_cast_t<R, auto_ptr<T, Traits> > { 00214 R operator()(auto_ptr<T, Traits>& x) const 00215 { 00216 typedef typename R::element_type* dest_type; 00217 dest_type result = dynamic_cast<dest_type>(x.get()); 00218 if (result) x.release(); 00219 return R(result); 00220 } 00221 }; 00222 00224 template <typename T, class Traits> 00225 struct ptr_traits<auto_resource<T, Traits> > 00226 { 00227 typedef typename Traits::element_type element_type; 00228 typedef auto_resource<T, Traits> pointer_type; 00229 typedef auto_resource<const T, Traits> const_pointer_type; 00230 00231 enum { is_array = Traits::is_array }; 00232 }; 00233 00235 template <typename R, typename T, typename Traits> 00236 struct runtime_cast_t<R, auto_resource<T, Traits> > { 00237 R operator()(auto_resource<T, Traits>& x) const 00238 { 00239 typedef typename R::element_type* dest_type; 00240 dest_type result = dynamic_cast<dest_type>(x.get()); 00241 if (result) x.release(); 00242 return R(result); 00243 } 00244 }; 00245 00246 00247 /*************************************************************************************************/ 00248 00249 #ifndef NO_DOCUMENTATION 00250 00251 /* 00252 REVISIT (sparent) : This could use boost::static_assert but it doesn't seem worth adding a 00253 boost dependency just for this case. 00254 */ 00255 00256 namespace implementation { 00257 template <bool x> struct adobe_static_assert; 00258 template <> struct adobe_static_assert<true> { }; 00259 } 00260 00261 #endif 00262 00263 /*************************************************************************************************/ 00264 00281 template <typename X, class Traits = ptr_traits<X> > 00282 class auto_resource 00283 { 00284 struct clear_type { }; 00285 operator int() const; 00286 00287 public: 00288 typedef Traits traits_type; 00289 typedef typename traits_type::element_type element_type; 00290 typedef typename traits_type::pointer_type pointer_type; 00291 00292 // 20.4.5.1 construct/copy/destroy: 00293 explicit auto_resource(pointer_type p = 0) throw(); 00294 00295 auto_resource(auto_resource&) throw(); 00296 template <typename Y> auto_resource(const auto_resource<Y, typename traits_type::template rebind<Y>::other>&) throw(); 00297 00298 auto_resource& operator=(auto_resource&) throw(); 00299 template<typename Y> auto_resource& operator=(auto_resource<Y, typename traits_type::template rebind<Y>::other>) throw(); 00300 00301 ~auto_resource() throw(); 00302 00303 // assignment from NULL 00304 auto_resource& operator=(const clear_type*) throw(); 00305 00306 // 20.4.5.2 members: 00307 pointer_type get() const throw(); 00308 pointer_type release() throw(); 00309 void reset(pointer_type p = 0) throw(); 00310 00311 // Safe bool conversion (private int conversion prevents unsafe use) 00312 operator bool () const throw() { return (pointer_m != NULL); } 00313 bool operator!() const throw(); 00314 00315 private: 00316 /* 00317 20.4.5.3 conversions: 00318 00319 NOTE (spraent) : As per the recommendations on standard issue 463 the conversion 00320 operators through auto_ptr_ref have been removed in favor of using this conditional 00321 enabled trick. 00322 00323 http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#463 00324 */ 00325 // VC 2003 internal compiler error workaround. Some misues of auto_resource will go undetected under MSVC until fixed. 00326 #ifndef BOOST_MSVC 00327 template <typename Y> struct error_on_const_auto_type; 00328 template <typename Y> struct error_on_const_auto_type<auto_resource<Y, typename traits_type::template rebind<Y>::other> const> 00329 { typedef typename auto_resource<Y, typename traits_type::template rebind<Y>::other>::const_auto_type_is_not_allowed type; }; 00330 00331 template <class Y> 00332 auto_resource(Y& rhs, typename error_on_const_auto_type<Y>::type = 0); 00333 #endif 00334 pointer_type pointer_m; 00335 }; 00336 00337 /*************************************************************************************************/ 00338 00397 template<typename X, class Traits = ptr_traits<X*> > 00398 class auto_ptr : public auto_resource<X*, Traits> 00399 { 00400 typedef auto_resource<X*, Traits> inherited; 00401 struct clear_type { }; 00402 00403 public: 00404 typedef Traits traits_type; 00405 typedef typename traits_type::element_type element_type; 00406 typedef typename traits_type::pointer_type pointer_type; 00407 // 20.4.5.1 construct/copy/destroy: 00408 explicit auto_ptr(pointer_type p = 0) throw(); 00409 00410 auto_ptr(auto_ptr&) throw(); 00411 template <typename Y> auto_ptr(const auto_ptr<Y, typename traits_type::template rebind<Y*>::other>&) throw(); 00412 00413 auto_ptr& operator=(auto_ptr&) throw(); 00414 template<typename Y> auto_ptr& operator=(auto_ptr<Y, typename traits_type::template rebind<Y*>::other>) throw(); 00415 00416 // assignment from NULL 00417 auto_ptr& operator=(const clear_type*) throw(); 00418 00419 // additions for interop with std::auto_ptr 00420 auto_ptr(std::auto_ptr<X> r) throw(); 00421 template <typename Y> auto_ptr(std::auto_ptr<Y> r) throw(); 00422 00423 auto_ptr& operator=(std::auto_ptr<X>) throw(); 00424 template<typename Y> auto_ptr& operator=(std::auto_ptr<Y>) throw(); 00425 00426 operator std::auto_ptr<X> () throw() { return std::auto_ptr<X>(inherited::release()); } 00427 00428 // 20.4.5.2 members: 00429 element_type& operator * () const throw(); 00430 pointer_type operator -> () const throw(); 00431 element_type& operator [] (std::size_t index) const throw(); // addition 00432 00433 private: 00434 template <typename Y> struct error_on_const_auto_type; 00435 template <typename Y> struct error_on_const_auto_type<auto_ptr<Y, typename traits_type::template rebind<Y*>::other> const> 00436 { typedef typename auto_ptr<Y, typename traits_type::template rebind<Y*>::other>::const_auto_type_is_not_allowed type; }; 00437 00438 template <class U> 00439 auto_ptr(U& rhs, typename error_on_const_auto_type<U>::type = 0); 00440 }; 00441 00443 00444 /*************************************************************************************************/ 00445 00446 template <typename X, class Traits> 00447 inline auto_resource<X, Traits>::auto_resource(pointer_type p) throw() : 00448 pointer_m(p) 00449 { } 00450 00451 template <typename X, class Traits> 00452 inline auto_resource<X, Traits>::auto_resource(auto_resource& x) throw() : 00453 pointer_m(x.release()) 00454 { } 00455 00456 template <typename X, class Traits> 00457 template <typename Y> 00458 inline auto_resource <X, Traits>::auto_resource(auto_resource<Y, typename traits_type::template rebind<Y>::other> const& x) throw() : 00459 pointer_m(const_cast<auto_resource<Y, typename traits_type::template rebind<Y>::other>&>(x).release()) 00460 { } 00461 00462 template <typename X, class Traits> 00463 inline auto_resource<X, Traits>& auto_resource<X, Traits>::operator=(auto_resource& x) throw() 00464 { 00465 reset(x.release()); 00466 return *this; 00467 } 00468 00469 template <typename X, class Traits> 00470 template <typename Y> 00471 inline auto_resource<X, Traits>& auto_resource<X, Traits>::operator=( 00472 auto_resource<Y, typename traits_type::template rebind<Y>::other> x) throw() 00473 { 00474 reset(x.release()); 00475 return *this; 00476 } 00477 00478 template <typename X, class Traits> 00479 inline auto_resource<X, Traits>::~auto_resource() throw() 00480 { traits_type::delete_ptr(pointer_m); } 00481 00482 /*************************************************************************************************/ 00483 00484 template <typename X, class Traits> 00485 inline auto_resource<X, Traits>& auto_resource<X, Traits>::operator=(const clear_type*) throw() 00486 { 00487 reset(); 00488 return *this; 00489 } 00490 00491 /*************************************************************************************************/ 00492 00493 template <typename X, class Traits> 00494 inline typename auto_resource<X, Traits>::pointer_type auto_resource<X, Traits>::get() const throw() 00495 { 00496 return pointer_m; 00497 } 00498 00499 template <typename X, class Traits> 00500 inline typename auto_resource<X, Traits>::pointer_type auto_resource<X, Traits>::release() throw() 00501 { 00502 pointer_type result(pointer_m); 00503 pointer_m = NULL; 00504 return result; 00505 } 00506 00507 template <typename X, class Traits> 00508 inline void auto_resource<X, Traits>::reset(pointer_type p) throw() 00509 { 00510 if (pointer_m != p) 00511 { 00512 traits_type::delete_ptr(pointer_m); 00513 pointer_m = p; 00514 } 00515 } 00516 00517 /*************************************************************************************************/ 00518 00519 template <typename X, class Traits> 00520 inline bool auto_resource<X, Traits>::operator!() const throw() 00521 { 00522 return !pointer_m; 00523 } 00524 00525 /*************************************************************************************************/ 00526 00527 00528 template <typename X, class Traits> 00529 inline auto_ptr<X, Traits>::auto_ptr(pointer_type p) throw() : 00530 inherited(p) 00531 { } 00532 00533 template <typename X, class Traits> 00534 inline auto_ptr<X, Traits>::auto_ptr(auto_ptr& r) throw() : 00535 inherited(r) 00536 { } 00537 00538 template <typename X, class Traits> 00539 template <typename Y> 00540 inline auto_ptr<X, Traits>::auto_ptr(const auto_ptr<Y, typename traits_type::template rebind<Y*>::other>& r) throw() : 00541 inherited(const_cast<auto_ptr<Y, typename traits_type::template rebind<Y*>::other>&>(r)) 00542 { } 00543 00544 template <typename X, class Traits> 00545 inline auto_ptr<X, Traits>& auto_ptr<X, Traits>::operator=(auto_ptr& r) throw() 00546 { 00547 inherited::operator=(r); 00548 return *this; 00549 } 00550 00551 template <typename X, class Traits> 00552 template<typename Y> 00553 inline auto_ptr<X, Traits>& auto_ptr<X, Traits>::operator=( 00554 auto_ptr<Y, typename traits_type::template rebind<Y*>::other> r) throw() 00555 { 00556 inherited::operator=(r); 00557 return *this; 00558 } 00559 00560 /*************************************************************************************************/ 00561 00562 template <typename X, class Traits> 00563 inline auto_ptr<X, Traits>& auto_ptr<X, Traits>::operator=(const clear_type*) throw() 00564 { 00565 inherited::reset(); 00566 return *this; 00567 } 00568 00569 /*************************************************************************************************/ 00570 00571 template <typename X, class Traits> 00572 inline auto_ptr<X, Traits>::auto_ptr(std::auto_ptr<X> r) throw() : 00573 inherited(r.release()) 00574 { } 00575 00576 template <typename X, class Traits> 00577 template <typename Y> 00578 inline auto_ptr<X, Traits>::auto_ptr(std::auto_ptr<Y> r) throw() : 00579 inherited(r.release()) 00580 { } 00581 00582 template <typename X, class Traits> 00583 inline auto_ptr<X, Traits>& auto_ptr<X, Traits>::operator=(std::auto_ptr<X> r) throw() 00584 { 00585 inherited::reset(r.release()); 00586 return *this; 00587 } 00588 00589 template <typename X, class Traits> 00590 template<typename Y> 00591 inline auto_ptr<X, Traits>& auto_ptr<X, Traits>::operator=( 00592 std::auto_ptr<Y> r) throw() 00593 { 00594 inherited::reset(r.release()); 00595 return *this; 00596 } 00597 00598 /*************************************************************************************************/ 00599 00600 template <typename X, class Traits> 00601 inline typename auto_ptr<X, Traits>::element_type& auto_ptr<X, Traits>::operator * () const throw() 00602 { 00603 assert(!traits_type::empty_ptr(this->get())); 00604 return *this->get(); 00605 } 00606 00607 template <typename X, class Traits> 00608 inline typename auto_ptr<X, Traits>::pointer_type auto_ptr<X, Traits>::operator -> () const throw() 00609 { 00610 assert(!traits_type::empty_ptr(this->get())); 00611 return this->get(); 00612 } 00613 00614 template <typename X, class Traits> 00615 inline typename auto_ptr<X, Traits>::element_type& auto_ptr<X, Traits>::operator [] (std::size_t index) const throw() 00616 { 00617 implementation::adobe_static_assert<traits_type::is_array>(); 00618 00619 assert(!traits_type::empty_ptr(this->get())); 00620 return *(this->get() + index); 00621 } 00622 00623 /*************************************************************************************************/ 00624 00625 template <typename T> // T models Regular 00626 inline void destroy(T* p) { p->~T(); } 00627 00628 template <typename T> // T models Regular 00629 inline void construct(T* p) { ::new(static_cast<void*>(p)) T(); } 00630 00631 template <typename T> // T models Regular 00632 inline void construct(T* p, T x) { ::new(static_cast<void*>(p)) T(adobe::move(x)); } 00633 00634 template <typename F> // F models ForwardIterator 00635 inline void destroy(F f, F l) 00636 { 00637 while (f != l) { 00638 destroy(&*f); 00639 ++f; 00640 } 00641 } 00642 00643 /*************************************************************************************************/ 00644 00648 template <typename I, // I models InputIterator 00649 typename F> // F models ForwardIterator 00650 F uninitialized_move(I f, I l, F r) 00651 { 00652 while (f != l) { 00653 construct(&*r, adobe::move(*f)); 00654 ++f; ++r; 00655 } 00656 return r; 00657 } 00658 00659 /*************************************************************************************************/ 00660 00661 namespace version_1 { 00662 00665 00666 struct new_delete_t 00667 { 00668 void* (*new_)(std::size_t); 00669 void (*delete_)(void*); 00670 }; 00671 00672 extern const new_delete_t local_new_delete_g; 00673 00674 template < > 00675 class capture_allocator<void> 00676 { 00677 public: 00678 void* pointer; 00679 typedef const void* const_pointer; 00680 typedef void value_type; 00681 template <class U> struct rebind { typedef capture_allocator<U> other; }; 00682 00683 friend inline bool operator==(const capture_allocator&, const capture_allocator&) 00684 { return true; } 00685 00686 friend inline bool operator!=(const capture_allocator&, const capture_allocator&) 00687 { return false; } 00688 }; 00689 00690 template <typename T> 00691 class capture_allocator 00692 { 00693 public: 00694 typedef std::size_t size_type; 00695 typedef std::ptrdiff_t difference_type; 00696 typedef T* pointer; 00697 typedef const T* const_pointer; 00698 typedef T& reference; 00699 typedef const T& const_reference; 00700 typedef T value_type; 00701 template <typename U> struct rebind { typedef capture_allocator<U> other; }; 00702 00703 capture_allocator() : new_delete_m(&local_new_delete_g) { } 00704 template <typename U> 00705 capture_allocator(const capture_allocator<U>& x) : new_delete_m(x.new_delete()) { } 00706 00707 pointer address(reference x) const { return &x; } 00708 const_pointer address(const_reference x) const { return &x; } 00709 pointer allocate(size_type n, capture_allocator<void>::const_pointer = 0) 00710 { 00711 if (n > max_size()) throw std::bad_alloc(); 00712 pointer result = static_cast<pointer>(new_delete_m->new_(n * sizeof(T))); 00713 if (!result) throw std::bad_alloc(); 00714 return result; 00715 } 00716 void deallocate(pointer p, size_type) 00717 { 00718 new_delete_m->delete_(p); 00719 } 00720 size_type max_size() const { return size_type(-1) / sizeof(T); } 00721 void construct(pointer p, const T& x) { adobe::construct(p, x); } 00722 void destroy(pointer p) { adobe::destroy(p); } 00723 00724 friend inline bool operator==(const capture_allocator& x, const capture_allocator& y) 00725 { return x.new_delete_m == y.new_delete_m; } 00726 00727 friend inline bool operator!=(const capture_allocator& x, const capture_allocator& y) 00728 { return x.new_delete_m != y.new_delete_m; } 00729 00730 const new_delete_t* new_delete() const { return new_delete_m; } 00731 00732 private: 00733 const new_delete_t* new_delete_m; 00734 }; 00735 00737 /*************************************************************************************************/ 00738 00739 } // namespace version_1 00740 00741 /*************************************************************************************************/ 00742 00743 /* 00744 Note (sparent) : The aligned storage class is intended to pad out an item of size_t such that 00745 anything following it is aligned to the max alignement on the machine - in this case, quadword. 00746 */ 00747 00750 template <typename T> 00751 struct aligned_storage 00752 { 00753 aligned_storage() { construct(&get()); } 00754 00755 explicit aligned_storage(T x) 00756 { construct(&get(), adobe::move(x)); } 00757 00758 ~aligned_storage() { destroy(&get()); } 00759 00760 aligned_storage(const aligned_storage& x) { construct(&get(), x.get()); } 00761 aligned_storage(move_from<aligned_storage> x) { construct(&get(), adobe::move(x.source.get())); } 00762 00763 aligned_storage& operator=(aligned_storage x) { swap(*this, x); return *this; } 00764 00765 T& get() { return *static_cast<T*>(storage()); } 00766 const T& get() const { return *static_cast<const T*>(storage()); } 00767 00768 friend inline void swap(aligned_storage& x, aligned_storage& y) 00769 { swap(x.get(), y.get()); } 00770 00771 private: 00772 enum { word_size = 16 }; // quad word alignment 00773 00774 typedef double storage_t[((sizeof(T) + (word_size - 1)) / word_size) * (word_size / sizeof(double))]; 00775 00776 void* storage() { return &data_m; } 00777 const void* storage() const { return &data_m; } 00778 storage_t data_m; 00779 00780 BOOST_STATIC_ASSERT(sizeof(T) <= sizeof(storage_t)); 00781 }; 00782 00784 00785 /*************************************************************************************************/ 00786 00787 } // namespace adobe 00788 00789 ADOBE_NAME_TYPE_1("capture_allocator:version_1:adobe", adobe::version_1::capture_allocator<T0>) 00790 00791 /*************************************************************************************************/ 00792 00793 #endif 00794 00795 /*************************************************************************************************/ |