Skip to content

Commit

Permalink
add any_allocator
Browse files Browse the repository at this point in the history
  • Loading branch information
alandefreitas committed Jan 18, 2022
1 parent cbd0ad6 commit c00ae2f
Show file tree
Hide file tree
Showing 9 changed files with 1,200 additions and 2 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Expand Up @@ -64,6 +64,7 @@ function(boost_url_setup_properties target)
Boost::align
Boost::assert
Boost::config
Boost::core
Boost::exception
Boost::mp11
Boost::system
Expand Down
1 change: 1 addition & 0 deletions doc/qbk/quickref.xml
Expand Up @@ -25,6 +25,7 @@
<entry valign="top">
<bridgehead renderas="sect3">Classes</bridgehead>
<simplelist type="vert" columns="1">
<member><link linkend="url.ref.boost__urls__any_allocator">any_allocator</link></member>
<member><link linkend="url.ref.boost__urls__authority_view">authority_view</link></member>
<member><link linkend="url.ref.boost__urls__ipv4_address">ipv4_address</link></member>
<member><link linkend="url.ref.boost__urls__ipv6_address">ipv6_address</link></member>
Expand Down
126 changes: 126 additions & 0 deletions include/boost/url/any_allocator.hpp
@@ -0,0 +1,126 @@
//
// Copyright (c) 2022 Alan Freitas (alandefreitas@gmail.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/CPPAlliance/url
//

#ifndef BOOST_URL_ANY_ALLOCATOR_HPP
#define BOOST_URL_ANY_ALLOCATOR_HPP

#include <boost/url/detail/config.hpp>
#include <boost/url/detail/any_allocator.hpp>

#include <memory>
#include <type_traits>

namespace boost {
namespace urls {

/** A type-erased allocator with shared ownership.
This type satisfies the requirements for
<em>Allocator</em>
@par Specification
@li <a
href="https://en.cppreference.com/w/cpp/named_req/Allocator"
>Allocator (cppreference.com)</a>
*/
#ifdef BOOST_URL_DOCS
template <class T>
using any_allocator = __see_below__;
#else
template <class T>
class any_allocator
: private detail::any_allocator_base
{
std::shared_ptr<base> p_;

template <class U>
friend class any_allocator;

public:
using value_type = T;

using size_type = boost::
allocator_size_type_t<any_allocator<T>>;

using difference_type =
allocator_difference_type_t<
any_allocator<T>>;

using reference = value_type&;

using const_reference = value_type const&;

using pointer = value_type*;

using const_pointer = value_type const*;

template <class U>
struct rebind
{
using other = any_allocator<U>;
};

using is_always_equal = std::false_type;

#ifndef BOOST_URL_NO_GCC_4_2_WORKAROUND
any_allocator() = default;
#endif

any_allocator(any_allocator const&) = default;

template <class U>
explicit any_allocator(
any_allocator<U> const& other) noexcept;

template <class Allocator>
explicit any_allocator(Allocator const& a);

any_allocator&
operator=(any_allocator const&) = default;

T*
allocate(std::size_t n) const;

void
deallocate(T* p, std::size_t n);

template <class U, class... Args>
void
construct(U* p, Args&&... args);

template< class U >
void destroy( U* p );

friend bool
operator==(const any_allocator& a,
const any_allocator& b) noexcept
{
return (a.p_ == b.p_) ||
(a.p_ != nullptr
&& b.p_ != nullptr &&
(a.p_->type_id == b.p_->type_id &&
a.p_->is_equal(*b.p_)));
}

friend bool
operator!=(const any_allocator& a,
const any_allocator& b) noexcept
{
return !(a == b);
}
};
#endif

} // namespace urls
} // namespace boost

#include <boost/url/impl/any_allocator.hpp>

#endif
251 changes: 251 additions & 0 deletions include/boost/url/detail/any_allocator.hpp
@@ -0,0 +1,251 @@
//
// Copyright (c) 2022 Alan Freitas (alandefreitas@gmail.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/CPPAlliance/url
//


#ifndef BOOST_URL_DETAIL_ANY_ALLOCATOR_HPP
#define BOOST_URL_DETAIL_ANY_ALLOCATOR_HPP

#include <boost/url/detail/type_id.hpp>

#include <boost/core/allocator_access.hpp>
#include <boost/core/empty_value.hpp>
#include <boost/type_traits/type_with_alignment.hpp>

#include <cstddef>

