/* * Copyright 2020 ByteDance Games, Inc. All Rights Reserved. * * Author: Liuziming */ #pragma once #include #include #include #include #include #include #ifndef _MSC_VER #define SHM_LIKELY(exp) __builtin_expect(!!(exp), 1) #define SHM_UNLIKELY(exp) __builtin_expect(!!(exp), 0) #define SHM_FORCE_INLINE __attribute__((always_inline)) #else #define SHM_LIKELY(exp) (exp) #define SHM_UNLIKELY(exp) !(exp) #define SHM_FORCE_INLINE #endif namespace bg { enum ShmLogLevel { SHM_LOG_TRACE = 0, SHM_LOG_DEBUG, SHM_LOG_INFO, SHM_LOG_WARN, SHM_LOG_ERROR, SHM_LOG_FATAL }; using ShmLogger = void(ShmLogLevel level, const char* file, size_t line, const char* func, const char* msg); namespace detail { class ShmManager; class TypeName; void ShmLog(ShmLogLevel level, const char* file, size_t line, const char* func, const char* fmt, ...);/* __attribute__((format(printf, 5, 6)));*/ void ShmStdoutLog(ShmLogLevel level, const char* file, size_t line, const char* func, const char* msg); void* ShmAllocate(size_t bytes, const void*); void ShmDeallocate(void* ptr, size_t); uint64_t ShmCurrentVersion(); void* ShmAllocateRawMemory(size_t* bytes, size_t alignment); bool ShmHasSingleton(const TypeName& type); void* ShmGetSingleton(const TypeName& type, size_t bytes, bool* first_call); void ShmFreeSingleton(const TypeName& type); class TypeName { public: explicit TypeName(const char* type, size_t size = 0); const char* data() const { return m_type; } size_t length() const { return strnlen(m_type, MAX_TYPE_NAME_LENGTH); } const char* c_str() const { return m_type; } bool operator<(const TypeName& that) const { return strncmp(m_type, that.m_type, MAX_TYPE_NAME_LENGTH) < 0; } bool operator==(const TypeName& that) const { return strncmp(m_type, that.m_type, MAX_TYPE_NAME_LENGTH) == 0; } bool operator!=(const TypeName& that) const { return strncmp(m_type, that.m_type, MAX_TYPE_NAME_LENGTH) != 0; } private: static const size_t MAX_TYPE_NAME_LENGTH = 1024; char m_type[MAX_TYPE_NAME_LENGTH]; }; struct TypeNameHasher { size_t operator()(const TypeName& type) const { return std::_Fnv1a_append_value(type.length(), type.data()); } }; struct ShmContext { ShmLogger* logger = ShmStdoutLog; ShmManager* mgr = nullptr; size_t mmap_size = 0; char path[256]; ShmContext() { memset(path, 0x00, sizeof(path)); } }; template struct VptrHelper { struct D : public T { // NOTE: The destructor is not required, it's added to avoid compiler warning. virtual ~D() = default; virtual void IntroduceVptr() {} }; static const bool value = std::is_polymorphic::value || (sizeof(D) == sizeof(T)); }; template struct HasVptr : public std::integral_constant::value> {}; template class ShmAllocator { public: typedef size_t size_type; typedef ptrdiff_t difference_type; typedef T* pointer; typedef const T* const_pointer; typedef T& reference; typedef const T& const_reference; typedef T value_type; template struct rebind { typedef ShmAllocator other; }; ShmAllocator() = default; template explicit ShmAllocator(const ShmAllocator&) {} pointer address(reference x) const { return &x; } const_pointer address(const_reference x) const { return &x; } size_type max_size() const { return size_t(-1) / sizeof(T); } void construct(pointer p, const T& val) { ::new(p) T(val); } void construct(pointer p) { ::new(p) T(); } void destroy(pointer p) { p->~T(); } // This is the C++11 version of construct. template void construct(U* u, Args&&... args) { ::new(u) U(std::forward(args)...); } // This is the C++11 version of destroy. template void destroy(U* u) { u->~U(); } bool operator==(const ShmAllocator&) const { return true; } bool operator!=(const ShmAllocator&) const { return false; } pointer allocate(size_type n, const void* ptr = nullptr) { return static_cast(ShmAllocate(n * sizeof(value_type), ptr)); } void deallocate(pointer ptr, size_type size = 0) { ShmDeallocate(ptr, size); } }; } // namespace detail } // namespace bg #define __SHM_LOG(level, fmt, ...) bg::detail::ShmLog(level, __FILE__, __LINE__, __FUNCTION__, fmt, ##__VA_ARGS__) #define SHM_TRACE(fmt, ...) __SHM_LOG(bg::SHM_LOG_TRACE, fmt, ##__VA_ARGS__) #define SHM_DEBUG(fmt, ...) __SHM_LOG(bg::SHM_LOG_DEBUG, fmt, ##__VA_ARGS__) #define SHM_INFO(fmt, ...) __SHM_LOG(bg::SHM_LOG_INFO, fmt, ##__VA_ARGS__) #define SHM_WARN(fmt, ...) __SHM_LOG(bg::SHM_LOG_WARN, fmt, ##__VA_ARGS__) #define SHM_ERROR(fmt, ...) __SHM_LOG(bg::SHM_LOG_ERROR, fmt, ##__VA_ARGS__) #define SHM_FATAL(fmt, ...) __SHM_LOG(bg::SHM_LOG_FATAL, fmt, ##__VA_ARGS__) // TODO: print stack trace here #define __SHM_DO_ASSERT(exp) \ SHM_FATAL("assertion failure: %s", #exp); \ assert(exp) #define SHM_ASSERT(exp) \ do { \ if (SHM_LIKELY(exp)) break; \ __SHM_DO_ASSERT(exp); \ } while (0) #define SHM_ASSERT_RETURN_VALUE(exp, val) \ do { \ if (SHM_LIKELY(exp)) break; \ __SHM_DO_ASSERT(exp); \ return (val); \ } while (0) #define SHM_ASSERT_RETURN_VOID(exp) \ do { \ if (SHM_LIKELY(exp)) break; \ __SHM_DO_ASSERT(exp); \ return; \ } while (0) #define SHM_ASSERT_RETURN_NULL(exp) SHM_ASSERT_RETURN_VALUE(exp, nullptr) #define SHM_ASSERT_RETURN_TRUE(exp) SHM_ASSERT_RETURN_VALUE(exp, true) #define SHM_ASSERT_RETURN_FALSE(exp) SHM_ASSERT_RETURN_VALUE(exp, false) #ifdef NDEBUG #define SHM_DEBUG_ASSERT(exp) #else #define SHM_DEBUG_ASSERT(exp) SHM_ASSERT(exp) #endif