diff --git a/include/libipc/imp/nameof.h b/include/libipc/imp/nameof.h new file mode 100644 index 0000000..ea2d362 --- /dev/null +++ b/include/libipc/imp/nameof.h @@ -0,0 +1,43 @@ +/** + * \file libimp/nameof.h + * \author mutouyun (orz@orzz.org) + * \brief Gets the name string of a type. + */ +#pragma once + +#include +#include +#include + +#include "libipc/imp/export.h" +#include "libipc/imp/span.h" +#include "libipc/imp/detect_plat.h" + +namespace ipc { + +/** + * \brief The conventional way to obtain demangled symbol name. + * \see https://www.boost.org/doc/libs/1_80_0/libs/core/doc/html/core/demangle.html + * + * \param name the mangled name + * \return std::string a human-readable demangled type name + */ +IPC_EXPORT std::string demangle(std::string name) noexcept; + +/** + * \brief Returns an implementation defined string containing the name of the type. + * \see https://en.cppreference.com/w/cpp/types/type_info/name + * + * \tparam T a type + * \return std::string a human-readable demangled type name + */ +template +std::string nameof() noexcept { + LIBIPC_TRY { + return demangle(typeid(T).name()); + } LIBIPC_CATCH(...) { + return {}; + } +} + +} // namespace ipc diff --git a/include/libipc/imp/scope_exit.h b/include/libipc/imp/scope_exit.h new file mode 100644 index 0000000..4f93790 --- /dev/null +++ b/include/libipc/imp/scope_exit.h @@ -0,0 +1,77 @@ +/** + * \file libimp/scope_exit.h + * \author mutouyun (orz@orzz.org) + * \brief Execute guard function when the enclosing scope exits. + */ +#pragma once + +#include // std::forward, std::move +#include // std::function +#include + +#include "libipc/imp/detect_plat.h" + +namespace ipc { + +template > +class scope_exit { + F destructor_; + mutable bool released_; + +public: + template + explicit scope_exit(G &&destructor) noexcept + : destructor_(std::forward(destructor)) + , released_ (false) {} + + scope_exit(scope_exit &&other) noexcept + : destructor_(std::move(other.destructor_)) + , released_ (std::exchange(other.released_, true)) /*release rhs*/ {} + + scope_exit &operator=(scope_exit &&other) noexcept { + destructor_ = std::move(other.destructor_); + released_ = std::exchange(other.released_, true); + return *this; + } + + ~scope_exit() noexcept { + if (!released_) destructor_(); + } + + void release() const noexcept { + released_ = true; + } + + void do_exit() noexcept { + if (released_) return; + destructor_(); + released_ = true; + } + + void swap(scope_exit &other) noexcept { + std::swap(destructor_, other.destructor_); + std::swap(released_ , other.released_); + } +}; + +/// \brief Creates a scope_exit object. +template +auto make_scope_exit(F &&destructor) noexcept { + return scope_exit>(std::forward(destructor)); +} + +namespace detail_scope_exit { + +struct scope_exit_helper { + template + auto operator=(F &&f) const noexcept { + return make_scope_exit(std::forward(f)); + } +}; + +} // namespace detail_scope_exit + +#define LIBIPC_SCOPE_EXIT($VAL) \ + LIBIPC_UNUSED auto $VAL = ::ipc::detail_scope_exit::scope_exit_helper{} + +} // namespace ipc diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0d16732..2af3981 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,8 @@ set (PACKAGE_VERSION 1.3.0) aux_source_directory(${LIBIPC_PROJECT_DIR}/src/libipc SRC_FILES) aux_source_directory(${LIBIPC_PROJECT_DIR}/src/libipc/sync SRC_FILES) aux_source_directory(${LIBIPC_PROJECT_DIR}/src/libipc/platform SRC_FILES) +aux_source_directory(${LIBIPC_PROJECT_DIR}/src/libipc/imp SRC_FILES) +aux_source_directory(${LIBIPC_PROJECT_DIR}/src/libipc/mem SRC_FILES) file(GLOB HEAD_FILES ${LIBIPC_PROJECT_DIR}/include/libipc/*.h diff --git a/src/libipc/imp/nameof.cpp b/src/libipc/imp/nameof.cpp new file mode 100644 index 0000000..462473b --- /dev/null +++ b/src/libipc/imp/nameof.cpp @@ -0,0 +1,7 @@ + +#include "libipc/imp/detect_plat.h" +#if defined(LIBIPC_CC_GNUC) +# include "libipc/platform/gnuc/demangle.h" +#else +# include "libipc/platform/win/demangle.h" +#endif diff --git a/src/libipc/platform/gnuc/demangle.h b/src/libipc/platform/gnuc/demangle.h new file mode 100644 index 0000000..888b619 --- /dev/null +++ b/src/libipc/platform/gnuc/demangle.h @@ -0,0 +1,43 @@ +/** + * \file libipc/platform/gnuc/demangle.h + * \author mutouyun (orz@orzz.org) + */ +#pragma once + +#include // abi::__cxa_demangle +#include // std::malloc + +#include "libipc/imp/nameof.h" +#include "libipc/imp/scope_exit.h" +#include "libipc/imp/detect_plat.h" + +namespace ipc { + +/** + * \brief The conventional way to obtain demangled symbol name. + * \see https://www.boost.org/doc/libs/1_80_0/libs/core/doc/html/core/demangle.html + * + * \param name the mangled name + * \return std::string a human-readable demangled type name + */ +std::string demangle(std::string name) noexcept { + /// \see https://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html + std::size_t sz = name.size() + 1; + char *buffer = static_cast(std::malloc(sz)); + int status = 0; + char *realname = abi::__cxa_demangle(name.data(), buffer, &sz, &status); + if (realname == nullptr) { + std::free(buffer); + return {}; + } + LIBIPC_SCOPE_EXIT(guard) = [realname] { + std::free(realname); + }; + LIBIPC_TRY { + return std::move(name.assign(realname, sz)); + } LIBIPC_CATCH(...) { + return {}; + } +} + +} // namespace ipc diff --git a/src/libipc/platform/win/demangle.h b/src/libipc/platform/win/demangle.h new file mode 100644 index 0000000..791f64d --- /dev/null +++ b/src/libipc/platform/win/demangle.h @@ -0,0 +1,15 @@ +/** + * \file libipc/platform/win/demangle.h + * \author mutouyun (orz@orzz.org) + */ +#pragma once + +#include "libipc/imp/nameof.h" + +namespace ipc { + +std::string demangle(std::string name) noexcept { + return std::move(name); +} + +} // namespace ipc