/* * Copyright (c) Facebook, Inc. and its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include #include #include #include #include #include #include #include #include namespace folly { namespace detail { // Does not support dynamic loading but works without rtti. class StaticSingletonManagerSansRtti { private: using Cache = std::atomic; using Make = void*(); struct Arg { Cache cache{}; // should be first field Make* make; template /* implicit */ constexpr Arg(tag_t) noexcept : make{thunk::make} {} }; template static void* create_(Arg&) noexcept(Noexcept); // no defn; only for decltype template using Create = decltype(create_); public: template struct ArgCreate : private Arg { friend class StaticSingletonManagerSansRtti; template /* implicit */ constexpr ArgCreate(tag_t t) noexcept : Arg{t}, create{create_} { static_assert(Noexcept == noexcept(T()), "mismatched noexcept"); } private: Create* create; }; template FOLLY_EXPORT FOLLY_ALWAYS_INLINE static T& create() { static Arg arg{tag}; return create(arg); } template FOLLY_ERASE static T& create(ArgCreate& arg) { auto const v = arg.cache.load(std::memory_order_acquire); auto const p = FOLLY_LIKELY(!!v) ? v : arg.create(arg); return *static_cast(p); } private: template FOLLY_ERASE static T& create(Arg& arg) { auto const v = arg.cache.load(std::memory_order_acquire); auto const p = FOLLY_LIKELY(!!v) ? v : create_(arg); return *static_cast(p); } template FOLLY_EXPORT FOLLY_NOINLINE static void* create_(Arg& arg) noexcept( noexcept(T())) { auto& cache = arg.cache; static Indestructible 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. // // Supports dynamic loading but requires rtti. class StaticSingletonManagerWithRtti { private: using Key = std::type_info; using Make = void*(); using Cache = std::atomic; struct Arg { Cache cache{}; // should be first field Key const* key; Make* make; // gcc and clang behave poorly if typeid is hidden behind a non-constexpr // function, but typeid is not constexpr under msvc template /* implicit */ constexpr Arg(tag_t) noexcept : key{FOLLY_TYPE_INFO_OF(tag_t)}, make{thunk::make} {} }; template FOLLY_NOINLINE static void* create_(Arg&) noexcept(Noexcept); template using Create = decltype(create_); public: template struct ArgCreate : private Arg { friend class StaticSingletonManagerWithRtti; template /* implicit */ constexpr ArgCreate(tag_t t) noexcept : Arg{t}, create{create_} { static_assert(Noexcept == noexcept(T()), "mismatched noexcept"); } private: Create* create; }; template FOLLY_EXPORT FOLLY_ALWAYS_INLINE static T& create() { static Arg arg{tag}; return create(arg); } template FOLLY_ERASE static T& create(ArgCreate& arg) { auto const v = arg.cache.load(std::memory_order_acquire); auto const p = FOLLY_LIKELY(!!v) ? v : arg.create(arg); return *static_cast(p); } private: template FOLLY_ERASE static T& create(Arg& arg) { auto const v = arg.cache.load(std::memory_order_acquire); auto const p = FOLLY_LIKELY(!!v) ? v : create_(arg); return *static_cast(p); } }; using StaticSingletonManager = std::conditional_t< kHasRtti, StaticSingletonManagerWithRtti, StaticSingletonManagerSansRtti>; template FOLLY_ERASE T& createGlobal() { return StaticSingletonManager::create(); } } // namespace detail } // namespace folly