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

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2020 Project CHIP Authors
       4             :  *    Copyright (c) 2013-2017 Nest Labs, Inc.
       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             : #pragma once
      19             : 
      20             : #include <lib/support/StringBuilder.h>
      21             : #include <lib/support/TypeTraits.h>
      22             : 
      23             : #include <cstdint>
      24             : #include <type_traits>
      25             : 
      26             : namespace chip {
      27             : namespace TLV {
      28             : 
      29             : class Tag
      30             : {
      31             : public:
      32             :     enum SpecialTagNumber : uint32_t
      33             :     {
      34             :         kContextTagMaxNum = UINT8_MAX,
      35             :         kAnonymousTagNum,
      36             :         kUnknownImplicitTagNum
      37             :     };
      38             : 
      39             :     Tag() = default;
      40             : 
      41     4698335 :     constexpr bool operator==(const Tag & other) const { return mVal == other.mVal; }
      42     2486010 :     constexpr bool operator!=(const Tag & other) const { return mVal != other.mVal; }
      43             : 
      44             :     /// Appends the text representation of the tag to the given string builder base.
      45             :     StringBuilderBase & AppendTo(StringBuilderBase & out);
      46             : 
      47             : private:
      48    48487351 :     explicit constexpr Tag(uint64_t val) : mVal(val) {}
      49             : 
      50             :     friend constexpr Tag ProfileTag(uint32_t profileId, uint32_t tagNum);
      51             :     friend constexpr Tag ProfileTag(uint16_t vendorId, uint16_t profileNum, uint32_t tagNum);
      52             :     friend constexpr Tag ContextTag(uint8_t tagNum);
      53             :     friend constexpr Tag CommonTag(uint32_t tagNum);
      54             :     friend constexpr Tag AnonymousTag();
      55             :     friend constexpr Tag UnknownImplicitTag();
      56             : 
      57             :     // The following friend functions could be Tag class methods, but it turns out in some cases
      58             :     // they may not be inlined and then passing the tag by argument/value results in smaller code
      59             :     // than passing it by 'this' pointer. This can be worked around by applying 'always_inline'
      60             :     // function attribute, but friend functions are likely a more portable solution.
      61             : 
      62             :     friend constexpr uint32_t ProfileIdFromTag(Tag tag);
      63             :     friend constexpr uint16_t VendorIdFromTag(Tag tag);
      64             :     friend constexpr uint16_t ProfileNumFromTag(Tag tag);
      65             :     friend constexpr uint32_t TagNumFromTag(Tag tag);
      66             : 
      67             :     friend constexpr bool IsProfileTag(Tag tag);
      68             :     friend constexpr bool IsContextTag(Tag tag);
      69             :     friend constexpr bool IsSpecialTag(Tag tag);
      70             : 
      71             :     static constexpr uint32_t kProfileIdShift      = 32;
      72             :     static constexpr uint32_t kVendorIdShift       = 48;
      73             :     static constexpr uint32_t kProfileNumShift     = 32;
      74             :     static constexpr uint32_t kSpecialTagProfileId = 0xFFFFFFFF;
      75             : 
      76             :     // The storage of the tag value uses the following encoding:
      77             :     //
      78             :     //  63                              47                              31
      79             :     // +-------------------------------+-------------------------------+----------------------------------------------+
      80             :     // | Vendor id (bitwise-negated)   | Profile num (bitwise-negated) | Tag number                                   |
      81             :     // +-------------------------------+-------------------------------+----------------------------------------------+
      82             :     //
      83             :     // Vendor id and profile number are bitwise-negated in order to optimize the code size when
      84             :     // using context tags, the most commonly used tags in the SDK.
      85             :     uint64_t mVal;
      86             : };
      87             : 
      88             : enum TLVCommonProfiles
      89             : {
      90             :     /**
      91             :      * Used to indicate the absence of a profile id in a variable or member.
      92             :      * This is essentially the same as kCHIPProfile_NotSpecified defined in CHIPProfiles.h
      93             :      */
      94             :     kProfileIdNotSpecified = 0xFFFFFFFF,
      95             : 
      96             :     // TODO: Replace with chip::Profiles::kCHIPProfile_Common
      97             :     kCommonProfileId = 0
      98             : };
      99             : 
     100             : // TODO: Move to private namespace
     101             : enum class TLVTagControl : uint8_t
     102             : {
     103             :     // IMPORTANT: All values here must have no bits in common with specified
     104             :     // values of TLVElementType.
     105             :     Anonymous              = 0x00,
     106             :     ContextSpecific        = 0x20,
     107             :     CommonProfile_2Bytes   = 0x40,
     108             :     CommonProfile_4Bytes   = 0x60,
     109             :     ImplicitProfile_2Bytes = 0x80,
     110             :     ImplicitProfile_4Bytes = 0xA0,
     111             :     FullyQualified_6Bytes  = 0xC0,
     112             :     FullyQualified_8Bytes  = 0xE0
     113             : };
     114             : 
     115             : template <typename T>
     116    10483731 : inline uint8_t operator>>(TLVTagControl lhs, const T & rhs)
     117             : {
     118    10483731 :     return static_cast<uint8_t>(static_cast<uint8_t>(lhs) >> rhs);
     119             : }
     120             : 
     121             : // TODO: Move to private namespace
     122             : enum
     123             : {
     124             :     kTLVTagControlMask  = 0xE0,
     125             :     kTLVTagControlShift = 5
     126             : };
     127             : 
     128             : /**
     129             :  * Generates the API representation of a profile-specific TLV tag from a profile id and tag number
     130             :  *
     131             :  * @param[in]   profileId       The id of the profile within which the tag is defined.
     132             :  * @param[in]   tagNum          The profile-specific tag number assigned to the tag.
     133             :  * @return                      A 64-bit integer representing the tag.
     134             :  */
     135    48487351 : constexpr Tag ProfileTag(uint32_t profileId, uint32_t tagNum)
     136             : {
     137    48487351 :     return Tag((static_cast<uint64_t>(~profileId) << Tag::kProfileIdShift) | tagNum);
     138             : }
     139             : 
     140             : /**
     141             :  * Generates the API representation of a profile-specific TLV tag from a vendor id, profile number and tag number
     142             :  *
     143             :  * @param[in]   vendorId        The id of the vendor that defined the tag.
     144             :  * @param[in]   profileNum      The vendor assigned number for the profile within which the tag is defined.
     145             :  * @param[in]   tagNum          The profile-specific tag number assigned to the tag.
     146             :  * @return                      A 64-bit integer representing the tag.
     147             :  */
     148     2835714 : constexpr Tag ProfileTag(uint16_t vendorId, uint16_t profileNum, uint32_t tagNum)
     149             : {
     150     2835714 :     constexpr uint32_t kVendorIdShift = Tag::kVendorIdShift - Tag::kProfileIdShift;
     151             : 
     152     2835714 :     return ProfileTag((static_cast<uint32_t>(vendorId) << kVendorIdShift) | profileNum, tagNum);
     153             : }
     154             : 
     155             : /**
     156             :  * Generates the API representation of a context-specific TLV tag
     157             :  *
     158             :  * @param[in]   tagNum          The context-specific tag number assigned to the tag.
     159             :  * @return                      A 64-bit integer representing the tag.
     160             :  */
     161     5578186 : constexpr Tag ContextTag(uint8_t tagNum)
     162             : {
     163     5578186 :     return ProfileTag(Tag::kSpecialTagProfileId, tagNum);
     164             : }
     165             : 
     166             : /**
     167             :  * Also allow using enum class values as context tags.  There are four possible
     168             :  * cases when is_enum is true:
     169             :  *
     170             :  * 1) The enum is a scoped enum (enum class) and the underlying type is
     171             :  *    uint8_t.  Then the is_convertible test will test false, this overload will be
     172             :  *    used, to_underlying will return a uint8_t, and everything will work.
     173             :  * 2) The enum is a scoped enum (enum class) and the underlying type is
     174             :  *    not uint8_t.  Then the is_convertible test will test false, this overload will be
     175             :  *    used, to_underlying will return the other type, and -Wconversion will
     176             :  *    catch the type mismatch, if it's enabled.
     177             :  * 3) The enum is an old-style enum.  Then the is_convertible test will test
     178             :  *    true, this overload will be not be used, and the uint8_t overload will be
     179             :  *    used instead.  The compiler should then catch (at least with sufficient
     180             :  *    warnings turned on) if the constant being passed in is too big to fit into
     181             :  *    uint8_t.
     182             :  *
     183             :  * Leaving out the is_convertible test, so this overload gets used for old-style
     184             :  * enums, would cause old-style enums where the underlying type is wider than
     185             :  * uint8_t to fail compilation with -Wconversion even if the values are all
     186             :  * inside the uint8_t range, since to_underlying would explicitly return a type
     187             :  * that is wider than uint8_t.
     188             :  */
     189             : template <typename T, std::enable_if_t<std::is_enum<T>::value && !std::is_convertible<T, uint8_t>::value, int> = 0>
     190      248764 : constexpr Tag ContextTag(T tagNum)
     191             : {
     192      248764 :     return ContextTag(to_underlying(tagNum));
     193             : }
     194             : 
     195             : /**
     196             :  * Generates the API representation of a common profile TLV tag
     197             :  *
     198             :  * @param[in]   tagNum          The common profile tag number assigned to the tag.
     199             :  * @return                      A 64-bit integer representing the tag.
     200             :  */
     201         127 : constexpr Tag CommonTag(uint32_t tagNum)
     202             : {
     203         127 :     return ProfileTag(kCommonProfileId, tagNum);
     204             : }
     205             : 
     206             : /**
     207             :  * A value signifying a TLV element that has no tag (i.e. an anonymous element).
     208             :  */
     209    24801005 : constexpr Tag AnonymousTag()
     210             : {
     211    24801005 :     return ProfileTag(Tag::kSpecialTagProfileId, Tag::kAnonymousTagNum);
     212             : }
     213             : 
     214             : /**
     215             :  * An invalid tag that represents a TLV element decoding error due to unknown implicit profile id.
     216             :  */
     217     9629416 : constexpr Tag UnknownImplicitTag()
     218             : {
     219     9629416 :     return ProfileTag(Tag::kSpecialTagProfileId, Tag::kUnknownImplicitTagNum);
     220             : }
     221             : 
     222             : /**
     223             :  * Returns the profile id from a TLV tag
     224             :  *
     225             :  * @note The behavior of this function is undefined if the supplied tag is not a profile-specific tag.
     226             :  *
     227             :  * @param[in]   tag             The API representation of a profile-specific TLV tag.
     228             :  * @return                      The profile id.
     229             :  */
     230     2061462 : constexpr uint32_t ProfileIdFromTag(Tag tag)
     231             : {
     232     2061462 :     return ~static_cast<uint32_t>(tag.mVal >> Tag::kProfileIdShift);
     233             : }
     234             : 
     235             : /**
     236             :  * Returns the vendor id from a TLV tag
     237             :  *
     238             :  * @note The behavior of this function is undefined if the supplied tag is not a profile-specific tag.
     239             :  *
     240             :  * @param[in]   tag             The API representation of a profile-specific TLV tag.
     241             :  * @return                      The associated vendor id.
     242             :  */
     243          16 : constexpr uint16_t VendorIdFromTag(Tag tag)
     244             : {
     245          16 :     constexpr uint32_t kVendorIdShift = Tag::kVendorIdShift - Tag::kProfileIdShift;
     246             : 
     247          16 :     return static_cast<uint16_t>(ProfileIdFromTag(tag) >> kVendorIdShift);
     248             : }
     249             : 
     250             : /**
     251             :  * Returns the profile number from a TLV tag
     252             :  *
     253             :  * @note The behavior of this function is undefined if the supplied tag is not a profile-specific tag.
     254             :  *
     255             :  * @param[in]   tag             The API representation of a profile-specific TLV tag.
     256             :  * @return                      The associated profile number.
     257             :  */
     258          16 : constexpr uint16_t ProfileNumFromTag(Tag tag)
     259             : {
     260          16 :     return static_cast<uint16_t>(ProfileIdFromTag(tag));
     261             : }
     262             : 
     263             : /**
     264             :  * Returns the tag number from a TLV tag
     265             :  *
     266             :  * @note The behavior of this function is undefined if the supplied tag is not a profile-specific
     267             :  * or context-specific tag.
     268             :  *
     269             :  * @sa IsProfileTag() and IsContextTag()
     270             :  *
     271             :  * @param[in]   tag             The API representation of a profile-specific or context-specific TLV tag.
     272             :  * @return                      The associated tag number.
     273             :  */
     274      884157 : constexpr uint32_t TagNumFromTag(Tag tag)
     275             : {
     276      884157 :     return static_cast<uint32_t>(tag.mVal);
     277             : }
     278             : 
     279             : /**
     280             :  * Returns true of the supplied tag is a profile-specific tag.
     281             :  */
     282        6130 : constexpr bool IsProfileTag(Tag tag)
     283             : {
     284        6130 :     return ProfileIdFromTag(tag) != Tag::kSpecialTagProfileId;
     285             : }
     286             : 
     287             : /**
     288             :  * Returns true if the supplied tag is a context-specific tag.
     289             :  */
     290     1733997 : constexpr bool IsContextTag(Tag tag)
     291             : {
     292     1733997 :     return ProfileIdFromTag(tag) == Tag::kSpecialTagProfileId && TagNumFromTag(tag) <= Tag::kContextTagMaxNum;
     293             : }
     294             : 
     295             : // TODO: move to private namespace
     296      317137 : constexpr bool IsSpecialTag(Tag tag)
     297             : {
     298      317137 :     return ProfileIdFromTag(tag) == Tag::kSpecialTagProfileId;
     299             : }
     300             : 
     301             : } // namespace TLV
     302             : } // namespace chip

Generated by: LCOV version 1.14