LCOV - code coverage report
Current view: top level - mfbt - RangedPtr.h (source / functions) Hit Total Coverage
Test: output.info Lines: 86 91 94.5 %
Date: 2017-07-14 16:53:18 Functions: 123 166 74.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /*
       8             :  * Implements a smart pointer asserted to remain within a range specified at
       9             :  * construction.
      10             :  */
      11             : 
      12             : #ifndef mozilla_RangedPtr_h
      13             : #define mozilla_RangedPtr_h
      14             : 
      15             : #include "mozilla/ArrayUtils.h"
      16             : #include "mozilla/Assertions.h"
      17             : #include "mozilla/Attributes.h"
      18             : 
      19             : #include <stdint.h>
      20             : 
      21             : namespace mozilla {
      22             : 
      23             : /*
      24             :  * RangedPtr is a smart pointer restricted to an address range specified at
      25             :  * creation.  The pointer (and any smart pointers derived from it) must remain
      26             :  * within the range [start, end] (inclusive of end to facilitate use as
      27             :  * sentinels).  Dereferencing or indexing into the pointer (or pointers derived
      28             :  * from it) must remain within the range [start, end).  All the standard pointer
      29             :  * operators are defined on it; in debug builds these operations assert that the
      30             :  * range specified at construction is respected.
      31             :  *
      32             :  * In theory passing a smart pointer instance as an argument can be slightly
      33             :  * slower than passing a T* (due to ABI requirements for passing structs versus
      34             :  * passing pointers), if the method being called isn't inlined.  If you are in
      35             :  * extremely performance-critical code, you may want to be careful using this
      36             :  * smart pointer as an argument type.
      37             :  *
      38             :  * RangedPtr<T> intentionally does not implicitly convert to T*.  Use get() to
      39             :  * explicitly convert to T*.  Keep in mind that the raw pointer of course won't
      40             :  * implement bounds checking in debug builds.
      41             :  */
      42             : template<typename T>
      43             : class RangedPtr
      44             : {
      45             :   T* mPtr;
      46             : 
      47             : #ifdef DEBUG
      48             :   T* const mRangeStart;
      49             :   T* const mRangeEnd;
      50             : #endif
      51             : 
      52     1676850 :   void checkSanity()
      53             :   {
      54     1676850 :     MOZ_ASSERT(mRangeStart <= mPtr);
      55     1676850 :     MOZ_ASSERT(mPtr <= mRangeEnd);
      56     1676850 :   }
      57             : 
      58             :   /* Creates a new pointer for |aPtr|, restricted to this pointer's range. */
      59     1385169 :   RangedPtr<T> create(T* aPtr) const
      60             :   {
      61             : #ifdef DEBUG
      62     1385169 :     return RangedPtr<T>(aPtr, mRangeStart, mRangeEnd);
      63             : #else
      64             :     return RangedPtr<T>(aPtr, nullptr, size_t(0));
      65             : #endif
      66             :   }
      67             : 
      68      258446 :   uintptr_t asUintptr() const { return reinterpret_cast<uintptr_t>(mPtr); }
      69             : 
      70             : public:
      71     1523746 :   RangedPtr(T* aPtr, T* aStart, T* aEnd)
      72             :     : mPtr(aPtr)
      73             : #ifdef DEBUG
      74     1523746 :     , mRangeStart(aStart), mRangeEnd(aEnd)
      75             : #endif
      76             :   {
      77     1523746 :     MOZ_ASSERT(mRangeStart <= mRangeEnd);
      78     1523746 :     checkSanity();
      79     1523747 :   }
      80        2625 :   RangedPtr(T* aPtr, T* aStart, size_t aLength)
      81             :     : mPtr(aPtr)
      82             : #ifdef DEBUG
      83        2625 :     , mRangeStart(aStart), mRangeEnd(aStart + aLength)
      84             : #endif
      85             :   {
      86         700 :     MOZ_ASSERT(aLength <= size_t(-1) / sizeof(T));
      87        2625 :     MOZ_ASSERT(reinterpret_cast<uintptr_t>(mRangeStart) + aLength * sizeof(T) >=
      88             :                reinterpret_cast<uintptr_t>(mRangeStart));
      89        2625 :     checkSanity();
      90        2625 :   }
      91             : 
      92             :   /* Equivalent to RangedPtr(aPtr, aPtr, aLength). */
      93       12762 :   RangedPtr(T* aPtr, size_t aLength)
      94             :     : mPtr(aPtr)
      95             : #ifdef DEBUG
      96       12762 :     , mRangeStart(aPtr), mRangeEnd(aPtr + aLength)
      97             : #endif
      98             :   {
      99        1019 :     MOZ_ASSERT(aLength <= size_t(-1) / sizeof(T));
     100       12762 :     MOZ_ASSERT(reinterpret_cast<uintptr_t>(mRangeStart) + aLength * sizeof(T) >=
     101             :                reinterpret_cast<uintptr_t>(mRangeStart));
     102       12762 :     checkSanity();
     103       12762 :   }
     104             : 
     105             :   /* Equivalent to RangedPtr(aArr, aArr, N). */
     106             :   template<size_t N>
     107             :   explicit RangedPtr(T (&aArr)[N])
     108             :     : mPtr(aArr)
     109             : #ifdef DEBUG
     110             :     , mRangeStart(aArr), mRangeEnd(aArr + N)
     111             : #endif
     112             :   {
     113             :     checkSanity();
     114             :   }
     115             : 
     116       60243 :   T* get() const { return mPtr; }
     117             : 
     118           0 :   explicit operator bool() const { return mPtr != nullptr; }
     119             : 
     120      137403 :   void checkIdenticalRange(const RangedPtr<T>& aOther) const
     121             :   {
     122      137403 :     MOZ_ASSERT(mRangeStart == aOther.mRangeStart);
     123      137403 :     MOZ_ASSERT(mRangeEnd == aOther.mRangeEnd);
     124      137403 :   }
     125             : 
     126             :   /*
     127             :    * You can only assign one RangedPtr into another if the two pointers have
     128             :    * the same valid range:
     129             :    *
     130             :    *   char arr1[] = "hi";
     131             :    *   char arr2[] = "bye";
     132             :    *   RangedPtr<char> p1(arr1, 2);
     133             :    *   p1 = RangedPtr<char>(arr1 + 1, arr1, arr1 + 2); // works
     134             :    *   p1 = RangedPtr<char>(arr2, 3);                  // asserts
     135             :    */
     136      137191 :   RangedPtr<T>& operator=(const RangedPtr<T>& aOther)
     137             :   {
     138      137191 :     checkIdenticalRange(aOther);
     139      137191 :     mPtr = aOther.mPtr;
     140      137191 :     checkSanity();
     141      137191 :     return *this;
     142             :   }
     143             : 
     144      127132 :   RangedPtr<T> operator+(size_t aInc) const
     145             :   {
     146       24370 :     MOZ_ASSERT(aInc <= size_t(-1) / sizeof(T));
     147      127132 :     MOZ_ASSERT(asUintptr() + aInc * sizeof(T) >= asUintptr());
     148      127132 :     return create(mPtr + aInc);
     149             :   }
     150             : 
     151        2091 :   RangedPtr<T> operator-(size_t aDec) const
     152             :   {
     153           2 :     MOZ_ASSERT(aDec <= size_t(-1) / sizeof(T));
     154        2091 :     MOZ_ASSERT(asUintptr() - aDec * sizeof(T) <= asUintptr());
     155        2091 :     return create(mPtr - aDec);
     156             :   }
     157             : 
     158             :   /*
     159             :    * You can assign a raw pointer into a RangedPtr if the raw pointer is
     160             :    * within the range specified at creation.
     161             :    */
     162             :   template <typename U>
     163             :   RangedPtr<T>& operator=(U* aPtr)
     164             :   {
     165             :     *this = create(aPtr);
     166             :     return *this;
     167             :   }
     168             : 
     169             :   template <typename U>
     170             :   RangedPtr<T>& operator=(const RangedPtr<U>& aPtr)
     171             :   {
     172             :     MOZ_ASSERT(mRangeStart <= aPtr.mPtr);
     173             :     MOZ_ASSERT(aPtr.mPtr <= mRangeEnd);
     174             :     mPtr = aPtr.mPtr;
     175             :     checkSanity();
     176             :     return *this;
     177             :   }
     178             : 
     179      126414 :   RangedPtr<T>& operator++()
     180             :   {
     181      126414 :     return (*this += 1);
     182             :   }
     183             : 
     184       98976 :   RangedPtr<T> operator++(int)
     185             :   {
     186       98976 :     RangedPtr<T> rcp = *this;
     187       98976 :     ++*this;
     188       98976 :     return rcp;
     189             :   }
     190             : 
     191        1626 :   RangedPtr<T>& operator--()
     192             :   {
     193        1626 :     return (*this -= 1);
     194             :   }
     195             : 
     196           0 :   RangedPtr<T> operator--(int)
     197             :   {
     198           0 :     RangedPtr<T> rcp = *this;
     199           0 :     --*this;
     200           0 :     return rcp;
     201             :   }
     202             : 
     203      126502 :   RangedPtr<T>& operator+=(size_t aInc)
     204             :   {
     205      126502 :     *this = *this + aInc;
     206      126502 :     return *this;
     207             :   }
     208             : 
     209        1626 :   RangedPtr<T>& operator-=(size_t aDec)
     210             :   {
     211        1626 :     *this = *this - aDec;
     212        1626 :     return *this;
     213             :   }
     214             : 
     215     1253176 :   T& operator[](int aIndex) const
     216             :   {
     217      400479 :     MOZ_ASSERT(size_t(aIndex > 0 ? aIndex : -aIndex) <= size_t(-1) / sizeof(T));
     218     1253176 :     return *create(mPtr + aIndex);
     219             :   }
     220             : 
     221     1461374 :   T& operator*() const
     222             :   {
     223     1461374 :     MOZ_ASSERT(mPtr >= mRangeStart);
     224     1461374 :     MOZ_ASSERT(mPtr < mRangeEnd);
     225     1461374 :     return *mPtr;
     226             :   }
     227             : 
     228           6 :   T* operator->() const
     229             :   {
     230           6 :     MOZ_ASSERT(mPtr >= mRangeStart);
     231           6 :     MOZ_ASSERT(mPtr < mRangeEnd);
     232           6 :     return mPtr;
     233             :   }
     234             : 
     235             :   template <typename U>
     236       34062 :   bool operator==(const RangedPtr<U>& aOther) const
     237             :   {
     238       34062 :     return mPtr == aOther.mPtr;
     239             :   }
     240             :   template <typename U>
     241       23892 :   bool operator!=(const RangedPtr<U>& aOther) const
     242             :   {
     243       23892 :     return !(*this == aOther);
     244             :   }
     245             : 
     246             :   template<typename U>
     247           4 :   bool operator==(const U* u) const
     248             :   {
     249           4 :     return mPtr == u;
     250             :   }
     251             :   template<typename U>
     252           4 :   bool operator!=(const U* u) const
     253             :   {
     254           4 :     return !(*this == u);
     255             :   }
     256             : 
     257             :   template <typename U>
     258       28241 :   bool operator<(const RangedPtr<U>& aOther) const
     259             :   {
     260       28241 :     return mPtr < aOther.mPtr;
     261             :   }
     262             :   template <typename U>
     263         222 :   bool operator<=(const RangedPtr<U>& aOther) const
     264             :   {
     265         222 :     return mPtr <= aOther.mPtr;
     266             :   }
     267             : 
     268             :   template <typename U>
     269         208 :   bool operator>(const RangedPtr<U>& aOther) const
     270             :   {
     271         208 :     return mPtr > aOther.mPtr;
     272             :   }
     273             :   template <typename U>
     274        1119 :   bool operator>=(const RangedPtr<U>& aOther) const
     275             :   {
     276        1119 :     return mPtr >= aOther.mPtr;
     277             :   }
     278             : 
     279      907928 :   size_t operator-(const RangedPtr<T>& aOther) const
     280             :   {
     281      907928 :     MOZ_ASSERT(mPtr >= aOther.mPtr);
     282      907928 :     return PointerRangeSize(aOther.mPtr, mPtr);
     283             :   }
     284             : 
     285             : private:
     286             :   RangedPtr() = delete;
     287             : };
     288             : 
     289             : } /* namespace mozilla */
     290             : 
     291             : #endif /* mozilla_RangedPtr_h */

Generated by: LCOV version 1.13