LCOV - code coverage report
Current view: top level - lib/core - Global.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 5 5 100.0 %
Date: 2024-02-15 08:20:41 Functions: 15 22 68.2 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2023 Project CHIP Authors
       4             :  *
       5             :  *    Licensed under the Apache License, Version 2.0 (the "License");
       6             :  *    you may not use this file except in compliance with the License.
       7             :  *    You may obtain a copy of the License at
       8             :  *
       9             :  *        http://www.apache.org/licenses/LICENSE-2.0
      10             :  *
      11             :  *    Unless required by applicable law or agreed to in writing, software
      12             :  *    distributed under the License is distributed on an "AS IS" BASIS,
      13             :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      14             :  *    See the License for the specific language governing permissions and
      15             :  *    limitations under the License.
      16             :  */
      17             : 
      18             : #pragma once
      19             : 
      20             : #include <lib/core/CHIPConfig.h>
      21             : 
      22             : #include <new>
      23             : 
      24             : namespace chip {
      25             : 
      26             : /**
      27             :  * A wrapper for global object that enables initialization and destruction to
      28             :  * be configured by the platform via `CHIP_CONFIG_GLOBALS_*` options.
      29             :  *
      30             :  * The contained object of type T is default constructed, possibly lazily.
      31             :  *
      32             :  * This class is generally NOT thread-safe; external synchronization is required.
      33             :  */
      34             : template <class T>
      35             : class Global
      36             : {
      37             : public:
      38             :     /// Returns the global object, initializing it if necessary.
      39             :     /// NOT thread-safe, external synchronization is required.
      40       11469 :     T & get() { return _get(); }
      41          10 :     T * operator->() { return &_get(); }
      42             : 
      43             : #if CHIP_CONFIG_GLOBALS_LAZY_INIT
      44             : public:
      45             :     constexpr Global() = default;
      46             :     ~Global()          = default;
      47             : 
      48             : private:
      49             :     // Zero-initialize everything. We should technically leave mStorage uninitialized,
      50             :     // but that can sometimes cause clang to be unable to constant-initialize the object.
      51             :     alignas(T) unsigned char mStorage[sizeof(T)] = {};
      52             :     bool mInitialized                            = false;
      53             : 
      54             :     T & _value() { return *reinterpret_cast<T *>(mStorage); }
      55             : 
      56             :     T & _get()
      57             :     {
      58             :         if (!mInitialized)
      59             :         {
      60             :             new (mStorage) T();
      61             :             mInitialized = true;
      62             : #if !CHIP_CONFIG_GLOBALS_NO_DESTRUCT
      63             :             CHIP_CXA_ATEXIT(&destroy, this);
      64             : #endif // CHIP_CONFIG_GLOBALS_NO_DESTRUCT
      65             :         }
      66             :         return _value();
      67             :     }
      68             : 
      69             :     static void destroy(void * context) { static_cast<Global<T> *>(context)->_value().~T(); }
      70             : 
      71             : #else // CHIP_CONFIG_GLOBALS_LAZY_INIT
      72             : public:
      73          96 :     constexpr Global() : mValue() {}
      74             : 
      75             : private:
      76       11479 :     T & _get() { return mValue; }
      77             : 
      78             : #if CHIP_CONFIG_GLOBALS_NO_DESTRUCT
      79             : public:
      80             :     // For not-trivially-destructible T, hiding it inside a union means the destructor
      81             :     // won't get called automatically, however our own default destructor will be implicitly
      82             :     // deleted. So Global<T> is technically not trivially-destructible, however the compiler
      83             :     // tends to be able to optimize away the empty destructor call in practice. Getting around
      84             :     // this cleanly requires using the "storage" approach used in the lazy variant, however
      85             :     // this would require std::construct_at from C++20 to get constexpr initialization.
      86             :     ~Global() {} // not "= default"
      87             : 
      88             : private:
      89             :     union
      90             :     {
      91             :         T mValue;
      92             :     };
      93             : #else  // CHIP_CONFIG_GLOBALS_NO_DESTRUCT
      94             : public:
      95         177 :     ~Global() = default;
      96             : 
      97             : private:
      98             :     T mValue;
      99             : #endif // CHIP_CONFIG_GLOBALS_NO_DESTRUCT
     100             : #endif // CHIP_CONFIG_GLOBALS_LAZY_INIT
     101             : };
     102             : 
     103             : } // namespace chip

Generated by: LCOV version 1.14