diff --git a/mfbt/NeverDestroyed.h b/mfbt/NeverDestroyed.h new file mode 100644 index 000000000000..fe3b366c6946 --- /dev/null +++ b/mfbt/NeverDestroyed.h @@ -0,0 +1,66 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_NeverDestroyed_h +#define mozilla_NeverDestroyed_h + +#include +#include +#include +#include "mozilla/Attributes.h" + +namespace mozilla { + +// Helper type for creating a local static member of type `T` when `T` has a +// non-trivial static destructor. When used for the local static value, this +// type will avoid introducing a static destructor for these types, as they +// will survive until shutdown. +// +// This can be very useful to avoid static destructors, which are heavily +// discouraged. Using this type is unnecessary if `T` already has a trivial +// destructor, and may introduce unnecessary extra overhead. +// +// This type must only be used with static local members within a function, +// which will be enforced by the clang static analysis. +template +class MOZ_STATIC_LOCAL_CLASS MOZ_INHERIT_TYPE_ANNOTATIONS_FROM_TEMPLATE_ARGS + NeverDestroyed { + public: + static_assert( + !std::is_trivially_destructible_v, + "NeverDestroyed is unnecessary for trivially destructable types"); + + // Allow constructing the inner type. + // This isn't constexpr, as it requires invoking placement-new. See the + // comment on `mStorage`. + template + explicit NeverDestroyed(U&&... aArgs) { + new (mStorage) T(std::forward(aArgs)...); + } + + 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(mStorage); } + T* get() { return reinterpret_cast(mStorage); } + + // Block copy & move constructor, as the type is not safe to copy. + NeverDestroyed(const NeverDestroyed&) = delete; + NeverDestroyed& operator=(const NeverDestroyed&) = delete; + + private: + // Correctly aligned storage for the type. We unfortunately can't use a union + // for alignment & constexpr initialization as that would require an explicit + // destructor declaration, making `NeverDestroyed` non-trivially destructable. + alignas(T) char mStorage[sizeof(T)]; +}; + +}; // namespace mozilla + +#endif // mozilla_NeverDestroyed_h diff --git a/mfbt/moz.build b/mfbt/moz.build index 5f8c0925a545..3d5b7bcee997 100644 --- a/mfbt/moz.build +++ b/mfbt/moz.build @@ -73,6 +73,7 @@ EXPORTS.mozilla = [ "MemoryReporting.h", "MoveOnlyFunction.h", "MruCache.h", + "NeverDestroyed.h", "NonDereferenceable.h", "NotNull.h", "Opaque.h",