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 dtl {
37 
38 template<class Allocator, unsigned Version = boost::container::dtl::version<Allocator>::value>
39 struct allocator_version_traits
40 {
41    typedef ::boost::container::dtl::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::dtl::allocator_version_traits50    static pointer allocate_one(Allocator &a)
51    {  return a.allocate_one();   }
52 
deallocate_oneboost::container::dtl::allocator_version_traits53    static void deallocate_one(Allocator &a, const pointer &p)
54    {  a.deallocate_one(p);   }
55 
allocate_individualboost::container::dtl::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::dtl::allocator_version_traits59    static void deallocate_individual(Allocator &a, multiallocation_chain &holder)
60    {  a.deallocate_individual(holder);   }
61 
allocation_commandboost::container::dtl::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::dtl::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 dtl::basic_multiallocation_chain
80       <void_ptr>                                            multialloc_cached_counted;
81    typedef boost::container::dtl::
82       transform_multiallocation_chain
83          < multialloc_cached_counted, value_type>           multiallocation_chain;
84 
85    //Node allocation interface
allocate_oneboost::container::dtl::allocator_version_traits86    static pointer allocate_one(Allocator &a)
87    {  return a.allocate(1);   }
88 
deallocate_oneboost::container::dtl::allocator_version_traits89    static void deallocate_one(Allocator &a, const pointer &p)
90    {  a.deallocate(p, 1);   }
91 
deallocate_individualboost::container::dtl::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          --n;
98          pointer p = boost::intrusive::pointer_traits<pointer>::pointer_to(*it);
99          ++it;
100          a.deallocate(p, 1);
101       }
102    }
103 
104    struct allocate_individual_rollback
105    {
allocate_individual_rollbackboost::container::dtl::allocator_version_traits::allocate_individual_rollback106       allocate_individual_rollback(Allocator &a, multiallocation_chain &chain)
107          : mr_a(a), mp_chain(&chain)
108       {}
109 
~allocate_individual_rollbackboost::container::dtl::allocator_version_traits::allocate_individual_rollback110       ~allocate_individual_rollback()
111       {
112          if(mp_chain)
113             allocator_version_traits::deallocate_individual(mr_a, *mp_chain);
114       }
115 
releaseboost::container::dtl::allocator_version_traits::allocate_individual_rollback116       void release()
117       {
118          mp_chain = 0;
119       }
120 
121       Allocator &mr_a;
122       multiallocation_chain * mp_chain;
123    };
124 
allocate_individualboost::container::dtl::allocator_version_traits125    static void allocate_individual(Allocator &a, size_type n, multiallocation_chain &m)
126    {
127       allocate_individual_rollback rollback(a, m);
128       while(n--){
129          m.push_front(a.allocate(1));
130       }
131       rollback.release();
132    }
133 
allocation_commandboost::container::dtl::allocator_version_traits134    static pointer allocation_command(Allocator &a, allocation_type command,
135                          size_type, size_type &prefer_in_recvd_out_size, pointer &reuse)
136    {
137       pointer ret = pointer();
138       if(BOOST_UNLIKELY(!(command & allocate_new) && !(command & nothrow_allocation))){
139          throw_logic_error("version 1 allocator without allocate_new flag");
140       }
141       else{
142          BOOST_TRY{
143             ret = a.allocate(prefer_in_recvd_out_size);
144          }
145          BOOST_CATCH(...){
146             if(!(command & nothrow_allocation)){
147                BOOST_RETHROW
148             }
149          }
150          BOOST_CATCH_END
151          reuse = pointer();
152       }
153       return ret;
154    }
155 };
156 
157 }  //namespace dtl {
158 }  //namespace container {
159 }  //namespace boost {
160 
161 #include <boost/container/detail/config_end.hpp>
162 
163 #endif // ! defined(BOOST_CONTAINER_DETAIL_ALLOCATOR_VERSION_TRAITS_HPP)
164