mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-07 01:06: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)
|
* \author mutouyun (orz@orzz.org)
|
||||||
* \brief A generic polymorphic memory allocator.
|
* \brief A generic polymorphic memory allocator.
|
||||||
*/
|
*/
|
||||||
@ -50,13 +50,13 @@ using is_memory_resource =
|
|||||||
* \brief An allocator which exhibits different allocation behavior
|
* \brief An allocator which exhibits different allocation behavior
|
||||||
* depending upon the memory resource from which it is constructed.
|
* 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
|
* rely on a specific inheritance relationship and only restricts
|
||||||
* the interface behavior of the incoming memory resource object to
|
* the interface behavior of the incoming memory resource object to
|
||||||
* conform to `std::pmr::memory_resource`.
|
* conform to `std::pmr::memory_resource`.
|
||||||
*
|
*
|
||||||
* \see https://en.cppreference.com/w/cpp/memory/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 {
|
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 mem
|
||||||
} // namespace ipc
|
} // namespace ipc
|
||||||
@ -6,7 +6,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "libipc/imp/export.h"
|
#include "libipc/imp/export.h"
|
||||||
#include "libipc/mem/polymorphic_allocator.h"
|
#include "libipc/mem/bytes_allocator.h"
|
||||||
|
|
||||||
namespace ipc {
|
namespace ipc {
|
||||||
namespace mem {
|
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/export.h"
|
||||||
#include "libipc/imp/span.h"
|
#include "libipc/imp/span.h"
|
||||||
#include "libipc/imp/byte.h"
|
#include "libipc/imp/byte.h"
|
||||||
#include "libipc/mem/polymorphic_allocator.h"
|
#include "libipc/mem/bytes_allocator.h"
|
||||||
|
|
||||||
namespace ipc {
|
namespace ipc {
|
||||||
namespace mem {
|
namespace mem {
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
#include <algorithm> // std::swap
|
#include <algorithm> // std::swap
|
||||||
|
|
||||||
#include "libipc/imp/log.h"
|
#include "libipc/imp/log.h"
|
||||||
#include "libipc/mem/polymorphic_allocator.h"
|
#include "libipc/mem/bytes_allocator.h"
|
||||||
#include "libipc/mem/memory_resource.h"
|
#include "libipc/mem/memory_resource.h"
|
||||||
|
|
||||||
namespace ipc {
|
namespace ipc {
|
||||||
@ -6,7 +6,7 @@
|
|||||||
#include "libipc/def.h"
|
#include "libipc/def.h"
|
||||||
#include "libipc/imp/detect_plat.h"
|
#include "libipc/imp/detect_plat.h"
|
||||||
#include "libipc/imp/byte.h"
|
#include "libipc/imp/byte.h"
|
||||||
#include "libipc/mem/polymorphic_allocator.h"
|
#include "libipc/mem/bytes_allocator.h"
|
||||||
#include "libipc/mem/memory_resource.h"
|
#include "libipc/mem/memory_resource.h"
|
||||||
|
|
||||||
namespace ipc {
|
namespace ipc {
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#include "libipc/def.h"
|
#include "libipc/def.h"
|
||||||
#include "libipc/imp/fmt.h"
|
#include "libipc/imp/fmt.h"
|
||||||
#include "libipc/mem/polymorphic_allocator.h"
|
#include "libipc/mem/container_allocator.h"
|
||||||
|
|
||||||
namespace ipc {
|
namespace ipc {
|
||||||
|
|
||||||
@ -15,12 +15,12 @@ struct hash : public std::hash<T> {};
|
|||||||
|
|
||||||
template <typename Key, typename T>
|
template <typename Key, typename T>
|
||||||
using unordered_map = std::unordered_map<
|
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>
|
template <typename Key, typename T>
|
||||||
using map = std::map<
|
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.
|
/// \brief Check string validity.
|
||||||
|
|||||||
@ -8,15 +8,15 @@
|
|||||||
# include <memory_resource>
|
# include <memory_resource>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "libipc/mem/polymorphic_allocator.h"
|
#include "libipc/mem/bytes_allocator.h"
|
||||||
#include "libipc/mem/memory_resource.h"
|
#include "libipc/mem/memory_resource.h"
|
||||||
|
|
||||||
TEST(polymorphic_allocator, ctor) {
|
TEST(bytes_allocator, ctor) {
|
||||||
ipc::mem::bytes_allocator alc;
|
ipc::mem::bytes_allocator alc;
|
||||||
SUCCEED();
|
SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(polymorphic_allocator, ctor_value_initialization) {
|
TEST(bytes_allocator, ctor_value_initialization) {
|
||||||
ipc::mem::bytes_allocator alc{};
|
ipc::mem::bytes_allocator alc{};
|
||||||
auto p = alc.allocate(128);
|
auto p = alc.allocate(128);
|
||||||
EXPECT_NE(p, nullptr);
|
EXPECT_NE(p, nullptr);
|
||||||
@ -37,14 +37,14 @@ public:
|
|||||||
|
|
||||||
} // namespace
|
} // 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<void>::value);
|
||||||
EXPECT_FALSE(ipc::mem::has_allocate<int>::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::vector<int>>::value);
|
||||||
EXPECT_FALSE(ipc::mem::has_allocate<std::allocator<int>>::value);
|
EXPECT_FALSE(ipc::mem::has_allocate<std::allocator<int>>::value);
|
||||||
#if defined(LIBIMP_CPP_17) && defined(__cpp_lib_memory_resource)
|
#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::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
|
#endif
|
||||||
|
|
||||||
EXPECT_FALSE(ipc::mem::has_deallocate<void>::value);
|
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);
|
EXPECT_FALSE(ipc::mem::has_deallocate<std::allocator<int>>::value);
|
||||||
#if defined(LIBIMP_CPP_17) && defined(__cpp_lib_memory_resource)
|
#if defined(LIBIMP_CPP_17) && defined(__cpp_lib_memory_resource)
|
||||||
EXPECT_TRUE (ipc::mem::has_deallocate<std::ipc::mem::memory_resource>::value);
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(polymorphic_allocator, ctor_copy_move) {
|
TEST(bytes_allocator, ctor_copy_move) {
|
||||||
ipc::mem::new_delete_resource mem_res;
|
ipc::mem::new_delete_resource mem_res;
|
||||||
dummy_resource dummy_res;
|
dummy_resource dummy_res;
|
||||||
ipc::mem::bytes_allocator alc1{&mem_res}, alc2{&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));
|
ASSERT_NO_THROW(alc5.deallocate(p, 128));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(polymorphic_allocator, swap) {
|
TEST(bytes_allocator, swap) {
|
||||||
ipc::mem::new_delete_resource mem_res;
|
ipc::mem::new_delete_resource mem_res;
|
||||||
dummy_resource dummy_res;
|
dummy_resource dummy_res;
|
||||||
ipc::mem::bytes_allocator alc1{&mem_res}, alc2{&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);
|
ASSERT_EQ(alc1.allocate(128), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(polymorphic_allocator, invalid_alloc_free) {
|
TEST(bytes_allocator, invalid_alloc_free) {
|
||||||
ipc::mem::bytes_allocator alc1;
|
ipc::mem::bytes_allocator alc1;
|
||||||
EXPECT_EQ(alc1.allocate(0), nullptr);
|
EXPECT_EQ(alc1.allocate(0), nullptr);
|
||||||
EXPECT_NO_THROW(alc1.deallocate(nullptr, 128));
|
EXPECT_NO_THROW(alc1.deallocate(nullptr, 128));
|
||||||
@ -98,6 +98,6 @@ TEST(polymorphic_allocator, invalid_alloc_free) {
|
|||||||
EXPECT_NO_THROW(alc1.deallocate(&alc1, 0));
|
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);
|
EXPECT_EQ(sizeof(ipc::mem::bytes_allocator), sizeof(void *) * 2);
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user