[libc-commits] [libc] c86a0dd - [libc] Extend optional to support non trivially destructible objects

Mikhail R. Gadelha via libc-commits libc-commits at lists.llvm.org
Thu Aug 17 10:27:07 PDT 2023


Author: Mikhail R. Gadelha
Date: 2023-08-17T14:24:32-03:00
New Revision: c86a0dd134bf66caded2429834d824f16c2a39f0

URL: https://github.com/llvm/llvm-project/commit/c86a0dd134bf66caded2429834d824f16c2a39f0
DIFF: https://github.com/llvm/llvm-project/commit/c86a0dd134bf66caded2429834d824f16c2a39f0.diff

LOG: [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

Added: 
    

Modified: 
    libc/src/__support/CPP/optional.h

Removed: 
    


################################################################################
diff  --git a/libc/src/__support/CPP/optional.h b/libc/src/__support/CPP/optional.h
index a1eca2c860697a..bbf9188087c1b3 100644
--- a/libc/src/__support/CPP/optional.h
+++ b/libc/src/__support/CPP/optional.h
@@ -36,85 +36,93 @@ LIBC_INLINE_VAR constexpr in_place_t in_place{};
 // several assumptions that the underlying type is trivially constructable,
 // copyable, or movable.
 template <typename T> class optional {
-  template <typename U> class OptionalStorage {
+  template <typename U, bool = !is_trivially_destructible<U>::value>
+  struct OptionalStorage {
     union {
       char empty;
       U stored_value;
     };
-    bool in_use;
 
-  public:
-    LIBC_INLINE ~OptionalStorage() { reset(); }
-
-    LIBC_INLINE constexpr OptionalStorage() : empty(), in_use(false) {}
+    LIBC_INLINE ~OptionalStorage() { stored_value.~U(); }
+    LIBC_INLINE constexpr OptionalStorage() : empty() {}
 
     template <typename... Args>
     LIBC_INLINE constexpr explicit OptionalStorage(in_place_t, Args &&...args)
-        : stored_value(forward<Args>(args)...), in_use(true) {}
+        : stored_value(forward<Args>(args)...) {}
+  };
 
-    LIBC_INLINE void reset() {
-      if (in_use)
-        stored_value.~U();
-      in_use = false;
-    }
+  template <typename U> struct OptionalStorage<U, false> {
+    union {
+      char empty;
+      U stored_value;
+    };
 
-    LIBC_INLINE constexpr bool has_value() const { return in_use; }
+    // The only 
diff erence is that this class doesn't have a destructor.
+    LIBC_INLINE constexpr OptionalStorage() : empty() {}
 
-    LIBC_INLINE U &value() & { return stored_value; }
-    LIBC_INLINE constexpr U const &value() const & { return stored_value; }
-    LIBC_INLINE U &&value() && { return move(stored_value); }
+    template <typename... Args>
+    LIBC_INLINE constexpr explicit OptionalStorage(in_place_t, Args &&...args)
+        : stored_value(forward<Args>(args)...) {}
   };
 
   OptionalStorage<T> storage;
+  bool in_use = false;
 
 public:
   LIBC_INLINE constexpr optional() = default;
   LIBC_INLINE constexpr optional(nullopt_t) {}
 
-  LIBC_INLINE constexpr optional(const T &t) : storage(in_place, t) {}
+  LIBC_INLINE constexpr optional(const T &t)
+      : storage(in_place, t), in_use(true) {}
   LIBC_INLINE constexpr optional(const optional &) = default;
 
-  LIBC_INLINE constexpr optional(T &&t) : storage(in_place, move(t)) {}
+  LIBC_INLINE constexpr optional(T &&t)
+      : storage(in_place, move(t)), in_use(true) {}
   LIBC_INLINE constexpr optional(optional &&O) = default;
 
   template <typename... ArgTypes>
   LIBC_INLINE constexpr optional(in_place_t, ArgTypes &&...Args)
-      : storage(in_place, forward<ArgTypes>(Args)...) {}
+      : storage(in_place, forward<ArgTypes>(Args)...), in_use(true) {}
 
-  LIBC_INLINE optional &operator=(T &&t) {
+  LIBC_INLINE constexpr optional &operator=(T &&t) {
     storage = move(t);
     return *this;
   }
-  LIBC_INLINE optional &operator=(optional &&) = default;
-
-  LIBC_INLINE static constexpr optional create(const T *t) {
-    return t ? optional(*t) : optional();
-  }
+  LIBC_INLINE constexpr optional &operator=(optional &&) = default;
 
-  LIBC_INLINE optional &operator=(const T &t) {
+  LIBC_INLINE constexpr optional &operator=(const T &t) {
     storage = t;
     return *this;
   }
-  LIBC_INLINE optional &operator=(const optional &) = default;
+  LIBC_INLINE constexpr optional &operator=(const optional &) = default;
 
-  LIBC_INLINE void reset() { storage.reset(); }
+  LIBC_INLINE constexpr void reset() {
+    if (in_use)
+      storage.~OptionalStorage();
+    in_use = false;
+  }
 
-  LIBC_INLINE constexpr const T &value() const & { return storage.value(); }
-  LIBC_INLINE T &value() & { return storage.value(); }
+  LIBC_INLINE constexpr const T &value() const & {
+    return storage.stored_value;
+  }
 
-  LIBC_INLINE constexpr explicit operator bool() const { return has_value(); }
-  LIBC_INLINE constexpr bool has_value() const { return storage.has_value(); }
-  LIBC_INLINE constexpr const T *operator->() const { return &storage.value(); }
-  LIBC_INLINE T *operator->() { return &storage.value(); }
-  LIBC_INLINE constexpr const T &operator*() const & { return value(); }
-  LIBC_INLINE T &operator*() & { return value(); }
+  LIBC_INLINE constexpr T &value() & { return storage.stored_value; }
 
-  template <typename U> LIBC_INLINE constexpr T value_or(U &&value) const & {
-    return has_value() ? value() : forward<U>(value);
+  LIBC_INLINE constexpr explicit operator bool() const { return in_use; }
+  LIBC_INLINE constexpr bool has_value() const { return in_use; }
+  LIBC_INLINE constexpr const T *operator->() const {
+    return &storage.stored_value;
+  }
+  LIBC_INLINE constexpr T *operator->() { return &storage.stored_value; }
+  LIBC_INLINE constexpr const T &operator*() const & {
+    return storage.stored_value;
   }
+  LIBC_INLINE constexpr T &operator*() & { return storage.stored_value; }
 
-  LIBC_INLINE T &&value() && { return move(storage.value()); }
-  LIBC_INLINE T &&operator*() && { return move(storage.value()); }
+  LIBC_INLINE constexpr T &&value() && { return move(storage.stored_value); }
+  LIBC_INLINE constexpr T &&operator*() && {
+    return move(storage.stored_value);
+  }
 };
 
 } // namespace cpp


        


More information about the libc-commits mailing list