Skip to content

Commit c86a0dd

Browse files
[libc] Extend optional to support non trivially destructible objects
This patch moves the storage from inside the libc's optional class to its own set of class, so we can support non-trivially destructible objects. These new classes check if the class is or isn't non trivially destructible and instantiate the correct base class, i.e., we explicitly call the destructor if an object is not trivially destructible. The motivation is to support cpp::optional<UInt<128>> (used by UInt<T>::div), which is used when a platform does not support native int128_t types (e.g., riscv32). The code here is a trimmed-down version of llvm::optional. Reviewed By: michaelrj Differential Revision: https://reviews.llvm.org/D150211
1 parent 56ce752 commit c86a0dd

File tree

1 file changed

+48
-40
lines changed

1 file changed

+48
-40
lines changed

libc/src/__support/CPP/optional.h

Lines changed: 48 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -36,85 +36,93 @@ LIBC_INLINE_VAR constexpr in_place_t in_place{};
3636
// several assumptions that the underlying type is trivially constructable,
3737
// copyable, or movable.
3838
template <typename T> class optional {
39-
template <typename U> class OptionalStorage {
39+
template <typename U, bool = !is_trivially_destructible<U>::value>
40+
struct OptionalStorage {
4041
union {
4142
char empty;
4243
U stored_value;
4344
};
44-
bool in_use;
4545

46-
public:
47-
LIBC_INLINE ~OptionalStorage() { reset(); }
48-
49-
LIBC_INLINE constexpr OptionalStorage() : empty(), in_use(false) {}
46+
LIBC_INLINE ~OptionalStorage() { stored_value.~U(); }
47+
LIBC_INLINE constexpr OptionalStorage() : empty() {}
5048

5149
template <typename... Args>
5250
LIBC_INLINE constexpr explicit OptionalStorage(in_place_t, Args &&...args)
53-
: stored_value(forward<Args>(args)...), in_use(true) {}
51+
: stored_value(forward<Args>(args)...) {}
52+
};
5453

55-
LIBC_INLINE void reset() {
56-
if (in_use)
57-
stored_value.~U();
58-
in_use = false;
59-
}
54+
template <typename U> struct OptionalStorage<U, false> {
55+
union {
56+
char empty;
57+
U stored_value;
58+
};
6059

61-
LIBC_INLINE constexpr bool has_value() const { return in_use; }
60+
// The only difference is that this class doesn't have a destructor.
61+
LIBC_INLINE constexpr OptionalStorage() : empty() {}
6262

63-
LIBC_INLINE U &value() & { return stored_value; }
64-
LIBC_INLINE constexpr U const &value() const & { return stored_value; }
65-
LIBC_INLINE U &&value() && { return move(stored_value); }
63+
template <typename... Args>
64+
LIBC_INLINE constexpr explicit OptionalStorage(in_place_t, Args &&...args)
65+
: stored_value(forward<Args>(args)...) {}
6666
};
6767

6868
OptionalStorage<T> storage;
69+
bool in_use = false;
6970

7071
public:
7172
LIBC_INLINE constexpr optional() = default;
7273
LIBC_INLINE constexpr optional(nullopt_t) {}
7374

74-
LIBC_INLINE constexpr optional(const T &t) : storage(in_place, t) {}
75+
LIBC_INLINE constexpr optional(const T &t)
76+
: storage(in_place, t), in_use(true) {}
7577
LIBC_INLINE constexpr optional(const optional &) = default;
7678

77-
LIBC_INLINE constexpr optional(T &&t) : storage(in_place, move(t)) {}
79+
LIBC_INLINE constexpr optional(T &&t)
80+
: storage(in_place, move(t)), in_use(true) {}
7881
LIBC_INLINE constexpr optional(optional &&O) = default;
7982

8083
template <typename... ArgTypes>
8184
LIBC_INLINE constexpr optional(in_place_t, ArgTypes &&...Args)
82-
: storage(in_place, forward<ArgTypes>(Args)...) {}
85+
: storage(in_place, forward<ArgTypes>(Args)...), in_use(true) {}
8386

84-
LIBC_INLINE optional &operator=(T &&t) {
87+
LIBC_INLINE constexpr optional &operator=(T &&t) {
8588
storage = move(t);
8689
return *this;
8790
}
88-
LIBC_INLINE optional &operator=(optional &&) = default;
89-
90-
LIBC_INLINE static constexpr optional create(const T *t) {
91-
return t ? optional(*t) : optional();
92-
}
91+
LIBC_INLINE constexpr optional &operator=(optional &&) = default;
9392

94-
LIBC_INLINE optional &operator=(const T &t) {
93+
LIBC_INLINE constexpr optional &operator=(const T &t) {
9594
storage = t;
9695
return *this;
9796
}
98-
LIBC_INLINE optional &operator=(const optional &) = default;
97+
LIBC_INLINE constexpr optional &operator=(const optional &) = default;
9998

100-
LIBC_INLINE void reset() { storage.reset(); }
99+
LIBC_INLINE constexpr void reset() {
100+
if (in_use)
101+
storage.~OptionalStorage();
102+
in_use = false;
103+
}
101104

102-
LIBC_INLINE constexpr const T &value() const & { return storage.value(); }
103-
LIBC_INLINE T &value() & { return storage.value(); }
105+
LIBC_INLINE constexpr const T &value() const & {
106+
return storage.stored_value;
107+
}
104108

105-
LIBC_INLINE constexpr explicit operator bool() const { return has_value(); }
106-
LIBC_INLINE constexpr bool has_value() const { return storage.has_value(); }
107-
LIBC_INLINE constexpr const T *operator->() const { return &storage.value(); }
108-
LIBC_INLINE T *operator->() { return &storage.value(); }
109-
LIBC_INLINE constexpr const T &operator*() const & { return value(); }
110-
LIBC_INLINE T &operator*() & { return value(); }
109+
LIBC_INLINE constexpr T &value() & { return storage.stored_value; }
111110

112-
template <typename U> LIBC_INLINE constexpr T value_or(U &&value) const & {
113-
return has_value() ? value() : forward<U>(value);
111+
LIBC_INLINE constexpr explicit operator bool() const { return in_use; }
112+
LIBC_INLINE constexpr bool has_value() const { return in_use; }
113+
LIBC_INLINE constexpr const T *operator->() const {
114+
return &storage.stored_value;
115+
}
116+
LIBC_INLINE constexpr T *operator->() { return &storage.stored_value; }
117+
LIBC_INLINE constexpr const T &operator*() const & {
118+
return storage.stored_value;
114119
}
120+
LIBC_INLINE constexpr T &operator*() & { return storage.stored_value; }
115121

116-
LIBC_INLINE T &&value() && { return move(storage.value()); }
117-
LIBC_INLINE T &&operator*() && { return move(storage.value()); }
122+
LIBC_INLINE constexpr T &&value() && { return move(storage.stored_value); }
123+
LIBC_INLINE constexpr T &&operator*() && {
124+
return move(storage.stored_value);
125+
}
118126
};
119127

120128
} // namespace cpp

0 commit comments

Comments
 (0)