File indexing completed on 2025-12-16 10:08:50
0001
0002
0003
0004
0005
0006
0007
0008 #ifndef BOOST_SMART_PTR_ALLOCATE_UNIQUE_HPP
0009 #define BOOST_SMART_PTR_ALLOCATE_UNIQUE_HPP
0010
0011 #include <boost/core/allocator_access.hpp>
0012 #include <boost/core/alloc_construct.hpp>
0013 #include <boost/core/empty_value.hpp>
0014 #include <boost/core/first_scalar.hpp>
0015 #include <boost/core/noinit_adaptor.hpp>
0016 #include <boost/core/pointer_traits.hpp>
0017 #include <boost/smart_ptr/detail/sp_type_traits.hpp>
0018 #include <boost/config.hpp>
0019 #include <memory>
0020 #include <utility>
0021 #include <cstddef>
0022 #include <type_traits>
0023
0024 namespace boost {
0025 namespace detail {
0026
0027 template<class T>
0028 struct sp_alloc_size {
0029 static constexpr std::size_t value = 1;
0030 };
0031
0032 template<class T>
0033 struct sp_alloc_size<T[]> {
0034 static constexpr std::size_t value = sp_alloc_size<T>::value;
0035 };
0036
0037 template<class T, std::size_t N>
0038 struct sp_alloc_size<T[N]> {
0039 static constexpr std::size_t value = N * sp_alloc_size<T>::value;
0040 };
0041
0042 template<class T>
0043 struct sp_alloc_result {
0044 typedef T type;
0045 };
0046
0047 template<class T, std::size_t N>
0048 struct sp_alloc_result<T[N]> {
0049 typedef T type[];
0050 };
0051
0052 template<class T>
0053 struct sp_alloc_value {
0054 typedef typename std::remove_cv<typename
0055 std::remove_extent<T>::type>::type type;
0056 };
0057
0058 template<class T, class P>
0059 class sp_alloc_ptr {
0060 public:
0061 typedef T element_type;
0062
0063 sp_alloc_ptr() noexcept
0064 : p_() { }
0065
0066 #if defined(BOOST_MSVC) && BOOST_MSVC == 1600
0067 sp_alloc_ptr(T* p) noexcept
0068 : p_(const_cast<typename std::remove_cv<T>::type*>(p)) { }
0069 #endif
0070
0071 sp_alloc_ptr(std::size_t, P p) noexcept
0072 : p_(p) { }
0073
0074 sp_alloc_ptr(std::nullptr_t) noexcept
0075 : p_() { }
0076
0077 T& operator*() const {
0078 return *p_;
0079 }
0080
0081 T* operator->() const noexcept {
0082 return boost::to_address(p_);
0083 }
0084
0085 explicit operator bool() const noexcept {
0086 return !!p_;
0087 }
0088
0089 bool operator!() const noexcept {
0090 return !p_;
0091 }
0092
0093 P ptr() const noexcept {
0094 return p_;
0095 }
0096
0097 static constexpr std::size_t size() noexcept {
0098 return 1;
0099 }
0100
0101 #if defined(BOOST_MSVC) && BOOST_MSVC < 1910
0102 static sp_alloc_ptr pointer_to(T& v) {
0103 return sp_alloc_ptr(1,
0104 std::pointer_traits<P>::pointer_to(const_cast<typename
0105 std::remove_cv<T>::type&>(v)));
0106 }
0107 #endif
0108
0109 private:
0110 P p_;
0111 };
0112
0113 template<class T, class P>
0114 class sp_alloc_ptr<T[], P> {
0115 public:
0116 typedef T element_type;
0117
0118 sp_alloc_ptr() noexcept
0119 : p_() { }
0120
0121 sp_alloc_ptr(std::size_t n, P p) noexcept
0122 : p_(p)
0123 , n_(n) { }
0124
0125 sp_alloc_ptr(std::nullptr_t) noexcept
0126 : p_() { }
0127
0128 T& operator[](std::size_t i) const {
0129 return p_[i];
0130 }
0131
0132 explicit operator bool() const noexcept {
0133 return !!p_;
0134 }
0135
0136 bool operator!() const noexcept {
0137 return !p_;
0138 }
0139
0140 P ptr() const noexcept {
0141 return p_;
0142 }
0143
0144 std::size_t size() const noexcept {
0145 return n_;
0146 }
0147
0148 #if defined(BOOST_MSVC) && BOOST_MSVC < 1910
0149 static sp_alloc_ptr pointer_to(T& v) {
0150 return sp_alloc_ptr(n_,
0151 std::pointer_traits<P>::pointer_to(const_cast<typename
0152 std::remove_cv<T>::type&>(v)));
0153 }
0154 #endif
0155
0156 private:
0157 P p_;
0158 std::size_t n_;
0159 };
0160
0161 template<class T, std::size_t N, class P>
0162 class sp_alloc_ptr<T[N], P> {
0163 public:
0164 typedef T element_type;
0165
0166 sp_alloc_ptr() noexcept
0167 : p_() { }
0168
0169 sp_alloc_ptr(std::size_t, P p) noexcept
0170 : p_(p) { }
0171
0172 sp_alloc_ptr(std::nullptr_t) noexcept
0173 : p_() { }
0174
0175 T& operator[](std::size_t i) const {
0176 return p_[i];
0177 }
0178
0179 explicit operator bool() const noexcept {
0180 return !!p_;
0181 }
0182
0183 bool operator!() const noexcept {
0184 return !p_;
0185 }
0186
0187 P ptr() const noexcept {
0188 return p_;
0189 }
0190
0191 static constexpr std::size_t size() noexcept {
0192 return N;
0193 }
0194
0195 #if defined(BOOST_MSVC) && BOOST_MSVC < 1910
0196 static sp_alloc_ptr pointer_to(T& v) {
0197 return sp_alloc_ptr(N,
0198 std::pointer_traits<P>::pointer_to(const_cast<typename
0199 std::remove_cv<T>::type&>(v)));
0200 }
0201 #endif
0202
0203 private:
0204 P p_;
0205 };
0206
0207 template<class T, class P>
0208 inline bool
0209 operator==(const sp_alloc_ptr<T, P>& lhs, const sp_alloc_ptr<T, P>& rhs)
0210 {
0211 return lhs.ptr() == rhs.ptr();
0212 }
0213
0214 template<class T, class P>
0215 inline bool
0216 operator!=(const sp_alloc_ptr<T, P>& lhs, const sp_alloc_ptr<T, P>& rhs)
0217 {
0218 return !(lhs == rhs);
0219 }
0220
0221 template<class T, class P>
0222 inline bool
0223 operator==(const sp_alloc_ptr<T, P>& lhs,
0224 std::nullptr_t) noexcept
0225 {
0226 return !lhs.ptr();
0227 }
0228
0229 template<class T, class P>
0230 inline bool
0231 operator==(std::nullptr_t,
0232 const sp_alloc_ptr<T, P>& rhs) noexcept
0233 {
0234 return !rhs.ptr();
0235 }
0236
0237 template<class T, class P>
0238 inline bool
0239 operator!=(const sp_alloc_ptr<T, P>& lhs,
0240 std::nullptr_t) noexcept
0241 {
0242 return !!lhs.ptr();
0243 }
0244
0245 template<class T, class P>
0246 inline bool
0247 operator!=(std::nullptr_t,
0248 const sp_alloc_ptr<T, P>& rhs) noexcept
0249 {
0250 return !!rhs.ptr();
0251 }
0252
0253 template<class A>
0254 inline void
0255 sp_alloc_clear(A& a, typename boost::allocator_pointer<A>::type p, std::size_t,
0256 std::false_type)
0257 {
0258 boost::alloc_destroy(a, boost::to_address(p));
0259 }
0260
0261 template<class A>
0262 inline void
0263 sp_alloc_clear(A& a, typename boost::allocator_pointer<A>::type p,
0264 std::size_t n, std::true_type)
0265 {
0266 #if defined(BOOST_MSVC) && BOOST_MSVC < 1800
0267 if (!p) {
0268 return;
0269 }
0270 #endif
0271 boost::alloc_destroy_n(a, boost::first_scalar(boost::to_address(p)),
0272 n * sp_alloc_size<typename A::value_type>::value);
0273 }
0274
0275 }
0276
0277 template<class T, class A>
0278 class alloc_deleter
0279 : empty_value<typename allocator_rebind<A,
0280 typename detail::sp_alloc_value<T>::type>::type> {
0281 typedef typename allocator_rebind<A,
0282 typename detail::sp_alloc_value<T>::type>::type allocator;
0283 typedef empty_value<allocator> base;
0284
0285 public:
0286 typedef detail::sp_alloc_ptr<T,
0287 typename allocator_pointer<allocator>::type> pointer;
0288
0289 explicit alloc_deleter(const allocator& a) noexcept
0290 : base(empty_init_t(), a) { }
0291
0292 void operator()(pointer p) {
0293 detail::sp_alloc_clear(base::get(), p.ptr(), p.size(), std::is_array<T>());
0294 base::get().deallocate(p.ptr(), p.size());
0295 }
0296 };
0297
0298 template<class T, class A>
0299 using alloc_noinit_deleter = alloc_deleter<T, noinit_adaptor<A> >;
0300
0301 namespace detail {
0302
0303 template<class T, class A>
0304 class sp_alloc_make {
0305 public:
0306 typedef typename boost::allocator_rebind<A,
0307 typename sp_alloc_value<T>::type>::type allocator;
0308
0309 private:
0310 typedef boost::alloc_deleter<T, A> deleter;
0311
0312 public:
0313 typedef std::unique_ptr<typename sp_alloc_result<T>::type, deleter> type;
0314
0315 sp_alloc_make(const A& a, std::size_t n)
0316 : a_(a)
0317 , n_(n)
0318 , p_(a_.allocate(n)) { }
0319
0320 ~sp_alloc_make() {
0321 if (p_) {
0322 a_.deallocate(p_, n_);
0323 }
0324 }
0325
0326 typename allocator::value_type* get() const noexcept {
0327 return boost::to_address(p_);
0328 }
0329
0330 allocator& state() noexcept {
0331 return a_;
0332 }
0333
0334 type release() noexcept {
0335 pointer p = p_;
0336 p_ = pointer();
0337 return type(typename deleter::pointer(n_, p), deleter(a_));
0338 }
0339
0340 private:
0341 typedef typename boost::allocator_pointer<allocator>::type pointer;
0342
0343 allocator a_;
0344 std::size_t n_;
0345 pointer p_;
0346 };
0347
0348 }
0349
0350 template<class T, class A>
0351 inline typename std::enable_if<!std::is_array<T>::value,
0352 std::unique_ptr<T, alloc_deleter<T, A> > >::type
0353 allocate_unique(const A& alloc)
0354 {
0355 detail::sp_alloc_make<T, A> c(alloc, 1);
0356 boost::alloc_construct(c.state(), c.get());
0357 return c.release();
0358 }
0359
0360 template<class T, class A, class... Args>
0361 inline typename std::enable_if<!std::is_array<T>::value,
0362 std::unique_ptr<T, alloc_deleter<T, A> > >::type
0363 allocate_unique(const A& alloc, Args&&... args)
0364 {
0365 detail::sp_alloc_make<T, A> c(alloc, 1);
0366 boost::alloc_construct(c.state(), c.get(), std::forward<Args>(args)...);
0367 return c.release();
0368 }
0369
0370 template<class T, class A>
0371 inline typename std::enable_if<!std::is_array<T>::value,
0372 std::unique_ptr<T, alloc_deleter<T, A> > >::type
0373 allocate_unique(const A& alloc, typename detail::sp_type_identity<T>::type&& value)
0374 {
0375 detail::sp_alloc_make<T, A> c(alloc, 1);
0376 boost::alloc_construct(c.state(), c.get(), std::move(value));
0377 return c.release();
0378 }
0379
0380 template<class T, class A>
0381 inline typename std::enable_if<!std::is_array<T>::value,
0382 std::unique_ptr<T, alloc_deleter<T, noinit_adaptor<A> > > >::type
0383 allocate_unique_noinit(const A& alloc)
0384 {
0385 return boost::allocate_unique<T, noinit_adaptor<A> >(alloc);
0386 }
0387
0388 template<class T, class A>
0389 inline typename std::enable_if<detail::sp_is_unbounded_array<T>::value,
0390 std::unique_ptr<T, alloc_deleter<T, A> > >::type
0391 allocate_unique(const A& alloc, std::size_t size)
0392 {
0393 detail::sp_alloc_make<T, A> c(alloc, size);
0394 boost::alloc_construct_n(c.state(), boost::first_scalar(c.get()),
0395 size * detail::sp_alloc_size<T>::value);
0396 return c.release();
0397 }
0398
0399 template<class T, class A>
0400 inline typename std::enable_if<detail::sp_is_bounded_array<T>::value,
0401 std::unique_ptr<typename detail::sp_alloc_result<T>::type,
0402 alloc_deleter<T, A> > >::type
0403 allocate_unique(const A& alloc)
0404 {
0405 detail::sp_alloc_make<T, A> c(alloc, std::extent<T>::value);
0406 boost::alloc_construct_n(c.state(), boost::first_scalar(c.get()),
0407 detail::sp_alloc_size<T>::value);
0408 return c.release();
0409 }
0410
0411 template<class T, class A>
0412 inline typename std::enable_if<detail::sp_is_unbounded_array<T>::value,
0413 std::unique_ptr<T, alloc_deleter<T, noinit_adaptor<A> > > >::type
0414 allocate_unique_noinit(const A& alloc, std::size_t size)
0415 {
0416 return boost::allocate_unique<T, noinit_adaptor<A> >(alloc, size);
0417 }
0418
0419 template<class T, class A>
0420 inline typename std::enable_if<detail::sp_is_bounded_array<T>::value,
0421 std::unique_ptr<typename detail::sp_alloc_result<T>::type,
0422 alloc_deleter<T, noinit_adaptor<A> > > >::type
0423 allocate_unique_noinit(const A& alloc)
0424 {
0425 return boost::allocate_unique<T, noinit_adaptor<A> >(alloc);
0426 }
0427
0428 template<class T, class A>
0429 inline typename std::enable_if<detail::sp_is_unbounded_array<T>::value,
0430 std::unique_ptr<T, alloc_deleter<T, A> > >::type
0431 allocate_unique(const A& alloc, std::size_t size,
0432 const typename std::remove_extent<T>::type& value)
0433 {
0434 detail::sp_alloc_make<T, A> c(alloc, size);
0435 boost::alloc_construct_n(c.state(), boost::first_scalar(c.get()),
0436 size * detail::sp_alloc_size<T>::value, boost::first_scalar(&value),
0437 detail::sp_alloc_size<typename std::remove_extent<T>::type>::value);
0438 return c.release();
0439 }
0440
0441 template<class T, class A>
0442 inline typename std::enable_if<detail::sp_is_bounded_array<T>::value,
0443 std::unique_ptr<typename detail::sp_alloc_result<T>::type,
0444 alloc_deleter<T, A> > >::type
0445 allocate_unique(const A& alloc,
0446 const typename std::remove_extent<T>::type& value)
0447 {
0448 detail::sp_alloc_make<T, A> c(alloc, std::extent<T>::value);
0449 boost::alloc_construct_n(c.state(), boost::first_scalar(c.get()),
0450 detail::sp_alloc_size<T>::value, boost::first_scalar(&value),
0451 detail::sp_alloc_size<typename std::remove_extent<T>::type>::value);
0452 return c.release();
0453 }
0454
0455 template<class T, class U, class A>
0456 inline typename allocator_pointer<typename allocator_rebind<A,
0457 typename detail::sp_alloc_value<T>::type>::type>::type
0458 get_allocator_pointer(const std::unique_ptr<T,
0459 alloc_deleter<U, A> >& p) noexcept
0460 {
0461 return p.get().ptr();
0462 }
0463
0464 }
0465
0466 #endif