1 +
 //
 
2 +
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
 
3 +
//
 
4 +
// Distributed under the Boost Software License, Version 1.0. (See accompanying
 
5 +
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
6 +
//
 
7 +
// Official repository: https://github.com/boostorg/url
 
8 +
//
 
9 +

 
10 +
#ifndef BOOST_URL_DETAIL_OVER_ALLOCATOR_HPP
 
11 +
#define BOOST_URL_DETAIL_OVER_ALLOCATOR_HPP
 
12 +

 
13 +
#include <boost/config.hpp>
 
14 +
#include <boost/core/empty_value.hpp>
 
15 +
#include <boost/assert.hpp>
 
16 +
#include <boost/type_traits/is_final.hpp>
 
17 +
#include <boost/type_traits/type_with_alignment.hpp>
 
18 +
#ifdef BOOST_NO_CXX11_ALLOCATOR
 
19 +
# include <boost/core/allocator_traits.hpp>
 
20 +
#endif
 
21 +
#include <cstddef>
 
22 +
#include <memory>
 
23 +
#include <type_traits>
 
24 +
#include <utility>
 
25 +

 
26 +
namespace boost {
 
27 +
namespace urls {
 
28 +
namespace detail {
 
29 +

 
30 +
// This is a workaround for allocator_traits
 
31 +
// implementations which falsely claim C++11
 
32 +
// compatibility.
 
33 +
#ifdef BOOST_NO_CXX11_ALLOCATOR
 
34 +
template<class Alloc>
 
35 +
using allocator_traits =
 
36 +
    boost::allocator_traits<Alloc>;
 
37 +
#else
 
38 +
template<class Alloc>
 
39 +
using allocator_traits = std::allocator_traits<Alloc>;
 
40 +
#endif
 
41 +

 
42 +
template<class T, class Allocator>
 
43 +
class over_allocator
 
44 +
    : private empty_value<Allocator>
 
45 +
{
 
46 +
    template<class U, class OtherAlloc>
 
47 +
    friend class over_allocator;
 
48 +

 
49 +
    std::size_t extra_;
 
50 +

 
51 +
public:
 
52 +
    using is_always_equal = std::false_type;
 
53 +
    using value_type = typename
 
54 +
        allocator_traits<typename allocator_traits<
 
55 +
            Allocator>::template rebind_alloc<T>>::value_type;
 
56 +
    using pointer = typename
 
57 +
        allocator_traits<typename allocator_traits<
 
58 +
            Allocator>::template rebind_alloc<T>>::pointer;
 
59 +
    using const_pointer = typename
 
60 +
        allocator_traits<typename allocator_traits<
 
61 +
            Allocator>::template rebind_alloc<T>>::const_pointer;
 
62 +
    using size_type = typename
 
63 +
        allocator_traits<typename allocator_traits<
 
64 +
            Allocator>::template rebind_alloc<T>>::size_type;
 
65 +
    using difference_type = typename
 
66 +
        allocator_traits<typename allocator_traits<
 
67 +
            Allocator>::template rebind_alloc<T>>::difference_type;
 
68 +

 
69 +
    template<class U>
 
70 +
    struct rebind
 
71 +
    {
 
72 +
        using other = over_allocator<U, Allocator>;
 
73 +
    };
 
74 +

 
75 +
    over_allocator(
 
76 +
        std::size_t extra,
 
77 +
        Allocator const& alloc)
 
78 +
        : empty_value<Allocator>(
 
79 +
            empty_init, alloc)
 
80 +
        , extra_(extra)
 
81 +
    {
 
82 +
    }
 
83 +

 
84 +
    template<class U>
 
85 +
    over_allocator(over_allocator<U, Allocator> const& other) noexcept
 
86 +
        : empty_value<Allocator>(
 
87 +
            empty_init, other.get())
 
88 +
        , extra_(other.extra_)
 
89 +
    {
 
90 +
    }
 
91 +

 
92 +
    pointer
 
93 +
    allocate(size_type n)
 
94 +
    {
 
95 +
        BOOST_ASSERT(n == 1);
 
96 +
        using U = typename boost::type_with_alignment<
 
97 +
            alignof(value_type)>::type;
 
98 +
        auto constexpr S = sizeof(U);
 
99 +
        using A = typename allocator_traits<
 
100 +
            Allocator>::template rebind_alloc<U>;
 
101 +
        A a(this->get());
 
102 +
        return reinterpret_cast<pointer>(
 
103 +
            std::allocator_traits<A>::allocate(a,
 
104 +
                (n * sizeof(value_type) + extra_ + S - 1) / S));
 
105 +
    }
 
106 +

 
107 +
    void
 
108 +
    deallocate(pointer p, size_type n)
 
109 +
    {
 
110 +
        BOOST_ASSERT(n == 1);
 
111 +
        using U = typename boost::type_with_alignment<
 
112 +
            alignof(value_type)>::type;
 
113 +
        auto constexpr S = sizeof(U);
 
114 +
        using A = typename allocator_traits<
 
115 +
            Allocator>::template rebind_alloc<U>;
 
116 +
        A a{this->get()};
 
117 +
        std::allocator_traits<A>::deallocate(a,
 
118 +
            reinterpret_cast<U*>(p),
 
119 +
                (n * sizeof(value_type) + extra_ + S - 1) / S);
 
120 +
    }
 
121 +

 
122 +
#if defined(BOOST_LIBSTDCXX_VERSION) && BOOST_LIBSTDCXX_VERSION < 60000
 
123 +
    template<class U, class... Args>
 
124 +
    void
 
125 +
    construct(U* ptr, Args&&... args)
 
126 +
    {
 
127 +
        ::new((void*)ptr) U(std::forward<Args>(args)...);
 
128 +
    }
 
129 +

 
130 +
    template<class U>
 
131 +
    void
 
132 +
    destroy(U* ptr)
 
133 +
    {
 
134 +
        ptr->~U();
 
135 +
    }
 
136 +
#endif
 
137 +

 
138 +
    template<class U>
 
139 +
    friend
 
140 +
    bool
 
141 +
    operator==(
 
142 +
        over_allocator const& lhs,
 
143 +
        over_allocator<U, Allocator> const& rhs)
 
144 +
    {
 
145 +
        return
 
146 +
            lhs.get() == rhs.get() &&
 
147 +
            lhs.extra_ == rhs.extra_;
 
148 +
    }
 
149 +

 
150 +
    template<class U>
 
151 +
    friend
 
152 +
    bool
 
153 +
    operator!=(
 
154 +
        over_allocator const& lhs,
 
155 +
        over_allocator<U, Allocator> const& rhs)
 
156 +
    {
 
157 +
        return ! (lhs == rhs);
 
158 +
    }
 
159 +
};
 
160 +

 
161 +
} // detail
 
162 +
} // urls
 
163 +
} // boost
 
164 +

 
165 +
#endif