LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/base - optional.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 84 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 354 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright 2015 The WebRTC Project Authors. All rights reserved.
       3             :  *
       4             :  *  Use of this source code is governed by a BSD-style license
       5             :  *  that can be found in the LICENSE file in the root of the source
       6             :  *  tree. An additional intellectual property rights grant can be found
       7             :  *  in the file PATENTS.  All contributing project authors may
       8             :  *  be found in the AUTHORS file in the root of the source tree.
       9             :  */
      10             : 
      11             : #ifndef WEBRTC_BASE_OPTIONAL_H_
      12             : #define WEBRTC_BASE_OPTIONAL_H_
      13             : 
      14             : #include <algorithm>
      15             : #include <memory>
      16             : #include <utility>
      17             : 
      18             : #include "webrtc/base/array_view.h"
      19             : #include "webrtc/base/checks.h"
      20             : #include "webrtc/base/sanitizer.h"
      21             : 
      22             : namespace rtc {
      23             : 
      24             : namespace optional_internal {
      25             : 
      26             : #if RTC_HAS_ASAN
      27             : 
      28             : // This is a non-inlined function. The optimizer can't see inside it.
      29             : void* FunctionThatDoesNothingImpl(void*);
      30             : 
      31             : template <typename T>
      32             : inline T* FunctionThatDoesNothing(T* x) {
      33             :   return reinterpret_cast<T*>(
      34             :       FunctionThatDoesNothingImpl(reinterpret_cast<void*>(x)));
      35             : }
      36             : 
      37             : #else
      38             : 
      39             : template <typename T>
      40           0 : inline T* FunctionThatDoesNothing(T* x) { return x; }
      41             : 
      42             : #endif
      43             : 
      44             : }  // namespace optional_internal
      45             : 
      46             : // Simple std::optional-wannabe. It either contains a T or not.
      47             : //
      48             : // A moved-from Optional<T> may only be destroyed, and assigned to if T allows
      49             : // being assigned to after having been moved from. Specifically, you may not
      50             : // assume that it just doesn't contain a value anymore.
      51             : //
      52             : // Examples of good places to use Optional:
      53             : //
      54             : // - As a class or struct member, when the member doesn't always have a value:
      55             : //     struct Prisoner {
      56             : //       std::string name;
      57             : //       Optional<int> cell_number;  // Empty if not currently incarcerated.
      58             : //     };
      59             : //
      60             : // - As a return value for functions that may fail to return a value on all
      61             : //   allowed inputs. For example, a function that searches an array might
      62             : //   return an Optional<size_t> (the index where it found the element, or
      63             : //   nothing if it didn't find it); and a function that parses numbers might
      64             : //   return Optional<double> (the parsed number, or nothing if parsing failed).
      65             : //
      66             : // Examples of bad places to use Optional:
      67             : //
      68             : // - As a return value for functions that may fail because of disallowed
      69             : //   inputs. For example, a string length function should not return
      70             : //   Optional<size_t> so that it can return nothing in case the caller passed
      71             : //   it a null pointer; the function should probably use RTC_[D]CHECK instead,
      72             : //   and return plain size_t.
      73             : //
      74             : // - As a return value for functions that may fail to return a value on all
      75             : //   allowed inputs, but need to tell the caller what went wrong. Returning
      76             : //   Optional<double> when parsing a single number as in the example above
      77             : //   might make sense, but any larger parse job is probably going to need to
      78             : //   tell the caller what the problem was, not just that there was one.
      79             : //
      80             : // - As a non-mutable function argument. When you want to pass a value of a
      81             : //   type T that can fail to be there, const T* is almost always both fastest
      82             : //   and cleanest. (If you're *sure* that the the caller will always already
      83             : //   have an Optional<T>, const Optional<T>& is slightly faster than const T*,
      84             : //   but this is a micro-optimization. In general, stick to const T*.)
      85             : //
      86             : // TODO(kwiberg): Get rid of this class when the standard library has
      87             : // std::optional (and we're allowed to use it).
      88             : template <typename T>
      89             : class Optional final {
      90             :  public:
      91             :   // Construct an empty Optional.
      92           0 :   Optional() : has_value_(false), empty_('\0') {
      93           0 :     PoisonValue();
      94           0 :   }
      95             : 
      96             :   // Construct an Optional that contains a value.
      97           0 :   explicit Optional(const T& value) : has_value_(true) {
      98           0 :     new (&value_) T(value);
      99           0 :   }
     100           0 :   explicit Optional(T&& value) : has_value_(true) {
     101           0 :     new (&value_) T(std::move(value));
     102           0 :   }
     103             : 
     104             :   // Copy constructor: copies the value from m if it has one.
     105           0 :   Optional(const Optional& m) : has_value_(m.has_value_) {
     106           0 :     if (has_value_)
     107           0 :       new (&value_) T(m.value_);
     108             :     else
     109           0 :       PoisonValue();
     110           0 :   }
     111             : 
     112             :   // Move constructor: if m has a value, moves the value from m, leaving m
     113             :   // still in a state where it has a value, but a moved-from one (the
     114             :   // properties of which depends on T; the only general guarantee is that we
     115             :   // can destroy m).
     116           0 :   Optional(Optional&& m) : has_value_(m.has_value_) {
     117           0 :     if (has_value_)
     118           0 :       new (&value_) T(std::move(m.value_));
     119             :     else
     120           0 :       PoisonValue();
     121           0 :   }
     122             : 
     123           0 :   ~Optional() {
     124           0 :     if (has_value_)
     125           0 :       value_.~T();
     126             :     else
     127           0 :       UnpoisonValue();
     128           0 :   }
     129             : 
     130             :   // Copy assignment. Uses T's copy assignment if both sides have a value, T's
     131             :   // copy constructor if only the right-hand side has a value.
     132           0 :   Optional& operator=(const Optional& m) {
     133           0 :     if (m.has_value_) {
     134           0 :       if (has_value_) {
     135           0 :         value_ = m.value_;  // T's copy assignment.
     136             :       } else {
     137           0 :         UnpoisonValue();
     138           0 :         new (&value_) T(m.value_);  // T's copy constructor.
     139           0 :         has_value_ = true;
     140             :       }
     141             :     } else {
     142           0 :       reset();
     143             :     }
     144           0 :     return *this;
     145             :   }
     146             : 
     147             :   // Move assignment. Uses T's move assignment if both sides have a value, T's
     148             :   // move constructor if only the right-hand side has a value. The state of m
     149             :   // after it's been moved from is as for the move constructor.
     150           0 :   Optional& operator=(Optional&& m) {
     151           0 :     if (m.has_value_) {
     152           0 :       if (has_value_) {
     153           0 :         value_ = std::move(m.value_);  // T's move assignment.
     154             :       } else {
     155           0 :         UnpoisonValue();
     156           0 :         new (&value_) T(std::move(m.value_));  // T's move constructor.
     157           0 :         has_value_ = true;
     158             :       }
     159             :     } else {
     160           0 :       reset();
     161             :     }
     162           0 :     return *this;
     163             :   }
     164             : 
     165             :   // Swap the values if both m1 and m2 have values; move the value if only one
     166             :   // of them has one.
     167             :   friend void swap(Optional& m1, Optional& m2) {
     168             :     if (m1.has_value_) {
     169             :       if (m2.has_value_) {
     170             :         // Both have values: swap.
     171             :         using std::swap;
     172             :         swap(m1.value_, m2.value_);
     173             :       } else {
     174             :         // Only m1 has a value: move it to m2.
     175             :         m2.UnpoisonValue();
     176             :         new (&m2.value_) T(std::move(m1.value_));
     177             :         m1.value_.~T();  // Destroy the moved-from value.
     178             :         m1.has_value_ = false;
     179             :         m2.has_value_ = true;
     180             :         m1.PoisonValue();
     181             :       }
     182             :     } else if (m2.has_value_) {
     183             :       // Only m2 has a value: move it to m1.
     184             :       m1.UnpoisonValue();
     185             :       new (&m1.value_) T(std::move(m2.value_));
     186             :       m2.value_.~T();  // Destroy the moved-from value.
     187             :       m1.has_value_ = true;
     188             :       m2.has_value_ = false;
     189             :       m2.PoisonValue();
     190             :     }
     191             :   }
     192             : 
     193             :   // Destroy any contained value. Has no effect if we have no value.
     194           0 :   void reset() {
     195           0 :     if (!has_value_)
     196           0 :       return;
     197           0 :     value_.~T();
     198           0 :     has_value_ = false;
     199           0 :     PoisonValue();
     200             :   }
     201             : 
     202             :   template <class... Args>
     203           0 :   void emplace(Args&&... args) {
     204           0 :     if (has_value_)
     205           0 :       value_.~T();
     206             :     else
     207           0 :       UnpoisonValue();
     208           0 :     new (&value_) T(std::forward<Args>(args)...);
     209           0 :     has_value_ = true;
     210           0 :   }
     211             : 
     212             :   // Conversion to bool to test if we have a value.
     213           0 :   explicit operator bool() const { return has_value_; }
     214             : 
     215             :   // Dereferencing. Only allowed if we have a value.
     216           0 :   const T* operator->() const {
     217           0 :     RTC_DCHECK(has_value_);
     218           0 :     return &value_;
     219             :   }
     220           0 :   T* operator->() {
     221           0 :     RTC_DCHECK(has_value_);
     222           0 :     return &value_;
     223             :   }
     224           0 :   const T& operator*() const {
     225           0 :     RTC_DCHECK(has_value_);
     226           0 :     return value_;
     227             :   }
     228           0 :   T& operator*() {
     229           0 :     RTC_DCHECK(has_value_);
     230           0 :     return value_;
     231             :   }
     232             : 
     233             :   // Dereference with a default value in case we don't have a value.
     234           0 :   const T& value_or(const T& default_val) const {
     235             :     // The no-op call prevents the compiler from generating optimized code that
     236             :     // reads value_ even if !has_value_, but only if FunctionThatDoesNothing is
     237             :     // not completely inlined; see its declaration.).
     238           0 :     return has_value_ ? *optional_internal::FunctionThatDoesNothing(&value_)
     239           0 :                       : default_val;
     240             :   }
     241             : 
     242             :   // Equality tests. Two Optionals are equal if they contain equivalent values,
     243             :   // or if they're both empty.
     244             :   friend bool operator==(const Optional& m1, const Optional& m2) {
     245             :     return m1.has_value_ && m2.has_value_ ? m1.value_ == m2.value_
     246             :                                           : m1.has_value_ == m2.has_value_;
     247             :   }
     248             :   friend bool operator==(const Optional& opt, const T& value) {
     249             :     return opt.has_value_ && opt.value_ == value;
     250             :   }
     251           0 :   friend bool operator==(const T& value, const Optional& opt) {
     252           0 :     return opt.has_value_ && value == opt.value_;
     253             :   }
     254             : 
     255           0 :   friend bool operator!=(const Optional& m1, const Optional& m2) {
     256           0 :     return m1.has_value_ && m2.has_value_ ? m1.value_ != m2.value_
     257           0 :                                           : m1.has_value_ != m2.has_value_;
     258             :   }
     259             :   friend bool operator!=(const Optional& opt, const T& value) {
     260             :     return !opt.has_value_ || opt.value_ != value;
     261             :   }
     262             :   friend bool operator!=(const T& value, const Optional& opt) {
     263             :     return !opt.has_value_ || value != opt.value_;
     264             :   }
     265             : 
     266             :  private:
     267             :   // Tell sanitizers that value_ shouldn't be touched.
     268           0 :   void PoisonValue() {
     269           0 :     rtc::AsanPoison(rtc::MakeArrayView(&value_, 1));
     270           0 :     rtc::MsanMarkUninitialized(rtc::MakeArrayView(&value_, 1));
     271           0 :   }
     272             : 
     273             :   // Tell sanitizers that value_ is OK to touch again.
     274           0 :   void UnpoisonValue() {
     275           0 :     rtc::AsanUnpoison(rtc::MakeArrayView(&value_, 1));
     276           0 :   }
     277             : 
     278             :   bool has_value_;  // True iff value_ contains a live value.
     279             :   union {
     280             :     // empty_ exists only to make it possible to initialize the union, even when
     281             :     // it doesn't contain any data. If the union goes uninitialized, it may
     282             :     // trigger compiler warnings.
     283             :     char empty_;
     284             :     // By placing value_ in a union, we get to manage its construction and
     285             :     // destruction manually: the Optional constructors won't automatically
     286             :     // construct it, and the Optional destructor won't automatically destroy
     287             :     // it. Basically, this just allocates a properly sized and aligned block of
     288             :     // memory in which we can manually put a T with placement new.
     289             :     T value_;
     290             :   };
     291             : };
     292             : 
     293             : }  // namespace rtc
     294             : 
     295             : #endif  // WEBRTC_BASE_OPTIONAL_H_

Generated by: LCOV version 1.13