LCOV - code coverage report
Current view: top level - include/llvm/ADT - Optional.h (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 92 93 98.9 %
Date: 2018-07-13 00:08:38 Functions: 404 487 83.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===- Optional.h - Simple variant for passing optional values --*- C++ -*-===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : //
      10             : //  This file provides Optional, a template class modeled in the spirit of
      11             : //  OCaml's 'opt' variant.  The idea is to strongly type whether or not
      12             : //  a value can be optional.
      13             : //
      14             : //===----------------------------------------------------------------------===//
      15             : 
      16             : #ifndef LLVM_ADT_OPTIONAL_H
      17             : #define LLVM_ADT_OPTIONAL_H
      18             : 
      19             : #include "llvm/ADT/None.h"
      20             : #include "llvm/Support/AlignOf.h"
      21             : #include "llvm/Support/Compiler.h"
      22             : #include "llvm/Support/type_traits.h"
      23             : #include <algorithm>
      24             : #include <cassert>
      25             : #include <new>
      26             : #include <utility>
      27             : 
      28             : namespace llvm {
      29             : 
      30             : namespace optional_detail {
      31             : /// Storage for any type.
      32             : template <typename T, bool IsPodLike> struct OptionalStorage {
      33             :   AlignedCharArrayUnion<T> storage;
      34             :   bool hasVal = false;
      35             : 
      36   162517670 :   OptionalStorage() = default;
      37             : 
      38    20093787 :   OptionalStorage(const T &y) : hasVal(true) { new (storage.buffer) T(y); }
      39    57286490 :   OptionalStorage(const OptionalStorage &O) : hasVal(O.hasVal) {
      40    52925144 :     if (hasVal)
      41     6353541 :       new (storage.buffer) T(*O.getPointer());
      42        4202 :   }
      43    54942763 :   OptionalStorage(T &&y) : hasVal(true) {
      44    54925049 :     new (storage.buffer) T(std::forward<T>(y));
      45         215 :   }
      46     7683739 :   OptionalStorage(OptionalStorage &&O) : hasVal(O.hasVal) {
      47     7073774 :     if (O.hasVal) {
      48     2020457 :       new (storage.buffer) T(std::move(*O.getPointer()));
      49             :     }
      50          33 :   }
      51             : 
      52     3234315 :   OptionalStorage &operator=(T &&y) {
      53     9490878 :     if (hasVal)
      54     3178596 :       *getPointer() = std::move(y);
      55             :     else {
      56    12780599 :       new (storage.buffer) T(std::move(y));
      57    12910030 :       hasVal = true;
      58             :     }
      59     3234315 :     return *this;
      60             :   }
      61      324145 :   OptionalStorage &operator=(OptionalStorage &&O) {
      62     1322647 :     if (!O.hasVal)
      63           0 :       reset();
      64             :     else {
      65      334101 :       *this = std::move(*O.getPointer());
      66             :     }
      67      324145 :     return *this;
      68             :   }
      69             : 
      70             :   // FIXME: these assignments (& the equivalent const T&/const Optional& ctors)
      71             :   // could be made more efficient by passing by value, possibly unifying them
      72             :   // with the rvalue versions above - but this could place a different set of
      73             :   // requirements (notably: the existence of a default ctor) when implemented
      74             :   // in that way. Careful SFINAE to avoid such pitfalls would be required.
      75       34232 :   OptionalStorage &operator=(const T &y) {
      76     2494570 :     if (hasVal)
      77     1044839 :       *getPointer() = y;
      78             :     else {
      79     1692850 :       new (storage.buffer) T(y);
      80     1695173 :       hasVal = true;
      81             :     }
      82       34232 :     return *this;
      83             :   }
      84       84490 :   OptionalStorage &operator=(const OptionalStorage &O) {
      85     1218397 :     if (!O.hasVal)
      86             :       reset();
      87             :     else
      88      336636 :       *this = *O.getPointer();
      89       84490 :     return *this;
      90             :   }
      91             : 
      92      529850 :   ~OptionalStorage() { reset(); }
      93             : 
      94     1189751 :   void reset() {
      95     8586310 :     if (hasVal) {
      96      545369 :       (*getPointer()).~T();
      97      469310 :       hasVal = false;
      98             :     }
      99     1189751 :   }
     100             : 
     101             :   T *getPointer() {
     102             :     assert(hasVal);
     103     3707514 :     return reinterpret_cast<T *>(storage.buffer);
     104             :   }
     105             :   const T *getPointer() const {
     106             :     assert(hasVal);
     107       19018 :     return reinterpret_cast<const T *>(storage.buffer);
     108             :   }
     109             : };
     110             : 
     111             : #if !defined(__GNUC__) || defined(__clang__) // GCC up to GCC7 miscompiles this.
     112             : /// Storage for trivially copyable types only.
     113             : template <typename T> struct OptionalStorage<T, true> {
     114             :   AlignedCharArrayUnion<T> storage;
     115             :   bool hasVal = false;
     116             : 
     117             :   OptionalStorage() = default;
     118             : 
     119             :   OptionalStorage(const T &y) : hasVal(true) { new (storage.buffer) T(y); }
     120             :   OptionalStorage &operator=(const T &y) {
     121             :     *reinterpret_cast<T *>(storage.buffer) = y;
     122             :     hasVal = true;
     123             :     return *this;
     124             :   }
     125             : 
     126             :   void reset() { hasVal = false; }
     127             : };
     128             : #endif
     129             : } // namespace optional_detail
     130             : 
     131     8511088 : template <typename T> class Optional {
     132             :   optional_detail::OptionalStorage<T, isPodLike<T>::value> Storage;
     133             : 
     134             : public:
     135             :   using value_type = T;
     136             : 
     137    65492411 :   constexpr Optional() {}
     138    13822817 :   constexpr Optional(NoneType) {}
     139             : 
     140    13251462 :   Optional(const T &y) : Storage(y) {}
     141    40545486 :   Optional(const Optional &O) = default;
     142             : 
     143    32886597 :   Optional(T &&y) : Storage(std::forward<T>(y)) {}
     144     5675515 :   Optional(Optional &&O) = default;
     145             : 
     146     5631480 :   Optional &operator=(T &&y) {
     147     8493657 :     Storage = std::move(y);
     148     5631480 :     return *this;
     149             :   }
     150             :   Optional &operator=(Optional &&O) = default;
     151             : 
     152             :   /// Create a new object by constructing it in place with the given arguments.
     153      470902 :   template <typename... ArgTypes> void emplace(ArgTypes &&... Args) {
     154             :     reset();
     155     5679156 :     Storage.hasVal = true;
     156     5600632 :     new (getPointer()) T(std::forward<ArgTypes>(Args)...);
     157      470902 :   }
     158             : 
     159             :   static inline Optional create(const T *y) {
     160      614275 :     return y ? Optional(*y) : Optional();
     161             :   }
     162             : 
     163             :   Optional &operator=(const T &y) {
     164       16954 :     Storage = y;
     165             :     return *this;
     166             :   }
     167             :   Optional &operator=(const Optional &O) = default;
     168             : 
     169      659901 :   void reset() { Storage.reset(); }
     170             : 
     171             :   const T *getPointer() const {
     172             :     assert(Storage.hasVal);
     173     1398118 :     return reinterpret_cast<const T *>(Storage.storage.buffer);
     174             :   }
     175             :   T *getPointer() {
     176             :     assert(Storage.hasVal);
     177    36341524 :     return reinterpret_cast<T *>(Storage.storage.buffer);
     178             :   }
     179             :   const T &getValue() const LLVM_LVALUE_FUNCTION { return *getPointer(); }
     180             :   T &getValue() LLVM_LVALUE_FUNCTION { return *getPointer(); }
     181             : 
     182    52427935 :   explicit operator bool() const { return Storage.hasVal; }
     183             :   bool hasValue() const { return Storage.hasVal; }
     184             :   const T *operator->() const { return getPointer(); }
     185             :   T *operator->() { return getPointer(); }
     186             :   const T &operator*() const LLVM_LVALUE_FUNCTION { return *getPointer(); }
     187    11305752 :   T &operator*() LLVM_LVALUE_FUNCTION { return *getPointer(); }
     188             : 
     189             :   template <typename U>
     190          18 :   constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION {
     191    44054148 :     return hasValue() ? getValue() : std::forward<U>(value);
     192             :   }
     193             : 
     194             : #if LLVM_HAS_RVALUE_REFERENCE_THIS
     195             :   T &&getValue() && { return std::move(*getPointer()); }
     196             :   T &&operator*() && { return std::move(*getPointer()); }
     197             : 
     198             :   template <typename U>
     199             :   T getValueOr(U &&value) && {
     200      391872 :     return hasValue() ? std::move(getValue()) : std::forward<U>(value);
     201             :   }
     202             : #endif
     203             : };
     204             : 
     205             : template <typename T> struct isPodLike<Optional<T>> {
     206             :   // An Optional<T> is pod-like if T is.
     207             :   static const bool value = isPodLike<T>::value;
     208             : };
     209             : 
     210             : template <typename T, typename U>
     211         174 : bool operator==(const Optional<T> &X, const Optional<U> &Y) {
     212      348596 :   if (X && Y)
     213         865 :     return *X == *Y;
     214      347574 :   return X.hasValue() == Y.hasValue();
     215             : }
     216             : 
     217             : template <typename T, typename U>
     218          23 : bool operator!=(const Optional<T> &X, const Optional<U> &Y) {
     219         195 :   return !(X == Y);
     220             : }
     221             : 
     222             : template <typename T, typename U>
     223             : bool operator<(const Optional<T> &X, const Optional<U> &Y) {
     224          20 :   if (X && Y)
     225           8 :     return *X < *Y;
     226          12 :   return X.hasValue() < Y.hasValue();
     227             : }
     228             : 
     229             : template <typename T, typename U>
     230           5 : bool operator<=(const Optional<T> &X, const Optional<U> &Y) {
     231           5 :   return !(Y < X);
     232             : }
     233             : 
     234             : template <typename T, typename U>
     235             : bool operator>(const Optional<T> &X, const Optional<U> &Y) {
     236             :   return Y < X;
     237             : }
     238             : 
     239             : template <typename T, typename U>
     240           5 : bool operator>=(const Optional<T> &X, const Optional<U> &Y) {
     241           5 :   return !(X < Y);
     242             : }
     243             : 
     244             : template<typename T>
     245             : bool operator==(const Optional<T> &X, NoneType) {
     246    14826628 :   return !X;
     247             : }
     248             : 
     249             : template<typename T>
     250             : bool operator==(NoneType, const Optional<T> &X) {
     251             :   return X == None;
     252             : }
     253             : 
     254             : template<typename T>
     255             : bool operator!=(const Optional<T> &X, NoneType) {
     256             :   return !(X == None);
     257             : }
     258             : 
     259             : template<typename T>
     260             : bool operator!=(NoneType, const Optional<T> &X) {
     261             :   return X != None;
     262             : }
     263             : 
     264             : template <typename T> bool operator<(const Optional<T> &X, NoneType) {
     265             :   return false;
     266             : }
     267             : 
     268             : template <typename T> bool operator<(NoneType, const Optional<T> &X) {
     269           8 :   return X.hasValue();
     270             : }
     271             : 
     272             : template <typename T> bool operator<=(const Optional<T> &X, NoneType) {
     273           4 :   return !(None < X);
     274             : }
     275             : 
     276             : template <typename T> bool operator<=(NoneType, const Optional<T> &X) {
     277             :   return !(X < None);
     278             : }
     279             : 
     280             : template <typename T> bool operator>(const Optional<T> &X, NoneType) {
     281             :   return None < X;
     282             : }
     283             : 
     284             : template <typename T> bool operator>(NoneType, const Optional<T> &X) {
     285             :   return X < None;
     286             : }
     287             : 
     288             : template <typename T> bool operator>=(const Optional<T> &X, NoneType) {
     289             :   return None <= X;
     290             : }
     291             : 
     292             : template <typename T> bool operator>=(NoneType, const Optional<T> &X) {
     293             :   return X <= None;
     294             : }
     295             : 
     296             : template <typename T> bool operator==(const Optional<T> &X, const T &Y) {
     297      168721 :   return X && *X == Y;
     298             : }
     299             : 
     300           1 : template <typename T> bool operator==(const T &X, const Optional<T> &Y) {
     301          21 :   return Y && X == *Y;
     302             : }
     303             : 
     304             : template <typename T> bool operator!=(const Optional<T> &X, const T &Y) {
     305           3 :   return !(X == Y);
     306             : }
     307             : 
     308             : template <typename T> bool operator!=(const T &X, const Optional<T> &Y) {
     309           3 :   return !(X == Y);
     310             : }
     311             : 
     312             : template <typename T> bool operator<(const Optional<T> &X, const T &Y) {
     313          21 :   return !X || *X < Y;
     314             : }
     315             : 
     316             : template <typename T> bool operator<(const T &X, const Optional<T> &Y) {
     317          30 :   return Y && X < *Y;
     318             : }
     319             : 
     320             : template <typename T> bool operator<=(const Optional<T> &X, const T &Y) {
     321           3 :   return !(Y < X);
     322             : }
     323             : 
     324             : template <typename T> bool operator<=(const T &X, const Optional<T> &Y) {
     325           3 :   return !(Y < X);
     326             : }
     327             : 
     328             : template <typename T> bool operator>(const Optional<T> &X, const T &Y) {
     329             :   return Y < X;
     330             : }
     331             : 
     332             : template <typename T> bool operator>(const T &X, const Optional<T> &Y) {
     333             :   return Y < X;
     334             : }
     335             : 
     336             : template <typename T> bool operator>=(const Optional<T> &X, const T &Y) {
     337           3 :   return !(X < Y);
     338             : }
     339             : 
     340             : template <typename T> bool operator>=(const T &X, const Optional<T> &Y) {
     341           3 :   return !(X < Y);
     342             : }
     343             : 
     344             : } // end namespace llvm
     345             : 
     346             : #endif // LLVM_ADT_OPTIONAL_H

Generated by: LCOV version 1.13