// std::weak_ptr<MyExpensiveService> instance =
// Singleton<MyExpensiveService>::get_weak();
//
-// Within same compilation unit you should directly access it by the variable
-// defining the singleton via get_fast()/get_weak_fast(), and even treat that
-// variable like a smart pointer (dereferencing it or using the -> operator):
-//
-// MyExpensiveService* instance = the_singleton.get_fast();
-// or
-// std::weak_ptr<MyExpensiveService> instance = the_singleton.get_weak_fast();
-// or even
-// the_singleton->doSomething();
-//
-// *_fast() accessors are faster than static accessors, and have performance
-// similar to Meyers singletons/static objects.
+// You also can directly access it by the variable defining the
+// singleton rather than via get(), and even treat that variable like
+// a smart pointer (dereferencing it or using the -> operator).
//
// Please note, however, that all non-weak_ptr interfaces are
// inherently subject to races with destruction. Use responsibly.
// folly::Singleton<MyExpensiveService, Tag2> s2();
// }
// ...
-// MyExpensiveService* svc_default = s_default.get_fast();
-// MyExpensiveService* svc1 = s1.get_fast();
-// MyExpensiveService* svc2 = s2.get_fast();
+// MyExpensiveService* svc_default = s_default.get();
+// MyExpensiveService* svc1 = s1.get();
+// MyExpensiveService* svc2 = s2.get();
//
// By default, the singleton instance is constructed via new and
// deleted via delete, but this is configurable:
return getEntry().get();
}
- // Same as get, but should be preffered to it in the same compilation
- // unit, where Singleton is registered.
- T* get_fast() {
- return entry_.get();
- }
-
// If, however, you do need to hold a reference to the specific
// singleton, you can try to do so with a weak_ptr. Avoid this when
// possible but the inability to lock the weak pointer can be a
return getEntry().get_weak();
}
- // Same as get_weak, but should be preffered to it in the same compilation
- // unit, where Singleton is registered.
- std::weak_ptr<T> get_weak_fast() {
- return entry_.get_weak();
- }
-
// Allow the Singleton<t> instance to also retrieve the underlying
// singleton, if desired.
- T* ptr() { return get_fast(); }
- T& operator*() { return *ptr(); }
- T* operator->() { return ptr(); }
+ T& operator*() { return *get(); }
+ T* operator->() { return get(); }
explicit Singleton(std::nullptr_t _ = nullptr,
Singleton::TeardownFunc t = nullptr) :
}
explicit Singleton(Singleton::CreateFunc c,
- Singleton::TeardownFunc t = nullptr) : entry_(getEntry()) {
+ Singleton::TeardownFunc t = nullptr) {
if (c == nullptr) {
throw std::logic_error(
"nullptr_t should be passed if you want T to be default constructed");
}
auto vault = SingletonVault::singleton<VaultTag>();
- entry_.registerSingleton(std::move(c), getTeardownFunc(std::move(t)));
- vault->registerSingleton(&entry_);
+ getEntry().registerSingleton(std::move(c), getTeardownFunc(std::move(t)));
+ vault->registerSingleton(&getEntry());
}
/**
return t;
}
}
-
- // This is pointing to SingletonHolder paired with this singleton object. This
- // is never reset, so each SingletonHolder should never be destroyed.
- // We rely on the fact that Singleton destructor won't reset this pointer, so
- // it can be "safely" used even after static Singleton object is destroyed.
- detail::SingletonHolder<T>& entry_;
};
}
EXPECT_EQ(vault.registeredSingletonCount(), 2);
vault.registrationComplete();
- EXPECT_NE(watchdog.ptr(), nullptr);
- EXPECT_EQ(watchdog.ptr(), SingletonDirectUsage<Watchdog>::get());
- EXPECT_NE(watchdog.ptr(), named_watchdog.ptr());
+ EXPECT_NE(watchdog.get(), nullptr);
+ EXPECT_EQ(watchdog.get(), SingletonDirectUsage<Watchdog>::get());
+ EXPECT_NE(watchdog.get(), named_watchdog.get());
EXPECT_EQ(watchdog->livingWatchdogCount(), 2);
EXPECT_EQ((*watchdog).livingWatchdogCount(), 2);
// Verify our three singletons are distinct and non-nullptr.
Watchdog* s1 = SingletonNamedUsage<Watchdog, Watchdog1>::get();
- EXPECT_EQ(s1, watchdog1_singleton.ptr());
+ EXPECT_EQ(s1, watchdog1_singleton.get());
Watchdog* s2 = SingletonNamedUsage<Watchdog, Watchdog2>::get();
- EXPECT_EQ(s2, watchdog2_singleton.ptr());
+ EXPECT_EQ(s2, watchdog2_singleton.get());
EXPECT_NE(s1, s2);
Watchdog* s3 = SingletonNamedUsage<Watchdog, Watchdog3>::get();
- EXPECT_EQ(s3, watchdog3_singleton.ptr());
+ EXPECT_EQ(s3, watchdog3_singleton.get());
EXPECT_NE(s3, s1);
EXPECT_NE(s3, s2);
// Verify the "default" singleton is the same as the DefaultTag-tagged
// singleton.
Watchdog* s4 = SingletonNamedUsage<Watchdog>::get();
- EXPECT_EQ(s4, watchdog3_singleton.ptr());
+ EXPECT_EQ(s4, watchdog3_singleton.get());
vault.destroyInstances();
}
template <typename T, typename Tag = detail::DefaultTag>
using SingletonBenchmark = Singleton <T, Tag, BenchmarkTag>;
-SingletonBenchmark<BenchmarkSingleton> benchmark_singleton;
+struct GetTag{};
+struct GetWeakTag{};
-BENCHMARK_RELATIVE(FollySingletonSlow, n) {
- for (size_t i = 0; i < n; ++i) {
- doNotOptimizeAway(SingletonBenchmark<BenchmarkSingleton>::get());
- }
-}
+SingletonBenchmark<BenchmarkSingleton, GetTag> benchmark_singleton_get;
+SingletonBenchmark<BenchmarkSingleton, GetWeakTag> benchmark_singleton_get_weak;
-BENCHMARK_RELATIVE(FollySingletonFast, n) {
+BENCHMARK_RELATIVE(FollySingleton, n) {
for (size_t i = 0; i < n; ++i) {
- doNotOptimizeAway(benchmark_singleton.get_fast());
+ doNotOptimizeAway(SingletonBenchmark<BenchmarkSingleton, GetTag>::get());
}
}
-BENCHMARK_RELATIVE(FollySingletonFastWeak, n) {
+BENCHMARK_RELATIVE(FollySingletonWeak, n) {
for (size_t i = 0; i < n; ++i) {
- benchmark_singleton.get_weak_fast();
+ SingletonBenchmark<BenchmarkSingleton, GetWeakTag>::get_weak();
}
}
}
Timekeeper* getTimekeeperSingleton() {
- return timekeeperSingleton_.get_fast();
+ return timekeeperSingleton_.get();
}
}} // folly::detail
Singleton<std::shared_ptr<DefaultExe>>& sDefaultExecutor,
Singleton<RWSpinLock, LockTag>& sExecutorLock) {
std::shared_ptr<Exe> executor;
- auto singleton = sExecutor.get_fast();
- auto lock = sExecutorLock.get_fast();
+ auto singleton = sExecutor.get();
+ auto lock = sExecutorLock.get();
{
RWSpinLock::ReadHolder guard(lock);
RWSpinLock::WriteHolder guard(lock);
executor = singleton->lock();
if (!executor) {
- executor = *sDefaultExecutor.get_fast();
+ executor = *sDefaultExecutor.get();
*singleton = executor;
}
return executor;
std::shared_ptr<Exe> executor,
Singleton<std::weak_ptr<Exe>>& sExecutor,
Singleton<RWSpinLock, LockTag>& sExecutorLock) {
- RWSpinLock::WriteHolder guard(sExecutorLock.get_fast());
- *sExecutor.get_fast() = std::move(executor);
+ RWSpinLock::WriteHolder guard(sExecutorLock.get());
+ *sExecutor.get() = std::move(executor);
}
std::shared_ptr<Executor> getCPUExecutor() {