Matter SDK Coverage Report
Current view: top level - app/reporting - Generations.h (source / functions) Coverage Total Hit
Test: SHA:e021a368d10ac6f3f201c101585146211fdcdaa2 Lines: 92.9 % 14 13
Test Date: 2026-02-13 08:13:38 Functions: 100.0 % 9 9

            Line data    Source code
       1              : /*
       2              :  *    Copyright (c) 2026 Project CHIP Authors
       3              :  *    All rights reserved.
       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              : #pragma once
      18              : 
      19              : #include <cstdint>
      20              : 
      21              : namespace chip::app::reporting {
      22              : 
      23              : // u32 generations can generally wrap around. We try to do a best effort figuring out
      24              : // if First < Second considering wrap-around. So we cast their difference to i32 and
      25              : // see if that is positive.
      26         4818 : inline constexpr bool AreGenerationsInOrder(uint32_t generationFirst, uint32_t generationSecond)
      27              : {
      28         4818 :     return static_cast<int32_t>(generationSecond - generationFirst) > 0;
      29              : }
      30              : 
      31              : // essentially our unit tests
      32              : static_assert(AreGenerationsInOrder(1, 100));
      33              : static_assert(!AreGenerationsInOrder(100, 1));
      34              : 
      35              : static_assert(AreGenerationsInOrder(0xFFFFFFAB, 120));
      36              : static_assert(!AreGenerationsInOrder(120, 0xFFFFFFAB));
      37              : 
      38              : static_assert(AreGenerationsInOrder(1, 0x7FFFFFFF));
      39              : static_assert(!AreGenerationsInOrder(0x7FFFFFFF, 1));
      40              : 
      41              : // random increases from small numbers
      42              : static_assert(AreGenerationsInOrder(2, 0x80000000));
      43              : static_assert(AreGenerationsInOrder(100, 0x80000000));
      44              : static_assert(AreGenerationsInOrder(1000, 0x800000AB));
      45              : 
      46              : // wrap-arounds
      47              : static_assert(AreGenerationsInOrder(0x80000000 + 1000, 900));
      48              : static_assert(AreGenerationsInOrder(0x80000000 + 0x12345, 0x12344));
      49              : 
      50              : /// Represents a generation of an attribute. A thin wrapper around `uint32_t` that intentionally does not
      51              : /// provide an implicit conversion operator back to `uint32_t`, ensuring that callers use
      52              : /// wrap-around-aware comparison logic (e.g. `Before`/`After`) instead of
      53              : /// raw integer comparisons which would break at the 2^32-1 boundary.
      54              : ///
      55              : /// Note: usage of uint32_t is intentional to minimize size overhead. For example, in
      56              : /// `struct AttributePathParamsWithGeneration` (defined in Engine.h), using 32-bit generations
      57              : /// keeps the structure size at 16 bytes.
      58              : ///
      59              : /// The size breakdown is as follows:
      60              : /// - Base `AttributePathParams`: 12 bytes (4-byte ClusterId, 4-byte AttributeId,
      61              : ///   2-byte EndpointId, 2-byte ListIndex).
      62              : /// - Current: Adding a 4-byte `AttributeGeneration` results in a total of 16 bytes.
      63              : /// - Hypothetical: If this were 64-bit, the compiler would insert 4 bytes of alignment
      64              : ///   padding after the 12-byte base to satisfy the 8-byte alignment requirement for
      65              : ///   the uint64_t, resulting in 24 bytes (12 + 4 + 8) — a 50% increase in size.
      66              : ///
      67              : /// On typical 32-bit MCU targets used by this stack, using 32-bit arithmetic instead of
      68              : /// 64-bit handling often results in smaller generated code, helping reduce flash usage.
      69              : /// The value 0 is reserved as a "not defined" marker and is skipped during increment.
      70              : class AttributeGeneration
      71              : {
      72              : public:
      73         4641 :     explicit AttributeGeneration(uint32_t value) : mValue(value) {}
      74              : 
      75          240 :     AttributeGeneration()                            = default;
      76              :     AttributeGeneration(const AttributeGeneration &) = default;
      77              :     AttributeGeneration(AttributeGeneration &&)      = default;
      78              : 
      79              :     AttributeGeneration & operator=(const AttributeGeneration &) = default;
      80              :     AttributeGeneration & operator=(AttributeGeneration &&)      = default;
      81              : 
      82           28 :     constexpr bool Before(const AttributeGeneration & other) const { return AreGenerationsInOrder(mValue, other.mValue); }
      83         4790 :     constexpr bool After(const AttributeGeneration & other) const { return AreGenerationsInOrder(other.mValue, mValue); }
      84              : 
      85              :     // zero is a special marker, generally may be used as "not defined"
      86          128 :     constexpr bool IsZero() const { return mValue == 0; }
      87              : 
      88              :     // reset to zero value (since zero is used as a special/uninitialized marker)
      89           28 :     void Clear() { mValue = 0; }
      90              : 
      91         3960 :     uint32_t Raw() const { return mValue; }
      92              : 
      93              :     // increment, guarantees 0 is NOT used as a value when incrementing and wrapping around
      94         5413 :     void Increment()
      95              :     {
      96         5413 :         mValue++;
      97         5413 :         if (mValue == 0)
      98              :         {
      99            0 :             mValue = 1;
     100              :         }
     101         5413 :     }
     102              : 
     103              : private:
     104              :     uint32_t mValue{};
     105              : };
     106              : 
     107              : } // namespace chip::app::reporting
        

Generated by: LCOV version 2.0-1