1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // (C) Copyright Ion Gaztanaga 2012-2013. Distributed under the Boost
4 // Software License, Version 1.0. (See accompanying file
5 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // See http://www.boost.org/libs/container for documentation.
8 //
9 //////////////////////////////////////////////////////////////////////////////
10 
11 #ifndef BOOST_CONTAINER_DETAIL_ALLOCATOR_VERSION_TRAITS_HPP
12 #define BOOST_CONTAINER_DETAIL_ALLOCATOR_VERSION_TRAITS_HPP
13 
14 #ifndef BOOST_CONFIG_HPP
15 #  include <boost/config.hpp>
16 #endif
17 
18 #if defined(BOOST_HAS_PRAGMA_ONCE)
19 #  pragma once
20 #endif
21 
22 #include <boost/container/detail/config_begin.hpp>
23 #include <boost/container/detail/workaround.hpp>
24 
25 #include <boost/container/allocator_traits.hpp>             //allocator_traits
26 #include <boost/container/throw_exception.hpp>
27 #include <boost/container/detail/multiallocation_chain.hpp> //multiallocation_chain
28 #include <boost/container/detail/version_type.hpp>          //version_type
29 #include <boost/container/detail/allocation_type.hpp>       //allocation_type
30 #include <boost/container/detail/mpl.hpp>                   //integral_constant
31 #include <boost/intrusive/pointer_traits.hpp>               //pointer_traits
32 #include <boost/core/no_exceptions_support.hpp>             //BOOST_TRY
33 
34 namespace boost {
35 namespace container {
36 namespace container_detail {
37 
38 template<class Allocator, unsigned Version = boost::container::container_detail::version<Allocator>::value>
39 struct allocator_version_traits
40 {
41    typedef ::boost::container::container_detail::integral_constant
42       <unsigned, Version> alloc_version;
43 
44    typedef typename Allocator::multiallocation_chain multiallocation_chain;
45 
46    typedef typename boost::container::allocator_traits<Allocator>::pointer    pointer;
47    typedef typename boost::container::allocator_traits<Allocator>::size_type  size_type;
48 
49    //Node allocation interface
allocate_oneboost::container::container_detail::allocator_version_traits50    static pointer allocate_one(Allocator &a)
51    {  return a.allocate_one();   }
52 
deallocate_oneboost::container::container_detail::allocator_version_traits53    static void deallocate_one(Allocator &a, const pointer &p)
54    {  a.deallocate_one(p);   }
55 
allocate_individualboost::container::container_detail::allocator_version_traits56    static void allocate_individual(Allocator &a, size_type n, multiallocation_chain &m)
57    {  return a.allocate_individual(n, m);   }
58 
deallocate_individualboost::container::container_detail::allocator_version_traits59    static void deallocate_individual(Allocator &a, multiallocation_chain &holder)
60    {  a.deallocate_individual(holder);   }
61 
allocation_commandboost::container::container_detail::allocator_version_traits62    static pointer allocation_command(Allocator &a, allocation_type command,
63                          size_type limit_size, size_type &prefer_in_recvd_out_size, pointer &reuse)
64    {  return a.allocation_command(command, limit_size, prefer_in_recvd_out_size, reuse);  }
65 };
66 
67 template<class Allocator>
68 struct allocator_version_traits<Allocator, 1>
69 {
70    typedef ::boost::container::container_detail::integral_constant
71       <unsigned, 1> alloc_version;
72 
73    typedef typename boost::container::allocator_traits<Allocator>::pointer    pointer;
74    typedef typename boost::container::allocator_traits<Allocator>::size_type  size_type;
75    typedef typename boost::container::allocator_traits<Allocator>::value_type value_type;
76 
77    typedef typename boost::intrusive::pointer_traits<pointer>::
78          template rebind_pointer<void>::type                void_ptr;
79    typedef container_detail::basic_multiallocation_chain
80       <void_ptr>                                            multialloc_cached_counted;
81    typedef boost::container::container_detail::
82       transform_multiallocation_chain
83          < multialloc_cached_counted, value_type>           multiallocation_chain;
84 
85    //Node allocation interface
allocate_oneboost::container::container_detail::allocator_version_traits86    static pointer allocate_one(Allocator &a)
87    {  return a.allocate(1);   }
88 
deallocate_oneboost::container::container_detail::allocator_version_traits89    static void deallocate_one(Allocator &a, const pointer &p)
90    {  a.deallocate(p, 1);   }
91 
deallocate_individualboost::container::container_detail::allocator_version_traits92    static void deallocate_individual(Allocator &a, multiallocation_chain &holder)
93    {
94       size_type n = holder.size();
95       typename multiallocation_chain::iterator it = holder.begin();
96       while(n--){
97          pointer p = boost::intrusive::pointer_traits<pointer>::pointer_to(*it);
98          ++it;
99          a.deallocate(p, 1);
100       }
101    }
102 
103    struct allocate_individual_rollback
104    {
allocate_individual_rollbackboost::container::container_detail::allocator_version_traits::allocate_individual_rollback105       allocate_individual_rollback(Allocator &a, multiallocation_chain &chain)
106          : mr_a(a), mp_chain(&chain)
107       {}
108 
~allocate_individual_rollbackboost::container::container_detail::allocator_version_traits::allocate_individual_rollback109       ~allocate_individual_rollback()
110       {
111          if(mp_chain)
112             allocator_version_traits::deallocate_individual(mr_a, *mp_chain);
113       }
114 
releaseboost::container::container_detail::allocator_version_traits::allocate_individual_rollback115       void release()
116       {
117          mp_chain = 0;
118       }
119 
120       Allocator &mr_a;
121       multiallocation_chain * mp_chain;
122    };
123 
allocate_individualboost::container::container_detail::allocator_version_traits124    static void allocate_individual(Allocator &a, size_type n, multiallocation_chain &m)
125    {
126       allocate_individual_rollback rollback(a, m);
127       while(n--){
128          m.push_front(a.allocate(1));
129       }
130       rollback.release();
131    }
132 
allocation_commandboost::container::container_detail::allocator_version_traits133    static pointer allocation_command(Allocator &a, allocation_type command,
134                          size_type, size_type &prefer_in_recvd_out_size, pointer &reuse)
135    {
136       pointer ret = pointer();
137       if(BOOST_UNLIKELY(!(command & allocate_new) && !(command & nothrow_allocation))){
138          throw_logic_error("version 1 allocator without allocate_new flag");
139       }
140       else{
141          BOOST_TRY{
142             ret = a.allocate(prefer_in_recvd_out_size);
143          }
144          BOOST_CATCH(...){
145             if(!(command & nothrow_allocation)){
146                BOOST_RETHROW
147             }
148          }
149          BOOST_CATCH_END
150          reuse = pointer();
151       }
152       return ret;
153    }
154 };
155 
156 }  //namespace container_detail {
157 }  //namespace container {
158 }  //namespace boost {
159 
160 #include <boost/container/detail/config_end.hpp>
161 
162 #endif // ! defined(BOOST_CONTAINER_DETAIL_ALLOCATOR_VERSION_TRAITS_HPP)
163