master
  1//===-- Standalone implementation of std::optional --------------*- C++ -*-===//
  2//
  3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4// See https://llvm.org/LICENSE.txt for license information.
  5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6//
  7//===----------------------------------------------------------------------===//
  8
  9#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_OPTIONAL_H
 10#define LLVM_LIBC_SRC___SUPPORT_CPP_OPTIONAL_H
 11
 12#include "src/__support/CPP/type_traits.h"
 13#include "src/__support/CPP/utility.h"
 14#include "src/__support/macros/attributes.h"
 15#include "src/__support/macros/config.h"
 16
 17namespace LIBC_NAMESPACE_DECL {
 18namespace cpp {
 19
 20// Trivial nullopt_t struct.
 21struct nullopt_t {
 22  LIBC_INLINE constexpr explicit nullopt_t() = default;
 23};
 24
 25// nullopt that can be used and returned.
 26LIBC_INLINE_VAR constexpr nullopt_t nullopt{};
 27
 28// This is very simple implementation of the std::optional class. It makes
 29// several assumptions that the underlying type is trivially constructible,
 30// copyable, or movable.
 31template <typename T> class optional {
 32  template <typename U, bool = !is_trivially_destructible<U>::value>
 33  struct OptionalStorage {
 34    union {
 35      char empty;
 36      U stored_value;
 37    };
 38
 39    bool in_use = false;
 40
 41    LIBC_INLINE ~OptionalStorage() { reset(); }
 42
 43    LIBC_INLINE constexpr OptionalStorage() : empty() {}
 44
 45    template <typename... Args>
 46    LIBC_INLINE constexpr explicit OptionalStorage(in_place_t, Args &&...args)
 47        : stored_value(forward<Args>(args)...) {}
 48
 49    LIBC_INLINE constexpr void reset() {
 50      if (in_use)
 51        stored_value.~U();
 52      in_use = false;
 53    }
 54  };
 55
 56  // The only difference is that this type U doesn't have a nontrivial
 57  // destructor.
 58  template <typename U> struct OptionalStorage<U, false> {
 59    union {
 60      char empty;
 61      U stored_value;
 62    };
 63
 64    bool in_use = false;
 65
 66    LIBC_INLINE constexpr OptionalStorage() : empty() {}
 67
 68    template <typename... Args>
 69    LIBC_INLINE constexpr explicit OptionalStorage(in_place_t, Args &&...args)
 70        : stored_value(forward<Args>(args)...) {}
 71
 72    LIBC_INLINE constexpr void reset() { in_use = false; }
 73  };
 74
 75  OptionalStorage<T> storage;
 76
 77public:
 78  LIBC_INLINE constexpr optional() = default;
 79  LIBC_INLINE constexpr optional(nullopt_t) {}
 80
 81  LIBC_INLINE constexpr optional(const T &t) : storage(in_place, t) {
 82    storage.in_use = true;
 83  }
 84  LIBC_INLINE constexpr optional(const optional &) = default;
 85
 86  LIBC_INLINE constexpr optional(T &&t) : storage(in_place, move(t)) {
 87    storage.in_use = true;
 88  }
 89  LIBC_INLINE constexpr optional(optional &&O) = default;
 90
 91  template <typename... ArgTypes>
 92  LIBC_INLINE constexpr optional(in_place_t, ArgTypes &&...Args)
 93      : storage(in_place, forward<ArgTypes>(Args)...) {
 94    storage.in_use = true;
 95  }
 96
 97  LIBC_INLINE constexpr optional &operator=(T &&t) {
 98    storage = move(t);
 99    return *this;
100  }
101  LIBC_INLINE constexpr optional &operator=(optional &&) = default;
102
103  LIBC_INLINE constexpr optional &operator=(const T &t) {
104    storage = t;
105    return *this;
106  }
107  LIBC_INLINE constexpr optional &operator=(const optional &) = default;
108
109  LIBC_INLINE constexpr void reset() { storage.reset(); }
110
111  LIBC_INLINE constexpr const T &value() const & {
112    return storage.stored_value;
113  }
114
115  LIBC_INLINE constexpr T &value() & { return storage.stored_value; }
116
117  LIBC_INLINE constexpr explicit operator bool() const {
118    return storage.in_use;
119  }
120  LIBC_INLINE constexpr bool has_value() const { return storage.in_use; }
121  LIBC_INLINE constexpr const T *operator->() const {
122    return &storage.stored_value;
123  }
124  LIBC_INLINE constexpr T *operator->() { return &storage.stored_value; }
125  LIBC_INLINE constexpr const T &operator*() const & {
126    return storage.stored_value;
127  }
128  LIBC_INLINE constexpr T &operator*() & { return storage.stored_value; }
129
130  LIBC_INLINE constexpr T &&value() && { return move(storage.stored_value); }
131  LIBC_INLINE constexpr T &&operator*() && {
132    return move(storage.stored_value);
133  }
134};
135
136} // namespace cpp
137} // namespace LIBC_NAMESPACE_DECL
138
139#endif // LLVM_LIBC_SRC___SUPPORT_CPP_OPTIONAL_H