File indexing completed on 2025-01-30 09:34:56
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_CONTAINER_PMR_RESOURCE_ADAPTOR_HPP
0012 #define BOOST_CONTAINER_PMR_RESOURCE_ADAPTOR_HPP
0013
0014 #if defined (_MSC_VER)
0015 # pragma once
0016 #endif
0017
0018 #include <boost/container/detail/config_begin.hpp>
0019 #include <boost/container/detail/workaround.hpp>
0020 #include <boost/container/container_fwd.hpp>
0021
0022 #include <boost/container/pmr/memory_resource.hpp>
0023 #include <boost/container/allocator_traits.hpp>
0024 #include <boost/intrusive/detail/ebo_functor_holder.hpp>
0025 #include <boost/move/utility_core.hpp>
0026 #include <boost/move/detail/type_traits.hpp>
0027 #include <boost/container/detail/std_fwd.hpp>
0028
0029 #include <cstring>
0030
0031 namespace boost {
0032 namespace container {
0033
0034 namespace pmr_dtl {
0035
0036 template<class T>
0037 struct max_allocator_alignment
0038 {
0039 static const std::size_t value = 1;
0040 };
0041
0042 template<class T>
0043 struct max_allocator_alignment< ::boost::container::new_allocator<T> >
0044 {
0045 static const std::size_t value = boost::move_detail::alignment_of<boost::move_detail::max_align_t>::value;
0046 };
0047
0048 template<class T>
0049 struct max_allocator_alignment< std::allocator<T> >
0050 {
0051 static const std::size_t value = boost::move_detail::alignment_of<boost::move_detail::max_align_t>::value;
0052 };
0053
0054 }
0055
0056 namespace pmr {
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075 template <class Allocator>
0076 class resource_adaptor_imp
0077 : public memory_resource
0078 #ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
0079 , private ::boost::intrusive::detail::ebo_functor_holder<Allocator>
0080 #endif
0081 {
0082 #ifdef BOOST_CONTAINER_DOXYGEN_INVOKED
0083 Allocator m_alloc;
0084 #else
0085 BOOST_COPYABLE_AND_MOVABLE(resource_adaptor_imp)
0086 typedef ::boost::intrusive::detail::ebo_functor_holder<Allocator> ebo_alloc_t;
0087 void static_assert_if_not_char_allocator() const
0088 {
0089
0090 BOOST_STATIC_ASSERT((boost::container::dtl::is_same<typename Allocator::value_type, char>::value));
0091 }
0092 #endif
0093
0094 public:
0095 typedef Allocator allocator_type;
0096
0097
0098
0099 resource_adaptor_imp()
0100 { this->static_assert_if_not_char_allocator(); }
0101
0102
0103
0104 resource_adaptor_imp(const resource_adaptor_imp &other)
0105 : ebo_alloc_t(other.ebo_alloc_t::get())
0106 {}
0107
0108
0109
0110 resource_adaptor_imp(BOOST_RV_REF(resource_adaptor_imp) other)
0111 : ebo_alloc_t(::boost::move(other.get()))
0112 {}
0113
0114
0115
0116 explicit resource_adaptor_imp(const Allocator& a2)
0117 : ebo_alloc_t(a2)
0118 { this->static_assert_if_not_char_allocator(); }
0119
0120
0121
0122 explicit resource_adaptor_imp(BOOST_RV_REF(Allocator) a2)
0123 : ebo_alloc_t(::boost::move(a2))
0124 { this->static_assert_if_not_char_allocator(); }
0125
0126
0127
0128 resource_adaptor_imp& operator=(BOOST_COPY_ASSIGN_REF(resource_adaptor_imp) other)
0129 { this->ebo_alloc_t::get() = other.ebo_alloc_t::get(); return *this; }
0130
0131
0132
0133 resource_adaptor_imp& operator=(BOOST_RV_REF(resource_adaptor_imp) other)
0134 { this->ebo_alloc_t::get() = ::boost::move(other.ebo_alloc_t::get()); return *this; }
0135
0136
0137 allocator_type &get_allocator()
0138 { return this->ebo_alloc_t::get(); }
0139
0140
0141 const allocator_type &get_allocator() const
0142 { return this->ebo_alloc_t::get(); }
0143
0144 protected:
0145
0146
0147 virtual void* do_allocate(std::size_t bytes, std::size_t alignment) BOOST_OVERRIDE
0148 {
0149 if (alignment <= priv_guaranteed_allocator_alignment())
0150 return this->ebo_alloc_t::get().allocate(bytes);
0151 else
0152 return this->priv_aligned_alloc(bytes, alignment);
0153 }
0154
0155
0156
0157
0158
0159 virtual void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) BOOST_OVERRIDE
0160 {
0161 if (alignment <= priv_guaranteed_allocator_alignment())
0162 this->ebo_alloc_t::get().deallocate((char*)p, bytes);
0163 else
0164 this->priv_aligned_dealloc(p, bytes, alignment);
0165 }
0166
0167
0168
0169
0170 virtual bool do_is_equal(const memory_resource& other) const BOOST_NOEXCEPT BOOST_OVERRIDE
0171 {
0172 const resource_adaptor_imp* p = dynamic_cast<const resource_adaptor_imp*>(&other);
0173 return p && p->ebo_alloc_t::get() == this->ebo_alloc_t::get();
0174 }
0175
0176 private:
0177 void * priv_aligned_alloc(std::size_t bytes, std::size_t alignment)
0178 {
0179
0180 void *const p = this->ebo_alloc_t::get().allocate(bytes + priv_extra_bytes_for_overalignment(alignment));
0181
0182 if (0 != p) {
0183
0184 void *const aligned_ptr = (void*)(((std::size_t)p + priv_extra_bytes_for_overalignment(alignment)) & ~(alignment - 1));
0185
0186
0187
0188 std::memcpy(priv_bookeeping_addr_from_aligned_ptr(aligned_ptr), &p, sizeof(p));
0189 return aligned_ptr;
0190 }
0191 return 0;
0192 }
0193
0194 void priv_aligned_dealloc(void *aligned_ptr, std::size_t bytes, std::size_t alignment)
0195 {
0196
0197 void *p;
0198 std::memcpy(&p, priv_bookeeping_addr_from_aligned_ptr(aligned_ptr), sizeof(p));
0199 std::size_t s = bytes + priv_extra_bytes_for_overalignment(alignment);
0200 this->ebo_alloc_t::get().deallocate((char*)p, s);
0201 }
0202
0203 static BOOST_CONTAINER_FORCEINLINE void *priv_bookeeping_addr_from_aligned_ptr(void *aligned_ptr)
0204 {
0205 return reinterpret_cast<void*>(reinterpret_cast<std::size_t>(aligned_ptr) - sizeof(void*));
0206 }
0207
0208 BOOST_CONTAINER_FORCEINLINE static std::size_t priv_extra_bytes_for_overalignment(std::size_t alignment)
0209 {
0210 return alignment - 1 + sizeof(void*);
0211 }
0212
0213 BOOST_CONTAINER_FORCEINLINE static std::size_t priv_guaranteed_allocator_alignment()
0214 {
0215 return pmr_dtl::max_allocator_alignment<Allocator>::value;
0216 }
0217 };
0218
0219 #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) || defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
0220
0221
0222
0223 template <class Allocator>
0224 using resource_adaptor = resource_adaptor_imp
0225 <typename allocator_traits<Allocator>::template rebind_alloc<char> >;
0226
0227 #else
0228
0229 template <class Allocator>
0230 class resource_adaptor
0231 : public resource_adaptor_imp
0232 <typename allocator_traits<Allocator>::template portable_rebind_alloc<char>::type>
0233 {
0234 typedef resource_adaptor_imp
0235 <typename allocator_traits<Allocator>::template portable_rebind_alloc<char>::type> base_t;
0236
0237 BOOST_COPYABLE_AND_MOVABLE(resource_adaptor)
0238
0239 public:
0240 resource_adaptor()
0241 : base_t()
0242 {}
0243
0244 resource_adaptor(const resource_adaptor &other)
0245 : base_t(other)
0246 {}
0247
0248 resource_adaptor(BOOST_RV_REF(resource_adaptor) other)
0249 : base_t(BOOST_MOVE_BASE(base_t, other))
0250 {}
0251
0252 explicit resource_adaptor(const Allocator& a2)
0253 : base_t(a2)
0254 {}
0255
0256 explicit resource_adaptor(BOOST_RV_REF(Allocator) a2)
0257 : base_t(::boost::move(a2))
0258 {}
0259
0260 resource_adaptor& operator=(BOOST_COPY_ASSIGN_REF(resource_adaptor) other)
0261 { return static_cast<resource_adaptor&>(this->base_t::operator=(other)); }
0262
0263 resource_adaptor& operator=(BOOST_RV_REF(resource_adaptor) other)
0264 { return static_cast<resource_adaptor&>(this->base_t::operator=(BOOST_MOVE_BASE(base_t, other))); }
0265
0266
0267 };
0268
0269 #endif
0270
0271 }
0272 }
0273 }
0274
0275 #include <boost/container/detail/config_end.hpp>
0276
0277 #endif