#ifndef SERVICE_API_SERVICE_API_UTILS_H_
#define SERVICE_API_SERVICE_API_UTILS_H_
#include <string>
#include <utility>
#if defined(OS_IOS)
#include <service_api/service_lazy_load.h>
#endif
#if defined(_WIN32)
#define LYNX_SERVICE_API_EXPORT
#define LYNX_SERVICE_API_USED __declspec(noinline)
#define LYNX_SERVICE_API_VAR_USED
#else
#define LYNX_SERVICE_API_EXPORT __attribute__((visibility("default")))
#define LYNX_SERVICE_API_USED __attribute__((noinline)) __attribute__((used))
#define LYNX_SERVICE_API_VAR_USED __attribute__((used))
#endif
#define EXPORT_FUNC LYNX_SERVICE_API_EXPORT LYNX_SERVICE_API_USED
#define EXPORT_VAR LYNX_SERVICE_API_EXPORT LYNX_SERVICE_API_VAR_USED
#define EXPORT_CLASS LYNX_SERVICE_API_EXPORT
#define DYLIB_ENTRY(name) __attribute__((constructor)) void name()
#if defined(OS_IOS)
#define _LYNX_SERVICE_ENTRY_FUNC(name) SERVICE_LAZY_LOAD_CPP(name)
#else
#define _LYNX_SERVICE_ENTRY_FUNC(name) DYLIB_ENTRY(name)
#endif
#ifndef BASE_CONCAT
#define BASE_CONCAT2(A, B) A##B
#define BASE_CONCAT(A, B) BASE_CONCAT2(A, B)
#endif
#ifdef LYNX_SERVICE_API_NEED_EXPORTS
#define _LYNX_SERVICE_ANCHOR(ServiceClass) \
* the function in the service_api.so/service_api.o, preventing it from \
* being optimized away by the compiler or linker. \
*/ \
namespace { \
__attribute__((used)) void __##ServiceClass##_registry_f() { \
lynx::service::get_registry<ServiceClass>(); \
} \
}
#else
#define _LYNX_SERVICE_ANCHOR(ServiceClass)
#endif
* Defines a link anchor function that forces the linker to keep associated
* code. This macro creates a dummy function marked with __attribute__((used))
* to prevent the linker from optimizing it away.
*
* This pattern is commonly used to ensure that self-registering code (like
* static initializers or factory registration) is linked into the final binary,
* even when not directly referenced by other code.
*
* @param name - Identifier for the link anchor
*
* @example
* @code{.cpp}
* // In a.cc which contains standalone self-registering code
* DEFINE_LINK_ANCHOR(my_module)
* // In b.cc which is directly referenced by the main program
* USE_LINK_ANCHOR(my_module)
* @endcode
*
* @see USE_LINK_ANCHOR
*/
#define DEFINE_LINK_ANCHOR(name) \
__attribute__((used)) void __lynx_link_anchor_##name(void) {}
* References a previously defined link anchor to establish a dependency.
*
* @param name - Identifier matching a DEFINE_LINK_ANCHOR declaration
*
* @see DEFINE_LINK_ANCHOR
*/
#define USE_LINK_ANCHOR(name) \
extern void __lynx_link_anchor_##name(void); \
__attribute__((used)) static void *__lynx_link_anchor_ref_##name = \
(void *)&__lynx_link_anchor_##name
namespace lynx {
namespace service {
namespace utils {
* Get type name at compilation time without RTTI.
*/
template <typename T>
constexpr std::string_view type_name() {
#ifdef __clang__
std::string_view name = __PRETTY_FUNCTION__;
std::string_view prefix =
"std::string_view lynx::service::utils::type_name() [T = ";
std::string_view suffix = "]";
#elif defined(__GNUC__)
std::string_view name = __PRETTY_FUNCTION__;
std::string_view prefix =
"constexpr std::string_view lynx::service::utils::type_name() "
"[with T = ";
std::string_view suffix = "]";
#elif defined(_MSC_VER)
std::string_view name = __FUNCSIG__;
std::string_view prefix =
"class std::basic_string_view<char,struct std::char_traits<char> > "
"__cdecl lynx::service::utils::type_name<";
std::string_view suffix = ">(void)";
#endif
name.remove_prefix(prefix.size());
name.remove_suffix(suffix.size());
return name;
}
template <typename T>
class NoDestructor {
public:
template <typename... Args>
explicit NoDestructor(Args &&...args) {
new (storage_) T(std::forward<Args>(args)...);
}
explicit NoDestructor(const T &x) { new (storage_) T(x); }
explicit NoDestructor(T &&x) { new (storage_) T(std::move(x)); }
NoDestructor(const NoDestructor &) = delete;
NoDestructor &operator=(const NoDestructor &) = delete;
~NoDestructor() = default;
const T &operator*() const { return *get(); }
T &operator*() { return *get(); }
const T *operator->() const { return get(); }
T *operator->() { return get(); }
const T *get() const { return reinterpret_cast<const T *>(storage_); }
T *get() { return reinterpret_cast<T *>(storage_); }
private:
alignas(T) char storage_[sizeof(T)];
#if defined(LEAK_SANITIZER)
T *storage_ptr_ = reinterpret_cast<T *>(storage_);
#endif
};
}
}
}
#endif