Matter SDK Coverage Report
Current view: top level - lib/support - Variant.h (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 82.1 % 56 46
Test Date: 2025-01-17 19:00:11 Functions: 50.4 % 139 70

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2021 Project CHIP Authors
       4              :  *    All rights reserved.
       5              :  *
       6              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       7              :  *    you may not use this file except in compliance with the License.
       8              :  *    You may obtain a copy of the License at
       9              :  *
      10              :  *        http://www.apache.org/licenses/LICENSE-2.0
      11              :  *
      12              :  *    Unless required by applicable law or agreed to in writing, software
      13              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      14              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      15              :  *    See the License for the specific language governing permissions and
      16              :  *    limitations under the License.
      17              :  */
      18              : 
      19              : #pragma once
      20              : 
      21              : #include <lib/core/CHIPCore.h>
      22              : 
      23              : #include <algorithm>
      24              : #include <new>
      25              : #include <tuple>
      26              : #include <type_traits>
      27              : #include <typeinfo>
      28              : #include <utility>
      29              : 
      30              : #include <lib/core/InPlace.h>
      31              : 
      32              : namespace chip {
      33              : 
      34              : namespace VariantInternal {
      35              : 
      36              : template <std::size_t Index, typename... Ts>
      37              : struct VariantCurry;
      38              : 
      39              : template <std::size_t Index, typename T, typename... Ts>
      40              : struct VariantCurry<Index, T, Ts...>
      41              : {
      42         9443 :     inline static void Destroy(std::size_t id, void * data)
      43              :     {
      44         9443 :         if (id == Index)
      45           45 :             reinterpret_cast<T *>(data)->~T();
      46              :         else
      47         9398 :             VariantCurry<Index + 1, Ts...>::Destroy(id, data);
      48         9443 :     }
      49              : 
      50         2491 :     inline static void Move(std::size_t that_t, void * that_v, void * this_v)
      51              :     {
      52         2491 :         if (that_t == Index)
      53          115 :             new (this_v) T(std::move(*reinterpret_cast<T *>(that_v)));
      54              :         else
      55         2376 :             VariantCurry<Index + 1, Ts...>::Move(that_t, that_v, this_v);
      56         2491 :     }
      57              : 
      58          116 :     inline static void Copy(std::size_t that_t, const void * that_v, void * this_v)
      59              :     {
      60          116 :         if (that_t == Index)
      61              :         {
      62           67 :             new (this_v) T(*reinterpret_cast<const T *>(that_v));
      63              :         }
      64              :         else
      65              :         {
      66           49 :             VariantCurry<Index + 1, Ts...>::Copy(that_t, that_v, this_v);
      67              :         }
      68          116 :     }
      69              : 
      70              :     inline static bool Equal(std::size_t type_t, const void * that_v, const void * this_v)
      71              :     {
      72              :         if (type_t == Index)
      73              :         {
      74              :             return *reinterpret_cast<const T *>(this_v) == *reinterpret_cast<const T *>(that_v);
      75              :         }
      76              : 
      77              :         return VariantCurry<Index + 1, Ts...>::Equal(type_t, that_v, this_v);
      78              :     }
      79              : };
      80              : 
      81              : template <std::size_t Index>
      82              : struct VariantCurry<Index>
      83              : {
      84         4123 :     inline static void Destroy(std::size_t id, void * data) {}
      85         1016 :     inline static void Move(std::size_t that_t, void * that_v, void * this_v) {}
      86            0 :     inline static void Copy(std::size_t that_t, const void * that_v, void * this_v) {}
      87              :     inline static bool Equal(std::size_t type_t, const void * that_v, const void * this_v)
      88              :     {
      89              :         VerifyOrDie(false);
      90              :         return false;
      91              :     }
      92              : };
      93              : 
      94              : template <typename T, typename TupleType>
      95              : class TupleIndexOfType
      96              : {
      97              : private:
      98              :     template <std::size_t Index>
      99              :     static constexpr
     100              :         typename std::enable_if<std::is_same<T, typename std::tuple_element<Index, TupleType>::type>::value, std::size_t>::type
     101              :         calculate()
     102              :     {
     103              :         return Index;
     104              :     }
     105              : 
     106              :     template <std::size_t Index>
     107              :     static constexpr
     108              :         typename std::enable_if<!std::is_same<T, typename std::tuple_element<Index, TupleType>::type>::value, std::size_t>::type
     109              :         calculate()
     110              :     {
     111              :         return calculate<Index + 1>();
     112              :     }
     113              : 
     114              : public:
     115              :     static constexpr std::size_t value = calculate<0>();
     116              : };
     117              : 
     118              : } // namespace VariantInternal
     119              : 
     120              : /**
     121              :  * @brief
     122              :  *   Represents a type-safe union. An instance of Variant at any given time either holds a value of one of its
     123              :  *   alternative types, or no value.
     124              :  *
     125              :  *   Example:
     126              :  *     struct Type1 {};
     127              :  *
     128              :  *     struct Type2 {};
     129              :  *
     130              :  *     Variant<Type1, Type2> v;
     131              :  *     v.Set<Type1>(); // v contains Type1
     132              :  *     Type1 o1 = v.Get<Type1>();
     133              :  */
     134              : template <typename... Ts>
     135              : struct Variant
     136              : {
     137              : private:
     138              :     static constexpr std::size_t kDataSize    = std::max({ sizeof(Ts)... });
     139              :     static constexpr std::size_t kDataAlign   = std::max({ alignof(Ts)... });
     140              :     static constexpr std::size_t kInvalidType = SIZE_MAX;
     141              : 
     142              :     using Data  = typename std::aligned_storage<kDataSize, kDataAlign>::type;
     143              :     using Curry = VariantInternal::VariantCurry<0, Ts...>;
     144              : 
     145              :     std::size_t mTypeId;
     146              :     Data mData;
     147              : 
     148              : public:
     149         2255 :     Variant() : mTypeId(kInvalidType) {}
     150              : 
     151              :     template <typename T, class... Args>
     152            0 :     constexpr explicit Variant(InPlaceTemplateType<T>, Args &&... args) :
     153            0 :         mTypeId(VariantInternal::TupleIndexOfType<T, std::tuple<Ts...>>::value)
     154              :     {
     155            0 :         new (&mData) T(std::forward<Args>(args)...);
     156            0 :     }
     157              : 
     158           43 :     Variant(const Variant<Ts...> & that) : mTypeId(that.mTypeId) { Curry::Copy(that.mTypeId, &that.mData, &mData); }
     159              : 
     160            0 :     Variant(Variant<Ts...> && that) : mTypeId(that.mTypeId)
     161              :     {
     162            0 :         Curry::Move(that.mTypeId, &that.mData, &mData);
     163            0 :         Curry::Destroy(that.mTypeId, &that.mData);
     164            0 :         that.mTypeId = kInvalidType;
     165            0 :     }
     166              : 
     167           24 :     Variant<Ts...> & operator=(const Variant<Ts...> & that)
     168              :     {
     169           24 :         Curry::Destroy(mTypeId, &mData);
     170           24 :         mTypeId = that.mTypeId;
     171           24 :         Curry::Copy(that.mTypeId, &that.mData, &mData);
     172           24 :         return *this;
     173              :     }
     174              : 
     175         1131 :     Variant<Ts...> & operator=(Variant<Ts...> && that)
     176              :     {
     177         1131 :         Curry::Destroy(mTypeId, &mData);
     178         1131 :         mTypeId = that.mTypeId;
     179         1131 :         Curry::Move(that.mTypeId, &that.mData, &mData);
     180         1131 :         Curry::Destroy(that.mTypeId, &that.mData);
     181         1131 :         that.mTypeId = kInvalidType;
     182         1131 :         return *this;
     183              :     }
     184              : 
     185              :     bool operator==(const Variant & other) const
     186              :     {
     187              :         return GetType() == other.GetType() && (!Valid() || Curry::Equal(mTypeId, &other.mData, &mData));
     188              :     }
     189              : 
     190              :     template <typename T>
     191         7023 :     bool Is() const
     192              :     {
     193         7023 :         return (mTypeId == VariantInternal::TupleIndexOfType<T, std::tuple<Ts...>>::value);
     194              :     }
     195              : 
     196              :     std::size_t GetType() const { return mTypeId; }
     197              : 
     198          444 :     bool Valid() const { return (mTypeId != kInvalidType); }
     199              : 
     200              :     template <typename T, typename... Args>
     201              :     static Variant<Ts...> Create(Args &&... args)
     202              :     {
     203              :         return Variant<Ts...>(InPlaceTemplate<T>, std::forward<Args>(args)...);
     204              :     }
     205              : 
     206              :     template <typename T, typename... Args>
     207          159 :     void Set(Args &&... args)
     208              :     {
     209          159 :         Curry::Destroy(mTypeId, &mData);
     210          159 :         new (&mData) T(std::forward<Args>(args)...);
     211          159 :         mTypeId = VariantInternal::TupleIndexOfType<T, std::tuple<Ts...>>::value;
     212          159 :     }
     213              : 
     214              :     template <typename T>
     215          575 :     T & Get()
     216              :     {
     217          575 :         VerifyOrDie((mTypeId == VariantInternal::TupleIndexOfType<T, std::tuple<Ts...>>::value));
     218          575 :         return *reinterpret_cast<T *>(&mData);
     219              :     }
     220              : 
     221              :     template <typename T>
     222         1539 :     const T & Get() const
     223              :     {
     224         1539 :         VerifyOrDie((mTypeId == VariantInternal::TupleIndexOfType<T, std::tuple<Ts...>>::value));
     225         1539 :         return *reinterpret_cast<const T *>(&mData);
     226              :     }
     227              : 
     228              :     // Ideally we would suppress this from within Optional.h, where this false positive is coming from. That said suppressing
     229              :     // here is okay since mTypeId would seemingly only be uninitialized when Variant is in a union.
     230              :     //
     231              :     // NOLINTNEXTLINE(clang-analyzer-core.CallAndMessage): Only in a false positive is mTypeId uninitialized.
     232         2163 :     ~Variant() { Curry::Destroy(mTypeId, &mData); }
     233              : };
     234              : 
     235              : } // namespace chip
        

Generated by: LCOV version 2.0-1