Matter SDK Coverage Report
Current view: top level - lib/core - Optional.h (source / functions) Coverage Total Hit
Test: SHA:f1767a8b0a3778fdf31b1d979afbdf544892fd94 Lines: 97.3 % 111 108
Test Date: 2026-06-03 07:35:21 Functions: 85.7 % 1135 973

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020 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              : /**
      19              :  *    @file
      20              :  *      This file defines the chip::Optional class to handle values which may
      21              :  *      or may not be present.
      22              :  *
      23              :  */
      24              : #pragma once
      25              : 
      26              : #include <new>
      27              : #include <optional>
      28              : #include <type_traits>
      29              : #include <utility>
      30              : 
      31              : #include <lib/core/InPlace.h>
      32              : #include <lib/support/CodeUtils.h>
      33              : 
      34              : namespace chip {
      35              : 
      36              : /// An empty class type used to indicate optional type with uninitialized state.
      37              : struct NullOptionalType
      38              : {
      39              :     explicit NullOptionalType() = default;
      40              : };
      41              : inline constexpr NullOptionalType NullOptional{};
      42              : 
      43              : /**
      44              :  * Pairs an object with a boolean value to determine if the object value
      45              :  * is actually valid or not.
      46              :  *
      47              :  * @note Despite the `constexpr` keywords throughout the class, this class is not a literal type and thus cannot be used in
      48              :  * compile-time contexts. This is mainly because of the use of placement new.
      49              :  */
      50              : template <class T>
      51              : class Optional
      52              : {
      53              : public:
      54       804643 :     constexpr Optional() {}
      55        31102 :     constexpr Optional(NullOptionalType) {}
      56              : 
      57          904 :     explicit Optional(const T & value)
      58          904 :     {
      59          904 :         mValueHolder.mHasValue = true;
      60          904 :         new (&mValueHolder.mValue.mData) T(value);
      61          904 :     }
      62              : 
      63              :     template <class... Args>
      64       368061 :     constexpr explicit Optional(InPlaceType, Args &&... args)
      65       368061 :     {
      66       368061 :         mValueHolder.mHasValue = true;
      67       368061 :         new (&mValueHolder.mValue.mData) T(std::forward<Args>(args)...);
      68       368061 :     }
      69              : 
      70        23239 :     constexpr Optional(const Optional & other)
      71        23239 :     {
      72        23239 :         mValueHolder.mHasValue = other.mValueHolder.mHasValue;
      73        23239 :         if (mValueHolder.mHasValue)
      74              :         {
      75         3744 :             new (&mValueHolder.mValue.mData) T(other.mValueHolder.mValue.mData);
      76              :         }
      77        23239 :     }
      78              : 
      79              :     // Converts an Optional of an implicitly convertible type
      80              :     template <class U, std::enable_if_t<!std::is_same_v<T, U> && std::is_convertible_v<const U, T>, bool> = true>
      81          520 :     constexpr Optional(const Optional<U> & other)
      82          520 :     {
      83          520 :         mValueHolder.mHasValue = other.HasValue();
      84          520 :         if (mValueHolder.mHasValue)
      85              :         {
      86          517 :             new (&mValueHolder.mValue.mData) T(other.Value());
      87              :         }
      88          520 :     }
      89              : 
      90              :     // Converts an Optional of a type that requires explicit conversion
      91              :     template <class U,
      92              :               std::enable_if_t<!std::is_same_v<T, U> && !std::is_convertible_v<const U, T> && std::is_constructible_v<T, const U &>,
      93              :                                bool> = true>
      94            1 :     constexpr explicit Optional(const Optional<U> & other)
      95            1 :     {
      96            1 :         mValueHolder.mHasValue = other.HasValue();
      97            1 :         if (mValueHolder.mHasValue)
      98              :         {
      99            1 :             new (&mValueHolder.mValue.mData) T(other.Value());
     100              :         }
     101            1 :     }
     102              : 
     103       136158 :     constexpr Optional(Optional && other)
     104       136158 :     {
     105       136158 :         mValueHolder.mHasValue = other.mValueHolder.mHasValue;
     106       136158 :         if (mValueHolder.mHasValue)
     107              :         {
     108       134691 :             new (&mValueHolder.mValue.mData) T(std::move(other.mValueHolder.mValue.mData));
     109       134691 :             other.mValueHolder.mValue.mData.~T();
     110       134691 :             other.mValueHolder.mHasValue = false;
     111              :         }
     112       136158 :     }
     113              : 
     114        15922 :     constexpr Optional & operator=(const Optional & other)
     115              :     {
     116        15922 :         if (mValueHolder.mHasValue)
     117              :         {
     118         2091 :             mValueHolder.mValue.mData.~T();
     119              :         }
     120        15922 :         mValueHolder.mHasValue = other.mValueHolder.mHasValue;
     121        15922 :         if (mValueHolder.mHasValue)
     122              :         {
     123         7823 :             new (&mValueHolder.mValue.mData) T(other.mValueHolder.mValue.mData);
     124              :         }
     125        15922 :         return *this;
     126              :     }
     127              : 
     128       138168 :     constexpr Optional & operator=(Optional && other)
     129              :     {
     130       138168 :         if (mValueHolder.mHasValue)
     131              :         {
     132         1397 :             mValueHolder.mValue.mData.~T();
     133              :         }
     134       138168 :         mValueHolder.mHasValue = other.mValueHolder.mHasValue;
     135       138168 :         if (mValueHolder.mHasValue)
     136              :         {
     137       135065 :             new (&mValueHolder.mValue.mData) T(std::move(other.mValueHolder.mValue.mData));
     138       135065 :             other.mValueHolder.mValue.mData.~T();
     139       135065 :             other.mValueHolder.mHasValue = false;
     140              :         }
     141       138168 :         return *this;
     142              :     }
     143              : 
     144              :     /// Constructs the contained value in-place
     145              :     template <class... Args>
     146        10965 :     constexpr T & Emplace(Args &&... args)
     147              :     {
     148        10965 :         if (mValueHolder.mHasValue)
     149              :         {
     150           25 :             mValueHolder.mValue.mData.~T();
     151              :         }
     152        10965 :         mValueHolder.mHasValue = true;
     153        10965 :         new (&mValueHolder.mValue.mData) T(std::forward<Args>(args)...);
     154        10965 :         return mValueHolder.mValue.mData;
     155              :     }
     156              : 
     157              :     /** Make the optional contain a specific value */
     158        42981 :     constexpr void SetValue(const T & value)
     159              :     {
     160        42981 :         if (mValueHolder.mHasValue)
     161              :         {
     162         5985 :             mValueHolder.mValue.mData.~T();
     163              :         }
     164        42981 :         mValueHolder.mHasValue = true;
     165        42981 :         new (&mValueHolder.mValue.mData) T(value);
     166        42981 :     }
     167              : 
     168              :     constexpr void SetValue(std::optional<T> & value)
     169              :     {
     170              :         if (value.has_value())
     171              :         {
     172              :             SetValue(*value);
     173              :         }
     174              :         else
     175              :         {
     176              :             ClearValue();
     177              :         }
     178              :     }
     179              : 
     180              :     /** Make the optional contain a specific value */
     181         5923 :     constexpr void SetValue(T && value)
     182              :     {
     183         5923 :         if (mValueHolder.mHasValue)
     184              :         {
     185         1379 :             mValueHolder.mValue.mData.~T();
     186              :         }
     187         5923 :         mValueHolder.mHasValue = true;
     188         5923 :         new (&mValueHolder.mValue.mData) T(std::move(value));
     189         5923 :     }
     190              : 
     191              :     /** Invalidate the value inside the optional. Optional now has no value */
     192       140469 :     constexpr void ClearValue()
     193              :     {
     194       140469 :         if (mValueHolder.mHasValue)
     195              :         {
     196        11984 :             mValueHolder.mValue.mData.~T();
     197              :         }
     198       140469 :         mValueHolder.mHasValue = false;
     199       140469 :     }
     200              : 
     201              :     /** Gets the current value of the optional. Valid IFF `HasValue`. */
     202       819058 :     T & Value() &
     203              :     {
     204       819058 :         VerifyOrDie(HasValue());
     205       819058 :         return mValueHolder.mValue.mData;
     206              :     }
     207              : 
     208              :     /** Gets the current value of the optional. Valid IFF `HasValue`. */
     209       300619 :     const T & Value() const &
     210              :     {
     211       300619 :         VerifyOrDie(HasValue());
     212       300619 :         return mValueHolder.mValue.mData;
     213              :     }
     214              : 
     215              :     /** Gets the current value of the optional if the optional has a value;
     216              :         otherwise returns the provided default value. */
     217        14010 :     const T & ValueOr(const T & defaultValue) const { return HasValue() ? Value() : defaultValue; }
     218              : 
     219              :     /** Checks if the optional contains a value or not */
     220      2264963 :     constexpr bool HasValue() const { return mValueHolder.mHasValue; }
     221              : 
     222          759 :     bool operator==(const Optional & other) const
     223              :     {
     224         1510 :         return (mValueHolder.mHasValue == other.mValueHolder.mHasValue) &&
     225         1510 :             (!other.mValueHolder.mHasValue || (mValueHolder.mValue.mData == other.mValueHolder.mValue.mData));
     226              :     }
     227           55 :     bool operator!=(const Optional & other) const { return !(*this == other); }
     228           35 :     bool operator==(const T & other) const { return HasValue() && Value() == other; }
     229           24 :     bool operator!=(const T & other) const { return !(*this == other); }
     230              : 
     231           29 :     std::optional<T> std_optional() const
     232              :     {
     233           29 :         VerifyOrReturnValue(HasValue(), std::nullopt);
     234           11 :         return std::make_optional(Value());
     235              :     }
     236              : 
     237              :     /** Convenience method to create an optional without a valid value. */
     238       146474 :     static Optional<T> Missing() { return Optional<T>(); }
     239              : 
     240              :     /** Convenience method to create an optional containing the specified value. */
     241              :     template <class... Args>
     242          108 :     static Optional<T> Value(Args &&... args)
     243              :     {
     244          108 :         return Optional(InPlace, std::forward<Args>(args)...);
     245              :     }
     246              : 
     247              : private:
     248              :     // A container of bool + value (without constructor/destructor) when the underlying
     249              :     // type has a trivial destructor
     250              :     class TrivialDestructor
     251              :     {
     252              :     public:
     253              :         bool mHasValue = false;
     254              :         union Value
     255              :         {
     256       852594 :             Value() {}
     257              :             T mData;
     258              :         } mValue;
     259              :     };
     260              : 
     261              :     // A container of bool + value that destroys the underlying type when mHasValue is true.
     262              :     // To be used for non-trivial destructor classes.
     263              :     class NonTrivialDestructor
     264              :     {
     265              :     public:
     266       512825 :         ~NonTrivialDestructor()
     267              :         {
     268              :             // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.Branch): mData is set when mHasValue
     269       512825 :             if (mHasValue)
     270              :             {
     271       233346 :                 mValue.mData.~T();
     272              :             }
     273       512825 :         }
     274              : 
     275              :         bool mHasValue = false;
     276              :         union Value
     277              :         {
     278       512825 :             Value() {}
     279       512825 :             ~Value() {}
     280              :             T mData;
     281              :         } mValue;
     282              :     };
     283              : 
     284              :     class ValueHolder : public std::conditional_t<std::is_trivially_destructible_v<T>, TrivialDestructor, NonTrivialDestructor>
     285              :     {
     286              :     };
     287              : 
     288              :     ValueHolder mValueHolder;
     289              : };
     290              : 
     291              : template <class T>
     292         1260 : constexpr Optional<std::decay_t<T>> MakeOptional(T && value)
     293              : {
     294         1260 :     return Optional<std::decay_t<T>>(InPlace, std::forward<T>(value));
     295              : }
     296              : 
     297              : template <class T>
     298            0 : constexpr Optional<T> FromStdOptional(const std::optional<T> & value)
     299              : {
     300            0 :     VerifyOrReturnValue(value.has_value(), NullOptional);
     301            0 :     return MakeOptional(*value);
     302              : }
     303              : 
     304              : template <class T, class... Args>
     305       366693 : constexpr Optional<T> MakeOptional(Args &&... args)
     306              : {
     307       366693 :     return Optional<T>(InPlace, std::forward<Args>(args)...);
     308              : }
     309              : 
     310              : } // namespace chip
        

Generated by: LCOV version 2.0-1