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 19, 2022
1 parent a511da2 commit 8640a18
Show file tree
Hide file tree
Showing 10 changed files with 1,235 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
119 changes: 119 additions & 0 deletions include/boost/url/any_allocator.hpp
@@ -0,0 +1,119 @@
//
// 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 = std::size_t;
using difference_type = std::ptrdiff_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);

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
250 changes: 250 additions & 0 deletions include/boost/url/detail/any_allocator.hpp
@@ -0,0 +1,250 @@
//
// 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 this->get().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))
this->get().deallocate(
reinterpret_cast<char*>(p),
n);
else
deallocate_aligned(p,
n,
size,
align);
}

bool
is_equal(const base& other) override
{
const impl* other_impl = static_cast<
const impl*>(&other);
return this->get() ==
other_impl->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_alloc_t = boost::
allocator_rebind_t<Allocator,
aligned_t>;
return aligned_alloc_t(
this->get())
.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_alloc_t = boost::
allocator_rebind_t<Allocator,
aligned_t>;
return aligned_alloc_t(
this->get())
.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_alloc_t = boost::allocator_rebind_t<Allocator,
aligned_t>;
aligned_alloc_t(this->get())
.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_alloc_t = boost::
allocator_rebind_t<Allocator,
aligned_t>;
aligned_alloc_t(this->get())
.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 8640a18

Please sign in to comment.