LCOV - code coverage report
Current view: top level - lib/support - ScopedBuffer.h (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 64 65 98.5 %
Date: 2024-02-15 08:20:41 Functions: 35 62 56.5 %

          Line data    Source code
       1             : /*
       2             :  *
       3             :  *    Copyright (c) 2020 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             : /**
      20             :  *    @file
      21             :  *      Defines scoped auto-free buffers for CHIP.
      22             :  *
      23             :  */
      24             : 
      25             : #pragma once
      26             : 
      27             : #include <lib/support/CHIPMem.h>
      28             : #include <lib/support/CodeUtils.h>
      29             : 
      30             : #include <type_traits>
      31             : #include <utility>
      32             : 
      33             : namespace chip {
      34             : namespace Platform {
      35             : 
      36             : namespace Impl {
      37             : 
      38             : /**
      39             :  * Represents a memory buffer that is auto-freed in the destructor.
      40             :  *
      41             :  * This class uses void* underneath on purpose (rather than a unique_ptr like
      42             :  * 'Type') and uses  templated type on Ptr(). This is to avoid template explosion
      43             :  * when the buffers are used for different types - only one implementation of
      44             :  * the class will be stored in flash.
      45             :  */
      46             : template <class Impl>
      47             : class ScopedMemoryBufferBase
      48             : {
      49             : public:
      50        9609 :     ScopedMemoryBufferBase() {}
      51             :     ScopedMemoryBufferBase(const ScopedMemoryBufferBase &)                   = delete;
      52             :     ScopedMemoryBufferBase & operator=(const ScopedMemoryBufferBase & other) = delete;
      53             : 
      54             :     ScopedMemoryBufferBase(ScopedMemoryBufferBase && other) { *this = std::move(other); }
      55             : 
      56        6039 :     ScopedMemoryBufferBase & operator=(ScopedMemoryBufferBase && other)
      57             :     {
      58        6039 :         if (this != &other)
      59             :         {
      60        6039 :             mBuffer       = other.mBuffer;
      61        6039 :             other.mBuffer = nullptr;
      62             :         }
      63        6039 :         return *this;
      64             :     }
      65             : 
      66        9609 :     ~ScopedMemoryBufferBase() { Free(); }
      67             : 
      68             :     /** Check if a buffer is valid */
      69         140 :     explicit operator bool() const { return mBuffer != nullptr; }
      70        5243 :     bool operator!() const { return mBuffer == nullptr; }
      71             : 
      72             :     /** Release memory used */
      73       19184 :     void Free()
      74             :     {
      75       19184 :         if (mBuffer == nullptr)
      76             :         {
      77       13399 :             return;
      78             :         }
      79        5785 :         Impl::MemoryFree(mBuffer);
      80        5785 :         mBuffer = nullptr;
      81             :     }
      82             : 
      83             : protected:
      84       12983 :     void * Ptr() { return mBuffer; }
      85        6232 :     const void * Ptr() const { return mBuffer; }
      86             : 
      87             :     /**
      88             :      * Releases the underlying buffer.
      89             :      *
      90             :      * The buffer stops being managed and will not be auto-freed.
      91             :      */
      92             :     CHECK_RETURN_VALUE void * Release()
      93             :     {
      94             :         void * buffer = mBuffer;
      95             :         mBuffer       = nullptr;
      96             :         return buffer;
      97             :     }
      98             : 
      99        4148 :     void Alloc(size_t size)
     100             :     {
     101        4148 :         Free();
     102        4148 :         mBuffer = Impl::MemoryAlloc(size);
     103        4148 :     }
     104             : 
     105        3753 :     void Calloc(size_t elementCount, size_t elementSize)
     106             :     {
     107        3753 :         Free();
     108        3753 :         mBuffer = Impl::MemoryCalloc(elementCount, elementSize);
     109        3753 :     }
     110             : 
     111             : private:
     112             :     void * mBuffer = nullptr;
     113             : };
     114             : 
     115             : /**
     116             :  * Helper class that forwards memory management tasks to Platform::Memory* calls.
     117             :  */
     118             : class PlatformMemoryManagement
     119             : {
     120             : public:
     121        5785 :     static void MemoryFree(void * p) { chip::Platform::MemoryFree(p); }
     122        4148 :     static void * MemoryAlloc(size_t size) { return chip::Platform::MemoryAlloc(size); }
     123        3753 :     static void * MemoryCalloc(size_t num, size_t size) { return chip::Platform::MemoryCalloc(num, size); }
     124             : };
     125             : 
     126             : } // namespace Impl
     127             : 
     128             : /**
     129             :  * Represents a memory buffer allocated using chip::Platform::Memory*Alloc
     130             :  * methods.
     131             :  *
     132             :  * Use for RAII to auto-free after use.
     133             :  */
     134             : template <typename T, class MemoryManagement = Impl::PlatformMemoryManagement>
     135             : class ScopedMemoryBuffer : public Impl::ScopedMemoryBufferBase<MemoryManagement>
     136             : {
     137             :     friend class Impl::ScopedMemoryBufferBase<MemoryManagement>;
     138             : 
     139             : public:
     140             :     using Base = Impl::ScopedMemoryBufferBase<MemoryManagement>;
     141             : 
     142             :     static_assert(std::is_trivially_destructible<T>::value, "Destructors won't get run");
     143             : 
     144       12687 :     T * Get() { return static_cast<T *>(Base::Ptr()); }
     145         183 :     T & operator[](size_t index) { return Get()[index]; }
     146             : 
     147        6232 :     const T * Get() const { return static_cast<const T *>(Base::Ptr()); }
     148           0 :     const T & operator[](size_t index) const { return Get()[index]; }
     149             : 
     150             :     /**
     151             :      * Releases the underlying buffer.
     152             :      *
     153             :      * The buffer stops being managed and will not be auto-freed.
     154             :      */
     155             :     CHECK_RETURN_VALUE T * Release() { return static_cast<T *>(Base::Release()); }
     156             : 
     157        3718 :     ScopedMemoryBuffer & Calloc(size_t elementCount)
     158             :     {
     159        3718 :         Base::Calloc(elementCount, sizeof(T));
     160        3718 :         ExecuteConstructors(elementCount);
     161        3718 :         return *this;
     162             :     }
     163             : 
     164        4143 :     ScopedMemoryBuffer & Alloc(size_t elementCount)
     165             :     {
     166        4143 :         Base::Alloc(elementCount * sizeof(T));
     167        4143 :         ExecuteConstructors(elementCount);
     168        4143 :         return *this;
     169             :     }
     170             : 
     171             : private:
     172             :     template <typename U = T, std::enable_if_t<std::is_trivial<U>::value, int> = 0>
     173        7546 :     void ExecuteConstructors(size_t elementCount)
     174             :     {
     175             :         // Do nothing if our type is trivial.  In particular, if we are a buffer
     176             :         // of integers, we should not go zero-initializing them here: either
     177             :         // caller wants that and called Calloc(), or it doesn't and we shouldn't
     178             :         // do it.
     179        7546 :     }
     180             : 
     181             :     template <typename U = T, std::enable_if_t<!std::is_trivial<U>::value, int> = 0>
     182             :     void ExecuteConstructors(size_t elementCount)
     183             :     {
     184             :         T * elementPtr = Get();
     185             :         if (elementPtr == nullptr)
     186             :         {
     187             :             // Alloc failed, don't bother.
     188             :             return;
     189             :         }
     190             :         for (size_t i = 0; i < elementCount; ++i)
     191             :         {
     192             :             new (&elementPtr[i]) T();
     193             :         }
     194             :     }
     195             : };
     196             : 
     197             : /**
     198             :  * Represents a memory buffer with buffer size allocated using chip::Platform::Memory*Alloc
     199             :  * methods.
     200             :  *
     201             :  * Use for RAII to auto-free after use.
     202             :  */
     203             : template <typename T>
     204             : class ScopedMemoryBufferWithSize : public ScopedMemoryBuffer<T>
     205             : {
     206             : public:
     207           5 :     ScopedMemoryBufferWithSize() {}
     208         148 :     ScopedMemoryBufferWithSize(ScopedMemoryBufferWithSize && other) { *this = std::move(other); }
     209             : 
     210        2106 :     ScopedMemoryBufferWithSize & operator=(ScopedMemoryBufferWithSize && other)
     211             :     {
     212        2106 :         if (this != &other)
     213             :         {
     214        2106 :             mCount       = other.mCount;
     215        2106 :             other.mCount = 0;
     216             :         }
     217        2106 :         ScopedMemoryBuffer<T>::operator=(std::move(other));
     218        2106 :         return *this;
     219             :     }
     220             : 
     221           5 :     ~ScopedMemoryBufferWithSize() { mCount = 0; }
     222             : 
     223             :     // return the size as count of elements
     224        3943 :     inline size_t AllocatedSize() const { return mCount; }
     225             : 
     226         676 :     void Free()
     227             :     {
     228         676 :         mCount = 0;
     229         676 :         ScopedMemoryBuffer<T>::Free();
     230         676 :     }
     231             : 
     232             :     /**
     233             :      * Releases the underlying buffer.
     234             :      *
     235             :      * The buffer stops being managed and will not be auto-freed.
     236             :      */
     237             :     CHECK_RETURN_VALUE T * Release()
     238             :     {
     239             :         T * buffer = ScopedMemoryBuffer<T>::Release();
     240             :         mCount     = 0;
     241             :         return buffer;
     242             :     }
     243             : 
     244         130 :     ScopedMemoryBufferWithSize & Calloc(size_t elementCount)
     245             :     {
     246         130 :         ScopedMemoryBuffer<T>::Calloc(elementCount);
     247         130 :         if (this->Get() != nullptr)
     248             :         {
     249         130 :             mCount = elementCount;
     250             :         }
     251         130 :         return *this;
     252             :     }
     253             : 
     254        1611 :     ScopedMemoryBufferWithSize & Alloc(size_t elementCount)
     255             :     {
     256        1611 :         ScopedMemoryBuffer<T>::Alloc(elementCount);
     257        1611 :         if (this->Get() != nullptr)
     258             :         {
     259        1611 :             mCount = elementCount;
     260             :         }
     261        1611 :         return *this;
     262             :     }
     263             : 
     264             : private:
     265             :     size_t mCount = 0;
     266             : };
     267             : 
     268             : } // namespace Platform
     269             : } // namespace chip

Generated by: LCOV version 1.14