140 lines · c
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-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_OPTIONAL_H10#define LLVM_LIBC_SRC___SUPPORT_CPP_OPTIONAL_H11 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 makes29// 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 nontrivial57 // 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 cpp137} // namespace LIBC_NAMESPACE_DECL138 139#endif // LLVM_LIBC_SRC___SUPPORT_CPP_OPTIONAL_H140