mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-06 16:56:45 +08:00
Reimplement the allocator required for the container type with $new
This commit is contained in:
parent
4e70d6c60b
commit
10c0d14de6
@ -1,5 +1,5 @@
|
||||
/**
|
||||
* \file libipc/polymorphic_allocator
|
||||
* \file libipc/bytes_allocator.h
|
||||
* \author mutouyun (orz@orzz.org)
|
||||
* \brief A generic polymorphic memory allocator.
|
||||
*/
|
||||
@ -50,13 +50,13 @@ using is_memory_resource =
|
||||
* \brief An allocator which exhibits different allocation behavior
|
||||
* depending upon the memory resource from which it is constructed.
|
||||
*
|
||||
* \note Unlike `std::pmr::polymorphic_allocator`, it does not
|
||||
* \note Unlike `std::pmr::container_allocator`, it does not
|
||||
* rely on a specific inheritance relationship and only restricts
|
||||
* the interface behavior of the incoming memory resource object to
|
||||
* conform to `std::pmr::memory_resource`.
|
||||
*
|
||||
* \see https://en.cppreference.com/w/cpp/memory/memory_resource
|
||||
* https://en.cppreference.com/w/cpp/memory/polymorphic_allocator
|
||||
* https://en.cppreference.com/w/cpp/memory/container_allocator
|
||||
*/
|
||||
class LIBIPC_EXPORT bytes_allocator {
|
||||
|
||||
@ -159,88 +159,5 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief An allocator that can be used by all standard library containers,
|
||||
* based on ipc::bytes_allocator.
|
||||
*
|
||||
* \see https://en.cppreference.com/w/cpp/memory/allocator
|
||||
* https://en.cppreference.com/w/cpp/memory/polymorphic_allocator
|
||||
*/
|
||||
template <typename T>
|
||||
class polymorphic_allocator {
|
||||
|
||||
template <typename U>
|
||||
friend class polymorphic_allocator;
|
||||
|
||||
public:
|
||||
// type definitions
|
||||
typedef T value_type;
|
||||
typedef value_type * pointer;
|
||||
typedef const value_type *const_pointer;
|
||||
typedef value_type & reference;
|
||||
typedef const value_type &const_reference;
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
private:
|
||||
bytes_allocator alloc_;
|
||||
|
||||
public:
|
||||
// the other type of std_allocator
|
||||
template <typename U>
|
||||
struct rebind {
|
||||
using other = polymorphic_allocator<U>;
|
||||
};
|
||||
|
||||
polymorphic_allocator() noexcept {}
|
||||
|
||||
template <typename P, is_memory_resource<P> = true>
|
||||
polymorphic_allocator(P *p_mr) noexcept : alloc_(p_mr) {}
|
||||
|
||||
// construct by copying (do nothing)
|
||||
polymorphic_allocator (polymorphic_allocator<T> const &) noexcept {}
|
||||
polymorphic_allocator& operator=(polymorphic_allocator<T> const &) noexcept { return *this; }
|
||||
|
||||
// construct from a related allocator (do nothing)
|
||||
template <typename U> polymorphic_allocator (polymorphic_allocator<U> const &) noexcept {}
|
||||
template <typename U> polymorphic_allocator &operator=(polymorphic_allocator<U> const &) noexcept { return *this; }
|
||||
|
||||
polymorphic_allocator (polymorphic_allocator &&) noexcept = default;
|
||||
polymorphic_allocator& operator=(polymorphic_allocator &&) noexcept = default;
|
||||
|
||||
constexpr size_type max_size(void) const noexcept {
|
||||
return (std::numeric_limits<size_type>::max)() / sizeof(value_type);
|
||||
}
|
||||
|
||||
pointer allocate(size_type count) noexcept {
|
||||
if (count == 0) return nullptr;
|
||||
if (count > this->max_size()) return nullptr;
|
||||
return static_cast<pointer>(alloc_.allocate(count * sizeof(value_type), alignof(T)));
|
||||
}
|
||||
|
||||
void deallocate(pointer p, size_type count) noexcept {
|
||||
alloc_.deallocate(p, count * sizeof(value_type), alignof(T));
|
||||
}
|
||||
|
||||
template <typename... P>
|
||||
static void construct(pointer p, P && ... params) {
|
||||
std::ignore = ipc::construct<T>(p, std::forward<P>(params)...);
|
||||
}
|
||||
|
||||
static void destroy(pointer p) {
|
||||
std::ignore = ipc::destroy(p);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
constexpr bool operator==(polymorphic_allocator<T> const &, polymorphic_allocator<U> const &) noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
constexpr bool operator!=(polymorphic_allocator<T> const &, polymorphic_allocator<U> const &) noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace mem
|
||||
} // namespace ipc
|
||||
@ -6,7 +6,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "libipc/imp/export.h"
|
||||
#include "libipc/mem/polymorphic_allocator.h"
|
||||
#include "libipc/mem/bytes_allocator.h"
|
||||
|
||||
namespace ipc {
|
||||
namespace mem {
|
||||
|
||||
95
include/libipc/mem/container_allocator.h
Normal file
95
include/libipc/mem/container_allocator.h
Normal file
@ -0,0 +1,95 @@
|
||||
/**
|
||||
* \file libipc/container_allocator.h
|
||||
* \author mutouyun (orz@orzz.org)
|
||||
* \brief An allocator that can be used by all standard library containers.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
#include "libipc/imp/uninitialized.h"
|
||||
#include "libipc/mem/new.h"
|
||||
|
||||
namespace ipc {
|
||||
namespace mem {
|
||||
|
||||
/**
|
||||
* \brief An allocator that can be used by all standard library containers.
|
||||
*
|
||||
* \see https://en.cppreference.com/w/cpp/memory/allocator
|
||||
* https://en.cppreference.com/w/cpp/memory/polymorphic_allocator
|
||||
*/
|
||||
template <typename T>
|
||||
class container_allocator {
|
||||
|
||||
template <typename U>
|
||||
friend class container_allocator;
|
||||
|
||||
public:
|
||||
// type definitions
|
||||
typedef T value_type;
|
||||
typedef value_type * pointer;
|
||||
typedef const value_type *const_pointer;
|
||||
typedef value_type & reference;
|
||||
typedef const value_type &const_reference;
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
|
||||
// the other type of std_allocator
|
||||
template <typename U>
|
||||
struct rebind {
|
||||
using other = container_allocator<U>;
|
||||
};
|
||||
|
||||
container_allocator() noexcept {}
|
||||
|
||||
// construct by copying (do nothing)
|
||||
container_allocator (container_allocator<T> const &) noexcept {}
|
||||
container_allocator& operator=(container_allocator<T> const &) noexcept { return *this; }
|
||||
|
||||
// construct from a related allocator (do nothing)
|
||||
template <typename U> container_allocator (container_allocator<U> const &) noexcept {}
|
||||
template <typename U> container_allocator &operator=(container_allocator<U> const &) noexcept { return *this; }
|
||||
|
||||
container_allocator (container_allocator &&) noexcept = default;
|
||||
container_allocator& operator=(container_allocator &&) noexcept = default;
|
||||
|
||||
constexpr size_type max_size() const noexcept {
|
||||
return 1;
|
||||
}
|
||||
|
||||
pointer allocate(size_type count) noexcept {
|
||||
if (count == 0) return nullptr;
|
||||
if (count > this->max_size()) return nullptr;
|
||||
return mem::$new<value_type>();
|
||||
}
|
||||
|
||||
void deallocate(pointer p, size_type count) noexcept {
|
||||
if (count == 0) return;
|
||||
if (count > this->max_size()) return;
|
||||
mem::$delete(p);
|
||||
}
|
||||
|
||||
template <typename... P>
|
||||
static void construct(pointer p, P && ... params) {
|
||||
std::ignore = ipc::construct<T>(p, std::forward<P>(params)...);
|
||||
}
|
||||
|
||||
static void destroy(pointer p) {
|
||||
std::ignore = ipc::destroy(p);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
constexpr bool operator==(container_allocator<T> const &, container_allocator<U> const &) noexcept {
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T, typename U>
|
||||
constexpr bool operator!=(container_allocator<T> const &, container_allocator<U> const &) noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace mem
|
||||
} // namespace ipc
|
||||
@ -11,7 +11,7 @@
|
||||
#include "libipc/imp/export.h"
|
||||
#include "libipc/imp/span.h"
|
||||
#include "libipc/imp/byte.h"
|
||||
#include "libipc/mem/polymorphic_allocator.h"
|
||||
#include "libipc/mem/bytes_allocator.h"
|
||||
|
||||
namespace ipc {
|
||||
namespace mem {
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
#include <algorithm> // std::swap
|
||||
|
||||
#include "libipc/imp/log.h"
|
||||
#include "libipc/mem/polymorphic_allocator.h"
|
||||
#include "libipc/mem/bytes_allocator.h"
|
||||
#include "libipc/mem/memory_resource.h"
|
||||
|
||||
namespace ipc {
|
||||
@ -6,7 +6,7 @@
|
||||
#include "libipc/def.h"
|
||||
#include "libipc/imp/detect_plat.h"
|
||||
#include "libipc/imp/byte.h"
|
||||
#include "libipc/mem/polymorphic_allocator.h"
|
||||
#include "libipc/mem/bytes_allocator.h"
|
||||
#include "libipc/mem/memory_resource.h"
|
||||
|
||||
namespace ipc {
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
#include "libipc/def.h"
|
||||
#include "libipc/imp/fmt.h"
|
||||
#include "libipc/mem/polymorphic_allocator.h"
|
||||
#include "libipc/mem/container_allocator.h"
|
||||
|
||||
namespace ipc {
|
||||
|
||||
@ -15,12 +15,12 @@ struct hash : public std::hash<T> {};
|
||||
|
||||
template <typename Key, typename T>
|
||||
using unordered_map = std::unordered_map<
|
||||
Key, T, ipc::hash<Key>, std::equal_to<Key>, ipc::mem::polymorphic_allocator<std::pair<Key const, T>>
|
||||
Key, T, ipc::hash<Key>, std::equal_to<Key>, ipc::mem::container_allocator<std::pair<Key const, T>>
|
||||
>;
|
||||
|
||||
template <typename Key, typename T>
|
||||
using map = std::map<
|
||||
Key, T, std::less<Key>, ipc::mem::polymorphic_allocator<std::pair<Key const, T>>
|
||||
Key, T, std::less<Key>, ipc::mem::container_allocator<std::pair<Key const, T>>
|
||||
>;
|
||||
|
||||
/// \brief Check string validity.
|
||||
|
||||
@ -8,15 +8,15 @@
|
||||
# include <memory_resource>
|
||||
#endif
|
||||
|
||||
#include "libipc/mem/polymorphic_allocator.h"
|
||||
#include "libipc/mem/bytes_allocator.h"
|
||||
#include "libipc/mem/memory_resource.h"
|
||||
|
||||
TEST(polymorphic_allocator, ctor) {
|
||||
TEST(bytes_allocator, ctor) {
|
||||
ipc::mem::bytes_allocator alc;
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST(polymorphic_allocator, ctor_value_initialization) {
|
||||
TEST(bytes_allocator, ctor_value_initialization) {
|
||||
ipc::mem::bytes_allocator alc{};
|
||||
auto p = alc.allocate(128);
|
||||
EXPECT_NE(p, nullptr);
|
||||
@ -37,14 +37,14 @@ public:
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(polymorphic_allocator, memory_resource_traits) {
|
||||
TEST(bytes_allocator, memory_resource_traits) {
|
||||
EXPECT_FALSE(ipc::mem::has_allocate<void>::value);
|
||||
EXPECT_FALSE(ipc::mem::has_allocate<int>::value);
|
||||
EXPECT_FALSE(ipc::mem::has_allocate<std::vector<int>>::value);
|
||||
EXPECT_FALSE(ipc::mem::has_allocate<std::allocator<int>>::value);
|
||||
#if defined(LIBIMP_CPP_17) && defined(__cpp_lib_memory_resource)
|
||||
EXPECT_TRUE (ipc::mem::has_allocate<std::ipc::mem::memory_resource>::value);
|
||||
EXPECT_TRUE (ipc::mem::has_allocate<std::ipc::mem::polymorphic_allocator<int>>::value);
|
||||
EXPECT_TRUE (ipc::mem::has_allocate<std::ipc::mem::container_allocator<int>>::value);
|
||||
#endif
|
||||
|
||||
EXPECT_FALSE(ipc::mem::has_deallocate<void>::value);
|
||||
@ -53,11 +53,11 @@ TEST(polymorphic_allocator, memory_resource_traits) {
|
||||
EXPECT_FALSE(ipc::mem::has_deallocate<std::allocator<int>>::value);
|
||||
#if defined(LIBIMP_CPP_17) && defined(__cpp_lib_memory_resource)
|
||||
EXPECT_TRUE (ipc::mem::has_deallocate<std::ipc::mem::memory_resource>::value);
|
||||
EXPECT_FALSE(ipc::mem::has_deallocate<std::ipc::mem::polymorphic_allocator<int>>::value);
|
||||
EXPECT_FALSE(ipc::mem::has_deallocate<std::ipc::mem::container_allocator<int>>::value);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(polymorphic_allocator, ctor_copy_move) {
|
||||
TEST(bytes_allocator, ctor_copy_move) {
|
||||
ipc::mem::new_delete_resource mem_res;
|
||||
dummy_resource dummy_res;
|
||||
ipc::mem::bytes_allocator alc1{&mem_res}, alc2{&dummy_res};
|
||||
@ -79,7 +79,7 @@ TEST(polymorphic_allocator, ctor_copy_move) {
|
||||
ASSERT_NO_THROW(alc5.deallocate(p, 128));
|
||||
}
|
||||
|
||||
TEST(polymorphic_allocator, swap) {
|
||||
TEST(bytes_allocator, swap) {
|
||||
ipc::mem::new_delete_resource mem_res;
|
||||
dummy_resource dummy_res;
|
||||
ipc::mem::bytes_allocator alc1{&mem_res}, alc2{&dummy_res};
|
||||
@ -90,7 +90,7 @@ TEST(polymorphic_allocator, swap) {
|
||||
ASSERT_EQ(alc1.allocate(128), nullptr);
|
||||
}
|
||||
|
||||
TEST(polymorphic_allocator, invalid_alloc_free) {
|
||||
TEST(bytes_allocator, invalid_alloc_free) {
|
||||
ipc::mem::bytes_allocator alc1;
|
||||
EXPECT_EQ(alc1.allocate(0), nullptr);
|
||||
EXPECT_NO_THROW(alc1.deallocate(nullptr, 128));
|
||||
@ -98,6 +98,6 @@ TEST(polymorphic_allocator, invalid_alloc_free) {
|
||||
EXPECT_NO_THROW(alc1.deallocate(&alc1, 0));
|
||||
}
|
||||
|
||||
TEST(polymorphic_allocator, sizeof) {
|
||||
TEST(bytes_allocator, sizeof) {
|
||||
EXPECT_EQ(sizeof(ipc::mem::bytes_allocator), sizeof(void *) * 2);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user