/* * Copyright (c) Meta Platforms, Inc. and 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 <array> #include <atomic> #include <iterator> #include <memory> #include <stdexcept> #include <folly/detail/StaticSingletonManager.h> #include <folly/Format.h> #include <folly/Function.h> #include <folly/SharedMutex.h> namespace folly { // A mixin to register and issue callbacks every time a class constructor is // invoked // // For example: // #include <folly/ConstructorCallbackList.h> // // class Foo { // ... // private: // ... // // add this member last to minimize partially constructed errors // ConstructorCallbackList<Foo> constructorCB_{this}; // } // // int main() { // auto cb = [](Foo * f) { // std::cout << "New Foo" << f << std::endl; // }; // ConstructorCallbackList<Foo>::addCallback(cb); // Foo f{}; // will call callback, print to stdout // } // // This code is designed to be light weight so as to mixin to many // places with low overhead. // // NOTE: The callback is triggered with a *partially* constructed object. // This implies that that callback code can only access members that are // constructed *before* the ConstructorCallbackList object. Also, at the time // of the callback, none of the Foo() constructor code will have run. // Per the example above, // the best practice is to place the ConstructorCallbackList declaration last // in the parent class. This will minimize the amount of uninitialized // data in the Foo instance, but will not eliminate it unless it has a trivial // constructor. // // Implementation/Overhead Notes: // // By design, adding ConstructorCallbackList to an object should be very // light weight. From a memory context, this adds 1 byte of memory to the // parent class. From a CPU/performance perspective, the constructor does a load // of an atomic int and the cost of the actual callbacks themselves. So if this // is put in place and only used infrequently, e.g., during debugging, // this cost should be quite small. // // A compile-time static array is used intentionally over a dynamic one for // two reasons: (1) a dynamic array seems to require a proper lock in // the constructor which would exceed our perf target, and (2) having a // finite array provides some sanity checking on the number of callbacks // that can be registered. template <class T, std::size_t MaxCallbacks = 4> class ConstructorCallbackList { … }; } // namespace folly