Matter SDK Coverage Report
Current view: top level - lib/core - Optional.h (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 98.8 % 81 80
Test Date: 2025-01-17 19:00:11 Functions: 42.5 % 482 205

            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       101786 :     constexpr Optional() : mHasValue(false) {}
      52        15859 :     constexpr Optional(NullOptionalType) : mHasValue(false) {}
      53              : 
      54       127800 :     ~Optional()
      55              :     {
      56              :         // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.Branch): mData is set when mHasValue
      57       127800 :         if (mHasValue)
      58              :         {
      59        18175 :             mValue.mData.~T();
      60              :         }
      61       127800 :     }
      62              : 
      63          556 :     explicit Optional(const T & value) : mHasValue(true) { new (&mValue.mData) T(value); }
      64              : 
      65              :     template <class... Args>
      66       287295 :     constexpr explicit Optional(InPlaceType, Args &&... args) : mHasValue(true)
      67              :     {
      68       287295 :         new (&mValue.mData) T(std::forward<Args>(args)...);
      69       287295 :     }
      70              : 
      71         6868 :     constexpr Optional(const Optional & other) : mHasValue(other.mHasValue)
      72              :     {
      73         6868 :         if (mHasValue)
      74              :         {
      75          861 :             new (&mValue.mData) T(other.mValue.mData);
      76              :         }
      77         6868 :     }
      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              :     constexpr Optional(const Optional<U> & other) : mHasValue(other.HasValue())
      82              :     {
      83              :         if (mHasValue)
      84              :         {
      85              :             new (&mValue.mData) T(other.Value());
      86              :         }
      87              :     }
      88              : 
      89              :     // Converts an Optional of a type that requires explicit conversion
      90              :     template <class U,
      91              :               std::enable_if_t<!std::is_same_v<T, U> && !std::is_convertible_v<const U, T> && std::is_constructible_v<T, const U &>,
      92              :                                bool> = true>
      93              :     constexpr explicit Optional(const Optional<U> & other) : mHasValue(other.HasValue())
      94              :     {
      95              :         if (mHasValue)
      96              :         {
      97              :             new (&mValue.mData) T(other.Value());
      98              :         }
      99              :     }
     100              : 
     101       134708 :     constexpr Optional(Optional && other) : mHasValue(other.mHasValue)
     102              :     {
     103       134708 :         if (mHasValue)
     104              :         {
     105       134396 :             new (&mValue.mData) T(std::move(other.mValue.mData));
     106       134396 :             other.mValue.mData.~T();
     107       134396 :             other.mHasValue = false;
     108              :         }
     109       134708 :     }
     110              : 
     111         3976 :     constexpr Optional & operator=(const Optional & other)
     112              :     {
     113         3976 :         if (mHasValue)
     114              :         {
     115          176 :             mValue.mData.~T();
     116              :         }
     117         3976 :         mHasValue = other.mHasValue;
     118         3976 :         if (mHasValue)
     119              :         {
     120         3489 :             new (&mValue.mData) T(other.mValue.mData);
     121              :         }
     122         3976 :         return *this;
     123              :     }
     124              : 
     125         1244 :     constexpr Optional & operator=(Optional && other)
     126              :     {
     127         1244 :         if (mHasValue)
     128              :         {
     129          904 :             mValue.mData.~T();
     130              :         }
     131         1244 :         mHasValue = other.mHasValue;
     132         1244 :         if (mHasValue)
     133              :         {
     134          342 :             new (&mValue.mData) T(std::move(other.mValue.mData));
     135          342 :             other.mValue.mData.~T();
     136          342 :             other.mHasValue = false;
     137              :         }
     138         1244 :         return *this;
     139              :     }
     140              : 
     141              :     /// Constructs the contained value in-place
     142              :     template <class... Args>
     143         8479 :     constexpr T & Emplace(Args &&... args)
     144              :     {
     145         8479 :         if (mHasValue)
     146              :         {
     147           23 :             mValue.mData.~T();
     148              :         }
     149         8479 :         mHasValue = true;
     150         8479 :         new (&mValue.mData) T(std::forward<Args>(args)...);
     151         8479 :         return mValue.mData;
     152              :     }
     153              : 
     154              :     /** Make the optional contain a specific value */
     155        25951 :     constexpr void SetValue(const T & value)
     156              :     {
     157        25951 :         if (mHasValue)
     158              :         {
     159         2954 :             mValue.mData.~T();
     160              :         }
     161        25951 :         mHasValue = true;
     162        25951 :         new (&mValue.mData) T(value);
     163        25951 :     }
     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 (mHasValue)
     181              :         {
     182         1228 :             mValue.mData.~T();
     183              :         }
     184         1997 :         mHasValue = true;
     185         1997 :         new (&mValue.mData) T(std::move(value));
     186         1997 :     }
     187              : 
     188              :     /** Invalidate the value inside the optional. Optional now has no value */
     189        61570 :     constexpr void ClearValue()
     190              :     {
     191        61570 :         if (mHasValue)
     192              :         {
     193         9213 :             mValue.mData.~T();
     194              :         }
     195        61570 :         mHasValue = false;
     196        61570 :     }
     197              : 
     198              :     /** Gets the current value of the optional. Valid IFF `HasValue`. */
     199       430523 :     T & Value() &
     200              :     {
     201       430523 :         VerifyOrDie(HasValue());
     202       430523 :         return mValue.mData;
     203              :     }
     204              : 
     205              :     /** Gets the current value of the optional. Valid IFF `HasValue`. */
     206        65561 :     const T & Value() const &
     207              :     {
     208        65561 :         VerifyOrDie(HasValue());
     209        65561 :         return 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         2432 :     const T & ValueOr(const T & defaultValue) const { return HasValue() ? Value() : defaultValue; }
     215              : 
     216              :     /** Checks if the optional contains a value or not */
     217      1009811 :     constexpr bool HasValue() const { return mHasValue; }
     218              : 
     219          317 :     bool operator==(const Optional & other) const
     220              :     {
     221          317 :         return (mHasValue == other.mHasValue) && (!other.mHasValue || (mValue.mData == other.mValue.mData));
     222              :     }
     223              :     bool operator!=(const Optional & other) const { return !(*this == other); }
     224              :     bool operator==(const T & other) const { return HasValue() && Value() == other; }
     225              :     bool operator!=(const T & other) const { return !(*this == other); }
     226              : 
     227            7 :     std::optional<T> std_optional() const
     228              :     {
     229            7 :         VerifyOrReturnValue(HasValue(), std::nullopt);
     230            0 :         return std::make_optional(Value());
     231              :     }
     232              : 
     233              :     /** Convenience method to create an optional without a valid value. */
     234        12094 :     static Optional<T> Missing() { return Optional<T>(); }
     235              : 
     236              :     /** Convenience method to create an optional containing the specified value. */
     237              :     template <class... Args>
     238           47 :     static Optional<T> Value(Args &&... args)
     239              :     {
     240           47 :         return Optional(InPlace, std::forward<Args>(args)...);
     241              :     }
     242              : 
     243              : private:
     244              :     bool mHasValue;
     245              :     union Value
     246              :     {
     247       127119 :         Value() {}
     248       127800 :         ~Value() {}
     249              :         T mData;
     250              :     } mValue;
     251              : };
     252              : 
     253              : template <class T>
     254          954 : constexpr Optional<std::decay_t<T>> MakeOptional(T && value)
     255              : {
     256          954 :     return Optional<std::decay_t<T>>(InPlace, std::forward<T>(value));
     257              : }
     258              : 
     259              : template <class T>
     260              : constexpr Optional<T> FromStdOptional(const std::optional<T> & value)
     261              : {
     262              :     VerifyOrReturnValue(value.has_value(), NullOptional);
     263              :     return MakeOptional(*value);
     264              : }
     265              : 
     266              : template <class T, class... Args>
     267       286294 : constexpr Optional<T> MakeOptional(Args &&... args)
     268              : {
     269       286294 :     return Optional<T>(InPlace, std::forward<Args>(args)...);
     270              : }
     271              : 
     272              : } // namespace chip
        

Generated by: LCOV version 2.0-1