Matter SDK Coverage Report
Current view: top level - lib/core - Optional.h (source / functions) Coverage Total Hit
Test: SHA:f84fe08d06f240e801b5d923f8a938a9938ca110 Lines: 98.9 % 93 92
Test Date: 2025-02-22 08:08:07 Functions: 43.8 % 420 184

            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              : template <class T>
      48              : class Optional
      49              : {
      50              : public:
      51       107341 :     constexpr Optional() {}
      52        15867 :     constexpr Optional(NullOptionalType) {}
      53              : 
      54          580 :     explicit Optional(const T & value)
      55          580 :     {
      56          580 :         mValueHolder.mHasValue = true;
      57          580 :         new (&mValueHolder.mValue.mData) T(value);
      58          580 :     }
      59              : 
      60              :     template <class... Args>
      61       291549 :     constexpr explicit Optional(InPlaceType, Args &&... args)
      62       291549 :     {
      63       291549 :         mValueHolder.mHasValue = true;
      64       291549 :         new (&mValueHolder.mValue.mData) T(std::forward<Args>(args)...);
      65       291549 :     }
      66              : 
      67         8045 :     constexpr Optional(const Optional & other)
      68         8045 :     {
      69         8045 :         mValueHolder.mHasValue = other.mValueHolder.mHasValue;
      70         8045 :         if (mValueHolder.mHasValue)
      71              :         {
      72          128 :             new (&mValueHolder.mValue.mData) T(other.mValueHolder.mValue.mData);
      73              :         }
      74         8045 :     }
      75              : 
      76              :     // Converts an Optional of an implicitly convertible type
      77              :     template <class U, std::enable_if_t<!std::is_same_v<T, U> && std::is_convertible_v<const U, T>, bool> = true>
      78              :     constexpr Optional(const Optional<U> & other)
      79              :     {
      80              :         mValueHolder.mHasValue = other.HasValue();
      81              :         if (mValueHolder.mHasValue)
      82              :         {
      83              :             new (&mValueHolder.mValue.mData) T(other.Value());
      84              :         }
      85              :     }
      86              : 
      87              :     // Converts an Optional of a type that requires explicit conversion
      88              :     template <class U,
      89              :               std::enable_if_t<!std::is_same_v<T, U> && !std::is_convertible_v<const U, T> && std::is_constructible_v<T, const U &>,
      90              :                                bool> = true>
      91              :     constexpr explicit Optional(const Optional<U> & other)
      92              :     {
      93              :         mValueHolder.mHasValue = other.HasValue();
      94              :         if (mValueHolder.mHasValue)
      95              :         {
      96              :             new (&mValueHolder.mValue.mData) T(other.Value());
      97              :         }
      98              :     }
      99              : 
     100       134680 :     constexpr Optional(Optional && other)
     101       134680 :     {
     102       134680 :         mValueHolder.mHasValue = other.mValueHolder.mHasValue;
     103       134680 :         if (mValueHolder.mHasValue)
     104              :         {
     105       134396 :             new (&mValueHolder.mValue.mData) T(std::move(other.mValueHolder.mValue.mData));
     106       134396 :             other.mValueHolder.mValue.mData.~T();
     107       134396 :             other.mValueHolder.mHasValue = false;
     108              :         }
     109       134680 :     }
     110              : 
     111         4211 :     constexpr Optional & operator=(const Optional & other)
     112              :     {
     113         4211 :         if (mValueHolder.mHasValue)
     114              :         {
     115          219 :             mValueHolder.mValue.mData.~T();
     116              :         }
     117         4211 :         mValueHolder.mHasValue = other.mValueHolder.mHasValue;
     118         4211 :         if (mValueHolder.mHasValue)
     119              :         {
     120         3744 :             new (&mValueHolder.mValue.mData) T(other.mValueHolder.mValue.mData);
     121              :         }
     122         4211 :         return *this;
     123              :     }
     124              : 
     125         1455 :     constexpr Optional & operator=(Optional && other)
     126              :     {
     127         1455 :         if (mValueHolder.mHasValue)
     128              :         {
     129          900 :             mValueHolder.mValue.mData.~T();
     130              :         }
     131         1455 :         mValueHolder.mHasValue = other.mValueHolder.mHasValue;
     132         1455 :         if (mValueHolder.mHasValue)
     133              :         {
     134          450 :             new (&mValueHolder.mValue.mData) T(std::move(other.mValueHolder.mValue.mData));
     135          450 :             other.mValueHolder.mValue.mData.~T();
     136          450 :             other.mValueHolder.mHasValue = false;
     137              :         }
     138         1455 :         return *this;
     139              :     }
     140              : 
     141              :     /// Constructs the contained value in-place
     142              :     template <class... Args>
     143         8845 :     constexpr T & Emplace(Args &&... args)
     144              :     {
     145         8845 :         if (mValueHolder.mHasValue)
     146              :         {
     147           23 :             mValueHolder.mValue.mData.~T();
     148              :         }
     149         8845 :         mValueHolder.mHasValue = true;
     150         8845 :         new (&mValueHolder.mValue.mData) T(std::forward<Args>(args)...);
     151         8845 :         return mValueHolder.mValue.mData;
     152              :     }
     153              : 
     154              :     /** Make the optional contain a specific value */
     155        26689 :     constexpr void SetValue(const T & value)
     156              :     {
     157        26689 :         if (mValueHolder.mHasValue)
     158              :         {
     159         2978 :             mValueHolder.mValue.mData.~T();
     160              :         }
     161        26689 :         mValueHolder.mHasValue = true;
     162        26689 :         new (&mValueHolder.mValue.mData) T(value);
     163        26689 :     }
     164              : 
     165              :     constexpr void SetValue(std::optional<T> & value)
     166              :     {
     167              :         if (value.has_value())
     168              :         {
     169              :             SetValue(*value);
     170              :         }
     171              :         else
     172              :         {
     173              :             ClearValue();
     174              :         }
     175              :     }
     176              : 
     177              :     /** Make the optional contain a specific value */
     178         1997 :     constexpr void SetValue(T && value)
     179              :     {
     180         1997 :         if (mValueHolder.mHasValue)
     181              :         {
     182         1228 :             mValueHolder.mValue.mData.~T();
     183              :         }
     184         1997 :         mValueHolder.mHasValue = true;
     185         1997 :         new (&mValueHolder.mValue.mData) T(std::move(value));
     186         1997 :     }
     187              : 
     188              :     /** Invalidate the value inside the optional. Optional now has no value */
     189        63091 :     constexpr void ClearValue()
     190              :     {
     191        63091 :         if (mValueHolder.mHasValue)
     192              :         {
     193         9650 :             mValueHolder.mValue.mData.~T();
     194              :         }
     195        63091 :         mValueHolder.mHasValue = false;
     196        63091 :     }
     197              : 
     198              :     /** Gets the current value of the optional. Valid IFF `HasValue`. */
     199       437272 :     T & Value() &
     200              :     {
     201       437272 :         VerifyOrDie(HasValue());
     202       437272 :         return mValueHolder.mValue.mData;
     203              :     }
     204              : 
     205              :     /** Gets the current value of the optional. Valid IFF `HasValue`. */
     206        73924 :     const T & Value() const &
     207              :     {
     208        73924 :         VerifyOrDie(HasValue());
     209        73924 :         return mValueHolder.mValue.mData;
     210              :     }
     211              : 
     212              :     /** Gets the current value of the optional if the optional has a value;
     213              :         otherwise returns the provided default value. */
     214         2471 :     const T & ValueOr(const T & defaultValue) const { return HasValue() ? Value() : defaultValue; }
     215              : 
     216              :     /** Checks if the optional contains a value or not */
     217      1058337 :     constexpr bool HasValue() const { return mValueHolder.mHasValue; }
     218              : 
     219          314 :     bool operator==(const Optional & other) const
     220              :     {
     221          625 :         return (mValueHolder.mHasValue == other.mValueHolder.mHasValue) &&
     222          625 :             (!other.mValueHolder.mHasValue || (mValueHolder.mValue.mData == other.mValueHolder.mValue.mData));
     223              :     }
     224              :     bool operator!=(const Optional & other) const { return !(*this == other); }
     225              :     bool operator==(const T & other) const { return HasValue() && Value() == other; }
     226              :     bool operator!=(const T & other) const { return !(*this == other); }
     227              : 
     228            7 :     std::optional<T> std_optional() const
     229              :     {
     230            7 :         VerifyOrReturnValue(HasValue(), std::nullopt);
     231            0 :         return std::make_optional(Value());
     232              :     }
     233              : 
     234              :     /** Convenience method to create an optional without a valid value. */
     235        12398 :     static Optional<T> Missing() { return Optional<T>(); }
     236              : 
     237              :     /** Convenience method to create an optional containing the specified value. */
     238              :     template <class... Args>
     239           47 :     static Optional<T> Value(Args &&... args)
     240              :     {
     241           47 :         return Optional(InPlace, std::forward<Args>(args)...);
     242              :     }
     243              : 
     244              : private:
     245              :     // A container of bool + value (without constructor/destructor) when the underlying
     246              :     // type has a trivial destructor
     247              :     class TrivialDestructor
     248              :     {
     249              :     public:
     250              :         bool mHasValue = false;
     251              :         union Value
     252              :         {
     253       129096 :             Value() {}
     254              :             T mData;
     255              :         } mValue;
     256              :     };
     257              : 
     258              :     // A container of bool + value that destroys the underlying type when mHasValue is true.
     259              :     // To be used for non-trivial destructor classes.
     260              :     class NonTrivialDestructor
     261              :     {
     262              :     public:
     263         9450 :         ~NonTrivialDestructor()
     264              :         {
     265              :             // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.Branch): mData is set when mHasValue
     266         9450 :             if (mHasValue)
     267              :             {
     268         1492 :                 mValue.mData.~T();
     269              :             }
     270         9450 :         }
     271              : 
     272              :         bool mHasValue = false;
     273              :         union Value
     274              :         {
     275         1804 :             Value() {}
     276         9450 :             ~Value() {}
     277              :             T mData;
     278              :         } mValue;
     279              :     };
     280              : 
     281              :     class ValueHolder : public std::conditional_t<std::is_trivially_destructible_v<T>, TrivialDestructor, NonTrivialDestructor>
     282              :     {
     283              :     };
     284              : 
     285              :     ValueHolder mValueHolder;
     286              : };
     287              : 
     288              : template <class T>
     289          264 : constexpr Optional<std::decay_t<T>> MakeOptional(T && value)
     290              : {
     291          264 :     return Optional<std::decay_t<T>>(InPlace, std::forward<T>(value));
     292              : }
     293              : 
     294              : template <class T>
     295              : constexpr Optional<T> FromStdOptional(const std::optional<T> & value)
     296              : {
     297              :     VerifyOrReturnValue(value.has_value(), NullOptional);
     298              :     return MakeOptional(*value);
     299              : }
     300              : 
     301              : template <class T, class... Args>
     302       291238 : constexpr Optional<T> MakeOptional(Args &&... args)
     303              : {
     304       291238 :     return Optional<T>(InPlace, std::forward<Args>(args)...);
     305              : }
     306              : 
     307              : } // namespace chip
        

Generated by: LCOV version 2.0-1