LCOV - code coverage report
Current view: top level - mfbt - MaybeOneOf.h (source / functions) Hit Total Coverage
Test: output.info Lines: 33 33 100.0 %
Date: 2017-07-14 16:53:18 Functions: 40 58 69.0 %
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             :  * A class storing one of two optional value types that supports in-place lazy
       9             :  * construction.
      10             :  */
      11             : 
      12             : #ifndef mozilla_MaybeOneOf_h
      13             : #define mozilla_MaybeOneOf_h
      14             : 
      15             : #include "mozilla/Assertions.h"
      16             : #include "mozilla/Move.h"
      17             : #include "mozilla/OperatorNewExtensions.h"
      18             : #include "mozilla/TemplateLib.h"
      19             : 
      20             : #include <new> // for placement new
      21             : #include <stddef.h> // for size_t
      22             : 
      23             : namespace mozilla {
      24             : 
      25             : /*
      26             :  * MaybeOneOf<T1, T2> is like Maybe, but it supports constructing either T1
      27             :  * or T2. When a MaybeOneOf<T1, T2> is constructed, it is |empty()|, i.e.,
      28             :  * no value has been constructed and no destructor will be called when the
      29             :  * MaybeOneOf<T1, T2> is destroyed. Upon calling |construct<T1>()| or
      30             :  * |construct<T2>()|, a T1 or T2 object will be constructed with the given
      31             :  * arguments and that object will be destroyed when the owning MaybeOneOf is
      32             :  * destroyed.
      33             :  *
      34             :  * Because MaybeOneOf must be aligned suitable to hold any value stored within
      35             :  * it, and because |alignas| requirements don't affect platform ABI with respect
      36             :  * to how parameters are laid out in memory, MaybeOneOf can't be used as the
      37             :  * type of a function parameter.  Pass MaybeOneOf to functions by pointer or
      38             :  * reference instead.
      39             :  */
      40             : template<class T1, class T2>
      41             : class MOZ_NON_PARAM MaybeOneOf
      42             : {
      43             :   static constexpr size_t StorageAlignment =
      44             :     tl::Max<alignof(T1), alignof(T2)>::value;
      45             :   static constexpr size_t StorageSize =
      46             :     tl::Max<sizeof(T1), sizeof(T2)>::value;
      47             : 
      48             :   alignas(StorageAlignment) unsigned char storage[StorageSize];
      49             : 
      50             :   // GCC fails due to -Werror=strict-aliasing if |storage| is directly cast to
      51             :   // T*.  Indirecting through these functions addresses the problem.
      52      138861 :   void* data() { return storage; }
      53       31854 :   const void* data() const { return storage; }
      54             : 
      55             :   enum State { None, SomeT1, SomeT2 } state;
      56             :   template <class T, class Ignored = void> struct Type2State {};
      57             : 
      58             :   template <class T>
      59      114032 :   T& as()
      60             :   {
      61      114032 :     MOZ_ASSERT(state == Type2State<T>::result);
      62      114032 :     return *static_cast<T*>(data());
      63             :   }
      64             : 
      65             :   template <class T>
      66       31854 :   const T& as() const
      67             :   {
      68       31854 :     MOZ_ASSERT(state == Type2State<T>::result);
      69       31854 :     return *static_cast<const T*>(data());
      70             :   }
      71             : 
      72             : public:
      73       25090 :   MaybeOneOf() : state(None) {}
      74       24777 :   ~MaybeOneOf() { destroyIfConstructed(); }
      75             : 
      76             :   MaybeOneOf(MaybeOneOf&& rhs)
      77             :     : state(None)
      78             :   {
      79             :     if (!rhs.empty()) {
      80             :       if (rhs.constructed<T1>()) {
      81             :         construct<T1>(Move(rhs.as<T1>()));
      82             :         rhs.as<T1>().~T1();
      83             :       } else {
      84             :         construct<T2>(Move(rhs.as<T2>()));
      85             :         rhs.as<T2>().~T2();
      86             :       }
      87             :       rhs.state = None;
      88             :     }
      89             :   }
      90             : 
      91             :   MaybeOneOf& operator=(MaybeOneOf&& rhs)
      92             :   {
      93             :     MOZ_ASSERT(this != &rhs, "Self-move is prohibited");
      94             :     this->~MaybeOneOf();
      95             :     new(this) MaybeOneOf(Move(rhs));
      96             :     return *this;
      97             :   }
      98             : 
      99       24795 :   bool empty() const { return state == None; }
     100             : 
     101             :   template <class T>
     102      103093 :   bool constructed() const { return state == Type2State<T>::result; }
     103             : 
     104             :   template <class T, class... Args>
     105       24829 :   void construct(Args&&... aArgs)
     106             :   {
     107       24829 :     MOZ_ASSERT(state == None);
     108       24829 :     state = Type2State<T>::result;
     109       24829 :     ::new (KnownNotNull, data()) T(Forward<Args>(aArgs)...);
     110       24829 :   }
     111             : 
     112             :   template <class T>
     113       89221 :   T& ref()
     114             :   {
     115       89221 :     return as<T>();
     116             :   }
     117             : 
     118             :   template <class T>
     119       31854 :   const T& ref() const
     120             :   {
     121       31854 :     return as<T>();
     122             :   }
     123             : 
     124       24811 :   void destroy()
     125             :   {
     126       24811 :     MOZ_ASSERT(state == SomeT1 || state == SomeT2);
     127       24811 :     if (state == SomeT1) {
     128       24794 :       as<T1>().~T1();
     129          17 :     } else if (state == SomeT2) {
     130          17 :       as<T2>().~T2();
     131             :     }
     132       24811 :     state = None;
     133       24811 :   }
     134             : 
     135       24777 :   void destroyIfConstructed()
     136             :   {
     137       24777 :     if (!empty()) {
     138       24776 :       destroy();
     139             :     }
     140       24777 :   }
     141             : 
     142             : private:
     143             :   MaybeOneOf(const MaybeOneOf& aOther) = delete;
     144             :   const MaybeOneOf& operator=(const MaybeOneOf& aOther) = delete;
     145             : };
     146             : 
     147             : template <class T1, class T2>
     148             : template <class Ignored>
     149             : struct MaybeOneOf<T1, T2>::Type2State<T1, Ignored>
     150             : {
     151             :   typedef MaybeOneOf<T1, T2> Enclosing;
     152             :   static const typename Enclosing::State result = Enclosing::SomeT1;
     153             : };
     154             : 
     155             : template <class T1, class T2>
     156             : template <class Ignored>
     157             : struct MaybeOneOf<T1, T2>::Type2State<T2, Ignored>
     158             : {
     159             :   typedef MaybeOneOf<T1, T2> Enclosing;
     160             :   static const typename Enclosing::State result = Enclosing::SomeT2;
     161             : };
     162             : 
     163             : } // namespace mozilla
     164             : 
     165             : #endif /* mozilla_MaybeOneOf_h */

Generated by: LCOV version 1.13