// Copyright 2023 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CHROME_BROWSER_UI_TABS_SUPPORTS_HANDLES_H_ #define CHROME_BROWSER_UI_TABS_SUPPORTS_HANDLES_H_ // SupportsHandles is a way to add "handle" support to an object, such as a tab // or browser window which: // - may be transient (i.e. the reference could later become invalid) // - needs to be safely referenced from code in other languages, such as // JavaScript code in extensions // // If you do not need *both* of these, consider a raw or weak pointer instead. // // A handle is a semi-opaque value that is safe to store and pass around even // after the underlying object is destroyed. They behave more or less like weak // pointers, but have the added benefit that they contain an integral // `raw_value` which can be copied around, and even passed between programming // languages. // // To use handles with a class, inherit publicly from // `SupportsHandles<YourClassName>`. Then a handle can be retrieved from an // instance, and the instance retrieved from the handle: // ``` // MyClass::Handle handle = my_object->GetHandle(); // // Do a bunch of stuff that might delete `my_object`. // if (MyClass* obj = handle.Get()) { // obj->DoAThing(); // } // ``` // // Notes: // // Handle values do not persist across process restart (though restoring handle // values at startup could be implemented in some future iteration of this // library.) // // Objects with handles may only be generated and retrieved on the primary UI // thread, though their handles and handle values may be copied to and stored on // any thread. // // The default raw handle type `V` is a 32-bit signed integer, since (a) there // are usually not more than 4 billion of any UI object, and (b) signed integers // provide the broadest possible language support. However, you may choose any // integral type for `V`. // // Regardless of choice of `V`, the null value for handles is always zero. // // It is a fatal error to try to create a new object if all valid values of `V` // have already been used. If an object is likely to run through all possible // values of V (that is, have more than 4 billion constructed over the life of // a chrome instance) then it is probably a poor candidate for handles (or at // the very least, you need to pick a larger V). // // TODO(dfried, tbergquist): move this file down to c/b/ui if it's used outside // of the tabstrip. #include <concepts> #include <cstdint> #include <map> #include "base/check.h" #include "base/no_destructor.h" #include "base/sequence_checker.h" // Inherit from this type to have your class support handles. Objects that // support handles cannot be copyable or assignable: // ``` // class C : public SupportsHandles<C> { ... } // ``` // // `V` defines the type (and therefore size in bits) of the underlying handle // value. A wider value type will provide more unique handle values. // // It is required that `T` derive from this class. This constraint is enforced // via a helper class, as it cannot be enforced before SupportsHandles is // defined. template <typename T, std::integral V = int32_t> class SupportsHandles { … }; // The handle type for an object of type `T`. // // This is a default-constructable, orderable, comparable, copyable value type. // // Unlike WeakPtr there is some overhead in looking up a handle, so convenience // operators (bool, !, ->, *) are not provided. template <typename T, std::integral V> class SupportsHandles<T, V>::Handle { … }; class SupportsHandlesTest; namespace internal { // Provides handle lookup table storage for each class that supports handles. // // This object is strictly sequence-checked and should only ever be accessed // from the primary UI thread. template <typename T, std::integral V> requires std::derived_from<T, SupportsHandles<T, V>> class HandleHelper { … }; } // namespace internal template <typename T, std::integral V> SupportsHandles<T, V>::SupportsHandles() : … { … } template <typename T, std::integral V> SupportsHandles<T, V>::~SupportsHandles() { … } template <typename T, std::integral V> typename SupportsHandles<T, V>::Handle SupportsHandles<T, V>::GetHandle() const { … } template <typename T, std::integral V> T* SupportsHandles<T, V>::Handle::Get() const { … } #endif // CHROME_BROWSER_UI_TABS_SUPPORTS_HANDLES_H_