1/* Copyright 2003-2020 Joaquin M Lopez Munoz.
2 * Distributed under the Boost Software License, Version 1.0.
3 * (See accompanying file LICENSE_1_0.txt or copy at
4 * http://www.boost.org/LICENSE_1_0.txt)
5 *
6 * See http://www.boost.org/libs/multi_index for library home page.
7 */
8
9#ifndef BOOST_MULTI_INDEX_DETAIL_ALLOCATOR_TRAITS_HPP
10#define BOOST_MULTI_INDEX_DETAIL_ALLOCATOR_TRAITS_HPP
11
12#if defined(_MSC_VER)
13#pragma once
14#endif
15
16#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
17
18#if !defined(BOOST_NO_CXX11_ALLOCATOR)
19#include <boost/type_traits/is_empty.hpp>
20#include <memory>
21#else
22#include <boost/detail/workaround.hpp>
23#include <boost/move/core.hpp>
24#include <boost/move/utility_core.hpp>
25#include <boost/multi_index/detail/vartempl_support.hpp>
26#include <boost/type_traits/integral_constant.hpp>
27#include <boost/type_traits/is_empty.hpp>
28#include <new>
29#endif
30
31namespace boost{
32
33namespace multi_index{
34
35namespace detail{
36
37/* poor man's replacement of std::allocator_traits */
38
39#if !defined(BOOST_NO_CXX11_ALLOCATOR)
40
41template<typename T> struct void_helper{typedef void type;};
42
43template<typename Allocator,typename=void>
44struct allocator_is_always_equal:boost::is_empty<Allocator>{};
45
46template<typename Allocator>
47struct allocator_is_always_equal<
48 Allocator,
49 typename void_helper<
50 typename std::allocator_traits<Allocator>::is_always_equal
51 >::type
52>:std::allocator_traits<Allocator>::is_always_equal{};
53
54template<typename Allocator>
55struct allocator_traits:std::allocator_traits<Allocator>
56{
57 /* wrap std::allocator_traits alias templates for use in C++03 codebase */
58
59 typedef std::allocator_traits<Allocator> super;
60
61 /* pre-C++17 compatibilty */
62
63 typedef allocator_is_always_equal<Allocator> is_always_equal;
64
65 template<typename T>
66 struct rebind_alloc
67 {
68 typedef typename super::template rebind_alloc<T> type;
69 };
70
71 template<typename T>
72 struct rebind_traits
73 {
74 typedef typename super::template rebind_traits<T> type;
75 };
76};
77
78#else
79
80/* not a full std::allocator_traits rewrite (not needed) */
81
82template<typename Allocator>
83struct allocator_traits
84{
85 typedef Allocator allocator_type;
86 typedef typename Allocator::value_type value_type;
87 typedef typename Allocator::pointer pointer;
88 typedef typename Allocator::const_pointer const_pointer;
89
90 /* [const_]void_pointer not provided as boost::pointer_traits's
91 * rebind_to has been seen to fail with things like
92 * boost::interprocess::offset_ptr in relatively old environments.
93 */
94
95 typedef typename Allocator::difference_type difference_type;
96 typedef typename Allocator::size_type size_type;
97
98 typedef boost::false_type propagate_on_container_copy_assignment;
99 typedef boost::false_type propagate_on_container_move_assignment;
100 typedef boost::false_type propagate_on_container_swap;
101 typedef boost::is_empty<Allocator> is_always_equal;
102
103 template<typename T>
104 struct rebind_alloc
105 {
106 typedef typename Allocator::template rebind<T>::other type;
107 };
108
109 template<typename T>
110 struct rebind_traits
111 {
112 typedef allocator_traits<typename rebind_alloc<T>::type> type;
113 };
114
115 static pointer allocate(Allocator& a,size_type n){return a.allocate(n);}
116 static pointer allocate(Allocator& a,size_type n,const_pointer p)
117 /* should've been const_void_pointer p */
118 {return a.allocate(n,p);}
119 static void deallocate(Allocator& a,pointer p,size_type n)
120 {a.deallocate(p,n);}
121 template<typename T>
122 static void construct(Allocator&,T* p,const T& x)
123 {::new (static_cast<void*>(p)) T(x);}
124 template<typename T>
125 static void construct(Allocator&,T* p,BOOST_RV_REF(T) x)
126 {::new (static_cast<void*>(p)) T(boost::move(x));}
127
128 template<typename T,BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK>
129 static void construct(Allocator&,T* p,BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK)
130 {
131 vartempl_placement_new(p,BOOST_MULTI_INDEX_FORWARD_PARAM_PACK);
132 }
133
134#if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1500))
135/* MSVC issues spurious warnings about unreferencend formal parameters in
136 * destroy<T> when T is a class with trivial dtor.
137 */
138
139#pragma warning(push)
140#pragma warning(disable:4100)
141#endif
142
143 template<typename T>
144 static void destroy(Allocator&,T* p){p->~T();}
145
146#if BOOST_WORKAROUND(BOOST_MSVC,BOOST_TESTED_AT(1500))
147#pragma warning(pop)
148#endif
149
150 static size_type max_size(Allocator& a)BOOST_NOEXCEPT{return a.max_size();}
151
152 static Allocator select_on_container_copy_construction(const Allocator& a)
153 {
154 return a;
155 }
156};
157
158#endif
159
160template<typename Allocator,typename T>
161struct rebind_alloc_for
162{
163 typedef typename allocator_traits<Allocator>::
164 template rebind_alloc<T>::type type;
165};
166
167} /* namespace multi_index::detail */
168
169} /* namespace multi_index */
170
171} /* namespace boost */
172
173#endif
174