LCOV - code coverage report
Current view: top level - app/util - odd-sized-integers.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 0 44 0.0 %
Date: 2024-02-15 08:20:41 Functions: 0 56 0.0 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2021 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             : #pragma once
      19             : 
      20             : #include <app/util/attribute-storage-null-handling.h>
      21             : #include <lib/support/TypeTraits.h>
      22             : 
      23             : #include <limits>
      24             : 
      25             : namespace chip {
      26             : namespace app {
      27             : 
      28             : namespace detail {
      29             : template <int ByteSize, bool IsSigned>
      30             : struct WorkingTypeMapper
      31             : {
      32             : };
      33             : template <int ByteSize>
      34             : struct WorkingTypeMapper<ByteSize, true>
      35             : {
      36             :     using WorkingType = int64_t;
      37             : };
      38             : template <>
      39             : struct WorkingTypeMapper<3, true>
      40             : {
      41             :     using WorkingType = int32_t;
      42             : };
      43             : template <int ByteSize>
      44             : struct WorkingTypeMapper<ByteSize, false>
      45             : {
      46             :     using WorkingType = uint64_t;
      47             : };
      48             : template <>
      49             : struct WorkingTypeMapper<3, false>
      50             : {
      51             :     using WorkingType = uint32_t;
      52             : };
      53             : } // namespace detail
      54             : 
      55             : template <int ByteSize, bool IsSigned>
      56             : struct OddSizedInteger
      57             : {
      58             :     // WorkingType is the type we use to represent the value as an actual
      59             :     // integer that we can do arithmetic, greater/less-than compares, etc on.
      60             :     using WorkingType = typename detail::WorkingTypeMapper<ByteSize, IsSigned>::WorkingType;
      61             : 
      62             :     // StorageType is the type "at rest" in the attribute store.  It's a
      63             :     // native-endian byte buffer.
      64             :     using StorageType = uint8_t[ByteSize];
      65             : };
      66             : 
      67             : namespace detail {
      68             : template <int ByteSize, bool IsBigEndian>
      69             : struct IntegerByteIndexing;
      70             : 
      71             : template <int ByteSize>
      72             : struct IntegerByteIndexing<ByteSize, true>
      73             : {
      74             :     static constexpr int highIndex     = 0;
      75             :     static constexpr int lowIndex      = ByteSize - 1;
      76             :     static constexpr int lowerIndex    = 1;
      77             :     static constexpr int raiseIndex    = -1;
      78             :     static constexpr int pastLowIndex  = ByteSize;
      79             :     static constexpr int pastHighIndex = -1;
      80             : };
      81             : 
      82             : template <int ByteSize>
      83             : struct IntegerByteIndexing<ByteSize, false>
      84             : {
      85             :     static constexpr int highIndex     = ByteSize - 1;
      86             :     static constexpr int lowIndex      = 0;
      87             :     static constexpr int lowerIndex    = -1;
      88             :     static constexpr int raiseIndex    = 1;
      89             :     static constexpr int pastLowIndex  = -1;
      90             :     static constexpr int pastHighIndex = ByteSize;
      91             : };
      92             : } // namespace detail
      93             : 
      94             : template <int ByteSize, bool IsSigned, bool IsBigEndian>
      95             : struct NumericAttributeTraits<OddSizedInteger<ByteSize, IsSigned>, IsBigEndian> : detail::IntegerByteIndexing<ByteSize, IsBigEndian>
      96             : {
      97             :     using IntType = OddSizedInteger<ByteSize, IsSigned>;
      98             :     // StorageType is the type "at rest" in the attribute store.  It's a
      99             :     // native-endian byte buffer.
     100             :     using StorageType = typename IntType::StorageType;
     101             :     // WorkingType is the type we use to represent the value as an actual
     102             :     // integer that we can do arithmetic, greater/less-than compares, etc on.
     103             :     using WorkingType = typename IntType::WorkingType;
     104             : 
     105             :     using Indexing = detail::IntegerByteIndexing<ByteSize, IsBigEndian>;
     106             :     using Indexing::highIndex;
     107             :     using Indexing::lowerIndex;
     108             :     using Indexing::lowIndex;
     109             :     using Indexing::pastHighIndex;
     110             :     using Indexing::pastLowIndex;
     111             :     using Indexing::raiseIndex;
     112             : 
     113           0 :     static constexpr WorkingType StorageToWorking(StorageType storageValue)
     114             :     {
     115             :         // WorkingType can always fit all of our bit-shifting, because it has at
     116             :         // least one extra byte.
     117           0 :         WorkingType value = 0;
     118           0 :         for (int i = highIndex; i != pastLowIndex; i += lowerIndex)
     119             :         {
     120           0 :             value = (value << 8) | storageValue[i];
     121             :         }
     122             : 
     123             :         // If unsigned, we are done.  If signed, we need to make sure our high
     124             :         // bit gets treated as a sign bit, not a value bit, with our bits in 2s
     125             :         // complement.
     126             :         if (IsSigned)
     127             :         {
     128           0 :             constexpr WorkingType MaxPositive = (static_cast<WorkingType>(1) << (8 * ByteSize - 1)) - 1;
     129           0 :             if (value > MaxPositive)
     130             :             {
     131           0 :                 value = value - (static_cast<WorkingType>(1) << (8 * ByteSize));
     132             :             }
     133             :         }
     134             : 
     135           0 :         return value;
     136             :     }
     137             : 
     138           0 :     static constexpr void WorkingToStorage(WorkingType workingValue, StorageType & storageValue)
     139             :     {
     140             :         // We can just grab the low ByteSize bytes of workingValue.
     141           0 :         for (int i = lowIndex; i != pastHighIndex; i += raiseIndex)
     142             :         {
     143             :             // Casting to uint8_t exactly grabs the lowest byte.
     144           0 :             storageValue[i] = static_cast<uint8_t>(workingValue);
     145           0 :             workingValue    = workingValue >> 8;
     146             :         }
     147           0 :     }
     148             : 
     149           0 :     static constexpr bool IsNullValue(StorageType value)
     150             :     {
     151             :         if (IsSigned)
     152             :         {
     153             :             // Check for the equivalent of the most negative integer, in 2s
     154             :             // complement notation.
     155           0 :             if (value[highIndex] != 0x80)
     156             :             {
     157           0 :                 return false;
     158             :             }
     159           0 :             for (int i = highIndex + lowerIndex; i != pastLowIndex; i += lowerIndex)
     160             :             {
     161           0 :                 if (value[i] != 0x00)
     162             :                 {
     163           0 :                     return false;
     164             :                 }
     165             :             }
     166           0 :             return true;
     167             :         }
     168             : 
     169             :         // Check for the equivalent of the largest unsigned integer.
     170           0 :         for (int i = highIndex; i != pastLowIndex; i += lowerIndex)
     171             :         {
     172           0 :             if (value[i] != 0xFF)
     173             :             {
     174           0 :                 return false;
     175             :             }
     176             :         }
     177           0 :         return true;
     178             :     }
     179             : 
     180           0 :     static constexpr void SetNull(StorageType & value)
     181             :     {
     182             :         if (IsSigned)
     183             :         {
     184           0 :             value[highIndex] = 0x80;
     185           0 :             for (int i = highIndex + lowerIndex; i != pastLowIndex; i += lowerIndex)
     186             :             {
     187           0 :                 value[i] = 0x00;
     188             :             }
     189             :         }
     190             :         else
     191             :         {
     192           0 :             for (int i = highIndex; i != pastLowIndex; i += lowerIndex)
     193             :             {
     194           0 :                 value[i] = 0xFF;
     195             :             }
     196             :         }
     197           0 :     }
     198             : 
     199           0 :     static constexpr bool CanRepresentValue(bool isNullable, StorageType value) { return !isNullable || !IsNullValue(value); }
     200             : 
     201           0 :     static constexpr bool CanRepresentValue(bool isNullable, WorkingType value)
     202             :     {
     203             :         // Since WorkingType has at least one extra byte, none of our bitshifts
     204             :         // overflow.
     205             :         if (IsSigned)
     206             :         {
     207           0 :             WorkingType max = (static_cast<WorkingType>(1) << (8 * ByteSize - 1)) - 1;
     208           0 :             WorkingType min = -max;
     209           0 :             if (!isNullable)
     210             :             {
     211             :                 // We have one more value.
     212           0 :                 min -= 1;
     213             :             }
     214           0 :             return value >= min && value <= max;
     215             :         }
     216             : 
     217           0 :         WorkingType max = (static_cast<WorkingType>(1) << (8 * ByteSize)) - 1;
     218           0 :         if (isNullable)
     219             :         {
     220             :             // we have one less value
     221           0 :             max -= 1;
     222             :         }
     223           0 :         return value <= max;
     224             :     }
     225             : 
     226           0 :     static CHIP_ERROR Encode(TLV::TLVWriter & writer, TLV::Tag tag, StorageType value)
     227             :     {
     228           0 :         return writer.Put(tag, StorageToWorking(value));
     229             :     }
     230             : 
     231             :     static uint8_t * ToAttributeStoreRepresentation(StorageType & value) { return value; }
     232             : };
     233             : 
     234             : } // namespace app
     235             : } // namespace chip

Generated by: LCOV version 1.14