Commit 670a8e06 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

StaticSingletonManager without RTTI

Summary: [Folly] `StaticSingletonManager` without RTTI as a variant, but without support for dynamic loading either.

Reviewed By: andriigrynenko

Differential Revision: D14018865

fbshipit-source-id: d4eadc8924e6fec2cbb1dae957e311d80e9ce289
parent 0f039163
......@@ -25,7 +25,7 @@ namespace detail {
namespace {
class StaticSingletonManagerImpl {
class StaticSingletonManagerWithRttiImpl {
public:
using Make = void*();
using Cache = std::atomic<void*>;
......@@ -59,12 +59,12 @@ class StaticSingletonManagerImpl {
} // namespace
void* StaticSingletonManager::create_(
void* StaticSingletonManagerWithRtti::create_(
Key const& key,
Make& make,
Cache& cache) {
// This Leaky Meyers Singleton must always live in the .cpp file.
static auto& instance = *new StaticSingletonManagerImpl();
static auto& instance = *new StaticSingletonManagerWithRttiImpl();
return instance.create(key, make, cache);
}
......
......@@ -20,22 +20,45 @@
#include <typeinfo>
#include <folly/CPortability.h>
#include <folly/Indestructible.h>
#include <folly/Likely.h>
#include <folly/detail/Singleton.h>
#include <folly/lang/Exception.h>
namespace folly {
namespace detail {
// Does not support dynamic loading but works without rtti.
class StaticSingletonManagerSansRtti {
public:
template <typename T, typename Tag>
FOLLY_EXPORT FOLLY_ALWAYS_INLINE static T& create() {
std::atomic<T*> cache{};
auto const pointer = cache.load(std::memory_order_acquire);
return FOLLY_LIKELY(!!pointer) ? *pointer : create_<T, Tag>(cache);
}
private:
template <typename T, typename Tag>
FOLLY_EXPORT FOLLY_NOINLINE static T& create_(std::atomic<T*>& cache) {
static Indestructible<T> instance;
cache.store(&*instance, std::memory_order_release);
return *instance;
}
};
// This internal-use-only class is used to create all leaked Meyers singletons.
// It guarantees that only one instance of every such singleton will ever be
// created, even when requested from different compilation units linked
// dynamically.
class StaticSingletonManager {
//
// Supports dynamic loading but requires rtti.
class StaticSingletonManagerWithRtti {
public:
template <typename T, typename Tag>
FOLLY_EXPORT FOLLY_ALWAYS_INLINE static T& create() {
static Cache cache{};
auto const& key = typeid(TypeTuple<T, Tag>);
auto const& key = key_<T, Tag>();
auto const v = cache.load(std::memory_order_acquire);
auto const p = FOLLY_LIKELY(!!v) ? v : create_(key, make<T>, cache);
return *static_cast<T*>(p);
......@@ -51,9 +74,23 @@ class StaticSingletonManager {
return new T();
}
template <typename T, typename Tag>
FOLLY_ALWAYS_INLINE static std::type_info const& key_() {
#if FOLLY_HAS_RTTI
return typeid(TypeTuple<T, Tag>);
#else
throw_exception<std::logic_error>("rtti unavailable");
#endif
}
FOLLY_NOINLINE static void* create_(Key const& key, Make& make, Cache& cache);
};
using StaticSingletonManager = std::conditional_t<
FOLLY_HAS_RTTI,
StaticSingletonManagerWithRtti,
StaticSingletonManagerSansRtti>;
template <typename T, typename Tag>
FOLLY_ALWAYS_INLINE FOLLY_ATTR_VISIBILITY_HIDDEN T& createGlobal() {
return StaticSingletonManager::create<T, Tag>();
......
......@@ -33,6 +33,40 @@ struct Tag {};
template <int I>
using Int = std::integral_constant<int, I>;
TEST_F(StaticSingletonManagerTest, example_sans_rtti) {
using K = StaticSingletonManagerSansRtti;
using T = std::integral_constant<int, 3>;
auto& i = K::create<T, Tag<char>>();
EXPECT_EQ(T::value, i);
auto& j = K::create<T, Tag<char>>();
EXPECT_EQ(&i, &j);
EXPECT_EQ(T::value, j);
auto& k = K::create<T, Tag<char*>>();
EXPECT_NE(&i, &k);
EXPECT_EQ(T::value, k);
}
TEST_F(StaticSingletonManagerTest, example_with_rtti) {
using K = StaticSingletonManagerWithRtti;
using T = std::integral_constant<int, 3>;
auto& i = K::create<T, Tag<char>>();
EXPECT_EQ(T::value, i);
auto& j = K::create<T, Tag<char>>();
EXPECT_EQ(&i, &j);
EXPECT_EQ(T::value, j);
auto& k = K::create<T, Tag<char*>>();
EXPECT_NE(&i, &k);
EXPECT_EQ(T::value, k);
}
TEST_F(StaticSingletonManagerTest, example) {
using T = std::integral_constant<int, 3>;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment