mirror of
https://github.com/mutouyun/cpp-ipc.git
synced 2025-12-06 16:56:45 +08:00
add: [pmr] new_delete_resource & ut
This commit is contained in:
parent
15d89aed5c
commit
6bd967323d
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file libconcur/concurrent.h
|
||||
* @author mutouyun (orz@orzz.org)
|
||||
* @brief Define different policies for concurrent queue
|
||||
* @brief Define different policies for concurrent queue.
|
||||
* @date 2022-11-07
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file libconcur/def.h
|
||||
* @author mutouyun (orz@orzz.org)
|
||||
* @brief Define the trivial configuration information for concurrency
|
||||
* @brief Define the trivial configuration information for concurrency.
|
||||
* @date 2022-11-07
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file libimp/byte.h
|
||||
* @author mutouyun (orz@orzz.org)
|
||||
* @brief Define the byte type
|
||||
* @brief Define the byte type.
|
||||
* @date 2022-11-12
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file libimp/def.h
|
||||
* @author mutouyun (orz@orzz.org)
|
||||
* @brief Define the trivial configuration information
|
||||
* @brief Define the trivial configuration information.
|
||||
* @date 2022-04-23
|
||||
*/
|
||||
#pragma once
|
||||
@ -15,6 +15,6 @@
|
||||
|
||||
LIBIMP_NAMESPACE_BEG_
|
||||
|
||||
// constants
|
||||
/// @brief Constants.
|
||||
|
||||
LIBIMP_NAMESPACE_END_
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
/**
|
||||
* @file libimp/detect_plat.h
|
||||
* @author mutouyun (orz@orzz.org)
|
||||
* @brief Define platform detection related interfaces
|
||||
* @brief Define platform detection related interfaces.
|
||||
* @date 2022-02-27
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
// OS
|
||||
/// @brief OS check.
|
||||
|
||||
#if defined(WINCE) || defined(_WIN32_WCE)
|
||||
# define LIBIMP_OS_WINCE
|
||||
@ -35,7 +35,7 @@
|
||||
# define LIBIMP_OS_WIN
|
||||
#endif
|
||||
|
||||
// Compiler
|
||||
/// @brief Compiler check.
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
# define LIBIMP_CC_MSVC _MSC_VER
|
||||
@ -48,8 +48,8 @@
|
||||
# error "This compiler is unsupported."
|
||||
#endif
|
||||
|
||||
// Instruction set
|
||||
// @see https://sourceforge.net/p/predef/wiki/Architectures/
|
||||
/// @brief Instruction set.
|
||||
/// @see https://sourceforge.net/p/predef/wiki/Architectures/
|
||||
|
||||
#if defined(_M_X64) || defined(_M_AMD64) || \
|
||||
defined(__x86_64__) || defined(__x86_64) || \
|
||||
@ -74,7 +74,7 @@
|
||||
# define LIBIMP_INSTR_ARM
|
||||
#endif
|
||||
|
||||
// Byte order
|
||||
/// @brief Byte order.
|
||||
|
||||
#if defined(__BYTE_ORDER__)
|
||||
# define LIBIMP_ENDIAN_BIG (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||
@ -84,7 +84,7 @@
|
||||
# define LIBIMP_ENDIAN_LIT (1)
|
||||
#endif
|
||||
|
||||
// C++ version
|
||||
/// @brief C++ version.
|
||||
|
||||
#if (__cplusplus >= 202002L) && !defined(LIBIMP_CPP_20)
|
||||
# define LIBIMP_CPP_20
|
||||
@ -102,7 +102,7 @@
|
||||
# error "This C++ version is unsupported."
|
||||
#endif
|
||||
|
||||
// C++ attributes
|
||||
/// @brief C++ attributes.
|
||||
|
||||
#if defined(__has_cpp_attribute)
|
||||
# if __has_cpp_attribute(fallthrough)
|
||||
@ -117,6 +117,9 @@
|
||||
# if __has_cpp_attribute(unlikely)
|
||||
# define LIBIMP_UNLIKELY(...) (__VA_ARGS__) [[unlikely]]
|
||||
# endif
|
||||
# if __has_cpp_attribute(nodiscard)
|
||||
# define LIBIMP_NODISCARD [[nodiscard]]
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(LIBIMP_FALLTHROUGH)
|
||||
@ -160,3 +163,28 @@
|
||||
#if !defined(LIBIMP_UNLIKELY)
|
||||
# define LIBIMP_UNLIKELY(...) (__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#if !defined(LIBIMP_NODISCARD)
|
||||
/// @see https://stackoverflow.com/questions/4226308/msvc-equivalent-of-attribute-warn-unused-result
|
||||
# if defined(LIBIMP_CC_GNUC) && (LIBIMP_CC_GNUC >= 4)
|
||||
# define LIBIMP_NODISCARD __attribute__((warn_unused_result))
|
||||
# elif defined(LIBIMP_CC_MSVC) && (LIBIMP_CC_MSVC >= 1700)
|
||||
# define LIBIMP_NODISCARD _Check_return_
|
||||
# else
|
||||
# define LIBIMP_NODISCARD
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/// @see https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_exceptions.html
|
||||
/// https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros
|
||||
/// https://stackoverflow.com/questions/6487013/programmatically-determine-whether-exceptions-are-enabled
|
||||
#if defined(__cpp_exceptions) && __cpp_exceptions || \
|
||||
defined(__EXCEPTIONS) || defined(_CPPUNWIND)
|
||||
# define LIBIMP_TRY try
|
||||
# define LIBIMP_CATCH(...) catch(__VA_ARGS__)
|
||||
# define LIBIMP_THROW(...) throw __VA_ARGS__
|
||||
#else
|
||||
# define LIBIMP_TRY if (true)
|
||||
# define LIBIMP_CATCH(...) else if (false)
|
||||
# define LIBIMP_THROW(...)
|
||||
#endif
|
||||
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @file libipc/def.h
|
||||
* @author mutouyun (orz@orzz.org)
|
||||
* @brief Define the trivial configuration information
|
||||
* @brief Define the trivial configuration information.
|
||||
* @date 2022-02-27
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
28
include/libpmr/allocator.h
Normal file
28
include/libpmr/allocator.h
Normal file
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @file libpmr/allocator.h
|
||||
* @author mutouyun (orz@orzz.org)
|
||||
* @brief A generic polymorphic memory allocator.
|
||||
* @date 2022-11-13
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "libpmr/def.h"
|
||||
#include "libpmr/memory_resource.h"
|
||||
|
||||
LIBPMR_NAMESPACE_BEG_
|
||||
|
||||
/**
|
||||
* @brief An allocator which exhibits different allocation behavior
|
||||
* depending upon the memory resource from which it is constructed.
|
||||
*
|
||||
* @remarks Unlike std::pmr::polymorphic_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
|
||||
*/
|
||||
|
||||
|
||||
LIBPMR_NAMESPACE_END_
|
||||
17
include/libpmr/def.h
Normal file
17
include/libpmr/def.h
Normal file
@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @file libpmr/def.h
|
||||
* @author mutouyun (orz@orzz.org)
|
||||
* @brief Define the trivial configuration information for memory resources.
|
||||
* @date 2022-11-13
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#define LIBPMR_ pmr
|
||||
#define LIBPMR_NAMESPACE_BEG_ namespace LIBPMR_ {
|
||||
#define LIBPMR_NAMESPACE_END_ }
|
||||
|
||||
LIBPMR_NAMESPACE_BEG_
|
||||
|
||||
/// @brief Constants.
|
||||
|
||||
LIBPMR_NAMESPACE_END_
|
||||
34
include/libpmr/memory_resource.h
Normal file
34
include/libpmr/memory_resource.h
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @file libpmr/memory_resource.h
|
||||
* @author mutouyun (orz@orzz.org)
|
||||
* @brief Implement memory allocation strategies that can be used by pmr::allocator.
|
||||
* @date 2022-11-13
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <cstddef> // std::size_t
|
||||
|
||||
#include "libimp/export.h"
|
||||
#include "libpmr/def.h"
|
||||
|
||||
LIBPMR_NAMESPACE_BEG_
|
||||
|
||||
/**
|
||||
* @brief A memory resource that uses the
|
||||
* global operator new and operator delete to allocate memory.
|
||||
*
|
||||
* @see https://en.cppreference.com/w/cpp/memory/new_delete_resource
|
||||
*/
|
||||
class LIBIMP_EXPORT new_delete_resource {
|
||||
public:
|
||||
/// @brief Allocates storage with a size of at least bytes bytes, aligned to the specified alignment.
|
||||
/// @remark Returns nullptr if storage of the requested size and alignment cannot be obtained.
|
||||
/// @see https://en.cppreference.com/w/cpp/memory/memory_resource/do_allocate
|
||||
void *do_allocate(std::size_t bytes, std::size_t alignment) noexcept;
|
||||
|
||||
/// @brief Deallocates the storage pointed to by p.
|
||||
/// @see https://en.cppreference.com/w/cpp/memory/memory_resource/deallocate
|
||||
void do_deallocate(void* p, std::size_t bytes, std::size_t alignment) noexcept;
|
||||
};
|
||||
|
||||
LIBPMR_NAMESPACE_END_
|
||||
@ -1,3 +1,4 @@
|
||||
|
||||
add_subdirectory(libimp)
|
||||
add_subdirectory(libpmr)
|
||||
add_subdirectory(libipc)
|
||||
|
||||
32
src/libpmr/CMakeLists.txt
Normal file
32
src/libpmr/CMakeLists.txt
Normal file
@ -0,0 +1,32 @@
|
||||
project(pmr)
|
||||
|
||||
if(NOT MSVC)
|
||||
add_compile_options(
|
||||
-Wno-attributes)
|
||||
endif()
|
||||
|
||||
aux_source_directory(${LIBIPC_PROJECT_DIR}/src/libpmr SRC_FILES)
|
||||
|
||||
file(GLOB HEAD_FILES
|
||||
${LIBIPC_PROJECT_DIR}/include/libpmr/*.h)
|
||||
|
||||
add_library(${PROJECT_NAME} STATIC ${SRC_FILES} ${HEAD_FILES})
|
||||
|
||||
# set output directory
|
||||
set_target_properties(${PROJECT_NAME}
|
||||
PROPERTIES
|
||||
ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib"
|
||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
||||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PUBLIC ${LIBIPC_PROJECT_DIR}/include
|
||||
PRIVATE ${LIBIPC_PROJECT_DIR}/src)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC imp)
|
||||
|
||||
install(
|
||||
TARGETS ${PROJECT_NAME}
|
||||
RUNTIME DESTINATION bin
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib)
|
||||
117
src/libpmr/memory_resource.cpp
Normal file
117
src/libpmr/memory_resource.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
|
||||
#include <cstdlib> // std::aligned_alloc
|
||||
#include <cstddef> // std::max_align_t
|
||||
#include <exception>
|
||||
|
||||
#include "libimp/detect_plat.h"
|
||||
#include "libimp/system.h"
|
||||
#include "libimp/log.h"
|
||||
|
||||
#include "libpmr/memory_resource.h"
|
||||
|
||||
LIBPMR_NAMESPACE_BEG_
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* @brief Check that bytes is not 0 and that the alignment is a power of two.
|
||||
*/
|
||||
bool verify_args(::LIBIMP_::log::gripper &log, std::size_t bytes, std::size_t alignment) noexcept {
|
||||
if (bytes == 0) {
|
||||
return false;
|
||||
}
|
||||
if ((alignment == 0) || (alignment & (alignment - 1)) != 0) {
|
||||
log.error("invalid bytes = {}, alignment = {}", bytes, alignment);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/**
|
||||
* @brief Allocates storage with a size of at least bytes bytes, aligned to the specified alignment.
|
||||
* @remark Alignment shall be a power of two.
|
||||
*
|
||||
* @see https://en.cppreference.com/w/cpp/memory/memory_resource/do_allocate
|
||||
* https://www.cppstories.com/2019/08/newnew-align/
|
||||
*
|
||||
* @return void * - nullptr if storage of the requested size and alignment cannot be obtained.
|
||||
*/
|
||||
void *new_delete_resource::do_allocate(std::size_t bytes, std::size_t alignment) noexcept {
|
||||
LIBIMP_LOG_();
|
||||
if (!verify_args(log, bytes, alignment)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (alignment <= alignof(std::max_align_t)) {
|
||||
/// @see https://en.cppreference.com/w/cpp/memory/c/malloc
|
||||
return std::malloc(bytes);
|
||||
}
|
||||
#if defined(LIBIMP_CPP_17)
|
||||
LIBIMP_TRY {
|
||||
/// @see https://en.cppreference.com/w/cpp/memory/c/aligned_alloc
|
||||
return std::aligned_alloc(alignment, bytes);
|
||||
} LIBIMP_CATCH(std::exception const &e) {
|
||||
log.error("std::aligned_alloc(alignment = {}, bytes = {}) fails. error = {}",
|
||||
alignment, bytes, e.what());
|
||||
return nullptr;
|
||||
} LIBIMP_CATCH(...) {
|
||||
log.error("std::aligned_alloc(alignment = {}, bytes = {}) fails. error = unknown exception",
|
||||
alignment, bytes);
|
||||
return nullptr;
|
||||
}
|
||||
#elif defined(LIBIMP_OS_WIN)
|
||||
/// @see https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/aligned-malloc
|
||||
return ::_aligned_malloc(bytes, alignment);
|
||||
#else // try posix
|
||||
/// @see https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_memalign.html
|
||||
void *p = nullptr;
|
||||
int ret = ::posix_memalign(&p, alignment, bytes);
|
||||
if (ret != 0) {
|
||||
log.error("posix_memalign(alignment = {}, bytes = {}) fails. error = {}",
|
||||
alignment, bytes, sys::error(ret));
|
||||
return nullptr;
|
||||
}
|
||||
return p;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deallocates the storage pointed to by p.
|
||||
* @remark The storage it points to must not yet have been deallocated, otherwise the behavior is undefined.
|
||||
*
|
||||
* @see https://en.cppreference.com/w/cpp/memory/memory_resource/do_deallocate
|
||||
*
|
||||
* @param p must have been returned by a prior call to new_delete_resource::do_allocate(bytes, alignment).
|
||||
*/
|
||||
void new_delete_resource::do_deallocate(void* p, std::size_t bytes, std::size_t alignment) noexcept {
|
||||
LIBIMP_LOG_();
|
||||
if (p == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (!verify_args(log, bytes, alignment)) {
|
||||
return;
|
||||
}
|
||||
if (alignment <= alignof(std::max_align_t)) {
|
||||
/// @see https://en.cppreference.com/w/cpp/memory/c/free
|
||||
std::free(p);
|
||||
return;
|
||||
}
|
||||
#if defined(LIBIMP_CPP_17)
|
||||
LIBIMP_TRY {
|
||||
std::free(p);
|
||||
} LIBIMP_CATCH(std::exception const &e) {
|
||||
log.error("std::free(p = {}) fails, alignment = {}, bytes = {}. error = {}",
|
||||
p, alignment, bytes, e.what());
|
||||
} LIBIMP_CATCH(...) {
|
||||
log.error("std::free(p = {}) fails, alignment = {}, bytes = {}. error = unknown exception",
|
||||
p, alignment, bytes);
|
||||
}
|
||||
#elif defined(LIBIMP_OS_WIN)
|
||||
/// @see https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/aligned-free
|
||||
::_aligned_free(p);
|
||||
#else // try posix
|
||||
::free(p);
|
||||
#endif
|
||||
}
|
||||
|
||||
LIBPMR_NAMESPACE_END_
|
||||
@ -15,6 +15,7 @@ include_directories(
|
||||
|
||||
file(GLOB SRC_FILES
|
||||
${LIBIPC_PROJECT_DIR}/test/imp/*.cpp
|
||||
${LIBIPC_PROJECT_DIR}/test/pmr/*.cpp
|
||||
${LIBIPC_PROJECT_DIR}/test/*.cpp)
|
||||
|
||||
file(GLOB HEAD_FILES
|
||||
@ -23,5 +24,5 @@ file(GLOB HEAD_FILES
|
||||
add_executable(${PROJECT_NAME} ${SRC_FILES} ${HEAD_FILES})
|
||||
|
||||
link_directories(${LIBIPC_PROJECT_DIR}/3rdparty/gperftools)
|
||||
target_link_libraries(${PROJECT_NAME} gtest_main imp ipc)
|
||||
target_link_libraries(${PROJECT_NAME} gtest_main imp pmr ipc)
|
||||
#target_link_libraries(${PROJECT_NAME} tcmalloc_minimal)
|
||||
|
||||
7
test/pmr/test_pmr_allocator.cpp
Normal file
7
test/pmr/test_pmr_allocator.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "libpmr/allocator.h"
|
||||
|
||||
TEST(allocator, construct) {
|
||||
}
|
||||
40
test/pmr/test_pmr_memory_resource.cpp
Normal file
40
test/pmr/test_pmr_memory_resource.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "libpmr/memory_resource.h"
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
void *test_mr(T &&mr, std::size_t bytes, std::size_t alignment) {
|
||||
auto p = std::forward<T>(mr).do_allocate(bytes, alignment);
|
||||
if (alignment == 0) {
|
||||
EXPECT_EQ(p, nullptr);
|
||||
} else if (p != nullptr) {
|
||||
EXPECT_EQ((std::size_t)p % alignment, 0);
|
||||
}
|
||||
std::forward<T>(mr).do_deallocate(p, bytes, alignment);
|
||||
return p;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(memory_resource, new_delete_resource) {
|
||||
pmr::new_delete_resource m_res;
|
||||
|
||||
EXPECT_EQ(test_mr(m_res, 0, 0), nullptr);
|
||||
EXPECT_EQ(test_mr(m_res, 0, 1), nullptr);
|
||||
EXPECT_EQ(test_mr(m_res, 0, 2), nullptr);
|
||||
EXPECT_EQ(test_mr(m_res, 0, 3), nullptr);
|
||||
EXPECT_EQ(test_mr(m_res, 0, 8), nullptr);
|
||||
EXPECT_EQ(test_mr(m_res, 0, 64), nullptr);
|
||||
|
||||
EXPECT_EQ(test_mr(m_res, 1, 0), nullptr);
|
||||
EXPECT_NE(test_mr(m_res, 1, 1), nullptr);
|
||||
EXPECT_NE(test_mr(m_res, 1, 2), nullptr);
|
||||
EXPECT_EQ(test_mr(m_res, 1, 3), nullptr);
|
||||
EXPECT_NE(test_mr(m_res, 1, 8), nullptr);
|
||||
EXPECT_NE(test_mr(m_res, 1, 64), nullptr);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user