namespace boost {
namespace urls {
namespace detail {

struct any_allocator_base
{
struct base
{
type_id_t type_id;

virtual ~base() = default;

virtual void*
allocate(std::size_t n,
std::size_t size,
std::size_t align) = 0;

virtual void
deallocate(void* p,
std::size_t n,
std::size_t size,
std::size_t align) = 0;

virtual bool
is_equal(const any_allocator_base::base&
p) = 0;
};

template <typename Allocator>
struct impl
: public base
, private empty_value<
boost::allocator_rebind_t<Allocator,
char>,
0>
{
using allocator_type = boost::
allocator_rebind_t<Allocator, char>;

explicit impl(allocator_type const& a)
: empty_value<allocator_type, 0>(
empty_init_t(), a)
{
type_id = get_type_id<allocator_type>();
}

void*
allocate(std::size_t n,
std::size_t size,
std::size_t align) override
{
if(align == 1)
return allocator().allocate(n);
else
return allocate_aligned(
n, size, align);
}

void
deallocate(void* p,
std::size_t n,
std::size_t size,
std::size_t align) override
{
if(align == alignof(char))
allocator().deallocate(
reinterpret_cast<char*>(p),
n);
else
deallocate_aligned(
p, n, size, align);
}

bool
is_equal(
const any_allocator_base::base& other)
override
{
const impl* other_impl = static_cast<
const impl*>(&other);
return allocator() ==
other_impl->allocator();
};

const allocator_type&
allocator() const
{
return empty_value<allocator_type,
0>::get();
}

allocator_type&
allocator()
{
return empty_value<allocator_type,
0>::get();
}

#if BOOST_WORKAROUND(BOOST_GCC, < 40900)
using max_align_t = ::max_align_t;
#else
using max_align_t = std::max_align_t;
#endif

static std::size_t
ceil_div(std::size_t n, std::size_t d)
{
return (n + d - 1) / d;
}

template <std::size_t N>
typename std::enable_if<
alignof(max_align_t) <= N,
void*>::type
try_allocate_aligned(std::size_t n,
std::size_t size,
std::size_t align)
{
using aligned_t = max_align_t;
using aligned_allocator_t = boost::
allocator_rebind_t<Allocator,
aligned_t>;
return aligned_allocator_t(
allocator())
.allocate(
n * ceil_div(size, align));
}

template <std::size_t N>
typename std::enable_if <
N< alignof(max_align_t), void*>::type
try_allocate_aligned(std::size_t n,
std::size_t size,
std::size_t align)
{
if(align <= N)
{
using aligned_t = typename boost::
type_with_alignment<N>::type;
using aligned_allocator_t = boost::
allocator_rebind_t<Allocator,
aligned_t>;
return aligned_allocator_t(
allocator())
.allocate(n *
ceil_div(size, align));
}
else
{
return try_allocate_aligned<2 *
N>(n, size, align);
}
}

void*
allocate_aligned(std::size_t n,
std::size_t size,
std::size_t align)
{
return try_allocate_aligned<2>(
n, size, align);
}


template <std::size_t N>
typename std::enable_if<
alignof(max_align_t) <= N,
void>::type
try_deallocate_aligned(void* p,
std::size_t n,
std::size_t size,
std::size_t align)
{
using aligned_t = max_align_t;
using aligned_allocator_t = boost::
allocator_rebind_t<Allocator,
aligned_t>;
aligned_allocator_t(allocator())
.deallocate(
reinterpret_cast<aligned_t*>(
p),
n * ceil_div(size, align));
}

template <std::size_t N>
typename std::enable_if <
N< alignof(max_align_t), void>::type
try_deallocate_aligned(void* p,
std::size_t n,
std::size_t size,
std::size_t align)
{
if(align <= N)
{
using aligned_t = typename boost::
type_with_alignment<N>::type;
using aligned_allocator_t = boost::
allocator_rebind_t<Allocator,
aligned_t>;
aligned_allocator_t(allocator())
.deallocate(
reinterpret_cast<
aligned_t*>(p),
n * ceil_div(size, align));
}
else
{
try_deallocate_aligned<2 * N>(
p, n, size, align);
}
}

void
deallocate_aligned(void* p,
std::size_t n,
std::size_t size,
std::size_t align)
{
try_deallocate_aligned<2>(
p, n, size, align);
}
};
};

} // namespace detail
} // namespace urls
} // namespace boost


#endif

0 comments on commit c00ae2f

Please sign in to comment.